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 "tst_qjsvalue.h"
30
31#include <private/qv4engine_p.h>
32#include <private/qjsvalue_p.h>
33
34#include <QtWidgets/QPushButton>
35#include <QtCore/qthread.h>
36
37#include <memory>
38
39tst_QJSValue::tst_QJSValue()
40 : engine(nullptr)
41{
42}
43
44tst_QJSValue::~tst_QJSValue()
45{
46 delete engine;
47}
48
49void tst_QJSValue::ctor_invalid()
50{
51 QJSEngine eng;
52 {
53 QJSValue v;
54 QVERIFY(v.isUndefined());
55#ifdef QT_DEPRECATED
56 QCOMPARE(v.engine(), (QJSEngine *)nullptr);
57#endif
58 }
59}
60
61void tst_QJSValue::ctor_undefinedWithEngine()
62{
63 QJSEngine eng;
64 {
65 QJSValue v = eng.toScriptValue(value: QVariant());
66 QVERIFY(v.isUndefined());
67 QCOMPARE(v.isObject(), false);
68#ifdef QT_DEPRECATED
69 QCOMPARE(v.engine(), &eng);
70#endif
71 }
72}
73
74void tst_QJSValue::ctor_nullWithEngine()
75{
76 QJSEngine eng;
77 {
78 QJSValue v = eng.evaluate(program: "null");
79 QVERIFY(!v.isUndefined());
80 QCOMPARE(v.isNull(), true);
81 QCOMPARE(v.isObject(), false);
82#ifdef QT_DEPRECATED
83 QCOMPARE(v.engine(), &eng);
84#endif
85 }
86}
87
88void tst_QJSValue::ctor_boolWithEngine()
89{
90 QJSEngine eng;
91 {
92 QJSValue v = eng.toScriptValue(value: false);
93 QVERIFY(!v.isUndefined());
94 QCOMPARE(v.isBool(), true);
95 QCOMPARE(v.isObject(), false);
96 QCOMPARE(v.toBool(), false);
97#ifdef QT_DEPRECATED
98 QCOMPARE(v.engine(), &eng);
99#endif
100 }
101}
102
103void tst_QJSValue::ctor_intWithEngine()
104{
105 QJSEngine eng;
106 {
107 QJSValue v = eng.toScriptValue(value: int(1));
108 QVERIFY(!v.isUndefined());
109 QCOMPARE(v.isNumber(), true);
110 QCOMPARE(v.isObject(), false);
111 QCOMPARE(v.toNumber(), 1.0);
112#ifdef QT_DEPRECATED
113 QCOMPARE(v.engine(), &eng);
114#endif
115 }
116}
117
118void tst_QJSValue::ctor_int()
119{
120 {
121 QJSValue v(int(0x43211234));
122 QVERIFY(v.isNumber());
123 QCOMPARE(v.toInt(), 0x43211234);
124 }
125 {
126 QJSValue v(int(1));
127 QVERIFY(!v.isUndefined());
128 QCOMPARE(v.isNumber(), true);
129 QCOMPARE(v.isObject(), false);
130 QCOMPARE(v.toNumber(), 1.0);
131#ifdef QT_DEPRECATED
132 QCOMPARE(v.engine(), (QJSEngine *)nullptr);
133#endif
134 }
135}
136
137void tst_QJSValue::ctor_uintWithEngine()
138{
139 QJSEngine eng;
140 {
141 QJSValue v = eng.toScriptValue(value: uint(1));
142 QVERIFY(!v.isUndefined());
143 QCOMPARE(v.isNumber(), true);
144 QCOMPARE(v.isObject(), false);
145 QCOMPARE(v.toNumber(), 1.0);
146#ifdef QT_DEPRECATED
147 QCOMPARE(v.engine(), &eng);
148#endif
149 }
150}
151
152void tst_QJSValue::ctor_uint()
153{
154 {
155 QJSValue v(uint(0x43211234));
156 QVERIFY(v.isNumber());
157 QCOMPARE(v.toUInt(), uint(0x43211234));
158 }
159 {
160 QJSValue v(uint(1));
161 QVERIFY(!v.isUndefined());
162 QCOMPARE(v.isNumber(), true);
163 QCOMPARE(v.isObject(), false);
164 QCOMPARE(v.toNumber(), 1.0);
165#ifdef QT_DEPRECATED
166 QCOMPARE(v.engine(), (QJSEngine *)nullptr);
167#endif
168 }
169}
170
171void tst_QJSValue::ctor_floatWithEngine()
172{
173 QJSEngine eng;
174 {
175 QJSValue v = eng.toScriptValue(value: float(1.0));
176 QVERIFY(!v.isUndefined());
177 QCOMPARE(v.isNumber(), true);
178 QCOMPARE(v.isObject(), false);
179 QCOMPARE(v.toNumber(), 1.0);
180#ifdef QT_DEPRECATED
181 QCOMPARE(v.engine(), &eng);
182#endif
183 }
184}
185
186void tst_QJSValue::ctor_float()
187{
188 {
189 QJSValue v(12345678910.5);
190 QVERIFY(v.isNumber());
191 QCOMPARE(v.toNumber(), 12345678910.5);
192 }
193 {
194 QJSValue v(1.0);
195 QVERIFY(!v.isUndefined());
196 QCOMPARE(v.isNumber(), true);
197 QCOMPARE(v.isObject(), false);
198 QCOMPARE(v.toNumber(), 1.0);
199#ifdef QT_DEPRECATED
200 QCOMPARE(v.engine(), (QJSEngine *)nullptr);
201#endif
202 }
203}
204
205void tst_QJSValue::ctor_stringWithEngine()
206{
207 QJSEngine eng;
208 {
209 QJSValue v = eng.toScriptValue(value: QString::fromLatin1(str: "ciao"));
210 QVERIFY(!v.isUndefined());
211 QCOMPARE(v.isString(), true);
212 QCOMPARE(v.isObject(), false);
213 QCOMPARE(v.toString(), QLatin1String("ciao"));
214#ifdef QT_DEPRECATED
215 QCOMPARE(v.engine(), &eng);
216#endif
217 }
218}
219
220void tst_QJSValue::ctor_string()
221{
222 {
223 QJSValue v(QString("ciao"));
224 QVERIFY(!v.isUndefined());
225 QCOMPARE(v.isString(), true);
226 QCOMPARE(v.isObject(), false);
227 QCOMPARE(v.toString(), QLatin1String("ciao"));
228#ifdef QT_DEPRECATED
229 QCOMPARE(v.engine(), (QJSEngine *)nullptr);
230#endif
231 }
232 {
233 QJSValue v("ciao");
234 QVERIFY(!v.isUndefined());
235 QCOMPARE(v.isString(), true);
236 QCOMPARE(v.isObject(), false);
237 QCOMPARE(v.toString(), QLatin1String("ciao"));
238#ifdef QT_DEPRECATED
239 QCOMPARE(v.engine(), (QJSEngine *)nullptr);
240#endif
241 }
242}
243
244void tst_QJSValue::ctor_copyAndAssignWithEngine()
245{
246 QJSEngine eng;
247 // copy constructor, operator=
248 {
249 QJSValue v = eng.toScriptValue(value: 1.0);
250 QJSValue v2(v);
251 QCOMPARE(v2.strictlyEquals(v), true);
252#ifdef QT_DEPRECATED
253 QCOMPARE(v2.engine(), &eng);
254#endif
255
256 QJSValue v3(v);
257 QCOMPARE(v3.strictlyEquals(v), true);
258 QCOMPARE(v3.strictlyEquals(v2), true);
259#ifdef QT_DEPRECATED
260 QCOMPARE(v3.engine(), &eng);
261#endif
262
263 QJSValue v4 = eng.toScriptValue(value: 2.0);
264 QCOMPARE(v4.strictlyEquals(v), false);
265 v3 = v4;
266 QCOMPARE(v3.strictlyEquals(v), false);
267 QCOMPARE(v3.strictlyEquals(v4), true);
268
269 v2 = QJSValue();
270 QCOMPARE(v2.strictlyEquals(v), false);
271 QCOMPARE(v.toNumber(), 1.0);
272
273 QJSValue v5(v);
274 QCOMPARE(v5.strictlyEquals(v), true);
275 v = QJSValue();
276 QCOMPARE(v5.strictlyEquals(v), false);
277 QCOMPARE(v5.toNumber(), 1.0);
278 }
279}
280
281void tst_QJSValue::ctor_undefined()
282{
283 QJSValue v(QJSValue::UndefinedValue);
284 QVERIFY(v.isUndefined());
285 QCOMPARE(v.isObject(), false);
286#ifdef QT_DEPRECATED
287 QCOMPARE(v.engine(), (QJSEngine *)nullptr);
288#endif
289}
290
291void tst_QJSValue::ctor_null()
292{
293 QJSValue v(QJSValue::NullValue);
294 QVERIFY(!v.isUndefined());
295 QCOMPARE(v.isNull(), true);
296 QCOMPARE(v.isObject(), false);
297#ifdef QT_DEPRECATED
298 QCOMPARE(v.engine(), (QJSEngine *)nullptr);
299#endif
300}
301
302void tst_QJSValue::ctor_bool()
303{
304 QJSValue v(false);
305 QVERIFY(!v.isUndefined());
306 QCOMPARE(v.isBool(), true);
307 QCOMPARE(v.isBool(), true);
308 QCOMPARE(v.isObject(), false);
309 QCOMPARE(v.toBool(), false);
310#ifdef QT_DEPRECATED
311 QCOMPARE(v.engine(), (QJSEngine *)nullptr);
312#endif
313}
314
315void tst_QJSValue::ctor_copyAndAssign()
316{
317 QJSValue v(1.0);
318 QJSValue v2(v);
319 QCOMPARE(v2.strictlyEquals(v), true);
320#ifdef QT_DEPRECATED
321 QCOMPARE(v2.engine(), (QJSEngine *)nullptr);
322#endif
323
324 QJSValue v3(v);
325 QCOMPARE(v3.strictlyEquals(v), true);
326 QCOMPARE(v3.strictlyEquals(v2), true);
327#ifdef QT_DEPRECATED
328 QCOMPARE(v3.engine(), (QJSEngine *)nullptr);
329#endif
330
331 QJSValue v4(2.0);
332 QCOMPARE(v4.strictlyEquals(v), false);
333 v3 = v4;
334 QCOMPARE(v3.strictlyEquals(v), false);
335 QCOMPARE(v3.strictlyEquals(v4), true);
336
337 v2 = QJSValue();
338 QCOMPARE(v2.strictlyEquals(v), false);
339 QCOMPARE(v.toNumber(), 1.0);
340
341 QJSValue v5(v);
342 QCOMPARE(v5.strictlyEquals(v), true);
343 v = QJSValue();
344 QCOMPARE(v5.strictlyEquals(v), false);
345 QCOMPARE(v5.toNumber(), 1.0);
346}
347
348static QJSValue createUnboundValue(const QJSValue &value)
349{
350 QVariant variant = QVariant::fromValue(value);
351 QBuffer buffer;
352 buffer.open(openMode: QIODevice::ReadWrite);
353 QDataStream stream(&buffer);
354 variant.save(ds&: stream);
355 buffer.seek(off: 0);
356 QVariant resultVariant;
357 resultVariant.load(ds&: stream);
358 return resultVariant.value<QJSValue>();
359}
360
361void tst_QJSValue::toString()
362{
363 QJSEngine eng;
364
365 QJSValue undefined = eng.toScriptValue(value: QVariant());
366 QCOMPARE(undefined.toString(), QString("undefined"));
367 QCOMPARE(qjsvalue_cast<QString>(undefined), QString());
368
369 QJSValue null = eng.evaluate(program: "null");
370 QCOMPARE(null.toString(), QString("null"));
371 QCOMPARE(qjsvalue_cast<QString>(null), QString());
372
373 {
374 QJSValue falskt = eng.toScriptValue(value: false);
375 QCOMPARE(falskt.toString(), QString("false"));
376 QCOMPARE(qjsvalue_cast<QString>(falskt), QString("false"));
377
378 QJSValue sant = eng.toScriptValue(value: true);
379 QCOMPARE(sant.toString(), QString("true"));
380 QCOMPARE(qjsvalue_cast<QString>(sant), QString("true"));
381 }
382 {
383 QJSValue number = eng.toScriptValue(value: 123);
384 QCOMPARE(number.toString(), QString("123"));
385 QCOMPARE(qjsvalue_cast<QString>(number), QString("123"));
386 }
387 {
388 QJSValue number = eng.toScriptValue(value: 6.37e-8);
389 QCOMPARE(number.toString(), QString("6.37e-8"));
390 }
391 {
392 QJSValue number = eng.toScriptValue(value: -6.37e-8);
393 QCOMPARE(number.toString(), QString("-6.37e-8"));
394
395 QJSValue str = eng.toScriptValue(value: QString("ciao"));
396 QCOMPARE(str.toString(), QString("ciao"));
397 QCOMPARE(qjsvalue_cast<QString>(str), QString("ciao"));
398 }
399
400 QJSValue object = eng.newObject();
401 QCOMPARE(object.toString(), QString("[object Object]"));
402 QCOMPARE(qjsvalue_cast<QString>(object), QString("[object Object]"));
403
404 // toString() that throws exception
405 {
406 QJSValue objectObject = eng.evaluate(
407 program: "(function(){"
408 " o = { };"
409 " o.toString = function() { throw new Error('toString'); };"
410 " return o;"
411 "})()");
412 QCOMPARE(objectObject.toString(), QLatin1String("Error: toString"));
413 }
414 {
415 QJSValue objectObject = eng.evaluate(
416 program: "(function(){"
417 " var f = function() {};"
418 " f.prototype = Date;"
419 " return new f;"
420 "})()");
421 QVERIFY(!objectObject.isError());
422 QVERIFY(objectObject.isObject());
423 QCOMPARE(objectObject.toString(), QString::fromLatin1("TypeError: Type error"));
424 }
425
426 QJSValue inv = QJSValue();
427 QCOMPARE(inv.toString(), QString::fromLatin1("undefined"));
428
429 // V2 constructors
430 {
431 QJSValue falskt = QJSValue(false);
432 QCOMPARE(falskt.toString(), QString("false"));
433 QCOMPARE(qjsvalue_cast<QString>(falskt), QString("false"));
434
435 QJSValue sant = QJSValue(true);
436 QCOMPARE(sant.toString(), QString("true"));
437 QCOMPARE(qjsvalue_cast<QString>(sant), QString("true"));
438
439 QJSValue number = QJSValue(123);
440 QCOMPARE(number.toString(), QString("123"));
441 QCOMPARE(qjsvalue_cast<QString>(number), QString("123"));
442
443 QJSValue number2(int(0x43211234));
444 QCOMPARE(number2.toString(), QString("1126240820"));
445
446 QJSValue str = QJSValue(QString("ciao"));
447 QCOMPARE(str.toString(), QString("ciao"));
448 QCOMPARE(qjsvalue_cast<QString>(str), QString("ciao"));
449 }
450
451 // variant should use internal valueOf(), then fall back to QVariant::toString(),
452 // then fall back to "QVariant(typename)"
453 QJSValue variant = eng.toScriptValue(value: QPoint(10, 20));
454 QVERIFY(!variant.isVariant());
455 QCOMPARE(variant.toString(), QString::fromLatin1("QPoint(10, 20)"));
456 variant = eng.toScriptValue(value: QUrl());
457 QVERIFY(variant.isVariant());
458 QVERIFY(variant.toString().isEmpty());
459
460 {
461 QJSValue o = eng.newObject();
462 o.setProperty(QStringLiteral("test"), value: 42);
463 QCOMPARE(o.toString(), QStringLiteral("[object Object]"));
464
465 o = createUnboundValue(value: o);
466#ifdef QT_DEPRECATED
467 QVERIFY(!o.engine());
468#endif
469 QCOMPARE(o.toString(), QStringLiteral("[object Object]"));
470 }
471
472 {
473 QJSValue o = eng.newArray();
474 o.setProperty(arrayIndex: 0, value: 1);
475 o.setProperty(arrayIndex: 1, value: 2);
476 o.setProperty(arrayIndex: 2, value: 3);
477 QCOMPARE(o.toString(), QStringLiteral("1,2,3"));
478
479 o = createUnboundValue(value: o);
480#ifdef QT_DEPRECATED
481 QVERIFY(!o.engine());
482#endif
483 QCOMPARE(o.toString(), QStringLiteral("1,2,3"));
484 }
485
486 {
487 QByteArray hello = QByteArrayLiteral("Hello World");
488 QJSValue jsValue = eng.toScriptValue(value: hello);
489 QCOMPARE(jsValue.toString(), QString::fromUtf8(hello));
490 }
491}
492
493void tst_QJSValue::toNumber()
494{
495 QJSEngine eng;
496
497 QJSValue undefined = eng.toScriptValue(value: QVariant());
498 QCOMPARE(qIsNaN(undefined.toNumber()), true);
499 QCOMPARE(qIsNaN(qjsvalue_cast<qreal>(undefined)), true);
500
501 QJSValue null = eng.evaluate(program: "null");
502 QCOMPARE(null.toNumber(), 0.0);
503 QCOMPARE(qjsvalue_cast<qreal>(null), 0.0);
504 QCOMPARE(createUnboundValue(null).toNumber(), 0.0);
505
506 {
507 QJSValue falskt = eng.toScriptValue(value: false);
508 QCOMPARE(falskt.toNumber(), 0.0);
509 QCOMPARE(createUnboundValue(falskt).toNumber(), 0.0);
510 QCOMPARE(qjsvalue_cast<qreal>(falskt), 0.0);
511
512 QJSValue sant = eng.toScriptValue(value: true);
513 QCOMPARE(sant.toNumber(), 1.0);
514 QCOMPARE(createUnboundValue(sant).toNumber(), 1.0);
515 QCOMPARE(qjsvalue_cast<qreal>(sant), 1.0);
516
517 QJSValue number = eng.toScriptValue(value: 123.0);
518 QCOMPARE(number.toNumber(), 123.0);
519 QCOMPARE(qjsvalue_cast<qreal>(number), 123.0);
520 QCOMPARE(createUnboundValue(number).toNumber(), 123.0);
521
522 QJSValue str = eng.toScriptValue(value: QString("ciao"));
523 QCOMPARE(qIsNaN(str.toNumber()), true);
524 QCOMPARE(qIsNaN(qjsvalue_cast<qreal>(str)), true);
525 QCOMPARE(qIsNaN(createUnboundValue(str).toNumber()), true);
526
527 QJSValue str2 = eng.toScriptValue(value: QString("123"));
528 QCOMPARE(str2.toNumber(), 123.0);
529 QCOMPARE(qjsvalue_cast<qreal>(str2), 123.0);
530 QCOMPARE(createUnboundValue(str2).toNumber(), 123.0);
531 }
532
533 QJSValue object = eng.newObject();
534 QCOMPARE(qIsNaN(object.toNumber()), true);
535 QCOMPARE(qIsNaN(createUnboundValue(object).toNumber()), true);
536 QCOMPARE(qIsNaN(qjsvalue_cast<qreal>(object)), true);
537
538 QJSValue inv = QJSValue();
539 QVERIFY(qIsNaN(inv.toNumber()));
540 QCOMPARE(qIsNaN(createUnboundValue(inv).toNumber()), true);
541 QVERIFY(qIsNaN(qjsvalue_cast<qreal>(inv)));
542
543 // V2 constructors
544 {
545 QJSValue falskt = QJSValue(false);
546 QCOMPARE(falskt.toNumber(), 0.0);
547 QCOMPARE(qjsvalue_cast<qreal>(falskt), 0.0);
548
549 QJSValue sant = QJSValue(true);
550 QCOMPARE(sant.toNumber(), 1.0);
551 QCOMPARE(qjsvalue_cast<qreal>(sant), 1.0);
552
553 QJSValue number = QJSValue(123.0);
554 QCOMPARE(number.toNumber(), 123.0);
555 QCOMPARE(qjsvalue_cast<qreal>(number), 123.0);
556
557 QJSValue number2(int(0x43211234));
558 QCOMPARE(number2.toNumber(), 1126240820.0);
559
560 QJSValue str = QJSValue(QString("ciao"));
561 QCOMPARE(qIsNaN(str.toNumber()), true);
562 QCOMPARE(qIsNaN(qjsvalue_cast<qreal>(str)), true);
563
564 QJSValue str2 = QJSValue(QString("123"));
565 QCOMPARE(str2.toNumber(), 123.0);
566 QCOMPARE(qjsvalue_cast<qreal>(str2), 123.0);
567 }
568}
569
570void tst_QJSValue::toBoolean() // deprecated
571{
572 QJSEngine eng;
573
574 QJSValue undefined = eng.toScriptValue(value: QVariant());
575 QCOMPARE(undefined.toBool(), false);
576 QCOMPARE(qjsvalue_cast<bool>(undefined), false);
577
578 QJSValue null = eng.evaluate(program: "null");
579 QCOMPARE(null.toBool(), false);
580 QCOMPARE(qjsvalue_cast<bool>(null), false);
581
582 {
583 QJSValue falskt = eng.toScriptValue(value: false);
584 QCOMPARE(falskt.toBool(), false);
585 QCOMPARE(qjsvalue_cast<bool>(falskt), false);
586
587 QJSValue sant = eng.toScriptValue(value: true);
588 QCOMPARE(sant.toBool(), true);
589 QCOMPARE(qjsvalue_cast<bool>(sant), true);
590
591 QJSValue number = eng.toScriptValue(value: 0.0);
592 QCOMPARE(number.toBool(), false);
593 QCOMPARE(qjsvalue_cast<bool>(number), false);
594
595 QJSValue number2 = eng.toScriptValue(value: qQNaN());
596 QCOMPARE(number2.toBool(), false);
597 QCOMPARE(qjsvalue_cast<bool>(number2), false);
598
599 QJSValue number3 = eng.toScriptValue(value: 123.0);
600 QCOMPARE(number3.toBool(), true);
601 QCOMPARE(qjsvalue_cast<bool>(number3), true);
602
603 QJSValue number4 = eng.toScriptValue(value: -456.0);
604 QCOMPARE(number4.toBool(), true);
605 QCOMPARE(qjsvalue_cast<bool>(number4), true);
606
607 QJSValue str = eng.toScriptValue(value: QString(""));
608 QCOMPARE(str.toBool(), false);
609 QCOMPARE(qjsvalue_cast<bool>(str), false);
610
611 QJSValue str2 = eng.toScriptValue(value: QString("123"));
612 QCOMPARE(str2.toBool(), true);
613 QCOMPARE(qjsvalue_cast<bool>(str2), true);
614 }
615
616 QJSValue object = eng.newObject();
617 QCOMPARE(object.toBool(), true);
618 QCOMPARE(qjsvalue_cast<bool>(object), true);
619
620 QJSValue inv = QJSValue();
621 QCOMPARE(inv.toBool(), false);
622 QCOMPARE(qjsvalue_cast<bool>(inv), false);
623
624 // V2 constructors
625 {
626 QJSValue falskt = QJSValue(false);
627 QCOMPARE(falskt.toBool(), false);
628 QCOMPARE(qjsvalue_cast<bool>(falskt), false);
629
630 QJSValue sant = QJSValue(true);
631 QCOMPARE(sant.toBool(), true);
632 QCOMPARE(qjsvalue_cast<bool>(sant), true);
633
634 QJSValue number = QJSValue(0.0);
635 QCOMPARE(number.toBool(), false);
636 QCOMPARE(qjsvalue_cast<bool>(number), false);
637
638 QJSValue number2 = QJSValue(qQNaN());
639 QCOMPARE(number2.toBool(), false);
640 QCOMPARE(qjsvalue_cast<bool>(number2), false);
641
642 QJSValue number3 = QJSValue(123.0);
643 QCOMPARE(number3.toBool(), true);
644 QCOMPARE(qjsvalue_cast<bool>(number3), true);
645
646 QJSValue number4 = QJSValue(-456.0);
647 QCOMPARE(number4.toBool(), true);
648 QCOMPARE(qjsvalue_cast<bool>(number4), true);
649
650 QJSValue number5 = QJSValue(0x43211234);
651 QCOMPARE(number5.toBool(), true);
652
653 QJSValue str = QJSValue(QString(""));
654 QCOMPARE(str.toBool(), false);
655 QCOMPARE(qjsvalue_cast<bool>(str), false);
656
657 QJSValue str2 = QJSValue(QString("123"));
658 QCOMPARE(str2.toBool(), true);
659 QCOMPARE(qjsvalue_cast<bool>(str2), true);
660 }
661}
662
663void tst_QJSValue::toBool()
664{
665 QJSEngine eng;
666
667 QJSValue undefined = eng.toScriptValue(value: QVariant());
668 QCOMPARE(undefined.toBool(), false);
669 QCOMPARE(qjsvalue_cast<bool>(undefined), false);
670
671 QJSValue null = eng.evaluate(program: "null");
672 QCOMPARE(null.toBool(), false);
673 QCOMPARE(qjsvalue_cast<bool>(null), false);
674
675 {
676 QJSValue falskt = eng.toScriptValue(value: false);
677 QCOMPARE(falskt.toBool(), false);
678 QCOMPARE(qjsvalue_cast<bool>(falskt), false);
679
680 QJSValue sant = eng.toScriptValue(value: true);
681 QCOMPARE(sant.toBool(), true);
682 QCOMPARE(qjsvalue_cast<bool>(sant), true);
683
684 QJSValue number = eng.toScriptValue(value: 0.0);
685 QCOMPARE(number.toBool(), false);
686 QCOMPARE(qjsvalue_cast<bool>(number), false);
687
688 QJSValue number2 = eng.toScriptValue(value: qQNaN());
689 QCOMPARE(number2.toBool(), false);
690 QCOMPARE(qjsvalue_cast<bool>(number2), false);
691
692 QJSValue number3 = eng.toScriptValue(value: 123.0);
693 QCOMPARE(number3.toBool(), true);
694 QCOMPARE(qjsvalue_cast<bool>(number3), true);
695
696 QJSValue number4 = eng.toScriptValue(value: -456.0);
697 QCOMPARE(number4.toBool(), true);
698 QCOMPARE(qjsvalue_cast<bool>(number4), true);
699
700 QJSValue str = eng.toScriptValue(value: QString(""));
701 QCOMPARE(str.toBool(), false);
702 QCOMPARE(qjsvalue_cast<bool>(str), false);
703
704 QJSValue str2 = eng.toScriptValue(value: QString("123"));
705 QCOMPARE(str2.toBool(), true);
706 QCOMPARE(qjsvalue_cast<bool>(str2), true);
707 }
708
709 QJSValue object = eng.newObject();
710 QCOMPARE(object.toBool(), true);
711 QCOMPARE(qjsvalue_cast<bool>(object), true);
712
713 QJSValue inv = QJSValue();
714 QCOMPARE(inv.toBool(), false);
715 QCOMPARE(qjsvalue_cast<bool>(inv), false);
716
717 // V2 constructors
718 {
719 QJSValue falskt = QJSValue(false);
720 QCOMPARE(falskt.toBool(), false);
721 QCOMPARE(qjsvalue_cast<bool>(falskt), false);
722
723 QJSValue sant = QJSValue(true);
724 QCOMPARE(sant.toBool(), true);
725 QCOMPARE(qjsvalue_cast<bool>(sant), true);
726
727 QJSValue number = QJSValue(0.0);
728 QCOMPARE(number.toBool(), false);
729 QCOMPARE(qjsvalue_cast<bool>(number), false);
730
731 QJSValue number2 = QJSValue(qQNaN());
732 QCOMPARE(number2.toBool(), false);
733 QCOMPARE(qjsvalue_cast<bool>(number2), false);
734
735 QJSValue number3 = QJSValue(123.0);
736 QCOMPARE(number3.toBool(), true);
737 QCOMPARE(qjsvalue_cast<bool>(number3), true);
738
739 QJSValue number4 = QJSValue(-456.0);
740 QCOMPARE(number4.toBool(), true);
741 QCOMPARE(qjsvalue_cast<bool>(number4), true);
742
743 QJSValue number5 = QJSValue(0x43211234);
744 QCOMPARE(number5.toBool(), true);
745
746 QJSValue str = QJSValue(QString(""));
747 QCOMPARE(str.toBool(), false);
748 QCOMPARE(qjsvalue_cast<bool>(str), false);
749
750 QJSValue str2 = QJSValue(QString("123"));
751 QCOMPARE(str2.toBool(), true);
752 QCOMPARE(qjsvalue_cast<bool>(str2), true);
753 }
754}
755
756void tst_QJSValue::toInt()
757{
758 QJSEngine eng;
759
760 {
761 QJSValue zer0 = eng.toScriptValue(value: 0.0);
762 QCOMPARE(zer0.toInt(), 0);
763 QCOMPARE(qjsvalue_cast<qint32>(zer0), 0);
764
765 QJSValue number = eng.toScriptValue(value: 123.0);
766 QCOMPARE(number.toInt(), 123);
767 QCOMPARE(qjsvalue_cast<qint32>(number), 123);
768
769 QJSValue number2 = eng.toScriptValue(value: qQNaN());
770 QCOMPARE(number2.toInt(), 0);
771 QCOMPARE(qjsvalue_cast<qint32>(number2), 0);
772
773 QJSValue number3 = eng.toScriptValue(value: +qInf());
774 QCOMPARE(number3.toInt(), 0);
775 QCOMPARE(qjsvalue_cast<qint32>(number3), 0);
776
777 QJSValue number3_2 = eng.toScriptValue(value: -qInf());
778 QCOMPARE(number3_2.toInt(), 0);
779 QCOMPARE(qjsvalue_cast<qint32>(number3_2), 0);
780
781 QJSValue number4 = eng.toScriptValue(value: 0.5);
782 QCOMPARE(number4.toInt(), 0);
783 QCOMPARE(qjsvalue_cast<qint32>(number4), 0);
784
785 QJSValue number5 = eng.toScriptValue(value: 123.5);
786 QCOMPARE(number5.toInt(), 123);
787 QCOMPARE(qjsvalue_cast<qint32>(number5), 123);
788
789 QJSValue number6 = eng.toScriptValue(value: -456.5);
790 QCOMPARE(number6.toInt(), -456);
791 QCOMPARE(qjsvalue_cast<qint32>(number6), -456);
792
793 QJSValue str = eng.toScriptValue(value: QString::fromLatin1(str: "123.0"));
794 QCOMPARE(str.toInt(), 123);
795 QCOMPARE(qjsvalue_cast<qint32>(str), 123);
796
797 QJSValue str2 = eng.toScriptValue(value: QString::fromLatin1(str: "NaN"));
798 QCOMPARE(str2.toInt(), 0);
799 QCOMPARE(qjsvalue_cast<qint32>(str2), 0);
800
801 QJSValue str3 = eng.toScriptValue(value: QString::fromLatin1(str: "Infinity"));
802 QCOMPARE(str3.toInt(), 0);
803 QCOMPARE(qjsvalue_cast<qint32>(str3), 0);
804
805 QJSValue str3_2 = eng.toScriptValue(value: QString::fromLatin1(str: "-Infinity"));
806 QCOMPARE(str3_2.toInt(), 0);
807 QCOMPARE(qjsvalue_cast<qint32>(str3_2), 0);
808
809 QJSValue str4 = eng.toScriptValue(value: QString::fromLatin1(str: "0.5"));
810 QCOMPARE(str4.toInt(), 0);
811 QCOMPARE(qjsvalue_cast<qint32>(str4), 0);
812
813 QJSValue str5 = eng.toScriptValue(value: QString::fromLatin1(str: "123.5"));
814 QCOMPARE(str5.toInt(), 123);
815 QCOMPARE(qjsvalue_cast<qint32>(str5), 123);
816
817 QJSValue str6 = eng.toScriptValue(value: QString::fromLatin1(str: "-456.5"));
818 QCOMPARE(str6.toInt(), -456);
819 QCOMPARE(qjsvalue_cast<qint32>(str6), -456);
820 }
821 // V2 constructors
822 {
823 QJSValue zer0 = QJSValue(0.0);
824 QCOMPARE(zer0.toInt(), 0);
825 QCOMPARE(qjsvalue_cast<qint32>(zer0), 0);
826
827 QJSValue number = QJSValue(123.0);
828 QCOMPARE(number.toInt(), 123);
829 QCOMPARE(qjsvalue_cast<qint32>(number), 123);
830
831 QJSValue number2 = QJSValue(qQNaN());
832 QCOMPARE(number2.toInt(), 0);
833 QCOMPARE(qjsvalue_cast<qint32>(number2), 0);
834
835 QJSValue number3 = QJSValue(+qInf());
836 QCOMPARE(number3.toInt(), 0);
837 QCOMPARE(qjsvalue_cast<qint32>(number3), 0);
838
839 QJSValue number3_2 = QJSValue(-qInf());
840 QCOMPARE(number3_2.toInt(), 0);
841 QCOMPARE(qjsvalue_cast<qint32>(number3_2), 0);
842
843 QJSValue number4 = QJSValue(0.5);
844 QCOMPARE(number4.toInt(), 0);
845 QCOMPARE(qjsvalue_cast<qint32>(number4), 0);
846
847 QJSValue number5 = QJSValue(123.5);
848 QCOMPARE(number5.toInt(), 123);
849 QCOMPARE(qjsvalue_cast<qint32>(number5), 123);
850
851 QJSValue number6 = QJSValue(-456.5);
852 QCOMPARE(number6.toInt(), -456);
853 QCOMPARE(qjsvalue_cast<qint32>(number6), -456);
854
855 QJSValue number7 = QJSValue(0x43211234);
856 QCOMPARE(number7.toInt(), 0x43211234);
857
858 QJSValue str = QJSValue("123.0");
859 QCOMPARE(str.toInt(), 123);
860 QCOMPARE(qjsvalue_cast<qint32>(str), 123);
861
862 QJSValue str2 = QJSValue("NaN");
863 QCOMPARE(str2.toInt(), 0);
864 QCOMPARE(qjsvalue_cast<qint32>(str2), 0);
865
866 QJSValue str3 = QJSValue("Infinity");
867 QCOMPARE(str3.toInt(), 0);
868 QCOMPARE(qjsvalue_cast<qint32>(str3), 0);
869
870 QJSValue str3_2 = QJSValue("-Infinity");
871 QCOMPARE(str3_2.toInt(), 0);
872 QCOMPARE(qjsvalue_cast<qint32>(str3_2), 0);
873
874 QJSValue str4 = QJSValue("0.5");
875 QCOMPARE(str4.toInt(), 0);
876 QCOMPARE(qjsvalue_cast<qint32>(str4), 0);
877
878 QJSValue str5 = QJSValue("123.5");
879 QCOMPARE(str5.toInt(), 123);
880 QCOMPARE(qjsvalue_cast<qint32>(str5), 123);
881
882 QJSValue str6 = QJSValue("-456.5");
883 QCOMPARE(str6.toInt(), -456);
884 QCOMPARE(qjsvalue_cast<qint32>(str6), -456);
885 }
886
887 QJSValue inv;
888 QCOMPARE(inv.toInt(), 0);
889 QCOMPARE(qjsvalue_cast<qint32>(inv), 0);
890}
891
892void tst_QJSValue::toUInt()
893{
894 QJSEngine eng;
895
896 {
897 QJSValue zer0 = eng.toScriptValue(value: 0.0);
898 QCOMPARE(zer0.toUInt(), quint32(0));
899 QCOMPARE(qjsvalue_cast<quint32>(zer0), quint32(0));
900
901 QJSValue number = eng.toScriptValue(value: 123.0);
902 QCOMPARE(number.toUInt(), quint32(123));
903 QCOMPARE(qjsvalue_cast<quint32>(number), quint32(123));
904
905 QJSValue number2 = eng.toScriptValue(value: qQNaN());
906 QCOMPARE(number2.toUInt(), quint32(0));
907 QCOMPARE(qjsvalue_cast<quint32>(number2), quint32(0));
908
909 QJSValue number3 = eng.toScriptValue(value: +qInf());
910 QCOMPARE(number3.toUInt(), quint32(0));
911 QCOMPARE(qjsvalue_cast<quint32>(number3), quint32(0));
912
913 QJSValue number3_2 = eng.toScriptValue(value: -qInf());
914 QCOMPARE(number3_2.toUInt(), quint32(0));
915 QCOMPARE(qjsvalue_cast<quint32>(number3_2), quint32(0));
916
917 QJSValue number4 = eng.toScriptValue(value: 0.5);
918 QCOMPARE(number4.toUInt(), quint32(0));
919
920 QJSValue number5 = eng.toScriptValue(value: 123.5);
921 QCOMPARE(number5.toUInt(), quint32(123));
922
923 QJSValue number6 = eng.toScriptValue(value: -456.5);
924 QCOMPARE(number6.toUInt(), quint32(-456));
925 QCOMPARE(qjsvalue_cast<quint32>(number6), quint32(-456));
926
927 QJSValue str = eng.toScriptValue(value: QString::fromLatin1(str: "123.0"));
928 QCOMPARE(str.toUInt(), quint32(123));
929 QCOMPARE(qjsvalue_cast<quint32>(str), quint32(123));
930
931 QJSValue str2 = eng.toScriptValue(value: QString::fromLatin1(str: "NaN"));
932 QCOMPARE(str2.toUInt(), quint32(0));
933 QCOMPARE(qjsvalue_cast<quint32>(str2), quint32(0));
934
935 QJSValue str3 = eng.toScriptValue(value: QString::fromLatin1(str: "Infinity"));
936 QCOMPARE(str3.toUInt(), quint32(0));
937 QCOMPARE(qjsvalue_cast<quint32>(str3), quint32(0));
938
939 QJSValue str3_2 = eng.toScriptValue(value: QString::fromLatin1(str: "-Infinity"));
940 QCOMPARE(str3_2.toUInt(), quint32(0));
941 QCOMPARE(qjsvalue_cast<quint32>(str3_2), quint32(0));
942
943 QJSValue str4 = eng.toScriptValue(value: QString::fromLatin1(str: "0.5"));
944 QCOMPARE(str4.toUInt(), quint32(0));
945 QCOMPARE(qjsvalue_cast<quint32>(str4), quint32(0));
946
947 QJSValue str5 = eng.toScriptValue(value: QString::fromLatin1(str: "123.5"));
948 QCOMPARE(str5.toUInt(), quint32(123));
949 QCOMPARE(qjsvalue_cast<quint32>(str5), quint32(123));
950
951 QJSValue str6 = eng.toScriptValue(value: QString::fromLatin1(str: "-456.5"));
952 QCOMPARE(str6.toUInt(), quint32(-456));
953 QCOMPARE(qjsvalue_cast<quint32>(str6), quint32(-456));
954 }
955 // V2 constructors
956 {
957 QJSValue zer0 = QJSValue(0.0);
958 QCOMPARE(zer0.toUInt(), quint32(0));
959 QCOMPARE(qjsvalue_cast<quint32>(zer0), quint32(0));
960
961 QJSValue number = QJSValue(123.0);
962 QCOMPARE(number.toUInt(), quint32(123));
963 QCOMPARE(qjsvalue_cast<quint32>(number), quint32(123));
964
965 QJSValue number2 = QJSValue(qQNaN());
966 QCOMPARE(number2.toUInt(), quint32(0));
967 QCOMPARE(qjsvalue_cast<quint32>(number2), quint32(0));
968
969 QJSValue number3 = QJSValue(+qInf());
970 QCOMPARE(number3.toUInt(), quint32(0));
971 QCOMPARE(qjsvalue_cast<quint32>(number3), quint32(0));
972
973 QJSValue number3_2 = QJSValue(-qInf());
974 QCOMPARE(number3_2.toUInt(), quint32(0));
975 QCOMPARE(qjsvalue_cast<quint32>(number3_2), quint32(0));
976
977 QJSValue number4 = QJSValue(0.5);
978 QCOMPARE(number4.toUInt(), quint32(0));
979
980 QJSValue number5 = QJSValue(123.5);
981 QCOMPARE(number5.toUInt(), quint32(123));
982
983 QJSValue number6 = QJSValue(-456.5);
984 QCOMPARE(number6.toUInt(), quint32(-456));
985 QCOMPARE(qjsvalue_cast<quint32>(number6), quint32(-456));
986
987 QJSValue number7 = QJSValue(0x43211234);
988 QCOMPARE(number7.toUInt(), quint32(0x43211234));
989
990 QJSValue str = QJSValue(QLatin1String("123.0"));
991 QCOMPARE(str.toUInt(), quint32(123));
992 QCOMPARE(qjsvalue_cast<quint32>(str), quint32(123));
993
994 QJSValue str2 = QJSValue(QLatin1String("NaN"));
995 QCOMPARE(str2.toUInt(), quint32(0));
996 QCOMPARE(qjsvalue_cast<quint32>(str2), quint32(0));
997
998 QJSValue str3 = QJSValue(QLatin1String("Infinity"));
999 QCOMPARE(str3.toUInt(), quint32(0));
1000 QCOMPARE(qjsvalue_cast<quint32>(str3), quint32(0));
1001
1002 QJSValue str3_2 = QJSValue(QLatin1String("-Infinity"));
1003 QCOMPARE(str3_2.toUInt(), quint32(0));
1004 QCOMPARE(qjsvalue_cast<quint32>(str3_2), quint32(0));
1005
1006 QJSValue str4 = QJSValue(QLatin1String("0.5"));
1007 QCOMPARE(str4.toUInt(), quint32(0));
1008 QCOMPARE(qjsvalue_cast<quint32>(str4), quint32(0));
1009
1010 QJSValue str5 = QJSValue(QLatin1String("123.5"));
1011 QCOMPARE(str5.toUInt(), quint32(123));
1012 QCOMPARE(qjsvalue_cast<quint32>(str5), quint32(123));
1013
1014 QJSValue str6 = QJSValue(QLatin1String("-456.5"));
1015 QCOMPARE(str6.toUInt(), quint32(-456));
1016 QCOMPARE(qjsvalue_cast<quint32>(str6), quint32(-456));
1017 }
1018
1019 QJSValue inv;
1020 QCOMPARE(inv.toUInt(), quint32(0));
1021 QCOMPARE(qjsvalue_cast<quint32>(inv), quint32(0));
1022}
1023
1024void tst_QJSValue::toVariant()
1025{
1026 QJSEngine eng;
1027 QObject temp;
1028
1029 QJSValue undefined = eng.toScriptValue(value: QVariant());
1030 QCOMPARE(undefined.toVariant(), QVariant());
1031 QCOMPARE(qjsvalue_cast<QVariant>(undefined), QVariant());
1032
1033 QJSValue null = eng.evaluate(program: "null");
1034 QCOMPARE(null.toVariant(), QVariant::fromValue(nullptr));
1035 QCOMPARE(qjsvalue_cast<QVariant>(null), QVariant::fromValue(nullptr));
1036
1037 {
1038 QJSValue number = eng.toScriptValue(value: 123.0);
1039 QCOMPARE(number.toVariant(), QVariant(123.0));
1040 QCOMPARE(qjsvalue_cast<QVariant>(number), QVariant(123.0));
1041
1042 QJSValue intNumber = eng.toScriptValue(value: (qint32)123);
1043 QCOMPARE(intNumber.toVariant().type(), QVariant((qint32)123).type());
1044 QCOMPARE((qjsvalue_cast<QVariant>(number)).type(), QVariant((qint32)123).type());
1045
1046 QJSValue falskt = eng.toScriptValue(value: false);
1047 QCOMPARE(falskt.toVariant(), QVariant(false));
1048 QCOMPARE(qjsvalue_cast<QVariant>(falskt), QVariant(false));
1049
1050 QJSValue sant = eng.toScriptValue(value: true);
1051 QCOMPARE(sant.toVariant(), QVariant(true));
1052 QCOMPARE(qjsvalue_cast<QVariant>(sant), QVariant(true));
1053
1054 QJSValue str = eng.toScriptValue(value: QString("ciao"));
1055 QCOMPARE(str.toVariant(), QVariant(QString("ciao")));
1056 QCOMPARE(qjsvalue_cast<QVariant>(str), QVariant(QString("ciao")));
1057 }
1058
1059 QJSValue object = eng.newObject();
1060 QCOMPARE(object.toVariant(), QVariant(QVariantMap()));
1061
1062 QJSValue qobject = eng.newQObject(object: &temp);
1063 {
1064 QVariant var = qobject.toVariant();
1065 QCOMPARE(var.userType(), int(QMetaType::QObjectStar));
1066 QCOMPARE(qvariant_cast<QObject*>(var), (QObject *)&temp);
1067 }
1068
1069 {
1070 QDateTime dateTime = QDate(1980, 10, 4).startOfDay();
1071 QJSValue dateObject = eng.toScriptValue(value: dateTime);
1072 QVariant var = dateObject.toVariant();
1073 QCOMPARE(var, QVariant(dateTime));
1074 }
1075
1076 {
1077 QRegExp rx = QRegExp("[0-9a-z]+", Qt::CaseSensitive, QRegExp::RegExp2);
1078 QJSValue rxObject = eng.toScriptValue(value: rx);
1079 QVERIFY(rxObject.isRegExp());
1080 QVariant var = rxObject.toVariant();
1081
1082 // We can't roundtrip a QRegExp this way, as toVariant() has no information on whether we
1083 // want QRegExp or QRegularExpression. It will always create a QRegularExpression.
1084 QCOMPARE(var.userType(), QMetaType::QRegularExpression);
1085 QRegularExpression result = var.toRegularExpression();
1086 QCOMPARE(result.pattern(), rx.pattern());
1087 QCOMPARE(result.patternOptions() & QRegularExpression::CaseInsensitiveOption, 0);
1088 }
1089
1090 {
1091 QRegularExpression rx = QRegularExpression("[0-9a-z]+");
1092 QJSValue rxObject = eng.toScriptValue(value: rx);
1093 QVERIFY(rxObject.isRegExp());
1094 QVariant var = rxObject.toVariant();
1095 QCOMPARE(var, QVariant(rx));
1096 }
1097
1098 QJSValue inv;
1099 QCOMPARE(inv.toVariant(), QVariant());
1100 QCOMPARE(qjsvalue_cast<QVariant>(inv), QVariant());
1101
1102 // V2 constructors
1103 {
1104 QJSValue number = QJSValue(123.0);
1105 QCOMPARE(number.toVariant(), QVariant(123.0));
1106 QCOMPARE(qjsvalue_cast<QVariant>(number), QVariant(123.0));
1107
1108 QJSValue falskt = QJSValue(false);
1109 QCOMPARE(falskt.toVariant(), QVariant(false));
1110 QCOMPARE(qjsvalue_cast<QVariant>(falskt), QVariant(false));
1111
1112 QJSValue sant = QJSValue(true);
1113 QCOMPARE(sant.toVariant(), QVariant(true));
1114 QCOMPARE(qjsvalue_cast<QVariant>(sant), QVariant(true));
1115
1116 QJSValue str = QJSValue(QString("ciao"));
1117 QCOMPARE(str.toVariant(), QVariant(QString("ciao")));
1118 QCOMPARE(qjsvalue_cast<QVariant>(str), QVariant(QString("ciao")));
1119
1120 QJSValue undef = QJSValue(QJSValue::UndefinedValue);
1121 QCOMPARE(undef.toVariant(), QVariant());
1122 QCOMPARE(qjsvalue_cast<QVariant>(undef), QVariant());
1123
1124 QJSValue nil = QJSValue(QJSValue::NullValue);
1125 QCOMPARE(nil.toVariant(), QVariant::fromValue(nullptr));
1126 QCOMPARE(qjsvalue_cast<QVariant>(nil), QVariant::fromValue(nullptr));
1127 }
1128
1129 // array
1130 {
1131 auto handler = qInstallMessageHandler([](QtMsgType type, const QMessageLogContext &, const QString &) {
1132 if (type == QtMsgType::QtWarningMsg)
1133 QFAIL("Converting QJSValue to QVariant should not cause error messages");
1134 });
1135 QVariantList listIn;
1136 listIn << 123 << "hello";
1137 QJSValue array = eng.toScriptValue(value: listIn);
1138 QVERIFY(array.isArray());
1139 QCOMPARE(array.property("length").toInt(), 2);
1140 QVariant ret = array.toVariant();
1141 QCOMPARE(ret.userType(), QVariant::List);
1142 QVariantList listOut = ret.toList();
1143 QCOMPARE(listOut.size(), listIn.size());
1144 for (int i = 0; i < listIn.size(); ++i)
1145 QCOMPARE(listOut.at(i), listIn.at(i));
1146 // round-trip conversion
1147 QJSValue array2 = eng.toScriptValue(value: ret);
1148 QVERIFY(array2.isArray());
1149 QCOMPARE(array2.property("length").toInt(), array.property("length").toInt());
1150 for (int i = 0; i < array.property(name: "length").toInt(); ++i)
1151 QVERIFY(array2.property(i).strictlyEquals(array.property(i)));
1152
1153 qInstallMessageHandler(handler);
1154 }
1155}
1156
1157void tst_QJSValue::toQObject_nonQObject_data()
1158{
1159 newEngine();
1160 QTest::addColumn<QJSValue>(name: "value");
1161
1162 QTest::newRow(dataTag: "invalid") << QJSValue();
1163 QTest::newRow(dataTag: "bool(false)") << QJSValue(false);
1164 QTest::newRow(dataTag: "bool(true)") << QJSValue(true);
1165 QTest::newRow(dataTag: "int") << QJSValue(123);
1166 QTest::newRow(dataTag: "string") << QJSValue(QString::fromLatin1(str: "ciao"));
1167 QTest::newRow(dataTag: "undefined") << QJSValue(QJSValue::UndefinedValue);
1168 QTest::newRow(dataTag: "null") << QJSValue(QJSValue::NullValue);
1169
1170 QTest::newRow(dataTag: "bool bound(false)") << engine->toScriptValue(value: false);
1171 QTest::newRow(dataTag: "bool bound(true)") << engine->toScriptValue(value: true);
1172 QTest::newRow(dataTag: "int bound") << engine->toScriptValue(value: 123);
1173 QTest::newRow(dataTag: "string bound") << engine->toScriptValue(value: QString::fromLatin1(str: "ciao"));
1174 QTest::newRow(dataTag: "undefined bound") << engine->toScriptValue(value: QVariant());
1175 QTest::newRow(dataTag: "null bound") << engine->evaluate(program: "null");
1176 QTest::newRow(dataTag: "object") << engine->newObject();
1177 QTest::newRow(dataTag: "array") << engine->newArray();
1178 QTest::newRow(dataTag: "date") << engine->evaluate(program: "new Date(124)");
1179 QTest::newRow(dataTag: "variant(12345)") << engine->toScriptValue(value: QVariant(12345));
1180 QTest::newRow(dataTag: "variant((QObject*)0)") << engine->toScriptValue(value: QVariant::fromValue(value: (QObject*)nullptr));
1181 QTest::newRow(dataTag: "newQObject(0)") << engine->newQObject(object: nullptr);
1182}
1183
1184
1185void tst_QJSValue::toQObject_nonQObject()
1186{
1187 QFETCH(QJSValue, value);
1188 QCOMPARE(value.toQObject(), (QObject *)nullptr);
1189 QCOMPARE(qjsvalue_cast<QObject*>(value), (QObject *)nullptr);
1190}
1191
1192// unfortunately, this is necessary in order to do qscriptvalue_cast<QPushButton*>(...)
1193Q_DECLARE_METATYPE(QPushButton*);
1194
1195void tst_QJSValue::toQObject()
1196{
1197 QJSEngine eng;
1198 QObject temp;
1199
1200 QJSValue qobject = eng.newQObject(object: &temp);
1201 QCOMPARE(qobject.toQObject(), (QObject *)&temp);
1202 QCOMPARE(qjsvalue_cast<QObject*>(qobject), (QObject *)&temp);
1203 QCOMPARE(qjsvalue_cast<QWidget*>(qobject), (QWidget *)nullptr);
1204
1205 QWidget widget;
1206 QJSValue qwidget = eng.newQObject(object: &widget);
1207 QCOMPARE(qwidget.toQObject(), (QObject *)&widget);
1208 QCOMPARE(qjsvalue_cast<QObject*>(qwidget), (QObject *)&widget);
1209 QCOMPARE(qjsvalue_cast<QWidget*>(qwidget), &widget);
1210
1211 QPushButton button;
1212 QJSValue qbutton = eng.newQObject(object: &button);
1213 QCOMPARE(qbutton.toQObject(), (QObject *)&button);
1214 QCOMPARE(qjsvalue_cast<QObject*>(qbutton), (QObject *)&button);
1215 QCOMPARE(qjsvalue_cast<QWidget*>(qbutton), (QWidget *)&button);
1216 QCOMPARE(qjsvalue_cast<QPushButton*>(qbutton), &button);
1217}
1218
1219void tst_QJSValue::toDateTime()
1220{
1221 QJSEngine eng;
1222 QDateTime dt = eng.evaluate(program: "new Date(0)").toDateTime();
1223 QVERIFY(dt.isValid());
1224 QCOMPARE(dt.timeSpec(), Qt::LocalTime);
1225 QCOMPARE(dt.toUTC(), QDate(1970, 1, 1).startOfDay(Qt::UTC));
1226
1227 QVERIFY(!eng.evaluate("[]").toDateTime().isValid());
1228 QVERIFY(!eng.evaluate("{}").toDateTime().isValid());
1229 QVERIFY(!eng.globalObject().toDateTime().isValid());
1230 QVERIFY(!QJSValue().toDateTime().isValid());
1231 QVERIFY(!QJSValue(123).toDateTime().isValid());
1232 QVERIFY(!QJSValue(false).toDateTime().isValid());
1233 QVERIFY(!eng.evaluate("null").toDateTime().isValid());
1234 QVERIFY(!eng.toScriptValue(QVariant()).toDateTime().isValid());
1235}
1236
1237void tst_QJSValue::toRegExp()
1238{
1239 QJSEngine eng;
1240 {
1241 QRegExp rx = qjsvalue_cast<QRegExp>(value: eng.evaluate(program: "/foo/"));
1242 QVERIFY(rx.isValid());
1243 QCOMPARE(rx.patternSyntax(), QRegExp::RegExp2);
1244 QCOMPARE(rx.pattern(), QString::fromLatin1("foo"));
1245 QCOMPARE(rx.caseSensitivity(), Qt::CaseSensitive);
1246 QVERIFY(!rx.isMinimal());
1247 }
1248 {
1249 QRegExp rx = qjsvalue_cast<QRegExp>(value: eng.evaluate(program: "/bar/gi"));
1250 QVERIFY(rx.isValid());
1251 QCOMPARE(rx.patternSyntax(), QRegExp::RegExp2);
1252 QCOMPARE(rx.pattern(), QString::fromLatin1("bar"));
1253 QCOMPARE(rx.caseSensitivity(), Qt::CaseInsensitive);
1254 QVERIFY(!rx.isMinimal());
1255 }
1256
1257 QVERIFY(qjsvalue_cast<QRegExp>(eng.evaluate("[]")).isEmpty());
1258 QVERIFY(qjsvalue_cast<QRegExp>(eng.evaluate("{}")).isEmpty());
1259 QVERIFY(qjsvalue_cast<QRegExp>(eng.globalObject()).isEmpty());
1260 QVERIFY(qjsvalue_cast<QRegExp>(QJSValue()).isEmpty());
1261 QVERIFY(qjsvalue_cast<QRegExp>(QJSValue(123)).isEmpty());
1262 QVERIFY(qjsvalue_cast<QRegExp>(QJSValue(false)).isEmpty());
1263 QVERIFY(qjsvalue_cast<QRegExp>(eng.evaluate("null")).isEmpty());
1264 QVERIFY(qjsvalue_cast<QRegExp>(eng.toScriptValue(QVariant())).isEmpty());
1265}
1266
1267void tst_QJSValue::toRegularExpression()
1268{
1269 QJSEngine eng;
1270 {
1271 QRegularExpression rx = qjsvalue_cast<QRegularExpression>(value: eng.evaluate(program: "/foo/"));
1272 QVERIFY(rx.isValid());
1273 QCOMPARE(rx.pattern(), QString::fromLatin1("foo"));
1274 QVERIFY(!(rx.patternOptions() & QRegularExpression::CaseInsensitiveOption));
1275 }
1276 {
1277 QRegularExpression rx = qjsvalue_cast<QRegularExpression>(value: eng.evaluate(program: "/bar/gi"));
1278 QVERIFY(rx.isValid());
1279 QCOMPARE(rx.pattern(), QString::fromLatin1("bar"));
1280 QVERIFY(rx.patternOptions() & QRegularExpression::CaseInsensitiveOption);
1281 }
1282
1283 QVERIFY(qjsvalue_cast<QRegularExpression>(eng.evaluate("[]")).pattern().isEmpty());
1284 QVERIFY(qjsvalue_cast<QRegularExpression>(eng.evaluate("{}")).pattern().isEmpty());
1285 QVERIFY(qjsvalue_cast<QRegularExpression>(eng.globalObject()).pattern().isEmpty());
1286 QVERIFY(qjsvalue_cast<QRegularExpression>(QJSValue()).pattern().isEmpty());
1287 QVERIFY(qjsvalue_cast<QRegularExpression>(QJSValue(123)).pattern().isEmpty());
1288 QVERIFY(qjsvalue_cast<QRegularExpression>(QJSValue(false)).pattern().isEmpty());
1289 QVERIFY(qjsvalue_cast<QRegularExpression>(eng.evaluate("null")).pattern().isEmpty());
1290 QVERIFY(qjsvalue_cast<QRegularExpression>(eng.toScriptValue(QVariant())).pattern().isEmpty());
1291}
1292
1293void tst_QJSValue::isArray_data()
1294{
1295 newEngine();
1296
1297 QTest::addColumn<QJSValue>(name: "value");
1298 QTest::addColumn<bool>(name: "array");
1299
1300 QTest::newRow(dataTag: "[]") << engine->evaluate(program: "[]") << true;
1301 QTest::newRow(dataTag: "{}") << engine->evaluate(program: "{}") << false;
1302 QTest::newRow(dataTag: "globalObject") << engine->globalObject() << false;
1303 QTest::newRow(dataTag: "invalid") << QJSValue() << false;
1304 QTest::newRow(dataTag: "number") << QJSValue(123) << false;
1305 QTest::newRow(dataTag: "bool") << QJSValue(false) << false;
1306 QTest::newRow(dataTag: "null") << engine->evaluate(program: "null") << false;
1307 QTest::newRow(dataTag: "undefined") << engine->toScriptValue(value: QVariant()) << false;
1308}
1309
1310void tst_QJSValue::isArray()
1311{
1312 QFETCH(QJSValue, value);
1313 QFETCH(bool, array);
1314
1315 QCOMPARE(value.isArray(), array);
1316}
1317
1318void tst_QJSValue::isDate_data()
1319{
1320 newEngine();
1321
1322 QTest::addColumn<QJSValue>(name: "value");
1323 QTest::addColumn<bool>(name: "date");
1324
1325 QTest::newRow(dataTag: "date") << engine->evaluate(program: "new Date()") << true;
1326 QTest::newRow(dataTag: "[]") << engine->evaluate(program: "[]") << false;
1327 QTest::newRow(dataTag: "{}") << engine->evaluate(program: "{}") << false;
1328 QTest::newRow(dataTag: "globalObject") << engine->globalObject() << false;
1329 QTest::newRow(dataTag: "invalid") << QJSValue() << false;
1330 QTest::newRow(dataTag: "number") << QJSValue(123) << false;
1331 QTest::newRow(dataTag: "bool") << QJSValue(false) << false;
1332 QTest::newRow(dataTag: "null") << engine->evaluate(program: "null") << false;
1333 QTest::newRow(dataTag: "undefined") << engine->toScriptValue(value: QVariant()) << false;
1334}
1335
1336void tst_QJSValue::isDate()
1337{
1338 QFETCH(QJSValue, value);
1339 QFETCH(bool, date);
1340
1341 QCOMPARE(value.isDate(), date);
1342}
1343
1344void tst_QJSValue::isError_propertiesOfGlobalObject()
1345{
1346 QStringList errors;
1347 errors << "Error"
1348 << "EvalError"
1349 << "RangeError"
1350 << "ReferenceError"
1351 << "SyntaxError"
1352 << "TypeError"
1353 << "URIError";
1354 QJSEngine eng;
1355 for (int i = 0; i < errors.size(); ++i) {
1356 QJSValue ctor = eng.globalObject().property(name: errors.at(i));
1357 QVERIFY(ctor.isCallable());
1358 QVERIFY(ctor.property("prototype").isObject());
1359 }
1360}
1361
1362void tst_QJSValue::isError_data()
1363{
1364 newEngine();
1365
1366 QTest::addColumn<QJSValue>(name: "value");
1367 QTest::addColumn<bool>(name: "error");
1368
1369 QTest::newRow(dataTag: "syntax error") << engine->evaluate(program: "%fsdg's") << true;
1370 QTest::newRow(dataTag: "[]") << engine->evaluate(program: "[]") << false;
1371 QTest::newRow(dataTag: "{}") << engine->evaluate(program: "{}") << false;
1372 QTest::newRow(dataTag: "globalObject") << engine->globalObject() << false;
1373 QTest::newRow(dataTag: "invalid") << QJSValue() << false;
1374 QTest::newRow(dataTag: "number") << QJSValue(123) << false;
1375 QTest::newRow(dataTag: "bool") << QJSValue(false) << false;
1376 QTest::newRow(dataTag: "null") << engine->evaluate(program: "null") << false;
1377 QTest::newRow(dataTag: "undefined") << engine->toScriptValue(value: QVariant()) << false;
1378 QTest::newRow(dataTag: "newObject") << engine->newObject() << false;
1379 QTest::newRow(dataTag: "new Object") << engine->evaluate(program: "new Object()") << false;
1380}
1381
1382void tst_QJSValue::isError()
1383{
1384 QFETCH(QJSValue, value);
1385 QFETCH(bool, error);
1386
1387 QCOMPARE(value.isError(), error);
1388}
1389
1390void tst_QJSValue::isRegExp_data()
1391{
1392 newEngine();
1393
1394 QTest::addColumn<QJSValue>(name: "value");
1395 QTest::addColumn<bool>(name: "regexp");
1396
1397 QTest::newRow(dataTag: "/foo/") << engine->evaluate(program: "/foo/") << true;
1398 QTest::newRow(dataTag: "[]") << engine->evaluate(program: "[]") << false;
1399 QTest::newRow(dataTag: "{}") << engine->evaluate(program: "{}") << false;
1400 QTest::newRow(dataTag: "globalObject") << engine->globalObject() << false;
1401 QTest::newRow(dataTag: "invalid") << QJSValue() << false;
1402 QTest::newRow(dataTag: "number") << QJSValue(123) << false;
1403 QTest::newRow(dataTag: "bool") << QJSValue(false) << false;
1404 QTest::newRow(dataTag: "null") << engine->evaluate(program: "null") << false;
1405 QTest::newRow(dataTag: "undefined") << engine->toScriptValue(value: QVariant()) << false;
1406}
1407
1408void tst_QJSValue::isRegExp()
1409{
1410 QFETCH(QJSValue, value);
1411 QFETCH(bool, regexp);
1412
1413 QCOMPARE(value.isRegExp(), regexp);
1414}
1415
1416void tst_QJSValue::hasProperty_basic()
1417{
1418 QJSEngine eng;
1419 QJSValue obj = eng.newObject();
1420 QVERIFY(obj.hasProperty("hasOwnProperty")); // inherited from Object.prototype
1421 QVERIFY(!obj.hasOwnProperty("hasOwnProperty"));
1422
1423 QVERIFY(!obj.hasProperty("foo"));
1424 QVERIFY(!obj.hasOwnProperty("foo"));
1425 obj.setProperty(name: "foo", value: 123);
1426 QVERIFY(obj.hasProperty("foo"));
1427 QVERIFY(obj.hasOwnProperty("foo"));
1428
1429 QVERIFY(!obj.hasProperty("bar"));
1430 QVERIFY(!obj.hasOwnProperty("bar"));
1431}
1432
1433void tst_QJSValue::hasProperty_globalObject()
1434{
1435 QJSEngine eng;
1436 QJSValue global = eng.globalObject();
1437 QVERIFY(global.hasProperty("Math"));
1438 QVERIFY(global.hasOwnProperty("Math"));
1439 QVERIFY(!global.hasProperty("NoSuchStandardProperty"));
1440 QVERIFY(!global.hasOwnProperty("NoSuchStandardProperty"));
1441
1442 QVERIFY(!global.hasProperty("foo"));
1443 QVERIFY(!global.hasOwnProperty("foo"));
1444 global.setProperty(name: "foo", value: 123);
1445 QVERIFY(global.hasProperty("foo"));
1446 QVERIFY(global.hasOwnProperty("foo"));
1447}
1448
1449void tst_QJSValue::hasProperty_changePrototype()
1450{
1451 QJSEngine eng;
1452 QJSValue obj = eng.newObject();
1453 QJSValue proto = eng.newObject();
1454 obj.setPrototype(proto);
1455
1456 QVERIFY(!obj.hasProperty("foo"));
1457 QVERIFY(!obj.hasOwnProperty("foo"));
1458 proto.setProperty(name: "foo", value: 123);
1459 QVERIFY(obj.hasProperty("foo"));
1460 QVERIFY(!obj.hasOwnProperty("foo"));
1461
1462 obj.setProperty(name: "foo", value: 456); // override prototype property
1463 QVERIFY(obj.hasProperty("foo"));
1464 QVERIFY(obj.hasOwnProperty("foo"));
1465}
1466
1467void tst_QJSValue::hasProperty_QTBUG56830_data()
1468{
1469 QTest::addColumn<QString>(name: "key");
1470 QTest::addColumn<QString>(name: "lookup");
1471
1472 QTest::newRow(dataTag: "bugreport-1") << QStringLiteral("240000000000") << QStringLiteral("3776798720");
1473 QTest::newRow(dataTag: "bugreport-2") << QStringLiteral("240000000001") << QStringLiteral("3776798721");
1474 QTest::newRow(dataTag: "biggest-ok-before-bug") << QStringLiteral("238609294221") << QStringLiteral("2386092941");
1475 QTest::newRow(dataTag: "smallest-bugged") << QStringLiteral("238609294222") << QStringLiteral("2386092942");
1476 QTest::newRow(dataTag: "biggest-bugged") << QStringLiteral("249108103166") << QStringLiteral("12884901886");
1477 QTest::newRow(dataTag: "smallest-ok-after-bug") << QStringLiteral("249108103167") << QStringLiteral("12884901887");
1478}
1479
1480void tst_QJSValue::hasProperty_QTBUG56830()
1481{
1482 QFETCH(QString, key);
1483 QFETCH(QString, lookup);
1484
1485 QJSEngine eng;
1486 const QJSValue value(42);
1487
1488 QJSValue obj = eng.newObject();
1489 obj.setProperty(name: key, value);
1490 QVERIFY(obj.hasProperty(key));
1491 QVERIFY(!obj.hasProperty(lookup));
1492}
1493
1494void tst_QJSValue::deleteProperty_basic()
1495{
1496 QJSEngine eng;
1497 QJSValue obj = eng.newObject();
1498 // deleteProperty() behavior matches JS delete operator
1499 QVERIFY(obj.deleteProperty("foo"));
1500
1501 obj.setProperty(name: "foo", value: 123);
1502 QVERIFY(obj.deleteProperty("foo"));
1503 QVERIFY(!obj.hasOwnProperty("foo"));
1504}
1505
1506void tst_QJSValue::deleteProperty_globalObject()
1507{
1508 QJSEngine eng;
1509 QJSValue global = eng.globalObject();
1510 // deleteProperty() behavior matches JS delete operator
1511 QVERIFY(global.deleteProperty("foo"));
1512
1513 global.setProperty(name: "foo", value: 123);
1514 QVERIFY(global.deleteProperty("foo"));
1515 QVERIFY(!global.hasProperty("foo"));
1516
1517 QVERIFY(global.deleteProperty("Math"));
1518 QVERIFY(!global.hasProperty("Math"));
1519
1520 QVERIFY(!global.deleteProperty("NaN")); // read-only
1521 QVERIFY(global.hasProperty("NaN"));
1522}
1523
1524void tst_QJSValue::deleteProperty_inPrototype()
1525{
1526 QJSEngine eng;
1527 QJSValue obj = eng.newObject();
1528 QJSValue proto = eng.newObject();
1529 obj.setPrototype(proto);
1530
1531 proto.setProperty(name: "foo", value: 123);
1532 QVERIFY(obj.hasProperty("foo"));
1533 // deleteProperty() behavior matches JS delete operator
1534 QVERIFY(obj.deleteProperty("foo"));
1535 QVERIFY(obj.hasProperty("foo"));
1536}
1537
1538void tst_QJSValue::getSetProperty_HooliganTask162051()
1539{
1540 QJSEngine eng;
1541 // task 162051 -- detecting whether the property is an array index or not
1542 QVERIFY(eng.evaluate("a = []; a['00'] = 123; a['00']").strictlyEquals(eng.toScriptValue(123)));
1543 QVERIFY(eng.evaluate("a.length").strictlyEquals(eng.toScriptValue(0)));
1544 QVERIFY(eng.evaluate("a.hasOwnProperty('00')").strictlyEquals(eng.toScriptValue(true)));
1545 QVERIFY(eng.evaluate("a.hasOwnProperty('0')").strictlyEquals(eng.toScriptValue(false)));
1546 QVERIFY(eng.evaluate("a[0]").isUndefined());
1547 QVERIFY(eng.evaluate("a[0.5] = 456; a[0.5]").strictlyEquals(eng.toScriptValue(456)));
1548 QVERIFY(eng.evaluate("a.length").strictlyEquals(eng.toScriptValue(0)));
1549 QVERIFY(eng.evaluate("a.hasOwnProperty('0.5')").strictlyEquals(eng.toScriptValue(true)));
1550 QVERIFY(eng.evaluate("a[0]").isUndefined());
1551 QVERIFY(eng.evaluate("a[0] = 789; a[0]").strictlyEquals(eng.toScriptValue(789)));
1552 QVERIFY(eng.evaluate("a.length").strictlyEquals(eng.toScriptValue(1)));
1553}
1554
1555void tst_QJSValue::getSetProperty_HooliganTask183072()
1556{
1557 QJSEngine eng;
1558 // task 183072 -- 0x800000000 is not an array index
1559 eng.evaluate(program: "a = []; a[0x800000000] = 123");
1560 QVERIFY(eng.evaluate("a.length").strictlyEquals(eng.toScriptValue(0)));
1561 QVERIFY(eng.evaluate("a[0]").isUndefined());
1562 QVERIFY(eng.evaluate("a[0x800000000]").strictlyEquals(eng.toScriptValue(123)));
1563}
1564
1565void tst_QJSValue::getSetProperty_propertyRemoval()
1566{
1567 QJSEngine eng;
1568 QJSValue object = eng.newObject();
1569 QJSValue str = eng.toScriptValue(value: QString::fromLatin1(str: "bar"));
1570 QJSValue num = eng.toScriptValue(value: 123.0);
1571
1572 object.setProperty(name: "foo", value: num);
1573 QCOMPARE(object.property("foo").strictlyEquals(num), true);
1574 object.setProperty(name: "bar", value: str);
1575 QCOMPARE(object.property("bar").strictlyEquals(str), true);
1576 QVERIFY(object.deleteProperty("foo"));
1577 QVERIFY(!object.hasOwnProperty("foo"));
1578 QCOMPARE(object.property("bar").strictlyEquals(str), true);
1579 object.setProperty(name: "foo", value: num);
1580 QCOMPARE(object.property("foo").strictlyEquals(num), true);
1581 QCOMPARE(object.property("bar").strictlyEquals(str), true);
1582 QVERIFY(object.deleteProperty("bar"));
1583 QVERIFY(!object.hasOwnProperty("bar"));
1584 QCOMPARE(object.property("foo").strictlyEquals(num), true);
1585 QVERIFY(object.deleteProperty("foo"));
1586 QVERIFY(!object.hasOwnProperty("foo"));
1587
1588 eng.globalObject().setProperty(name: "object3", value: object);
1589 QCOMPARE(eng.evaluate("object3.hasOwnProperty('foo')")
1590 .strictlyEquals(eng.toScriptValue(false)), true);
1591 object.setProperty(name: "foo", value: num);
1592 QCOMPARE(eng.evaluate("object3.hasOwnProperty('foo')")
1593 .strictlyEquals(eng.toScriptValue(true)), true);
1594 QVERIFY(eng.globalObject().deleteProperty("object3"));
1595 QCOMPARE(eng.evaluate("this.hasOwnProperty('object3')")
1596 .strictlyEquals(eng.toScriptValue(false)), true);
1597}
1598
1599void tst_QJSValue::getSetProperty_resolveMode()
1600{
1601 // test ResolveMode
1602 QJSEngine eng;
1603 QJSValue object = eng.newObject();
1604 QJSValue prototype = eng.newObject();
1605 object.setPrototype(prototype);
1606 QJSValue num2 = eng.toScriptValue(value: 456.0);
1607 prototype.setProperty(name: "propertyInPrototype", value: num2);
1608 // default is ResolvePrototype
1609 QCOMPARE(object.property("propertyInPrototype")
1610 .strictlyEquals(num2), true);
1611#if 0 // FIXME: ResolveFlags removed from API
1612 QCOMPARE(object.property("propertyInPrototype", QJSValue::ResolvePrototype)
1613 .strictlyEquals(num2), true);
1614 QCOMPARE(object.property("propertyInPrototype", QJSValue::ResolveLocal)
1615 .isValid(), false);
1616 QCOMPARE(object.property("propertyInPrototype", QJSValue::ResolveScope)
1617 .strictlyEquals(num2), false);
1618 QCOMPARE(object.property("propertyInPrototype", QJSValue::ResolveFull)
1619 .strictlyEquals(num2), true);
1620#endif
1621}
1622
1623void tst_QJSValue::getSetProperty_twoEngines()
1624{
1625 QJSEngine engine;
1626 QJSValue object = engine.newObject();
1627
1628 QJSEngine otherEngine;
1629 QJSValue otherNum = otherEngine.toScriptValue(value: 123);
1630 QTest::ignoreMessage(type: QtWarningMsg, message: "QJSValue::setProperty(oof) failed: cannot set value created in a different engine");
1631 object.setProperty(name: "oof", value: otherNum);
1632 QVERIFY(!object.hasOwnProperty("oof"));
1633 QVERIFY(object.property("oof").isUndefined());
1634}
1635
1636void tst_QJSValue::getSetProperty_gettersAndSettersThrowErrorJS()
1637{
1638 // getter/setter that throws an error (from js function)
1639 QJSEngine eng;
1640 QJSValue str = eng.toScriptValue(value: QString::fromLatin1(str: "bar"));
1641
1642 eng.evaluate(program: "o = new Object; "
1643 "o.__defineGetter__('foo', function() { throw new Error('get foo') }); "
1644 "o.__defineSetter__('foo', function() { throw new Error('set foo') }); ");
1645 QJSValue object = eng.evaluate(program: "o");
1646 QVERIFY(!object.isError());
1647 QJSValue ret = object.property(name: "foo");
1648 QVERIFY(ret.isError());
1649 QCOMPARE(ret.toString(), QLatin1String("Error: get foo"));
1650 QVERIFY(!eng.evaluate("Object").isError()); // clear exception state...
1651 object.setProperty(name: "foo", value: str);
1652// ### No way to check whether setProperty() threw an exception
1653// QVERIFY(eng.hasUncaughtException());
1654// QCOMPARE(eng.uncaughtException().toString(), QLatin1String("Error: set foo"));
1655}
1656
1657void tst_QJSValue::getSetProperty_array()
1658{
1659 QJSEngine eng;
1660 QJSValue str = eng.toScriptValue(value: QString::fromLatin1(str: "bar"));
1661 QJSValue num = eng.toScriptValue(value: 123.0);
1662 QJSValue array = eng.newArray();
1663
1664 QVERIFY(array.isArray());
1665 array.setProperty(arrayIndex: 0, value: num);
1666 QCOMPARE(array.property(0).toNumber(), num.toNumber());
1667 QCOMPARE(array.property("0").toNumber(), num.toNumber());
1668 QCOMPARE(array.property("length").toUInt(), quint32(1));
1669 array.setProperty(arrayIndex: 1, value: str);
1670 QCOMPARE(array.property(1).toString(), str.toString());
1671 QCOMPARE(array.property("1").toString(), str.toString());
1672 QCOMPARE(array.property("length").toUInt(), quint32(2));
1673 array.setProperty(name: "length", value: eng.toScriptValue(value: 1));
1674 QCOMPARE(array.property("length").toUInt(), quint32(1));
1675 QVERIFY(array.property(1).isUndefined());
1676}
1677
1678void tst_QJSValue::getSetProperty()
1679{
1680 QJSEngine eng;
1681
1682 QJSValue object = eng.newObject();
1683
1684 QJSValue str = eng.toScriptValue(value: QString::fromLatin1(str: "bar"));
1685 object.setProperty(name: "foo", value: str);
1686 QCOMPARE(object.property("foo").toString(), str.toString());
1687
1688 QJSValue num = eng.toScriptValue(value: 123.0);
1689 object.setProperty(name: "baz", value: num);
1690 QCOMPARE(object.property("baz").toNumber(), num.toNumber());
1691
1692 QJSValue strstr = QJSValue("bar");
1693#ifdef QT_DEPRECATED
1694 QCOMPARE(strstr.engine(), (QJSEngine *)nullptr);
1695#endif
1696 object.setProperty(name: "foo", value: strstr);
1697 QCOMPARE(object.property("foo").toString(), strstr.toString());
1698#ifdef QT_DEPRECATED
1699 QCOMPARE(strstr.engine(), &eng); // the value has been bound to the engine
1700#endif
1701
1702 QJSValue numnum = QJSValue(123.0);
1703 object.setProperty(name: "baz", value: numnum);
1704 QCOMPARE(object.property("baz").toNumber(), numnum.toNumber());
1705
1706 QJSValue inv;
1707 inv.setProperty(name: "foo", value: num);
1708 QCOMPARE(inv.property("foo").isUndefined(), true);
1709
1710 eng.globalObject().setProperty(name: "object", value: object);
1711
1712 // Setting index property on non-Array
1713 object.setProperty(arrayIndex: 13, value: num);
1714 QVERIFY(object.property(13).equals(num));
1715}
1716
1717void tst_QJSValue::getSetPrototype_cyclicPrototype()
1718{
1719 QJSEngine eng;
1720 QJSValue prototype = eng.newObject();
1721 QJSValue object = eng.newObject();
1722 object.setPrototype(prototype);
1723
1724 QJSValue previousPrototype = prototype.prototype();
1725 QTest::ignoreMessage(type: QtWarningMsg, message: "QJSValue::setPrototype() failed: cyclic prototype value");
1726 prototype.setPrototype(prototype);
1727 QCOMPARE(prototype.prototype().strictlyEquals(previousPrototype), true);
1728
1729 object.setPrototype(prototype);
1730 QTest::ignoreMessage(type: QtWarningMsg, message: "QJSValue::setPrototype() failed: cyclic prototype value");
1731 prototype.setPrototype(object);
1732 QCOMPARE(prototype.prototype().strictlyEquals(previousPrototype), true);
1733
1734}
1735
1736void tst_QJSValue::getSetPrototype_evalCyclicPrototype()
1737{
1738 QJSEngine eng;
1739 QJSValue ret = eng.evaluate(program: "o = { }; p = { }; o.__proto__ = p; p.__proto__ = o");
1740 QCOMPARE(ret.isError(), true);
1741 QCOMPARE(ret.toString(), QLatin1String("TypeError: Could not change prototype."));
1742}
1743
1744void tst_QJSValue::getSetPrototype_eval()
1745{
1746 QJSEngine eng;
1747 QJSValue ret = eng.evaluate(program: "p = { }; p.__proto__ = { }");
1748 QCOMPARE(ret.isError(), false);
1749}
1750
1751void tst_QJSValue::getSetPrototype_invalidPrototype()
1752{
1753 QJSEngine eng;
1754 QJSValue inv;
1755 QJSValue object = eng.newObject();
1756 QJSValue proto = object.prototype();
1757 QVERIFY(object.prototype().strictlyEquals(proto));
1758 inv.setPrototype(object);
1759 QVERIFY(inv.prototype().isUndefined());
1760 object.setPrototype(inv);
1761 QVERIFY(object.prototype().strictlyEquals(proto));
1762}
1763
1764void tst_QJSValue::getSetPrototype_twoEngines()
1765{
1766 QJSEngine eng;
1767 QJSValue prototype = eng.newObject();
1768 QJSValue object = eng.newObject();
1769 object.setPrototype(prototype);
1770 QJSEngine otherEngine;
1771 QJSValue newPrototype = otherEngine.newObject();
1772 QTest::ignoreMessage(type: QtWarningMsg, message: "QJSValue::setPrototype() failed: cannot set a prototype created in a different engine");
1773 object.setPrototype(newPrototype);
1774 QCOMPARE(object.prototype().strictlyEquals(prototype), true);
1775
1776}
1777
1778void tst_QJSValue::getSetPrototype_null()
1779{
1780 QJSEngine eng;
1781 QJSValue object = eng.newObject();
1782 object.setPrototype(QJSValue(QJSValue::NullValue));
1783 QVERIFY(object.prototype().isNull());
1784
1785 QJSValue newProto = eng.newObject();
1786 object.setPrototype(newProto);
1787 QVERIFY(object.prototype().equals(newProto));
1788
1789 object.setPrototype(eng.evaluate(program: "null"));
1790 QVERIFY(object.prototype().isNull());
1791}
1792
1793void tst_QJSValue::getSetPrototype_notObjectOrNull()
1794{
1795 QJSEngine eng;
1796 QJSValue object = eng.newObject();
1797 QJSValue originalProto = object.prototype();
1798
1799 // bool
1800 object.setPrototype(true);
1801 QVERIFY(object.prototype().equals(originalProto));
1802 object.setPrototype(eng.toScriptValue(value: true));
1803 QVERIFY(object.prototype().equals(originalProto));
1804
1805 // number
1806 object.setPrototype(123);
1807 QVERIFY(object.prototype().equals(originalProto));
1808 object.setPrototype(eng.toScriptValue(value: 123));
1809 QVERIFY(object.prototype().equals(originalProto));
1810
1811 // string
1812 object.setPrototype("foo");
1813 QVERIFY(object.prototype().equals(originalProto));
1814 object.setPrototype(eng.toScriptValue(value: QString::fromLatin1(str: "foo")));
1815 QVERIFY(object.prototype().equals(originalProto));
1816
1817 // undefined
1818 object.setPrototype(QJSValue(QJSValue::UndefinedValue));
1819 QVERIFY(object.prototype().equals(originalProto));
1820 object.setPrototype(eng.toScriptValue(value: QVariant()));
1821 QVERIFY(object.prototype().equals(originalProto));
1822}
1823
1824void tst_QJSValue::getSetPrototype()
1825{
1826 QJSEngine eng;
1827 QJSValue prototype = eng.newObject();
1828 QJSValue object = eng.newObject();
1829 object.setPrototype(prototype);
1830 QCOMPARE(object.prototype().strictlyEquals(prototype), true);
1831}
1832
1833void tst_QJSValue::call_function()
1834{
1835 QJSEngine eng;
1836 QJSValue fun = eng.evaluate(program: "(function() { return 1; })");
1837 QVERIFY(fun.isCallable());
1838 QJSValue result = fun.call();
1839 QVERIFY(result.isNumber());
1840 QCOMPARE(result.toInt(), 1);
1841}
1842
1843void tst_QJSValue::call_object()
1844{
1845 QJSEngine eng;
1846 QJSValue Object = eng.evaluate(program: "Object");
1847 QCOMPARE(Object.isCallable(), true);
1848 QJSValue result = Object.callWithInstance(instance: Object);
1849 QCOMPARE(result.isObject(), true);
1850}
1851
1852void tst_QJSValue::call_newObjects()
1853{
1854 QJSEngine eng;
1855 // test that call() doesn't construct new objects
1856 QJSValue Number = eng.evaluate(program: "Number");
1857 QJSValue Object = eng.evaluate(program: "Object");
1858 QCOMPARE(Object.isCallable(), true);
1859 QJSValueList args;
1860 args << eng.toScriptValue(value: 123);
1861 QJSValue result = Number.callWithInstance(instance: Object, args);
1862 QCOMPARE(result.strictlyEquals(args.at(0)), true);
1863}
1864
1865void tst_QJSValue::call_this()
1866{
1867 QJSEngine eng;
1868 // test that correct "this" object is used
1869 QJSValue fun = eng.evaluate(program: "(function() { return this; })");
1870 QCOMPARE(fun.isCallable(), true);
1871
1872 QJSValue numberObject = eng.evaluate(program: "new Number(123)");
1873 QJSValue result = fun.callWithInstance(instance: numberObject);
1874 QCOMPARE(result.isObject(), true);
1875 QCOMPARE(result.toNumber(), 123.0);
1876}
1877
1878void tst_QJSValue::call_arguments()
1879{
1880 QJSEngine eng;
1881 // test that correct arguments are passed
1882
1883 QJSValue fun = eng.evaluate(program: "(function() { return arguments[0]; })");
1884 QCOMPARE(fun.isCallable(), true);
1885 {
1886 QJSValue result = fun.callWithInstance(instance: eng.toScriptValue(value: QVariant()));
1887 QCOMPARE(result.isUndefined(), true);
1888 }
1889 {
1890 QJSValueList args;
1891 args << eng.toScriptValue(value: 123.0);
1892 QJSValue result = fun.callWithInstance(instance: eng.toScriptValue(value: QVariant()), args);
1893 QCOMPARE(result.isNumber(), true);
1894 QCOMPARE(result.toNumber(), 123.0);
1895 }
1896 // V2 constructors
1897 {
1898 QJSValueList args;
1899 args << QJSValue(123.0);
1900 QJSValue result = fun.callWithInstance(instance: eng.toScriptValue(value: QVariant()), args);
1901 QCOMPARE(result.isNumber(), true);
1902 QCOMPARE(result.toNumber(), 123.0);
1903 }
1904}
1905
1906void tst_QJSValue::call()
1907{
1908 QJSEngine eng;
1909 {
1910 QJSValue fun = eng.evaluate(program: "(function() { return arguments[1]; })");
1911 QCOMPARE(fun.isCallable(), true);
1912
1913 {
1914 QJSValueList args;
1915 args << eng.toScriptValue(value: 123.0) << eng.toScriptValue(value: 456.0);
1916 QJSValue result = fun.callWithInstance(instance: eng.toScriptValue(value: QVariant()), args);
1917 QCOMPARE(result.isNumber(), true);
1918 QCOMPARE(result.toNumber(), 456.0);
1919 }
1920 }
1921 {
1922 QJSValue fun = eng.evaluate(program: "(function() { throw new Error('foo'); })");
1923 QCOMPARE(fun.isCallable(), true);
1924 QVERIFY(!fun.isError());
1925
1926 {
1927 QJSValue result = fun.call();
1928 QCOMPARE(result.isError(), true);
1929 }
1930 }
1931}
1932
1933void tst_QJSValue::call_twoEngines()
1934{
1935 QJSEngine eng;
1936 QJSValue object = eng.evaluate(program: "Object");
1937 QJSEngine otherEngine;
1938 QJSValue fun = otherEngine.evaluate(program: "(function() { return 1; })");
1939 QVERIFY(fun.isCallable());
1940 QTest::ignoreMessage(type: QtWarningMsg, message: "QJSValue::call() failed: "
1941 "cannot call function with thisObject created in "
1942 "a different engine");
1943 QVERIFY(fun.callWithInstance(object).isUndefined());
1944 QTest::ignoreMessage(type: QtWarningMsg, message: "QJSValue::call() failed: "
1945 "cannot call function with argument created in "
1946 "a different engine");
1947 QVERIFY(fun.call(QJSValueList() << eng.toScriptValue(123)).isUndefined());
1948 {
1949 QJSValue fun = eng.evaluate(program: "Object");
1950 QVERIFY(fun.isCallable());
1951 QJSEngine eng2;
1952 QJSValue objectInDifferentEngine = eng2.newObject();
1953 QJSValueList args;
1954 args << objectInDifferentEngine;
1955 QTest::ignoreMessage(type: QtWarningMsg, message: "QJSValue::call() failed: cannot call function with argument created in a different engine");
1956 fun.call(args);
1957 }
1958}
1959
1960void tst_QJSValue::call_nonFunction_data()
1961{
1962 newEngine();
1963 QTest::addColumn<QJSValue>(name: "value");
1964
1965 QTest::newRow(dataTag: "invalid") << QJSValue();
1966 QTest::newRow(dataTag: "bool") << QJSValue(false);
1967 QTest::newRow(dataTag: "int") << QJSValue(123);
1968 QTest::newRow(dataTag: "string") << QJSValue(QString::fromLatin1(str: "ciao"));
1969 QTest::newRow(dataTag: "undefined") << QJSValue(QJSValue::UndefinedValue);
1970 QTest::newRow(dataTag: "null") << QJSValue(QJSValue::NullValue);
1971
1972 QTest::newRow(dataTag: "bool bound") << engine->toScriptValue(value: false);
1973 QTest::newRow(dataTag: "int bound") << engine->toScriptValue(value: 123);
1974 QTest::newRow(dataTag: "string bound") << engine->toScriptValue(value: QString::fromLatin1(str: "ciao"));
1975 QTest::newRow(dataTag: "undefined bound") << engine->toScriptValue(value: QVariant());
1976 QTest::newRow(dataTag: "null bound") << engine->evaluate(program: "null");
1977}
1978
1979void tst_QJSValue::call_nonFunction()
1980{
1981 // calling things that are not functions
1982 QFETCH(QJSValue, value);
1983 QVERIFY(value.call().isUndefined());
1984}
1985
1986void tst_QJSValue::construct_nonFunction_data()
1987{
1988 newEngine();
1989 QTest::addColumn<QJSValue>(name: "value");
1990
1991 QTest::newRow(dataTag: "invalid") << QJSValue();
1992 QTest::newRow(dataTag: "bool") << QJSValue(false);
1993 QTest::newRow(dataTag: "int") << QJSValue(123);
1994 QTest::newRow(dataTag: "string") << QJSValue(QString::fromLatin1(str: "ciao"));
1995 QTest::newRow(dataTag: "undefined") << QJSValue(QJSValue::UndefinedValue);
1996 QTest::newRow(dataTag: "null") << QJSValue(QJSValue::NullValue);
1997
1998 QTest::newRow(dataTag: "bool bound") << engine->toScriptValue(value: false);
1999 QTest::newRow(dataTag: "int bound") << engine->toScriptValue(value: 123);
2000 QTest::newRow(dataTag: "string bound") << engine->toScriptValue(value: QString::fromLatin1(str: "ciao"));
2001 QTest::newRow(dataTag: "undefined bound") << engine->toScriptValue(value: QVariant());
2002 QTest::newRow(dataTag: "null bound") << engine->evaluate(program: "null");
2003}
2004
2005void tst_QJSValue::construct_nonFunction()
2006{
2007 QFETCH(QJSValue, value);
2008 QVERIFY(value.callAsConstructor().isUndefined());
2009}
2010
2011void tst_QJSValue::construct_simple()
2012{
2013 QJSEngine eng;
2014 QJSValue fun = eng.evaluate(program: "(function () { this.foo = 123; })");
2015 QVERIFY(fun.isCallable());
2016 QJSValue ret = fun.callAsConstructor();
2017 QVERIFY(!ret.isUndefined());
2018 QVERIFY(ret.isObject());
2019 QVERIFY(ret.prototype().strictlyEquals(fun.property("prototype")));
2020 QCOMPARE(ret.property("foo").toInt(), 123);
2021}
2022
2023void tst_QJSValue::construct_newObjectJS()
2024{
2025 QJSEngine eng;
2026 // returning a different object overrides the default-constructed one
2027 QJSValue fun = eng.evaluate(program: "(function () { return { bar: 456 }; })");
2028 QVERIFY(fun.isCallable());
2029 QJSValue ret = fun.callAsConstructor();
2030 QVERIFY(ret.isObject());
2031 QVERIFY(!ret.prototype().strictlyEquals(fun.property("prototype")));
2032 QCOMPARE(ret.property("bar").toInt(), 456);
2033}
2034
2035void tst_QJSValue::construct_arg()
2036{
2037 QJSEngine eng;
2038 QJSValue Number = eng.evaluate(program: "Number");
2039 QCOMPARE(Number.isCallable(), true);
2040 QJSValueList args;
2041 args << eng.toScriptValue(value: 123);
2042 QJSValue ret = Number.callAsConstructor(args);
2043 QCOMPARE(ret.isObject(), true);
2044 QCOMPARE(ret.toNumber(), args.at(0).toNumber());
2045}
2046
2047void tst_QJSValue::construct_proto()
2048{
2049 QJSEngine eng;
2050 // test that internal prototype is set correctly
2051 QJSValue fun = eng.evaluate(program: "(function() { return this.__proto__; })");
2052 QCOMPARE(fun.isCallable(), true);
2053 QCOMPARE(fun.property("prototype").isObject(), true);
2054 QJSValue ret = fun.callAsConstructor();
2055 QCOMPARE(fun.property("prototype").strictlyEquals(ret), true);
2056}
2057
2058void tst_QJSValue::construct_returnInt()
2059{
2060 QJSEngine eng;
2061 // test that we return the new object even if a non-object value is returned from the function
2062 QJSValue fun = eng.evaluate(program: "(function() { return 123; })");
2063 QCOMPARE(fun.isCallable(), true);
2064 QJSValue ret = fun.callAsConstructor();
2065 QCOMPARE(ret.isObject(), true);
2066}
2067
2068void tst_QJSValue::construct_throw()
2069{
2070 QJSEngine eng;
2071 QJSValue fun = eng.evaluate(program: "(function() { throw new Error('foo'); })");
2072 QCOMPARE(fun.isCallable(), true);
2073 QJSValue ret = fun.callAsConstructor();
2074 QCOMPARE(ret.isError(), true);
2075}
2076
2077void tst_QJSValue::construct_twoEngines()
2078{
2079 QJSEngine engine;
2080 QJSEngine otherEngine;
2081 QJSValue ctor = engine.evaluate(program: "(function (a, b) { this.foo = 123; })");
2082 QJSValue arg = otherEngine.toScriptValue(value: 124567);
2083 QTest::ignoreMessage(type: QtWarningMsg, message: "QJSValue::callAsConstructor() failed: cannot construct function with argument created in a different engine");
2084 QVERIFY(ctor.callAsConstructor(QJSValueList() << arg).isUndefined());
2085 QTest::ignoreMessage(type: QtWarningMsg, message: "QJSValue::callAsConstructor() failed: cannot construct function with argument created in a different engine");
2086 QVERIFY(ctor.callAsConstructor(QJSValueList() << arg << otherEngine.newObject()).isUndefined());
2087}
2088
2089void tst_QJSValue::construct_constructorThrowsPrimitive()
2090{
2091 QJSEngine eng;
2092 QJSValue fun = eng.evaluate(program: "(function() { throw 123; })");
2093 QVERIFY(fun.isCallable());
2094 // construct(QJSValueList)
2095 {
2096 QJSValue ret = fun.callAsConstructor();
2097 QVERIFY(ret.isNumber());
2098 QCOMPARE(ret.toNumber(), 123.0);
2099 QVERIFY(!ret.isError());
2100 }
2101}
2102
2103void tst_QJSValue::equals()
2104{
2105 QJSEngine eng;
2106 QObject temp;
2107
2108 QVERIFY(QJSValue().equals(QJSValue()));
2109
2110 QJSValue num = eng.toScriptValue(value: 123);
2111 QCOMPARE(num.equals(eng.toScriptValue(123)), true);
2112 QCOMPARE(num.equals(eng.toScriptValue(321)), false);
2113 QCOMPARE(num.equals(eng.toScriptValue(QString::fromLatin1("123"))), true);
2114 QCOMPARE(num.equals(eng.toScriptValue(QString::fromLatin1("321"))), false);
2115 QCOMPARE(num.equals(eng.evaluate("new Number(123)")), true);
2116 QCOMPARE(num.equals(eng.evaluate("new Number(321)")), false);
2117 QCOMPARE(num.equals(eng.evaluate("new String('123')")), true);
2118 QCOMPARE(num.equals(eng.evaluate("new String('321')")), false);
2119 QVERIFY(eng.evaluate("new Number(123)").equals(num));
2120 QCOMPARE(num.equals(QJSValue()), false);
2121
2122 QJSValue str = eng.toScriptValue(value: QString::fromLatin1(str: "123"));
2123 QCOMPARE(str.equals(eng.toScriptValue(QString::fromLatin1("123"))), true);
2124 QCOMPARE(str.equals(eng.toScriptValue(QString::fromLatin1("321"))), false);
2125 QCOMPARE(str.equals(eng.toScriptValue(123)), true);
2126 QCOMPARE(str.equals(eng.toScriptValue(321)), false);
2127 QCOMPARE(str.equals(eng.evaluate("new String('123')")), true);
2128 QCOMPARE(str.equals(eng.evaluate("new String('321')")), false);
2129 QCOMPARE(str.equals(eng.evaluate("new Number(123)")), true);
2130 QCOMPARE(str.equals(eng.evaluate("new Number(321)")), false);
2131 QVERIFY(eng.evaluate("new String('123')").equals(str));
2132 QCOMPARE(str.equals(QJSValue()), false);
2133
2134 QJSValue num2 = QJSValue(123);
2135 QCOMPARE(num2.equals(QJSValue(123)), true);
2136 QCOMPARE(num2.equals(QJSValue(321)), false);
2137 QCOMPARE(num2.equals(QJSValue("123")), true);
2138 QCOMPARE(num2.equals(QJSValue("321")), false);
2139 QCOMPARE(num2.equals(QJSValue()), false);
2140
2141 QJSValue str2 = QJSValue("123");
2142 QCOMPARE(str2.equals(QJSValue("123")), true);
2143 QCOMPARE(str2.equals(QJSValue("321")), false);
2144 QCOMPARE(str2.equals(QJSValue(123)), true);
2145 QCOMPARE(str2.equals(QJSValue(321)), false);
2146 QCOMPARE(str2.equals(QJSValue()), false);
2147
2148 QJSValue date1 = eng.toScriptValue(value: QDate(2000, 1, 1).startOfDay());
2149 QJSValue date2 = eng.toScriptValue(value: QDate(1999, 1, 1).startOfDay());
2150 QCOMPARE(date1.equals(date2), false);
2151 QCOMPARE(date1.equals(date1), true);
2152 QCOMPARE(date2.equals(date2), true);
2153
2154 QJSValue undefined = eng.toScriptValue(value: QVariant());
2155 QJSValue null = eng.evaluate(program: "null");
2156 QCOMPARE(undefined.equals(undefined), true);
2157 QCOMPARE(null.equals(null), true);
2158 QCOMPARE(undefined.equals(null), true);
2159 QCOMPARE(null.equals(undefined), true);
2160 QVERIFY(undefined.equals(QJSValue()));
2161 QVERIFY(null.equals(QJSValue()));
2162 QVERIFY(!null.equals(num));
2163 QVERIFY(!undefined.equals(num));
2164
2165 QJSValue sant = eng.toScriptValue(value: true);
2166 QVERIFY(sant.equals(eng.toScriptValue(1)));
2167 QVERIFY(sant.equals(eng.toScriptValue(QString::fromLatin1("1"))));
2168 QVERIFY(sant.equals(sant));
2169 QVERIFY(sant.equals(eng.evaluate("new Number(1)")));
2170 QVERIFY(sant.equals(eng.evaluate("new String('1')")));
2171 QVERIFY(sant.equals(eng.evaluate("new Boolean(true)")));
2172 QVERIFY(eng.evaluate("new Boolean(true)").equals(sant));
2173 QVERIFY(!sant.equals(eng.toScriptValue(0)));
2174 QVERIFY(!sant.equals(undefined));
2175 QVERIFY(!sant.equals(null));
2176
2177 QJSValue falskt = eng.toScriptValue(value: false);
2178 QVERIFY(falskt.equals(eng.toScriptValue(0)));
2179 QVERIFY(falskt.equals(eng.toScriptValue(QString::fromLatin1("0"))));
2180 QVERIFY(falskt.equals(falskt));
2181 QVERIFY(falskt.equals(eng.evaluate("new Number(0)")));
2182 QVERIFY(falskt.equals(eng.evaluate("new String('0')")));
2183 QVERIFY(falskt.equals(eng.evaluate("new Boolean(false)")));
2184 QVERIFY(eng.evaluate("new Boolean(false)").equals(falskt));
2185 QVERIFY(!falskt.equals(sant));
2186 QVERIFY(!falskt.equals(undefined));
2187 QVERIFY(!falskt.equals(null));
2188
2189 QJSValue obj1 = eng.newObject();
2190 QJSValue obj2 = eng.newObject();
2191 QCOMPARE(obj1.equals(obj2), false);
2192 QCOMPARE(obj2.equals(obj1), false);
2193 QCOMPARE(obj1.equals(obj1), true);
2194 QCOMPARE(obj2.equals(obj2), true);
2195
2196 QJSValue qobj1 = eng.newQObject(object: &temp);
2197 QJSValue qobj2 = eng.newQObject(object: &temp);
2198 QJSValue qobj3 = eng.newQObject(object: nullptr);
2199
2200 // FIXME: No ScriptOwnership: QJSValue qobj4 = eng.newQObject(new QObject(), QScriptEngine::ScriptOwnership);
2201 QJSValue qobj4 = eng.newQObject(object: new QObject());
2202
2203 QVERIFY(qobj1.equals(qobj2)); // compares the QObject pointers
2204 QVERIFY(!qobj2.equals(qobj4)); // compares the QObject pointers
2205 QVERIFY(!qobj2.equals(obj2)); // compares the QObject pointers
2206
2207 QJSValue compareFun = eng.evaluate(program: "(function(a, b) { return a == b; })");
2208 QVERIFY(compareFun.isCallable());
2209 {
2210 QJSValue ret = compareFun.call(args: QJSValueList() << qobj1 << qobj2);
2211 QVERIFY(ret.isBool());
2212 ret = compareFun.call(args: QJSValueList() << qobj1 << qobj3);
2213 QVERIFY(ret.isBool());
2214 QVERIFY(!ret.toBool());
2215 ret = compareFun.call(args: QJSValueList() << qobj1 << qobj4);
2216 QVERIFY(ret.isBool());
2217 QVERIFY(!ret.toBool());
2218 ret = compareFun.call(args: QJSValueList() << qobj1 << obj1);
2219 QVERIFY(ret.isBool());
2220 QVERIFY(!ret.toBool());
2221 }
2222
2223 {
2224 QJSValue var1 = eng.toScriptValue(value: QVariant(QPoint(1, 2)));
2225 QJSValue var2 = eng.toScriptValue(value: QVariant(QPoint(1, 2)));
2226 QVERIFY(var1.equals(var2));
2227 }
2228 {
2229 QJSValue var1 = eng.toScriptValue(value: QVariant(QPoint(1, 2)));
2230 QJSValue var2 = eng.toScriptValue(value: QVariant(QPoint(3, 4)));
2231 QVERIFY(!var1.equals(var2));
2232 }
2233}
2234
2235void tst_QJSValue::strictlyEquals()
2236{
2237 QJSEngine eng;
2238 QObject temp;
2239
2240 QVERIFY(QJSValue().strictlyEquals(QJSValue()));
2241
2242 QJSValue num = eng.toScriptValue(value: 123);
2243 QCOMPARE(num.strictlyEquals(eng.toScriptValue(123)), true);
2244 QCOMPARE(num.strictlyEquals(eng.toScriptValue(321)), false);
2245 QCOMPARE(num.strictlyEquals(eng.toScriptValue(QString::fromLatin1("123"))), false);
2246 QCOMPARE(num.strictlyEquals(eng.toScriptValue(QString::fromLatin1("321"))), false);
2247 QCOMPARE(num.strictlyEquals(eng.evaluate("new Number(123)")), false);
2248 QCOMPARE(num.strictlyEquals(eng.evaluate("new Number(321)")), false);
2249 QCOMPARE(num.strictlyEquals(eng.evaluate("new String('123')")), false);
2250 QCOMPARE(num.strictlyEquals(eng.evaluate("new String('321')")), false);
2251 QVERIFY(!eng.evaluate("new Number(123)").strictlyEquals(num));
2252 QVERIFY(!num.strictlyEquals(QJSValue()));
2253 QVERIFY(!QJSValue().strictlyEquals(num));
2254
2255 QJSValue str = eng.toScriptValue(value: QString::fromLatin1(str: "123"));
2256 QCOMPARE(str.strictlyEquals(eng.toScriptValue(QString::fromLatin1("123"))), true);
2257 QCOMPARE(str.strictlyEquals(eng.toScriptValue(QString::fromLatin1("321"))), false);
2258 QCOMPARE(str.strictlyEquals(eng.toScriptValue(123)), false);
2259 QCOMPARE(str.strictlyEquals(eng.toScriptValue(321)), false);
2260 QCOMPARE(str.strictlyEquals(eng.evaluate("new String('123')")), false);
2261 QCOMPARE(str.strictlyEquals(eng.evaluate("new String('321')")), false);
2262 QCOMPARE(str.strictlyEquals(eng.evaluate("new Number(123)")), false);
2263 QCOMPARE(str.strictlyEquals(eng.evaluate("new Number(321)")), false);
2264 QVERIFY(!eng.evaluate("new String('123')").strictlyEquals(str));
2265 QVERIFY(!str.strictlyEquals(QJSValue()));
2266
2267 QJSValue num2 = QJSValue(123);
2268 QCOMPARE(num2.strictlyEquals(QJSValue(123)), true);
2269 QCOMPARE(num2.strictlyEquals(QJSValue(321)), false);
2270 QCOMPARE(num2.strictlyEquals(QJSValue("123")), false);
2271 QCOMPARE(num2.strictlyEquals(QJSValue("321")), false);
2272 QVERIFY(!num2.strictlyEquals(QJSValue()));
2273
2274 QJSValue str2 = QJSValue("123");
2275 QCOMPARE(str2.strictlyEquals(QJSValue("123")), true);
2276 QCOMPARE(str2.strictlyEquals(QJSValue("321")), false);
2277 QCOMPARE(str2.strictlyEquals(QJSValue(123)), false);
2278 QCOMPARE(str2.strictlyEquals(QJSValue(321)), false);
2279 QVERIFY(!str2.strictlyEquals(QJSValue()));
2280
2281 QJSValue date1 = eng.toScriptValue(value: QDate(2000, 1, 1).startOfDay());
2282 QJSValue date2 = eng.toScriptValue(value: QDate(1999, 1, 1).startOfDay());
2283 QCOMPARE(date1.strictlyEquals(date2), false);
2284 QCOMPARE(date1.strictlyEquals(date1), true);
2285 QCOMPARE(date2.strictlyEquals(date2), true);
2286 QVERIFY(!date1.strictlyEquals(QJSValue()));
2287
2288 QJSValue undefined = eng.toScriptValue(value: QVariant());
2289 QJSValue null = eng.evaluate(program: "null");
2290 QCOMPARE(undefined.strictlyEquals(undefined), true);
2291 QCOMPARE(null.strictlyEquals(null), true);
2292 QCOMPARE(undefined.strictlyEquals(null), false);
2293 QCOMPARE(null.strictlyEquals(undefined), false);
2294 QVERIFY(!null.strictlyEquals(QJSValue()));
2295
2296 QJSValue sant = eng.toScriptValue(value: true);
2297 QVERIFY(!sant.strictlyEquals(eng.toScriptValue(1)));
2298 QVERIFY(!sant.strictlyEquals(eng.toScriptValue(QString::fromLatin1("1"))));
2299 QVERIFY(sant.strictlyEquals(sant));
2300 QVERIFY(!sant.strictlyEquals(eng.evaluate("new Number(1)")));
2301 QVERIFY(!sant.strictlyEquals(eng.evaluate("new String('1')")));
2302 QVERIFY(!sant.strictlyEquals(eng.evaluate("new Boolean(true)")));
2303 QVERIFY(!eng.evaluate("new Boolean(true)").strictlyEquals(sant));
2304 QVERIFY(!sant.strictlyEquals(eng.toScriptValue(0)));
2305 QVERIFY(!sant.strictlyEquals(undefined));
2306 QVERIFY(!sant.strictlyEquals(null));
2307 QVERIFY(!sant.strictlyEquals(QJSValue()));
2308
2309 QJSValue falskt = eng.toScriptValue(value: false);
2310 QVERIFY(!falskt.strictlyEquals(eng.toScriptValue(0)));
2311 QVERIFY(!falskt.strictlyEquals(eng.toScriptValue(QString::fromLatin1("0"))));
2312 QVERIFY(falskt.strictlyEquals(falskt));
2313 QVERIFY(!falskt.strictlyEquals(eng.evaluate("new Number(0)")));
2314 QVERIFY(!falskt.strictlyEquals(eng.evaluate("new String('0')")));
2315 QVERIFY(!falskt.strictlyEquals(eng.evaluate("new Boolean(false)")));
2316 QVERIFY(!eng.evaluate("new Boolean(false)").strictlyEquals(falskt));
2317 QVERIFY(!falskt.strictlyEquals(sant));
2318 QVERIFY(!falskt.strictlyEquals(undefined));
2319 QVERIFY(!falskt.strictlyEquals(null));
2320 QVERIFY(!falskt.strictlyEquals(QJSValue()));
2321
2322 QVERIFY(!QJSValue(false).strictlyEquals(123));
2323 QVERIFY(!QJSValue(QJSValue::UndefinedValue).strictlyEquals(123));
2324 QVERIFY(!QJSValue(QJSValue::NullValue).strictlyEquals(123));
2325 QVERIFY(!QJSValue(false).strictlyEquals("ciao"));
2326 QVERIFY(!QJSValue(QJSValue::UndefinedValue).strictlyEquals("ciao"));
2327 QVERIFY(!QJSValue(QJSValue::NullValue).strictlyEquals("ciao"));
2328 QVERIFY(eng.toScriptValue(QString::fromLatin1("ciao")).strictlyEquals("ciao"));
2329 QVERIFY(QJSValue("ciao").strictlyEquals(eng.toScriptValue(QString::fromLatin1("ciao"))));
2330 QVERIFY(!QJSValue("ciao").strictlyEquals(123));
2331 QVERIFY(!QJSValue("ciao").strictlyEquals(eng.toScriptValue(123)));
2332 QVERIFY(!QJSValue(123).strictlyEquals("ciao"));
2333 QVERIFY(!QJSValue(123).strictlyEquals(eng.toScriptValue(QString::fromLatin1("ciao"))));
2334 QVERIFY(!eng.toScriptValue(123).strictlyEquals("ciao"));
2335
2336 QJSValue obj1 = eng.newObject();
2337 QJSValue obj2 = eng.newObject();
2338 QCOMPARE(obj1.strictlyEquals(obj2), false);
2339 QCOMPARE(obj2.strictlyEquals(obj1), false);
2340 QCOMPARE(obj1.strictlyEquals(obj1), true);
2341 QCOMPARE(obj2.strictlyEquals(obj2), true);
2342 QVERIFY(!obj1.strictlyEquals(QJSValue()));
2343
2344 QJSValue qobj1 = eng.newQObject(object: &temp);
2345 QJSValue qobj2 = eng.newQObject(object: &temp);
2346 QVERIFY(qobj1.strictlyEquals(qobj2));
2347
2348 {
2349 QJSValue var1 = eng.toScriptValue(value: QVariant(QStringList() << "a"));
2350 QJSValue var2 = eng.toScriptValue(value: QVariant(QStringList() << "a"));
2351 QVERIFY(!var1.isArray());
2352 QVERIFY(!var2.isArray());
2353 QVERIFY(!var1.strictlyEquals(var2));
2354 }
2355 {
2356 QJSValue var1 = eng.toScriptValue(value: QVariant(QStringList() << "a"));
2357 QJSValue var2 = eng.toScriptValue(value: QVariant(QStringList() << "b"));
2358 QVERIFY(!var1.strictlyEquals(var2));
2359 }
2360 {
2361 QJSValue var1 = eng.toScriptValue(value: QVariant(QPoint(1, 2)));
2362 QJSValue var2 = eng.toScriptValue(value: QVariant(QPoint(1, 2)));
2363 QVERIFY(var1.strictlyEquals(var2));
2364 }
2365 {
2366 QJSValue var1 = eng.toScriptValue(value: QVariant(QPoint(1, 2)));
2367 QJSValue var2 = eng.toScriptValue(value: QVariant(QPoint(3, 4)));
2368 QVERIFY(!var1.strictlyEquals(var2));
2369 }
2370}
2371
2372Q_DECLARE_METATYPE(int*)
2373Q_DECLARE_METATYPE(double*)
2374Q_DECLARE_METATYPE(QColor*)
2375Q_DECLARE_METATYPE(QBrush*)
2376
2377void tst_QJSValue::castToPointer()
2378{
2379 QJSEngine eng;
2380 {
2381 QColor c(123, 210, 231);
2382 QJSValue v = eng.toScriptValue(value: c);
2383 QColor *cp = qjsvalue_cast<QColor*>(value: v);
2384 QVERIFY(cp != nullptr);
2385 QCOMPARE(*cp, c);
2386
2387 QBrush *bp = qjsvalue_cast<QBrush*>(value: v);
2388 QVERIFY(!bp);
2389
2390 QJSValue v2 = eng.toScriptValue(value: QVariant::fromValue(value: cp));
2391 QCOMPARE(qjsvalue_cast<QColor*>(v2), cp);
2392 }
2393}
2394
2395void tst_QJSValue::prettyPrinter_data()
2396{
2397 QTest::addColumn<QString>(name: "function");
2398 QTest::addColumn<QString>(name: "expected");
2399 QTest::newRow(dataTag: "function() { }") << QString("function() { }") << QString("function () { }");
2400 QTest::newRow(dataTag: "function foo() { }") << QString("(function foo() { })") << QString("function foo() { }");
2401 QTest::newRow(dataTag: "function foo(bar) { }") << QString("(function foo(bar) { })") << QString("function foo(bar) { }");
2402 QTest::newRow(dataTag: "function foo(bar, baz) { }") << QString("(function foo(bar, baz) { })") << QString("function foo(bar, baz) { }");
2403 QTest::newRow(dataTag: "this") << QString("function() { this; }") << QString("function () { this; }");
2404 QTest::newRow(dataTag: "identifier") << QString("function(a) { a; }") << QString("function (a) { a; }");
2405 QTest::newRow(dataTag: "null") << QString("function() { null; }") << QString("function () { null; }");
2406 QTest::newRow(dataTag: "true") << QString("function() { true; }") << QString("function () { true; }");
2407 QTest::newRow(dataTag: "false") << QString("function() { false; }") << QString("function () { false; }");
2408 QTest::newRow(dataTag: "string") << QString("function() { 'test'; }") << QString("function () { \'test\'; }");
2409 QTest::newRow(dataTag: "string") << QString("function() { \"test\"; }") << QString("function () { \"test\"; }");
2410 QTest::newRow(dataTag: "number") << QString("function() { 123; }") << QString("function () { 123; }");
2411 QTest::newRow(dataTag: "number") << QString("function() { 123.456; }") << QString("function () { 123.456; }");
2412 QTest::newRow(dataTag: "regexp") << QString("function() { /hello/; }") << QString("function () { /hello/; }");
2413 QTest::newRow(dataTag: "regexp") << QString("function() { /hello/gim; }") << QString("function () { /hello/gim; }");
2414 QTest::newRow(dataTag: "array") << QString("function() { []; }") << QString("function () { []; }");
2415 QTest::newRow(dataTag: "array") << QString("function() { [10]; }") << QString("function () { [10]; }");
2416 QTest::newRow(dataTag: "array") << QString("function() { [10, 20, 30]; }") << QString("function () { [10, 20, 30]; }");
2417 QTest::newRow(dataTag: "array") << QString("function() { [10, 20, , 40]; }") << QString("function () { [10, 20, , 40]; }");
2418 QTest::newRow(dataTag: "array") << QString("function() { [,]; }") << QString("function () { [,]; }");
2419 QTest::newRow(dataTag: "array") << QString("function() { [, 10]; }") << QString("function () { [, 10]; }");
2420 QTest::newRow(dataTag: "array") << QString("function() { [, 10, ]; }") << QString("function () { [, 10, ]; }");
2421 QTest::newRow(dataTag: "array") << QString("function() { [, 10, ,]; }") << QString("function () { [, 10, ,]; }");
2422 QTest::newRow(dataTag: "array") << QString("function() { [[10], [20]]; }") << QString("function () { [[10], [20]]; }");
2423 QTest::newRow(dataTag: "member") << QString("function() { a.b; }") << QString("function () { a.b; }");
2424 QTest::newRow(dataTag: "member") << QString("function() { a.b.c; }") << QString("function () { a.b.c; }");
2425 QTest::newRow(dataTag: "call") << QString("function() { f(); }") << QString("function () { f(); }");
2426 QTest::newRow(dataTag: "call") << QString("function() { f(a); }") << QString("function () { f(a); }");
2427 QTest::newRow(dataTag: "call") << QString("function() { f(a, b); }") << QString("function () { f(a, b); }");
2428 QTest::newRow(dataTag: "new") << QString("function() { new C(); }") << QString("function () { new C(); }");
2429 QTest::newRow(dataTag: "new") << QString("function() { new C(a); }") << QString("function () { new C(a); }");
2430 QTest::newRow(dataTag: "new") << QString("function() { new C(a, b); }") << QString("function () { new C(a, b); }");
2431 QTest::newRow(dataTag: "++") << QString("function() { a++; }") << QString("function () { a++; }");
2432 QTest::newRow(dataTag: "++") << QString("function() { ++a; }") << QString("function () { ++a; }");
2433 QTest::newRow(dataTag: "--") << QString("function() { a--; }") << QString("function () { a--; }");
2434 QTest::newRow(dataTag: "--") << QString("function() { --a; }") << QString("function () { --a; }");
2435 QTest::newRow(dataTag: "delete") << QString("function() { delete a; }") << QString("function () { delete a; }");
2436 QTest::newRow(dataTag: "void") << QString("function() { void a; }") << QString("function () { void a; }");
2437 QTest::newRow(dataTag: "typeof") << QString("function() { typeof a; }") << QString("function () { typeof a; }");
2438 QTest::newRow(dataTag: "+") << QString("function() { +a; }") << QString("function () { +a; }");
2439 QTest::newRow(dataTag: "-") << QString("function() { -a; }") << QString("function () { -a; }");
2440 QTest::newRow(dataTag: "~") << QString("function() { ~a; }") << QString("function () { ~a; }");
2441 QTest::newRow(dataTag: "!") << QString("function() { !a; }") << QString("function () { !a; }");
2442 QTest::newRow(dataTag: "+") << QString("function() { a + b; }") << QString("function () { a + b; }");
2443 QTest::newRow(dataTag: "&&") << QString("function() { a && b; }") << QString("function () { a && b; }");
2444 QTest::newRow(dataTag: "&=") << QString("function() { a &= b; }") << QString("function () { a &= b; }");
2445 QTest::newRow(dataTag: "=") << QString("function() { a = b; }") << QString("function () { a = b; }");
2446 QTest::newRow(dataTag: "&") << QString("function() { a & b; }") << QString("function () { a & b; }");
2447 QTest::newRow(dataTag: "|") << QString("function() { a | b; }") << QString("function () { a | b; }");
2448 QTest::newRow(dataTag: "^") << QString("function() { a ^ b; }") << QString("function () { a ^ b; }");
2449 QTest::newRow(dataTag: "-=") << QString("function() { a -= b; }") << QString("function () { a -= b; }");
2450 QTest::newRow(dataTag: "/") << QString("function() { a / b; }") << QString("function () { a / b; }");
2451 QTest::newRow(dataTag: "/=") << QString("function() { a /= b; }") << QString("function () { a /= b; }");
2452 QTest::newRow(dataTag: "==") << QString("function() { a == b; }") << QString("function () { a == b; }");
2453 QTest::newRow(dataTag: ">=") << QString("function() { a >= b; }") << QString("function () { a >= b; }");
2454 QTest::newRow(dataTag: ">") << QString("function() { a > b; }") << QString("function () { a > b; }");
2455 QTest::newRow(dataTag: "in") << QString("function() { a in b; }") << QString("function () { a in b; }");
2456 QTest::newRow(dataTag: "+=") << QString("function() { a += b; }") << QString("function () { a += b; }");
2457 QTest::newRow(dataTag: "instanceof") << QString("function() { a instanceof b; }") << QString("function () { a instanceof b; }");
2458 QTest::newRow(dataTag: "<=") << QString("function() { a <= b; }") << QString("function () { a <= b; }");
2459 QTest::newRow(dataTag: "<<") << QString("function() { a << b; }") << QString("function () { a << b; }");
2460 QTest::newRow(dataTag: "<<=") << QString("function() { a <<= b; }") << QString("function () { a <<= b; }");
2461 QTest::newRow(dataTag: "<") << QString("function() { a < b; }") << QString("function () { a < b; }");
2462 QTest::newRow(dataTag: "%") << QString("function() { a % b; }") << QString("function () { a % b; }");
2463 QTest::newRow(dataTag: "%=") << QString("function() { a %= b; }") << QString("function () { a %= b; }");
2464 QTest::newRow(dataTag: "*") << QString("function() { a * b; }") << QString("function () { a * b; }");
2465 QTest::newRow(dataTag: "*=") << QString("function() { a *= b; }") << QString("function () { a *= b; }");
2466 QTest::newRow(dataTag: "!=") << QString("function() { a != b; }") << QString("function () { a != b; }");
2467 QTest::newRow(dataTag: "||") << QString("function() { a || b; }") << QString("function () { a || b; }");
2468 QTest::newRow(dataTag: "|=") << QString("function() { a |= b; }") << QString("function () { a |= b; }");
2469 QTest::newRow(dataTag: ">>") << QString("function() { a >> b; }") << QString("function () { a >> b; }");
2470 QTest::newRow(dataTag: ">>=") << QString("function() { a >>= b; }") << QString("function () { a >>= b; }");
2471 QTest::newRow(dataTag: "===") << QString("function() { a === b; }") << QString("function () { a === b; }");
2472 QTest::newRow(dataTag: "!==") << QString("function() { a !== b; }") << QString("function () { a !== b; }");
2473 QTest::newRow(dataTag: "-") << QString("function() { a - b; }") << QString("function () { a - b; }");
2474 QTest::newRow(dataTag: ">>>") << QString("function() { a >>> b; }") << QString("function () { a >>> b; }");
2475 QTest::newRow(dataTag: ">>>=") << QString("function() { a >>>= b; }") << QString("function () { a >>>= b; }");
2476 QTest::newRow(dataTag: "^=") << QString("function() { a ^= b; }") << QString("function () { a ^= b; }");
2477 QTest::newRow(dataTag: "? :") << QString("function() { a ? b : c; }") << QString("function () { a ? b : c; }");
2478 QTest::newRow(dataTag: "a; b; c") << QString("function() { a; b; c; }") << QString("function () { a; b; c; }");
2479 QTest::newRow(dataTag: "var a;") << QString("function() { var a; }") << QString("function () { var a; }");
2480 QTest::newRow(dataTag: "var a, b;") << QString("function() { var a, b; }") << QString("function () { var a, b; }");
2481 QTest::newRow(dataTag: "var a = 10;") << QString("function() { var a = 10; }") << QString("function () { var a = 10; }");
2482 QTest::newRow(dataTag: "var a, b = 20;") << QString("function() { var a, b = 20; }") << QString("function () { var a, b = 20; }");
2483 QTest::newRow(dataTag: "var a = 10, b = 20;") << QString("function() { var a = 10, b = 20; }") << QString("function () { var a = 10, b = 20; }");
2484 QTest::newRow(dataTag: "if") << QString("function() { if (a) b; }") << QString("function () { if (a) b; }");
2485 QTest::newRow(dataTag: "if") << QString("function() { if (a) { b; c; } }") << QString("function () { if (a) { b; c; } }");
2486 QTest::newRow(dataTag: "if-else") << QString("function() { if (a) b; else c; }") << QString("function () { if (a) b; else c; }");
2487 QTest::newRow(dataTag: "if-else") << QString("function() { if (a) { b; c; } else { d; e; } }") << QString("function () { if (a) { b; c; } else { d; e; } }");
2488 QTest::newRow(dataTag: "do-while") << QString("function() { do { a; } while (b); }") << QString("function () { do { a; } while (b); }");
2489 QTest::newRow(dataTag: "do-while") << QString("function() { do { a; b; c; } while (d); }") << QString("function () { do { a; b; c; } while (d); }");
2490 QTest::newRow(dataTag: "while") << QString("function() { while (a) { b; } }") << QString("function () { while (a) { b; } }");
2491 QTest::newRow(dataTag: "while") << QString("function() { while (a) { b; c; } }") << QString("function () { while (a) { b; c; } }");
2492 QTest::newRow(dataTag: "for") << QString("function() { for (a; b; c) { } }") << QString("function () { for (a; b; c) { } }");
2493 QTest::newRow(dataTag: "for") << QString("function() { for (; a; b) { } }") << QString("function () { for (; a; b) { } }");
2494 QTest::newRow(dataTag: "for") << QString("function() { for (; ; a) { } }") << QString("function () { for (; ; a) { } }");
2495 QTest::newRow(dataTag: "for") << QString("function() { for (; ; ) { } }") << QString("function () { for (; ; ) { } }");
2496 QTest::newRow(dataTag: "for") << QString("function() { for (var a; b; c) { } }") << QString("function () { for (var a; b; c) { } }");
2497 QTest::newRow(dataTag: "for") << QString("function() { for (var a, b, c; d; e) { } }") << QString("function () { for (var a, b, c; d; e) { } }");
2498 QTest::newRow(dataTag: "continue") << QString("function() { for (; ; ) { continue; } }") << QString("function () { for (; ; ) { continue; } }");
2499 QTest::newRow(dataTag: "break") << QString("function() { for (; ; ) { break; } }") << QString("function () { for (; ; ) { break; } }");
2500 QTest::newRow(dataTag: "return") << QString("function() { return; }") << QString("function () { return; }");
2501 QTest::newRow(dataTag: "return") << QString("function() { return 10; }") << QString("function () { return 10; }");
2502 QTest::newRow(dataTag: "with") << QString("function() { with (a) { b; } }") << QString("function () { with (a) { b; } }");
2503 QTest::newRow(dataTag: "with") << QString("function() { with (a) { b; c; } }") << QString("function () { with (a) { b; c; } }");
2504 QTest::newRow(dataTag: "switch") << QString("function() { switch (a) { } }") << QString("function () { switch (a) { } }");
2505 QTest::newRow(dataTag: "switch") << QString("function() { switch (a) { case 1: ; } }") << QString("function () { switch (a) { case 1: ; } }");
2506 QTest::newRow(dataTag: "switch") << QString("function() { switch (a) { case 1: b; break; } }") << QString("function () { switch (a) { case 1: b; break; } }");
2507 QTest::newRow(dataTag: "switch") << QString("function() { switch (a) { case 1: b; break; case 2: break; } }") << QString("function () { switch (a) { case 1: b; break; case 2: break; } }");
2508 QTest::newRow(dataTag: "switch") << QString("function() { switch (a) { case 1: case 2: ; } }") << QString("function () { switch (a) { case 1: case 2: ; } }");
2509 QTest::newRow(dataTag: "switch") << QString("function() { switch (a) { case 1: default: ; } }") << QString("function () { switch (a) { case 1: default: ; } }");
2510 QTest::newRow(dataTag: "switch") << QString("function() { switch (a) { case 1: default: ; case 3: ; } }") << QString("function () { switch (a) { case 1: default: ; case 3: ; } }");
2511 QTest::newRow(dataTag: "label") << QString("function() { a: b; }") << QString("function () { a: b; }");
2512 QTest::newRow(dataTag: "throw") << QString("function() { throw a; }") << QString("function () { throw a; }");
2513 QTest::newRow(dataTag: "try-catch") << QString("function() { try { a; } catch (e) { b; } }") << QString("function () { try { a; } catch (e) { b; } }");
2514 QTest::newRow(dataTag: "try-finally") << QString("function() { try { a; } finally { b; } }") << QString("function () { try { a; } finally { b; } }");
2515 QTest::newRow(dataTag: "try-catch-finally") << QString("function() { try { a; } catch (e) { b; } finally { c; } }") << QString("function () { try { a; } catch (e) { b; } finally { c; } }");
2516 QTest::newRow(dataTag: "a + b + c + d") << QString("function() { a + b + c + d; }") << QString("function () { a + b + c + d; }");
2517 QTest::newRow(dataTag: "a + b - c") << QString("function() { a + b - c; }") << QString("function () { a + b - c; }");
2518 QTest::newRow(dataTag: "a + -b") << QString("function() { a + -b; }") << QString("function () { a + -b; }");
2519 QTest::newRow(dataTag: "a + ~b") << QString("function() { a + ~b; }") << QString("function () { a + ~b; }");
2520 QTest::newRow(dataTag: "a + !b") << QString("function() { a + !b; }") << QString("function () { a + !b; }");
2521 QTest::newRow(dataTag: "a + +b") << QString("function() { a + +b; }") << QString("function () { a + +b; }");
2522 QTest::newRow(dataTag: "(a + b) - c") << QString("function() { (a + b) - c; }") << QString("function () { (a + b) - c; }");
2523 QTest::newRow(dataTag: "(a - b + c") << QString("function() { a - b + c; }") << QString("function () { a - b + c; }");
2524 QTest::newRow(dataTag: "(a - (b + c)") << QString("function() { a - (b + c); }") << QString("function () { a - (b + c); }");
2525 QTest::newRow(dataTag: "a + -(b + c)") << QString("function() { a + -(b + c); }") << QString("function () { a + -(b + c); }");
2526 QTest::newRow(dataTag: "a + ~(b + c)") << QString("function() { a + ~(b + c); }") << QString("function () { a + ~(b + c); }");
2527 QTest::newRow(dataTag: "a + !(b + c)") << QString("function() { a + !(b + c); }") << QString("function () { a + !(b + c); }");
2528 QTest::newRow(dataTag: "a + +(b + c)") << QString("function() { a + +(b + c); }") << QString("function () { a + +(b + c); }");
2529 QTest::newRow(dataTag: "a + b * c") << QString("function() { a + b * c; }") << QString("function () { a + b * c; }");
2530 QTest::newRow(dataTag: "(a + b) * c") << QString("function() { (a + b) * c; }") << QString("function () { (a + b) * c; }");
2531 QTest::newRow(dataTag: "(a + b) * (c + d)") << QString("function() { (a + b) * (c + d); }") << QString("function () { (a + b) * (c + d); }");
2532 QTest::newRow(dataTag: "a + (b * c)") << QString("function() { a + (b * c); }") << QString("function () { a + (b * c); }");
2533 QTest::newRow(dataTag: "a + (b / c)") << QString("function() { a + (b / c); }") << QString("function () { a + (b / c); }");
2534 QTest::newRow(dataTag: "(a / b) * c") << QString("function() { (a / b) * c; }") << QString("function () { (a / b) * c; }");
2535 QTest::newRow(dataTag: "a / (b * c)") << QString("function() { a / (b * c); }") << QString("function () { a / (b * c); }");
2536 QTest::newRow(dataTag: "a / (b % c)") << QString("function() { a / (b % c); }") << QString("function () { a / (b % c); }");
2537 QTest::newRow(dataTag: "a && b || c") << QString("function() { a && b || c; }") << QString("function () { a && b || c; }");
2538 QTest::newRow(dataTag: "a && (b || c)") << QString("function() { a && (b || c); }") << QString("function () { a && (b || c); }");
2539 QTest::newRow(dataTag: "a & b | c") << QString("function() { a & b | c; }") << QString("function () { a & b | c; }");
2540 QTest::newRow(dataTag: "a & (b | c)") << QString("function() { a & (b | c); }") << QString("function () { a & (b | c); }");
2541 QTest::newRow(dataTag: "a & b | c ^ d") << QString("function() { a & b | c ^ d; }") << QString("function () { a & b | c ^ d; }");
2542 QTest::newRow(dataTag: "a & (b | c ^ d)") << QString("function() { a & (b | c ^ d); }") << QString("function () { a & (b | c ^ d); }");
2543 QTest::newRow(dataTag: "(a & b | c) ^ d") << QString("function() { (a & b | c) ^ d; }") << QString("function () { (a & b | c) ^ d; }");
2544 QTest::newRow(dataTag: "a << b + c") << QString("function() { a << b + c; }") << QString("function () { a << b + c; }");
2545 QTest::newRow(dataTag: "(a << b) + c") << QString("function() { (a << b) + c; }") << QString("function () { (a << b) + c; }");
2546 QTest::newRow(dataTag: "a >> b + c") << QString("function() { a >> b + c; }") << QString("function () { a >> b + c; }");
2547 QTest::newRow(dataTag: "(a >> b) + c") << QString("function() { (a >> b) + c; }") << QString("function () { (a >> b) + c; }");
2548 QTest::newRow(dataTag: "a >>> b + c") << QString("function() { a >>> b + c; }") << QString("function () { a >>> b + c; }");
2549 QTest::newRow(dataTag: "(a >>> b) + c") << QString("function() { (a >>> b) + c; }") << QString("function () { (a >>> b) + c; }");
2550 QTest::newRow(dataTag: "a == b || c != d") << QString("function() { a == b || c != d; }") << QString("function () { a == b || c != d; }");
2551 QTest::newRow(dataTag: "a == (b || c != d)") << QString("function() { a == (b || c != d); }") << QString("function () { a == (b || c != d); }");
2552 QTest::newRow(dataTag: "a === b || c !== d") << QString("function() { a === b || c !== d; }") << QString("function () { a === b || c !== d; }");
2553 QTest::newRow(dataTag: "a === (b || c !== d)") << QString("function() { a === (b || c !== d); }") << QString("function () { a === (b || c !== d); }");
2554 QTest::newRow(dataTag: "a &= b + c") << QString("function() { a &= b + c; }") << QString("function () { a &= b + c; }");
2555 QTest::newRow(dataTag: "debugger") << QString("function() { debugger; }") << QString("function () { debugger; }");
2556}
2557
2558void tst_QJSValue::prettyPrinter()
2559{
2560 QFETCH(QString, function);
2561 QFETCH(QString, expected);
2562 QJSEngine eng;
2563 QJSValue val = eng.evaluate(program: QLatin1Char('(') + function + QLatin1Char(')'));
2564 QVERIFY(val.isCallable());
2565 QString actual = val.toString();
2566 QSKIP("Function::toString() doesn't give the whole function on v4");
2567 int count = qMin(a: actual.size(), b: expected.size());
2568 for (int i = 0; i < count; ++i) {
2569 QCOMPARE(actual.at(i), expected.at(i));
2570 }
2571 QCOMPARE(actual.size(), expected.size());
2572}
2573
2574void tst_QJSValue::engineDeleted()
2575{
2576 QJSEngine *eng = new QJSEngine;
2577 QObject *temp = new QObject(); // Owned by JS engine, as newQObject() sets JS ownership explicitly
2578 QJSValue v1 = eng->toScriptValue(value: 123);
2579 QVERIFY(v1.isNumber());
2580 QJSValue v2 = eng->toScriptValue(value: QString("ciao"));
2581 QVERIFY(v2.isString());
2582 QJSValue v3 = eng->newObject();
2583 QVERIFY(v3.isObject());
2584 QJSValue v4 = eng->newQObject(object: temp);
2585 QVERIFY(v4.isQObject());
2586 QJSValue v5 = "Hello";
2587 QVERIFY(v2.isString());
2588
2589 delete eng;
2590
2591 QVERIFY(v1.isUndefined());
2592 QVERIFY(v2.isUndefined());
2593 QVERIFY(v3.isUndefined());
2594 QVERIFY(v4.isUndefined());
2595 QVERIFY(v5.isString()); // was not bound to engine
2596
2597#ifdef QT_DEPRECATED
2598 QVERIFY(!v1.engine());
2599 QVERIFY(!v2.engine());
2600 QVERIFY(!v3.engine());
2601 QVERIFY(!v4.engine());
2602 QVERIFY(!v5.engine());
2603#endif
2604
2605 QVERIFY(v3.property("foo").isUndefined());
2606}
2607
2608void tst_QJSValue::valueOfWithClosure()
2609{
2610 QJSEngine eng;
2611 // valueOf()
2612 {
2613 QJSValue obj = eng.evaluate(program: "o = {}; (function(foo) { o.valueOf = function() { return foo; } })(123); o");
2614 QVERIFY(obj.isObject());
2615 QCOMPARE(obj.toInt(), 123);
2616 }
2617 // toString()
2618 {
2619 QJSValue obj = eng.evaluate(program: "o = {}; (function(foo) { o.toString = function() { return foo; } })('ciao'); o");
2620 QVERIFY(obj.isObject());
2621 QCOMPARE(obj.toString(), QString::fromLatin1("ciao"));
2622 }
2623}
2624
2625void tst_QJSValue::nestedObjectToVariant_data()
2626{
2627 QTest::addColumn<QString>(name: "program");
2628 QTest::addColumn<QVariant>(name: "expected");
2629
2630 // Array literals
2631 QTest::newRow(dataTag: "[[]]")
2632 << QString::fromLatin1(str: "[[]]")
2633 << QVariant(QVariantList() << (QVariant(QVariantList())));
2634 QTest::newRow(dataTag: "[[123]]")
2635 << QString::fromLatin1(str: "[[123]]")
2636 << QVariant(QVariantList() << (QVariant(QVariantList() << 123)));
2637 QTest::newRow(dataTag: "[[], 123]")
2638 << QString::fromLatin1(str: "[[], 123]")
2639 << QVariant(QVariantList() << QVariant(QVariantList()) << 123);
2640
2641 // Cyclic arrays
2642 QTest::newRow(dataTag: "var a=[]; a.push(a)")
2643 << QString::fromLatin1(str: "var a=[]; a.push(a); a")
2644 << QVariant(QVariantList() << QVariant(QVariantList()));
2645 QTest::newRow(dataTag: "var a=[]; a.push(123, a)")
2646 << QString::fromLatin1(str: "var a=[]; a.push(123, a); a")
2647 << QVariant(QVariantList() << 123 << QVariant(QVariantList()));
2648 QTest::newRow(dataTag: "var a=[]; var b=[]; a.push(b); b.push(a)")
2649 << QString::fromLatin1(str: "var a=[]; var b=[]; a.push(b); b.push(a); a")
2650 << QVariant(QVariantList() << QVariant(QVariantList() << QVariant(QVariantList())));
2651 QTest::newRow(dataTag: "var a=[]; var b=[]; a.push(123, b); b.push(456, a)")
2652 << QString::fromLatin1(str: "var a=[]; var b=[]; a.push(123, b); b.push(456, a); a")
2653 << QVariant(QVariantList() << 123 << QVariant(QVariantList() << 456 << QVariant(QVariantList())));
2654
2655 // Object literals
2656 {
2657 QVariantMap m;
2658 QTest::newRow(dataTag: "{}")
2659 << QString::fromLatin1(str: "({})")
2660 << QVariant(m);
2661 }
2662 {
2663 QVariantMap m;
2664 m["a"] = QVariantMap();
2665 QTest::newRow(dataTag: "{ a:{} }")
2666 << QString::fromLatin1(str: "({ a:{} })")
2667 << QVariant(m);
2668 }
2669 {
2670 QVariantMap m, m2;
2671 m2["b"] = 10;
2672 m2["c"] = 20;
2673 m["a"] = m2;
2674 QTest::newRow(dataTag: "{ a:{b:10, c:20} }")
2675 << QString::fromLatin1(str: "({ a:{b:10, c:20} })")
2676 << QVariant(m);
2677 }
2678 {
2679 QVariantMap m;
2680 m["a"] = 10;
2681 m["b"] = QVariantList() << 20 << 30;
2682 QTest::newRow(dataTag: "{ a:10, b:[20, 30]}")
2683 << QString::fromLatin1(str: "({ a:10, b:[20,30]})")
2684 << QVariant(m);
2685 }
2686
2687 // Cyclic objects
2688 {
2689 QVariantMap m;
2690 m["p"] = QVariantMap();
2691 QTest::newRow(dataTag: "var o={}; o.p=o")
2692 << QString::fromLatin1(str: "var o={}; o.p=o; o")
2693 << QVariant(m);
2694 }
2695 {
2696 QVariantMap m;
2697 m["p"] = 123;
2698 m["q"] = QVariantMap();
2699 QTest::newRow(dataTag: "var o={}; o.p=123; o.q=o")
2700 << QString::fromLatin1(str: "var o={}; o.p=123; o.q=o; o")
2701 << QVariant(m);
2702 }
2703}
2704
2705void tst_QJSValue::nestedObjectToVariant()
2706{
2707 QJSEngine eng;
2708 QFETCH(QString, program);
2709 QFETCH(QVariant, expected);
2710 QJSValue o = eng.evaluate(program);
2711 QVERIFY(!o.isError());
2712 QVERIFY(o.isObject());
2713 QCOMPARE(o.toVariant(), expected);
2714}
2715
2716static int instanceCount = 0;
2717
2718struct MyType
2719{
2720 MyType(int n = 0, const char *t=nullptr): number(n), text(t)
2721 {
2722 ++instanceCount;
2723 }
2724 MyType(const MyType &other)
2725 : number(other.number), text(other.text)
2726 {
2727 ++instanceCount;
2728 }
2729 ~MyType()
2730 {
2731 --instanceCount;
2732 }
2733 int number;
2734 const char *text;
2735};
2736
2737Q_DECLARE_METATYPE(MyType)
2738Q_DECLARE_METATYPE(MyType*)
2739
2740void tst_QJSValue::jsvalueArrayToSequenceType()
2741{
2742 QCOMPARE(instanceCount, 0);
2743 {
2744 QJSEngine eng {};
2745 auto testObject = eng.newObject();
2746 testObject.setProperty(name: "test", value: 42);
2747 testObject.setProperty(name: "mytypeobject", value: eng.toScriptValue(value: QVariant::fromValue(value: MyType {42, "hello"})));
2748 auto array = eng.newArray(length: 4);
2749 array.setProperty(arrayIndex: 0, value: QLatin1String("Hello World"));
2750 array.setProperty(arrayIndex: 1, value: 42);
2751 array.setProperty(arrayIndex: 2, value: QJSValue(QJSValue::UndefinedValue));
2752 array.setProperty(arrayIndex: 3, value: testObject);
2753 auto asVariant = QVariant::fromValue(value: array);
2754 QVERIFY(asVariant.canConvert<QVariantList>());
2755 auto asIterable = asVariant.value<QSequentialIterable>();
2756 for (auto it = asIterable.begin(); it != asIterable.end(); ++it) {
2757 Q_UNUSED(*it)
2758 }
2759 int i = 0;
2760 for (QVariant myVariant: asIterable) {
2761 QCOMPARE(myVariant.isValid(), i != 2);
2762 ++i;
2763 }
2764 QVERIFY(asIterable.at(2).value<QVariant>().isNull());
2765 QCOMPARE(asIterable.at(3).value<QVariantMap>().find("mytypeobject")->value<MyType>().number, 42);
2766 QCOMPARE(asIterable.at(0).value<QVariant>().toString(), QLatin1String("Hello World"));
2767 auto it1 = asIterable.begin();
2768 auto it2 = asIterable.begin();
2769 QCOMPARE((*it1).value<QVariant>().toString(), (*it2).value<QVariant>().toString());
2770 QCOMPARE((*it1).value<QVariant>().toString(), QLatin1String("Hello World"));
2771 ++it2;
2772 QCOMPARE((*it1).value<QVariant>().toString(), QLatin1String("Hello World"));
2773 QCOMPARE((*it2).value<QVariant>().toInt(), 42);
2774 }
2775 // tests need to be done after engine has been destroyed, else it will hold a reference until
2776 // the gc decides to collect it
2777 QCOMPARE(instanceCount, 0);
2778}
2779
2780void tst_QJSValue::deleteFromDifferentThread()
2781{
2782#if !QT_CONFIG(thread)
2783 QSKIP("Need thread support to destroy QJSValues from different threads");
2784#else
2785 QV4::PersistentValueStorage storage(engine->handle());
2786 QCOMPARE(storage.firstPage, nullptr);
2787 QJSValue jsval;
2788 QJSValuePrivate::setRawValue(jsval: &jsval, v: storage.allocate());
2789 QVERIFY(storage.firstPage != nullptr);
2790
2791 QMutex mutex;
2792 QWaitCondition condition;
2793
2794 std::unique_ptr<QThread> thread(QThread::create(f: [&]() {
2795 QMutexLocker locker(&mutex);
2796 QJSValuePrivate::free(jsval: &jsval);
2797 QJSValuePrivate::setRawValue(jsval: &jsval, v: nullptr);
2798 QVERIFY(storage.firstPage != nullptr);
2799 condition.wakeOne();
2800 }));
2801
2802 QMutexLocker locker(&mutex);
2803 thread->start();
2804 condition.wait(lockedMutex: &mutex);
2805 QTRY_VERIFY(thread->isFinished());
2806 QTRY_COMPARE(storage.firstPage, nullptr);
2807#endif
2808}
2809
2810QTEST_MAIN(tst_QJSValue)
2811

source code of qtdeclarative/tests/auto/qml/qjsvalue/tst_qjsvalue.cpp