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#include <private/qqmlengine_p.h>
29
30#include <qtest.h>
31#include <QDebug>
32#include <QQmlEngine>
33#include <QFontDatabase>
34#include <QFileInfo>
35#include <QQmlComponent>
36#include <QDesktopServices>
37#include <QDir>
38#include <QCryptographicHash>
39#include <QtQuick/QQuickItem>
40#include <QSignalSpy>
41#include <QVector2D>
42#include <QVector3D>
43#include <QVector4D>
44#include <QQuaternion>
45#include <QMatrix4x4>
46#include <QFont>
47#include "../../shared/util.h"
48
49// Copied from tst_qdatetime.cpp
50#ifdef Q_OS_WIN
51# include <qt_windows.h>
52# include <time.h>
53# if defined(Q_OS_WINRT)
54# define tzset()
55# endif
56#endif
57
58class tst_qqmlqt : public QQmlDataTest
59{
60 Q_OBJECT
61public:
62 tst_qqmlqt() {}
63
64private slots:
65 void initTestCase();
66 void enums();
67 void rgba();
68 void hsla();
69 void hsva();
70 void colorEqual();
71 void rect();
72 void point();
73 void size();
74 void vector2d();
75 void vector3d();
76 void vector4d();
77 void quaternion();
78 void matrix4x4();
79 void font();
80 void lighter();
81 void darker();
82 void tint();
83 void openUrlExternally();
84 void openUrlExternally_pragmaLibrary();
85 void md5();
86 void createComponent();
87 void createComponent_pragmaLibrary();
88 void createQmlObject();
89 void dateTimeConversion();
90 void dateTimeFormatting();
91 void dateTimeFormatting_data();
92 void dateTimeFormattingVariants();
93 void dateTimeFormattingVariants_data();
94 void dateTimeFormattingWithLocale();
95 void isQtObject();
96 void btoa();
97 void atob();
98 void fontFamilies();
99 void quit();
100 void exit();
101 void resolvedUrl();
102 void later_data();
103 void later();
104 void qtObjectContents();
105
106 void timeRoundtrip_data();
107 void timeRoundtrip();
108
109private:
110 QQmlEngine engine;
111};
112
113// for callLater()
114class TestElement : public QQuickItem
115{
116 Q_OBJECT
117public:
118 TestElement() : m_intptr(new int) {}
119 ~TestElement() { delete m_intptr; }
120
121 Q_INVOKABLE void dangerousFunction() {
122 delete m_intptr;
123 m_intptr = new int;
124 *m_intptr = 5;
125 }
126private:
127 int *m_intptr;
128};
129
130// for callLater()
131class TestModuleApi : public QObject
132{
133 Q_OBJECT
134 Q_PROPERTY(int intProp READ intProp WRITE setIntProp NOTIFY intPropChanged)
135
136public:
137 TestModuleApi() : m_int(0) {}
138 ~TestModuleApi() {}
139
140 int intProp() const { return m_int; }
141 void setIntProp(int v) { m_int = v; emit intPropChanged(); }
142
143 Q_INVOKABLE void testFunc() { ++m_int; emit intPropChanged(); }
144 Q_INVOKABLE void resetIntProp() { m_int = 0; emit intPropChanged(); }
145
146signals:
147 void intPropChanged();
148
149private:
150 int m_int;
151};
152
153static QObject *test_module_api_factory(QQmlEngine *engine, QJSEngine *scriptEngine)
154{
155 Q_UNUSED(engine)
156 Q_UNUSED(scriptEngine)
157 TestModuleApi *api = new TestModuleApi;
158 return api;
159}
160
161void tst_qqmlqt::initTestCase()
162{
163 QQmlDataTest::initTestCase();
164 qmlRegisterSingletonType<TestModuleApi>(uri: "LaterImports", versionMajor: 1, versionMinor: 0, typeName: "SingletonType", callback: test_module_api_factory);
165 qmlRegisterType<TestElement>(uri: "LaterImports", versionMajor: 1, versionMinor: 0, qmlName: "TestElement");
166}
167
168void tst_qqmlqt::enums()
169{
170 QQmlComponent component(&engine, testFileUrl(fileName: "enums.qml"));
171 QObject *object = component.create();
172 QVERIFY(object != nullptr);
173
174 QCOMPARE(object->property("test1").toInt(), (int)Qt::Key_Escape);
175 QCOMPARE(object->property("test2").toInt(), (int)Qt::DescendingOrder);
176 QCOMPARE(object->property("test3").toInt(), (int)Qt::ElideMiddle);
177 QCOMPARE(object->property("test4").toInt(), (int)Qt::AlignRight);
178
179 delete object;
180}
181
182void tst_qqmlqt::rgba()
183{
184 QQmlComponent component(&engine, testFileUrl(fileName: "rgba.qml"));
185
186 QString warning1 = component.url().toString() + ":6: Error: Qt.rgba(): Invalid arguments";
187 QString warning2 = component.url().toString() + ":7: Error: Qt.rgba(): Invalid arguments";
188 QTest::ignoreMessage(type: QtWarningMsg, qPrintable(warning1));
189 QTest::ignoreMessage(type: QtWarningMsg, qPrintable(warning2));
190
191 QObject *object = component.create();
192 QVERIFY(object != nullptr);
193
194
195 QCOMPARE(qvariant_cast<QColor>(object->property("test1")), QColor::fromRgbF(1, 0, 0, 0.8));
196 QCOMPARE(qvariant_cast<QColor>(object->property("test2")), QColor::fromRgbF(1, 0.5, 0.3, 1));
197 QCOMPARE(qvariant_cast<QColor>(object->property("test3")), QColor());
198 QCOMPARE(qvariant_cast<QColor>(object->property("test4")), QColor());
199 QCOMPARE(qvariant_cast<QColor>(object->property("test5")), QColor::fromRgbF(1, 1, 1, 1));
200 QCOMPARE(qvariant_cast<QColor>(object->property("test6")), QColor::fromRgbF(0, 0, 0, 0));
201
202 delete object;
203}
204
205void tst_qqmlqt::hsla()
206{
207 QQmlComponent component(&engine, testFileUrl(fileName: "hsla.qml"));
208
209 QString warning1 = component.url().toString() + ":6: Error: Qt.hsla(): Invalid arguments";
210 QString warning2 = component.url().toString() + ":7: Error: Qt.hsla(): Invalid arguments";
211 QTest::ignoreMessage(type: QtWarningMsg, qPrintable(warning1));
212 QTest::ignoreMessage(type: QtWarningMsg, qPrintable(warning2));
213
214 QObject *object = component.create();
215 QVERIFY(object != nullptr);
216
217 QCOMPARE(qvariant_cast<QColor>(object->property("test1")), QColor::fromHslF(1, 0, 0, 0.8));
218 QCOMPARE(qvariant_cast<QColor>(object->property("test2")), QColor::fromHslF(1, 0.5, 0.3, 1));
219 QCOMPARE(qvariant_cast<QColor>(object->property("test3")), QColor());
220 QCOMPARE(qvariant_cast<QColor>(object->property("test4")), QColor());
221 QCOMPARE(qvariant_cast<QColor>(object->property("test5")), QColor::fromHslF(1, 1, 1, 1));
222 QCOMPARE(qvariant_cast<QColor>(object->property("test6")), QColor::fromHslF(0, 0, 0, 0));
223
224 delete object;
225}
226
227void tst_qqmlqt::hsva()
228{
229 QQmlComponent component(&engine, testFileUrl(fileName: "hsva.qml"));
230
231 QString warning1 = component.url().toString() + ":6: Error: Qt.hsva(): Invalid arguments";
232 QString warning2 = component.url().toString() + ":7: Error: Qt.hsva(): Invalid arguments";
233 QTest::ignoreMessage(type: QtWarningMsg, qPrintable(warning1));
234 QTest::ignoreMessage(type: QtWarningMsg, qPrintable(warning2));
235
236 QObject *object = component.create();
237 QVERIFY(object != nullptr);
238
239 QCOMPARE(qvariant_cast<QColor>(object->property("test1")), QColor::fromHsvF(1, 0, 0, 0.8));
240 QCOMPARE(qvariant_cast<QColor>(object->property("test2")), QColor::fromHsvF(1, 0.5, 0.3, 1));
241 QCOMPARE(qvariant_cast<QColor>(object->property("test3")), QColor());
242 QCOMPARE(qvariant_cast<QColor>(object->property("test4")), QColor());
243 QCOMPARE(qvariant_cast<QColor>(object->property("test5")), QColor::fromHsvF(1, 1, 1, 1));
244 QCOMPARE(qvariant_cast<QColor>(object->property("test6")), QColor::fromHsvF(0, 0, 0, 0));
245
246 delete object;
247}
248
249void tst_qqmlqt::colorEqual()
250{
251 QQmlComponent component(&engine, testFileUrl(fileName: "colorEqual.qml"));
252
253 QTest::ignoreMessage(type: QtWarningMsg, qPrintable(component.url().toString() + ":6: Error: Qt.colorEqual(): Invalid arguments"));
254 QTest::ignoreMessage(type: QtWarningMsg, qPrintable(component.url().toString() + ":7: Error: Qt.colorEqual(): Invalid arguments"));
255 QTest::ignoreMessage(type: QtWarningMsg, qPrintable(component.url().toString() + ":9: Error: Qt.colorEqual(): Invalid color name"));
256 QTest::ignoreMessage(type: QtWarningMsg, qPrintable(component.url().toString() + ":10: Error: Qt.colorEqual(): Invalid color name"));
257 QTest::ignoreMessage(type: QtWarningMsg, qPrintable(component.url().toString() + ":12: Error: Qt.colorEqual(): Invalid arguments"));
258 QTest::ignoreMessage(type: QtWarningMsg, qPrintable(component.url().toString() + ":13: Error: Qt.colorEqual(): Invalid arguments"));
259 QTest::ignoreMessage(type: QtWarningMsg, qPrintable(component.url().toString() + ":17: Error: Qt.colorEqual(): Invalid arguments"));
260 QTest::ignoreMessage(type: QtWarningMsg, qPrintable(component.url().toString() + ":18: Error: Qt.colorEqual(): Invalid arguments"));
261 QTest::ignoreMessage(type: QtWarningMsg, qPrintable(component.url().toString() + ":34: Error: Qt.colorEqual(): Invalid color name"));
262 QTest::ignoreMessage(type: QtWarningMsg, qPrintable(component.url().toString() + ":35: Error: Qt.colorEqual(): Invalid color name"));
263
264 QObject *object = component.create();
265 QVERIFY(object != nullptr);
266
267 QCOMPARE(object->property("test1a").toBool(), false);
268 QCOMPARE(object->property("test1b").toBool(), false);
269 QCOMPARE(object->property("test1c").toBool(), false);
270 QCOMPARE(object->property("test1d").toBool(), false);
271 QCOMPARE(object->property("test1e").toBool(), false);
272 QCOMPARE(object->property("test1f").toBool(), false);
273 QCOMPARE(object->property("test1g").toBool(), false);
274 QCOMPARE(object->property("test1h").toBool(), false);
275
276 QCOMPARE(object->property("test2a").toBool(), true);
277 QCOMPARE(object->property("test2b").toBool(), true);
278 QCOMPARE(object->property("test2c").toBool(), true);
279 QCOMPARE(object->property("test2d").toBool(), true);
280 QCOMPARE(object->property("test2e").toBool(), true);
281 QCOMPARE(object->property("test2f").toBool(), true);
282 QCOMPARE(object->property("test2g").toBool(), true);
283 QCOMPARE(object->property("test2h").toBool(), true);
284 QCOMPARE(object->property("test2i").toBool(), false);
285 QCOMPARE(object->property("test2j").toBool(), false);
286 QCOMPARE(object->property("test2k").toBool(), false);
287 QCOMPARE(object->property("test2l").toBool(), false);
288 QCOMPARE(object->property("test2m").toBool(), false);
289 QCOMPARE(object->property("test2n").toBool(), false);
290
291 QCOMPARE(object->property("test3a").toBool(), true);
292 QCOMPARE(object->property("test3b").toBool(), true);
293 QCOMPARE(object->property("test3c").toBool(), true);
294 QCOMPARE(object->property("test3d").toBool(), true);
295 QCOMPARE(object->property("test3e").toBool(), true);
296 QCOMPARE(object->property("test3f").toBool(), true);
297 QCOMPARE(object->property("test3g").toBool(), false);
298 QCOMPARE(object->property("test3h").toBool(), false);
299 QCOMPARE(object->property("test3i").toBool(), true);
300 QCOMPARE(object->property("test3j").toBool(), true);
301 QCOMPARE(object->property("test3k").toBool(), true);
302 QCOMPARE(object->property("test3l").toBool(), true);
303 QCOMPARE(object->property("test3m").toBool(), true);
304 QCOMPARE(object->property("test3n").toBool(), true);
305
306 QCOMPARE(object->property("test4a").toBool(), true);
307 QCOMPARE(object->property("test4b").toBool(), true);
308 QCOMPARE(object->property("test4c").toBool(), false);
309 QCOMPARE(object->property("test4d").toBool(), false);
310 QCOMPARE(object->property("test4e").toBool(), false);
311 QCOMPARE(object->property("test4f").toBool(), false);
312 QCOMPARE(object->property("test4g").toBool(), false);
313 QCOMPARE(object->property("test4h").toBool(), false);
314 QCOMPARE(object->property("test4i").toBool(), false);
315 QCOMPARE(object->property("test4j").toBool(), false);
316
317 QCOMPARE(object->property("test5a").toBool(), true);
318 QCOMPARE(object->property("test5b").toBool(), true);
319 QCOMPARE(object->property("test5c").toBool(), true);
320 QCOMPARE(object->property("test5d").toBool(), false);
321 QCOMPARE(object->property("test5e").toBool(), false);
322
323 QCOMPARE(object->property("test6a").toBool(), true);
324 QCOMPARE(object->property("test6b").toBool(), true);
325 QCOMPARE(object->property("test6c").toBool(), true);
326 QCOMPARE(object->property("test6d").toBool(), false);
327 QCOMPARE(object->property("test6e").toBool(), false);
328
329 delete object;
330}
331
332void tst_qqmlqt::rect()
333{
334 QQmlComponent component(&engine, testFileUrl(fileName: "rect.qml"));
335
336 QString warning1 = component.url().toString() + ":6: Error: Qt.rect(): Invalid arguments";
337 QString warning2 = component.url().toString() + ":7: Error: Qt.rect(): Invalid arguments";
338 QTest::ignoreMessage(type: QtWarningMsg, qPrintable(warning1));
339 QTest::ignoreMessage(type: QtWarningMsg, qPrintable(warning2));
340
341 QObject *object = component.create();
342 QVERIFY(object != nullptr);
343
344 QCOMPARE(qvariant_cast<QRectF>(object->property("test1")), QRectF(10, 13, 100, 109));
345 QCOMPARE(qvariant_cast<QRectF>(object->property("test2")), QRectF(-10, 13, 100, 109.6));
346 QCOMPARE(qvariant_cast<QRectF>(object->property("test3")), QRectF());
347 QCOMPARE(qvariant_cast<QRectF>(object->property("test4")), QRectF());
348 QCOMPARE(qvariant_cast<QRectF>(object->property("test5")), QRectF(10, 13, 100, -109));
349
350 delete object;
351}
352
353void tst_qqmlqt::point()
354{
355 QQmlComponent component(&engine, testFileUrl(fileName: "point.qml"));
356
357 QString warning1 = component.url().toString() + ":6: Error: Qt.point(): Invalid arguments";
358 QString warning2 = component.url().toString() + ":7: Error: Qt.point(): Invalid arguments";
359 QTest::ignoreMessage(type: QtWarningMsg, qPrintable(warning1));
360 QTest::ignoreMessage(type: QtWarningMsg, qPrintable(warning2));
361
362 QObject *object = component.create();
363 QVERIFY(object != nullptr);
364
365 QCOMPARE(qvariant_cast<QPointF>(object->property("test1")), QPointF(19, 34));
366 QCOMPARE(qvariant_cast<QPointF>(object->property("test2")), QPointF(-3, 109.2));
367 QCOMPARE(qvariant_cast<QPointF>(object->property("test3")), QPointF());
368 QCOMPARE(qvariant_cast<QPointF>(object->property("test4")), QPointF());
369
370 delete object;
371}
372
373void tst_qqmlqt::size()
374{
375 QQmlComponent component(&engine, testFileUrl(fileName: "size.qml"));
376
377 QString warning1 = component.url().toString() + ":7: Error: Qt.size(): Invalid arguments";
378 QString warning2 = component.url().toString() + ":8: Error: Qt.size(): Invalid arguments";
379 QTest::ignoreMessage(type: QtWarningMsg, qPrintable(warning1));
380 QTest::ignoreMessage(type: QtWarningMsg, qPrintable(warning2));
381
382 QObject *object = component.create();
383 QVERIFY(object != nullptr);
384
385 QCOMPARE(qvariant_cast<QSizeF>(object->property("test1")), QSizeF(19, 34));
386 QCOMPARE(qvariant_cast<QSizeF>(object->property("test2")), QSizeF(3, 109.2));
387 QCOMPARE(qvariant_cast<QSizeF>(object->property("test3")), QSizeF(-3, 10));
388 QCOMPARE(qvariant_cast<QSizeF>(object->property("test4")), QSizeF());
389 QCOMPARE(qvariant_cast<QSizeF>(object->property("test5")), QSizeF());
390
391 delete object;
392}
393
394void tst_qqmlqt::vector2d()
395{
396 QQmlComponent component(&engine, testFileUrl(fileName: "vector2.qml"));
397
398 QString warning1 = component.url().toString() + ":6: Error: Qt.vector2d(): Invalid arguments";
399 QString warning2 = component.url().toString() + ":7: Error: Qt.vector2d(): Invalid arguments";
400 QTest::ignoreMessage(type: QtWarningMsg, qPrintable(warning1));
401 QTest::ignoreMessage(type: QtWarningMsg, qPrintable(warning2));
402
403 QObject *object = component.create();
404 QVERIFY(object != nullptr);
405
406 QCOMPARE(qvariant_cast<QVector2D>(object->property("test1")), QVector2D(1, 0.9f));
407 QCOMPARE(qvariant_cast<QVector2D>(object->property("test2")), QVector2D(102, -982.1f));
408 QCOMPARE(qvariant_cast<QVector2D>(object->property("test3")), QVector2D());
409 QCOMPARE(qvariant_cast<QVector2D>(object->property("test4")), QVector2D());
410
411 delete object;
412}
413
414void tst_qqmlqt::vector3d()
415{
416 QQmlComponent component(&engine, testFileUrl(fileName: "vector.qml"));
417
418 QString warning1 = component.url().toString() + ":6: Error: Qt.vector3d(): Invalid arguments";
419 QString warning2 = component.url().toString() + ":7: Error: Qt.vector3d(): Invalid arguments";
420 QTest::ignoreMessage(type: QtWarningMsg, qPrintable(warning1));
421 QTest::ignoreMessage(type: QtWarningMsg, qPrintable(warning2));
422
423 QObject *object = component.create();
424 QVERIFY(object != nullptr);
425
426 QCOMPARE(qvariant_cast<QVector3D>(object->property("test1")), QVector3D(1, 0, 0.9f));
427 QCOMPARE(qvariant_cast<QVector3D>(object->property("test2")), QVector3D(102, -10, -982.1f));
428 QCOMPARE(qvariant_cast<QVector3D>(object->property("test3")), QVector3D());
429 QCOMPARE(qvariant_cast<QVector3D>(object->property("test4")), QVector3D());
430
431 delete object;
432}
433
434void tst_qqmlqt::vector4d()
435{
436 QQmlComponent component(&engine, testFileUrl(fileName: "vector4.qml"));
437
438 QString warning1 = component.url().toString() + ":6: Error: Qt.vector4d(): Invalid arguments";
439 QString warning2 = component.url().toString() + ":7: Error: Qt.vector4d(): Invalid arguments";
440 QTest::ignoreMessage(type: QtWarningMsg, qPrintable(warning1));
441 QTest::ignoreMessage(type: QtWarningMsg, qPrintable(warning2));
442
443 QObject *object = component.create();
444 QVERIFY(object != nullptr);
445
446 QCOMPARE(qvariant_cast<QVector4D>(object->property("test1")), QVector4D(1, 0, 0.9f, 0.6f));
447 QCOMPARE(qvariant_cast<QVector4D>(object->property("test2")), QVector4D(102, -10, -982.1f, 10));
448 QCOMPARE(qvariant_cast<QVector4D>(object->property("test3")), QVector4D());
449 QCOMPARE(qvariant_cast<QVector4D>(object->property("test4")), QVector4D());
450
451 delete object;
452}
453
454void tst_qqmlqt::quaternion()
455{
456 QQmlComponent component(&engine, testFileUrl(fileName: "quaternion.qml"));
457
458 QString warning1 = component.url().toString() + ":6: Error: Qt.quaternion(): Invalid arguments";
459 QString warning2 = component.url().toString() + ":7: Error: Qt.quaternion(): Invalid arguments";
460 QTest::ignoreMessage(type: QtWarningMsg, qPrintable(warning1));
461 QTest::ignoreMessage(type: QtWarningMsg, qPrintable(warning2));
462
463 QObject *object = component.create();
464 QVERIFY(object != nullptr);
465
466 QCOMPARE(qvariant_cast<QQuaternion>(object->property("test1")), QQuaternion(2, 17, 0.9f, 0.6f));
467 QCOMPARE(qvariant_cast<QQuaternion>(object->property("test2")), QQuaternion(102, -10, -982.1f, 10));
468 QCOMPARE(qvariant_cast<QQuaternion>(object->property("test3")), QQuaternion());
469 QCOMPARE(qvariant_cast<QQuaternion>(object->property("test4")), QQuaternion());
470
471 delete object;
472}
473
474void tst_qqmlqt::matrix4x4()
475{
476 QQmlComponent component(&engine, testFileUrl(fileName: "matrix4x4.qml"));
477
478 QString warning1 = component.url().toString() + ":6: Error: Qt.matrix4x4(): Invalid arguments";
479 QString warning2 = component.url().toString() + ":7: Error: Qt.matrix4x4(): Invalid argument: not a valid matrix4x4 values array";
480 QString warning3 = component.url().toString() + ":8: Error: Qt.matrix4x4(): Invalid argument: not a valid matrix4x4 values array";
481 QTest::ignoreMessage(type: QtWarningMsg, qPrintable(warning1));
482 QTest::ignoreMessage(type: QtWarningMsg, qPrintable(warning2));
483 QTest::ignoreMessage(type: QtWarningMsg, qPrintable(warning3));
484
485 QObject *object = component.create();
486 QVERIFY(object != nullptr);
487
488 QCOMPARE(qvariant_cast<QMatrix4x4>(object->property("test1")), QMatrix4x4(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16));
489 QCOMPARE(qvariant_cast<QMatrix4x4>(object->property("test2")), QMatrix4x4(1,1,1,1,2,2,2,2,3,3,3,3,4,4,4,4));
490 QCOMPARE(qvariant_cast<QMatrix4x4>(object->property("test3")), QMatrix4x4());
491 QCOMPARE(qvariant_cast<QMatrix4x4>(object->property("test4")), QMatrix4x4());
492 QCOMPARE(qvariant_cast<QMatrix4x4>(object->property("test5")), QMatrix4x4());
493
494 delete object;
495}
496
497void tst_qqmlqt::font()
498{
499 QQmlComponent component(&engine, testFileUrl(fileName: "font.qml"));
500
501 QString warning1 = component.url().toString() + ":6: Error: Qt.font(): Invalid arguments";
502 QString warning2 = component.url().toString() + ":7: Error: Qt.font(): Invalid argument: no valid font subproperties specified";
503 QTest::ignoreMessage(type: QtWarningMsg, qPrintable(warning1));
504 QTest::ignoreMessage(type: QtWarningMsg, qPrintable(warning2));
505
506 QObject *object = component.create();
507 QVERIFY(object != nullptr);
508
509 QFont f;
510 f.setFamily("Arial");
511 f.setPointSize(22);
512 QCOMPARE(qvariant_cast<QFont>(object->property("test1")), f);
513 f.setPointSize(20);
514 f.setWeight(QFont::DemiBold);
515 f.setItalic(true);
516 QCOMPARE(qvariant_cast<QFont>(object->property("test2")), f);
517 QCOMPARE(qvariant_cast<QFont>(object->property("test3")), QFont());
518 QCOMPARE(qvariant_cast<QFont>(object->property("test4")), QFont());
519
520 delete object;
521}
522
523void tst_qqmlqt::lighter()
524{
525 QQmlComponent component(&engine, testFileUrl(fileName: "lighter.qml"));
526
527 QString warning1 = component.url().toString() + ":5: Error: Qt.lighter(): Invalid arguments";
528 QString warning2 = component.url().toString() + ":10: Error: Qt.lighter(): Invalid arguments";
529 QTest::ignoreMessage(type: QtWarningMsg, qPrintable(warning1));
530 QTest::ignoreMessage(type: QtWarningMsg, qPrintable(warning2));
531
532 QObject *object = component.create();
533 QVERIFY(object != nullptr);
534
535 QCOMPARE(qvariant_cast<QColor>(object->property("test1")), QColor::fromRgbF(1, 0.8, 0.3).lighter());
536 QCOMPARE(qvariant_cast<QColor>(object->property("test2")), QColor());
537 QCOMPARE(qvariant_cast<QColor>(object->property("test3")), QColor::fromRgbF(1, 0.8, 0.3).lighter(180));
538 QCOMPARE(qvariant_cast<QColor>(object->property("test4")), QColor("red").lighter());
539 QCOMPARE(qvariant_cast<QColor>(object->property("test5")), QColor());
540 QCOMPARE(qvariant_cast<QColor>(object->property("test6")), QColor());
541
542 delete object;
543}
544
545void tst_qqmlqt::darker()
546{
547 QQmlComponent component(&engine, testFileUrl(fileName: "darker.qml"));
548
549 QString warning1 = component.url().toString() + ":5: Error: Qt.darker(): Invalid arguments";
550 QString warning2 = component.url().toString() + ":10: Error: Qt.darker(): Invalid arguments";
551 QTest::ignoreMessage(type: QtWarningMsg, qPrintable(warning1));
552 QTest::ignoreMessage(type: QtWarningMsg, qPrintable(warning2));
553
554 QObject *object = component.create();
555 QVERIFY(object != nullptr);
556
557 QCOMPARE(qvariant_cast<QColor>(object->property("test1")), QColor::fromRgbF(1, 0.8, 0.3).darker());
558 QCOMPARE(qvariant_cast<QColor>(object->property("test2")), QColor());
559 QCOMPARE(qvariant_cast<QColor>(object->property("test3")), QColor::fromRgbF(1, 0.8, 0.3).darker(280));
560 QCOMPARE(qvariant_cast<QColor>(object->property("test4")), QColor("red").darker());
561 QCOMPARE(qvariant_cast<QColor>(object->property("test5")), QColor());
562 QCOMPARE(qvariant_cast<QColor>(object->property("test6")), QColor());
563
564 delete object;
565}
566
567void tst_qqmlqt::tint()
568{
569 QQmlComponent component(&engine, testFileUrl(fileName: "tint.qml"));
570
571 QString warning1 = component.url().toString() + ":7: Error: Qt.tint(): Invalid arguments";
572 QString warning2 = component.url().toString() + ":8: Error: Qt.tint(): Invalid arguments";
573
574 QTest::ignoreMessage(type: QtWarningMsg, qPrintable(warning1));
575 QTest::ignoreMessage(type: QtWarningMsg, qPrintable(warning2));
576
577 QObject *object = component.create();
578 QVERIFY(object != nullptr);
579
580 QCOMPARE(qvariant_cast<QColor>(object->property("test1")), QColor::fromRgbF(0, 0, 1));
581 QCOMPARE(qvariant_cast<QColor>(object->property("test2")), QColor::fromRgbF(1, 0, 0));
582 QColor test3 = qvariant_cast<QColor>(v: object->property(name: "test3"));
583 QCOMPARE(test3.rgba(), 0xFF7F0080);
584 QCOMPARE(qvariant_cast<QColor>(object->property("test4")), QColor());
585 QCOMPARE(qvariant_cast<QColor>(object->property("test5")), QColor());
586
587 delete object;
588}
589
590class MyUrlHandler : public QObject
591{
592 Q_OBJECT
593public:
594 MyUrlHandler() : called(0) { }
595 int called;
596 QUrl last;
597
598public slots:
599 void noteCall(const QUrl &url) { called++; last = url; }
600};
601
602void tst_qqmlqt::openUrlExternally()
603{
604 MyUrlHandler handler;
605
606 QDesktopServices::setUrlHandler(scheme: "test", receiver: &handler, method: "noteCall");
607 QDesktopServices::setUrlHandler(scheme: "file", receiver: &handler, method: "noteCall");
608
609 QQmlComponent component(&engine, testFileUrl(fileName: "openUrlExternally.qml"));
610 QObject *object = component.create();
611 QVERIFY(object != nullptr);
612 QCOMPARE(handler.called,1);
613 QCOMPARE(handler.last, QUrl("test:url"));
614
615 object->setProperty(name: "testFile", value: true);
616
617 QCOMPARE(handler.called,2);
618 QCOMPARE(handler.last, testFileUrl("test.html"));
619
620 QDesktopServices::unsetUrlHandler(scheme: "test");
621 QDesktopServices::unsetUrlHandler(scheme: "file");
622}
623
624void tst_qqmlqt::openUrlExternally_pragmaLibrary()
625{
626 MyUrlHandler handler;
627
628 QDesktopServices::setUrlHandler(scheme: "test", receiver: &handler, method: "noteCall");
629 QDesktopServices::setUrlHandler(scheme: "file", receiver: &handler, method: "noteCall");
630
631 QQmlComponent component(&engine, testFileUrl(fileName: "openUrlExternally_lib.qml"));
632 QObject *object = component.create();
633 QVERIFY(object != nullptr);
634 QCOMPARE(handler.called,1);
635 QCOMPARE(handler.last, QUrl("test:url"));
636
637 object->setProperty(name: "testFile", value: true);
638
639 QCOMPARE(handler.called,2);
640 QCOMPARE(handler.last, testFileUrl("test.html"));
641
642 QDesktopServices::unsetUrlHandler(scheme: "test");
643 QDesktopServices::unsetUrlHandler(scheme: "file");
644}
645
646void tst_qqmlqt::md5()
647{
648 QQmlComponent component(&engine, testFileUrl(fileName: "md5.qml"));
649
650 QString warning1 = component.url().toString() + ":4: Error: Qt.md5(): Invalid arguments";
651 QTest::ignoreMessage(type: QtWarningMsg, qPrintable(warning1));
652
653 QObject *object = component.create();
654 QVERIFY(object != nullptr);
655
656 QCOMPARE(object->property("test2").toString(), QLatin1String(QCryptographicHash::hash("Hello World", QCryptographicHash::Md5).toHex()));
657
658 delete object;
659}
660
661void tst_qqmlqt::createComponent()
662{
663 {
664 QQmlComponent component(&engine, testFileUrl(fileName: "createComponent.qml"));
665
666 QString warning1 = component.url().toString() + ":9: Error: Qt.createComponent(): Invalid arguments";
667 QString warning2 = component.url().toString() + ":10: Error: Qt.createComponent(): Invalid arguments";
668 QTest::ignoreMessage(type: QtWarningMsg, qPrintable(warning1));
669 QTest::ignoreMessage(type: QtWarningMsg, qPrintable(warning2));
670
671 QObject *object = component.create();
672 QVERIFY(object != nullptr);
673
674 QCOMPARE(object->property("absoluteUrl").toString(), QString("http://www.example.com/test.qml"));
675 QCOMPARE(object->property("relativeUrl").toString(), testFileUrl("createComponentData.qml").toString());
676
677 QTRY_VERIFY(object->property("asyncResult").toBool());
678
679 delete object;
680 }
681
682 // simultaneous sync and async compilation
683 {
684 QQmlComponent component(&engine, testFileUrl(fileName: "createComponent.2.qml"));
685 QObject *object = component.create();
686 QVERIFY(object != nullptr);
687 QTRY_VERIFY(object->property("success").toBool());
688 delete object;
689 }
690}
691
692void tst_qqmlqt::createComponent_pragmaLibrary()
693{
694 // Currently, just loading createComponent_lib.qml causes crash on some platforms
695 QQmlComponent component(&engine, testFileUrl(fileName: "createComponent_lib.qml"));
696 QObject *object = component.create();
697 QVERIFY(object != nullptr);
698 QCOMPARE(object->property("status").toInt(), int(QQmlComponent::Ready));
699 QCOMPARE(object->property("readValue").toInt(), int(1913));
700 delete object;
701}
702
703void tst_qqmlqt::createQmlObject()
704{
705 QQmlComponent component(&engine, testFileUrl(fileName: "createQmlObject.qml"));
706
707 QString warning1 = component.url().toString() + ":7: Error: Qt.createQmlObject(): Invalid arguments";
708 QString warning2 = component.url().toString()+ ":10: Error: Qt.createQmlObject(): failed to create object: \n " + testFileUrl(fileName: "inline").toString() + ":2:10: Blah is not a type";
709 QString warning3 = component.url().toString()+ ":11: Error: Qt.createQmlObject(): failed to create object: \n " + testFileUrl(fileName: "main.qml").toString() + ":4:14: Duplicate property name";
710 QString warning4 = component.url().toString()+ ":9: Error: Qt.createQmlObject(): Missing parent object";
711 QString warning5 = component.url().toString()+ ":8: Error: Qt.createQmlObject(): Invalid arguments";
712 QString warning6 = "RunTimeError: Qt.createQmlObject(): failed to create object: \n " + testFileUrl(fileName: "inline").toString() + ":3:16: Cannot assign object type QObject with no default method";
713 QTest::ignoreMessage(type: QtWarningMsg, qPrintable(warning1));
714 QTest::ignoreMessage(type: QtWarningMsg, qPrintable(warning2));
715 QTest::ignoreMessage(type: QtWarningMsg, qPrintable(warning3));
716 QTest::ignoreMessage(type: QtWarningMsg, qPrintable(warning4));
717 QTest::ignoreMessage(type: QtWarningMsg, qPrintable(warning5));
718 QTest::ignoreMessage(type: QtDebugMsg, qPrintable(warning6));
719
720 QObject *object = component.create();
721 QVERIFY(object != nullptr);
722
723 QCOMPARE(object->property("emptyArg").toBool(), true);
724 QCOMPARE(object->property("success").toBool(), true);
725
726 QQuickItem *item = qobject_cast<QQuickItem *>(object);
727 QVERIFY(item != nullptr);
728 QCOMPARE(item->childItems().count(), 1);
729
730 delete object;
731}
732
733
734void tst_qqmlqt::dateTimeConversion()
735{
736 QDate date(2008,12,24);
737 QTime time(14,15,38,200);
738 QDateTime dateTime(date, time);
739 //Note that when converting Date to QDateTime they can argue over historical DST data when converting to local time.
740 //Tests should use UTC or recent dates.
741 QDateTime dateTime2(QDate(2852,12,31), QTime(23,59,59,500));
742 QDateTime dateTime3(QDate(2000,1,1), QTime(0,0,0,0));
743 QDateTime dateTime4(QDate(2001,2,2), QTime(0,0,0,0));
744 QDateTime dateTime5(QDate(1999,1,1), QTime(2,3,4,0));
745 QDateTime dateTime6(QDate(2008,2,24), QTime(14,15,38,200));
746 QDateTime dateTime7(QDate(1970,1,1), QTime(0,0,0,0), Qt::UTC);
747 QDateTime dateTime8(QDate(1586,2,2), QTime(0,0,0,0), Qt::UTC);
748 QDateTime dateTime9(QDate(955,1,1), QTime(0,0,0,0), Qt::UTC);
749 QDateTime dateTime10(QDate(113,2,24), QTime(14,15,38,200), Qt::UTC);
750
751 QQmlEngine eng;
752 QQmlComponent component(&eng, testFileUrl(fileName: "dateTimeConversion.qml"));
753 QObject *obj = component.create();
754
755 QCOMPARE(obj->property("qdate").toDate(), date);
756 QCOMPARE(obj->property("qtime").toTime(), time);
757 QCOMPARE(obj->property("qdatetime").toDateTime(), dateTime);
758 QCOMPARE(obj->property("qdatetime2").toDateTime(), dateTime2);
759 QCOMPARE(obj->property("qdatetime3").toDateTime(), dateTime3);
760 QCOMPARE(obj->property("qdatetime4").toDateTime(), dateTime4);
761 QCOMPARE(obj->property("qdatetime5").toDateTime(), dateTime5);
762 QCOMPARE(obj->property("qdatetime6").toDateTime(), dateTime6);
763 QCOMPARE(obj->property("qdatetime7").toDateTime(), dateTime7);
764 QCOMPARE(obj->property("qdatetime8").toDateTime(), dateTime8);
765 QCOMPARE(obj->property("qdatetime9").toDateTime(), dateTime9);
766 QCOMPARE(obj->property("qdatetime10").toDateTime(), dateTime10);
767}
768
769void tst_qqmlqt::dateTimeFormatting()
770{
771 QFETCH(QString, method);
772 QFETCH(QStringList, inputProperties);
773 QFETCH(QStringList, expectedResults);
774
775 QDate date(2008,12,24);
776 QTime time(14,15,38,200);
777 QDateTime dateTime(date, time);
778
779 QQmlEngine eng;
780
781 QQmlComponent component(&eng, testFileUrl(fileName: "formatting.qml"));
782
783 QStringList warnings;
784 warnings << component.url().toString() + ":37: Error: Qt.formatDate(): Bad second argument (must be either string, number or locale)"
785 << component.url().toString() + ":36: Error: Qt.formatDate(): Missing argument"
786 << component.url().toString() + ":40: Error: Qt.formatTime(): Bad second argument (must be either string, number or locale)"
787 << component.url().toString() + ":39: Error: Qt.formatTime(): Missing argument"
788 << component.url().toString() + ":43: Error: Qt.formatDateTime(): Bad second argument (must be either string, number or locale)"
789 << component.url().toString() + ":42: Error: Qt.formatDateTime(): Missing argument";
790
791 foreach (const QString &warning, warnings)
792 QTest::ignoreMessage(type: QtWarningMsg, qPrintable(warning));
793
794 QObject *object = component.createWithInitialProperties(initialProperties: {
795 {"qdate", date},
796 {"qtime", time},
797 {"qdatetime", dateTime}
798 });
799 QVERIFY2(component.errorString().isEmpty(), qPrintable(component.errorString()));
800 QVERIFY(object != nullptr);
801
802 QVERIFY(inputProperties.count() > 0);
803 QVariant result;
804 foreach(const QString &prop, inputProperties) {
805 QVERIFY(QMetaObject::invokeMethod(object, method.toUtf8().constData(),
806 Q_RETURN_ARG(QVariant, result),
807 Q_ARG(QVariant, prop)));
808 QStringList output = result.toStringList();
809 QCOMPARE(output.size(), expectedResults.size());
810 for (int i=0; i<output.count(); i++)
811 QCOMPARE(output[i], expectedResults[i]);
812 }
813
814 delete object;
815}
816
817void tst_qqmlqt::dateTimeFormatting_data()
818{
819 QT_WARNING_PUSH QT_WARNING_DISABLE_DEPRECATED
820 // Test intentionally uses deprecated enumerators from Qt::DateFormat
821 QTest::addColumn<QString>(name: "method");
822 QTest::addColumn<QStringList>(name: "inputProperties");
823 QTest::addColumn<QStringList>(name: "expectedResults");
824
825 QDate date(2008,12,24);
826 QTime time(14,15,38,200);
827 QDateTime dateTime(date, time);
828
829 QTest::newRow(dataTag: "formatDate")
830 << "formatDate"
831 << (QStringList() << "dateFromString" << "jsdate" << "qdate" << "qdatetime")
832 << (QStringList() << date.toString(format: Qt::DefaultLocaleShortDate)
833 << date.toString(format: Qt::DefaultLocaleLongDate)
834 << date.toString(format: "ddd MMMM d yy"));
835
836 QTest::newRow(dataTag: "formatTime")
837 << "formatTime"
838 << (QStringList() << "jsdate" << "qtime" << "qdatetime")
839 << (QStringList() << time.toString(f: Qt::DefaultLocaleShortDate)
840 << time.toString(f: Qt::DefaultLocaleLongDate)
841 << time.toString(format: "H:m:s a")
842 << time.toString(format: "hh:mm:ss.zzz"));
843
844 QTest::newRow(dataTag: "formatDateTime")
845 << "formatDateTime"
846 << (QStringList() << "jsdate" << "qdatetime")
847 << (QStringList() << dateTime.toString(format: Qt::DefaultLocaleShortDate)
848 << dateTime.toString(format: Qt::DefaultLocaleLongDate)
849 << dateTime.toString(format: "M/d/yy H:m:s a"));
850 QT_WARNING_POP
851}
852
853void tst_qqmlqt::dateTimeFormattingVariants()
854{
855 QFETCH(QString, method);
856 QFETCH(QVariant, variant);
857 QFETCH(QStringList, expectedResults);
858
859 QQmlEngine eng;
860 QQmlComponent component(&eng, testFileUrl(fileName: "formatting.qml"));
861
862 QStringList warnings;
863 warnings << component.url().toString() + ":37: Error: Qt.formatDate(): Bad second argument (must be either string, number or locale)"
864 << component.url().toString() + ":36: Error: Qt.formatDate(): Missing argument"
865 << component.url().toString() + ":40: Error: Qt.formatTime(): Bad second argument (must be either string, number or locale)"
866 << component.url().toString() + ":39: Error: Qt.formatTime(): Missing argument"
867 << component.url().toString() + ":43: Error: Qt.formatDateTime(): Bad second argument (must be either string, number or locale)"
868 << component.url().toString() + ":42: Error: Qt.formatDateTime(): Missing argument";
869
870 foreach (const QString &warning, warnings)
871 QTest::ignoreMessage(type: QtWarningMsg, qPrintable(warning));
872
873 QObject *object = component.createWithInitialProperties(initialProperties: {{"qvariant", variant}});
874 QVERIFY2(component.errorString().isEmpty(), qPrintable(component.errorString()));
875 QVERIFY(object != nullptr);
876
877 QVariant result;
878 QVERIFY(QMetaObject::invokeMethod(object, method.toUtf8().constData(),
879 Q_RETURN_ARG(QVariant, result),
880 Q_ARG(QVariant, QString(QLatin1String("qvariant")))));
881 QStringList output = result.toStringList();
882 QCOMPARE(output, expectedResults);
883
884 delete object;
885}
886
887void tst_qqmlqt::dateTimeFormattingVariants_data()
888{
889 QT_WARNING_PUSH QT_WARNING_DISABLE_DEPRECATED
890 // Test intentionally uses deprecated enumerators from Qt::DateFormat
891 QTest::addColumn<QString>(name: "method");
892 QTest::addColumn<QVariant>(name: "variant");
893 QTest::addColumn<QStringList>(name: "expectedResults");
894
895 QDateTime temporary;
896
897 QTime time(11, 16, 39, 755);
898 temporary = QDateTime(QDate(1970,1,1), time);
899 QTest::newRow(dataTag: "formatTime, qtime") << "formatTime" << QVariant::fromValue(value: time) << (QStringList() << temporary.time().toString(f: Qt::DefaultLocaleShortDate) << temporary.time().toString(f: Qt::DefaultLocaleLongDate) << temporary.time().toString(format: "H:m:s a") << temporary.time().toString(format: "hh:mm:ss.zzz"));
900
901 QDate date(2011,5,31);
902 // V4 reads the date in UTC but DateObject::toQDateTime() gives it back in local time:
903 temporary = QDateTime(date, QTime(0, 0, 0), Qt::UTC).toLocalTime();
904 QTest::newRow(dataTag: "formatDate, qdate") << "formatDate" << QVariant::fromValue(value: date) << (QStringList() << temporary.date().toString(format: Qt::DefaultLocaleShortDate) << temporary.date().toString(format: Qt::DefaultLocaleLongDate) << temporary.date().toString(format: "ddd MMMM d yy"));
905 QTest::newRow(dataTag: "formatDateTime, qdate") << "formatDateTime" << QVariant::fromValue(value: date) << (QStringList() << temporary.toString(format: Qt::DefaultLocaleShortDate) << temporary.toString(format: Qt::DefaultLocaleLongDate) << temporary.toString(format: "M/d/yy H:m:s a"));
906 QTest::newRow(dataTag: "formatTime, qdate") << "formatTime" << QVariant::fromValue(value: date) << (QStringList() << temporary.time().toString(f: Qt::DefaultLocaleShortDate) << temporary.time().toString(f: Qt::DefaultLocaleLongDate) << temporary.time().toString(format: "H:m:s a") << temporary.time().toString(format: "hh:mm:ss.zzz"));
907
908 QDateTime dateTime(date, time);
909 temporary = dateTime;
910 QTest::newRow(dataTag: "formatDate, qdatetime") << "formatDate" << QVariant::fromValue(value: dateTime) << (QStringList() << temporary.date().toString(format: Qt::DefaultLocaleShortDate) << temporary.date().toString(format: Qt::DefaultLocaleLongDate) << temporary.date().toString(format: "ddd MMMM d yy"));
911 QTest::newRow(dataTag: "formatDateTime, qdatetime") << "formatDateTime" << QVariant::fromValue(value: dateTime) << (QStringList() << temporary.toString(format: Qt::DefaultLocaleShortDate) << temporary.toString(format: Qt::DefaultLocaleLongDate) << temporary.toString(format: "M/d/yy H:m:s a"));
912 QTest::newRow(dataTag: "formatTime, qdatetime") << "formatTime" << QVariant::fromValue(value: dateTime) << (QStringList() << temporary.time().toString(f: Qt::DefaultLocaleShortDate) << temporary.time().toString(f: Qt::DefaultLocaleLongDate) << temporary.time().toString(format: "H:m:s a") << temporary.time().toString(format: "hh:mm:ss.zzz"));
913
914 QString string(QLatin1String("2011/05/31 11:16:39.755"));
915 temporary = QDateTime::fromString(s: string, format: "yyyy/MM/dd HH:mm:ss.zzz");
916 QTest::newRow(dataTag: "formatDate, qstring") << "formatDate" << QVariant::fromValue(value: string) << (QStringList() << temporary.date().toString(format: Qt::DefaultLocaleShortDate) << temporary.date().toString(format: Qt::DefaultLocaleLongDate) << temporary.date().toString(format: "ddd MMMM d yy"));
917 QTest::newRow(dataTag: "formatDateTime, qstring") << "formatDateTime" << QVariant::fromValue(value: string) << (QStringList() << temporary.toString(format: Qt::DefaultLocaleShortDate) << temporary.toString(format: Qt::DefaultLocaleLongDate) << temporary.toString(format: "M/d/yy H:m:s a"));
918 QTest::newRow(dataTag: "formatTime, qstring") << "formatTime" << QVariant::fromValue(value: string) << (QStringList() << temporary.time().toString(f: Qt::DefaultLocaleShortDate) << temporary.time().toString(f: Qt::DefaultLocaleLongDate) << temporary.time().toString(format: "H:m:s a") << temporary.time().toString(format: "hh:mm:ss.zzz"));
919
920 QColor color(Qt::red);
921 temporary = QVariant::fromValue(value: color).toDateTime();
922 QTest::newRow(dataTag: "formatDate, qcolor") << "formatDate" << QVariant::fromValue(value: color) << (QStringList() << temporary.date().toString(format: Qt::DefaultLocaleShortDate) << temporary.date().toString(format: Qt::DefaultLocaleLongDate) << temporary.date().toString(format: "ddd MMMM d yy"));
923 QTest::newRow(dataTag: "formatDateTime, qcolor") << "formatDateTime" << QVariant::fromValue(value: color) << (QStringList() << temporary.toString(format: Qt::DefaultLocaleShortDate) << temporary.toString(format: Qt::DefaultLocaleLongDate) << temporary.toString(format: "M/d/yy H:m:s a"));
924 QTest::newRow(dataTag: "formatTime, qcolor") << "formatTime" << QVariant::fromValue(value: color) << (QStringList() << temporary.time().toString(f: Qt::DefaultLocaleShortDate) << temporary.time().toString(f: Qt::DefaultLocaleLongDate) << temporary.time().toString(format: "H:m:s a") << temporary.time().toString(format: "hh:mm:ss.zzz"));
925
926 int integer(4);
927 temporary = QVariant::fromValue(value: integer).toDateTime();
928 QTest::newRow(dataTag: "formatDate, int") << "formatDate" << QVariant::fromValue(value: integer) << (QStringList() << temporary.date().toString(format: Qt::DefaultLocaleShortDate) << temporary.date().toString(format: Qt::DefaultLocaleLongDate) << temporary.date().toString(format: "ddd MMMM d yy"));
929 QTest::newRow(dataTag: "formatDateTime, int") << "formatDateTime" << QVariant::fromValue(value: integer) << (QStringList() << temporary.toString(format: Qt::DefaultLocaleShortDate) << temporary.toString(format: Qt::DefaultLocaleLongDate) << temporary.toString(format: "M/d/yy H:m:s a"));
930 QTest::newRow(dataTag: "formatTime, int") << "formatTime" << QVariant::fromValue(value: integer) << (QStringList() << temporary.time().toString(f: Qt::DefaultLocaleShortDate) << temporary.time().toString(f: Qt::DefaultLocaleLongDate) << temporary.time().toString(format: "H:m:s a") << temporary.time().toString(format: "hh:mm:ss.zzz"));
931 QT_WARNING_POP
932}
933
934void tst_qqmlqt::dateTimeFormattingWithLocale()
935{
936 QQmlEngine engine;
937 auto url = testFileUrl(fileName: "formattingLocale.qml");
938 QQmlComponent comp(&engine, url);
939 QDateTime dateTime = QDateTime::fromString(s: "M1d1y9800:01:02",
940 format: "'M'M'd'd'y'yyhh:mm:ss");
941 QDate date(1995, 5, 17);
942 QScopedPointer<QObject> o(comp.createWithInitialProperties(initialProperties: { {"myDateTime", dateTime}, {"myDate", date} }));
943 QVERIFY(!o.isNull());
944
945 auto dateTimeString = o->property(name: "dateTimeString").toString();
946 QCOMPARE(dateTimeString, QLocale("de_DE").toString(dateTime, QLocale::NarrowFormat));
947 auto dateString = o->property(name: "dateString").toString();
948 QCOMPARE(dateString, QLocale("de_DE").toString(date, QLocale::ShortFormat));
949
950 QString warningMsg = url.toString() + QLatin1String(":11: Error: Qt.formatTime(): Third argument must be a Locale format option");
951 QTest::ignoreMessage(type: QtMsgType::QtWarningMsg, message: warningMsg.toUtf8().constData());
952 QMetaObject::invokeMethod(obj: o.get(), member: "invalidUsage");
953}
954
955void tst_qqmlqt::isQtObject()
956{
957 QQmlComponent component(&engine, testFileUrl(fileName: "isQtObject.qml"));
958 QObject *object = component.create();
959 QVERIFY(object != nullptr);
960
961 QCOMPARE(object->property("test1").toBool(), true);
962 QCOMPARE(object->property("test2").toBool(), false);
963 QCOMPARE(object->property("test3").toBool(), false);
964 QCOMPARE(object->property("test4").toBool(), false);
965 QCOMPARE(object->property("test5").toBool(), false);
966
967 delete object;
968}
969
970void tst_qqmlqt::btoa()
971{
972 QQmlComponent component(&engine, testFileUrl(fileName: "btoa.qml"));
973
974 QString warning1 = component.url().toString() + ":4: Error: Qt.btoa(): Invalid arguments";
975 QTest::ignoreMessage(type: QtWarningMsg, qPrintable(warning1));
976
977 QObject *object = component.create();
978 QVERIFY(object != nullptr);
979
980 QCOMPARE(object->property("test2").toString(), QString("SGVsbG8gd29ybGQh"));
981
982 delete object;
983}
984
985void tst_qqmlqt::atob()
986{
987 QQmlComponent component(&engine, testFileUrl(fileName: "atob.qml"));
988
989 QString warning1 = component.url().toString() + ":4: Error: Qt.atob(): Invalid arguments";
990 QTest::ignoreMessage(type: QtWarningMsg, qPrintable(warning1));
991
992 QObject *object = component.create();
993 QVERIFY(object != nullptr);
994
995 QCOMPARE(object->property("test2").toString(), QString("Hello world!"));
996
997 delete object;
998}
999
1000void tst_qqmlqt::fontFamilies()
1001{
1002 QQmlComponent component(&engine, testFileUrl(fileName: "fontFamilies.qml"));
1003
1004 QString warning1 = component.url().toString() + ":4: Error: Qt.fontFamilies(): Invalid arguments";
1005 QTest::ignoreMessage(type: QtWarningMsg, qPrintable(warning1));
1006
1007 QObject *object = component.create();
1008 QVERIFY(object != nullptr);
1009
1010 QFontDatabase database;
1011 QCOMPARE(object->property("test2"), QVariant::fromValue(database.families()));
1012
1013 delete object;
1014}
1015
1016void tst_qqmlqt::quit()
1017{
1018 QQmlComponent component(&engine, testFileUrl(fileName: "quit.qml"));
1019
1020 QSignalSpy spy(&engine, SIGNAL(quit()));
1021 QObject *object = component.create();
1022 QVERIFY(object != nullptr);
1023 QCOMPARE(spy.count(), 1);
1024
1025 delete object;
1026}
1027
1028void tst_qqmlqt::exit()
1029{
1030 QQmlComponent component(&engine, testFileUrl(fileName: "exit.qml"));
1031
1032 QSignalSpy spy(&engine, &QQmlEngine::exit);
1033 QObject *object = component.create();
1034 QVERIFY(object != nullptr);
1035 QCOMPARE(spy.count(), 1);
1036 QList<QVariant> arguments = spy.takeFirst();
1037 QVERIFY(arguments.at(0).toInt() == object->property("returnCode").toInt());
1038
1039 delete object;
1040}
1041
1042void tst_qqmlqt::resolvedUrl()
1043{
1044 QQmlComponent component(&engine, testFileUrl(fileName: "resolvedUrl.qml"));
1045
1046 QObject *object = component.create();
1047 QVERIFY(object != nullptr);
1048
1049 QCOMPARE(object->property("result").toString(), component.url().toString());
1050 QCOMPARE(object->property("isString").toBool(), true);
1051
1052 delete object;
1053}
1054
1055void tst_qqmlqt::later_data()
1056{
1057 QTest::addColumn<QString>(name: "function");
1058 QTest::addColumn<QStringList>(name: "expectedWarnings");
1059 QTest::addColumn<QStringList>(name: "propNames");
1060 QTest::addColumn<QVariantList>(name: "values");
1061
1062 QVariant vtrue = QVariant(true);
1063
1064 QTest::newRow(dataTag: "callLater from onCompleted")
1065 << QString()
1066 << QStringList()
1067 << (QStringList() << "test1_1" << "test2_1" << "processEvents" << "test1_2" << "test2_2")
1068 << (QVariantList() << vtrue << vtrue << QVariant() << vtrue << vtrue);
1069
1070 QTest::newRow(dataTag: "trigger Qt.callLater() via repeater")
1071 << QString(QLatin1String("test2"))
1072 << QStringList()
1073 << (QStringList() << "processEvents" << "test2_2")
1074 << (QVariantList() << QVariant() << vtrue);
1075
1076 QTest::newRow(dataTag: "recursive Qt.callLater()")
1077 << QString(QLatin1String("test3"))
1078 << QStringList()
1079 << (QStringList() << "processEvents" << "test3_1" << "processEvents" << "test3_2" << "processEvents" << "test3_3")
1080 << (QVariantList() << QVariant() << vtrue << QVariant() << vtrue << QVariant() << vtrue);
1081
1082 QTest::newRow(dataTag: "nonexistent function")
1083 << QString(QLatin1String("test4"))
1084 << (QStringList() << QString(testFileUrl(fileName: "later.qml").toString() + QLatin1String(":70: ReferenceError: functionThatDoesNotExist is not defined")))
1085 << QStringList()
1086 << QVariantList();
1087
1088 QTest::newRow(dataTag: "callLater with different args")
1089 << QString(QLatin1String("test5"))
1090 << QStringList()
1091 << (QStringList() << "processEvents" << "test5_1")
1092 << (QVariantList() << QVariant() << vtrue);
1093
1094 QTest::newRow(dataTag: "delayed call ordering")
1095 << QString(QLatin1String("test6"))
1096 << QStringList()
1097 << (QStringList() << "processEvents" << "test6_1")
1098 << (QVariantList() << QVariant() << vtrue);
1099
1100 QTest::newRow(dataTag: "invoke module api invokable")
1101 << QString(QLatin1String("test9"))
1102 << QStringList()
1103 << (QStringList() << "processEvents" << "test9_1" << "processEvents")
1104 << (QVariantList() << QVariant() << QVariant(1) << QVariant());
1105
1106 QTest::newRow(dataTag: "invoke function of deleted QObject via callLater() causing deletion")
1107 << QString(QLatin1String("test10"))
1108 << (QStringList() << QString(testFileUrl(fileName: "LaterComponent.qml").toString() + QLatin1String(":8: ReferenceError: dangerousFunction is not defined (exception occurred during delayed function evaluation)")))
1109 << (QStringList() << "processEvents" << "test10_1" << "processEvents")
1110 << (QVariantList() << QVariant() << QVariant(0) << QVariant());
1111
1112 QTest::newRow(dataTag: "invoke function of deleted QObject via callLater() after deletion")
1113 << QString(QLatin1String("test11"))
1114 << QStringList()
1115 << (QStringList() << "collectGarbage" << "processEvents" << "test11_1" << "processEvents")
1116 << (QVariantList() << QVariant() << QVariant() << QVariant(1) << QVariant());
1117
1118 QTest::newRow(dataTag: "invoke function which has no script origin")
1119 << QString(QLatin1String("test14"))
1120 << QStringList()
1121 << (QStringList() << "collectGarbage")
1122 << (QVariantList() << QVariant());
1123}
1124
1125void tst_qqmlqt::later()
1126{
1127 QFETCH(QString, function);
1128 QFETCH(QStringList, expectedWarnings);
1129 QFETCH(QStringList, propNames);
1130 QFETCH(QVariantList, values);
1131
1132 foreach (const QString &w, expectedWarnings)
1133 QTest::ignoreMessage(type: QtWarningMsg, qPrintable(w));
1134
1135 QQmlComponent component(&engine, testFileUrl(fileName: "later.qml"));
1136 QObject *root = component.create();
1137 QVERIFY(root != nullptr);
1138
1139 if (!function.isEmpty())
1140 QMetaObject::invokeMethod(obj: root, qPrintable(function));
1141
1142 for (int i = 0; i < propNames.size(); ++i) {
1143 if (propNames.at(i) == QLatin1String("processEvents")) {
1144 QCoreApplication::sendPostedEvents(receiver: nullptr, event_type: QEvent::DeferredDelete);
1145 QCoreApplication::processEvents();
1146 } else if (propNames.at(i) == QLatin1String("collectGarbage")) {
1147 engine.collectGarbage();
1148 } else {
1149 QCOMPARE(root->property(qPrintable(propNames.at(i))), values.at(i));
1150 }
1151 }
1152
1153 delete root;
1154}
1155
1156void tst_qqmlqt::qtObjectContents()
1157{
1158 struct StaticQtMetaObject : public QObject
1159 {
1160 static const QMetaObject *get()
1161 { return &staticQtMetaObject; }
1162 };
1163
1164 QQmlComponent component(&engine, testFileUrl(fileName: "qtObjectContents.qml"));
1165
1166 QObject *object = component.create();
1167 QVERIFY(object != nullptr);
1168
1169 QVERIFY(object->property("values").canConvert<QJSValue>());
1170 QVariantMap values = object->property(name: "values").value<QJSValue>().toVariant().toMap();
1171
1172 QSet<const char *> keys;
1173 int uniqueKeys = 0;
1174 const QMetaObject *qtMetaObject = StaticQtMetaObject::get();
1175 for (int ii = 0; ii < qtMetaObject->enumeratorCount(); ++ii) {
1176 QMetaEnum enumerator = qtMetaObject->enumerator(index: ii);
1177 for (int jj = 0; jj < enumerator.keyCount(); ++jj) {
1178 auto key = enumerator.key(index: jj);
1179// qDebug() << "key:" << key;
1180 if (!keys.contains(value: key)) {
1181 ++uniqueKeys;
1182 keys.insert(value: key);
1183 }
1184 QVERIFY(values.contains(key));
1185 QVariant value = values.value(akey: key);
1186 QVERIFY(value.canConvert<int>());
1187 QCOMPARE(value.toInt(), enumerator.value(jj));
1188 }
1189 }
1190 QVERIFY(values.contains("Asynchronous"));
1191 QCOMPARE(values.value("Asynchronous").toInt(), 0);
1192 ++uniqueKeys;
1193 QVERIFY(values.contains("Synchronous"));
1194 QCOMPARE(values.value("Synchronous").toInt(), 1);
1195 ++uniqueKeys;
1196 QCOMPARE(values.count(), uniqueKeys);
1197
1198 delete object;
1199}
1200
1201class TimeProvider: public QObject
1202{
1203 Q_OBJECT
1204 QML_NAMED_ELEMENT(TimeProvider)
1205 Q_PROPERTY(QTime time READ time WRITE setTime NOTIFY timeChanged)
1206
1207public:
1208 TimeProvider(const QTime &t)
1209 : m_getTime(t)
1210 {}
1211
1212 QTime time() const { return m_getTime; }
1213 void setTime(const QTime &t) { m_putTime = t; emit timeChanged(); }
1214
1215signals:
1216 void timeChanged();
1217
1218public:
1219 QTime m_getTime, m_putTime;
1220};
1221
1222class TimeZoneSwitch
1223{
1224public:
1225 TimeZoneSwitch(const char *newZone)
1226 : doChangeZone(qstrcmp(str1: newZone, str2: "localtime") == 0)
1227 {
1228 if (!doChangeZone)
1229 return;
1230
1231 hadOldZone = qEnvironmentVariableIsSet(varName: "TZ");
1232 if (hadOldZone) {
1233 oldZone = qgetenv(varName: "TZ");
1234 }
1235 qputenv(varName: "TZ", value: newZone);
1236 tzset();
1237 }
1238
1239 ~TimeZoneSwitch()
1240 {
1241 if (!doChangeZone)
1242 return;
1243
1244 if (hadOldZone)
1245 qputenv(varName: "TZ", value: oldZone);
1246 else
1247 qunsetenv(varName: "TZ");
1248 tzset();
1249 }
1250
1251private:
1252 bool doChangeZone;
1253 bool hadOldZone;
1254 QByteArray oldZone;
1255};
1256
1257void tst_qqmlqt::timeRoundtrip_data()
1258{
1259 QTest::addColumn<QTime>(name: "time");
1260
1261 // Local timezone:
1262 QTest::newRow(dataTag: "localtime") << QTime(0, 0, 0);
1263
1264 // No DST:
1265 QTest::newRow(dataTag: "UTC") << QTime(0, 0, 0);
1266 QTest::newRow(dataTag: "Europe/Amsterdam") << QTime(1, 0, 0);
1267 QTest::newRow(dataTag: "Asia/Jakarta") << QTime(7, 0, 0);
1268
1269 // DST:
1270 QTest::newRow(dataTag: "Namibia/Windhoek") << QTime(1, 0, 0);
1271 QTest::newRow(dataTag: "Australia/Adelaide") << QTime(10, 0, 0);
1272 QTest::newRow(dataTag: "Australia/Hobart") << QTime(10, 0, 0);
1273 QTest::newRow(dataTag: "Pacific/Auckland") << QTime(12, 0, 0);
1274 QTest::newRow(dataTag: "Pacific/Samoa") << QTime(13, 0, 0);
1275}
1276
1277void tst_qqmlqt::timeRoundtrip()
1278{
1279#ifdef Q_OS_WIN
1280 QSKIP("On Windows, the DateObject doesn't handle DST transitions correctly when the timezone is not localtime."); // I.e.: for this test.
1281#endif
1282
1283 TimeZoneSwitch tzs(QTest::currentDataTag());
1284 QFETCH(QTime, time);
1285 qmlRegisterTypesAndRevisions<TimeProvider>(uri: "Test", versionMajor: 1);
1286
1287 TimeProvider tp(time);
1288
1289 QQmlEngine eng;
1290 //qmlRegisterSingletonInstance("Test", 1, 0, "TimeProvider", &tp);
1291 QQmlComponent component(&eng, testFileUrl(fileName: "timeRoundtrip.qml"));
1292 QObject *obj = component.createWithInitialProperties(initialProperties: {{"tp", QVariant::fromValue(value: &tp)}});
1293 QVERIFY(obj != nullptr);
1294
1295 // QML reads m_getTime and saves the result as m_putTime; this should come out the same, without
1296 // any perturbation (e.g. by DST effects) from converting from QTime to V4's Date and back
1297 // again.
1298 QCOMPARE(tp.m_getTime, tp.m_putTime);
1299}
1300
1301QTEST_MAIN(tst_qqmlqt)
1302
1303#include "tst_qqmlqt.moc"
1304

source code of qtdeclarative/tests/auto/qml/qqmlqt/tst_qqmlqt.cpp