diff options
Diffstat (limited to 'tests/auto/qml/qmltyperegistrar')
18 files changed, 1272 insertions, 84 deletions
diff --git a/tests/auto/qml/qmltyperegistrar/CMakeLists.txt b/tests/auto/qml/qmltyperegistrar/CMakeLists.txt index 039f1647db..45669769e4 100644 --- a/tests/auto/qml/qmltyperegistrar/CMakeLists.txt +++ b/tests/auto/qml/qmltyperegistrar/CMakeLists.txt @@ -7,12 +7,18 @@ ## tst_qmltyperegistrar Test: ##################################################################### +if(NOT QT_BUILD_STANDALONE_TESTS AND NOT QT_BUILDING_QT) + cmake_minimum_required(VERSION 3.16) + project(tst_qmltyperegistrar LANGUAGES CXX) + find_package(Qt6BuildInternals REQUIRED COMPONENTS STANDALONE_TEST) +endif() + add_subdirectory(VersionZero) add_subdirectory(UnregisteredTypes) add_subdirectory(foreign) qt_manual_moc(moc_files OUTPUT_MOC_JSON_FILES json_list noextheader - INCLUDE_DIRECTORY_TARGETS Qt::Qml) + TARGETS Qt6::Qml) # Dummy target to pass --private-includes to qmltyperegistrar for tst_qmltyperegistrar. # We want to test that it expects files named foo_p.h appearing in foreign metatypes @@ -76,9 +82,11 @@ qt_add_library(tst-qmltyperegistrar-with-dashes) qt_autogen_tools_initial_setup(tst-qmltyperegistrar-with-dashes) target_link_libraries(tst-qmltyperegistrar-with-dashes PRIVATE Qt::Core Qt::Qml) qt_enable_autogen_tool(tst-qmltyperegistrar-with-dashes "moc" ON) + +qt_policy(SET QTP0001 NEW) + qt_add_qml_module(tst-qmltyperegistrar-with-dashes URI Module-With-Dashes - AUTO_RESOURCE_PREFIX SOURCES foo.cpp foo.h OUTPUT_DIRECTORY Module-With-Dashes @@ -90,4 +98,20 @@ qt_internal_add_resource(tst_qmltyperegistrar "resources" "/" FILES duplicatedExports.json + missingTypes.json ) + +set(CMAKE_INCLUDE_CURRENT_DIR ON) +qt_add_library(tst-qmltyperegistrar-enum-foreign STATIC enum.cpp) +qt_autogen_tools_initial_setup(tst-qmltyperegistrar-enum-foreign) +qt_enable_autogen_tool(tst-qmltyperegistrar-enum-foreign "moc" ON) +target_link_libraries(tst-qmltyperegistrar-enum-foreign PRIVATE Qt::QmlIntegration) + +qt_add_library(tst-qmltyperegistrar-enum STATIC) +qt_autogen_tools_initial_setup(tst-qmltyperegistrar-enum) +qt_enable_autogen_tool(tst-qmltyperegistrar-enum "moc" ON) +target_link_libraries(tst-qmltyperegistrar-enum PRIVATE Qt::Qml tst-qmltyperegistrar-enum-foreign) + +qt_add_qml_module(tst-qmltyperegistrar-enum URI TstEnum OUTPUT_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/TstEnum) +qt_autogen_tools_initial_setup(tst-qmltyperegistrar-enumplugin) +qt_generate_foreign_qml_types(tst-qmltyperegistrar-enum-foreign tst-qmltyperegistrar-enum) diff --git a/tests/auto/qml/qmltyperegistrar/UnregisteredTypes/CMakeLists.txt b/tests/auto/qml/qmltyperegistrar/UnregisteredTypes/CMakeLists.txt index cb020e95e0..d469f1e97f 100644 --- a/tests/auto/qml/qmltyperegistrar/UnregisteredTypes/CMakeLists.txt +++ b/tests/auto/qml/qmltyperegistrar/UnregisteredTypes/CMakeLists.txt @@ -2,13 +2,15 @@ # SPDX-License-Identifier: BSD-3-Clause # Use NO_GENERATE_QMLTYPES to avoid static asserts during compilation of the types to be tested, same for NO_PLUGIN + +qt_policy(SET QTP0001 NEW) + qt_add_qml_module(UnregisteredTypes STATIC URI UnregisteredTypes NO_GENERATE_QMLTYPES NO_PLUGIN SOURCES uncreatable.h - AUTO_RESOURCE_PREFIX ) qt_enable_autogen_tool(UnregisteredTypes "moc" ON) diff --git a/tests/auto/qml/qmltyperegistrar/UnregisteredTypes/uncreatable.h b/tests/auto/qml/qmltyperegistrar/UnregisteredTypes/uncreatable.h index 9726f4683c..2274f87e3d 100644 --- a/tests/auto/qml/qmltyperegistrar/UnregisteredTypes/uncreatable.h +++ b/tests/auto/qml/qmltyperegistrar/UnregisteredTypes/uncreatable.h @@ -1,5 +1,5 @@ // Copyright (C) 2021 The Qt Company Ltd. -// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only #ifndef UNCREATABLE_H #define UNCREATABLE_H @@ -39,6 +39,39 @@ public: static SingletonCreatable3 *create(QQmlEngine *, QJSEngine *) { return nullptr; } }; +class SingletonForeign : public QObject +{ + Q_OBJECT + SingletonForeign() = delete; +}; + +class SingletonLocalCreatable +{ + Q_GADGET + QML_FOREIGN(SingletonForeign) + QML_ELEMENT + QML_SINGLETON +public: + static SingletonForeign *create(QQmlEngine *, QJSEngine *) { return nullptr; } +}; + +class SingletonLocalUncreatable1 +{ + Q_GADGET + QML_FOREIGN(SingletonForeign) + QML_ELEMENT + QML_SINGLETON + static SingletonForeign *create(QQmlEngine *, QJSEngine *) { return nullptr; } +}; + +class SingletonLocalUncreatable2 +{ + Q_GADGET + QML_FOREIGN(SingletonForeign) + QML_ELEMENT + QML_SINGLETON +}; + class SingletonIncreatable : public QObject { Q_OBJECT @@ -184,4 +217,20 @@ class FixingBadUncreatable QML_FOREIGN(BadUncreatable) QML_UNCREATABLE("") }; + +class SingletonVesion0 : public QObject +{ + Q_OBJECT + QML_ELEMENT + QML_SINGLETON + // is default constructible +}; + +class SingletonVesion1 : public QObject +{ + Q_OBJECT + QML_ELEMENT + QML_SINGLETON + // is default constructible +}; #endif // UNCREATABLE_H diff --git a/tests/auto/qml/qmltyperegistrar/VersionZero/version_zero_type.h b/tests/auto/qml/qmltyperegistrar/VersionZero/version_zero_type.h index a3277e6ab3..0ad477c3cb 100644 --- a/tests/auto/qml/qmltyperegistrar/VersionZero/version_zero_type.h +++ b/tests/auto/qml/qmltyperegistrar/VersionZero/version_zero_type.h @@ -1,5 +1,5 @@ // Copyright (C) 2022 The Qt Company Ltd. -// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only #ifndef VERSION_ZERO_TYPE_H #define VERSION_ZERO_TYPE_H diff --git a/tests/auto/qml/qmltyperegistrar/duplicatedExports.h b/tests/auto/qml/qmltyperegistrar/duplicatedExports.h index 5ae2e77551..e72a2f19c9 100644 --- a/tests/auto/qml/qmltyperegistrar/duplicatedExports.h +++ b/tests/auto/qml/qmltyperegistrar/duplicatedExports.h @@ -1,5 +1,5 @@ // Copyright (C) 2021 The Qt Company Ltd. -// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only #ifndef DUPLICATEDEXPORTS_H #define DUPLICATEDEXPORTS_H diff --git a/tests/auto/qml/qmltyperegistrar/enum.cpp b/tests/auto/qml/qmltyperegistrar/enum.cpp new file mode 100644 index 0000000000..34d2e00ffa --- /dev/null +++ b/tests/auto/qml/qmltyperegistrar/enum.cpp @@ -0,0 +1,5 @@ +// Copyright (C) 2024 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only + +#include "enum.h" +#include "moc_enum.cpp" diff --git a/tests/auto/qml/qmltyperegistrar/enum.h b/tests/auto/qml/qmltyperegistrar/enum.h new file mode 100644 index 0000000000..653c48c79f --- /dev/null +++ b/tests/auto/qml/qmltyperegistrar/enum.h @@ -0,0 +1,40 @@ +// Copyright (C) 2024 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only + +#ifndef ENUM_NS_HELLO_H +#define ENUM_NS_HELLO_H + +#include <QObject> +#include <QtQmlIntegration/qqmlintegration.h> + +namespace Hello { + Q_NAMESPACE + QML_NAMED_ELEMENT(World) + enum class World { + Europe = 2024, + }; + Q_ENUM_NS(World) +} + +namespace Universe { + namespace Galaxy { + Q_NAMESPACE + QML_NAMED_ELEMENT(Solar) + enum class Solar { + Earth, + }; + Q_ENUM_NS(Solar) + } + + class Blackhole { + Q_GADGET + QML_ELEMENT + public: + enum SagittariusA { + Singularity + }; + Q_ENUM(SagittariusA) + }; +} + +#endif // ENUM_NS_HELLO_H diff --git a/tests/auto/qml/qmltyperegistrar/foo.cpp b/tests/auto/qml/qmltyperegistrar/foo.cpp index ba95235bd6..c5ef8313dc 100644 --- a/tests/auto/qml/qmltyperegistrar/foo.cpp +++ b/tests/auto/qml/qmltyperegistrar/foo.cpp @@ -1,5 +1,5 @@ // Copyright (C) 2021 The Qt Company Ltd. -// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only #include "foo.h" #include <QDebug> diff --git a/tests/auto/qml/qmltyperegistrar/foo.h b/tests/auto/qml/qmltyperegistrar/foo.h index 7872c35c17..5af2e11eaa 100644 --- a/tests/auto/qml/qmltyperegistrar/foo.h +++ b/tests/auto/qml/qmltyperegistrar/foo.h @@ -1,5 +1,5 @@ // Copyright (C) 2021 The Qt Company Ltd. -// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only #ifndef FOO_H #define FOO_H diff --git a/tests/auto/qml/qmltyperegistrar/foreign/CMakeLists.txt b/tests/auto/qml/qmltyperegistrar/foreign/CMakeLists.txt index 5334225692..68223ae6a5 100644 --- a/tests/auto/qml/qmltyperegistrar/foreign/CMakeLists.txt +++ b/tests/auto/qml/qmltyperegistrar/foreign/CMakeLists.txt @@ -10,7 +10,8 @@ qt_internal_add_cmake_library(foreign STATIC SOURCES - foreign.cpp foreign.h foreign_p.h + foreign.cpp foreign.h + private/foreign_p.h PUBLIC_LIBRARIES Qt::Core ) diff --git a/tests/auto/qml/qmltyperegistrar/foreign/foreign.cpp b/tests/auto/qml/qmltyperegistrar/foreign/foreign.cpp index f78dd47237..1691f5396a 100644 --- a/tests/auto/qml/qmltyperegistrar/foreign/foreign.cpp +++ b/tests/auto/qml/qmltyperegistrar/foreign/foreign.cpp @@ -1,5 +1,5 @@ // Copyright (C) 2020 The Qt Company Ltd. -// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only #include "foreign.h" diff --git a/tests/auto/qml/qmltyperegistrar/foreign/foreign.h b/tests/auto/qml/qmltyperegistrar/foreign/foreign.h index ea78a58432..79ac8074cf 100644 --- a/tests/auto/qml/qmltyperegistrar/foreign/foreign.h +++ b/tests/auto/qml/qmltyperegistrar/foreign/foreign.h @@ -1,5 +1,5 @@ // Copyright (C) 2020 The Qt Company Ltd. -// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only #ifndef FOREIGN_H #define FOREIGN_H diff --git a/tests/auto/qml/qmltyperegistrar/foreign/foreign_p.h b/tests/auto/qml/qmltyperegistrar/foreign/private/foreign_p.h index fe7986471f..ed23d78284 100644 --- a/tests/auto/qml/qmltyperegistrar/foreign/foreign_p.h +++ b/tests/auto/qml/qmltyperegistrar/foreign/private/foreign_p.h @@ -1,5 +1,5 @@ // Copyright (C) 2021 The Qt Company Ltd. -// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only #ifndef FOREIGN_P_H #define FOREIGN_P_H @@ -7,7 +7,6 @@ #include <QtCore/qobject.h> // qmltyperegistrar will assume this file is reachable under <private/foreign_p.h> -// It's not true, but this is how it works on actual private headers in Qt. // See the trick in tst_qmltyperegistrar's CMakeLists.txt to turn on the --private-includes option. class ForeignPrivate : public QObject { diff --git a/tests/auto/qml/qmltyperegistrar/hppheader.hpp b/tests/auto/qml/qmltyperegistrar/hppheader.hpp index dc82fc8530..4278601a9e 100644 --- a/tests/auto/qml/qmltyperegistrar/hppheader.hpp +++ b/tests/auto/qml/qmltyperegistrar/hppheader.hpp @@ -1,5 +1,5 @@ // Copyright (C) 2021 The Qt Company Ltd. -// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only #ifndef HPPHEADER_HPP #define HPPHEADER_HPP diff --git a/tests/auto/qml/qmltyperegistrar/missingTypes.json b/tests/auto/qml/qmltyperegistrar/missingTypes.json new file mode 100644 index 0000000000..dacec11c4c --- /dev/null +++ b/tests/auto/qml/qmltyperegistrar/missingTypes.json @@ -0,0 +1,167 @@ +[ + { + "classes": [ + { + "classInfos": [ + { + "name": "QML.Element", + "value": "int" + }, + { + "name": "QML.Extended", + "value": "QQmlIntForeign" + }, + { + "name": "QML.Foreign", + "value": "int" + } + ], + "className": "QQmlIntForeign", + "gadget": true, + "qualifiedClassName": "QQmlIntForeign" + }, + { + "classInfos": [ + { + "name": "QML.Element", + "value": "auto" + } + ], + "className": "ExcessiveVersion", + "object": true, + "properties": [ + { + "constant": false, + "designable": true, + "final": false, + "index": 0, + "name": "palette", + "notify": "paletteChanged", + "read": "palette", + "required": false, + "revision": 1536, + "scriptable": true, + "stored": true, + "type": "int", + "user": false, + "write": "setPalette" + } + ], + "enums": [ + { + "isClass": false, + "isFlag": false, + "name": "RestorationMode", + "type": "NotAnUnderlyingType", + "values": [ + "RestoreNone", + "RestoreBinding", + "RestoreValue", + "RestoreBindingOrValue" + ] + } + ], + "qualifiedClassName": "ExcessiveVersion", + "signals": [ + { + "access": "public", + "name": "paletteChanged", + "returnType": "void", + "revision": 1536 + } + ], + "superClasses": [ + { + "access": "public", + "name": "NotQObject" + } + ] + }, + { + "classInfos": [ + { + "name": "QML.Element", + "value": "Versioned" + }, + { + "name": "QML.AddedInVersion", + "value": "264" + } + ], + "className": "AddedInLateVersion", + "object": true, + "properties": [ + { + "constant": true, + "designable": true, + "final": false, + "index": 0, + "name": "revisioned", + "read": "revisioned", + "required": false, + "revision": 260, + "scriptable": true, + "stored": true, + "type": "NotAPropertyType", + "user": false + } + ], + "methods": [ + { + "access": "public", + "arguments": [ + { + "type": "NotAnArgumentType" + } + ], + "name": "createAThing", + "returnType": "NotAReturnType" + } + ], + "qualifiedClassName": "AddedInLateVersion", + "superClasses": [ + { + "access": "public", + "name": "NotQObject" + } + ] + }, + { + "classInfos": [ + { + "name": "QML.Foreign", + "value": "Invisible" + }, + { + "name": "QML.Element", + "value": "Invisible" + } + ], + "className": "InvisibleForeign", + "gadget": true, + "qualifiedClassName": "InvisibleForeign" + }, + { + "classInfos": [ + { + "name": "QML.Element", + "value": "anonymous" + }, + { + "name": "QML.Sequence", + "value": "NotQByteArray" + }, + { + "name": "QML.Foreign", + "value": "std::vector<NotQByteArray>" + } + ], + "className": "NotQByteArrayStdVectorForeign", + "gadget": true, + "qualifiedClassName": "NotQByteArrayStdVectorForeign" + } + ], + "inputFile": "tst_qmltyperegistrar.h", + "outputRevision": 68 + } +] diff --git a/tests/auto/qml/qmltyperegistrar/noextheader b/tests/auto/qml/qmltyperegistrar/noextheader index 1bad168044..2b3579a34b 100644 --- a/tests/auto/qml/qmltyperegistrar/noextheader +++ b/tests/auto/qml/qmltyperegistrar/noextheader @@ -1,5 +1,5 @@ // Copyright (C) 2020 The Qt Company Ltd. -// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only #ifndef NOEXTHEADER #define NOEXTHEADER diff --git a/tests/auto/qml/qmltyperegistrar/tst_qmltyperegistrar.cpp b/tests/auto/qml/qmltyperegistrar/tst_qmltyperegistrar.cpp index a0f9a92b5c..e79e9b84b6 100644 --- a/tests/auto/qml/qmltyperegistrar/tst_qmltyperegistrar.cpp +++ b/tests/auto/qml/qmltyperegistrar/tst_qmltyperegistrar.cpp @@ -1,5 +1,5 @@ // Copyright (C) 2021 The Qt Company Ltd. -// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only #include "tst_qmltyperegistrar.h" #include <QtTest/qtest.h> @@ -116,8 +116,8 @@ void tst_qmltyperegistrar::pastMajorVersions() void tst_qmltyperegistrar::implementsInterfaces() { - QVERIFY(qmltypesData.contains("interfaces: [\"Interface\"]")); - QVERIFY(qmltypesData.contains("interfaces: [\"Interface\", \"Interface2\"]")); + QVERIFY(qmltypesData.contains("interfaces: [\"Interface1\"]")); + QVERIFY(qmltypesData.contains("interfaces: [\"Interface1\", \"Interface2\"]")); } void tst_qmltyperegistrar::namespacedElement() @@ -145,9 +145,9 @@ void tst_qmltyperegistrar::metaTypesRegistered() auto verifyMetaType = [](const char *name, const char *className) { const auto foundMetaType = QMetaType::fromName(name); - QVERIFY(foundMetaType.isValid()); + QVERIFY2(foundMetaType.isValid(), name); QCOMPARE(foundMetaType.name(), name); - QVERIFY(foundMetaType.metaObject()); + QVERIFY2(foundMetaType.metaObject(), name); QCOMPARE(foundMetaType.metaObject()->className(), className); }; @@ -356,6 +356,12 @@ void tst_qmltyperegistrar::addRemoveVersion() QCOMPARE(o->property("thing").toInt(), thingAccessible ? 24 : 0); } +void tst_qmltyperegistrar::addInMinorVersion() +{ + QVERIFY(qmltypesData.contains("exports: [\"QmlTypeRegistrarTest/MinorVersioned 1.5\"]")); + QVERIFY(qmltypesData.contains("exports: [\"QmlTypeRegistrarTest/MinorVersioned 1.2\"]")); +} + #ifdef QT_QUICK_LIB void tst_qmltyperegistrar::foreignRevisionedProperty() { @@ -398,23 +404,83 @@ void tst_qmltyperegistrar::duplicateExportWarnings() MetaTypesJsonProcessor processor(true); QVERIFY(processor.processTypes({ ":/duplicatedExports.json" })); processor.postProcessTypes(); - QVector<QJsonObject> types = processor.types(); - QVector<QJsonObject> typesforeign = processor.foreignTypes(); + QVector<MetaType> types = processor.types(); + QVector<MetaType> typesforeign = processor.foreignTypes(); r.setTypes(types, typesforeign); - auto expectWarning = [](QString message) { - QTest::ignoreMessage(QtWarningMsg, qPrintable(message)); + const auto expectWarning = [](const char *message) { + QTest::ignoreMessage(QtWarningMsg, message); }; - expectWarning("Warning: ExportedQmlElement was registered multiple times by following Cpp " - "classes: ExportedQmlElement, ExportedQmlElement2 (added in 1.2), " - "ExportedQmlElementDifferentVersion (added in 1.0) (removed in 1.7)"); - expectWarning("Warning: SameNameSameExport was registered multiple times by following Cpp " - "classes: SameNameSameExport, SameNameSameExport2 (added in 1.2), " - "SameNameSameExportDifferentVersion (added in 1.0)"); + expectWarning("Warning: duplicatedExports.h:: ExportedQmlElement is registered multiple times " + "by the following C++ classes: ExportedQmlElement, ExportedQmlElement2 " + "(added in 1.2), ExportedQmlElementDifferentVersion (added in 1.0) " + "(removed in 1.7)"); + expectWarning("Warning: duplicatedExports.h:: SameNameSameExport is registered multiple times " + "by the following C++ classes: SameNameSameExport, SameNameSameExport2 " + "(added in 1.2), SameNameSameExportDifferentVersion (added in 1.0)"); QString outputData; QTextStream output(&outputData, QIODeviceBase::ReadWrite); - r.write(output); + r.write(output, "tst_qmltyperegistrar_qmltyperegistrations.cpp"); +} + +void tst_qmltyperegistrar::consistencyWarnings() +{ + QmlTypeRegistrar r; + r.setModuleVersions(QTypeRevision::fromVersion(1, 1), {}, false); + QString moduleName = "tstmodule"; + QString targetNamespace = "tstnamespace"; + r.setModuleNameAndNamespace(moduleName, targetNamespace); + + MetaTypesJsonProcessor processor(true); + + QVERIFY(processor.processTypes({ ":/missingTypes.json" })); + processor.postProcessTypes(); + + const auto expectWarning = [](const char *message) { + QTest::ignoreMessage(QtWarningMsg, message); + }; + + expectWarning("Warning: tst_qmltyperegistrar.h:: " + "NotQObject is used as base type but cannot be found."); + expectWarning("Warning: tst_qmltyperegistrar.h:: NotQObject is used as base type " + "but cannot be found."); + expectWarning("Warning: tst_qmltyperegistrar.h:: Invisible is declared as foreign type, " + "but cannot be found."); + expectWarning("Warning: tst_qmltyperegistrar.h:: NotQByteArray is used as sequence value type " + "but cannot be found."); + expectWarning("Warning: tst_qmltyperegistrar.h:: NotAPropertyType is used as property type " + "but cannot be found."); + expectWarning("Warning: tst_qmltyperegistrar.h:: NotAnArgumentType is used as argument type " + "but cannot be found."); + expectWarning("Warning: tst_qmltyperegistrar.h:: NotAReturnType is used as return type " + "but cannot be found."); + expectWarning("Warning: tst_qmltyperegistrar.h:: NotAnUnderlyingType is used as enum type " + "but cannot be found."); + + processor.postProcessForeignTypes(); + + QVector<MetaType> types = processor.types(); + QVector<MetaType> typesforeign = processor.foreignTypes(); + r.setTypes(types, typesforeign); + + QString outputData; + QTextStream output(&outputData, QIODeviceBase::ReadWrite); + + expectWarning("Warning: tst_qmltyperegistrar.h:: AddedInLateVersion is trying to register " + "property revisioned with future version 1.4 when module version is only 1.1"); + expectWarning("Warning: tst_qmltyperegistrar.h:: ExcessiveVersion is trying to register " + "property palette with future version 6.0 when module version is only 1.1"); + + r.write(output, "tst_qmltyperegistrar_qmltyperegistrations.cpp"); + + QTemporaryFile pluginTypes; + QVERIFY(pluginTypes.open()); + + expectWarning("Warning: tst_qmltyperegistrar.h:: Refusing to generate non-lowercase name " + "Invisible for unknown foreign type"); + + r.generatePluginTypes(pluginTypes.fileName()); } void tst_qmltyperegistrar::clonedSignal() @@ -432,17 +498,17 @@ void tst_qmltyperegistrar::hasIsConstantInParameters() QVERIFY(qmltypesData.contains(R"( Signal { name: "mySignal" Parameter { name: "myObject"; type: "QObject"; isPointer: true } - Parameter { name: "myConstObject"; type: "QObject"; isPointer: true; isConstant: true } - Parameter { name: "myConstObject2"; type: "QObject"; isPointer: true; isConstant: true } + Parameter { name: "myConstObject"; type: "QObject"; isPointer: true; isTypeConstant: true } + Parameter { name: "myConstObject2"; type: "QObject"; isPointer: true; isTypeConstant: true } Parameter { name: "myObject2"; type: "QObject"; isPointer: true } - Parameter { name: "myConstObject3"; type: "QObject"; isPointer: true; isConstant: true } + Parameter { name: "myConstObject3"; type: "QObject"; isPointer: true; isTypeConstant: true } } )")); QVERIFY(qmltypesData.contains(R"(Signal { name: "myVolatileSignal" - Parameter { name: "a"; type: "volatile QObject"; isPointer: true; isConstant: true } - Parameter { name: "b"; type: "volatile QObject"; isPointer: true; isConstant: true } + Parameter { name: "a"; type: "volatile QObject"; isPointer: true; isTypeConstant: true } + Parameter { name: "b"; type: "volatile QObject"; isPointer: true; isTypeConstant: true } Parameter { name: "nonConst"; type: "volatile QObject"; isPointer: true } } )")); @@ -450,70 +516,101 @@ void tst_qmltyperegistrar::hasIsConstantInParameters() void tst_qmltyperegistrar::uncreatable() { + using namespace QQmlPrivate; + // "normal" constructible types - QVERIFY(QQmlPrivate::QmlMetaType<Creatable>::hasAcceptableCtors()); - QVERIFY(QQmlPrivate::QmlMetaType<Creatable2>::hasAcceptableCtors()); + QVERIFY(QmlMetaType<Creatable>::hasAcceptableCtors()); + QVERIFY(QmlMetaType<Creatable2>::hasAcceptableCtors()); // good singletons - QVERIFY(QQmlPrivate::QmlMetaType<SingletonCreatable>::hasAcceptableSingletonCtors()); - QVERIFY(QQmlPrivate::QmlMetaType<SingletonCreatable2>::hasAcceptableSingletonCtors()); - QVERIFY(QQmlPrivate::QmlMetaType<SingletonCreatable3>::hasAcceptableSingletonCtors()); + QCOMPARE((singletonConstructionMode<SingletonCreatable, SingletonCreatable>()), + SingletonConstructionMode::Factory); + QCOMPARE((singletonConstructionMode<SingletonCreatable2, SingletonCreatable2>()), + SingletonConstructionMode::Constructor); + QCOMPARE((singletonConstructionMode<SingletonCreatable2, SingletonCreatable2>()), + SingletonConstructionMode::Constructor); + QCOMPARE((singletonConstructionMode<SingletonForeign, SingletonLocalCreatable>()), + SingletonConstructionMode::FactoryWrapper); // bad singletons - QVERIFY(!QQmlPrivate::QmlMetaType<SingletonIncreatable>::hasAcceptableSingletonCtors()); - QVERIFY(!QQmlPrivate::QmlMetaType<SingletonIncreatable2>::hasAcceptableSingletonCtors()); - QVERIFY(!QQmlPrivate::QmlMetaType<SingletonIncreatable3>::hasAcceptableSingletonCtors()); - QVERIFY(!QQmlPrivate::QmlMetaType<SingletonIncreatable4>::hasAcceptableSingletonCtors()); - QVERIFY(!QQmlPrivate::QmlMetaType<SingletonIncreatableExtended>::hasAcceptableSingletonCtors()); + QCOMPARE((singletonConstructionMode<SingletonIncreatable, SingletonIncreatable>()), + SingletonConstructionMode::None); + QCOMPARE((singletonConstructionMode<SingletonIncreatable2, SingletonIncreatable2>()), + SingletonConstructionMode::None); + QCOMPARE((singletonConstructionMode<SingletonIncreatable3, SingletonIncreatable3>()), + SingletonConstructionMode::None); + QCOMPARE((singletonConstructionMode<SingletonIncreatable4, SingletonIncreatable4>()), + SingletonConstructionMode::None); + QCOMPARE((singletonConstructionMode<SingletonIncreatableExtended, + SingletonIncreatableExtended>()), + SingletonConstructionMode::None); + QCOMPARE((singletonConstructionMode<SingletonForeign, SingletonLocalUncreatable1>()), + SingletonConstructionMode::None); + QCOMPARE((singletonConstructionMode<SingletonForeign, SingletonLocalUncreatable2>()), + SingletonConstructionMode::None); #if QT_DEPRECATED_SINCE(6, 4) QTest::ignoreMessage( QtWarningMsg, - "Singleton SingletonIncreatable needs either a default constructor or, " - "when adding a default constructor is infeasible, a public static " - "create(QQmlEngine *, QJSEngine *) method."); + "Singleton SingletonIncreatable needs to be a concrete class with either a " + "default constructor or, when adding a default constructor is infeasible, " + "a public static create(QQmlEngine *, QJSEngine *) method."); qmlRegisterTypesAndRevisions<SingletonIncreatable>("A", 1); QTest::ignoreMessage( QtWarningMsg, - "Singleton SingletonIncreatable2 needs either a default constructor or, " - "when adding a default constructor is infeasible, a public static " - "create(QQmlEngine *, QJSEngine *) method."); + "Singleton SingletonIncreatable2 needs to be a concrete class with either a " + "default constructor or, when adding a default constructor is infeasible, " + "a public static create(QQmlEngine *, QJSEngine *) method."); qmlRegisterTypesAndRevisions<SingletonIncreatable2>("A", 1); QTest::ignoreMessage( QtWarningMsg, - "Singleton SingletonIncreatable3 needs either a default constructor or, " - "when adding a default constructor is infeasible, a public static " - "create(QQmlEngine *, QJSEngine *) method."); + "Singleton SingletonIncreatable3 needs to be a concrete class with either a " + "default constructor or, when adding a default constructor is infeasible, " + "a public static create(QQmlEngine *, QJSEngine *) method."); qmlRegisterTypesAndRevisions<SingletonIncreatable3>("A", 1); QTest::ignoreMessage( QtWarningMsg, - "Singleton SingletonIncreatable4 needs either a default constructor or, " - "when adding a default constructor is infeasible, a public static " - "create(QQmlEngine *, QJSEngine *) method."); + "Singleton SingletonIncreatable4 needs to be a concrete class with either a " + "default constructor or, when adding a default constructor is infeasible, " + "a public static create(QQmlEngine *, QJSEngine *) method."); qmlRegisterTypesAndRevisions<SingletonIncreatable4>("A", 1); QTest::ignoreMessage( QtWarningMsg, - "Singleton SingletonIncreatableExtended needs either a default constructor or, " - "when adding a default constructor is infeasible, a public static " - "create(QQmlEngine *, QJSEngine *) method."); + "Singleton SingletonIncreatableExtended needs to be a concrete class with either a " + "default constructor or, when adding a default constructor is infeasible, " + "a public static create(QQmlEngine *, QJSEngine *) method."); qmlRegisterTypesAndRevisions<SingletonIncreatableExtended>("A", 1); + QTest::ignoreMessage( + QtWarningMsg, + "Singleton SingletonForeign needs to be a concrete class with either a " + "default constructor or, when adding a default constructor is infeasible, " + "a public static create(QQmlEngine *, QJSEngine *) method."); + qmlRegisterTypesAndRevisions<SingletonLocalUncreatable1>("A", 1); + QTest::ignoreMessage( + QtWarningMsg, + "Singleton SingletonForeign needs to be a concrete class with either a " + "default constructor or, when adding a default constructor is infeasible, " + "a public static create(QQmlEngine *, QJSEngine *) method."); + qmlRegisterTypesAndRevisions<SingletonLocalUncreatable2>("A", 1); #endif // QML_UNCREATABLE types - QVERIFY(!QQmlPrivate::QmlMetaType<BadUncreatable>::hasAcceptableCtors()); - QVERIFY(!QQmlPrivate::QmlMetaType<BadUncreatableExtended>::hasAcceptableCtors()); - QVERIFY(!QQmlPrivate::QmlMetaType<GoodUncreatable>::hasAcceptableCtors()); - QVERIFY(!QQmlPrivate::QmlMetaType<UncreatableNeedsForeign>::hasAcceptableCtors()); - QVERIFY(!QQmlPrivate::QmlMetaType<GoodUncreatableExtended>::hasAcceptableCtors()); + QVERIFY(!QmlMetaType<BadUncreatable>::hasAcceptableCtors()); + QVERIFY(!QmlMetaType<BadUncreatableExtended>::hasAcceptableCtors()); + QVERIFY(!QmlMetaType<GoodUncreatable>::hasAcceptableCtors()); + QVERIFY(!QmlMetaType<UncreatableNeedsForeign>::hasAcceptableCtors()); + QVERIFY(!QmlMetaType<GoodUncreatableExtended>::hasAcceptableCtors()); #if QT_DEPRECATED_SINCE(6, 4) QTest::ignoreMessage( QtWarningMsg, - "BadUncreatable is neither a QObject, nor default- and copy-constructible, " - "nor uncreatable. You should not use it as a QML type."); + "BadUncreatable is neither a default constructible QObject, nor a default- " + "and copy-constructible Q_GADGET, nor marked as uncreatable.\n" + "You should not use it as a QML type."); qmlRegisterTypesAndRevisions<BadUncreatable>("A", 1); QTest::ignoreMessage( QtWarningMsg, - "BadUncreatableExtended is neither a QObject, nor default- and copy-constructible, " - "nor uncreatable. You should not use it as a QML type."); + "BadUncreatableExtended is neither a default constructible QObject, nor a default- " + "and copy-constructible Q_GADGET, nor marked as uncreatable.\n" + "You should not use it as a QML type."); qmlRegisterTypesAndRevisions<BadUncreatableExtended>("A", 1); #endif @@ -537,6 +634,26 @@ void tst_qmltyperegistrar::uncreatable() qmlRegisterTypesAndRevisions<GoodUncreatableExtended>("A", 1); } +void tst_qmltyperegistrar::singletonVersions() +{ + QQmlEngine engine; + qmlRegisterTypesAndRevisions<SingletonVesion0>("A", 0); + qmlRegisterTypesAndRevisions<SingletonVesion1>("B", 1); + + QQmlComponent c(&engine); + c.setData("import QtQuick\n" + "import A\n" + "import B\n" + "QtObject {\n" + " property QtObject v0: SingletonVesion0\n" + " property QtObject v1: SingletonVesion1\n" + "}", QUrl()); + QVERIFY2(c.isReady(), qPrintable(c.errorString())); + QScopedPointer<QObject> obj(c.create()); + QVERIFY2(!obj->property("v0").isNull(), "Singleton version 0 is not registered"); + QVERIFY2(!obj->property("v1").isNull(), "Singleton version 1 is not registered"); +} + void tst_qmltyperegistrar::baseVersionInQmltypes() { // Since it has no QML_ADDED_IN_VERSION, WithMethod was added in .0 of the current version. @@ -544,4 +661,428 @@ void tst_qmltyperegistrar::baseVersionInQmltypes() QVERIFY(qmltypesData.contains("exports: [\"QmlTypeRegistrarTest/WithMethod 1.0\"]")); } +void tst_qmltyperegistrar::unconstructibleValueType() +{ + QVERIFY(qmltypesData.contains( + R"(Component { + file: "tst_qmltyperegistrar.h" + name: "Unconstructible" + accessSemantics: "value" + exports: ["QmlTypeRegistrarTest/unconstructible 1.0"] + isCreatable: false + exportMetaObjectRevisions: [256] + })")); +} + +void tst_qmltyperegistrar::constructibleValueType() +{ + QVERIFY(qmltypesData.contains( + R"(Component { + file: "tst_qmltyperegistrar.h" + name: "Constructible" + accessSemantics: "value" + exports: ["QmlTypeRegistrarTest/constructible 1.0"] + exportMetaObjectRevisions: [256] + Method { + name: "Constructible" + isConstructor: true + Parameter { name: "i"; type: "int" } + } + Method { name: "Constructible"; isCloned: true; isConstructor: true } + })")); +} + +void tst_qmltyperegistrar::structuredValueType() +{ + QVERIFY(qmltypesData.contains( + R"(Component { + file: "tst_qmltyperegistrar.h" + name: "Structured" + accessSemantics: "value" + exports: ["QmlTypeRegistrarTest/structured 1.0"] + isStructured: true + exportMetaObjectRevisions: [256] + Property { name: "i"; type: "int"; index: 0; isFinal: true } + })")); +} + +void tst_qmltyperegistrar::anonymousAndUncreatable() +{ + QVERIFY(qmltypesData.contains( + R"(Component { + file: "tst_qmltyperegistrar.h" + name: "AnonymousAndUncreatable" + accessSemantics: "reference" + prototype: "QObject" + })")); +} + +void tst_qmltyperegistrar::omitInvisible() +{ + // If it cannot resolve the type a QML_FOREIGN refers to, it should not generate anything. + QVERIFY(qmltypesData.contains( + R"(Component { file: "tst_qmltyperegistrar.h"; name: "Invisible"; accessSemantics: "none" })")); +} + +void tst_qmltyperegistrar::typedEnum() +{ + QVERIFY(qmltypesData.contains( + R"(Component { + file: "tst_qmltyperegistrar.h" + name: "TypedEnum" + accessSemantics: "reference" + prototype: "QObject" + exports: ["QmlTypeRegistrarTest/TypedEnum 1.0"] + exportMetaObjectRevisions: [256] + Enum { + name: "UChar" + type: "quint8" + values: ["V0"] + } + Enum { + name: "Int8_T" + type: "qint8" + values: ["V1"] + } + Enum { + name: "UInt8_T" + type: "quint8" + values: ["V2"] + } + Enum { + name: "Int16_T" + type: "short" + values: ["V3"] + } + Enum { + name: "UInt16_T" + type: "ushort" + values: ["V4"] + } + Enum { + name: "Int32_T" + type: "int" + values: ["V5"] + } + Enum { + name: "UInt32_T" + type: "uint" + values: ["V6"] + } + Enum { + name: "S" + type: "short" + values: ["A", "B", "C"] + } + Enum { + name: "T" + type: "ushort" + values: ["D", "E", "F"] + } + Enum { + name: "U" + type: "qint8" + values: ["G", "H", "I"] + } + Enum { + name: "V" + type: "quint8" + values: ["J", "K", "L"] + } + })")); +} + +void tst_qmltyperegistrar::listSignal() +{ + QVERIFY(qmltypesData.contains( + R"(Component { + file: "tst_qmltyperegistrar.h" + name: "ListSignal" + accessSemantics: "reference" + prototype: "QObject" + Signal { + name: "objectListHappened" + Parameter { type: "QObjectList" } + } + })")); +} + +void tst_qmltyperegistrar::withNamespace() +{ + QVERIFY(qmltypesData.contains(R"(Component { + file: "tst_qmltyperegistrar.h" + name: "Bar" + accessSemantics: "reference" + prototype: "QObject" + Property { + name: "outerBarProp" + type: "int" + read: "bar" + index: 0 + isReadonly: true + isPropertyConstant: true + } + })")); + + QVERIFY(qmltypesData.contains(R"(Component { + file: "tst_qmltyperegistrar.h" + name: "Testing::Bar" + accessSemantics: "reference" + prototype: "Testing::Foo" + exports: ["QmlTypeRegistrarTest/Bar 1.0"] + exportMetaObjectRevisions: [256] + Property { + name: "barProp" + type: "int" + read: "bar" + index: 0 + isReadonly: true + isPropertyConstant: true + } + })")); + + QVERIFY(qmltypesData.contains(R"(Component { + file: "tst_qmltyperegistrar.h" + name: "Testing::Foo" + accessSemantics: "reference" + prototype: "QObject" + Property { + name: "fooProp" + type: "int" + read: "foo" + index: 0 + isReadonly: true + isPropertyConstant: true + } + })")); + + QVERIFY(qmltypesData.contains(R"(Component { + file: "tst_qmltyperegistrar.h" + name: "Testing::Inner::Baz" + accessSemantics: "reference" + prototype: "Testing::Bar" + extension: "Bar" + exports: ["QmlTypeRegistrarTest/Baz 1.0"] + exportMetaObjectRevisions: [256] + attachedType: "Testing::Foo" + })")); +} + +void tst_qmltyperegistrar::sequenceRegistration() +{ + QVERIFY(qmltypesData.contains(R"(Component { + file: "tst_qmltyperegistrar.h" + name: "std::vector<QByteArray>" + accessSemantics: "sequence" + valueType: "QByteArray" + })")); +} + +void tst_qmltyperegistrar::valueTypeSelfReference() +{ + QVERIFY(qmltypesData.contains(R"(Component { + file: "tst_qmltyperegistrar.h" + name: "QPersistentModelIndex" + accessSemantics: "value" + extension: "QPersistentModelIndexValueType" + })")); + QVERIFY(qmltypesData.contains(R"(Component { + file: "tst_qmltyperegistrar.h" + name: "QPersistentModelIndexValueType" + accessSemantics: "value" + Property { name: "row"; type: "int"; read: "row"; index: 0; isReadonly: true; isFinal: true } + })")); +} + +void tst_qmltyperegistrar::foreignNamespaceFromGadget() +{ + QQmlEngine engine; + { + QQmlComponent c(&engine); + c.setData(QStringLiteral(R"( + import QtQml + import QmlTypeRegistrarTest + QtObject { + objectName: 'b' + NetworkManager.B + } + )").toUtf8(), QUrl("foreignNamespaceFromGadget.qml")); + QVERIFY2(c.isReady(), qPrintable(c.errorString())); + QScopedPointer<QObject> o(c.create()); + QCOMPARE(o->objectName(), QStringLiteral("b1")); + } + + { + QQmlComponent c(&engine); + c.setData(QStringLiteral(R"( + import QtQml + import QmlTypeRegistrarTest + QtObject { + objectName: 'b' + NotNamespaceForeign.B + } + )").toUtf8(), QUrl("foreignNamespaceFromGadget2.qml")); + QVERIFY2(c.isReady(), qPrintable(c.errorString())); + QScopedPointer<QObject> o(c.create()); + QCOMPARE(o->objectName(), QStringLiteral("b1")); + } +} + +void tst_qmltyperegistrar::nameExplosion_data() +{ + QTest::addColumn<QByteArray>("qml"); + QTest::addRow("Name1") << QByteArray("import QmlTypeRegistrarTest\nName1{}"); + QTest::addRow("Name2") << QByteArray("import QmlTypeRegistrarTest\nName2{}"); + QTest::addRow("NameExplosion") << QByteArray("import QmlTypeRegistrarTest\nNameExplosion{}"); +} + +void tst_qmltyperegistrar::nameExplosion() +{ + QVERIFY(qmltypesData.contains(R"(Component { + file: "tst_qmltyperegistrar.h" + name: "NameExplosion" + accessSemantics: "reference" + prototype: "QObject" + exports: [ + "QmlTypeRegistrarTest/Name1 1.0", + "QmlTypeRegistrarTest/Name2 1.0", + "QmlTypeRegistrarTest/NameExplosion 1.0" + ] + exportMetaObjectRevisions: [256] + })")); + + QFETCH(QByteArray, qml); + + QQmlEngine engine; + QQmlComponent c(&engine); + + c.setData(qml, QUrl()); + QVERIFY2(c.isReady(), qPrintable(c.errorString())); + QScopedPointer<QObject> o(c.create()); + QVERIFY(!o.isNull()); +} + +void tst_qmltyperegistrar::javaScriptExtension() +{ + QVERIFY(qmltypesData.contains(R"(Component { + file: "tst_qmltyperegistrar.h" + name: "JavaScriptExtension" + accessSemantics: "reference" + prototype: "QObject" + extension: "SymbolPrototype" + extensionIsJavaScript: true + exports: ["QmlTypeRegistrarTest/JavaScriptExtension 1.0"] + exportMetaObjectRevisions: [256] + })")); +} + +void tst_qmltyperegistrar::relatedAddedInVersion() +{ + QVERIFY(qmltypesData.contains(R"(Component { + file: "tst_qmltyperegistrar.h" + name: "AddedIn1_0" + accessSemantics: "reference" + prototype: "AddedIn1_5" + exports: [ + "QmlTypeRegistrarTest/AddedIn1_0 1.0", + "QmlTypeRegistrarTest/AddedIn1_0 1.5" + ] + exportMetaObjectRevisions: [256, 261] + })")); +} + +void tst_qmltyperegistrar::longNumberTypes() +{ + QVERIFY(qmltypesData.contains(R"(Component { + file: "tst_qmltyperegistrar.h" + name: "LongNumberTypes" + accessSemantics: "reference" + prototype: "QObject" + exports: ["QmlTypeRegistrarTest/LongNumberTypes 1.0"] + exportMetaObjectRevisions: [256] + Property { name: "a"; type: "qlonglong"; index: 0 } + Property { name: "b"; type: "qlonglong"; index: 1 } + Property { name: "c"; type: "qulonglong"; index: 2 } + Property { name: "d"; type: "qulonglong"; index: 3 } + })")); +} + +void tst_qmltyperegistrar::enumList() { + QVERIFY(qmltypesData.contains(R"(Component { + file: "tst_qmltyperegistrar.h" + name: "QList<NetworkManager::NM>" + accessSemantics: "sequence" + valueType: "NetworkManager::NM" + })")); +} + +void tst_qmltyperegistrar::constReturnType() +{ + QVERIFY(qmltypesData.contains(R"(Component { + file: "tst_qmltyperegistrar.h" + name: "ConstInvokable" + accessSemantics: "reference" + prototype: "QObject" + exports: ["QmlTypeRegistrarTest/ConstInvokable 1.0"] + exportMetaObjectRevisions: [256] + Method { name: "getObject"; type: "QObject"; isPointer: true; isTypeConstant: true } + })")); +} + +void tst_qmltyperegistrar::usingDeclaration() +{ + QVERIFY(qmltypesData.contains(R"(Component { + file: "tst_qmltyperegistrar.h" + name: "WithMyInt" + accessSemantics: "reference" + prototype: "QObject" + exports: ["QmlTypeRegistrarTest/WithMyInt 1.0"] + exportMetaObjectRevisions: [256] + Property { name: "a"; type: "int"; read: "a"; index: 0; isReadonly: true; isPropertyConstant: true } + })")); +} + +void tst_qmltyperegistrar::enumsRegistered() +{ + QCOMPARE(QMetaType::fromName("SizeEnums::Unit"), QMetaType::fromType<SizeEnums::Unit>()); + QCOMPARE(QMetaType::fromName("Local::Flag"), QMetaType::fromType<Local::Flag>()); + QCOMPARE(QMetaType::fromName("Local::Flags"), QMetaType::fromType<Local::Flags>()); + QCOMPARE(QMetaType::fromName("ValueTypeWithEnum1::Quality"), + QMetaType::fromType<ValueTypeWithEnum1::Quality>()); + QCOMPARE(QMetaType::fromName("ValueTypeWithEnum2::Quality"), + QMetaType::fromType<ValueTypeWithEnum2::Quality>()); + QCOMPARE(QMetaType::fromName("BaseNamespace::BBB"), QMetaType::fromType<BaseNamespace::BBB>()); + QCOMPARE(QMetaType::fromName("ExtensionValueType::EEE"), + QMetaType::fromType<ExtensionValueType::EEE>()); + QCOMPARE(QMetaType::fromName("TypedEnum::UChar"), QMetaType::fromType<TypedEnum::UChar>()); + QCOMPARE(QMetaType::fromName("TypedEnum::Int8_T"), QMetaType::fromType<TypedEnum::Int8_T>()); + QCOMPARE(QMetaType::fromName("TypedEnum::UInt8_T"), QMetaType::fromType<TypedEnum::UInt8_T>()); + QCOMPARE(QMetaType::fromName("TypedEnum::Int16_T"), QMetaType::fromType<TypedEnum::Int16_T>()); + QCOMPARE(QMetaType::fromName("TypedEnum::UInt16_T"), QMetaType::fromType<TypedEnum::UInt16_T>()); + QCOMPARE(QMetaType::fromName("TypedEnum::Int32_T"), QMetaType::fromType<TypedEnum::Int32_T>()); + QCOMPARE(QMetaType::fromName("TypedEnum::UInt32_T"), QMetaType::fromType<TypedEnum::UInt32_T>()); + QCOMPARE(QMetaType::fromName("TypedEnum::S"), QMetaType::fromType<TypedEnum::S>()); + QCOMPARE(QMetaType::fromName("TypedEnum::T"), QMetaType::fromType<TypedEnum::T>()); + QCOMPARE(QMetaType::fromName("TypedEnum::U"), QMetaType::fromType<TypedEnum::U>()); + QCOMPARE(QMetaType::fromName("TypedEnum::V"), QMetaType::fromType<TypedEnum::V>()); + QCOMPARE(QMetaType::fromName("NetworkManager::NM"), QMetaType::fromType<NetworkManager::NM>()); + QCOMPARE(QMetaType::fromName("NotNamespace::Abc"), QMetaType::fromType<NotNamespace::Abc>()); +} + +void tst_qmltyperegistrar::doNotDuplicateQtNamespace() +{ + QVERIFY(!qmltypesData.contains(R"(file: "qnamespace.h")")); +} + +void tst_qmltyperegistrar::slotsBeforeInvokables() +{ + QVERIFY(qmltypesData.contains(R"(Component { + file: "tst_qmltyperegistrar.h" + name: "SlotsBeforeInvokables" + accessSemantics: "reference" + prototype: "QObject" + Method { name: "bar" } + Method { name: "foo" } + Method { name: "baz" } + })")); +} + QTEST_MAIN(tst_qmltyperegistrar) diff --git a/tests/auto/qml/qmltyperegistrar/tst_qmltyperegistrar.h b/tests/auto/qml/qmltyperegistrar/tst_qmltyperegistrar.h index df755472d7..1eff2af024 100644 --- a/tests/auto/qml/qmltyperegistrar/tst_qmltyperegistrar.h +++ b/tests/auto/qml/qmltyperegistrar/tst_qmltyperegistrar.h @@ -1,46 +1,50 @@ // Copyright (C) 2020 The Qt Company Ltd. -// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only #ifndef TST_QMLTYPEREGISTRAR_H #define TST_QMLTYPEREGISTRAR_H #include "foreign.h" -#include "foreign_p.h" +#include "private/foreign_p.h" -#include <QtQml/qqml.h> -#include <QtQml/qqmlcomponent.h> -#include <QtCore/qproperty.h> -#include <QtCore/qtimeline.h> -#include <QtCore/qrect.h> #include <QtQmlTypeRegistrar/private/qqmltyperegistrar_p.h> -#include <QtCore/qtemporaryfile.h> #ifdef QT_QUICK_LIB # include <QtQuick/qquickitem.h> #endif -class Interface {}; +#include <QtQml/qqml.h> +#include <QtQml/qqmlcomponent.h> + +#include <QtCore/qabstractitemmodel.h> +#include <QtCore/qnamespace.h> +#include <QtCore/qproperty.h> +#include <QtCore/qrect.h> +#include <QtCore/qtemporaryfile.h> +#include <QtCore/qtimeline.h> + +class Interface1 {}; class Interface2 {}; class Interface3 {}; QT_BEGIN_NAMESPACE -Q_DECLARE_INTERFACE(Interface, "io.qt.bugreports.Interface"); +Q_DECLARE_INTERFACE(Interface1, "io.qt.bugreports.Interface1"); Q_DECLARE_INTERFACE(Interface2, "io.qt.bugreports.Interface2"); Q_DECLARE_INTERFACE(Interface3, "io.qt.bugreports.Interface3"); QT_END_NAMESPACE -class ImplementsInterfaces : public QObject, public Interface +class ImplementsInterfaces : public QObject, public Interface1 { Q_OBJECT QML_ELEMENT - QML_IMPLEMENTS_INTERFACES(Interface) + QML_IMPLEMENTS_INTERFACES(Interface1) }; -class ImplementsInterfaces2 : public QObject, public Interface, public Interface2 +class ImplementsInterfaces2 : public QObject, public Interface1, public Interface2 { Q_OBJECT QML_ELEMENT - QML_IMPLEMENTS_INTERFACES(Interface Interface2) + QML_IMPLEMENTS_INTERFACES(Interface1 Interface2) }; class ExcessiveVersion : public QObject @@ -458,6 +462,29 @@ public: int revisioned() const { return 24; } }; +class AddedInLateMinorVersion : public QObject +{ + Q_OBJECT + QML_ADDED_IN_VERSION(1, 5) + Q_PROPERTY(int revisioned READ revisioned CONSTANT) + QML_NAMED_ELEMENT(MinorVersioned) +public: + AddedInLateMinorVersion(QObject *parent = nullptr) : QObject(parent) {} + int revisioned() const { return 123; } +}; + +class RemovedInLateMinorVersion : public QObject +{ + Q_OBJECT + QML_ADDED_IN_VERSION(1, 2) + QML_REMOVED_IN_VERSION(1, 4) + Q_PROPERTY(int revisioned READ revisioned CONSTANT) + QML_NAMED_ELEMENT(MinorVersioned) +public: + RemovedInLateMinorVersion(QObject *parent = nullptr) : QObject(parent) { } + int revisioned() const { return 456; } +}; + class RemovedInEarlyVersion : public AddedInLateVersion { Q_OBJECT @@ -468,6 +495,23 @@ public: RemovedInEarlyVersion(QObject *parent = nullptr) : AddedInLateVersion(parent) {} }; +class AddedIn1_5 : public QObject +{ + Q_OBJECT + QML_ELEMENT + QML_ADDED_IN_VERSION(1, 5) +}; + +// Slightly absurd. The reason for such a thing may be a change in the versioning +// scheme of the base class. We still have to retain all of the version information +// so that you can at least use version 1.5. +class AddedIn1_0 : public AddedIn1_5 +{ + Q_OBJECT + QML_ELEMENT + QML_ADDED_IN_VERSION(1, 0) +}; + class HasResettableProperty : public QObject { Q_OBJECT @@ -501,6 +545,293 @@ signals: void clonedSignal(int i = 7); }; +class Unconstructible +{ + Q_GADGET + QML_VALUE_TYPE(unconstructible) + int m_i = 11; +}; + +class Constructible +{ + Q_GADGET + QML_VALUE_TYPE(constructible) + QML_CONSTRUCTIBLE_VALUE +public: + Q_INVOKABLE Constructible(int i = 12) : m_i(i) {} + +private: + int m_i; +}; + +class Structured +{ + Q_GADGET + QML_VALUE_TYPE(structured) + QML_STRUCTURED_VALUE + Q_PROPERTY(int i MEMBER m_i FINAL) + +private: + int m_i; +}; + +class AnonymousAndUncreatable : public QObject +{ + Q_OBJECT + QML_ANONYMOUS + QML_UNCREATABLE("Pointless uncreatable message") +}; + +class Invisible : public QObject +{ +}; + +struct InvisibleForeign +{ + Q_GADGET + QML_FOREIGN(Invisible) + QML_NAMED_ELEMENT(Invisible) +}; + +class TypedEnum : public QObject +{ + Q_OBJECT + QML_ELEMENT +public: + enum UChar: uchar { V0 = 41 }; + Q_ENUM(UChar) + enum Int8_T: int8_t { V1 = 42 }; + Q_ENUM(Int8_T) + enum UInt8_T: uint8_t { V2 = 43 }; + Q_ENUM(UInt8_T) + enum Int16_T: int16_t { V3 = 44 }; + Q_ENUM(Int16_T) + enum UInt16_T: uint16_t { V4 = 45 }; + Q_ENUM(UInt16_T) + enum Int32_T: int32_t { V5 = 46 }; + Q_ENUM(Int32_T) + enum UInt32_T: uint32_t { V6 = 47 }; + Q_ENUM(UInt32_T) + + // TODO: We cannot handle 64bit numbers as underlying types for enums. + // Luckily, moc generates bad code for those. So we don't have to, for now. + + enum S: qint16 { + A, B, C + }; + Q_ENUM(S) + + enum T: quint16 { + D, E, F + }; + Q_ENUM(T) + + enum U: qint8 { + G, H, I + }; + Q_ENUM(U) + + enum V: quint8 { + J, K, L + }; + Q_ENUM(V) +}; + +class ListSignal : public QObject +{ + Q_OBJECT + QML_ANONYMOUS + +Q_SIGNALS: + void objectListHappened(const QList<QObject *> &); +}; + +class Bar : public QObject +{ + Q_OBJECT + Q_PROPERTY(int outerBarProp READ bar CONSTANT) +public: + Bar(QObject *parent = nullptr) : QObject(parent) {} + int bar() const { return 44; } +}; + +namespace Testing { + +class Foo : public QObject +{ + Q_OBJECT + Q_PROPERTY(int fooProp READ foo CONSTANT) + +public: + int foo() const { return 42; } +}; + +class Bar : public Foo +{ + Q_OBJECT + QML_ELEMENT + Q_PROPERTY(int barProp READ bar CONSTANT) + +public: + int bar() const { return 43; } +}; + +namespace Inner { + +class Baz : public Bar +{ + Q_OBJECT + QML_ELEMENT + + QML_EXTENDED(::Bar) + QML_ATTACHED(Foo) + +public: + static Foo *qmlAttachedProperties(QObject *) { return new Foo; } +}; + +} // namespace Inner +} // namespace Testing + +struct QByteArrayStdVectorForeign +{ + Q_GADGET + QML_ANONYMOUS + QML_SEQUENTIAL_CONTAINER(QByteArray) + QML_FOREIGN(std::vector<QByteArray>) +}; + +// Anonymous value type for an unknown foreign type +struct QPersistentModelIndexValueType +{ + QPersistentModelIndex v; + Q_PROPERTY(int row READ row FINAL) + Q_GADGET + QML_ANONYMOUS + QML_EXTENDED(QPersistentModelIndexValueType) + QML_FOREIGN(QPersistentModelIndex) + +public: + inline int row() const { return v.row(); } +}; + + +namespace NetworkManager { +Q_NAMESPACE + +enum NM { A, B, C}; +Q_ENUM_NS(NM) +} + +struct NMForeign +{ + Q_GADGET + QML_NAMED_ELEMENT(NetworkManager) + QML_FOREIGN_NAMESPACE(NetworkManager) +}; + +struct NotNamespace { + Q_GADGET +public: + enum Abc { + A, B, C, D + }; + Q_ENUM(Abc); +}; + +struct NotNamespaceForeign { + Q_GADGET + QML_FOREIGN_NAMESPACE(NotNamespace) + QML_ELEMENT +}; + +class NameExplosion : public QObject +{ + Q_OBJECT + QML_NAMED_ELEMENT(Name1) + QML_NAMED_ELEMENT(Name2) + QML_ELEMENT + QML_ANONYMOUS +}; + +class JavaScriptExtension : public QObject +{ + Q_OBJECT + QML_ELEMENT + Q_CLASSINFO("QML.Extended", "SymbolPrototype") + Q_CLASSINFO("QML.ExtensionIsJavaScript", "true") +}; + +class LongNumberTypes : public QObject +{ + Q_OBJECT + QML_ELEMENT + Q_PROPERTY(qint64 a MEMBER m_a) + Q_PROPERTY(int64_t b MEMBER m_b) + Q_PROPERTY(quint64 c MEMBER m_c) + Q_PROPERTY(uint64_t d MEMBER m_d) + + qint64 m_a = 1; + int64_t m_b = 2; + quint64 m_c = 3; + uint64_t m_d = 4; +}; + +struct EnumList +{ + Q_GADGET + QML_ANONYMOUS + QML_FOREIGN(QList<NetworkManager::NM>) + QML_SEQUENTIAL_CONTAINER(NetworkManager::NM) +}; + +class ConstInvokable : public QObject +{ + Q_OBJECT + QML_ELEMENT +public: + Q_INVOKABLE const QObject *getObject() { return nullptr; } +}; + +using myint = int; + +struct IntAlias +{ + Q_GADGET + QML_FOREIGN(myint) + QML_USING(int); +}; + +class WithMyInt : public QObject +{ + Q_OBJECT + QML_ELEMENT + Q_PROPERTY(myint a READ a CONSTANT) +public: + myint a() const { return 10; } +}; + +class UsesQtNamespace : public QObject +{ + Q_OBJECT + QML_ANONYMOUS + Q_PROPERTY(Qt::Key key READ key CONSTANT) +public: + Qt::Key key() const { return Qt::Key_Escape; } +}; + +class SlotsBeforeInvokables : public QObject +{ + Q_OBJECT + QML_ANONYMOUS +public: + Q_INVOKABLE void foo() {} +public Q_SLOTS: + void bar() {} +public: + Q_INVOKABLE void baz() {} +}; + class tst_qmltyperegistrar : public QObject { Q_OBJECT @@ -537,6 +868,7 @@ private slots: void methodReturnType(); void hasIsConstantInParameters(); void uncreatable(); + void singletonVersions(); #ifdef QT_QUICK_LIB void foreignRevisionedProperty(); @@ -544,11 +876,39 @@ private slots: void addRemoveVersion_data(); void addRemoveVersion(); + void addInMinorVersion(); void typeInModuleMajorVersionZero(); void resettableProperty(); void duplicateExportWarnings(); void clonedSignal(); void baseVersionInQmltypes(); + void unconstructibleValueType(); + void constructibleValueType(); + void structuredValueType(); + void anonymousAndUncreatable(); + void omitInvisible(); + void typedEnum(); + void listSignal(); + void withNamespace(); + void sequenceRegistration(); + void valueTypeSelfReference(); + void foreignNamespaceFromGadget(); + + void nameExplosion_data(); + void nameExplosion(); + + void javaScriptExtension(); + + void consistencyWarnings(); + void relatedAddedInVersion(); + void longNumberTypes(); + void enumList(); + void constReturnType(); + + void usingDeclaration(); + void enumsRegistered(); + void doNotDuplicateQtNamespace(); + void slotsBeforeInvokables(); private: QByteArray qmltypesData; |