From b6e78b38367a23f0b053bbd2abe4ef161e4053b9 Mon Sep 17 00:00:00 2001 From: Chris Adams Date: Mon, 6 Feb 2012 14:24:42 +1000 Subject: Improve support for var properties This commit changes the semantics of function assignment in QML. Previously, function assignment was interpreted as binding assignment. Now, function assignment is interpreted as function assignment, and therefore fails for all property types other than "var" properties. To support imperative binding assignment, a new function was added to the Qt object: Qt.binding(function) which takes a single function parameter and returns a function object which will be interpreted as an assignable binding expression by the QML engine. Finally, this commit also slightly changes the semantics of var properties in that the "special" JavaScript values of null and undefined may be assigned to var properties, rather than being interpreted as reset requests. Task-number: QTBUG-21842 Change-Id: Iee99a878b9badf0fb76e983da7ebfa493f55ceb5 Reviewed-by: Matthew Vogt --- .../qqmlcomponent/data/createObjectWithScript.qml | 4 +-- .../qqmlecmascript/data/functionAssignment.1.qml | 2 ++ .../qqmlecmascript/data/functionAssignment.2.qml | 14 +++++----- .../qqmlecmascript/data/functionAssignment.3.qml | 18 +++++++++++++ .../qml/qqmlecmascript/data/functionAssignment.js | 4 +-- .../qml/qqmlecmascript/data/propertyVar.11.qml | 21 +++++++++++++++ .../qml/qqmlecmascript/data/propertyVar.12.qml | 19 ++++++++++++++ .../qml/qqmlecmascript/data/propertyVar.13.qml | 19 ++++++++++++++ .../qml/qqmlecmascript/data/propertyVar.14.qml | 21 +++++++++++++++ .../qml/qqmlecmascript/data/propertyVar.15.qml | 20 +++++++++++++++ .../auto/qml/qqmlecmascript/tst_qqmlecmascript.cpp | 30 ++++++++++++++++++++-- .../qqmlvaluetypes/data/bindingAssignment.2.qml | 12 +++++++++ .../qml/qqmlvaluetypes/data/bindingAssignment.qml | 5 ++++ .../auto/qml/qqmlvaluetypes/tst_qqmlvaluetypes.cpp | 20 +++++++++++++++ .../data/initialPropertyValues.binding.qml | 2 +- 15 files changed, 197 insertions(+), 14 deletions(-) create mode 100644 tests/auto/qml/qqmlecmascript/data/functionAssignment.3.qml create mode 100644 tests/auto/qml/qqmlecmascript/data/propertyVar.11.qml create mode 100644 tests/auto/qml/qqmlecmascript/data/propertyVar.12.qml create mode 100644 tests/auto/qml/qqmlecmascript/data/propertyVar.13.qml create mode 100644 tests/auto/qml/qqmlecmascript/data/propertyVar.14.qml create mode 100644 tests/auto/qml/qqmlecmascript/data/propertyVar.15.qml create mode 100644 tests/auto/qml/qqmlvaluetypes/data/bindingAssignment.2.qml (limited to 'tests/auto') diff --git a/tests/auto/qml/qqmlcomponent/data/createObjectWithScript.qml b/tests/auto/qml/qqmlcomponent/data/createObjectWithScript.qml index 122c6a87c8..989b295cb5 100644 --- a/tests/auto/qml/qqmlcomponent/data/createObjectWithScript.qml +++ b/tests/auto/qml/qqmlcomponent/data/createObjectWithScript.qml @@ -37,7 +37,7 @@ Item{ root.declarativerectangle = a.createObject(root, {"x":17,"y":17, "color":"white", "border.width":3, "innerRect.border.width": 20}); root.declarativeitem = b.createObject(root, {"x":17,"y":17,"testBool":true,"testInt":17,"testObject":root}); - root.bindingTestObject = c.createObject(root, {'testValue': (function(){return width * 3}) }) // use root.width - root.bindingThisTestObject = c.createObject(root, {'testValue': (function(){return this.width * 3}) }) // use width of Item within 'c' + root.bindingTestObject = c.createObject(root, {'testValue': Qt.binding(function(){return width * 3}) }) // use root.width + root.bindingThisTestObject = c.createObject(root, {'testValue': Qt.binding(function(){return this.width * 3}) }) // use width of Item within 'c' } } diff --git a/tests/auto/qml/qqmlecmascript/data/functionAssignment.1.qml b/tests/auto/qml/qqmlecmascript/data/functionAssignment.1.qml index 09540f1f6e..0b1b45b41b 100644 --- a/tests/auto/qml/qqmlecmascript/data/functionAssignment.1.qml +++ b/tests/auto/qml/qqmlecmascript/data/functionAssignment.1.qml @@ -2,4 +2,6 @@ import Qt.test 1.0 MyQmlObject { property variant a: function myFunction() { return 2; } + property variant b: Qt.binding(function() { return 2; }) + property var c: Qt.binding(function() { return 2; }) } diff --git a/tests/auto/qml/qqmlecmascript/data/functionAssignment.2.qml b/tests/auto/qml/qqmlecmascript/data/functionAssignment.2.qml index 0f78eaf1dc..3d8fd85a88 100644 --- a/tests/auto/qml/qqmlecmascript/data/functionAssignment.2.qml +++ b/tests/auto/qml/qqmlecmascript/data/functionAssignment.2.qml @@ -24,7 +24,7 @@ MyQmlObject { function myFunction() { return aNumber * 10; } - a = myFunction; + a = Qt.binding(myFunction); } property QtObject obj: QtObject { @@ -34,7 +34,7 @@ MyQmlObject { } } onAssignWithThisChanged: { - a = obj.myFunction; + a = Qt.binding(obj.myFunction); } onAssignToPropertyFromJsFileChanged: { @@ -47,8 +47,8 @@ MyQmlObject { property Text text: Text { } onAssignToValueTypeChanged: { - text.font.pixelSize = (function() { return aNumber * 10; }) - a = (function() { return text.font.pixelSize; }) + text.font.pixelSize = Qt.binding(function() { return aNumber * 10; }) + a = Qt.binding(function() { return text.font.pixelSize; }) } @@ -57,17 +57,17 @@ MyQmlObject { onAssignFuncWithoutReturnChanged: { function myFunction() { } - a = myFunction; + a = Qt.binding(myFunction); } onAssignWrongTypeChanged: { function myFunction() { return 'a string'; } - aNumber = myFunction; + aNumber = Qt.binding(myFunction); } onAssignWrongTypeToValueTypeChanged: { - text.font.pixelSize = (function() { return 'a string'; }) + text.font.pixelSize = Qt.binding(function() { return 'a string'; }) } } diff --git a/tests/auto/qml/qqmlecmascript/data/functionAssignment.3.qml b/tests/auto/qml/qqmlecmascript/data/functionAssignment.3.qml new file mode 100644 index 0000000000..c34a868949 --- /dev/null +++ b/tests/auto/qml/qqmlecmascript/data/functionAssignment.3.qml @@ -0,0 +1,18 @@ +import QtQuick 2.0 + +Item { + property int t1: 1 + property int t2: 2 + + function randomNumber() { + return 4; + } + + Component.onCompleted: { + // shouldn't "convert" the randomNumber function into a binding permanently + t1 = Qt.binding(randomNumber) + + // therefore, the following assignment should fail. + t2 = randomNumber + } +} diff --git a/tests/auto/qml/qqmlecmascript/data/functionAssignment.js b/tests/auto/qml/qqmlecmascript/data/functionAssignment.js index 14daa7629f..3ba4e193e6 100644 --- a/tests/auto/qml/qqmlecmascript/data/functionAssignment.js +++ b/tests/auto/qml/qqmlecmascript/data/functionAssignment.js @@ -1,6 +1,6 @@ function bindProperty() { - a = (function(){ return aNumber * 10 }) + a = Qt.binding(function(){ return aNumber * 10 }) } @@ -13,5 +13,5 @@ var testObj = new TestObject() function bindPropertyWithThis() { - a = testObj.bindFunction + a = Qt.binding(testObj.bindFunction) } diff --git a/tests/auto/qml/qqmlecmascript/data/propertyVar.11.qml b/tests/auto/qml/qqmlecmascript/data/propertyVar.11.qml new file mode 100644 index 0000000000..63be26717e --- /dev/null +++ b/tests/auto/qml/qqmlecmascript/data/propertyVar.11.qml @@ -0,0 +1,21 @@ +import QtQuick 2.0 + +Item { + property bool test: false + property var fnResult: testFunction(5) + property var f1: testFunction + property var f2 + + function testFunction(x) { + return x; + } + + Component.onCompleted: { + f2 = testFunction; + if (fnResult != 5) return; + if (f1(6) != 6) return; + if (f2(7) != 7) return; + if (f1 != f2) return; + test = true; + } +} diff --git a/tests/auto/qml/qqmlecmascript/data/propertyVar.12.qml b/tests/auto/qml/qqmlecmascript/data/propertyVar.12.qml new file mode 100644 index 0000000000..3510bd2350 --- /dev/null +++ b/tests/auto/qml/qqmlecmascript/data/propertyVar.12.qml @@ -0,0 +1,19 @@ +import QtQuick 2.0 + +Item { + property bool test: false + property var nullOne: null + property var nullTwo + property var undefOne: undefined + property var undefTwo + + Component.onCompleted: { + nullTwo = null; + undefTwo = undefined; + if (nullOne != null) return; + if (nullOne != nullTwo) return; + if (undefOne != undefined) return; + if (undefOne != undefTwo) return; + test = true; + } +} diff --git a/tests/auto/qml/qqmlecmascript/data/propertyVar.13.qml b/tests/auto/qml/qqmlecmascript/data/propertyVar.13.qml new file mode 100644 index 0000000000..14c7c677ae --- /dev/null +++ b/tests/auto/qml/qqmlecmascript/data/propertyVar.13.qml @@ -0,0 +1,19 @@ +import QtQuick 2.0 + +Item { + property bool test: false + property var f: b + 12 + property int a: 100 + property int b: testFunction() + + function testFunction() { + return a * 3; + } + + Component.onCompleted: { + if (f != 312) return; + a = 120; + if (f != 372) return; + test = true; + } +} diff --git a/tests/auto/qml/qqmlecmascript/data/propertyVar.14.qml b/tests/auto/qml/qqmlecmascript/data/propertyVar.14.qml new file mode 100644 index 0000000000..a1e26661bb --- /dev/null +++ b/tests/auto/qml/qqmlecmascript/data/propertyVar.14.qml @@ -0,0 +1,21 @@ +import QtQuick 2.0 + +Item { + property bool test: false + property var f + property int a: 100 + property int b + + function testFunction() { + return a * 3; + } + + Component.onCompleted: { + b = Qt.binding(testFunction); + f = Qt.binding(function() { return b + 12; }); + if (f != 312) return; + a = 120; + if (f != 372) return; + test = true; + } +} diff --git a/tests/auto/qml/qqmlecmascript/data/propertyVar.15.qml b/tests/auto/qml/qqmlecmascript/data/propertyVar.15.qml new file mode 100644 index 0000000000..5e5071fc2d --- /dev/null +++ b/tests/auto/qml/qqmlecmascript/data/propertyVar.15.qml @@ -0,0 +1,20 @@ +import QtQuick 2.0 + +Item { + property bool test: false + property var storedBinding: [ Qt.binding(function() { return testFunction() + 12; }) ] + property int a: 100 + property int b + + function testFunction() { + return a * 3; + } + + Component.onCompleted: { + b = storedBinding[0]; + if (b != 312) return; + a = 120; + if (b != 372) return; + test = true; + } +} diff --git a/tests/auto/qml/qqmlecmascript/tst_qqmlecmascript.cpp b/tests/auto/qml/qqmlecmascript/tst_qqmlecmascript.cpp index 676557a81c..9c8d1e750b 100644 --- a/tests/auto/qml/qqmlecmascript/tst_qqmlecmascript.cpp +++ b/tests/auto/qml/qqmlecmascript/tst_qqmlecmascript.cpp @@ -195,6 +195,7 @@ private slots: void functionAssignment_fromJS(); void functionAssignment_fromJS_data(); void functionAssignmentfromJS_invalid(); + void functionAssignment_afterBinding(); void eval(); void function(); void functionException(); @@ -3768,6 +3769,11 @@ void tst_qqmlecmascript::propertyVar_data() QTest::newRow("literal property assignment") << testFileUrl("propertyVar.8.qml"); QTest::newRow("qobject property assignment") << testFileUrl("propertyVar.9.qml"); QTest::newRow("base class var property assignment") << testFileUrl("propertyVar.10.qml"); + QTest::newRow("javascript function assignment") << testFileUrl("propertyVar.11.qml"); + QTest::newRow("javascript special assignment") << testFileUrl("propertyVar.12.qml"); + QTest::newRow("declarative binding assignment") << testFileUrl("propertyVar.13.qml"); + QTest::newRow("imperative binding assignment") << testFileUrl("propertyVar.14.qml"); + QTest::newRow("stored binding assignment") << testFileUrl("propertyVar.15.qml"); } void tst_qqmlecmascript::propertyVar() @@ -5025,8 +5031,12 @@ void tst_qqmlecmascript::functionAssignment_fromBinding() QQmlComponent component(&engine, testFileUrl("functionAssignment.1.qml")); QString url = component.url().toString(); - QString warning = url + ":4: Unable to assign a function to a property."; - QTest::ignoreMessage(QtWarningMsg, warning.toLatin1().constData()); + QString w1 = url + ":4: Unable to assign a function to a property of any type other than var."; + QString w2 = url + ":5: Invalid use of Qt.binding() in a binding declaration."; + QString w3 = url + ":6: Invalid use of Qt.binding() in a binding declaration."; + QTest::ignoreMessage(QtWarningMsg, w1.toLatin1().constData()); + QTest::ignoreMessage(QtWarningMsg, w2.toLatin1().constData()); + QTest::ignoreMessage(QtWarningMsg, w3.toLatin1().constData()); MyQmlObject *o = qobject_cast(component.create()); QVERIFY(o != 0); @@ -5094,6 +5104,22 @@ void tst_qqmlecmascript::functionAssignmentfromJS_invalid() delete o; } +void tst_qqmlecmascript::functionAssignment_afterBinding() +{ + QQmlComponent component(&engine, testFileUrl("functionAssignment.3.qml")); + + QString url = component.url().toString(); + QString w1 = url + ":16: Error: Cannot assign JavaScript function to int"; + QTest::ignoreMessage(QtWarningMsg, w1.toLatin1().constData()); + + QObject *o = component.create(); + QVERIFY(o != 0); + QCOMPARE(o->property("t1"), QVariant::fromValue(4)); // should have bound + QCOMPARE(o->property("t2"), QVariant::fromValue(2)); // should not have changed + + delete o; +} + void tst_qqmlecmascript::eval() { QQmlComponent component(&engine, testFileUrl("eval.qml")); diff --git a/tests/auto/qml/qqmlvaluetypes/data/bindingAssignment.2.qml b/tests/auto/qml/qqmlvaluetypes/data/bindingAssignment.2.qml new file mode 100644 index 0000000000..0da717ba5c --- /dev/null +++ b/tests/auto/qml/qqmlvaluetypes/data/bindingAssignment.2.qml @@ -0,0 +1,12 @@ +import QtQuick 2.0 +import Test 1.0 + +MyTypeObject { + property int value: 10 + rect.y: Qt.binding(function() { return value; }); // error. + + Component.onCompleted: { + rect.x = 5; + rect.x = (function() { return value; }); // error. + } +} diff --git a/tests/auto/qml/qqmlvaluetypes/data/bindingAssignment.qml b/tests/auto/qml/qqmlvaluetypes/data/bindingAssignment.qml index a65218669b..9b10803649 100644 --- a/tests/auto/qml/qqmlvaluetypes/data/bindingAssignment.qml +++ b/tests/auto/qml/qqmlvaluetypes/data/bindingAssignment.qml @@ -1,7 +1,12 @@ +import QtQuick 2.0 import Test 1.0 MyTypeObject { property int value: 10 rect.x: value + + Component.onCompleted: { + rect.y = Qt.binding(function() { return value + 5; }); + } } diff --git a/tests/auto/qml/qqmlvaluetypes/tst_qqmlvaluetypes.cpp b/tests/auto/qml/qqmlvaluetypes/tst_qqmlvaluetypes.cpp index 0aa223e733..c37a42fee5 100644 --- a/tests/auto/qml/qqmlvaluetypes/tst_qqmlvaluetypes.cpp +++ b/tests/auto/qml/qqmlvaluetypes/tst_qqmlvaluetypes.cpp @@ -871,17 +871,37 @@ void tst_qqmlvaluetypes::color() // Test bindings can write to value types void tst_qqmlvaluetypes::bindingAssignment() { + // binding declaration + { QQmlComponent component(&engine, testFileUrl("bindingAssignment.qml")); MyTypeObject *object = qobject_cast(component.create()); QVERIFY(object != 0); QCOMPARE(object->rect().x(), 10); + QCOMPARE(object->rect().y(), 15); object->setProperty("value", QVariant(92)); QCOMPARE(object->rect().x(), 92); + QCOMPARE(object->rect().y(), 97); delete object; + } + + // function assignment should fail without crashing + { + QString warning1 = testFileUrl("bindingAssignment.2.qml").toString() + QLatin1String(":6: Invalid use of Qt.binding() in a binding declaration."); + QString warning2 = testFileUrl("bindingAssignment.2.qml").toString() + QLatin1String(":10: Error: Cannot assign JavaScript function to value-type property"); + QTest::ignoreMessage(QtWarningMsg, qPrintable(warning1)); + QTest::ignoreMessage(QtWarningMsg, qPrintable(warning2)); + QQmlComponent component(&engine, testFileUrl("bindingAssignment.2.qml")); + MyTypeObject *object = qobject_cast(component.create()); + QVERIFY(object != 0); + QCOMPARE(object->rect().x(), 5); + object->setProperty("value", QVariant(92)); + QCOMPARE(object->rect().x(), 5); + delete object; + } } // Test bindings can read from value types diff --git a/tests/auto/quick/qquickloader/data/initialPropertyValues.binding.qml b/tests/auto/quick/qquickloader/data/initialPropertyValues.binding.qml index e0df50a74a..2ee60b0b50 100644 --- a/tests/auto/quick/qquickloader/data/initialPropertyValues.binding.qml +++ b/tests/auto/quick/qquickloader/data/initialPropertyValues.binding.qml @@ -16,6 +16,6 @@ Item { } Component.onCompleted: { - loader.setSource("InitialPropertyValuesComponent.qml", {"canary": (function() { return root.bindable })}); + loader.setSource("InitialPropertyValuesComponent.qml", {"canary": Qt.binding(function() { return root.bindable })}); } } -- cgit v1.2.3 From 92b1f9981d225ecee28da1f0a88fb3046000cb5e Mon Sep 17 00:00:00 2001 From: Chris Adams Date: Mon, 27 Feb 2012 10:51:57 +1000 Subject: Allow function assignment to cause binding for non-var props This patch maintains the old function-assignment behaviour for non-var properties, and will be reverted soon. Change-Id: I523e464501106616c51ff7478f7eb7171c1ca350 Reviewed-by: Matthew Vogt --- tests/auto/qml/qqmlecmascript/tst_qqmlecmascript.cpp | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) (limited to 'tests/auto') diff --git a/tests/auto/qml/qqmlecmascript/tst_qqmlecmascript.cpp b/tests/auto/qml/qqmlecmascript/tst_qqmlecmascript.cpp index 9c8d1e750b..45406390de 100644 --- a/tests/auto/qml/qqmlecmascript/tst_qqmlecmascript.cpp +++ b/tests/auto/qml/qqmlecmascript/tst_qqmlecmascript.cpp @@ -5109,13 +5109,15 @@ void tst_qqmlecmascript::functionAssignment_afterBinding() QQmlComponent component(&engine, testFileUrl("functionAssignment.3.qml")); QString url = component.url().toString(); - QString w1 = url + ":16: Error: Cannot assign JavaScript function to int"; + //QString w1 = url + ":16: Error: Cannot assign JavaScript function to int"; // for now, function assignment = binding assignment + QString w1 = QLatin1String("WARNING: function assignment is DEPRECATED and will be removed! Wrap RHS in Qt.binding(): ") + url + QLatin1String(":16"); QTest::ignoreMessage(QtWarningMsg, w1.toLatin1().constData()); QObject *o = component.create(); QVERIFY(o != 0); QCOMPARE(o->property("t1"), QVariant::fromValue(4)); // should have bound - QCOMPARE(o->property("t2"), QVariant::fromValue(2)); // should not have changed + //QCOMPARE(o->property("t2"), QVariant::fromValue(2)); // should not have changed + QCOMPARE(o->property("t2"), QVariant::fromValue(4)); // for now, function assignment = binding assignment delete o; } -- cgit v1.2.3 From 3bc907d155034fe64efc8cb6056b48f0c6401bfb Mon Sep 17 00:00:00 2001 From: Matthew Vogt Date: Mon, 5 Mar 2012 17:01:33 +1000 Subject: Remove uses of QtGui symbols in QQmlEngine. Move the code dealing with QImage and QPixmap out of QQmlEngine and into the QtQuick library. QQmlEngine remains the owner of image provider resources, but does not use them directly. Change-Id: I52083581394d9c308db446372883eb7479ccf807 Reviewed-by: Martin Jones --- tests/auto/qml/qml.pro | 1 - .../qml/qqmlimageprovider/qqmlimageprovider.pro | 9 - .../qqmlimageprovider/tst_qqmlimageprovider.cpp | 424 --------------------- .../qquickimageprovider/qquickimageprovider.pro | 9 + .../tst_qquickimageprovider.cpp | 424 +++++++++++++++++++++ .../qquickpixmapcache/tst_qquickpixmapcache.cpp | 6 +- tests/auto/quick/quick.pro | 1 + 7 files changed, 437 insertions(+), 437 deletions(-) delete mode 100644 tests/auto/qml/qqmlimageprovider/qqmlimageprovider.pro delete mode 100644 tests/auto/qml/qqmlimageprovider/tst_qqmlimageprovider.cpp create mode 100644 tests/auto/quick/qquickimageprovider/qquickimageprovider.pro create mode 100644 tests/auto/quick/qquickimageprovider/tst_qquickimageprovider.cpp (limited to 'tests/auto') diff --git a/tests/auto/qml/qml.pro b/tests/auto/qml/qml.pro index bcfbcbdbf0..d58a29066d 100644 --- a/tests/auto/qml/qml.pro +++ b/tests/auto/qml/qml.pro @@ -32,7 +32,6 @@ PRIVATETESTS += \ qqmlcpputils \ qqmlecmascript \ qqmlexpression \ - qqmlimageprovider \ qqmlinstruction \ qqmllanguage \ qqmlproperty \ diff --git a/tests/auto/qml/qqmlimageprovider/qqmlimageprovider.pro b/tests/auto/qml/qqmlimageprovider/qqmlimageprovider.pro deleted file mode 100644 index 9feeee15fd..0000000000 --- a/tests/auto/qml/qqmlimageprovider/qqmlimageprovider.pro +++ /dev/null @@ -1,9 +0,0 @@ -CONFIG += testcase -TARGET = tst_qqmlimageprovider -macx:CONFIG -= app_bundle - -SOURCES += tst_qqmlimageprovider.cpp - -CONFIG += parallel_test - -QT += core-private gui-private qml-private quick-private network testlib diff --git a/tests/auto/qml/qqmlimageprovider/tst_qqmlimageprovider.cpp b/tests/auto/qml/qqmlimageprovider/tst_qqmlimageprovider.cpp deleted file mode 100644 index bc53544566..0000000000 --- a/tests/auto/qml/qqmlimageprovider/tst_qqmlimageprovider.cpp +++ /dev/null @@ -1,424 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies). -** Contact: http://www.qt-project.org/ -** -** This file is part of the test suite of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL$ -** GNU Lesser General Public License Usage -** 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, Nokia gives you certain additional -** rights. These rights are described in the Nokia 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. -** -** Other Usage -** Alternatively, this file may be used in accordance with the terms and -** conditions contained in a signed written agreement between you and Nokia. -** -** -** -** -** -** -** $QT_END_LICENSE$ -** -****************************************************************************/ -#include -#include -#include -#include -#include -#include -#include - -Q_DECLARE_METATYPE(QQmlImageProvider*); - -class tst_qqmlimageprovider : public QObject -{ - Q_OBJECT -public: - tst_qqmlimageprovider() - { - } - -private slots: - void requestImage_sync_data(); - void requestImage_sync(); - void requestImage_async_data(); - void requestImage_async(); - - void requestPixmap_sync_data(); - void requestPixmap_sync(); - void requestPixmap_async(); - - void removeProvider_data(); - void removeProvider(); - - void threadTest(); - -private: - QString newImageFileName() const; - void fillRequestTestsData(const QString &id); - void runTest(bool async, QQmlImageProvider *provider); -}; - - -class TestQImageProvider : public QQmlImageProvider -{ -public: - TestQImageProvider(bool *deleteWatch = 0) - : QQmlImageProvider(Image), deleteWatch(deleteWatch) - { - } - - ~TestQImageProvider() - { - if (deleteWatch) - *deleteWatch = true; - } - - QImage requestImage(const QString &id, QSize *size, const QSize& requestedSize) - { - lastImageId = id; - - if (id == QLatin1String("no-such-file.png")) - return QImage(); - - int width = 100; - int height = 100; - QImage image(width, height, QImage::Format_RGB32); - if (size) - *size = QSize(width, height); - if (requestedSize.isValid()) - image = image.scaled(requestedSize); - return image; - } - - bool *deleteWatch; - QString lastImageId; -}; -Q_DECLARE_METATYPE(TestQImageProvider*); - - -class TestQPixmapProvider : public QQmlImageProvider -{ -public: - TestQPixmapProvider(bool *deleteWatch = 0) - : QQmlImageProvider(Pixmap), deleteWatch(deleteWatch) - { - } - - ~TestQPixmapProvider() - { - if (deleteWatch) - *deleteWatch = true; - } - - QPixmap requestPixmap(const QString &id, QSize *size, const QSize& requestedSize) - { - lastImageId = id; - - if (id == QLatin1String("no-such-file.png")) - return QPixmap(); - - int width = 100; - int height = 100; - QPixmap image(width, height); - if (size) - *size = QSize(width, height); - if (requestedSize.isValid()) - image = image.scaled(requestedSize); - return image; - } - - bool *deleteWatch; - QString lastImageId; -}; -Q_DECLARE_METATYPE(TestQPixmapProvider*); - - -QString tst_qqmlimageprovider::newImageFileName() const -{ - // need to generate new filenames each time or else images are loaded - // from cache and we won't get loading status changes when testing - // async loading - static int count = 0; - return QString("image://test/image-%1.png").arg(count++); -} - -void tst_qqmlimageprovider::fillRequestTestsData(const QString &id) -{ - QTest::addColumn("source"); - QTest::addColumn("imageId"); - QTest::addColumn("properties"); - QTest::addColumn("size"); - QTest::addColumn("error"); - - QString fileName = newImageFileName(); - QTest::newRow(QTest::toString(id + " simple test")) - << "image://test/" + fileName << fileName << "" << QSize(100,100) << ""; - - fileName = newImageFileName(); - QTest::newRow(QTest::toString(id + " simple test with capitalization"))//As it's a URL, should make no difference - << "image://Test/" + fileName << fileName << "" << QSize(100,100) << ""; - - fileName = newImageFileName(); - QTest::newRow(QTest::toString(id + " url with no id")) - << "image://test/" + fileName << "" + fileName << "" << QSize(100,100) << ""; - - fileName = newImageFileName(); - QTest::newRow(QTest::toString(id + " url with path")) - << "image://test/test/path" + fileName << "test/path" + fileName << "" << QSize(100,100) << ""; - - fileName = newImageFileName(); - QTest::newRow(QTest::toString(id + " url with fragment")) - << "image://test/faq.html?#question13" + fileName << "faq.html?#question13" + fileName << "" << QSize(100,100) << ""; - - fileName = newImageFileName(); - QTest::newRow(QTest::toString(id + " url with query")) - << "image://test/cgi-bin/drawgraph.cgi?type=pie&color=green" + fileName << "cgi-bin/drawgraph.cgi?type=pie&color=green" + fileName - << "" << QSize(100,100) << ""; - - fileName = newImageFileName(); - QTest::newRow(QTest::toString(id + " scaled image")) - << "image://test/" + fileName << fileName << "sourceSize: \"80x30\"" << QSize(80,30) << ""; - - 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"; - - QTest::newRow(QTest::toString(id + " unknown provider")) - << "image://bogus/exists.png" << "" << "" << QSize() - << "file::2:1: QML Image: Invalid image provider: image://bogus/exists.png"; -} - -void tst_qqmlimageprovider::runTest(bool async, QQmlImageProvider *provider) -{ - QFETCH(QString, source); - QFETCH(QString, imageId); - QFETCH(QString, properties); - QFETCH(QSize, size); - QFETCH(QString, error); - - if (!error.isEmpty()) - QTest::ignoreMessage(QtWarningMsg, error.toUtf8()); - - QQmlEngine engine; - - engine.addImageProvider("test", provider); - QVERIFY(engine.imageProvider("test") != 0); - - QString componentStr = "import QtQuick 2.0\nImage { source: \"" + source + "\"; " - + (async ? "asynchronous: true; " : "") - + properties + " }"; - QQmlComponent component(&engine); - component.setData(componentStr.toLatin1(), QUrl::fromLocalFile("")); - QQuickImage *obj = qobject_cast(component.create()); - QVERIFY(obj != 0); - - if (async) - QTRY_VERIFY(obj->status() == QQuickImage::Loading); - - QCOMPARE(obj->source(), QUrl(source)); - - if (error.isEmpty()) { - if (async) - QTRY_VERIFY(obj->status() == QQuickImage::Ready); - else - QVERIFY(obj->status() == QQuickImage::Ready); - if (QByteArray(QTest::currentDataTag()).startsWith("qimage")) - QCOMPARE(static_cast(provider)->lastImageId, imageId); - else - QCOMPARE(static_cast(provider)->lastImageId, imageId); - - QCOMPARE(obj->width(), qreal(size.width())); - QCOMPARE(obj->height(), qreal(size.height())); - QCOMPARE(obj->fillMode(), QQuickImage::Stretch); - QCOMPARE(obj->progress(), 1.0); - } else { - if (async) - QTRY_VERIFY(obj->status() == QQuickImage::Error); - else - QVERIFY(obj->status() == QQuickImage::Error); - } - - delete obj; -} - -void tst_qqmlimageprovider::requestImage_sync_data() -{ - fillRequestTestsData("qimage|sync"); -} - -void tst_qqmlimageprovider::requestImage_sync() -{ - bool deleteWatch = false; - runTest(false, new TestQImageProvider(&deleteWatch)); - QVERIFY(deleteWatch); -} - -void tst_qqmlimageprovider::requestImage_async_data() -{ - fillRequestTestsData("qimage|async"); -} - -void tst_qqmlimageprovider::requestImage_async() -{ - bool deleteWatch = false; - runTest(true, new TestQImageProvider(&deleteWatch)); - QVERIFY(deleteWatch); -} - -void tst_qqmlimageprovider::requestPixmap_sync_data() -{ - fillRequestTestsData("qpixmap"); -} - -void tst_qqmlimageprovider::requestPixmap_sync() -{ - bool deleteWatch = false; - runTest(false, new TestQPixmapProvider(&deleteWatch)); - QVERIFY(deleteWatch); -} - -void tst_qqmlimageprovider::requestPixmap_async() -{ - QQmlEngine engine; - QQmlImageProvider *provider = new TestQPixmapProvider(); - - engine.addImageProvider("test", provider); - QVERIFY(engine.imageProvider("test") != 0); - - // pixmaps are loaded synchronously regardless of 'asynchronous' value - QString componentStr = "import QtQuick 2.0\nImage { asynchronous: true; source: \"image://test/pixmap-async-test.png\" }"; - QQmlComponent component(&engine); - component.setData(componentStr.toLatin1(), QUrl::fromLocalFile("")); - QQuickImage *obj = qobject_cast(component.create()); - QVERIFY(obj != 0); - - delete obj; -} - -void tst_qqmlimageprovider::removeProvider_data() -{ - QTest::addColumn("provider"); - - QTest::newRow("qimage") << static_cast(new TestQImageProvider); - QTest::newRow("qpixmap") << static_cast(new TestQPixmapProvider); -} - -void tst_qqmlimageprovider::removeProvider() -{ - QFETCH(QQmlImageProvider*, provider); - - QQmlEngine engine; - - engine.addImageProvider("test", provider); - QVERIFY(engine.imageProvider("test") != 0); - - // add provider, confirm it works - QString componentStr = "import QtQuick 2.0\nImage { source: \"" + newImageFileName() + "\" }"; - QQmlComponent component(&engine); - component.setData(componentStr.toLatin1(), QUrl::fromLocalFile("")); - QQuickImage *obj = qobject_cast(component.create()); - QVERIFY(obj != 0); - - QCOMPARE(obj->status(), QQuickImage::Ready); - - // remove the provider and confirm - QString fileName = newImageFileName(); - QString error("file::2:1: QML Image: Invalid image provider: " + fileName); - QTest::ignoreMessage(QtWarningMsg, error.toUtf8()); - - engine.removeImageProvider("test"); - - obj->setSource(QUrl(fileName)); - QCOMPARE(obj->status(), QQuickImage::Error); - - delete obj; -} - -class TestThreadProvider : public QQmlImageProvider -{ - public: - TestThreadProvider() : QQmlImageProvider(Image), ok(false) {} - - ~TestThreadProvider() {} - - QImage requestImage(const QString &id, QSize *size, const QSize& requestedSize) - { - mutex.lock(); - if (!ok) - cond.wait(&mutex); - mutex.unlock(); - QVector v; - for (int i = 0; i < 10000; i++) - v.prepend(i); //do some computation - QImage image(50,50, QImage::Format_RGB32); - image.fill(QColor(id).rgb()); - if (size) - *size = image.size(); - if (requestedSize.isValid()) - image = image.scaled(requestedSize); - return image; - } - - QWaitCondition cond; - QMutex mutex; - bool ok; -}; - - -void tst_qqmlimageprovider::threadTest() -{ - QQmlEngine engine; - - TestThreadProvider *provider = new TestThreadProvider; - - engine.addImageProvider("test_thread", provider); - QVERIFY(engine.imageProvider("test_thread") != 0); - - QString componentStr = "import QtQuick 2.0\nItem { \n" - "Image { source: \"image://test_thread/blue\"; asynchronous: true; }\n" - "Image { source: \"image://test_thread/red\"; asynchronous: true; }\n" - "Image { source: \"image://test_thread/green\"; asynchronous: true; }\n" - "Image { source: \"image://test_thread/yellow\"; asynchronous: true; }\n" - " }"; - QQmlComponent component(&engine); - component.setData(componentStr.toLatin1(), QUrl::fromLocalFile("")); - QObject *obj = component.create(); - //MUST not deadlock - QVERIFY(obj != 0); - QList images = obj->findChildren(); - QCOMPARE(images.count(), 4); - QTest::qWait(100); - foreach (QQuickImage *img, images) { - QCOMPARE(img->status(), QQuickImage::Loading); - } - provider->ok = true; - provider->cond.wakeAll(); - QTest::qWait(250); - foreach (QQuickImage *img, images) { - QTRY_VERIFY(img->status() == QQuickImage::Ready); - } -} - - -QTEST_MAIN(tst_qqmlimageprovider) - -#include "tst_qqmlimageprovider.moc" diff --git a/tests/auto/quick/qquickimageprovider/qquickimageprovider.pro b/tests/auto/quick/qquickimageprovider/qquickimageprovider.pro new file mode 100644 index 0000000000..269f06a046 --- /dev/null +++ b/tests/auto/quick/qquickimageprovider/qquickimageprovider.pro @@ -0,0 +1,9 @@ +CONFIG += testcase +TARGET = tst_qquickimageprovider +macx:CONFIG -= app_bundle + +SOURCES += tst_qquickimageprovider.cpp + +CONFIG += parallel_test + +QT += core-private gui-private qml-private quick-private network testlib diff --git a/tests/auto/quick/qquickimageprovider/tst_qquickimageprovider.cpp b/tests/auto/quick/qquickimageprovider/tst_qquickimageprovider.cpp new file mode 100644 index 0000000000..7f9a0efb33 --- /dev/null +++ b/tests/auto/quick/qquickimageprovider/tst_qquickimageprovider.cpp @@ -0,0 +1,424 @@ +/**************************************************************************** +** +** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/ +** +** This file is part of the test suite of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** 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, Nokia gives you certain additional +** rights. These rights are described in the Nokia 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. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ +#include +#include +#include +#include +#include +#include +#include + +Q_DECLARE_METATYPE(QQuickImageProvider*); + +class tst_qquickimageprovider : public QObject +{ + Q_OBJECT +public: + tst_qquickimageprovider() + { + } + +private slots: + void requestImage_sync_data(); + void requestImage_sync(); + void requestImage_async_data(); + void requestImage_async(); + + void requestPixmap_sync_data(); + void requestPixmap_sync(); + void requestPixmap_async(); + + void removeProvider_data(); + void removeProvider(); + + void threadTest(); + +private: + QString newImageFileName() const; + void fillRequestTestsData(const QString &id); + void runTest(bool async, QQuickImageProvider *provider); +}; + + +class TestQImageProvider : public QQuickImageProvider +{ +public: + TestQImageProvider(bool *deleteWatch = 0) + : QQuickImageProvider(Image), deleteWatch(deleteWatch) + { + } + + ~TestQImageProvider() + { + if (deleteWatch) + *deleteWatch = true; + } + + QImage requestImage(const QString &id, QSize *size, const QSize& requestedSize) + { + lastImageId = id; + + if (id == QLatin1String("no-such-file.png")) + return QImage(); + + int width = 100; + int height = 100; + QImage image(width, height, QImage::Format_RGB32); + if (size) + *size = QSize(width, height); + if (requestedSize.isValid()) + image = image.scaled(requestedSize); + return image; + } + + bool *deleteWatch; + QString lastImageId; +}; +Q_DECLARE_METATYPE(TestQImageProvider*); + + +class TestQPixmapProvider : public QQuickImageProvider +{ +public: + TestQPixmapProvider(bool *deleteWatch = 0) + : QQuickImageProvider(Pixmap), deleteWatch(deleteWatch) + { + } + + ~TestQPixmapProvider() + { + if (deleteWatch) + *deleteWatch = true; + } + + QPixmap requestPixmap(const QString &id, QSize *size, const QSize& requestedSize) + { + lastImageId = id; + + if (id == QLatin1String("no-such-file.png")) + return QPixmap(); + + int width = 100; + int height = 100; + QPixmap image(width, height); + if (size) + *size = QSize(width, height); + if (requestedSize.isValid()) + image = image.scaled(requestedSize); + return image; + } + + bool *deleteWatch; + QString lastImageId; +}; +Q_DECLARE_METATYPE(TestQPixmapProvider*); + + +QString tst_qquickimageprovider::newImageFileName() const +{ + // need to generate new filenames each time or else images are loaded + // from cache and we won't get loading status changes when testing + // async loading + static int count = 0; + return QString("image://test/image-%1.png").arg(count++); +} + +void tst_qquickimageprovider::fillRequestTestsData(const QString &id) +{ + QTest::addColumn("source"); + QTest::addColumn("imageId"); + QTest::addColumn("properties"); + QTest::addColumn("size"); + QTest::addColumn("error"); + + QString fileName = newImageFileName(); + QTest::newRow(QTest::toString(id + " simple test")) + << "image://test/" + fileName << fileName << "" << QSize(100,100) << ""; + + fileName = newImageFileName(); + QTest::newRow(QTest::toString(id + " simple test with capitalization"))//As it's a URL, should make no difference + << "image://Test/" + fileName << fileName << "" << QSize(100,100) << ""; + + fileName = newImageFileName(); + QTest::newRow(QTest::toString(id + " url with no id")) + << "image://test/" + fileName << "" + fileName << "" << QSize(100,100) << ""; + + fileName = newImageFileName(); + QTest::newRow(QTest::toString(id + " url with path")) + << "image://test/test/path" + fileName << "test/path" + fileName << "" << QSize(100,100) << ""; + + fileName = newImageFileName(); + QTest::newRow(QTest::toString(id + " url with fragment")) + << "image://test/faq.html?#question13" + fileName << "faq.html?#question13" + fileName << "" << QSize(100,100) << ""; + + fileName = newImageFileName(); + QTest::newRow(QTest::toString(id + " url with query")) + << "image://test/cgi-bin/drawgraph.cgi?type=pie&color=green" + fileName << "cgi-bin/drawgraph.cgi?type=pie&color=green" + fileName + << "" << QSize(100,100) << ""; + + fileName = newImageFileName(); + QTest::newRow(QTest::toString(id + " scaled image")) + << "image://test/" + fileName << fileName << "sourceSize: \"80x30\"" << QSize(80,30) << ""; + + 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"; + + QTest::newRow(QTest::toString(id + " unknown provider")) + << "image://bogus/exists.png" << "" << "" << QSize() + << "file::2:1: QML Image: Invalid image provider: image://bogus/exists.png"; +} + +void tst_qquickimageprovider::runTest(bool async, QQuickImageProvider *provider) +{ + QFETCH(QString, source); + QFETCH(QString, imageId); + QFETCH(QString, properties); + QFETCH(QSize, size); + QFETCH(QString, error); + + if (!error.isEmpty()) + QTest::ignoreMessage(QtWarningMsg, error.toUtf8()); + + QQmlEngine engine; + + engine.addImageProvider("test", provider); + QVERIFY(engine.imageProvider("test") != 0); + + QString componentStr = "import QtQuick 2.0\nImage { source: \"" + source + "\"; " + + (async ? "asynchronous: true; " : "") + + properties + " }"; + QQmlComponent component(&engine); + component.setData(componentStr.toLatin1(), QUrl::fromLocalFile("")); + QQuickImage *obj = qobject_cast(component.create()); + QVERIFY(obj != 0); + + if (async) + QTRY_VERIFY(obj->status() == QQuickImage::Loading); + + QCOMPARE(obj->source(), QUrl(source)); + + if (error.isEmpty()) { + if (async) + QTRY_VERIFY(obj->status() == QQuickImage::Ready); + else + QVERIFY(obj->status() == QQuickImage::Ready); + if (QByteArray(QTest::currentDataTag()).startsWith("qimage")) + QCOMPARE(static_cast(provider)->lastImageId, imageId); + else + QCOMPARE(static_cast(provider)->lastImageId, imageId); + + QCOMPARE(obj->width(), qreal(size.width())); + QCOMPARE(obj->height(), qreal(size.height())); + QCOMPARE(obj->fillMode(), QQuickImage::Stretch); + QCOMPARE(obj->progress(), 1.0); + } else { + if (async) + QTRY_VERIFY(obj->status() == QQuickImage::Error); + else + QVERIFY(obj->status() == QQuickImage::Error); + } + + delete obj; +} + +void tst_qquickimageprovider::requestImage_sync_data() +{ + fillRequestTestsData("qimage|sync"); +} + +void tst_qquickimageprovider::requestImage_sync() +{ + bool deleteWatch = false; + runTest(false, new TestQImageProvider(&deleteWatch)); + QVERIFY(deleteWatch); +} + +void tst_qquickimageprovider::requestImage_async_data() +{ + fillRequestTestsData("qimage|async"); +} + +void tst_qquickimageprovider::requestImage_async() +{ + bool deleteWatch = false; + runTest(true, new TestQImageProvider(&deleteWatch)); + QVERIFY(deleteWatch); +} + +void tst_qquickimageprovider::requestPixmap_sync_data() +{ + fillRequestTestsData("qpixmap"); +} + +void tst_qquickimageprovider::requestPixmap_sync() +{ + bool deleteWatch = false; + runTest(false, new TestQPixmapProvider(&deleteWatch)); + QVERIFY(deleteWatch); +} + +void tst_qquickimageprovider::requestPixmap_async() +{ + QQmlEngine engine; + QQuickImageProvider *provider = new TestQPixmapProvider(); + + engine.addImageProvider("test", provider); + QVERIFY(engine.imageProvider("test") != 0); + + // pixmaps are loaded synchronously regardless of 'asynchronous' value + QString componentStr = "import QtQuick 2.0\nImage { asynchronous: true; source: \"image://test/pixmap-async-test.png\" }"; + QQmlComponent component(&engine); + component.setData(componentStr.toLatin1(), QUrl::fromLocalFile("")); + QQuickImage *obj = qobject_cast(component.create()); + QVERIFY(obj != 0); + + delete obj; +} + +void tst_qquickimageprovider::removeProvider_data() +{ + QTest::addColumn("provider"); + + QTest::newRow("qimage") << static_cast(new TestQImageProvider); + QTest::newRow("qpixmap") << static_cast(new TestQPixmapProvider); +} + +void tst_qquickimageprovider::removeProvider() +{ + QFETCH(QQuickImageProvider*, provider); + + QQmlEngine engine; + + engine.addImageProvider("test", provider); + QVERIFY(engine.imageProvider("test") != 0); + + // add provider, confirm it works + QString componentStr = "import QtQuick 2.0\nImage { source: \"" + newImageFileName() + "\" }"; + QQmlComponent component(&engine); + component.setData(componentStr.toLatin1(), QUrl::fromLocalFile("")); + QQuickImage *obj = qobject_cast(component.create()); + QVERIFY(obj != 0); + + QCOMPARE(obj->status(), QQuickImage::Ready); + + // remove the provider and confirm + QString fileName = newImageFileName(); + QString error("file::2:1: QML Image: Invalid image provider: " + fileName); + QTest::ignoreMessage(QtWarningMsg, error.toUtf8()); + + engine.removeImageProvider("test"); + + obj->setSource(QUrl(fileName)); + QCOMPARE(obj->status(), QQuickImage::Error); + + delete obj; +} + +class TestThreadProvider : public QQuickImageProvider +{ + public: + TestThreadProvider() : QQuickImageProvider(Image), ok(false) {} + + ~TestThreadProvider() {} + + QImage requestImage(const QString &id, QSize *size, const QSize& requestedSize) + { + mutex.lock(); + if (!ok) + cond.wait(&mutex); + mutex.unlock(); + QVector v; + for (int i = 0; i < 10000; i++) + v.prepend(i); //do some computation + QImage image(50,50, QImage::Format_RGB32); + image.fill(QColor(id).rgb()); + if (size) + *size = image.size(); + if (requestedSize.isValid()) + image = image.scaled(requestedSize); + return image; + } + + QWaitCondition cond; + QMutex mutex; + bool ok; +}; + + +void tst_qquickimageprovider::threadTest() +{ + QQmlEngine engine; + + TestThreadProvider *provider = new TestThreadProvider; + + engine.addImageProvider("test_thread", provider); + QVERIFY(engine.imageProvider("test_thread") != 0); + + QString componentStr = "import QtQuick 2.0\nItem { \n" + "Image { source: \"image://test_thread/blue\"; asynchronous: true; }\n" + "Image { source: \"image://test_thread/red\"; asynchronous: true; }\n" + "Image { source: \"image://test_thread/green\"; asynchronous: true; }\n" + "Image { source: \"image://test_thread/yellow\"; asynchronous: true; }\n" + " }"; + QQmlComponent component(&engine); + component.setData(componentStr.toLatin1(), QUrl::fromLocalFile("")); + QObject *obj = component.create(); + //MUST not deadlock + QVERIFY(obj != 0); + QList images = obj->findChildren(); + QCOMPARE(images.count(), 4); + QTest::qWait(100); + foreach (QQuickImage *img, images) { + QCOMPARE(img->status(), QQuickImage::Loading); + } + provider->ok = true; + provider->cond.wakeAll(); + QTest::qWait(250); + foreach (QQuickImage *img, images) { + QTRY_VERIFY(img->status() == QQuickImage::Ready); + } +} + + +QTEST_MAIN(tst_qquickimageprovider) + +#include "tst_qquickimageprovider.moc" diff --git a/tests/auto/quick/qquickpixmapcache/tst_qquickpixmapcache.cpp b/tests/auto/quick/qquickpixmapcache/tst_qquickpixmapcache.cpp index 855322e376..8d2eb66e08 100644 --- a/tests/auto/quick/qquickpixmapcache/tst_qquickpixmapcache.cpp +++ b/tests/auto/quick/qquickpixmapcache/tst_qquickpixmapcache.cpp @@ -42,7 +42,7 @@ #include #include #include -#include +#include #include #include "../../shared/util.h" #include "testhttpserver.h" @@ -335,11 +335,11 @@ void tst_qquickpixmapcache::cancelcrash() } } -class MyPixmapProvider : public QQmlImageProvider +class MyPixmapProvider : public QQuickImageProvider { public: MyPixmapProvider() - : QQmlImageProvider(Pixmap) {} + : QQuickImageProvider(Pixmap) {} virtual QPixmap requestPixmap(const QString &d, QSize *, const QSize &) { Q_UNUSED(d) diff --git a/tests/auto/quick/quick.pro b/tests/auto/quick/quick.pro index 4065dbf508..45fa9763da 100644 --- a/tests/auto/quick/quick.pro +++ b/tests/auto/quick/quick.pro @@ -15,6 +15,7 @@ PRIVATETESTS += \ qquickapplication \ qquickbehaviors \ qquickfontloader \ + qquickimageprovider \ qquickpath \ qquicksmoothedanimation \ qquickspringanimation \ -- cgit v1.2.3 From 4dd4c442e15a155ff3784f28d6c1ebc68fe8382e Mon Sep 17 00:00:00 2001 From: Kent Hansen Date: Mon, 5 Mar 2012 08:31:00 +0100 Subject: Adapt to Qt5 meta-object changes QMetaMethod::signature() has been renamed to methodSignature(), and it now returns a QByteArray. Also, the new function QMetaMethod::isValid() should be used to determine whether a method is valid, instead of relying on signature() returning a 0 pointer. Where it makes sense, the existing code that was using signature() and parameterTypes() has been changed to use the new API QMetaMethod::name(), parameterCount(), and parameterType(int). Also, in the new meta-object revision (7), the QMetaObject stringdata member is now of type QByteArrayData*. QFastMetaBuilder will be ported to generate the new format, but for now it's sufficient to reinterpret_cast the stringdata assignment to keep it compiling. Change-Id: Ie340ef17bcebc3afa4aae6450dfe2d06e4d881a4 Reviewed-by: Aaron Kennedy --- .../auto/qml/qqmlmetaobject/tst_qqmlmetaobject.cpp | 4 ++-- tests/auto/qml/qqmlproperty/tst_qqmlproperty.cpp | 26 +++++++++++----------- tests/auto/quick/qquickstates/tst_qquickstates.cpp | 2 +- 3 files changed, 16 insertions(+), 16 deletions(-) (limited to 'tests/auto') diff --git a/tests/auto/qml/qqmlmetaobject/tst_qqmlmetaobject.cpp b/tests/auto/qml/qqmlmetaobject/tst_qqmlmetaobject.cpp index f2c50ddbef..8876524429 100644 --- a/tests/auto/qml/qqmlmetaobject/tst_qqmlmetaobject.cpp +++ b/tests/auto/qml/qqmlmetaobject/tst_qqmlmetaobject.cpp @@ -244,7 +244,7 @@ void tst_QQmlMetaObject::property() QVERIFY(prop.notifySignalIndex() != -1); QMetaMethod signal = prop.notifySignal(); QCOMPARE(signal.methodType(), QMetaMethod::Signal); - QCOMPARE(signal.signature(), "testChanged()"); + QCOMPARE(signal.methodSignature(), QByteArray("testChanged()")); QCOMPARE(signal.access(), QMetaMethod::Protected); QCOMPARE(signal.parameterTypes(), QList()); QCOMPARE(signal.parameterNames(), QList()); @@ -361,7 +361,7 @@ void tst_QQmlMetaObject::method() QMetaMethod method = mo->method(mo->methodOffset()); QCOMPARE(method.methodType(), methodType); - QCOMPARE(QString::fromUtf8(method.signature()), signature); + QCOMPARE(QString::fromUtf8(method.methodSignature().constData()), signature); QCOMPARE(method.access(), QMetaMethod::Protected); QCOMPARE(method.parameterTypes(), parameterTypeNames); QCOMPARE(method.parameterNames(), parameterNames); diff --git a/tests/auto/qml/qqmlproperty/tst_qqmlproperty.cpp b/tests/auto/qml/qqmlproperty/tst_qqmlproperty.cpp index 13ea1abd73..10b9b83999 100644 --- a/tests/auto/qml/qqmlproperty/tst_qqmlproperty.cpp +++ b/tests/auto/qml/qqmlproperty/tst_qqmlproperty.cpp @@ -161,7 +161,7 @@ void tst_qqmlproperty::qmlmetaproperty() QCOMPARE(prop.connectNotifySignal(0, obj->metaObject()->indexOfMethod("deleteLater()")), false); QCOMPARE(prop.connectNotifySignal(obj, obj->metaObject()->indexOfMethod("deleteLater()")), false); QCOMPARE(prop.connectNotifySignal(obj, -1), false); - QVERIFY(prop.method().signature() == 0); + QVERIFY(!prop.method().isValid()); QCOMPARE(prop.type(), QQmlProperty::Invalid); QCOMPARE(prop.isProperty(), false); QCOMPARE(prop.isWritable(), false); @@ -264,7 +264,7 @@ void tst_qqmlproperty::qmlmetaproperty_object() QCOMPARE(prop.connectNotifySignal(0, obj->metaObject()->indexOfMethod("deleteLater()")), false); QCOMPARE(prop.connectNotifySignal(obj, obj->metaObject()->indexOfMethod("deleteLater()")), false); QCOMPARE(prop.connectNotifySignal(obj, -1), false); - QVERIFY(prop.method().signature() == 0); + QVERIFY(!prop.method().isValid()); QCOMPARE(prop.type(), QQmlProperty::Invalid); QCOMPARE(prop.isProperty(), false); QCOMPARE(prop.isWritable(), false); @@ -311,7 +311,7 @@ void tst_qqmlproperty::qmlmetaproperty_object() QCOMPARE(prop.connectNotifySignal(0, obj->metaObject()->indexOfMethod("deleteLater()")), false); QCOMPARE(prop.connectNotifySignal(obj, obj->metaObject()->indexOfMethod("deleteLater()")), false); QCOMPARE(prop.connectNotifySignal(obj, -1), false); - QVERIFY(prop.method().signature() == 0); + QVERIFY(!prop.method().isValid()); QCOMPARE(prop.type(), QQmlProperty::Property); QCOMPARE(prop.isProperty(), true); QCOMPARE(prop.isWritable(), false); @@ -365,7 +365,7 @@ void tst_qqmlproperty::qmlmetaproperty_object_string() QCOMPARE(prop.connectNotifySignal(0, obj->metaObject()->indexOfMethod("deleteLater()")), false); QCOMPARE(prop.connectNotifySignal(obj, obj->metaObject()->indexOfMethod("deleteLater()")), false); QCOMPARE(prop.connectNotifySignal(obj, -1), false); - QVERIFY(prop.method().signature() == 0); + QVERIFY(!prop.method().isValid()); QCOMPARE(prop.type(), QQmlProperty::Invalid); QCOMPARE(prop.isProperty(), false); QCOMPARE(prop.isWritable(), false); @@ -412,7 +412,7 @@ void tst_qqmlproperty::qmlmetaproperty_object_string() QCOMPARE(prop.connectNotifySignal(0, obj->metaObject()->indexOfMethod("deleteLater()")), false); QCOMPARE(prop.connectNotifySignal(obj, obj->metaObject()->indexOfMethod("deleteLater()")), false); QCOMPARE(prop.connectNotifySignal(obj, -1), false); - QVERIFY(prop.method().signature() == 0); + QVERIFY(!prop.method().isValid()); QCOMPARE(prop.type(), QQmlProperty::Property); QCOMPARE(prop.isProperty(), true); QCOMPARE(prop.isWritable(), false); @@ -461,7 +461,7 @@ void tst_qqmlproperty::qmlmetaproperty_object_string() QCOMPARE(prop.connectNotifySignal(0, obj->metaObject()->indexOfMethod("deleteLater()")), false); QCOMPARE(prop.connectNotifySignal(obj, obj->metaObject()->indexOfMethod("deleteLater()")), false); QCOMPARE(prop.connectNotifySignal(obj, -1), false); - QCOMPARE(QString(prop.method().signature()), QString("clicked()")); + QCOMPARE(QString(prop.method().methodSignature()), QString("clicked()")); QCOMPARE(prop.type(), QQmlProperty::SignalProperty); QCOMPARE(prop.isProperty(), false); QCOMPARE(prop.isWritable(), false); @@ -509,7 +509,7 @@ void tst_qqmlproperty::qmlmetaproperty_object_string() QCOMPARE(prop.connectNotifySignal(0, obj->metaObject()->indexOfMethod("deleteLater()")), false); QCOMPARE(prop.connectNotifySignal(obj, obj->metaObject()->indexOfMethod("deleteLater()")), false); QCOMPARE(prop.connectNotifySignal(obj, -1), false); - QCOMPARE(QString(prop.method().signature()), QString("oddlyNamedNotifySignal()")); + QCOMPARE(QString(prop.method().methodSignature()), QString("oddlyNamedNotifySignal()")); QCOMPARE(prop.type(), QQmlProperty::SignalProperty); QCOMPARE(prop.isProperty(), false); QCOMPARE(prop.isWritable(), false); @@ -562,7 +562,7 @@ void tst_qqmlproperty::qmlmetaproperty_object_context() QCOMPARE(prop.connectNotifySignal(0, obj->metaObject()->indexOfMethod("deleteLater()")), false); QCOMPARE(prop.connectNotifySignal(obj, obj->metaObject()->indexOfMethod("deleteLater()")), false); QCOMPARE(prop.connectNotifySignal(obj, -1), false); - QVERIFY(prop.method().signature() == 0); + QVERIFY(!prop.method().isValid()); QCOMPARE(prop.type(), QQmlProperty::Invalid); QCOMPARE(prop.isProperty(), false); QCOMPARE(prop.isWritable(), false); @@ -609,7 +609,7 @@ void tst_qqmlproperty::qmlmetaproperty_object_context() QCOMPARE(prop.connectNotifySignal(0, obj->metaObject()->indexOfMethod("deleteLater()")), false); QCOMPARE(prop.connectNotifySignal(obj, obj->metaObject()->indexOfMethod("deleteLater()")), false); QCOMPARE(prop.connectNotifySignal(obj, -1), false); - QVERIFY(prop.method().signature() == 0); + QVERIFY(!prop.method().isValid()); QCOMPARE(prop.type(), QQmlProperty::Property); QCOMPARE(prop.isProperty(), true); QCOMPARE(prop.isWritable(), false); @@ -663,7 +663,7 @@ void tst_qqmlproperty::qmlmetaproperty_object_string_context() QCOMPARE(prop.connectNotifySignal(0, obj->metaObject()->indexOfMethod("deleteLater()")), false); QCOMPARE(prop.connectNotifySignal(obj, obj->metaObject()->indexOfMethod("deleteLater()")), false); QCOMPARE(prop.connectNotifySignal(obj, -1), false); - QVERIFY(prop.method().signature() == 0); + QVERIFY(!prop.method().isValid()); QCOMPARE(prop.type(), QQmlProperty::Invalid); QCOMPARE(prop.isProperty(), false); QCOMPARE(prop.isWritable(), false); @@ -710,7 +710,7 @@ void tst_qqmlproperty::qmlmetaproperty_object_string_context() QCOMPARE(prop.connectNotifySignal(0, obj->metaObject()->indexOfMethod("deleteLater()")), false); QCOMPARE(prop.connectNotifySignal(obj, obj->metaObject()->indexOfMethod("deleteLater()")), false); QCOMPARE(prop.connectNotifySignal(obj, -1), false); - QVERIFY(prop.method().signature() == 0); + QVERIFY(!prop.method().isValid()); QCOMPARE(prop.type(), QQmlProperty::Property); QCOMPARE(prop.isProperty(), true); QCOMPARE(prop.isWritable(), false); @@ -759,7 +759,7 @@ void tst_qqmlproperty::qmlmetaproperty_object_string_context() QCOMPARE(prop.connectNotifySignal(0, obj->metaObject()->indexOfMethod("deleteLater()")), false); QCOMPARE(prop.connectNotifySignal(obj, obj->metaObject()->indexOfMethod("deleteLater()")), false); QCOMPARE(prop.connectNotifySignal(obj, -1), false); - QCOMPARE(QString(prop.method().signature()), QString("clicked()")); + QCOMPARE(QString(prop.method().methodSignature()), QString("clicked()")); QCOMPARE(prop.type(), QQmlProperty::SignalProperty); QCOMPARE(prop.isProperty(), false); QCOMPARE(prop.isWritable(), false); @@ -807,7 +807,7 @@ void tst_qqmlproperty::qmlmetaproperty_object_string_context() QCOMPARE(prop.connectNotifySignal(0, obj->metaObject()->indexOfMethod("deleteLater()")), false); QCOMPARE(prop.connectNotifySignal(obj, obj->metaObject()->indexOfMethod("deleteLater()")), false); QCOMPARE(prop.connectNotifySignal(obj, -1), false); - QCOMPARE(QString(prop.method().signature()), QString("oddlyNamedNotifySignal()")); + QCOMPARE(QString(prop.method().methodSignature()), QString("oddlyNamedNotifySignal()")); QCOMPARE(prop.type(), QQmlProperty::SignalProperty); QCOMPARE(prop.isProperty(), false); QCOMPARE(prop.isWritable(), false); diff --git a/tests/auto/quick/qquickstates/tst_qquickstates.cpp b/tests/auto/quick/qquickstates/tst_qquickstates.cpp index fc8194f6ca..7fd8fc4498 100644 --- a/tests/auto/quick/qquickstates/tst_qquickstates.cpp +++ b/tests/auto/quick/qquickstates/tst_qquickstates.cpp @@ -245,7 +245,7 @@ void tst_qquickstates::basicChanges() QMetaProperty prop = rect->metaObject()->property(rect->metaObject()->indexOfProperty("propertyWithNotify")); QVERIFY(prop.hasNotifySignal()); - QString notifySignal = QByteArray(prop.notifySignal().signature()); + QString notifySignal = prop.notifySignal().methodSignature(); QVERIFY(!notifySignal.startsWith("propertyWithNotifyChanged(")); QCOMPARE(rect->color(), QColor(Qt::red)); -- cgit v1.2.3 From 7a5651b4f9fef530e1dc5516899c7f481f4480ef Mon Sep 17 00:00:00 2001 From: Kent Hansen Date: Mon, 5 Mar 2012 10:22:37 +0100 Subject: Make QFastMetaBuilder generate revision 7 meta-objects Support for revision <= 6 will go away in Qt5. This commit updates QFMB to match the latest format generated by moc: - Store string table as an array of QByteArrayData (literals) - Store only the meta-method name, not the full signature - Don't store parameter names as a comma-delimited string - Store explicit information about parameters (count, types, names) Since the meta-data can now hold type ids > 256, there is no need to store the names of property/parameter types at all anymore. Change-Id: I487b14d22b2a92d9e6a9aa4e348f4bab181daff4 Reviewed-by: Aaron Kennedy --- .../auto/qml/qqmlmetaobject/tst_qqmlmetaobject.cpp | 48 +++++++++++++++++----- 1 file changed, 37 insertions(+), 11 deletions(-) (limited to 'tests/auto') diff --git a/tests/auto/qml/qqmlmetaobject/tst_qqmlmetaobject.cpp b/tests/auto/qml/qqmlmetaobject/tst_qqmlmetaobject.cpp index 8876524429..ca48f027e0 100644 --- a/tests/auto/qml/qqmlmetaobject/tst_qqmlmetaobject.cpp +++ b/tests/auto/qml/qqmlmetaobject/tst_qqmlmetaobject.cpp @@ -211,10 +211,10 @@ void tst_QQmlMetaObject::property() QCOMPARE(prop.name(), "test"); QCOMPARE(QByteArray(prop.typeName()), cppTypeName); - QEXPECT_FAIL("QtObject", "prop.type() returns UserType for QtObject properties", Continue); - QEXPECT_FAIL("alias-2", "prop.type() returns UserType for QtObject properties", Continue); if (prop.userType() < QMetaType::User) QCOMPARE(prop.type(), QVariant::Type(cppType)); + else + QCOMPARE(prop.type(), QVariant::UserType); QCOMPARE(prop.userType(), cppType); QVERIFY(!prop.isConstant()); @@ -244,12 +244,15 @@ void tst_QQmlMetaObject::property() QVERIFY(prop.notifySignalIndex() != -1); QMetaMethod signal = prop.notifySignal(); QCOMPARE(signal.methodType(), QMetaMethod::Signal); + QCOMPARE(signal.name(), QByteArray("testChanged")); QCOMPARE(signal.methodSignature(), QByteArray("testChanged()")); QCOMPARE(signal.access(), QMetaMethod::Protected); + QCOMPARE(signal.parameterCount(), 0); QCOMPARE(signal.parameterTypes(), QList()); QCOMPARE(signal.parameterNames(), QList()); QCOMPARE(signal.tag(), ""); QCOMPARE(signal.typeName(), ""); + QCOMPARE(signal.returnType(), int(QMetaType::Void)); QSignalSpy changedSpy(object, SIGNAL(testChanged())); QObject::connect(object, SIGNAL(testChanged()), object, SLOT(deleteLater())); @@ -277,62 +280,73 @@ void tst_QQmlMetaObject::method_data() QTest::addColumn("testFile"); QTest::addColumn("signature"); QTest::addColumn("methodType"); + QTest::addColumn("returnType"); QTest::addColumn("returnTypeName"); + QTest::addColumn >("parameterTypes"); QTest::addColumn >("parameterTypeNames"); QTest::addColumn >("parameterNames"); QTest::newRow("testFunction()") << "method.1.qml" << "testFunction()" << QMetaMethod::Slot - << "QVariant" + << int(QMetaType::QVariant) << "QVariant" + << QList() << QList() << QList(); QTest::newRow("testFunction(foo)") << "method.2.qml" << "testFunction(QVariant)" << QMetaMethod::Slot - << "QVariant" + << int(QMetaType::QVariant) << "QVariant" + << (QList() << QMetaType::QVariant) << (QList() << "QVariant") << (QList() << "foo"); QTest::newRow("testFunction(foo, bar, baz)") << "method.3.qml" << "testFunction(QVariant,QVariant,QVariant)" << QMetaMethod::Slot - << "QVariant" + << int(QMetaType::QVariant) << "QVariant" + << (QList() << QMetaType::QVariant << QMetaType::QVariant << QMetaType::QVariant) << (QList() << "QVariant" << "QVariant" << "QVariant") << (QList() << "foo" << "bar" << "baz"); QTest::newRow("testSignal") << "signal.1.qml" << "testSignal()" << QMetaMethod::Signal - << "" + << int(QMetaType::Void) << "" + << QList() << QList() << QList(); QTest::newRow("testSignal(string foo)") << "signal.2.qml" << "testSignal(QString)" << QMetaMethod::Signal - << "" + << int(QMetaType::Void) << "" + << (QList() << QMetaType::QString) << (QList() << "QString") << (QList() << "foo"); QTest::newRow("testSignal(int foo, bool bar, real baz)") << "signal.3.qml" << "testSignal(int,bool,double)" << QMetaMethod::Signal - << "" + << int(QMetaType::Void) << "" + << (QList() << QMetaType::Int << QMetaType::Bool << QMetaType::Double) << (QList() << "int" << "bool" << "double") << (QList() << "foo" << "bar" << "baz"); QTest::newRow("testSignal(variant foo, var bar)") << "signal.4.qml" << "testSignal(QVariant,QVariant)" << QMetaMethod::Signal - << "" + << int(QMetaType::Void) << "" + << (QList() << QMetaType::QVariant << QMetaType::QVariant) << (QList() << "QVariant" << "QVariant") << (QList() << "foo" << "bar"); QTest::newRow("testSignal(color foo, date bar, url baz)") << "signal.5.qml" << "testSignal(QColor,QDateTime,QUrl)" << QMetaMethod::Signal - << "" + << int(QMetaType::Void) << "" + << (QList() << QMetaType::QColor << QMetaType::QDateTime << QMetaType::QUrl) << (QList() << "QColor" << "QDateTime" << "QUrl") << (QList() << "foo" << "bar" << "baz"); QTest::newRow("testSignal(double foo)") << "signal.6.qml" << "testSignal(double)" << QMetaMethod::Signal - << "" + << int(QMetaType::Void) << "" + << (QList() << QMetaType::Double) << (QList() << "double") << (QList() << "foo"); } @@ -342,10 +356,13 @@ void tst_QQmlMetaObject::method() QFETCH(QString, testFile); QFETCH(QString, signature); QFETCH(QMetaMethod::MethodType, methodType); + QFETCH(int, returnType); QFETCH(QString, returnTypeName); + QFETCH(QList, parameterTypes); QFETCH(QList, parameterTypeNames); QFETCH(QList, parameterNames); + QCOMPARE(parameterTypes.size(), parameterTypeNames.size()); QCOMPARE(parameterTypeNames.size(), parameterNames.size()); QQmlEngine engine; @@ -363,10 +380,19 @@ void tst_QQmlMetaObject::method() QCOMPARE(method.methodType(), methodType); QCOMPARE(QString::fromUtf8(method.methodSignature().constData()), signature); QCOMPARE(method.access(), QMetaMethod::Protected); + + QString computedName = signature.left(signature.indexOf('(')); + QCOMPARE(QString::fromUtf8(method.name()), computedName); + + QCOMPARE(method.parameterCount(), parameterTypes.size()); + for (int i = 0; i < parameterTypes.size(); ++i) + QCOMPARE(method.parameterType(i), parameterTypes.at(i)); QCOMPARE(method.parameterTypes(), parameterTypeNames); QCOMPARE(method.parameterNames(), parameterNames); QCOMPARE(method.tag(), ""); + QCOMPARE(QString::fromUtf8(method.typeName()), returnTypeName); + QCOMPARE(method.returnType(), returnType); delete object; } -- cgit v1.2.3 From 83f11e33745180e9370d484cbcedd0bac020c9dd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C4=99drzej=20Nowacki?= Date: Mon, 5 Mar 2012 14:45:34 +0100 Subject: Crash fix after QMetaType change. QMetaType::UnknownType was added so we can distinguish between "void" and an unregistered type. Change-Id: If8cee21b3f84bf129343dc457d10ab31a9bfc8b8 Reviewed-by: Kent Hansen --- tests/auto/qml/qqmlecmascript/tst_qqmlecmascript.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'tests/auto') diff --git a/tests/auto/qml/qqmlecmascript/tst_qqmlecmascript.cpp b/tests/auto/qml/qqmlecmascript/tst_qqmlecmascript.cpp index 4389fe5cb7..b475e991b2 100644 --- a/tests/auto/qml/qqmlecmascript/tst_qqmlecmascript.cpp +++ b/tests/auto/qml/qqmlecmascript/tst_qqmlecmascript.cpp @@ -4613,7 +4613,7 @@ void tst_qqmlecmascript::sequenceConversionWrite() QVERIFY(seq != 0); // we haven't registered QList as a sequence type, so writing shouldn't work. - QString warningOne = qmlFile.toString() + QLatin1String(":16: Error: Cannot assign QVariantList to void"); + QString warningOne = qmlFile.toString() + QLatin1String(":16: Error: Cannot assign QVariantList to an unregistered type"); QTest::ignoreMessage(QtWarningMsg, warningOne.toAscii().constData()); QMetaObject::invokeMethod(object, "performTest"); -- cgit v1.2.3 From ab1e510121c8a679fdaca12ccd30e0f7ac12a26b Mon Sep 17 00:00:00 2001 From: Matthew Vogt Date: Fri, 2 Mar 2012 08:25:43 +1000 Subject: Migrate gui dependencies from QtQml to QtQuick. Ensure that users of declarative that have no need for functionality provided by the Qt Gui module do not have to link against it. Any use of QtGui functionality is delegated to providers that can be installed by another library; QtQuick adds default providers for this functionality when linked against QtQml. Task-number: QTBUG-24559 Change-Id: I5e6a58a4198732dc2f8f52f71abfa1152b871aa7 Reviewed-by: Martin Jones --- tests/auto/qml/qml.pro | 1 + tests/auto/qml/qqmlecmascript/testtypes.h | 1 + tests/auto/qml/qqmlglobal/qqmlglobal.pro | 7 ++ tests/auto/qml/qqmlglobal/tst_qqmlglobal.cpp | 88 ++++++++++++++++++++++ .../qml/qqmlinstruction/tst_qqmlinstruction.cpp | 3 + .../qml/qqmllanguage/data/wrongType.7.errors.txt | 2 +- tests/auto/qml/qqmllanguage/data/wrongType.7.qml | 1 + tests/auto/qml/qqmlqt/qqmlqt.pro | 2 +- tests/auto/qml/qqmlqt/tst_qqmlqt.cpp | 2 + tests/auto/qml/qqmlvaluetypes/qqmlvaluetypes.pro | 2 +- .../auto/qml/qqmlvaluetypes/tst_qqmlvaluetypes.cpp | 16 ++-- .../qquickapplication/tst_qquickapplication.cpp | 15 +++- tests/auto/quick/qquicktext/tst_qquicktext.cpp | 18 ++--- 13 files changed, 137 insertions(+), 21 deletions(-) create mode 100644 tests/auto/qml/qqmlglobal/qqmlglobal.pro create mode 100644 tests/auto/qml/qqmlglobal/tst_qqmlglobal.cpp (limited to 'tests/auto') diff --git a/tests/auto/qml/qml.pro b/tests/auto/qml/qml.pro index 4d1644f6b3..0657ea891e 100644 --- a/tests/auto/qml/qml.pro +++ b/tests/auto/qml/qml.pro @@ -32,6 +32,7 @@ PRIVATETESTS += \ qqmlecmascript \ qqmlcontext \ qqmlexpression \ + qqmlglobal \ qqmlinstruction \ qqmllanguage \ qqmlproperty \ diff --git a/tests/auto/qml/qqmlecmascript/testtypes.h b/tests/auto/qml/qqmlecmascript/testtypes.h index 54fab26405..ab8f85baa3 100644 --- a/tests/auto/qml/qqmlecmascript/testtypes.h +++ b/tests/auto/qml/qqmlecmascript/testtypes.h @@ -51,6 +51,7 @@ #include #include #include +#include #include #include #include diff --git a/tests/auto/qml/qqmlglobal/qqmlglobal.pro b/tests/auto/qml/qqmlglobal/qqmlglobal.pro new file mode 100644 index 0000000000..b39c04500c --- /dev/null +++ b/tests/auto/qml/qqmlglobal/qqmlglobal.pro @@ -0,0 +1,7 @@ +CONFIG += testcase +TARGET = tst_qqmlglobal +SOURCES += tst_qqmlglobal.cpp +macx:CONFIG -= app_bundle + +CONFIG += parallel_test +QT += qml-private testlib diff --git a/tests/auto/qml/qqmlglobal/tst_qqmlglobal.cpp b/tests/auto/qml/qqmlglobal/tst_qqmlglobal.cpp new file mode 100644 index 0000000000..e2cdd50883 --- /dev/null +++ b/tests/auto/qml/qqmlglobal/tst_qqmlglobal.cpp @@ -0,0 +1,88 @@ +/**************************************************************************** +** +** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/ +** +** This file is part of the test suite of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** 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, Nokia gives you certain additional +** rights. These rights are described in the Nokia 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. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include +#include + +#include + +class tst_qqmlglobal : public QObject +{ + Q_OBJECT +public: + tst_qqmlglobal() {} + +private slots: + void initTestCase(); + + void valueTypeProviderWarning(); + void colorProviderWarning(); + void guiProviderWarning(); +}; + +void tst_qqmlglobal::initTestCase() +{ +} + +void tst_qqmlglobal::valueTypeProviderWarning() +{ + const QLatin1String expected("Warning: QQml_valueTypeProvider: no value type provider has been set! "); + QTest::ignoreMessage(QtWarningMsg, expected.data()); + QQml_valueTypeProvider(); +} + +void tst_qqmlglobal::colorProviderWarning() +{ + const QLatin1String expected("Warning: QQml_colorProvider: no color provider has been set! "); + QTest::ignoreMessage(QtWarningMsg, expected.data()); + QQml_colorProvider(); +} + +void tst_qqmlglobal::guiProviderWarning() +{ + const QLatin1String expected("Warning: QQml_guiProvider: no GUI provider has been set! "); + QTest::ignoreMessage(QtWarningMsg, expected.data()); + QQml_guiProvider(); +} + +QTEST_MAIN(tst_qqmlglobal) + +#include "tst_qqmlglobal.moc" diff --git a/tests/auto/qml/qqmlinstruction/tst_qqmlinstruction.cpp b/tests/auto/qml/qqmlinstruction/tst_qqmlinstruction.cpp index d076f038d3..d0e818f076 100644 --- a/tests/auto/qml/qqmlinstruction/tst_qqmlinstruction.cpp +++ b/tests/auto/qml/qqmlinstruction/tst_qqmlinstruction.cpp @@ -42,6 +42,9 @@ #include #include +#include +#include + class tst_qqmlinstruction : public QObject { Q_OBJECT diff --git a/tests/auto/qml/qqmllanguage/data/wrongType.7.errors.txt b/tests/auto/qml/qqmllanguage/data/wrongType.7.errors.txt index 614346bd2b..8a168d2941 100644 --- a/tests/auto/qml/qqmllanguage/data/wrongType.7.errors.txt +++ b/tests/auto/qml/qqmllanguage/data/wrongType.7.errors.txt @@ -1 +1 @@ -3:20:Invalid property assignment: color expected +4:20:Invalid property assignment: color expected diff --git a/tests/auto/qml/qqmllanguage/data/wrongType.7.qml b/tests/auto/qml/qqmllanguage/data/wrongType.7.qml index ddc3835199..e9dd71079a 100644 --- a/tests/auto/qml/qqmllanguage/data/wrongType.7.qml +++ b/tests/auto/qml/qqmllanguage/data/wrongType.7.qml @@ -1,4 +1,5 @@ import Test 1.0 +import QtQuick 2.0 MyTypeObject { colorProperty: 12 } diff --git a/tests/auto/qml/qqmlqt/qqmlqt.pro b/tests/auto/qml/qqmlqt/qqmlqt.pro index 92fabf5882..012f58ae70 100644 --- a/tests/auto/qml/qqmlqt/qqmlqt.pro +++ b/tests/auto/qml/qqmlqt/qqmlqt.pro @@ -10,4 +10,4 @@ TESTDATA = data/* CONFIG += parallel_test -QT += core-private gui-private v8-private qml-private quick-private testlib +QT += core-private v8-private qml-private quick-private testlib gui diff --git a/tests/auto/qml/qqmlqt/tst_qqmlqt.cpp b/tests/auto/qml/qqmlqt/tst_qqmlqt.cpp index d3dc3e7343..a1d7291565 100644 --- a/tests/auto/qml/qqmlqt/tst_qqmlqt.cpp +++ b/tests/auto/qml/qqmlqt/tst_qqmlqt.cpp @@ -52,6 +52,8 @@ #include #include #include +#include +#include #include "../../shared/util.h" class tst_qqmlqt : public QQmlDataTest diff --git a/tests/auto/qml/qqmlvaluetypes/qqmlvaluetypes.pro b/tests/auto/qml/qqmlvaluetypes/qqmlvaluetypes.pro index 9155cbee96..8d9acb65b3 100644 --- a/tests/auto/qml/qqmlvaluetypes/qqmlvaluetypes.pro +++ b/tests/auto/qml/qqmlvaluetypes/qqmlvaluetypes.pro @@ -13,4 +13,4 @@ TESTDATA = data/* CONFIG += parallel_test -QT += core-private gui-private v8-private qml-private testlib +QT += core-private gui-private v8-private qml-private quick-private gui testlib diff --git a/tests/auto/qml/qqmlvaluetypes/tst_qqmlvaluetypes.cpp b/tests/auto/qml/qqmlvaluetypes/tst_qqmlvaluetypes.cpp index 54791fc340..359653caa4 100644 --- a/tests/auto/qml/qqmlvaluetypes/tst_qqmlvaluetypes.cpp +++ b/tests/auto/qml/qqmlvaluetypes/tst_qqmlvaluetypes.cpp @@ -43,12 +43,12 @@ #include #include #include -#include +#include #include "../../shared/util.h" #include "testtypes.h" QT_BEGIN_NAMESPACE -extern int qt_defaultDpi(); +extern int qt_defaultDpi(void); QT_END_NAMESPACE class tst_qqmlvaluetypes : public QQmlDataTest @@ -1129,13 +1129,13 @@ void tst_qqmlvaluetypes::cppClasses() CPP_TEST(QQmlSizeFValueType, QSizeF(-100.7, 18.2)); CPP_TEST(QQmlRectValueType, QRect(13, 39, 10928, 88)); CPP_TEST(QQmlRectFValueType, QRectF(88.2, -90.1, 103.2, 118)); - CPP_TEST(QQmlVector2DValueType, QVector2D(19.7, 1002)); - CPP_TEST(QQmlVector3DValueType, QVector3D(18.2, 19.7, 1002)); - CPP_TEST(QQmlVector4DValueType, QVector4D(18.2, 19.7, 1002, 54)); - CPP_TEST(QQmlQuaternionValueType, QQuaternion(18.2, 19.7, 1002, 54)); - CPP_TEST(QQmlMatrix4x4ValueType, + CPP_TEST(QQuickVector2DValueType, QVector2D(19.7, 1002)); + CPP_TEST(QQuickVector3DValueType, QVector3D(18.2, 19.7, 1002)); + CPP_TEST(QQuickVector4DValueType, QVector4D(18.2, 19.7, 1002, 54)); + CPP_TEST(QQuickQuaternionValueType, QQuaternion(18.2, 19.7, 1002, 54)); + CPP_TEST(QQuickMatrix4x4ValueType, QMatrix4x4(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16)); - CPP_TEST(QQmlFontValueType, QFont("Helvetica")); + CPP_TEST(QQuickFontValueType, QFont("Helvetica")); } diff --git a/tests/auto/quick/qquickapplication/tst_qquickapplication.cpp b/tests/auto/quick/qquickapplication/tst_qquickapplication.cpp index 61675d980d..4dd7688f6a 100644 --- a/tests/auto/quick/qquickapplication/tst_qquickapplication.cpp +++ b/tests/auto/quick/qquickapplication/tst_qquickapplication.cpp @@ -69,7 +69,15 @@ tst_qquickapplication::tst_qquickapplication() void tst_qquickapplication::active() { QQmlComponent component(&engine); - component.setData("import QtQuick 2.0; Item { property bool active: Qt.application.active }", QUrl::fromLocalFile("")); + component.setData("import QtQuick 2.0; " + "Item { " + " property bool active: Qt.application.active; " + " property bool active2: false; " + " Connections { " + " target: Qt.application; " + " onActiveChanged: active2 = Qt.application.active; " + " } " + "}", QUrl::fromLocalFile("")); QQuickItem *item = qobject_cast(component.create()); QVERIFY(item); QQuickView view; @@ -77,6 +85,7 @@ void tst_qquickapplication::active() // not active QVERIFY(!item->property("active").toBool()); + QVERIFY(!item->property("active2").toBool()); QCOMPARE(item->property("active").toBool(), QGuiApplication::activeWindow() != 0); // active @@ -86,6 +95,7 @@ void tst_qquickapplication::active() QEXPECT_FAIL("", "QTBUG-21573", Abort); QTRY_COMPARE(view.status(), QQuickView::Ready); QCOMPARE(item->property("active").toBool(), QGuiApplication::activeWindow() != 0); + QCOMPARE(item->property("active2").toBool(), QGuiApplication::activeWindow() != 0); #if 0 // QGuiApplication has no equivalent of setActiveWindow(0). QTBUG-21573 @@ -128,6 +138,9 @@ void tst_qquickapplication::layoutDirection() void tst_qquickapplication::inputPanel() { + const QLatin1String expected("Qt.application.inputPanel is deprecated, use Qt.inputMethod instead "); + QTest::ignoreMessage(QtWarningMsg, expected.data()); + QQmlComponent component(&engine); component.setData("import QtQuick 2.0; Item { property variant inputPanel: Qt.application.inputPanel }", QUrl::fromLocalFile("")); QQuickItem *item = qobject_cast(component.create()); diff --git a/tests/auto/quick/qquicktext/tst_qquicktext.cpp b/tests/auto/quick/qquicktext/tst_qquicktext.cpp index 92e8528a0d..77f0ec190d 100644 --- a/tests/auto/quick/qquicktext/tst_qquicktext.cpp +++ b/tests/auto/quick/qquicktext/tst_qquicktext.cpp @@ -45,7 +45,7 @@ #include #include #include -#include +#include #include #include #include @@ -93,7 +93,7 @@ private slots: void color(); void smooth(); - // QQmlFontValueType + // QQuickFontValueType void weight(); void underline(); void overline(); @@ -1119,7 +1119,7 @@ void tst_qquicktext::weight() QQuickText *textObject = qobject_cast(textComponent.create()); QVERIFY(textObject != 0); - QCOMPARE((int)textObject->font().weight(), (int)QQmlFontValueType::Normal); + QCOMPARE((int)textObject->font().weight(), (int)QQuickFontValueType::Normal); delete textObject; } @@ -1130,7 +1130,7 @@ void tst_qquicktext::weight() QQuickText *textObject = qobject_cast(textComponent.create()); QVERIFY(textObject != 0); - QCOMPARE((int)textObject->font().weight(), (int)QQmlFontValueType::Bold); + QCOMPARE((int)textObject->font().weight(), (int)QQuickFontValueType::Bold); delete textObject; } @@ -1223,7 +1223,7 @@ void tst_qquicktext::capitalization() QQuickText *textObject = qobject_cast(textComponent.create()); QVERIFY(textObject != 0); - QCOMPARE((int)textObject->font().capitalization(), (int)QQmlFontValueType::MixedCase); + QCOMPARE((int)textObject->font().capitalization(), (int)QQuickFontValueType::MixedCase); delete textObject; } @@ -1234,7 +1234,7 @@ void tst_qquicktext::capitalization() QQuickText *textObject = qobject_cast(textComponent.create()); QVERIFY(textObject != 0); - QCOMPARE((int)textObject->font().capitalization(), (int)QQmlFontValueType::AllUppercase); + QCOMPARE((int)textObject->font().capitalization(), (int)QQuickFontValueType::AllUppercase); delete textObject; } @@ -1245,7 +1245,7 @@ void tst_qquicktext::capitalization() QQuickText *textObject = qobject_cast(textComponent.create()); QVERIFY(textObject != 0); - QCOMPARE((int)textObject->font().capitalization(), (int)QQmlFontValueType::AllLowercase); + QCOMPARE((int)textObject->font().capitalization(), (int)QQuickFontValueType::AllLowercase); delete textObject; } @@ -1256,7 +1256,7 @@ void tst_qquicktext::capitalization() QQuickText *textObject = qobject_cast(textComponent.create()); QVERIFY(textObject != 0); - QCOMPARE((int)textObject->font().capitalization(), (int)QQmlFontValueType::SmallCaps); + QCOMPARE((int)textObject->font().capitalization(), (int)QQuickFontValueType::SmallCaps); delete textObject; } @@ -1267,7 +1267,7 @@ void tst_qquicktext::capitalization() QQuickText *textObject = qobject_cast(textComponent.create()); QVERIFY(textObject != 0); - QCOMPARE((int)textObject->font().capitalization(), (int)QQmlFontValueType::Capitalize); + QCOMPARE((int)textObject->font().capitalization(), (int)QQuickFontValueType::Capitalize); delete textObject; } -- cgit v1.2.3 From c3babc03c99c6ca5fa210486e133eb456a405bab Mon Sep 17 00:00:00 2001 From: Kent Hansen Date: Tue, 20 Mar 2012 20:07:50 +0100 Subject: Adapt to QMetaMethod::typeName() behavioral change for "void" MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit QMetaMethod::typeName() has been changed to return "void", rather than an empty string, when the return type is void. Change-Id: Ifc903ba60a06ffaefe27c94fe629698d64904d94 Reviewed-by: Jędrzej Nowacki --- tests/auto/qml/qqmlmetaobject/tst_qqmlmetaobject.cpp | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) (limited to 'tests/auto') diff --git a/tests/auto/qml/qqmlmetaobject/tst_qqmlmetaobject.cpp b/tests/auto/qml/qqmlmetaobject/tst_qqmlmetaobject.cpp index ca48f027e0..8e35c24b7d 100644 --- a/tests/auto/qml/qqmlmetaobject/tst_qqmlmetaobject.cpp +++ b/tests/auto/qml/qqmlmetaobject/tst_qqmlmetaobject.cpp @@ -251,7 +251,7 @@ void tst_QQmlMetaObject::property() QCOMPARE(signal.parameterTypes(), QList()); QCOMPARE(signal.parameterNames(), QList()); QCOMPARE(signal.tag(), ""); - QCOMPARE(signal.typeName(), ""); + QCOMPARE(signal.typeName(), "void"); QCOMPARE(signal.returnType(), int(QMetaType::Void)); QSignalSpy changedSpy(object, SIGNAL(testChanged())); @@ -310,42 +310,42 @@ void tst_QQmlMetaObject::method_data() QTest::newRow("testSignal") << "signal.1.qml" << "testSignal()" << QMetaMethod::Signal - << int(QMetaType::Void) << "" + << int(QMetaType::Void) << "void" << QList() << QList() << QList(); QTest::newRow("testSignal(string foo)") << "signal.2.qml" << "testSignal(QString)" << QMetaMethod::Signal - << int(QMetaType::Void) << "" + << int(QMetaType::Void) << "void" << (QList() << QMetaType::QString) << (QList() << "QString") << (QList() << "foo"); QTest::newRow("testSignal(int foo, bool bar, real baz)") << "signal.3.qml" << "testSignal(int,bool,double)" << QMetaMethod::Signal - << int(QMetaType::Void) << "" + << int(QMetaType::Void) << "void" << (QList() << QMetaType::Int << QMetaType::Bool << QMetaType::Double) << (QList() << "int" << "bool" << "double") << (QList() << "foo" << "bar" << "baz"); QTest::newRow("testSignal(variant foo, var bar)") << "signal.4.qml" << "testSignal(QVariant,QVariant)" << QMetaMethod::Signal - << int(QMetaType::Void) << "" + << int(QMetaType::Void) << "void" << (QList() << QMetaType::QVariant << QMetaType::QVariant) << (QList() << "QVariant" << "QVariant") << (QList() << "foo" << "bar"); QTest::newRow("testSignal(color foo, date bar, url baz)") << "signal.5.qml" << "testSignal(QColor,QDateTime,QUrl)" << QMetaMethod::Signal - << int(QMetaType::Void) << "" + << int(QMetaType::Void) << "void" << (QList() << QMetaType::QColor << QMetaType::QDateTime << QMetaType::QUrl) << (QList() << "QColor" << "QDateTime" << "QUrl") << (QList() << "foo" << "bar" << "baz"); QTest::newRow("testSignal(double foo)") << "signal.6.qml" << "testSignal(double)" << QMetaMethod::Signal - << int(QMetaType::Void) << "" + << int(QMetaType::Void) << "void" << (QList() << QMetaType::Double) << (QList() << "double") << (QList() << "foo"); -- cgit v1.2.3 From 3e6a8eca00334df344a45f09afbcf8fd8e2b7c54 Mon Sep 17 00:00:00 2001 From: Kent Hansen Date: Fri, 23 Mar 2012 18:10:18 +0100 Subject: Mark tst_qquickimage as insignificant The nullPixmapPaint() test is flaky. There are also several other places where QQuickView::show() is called without a subsequent call to QTest::qWaitForWindowShown(); in some of the test functions, processEvents() is called instead (twice, even, just to be sure: see the imageCrash_QTBUG_22125 function). Change-Id: Icb49a36dcf968664f16c3223658ddd6189e965fc Reviewed-by: Kent Hansen --- tests/auto/quick/qquickimage/qquickimage.pro | 1 + 1 file changed, 1 insertion(+) (limited to 'tests/auto') diff --git a/tests/auto/quick/qquickimage/qquickimage.pro b/tests/auto/quick/qquickimage/qquickimage.pro index ad0097df08..e0d309da33 100644 --- a/tests/auto/quick/qquickimage/qquickimage.pro +++ b/tests/auto/quick/qquickimage/qquickimage.pro @@ -13,3 +13,4 @@ TESTDATA = data/* CONFIG += parallel_test QT += core-private gui-private qml-private quick-private network testlib +CONFIG += insignificant_test -- cgit v1.2.3 From 2d393ae042d5badf0862c0f95122f9662042f2a9 Mon Sep 17 00:00:00 2001 From: Thiago Macieira Date: Wed, 11 Apr 2012 15:57:06 -0300 Subject: Stop stuffing the URL "" in QML errors QQmlError already knows how to deal with source scripts with no URL and it will use "" when converting to a string. QUrl in Qt 5 leaves the "<" and ">" characters encoded, which means we ended up getting warnings about "%3CUnknown File%3E", which isn't nice. Change-Id: I504604fa37bb734549048432aaf9db3b1fa568d2 Reviewed-by: Lars Knoll --- tests/auto/qml/qqmlcontext/tst_qqmlcontext.cpp | 2 +- tests/auto/qml/qqmlengine/tst_qqmlengine.cpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) (limited to 'tests/auto') diff --git a/tests/auto/qml/qqmlcontext/tst_qqmlcontext.cpp b/tests/auto/qml/qqmlcontext/tst_qqmlcontext.cpp index 6525bde9b8..16365eeaa8 100644 --- a/tests/auto/qml/qqmlcontext/tst_qqmlcontext.cpp +++ b/tests/auto/qml/qqmlcontext/tst_qqmlcontext.cpp @@ -345,7 +345,7 @@ void tst_qqmlcontext::setContextProperty() QQmlContext ctxt(engine.rootContext()); ctxt.setContextProperty("ctxtProp", QVariant()); - QTest::ignoreMessage(QtWarningMsg, ":1: TypeError: Cannot read property 'a' of undefined"); + QTest::ignoreMessage(QtWarningMsg, ": TypeError: Cannot read property 'a' of undefined"); QObject *obj = component.create(&ctxt); QVariant v = obj->property("obj"); diff --git a/tests/auto/qml/qqmlengine/tst_qqmlengine.cpp b/tests/auto/qml/qqmlengine/tst_qqmlengine.cpp index af2c897d7a..89fc8e05d9 100644 --- a/tests/auto/qml/qqmlengine/tst_qqmlengine.cpp +++ b/tests/auto/qml/qqmlengine/tst_qqmlengine.cpp @@ -268,7 +268,7 @@ void tst_qqmlengine::outputWarningsToStandardError() delete o; QCOMPARE(warnings.count(), 1); - QCOMPARE(warnings.at(0), QLatin1String(":1: Unable to assign [undefined] to int")); + QCOMPARE(warnings.at(0), QLatin1String(": Unable to assign [undefined] to int")); warnings.clear(); -- cgit v1.2.3 From 31c5b237c4f0eb6848c7d2e3ae84232c6f8f6d26 Mon Sep 17 00:00:00 2001 From: Thiago Macieira Date: Wed, 11 Apr 2012 14:05:32 -0300 Subject: Update test after QUrl minor behaviour change Changes required: - Uppercase the hex in percent-encodings - The tolerant decoder treats all % as broken if any one is broken (Input "%2B50%" is rendered now "%252B50%25", where previously it was "%2B50%25) The extra test is just so we use QString first. If the test fails, we get a nicer output from QtTest, instead of the hex dump it uses for QByteArray. Change-Id: I4c5cbfa3be962c648b50a69dc8bc3c4acc551e62 Reviewed-by: Lars Knoll --- tests/auto/qml/qqmlproperty/tst_qqmlproperty.cpp | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) (limited to 'tests/auto') diff --git a/tests/auto/qml/qqmlproperty/tst_qqmlproperty.cpp b/tests/auto/qml/qqmlproperty/tst_qqmlproperty.cpp index f2521e93ef..d99ed303ba 100644 --- a/tests/auto/qml/qqmlproperty/tst_qqmlproperty.cpp +++ b/tests/auto/qml/qqmlproperty/tst_qqmlproperty.cpp @@ -1431,10 +1431,10 @@ void tst_qqmlproperty::urlHandling_data() << QByteArray("http://www.example.com/main%20file.qml"); QTest::newRow("preencodedName") - << QByteArray("http://www.example.com/resources%7cmain%20file.qml") + << QByteArray("http://www.example.com/resources%7Cmain%20file.qml") << QString("http") << QString("/resources|main file.qml") - << QByteArray("http://www.example.com/resources%7cmain%20file.qml"); + << QByteArray("http://www.example.com/resources%7Cmain%20file.qml"); QTest::newRow("encodableQuery") << QByteArray("http://www.example.com/main.qml?type=text/qml&comment=now working?") @@ -1443,10 +1443,10 @@ void tst_qqmlproperty::urlHandling_data() << QByteArray("http://www.example.com/main.qml?type=text/qml&comment=now%20working?"); QTest::newRow("preencodedQuery") - << QByteArray("http://www.example.com/main.qml?type=text%2fqml&comment=now working%3f") + << QByteArray("http://www.example.com/main.qml?type=text%2Fqml&comment=now working%3F") << QString("http") << QString("/main.qml") - << QByteArray("http://www.example.com/main.qml?type=text%2fqml&comment=now%20working%3f"); + << QByteArray("http://www.example.com/main.qml?type=text%2Fqml&comment=now%20working%3F"); QTest::newRow("encodableFragment") << QByteArray("http://www.example.com/main.qml?type=text/qml#start+30000|volume+50%") @@ -1454,11 +1454,11 @@ void tst_qqmlproperty::urlHandling_data() << QString("/main.qml") << QByteArray("http://www.example.com/main.qml?type=text/qml#start+30000%7Cvolume+50%25"); - QTest::newRow("preencodedFragment") - << QByteArray("http://www.example.com/main.qml?type=text/qml#start+30000%7cvolume%2b50%") + QTest::newRow("improperlyEncodedFragment") + << QByteArray("http://www.example.com/main.qml?type=text/qml#start+30000%7Cvolume%2B50%") << QString("http") << QString("/main.qml") - << QByteArray("http://www.example.com/main.qml?type=text/qml#start+30000%7cvolume%2b50%25"); + << QByteArray("http://www.example.com/main.qml?type=text/qml#start+30000%257Cvolume%252B50%25"); } void tst_qqmlproperty::urlHandling() @@ -1480,6 +1480,7 @@ void tst_qqmlproperty::urlHandling() QCOMPARE(byteArrayResult.scheme(), scheme); QCOMPARE(byteArrayResult.path(), path); + QCOMPARE(byteArrayResult.toString(QUrl::FullyEncoded), QString::fromUtf8(encoded)); QCOMPARE(byteArrayResult.toEncoded(), encoded); } @@ -1493,6 +1494,7 @@ void tst_qqmlproperty::urlHandling() QCOMPARE(stringResult.scheme(), scheme); QCOMPARE(stringResult.path(), path); + QCOMPARE(stringResult.toString(QUrl::FullyEncoded), QString::fromUtf8(encoded)); QCOMPARE(stringResult.toEncoded(), encoded); } } -- cgit v1.2.3 From e5f45d9b57bb0542ec47e5a8a4e57388b6d59d35 Mon Sep 17 00:00:00 2001 From: Kent Hansen Date: Fri, 23 Mar 2012 18:14:29 +0100 Subject: Add QJson support to QV8Engine Make QV8Engine perform direct conversion between JavaScript values and QJson{Value,Object,Array}. This implementation always makes a deep clone of the QJson{Object,Array} when converting to JS; it might make sense to add a lazy conversion scheme for dealing with large objects. Change-Id: Id0b65891a19515ce22f1e51fa8a28d9f3e595271 Reviewed-by: Aaron Kennedy Reviewed-by: Jamey Hicks Reviewed-by: Lars Knoll --- tests/auto/qml/qjsonbinding/data/array.0.json | 1 + tests/auto/qml/qjsonbinding/data/array.1.json | 1 + tests/auto/qml/qjsonbinding/data/array.2.json | 1 + tests/auto/qml/qjsonbinding/data/array.3.json | 1 + tests/auto/qml/qjsonbinding/data/array.4.json | 1 + tests/auto/qml/qjsonbinding/data/empty.json | 0 tests/auto/qml/qjsonbinding/data/false.json | 1 + tests/auto/qml/qjsonbinding/data/null.json | 1 + tests/auto/qml/qjsonbinding/data/number.0.json | 1 + tests/auto/qml/qjsonbinding/data/number.1.json | 1 + tests/auto/qml/qjsonbinding/data/object.0.json | 1 + tests/auto/qml/qjsonbinding/data/object.1.json | 1 + tests/auto/qml/qjsonbinding/data/object.2.json | 1 + tests/auto/qml/qjsonbinding/data/object.3.json | 1 + tests/auto/qml/qjsonbinding/data/object.4.json | 1 + tests/auto/qml/qjsonbinding/data/string.0.json | 1 + tests/auto/qml/qjsonbinding/data/true.json | 1 + tests/auto/qml/qjsonbinding/qjsonbinding.pro | 16 + tests/auto/qml/qjsonbinding/tst_qjsonbinding.cpp | 535 +++++++++++++++++++++++ tests/auto/qml/qml.pro | 1 + 20 files changed, 568 insertions(+) create mode 100644 tests/auto/qml/qjsonbinding/data/array.0.json create mode 100644 tests/auto/qml/qjsonbinding/data/array.1.json create mode 100644 tests/auto/qml/qjsonbinding/data/array.2.json create mode 100644 tests/auto/qml/qjsonbinding/data/array.3.json create mode 100644 tests/auto/qml/qjsonbinding/data/array.4.json create mode 100644 tests/auto/qml/qjsonbinding/data/empty.json create mode 100644 tests/auto/qml/qjsonbinding/data/false.json create mode 100644 tests/auto/qml/qjsonbinding/data/null.json create mode 100644 tests/auto/qml/qjsonbinding/data/number.0.json create mode 100644 tests/auto/qml/qjsonbinding/data/number.1.json create mode 100644 tests/auto/qml/qjsonbinding/data/object.0.json create mode 100644 tests/auto/qml/qjsonbinding/data/object.1.json create mode 100644 tests/auto/qml/qjsonbinding/data/object.2.json create mode 100644 tests/auto/qml/qjsonbinding/data/object.3.json create mode 100644 tests/auto/qml/qjsonbinding/data/object.4.json create mode 100644 tests/auto/qml/qjsonbinding/data/string.0.json create mode 100644 tests/auto/qml/qjsonbinding/data/true.json create mode 100644 tests/auto/qml/qjsonbinding/qjsonbinding.pro create mode 100644 tests/auto/qml/qjsonbinding/tst_qjsonbinding.cpp (limited to 'tests/auto') diff --git a/tests/auto/qml/qjsonbinding/data/array.0.json b/tests/auto/qml/qjsonbinding/data/array.0.json new file mode 100644 index 0000000000..fe51488c70 --- /dev/null +++ b/tests/auto/qml/qjsonbinding/data/array.0.json @@ -0,0 +1 @@ +[] diff --git a/tests/auto/qml/qjsonbinding/data/array.1.json b/tests/auto/qml/qjsonbinding/data/array.1.json new file mode 100644 index 0000000000..3214bfe58c --- /dev/null +++ b/tests/auto/qml/qjsonbinding/data/array.1.json @@ -0,0 +1 @@ +[123] diff --git a/tests/auto/qml/qjsonbinding/data/array.2.json b/tests/auto/qml/qjsonbinding/data/array.2.json new file mode 100644 index 0000000000..7fd87cd054 --- /dev/null +++ b/tests/auto/qml/qjsonbinding/data/array.2.json @@ -0,0 +1 @@ +[true,false,null,"hello"] diff --git a/tests/auto/qml/qjsonbinding/data/array.3.json b/tests/auto/qml/qjsonbinding/data/array.3.json new file mode 100644 index 0000000000..3b418fce74 --- /dev/null +++ b/tests/auto/qml/qjsonbinding/data/array.3.json @@ -0,0 +1 @@ +[{"a":42}] diff --git a/tests/auto/qml/qjsonbinding/data/array.4.json b/tests/auto/qml/qjsonbinding/data/array.4.json new file mode 100644 index 0000000000..55e9fdce97 --- /dev/null +++ b/tests/auto/qml/qjsonbinding/data/array.4.json @@ -0,0 +1 @@ +[[[42]],[]] diff --git a/tests/auto/qml/qjsonbinding/data/empty.json b/tests/auto/qml/qjsonbinding/data/empty.json new file mode 100644 index 0000000000..e69de29bb2 diff --git a/tests/auto/qml/qjsonbinding/data/false.json b/tests/auto/qml/qjsonbinding/data/false.json new file mode 100644 index 0000000000..c508d5366f --- /dev/null +++ b/tests/auto/qml/qjsonbinding/data/false.json @@ -0,0 +1 @@ +false diff --git a/tests/auto/qml/qjsonbinding/data/null.json b/tests/auto/qml/qjsonbinding/data/null.json new file mode 100644 index 0000000000..19765bd501 --- /dev/null +++ b/tests/auto/qml/qjsonbinding/data/null.json @@ -0,0 +1 @@ +null diff --git a/tests/auto/qml/qjsonbinding/data/number.0.json b/tests/auto/qml/qjsonbinding/data/number.0.json new file mode 100644 index 0000000000..190a18037c --- /dev/null +++ b/tests/auto/qml/qjsonbinding/data/number.0.json @@ -0,0 +1 @@ +123 diff --git a/tests/auto/qml/qjsonbinding/data/number.1.json b/tests/auto/qml/qjsonbinding/data/number.1.json new file mode 100644 index 0000000000..c07e7a1490 --- /dev/null +++ b/tests/auto/qml/qjsonbinding/data/number.1.json @@ -0,0 +1 @@ +42.35 diff --git a/tests/auto/qml/qjsonbinding/data/object.0.json b/tests/auto/qml/qjsonbinding/data/object.0.json new file mode 100644 index 0000000000..0967ef424b --- /dev/null +++ b/tests/auto/qml/qjsonbinding/data/object.0.json @@ -0,0 +1 @@ +{} diff --git a/tests/auto/qml/qjsonbinding/data/object.1.json b/tests/auto/qml/qjsonbinding/data/object.1.json new file mode 100644 index 0000000000..bde58e7952 --- /dev/null +++ b/tests/auto/qml/qjsonbinding/data/object.1.json @@ -0,0 +1 @@ +{"foo":123} diff --git a/tests/auto/qml/qjsonbinding/data/object.2.json b/tests/auto/qml/qjsonbinding/data/object.2.json new file mode 100644 index 0000000000..d6f25a1488 --- /dev/null +++ b/tests/auto/qml/qjsonbinding/data/object.2.json @@ -0,0 +1 @@ +{"a":true,"b":false,"c":null,"d":"hello"} diff --git a/tests/auto/qml/qjsonbinding/data/object.3.json b/tests/auto/qml/qjsonbinding/data/object.3.json new file mode 100644 index 0000000000..9b7611740f --- /dev/null +++ b/tests/auto/qml/qjsonbinding/data/object.3.json @@ -0,0 +1 @@ +{"a":{"b":{"c":42}}} diff --git a/tests/auto/qml/qjsonbinding/data/object.4.json b/tests/auto/qml/qjsonbinding/data/object.4.json new file mode 100644 index 0000000000..377313739d --- /dev/null +++ b/tests/auto/qml/qjsonbinding/data/object.4.json @@ -0,0 +1 @@ +{"a":[],"b":[42],"c":{"d":null}} diff --git a/tests/auto/qml/qjsonbinding/data/string.0.json b/tests/auto/qml/qjsonbinding/data/string.0.json new file mode 100644 index 0000000000..3580093b9d --- /dev/null +++ b/tests/auto/qml/qjsonbinding/data/string.0.json @@ -0,0 +1 @@ +"hello" diff --git a/tests/auto/qml/qjsonbinding/data/true.json b/tests/auto/qml/qjsonbinding/data/true.json new file mode 100644 index 0000000000..27ba77ddaf --- /dev/null +++ b/tests/auto/qml/qjsonbinding/data/true.json @@ -0,0 +1 @@ +true diff --git a/tests/auto/qml/qjsonbinding/qjsonbinding.pro b/tests/auto/qml/qjsonbinding/qjsonbinding.pro new file mode 100644 index 0000000000..92e5b7a746 --- /dev/null +++ b/tests/auto/qml/qjsonbinding/qjsonbinding.pro @@ -0,0 +1,16 @@ +CONFIG += testcase +TARGET = tst_qjsonbinding +macx:CONFIG -= app_bundle + +SOURCES += tst_qjsonbinding.cpp +INCLUDEPATH += ../../shared + +include (../../shared/util.pri) + +# QMAKE_CXXFLAGS = -fprofile-arcs -ftest-coverage +# LIBS += -lgcov + +TESTDATA = data/* + +CONFIG += parallel_test +QT += core qml testlib diff --git a/tests/auto/qml/qjsonbinding/tst_qjsonbinding.cpp b/tests/auto/qml/qjsonbinding/tst_qjsonbinding.cpp new file mode 100644 index 0000000000..09b256288a --- /dev/null +++ b/tests/auto/qml/qjsonbinding/tst_qjsonbinding.cpp @@ -0,0 +1,535 @@ +/**************************************************************************** +** +** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/ +** +** This file is part of the test suite of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** 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, Nokia gives you certain additional +** rights. These rights are described in the Nokia 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. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ +#include +#include +#include "../../shared/util.h" + +Q_DECLARE_METATYPE(QJsonValue::Type) + +class JsonPropertyObject : public QObject +{ + Q_OBJECT + Q_PROPERTY(QJsonValue value READ value WRITE setValue) + Q_PROPERTY(QJsonObject object READ object WRITE setObject) + Q_PROPERTY(QJsonArray array READ array WRITE setArray) +public: + QJsonValue value() const { return m_value; } + void setValue(const QJsonValue &v) { m_value = v; } + QJsonObject object() const { return m_object; } + void setObject(const QJsonObject &o) { m_object = o; } + QJsonArray array() const { return m_array; } + void setArray(const QJsonArray &a) { m_array = a; } + +private: + QJsonValue m_value; + QJsonObject m_object; + QJsonArray m_array; +}; + +class tst_qjsonbinding : public QQmlDataTest +{ + Q_OBJECT +public: + tst_qjsonbinding() {} + +private slots: + void cppJsConversion_data(); + void cppJsConversion(); + + void readValueProperty_data(); + void readValueProperty(); + void readObjectOrArrayProperty_data(); + void readObjectOrArrayProperty(); + + void writeValueProperty_data(); + void writeValueProperty(); + void writeObjectOrArrayProperty_data(); + void writeObjectOrArrayProperty(); + + void writeProperty_incompatibleType_data(); + void writeProperty_incompatibleType(); + + void writeProperty_javascriptExpression_data(); + void writeProperty_javascriptExpression(); + +private: + QByteArray readAsUtf8(const QString &fileName); + static QJsonValue valueFromJson(const QByteArray &json); + + void addPrimitiveDataTestFiles(); + void addObjectDataTestFiles(); + void addArrayDataTestFiles(); +}; + +QByteArray tst_qjsonbinding::readAsUtf8(const QString &fileName) +{ + QFile file(testFile(fileName)); + file.open(QIODevice::ReadOnly); + QTextStream stream(&file); + return stream.readAll().trimmed().toUtf8(); +} + +QJsonValue tst_qjsonbinding::valueFromJson(const QByteArray &json) +{ + if (json.isEmpty()) + return QJsonValue(QJsonValue::Undefined); + + QJsonDocument doc = QJsonDocument::fromJson(json); + if (!doc.isEmpty()) + return doc.isObject() ? QJsonValue(doc.object()) : QJsonValue(doc.array()); + + // QJsonDocument::fromJson() only handles objects and arrays... + // Wrap the JSON inside a dummy object and extract the value. + QByteArray wrappedJson = "{\"prop\":" + json + "}"; + doc = QJsonDocument::fromJson(wrappedJson); + Q_ASSERT(doc.isObject()); + return doc.object().value("prop"); +} + +void tst_qjsonbinding::addPrimitiveDataTestFiles() +{ + QTest::newRow("true") << "true.json"; + QTest::newRow("false") << "false.json"; + + QTest::newRow("null") << "null.json"; + + QTest::newRow("number.0") << "number.0.json"; + QTest::newRow("number.1") << "number.1.json"; + + QTest::newRow("string.0") << "string.0.json"; + + QTest::newRow("undefined") << "empty.json"; +} + +void tst_qjsonbinding::addObjectDataTestFiles() +{ + QTest::newRow("object.0") << "object.0.json"; + QTest::newRow("object.1") << "object.1.json"; + QTest::newRow("object.2") << "object.2.json"; + QTest::newRow("object.3") << "object.3.json"; + QTest::newRow("object.4") << "object.4.json"; +} + +void tst_qjsonbinding::addArrayDataTestFiles() +{ + QTest::newRow("array.0") << "array.0.json"; + QTest::newRow("array.1") << "array.1.json"; + QTest::newRow("array.2") << "array.2.json"; + QTest::newRow("array.3") << "array.3.json"; + QTest::newRow("array.4") << "array.4.json"; +} + +void tst_qjsonbinding::cppJsConversion_data() +{ + QTest::addColumn("fileName"); + + addPrimitiveDataTestFiles(); + addObjectDataTestFiles(); + addArrayDataTestFiles(); +} + +void tst_qjsonbinding::cppJsConversion() +{ + QFETCH(QString, fileName); + + QByteArray json = readAsUtf8(fileName); + QJsonValue jsonValue = valueFromJson(json); + + QJSEngine eng; + QJSValue stringify = eng.globalObject().property("JSON").property("stringify"); + QVERIFY(stringify.isCallable()); + + { + QJSValue jsValue = eng.toScriptValue(jsonValue); + QVERIFY(!jsValue.isVariant()); + switch (jsonValue.type()) { + case QJsonValue::Null: + QVERIFY(jsValue.isNull()); + break; + case QJsonValue::Bool: + QVERIFY(jsValue.isBool()); + QCOMPARE(jsValue.toBool(), jsonValue.toBool()); + break; + case QJsonValue::Double: + QVERIFY(jsValue.isNumber()); + QCOMPARE(jsValue.toNumber(), jsonValue.toDouble()); + break; + case QJsonValue::String: + QVERIFY(jsValue.isString()); + QCOMPARE(jsValue.toString(), jsonValue.toString()); + break; + case QJsonValue::Array: + QVERIFY(jsValue.isArray()); + break; + case QJsonValue::Object: + QVERIFY(jsValue.isObject()); + break; + case QJsonValue::Undefined: + QVERIFY(jsValue.isUndefined()); + break; + } + + if (jsValue.isUndefined()) { + QVERIFY(json.isEmpty()); + } else { + QJSValue stringified = stringify.call(QJSValueList() << jsValue); + QVERIFY(!stringified.isError()); + QCOMPARE(stringified.toString().toUtf8(), json); + } + + QJsonValue roundtrip = qjsvalue_cast(jsValue); + // Workarounds for QTBUG-25164 + if (jsonValue.isObject() && jsonValue.toObject().isEmpty()) + QVERIFY(roundtrip.isObject() && roundtrip.toObject().isEmpty()); + else if (jsonValue.isArray() && jsonValue.toArray().isEmpty()) + QVERIFY(roundtrip.isArray() && roundtrip.toArray().isEmpty()); + else + QCOMPARE(roundtrip, jsonValue); + } + + if (jsonValue.isObject()) { + QJsonObject jsonObject = jsonValue.toObject(); + QJSValue jsObject = eng.toScriptValue(jsonObject); + QVERIFY(!jsObject.isVariant()); + QVERIFY(jsObject.isObject()); + + QJSValue stringified = stringify.call(QJSValueList() << jsObject); + QVERIFY(!stringified.isError()); + QCOMPARE(stringified.toString().toUtf8(), json); + + QJsonObject roundtrip = qjsvalue_cast(jsObject); + QCOMPARE(roundtrip, jsonObject); + } else if (jsonValue.isArray()) { + QJsonArray jsonArray = jsonValue.toArray(); + QJSValue jsArray = eng.toScriptValue(jsonArray); + QVERIFY(!jsArray.isVariant()); + QVERIFY(jsArray.isArray()); + + QJSValue stringified = stringify.call(QJSValueList() << jsArray); + QVERIFY(!stringified.isError()); + QCOMPARE(stringified.toString().toUtf8(), json); + + QJsonArray roundtrip = qjsvalue_cast(jsArray); + QCOMPARE(roundtrip, jsonArray); + } +} + +void tst_qjsonbinding::readValueProperty_data() +{ + cppJsConversion_data(); +} + +void tst_qjsonbinding::readValueProperty() +{ + QFETCH(QString, fileName); + + QByteArray json = readAsUtf8(fileName); + QJsonValue jsonValue = valueFromJson(json); + + QJSEngine eng; + JsonPropertyObject obj; + obj.setValue(jsonValue); + eng.globalObject().setProperty("obj", eng.newQObject(&obj)); + QJSValue stringified = eng.evaluate( + "var v = obj.value; (typeof v == 'undefined') ? '' : JSON.stringify(v)"); + QVERIFY(!stringified.isError()); + QCOMPARE(stringified.toString().toUtf8(), json); +} + +void tst_qjsonbinding::readObjectOrArrayProperty_data() +{ + QTest::addColumn("fileName"); + + addObjectDataTestFiles(); + addArrayDataTestFiles(); +} + +void tst_qjsonbinding::readObjectOrArrayProperty() +{ + QFETCH(QString, fileName); + + QByteArray json = readAsUtf8(fileName); + QJsonValue jsonValue = valueFromJson(json); + QVERIFY(jsonValue.isObject() || jsonValue.isArray()); + + QJSEngine eng; + JsonPropertyObject obj; + if (jsonValue.isObject()) + obj.setObject(jsonValue.toObject()); + else + obj.setArray(jsonValue.toArray()); + eng.globalObject().setProperty("obj", eng.newQObject(&obj)); + + QJSValue stringified = eng.evaluate( + QString::fromLatin1("JSON.stringify(obj.%0)").arg( + jsonValue.isObject() ? "object" : "array")); + QVERIFY(!stringified.isError()); + QCOMPARE(stringified.toString().toUtf8(), json); +} + +void tst_qjsonbinding::writeValueProperty_data() +{ + readValueProperty_data(); +} + +void tst_qjsonbinding::writeValueProperty() +{ + QFETCH(QString, fileName); + + QByteArray json = readAsUtf8(fileName); + QJsonValue jsonValue = valueFromJson(json); + + QJSEngine eng; + JsonPropertyObject obj; + eng.globalObject().setProperty("obj", eng.newQObject(&obj)); + + QJSValue fun = eng.evaluate( + "(function(json) {" + " void(obj.value = (json == '') ? undefined : JSON.parse(json));" + "})"); + QVERIFY(fun.isCallable()); + + QVERIFY(obj.value().isNull()); + QVERIFY(fun.call(QJSValueList() << QString::fromUtf8(json)).isUndefined()); + + // Workarounds for QTBUG-25164 + if (jsonValue.isObject() && jsonValue.toObject().isEmpty()) + QVERIFY(obj.value().isObject() && obj.value().toObject().isEmpty()); + else if (jsonValue.isArray() && jsonValue.toArray().isEmpty()) + QVERIFY(obj.value().isArray() && obj.value().toArray().isEmpty()); + else + QCOMPARE(obj.value(), jsonValue); +} + +void tst_qjsonbinding::writeObjectOrArrayProperty_data() +{ + readObjectOrArrayProperty_data(); +} + +void tst_qjsonbinding::writeObjectOrArrayProperty() +{ + QFETCH(QString, fileName); + + QByteArray json = readAsUtf8(fileName); + QJsonValue jsonValue = valueFromJson(json); + QVERIFY(jsonValue.isObject() || jsonValue.isArray()); + + QJSEngine eng; + JsonPropertyObject obj; + eng.globalObject().setProperty("obj", eng.newQObject(&obj)); + + QJSValue fun = eng.evaluate( + QString::fromLatin1( + "(function(json) {" + " void(obj.%0 = JSON.parse(json));" + "})").arg(jsonValue.isObject() ? "object" : "array") + ); + QVERIFY(fun.isCallable()); + + QVERIFY(obj.object().isEmpty() && obj.array().isEmpty()); + QVERIFY(fun.call(QJSValueList() << QString::fromUtf8(json)).isUndefined()); + + if (jsonValue.isObject()) + QCOMPARE(obj.object(), jsonValue.toObject()); + else + QCOMPARE(obj.array(), jsonValue.toArray()); +} + +void tst_qjsonbinding::writeProperty_incompatibleType_data() +{ + QTest::addColumn("property"); + QTest::addColumn("expression"); + + QTest::newRow("value=function") << "value" << "(function(){})"; + + QTest::newRow("object=undefined") << "object" << "undefined"; + QTest::newRow("object=null") << "object" << "null"; + QTest::newRow("object=false") << "object" << "false"; + QTest::newRow("object=true") << "object" << "true"; + QTest::newRow("object=123") << "object" << "123"; + QTest::newRow("object=42.35") << "object" << "42.35"; + QTest::newRow("object='foo'") << "object" << "'foo'"; + QTest::newRow("object=[]") << "object" << "[]"; + QTest::newRow("object=function") << "object" << "(function(){})"; + + QTest::newRow("array=undefined") << "array" << "undefined"; + QTest::newRow("array=null") << "array" << "null"; + QTest::newRow("array=false") << "array" << "false"; + QTest::newRow("array=true") << "array" << "true"; + QTest::newRow("array=123") << "array" << "123"; + QTest::newRow("array=42.35") << "array" << "42.35"; + QTest::newRow("array='foo'") << "array" << "'foo'"; + QTest::newRow("array={}") << "array" << "{}"; + QTest::newRow("array=function") << "array" << "(function(){})"; +} + +void tst_qjsonbinding::writeProperty_incompatibleType() +{ + QFETCH(QString, property); + QFETCH(QString, expression); + + QJSEngine eng; + JsonPropertyObject obj; + eng.globalObject().setProperty("obj", eng.newQObject(&obj)); + + QJSValue ret = eng.evaluate(QString::fromLatin1("obj.%0 = %1") + .arg(property).arg(expression)); + QEXPECT_FAIL("value=function", "See 'XXX TODO: uncomment the following lines' in qv8qobjectwrapper.cpp", Abort); + QEXPECT_FAIL("object=function", "See 'XXX TODO: uncomment the following lines' in qv8qobjectwrapper.cpp", Abort); + QEXPECT_FAIL("array=function", "See 'XXX TODO: uncomment the following lines' in qv8qobjectwrapper.cpp", Abort); + QVERIFY(ret.isError()); + QVERIFY(ret.toString().contains("Cannot assign")); +} + +void tst_qjsonbinding::writeProperty_javascriptExpression_data() +{ + QTest::addColumn("property"); + QTest::addColumn("expression"); + QTest::addColumn("expectedJson"); + + // Function properties should be omitted. + QTest::newRow("value = object with function property") + << "value" << "{ foo: function() {} }" << "{}"; + QTest::newRow("object = object with function property") + << "object" << "{ foo: function() {} }" << "{}"; + QTest::newRow("array = array with function property") + << "array" << "[function() {}]" << "[]"; + + // Inherited properties should not be included. + QTest::newRow("value = object with inherited property") + << "value" << "{ __proto__: { proto_foo: 123 } }" + << "{}"; + QTest::newRow("value = object with inherited property 2") + << "value" << "{ foo: 123, __proto__: { proto_foo: 456 } }" + << "{\"foo\":123}"; + QTest::newRow("value = array with inherited property") + << "value" << "(function() { var a = []; a.__proto__ = { proto_foo: 123 }; return a; })()" + << "[]"; + QTest::newRow("value = array with inherited property 2") + << "value" << "(function() { var a = [10, 20]; a.__proto__ = { proto_foo: 123 }; return a; })()" + << "[10,20]"; + + QTest::newRow("object = object with inherited property") + << "object" << "{ __proto__: { proto_foo: 123 } }" + << "{}"; + QTest::newRow("object = object with inherited property 2") + << "object" << "{ foo: 123, __proto__: { proto_foo: 456 } }" + << "{\"foo\":123}"; + QTest::newRow("array = array with inherited property") + << "array" << "(function() { var a = []; a.__proto__ = { proto_foo: 123 }; return a; })()" + << "[]"; + QTest::newRow("array = array with inherited property 2") + << "array" << "(function() { var a = [10, 20]; a.__proto__ = { proto_foo: 123 }; return a; })()" + << "[10,20]"; + + // Non-enumerable properties should be included. + QTest::newRow("value = object with non-enumerable property") + << "value" << "Object.defineProperty({}, 'foo', { value: 123, enumerable: false })" + << "{\"foo\":123}"; + QTest::newRow("object = object with non-enumerable property") + << "object" << "Object.defineProperty({}, 'foo', { value: 123, enumerable: false })" + << "{\"foo\":123}"; + + // Cyclic data structures are permitted, but the cyclic links become + // empty objects. + QTest::newRow("value = cyclic object") + << "value" << "(function() { var o = { foo: 123 }; o.o = o; return o; })()" + << "{\"foo\":123,\"o\":{}}"; + QTest::newRow("value = cyclic array") + << "value" << "(function() { var a = [10, 20]; a.push(a); return a; })()" + << "[10,20,[]]"; + QTest::newRow("object = cyclic object") + << "object" << "(function() { var o = { bar: true }; o.o = o; return o; })()" + << "{\"bar\":true,\"o\":{}}"; + QTest::newRow("array = cyclic array") + << "array" << "(function() { var a = [30, 40]; a.unshift(a); return a; })()" + << "[[],30,40]"; + + // Properties with undefined value are excluded. + QTest::newRow("value = { foo: undefined }") + << "value" << "{ foo: undefined }" << "{}"; + QTest::newRow("value = { foo: undefined, bar: 123 }") + << "value" << "{ foo: undefined, bar: 123 }" << "{\"bar\":123}"; + QTest::newRow("value = { foo: 456, bar: undefined }") + << "value" << "{ foo: 456, bar: undefined }" << "{\"foo\":456}"; + + QTest::newRow("object = { foo: undefined }") + << "object" << "{ foo: undefined }" << "{}"; + QTest::newRow("object = { foo: undefined, bar: 123 }") + << "object" << "{ foo: undefined, bar: 123 }" << "{\"bar\":123}"; + QTest::newRow("object = { foo: 456, bar: undefined }") + << "object" << "{ foo: 456, bar: undefined }" << "{\"foo\":456}"; + + // QJsonArray::append() implicitly converts undefined values to null. + QTest::newRow("value = [undefined]") + << "value" << "[undefined]" << "[null]"; + QTest::newRow("value = [undefined, 10]") + << "value" << "[undefined, 10]" << "[null,10]"; + QTest::newRow("value = [10, undefined, 20]") + << "value" << "[10, undefined, 20]" << "[10,null,20]"; + + QTest::newRow("array = [undefined]") + << "array" << "[undefined]" << "[null]"; + QTest::newRow("array = [undefined, 10]") + << "array" << "[undefined, 10]" << "[null,10]"; + QTest::newRow("array = [10, undefined, 20]") + << "array" << "[10, undefined, 20]" << "[10,null,20]"; +} + +void tst_qjsonbinding::writeProperty_javascriptExpression() +{ + QFETCH(QString, property); + QFETCH(QString, expression); + QFETCH(QString, expectedJson); + + QJSEngine eng; + JsonPropertyObject obj; + eng.globalObject().setProperty("obj", eng.newQObject(&obj)); + + QJSValue ret = eng.evaluate(QString::fromLatin1("obj.%0 = %1; JSON.stringify(obj.%0)") + .arg(property).arg(expression)); + QVERIFY(!ret.isError()); + QCOMPARE(ret.toString(), expectedJson); +} + +QTEST_MAIN(tst_qjsonbinding) + +#include "tst_qjsonbinding.moc" diff --git a/tests/auto/qml/qml.pro b/tests/auto/qml/qml.pro index 0657ea891e..3166c3b6e1 100644 --- a/tests/auto/qml/qml.pro +++ b/tests/auto/qml/qml.pro @@ -8,6 +8,7 @@ PUBLICTESTS += \ qjsengine \ qjsvalue \ qjsvalueiterator \ + qjsonbinding \ qmlmin \ qmlplugindump \ qqmlcomponent \ -- cgit v1.2.3