/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the test suite of the Qt Toolkit. ** ** $QT_BEGIN_LICENSE:GPL-EXCEPT$ ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and The Qt Company. For licensing terms ** and conditions see https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 3 as published by the Free Software ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #include #include #include #include #include #include #include #include #include "../../shared/util.h" #include "testtypes.h" QT_BEGIN_NAMESPACE extern int qt_defaultDpi(void); QT_END_NAMESPACE // There is some overlap between the qqmllanguage and qqmlvaluetypes // test here, but it needs to be separate to ensure that no QML plugins // are loaded prior to these tests, which could contaminate the type // system with more providers. class tst_qqmlvaluetypeproviders : public QQmlDataTest { Q_OBJECT public: tst_qqmlvaluetypeproviders() {} private slots: void initTestCase(); void qtqmlValueTypes(); // This test function _must_ be the first test function run. void qtquickValueTypes(); void comparisonSemantics(); void cppIntegration(); void jsObjectConversion(); void invokableFunctions(); void userType(); void changedSignal(); }; void tst_qqmlvaluetypeproviders::initTestCase() { QQmlDataTest::initTestCase(); registerTypes(); } void tst_qqmlvaluetypeproviders::qtqmlValueTypes() { QQmlEngine e; QQmlComponent component(&e, testFileUrl("qtqmlValueTypes.qml")); QVERIFY(!component.isError()); QVERIFY(component.errors().isEmpty()); QObject *object = component.create(); QVERIFY(object != nullptr); QVERIFY(object->property("qtqmlTypeSuccess").toBool()); QVERIFY(object->property("qtquickTypeSuccess").toBool()); delete object; } void tst_qqmlvaluetypeproviders::qtquickValueTypes() { QQmlEngine e; QQmlComponent component(&e, testFileUrl("qtquickValueTypes.qml")); QVERIFY(!component.isError()); QVERIFY(component.errors().isEmpty()); QObject *object = component.create(); QVERIFY(object != nullptr); QVERIFY(object->property("qtqmlTypeSuccess").toBool()); QVERIFY(object->property("qtquickTypeSuccess").toBool()); delete object; } void tst_qqmlvaluetypeproviders::comparisonSemantics() { QQmlEngine e; QQmlComponent component(&e, testFileUrl("comparisonSemantics.qml")); QVERIFY(!component.isError()); QVERIFY(component.errors().isEmpty()); QObject *object = component.create(); QVERIFY(object != nullptr); QVERIFY(object->property("comparisonSuccess").toBool()); delete object; } void tst_qqmlvaluetypeproviders::cppIntegration() { QQmlEngine e; QQmlComponent component(&e, testFileUrl("cppIntegration.qml")); QVERIFY(!component.isError()); QVERIFY(component.errors().isEmpty()); QObject *object = component.create(); QVERIFY(object != nullptr); // ensure accessing / comparing / assigning cpp-defined props // and qml-defined props works in QML. QVERIFY(object->property("success").toBool()); // ensure types match QCOMPARE(object->property("g").userType(), object->property("rectf").userType()); QCOMPARE(object->property("p").userType(), object->property("pointf").userType()); QCOMPARE(object->property("z").userType(), object->property("sizef").userType()); QCOMPARE(object->property("v2").userType(), object->property("vector2").userType()); QCOMPARE(object->property("v3").userType(), object->property("vector").userType()); QCOMPARE(object->property("v4").userType(), object->property("vector4").userType()); QCOMPARE(object->property("q").userType(), object->property("quaternion").userType()); QCOMPARE(object->property("m").userType(), object->property("matrix").userType()); QCOMPARE(object->property("c").userType(), object->property("color").userType()); QCOMPARE(object->property("f").userType(), object->property("font").userType()); // ensure values match QCOMPARE(object->property("g").value(), object->property("rectf").value()); QCOMPARE(object->property("p").value(), object->property("pointf").value()); QCOMPARE(object->property("z").value(), object->property("sizef").value()); QCOMPARE(object->property("v2").value(), object->property("vector2").value()); QCOMPARE(object->property("v3").value(), object->property("vector").value()); QCOMPARE(object->property("v4").value(), object->property("vector4").value()); QCOMPARE(object->property("q").value(), object->property("quaternion").value()); QCOMPARE(object->property("m").value(), object->property("matrix").value()); QCOMPARE(object->property("c").value(), object->property("color").value()); QCOMPARE(object->property("f").value(), object->property("font").value()); delete object; } void tst_qqmlvaluetypeproviders::jsObjectConversion() { QQmlEngine e; QQmlComponent component(&e, testFileUrl("jsObjectConversion.qml")); QVERIFY(!component.isError()); QVERIFY(component.errors().isEmpty()); QObject *object = component.create(); QVERIFY(object != nullptr); QVERIFY(object->property("qtquickTypeSuccess").toBool()); delete object; } void tst_qqmlvaluetypeproviders::invokableFunctions() { QQmlEngine e; QQmlComponent component(&e, testFileUrl("invokableFunctions.qml")); QVERIFY(!component.isError()); QVERIFY(component.errors().isEmpty()); QObject *object = component.create(); QVERIFY(object != nullptr); QVERIFY(object->property("complete").toBool()); QVERIFY(object->property("success").toBool()); delete object; } namespace { // A value-type class to export to QML class TestValue { public: TestValue() : m_p1(0), m_p2(0.0) {} TestValue(int p1, double p2) : m_p1(p1), m_p2(p2) {} TestValue(const TestValue &other) : m_p1(other.m_p1), m_p2(other.m_p2) {} ~TestValue() {} TestValue &operator=(const TestValue &other) { m_p1 = other.m_p1; m_p2 = other.m_p2; return *this; } int property1() const { return m_p1; } void setProperty1(int p1) { m_p1 = p1; } double property2() const { return m_p2; } void setProperty2(double p2) { m_p2 = p2; } bool operator==(const TestValue &other) const { return (m_p1 == other.m_p1) && (m_p2 == other.m_p2); } bool operator!=(const TestValue &other) const { return !operator==(other); } bool operator<(const TestValue &other) const { if (m_p1 < other.m_p1) return true; return m_p2 < other.m_p2; } private: int m_p1; double m_p2; }; } Q_DECLARE_METATYPE(TestValue); namespace { class TestValueType { TestValue v; Q_GADGET Q_PROPERTY(int property1 READ property1 WRITE setProperty1) Q_PROPERTY(double property2 READ property2 WRITE setProperty2) public: Q_INVOKABLE QString toString() const { return QString::number(property1()) + QLatin1Char(',') + QString::number(property2()); } int property1() const { return v.property1(); } void setProperty1(int p1) { v.setProperty1(p1); } double property2() const { return v.property2(); } void setProperty2(double p2) { v.setProperty2(p2); } }; class TestValueTypeProvider : public QQmlValueTypeProvider { public: const QMetaObject *getMetaObjectForMetaType(int type) { if (type == qMetaTypeId()) return &TestValueType::staticMetaObject; return nullptr; } }; TestValueTypeProvider *getValueTypeProvider() { static TestValueTypeProvider valueTypeProvider; return &valueTypeProvider; } bool initializeProviders() { QQml_addValueTypeProvider(getValueTypeProvider()); return true; } const bool initialized = initializeProviders(); class TestValueExporter : public QObject { Q_OBJECT Q_PROPERTY(TestValue testValue READ testValue WRITE setTestValue) public: TestValue testValue() const { return m_testValue; } void setTestValue(const TestValue &v) { m_testValue = v; } Q_INVOKABLE TestValue getTestValue() const { return TestValue(333, 666.999); } private: TestValue m_testValue; }; } void tst_qqmlvaluetypeproviders::userType() { Q_ASSERT(initialized); Q_ASSERT(qMetaTypeId() >= QMetaType::User); qRegisterMetaType(); QMetaType::registerComparators(); qmlRegisterType("Test", 1, 0, "TestValueExporter"); TestValueExporter exporter; QQmlEngine e; e.rootContext()->setContextProperty("testValueExporter", &exporter); QQmlComponent component(&e, testFileUrl("userType.qml")); QScopedPointer obj(component.create()); QVERIFY(obj != nullptr); QCOMPARE(obj->property("success").toBool(), true); } void tst_qqmlvaluetypeproviders::changedSignal() { QQmlEngine e; QQmlComponent component(&e, testFileUrl("changedSignal.qml")); QVERIFY(!component.isError()); QVERIFY(component.errors().isEmpty()); QScopedPointer object(component.create()); QVERIFY(object != nullptr); QVERIFY(object->property("complete").toBool()); QVERIFY(object->property("success").toBool()); } QTEST_MAIN(tst_qqmlvaluetypeproviders) #include "tst_qqmlvaluetypeproviders.moc"