diff options
Diffstat (limited to 'tests/auto/qml')
49 files changed, 946 insertions, 496 deletions
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 --- /dev/null +++ b/tests/auto/qml/qjsonbinding/data/empty.json 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 <QtTest/QtTest> +#include <QtQml/QtQml> +#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<QString>("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<QJsonValue>(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<QJsonObject>(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<QJsonArray>(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<QString>("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<QString>("property"); + QTest::addColumn<QString>("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<QString>("property"); + QTest::addColumn<QString>("expression"); + QTest::addColumn<QString>("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 6892680d79..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 \ @@ -32,7 +33,7 @@ PRIVATETESTS += \ qqmlecmascript \ qqmlcontext \ qqmlexpression \ - qqmlimageprovider \ + qqmlglobal \ qqmlinstruction \ qqmllanguage \ qqmlproperty \ 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/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, "<Unknown File>:1: TypeError: Cannot read property 'a' of undefined"); + QTest::ignoreMessage(QtWarningMsg, "<Unknown File>: TypeError: Cannot read property 'a' of undefined"); QObject *obj = component.create(&ctxt); QVariant v = obj->property("obj"); diff --git a/tests/auto/qml/qqmlecmascript/data/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/testtypes.h b/tests/auto/qml/qqmlecmascript/testtypes.h index 519f9e479a..167e944aa6 100644 --- a/tests/auto/qml/qqmlecmascript/testtypes.h +++ b/tests/auto/qml/qqmlecmascript/testtypes.h @@ -51,6 +51,7 @@ #include <QtGui/qmatrix.h> #include <QtGui/qcolor.h> #include <QtGui/qvector3d.h> +#include <QtGui/QFont> #include <QtGui/QPixmap> #include <QtCore/qdatetime.h> #include <QtQml/qjsvalue.h> diff --git a/tests/auto/qml/qqmlecmascript/tst_qqmlecmascript.cpp b/tests/auto/qml/qqmlecmascript/tst_qqmlecmascript.cpp index 273cd07986..c2d490e3c5 100644 --- a/tests/auto/qml/qqmlecmascript/tst_qqmlecmascript.cpp +++ b/tests/auto/qml/qqmlecmascript/tst_qqmlecmascript.cpp @@ -202,6 +202,7 @@ private slots: void functionAssignment_fromJS(); void functionAssignment_fromJS_data(); void functionAssignmentfromJS_invalid(); + void functionAssignment_afterBinding(); void eval(); void function(); void functionException(); @@ -4053,6 +4054,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() @@ -4900,7 +4906,7 @@ void tst_qqmlecmascript::sequenceConversionWrite() QVERIFY(seq != 0); // we haven't registered QList<QPoint> 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"); @@ -5315,9 +5321,13 @@ void tst_qqmlecmascript::functionAssignment_fromBinding() QQmlComponent component(&engine, testFileUrl("functionAssignment.1.qml")); QString url = component.url().toString(); - QString warning = url + ":4:25: Unable to assign a function to a property."; - QTest::ignoreMessage(QtWarningMsg, warning.toLatin1().constData()); - + QString w1 = url + ":4:25: Unable to assign a function to a property of any type other than var."; + QString w2 = url + ":5:25: Invalid use of Qt.binding() in a binding declaration."; + QString w3 = url + ":6:21: 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<MyQmlObject *>(component.create()); QVERIFY(o != 0); @@ -5384,6 +5394,24 @@ 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"; // 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<int>(4)); // should have bound + //QCOMPARE(o->property("t2"), QVariant::fromValue<int>(2)); // should not have changed + QCOMPARE(o->property("t2"), QVariant::fromValue<int>(4)); // for now, function assignment = binding assignment + + delete o; +} + void tst_qqmlecmascript::eval() { QQmlComponent component(&engine, testFileUrl("eval.qml")); 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("<Unknown File>:1: Unable to assign [undefined] to int")); + QCOMPARE(warnings.at(0), QLatin1String("<Unknown File>: Unable to assign [undefined] to int")); warnings.clear(); 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 <qtest.h> +#include <qqml.h> + +#include <private/qqmlglobal_p.h> + +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/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 <qtest.h> -#include <QtTest/QtTest> -#include <QtQml/qqmlengine.h> -#include <QtQml/qqmlimageprovider.h> -#include <private/qquickimage_p.h> -#include <QImageReader> -#include <QWaitCondition> - -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<QString>("source"); - QTest::addColumn<QString>("imageId"); - QTest::addColumn<QString>("properties"); - QTest::addColumn<QSize>("size"); - QTest::addColumn<QString>("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<QQuickImage*>(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<TestQImageProvider*>(provider)->lastImageId, imageId); - else - QCOMPARE(static_cast<TestQPixmapProvider*>(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<QQuickImage*>(component.create()); - QVERIFY(obj != 0); - - delete obj; -} - -void tst_qqmlimageprovider::removeProvider_data() -{ - QTest::addColumn<QQmlImageProvider*>("provider"); - - QTest::newRow("qimage") << static_cast<QQmlImageProvider*>(new TestQImageProvider); - QTest::newRow("qpixmap") << static_cast<QQmlImageProvider*>(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<QQuickImage*>(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<int> 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<QQuickImage *> images = obj->findChildren<QQuickImage *>(); - 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/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 <qtest.h> #include <private/qqmlcompiler_p.h> +#include <QVector3D> +#include <QVector4D> + 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/qqmlmetaobject/tst_qqmlmetaobject.cpp b/tests/auto/qml/qqmlmetaobject/tst_qqmlmetaobject.cpp index f2c50ddbef..8e35c24b7d 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.signature(), "testChanged()"); + QCOMPARE(signal.name(), QByteArray("testChanged")); + QCOMPARE(signal.methodSignature(), QByteArray("testChanged()")); QCOMPARE(signal.access(), QMetaMethod::Protected); + QCOMPARE(signal.parameterCount(), 0); QCOMPARE(signal.parameterTypes(), QList<QByteArray>()); QCOMPARE(signal.parameterNames(), QList<QByteArray>()); QCOMPARE(signal.tag(), ""); - QCOMPARE(signal.typeName(), ""); + QCOMPARE(signal.typeName(), "void"); + 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<QString>("testFile"); QTest::addColumn<QString>("signature"); QTest::addColumn<QMetaMethod::MethodType>("methodType"); + QTest::addColumn<int>("returnType"); QTest::addColumn<QString>("returnTypeName"); + QTest::addColumn<QList<int> >("parameterTypes"); QTest::addColumn<QList<QByteArray> >("parameterTypeNames"); QTest::addColumn<QList<QByteArray> >("parameterNames"); QTest::newRow("testFunction()") << "method.1.qml" << "testFunction()" << QMetaMethod::Slot - << "QVariant" + << int(QMetaType::QVariant) << "QVariant" + << QList<int>() << QList<QByteArray>() << QList<QByteArray>(); QTest::newRow("testFunction(foo)") << "method.2.qml" << "testFunction(QVariant)" << QMetaMethod::Slot - << "QVariant" + << int(QMetaType::QVariant) << "QVariant" + << (QList<int>() << QMetaType::QVariant) << (QList<QByteArray>() << "QVariant") << (QList<QByteArray>() << "foo"); QTest::newRow("testFunction(foo, bar, baz)") << "method.3.qml" << "testFunction(QVariant,QVariant,QVariant)" << QMetaMethod::Slot - << "QVariant" + << int(QMetaType::QVariant) << "QVariant" + << (QList<int>() << QMetaType::QVariant << QMetaType::QVariant << QMetaType::QVariant) << (QList<QByteArray>() << "QVariant" << "QVariant" << "QVariant") << (QList<QByteArray>() << "foo" << "bar" << "baz"); QTest::newRow("testSignal") << "signal.1.qml" << "testSignal()" << QMetaMethod::Signal - << "" + << int(QMetaType::Void) << "void" + << QList<int>() << QList<QByteArray>() << QList<QByteArray>(); QTest::newRow("testSignal(string foo)") << "signal.2.qml" << "testSignal(QString)" << QMetaMethod::Signal - << "" + << int(QMetaType::Void) << "void" + << (QList<int>() << QMetaType::QString) << (QList<QByteArray>() << "QString") << (QList<QByteArray>() << "foo"); QTest::newRow("testSignal(int foo, bool bar, real baz)") << "signal.3.qml" << "testSignal(int,bool,double)" << QMetaMethod::Signal - << "" + << int(QMetaType::Void) << "void" + << (QList<int>() << QMetaType::Int << QMetaType::Bool << QMetaType::Double) << (QList<QByteArray>() << "int" << "bool" << "double") << (QList<QByteArray>() << "foo" << "bar" << "baz"); QTest::newRow("testSignal(variant foo, var bar)") << "signal.4.qml" << "testSignal(QVariant,QVariant)" << QMetaMethod::Signal - << "" + << int(QMetaType::Void) << "void" + << (QList<int>() << QMetaType::QVariant << QMetaType::QVariant) << (QList<QByteArray>() << "QVariant" << "QVariant") << (QList<QByteArray>() << "foo" << "bar"); QTest::newRow("testSignal(color foo, date bar, url baz)") << "signal.5.qml" << "testSignal(QColor,QDateTime,QUrl)" << QMetaMethod::Signal - << "" + << int(QMetaType::Void) << "void" + << (QList<int>() << QMetaType::QColor << QMetaType::QDateTime << QMetaType::QUrl) << (QList<QByteArray>() << "QColor" << "QDateTime" << "QUrl") << (QList<QByteArray>() << "foo" << "bar" << "baz"); QTest::newRow("testSignal(double foo)") << "signal.6.qml" << "testSignal(double)" << QMetaMethod::Signal - << "" + << int(QMetaType::Void) << "void" + << (QList<int>() << QMetaType::Double) << (QList<QByteArray>() << "double") << (QList<QByteArray>() << "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<int>, parameterTypes); QFETCH(QList<QByteArray>, parameterTypeNames); QFETCH(QList<QByteArray>, parameterNames); + QCOMPARE(parameterTypes.size(), parameterTypeNames.size()); QCOMPARE(parameterTypeNames.size(), parameterNames.size()); QQmlEngine engine; @@ -361,12 +378,21 @@ 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); + + 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; } diff --git a/tests/auto/qml/qqmlproperty/tst_qqmlproperty.cpp b/tests/auto/qml/qqmlproperty/tst_qqmlproperty.cpp index 5d7485c68d..d99ed303ba 100644 --- a/tests/auto/qml/qqmlproperty/tst_qqmlproperty.cpp +++ b/tests/auto/qml/qqmlproperty/tst_qqmlproperty.cpp @@ -164,7 +164,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); @@ -268,7 +268,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); @@ -316,7 +316,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); @@ -371,7 +371,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); @@ -419,7 +419,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); @@ -469,7 +469,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); @@ -518,7 +518,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); @@ -572,7 +572,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); @@ -620,7 +620,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); @@ -675,7 +675,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); @@ -723,7 +723,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); @@ -773,7 +773,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); @@ -822,7 +822,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); @@ -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); } } 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 d4bf23306e..c81e6771b8 100644 --- a/tests/auto/qml/qqmlqt/tst_qqmlqt.cpp +++ b/tests/auto/qml/qqmlqt/tst_qqmlqt.cpp @@ -52,6 +52,8 @@ #include <QCryptographicHash> #include <QtQuick/QQuickItem> #include <QSignalSpy> +#include <QVector3D> +#include <QVector4D> #include "../../shared/util.h" class tst_qqmlqt : public QQmlDataTest 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/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 0aa223e733..359653caa4 100644 --- a/tests/auto/qml/qqmlvaluetypes/tst_qqmlvaluetypes.cpp +++ b/tests/auto/qml/qqmlvaluetypes/tst_qqmlvaluetypes.cpp @@ -43,12 +43,12 @@ #include <QQmlEngine> #include <QQmlComponent> #include <QDebug> -#include <private/qqmlvaluetype_p.h> +#include <private/qquickvaluetypes_p.h> #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 @@ -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<MyTypeObject *>(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:13: 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<MyTypeObject *>(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 @@ -1109,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")); } |