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 | |
40 | QT_BEGIN_NAMESPACE |
41 | extern int qt_defaultDpi(void); |
42 | QT_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 | |
49 | class tst_qqmlvaluetypeproviders : public QQmlDataTest |
50 | { |
51 | Q_OBJECT |
52 | public: |
53 | tst_qqmlvaluetypeproviders() {} |
54 | |
55 | private 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 | |
68 | void tst_qqmlvaluetypeproviders::initTestCase() |
69 | { |
70 | QQmlDataTest::initTestCase(); |
71 | registerTypes(); |
72 | } |
73 | |
74 | void 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 | |
87 | void 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 | |
100 | void 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 | |
112 | void 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 | |
152 | void 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 | |
164 | void 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 | |
177 | namespace { |
178 | |
179 | // A value-type class to export to QML |
180 | class TestValue |
181 | { |
182 | public: |
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 | |
201 | private: |
202 | int m_p1; |
203 | double m_p2; |
204 | }; |
205 | |
206 | } |
207 | |
208 | Q_DECLARE_METATYPE(TestValue); |
209 | |
210 | namespace { |
211 | |
212 | class 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) |
218 | public: |
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 | |
228 | class TestValueTypeProvider : public QQmlValueTypeProvider |
229 | { |
230 | public: |
231 | const QMetaObject *getMetaObjectForMetaType(int type) |
232 | { |
233 | if (type == qMetaTypeId<TestValue>()) |
234 | return &TestValueType::staticMetaObject; |
235 | |
236 | return nullptr; |
237 | } |
238 | |
239 | }; |
240 | |
241 | TestValueTypeProvider *getValueTypeProvider() |
242 | { |
243 | static TestValueTypeProvider valueTypeProvider; |
244 | return &valueTypeProvider; |
245 | } |
246 | |
247 | bool initializeProviders() |
248 | { |
249 | QQml_addValueTypeProvider(getValueTypeProvider()); |
250 | return true; |
251 | } |
252 | |
253 | const bool initialized = initializeProviders(); |
254 | |
255 | class TestValueExporter : public QObject |
256 | { |
257 | Q_OBJECT |
258 | Q_PROPERTY(TestValue testValue READ testValue WRITE setTestValue) |
259 | QML_NAMED_ELEMENT(TestValueExporter) |
260 | public: |
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 | |
266 | private: |
267 | TestValue m_testValue; |
268 | }; |
269 | |
270 | } |
271 | |
272 | void 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 | |
291 | void 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 | |
303 | QTEST_MAIN(tst_qqmlvaluetypeproviders) |
304 | |
305 | #include "tst_qqmlvaluetypeproviders.moc" |
306 | |