diff options
Diffstat (limited to 'tests/auto/qml')
28 files changed, 588 insertions, 6 deletions
diff --git a/tests/auto/qml/debugger/qv4debugger/CMakeLists.txt b/tests/auto/qml/debugger/qv4debugger/CMakeLists.txt index e8fe26cb5a..92565f55c1 100644 --- a/tests/auto/qml/debugger/qv4debugger/CMakeLists.txt +++ b/tests/auto/qml/debugger/qv4debugger/CMakeLists.txt @@ -20,6 +20,7 @@ qt6_add_qml_module(testCppTypes SOURCES commontypes.h ) +qt_autogen_tools_initial_setup(testCppTypesplugin) qt_internal_add_test(tst_qv4debugger SOURCES diff --git a/tests/auto/qml/ecmascripttests/qjstest/test262runner.cpp b/tests/auto/qml/ecmascripttests/qjstest/test262runner.cpp index 24633d9c6d..9037ed0c92 100644 --- a/tests/auto/qml/ecmascripttests/qjstest/test262runner.cpp +++ b/tests/auto/qml/ecmascripttests/qjstest/test262runner.cpp @@ -393,9 +393,7 @@ void Test262Runner::loadTestExpectations() return; } - int line = 0; while (!file.atEnd()) { - ++line; QByteArray line = file.readLine().trimmed(); if (line.startsWith('#') || line.isEmpty()) continue; @@ -440,9 +438,7 @@ void Test262Runner::updateTestExpectations() QTemporaryFile updatedExpectations; updatedExpectations.open(); - int line = 0; while (!file.atEnd()) { - ++line; QByteArray originalLine = file.readLine(); QByteArray line = originalLine.trimmed(); if (line.startsWith('#') || line.isEmpty()) { diff --git a/tests/auto/qml/qmldiskcache/tst_qmldiskcache.cpp b/tests/auto/qml/qmldiskcache/tst_qmldiskcache.cpp index 3f429fec22..d84aaaeba3 100644 --- a/tests/auto/qml/qmldiskcache/tst_qmldiskcache.cpp +++ b/tests/auto/qml/qmldiskcache/tst_qmldiskcache.cpp @@ -65,6 +65,7 @@ private slots: void cppRegisteredSingletonDependency(); void cacheModuleScripts(); void reuseStaticMappings(); + void invalidateSaveLoadCache(); private: QDir m_qmlCacheDirectory; @@ -550,6 +551,7 @@ void tst_qmldiskcache::recompileAfterChange() CleanlyLoadingComponent component(&engine, testCompiler.testFilePath); QScopedPointer<TypeVersion2> obj(qobject_cast<TypeVersion2*>(component.create())); QVERIFY(!obj.isNull()); + qDebug() << obj->property("x"); QVERIFY(QFileInfo(testCompiler.cacheFilePath).lastModified() > initialCacheTimeStamp); } } @@ -1030,6 +1032,112 @@ void tst_qmldiskcache::reuseStaticMappings() QCOMPARE(testCompiler.unitData(), data1); } +class AParent : public QObject +{ + Q_OBJECT + Q_PROPERTY(int x MEMBER x) +public: + AParent(QObject *parent = nullptr) : QObject(parent) {} + int x = 25; +}; + +class BParent : public QObject +{ + Q_OBJECT + + // Insert y before x, to change the property index of x + Q_PROPERTY(int y MEMBER y) + + Q_PROPERTY(int x MEMBER x) +public: + BParent(QObject *parent = nullptr) : QObject(parent) {} + int y = 13; + int x = 25; +}; + +static QString writeTempFile( + const QTemporaryDir &tempDir, const QString &fileName, const char *contents) { + QFile f(tempDir.path() + '/' + fileName); + const bool ok = f.open(QIODevice::WriteOnly | QIODevice::Truncate); + Q_ASSERT(ok); + f.write(contents); + return f.fileName(); +}; + +void tst_qmldiskcache::invalidateSaveLoadCache() +{ + qmlRegisterType<AParent>("Base", 1, 0, "Parent"); + QQmlEngine e; + + // If you store a CU to a .qmlc file at run time, the .qmlc file will contain + // alias entries with the encodedMetaPropertyIndex pre-resolved. That's in + // contrast to .qmlc files generated ahead of time. Exploit that to cause + // a need to recompile the file. + + QTemporaryDir tempDir; + const QString fileName = writeTempFile( + tempDir, QLatin1String("a.qml"), + "import Base\nParent { id: self; property alias z: self.x }"); + const QUrl url = QUrl::fromLocalFile(fileName); + waitForFileSystem(); + + { + QQmlComponent a(&e, url); + QVERIFY2(a.isReady(), qPrintable(a.errorString())); + QScopedPointer<QObject> ao(a.create()); + QVERIFY(!ao.isNull()); + AParent *ap = qobject_cast<AParent *>(ao.data()); + QCOMPARE(ap->property("z").toInt(), ap->x); + } + + QString errorString; + QQmlRefPointer<QV4::ExecutableCompilationUnit> oldUnit + = QV4::ExecutableCompilationUnit::create(); + QVERIFY2(oldUnit->loadFromDisk(url, QFileInfo(fileName).lastModified(), &errorString), qPrintable(errorString)); + + // Produce a checksum mismatch. + e.clearComponentCache(); + qmlClearTypeRegistrations(); + qmlRegisterType<BParent>("Base", 1, 0, "Parent"); + + { + QQmlComponent b(&e, url); + QVERIFY2(b.isReady(), qPrintable(b.errorString())); + QScopedPointer<QObject> bo(b.create()); + QVERIFY(!bo.isNull()); + BParent *bp = qobject_cast<BParent *>(bo.data()); + QCOMPARE(bp->property("z").toInt(), bp->x); + } + + // Make it recompile again. + e.clearComponentCache(); + { + QFile file(fileName); + file.open(QIODevice::WriteOnly | QIODevice::Append); + file.write(" "); + } + waitForFileSystem(); + + { + QQmlComponent b(&e, url); + QVERIFY2(b.isReady(), qPrintable(b.errorString())); + QScopedPointer<QObject> bo(b.create()); + QVERIFY(!bo.isNull()); + BParent *bp = qobject_cast<BParent *>(bo.data()); + QCOMPARE(bp->property("z").toInt(), bp->x); + } + + // Verify that the mapped unit data is actually different now. + // The cache should have been invalidated after all. + // So, now we should be able to load a freshly written CU. + + QQmlRefPointer<QV4::ExecutableCompilationUnit> unit + = QV4::ExecutableCompilationUnit::create(); + QVERIFY2(unit->loadFromDisk(url, QFileInfo(fileName).lastModified(), &errorString), qPrintable(errorString)); + + QVERIFY(unit->unitData() != oldUnit->unitData()); +} + QTEST_MAIN(tst_qmldiskcache) #include "tst_qmldiskcache.moc" diff --git a/tests/auto/qml/qmlformat/data/ecmaScriptClassInQml.formatted.qml b/tests/auto/qml/qmlformat/data/ecmaScriptClassInQml.formatted.qml new file mode 100644 index 0000000000..edbb12c6e6 --- /dev/null +++ b/tests/auto/qml/qmlformat/data/ecmaScriptClassInQml.formatted.qml @@ -0,0 +1,37 @@ +import QtQuick + +Item { + + function f() { + var count = 0; + class Person { + constructor(name){ + this._name = name; + } + } + class Employee extends Person { + constructor(name, age){ + super(name); + this._name = name; + this._age = age; + ++count; + } + + doWork(){} + + /* do we get the comment? */ get name(){ + return this._name.toUpperCase(); + } + + set name(newName){ + if (newName) { + this._name = newName; + } + } + + static get count(){ + return count; + } + } + } +} diff --git a/tests/auto/qml/qmlformat/data/ecmaScriptClassInQml.qml b/tests/auto/qml/qmlformat/data/ecmaScriptClassInQml.qml new file mode 100644 index 0000000000..268859d3cc --- /dev/null +++ b/tests/auto/qml/qmlformat/data/ecmaScriptClassInQml.qml @@ -0,0 +1,45 @@ +import QtQuick + +Item { + +function f() { + +var count = 0; + +class Person { + constructor(name) { + this._name = name + } +} + +class Employee extends Person{ + + + constructor(name, age) { + super(name); + this._name = name; + this._age = age; + ++count; + } + + doWork() { + + } + + get /* do we get the comment? */ name() { + return this._name.toUpperCase(); + } + + set name(newName){ + if(newName){ + this._name = newName; + } + } + + static get count() { return count;} +} + + +} + +}
\ No newline at end of file diff --git a/tests/auto/qml/qmlformat/tst_qmlformat.cpp b/tests/auto/qml/qmlformat/tst_qmlformat.cpp index 65b423b919..843c078f8c 100644 --- a/tests/auto/qml/qmlformat/tst_qmlformat.cpp +++ b/tests/auto/qml/qmlformat/tst_qmlformat.cpp @@ -252,6 +252,9 @@ void TestQmlformat::testFormat_data() << "emptyObject.formatted.qml" << QStringList {}; QTest::newRow("arrow functions") << "arrowFunctions.qml" << "arrowFunctions.formatted.qml" << QStringList {}; + QTest::newRow("ecmaScriptClassInQml") + << "ecmaScriptClassInQml.qml" + << "ecmaScriptClassInQml.formatted.qml" << QStringList {}; } void TestQmlformat::testFormat() diff --git a/tests/auto/qml/qmltyperegistrar/CMakeLists.txt b/tests/auto/qml/qmltyperegistrar/CMakeLists.txt index 9ab6c69b9c..02a0347ac2 100644 --- a/tests/auto/qml/qmltyperegistrar/CMakeLists.txt +++ b/tests/auto/qml/qmltyperegistrar/CMakeLists.txt @@ -67,3 +67,4 @@ qt_add_qml_module(tst-qmltyperegistrar-with-dashes SOURCES foo.cpp foo.h ) +qt_autogen_tools_initial_setup(tst-qmltyperegistrar-with-dashesplugin) diff --git a/tests/auto/qml/qmltyperegistrar/tst_qmltyperegistrar.cpp b/tests/auto/qml/qmltyperegistrar/tst_qmltyperegistrar.cpp index aeb46a8274..27f83ca22f 100644 --- a/tests/auto/qml/qmltyperegistrar/tst_qmltyperegistrar.cpp +++ b/tests/auto/qml/qmltyperegistrar/tst_qmltyperegistrar.cpp @@ -300,4 +300,11 @@ void tst_qmltyperegistrar::methodReturnType() QVERIFY(qmltypesData.contains("type: \"QQmlComponent\"")); } +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" })")); +} + QTEST_MAIN(tst_qmltyperegistrar) diff --git a/tests/auto/qml/qmltyperegistrar/tst_qmltyperegistrar.h b/tests/auto/qml/qmltyperegistrar/tst_qmltyperegistrar.h index 7cfce1c2be..1372c32d02 100644 --- a/tests/auto/qml/qmltyperegistrar/tst_qmltyperegistrar.h +++ b/tests/auto/qml/qmltyperegistrar/tst_qmltyperegistrar.h @@ -398,6 +398,17 @@ public: Q_INVOKABLE QQmlComponent *createAThing(int) { return nullptr; } }; +class Invisible : public QObject +{ +}; + +struct InvisibleForeign +{ + Q_GADGET + QML_FOREIGN(Invisible) + QML_NAMED_ELEMENT(Invisible) +}; + class tst_qmltyperegistrar : public QObject { Q_OBJECT @@ -429,6 +440,7 @@ private slots: void namespacesAndValueTypes(); void derivedFromForeignPrivate(); void methodReturnType(); + void omitInvisible(); private: QByteArray qmltypesData; diff --git a/tests/auto/qml/qqmlconnections/data/invalidTarget.qml b/tests/auto/qml/qqmlconnections/data/invalidTarget.qml new file mode 100644 index 0000000000..23599649ec --- /dev/null +++ b/tests/auto/qml/qqmlconnections/data/invalidTarget.qml @@ -0,0 +1,31 @@ +import QtQml + +QtObject { + id: root + objectName: button.objectName + + property QtObject b: QtObject { + objectName: "button" + id: button + signal clicked + } + + property Connections c: Connections { + id: connections + target: null + function onClicked() { button.destroy(); } + } + + property Timer t: Timer { + interval: 10 + running: true + onTriggered: { + root.objectName = connections.target.objectName + } + } + + Component.onCompleted: { + connections.target = button; + button.clicked() + } +} diff --git a/tests/auto/qml/qqmlconnections/tst_qqmlconnections.cpp b/tests/auto/qml/qqmlconnections/tst_qqmlconnections.cpp index 1cdf458c0d..a28a8dd9dd 100644 --- a/tests/auto/qml/qqmlconnections/tst_qqmlconnections.cpp +++ b/tests/auto/qml/qqmlconnections/tst_qqmlconnections.cpp @@ -78,6 +78,7 @@ private slots: void noAcceleratedGlobalLookup(); void bindToPropertyWithUnderscoreChangeHandler(); + void invalidTarget(); private: QQmlEngine engine; @@ -490,6 +491,25 @@ void tst_qqmlconnections::bindToPropertyWithUnderscoreChangeHandler() QVERIFY(root->property("success").toBool()); } +void tst_qqmlconnections::invalidTarget() +{ + QQmlEngine engine; + const QUrl url = testFileUrl("invalidTarget.qml"); + QQmlComponent component(&engine, url); + QVERIFY2(component.isReady(), qPrintable(component.errorString())); + + QScopedPointer<QObject> root {component.create()}; + QVERIFY(root); + QCOMPARE(root->objectName(), QStringLiteral("button")); + + QTest::ignoreMessage( + QtWarningMsg, + qPrintable( + url.toString() + + QLatin1String(":5:5: TypeError: Cannot read property 'objectName' of null"))); + QTRY_VERIFY(root->objectName().isEmpty()); +} + QTEST_MAIN(tst_qqmlconnections) #include "tst_qqmlconnections.moc" diff --git a/tests/auto/qml/qqmlecmascript/data/methodTypeMismatch.qml b/tests/auto/qml/qqmlecmascript/data/methodTypeMismatch.qml new file mode 100644 index 0000000000..fdf5f4ea11 --- /dev/null +++ b/tests/auto/qml/qqmlecmascript/data/methodTypeMismatch.qml @@ -0,0 +1,25 @@ +import QtQuick 2.0 + +Item { + id: self + property font myFont + property int notMyFont + + property var object + + function callWithFont() { + object.method_gadget(myFont) // should be fine + } + function callWithInt() { + object.method_gadget(123) + } + function callWithInt2() { + object.method_gadget(notMyFont) + } + function callWithNull() { + object.method_gadget(null) + } + function callWithAllowedNull() { + object.method_qobject(null) + } +} diff --git a/tests/auto/qml/qqmlecmascript/data/readOnlyBindable.qml b/tests/auto/qml/qqmlecmascript/data/readOnlyBindable.qml new file mode 100644 index 0000000000..116036c9ff --- /dev/null +++ b/tests/auto/qml/qqmlecmascript/data/readOnlyBindable.qml @@ -0,0 +1,7 @@ +import Qt.test +import QtQuick + +ReadOnlyBindable { + property int v: 12 + x: v +} diff --git a/tests/auto/qml/qqmlecmascript/testtypes.cpp b/tests/auto/qml/qqmlecmascript/testtypes.cpp index 87d8ed0c1f..cd83702d3a 100644 --- a/tests/auto/qml/qqmlecmascript/testtypes.cpp +++ b/tests/auto/qml/qqmlecmascript/testtypes.cpp @@ -560,6 +560,7 @@ void registerTypes() qmlRegisterType<Receiver>("Qt.test", 1,0, "Receiver"); qmlRegisterType<Sender>("Qt.test", 1,0, "Sender"); + qmlRegisterTypesAndRevisions<ReadOnlyBindable>("Qt.test", 1); } #include "testtypes.moc" diff --git a/tests/auto/qml/qqmlecmascript/testtypes.h b/tests/auto/qml/qqmlecmascript/testtypes.h index acc066fddd..a3df73972e 100644 --- a/tests/auto/qml/qqmlecmascript/testtypes.h +++ b/tests/auto/qml/qqmlecmascript/testtypes.h @@ -833,12 +833,38 @@ public: Q_INVOKABLE void method_unknown(NonRegisteredType) { invoke(28); } + Q_PROPERTY(QFont someFont READ someFont WRITE setSomeFont NOTIFY someFontChanged); + QFont someFont() { return m_someFont; } + void setSomeFont(const QFont &f) + { + if (f == m_someFont) + return; + m_someFont = f; + emit someFontChanged(); + } + Q_INVOKABLE void method_gadget(QFont f) + { + invoke(40); + m_actuals << f; + } + Q_INVOKABLE void method_qobject(QObject *o) + { + invoke(41); + m_actuals << QVariant::fromValue(o); + } + private: friend class MyInvokableBaseObject; void invoke(int idx) { if (m_invoked != -1) m_invokedError = true; m_invoked = idx;} int m_invoked; bool m_invokedError; QVariantList m_actuals; + + QFont m_someFont; + +public: +Q_SIGNALS: + void someFontChanged(); }; MyInvokableBaseObject::~MyInvokableBaseObject() {} @@ -1847,6 +1873,25 @@ public slots: int slot1(int i, int j, int k) {return i+j+k;} }; +class ReadOnlyBindable : public QObject +{ + Q_OBJECT + QML_ELEMENT + Q_PROPERTY(int x READ x WRITE setX BINDABLE bindableX) + Q_OBJECT_BINDABLE_PROPERTY(ReadOnlyBindable, int, _xProp) + +public: + ReadOnlyBindable(QObject *parent = nullptr) + : QObject(parent) + { + setX(7); + } + + int x() const { return _xProp.value(); } + void setX(int x) { _xProp.setValue(x); } + QBindable<int> bindableX() const { return &_xProp; } +}; + void registerTypes(); #endif // TESTTYPES_H diff --git a/tests/auto/qml/qqmlecmascript/tst_qqmlecmascript.cpp b/tests/auto/qml/qqmlecmascript/tst_qqmlecmascript.cpp index 2d38bf0524..f47c7132a2 100644 --- a/tests/auto/qml/qqmlecmascript/tst_qqmlecmascript.cpp +++ b/tests/auto/qml/qqmlecmascript/tst_qqmlecmascript.cpp @@ -428,6 +428,9 @@ private slots: void functionAsDefaultArgument(); void internalClassParentGc(); + void methodTypeMismatch(); + + void doNotCrashOnReadOnlyBindable(); private: // static void propertyVarWeakRefCallback(v8::Persistent<v8::Value> object, void* parameter); @@ -3331,6 +3334,19 @@ void tst_qqmlecmascript::callQtInvokables() QJSValue callback = qvariant_cast<QJSValue>(o->actuals().at(1)); QVERIFY(!callback.isNull()); QVERIFY(callback.isCallable()); + + o->reset(); + QVERIFY(EVALUATE_VALUE("object.method_gadget(object.someFont)", + QV4::Primitive::undefinedValue())); + QCOMPARE(o->error(), false); + QCOMPARE(o->invoked(), 40); + QCOMPARE(o->actuals(), QVariantList() << QVariant(o->someFont())); + + o->reset(); + QVERIFY(EVALUATE_ERROR("object.method_gadget(123)")); + QCOMPARE(o->error(), false); + QCOMPARE(o->invoked(), -1); + QCOMPARE(o->actuals(), QVariantList()); } void tst_qqmlecmascript::resolveClashingProperties() @@ -9978,6 +9994,85 @@ void tst_qqmlecmascript::internalClassParentGc() QCOMPARE(root->objectName(), "3"); } +void tst_qqmlecmascript::methodTypeMismatch() +{ + QQmlEngine engine; + QQmlComponent component(&engine, testFileUrl("methodTypeMismatch.qml")); + + QScopedPointer<MyInvokableObject> object(new MyInvokableObject()); + + QScopedPointer<QObject> o(component.create()); + QVERIFY2(o, qPrintable(component.errorString())); + o->setProperty("object", QVariant::fromValue(object.get())); + + auto mo = o->metaObject(); + QVERIFY(mo); + + auto method = mo->method(mo->indexOfMethod("callWithFont()")); + QVERIFY(method.isValid()); + QVERIFY(method.invoke(o.get())); + QCOMPARE(object->actuals(), QVariantList() << QVariant(object->someFont())); + + QRegularExpression argumentConversionErrorMatcher("Could not convert argument 0"); + QRegularExpression argumentConversionErrorMatcher2(".*/methodTypeMismatch.qml"); + QRegularExpression typeErrorMatcher( + ".*/methodTypeMismatch\\.qml:..: TypeError: Passing incompatible arguments to C\\+\\+ " + "functions from JavaScript is not allowed."); + + QTest::ignoreMessage(QtWarningMsg, argumentConversionErrorMatcher); + QTest::ignoreMessage(QtWarningMsg, argumentConversionErrorMatcher2); + QTest::ignoreMessage(QtWarningMsg, typeErrorMatcher); + object->reset(); + method = mo->method(mo->indexOfMethod("callWithInt()")); + QVERIFY(method.isValid()); + QVERIFY(method.invoke(o.get())); + QCOMPARE(object->actuals().size(), + 0); // actuals() should not contain reinterpret_cast<QFont>(123) !!! + + QTest::ignoreMessage(QtWarningMsg, argumentConversionErrorMatcher); + QTest::ignoreMessage(QtWarningMsg, argumentConversionErrorMatcher2); + QTest::ignoreMessage(QtWarningMsg, typeErrorMatcher); + object->reset(); + method = mo->method(mo->indexOfMethod("callWithInt2()")); + QVERIFY(method.isValid()); + QVERIFY(method.invoke(o.get())); + QCOMPARE(object->actuals().size(), + 0); // actuals() should not contain reinterpret_cast<QFont>(0) !!! + + QTest::ignoreMessage(QtWarningMsg, argumentConversionErrorMatcher); + QTest::ignoreMessage(QtWarningMsg, argumentConversionErrorMatcher2); + QTest::ignoreMessage(QtWarningMsg, typeErrorMatcher); + object->reset(); + method = mo->method(mo->indexOfMethod("callWithNull()")); + QVERIFY(method.isValid()); + QVERIFY(method.invoke(o.get())); + QCOMPARE(object->actuals().size(), + 0); // actuals() should not contain reinterpret_cast<QFont>(nullptr) !!! + + // make sure that null is still accepted by functions accepting, e.g., a QObject*! + object->reset(); + method = mo->method(mo->indexOfMethod("callWithAllowedNull()")); + QVERIFY(method.isValid()); + QVERIFY(method.invoke(o.get())); + QCOMPARE(object->actuals(), QVariantList() << QVariant::fromValue((QObject *)nullptr)); +} + +void tst_qqmlecmascript::doNotCrashOnReadOnlyBindable() +{ + QQmlEngine engine; + QQmlComponent c(&engine, testFileUrl("readOnlyBindable.qml")); + QVERIFY2(c.isReady(), qPrintable(c.errorString())); +#ifndef QT_NO_DEBUG + QTest::ignoreMessage( + QtWarningMsg, + "setBinding: Could not set binding via bindable interface. " + "The QBindable is read-only."); +#endif + QScopedPointer<QObject> o(c.create()); + QVERIFY(o); + QCOMPARE(o->property("x").toInt(), 7); +} + QTEST_MAIN(tst_qqmlecmascript) #include "tst_qqmlecmascript.moc" diff --git a/tests/auto/qml/qqmlfileselector/data/qmldirtest/main.qml b/tests/auto/qml/qqmlfileselector/data/qmldirtest/main.qml new file mode 100644 index 0000000000..d6dd2c9b90 --- /dev/null +++ b/tests/auto/qml/qqmlfileselector/data/qmldirtest/main.qml @@ -0,0 +1,13 @@ +import QtQuick +import qmldirtest + +Window { + width: 640 + height: 480 + visible: true + property color color: mybutton.color + + MyButton { + id: mybutton + } +} diff --git a/tests/auto/qml/qqmlfileselector/data/qmldirtest/qml/+linux/MyButton.qml b/tests/auto/qml/qqmlfileselector/data/qmldirtest/qml/+linux/MyButton.qml new file mode 100644 index 0000000000..cc6eb967da --- /dev/null +++ b/tests/auto/qml/qqmlfileselector/data/qmldirtest/qml/+linux/MyButton.qml @@ -0,0 +1,7 @@ +import QtQuick + +Rectangle { + width: 300 + height: 50 + color: "blue" +} diff --git a/tests/auto/qml/qqmlfileselector/data/qmldirtest/qml/+macos/MyButton.qml b/tests/auto/qml/qqmlfileselector/data/qmldirtest/qml/+macos/MyButton.qml new file mode 100644 index 0000000000..5bf632c48d --- /dev/null +++ b/tests/auto/qml/qqmlfileselector/data/qmldirtest/qml/+macos/MyButton.qml @@ -0,0 +1,7 @@ +import QtQuick + +Rectangle { + width: 300 + height: 50 + color: "yellow" +} diff --git a/tests/auto/qml/qqmlfileselector/data/qmldirtest/qml/MyButton.qml b/tests/auto/qml/qqmlfileselector/data/qmldirtest/qml/MyButton.qml new file mode 100644 index 0000000000..32db428c4f --- /dev/null +++ b/tests/auto/qml/qqmlfileselector/data/qmldirtest/qml/MyButton.qml @@ -0,0 +1,7 @@ +import QtQuick + +Rectangle { + width: 300 + height: 50 + color: "green" +} diff --git a/tests/auto/qml/qqmlfileselector/data/qmldirtest/qmldir b/tests/auto/qml/qqmlfileselector/data/qmldirtest/qmldir new file mode 100644 index 0000000000..ac68d9097d --- /dev/null +++ b/tests/auto/qml/qqmlfileselector/data/qmldirtest/qmldir @@ -0,0 +1,5 @@ +module qmldirtest +MyButton 1.0 qml/MyButton.qml +MyButton 1.0 qml/+linux/MyButton.qml +MyButton 1.0 qml/+macos/MyButton.qml + diff --git a/tests/auto/qml/qqmlfileselector/tst_qqmlfileselector.cpp b/tests/auto/qml/qqmlfileselector/tst_qqmlfileselector.cpp index 4c99bcf9c8..fe55d8b056 100644 --- a/tests/auto/qml/qqmlfileselector/tst_qqmlfileselector.cpp +++ b/tests/auto/qml/qqmlfileselector/tst_qqmlfileselector.cpp @@ -47,7 +47,7 @@ private slots: void basicTest(); void basicTestCached(); void applicationEngineTest(); - + void qmldirCompatibility(); }; void tst_qqmlfileselector::basicTest() @@ -95,6 +95,23 @@ void tst_qqmlfileselector::applicationEngineTest() QCOMPARE(object->property("value").toString(), QString("selected")); } +void tst_qqmlfileselector::qmldirCompatibility() +{ + QQmlApplicationEngine engine; + engine.addImportPath(dataDirectory()); + engine.load(testFileUrl("qmldirtest/main.qml")); + QVERIFY(!engine.rootObjects().isEmpty()); + QObject *object = engine.rootObjects().at(0); + auto color = object->property("color").value<QColor>(); +#if defined(Q_OS_LINUX) && !defined(Q_OS_ANDROID) + QCOMPARE(color, QColorConstants::Svg::blue); +#elif defined(Q_OS_DARWIN) + QCOMPARE(color, QColorConstants::Svg::yellow); +#else + QCOMPARE(color, QColorConstants::Svg::green); +#endif +} + QTEST_MAIN(tst_qqmlfileselector) #include "tst_qqmlfileselector.moc" diff --git a/tests/auto/qml/qqmllanguage/data/MyRectangle.qml b/tests/auto/qml/qqmllanguage/data/MyRectangle.qml new file mode 100644 index 0000000000..4d5e7c6c8d --- /dev/null +++ b/tests/auto/qml/qqmllanguage/data/MyRectangle.qml @@ -0,0 +1,10 @@ +import QtQuick + +Item { + property alias rectangle1AnchorsleftMargin: rectangle1.anchors.leftMargin + + Rectangle { + id: rectangle1 + anchors.leftMargin: 250 + } +} diff --git a/tests/auto/qml/qqmllanguage/data/alias.19.qml b/tests/auto/qml/qqmllanguage/data/alias.19.qml new file mode 100644 index 0000000000..a96c0c694d --- /dev/null +++ b/tests/auto/qml/qqmllanguage/data/alias.19.qml @@ -0,0 +1,11 @@ +import QtQuick + +Item { + id: myThing + width: 1920 + + MyRectangle { + rectangle1AnchorsleftMargin: myThing.width / 2 + Component.onCompleted: myThing.height = rectangle1AnchorsleftMargin + } +} diff --git a/tests/auto/qml/qqmllanguage/tst_qqmllanguage.cpp b/tests/auto/qml/qqmllanguage/tst_qqmllanguage.cpp index 06b2738c9e..047df2f6d0 100644 --- a/tests/auto/qml/qqmllanguage/tst_qqmllanguage.cpp +++ b/tests/auto/qml/qqmllanguage/tst_qqmllanguage.cpp @@ -2257,6 +2257,16 @@ void tst_qqmllanguage::aliasProperties() QQmlComponent component(&engine, testFileUrl("alias.18.qml")); VERIFY_ERRORS("alias.18.errors.txt"); } + + // Binding on deep alias + { + QQmlComponent component(&engine, testFileUrl("alias.19.qml")); + VERIFY_ERRORS(0); + + QScopedPointer<QObject> object(component.create()); + QVERIFY(!object.isNull()); + QCOMPARE(object->property("height").toInt(), 960); + } } // QTBUG-13374 Test that alias properties and signals can coexist diff --git a/tests/auto/qml/qqmllistmodel/data/protectQObjectFromGC.qml b/tests/auto/qml/qqmllistmodel/data/protectQObjectFromGC.qml new file mode 100644 index 0000000000..43b375b681 --- /dev/null +++ b/tests/auto/qml/qqmllistmodel/data/protectQObjectFromGC.qml @@ -0,0 +1,21 @@ +import QtQml +import QtQml.Models + +ListModel { + id: filesModel + property Component testComponent: Component { + id: testComponent + QtObject { + required property string name + } + } + Component.onCompleted: { + filesModel.clear() + for(let i = 0; i < 10; i++) { + filesModel.append({ + path: testComponent.createObject(null, { name: "" + i }) + }) + } + gc() + } +} diff --git a/tests/auto/qml/qqmllistmodel/tst_qqmllistmodel.cpp b/tests/auto/qml/qqmllistmodel/tst_qqmllistmodel.cpp index 37b0f6f1fe..fbdf6d90f3 100644 --- a/tests/auto/qml/qqmllistmodel/tst_qqmllistmodel.cpp +++ b/tests/auto/qml/qqmllistmodel/tst_qqmllistmodel.cpp @@ -139,6 +139,7 @@ private slots: void listElementWithTemplateString(); void destroyComponentObject(); void objectOwnershipFlip(); + void protectQObjectFromGC(); }; bool tst_qqmllistmodel::compareVariantList(const QVariantList &testList, QVariant object) @@ -1882,7 +1883,7 @@ void tst_qqmllistmodel::destroyComponentObject() Q_RETURN_ARG(QVariant, retVal)); QVERIFY(retVal.toBool()); QTRY_VERIFY(created.isNull()); - QTRY_VERIFY(list->get(0).property("obj").isUndefined()); + QTRY_VERIFY(list->get(0).property("obj").isNull()); QCOMPARE(list->count(), 1); } @@ -1920,6 +1921,25 @@ void tst_qqmllistmodel::objectOwnershipFlip() QCOMPARE(QJSEngine::objectOwnership(item.data()), QJSEngine::CppOwnership); } +void tst_qqmllistmodel::protectQObjectFromGC() +{ + QQmlEngine engine; + QQmlComponent component(&engine, testFileUrl("protectQObjectFromGC.qml")); + QVERIFY2(component.isReady(), qPrintable(component.errorString())); + QScopedPointer<QObject> root(component.create()); + QVERIFY(!root.isNull()); + + QQmlListModel *listModel = qobject_cast<QQmlListModel *>(root.data()); + QVERIFY(listModel); + QCOMPARE(listModel->count(), 10); + + for (int i = 0; i < 10; ++i) { + QObject *element = qjsvalue_cast<QObject *>(listModel->get(i).property("path")); + QVERIFY(element); + QCOMPARE(element->property("name").toString(), QString::number(i)); + } +} + QTEST_MAIN(tst_qqmllistmodel) #include "tst_qqmllistmodel.moc" diff --git a/tests/auto/qml/qqmlmetatype/tst_qqmlmetatype.cpp b/tests/auto/qml/qqmlmetatype/tst_qqmlmetatype.cpp index be493484ee..f726855727 100644 --- a/tests/auto/qml/qqmlmetatype/tst_qqmlmetatype.cpp +++ b/tests/auto/qml/qqmlmetatype/tst_qqmlmetatype.cpp @@ -72,6 +72,8 @@ private slots: void enumsInRecursiveImport_data(); void enumsInRecursiveImport(); + + void clearPropertyCaches(); }; class TestType : public QObject @@ -734,6 +736,24 @@ void tst_qqmlmetatype::enumsInRecursiveImport() QTRY_COMPARE(obj->property("color").toString(), QString("green")); } +void tst_qqmlmetatype::clearPropertyCaches() +{ + qmlClearTypeRegistrations(); + qmlRegisterType<TestType>("ClearPropertyCaches", 1, 0, "A"); + + QQmlRefPointer<QQmlPropertyCache> oldCache( + QQmlMetaType::propertyCache(&TestType::staticMetaObject)); + QVERIFY(oldCache); + + qmlClearTypeRegistrations(); + qmlRegisterType<TestType>("ClearPropertyCaches", 1, 0, "B"); + QQmlRefPointer<QQmlPropertyCache> newCache( + QQmlMetaType::propertyCache(&TestType::staticMetaObject)); + QVERIFY(newCache); + + QVERIFY(oldCache.data() != newCache.data()); +} + QTEST_MAIN(tst_qqmlmetatype) #include "tst_qqmlmetatype.moc" |