diff options
Diffstat (limited to 'tests/auto/qml')
83 files changed, 2528 insertions, 228 deletions
diff --git a/tests/auto/qml/animation/qparallelanimationgroupjob/tst_qparallelanimationgroupjob.cpp b/tests/auto/qml/animation/qparallelanimationgroupjob/tst_qparallelanimationgroupjob.cpp index ab8fa8a9ef..476ad2e955 100644 --- a/tests/auto/qml/animation/qparallelanimationgroupjob/tst_qparallelanimationgroupjob.cpp +++ b/tests/auto/qml/animation/qparallelanimationgroupjob/tst_qparallelanimationgroupjob.cpp @@ -63,8 +63,8 @@ private slots: void tst_QParallelAnimationGroupJob::initTestCase() { qRegisterMetaType<QAbstractAnimationJob::State>("QAbstractAnimationJob::State"); -#if defined(Q_OS_MAC) || defined(Q_OS_WINCE) - // give the mac/wince app start event queue time to clear +#if defined(Q_OS_DARWIN) + // give the Apple application's start event queue time to clear QTest::qWait(1000); #endif } diff --git a/tests/auto/qml/debugger/debugger.pro b/tests/auto/qml/debugger/debugger.pro index ccb2d71c53..a50411e18b 100644 --- a/tests/auto/qml/debugger/debugger.pro +++ b/tests/auto/qml/debugger/debugger.pro @@ -20,6 +20,6 @@ PRIVATETESTS += \ SUBDIRS += $$PUBLICTESTS -contains(QT_CONFIG, private_tests) { +qtConfig(private_tests): \ SUBDIRS += $$PRIVATETESTS -} + diff --git a/tests/auto/qml/debugger/qqmldebugjs/qqmldebugjs/tst_qqmldebugjs.cpp b/tests/auto/qml/debugger/qqmldebugjs/qqmldebugjs/tst_qqmldebugjs.cpp index b800cc3715..d1150be831 100644 --- a/tests/auto/qml/debugger/qqmldebugjs/qqmldebugjs/tst_qqmldebugjs.cpp +++ b/tests/auto/qml/debugger/qqmldebugjs/qqmldebugjs/tst_qqmldebugjs.cpp @@ -42,11 +42,6 @@ #include <QtCore/qlibraryinfo.h> #include <QtQml/qjsengine.h> -#if defined (Q_OS_WINCE) -#undef IN -#undef OUT -#endif - const char *V8REQUEST = "v8request"; const char *V8MESSAGE = "v8message"; const char *SEQ = "seq"; diff --git a/tests/auto/qml/debugger/qqmlenginedebugservice/tst_qqmlenginedebugservice.cpp b/tests/auto/qml/debugger/qqmlenginedebugservice/tst_qqmlenginedebugservice.cpp index 4568d25dc1..40e19d375d 100644 --- a/tests/auto/qml/debugger/qqmlenginedebugservice/tst_qqmlenginedebugservice.cpp +++ b/tests/auto/qml/debugger/qqmlenginedebugservice/tst_qqmlenginedebugservice.cpp @@ -1223,16 +1223,15 @@ void tst_QQmlEngineDebugService::queryObjectTree() int main(int argc, char *argv[]) { int _argc = argc + 1; - char **_argv = new char*[_argc]; + QScopedArrayPointer<char *>_argv(new char*[_argc]); for (int i = 0; i < argc; ++i) _argv[i] = argv[i]; char arg[] = "-qmljsdebugger=port:3768,services:QmlDebugger"; _argv[_argc - 1] = arg; - QGuiApplication app(_argc, _argv); + QGuiApplication app(_argc, _argv.data()); tst_QQmlEngineDebugService tc; - return QTest::qExec(&tc, _argc, _argv); - delete _argv; + return QTest::qExec(&tc, _argc, _argv.data()); } #include "tst_qqmlenginedebugservice.moc" diff --git a/tests/auto/qml/debugger/qqmlprofilerservice/data/controlFromJS.qml b/tests/auto/qml/debugger/qqmlprofilerservice/data/controlFromJS.qml index d1db2af367..dd7cb2055d 100644 --- a/tests/auto/qml/debugger/qqmlprofilerservice/data/controlFromJS.qml +++ b/tests/auto/qml/debugger/qqmlprofilerservice/data/controlFromJS.qml @@ -26,10 +26,10 @@ ** ****************************************************************************/ -import QtQuick 2.0 +import QtQml 2.0 -Rectangle { - Timer { +QtObject { + property var timer: Timer { running: true interval: 1 onTriggered: { @@ -38,7 +38,7 @@ Rectangle { } } - Timer { + property var stopTimer: Timer { id: stopTimer interval: 1000 onTriggered: { @@ -47,7 +47,7 @@ Rectangle { } } - Timer { + property var endTimer: Timer { id: endTimer interval: 1000 onTriggered: Qt.quit(); diff --git a/tests/auto/qml/debugger/qqmlprofilerservice/data/exit.qml b/tests/auto/qml/debugger/qqmlprofilerservice/data/exit.qml index b250524caa..4236d70ea3 100644 --- a/tests/auto/qml/debugger/qqmlprofilerservice/data/exit.qml +++ b/tests/auto/qml/debugger/qqmlprofilerservice/data/exit.qml @@ -1,6 +1,6 @@ -import QtQuick 2.0 +import QtQml 2.0 -Item { +QtObject { Timer { running: true interval: 1 diff --git a/tests/auto/qml/debugger/qqmlprofilerservice/data/javascript.qml b/tests/auto/qml/debugger/qqmlprofilerservice/data/javascript.qml index 0555d49652..e25c7524f4 100644 --- a/tests/auto/qml/debugger/qqmlprofilerservice/data/javascript.qml +++ b/tests/auto/qml/debugger/qqmlprofilerservice/data/javascript.qml @@ -1,6 +1,6 @@ -import QtQuick 2.0 +import QtQml 2.0 -Rectangle { +QtObject { function something(i) { if (i > 10) { something(i / 4); @@ -9,8 +9,8 @@ Rectangle { } } - width: 400 - height: 400 + property int width: 400 + property int height: 400 onWidthChanged: something(width); Component.onCompleted: width = 500; diff --git a/tests/auto/qml/debugger/qqmlprofilerservice/data/signalSourceLocation.qml b/tests/auto/qml/debugger/qqmlprofilerservice/data/signalSourceLocation.qml index 25e63669c4..0eff9e9030 100644 --- a/tests/auto/qml/debugger/qqmlprofilerservice/data/signalSourceLocation.qml +++ b/tests/auto/qml/debugger/qqmlprofilerservice/data/signalSourceLocation.qml @@ -1,8 +1,8 @@ -import QtQuick 2.0 +import QtQml 2.0 -Rectangle { - width: 400 - height: 400 +QtObject { + property int width: 400 + property int height: 400 onWidthChanged: console.log(width); Component.onCompleted: width = 500; diff --git a/tests/auto/qml/debugger/qqmlprofilerservice/data/test.qml b/tests/auto/qml/debugger/qqmlprofilerservice/data/test.qml index 9c36e13c5b..5dd5caf12f 100644 --- a/tests/auto/qml/debugger/qqmlprofilerservice/data/test.qml +++ b/tests/auto/qml/debugger/qqmlprofilerservice/data/test.qml @@ -1,5 +1,5 @@ -import QtQuick 2.0 +import QtQml 2.0 -Item { +QtObject { } diff --git a/tests/auto/qml/debugger/qqmlprofilerservice/data/timer.qml b/tests/auto/qml/debugger/qqmlprofilerservice/data/timer.qml index 18b8947172..4af555a27b 100644 --- a/tests/auto/qml/debugger/qqmlprofilerservice/data/timer.qml +++ b/tests/auto/qml/debugger/qqmlprofilerservice/data/timer.qml @@ -1,10 +1,10 @@ -import QtQuick 2.0 +import QtQml 2.0 -Rectangle { - width: 100 - height: 62 +QtObject { + property int width: 100 + property int height: 62 - Timer { + property var timer: Timer { running: true repeat: true interval: 50 diff --git a/tests/auto/qml/debugger/qqmlprofilerservice/tst_qqmlprofilerservice.cpp b/tests/auto/qml/debugger/qqmlprofilerservice/tst_qqmlprofilerservice.cpp index 4f9088d67d..c4b17aa60a 100644 --- a/tests/auto/qml/debugger/qqmlprofilerservice/tst_qqmlprofilerservice.cpp +++ b/tests/auto/qml/debugger/qqmlprofilerservice/tst_qqmlprofilerservice.cpp @@ -64,7 +64,8 @@ class QQmlProfilerTestClient : public QQmlProfilerClient Q_OBJECT public: - QQmlProfilerTestClient(QQmlDebugConnection *connection) : QQmlProfilerClient(connection) {} + QQmlProfilerTestClient(QQmlDebugConnection *connection) : QQmlProfilerClient(connection), + lastTimestamp(-1) {} QVector<QQmlProfilerData> qmlMessages; QVector<QQmlProfilerData> javascriptMessages; @@ -72,6 +73,8 @@ public: QVector<QQmlProfilerData> asynchronousMessages; QVector<QQmlProfilerData> pixmapMessages; + qint64 lastTimestamp; + signals: void recordingFinished(); @@ -114,6 +117,8 @@ void QQmlProfilerTestClient::traceFinished(qint64 time, int engineId) void QQmlProfilerTestClient::rangeStart(QQmlProfilerDefinitions::RangeType type, qint64 startTime) { QVERIFY(type >= 0 && type < QQmlProfilerDefinitions::MaximumRangeType); + QVERIFY(lastTimestamp <= startTime); + lastTimestamp = startTime; QQmlProfilerData data(startTime, QQmlProfilerDefinitions::RangeStart, type); if (type == QQmlProfilerDefinitions::Javascript) javascriptMessages.append(data); @@ -125,6 +130,8 @@ void QQmlProfilerTestClient::rangeData(QQmlProfilerDefinitions::RangeType type, const QString &string) { QVERIFY(type >= 0 && type < QQmlProfilerDefinitions::MaximumRangeType); + QVERIFY(lastTimestamp <= time); + lastTimestamp = time; QQmlProfilerData data(time, QQmlProfilerDefinitions::RangeData, type, string); if (type == QQmlProfilerDefinitions::Javascript) javascriptMessages.append(data); @@ -137,6 +144,8 @@ void QQmlProfilerTestClient::rangeLocation(QQmlProfilerDefinitions::RangeType ty { QVERIFY(type >= 0 && type < QQmlProfilerDefinitions::MaximumRangeType); QVERIFY(location.line >= -2); + QVERIFY(lastTimestamp <= time); + lastTimestamp = time; QQmlProfilerData data(time, QQmlProfilerDefinitions::RangeLocation, type, location.filename); data.line = location.line; data.column = location.column; @@ -149,6 +158,8 @@ void QQmlProfilerTestClient::rangeLocation(QQmlProfilerDefinitions::RangeType ty void QQmlProfilerTestClient::rangeEnd(QQmlProfilerDefinitions::RangeType type, qint64 endTime) { QVERIFY(type >= 0 && type < QQmlProfilerDefinitions::MaximumRangeType); + QVERIFY(lastTimestamp <= endTime); + lastTimestamp = endTime; QQmlProfilerData data(endTime, QQmlProfilerDefinitions::RangeEnd, type); if (type == QQmlProfilerDefinitions::Javascript) javascriptMessages.append(data); @@ -161,6 +172,8 @@ void QQmlProfilerTestClient::animationFrame(qint64 time, int frameRate, int anim QVERIFY(threadId >= 0); QVERIFY(frameRate != -1); QVERIFY(animationCount != -1); + QVERIFY(lastTimestamp <= time); + lastTimestamp = time; QQmlProfilerData data(time, QQmlProfilerDefinitions::Event, QQmlProfilerDefinitions::AnimationFrame); data.framerate = frameRate; @@ -178,6 +191,8 @@ void QQmlProfilerTestClient::sceneGraphEvent(QQmlProfilerDefinitions::SceneGraph Q_UNUSED(numericData3); Q_UNUSED(numericData4); Q_UNUSED(numericData5); + QVERIFY(lastTimestamp <= time); + lastTimestamp = time; asynchronousMessages.append(QQmlProfilerData(time, QQmlProfilerDefinitions::SceneGraphFrame, type)); } @@ -186,6 +201,8 @@ void QQmlProfilerTestClient::pixmapCacheEvent(QQmlProfilerDefinitions::PixmapEve qint64 time, const QString &url, int numericData1, int numericData2) { + QVERIFY(lastTimestamp <= time); + lastTimestamp = time; QQmlProfilerData data(time, QQmlProfilerDefinitions::PixmapCacheEvent, type, url); switch (type) { case QQmlProfilerDefinitions::PixmapSizeKnown: @@ -205,6 +222,8 @@ void QQmlProfilerTestClient::pixmapCacheEvent(QQmlProfilerDefinitions::PixmapEve void QQmlProfilerTestClient::memoryAllocation(QQmlProfilerDefinitions::MemoryType type, qint64 time, qint64 amount) { + QVERIFY(lastTimestamp <= time); + lastTimestamp = time; QQmlProfilerData data(time, QQmlProfilerDefinitions::MemoryAllocation, type); data.amount = amount; jsHeapMessages.append(data); @@ -213,6 +232,8 @@ void QQmlProfilerTestClient::memoryAllocation(QQmlProfilerDefinitions::MemoryTyp void QQmlProfilerTestClient::inputEvent(QQmlProfilerDefinitions::InputEventType type, qint64 time, int a, int b) { + QVERIFY(lastTimestamp <= time); + lastTimestamp = time; qmlMessages.append(QQmlProfilerData(time, QQmlProfilerDefinitions::Event, type, QString::number(a) + QLatin1Char('x') + QString::number(b))); @@ -597,7 +618,7 @@ void tst_QQmlProfilerService::scenegraphData() // if the clocks are acting up. qint64 contextFrameTime = -1; qint64 renderFrameTime = -1; - +#ifndef QT_NO_OPENGL //Software renderer doesn't have context frames foreach (const QQmlProfilerData &msg, m_client->asynchronousMessages) { if (msg.messageType == QQmlProfilerDefinitions::SceneGraphFrame) { if (msg.detailType == QQmlProfilerDefinitions::SceneGraphContextFrame) { @@ -608,7 +629,7 @@ void tst_QQmlProfilerService::scenegraphData() } QVERIFY(contextFrameTime != -1); - +#endif foreach (const QQmlProfilerData &msg, m_client->asynchronousMessages) { if (msg.detailType == QQmlProfilerDefinitions::SceneGraphRendererFrame) { QVERIFY(msg.time >= contextFrameTime); @@ -667,11 +688,11 @@ void tst_QQmlProfilerService::signalSourceLocation() QLatin1String("signalSourceLocation.qml")); expected.line = 8; expected.column = 28; - VERIFY(MessageListQML, 13, expected, CheckAll); + VERIFY(MessageListQML, 9, expected, CheckAll); expected.line = 7; expected.column = 21; - VERIFY(MessageListQML, 15, expected, CheckAll); + VERIFY(MessageListQML, 11, expected, CheckAll); } void tst_QQmlProfilerService::javascript() diff --git a/tests/auto/qml/debugger/qv4debugger/tst_qv4debugger.cpp b/tests/auto/qml/debugger/qv4debugger/tst_qv4debugger.cpp index 3f89913f3b..a23b7e37eb 100644 --- a/tests/auto/qml/debugger/qv4debugger/tst_qv4debugger.cpp +++ b/tests/auto/qml/debugger/qv4debugger/tst_qv4debugger.cpp @@ -326,7 +326,7 @@ private slots: private: QV4Debugger *debugger() const { - return static_cast<QV4Debugger *>(m_v4->debugger); + return static_cast<QV4Debugger *>(m_v4->debugger()); } void evaluateJavaScript(const QString &script, const QString &fileName, int lineNumber = 1) { @@ -444,7 +444,7 @@ void tst_qv4debugger::addBreakPointWhilePaused() static QV4::ReturnedValue someCall(QV4::CallContext *ctx) { - static_cast<QV4Debugger *>(ctx->d()->engine->debugger) + static_cast<QV4Debugger *>(ctx->d()->engine->debugger()) ->removeBreakPoint("removeBreakPointForNextInstruction", 2); return QV4::Encode::undefined(); } diff --git a/tests/auto/qml/debugger/shared/debugutil_p.h b/tests/auto/qml/debugger/shared/debugutil_p.h index 6fe5d897e0..1ec0a6513d 100644 --- a/tests/auto/qml/debugger/shared/debugutil_p.h +++ b/tests/auto/qml/debugger/shared/debugutil_p.h @@ -135,8 +135,6 @@ public: int lastResponseId; bool lastResult; -public slots: - void recordResponse(int requestId, bool result) { lastResponseId = requestId; diff --git a/tests/auto/qml/qjsengine/tst_qjsengine.cpp b/tests/auto/qml/qjsengine/tst_qjsengine.cpp index 63fefbe9f1..c20f0888d8 100644 --- a/tests/auto/qml/qjsengine/tst_qjsengine.cpp +++ b/tests/auto/qml/qjsengine/tst_qjsengine.cpp @@ -73,6 +73,7 @@ private slots: void newQObject(); void newQObject_ownership(); void newQObject_deletedEngine(); + void newQMetaObject(); void exceptionInSlot(); void globalObjectProperties(); void globalObjectEquals(); @@ -124,6 +125,7 @@ private slots: void jsIncDecNonObjectProperty(); void JSONparse(); void arraySort(); + void lookupOnDisappearingProperty(); void qRegExpInport_data(); void qRegExpInport(); @@ -192,6 +194,8 @@ private slots: void withNoContext(); void holeInPropertyData(); + void basicBlockMergeAfterLoopPeeling(); + signals: void testSignal(); }; @@ -716,6 +720,104 @@ void tst_QJSEngine::newQObject_deletedEngine() QTRY_VERIFY(spy.count()); } +class TestQMetaObject : public QObject { + Q_OBJECT + Q_PROPERTY(int called READ called) +public: + enum Enum1 { + Zero = 0, + One, + Two + }; + enum Enum2 { + A = 0, + B, + C + }; + Q_ENUMS(Enum1 Enum2) + + Q_INVOKABLE TestQMetaObject() + : m_called(1) { + } + Q_INVOKABLE TestQMetaObject(int) + : m_called(2) { + } + Q_INVOKABLE TestQMetaObject(QString) + : m_called(3) { + } + Q_INVOKABLE TestQMetaObject(QString, int) + : m_called(4) { + } + int called() const { + return m_called; + } +private: + int m_called; +}; + +void tst_QJSEngine::newQMetaObject() { + { + QJSEngine engine; + QJSValue metaObject = engine.newQMetaObject(&TestQMetaObject::staticMetaObject); + QCOMPARE(metaObject.isNull(), false); + QCOMPARE(metaObject.isObject(), true); + QCOMPARE(metaObject.isQObject(), false); + QCOMPARE(metaObject.isCallable(), true); + QCOMPARE(metaObject.isQMetaObject(), true); + + QCOMPARE(metaObject.toQMetaObject(), &TestQMetaObject::staticMetaObject); + + QVERIFY(metaObject.strictlyEquals(engine.newQMetaObject<TestQMetaObject>())); + + + { + auto result = metaObject.callAsConstructor(); + if (result.isError()) + qDebug() << result.toString(); + QCOMPARE(result.isError(), false); + QCOMPARE(result.isNull(), false); + QCOMPARE(result.isObject(), true); + QCOMPARE(result.isQObject(), true); + QVERIFY(result.property("constructor").strictlyEquals(metaObject)); + QVERIFY(result.prototype().strictlyEquals(metaObject)); + + + QCOMPARE(result.property("called").toInt(), 1); + + } + + QJSValue integer(42); + QJSValue string("foo"); + + { + auto result = metaObject.callAsConstructor({integer}); + QCOMPARE(result.property("called").toInt(), 2); + } + + { + auto result = metaObject.callAsConstructor({string}); + QCOMPARE(result.property("called").toInt(), 3); + } + + { + auto result = metaObject.callAsConstructor({string, integer}); + QCOMPARE(result.property("called").toInt(), 4); + } + } + + { + QJSEngine engine; + QJSValue metaObject = engine.newQMetaObject(&TestQMetaObject::staticMetaObject); + QCOMPARE(metaObject.property("Zero").toInt(), 0); + QCOMPARE(metaObject.property("One").toInt(), 1); + QCOMPARE(metaObject.property("Two").toInt(), 2); + QCOMPARE(metaObject.property("A").toInt(), 0); + QCOMPARE(metaObject.property("B").toInt(), 1); + QCOMPARE(metaObject.property("C").toInt(), 2); + } + +} + void tst_QJSEngine::exceptionInSlot() { QJSEngine engine; @@ -1029,11 +1131,14 @@ void tst_QJSEngine::builtinFunctionNames_data() QTest::newRow("Math.pow") << QString("Math.pow") << QString("pow"); QTest::newRow("Math.random") << QString("Math.random") << QString("random"); QTest::newRow("Math.round") << QString("Math.round") << QString("round"); + QTest::newRow("Math.sign") << QString("Math.sign") << QString("sign"); QTest::newRow("Math.sin") << QString("Math.sin") << QString("sin"); QTest::newRow("Math.sqrt") << QString("Math.sqrt") << QString("sqrt"); QTest::newRow("Math.tan") << QString("Math.tan") << QString("tan"); QTest::newRow("Number") << QString("Number") << QString("Number"); + QTest::newRow("Number.isFinite") << QString("Number.isFinite") << QString("isFinite"); + QTest::newRow("Number.isNaN") << QString("Number.isNaN") << QString("isNaN"); QTest::newRow("Number.prototype.toString") << QString("Number.prototype.toString") << QString("toString"); QTest::newRow("Number.prototype.toLocaleString") << QString("Number.prototype.toLocaleString") << QString("toLocaleString"); QTest::newRow("Number.prototype.valueOf") << QString("Number.prototype.valueOf") << QString("valueOf"); @@ -1062,6 +1167,8 @@ void tst_QJSEngine::builtinFunctionNames_data() QTest::newRow("String.prototype.charAt") << QString("String.prototype.charAt") << QString("charAt"); QTest::newRow("String.prototype.charCodeAt") << QString("String.prototype.charCodeAt") << QString("charCodeAt"); QTest::newRow("String.prototype.concat") << QString("String.prototype.concat") << QString("concat"); + QTest::newRow("String.prototype.endsWith") << QString("String.prototype.endsWith") << QString("endsWith"); + QTest::newRow("String.prototype.includes") << QString("String.prototype.includes") << QString("includes"); QTest::newRow("String.prototype.indexOf") << QString("String.prototype.indexOf") << QString("indexOf"); QTest::newRow("String.prototype.lastIndexOf") << QString("String.prototype.lastIndexOf") << QString("lastIndexOf"); QTest::newRow("String.prototype.localeCompare") << QString("String.prototype.localeCompare") << QString("localeCompare"); @@ -1070,6 +1177,7 @@ void tst_QJSEngine::builtinFunctionNames_data() QTest::newRow("String.prototype.search") << QString("String.prototype.search") << QString("search"); QTest::newRow("String.prototype.slice") << QString("String.prototype.slice") << QString("slice"); QTest::newRow("String.prototype.split") << QString("String.prototype.split") << QString("split"); + QTest::newRow("String.prototype.startsWith") << QString("String.prototype.startsWith") << QString("startsWith"); QTest::newRow("String.prototype.substring") << QString("String.prototype.substring") << QString("substring"); QTest::newRow("String.prototype.toLowerCase") << QString("String.prototype.toLowerCase") << QString("toLowerCase"); QTest::newRow("String.prototype.toLocaleLowerCase") << QString("String.prototype.toLocaleLowerCase") << QString("toLocaleLowerCase"); @@ -1341,6 +1449,7 @@ void tst_QJSEngine::valueConversion_QVariant() QCOMPARE(qjsvalue_cast<QVariant>(QJSValue(123)), QVariant(123)); QVERIFY(eng.toScriptValue(QVariant(QMetaType::VoidStar, 0)).isNull()); + QVERIFY(eng.toScriptValue(QVariant::fromValue(nullptr)).isNull()); { QVariantMap map; @@ -1922,6 +2031,7 @@ void tst_QJSEngine::jsNumberClass() QVERIFY(ctor.property("NaN").isNumber()); QVERIFY(ctor.property("NEGATIVE_INFINITY").isNumber()); QVERIFY(ctor.property("POSITIVE_INFINITY").isNumber()); + QVERIFY(ctor.property("EPSILON").isNumber()); } QCOMPARE(proto.toNumber(), qreal(0)); QVERIFY(proto.property("constructor").strictlyEquals(ctor)); @@ -1960,6 +2070,50 @@ void tst_QJSEngine::jsNumberClass() QCOMPARE(ret.toNumber(), qreal(456)); } + QVERIFY(ctor.property("isFinite").isCallable()); + { + QJSValue ret = eng.evaluate("Number.isFinite()"); + QVERIFY(ret.isBool()); + QCOMPARE(ret.toBool(), false); + } + { + QJSValue ret = eng.evaluate("Number.isFinite(NaN)"); + QVERIFY(ret.isBool()); + QCOMPARE(ret.toBool(), false); + } + { + QJSValue ret = eng.evaluate("Number.isFinite(Infinity)"); + QVERIFY(ret.isBool()); + QCOMPARE(ret.toBool(), false); + } + { + QJSValue ret = eng.evaluate("Number.isFinite(-Infinity)"); + QVERIFY(ret.isBool()); + QCOMPARE(ret.toBool(), false); + } + { + QJSValue ret = eng.evaluate("Number.isFinite(123)"); + QVERIFY(ret.isBool()); + QCOMPARE(ret.toBool(), true); + } + + QVERIFY(ctor.property("isNaN").isCallable()); + { + QJSValue ret = eng.evaluate("Number.isNaN()"); + QVERIFY(ret.isBool()); + QCOMPARE(ret.toBool(), false); + } + { + QJSValue ret = eng.evaluate("Number.isNaN(NaN)"); + QVERIFY(ret.isBool()); + QCOMPARE(ret.toBool(), true); + } + { + QJSValue ret = eng.evaluate("Number.isNaN(123)"); + QVERIFY(ret.isBool()); + QCOMPARE(ret.toBool(), false); + } + QVERIFY(proto.property("toString").isCallable()); { QJSValue ret = eng.evaluate("new Number(123).toString()"); @@ -2813,6 +2967,22 @@ void tst_QJSEngine::arraySort() "crashMe();"); } +void tst_QJSEngine::lookupOnDisappearingProperty() +{ + QJSEngine eng; + QJSValue func = eng.evaluate("(function(){\"use strict\"; return eval(\"function(obj) { return obj.someProperty; }\")})()"); + QVERIFY(func.isCallable()); + + QJSValue o = eng.newObject(); + o.setProperty(QStringLiteral("someProperty"), 42); + + QCOMPARE(func.call(QJSValueList()<< o).toInt(), 42); + + o = eng.newObject(); + QVERIFY(func.call(QJSValueList()<< o).isUndefined()); + QVERIFY(func.call(QJSValueList()<< o).isUndefined()); +} + static QRegExp minimal(QRegExp r) { r.setMinimal(true); return r; } void tst_QJSEngine::qRegExpInport_data() @@ -3876,6 +4046,22 @@ void tst_QJSEngine::holeInPropertyData() QVERIFY(ok.toBool()); } +void tst_QJSEngine::basicBlockMergeAfterLoopPeeling() +{ + QJSEngine engine; + QJSValue ok = engine.evaluate( + "function crashMe() {\n" + " var seen = false;\n" + " while (globalVar) {\n" + " if (seen)\n" + " return;\n" + " seen = true;\n" + " }\n" + "}\n"); + QVERIFY(!ok.isCallable()); + +} + QTEST_MAIN(tst_QJSEngine) #include "tst_qjsengine.moc" diff --git a/tests/auto/qml/qjsvalue/tst_qjsvalue.cpp b/tests/auto/qml/qjsvalue/tst_qjsvalue.cpp index 859caf72c7..d28bbc1ffa 100644 --- a/tests/auto/qml/qjsvalue/tst_qjsvalue.cpp +++ b/tests/auto/qml/qjsvalue/tst_qjsvalue.cpp @@ -431,6 +431,12 @@ void tst_QJSValue::toString() QVERIFY(!o.engine()); QCOMPARE(o.toString(), QStringLiteral("1,2,3")); } + + { + QByteArray hello = QByteArrayLiteral("Hello World"); + QJSValue jsValue = eng.toScriptValue(hello); + QCOMPARE(jsValue.toString(), QString::fromUtf8(hello)); + } } void tst_QJSValue::toNumber() @@ -978,8 +984,8 @@ void tst_QJSValue::toVariant() QCOMPARE(qjsvalue_cast<QVariant>(undefined), QVariant()); QJSValue null = eng.evaluate("null"); - QCOMPARE(null.toVariant(), QVariant(QMetaType::VoidStar, 0)); - QCOMPARE(qjsvalue_cast<QVariant>(null), QVariant(QMetaType::VoidStar, 0)); + QCOMPARE(null.toVariant(), QVariant::fromValue(nullptr)); + QCOMPARE(qjsvalue_cast<QVariant>(null), QVariant::fromValue(nullptr)); { QJSValue number = eng.toScriptValue(123.0); @@ -1055,8 +1061,8 @@ void tst_QJSValue::toVariant() QCOMPARE(qjsvalue_cast<QVariant>(undef), QVariant()); QJSValue nil = QJSValue(QJSValue::NullValue); - QCOMPARE(nil.toVariant(), QVariant(QMetaType::VoidStar, 0)); - QCOMPARE(qjsvalue_cast<QVariant>(nil), QVariant(QMetaType::VoidStar, 0)); + QCOMPARE(nil.toVariant(), QVariant::fromValue(nullptr)); + QCOMPARE(qjsvalue_cast<QVariant>(nil), QVariant::fromValue(nullptr)); } // array diff --git a/tests/auto/qml/qml.pro b/tests/auto/qml/qml.pro index 28f04be5d7..68a2eace19 100644 --- a/tests/auto/qml/qml.pro +++ b/tests/auto/qml/qml.pro @@ -8,7 +8,6 @@ PUBLICTESTS += \ qjsvalueiterator \ qjsonbinding \ qmlmin \ - qmlplugindump \ qqmlcomponent \ qqmlconsole \ qqmlengine \ @@ -61,7 +60,9 @@ PRIVATETESTS += \ v4misc \ qqmltranslation \ qqmlimport \ - qqmlobjectmodel + qqmlobjectmodel \ + qmldiskcache \ + qv4mm qtHaveModule(widgets) { PUBLICTESTS += \ @@ -72,14 +73,13 @@ qtHaveModule(widgets) { SUBDIRS += $$PUBLICTESTS \ qqmlextensionplugin SUBDIRS += $$METATYPETESTS -!winrt { # no QProcess on winrt +!uikit:!winrt { # no QProcess on uikit/winrt !contains(QT_CONFIG, no-qml-debug): SUBDIRS += debugger - SUBDIRS += qmllint + SUBDIRS += qmllint qmlplugindump } -contains(QT_CONFIG, private_tests) { +qtConfig(private_tests): \ SUBDIRS += $$PRIVATETESTS -} qtNomakeTools( \ qmlplugindump \ diff --git a/tests/auto/qml/qmldiskcache/qmldiskcache.pro b/tests/auto/qml/qmldiskcache/qmldiskcache.pro new file mode 100644 index 0000000000..f98a157b6a --- /dev/null +++ b/tests/auto/qml/qmldiskcache/qmldiskcache.pro @@ -0,0 +1,9 @@ +CONFIG += testcase +TARGET = tst_qmldiskcache +osx:CONFIG -= app_bundle + +SOURCES += tst_qmldiskcache.cpp + +RESOURCES += test.qml + +QT += core-private qml-private testlib diff --git a/tests/auto/qml/qmldiskcache/test.qml b/tests/auto/qml/qmldiskcache/test.qml new file mode 100644 index 0000000000..d632422616 --- /dev/null +++ b/tests/auto/qml/qmldiskcache/test.qml @@ -0,0 +1,4 @@ +import QtQml 2.0 +QtObject { + property int value: 20 +} diff --git a/tests/auto/qml/qmldiskcache/tst_qmldiskcache.cpp b/tests/auto/qml/qmldiskcache/tst_qmldiskcache.cpp new file mode 100644 index 0000000000..e2c0055ea1 --- /dev/null +++ b/tests/auto/qml/qmldiskcache/tst_qmldiskcache.cpp @@ -0,0 +1,671 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the test suite of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:GPL-EXCEPT$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 as published by the Free Software +** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include <qtest.h> + +#include <private/qv4compileddata_p.h> +#include <private/qv4compiler_p.h> +#include <private/qv4jsir_p.h> +#include <private/qv4isel_p.h> +#include <private/qv8engine_p.h> +#include <private/qv4engine_p.h> +#include <QQmlComponent> +#include <QQmlEngine> +#include <QQmlFileSelector> +#include <QThread> +#include <QCryptographicHash> +#include <QStandardPaths> +#include <QDirIterator> + +class tst_qmldiskcache: public QObject +{ + Q_OBJECT + +private slots: + void initTestCase(); + + void regenerateAfterChange(); + void registerImportForImplicitComponent(); + void basicVersionChecks(); + void recompileAfterChange(); + void fileSelectors(); + void localAliases(); + void cacheResources(); + void stableOrderOfDependentCompositeTypes(); +}; + +// A wrapper around QQmlComponent to ensure the temporary reference counts +// on the type data as a result of the main thread <> loader thread communication +// are dropped. Regular Synchronous loading will leave us with an event posted +// to the gui thread and an extra refcount that will only be dropped after the +// event delivery. A plain sendPostedEvents() however is insufficient because +// we can't be sure that the event is posted after the constructor finished. +class CleanlyLoadingComponent : public QQmlComponent +{ +public: + CleanlyLoadingComponent(QQmlEngine *engine, const QUrl &url) + : QQmlComponent(engine, url, QQmlComponent::Asynchronous) + { waitForLoad(); } + CleanlyLoadingComponent(QQmlEngine *engine, const QString &fileName) + : QQmlComponent(engine, fileName, QQmlComponent::Asynchronous) + { waitForLoad(); } + + void waitForLoad() + { + QTRY_VERIFY(status() == QQmlComponent::Ready || status() == QQmlComponent::Error); + } +}; + +static void waitForFileSystem() +{ + // On macOS with HFS+ the precision of file times is measured in seconds, so to ensure that + // the newly written file has a modification date newer than an existing cache file, we must + // wait. + // Similar effects of lacking precision have been observed on some Linux systems. + QThread::sleep(1); +} + +struct TestCompiler +{ + TestCompiler(QQmlEngine *engine) + : engine(engine) + , tempDir() + , testFilePath(tempDir.path() + QStringLiteral("/test.qml")) + , cacheFilePath(tempDir.path() + QStringLiteral("/test.qmlc")) + , mappedFile(cacheFilePath) + , currentMapping(nullptr) + { + } + + bool compile(const QByteArray &contents) + { + closeMapping(); + engine->clearComponentCache(); + + waitForFileSystem(); + + { + QFile f(testFilePath); + if (!f.open(QIODevice::WriteOnly | QIODevice::Truncate)) { + lastErrorString = f.errorString(); + return false; + } + if (f.write(contents) != contents.size()) { + lastErrorString = f.errorString(); + return false; + } + } + + CleanlyLoadingComponent component(engine, testFilePath); + if (!component.isReady()) { + lastErrorString = component.errorString(); + return false; + } + + return true; + } + + const QV4::CompiledData::Unit *mapUnit() + { + if (!mappedFile.open(QIODevice::ReadOnly)) { + lastErrorString = mappedFile.errorString(); + return nullptr; + } + + currentMapping = mappedFile.map(/*offset*/0, mappedFile.size()); + if (!currentMapping) { + lastErrorString = mappedFile.errorString(); + return nullptr; + } + QV4::CompiledData::Unit *unitPtr; + memcpy(&unitPtr, ¤tMapping, sizeof(unitPtr)); + return unitPtr; + } + + typedef void (*HeaderTweakFunction)(QV4::CompiledData::Unit *header); + bool tweakHeader(HeaderTweakFunction function) + { + closeMapping(); + + QFile f(cacheFilePath); + if (!f.open(QIODevice::ReadWrite)) + return false; + QV4::CompiledData::Unit header; + if (f.read(reinterpret_cast<char *>(&header), sizeof(header)) != sizeof(header)) + return false; + function(&header); + f.seek(0); + return f.write(reinterpret_cast<const char *>(&header), sizeof(header)) == sizeof(header); + } + + bool verify() + { + QV4::ExecutionEngine *v4 = QV8Engine::getV4(engine); + QQmlRefPointer<QV4::CompiledData::CompilationUnit> unit = v4->iselFactory->createUnitForLoading(); + return unit->loadFromDisk(QUrl::fromLocalFile(testFilePath), v4->iselFactory.data(), &lastErrorString); + } + + void closeMapping() + { + if (currentMapping) { + mappedFile.unmap(currentMapping); + currentMapping = nullptr; + } + mappedFile.close(); + } + + void clearCache() + { + closeMapping(); + QFile::remove(cacheFilePath); + } + + QQmlEngine *engine; + const QTemporaryDir tempDir; + const QString testFilePath; + const QString cacheFilePath; + QString lastErrorString; + QFile mappedFile; + uchar *currentMapping; +}; + +void tst_qmldiskcache::initTestCase() +{ + qputenv("QML_FORCE_DISK_CACHE", "1"); +} + +void tst_qmldiskcache::regenerateAfterChange() +{ + QQmlEngine engine; + TestCompiler testCompiler(&engine); + + QVERIFY(testCompiler.tempDir.isValid()); + + const QByteArray contents = QByteArrayLiteral("import QtQml 2.0\n" + "QtObject {\n" + " property string blah: Qt.platform;\n" + "}"); + + QVERIFY2(testCompiler.compile(contents), qPrintable(testCompiler.lastErrorString)); + + { + const QV4::CompiledData::Unit *testUnit = testCompiler.mapUnit(); + QVERIFY2(testUnit, qPrintable(testCompiler.lastErrorString)); + + QCOMPARE(quint32(testUnit->nObjects), quint32(1)); + + const QV4::CompiledData::Object *obj = testUnit->objectAt(0); + QCOMPARE(quint32(obj->nBindings), quint32(1)); + QCOMPARE(quint32(obj->bindingTable()->type), quint32(QV4::CompiledData::Binding::Type_Script)); + QCOMPARE(quint32(obj->bindingTable()->value.compiledScriptIndex), quint32(1)); + + QCOMPARE(quint32(testUnit->functionTableSize), quint32(2)); + + const QV4::CompiledData::Function *bindingFunction = testUnit->functionAt(1); + QVERIFY(bindingFunction->codeOffset > testUnit->unitSize); + } + + { + const QByteArray newContents = QByteArrayLiteral("import QtQml 2.0\n" + "QtObject {\n" + " property string blah: Qt.platform;\n" + " property int secondProperty: 42;\n" + "}"); + + QVERIFY2(testCompiler.compile(newContents), qPrintable(testCompiler.lastErrorString)); + const QV4::CompiledData::Unit *testUnit = testCompiler.mapUnit(); + QVERIFY2(testUnit, qPrintable(testCompiler.lastErrorString)); + + QCOMPARE(quint32(testUnit->nObjects), quint32(1)); + + const QV4::CompiledData::Object *obj = testUnit->objectAt(0); + QCOMPARE(quint32(obj->nBindings), quint32(2)); + QCOMPARE(quint32(obj->bindingTable()->type), quint32(QV4::CompiledData::Binding::Type_Number)); + QCOMPARE(obj->bindingTable()->valueAsNumber(), double(42)); + + QCOMPARE(quint32(testUnit->functionTableSize), quint32(2)); + + const QV4::CompiledData::Function *bindingFunction = testUnit->functionAt(1); + QVERIFY(bindingFunction->codeOffset > testUnit->unitSize); + } +} + +void tst_qmldiskcache::registerImportForImplicitComponent() +{ + QQmlEngine engine; + + TestCompiler testCompiler(&engine); + QVERIFY(testCompiler.tempDir.isValid()); + + const QByteArray contents = QByteArrayLiteral("import QtQuick 2.0\n" + "Loader {\n" + " sourceComponent: Item {}\n" + "}"); + + QVERIFY2(testCompiler.compile(contents), qPrintable(testCompiler.lastErrorString)); + { + const QV4::CompiledData::Unit *testUnit = testCompiler.mapUnit(); + QVERIFY2(testUnit, qPrintable(testCompiler.lastErrorString)); + + QCOMPARE(quint32(testUnit->nImports), quint32(2)); + QCOMPARE(testUnit->stringAt(testUnit->importAt(0)->uriIndex), QStringLiteral("QtQuick")); + + QQmlType *componentType = QQmlMetaType::qmlType(&QQmlComponent::staticMetaObject); + + QCOMPARE(testUnit->stringAt(testUnit->importAt(1)->uriIndex), QString(componentType->module())); + QCOMPARE(testUnit->stringAt(testUnit->importAt(1)->qualifierIndex), QStringLiteral("QmlInternals")); + + QCOMPARE(quint32(testUnit->nObjects), quint32(3)); + + const QV4::CompiledData::Object *obj = testUnit->objectAt(0); + QCOMPARE(quint32(obj->nBindings), quint32(1)); + QCOMPARE(quint32(obj->bindingTable()->type), quint32(QV4::CompiledData::Binding::Type_Object)); + + const QV4::CompiledData::Object *implicitComponent = testUnit->objectAt(obj->bindingTable()->value.objectIndex); + QCOMPARE(testUnit->stringAt(implicitComponent->inheritedTypeNameIndex), QStringLiteral("QmlInternals.") + componentType->elementName()); + } +} + +void tst_qmldiskcache::basicVersionChecks() +{ + QQmlEngine engine; + + TestCompiler testCompiler(&engine); + QVERIFY(testCompiler.tempDir.isValid()); + + const QByteArray contents = QByteArrayLiteral("import QtQml 2.0\n" + "QtObject {\n" + " property string blah: Qt.platform;\n" + "}"); + + { + testCompiler.clearCache(); + QVERIFY2(testCompiler.compile(contents), qPrintable(testCompiler.lastErrorString)); + QVERIFY2(testCompiler.verify(), qPrintable(testCompiler.lastErrorString)); + } + + { + testCompiler.clearCache(); + QVERIFY2(testCompiler.compile(contents), qPrintable(testCompiler.lastErrorString)); + + testCompiler.tweakHeader([](QV4::CompiledData::Unit *header) { + header->qtVersion = 0; + }); + + QVERIFY(!testCompiler.verify()); + QCOMPARE(testCompiler.lastErrorString, QString::fromUtf8("Qt version mismatch. Found 0 expected %1").arg(QT_VERSION, 0, 16)); + testCompiler.clearCache(); + } + + { + testCompiler.clearCache(); + QVERIFY2(testCompiler.compile(contents), qPrintable(testCompiler.lastErrorString)); + + testCompiler.tweakHeader([](QV4::CompiledData::Unit *header) { + header->version = 0; + }); + + QVERIFY(!testCompiler.verify()); + QCOMPARE(testCompiler.lastErrorString, QString::fromUtf8("V4 data structure version mismatch. Found 0 expected %1").arg(QV4_DATA_STRUCTURE_VERSION, 0, 16)); + } + + { + testCompiler.clearCache(); + QVERIFY2(testCompiler.compile(contents), qPrintable(testCompiler.lastErrorString)); + + testCompiler.tweakHeader([](QV4::CompiledData::Unit *header) { + header->architectureIndex = 0; + }); + + QVERIFY(!testCompiler.verify()); + QCOMPARE(testCompiler.lastErrorString, QString::fromUtf8("Architecture mismatch. Found expected %1").arg(QSysInfo::buildAbi())); + } + + { + testCompiler.clearCache(); + QVERIFY2(testCompiler.compile(contents), qPrintable(testCompiler.lastErrorString)); + + testCompiler.tweakHeader([](QV4::CompiledData::Unit *header) { + header->codeGeneratorIndex = 0; + }); + + QVERIFY(!testCompiler.verify()); + QCOMPARE(testCompiler.lastErrorString, QString::fromUtf8("Code generator mismatch. Found code generated by but expected %1").arg(QV8Engine::getV4(&engine)->iselFactory->codeGeneratorName)); + } +} + +class TypeVersion1 : public QObject +{ + Q_OBJECT + Q_PROPERTY(int value READ value WRITE setValue NOTIFY valueChanged); +public: + + + int m_value = 0; + int value() const { return m_value; } + void setValue(int v) { m_value = v; emit valueChanged(); } + +signals: + void valueChanged(); +}; + +// Same as TypeVersion1 except the property type changed! +class TypeVersion2 : public QObject +{ + Q_OBJECT + Q_PROPERTY(QString value READ value WRITE setValue NOTIFY valueChanged); +public: + + + QString m_value; + QString value() const { return m_value; } + void setValue(QString v) { m_value = v; emit valueChanged(); } + +signals: + void valueChanged(); +}; + +void tst_qmldiskcache::recompileAfterChange() +{ + QQmlEngine engine; + + TestCompiler testCompiler(&engine); + QVERIFY(testCompiler.tempDir.isValid()); + + const QByteArray contents = QByteArrayLiteral("import TypeTest 1.0\n" + "TypeThatWillChange {\n" + "}"); + + qmlRegisterType<TypeVersion1>("TypeTest", 1, 0, "TypeThatWillChange"); + + { + testCompiler.clearCache(); + QVERIFY2(testCompiler.compile(contents), qPrintable(testCompiler.lastErrorString)); + QVERIFY2(testCompiler.verify(), qPrintable(testCompiler.lastErrorString)); + } + + QDateTime initialCacheTimeStamp = QFileInfo(testCompiler.cacheFilePath).lastModified(); + + { + CleanlyLoadingComponent component(&engine, testCompiler.testFilePath); + QScopedPointer<TypeVersion1> obj(qobject_cast<TypeVersion1*>(component.create())); + QVERIFY(!obj.isNull()); + QCOMPARE(QFileInfo(testCompiler.cacheFilePath).lastModified(), initialCacheTimeStamp); + } + + engine.clearComponentCache(); + + { + CleanlyLoadingComponent component(&engine, testCompiler.testFilePath); + QScopedPointer<TypeVersion1> obj(qobject_cast<TypeVersion1*>(component.create())); + QVERIFY(!obj.isNull()); + QCOMPARE(QFileInfo(testCompiler.cacheFilePath).lastModified(), initialCacheTimeStamp); + } + + engine.clearComponentCache(); + qmlClearTypeRegistrations(); + qmlRegisterType<TypeVersion2>("TypeTest", 1, 0, "TypeThatWillChange"); + + waitForFileSystem(); + + { + CleanlyLoadingComponent component(&engine, testCompiler.testFilePath); + QScopedPointer<TypeVersion2> obj(qobject_cast<TypeVersion2*>(component.create())); + QVERIFY(!obj.isNull()); + QVERIFY(QFileInfo(testCompiler.cacheFilePath).lastModified() > initialCacheTimeStamp); + } +} + +void tst_qmldiskcache::fileSelectors() +{ + QQmlEngine engine; + + QTemporaryDir tempDir; + QVERIFY(tempDir.isValid()); + + const QString testFilePath = tempDir.path() + "/test.qml"; + { + QFile f(testFilePath); + QVERIFY2(f.open(QIODevice::WriteOnly), qPrintable(f.errorString())); + f.write(QByteArrayLiteral("import QtQml 2.0\nQtObject { property int value: 42 }")); + } + + const QString selector = QStringLiteral("testSelector"); + const QString selectorPath = tempDir.path() + "/+" + selector; + const QString selectedTestFilePath = selectorPath + "/test.qml"; + { + QVERIFY(QDir::root().mkpath(selectorPath)); + QFile f(selectorPath + "/test.qml"); + QVERIFY2(f.open(QIODevice::WriteOnly), qPrintable(f.errorString())); + f.write(QByteArrayLiteral("import QtQml 2.0\nQtObject { property int value: 100 }")); + } + + { + QQmlComponent component(&engine, testFilePath); + QScopedPointer<QObject> obj(component.create()); + QVERIFY(!obj.isNull()); + QCOMPARE(obj->property("value").toInt(), 42); + + QFile cacheFile(testFilePath + "c"); + QVERIFY2(cacheFile.exists(), qPrintable(cacheFile.fileName())); + } + + QQmlFileSelector qmlSelector(&engine); + qmlSelector.setExtraSelectors(QStringList() << selector); + + engine.clearComponentCache(); + + { + QQmlComponent component(&engine, testFilePath); + QScopedPointer<QObject> obj(component.create()); + QVERIFY(!obj.isNull()); + QCOMPARE(obj->property("value").toInt(), 100); + + QFile cacheFile(selectedTestFilePath + "c"); + QVERIFY2(cacheFile.exists(), qPrintable(cacheFile.fileName())); + } +} + +void tst_qmldiskcache::localAliases() +{ + QQmlEngine engine; + + TestCompiler testCompiler(&engine); + QVERIFY(testCompiler.tempDir.isValid()); + + const QByteArray contents = QByteArrayLiteral("import QtQml 2.0\n" + "QtObject {\n" + " id: root\n" + " property int prop: 100\n" + " property alias dummy1: root.prop\n" + " property alias dummy2: root.prop\n" + " property alias dummy3: root.prop\n" + " property alias dummy4: root.prop\n" + " property alias dummy5: root.prop\n" + " property alias foo: root.prop\n" + " property alias bar: root.foo\n" + "}"); + + { + testCompiler.clearCache(); + QVERIFY2(testCompiler.compile(contents), qPrintable(testCompiler.lastErrorString)); + QVERIFY2(testCompiler.verify(), qPrintable(testCompiler.lastErrorString)); + } + + { + CleanlyLoadingComponent component(&engine, testCompiler.testFilePath); + QScopedPointer<QObject> obj(component.create()); + QVERIFY(!obj.isNull()); + QCOMPARE(obj->property("bar").toInt(), 100); + } + + engine.clearComponentCache(); + + { + CleanlyLoadingComponent component(&engine, testCompiler.testFilePath); + QScopedPointer<QObject> obj(component.create()); + QVERIFY(!obj.isNull()); + QCOMPARE(obj->property("bar").toInt(), 100); + } +} + +void tst_qmldiskcache::cacheResources() +{ + const QString cacheDirectory = QStandardPaths::writableLocation(QStandardPaths::CacheLocation); + QVERIFY(QDir::root().mkpath(cacheDirectory)); + + const QString qmlCacheDirectory = cacheDirectory + QLatin1String("/qmlcache/"); + QVERIFY(QDir(qmlCacheDirectory).removeRecursively()); + QVERIFY(QDir::root().mkpath(qmlCacheDirectory)); + QVERIFY(QDir(qmlCacheDirectory).entryList(QDir::NoDotAndDotDot).isEmpty()); + + + QQmlEngine engine; + + { + CleanlyLoadingComponent component(&engine, QUrl("qrc:/test.qml")); + qDebug() << component.errorString(); + QScopedPointer<QObject> obj(component.create()); + QVERIFY(!obj.isNull()); + QCOMPARE(obj->property("value").toInt(), 20); + } + + const QStringList entries = QDir(qmlCacheDirectory).entryList(QDir::NoDotAndDotDot | QDir::Files); + QCOMPARE(entries.count(), 1); + + { + QFile cacheFile(qmlCacheDirectory + QLatin1Char('/') + entries.constFirst()); + QVERIFY2(cacheFile.open(QIODevice::ReadOnly), qPrintable(cacheFile.errorString())); + QV4::CompiledData::Unit unit; + QVERIFY(cacheFile.read(reinterpret_cast<char *>(&unit), sizeof(unit)) == sizeof(unit)); + QCOMPARE(qint64(unit.sourceTimeStamp), QFileInfo(QCoreApplication::applicationFilePath()).lastModified().toMSecsSinceEpoch()); + } +} + +void tst_qmldiskcache::stableOrderOfDependentCompositeTypes() +{ + QQmlEngine engine; + + QTemporaryDir tempDir; + QVERIFY(tempDir.isValid()); + + { + const QString depFilePath = tempDir.path() + "/FirstDependentType.qml"; + QFile f(depFilePath); + QVERIFY2(f.open(QIODevice::WriteOnly), qPrintable(f.errorString())); + f.write(QByteArrayLiteral("import QtQml 2.0\nQtObject { property int value: 42 }")); + } + + { + const QString depFilePath = tempDir.path() + "/SecondDependentType.qml"; + QFile f(depFilePath); + QVERIFY2(f.open(QIODevice::WriteOnly), qPrintable(f.errorString())); + f.write(QByteArrayLiteral("import QtQml 2.0\nQtObject { property int value: 100 }")); + } + + const QString testFilePath = tempDir.path() + "/main.qml"; + { + QFile f(testFilePath); + QVERIFY2(f.open(QIODevice::WriteOnly), qPrintable(f.errorString())); + f.write(QByteArrayLiteral("import QtQml 2.0\nQtObject {\n" + " property QtObject dep1: FirstDependentType{}\n" + " property QtObject dep2: SecondDependentType{}\n" + " property int value: dep1.value + dep2.value\n" + "}")); + } + + QByteArray firstDependentTypeClassName; + QByteArray secondDependentTypeClassName; + + { + CleanlyLoadingComponent component(&engine, QUrl::fromLocalFile(testFilePath)); + QScopedPointer<QObject> obj(component.create()); + QVERIFY(!obj.isNull()); + QCOMPARE(obj->property("value").toInt(), 142); + + firstDependentTypeClassName = qvariant_cast<QObject *>(obj->property("dep1"))->metaObject()->className(); + secondDependentTypeClassName = qvariant_cast<QObject *>(obj->property("dep2"))->metaObject()->className(); + } + + QVERIFY(firstDependentTypeClassName != secondDependentTypeClassName); + QVERIFY2(firstDependentTypeClassName.contains("QMLTYPE"), firstDependentTypeClassName.constData()); + QVERIFY2(secondDependentTypeClassName.contains("QMLTYPE"), secondDependentTypeClassName.constData()); + + const QString testFileCachePath = testFilePath + QLatin1Char('c'); + QVERIFY(QFile::exists(testFileCachePath)); + QDateTime initialCacheTimeStamp = QFileInfo(testFileCachePath).lastModified(); + + engine.clearComponentCache(); + waitForFileSystem(); + + // Creating the test component a second time should load it from the cache (same time stamp), + // despite the class names of the dependent composite types differing. + { + CleanlyLoadingComponent component(&engine, QUrl::fromLocalFile(testFilePath)); + QScopedPointer<QObject> obj(component.create()); + QVERIFY(!obj.isNull()); + QCOMPARE(obj->property("value").toInt(), 142); + + QVERIFY(qvariant_cast<QObject *>(obj->property("dep1"))->metaObject()->className() != firstDependentTypeClassName); + QVERIFY(qvariant_cast<QObject *>(obj->property("dep2"))->metaObject()->className() != secondDependentTypeClassName); + } + + { + QVERIFY(QFile::exists(testFileCachePath)); + QDateTime newCacheTimeStamp = QFileInfo(testFileCachePath).lastModified(); + QCOMPARE(newCacheTimeStamp, initialCacheTimeStamp); + } + + // Now change the first dependent QML type and see if we correctly re-generate the + // caches. + engine.clearComponentCache(); + waitForFileSystem(); + { + const QString depFilePath = tempDir.path() + "/FirstDependentType.qml"; + QFile f(depFilePath); + QVERIFY2(f.open(QIODevice::WriteOnly), qPrintable(f.errorString())); + f.write(QByteArrayLiteral("import QtQml 2.0\nQtObject { property int value: 40 }")); + } + + { + CleanlyLoadingComponent component(&engine, QUrl::fromLocalFile(testFilePath)); + QScopedPointer<QObject> obj(component.create()); + QVERIFY(!obj.isNull()); + QCOMPARE(obj->property("value").toInt(), 140); + } + + { + QVERIFY(QFile::exists(testFileCachePath)); + QDateTime newCacheTimeStamp = QFileInfo(testFileCachePath).lastModified(); + QVERIFY2(newCacheTimeStamp > initialCacheTimeStamp, qPrintable(newCacheTimeStamp.toString())); + } +} + +QTEST_MAIN(tst_qmldiskcache) + +#include "tst_qmldiskcache.moc" diff --git a/tests/auto/qml/qmlplugindump/tst_qmlplugindump.cpp b/tests/auto/qml/qmlplugindump/tst_qmlplugindump.cpp index ee417bb480..838966e2a0 100644 --- a/tests/auto/qml/qmlplugindump/tst_qmlplugindump.cpp +++ b/tests/auto/qml/qmlplugindump/tst_qmlplugindump.cpp @@ -108,6 +108,7 @@ void tst_qmlplugindump::singleton() dumper.waitForFinished(); const QString &result = dumper.readAllStandardOutput(); + qDebug() << "result: " << result; QVERIFY(result.contains(QLatin1String("exports: [\"Singleton 1.0\"]"))); QVERIFY(result.contains(QLatin1String("exportMetaObjectRevisions: [0]"))); } diff --git a/tests/auto/qml/qqmlbinding/data/delayed.qml b/tests/auto/qml/qqmlbinding/data/delayed.qml new file mode 100644 index 0000000000..6f8281cc33 --- /dev/null +++ b/tests/auto/qml/qqmlbinding/data/delayed.qml @@ -0,0 +1,26 @@ +import QtQuick 2.8 + +Item { + width: 400 + height: 400 + + property int changeCount: 0 + + property string text1 + property string text2 + + function updateText() { + text1 = "Hello" + text2 = "World" + } + + Text { + anchors.centerIn: parent + Binding on text { + value: text1 + " " + text2 + delayed: true + } + onTextChanged: ++changeCount + } +} + diff --git a/tests/auto/qml/qqmlbinding/tst_qqmlbinding.cpp b/tests/auto/qml/qqmlbinding/tst_qqmlbinding.cpp index 3e8dfbdb12..6f1d82eca5 100644 --- a/tests/auto/qml/qqmlbinding/tst_qqmlbinding.cpp +++ b/tests/auto/qml/qqmlbinding/tst_qqmlbinding.cpp @@ -49,6 +49,7 @@ private slots: void warningOnReadOnlyProperty(); void disabledOnUnknownProperty(); void disabledOnReadonlyProperty(); + void delayed(); private: QQmlEngine engine; @@ -281,6 +282,27 @@ void tst_qqmlbinding::disabledOnReadonlyProperty() QCOMPARE(messageHandler.messages().count(), 0); } +void tst_qqmlbinding::delayed() +{ + QQmlEngine engine; + QQmlComponent c(&engine, testFileUrl("delayed.qml")); + QQuickItem *item = qobject_cast<QQuickItem*>(c.create()); + + QVERIFY(item != 0); + // update on creation + QCOMPARE(item->property("changeCount").toInt(), 1); + + QMetaObject::invokeMethod(item, "updateText"); + // doesn't update immediately + QCOMPARE(item->property("changeCount").toInt(), 1); + + QCoreApplication::processEvents(); + // only updates once (non-delayed would update twice) + QCOMPARE(item->property("changeCount").toInt(), 2); + + delete item; +} + QTEST_MAIN(tst_qqmlbinding) #include "tst_qqmlbinding.moc" diff --git a/tests/auto/qml/qqmlconsole/data/categorized_logging.qml b/tests/auto/qml/qqmlconsole/data/categorized_logging.qml new file mode 100644 index 0000000000..d19b6ecc41 --- /dev/null +++ b/tests/auto/qml/qqmlconsole/data/categorized_logging.qml @@ -0,0 +1,65 @@ +/**************************************************************************** +** +** Copyright (C) 2016 Pelagicore AG +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the QtQml module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or (at your option) the GNU General +** Public license version 3 or any later version approved by the KDE Free +** Qt Foundation. The licenses are as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +import QtQuick 2.8 + +Item { + id:root + + LoggingCategory { + id: testCategory + name: "qt.test" + } + + LoggingCategory { + id: emptyCategory + } + + Component.onCompleted: { + console.debug(testCategory, "console.debug"); + console.log(testCategory, "console.log"); + console.info(testCategory, "console.info"); + console.warn(testCategory, "console.warn"); + console.error(testCategory, "console.error"); + + testCategory.name = "qt.test2"; + + console.error(emptyCategory, "console.error"); + } +} diff --git a/tests/auto/qml/qqmlconsole/tst_qqmlconsole.cpp b/tests/auto/qml/qqmlconsole/tst_qqmlconsole.cpp index f12656c5fe..f832143935 100644 --- a/tests/auto/qml/qqmlconsole/tst_qqmlconsole.cpp +++ b/tests/auto/qml/qqmlconsole/tst_qqmlconsole.cpp @@ -40,6 +40,7 @@ public: private slots: void logging(); + void categorized_logging(); void tracing(); void profiling(); void testAssert(); @@ -87,6 +88,41 @@ void tst_qqmlconsole::logging() delete object; } +void tst_qqmlconsole::categorized_logging() +{ + QUrl testUrl = testFileUrl("categorized_logging.qml"); + QQmlTestMessageHandler messageHandler; + messageHandler.setIncludeCategoriesEnabled(true); + + QLoggingCategory testCategory("qt.test"); + testCategory.setEnabled(QtDebugMsg, true); + QVERIFY(testCategory.isDebugEnabled()); + QVERIFY(testCategory.isWarningEnabled()); + QVERIFY(testCategory.isCriticalEnabled()); + + QQmlComponent component(&engine, testUrl); + QObject *object = component.create(); + QVERIFY2(object != 0, component.errorString().toUtf8()); + + QVERIFY(messageHandler.messages().contains("qt.test: console.info")); + QVERIFY(messageHandler.messages().contains("qt.test: console.warn")); + QVERIFY(messageHandler.messages().contains("qt.test: console.error")); + + QString emptyCategory = "default: " + QString::fromLatin1("%1:%2:%3: ").arg(testUrl.toString()).arg(50).arg(5) + + "QML LoggingCategory: Declaring the name of the LoggingCategory is mandatory and cannot be changed later !"; + QVERIFY(messageHandler.messages().contains(emptyCategory)); + + QString changedCategory = "default: " + QString::fromLatin1("%1:%2:%3: ").arg(testUrl.toString()).arg(45).arg(5) + + "QML LoggingCategory: The name of a LoggingCategory cannot be changed after the Item is created"; + QVERIFY(messageHandler.messages().contains(changedCategory)); + + QString useEmptyCategory = "default: " + QString::fromLatin1("%1:%2: ").arg(testUrl.toString()).arg(63) + + "Error: A QmlLoggingCatgory was provided without a valid name"; + QVERIFY(messageHandler.messages().contains(useEmptyCategory)); + + delete object; +} + void tst_qqmlconsole::tracing() { QUrl testUrl = testFileUrl("tracing.qml"); diff --git a/tests/auto/qml/qqmlecmascript/data/NullObjectInitializerBase.qml b/tests/auto/qml/qqmlecmascript/data/NullObjectInitializerBase.qml new file mode 100644 index 0000000000..4006a2a782 --- /dev/null +++ b/tests/auto/qml/qqmlecmascript/data/NullObjectInitializerBase.qml @@ -0,0 +1,5 @@ +import QtQml 2.0 +QtObject { + property Component factory: Component { QtObject {} } + property QtObject testProperty: factory.createObject() +} diff --git a/tests/auto/qml/qqmlecmascript/data/dependenciesWithFunctions.qml b/tests/auto/qml/qqmlecmascript/data/dependenciesWithFunctions.qml new file mode 100644 index 0000000000..57d3ae2f14 --- /dev/null +++ b/tests/auto/qml/qqmlecmascript/data/dependenciesWithFunctions.qml @@ -0,0 +1,12 @@ +import QtQml 2.0 +QtObject { + property int value: 100 + property bool success: { + unrelatedFunction(); + return value == 42; + } + property int unrelatedValue: 100 + function unrelatedFunction() { + return unrelatedValue; + } +} diff --git a/tests/auto/qml/qqmlecmascript/data/nullObjectInitializer.2.qml b/tests/auto/qml/qqmlecmascript/data/nullObjectInitializer.2.qml new file mode 100644 index 0000000000..d59f8f99f9 --- /dev/null +++ b/tests/auto/qml/qqmlecmascript/data/nullObjectInitializer.2.qml @@ -0,0 +1,8 @@ +import QtQml 2.0 +NullObjectInitializerBase { + testProperty: null + property bool success: false + Component.onCompleted: { + success = testProperty === null; + } +} diff --git a/tests/auto/qml/qqmlecmascript/data/nullObjectInitializer.qml b/tests/auto/qml/qqmlecmascript/data/nullObjectInitializer.qml new file mode 100644 index 0000000000..32bc62c9f2 --- /dev/null +++ b/tests/auto/qml/qqmlecmascript/data/nullObjectInitializer.qml @@ -0,0 +1,4 @@ +import QtQml 2.0 +QtObject { + property QtObject testProperty: null +} diff --git a/tests/auto/qml/qqmlecmascript/testtypes.h b/tests/auto/qml/qqmlecmascript/testtypes.h index d4d051443f..47fb2a56e7 100644 --- a/tests/auto/qml/qqmlecmascript/testtypes.h +++ b/tests/auto/qml/qqmlecmascript/testtypes.h @@ -790,7 +790,8 @@ public: Q_INVOKABLE void method_QObject(QObject *a) { invoke(13); m_actuals << qVariantFromValue(a); } Q_INVOKABLE void method_QScriptValue(QJSValue a) { invoke(14); m_actuals << qVariantFromValue(a); } Q_INVOKABLE void method_intQScriptValue(int a, QJSValue b) { invoke(15); m_actuals << a << qVariantFromValue(b); } - Q_INVOKABLE QJSValue method_intQJSValue(int a, QJSValue b) { invoke(29); m_actuals << a << qVariantFromValue(b); return b.call(); } + Q_INVOKABLE void method_QByteArray(QByteArray value) { invoke(29); m_actuals << value; } + Q_INVOKABLE QJSValue method_intQJSValue(int a, QJSValue b) { invoke(30); m_actuals << a << qVariantFromValue(b); return b.call(); } Q_INVOKABLE QJSValue method_intQJSValue(int a, int b) { m_actuals << a << b; return QJSValue();} // Should never be called. Q_INVOKABLE void method_overload(int a) { invoke(16); m_actuals << a; } diff --git a/tests/auto/qml/qqmlecmascript/tst_qqmlecmascript.cpp b/tests/auto/qml/qqmlecmascript/tst_qqmlecmascript.cpp index 26a15d730c..be04ec2bf3 100644 --- a/tests/auto/qml/qqmlecmascript/tst_qqmlecmascript.cpp +++ b/tests/auto/qml/qqmlecmascript/tst_qqmlecmascript.cpp @@ -84,6 +84,7 @@ private slots: void arrayExpressions(); void contextPropertiesTriggerReeval(); void objectPropertiesTriggerReeval(); + void dependenciesWithFunctions(); void deferredProperties(); void deferredPropertiesErrors(); void deferredPropertiesInComponents(); @@ -210,6 +211,7 @@ private slots: void dynamicCreationOwnership(); void regExpBug(); void nullObjectBinding(); + void nullObjectInitializer(); void deletedEngine(); void libraryScriptAssert(); void variantsAssignedUndefined(); @@ -881,6 +883,18 @@ void tst_qqmlecmascript::objectPropertiesTriggerReeval() } } +void tst_qqmlecmascript::dependenciesWithFunctions() +{ + QQmlEngine engine; + QQmlComponent component(&engine, testFileUrl("dependenciesWithFunctions.qml")); + + QScopedPointer<QObject> object(component.create()); + QVERIFY2(object, qPrintable(component.errorString())); + QVERIFY(!object->property("success").toBool()); + object->setProperty("value", 42); + QVERIFY(object->property("success").toBool()); +} + void tst_qqmlecmascript::deferredProperties() { QQmlComponent component(&engine, testFileUrl("deferredProperties.qml")); @@ -2318,7 +2332,7 @@ static inline bool evaluate_error(QV8Engine *engine, const QV4::Value &o, const QV4::ScopedCallData d(scope, 1); d->args[0] = o; d->thisObject = engine->global(); - function->call(d); + function->call(scope, d); if (scope.engine->hasException) { scope.engine->catchException(); return true; @@ -2344,16 +2358,15 @@ static inline bool evaluate_value(QV8Engine *engine, const QV4::Value &o, if (!function) return false; - QV4::ScopedValue value(scope); QV4::ScopedCallData d(scope, 1); d->args[0] = o; d->thisObject = engine->global(); - value = function->call(d); + function->call(scope, d); if (scope.engine->hasException) { scope.engine->catchException(); return false; } - return QV4::Runtime::strictEqual(value, result); + return QV4::Runtime::method_strictEqual(scope.result, result); } static inline QV4::ReturnedValue evaluate(QV8Engine *engine, const QV4::Value &o, @@ -2377,12 +2390,12 @@ static inline QV4::ReturnedValue evaluate(QV8Engine *engine, const QV4::Value &o QV4::ScopedCallData d(scope, 1); d->args[0] = o; d->thisObject = engine->global(); - QV4::ScopedValue result(scope, function->call(d)); + function->call(scope, d); if (scope.engine->hasException) { scope.engine->catchException(); return QV4::Encode::undefined(); } - return result->asReturnedValue(); + return scope.result.asReturnedValue(); } #define EVALUATE_ERROR(source) evaluate_error(engine, object, source) @@ -2946,9 +2959,16 @@ void tst_qqmlecmascript::callQtInvokables() QCOMPARE(o->actuals().count(), 0); o->reset(); - QV4::ScopedValue ret(scope, EVALUATE("object.method_intQJSValue(123, function() { return \"Hello world!\";})")); + QVERIFY(EVALUATE_VALUE("object.method_QByteArray(\"Hello\")", QV4::Primitive::undefinedValue())); QCOMPARE(o->error(), false); QCOMPARE(o->invoked(), 29); + QCOMPARE(o->actuals().count(), 1); + QCOMPARE(qvariant_cast<QByteArray>(o->actuals().at(0)), QByteArray("Hello")); + + o->reset(); + QV4::ScopedValue ret(scope, EVALUATE("object.method_intQJSValue(123, function() { return \"Hello world!\";})")); + QCOMPARE(o->error(), false); + QCOMPARE(o->invoked(), 30); QVERIFY(ret->isString()); QCOMPARE(ret->toQStringNoThrow(), QString("Hello world!")); QCOMPARE(o->actuals().count(), 2); @@ -5707,6 +5727,49 @@ void tst_qqmlecmascript::nullObjectBinding() delete object; } +void tst_qqmlecmascript::nullObjectInitializer() +{ + { + QQmlComponent component(&engine, testFileUrl("nullObjectInitializer.qml")); + QScopedPointer<QObject> obj(component.create()); + QVERIFY(!obj.isNull()); + + QQmlData *ddata = QQmlData::get(obj.data(), /*create*/false); + QVERIFY(ddata); + + { + const int propertyIndex = obj->metaObject()->indexOfProperty("testProperty"); + QVERIFY(propertyIndex > 0); + QVERIFY(!ddata->hasBindingBit(propertyIndex)); + } + + QVariant value = obj->property("testProperty"); + QVERIFY(value.userType() == qMetaTypeId<QObject*>()); + QVERIFY(!value.value<QObject*>()); + } + + { + QQmlComponent component(&engine, testFileUrl("nullObjectInitializer.2.qml")); + QScopedPointer<QObject> obj(component.create()); + QVERIFY(!obj.isNull()); + + QQmlData *ddata = QQmlData::get(obj.data(), /*create*/false); + QVERIFY(ddata); + + { + const int propertyIndex = obj->metaObject()->indexOfProperty("testProperty"); + QVERIFY(propertyIndex > 0); + QVERIFY(ddata->hasBindingBit(propertyIndex)); + } + + QVERIFY(obj->property("success").toBool()); + + QVariant value = obj->property("testProperty"); + QVERIFY(value.userType() == qMetaTypeId<QObject*>()); + QVERIFY(!value.value<QObject*>()); + } +} + // Test that bindings don't evaluate once the engine has been destroyed void tst_qqmlecmascript::deletedEngine() { @@ -5768,7 +5831,7 @@ void tst_qqmlecmascript::variants() QVERIFY(object != 0); QCOMPARE(object->property("undefinedVariant").type(), QVariant::Invalid); - QCOMPARE(int(object->property("nullVariant").type()), int(QMetaType::VoidStar)); + QCOMPARE(int(object->property("nullVariant").type()), int(QMetaType::Nullptr)); QCOMPARE(object->property("intVariant").type(), QVariant::Int); QCOMPARE(object->property("doubleVariant").type(), QVariant::Double); @@ -7196,14 +7259,16 @@ namespace QV4 { namespace Heap { struct WeakReferenceSentinel : public Object { - WeakReferenceSentinel(WeakValue *weakRef, bool *resultPtr) - : weakRef(weakRef) - , resultPtr(resultPtr) { - + void init(WeakValue *weakRef, bool *resultPtr) + { + Object::init(); + this->weakRef = weakRef; + this->resultPtr = resultPtr; } - ~WeakReferenceSentinel() { + void destroy() { *resultPtr = weakRef->isNullOrUndefined(); + Object::destroy(); } WeakValue *weakRef; diff --git a/tests/auto/qml/qqmlengine/data/qtqmlModule.4.qml b/tests/auto/qml/qqmlengine/data/qtqmlModule.4.qml index 9b9b7922da..94ee46ddf0 100644 --- a/tests/auto/qml/qqmlengine/data/qtqmlModule.4.qml +++ b/tests/auto/qml/qqmlengine/data/qtqmlModule.4.qml @@ -1,4 +1,4 @@ -import QtQml 2.5 +import QtQml 2.50 QtObject { } diff --git a/tests/auto/qml/qqmlengine/tst_qqmlengine.cpp b/tests/auto/qml/qqmlengine/tst_qqmlengine.cpp index 3208745c5c..9c155eda5b 100644 --- a/tests/auto/qml/qqmlengine/tst_qqmlengine.cpp +++ b/tests/auto/qml/qqmlengine/tst_qqmlengine.cpp @@ -275,6 +275,12 @@ void tst_qqmlengine::clearComponentCache() // Modify qml file { + // On macOS with HFS+ the precision of file times is measured in seconds, so to ensure that + // the newly written file has a modification date newer than an existing cache file, we must + // wait. + // Similar effects of lacking precision have been observed on some Linux systems. + QThread::sleep(1); + QFile file("temp.qml"); QVERIFY(file.open(QIODevice::WriteOnly)); file.write("import QtQuick 2.0\nQtObject {\nproperty int test: 11\n}\n"); @@ -317,6 +323,11 @@ public: QCoreApplication::sendPostedEvents(0, QEvent::DeferredDelete); QCoreApplication::processEvents(); + // There might be JS function objects around that hold a last ref to the compilation unit that's + // keeping the type compilation data (CompilationUnit) around. Let's collect them as well so that + // trim works well. + engine->collectGarbage(); + engine->trimComponentCache(); } @@ -615,9 +626,9 @@ void tst_qqmlengine::qtqmlModule_data() << QString(testFileUrl("qtqmlModule.3.qml").toString() + QLatin1String(":1 module \"QtQml\" version 1.0 is not installed\n")) << QStringList(); - QTest::newRow("import QtQml of incorrect version (2.5)") + QTest::newRow("import QtQml of incorrect version (2.50)") << testFileUrl("qtqmlModule.4.qml") - << QString(testFileUrl("qtqmlModule.4.qml").toString() + QLatin1String(":1 module \"QtQml\" version 2.5 is not installed\n")) + << QString(testFileUrl("qtqmlModule.4.qml").toString() + QLatin1String(":1 module \"QtQml\" version 2.50 is not installed\n")) << QStringList(); QTest::newRow("QtQml 2.0 module provides Component, QtObject, Connections, Binding and Timer") diff --git a/tests/auto/qml/qqmlenginecleanup/data/types.qml b/tests/auto/qml/qqmlenginecleanup/data/types.qml index 3d27900744..7282c7dbfb 100644 --- a/tests/auto/qml/qqmlenginecleanup/data/types.qml +++ b/tests/auto/qml/qqmlenginecleanup/data/types.qml @@ -29,7 +29,7 @@ import QtQml 2.0 import QtQuick 2.0 import QtQuick.Window 2.0 -import QtQuick.Particles 2.0 + import Test 2.0 import "." @@ -37,7 +37,6 @@ QtObject { //Doesn't create items, just checks that the types are accessible property TestType tt property TestTypeCpp ttc - property ParticleSystem ps property Window wi property Item it } diff --git a/tests/auto/qml/qqmlextensionplugin/tst_qqmlextensionplugin.cpp b/tests/auto/qml/qqmlextensionplugin/tst_qqmlextensionplugin.cpp index bd44bd7c8b..124a107a37 100644 --- a/tests/auto/qml/qqmlextensionplugin/tst_qqmlextensionplugin.cpp +++ b/tests/auto/qml/qqmlextensionplugin/tst_qqmlextensionplugin.cpp @@ -109,7 +109,7 @@ void tst_qqmlextensionplugin::iidCheck() QFETCH(QString, filePath); QPluginLoader loader(filePath); - QVERIFY(loader.load()); + QVERIFY2(loader.load(), qPrintable(loader.errorString())); QVERIFY(loader.instance() != Q_NULLPTR); if (qobject_cast<QQmlExtensionPlugin *>(loader.instance())) { diff --git a/tests/auto/qml/qqmllanguage/data/alias.12.qml b/tests/auto/qml/qqmllanguage/data/alias.12.qml new file mode 100644 index 0000000000..cc17318092 --- /dev/null +++ b/tests/auto/qml/qqmllanguage/data/alias.12.qml @@ -0,0 +1,15 @@ +import QtQml 2.0 + +QtObject { + id: root + property alias topLevelAlias: subObject.targetProperty + + property QtObject referencingSubObject: QtObject { + property alias success: root.topLevelAlias + } + + property QtObject foo: QtObject { + id: subObject + property bool targetProperty: true + } +} diff --git a/tests/auto/qml/qqmllanguage/data/alias.13.qml b/tests/auto/qml/qqmllanguage/data/alias.13.qml new file mode 100644 index 0000000000..cff8a72d9a --- /dev/null +++ b/tests/auto/qml/qqmllanguage/data/alias.13.qml @@ -0,0 +1,16 @@ +import QtQml 2.0 + +QtObject { + id: root + property bool targetProperty: true + + property QtObject foo: QtObject { + id: otherSubObject + property alias theAlias: root.targetProperty + } + + property QtObject referencingSubObject: QtObject { + property alias success: otherSubObject.theAlias + } + +} diff --git a/tests/auto/qml/qqmllanguage/data/alias.14.errors.txt b/tests/auto/qml/qqmllanguage/data/alias.14.errors.txt new file mode 100644 index 0000000000..90a3ea4317 --- /dev/null +++ b/tests/auto/qml/qqmllanguage/data/alias.14.errors.txt @@ -0,0 +1 @@ +10:34:References to other aliases within the same object are not supported at the moment diff --git a/tests/auto/qml/qqmllanguage/data/alias.14.qml b/tests/auto/qml/qqmllanguage/data/alias.14.qml new file mode 100644 index 0000000000..ff3c36d990 --- /dev/null +++ b/tests/auto/qml/qqmllanguage/data/alias.14.qml @@ -0,0 +1,17 @@ +import QtQml 2.0 + +QtObject { + id: root + property bool targetProperty: true + + property QtObject foo: QtObject { + id: otherSubObject + property alias theAliasOrigin: root.targetProperty + property alias theAlias: otherSubObject.theAliasOrigin + } + + property QtObject referencingSubObject: QtObject { + property alias success: otherSubObject.theAlias + } + +} diff --git a/tests/auto/qml/qqmllanguage/data/arraybuffer_method_arg.qml b/tests/auto/qml/qqmllanguage/data/arraybuffer_method_arg.qml new file mode 100644 index 0000000000..b64a2e23c0 --- /dev/null +++ b/tests/auto/qml/qqmllanguage/data/arraybuffer_method_arg.qml @@ -0,0 +1,11 @@ +import QtQuick 2.7 +import Test 1.0 + +MyArrayBufferTestClass { + property bool ok: false + Component.onCompleted: { + var data = new Uint8Array([1, 2, 3]); + var sum = byteArrayMethod_Sum(data.buffer); + ok = sum == 6; + } +} diff --git a/tests/auto/qml/qqmllanguage/data/arraybuffer_method_overload.qml b/tests/auto/qml/qqmllanguage/data/arraybuffer_method_overload.qml new file mode 100644 index 0000000000..9e1c91810a --- /dev/null +++ b/tests/auto/qml/qqmllanguage/data/arraybuffer_method_overload.qml @@ -0,0 +1,7 @@ +import QtQuick 2.7 +import Test 1.0 + +MyArrayBufferTestClass { + property bool ok: false + Component.onCompleted: ok = byteArrayMethod_Overloaded(new ArrayBuffer()); +} diff --git a/tests/auto/qml/qqmllanguage/data/arraybuffer_method_return.qml b/tests/auto/qml/qqmllanguage/data/arraybuffer_method_return.qml new file mode 100644 index 0000000000..5a4f9fec0b --- /dev/null +++ b/tests/auto/qml/qqmllanguage/data/arraybuffer_method_return.qml @@ -0,0 +1,15 @@ +import QtQuick 2.7 +import Test 1.0 + +MyArrayBufferTestClass { + property bool ok: false + Component.onCompleted: { + var buf = byteArrayMethod_CountUp(1, 3); + var view = new DataView(buf); + ok = buf instanceof ArrayBuffer + && buf.byteLength == 3 + && view.getUint8(0) == 1 + && view.getUint8(1) == 2 + && view.getUint8(2) == 3; + } +} diff --git a/tests/auto/qml/qqmllanguage/data/arraybuffer_property_get.qml b/tests/auto/qml/qqmllanguage/data/arraybuffer_property_get.qml new file mode 100644 index 0000000000..78ebb1abe1 --- /dev/null +++ b/tests/auto/qml/qqmllanguage/data/arraybuffer_property_get.qml @@ -0,0 +1,5 @@ +import Test 1.0 + +MyArrayBufferTestClass { + property bool ok: byteArrayProperty instanceof ArrayBuffer +} diff --git a/tests/auto/qml/qqmllanguage/data/arraybuffer_property_set.qml b/tests/auto/qml/qqmllanguage/data/arraybuffer_property_set.qml new file mode 100644 index 0000000000..e8a51273ca --- /dev/null +++ b/tests/auto/qml/qqmllanguage/data/arraybuffer_property_set.qml @@ -0,0 +1,11 @@ +import QtQuick 2.7 +import Test 1.0 + +MyArrayBufferTestClass { + property bool ok: false + onByteArraySignal: ok = byteArrayProperty instanceof ArrayBuffer + Component.onCompleted: { + byteArrayProperty = new ArrayBuffer(42); + ok = byteArrayProperty instanceof ArrayBuffer && byteArrayProperty.byteLength == 42; + } +} diff --git a/tests/auto/qml/qqmllanguage/data/arraybuffer_signal_arg.qml b/tests/auto/qml/qqmllanguage/data/arraybuffer_signal_arg.qml new file mode 100644 index 0000000000..d9f436e788 --- /dev/null +++ b/tests/auto/qml/qqmllanguage/data/arraybuffer_signal_arg.qml @@ -0,0 +1,14 @@ +import QtQuick 2.7 +import Test 1.0 + +MyArrayBufferTestClass { + property bool ok: false + onByteArraySignal: { + var view = new DataView(arg); + ok = arg instanceof ArrayBuffer + && arg.byteLength == 2 + && view.getUint8(0) == 42 + && view.getUint8(1) == 43; + } + Component.onCompleted: emitByteArraySignal(42, 2) +} diff --git a/tests/auto/qml/qqmllanguage/data/badCompositeRegistration.1.errors.txt b/tests/auto/qml/qqmllanguage/data/badCompositeRegistration.1.errors.txt index 7a75447a62..acf0d1da84 100644 --- a/tests/auto/qml/qqmllanguage/data/badCompositeRegistration.1.errors.txt +++ b/tests/auto/qml/qqmllanguage/data/badCompositeRegistration.1.errors.txt @@ -1,2 +1,2 @@ 3:1:Type RegisteredCompositeType2 unavailable --1:-1:File not found +-1:-1:No such file or directory diff --git a/tests/auto/qml/qqmllanguage/data/cppnamespace.qml b/tests/auto/qml/qqmllanguage/data/cppnamespace.qml index e1daf3b78f..efedf2b14a 100644 --- a/tests/auto/qml/qqmllanguage/data/cppnamespace.qml +++ b/tests/auto/qml/qqmllanguage/data/cppnamespace.qml @@ -1,4 +1,5 @@ import Test 1.0 MyNamespacedType { + myEnum: MyNamespace.Key5 } diff --git a/tests/auto/qml/qqmllanguage/data/invalidAlias.11.errors.txt b/tests/auto/qml/qqmllanguage/data/invalidAlias.11.errors.txt new file mode 100644 index 0000000000..b79b660c46 --- /dev/null +++ b/tests/auto/qml/qqmllanguage/data/invalidAlias.11.errors.txt @@ -0,0 +1 @@ +5:5:Circular alias reference detected diff --git a/tests/auto/qml/qqmllanguage/data/invalidAlias.11.qml b/tests/auto/qml/qqmllanguage/data/invalidAlias.11.qml new file mode 100644 index 0000000000..9b50b48df8 --- /dev/null +++ b/tests/auto/qml/qqmllanguage/data/invalidAlias.11.qml @@ -0,0 +1,10 @@ +import QtQml 2.0 + +QtObject { + id: root + property alias a: subObject.b + property QtObject foo: QtObject { + id: subObject + property alias b: root.a + } +} diff --git a/tests/auto/qml/qqmllanguage/data/rootItemIsComponent.qml b/tests/auto/qml/qqmllanguage/data/rootItemIsComponent.qml new file mode 100644 index 0000000000..dd653352d9 --- /dev/null +++ b/tests/auto/qml/qqmllanguage/data/rootItemIsComponent.qml @@ -0,0 +1,6 @@ +import QtQml 2.0 +Component { + QtObject { + id: blah + } +} diff --git a/tests/auto/qml/qqmllanguage/data/singletonTest10.error.txt b/tests/auto/qml/qqmllanguage/data/singletonTest10.error.txt deleted file mode 100644 index 32d2ed857e..0000000000 --- a/tests/auto/qml/qqmllanguage/data/singletonTest10.error.txt +++ /dev/null @@ -1 +0,0 @@ -4:1:Composite Singleton Type SingletonType is not creatable. diff --git a/tests/auto/qml/qqmllanguage/data/singletonTest12.error.txt b/tests/auto/qml/qqmllanguage/data/singletonTest12.error.txt index 716cf5709a..b3082d80e6 100644 --- a/tests/auto/qml/qqmllanguage/data/singletonTest12.error.txt +++ b/tests/auto/qml/qqmllanguage/data/singletonTest12.error.txt @@ -1,2 +1,2 @@ 5:5:Type RegisteredCompositeType unavailable -2:1:pragma Singleton used with a non composite singleton type CompositeSingletonTest/RegisteredCompositeType +-1:-1:pragma Singleton used with a non composite singleton type CompositeSingletonTest/RegisteredCompositeType diff --git a/tests/auto/qml/qqmllanguage/data/singletonTest4.error.txt b/tests/auto/qml/qqmllanguage/data/singletonTest4.error.txt index 77c26df310..ebeab6987b 100644 --- a/tests/auto/qml/qqmllanguage/data/singletonTest4.error.txt +++ b/tests/auto/qml/qqmllanguage/data/singletonTest4.error.txt @@ -1 +1 @@ -2:1:No matching type found, pragma Singleton files cannot be used by QQmlComponent. +-1:-1:No matching type found, pragma Singleton files cannot be used by QQmlComponent. diff --git a/tests/auto/qml/qqmllanguage/data/uncreatableTypeAsProperty.qml b/tests/auto/qml/qqmllanguage/data/uncreatableTypeAsProperty.qml new file mode 100644 index 0000000000..8369ab1eea --- /dev/null +++ b/tests/auto/qml/qqmllanguage/data/uncreatableTypeAsProperty.qml @@ -0,0 +1,6 @@ +import QtQml 2.0 +import Test 1.0 + +QtObject { + property MyUncreateableBaseClass someProperty; +} diff --git a/tests/auto/qml/qqmllanguage/testtypes.cpp b/tests/auto/qml/qqmllanguage/testtypes.cpp index 9593bfc940..3af7645ff7 100644 --- a/tests/auto/qml/qqmllanguage/testtypes.cpp +++ b/tests/auto/qml/qqmllanguage/testtypes.cpp @@ -27,8 +27,6 @@ ****************************************************************************/ #include "testtypes.h" -#include <private/qqmlcompiler_p.h> - static QObject *myTypeObjectSingleton(QQmlEngine *engine, QJSEngine *scriptEngine) { Q_UNUSED(engine) @@ -47,6 +45,7 @@ void registerTypes() qmlRegisterType<MyDotPropertyObject>("Test",1,0,"MyDotPropertyObject"); qmlRegisterType<MyNamespace::MyNamespacedType>("Test",1,0,"MyNamespacedType"); qmlRegisterType<MyNamespace::MySecondNamespacedType>("Test",1,0,"MySecondNamespacedType"); + qmlRegisterUncreatableMetaObject(MyNamespace::staticMetaObject, "Test", 1, 0, "MyNamespace", "Access to enums & flags only"); qmlRegisterType<MyParserStatus>("Test",1,0,"MyParserStatus"); qmlRegisterType<MyGroupedObject>(); qmlRegisterType<MyRevisionedClass>("Test",1,0,"MyRevisionedClass"); @@ -98,6 +97,8 @@ void registerTypes() qmlRegisterType<MyCompositeBaseType>("Test", 1, 0, "MyCompositeBaseType"); qmlRegisterSingletonType<MyTypeObjectSingleton>("Test", 1, 0, "MyTypeObjectSingleton", myTypeObjectSingleton); + + qmlRegisterType<MyArrayBufferTestClass>("Test", 1, 0, "MyArrayBufferTestClass"); } QVariant myCustomVariantTypeConverter(const QString &data) @@ -108,11 +109,11 @@ QVariant myCustomVariantTypeConverter(const QString &data) } -void CustomBindingParser::applyBindings(QObject *object, QQmlCompiledData *cdata, const QList<const QV4::CompiledData::Binding *> &bindings) +void CustomBindingParser::applyBindings(QObject *object, QV4::CompiledData::CompilationUnit *compilationUnit, const QList<const QV4::CompiledData::Binding *> &bindings) { CustomBinding *customBinding = qobject_cast<CustomBinding*>(object); Q_ASSERT(customBinding); - customBinding->cdata = cdata; + customBinding->compilationUnit = compilationUnit; customBinding->bindings = bindings; } @@ -121,17 +122,18 @@ void CustomBinding::componentComplete() Q_ASSERT(m_target); foreach (const QV4::CompiledData::Binding *binding, bindings) { - QString name = cdata->compilationUnit->data->stringAt(binding->propertyNameIndex); + QString name = compilationUnit->data->stringAt(binding->propertyNameIndex); int bindingId = binding->value.compiledScriptIndex; QQmlContextData *context = QQmlContextData::get(qmlContext(this)); QV4::Scope scope(QQmlEnginePrivate::getV4Engine(qmlEngine(this))); - QV4::ScopedValue function(scope, QV4::FunctionObject::createQmlFunction(context, m_target, cdata->compilationUnit->runtimeFunctions[bindingId])); - QQmlBinding *qmlBinding = new QQmlBinding(function, m_target, context); + QV4::ScopedValue function(scope, QV4::FunctionObject::createQmlFunction(context, m_target, compilationUnit->runtimeFunctions[bindingId])); QQmlProperty property(m_target, name, qmlContext(this)); + QQmlBinding *qmlBinding = QQmlBinding::create(&QQmlPropertyPrivate::get(property)->core, + function, m_target, context); qmlBinding->setTarget(property); QQmlPropertyPrivate::setBinding(property, qmlBinding); } @@ -167,7 +169,7 @@ void EnumSupportingCustomParser::verifyBindings(const QV4::CompiledData::Unit *q } } -void SimpleObjectCustomParser::applyBindings(QObject *object, QQmlCompiledData *, const QList<const QV4::CompiledData::Binding *> &bindings) +void SimpleObjectCustomParser::applyBindings(QObject *object, QV4::CompiledData::CompilationUnit *, const QList<const QV4::CompiledData::Binding *> &bindings) { SimpleObjectWithCustomParser *o = qobject_cast<SimpleObjectWithCustomParser*>(object); Q_ASSERT(o); diff --git a/tests/auto/qml/qqmllanguage/testtypes.h b/tests/auto/qml/qqmllanguage/testtypes.h index 337ba91532..6c62bcf7b9 100644 --- a/tests/auto/qml/qqmllanguage/testtypes.h +++ b/tests/auto/qml/qqmllanguage/testtypes.h @@ -43,7 +43,6 @@ #include <QtQml/qqmlpropertyvaluesource.h> #include <QtQml/qqmlscriptstring.h> #include <QtQml/qqmlproperty.h> -#include <private/qqmlcompiler_p.h> #include <private/qqmlcustomparser_p.h> QVariant myCustomVariantTypeConverter(const QString &data); @@ -731,9 +730,19 @@ private: namespace MyNamespace { + Q_NAMESPACE + enum MyNSEnum { + Key1 = 1, + Key2, + Key5 = 5 + }; + Q_ENUM_NS(MyNSEnum); + class MyNamespacedType : public QObject { Q_OBJECT + Q_PROPERTY(MyNamespace::MyNSEnum myEnum MEMBER m_myEnum) + MyNamespace::MyNSEnum m_myEnum = MyNSEnum::Key1; }; class MySecondNamespacedType : public QObject @@ -757,14 +766,14 @@ class MyCustomParserTypeParser : public QQmlCustomParser { public: virtual void verifyBindings(const QV4::CompiledData::Unit *, const QList<const QV4::CompiledData::Binding *> &) {} - virtual void applyBindings(QObject *, QQmlCompiledData *, const QList<const QV4::CompiledData::Binding *> &) {} + virtual void applyBindings(QObject *, QV4::CompiledData::CompilationUnit *, const QList<const QV4::CompiledData::Binding *> &) {} }; class EnumSupportingCustomParser : public QQmlCustomParser { public: virtual void verifyBindings(const QV4::CompiledData::Unit *, const QList<const QV4::CompiledData::Binding *> &); - virtual void applyBindings(QObject *, QQmlCompiledData *, const QList<const QV4::CompiledData::Binding *> &) {} + virtual void applyBindings(QObject *, QV4::CompiledData::CompilationUnit *, const QList<const QV4::CompiledData::Binding *> &) {} }; class MyParserStatus : public QObject, public QQmlParserStatus @@ -1114,6 +1123,58 @@ public: static QObject *qmlAttachedProperties(QObject *parent) { return new QObject(parent); } }; +class MyArrayBufferTestClass : public QObject +{ + Q_OBJECT + Q_PROPERTY(QByteArray byteArrayProperty READ byteArrayProperty WRITE setByteArrayProperty NOTIFY byteArrayPropertyChanged) + +signals: + void byteArrayPropertyChanged(); + void byteArraySignal(QByteArray arg); + +public: + QByteArray byteArrayPropertyValue; + QByteArray byteArrayProperty() const { + return byteArrayPropertyValue; + } + void setByteArrayProperty(const QByteArray &v) { + byteArrayPropertyValue = v; + emit byteArrayPropertyChanged(); + } + Q_INVOKABLE void emitByteArraySignal(char begin, char num) { + byteArraySignal(byteArrayMethod_CountUp(begin, num)); + } + Q_INVOKABLE int byteArrayMethod_Sum(QByteArray arg) { + int sum = 0; + for (int i = 0; i < arg.size(); ++i) { + sum += arg[i]; + } + return sum; + } + Q_INVOKABLE QByteArray byteArrayMethod_CountUp(char begin, int num) { + QByteArray ret; + for (int i = 0; i < num; ++i) { + ret.push_back(begin++); + } + return ret; + } + Q_INVOKABLE bool byteArrayMethod_Overloaded(QByteArray) { + return true; + } + Q_INVOKABLE bool byteArrayMethod_Overloaded(int) { + return false; + } + Q_INVOKABLE bool byteArrayMethod_Overloaded(QString) { + return false; + } + Q_INVOKABLE bool byteArrayMethod_Overloaded(QJSValue) { + return false; + } + Q_INVOKABLE bool byteArrayMethod_Overloaded(QVariant) { + return false; + } +}; + Q_DECLARE_METATYPE(MyEnum2Class::EnumB) Q_DECLARE_METATYPE(MyEnum1Class::EnumA) Q_DECLARE_METATYPE(Qt::TextFormat) @@ -1142,7 +1203,7 @@ public: void setTarget(QObject *newTarget) { m_target = newTarget; } QPointer<QObject> m_target; - QQmlRefPointer<QQmlCompiledData> cdata; + QQmlRefPointer<QV4::CompiledData::CompilationUnit> compilationUnit; QList<const QV4::CompiledData::Binding*> bindings; QByteArray m_bindingData; }; @@ -1150,7 +1211,7 @@ public: class CustomBindingParser : public QQmlCustomParser { virtual void verifyBindings(const QV4::CompiledData::Unit *, const QList<const QV4::CompiledData::Binding *> &) {} - virtual void applyBindings(QObject *, QQmlCompiledData *, const QList<const QV4::CompiledData::Binding *> &); + virtual void applyBindings(QObject *, QV4::CompiledData::CompilationUnit *, const QList<const QV4::CompiledData::Binding *> &); }; class SimpleObjectWithCustomParser : public QObject @@ -1196,7 +1257,7 @@ private: class SimpleObjectCustomParser : public QQmlCustomParser { virtual void verifyBindings(const QV4::CompiledData::Unit *, const QList<const QV4::CompiledData::Binding *> &) {} - virtual void applyBindings(QObject *, QQmlCompiledData *, const QList<const QV4::CompiledData::Binding *> &); + virtual void applyBindings(QObject *, QV4::CompiledData::CompilationUnit *, const QList<const QV4::CompiledData::Binding *> &); }; class RootObjectInCreationTester : public QObject diff --git a/tests/auto/qml/qqmllanguage/tst_qqmllanguage.cpp b/tests/auto/qml/qqmllanguage/tst_qqmllanguage.cpp index 4e4b939e8b..ad06946b0b 100644 --- a/tests/auto/qml/qqmllanguage/tst_qqmllanguage.cpp +++ b/tests/auto/qml/qqmllanguage/tst_qqmllanguage.cpp @@ -108,6 +108,7 @@ private slots: void bindTypeToJSValue(); void customParserTypes(); void rootAsQmlComponent(); + void rootItemIsComponent(); void inlineQmlComponents(); void idProperty(); void autoNotifyConnection(); @@ -188,6 +189,8 @@ private slots: void subclassedUncreateableRevision_data(); void subclassedUncreateableRevision(); + void uncreatableTypesAsProperties(); + void propertyInit(); void remoteLoadCrash(); void signalWithDefaultArg(); @@ -246,10 +249,11 @@ private slots: void earlyIdObjectAccess(); - void dataAlignment(); - void deleteSingletons(); + void arrayBuffer_data(); + void arrayBuffer(); + private: QQmlEngine engine; QStringList defaultImportPathList; @@ -490,6 +494,7 @@ void tst_qqmllanguage::errors_data() QTest::newRow("invalidAlias.8") << "invalidAlias.8.qml" << "invalidAlias.8.errors.txt" << false; QTest::newRow("invalidAlias.9") << "invalidAlias.9.qml" << "invalidAlias.9.errors.txt" << false; QTest::newRow("invalidAlias.10") << "invalidAlias.10.qml" << "invalidAlias.10.errors.txt" << false; + QTest::newRow("invalidAlias.11") << "invalidAlias.11.qml" << "invalidAlias.11.errors.txt" << false; QTest::newRow("invalidAttachedProperty.1") << "invalidAttachedProperty.1.qml" << "invalidAttachedProperty.1.errors.txt" << false; QTest::newRow("invalidAttachedProperty.2") << "invalidAttachedProperty.2.qml" << "invalidAttachedProperty.2.errors.txt" << false; @@ -1193,6 +1198,19 @@ void tst_qqmllanguage::rootAsQmlComponent() QCOMPARE(object->getChildren()->count(), 2); } +void tst_qqmllanguage::rootItemIsComponent() +{ + QQmlComponent component(&engine, testFileUrl("rootItemIsComponent.qml")); + VERIFY_ERRORS(0); + QScopedPointer<QObject> root(component.create()); + QVERIFY(qobject_cast<QQmlComponent*>(root.data())); + QScopedPointer<QObject> other(qobject_cast<QQmlComponent*>(root.data())->create()); + QVERIFY(!other.isNull()); + QQmlContext *context = qmlContext(other.data()); + QVERIFY(context); + QCOMPARE(context->nameForObject(other.data()), QStringLiteral("blah")); +} + // Tests that components can be specified inline void tst_qqmllanguage::inlineQmlComponents() { @@ -1787,6 +1805,48 @@ void tst_qqmllanguage::aliasProperties() delete object; } + + // Nested aliases with a qml file + { + QQmlComponent component(&engine, testFileUrl("alias.12.qml")); + VERIFY_ERRORS(0); + QScopedPointer<QObject> object(component.create()); + QVERIFY(!object.isNull()); + + QPointer<QObject> subObject = qvariant_cast<QObject*>(object->property("referencingSubObject")); + QVERIFY(!subObject.isNull()); + + QVERIFY(subObject->property("success").toBool()); + } + + // Nested aliases with a qml file with reverse ordering + { + // This is known to fail at the moment. + QQmlComponent component(&engine, testFileUrl("alias.13.qml")); + VERIFY_ERRORS(0); + QScopedPointer<QObject> object(component.create()); + QVERIFY(!object.isNull()); + + QPointer<QObject> subObject = qvariant_cast<QObject*>(object->property("referencingSubObject")); + QVERIFY(!subObject.isNull()); + + QVERIFY(subObject->property("success").toBool()); + } + + // "Nested" aliases within an object that require iterative resolution + { + // This is known to fail at the moment. + QQmlComponent component(&engine, testFileUrl("alias.14.qml")); + VERIFY_ERRORS(0); + + QScopedPointer<QObject> object(component.create()); + QVERIFY(!object.isNull()); + + QPointer<QObject> subObject = qvariant_cast<QObject*>(object->property("referencingSubObject")); + QVERIFY(!subObject.isNull()); + + QVERIFY(subObject->property("success").toBool()); + } } // QTBUG-13374 Test that alias properties and signals can coexist @@ -2058,8 +2118,13 @@ void tst_qqmllanguage::scriptStringWithoutSourceCode() QQmlTypeData *td = eng->typeLoader.getType(url); Q_ASSERT(td); - QV4::CompiledData::Unit *qmlUnit = td->compiledData()->compilationUnit->data; - Q_ASSERT(qmlUnit); + const QV4::CompiledData::Unit *readOnlyQmlUnit = td->compilationUnit()->data; + Q_ASSERT(readOnlyQmlUnit); + QV4::CompiledData::Unit *qmlUnit = reinterpret_cast<QV4::CompiledData::Unit *>(malloc(readOnlyQmlUnit->unitSize)); + memcpy(qmlUnit, readOnlyQmlUnit, readOnlyQmlUnit->unitSize); + qmlUnit->flags &= ~QV4::CompiledData::Unit::StaticData; + td->compilationUnit()->data = qmlUnit; + const QV4::CompiledData::Object *rootObject = qmlUnit->objectAt(qmlUnit->indexOfRootObject); QCOMPARE(qmlUnit->stringAt(rootObject->inheritedTypeNameIndex), QString("MyTypeObject")); quint32 i; @@ -2536,7 +2601,7 @@ void tst_qqmllanguage::basicRemote_data() QTest::newRow("no need for qmldir") << QUrl(serverdir+"Test.qml") << "" << ""; QTest::newRow("absent qmldir") << QUrl(serverdir+"/noqmldir/Test.qml") << "" << ""; - QTest::newRow("need qmldir") << QUrl(serverdir+"TestLocal.qml") << "" << ""; + QTest::newRow("need qmldir") << QUrl(serverdir+"TestNamed.qml") << "" << ""; } void tst_qqmllanguage::basicRemote() @@ -2576,6 +2641,8 @@ void tst_qqmllanguage::importsRemote_data() << ""; QTest::newRow("remote import with local") << "import \""+serverdir+"\"\nTestLocal {}" << "QQuickImage" << ""; + QTest::newRow("remote import with qualifier") << "import \""+serverdir+"\" as NS\nNS.NamedLocal {}" << "QQuickImage" + << ""; QTest::newRow("wrong remote import with undeclared local") << "import \""+serverdir+"\"\nWrongTestLocal {}" << "" << "WrongTestLocal is not a type"; QTest::newRow("wrong remote import of internal local") << "import \""+serverdir+"\"\nLocalInternal {}" << "" @@ -2882,7 +2949,7 @@ void tst_qqmllanguage::importIncorrectCase() QCOMPARE(errors.count(), 1); const QString expectedError = isCaseSensitiveFileSystem(dataDirectory()) ? - QStringLiteral("File not found") : + QStringLiteral("No such file or directory") : QStringLiteral("File name case mismatch"); QCOMPARE(errors.at(0).description(), expectedError); @@ -3156,6 +3223,14 @@ void tst_qqmllanguage::subclassedUncreateableRevision() delete obj; } +void tst_qqmllanguage::uncreatableTypesAsProperties() +{ + QQmlEngine engine; + QQmlComponent component(&engine, testFileUrl("uncreatableTypeAsProperty.qml")); + QScopedPointer<QObject> object(component.create()); + QVERIFY(!object.isNull()); +} + void tst_qqmllanguage::initTestCase() { QQmlDataTest::initTestCase(); @@ -3861,12 +3936,11 @@ void tst_qqmllanguage::compositeSingletonInstantiateError() VERIFY_ERRORS("singletonTest9.error.txt"); } -// Having a composite singleton type as dynamic property type fails -// (like C++ singleton) +// Having a composite singleton type as dynamic property type is allowed void tst_qqmllanguage::compositeSingletonDynamicPropertyError() { QQmlComponent component(&engine, testFile("singletonTest10.qml")); - VERIFY_ERRORS("singletonTest10.error.txt"); + VERIFY_ERRORS(0); } // Having a composite singleton type as dynamic signal parameter succeeds @@ -4054,7 +4128,7 @@ void tst_qqmllanguage::preservePropertyCacheOnGroupObjects() QVERIFY(subCache); QQmlPropertyData *pd = subCache->property(QStringLiteral("newProperty"), /*object*/0, /*context*/0); QVERIFY(pd); - QCOMPARE(pd->propType, qMetaTypeId<int>()); + QCOMPARE(pd->propType(), qMetaTypeId<int>()); } void tst_qqmllanguage::propertyCacheInSync() @@ -4120,14 +4194,6 @@ void tst_qqmllanguage::earlyIdObjectAccess() QVERIFY(o->property("success").toBool()); } -void tst_qqmllanguage::dataAlignment() -{ - QVERIFY(sizeof(QQmlVMEMetaData) % sizeof(int) == 0); - QVERIFY(sizeof(QQmlVMEMetaData::AliasData) % sizeof(int) == 0); - QVERIFY(sizeof(QQmlVMEMetaData::PropertyData) % sizeof(int) == 0); - QVERIFY(sizeof(QQmlVMEMetaData::MethodData) % sizeof(int) == 0); -} - void tst_qqmllanguage::deleteSingletons() { QPointer<QObject> singleton; @@ -4146,6 +4212,27 @@ void tst_qqmllanguage::deleteSingletons() QVERIFY(singleton.data() == 0); } +void tst_qqmllanguage::arrayBuffer_data() +{ + QTest::addColumn<QString>("file"); + QTest::newRow("arraybuffer_property_get") << "arraybuffer_property_get.qml"; + QTest::newRow("arraybuffer_property_set") << "arraybuffer_property_set.qml"; + QTest::newRow("arraybuffer_signal_arg") << "arraybuffer_signal_arg.qml"; + QTest::newRow("arraybuffer_method_arg") << "arraybuffer_method_arg.qml"; + QTest::newRow("arraybuffer_method_return") << "arraybuffer_method_return.qml"; + QTest::newRow("arraybuffer_method_overload") << "arraybuffer_method_overload.qml"; +} + +void tst_qqmllanguage::arrayBuffer() +{ + QFETCH(QString, file); + QQmlComponent component(&engine, testFile(file)); + VERIFY_ERRORS(0); + QObject *object = component.create(); + QVERIFY(object != 0); + QCOMPARE(object->property("ok").toBool(), true); +} + QTEST_MAIN(tst_qqmllanguage) #include "tst_qqmllanguage.moc" diff --git a/tests/auto/qml/qqmlmoduleplugin/plugin.2.1/childplugin/childplugin.cpp b/tests/auto/qml/qqmlmoduleplugin/plugin.2.1/childplugin/childplugin.cpp index 53247e7912..515d56a3c4 100644 --- a/tests/auto/qml/qqmlmoduleplugin/plugin.2.1/childplugin/childplugin.cpp +++ b/tests/auto/qml/qqmlmoduleplugin/plugin.2.1/childplugin/childplugin.cpp @@ -53,7 +53,7 @@ private: class MyChildPlugin : public QQmlExtensionPlugin { Q_OBJECT - Q_PLUGIN_METADATA(IID "org.qt-project.Qt.QQmlExtensionInterface") + Q_PLUGIN_METADATA(IID QQmlExtensionInterface_iid) public: MyChildPlugin() diff --git a/tests/auto/qml/qqmlmoduleplugin/plugin.2/childplugin/childplugin.cpp b/tests/auto/qml/qqmlmoduleplugin/plugin.2/childplugin/childplugin.cpp index a59347d3a9..56545cfa3c 100644 --- a/tests/auto/qml/qqmlmoduleplugin/plugin.2/childplugin/childplugin.cpp +++ b/tests/auto/qml/qqmlmoduleplugin/plugin.2/childplugin/childplugin.cpp @@ -53,7 +53,7 @@ private: class MyChildPlugin : public QQmlExtensionPlugin { Q_OBJECT - Q_PLUGIN_METADATA(IID "org.qt-project.Qt.QQmlExtensionInterface") + Q_PLUGIN_METADATA(IID QQmlExtensionInterface_iid) public: MyChildPlugin() diff --git a/tests/auto/qml/qqmlmoduleplugin/plugin/childplugin/childplugin.cpp b/tests/auto/qml/qqmlmoduleplugin/plugin/childplugin/childplugin.cpp index 5f4f96f7e4..28490d3d98 100644 --- a/tests/auto/qml/qqmlmoduleplugin/plugin/childplugin/childplugin.cpp +++ b/tests/auto/qml/qqmlmoduleplugin/plugin/childplugin/childplugin.cpp @@ -52,7 +52,7 @@ private: class MyChildPlugin : public QQmlExtensionPlugin { Q_OBJECT - Q_PLUGIN_METADATA(IID "org.qt-project.Qt.QQmlExtensionInterface") + Q_PLUGIN_METADATA(IID QQmlExtensionInterface_iid) public: MyChildPlugin() diff --git a/tests/auto/qml/qqmlproperty/tst_qqmlproperty.cpp b/tests/auto/qml/qqmlproperty/tst_qqmlproperty.cpp index 1d01f69d9b..fe73610bcc 100644 --- a/tests/auto/qml/qqmlproperty/tst_qqmlproperty.cpp +++ b/tests/auto/qml/qqmlproperty/tst_qqmlproperty.cpp @@ -157,7 +157,7 @@ void tst_qqmlproperty::qmlmetaproperty() QObject *obj = new QObject; - QQmlAbstractBinding::Ptr binding(new QQmlBinding(QLatin1String("null"), 0, engine.rootContext())); + QQmlAbstractBinding::Ptr binding(QQmlBinding::create(nullptr, QLatin1String("null"), 0, engine.rootContext())); QVERIFY(binding); QQmlBoundSignalExpression *sigExpr = new QQmlBoundSignalExpression(obj, QObjectPrivate::get(obj)->signalIndex("destroyed()"), QQmlContextData::get(engine.rootContext()), 0, QLatin1String("null"), QString(), -1, -1); QQmlJavaScriptExpression::DeleteWatcher sigExprWatcher(sigExpr); @@ -194,7 +194,8 @@ void tst_qqmlproperty::qmlmetaproperty() QQmlPropertyPrivate::takeSignalExpression(prop, sigExpr); QVERIFY(sigExprWatcher.wasDeleted()); QCOMPARE(prop.index(), -1); - QCOMPARE(QQmlPropertyPrivate::valueTypeCoreIndex(prop), -1); + QCOMPARE(QQmlPropertyPrivate::propertyIndex(prop).valueTypeIndex(), -1); + QVERIFY(!QQmlPropertyPrivate::propertyIndex(prop).hasValueTypeIndex()); delete obj; } @@ -398,7 +399,7 @@ void tst_qqmlproperty::qmlmetaproperty_object() { QQmlProperty prop(&object); - QQmlAbstractBinding::Ptr binding(new QQmlBinding(QLatin1String("null"), 0, engine.rootContext())); + QQmlAbstractBinding::Ptr binding(QQmlBinding::create(&QQmlPropertyPrivate::get(prop)->core, QLatin1String("null"), 0, engine.rootContext())); QVERIFY(binding); QQmlBoundSignalExpression *sigExpr = new QQmlBoundSignalExpression(&object, QObjectPrivate::get(&object)->signalIndex("destroyed()"), QQmlContextData::get(engine.rootContext()), 0, QLatin1String("null"), QString(), -1, -1); QQmlJavaScriptExpression::DeleteWatcher sigExprWatcher(sigExpr); @@ -437,7 +438,8 @@ void tst_qqmlproperty::qmlmetaproperty_object() QQmlPropertyPrivate::takeSignalExpression(prop, sigExpr); QVERIFY(sigExprWatcher.wasDeleted()); QCOMPARE(prop.index(), -1); - QCOMPARE(QQmlPropertyPrivate::valueTypeCoreIndex(prop), -1); + QCOMPARE(QQmlPropertyPrivate::propertyIndex(prop).valueTypeIndex(), -1); + QVERIFY(!QQmlPropertyPrivate::propertyIndex(prop).hasValueTypeIndex()); delete obj; } @@ -445,7 +447,7 @@ void tst_qqmlproperty::qmlmetaproperty_object() { QQmlProperty prop(&dobject); - QQmlAbstractBinding::Ptr binding(new QQmlBinding(QLatin1String("null"), 0, engine.rootContext())); + QQmlAbstractBinding::Ptr binding(QQmlBinding::create(&QQmlPropertyPrivate::get(prop)->core, QLatin1String("null"), 0, engine.rootContext())); static_cast<QQmlBinding *>(binding.data())->setTarget(prop); QVERIFY(binding); QQmlBoundSignalExpression *sigExpr = new QQmlBoundSignalExpression(&dobject, QObjectPrivate::get(&dobject)->signalIndex("clicked()"), QQmlContextData::get(engine.rootContext()), 0, QLatin1String("null"), QString(), -1, -1); @@ -487,7 +489,8 @@ void tst_qqmlproperty::qmlmetaproperty_object() QQmlPropertyPrivate::takeSignalExpression(prop, sigExpr); QVERIFY(sigExprWatcher.wasDeleted()); QCOMPARE(prop.index(), dobject.metaObject()->indexOfProperty("defaultProperty")); - QCOMPARE(QQmlPropertyPrivate::valueTypeCoreIndex(prop), -1); + QCOMPARE(QQmlPropertyPrivate::propertyIndex(prop).valueTypeIndex(), -1); + QVERIFY(!QQmlPropertyPrivate::propertyIndex(prop).hasValueTypeIndex()); delete obj; } @@ -501,7 +504,7 @@ void tst_qqmlproperty::qmlmetaproperty_object_string() { QQmlProperty prop(&object, QString("defaultProperty")); - QQmlAbstractBinding::Ptr binding(new QQmlBinding(QLatin1String("null"), 0, engine.rootContext())); + QQmlAbstractBinding::Ptr binding(QQmlBinding::create(&QQmlPropertyPrivate::get(prop)->core, QLatin1String("null"), 0, engine.rootContext())); QVERIFY(binding); QQmlBoundSignalExpression *sigExpr = new QQmlBoundSignalExpression(&object, QObjectPrivate::get(&object)->signalIndex("destroyed()"), QQmlContextData::get(engine.rootContext()), 0, QLatin1String("null"), QString(), -1, -1); QQmlJavaScriptExpression::DeleteWatcher sigExprWatcher(sigExpr); @@ -540,7 +543,8 @@ void tst_qqmlproperty::qmlmetaproperty_object_string() QQmlPropertyPrivate::takeSignalExpression(prop, sigExpr); QVERIFY(sigExprWatcher.wasDeleted()); QCOMPARE(prop.index(), -1); - QCOMPARE(QQmlPropertyPrivate::valueTypeCoreIndex(prop), -1); + QCOMPARE(QQmlPropertyPrivate::propertyIndex(prop).valueTypeIndex(), -1); + QVERIFY(!QQmlPropertyPrivate::propertyIndex(prop).hasValueTypeIndex()); delete obj; } @@ -548,7 +552,7 @@ void tst_qqmlproperty::qmlmetaproperty_object_string() { QQmlProperty prop(&dobject, QString("defaultProperty")); - QQmlAbstractBinding::Ptr binding(new QQmlBinding(QLatin1String("null"), 0, engine.rootContext())); + QQmlAbstractBinding::Ptr binding(QQmlBinding::create(&QQmlPropertyPrivate::get(prop)->core, QLatin1String("null"), 0, engine.rootContext())); static_cast<QQmlBinding *>(binding.data())->setTarget(prop); QVERIFY(binding); QQmlBoundSignalExpression *sigExpr = new QQmlBoundSignalExpression(&dobject, QObjectPrivate::get(&dobject)->signalIndex("clicked()"), QQmlContextData::get(engine.rootContext()), 0, QLatin1String("null"), QString(), -1, -1); @@ -590,7 +594,8 @@ void tst_qqmlproperty::qmlmetaproperty_object_string() QQmlPropertyPrivate::takeSignalExpression(prop, sigExpr); QVERIFY(sigExprWatcher.wasDeleted()); QCOMPARE(prop.index(), dobject.metaObject()->indexOfProperty("defaultProperty")); - QCOMPARE(QQmlPropertyPrivate::valueTypeCoreIndex(prop), -1); + QCOMPARE(QQmlPropertyPrivate::propertyIndex(prop).valueTypeIndex(), -1); + QVERIFY(!QQmlPropertyPrivate::propertyIndex(prop).hasValueTypeIndex()); delete obj; } @@ -598,7 +603,7 @@ void tst_qqmlproperty::qmlmetaproperty_object_string() { QQmlProperty prop(&dobject, QString("onClicked")); - QQmlAbstractBinding::Ptr binding(new QQmlBinding(QLatin1String("null"), 0, engine.rootContext())); + QQmlAbstractBinding::Ptr binding(QQmlBinding::create(&QQmlPropertyPrivate::get(prop)->core, QLatin1String("null"), 0, engine.rootContext())); static_cast<QQmlBinding *>(binding.data())->setTarget(prop); QVERIFY(binding); QQmlBoundSignalExpression *sigExpr = new QQmlBoundSignalExpression(&dobject, QQmlPropertyPrivate::get(prop)->signalIndex(), QQmlContextData::get(engine.rootContext()), 0, QLatin1String("null"), QString(), -1, -1); @@ -639,7 +644,8 @@ void tst_qqmlproperty::qmlmetaproperty_object_string() QVERIFY(!sigExprWatcher.wasDeleted()); QCOMPARE(QQmlPropertyPrivate::signalExpression(prop), sigExpr); QCOMPARE(prop.index(), dobject.metaObject()->indexOfMethod("clicked()")); - QCOMPARE(QQmlPropertyPrivate::valueTypeCoreIndex(prop), -1); + QCOMPARE(QQmlPropertyPrivate::propertyIndex(prop).valueTypeIndex(), -1); + QVERIFY(!QQmlPropertyPrivate::propertyIndex(prop).hasValueTypeIndex()); delete obj; } @@ -647,7 +653,7 @@ void tst_qqmlproperty::qmlmetaproperty_object_string() { QQmlProperty prop(&dobject, QString("onPropertyWithNotifyChanged")); - QQmlAbstractBinding::Ptr binding(new QQmlBinding(QLatin1String("null"), 0, engine.rootContext())); + QQmlAbstractBinding::Ptr binding(QQmlBinding::create(&QQmlPropertyPrivate::get(prop)->core, QLatin1String("null"), 0, engine.rootContext())); static_cast<QQmlBinding *>(binding.data())->setTarget(prop); QVERIFY(binding); QQmlBoundSignalExpression *sigExpr = new QQmlBoundSignalExpression(&dobject, QQmlPropertyPrivate::get(prop)->signalIndex(), QQmlContextData::get(engine.rootContext()), 0, QLatin1String("null"), QString(), -1, -1); @@ -688,7 +694,8 @@ void tst_qqmlproperty::qmlmetaproperty_object_string() QVERIFY(!sigExprWatcher.wasDeleted()); QCOMPARE(QQmlPropertyPrivate::signalExpression(prop), sigExpr); QCOMPARE(prop.index(), dobject.metaObject()->indexOfMethod("oddlyNamedNotifySignal()")); - QCOMPARE(QQmlPropertyPrivate::valueTypeCoreIndex(prop), -1); + QCOMPARE(QQmlPropertyPrivate::propertyIndex(prop).valueTypeIndex(), -1); + QVERIFY(!QQmlPropertyPrivate::propertyIndex(prop).hasValueTypeIndex()); delete obj; } @@ -702,7 +709,7 @@ void tst_qqmlproperty::qmlmetaproperty_object_context() { QQmlProperty prop(&object, engine.rootContext()); - QQmlAbstractBinding::Ptr binding(new QQmlBinding(QLatin1String("null"), 0, engine.rootContext())); + QQmlAbstractBinding::Ptr binding(QQmlBinding::create(&QQmlPropertyPrivate::get(prop)->core, QLatin1String("null"), 0, engine.rootContext())); QVERIFY(binding); QQmlBoundSignalExpression *sigExpr = new QQmlBoundSignalExpression(&object, QObjectPrivate::get(&object)->signalIndex("destroyed()"), QQmlContextData::get(engine.rootContext()), 0, QLatin1String("null"), QString(), -1, -1); QQmlJavaScriptExpression::DeleteWatcher sigExprWatcher(sigExpr); @@ -741,7 +748,8 @@ void tst_qqmlproperty::qmlmetaproperty_object_context() QQmlPropertyPrivate::takeSignalExpression(prop, sigExpr); QVERIFY(sigExprWatcher.wasDeleted()); QCOMPARE(prop.index(), -1); - QCOMPARE(QQmlPropertyPrivate::valueTypeCoreIndex(prop), -1); + QCOMPARE(QQmlPropertyPrivate::propertyIndex(prop).valueTypeIndex(), -1); + QVERIFY(!QQmlPropertyPrivate::propertyIndex(prop).hasValueTypeIndex()); delete obj; } @@ -749,7 +757,7 @@ void tst_qqmlproperty::qmlmetaproperty_object_context() { QQmlProperty prop(&dobject, engine.rootContext()); - QQmlAbstractBinding::Ptr binding(new QQmlBinding(QLatin1String("null"), 0, engine.rootContext())); + QQmlAbstractBinding::Ptr binding(QQmlBinding::create(&QQmlPropertyPrivate::get(prop)->core, QLatin1String("null"), 0, engine.rootContext())); static_cast<QQmlBinding *>(binding.data())->setTarget(prop); QVERIFY(binding); QQmlBoundSignalExpression *sigExpr = new QQmlBoundSignalExpression(&dobject, QObjectPrivate::get(&dobject)->signalIndex("clicked()"), QQmlContextData::get(engine.rootContext()), 0, QLatin1String("null"), QString(), -1, -1); @@ -791,7 +799,8 @@ void tst_qqmlproperty::qmlmetaproperty_object_context() QQmlPropertyPrivate::takeSignalExpression(prop, sigExpr); QVERIFY(sigExprWatcher.wasDeleted()); QCOMPARE(prop.index(), dobject.metaObject()->indexOfProperty("defaultProperty")); - QCOMPARE(QQmlPropertyPrivate::valueTypeCoreIndex(prop), -1); + QCOMPARE(QQmlPropertyPrivate::propertyIndex(prop).valueTypeIndex(), -1); + QVERIFY(!QQmlPropertyPrivate::propertyIndex(prop).hasValueTypeIndex()); delete obj; } @@ -805,7 +814,7 @@ void tst_qqmlproperty::qmlmetaproperty_object_string_context() { QQmlProperty prop(&object, QString("defaultProperty"), engine.rootContext()); - QQmlAbstractBinding::Ptr binding(new QQmlBinding(QLatin1String("null"), 0, engine.rootContext())); + QQmlAbstractBinding::Ptr binding(QQmlBinding::create(&QQmlPropertyPrivate::get(prop)->core, QLatin1String("null"), 0, engine.rootContext())); QVERIFY(binding); QQmlBoundSignalExpression *sigExpr = new QQmlBoundSignalExpression(&object, QObjectPrivate::get(&object)->signalIndex("destroyed()"), QQmlContextData::get(engine.rootContext()), 0, QLatin1String("null"), QString(), -1, -1); QQmlJavaScriptExpression::DeleteWatcher sigExprWatcher(sigExpr); @@ -844,7 +853,8 @@ void tst_qqmlproperty::qmlmetaproperty_object_string_context() QQmlPropertyPrivate::takeSignalExpression(prop, sigExpr); QVERIFY(sigExprWatcher.wasDeleted()); QCOMPARE(prop.index(), -1); - QCOMPARE(QQmlPropertyPrivate::valueTypeCoreIndex(prop), -1); + QCOMPARE(QQmlPropertyPrivate::propertyIndex(prop).valueTypeIndex(), -1); + QVERIFY(!QQmlPropertyPrivate::propertyIndex(prop).hasValueTypeIndex()); delete obj; } @@ -852,7 +862,7 @@ void tst_qqmlproperty::qmlmetaproperty_object_string_context() { QQmlProperty prop(&dobject, QString("defaultProperty"), engine.rootContext()); - QQmlAbstractBinding::Ptr binding(new QQmlBinding(QLatin1String("null"), 0, engine.rootContext())); + QQmlAbstractBinding::Ptr binding(QQmlBinding::create(&QQmlPropertyPrivate::get(prop)->core, QLatin1String("null"), 0, engine.rootContext())); static_cast<QQmlBinding *>(binding.data())->setTarget(prop); QVERIFY(binding); QQmlBoundSignalExpression *sigExpr = new QQmlBoundSignalExpression(&dobject, QObjectPrivate::get(&dobject)->signalIndex("clicked()"), QQmlContextData::get(engine.rootContext()), 0, QLatin1String("null"), QString(), -1, -1); @@ -894,7 +904,8 @@ void tst_qqmlproperty::qmlmetaproperty_object_string_context() QQmlPropertyPrivate::takeSignalExpression(prop, sigExpr); QVERIFY(sigExprWatcher.wasDeleted()); QCOMPARE(prop.index(), dobject.metaObject()->indexOfProperty("defaultProperty")); - QCOMPARE(QQmlPropertyPrivate::valueTypeCoreIndex(prop), -1); + QCOMPARE(QQmlPropertyPrivate::propertyIndex(prop).valueTypeIndex(), -1); + QVERIFY(!QQmlPropertyPrivate::propertyIndex(prop).hasValueTypeIndex()); delete obj; } @@ -902,7 +913,7 @@ void tst_qqmlproperty::qmlmetaproperty_object_string_context() { QQmlProperty prop(&dobject, QString("onClicked"), engine.rootContext()); - QQmlAbstractBinding::Ptr binding(new QQmlBinding(QLatin1String("null"), 0, engine.rootContext())); + QQmlAbstractBinding::Ptr binding(QQmlBinding::create(&QQmlPropertyPrivate::get(prop)->core, QLatin1String("null"), 0, engine.rootContext())); static_cast<QQmlBinding *>(binding.data())->setTarget(prop); QVERIFY(binding); QQmlBoundSignalExpression *sigExpr = new QQmlBoundSignalExpression(&dobject, QQmlPropertyPrivate::get(prop)->signalIndex(), QQmlContextData::get(engine.rootContext()), 0, QLatin1String("null"), QString(), -1, -1); @@ -943,7 +954,8 @@ void tst_qqmlproperty::qmlmetaproperty_object_string_context() QVERIFY(!sigExprWatcher.wasDeleted()); QCOMPARE(QQmlPropertyPrivate::signalExpression(prop), sigExpr); QCOMPARE(prop.index(), dobject.metaObject()->indexOfMethod("clicked()")); - QCOMPARE(QQmlPropertyPrivate::valueTypeCoreIndex(prop), -1); + QCOMPARE(QQmlPropertyPrivate::propertyIndex(prop).valueTypeIndex(), -1); + QVERIFY(!QQmlPropertyPrivate::propertyIndex(prop).hasValueTypeIndex()); delete obj; } @@ -951,7 +963,7 @@ void tst_qqmlproperty::qmlmetaproperty_object_string_context() { QQmlProperty prop(&dobject, QString("onPropertyWithNotifyChanged"), engine.rootContext()); - QQmlAbstractBinding::Ptr binding(new QQmlBinding(QLatin1String("null"), 0, engine.rootContext())); + QQmlAbstractBinding::Ptr binding(QQmlBinding::create(&QQmlPropertyPrivate::get(prop)->core, QLatin1String("null"), 0, engine.rootContext())); static_cast<QQmlBinding *>(binding.data())->setTarget(prop); QVERIFY(binding); QQmlBoundSignalExpression *sigExpr = new QQmlBoundSignalExpression(&dobject, QQmlPropertyPrivate::get(prop)->signalIndex(), QQmlContextData::get(engine.rootContext()), 0, QLatin1String("null"), QString(), -1, -1); @@ -992,7 +1004,8 @@ void tst_qqmlproperty::qmlmetaproperty_object_string_context() QVERIFY(!sigExprWatcher.wasDeleted()); QCOMPARE(QQmlPropertyPrivate::signalExpression(prop), sigExpr); QCOMPARE(prop.index(), dobject.metaObject()->indexOfMethod("oddlyNamedNotifySignal()")); - QCOMPARE(QQmlPropertyPrivate::valueTypeCoreIndex(prop), -1); + QCOMPARE(QQmlPropertyPrivate::propertyIndex(prop).valueTypeIndex(), -1); + QVERIFY(!QQmlPropertyPrivate::propertyIndex(prop).hasValueTypeIndex()); delete obj; } diff --git a/tests/auto/qml/qqmlpropertycache/tst_qqmlpropertycache.cpp b/tests/auto/qml/qqmlpropertycache/tst_qqmlpropertycache.cpp index 5f15afff85..824fe445c0 100644 --- a/tests/auto/qml/qqmlpropertycache/tst_qqmlpropertycache.cpp +++ b/tests/auto/qml/qqmlpropertycache/tst_qqmlpropertycache.cpp @@ -30,6 +30,8 @@ #include <private/qqmlpropertycache_p.h> #include <QtQml/qqmlengine.h> #include <private/qv8engine_p.h> +#include <private/qmetaobjectbuilder_p.h> +#include <QCryptographicHash> #include "../../shared/util.h" class tst_qqmlpropertycache : public QObject @@ -45,6 +47,9 @@ private slots: void methodsDerived(); void signalHandlers(); void signalHandlersDerived(); + void metaObjectSize_data(); + void metaObjectSize(); + void metaObjectChecksum(); private: QQmlEngine engine; @@ -105,17 +110,17 @@ void tst_qqmlpropertycache::properties() QQmlRefPointer<QQmlPropertyCache> cache(new QQmlPropertyCache(v4, metaObject)); QQmlPropertyData *data; - QVERIFY(data = cacheProperty(cache, "propertyA")); - QCOMPARE(data->coreIndex, metaObject->indexOfProperty("propertyA")); + QVERIFY((data = cacheProperty(cache, "propertyA"))); + QCOMPARE(data->coreIndex(), metaObject->indexOfProperty("propertyA")); - QVERIFY(data = cacheProperty(cache, "propertyB")); - QCOMPARE(data->coreIndex, metaObject->indexOfProperty("propertyB")); + QVERIFY((data = cacheProperty(cache, "propertyB"))); + QCOMPARE(data->coreIndex(), metaObject->indexOfProperty("propertyB")); - QVERIFY(data = cacheProperty(cache, "propertyC")); - QCOMPARE(data->coreIndex, metaObject->indexOfProperty("propertyC")); + QVERIFY((data = cacheProperty(cache, "propertyC"))); + QCOMPARE(data->coreIndex(), metaObject->indexOfProperty("propertyC")); - QVERIFY(data = cacheProperty(cache, "propertyD")); - QCOMPARE(data->coreIndex, metaObject->indexOfProperty("propertyD")); + QVERIFY((data = cacheProperty(cache, "propertyD"))); + QCOMPARE(data->coreIndex(), metaObject->indexOfProperty("propertyD")); } void tst_qqmlpropertycache::propertiesDerived() @@ -129,17 +134,17 @@ void tst_qqmlpropertycache::propertiesDerived() QQmlRefPointer<QQmlPropertyCache> cache(parentCache->copyAndAppend(object.metaObject())); QQmlPropertyData *data; - QVERIFY(data = cacheProperty(cache, "propertyA")); - QCOMPARE(data->coreIndex, metaObject->indexOfProperty("propertyA")); + QVERIFY((data = cacheProperty(cache, "propertyA"))); + QCOMPARE(data->coreIndex(), metaObject->indexOfProperty("propertyA")); - QVERIFY(data = cacheProperty(cache, "propertyB")); - QCOMPARE(data->coreIndex, metaObject->indexOfProperty("propertyB")); + QVERIFY((data = cacheProperty(cache, "propertyB"))); + QCOMPARE(data->coreIndex(), metaObject->indexOfProperty("propertyB")); - QVERIFY(data = cacheProperty(cache, "propertyC")); - QCOMPARE(data->coreIndex, metaObject->indexOfProperty("propertyC")); + QVERIFY((data = cacheProperty(cache, "propertyC"))); + QCOMPARE(data->coreIndex(), metaObject->indexOfProperty("propertyC")); - QVERIFY(data = cacheProperty(cache, "propertyD")); - QCOMPARE(data->coreIndex, metaObject->indexOfProperty("propertyD")); + QVERIFY((data = cacheProperty(cache, "propertyD"))); + QCOMPARE(data->coreIndex(), metaObject->indexOfProperty("propertyD")); } void tst_qqmlpropertycache::methods() @@ -152,29 +157,29 @@ void tst_qqmlpropertycache::methods() QQmlRefPointer<QQmlPropertyCache> cache(new QQmlPropertyCache(v4, metaObject)); QQmlPropertyData *data; - QVERIFY(data = cacheProperty(cache, "slotA")); - QCOMPARE(data->coreIndex, metaObject->indexOfMethod("slotA()")); + QVERIFY((data = cacheProperty(cache, "slotA"))); + QCOMPARE(data->coreIndex(), metaObject->indexOfMethod("slotA()")); - QVERIFY(data = cacheProperty(cache, "slotB")); - QCOMPARE(data->coreIndex, metaObject->indexOfMethod("slotB()")); + QVERIFY((data = cacheProperty(cache, "slotB"))); + QCOMPARE(data->coreIndex(), metaObject->indexOfMethod("slotB()")); - QVERIFY(data = cacheProperty(cache, "signalA")); - QCOMPARE(data->coreIndex, metaObject->indexOfMethod("signalA()")); + QVERIFY((data = cacheProperty(cache, "signalA"))); + QCOMPARE(data->coreIndex(), metaObject->indexOfMethod("signalA()")); - QVERIFY(data = cacheProperty(cache, "signalB")); - QCOMPARE(data->coreIndex, metaObject->indexOfMethod("signalB()")); + QVERIFY((data = cacheProperty(cache, "signalB"))); + QCOMPARE(data->coreIndex(), metaObject->indexOfMethod("signalB()")); - QVERIFY(data = cacheProperty(cache, "propertyAChanged")); - QCOMPARE(data->coreIndex, metaObject->indexOfMethod("propertyAChanged()")); + QVERIFY((data = cacheProperty(cache, "propertyAChanged"))); + QCOMPARE(data->coreIndex(), metaObject->indexOfMethod("propertyAChanged()")); - QVERIFY(data = cacheProperty(cache, "propertyBChanged")); - QCOMPARE(data->coreIndex, metaObject->indexOfMethod("propertyBChanged()")); + QVERIFY((data = cacheProperty(cache, "propertyBChanged"))); + QCOMPARE(data->coreIndex(), metaObject->indexOfMethod("propertyBChanged()")); - QVERIFY(data = cacheProperty(cache, "propertyCChanged")); - QCOMPARE(data->coreIndex, metaObject->indexOfMethod("propertyCChanged()")); + QVERIFY((data = cacheProperty(cache, "propertyCChanged"))); + QCOMPARE(data->coreIndex(), metaObject->indexOfMethod("propertyCChanged()")); - QVERIFY(data = cacheProperty(cache, "propertyDChanged")); - QCOMPARE(data->coreIndex, metaObject->indexOfMethod("propertyDChanged()")); + QVERIFY((data = cacheProperty(cache, "propertyDChanged"))); + QCOMPARE(data->coreIndex(), metaObject->indexOfMethod("propertyDChanged()")); } void tst_qqmlpropertycache::methodsDerived() @@ -188,29 +193,29 @@ void tst_qqmlpropertycache::methodsDerived() QQmlRefPointer<QQmlPropertyCache> cache(parentCache->copyAndAppend(object.metaObject())); QQmlPropertyData *data; - QVERIFY(data = cacheProperty(cache, "slotA")); - QCOMPARE(data->coreIndex, metaObject->indexOfMethod("slotA()")); + QVERIFY((data = cacheProperty(cache, "slotA"))); + QCOMPARE(data->coreIndex(), metaObject->indexOfMethod("slotA()")); - QVERIFY(data = cacheProperty(cache, "slotB")); - QCOMPARE(data->coreIndex, metaObject->indexOfMethod("slotB()")); + QVERIFY((data = cacheProperty(cache, "slotB"))); + QCOMPARE(data->coreIndex(), metaObject->indexOfMethod("slotB()")); - QVERIFY(data = cacheProperty(cache, "signalA")); - QCOMPARE(data->coreIndex, metaObject->indexOfMethod("signalA()")); + QVERIFY((data = cacheProperty(cache, "signalA"))); + QCOMPARE(data->coreIndex(), metaObject->indexOfMethod("signalA()")); - QVERIFY(data = cacheProperty(cache, "signalB")); - QCOMPARE(data->coreIndex, metaObject->indexOfMethod("signalB()")); + QVERIFY((data = cacheProperty(cache, "signalB"))); + QCOMPARE(data->coreIndex(), metaObject->indexOfMethod("signalB()")); - QVERIFY(data = cacheProperty(cache, "propertyAChanged")); - QCOMPARE(data->coreIndex, metaObject->indexOfMethod("propertyAChanged()")); + QVERIFY((data = cacheProperty(cache, "propertyAChanged"))); + QCOMPARE(data->coreIndex(), metaObject->indexOfMethod("propertyAChanged()")); - QVERIFY(data = cacheProperty(cache, "propertyBChanged")); - QCOMPARE(data->coreIndex, metaObject->indexOfMethod("propertyBChanged()")); + QVERIFY((data = cacheProperty(cache, "propertyBChanged"))); + QCOMPARE(data->coreIndex(), metaObject->indexOfMethod("propertyBChanged()")); - QVERIFY(data = cacheProperty(cache, "propertyCChanged")); - QCOMPARE(data->coreIndex, metaObject->indexOfMethod("propertyCChanged()")); + QVERIFY((data = cacheProperty(cache, "propertyCChanged"))); + QCOMPARE(data->coreIndex(), metaObject->indexOfMethod("propertyCChanged()")); - QVERIFY(data = cacheProperty(cache, "propertyDChanged")); - QCOMPARE(data->coreIndex, metaObject->indexOfMethod("propertyDChanged()")); + QVERIFY((data = cacheProperty(cache, "propertyDChanged"))); + QCOMPARE(data->coreIndex(), metaObject->indexOfMethod("propertyDChanged()")); } void tst_qqmlpropertycache::signalHandlers() @@ -223,23 +228,23 @@ void tst_qqmlpropertycache::signalHandlers() QQmlRefPointer<QQmlPropertyCache> cache(new QQmlPropertyCache(v4, metaObject)); QQmlPropertyData *data; - QVERIFY(data = cacheProperty(cache, "onSignalA")); - QCOMPARE(data->coreIndex, metaObject->indexOfMethod("signalA()")); + QVERIFY((data = cacheProperty(cache, "onSignalA"))); + QCOMPARE(data->coreIndex(), metaObject->indexOfMethod("signalA()")); - QVERIFY(data = cacheProperty(cache, "onSignalB")); - QCOMPARE(data->coreIndex, metaObject->indexOfMethod("signalB()")); + QVERIFY((data = cacheProperty(cache, "onSignalB"))); + QCOMPARE(data->coreIndex(), metaObject->indexOfMethod("signalB()")); - QVERIFY(data = cacheProperty(cache, "onPropertyAChanged")); - QCOMPARE(data->coreIndex, metaObject->indexOfMethod("propertyAChanged()")); + QVERIFY((data = cacheProperty(cache, "onPropertyAChanged"))); + QCOMPARE(data->coreIndex(), metaObject->indexOfMethod("propertyAChanged()")); - QVERIFY(data = cacheProperty(cache, "onPropertyBChanged")); - QCOMPARE(data->coreIndex, metaObject->indexOfMethod("propertyBChanged()")); + QVERIFY((data = cacheProperty(cache, "onPropertyBChanged"))); + QCOMPARE(data->coreIndex(), metaObject->indexOfMethod("propertyBChanged()")); - QVERIFY(data = cacheProperty(cache, "onPropertyCChanged")); - QCOMPARE(data->coreIndex, metaObject->indexOfMethod("propertyCChanged()")); + QVERIFY((data = cacheProperty(cache, "onPropertyCChanged"))); + QCOMPARE(data->coreIndex(), metaObject->indexOfMethod("propertyCChanged()")); - QVERIFY(data = cacheProperty(cache, "onPropertyDChanged")); - QCOMPARE(data->coreIndex, metaObject->indexOfMethod("propertyDChanged()")); + QVERIFY((data = cacheProperty(cache, "onPropertyDChanged"))); + QCOMPARE(data->coreIndex(), metaObject->indexOfMethod("propertyDChanged()")); } void tst_qqmlpropertycache::signalHandlersDerived() @@ -253,25 +258,145 @@ void tst_qqmlpropertycache::signalHandlersDerived() QQmlRefPointer<QQmlPropertyCache> cache(parentCache->copyAndAppend(object.metaObject())); QQmlPropertyData *data; - QVERIFY(data = cacheProperty(cache, "onSignalA")); - QCOMPARE(data->coreIndex, metaObject->indexOfMethod("signalA()")); + QVERIFY((data = cacheProperty(cache, "onSignalA"))); + QCOMPARE(data->coreIndex(), metaObject->indexOfMethod("signalA()")); - QVERIFY(data = cacheProperty(cache, "onSignalB")); - QCOMPARE(data->coreIndex, metaObject->indexOfMethod("signalB()")); + QVERIFY((data = cacheProperty(cache, "onSignalB"))); + QCOMPARE(data->coreIndex(), metaObject->indexOfMethod("signalB()")); - QVERIFY(data = cacheProperty(cache, "onPropertyAChanged")); - QCOMPARE(data->coreIndex, metaObject->indexOfMethod("propertyAChanged()")); + QVERIFY((data = cacheProperty(cache, "onPropertyAChanged"))); + QCOMPARE(data->coreIndex(), metaObject->indexOfMethod("propertyAChanged()")); - QVERIFY(data = cacheProperty(cache, "onPropertyBChanged")); - QCOMPARE(data->coreIndex, metaObject->indexOfMethod("propertyBChanged()")); + QVERIFY((data = cacheProperty(cache, "onPropertyBChanged"))); + QCOMPARE(data->coreIndex(), metaObject->indexOfMethod("propertyBChanged()")); - QVERIFY(data = cacheProperty(cache, "onPropertyCChanged")); - QCOMPARE(data->coreIndex, metaObject->indexOfMethod("propertyCChanged()")); + QVERIFY((data = cacheProperty(cache, "onPropertyCChanged"))); + QCOMPARE(data->coreIndex(), metaObject->indexOfMethod("propertyCChanged()")); - QVERIFY(data = cacheProperty(cache, "onPropertyDChanged")); - QCOMPARE(data->coreIndex, metaObject->indexOfMethod("propertyDChanged()")); + QVERIFY((data = cacheProperty(cache, "onPropertyDChanged"))); + QCOMPARE(data->coreIndex(), metaObject->indexOfMethod("propertyDChanged()")); } -QTEST_MAIN(tst_qqmlpropertycache) +class TestClass : public QObject +{ + Q_OBJECT + Q_PROPERTY(int prop READ prop WRITE setProp NOTIFY propChanged) + int m_prop; + +public: + enum MyEnum { + First, Second + }; + Q_ENUM(MyEnum) + + Q_CLASSINFO("Foo", "Bar") + + TestClass() {} + + int prop() const + { + return m_prop; + } + +public slots: + void setProp(int prop) + { + if (m_prop == prop) + return; + + m_prop = prop; + emit propChanged(prop); + } +signals: + void propChanged(int prop); +}; + +class TestClassWithParameters : public QObject +{ + Q_OBJECT + +public: + Q_INVOKABLE void slotWithArguments(int firstArg) { + Q_UNUSED(firstArg); + } +}; + +class TestClassWithClassInfo : public QObject +{ + Q_OBJECT + Q_CLASSINFO("Key", "Value") +}; #include "tst_qqmlpropertycache.moc" + +#define ARRAY_SIZE(arr) \ + int(sizeof(arr) / sizeof(arr[0])) + +#define TEST_CLASS(Class) \ + QTest::newRow(#Class) << &Class::staticMetaObject << ARRAY_SIZE(qt_meta_data_##Class) << ARRAY_SIZE(qt_meta_stringdata_##Class.data) + +Q_DECLARE_METATYPE(const QMetaObject*); + +void tst_qqmlpropertycache::metaObjectSize_data() +{ + QTest::addColumn<const QMetaObject*>("metaObject"); + QTest::addColumn<int>("expectedFieldCount"); + QTest::addColumn<int>("expectedStringCount"); + + TEST_CLASS(TestClass); + TEST_CLASS(TestClassWithParameters); + TEST_CLASS(TestClassWithClassInfo); +} + +void tst_qqmlpropertycache::metaObjectSize() +{ + QFETCH(const QMetaObject *, metaObject); + QFETCH(int, expectedFieldCount); + QFETCH(int, expectedStringCount); + + int size = 0; + int stringDataSize = 0; + bool valid = QQmlPropertyCache::determineMetaObjectSizes(*metaObject, &size, &stringDataSize); + QVERIFY(valid); + + QCOMPARE(size, expectedFieldCount - 1); // Remove trailing zero field until fixed in moc. + QCOMPARE(stringDataSize, expectedStringCount); +} + +void tst_qqmlpropertycache::metaObjectChecksum() +{ + QMetaObjectBuilder builder; + builder.setClassName("Test"); + builder.addClassInfo("foo", "bar"); + + QCryptographicHash hash(QCryptographicHash::Md5); + + QScopedPointer<QMetaObject, QScopedPointerPodDeleter> mo(builder.toMetaObject()); + QVERIFY(!mo.isNull()); + + QVERIFY(QQmlPropertyCache::addToHash(hash, *mo.data())); + QByteArray initialHash = hash.result(); + QVERIFY(!initialHash.isEmpty()); + hash.reset(); + + { + QVERIFY(QQmlPropertyCache::addToHash(hash, *mo.data())); + QByteArray nextHash = hash.result(); + QVERIFY(!nextHash.isEmpty()); + hash.reset(); + QCOMPARE(initialHash, nextHash); + } + + builder.addProperty("testProperty", "int", -1); + + mo.reset(builder.toMetaObject()); + { + QVERIFY(QQmlPropertyCache::addToHash(hash, *mo.data())); + QByteArray nextHash = hash.result(); + QVERIFY(!nextHash.isEmpty()); + hash.reset(); + QVERIFY(initialHash != nextHash); + } +} + +QTEST_MAIN(tst_qqmlpropertycache) diff --git a/tests/auto/qml/qqmlqt/data/LaterComponent.qml b/tests/auto/qml/qqmlqt/data/LaterComponent.qml new file mode 100644 index 0000000000..7dbd81d93d --- /dev/null +++ b/tests/auto/qml/qqmlqt/data/LaterComponent.qml @@ -0,0 +1,14 @@ +import QtQuick 2.0 +import LaterImports 1.0 + +TestElement { + id: deleteme + function testFn() { + gc(); // at this point, obj is deleted. + dangerousFunction(); // calling this function will throw an exeption + // because this object has been deleted and its context is not available + + // which means that we shouldn't get to this line. + row.test10_1 = 1; + } +} diff --git a/tests/auto/qml/qqmlqt/data/LaterComponent2.qml b/tests/auto/qml/qqmlqt/data/LaterComponent2.qml new file mode 100644 index 0000000000..56bcc0235b --- /dev/null +++ b/tests/auto/qml/qqmlqt/data/LaterComponent2.qml @@ -0,0 +1,13 @@ +import QtQuick 2.0 + +Item { + id: deleteme2 + function testFn() { + // this function shouldn't be called, + // since the object will have been deleted. + var crashy = Qt.createQmlObject("import QtQuick 2.0; Item { }", deleteme2) // invalid calling context if invoked after gc + row.test11_1 = 2; + } + + Component.onDestruction: row.test11_1 = 1; // success == the object was deleted, but testFn wasn't called. +} diff --git a/tests/auto/qml/qqmlqt/data/LaterComponent3.qml b/tests/auto/qml/qqmlqt/data/LaterComponent3.qml new file mode 100644 index 0000000000..c6f445253a --- /dev/null +++ b/tests/auto/qml/qqmlqt/data/LaterComponent3.qml @@ -0,0 +1,14 @@ +import QtQuick 2.0 +import LaterImports 1.0 + +TestElement { + id: deleteme3 + function testFn() { + gc(); // at this point, obj is deleted. + dangerousFunction(); // calling this function will throw an exeption + // because this object has been deleted and its context is not available + + // which means that we shouldn't get to this line. + row.test12_1 = 1; + } +} diff --git a/tests/auto/qml/qqmlqt/data/LaterComponent4.qml b/tests/auto/qml/qqmlqt/data/LaterComponent4.qml new file mode 100644 index 0000000000..0c53bd368b --- /dev/null +++ b/tests/auto/qml/qqmlqt/data/LaterComponent4.qml @@ -0,0 +1,12 @@ +import QtQuick 2.0 + +Item { + id: deleteme4 + function testFn() { + // this function shouldn't be called, + // since the object will have been deleted. + row.test13_1 = 2; + } + + Component.onDestruction: row.test13_1 = 1; // success == the object was deleted, but testFn wasn't called. +} diff --git a/tests/auto/qml/qqmlqt/data/exit.qml b/tests/auto/qml/qqmlqt/data/exit.qml new file mode 100644 index 0000000000..12727d9f04 --- /dev/null +++ b/tests/auto/qml/qqmlqt/data/exit.qml @@ -0,0 +1,7 @@ +import QtQuick 2.0 + +QtObject { + property int returnCode: -1 + Component.onCompleted: Qt.exit(returnCode) +} + diff --git a/tests/auto/qml/qqmlqt/data/later.qml b/tests/auto/qml/qqmlqt/data/later.qml new file mode 100644 index 0000000000..a90f3aba9f --- /dev/null +++ b/tests/auto/qml/qqmlqt/data/later.qml @@ -0,0 +1,124 @@ +import QtQuick 2.0 +import LaterImports 1.0 + +Row { + id: row + Repeater { + id: repeater + model: 5 + delegate: Item { } + } + + property bool test1_1: false + property bool test1_2: row.focus + property bool test2_1: false + property bool test2_2: (firstFunctionCallCounter == 1 && secondFunctionCallCounter == 1 && signalCallCounter == 1) + + property int firstFunctionCallCounter: 0 + property int secondFunctionCallCounter: 0 + property int signalCallCounter: 0 + + signal testSignal + onTestSignal: { + signalCallCounter++; + } + + onChildrenChanged: { + Qt.callLater(row.forceActiveFocus); // built-in function + Qt.callLater(row.firstFunction); // JS function + Qt.callLater(row.testSignal); // signal + } + + function firstFunction() { + firstFunctionCallCounter++; + } + + function secondFunction() { + secondFunctionCallCounter++; + } + + Component.onCompleted: { + test1_1 = !row.focus; + test2_1 = (firstFunctionCallCounter == 0); + + Qt.callLater(secondFunction); + Qt.callLater(firstFunction); + Qt.callLater(secondFunction); + } + + function test2() { + repeater.model = 2; + } + + function test3() { + Qt.callLater(test3_recursive); + } + + property int recursion: 0 + property bool test3_1: (recursion == 1) + property bool test3_2: (recursion == 2) + property bool test3_3: (recursion == 3) + function test3_recursive() { + if (recursion < 3) { + Qt.callLater(test3_recursive); + Qt.callLater(test3_recursive); + } + recursion++; + } + + function test4() { + Qt.callLater(functionThatDoesNotExist); + } + + property bool test5_1: false + function test5() { + Qt.callLater(functionWithArguments, "THESE", "ARGS", "WILL", "BE", "OVERWRITTEN") + Qt.callLater(functionWithArguments, "firstArg", 2, "thirdArg") + } + + function functionWithArguments(firstStr, secondInt, thirdString) { + test5_1 = (firstStr == "firstArg" && secondInt == 2 && thirdString == "thirdArg"); + } + + + property bool test6_1: (callOrder_Later == "TWO THREE ") // not "THREE TWO " + function test6() { + Qt.callLater(test6Function1, "ONE"); + Qt.callLater(test6Function2, "TWO"); + Qt.callLater(test6Function1, "THREE"); + } + + property string callOrder_Later + function test6Function1(arg) { callOrder_Later += arg + " "; } + function test6Function2(arg) { callOrder_Later += arg + " "; } + + property int test9_1: SingletonType.intProp; + function test9() { + SingletonType.resetIntProp(); + Qt.callLater(SingletonType.testFunc) + Qt.callLater(SingletonType.testFunc) + Qt.callLater(SingletonType.testFunc) + Qt.callLater(SingletonType.testFunc) + // should only get called once. + } + + property int test10_1: 0 + function test10() { + var c = Qt.createComponent("LaterComponent.qml"); + var obj = c.createObject(); // QML ownership. + Qt.callLater(obj.testFn); + // note: obj will be cleaned up during next gc(). + } + + property int test11_1: 0 + function test11() { + var c = Qt.createComponent("LaterComponent2.qml"); + var obj = c.createObject(); // QML ownership. + Qt.callLater(obj.testFn); + gc(); // this won't actually collect the obj, we need to trigger gc manually in the test. + } + + function test14() { + Qt.callLater(console.log, "success") + } +} diff --git a/tests/auto/qml/qqmlqt/data/timeRoundtrip.qml b/tests/auto/qml/qqmlqt/data/timeRoundtrip.qml new file mode 100644 index 0000000000..9d73640c87 --- /dev/null +++ b/tests/auto/qml/qqmlqt/data/timeRoundtrip.qml @@ -0,0 +1,8 @@ +import QtQuick 2.0 + +QtObject { + Component.onCompleted: { + var t = tp.time; + tp.time = t; + } +} diff --git a/tests/auto/qml/qqmlqt/tst_qqmlqt.cpp b/tests/auto/qml/qqmlqt/tst_qqmlqt.cpp index 2f44c34bc2..0576650d01 100644 --- a/tests/auto/qml/qqmlqt/tst_qqmlqt.cpp +++ b/tests/auto/qml/qqmlqt/tst_qqmlqt.cpp @@ -46,6 +46,15 @@ #include <QFont> #include "../../shared/util.h" +// Copied from tst_qdatetime.cpp +#ifdef Q_OS_WIN +# include <qt_windows.h> +# include <time.h> +# if defined(Q_OS_WINRT) +# define tzset() +# endif +#endif + class tst_qqmlqt : public QQmlDataTest { Q_OBJECT @@ -53,6 +62,7 @@ public: tst_qqmlqt() {} private slots: + void initTestCase(); void enums(); void rgba(); void hsla(); @@ -86,13 +96,74 @@ private slots: void atob(); void fontFamilies(); void quit(); + void exit(); void resolvedUrl(); + void later_data(); + void later(); void qtObjectContents(); + void timeRoundtrip_data(); + void timeRoundtrip(); + private: QQmlEngine engine; }; +// for callLater() +class TestElement : public QQuickItem +{ + Q_OBJECT +public: + TestElement() : m_intptr(new int) {} + ~TestElement() { delete m_intptr; } + + Q_INVOKABLE void dangerousFunction() { + delete m_intptr; + m_intptr = new int; + *m_intptr = 5; + } +private: + int *m_intptr; +}; + +// for callLater() +class TestModuleApi : public QObject +{ + Q_OBJECT + Q_PROPERTY(int intProp READ intProp WRITE setIntProp NOTIFY intPropChanged) + +public: + TestModuleApi() : m_int(0) {} + ~TestModuleApi() {} + + int intProp() const { return m_int; } + void setIntProp(int v) { m_int = v; emit intPropChanged(); } + + Q_INVOKABLE void testFunc() { ++m_int; emit intPropChanged(); } + Q_INVOKABLE void resetIntProp() { m_int = 0; emit intPropChanged(); } + +signals: + void intPropChanged(); + +private: + int m_int; +}; + +static QObject *test_module_api_factory(QQmlEngine *engine, QJSEngine *scriptEngine) +{ + Q_UNUSED(engine) + Q_UNUSED(scriptEngine) + TestModuleApi *api = new TestModuleApi; + return api; +} + +void tst_qqmlqt::initTestCase() +{ + QQmlDataTest::initTestCase(); + qmlRegisterSingletonType<TestModuleApi>("LaterImports", 1, 0, "SingletonType", test_module_api_factory); + qmlRegisterType<TestElement>("LaterImports", 1, 0, "TestElement"); +} + void tst_qqmlqt::enums() { QQmlComponent component(&engine, testFileUrl("enums.qml")); @@ -814,8 +885,6 @@ void tst_qqmlqt::dateTimeFormattingVariants_data() QTime time(11, 16, 39, 755); temporary = QDateTime(QDate(1970,1,1), time); - QTest::newRow("formatDate, qtime") << "formatDate" << QVariant::fromValue(time) << (QStringList() << temporary.date().toString(Qt::DefaultLocaleShortDate) << temporary.date().toString(Qt::DefaultLocaleLongDate) << temporary.date().toString("ddd MMMM d yy")); - QTest::newRow("formatDateTime, qtime") << "formatDateTime" << QVariant::fromValue(time) << (QStringList() << temporary.toString(Qt::DefaultLocaleShortDate) << temporary.toString(Qt::DefaultLocaleLongDate) << temporary.toString("M/d/yy H:m:s a")); QTest::newRow("formatTime, qtime") << "formatTime" << QVariant::fromValue(time) << (QStringList() << temporary.time().toString(Qt::DefaultLocaleShortDate) << temporary.time().toString(Qt::DefaultLocaleLongDate) << temporary.time().toString("H:m:s a") << temporary.time().toString("hh:mm:ss.zzz")); QDate date(2011,5,31); @@ -922,6 +991,20 @@ void tst_qqmlqt::quit() delete object; } +void tst_qqmlqt::exit() +{ + QQmlComponent component(&engine, testFileUrl("exit.qml")); + + QSignalSpy spy(&engine, &QQmlEngine::exit); + QObject *object = component.create(); + QVERIFY(object != Q_NULLPTR); + QCOMPARE(spy.count(), 1); + QList<QVariant> arguments = spy.takeFirst(); + QVERIFY(arguments.at(0).toInt() == object->property("returnCode").toInt()); + + delete object; +} + void tst_qqmlqt::resolvedUrl() { QQmlComponent component(&engine, testFileUrl("resolvedUrl.qml")); @@ -935,6 +1018,107 @@ void tst_qqmlqt::resolvedUrl() delete object; } +void tst_qqmlqt::later_data() +{ + QTest::addColumn<QString>("function"); + QTest::addColumn<QStringList>("expectedWarnings"); + QTest::addColumn<QStringList>("propNames"); + QTest::addColumn<QVariantList>("values"); + + QVariant vtrue = QVariant(true); + + QTest::newRow("callLater from onCompleted") + << QString() + << QStringList() + << (QStringList() << "test1_1" << "test2_1" << "processEvents" << "test1_2" << "test2_2") + << (QVariantList() << vtrue << vtrue << QVariant() << vtrue << vtrue); + + QTest::newRow("trigger Qt.callLater() via repeater") + << QString(QLatin1String("test2")) + << QStringList() + << (QStringList() << "processEvents" << "test2_2") + << (QVariantList() << QVariant() << vtrue); + + QTest::newRow("recursive Qt.callLater()") + << QString(QLatin1String("test3")) + << QStringList() + << (QStringList() << "processEvents" << "test3_1" << "processEvents" << "test3_2" << "processEvents" << "test3_3") + << (QVariantList() << QVariant() << vtrue << QVariant() << vtrue << QVariant() << vtrue); + + QTest::newRow("nonexistent function") + << QString(QLatin1String("test4")) + << (QStringList() << QString(testFileUrl("later.qml").toString() + QLatin1String(":70: ReferenceError: functionThatDoesNotExist is not defined"))) + << QStringList() + << QVariantList(); + + QTest::newRow("callLater with different args") + << QString(QLatin1String("test5")) + << QStringList() + << (QStringList() << "processEvents" << "test5_1") + << (QVariantList() << QVariant() << vtrue); + + QTest::newRow("delayed call ordering") + << QString(QLatin1String("test6")) + << QStringList() + << (QStringList() << "processEvents" << "test6_1") + << (QVariantList() << QVariant() << vtrue); + + QTest::newRow("invoke module api invokable") + << QString(QLatin1String("test9")) + << QStringList() + << (QStringList() << "processEvents" << "test9_1" << "processEvents") + << (QVariantList() << QVariant() << QVariant(1) << QVariant()); + + QTest::newRow("invoke function of deleted QObject via callLater() causing deletion") + << QString(QLatin1String("test10")) + << (QStringList() << QString(testFileUrl("LaterComponent.qml").toString() + QLatin1String(":8: ReferenceError: dangerousFunction is not defined (exception occurred during delayed function evaluation)"))) + << (QStringList() << "processEvents" << "test10_1" << "processEvents") + << (QVariantList() << QVariant() << QVariant(0) << QVariant()); + + QTest::newRow("invoke function of deleted QObject via callLater() after deletion") + << QString(QLatin1String("test11")) + << QStringList() + << (QStringList() << "collectGarbage" << "processEvents" << "test11_1" << "processEvents") + << (QVariantList() << QVariant() << QVariant() << QVariant(1) << QVariant()); + + QTest::newRow("invoke function which has no script origin") + << QString(QLatin1String("test14")) + << QStringList() + << (QStringList() << "collectGarbage") + << (QVariantList() << QVariant()); +} + +void tst_qqmlqt::later() +{ + QFETCH(QString, function); + QFETCH(QStringList, expectedWarnings); + QFETCH(QStringList, propNames); + QFETCH(QVariantList, values); + + foreach (const QString &w, expectedWarnings) + QTest::ignoreMessage(QtWarningMsg, qPrintable(w)); + + QQmlComponent component(&engine, testFileUrl("later.qml")); + QObject *root = component.create(); + QVERIFY(root != 0); + + if (!function.isEmpty()) + QMetaObject::invokeMethod(root, qPrintable(function)); + + for (int i = 0; i < propNames.size(); ++i) { + if (propNames.at(i) == QLatin1String("processEvents")) { + QCoreApplication::sendPostedEvents(0, QEvent::DeferredDelete); + QCoreApplication::processEvents(); + } else if (propNames.at(i) == QLatin1String("collectGarbage")) { + engine.collectGarbage(); + } else { + QCOMPARE(root->property(qPrintable(propNames.at(i))), values.at(i)); + } + } + + delete root; +} + void tst_qqmlqt::qtObjectContents() { struct StaticQtMetaObject : public QObject @@ -980,6 +1164,104 @@ void tst_qqmlqt::qtObjectContents() delete object; } +class TimeProvider: public QObject +{ + Q_OBJECT + Q_PROPERTY(QTime time READ time WRITE setTime NOTIFY timeChanged) + +public: + TimeProvider(const QTime &t) + : m_getTime(t) + {} + + QTime time() const { return m_getTime; } + void setTime(const QTime &t) { m_putTime = t; emit timeChanged(); } + +signals: + void timeChanged(); + +public: + QTime m_getTime, m_putTime; +}; + +class TimeZoneSwitch +{ +public: + TimeZoneSwitch(const char *newZone) + : doChangeZone(qstrcmp(newZone, "localtime") == 0) + { + if (!doChangeZone) + return; + + hadOldZone = qEnvironmentVariableIsSet("TZ"); + if (hadOldZone) { + oldZone = qgetenv("TZ"); + } + qputenv("TZ", newZone); + tzset(); + } + + ~TimeZoneSwitch() + { + if (!doChangeZone) + return; + + if (hadOldZone) + qputenv("TZ", oldZone); + else + qunsetenv("TZ"); + tzset(); + } + +private: + bool doChangeZone; + bool hadOldZone; + QByteArray oldZone; +}; + +void tst_qqmlqt::timeRoundtrip_data() +{ + QTest::addColumn<QTime>("time"); + + // Local timezone: + QTest::newRow("localtime") << QTime(0, 0, 0); + + // No DST: + QTest::newRow("UTC") << QTime(0, 0, 0); + QTest::newRow("Europe/Amsterdam") << QTime(1, 0, 0); + QTest::newRow("Asia/Jakarta") << QTime(7, 0, 0); + + // DST: + QTest::newRow("Namibia/Windhoek") << QTime(1, 0, 0); + QTest::newRow("Australia/Adelaide") << QTime(10, 0, 0); + QTest::newRow("Australia/Hobart") << QTime(10, 0, 0); + QTest::newRow("Pacific/Auckland") << QTime(12, 0, 0); + QTest::newRow("Pacific/Samoa") << QTime(13, 0, 0); +} + +void tst_qqmlqt::timeRoundtrip() +{ +#ifdef Q_OS_WIN + QSKIP("On Windows, the DateObject doesn't handle DST transitions correctly when the timezone is not localtime."); // I.e.: for this test. +#endif + + TimeZoneSwitch tzs(QTest::currentDataTag()); + QFETCH(QTime, time); + + TimeProvider tp(time); + + QQmlEngine eng; + eng.rootContext()->setContextProperty(QLatin1String("tp"), &tp); + QQmlComponent component(&eng, testFileUrl("timeRoundtrip.qml")); + QObject *obj = component.create(); + QVERIFY(obj != 0); + + // QML reads m_getTime and saves the result as m_putTime; this should come out the same, without + // any perturbation (e.g. by DST effects) from converting from QTime to V4's Date and back + // again. + QCOMPARE(tp.m_getTime, tp.m_putTime); +} + QTEST_MAIN(tst_qqmlqt) #include "tst_qqmlqt.moc" diff --git a/tests/auto/qml/qqmltranslation/tst_qqmltranslation.cpp b/tests/auto/qml/qqmltranslation/tst_qqmltranslation.cpp index bf255ba6a0..1fc803a395 100644 --- a/tests/auto/qml/qqmltranslation/tst_qqmltranslation.cpp +++ b/tests/auto/qml/qqmltranslation/tst_qqmltranslation.cpp @@ -31,7 +31,6 @@ #include <QQmlComponent> #include <QTranslator> #include <QQmlContext> -#include <private/qqmlcompiler_p.h> #include <private/qqmlengine_p.h> #include "../../shared/util.h" @@ -77,15 +76,15 @@ void tst_qqmltranslation::translation() QQmlContext *context = qmlContext(object); QQmlEnginePrivate *engine = QQmlEnginePrivate::get(context->engine()); QQmlTypeData *typeData = engine->typeLoader.getType(context->baseUrl()); - QQmlCompiledData *cdata = typeData->compiledData(); - QVERIFY(cdata); + QV4::CompiledData::CompilationUnit *compilationUnit = typeData->compilationUnit(); + QVERIFY(compilationUnit); QSet<QString> compiledTranslations; compiledTranslations << QStringLiteral("basic") << QStringLiteral("disambiguation") << QStringLiteral("singular") << QStringLiteral("plural"); - const QV4::CompiledData::Unit *unit = cdata->compilationUnit->data; + const QV4::CompiledData::Unit *unit = compilationUnit->data; const QV4::CompiledData::Object *rootObject = unit->objectAt(unit->indexOfRootObject); const QV4::CompiledData::Binding *binding = rootObject->bindingTable(); for (quint32 i = 0; i < rootObject->nBindings; ++i, ++binding) { @@ -96,7 +95,7 @@ void tst_qqmltranslation::translation() if (expectCompiledTranslation) { if (binding->type != QV4::CompiledData::Binding::Type_Translation) qDebug() << "binding for property" << propertyName << "is not a compiled translation"; - QCOMPARE(binding->type, quint32(QV4::CompiledData::Binding::Type_Translation)); + QCOMPARE(quint32(binding->type), quint32(QV4::CompiledData::Binding::Type_Translation)); } else { if (binding->type == QV4::CompiledData::Binding::Type_Translation) qDebug() << "binding for property" << propertyName << "is not supposed to be a compiled translation"; @@ -137,10 +136,10 @@ void tst_qqmltranslation::idTranslation() QQmlContext *context = qmlContext(object); QQmlEnginePrivate *engine = QQmlEnginePrivate::get(context->engine()); QQmlTypeData *typeData = engine->typeLoader.getType(context->baseUrl()); - QQmlCompiledData *cdata = typeData->compiledData(); - QVERIFY(cdata); + QV4::CompiledData::CompilationUnit *compilationUnit = typeData->compilationUnit(); + QVERIFY(compilationUnit); - const QV4::CompiledData::Unit *unit = cdata->compilationUnit->data; + const QV4::CompiledData::Unit *unit = compilationUnit->data; const QV4::CompiledData::Object *rootObject = unit->objectAt(unit->indexOfRootObject); const QV4::CompiledData::Binding *binding = rootObject->bindingTable(); for (quint32 i = 0; i < rootObject->nBindings; ++i, ++binding) { @@ -148,7 +147,7 @@ void tst_qqmltranslation::idTranslation() if (propertyName == "idTranslation") { if (binding->type != QV4::CompiledData::Binding::Type_TranslationById) qDebug() << "binding for property" << propertyName << "is not a compiled translation"; - QCOMPARE(binding->type, quint32(QV4::CompiledData::Binding::Type_TranslationById)); + QCOMPARE(quint32(binding->type), quint32(QV4::CompiledData::Binding::Type_TranslationById)); } else { QVERIFY(binding->type != QV4::CompiledData::Binding::Type_Translation); } diff --git a/tests/auto/qml/qqmltypeloader/tst_qqmltypeloader.cpp b/tests/auto/qml/qqmltypeloader/tst_qqmltypeloader.cpp index 36350e2d08..3d3a7ff725 100644 --- a/tests/auto/qml/qqmltypeloader/tst_qqmltypeloader.cpp +++ b/tests/auto/qml/qqmltypeloader/tst_qqmltypeloader.cpp @@ -32,7 +32,6 @@ #include <QtQuick/qquickitem.h> #include <QtQml/private/qqmlengine_p.h> #include <QtQml/private/qqmltypeloader_p.h> -#include <QtQml/private/qqmlcompiler_p.h> #include "../../shared/util.h" class tst_QQMLTypeLoader : public QQmlDataTest @@ -90,7 +89,7 @@ void tst_QQMLTypeLoader::trimCache() if (i % 10 == 0) { // keep ref on data, don't add ref on data->compiledData() } else if (i % 5 == 0) { - data->compiledData()->addref(); + data->compilationUnit()->addref(); data->release(); } else { data->release(); diff --git a/tests/auto/qml/qqmlvaluetypes/data/color_read.qml b/tests/auto/qml/qqmlvaluetypes/data/color_read.qml index bc92b1e5f9..73d2b921a7 100644 --- a/tests/auto/qml/qqmlvaluetypes/data/color_read.qml +++ b/tests/auto/qml/qqmlvaluetypes/data/color_read.qml @@ -5,5 +5,11 @@ MyTypeObject { property real v_g: color.g property real v_b: color.b property real v_a: color.a + property real hsv_h: color.hsvHue + property real hsv_s: color.hsvSaturation + property real hsv_v: color.hsvValue + property real hsl_h: color.hslHue + property real hsl_s: color.hslSaturation + property real hsl_l: color.hslLightness property variant copy: color } diff --git a/tests/auto/qml/qqmlvaluetypes/data/color_write_HSL.qml b/tests/auto/qml/qqmlvaluetypes/data/color_write_HSL.qml new file mode 100644 index 0000000000..0034163bbe --- /dev/null +++ b/tests/auto/qml/qqmlvaluetypes/data/color_write_HSL.qml @@ -0,0 +1,8 @@ +import Test 1.0 + +MyTypeObject { + color.hslHue: if (true) 0.43 + color.hslSaturation: if (true) 0.74 + color.hslLightness: if (true) 0.54 + color.a: if (true) 0.7 +} diff --git a/tests/auto/qml/qqmlvaluetypes/data/color_write_HSV.qml b/tests/auto/qml/qqmlvaluetypes/data/color_write_HSV.qml new file mode 100644 index 0000000000..1fc47d460e --- /dev/null +++ b/tests/auto/qml/qqmlvaluetypes/data/color_write_HSV.qml @@ -0,0 +1,8 @@ +import Test 1.0 + +MyTypeObject { + color.hsvHue: if (true) 0.43 + color.hsvSaturation: if (true) 0.77 + color.hsvValue: if (true) 0.88 + color.a: if (true) 0.7 +} diff --git a/tests/auto/qml/qqmlvaluetypes/testtypes.h b/tests/auto/qml/qqmlvaluetypes/testtypes.h index 77d723fbd4..bcfe4028c6 100644 --- a/tests/auto/qml/qqmlvaluetypes/testtypes.h +++ b/tests/auto/qml/qqmlvaluetypes/testtypes.h @@ -194,7 +194,7 @@ class MyOffsetValueInterceptor : public QObject, public QQmlPropertyValueInterce Q_INTERFACES(QQmlPropertyValueInterceptor) public: virtual void setTarget(const QQmlProperty &p) { prop = p; } - virtual void write(const QVariant &value) { QQmlPropertyPrivate::write(prop, value.toInt() + 13, QQmlPropertyPrivate::BypassInterceptor); } + virtual void write(const QVariant &value) { QQmlPropertyPrivate::write(prop, value.toInt() + 13, QQmlPropertyData::BypassInterceptor); } private: QQmlProperty prop; @@ -215,7 +215,7 @@ public: c.getRgb(&r, &g, &b, &a); c.setRgb(a, b, g, r); - QQmlPropertyPrivate::write(prop, c, QQmlPropertyPrivate::BypassInterceptor); + QQmlPropertyPrivate::write(prop, c, QQmlPropertyData::BypassInterceptor); } private: @@ -230,7 +230,7 @@ public: virtual void setTarget(const QQmlProperty &p) { prop = p; } virtual void write(const QVariant &) { - QQmlPropertyPrivate::write(prop, 0.0f, QQmlPropertyPrivate::BypassInterceptor); + QQmlPropertyPrivate::write(prop, 0.0f, QQmlPropertyData::BypassInterceptor); } private: diff --git a/tests/auto/qml/qqmlvaluetypes/tst_qqmlvaluetypes.cpp b/tests/auto/qml/qqmlvaluetypes/tst_qqmlvaluetypes.cpp index 300f5b90e5..803bad197a 100644 --- a/tests/auto/qml/qqmlvaluetypes/tst_qqmlvaluetypes.cpp +++ b/tests/auto/qml/qqmlvaluetypes/tst_qqmlvaluetypes.cpp @@ -30,6 +30,7 @@ #include <QQmlEngine> #include <QQmlComponent> #include <QDebug> +#include <QJSValueIterator> #include <private/qquickvaluetypes_p.h> #include <private/qqmlglobal_p.h> #include "../../shared/util.h" @@ -89,6 +90,7 @@ private slots: void customValueTypeInQml(); void gadgetInheritance(); void toStringConversion(); + void enumerableProperties(); private: QQmlEngine engine; @@ -905,6 +907,15 @@ void tst_qqmlvaluetypes::color() QCOMPARE((float)object->property("v_g").toDouble(), (float)0.88); QCOMPARE((float)object->property("v_b").toDouble(), (float)0.6); QCOMPARE((float)object->property("v_a").toDouble(), (float)0.34); + + QCOMPARE(qRound(object->property("hsv_h").toDouble() * 100), 43); + QCOMPARE(qRound(object->property("hsv_s").toDouble() * 100), 77); + QCOMPARE(qRound(object->property("hsv_v").toDouble() * 100), 88); + + QCOMPARE(qRound(object->property("hsl_h").toDouble() * 100), 43); + QCOMPARE(qRound(object->property("hsl_s").toDouble() * 100), 74); + QCOMPARE(qRound(object->property("hsl_l").toDouble() * 100), 54); + QColor comparison; comparison.setRedF(0.2); comparison.setGreenF(0.88); @@ -931,6 +942,30 @@ void tst_qqmlvaluetypes::color() } { + QQmlComponent component(&engine, testFileUrl("color_write_HSV.qml")); + MyTypeObject *object = qobject_cast<MyTypeObject *>(component.create()); + QVERIFY(object != 0); + + QColor newColor; + newColor.setHsvF(0.43, 0.77, 0.88, 0.7); + QCOMPARE(object->color(), newColor); + + delete object; + } + + { + QQmlComponent component(&engine, testFileUrl("color_write_HSL.qml")); + MyTypeObject *object = qobject_cast<MyTypeObject *>(component.create()); + QVERIFY(object != 0); + + QColor newColor; + newColor.setHslF(0.43, 0.74, 0.54, 0.7); + QCOMPARE(object->color(), newColor); + + delete object; + } + + { QQmlComponent component(&engine, testFileUrl("color_compare.qml")); MyTypeObject *object = qobject_cast<MyTypeObject *>(component.create()); QVERIFY(object != 0); @@ -1649,6 +1684,25 @@ void tst_qqmlvaluetypes::toStringConversion() QCOMPARE(stringConversion.toString(), StringLessGadget_to_QString(g)); } +void tst_qqmlvaluetypes::enumerableProperties() +{ + QJSEngine engine; + DerivedGadget g; + QJSValue value = engine.toScriptValue(g); + QSet<QString> names; + QJSValueIterator it(value); + while (it.hasNext()) { + it.next(); + const QString name = it.name(); + QVERIFY(!names.contains(name)); + names.insert(name); + } + + QCOMPARE(names.count(), 2); + QVERIFY(names.contains(QStringLiteral("baseProperty"))); + QVERIFY(names.contains(QStringLiteral("derivedProperty"))); +} + QTEST_MAIN(tst_qqmlvaluetypes) diff --git a/tests/auto/qml/qqmlxmlhttprequest/data/send_patch.expect b/tests/auto/qml/qqmlxmlhttprequest/data/send_patch.expect new file mode 100644 index 0000000000..8c13977462 --- /dev/null +++ b/tests/auto/qml/qqmlxmlhttprequest/data/send_patch.expect @@ -0,0 +1,17 @@ +PATCH /qqmlxmlhttprequest.cpp HTTP/1.1 +Accept-Language: en-US +If-Match: "ETagNumber" +Content-Type: application/example +Content-Length: 247 +Connection: Keep-Alive +Accept-Encoding: gzip, deflate +User-Agent: Mozilla/5.0 +Host: {{ServerHostUrl}} + +--- a/qqmlxmlhttprequest.cpp ++++ b/qqmlxmlhttprequest.cpp +@@ -1238,11 +1238,13 @@ +- } else if (m_method == QLatin1String("OPTIONS")) { ++ } else if (m_method == QLatin1String("OPTIONS") || ++ (m_method == QLatin1String("PATCH"))) { + diff --git a/tests/auto/qml/qqmlxmlhttprequest/data/send_patch.qml b/tests/auto/qml/qqmlxmlhttprequest/data/send_patch.qml new file mode 100644 index 0000000000..2abf1c60a8 --- /dev/null +++ b/tests/auto/qml/qqmlxmlhttprequest/data/send_patch.qml @@ -0,0 +1,68 @@ +/**************************************************************************** +** +** Copyright (C) 2015 Canonical Limited and/or its subsidiary(-ies). +** Contact: http://www.qt.io/licensing/ +** +** This file is part of the test suite of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL21$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see http://www.qt.io/terms-conditions. For further +** information use the contact form at http://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 or version 3 as published by the Free +** Software Foundation and appearing in the file LICENSE.LGPLv21 and +** LICENSE.LGPLv3 included in the packaging of this file. Please review the +** following information to ensure the GNU Lesser General Public License +** requirements will be met: https://www.gnu.org/licenses/lgpl.html and +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** As a special exception, The Qt Company gives you certain additional +** rights. These rights are described in The Qt Company LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +import QtQuick 2.0 + +QtObject { + property string url + + property bool dataOK: false + property bool headerOK: false + + Component.onCompleted: { + var x = new XMLHttpRequest; + x.open("PATCH", url); + x.setRequestHeader("Accept-Language","en-US"); + x.setRequestHeader("If-Match","\"ETagNumber\""); + + // Test to the end + x.onreadystatechange = function() { + if (x.readyState == XMLHttpRequest.HEADERS_RECEIVED) { + headerOK = (x.getResponseHeader("Content-Location") == "/qqmlxmlhttprequest.cpp") && + (x.getResponseHeader("ETag") == "\"ETagNumber\"") && + (x.status == "204"); + } else if (x.readyState == XMLHttpRequest.DONE) { + dataOK = (x.responseText === ""); + } + } + + var body = "--- a/qqmlxmlhttprequest.cpp\n" + + "+++ b/qqmlxmlhttprequest.cpp\n" + + "@@ -1238,11 +1238,13 @@\n" + + "- } else if (m_method == QLatin1String(\"OPTIONS\")) {\n" + + "+ } else if (m_method == QLatin1String(\"OPTIONS\") ||\n" + + "+ (m_method == QLatin1String(\"PATCH\"))) {\n" + + x.send(body); + } +} diff --git a/tests/auto/qml/qqmlxmlhttprequest/data/send_patch.reply b/tests/auto/qml/qqmlxmlhttprequest/data/send_patch.reply new file mode 100644 index 0000000000..cece41ced1 --- /dev/null +++ b/tests/auto/qml/qqmlxmlhttprequest/data/send_patch.reply @@ -0,0 +1,3 @@ +HTTP/1.1 204 No Content +Content-Location: /qqmlxmlhttprequest.cpp +ETag: "ETagNumber" diff --git a/tests/auto/qml/qqmlxmlhttprequest/tst_qqmlxmlhttprequest.cpp b/tests/auto/qml/qqmlxmlhttprequest/tst_qqmlxmlhttprequest.cpp index 425e12677f..1ce07ecdab 100644 --- a/tests/auto/qml/qqmlxmlhttprequest/tst_qqmlxmlhttprequest.cpp +++ b/tests/auto/qml/qqmlxmlhttprequest/tst_qqmlxmlhttprequest.cpp @@ -71,6 +71,7 @@ private slots: void send_withdata_data(); void send_options(); void send_options_data(); + void send_patch(); void abort(); void abort_unsent(); void abort_opened(); @@ -639,6 +640,26 @@ void tst_qqmlxmlhttprequest::send_options_data() QTest::newRow("OPTIONS (with data)") << "testdocument.html" << "send_data.10.expect" << "send_data.9.qml" << "send_data.2.reply"; } +void tst_qqmlxmlhttprequest::send_patch() +{ + TestHTTPServer server; + QVERIFY2(server.listen(), qPrintable(server.errorString())); + QVERIFY(server.wait(testFileUrl("send_patch.expect"), + testFileUrl("send_patch.reply"), + // the content of response file will be ignored due to 204 status code + testFileUrl("testdocument.html"))); + + QQmlComponent component(&engine, testFileUrl("send_patch.qml")); + QScopedPointer<QObject> object(component.beginCreate(engine.rootContext())); + QVERIFY(!object.isNull()); + object->setProperty("url", server.urlString("/qqmlxmlhttprequest.cpp")); + component.completeCreate(); + + QTRY_VERIFY(object->property("dataOK").toBool()); + QTRY_VERIFY(object->property("headerOK").toBool()); +} + + // Test abort() has no effect in unsent state void tst_qqmlxmlhttprequest::abort_unsent() { diff --git a/tests/auto/qml/qquickfolderlistmodel/tst_qquickfolderlistmodel.cpp b/tests/auto/qml/qquickfolderlistmodel/tst_qquickfolderlistmodel.cpp index f3ba3e8971..f19e82032a 100644 --- a/tests/auto/qml/qquickfolderlistmodel/tst_qquickfolderlistmodel.cpp +++ b/tests/auto/qml/qquickfolderlistmodel/tst_qquickfolderlistmodel.cpp @@ -56,6 +56,7 @@ public slots: } private slots: + void initTestCase(); void basicProperties(); void showFiles(); void resetFiltering(); @@ -97,6 +98,15 @@ void tst_qquickfolderlistmodel::checkNoErrors(const QQmlComponent& component) QVERIFY(!component.isError()); } +void tst_qquickfolderlistmodel::initTestCase() +{ + // The tests rely on a fixed number of files in the directory with the qml files + // (the data dir), so disable the disk cache to avoid creating .qmlc files and + // confusing the test. + qputenv("QML_DISABLE_DISK_CACHE", "1"); + QQmlDataTest::initTestCase(); +} + void tst_qquickfolderlistmodel::basicProperties() { QQmlComponent component(&engine, testFileUrl("basic.qml")); diff --git a/tests/auto/qml/qv4mm/qv4mm.pro b/tests/auto/qml/qv4mm/qv4mm.pro new file mode 100644 index 0000000000..d9b749af4a --- /dev/null +++ b/tests/auto/qml/qv4mm/qv4mm.pro @@ -0,0 +1,8 @@ +CONFIG += testcase +TARGET = tst_qv4mm +osx:CONFIG -= app_bundle + +SOURCES += tst_qv4mm.cpp + +QT += qml qml-private testlib + diff --git a/tests/auto/qml/qv4mm/tst_qv4mm.cpp b/tests/auto/qml/qv4mm/tst_qv4mm.cpp new file mode 100644 index 0000000000..d4ba363d00 --- /dev/null +++ b/tests/auto/qml/qv4mm/tst_qv4mm.cpp @@ -0,0 +1,58 @@ +/**************************************************************************** +** +** Copyright (C) 2016 basysKom GmbH. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the test suite of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:GPL-EXCEPT$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 as published by the Free Software +** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include <qtest.h> +#include <QQmlEngine> +#include <private/qv4mm_p.h> + +class tst_qv4mm : public QObject +{ + Q_OBJECT + +private slots: + void gcStats(); + void tweaks(); +}; + +void tst_qv4mm::gcStats() +{ + qputenv(QV4_MM_STATS, "1"); + QQmlEngine engine; + engine.collectGarbage(); +} + +void tst_qv4mm::tweaks() +{ + qputenv(QV4_MM_MAXBLOCK_SHIFT, "5"); + qputenv(QV4_MM_MAX_CHUNK_SIZE, "65536"); + QQmlEngine engine; +} + +QTEST_MAIN(tst_qv4mm) + +#include "tst_qv4mm.moc" |