1/****************************************************************************
2**
3** Copyright (C) 2016 The Qt Company Ltd.
4** Contact: https://www.qt.io/licensing/
5**
6** This file is part of the test suite of the Qt Toolkit.
7**
8** $QT_BEGIN_LICENSE:GPL-EXCEPT$
9** Commercial License Usage
10** Licensees holding valid commercial Qt licenses may use this file in
11** accordance with the commercial license agreement provided with the
12** Software or, alternatively, in accordance with the terms contained in
13** a written agreement between you and The Qt Company. For licensing terms
14** and conditions see https://www.qt.io/terms-conditions. For further
15** information use the contact form at https://www.qt.io/contact-us.
16**
17** GNU General Public License Usage
18** Alternatively, this file may be used under the terms of the GNU
19** General Public License version 3 as published by the Free Software
20** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
21** included in the packaging of this file. Please review the following
22** information to ensure the GNU General Public License requirements will
23** be met: https://www.gnu.org/licenses/gpl-3.0.html.
24**
25** $QT_END_LICENSE$
26**
27****************************************************************************/
28
29#include <qtest.h>
30#include <QQmlEngine>
31#include <QQmlComponent>
32#include <QQmlContext>
33#include <QDebug>
34#include <QScopedPointer>
35#include <private/qqmlglobal_p.h>
36#include <private/qquickvaluetypes_p.h>
37#include "../../shared/util.h"
38#include "testtypes.h"
39
40QT_BEGIN_NAMESPACE
41extern int qt_defaultDpi(void);
42QT_END_NAMESPACE
43
44// There is some overlap between the qqmllanguage and qqmlvaluetypes
45// test here, but it needs to be separate to ensure that no QML plugins
46// are loaded prior to these tests, which could contaminate the type
47// system with more providers.
48
49class tst_qqmlvaluetypeproviders : public QQmlDataTest
50{
51 Q_OBJECT
52public:
53 tst_qqmlvaluetypeproviders() {}
54
55private slots:
56 void initTestCase();
57
58 void qtqmlValueTypes(); // This test function _must_ be the first test function run.
59 void qtquickValueTypes();
60 void comparisonSemantics();
61 void cppIntegration();
62 void jsObjectConversion();
63 void invokableFunctions();
64 void userType();
65 void changedSignal();
66};
67
68void tst_qqmlvaluetypeproviders::initTestCase()
69{
70 QQmlDataTest::initTestCase();
71 registerTypes();
72}
73
74void tst_qqmlvaluetypeproviders::qtqmlValueTypes()
75{
76 QQmlEngine e;
77 QQmlComponent component(&e, testFileUrl(fileName: "qtqmlValueTypes.qml"));
78 QVERIFY(!component.isError());
79 QVERIFY(component.errors().isEmpty());
80 QObject *object = component.create();
81 QVERIFY(object != nullptr);
82 QVERIFY(object->property("qtqmlTypeSuccess").toBool());
83 QVERIFY(object->property("qtquickTypeSuccess").toBool());
84 delete object;
85}
86
87void tst_qqmlvaluetypeproviders::qtquickValueTypes()
88{
89 QQmlEngine e;
90 QQmlComponent component(&e, testFileUrl(fileName: "qtquickValueTypes.qml"));
91 QVERIFY(!component.isError());
92 QVERIFY(component.errors().isEmpty());
93 QObject *object = component.create();
94 QVERIFY(object != nullptr);
95 QVERIFY(object->property("qtqmlTypeSuccess").toBool());
96 QVERIFY(object->property("qtquickTypeSuccess").toBool());
97 delete object;
98}
99
100void tst_qqmlvaluetypeproviders::comparisonSemantics()
101{
102 QQmlEngine e;
103 QQmlComponent component(&e, testFileUrl(fileName: "comparisonSemantics.qml"));
104 QVERIFY(!component.isError());
105 QVERIFY(component.errors().isEmpty());
106 QObject *object = component.create();
107 QVERIFY(object != nullptr);
108 QVERIFY(object->property("comparisonSuccess").toBool());
109 delete object;
110}
111
112void tst_qqmlvaluetypeproviders::cppIntegration()
113{
114 QQmlEngine e;
115 QQmlComponent component(&e, testFileUrl(fileName: "cppIntegration.qml"));
116 QVERIFY(!component.isError());
117 QVERIFY(component.errors().isEmpty());
118 QObject *object = component.create();
119 QVERIFY(object != nullptr);
120
121 // ensure accessing / comparing / assigning cpp-defined props
122 // and qml-defined props works in QML.
123 QVERIFY(object->property("success").toBool());
124
125 // ensure types match
126 QCOMPARE(object->property("g").userType(), object->property("rectf").userType());
127 QCOMPARE(object->property("p").userType(), object->property("pointf").userType());
128 QCOMPARE(object->property("z").userType(), object->property("sizef").userType());
129 QCOMPARE(object->property("v2").userType(), object->property("vector2").userType());
130 QCOMPARE(object->property("v3").userType(), object->property("vector").userType());
131 QCOMPARE(object->property("v4").userType(), object->property("vector4").userType());
132 QCOMPARE(object->property("q").userType(), object->property("quaternion").userType());
133 QCOMPARE(object->property("m").userType(), object->property("matrix").userType());
134 QCOMPARE(object->property("c").userType(), object->property("color").userType());
135 QCOMPARE(object->property("f").userType(), object->property("font").userType());
136
137 // ensure values match
138 QCOMPARE(object->property("g").value<QRectF>(), object->property("rectf").value<QRectF>());
139 QCOMPARE(object->property("p").value<QPointF>(), object->property("pointf").value<QPointF>());
140 QCOMPARE(object->property("z").value<QSizeF>(), object->property("sizef").value<QSizeF>());
141 QCOMPARE(object->property("v2").value<QVector2D>(), object->property("vector2").value<QVector2D>());
142 QCOMPARE(object->property("v3").value<QVector3D>(), object->property("vector").value<QVector3D>());
143 QCOMPARE(object->property("v4").value<QVector4D>(), object->property("vector4").value<QVector4D>());
144 QCOMPARE(object->property("q").value<QQuaternion>(), object->property("quaternion").value<QQuaternion>());
145 QCOMPARE(object->property("m").value<QMatrix4x4>(), object->property("matrix").value<QMatrix4x4>());
146 QCOMPARE(object->property("c").value<QColor>(), object->property("color").value<QColor>());
147 QCOMPARE(object->property("f").value<QFont>(), object->property("font").value<QFont>());
148
149 delete object;
150}
151
152void tst_qqmlvaluetypeproviders::jsObjectConversion()
153{
154 QQmlEngine e;
155 QQmlComponent component(&e, testFileUrl(fileName: "jsObjectConversion.qml"));
156 QVERIFY(!component.isError());
157 QVERIFY(component.errors().isEmpty());
158 QObject *object = component.create();
159 QVERIFY(object != nullptr);
160 QVERIFY(object->property("qtquickTypeSuccess").toBool());
161 delete object;
162}
163
164void tst_qqmlvaluetypeproviders::invokableFunctions()
165{
166 QQmlEngine e;
167 QQmlComponent component(&e, testFileUrl(fileName: "invokableFunctions.qml"));
168 QVERIFY(!component.isError());
169 QVERIFY(component.errors().isEmpty());
170 QObject *object = component.create();
171 QVERIFY(object != nullptr);
172 QVERIFY(object->property("complete").toBool());
173 QVERIFY(object->property("success").toBool());
174 delete object;
175}
176
177namespace {
178
179// A value-type class to export to QML
180class TestValue
181{
182public:
183 TestValue() : m_p1(0), m_p2(0.0) {}
184 TestValue(int p1, double p2) : m_p1(p1), m_p2(p2) {}
185 TestValue(const TestValue &other) : m_p1(other.m_p1), m_p2(other.m_p2) {}
186 ~TestValue() {}
187
188 TestValue &operator=(const TestValue &other) { m_p1 = other.m_p1; m_p2 = other.m_p2; return *this; }
189
190 int property1() const { return m_p1; }
191 void setProperty1(int p1) { m_p1 = p1; }
192
193 double property2() const { return m_p2; }
194 void setProperty2(double p2) { m_p2 = p2; }
195
196 bool operator==(const TestValue &other) const { return (m_p1 == other.m_p1) && (m_p2 == other.m_p2); }
197 bool operator!=(const TestValue &other) const { return !operator==(other); }
198
199 bool operator<(const TestValue &other) const { if (m_p1 < other.m_p1) return true; return m_p2 < other.m_p2; }
200
201private:
202 int m_p1;
203 double m_p2;
204};
205
206}
207
208Q_DECLARE_METATYPE(TestValue);
209
210namespace {
211
212class TestValueType
213{
214 TestValue v;
215 Q_GADGET
216 Q_PROPERTY(int property1 READ property1 WRITE setProperty1)
217 Q_PROPERTY(double property2 READ property2 WRITE setProperty2)
218public:
219 Q_INVOKABLE QString toString() const { return QString::number(property1()) + QLatin1Char(',') + QString::number(property2()); }
220
221 int property1() const { return v.property1(); }
222 void setProperty1(int p1) { v.setProperty1(p1); }
223
224 double property2() const { return v.property2(); }
225 void setProperty2(double p2) { v.setProperty2(p2); }
226};
227
228class TestValueTypeProvider : public QQmlValueTypeProvider
229{
230public:
231 const QMetaObject *getMetaObjectForMetaType(int type)
232 {
233 if (type == qMetaTypeId<TestValue>())
234 return &TestValueType::staticMetaObject;
235
236 return nullptr;
237 }
238
239};
240
241TestValueTypeProvider *getValueTypeProvider()
242{
243 static TestValueTypeProvider valueTypeProvider;
244 return &valueTypeProvider;
245}
246
247bool initializeProviders()
248{
249 QQml_addValueTypeProvider(getValueTypeProvider());
250 return true;
251}
252
253const bool initialized = initializeProviders();
254
255class TestValueExporter : public QObject
256{
257 Q_OBJECT
258 Q_PROPERTY(TestValue testValue READ testValue WRITE setTestValue)
259 QML_NAMED_ELEMENT(TestValueExporter)
260public:
261 TestValue testValue() const { return m_testValue; }
262 void setTestValue(const TestValue &v) { m_testValue = v; }
263
264 Q_INVOKABLE TestValue getTestValue() const { return TestValue(333, 666.999); }
265
266private:
267 TestValue m_testValue;
268};
269
270}
271
272void tst_qqmlvaluetypeproviders::userType()
273{
274 Q_ASSERT(initialized);
275 Q_ASSERT(qMetaTypeId<TestValue>() >= QMetaType::User);
276
277 qRegisterMetaType<TestValue>();
278 QMetaType::registerComparators<TestValue>();
279 qmlRegisterTypesAndRevisions<TestValueExporter>(uri: "Test", versionMajor: 1);
280
281 TestValueExporter exporter;
282
283 QQmlEngine e;
284
285 QQmlComponent component(&e, testFileUrl(fileName: "userType.qml"));
286 QScopedPointer<QObject> obj(component.createWithInitialProperties(initialProperties: {{"testValueExporter", QVariant::fromValue(value: &exporter)}}));
287 QVERIFY(obj != nullptr);
288 QCOMPARE(obj->property("success").toBool(), true);
289}
290
291void tst_qqmlvaluetypeproviders::changedSignal()
292{
293 QQmlEngine e;
294 QQmlComponent component(&e, testFileUrl(fileName: "changedSignal.qml"));
295 QVERIFY(!component.isError());
296 QVERIFY(component.errors().isEmpty());
297 QScopedPointer<QObject> object(component.create());
298 QVERIFY(object != nullptr);
299 QVERIFY(object->property("complete").toBool());
300 QVERIFY(object->property("success").toBool());
301}
302
303QTEST_MAIN(tst_qqmlvaluetypeproviders)
304
305#include "tst_qqmlvaluetypeproviders.moc"
306

source code of qtdeclarative/tests/auto/qml/qqmlvaluetypeproviders/tst_qqmlvaluetypeproviders.cpp