diff options
Diffstat (limited to 'tests/auto/qml')
45 files changed, 1151 insertions, 186 deletions
diff --git a/tests/auto/qml/debugger/qqmldebugjs/tst_qqmldebugjs.cpp b/tests/auto/qml/debugger/qqmldebugjs/tst_qqmldebugjs.cpp index fef020704f..8763c4fa55 100644 --- a/tests/auto/qml/debugger/qqmldebugjs/tst_qqmldebugjs.cpp +++ b/tests/auto/qml/debugger/qqmldebugjs/tst_qqmldebugjs.cpp @@ -187,7 +187,7 @@ private slots: void setBreakpointInScriptOnComment(); void setBreakpointInScriptOnEmptyLine(); void setBreakpointInScriptOnOptimizedBinding(); -// void setBreakpointInScriptWithCondition(); // Not supported yet. + void setBreakpointInScriptWithCondition(); void setBreakpointInScriptThatQuits(); //void setBreakpointInFunction(); //NOT SUPPORTED // void setBreakpointOnEvent(); @@ -1082,13 +1082,8 @@ void tst_QQmlDebugJS::setBreakpointInScriptOnOptimizedBinding() QCOMPARE(QFileInfo(body.value("script").toMap().value("name").toString()).fileName(), QLatin1String(BREAKPOINTRELOCATION_QMLFILE)); } -#if 0 void tst_QQmlDebugJS::setBreakpointInScriptWithCondition() { - QFAIL("conditional breakpoints are not yet supported"); - - //void setBreakpoint(QString type, QString target, int line = -1, int column = -1, bool enabled = false, QString condition = QString(), int ignoreCount = -1) - int out = 10; int sourceLine = 50; QVERIFY(init(CONDITION_QMLFILE)); @@ -1102,23 +1097,26 @@ void tst_QQmlDebugJS::setBreakpointInScriptWithCondition() QString jsonString = client->response; QVariantMap value = client->parser.call(QJSValueList() << QJSValue(jsonString)).toVariant().toMap(); - QVariantMap body = value.value("body").toMap(); - - int frameIndex = body.value("index").toInt(); - - //Verify the value of 'result' - client->evaluate(QLatin1String("a"),frameIndex); + { + QVariantMap body = value.value("body").toMap(); + int frameIndex = body.value("index").toInt(); - QVERIFY(QQmlDebugTest::waitForSignal(client, SIGNAL(result()))); + //Verify the value of 'result' + client->evaluate(QLatin1String("a"),frameIndex); + QVERIFY(QQmlDebugTest::waitForSignal(client, SIGNAL(result()))); + } jsonString = client->response; - value = client->parser.call(QJSValueList() << QJSValue(jsonString)).toVariant().toMap(); - - body = value.value("body").toMap(); - - QVERIFY(body.value("value").toInt() > out); + QJSValue val = client->parser.call(QJSValueList() << QJSValue(jsonString)); + QVERIFY(val.isObject()); + QJSValue body = val.property(QStringLiteral("body")); + QVERIFY(body.isObject()); + val = body.property("value"); + QVERIFY(val.isNumber()); + + const int a = val.toInt(); + QVERIFY(a > out); } -#endif void tst_QQmlDebugJS::setBreakpointInScriptThatQuits() { diff --git a/tests/auto/qml/debugger/qqmlprofilerservice/tst_qqmlprofilerservice.cpp b/tests/auto/qml/debugger/qqmlprofilerservice/tst_qqmlprofilerservice.cpp index b544427c08..935b9d4120 100644 --- a/tests/auto/qml/debugger/qqmlprofilerservice/tst_qqmlprofilerservice.cpp +++ b/tests/auto/qml/debugger/qqmlprofilerservice/tst_qqmlprofilerservice.cpp @@ -61,6 +61,7 @@ struct QQmlProfilerData int column; //used by RangeLocation int framerate; //used by animation events int animationcount; //used by animation events + qint64 amount; //used by heap events QByteArray toByteArray() const; }; @@ -79,6 +80,7 @@ public: Complete, // end of transmission PixmapCacheEvent, SceneGraphFrame, + MemoryAllocation, MaximumMessage }; @@ -131,6 +133,12 @@ public: MaximumSceneGraphFrameType }; + enum MemoryType { + HeapPage, + LargeItem, + SmallItem + }; + QQmlProfilerClient(QQmlDebugConnection *connection) : QQmlDebugClient(QLatin1String("CanvasFrameRate"), connection) { @@ -138,6 +146,7 @@ public: QList<QQmlProfilerData> qmlMessages; QList<QQmlProfilerData> javascriptMessages; + QList<QQmlProfilerData> jsHeapMessages; QList<QQmlProfilerData> asynchronousMessages; QList<QQmlProfilerData> pixmapMessages; @@ -175,6 +184,7 @@ private: void connect(bool block, const QString &testFile); void checkTraceReceived(); + void checkJsHeap(); private slots: void cleanup(); @@ -303,6 +313,11 @@ void QQmlProfilerClient::messageReceived(const QByteArray &message) } break; } + case QQmlProfilerClient::MemoryAllocation: { + stream >> data.detailType; + stream >> data.amount; + break; + } default: QString failMsg = QString("Unknown message type:") + data.messageType; QFAIL(qPrintable(failMsg)); @@ -314,6 +329,8 @@ void QQmlProfilerClient::messageReceived(const QByteArray &message) else if (data.messageType == QQmlProfilerClient::SceneGraphFrame || data.messageType == QQmlProfilerClient::Event) asynchronousMessages.append(data); + else if (data.messageType == QQmlProfilerClient::MemoryAllocation) + jsHeapMessages.append(data); else if (data.detailType == QQmlProfilerClient::Javascript) javascriptMessages.append(data); else @@ -357,6 +374,48 @@ void tst_QQmlProfilerService::checkTraceReceived() QCOMPARE(m_client->asynchronousMessages.last().detailType, (int)QQmlProfilerClient::EndTrace); } +void tst_QQmlProfilerService::checkJsHeap() +{ + QVERIFY2(m_client->jsHeapMessages.count() > 0, "no JavaScript heap messages received"); + + bool seen_alloc = false; + bool seen_small = false; + bool seen_large = false; + qint64 allocated = 0; + qint64 used = 0; + foreach (const QQmlProfilerData &message, m_client->jsHeapMessages) { + switch (message.detailType) { + case QQmlProfilerClient::HeapPage: + allocated += message.amount; + seen_alloc = true; + break; + case QQmlProfilerClient::SmallItem: + used += message.amount; + seen_small = true; + break; + case QQmlProfilerClient::LargeItem: + allocated += message.amount; + used += message.amount; + seen_large = true; + break; + } + + QVERIFY2(used >= 0, QString::fromLatin1("Negative memory usage seen: %1") + .arg(used).toUtf8().constData()); + + QVERIFY2(allocated >= 0, QString::fromLatin1("Negative memory allocation seen: %1") + .arg(allocated).toUtf8().constData()); + + QVERIFY2(used <= allocated, + QString::fromLatin1("More memory usage than allocation seen: %1 > %2") + .arg(used).arg(allocated).toUtf8().constData()); + } + + QVERIFY2(seen_alloc, "No heap allocation seen"); + QVERIFY2(seen_small, "No small item seen"); + QVERIFY2(seen_large, "No large item seen"); +} + void tst_QQmlProfilerService::cleanup() { if (QTest::currentTestFailed()) { @@ -388,6 +447,12 @@ void tst_QQmlProfilerService::cleanup() << data.line << data.column; } qDebug() << " "; + qDebug() << "Javascript Heap Messages:" << m_client->jsHeapMessages.count(); + i = 0; + foreach (const QQmlProfilerData &data, m_client->jsHeapMessages) { + qDebug() << i++ << data.time << data.messageType << data.detailType; + } + qDebug() << " "; qDebug() << "Process State:" << (m_process ? m_process->state() : QLatin1String("null")); qDebug() << "Application Output:" << (m_process ? m_process->output() : QLatin1String("null")); qDebug() << "Connection State:" << (m_connection ? m_connection->stateString() : QLatin1String("null")); @@ -410,6 +475,7 @@ void tst_QQmlProfilerService::blockingConnectWithTraceEnabled() m_client->setTraceState(true); m_client->setTraceState(false); checkTraceReceived(); + checkJsHeap(); } void tst_QQmlProfilerService::blockingConnectWithTraceDisabled() @@ -422,6 +488,7 @@ void tst_QQmlProfilerService::blockingConnectWithTraceDisabled() m_client->setTraceState(true); m_client->setTraceState(false); checkTraceReceived(); + checkJsHeap(); } void tst_QQmlProfilerService::nonBlockingConnect() @@ -433,6 +500,7 @@ void tst_QQmlProfilerService::nonBlockingConnect() m_client->setTraceState(true); m_client->setTraceState(false); checkTraceReceived(); + checkJsHeap(); } void tst_QQmlProfilerService::pixmapCacheData() @@ -451,6 +519,7 @@ void tst_QQmlProfilerService::pixmapCacheData() m_client->setTraceState(false); checkTraceReceived(); + checkJsHeap(); QVERIFY2(m_client->pixmapMessages.count() >= 4, QString::number(m_client->pixmapMessages.count()).toUtf8().constData()); @@ -487,6 +556,7 @@ void tst_QQmlProfilerService::scenegraphData() m_client->setTraceState(false); checkTraceReceived(); + checkJsHeap(); // check that at least one frame was rendered // there should be a SGPolishAndSync + SGRendererFrame + SGRenderLoopFrame sequence @@ -516,6 +586,7 @@ void tst_QQmlProfilerService::profileOnExit() m_client->setTraceState(true); checkTraceReceived(); + checkJsHeap(); } void tst_QQmlProfilerService::controlFromJS() @@ -526,6 +597,7 @@ void tst_QQmlProfilerService::controlFromJS() m_client->setTraceState(false); checkTraceReceived(); + checkJsHeap(); } void tst_QQmlProfilerService::signalSourceLocation() @@ -539,6 +611,7 @@ void tst_QQmlProfilerService::signalSourceLocation() QVERIFY(QQmlDebugTest::waitForSignal(m_process, SIGNAL(readyReadStandardOutput()))); m_client->setTraceState(false); checkTraceReceived(); + checkJsHeap(); QVERIFY2(m_client->qmlMessages.count() >= 16, QString::number(m_client->qmlMessages.count()).toUtf8().constData()); @@ -569,6 +642,7 @@ void tst_QQmlProfilerService::javascript() QVERIFY(QQmlDebugTest::waitForSignal(m_process, SIGNAL(readyReadStandardOutput()))); m_client->setTraceState(false); checkTraceReceived(); + checkJsHeap(); QVERIFY2(m_client->javascriptMessages.count() >= 22, QString::number(m_client->javascriptMessages.count()).toUtf8().constData()); diff --git a/tests/auto/qml/debugger/shared/qqmlenginedebugclient.cpp b/tests/auto/qml/debugger/shared/qqmlenginedebugclient.cpp index 610d80d559..022ba8c440 100644 --- a/tests/auto/qml/debugger/shared/qqmlenginedebugclient.cpp +++ b/tests/auto/qml/debugger/shared/qqmlenginedebugclient.cpp @@ -84,7 +84,8 @@ QQmlEngineDebugClient::QQmlEngineDebugClient( QQmlDebugConnection *connection) : QQmlDebugClient(QLatin1String("QmlDebugger"), connection), m_nextId(0), - m_valid(false) + m_valid(false), + m_connection(connection) { } @@ -467,6 +468,9 @@ void QQmlEngineDebugClient::messageReceived(const QByteArray &data) { m_valid = false; QDataStream ds(data); + ds.setVersion(m_connection->dataStreamVersion()); + + int queryId; QByteArray type; ds >> type >> queryId; diff --git a/tests/auto/qml/debugger/shared/qqmlenginedebugclient.h b/tests/auto/qml/debugger/shared/qqmlenginedebugclient.h index 1d4b95a9e3..2712692389 100644 --- a/tests/auto/qml/debugger/shared/qqmlenginedebugclient.h +++ b/tests/auto/qml/debugger/shared/qqmlenginedebugclient.h @@ -242,6 +242,8 @@ private: QmlDebugObjectReference m_object; QList<QmlDebugObjectReference> m_objects; QVariant m_exprResult; + + QQmlDebugConnection *m_connection; }; #endif // QQMLENGINEDEBUGCLIENT_H diff --git a/tests/auto/qml/qjsengine/idtranslatable-unicode.js b/tests/auto/qml/qjsengine/idtranslatable-unicode.js new file mode 100644 index 0000000000..e17d6172bc --- /dev/null +++ b/tests/auto/qml/qjsengine/idtranslatable-unicode.js @@ -0,0 +1,5 @@ +qsTrId('\u01F8\u01D2\u0199\u01D0\u01E1'); + +QT_TRID_NOOP("\u0191\u01CE\u0211\u0229\u019C\u018E\u019A\u01D0"); + +qsTrId("\u0181\u01A1\u0213\u018F\u018C", 10); diff --git a/tests/auto/qml/qjsengine/idtranslatable.js b/tests/auto/qml/qjsengine/idtranslatable.js new file mode 100644 index 0000000000..554ca88d41 --- /dev/null +++ b/tests/auto/qml/qjsengine/idtranslatable.js @@ -0,0 +1,5 @@ +qsTrId("qtn_foo_bar"); + +var more_greeting_strings = [ QT_TRID_NOOP("qtn_needle"), QT_TRID_NOOP("qtn_haystack") ]; + +qsTrId("qtn_bar_baz", 10); diff --git a/tests/auto/qml/qjsengine/qjsengine.pro b/tests/auto/qml/qjsengine/qjsengine.pro index a62eb75c21..fc2452c2bc 100644 --- a/tests/auto/qml/qjsengine/qjsengine.pro +++ b/tests/auto/qml/qjsengine/qjsengine.pro @@ -4,6 +4,7 @@ TARGET = tst_qjsengine QT += qml qml-private widgets testlib gui-private macx:CONFIG -= app_bundle SOURCES += tst_qjsengine.cpp +RESOURCES += qjsengine.qrc TESTDATA = script/* DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0 diff --git a/tests/auto/qml/qjsengine/qjsengine.qrc b/tests/auto/qml/qjsengine/qjsengine.qrc new file mode 100644 index 0000000000..d05d115966 --- /dev/null +++ b/tests/auto/qml/qjsengine/qjsengine.qrc @@ -0,0 +1,8 @@ +<!DOCTYPE RCC><RCC version="1.0"> +<qresource> + <file>translations/translatable_la.qm</file> + <file>translations/idtranslatable_la.qm</file> + <file>translations/translatable-unicode.qm</file> + <file>translations/idtranslatable-unicode.qm</file> +</qresource> +</RCC> diff --git a/tests/auto/qml/qjsengine/translatable-unicode.js b/tests/auto/qml/qjsengine/translatable-unicode.js new file mode 100644 index 0000000000..afe2aff21c --- /dev/null +++ b/tests/auto/qml/qjsengine/translatable-unicode.js @@ -0,0 +1,9 @@ +qsTr("H\u2082O"); +qsTranslate("\u010C\u0101\u011F\u0115", "CO\u2082"); + +var unicode_strings = [ + QT_TR_NOOP("\u0391\u0392\u0393"), + QT_TRANSLATE_NOOP("\u010C\u0101\u011F\u0115", "\u0414\u0415\u0416") +]; + +qsTr("H\u2082O", "not the same H\u2082O"); diff --git a/tests/auto/qml/qjsengine/translatable.js b/tests/auto/qml/qjsengine/translatable.js new file mode 100644 index 0000000000..5d6ad9b3b6 --- /dev/null +++ b/tests/auto/qml/qjsengine/translatable.js @@ -0,0 +1,12 @@ +qsTr("One"); +qsTranslate("FooContext", "Two"); + +var greeting_strings = [ + QT_TR_NOOP("Hello"), + QT_TRANSLATE_NOOP("FooContext", "Goodbye") +]; + +qsTr("One", "not the same one"); + +qsTr("%n message(s) saved", "", 10); +qsTranslate("FooContext", "%n fooish bar(s) found", "", 10); diff --git a/tests/auto/qml/qjsengine/translatable2.js b/tests/auto/qml/qjsengine/translatable2.js new file mode 100644 index 0000000000..eee66f17c1 --- /dev/null +++ b/tests/auto/qml/qjsengine/translatable2.js @@ -0,0 +1,9 @@ +qsTr("Three"); +qsTranslate("BarContext", "Four"); + +var celebration_strings = [ + QT_TR_NOOP("Happy birthday!"), + QT_TRANSLATE_NOOP("BarContext", "Congratulations!") +]; + +qsTr("Three", "not the same three"); diff --git a/tests/auto/qml/qjsengine/translations/idtranslatable-unicode.qm b/tests/auto/qml/qjsengine/translations/idtranslatable-unicode.qm Binary files differnew file mode 100644 index 0000000000..8c5fb91b1d --- /dev/null +++ b/tests/auto/qml/qjsengine/translations/idtranslatable-unicode.qm diff --git a/tests/auto/qml/qjsengine/translations/idtranslatable-unicode.ts b/tests/auto/qml/qjsengine/translations/idtranslatable-unicode.ts new file mode 100644 index 0000000000..74ebf43c47 --- /dev/null +++ b/tests/auto/qml/qjsengine/translations/idtranslatable-unicode.ts @@ -0,0 +1,26 @@ +<?xml version="1.0" encoding="utf-8"?> +<!DOCTYPE TS> +<TS version="2.0" language="nb_NO"> +<defaultcodec>UTF-8</defaultcodec> +<context> + <name></name> + <message id="Ǹǒƙǐǡ"> + <location filename="idtranslatable-unicode.js" line="1"/> + <source></source> + <translation>Ƨưƈȼȝȿș</translation> + </message> + <message id="ƑǎȑȩƜƎƚǐ"> + <location filename="idtranslatable-unicode.js" line="3"/> + <source></source> + <translation>Ǡȡȋȅȕ</translation> + </message> + <message id="ƁơȓƏƌ" numerus="yes"> + <location filename="idtranslatable-unicode.js" line="5"/> + <source></source> + <translation> + <numerusform>Ƒưǹ</numerusform> + <numerusform>%n ƒơǒ(ș)</numerusform> + </translation> + </message> +</context> +</TS> diff --git a/tests/auto/qml/qjsengine/translations/idtranslatable_la.qm b/tests/auto/qml/qjsengine/translations/idtranslatable_la.qm Binary files differnew file mode 100644 index 0000000000..c8c0b72acb --- /dev/null +++ b/tests/auto/qml/qjsengine/translations/idtranslatable_la.qm diff --git a/tests/auto/qml/qjsengine/translations/idtranslatable_la.ts b/tests/auto/qml/qjsengine/translations/idtranslatable_la.ts new file mode 100644 index 0000000000..b6d7053024 --- /dev/null +++ b/tests/auto/qml/qjsengine/translations/idtranslatable_la.ts @@ -0,0 +1,30 @@ +<?xml version="1.0" encoding="utf-8"?> +<!DOCTYPE TS> +<TS version="2.0" language="nb_NO"> +<context> + <name></name> + <message id="qtn_foo_bar"> + <location filename="idtranslatable.js" line="1"/> + <source></source> + <translation>First string</translation> + </message> + <message id="qtn_needle"> + <location filename="idtranslatable.js" line="3"/> + <source></source> + <translation>Second string</translation> + </message> + <message id="qtn_haystack"> + <location filename="idtranslatable.js" line="3"/> + <source></source> + <translation>Third string</translation> + </message> + <message id="qtn_bar_baz" numerus="yes"> + <location filename="idtranslatable.js" line="5"/> + <source></source> + <translation> + <numerusform>Fourth string</numerusform> + <numerusform>%n fooish bar(s) found</numerusform> + </translation> + </message> +</context> +</TS> diff --git a/tests/auto/qml/qjsengine/translations/translatable-unicode.qm b/tests/auto/qml/qjsengine/translations/translatable-unicode.qm Binary files differnew file mode 100644 index 0000000000..aa75ce61df --- /dev/null +++ b/tests/auto/qml/qjsengine/translations/translatable-unicode.qm diff --git a/tests/auto/qml/qjsengine/translations/translatable-unicode.ts b/tests/auto/qml/qjsengine/translations/translatable-unicode.ts new file mode 100644 index 0000000000..1b8b4d2309 --- /dev/null +++ b/tests/auto/qml/qjsengine/translations/translatable-unicode.ts @@ -0,0 +1,37 @@ +<?xml version="1.0" encoding="utf-8"?> +<!DOCTYPE TS> +<TS version="2.0"> +<defaultcodec>UTF-8</defaultcodec> +<context> + <name>translatable-unicode</name> + <message> + <location filename="translatable-unicode.js" line="1"/> + <source>H₂O</source> + <translation>ͻͼͽ</translation> + </message> + <message> + <location filename="translatable-unicode.js" line="5"/> + <source>ΑΒΓ</source> + <translation>ӜҴѼ</translation> + </message> + <message> + <location filename="translatable-unicode.js" line="9"/> + <source>H₂O</source> + <comment>not the same H₂O</comment> + <translation>ԶՊՒ</translation> + </message> +</context> +<context> + <name>Čāğĕ</name> + <message> + <location filename="translatable-unicode.js" line="2"/> + <source>CO₂</source> + <translation>בךע</translation> + </message> + <message> + <location filename="translatable-unicode.js" line="6"/> + <source>ДЕЖ</source> + <translation>خسس</translation> + </message> +</context> +</TS> diff --git a/tests/auto/qml/qjsengine/translations/translatable_la.qm b/tests/auto/qml/qjsengine/translations/translatable_la.qm Binary files differnew file mode 100644 index 0000000000..d76b1cad5f --- /dev/null +++ b/tests/auto/qml/qjsengine/translations/translatable_la.qm diff --git a/tests/auto/qml/qjsengine/translations/translatable_la.ts b/tests/auto/qml/qjsengine/translations/translatable_la.ts new file mode 100644 index 0000000000..36271c9cbe --- /dev/null +++ b/tests/auto/qml/qjsengine/translations/translatable_la.ts @@ -0,0 +1,88 @@ +<?xml version="1.0" encoding="utf-8"?> +<!DOCTYPE TS> +<TS version="2.0" language="nb_NO"> +<context> + <name>BarContext</name> + <message> + <location filename="translatable2.js" line="2"/> + <source>Four</source> + <translation>Fire</translation> + </message> + <message> + <location filename="translatable2.js" line="6"/> + <source>Congratulations!</source> + <translation>Gratulerer!</translation> + </message> +</context> +<context> + <name>FooContext</name> + <message> + <location filename="translatable.js" line="2"/> + <source>Two</source> + <translation>To</translation> + </message> + <message> + <location filename="translatable.js" line="6"/> + <source>Goodbye</source> + <translation>Farvel</translation> + </message> + <message numerus="yes"> + <location filename="translatable.js" line="12"/> + <source>%n fooish bar(s) found</source> + <translation> + <numerusform>%n fooaktig bar funnet</numerusform> + <numerusform>%n fooaktige barer funnet</numerusform> + </translation> + </message> +</context> +<context> + <name>translatable</name> + <message> + <location filename="translatable.js" line="1"/> + <source>One</source> + <translation>En</translation> + </message> + <message> + <location filename="translatable.js" line="5"/> + <source>Hello</source> + <translation>Hallo</translation> + </message> + <message> + <location filename="translatable.js" line="9"/> + <source>One</source> + <comment>not the same one</comment> + <translation>Enda en</translation> + </message> + <message numerus="yes"> + <location filename="translatable.js" line="11"/> + <source>%n message(s) saved</source> + <translation> + <numerusform>%n melding lagret</numerusform> + <numerusform>%n meldinger lagret</numerusform> + </translation> + </message> + <message> + <source>Goodbye</source> + <translation type="obsolete">Farvel</translation> + </message> +</context> +<context> + <name>translatable2</name> + <message> + <location filename="translatable2.js" line="1"/> + <source>Three</source> + <translation>Tre</translation> + </message> + <message> + <location filename="translatable2.js" line="5"/> + <source>Happy birthday!</source> + <translation>Gratulerer med dagen!</translation> + </message> + <message> + <location filename="translatable2.js" line="9"/> + <source>Three</source> + <comment>not the same three</comment> + <translation>Tre andre</translation> + </message> +</context> +</TS> diff --git a/tests/auto/qml/qjsengine/tst_qjsengine.cpp b/tests/auto/qml/qjsengine/tst_qjsengine.cpp index 51cd69998a..8a1bedb600 100644 --- a/tests/auto/qml/qjsengine/tst_qjsengine.cpp +++ b/tests/auto/qml/qjsengine/tst_qjsengine.cpp @@ -159,6 +159,27 @@ private slots: void scopeOfEvaluate(); + void callConstants(); + + void installTranslatorFunctions(); + void translateScript_data(); + void translateScript(); + void translateScript_crossScript(); + void translateScript_trNoOp(); + void translateScript_callQsTrFromCpp(); + void translateWithInvalidArgs_data(); + void translateWithInvalidArgs(); + void translationContext_data(); + void translationContext(); + void translateScriptIdBased(); + void translateScriptUnicode_data(); + void translateScriptUnicode(); + void translateScriptUnicodeIdBased_data(); + void translateScriptUnicodeIdBased(); + void translateFromBuiltinCallback(); + + void privateMethods(); + signals: void testSignal(); }; @@ -3099,6 +3120,471 @@ void tst_QJSEngine::scopeOfEvaluate() QCOMPARE(result.toInt(), 42); } +void tst_QJSEngine::callConstants() +{ + QJSEngine engine; + engine.evaluate("function f() {\n" + " var one; one();\n" + " var two = null; two();\n" + "}\n"); +} + +void tst_QJSEngine::installTranslatorFunctions() +{ + QJSEngine eng; + QJSValue global = eng.globalObject(); + QVERIFY(global.property("qsTranslate").isUndefined()); + QVERIFY(global.property("QT_TRANSLATE_NOOP").isUndefined()); + QVERIFY(global.property("qsTr").isUndefined()); + QVERIFY(global.property("QT_TR_NOOP").isUndefined()); + QVERIFY(global.property("qsTrId").isUndefined()); + QVERIFY(global.property("QT_TRID_NOOP").isUndefined()); + + eng.installTranslatorFunctions(); + QVERIFY(global.property("qsTranslate").isCallable()); + QVERIFY(global.property("QT_TRANSLATE_NOOP").isCallable()); + QVERIFY(global.property("qsTr").isCallable()); + QVERIFY(global.property("QT_TR_NOOP").isCallable()); + QVERIFY(global.property("qsTrId").isCallable()); + QVERIFY(global.property("QT_TRID_NOOP").isCallable()); + + { + QJSValue ret = eng.evaluate("qsTr('foo')"); + QVERIFY(ret.isString()); + QCOMPARE(ret.toString(), QString::fromLatin1("foo")); + } + { + QJSValue ret = eng.evaluate("qsTranslate('foo', 'bar')"); + QVERIFY(ret.isString()); + QCOMPARE(ret.toString(), QString::fromLatin1("bar")); + } + { + QJSValue ret = eng.evaluate("QT_TR_NOOP('foo')"); + QVERIFY(ret.isString()); + QCOMPARE(ret.toString(), QString::fromLatin1("foo")); + } + { + QJSValue ret = eng.evaluate("QT_TRANSLATE_NOOP('foo', 'bar')"); + QVERIFY(ret.isString()); + QCOMPARE(ret.toString(), QString::fromLatin1("bar")); + } + + { + QJSValue ret = eng.evaluate("qsTrId('foo')"); + QVERIFY(ret.isString()); + QCOMPARE(ret.toString(), QString::fromLatin1("foo")); + } + { + QJSValue ret = eng.evaluate("QT_TRID_NOOP('foo')"); + QVERIFY(ret.isString()); + QCOMPARE(ret.toString(), QString::fromLatin1("foo")); + } + QVERIFY(eng.evaluate("QT_TRID_NOOP()").isUndefined()); +} + +class TranslationScope +{ +public: + TranslationScope(const QString &fileName) + { + translator.load(fileName); + QCoreApplication::instance()->installTranslator(&translator); + } + ~TranslationScope() + { + QCoreApplication::instance()->removeTranslator(&translator); + } + +private: + QTranslator translator; +}; + +void tst_QJSEngine::translateScript_data() +{ + QTest::addColumn<QString>("expression"); + QTest::addColumn<QString>("fileName"); + QTest::addColumn<QString>("expectedTranslation"); + + QString fileName = QString::fromLatin1("translatable.js"); + // Top-level + QTest::newRow("qsTr('One')@translatable.js") + << QString::fromLatin1("qsTr('One')") << fileName << QString::fromLatin1("En"); + QTest::newRow("qsTr('Hello')@translatable.js") + << QString::fromLatin1("qsTr('Hello')") << fileName << QString::fromLatin1("Hallo"); + // From function + QTest::newRow("(function() { return qsTr('One'); })()@translatable.js") + << QString::fromLatin1("(function() { return qsTr('One'); })()") << fileName << QString::fromLatin1("En"); + QTest::newRow("(function() { return qsTr('Hello'); })()@translatable.js") + << QString::fromLatin1("(function() { return qsTr('Hello'); })()") << fileName << QString::fromLatin1("Hallo"); + // Plural + QTest::newRow("qsTr('%n message(s) saved', '', 1)@translatable.js") + << QString::fromLatin1("qsTr('%n message(s) saved', '', 1)") << fileName << QString::fromLatin1("1 melding lagret"); + QTest::newRow("qsTr('%n message(s) saved', '', 3).arg@translatable.js") + << QString::fromLatin1("qsTr('%n message(s) saved', '', 3)") << fileName << QString::fromLatin1("3 meldinger lagret"); + + // Top-level + QTest::newRow("qsTranslate('FooContext', 'Two')@translatable.js") + << QString::fromLatin1("qsTranslate('FooContext', 'Two')") << fileName << QString::fromLatin1("To"); + QTest::newRow("qsTranslate('FooContext', 'Goodbye')@translatable.js") + << QString::fromLatin1("qsTranslate('FooContext', 'Goodbye')") << fileName << QString::fromLatin1("Farvel"); + // From eval + QTest::newRow("eval('qsTranslate(\\'FooContext\\', \\'Two\\')')@translatable.js") + << QString::fromLatin1("eval('qsTranslate(\\'FooContext\\', \\'Two\\')')") << fileName << QString::fromLatin1("To"); + QTest::newRow("eval('qsTranslate(\\'FooContext\\', \\'Goodbye\\')')@translatable.js") + << QString::fromLatin1("eval('qsTranslate(\\'FooContext\\', \\'Goodbye\\')')") << fileName << QString::fromLatin1("Farvel"); + + QTest::newRow("qsTranslate('FooContext', 'Goodbye', '')@translatable.js") + << QString::fromLatin1("qsTranslate('FooContext', 'Goodbye', '')") << fileName << QString::fromLatin1("Farvel"); + + QTest::newRow("qsTranslate('FooContext', 'Goodbye', '', 42)@translatable.js") + << QString::fromLatin1("qsTranslate('FooContext', 'Goodbye', '', 42)") << fileName << QString::fromLatin1("Goodbye"); + + QTest::newRow("qsTr('One', 'not the same one')@translatable.js") + << QString::fromLatin1("qsTr('One', 'not the same one')") << fileName << QString::fromLatin1("Enda en"); + + QTest::newRow("qsTr('One', 'not the same one', 42)@translatable.js") + << QString::fromLatin1("qsTr('One', 'not the same one', 42)") << fileName << QString::fromLatin1("One"); + + // Plural + QTest::newRow("qsTranslate('FooContext', '%n fooish bar(s) found', '', 1)@translatable.js") + << QString::fromLatin1("qsTranslate('FooContext', '%n fooish bar(s) found', '', 1)") << fileName << QString::fromLatin1("1 fooaktig bar funnet"); + QTest::newRow("qsTranslate('FooContext', '%n fooish bar(s) found', '', 2)@translatable.js") + << QString::fromLatin1("qsTranslate('FooContext', '%n fooish bar(s) found', '', 2)") << fileName << QString::fromLatin1("2 fooaktige barer funnet"); + + // Don't exist in translation + QTest::newRow("qsTr('Three')@translatable.js") + << QString::fromLatin1("qsTr('Three')") << fileName << QString::fromLatin1("Three"); + QTest::newRow("qsTranslate('FooContext', 'So long')@translatable.js") + << QString::fromLatin1("qsTranslate('FooContext', 'So long')") << fileName << QString::fromLatin1("So long"); + QTest::newRow("qsTranslate('BarContext', 'Goodbye')@translatable.js") + << QString::fromLatin1("qsTranslate('BarContext', 'Goodbye')") << fileName << QString::fromLatin1("Goodbye"); + + // Translate strings from the second script (translatable2.js) + + QString fileName2 = QString::fromLatin1("translatable2.js"); + QTest::newRow("qsTr('Three')@translatable2.js") + << QString::fromLatin1("qsTr('Three')") << fileName2 << QString::fromLatin1("Tre"); + QTest::newRow("qsTr('Happy birthday!')@translatable2.js") + << QString::fromLatin1("qsTr('Happy birthday!')") << fileName2 << QString::fromLatin1("Gratulerer med dagen!"); + + // Not translated because translation is only in translatable.js + QTest::newRow("qsTr('One')@translatable2.js") + << QString::fromLatin1("qsTr('One')") << fileName2 << QString::fromLatin1("One"); + QTest::newRow("(function() { return qsTr('One'); })()@translatable2.js") + << QString::fromLatin1("(function() { return qsTr('One'); })()") << fileName2 << QString::fromLatin1("One"); + + // For qsTranslate() the filename shouldn't matter + QTest::newRow("qsTranslate('FooContext', 'Two')@translatable2.js") + << QString::fromLatin1("qsTranslate('FooContext', 'Two')") << fileName2 << QString::fromLatin1("To"); + QTest::newRow("qsTranslate('BarContext', 'Congratulations!')@translatable.js") + << QString::fromLatin1("qsTranslate('BarContext', 'Congratulations!')") << fileName << QString::fromLatin1("Gratulerer!"); +} + +void tst_QJSEngine::translateScript() +{ + QFETCH(QString, expression); + QFETCH(QString, fileName); + QFETCH(QString, expectedTranslation); + + QJSEngine engine; + + TranslationScope tranScope(":/translations/translatable_la"); + engine.installTranslatorFunctions(); + + QCOMPARE(engine.evaluate(expression, fileName).toString(), expectedTranslation); +} + +void tst_QJSEngine::translateScript_crossScript() +{ + QJSEngine engine; + TranslationScope tranScope(":/translations/translatable_la"); + engine.installTranslatorFunctions(); + + QString fileName = QString::fromLatin1("translatable.js"); + QString fileName2 = QString::fromLatin1("translatable2.js"); + // qsTr() should use the innermost filename as context + engine.evaluate("function foo(s) { return bar(s); }", fileName); + engine.evaluate("function bar(s) { return qsTr(s); }", fileName2); + QCOMPARE(engine.evaluate("bar('Three')", fileName2).toString(), QString::fromLatin1("Tre")); + QCOMPARE(engine.evaluate("bar('Three')", fileName).toString(), QString::fromLatin1("Tre")); + QCOMPARE(engine.evaluate("bar('One')", fileName2).toString(), QString::fromLatin1("One")); + + engine.evaluate("function foo(s) { return bar(s); }", fileName2); + engine.evaluate("function bar(s) { return qsTr(s); }", fileName); + QCOMPARE(engine.evaluate("bar('Three')", fileName2).toString(), QString::fromLatin1("Three")); + QCOMPARE(engine.evaluate("bar('One')", fileName).toString(), QString::fromLatin1("En")); + QCOMPARE(engine.evaluate("bar('One')", fileName2).toString(), QString::fromLatin1("En")); +} + +void tst_QJSEngine::translateScript_trNoOp() +{ + QJSEngine engine; + TranslationScope tranScope(":/translations/translatable_la"); + engine.installTranslatorFunctions(); + + QVERIFY(engine.evaluate("QT_TR_NOOP()").isUndefined()); + QCOMPARE(engine.evaluate("QT_TR_NOOP('One')").toString(), QString::fromLatin1("One")); + + QVERIFY(engine.evaluate("QT_TRANSLATE_NOOP()").isUndefined()); + QVERIFY(engine.evaluate("QT_TRANSLATE_NOOP('FooContext')").isUndefined()); + QCOMPARE(engine.evaluate("QT_TRANSLATE_NOOP('FooContext', 'Two')").toString(), QString::fromLatin1("Two")); +} + +void tst_QJSEngine::translateScript_callQsTrFromCpp() +{ + QJSEngine engine; + TranslationScope tranScope(":/translations/translatable_la"); + engine.installTranslatorFunctions(); + + // There is no context, but it shouldn't crash + QCOMPARE(engine.globalObject().property("qsTr").call(QJSValueList() << "One").toString(), QString::fromLatin1("One")); +} + +void tst_QJSEngine::translateWithInvalidArgs_data() +{ + QTest::addColumn<QString>("expression"); + QTest::addColumn<QString>("expectedError"); + + QTest::newRow("qsTr()") << "qsTr()" << "Error: qsTr() requires at least one argument"; + QTest::newRow("qsTr(123)") << "qsTr(123)" << "Error: qsTr(): first argument (sourceText) must be a string"; + QTest::newRow("qsTr('foo', 123)") << "qsTr('foo', 123)" << "Error: qsTr(): second argument (disambiguation) must be a string"; + QTest::newRow("qsTr('foo', 'bar', 'baz')") << "qsTr('foo', 'bar', 'baz')" << "Error: qsTr(): third argument (n) must be a number"; + QTest::newRow("qsTr('foo', 'bar', true)") << "qsTr('foo', 'bar', true)" << "Error: qsTr(): third argument (n) must be a number"; + + QTest::newRow("qsTranslate()") << "qsTranslate()" << "Error: qsTranslate() requires at least two arguments"; + QTest::newRow("qsTranslate('foo')") << "qsTranslate('foo')" << "Error: qsTranslate() requires at least two arguments"; + QTest::newRow("qsTranslate(123, 'foo')") << "qsTranslate(123, 'foo')" << "Error: qsTranslate(): first argument (context) must be a string"; + QTest::newRow("qsTranslate('foo', 123)") << "qsTranslate('foo', 123)" << "Error: qsTranslate(): second argument (sourceText) must be a string"; + QTest::newRow("qsTranslate('foo', 'bar', 123)") << "qsTranslate('foo', 'bar', 123)" << "Error: qsTranslate(): third argument (disambiguation) must be a string"; + + QTest::newRow("qsTrId()") << "qsTrId()" << "Error: qsTrId() requires at least one argument"; + QTest::newRow("qsTrId(123)") << "qsTrId(123)" << "TypeError: qsTrId(): first argument (id) must be a string"; + QTest::newRow("qsTrId('foo', 'bar')") << "qsTrId('foo', 'bar')" << "TypeError: qsTrId(): second argument (n) must be a number"; +} + +void tst_QJSEngine::translateWithInvalidArgs() +{ + QFETCH(QString, expression); + QFETCH(QString, expectedError); + QJSEngine engine; + engine.installTranslatorFunctions(); + QJSValue result = engine.evaluate(expression); + QVERIFY(result.isError()); + QCOMPARE(result.toString(), expectedError); +} + +void tst_QJSEngine::translationContext_data() +{ + QTest::addColumn<QString>("path"); + QTest::addColumn<QString>("text"); + QTest::addColumn<QString>("expectedTranslation"); + + QTest::newRow("translatable.js") << "translatable.js" << "One" << "En"; + QTest::newRow("/translatable.js") << "/translatable.js" << "One" << "En"; + QTest::newRow("/foo/translatable.js") << "/foo/translatable.js" << "One" << "En"; + QTest::newRow("/foo/bar/translatable.js") << "/foo/bar/translatable.js" << "One" << "En"; + QTest::newRow("./translatable.js") << "./translatable.js" << "One" << "En"; + QTest::newRow("../translatable.js") << "../translatable.js" << "One" << "En"; + QTest::newRow("foo/translatable.js") << "foo/translatable.js" << "One" << "En"; + QTest::newRow("file:///home/qt/translatable.js") << "file:///home/qt/translatable.js" << "One" << "En"; + QTest::newRow(":/resources/translatable.js") << ":/resources/translatable.js" << "One" << "En"; + QTest::newRow("/translatable.js.foo") << "/translatable.js.foo" << "One" << "En"; + QTest::newRow("/translatable.txt") << "/translatable.txt" << "One" << "En"; + QTest::newRow("translatable") << "translatable" << "One" << "En"; + QTest::newRow("foo/translatable") << "foo/translatable" << "One" << "En"; + + QTest::newRow("translatable.js/") << "translatable.js/" << "One" << "One"; + QTest::newRow("nosuchscript.js") << "" << "One" << "One"; + QTest::newRow("(empty)") << "" << "One" << "One"; +} + +void tst_QJSEngine::translationContext() +{ + TranslationScope tranScope(":/translations/translatable_la"); + + QJSEngine engine; + engine.installTranslatorFunctions(); + + QFETCH(QString, path); + QFETCH(QString, text); + QFETCH(QString, expectedTranslation); + QJSValue ret = engine.evaluate(QString::fromLatin1("qsTr('%0')").arg(text), path); + QVERIFY(ret.isString()); + QCOMPARE(ret.toString(), expectedTranslation); +} + +void tst_QJSEngine::translateScriptIdBased() +{ + QJSEngine engine; + + TranslationScope tranScope(":/translations/idtranslatable_la"); + engine.installTranslatorFunctions(); + + QString fileName = QString::fromLatin1("idtranslatable.js"); + + QHash<QString, QString> expectedTranslations; + expectedTranslations["qtn_foo_bar"] = "First string"; + expectedTranslations["qtn_needle"] = "Second string"; + expectedTranslations["qtn_haystack"] = "Third string"; + expectedTranslations["qtn_bar_baz"] = "Fourth string"; + + QHash<QString, QString>::const_iterator it; + for (it = expectedTranslations.constBegin(); it != expectedTranslations.constEnd(); ++it) { + for (int x = 0; x < 2; ++x) { + QString fn; + if (x) + fn = fileName; + // Top-level + QCOMPARE(engine.evaluate(QString::fromLatin1("qsTrId('%0')") + .arg(it.key()), fn).toString(), + it.value()); + QCOMPARE(engine.evaluate(QString::fromLatin1("QT_TRID_NOOP('%0')") + .arg(it.key()), fn).toString(), + it.key()); + // From function + QCOMPARE(engine.evaluate(QString::fromLatin1("(function() { return qsTrId('%0'); })()") + .arg(it.key()), fn).toString(), + it.value()); + QCOMPARE(engine.evaluate(QString::fromLatin1("(function() { return QT_TRID_NOOP('%0'); })()") + .arg(it.key()), fn).toString(), + it.key()); + } + } + + // Plural form + QCOMPARE(engine.evaluate("qsTrId('qtn_bar_baz', 10)").toString(), + QString::fromLatin1("10 fooish bar(s) found")); + QCOMPARE(engine.evaluate("qsTrId('qtn_foo_bar', 10)").toString(), + QString::fromLatin1("qtn_foo_bar")); // Doesn't have plural +} + +// How to add a new test row: +// - Find a nice list of Unicode characters to choose from +// - Write source string/context/comment in .js using Unicode escape sequences (\uABCD) +// - Update corresponding .ts file (e.g. lupdate foo.js -ts foo.ts -codecfortr UTF-8) +// - Enter translation in Linguist +// - Update corresponding .qm file (e.g. lrelease foo.ts) +// - Evaluate script that performs translation; make sure the correct result is returned +// (e.g. by setting the resulting string as the text of a QLabel and visually verifying +// that it looks the same as what you entered in Linguist :-) ) +// - Generate the expectedTranslation column data using toUtf8().toHex() +void tst_QJSEngine::translateScriptUnicode_data() +{ + QTest::addColumn<QString>("expression"); + QTest::addColumn<QString>("fileName"); + QTest::addColumn<QString>("expectedTranslation"); + + QString fileName = QString::fromLatin1("translatable-unicode.js"); + QTest::newRow("qsTr('H\\u2082O')@translatable-unicode.js") + << QString::fromLatin1("qsTr('H\\u2082O')") << fileName << QString::fromUtf8("\xcd\xbb\xcd\xbc\xcd\xbd"); + QTest::newRow("qsTranslate('\\u010C\\u0101\\u011F\\u0115', 'CO\\u2082')@translatable-unicode.js") + << QString::fromLatin1("qsTranslate('\\u010C\\u0101\\u011F\\u0115', 'CO\\u2082')") << fileName << QString::fromUtf8("\xd7\x91\xd7\x9a\xd7\xa2"); + QTest::newRow("qsTr('\\u0391\\u0392\\u0393')@translatable-unicode.js") + << QString::fromLatin1("qsTr('\\u0391\\u0392\\u0393')") << fileName << QString::fromUtf8("\xd3\x9c\xd2\xb4\xd1\xbc"); + QTest::newRow("qsTranslate('\\u010C\\u0101\\u011F\\u0115', '\\u0414\\u0415\\u0416')@translatable-unicode.js") + << QString::fromLatin1("qsTranslate('\\u010C\\u0101\\u011F\\u0115', '\\u0414\\u0415\\u0416')") << fileName << QString::fromUtf8("\xd8\xae\xd8\xb3\xd8\xb3"); + QTest::newRow("qsTr('H\\u2082O', 'not the same H\\u2082O')@translatable-unicode.js") + << QString::fromLatin1("qsTr('H\\u2082O', 'not the same H\\u2082O')") << fileName << QString::fromUtf8("\xd4\xb6\xd5\x8a\xd5\x92"); + QTest::newRow("qsTr('H\\u2082O')") + << QString::fromLatin1("qsTr('H\\u2082O')") << QString() << QString::fromUtf8("\x48\xe2\x82\x82\x4f"); + QTest::newRow("qsTranslate('\\u010C\\u0101\\u011F\\u0115', 'CO\\u2082')") + << QString::fromLatin1("qsTranslate('\\u010C\\u0101\\u011F\\u0115', 'CO\\u2082')") << QString() << QString::fromUtf8("\xd7\x91\xd7\x9a\xd7\xa2"); +} + +void tst_QJSEngine::translateScriptUnicode() +{ + QFETCH(QString, expression); + QFETCH(QString, fileName); + QFETCH(QString, expectedTranslation); + + QJSEngine engine; + + TranslationScope tranScope(":/translations/translatable-unicode"); + engine.installTranslatorFunctions(); + + QCOMPARE(engine.evaluate(expression, fileName).toString(), expectedTranslation); +} + +void tst_QJSEngine::translateScriptUnicodeIdBased_data() +{ + QTest::addColumn<QString>("expression"); + QTest::addColumn<QString>("expectedTranslation"); + + QTest::newRow("qsTrId('\\u01F8\\u01D2\\u0199\\u01D0\\u01E1'')") + << QString::fromLatin1("qsTrId('\\u01F8\\u01D2\\u0199\\u01D0\\u01E1')") << QString::fromUtf8("\xc6\xa7\xc6\xb0\xc6\x88\xc8\xbc\xc8\x9d\xc8\xbf\xc8\x99"); + QTest::newRow("qsTrId('\\u0191\\u01CE\\u0211\\u0229\\u019C\\u018E\\u019A\\u01D0')") + << QString::fromLatin1("qsTrId('\\u0191\\u01CE\\u0211\\u0229\\u019C\\u018E\\u019A\\u01D0')") << QString::fromUtf8("\xc7\xa0\xc8\xa1\xc8\x8b\xc8\x85\xc8\x95"); + QTest::newRow("qsTrId('\\u0181\\u01A1\\u0213\\u018F\\u018C', 10)") + << QString::fromLatin1("qsTrId('\\u0181\\u01A1\\u0213\\u018F\\u018C', 10)") << QString::fromUtf8("\x31\x30\x20\xc6\x92\xc6\xa1\xc7\x92\x28\xc8\x99\x29"); + QTest::newRow("qsTrId('\\u0181\\u01A1\\u0213\\u018F\\u018C')") + << QString::fromLatin1("qsTrId('\\u0181\\u01A1\\u0213\\u018F\\u018C')") << QString::fromUtf8("\xc6\x91\xc6\xb0\xc7\xb9"); + QTest::newRow("qsTrId('\\u01CD\\u0180\\u01A8\\u0190\\u019E\\u01AB')") + << QString::fromLatin1("qsTrId('\\u01CD\\u0180\\u01A8\\u0190\\u019E\\u01AB')") << QString::fromUtf8("\xc7\x8d\xc6\x80\xc6\xa8\xc6\x90\xc6\x9e\xc6\xab"); +} + +void tst_QJSEngine::translateScriptUnicodeIdBased() +{ + QFETCH(QString, expression); + QFETCH(QString, expectedTranslation); + + QJSEngine engine; + + TranslationScope tranScope(":/translations/idtranslatable-unicode"); + engine.installTranslatorFunctions(); + + QCOMPARE(engine.evaluate(expression).toString(), expectedTranslation); +} + +void tst_QJSEngine::translateFromBuiltinCallback() +{ + QJSEngine eng; + eng.installTranslatorFunctions(); + + // Callback has no translation context. + eng.evaluate("function foo() { qsTr('foo'); }"); + + // Stack at translation time will be: + // qsTr, foo, forEach, global + // qsTr() needs to walk to the outer-most (global) frame before it finds + // a translation context, and this should not crash. + eng.evaluate("[10,20].forEach(foo)", "script.js"); +} + +class ObjectWithPrivateMethods : public QObject +{ + Q_OBJECT +private slots: + void myPrivateMethod() {} +}; + +void tst_QJSEngine::privateMethods() +{ + ObjectWithPrivateMethods object; + QJSEngine engine; + QJSValue jsWrapper = engine.newQObject(&object); + QQmlEngine::setObjectOwnership(&object, QQmlEngine::CppOwnership); + + QSet<QString> privateMethods; + { + const QMetaObject *mo = object.metaObject(); + for (int i = 0; i < mo->methodCount(); ++i) { + const QMetaMethod method = mo->method(i); + if (method.access() == QMetaMethod::Private) + privateMethods << QString::fromUtf8(method.name()); + } + } + + QVERIFY(privateMethods.contains("myPrivateMethod")); + QVERIFY(privateMethods.contains("_q_reregisterTimers")); + privateMethods << QStringLiteral("deleteLater") << QStringLiteral("destroyed"); + + QJSValueIterator it(jsWrapper); + while (it.hasNext()) { + it.next(); + QVERIFY(!privateMethods.contains(it.name())); + } +} + QTEST_MAIN(tst_QJSEngine) #include "tst_qjsengine.moc" diff --git a/tests/auto/qml/qqmlapplicationengine/tst_qqmlapplicationengine.cpp b/tests/auto/qml/qqmlapplicationengine/tst_qqmlapplicationengine.cpp index b261bb5191..9dcf68f50c 100644 --- a/tests/auto/qml/qqmlapplicationengine/tst_qqmlapplicationengine.cpp +++ b/tests/auto/qml/qqmlapplicationengine/tst_qqmlapplicationengine.cpp @@ -64,6 +64,7 @@ private: void tst_qqmlapplicationengine::initTestCase() { + qputenv("QT_MESSAGE_PATTERN", ""); // don't let it modify the debug output from testapp buildDir = QDir::currentPath(); QQmlDataTest::initTestCase(); //Changes current path to src dir srcDir = QDir::currentPath(); @@ -123,7 +124,7 @@ void tst_qqmlapplicationengine::application() test_stderr_target.replace('\n', QByteArray("\r\n")); #endif QCOMPARE(test_stdout, QByteArray("")); - QCOMPARE(test_stderr, test_stderr_target); + QCOMPARE(QString(test_stderr), QString(test_stderr_target)); delete testProcess; QDir::setCurrent(srcDir); #else // !QT_NO_PROCESS diff --git a/tests/auto/qml/qqmlchangeset/tst_qqmlchangeset.cpp b/tests/auto/qml/qqmlchangeset/tst_qqmlchangeset.cpp index 0f09de26d3..cfc850a9c6 100644 --- a/tests/auto/qml/qqmlchangeset/tst_qqmlchangeset.cpp +++ b/tests/auto/qml/qqmlchangeset/tst_qqmlchangeset.cpp @@ -148,7 +148,7 @@ public: return false; } if (signal.moveId != -1) { - QQmlChangeSet::Insert insert(signal.index, signal.count, signal.moveId, signal.offset); + QQmlChangeSet::Change insert(signal.index, signal.count, signal.moveId, signal.offset); for (int i = insert.start(); i < insert.end(); ++i) list.insert(i, removedValues.take(insert.moveKey(i))); } else { @@ -160,7 +160,7 @@ public: return false; } if (signal.moveId != -1) { - QQmlChangeSet::Remove remove(signal.index, signal.count, signal.moveId, signal.offset); + QQmlChangeSet::Change remove(signal.index, signal.count, signal.moveId, signal.offset); for (int i = remove.start(); i < remove.end(); ++i) removedValues.insert(remove.moveKey(i), list.at(i)); } @@ -1182,9 +1182,9 @@ void tst_qqmlchangeset::sequence() } SignalList changes; - foreach (const QQmlChangeSet::Remove &remove, set.removes()) + foreach (const QQmlChangeSet::Change &remove, set.removes()) changes << Remove(remove.index, remove.count, remove.moveId, remove.offset); - foreach (const QQmlChangeSet::Insert &insert, set.inserts()) + foreach (const QQmlChangeSet::Change &insert, set.inserts()) changes << Insert(insert.index, insert.count, insert.moveId, insert.offset); foreach (const QQmlChangeSet::Change &change, set.changes()) changes << Change(change.index, change.count); @@ -1322,15 +1322,15 @@ void tst_qqmlchangeset::apply() } SignalList changes; - foreach (const QQmlChangeSet::Remove &remove, set.removes()) + foreach (const QQmlChangeSet::Change &remove, set.removes()) changes << Remove(remove.index, remove.count, remove.moveId, remove.offset); - foreach (const QQmlChangeSet::Insert &insert, set.inserts()) + foreach (const QQmlChangeSet::Change &insert, set.inserts()) changes << Insert(insert.index, insert.count, insert.moveId, insert.offset); SignalList linearChanges; - foreach (const QQmlChangeSet::Remove &remove, linearSet.removes()) + foreach (const QQmlChangeSet::Change &remove, linearSet.removes()) linearChanges << Remove(remove.index, remove.count, remove.moveId, remove.offset); - foreach (const QQmlChangeSet::Insert &insert, linearSet.inserts()) + foreach (const QQmlChangeSet::Change &insert, linearSet.inserts()) linearChanges << Insert(insert.index, insert.count, insert.moveId, insert.offset); // The output in the failing tests isn't incorrect, merely sub-optimal. @@ -1364,17 +1364,17 @@ void tst_qqmlchangeset::removeConsecutive() QFETCH(SignalList, input); QFETCH(SignalList, output); - QVector<QQmlChangeSet::Remove> removes; + QVector<QQmlChangeSet::Change> removes; foreach (const Signal &signal, input) { QVERIFY(signal.isRemove()); - removes.append(QQmlChangeSet::Remove(signal.index, signal.count, signal.moveId, signal.offset)); + removes.append(QQmlChangeSet::Change(signal.index, signal.count, signal.moveId, signal.offset)); } QQmlChangeSet set; set.remove(removes); SignalList changes; - foreach (const QQmlChangeSet::Remove &remove, set.removes()) + foreach (const QQmlChangeSet::Change &remove, set.removes()) changes << Remove(remove.index, remove.count, remove.moveId, remove.offset); QVERIFY(set.inserts().isEmpty()); QVERIFY(set.changes().isEmpty()); @@ -1404,17 +1404,17 @@ void tst_qqmlchangeset::insertConsecutive() QFETCH(SignalList, input); QFETCH(SignalList, output); - QVector<QQmlChangeSet::Insert> inserts; + QVector<QQmlChangeSet::Change> inserts; foreach (const Signal &signal, input) { QVERIFY(signal.isInsert()); - inserts.append(QQmlChangeSet::Insert(signal.index, signal.count, signal.moveId, signal.offset)); + inserts.append(QQmlChangeSet::Change(signal.index, signal.count, signal.moveId, signal.offset)); } QQmlChangeSet set; set.insert(inserts); SignalList changes; - foreach (const QQmlChangeSet::Insert &insert, set.inserts()) + foreach (const QQmlChangeSet::Change &insert, set.inserts()) changes << Insert(insert.index, insert.count, insert.moveId, insert.offset); QVERIFY(set.removes().isEmpty()); QVERIFY(set.changes().isEmpty()); @@ -1462,12 +1462,12 @@ void tst_qqmlchangeset::debug() changeSet.insert(15, 2); changeSet.change(24, 8); - QTest::ignoreMessage(QtDebugMsg, "QQmlChangeSet(Remove(0,12) Remove(5,4) Insert(3,9) Insert(15,2) Change(24,8) )"); + QTest::ignoreMessage(QtDebugMsg, "QQmlChangeSet(Change(0,12) Change(5,4) Change(3,9) Change(15,2) Change(24,8) )"); qDebug() << changeSet; changeSet.clear(); - QTest::ignoreMessage(QtDebugMsg, "QQmlChangeSet(Remove(12,4,0,0) Insert(5,4,0,0) )"); + QTest::ignoreMessage(QtDebugMsg, "QQmlChangeSet(Change(12,4) Change(5,4) )"); changeSet.move(12, 5, 4, 0); qDebug() << changeSet; @@ -1537,9 +1537,9 @@ void tst_qqmlchangeset::random() } SignalList output; - foreach (const QQmlChangeSet::Remove &remove, accumulatedSet.removes()) + foreach (const QQmlChangeSet::Change &remove, accumulatedSet.removes()) output << Remove(remove.index, remove.count, remove.moveId, remove.offset); - foreach (const QQmlChangeSet::Insert &insert, accumulatedSet.inserts()) + foreach (const QQmlChangeSet::Change &insert, accumulatedSet.inserts()) output << Insert(insert.index, insert.count, insert.moveId, insert.offset); QVector<int> inputList; diff --git a/tests/auto/qml/qqmlcomponent/tst_qqmlcomponent.cpp b/tests/auto/qml/qqmlcomponent/tst_qqmlcomponent.cpp index dbf28a5471..d5a5f10634 100644 --- a/tests/auto/qml/qqmlcomponent/tst_qqmlcomponent.cpp +++ b/tests/auto/qml/qqmlcomponent/tst_qqmlcomponent.cpp @@ -267,8 +267,8 @@ void tst_qqmlcomponent::qmlCreateParentReference() void tst_qqmlcomponent::async() { - TestHTTPServer server(SERVER_PORT); - QVERIFY(server.isValid()); + TestHTTPServer server; + QVERIFY2(server.listen(SERVER_PORT), qPrintable(server.errorString())); server.serveDirectory(dataDirectory()); QQmlComponent component(&engine); @@ -287,8 +287,8 @@ void tst_qqmlcomponent::async() void tst_qqmlcomponent::asyncHierarchy() { - TestHTTPServer server(SERVER_PORT); - QVERIFY(server.isValid()); + TestHTTPServer server; + QVERIFY2(server.listen(SERVER_PORT), qPrintable(server.errorString())); server.serveDirectory(dataDirectory()); // ensure that the item hierarchy is compiled correctly. diff --git a/tests/auto/qml/qqmlcontext/tst_qqmlcontext.cpp b/tests/auto/qml/qqmlcontext/tst_qqmlcontext.cpp index 553663ac22..147887109f 100644 --- a/tests/auto/qml/qqmlcontext/tst_qqmlcontext.cpp +++ b/tests/auto/qml/qqmlcontext/tst_qqmlcontext.cpp @@ -348,7 +348,7 @@ void tst_qqmlcontext::setContextProperty() QQmlContext ctxt(engine.rootContext()); ctxt.setContextProperty("ctxtProp", QVariant()); - QTest::ignoreMessage(QtWarningMsg, "<Unknown File>: TypeError: Cannot read property 'a' of undefined"); + QTest::ignoreMessage(QtWarningMsg, "<Unknown File>:1: TypeError: Cannot read property 'a' of undefined"); QObject *obj = component.create(&ctxt); QVariant v = obj->property("obj"); diff --git a/tests/auto/qml/qqmlecmascript/data/assignSequenceTypes.1.qml b/tests/auto/qml/qqmlecmascript/data/assignSequenceTypes.1.qml index be283fdda1..027fdbdfcb 100644 --- a/tests/auto/qml/qqmlecmascript/data/assignSequenceTypes.1.qml +++ b/tests/auto/qml/qqmlecmascript/data/assignSequenceTypes.1.qml @@ -3,7 +3,7 @@ import Qt.test 1.0 MySequenceConversionObject { intListProperty: [1, 2] - qrealListProperty: [1.1, 2.2] + qrealListProperty: [1.1, 2.2, 3] boolListProperty: [false, true] urlListProperty: [ "http://www.example1.com", "http://www.example2.com" ] stringListProperty: [ "one", "two" ] diff --git a/tests/auto/qml/qqmlecmascript/data/assignSequenceTypes.3.qml b/tests/auto/qml/qqmlecmascript/data/assignSequenceTypes.3.qml index ad8a92e317..e486feb96c 100644 --- a/tests/auto/qml/qqmlecmascript/data/assignSequenceTypes.3.qml +++ b/tests/auto/qml/qqmlecmascript/data/assignSequenceTypes.3.qml @@ -3,7 +3,7 @@ import Qt.test 1.0 MySequenceConversionObject { intListProperty: 1 - qrealListProperty: 1.1 + qrealListProperty: 1 boolListProperty: false urlListProperty: Qt.resolvedUrl("example.html") } diff --git a/tests/auto/qml/qqmlecmascript/data/assignSequenceTypes.4.qml b/tests/auto/qml/qqmlecmascript/data/assignSequenceTypes.4.qml index a9f2e642d1..10e49af8e0 100644 --- a/tests/auto/qml/qqmlecmascript/data/assignSequenceTypes.4.qml +++ b/tests/auto/qml/qqmlecmascript/data/assignSequenceTypes.4.qml @@ -4,7 +4,7 @@ import Qt.test 1.0 MySequenceConversionObject { Component.onCompleted: { intListProperty = [1, 2] - qrealListProperty = [1.1, 2.2] + qrealListProperty = [1.1, 2.2, 3] boolListProperty = [false, true] urlListProperty = [ "http://www.example1.com", "http://www.example2.com" ] stringListProperty = [ "one", "two" ] diff --git a/tests/auto/qml/qqmlecmascript/data/assignSequenceTypes.6.qml b/tests/auto/qml/qqmlecmascript/data/assignSequenceTypes.6.qml index 7a794eb694..bc72b78af7 100644 --- a/tests/auto/qml/qqmlecmascript/data/assignSequenceTypes.6.qml +++ b/tests/auto/qml/qqmlecmascript/data/assignSequenceTypes.6.qml @@ -4,7 +4,7 @@ import Qt.test 1.0 MySequenceConversionObject { Component.onCompleted: { intListProperty = 1; - qrealListProperty = 1.1; + qrealListProperty = 1; boolListProperty = false; urlListProperty = Qt.resolvedUrl("example.html"); } diff --git a/tests/auto/qml/qqmlecmascript/data/extendedObjectPropertyLookup3.qml b/tests/auto/qml/qqmlecmascript/data/extendedObjectPropertyLookup3.qml new file mode 100644 index 0000000000..ef574f9361 --- /dev/null +++ b/tests/auto/qml/qqmlecmascript/data/extendedObjectPropertyLookup3.qml @@ -0,0 +1,13 @@ +import Qt.test 1.0 +import QtQuick 2.0 + +QtObject { + property ImplementedExtensionObject a : ImplementedExtensionObject { id: root; extendedProperty : 42 } + property int b: root.abstractProperty + property int c: root.implementedProperty + property int d: root.extendedProperty + + function getAbstractProperty() { return b; } + function getImplementedProperty() { return c; } + function getExtendedProperty() { return d; } +} diff --git a/tests/auto/qml/qqmlecmascript/data/uncreatableExtendedObjectFailureCheck.qml b/tests/auto/qml/qqmlecmascript/data/uncreatableExtendedObjectFailureCheck.qml new file mode 100644 index 0000000000..3619d8588c --- /dev/null +++ b/tests/auto/qml/qqmlecmascript/data/uncreatableExtendedObjectFailureCheck.qml @@ -0,0 +1,8 @@ +import Qt.test 1.0 +import QtQuick 2.0 + +QtObject { + property AbstractExtensionObject a; + a: AbstractExtensionObject { id: root } + property int b: Math.max(root.abstractProperty, 0) +} diff --git a/tests/auto/qml/qqmlecmascript/testtypes.cpp b/tests/auto/qml/qqmlecmascript/testtypes.cpp index 560d86005c..c4e6709958 100644 --- a/tests/auto/qml/qqmlecmascript/testtypes.cpp +++ b/tests/auto/qml/qqmlecmascript/testtypes.cpp @@ -63,6 +63,44 @@ private: int m_value; }; +class AbstractExtensionObject : public QObject +{ + Q_OBJECT + Q_PROPERTY(int abstractProperty READ abstractProperty WRITE setAbstractProperty NOTIFY abstractPropertyChanged) +public: + + AbstractExtensionObject(QObject *parent = 0) : QObject(parent), m_abstractProperty(-1) {} + + void setAbstractProperty(int abstractProperty) { m_abstractProperty = abstractProperty; emit abstractPropertyChanged(); } + int abstractProperty() const { return m_abstractProperty; } + + virtual void shouldBeImplemented() = 0; + +signals: + void abstractPropertyChanged(); + +private: + int m_abstractProperty; +}; + +class ImplementedExtensionObject : public AbstractExtensionObject +{ + Q_OBJECT + Q_PROPERTY(int implementedProperty READ implementedProperty WRITE setImplementedProperty NOTIFY implementedPropertyChanged) +public: + ImplementedExtensionObject(QObject *parent = 0) : AbstractExtensionObject(parent), m_implementedProperty(883) {} + void shouldBeImplemented() {} + + void setImplementedProperty(int implementedProperty) { m_implementedProperty = implementedProperty; emit implementedPropertyChanged(); } + int implementedProperty() const { return m_implementedProperty; } + +signals: + void implementedPropertyChanged(); + +private: + int m_implementedProperty; +}; + class ExtensionObject : public QObject { Q_OBJECT @@ -376,6 +414,9 @@ void registerTypes() qmlRegisterType<MyRevisionedClass,1>("Qt.test",1,1,"MyRevisionedClass"); qmlRegisterType<MyWorkerObject>("Qt.test", 1,0, "MyWorkerObject"); + qmlRegisterExtendedUncreatableType<AbstractExtensionObject, ExtensionObject>("Qt.test", 1,0, "AbstractExtensionObject", QStringLiteral("Abstracts are uncreatable")); + qmlRegisterType<ImplementedExtensionObject>("Qt.test", 1,0, "ImplementedExtensionObject"); + // test scarce resource property binding post-evaluation optimization // and for testing memory usage in property var circular reference test qmlRegisterType<ScarceResourceObject>("Qt.test", 1,0, "MyScarceResourceObject"); diff --git a/tests/auto/qml/qqmlecmascript/testtypes.h b/tests/auto/qml/qqmlecmascript/testtypes.h index d5a1220f23..8f9dae4d17 100644 --- a/tests/auto/qml/qqmlecmascript/testtypes.h +++ b/tests/auto/qml/qqmlecmascript/testtypes.h @@ -1135,7 +1135,7 @@ class testQObjectApi : public QObject { Q_OBJECT Q_ENUMS(MyEnum) - Q_PROPERTY (int qobjectTestProperty READ qobjectTestProperty NOTIFY qobjectTestPropertyChanged) + Q_PROPERTY (int qobjectTestProperty READ qobjectTestProperty NOTIFY qobjectTestPropertyChanged FINAL) Q_PROPERTY (int qobjectTestWritableProperty READ qobjectTestWritableProperty WRITE setQObjectTestWritableProperty NOTIFY qobjectTestWritablePropertyChanged) Q_PROPERTY (int qobjectTestWritableFinalProperty READ qobjectTestWritableFinalProperty WRITE setQObjectTestWritableFinalProperty NOTIFY qobjectTestWritableFinalPropertyChanged FINAL) diff --git a/tests/auto/qml/qqmlecmascript/tst_qqmlecmascript.cpp b/tests/auto/qml/qqmlecmascript/tst_qqmlecmascript.cpp index 34413b23de..2550dd5473 100644 --- a/tests/auto/qml/qqmlecmascript/tst_qqmlecmascript.cpp +++ b/tests/auto/qml/qqmlecmascript/tst_qqmlecmascript.cpp @@ -122,6 +122,8 @@ private slots: void selfDeletingBinding(); void extendedObjectPropertyLookup(); void extendedObjectPropertyLookup2(); + void uncreatableExtendedObjectFailureCheck(); + void extendedObjectPropertyLookup3(); void scriptErrors(); void functionErrors(); void propertyAssignmentErrors(); @@ -323,6 +325,7 @@ private slots: void importedScriptsAccessOnObjectWithInvalidContext(); void contextObjectOnLazyBindings(); void garbageCollectionDuringCreation(); + void qtbug_39520(); private: // static void propertyVarWeakRefCallback(v8::Persistent<v8::Value> object, void* parameter); @@ -1834,6 +1837,38 @@ void tst_qqmlecmascript::extendedObjectPropertyLookup2() delete object; } + +/* +Test failure when trying to create and uncreatable extended type object. + */ +void tst_qqmlecmascript::uncreatableExtendedObjectFailureCheck() +{ + QQmlComponent component(&engine, testFileUrl("uncreatableExtendedObjectFailureCheck.qml")); + + QObject *object = component.create(); + QVERIFY(object == 0); +} + +/* +Test that an subclass of an uncreatable extended object contains all the required properties. + */ +void tst_qqmlecmascript::extendedObjectPropertyLookup3() +{ + QQmlComponent component(&engine, testFileUrl("extendedObjectPropertyLookup3.qml")); + + QObject *object = component.create(); + QVERIFY(object != 0); + + QVariant returnValue; + QVERIFY(QMetaObject::invokeMethod(object, "getAbstractProperty", Q_RETURN_ARG(QVariant, returnValue))); + QCOMPARE(returnValue.toInt(), -1); + QVERIFY(QMetaObject::invokeMethod(object, "getImplementedProperty", Q_RETURN_ARG(QVariant, returnValue))); + QCOMPARE(returnValue.toInt(), 883); + QVERIFY(QMetaObject::invokeMethod(object, "getExtendedProperty", Q_RETURN_ARG(QVariant, returnValue))); + QCOMPARE(returnValue.toInt(), 42); + + delete object; +} /* Test file/lineNumbers for binding/Script errors. */ @@ -3925,7 +3960,7 @@ void tst_qqmlecmascript::verifyContextLifetime(QQmlContextData *ctxt) { Q_UNUSED(temporaryScope) } - engine->gc(); + ctxt->engine->collectGarbage(); qml = scripts->getIndexed(i); newContext = QV4::QmlContextWrapper::getContext(qml); QVERIFY(scriptContext == newContext); @@ -4172,8 +4207,8 @@ void tst_qqmlecmascript::importScripts() QFETCH(QStringList, propertyNames); QFETCH(QVariantList, propertyValues); - TestHTTPServer server(8111); - QVERIFY(server.isValid()); + TestHTTPServer server; + QVERIFY2(server.listen(8111), qPrintable(server.errorString())); server.serveDirectory(dataDirectory() + "/remote"); QStringList importPathList = engine.importPathList(); @@ -5549,7 +5584,7 @@ void tst_qqmlecmascript::assignSequenceTypes() MySequenceConversionObject *object = qobject_cast<MySequenceConversionObject *>(component.create()); QVERIFY(object != 0); QCOMPARE(object->intListProperty(), (QList<int>() << 1 << 2)); - QCOMPARE(object->qrealListProperty(), (QList<qreal>() << 1.1 << 2.2)); + QCOMPARE(object->qrealListProperty(), (QList<qreal>() << 1.1 << 2.2 << 3)); QCOMPARE(object->boolListProperty(), (QList<bool>() << false << true)); QCOMPARE(object->urlListProperty(), (QList<QUrl>() << QUrl("http://www.example1.com") << QUrl("http://www.example2.com"))); QCOMPARE(object->stringListProperty(), (QList<QString>() << QLatin1String("one") << QLatin1String("two"))); @@ -5577,7 +5612,7 @@ void tst_qqmlecmascript::assignSequenceTypes() MySequenceConversionObject *object = qobject_cast<MySequenceConversionObject *>(component.create()); QVERIFY(object != 0); QCOMPARE(object->intListProperty(), (QList<int>() << 1)); - QCOMPARE(object->qrealListProperty(), (QList<qreal>() << 1.1)); + QCOMPARE(object->qrealListProperty(), (QList<qreal>() << 1)); QCOMPARE(object->boolListProperty(), (QList<bool>() << false)); QCOMPARE(object->urlListProperty(), (QList<QUrl>() << QUrl(testFileUrl("example.html")))); delete object; @@ -5589,7 +5624,7 @@ void tst_qqmlecmascript::assignSequenceTypes() MySequenceConversionObject *object = qobject_cast<MySequenceConversionObject *>(component.create()); QVERIFY(object != 0); QCOMPARE(object->intListProperty(), (QList<int>() << 1 << 2)); - QCOMPARE(object->qrealListProperty(), (QList<qreal>() << 1.1 << 2.2)); + QCOMPARE(object->qrealListProperty(), (QList<qreal>() << 1.1 << 2.2 << 3)); QCOMPARE(object->boolListProperty(), (QList<bool>() << false << true)); QCOMPARE(object->urlListProperty(), (QList<QUrl>() << QUrl("http://www.example1.com") << QUrl("http://www.example2.com"))); QCOMPARE(object->stringListProperty(), (QList<QString>() << QLatin1String("one") << QLatin1String("two"))); @@ -5617,7 +5652,7 @@ void tst_qqmlecmascript::assignSequenceTypes() MySequenceConversionObject *object = qobject_cast<MySequenceConversionObject *>(component.create()); QVERIFY(object != 0); QCOMPARE(object->intListProperty(), (QList<int>() << 1)); - QCOMPARE(object->qrealListProperty(), (QList<qreal>() << 1.1)); + QCOMPARE(object->qrealListProperty(), (QList<qreal>() << 1)); QCOMPARE(object->boolListProperty(), (QList<bool>() << false)); QCOMPARE(object->urlListProperty(), (QList<QUrl>() << QUrl(testFileUrl("example.html")))); delete object; @@ -6000,8 +6035,8 @@ void tst_qqmlecmascript::include() // Remote - error { - TestHTTPServer server(8111); - QVERIFY(server.isValid()); + TestHTTPServer server; + QVERIFY2(server.listen(8111), qPrintable(server.errorString())); server.serveDirectory(dataDirectory()); QQmlComponent component(&engine, testFileUrl("include_remote_missing.qml")); @@ -6042,8 +6077,8 @@ void tst_qqmlecmascript::includeRemoteSuccess() #endif // Remote - success - TestHTTPServer server(8111); - QVERIFY(server.isValid()); + TestHTTPServer server; + QVERIFY2(server.listen(8111), qPrintable(server.errorString())); server.serveDirectory(dataDirectory()); QQmlComponent component(&engine, testFileUrl("include_remote.qml")); @@ -7648,6 +7683,30 @@ void tst_qqmlecmascript::garbageCollectionDuringCreation() QCOMPARE(container->dataChildren.count(), 0); } +void tst_qqmlecmascript::qtbug_39520() +{ + QQmlComponent component(&engine); + component.setData("import QtQuick 2.0\n" + "Item {\n" + " property string s\n" + " Component.onCompleted: test()\n" + " function test() {\n" + " var count = 1 * 1000 * 1000\n" + " var t = ''\n" + " for (var i = 0; i < count; ++i)\n" + " t += 'testtest ' + i + '\n'\n" + " s = t\n" + " }\n" + "}\n", + QUrl()); + + QScopedPointer<QObject> object(component.create()); + QVERIFY(!object.isNull()); + + QString s = object->property("s").toString(); + QCOMPARE(s.count('\n'), 1 * 1000 * 1000); +} + QTEST_MAIN(tst_qqmlecmascript) #include "tst_qqmlecmascript.moc" diff --git a/tests/auto/qml/qqmlengine/tst_qqmlengine.cpp b/tests/auto/qml/qqmlengine/tst_qqmlengine.cpp index 004514d39c..23c50f940b 100644 --- a/tests/auto/qml/qqmlengine/tst_qqmlengine.cpp +++ b/tests/auto/qml/qqmlengine/tst_qqmlengine.cpp @@ -488,7 +488,7 @@ void tst_qqmlengine::outputWarningsToStandardError() delete o; QCOMPARE(messageHandler.messages().count(), 1); - QCOMPARE(messageHandler.messages().at(0), QLatin1String("<Unknown File>: Unable to assign [undefined] to int")); + QCOMPARE(messageHandler.messages().at(0), QLatin1String("<Unknown File>:1:48: Unable to assign [undefined] to int")); messageHandler.clear(); engine.setOutputWarningsToStandardError(false); diff --git a/tests/auto/qml/qqmllanguage/data/customExtendedParserProperties.qml b/tests/auto/qml/qqmllanguage/data/customExtendedParserProperties.qml new file mode 100644 index 0000000000..e53a7c6bd5 --- /dev/null +++ b/tests/auto/qml/qqmllanguage/data/customExtendedParserProperties.qml @@ -0,0 +1,12 @@ +import Test 1.0 +import QtQml 2.0 +SimpleExtendedObjectWithCustomParser { + id : obj + intProperty: 42 + property string qmlString: "Hello" + property var someObject: QtObject {} + + property int c : obj.extendedProperty + + function getExtendedProperty() { return c; } +} diff --git a/tests/auto/qml/qqmllanguage/testtypes.cpp b/tests/auto/qml/qqmllanguage/testtypes.cpp index 8ffa327cf2..b37c6836eb 100644 --- a/tests/auto/qml/qqmllanguage/testtypes.cpp +++ b/tests/auto/qml/qqmllanguage/testtypes.cpp @@ -40,6 +40,8 @@ ****************************************************************************/ #include "testtypes.h" +#include <private/qqmlcompiler_p.h> + void registerTypes() { qmlRegisterInterface<MyInterface>("MyInterface"); @@ -94,6 +96,8 @@ void registerTypes() qmlRegisterCustomType<CustomBinding>("Test", 1, 0, "CustomBinding", new CustomBindingParser); qmlRegisterCustomType<SimpleObjectWithCustomParser>("Test", 1, 0, "SimpleObjectWithCustomParser", new SimpleObjectCustomParser); + qmlRegisterCustomExtendedType<SimpleObjectWithCustomParser, SimpleObjectExtension>("Test", 1, 0, "SimpleExtendedObjectWithCustomParser", new SimpleObjectCustomParser); + qmlRegisterType<RootObjectInCreationTester>("Test", 1, 0, "RootObjectInCreationTester"); } @@ -105,105 +109,70 @@ QVariant myCustomVariantTypeConverter(const QString &data) } -QByteArray CustomBindingParser::compile(const QV4::CompiledData::QmlUnit *qmlUnit, const QList<const QV4::CompiledData::Binding *> &bindings) -{ - QByteArray result; - QDataStream ds(&result, QIODevice::WriteOnly); - - ds << bindings.count(); - for (int i = 0; i < bindings.count(); ++i) { - const QV4::CompiledData::Binding *binding = bindings.at(i); - ds << qmlUnit->header.stringAt(binding->propertyNameIndex); - - Q_ASSERT(binding->type == QV4::CompiledData::Binding::Type_Script); - int bindingId = bindingIdentifier(binding); - ds << bindingId; - - ds << binding->location.line; - } - - return result; -} - -void CustomBindingParser::setCustomData(QObject *object, const QByteArray &data, QQmlCompiledData*) +void CustomBindingParser::applyBindings(QObject *object, QQmlCompiledData *cdata, const QList<const QV4::CompiledData::Binding *> &bindings) { CustomBinding *customBinding = qobject_cast<CustomBinding*>(object); Q_ASSERT(customBinding); - customBinding->m_bindingData = data; + customBinding->cdata = cdata; + customBinding->bindings = bindings; } void CustomBinding::componentComplete() { Q_ASSERT(m_target); - QDataStream ds(m_bindingData); - int count; - ds >> count; - for (int i = 0; i < count; ++i) { - QString name; - ds >> name; + foreach (const QV4::CompiledData::Binding *binding, bindings) { + QString name = cdata->compilationUnit->data->stringAt(binding->propertyNameIndex); - int bindingId; - ds >> bindingId; + int bindingId = binding->value.compiledScriptIndex; - int line; - ds >> line; + QQmlContextData *context = QQmlContextData::get(qmlContext(this)); - QQmlBinding *binding = QQmlBinding::createBinding(QQmlBinding::Identifier(bindingId), m_target, qmlContext(this)); + QV4::Scope scope(QQmlEnginePrivate::getV4Engine(qmlEngine(this))); + QV4::ScopedValue function(scope, QV4::QmlBindingWrapper::createQmlCallableForFunction(context, m_target, cdata->compilationUnit->runtimeFunctions[bindingId])); + QQmlBinding *qmlBinding = new QQmlBinding(function, m_target, context); QQmlProperty property(m_target, name, qmlContext(this)); - binding->setTarget(property); - QQmlPropertyPrivate::setBinding(property, binding); + qmlBinding->setTarget(property); + QQmlPropertyPrivate::setBinding(property, qmlBinding); } } -QByteArray EnumSupportingCustomParser::compile(const QV4::CompiledData::QmlUnit *qmlUnit, const QList<const QV4::CompiledData::Binding *> &bindings) +void EnumSupportingCustomParser::verifyBindings(const QV4::CompiledData::QmlUnit *qmlUnit, const QList<const QV4::CompiledData::Binding *> &bindings) { - Q_UNUSED(qmlUnit) - if (bindings.count() != 1) { error(bindings.first(), QStringLiteral("Custom parser invoked incorrectly for unit test")); - return QByteArray(); + return; } const QV4::CompiledData::Binding *binding = bindings.first(); if (qmlUnit->header.stringAt(binding->propertyNameIndex) != QStringLiteral("foo")) { error(binding, QStringLiteral("Custom parser invoked with the wrong property name")); - return QByteArray(); + return; } if (binding->type != QV4::CompiledData::Binding::Type_Script) { error(binding, QStringLiteral("Custom parser invoked with the wrong property value. Expected script that evaluates to enum")); - return QByteArray(); + return; } QByteArray script = qmlUnit->header.stringAt(binding->stringIndex).toUtf8(); bool ok; int v = evaluateEnum(script, &ok); if (!ok) { error(binding, QStringLiteral("Custom parser invoked with the wrong property value. Script did not evaluate to enum")); - return QByteArray(); + return; } if (v != MyEnum1Class::A_13) { error(binding, QStringLiteral("Custom parser invoked with the wrong property value. Enum value is not the expected value.")); - return QByteArray(); + return; } - - return QByteArray(); -} - - -QByteArray SimpleObjectCustomParser::compile(const QV4::CompiledData::QmlUnit *, const QList<const QV4::CompiledData::Binding *> &bindings) -{ - return QByteArray::number(bindings.count()); } -void SimpleObjectCustomParser::setCustomData(QObject *object, const QByteArray &data, QQmlCompiledData*) +void SimpleObjectCustomParser::applyBindings(QObject *object, QQmlCompiledData *, const QList<const QV4::CompiledData::Binding *> &bindings) { - SimpleObjectWithCustomParser *o = qobject_cast<SimpleObjectWithCustomParser*>(object); - Q_ASSERT(o); - bool ok = false; - o->setCustomBindingsCount(data.toInt(&ok)); - Q_ASSERT(ok); + SimpleObjectWithCustomParser *o = qobject_cast<SimpleObjectWithCustomParser*>(object); + Q_ASSERT(o); + o->setCustomBindingsCount(bindings.count()); } diff --git a/tests/auto/qml/qqmllanguage/testtypes.h b/tests/auto/qml/qqmllanguage/testtypes.h index 1c13a2e21c..bb1e9c158d 100644 --- a/tests/auto/qml/qqmllanguage/testtypes.h +++ b/tests/auto/qml/qqmllanguage/testtypes.h @@ -54,7 +54,7 @@ #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); @@ -739,15 +739,15 @@ class MyCustomParserType : public QObject class MyCustomParserTypeParser : public QQmlCustomParser { public: - QByteArray compile(const QV4::CompiledData::QmlUnit *, const QList<const QV4::CompiledData::Binding *> &) { return QByteArray(); } - void setCustomData(QObject *, const QByteArray &, QQmlCompiledData*) {} + virtual void verifyBindings(const QV4::CompiledData::QmlUnit *, const QList<const QV4::CompiledData::Binding *> &) {} + virtual void applyBindings(QObject *, QQmlCompiledData *, const QList<const QV4::CompiledData::Binding *> &) {} }; class EnumSupportingCustomParser : public QQmlCustomParser { public: - QByteArray compile(const QV4::CompiledData::QmlUnit *qmlUnit, const QList<const QV4::CompiledData::Binding *> &bindings); - void setCustomData(QObject *, const QByteArray &, QQmlCompiledData*) {} + virtual void verifyBindings(const QV4::CompiledData::QmlUnit *, const QList<const QV4::CompiledData::Binding *> &); + virtual void applyBindings(QObject *, QQmlCompiledData *, const QList<const QV4::CompiledData::Binding *> &) {} }; class MyParserStatus : public QObject, public QQmlParserStatus @@ -1112,13 +1112,15 @@ public: void setTarget(QObject *newTarget) { m_target = newTarget; } QPointer<QObject> m_target; + QQmlRefPointer<QQmlCompiledData> cdata; + QList<const QV4::CompiledData::Binding*> bindings; QByteArray m_bindingData; }; class CustomBindingParser : public QQmlCustomParser { - virtual QByteArray compile(const QV4::CompiledData::QmlUnit *qmlUnit, const QList<const QV4::CompiledData::Binding *> &bindings); - virtual void setCustomData(QObject *object, const QByteArray &data, QQmlCompiledData *); + virtual void verifyBindings(const QV4::CompiledData::QmlUnit *, const QList<const QV4::CompiledData::Binding *> &) {} + virtual void applyBindings(QObject *, QQmlCompiledData *, const QList<const QV4::CompiledData::Binding *> &); }; class SimpleObjectWithCustomParser : public QObject @@ -1142,10 +1144,29 @@ private: int m_customBindingsCount; }; +class SimpleObjectExtension : public QObject +{ + Q_OBJECT + Q_PROPERTY(int extendedProperty READ extendedProperty WRITE setExtendedProperty NOTIFY extendedPropertyChanged) +public: + SimpleObjectExtension(QObject *parent = 0) + : QObject(parent) + , m_extendedProperty(1584) + {} + + void setExtendedProperty(int extendedProperty) { m_extendedProperty = extendedProperty; emit extendedPropertyChanged(); } + int extendedProperty() const { return m_extendedProperty; } + +signals: + void extendedPropertyChanged(); +private: + int m_extendedProperty; +}; + class SimpleObjectCustomParser : public QQmlCustomParser { - virtual QByteArray compile(const QV4::CompiledData::QmlUnit *, const QList<const QV4::CompiledData::Binding *> &bindings); - virtual void setCustomData(QObject *object, const QByteArray &data, QQmlCompiledData *); + virtual void verifyBindings(const QV4::CompiledData::QmlUnit *, const QList<const QV4::CompiledData::Binding *> &) {} + virtual void applyBindings(QObject *, QQmlCompiledData *, 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 7976987b58..8bc937d2bc 100644 --- a/tests/auto/qml/qqmllanguage/tst_qqmllanguage.cpp +++ b/tests/auto/qml/qqmllanguage/tst_qqmllanguage.cpp @@ -232,6 +232,7 @@ private slots: void customParserBindingScopes(); void customParserEvaluateEnum(); void customParserProperties(); + void customParserWithExtendedObject(); void preservePropertyCacheOnGroupObjects(); void propertyCacheInSync(); @@ -2359,7 +2360,8 @@ void tst_qqmllanguage::basicRemote() QFETCH(QString, type); QFETCH(QString, error); - TestHTTPServer server(14447); + TestHTTPServer server; + QVERIFY2(server.listen(14447), qPrintable(server.errorString())); server.serveDirectory(dataDirectory()); QQmlComponent component(&engine, url); @@ -2403,7 +2405,8 @@ void tst_qqmllanguage::importsRemote() QFETCH(QString, type); QFETCH(QString, error); - TestHTTPServer server(14447); + TestHTTPServer server; + QVERIFY2(server.listen(14447), qPrintable(server.errorString())); server.serveDirectory(dataDirectory()); testType(qml,type,error); @@ -2495,7 +2498,8 @@ void tst_qqmllanguage::importsInstalledRemote() QFETCH(QString, type); QFETCH(QString, error); - TestHTTPServer server(14447); + TestHTTPServer server; + QVERIFY2(server.listen(14447), qPrintable(server.errorString())); server.serveDirectory(dataDirectory()); QString serverdir = "http://127.0.0.1:14447/lib/"; @@ -2561,7 +2565,8 @@ void tst_qqmllanguage::importsPath() QFETCH(QString, qml); QFETCH(QString, value); - TestHTTPServer server(14447); + TestHTTPServer server; + QVERIFY2(server.listen(14447), qPrintable(server.errorString())); server.serveDirectory(dataDirectory()); engine.setImportPathList(QStringList(defaultImportPathList) << importPath); @@ -3137,7 +3142,8 @@ void tst_qqmllanguage::registeredCompositeType() // QTBUG-18268 void tst_qqmllanguage::remoteLoadCrash() { - TestHTTPServer server(14448); + TestHTTPServer server; + QVERIFY2(server.listen(14448), qPrintable(server.errorString())); server.serveDirectory(dataDirectory()); QQmlComponent component(&engine); @@ -3627,7 +3633,8 @@ void tst_qqmllanguage::compositeSingletonQmlDirError() // Load a remote composite singleton type via qmldir that defines the type as a singleton void tst_qqmllanguage::compositeSingletonRemote() { - TestHTTPServer server(14447); + TestHTTPServer server; + QVERIFY2(server.listen(14447), qPrintable(server.errorString())); server.serveDirectory(dataDirectory()); QQmlComponent component(&engine, testFile("singletonTest15.qml")); @@ -3718,6 +3725,24 @@ void tst_qqmllanguage::customParserProperties() QVERIFY(!testObject->property("someObject").isNull()); } +void tst_qqmllanguage::customParserWithExtendedObject() +{ + QQmlComponent component(&engine, testFile("customExtendedParserProperties.qml")); + VERIFY_ERRORS(0); + QScopedPointer<QObject> o(component.create()); + QVERIFY(!o.isNull()); + SimpleObjectWithCustomParser *testObject = qobject_cast<SimpleObjectWithCustomParser*>(o.data()); + QVERIFY(testObject); + QCOMPARE(testObject->customBindingsCount(), 0); + QCOMPARE(testObject->intProperty(), 42); + QCOMPARE(testObject->property("qmlString").toString(), QStringLiteral("Hello")); + QVERIFY(!testObject->property("someObject").isNull()); + + QVariant returnValue; + QVERIFY(QMetaObject::invokeMethod(o.data(), "getExtendedProperty", Q_RETURN_ARG(QVariant, returnValue))); + QCOMPARE(returnValue.toInt(), 1584); +} + void tst_qqmllanguage::preservePropertyCacheOnGroupObjects() { QQmlComponent component(&engine, testFile("preservePropertyCacheOnGroupObjects.qml")); diff --git a/tests/auto/qml/qqmllistmodel/tst_qqmllistmodel.cpp b/tests/auto/qml/qqmllistmodel/tst_qqmllistmodel.cpp index b37f0e3d26..ede80b355a 100644 --- a/tests/auto/qml/qqmllistmodel/tst_qqmllistmodel.cpp +++ b/tests/auto/qml/qqmllistmodel/tst_qqmllistmodel.cpp @@ -353,12 +353,12 @@ void tst_qqmllistmodel::dynamic_i18n_data() QTest::newRow("qsTr") << QString::fromUtf8("ListElement { foo: qsTr(\"test\") }") << QVariant(QString::fromUtf8("test")) - << QString("ListElement: cannot use script for property value"); + << QString(); QTest::newRow("qsTrId") << "ListElement { foo: qsTrId(\"qtn_test\") }" << QVariant(QString("qtn_test")) - << QString("ListElement: cannot use script for property value"); + << QString(); } void tst_qqmllistmodel::dynamic_i18n() diff --git a/tests/auto/qml/qqmlmoduleplugin/tst_qqmlmoduleplugin.cpp b/tests/auto/qml/qqmlmoduleplugin/tst_qqmlmoduleplugin.cpp index 15be1fdbc0..1861b37bea 100644 --- a/tests/auto/qml/qqmlmoduleplugin/tst_qqmlmoduleplugin.cpp +++ b/tests/auto/qml/qqmlmoduleplugin/tst_qqmlmoduleplugin.cpp @@ -247,8 +247,8 @@ void tst_qqmlmoduleplugin::importPluginWithQmlFile() void tst_qqmlmoduleplugin::remoteImportWithQuotedUrl() { - TestHTTPServer server(SERVER_PORT); - QVERIFY(server.isValid()); + TestHTTPServer server; + QVERIFY2(server.listen(SERVER_PORT), qPrintable(server.errorString())); server.serveDirectory(m_dataImportsDirectory); QQmlEngine engine; @@ -268,8 +268,8 @@ void tst_qqmlmoduleplugin::remoteImportWithQuotedUrl() void tst_qqmlmoduleplugin::remoteImportWithUnquotedUri() { - TestHTTPServer server(SERVER_PORT); - QVERIFY(server.isValid()); + TestHTTPServer server; + QVERIFY2(server.listen(SERVER_PORT), qPrintable(server.errorString())); server.serveDirectory(m_dataImportsDirectory); QQmlEngine engine; diff --git a/tests/auto/qml/qqmlproperty/tst_qqmlproperty.cpp b/tests/auto/qml/qqmlproperty/tst_qqmlproperty.cpp index 27c3fd985e..fc4f7edcb8 100644 --- a/tests/auto/qml/qqmlproperty/tst_qqmlproperty.cpp +++ b/tests/auto/qml/qqmlproperty/tst_qqmlproperty.cpp @@ -46,7 +46,6 @@ #include <QtQml/private/qqmlproperty_p.h> #include <private/qqmlbinding_p.h> #include <private/qqmlboundsignal_p.h> -#include <QtWidgets/QLineEdit> #include <QtCore/qfileinfo.h> #include <QtCore/qdir.h> #include <QtCore/private/qobject_p.h> diff --git a/tests/auto/qml/qqmlpropertymap/tst_qqmlpropertymap.cpp b/tests/auto/qml/qqmlpropertymap/tst_qqmlpropertymap.cpp index b8c2ce4460..c0d66785bb 100644 --- a/tests/auto/qml/qqmlpropertymap/tst_qqmlpropertymap.cpp +++ b/tests/auto/qml/qqmlpropertymap/tst_qqmlpropertymap.cpp @@ -451,7 +451,7 @@ void tst_QQmlPropertyMap::disallowExtending() obj.reset(component.create()); QVERIFY(obj.isNull()); QCOMPARE(component.errors().count(), 1); - QCOMPARE(component.errors().at(0).toString(), QStringLiteral("<Unknown File>: Fully dynamic types cannot declare new properties.")); + QCOMPARE(component.errors().at(0).toString(), QStringLiteral("<Unknown File>:3:1: Fully dynamic types cannot declare new properties.")); } void tst_QQmlPropertyMap::QTBUG_35906() diff --git a/tests/auto/qml/qqmlxmlhttprequest/tst_qqmlxmlhttprequest.cpp b/tests/auto/qml/qqmlxmlhttprequest/tst_qqmlxmlhttprequest.cpp index 17becb3714..e1ccde2c42 100644 --- a/tests/auto/qml/qqmlxmlhttprequest/tst_qqmlxmlhttprequest.cpp +++ b/tests/auto/qml/qqmlxmlhttprequest/tst_qqmlxmlhttprequest.cpp @@ -240,13 +240,12 @@ void tst_qqmlxmlhttprequest::open() QFETCH(QString, url); QFETCH(bool, remote); - QScopedPointer<TestHTTPServer> server; // ensure deletion in case test fails + TestHTTPServer server; if (remote) { - server.reset(new TestHTTPServer(SERVER_PORT)); - QVERIFY(server->isValid()); - QVERIFY(server->wait(testFileUrl("open_network.expect"), - testFileUrl("open_network.reply"), - testFileUrl("testdocument.html"))); + QVERIFY2(server.listen(SERVER_PORT), qPrintable(server.errorString())); + QVERIFY(server.wait(testFileUrl("open_network.expect"), + testFileUrl("open_network.reply"), + testFileUrl("testdocument.html"))); } QQmlComponent component(&engine, qmlFile); @@ -322,8 +321,8 @@ void tst_qqmlxmlhttprequest::open_arg_count() // Test valid setRequestHeader() calls void tst_qqmlxmlhttprequest::setRequestHeader() { - TestHTTPServer server(SERVER_PORT); - QVERIFY(server.isValid()); + TestHTTPServer server; + QVERIFY2(server.listen(SERVER_PORT), qPrintable(server.errorString())); QVERIFY(server.wait(testFileUrl("setRequestHeader.expect"), testFileUrl("setRequestHeader.reply"), testFileUrl("testdocument.html"))); @@ -340,8 +339,8 @@ void tst_qqmlxmlhttprequest::setRequestHeader() // Test valid setRequestHeader() calls with different header cases void tst_qqmlxmlhttprequest::setRequestHeader_caseInsensitive() { - TestHTTPServer server(SERVER_PORT); - QVERIFY(server.isValid()); + TestHTTPServer server; + QVERIFY2(server.listen(SERVER_PORT), qPrintable(server.errorString())); QVERIFY(server.wait(testFileUrl("setRequestHeader.expect"), testFileUrl("setRequestHeader.reply"), testFileUrl("testdocument.html"))); @@ -397,8 +396,8 @@ void tst_qqmlxmlhttprequest::setRequestHeader_illegalName() { QFETCH(QString, name); - TestHTTPServer server(SERVER_PORT); - QVERIFY(server.isValid()); + TestHTTPServer server; + QVERIFY2(server.listen(SERVER_PORT), qPrintable(server.errorString())); QVERIFY(server.wait(testFileUrl("open_network.expect"), testFileUrl("open_network.reply"), testFileUrl("testdocument.html"))); @@ -423,8 +422,8 @@ void tst_qqmlxmlhttprequest::setRequestHeader_illegalName() // Test that attempting to set a header after a request is sent throws an exception void tst_qqmlxmlhttprequest::setRequestHeader_sent() { - TestHTTPServer server(SERVER_PORT); - QVERIFY(server.isValid()); + TestHTTPServer server; + QVERIFY2(server.listen(SERVER_PORT), qPrintable(server.errorString())); QVERIFY(server.wait(testFileUrl("open_network.expect"), testFileUrl("open_network.reply"), testFileUrl("testdocument.html"))); @@ -475,8 +474,8 @@ void tst_qqmlxmlhttprequest::send_alreadySent() void tst_qqmlxmlhttprequest::send_ignoreData() { { - TestHTTPServer server(SERVER_PORT); - QVERIFY(server.isValid()); + TestHTTPServer server; + QVERIFY2(server.listen(SERVER_PORT), qPrintable(server.errorString())); QVERIFY(server.wait(testFileUrl("send_ignoreData_GET.expect"), testFileUrl("send_ignoreData.reply"), testFileUrl("testdocument.html"))); @@ -492,8 +491,8 @@ void tst_qqmlxmlhttprequest::send_ignoreData() } { - TestHTTPServer server(SERVER_PORT); - QVERIFY(server.isValid()); + TestHTTPServer server; + QVERIFY2(server.listen(SERVER_PORT), qPrintable(server.errorString())); QVERIFY(server.wait(testFileUrl("send_ignoreData_HEAD.expect"), testFileUrl("send_ignoreData.reply"), QUrl())); @@ -509,8 +508,8 @@ void tst_qqmlxmlhttprequest::send_ignoreData() } { - TestHTTPServer server(SERVER_PORT); - QVERIFY(server.isValid()); + TestHTTPServer server; + QVERIFY2(server.listen(SERVER_PORT), qPrintable(server.errorString())); QVERIFY(server.wait(testFileUrl("send_ignoreData_DELETE.expect"), testFileUrl("send_ignoreData.reply"), QUrl())); @@ -532,8 +531,8 @@ void tst_qqmlxmlhttprequest::send_withdata() QFETCH(QString, file_expected); QFETCH(QString, file_qml); - TestHTTPServer server(SERVER_PORT); - QVERIFY(server.isValid()); + TestHTTPServer server; + QVERIFY2(server.listen(SERVER_PORT), qPrintable(server.errorString())); QVERIFY(server.wait(testFileUrl(file_expected), testFileUrl("send_data.reply"), testFileUrl("testdocument.html"))); @@ -602,8 +601,8 @@ void tst_qqmlxmlhttprequest::abort_opened() // Test abort() aborts in progress send void tst_qqmlxmlhttprequest::abort() { - TestHTTPServer server(SERVER_PORT); - QVERIFY(server.isValid()); + TestHTTPServer server; + QVERIFY2(server.listen(SERVER_PORT), qPrintable(server.errorString())); QVERIFY(server.wait(testFileUrl("abort.expect"), testFileUrl("abort.reply"), testFileUrl("testdocument.html"))); @@ -626,8 +625,8 @@ void tst_qqmlxmlhttprequest::getResponseHeader() { QQmlEngine engine; // Avoid cookie contamination - TestHTTPServer server(SERVER_PORT); - QVERIFY(server.isValid()); + TestHTTPServer server; + QVERIFY2(server.listen(SERVER_PORT), qPrintable(server.errorString())); QVERIFY(server.wait(testFileUrl("getResponseHeader.expect"), testFileUrl("getResponseHeader.reply"), testFileUrl("testdocument.html"))); @@ -693,8 +692,8 @@ void tst_qqmlxmlhttprequest::getAllResponseHeaders() { QQmlEngine engine; // Avoid cookie contamination - TestHTTPServer server(SERVER_PORT); - QVERIFY(server.isValid()); + TestHTTPServer server; + QVERIFY2(server.listen(SERVER_PORT), qPrintable(server.errorString())); QVERIFY(server.wait(testFileUrl("getResponseHeader.expect"), testFileUrl("getResponseHeader.reply"), testFileUrl("testdocument.html"))); @@ -754,8 +753,8 @@ void tst_qqmlxmlhttprequest::status() QFETCH(QUrl, replyUrl); QFETCH(int, status); - TestHTTPServer server(SERVER_PORT); - QVERIFY(server.isValid()); + TestHTTPServer server; + QVERIFY2(server.listen(SERVER_PORT), qPrintable(server.errorString())); QVERIFY(server.wait(testFileUrl("status.expect"), replyUrl, testFileUrl("testdocument.html"))); @@ -793,8 +792,8 @@ void tst_qqmlxmlhttprequest::statusText() QFETCH(QUrl, replyUrl); QFETCH(QString, statusText); - TestHTTPServer server(SERVER_PORT); - QVERIFY(server.isValid()); + TestHTTPServer server; + QVERIFY2(server.listen(SERVER_PORT), qPrintable(server.errorString())); QVERIFY(server.wait(testFileUrl("status.expect"), replyUrl, testFileUrl("testdocument.html"))); @@ -833,8 +832,8 @@ void tst_qqmlxmlhttprequest::responseText() QFETCH(QUrl, bodyUrl); QFETCH(QString, responseText); - TestHTTPServer server(SERVER_PORT); - QVERIFY(server.isValid()); + TestHTTPServer server; + QVERIFY2(server.listen(SERVER_PORT), qPrintable(server.errorString())); QVERIFY(server.wait(testFileUrl("status.expect"), replyUrl, bodyUrl)); @@ -934,8 +933,8 @@ void tst_qqmlxmlhttprequest::invalidMethodUsage() void tst_qqmlxmlhttprequest::redirects() { { - TestHTTPServer server(SERVER_PORT); - QVERIFY(server.isValid()); + TestHTTPServer server; + QVERIFY2(server.listen(SERVER_PORT), qPrintable(server.errorString())); server.addRedirect("redirect.html", "http://127.0.0.1:14445/redirecttarget.html"); server.serveDirectory(dataDirectory()); @@ -951,8 +950,8 @@ void tst_qqmlxmlhttprequest::redirects() } { - TestHTTPServer server(SERVER_PORT); - QVERIFY(server.isValid()); + TestHTTPServer server; + QVERIFY2(server.listen(SERVER_PORT), qPrintable(server.errorString())); server.addRedirect("redirect.html", "http://127.0.0.1:14445/redirectmissing.html"); server.serveDirectory(dataDirectory()); @@ -968,8 +967,8 @@ void tst_qqmlxmlhttprequest::redirects() } { - TestHTTPServer server(SERVER_PORT); - QVERIFY(server.isValid()); + TestHTTPServer server; + QVERIFY2(server.listen(SERVER_PORT), qPrintable(server.errorString())); server.addRedirect("redirect.html", "http://127.0.0.1:14445/redirect.html"); server.serveDirectory(dataDirectory()); @@ -1070,8 +1069,8 @@ void tst_qqmlxmlhttprequest::stateChangeCallingContext() // ensure that we don't crash by attempting to evaluate // without a valid calling context. - TestHTTPServer server(SERVER_PORT); - QVERIFY(server.isValid()); + TestHTTPServer server; + QVERIFY2(server.listen(SERVER_PORT), qPrintable(server.errorString())); server.serveDirectory(dataDirectory(), TestHTTPServer::Delay); QQmlComponent component(&engine, testFileUrl("stateChangeCallingContext.qml")); diff --git a/tests/auto/qml/qv4debugger/tst_qv4debugger.cpp b/tests/auto/qml/qv4debugger/tst_qv4debugger.cpp index b7e5cf48e0..45652d7191 100644 --- a/tests/auto/qml/qv4debugger/tst_qv4debugger.cpp +++ b/tests/auto/qml/qv4debugger/tst_qv4debugger.cpp @@ -89,7 +89,7 @@ public: QV4::Scope scope(v4); QV4::Scoped<QV4::String> name(scope, v4->newString(functionName)); - QV4::ScopedValue function(scope, v4->newBuiltinFunction(v4->rootContext, name, injectedFunction)); + QV4::ScopedValue function(scope, BuiltinFunction::create(v4->rootContext, name, injectedFunction)); v4->globalObject->put(name, function); } @@ -266,6 +266,7 @@ private slots: void removePendingBreakPoint(); void addBreakPointWhilePaused(); void removeBreakPointForNextInstruction(); + void conditionalBreakPoint(); // context access: void readArguments(); @@ -393,7 +394,7 @@ void tst_qv4debugger::addBreakPointWhilePaused() static QV4::ReturnedValue someCall(QV4::CallContext *ctx) { - ctx->engine->debugger->removeBreakPoint("removeBreakPointForNextInstruction", 2); + ctx->d()->engine->debugger->removeBreakPoint("removeBreakPointForNextInstruction", 2); return QV4::Encode::undefined(); } @@ -412,6 +413,29 @@ void tst_qv4debugger::removeBreakPointForNextInstruction() QVERIFY(!m_debuggerAgent->m_wasPaused); } +void tst_qv4debugger::conditionalBreakPoint() +{ + m_debuggerAgent->m_captureContextInfo = true; + QString script = + "function test() {\n" + " for (var i = 0; i < 15; ++i) {\n" + " var x = i;\n" + " }\n" + "}\n" + "test()\n"; + + m_debuggerAgent->addBreakPoint("conditionalBreakPoint", 3, /*enabled*/true, QStringLiteral("i > 10")); + evaluateJavaScript(script, "conditionalBreakPoint"); + QVERIFY(m_debuggerAgent->m_wasPaused); + QCOMPARE(m_debuggerAgent->m_statesWhenPaused.count(), 4); + QV4::Debugging::Debugger::ExecutionState state = m_debuggerAgent->m_statesWhenPaused.first(); + QCOMPARE(state.fileName, QString("conditionalBreakPoint")); + QCOMPARE(state.lineNumber, 3); + QCOMPARE(m_debuggerAgent->m_capturedLocals[0].size(), 2); + QVERIFY(m_debuggerAgent->m_capturedLocals[0].contains(QStringLiteral("i"))); + QCOMPARE(m_debuggerAgent->m_capturedLocals[0]["i"].toInt(), 11); +} + void tst_qv4debugger::readArguments() { m_debuggerAgent->m_captureContextInfo = true; diff --git a/tests/auto/qml/v4misc/tst_v4misc.cpp b/tests/auto/qml/v4misc/tst_v4misc.cpp index 79ccdc9a4b..17f2fed3f9 100644 --- a/tests/auto/qml/v4misc/tst_v4misc.cpp +++ b/tests/auto/qml/v4misc/tst_v4misc.cpp @@ -139,7 +139,7 @@ void tst_v4misc::rangeSplitting_3() interval.validate(); QCOMPARE(interval.end(), 71); - LifeTimeInterval newInterval = interval.split(64, LifeTimeInterval::Invalid); + LifeTimeInterval newInterval = interval.split(64, LifeTimeInterval::InvalidPosition); interval.validate(); newInterval.validate(); QVERIFY(!newInterval.isValid()); |