diff options
Diffstat (limited to 'tests')
130 files changed, 6269 insertions, 459 deletions
diff --git a/tests/auto/auto.pro b/tests/auto/auto.pro index 715f3e01ad..d37e4a57ed 100644 --- a/tests/auto/auto.pro +++ b/tests/auto/auto.pro @@ -9,6 +9,8 @@ SUBDIRS=\ cmake \ installed_cmake +qtHaveModule(widgets): SUBDIRS += quickwidgets + qmldevtools.CONFIG = host_build installed_cmake.depends = cmake 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()); diff --git a/tests/auto/qmltest/item/tst_layerInPositioner.qml b/tests/auto/qmltest/item/tst_layerInPositioner.qml new file mode 100644 index 0000000000..9144fe1d8f --- /dev/null +++ b/tests/auto/qmltest/item/tst_layerInPositioner.qml @@ -0,0 +1,207 @@ +/**************************************************************************** +** +** Copyright (C) 2014 Jolla Ltd, author: <gunnar.sletta@jollamobile.com> +** Contact: http://www.qt-project.org/legal +** +** This file is part of the test suite of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Digia gives you certain additional +** rights. These rights are described in the Digia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +import QtQuick 2.4 +import QtTest 1.0 + +Item { + id: root; + width: 400 + height: 400 + + TestCase { + id: testCase + name: "transparentForPositioner" + when: windowShown + function test_endresult() { + var image = grabImage(root); + + // Row of red, green, blue and white box inside blue + // At 10,10, spanning 10x10 pixels each + verify(image.pixel(10, 10) == Qt.rgba(1, 0, 0, 1)); + verify(image.pixel(20, 10) == Qt.rgba(0, 1, 0, 1)); + verify(image.pixel(30, 10) == Qt.rgba(0, 0, 1, 1)); + + // Column of red, green, blue and white box inside blue + // At 10,30, spanning 10x10 pixels each + verify(image.pixel(10, 30) == Qt.rgba(1, 0, 0, 1)); + verify(image.pixel(10, 40) == Qt.rgba(0, 1, 0, 1)); + verify(image.pixel(10, 50) == Qt.rgba(0, 0, 1, 1)); + + // Flow of red, green, blue and white box inside blue + // At 30,30, spanning 10x10 pixels each, wrapping after two boxes + verify(image.pixel(30, 30) == Qt.rgba(1, 0, 0, 1)); + verify(image.pixel(40, 30) == Qt.rgba(0, 1, 0, 1)); + verify(image.pixel(30, 40) == Qt.rgba(0, 0, 1, 1)); + + // Flow of red, green, blue and white box inside blue + // At 100,10, spanning 10x10 pixels each, wrapping after two boxes + verify(image.pixel(60, 10) == Qt.rgba(1, 0, 0, 1)); + verify(image.pixel(70, 10) == Qt.rgba(0, 1, 0, 1)); + verify(image.pixel(60, 20) == Qt.rgba(0, 0, 1, 1)); + } + } + + Component { + id: greenPassThrough + ShaderEffect { + fragmentShader: + " + uniform lowp sampler2D source; + varying highp vec2 qt_TexCoord0; + void main() { + gl_FragColor = texture2D(source, qt_TexCoord0) * vec4(0, 1, 0, 1); + } + " + } + } + + Row { + id: theRow + x: 10 + y: 10 + Rectangle { + width: 10 + height: 10 + color: "#ff0000" + layer.enabled: true + } + + Rectangle { + width: 10 + height: 10 + color: "#ffffff" + layer.enabled: true + layer.effect: greenPassThrough + } + + Rectangle { + id: blueInRow + width: 10 + height: 10 + color: "#0000ff" + } + } + + Column { + id: theColumn + x: 10 + y: 30 + Rectangle { + width: 10 + height: 10 + color: "#ff0000" + layer.enabled: true + } + + Rectangle { + width: 10 + height: 10 + color: "#ffffff" + layer.enabled: true + layer.effect: greenPassThrough + } + + Rectangle { + id: blueInColumn + width: 10 + height: 10 + color: "#0000ff" + } + } + + Flow { + id: theFlow + x: 30 + y: 30 + width: 20 + Rectangle { + width: 10 + height: 10 + color: "#ff0000" + layer.enabled: true + } + + Rectangle { + width: 10 + height: 10 + color: "#ffffff" + layer.enabled: true + layer.effect: greenPassThrough + } + + Rectangle { + id: blueInFlow + width: 10 + height: 10 + color: "#0000ff" + } + } + + Grid { + id: theGrid + x: 60 + y: 10 + columns: 2 + Rectangle { + width: 10 + height: 10 + color: "#ff0000" + layer.enabled: true + } + + Rectangle { + width: 10 + height: 10 + color: "#ffffff" + layer.enabled: true + layer.effect: greenPassThrough + } + + Rectangle { + id: blueInGrid + width: 10 + height: 10 + color: "#0000ff" + } + } + +} diff --git a/tests/auto/qmltest/itemgrabber/tst_itemgrabber.qml b/tests/auto/qmltest/itemgrabber/tst_itemgrabber.qml new file mode 100644 index 0000000000..4f827bbf33 --- /dev/null +++ b/tests/auto/qmltest/itemgrabber/tst_itemgrabber.qml @@ -0,0 +1,160 @@ +/**************************************************************************** +** +** Copyright (C) 2014 Jolla Ltd, author: <gunnar.sletta@jollamobile.com> +** Contact: http://www.qt-project.org/legal +** +** This file is part of the test suite of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Digia gives you certain additional +** rights. These rights are described in the Digia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +import QtQuick 2.4 +import QtTest 1.0 + +Item { + id: root; + width: 400 + height: 400 + + TestCase { + id: testCase + name: "item-grabber" + when: imageOnDisk.ready && imageOnDiskSmall.ready && imageInCache.ready && imageInCacheSmall.ready + function test_endresult() { + var image = grabImage(root); + + // imageOnDisk at (0, 0) - (100x100) + compare(imageOnDisk.width, 100); + compare(imageOnDisk.height, 100); + verify(image.pixel(0, 0) === Qt.rgba(1, 0, 0, 1)); // Use verify because compare doesn't support colors (QTBUG-34878) + verify(image.pixel(99, 99) === Qt.rgba(0, 0, 1, 1)); + + // imageOnDiskSmall at (100, 0) - 50x50 + compare(imageOnDiskSmall.width, 50); + compare(imageOnDiskSmall.height, 50); + verify(image.pixel(100, 0) === Qt.rgba(1, 0, 0, 1)); + verify(image.pixel(149, 49) === Qt.rgba(0, 0, 1, 1)); + + // imageInCache at (0, 100) - 100x100 + compare(imageInCache.width, 100); + compare(imageInCache.height, 100); + verify(image.pixel(0, 100) === Qt.rgba(1, 0, 0, 1)); + verify(image.pixel(99, 199) === Qt.rgba(0, 0, 1, 1)); + + // imageInCacheSmall at (100, 100) - 50x50 + compare(imageInCacheSmall.width, 50); + compare(imageInCacheSmall.height, 50); + verify(image.pixel(100, 100) === Qt.rgba(1, 0, 0, 1)); + verify(image.pixel(149, 149) === Qt.rgba(0, 0, 1, 1)); + + // After all that has been going on, it should only have been called that one time.. + compare(imageOnDisk.callCount, 1); + } + + onWindowShownChanged: { + box.grabToImage(imageOnDisk.handleGrab); + box.grabToImage(imageOnDiskSmall.handleGrab, Qt.size(50, 50)); + box.grabToImage(imageInCache.handleGrab); + box.grabToImage(imageInCacheSmall.handleGrab, Qt.size(50, 50)); + } + + } + + Rectangle { + id: box + width: 100 + height: 100 + color: "red"; + + visible: false + + Rectangle { + anchors.bottom: parent.bottom; + anchors.right: parent.right; + width: 10 + height: 10 + color: "blue"; + } + } + + Image { + id: imageOnDisk + x: 0 + y: 0 + property int callCount: 0; + property bool ready: false; + function handleGrab(result) { + if (!result.saveToFile("image.png")) + print("Error: Failed to save image to disk..."); + source = "image.png"; + ready = true; + ++callCount; + } + } + + Image { + id: imageOnDiskSmall + x: 100 + y: 0 + property bool ready: false; + function handleGrab(result) { + if (!result.saveToFile("image_small.png")) + print("Error: Failed to save image to disk..."); + source = "image_small.png"; + ready = true; + } + } + + Image { + id: imageInCache + x: 0 + y: 100 + property bool ready: false; + function handleGrab(result) { + source = result.url; + ready = true; + } + } + + Image { + id: imageInCacheSmall + x: 100 + y: 100 + property bool ready: false; + function handleGrab(result) { + source = result.url; + ready = true; + } + } +} diff --git a/tests/auto/qmltest/selftests/tst_findChild.qml b/tests/auto/qmltest/selftests/tst_findChild.qml new file mode 100644 index 0000000000..cb41cbf061 --- /dev/null +++ b/tests/auto/qmltest/selftests/tst_findChild.qml @@ -0,0 +1,112 @@ +/**************************************************************************** +** +** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the test suite of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Digia gives you certain additional +** rights. These rights are described in the Digia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +import QtQuick 2.0 +import QtTest 1.0 + +TestCase { + name: "tst_findChild" + + QtObject { + id: singleObject + } + + Item { + id: oneObjectChildItem + + QtObject { + id: childObject + objectName: "childObject" + } + } + + Item { + id: oneItemChildItem + + Item { + id: childItem + objectName: "childItem" + } + } + + Item { + id: nestedChildrenItem + + Item { + id: nestedChildItem0 + objectName: "nestedChildItem0" + + Item { + id: nestedChildItem1 + objectName: "nestedChildItem1" + + Item { + id: nestedChildItem2 + objectName: "nestedChildItem2" + } + } + } + } + + property Component duplicateNestedChildItem2Component: Item { + objectName: "nestedChildItem2" + } + + function test_findChild() { + compare(findChild(null, ""), null); + compare(findChild(undefined, ""), null); + compare(findChild(singleObject, "doesNotExist"), null); + compare(findChild(oneObjectChildItem, "childObject"), childObject); + compare(findChild(oneItemChildItem, "childItem"), childItem); + compare(findChild(nestedChildrenItem, "nestedChildItem0"), nestedChildItem0); + compare(findChild(nestedChildrenItem, "nestedChildItem1"), nestedChildItem1); + compare(findChild(nestedChildrenItem, "nestedChildItem2"), nestedChildItem2); + + // Shouldn't be found, since it's not the first in the list. + duplicateNestedChildItem2Component.createObject(nestedChildItem1); + compare(nestedChildItem1.children.length, 2); + compare(findChild(nestedChildrenItem, "nestedChildItem2"), nestedChildItem2); + + var mostDirectChild = duplicateNestedChildItem2Component.createObject(nestedChildItem0); + compare(nestedChildItem0.children.length, 2); + compare(findChild(nestedChildrenItem, "nestedChildItem2"), mostDirectChild); + } +} diff --git a/tests/auto/qmltest/shadersource/tst_DynamicallyCreated.qml b/tests/auto/qmltest/shadersource/tst_DynamicallyCreated.qml new file mode 100644 index 0000000000..ba0289fadc --- /dev/null +++ b/tests/auto/qmltest/shadersource/tst_DynamicallyCreated.qml @@ -0,0 +1,84 @@ +/**************************************************************************** +** +** Copyright (C) 2014 Jolla Ltd, author: <gunnar.sletta@jollamobile.com> +** Contact: http://www.qt-project.org/legal +** +** This file is part of the test suite of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Digia gives you certain additional +** rights. These rights are described in the Digia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +import QtQuick 2.2 +import QtQuick.Window 2.0 +import QtTest 1.0 + +Item { + width: 100 + height: 100 + + Window { + id: win + + width: 100 + height: 100 + + property bool rendered: false; + visible: true + + title: "QML window" + + onFrameSwapped: { + if (shaderSource.sourceItem) { + rendered = true; + } else { + var com = Qt.createQmlObject('import QtQuick 2.2; Rectangle { color: "red"; width: 100; height: 100 }', win); + shaderSource.sourceItem = com; + } + } + + ShaderEffectSource { + id: shaderSource + } + + } + + TestCase { + when: win.rendered; + name: "shadersource-dynamic-sourceobject" + function test_endresult() { + var image = grabImage(shaderSource); + compare(image.pixel(0, 0), Qt.rgba(1, 0, 0, 1)); + } + } +} diff --git a/tests/auto/qmltest/shadersource/tst_SourceInOtherWindow.qml b/tests/auto/qmltest/shadersource/tst_SourceInOtherWindow.qml new file mode 100644 index 0000000000..d9959d7fad --- /dev/null +++ b/tests/auto/qmltest/shadersource/tst_SourceInOtherWindow.qml @@ -0,0 +1,81 @@ +/**************************************************************************** +** +** Copyright (C) 2014 Jolla Ltd, author: <gunnar.sletta@jollamobile.com> +** Contact: http://www.qt-project.org/legal +** +** This file is part of the test suite of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Digia gives you certain additional +** rights. These rights are described in the Digia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +import QtQuick 2.0 +import QtQuick.Window 2.0 + +import QtTest 1.0 + +Item { + Rectangle { + id: box + color: "red" + } + + Window { + id: childWindow + + width: 100 + height: 100 + + property bool rendered: false; + visible: true + onFrameSwapped: rendered = true; + + ShaderEffectSource { + id: theSource + sourceItem: box + } + + ShaderEffect { + property variant source: theSource; + anchors.fill: parent + } + } + + TestCase { + name: "shadersource-from-other-window" + when: childWindow.isRendered + function test_endresult() { + verify(true); // that we got here without problems... + } + } +} diff --git a/tests/auto/qmltest/shadersource/tst_SourcedFromOtherWindow.qml b/tests/auto/qmltest/shadersource/tst_SourcedFromOtherWindow.qml new file mode 100644 index 0000000000..436705befc --- /dev/null +++ b/tests/auto/qmltest/shadersource/tst_SourcedFromOtherWindow.qml @@ -0,0 +1,81 @@ +/**************************************************************************** +** +** Copyright (C) 2014 Jolla Ltd, author: <gunnar.sletta@jollamobile.com> +** Contact: http://www.qt-project.org/legal +** +** This file is part of the test suite of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Digia gives you certain additional +** rights. These rights are described in the Digia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +import QtQuick 2.0 +import QtQuick.Window 2.0 + +import QtTest 1.0 + +Item { + Rectangle { + id: box + color: "red" + } + + ShaderEffectSource { + id: theSource + sourceItem: box + } + + Window { + id: childWindow + + width: 100 + height: 100 + + property bool rendered: false; + visible: true + onFrameSwapped: rendered = true; + + ShaderEffect { + property variant source: theSource; + anchors.fill: parent + } + } + + TestCase { + name: "shadersource-from-other-window" + when: childWindow.isRendered + function test_endresult() { + verify(true); // that we got here without problems... + } + } +} diff --git a/tests/auto/qmltest/statemachine/tst_anonymousstate.qml b/tests/auto/qmltest/statemachine/tst_anonymousstate.qml new file mode 100644 index 0000000000..cd20f67c20 --- /dev/null +++ b/tests/auto/qmltest/statemachine/tst_anonymousstate.qml @@ -0,0 +1,52 @@ +/**************************************************************************** +** +** Copyright (C) 2014 Ford Motor Company +** Contact: http://www.qt-project.org/legal +** +** This file is part of the test suite module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Digia gives you certain additional +** rights. These rights are described in the Digia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +import QtQml.StateMachine 1.0 +import QtTest 1.0 + +TestCase { + StateMachine { + StateBase { + } + } + name: "anonymousState" + // no real tests, just make sure it runs +} diff --git a/tests/auto/qmltest/statemachine/tst_historystate.qml b/tests/auto/qmltest/statemachine/tst_historystate.qml new file mode 100644 index 0000000000..86e63af5b0 --- /dev/null +++ b/tests/auto/qmltest/statemachine/tst_historystate.qml @@ -0,0 +1,102 @@ +/**************************************************************************** +** +** Copyright (C) 2014 Ford Motor Company +** Contact: http://www.qt-project.org/legal +** +** This file is part of the test suite module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Digia gives you certain additional +** rights. These rights are described in the Digia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +import QtQml.StateMachine 1.0 +import QtTest 1.0 + +TestCase { + + StateMachine { + id: stateMachine + initialState: historyState1 + + StateBase { + id: state1 + SignalTransition { + id: st1 + targetState: state2 + } + } + + StateBase { + id: state2 + initialState: historyState2 + HistoryState { + id: historyState2 + defaultState: state21 + } + StateBase { + id: state21 + } + } + + HistoryState { + id: historyState1 + defaultState: state1 + } + } + + SignalSpy { + id: state1SpyActive + target: state1 + signalName: "activeChanged" + } + + SignalSpy { + id: state2SpyActive + target: state2 + signalName: "activeChanged" + } + + + function test_historyStateAsInitialState() + { + stateMachine.start(); + tryCompare(stateMachine, "running", true); + tryCompare(state1SpyActive, "count" , 1); + tryCompare(state2SpyActive, "count" , 0); + st1.invoke(); + tryCompare(state1SpyActive, "count" , 2); + tryCompare(state2SpyActive, "count" , 1); + tryCompare(state21, "active", true); + tryCompare(state1, "active", false); + } +} diff --git a/tests/auto/qmltest/statemachine/tst_initialstate.qml b/tests/auto/qmltest/statemachine/tst_initialstate.qml new file mode 100644 index 0000000000..660bfcb327 --- /dev/null +++ b/tests/auto/qmltest/statemachine/tst_initialstate.qml @@ -0,0 +1,65 @@ +/**************************************************************************** +** +** Copyright (C) 2014 Ford Motor Company +** Contact: http://www.qt-project.org/legal +** +** This file is part of the test suite module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Digia gives you certain additional +** rights. These rights are described in the Digia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +import QtQml.StateMachine 1.0 +import QtTest 1.0 + +TestCase { + StateMachine { + id: myStateMachine + initialState: myState; + running: true + StateBase { + id: myState + } + } + + name: "initialStateTest" + function test_initialState() { + tryCompare(myStateMachine, "running", true); + compare(myState.active, true); + myStateMachine.running = false; + tryCompare(myStateMachine, "running", false); + myStateMachine.running = true; + tryCompare(myStateMachine, "running", true); + tryCompare(myState, "active", true); + } +} diff --git a/tests/auto/qmltest/statemachine/tst_nestedinitialstates.qml b/tests/auto/qmltest/statemachine/tst_nestedinitialstates.qml new file mode 100644 index 0000000000..60230f1e86 --- /dev/null +++ b/tests/auto/qmltest/statemachine/tst_nestedinitialstates.qml @@ -0,0 +1,74 @@ +/**************************************************************************** +** +** Copyright (C) 2014 Ford Motor Company +** Contact: http://www.qt-project.org/legal +** +** This file is part of the test suite module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Digia gives you certain additional +** rights. These rights are described in the Digia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +import QtQml.StateMachine 1.0 +import QtTest 1.0 + +TestCase { + StateMachine { + id: myStateMachine + initialState: parentState + StateBase { + id: parentState + initialState: childState1 + StateBase { + id: childState1 + } + StateBase { + id: childState2 + } + } + } + name: "nestedInitalStates" + + function test_nestedInitalStates() { + // uncomment me after vm problems are fixed. + // compare(myStateMachine.running, false); + compare(parentState.active, false); + compare(childState1.active, false); + compare(childState2.active, false); + myStateMachine.start(); + tryCompare(myStateMachine, "running", true); + tryCompare(parentState, "active", true); + tryCompare(childState1, "active", true); + compare(childState2.active, false); + } +} diff --git a/tests/auto/qmltest/statemachine/tst_parallelmachine.qml b/tests/auto/qmltest/statemachine/tst_parallelmachine.qml new file mode 100644 index 0000000000..99ef49860c --- /dev/null +++ b/tests/auto/qmltest/statemachine/tst_parallelmachine.qml @@ -0,0 +1,90 @@ +/**************************************************************************** +** +** Copyright (C) 2014 Ford Motor Company +** Contact: http://www.qt-project.org/legal +** +** This file is part of the test suite module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Digia gives you certain additional +** rights. These rights are described in the Digia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +import QtQml.StateMachine 1.0 +import QtTest 1.0 + +TestCase { + StateMachine { + id: myStateMachine + childMode: StateBase.ParallelStates + StateBase { + id: childState1 + childMode: StateBase.ParallelStates + StateBase { + id: childState11 + } + StateBase { + id: childState12 + } + } + StateBase { + id: childState2 + initialState: childState21 + StateBase { + id: childState21 + } + StateBase { + id: childState22 + } + } + } + name: "nestedParallelMachineStates" + + function test_nestedInitalStates() { + // uncomment me after vm problems are fixed. + // compare(myStateMachine.running, false); + compare(childState1.active, false); + compare(childState11.active, false); + compare(childState12.active, false); + compare(childState2.active, false); + compare(childState21.active, false); + compare(childState22.active, false); + myStateMachine.start(); + tryCompare(myStateMachine, "running", true); + tryCompare(childState1, "active", true); + tryCompare(childState11, "active", true); + tryCompare(childState12, "active", true); + tryCompare(childState2, "active", true); + tryCompare(childState21, "active", true); + tryCompare(childState22, "active", false); + } +} diff --git a/tests/auto/qmltest/statemachine/tst_trafficlight.qml b/tests/auto/qmltest/statemachine/tst_trafficlight.qml new file mode 100644 index 0000000000..7b02cd0597 --- /dev/null +++ b/tests/auto/qmltest/statemachine/tst_trafficlight.qml @@ -0,0 +1,157 @@ +/**************************************************************************** +** +** Copyright (C) 2014 Ford Motor Company +** Contact: http://www.qt-project.org/legal +** +** This file is part of the test suite module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Digia gives you certain additional +** rights. These rights are described in the Digia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +import QtQml.StateMachine 1.0 +import QtTest 1.0 + +TestCase { + StateMachine { + id: machine + initialState: red + FinalState { + id: finalState + } + + StateBase { + id: red + initialState: justRed + StateBase { + id: justRed + SignalTransition { + id: e1 + targetState: waitingForGreen + } + SignalTransition { + id: finalSignal + targetState: finalState + } + } + StateBase { + id: waitingForGreen + TimeoutTransition { + id: e2 + targetState: yellowred + timeout: 30 + } + } + } + StateBase { + id: yellowred + TimeoutTransition { + id: e3 + targetState: green + timeout: 10 + } + } + StateBase { + id: green + TimeoutTransition { + id: e4 + targetState: yellow + timeout: 50 + } + } + StateBase { + id: yellow + TimeoutTransition { + id: e5 + targetState: red + timeout: 10 + } + } + } + + SignalSpy { + id: machineSpyRunning + target: machine + signalName: "runningChanged" + } + + SignalSpy { + id: redSpyActive + target: red + signalName: "activeChanged" + } + + SignalSpy { + id: yellowredSpyActive + target: yellowred + signalName: "activeChanged" + } + + SignalSpy { + id: greenSpyActive + target: green + signalName: "activeChanged" + } + + SignalSpy { + id: yellowSpyActive + target: yellow + signalName: "activeChanged" + } + + + name: "testTrafficLight" + function test_trafficLight() + { + var i = 1; + machine.start(); + tryCompare(machine, "running", true); + tryCompare(machineSpyRunning, "count", 1); + tryCompare(redSpyActive, "count", 1); + for (; i <= 5; ++i) { + e1.invoke(); + tryCompare(yellowredSpyActive, "count", i * 2); + tryCompare(greenSpyActive, "count", i * 2); + tryCompare(redSpyActive, "count", i * 2 + 1); + tryCompare(yellowSpyActive, "count", i * 2); + } + finalSignal.guard = false; + finalSignal.invoke(); + wait(100); + tryCompare(machine, "running", true); + finalSignal.guard = true; + finalSignal.invoke(); + tryCompare(machine, "running", false); + tryCompare(redSpyActive, "count", i * 2); + } +} diff --git a/tests/auto/quick/nodes/tst_nodestest.cpp b/tests/auto/quick/nodes/tst_nodestest.cpp index 662e78ef6c..212337957e 100644 --- a/tests/auto/quick/nodes/tst_nodestest.cpp +++ b/tests/auto/quick/nodes/tst_nodestest.cpp @@ -52,6 +52,8 @@ #include <QtQuick/private/qsgcontext_p.h> #include <QtQuick/qsgsimplerectnode.h> +#include <QtQuick/qsgsimpletexturenode.h> +#include <QtQuick/private/qsgtexture_p.h> class NodesTest : public QObject { @@ -74,6 +76,8 @@ private Q_SLOTS: void isBlockedCheck(); + void textureNodeTextureOwnership(); + private: QOffscreenSurface *surface; QOpenGLContext *context; @@ -259,6 +263,32 @@ void NodesTest::isBlockedCheck() QVERIFY(!updater.isNodeBlocked(node, &root)); } +void NodesTest::textureNodeTextureOwnership() +{ + { // Check that it is not deleted by default + QPointer<QSGTexture> texture(new QSGPlainTexture()); + + QSGSimpleTextureNode *tn = new QSGSimpleTextureNode(); + QVERIFY(!tn->ownsTexture()); + + tn->setTexture(texture); + delete tn; + QVERIFY(!texture.isNull()); + } + + { // Check that it is deleted when we so desire + QPointer<QSGTexture> texture(new QSGPlainTexture()); + + QSGSimpleTextureNode *tn = new QSGSimpleTextureNode(); + tn->setOwnsTexture(true); + QVERIFY(tn->ownsTexture()); + + tn->setTexture(texture); + delete tn; + QVERIFY(texture.isNull()); + } +} + QTEST_MAIN(NodesTest); #include "tst_nodestest.moc" diff --git a/tests/auto/quick/qquickaccessible/tst_qquickaccessible.cpp b/tests/auto/quick/qquickaccessible/tst_qquickaccessible.cpp index 760cdd7b49..cb801f5539 100644 --- a/tests/auto/quick/qquickaccessible/tst_qquickaccessible.cpp +++ b/tests/auto/quick/qquickaccessible/tst_qquickaccessible.cpp @@ -41,7 +41,7 @@ #include <QtTest/QtTest> -#include "QtTest/qtestaccessible.h" +#include <QtTest/qtestaccessible.h> #include <QtGui/qaccessible.h> #include <QtGui/private/qguiapplication_p.h> diff --git a/tests/auto/quick/qquickanchors/tst_qquickanchors.cpp b/tests/auto/quick/qquickanchors/tst_qquickanchors.cpp index ee277ecd9b..02c30b652a 100644 --- a/tests/auto/quick/qquickanchors/tst_qquickanchors.cpp +++ b/tests/auto/quick/qquickanchors/tst_qquickanchors.cpp @@ -310,55 +310,55 @@ void tst_qquickanchors::illegalSets_data() QTest::newRow("H - too many anchors") << "Rectangle { id: rect; Rectangle { anchors.left: rect.left; anchors.right: rect.right; anchors.horizontalCenter: rect.horizontalCenter } }" - << "file::2:23: QML Rectangle: Cannot specify left, right, and horizontalCenter anchors at the same time."; + << "<Unknown File>:2:23: QML Rectangle: Cannot specify left, right, and horizontalCenter anchors at the same time."; foreach (const QString &side, QStringList() << "left" << "right") { QTest::newRow("H - anchor to V") << QString("Rectangle { Rectangle { anchors.%1: parent.top } }").arg(side) - << "file::2:13: QML Rectangle: Cannot anchor a horizontal edge to a vertical edge."; + << "<Unknown File>:2:13: QML Rectangle: Cannot anchor a horizontal edge to a vertical edge."; QTest::newRow("H - anchor to non parent/sibling") << QString("Rectangle { Item { Rectangle { id: rect } } Rectangle { anchors.%1: rect.%1 } }").arg(side) - << "file::2:45: QML Rectangle: Cannot anchor to an item that isn't a parent or sibling."; + << "<Unknown File>:2:45: QML Rectangle: Cannot anchor to an item that isn't a parent or sibling."; QTest::newRow("H - anchor to self") << QString("Rectangle { id: rect; anchors.%1: rect.%1 }").arg(side) - << "file::2:1: QML Rectangle: Cannot anchor item to self."; + << "<Unknown File>:2:1: QML Rectangle: Cannot anchor item to self."; } QTest::newRow("V - too many anchors") << "Rectangle { id: rect; Rectangle { anchors.top: rect.top; anchors.bottom: rect.bottom; anchors.verticalCenter: rect.verticalCenter } }" - << "file::2:23: QML Rectangle: Cannot specify top, bottom, and verticalCenter anchors at the same time."; + << "<Unknown File>:2:23: QML Rectangle: Cannot specify top, bottom, and verticalCenter anchors at the same time."; QTest::newRow("V - too many anchors with baseline") << "Rectangle { Text { id: text1; text: \"Hello\" } Text { anchors.baseline: text1.baseline; anchors.top: text1.top; } }" - << "file::2:47: QML Text: Baseline anchor cannot be used in conjunction with top, bottom, or verticalCenter anchors."; + << "<Unknown File>:2:47: QML Text: Baseline anchor cannot be used in conjunction with top, bottom, or verticalCenter anchors."; foreach (const QString &side, QStringList() << "top" << "bottom" << "baseline") { QTest::newRow("V - anchor to H") << QString("Rectangle { Rectangle { anchors.%1: parent.left } }").arg(side) - << "file::2:13: QML Rectangle: Cannot anchor a vertical edge to a horizontal edge."; + << "<Unknown File>:2:13: QML Rectangle: Cannot anchor a vertical edge to a horizontal edge."; QTest::newRow("V - anchor to non parent/sibling") << QString("Rectangle { Item { Rectangle { id: rect } } Rectangle { anchors.%1: rect.%1 } }").arg(side) - << "file::2:45: QML Rectangle: Cannot anchor to an item that isn't a parent or sibling."; + << "<Unknown File>:2:45: QML Rectangle: Cannot anchor to an item that isn't a parent or sibling."; QTest::newRow("V - anchor to self") << QString("Rectangle { id: rect; anchors.%1: rect.%1 }").arg(side) - << "file::2:1: QML Rectangle: Cannot anchor item to self."; + << "<Unknown File>:2:1: QML Rectangle: Cannot anchor item to self."; } QTest::newRow("centerIn - anchor to non parent/sibling") << "Rectangle { Item { Rectangle { id: rect } } Rectangle { anchors.centerIn: rect} }" - << "file::2:45: QML Rectangle: Cannot anchor to an item that isn't a parent or sibling."; + << "<Unknown File>:2:45: QML Rectangle: Cannot anchor to an item that isn't a parent or sibling."; QTest::newRow("fill - anchor to non parent/sibling") << "Rectangle { Item { Rectangle { id: rect } } Rectangle { anchors.fill: rect} }" - << "file::2:45: QML Rectangle: Cannot anchor to an item that isn't a parent or sibling."; + << "<Unknown File>:2:45: QML Rectangle: Cannot anchor to an item that isn't a parent or sibling."; } void tst_qquickanchors::reset() diff --git a/tests/auto/quick/qquickanimatedimage/tst_qquickanimatedimage.cpp b/tests/auto/quick/qquickanimatedimage/tst_qquickanimatedimage.cpp index d10963b579..eb0ea7c8f5 100644 --- a/tests/auto/quick/qquickanimatedimage/tst_qquickanimatedimage.cpp +++ b/tests/auto/quick/qquickanimatedimage/tst_qquickanimatedimage.cpp @@ -259,8 +259,8 @@ void tst_qquickanimatedimage::remote() QFETCH(QString, fileName); QFETCH(bool, paused); - TestHTTPServer server(14449); - QVERIFY(server.isValid()); + TestHTTPServer server; + QVERIFY2(server.listen(14449), qPrintable(server.errorString())); server.serveDirectory(dataDirectory()); QQmlEngine engine; @@ -305,10 +305,10 @@ void tst_qquickanimatedimage::invalidSource() { QQmlEngine engine; QQmlComponent component(&engine); - component.setData("import QtQuick 2.0\n AnimatedImage { source: \"no-such-file.gif\" }", QUrl::fromLocalFile("")); + component.setData("import QtQuick 2.0\n AnimatedImage { source: \"no-such-file.gif\" }", QUrl::fromLocalFile("relative")); QVERIFY(component.isReady()); - QTest::ignoreMessage(QtWarningMsg, "file::2:2: QML AnimatedImage: Error Reading Animated Image File file:no-such-file.gif"); + QTest::ignoreMessage(QtWarningMsg, "file:relative:2:2: QML AnimatedImage: Error Reading Animated Image File file:no-such-file.gif"); QQuickAnimatedImage *anim = qobject_cast<QQuickAnimatedImage *>(component.create()); QVERIFY(anim); @@ -324,8 +324,8 @@ void tst_qquickanimatedimage::invalidSource() void tst_qquickanimatedimage::sourceSizeChanges() { - TestHTTPServer server(14449); - QVERIFY(server.isValid()); + TestHTTPServer server; + QVERIFY2(server.listen(14449), qPrintable(server.errorString())); server.serveDirectory(dataDirectory()); QQmlEngine engine; @@ -390,8 +390,8 @@ void tst_qquickanimatedimage::sourceSizeChanges() void tst_qquickanimatedimage::qtbug_16520() { - TestHTTPServer server(14449); - QVERIFY(server.isValid()); + TestHTTPServer server; + QVERIFY2(server.listen(14449), qPrintable(server.errorString())); server.serveDirectory(dataDirectory()); QQmlEngine engine; @@ -413,8 +413,8 @@ void tst_qquickanimatedimage::qtbug_16520() void tst_qquickanimatedimage::progressAndStatusChanges() { - TestHTTPServer server(14449); - QVERIFY(server.isValid()); + TestHTTPServer server; + QVERIFY2(server.listen(14449), qPrintable(server.errorString())); server.serveDirectory(dataDirectory()); QQmlEngine engine; diff --git a/tests/auto/quick/qquickapplication/tst_qquickapplication.cpp b/tests/auto/quick/qquickapplication/tst_qquickapplication.cpp index dfcef43a7e..0993d03ee4 100644 --- a/tests/auto/quick/qquickapplication/tst_qquickapplication.cpp +++ b/tests/auto/quick/qquickapplication/tst_qquickapplication.cpp @@ -60,6 +60,7 @@ private slots: void state(); void layoutDirection(); void inputMethod(); + void cleanup(); private: QQmlEngine engine; @@ -69,6 +70,14 @@ tst_qquickapplication::tst_qquickapplication() { } +void tst_qquickapplication::cleanup() +{ + if (QGuiApplicationPrivate::platformIntegration()->hasCapability(QPlatformIntegration::ApplicationState)) { + QWindowSystemInterface::handleApplicationStateChanged(Qt::ApplicationInactive); + QTest::waitForEvents(); + } +} + void tst_qquickapplication::active() { QQmlComponent component(&engine); @@ -98,12 +107,19 @@ void tst_qquickapplication::active() QVERIFY(item->property("active").toBool()); QVERIFY(item->property("active2").toBool()); - // not active again QWindowSystemInterface::handleWindowActivated(0); +#ifdef Q_OS_OSX + // OS X has the concept of "reactivation" + QTRY_VERIFY(QGuiApplication::focusWindow() != &window); + QVERIFY(item->property("active").toBool()); + QVERIFY(item->property("active2").toBool()); +#else + // not active again QTRY_VERIFY(QGuiApplication::focusWindow() != &window); QVERIFY(!item->property("active").toBool()); QVERIFY(!item->property("active2").toBool()); +#endif } void tst_qquickapplication::state() @@ -117,6 +133,7 @@ void tst_qquickapplication::state() " target: Qt.application; " " onStateChanged: state2 = Qt.application.state; " " } " + " Component.onCompleted: state2 = Qt.application.state; " "}", QUrl::fromLocalFile("")); QQuickItem *item = qobject_cast<QQuickItem *>(component.create()); QVERIFY(item); diff --git a/tests/auto/quick/qquickborderimage/tst_qquickborderimage.cpp b/tests/auto/quick/qquickborderimage/tst_qquickborderimage.cpp index 4e7b6522dd..ce4394cf6f 100644 --- a/tests/auto/quick/qquickborderimage/tst_qquickborderimage.cpp +++ b/tests/auto/quick/qquickborderimage/tst_qquickborderimage.cpp @@ -131,10 +131,10 @@ void tst_qquickborderimage::imageSource_data() QTest::newRow("local") << testFileUrl("colors.png").toString() << false << ""; QTest::newRow("local not found") << testFileUrl("no-such-file.png").toString() << false - << "file::2:1: QML BorderImage: Cannot open: " + testFileUrl("no-such-file.png").toString(); + << "<Unknown File>:2:1: QML BorderImage: Cannot open: " + testFileUrl("no-such-file.png").toString(); QTest::newRow("remote") << SERVER_ADDR "/colors.png" << true << ""; QTest::newRow("remote not found") << SERVER_ADDR "/no-such-file.png" << true - << "file::2:1: QML BorderImage: Error downloading " SERVER_ADDR "/no-such-file.png - server replied: Not found"; + << "<Unknown File>:2:1: QML BorderImage: Error downloading " SERVER_ADDR "/no-such-file.png - server replied: Not found"; } void tst_qquickborderimage::imageSource() @@ -143,11 +143,10 @@ void tst_qquickborderimage::imageSource() QFETCH(bool, remote); QFETCH(QString, error); - TestHTTPServer *server = 0; + TestHTTPServer server; if (remote) { - server = new TestHTTPServer(SERVER_PORT); - QVERIFY(server->isValid()); - server->serveDirectory(dataDirectory()); + QVERIFY2(server.listen(SERVER_PORT), qPrintable(server.errorString())); + server.serveDirectory(dataDirectory()); } if (!error.isEmpty()) @@ -177,7 +176,6 @@ void tst_qquickborderimage::imageSource() } delete obj; - delete server; } void tst_qquickborderimage::clearSource() @@ -292,11 +290,11 @@ void tst_qquickborderimage::sciSource() QFETCH(bool, valid); bool remote = source.startsWith("http"); - TestHTTPServer *server = 0; + + TestHTTPServer server; if (remote) { - server = new TestHTTPServer(SERVER_PORT); - QVERIFY(server->isValid()); - server->serveDirectory(dataDirectory()); + QVERIFY2(server.listen(SERVER_PORT), qPrintable(server.errorString())); + server.serveDirectory(dataDirectory()); } QString componentStr = "import QtQuick 2.0\nBorderImage { source: \"" + source + "\"; width: 300; height: 300 }"; @@ -325,7 +323,6 @@ void tst_qquickborderimage::sciSource() } delete obj; - delete server; } void tst_qquickborderimage::sciSource_data() @@ -435,11 +432,10 @@ void tst_qquickborderimage::statusChanges() QFETCH(bool, remote); QFETCH(QQuickImageBase::Status, finalStatus); - TestHTTPServer *server = 0; + TestHTTPServer server; if (remote) { - server = new TestHTTPServer(SERVER_PORT); - QVERIFY(server->isValid()); - server->serveDirectory(dataDirectory(), TestHTTPServer::Delay); + QVERIFY2(server.listen(SERVER_PORT), qPrintable(server.errorString())); + server.serveDirectory(dataDirectory()); } QString componentStr = "import QtQuick 2.0\nBorderImage { width: 300; height: 300 }"; @@ -452,18 +448,17 @@ void tst_qquickborderimage::statusChanges() QVERIFY(obj != 0); obj->setSource(source); if (remote) - server->sendDelayedItem(); + server.sendDelayedItem(); QTRY_VERIFY(obj->status() == finalStatus); QCOMPARE(spy.count(), emissions); delete obj; - delete server; } void tst_qquickborderimage::sourceSizeChanges() { - TestHTTPServer server(14449); - QVERIFY(server.isValid()); + TestHTTPServer server; + QVERIFY2(server.listen(14449), qPrintable(server.errorString())); server.serveDirectory(dataDirectory()); QQmlEngine engine; @@ -528,8 +523,8 @@ void tst_qquickborderimage::sourceSizeChanges() void tst_qquickborderimage::progressAndStatusChanges() { - TestHTTPServer server(14449); - QVERIFY(server.isValid()); + TestHTTPServer server; + QVERIFY2(server.listen(14449), qPrintable(server.errorString())); server.serveDirectory(dataDirectory()); QQmlEngine engine; diff --git a/tests/auto/quick/qquickcanvasitem/data/tst_canvas.qml b/tests/auto/quick/qquickcanvasitem/data/tst_canvas.qml index d90eb3971e..23fd5192f3 100644 --- a/tests/auto/quick/qquickcanvasitem/data/tst_canvas.qml +++ b/tests/auto/quick/qquickcanvasitem/data/tst_canvas.qml @@ -247,5 +247,348 @@ CanvasTestCase { c.destroy(); } + + Image { + id: image + source: "anim-gr.png" + } + + /* + Ensures that extra arguments to functions are ignored, + by checking that drawing, clearing, etc. still occurs. + */ + function test_extraArgumentsIgnored_data() { + var extra = 0; + return [ + { + tag: "arc", + test: function(ctx) { + ctx.arc(10, 10, 5, 0, Math.PI * 2, true, extra); + ctx.fill(); + comparePixel(ctx, 10, 10, 255, 0, 0, 255); + } + }, + { + tag: "arcTo", + test: function(ctx) { + ctx.translate(-50, -25); + ctx.moveTo(20,20); + ctx.arcTo(150, 20, 100, 70, 50, extra); + ctx.fill(); + comparePixel(ctx, 0, 0, 255, 0, 0, 255); + } + }, + { + tag: "bezierCurveTo", + test: function(ctx) { + ctx.beginPath(); + ctx.moveTo(-20, -20); + ctx.bezierCurveTo(20, 100, 100, 100, 100, 20, extra); + ctx.fill(); + comparePixel(ctx, 0, 0, 255, 0, 0, 255); + } + }, + { + tag: "clearRect", + test: function(ctx) { + ctx.fillRect(0, 0, ctx.canvas.width, ctx.canvas.height); + ctx.clearRect(0, 0, 10, 10, extra); + comparePixel(ctx, 0, 0, 0, 0, 0, 0); + } + }, + { + tag: "createConicalGradient", + test: function(ctx) { + verify(ctx.createConicalGradient(0, 0, 0, extra) !== ctx); + } + }, + { + tag: "createLinearGradient", + test: function(ctx) { + verify(ctx.createLinearGradient(0, 0, 10, 10, extra) !== ctx); + } + }, + { + tag: "createRadialGradient", + test: function(ctx) { + verify(ctx.createRadialGradient(0, 0, 10, 20, 20, 10, extra) !== ctx); + } + }, + { + tag: "createPattern-image", + test: function(ctx) { + verify(ctx.createPattern(image, "repeat", extra) !== undefined); + } + }, + { + tag: "createPattern-color", + test: function(ctx) { + verify(ctx.createPattern("red", Qt.SolidPattern, extra) !== undefined); + } + }, + { + tag: "drawImage-9-args", + test: function(ctx) { + ctx.drawImage(image, 0, 0, image.sourceSize.width, image.sourceSize.height, + 0, 0, image.sourceSize.width, image.sourceSize.height, extra); + comparePixel(ctx, 10, 10, 0, 255, 0, 255); + } + }, + { + tag: "drawImage-5-args", + test: function(ctx) { + ctx.drawImage(image, 0, 0, image.sourceSize.width, image.sourceSize.height, extra); + comparePixel(ctx, 10, 10, 0, 255, 0, 255); + } + }, + { + tag: "drawImage-3-args", + test: function(ctx) { + ctx.drawImage(image, 0, 0, extra); + comparePixel(ctx, 10, 10, 0, 255, 0, 255); + } + }, + { + tag: "ellipse", + test: function(ctx) { + ctx.ellipse(0, 0, 10, 10); + ctx.fill(); + comparePixel(ctx, 5, 5, 255, 0, 0, 255); + } + }, + { + tag: "fillRect", + test: function(ctx) { + ctx.fillRect(0, 0, 10, 10, extra); + comparePixel(ctx, 0, 0, 255, 0, 0, 255, 200); + } + }, + { + tag: "fillText", + test: function(ctx) { + ctx.font = "100px sans-serif"; + ctx.fillText("Hello", -10, 10, extra); + comparePixel(ctx, 0, 0, 255, 0, 0, 255); + } + }, + { + tag: "getImageData", + test: function(ctx) { + verify(ctx.getImageData(0, 0, 1, 1, extra) !== null); + } + }, + { + tag: "isPointInPath", + test: function(ctx) { + ctx.moveTo(0, 0); + ctx.lineTo(10, 10); + verify(ctx.isPointInPath(0, 0, extra)); + } + }, + { + tag: "lineTo", + test: function(ctx) { + ctx.lineWidth = 5; + ctx.moveTo(0, 0); + ctx.lineTo(10, 10, extra); + ctx.stroke(); + comparePixel(ctx, 0, 0, 255, 0, 0, 255); + } + }, + { + tag: "measureText", + test: function(ctx) { + var textMetrics = ctx.measureText("Hello", extra); + verify(textMetrics !== undefined); + verify(textMetrics.width > 0); + } + }, + { + tag: "moveTo", + test: function(ctx) { + ctx.lineWidth = 5; + ctx.moveTo(10, 10, extra); + ctx.lineTo(20, 20, extra); + ctx.stroke(); + comparePixel(ctx, 0, 0, 0, 0, 0, 0); + comparePixel(ctx, 10, 10, 255, 0, 0, 255); + } + }, + { + tag: "putImageData", + test: function(ctx) { + ctx.drawImage(image, 0, 0); + comparePixel(ctx, 0, 0, 0, 255, 0, 255); + var imageData = ctx.getImageData(0, 0, 1, 1); + // Swap green with red. + imageData.data[0] = 255; + imageData.data[1] = 0; + ctx.putImageData(imageData, 0, 0, 0, 0, ctx.canvas.width, ctx.canvas.height, extra); + comparePixel(ctx, 0, 0, 255, 0, 0, 255); + } + }, + { + tag: "quadraticCurveTo", + test: function(ctx) { + ctx.lineWidth = 5; + ctx.moveTo(0, 0); + ctx.quadraticCurveTo(20, 100, 100, 20, extra); + ctx.stroke(); + comparePixel(ctx, 0, 0, 255, 0, 0, 255); + } + }, + { + tag: "rect", + test: function(ctx) { + ctx.rect(0, 0, 1, 1, extra); + ctx.fill(); + comparePixel(ctx, 0, 0, 255, 0, 0, 255); + } + }, + { + tag: "rotate", + test: function(ctx) { + // If we don't rotate, it should be red in the middle. + comparePixel(ctx, 50, 50, 0, 0, 0, 0); + ctx.fillRect(50, 50, 1, 1); + comparePixel(ctx, 50, 50, 255, 0, 0, 255); + + ctx.reset(); + comparePixel(ctx, 50, 50, 0, 0, 0, 0); + + // If we do rotate, it shouldn't be there. + ctx.rotate(Math.PI / 4, extra); + ctx.fillRect(50, 50, 1, 1); + comparePixel(ctx, 50, 50, 0, 0, 0, 0); + } + }, + { + tag: "roundedRect", + test: function(ctx) { + ctx.roundedRect(0, 0, 50, 50, 5, 5, extra); + ctx.fill(); + comparePixel(ctx, 25, 25, 255, 0, 0, 255); + } + }, + { + tag: "scale", + test: function(ctx) { + // If we don't scale, it should be red in the middle. + comparePixel(ctx, 50, 50, 0, 0, 0, 0); + ctx.fillRect(50, 50, 1, 1); + comparePixel(ctx, 50, 50, 255, 0, 0, 255); + + ctx.reset(); + comparePixel(ctx, 50, 50, 0, 0, 0, 0); + + // If we do scale, it shouldn't be there. + ctx.scale(1.25, 1.25, extra); + ctx.fillRect(50, 50, 1, 1); + comparePixel(ctx, 50, 50, 0, 0, 0, 0); + } + }, + { + tag: "setTransform", + test: function(ctx) { + // The same as the scale test, except with setTransform. + comparePixel(ctx, 50, 50, 0, 0, 0, 0); + ctx.fillRect(50, 50, 1, 1); + comparePixel(ctx, 50, 50, 255, 0, 0, 255); + + ctx.reset(); + comparePixel(ctx, 50, 50, 0, 0, 0, 0); + + ctx.setTransform(1.25, 0, 0, 1.25, 0, 0, extra); + ctx.fillRect(50, 50, 1, 1); + comparePixel(ctx, 50, 50, 0, 0, 0, 0); + } + }, + { + tag: "shear", + test: function(ctx) { + comparePixel(ctx, 50, 50, 0, 0, 0, 0); + ctx.fillRect(50, 50, 1, 1); + comparePixel(ctx, 50, 50, 255, 0, 0, 255); + + ctx.reset(); + comparePixel(ctx, 50, 50, 0, 0, 0, 0); + + ctx.shear(0.5, 0, extra); + ctx.fillRect(50, 50, 1, 1); + comparePixel(ctx, 50, 50, 0, 0, 0, 0); + } + }, + { + tag: "strokeRect", + test: function(ctx) { + ctx.strokeRect(0, 0, 10, 10, extra); + comparePixel(ctx, 0, 0, 255, 0, 0, 255, 200); + } + }, + { + tag: "strokeText", + test: function(ctx) { + ctx.font = "10px sans-serif"; + ctx.strokeText("Hello", -1, 5, extra); + comparePixel(ctx, 0, 5, 255, 0, 0, 255, 200); + } + }, + { + tag: "text", + test: function(ctx) { + ctx.font = "100px sans-serif"; + ctx.text(".", -15, 8, extra); + ctx.fill(); + comparePixel(ctx, 0, 0, 255, 0, 0, 255, 200); + } + }, + { + tag: "transform", + test: function(ctx) { + comparePixel(ctx, 50, 50, 0, 0, 0, 0); + ctx.fillRect(50, 50, 1, 1); + comparePixel(ctx, 50, 50, 255, 0, 0, 255); + + ctx.reset(); + comparePixel(ctx, 50, 50, 0, 0, 0, 0); + + ctx.transform(1.25, 0, 0, 1.25, 0, 0, extra); + ctx.fillRect(50, 50, 1, 1); + comparePixel(ctx, 50, 50, 0, 0, 0, 0); + } + }, + { + tag: "translate", + test: function(ctx) { + comparePixel(ctx, 50, 50, 0, 0, 0, 0); + ctx.fillRect(50, 50, 1, 1); + comparePixel(ctx, 50, 50, 255, 0, 0, 255); + + ctx.reset(); + comparePixel(ctx, 50, 50, 0, 0, 0, 0); + + ctx.translate(1, 1, extra); + ctx.fillRect(50, 50, 1, 1); + comparePixel(ctx, 50, 50, 0, 0, 0, 0); + } + } + ]; + } + + function test_extraArgumentsIgnored(data) { + var canvas = Qt.createQmlObject("import QtQuick 2.3; Canvas { onPaint: {} }", testCase); + verify(canvas); + canvas.width = 100; + canvas.height = 100; + + var ctx = canvas.getContext("2d"); + + ctx.beginPath(); + ctx.fillStyle = "red"; + ctx.strokeStyle = "red"; + data.test(ctx); + + canvas.destroy(); + } } diff --git a/tests/auto/quick/qquickdrag/tst_qquickdrag.cpp b/tests/auto/quick/qquickdrag/tst_qquickdrag.cpp index 15282d4b02..410220899a 100644 --- a/tests/auto/quick/qquickdrag/tst_qquickdrag.cpp +++ b/tests/auto/quick/qquickdrag/tst_qquickdrag.cpp @@ -416,7 +416,7 @@ void tst_QQuickDrag::drop() QCOMPARE(evaluate<bool>(item, "dragActive"), true); QCOMPARE(evaluate<QObject *>(item, "Drag.target"), static_cast<QObject *>(&innerTarget)); QCOMPARE(evaluate<QObject *>(item, "dragTarget"), static_cast<QObject *>(&innerTarget)); - QCOMPARE(outerTarget.enterEvents, 1); QCOMPARE(outerTarget.leaveEvents, 0); QCOMPARE(outerTarget.dropEvents, 0); + QCOMPARE(outerTarget.enterEvents, 0); QCOMPARE(outerTarget.leaveEvents, 0); QCOMPARE(outerTarget.dropEvents, 0); QCOMPARE(innerTarget.enterEvents, 1); QCOMPARE(innerTarget.leaveEvents, 0); QCOMPARE(innerTarget.dropEvents, 0); innerTarget.reset(); outerTarget.reset(); @@ -425,7 +425,7 @@ void tst_QQuickDrag::drop() QCOMPARE(evaluate<bool>(item, "dragActive"), false); QCOMPARE(evaluate<QObject *>(item, "Drag.target"), static_cast<QObject *>(&innerTarget)); QCOMPARE(evaluate<QObject *>(item, "dragTarget"), static_cast<QObject *>(&innerTarget)); - QCOMPARE(outerTarget.enterEvents, 0); QCOMPARE(outerTarget.leaveEvents, 1); QCOMPARE(outerTarget.dropEvents, 0); + QCOMPARE(outerTarget.enterEvents, 0); QCOMPARE(outerTarget.leaveEvents, 0); QCOMPARE(outerTarget.dropEvents, 0); QCOMPARE(innerTarget.enterEvents, 0); QCOMPARE(innerTarget.leaveEvents, 0); QCOMPARE(innerTarget.dropEvents, 1); innerTarget.reset(); outerTarget.reset(); @@ -434,24 +434,13 @@ void tst_QQuickDrag::drop() QCOMPARE(evaluate<bool>(item, "dragActive"), true); QCOMPARE(evaluate<QObject *>(item, "Drag.target"), static_cast<QObject *>(&innerTarget)); QCOMPARE(evaluate<QObject *>(item, "dragTarget"), static_cast<QObject *>(&innerTarget)); - QCOMPARE(outerTarget.enterEvents, 1); QCOMPARE(outerTarget.leaveEvents, 0); QCOMPARE(outerTarget.dropEvents, 0); + QCOMPARE(outerTarget.enterEvents, 0); QCOMPARE(outerTarget.leaveEvents, 0); QCOMPARE(outerTarget.dropEvents, 0); QCOMPARE(innerTarget.enterEvents, 1); QCOMPARE(innerTarget.leaveEvents, 0); QCOMPARE(innerTarget.dropEvents, 0); - // Inner target declines the drop so it is propagated to the outer target. - innerTarget.accept = false; - - innerTarget.reset(); outerTarget.reset(); - QCOMPARE(evaluate<bool>(item, "Drag.drop() == Qt.CopyAction"), true); - QCOMPARE(evaluate<bool>(item, "Drag.active"), false); - QCOMPARE(evaluate<bool>(item, "dragActive"), false); - QCOMPARE(evaluate<QObject *>(item, "Drag.target"), static_cast<QObject *>(&outerTarget)); - QCOMPARE(evaluate<QObject *>(item, "dragTarget"), static_cast<QObject *>(&outerTarget)); - QCOMPARE(outerTarget.enterEvents, 0); QCOMPARE(outerTarget.leaveEvents, 0); QCOMPARE(outerTarget.dropEvents, 1); - QCOMPARE(innerTarget.enterEvents, 0); QCOMPARE(innerTarget.leaveEvents, 0); QCOMPARE(innerTarget.dropEvents, 1); - + evaluate<void>(item, "Drag.active = false"); // Inner target doesn't accept enter so drop goes directly to outer. - innerTarget.accept = true; + innerTarget.accept = false; innerTarget.setFlags(QQuickItem::Flags()); innerTarget.reset(); outerTarget.reset(); @@ -584,10 +573,9 @@ void tst_QQuickDrag::move() QCoreApplication::processEvents(); QCOMPARE(evaluate<QObject *>(item, "Drag.target"), static_cast<QObject *>(&rightTarget)); QCOMPARE(evaluate<QObject *>(item, "dragTarget"), static_cast<QObject *>(&rightTarget)); - QCOMPARE(outerTarget.enterEvents, 0); QCOMPARE(outerTarget.leaveEvents, 0); QCOMPARE(outerTarget.moveEvents, 1); + QCOMPARE(outerTarget.enterEvents, 0); QCOMPARE(outerTarget.leaveEvents, 0); QCOMPARE(outerTarget.moveEvents, 0); QCOMPARE(leftTarget .enterEvents, 0); QCOMPARE(leftTarget .leaveEvents, 0); QCOMPARE(leftTarget .moveEvents, 0); QCOMPARE(rightTarget.enterEvents, 1); QCOMPARE(rightTarget.leaveEvents, 0); QCOMPARE(rightTarget.moveEvents, 0); - QCOMPARE(outerTarget.position.x(), qreal(75)); QCOMPARE(outerTarget.position.y(), qreal(50)); QCOMPARE(rightTarget.position.x(), qreal(5)); QCOMPARE(rightTarget.position.y(), qreal(15)); // Move into the left target. @@ -596,10 +584,9 @@ void tst_QQuickDrag::move() QCoreApplication::processEvents(); QCOMPARE(evaluate<QObject *>(item, "Drag.target"), static_cast<QObject *>(&leftTarget)); QCOMPARE(evaluate<QObject *>(item, "dragTarget"), static_cast<QObject *>(&leftTarget)); - QCOMPARE(outerTarget.enterEvents, 0); QCOMPARE(outerTarget.leaveEvents, 0); QCOMPARE(outerTarget.moveEvents, 1); + QCOMPARE(outerTarget.enterEvents, 0); QCOMPARE(outerTarget.leaveEvents, 0); QCOMPARE(outerTarget.moveEvents, 0); QCOMPARE(leftTarget .enterEvents, 1); QCOMPARE(leftTarget .leaveEvents, 0); QCOMPARE(leftTarget .moveEvents, 0); QCOMPARE(rightTarget.enterEvents, 0); QCOMPARE(rightTarget.leaveEvents, 1); QCOMPARE(rightTarget.moveEvents, 0); - QCOMPARE(outerTarget.position.x(), qreal(25)); QCOMPARE(outerTarget.position.y(), qreal(50)); QCOMPARE(leftTarget.position.x(), qreal(25)); QCOMPARE(leftTarget.position.y(), qreal(15)); // Move within the left target. diff --git a/tests/auto/quick/qquickdroparea/tst_qquickdroparea.cpp b/tests/auto/quick/qquickdroparea/tst_qquickdroparea.cpp index b65e766190..375613e3c7 100644 --- a/tests/auto/quick/qquickdroparea/tst_qquickdroparea.cpp +++ b/tests/auto/quick/qquickdroparea/tst_qquickdroparea.cpp @@ -84,6 +84,7 @@ private slots: void position_external(); void drop_internal(); // void drop_external(); + void competingDrags(); void simultaneousDrags(); private: @@ -767,6 +768,50 @@ void tst_QQuickDropArea::drop_internal() //{ //} +void tst_QQuickDropArea::competingDrags() +{ + QQuickWindow window; + QQmlComponent component(&engine); + component.setData( + "import QtQuick 2.0\n" + "DropArea {\n" + "width: 100; height: 100\n" + "objectName: \"dropArea1\"\n" + "property string statuslol\n" + "onEntered: { statuslol = 'parent' }\n" + "DropArea {\n" + "objectName: \"dropArea2\"\n" + "width: 100; height: 100\n" + "property bool acceptsEnters: true\n" + "onEntered: { parent.statuslol = 'son'; drag.accepted = acceptsEnters; }\n" + "}\n" + "Item {\n" + "objectName: \"dragItem\"\n" + "x: 50; y: 50\n" + "width: 10; height: 10\n" + "}\n" + "}\n", QUrl()); + + QScopedPointer<QObject> object(component.create()); + QQuickItem *dropArea1 = qobject_cast<QQuickItem *>(object.data()); + QVERIFY(dropArea1); + dropArea1->setParentItem(window.contentItem()); + + QQuickItem *dropArea2 = dropArea1->findChild<QQuickItem *>("dropArea2"); + QVERIFY(dropArea2); + + QQuickItem *dragItem = dropArea1->findChild<QQuickItem *>("dragItem"); + QVERIFY(dragItem); + + QCOMPARE(evaluate<QString>(dropArea1, "statuslol"), QStringLiteral("")); + evaluate<void>(dragItem, "Drag.active = true"); + QCOMPARE(evaluate<QString>(dropArea1, "statuslol"), QStringLiteral("son")); + evaluate<void>(dragItem, "Drag.active = false"); + evaluate<void>(dropArea2, "acceptsEnters = false"); + evaluate<void>(dragItem, "Drag.active = true"); + QCOMPARE(evaluate<QString>(dropArea1, "statuslol"), QStringLiteral("parent")); +} + void tst_QQuickDropArea::simultaneousDrags() { QQuickWindow window; @@ -777,6 +822,7 @@ void tst_QQuickDropArea::simultaneousDrags() "property int enterEvents: 0\n" "property int exitEvents: 0\n" "width: 100; height: 100\n" + "objectName: \"dropArea1\"\n" "keys: [\"red\", \"text/x-red\"]\n" "onEntered: {++enterEvents}\n" "onExited: {++exitEvents}\n" @@ -827,8 +873,8 @@ void tst_QQuickDropArea::simultaneousDrags() evaluate<void>(dropArea1, "{ enterEvents = 0; exitEvents = 0 }"); evaluate<void>(dropArea2, "{ enterEvents = 0; exitEvents = 0 }"); evaluate<void>(dragItem1, "Drag.active = true"); - QCOMPARE(evaluate<bool>(dropArea1, "containsDrag"), true); - QCOMPARE(evaluate<int>(dropArea1, "enterEvents"), 1); + QCOMPARE(evaluate<bool>(dropArea1, "containsDrag"), false); + QCOMPARE(evaluate<int>(dropArea1, "enterEvents"), 0); QCOMPARE(evaluate<int>(dropArea1, "exitEvents"), 0); QCOMPARE(evaluate<bool>(dropArea2, "containsDrag"), true); QCOMPARE(evaluate<int>(dropArea2, "enterEvents"), 1); @@ -837,32 +883,33 @@ void tst_QQuickDropArea::simultaneousDrags() evaluate<void>(dropArea1, "{ enterEvents = 0; exitEvents = 0 }"); evaluate<void>(dropArea2, "{ enterEvents = 0; exitEvents = 0 }"); evaluate<void>(dragItem2, "Drag.active = true"); + //DropArea discards events if already contains something being dragged in QCOMPARE(evaluate<bool>(dropArea1, "containsDrag"), true); - QCOMPARE(evaluate<int>(dropArea1, "enterEvents"), 0); + QCOMPARE(evaluate<int>(dropArea1, "enterEvents"), 1); QCOMPARE(evaluate<int>(dropArea1, "exitEvents"), 0); QCOMPARE(evaluate<bool>(dropArea2, "containsDrag"), true); QCOMPARE(evaluate<int>(dropArea2, "enterEvents"), 0); QCOMPARE(evaluate<int>(dropArea2, "exitEvents"), 0); evaluate<void>(dragItem2, "Drag.active = false"); - QCOMPARE(evaluate<bool>(dropArea1, "containsDrag"), true); - QCOMPARE(evaluate<int>(dropArea1, "enterEvents"), 0); - QCOMPARE(evaluate<int>(dropArea1, "exitEvents"), 0); + QCOMPARE(evaluate<bool>(dropArea1, "containsDrag"), false); + QCOMPARE(evaluate<int>(dropArea1, "enterEvents"), 1); + QCOMPARE(evaluate<int>(dropArea1, "exitEvents"), 1); QCOMPARE(evaluate<bool>(dropArea2, "containsDrag"), true); QCOMPARE(evaluate<int>(dropArea2, "enterEvents"), 0); QCOMPARE(evaluate<int>(dropArea2, "exitEvents"), 0); evaluate<void>(dragItem2, "Drag.active = true"); QCOMPARE(evaluate<bool>(dropArea1, "containsDrag"), true); - QCOMPARE(evaluate<int>(dropArea1, "enterEvents"), 0); - QCOMPARE(evaluate<int>(dropArea1, "exitEvents"), 0); + QCOMPARE(evaluate<int>(dropArea1, "enterEvents"), 2); + QCOMPARE(evaluate<int>(dropArea1, "exitEvents"), 1); QCOMPARE(evaluate<bool>(dropArea2, "containsDrag"), true); QCOMPARE(evaluate<int>(dropArea2, "enterEvents"), 0); QCOMPARE(evaluate<int>(dropArea2, "exitEvents"), 0); evaluate<void>(dragItem1, "Drag.active = false"); - QCOMPARE(evaluate<bool>(dropArea1, "containsDrag"), false); - QCOMPARE(evaluate<int>(dropArea1, "enterEvents"), 0); + QCOMPARE(evaluate<bool>(dropArea1, "containsDrag"), true); + QCOMPARE(evaluate<int>(dropArea1, "enterEvents"), 2); QCOMPARE(evaluate<int>(dropArea1, "exitEvents"), 1); QCOMPARE(evaluate<bool>(dropArea2, "containsDrag"), false); QCOMPARE(evaluate<int>(dropArea2, "enterEvents"), 0); @@ -873,7 +920,7 @@ void tst_QQuickDropArea::simultaneousDrags() evaluate<void>(dragItem2, "Drag.active = false"); QCOMPARE(evaluate<bool>(dropArea1, "containsDrag"), false); QCOMPARE(evaluate<int>(dropArea1, "enterEvents"), 0); - QCOMPARE(evaluate<int>(dropArea1, "exitEvents"), 0); + QCOMPARE(evaluate<int>(dropArea1, "exitEvents"), 1); QCOMPARE(evaluate<bool>(dropArea2, "containsDrag"), false); QCOMPARE(evaluate<int>(dropArea2, "enterEvents"), 0); QCOMPARE(evaluate<int>(dropArea2, "exitEvents"), 0); @@ -882,8 +929,8 @@ void tst_QQuickDropArea::simultaneousDrags() evaluate<void>(dropArea1, "{ enterEvents = 0; exitEvents = 0 }"); evaluate<void>(dropArea2, "{ enterEvents = 0; exitEvents = 0 }"); evaluate<void>(dragItem1, "Drag.active = true"); - QCOMPARE(evaluate<bool>(dropArea1, "containsDrag"), true); - QCOMPARE(evaluate<int>(dropArea1, "enterEvents"), 1); + QCOMPARE(evaluate<bool>(dropArea1, "containsDrag"), false); + QCOMPARE(evaluate<int>(dropArea1, "enterEvents"), 0); QCOMPARE(evaluate<int>(dropArea1, "exitEvents"), 0); QCOMPARE(evaluate<bool>(dropArea2, "containsDrag"), true); QCOMPARE(evaluate<int>(dropArea2, "enterEvents"), 1); @@ -892,32 +939,33 @@ void tst_QQuickDropArea::simultaneousDrags() evaluate<void>(dropArea1, "{ enterEvents = 0; exitEvents = 0 }"); evaluate<void>(dropArea2, "{ enterEvents = 0; exitEvents = 0 }"); QWindowSystemInterface::handleDrag(&window, &data, QPoint(50, 50), Qt::CopyAction); + //Same as in the first case, dropArea2 already contains a drag, dropArea1 will get the event QCOMPARE(evaluate<bool>(dropArea1, "containsDrag"), true); - QCOMPARE(evaluate<int>(dropArea1, "enterEvents"), 0); + QCOMPARE(evaluate<int>(dropArea1, "enterEvents"), 1); QCOMPARE(evaluate<int>(dropArea1, "exitEvents"), 0); QCOMPARE(evaluate<bool>(dropArea2, "containsDrag"), true); QCOMPARE(evaluate<int>(dropArea2, "enterEvents"), 0); QCOMPARE(evaluate<int>(dropArea2, "exitEvents"), 0); QWindowSystemInterface::handleDrag(&alternateWindow, &data, QPoint(50, 50), Qt::CopyAction); - QCOMPARE(evaluate<bool>(dropArea1, "containsDrag"), true); - QCOMPARE(evaluate<int>(dropArea1, "enterEvents"), 0); - QCOMPARE(evaluate<int>(dropArea1, "exitEvents"), 0); + QCOMPARE(evaluate<bool>(dropArea1, "containsDrag"), false); + QCOMPARE(evaluate<int>(dropArea1, "enterEvents"), 1); + QCOMPARE(evaluate<int>(dropArea1, "exitEvents"), 1); QCOMPARE(evaluate<bool>(dropArea2, "containsDrag"), true); QCOMPARE(evaluate<int>(dropArea2, "enterEvents"), 0); QCOMPARE(evaluate<int>(dropArea2, "exitEvents"), 0); QWindowSystemInterface::handleDrag(&window, &data, QPoint(50, 50), Qt::CopyAction); QCOMPARE(evaluate<bool>(dropArea1, "containsDrag"), true); - QCOMPARE(evaluate<int>(dropArea1, "enterEvents"), 0); - QCOMPARE(evaluate<int>(dropArea1, "exitEvents"), 0); + QCOMPARE(evaluate<int>(dropArea1, "enterEvents"), 2); + QCOMPARE(evaluate<int>(dropArea1, "exitEvents"), 1); QCOMPARE(evaluate<bool>(dropArea2, "containsDrag"), true); QCOMPARE(evaluate<int>(dropArea2, "enterEvents"), 0); QCOMPARE(evaluate<int>(dropArea2, "exitEvents"), 0); evaluate<void>(dragItem1, "Drag.active = false"); - QCOMPARE(evaluate<bool>(dropArea1, "containsDrag"), false); - QCOMPARE(evaluate<int>(dropArea1, "enterEvents"), 0); + QCOMPARE(evaluate<bool>(dropArea1, "containsDrag"), true); + QCOMPARE(evaluate<int>(dropArea1, "enterEvents"), 2); QCOMPARE(evaluate<int>(dropArea1, "exitEvents"), 1); QCOMPARE(evaluate<bool>(dropArea2, "containsDrag"), false); QCOMPARE(evaluate<int>(dropArea2, "enterEvents"), 0); @@ -928,7 +976,7 @@ void tst_QQuickDropArea::simultaneousDrags() QWindowSystemInterface::handleDrag(&alternateWindow, &data, QPoint(50, 50), Qt::CopyAction); QCOMPARE(evaluate<bool>(dropArea1, "containsDrag"), false); QCOMPARE(evaluate<int>(dropArea1, "enterEvents"), 0); - QCOMPARE(evaluate<int>(dropArea1, "exitEvents"), 0); + QCOMPARE(evaluate<int>(dropArea1, "exitEvents"), 1); QCOMPARE(evaluate<bool>(dropArea2, "containsDrag"), false); QCOMPARE(evaluate<int>(dropArea2, "enterEvents"), 0); QCOMPARE(evaluate<int>(dropArea2, "exitEvents"), 0); @@ -937,8 +985,8 @@ void tst_QQuickDropArea::simultaneousDrags() evaluate<void>(dropArea1, "{ enterEvents = 0; exitEvents = 0 }"); evaluate<void>(dropArea2, "{ enterEvents = 0; exitEvents = 0 }"); QWindowSystemInterface::handleDrag(&window, &data, QPoint(50, 50), Qt::CopyAction); - QCOMPARE(evaluate<bool>(dropArea1, "containsDrag"), true); - QCOMPARE(evaluate<int>(dropArea1, "enterEvents"), 1); + QCOMPARE(evaluate<bool>(dropArea1, "containsDrag"), false); + QCOMPARE(evaluate<int>(dropArea1, "enterEvents"), 0); QCOMPARE(evaluate<int>(dropArea1, "exitEvents"), 0); QCOMPARE(evaluate<bool>(dropArea2, "containsDrag"), true); QCOMPARE(evaluate<int>(dropArea2, "enterEvents"), 1); @@ -948,31 +996,31 @@ void tst_QQuickDropArea::simultaneousDrags() evaluate<void>(dropArea2, "{ enterEvents = 0; exitEvents = 0 }"); evaluate<void>(dragItem2, "Drag.active = true"); QCOMPARE(evaluate<bool>(dropArea1, "containsDrag"), true); - QCOMPARE(evaluate<int>(dropArea1, "enterEvents"), 0); + QCOMPARE(evaluate<int>(dropArea1, "enterEvents"), 1); QCOMPARE(evaluate<int>(dropArea1, "exitEvents"), 0); QCOMPARE(evaluate<bool>(dropArea2, "containsDrag"), true); QCOMPARE(evaluate<int>(dropArea2, "enterEvents"), 0); QCOMPARE(evaluate<int>(dropArea2, "exitEvents"), 0); evaluate<void>(dragItem2, "Drag.active = false"); - QCOMPARE(evaluate<bool>(dropArea1, "containsDrag"), true); - QCOMPARE(evaluate<int>(dropArea1, "enterEvents"), 0); - QCOMPARE(evaluate<int>(dropArea1, "exitEvents"), 0); + QCOMPARE(evaluate<bool>(dropArea1, "containsDrag"), false); + QCOMPARE(evaluate<int>(dropArea1, "enterEvents"), 1); + QCOMPARE(evaluate<int>(dropArea1, "exitEvents"), 1); QCOMPARE(evaluate<bool>(dropArea2, "containsDrag"), true); QCOMPARE(evaluate<int>(dropArea2, "enterEvents"), 0); QCOMPARE(evaluate<int>(dropArea2, "exitEvents"), 0); evaluate<void>(dragItem2, "Drag.active = true"); QCOMPARE(evaluate<bool>(dropArea1, "containsDrag"), true); - QCOMPARE(evaluate<int>(dropArea1, "enterEvents"), 0); - QCOMPARE(evaluate<int>(dropArea1, "exitEvents"), 0); + QCOMPARE(evaluate<int>(dropArea1, "enterEvents"), 2); + QCOMPARE(evaluate<int>(dropArea1, "exitEvents"), 1); QCOMPARE(evaluate<bool>(dropArea2, "containsDrag"), true); QCOMPARE(evaluate<int>(dropArea2, "enterEvents"), 0); QCOMPARE(evaluate<int>(dropArea2, "exitEvents"), 0); QWindowSystemInterface::handleDrag(&alternateWindow, &data, QPoint(50, 50), Qt::CopyAction); - QCOMPARE(evaluate<bool>(dropArea1, "containsDrag"), false); - QCOMPARE(evaluate<int>(dropArea1, "enterEvents"), 0); + QCOMPARE(evaluate<bool>(dropArea1, "containsDrag"), true); + QCOMPARE(evaluate<int>(dropArea1, "enterEvents"), 2); QCOMPARE(evaluate<int>(dropArea1, "exitEvents"), 1); QCOMPARE(evaluate<bool>(dropArea2, "containsDrag"), false); QCOMPARE(evaluate<int>(dropArea2, "enterEvents"), 0); @@ -983,7 +1031,7 @@ void tst_QQuickDropArea::simultaneousDrags() evaluate<void>(dragItem2, "Drag.active = false"); QCOMPARE(evaluate<bool>(dropArea1, "containsDrag"), false); QCOMPARE(evaluate<int>(dropArea1, "enterEvents"), 0); - QCOMPARE(evaluate<int>(dropArea1, "exitEvents"), 0); + QCOMPARE(evaluate<int>(dropArea1, "exitEvents"), 1); QCOMPARE(evaluate<bool>(dropArea2, "containsDrag"), false); QCOMPARE(evaluate<int>(dropArea2, "enterEvents"), 0); QCOMPARE(evaluate<int>(dropArea2, "exitEvents"), 0); diff --git a/tests/auto/quick/qquickflickable/data/nestedClickThenFlick.qml b/tests/auto/quick/qquickflickable/data/nestedClickThenFlick.qml new file mode 100644 index 0000000000..619ab6d1dc --- /dev/null +++ b/tests/auto/quick/qquickflickable/data/nestedClickThenFlick.qml @@ -0,0 +1,39 @@ +import QtQuick 2.0 + +Flickable { + property bool pressed: ma.pressed + width: 240 + height: 320 + contentWidth: 480 + contentHeight: 320 + flickableDirection: Flickable.HorizontalFlick + pressDelay: 50 + Rectangle { + anchors.fill: parent + anchors.margins: 50 + color: "yellow" + + } + + onMovingChanged: console.log("outer moving", moving) + + Flickable { + objectName: "innerFlickable" + anchors.fill: parent + flickableDirection: Flickable.VerticalFlick + contentWidth: 480 + contentHeight: 1480 + pressDelay: 50 + Rectangle { + anchors.fill: parent + anchors.margins: 100 + color: ma.pressed ? 'blue' : 'green' + } + MouseArea { + id: ma + objectName: "mouseArea" + anchors.fill: parent + } + } +} + diff --git a/tests/auto/quick/qquickflickable/tst_qquickflickable.cpp b/tests/auto/quick/qquickflickable/tst_qquickflickable.cpp index 8ab86bf2d3..80aaf5895f 100644 --- a/tests/auto/quick/qquickflickable/tst_qquickflickable.cpp +++ b/tests/auto/quick/qquickflickable/tst_qquickflickable.cpp @@ -75,6 +75,7 @@ private slots: void flickDeceleration(); void pressDelay(); void nestedPressDelay(); + void nestedClickThenFlick(); void flickableDirection(); void resizeContent(); void returnToBounds(); @@ -100,7 +101,7 @@ private slots: void pressDelayWithLoader(); private: - void flickWithTouch(QWindow *window, QTouchDevice *touchDevice, const QPoint &from, const QPoint &to); + void flickWithTouch(QQuickWindow *window, QTouchDevice *touchDevice, const QPoint &from, const QPoint &to); QQmlEngine engine; }; @@ -513,6 +514,51 @@ void tst_qquickflickable::nestedPressDelay() QTest::mouseRelease(window.data(), Qt::LeftButton, 0, QPoint(90, 150)); } +// QTBUG-37316 +void tst_qquickflickable::nestedClickThenFlick() +{ + QScopedPointer<QQuickView> window(new QQuickView); + window->setSource(testFileUrl("nestedClickThenFlick.qml")); + QTRY_COMPARE(window->status(), QQuickView::Ready); + QQuickViewTestUtil::centerOnScreen(window.data()); + QQuickViewTestUtil::moveMouseAway(window.data()); + window->show(); + QVERIFY(QTest::qWaitForWindowExposed(window.data())); + QVERIFY(window->rootObject() != 0); + + QQuickFlickable *outer = qobject_cast<QQuickFlickable*>(window->rootObject()); + QVERIFY(outer != 0); + + QQuickFlickable *inner = window->rootObject()->findChild<QQuickFlickable*>("innerFlickable"); + QVERIFY(inner != 0); + + QTest::mousePress(window.data(), Qt::LeftButton, 0, QPoint(150, 150)); + + // the MouseArea is not pressed immediately + QVERIFY(outer->property("pressed").toBool() == false); + QTRY_VERIFY(outer->property("pressed").toBool() == true); + + QTest::mouseRelease(window.data(), Qt::LeftButton, 0, QPoint(150, 150)); + + QVERIFY(outer->property("pressed").toBool() == false); + + // Dragging inner Flickable should work + QTest::mousePress(window.data(), Qt::LeftButton, 0, QPoint(80, 150)); + // the MouseArea is not pressed immediately + + QVERIFY(outer->property("pressed").toBool() == false); + + QTest::mouseMove(window.data(), QPoint(80, 148)); + QTest::mouseMove(window.data(), QPoint(80, 140)); + QTest::mouseMove(window.data(), QPoint(80, 120)); + QTest::mouseMove(window.data(), QPoint(80, 100)); + + QVERIFY(outer->property("moving").toBool() == false); + QVERIFY(inner->property("moving").toBool() == true); + + QTest::mouseRelease(window.data(), Qt::LeftButton, 0, QPoint(80, 100)); +} + void tst_qquickflickable::flickableDirection() { QQmlComponent component(&engine); @@ -1349,20 +1395,18 @@ void tst_qquickflickable::flickTwiceUsingTouches() QTRY_VERIFY(contentYAfterSecondFlick > (contentYAfterFirstFlick + 80.0f)); } -void tst_qquickflickable::flickWithTouch(QWindow *window, QTouchDevice *touchDevice, const QPoint &from, const QPoint &to) +void tst_qquickflickable::flickWithTouch(QQuickWindow *window, QTouchDevice *touchDevice, const QPoint &from, const QPoint &to) { - QTest::touchEvent(window, touchDevice) - .press(0, from, window); - QTest::qWait(1); + QTest::touchEvent(window, touchDevice).press(0, from, window); + QQuickTouchUtils::flush(window); + QPoint diff = to - from; for (int i = 1; i <= 8; ++i) { - QTest::touchEvent(window, touchDevice) - .move(0, from + i*diff/8, window); - QTest::qWait(1); + QTest::touchEvent(window, touchDevice).move(0, from + i*diff/8, window); + QQuickTouchUtils::flush(window); } - QTest::touchEvent(window, touchDevice) - .release(0, to, window); - QTest::qWait(1); + QTest::touchEvent(window, touchDevice).release(0, to, window); + QQuickTouchUtils::flush(window); } void tst_qquickflickable::nestedStopAtBounds_data() diff --git a/tests/auto/quick/qquickfontloader/tst_qquickfontloader.cpp b/tests/auto/quick/qquickfontloader/tst_qquickfontloader.cpp index bcb496eab7..225cdb5389 100644 --- a/tests/auto/quick/qquickfontloader/tst_qquickfontloader.cpp +++ b/tests/auto/quick/qquickfontloader/tst_qquickfontloader.cpp @@ -75,8 +75,7 @@ private: TestHTTPServer server; }; -tst_qquickfontloader::tst_qquickfontloader() : - server(SERVER_PORT) +tst_qquickfontloader::tst_qquickfontloader() { } @@ -84,7 +83,7 @@ void tst_qquickfontloader::initTestCase() { QQmlDataTest::initTestCase(); server.serveDirectory(dataDirectory()); - QVERIFY(server.isValid()); + QVERIFY2(server.listen(SERVER_PORT), qPrintable(server.errorString())); } void tst_qquickfontloader::noFont() @@ -131,7 +130,7 @@ void tst_qquickfontloader::localFont() void tst_qquickfontloader::failLocalFont() { QString componentStr = "import QtQuick 2.0\nFontLoader { source: \"" + testFileUrl("dummy.ttf").toString() + "\" }"; - QTest::ignoreMessage(QtWarningMsg, QString("file::2:1: QML FontLoader: Cannot load font: \"" + testFileUrl("dummy.ttf").toString() + "\"").toUtf8().constData()); + QTest::ignoreMessage(QtWarningMsg, QString("<Unknown File>:2:1: QML FontLoader: Cannot load font: \"" + testFileUrl("dummy.ttf").toString() + "\"").toUtf8().constData()); QQmlComponent component(&engine); component.setData(componentStr.toLatin1(), QUrl::fromLocalFile("")); QQuickFontLoader *fontObject = qobject_cast<QQuickFontLoader*>(component.create()); @@ -175,7 +174,7 @@ void tst_qquickfontloader::redirWebFont() void tst_qquickfontloader::failWebFont() { QString componentStr = "import QtQuick 2.0\nFontLoader { source: \"" SERVER_ADDR "/nonexist.ttf\" }"; - QTest::ignoreMessage(QtWarningMsg, "file::2:1: QML FontLoader: Cannot load font: \"" SERVER_ADDR "/nonexist.ttf\""); + QTest::ignoreMessage(QtWarningMsg, "<Unknown File>:2:1: QML FontLoader: Cannot load font: \"" SERVER_ADDR "/nonexist.ttf\""); QQmlComponent component(&engine); component.setData(componentStr.toLatin1(), QUrl::fromLocalFile("")); QQuickFontLoader *fontObject = qobject_cast<QQuickFontLoader*>(component.create()); diff --git a/tests/auto/quick/qquickfontmetrics/qquickfontmetrics.pro b/tests/auto/quick/qquickfontmetrics/qquickfontmetrics.pro new file mode 100644 index 0000000000..452dd70bd3 --- /dev/null +++ b/tests/auto/quick/qquickfontmetrics/qquickfontmetrics.pro @@ -0,0 +1,10 @@ +CONFIG += testcase +TARGET = tst_quickfontmetrics +osx:CONFIG -= app_bundle + +SOURCES += tst_quickfontmetrics.cpp + +CONFIG += parallel_test + +QT += core gui qml quick-private testlib +DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0 diff --git a/tests/auto/quick/qquickfontmetrics/tst_quickfontmetrics.cpp b/tests/auto/quick/qquickfontmetrics/tst_quickfontmetrics.cpp new file mode 100644 index 0000000000..5e64858955 --- /dev/null +++ b/tests/auto/quick/qquickfontmetrics/tst_quickfontmetrics.cpp @@ -0,0 +1,150 @@ +/**************************************************************************** +** +** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the QtQml module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Digia gives you certain additional +** rights. These rights are described in the Digia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include <QFont> +#include <QFontDatabase> +#include <QString> +#include <QtTest> +#include <QCoreApplication> + +#include <QtQuick/private/qquickfontmetrics_p.h> + +#include <QFontMetricsF> + +class tst_QuickFontMetrics : public QObject +{ + Q_OBJECT + +public: + tst_QuickFontMetrics(); + +private Q_SLOTS: + void properties(); + void functions_data(); + void functions(); +}; + +tst_QuickFontMetrics::tst_QuickFontMetrics() +{ +} + +void tst_QuickFontMetrics::properties() +{ + QStringList families = QFontDatabase().families().mid(0, 10); + QQuickFontMetrics metrics; + + foreach (const QString &family, families) { + QFont font(family); + QFontMetricsF expected(font); + + QSignalSpy spy(&metrics, SIGNAL(fontChanged(QFont))); + metrics.setFont(font); + QCOMPARE(spy.count(), 1); + + QCOMPARE(metrics.ascent(), expected.ascent()); + QCOMPARE(metrics.descent(), expected.descent()); + QCOMPARE(metrics.height(), expected.height()); + QCOMPARE(metrics.leading(), expected.leading()); + QCOMPARE(metrics.lineSpacing(), expected.lineSpacing()); + QCOMPARE(metrics.minimumLeftBearing(), expected.minLeftBearing()); + QCOMPARE(metrics.minimumRightBearing(), expected.minRightBearing()); + QCOMPARE(metrics.maximumCharacterWidth(), expected.maxWidth()); + QCOMPARE(metrics.xHeight(), expected.xHeight()); + QCOMPARE(metrics.averageCharacterWidth(), expected.averageCharWidth()); + QCOMPARE(metrics.underlinePosition(), expected.underlinePos()); + QCOMPARE(metrics.overlinePosition(), expected.overlinePos()); + QCOMPARE(metrics.strikeOutPosition(), expected.strikeOutPos()); + QCOMPARE(metrics.lineWidth(), expected.lineWidth()); + } +} + +Q_DECLARE_METATYPE(Qt::TextElideMode) + +void tst_QuickFontMetrics::functions_data() +{ + QTest::addColumn<QString>("text"); + QTest::addColumn<Qt::TextElideMode>("mode"); + QTest::addColumn<qreal>("width"); + QTest::addColumn<int>("flags"); + + QStringList strings; + strings << QString() + << QString::fromLatin1("") + << QString::fromLatin1("0") + << QString::fromLatin1("@@@@@@@") + << QString::fromLatin1("Hello"); + + QVector<Qt::TextElideMode> elideModes; + elideModes << Qt::ElideLeft << Qt::ElideMiddle << Qt::ElideRight << Qt::ElideNone; + + for (int stringIndex = 0; stringIndex < strings.size(); ++stringIndex) { + const QString string = strings.at(stringIndex); + + for (int elideModeIndex = 0; elideModeIndex < elideModes.size(); ++elideModeIndex) { + Qt::TextElideMode elideMode = static_cast<Qt::TextElideMode>(elideModes.at(elideModeIndex)); + + for (qreal width = 0; width < 100; width += 20) { + const QString tag = QString::fromLatin1("string=%1, mode=%2, width=%3").arg(string).arg(elideMode).arg(width); + QTest::newRow(qPrintable(tag)) << QString() << elideMode << width << 0; + } + } + } +} + +void tst_QuickFontMetrics::functions() +{ + QFETCH(QString, text); + QFETCH(Qt::TextElideMode, mode); + QFETCH(qreal, width); + QFETCH(int, flags); + + QQuickFontMetrics metrics; + QFontMetricsF expected = QFontMetricsF(QFont()); + + QCOMPARE(metrics.elidedText(text, mode, width, flags), expected.elidedText(text, mode, width, flags)); + QCOMPARE(metrics.advanceWidth(text), expected.width(text)); + QCOMPARE(metrics.boundingRect(text), expected.boundingRect(text)); + QCOMPARE(metrics.tightBoundingRect(text), expected.tightBoundingRect(text)); +} + +QTEST_MAIN(tst_QuickFontMetrics) + +#include "tst_quickfontmetrics.moc" diff --git a/tests/auto/quick/qquickframebufferobject/tst_qquickframebufferobject.cpp b/tests/auto/quick/qquickframebufferobject/tst_qquickframebufferobject.cpp index b7b58c6d3d..35a01b33ba 100644 --- a/tests/auto/quick/qquickframebufferobject/tst_qquickframebufferobject.cpp +++ b/tests/auto/quick/qquickframebufferobject/tst_qquickframebufferobject.cpp @@ -45,6 +45,7 @@ #include <QtQuick/qquickview.h> #include <QtGui/qopenglcontext.h> #include <QtGui/qopenglframebufferobject.h> +#include <QtGui/qopenglfunctions.h> #include <QtQuick/QQuickFramebufferObject> @@ -62,7 +63,7 @@ struct FrameInfo { QSize fboSize; } frameInfo; -class ColorRenderer : public QQuickFramebufferObject::Renderer +class ColorRenderer : public QQuickFramebufferObject::Renderer, protected QOpenGLFunctions { public: void render(); @@ -142,6 +143,7 @@ void ColorRenderer::synchronize(QQuickFramebufferObject *item) QOpenGLFramebufferObject *ColorRenderer::createFramebufferObject(const QSize &size) { + initializeOpenGLFunctions(); frameInfo.createFBOCount++; QOpenGLFramebufferObjectFormat format; if (msaa) diff --git a/tests/auto/quick/qquickimage/tst_qquickimage.cpp b/tests/auto/quick/qquickimage/tst_qquickimage.cpp index 0e012c5c6a..a68a763887 100644 --- a/tests/auto/quick/qquickimage/tst_qquickimage.cpp +++ b/tests/auto/quick/qquickimage/tst_qquickimage.cpp @@ -153,9 +153,9 @@ void tst_qquickimage::imageSource_data() QTest::newRow("local no cache") << testFileUrl("colors.png").toString() << 120.0 << 120.0 << false << false << false << ""; QTest::newRow("local async") << testFileUrl("colors1.png").toString() << 120.0 << 120.0 << false << true << true << ""; QTest::newRow("local not found") << testFileUrl("no-such-file.png").toString() << 0.0 << 0.0 << false - << false << true << "file::2:1: QML Image: Cannot open: " + testFileUrl("no-such-file.png").toString(); + << false << true << "<Unknown File>:2:1: QML Image: Cannot open: " + testFileUrl("no-such-file.png").toString(); QTest::newRow("local async not found") << testFileUrl("no-such-file-1.png").toString() << 0.0 << 0.0 << false - << true << true << "file::2:1: QML Image: Cannot open: " + testFileUrl("no-such-file-1.png").toString(); + << true << true << "<Unknown File>:2:1: QML Image: Cannot open: " + testFileUrl("no-such-file-1.png").toString(); QTest::newRow("remote") << SERVER_ADDR "/colors.png" << 120.0 << 120.0 << true << false << true << ""; QTest::newRow("remote redirected") << SERVER_ADDR "/oldcolors.png" << 120.0 << 120.0 << true << false << false << ""; if (QImageReader::supportedImageFormats().contains("svg")) @@ -163,7 +163,7 @@ void tst_qquickimage::imageSource_data() if (QImageReader::supportedImageFormats().contains("svgz")) QTest::newRow("remote svgz") << SERVER_ADDR "/heart.svgz" << 550.0 << 500.0 << true << false << false << ""; QTest::newRow("remote not found") << SERVER_ADDR "/no-such-file.png" << 0.0 << 0.0 << true - << false << true << "file::2:1: QML Image: Error downloading " SERVER_ADDR "/no-such-file.png - server replied: Not found"; + << false << true << "<Unknown File>:2:1: QML Image: Error downloading " SERVER_ADDR "/no-such-file.png - server replied: Not found"; } @@ -177,9 +177,9 @@ void tst_qquickimage::imageSource() QFETCH(bool, cache); QFETCH(QString, error); - TestHTTPServer server(SERVER_PORT); + TestHTTPServer server; if (remote) { - QVERIFY(server.isValid()); + QVERIFY2(server.listen(SERVER_PORT), qPrintable(server.errorString())); server.serveDirectory(dataDirectory()); server.addRedirect("oldcolors.png", SERVER_ADDR "/colors.png"); } @@ -263,8 +263,9 @@ void tst_qquickimage::resized() void tst_qquickimage::preserveAspectRatio() { - QQuickView *window = new QQuickView(0); + QScopedPointer<QQuickView> window(new QQuickView(0)); window->show(); + QVERIFY(QTest::qWaitForWindowExposed(window.data())); window->setSource(testFileUrl("aspectratio.qml")); QQuickImage *image = qobject_cast<QQuickImage*>(window->rootObject()); @@ -279,7 +280,6 @@ void tst_qquickimage::preserveAspectRatio() QVERIFY(image != 0); QCOMPARE(image->height(), 60.); QCOMPARE(image->width(), 60.); - delete window; } void tst_qquickimage::smooth() @@ -312,7 +312,7 @@ void tst_qquickimage::mirror() QWindow dummy; // On BlackBerry first window is always full screen, dummy.showFullScreen(); // so make test window a second window. #endif - QQuickView *window = new QQuickView; + QScopedPointer<QQuickView> window(new QQuickView); window->setSource(testFileUrl("mirror.qml")); QQuickImage *obj = window->rootObject()->findChild<QQuickImage*>("image"); @@ -321,11 +321,10 @@ void tst_qquickimage::mirror() obj->setFillMode(fillMode); obj->setProperty("mirror", true); window->showNormal(); - QVERIFY(QTest::qWaitForWindowExposed(window)); + QVERIFY(QTest::qWaitForWindowExposed(window.data())); QImage screenshot = window->grabWindow(); screenshots[fillMode] = screenshot; - delete window; } foreach (QQuickImage::FillMode fillMode, fillModes) { @@ -529,8 +528,8 @@ void tst_qquickimage::noLoading() { qRegisterMetaType<QQuickImageBase::Status>(); - TestHTTPServer server(SERVER_PORT); - QVERIFY(server.isValid()); + TestHTTPServer server; + QVERIFY2(server.listen(SERVER_PORT), qPrintable(server.errorString())); server.serveDirectory(dataDirectory()); server.addRedirect("oldcolors.png", SERVER_ADDR "/colors.png"); @@ -644,10 +643,10 @@ void tst_qquickimage::sourceSize_QTBUG_14303() void tst_qquickimage::sourceSize_QTBUG_16389() { - QQuickView *window = new QQuickView(0); + QScopedPointer<QQuickView> window(new QQuickView(0)); window->setSource(testFileUrl("qtbug_16389.qml")); window->show(); - qApp->processEvents(); + QVERIFY(QTest::qWaitForWindowExposed(window.data())); QQuickImage *image = findItem<QQuickImage>(window->rootObject(), "iconImage"); QQuickItem *handle = findItem<QQuickItem>(window->rootObject(), "blueHandle"); @@ -663,16 +662,15 @@ void tst_qquickimage::sourceSize_QTBUG_16389() QCOMPARE(image->sourceSize().height(), 200); QCOMPARE(image->paintedWidth(), 20.0); QCOMPARE(image->paintedHeight(), 20.0); - - delete window; } // QTBUG-15690 void tst_qquickimage::nullPixmapPaint() { - QQuickView *window = new QQuickView(0); + QScopedPointer<QQuickView> window(new QQuickView(0)); window->setSource(testFileUrl("nullpixmap.qml")); window->show(); + QVERIFY(QTest::qWaitForWindowExposed(window.data())); QQuickImage *image = qobject_cast<QQuickImage*>(window->rootObject()); QTRY_VERIFY(image != 0); @@ -681,23 +679,20 @@ void tst_qquickimage::nullPixmapPaint() QQmlTestMessageHandler messageHandler; // used to print "QTransform::translate with NaN called" QPixmap pm = QPixmap::fromImage(window->grabWindow()); - const QStringList glErrors = messageHandler.messages().filter(QLatin1String("QGLContext::makeCurrent(): Failed."), Qt::CaseInsensitive); - QVERIFY2(glErrors.size() == messageHandler.messages().size(), qPrintable(messageHandler.messageString())); + QVERIFY2(messageHandler.messages().size() == 0, qPrintable(messageHandler.messageString())); delete image; - - delete window; } void tst_qquickimage::imageCrash_QTBUG_22125() { - TestHTTPServer server(SERVER_PORT); - QVERIFY(server.isValid()); + TestHTTPServer server; + QVERIFY2(server.listen(SERVER_PORT), qPrintable(server.errorString())); server.serveDirectory(dataDirectory(), TestHTTPServer::Delay); { QQuickView view(testFileUrl("qtbug_22125.qml")); view.show(); - qApp->processEvents(); + QVERIFY(QTest::qWaitForWindowExposed(&view)); qApp->processEvents(); // shouldn't crash when the view drops out of scope due to // QQuickPixmapData attempting to dereference a pointer to @@ -739,14 +734,14 @@ void tst_qquickimage::sourceSize() QFETCH(qreal, implicitWidth); QFETCH(qreal, implicitHeight); - QQuickView *window = new QQuickView(0); + QScopedPointer<QQuickView> window(new QQuickView(0)); QQmlContext *ctxt = window->rootContext(); ctxt->setContextProperty("srcWidth", sourceWidth); ctxt->setContextProperty("srcHeight", sourceHeight); window->setSource(testFileUrl("sourceSize.qml")); window->show(); - qApp->processEvents(); + QVERIFY(QTest::qWaitForWindowExposed(window.data())); QQuickImage *image = qobject_cast<QQuickImage*>(window->rootObject()); QVERIFY(image); @@ -755,14 +750,12 @@ void tst_qquickimage::sourceSize() QCOMPARE(image->sourceSize().height(), sourceHeight); QCOMPARE(image->implicitWidth(), implicitWidth); QCOMPARE(image->implicitHeight(), implicitHeight); - - delete window; } void tst_qquickimage::sourceSizeChanges() { - TestHTTPServer server(14449); - QVERIFY(server.isValid()); + TestHTTPServer server; + QVERIFY2(server.listen(14449), qPrintable(server.errorString())); server.serveDirectory(dataDirectory()); QQmlEngine engine; @@ -827,8 +820,8 @@ void tst_qquickimage::sourceSizeChanges() void tst_qquickimage::progressAndStatusChanges() { - TestHTTPServer server(14449); - QVERIFY(server.isValid()); + TestHTTPServer server; + QVERIFY2(server.listen(14449), qPrintable(server.errorString())); server.serveDirectory(dataDirectory()); QQmlEngine engine; @@ -935,8 +928,8 @@ void tst_qquickimage::correctStatus() void tst_qquickimage::highdpi() { - TestHTTPServer server(14449); - QVERIFY(server.isValid()); + TestHTTPServer server; + QVERIFY2(server.listen(SERVER_PORT), qPrintable(server.errorString())); server.serveDirectory(dataDirectory()); QString componentStr = "import QtQuick 2.0\nImage { source: srcImage ; }"; diff --git a/tests/auto/quick/qquickimageprovider/tst_qquickimageprovider.cpp b/tests/auto/quick/qquickimageprovider/tst_qquickimageprovider.cpp index 48af48b17b..be302241da 100644 --- a/tests/auto/quick/qquickimageprovider/tst_qquickimageprovider.cpp +++ b/tests/auto/quick/qquickimageprovider/tst_qquickimageprovider.cpp @@ -206,11 +206,11 @@ void tst_qquickimageprovider::fillRequestTestsData(const QString &id) QTest::newRow(QTest::toString(id + " missing")) << "image://test/no-such-file.png" << "no-such-file.png" << "" << QSize(100,100) - << "file::2:1: QML Image: Failed to get image from provider: image://test/no-such-file.png"; + << "<Unknown File>:2:1: QML Image: Failed to get image from provider: image://test/no-such-file.png"; QTest::newRow(QTest::toString(id + " unknown provider")) << "image://bogus/exists.png" << "" << "" << QSize() - << "file::2:1: QML Image: Invalid image provider: image://bogus/exists.png"; + << "<Unknown File>:2:1: QML Image: Invalid image provider: image://bogus/exists.png"; } void tst_qquickimageprovider::runTest(bool async, QQuickImageProvider *provider) @@ -364,7 +364,7 @@ void tst_qquickimageprovider::removeProvider() // remove the provider and confirm QString fileName = newImageFileName(); - QString error("file::2:1: QML Image: Invalid image provider: " + fileName); + QString error("<Unknown File>:2:1: QML Image: Invalid image provider: " + fileName); QTest::ignoreMessage(QtWarningMsg, error.toUtf8()); engine.removeImageProvider("test"); diff --git a/tests/auto/quick/qquickitem/qquickitem.pro b/tests/auto/quick/qquickitem/qquickitem.pro index d4bd0874d8..1d8ae0148b 100644 --- a/tests/auto/quick/qquickitem/qquickitem.pro +++ b/tests/auto/quick/qquickitem/qquickitem.pro @@ -3,6 +3,7 @@ TARGET = tst_qquickitem SOURCES += tst_qquickitem.cpp include (../../shared/util.pri) +include (../shared/util.pri) macx:CONFIG -= app_bundle diff --git a/tests/auto/quick/qquickitem/tst_qquickitem.cpp b/tests/auto/quick/qquickitem/tst_qquickitem.cpp index 2db510a69e..5993008c4a 100644 --- a/tests/auto/quick/qquickitem/tst_qquickitem.cpp +++ b/tests/auto/quick/qquickitem/tst_qquickitem.cpp @@ -51,6 +51,8 @@ #include <QTimer> #include <QQmlEngine> #include "../../shared/util.h" +#include "../shared/viewtestutil.h" +#include <QSignalSpy> class TestItem : public QQuickItem { @@ -171,6 +173,8 @@ private slots: void visualParentOwnership(); void visualParentOwnershipWindow(); + void testSGInitializeAndInvalidate(); + private: enum PaintOrderOp { @@ -1313,6 +1317,7 @@ void tst_qquickitem::touchEventAcceptIgnore() item->touchEventReached = false; bool accepted = window.event(&event); + QQuickTouchUtils::flush(&window); QVERIFY(item->touchEventReached); @@ -1336,6 +1341,7 @@ void tst_qquickitem::touchEventAcceptIgnore() item->touchEventReached = false; bool accepted = window.event(&event); + QQuickTouchUtils::flush(&window); QCOMPARE(item->touchEventReached, itemSupportsTouch); @@ -1359,6 +1365,7 @@ void tst_qquickitem::touchEventAcceptIgnore() item->touchEventReached = false; bool accepted = window.event(&event); + QQuickTouchUtils::flush(&window); QCOMPARE(item->touchEventReached, itemSupportsTouch); @@ -1879,6 +1886,37 @@ void tst_qquickitem::visualParentOwnershipWindow() } } +void tst_qquickitem::testSGInitializeAndInvalidate() +{ + for (int i=0; i<2; ++i) { + QScopedPointer<QQuickView> view(new QQuickView()); + + QQuickItem *item = new QQuickItem(); + + int expected; + if (i == 0) { + // First iteration, item has contents and should get signals + expected = 1; + item->setFlag(QQuickItem::ItemHasContents, true); + } else { + // Second iteration, item does not have content and will not get signals + expected = 0; + } + + QSignalSpy initializeSpy(item, SIGNAL(sceneGraphInitialized())); + QSignalSpy invalidateSpy(item, SIGNAL(sceneGraphInvalidated())); + item->setParentItem(view->contentItem()); + view->show(); + + QVERIFY(QTest::qWaitForWindowExposed(view.data())); + QCOMPARE(initializeSpy.size(), expected); + + delete view.take(); + QCOMPARE(invalidateSpy.size(), expected); + } + +} + QTEST_MAIN(tst_qquickitem) #include "tst_qquickitem.moc" diff --git a/tests/auto/quick/qquickitem2/data/grabToImage.qml b/tests/auto/quick/qquickitem2/data/grabToImage.qml new file mode 100644 index 0000000000..9f25210ee2 --- /dev/null +++ b/tests/auto/quick/qquickitem2/data/grabToImage.qml @@ -0,0 +1,60 @@ +/**************************************************************************** +** +** Copyright (C) 2014 Jolla Ltd, author: <gunnar.sletta@jollamobile.com> +** Contact: http://www.qt-project.org/legal +** +** This file is part of the test suite of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Digia gives you certain additional +** rights. These rights are described in the Digia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +import QtQuick 2.0 + +Item { + width: 320 + height: 480 + Rectangle { + objectName: "myItem"; + width: 100 + height: 100 + color: "red" + Rectangle { + anchors.right: parent.right + anchors.bottom: parent.bottom + width: 10 + height: 10 + color: "blue" + } + } +} diff --git a/tests/auto/quick/qquickitem2/tst_qquickitem.cpp b/tests/auto/quick/qquickitem2/tst_qquickitem.cpp index bcfafac93b..1eb9bb0cf2 100644 --- a/tests/auto/quick/qquickitem2/tst_qquickitem.cpp +++ b/tests/auto/quick/qquickitem2/tst_qquickitem.cpp @@ -43,6 +43,7 @@ #include <QtQml/qqmlengine.h> #include <QtQml/qqmlcomponent.h> #include <QtQml/qqmlcontext.h> +#include <QtQuick/qquickitemgrabresult.h> #include <QtQuick/qquickview.h> #include <QtGui/private/qinputmethod_p.h> #include <QtQuick/private/qquickrectangle_p.h> @@ -91,6 +92,7 @@ private slots: void keyNavigation_RightToLeft(); void keyNavigation_skipNotVisible(); void keyNavigation_implicitSetting(); + void keyNavigation_focusReason(); void layoutMirroring(); void layoutMirroringIllegalParent(); void smooth(); @@ -120,6 +122,8 @@ private slots: void contains(); void childAt(); + void grab(); + private: QQmlEngine engine; bool qt_tab_all_widgets() { @@ -215,6 +219,21 @@ public: int mKey; }; +class FocusEventFilter : public QObject +{ +protected: + bool eventFilter(QObject *watched, QEvent *event) { + if ((event->type() == QEvent::FocusIn) || (event->type() == QEvent::FocusOut)) { + QFocusEvent *focusEvent = static_cast<QFocusEvent *>(event); + lastFocusReason = focusEvent->reason(); + return false; + } else + return QObject::eventFilter(watched, event); + } +public: + Qt::FocusReason lastFocusReason; +}; + QML_DECLARE_TYPE(KeyTestItem); class HollowTestItem : public QQuickItem @@ -1613,7 +1632,7 @@ void tst_QQuickItem::layoutMirroringIllegalParent() { QQmlComponent component(&engine); component.setData("import QtQuick 2.0; QtObject { LayoutMirroring.enabled: true; LayoutMirroring.childrenInherit: true }", QUrl::fromLocalFile("")); - QTest::ignoreMessage(QtWarningMsg, "file::1:21: QML QtObject: LayoutDirection attached property only works with Items"); + QTest::ignoreMessage(QtWarningMsg, "<Unknown File>:1:21: QML QtObject: LayoutDirection attached property only works with Items"); QObject *object = component.create(); QVERIFY(object != 0); } @@ -1961,6 +1980,62 @@ void tst_QQuickItem::keyNavigation_implicitSetting() delete window; } +void tst_QQuickItem::keyNavigation_focusReason() +{ + QQuickView *window = new QQuickView(0); + window->setBaseSize(QSize(240,320)); + + FocusEventFilter focusEventFilter; + + window->setSource(testFileUrl("keynavigationtest.qml")); + window->show(); + window->requestActivate(); + + QVERIFY(QTest::qWaitForWindowActive(window)); + QVERIFY(QGuiApplication::focusWindow() == window); + + // install event filter on first item + QQuickItem *item = findItem<QQuickItem>(window->rootObject(), "item1"); + QVERIFY(item); + QVERIFY(item->hasActiveFocus()); + item->installEventFilter(&focusEventFilter); + + //install event filter on second item + item = findItem<QQuickItem>(window->rootObject(), "item2"); + QVERIFY(item); + item->installEventFilter(&focusEventFilter); + + //install event filter on third item + item = findItem<QQuickItem>(window->rootObject(), "item3"); + QVERIFY(item); + item->installEventFilter(&focusEventFilter); + + //install event filter on last item + item = findItem<QQuickItem>(window->rootObject(), "item4"); + QVERIFY(item); + item->installEventFilter(&focusEventFilter); + + // tab + QKeyEvent key = QKeyEvent(QEvent::KeyPress, Qt::Key_Tab, Qt::NoModifier, "", false, 1); + QGuiApplication::sendEvent(window, &key); + QVERIFY(key.isAccepted()); + QCOMPARE(focusEventFilter.lastFocusReason, Qt::TabFocusReason); + + // backtab + key = QKeyEvent(QEvent::KeyPress, Qt::Key_Backtab, Qt::NoModifier, "", false, 1); + QGuiApplication::sendEvent(window, &key); + QVERIFY(key.isAccepted()); + QCOMPARE(focusEventFilter.lastFocusReason, Qt::BacktabFocusReason); + + // some arbitrary cursor key + key = QKeyEvent(QEvent::KeyPress, Qt::Key_Right, Qt::NoModifier, "", false, 1); + QGuiApplication::sendEvent(window, &key); + QVERIFY(key.isAccepted()); + QCOMPARE(focusEventFilter.lastFocusReason, Qt::OtherFocusReason); + + delete window; +} + void tst_QQuickItem::smooth() { QQmlComponent component(&engine); @@ -2737,6 +2812,44 @@ void tst_QQuickItem::childAt() QCOMPARE(parent.childAt(300, 300), static_cast<QQuickItem *>(0)); } +void tst_QQuickItem::grab() +{ +#if defined(Q_OS_WIN32) && defined(QT_OPENGL_ES_2_ANGLE) + QSKIP("QTBUG-40649"); +#endif + QQuickView view; + view.setSource(testFileUrl("grabToImage.qml")); + view.show(); + QTest::qWaitForWindowExposed(&view); + + QQuickItem *root = qobject_cast<QQuickItem *>(view.rootObject()); + QVERIFY(root); + QQuickItem *item = root->findChild<QQuickItem *>("myItem"); + QVERIFY(item); + + { // Default size (item is 100x100) + QSharedPointer<QQuickItemGrabResult> result = item->grabToImage(); + QSignalSpy spy(result.data(), SIGNAL(ready())); + QTRY_VERIFY(spy.size() > 0); + QVERIFY(!result->url().isEmpty()); + QImage image = result->image(); + QCOMPARE(image.pixel(0, 0), qRgb(255, 0, 0)); + QCOMPARE(image.pixel(99, 99), qRgb(0, 0, 255)); + } + + { // Smaller size + QSharedPointer<QQuickItemGrabResult> result = item->grabToImage(QSize(50, 50)); + QVERIFY(!result.isNull()); + QSignalSpy spy(result.data(), SIGNAL(ready())); + QTRY_VERIFY(spy.size() > 0); + QVERIFY(!result->url().isEmpty()); + QImage image = result->image(); + QCOMPARE(image.pixel(0, 0), qRgb(255, 0, 0)); + QCOMPARE(image.pixel(49, 49), qRgb(0, 0, 255)); + } + +} + QTEST_MAIN(tst_QQuickItem) diff --git a/tests/auto/quick/qquickitemlayer/tst_qquickitemlayer.cpp b/tests/auto/quick/qquickitemlayer/tst_qquickitemlayer.cpp index b5980929a6..2bef45056f 100644 --- a/tests/auto/quick/qquickitemlayer/tst_qquickitemlayer.cpp +++ b/tests/auto/quick/qquickitemlayer/tst_qquickitemlayer.cpp @@ -44,6 +44,7 @@ #include <QtQuick/qquickitem.h> #include <QtQuick/qquickview.h> #include <QtGui/qopenglcontext.h> +#include <QtGui/qopenglfunctions.h> #include "../../shared/util.h" @@ -107,13 +108,13 @@ tst_QQuickItemLayer::tst_QQuickItemLayer() window.create(); context.create(); context.makeCurrent(&window); - const char *vendor = (const char *)glGetString(GL_VENDOR); - const char *renderer = (const char *)glGetString(GL_RENDERER); + const char *vendor = (const char *)context.functions()->glGetString(GL_VENDOR); + const char *renderer = (const char *)context.functions()->glGetString(GL_RENDERER); m_isMesaSoftwareRasterizer = strcmp(vendor, "Mesa Project") == 0 && strcmp(renderer, "Software Rasterizer") == 0; if (m_isMesaSoftwareRasterizer) { // Expects format: <OpenGL version> Mesa <Mesa version>[-devel] [...] - const char *version = (const char *)glGetString(GL_VERSION); + const char *version = (const char *)context.functions()->glGetString(GL_VERSION); QList<QByteArray> list = QByteArray(version).split(' '); if (list.size() >= 3) { list = list.at(2).split('-').at(0).split('.'); @@ -137,6 +138,9 @@ tst_QQuickItemLayer::tst_QQuickItemLayer() void tst_QQuickItemLayer::layerSmooth() { +#if defined(Q_OS_WIN32) && defined(QT_OPENGL_ES_2_ANGLE) + QSKIP("QTBUG-40649"); +#endif if (m_isMesaSoftwareRasterizer && m_mesaVersion < QT_VERSION_CHECK(7, 11, 0)) QSKIP("Mesa Software Rasterizer below version 7.11 does not render this test correctly."); QImage fb = runTest("Smooth.qml"); @@ -156,6 +160,9 @@ void tst_QQuickItemLayer::layerSmooth() void tst_QQuickItemLayer::layerEnabled() { +#if defined(Q_OS_WIN32) && defined(QT_OPENGL_ES_2_ANGLE) + QSKIP("QTBUG-40649"); +#endif if (m_isMesaSoftwareRasterizer && m_mesaVersion < QT_VERSION_CHECK(7, 11, 0)) QSKIP("Mesa Software Rasterizer below version 7.11 does not render this test correctly."); QImage fb = runTest("Enabled.qml"); @@ -172,6 +179,9 @@ void tst_QQuickItemLayer::layerEnabled() void tst_QQuickItemLayer::layerMipmap() { +#if defined(Q_OS_WIN32) && defined(QT_OPENGL_ES_2_ANGLE) + QSKIP("QTBUG-40649"); +#endif if (m_isMesaSoftwareRasterizer) QSKIP("Mipmapping does not work with the Mesa Software Rasterizer."); QImage fb = runTest("Mipmap.qml"); @@ -186,6 +196,9 @@ void tst_QQuickItemLayer::layerMipmap() void tst_QQuickItemLayer::layerEffect() { +#if defined(Q_OS_WIN32) && defined(QT_OPENGL_ES_2_ANGLE) + QSKIP("QTBUG-40649"); +#endif if (m_isMesaSoftwareRasterizer && m_mesaVersion < QT_VERSION_CHECK(7, 11, 0)) QSKIP("Mesa Software Rasterizer below version 7.11 does not render this test correctly."); QImage fb = runTest("Effect.qml"); @@ -200,6 +213,9 @@ void tst_QQuickItemLayer::layerEffect() // a shader that pads transparent to blue. Everything else is red. void tst_QQuickItemLayer::layerSourceRect() { +#if defined(Q_OS_WIN32) && defined(QT_OPENGL_ES_2_ANGLE) + QSKIP("QTBUG-40649"); +#endif if (m_isMesaSoftwareRasterizer && m_mesaVersion < QT_VERSION_CHECK(7, 11, 0)) QSKIP("Mesa Software Rasterizer below version 7.11 does not render this test correctly."); @@ -221,6 +237,9 @@ void tst_QQuickItemLayer::layerSourceRect() // directly in a stand alone ShaderEffect void tst_QQuickItemLayer::layerIsTextureProvider() { +#if defined(Q_OS_WIN32) && defined(QT_OPENGL_ES_2_ANGLE) + QSKIP("QTBUG-40649"); +#endif if (m_isMesaSoftwareRasterizer && m_mesaVersion < QT_VERSION_CHECK(7, 11, 0)) QSKIP("Mesa Software Rasterizer below version 7.11 does not render this test correctly."); QImage fb = runTest("TextureProvider.qml"); @@ -253,6 +272,9 @@ void tst_QQuickItemLayer::layerVisibility_data() void tst_QQuickItemLayer::layerVisibility() { +#if defined(Q_OS_WIN32) && defined(QT_OPENGL_ES_2_ANGLE) + QSKIP("QTBUG-40649"); +#endif if (m_isMesaSoftwareRasterizer && m_mesaVersion < QT_VERSION_CHECK(7, 11, 0)) QSKIP("Mesa Software Rasterizer below version 7.11 does not render this test correctly."); @@ -301,6 +323,9 @@ void tst_QQuickItemLayer::layerZOrder_data() void tst_QQuickItemLayer::layerZOrder() { +#if defined(Q_OS_WIN32) && defined(QT_OPENGL_ES_2_ANGLE) + QSKIP("QTBUG-40649"); +#endif if (m_isMesaSoftwareRasterizer && m_mesaVersion < QT_VERSION_CHECK(7, 11, 0)) QSKIP("Mesa Software Rasterizer below version 7.11 does not render this test correctly."); @@ -335,6 +360,9 @@ void tst_QQuickItemLayer::changeZOrder_data() void tst_QQuickItemLayer::changeZOrder() { +#if defined(Q_OS_WIN32) && defined(QT_OPENGL_ES_2_ANGLE) + QSKIP("QTBUG-40649"); +#endif if (m_isMesaSoftwareRasterizer && m_mesaVersion < QT_VERSION_CHECK(7, 11, 0)) QSKIP("Mesa Software Rasterizer below version 7.11 does not render this test correctly."); @@ -403,6 +431,9 @@ void tst_QQuickItemLayer::disableLayer() void tst_QQuickItemLayer::changeSamplerName() { +#if defined(Q_OS_WIN32) && defined(QT_OPENGL_ES_2_ANGLE) + QSKIP("QTBUG-40649"); +#endif if (m_isMesaSoftwareRasterizer && m_mesaVersion < QT_VERSION_CHECK(7, 11, 0)) QSKIP("Mesa Software Rasterizer below version 7.11 does not render this test correctly."); QImage fb = runTest("SamplerNameChange.qml"); @@ -411,6 +442,9 @@ void tst_QQuickItemLayer::changeSamplerName() void tst_QQuickItemLayer::itemEffect() { +#if defined(Q_OS_WIN32) && defined(QT_OPENGL_ES_2_ANGLE) + QSKIP("QTBUG-40649"); +#endif if (m_isMesaSoftwareRasterizer && m_mesaVersion < QT_VERSION_CHECK(7, 11, 0)) QSKIP("Mesa Software Rasterizer below version 7.11 does not render this test correctly."); QImage fb = runTest("ItemEffect.qml"); diff --git a/tests/auto/quick/qquicklistview/data/sizeTransitions.qml b/tests/auto/quick/qquicklistview/data/sizeTransitions.qml new file mode 100644 index 0000000000..6dfc5ee70a --- /dev/null +++ b/tests/auto/quick/qquicklistview/data/sizeTransitions.qml @@ -0,0 +1,101 @@ +/**************************************************************************** +** +** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the test suite of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:BSD$ +** You may use this file under the terms of the BSD license as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of Digia Plc and its Subsidiary(-ies) nor the names +** of its contributors may be used to endorse or promote products derived +** from this software without specific prior written permission. +** +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +import QtQuick 2.2 +import QtQuick.Window 2.1 + +Rectangle { + id: root + width: 500 + height: 600 + property int animationDuration: 10 + property int itemHeight: 40 + + Rectangle { + id: sightingsListPanel + border.width: 2 + border.color: "lightgray" + y: 200 + anchors.fill: parent + anchors.topMargin: 200 + anchors.leftMargin: 200 + ListView { + id: list + objectName: "list" + orientation: topToBottom ? ListView.Vertical : ListView.Horizontal + property bool transitionFinished: false + property bool scriptActionExecuted : false + anchors { fill: parent; margins: parent.border.width; } + model: testModel + delegate: listDelegate + // clip when we have no animation running + clip: false + add: Transition { + id: trans + onRunningChanged: { + if (!running) + list.transitionFinished = true; + } + SequentialAnimation { + ParallelAnimation { + NumberAnimation { properties: "x"; from: -100; duration: root.animationDuration } + NumberAnimation { properties: "y"; from: -100; duration: root.animationDuration } + NumberAnimation { properties: "width"; from: 1; to: list.width; duration: root.animationDuration;} + // Commenting out the height animation and it works + NumberAnimation { properties: "height"; from: 1; to: root.itemHeight; duration: root.animationDuration } + } + ScriptAction { script: list.scriptActionExecuted = true;} + } + + } + } + // Delegate for defining a template for an item in the list + Component { + id: listDelegate + Rectangle { + id: background + width: list.width + height: root.itemHeight + border.width: 2 + radius: 3 + } + } + } +} diff --git a/tests/auto/quick/qquicklistview/data/stickyPositioning-both.qml b/tests/auto/quick/qquicklistview/data/stickyPositioning-both.qml new file mode 100644 index 0000000000..4bbe7a0053 --- /dev/null +++ b/tests/auto/quick/qquicklistview/data/stickyPositioning-both.qml @@ -0,0 +1,77 @@ +/**************************************************************************** +** +** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the test suite of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:BSD$ +** You may use this file under the terms of the BSD license as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of Digia Plc and its Subsidiary(-ies) nor the names +** of its contributors may be used to endorse or promote products derived +** from this software without specific prior written permission. +** +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** +** $QT_END_LICENSE$ +** +****************************************************************************/ +import QtQuick 2.4 + +Rectangle { + width: 240 + height: 320 + ListView { + id: list + objectName: "list" + width: 100 + height: 100 + cacheBuffer: 0 + anchors.centerIn: parent + model: testModel + orientation: testOrientation + layoutDirection: testLayoutDirection + verticalLayoutDirection: testVerticalLayoutDirection + delegate: Rectangle { + width: 10 + height: 10 + border.width: 1 + border.color: "gray" + } + headerPositioning: ListView.PullBackHeader + header: Rectangle { + width: 10 + height: 10 + color: "red" + objectName: "header" + } + footerPositioning: ListView.PullBackFooter + footer: Rectangle { + width: 10 + height: 10 + color: "blue" + objectName: "footer" + } + } +} diff --git a/tests/auto/quick/qquicklistview/data/stickyPositioning-footer.qml b/tests/auto/quick/qquicklistview/data/stickyPositioning-footer.qml new file mode 100644 index 0000000000..57773df37e --- /dev/null +++ b/tests/auto/quick/qquicklistview/data/stickyPositioning-footer.qml @@ -0,0 +1,70 @@ +/**************************************************************************** +** +** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the test suite of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:BSD$ +** You may use this file under the terms of the BSD license as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of Digia Plc and its Subsidiary(-ies) nor the names +** of its contributors may be used to endorse or promote products derived +** from this software without specific prior written permission. +** +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** +** $QT_END_LICENSE$ +** +****************************************************************************/ +import QtQuick 2.4 + +Rectangle { + width: 240 + height: 320 + ListView { + id: list + objectName: "list" + width: 100 + height: 100 + cacheBuffer: 0 + anchors.centerIn: parent + model: testModel + orientation: testOrientation + layoutDirection: testLayoutDirection + verticalLayoutDirection: testVerticalLayoutDirection + delegate: Rectangle { + width: 10 + height: 10 + border.width: 1 + border.color: "gray" + } + footerPositioning: ListView.PullBackFooter + footer: Rectangle { + width: 10 + height: 10 + color: "blue" + objectName: "footer" + } + } +} diff --git a/tests/auto/quick/qquicklistview/data/stickyPositioning-header.qml b/tests/auto/quick/qquicklistview/data/stickyPositioning-header.qml new file mode 100644 index 0000000000..1ca9813baa --- /dev/null +++ b/tests/auto/quick/qquicklistview/data/stickyPositioning-header.qml @@ -0,0 +1,70 @@ +/**************************************************************************** +** +** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the test suite of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:BSD$ +** You may use this file under the terms of the BSD license as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of Digia Plc and its Subsidiary(-ies) nor the names +** of its contributors may be used to endorse or promote products derived +** from this software without specific prior written permission. +** +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** +** $QT_END_LICENSE$ +** +****************************************************************************/ +import QtQuick 2.4 + +Rectangle { + width: 240 + height: 320 + ListView { + id: list + objectName: "list" + width: 100 + height: 100 + cacheBuffer: 0 + anchors.centerIn: parent + model: testModel + orientation: testOrientation + layoutDirection: testLayoutDirection + verticalLayoutDirection: testVerticalLayoutDirection + delegate: Rectangle { + width: 10 + height: 10 + border.width: 1 + border.color: "gray" + } + headerPositioning: ListView.PullBackHeader + header: Rectangle { + width: 10 + height: 10 + color: "red" + objectName: "header" + } + } +} diff --git a/tests/auto/quick/qquicklistview/tst_qquicklistview.cpp b/tests/auto/quick/qquicklistview/tst_qquicklistview.cpp index d22f3487da..50bf1e03f1 100644 --- a/tests/auto/quick/qquicklistview/tst_qquicklistview.cpp +++ b/tests/auto/quick/qquicklistview/tst_qquicklistview.cpp @@ -199,6 +199,9 @@ private slots: void populateTransitions(); void populateTransitions_data(); + void sizeTransitions(); + void sizeTransitions_data(); + void addTransitions(); void addTransitions_data(); void moveTransitions(); @@ -230,6 +233,9 @@ private slots: void QTBUG_36481(); void QTBUG_35920(); + void stickyPositioning(); + void stickyPositioning_data(); + void roundingErrors(); void roundingErrors_data(); @@ -5814,6 +5820,56 @@ void tst_QQuickListView::populateTransitions_data() QTest::newRow("empty to start with, no populate") << false << false << false; } + +/* + * Tests if the first visible item is not repositioned if the same item + * resized + changes position during a transition. The test does not test the + * actual position while it is transitioning (since its timing sensitive), but + * rather tests if the transition has reached its target state properly. + **/ +void tst_QQuickListView::sizeTransitions() +{ + QFETCH(bool, topToBottom); + QQuickView *window = getView(); + QQmlContext *ctxt = window->rootContext(); + QaimModel model; + ctxt->setContextProperty("testModel", &model); + ctxt->setContextProperty("topToBottom", topToBottom); + TestObject *testObject = new TestObject; + ctxt->setContextProperty("testObject", &model); + window->setSource(testFileUrl("sizeTransitions.qml")); + window->show(); + QVERIFY(QTest::qWaitForWindowExposed(window)); + + QQuickListView *listview = findItem<QQuickListView>(window->rootObject(), "list"); + QTRY_VERIFY(listview != 0); + QTRY_COMPARE(QQuickItemPrivate::get(listview)->polishScheduled, false); + + // the following will start the transition + model.addItem(QLatin1String("Test"), ""); + + // This ensures early failure in case of failure (in which case + // transitionFinished == true and scriptActionExecuted == false) + QTRY_COMPARE(listview->property("scriptActionExecuted").toBool() || + listview->property("transitionFinished").toBool(), true); + QCOMPARE(listview->property("scriptActionExecuted").toBool(), true); + QCOMPARE(listview->property("transitionFinished").toBool(), true); + + releaseView(window); + delete testObject; +} + +void tst_QQuickListView::sizeTransitions_data() +{ + QTest::addColumn<bool>("topToBottom"); + + QTest::newRow("TopToBottom") + << true; + + QTest::newRow("LeftToRight") + << false; +} + void tst_QQuickListView::addTransitions() { QFETCH(int, initialItemCount); @@ -7266,6 +7322,412 @@ void tst_QQuickListView::QTBUG_35920() QTest::mouseRelease(window.data(), Qt::LeftButton, 0, QPoint(10,100)); } +Q_DECLARE_METATYPE(Qt::Orientation) + +void tst_QQuickListView::stickyPositioning() +{ + QFETCH(QString, fileName); + + QFETCH(Qt::Orientation, orientation); + QFETCH(Qt::LayoutDirection, layoutDirection); + QFETCH(QQuickItemView::VerticalLayoutDirection, verticalLayoutDirection); + + QFETCH(int, positionIndex); + QFETCH(QQuickItemView::PositionMode, positionMode); + QFETCH(QList<QPointF>, movement); + + QFETCH(QPointF, headerPos); + QFETCH(QPointF, footerPos); + + QQuickView *window = createView(); + + QaimModel model; + for (int i = 0; i < 20; i++) + model.addItem(QString::number(i), QString::number(i/10)); + + QQmlContext *ctxt = window->rootContext(); + ctxt->setContextProperty("testModel", &model); + ctxt->setContextProperty("testOrientation", orientation); + ctxt->setContextProperty("testLayoutDirection", layoutDirection); + ctxt->setContextProperty("testVerticalLayoutDirection", verticalLayoutDirection); + + window->setSource(testFileUrl(fileName)); + window->show(); + QVERIFY(QTest::qWaitForWindowExposed(window)); + + QQuickListView *listview = findItem<QQuickListView>(window->rootObject(), "list"); + QVERIFY(listview); + + QQuickItem *contentItem = listview->contentItem(); + QVERIFY(contentItem); + + listview->positionViewAtIndex(positionIndex, positionMode); + + foreach (const QPointF &offset, movement) { + listview->setContentX(listview->contentX() + offset.x()); + listview->setContentY(listview->contentY() + offset.y()); + } + + if (listview->header()) { + QQuickItem *headerItem = listview->headerItem(); + QVERIFY(headerItem); + QPointF actualPos = listview->mapFromItem(contentItem, headerItem->position()); + QCOMPARE(actualPos, headerPos); + } + + if (listview->footer()) { + QQuickItem *footerItem = listview->footerItem(); + QVERIFY(footerItem); + QPointF actualPos = listview->mapFromItem(contentItem, footerItem->position()); + QCOMPARE(actualPos, footerPos); + } + + delete window; +} + +void tst_QQuickListView::stickyPositioning_data() +{ + qRegisterMetaType<Qt::Orientation>(); + qRegisterMetaType<Qt::LayoutDirection>(); + qRegisterMetaType<QQuickItemView::VerticalLayoutDirection>(); + qRegisterMetaType<QQuickItemView::PositionMode>(); + + QTest::addColumn<QString>("fileName"); + + QTest::addColumn<Qt::Orientation>("orientation"); + QTest::addColumn<Qt::LayoutDirection>("layoutDirection"); + QTest::addColumn<QQuickItemView::VerticalLayoutDirection>("verticalLayoutDirection"); + + QTest::addColumn<int>("positionIndex"); + QTest::addColumn<QQuickItemView::PositionMode>("positionMode"); + QTest::addColumn<QList<QPointF> >("movement"); + + QTest::addColumn<QPointF>("headerPos"); + QTest::addColumn<QPointF>("footerPos"); + + // header at the top + QTest::newRow("top header") << "stickyPositioning-header.qml" + << Qt::Vertical << Qt::LeftToRight << QQuickListView::TopToBottom + << 0 << QQuickItemView::Beginning << QList<QPointF>() + << QPointF(0,-10) << QPointF(); + + QTest::newRow("top header: 1/2 up") << "stickyPositioning-header.qml" + << Qt::Vertical << Qt::LeftToRight << QQuickListView::TopToBottom + << 1 << QQuickItemView::Beginning << (QList<QPointF>() << QPointF(0,-5)) + << QPointF(0,-5) << QPointF(); + + QTest::newRow("top header: up") << "stickyPositioning-header.qml" + << Qt::Vertical << Qt::LeftToRight << QQuickListView::TopToBottom + << 2 << QQuickItemView::Beginning << (QList<QPointF>() << QPointF(0,-15)) + << QPointF(0,0) << QPointF(); + + QTest::newRow("top header: 1/2 down") << "stickyPositioning-header.qml" + << Qt::Vertical << Qt::LeftToRight << QQuickListView::TopToBottom + << 3 << QQuickItemView::Beginning << (QList<QPointF>() << QPointF(0,-15) << QPointF(0,5)) + << QPointF(0,-5) << QPointF(); + + QTest::newRow("top header: down") << "stickyPositioning-header.qml" + << Qt::Vertical << Qt::LeftToRight << QQuickListView::TopToBottom + << 4 << QQuickItemView::Beginning << (QList<QPointF>() << QPointF(0,-15) << QPointF(0,10)) + << QPointF(0,-10) << QPointF(); + + + // footer at the top + QTest::newRow("top footer") << "stickyPositioning-footer.qml" + << Qt::Vertical << Qt::LeftToRight << QQuickListView::BottomToTop + << 19 << QQuickItemView::End << QList<QPointF>() + << QPointF() << QPointF(0,-10); + + QTest::newRow("top footer: 1/2 up") << "stickyPositioning-footer.qml" + << Qt::Vertical << Qt::LeftToRight << QQuickListView::BottomToTop + << 18 << QQuickItemView::End << (QList<QPointF>() << QPointF(0,-5)) + << QPointF() << QPointF(0,-5); + + QTest::newRow("top footer: up") << "stickyPositioning-footer.qml" + << Qt::Vertical << Qt::LeftToRight << QQuickListView::BottomToTop + << 17 << QQuickItemView::End << (QList<QPointF>() << QPointF(0,-15)) + << QPointF() << QPointF(0,0); + + QTest::newRow("top footer: 1/2 down") << "stickyPositioning-footer.qml" + << Qt::Vertical << Qt::LeftToRight << QQuickListView::BottomToTop + << 16 << QQuickItemView::End << (QList<QPointF>() << QPointF(0,-15) << QPointF(0,5)) + << QPointF() << QPointF(0,-5); + + QTest::newRow("top footer: down") << "stickyPositioning-footer.qml" + << Qt::Vertical << Qt::LeftToRight << QQuickListView::BottomToTop + << 15 << QQuickItemView::End << (QList<QPointF>() << QPointF(0,-15) << QPointF(0,10)) + << QPointF() << QPointF(0,-10); + + + // header at the bottom + QTest::newRow("bottom header") << "stickyPositioning-header.qml" + << Qt::Vertical << Qt::LeftToRight << QQuickListView::BottomToTop + << 0 << QQuickItemView::Beginning << QList<QPointF>() + << QPointF(0,100) << QPointF(); + + QTest::newRow("bottom header: 1/2 down") << "stickyPositioning-header.qml" + << Qt::Vertical << Qt::LeftToRight << QQuickListView::BottomToTop + << 1 << QQuickItemView::Beginning << (QList<QPointF>() << QPointF(0,5)) + << QPointF(0,95) << QPointF(); + + QTest::newRow("bottom header: down") << "stickyPositioning-header.qml" + << Qt::Vertical << Qt::LeftToRight << QQuickListView::BottomToTop + << 2 << QQuickItemView::Beginning << (QList<QPointF>() << QPointF(0,15)) + << QPointF(0,90) << QPointF(); + + QTest::newRow("bottom header: 1/2 up") << "stickyPositioning-header.qml" + << Qt::Vertical << Qt::LeftToRight << QQuickListView::BottomToTop + << 3 << QQuickItemView::Beginning << (QList<QPointF>() << QPointF(0,15) << QPointF(0,-5)) + << QPointF(0,95) << QPointF(); + + QTest::newRow("bottom header: up") << "stickyPositioning-header.qml" + << Qt::Vertical << Qt::LeftToRight << QQuickListView::BottomToTop + << 4 << QQuickItemView::Beginning << (QList<QPointF>() << QPointF(0,15) << QPointF(0,-10)) + << QPointF(0,100) << QPointF(); + + + // footer at the bottom + QTest::newRow("bottom footer") << "stickyPositioning-footer.qml" + << Qt::Vertical << Qt::LeftToRight << QQuickListView::TopToBottom + << 19 << QQuickItemView::End << QList<QPointF>() + << QPointF() << QPointF(0,100); + + QTest::newRow("bottom footer: 1/2 down") << "stickyPositioning-footer.qml" + << Qt::Vertical << Qt::LeftToRight << QQuickListView::TopToBottom + << 18 << QQuickItemView::End << (QList<QPointF>() << QPointF(0,5)) + << QPointF() << QPointF(0,95); + + QTest::newRow("bottom footer: down") << "stickyPositioning-footer.qml" + << Qt::Vertical << Qt::LeftToRight << QQuickListView::TopToBottom + << 17 << QQuickItemView::End << (QList<QPointF>() << QPointF(0,15)) + << QPointF() << QPointF(0,90); + + QTest::newRow("bottom footer: 1/2 up") << "stickyPositioning-footer.qml" + << Qt::Vertical << Qt::LeftToRight << QQuickListView::TopToBottom + << 16 << QQuickItemView::End << (QList<QPointF>() << QPointF(0,15) << QPointF(0,-5)) + << QPointF() << QPointF(0,95); + + QTest::newRow("bottom footer: up") << "stickyPositioning-footer.qml" + << Qt::Vertical << Qt::LeftToRight << QQuickListView::TopToBottom + << 15 << QQuickItemView::End << (QList<QPointF>() << QPointF(0,15) << QPointF(0,-10)) + << QPointF() << QPointF(0,100); + + + // header at the top (& footer at the bottom) + QTest::newRow("top header & bottom footer") << "stickyPositioning-both.qml" + << Qt::Vertical << Qt::LeftToRight << QQuickListView::TopToBottom + << 0 << QQuickItemView::Beginning << QList<QPointF>() + << QPointF(0,-10) << QPointF(0,90); + + QTest::newRow("top header & bottom footer: 1/2 up") << "stickyPositioning-both.qml" + << Qt::Vertical << Qt::LeftToRight << QQuickListView::TopToBottom + << 1 << QQuickItemView::Beginning << (QList<QPointF>() << QPointF(0,-5)) + << QPointF(0,-5) << QPointF(0,95); + + QTest::newRow("top header & bottom footer: up") << "stickyPositioning-both.qml" + << Qt::Vertical << Qt::LeftToRight << QQuickListView::TopToBottom + << 2 << QQuickItemView::Beginning << (QList<QPointF>() << QPointF(0,-15)) + << QPointF(0,0) << QPointF(0,100); + + QTest::newRow("top header & bottom footer: 1/2 down") << "stickyPositioning-both.qml" + << Qt::Vertical << Qt::LeftToRight << QQuickListView::TopToBottom + << 3 << QQuickItemView::Beginning << (QList<QPointF>() << QPointF(0,-15) << QPointF(0,5)) + << QPointF(0,-5) << QPointF(0,95); + + QTest::newRow("top header & bottom footer: down") << "stickyPositioning-both.qml" + << Qt::Vertical << Qt::LeftToRight << QQuickListView::TopToBottom + << 4 << QQuickItemView::Beginning << (QList<QPointF>() << QPointF(0,-15) << QPointF(0,10)) + << QPointF(0,-10) << QPointF(0,90); + + + // footer at the bottom (& header at the top) + QTest::newRow("bottom footer & top header") << "stickyPositioning-both.qml" + << Qt::Vertical << Qt::LeftToRight << QQuickListView::TopToBottom + << 1 << QQuickItemView::Beginning << QList<QPointF>() + << QPointF(0,-10) << QPointF(0,90); + + QTest::newRow("bottom footer & top header: 1/2 down") << "stickyPositioning-both.qml" + << Qt::Vertical << Qt::LeftToRight << QQuickListView::TopToBottom + << 1 << QQuickItemView::Beginning << (QList<QPointF>() << QPointF(0,5)) + << QPointF(0,-10) << QPointF(0,90); + + QTest::newRow("bottom footer & top header: down") << "stickyPositioning-both.qml" + << Qt::Vertical << Qt::LeftToRight << QQuickListView::TopToBottom + << 2 << QQuickItemView::Beginning << (QList<QPointF>() << QPointF(0,15)) + << QPointF(0,-10) << QPointF(0,90); + + QTest::newRow("bottom footer & top header: 1/2 up") << "stickyPositioning-both.qml" + << Qt::Vertical << Qt::LeftToRight << QQuickListView::TopToBottom + << 3 << QQuickItemView::Beginning << (QList<QPointF>() << QPointF(0,15) << QPointF(0,-5)) + << QPointF(0,-5) << QPointF(0,95); + + QTest::newRow("bottom footer & top header: up") << "stickyPositioning-both.qml" + << Qt::Vertical << Qt::LeftToRight << QQuickListView::TopToBottom + << 4 << QQuickItemView::Beginning << (QList<QPointF>() << QPointF(0,15) << QPointF(0,-10)) + << QPointF(0,0) << QPointF(0,100); + + // header on the left + QTest::newRow("left header") << "stickyPositioning-header.qml" + << Qt::Horizontal << Qt::LeftToRight << QQuickListView::TopToBottom + << 0 << QQuickItemView::Beginning << QList<QPointF>() + << QPointF(-10,0) << QPointF(); + + QTest::newRow("left header: 1/2 left") << "stickyPositioning-header.qml" + << Qt::Horizontal << Qt::LeftToRight << QQuickListView::TopToBottom + << 1 << QQuickItemView::Beginning << (QList<QPointF>() << QPointF(-5,0)) + << QPointF(-5,0) << QPointF(); + + QTest::newRow("left header: left") << "stickyPositioning-header.qml" + << Qt::Horizontal << Qt::LeftToRight << QQuickListView::TopToBottom + << 2 << QQuickItemView::Beginning << (QList<QPointF>() << QPointF(-15,0)) + << QPointF(0,0) << QPointF(); + + QTest::newRow("left header: 1/2 right") << "stickyPositioning-header.qml" + << Qt::Horizontal << Qt::LeftToRight << QQuickListView::TopToBottom + << 3 << QQuickItemView::Beginning << (QList<QPointF>() << QPointF(-15,0) << QPointF(5,0)) + << QPointF(-5,0) << QPointF(); + + QTest::newRow("left header: right") << "stickyPositioning-header.qml" + << Qt::Horizontal << Qt::LeftToRight << QQuickListView::TopToBottom + << 4 << QQuickItemView::Beginning << (QList<QPointF>() << QPointF(-15,0) << QPointF(10,0)) + << QPointF(-10,0) << QPointF(); + + + // footer on the left + QTest::newRow("left footer") << "stickyPositioning-footer.qml" + << Qt::Horizontal << Qt::RightToLeft << QQuickListView::TopToBottom + << 19 << QQuickItemView::End << QList<QPointF>() + << QPointF() << QPointF(-10,0); + + QTest::newRow("left footer: 1/2 left") << "stickyPositioning-footer.qml" + << Qt::Horizontal << Qt::RightToLeft << QQuickListView::TopToBottom + << 18 << QQuickItemView::End << (QList<QPointF>() << QPointF(-5,0)) + << QPointF() << QPointF(-5,0); + + QTest::newRow("left footer: left") << "stickyPositioning-footer.qml" + << Qt::Horizontal << Qt::RightToLeft << QQuickListView::TopToBottom + << 17 << QQuickItemView::End << (QList<QPointF>() << QPointF(-15,0)) + << QPointF() << QPointF(0,0); + + QTest::newRow("left footer: 1/2 right") << "stickyPositioning-footer.qml" + << Qt::Horizontal << Qt::RightToLeft << QQuickListView::TopToBottom + << 16 << QQuickItemView::End << (QList<QPointF>() << QPointF(-15,0) << QPointF(5,0)) + << QPointF() << QPointF(-5,0); + + QTest::newRow("left footer: right") << "stickyPositioning-footer.qml" + << Qt::Horizontal << Qt::RightToLeft << QQuickListView::TopToBottom + << 15 << QQuickItemView::End << (QList<QPointF>() << QPointF(-15,0) << QPointF(10,0)) + << QPointF() << QPointF(-10,0); + + + // header on the right + QTest::newRow("right header") << "stickyPositioning-header.qml" + << Qt::Horizontal << Qt::RightToLeft << QQuickListView::TopToBottom + << 0 << QQuickItemView::Beginning << QList<QPointF>() + << QPointF(100,0) << QPointF(); + + QTest::newRow("right header: 1/2 right") << "stickyPositioning-header.qml" + << Qt::Horizontal << Qt::RightToLeft << QQuickListView::TopToBottom + << 1 << QQuickItemView::Beginning << (QList<QPointF>() << QPointF(5,0)) + << QPointF(95,0) << QPointF(); + + QTest::newRow("right header: right") << "stickyPositioning-header.qml" + << Qt::Horizontal << Qt::RightToLeft << QQuickListView::TopToBottom + << 2 << QQuickItemView::Beginning << (QList<QPointF>() << QPointF(15,0)) + << QPointF(90,0) << QPointF(); + + QTest::newRow("right header: 1/2 left") << "stickyPositioning-header.qml" + << Qt::Horizontal << Qt::RightToLeft << QQuickListView::TopToBottom + << 3 << QQuickItemView::Beginning << (QList<QPointF>() << QPointF(15,0) << QPointF(-5,0)) + << QPointF(95,0) << QPointF(); + + QTest::newRow("right header: left") << "stickyPositioning-header.qml" + << Qt::Horizontal << Qt::RightToLeft << QQuickListView::TopToBottom + << 4 << QQuickItemView::Beginning << (QList<QPointF>() << QPointF(15,0) << QPointF(-10,0)) + << QPointF(100,0) << QPointF(); + + + // footer on the right + QTest::newRow("right footer") << "stickyPositioning-footer.qml" + << Qt::Horizontal << Qt::LeftToRight << QQuickListView::TopToBottom + << 19 << QQuickItemView::End << QList<QPointF>() + << QPointF() << QPointF(100,0); + + QTest::newRow("right footer: 1/2 right") << "stickyPositioning-footer.qml" + << Qt::Horizontal << Qt::LeftToRight << QQuickListView::TopToBottom + << 18 << QQuickItemView::End << (QList<QPointF>() << QPointF(5,0)) + << QPointF() << QPointF(95,0); + + QTest::newRow("right footer: right") << "stickyPositioning-footer.qml" + << Qt::Horizontal << Qt::LeftToRight << QQuickListView::TopToBottom + << 17 << QQuickItemView::End << (QList<QPointF>() << QPointF(15,0)) + << QPointF() << QPointF(90,0); + + QTest::newRow("right footer: 1/2 left") << "stickyPositioning-footer.qml" + << Qt::Horizontal << Qt::LeftToRight << QQuickListView::TopToBottom + << 16 << QQuickItemView::End << (QList<QPointF>() << QPointF(15,0) << QPointF(-5,0)) + << QPointF() << QPointF(95,0); + + QTest::newRow("right footer: left") << "stickyPositioning-footer.qml" + << Qt::Horizontal << Qt::LeftToRight << QQuickListView::TopToBottom + << 15 << QQuickItemView::End << (QList<QPointF>() << QPointF(15,0) << QPointF(-10,0)) + << QPointF() << QPointF(100,0); + + + // header on the left (& footer on the right) + QTest::newRow("left header & right footer") << "stickyPositioning-both.qml" + << Qt::Horizontal << Qt::LeftToRight << QQuickListView::TopToBottom + << 0 << QQuickItemView::Beginning << QList<QPointF>() + << QPointF(-10,0) << QPointF(90,0); + + QTest::newRow("left header & right footer: 1/2 left") << "stickyPositioning-both.qml" + << Qt::Horizontal << Qt::LeftToRight << QQuickListView::TopToBottom + << 1 << QQuickItemView::Beginning << (QList<QPointF>() << QPointF(-5,0)) + << QPointF(-5,0) << QPointF(95,0); + + QTest::newRow("left header & right footer: left") << "stickyPositioning-both.qml" + << Qt::Horizontal << Qt::LeftToRight << QQuickListView::TopToBottom + << 2 << QQuickItemView::Beginning << (QList<QPointF>() << QPointF(-15,0)) + << QPointF(0,0) << QPointF(100,0); + + QTest::newRow("left header & right footer: 1/2 right") << "stickyPositioning-both.qml" + << Qt::Horizontal << Qt::LeftToRight << QQuickListView::TopToBottom + << 3 << QQuickItemView::Beginning << (QList<QPointF>() << QPointF(-15,0) << QPointF(5,0)) + << QPointF(-5,0) << QPointF(95,0); + + QTest::newRow("left header & right footer: right") << "stickyPositioning-both.qml" + << Qt::Horizontal << Qt::LeftToRight << QQuickListView::TopToBottom + << 4 << QQuickItemView::Beginning << (QList<QPointF>() << QPointF(-15,0) << QPointF(10,0)) + << QPointF(-10,0) << QPointF(90,0); + + + // footer on the right (& header on the left) + QTest::newRow("right footer & left header") << "stickyPositioning-both.qml" + << Qt::Horizontal << Qt::LeftToRight << QQuickListView::TopToBottom + << 1 << QQuickItemView::Beginning << QList<QPointF>() + << QPointF(-10,0) << QPointF(90,0); + + QTest::newRow("right footer & left header: 1/2 right") << "stickyPositioning-both.qml" + << Qt::Horizontal << Qt::LeftToRight << QQuickListView::TopToBottom + << 1 << QQuickItemView::Beginning << (QList<QPointF>() << QPointF(5,0)) + << QPointF(-10,0) << QPointF(90,0); + + QTest::newRow("right footer & left header: right") << "stickyPositioning-both.qml" + << Qt::Horizontal << Qt::LeftToRight << QQuickListView::TopToBottom + << 2 << QQuickItemView::Beginning << (QList<QPointF>() << QPointF(15,0)) + << QPointF(-10,0) << QPointF(90,0); + + QTest::newRow("right footer & left header: 1/2 left") << "stickyPositioning-both.qml" + << Qt::Horizontal << Qt::LeftToRight << QQuickListView::TopToBottom + << 3 << QQuickItemView::Beginning << (QList<QPointF>() << QPointF(15,0) << QPointF(-5,0)) + << QPointF(-5,0) << QPointF(95,0); + + QTest::newRow("right footer & left header: left") << "stickyPositioning-both.qml" + << Qt::Horizontal << Qt::LeftToRight << QQuickListView::TopToBottom + << 4 << QQuickItemView::Beginning << (QList<QPointF>() << QPointF(15,0) << QPointF(-10,0)) + << QPointF(0,0) << QPointF(100,0); +} + void tst_QQuickListView::roundingErrors() { QFETCH(bool, pixelAligned); diff --git a/tests/auto/quick/qquickloader/tst_qquickloader.cpp b/tests/auto/quick/qquickloader/tst_qquickloader.cpp index 877bb59613..9ac2663f24 100644 --- a/tests/auto/quick/qquickloader/tst_qquickloader.cpp +++ b/tests/auto/quick/qquickloader/tst_qquickloader.cpp @@ -446,8 +446,8 @@ void tst_QQuickLoader::noResize() void tst_QQuickLoader::networkRequestUrl() { - TestHTTPServer server(SERVER_PORT); - QVERIFY(server.isValid()); + TestHTTPServer server; + QVERIFY2(server.listen(SERVER_PORT), qPrintable(server.errorString())); server.serveDirectory(dataDirectory()); QQmlComponent component(&engine); @@ -470,8 +470,8 @@ void tst_QQuickLoader::networkRequestUrl() /* XXX Component waits until all dependencies are loaded. Is this actually possible? */ void tst_QQuickLoader::networkComponent() { - 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); @@ -503,8 +503,8 @@ void tst_QQuickLoader::networkComponent() void tst_QQuickLoader::failNetworkRequest() { - TestHTTPServer server(SERVER_PORT); - QVERIFY(server.isValid()); + TestHTTPServer server; + QVERIFY2(server.listen(SERVER_PORT), qPrintable(server.errorString())); server.serveDirectory(dataDirectory()); QTest::ignoreMessage(QtWarningMsg, SERVER_ADDR "/IDontExist.qml: File not found"); @@ -718,8 +718,8 @@ void tst_QQuickLoader::initialPropertyValues() QFETCH(QStringList, propertyNames); QFETCH(QVariantList, propertyValues); - TestHTTPServer server(SERVER_PORT); - QVERIFY(server.isValid()); + TestHTTPServer server; + QVERIFY2(server.listen(SERVER_PORT), qPrintable(server.errorString())); server.serveDirectory(dataDirectory()); foreach (const QString &warning, expectedWarnings) diff --git a/tests/auto/quick/qquickmousearea/data/containsPress.qml b/tests/auto/quick/qquickmousearea/data/containsPress.qml new file mode 100644 index 0000000000..367c73c175 --- /dev/null +++ b/tests/auto/quick/qquickmousearea/data/containsPress.qml @@ -0,0 +1,20 @@ +import QtQuick 2.4 + +Item { + width: 500 + height: 500 + + Rectangle { + width: 300 + height: 300 + color: mouseArea.containsPress ? "red" : "grey" + x: 100 + y: 100 + + MouseArea { + id: mouseArea + objectName: "mouseArea" + anchors.fill: parent + } + } +} diff --git a/tests/auto/quick/qquickmousearea/tst_qquickmousearea.cpp b/tests/auto/quick/qquickmousearea/tst_qquickmousearea.cpp index d0a1c18885..75497a4b5f 100644 --- a/tests/auto/quick/qquickmousearea/tst_qquickmousearea.cpp +++ b/tests/auto/quick/qquickmousearea/tst_qquickmousearea.cpp @@ -86,6 +86,7 @@ private slots: void resetDrag(); void dragging_data() { acceptedButton_data(); } void dragging(); + void dragSmoothed(); void dragThreshold(); void invalidDrag_data() { rejectedButton_data(); } void invalidDrag(); @@ -122,6 +123,8 @@ private slots: void moveAndReleaseWithoutPress(); void nestedStopAtBounds(); void nestedStopAtBounds_data(); + void containsPress_data(); + void containsPress(); private: void acceptedButton_data(); @@ -334,6 +337,50 @@ void tst_QQuickMouseArea::dragging() QCOMPARE(blackRect->y(), 61.0); } +void tst_QQuickMouseArea::dragSmoothed() +{ + QQuickView window; + QByteArray errorMessage; + QVERIFY2(initView(window, testFileUrl("dragging.qml"), true, &errorMessage), errorMessage.constData()); + + window.show(); + QVERIFY(QTest::qWaitForWindowExposed(&window)); + QVERIFY(window.rootObject() != 0); + + QQuickMouseArea *mouseRegion = window.rootObject()->findChild<QQuickMouseArea*>("mouseregion"); + QQuickDrag *drag = mouseRegion->drag(); + drag->setThreshold(5); + + mouseRegion->setAcceptedButtons(Qt::LeftButton); + QQuickItem *blackRect = window.rootObject()->findChild<QQuickItem*>("blackrect"); + QVERIFY(blackRect != 0); + QVERIFY(blackRect == drag->target()); + QVERIFY(!drag->active()); + QTest::mousePress(&window, Qt::LeftButton, 0, QPoint(100,100)); + QVERIFY(!drag->active()); + QTest::mouseMove(&window, QPoint(100, 102), 50); + QTest::mouseMove(&window, QPoint(100, 106), 50); + QTest::mouseMove(&window, QPoint(100, 122), 50); + QTRY_COMPARE(blackRect->x(), 50.0); + QTRY_COMPARE(blackRect->y(), 66.0); + QTest::mouseRelease(&window, Qt::LeftButton, 0, QPoint(100,122)); + + // reset rect position + blackRect->setX(50.0); + blackRect->setY(50.0); + + // now try with smoothed disabled + drag->setSmoothed(false); + QVERIFY(!drag->active()); + QTest::mousePress(&window, Qt::LeftButton, 0, QPoint(100,100)); + QVERIFY(!drag->active()); + QTest::mouseMove(&window, QPoint(100, 102), 50); + QTest::mouseMove(&window, QPoint(100, 106), 50); + QTest::mouseMove(&window, QPoint(100, 122), 50); + QTRY_COMPARE(blackRect->x(), 50.0); + QTRY_COMPARE(blackRect->y(), 72.0); + QTest::mouseRelease(&window, Qt::LeftButton, 0, QPoint(100, 122)); +} void tst_QQuickMouseArea::dragThreshold() { @@ -1639,6 +1686,69 @@ void tst_QQuickMouseArea::nestedStopAtBounds() QTest::mouseRelease(&view, Qt::LeftButton, 0, position); } +void tst_QQuickMouseArea::containsPress_data() +{ + QTest::addColumn<bool>("hoverEnabled"); + + QTest::newRow("hover enabled") << true; + QTest::newRow("hover disaabled") << false; +} + +void tst_QQuickMouseArea::containsPress() +{ + QFETCH(bool, hoverEnabled); + + QQuickView window; + QByteArray errorMessage; + QVERIFY2(initView(window, testFileUrl("containsPress.qml"), true, &errorMessage), errorMessage.constData()); + window.show(); + window.requestActivate(); + QVERIFY(QTest::qWaitForWindowExposed(&window)); + QQuickItem *root = window.rootObject(); + QVERIFY(root != 0); + + QQuickMouseArea *mouseArea = window.rootObject()->findChild<QQuickMouseArea*>("mouseArea"); + QVERIFY(mouseArea != 0); + + QSignalSpy containsPressSpy(mouseArea, SIGNAL(containsPressChanged())); + + mouseArea->setHoverEnabled(hoverEnabled); + + QTest::mouseMove(&window, QPoint(22,33)); + QCOMPARE(mouseArea->hovered(), false); + QCOMPARE(mouseArea->pressed(), false); + QCOMPARE(mouseArea->containsPress(), false); + + QTest::mouseMove(&window, QPoint(200,200)); + QCOMPARE(mouseArea->hovered(), hoverEnabled); + QCOMPARE(mouseArea->pressed(), false); + QCOMPARE(mouseArea->containsPress(), false); + + QTest::mousePress(&window, Qt::LeftButton, Qt::NoModifier, QPoint(200,200)); + QCOMPARE(mouseArea->hovered(), true); + QTRY_COMPARE(mouseArea->pressed(), true); + QCOMPARE(mouseArea->containsPress(), true); + QCOMPARE(containsPressSpy.count(), 1); + + QTest::mouseMove(&window, QPoint(22,33)); + QCOMPARE(mouseArea->hovered(), false); + QCOMPARE(mouseArea->pressed(), true); + QCOMPARE(mouseArea->containsPress(), false); + QCOMPARE(containsPressSpy.count(), 2); + + QTest::mouseMove(&window, QPoint(200,200)); + QCOMPARE(mouseArea->hovered(), true); + QCOMPARE(mouseArea->pressed(), true); + QCOMPARE(mouseArea->containsPress(), true); + QCOMPARE(containsPressSpy.count(), 3); + + QTest::mouseRelease(&window, Qt::LeftButton, Qt::NoModifier, QPoint(200,200)); + QCOMPARE(mouseArea->hovered(), hoverEnabled); + QCOMPARE(mouseArea->pressed(), false); + QCOMPARE(mouseArea->containsPress(), false); + QCOMPARE(containsPressSpy.count(), 4); +} + QTEST_MAIN(tst_QQuickMouseArea) #include "tst_qquickmousearea.moc" diff --git a/tests/auto/quick/qquickmultipointtoucharea/qquickmultipointtoucharea.pro b/tests/auto/quick/qquickmultipointtoucharea/qquickmultipointtoucharea.pro index d3abc198d9..5724a7179e 100644 --- a/tests/auto/quick/qquickmultipointtoucharea/qquickmultipointtoucharea.pro +++ b/tests/auto/quick/qquickmultipointtoucharea/qquickmultipointtoucharea.pro @@ -8,6 +8,7 @@ SOURCES += tst_qquickmultipointtoucharea.cpp TESTDATA = data/* include(../../shared/util.pri) +include(../shared/util.pri) QT += core-private gui-private qml-private quick-private testlib DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0 diff --git a/tests/auto/quick/qquickmultipointtoucharea/tst_qquickmultipointtoucharea.cpp b/tests/auto/quick/qquickmultipointtoucharea/tst_qquickmultipointtoucharea.cpp index 1d4932c432..842babddd9 100644 --- a/tests/auto/quick/qquickmultipointtoucharea/tst_qquickmultipointtoucharea.cpp +++ b/tests/auto/quick/qquickmultipointtoucharea/tst_qquickmultipointtoucharea.cpp @@ -48,12 +48,14 @@ #include <QtQuick/qquickview.h> #include <QtGui/QScreen> #include "../../shared/util.h" +#include "../shared/viewtestutil.h" class tst_QQuickMultiPointTouchArea : public QQmlDataTest { Q_OBJECT public: tst_QQuickMultiPointTouchArea() : device(0) { } + private slots: void initTestCase() { QQmlDataTest::initTestCase(); @@ -118,6 +120,7 @@ void tst_QQuickMultiPointTouchArea::signalTest() QTest::QTouchEventSequence sequence = QTest::touchEvent(window.data(), device); sequence.press(0, p1).press(1, p2).commit(); + QQuickTouchUtils::flush(window.data()); QCOMPARE(area->property("touchPointPressCount").toInt(), 2); QCOMPARE(area->property("touchPointUpdateCount").toInt(), 0); @@ -126,6 +129,7 @@ void tst_QQuickMultiPointTouchArea::signalTest() QMetaObject::invokeMethod(area, "clearCounts"); sequence.stationary(0).stationary(1).press(2, p3).commit(); + QQuickTouchUtils::flush(window.data()); QCOMPARE(area->property("touchPointPressCount").toInt(), 1); QCOMPARE(area->property("touchPointUpdateCount").toInt(), 0); @@ -136,6 +140,7 @@ void tst_QQuickMultiPointTouchArea::signalTest() p1 -= QPoint(10,10); p2 += QPoint(10,10); sequence.move(0, p1).move(1, p2).stationary(2).commit(); + QQuickTouchUtils::flush(window.data()); QCOMPARE(area->property("touchPointPressCount").toInt(), 0); QCOMPARE(area->property("touchPointUpdateCount").toInt(), 2); @@ -146,6 +151,7 @@ void tst_QQuickMultiPointTouchArea::signalTest() p3 += QPoint(10,10); sequence.release(0, p1).release(1, p2) .move(2, p3).press(3, p4).press(4, p5).commit(); + QQuickTouchUtils::flush(window.data()); QCOMPARE(area->property("touchPointPressCount").toInt(), 2); QCOMPARE(area->property("touchPointUpdateCount").toInt(), 1); @@ -154,6 +160,7 @@ void tst_QQuickMultiPointTouchArea::signalTest() QMetaObject::invokeMethod(area, "clearCounts"); sequence.release(2, p3).release(3, p4).release(4, p5).commit(); + QQuickTouchUtils::flush(window.data()); QCOMPARE(area->property("touchPointPressCount").toInt(), 0); QCOMPARE(area->property("touchPointUpdateCount").toInt(), 0); @@ -177,12 +184,14 @@ void tst_QQuickMultiPointTouchArea::release() QTest::QTouchEventSequence sequence = QTest::touchEvent(window.data(), device); sequence.press(0, p1).commit(); + QQuickTouchUtils::flush(window.data()); QCOMPARE(point1->pressed(), true); p1 += QPoint(0,10); sequence.move(0, p1).commit(); + QQuickTouchUtils::flush(window.data()); QCOMPARE(point1->pressed(), true); QCOMPARE(point1->x(), qreal(20)); QCOMPARE(point1->y(), qreal(110)); @@ -190,6 +199,7 @@ void tst_QQuickMultiPointTouchArea::release() p1 += QPoint(4,10); sequence.release(0, p1).commit(); + QQuickTouchUtils::flush(window.data()); //test that a release without a prior move to the release position successfully updates the point's position QCOMPARE(point1->pressed(), false); @@ -216,12 +226,14 @@ void tst_QQuickMultiPointTouchArea::reuse() QTest::QTouchEventSequence sequence = QTest::touchEvent(window.data(), device); sequence.press(0, p1).press(1, p2).commit(); + QQuickTouchUtils::flush(window.data()); QCOMPARE(point1->pressed(), true); QCOMPARE(point2->pressed(), true); QCOMPARE(point3->pressed(), false); sequence.release(0, p1).stationary(1).press(2, p3).commit(); + QQuickTouchUtils::flush(window.data()); //we shouldn't reuse point 1 yet QCOMPARE(point1->pressed(), false); @@ -230,24 +242,28 @@ void tst_QQuickMultiPointTouchArea::reuse() //back to base state (no touches) sequence.release(1, p2).release(2, p3).commit(); + QQuickTouchUtils::flush(window.data()); QCOMPARE(point1->pressed(), false); QCOMPARE(point2->pressed(), false); QCOMPARE(point3->pressed(), false); sequence.press(0, p1).press(1, p2).commit(); + QQuickTouchUtils::flush(window.data()); QCOMPARE(point1->pressed(), true); QCOMPARE(point2->pressed(), true); QCOMPARE(point3->pressed(), false); sequence.release(0, p1).stationary(1).commit(); + QQuickTouchUtils::flush(window.data()); QCOMPARE(point1->pressed(), false); QCOMPARE(point2->pressed(), true); QCOMPARE(point3->pressed(), false); sequence.press(4, p4).stationary(1).commit(); + QQuickTouchUtils::flush(window.data()); //the new touch point should reuse point 1 QCOMPARE(point1->pressed(), true); @@ -283,6 +299,7 @@ void tst_QQuickMultiPointTouchArea::nonOverlapping() QTest::QTouchEventSequence sequence = QTest::touchEvent(window.data(), device); sequence.press(0, p1).commit(); + QQuickTouchUtils::flush(window.data()); QCOMPARE(point11->pressed(), false); QCOMPARE(point12->pressed(), false); @@ -291,6 +308,7 @@ void tst_QQuickMultiPointTouchArea::nonOverlapping() QCOMPARE(point23->pressed(), false); sequence.stationary(0).press(1, p2).commit(); + QQuickTouchUtils::flush(window.data()); QCOMPARE(point11->pressed(), true); QCOMPARE(point12->pressed(), true); @@ -304,6 +322,7 @@ void tst_QQuickMultiPointTouchArea::nonOverlapping() p1 += QPoint(0,10); p2 += QPoint(5,0); sequence.move(0, p1).move(1, p2).commit(); + QQuickTouchUtils::flush(window.data()); QCOMPARE(point11->pressed(), true); QCOMPARE(point12->pressed(), true); @@ -315,6 +334,7 @@ void tst_QQuickMultiPointTouchArea::nonOverlapping() QCOMPARE(point12->x(), qreal(45)); QCOMPARE(point12->y(), qreal(100)); sequence.stationary(0).stationary(1).press(2, p3).commit(); + QQuickTouchUtils::flush(window.data()); QCOMPARE(point11->pressed(), true); QCOMPARE(point12->pressed(), true); @@ -323,6 +343,7 @@ void tst_QQuickMultiPointTouchArea::nonOverlapping() QCOMPARE(point23->pressed(), false); sequence.stationary(0).stationary(1).stationary(2).press(3, p4).press(4, p5).commit(); + QQuickTouchUtils::flush(window.data()); QCOMPARE(point11->pressed(), true); QCOMPARE(point12->pressed(), true); @@ -342,6 +363,7 @@ void tst_QQuickMultiPointTouchArea::nonOverlapping() p4 += QPoint(1,-1); p5 += QPoint(-7,10); sequence.move(0, p1).move(1, p2).move(2, p3).move(3, p4).move(4, p5).commit(); + QQuickTouchUtils::flush(window.data()); QCOMPARE(point11->pressed(), true); QCOMPARE(point12->pressed(), true); @@ -356,6 +378,7 @@ void tst_QQuickMultiPointTouchArea::nonOverlapping() QCOMPARE(point23->x(), qreal(93)); QCOMPARE(point23->y(), qreal(30)); sequence.release(0, p1).release(1, p2).release(2, p3).release(3, p4).release(4, p5).commit(); + QQuickTouchUtils::flush(window.data()); QCOMPARE(point11->pressed(), false); QCOMPARE(point12->pressed(), false); @@ -388,6 +411,7 @@ void tst_QQuickMultiPointTouchArea::nested() QTest::QTouchEventSequence sequence = QTest::touchEvent(window.data(), device); sequence.press(0, p1).commit(); + QQuickTouchUtils::flush(window.data()); QCOMPARE(point11->pressed(), false); QCOMPARE(point12->pressed(), false); @@ -396,6 +420,7 @@ void tst_QQuickMultiPointTouchArea::nested() QCOMPARE(point23->pressed(), false); sequence.stationary(0).press(1, p2).commit(); + QQuickTouchUtils::flush(window.data()); QCOMPARE(point11->pressed(), true); QCOMPARE(point12->pressed(), true); @@ -409,6 +434,7 @@ void tst_QQuickMultiPointTouchArea::nested() p1 += QPoint(0,10); p2 += QPoint(5,0); sequence.move(0, p1).move(1, p2).commit(); + QQuickTouchUtils::flush(window.data()); QCOMPARE(point11->pressed(), true); QCOMPARE(point12->pressed(), true); @@ -420,6 +446,7 @@ void tst_QQuickMultiPointTouchArea::nested() QCOMPARE(point12->x(), qreal(45)); QCOMPARE(point12->y(), qreal(100)); sequence.stationary(0).stationary(1).press(2, p3).commit(); + QQuickTouchUtils::flush(window.data()); QCOMPARE(point11->pressed(), true); QCOMPARE(point12->pressed(), true); @@ -435,6 +462,7 @@ void tst_QQuickMultiPointTouchArea::nested() QCOMPARE(point23->x(), qreal(60)); QCOMPARE(point23->y(), qreal(180)); sequence.stationary(0).stationary(1).stationary(2).press(3, QPoint(80,180)).press(4, QPoint(100,180)).commit(); + QQuickTouchUtils::flush(window.data()); QCOMPARE(point11->pressed(), true); QCOMPARE(point12->pressed(), true); @@ -455,6 +483,7 @@ void tst_QQuickMultiPointTouchArea::nested() p2 += QPoint(17,17); p3 += QPoint(3,0); sequence.move(0, p1).move(1, p2).move(2, p3).commit(); + QQuickTouchUtils::flush(window.data()); QCOMPARE(point11->pressed(), true); QCOMPARE(point12->pressed(), true); @@ -472,6 +501,7 @@ void tst_QQuickMultiPointTouchArea::nested() p2 += QPoint(17,17); p3 += QPoint(3,0); sequence.move(0, p1).move(1, p2).move(2, p3).commit(); + QQuickTouchUtils::flush(window.data()); QCOMPARE(point11->pressed(), false); QCOMPARE(point12->pressed(), false); @@ -489,6 +519,7 @@ void tst_QQuickMultiPointTouchArea::nested() sequence.release(0, p1).release(1, p2).release(2, p3).commit(); sequence.press(0, p1).commit(); + QQuickTouchUtils::flush(window.data()); QCOMPARE(point11->pressed(), false); QCOMPARE(point12->pressed(), false); @@ -497,11 +528,13 @@ void tst_QQuickMultiPointTouchArea::nested() QCOMPARE(point23->pressed(), false); sequence.release(0, p1).commit(); + QQuickTouchUtils::flush(window.data()); //test with grabbing turned off window->rootObject()->setProperty("grabInnerArea", false); sequence.press(0, p1).press(1, p2).press(2, p3).commit(); + QQuickTouchUtils::flush(window.data()); QCOMPARE(point11->pressed(), true); QCOMPARE(point12->pressed(), true); @@ -513,6 +546,7 @@ void tst_QQuickMultiPointTouchArea::nested() p2 -= QPoint(17,17); p3 -= QPoint(3,0); sequence.move(0, p1).move(1, p2).move(2, p3).commit(); + QQuickTouchUtils::flush(window.data()); QCOMPARE(point11->pressed(), true); QCOMPARE(point12->pressed(), true); @@ -530,6 +564,7 @@ void tst_QQuickMultiPointTouchArea::nested() p2 -= QPoint(17,17); p3 -= QPoint(3,0); sequence.move(0, p1).move(1, p2).move(2, p3).commit(); + QQuickTouchUtils::flush(window.data()); QCOMPARE(point11->pressed(), true); QCOMPARE(point12->pressed(), true); @@ -545,6 +580,7 @@ void tst_QQuickMultiPointTouchArea::nested() QCOMPARE(point23->x(), qreal(60)); QCOMPARE(point23->y(), qreal(180)); sequence.release(0, p1).release(1, p2).release(2, p3).commit(); + QQuickTouchUtils::flush(window.data()); } void tst_QQuickMultiPointTouchArea::inFlickable() @@ -569,25 +605,30 @@ void tst_QQuickMultiPointTouchArea::inFlickable() //moving one point vertically QTest::touchEvent(window.data(), device).press(0, p1); + QQuickTouchUtils::flush(window.data()); p1 += QPoint(0,15); QTest::touchEvent(window.data(), device).move(0, p1); + QQuickTouchUtils::flush(window.data()); p1 += QPoint(0,15); QTest::touchEvent(window.data(), device).move(0, p1); + QQuickTouchUtils::flush(window.data()); p1 += QPoint(0,15); QTest::touchEvent(window.data(), device).move(0, p1); + QQuickTouchUtils::flush(window.data()); p1 += QPoint(0,15); QTest::touchEvent(window.data(), device).move(0, p1); + QQuickTouchUtils::flush(window.data()); QVERIFY(flickable->contentY() < 0); QCOMPARE(point11->pressed(), false); QCOMPARE(point12->pressed(), false); QTest::touchEvent(window.data(), device).release(0, p1); - QTest::qWait(50); + QQuickTouchUtils::flush(window.data()); QTRY_VERIFY(!flickable->isMoving()); @@ -595,6 +636,7 @@ void tst_QQuickMultiPointTouchArea::inFlickable() p1 = QPoint(20,100); QTest::touchEvent(window.data(), device).press(0, p1).press(1, p2); QTest::mousePress(window.data(), Qt::LeftButton, 0, p1); + QQuickTouchUtils::flush(window.data()); QCOMPARE(point11->pressed(), true); QCOMPARE(point12->pressed(), true); @@ -604,18 +646,22 @@ void tst_QQuickMultiPointTouchArea::inFlickable() p1 += QPoint(0,15); p2 += QPoint(0,15); QTest::touchEvent(window.data(), device).move(0, p1).move(1, p2); QTest::mouseMove(window.data(), p1); + QQuickTouchUtils::flush(window.data()); p1 += QPoint(0,15); p2 += QPoint(0,15); QTest::touchEvent(window.data(), device).move(0, p1).move(1, p2); QTest::mouseMove(window.data(), p1); + QQuickTouchUtils::flush(window.data()); p1 += QPoint(0,15); p2 += QPoint(0,15); QTest::touchEvent(window.data(), device).move(0, p1).move(1, p2); QTest::mouseMove(window.data(), p1); + QQuickTouchUtils::flush(window.data()); p1 += QPoint(0,15); p2 += QPoint(0,15); QTest::touchEvent(window.data(), device).move(0, p1).move(1, p2); QTest::mouseMove(window.data(), p1); + QQuickTouchUtils::flush(window.data()); QVERIFY(flickable->contentY() < 0); QCOMPARE(point11->pressed(), false); @@ -625,7 +671,7 @@ void tst_QQuickMultiPointTouchArea::inFlickable() QTest::touchEvent(window.data(), device).release(0, p1).release(1, p2); QTest::mouseRelease(window.data(), Qt::LeftButton, 0, p1); - QTest::qWait(50); + QQuickTouchUtils::flush(window.data()); QTRY_VERIFY(!flickable->isMoving()); @@ -633,6 +679,7 @@ void tst_QQuickMultiPointTouchArea::inFlickable() p1 = QPoint(20,100); p2 = QPoint(40,100); QTest::touchEvent(window.data(), device).press(0, p1).press(1, p2); + QQuickTouchUtils::flush(window.data()); // ensure that mouse events do not fall through to the Flickable mpta->setMaximumTouchPoints(3); QTest::mousePress(window.data(), Qt::LeftButton, 0, p1); @@ -643,34 +690,42 @@ void tst_QQuickMultiPointTouchArea::inFlickable() p1 += QPoint(15,0); p2 += QPoint(15,0); QTest::touchEvent(window.data(), device).move(0, p1).move(1, p2); QTest::mouseMove(window.data(), p1); + QQuickTouchUtils::flush(window.data()); p1 += QPoint(15,0); p2 += QPoint(15,0); QTest::touchEvent(window.data(), device).move(0, p1).move(1, p2); QTest::mouseMove(window.data(), p1); + QQuickTouchUtils::flush(window.data()); p1 += QPoint(15,0); p2 += QPoint(15,0); QTest::touchEvent(window.data(), device).move(0, p1).move(1, p2); QTest::mouseMove(window.data(), p1); + QQuickTouchUtils::flush(window.data()); p1 += QPoint(15,0); p2 += QPoint(15,0); QTest::touchEvent(window.data(), device).move(0, p1).move(1, p2); QTest::mouseMove(window.data(), p1); + QQuickTouchUtils::flush(window.data()); p1 += QPoint(0,15); p2 += QPoint(0,15); QTest::touchEvent(window.data(), device).move(0, p1).move(1, p2); QTest::mouseMove(window.data(), p1); + QQuickTouchUtils::flush(window.data()); p1 += QPoint(0,15); p2 += QPoint(0,15); QTest::touchEvent(window.data(), device).move(0, p1).move(1, p2); QTest::mouseMove(window.data(), p1); + QQuickTouchUtils::flush(window.data()); p1 += QPoint(0,15); p2 += QPoint(0,15); QTest::touchEvent(window.data(), device).move(0, p1).move(1, p2); QTest::mouseMove(window.data(), p1); + QQuickTouchUtils::flush(window.data()); p1 += QPoint(0,15); p2 += QPoint(0,15); QTest::touchEvent(window.data(), device).move(0, p1).move(1, p2); QTest::mouseMove(window.data(), p1); + QQuickTouchUtils::flush(window.data()); QVERIFY(flickable->contentY() == 0); QCOMPARE(point11->pressed(), true); @@ -678,7 +733,7 @@ void tst_QQuickMultiPointTouchArea::inFlickable() QTest::touchEvent(window.data(), device).release(0, p1).release(1, p2); QTest::mouseRelease(window.data(), Qt::LeftButton, 0, p1); - QTest::qWait(50); + QQuickTouchUtils::flush(window.data()); } // test that dragging out of a Flickable containing a MPTA doesn't harm Flickable's state. @@ -699,28 +754,34 @@ void tst_QQuickMultiPointTouchArea::inFlickable2() // move point horizontally, out of Flickable area QTest::touchEvent(window.data(), device).press(0, p1); + QQuickTouchUtils::flush(window.data()); QTest::mousePress(window.data(), Qt::LeftButton, 0, p1); p1 += QPoint(15,0); QTest::touchEvent(window.data(), device).move(0, p1); + QQuickTouchUtils::flush(window.data()); QTest::mouseMove(window.data(), p1); p1 += QPoint(15,0); QTest::touchEvent(window.data(), device).move(0, p1); + QQuickTouchUtils::flush(window.data()); QTest::mouseMove(window.data(), p1); p1 += QPoint(15,0); QTest::touchEvent(window.data(), device).move(0, p1); + QQuickTouchUtils::flush(window.data()); QTest::mouseMove(window.data(), p1); p1 += QPoint(15,0); QTest::touchEvent(window.data(), device).move(0, p1); + QQuickTouchUtils::flush(window.data()); QTest::mouseMove(window.data(), p1); QVERIFY(!flickable->isMoving()); QVERIFY(point11->pressed()); QTest::touchEvent(window.data(), device).release(0, p1); + QQuickTouchUtils::flush(window.data()); QTest::mouseRelease(window.data(), Qt::LeftButton, 0, p1); QTest::qWait(50); @@ -729,26 +790,32 @@ void tst_QQuickMultiPointTouchArea::inFlickable2() // Check that we can still move the Flickable p1 = QPoint(50,100); QTest::touchEvent(window.data(), device).press(0, p1); + QQuickTouchUtils::flush(window.data()); QCOMPARE(point11->pressed(), true); p1 += QPoint(0,15); QTest::touchEvent(window.data(), device).move(0, p1); + QQuickTouchUtils::flush(window.data()); p1 += QPoint(0,15); QTest::touchEvent(window.data(), device).move(0, p1); + QQuickTouchUtils::flush(window.data()); p1 += QPoint(0,15); QTest::touchEvent(window.data(), device).move(0, p1); + QQuickTouchUtils::flush(window.data()); p1 += QPoint(0,15); QTest::touchEvent(window.data(), device).move(0, p1); + QQuickTouchUtils::flush(window.data()); QVERIFY(flickable->contentY() < 0); QVERIFY(flickable->isMoving()); QCOMPARE(point11->pressed(), true); QTest::touchEvent(window.data(), device).release(0, p1); + QQuickTouchUtils::flush(window.data()); QTest::qWait(50); QTRY_VERIFY(!flickable->isMoving()); @@ -859,7 +926,9 @@ void tst_QQuickMultiPointTouchArea::mouseAsTouchpoint() // Touch both, release one, manipulate other touchpoint with mouse QTest::touchEvent(window.data(), device).press(1, touch1); + QQuickTouchUtils::flush(window.data()); QTest::touchEvent(window.data(), device).press(2, touch2); + QQuickTouchUtils::flush(window.data()); QCOMPARE(touch1rect->property("x").toInt(), touch1.x()); QCOMPARE(touch1rect->property("y").toInt(), touch1.y()); QCOMPARE(touch2rect->property("x").toInt(), touch2.x()); @@ -867,12 +936,14 @@ void tst_QQuickMultiPointTouchArea::mouseAsTouchpoint() QTest::touchEvent(window.data(), device).release(1, touch1); touch1.setY(20); QTest::mousePress(window.data(), Qt::LeftButton, 0, touch1); + QQuickTouchUtils::flush(window.data()); QCOMPARE(touch1rect->property("x").toInt(), touch1.x()); QCOMPARE(touch1rect->property("y").toInt(), touch1.y()); QCOMPARE(touch2rect->property("x").toInt(), touch2.x()); QCOMPARE(touch2rect->property("y").toInt(), touch2.y()); QTest::touchEvent(window.data(), device).release(2, touch2); QTest::mouseRelease(window.data(), Qt::LeftButton, 0, touch1); + QQuickTouchUtils::flush(window.data()); // Start with mouse, move it, touch second point, move it QTest::mousePress(window.data(), Qt::LeftButton, 0, touch1); @@ -882,12 +953,14 @@ void tst_QQuickMultiPointTouchArea::mouseAsTouchpoint() QCOMPARE(touch1rect->property("y").toInt(), touch1.y()); touch2.setX(60); QTest::touchEvent(window.data(), device).press(3, touch2); + QQuickTouchUtils::flush(window.data()); QCOMPARE(touch1rect->property("x").toInt(), touch1.x()); QCOMPARE(touch1rect->property("y").toInt(), touch1.y()); QCOMPARE(touch2rect->property("x").toInt(), touch2.x()); QCOMPARE(touch2rect->property("y").toInt(), touch2.y()); touch2.setY(150); QTest::touchEvent(window.data(), device).move(3, touch2); + QQuickTouchUtils::flush(window.data()); QCOMPARE(touch1rect->property("x").toInt(), touch1.x()); QCOMPARE(touch1rect->property("y").toInt(), touch1.y()); QCOMPARE(touch2rect->property("x").toInt(), touch2.x()); @@ -895,6 +968,7 @@ void tst_QQuickMultiPointTouchArea::mouseAsTouchpoint() // Touch third point - nothing happens QTest::touchEvent(window.data(), device).press(4, touch3); + QQuickTouchUtils::flush(window.data()); QCOMPARE(touch1rect->property("x").toInt(), touch1.x()); QCOMPARE(touch1rect->property("y").toInt(), touch1.y()); QCOMPARE(touch2rect->property("x").toInt(), touch2.x()); @@ -903,7 +977,9 @@ void tst_QQuickMultiPointTouchArea::mouseAsTouchpoint() // Release all QTest::mouseRelease(window.data(), Qt::LeftButton, 0, touch1); QTest::touchEvent(window.data(), device).release(3, touch2); + QQuickTouchUtils::flush(window.data()); QTest::touchEvent(window.data(), device).release(4, touch3); + QQuickTouchUtils::flush(window.data()); QCOMPARE(touch1rect->property("x").toInt(), touch1.x()); QCOMPARE(touch1rect->property("y").toInt(), touch1.y()); QCOMPARE(touch2rect->property("x").toInt(), touch2.x()); @@ -922,12 +998,14 @@ void tst_QQuickMultiPointTouchArea::mouseAsTouchpoint() QCOMPARE(touch1rect->property("x").toInt(), mouse1.x()); QCOMPARE(touch1rect->property("y").toInt(), mouse1.y()); QTest::touchEvent(window.data(), device).press(1, touch1); + QQuickTouchUtils::flush(window.data()); QCOMPARE(touch1rect->property("x").toInt(), mouse1.x()); QCOMPARE(touch1rect->property("y").toInt(), mouse1.y()); QCOMPARE(touch2rect->property("x").toInt(), touch1.x()); QCOMPARE(touch2rect->property("y").toInt(), touch1.y()); QTest::touchEvent(window.data(), device).press(2, touch2).press(3, touch3).press(4, touch4); + QQuickTouchUtils::flush(window.data()); QCOMPARE(touch1rect->property("x").toInt(), mouse1.x()); QCOMPARE(touch1rect->property("y").toInt(), mouse1.y()); QCOMPARE(touch2rect->property("x").toInt(), touch1.x()); @@ -942,6 +1020,7 @@ void tst_QQuickMultiPointTouchArea::mouseAsTouchpoint() // Release all QTest::mouseRelease(window.data(), Qt::LeftButton, 0, mouse1); QTest::touchEvent(window.data(), device).release(1, touch1).release(2, touch2).release(3, touch3).release(4, touch4); + QQuickTouchUtils::flush(window.data()); } dualmpta->setProperty("mouseEnabled", false); @@ -964,13 +1043,16 @@ void tst_QQuickMultiPointTouchArea::mouseAsTouchpoint() QCOMPARE(touch1rect->property("y").toInt(), 10); QTest::touchEvent(window.data(), device).press(1, touch1); + QQuickTouchUtils::flush(window.data()); QCOMPARE(touch1rect->property("x").toInt(), touch1.x()); QCOMPARE(touch1rect->property("y").toInt(), touch1.y()); touch1.setY(150); QTest::touchEvent(window.data(), device).move(1, touch1); + QQuickTouchUtils::flush(window.data()); QCOMPARE(touch1rect->property("x").toInt(), touch1.x()); QCOMPARE(touch1rect->property("y").toInt(), touch1.y()); QTest::touchEvent(window.data(), device).press(2, touch2); + QQuickTouchUtils::flush(window.data()); QCOMPARE(touch1rect->property("x").toInt(), touch1.x()); QCOMPARE(touch1rect->property("y").toInt(), touch1.y()); QCOMPARE(touch2rect->property("x").toInt(), touch2.x()); @@ -979,7 +1061,9 @@ void tst_QQuickMultiPointTouchArea::mouseAsTouchpoint() // Release all QTest::mouseRelease(window.data(), Qt::LeftButton, 0, mouse1); QTest::touchEvent(window.data(), device).release(1, touch1); + QQuickTouchUtils::flush(window.data()); QTest::touchEvent(window.data(), device).release(2, touch2); + QQuickTouchUtils::flush(window.data()); QCOMPARE(touch1rect->property("x").toInt(), touch1.x()); QCOMPARE(touch1rect->property("y").toInt(), touch1.y()); QCOMPARE(touch2rect->property("x").toInt(), touch2.x()); @@ -1028,7 +1112,6 @@ void tst_QQuickMultiPointTouchArea::transformedTouchArea_data() QTest::newRow("3rd point inside") << QPoint(140, 260) << QPoint(260, 140) << QPoint(200, 140) << 0 << 0 << 1; - QTest::newRow("all points inside") << QPoint(200, 140) << QPoint(200, 260) << QPoint(140, 200) << 1 << 2 << 3; diff --git a/tests/auto/quick/qquickopenglinfo/data/basic.qml b/tests/auto/quick/qquickopenglinfo/data/basic.qml new file mode 100644 index 0000000000..b48447941b --- /dev/null +++ b/tests/auto/quick/qquickopenglinfo/data/basic.qml @@ -0,0 +1,8 @@ +import QtQuick 2.4 + +Item { + property int majorVersion: OpenGLInfo.majorVersion + property int minorVersion: OpenGLInfo.minorVersion + property int profile: OpenGLInfo.profile + property int renderableType: OpenGLInfo.renderableType +} diff --git a/tests/auto/quick/qquickopenglinfo/qquickopenglinfo.pro b/tests/auto/quick/qquickopenglinfo/qquickopenglinfo.pro new file mode 100644 index 0000000000..8489dfffd2 --- /dev/null +++ b/tests/auto/quick/qquickopenglinfo/qquickopenglinfo.pro @@ -0,0 +1,15 @@ +CONFIG += testcase +TARGET = tst_qquickopenglinfo +SOURCES += tst_qquickopenglinfo.cpp + +TESTDATA = data/* +include(../../shared/util.pri) + +osx:CONFIG -= app_bundle + +CONFIG += parallel_test +QT += quick testlib + +OTHER_FILES += \ + data/basic.qml + diff --git a/tests/auto/quick/qquickopenglinfo/tst_qquickopenglinfo.cpp b/tests/auto/quick/qquickopenglinfo/tst_qquickopenglinfo.cpp new file mode 100644 index 0000000000..de28769e36 --- /dev/null +++ b/tests/auto/quick/qquickopenglinfo/tst_qquickopenglinfo.cpp @@ -0,0 +1,85 @@ +/**************************************************************************** +** +** Copyright (C) 2014 BlackBerry Ltd. +** Contact: http://www.qt-project.org/legal +** +** This file is part of the test suite of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Digia gives you certain additional +** rights. These rights are described in the Digia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include <QtTest/qtest.h> +#include <QtTest/qsignalspy.h> + +#include <QtQuick/qquickitem.h> +#include <QtQuick/qquickview.h> + +#include <QtGui/qopenglcontext.h> +#include <QtGui/qsurfaceformat.h> + +#include "../../shared/util.h" + +class tst_QQuickOpenGLInfo : public QQmlDataTest +{ + Q_OBJECT + +private slots: + void testProperties(); +}; + +void tst_QQuickOpenGLInfo::testProperties() +{ + QQuickView view; + view.setSource(QUrl::fromLocalFile("data/basic.qml")); + + view.show(); + QVERIFY(QTest::qWaitForWindowExposed(&view)); + + QSignalSpy spy(&view, SIGNAL(sceneGraphInitialized())); + spy.wait(); + + QVERIFY(view.openglContext()); + QSurfaceFormat format = view.openglContext()->format(); + + QObject* obj = view.rootObject(); + QVERIFY(obj); + QCOMPARE(obj->property("majorVersion").toInt(), format.majorVersion()); + QCOMPARE(obj->property("minorVersion").toInt(), format.minorVersion()); + QCOMPARE(obj->property("profile").toInt(), static_cast<int>(format.profile())); + QCOMPARE(obj->property("renderableType").toInt(), static_cast<int>(format.renderableType())); +} + +QTEST_MAIN(tst_QQuickOpenGLInfo) + +#include "tst_qquickopenglinfo.moc" diff --git a/tests/auto/quick/qquickpincharea/qquickpincharea.pro b/tests/auto/quick/qquickpincharea/qquickpincharea.pro index 970ce48851..fa14afa261 100644 --- a/tests/auto/quick/qquickpincharea/qquickpincharea.pro +++ b/tests/auto/quick/qquickpincharea/qquickpincharea.pro @@ -6,6 +6,7 @@ macx:CONFIG -= app_bundle SOURCES += tst_qquickpincharea.cpp include (../../shared/util.pri) +include (../shared/util.pri) TESTDATA = data/* diff --git a/tests/auto/quick/qquickpincharea/tst_qquickpincharea.cpp b/tests/auto/quick/qquickpincharea/tst_qquickpincharea.cpp index b9d314b63e..1dbce1b730 100644 --- a/tests/auto/quick/qquickpincharea/tst_qquickpincharea.cpp +++ b/tests/auto/quick/qquickpincharea/tst_qquickpincharea.cpp @@ -48,6 +48,7 @@ #include <QtQuick/qquickview.h> #include <QtQml/qqmlcontext.h> #include "../../shared/util.h" +#include "../shared/viewtestutil.h" class tst_QQuickPinchArea: public QQmlDataTest { @@ -232,15 +233,18 @@ void tst_QQuickPinchArea::scale() { QTest::QTouchEventSequence pinchSequence = QTest::touchEvent(window, device); pinchSequence.press(0, p1, window).commit(); + QQuickTouchUtils::flush(window); // In order for the stationary point to remember its previous position, // we have to reuse the same pinchSequence object. Otherwise if we let it // be destroyed and then start a new sequence, point 0 will default to being // stationary at 0, 0, and PinchArea will filter out that touchpoint because // it is outside its bounds. pinchSequence.stationary(0).press(1, p2, window).commit(); + QQuickTouchUtils::flush(window); p1 -= QPoint(10,10); p2 += QPoint(10,10); pinchSequence.move(0, p1,window).move(1, p2,window).commit(); + QQuickTouchUtils::flush(window); QCOMPARE(root->property("scale").toReal(), 1.0); QVERIFY(root->property("pinchActive").toBool()); @@ -248,6 +252,7 @@ void tst_QQuickPinchArea::scale() p1 -= QPoint(10,10); p2 += QPoint(10,10); pinchSequence.move(0, p1,window).move(1, p2,window).commit(); + QQuickTouchUtils::flush(window); QCOMPARE(root->property("scale").toReal(), 1.5); QCOMPARE(root->property("center").toPointF(), QPointF(40, 40)); // blackrect is at 50,50 @@ -260,8 +265,10 @@ void tst_QQuickPinchArea::scale() { QTest::QTouchEventSequence pinchSequence = QTest::touchEvent(window, device); pinchSequence.move(0, p1, window).move(1, p2, window).commit(); + QQuickTouchUtils::flush(window); QCOMPARE(blackRect->scale(), 2.0); pinchSequence.release(0, p1, window).release(1, p2, window).commit(); + QQuickTouchUtils::flush(window); } QVERIFY(!root->property("pinchActive").toBool()); } @@ -293,12 +300,15 @@ void tst_QQuickPinchArea::pan() { QTest::QTouchEventSequence pinchSequence = QTest::touchEvent(window, device); pinchSequence.press(0, p1, window).commit(); + QQuickTouchUtils::flush(window); // In order for the stationary point to remember its previous position, // we have to reuse the same pinchSequence object. pinchSequence.stationary(0).press(1, p2, window).commit(); + QQuickTouchUtils::flush(window); p1 += QPoint(10,10); p2 += QPoint(10,10); pinchSequence.move(0, p1,window).move(1, p2,window).commit(); + QQuickTouchUtils::flush(window); QCOMPARE(root->property("scale").toReal(), 1.0); QVERIFY(root->property("pinchActive").toBool()); @@ -306,6 +316,7 @@ void tst_QQuickPinchArea::pan() p1 += QPoint(10,10); p2 += QPoint(10,10); pinchSequence.move(0, p1,window).move(1, p2,window).commit(); + QQuickTouchUtils::flush(window); } QCOMPARE(root->property("center").toPointF(), QPointF(60, 60)); // blackrect is at 50,50 @@ -316,11 +327,13 @@ void tst_QQuickPinchArea::pan() p1 += QPoint(100,100); p2 += QPoint(100,100); QTest::touchEvent(window, device).move(0, p1, window).move(1, p2, window); + QQuickTouchUtils::flush(window); QCOMPARE(blackRect->x(), 140.0); QCOMPARE(blackRect->y(), 160.0); QTest::touchEvent(window, device).release(0, p1, window).release(1, p2, window); + QQuickTouchUtils::flush(window); QVERIFY(!root->property("pinchActive").toBool()); } @@ -355,12 +368,15 @@ void tst_QQuickPinchArea::retouch() { QTest::QTouchEventSequence pinchSequence = QTest::touchEvent(window, device); pinchSequence.press(0, p1, window).commit(); + QQuickTouchUtils::flush(window); // In order for the stationary point to remember its previous position, // we have to reuse the same pinchSequence object. pinchSequence.stationary(0).press(1, p2, window).commit(); + QQuickTouchUtils::flush(window); p1 -= QPoint(10,10); p2 += QPoint(10,10); pinchSequence.move(0, p1,window).move(1, p2,window).commit(); + QQuickTouchUtils::flush(window); QCOMPARE(root->property("scale").toReal(), 1.0); QVERIFY(root->property("pinchActive").toBool()); @@ -368,6 +384,7 @@ void tst_QQuickPinchArea::retouch() p1 -= QPoint(10,10); p2 += QPoint(10,10); pinchSequence.move(0, p1,window).move(1, p2,window).commit(); + QQuickTouchUtils::flush(window); QCOMPARE(startedSpy.count(), 1); @@ -382,6 +399,7 @@ void tst_QQuickPinchArea::retouch() // Hold down the first finger but release the second one pinchSequence.stationary(0).release(1, p2, window).commit(); + QQuickTouchUtils::flush(window); QCOMPARE(startedSpy.count(), 1); QCOMPARE(finishedSpy.count(), 0); @@ -390,9 +408,11 @@ void tst_QQuickPinchArea::retouch() // Keep holding down the first finger and re-touch the second one, then move them both pinchSequence.stationary(0).press(1, p2, window).commit(); + QQuickTouchUtils::flush(window); p1 -= QPoint(10,10); p2 += QPoint(10,10); pinchSequence.move(0, p1, window).move(1, p2, window).commit(); + QQuickTouchUtils::flush(window); // Lifting and retouching results in onPinchStarted being called again QCOMPARE(startedSpy.count(), 2); @@ -401,6 +421,7 @@ void tst_QQuickPinchArea::retouch() QCOMPARE(window->rootObject()->property("pointCount").toInt(), 2); pinchSequence.release(0, p1, window).release(1, p2, window).commit(); + QQuickTouchUtils::flush(window); QVERIFY(!root->property("pinchActive").toBool()); QCOMPARE(startedSpy.count(), 2); @@ -456,14 +477,18 @@ void tst_QQuickPinchArea::transformedPinchArea() QTest::QTouchEventSequence pinchSequence = QTest::touchEvent(view, device); // start pinch pinchSequence.press(0, p1, view).commit(); + QQuickTouchUtils::flush(view); // In order for the stationary point to remember its previous position, // we have to reuse the same pinchSequence object. pinchSequence.stationary(0).press(1, p2, view).commit(); + QQuickTouchUtils::flush(view); pinchSequence.stationary(0).move(1, p2 + QPoint(threshold * 2, 0), view).commit(); + QQuickTouchUtils::flush(view); QCOMPARE(pinchArea->property("pinching").toBool(), shouldPinch); // release pinch pinchSequence.release(0, p1, view).release(1, p2, view).commit(); + QQuickTouchUtils::flush(view); QCOMPARE(pinchArea->property("pinching").toBool(), false); } } diff --git a/tests/auto/quick/qquickpixmapcache/tst_qquickpixmapcache.cpp b/tests/auto/quick/qquickpixmapcache/tst_qquickpixmapcache.cpp index 75bd468aef..f104154205 100644 --- a/tests/auto/quick/qquickpixmapcache/tst_qquickpixmapcache.cpp +++ b/tests/auto/quick/qquickpixmapcache/tst_qquickpixmapcache.cpp @@ -59,7 +59,7 @@ class tst_qquickpixmapcache : public QQmlDataTest { Q_OBJECT public: - tst_qquickpixmapcache() : server(14452) {} + tst_qquickpixmapcache() {} private slots: void initTestCase(); @@ -116,6 +116,8 @@ void tst_qquickpixmapcache::initTestCase() { QQmlDataTest::initTestCase(); + QVERIFY2(server.listen(14452), qPrintable(server.errorString())); + // This avoids a race condition/deadlock bug in network config // manager when it is accessed by the HTTP server thread before // anything else. Bug report can be found at: @@ -379,7 +381,8 @@ void tst_qquickpixmapcache::shrinkcache() void createNetworkServer() { QEventLoop eventLoop; - TestHTTPServer server(14453); + TestHTTPServer server; + QVERIFY2(server.listen(14453), qPrintable(server.errorString())); server.serveDirectory(QQmlDataTest::instance()->testFile("http")); QTimer::singleShot(100, &eventLoop, SLOT(quit())); eventLoop.exec(); @@ -407,7 +410,8 @@ void tst_qquickpixmapcache::networkCrash() // QTBUG-22125 void tst_qquickpixmapcache::lockingCrash() { - TestHTTPServer server(14453); + TestHTTPServer server; + QVERIFY2(server.listen(14453), qPrintable(server.errorString())); server.serveDirectory(testFile("http"), TestHTTPServer::Delay); { diff --git a/tests/auto/quick/qquickpositioners/tst_qquickpositioners.cpp b/tests/auto/quick/qquickpositioners/tst_qquickpositioners.cpp index e63ff6639e..035735914a 100644 --- a/tests/auto/quick/qquickpositioners/tst_qquickpositioners.cpp +++ b/tests/auto/quick/qquickpositioners/tst_qquickpositioners.cpp @@ -1857,7 +1857,7 @@ void tst_qquickpositioners::test_conflictinganchors() item = qobject_cast<QQuickItem*>(component.create()); QVERIFY(item); QCOMPARE(messageHandler.messages().size(), 1); - QCOMPARE(messageHandler.messages().back(), QString("file::2:1: QML Column: Cannot specify top, bottom, verticalCenter, fill or centerIn anchors for items inside Column. Column will not function.")); + QCOMPARE(messageHandler.messages().back(), QString("<Unknown File>:2:1: QML Column: Cannot specify top, bottom, verticalCenter, fill or centerIn anchors for items inside Column. Column will not function.")); messageHandler.clear(); delete item; @@ -1865,7 +1865,7 @@ void tst_qquickpositioners::test_conflictinganchors() item = qobject_cast<QQuickItem*>(component.create()); QVERIFY(item); QCOMPARE(messageHandler.messages().size(), 1); - QCOMPARE(messageHandler.messages().back(), QString("file::2:1: QML Column: Cannot specify top, bottom, verticalCenter, fill or centerIn anchors for items inside Column. Column will not function.")); + QCOMPARE(messageHandler.messages().back(), QString("<Unknown File>:2:1: QML Column: Cannot specify top, bottom, verticalCenter, fill or centerIn anchors for items inside Column. Column will not function.")); messageHandler.clear(); delete item; @@ -1879,7 +1879,7 @@ void tst_qquickpositioners::test_conflictinganchors() item = qobject_cast<QQuickItem*>(component.create()); QVERIFY(item); QCOMPARE(messageHandler.messages().size(), 1); - QCOMPARE(messageHandler.messages().back(), QString("file::2:1: QML Row: Cannot specify left, right, horizontalCenter, fill or centerIn anchors for items inside Row. Row will not function.")); + QCOMPARE(messageHandler.messages().back(), QString("<Unknown File>:2:1: QML Row: Cannot specify left, right, horizontalCenter, fill or centerIn anchors for items inside Row. Row will not function.")); messageHandler.clear(); delete item; @@ -1887,7 +1887,7 @@ void tst_qquickpositioners::test_conflictinganchors() item = qobject_cast<QQuickItem*>(component.create()); QVERIFY(item); QCOMPARE(messageHandler.messages().size(), 1); - QCOMPARE(messageHandler.messages().back(), QString("file::2:1: QML Row: Cannot specify left, right, horizontalCenter, fill or centerIn anchors for items inside Row. Row will not function.")); + QCOMPARE(messageHandler.messages().back(), QString("<Unknown File>:2:1: QML Row: Cannot specify left, right, horizontalCenter, fill or centerIn anchors for items inside Row. Row will not function.")); messageHandler.clear(); delete item; @@ -1901,7 +1901,7 @@ void tst_qquickpositioners::test_conflictinganchors() item = qobject_cast<QQuickItem*>(component.create()); QVERIFY(item); QCOMPARE(messageHandler.messages().size(), 1); - QCOMPARE(messageHandler.messages().back(), QString("file::2:1: QML Grid: Cannot specify anchors for items inside Grid. Grid will not function.")); + QCOMPARE(messageHandler.messages().back(), QString("<Unknown File>:2:1: QML Grid: Cannot specify anchors for items inside Grid. Grid will not function.")); messageHandler.clear(); delete item; @@ -1909,7 +1909,7 @@ void tst_qquickpositioners::test_conflictinganchors() item = qobject_cast<QQuickItem*>(component.create()); QVERIFY(item); QCOMPARE(messageHandler.messages().size(), 1); - QCOMPARE(messageHandler.messages().back(), QString("file::2:1: QML Grid: Cannot specify anchors for items inside Grid. Grid will not function.")); + QCOMPARE(messageHandler.messages().back(), QString("<Unknown File>:2:1: QML Grid: Cannot specify anchors for items inside Grid. Grid will not function.")); messageHandler.clear(); delete item; @@ -1917,7 +1917,7 @@ void tst_qquickpositioners::test_conflictinganchors() item = qobject_cast<QQuickItem*>(component.create()); QVERIFY(item); QCOMPARE(messageHandler.messages().size(), 1); - QCOMPARE(messageHandler.messages().back(), QString("file::2:1: QML Flow: Cannot specify anchors for items inside Flow. Flow will not function.")); + QCOMPARE(messageHandler.messages().back(), QString("<Unknown File>:2:1: QML Flow: Cannot specify anchors for items inside Flow. Flow will not function.")); messageHandler.clear(); delete item; @@ -1925,7 +1925,7 @@ void tst_qquickpositioners::test_conflictinganchors() item = qobject_cast<QQuickItem*>(component.create()); QVERIFY(item); QCOMPARE(messageHandler.messages().size(), 1); - QCOMPARE(messageHandler.messages().back(), QString("file::2:1: QML Flow: Cannot specify anchors for items inside Flow. Flow will not function.")); + QCOMPARE(messageHandler.messages().back(), QString("<Unknown File>:2:1: QML Flow: Cannot specify anchors for items inside Flow. Flow will not function.")); delete item; } diff --git a/tests/auto/quick/qquickrepeater/data/invalidContextCrash.qml b/tests/auto/quick/qquickrepeater/data/invalidContextCrash.qml new file mode 100644 index 0000000000..4a822cf25a --- /dev/null +++ b/tests/auto/quick/qquickrepeater/data/invalidContextCrash.qml @@ -0,0 +1,7 @@ +import QtQuick 2.0 +Item { + Repeater { + model: badModel + delegate: Item {} + } +} diff --git a/tests/auto/quick/qquickrepeater/tst_qquickrepeater.cpp b/tests/auto/quick/qquickrepeater/tst_qquickrepeater.cpp index 9fb76f9584..2dc5a65d7d 100644 --- a/tests/auto/quick/qquickrepeater/tst_qquickrepeater.cpp +++ b/tests/auto/quick/qquickrepeater/tst_qquickrepeater.cpp @@ -79,6 +79,7 @@ private slots: void initParent(); void dynamicModelCrash(); void visualItemModelCrash(); + void invalidContextCrash(); }; class TestObject : public QObject @@ -744,6 +745,48 @@ void tst_QQuickRepeater::visualItemModelCrash() delete window; } +class BadModel : public QAbstractListModel +{ +public: + ~BadModel() + { + beginResetModel(); + endResetModel(); + } + + QVariant data(const QModelIndex &, int) const { return QVariant(); } + int rowCount(const QModelIndex &) const { return 0; } +}; + + +void tst_QQuickRepeater::invalidContextCrash() +{ + QQmlEngine engine; + QQmlComponent component(&engine, testFileUrl("invalidContextCrash.qml")); + + BadModel* model = new BadModel; + engine.rootContext()->setContextProperty("badModel", model); + + QScopedPointer<QObject> root(component.create()); + QCOMPARE(root->children().count(), 1); + QObject *repeater = root->children().first(); + + // Make sure the model comes first in the child list, so it will be + // deleted first and then the repeater. During deletion the QML context + // has been deleted already and is invalid. + model->setParent(root.data()); + repeater->setParent(0); + repeater->setParent(root.data()); + + QCOMPARE(root->children().count(), 2); + QVERIFY(root->children().at(0) == model); + QVERIFY(root->children().at(1) == repeater); + + // Delete the root object, which will invalidate/delete the QML context + // and then delete the child QObjects, which may try to access the context. + root.reset(0); +} + QTEST_MAIN(tst_QQuickRepeater) #include "tst_qquickrepeater.moc" diff --git a/tests/auto/quick/qquickspritesequence/tst_qquickspritesequence.cpp b/tests/auto/quick/qquickspritesequence/tst_qquickspritesequence.cpp index 79b80c5cfe..2676abb9eb 100644 --- a/tests/auto/quick/qquickspritesequence/tst_qquickspritesequence.cpp +++ b/tests/auto/quick/qquickspritesequence/tst_qquickspritesequence.cpp @@ -117,6 +117,9 @@ void tst_qquickspritesequence::test_framerateAdvance() void tst_qquickspritesequence::test_jumpToCrash() { +#if defined(QT_OPENGL_ES_2_ANGLE) && _MSC_VER==1600 + QSKIP("QTBUG-40658"); +#endif QQuickView *window = new QQuickView(0); window->setSource(testFileUrl("crashonstart.qml")); diff --git a/tests/auto/quick/qquicktext/tst_qquicktext.cpp b/tests/auto/quick/qquicktext/tst_qquicktext.cpp index 0a7c8c9f92..7897f6d36a 100644 --- a/tests/auto/quick/qquicktext/tst_qquicktext.cpp +++ b/tests/auto/quick/qquicktext/tst_qquicktext.cpp @@ -876,6 +876,9 @@ static inline QByteArray msgNotLessThan(int n1, int n2) void tst_qquicktext::hAlignImplicitWidth() { +#if defined(QT_OPENGL_ES_2_ANGLE) && _MSC_VER==1600 + QSKIP("QTBUG-40658"); +#endif QQuickView view(testFileUrl("hAlignImplicitWidth.qml")); view.setFlags(view.flags() | Qt::WindowStaysOnTopHint); // Prevent being obscured by other windows. view.show(); @@ -2034,7 +2037,8 @@ void tst_qquicktext::embeddedImages() QFETCH(QUrl, qmlfile); QFETCH(QString, error); - TestHTTPServer server(SERVER_PORT); + TestHTTPServer server; + QVERIFY2(server.listen(SERVER_PORT), qPrintable(server.errorString())); server.serveDirectory(testFile("http")); if (!error.isEmpty()) @@ -2772,7 +2776,8 @@ void tst_qquicktext::imgTagsBaseUrl() QFETCH(QUrl, contextUrl); QFETCH(qreal, imgHeight); - TestHTTPServer server(SERVER_PORT); + TestHTTPServer server; + QVERIFY2(server.listen(SERVER_PORT), qPrintable(server.errorString())); server.serveDirectory(testFile("")); QByteArray baseUrlFragment; @@ -2811,7 +2816,7 @@ void tst_qquicktext::imgTagsAlign() QFETCH(QString, align); QString componentStr = "import QtQuick 2.0\nText { text: \"This is a test <img src=\\\"" + src + "\\\" align=\\\"" + align + "\\\"> of image.\" }"; QQmlComponent textComponent(&engine); - textComponent.setData(componentStr.toLatin1(), QUrl::fromLocalFile("")); + textComponent.setData(componentStr.toLatin1(), QUrl::fromLocalFile(".")); QQuickText *textObject = qobject_cast<QQuickText*>(textComponent.create()); QVERIFY(textObject != 0); @@ -2836,7 +2841,7 @@ void tst_qquicktext::imgTagsMultipleImages() QString componentStr = "import QtQuick 2.0\nText { text: \"This is a starfish<img src=\\\"data/images/starfish_2.png\\\" width=\\\"60\\\" height=\\\"60\\\" > and another one<img src=\\\"data/images/heart200.png\\\" width=\\\"85\\\" height=\\\"85\\\">.\" }"; QQmlComponent textComponent(&engine); - textComponent.setData(componentStr.toLatin1(), QUrl::fromLocalFile("")); + textComponent.setData(componentStr.toLatin1(), QUrl::fromLocalFile(".")); QQuickText *textObject = qobject_cast<QQuickText*>(textComponent.create()); QVERIFY(textObject != 0); @@ -2897,8 +2902,8 @@ void tst_qquicktext::imgTagsError() QString componentStr = "import QtQuick 2.0\nText { text: \"This is a starfish<img src=\\\"data/images/starfish_2.pn\\\" width=\\\"60\\\" height=\\\"60\\\">.\" }"; QQmlComponent textComponent(&engine); - QTest::ignoreMessage(QtWarningMsg, "file::2:1: QML Text: Cannot open: file:data/images/starfish_2.pn"); - textComponent.setData(componentStr.toLatin1(), QUrl::fromLocalFile("")); + QTest::ignoreMessage(QtWarningMsg, "<Unknown File>:2:1: QML Text: Cannot open: file:data/images/starfish_2.pn"); + textComponent.setData(componentStr.toLatin1(), QUrl("file:")); QQuickText *textObject = qobject_cast<QQuickText*>(textComponent.create()); QVERIFY(textObject != 0); diff --git a/tests/auto/quick/qquicktextedit/tst_qquicktextedit.cpp b/tests/auto/quick/qquicktextedit/tst_qquicktextedit.cpp index 741a724632..00aa1dbe10 100644 --- a/tests/auto/quick/qquicktextedit/tst_qquicktextedit.cpp +++ b/tests/auto/quick/qquicktextedit/tst_qquicktextedit.cpp @@ -2603,7 +2603,8 @@ void tst_qquicktextedit::cursorDelegate() void tst_qquicktextedit::remoteCursorDelegate() { - TestHTTPServer server(SERVER_PORT); + TestHTTPServer server; + QVERIFY2(server.listen(SERVER_PORT), qPrintable(server.errorString())); server.serveDirectory(dataDirectory(), TestHTTPServer::Delay); QQuickView view; @@ -2740,7 +2741,8 @@ void tst_qquicktextedit::delegateLoading() QFETCH(QString, qmlfile); QFETCH(QString, error); - TestHTTPServer server(SERVER_PORT); + TestHTTPServer server; + QVERIFY2(server.listen(SERVER_PORT), qPrintable(server.errorString())); server.serveDirectory(testFile("httpfail"), TestHTTPServer::Disconnect); server.serveDirectory(testFile("httpslow"), TestHTTPServer::Delay); server.serveDirectory(testFile("http")); @@ -5214,7 +5216,8 @@ void tst_qquicktextedit::embeddedImages() QFETCH(QUrl, qmlfile); QFETCH(QString, error); - TestHTTPServer server(SERVER_PORT); + TestHTTPServer server; + QVERIFY2(server.listen(SERVER_PORT), qPrintable(server.errorString())); server.serveDirectory(testFile("http")); if (!error.isEmpty()) diff --git a/tests/auto/quick/qquicktextinput/tst_qquicktextinput.cpp b/tests/auto/quick/qquicktextinput/tst_qquicktextinput.cpp index e125c33a56..c50923b32f 100644 --- a/tests/auto/quick/qquicktextinput/tst_qquicktextinput.cpp +++ b/tests/auto/quick/qquicktextinput/tst_qquicktextinput.cpp @@ -232,6 +232,8 @@ private slots: void baselineOffset_data(); void baselineOffset(); + void ensureVisible(); + private: void simulateKey(QWindow *, int key); @@ -2232,25 +2234,34 @@ void tst_qquicktextinput::inputMethods() QTRY_COMPARE(qGuiApp->focusObject(), input); QGuiApplication::sendEvent(input, &event); QCOMPARE(input->text(), QString("My Hello world!")); + QCOMPARE(input->displayText(), QString("My Hello world!")); input->setCursorPosition(2); event.setCommitString("Your", -2, 2); QGuiApplication::sendEvent(input, &event); QCOMPARE(input->text(), QString("Your Hello world!")); + QCOMPARE(input->displayText(), QString("Your Hello world!")); QCOMPARE(input->cursorPosition(), 4); input->setCursorPosition(7); event.setCommitString("Goodbye", -2, 5); QGuiApplication::sendEvent(input, &event); QCOMPARE(input->text(), QString("Your Goodbye world!")); + QCOMPARE(input->displayText(), QString("Your Goodbye world!")); QCOMPARE(input->cursorPosition(), 12); input->setCursorPosition(8); event.setCommitString("Our", -8, 4); QGuiApplication::sendEvent(input, &event); QCOMPARE(input->text(), QString("Our Goodbye world!")); + QCOMPARE(input->displayText(), QString("Our Goodbye world!")); QCOMPARE(input->cursorPosition(), 7); + QInputMethodEvent preeditEvent("PREEDIT", QList<QInputMethodEvent::Attribute>()); + QGuiApplication::sendEvent(input, &preeditEvent); + QCOMPARE(input->text(), QString("Our Goodbye world!")); + QCOMPARE(input->displayText(), QString("Our GooPREEDITdbye world!")); + // input should reset selection even if replacement parameters are out of bounds input->setText("text"); input->setCursorPosition(0); @@ -2258,6 +2269,8 @@ void tst_qquicktextinput::inputMethods() event.setCommitString("replacement", -input->text().length(), input->text().length()); QGuiApplication::sendEvent(input, &event); QCOMPARE(input->selectionStart(), input->selectionEnd()); + QCOMPARE(input->text(), QString("replacement")); + QCOMPARE(input->displayText(), QString("replacement")); QInputMethodQueryEvent enabledQueryEvent(Qt::ImEnabled); QGuiApplication::sendEvent(input, &enabledQueryEvent); @@ -2490,7 +2503,7 @@ void tst_qquicktextinput::copyAndPaste() QCOMPARE(textInput->selectedText(), QString("Hello world!")); QCOMPARE(textInput->selectedText().length(), 12); textInput->setCursorPosition(0); - QVERIFY(textInput->canPaste()); + QTRY_VERIFY(textInput->canPaste()); textInput->paste(); QCOMPARE(textInput->text(), QString("Hello world!Hello world!")); QCOMPARE(textInput->text().length(), 24); @@ -2544,7 +2557,7 @@ void tst_qquicktextinput::copyAndPaste() QClipboard *clipboard = QGuiApplication::clipboard(); QVERIFY(clipboard); clipboard->clear(); - QVERIFY(!textInput->canPaste()); + QTRY_VERIFY(!textInput->canPaste()); // test that copy functionality is disabled // when echo mode is set to hide text/password mode @@ -2612,7 +2625,7 @@ void tst_qquicktextinput::copyAndPasteKeySequence() QClipboard *clipboard = QGuiApplication::clipboard(); QVERIFY(clipboard); clipboard->clear(); - QVERIFY(!textInput->canPaste()); + QTRY_VERIFY(!textInput->canPaste()); // test that copy functionality is disabled // when echo mode is set to hide text/password mode @@ -2853,7 +2866,8 @@ void tst_qquicktextinput::cursorDelegate() void tst_qquicktextinput::remoteCursorDelegate() { - TestHTTPServer server(SERVER_PORT); + TestHTTPServer server; + QVERIFY2(server.listen(SERVER_PORT), qPrintable(server.errorString())); server.serveDirectory(dataDirectory(), TestHTTPServer::Delay); QQuickView view; @@ -6269,13 +6283,11 @@ void tst_qquicktextinput::hasAcceptableInputMask() textInput->setText(invalid); QVERIFY(textInput->hasAcceptableInput()); - // at the moment we don't strip the blank character if it is valid input, this makes the test between x vs X useless - QEXPECT_FAIL( "Any optional and required", "To eat blanks or not? Known issue. Task 43172", Abort); - // test requiredMask textInput->setInputMask(requiredMask); textInput->setText(invalid); - QVERIFY(!textInput->hasAcceptableInput()); + // invalid text gets the input mask applied when setting, text becomes acceptable. + QVERIFY(textInput->hasAcceptableInput()); textInput->setText(valid); QVERIFY(textInput->hasAcceptableInput()); @@ -6463,6 +6475,50 @@ void tst_qquicktextinput::baselineOffset() } } +void tst_qquicktextinput::ensureVisible() +{ + QQmlComponent component(&engine); + component.setData("import QtQuick 2.0\n TextInput {}", QUrl()); + QScopedPointer<QObject> object(component.create()); + QQuickTextInput *input = qobject_cast<QQuickTextInput *>(object.data()); + QVERIFY(input); + + input->setWidth(QFontMetrics(input->font()).averageCharWidth() * 3); + input->setText("Hello World"); + + QTextLayout layout; + layout.setText(input->text()); + layout.setFont(input->font()); + + if (!qmlDisableDistanceField()) { + QTextOption option; + option.setUseDesignMetrics(true); + layout.setTextOption(option); + } + layout.beginLayout(); + QTextLine line = layout.createLine(); + layout.endLayout(); + + input->ensureVisible(0); + + QCOMPARE(input->boundingRect().x(), qreal(0)); + QCOMPARE(input->boundingRect().y(), qreal(0)); + QCOMPARE(input->boundingRect().width(), line.naturalTextWidth() + input->cursorRectangle().width()); + QCOMPARE(input->boundingRect().height(), line.height()); + + QSignalSpy cursorSpy(input, SIGNAL(cursorRectangleChanged())); + QVERIFY(cursorSpy.isValid()); + + input->ensureVisible(input->length()); + + QCOMPARE(cursorSpy.count(), 1); + + QCOMPARE(input->boundingRect().x(), input->width() - line.naturalTextWidth()); + QCOMPARE(input->boundingRect().y(), qreal(0)); + QCOMPARE(input->boundingRect().width(), line.naturalTextWidth() + input->cursorRectangle().width()); + QCOMPARE(input->boundingRect().height(), line.height()); +} + QTEST_MAIN(tst_qquicktextinput) #include "tst_qquicktextinput.moc" diff --git a/tests/auto/quick/qquicktextmetrics/qquicktextmetrics.pro b/tests/auto/quick/qquicktextmetrics/qquicktextmetrics.pro new file mode 100644 index 0000000000..6ef68db8e2 --- /dev/null +++ b/tests/auto/quick/qquicktextmetrics/qquicktextmetrics.pro @@ -0,0 +1,10 @@ +CONFIG += testcase +TARGET = tst_qquicktextmetrics +osx:CONFIG -= app_bundle + +SOURCES += tst_qquicktextmetrics.cpp + +CONFIG += parallel_test + +QT += core gui qml quick-private testlib +DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0 diff --git a/tests/auto/quick/qquicktextmetrics/tst_qquicktextmetrics.cpp b/tests/auto/quick/qquicktextmetrics/tst_qquicktextmetrics.cpp new file mode 100644 index 0000000000..733b3d06b3 --- /dev/null +++ b/tests/auto/quick/qquicktextmetrics/tst_qquicktextmetrics.cpp @@ -0,0 +1,161 @@ +/**************************************************************************** +** +** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the QtQml module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Digia gives you certain additional +** rights. These rights are described in the Digia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include <QFont> +#include <QString> +#include <QtTest> +#include <QCoreApplication> +#include <QQmlComponent> +#include <QQmlEngine> +#include <QQuickItem> + +#include <QtQuick/private/qquicktextmetrics_p.h> + +#include <QFontMetricsF> + +class tst_QQuickTextMetrics : public QObject +{ + Q_OBJECT + +public: + tst_QQuickTextMetrics(); + +private Q_SLOTS: + void font(); + void functionsWithArguments_data(); + void functionsWithArguments(); +}; + +tst_QQuickTextMetrics::tst_QQuickTextMetrics() +{ +} + +void tst_QQuickTextMetrics::font() +{ + QQuickTextMetrics metrics; + + QSignalSpy fontSpy(&metrics, SIGNAL(fontChanged())); + QSignalSpy metricsSpy(&metrics, SIGNAL(metricsChanged())); + QFont font; + font.setPointSize(font.pointSize() + 1); + metrics.setFont(font); + QCOMPARE(fontSpy.count(), 1); + QCOMPARE(metricsSpy.count(), 1); +} + +Q_DECLARE_METATYPE(Qt::TextElideMode) + +void tst_QQuickTextMetrics::functionsWithArguments_data() +{ + QTest::addColumn<QString>("text"); + QTest::addColumn<Qt::TextElideMode>("mode"); + QTest::addColumn<qreal>("width"); + + QStringList strings; + strings << QString() + << QString::fromLatin1("") + << QString::fromLatin1("0") + << QString::fromLatin1("@@@@@@@") + << QString::fromLatin1("Hello"); + + QVector<Qt::TextElideMode> elideModes; + elideModes << Qt::ElideLeft << Qt::ElideMiddle << Qt::ElideRight << Qt::ElideNone; + + for (int stringIndex = 0; stringIndex < strings.size(); ++stringIndex) { + const QString string = strings.at(stringIndex); + + for (int elideModeIndex = 0; elideModeIndex < elideModes.size(); ++elideModeIndex) { + Qt::TextElideMode elideMode = static_cast<Qt::TextElideMode>(elideModes.at(elideModeIndex)); + + for (qreal width = 0; width < 100; width += 20) { + const QString tag = QString::fromLatin1("string=%1, mode=%2, width=%3").arg(string).arg(elideMode).arg(width); + QTest::newRow(qPrintable(tag)) << QString() << elideMode << width; + } + } + } +} + +void tst_QQuickTextMetrics::functionsWithArguments() +{ + QFETCH(QString, text); + QFETCH(Qt::TextElideMode, mode); + QFETCH(qreal, width); + + QQuickTextMetrics metrics; + // Ensures that the values actually change. + metrics.setText(text + "extra"); + metrics.setElideWidth(width + 1); + switch (mode) { + case Qt::ElideNone: metrics.setElide(Qt::ElideMiddle); break; + case Qt::ElideLeft: metrics.setElide(Qt::ElideRight); break; + case Qt::ElideMiddle: metrics.setElide(Qt::ElideNone); break; + case Qt::ElideRight: metrics.setElide(Qt::ElideLeft); break; + } + + QSignalSpy textSpy(&metrics, SIGNAL(textChanged())); + QSignalSpy metricsSpy(&metrics, SIGNAL(metricsChanged())); + metrics.setText(text); + QCOMPARE(textSpy.count(), 1); + QCOMPARE(metricsSpy.count(), 1); + + QSignalSpy elideSpy(&metrics, SIGNAL(elideChanged())); + metrics.setElide(mode); + QCOMPARE(elideSpy.count(), 1); + QCOMPARE(metricsSpy.count(), 2); + + QSignalSpy elideWidthSpy(&metrics, SIGNAL(elideWidthChanged())); + metrics.setElideWidth(width); + QCOMPARE(elideWidthSpy.count(), 1); + QCOMPARE(metricsSpy.count(), 3); + + QFontMetricsF expected = QFontMetricsF(QFont()); + + QCOMPARE(metrics.elidedText(), expected.elidedText(text, mode, width, 0)); + QCOMPARE(metrics.advanceWidth(), expected.width(text)); + QCOMPARE(metrics.boundingRect(), expected.boundingRect(text)); + QCOMPARE(metrics.width(), expected.boundingRect(text).width()); + QCOMPARE(metrics.height(), expected.boundingRect(text).height()); + QCOMPARE(metrics.tightBoundingRect(), expected.tightBoundingRect(text)); +} + +QTEST_MAIN(tst_QQuickTextMetrics) + +#include "tst_qquicktextmetrics.moc" diff --git a/tests/auto/quick/qquickwindow/data/windowattached.qml b/tests/auto/quick/qquickwindow/data/windowattached.qml new file mode 100644 index 0000000000..e000d5c6fd --- /dev/null +++ b/tests/auto/quick/qquickwindow/data/windowattached.qml @@ -0,0 +1,25 @@ +import QtQuick 2.4 +import QtQuick.Window 2.2 + +Rectangle { + id: root + width: 100 + height: 100 + property bool windowActive: root.Window.active + Text { + objectName: "rectangleWindowText" + anchors.centerIn: parent + text: (windowActive ? "active" : "inactive") + "\nvisibility: " + root.Window.visibility + } + + property Window extraWindow: Window { + objectName: "extraWindow" + title: "extra window" + visible: true + Text { + objectName: "extraWindowText" + anchors.centerIn: parent + text: (extraWindow.active ? "active" : "inactive") + "\nvisibility: " + Window.visibility + } + } +} diff --git a/tests/auto/quick/qquickwindow/qquickwindow.pro b/tests/auto/quick/qquickwindow/qquickwindow.pro index 6bce209df9..e95b7dbb10 100644 --- a/tests/auto/quick/qquickwindow/qquickwindow.pro +++ b/tests/auto/quick/qquickwindow/qquickwindow.pro @@ -3,6 +3,7 @@ TARGET = tst_qquickwindow SOURCES += tst_qquickwindow.cpp include (../../shared/util.pri) +include(../shared/util.pri) macx:CONFIG -= app_bundle diff --git a/tests/auto/quick/qquickwindow/tst_qquickwindow.cpp b/tests/auto/quick/qquickwindow/tst_qquickwindow.cpp index b8f9102775..52dd3f1a8d 100644 --- a/tests/auto/quick/qquickwindow/tst_qquickwindow.cpp +++ b/tests/auto/quick/qquickwindow/tst_qquickwindow.cpp @@ -43,6 +43,7 @@ #include <QDebug> #include <QTouchEvent> #include <QtQuick/QQuickItem> +#include <QtQuick/QQuickView> #include <QtQuick/QQuickWindow> #include <QtQml/QQmlEngine> #include <QtQml/QQmlComponent> @@ -50,10 +51,12 @@ #include <QtQuick/private/qquickloader_p.h> #include "../../shared/util.h" #include "../shared/visualtestutil.h" +#include "../shared/viewtestutil.h" #include <QSignalSpy> #include <qpa/qwindowsysteminterface.h> #include <private/qquickwindow_p.h> #include <private/qguiapplication_p.h> +#include <QRunnable> struct TouchEventData { QEvent::Type type; @@ -328,6 +331,7 @@ private slots: void animationsWhileHidden(); void focusObject(); + void focusReason(); void ignoreUnhandledMouseEvents(); @@ -362,6 +366,12 @@ private slots: void contentItemSize(); + void defaultSurfaceFormat(); + + void attachedProperty(); + + void testRenderJob(); + private: QTouchDevice *touchDevice; QTouchDevice *touchDeviceWithVelocity; @@ -395,7 +405,7 @@ void tst_qquickwindow::aboutToStopSignal() window.hide(); - QVERIFY(spy.count() > 0); + QTRY_VERIFY(spy.count() > 0); } //If the item calls update inside updatePaintNode, it should schedule another sync pass @@ -522,7 +532,7 @@ void tst_qquickwindow::touchEvent_basic() // press multiple points QTest::touchEvent(window, touchDevice).press(0, topItem->mapToScene(pos).toPoint(),window) .press(1, bottomItem->mapToScene(pos).toPoint(), window); - QTest::qWait(50); + QQuickTouchUtils::flush(window); QCOMPARE(topItem->lastEvent.touchPoints.count(), 1); QVERIFY(middleItem->lastEvent.touchPoints.isEmpty()); QCOMPARE(bottomItem->lastEvent.touchPoints.count(), 1); @@ -533,9 +543,9 @@ void tst_qquickwindow::touchEvent_basic() // touch point on top item moves to bottom item, but top item should still receive the event QTest::touchEvent(window, touchDevice).press(0, topItem->mapToScene(pos).toPoint(), window); - QTest::qWait(50); + QQuickTouchUtils::flush(window); QTest::touchEvent(window, touchDevice).move(0, bottomItem->mapToScene(pos).toPoint(), window); - QTest::qWait(50); + QQuickTouchUtils::flush(window); QCOMPARE(topItem->lastEvent.touchPoints.count(), 1); COMPARE_TOUCH_DATA(topItem->lastEvent, makeTouchData(QEvent::TouchUpdate, window, Qt::TouchPointMoved, makeTouchPoint(topItem, topItem->mapFromItem(bottomItem, pos), pos))); @@ -543,9 +553,9 @@ void tst_qquickwindow::touchEvent_basic() // touch point on bottom item moves to top item, but bottom item should still receive the event QTest::touchEvent(window, touchDevice).press(0, bottomItem->mapToScene(pos).toPoint(), window); - QTest::qWait(50); + QQuickTouchUtils::flush(window); QTest::touchEvent(window, touchDevice).move(0, topItem->mapToScene(pos).toPoint(), window); - QTest::qWait(50); + QQuickTouchUtils::flush(window); QCOMPARE(bottomItem->lastEvent.touchPoints.count(), 1); COMPARE_TOUCH_DATA(bottomItem->lastEvent, makeTouchData(QEvent::TouchUpdate, window, Qt::TouchPointMoved, makeTouchPoint(bottomItem, bottomItem->mapFromItem(topItem, pos), pos))); @@ -553,10 +563,10 @@ void tst_qquickwindow::touchEvent_basic() // a single stationary press on an item shouldn't cause an event QTest::touchEvent(window, touchDevice).press(0, topItem->mapToScene(pos).toPoint(), window); - QTest::qWait(50); + QQuickTouchUtils::flush(window); QTest::touchEvent(window, touchDevice).stationary(0) .press(1, bottomItem->mapToScene(pos).toPoint(), window); - QTest::qWait(50); + QQuickTouchUtils::flush(window); QCOMPARE(topItem->lastEvent.touchPoints.count(), 1); // received press only, not stationary QVERIFY(middleItem->lastEvent.touchPoints.isEmpty()); QCOMPARE(bottomItem->lastEvent.touchPoints.count(), 1); @@ -568,12 +578,13 @@ void tst_qquickwindow::touchEvent_basic() // Otherwise you will get an assertion failure: // ASSERT: "itemForTouchPointId.isEmpty()" in file items/qquickwindow.cpp QTest::touchEvent(window, touchDevice).release(0, pos.toPoint(), window).release(1, pos.toPoint(), window); + QQuickTouchUtils::flush(window); // move touch point from top item to bottom, and release QTest::touchEvent(window, touchDevice).press(0, topItem->mapToScene(pos).toPoint(),window); - QTest::qWait(50); + QQuickTouchUtils::flush(window); QTest::touchEvent(window, touchDevice).release(0, bottomItem->mapToScene(pos).toPoint(),window); - QTest::qWait(50); + QQuickTouchUtils::flush(window); QCOMPARE(topItem->lastEvent.touchPoints.count(), 1); COMPARE_TOUCH_DATA(topItem->lastEvent, makeTouchData(QEvent::TouchEnd, window, Qt::TouchPointReleased, makeTouchPoint(topItem, topItem->mapFromItem(bottomItem, pos), pos))); @@ -582,12 +593,12 @@ void tst_qquickwindow::touchEvent_basic() // release while another point is pressed QTest::touchEvent(window, touchDevice).press(0, topItem->mapToScene(pos).toPoint(),window) .press(1, bottomItem->mapToScene(pos).toPoint(), window); - QTest::qWait(50); + QQuickTouchUtils::flush(window); QTest::touchEvent(window, touchDevice).move(0, bottomItem->mapToScene(pos).toPoint(), window); - QTest::qWait(50); + QQuickTouchUtils::flush(window); QTest::touchEvent(window, touchDevice).release(0, bottomItem->mapToScene(pos).toPoint(), window) .stationary(1); - QTest::qWait(50); + QQuickTouchUtils::flush(window); QCOMPARE(topItem->lastEvent.touchPoints.count(), 1); QVERIFY(middleItem->lastEvent.touchPoints.isEmpty()); QCOMPARE(bottomItem->lastEvent.touchPoints.count(), 1); @@ -835,12 +846,15 @@ void tst_qquickwindow::touchEvent_velocity() tp.area = QRectF(pos, QSizeF(4, 4)); points << tp; QWindowSystemInterface::handleTouchEvent(window, touchDeviceWithVelocity, points); + QGuiApplication::processEvents(); + QQuickTouchUtils::flush(window); points[0].state = Qt::TouchPointMoved; points[0].area.adjust(5, 5, 5, 5); QVector2D velocity(1.5, 2.5); points[0].velocity = velocity; QWindowSystemInterface::handleTouchEvent(window, touchDeviceWithVelocity, points); - QCoreApplication::processEvents(); + QGuiApplication::processEvents(); + QQuickTouchUtils::flush(window); QCOMPARE(item->touchEventCount, 2); QCOMPARE(item->lastEvent.touchPoints.count(), 1); QCOMPARE(item->lastVelocity, velocity); @@ -852,7 +866,8 @@ void tst_qquickwindow::touchEvent_velocity() QVector2D transformedVelocity = transformMatrix.mapVector(velocity).toVector2D(); points[0].area.adjust(5, 5, 5, 5); QWindowSystemInterface::handleTouchEvent(window, touchDeviceWithVelocity, points); - QCoreApplication::processEvents(); + QGuiApplication::processEvents(); + QQuickTouchUtils::flush(window); QCOMPARE(item->lastVelocity, transformedVelocity); QPoint itemLocalPos = item->mapFromScene(window->mapFromGlobal(points[0].area.center().toPoint())).toPoint(); QPoint itemLocalPosFromEvent = item->lastEvent.touchPoints[0].pos().toPoint(); @@ -860,7 +875,8 @@ void tst_qquickwindow::touchEvent_velocity() points[0].state = Qt::TouchPointReleased; QWindowSystemInterface::handleTouchEvent(window, touchDeviceWithVelocity, points); - QCoreApplication::processEvents(); + QGuiApplication::processEvents(); + QQuickTouchUtils::flush(window); delete item; } @@ -892,14 +908,19 @@ void tst_qquickwindow::mouseFromTouch_basic() tp.area = QRectF(pos, QSizeF(4, 4)); points << tp; QWindowSystemInterface::handleTouchEvent(window, touchDeviceWithVelocity, points); + QGuiApplication::processEvents(); + QQuickTouchUtils::flush(window); points[0].state = Qt::TouchPointMoved; points[0].area.adjust(5, 5, 5, 5); QVector2D velocity(1.5, 2.5); points[0].velocity = velocity; QWindowSystemInterface::handleTouchEvent(window, touchDeviceWithVelocity, points); + QGuiApplication::processEvents(); + QQuickTouchUtils::flush(window); points[0].state = Qt::TouchPointReleased; QWindowSystemInterface::handleTouchEvent(window, touchDeviceWithVelocity, points); - QCoreApplication::processEvents(); + QGuiApplication::processEvents(); + QQuickTouchUtils::flush(window); // The item should have received a mouse press, move, and release. QCOMPARE(item->mousePressNum, 1); @@ -918,16 +939,20 @@ void tst_qquickwindow::mouseFromTouch_basic() points[0].velocity = velocity; points[0].area = QRectF(pos, QSizeF(4, 4)); QWindowSystemInterface::handleTouchEvent(window, touchDeviceWithVelocity, points); + QGuiApplication::processEvents(); + QQuickTouchUtils::flush(window); points[0].state = Qt::TouchPointMoved; points[0].area.adjust(5, 5, 5, 5); QWindowSystemInterface::handleTouchEvent(window, touchDeviceWithVelocity, points); - QCoreApplication::processEvents(); + QGuiApplication::processEvents(); + QQuickTouchUtils::flush(window); QCOMPARE(item->lastMousePos.toPoint(), item->mapFromScene(window->mapFromGlobal(points[0].area.center().toPoint())).toPoint()); QCOMPARE(item->lastVelocityFromMouseMove, transformedVelocity); points[0].state = Qt::TouchPointReleased; QWindowSystemInterface::handleTouchEvent(window, touchDeviceWithVelocity, points); QCoreApplication::processEvents(); + QQuickTouchUtils::flush(window); delete item; } @@ -1275,6 +1300,33 @@ void tst_qquickwindow::focusObject() QCOMPARE(focusObjectSpy.count(), 3); } +void tst_qquickwindow::focusReason() +{ + QQuickWindow *window = new QQuickWindow; + QScopedPointer<QQuickWindow> cleanup(window); + window->resize(200, 200); + window->show(); + QVERIFY(QTest::qWaitForWindowExposed(window)); + + QQuickItem *firstItem = new QQuickItem; + firstItem->setSize(QSizeF(100, 100)); + firstItem->setParentItem(window->contentItem()); + + QQuickItem *secondItem = new QQuickItem; + secondItem->setSize(QSizeF(100, 100)); + secondItem->setParentItem(window->contentItem()); + + firstItem->forceActiveFocus(Qt::OtherFocusReason); + QCOMPARE(QQuickWindowPrivate::get(window)->lastFocusReason, Qt::OtherFocusReason); + + secondItem->forceActiveFocus(Qt::TabFocusReason); + QCOMPARE(QQuickWindowPrivate::get(window)->lastFocusReason, Qt::TabFocusReason); + + firstItem->forceActiveFocus(Qt::BacktabFocusReason); + QCOMPARE(QQuickWindowPrivate::get(window)->lastFocusReason, Qt::BacktabFocusReason); + +} + void tst_qquickwindow::ignoreUnhandledMouseEvents() { QQuickWindow *window = new QQuickWindow; @@ -1718,14 +1770,14 @@ void tst_qquickwindow::unloadSubWindow() QVERIFY(window); window->show(); QTest::qWaitForWindowExposed(window); - QQuickWindow *transient = Q_NULLPTR; + QPointer<QQuickWindow> transient; QTRY_VERIFY(transient = window->property("transientWindow").value<QQuickWindow*>()); QTest::qWaitForWindowExposed(transient); // Unload the inner window (in nested Loaders) and make sure it doesn't crash QQuickLoader *loader = window->property("loader1").value<QQuickLoader*>(); loader->setActive(false); - QTRY_VERIFY(!transient->isVisible()); + QTRY_VERIFY(transient.isNull() || !transient->isVisible()); } // QTBUG-32004 @@ -1851,6 +1903,121 @@ void tst_qquickwindow::contentItemSize() QCOMPARE(QSizeF(rect->width(), rect->height()), size); } +void tst_qquickwindow::defaultSurfaceFormat() +{ + // It is quite difficult to verify anything for real since the resulting format after + // surface/context creation can be anything, depending on the platform and drivers, + // and many options and settings may fail in various configurations, but test at + // least using some harmless settings to check that the global, static format is + // taken into account in the requested format. + + QSurfaceFormat savedDefaultFormat = QSurfaceFormat::defaultFormat(); + + // Verify that depth and stencil are set, as they should be, unless they are disabled + // via environment variables. + + QSurfaceFormat format = savedDefaultFormat; + format.setSwapInterval(0); + format.setRedBufferSize(8); + format.setGreenBufferSize(8); + format.setBlueBufferSize(8); + format.setProfile(QSurfaceFormat::CompatibilityProfile); + format.setOption(QSurfaceFormat::DebugContext); + // Will not set depth and stencil. That should be added automatically, + // unless the are disabled (but they aren't). + QSurfaceFormat::setDefaultFormat(format); + + QQuickWindow window; + window.show(); + QVERIFY(QTest::qWaitForWindowExposed(&window)); + + const QSurfaceFormat reqFmt = window.requestedFormat(); + QCOMPARE(format.swapInterval(), reqFmt.swapInterval()); + QCOMPARE(format.redBufferSize(), reqFmt.redBufferSize()); + QCOMPARE(format.greenBufferSize(), reqFmt.greenBufferSize()); + QCOMPARE(format.blueBufferSize(), reqFmt.blueBufferSize()); + QCOMPARE(format.profile(), reqFmt.profile()); + QCOMPARE(int(format.options()), int(reqFmt.options())); + + // Depth and stencil should be >= what has been requested. For real. But use + // the context since the window's surface format is only partially updated + // on most platforms. + QVERIFY(window.openglContext()->format().depthBufferSize() >= 16); + QVERIFY(window.openglContext()->format().stencilBufferSize() >= 8); + + QSurfaceFormat::setDefaultFormat(savedDefaultFormat); +} + +void tst_qquickwindow::attachedProperty() +{ + QQuickView view(testFileUrl("windowattached.qml")); + view.show(); + view.requestActivate(); + QVERIFY(QTest::qWaitForWindowActive(&view)); + QVERIFY(view.rootObject()->property("windowActive").toBool()); + + QQuickWindow *innerWindow = view.rootObject()->findChild<QQuickWindow*>("extraWindow"); + QVERIFY(innerWindow); + innerWindow->requestActivate(); + QVERIFY(QTest::qWaitForWindowActive(innerWindow)); + + QQuickText *text = view.rootObject()->findChild<QQuickText*>("extraWindowText"); + QVERIFY(text); + QCOMPARE(text->text(), QLatin1String("active\nvisibility: 2")); +} + +class RenderJob : public QRunnable +{ +public: + RenderJob(QQuickWindow::RenderStage s, QList<QQuickWindow::RenderStage> *l) : stage(s), list(l) { } + ~RenderJob() { ++deleted; } + QQuickWindow::RenderStage stage; + QList<QQuickWindow::RenderStage> *list; + void run() { + list->append(stage); + } + static int deleted; +}; + +int RenderJob::deleted = 0; + +void tst_qquickwindow::testRenderJob() +{ + QList<QQuickWindow::RenderStage> completedJobs; + + QQuickWindow window; + + QQuickWindow::RenderStage stages[] = { + QQuickWindow::BeforeSynchronizingStage, + QQuickWindow::AfterSynchronizingStage, + QQuickWindow::BeforeRenderingStage, + QQuickWindow::AfterRenderingStage, + QQuickWindow::AfterSwapStage + }; + // Schedule the jobs + for (int i=0; i<5; ++i) + window.scheduleRenderJob(new RenderJob(stages[i], &completedJobs), stages[i]); + window.show(); + + QTRY_COMPARE(completedJobs.size(), 5); + + for (int i=0; i<5; ++i) { + QCOMPARE(completedJobs.at(i), stages[i]); + } + + // Verify that jobs are deleted when window has not been rendered at all... + completedJobs.clear(); + RenderJob::deleted = 0; + { + QQuickWindow window2; + for (int i=0; i<5; ++i) { + window2.scheduleRenderJob(new RenderJob(stages[i], &completedJobs), stages[i]); + } + } + QCOMPARE(completedJobs.size(), 0); + QCOMPARE(RenderJob::deleted, 5); +} + QTEST_MAIN(tst_qquickwindow) #include "tst_qquickwindow.moc" diff --git a/tests/auto/quick/quick.pro b/tests/auto/quick/quick.pro index 6c163d9619..0a887534bd 100644 --- a/tests/auto/quick/quick.pro +++ b/tests/auto/quick/quick.pro @@ -18,6 +18,7 @@ PRIVATETESTS += \ qquickapplication \ qquickbehaviors \ qquickfontloader \ + qquickfontmetrics \ qquickimageprovider \ qquickpath \ qquicksmoothedanimation \ @@ -55,6 +56,7 @@ QUICKTESTS = \ qquickloader \ qquickmousearea \ qquickmultipointtoucharea \ + qquickopenglinfo \ qquickpainteditem \ qquickpathview \ qquickpincharea \ diff --git a/tests/auto/quick/rendernode/data/matrix.qml b/tests/auto/quick/rendernode/data/matrix.qml new file mode 100644 index 0000000000..8b721e5075 --- /dev/null +++ b/tests/auto/quick/rendernode/data/matrix.qml @@ -0,0 +1,87 @@ +/**************************************************************************** +** +** Copyright (C) 2014 Jolla Ltd, author: <gunnar.sletta@jollamobile.com> +** Contact: http://www.qt-project.org/legal +** +** This file is part of the test suite of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Digia gives you certain additional +** rights. These rights are described in the Digia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +import QtQuick 2.0 +import RenderNode 1.0 + +Item { + width: 320 + height: 480 + + Item { x: 10; y: 10; width: 10; height: 10; + StateRecorder { x: 10; y: 10; objectName: "no-clip; no-rotation"; } + } + + Item { x: 10; y: 10; width: 10; height: 10; clip: true + StateRecorder { x: 10; y: 10; objectName: "parent-clip; no-rotation"; } + } + + Item { x: 10; y: 10; width: 10; height: 10; + StateRecorder { x: 10; y: 10; objectName: "self-clip; no-rotation"; clip: true } + } + + + Item { x: 10; y: 10; width: 10; height: 10; rotation: 90 + StateRecorder { x: 10; y: 10; objectName: "no-clip; parent-rotation"; } + } + + Item { x: 10; y: 10; width: 10; height: 10; clip: true; rotation: 90 + StateRecorder { x: 10; y: 10; objectName: "parent-clip; parent-rotation"; } + } + + Item { x: 10; y: 10; width: 10; height: 10; rotation: 90 + StateRecorder { x: 10; y: 10; objectName: "self-clip; parent-rotation"; clip: true } + } + + + Item { x: 10; y: 10; width: 10; height: 10; + StateRecorder { x: 10; y: 10; objectName: "no-clip; self-rotation"; rotation: 90 } + } + + Item { x: 10; y: 10; width: 10; height: 10; clip: true; + StateRecorder { x: 10; y: 10; objectName: "parent-clip; self-rotation"; rotation: 90} + } + + Item { x: 10; y: 10; width: 10; height: 10; + StateRecorder { x: 10; y: 10; objectName: "self-clip; self-rotation"; clip: true; rotation: 90 } + } + +} diff --git a/tests/auto/quick/rendernode/rendernode.pro b/tests/auto/quick/rendernode/rendernode.pro index b55b7b0bec..bedcefde86 100644 --- a/tests/auto/quick/rendernode/rendernode.pro +++ b/tests/auto/quick/rendernode/rendernode.pro @@ -14,4 +14,6 @@ QT += core-private gui-private qml-private quick-private testlib OTHER_FILES += \ data/RenderOrder.qml \ data/MessUpState.qml \ + data/matrix.qml + DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0 diff --git a/tests/auto/quick/rendernode/tst_rendernode.cpp b/tests/auto/quick/rendernode/tst_rendernode.cpp index 06338e09e2..2397392419 100644 --- a/tests/auto/quick/rendernode/tst_rendernode.cpp +++ b/tests/auto/quick/rendernode/tst_rendernode.cpp @@ -44,6 +44,7 @@ #include <QtQuick/qquickitem.h> #include <QtQuick/qquickview.h> #include <QtGui/qopenglcontext.h> +#include <QtGui/qopenglfunctions.h> #include <QtGui/qscreen.h> #include <private/qsgrendernode_p.h> @@ -72,6 +73,7 @@ public: private slots: void renderOrder(); void messUpState(); + void matrix(); }; class ClearNode : public QSGRenderNode @@ -85,8 +87,8 @@ public: virtual void render(const RenderState &) { // If clip has been set, scissoring will make sure the right area is cleared. - glClearColor(color.redF(), color.greenF(), color.blueF(), 1.0f); - glClear(GL_COLOR_BUFFER_BIT); + QOpenGLContext::currentContext()->functions()->glClearColor(color.redF(), color.greenF(), color.blueF(), 1.0f); + QOpenGLContext::currentContext()->functions()->glClear(GL_COLOR_BUFFER_BIT); } QColor color; @@ -128,9 +130,11 @@ private: QColor m_color; }; -class MessUpNode : public QSGRenderNode +class MessUpNode : public QSGRenderNode, protected QOpenGLFunctions { public: + MessUpNode() : initialized(false) { } + virtual StateFlags changedStates() { return StateFlags(DepthState) | StencilState | ScissorState | ColorState | BlendState @@ -139,17 +143,17 @@ public: virtual void render(const RenderState &) { + if (!initialized) { + initializeOpenGLFunctions(); + initialized = true; + } // Don't draw anything, just mess up the state glViewport(10, 10, 10, 10); glDisable(GL_SCISSOR_TEST); glDepthMask(true); glEnable(GL_DEPTH_TEST); glDepthFunc(GL_EQUAL); -#if defined(QT_OPENGL_ES) glClearDepthf(1); -#else - glClearDepth(1); -#endif glClearStencil(42); glClearColor(1.0f, 0.5f, 1.0f, 0.0f); glClear(GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT); @@ -162,6 +166,8 @@ public: glFrontFace(frontFace == GL_CW ? GL_CCW : GL_CW); glEnable(GL_CULL_FACE); } + + bool initialized; }; class MessUpItem : public QQuickItem @@ -261,6 +267,84 @@ void tst_rendernode::messUpState() QCOMPARE(fb.pixel(x2, y5), qRgb(0x00, 0x00, 0x00)); } +class StateRecordingRenderNode : public QSGRenderNode +{ +public: + StateFlags changedStates() { return StateFlags(-1); } + void render(const RenderState &) { + matrices[name] = *matrix(); + + } + + QString name; + static QHash<QString, QMatrix4x4> matrices; +}; + +QHash<QString, QMatrix4x4> StateRecordingRenderNode::matrices; + +class StateRecordingRenderNodeItem : public QQuickItem +{ + Q_OBJECT +public: + StateRecordingRenderNodeItem() { setFlag(ItemHasContents, true); } + QSGNode *updatePaintNode(QSGNode *r, UpdatePaintNodeData *) { + if (r) + return r; + StateRecordingRenderNode *rn = new StateRecordingRenderNode(); + rn->name = objectName(); + return rn; + } +}; + +void tst_rendernode::matrix() +{ + qmlRegisterType<StateRecordingRenderNodeItem>("RenderNode", 1, 0, "StateRecorder"); + StateRecordingRenderNode::matrices.clear(); + runTest("matrix.qml"); + + QMatrix4x4 noRotateOffset; + noRotateOffset.translate(20, 20); + { QMatrix4x4 result = StateRecordingRenderNode::matrices.value(QStringLiteral("no-clip; no-rotation")); + QCOMPARE(result, noRotateOffset); + } + { QMatrix4x4 result = StateRecordingRenderNode::matrices.value(QStringLiteral("parent-clip; no-rotation")); + QCOMPARE(result, noRotateOffset); + } + { QMatrix4x4 result = StateRecordingRenderNode::matrices.value(QStringLiteral("self-clip; no-rotation")); + QCOMPARE(result, noRotateOffset); + } + + QMatrix4x4 parentRotation; + parentRotation.translate(10, 10); // parent at x/y: 10 + parentRotation.translate(5, 5); // rotate 90 around center (width/height: 10) + parentRotation.rotate(90, 0, 0, 1); + parentRotation.translate(-5, -5); + parentRotation.translate(10, 10); // StateRecorder at: x/y: 10 + { QMatrix4x4 result = StateRecordingRenderNode::matrices.value(QStringLiteral("no-clip; parent-rotation")); + QCOMPARE(result, parentRotation); + } + { QMatrix4x4 result = StateRecordingRenderNode::matrices.value(QStringLiteral("parent-clip; parent-rotation")); + QCOMPARE(result, parentRotation); + } + { QMatrix4x4 result = StateRecordingRenderNode::matrices.value(QStringLiteral("self-clip; parent-rotation")); + QCOMPARE(result, parentRotation); + } + + QMatrix4x4 selfRotation; + selfRotation.translate(10, 10); // parent at x/y: 10 + selfRotation.translate(10, 10); // StateRecorder at: x/y: 10 + selfRotation.rotate(90, 0, 0, 1); // rotate 90, width/height: 0 + { QMatrix4x4 result = StateRecordingRenderNode::matrices.value(QStringLiteral("no-clip; self-rotation")); + QCOMPARE(result, selfRotation); + } + { QMatrix4x4 result = StateRecordingRenderNode::matrices.value(QStringLiteral("parent-clip; self-rotation")); + QCOMPARE(result, selfRotation); + } + { QMatrix4x4 result = StateRecordingRenderNode::matrices.value(QStringLiteral("self-clip; self-rotation")); + QCOMPARE(result, selfRotation); + } +} + QTEST_MAIN(tst_rendernode) diff --git a/tests/auto/quick/scenegraph/data/render_DrawSets.qml b/tests/auto/quick/scenegraph/data/render_DrawSets.qml index 7515bcf95a..35a8e2860c 100644 --- a/tests/auto/quick/scenegraph/data/render_DrawSets.qml +++ b/tests/auto/quick/scenegraph/data/render_DrawSets.qml @@ -40,6 +40,7 @@ ****************************************************************************/ import QtQuick 2.2 +import SceneGraphTest 1.0 /* The purpose of the test is to verify that a batch of more than 64K @@ -64,39 +65,20 @@ RenderTestBase { id: root - Grid { + Column { id: clipped width: 100 - height: 500 clip: true - columns: 100 - Repeater { - id: clippedRepeater - model: clipped.width * clipped.height - Rectangle { - width: 1 - height: 1 - color: index < clippedRepeater.model / 2 ? "red" : "blue"; - } - } + PerPixelRect { width: 100; height: 250; color: "red" } + PerPixelRect { width: 100; height: 250; color: "blue" } } - Grid { + Column { id: unclipped x: 100 width: 100 - height: 500 - clip: true - columns: 100 - Repeater { - id: unclippedRepeater - model: unclipped.width * unclipped.height - Rectangle { - width: 1 - height: 1 - color: index < unclippedRepeater.model / 2 ? "black" : "#00ff00"; - } - } + PerPixelRect { width: 100; height: 250; color: "black" } + PerPixelRect { width: 100; height: 250; color: "#00ff00" } } SequentialAnimation { @@ -108,6 +90,5 @@ RenderTestBase onEnterFinalStage: { animation.running = true; - } } diff --git a/tests/auto/quick/scenegraph/tst_scenegraph.cpp b/tests/auto/quick/scenegraph/tst_scenegraph.cpp index d510fdcda8..301174656c 100644 --- a/tests/auto/quick/scenegraph/tst_scenegraph.cpp +++ b/tests/auto/quick/scenegraph/tst_scenegraph.cpp @@ -45,14 +45,59 @@ #include <private/qopenglcontext_p.h> - #include <QtQml> +class PerPixelRect : public QQuickItem +{ + Q_PROPERTY(QColor color READ color WRITE setColor NOTIFY colorChanged) + Q_OBJECT +public: + PerPixelRect() { + setFlag(ItemHasContents); + } + + void setColor(const QColor &c) { + if (c == m_color) + return; + m_color = c; + emit colorChanged(c); + } + + QColor color() const { return m_color; } + + QSGNode *updatePaintNode(QSGNode *old, UpdatePaintNodeData *) + { + if (old) + delete old; + + QSGNode *node = new QSGNode(); + + for (int y=0; y<height(); ++y) { + for (int x=0; x<width(); ++x) { + QSGSimpleRectNode *rn = new QSGSimpleRectNode(); + rn->setRect(x, y, 1, 1); + rn->setColor(m_color); + node->appendChildNode(rn); + } + } + + return node; + } + +Q_SIGNALS: + void colorChanged(const QColor &c ); + +private: + QColor m_color; +}; + class tst_SceneGraph : public QObject { Q_OBJECT private slots: + void initTestCase(); + void manyWindows_data(); void manyWindows(); @@ -67,6 +112,11 @@ public: ~ScopedList() { qDeleteAll(*this); } }; +void tst_SceneGraph::initTestCase() +{ + qmlRegisterType<PerPixelRect>("SceneGraphTest", 1, 0, "PerPixelRect"); +} + QQuickView *createView(const QString &file, QWindow *parent = 0, int x = -1, int y = -1, int w = -1, int h = -1) { QQuickView *view = new QQuickView(parent); diff --git a/tests/auto/quick/shared/viewtestutil.cpp b/tests/auto/quick/shared/viewtestutil.cpp index 0e3964d52d..aa6d7c4a93 100644 --- a/tests/auto/quick/shared/viewtestutil.cpp +++ b/tests/auto/quick/shared/viewtestutil.cpp @@ -47,6 +47,9 @@ #include <QtTest/QTest> +#include <private/qquickwindow_p.h> + + QQuickView *QQuickViewTestUtil::createView() { QQuickView *window = new QQuickView(0); @@ -341,3 +344,23 @@ QList<QPair<QString,QString> > QQuickViewTestUtil::ListRange::getModelDataValues return data; } +namespace QQuickTouchUtils { + + /* QQuickWindow does event compression and only delivers events just + * before it is about to render the next frame. Since some tests + * rely on events being delivered immediately AND that no other + * event processing has occurred in the meanwhile, we flush the + * event manually and immediately. + */ + void flush(QQuickWindow *window) { + if (!window) + return; + QQuickWindowPrivate *wd = QQuickWindowPrivate::get(window); + if (!wd || !wd->delayedTouch) + return; + wd->reallyDeliverTouchEvent(wd->delayedTouch); + delete wd->delayedTouch; + wd->delayedTouch = 0; + } + +} diff --git a/tests/auto/quick/shared/viewtestutil.h b/tests/auto/quick/shared/viewtestutil.h index 5b0b10b69c..e10966ddba 100644 --- a/tests/auto/quick/shared/viewtestutil.h +++ b/tests/auto/quick/shared/viewtestutil.h @@ -166,6 +166,10 @@ namespace QQuickViewTestUtil } } +namespace QQuickTouchUtils { + void flush(QQuickWindow *window); +} + Q_DECLARE_METATYPE(QQuickViewTestUtil::QaimModel*) Q_DECLARE_METATYPE(QQuickViewTestUtil::ListChange) Q_DECLARE_METATYPE(QList<QQuickViewTestUtil::ListChange>) diff --git a/tests/auto/quick/touchmouse/touchmouse.pro b/tests/auto/quick/touchmouse/touchmouse.pro index 445bee08ae..7d23dfc0ae 100644 --- a/tests/auto/quick/touchmouse/touchmouse.pro +++ b/tests/auto/quick/touchmouse/touchmouse.pro @@ -8,6 +8,7 @@ macx:CONFIG -= app_bundle SOURCES += tst_touchmouse.cpp include (../../shared/util.pri) +include (../shared/util.pri) TESTDATA = data/* diff --git a/tests/auto/quick/touchmouse/tst_touchmouse.cpp b/tests/auto/quick/touchmouse/tst_touchmouse.cpp index 5b4ad0ffa3..f39a22e131 100644 --- a/tests/auto/quick/touchmouse/tst_touchmouse.cpp +++ b/tests/auto/quick/touchmouse/tst_touchmouse.cpp @@ -58,6 +58,7 @@ #include <QtQml/qqmlproperty.h> #include "../../shared/util.h" +#include "../shared/viewtestutil.h" struct Event { @@ -221,12 +222,15 @@ void tst_TouchMouse::simpleTouchEvent() QPoint p1; p1 = QPoint(20, 20); QTest::touchEvent(window, device).press(0, p1, window); + QQuickTouchUtils::flush(window); QCOMPARE(eventItem1->eventList.size(), 1); QCOMPARE(eventItem1->eventList.at(0).type, QEvent::TouchBegin); p1 += QPoint(10, 0); QTest::touchEvent(window, device).move(0, p1, window); + QQuickTouchUtils::flush(window); QCOMPARE(eventItem1->eventList.size(), 1); QTest::touchEvent(window, device).release(0, p1, window); + QQuickTouchUtils::flush(window); QCOMPARE(eventItem1->eventList.size(), 1); eventItem1->eventList.clear(); @@ -234,11 +238,14 @@ void tst_TouchMouse::simpleTouchEvent() eventItem1->acceptTouch = true; p1 = QPoint(20, 20); QTest::touchEvent(window, device).press(0, p1, window); + QQuickTouchUtils::flush(window); QCOMPARE(eventItem1->eventList.size(), 1); p1 += QPoint(10, 0); QTest::touchEvent(window, device).move(0, p1, window); + QQuickTouchUtils::flush(window); QCOMPARE(eventItem1->eventList.size(), 2); QTest::touchEvent(window, device).release(0, p1, window); + QQuickTouchUtils::flush(window); QCOMPARE(eventItem1->eventList.size(), 3); eventItem1->eventList.clear(); @@ -251,6 +258,7 @@ void tst_TouchMouse::simpleTouchEvent() eventItem1->setAcceptedMouseButtons(Qt::LeftButton); p1 = QPoint(20, 20); QTest::touchEvent(window, device).press(0, p1, window); + QQuickTouchUtils::flush(window); QCOMPARE(eventItem1->eventList.size(), 2); QCOMPARE(eventItem1->eventList.at(0).type, QEvent::TouchBegin); QCOMPARE(eventItem1->eventList.at(1).type, QEvent::MouseButtonPress); @@ -268,10 +276,12 @@ void tst_TouchMouse::simpleTouchEvent() p1 += QPoint(10, 0); QTest::touchEvent(window, device).move(0, p1, window); + QQuickTouchUtils::flush(window); QCOMPARE(eventItem1->eventList.size(), 4); QCOMPARE(eventItem1->eventList.at(2).type, QEvent::TouchUpdate); QCOMPARE(eventItem1->eventList.at(3).type, QEvent::MouseMove); QTest::touchEvent(window, device).release(0, p1, window); + QQuickTouchUtils::flush(window); QCOMPARE(eventItem1->eventList.size(), 6); QCOMPARE(eventItem1->eventList.at(4).type, QEvent::TouchEnd); QCOMPARE(eventItem1->eventList.at(5).type, QEvent::MouseButtonRelease); @@ -286,13 +296,16 @@ void tst_TouchMouse::simpleTouchEvent() eventItem1->setAcceptedMouseButtons(Qt::LeftButton); p1 = QPoint(20, 20); QTest::touchEvent(window, device).press(0, p1, window); + QQuickTouchUtils::flush(window); QCOMPARE(eventItem1->eventList.size(), 2); QCOMPARE(eventItem1->eventList.at(0).type, QEvent::TouchBegin); QCOMPARE(eventItem1->eventList.at(1).type, QEvent::MouseButtonPress); p1 += QPoint(10, 0); QTest::touchEvent(window, device).move(0, p1, window); + QQuickTouchUtils::flush(window); QCOMPARE(eventItem1->eventList.size(), 2); QTest::touchEvent(window, device).release(0, p1, window); + QQuickTouchUtils::flush(window); QCOMPARE(eventItem1->eventList.size(), 2); eventItem1->eventList.clear(); @@ -304,13 +317,16 @@ void tst_TouchMouse::simpleTouchEvent() eventItem1->setAcceptedMouseButtons(Qt::LeftButton); p1 = QPoint(20, 20); QTest::touchEvent(window, device).press(0, p1, window); + QQuickTouchUtils::flush(window); QCOMPARE(eventItem1->eventList.size(), 1); QCOMPARE(eventItem1->eventList.at(0).type, QEvent::TouchBegin); p1 += QPoint(10, 0); QTest::touchEvent(window, device).move(0, p1, window); + QQuickTouchUtils::flush(window); QCOMPARE(eventItem1->eventList.size(), 2); QCOMPARE(eventItem1->eventList.at(1).type, QEvent::TouchUpdate); QTest::touchEvent(window, device).release(0, p1, window); + QQuickTouchUtils::flush(window); QCOMPARE(eventItem1->eventList.size(), 3); QCOMPARE(eventItem1->eventList.at(2).type, QEvent::TouchEnd); eventItem1->eventList.clear(); @@ -376,6 +392,7 @@ void tst_TouchMouse::mouse() // item 2 doesn't accept anything, thus it sees a touch pass by QPoint p1 = QPoint(30, 30); QTest::touchEvent(window, device).press(0, p1, window); + QQuickTouchUtils::flush(window); QCOMPARE(eventItem1->eventList.size(), 2); QCOMPARE(eventItem1->eventList.at(0).type, QEvent::TouchBegin); @@ -412,14 +429,17 @@ void tst_TouchMouse::touchOverMouse() QCOMPARE(eventItem1->eventList.size(), 0); QPoint p1 = QPoint(20, 20); QTest::touchEvent(window, device).press(0, p1, window); + QQuickTouchUtils::flush(window); QCOMPARE(eventItem1->eventList.size(), 0); QCOMPARE(eventItem2->eventList.size(), 1); QCOMPARE(eventItem2->eventList.at(0).type, QEvent::TouchBegin); p1 += QPoint(10, 0); QTest::touchEvent(window, device).move(0, p1, window); + QQuickTouchUtils::flush(window); QCOMPARE(eventItem2->eventList.size(), 2); QCOMPARE(eventItem2->eventList.at(1).type, QEvent::TouchUpdate); QTest::touchEvent(window, device).release(0, p1, window); + QQuickTouchUtils::flush(window); QCOMPARE(eventItem2->eventList.size(), 3); QCOMPARE(eventItem2->eventList.at(2).type, QEvent::TouchEnd); eventItem2->eventList.clear(); @@ -456,6 +476,7 @@ void tst_TouchMouse::mouseOverTouch() QPoint p1 = QPoint(20, 20); QTest::qWait(qApp->styleHints()->mouseDoubleClickInterval() + 10); QTest::touchEvent(window, device).press(0, p1, window); + QQuickTouchUtils::flush(window); QCOMPARE(eventItem1->eventList.size(), 0); QCOMPARE(eventItem2->eventList.size(), 2); QCOMPARE(eventItem2->eventList.at(0).type, QEvent::TouchBegin); @@ -510,10 +531,12 @@ void tst_TouchMouse::buttonOnFlickable() QCOMPARE(eventItem1->eventList.size(), 0); QPoint p1 = QPoint(20, 130); QTest::touchEvent(window, device).press(0, p1, window); + QQuickTouchUtils::flush(window); QTRY_COMPARE(eventItem1->eventList.size(), 2); QCOMPARE(eventItem1->eventList.at(0).type, QEvent::TouchBegin); QCOMPARE(eventItem1->eventList.at(1).type, QEvent::MouseButtonPress); QTest::touchEvent(window, device).release(0, p1, window); + QQuickTouchUtils::flush(window); QCOMPARE(eventItem1->eventList.size(), 4); QCOMPARE(eventItem1->eventList.at(2).type, QEvent::TouchEnd); QCOMPARE(eventItem1->eventList.at(3).type, QEvent::MouseButtonRelease); @@ -522,9 +545,11 @@ void tst_TouchMouse::buttonOnFlickable() // touch button p1 = QPoint(10, 310); QTest::touchEvent(window, device).press(0, p1, window); + QQuickTouchUtils::flush(window); QCOMPARE(eventItem2->eventList.size(), 1); QCOMPARE(eventItem2->eventList.at(0).type, QEvent::TouchBegin); QTest::touchEvent(window, device).release(0, p1, window); + QQuickTouchUtils::flush(window); QCOMPARE(eventItem2->eventList.size(), 2); QCOMPARE(eventItem2->eventList.at(1).type, QEvent::TouchEnd); QCOMPARE(eventItem1->eventList.size(), 0); @@ -536,8 +561,10 @@ void tst_TouchMouse::buttonOnFlickable() // click above button, no events please p1 = QPoint(10, 90); QTest::touchEvent(window, device).press(0, p1, window); + QQuickTouchUtils::flush(window); QCOMPARE(eventItem1->eventList.size(), 0); QTest::touchEvent(window, device).release(0, p1, window); + QQuickTouchUtils::flush(window); QCOMPARE(eventItem1->eventList.size(), 0); eventItem1->eventList.clear(); @@ -548,6 +575,7 @@ void tst_TouchMouse::buttonOnFlickable() QCOMPARE(eventItem1->eventList.size(), 0); p1 = QPoint(10, 110); QTest::touchEvent(window, device).press(0, p1, window); + QQuickTouchUtils::flush(window); QCOMPARE(eventItem1->eventList.size(), 2); QCOMPARE(eventItem1->eventList.at(0).type, QEvent::TouchBegin); QCOMPARE(eventItem1->eventList.at(1).type, QEvent::MouseButtonPress); @@ -560,12 +588,13 @@ void tst_TouchMouse::buttonOnFlickable() p1 += QPoint(0, -10); QPoint p2 = p1 + QPoint(0, -10); QPoint p3 = p2 + QPoint(0, -10); - QTest::qWait(10); + QQuickTouchUtils::flush(window); QTest::touchEvent(window, device).move(0, p1, window); - QTest::qWait(10); + QQuickTouchUtils::flush(window); QTest::touchEvent(window, device).move(0, p2, window); - QTest::qWait(10); + QQuickTouchUtils::flush(window); QTest::touchEvent(window, device).move(0, p3, window); + QQuickTouchUtils::flush(window); // we cannot really know when the events get grabbed away QVERIFY(eventItem1->eventList.size() >= 4); @@ -578,6 +607,7 @@ void tst_TouchMouse::buttonOnFlickable() QVERIFY(flickable->isMovingVertically()); QTest::touchEvent(window, device).release(0, p3, window); + QQuickTouchUtils::flush(window); delete window; } @@ -625,11 +655,13 @@ void tst_TouchMouse::buttonOnDelayedPressFlickable() QCOMPARE(eventItem1->eventList.size(), 0); QPoint p1 = QPoint(10, 110); QTest::touchEvent(window, device).press(0, p1, window); + QQuickTouchUtils::flush(window); // Flickable initially steals events QCOMPARE(eventItem1->eventList.size(), 0); // but we'll get the delayed mouse press after a delay QTRY_COMPARE(eventItem1->eventList.size(), 1); QCOMPARE(eventItem1->eventList.at(0).type, QEvent::MouseButtonPress); + QCOMPARE(filteredEventList.count(), 1); // eventItem1 should have the mouse grab, and have moved the itemForTouchPointId // for the touchMouseId to the new grabber. @@ -641,12 +673,13 @@ void tst_TouchMouse::buttonOnDelayedPressFlickable() p1 += QPoint(0, -10); QPoint p2 = p1 + QPoint(0, -10); QPoint p3 = p2 + QPoint(0, -10); - QTest::qWait(10); + QQuickTouchUtils::flush(window); QTest::touchEvent(window, device).move(0, p1, window); - QTest::qWait(10); + QQuickTouchUtils::flush(window); QTest::touchEvent(window, device).move(0, p2, window); - QTest::qWait(10); + QQuickTouchUtils::flush(window); QTest::touchEvent(window, device).move(0, p3, window); + QQuickTouchUtils::flush(window); QVERIFY(flickable->isMovingVertically()); // flickable should have the mouse grab, and have moved the itemForTouchPointId @@ -656,9 +689,11 @@ void tst_TouchMouse::buttonOnDelayedPressFlickable() QCOMPARE(windowPriv->itemForTouchPointId[0], flickable); QTest::touchEvent(window, device).release(0, p3, window); + QQuickTouchUtils::flush(window); - // We should not have received any synthesised mouse events from Qt gui. - QCOMPARE(filteredEventList.count(), 0); + // We should not have received any synthesised mouse events from Qt gui, + // just the delayed press. + QCOMPARE(filteredEventList.count(), 1); delete window; } @@ -709,7 +744,9 @@ void tst_TouchMouse::buttonOnTouch() // Normal touch click QPoint p1 = QPoint(10, 110); QTest::touchEvent(window, device).press(0, p1, window); + QQuickTouchUtils::flush(window); QTest::touchEvent(window, device).release(0, p1, window); + QQuickTouchUtils::flush(window); QCOMPARE(eventItem1->eventList.size(), 4); QCOMPARE(eventItem1->eventList.at(0).type, QEvent::TouchBegin); QCOMPARE(eventItem1->eventList.at(1).type, QEvent::MouseButtonPress); @@ -730,7 +767,9 @@ void tst_TouchMouse::buttonOnTouch() // Start the events after each other QTest::touchEvent(window, device).press(0, p1, window); + QQuickTouchUtils::flush(window); QTest::touchEvent(window, device).stationary(0).press(1, p2, window); + QQuickTouchUtils::flush(window); QCOMPARE(button1->scale(), 1.0); @@ -738,20 +777,24 @@ void tst_TouchMouse::buttonOnTouch() p1 -= QPoint(10, 0); p2 += QPoint(10, 0); QTest::touchEvent(window, device).move(0, p1, window).move(1, p2, window); + QQuickTouchUtils::flush(window); p1 -= QPoint(10, 0); p2 += QPoint(10, 0); QTest::touchEvent(window, device).move(0, p1, window).move(1, p2, window); + QQuickTouchUtils::flush(window); // QCOMPARE(button1->scale(), 1.5); qDebug() << "Button scale: " << button1->scale(); p1 -= QPoint(10, 0); p2 += QPoint(10, 0); QTest::touchEvent(window, device).move(0, p1, window).move(1, p2, window); + QQuickTouchUtils::flush(window); // QCOMPARE(button1->scale(), 2.0); qDebug() << "Button scale: " << button1->scale(); QTest::touchEvent(window, device).release(0, p1, window).release(1, p2, window); + QQuickTouchUtils::flush(window); // QVERIFY(eventItem1->eventList.isEmpty()); // QCOMPARE(button1->scale(), 2.0); qDebug() << "Button scale: " << button1->scale(); @@ -765,6 +808,7 @@ void tst_TouchMouse::buttonOnTouch() p1 = QPoint(40, 110); p2 = QPoint(60, 110); QTest::touchEvent(window, device).press(0, p1, window).press(1, p2, window); + QQuickTouchUtils::flush(window); QCOMPARE(button1->scale(), 1.0); QCOMPARE(eventItem1->eventList.count(), 2); QCOMPARE(eventItem1->eventList.at(0).type, QEvent::TouchBegin); @@ -774,20 +818,24 @@ void tst_TouchMouse::buttonOnTouch() p1 -= QPoint(10, 0); p2 += QPoint(10, 0); QTest::touchEvent(window, device).move(0, p1, window).move(1, p2, window); + QQuickTouchUtils::flush(window); p1 -= QPoint(10, 0); p2 += QPoint(10, 0); QTest::touchEvent(window, device).move(0, p1, window).move(1, p2, window); + QQuickTouchUtils::flush(window); //QCOMPARE(button1->scale(), 1.5); qDebug() << button1->scale(); p1 -= QPoint(10, 0); p2 += QPoint(10, 0); QTest::touchEvent(window, device).move(0, p1, window).move(1, p2, window); + QQuickTouchUtils::flush(window); qDebug() << button1->scale(); //QCOMPARE(button1->scale(), 2.0); QTest::touchEvent(window, device).release(0, p1, window).release(1, p2, window); + QQuickTouchUtils::flush(window); // QCOMPARE(eventItem1->eventList.size(), 99); qDebug() << button1->scale(); //QCOMPARE(button1->scale(), 2.0); @@ -816,18 +864,22 @@ void tst_TouchMouse::pinchOnFlickable() QVERIFY(flickable->contentX() == 0.0); QPoint p = QPoint(100, 100); QTest::touchEvent(window, device).press(0, p, window); + QQuickTouchUtils::flush(window); QCOMPARE(rect->position(), QPointF(200.0, 200.0)); p -= QPoint(10, 0); QTest::touchEvent(window, device).move(0, p, window); + QQuickTouchUtils::flush(window); p -= QPoint(10, 0); QTest::touchEvent(window, device).move(0, p, window); - QTest::qWait(10); + QQuickTouchUtils::flush(window); p -= QPoint(10, 0); QTest::touchEvent(window, device).move(0, p, window); - QTest::qWait(10); + QQuickTouchUtils::flush(window); p -= QPoint(10, 0); QTest::touchEvent(window, device).move(0, p, window); + QQuickTouchUtils::flush(window); QTest::touchEvent(window, device).release(0, p, window); + QQuickTouchUtils::flush(window); QGuiApplication::processEvents(); QTest::qWait(10); @@ -840,27 +892,36 @@ void tst_TouchMouse::pinchOnFlickable() QPoint p2 = QPoint(60, 20); QTest::QTouchEventSequence pinchSequence = QTest::touchEvent(window, device); + QQuickTouchUtils::flush(window); pinchSequence.press(0, p1, window).commit(); + QQuickTouchUtils::flush(window); // In order for the stationary point to remember its previous position, // we have to reuse the same pinchSequence object. Otherwise if we let it // be destroyed and then start a new sequence, point 0 will default to being // stationary at 0, 0, and PinchArea will filter out that touchpoint because // it is outside its bounds. pinchSequence.stationary(0).press(1, p2, window).commit(); + QQuickTouchUtils::flush(window); p1 -= QPoint(10,10); p2 += QPoint(10,10); pinchSequence.move(0, p1, window).move(1, p2, window).commit(); + QQuickTouchUtils::flush(window); QCOMPARE(rect->scale(), 1.0); p1 -= QPoint(10, 0); p2 += QPoint(10, 0); pinchSequence.move(0, p1, window).move(1, p2, window).commit(); + QQuickTouchUtils::flush(window); p1 -= QPoint(10, 0); p2 += QPoint(10, 0); pinchSequence.move(0, p1, window).move(1, p2, window).commit(); + QQuickTouchUtils::flush(window); p1 -= QPoint(10, 0); p2 += QPoint(10, 0); pinchSequence.move(0, p1, window).move(1, p2, window).commit(); + QVERIFY(!flickable->isDragging()); + QQuickTouchUtils::flush(window); pinchSequence.release(0, p1, window).release(1, p2, window).commit(); + QQuickTouchUtils::flush(window); QVERIFY(rect->scale() > 1.0); } @@ -885,17 +946,22 @@ void tst_TouchMouse::flickableOnPinch() QVERIFY(flickable->contentX() == 0.0); QPoint p = QPoint(100, 100); QTest::touchEvent(window, device).press(0, p, window); + QQuickTouchUtils::flush(window); QCOMPARE(rect->position(), QPointF(200.0, 200.0)); p -= QPoint(10, 0); QTest::touchEvent(window, device).move(0, p, window); + QQuickTouchUtils::flush(window); p -= QPoint(10, 0); QTest::touchEvent(window, device).move(0, p, window); + QQuickTouchUtils::flush(window); QTest::qWait(1000); p -= QPoint(10, 0); QTest::touchEvent(window, device).move(0, p, window); + QQuickTouchUtils::flush(window); QTest::touchEvent(window, device).release(0, p, window); + QQuickTouchUtils::flush(window); QTest::qWait(1000); @@ -909,26 +975,33 @@ void tst_TouchMouse::flickableOnPinch() QPoint p2 = QPoint(60, 20); QTest::QTouchEventSequence pinchSequence = QTest::touchEvent(window, device); pinchSequence.press(0, p1, window).commit(); + QQuickTouchUtils::flush(window); // In order for the stationary point to remember its previous position, // we have to reuse the same pinchSequence object. Otherwise if we let it // be destroyed and then start a new sequence, point 0 will default to being // stationary at 0, 0, and PinchArea will filter out that touchpoint because // it is outside its bounds. pinchSequence.stationary(0).press(1, p2, window).commit(); + QQuickTouchUtils::flush(window); p1 -= QPoint(10,10); p2 += QPoint(10,10); pinchSequence.move(0, p1, window).move(1, p2, window).commit(); + QQuickTouchUtils::flush(window); QCOMPARE(rect->scale(), 1.0); p1 -= QPoint(10, 0); p2 += QPoint(10, 0); pinchSequence.move(0, p1, window).move(1, p2, window).commit(); + QQuickTouchUtils::flush(window); p1 -= QPoint(10, 0); p2 += QPoint(10, 0); pinchSequence.move(0, p1, window).move(1, p2, window).commit(); + QQuickTouchUtils::flush(window); p1 -= QPoint(10, 0); p2 += QPoint(10, 0); pinchSequence.move(0, p1, window).move(1, p2, window).commit(); + QQuickTouchUtils::flush(window); pinchSequence.release(0, p1, window).release(1, p2, window).commit(); + QQuickTouchUtils::flush(window); QVERIFY(rect->scale() > 1.0); } @@ -953,16 +1026,19 @@ void tst_TouchMouse::mouseOnFlickableOnPinch() QVERIFY(flickable->contentX() == 0.0); QPoint p = QPoint(100, 100); QTest::touchEvent(window, device).press(0, p, window); + QQuickTouchUtils::flush(window); QCOMPARE(rect->position(), QPointF(200.0, 200.0)); p -= QPoint(10, 0); QTest::touchEvent(window, device).move(0, p, window); + QQuickTouchUtils::flush(window); p -= QPoint(10, 0); QTest::touchEvent(window, device).move(0, p, window); - QGuiApplication::processEvents(); + QQuickTouchUtils::flush(window); p -= QPoint(10, 0); QTest::touchEvent(window, device).move(0, p, window); + QQuickTouchUtils::flush(window); QTest::touchEvent(window, device).release(0, p, window); - QGuiApplication::processEvents(); + QQuickTouchUtils::flush(window); //QVERIFY(flickable->isMovingHorizontally()); @@ -975,26 +1051,33 @@ void tst_TouchMouse::mouseOnFlickableOnPinch() QPoint p2 = QPoint(60, 20); QTest::QTouchEventSequence pinchSequence = QTest::touchEvent(window, device); pinchSequence.press(0, p1, window).commit(); + QQuickTouchUtils::flush(window); // In order for the stationary point to remember its previous position, // we have to reuse the same pinchSequence object. Otherwise if we let it // be destroyed and then start a new sequence, point 0 will default to being // stationary at 0, 0, and PinchArea will filter out that touchpoint because // it is outside its bounds. pinchSequence.stationary(0).press(1, p2, window).commit(); + QQuickTouchUtils::flush(window); p1 -= QPoint(10,10); p2 += QPoint(10,10); pinchSequence.move(0, p1, window).move(1, p2, window).commit(); + QQuickTouchUtils::flush(window); QCOMPARE(rect->scale(), 1.0); p1 -= QPoint(10, 0); p2 += QPoint(10, 0); pinchSequence.move(0, p1, window).move(1, p2, window).commit(); + QQuickTouchUtils::flush(window); p1 -= QPoint(10, 0); p2 += QPoint(10, 0); pinchSequence.move(0, p1, window).move(1, p2, window).commit(); + QQuickTouchUtils::flush(window); p1 -= QPoint(10, 0); p2 += QPoint(10, 0); pinchSequence.move(0, p1, window).move(1, p2, window).commit(); + QQuickTouchUtils::flush(window); pinchSequence.release(0, p1, window).release(1, p2, window).commit(); + QQuickTouchUtils::flush(window); QVERIFY(rect->scale() > 1.0); // PinchArea should steal the event after flicking started @@ -1002,14 +1085,18 @@ void tst_TouchMouse::mouseOnFlickableOnPinch() flickable->setContentX(0.0); p = QPoint(100, 100); pinchSequence.press(0, p, window).commit(); + QQuickTouchUtils::flush(window); QCOMPARE(rect->position(), QPointF(200.0, 200.0)); p -= QPoint(10, 0); pinchSequence.move(0, p, window).commit(); + QQuickTouchUtils::flush(window); p -= QPoint(10, 0); pinchSequence.move(0, p, window).commit(); + QQuickTouchUtils::flush(window); QGuiApplication::processEvents(); p -= QPoint(10, 0); pinchSequence.move(0, p, window).commit(); + QQuickTouchUtils::flush(window); QQuickWindowPrivate *windowPriv = QQuickWindowPrivate::get(window); qDebug() << "Mouse Grabber: " << windowPriv->mouseGrabberItem << " itemForTouchPointId: " << windowPriv->itemForTouchPointId; @@ -1019,20 +1106,26 @@ void tst_TouchMouse::mouseOnFlickableOnPinch() p1 = QPoint(40, 100); p2 = QPoint(60, 100); pinchSequence.stationary(0).press(1, p2, window).commit(); + QQuickTouchUtils::flush(window); QCOMPARE(rect->scale(), 1.0); p1 -= QPoint(5, 0); p2 += QPoint(5, 0); pinchSequence.move(0, p1, window).move(1, p2, window).commit(); + QQuickTouchUtils::flush(window); p1 -= QPoint(5, 0); p2 += QPoint(5, 0); pinchSequence.move(0, p1, window).move(1, p2, window).commit(); + QQuickTouchUtils::flush(window); p1 -= QPoint(5, 0); p2 += QPoint(5, 0); pinchSequence.move(0, p1, window).move(1, p2, window).commit(); + QQuickTouchUtils::flush(window); pinchSequence.release(0, p1, window).release(1, p2, window).commit(); + QQuickTouchUtils::flush(window); QVERIFY(rect->scale() > 1.0); pinchSequence.release(0, p, window).commit(); + QQuickTouchUtils::flush(window); } /* @@ -1066,16 +1159,17 @@ void tst_TouchMouse::tapOnDismissiveTopMouseAreaClicksBottomOne() // tap the front mouse area (see qml file) QPoint p1(20, 20); QTest::touchEvent(window, device).press(0, p1, window); - QTest::qWait(1); + QQuickTouchUtils::flush(window); QTest::touchEvent(window, device).release(0, p1, window); + QQuickTouchUtils::flush(window); QCOMPARE(bottomClickedSpy.count(), 1); QCOMPARE(bottomDoubleClickedSpy.count(), 0); - QTest::qWait(15); QTest::touchEvent(window, device).press(0, p1, window); - QTest::qWait(1); + QQuickTouchUtils::flush(window); QTest::touchEvent(window, device).release(0, p1, window); + QQuickTouchUtils::flush(window); QCOMPARE(bottomClickedSpy.count(), 1); QCOMPARE(bottomDoubleClickedSpy.count(), 1); diff --git a/tests/auto/quickwidgets/qquickwidget/data/animating.qml b/tests/auto/quickwidgets/qquickwidget/data/animating.qml new file mode 100644 index 0000000000..1f6467aabe --- /dev/null +++ b/tests/auto/quickwidgets/qquickwidget/data/animating.qml @@ -0,0 +1,11 @@ +import QtQuick 2.0 + +Rectangle { + Rectangle { + width: 100 + height: 100 + anchors.centerIn: parent + color: "red" + NumberAnimation on rotation { from: 0; to: 360; duration: 2000; loops: Animation.Infinite; } + } +} diff --git a/tests/auto/quickwidgets/qquickwidget/data/error1.qml b/tests/auto/quickwidgets/qquickwidget/data/error1.qml new file mode 100644 index 0000000000..09df679555 --- /dev/null +++ b/tests/auto/quickwidgets/qquickwidget/data/error1.qml @@ -0,0 +1,5 @@ +import QtQuick 2.0 + +Rectangle { + nonExistentProperty: 5 +} diff --git a/tests/auto/quickwidgets/qquickwidget/data/rectangle.qml b/tests/auto/quickwidgets/qquickwidget/data/rectangle.qml new file mode 100644 index 0000000000..3b18ba35c1 --- /dev/null +++ b/tests/auto/quickwidgets/qquickwidget/data/rectangle.qml @@ -0,0 +1,8 @@ +import QtQuick 2.0 +Rectangle { + width: 200 + height: 200 + + color: "red" +} + diff --git a/tests/auto/quickwidgets/qquickwidget/data/resizemodeitem.qml b/tests/auto/quickwidgets/qquickwidget/data/resizemodeitem.qml new file mode 100644 index 0000000000..225c5711a9 --- /dev/null +++ b/tests/auto/quickwidgets/qquickwidget/data/resizemodeitem.qml @@ -0,0 +1,7 @@ +import QtQuick 2.0 +Item { + width: 200 + height: 200 + +} + diff --git a/tests/auto/quickwidgets/qquickwidget/qquickwidget.pro b/tests/auto/quickwidgets/qquickwidget/qquickwidget.pro new file mode 100644 index 0000000000..069270da3c --- /dev/null +++ b/tests/auto/quickwidgets/qquickwidget/qquickwidget.pro @@ -0,0 +1,19 @@ +CONFIG += testcase +TARGET = tst_qquickwidget +SOURCES += tst_qquickwidget.cpp + +include (../../shared/util.pri) + +osx:CONFIG -= app_bundle + +QT += core-private gui-private qml-private quick-private quickwidgets quickwidgets-private widgets-private testlib + +TESTDATA = data/* + +OTHER_FILES += \ + animating.qml \ + error1.qml \ + rectangle.qml \ + resizemodeitem.qml + +DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0 diff --git a/tests/auto/quickwidgets/qquickwidget/tst_qquickwidget.cpp b/tests/auto/quickwidgets/qquickwidget/tst_qquickwidget.cpp new file mode 100644 index 0000000000..db2d0e14e4 --- /dev/null +++ b/tests/auto/quickwidgets/qquickwidget/tst_qquickwidget.cpp @@ -0,0 +1,276 @@ +/**************************************************************************** +** +** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the test suite of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Digia gives you certain additional +** rights. These rights are described in the Digia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include <qtest.h> +#include <QtTest/QSignalSpy> +#include <QtQml/qqmlcomponent.h> +#include <QtQml/qqmlcontext.h> +#include <QtQuick/qquickview.h> +#include <QtQuick/qquickitem.h> +#include "../../shared/util.h" +#include <QtGui/QWindow> +#include <QtCore/QDebug> +#include <QtQml/qqmlengine.h> + +#include <QtQuickWidgets/QQuickWidget> + +class tst_qquickwidget : public QQmlDataTest +{ + Q_OBJECT +public: + tst_qquickwidget(); + +private slots: + void showHide(); + void reparentAfterShow(); + void changeGeometry(); + void resizemodeitem(); + void errors(); + void engine(); + void readback(); +}; + + +tst_qquickwidget::tst_qquickwidget() +{ +} + +void tst_qquickwidget::showHide() +{ + QWidget window; + + QQuickWidget *childView = new QQuickWidget(&window); + childView->setSource(testFileUrl("rectangle.qml")); + + window.show(); + QVERIFY(QTest::qWaitForWindowExposed(&window, 5000)); + + childView->hide(); +} + +void tst_qquickwidget::reparentAfterShow() +{ + QWidget window; + + QQuickWidget *childView = new QQuickWidget(&window); + childView->setSource(testFileUrl("rectangle.qml")); + window.show(); + QVERIFY(QTest::qWaitForWindowExposed(&window, 5000)); + + QScopedPointer<QQuickWidget> toplevelView(new QQuickWidget); + toplevelView->setParent(&window); + toplevelView->setSource(testFileUrl("rectangle.qml")); + toplevelView->show(); + QVERIFY(QTest::qWaitForWindowExposed(&window, 5000)); +} + +void tst_qquickwidget::changeGeometry() +{ + QWidget window; + + QQuickWidget *childView = new QQuickWidget(&window); + childView->setSource(testFileUrl("rectangle.qml")); + + window.show(); + QVERIFY(QTest::qWaitForWindowExposed(&window, 5000)); + + childView->setGeometry(100,100,100,100); +} + +void tst_qquickwidget::resizemodeitem() +{ + QWidget window; + window.setGeometry(0, 0, 400, 400); + + QScopedPointer<QQuickWidget> view(new QQuickWidget); + view->setParent(&window); + view->setResizeMode(QQuickWidget::SizeRootObjectToView); + QCOMPARE(QSize(0,0), view->initialSize()); + view->setSource(testFileUrl("resizemodeitem.qml")); + QQuickItem* item = qobject_cast<QQuickItem*>(view->rootObject()); + QVERIFY(item); + window.show(); + + view->showNormal(); + // initial size from root object + QCOMPARE(item->width(), 200.0); + QCOMPARE(item->height(), 200.0); + QCOMPARE(view->size(), QSize(200, 200)); + QCOMPARE(view->size(), view->sizeHint()); + QCOMPARE(view->size(), view->initialSize()); + + // size update from view + view->resize(QSize(80,100)); + + QTRY_COMPARE(item->width(), 80.0); + QCOMPARE(item->height(), 100.0); + QCOMPARE(view->size(), QSize(80, 100)); + QCOMPARE(view->size(), view->sizeHint()); + + view->setResizeMode(QQuickWidget::SizeViewToRootObject); + + // size update from view disabled + view->resize(QSize(60,80)); + QCOMPARE(item->width(), 80.0); + QCOMPARE(item->height(), 100.0); + QTRY_COMPARE(view->size(), QSize(60, 80)); + + // size update from root object + item->setWidth(250); + item->setHeight(350); + QCOMPARE(item->width(), 250.0); + QCOMPARE(item->height(), 350.0); + QTRY_COMPARE(view->size(), QSize(250, 350)); + QCOMPARE(view->size(), QSize(250, 350)); + QCOMPARE(view->size(), view->sizeHint()); + + // reset window + window.hide(); + view.reset(new QQuickWidget(&window)); + view->setResizeMode(QQuickWidget::SizeViewToRootObject); + view->setSource(testFileUrl("resizemodeitem.qml")); + item = qobject_cast<QQuickItem*>(view->rootObject()); + QVERIFY(item); + window.show(); + + view->showNormal(); + + // initial size for root object + QCOMPARE(item->width(), 200.0); + QCOMPARE(item->height(), 200.0); + QCOMPARE(view->size(), view->sizeHint()); + QCOMPARE(view->size(), view->initialSize()); + + // size update from root object + item->setWidth(80); + item->setHeight(100); + QCOMPARE(item->width(), 80.0); + QCOMPARE(item->height(), 100.0); + QTRY_COMPARE(view->size(), QSize(80, 100)); + QCOMPARE(view->size(), view->sizeHint()); + + // size update from root object disabled + view->setResizeMode(QQuickWidget::SizeRootObjectToView); + item->setWidth(60); + item->setHeight(80); + QCOMPARE(view->width(), 80); + QCOMPARE(view->height(), 100); + QCOMPARE(QSize(item->width(), item->height()), view->sizeHint()); + + // size update from view + view->resize(QSize(200,300)); + QTRY_COMPARE(item->width(), 200.0); + QCOMPARE(item->height(), 300.0); + QCOMPARE(view->size(), QSize(200, 300)); + QCOMPARE(view->size(), view->sizeHint()); + + window.hide(); + + // if we set a specific size for the view then it should keep that size + // for SizeRootObjectToView mode. + view.reset(new QQuickWidget(&window)); + view->resize(300, 300); + view->setResizeMode(QQuickWidget::SizeRootObjectToView); + QCOMPARE(QSize(0,0), view->initialSize()); + view->setSource(testFileUrl("resizemodeitem.qml")); + view->resize(300, 300); + item = qobject_cast<QQuickItem*>(view->rootObject()); + QVERIFY(item); + window.show(); + + view->showNormal(); + + // initial size from root object + QCOMPARE(item->width(), 300.0); + QCOMPARE(item->height(), 300.0); + QTRY_COMPARE(view->size(), QSize(300, 300)); + QCOMPARE(view->size(), view->sizeHint()); + QCOMPARE(view->initialSize(), QSize(200, 200)); // initial object size +} + +void tst_qquickwidget::errors() +{ + QQuickWidget *view = new QQuickWidget; + QScopedPointer<QQuickWidget> cleanupView(view); + + QQmlTestMessageHandler messageHandler; + view->setSource(testFileUrl("error1.qml")); + QVERIFY(view->status() == QQuickWidget::Error); + QVERIFY(view->errors().count() == 1); +} + +void tst_qquickwidget::engine() +{ + QScopedPointer<QQmlEngine> engine(new QQmlEngine); + QScopedPointer<QQuickWidget> view(new QQuickWidget(engine.data(), 0)); + QScopedPointer<QQuickWidget> view2(new QQuickWidget(view->engine(), 0)); + + QVERIFY(view->engine()); + QVERIFY(view2->engine()); + QCOMPARE(view->engine(), view2->engine()); +} + +void tst_qquickwidget::readback() +{ +#ifdef Q_OS_MAC + QSKIP("Skipping due to issues on OS X: QTBUG-39919"); +#endif + + QWidget window; + + QScopedPointer<QQuickWidget> view(new QQuickWidget); + view->setSource(testFileUrl("rectangle.qml")); + + view->show(); + QVERIFY(QTest::qWaitForWindowExposed(view.data(), 5000)); + + QImage img = view->grabFramebuffer(); + QVERIFY(!img.isNull()); + QCOMPARE(img.width(), view->width()); + QCOMPARE(img.height(), view->height()); + + QRgb pix = img.pixel(5, 5); + QCOMPARE(pix, qRgb(255, 0, 0)); +} + +QTEST_MAIN(tst_qquickwidget) + +#include "tst_qquickwidget.moc" diff --git a/tests/auto/quickwidgets/quickwidgets.pro b/tests/auto/quickwidgets/quickwidgets.pro new file mode 100644 index 0000000000..ee8d6077e6 --- /dev/null +++ b/tests/auto/quickwidgets/quickwidgets.pro @@ -0,0 +1,2 @@ +TEMPLATE = subdirs +SUBDIRS += qquickwidget diff --git a/tests/auto/shared/testhttpserver.cpp b/tests/auto/shared/testhttpserver.cpp index d3de584084..231f22b35b 100644 --- a/tests/auto/shared/testhttpserver.cpp +++ b/tests/auto/shared/testhttpserver.cpp @@ -71,7 +71,8 @@ slowFiles/slowMain.qml \endcode it can be added like this: \code -TestHTTPServer server(14445); +TestHTTPServer server; +QVERIFY2(server.listen(14445), qPrintable(server.errorString())); server.serveDirectory("disconnect", TestHTTPServer::Disconnect); server.serveDirectory("files"); server.serveDirectory("slowFiles", TestHTTPServer::Delay); @@ -87,17 +88,21 @@ The following request urls will then result in the appropriate action: \row \li http://localhost:14445/slowMain.qml \li slowMain.qml returned after 500ms \endtable */ -TestHTTPServer::TestHTTPServer(quint16 port) +TestHTTPServer::TestHTTPServer() : m_state(AwaitingHeader) { QObject::connect(&server, SIGNAL(newConnection()), this, SLOT(newConnection())); - server.listen(QHostAddress::LocalHost, port); } -bool TestHTTPServer::isValid() const +bool TestHTTPServer::listen(quint16 port) { - return server.isListening(); + return server.listen(QHostAddress::LocalHost, port); +} + +QString TestHTTPServer::errorString() const +{ + return server.errorString(); } bool TestHTTPServer::serveDirectory(const QString &dir, Mode mode) diff --git a/tests/auto/shared/testhttpserver.h b/tests/auto/shared/testhttpserver.h index ae7d137143..a71386ddec 100644 --- a/tests/auto/shared/testhttpserver.h +++ b/tests/auto/shared/testhttpserver.h @@ -51,9 +51,10 @@ class TestHTTPServer : public QObject { Q_OBJECT public: - TestHTTPServer(quint16 port); + TestHTTPServer(); - bool isValid() const; + bool listen(quint16 port); + QString errorString() const; enum Mode { Normal, Delay, Disconnect }; bool serveDirectory(const QString &, Mode = Normal); diff --git a/tests/manual/httpserver/main.cpp b/tests/manual/httpserver/main.cpp index ea729547ce..4ad44508b0 100644 --- a/tests/manual/httpserver/main.cpp +++ b/tests/manual/httpserver/main.cpp @@ -112,7 +112,11 @@ int main(int argc, char *argv[]) << "\":\n\n" << QDir(directory).entryList(QDir::Files).join(QLatin1Char('\n')) << "\n\non http://localhost:" << port << '\n'; - TestHTTPServer server(port); + TestHTTPServer server; + if (!server.listen(port)) { + std::wcout << "Couldn't listen on port " << port << server.errorString().toLocal8Bit(); + exit(-1); + } server.serveDirectory(directory); return a.exec(); diff --git a/tests/manual/v4/Sha1.js b/tests/manual/v4/Sha1.js new file mode 100644 index 0000000000..406849ca58 --- /dev/null +++ b/tests/manual/v4/Sha1.js @@ -0,0 +1,146 @@ +/* + * A JavaScript implementation of the Secure Hash Algorithm, SHA-1, as defined + * in FIPS PUB 180-1 + * Version 2.1a Copyright Paul Johnston 2000 - 2002. + * Other contributors: Greg Holt, Andrew Kepert, Ydnar, Lostinet + * Distributed under the BSD License + * See http://pajhome.org.uk/crypt/md5 for details. + */ + +/* + * Configurable variables. You may need to tweak these to be compatible with + * the server-side, but the defaults work in most cases. + */ +var hexcase = 0; /* hex output format. 0 - lowercase; 1 - uppercase */ +var chrsz = 8; /* bits per input character. 8 - ASCII; 16 - Unicode */ + +/* + * These are the functions you'll usually want to call + * They take string arguments and return either hex or base-64 encoded strings + */ +function hex_sha1(s){return binb2hex(core_sha1(str2binb(s),s.length * chrsz));} + +/* + * Perform a simple self-test to see if the VM is working + */ +function sha1_vm_test() +{ + return hex_sha1("abc") == "a9993e364706816aba3e25717850c26c9cd0d89d"; +} + +/* + * Calculate the SHA-1 of an array of big-endian words, and a bit length + */ +function core_sha1(x, len) +{ + /* append padding */ + x[len >> 5] |= 0x80 << (24 - len % 32); + x[((len + 64 >> 9) << 4) + 15] = len; + + var w = Array(80); + var a = 1732584193; + var b = -271733879; + var c = -1732584194; + var d = 271733878; + var e = -1009589776; + + for(var i = 0; i < x.length; i += 16) + { + var olda = a; + var oldb = b; + var oldc = c; + var oldd = d; + var olde = e; + + for(var j = 0; j < 80; j++) + { + if(j < 16) w[j] = x[i + j]; + else w[j] = rol(w[j-3] ^ w[j-8] ^ w[j-14] ^ w[j-16], 1); + var t = safe_add(safe_add(rol(a, 5), sha1_ft(j, b, c, d)), + safe_add(safe_add(e, w[j]), sha1_kt(j))); + e = d; + d = c; + c = rol(b, 30); + b = a; + a = t; + } + + a = safe_add(a, olda); + b = safe_add(b, oldb); + c = safe_add(c, oldc); + d = safe_add(d, oldd); + e = safe_add(e, olde); + } + return Array(a, b, c, d, e); + +} + +/* + * Perform the appropriate triplet combination function for the current + * iteration + */ +function sha1_ft(t, b, c, d) +{ + if(t < 20) return (b & c) | ((~b) & d); + if(t < 40) return b ^ c ^ d; + if(t < 60) return (b & c) | (b & d) | (c & d); + return b ^ c ^ d; +} + +/* + * Determine the appropriate additive constant for the current iteration + */ +function sha1_kt(t) +{ + return (t < 20) ? 1518500249 : (t < 40) ? 1859775393 : + (t < 60) ? -1894007588 : -899497514; +} + +/* + * Add integers, wrapping at 2^32. This uses 16-bit operations internally + * to work around bugs in some JS interpreters. + */ +function safe_add(x, y) +{ + var lsw = (x & 0xFFFF) + (y & 0xFFFF); + var msw = (x >> 16) + (y >> 16) + (lsw >> 16); + return (msw << 16) | (lsw & 0xFFFF); +} + +/* + * Bitwise rotate a 32-bit number to the left. + */ +function rol(num, cnt) +{ + return (num << cnt) | (num >>> (32 - cnt)); +} + +/* + * Convert an 8-bit or 16-bit string to an array of big-endian words + * In 8-bit function, characters >255 have their hi-byte silently ignored. + */ +function str2binb(str) +{ + var bin = Array(); + var mask = (1 << chrsz) - 1; + for(var i = 0; i < str.length * chrsz; i += chrsz) + bin[i>>5] |= (str.charCodeAt(i / chrsz) & mask) << (32 - chrsz - i%32); + return bin; +} + +/* + * Convert an array of big-endian words to a hex string. + */ +function binb2hex(binarray) +{ + var hex_tab = hexcase ? "0123456789ABCDEF" : "0123456789abcdef"; + var str = ""; + for(var i = 0; i < binarray.length * 4; i++) + { + str += hex_tab.charAt((binarray[i>>2] >> ((3 - i%4)*8+4)) & 0xF) + + hex_tab.charAt((binarray[i>>2] >> ((3 - i%4)*8 )) & 0xF); + } + return str; +} + +print ("Self check:", sha1_vm_test()) diff --git a/tests/testapplications/listview/sticky.qml b/tests/testapplications/listview/sticky.qml new file mode 100644 index 0000000000..6dcdf6b57e --- /dev/null +++ b/tests/testapplications/listview/sticky.qml @@ -0,0 +1,250 @@ +/**************************************************************************** +** +** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the test suite of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:BSD$ +** You may use this file under the terms of the BSD license as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of Digia Plc and its Subsidiary(-ies) nor the names +** of its contributors may be used to endorse or promote products derived +** from this software without specific prior written permission. +** +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +import QtQuick 2.4 +import QtQuick.Window 2.1 +import QtQuick.Layouts 1.1 +import QtQuick.Controls 1.1 +import QtQuick.Controls.Styles 1.1 +import Qt.labs.settings 1.0 + +ApplicationWindow { + id: window + + width: 640 + height: 480 + visible: true + + property int hspacing: 10 + property int vspacing: 35 + + Settings { + property alias windowX: window.x + property alias windowY: window.y + property alias windowWidth: window.width + property alias windowHeight: window.height + property alias orientation: oriItem.currentIndex + property alias layoutDirection: ldItem.currentIndex + property alias verticalLayoutDirection: vldItem.currentIndex + property alias hasHeader: hItem.checked + property alias headerPositioning: shItem.currentIndex + property alias hasFooter: fItem.checked + property alias footerPositioning: sfItem.currentIndex + property alias clipEnabled: clipItem.checked + property alias filterEnabled: filterItem.checked + property alias opacityEnabled: opacityItem.checked + property alias inlineSections: isItem.checked + property alias stickyCurrentSection: scsItem.checked + property alias stickyNextSection: snsItem.checked + } + + toolBar: GridLayout { + rows: 3 + flow: GridLayout.TopToBottom + + anchors.margins: hspacing + anchors.left: parent.left + anchors.right: parent.right + + ComboBox { id: oriItem; currentIndex: 1; model: ["Horizontal", "Vertical"] } + ComboBox { id: ldItem; model: ["LeftToRight", "RightToLeft"] } + ComboBox { id: vldItem; model: ["TopToBottom", "BottomToTop"] } + + CheckBox { id: clipItem; text: "Clip"; checked: true } + CheckBox { id: opacityItem; text: "Opaque"; checked: true } + CheckBox { id: filterItem; text: "Filter" } + + CheckBox { id: hItem; text: "Header:" } + CheckBox { id: fItem; text: "Footer:" } + Item { width: 1; height: 1 } + + ComboBox { id: shItem; model: shModel; textRole: "name"; enabled: hItem.checked } + ComboBox { id: sfItem; model: sfModel; textRole: "name"; enabled: fItem.checked } + Item { width: 1; height: 1 } + + CheckBox { id: scsItem; text: "Sticky current section" } + CheckBox { id: snsItem; text: "Sticky next section" } + CheckBox { id: isItem; text: "Inline sections" } + + Button { text: "Beginning"; onClicked: listview.positionViewAtBeginning() } + Button { text: "Middle"; onClicked: listview.positionViewAtIndex(50, ListView.Center) } + Button { text: "End"; onClicked: listview.positionViewAtEnd() } + } + + ListModel { + id: shModel + ListElement { name: "Inline"; value: ListView.InlineHeader } + ListElement { name: "Overlay"; value: ListView.OverlayHeader } + ListElement { name: "PullBack"; value: ListView.PullBackHeader } + } + + ListModel { + id: sfModel + ListElement { name: "Inline"; value: ListView.InlineFooter } + ListElement { name: "Overlay"; value: ListView.OverlayFooter } + ListElement { name: "PullBack"; value: ListView.PullBackFooter } + } + + statusBar: RowLayout { + anchors.margins: window.hspacing + anchors.left: parent.left + anchors.right: parent.right + Text { + anchors.left: parent.left + text: listview.currentSection ? "#" + listview.currentSection : "" + visible: scsItem.checked || snsItem.checked || isItem.checked + } + Text { + anchors.right: parent.right + property string pos: listview.isVertical ? listview.contentY.toFixed(2) : listview.contentX.toFixed(2) + property string size: listview.isVertical ? listview.contentHeight.toFixed(2) : listview.contentWidth.toFixed(2) + function padded(str) { + return String(" " + str).slice(-8) + } + text: padded(pos) + " /" + padded(size) + } + } + + ListView { + id: listview + + property bool isVertical: orientation == ListView.Vertical + + anchors.fill: parent + anchors.leftMargin: window.hspacing + anchors.rightMargin: window.hspacing + anchors.topMargin: window.vspacing + anchors.bottomMargin: window.vspacing + + clip: clipItem.checked + + orientation: oriItem.currentIndex === 0 ? ListView.Horizontal : ListView.Vertical + layoutDirection: ldItem.currentIndex === 0 ? ListView.LeftToRight : ListView.RightToLeft + verticalLayoutDirection: vldItem.currentIndex === 0 ? ListView.TopToBottom : ListView.BottomToTop + + model: ListModel { + Component.onCompleted: { + for (var i = 0; i < 100; ++i) + append({section: Math.floor(i / 10)}) + } + } + + delegate: Rectangle { + clip: true + property bool filterOut: filterItem.checked && index % 5 + visible: !filterOut + width: filterOut ? 0 : parent && listview.isVertical ? parent.width : label.implicitHeight + height: filterOut ? 0 : !parent || listview.isVertical ? label.implicitHeight : parent.height + color: index % 2 ? "#ffffff" : "#f3f3f3" + Text { + id: label + anchors.centerIn: parent + rotation: listview.isVertical ? 0 : -90 + text: index + } + } + + section.property: "section" + section.delegate: Rectangle { + width: parent && listview.orientation == ListView.Vertical ? parent.width : sectionLabel.implicitHeight + height: !parent || listview.orientation == ListView.Vertical ? sectionLabel.implicitHeight : parent.height + color: "darkgray" + opacity: opacityItem.checked ? 1.0 : 0.8 + Text { + id: sectionLabel + anchors.centerIn: parent + rotation: listview.isVertical ? 0 : -90 + text: "#" + section + } + } + section.labelPositioning: (isItem.checked ? ViewSection.InlineLabels : 0) | + (scsItem.checked ? ViewSection.CurrentLabelAtStart : 0) | + (snsItem.checked ? ViewSection.NextLabelAtEnd : 0) + + headerPositioning: shModel.get(shItem.currentIndex).value + header: hItem.checked ? headerComponent : null + + footerPositioning: sfModel.get(sfItem.currentIndex).value + footer: fItem.checked ? footerComponent : null + + Rectangle { + border.width: 1 + anchors.fill: parent + color: "transparent" + border.color: "darkgray" + } + + Component { + id: headerComponent + Rectangle { + z: 3 + width: parent && listview.orientation == ListView.Vertical ? parent.width : headerLabel.implicitHeight * 2 + height: !parent || listview.orientation == ListView.Vertical ? headerLabel.implicitHeight * 2 : parent.height + color: "steelblue" + opacity: opacityItem.checked ? 1.0 : 0.8 + Text { + id: headerLabel + text: "Header" + font.pointSize: 12 + anchors.centerIn: parent + rotation: listview.isVertical ? 0 : -90 + } + } + } + + Component { + id: footerComponent + Rectangle { + z: 3 + width: parent && listview.orientation == ListView.Vertical ? parent.width : footerLabel.implicitHeight * 2 + height: !parent || listview.orientation == ListView.Vertical ? footerLabel.implicitHeight * 2 : parent.height + color: "steelblue" + opacity: opacityItem.checked ? 1.0 : 0.8 + Text { + id: footerLabel + text: "Footer" + font.pointSize: 10 + anchors.centerIn: parent + rotation: listview.isVertical ? 0 : -90 + } + } + } + } +} |