aboutsummaryrefslogtreecommitdiffstats
path: root/tests/auto
diff options
context:
space:
mode:
authorQt Forward Merge Bot <qt_forward_merge_bot@qt-project.org>2020-01-09 01:00:43 +0100
committerFabian Kosmale <fabian.kosmale@qt.io>2020-01-09 07:24:26 +0000
commitba10b0b9ed93be007fcb156710ef6081000e3ae3 (patch)
treeea17c625900b83d5955cb4a2db1587a5f07e2fb4 /tests/auto
parent653c25d48298fb747cf6f3b012816855c51d4260 (diff)
parent1798d20ded699837f7b3afe0bb340617af266518 (diff)
Merge remote-tracking branch 'origin/5.14' into 5.15
Conflicts: src/particles/qquickitemparticle.cpp src/qmlmodels/qqmladaptormodel.cpp tests/auto/particles/qquickitemparticle/tst_qquickitemparticle.cpp Change-Id: Ibd8fbb91da6893a09f4ffe61ad0b95d8149bbc87
Diffstat (limited to 'tests/auto')
-rw-r--r--tests/auto/particles/qquickitemparticle/data/loader.qml65
-rw-r--r--tests/auto/particles/qquickitemparticle/tst_qquickitemparticle.cpp37
-rw-r--r--tests/auto/qml/qjsengine/tst_qjsengine.cpp182
-rw-r--r--tests/auto/qml/qjsvalue/tst_qjsvalue.cpp64
-rw-r--r--tests/auto/qml/qjsvalue/tst_qjsvalue.h2
-rw-r--r--tests/auto/qml/qqmlapplicationengine/data/invalid.qml5
-rw-r--r--tests/auto/qml/qqmlapplicationengine/tst_qqmlapplicationengine.cpp16
-rw-r--r--tests/auto/qml/qqmlecmascript/tst_qqmlecmascript.cpp49
-rw-r--r--tests/auto/qml/qquickworkerscript/data/doRequest.mjs6
-rw-r--r--tests/auto/qml/qquickworkerscript/data/xmlHttpRequest.qml16
-rw-r--r--tests/auto/qml/qquickworkerscript/tst_qquickworkerscript.cpp8
11 files changed, 450 insertions, 0 deletions
diff --git a/tests/auto/particles/qquickitemparticle/data/loader.qml b/tests/auto/particles/qquickitemparticle/data/loader.qml
new file mode 100644
index 0000000000..beac7a0410
--- /dev/null
+++ b/tests/auto/particles/qquickitemparticle/data/loader.qml
@@ -0,0 +1,65 @@
+/****************************************************************************
+**
+** Copyright (C) 2020 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the test suite of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import QtQuick 2.0
+import QtQuick.Particles 2.0
+
+Rectangle {
+ color: "black"
+ width: 320
+ height: 320
+
+ Component {
+ id: component
+
+ ParticleSystem {
+ id: sys
+ objectName: "system"
+ anchors.fill: parent
+ running: visible
+
+ ItemParticle {
+ delegate: Image { source: "../../shared/star.png" }
+ }
+
+ Emitter {
+ //0,0 position
+ size: 32
+ emitRate: 10
+ lifeSpan: 150000
+ }
+ }
+ }
+
+ Loader {
+ id: loader
+ objectName: "loader"
+ sourceComponent: component
+ anchors.fill: parent
+ }
+}
diff --git a/tests/auto/particles/qquickitemparticle/tst_qquickitemparticle.cpp b/tests/auto/particles/qquickitemparticle/tst_qquickitemparticle.cpp
index 0087c74a9c..28ebbb3c05 100644
--- a/tests/auto/particles/qquickitemparticle/tst_qquickitemparticle.cpp
+++ b/tests/auto/particles/qquickitemparticle/tst_qquickitemparticle.cpp
@@ -46,6 +46,8 @@ private slots:
void test_deletion();
void test_noDeletion();
void test_takeGive();
+ void test_noCrashOnReset();
+ void test_noLeakWhenDeleted();
};
void tst_qquickitemparticle::initTestCase()
@@ -120,6 +122,41 @@ void tst_qquickitemparticle::test_takeGive()
delete view;
}
+void tst_qquickitemparticle::test_noCrashOnReset()
+{
+ QQuickView* view = createView(testFileUrl("basic.qml"), 600);
+ QQuickParticleSystem* system = view->rootObject()->findChild<QQuickParticleSystem*>("system");
+
+ for (int i = 0; i < 10; ++i) {
+ ensureAnimTime(16, system->m_animation);
+ system->reset();
+ }
+
+ delete view;
+}
+
+void tst_qquickitemparticle::test_noLeakWhenDeleted()
+{
+ QQuickView* view = createView(testFileUrl("loader.qml"), 500);
+ QQuickParticleSystem* system = view->rootObject()->findChild<QQuickParticleSystem*>("system");
+ ensureAnimTime(100, system->m_animation);
+
+ auto particles = qAsConst(system->groupData[0]->data);
+ QVERIFY(!particles.isEmpty());
+
+ QQuickParticleData* firstParticleData = particles.first();
+ QPointer<QQuickItem> firstParticleDelegate = firstParticleData->delegate;
+ QVERIFY(!firstParticleDelegate.isNull());
+
+ QQuickItem* loader = view->rootObject()->findChild<QQuickItem*>("loader");
+ loader->setProperty("active", false); //This should destroy the ParticleSystem, ItemParticle and Emitter
+
+ QTest::qWait(1); //Process events to make sure the loader is properly unloaded
+ QVERIFY(firstParticleDelegate.isNull()); //Delegates should be deleted
+
+ delete view;
+}
+
QTEST_MAIN(tst_qquickitemparticle);
#include "tst_qquickitemparticle.moc"
diff --git a/tests/auto/qml/qjsengine/tst_qjsengine.cpp b/tests/auto/qml/qjsengine/tst_qjsengine.cpp
index f1ff396d4f..66a526fda8 100644
--- a/tests/auto/qml/qjsengine/tst_qjsengine.cpp
+++ b/tests/auto/qml/qjsengine/tst_qjsengine.cpp
@@ -252,6 +252,17 @@ private slots:
void interrupt();
void triggerBackwardJumpWithDestructuring();
+ void arrayConcatOnSparseArray();
+ void sortSparseArray();
+ void compileBrokenRegexp();
+ void sortNonStringArray();
+ void iterateInvalidProxy();
+ void applyOnHugeArray();
+
+ void tostringRecursionCheck();
+ void arrayIncludesWithLargeArray();
+ void printCircularArray();
+ void typedArraySet();
public:
Q_INVOKABLE QJSValue throwingCppMethod1();
@@ -4961,6 +4972,177 @@ void tst_QJSEngine::triggerBackwardJumpWithDestructuring()
QVERIFY(!value.isError());
}
+void tst_QJSEngine::arrayConcatOnSparseArray()
+{
+ QJSEngine engine;
+ engine.installExtensions(QJSEngine::GarbageCollectionExtension);
+ const auto value = engine.evaluate(
+ "(function() {\n"
+ " const v4 = [1,2,3];\n"
+ " const v7 = [4,5];\n"
+ " v7.length = 1337;\n"
+ " const v9 = v4.concat(v7);\n"
+ " gc();\n"
+ " return v9;\n"
+ "})();");
+ QCOMPARE(value.property("length").toInt(), 1340);
+ for (int i = 0; i < 5; ++i)
+ QCOMPARE(value.property(i).toInt(), i + 1);
+ for (int i = 5; i < 1340; ++i)
+ QVERIFY(value.property(i).isUndefined());
+}
+
+void tst_QJSEngine::sortSparseArray()
+{
+ QJSEngine engine;
+ engine.installExtensions(QJSEngine::ConsoleExtension);
+ const auto value = engine.evaluate(
+ "(function() {\n"
+ " var sparse = [0];\n"
+ " sparse = Object.defineProperty(sparse, \"10\", "
+ " {get: ()=>{return 2}, set: ()=>{return 2}} );\n"
+ " return Array.prototype.sort.call(sparse, ()=>{});\n"
+ "})();");
+
+ QCOMPARE(value.property("length").toInt(), 11);
+ QVERIFY(value.property(0).isNumber());
+ QCOMPARE(value.property(0).toInt(), 0);
+ QVERIFY(value.property(1).isNumber());
+ QCOMPARE(value.property(1).toInt(), 2);
+ QVERIFY(value.property(10).isUndefined());
+}
+
+void tst_QJSEngine::compileBrokenRegexp()
+{
+ QJSEngine engine;
+ const auto value = engine.evaluate(
+ "(function() {"
+ "var ret = new RegExp(Array(4097).join("
+ " String.fromCharCode(58)) + Array(4097).join(String.fromCharCode(480)) "
+ " + Array(65537).join(String.fromCharCode(5307)));"
+ "return RegExp.prototype.compile.call(ret, 'a','b');"
+ "})();"
+ );
+
+ QVERIFY(value.isError());
+ QCOMPARE(value.toString(), "SyntaxError: Invalid flags supplied to RegExp constructor");
+}
+
+void tst_QJSEngine::tostringRecursionCheck()
+{
+ QJSEngine engine;
+ auto value = engine.evaluate(R"js(
+ var a = {};
+ var b = new Array(1337);
+ function main() {
+ var ret = a.toLocaleString;
+ b[1] = ret;
+ Array = {};
+ Object.toString = b[1];
+ var ret = String.prototype.lastIndexOf.call({}, b[1]);
+ var ret = String.prototype.charAt.call(Function, Object);
+ }
+ main();
+ )js");
+ QVERIFY(value.isError());
+ QCOMPARE(value.toString(), QLatin1String("RangeError: Maximum call stack size exceeded."));
+}
+
+void tst_QJSEngine::arrayIncludesWithLargeArray()
+{
+ QJSEngine engine;
+ auto value = engine.evaluate(R"js(
+ let arr = new Array(10000000)
+ arr.includes(42)
+ )js");
+ QVERIFY(value.isBool());
+ QCOMPARE(value.toBool(), false);
+}
+
+void tst_QJSEngine::printCircularArray()
+{
+ QJSEngine engine;
+ engine.installExtensions(QJSEngine::ConsoleExtension);
+ QTest::ignoreMessage(QtMsgType::QtDebugMsg, "[[Circular]]");
+ auto value = engine.evaluate(R"js(
+ let v1 = []
+ v1.push(v1)
+ console.log(v1)
+ )js");
+}
+
+void tst_QJSEngine::sortNonStringArray()
+{
+ QJSEngine engine;
+ const auto value = engine.evaluate(
+ "const v4 = [Symbol.iterator, 1];"
+ "const v5 = v4.sort();"
+ );
+ QVERIFY(value.isError());
+ QCOMPARE(value.toString(), "TypeError: Cannot convert a symbol to a string.");
+}
+
+void tst_QJSEngine::iterateInvalidProxy()
+{
+ QJSEngine engine;
+ const auto value = engine.evaluate(
+ "const v1 = new Proxy(Reflect, Reflect);"
+ "for (const v2 in v1) {}"
+ "const v3 = { getOwnPropertyDescriptor: eval, getPrototypeOf: eval };"
+ "const v4 = new Proxy(v3, v3);"
+ "for (const v5 in v4) {}"
+ );
+ QVERIFY(value.isError());
+ QCOMPARE(value.toString(), "TypeError: Type error");
+}
+
+void tst_QJSEngine::applyOnHugeArray()
+{
+ QJSEngine engine;
+ const auto value = engine.evaluate(
+ "var a = new Array(10);"
+ "a[536870912] = Function;"
+ "Function.apply('aaaaaaaa', a);"
+ );
+ QVERIFY(value.isError());
+ QCOMPARE(value.toString(), "RangeError: Array too large for apply().");
+}
+
+void tst_QJSEngine::typedArraySet()
+{
+ QJSEngine engine;
+ const auto value = engine.evaluate(
+ "(function() {"
+ " var length = 0xffffffe;"
+ " var offset = 0xfffffff0;"
+ " var e1;"
+ " var e2;"
+ " try {"
+ " var source1 = new Int8Array(length);"
+ " var target1 = new Int8Array(length);"
+ " target1.set(source1, offset);"
+ " } catch (intError) {"
+ " e1 = intError;"
+ " }"
+ " try {"
+ " var source2 = new Array(length);"
+ " var target2 = new Int8Array(length);"
+ " target2.set(source2, offset);"
+ " } catch (arrayError) {"
+ " e2 = arrayError;"
+ " }"
+ " return [e1, e2];"
+ "})();"
+ );
+
+ QVERIFY(value.isArray());
+ for (int i = 0; i < 2; ++i) {
+ const auto error = value.property(i);
+ QVERIFY(error.isError());
+ QCOMPARE(error.toString(), "RangeError: TypedArray.set: out of range");
+ }
+}
+
QTEST_MAIN(tst_QJSEngine)
#include "tst_qjsengine.moc"
diff --git a/tests/auto/qml/qjsvalue/tst_qjsvalue.cpp b/tests/auto/qml/qjsvalue/tst_qjsvalue.cpp
index 37d0ea4dea..95f554776f 100644
--- a/tests/auto/qml/qjsvalue/tst_qjsvalue.cpp
+++ b/tests/auto/qml/qjsvalue/tst_qjsvalue.cpp
@@ -2708,6 +2708,70 @@ void tst_QJSValue::nestedObjectToVariant()
QCOMPARE(o.toVariant(), expected);
}
+static int instanceCount = 0;
+
+struct MyType
+{
+ MyType(int n = 0, const char *t=nullptr): number(n), text(t)
+ {
+ ++instanceCount;
+ }
+ MyType(const MyType &other)
+ : number(other.number), text(other.text)
+ {
+ ++instanceCount;
+ }
+ ~MyType()
+ {
+ --instanceCount;
+ }
+ int number;
+ const char *text;
+};
+
+Q_DECLARE_METATYPE(MyType)
+Q_DECLARE_METATYPE(MyType*)
+
+void tst_QJSValue::jsvalueArrayToSequenceType()
+{
+ QCOMPARE(instanceCount, 0);
+ {
+ QJSEngine eng {};
+ auto testObject = eng.newObject();
+ testObject.setProperty("test", 42);
+ testObject.setProperty("mytypeobject", eng.toScriptValue(QVariant::fromValue(MyType {42, "hello"})));
+ auto array = eng.newArray(4);
+ array.setProperty(0, QLatin1String("Hello World"));
+ array.setProperty(1, 42);
+ array.setProperty(2, QJSValue(QJSValue::UndefinedValue));
+ array.setProperty(3, testObject);
+ auto asVariant = QVariant::fromValue(array);
+ QVERIFY(asVariant.canConvert<QVariantList>());
+ auto asIterable = asVariant.value<QSequentialIterable>();
+ for (auto it = asIterable.begin(); it != asIterable.end(); ++it) {
+ Q_UNUSED(*it)
+ }
+ int i = 0;
+ for (QVariant myVariant: asIterable) {
+ QCOMPARE(myVariant.isValid(), i != 2);
+ ++i;
+ }
+ QVERIFY(asIterable.at(2).value<QVariant>().isNull());
+ QCOMPARE(asIterable.at(3).value<QVariantMap>().find("mytypeobject")->value<MyType>().number, 42);
+ QCOMPARE(asIterable.at(0).value<QVariant>().toString(), QLatin1String("Hello World"));
+ auto it1 = asIterable.begin();
+ auto it2 = asIterable.begin();
+ QCOMPARE((*it1).value<QVariant>().toString(), (*it2).value<QVariant>().toString());
+ QCOMPARE((*it1).value<QVariant>().toString(), QLatin1String("Hello World"));
+ ++it2;
+ QCOMPARE((*it1).value<QVariant>().toString(), QLatin1String("Hello World"));
+ QCOMPARE((*it2).value<QVariant>().toInt(), 42);
+ }
+ // tests need to be done after engine has been destroyed, else it will hold a reference until
+ // the gc decides to collect it
+ QCOMPARE(instanceCount, 0);
+}
+
void tst_QJSValue::deleteFromDifferentThread()
{
#if !QT_CONFIG(thread)
diff --git a/tests/auto/qml/qjsvalue/tst_qjsvalue.h b/tests/auto/qml/qjsvalue/tst_qjsvalue.h
index f704169d43..d85b9a0552 100644
--- a/tests/auto/qml/qjsvalue/tst_qjsvalue.h
+++ b/tests/auto/qml/qjsvalue/tst_qjsvalue.h
@@ -142,6 +142,8 @@ private slots:
void nestedObjectToVariant_data();
void nestedObjectToVariant();
+ void jsvalueArrayToSequenceType();
+
void deleteFromDifferentThread();
private:
diff --git a/tests/auto/qml/qqmlapplicationengine/data/invalid.qml b/tests/auto/qml/qqmlapplicationengine/data/invalid.qml
new file mode 100644
index 0000000000..5939a69a7a
--- /dev/null
+++ b/tests/auto/qml/qqmlapplicationengine/data/invalid.qml
@@ -0,0 +1,5 @@
+import QtQml 2.12
+
+QtObject {
+ JUST_SOME_INVALID_PROPERTY: 0
+}
diff --git a/tests/auto/qml/qqmlapplicationengine/tst_qqmlapplicationengine.cpp b/tests/auto/qml/qqmlapplicationengine/tst_qqmlapplicationengine.cpp
index 0f5eea8b95..5e855efe1a 100644
--- a/tests/auto/qml/qqmlapplicationengine/tst_qqmlapplicationengine.cpp
+++ b/tests/auto/qml/qqmlapplicationengine/tst_qqmlapplicationengine.cpp
@@ -30,6 +30,7 @@
#include <QQmlApplicationEngine>
#include <QScopedPointer>
#include <QSignalSpy>
+#include <QRegularExpression>
#if QT_CONFIG(process)
#include <QProcess>
#endif
@@ -53,6 +54,7 @@ private slots:
void loadTranslation_data();
void loadTranslation();
void setInitialProperties();
+ void failureToLoadTriggersWarningSignal();
private:
QString buildDir;
@@ -293,6 +295,20 @@ void tst_qqmlapplicationengine::setInitialProperties()
}
}
+Q_DECLARE_METATYPE(QList<QQmlError>) // for signalspy below
+
+void tst_qqmlapplicationengine::failureToLoadTriggersWarningSignal()
+{
+ auto url = testFileUrl("invalid.qml");
+ qRegisterMetaType<QList<QQmlError>>();
+ QTest::ignoreMessage(QtMsgType::QtWarningMsg, "QQmlApplicationEngine failed to load component");
+ QTest::ignoreMessage(QtMsgType::QtWarningMsg, QRegularExpression(url.toString() + QLatin1Char('*')));
+ QQmlApplicationEngine test;
+ QSignalSpy warningObserver(&test, &QQmlApplicationEngine::warnings);
+ test.load(url);
+ QTRY_COMPARE(warningObserver.count(), 1);
+}
+
QTEST_MAIN(tst_qqmlapplicationengine)
#include "tst_qqmlapplicationengine.moc"
diff --git a/tests/auto/qml/qqmlecmascript/tst_qqmlecmascript.cpp b/tests/auto/qml/qqmlecmascript/tst_qqmlecmascript.cpp
index 46297b3c16..ec0db16114 100644
--- a/tests/auto/qml/qqmlecmascript/tst_qqmlecmascript.cpp
+++ b/tests/auto/qml/qqmlecmascript/tst_qqmlecmascript.cpp
@@ -381,6 +381,8 @@ private slots:
void semicolonAfterProperty();
void hugeStack();
+ void gcCrashRegressionTest();
+
private:
// static void propertyVarWeakRefCallback(v8::Persistent<v8::Value> object, void* parameter);
static void verifyContextLifetime(QQmlContextData *ctxt);
@@ -9213,6 +9215,53 @@ void tst_qqmlecmascript::hugeStack()
QCOMPARE(qvariant_cast<QJSValue>(huge).property(QLatin1String("length")).toInt(), 33059);
}
+void tst_qqmlecmascript::gcCrashRegressionTest()
+{
+ const QString qmljs = QLibraryInfo::location(QLibraryInfo::BinariesPath) + "/qmljs";
+ if (!QFile::exists(qmljs)) {
+ QSKIP("Tets requires qmljs");
+ }
+ QProcess process;
+
+ QTemporaryFile infile;
+ QVERIFY(infile.open());
+ infile.write(R"js(
+ function i_want_to_break_free() {
+ var n = 400;
+ var m = 10;
+ var regex = new RegExp("(ab)".repeat(n), "g"); // g flag to trigger the vulnerable path
+ var part = "ab".repeat(n); // matches have to be at least size 2 to prevent interning
+ var s = (part + "|").repeat(m);
+ var cnt = 0;
+ var ary = [];
+ s.replace(regex, function() {
+ for (var i = 1; i < arguments.length-2; ++i) {
+ if (typeof arguments[i] !== 'string') {
+ i_am_free = arguments[i];
+ throw "success";
+ }
+ ary[cnt++] = arguments[i]; // root everything to force GC
+ }
+ return "x";
+ });
+ }
+ try { i_want_to_break_free(); } catch (e) {console.log("hi") }
+ console.log(typeof(i_am_free)); // will print "object"
+ )js");
+ infile.close();
+
+ QProcessEnvironment environment = QProcessEnvironment::systemEnvironment();
+ environment.insert("QV4_GC_MAX_STACK_SIZE", "32768");
+
+ process.setProcessEnvironment(environment);
+ process.start(qmljs, QStringList({infile.fileName()}));
+ QVERIFY(process.waitForStarted());
+ const qint64 pid = process.processId();
+ QVERIFY(pid != 0);
+ QVERIFY(process.waitForFinished());
+ QCOMPARE(process.exitCode(), 0);
+}
+
QTEST_MAIN(tst_qqmlecmascript)
#include "tst_qqmlecmascript.moc"
diff --git a/tests/auto/qml/qquickworkerscript/data/doRequest.mjs b/tests/auto/qml/qquickworkerscript/data/doRequest.mjs
new file mode 100644
index 0000000000..d607c3400d
--- /dev/null
+++ b/tests/auto/qml/qquickworkerscript/data/doRequest.mjs
@@ -0,0 +1,6 @@
+WorkerScript.onMessage = function(message)
+{
+ var req = new XMLHttpRequest();
+ req.open("GET", message.url, true);
+ req.send();
+};
diff --git a/tests/auto/qml/qquickworkerscript/data/xmlHttpRequest.qml b/tests/auto/qml/qquickworkerscript/data/xmlHttpRequest.qml
new file mode 100644
index 0000000000..42136d78f0
--- /dev/null
+++ b/tests/auto/qml/qquickworkerscript/data/xmlHttpRequest.qml
@@ -0,0 +1,16 @@
+import QtQuick 2.14
+
+Rectangle
+{
+ width: 100
+ height: 100
+
+ WorkerScript
+ {
+ source: "doRequest.mjs"
+ Component.onCompleted:
+ {
+ sendMessage({"url": "https://example.com"});
+ }
+ }
+}
diff --git a/tests/auto/qml/qquickworkerscript/tst_qquickworkerscript.cpp b/tests/auto/qml/qquickworkerscript/tst_qquickworkerscript.cpp
index bb4c9a7c1e..2f79f7157f 100644
--- a/tests/auto/qml/qquickworkerscript/tst_qquickworkerscript.cpp
+++ b/tests/auto/qml/qquickworkerscript/tst_qquickworkerscript.cpp
@@ -60,6 +60,7 @@ private slots:
void script_function();
void script_var();
void stressDispose();
+ void xmlHttpRequest();
private:
void waitForEchoMessage(QQuickWorkerScript *worker) {
@@ -359,6 +360,13 @@ void tst_QQuickWorkerScript::stressDispose()
}
}
+void tst_QQuickWorkerScript::xmlHttpRequest()
+{
+ QQmlComponent component(&m_engine, testFileUrl("xmlHttpRequest.qml"));
+ QScopedPointer<QObject> root{component.create()}; // should not crash
+ QVERIFY(root);
+}
+
QTEST_MAIN(tst_QQuickWorkerScript)
#include "tst_qquickworkerscript.moc"