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 <QtTest>
30
31#include "qjsonarray.h"
32#include "qjsonobject.h"
33#include "qjsonvalue.h"
34#include "qjsondocument.h"
35#include "qregularexpression.h"
36#include "private/qnumeric_p.h"
37#include <limits>
38
39#define INVALID_UNICODE "\xCE\xBA\xE1"
40#define UNICODE_NON_CHARACTER "\xEF\xBF\xBF"
41#define UNICODE_DJE "\320\202" // Character from the Serbian Cyrillic alphabet
42
43class tst_QtJson: public QObject
44{
45 Q_OBJECT
46
47private Q_SLOTS:
48 void initTestCase();
49
50 void testValueSimple();
51 void testNumbers();
52 void testNumbers_2();
53 void testNumbers_3();
54 void testNumbers_4();
55
56 void testObjectSimple();
57 void testObjectTakeDetach();
58 void testObjectSmallKeys();
59 void testObjectInsertCopies();
60 void testArraySimple();
61 void testArrayInsertCopies();
62 void testValueObject();
63 void testValueArray();
64 void testObjectNested();
65 void testArrayNested();
66 void testArrayNestedEmpty();
67 void testArrayComfortOperators();
68 void testObjectNestedEmpty();
69
70 void testValueRef();
71 void testValueRefComparison();
72 void testObjectIteration();
73 void testArrayIteration();
74
75 void testObjectFind();
76
77 void testDocument();
78
79 void nullValues();
80 void nullArrays();
81 void nullObject();
82 void constNullObject();
83
84 void keySorting_data();
85 void keySorting();
86
87 void undefinedValues();
88
89 void fromVariant_data();
90 void fromVariant();
91 void fromVariantSpecial_data();
92 void fromVariantSpecial();
93 void toVariant_data();
94 void toVariant();
95 void fromVariantMap();
96 void fromVariantHash();
97 void toVariantMap();
98 void toVariantHash();
99 void toVariantList();
100
101 void toJson();
102 void toJsonSillyNumericValues();
103 void toJsonLargeNumericValues();
104 void fromJson();
105 void fromJsonErrors();
106 void fromBinary();
107 void toAndFromBinary_data();
108 void toAndFromBinary();
109 void invalidBinaryData();
110 void parseNumbers();
111 void parseStrings();
112 void parseDuplicateKeys();
113 void testParser();
114
115 void compactArray();
116 void compactObject();
117
118 void validation();
119
120 void assignToDocument();
121
122 void testDuplicateKeys();
123 void testCompaction();
124 void testDebugStream();
125 void testCompactionError();
126
127 void parseUnicodeEscapes();
128
129 void assignObjects();
130 void assignArrays();
131
132 void testTrailingComma();
133 void testDetachBug();
134 void testJsonValueRefDefault();
135
136 void valueEquals();
137 void objectEquals_data();
138 void objectEquals();
139 void arrayEquals_data();
140 void arrayEquals();
141 void documentEquals_data();
142 void documentEquals();
143
144 void bom();
145 void nesting();
146
147 void longStrings();
148
149 void arrayInitializerList();
150 void objectInitializerList();
151
152 void unicodeKeys();
153 void garbageAtEnd();
154
155 void removeNonLatinKey();
156 void documentFromVariant();
157
158 void parseErrorOffset_data();
159 void parseErrorOffset();
160
161 void implicitValueType();
162 void implicitDocumentType();
163
164 void streamSerializationQJsonDocument_data();
165 void streamSerializationQJsonDocument();
166 void streamSerializationQJsonArray_data();
167 void streamSerializationQJsonArray();
168 void streamSerializationQJsonObject_data();
169 void streamSerializationQJsonObject();
170 void streamSerializationQJsonValue_data();
171 void streamSerializationQJsonValue();
172 void streamSerializationQJsonValueEmpty();
173 void streamVariantSerialization();
174 void escapeSurrogateCodePoints_data();
175 void escapeSurrogateCodePoints();
176
177 void fromToVariantConversions_data();
178 void fromToVariantConversions();
179
180 void noLeakOnNameClash();
181
182private:
183 QString testDataDir;
184};
185
186void tst_QtJson::initTestCase()
187{
188 testDataDir = QFileInfo(QFINDTESTDATA("test.json")).absolutePath();
189 if (testDataDir.isEmpty())
190 testDataDir = QCoreApplication::applicationDirPath();
191}
192
193void tst_QtJson::testValueSimple()
194{
195 QJsonObject object;
196 object.insert(key: "number", value: 999.);
197 QJsonArray array;
198 for (int i = 0; i < 10; ++i)
199 array.append(value: (double)i);
200
201 QJsonValue value(true);
202 QCOMPARE(value.type(), QJsonValue::Bool);
203 QCOMPARE(value.toDouble(), 0.);
204 QCOMPARE(value.toString(), QString());
205 QCOMPARE(value.toBool(), true);
206 QCOMPARE(value.toObject(), QJsonObject());
207 QCOMPARE(value.toArray(), QJsonArray());
208 QCOMPARE(value.toDouble(99.), 99.);
209 QCOMPARE(value.toString(QString("test")), QString("test"));
210 QCOMPARE(value.toObject(object), object);
211 QCOMPARE(value.toArray(array), array);
212
213 value = 999.;
214 QCOMPARE(value.type(), QJsonValue::Double);
215 QCOMPARE(value.toDouble(), 999.);
216 QCOMPARE(value.toString(), QString());
217 QCOMPARE(value.toBool(), false);
218 QCOMPARE(value.toBool(true), true);
219 QCOMPARE(value.toObject(), QJsonObject());
220 QCOMPARE(value.toArray(), QJsonArray());
221
222 value = QLatin1String("test");
223 QCOMPARE(value.toDouble(), 0.);
224 QCOMPARE(value.toString(), QLatin1String("test"));
225 QCOMPARE(value.toBool(), false);
226 QCOMPARE(value.toObject(), QJsonObject());
227 QCOMPARE(value.toArray(), QJsonArray());
228}
229
230void tst_QtJson::testNumbers()
231{
232 {
233 int numbers[] = {
234 0,
235 -1,
236 1,
237 (1<<26),
238 (1<<27),
239 (1<<28),
240 -(1<<26),
241 -(1<<27),
242 -(1<<28),
243 (1<<26) - 1,
244 (1<<27) - 1,
245 (1<<28) - 1,
246 -((1<<26) - 1),
247 -((1<<27) - 1),
248 -((1<<28) - 1)
249 };
250 int n = sizeof(numbers)/sizeof(int);
251
252 QJsonArray array;
253 for (int i = 0; i < n; ++i)
254 array.append(value: (double)numbers[i]);
255
256 QByteArray serialized = QJsonDocument(array).toJson();
257 QJsonDocument json = QJsonDocument::fromJson(json: serialized);
258 QJsonArray array2 = json.array();
259
260 QCOMPARE(array.size(), array2.size());
261 for (int i = 0; i < array.size(); ++i) {
262 QCOMPARE(array.at(i).type(), QJsonValue::Double);
263 QCOMPARE(array.at(i).toDouble(), (double)numbers[i]);
264 QCOMPARE(array2.at(i).type(), QJsonValue::Double);
265 QCOMPARE(array2.at(i).toDouble(), (double)numbers[i]);
266 }
267 }
268
269 {
270 qint64 numbers[] = {
271 0,
272 -1,
273 1,
274 (1ll<<54),
275 (1ll<<55),
276 (1ll<<56),
277 -(1ll<<54),
278 -(1ll<<55),
279 -(1ll<<56),
280 (1ll<<54) - 1,
281 (1ll<<55) - 1,
282 (1ll<<56) - 1,
283 -((1ll<<54) - 1),
284 -((1ll<<55) - 1),
285 -((1ll<<56) - 1)
286 };
287 int n = sizeof(numbers)/sizeof(qint64);
288
289 QJsonArray array;
290 for (int i = 0; i < n; ++i)
291 array.append(value: (double)numbers[i]);
292
293 QByteArray serialized = QJsonDocument(array).toJson();
294 QJsonDocument json = QJsonDocument::fromJson(json: serialized);
295 QJsonArray array2 = json.array();
296
297 QCOMPARE(array.size(), array2.size());
298 for (int i = 0; i < array.size(); ++i) {
299 QCOMPARE(array.at(i).type(), QJsonValue::Double);
300 QCOMPARE(array.at(i).toDouble(), (double)numbers[i]);
301 QCOMPARE(array2.at(i).type(), QJsonValue::Double);
302 QCOMPARE(array2.at(i).toDouble(), (double)numbers[i]);
303 }
304 }
305
306 {
307 double numbers[] = {
308 0,
309 -1,
310 1,
311 double(1ll<<54),
312 double(1ll<<55),
313 double(1ll<<56),
314 double(-(1ll<<54)),
315 double(-(1ll<<55)),
316 double(-(1ll<<56)),
317 double((1ll<<54) - 1),
318 double((1ll<<55) - 1),
319 double((1ll<<56) - 1),
320 double(-((1ll<<54) - 1)),
321 double(-((1ll<<55) - 1)),
322 double(-((1ll<<56) - 1)),
323 1.1,
324 0.1,
325 -0.1,
326 -1.1,
327 1e200,
328 -1e200
329 };
330 int n = sizeof(numbers)/sizeof(double);
331
332 QJsonArray array;
333 for (int i = 0; i < n; ++i)
334 array.append(value: numbers[i]);
335
336 QByteArray serialized = QJsonDocument(array).toJson();
337 QJsonDocument json = QJsonDocument::fromJson(json: serialized);
338 QJsonArray array2 = json.array();
339
340 QCOMPARE(array.size(), array2.size());
341 for (int i = 0; i < array.size(); ++i) {
342 QCOMPARE(array.at(i).type(), QJsonValue::Double);
343 QCOMPARE(array.at(i).toDouble(), numbers[i]);
344 QCOMPARE(array2.at(i).type(), QJsonValue::Double);
345 QCOMPARE(array2.at(i).toDouble(), numbers[i]);
346 }
347 }
348
349}
350
351void tst_QtJson::testNumbers_2()
352{
353 // test cases from TC39 test suite for ECMAScript
354 // http://hg.ecmascript.org/tests/test262/file/d067d2f0ca30/test/suite/ch08/8.5/8.5.1.js
355
356 // Fill an array with 2 to the power of (0 ... -1075)
357 double value = 1;
358 double floatValues[1076], floatValues_1[1076];
359 QJsonObject jObject;
360 for (int power = 0; power <= 1075; power++) {
361 floatValues[power] = value;
362 jObject.insert(key: QString::number(power), value: QJsonValue(floatValues[power]));
363 // Use basic math operations for testing, which are required to support 'gradual underflow' rather
364 // than Math.pow etc..., which are defined as 'implementation dependent'.
365 value = value * 0.5;
366 }
367
368 QJsonDocument jDocument1(jObject);
369 QByteArray ba(jDocument1.toJson());
370
371 QJsonDocument jDocument2(QJsonDocument::fromJson(json: ba));
372 for (int power = 0; power <= 1075; power++) {
373 floatValues_1[power] = jDocument2.object().value(key: QString::number(power)).toDouble();
374#ifdef Q_OS_QNX
375 if (power >= 970)
376 QEXPECT_FAIL("", "See QTBUG-37066", Abort);
377#endif
378 QVERIFY2(floatValues[power] == floatValues_1[power], QString("floatValues[%1] != floatValues_1[%1]").arg(power).toLatin1());
379 }
380
381 // The last value is below min denorm and should round to 0, everything else should contain a value
382 QVERIFY2(floatValues_1[1075] == 0, "Value after min denorm should round to 0");
383
384 // Validate the last actual value is min denorm
385 QVERIFY2(floatValues_1[1074] == 4.9406564584124654417656879286822e-324, QString("Min denorm value is incorrect: %1").arg(floatValues_1[1074]).toLatin1());
386
387 // Validate that every value is half the value before it up to 1
388 for (int index = 1074; index > 0; index--) {
389 QVERIFY2(floatValues_1[index] != 0, QString("2**- %1 should not be 0").arg(index).toLatin1());
390
391 QVERIFY2(floatValues_1[index - 1] == (floatValues_1[index] * 2), QString("Value should be double adjacent value at index %1").arg(index).toLatin1());
392 }
393}
394
395void tst_QtJson::testNumbers_3()
396{
397 // test case from QTBUG-31926
398 double d1 = 1.123451234512345;
399 double d2 = 1.123451234512346;
400
401 QJsonObject jObject;
402 jObject.insert(key: "d1", value: QJsonValue(d1));
403 jObject.insert(key: "d2", value: QJsonValue(d2));
404 QJsonDocument jDocument1(jObject);
405 QByteArray ba(jDocument1.toJson());
406
407 QJsonDocument jDocument2(QJsonDocument::fromJson(json: ba));
408
409 double d1_1(jDocument2.object().value(key: "d1").toDouble());
410 double d2_1(jDocument2.object().value(key: "d2").toDouble());
411 QVERIFY(d1_1 != d2_1);
412}
413
414void tst_QtJson::testNumbers_4()
415{
416 // no exponent notation used to print numbers between -2^64 and 2^64
417 QJsonArray array;
418 array << QJsonValue(+1000000000000000.0);
419 array << QJsonValue(-1000000000000000.0);
420 array << QJsonValue(+9007199254740992.0);
421 array << QJsonValue(-9007199254740992.0);
422 array << QJsonValue(+9223372036854775808.0);
423 array << QJsonValue(-9223372036854775808.0);
424 array << QJsonValue(+18446744073709551616.0);
425 array << QJsonValue(-18446744073709551616.0);
426 const QByteArray json(QJsonDocument(array).toJson());
427 const QByteArray expected =
428 "[\n"
429 " 1000000000000000,\n"
430 " -1000000000000000,\n"
431 " 9007199254740992,\n"
432 " -9007199254740992,\n"
433 " 9223372036854776000,\n"
434 " -9223372036854776000,\n"
435 " 18446744073709552000,\n"
436 " -18446744073709552000\n"
437 "]\n";
438 QCOMPARE(json, expected);
439}
440
441void tst_QtJson::testObjectSimple()
442{
443 QJsonObject object;
444 object.insert(key: "number", value: 999.);
445 QCOMPARE(object.value("number").type(), QJsonValue::Double);
446 QCOMPARE(object.value(QLatin1String("number")).toDouble(), 999.);
447 object.insert(key: "string", value: QString::fromLatin1(str: "test"));
448 QCOMPARE(object.value("string").type(), QJsonValue::String);
449 QCOMPARE(object.value(QLatin1String("string")).toString(), QString("test"));
450 object.insert(key: "boolean", value: true);
451 QCOMPARE(object.value("boolean").toBool(), true);
452 QCOMPARE(object.value(QLatin1String("boolean")).toBool(), true);
453 QJsonObject object2 = object;
454 QJsonObject object3 = object;
455
456 QStringList keys = object.keys();
457 QVERIFY2(keys.contains("number"), "key number not found");
458 QVERIFY2(keys.contains("string"), "key string not found");
459 QVERIFY2(keys.contains("boolean"), "key boolean not found");
460
461 // if we put a JsonValue into the JsonObject and retrieve
462 // it, it should be identical.
463 QJsonValue value(QLatin1String("foo"));
464 object.insert(key: "value", value);
465 QCOMPARE(object.value("value"), value);
466
467 int size = object.size();
468 object.remove(key: "boolean");
469 QCOMPARE(object.size(), size - 1);
470 QVERIFY2(!object.contains("boolean"), "key boolean should have been removed");
471
472 QJsonValue taken = object.take(key: "value");
473 QCOMPARE(taken, value);
474 QVERIFY2(!object.contains("value"), "key value should have been removed");
475
476 QString before = object.value(key: "string").toString();
477 object.insert(key: "string", value: QString::fromLatin1(str: "foo"));
478 QVERIFY2(object.value(QLatin1String("string")).toString() != before, "value should have been updated");
479
480 // same tests again but with QStringView keys
481 object2.insert(key: QStringView(u"value"), value);
482 QCOMPARE(object2.value("value"), value);
483
484 size = object2.size();
485 object2.remove(key: QStringView(u"boolean"));
486 QCOMPARE(object2.size(), size - 1);
487 QVERIFY2(!object2.contains(QStringView(u"boolean")), "key boolean should have been removed");
488
489 taken = object2.take(key: QStringView(u"value"));
490 QCOMPARE(taken, value);
491 QVERIFY2(!object2.contains("value"), "key value should have been removed");
492
493 before = object2.value(key: "string").toString();
494 object2.insert(key: QStringView(u"string"), value: QString::fromLatin1(str: "foo"));
495 QVERIFY2(object2.value(QStringView(u"string")).toString() != before, "value should have been updated");
496
497 // same tests again but with QLatin1String keys
498 object3.insert(key: QLatin1String("value"), value);
499 QCOMPARE(object3.value("value"), value);
500
501 size = object3.size();
502 object3.remove(key: QLatin1String("boolean"));
503 QCOMPARE(object3.size(), size - 1);
504 QVERIFY2(!object3.contains("boolean"), "key boolean should have been removed");
505
506 taken = object3.take(key: QLatin1String("value"));
507 QCOMPARE(taken, value);
508 QVERIFY2(!object3.contains("value"), "key value should have been removed");
509
510 before = object3.value(key: "string").toString();
511 object3.insert(key: QLatin1String("string"), value: QString::fromLatin1(str: "foo"));
512 QVERIFY2(object3.value(QLatin1String("string")).toString() != before, "value should have been updated");
513
514 size = object.size();
515 QJsonObject subobject;
516 subobject.insert(key: "number", value: 42);
517 subobject.insert(key: QLatin1String("string"), value: QLatin1String("foobar"));
518 object.insert(key: "subobject", value: subobject);
519 QCOMPARE(object.size(), size+1);
520 QJsonValue subvalue = object.take(key: QLatin1String("subobject"));
521 QCOMPARE(object.size(), size);
522 QCOMPARE(subvalue.toObject(), subobject);
523 // make object detach by modifying it many times
524 for (int i = 0; i < 64; ++i)
525 object.insert(key: QLatin1String("string"), value: QLatin1String("bar"));
526 QCOMPARE(object.size(), size);
527 QCOMPARE(subvalue.toObject(), subobject);
528}
529
530void tst_QtJson::testObjectTakeDetach()
531{
532 QJsonObject object1, object2;
533 object1["key1"] = 1;
534 object1["key2"] = 2;
535 object2 = object1;
536
537 object1.take(key: "key2");
538 object1.remove(key: "key1");
539 QVERIFY(!object1.contains("key1"));
540 QVERIFY(object2.contains("key1"));
541 QVERIFY(object2.value("key1").isDouble());
542
543 QVERIFY(!object1.contains("key2"));
544 QVERIFY(object2.contains("key2"));
545 QVERIFY(object2.value("key2").isDouble());
546}
547
548void tst_QtJson::testObjectSmallKeys()
549{
550 QJsonObject data1;
551 data1.insert(QStringLiteral("1"), value: 123.);
552 QVERIFY(data1.contains(QStringLiteral("1")));
553 QCOMPARE(data1.value(QStringLiteral("1")).toDouble(), (double)123);
554 data1.insert(QStringLiteral("12"), value: 133.);
555 QCOMPARE(data1.value(QStringLiteral("12")).toDouble(), (double)133);
556 QVERIFY(data1.contains(QStringLiteral("12")));
557 data1.insert(QStringLiteral("123"), value: 323.);
558 QCOMPARE(data1.value(QStringLiteral("12")).toDouble(), (double)133);
559 QVERIFY(data1.contains(QStringLiteral("123")));
560 QCOMPARE(data1.value(QStringLiteral("123")).type(), QJsonValue::Double);
561 QCOMPARE(data1.value(QStringLiteral("123")).toDouble(), (double)323);
562 QCOMPARE(data1.constEnd() - data1.constBegin(), 3);
563 QCOMPARE(data1.end() - data1.begin(), 3);
564}
565
566void tst_QtJson::testObjectInsertCopies()
567{
568 {
569 QJsonObject obj;
570 obj["prop1"] = "TEST";
571 QCOMPARE(obj.size(), 1);
572 QCOMPARE(obj.value("prop1"), "TEST");
573
574 obj["prop2"] = obj.value(key: "prop1");
575 QCOMPARE(obj.size(), 2);
576 QCOMPARE(obj.value("prop1"), "TEST");
577 QCOMPARE(obj.value("prop2"), "TEST");
578 }
579 {
580 // see QTBUG-83366
581 QJsonObject obj;
582 obj["value"] = "TEST";
583 QCOMPARE(obj.size(), 1);
584 QCOMPARE(obj.value("value"), "TEST");
585
586 obj["prop2"] = obj.value(key: "value");
587 QCOMPARE(obj.size(), 2);
588 QCOMPARE(obj.value("value"), "TEST");
589 QCOMPARE(obj.value("prop2"), "TEST");
590 }
591 {
592 QJsonObject obj;
593 obj["value"] = "TEST";
594 QCOMPARE(obj.size(), 1);
595 QCOMPARE(obj.value("value"), "TEST");
596
597 // same as previous, but this is a QJsonValueRef
598 QJsonValueRef rv = obj["prop2"];
599 rv = obj["value"];
600 QCOMPARE(obj.size(), 2);
601 QCOMPARE(obj.value("value"), "TEST");
602 QCOMPARE(obj.value("prop2"), "TEST");
603 }
604 {
605 QJsonObject obj;
606 obj["value"] = "TEST";
607 QCOMPARE(obj.size(), 1);
608 QCOMPARE(obj.value("value"), "TEST");
609
610 // same as previous, but this is a QJsonValueRef
611 QJsonValueRef rv = obj["value"];
612 obj["prop2"] = rv;
613 QCOMPARE(obj.size(), 2);
614 QCOMPARE(obj.value("value"), "TEST");
615 QEXPECT_FAIL("", "QTBUG-83398: design flaw: the obj[] call invalidates the QJsonValueRef", Continue);
616 QCOMPARE(obj.value("prop2"), "TEST");
617 }
618 {
619 QJsonObject obj;
620 obj["value"] = "TEST";
621 QCOMPARE(obj.size(), 1);
622 QCOMPARE(obj.value("value"), "TEST");
623
624 QJsonValueRef v = obj["value"];
625 QJsonObject obj2 = obj;
626 obj.insert(key: "prop2", value: v);
627 QCOMPARE(obj.size(), 2);
628 QCOMPARE(obj.value("value"), "TEST");
629 QCOMPARE(obj.value("prop2"), "TEST");
630 QCOMPARE(obj2.size(), 1);
631 QCOMPARE(obj2.value("value"), "TEST");
632 }
633}
634
635void tst_QtJson::testArraySimple()
636{
637 QJsonArray array;
638 array.append(value: 999.);
639 array.append(value: QString::fromLatin1(str: "test"));
640 array.append(value: true);
641
642 QJsonValue val = array.at(i: 0);
643 QCOMPARE(array.at(0).toDouble(), 999.);
644 QCOMPARE(array.at(1).toString(), QString("test"));
645 QCOMPARE(array.at(2).toBool(), true);
646 QCOMPARE(array.size(), 3);
647
648 // if we put a JsonValue into the JsonArray and retrieve
649 // it, it should be identical.
650 QJsonValue value(QLatin1String("foo"));
651 array.append(value);
652 QCOMPARE(array.at(3), value);
653
654 int size = array.size();
655 array.removeAt(i: 2);
656 --size;
657 QCOMPARE(array.size(), size);
658
659 QJsonValue taken = array.takeAt(i: 0);
660 --size;
661 QCOMPARE(taken.toDouble(), 999.);
662 QCOMPARE(array.size(), size);
663
664 // check whether null values work
665 array.append(value: QJsonValue());
666 ++size;
667 QCOMPARE(array.size(), size);
668 QCOMPARE(array.last().type(), QJsonValue::Null);
669 QCOMPARE(array.last(), QJsonValue());
670
671 QCOMPARE(array.first().type(), QJsonValue::String);
672 QCOMPARE(array.first(), QJsonValue(QLatin1String("test")));
673
674 array.prepend(value: false);
675 QCOMPARE(array.first().type(), QJsonValue::Bool);
676 QCOMPARE(array.first(), QJsonValue(false));
677
678 QCOMPARE(array.at(-1), QJsonValue(QJsonValue::Undefined));
679 QCOMPARE(array.at(array.size()), QJsonValue(QJsonValue::Undefined));
680
681 array.replace(i: 0, value: -555.);
682 QCOMPARE(array.first().type(), QJsonValue::Double);
683 QCOMPARE(array.first(), QJsonValue(-555.));
684 QCOMPARE(array.at(1).type(), QJsonValue::String);
685 QCOMPARE(array.at(1), QJsonValue(QLatin1String("test")));
686}
687
688void tst_QtJson::testArrayInsertCopies()
689{
690 {
691 QJsonArray array;
692 array.append(value: "TEST");
693 QCOMPARE(array.size(), 1);
694 QCOMPARE(array.at(0), "TEST");
695
696 array.append(value: array.at(i: 0));
697 QCOMPARE(array.size(), 2);
698 QCOMPARE(array.at(0), "TEST");
699 QCOMPARE(array.at(1), "TEST");
700 }
701 {
702 QJsonArray array;
703 array.append(value: "TEST");
704 QCOMPARE(array.size(), 1);
705 QCOMPARE(array.at(0), "TEST");
706
707 array.prepend(value: array.at(i: 0));
708 QCOMPARE(array.size(), 2);
709 QCOMPARE(array.at(0), "TEST");
710 QCOMPARE(array.at(1), "TEST");
711 }
712}
713
714void tst_QtJson::testValueObject()
715{
716 QJsonObject object;
717 object.insert(key: "number", value: 999.);
718 object.insert(key: "string", value: QLatin1String("test"));
719 object.insert(key: "boolean", value: true);
720
721 QJsonValue value(object);
722
723 // if we don't modify the original JsonObject, toObject()
724 // on the JsonValue should return the same object (non-detached).
725 QCOMPARE(value.toObject(), object);
726
727 // if we modify the original object, it should detach
728 object.insert(key: "test", value: QJsonValue(QLatin1String("test")));
729 QVERIFY2(value.toObject() != object, "object should have detached");
730}
731
732void tst_QtJson::testValueArray()
733{
734 QJsonArray array;
735 array.append(value: 999.);
736 array.append(value: QLatin1String("test"));
737 array.append(value: true);
738
739 QJsonValue value(array);
740
741 // if we don't modify the original JsonArray, toArray()
742 // on the JsonValue should return the same object (non-detached).
743 QCOMPARE(value.toArray(), array);
744
745 // if we modify the original array, it should detach
746 array.append(value: QLatin1String("test"));
747 QVERIFY2(value.toArray() != array, "array should have detached");
748}
749
750void tst_QtJson::testObjectNested()
751{
752 QJsonObject inner, outer;
753 inner.insert(key: "number", value: 999.);
754 outer.insert(key: "nested", value: inner);
755
756 // if we don't modify the original JsonObject, value()
757 // should return the same object (non-detached).
758 QJsonObject value = outer.value(key: "nested").toObject();
759 QCOMPARE(value, inner);
760 QCOMPARE(value.value("number").toDouble(), 999.);
761
762 // if we modify the original object, it should detach and not
763 // affect the nested object
764 inner.insert(key: "number", value: 555.);
765 value = outer.value(key: "nested").toObject();
766 QVERIFY2(inner.value("number").toDouble() != value.value("number").toDouble(),
767 "object should have detached");
768
769 // array in object
770 QJsonArray array;
771 array.append(value: 123.);
772 array.append(value: 456.);
773 outer.insert(key: "array", value: array);
774 QCOMPARE(outer.value("array").toArray(), array);
775 QCOMPARE(outer.value("array").toArray().at(1).toDouble(), 456.);
776
777 // two deep objects
778 QJsonObject twoDeep;
779 twoDeep.insert(key: "boolean", value: true);
780 inner.insert(key: "nested", value: twoDeep);
781 outer.insert(key: "nested", value: inner);
782 QCOMPARE(outer.value("nested").toObject().value("nested").toObject(), twoDeep);
783 QCOMPARE(outer.value("nested").toObject().value("nested").toObject().value("boolean").toBool(),
784 true);
785}
786
787void tst_QtJson::testArrayNested()
788{
789 QJsonArray inner, outer;
790 inner.append(value: 999.);
791 outer.append(value: inner);
792
793 // if we don't modify the original JsonArray, value()
794 // should return the same array (non-detached).
795 QJsonArray value = outer.at(i: 0).toArray();
796 QCOMPARE(value, inner);
797 QCOMPARE(value.at(0).toDouble(), 999.);
798
799 // if we modify the original array, it should detach and not
800 // affect the nested array
801 inner.append(value: 555.);
802 value = outer.at(i: 0).toArray();
803 QVERIFY2(inner.size() != value.size(), "array should have detached");
804
805 // objects in arrays
806 QJsonObject object;
807 object.insert(key: "boolean", value: true);
808 outer.append(value: object);
809 QCOMPARE(outer.last().toObject(), object);
810 QCOMPARE(outer.last().toObject().value("boolean").toBool(), true);
811
812 // two deep arrays
813 QJsonArray twoDeep;
814 twoDeep.append(value: QJsonValue(QString::fromLatin1(str: "nested")));
815 inner.append(value: twoDeep);
816 outer.append(value: inner);
817 QCOMPARE(outer.last().toArray().last().toArray(), twoDeep);
818 QCOMPARE(outer.last().toArray().last().toArray().at(0).toString(), QString("nested"));
819}
820
821void tst_QtJson::testArrayNestedEmpty()
822{
823 QJsonObject object;
824 QJsonArray inner;
825 object.insert(key: "inner", value: inner);
826 QJsonValue val = object.value(key: "inner");
827 QJsonArray value = object.value(key: "inner").toArray();
828 QVERIFY(QJsonDocument(value).isArray());
829 QCOMPARE(value.size(), 0);
830 QCOMPARE(value, inner);
831 QCOMPARE(value.size(), 0);
832 object.insert(key: "count", value: 0.);
833 QCOMPARE(object.value("inner").toArray().size(), 0);
834 QVERIFY(object.value("inner").toArray().isEmpty());
835 QJsonDocument(object).toBinaryData();
836 QCOMPARE(object.value("inner").toArray().size(), 0);
837}
838
839void tst_QtJson::testObjectNestedEmpty()
840{
841 QJsonObject object;
842 QJsonObject inner;
843 QJsonObject inner2;
844 object.insert(key: "inner", value: inner);
845 object.insert(key: "inner2", value: inner2);
846 QJsonObject value = object.value(key: "inner").toObject();
847 QVERIFY(QJsonDocument(value).isObject());
848 QCOMPARE(value.size(), 0);
849 QCOMPARE(value, inner);
850 QCOMPARE(value.size(), 0);
851 object.insert(key: "count", value: 0.);
852 QCOMPARE(object.value("inner").toObject().size(), 0);
853 QCOMPARE(object.value("inner").type(), QJsonValue::Object);
854 QJsonDocument(object).toBinaryData();
855 QVERIFY(object.value("inner").toObject().isEmpty());
856 QVERIFY(object.value("inner2").toObject().isEmpty());
857 QJsonDocument doc = QJsonDocument::fromBinaryData(data: QJsonDocument(object).toBinaryData());
858 QVERIFY(!doc.isNull());
859 QJsonObject reconstituted(doc.object());
860 QCOMPARE(reconstituted.value("inner").toObject().size(), 0);
861 QCOMPARE(reconstituted.value("inner").type(), QJsonValue::Object);
862 QCOMPARE(reconstituted.value("inner2").type(), QJsonValue::Object);
863}
864
865void tst_QtJson::testArrayComfortOperators()
866{
867 QJsonArray first;
868 first.append(value: 123.);
869 first.append(value: QLatin1String("foo"));
870
871 QJsonArray second = QJsonArray() << 123. << QLatin1String("foo");
872 QCOMPARE(first, second);
873
874 first = first + QLatin1String("bar");
875 second += QLatin1String("bar");
876 QCOMPARE(first, second);
877}
878
879void tst_QtJson::testValueRef()
880{
881 QJsonArray array;
882 array.append(value: 1.);
883 array.append(value: 2.);
884 array.append(value: 3.);
885 array.append(value: 4);
886 array.append(value: 4.1);
887 array[1] = false;
888
889 QCOMPARE(array.size(), 5);
890 QCOMPARE(array.at(0).toDouble(), 1.);
891 QCOMPARE(array.at(2).toDouble(), 3.);
892 QCOMPARE(array.at(3).toInt(), 4);
893 QCOMPARE(array.at(4).toInt(), 0);
894 QCOMPARE(array.at(1).type(), QJsonValue::Bool);
895 QCOMPARE(array.at(1).toBool(), false);
896
897 QJsonObject object;
898 object[QLatin1String("key")] = true;
899 QCOMPARE(object.size(), 1);
900 object.insert(key: QLatin1String("null"), value: QJsonValue());
901 QCOMPARE(object.value(QLatin1String("null")), QJsonValue());
902 object[QLatin1String("null")] = 100.;
903 QCOMPARE(object.value(QLatin1String("null")).type(), QJsonValue::Double);
904 QJsonValue val = qAsConst(t&: object)[QLatin1String("null")];
905 QCOMPARE(val.toDouble(), 100.);
906 QCOMPARE(object.size(), 2);
907
908 array[1] = array[2] = object[QLatin1String("key")] = 42;
909 QCOMPARE(array[1], array[2]);
910 QCOMPARE(array[2], object[QLatin1String("key")]);
911 QCOMPARE(object.value(QLatin1String("key")), QJsonValue(42));
912}
913
914void tst_QtJson::testValueRefComparison()
915{
916 QJsonValue a0 = 42.;
917 QJsonValue a1 = QStringLiteral("142");
918
919#define CHECK_IMPL(lhs, rhs, ineq) \
920 QCOMPARE(lhs, rhs); \
921 QVERIFY(!(lhs != rhs)); \
922 QVERIFY(lhs != ineq); \
923 QVERIFY(!(lhs == ineq)); \
924 QVERIFY(ineq != rhs); \
925 QVERIFY(!(ineq == rhs)); \
926 /* end */
927
928#define CHECK(lhs, rhs, ineq) \
929 do { \
930 CHECK_IMPL(lhs, rhs, ineq) \
931 CHECK_IMPL(qAsConst(lhs), rhs, ineq) \
932 CHECK_IMPL(lhs, qAsConst(rhs), ineq) \
933 CHECK_IMPL(qAsConst(lhs), qAsConst(rhs), ineq) \
934 } while (0)
935
936 // check that the (in)equality operators aren't ambiguous in C++20:
937 QJsonArray a = {a0, a1};
938
939 Q_STATIC_ASSERT((std::is_same<decltype(a[0]), QJsonValueRef>::value));
940
941 auto r0 = a.begin()[0];
942 auto r1 = a.begin()[1];
943 auto c0 = qAsConst(t&: a).begin()[0];
944 // ref <> ref
945 CHECK(r0, r0, r1);
946 // cref <> ref
947 CHECK(c0, r0, r1);
948 // ref <> cref
949 CHECK(r0, c0, r1);
950 // ref <> val
951 CHECK(r0, a0, r1);
952 // cref <> val
953 CHECK(c0, a0, r1);
954 // val <> ref
955 CHECK(a0, r0, a1);
956 // val <> cref
957 CHECK(a0, c0, a1);
958 // val <> val
959 CHECK(a0, a0, a1);
960
961#undef CHECK
962#undef CHECK_IMPL
963}
964
965void tst_QtJson::testObjectIteration()
966{
967 QJsonObject object;
968
969 for (QJsonObject::iterator it = object.begin(); it != object.end(); ++it)
970 QVERIFY(false);
971
972 const QString property = "kkk";
973 object.insert(key: property, value: 11);
974 object.take(key: property);
975 for (QJsonObject::iterator it = object.begin(); it != object.end(); ++it)
976 QVERIFY(false);
977
978 for (int i = 0; i < 10; ++i)
979 object[QString::number(i)] = (double)i;
980
981 QCOMPARE(object.size(), 10);
982
983 QCOMPARE(object.begin()->toDouble(), object.constBegin()->toDouble());
984
985 for (QJsonObject::iterator it = object.begin(); it != object.end(); ++it) {
986 QJsonValue value = it.value();
987 QCOMPARE((double)it.key().toInt(), value.toDouble());
988 }
989
990 {
991 QJsonObject object2 = object;
992 QCOMPARE(object, object2);
993
994 QJsonValue val = *object2.begin();
995 object2.erase(it: object2.begin());
996 QCOMPARE(object.size(), 10);
997 QCOMPARE(object2.size(), 9);
998
999 for (QJsonObject::const_iterator it = object2.constBegin(); it != object2.constEnd(); ++it) {
1000 QJsonValue value = it.value();
1001 QVERIFY(it.value() != val);
1002 QCOMPARE((double)it.key().toInt(), value.toDouble());
1003 }
1004 }
1005
1006 {
1007 QJsonObject object2 = object;
1008 QCOMPARE(object, object2);
1009
1010 QJsonObject::iterator it = object2.find(key: QString::number(5));
1011 QJsonValue val = *it;
1012 object2.erase(it);
1013 QCOMPARE(object.size(), 10);
1014 QCOMPARE(object2.size(), 9);
1015
1016 for (QJsonObject::const_iterator it = object2.constBegin(); it != object2.constEnd(); ++it) {
1017 QJsonValue value = it.value();
1018 QVERIFY(it.value() != val);
1019 QCOMPARE((double)it.key().toInt(), value.toDouble());
1020 }
1021 }
1022
1023 {
1024 QJsonObject::Iterator it = object.begin();
1025 it += 5;
1026 QCOMPARE(QJsonValue(it.value()).toDouble(), 5.);
1027 it -= 3;
1028 QCOMPARE(QJsonValue(it.value()).toDouble(), 2.);
1029 QJsonObject::Iterator it2 = it + 5;
1030 QCOMPARE(QJsonValue(it2.value()).toDouble(), 7.);
1031 it2 = it - 1;
1032 QCOMPARE(QJsonValue(it2.value()).toDouble(), 1.);
1033 }
1034
1035 {
1036 QJsonObject::ConstIterator it = object.constBegin();
1037 it += 5;
1038 QCOMPARE(QJsonValue(it.value()).toDouble(), 5.);
1039 it -= 3;
1040 QCOMPARE(QJsonValue(it.value()).toDouble(), 2.);
1041 QJsonObject::ConstIterator it2 = it + 5;
1042 QCOMPARE(QJsonValue(it2.value()).toDouble(), 7.);
1043 it2 = it - 1;
1044 QCOMPARE(QJsonValue(it2.value()).toDouble(), 1.);
1045 }
1046
1047 QJsonObject::Iterator it = object.begin();
1048 while (!object.isEmpty())
1049 it = object.erase(it);
1050 QCOMPARE(object.size() , 0);
1051 QCOMPARE(it, object.end());
1052}
1053
1054void tst_QtJson::testArrayIteration()
1055{
1056 QJsonArray array;
1057 for (int i = 0; i < 10; ++i)
1058 array.append(value: i);
1059
1060 QCOMPARE(array.size(), 10);
1061
1062 int i = 0;
1063 for (QJsonArray::iterator it = array.begin(); it != array.end(); ++it, ++i) {
1064 QJsonValue value = (*it);
1065 QCOMPARE((double)i, value.toDouble());
1066 }
1067
1068 QCOMPARE(array.begin()->toDouble(), array.constBegin()->toDouble());
1069
1070 {
1071 QJsonArray array2 = array;
1072 QCOMPARE(array, array2);
1073
1074 QJsonValue val = *array2.begin();
1075 array2.erase(it: array2.begin());
1076 QCOMPARE(array.size(), 10);
1077 QCOMPARE(array2.size(), 9);
1078
1079 i = 1;
1080 for (QJsonArray::const_iterator it = array2.constBegin(); it != array2.constEnd(); ++it, ++i) {
1081 QJsonValue value = (*it);
1082 QCOMPARE((double)i, value.toDouble());
1083 }
1084 }
1085
1086 {
1087 QJsonArray::Iterator it = array.begin();
1088 it += 5;
1089 QCOMPARE(QJsonValue((*it)).toDouble(), 5.);
1090 it -= 3;
1091 QCOMPARE(QJsonValue((*it)).toDouble(), 2.);
1092 QJsonArray::Iterator it2 = it + 5;
1093 QCOMPARE(QJsonValue(*it2).toDouble(), 7.);
1094 it2 = it - 1;
1095 QCOMPARE(QJsonValue(*it2).toDouble(), 1.);
1096 }
1097
1098 {
1099 QJsonArray::ConstIterator it = array.constBegin();
1100 it += 5;
1101 QCOMPARE(QJsonValue((*it)).toDouble(), 5.);
1102 it -= 3;
1103 QCOMPARE(QJsonValue((*it)).toDouble(), 2.);
1104 QJsonArray::ConstIterator it2 = it + 5;
1105 QCOMPARE(QJsonValue(*it2).toDouble(), 7.);
1106 it2 = it - 1;
1107 QCOMPARE(QJsonValue(*it2).toDouble(), 1.);
1108 }
1109
1110 QJsonArray::Iterator it = array.begin();
1111 while (!array.isEmpty())
1112 it = array.erase(it);
1113 QCOMPARE(array.size() , 0);
1114 QCOMPARE(it, array.end());
1115}
1116
1117void tst_QtJson::testObjectFind()
1118{
1119 QJsonObject object;
1120 for (int i = 0; i < 10; ++i)
1121 object[QString::number(i)] = i;
1122
1123 QCOMPARE(object.size(), 10);
1124
1125 QJsonObject::iterator it = object.find(key: QLatin1String("1"));
1126 QCOMPARE((*it).toDouble(), 1.);
1127 it = object.find(key: QString("11"));
1128 QCOMPARE((*it).type(), QJsonValue::Undefined);
1129 QCOMPARE(it, object.end());
1130
1131 QJsonObject::const_iterator cit = object.constFind(key: QLatin1String("1"));
1132 QCOMPARE((*cit).toDouble(), 1.);
1133 cit = object.constFind(key: QString("11"));
1134 QCOMPARE((*it).type(), QJsonValue::Undefined);
1135 QCOMPARE(it, object.end());
1136}
1137
1138void tst_QtJson::testDocument()
1139{
1140 QJsonDocument doc;
1141 QCOMPARE(doc.isEmpty(), true);
1142 QCOMPARE(doc.isArray(), false);
1143 QCOMPARE(doc.isObject(), false);
1144
1145 QJsonObject object;
1146 doc.setObject(object);
1147 QCOMPARE(doc.isEmpty(), false);
1148 QCOMPARE(doc.isArray(), false);
1149 QCOMPARE(doc.isObject(), true);
1150
1151 object.insert(key: QLatin1String("Key"), value: QLatin1String("Value"));
1152 doc.setObject(object);
1153 QCOMPARE(doc.isEmpty(), false);
1154 QCOMPARE(doc.isArray(), false);
1155 QCOMPARE(doc.isObject(), true);
1156 QCOMPARE(doc.object(), object);
1157 QCOMPARE(doc.array(), QJsonArray());
1158
1159 doc = QJsonDocument();
1160 QCOMPARE(doc.isEmpty(), true);
1161 QCOMPARE(doc.isArray(), false);
1162 QCOMPARE(doc.isObject(), false);
1163
1164 QJsonArray array;
1165 doc.setArray(array);
1166 QCOMPARE(doc.isEmpty(), false);
1167 QCOMPARE(doc.isArray(), true);
1168 QCOMPARE(doc.isObject(), false);
1169
1170 array.append(value: QLatin1String("Value"));
1171 doc.setArray(array);
1172 QCOMPARE(doc.isEmpty(), false);
1173 QCOMPARE(doc.isArray(), true);
1174 QCOMPARE(doc.isObject(), false);
1175 QCOMPARE(doc.array(), array);
1176 QCOMPARE(doc.object(), QJsonObject());
1177
1178 QJsonObject outer;
1179 outer.insert(key: QLatin1String("outerKey"), value: 22);
1180 QJsonObject inner;
1181 inner.insert(key: QLatin1String("innerKey"), value: 42);
1182 outer.insert(key: QLatin1String("innter"), value: inner);
1183 QJsonArray innerArray;
1184 innerArray.append(value: 23);
1185 outer.insert(key: QLatin1String("innterArray"), value: innerArray);
1186
1187 QJsonDocument doc2(outer.value(key: QLatin1String("innter")).toObject());
1188 QVERIFY(doc2.object().contains(QLatin1String("innerKey")));
1189 QCOMPARE(doc2.object().value(QLatin1String("innerKey")), QJsonValue(42));
1190
1191 QJsonDocument doc3;
1192 doc3.setObject(outer.value(key: QLatin1String("innter")).toObject());
1193 QCOMPARE(doc3.isArray(), false);
1194 QCOMPARE(doc3.isObject(), true);
1195 QVERIFY(doc3.object().contains(QString("innerKey")));
1196 QCOMPARE(doc3.object().value(QLatin1String("innerKey")), QJsonValue(42));
1197
1198 QJsonDocument doc4(outer.value(key: QLatin1String("innterArray")).toArray());
1199 QCOMPARE(doc4.isArray(), true);
1200 QCOMPARE(doc4.isObject(), false);
1201 QCOMPARE(doc4.array().size(), 1);
1202 QCOMPARE(doc4.array().at(0), QJsonValue(23));
1203
1204 QJsonDocument doc5;
1205 doc5.setArray(outer.value(key: QLatin1String("innterArray")).toArray());
1206 QCOMPARE(doc5.isArray(), true);
1207 QCOMPARE(doc5.isObject(), false);
1208 QCOMPARE(doc5.array().size(), 1);
1209 QCOMPARE(doc5.array().at(0), QJsonValue(23));
1210}
1211
1212void tst_QtJson::nullValues()
1213{
1214 QJsonArray array;
1215 array.append(value: QJsonValue());
1216
1217 QCOMPARE(array.size(), 1);
1218 QCOMPARE(array.at(0), QJsonValue());
1219
1220 QJsonObject object;
1221 object.insert(key: QString("key"), value: QJsonValue());
1222 QCOMPARE(object.contains(QLatin1String("key")), true);
1223 QCOMPARE(object.size(), 1);
1224 QCOMPARE(object.value(QString("key")), QJsonValue());
1225}
1226
1227void tst_QtJson::nullArrays()
1228{
1229 QJsonArray nullArray;
1230 QJsonArray nonNull;
1231 nonNull.append(value: QLatin1String("bar"));
1232
1233 QCOMPARE(nullArray, QJsonArray());
1234 QVERIFY(nullArray != nonNull);
1235 QVERIFY(nonNull != nullArray);
1236
1237 QCOMPARE(nullArray.size(), 0);
1238 QCOMPARE(nullArray.takeAt(0), QJsonValue(QJsonValue::Undefined));
1239 QCOMPARE(nullArray.first(), QJsonValue(QJsonValue::Undefined));
1240 QCOMPARE(nullArray.last(), QJsonValue(QJsonValue::Undefined));
1241 nullArray.removeAt(i: 0);
1242 nullArray.removeAt(i: -1);
1243
1244 nullArray.append(value: QString("bar"));
1245 nullArray.removeAt(i: 0);
1246
1247 QCOMPARE(nullArray.size(), 0);
1248 QCOMPARE(nullArray.takeAt(0), QJsonValue(QJsonValue::Undefined));
1249 QCOMPARE(nullArray.first(), QJsonValue(QJsonValue::Undefined));
1250 QCOMPARE(nullArray.last(), QJsonValue(QJsonValue::Undefined));
1251 nullArray.removeAt(i: 0);
1252 nullArray.removeAt(i: -1);
1253}
1254
1255void tst_QtJson::nullObject()
1256{
1257 QJsonObject nullObject;
1258 QJsonObject nonNull;
1259 nonNull.insert(key: QLatin1String("foo"), value: QLatin1String("bar"));
1260
1261 QCOMPARE(nullObject, QJsonObject());
1262 QVERIFY(nullObject != nonNull);
1263 QVERIFY(nonNull != nullObject);
1264
1265 QCOMPARE(nullObject.size(), 0);
1266 QCOMPARE(nullObject.keys(), QStringList());
1267 nullObject.remove(key: "foo");
1268 QCOMPARE(nullObject, QJsonObject());
1269 QCOMPARE(nullObject.take("foo"), QJsonValue(QJsonValue::Undefined));
1270 QCOMPARE(nullObject.contains("foo"), false);
1271
1272 nullObject.insert(key: "foo", value: QString("bar"));
1273 nullObject.remove(key: "foo");
1274
1275 QCOMPARE(nullObject.size(), 0);
1276 QCOMPARE(nullObject.keys(), QStringList());
1277 nullObject.remove(key: "foo");
1278 QCOMPARE(nullObject, QJsonObject());
1279 QCOMPARE(nullObject.take("foo"), QJsonValue(QJsonValue::Undefined));
1280 QCOMPARE(nullObject.contains("foo"), false);
1281}
1282
1283void tst_QtJson::constNullObject()
1284{
1285 const QJsonObject nullObject;
1286 QJsonObject nonNull;
1287 nonNull.insert(key: QLatin1String("foo"), value: QLatin1String("bar"));
1288
1289 QCOMPARE(nullObject, QJsonObject());
1290 QVERIFY(nullObject != nonNull);
1291 QVERIFY(nonNull != nullObject);
1292
1293 QCOMPARE(nullObject.size(), 0);
1294 QCOMPARE(nullObject.keys(), QStringList());
1295 QCOMPARE(nullObject, QJsonObject());
1296 QCOMPARE(nullObject.contains("foo"), false);
1297 QCOMPARE(nullObject["foo"], QJsonValue(QJsonValue::Undefined));
1298}
1299
1300void tst_QtJson::keySorting_data()
1301{
1302 QTest::addColumn<QString>(name: "json");
1303 QTest::addColumn<QStringList>(name: "sortedKeys");
1304
1305 QStringList list = {"A", "B"};
1306 QTest::newRow(dataTag: "sorted-ascii-2") << R"({ "A": false, "B": true })" << list;
1307 const char *json = "{ \"B\": true, \"A\": false }";
1308 QTest::newRow(dataTag: "unsorted-ascii-2") << json << list;
1309
1310 list = QStringList{"A", "B", "C", "D", "E"};
1311 QTest::newRow(dataTag: "sorted-ascii-5") << R"({"A": 1, "B": 2, "C": 3, "D": 4, "E": 5})" << list;
1312 QTest::newRow(dataTag: "unsorted-ascii-5") << R"({"A": 1, "C": 3, "D": 4, "B": 2, "E": 5})" << list;
1313 QTest::newRow(dataTag: "inverse-sorted-ascii-5") << R"({"E": 5, "D": 4, "C": 3, "B": 2, "A": 1})" << list;
1314
1315 list = QStringList{"á", "é", "í", "ó", "ú"};
1316 QTest::newRow(dataTag: "sorted-latin1") << R"({"á": 1, "é": 2, "í": 3, "ó": 4, "ú": 5})" << list;
1317 QTest::newRow(dataTag: "unsorted-latin1") << R"({"á": 1, "í": 3, "ó": 4, "é": 2, "ú": 5})" << list;
1318 QTest::newRow(dataTag: "inverse-sorted-latin1") << R"({"ú": 5, "ó": 4, "í": 3, "é": 2, "á": 1})" << list;
1319
1320 QTest::newRow(dataTag: "sorted-escaped-latin1") << R"({"\u00e1": 1, "\u00e9": 2, "\u00ed": 3, "\u00f3": 4, "\u00fa": 5})" << list;
1321 QTest::newRow(dataTag: "unsorted-escaped-latin1") << R"({"\u00e1": 1, "\u00ed": 3, "\u00f3": 4, "\u00e9": 2, "\u00fa": 5})" << list;
1322 QTest::newRow(dataTag: "inverse-sorted-escaped-latin1") << R"({"\u00fa": 5, "\u00f3": 4, "\u00ed": 3, "\u00e9": 2, "\u00e1": 1})" << list;
1323
1324 list = QStringList{"A", "α", "Я", "€", "测"};
1325 QTest::newRow(dataTag: "sorted") << R"({"A": 1, "α": 2, "Я": 3, "€": 4, "测": 5})" << list;
1326 QTest::newRow(dataTag: "unsorted") << R"({"A": 1, "Я": 3, "€": 4, "α": 2, "测": 5})" << list;
1327 QTest::newRow(dataTag: "inverse-sorted") << R"({"测": 5, "€": 4, "Я": 3, "α": 2, "A": 1})" << list;
1328
1329 QTest::newRow(dataTag: "sorted-escaped") << R"({"A": 1, "\u03b1": 2, "\u042f": 3, "\u20ac": 4, "\u6d4b": 5})" << list;
1330 QTest::newRow(dataTag: "unsorted-escaped") << R"({"A": 1, "\u042f": 3, "\u20ac": 4, "\u03b1": 2, "\u6d4b": 5})" << list;
1331 QTest::newRow(dataTag: "inverse-sorted-escaped") << R"({"\u6d4b": 5, "\u20ac": 4, "\u042f": 3, "\u03b1": 2, "A": 1})" << list;
1332}
1333
1334void tst_QtJson::keySorting()
1335{
1336 QFETCH(QString, json);
1337 QFETCH(QStringList, sortedKeys);
1338 QJsonDocument doc = QJsonDocument::fromJson(json: json.toUtf8());
1339
1340 QCOMPARE(doc.isObject(), true);
1341
1342 QJsonObject o = doc.object();
1343 QCOMPARE(o.size(), sortedKeys.size());
1344 QCOMPARE(o.keys(), sortedKeys);
1345 QJsonObject::const_iterator it = o.constBegin();
1346 QStringList::const_iterator it2 = sortedKeys.constBegin();
1347 for ( ; it != o.constEnd(); ++it, ++it2)
1348 QCOMPARE(it.key(), *it2);
1349}
1350
1351void tst_QtJson::undefinedValues()
1352{
1353 QJsonObject object;
1354 object.insert(key: "Key", value: QJsonValue(QJsonValue::Undefined));
1355 QCOMPARE(object.size(), 0);
1356 object["Key"] = QJsonValue(QJsonValue::Undefined);
1357 QCOMPARE(object.size(), 0);
1358
1359 object.insert(key: "Key", value: QLatin1String("Value"));
1360 QCOMPARE(object.size(), 1);
1361 QCOMPARE(object.value("Key").type(), QJsonValue::String);
1362 QCOMPARE(object.value("foo").type(), QJsonValue::Undefined);
1363 object.insert(key: "Key", value: QJsonValue(QJsonValue::Undefined));
1364 QCOMPARE(object.size(), 0);
1365 QCOMPARE(object.value("Key").type(), QJsonValue::Undefined);
1366
1367 QJsonArray array;
1368 array.append(value: QJsonValue(QJsonValue::Undefined));
1369 QCOMPARE(array.size(), 1);
1370 QCOMPARE(array.at(0).type(), QJsonValue::Null);
1371
1372 QCOMPARE(array.at(1).type(), QJsonValue::Undefined);
1373 QCOMPARE(array.at(-1).type(), QJsonValue::Undefined);
1374}
1375
1376void tst_QtJson::fromVariant_data()
1377{
1378 QTest::addColumn<QVariant>(name: "variant");
1379 QTest::addColumn<QJsonValue>(name: "jsonvalue");
1380
1381 bool boolValue = true;
1382 int intValue = -1;
1383 uint uintValue = 1;
1384 long long longlongValue = -2;
1385 unsigned long long ulonglongValue = 2;
1386 float floatValue = 3.3f;
1387 double doubleValue = 4.4;
1388 QString stringValue("str");
1389
1390 QStringList stringList;
1391 stringList.append(t: stringValue);
1392 stringList.append(t: "str2");
1393 QJsonArray jsonArray_string;
1394 jsonArray_string.append(value: stringValue);
1395 jsonArray_string.append(value: "str2");
1396
1397 QVariantList variantList;
1398 variantList.append(t: boolValue);
1399 variantList.append(t: floatValue);
1400 variantList.append(t: doubleValue);
1401 variantList.append(t: stringValue);
1402 variantList.append(t: stringList);
1403 variantList.append(t: QVariant::fromValue(value: nullptr));
1404 variantList.append(t: QVariant());
1405 QJsonArray jsonArray_variant;
1406 jsonArray_variant.append(value: boolValue);
1407 jsonArray_variant.append(value: floatValue);
1408 jsonArray_variant.append(value: doubleValue);
1409 jsonArray_variant.append(value: stringValue);
1410 jsonArray_variant.append(value: jsonArray_string);
1411 jsonArray_variant.append(value: QJsonValue(QJsonValue::Null));
1412 jsonArray_variant.append(value: QJsonValue());
1413
1414 QVariantMap variantMap;
1415 variantMap["bool"] = boolValue;
1416 variantMap["float"] = floatValue;
1417 variantMap["string"] = stringValue;
1418 variantMap["array"] = variantList;
1419 variantMap["null"] = QVariant::fromValue(value: nullptr);
1420 variantMap["default"] = QVariant();
1421 QVariantHash variantHash;
1422 variantHash["bool"] = boolValue;
1423 variantHash["float"] = floatValue;
1424 variantHash["string"] = stringValue;
1425 variantHash["array"] = variantList;
1426 variantHash["null"] = QVariant::fromValue(value: nullptr);
1427 variantHash["default"] = QVariant();
1428 QJsonObject jsonObject;
1429 jsonObject["bool"] = boolValue;
1430 jsonObject["float"] = floatValue;
1431 jsonObject["string"] = stringValue;
1432 jsonObject["array"] = jsonArray_variant;
1433 jsonObject["null"] = QJsonValue::Null;
1434 jsonObject["default"] = QJsonValue();
1435
1436 QTest::newRow(dataTag: "default") << QVariant() << QJsonValue(QJsonValue::Null);
1437 QTest::newRow(dataTag: "nullptr") << QVariant::fromValue(value: nullptr) << QJsonValue(QJsonValue::Null);
1438 QTest::newRow(dataTag: "bool") << QVariant(boolValue) << QJsonValue(boolValue);
1439 QTest::newRow(dataTag: "int") << QVariant(intValue) << QJsonValue(intValue);
1440 QTest::newRow(dataTag: "uint") << QVariant(uintValue) << QJsonValue(static_cast<double>(uintValue));
1441 QTest::newRow(dataTag: "longlong") << QVariant(longlongValue) << QJsonValue(longlongValue);
1442 QTest::newRow(dataTag: "ulonglong") << QVariant(ulonglongValue) << QJsonValue(static_cast<double>(ulonglongValue));
1443 QTest::newRow(dataTag: "float") << QVariant(floatValue) << QJsonValue(floatValue);
1444 QTest::newRow(dataTag: "double") << QVariant(doubleValue) << QJsonValue(doubleValue);
1445 QTest::newRow(dataTag: "string") << QVariant(stringValue) << QJsonValue(stringValue);
1446 QTest::newRow(dataTag: "stringList") << QVariant(stringList) << QJsonValue(jsonArray_string);
1447 QTest::newRow(dataTag: "variantList") << QVariant(variantList) << QJsonValue(jsonArray_variant);
1448 QTest::newRow(dataTag: "variantMap") << QVariant(variantMap) << QJsonValue(jsonObject);
1449 QTest::newRow(dataTag: "variantHash") << QVariant(variantHash) << QJsonValue(jsonObject);
1450}
1451
1452// replaces QVariant() with QVariant(nullptr)
1453static QVariant normalizedVariant(const QVariant &v)
1454{
1455 switch (v.userType()) {
1456 case QMetaType::UnknownType:
1457 return QVariant::fromValue(value: nullptr);
1458 case QMetaType::QVariantList: {
1459 const QVariantList in = v.toList();
1460 QVariantList out;
1461 out.reserve(alloc: in.size());
1462 for (const QVariant &v : in)
1463 out << normalizedVariant(v);
1464 return out;
1465 }
1466 case QMetaType::QVariantMap: {
1467 const QVariantMap in = v.toMap();
1468 QVariantMap out;
1469 for (auto it = in.begin(); it != in.end(); ++it)
1470 out.insert(akey: it.key(), avalue: normalizedVariant(v: it.value()));
1471 return out;
1472 }
1473 case QMetaType::QVariantHash: {
1474 const QVariantHash in = v.toHash();
1475 QVariantHash out;
1476 for (auto it = in.begin(); it != in.end(); ++it)
1477 out.insert(akey: it.key(), avalue: normalizedVariant(v: it.value()));
1478 return out;
1479 }
1480
1481 default:
1482 return v;
1483 }
1484}
1485
1486void tst_QtJson::fromVariant()
1487{
1488 QFETCH( QVariant, variant );
1489 QFETCH( QJsonValue, jsonvalue );
1490
1491 QCOMPARE(QJsonValue::fromVariant(variant), jsonvalue);
1492 QCOMPARE(normalizedVariant(variant).toJsonValue(), jsonvalue);
1493}
1494
1495void tst_QtJson::fromVariantSpecial_data()
1496{
1497 QTest::addColumn<QVariant>(name: "variant");
1498 QTest::addColumn<QJsonValue>(name: "jsonvalue");
1499
1500 // Qt types with special encoding
1501 QTest::newRow(dataTag: "url") << QVariant(QUrl("https://example.com/\xc2\xa9 "))
1502 << QJsonValue("https://example.com/%C2%A9%20");
1503 QTest::newRow(dataTag: "uuid") << QVariant(QUuid(0x40c01df6, 0x1ad5, 0x4762, 0x9c, 0xfe, 0xfd, 0xba, 0xfa, 0xb5, 0xde, 0xf8))
1504 << QJsonValue("40c01df6-1ad5-4762-9cfe-fdbafab5def8");
1505}
1506
1507void tst_QtJson::fromVariantSpecial()
1508{
1509 QFETCH( QVariant, variant );
1510 QFETCH( QJsonValue, jsonvalue );
1511
1512 QCOMPARE(QJsonValue::fromVariant(variant), jsonvalue);
1513}
1514
1515void tst_QtJson::toVariant_data()
1516{
1517 fromVariant_data();
1518}
1519
1520void tst_QtJson::toVariant()
1521{
1522 QFETCH( QVariant, variant );
1523 QFETCH( QJsonValue, jsonvalue );
1524
1525 QCOMPARE(jsonvalue.toVariant(), normalizedVariant(variant));
1526}
1527
1528void tst_QtJson::fromVariantMap()
1529{
1530 QVariantMap map;
1531 map.insert(akey: QLatin1String("key1"), avalue: QLatin1String("value1"));
1532 map.insert(akey: QLatin1String("key2"), avalue: QLatin1String("value2"));
1533 QJsonObject object = QJsonObject::fromVariantMap(map);
1534 QCOMPARE(object.size(), 2);
1535 QCOMPARE(object.value(QLatin1String("key1")), QJsonValue(QLatin1String("value1")));
1536 QCOMPARE(object.value(QLatin1String("key2")), QJsonValue(QLatin1String("value2")));
1537
1538 QVariantList list;
1539 list.append(t: true);
1540 list.append(t: QVariant());
1541 list.append(t: 999.);
1542 list.append(t: QLatin1String("foo"));
1543 map.insert(akey: "list", avalue: list);
1544 object = QJsonObject::fromVariantMap(map);
1545 QCOMPARE(object.size(), 3);
1546 QCOMPARE(object.value(QLatin1String("key1")), QJsonValue(QLatin1String("value1")));
1547 QCOMPARE(object.value(QLatin1String("key2")), QJsonValue(QLatin1String("value2")));
1548 QCOMPARE(object.value(QLatin1String("list")).type(), QJsonValue::Array);
1549 QJsonArray array = object.value(key: QLatin1String("list")).toArray();
1550 QCOMPARE(array.size(), 4);
1551 QCOMPARE(array.at(0).type(), QJsonValue::Bool);
1552 QCOMPARE(array.at(0).toBool(), true);
1553 QCOMPARE(array.at(1).type(), QJsonValue::Null);
1554 QCOMPARE(array.at(2).type(), QJsonValue::Double);
1555 QCOMPARE(array.at(2).toDouble(), 999.);
1556 QCOMPARE(array.at(3).type(), QJsonValue::String);
1557 QCOMPARE(array.at(3).toString(), QLatin1String("foo"));
1558}
1559
1560void tst_QtJson::fromVariantHash()
1561{
1562 QVariantHash map;
1563 map.insert(akey: QLatin1String("key1"), avalue: QLatin1String("value1"));
1564 map.insert(akey: QLatin1String("key2"), avalue: QLatin1String("value2"));
1565 QJsonObject object = QJsonObject::fromVariantHash(map);
1566 QCOMPARE(object.size(), 2);
1567 QCOMPARE(object.value(QLatin1String("key1")), QJsonValue(QLatin1String("value1")));
1568 QCOMPARE(object.value(QLatin1String("key2")), QJsonValue(QLatin1String("value2")));
1569}
1570
1571void tst_QtJson::toVariantMap()
1572{
1573 QCOMPARE(QMetaType::Type(QJsonValue(QJsonObject()).toVariant().type()), QMetaType::QVariantMap); // QTBUG-32524
1574
1575 QJsonObject object;
1576 QVariantMap map = object.toVariantMap();
1577 QVERIFY(map.isEmpty());
1578
1579 object.insert(key: "Key", value: QString("Value"));
1580 object.insert(key: "null", value: QJsonValue());
1581 QJsonArray array;
1582 array.append(value: true);
1583 array.append(value: 999.);
1584 array.append(value: QLatin1String("string"));
1585 array.append(value: QJsonValue::Null);
1586 object.insert(key: "Array", value: array);
1587
1588 map = object.toVariantMap();
1589
1590 QCOMPARE(map.size(), 3);
1591 QCOMPARE(map.value("Key"), QVariant(QString("Value")));
1592 QCOMPARE(map.value("null"), QVariant::fromValue(nullptr));
1593 QCOMPARE(map.value("Array").type(), QVariant::List);
1594 QVariantList list = map.value(akey: "Array").toList();
1595 QCOMPARE(list.size(), 4);
1596 QCOMPARE(list.at(0), QVariant(true));
1597 QCOMPARE(list.at(1), QVariant(999.));
1598 QCOMPARE(list.at(2), QVariant(QLatin1String("string")));
1599 QCOMPARE(list.at(3), QVariant::fromValue(nullptr));
1600}
1601
1602void tst_QtJson::toVariantHash()
1603{
1604 QJsonObject object;
1605 QVariantHash hash = object.toVariantHash();
1606 QVERIFY(hash.isEmpty());
1607
1608 object.insert(key: "Key", value: QString("Value"));
1609 object.insert(key: "null", value: QJsonValue::Null);
1610 QJsonArray array;
1611 array.append(value: true);
1612 array.append(value: 999.);
1613 array.append(value: QLatin1String("string"));
1614 array.append(value: QJsonValue::Null);
1615 object.insert(key: "Array", value: array);
1616
1617 hash = object.toVariantHash();
1618
1619 QCOMPARE(hash.size(), 3);
1620 QCOMPARE(hash.value("Key"), QVariant(QString("Value")));
1621 QCOMPARE(hash.value("null"), QVariant::fromValue(nullptr));
1622 QCOMPARE(hash.value("Array").type(), QVariant::List);
1623 QVariantList list = hash.value(akey: "Array").toList();
1624 QCOMPARE(list.size(), 4);
1625 QCOMPARE(list.at(0), QVariant(true));
1626 QCOMPARE(list.at(1), QVariant(999.));
1627 QCOMPARE(list.at(2), QVariant(QLatin1String("string")));
1628 QCOMPARE(list.at(3), QVariant::fromValue(nullptr));
1629}
1630
1631void tst_QtJson::toVariantList()
1632{
1633 QCOMPARE(QMetaType::Type(QJsonValue(QJsonArray()).toVariant().type()), QMetaType::QVariantList); // QTBUG-32524
1634
1635 QJsonArray array;
1636 QVariantList list = array.toVariantList();
1637 QVERIFY(list.isEmpty());
1638
1639 array.append(value: QString("Value"));
1640 array.append(value: QJsonValue());
1641 QJsonArray inner;
1642 inner.append(value: true);
1643 inner.append(value: 999.);
1644 inner.append(value: QLatin1String("string"));
1645 inner.append(value: QJsonValue());
1646 array.append(value: inner);
1647
1648 list = array.toVariantList();
1649
1650 QCOMPARE(list.size(), 3);
1651 QCOMPARE(list[0], QVariant(QString("Value")));
1652 QCOMPARE(list[1], QVariant::fromValue(nullptr));
1653 QCOMPARE(list[2].type(), QVariant::List);
1654 QVariantList vlist = list[2].toList();
1655 QCOMPARE(vlist.size(), 4);
1656 QCOMPARE(vlist.at(0), QVariant(true));
1657 QCOMPARE(vlist.at(1), QVariant(999.));
1658 QCOMPARE(vlist.at(2), QVariant(QLatin1String("string")));
1659 QCOMPARE(vlist.at(3), QVariant::fromValue(nullptr));
1660}
1661
1662void tst_QtJson::toJson()
1663{
1664 // Test QJsonDocument::Indented format
1665 {
1666 QJsonObject object;
1667 object.insert(key: "\\Key\n", value: QString("Value"));
1668 object.insert(key: "null", value: QJsonValue());
1669 QJsonArray array;
1670 array.append(value: true);
1671 array.append(value: 999.);
1672 array.append(value: QLatin1String("string"));
1673 array.append(value: QJsonValue());
1674 array.append(value: QLatin1String("\\\a\n\r\b\tabcABC\""));
1675 object.insert(key: "Array", value: array);
1676
1677 QByteArray json = QJsonDocument(object).toJson();
1678
1679 QByteArray expected =
1680 "{\n"
1681 " \"Array\": [\n"
1682 " true,\n"
1683 " 999,\n"
1684 " \"string\",\n"
1685 " null,\n"
1686 " \"\\\\\\u0007\\n\\r\\b\\tabcABC\\\"\"\n"
1687 " ],\n"
1688 " \"\\\\Key\\n\": \"Value\",\n"
1689 " \"null\": null\n"
1690 "}\n";
1691 QCOMPARE(json, expected);
1692
1693 QJsonDocument doc;
1694 doc.setObject(object);
1695 json = doc.toJson();
1696 QCOMPARE(json, expected);
1697
1698 doc.setArray(array);
1699 json = doc.toJson();
1700 expected =
1701 "[\n"
1702 " true,\n"
1703 " 999,\n"
1704 " \"string\",\n"
1705 " null,\n"
1706 " \"\\\\\\u0007\\n\\r\\b\\tabcABC\\\"\"\n"
1707 "]\n";
1708 QCOMPARE(json, expected);
1709 }
1710
1711 // Test QJsonDocument::Compact format
1712 {
1713 QJsonObject object;
1714 object.insert(key: "\\Key\n", value: QString("Value"));
1715 object.insert(key: "null", value: QJsonValue());
1716 QJsonArray array;
1717 array.append(value: true);
1718 array.append(value: 999.);
1719 array.append(value: QLatin1String("string"));
1720 array.append(value: QJsonValue());
1721 array.append(value: QLatin1String("\\\a\n\r\b\tabcABC\""));
1722 object.insert(key: "Array", value: array);
1723
1724 QByteArray json = QJsonDocument(object).toJson(format: QJsonDocument::Compact);
1725 QByteArray expected =
1726 "{\"Array\":[true,999,\"string\",null,\"\\\\\\u0007\\n\\r\\b\\tabcABC\\\"\"],\"\\\\Key\\n\":\"Value\",\"null\":null}";
1727 QCOMPARE(json, expected);
1728
1729 QJsonDocument doc;
1730 doc.setObject(object);
1731 json = doc.toJson(format: QJsonDocument::Compact);
1732 QCOMPARE(json, expected);
1733
1734 doc.setArray(array);
1735 json = doc.toJson(format: QJsonDocument::Compact);
1736 expected = "[true,999,\"string\",null,\"\\\\\\u0007\\n\\r\\b\\tabcABC\\\"\"]";
1737 QCOMPARE(json, expected);
1738 }
1739}
1740
1741void tst_QtJson::toJsonSillyNumericValues()
1742{
1743 QJsonObject object;
1744 QJsonArray array;
1745 array.append(value: QJsonValue(std::numeric_limits<double>::infinity())); // encode to: null
1746 array.append(value: QJsonValue(-std::numeric_limits<double>::infinity())); // encode to: null
1747 array.append(value: QJsonValue(std::numeric_limits<double>::quiet_NaN())); // encode to: null
1748 object.insert(key: "Array", value: array);
1749
1750 QByteArray json = QJsonDocument(object).toJson();
1751
1752 QByteArray expected =
1753 "{\n"
1754 " \"Array\": [\n"
1755 " null,\n"
1756 " null,\n"
1757 " null\n"
1758 " ]\n"
1759 "}\n";
1760
1761 QCOMPARE(json, expected);
1762
1763 QJsonDocument doc;
1764 doc.setObject(object);
1765 json = doc.toJson();
1766 QCOMPARE(json, expected);
1767}
1768
1769void tst_QtJson::toJsonLargeNumericValues()
1770{
1771 QJsonObject object;
1772 QJsonArray array;
1773 array.append(value: QJsonValue(1.234567)); // actual precision bug in Qt 5.0.0
1774 array.append(value: QJsonValue(1.7976931348623157e+308)); // JS Number.MAX_VALUE
1775 array.append(value: QJsonValue(5e-324)); // JS Number.MIN_VALUE
1776 array.append(value: QJsonValue(std::numeric_limits<double>::min()));
1777 array.append(value: QJsonValue(std::numeric_limits<double>::max()));
1778 array.append(value: QJsonValue(std::numeric_limits<double>::epsilon()));
1779 array.append(value: QJsonValue(std::numeric_limits<double>::denorm_min()));
1780 array.append(value: QJsonValue(0.0));
1781 array.append(value: QJsonValue(-std::numeric_limits<double>::min()));
1782 array.append(value: QJsonValue(-std::numeric_limits<double>::max()));
1783 array.append(value: QJsonValue(-std::numeric_limits<double>::epsilon()));
1784 array.append(value: QJsonValue(-std::numeric_limits<double>::denorm_min()));
1785 array.append(value: QJsonValue(-0.0));
1786 array.append(value: QJsonValue(9007199254740992LL)); // JS Number max integer
1787 array.append(value: QJsonValue(-9007199254740992LL)); // JS Number min integer
1788 object.insert(key: "Array", value: array);
1789
1790 QByteArray json = QJsonDocument(object).toJson();
1791
1792 QByteArray expected =
1793 "{\n"
1794 " \"Array\": [\n"
1795 " 1.234567,\n"
1796 " 1.7976931348623157e+308,\n"
1797#ifdef QT_NO_DOUBLECONVERSION // "shortest" double conversion is not very short then
1798 " 4.9406564584124654e-324,\n"
1799 " 2.2250738585072014e-308,\n"
1800 " 1.7976931348623157e+308,\n"
1801 " 2.2204460492503131e-16,\n"
1802 " 4.9406564584124654e-324,\n"
1803 " 0,\n"
1804 " -2.2250738585072014e-308,\n"
1805 " -1.7976931348623157e+308,\n"
1806 " -2.2204460492503131e-16,\n"
1807 " -4.9406564584124654e-324,\n"
1808#else
1809 " 5e-324,\n"
1810 " 2.2250738585072014e-308,\n"
1811 " 1.7976931348623157e+308,\n"
1812 " 2.220446049250313e-16,\n"
1813 " 5e-324,\n"
1814 " 0,\n"
1815 " -2.2250738585072014e-308,\n"
1816 " -1.7976931348623157e+308,\n"
1817 " -2.220446049250313e-16,\n"
1818 " -5e-324,\n"
1819#endif
1820 " 0,\n"
1821 " 9007199254740992,\n"
1822 " -9007199254740992\n"
1823 " ]\n"
1824 "}\n";
1825
1826#ifdef Q_OS_QNX
1827 QEXPECT_FAIL("", "See QTBUG-37066", Continue);
1828#endif
1829 QCOMPARE(json, expected);
1830
1831 QJsonDocument doc;
1832 doc.setObject(object);
1833 json = doc.toJson();
1834#ifdef Q_OS_QNX
1835 QEXPECT_FAIL("", "See QTBUG-37066", Continue);
1836#endif
1837 QCOMPARE(json, expected);
1838}
1839
1840void tst_QtJson::fromJson()
1841{
1842 {
1843 QByteArray json = "[\n true\n]\n";
1844 QJsonDocument doc = QJsonDocument::fromJson(json);
1845 QVERIFY(!doc.isEmpty());
1846 QCOMPARE(doc.isArray(), true);
1847 QCOMPARE(doc.isObject(), false);
1848 QJsonArray array = doc.array();
1849 QCOMPARE(array.size(), 1);
1850 QCOMPARE(array.at(0).type(), QJsonValue::Bool);
1851 QCOMPARE(array.at(0).toBool(), true);
1852 QCOMPARE(doc.toJson(), json);
1853 }
1854 {
1855 //regression test: test if unicode_control_characters are correctly decoded
1856 QByteArray json = "[\n \"" UNICODE_NON_CHARACTER "\"\n]\n";
1857 QJsonDocument doc = QJsonDocument::fromJson(json);
1858 QVERIFY(!doc.isEmpty());
1859 QCOMPARE(doc.isArray(), true);
1860 QCOMPARE(doc.isObject(), false);
1861 QJsonArray array = doc.array();
1862 QCOMPARE(array.size(), 1);
1863 QCOMPARE(array.at(0).type(), QJsonValue::String);
1864 QCOMPARE(array.at(0).toString(), QString::fromUtf8(UNICODE_NON_CHARACTER));
1865 QCOMPARE(doc.toJson(), json);
1866 }
1867 {
1868 QByteArray json = "[]";
1869 QJsonDocument doc = QJsonDocument::fromJson(json);
1870 QVERIFY(!doc.isEmpty());
1871 QCOMPARE(doc.isArray(), true);
1872 QCOMPARE(doc.isObject(), false);
1873 QJsonArray array = doc.array();
1874 QCOMPARE(array.size(), 0);
1875 }
1876 {
1877 QByteArray json = "{}";
1878 QJsonDocument doc = QJsonDocument::fromJson(json);
1879 QVERIFY(!doc.isEmpty());
1880 QCOMPARE(doc.isArray(), false);
1881 QCOMPARE(doc.isObject(), true);
1882 QJsonObject object = doc.object();
1883 QCOMPARE(object.size(), 0);
1884 }
1885 {
1886 QByteArray json = "{\n \"Key\": true\n}\n";
1887 QJsonDocument doc = QJsonDocument::fromJson(json);
1888 QVERIFY(!doc.isEmpty());
1889 QCOMPARE(doc.isArray(), false);
1890 QCOMPARE(doc.isObject(), true);
1891 QJsonObject object = doc.object();
1892 QCOMPARE(object.size(), 1);
1893 QCOMPARE(object.value("Key"), QJsonValue(true));
1894 QCOMPARE(doc.toJson(), json);
1895 }
1896 {
1897 QByteArray json = "[ null, true, false, \"Foo\", 1, [], {} ]";
1898 QJsonDocument doc = QJsonDocument::fromJson(json);
1899 QVERIFY(!doc.isEmpty());
1900 QCOMPARE(doc.isArray(), true);
1901 QCOMPARE(doc.isObject(), false);
1902 QJsonArray array = doc.array();
1903 QCOMPARE(array.size(), 7);
1904 QCOMPARE(array.at(0).type(), QJsonValue::Null);
1905 QCOMPARE(array.at(1).type(), QJsonValue::Bool);
1906 QCOMPARE(array.at(1).toBool(), true);
1907 QCOMPARE(array.at(2).type(), QJsonValue::Bool);
1908 QCOMPARE(array.at(2).toBool(), false);
1909 QCOMPARE(array.at(3).type(), QJsonValue::String);
1910 QCOMPARE(array.at(3).toString(), QLatin1String("Foo"));
1911 QCOMPARE(array.at(4).type(), QJsonValue::Double);
1912 QCOMPARE(array.at(4).toDouble(), 1.);
1913 QCOMPARE(array.at(5).type(), QJsonValue::Array);
1914 QCOMPARE(array.at(5).toArray().size(), 0);
1915 QCOMPARE(array.at(6).type(), QJsonValue::Object);
1916 QCOMPARE(array.at(6).toObject().size(), 0);
1917 }
1918 {
1919 QByteArray json = "{ \"0\": null, \"1\": true, \"2\": false, \"3\": \"Foo\", \"4\": 1, \"5\": [], \"6\": {} }";
1920 QJsonDocument doc = QJsonDocument::fromJson(json);
1921 QVERIFY(!doc.isEmpty());
1922 QCOMPARE(doc.isArray(), false);
1923 QCOMPARE(doc.isObject(), true);
1924 QJsonObject object = doc.object();
1925 QCOMPARE(object.size(), 7);
1926 QCOMPARE(object.value("0").type(), QJsonValue::Null);
1927 QCOMPARE(object.value("1").type(), QJsonValue::Bool);
1928 QCOMPARE(object.value("1").toBool(), true);
1929 QCOMPARE(object.value("2").type(), QJsonValue::Bool);
1930 QCOMPARE(object.value("2").toBool(), false);
1931 QCOMPARE(object.value("3").type(), QJsonValue::String);
1932 QCOMPARE(object.value("3").toString(), QLatin1String("Foo"));
1933 QCOMPARE(object.value("4").type(), QJsonValue::Double);
1934 QCOMPARE(object.value("4").toDouble(), 1.);
1935 QCOMPARE(object.value("5").type(), QJsonValue::Array);
1936 QCOMPARE(object.value("5").toArray().size(), 0);
1937 QCOMPARE(object.value("6").type(), QJsonValue::Object);
1938 QCOMPARE(object.value("6").toObject().size(), 0);
1939 }
1940 {
1941 QByteArray compactJson = "{\"Array\": [true,999,\"string\",null,\"\\\\\\u0007\\n\\r\\b\\tabcABC\\\"\"],\"\\\\Key\\n\": \"Value\",\"null\": null}";
1942 QJsonDocument doc = QJsonDocument::fromJson(json: compactJson);
1943 QVERIFY(!doc.isEmpty());
1944 QCOMPARE(doc.isArray(), false);
1945 QCOMPARE(doc.isObject(), true);
1946 QJsonObject object = doc.object();
1947 QCOMPARE(object.size(), 3);
1948 QCOMPARE(object.value("\\Key\n").isString(), true);
1949 QCOMPARE(object.value("\\Key\n").toString(), QString("Value"));
1950 QCOMPARE(object.value("null").isNull(), true);
1951 QCOMPARE(object.value("Array").isArray(), true);
1952 QJsonArray array = object.value(key: "Array").toArray();
1953 QCOMPARE(array.size(), 5);
1954 QCOMPARE(array.at(0).isBool(), true);
1955 QCOMPARE(array.at(0).toBool(), true);
1956 QCOMPARE(array.at(1).isDouble(), true);
1957 QCOMPARE(array.at(1).toDouble(), 999.);
1958 QCOMPARE(array.at(2).isString(), true);
1959 QCOMPARE(array.at(2).toString(), QLatin1String("string"));
1960 QCOMPARE(array.at(3).isNull(), true);
1961 QCOMPARE(array.at(4).isString(), true);
1962 QCOMPARE(array.at(4).toString(), QLatin1String("\\\a\n\r\b\tabcABC\""));
1963 }
1964}
1965
1966void tst_QtJson::fromJsonErrors()
1967{
1968 {
1969 QJsonParseError error;
1970 QByteArray json = "{\n \n\n";
1971 QJsonDocument doc = QJsonDocument::fromJson(json, error: &error);
1972 QVERIFY(doc.isEmpty());
1973 QCOMPARE(error.error, QJsonParseError::UnterminatedObject);
1974 QCOMPARE(error.offset, 8);
1975 }
1976 {
1977 QJsonParseError error;
1978 QByteArray json = "{\n \"key\" 10\n";
1979 QJsonDocument doc = QJsonDocument::fromJson(json, error: &error);
1980 QVERIFY(doc.isEmpty());
1981 QCOMPARE(error.error, QJsonParseError::MissingNameSeparator);
1982 QCOMPARE(error.offset, 13);
1983 }
1984 {
1985 QJsonParseError error;
1986 QByteArray json = "[\n \n\n";
1987 QJsonDocument doc = QJsonDocument::fromJson(json, error: &error);
1988 QVERIFY(doc.isEmpty());
1989 QCOMPARE(error.error, QJsonParseError::UnterminatedArray);
1990 QCOMPARE(error.offset, 8);
1991 }
1992 {
1993 QJsonParseError error;
1994 QByteArray json = "[\n 1, true\n\n";
1995 QJsonDocument doc = QJsonDocument::fromJson(json, error: &error);
1996 QVERIFY(doc.isEmpty());
1997 QCOMPARE(error.error, QJsonParseError::UnterminatedArray);
1998 QCOMPARE(error.offset, 14);
1999 }
2000 {
2001 QJsonParseError error;
2002 QByteArray json = "[\n 1 true\n\n";
2003 QJsonDocument doc = QJsonDocument::fromJson(json, error: &error);
2004 QVERIFY(doc.isEmpty());
2005 QCOMPARE(error.error, QJsonParseError::MissingValueSeparator);
2006 QCOMPARE(error.offset, 7);
2007 }
2008 {
2009 QJsonParseError error;
2010 QByteArray json = "[\n nul";
2011 QJsonDocument doc = QJsonDocument::fromJson(json, error: &error);
2012 QVERIFY(doc.isEmpty());
2013 QCOMPARE(error.error, QJsonParseError::IllegalValue);
2014 QCOMPARE(error.offset, 7);
2015 }
2016 {
2017 QJsonParseError error;
2018 QByteArray json = "[\n nulzz";
2019 QJsonDocument doc = QJsonDocument::fromJson(json, error: &error);
2020 QVERIFY(doc.isEmpty());
2021 QCOMPARE(error.error, QJsonParseError::IllegalValue);
2022 QCOMPARE(error.offset, 10);
2023 }
2024 {
2025 QJsonParseError error;
2026 QByteArray json = "[\n tru";
2027 QJsonDocument doc = QJsonDocument::fromJson(json, error: &error);
2028 QVERIFY(doc.isEmpty());
2029 QCOMPARE(error.error, QJsonParseError::IllegalValue);
2030 QCOMPARE(error.offset, 7);
2031 }
2032 {
2033 QJsonParseError error;
2034 QByteArray json = "[\n trud]";
2035 QJsonDocument doc = QJsonDocument::fromJson(json, error: &error);
2036 QVERIFY(doc.isEmpty());
2037 QCOMPARE(error.error, QJsonParseError::IllegalValue);
2038 QCOMPARE(error.offset, 10);
2039 }
2040 {
2041 QJsonParseError error;
2042 QByteArray json = "[\n fal";
2043 QJsonDocument doc = QJsonDocument::fromJson(json, error: &error);
2044 QVERIFY(doc.isEmpty());
2045 QCOMPARE(error.error, QJsonParseError::IllegalValue);
2046 QCOMPARE(error.offset, 7);
2047 }
2048 {
2049 QJsonParseError error;
2050 QByteArray json = "[\n falsd]";
2051 QJsonDocument doc = QJsonDocument::fromJson(json, error: &error);
2052 QVERIFY(doc.isEmpty());
2053 QCOMPARE(error.error, QJsonParseError::IllegalValue);
2054 QCOMPARE(error.offset, 11);
2055 }
2056 {
2057 QJsonParseError error;
2058 QByteArray json = "[\n 11111";
2059 QJsonDocument doc = QJsonDocument::fromJson(json, error: &error);
2060 QVERIFY(doc.isEmpty());
2061 QCOMPARE(error.error, QJsonParseError::TerminationByNumber);
2062 QCOMPARE(error.offset, 11);
2063 }
2064 {
2065 QJsonParseError error;
2066 QByteArray json = "[\n -1E10000]";
2067 QJsonDocument doc = QJsonDocument::fromJson(json, error: &error);
2068 QVERIFY(doc.isEmpty());
2069 QCOMPARE(error.error, QJsonParseError::IllegalNumber);
2070 QCOMPARE(error.offset, 14);
2071 }
2072 {
2073 QJsonParseError error;
2074 QByteArray json = "[\n -1e-10000]";
2075 QJsonDocument doc = QJsonDocument::fromJson(json, error: &error);
2076 QVERIFY(doc.isEmpty());
2077 QCOMPARE(error.error, QJsonParseError::IllegalNumber);
2078 QCOMPARE(error.offset, 15);
2079 }
2080 {
2081 QJsonParseError error;
2082 QByteArray json = "[\n \"\\u12\"]";
2083 QJsonDocument doc = QJsonDocument::fromJson(json, error: &error);
2084 QVERIFY(doc.isEmpty());
2085 QCOMPARE(error.error, QJsonParseError::IllegalEscapeSequence);
2086 QCOMPARE(error.offset, 11);
2087 }
2088 {
2089 QJsonParseError error;
2090 QByteArray json = "[\n \"foo" INVALID_UNICODE "bar\"]";
2091 QJsonDocument doc = QJsonDocument::fromJson(json, error: &error);
2092 QVERIFY(doc.isEmpty());
2093 QCOMPARE(error.error, QJsonParseError::IllegalUTF8String);
2094 QCOMPARE(error.offset, 12);
2095 }
2096 {
2097 QJsonParseError error;
2098 QByteArray json = "[\n \"";
2099 QJsonDocument doc = QJsonDocument::fromJson(json, error: &error);
2100 QVERIFY(doc.isEmpty());
2101 QCOMPARE(error.error, QJsonParseError::UnterminatedString);
2102 QCOMPARE(error.offset, 8);
2103 }
2104 {
2105 QJsonParseError error;
2106 QByteArray json = "[\n \"c" UNICODE_DJE "a\\u12\"]";
2107 QJsonDocument doc = QJsonDocument::fromJson(json, error: &error);
2108 QVERIFY(doc.isEmpty());
2109 QCOMPARE(error.error, QJsonParseError::IllegalEscapeSequence);
2110 QCOMPARE(error.offset, 15);
2111 }
2112 {
2113 QJsonParseError error;
2114 QByteArray json = "[\n \"c" UNICODE_DJE "a" INVALID_UNICODE "bar\"]";
2115 QJsonDocument doc = QJsonDocument::fromJson(json, error: &error);
2116 QVERIFY(doc.isEmpty());
2117 QCOMPARE(error.error, QJsonParseError::IllegalUTF8String);
2118 QCOMPARE(error.offset, 13);
2119 }
2120 {
2121 QJsonParseError error;
2122 QByteArray json = "[\n \"c" UNICODE_DJE "a ]";
2123 QJsonDocument doc = QJsonDocument::fromJson(json, error: &error);
2124 QVERIFY(doc.isEmpty());
2125 QCOMPARE(error.error, QJsonParseError::UnterminatedString);
2126 QCOMPARE(error.offset, 14);
2127 }
2128}
2129
2130void tst_QtJson::fromBinary()
2131{
2132 QFile file(testDataDir + "/test.json");
2133 file.open(flags: QFile::ReadOnly);
2134 QByteArray testJson = file.readAll();
2135
2136 QJsonDocument doc = QJsonDocument::fromJson(json: testJson);
2137 QJsonDocument outdoc = QJsonDocument::fromBinaryData(data: doc.toBinaryData());
2138 QVERIFY(!outdoc.isNull());
2139 QCOMPARE(doc, outdoc);
2140
2141 QFile bfile(testDataDir + "/test.bjson");
2142 bfile.open(flags: QFile::ReadOnly);
2143 QByteArray binary = bfile.readAll();
2144
2145 QJsonDocument bdoc = QJsonDocument::fromBinaryData(data: binary);
2146 QVERIFY(!bdoc.isNull());
2147 QCOMPARE(doc.toVariant(), bdoc.toVariant());
2148 QCOMPARE(doc, bdoc);
2149}
2150
2151void tst_QtJson::toAndFromBinary_data()
2152{
2153 QTest::addColumn<QString>(name: "filename");
2154 QTest::newRow(dataTag: "test.json") << (testDataDir + "/test.json");
2155 QTest::newRow(dataTag: "test2.json") << (testDataDir + "/test2.json");
2156}
2157
2158void tst_QtJson::toAndFromBinary()
2159{
2160 QFETCH(QString, filename);
2161 QFile file(filename);
2162 QVERIFY(file.open(QFile::ReadOnly));
2163 QByteArray data = file.readAll();
2164
2165 QJsonDocument doc = QJsonDocument::fromJson(json: data);
2166 QVERIFY(!doc.isNull());
2167 QJsonDocument outdoc = QJsonDocument::fromBinaryData(data: doc.toBinaryData());
2168 QVERIFY(!outdoc.isNull());
2169 QCOMPARE(doc, outdoc);
2170}
2171
2172void tst_QtJson::invalidBinaryData()
2173{
2174 QDir dir(testDataDir + "/invalidBinaryData");
2175 QFileInfoList files = dir.entryInfoList();
2176 for (int i = 0; i < files.size(); ++i) {
2177 if (!files.at(i).isFile())
2178 continue;
2179 QFile file(files.at(i).filePath());
2180 file.open(flags: QIODevice::ReadOnly);
2181 QByteArray bytes = file.readAll();
2182 bytes.squeeze();
2183 QJsonDocument document = QJsonDocument::fromRawData(data: bytes.constData(), size: bytes.size());
2184 QVERIFY(document.isNull());
2185 }
2186}
2187
2188void tst_QtJson::parseNumbers()
2189{
2190 {
2191 // test number parsing
2192 struct Numbers {
2193 const char *str;
2194 int n;
2195 };
2196 Numbers numbers [] = {
2197 { .str: "0", .n: 0 },
2198 { .str: "1", .n: 1 },
2199 { .str: "10", .n: 10 },
2200 { .str: "-1", .n: -1 },
2201 { .str: "100000", .n: 100000 },
2202 { .str: "-999", .n: -999 }
2203 };
2204 int size = sizeof(numbers)/sizeof(Numbers);
2205 for (int i = 0; i < size; ++i) {
2206 QByteArray json = "[ ";
2207 json += numbers[i].str;
2208 json += " ]";
2209 QJsonDocument doc = QJsonDocument::fromJson(json);
2210 QVERIFY(!doc.isEmpty());
2211 QCOMPARE(doc.isArray(), true);
2212 QCOMPARE(doc.isObject(), false);
2213 QJsonArray array = doc.array();
2214 QCOMPARE(array.size(), 1);
2215 QJsonValue val = array.at(i: 0);
2216 QCOMPARE(val.type(), QJsonValue::Double);
2217 QCOMPARE(val.toDouble(), (double)numbers[i].n);
2218 }
2219 }
2220 {
2221 // test number parsing
2222 struct Numbers {
2223 const char *str;
2224 double n;
2225 };
2226 Numbers numbers [] = {
2227 { .str: "0", .n: 0 },
2228 { .str: "1", .n: 1 },
2229 { .str: "10", .n: 10 },
2230 { .str: "-1", .n: -1 },
2231 { .str: "100000", .n: 100000 },
2232 { .str: "-999", .n: -999 },
2233 { .str: "1.1", .n: 1.1 },
2234 { .str: "1e10", .n: 1e10 },
2235 { .str: "-1.1", .n: -1.1 },
2236 { .str: "-1e10", .n: -1e10 },
2237 { .str: "-1E10", .n: -1e10 },
2238 { .str: "1.1e10", .n: 1.1e10 },
2239 { .str: "1.1e308", .n: 1.1e308 },
2240 { .str: "-1.1e308", .n: -1.1e308 },
2241 { .str: "1.1e-308", .n: 1.1e-308 },
2242 { .str: "-1.1e-308", .n: -1.1e-308 },
2243 { .str: "1.1e+308", .n: 1.1e+308 },
2244 { .str: "-1.1e+308", .n: -1.1e+308 },
2245 { .str: "1.e+308", .n: 1.e+308 },
2246 { .str: "-1.e+308", .n: -1.e+308 }
2247 };
2248 int size = sizeof(numbers)/sizeof(Numbers);
2249 for (int i = 0; i < size; ++i) {
2250 QByteArray json = "[ ";
2251 json += numbers[i].str;
2252 json += " ]";
2253 QJsonDocument doc = QJsonDocument::fromJson(json);
2254#ifdef Q_OS_QNX
2255 if (0 == QString::compare(numbers[i].str, "1.1e-308"))
2256 QEXPECT_FAIL("", "See QTBUG-37066", Abort);
2257#endif
2258 QVERIFY(!doc.isEmpty());
2259 QCOMPARE(doc.isArray(), true);
2260 QCOMPARE(doc.isObject(), false);
2261 QJsonArray array = doc.array();
2262 QCOMPARE(array.size(), 1);
2263 QJsonValue val = array.at(i: 0);
2264 QCOMPARE(val.type(), QJsonValue::Double);
2265 QCOMPARE(val.toDouble(), numbers[i].n);
2266 }
2267 }
2268}
2269
2270void tst_QtJson::parseStrings()
2271{
2272 const char *strings [] =
2273 {
2274 "Foo",
2275 "abc\\\"abc",
2276 "abc\\\\abc",
2277 "abc\\babc",
2278 "abc\\fabc",
2279 "abc\\nabc",
2280 "abc\\rabc",
2281 "abc\\tabc",
2282 "abc\\u0019abc",
2283 "abc" UNICODE_DJE "abc",
2284 UNICODE_NON_CHARACTER
2285 };
2286 int size = sizeof(strings)/sizeof(const char *);
2287
2288 for (int i = 0; i < size; ++i) {
2289 QByteArray json = "[\n \"";
2290 json += strings[i];
2291 json += "\"\n]\n";
2292 QJsonDocument doc = QJsonDocument::fromJson(json);
2293 QVERIFY(!doc.isEmpty());
2294 QCOMPARE(doc.isArray(), true);
2295 QCOMPARE(doc.isObject(), false);
2296 QJsonArray array = doc.array();
2297 QCOMPARE(array.size(), 1);
2298 QJsonValue val = array.at(i: 0);
2299 QCOMPARE(val.type(), QJsonValue::String);
2300
2301 QCOMPARE(doc.toJson(), json);
2302 }
2303
2304 struct Pairs {
2305 const char *in;
2306 const char *out;
2307 };
2308 Pairs pairs [] = {
2309 { .in: "abc\\/abc", .out: "abc/abc" },
2310 { .in: "abc\\u0402abc", .out: "abc" UNICODE_DJE "abc" },
2311 { .in: "abc\\u0065abc", .out: "abceabc" },
2312 { .in: "abc\\uFFFFabc", .out: "abc" UNICODE_NON_CHARACTER "abc" }
2313 };
2314 size = sizeof(pairs)/sizeof(Pairs);
2315
2316 for (int i = 0; i < size; ++i) {
2317 QByteArray json = "[\n \"";
2318 json += pairs[i].in;
2319 json += "\"\n]\n";
2320 QByteArray out = "[\n \"";
2321 out += pairs[i].out;
2322 out += "\"\n]\n";
2323 QJsonDocument doc = QJsonDocument::fromJson(json);
2324 QVERIFY(!doc.isEmpty());
2325 QCOMPARE(doc.isArray(), true);
2326 QCOMPARE(doc.isObject(), false);
2327 QJsonArray array = doc.array();
2328 QCOMPARE(array.size(), 1);
2329 QJsonValue val = array.at(i: 0);
2330 QCOMPARE(val.type(), QJsonValue::String);
2331
2332 QCOMPARE(doc.toJson(), out);
2333 }
2334
2335}
2336
2337void tst_QtJson::parseDuplicateKeys()
2338{
2339 const char *json = "{ \"B\": true, \"A\": null, \"B\": false }";
2340
2341 QJsonDocument doc = QJsonDocument::fromJson(json);
2342 QCOMPARE(doc.isObject(), true);
2343
2344 QJsonObject o = doc.object();
2345 QCOMPARE(o.size(), 2);
2346 QJsonObject::const_iterator it = o.constBegin();
2347 QCOMPARE(it.key(), QLatin1String("A"));
2348 QCOMPARE(it.value(), QJsonValue());
2349 ++it;
2350 QCOMPARE(it.key(), QLatin1String("B"));
2351 QCOMPARE(it.value(), QJsonValue(false));
2352}
2353
2354void tst_QtJson::testParser()
2355{
2356 QFile file(testDataDir + "/test.json");
2357 file.open(flags: QFile::ReadOnly);
2358 QByteArray testJson = file.readAll();
2359
2360 QJsonDocument doc = QJsonDocument::fromJson(json: testJson);
2361 QVERIFY(!doc.isEmpty());
2362}
2363
2364void tst_QtJson::compactArray()
2365{
2366 QJsonArray array;
2367 array.append(value: QLatin1String("First Entry"));
2368 array.append(value: QLatin1String("Second Entry"));
2369 array.append(value: QLatin1String("Third Entry"));
2370 QJsonDocument doc(array);
2371 int s = doc.toBinaryData().size();
2372 array.removeAt(i: 1);
2373 doc.setArray(array);
2374 QVERIFY(s > doc.toBinaryData().size());
2375 s = doc.toBinaryData().size();
2376 QCOMPARE(doc.toJson(),
2377 QByteArray("[\n"
2378 " \"First Entry\",\n"
2379 " \"Third Entry\"\n"
2380 "]\n"));
2381
2382 array.removeAt(i: 0);
2383 doc.setArray(array);
2384 QVERIFY(s > doc.toBinaryData().size());
2385 s = doc.toBinaryData().size();
2386 QCOMPARE(doc.toJson(),
2387 QByteArray("[\n"
2388 " \"Third Entry\"\n"
2389 "]\n"));
2390
2391 array.removeAt(i: 0);
2392 doc.setArray(array);
2393 QVERIFY(s > doc.toBinaryData().size());
2394 s = doc.toBinaryData().size();
2395 QCOMPARE(doc.toJson(),
2396 QByteArray("[\n"
2397 "]\n"));
2398
2399}
2400
2401void tst_QtJson::compactObject()
2402{
2403 QJsonObject object;
2404 object.insert(key: QLatin1String("Key1"), value: QLatin1String("First Entry"));
2405 object.insert(key: QLatin1String("Key2"), value: QLatin1String("Second Entry"));
2406 object.insert(key: QLatin1String("Key3"), value: QLatin1String("Third Entry"));
2407 QJsonDocument doc(object);
2408 int s = doc.toBinaryData().size();
2409 object.remove(key: QLatin1String("Key2"));
2410 doc.setObject(object);
2411 QVERIFY(s > doc.toBinaryData().size());
2412 s = doc.toBinaryData().size();
2413 QCOMPARE(doc.toJson(),
2414 QByteArray("{\n"
2415 " \"Key1\": \"First Entry\",\n"
2416 " \"Key3\": \"Third Entry\"\n"
2417 "}\n"));
2418
2419 object.remove(key: QLatin1String("Key1"));
2420 doc.setObject(object);
2421 QVERIFY(s > doc.toBinaryData().size());
2422 s = doc.toBinaryData().size();
2423 QCOMPARE(doc.toJson(),
2424 QByteArray("{\n"
2425 " \"Key3\": \"Third Entry\"\n"
2426 "}\n"));
2427
2428 object.remove(key: QLatin1String("Key3"));
2429 doc.setObject(object);
2430 QVERIFY(s > doc.toBinaryData().size());
2431 s = doc.toBinaryData().size();
2432 QCOMPARE(doc.toJson(),
2433 QByteArray("{\n"
2434 "}\n"));
2435
2436}
2437
2438void tst_QtJson::validation()
2439{
2440 // this basically tests that we don't crash on corrupt data
2441 QFile file(testDataDir + "/test.json");
2442 QVERIFY(file.open(QFile::ReadOnly));
2443 QByteArray testJson = file.readAll();
2444 QVERIFY(!testJson.isEmpty());
2445
2446 QJsonDocument doc = QJsonDocument::fromJson(json: testJson);
2447 QVERIFY(!doc.isNull());
2448
2449 QByteArray binary = doc.toBinaryData();
2450
2451 // only test the first 1000 bytes. Testing the full file takes too long
2452 for (int i = 0; i < 1000; ++i) {
2453 QByteArray corrupted = binary;
2454 corrupted[i] = char(0xff);
2455 QJsonDocument doc = QJsonDocument::fromBinaryData(data: corrupted);
2456 if (doc.isNull())
2457 continue;
2458 QByteArray json = doc.toJson();
2459 }
2460
2461
2462 QFile file2(testDataDir + "/test3.json");
2463 file2.open(flags: QFile::ReadOnly);
2464 testJson = file2.readAll();
2465 QVERIFY(!testJson.isEmpty());
2466
2467 doc = QJsonDocument::fromJson(json: testJson);
2468 QVERIFY(!doc.isNull());
2469
2470 binary = doc.toBinaryData();
2471
2472 for (int i = 0; i < binary.size(); ++i) {
2473 QByteArray corrupted = binary;
2474 corrupted[i] = char(0xff);
2475 QJsonDocument doc = QJsonDocument::fromBinaryData(data: corrupted);
2476 if (doc.isNull())
2477 continue;
2478 QByteArray json = doc.toJson();
2479
2480 corrupted = binary;
2481 corrupted[i] = 0x00;
2482 doc = QJsonDocument::fromBinaryData(data: corrupted);
2483 if (doc.isNull())
2484 continue;
2485 json = doc.toJson();
2486 }
2487}
2488
2489void tst_QtJson::assignToDocument()
2490{
2491 {
2492 const char *json = "{ \"inner\": { \"key\": true } }";
2493 QJsonDocument doc = QJsonDocument::fromJson(json);
2494
2495 QJsonObject o = doc.object();
2496 QJsonValue inner = o.value(key: "inner");
2497
2498 QJsonDocument innerDoc(inner.toObject());
2499
2500 QVERIFY(innerDoc != doc);
2501 QCOMPARE(innerDoc.object(), inner.toObject());
2502 }
2503 {
2504 const char *json = "[ [ true ] ]";
2505 QJsonDocument doc = QJsonDocument::fromJson(json);
2506
2507 QJsonArray a = doc.array();
2508 QJsonValue inner = a.at(i: 0);
2509
2510 QJsonDocument innerDoc(inner.toArray());
2511
2512 QVERIFY(innerDoc != doc);
2513 QCOMPARE(innerDoc.array(), inner.toArray());
2514 }
2515}
2516
2517
2518void tst_QtJson::testDuplicateKeys()
2519{
2520 QJsonObject obj;
2521 obj.insert(key: QLatin1String("foo"), value: QLatin1String("bar"));
2522 obj.insert(key: QLatin1String("foo"), value: QLatin1String("zap"));
2523 QCOMPARE(obj.size(), 1);
2524 QCOMPARE(obj.value(QLatin1String("foo")).toString(), QLatin1String("zap"));
2525}
2526
2527void tst_QtJson::testCompaction()
2528{
2529 // modify object enough times to trigger compactionCounter
2530 // and make sure the data is still valid
2531 QJsonObject obj;
2532 for (int i = 0; i < 33; ++i) {
2533 obj.remove(key: QLatin1String("foo"));
2534 obj.insert(key: QLatin1String("foo"), value: QLatin1String("bar"));
2535 }
2536 QCOMPARE(obj.size(), 1);
2537 QCOMPARE(obj.value(QLatin1String("foo")).toString(), QLatin1String("bar"));
2538
2539 QJsonDocument doc = QJsonDocument::fromBinaryData(data: QJsonDocument(obj).toBinaryData());
2540 QVERIFY(!doc.isNull());
2541 QVERIFY(!doc.isEmpty());
2542 QCOMPARE(doc.isArray(), false);
2543 QCOMPARE(doc.isObject(), true);
2544 QCOMPARE(doc.object(), obj);
2545}
2546
2547void tst_QtJson::testDebugStream()
2548{
2549 {
2550 // QJsonObject
2551
2552 QJsonObject object;
2553 QTest::ignoreMessage(type: QtDebugMsg, message: "QJsonObject()");
2554 qDebug() << object;
2555
2556 object.insert(key: QLatin1String("foo"), value: QLatin1String("bar"));
2557 QTest::ignoreMessage(type: QtDebugMsg, message: "QJsonObject({\"foo\":\"bar\"})");
2558 qDebug() << object;
2559 }
2560
2561 {
2562 // QJsonArray
2563
2564 QJsonArray array;
2565 QTest::ignoreMessage(type: QtDebugMsg, message: "QJsonArray()");
2566 qDebug() << array;
2567
2568 array.append(value: 1);
2569 array.append(value: QLatin1String("foo"));
2570 QTest::ignoreMessage(type: QtDebugMsg, message: "QJsonArray([1,\"foo\"])");
2571 qDebug() << array;
2572 }
2573
2574 {
2575 // QJsonDocument
2576
2577 QJsonDocument doc;
2578 QTest::ignoreMessage(type: QtDebugMsg, message: "QJsonDocument()");
2579 qDebug() << doc;
2580
2581 QJsonObject object;
2582 object.insert(key: QLatin1String("foo"), value: QLatin1String("bar"));
2583 doc.setObject(object);
2584 QTest::ignoreMessage(type: QtDebugMsg, message: "QJsonDocument({\"foo\":\"bar\"})");
2585 qDebug() << doc;
2586
2587 QJsonArray array;
2588 array.append(value: 1);
2589 array.append(value: QLatin1String("foo"));
2590 QTest::ignoreMessage(type: QtDebugMsg, message: "QJsonDocument([1,\"foo\"])");
2591 doc.setArray(array);
2592 qDebug() << doc;
2593 }
2594
2595 {
2596 // QJsonValue
2597
2598 QJsonValue value;
2599
2600 QTest::ignoreMessage(type: QtDebugMsg, message: "QJsonValue(null)");
2601 qDebug() << value;
2602
2603 value = QJsonValue(true); // bool
2604 QTest::ignoreMessage(type: QtDebugMsg, message: "QJsonValue(bool, true)");
2605 qDebug() << value;
2606
2607 value = QJsonValue((double)4.2); // double
2608 QTest::ignoreMessage(type: QtDebugMsg, message: "QJsonValue(double, 4.2)");
2609 qDebug() << value;
2610
2611 value = QJsonValue((int)42); // int
2612 QTest::ignoreMessage(type: QtDebugMsg, message: "QJsonValue(double, 42)");
2613 qDebug() << value;
2614
2615 value = QJsonValue(QLatin1String("foo")); // string
2616 QTest::ignoreMessage(type: QtDebugMsg, message: "QJsonValue(string, \"foo\")");
2617 qDebug() << value;
2618
2619 QJsonArray array;
2620 array.append(value: 1);
2621 array.append(value: QLatin1String("foo"));
2622 value = QJsonValue(array); // array
2623 QTest::ignoreMessage(type: QtDebugMsg, message: "QJsonValue(array, QJsonArray([1,\"foo\"]))");
2624 qDebug() << value;
2625
2626 QJsonObject object;
2627 object.insert(key: QLatin1String("foo"), value: QLatin1String("bar"));
2628 value = QJsonValue(object); // object
2629 QTest::ignoreMessage(type: QtDebugMsg, message: "QJsonValue(object, QJsonObject({\"foo\":\"bar\"}))");
2630 qDebug() << value;
2631 }
2632}
2633
2634void tst_QtJson::testCompactionError()
2635{
2636 QJsonObject schemaObject;
2637 schemaObject.insert(key: "_Type", value: QLatin1String("_SchemaType"));
2638 schemaObject.insert(key: "name", value: QLatin1String("Address"));
2639 schemaObject.insert(key: "schema", value: QJsonObject());
2640 {
2641 QJsonObject content(schemaObject);
2642 QJsonDocument doc(content);
2643 QVERIFY(!doc.isNull());
2644 QByteArray hash = QCryptographicHash::hash(data: doc.toBinaryData(), method: QCryptographicHash::Md5).toHex();
2645 schemaObject.insert(key: "_Version", value: QString::fromLatin1(str: hash.constData(), size: hash.size()));
2646 }
2647
2648 QJsonObject schema;
2649 schema.insert(key: "streetNumber", value: schema.value(key: "number").toObject());
2650 schemaObject.insert(key: "schema", value: schema);
2651 {
2652 QJsonObject content(schemaObject);
2653 content.remove(key: "_Uuid");
2654 content.remove(key: "_Version");
2655 QJsonDocument doc(content);
2656 QVERIFY(!doc.isNull());
2657 QByteArray hash = QCryptographicHash::hash(data: doc.toBinaryData(), method: QCryptographicHash::Md5).toHex();
2658 schemaObject.insert(key: "_Version", value: QString::fromLatin1(str: hash.constData(), size: hash.size()));
2659 }
2660}
2661
2662void tst_QtJson::parseUnicodeEscapes()
2663{
2664 const QByteArray json = "[ \"A\\u00e4\\u00C4\" ]";
2665
2666 QJsonDocument doc = QJsonDocument::fromJson(json);
2667 QJsonArray array = doc.array();
2668
2669 QString result = QLatin1String("A");
2670 result += QChar(0xe4);
2671 result += QChar(0xc4);
2672
2673 QCOMPARE(array.first().toString(), result);
2674}
2675
2676void tst_QtJson::assignObjects()
2677{
2678 const char *json =
2679 "[ { \"Key\": 1 }, { \"Key\": 2 } ]";
2680
2681 QJsonDocument doc = QJsonDocument::fromJson(json);
2682 QJsonArray array = doc.array();
2683
2684 QJsonObject object = array.at(i: 0).toObject();
2685 QCOMPARE(object.value("Key").toDouble(), 1.);
2686
2687 object = array.at(i: 1).toObject();
2688 QCOMPARE(object.value("Key").toDouble(), 2.);
2689}
2690
2691void tst_QtJson::assignArrays()
2692{
2693 const char *json =
2694 "[ [ 1 ], [ 2 ] ]";
2695
2696 QJsonDocument doc = QJsonDocument::fromJson(json);
2697 QJsonArray array = doc.array();
2698
2699 QJsonArray inner = array.at(i: 0).toArray() ;
2700 QCOMPARE(inner.at(0).toDouble(), 1.);
2701
2702 inner= array.at(i: 1).toArray();
2703 QCOMPARE(inner.at(0).toDouble(), 2.);
2704}
2705
2706void tst_QtJson::testTrailingComma()
2707{
2708 const char *jsons[] = { "{ \"Key\": 1, }", "[ { \"Key\": 1 }, ]" };
2709
2710 for (unsigned i = 0; i < sizeof(jsons)/sizeof(jsons[0]); ++i) {
2711 QJsonParseError error;
2712 QJsonDocument doc = QJsonDocument::fromJson(json: jsons[i], error: &error);
2713 QCOMPARE(error.error, QJsonParseError::MissingObject);
2714 }
2715}
2716
2717void tst_QtJson::testDetachBug()
2718{
2719 QJsonObject dynamic;
2720 QJsonObject embedded;
2721
2722 QJsonObject local;
2723
2724 embedded.insert(key: "Key1", value: QString("Value1"));
2725 embedded.insert(key: "Key2", value: QString("Value2"));
2726 dynamic.insert(QStringLiteral("Bogus"), value: QString("bogusValue"));
2727 dynamic.insert(key: "embedded", value: embedded);
2728 local = dynamic.value(key: "embedded").toObject();
2729
2730 dynamic.remove(key: "embedded");
2731
2732 QCOMPARE(local.keys().size(),2);
2733 local.remove(key: "Key1");
2734 local.remove(key: "Key2");
2735 QCOMPARE(local.keys().size(), 0);
2736
2737 local.insert(key: "Key1", value: QString("anotherValue"));
2738 QCOMPARE(local.keys().size(), 1);
2739}
2740
2741void tst_QtJson::valueEquals()
2742{
2743 QCOMPARE(QJsonValue(), QJsonValue());
2744 QVERIFY(QJsonValue() != QJsonValue(QJsonValue::Undefined));
2745 QVERIFY(QJsonValue() != QJsonValue(true));
2746 QVERIFY(QJsonValue() != QJsonValue(1.));
2747 QVERIFY(QJsonValue() != QJsonValue(QJsonArray()));
2748 QVERIFY(QJsonValue() != QJsonValue(QJsonObject()));
2749
2750 QCOMPARE(QJsonValue(true), QJsonValue(true));
2751 QVERIFY(QJsonValue(true) != QJsonValue(false));
2752 QVERIFY(QJsonValue(true) != QJsonValue(QJsonValue::Undefined));
2753 QVERIFY(QJsonValue(true) != QJsonValue());
2754 QVERIFY(QJsonValue(true) != QJsonValue(1.));
2755 QVERIFY(QJsonValue(true) != QJsonValue(QJsonArray()));
2756 QVERIFY(QJsonValue(true) != QJsonValue(QJsonObject()));
2757
2758 QCOMPARE(QJsonValue(1), QJsonValue(1));
2759 QVERIFY(QJsonValue(1) != QJsonValue(2));
2760 QCOMPARE(QJsonValue(1), QJsonValue(1.));
2761 QVERIFY(QJsonValue(1) != QJsonValue(1.1));
2762 QVERIFY(QJsonValue(1) != QJsonValue(QJsonValue::Undefined));
2763 QVERIFY(QJsonValue(1) != QJsonValue());
2764 QVERIFY(QJsonValue(1) != QJsonValue(true));
2765 QVERIFY(QJsonValue(1) != QJsonValue(QJsonArray()));
2766 QVERIFY(QJsonValue(1) != QJsonValue(QJsonObject()));
2767
2768 QCOMPARE(QJsonValue(1.), QJsonValue(1.));
2769 QVERIFY(QJsonValue(1.) != QJsonValue(2.));
2770 QVERIFY(QJsonValue(1.) != QJsonValue(QJsonValue::Undefined));
2771 QVERIFY(QJsonValue(1.) != QJsonValue());
2772 QVERIFY(QJsonValue(1.) != QJsonValue(true));
2773 QVERIFY(QJsonValue(1.) != QJsonValue(QJsonArray()));
2774 QVERIFY(QJsonValue(1.) != QJsonValue(QJsonObject()));
2775
2776 QCOMPARE(QJsonValue(QJsonArray()), QJsonValue(QJsonArray()));
2777 QJsonArray nonEmptyArray;
2778 nonEmptyArray.append(value: true);
2779 QVERIFY(QJsonValue(QJsonArray()) != nonEmptyArray);
2780 QVERIFY(QJsonValue(QJsonArray()) != QJsonValue(QJsonValue::Undefined));
2781 QVERIFY(QJsonValue(QJsonArray()) != QJsonValue());
2782 QVERIFY(QJsonValue(QJsonArray()) != QJsonValue(true));
2783 QVERIFY(QJsonValue(QJsonArray()) != QJsonValue(1.));
2784 QVERIFY(QJsonValue(QJsonArray()) != QJsonValue(QJsonObject()));
2785
2786 QCOMPARE(QJsonValue(QJsonObject()), QJsonValue(QJsonObject()));
2787 QJsonObject nonEmptyObject;
2788 nonEmptyObject.insert(key: "Key", value: true);
2789 QVERIFY(QJsonValue(QJsonObject()) != nonEmptyObject);
2790 QVERIFY(QJsonValue(QJsonObject()) != QJsonValue(QJsonValue::Undefined));
2791 QVERIFY(QJsonValue(QJsonObject()) != QJsonValue());
2792 QVERIFY(QJsonValue(QJsonObject()) != QJsonValue(true));
2793 QVERIFY(QJsonValue(QJsonObject()) != QJsonValue(1.));
2794 QVERIFY(QJsonValue(QJsonObject()) != QJsonValue(QJsonArray()));
2795
2796 QCOMPARE(QJsonValue("foo"), QJsonValue(QLatin1String("foo")));
2797 QCOMPARE(QJsonValue("foo"), QJsonValue(QString("foo")));
2798 QCOMPARE(QJsonValue("\x66\x6f\x6f"), QJsonValue(QString("foo")));
2799 QCOMPARE(QJsonValue("\x62\x61\x72"), QJsonValue("bar"));
2800 QCOMPARE(QJsonValue(UNICODE_NON_CHARACTER), QJsonValue(QString(UNICODE_NON_CHARACTER)));
2801 QCOMPARE(QJsonValue(UNICODE_DJE), QJsonValue(QString(UNICODE_DJE)));
2802 QCOMPARE(QJsonValue("\xc3\xa9"), QJsonValue(QString("\xc3\xa9")));
2803}
2804
2805void tst_QtJson::objectEquals_data()
2806{
2807 QTest::addColumn<QJsonObject>(name: "left");
2808 QTest::addColumn<QJsonObject>(name: "right");
2809 QTest::addColumn<bool>(name: "result");
2810
2811 QTest::newRow(dataTag: "two defaults") << QJsonObject() << QJsonObject() << true;
2812
2813 QJsonObject object1;
2814 object1.insert(key: "property", value: 1);
2815 QJsonObject object2;
2816 object2["property"] = 1;
2817 QJsonObject object3;
2818 object3.insert(key: "property1", value: 1);
2819 object3.insert(key: "property2", value: 2);
2820
2821 QTest::newRow(dataTag: "the same object (1 vs 2)") << object1 << object2 << true;
2822 QTest::newRow(dataTag: "the same object (3 vs 3)") << object3 << object3 << true;
2823 QTest::newRow(dataTag: "different objects (2 vs 3)") << object2 << object3 << false;
2824 QTest::newRow(dataTag: "object vs default") << object1 << QJsonObject() << false;
2825
2826 QJsonObject empty;
2827 empty.insert(key: "property", value: 1);
2828 empty.take(key: "property");
2829 QTest::newRow(dataTag: "default vs empty") << QJsonObject() << empty << true;
2830 QTest::newRow(dataTag: "empty vs empty") << empty << empty << true;
2831 QTest::newRow(dataTag: "object vs empty") << object1 << empty << false;
2832
2833 QJsonObject referencedEmpty;
2834 referencedEmpty["undefined"];
2835 QTest::newRow(dataTag: "referenced empty vs referenced empty") << referencedEmpty << referencedEmpty << true;
2836 QTest::newRow(dataTag: "referenced empty vs object") << referencedEmpty << object1 << false;
2837
2838 QJsonObject referencedObject1;
2839 referencedObject1.insert(key: "property", value: 1);
2840 referencedObject1["undefined"];
2841 QJsonObject referencedObject2;
2842 referencedObject2.insert(key: "property", value: 1);
2843 referencedObject2["aaaaaaaaa"]; // earlier then "property"
2844 referencedObject2["zzzzzzzzz"]; // after "property"
2845 QTest::newRow(dataTag: "referenced object vs default") << referencedObject1 << QJsonObject() << false;
2846 QTest::newRow(dataTag: "referenced object vs referenced object") << referencedObject1 << referencedObject1 << true;
2847 QTest::newRow(dataTag: "referenced object vs object (different)") << referencedObject1 << object3 << false;
2848}
2849
2850void tst_QtJson::objectEquals()
2851{
2852 QFETCH(QJsonObject, left);
2853 QFETCH(QJsonObject, right);
2854 QFETCH(bool, result);
2855
2856 QCOMPARE(left == right, result);
2857 QCOMPARE(right == left, result);
2858
2859 // invariants checks
2860 QCOMPARE(left, left);
2861 QCOMPARE(right, right);
2862 QCOMPARE(left != right, !result);
2863 QCOMPARE(right != left, !result);
2864
2865 // The same but from QJsonValue perspective
2866 QCOMPARE(QJsonValue(left) == QJsonValue(right), result);
2867 QCOMPARE(QJsonValue(left) != QJsonValue(right), !result);
2868 QCOMPARE(QJsonValue(right) == QJsonValue(left), result);
2869 QCOMPARE(QJsonValue(right) != QJsonValue(left), !result);
2870
2871 // The same, but from a QJsonDocument perspective
2872 QCOMPARE(QJsonDocument(left) == QJsonDocument(right), result);
2873 QCOMPARE(QJsonDocument(left) != QJsonDocument(right), !result);
2874 QCOMPARE(QJsonDocument(right) == QJsonDocument(left), result);
2875 QCOMPARE(QJsonDocument(right) != QJsonDocument(left), !result);
2876}
2877
2878void tst_QtJson::arrayEquals_data()
2879{
2880 QTest::addColumn<QJsonArray>(name: "left");
2881 QTest::addColumn<QJsonArray>(name: "right");
2882 QTest::addColumn<bool>(name: "result");
2883
2884 QTest::newRow(dataTag: "two defaults") << QJsonArray() << QJsonArray() << true;
2885
2886 QJsonArray array1;
2887 array1.append(value: 1);
2888 QJsonArray array2;
2889 array2.append(value: 2111);
2890 array2[0] = 1;
2891 QJsonArray array3;
2892 array3.insert(i: 0, value: 1);
2893 array3.insert(i: 1, value: 2);
2894
2895 QTest::newRow(dataTag: "the same array (1 vs 2)") << array1 << array2 << true;
2896 QTest::newRow(dataTag: "the same array (3 vs 3)") << array3 << array3 << true;
2897 QTest::newRow(dataTag: "different arrays (2 vs 3)") << array2 << array3 << false;
2898 QTest::newRow(dataTag: "array vs default") << array1 << QJsonArray() << false;
2899
2900 QJsonArray empty;
2901 empty.append(value: 1);
2902 empty.takeAt(i: 0);
2903 QTest::newRow(dataTag: "default vs empty") << QJsonArray() << empty << true;
2904 QTest::newRow(dataTag: "empty vs default") << empty << QJsonArray() << true;
2905 QTest::newRow(dataTag: "empty vs empty") << empty << empty << true;
2906 QTest::newRow(dataTag: "array vs empty") << array1 << empty << false;
2907}
2908
2909void tst_QtJson::arrayEquals()
2910{
2911 QFETCH(QJsonArray, left);
2912 QFETCH(QJsonArray, right);
2913 QFETCH(bool, result);
2914
2915 QCOMPARE(left == right, result);
2916 QCOMPARE(right == left, result);
2917
2918 // invariants checks
2919 QCOMPARE(left, left);
2920 QCOMPARE(right, right);
2921 QCOMPARE(left != right, !result);
2922 QCOMPARE(right != left, !result);
2923
2924 // The same but from QJsonValue perspective
2925 QCOMPARE(QJsonValue(left) == QJsonValue(right), result);
2926 QCOMPARE(QJsonValue(left) != QJsonValue(right), !result);
2927 QCOMPARE(QJsonValue(right) == QJsonValue(left), result);
2928 QCOMPARE(QJsonValue(right) != QJsonValue(left), !result);
2929
2930 // The same but from QJsonDocument perspective
2931 QCOMPARE(QJsonDocument(left) == QJsonDocument(right), result);
2932 QCOMPARE(QJsonDocument(left) != QJsonDocument(right), !result);
2933 QCOMPARE(QJsonDocument(right) == QJsonDocument(left), result);
2934 QCOMPARE(QJsonDocument(right) != QJsonDocument(left), !result);
2935}
2936
2937void tst_QtJson::documentEquals_data()
2938{
2939 QTest::addColumn<QJsonDocument>(name: "left");
2940 QTest::addColumn<QJsonDocument>(name: "right");
2941 QTest::addColumn<bool>(name: "result");
2942
2943 QTest::newRow(dataTag: "two defaults") << QJsonDocument() << QJsonDocument() << true;
2944
2945 QJsonDocument emptyobj(QJsonObject{});
2946 QJsonDocument emptyarr(QJsonArray{});
2947 QTest::newRow(dataTag: "emptyarray vs default") << emptyarr << QJsonDocument() << false;
2948 QTest::newRow(dataTag: "emptyobject vs default") << emptyobj << QJsonDocument() << false;
2949 QTest::newRow(dataTag: "emptyarray vs emptyobject") << emptyarr << emptyobj << false;
2950
2951 QJsonDocument array1(QJsonArray{1});
2952 QJsonDocument array2(QJsonArray{2});
2953 QTest::newRow(dataTag: "emptyarray vs emptyarray") << emptyarr << emptyarr << true;
2954 QTest::newRow(dataTag: "emptyarray vs array") << emptyarr << array1 << false;
2955 QTest::newRow(dataTag: "array vs array") << array1 << array1 << true;
2956 QTest::newRow(dataTag: "array vs otherarray") << array1 << array2 << false;
2957
2958 QJsonDocument object1(QJsonObject{{"hello", "world"}});
2959 QJsonDocument object2(QJsonObject{{"hello", 2}});
2960 QTest::newRow(dataTag: "emptyobject vs emptyobject") << emptyobj << emptyobj << true;
2961 QTest::newRow(dataTag: "emptyobject vs object") << emptyobj << object1 << false;
2962 QTest::newRow(dataTag: "object vs object") << object1 << object1 << true;
2963 QTest::newRow(dataTag: "object vs otherobject") << object1 << object2 << false;
2964
2965 QTest::newRow(dataTag: "object vs array") << array1 << object1 << false;
2966}
2967
2968void tst_QtJson::documentEquals()
2969{
2970 QFETCH(QJsonDocument, left);
2971 QFETCH(QJsonDocument, right);
2972 QFETCH(bool, result);
2973
2974 QCOMPARE(left == right, result);
2975 QCOMPARE(right == left, result);
2976
2977 // invariants checks
2978 QCOMPARE(left, left);
2979 QCOMPARE(right, right);
2980 QCOMPARE(left != right, !result);
2981 QCOMPARE(right != left, !result);
2982}
2983
2984void tst_QtJson::bom()
2985{
2986 QFile file(testDataDir + "/bom.json");
2987 file.open(flags: QFile::ReadOnly);
2988 QByteArray json = file.readAll();
2989
2990 // Import json document into a QJsonDocument
2991 QJsonParseError error;
2992 QJsonDocument doc = QJsonDocument::fromJson(json, error: &error);
2993
2994 QVERIFY(!doc.isNull());
2995 QCOMPARE(error.error, QJsonParseError::NoError);
2996}
2997
2998void tst_QtJson::nesting()
2999{
3000 // check that we abort parsing too deeply nested json documents.
3001 // this is to make sure we don't crash because the parser exhausts the
3002 // stack.
3003
3004 const char *array_data =
3005 "[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[["
3006 "[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[["
3007 "[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[["
3008 "[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[["
3009 "[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[["
3010 "[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[["
3011 "[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[["
3012 "[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[["
3013 "]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]"
3014 "]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]"
3015 "]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]"
3016 "]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]"
3017 "]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]"
3018 "]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]"
3019 "]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]"
3020 "]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]";
3021
3022 QByteArray json(array_data);
3023 QJsonParseError error;
3024 QJsonDocument doc = QJsonDocument::fromJson(json, error: &error);
3025
3026 QVERIFY(!doc.isNull());
3027 QCOMPARE(error.error, QJsonParseError::NoError);
3028
3029 json.prepend(c: '[');
3030 json.append(c: ']');
3031 doc = QJsonDocument::fromJson(json, error: &error);
3032
3033 QVERIFY(doc.isNull());
3034 QCOMPARE(error.error, QJsonParseError::DeepNesting);
3035
3036 json = QByteArray("true ");
3037
3038 for (int i = 0; i < 1024; ++i) {
3039 json.prepend(s: "{ \"Key\": ");
3040 json.append(s: " }");
3041 }
3042
3043 doc = QJsonDocument::fromJson(json, error: &error);
3044
3045 QVERIFY(!doc.isNull());
3046 QCOMPARE(error.error, QJsonParseError::NoError);
3047
3048 json.prepend(c: '[');
3049 json.append(c: ']');
3050 doc = QJsonDocument::fromJson(json, error: &error);
3051
3052 QVERIFY(doc.isNull());
3053 QCOMPARE(error.error, QJsonParseError::DeepNesting);
3054
3055}
3056
3057void tst_QtJson::longStrings()
3058{
3059 // test around 15 and 16 bit boundaries, as these are limits
3060 // in the data structures (for Latin1String in qjson_p.h)
3061 QString s(0x7ff0, 'a');
3062 QByteArray ba(0x7ff0, 'a');
3063 ba.append(n: 0x8010 - 0x7ff0, ch: 'c');
3064 for (int i = 0x7ff0; i < 0x8010; i++) {
3065 s.append(c: QLatin1Char('c'));
3066
3067 QMap <QString, QVariant> map;
3068 map["key"] = s;
3069
3070 /* Create a QJsonDocument from the QMap ... */
3071 QJsonDocument d1 = QJsonDocument::fromVariant(variant: QVariant(map));
3072 /* ... and a QByteArray from the QJsonDocument */
3073 QByteArray a1 = d1.toJson();
3074
3075 /* Create a QJsonDocument from the QByteArray ... */
3076 QJsonDocument d2 = QJsonDocument::fromJson(json: a1);
3077 /* ... and a QByteArray from the QJsonDocument */
3078 QByteArray a2 = d2.toJson();
3079 QCOMPARE(a1, a2);
3080
3081 // Test long keys
3082 QJsonObject o1, o2;
3083 o1[s] = 42;
3084 o2[QLatin1String(ba.data(), i + 1)] = 42;
3085 d1.setObject(o1);
3086 d2.setObject(o2);
3087 a1 = d1.toJson();
3088 a2 = d2.toJson();
3089 QCOMPARE(a1, a2);
3090 }
3091
3092 s = QString(0xfff0, 'a');
3093 ba = QByteArray(0xfff0, 'a');
3094 ba.append(n: 0x10010 - 0xfff0, ch: 'c');
3095 for (int i = 0xfff0; i < 0x10010; i++) {
3096 s.append(c: QLatin1Char('c'));
3097
3098 QMap <QString, QVariant> map;
3099 map["key"] = s;
3100
3101 /* Create a QJsonDocument from the QMap ... */
3102 QJsonDocument d1 = QJsonDocument::fromVariant(variant: QVariant(map));
3103 /* ... and a QByteArray from the QJsonDocument */
3104 QByteArray a1 = d1.toJson();
3105
3106 /* Create a QJsonDocument from the QByteArray ... */
3107 QJsonDocument d2 = QJsonDocument::fromJson(json: a1);
3108 /* ... and a QByteArray from the QJsonDocument */
3109 QByteArray a2 = d2.toJson();
3110 QCOMPARE(a1, a2);
3111
3112 // Test long keys
3113 QJsonObject o1, o2;
3114 o1[s] = 42;
3115 o2[QLatin1String(ba.data(), i + 1)] = 42;
3116 d1.setObject(o1);
3117 d2.setObject(o2);
3118 a1 = d1.toJson();
3119 a2 = d2.toJson();
3120 QCOMPARE(a1, a2);
3121 }
3122}
3123
3124void tst_QtJson::testJsonValueRefDefault()
3125{
3126 QJsonObject empty;
3127
3128 QCOMPARE(empty["n/a"].toString(), QString());
3129 QCOMPARE(empty["n/a"].toString("default"), QStringLiteral("default"));
3130
3131 QCOMPARE(empty["n/a"].toBool(), false);
3132 QCOMPARE(empty["n/a"].toBool(true), true);
3133
3134 QCOMPARE(empty["n/a"].toInt(), 0);
3135 QCOMPARE(empty["n/a"].toInt(42), 42);
3136
3137 QCOMPARE(empty["n/a"].toDouble(), 0.0);
3138 QCOMPARE(empty["n/a"].toDouble(42.0), 42.0);
3139}
3140
3141void tst_QtJson::arrayInitializerList()
3142{
3143 QVERIFY(QJsonArray{}.isEmpty());
3144 QCOMPARE(QJsonArray{"one"}.count(), 1);
3145 QCOMPARE(QJsonArray{1}.count(), 1);
3146
3147 {
3148 QJsonArray a{1.3, "hello", 0};
3149 QCOMPARE(QJsonValue(a[0]), QJsonValue(1.3));
3150 QCOMPARE(QJsonValue(a[1]), QJsonValue("hello"));
3151 QCOMPARE(QJsonValue(a[2]), QJsonValue(0));
3152 QCOMPARE(a.count(), 3);
3153 }
3154 {
3155 QJsonObject o;
3156 o["property"] = 1;
3157 QJsonArray a1 {o};
3158 QCOMPARE(a1.count(), 1);
3159 QCOMPARE(a1[0].toObject(), o);
3160
3161 QJsonArray a2 {o, 23};
3162 QCOMPARE(a2.count(), 2);
3163 QCOMPARE(a2[0].toObject(), o);
3164 QCOMPARE(QJsonValue(a2[1]), QJsonValue(23));
3165
3166 QJsonArray a3 { a1, o, a2 };
3167 QCOMPARE(QJsonValue(a3[0]), QJsonValue(a1));
3168 QCOMPARE(QJsonValue(a3[1]), QJsonValue(o));
3169 QCOMPARE(QJsonValue(a3[2]), QJsonValue(a2));
3170
3171 QJsonArray a4 { 1, QJsonArray{1,2,3}, QJsonArray{"hello", 2}, QJsonObject{{"one", 1}} };
3172 QCOMPARE(a4.count(), 4);
3173 QCOMPARE(QJsonValue(a4[0]), QJsonValue(1));
3174
3175 {
3176 QJsonArray a41 = a4[1].toArray();
3177 QJsonArray a42 = a4[2].toArray();
3178 QJsonObject a43 = a4[3].toObject();
3179 QCOMPARE(a41.count(), 3);
3180 QCOMPARE(a42.count(), 2);
3181 QCOMPARE(a43.count(), 1);
3182
3183 QCOMPARE(QJsonValue(a41[2]), QJsonValue(3));
3184 QCOMPARE(QJsonValue(a42[1]), QJsonValue(2));
3185 QCOMPARE(QJsonValue(a43["one"]), QJsonValue(1));
3186 }
3187 }
3188}
3189
3190void tst_QtJson::objectInitializerList()
3191{
3192 QVERIFY(QJsonObject{}.isEmpty());
3193
3194 { // one property
3195 QJsonObject one {{"one", 1}};
3196 QCOMPARE(one.count(), 1);
3197 QVERIFY(one.contains("one"));
3198 QCOMPARE(QJsonValue(one["one"]), QJsonValue(1));
3199 }
3200 { // two properties
3201 QJsonObject two {
3202 {"one", 1},
3203 {"two", 2}
3204 };
3205 QCOMPARE(two.count(), 2);
3206 QVERIFY(two.contains("one"));
3207 QVERIFY(two.contains("two"));
3208 QCOMPARE(QJsonValue(two["one"]), QJsonValue(1));
3209 QCOMPARE(QJsonValue(two["two"]), QJsonValue(2));
3210 }
3211 { // nested object
3212 QJsonObject object{{"nested", QJsonObject{{"innerProperty", 2}}}};
3213 QCOMPARE(object.count(), 1);
3214 QVERIFY(object.contains("nested"));
3215 QVERIFY(object["nested"].isObject());
3216
3217 QJsonObject nested = object["nested"].toObject();
3218 QCOMPARE(QJsonValue(nested["innerProperty"]), QJsonValue(2));
3219 }
3220 { // nested array
3221 QJsonObject object{{"nested", QJsonArray{"innerValue", 2.1, "bum cyk cyk"}}};
3222 QCOMPARE(object.count(), 1);
3223 QVERIFY(object.contains("nested"));
3224 QVERIFY(object["nested"].isArray());
3225
3226 QJsonArray nested = object["nested"].toArray();
3227 QCOMPARE(nested.count(), 3);
3228 QCOMPARE(QJsonValue(nested[0]), QJsonValue("innerValue"));
3229 QCOMPARE(QJsonValue(nested[1]), QJsonValue(2.1));
3230 }
3231}
3232
3233void tst_QtJson::unicodeKeys()
3234{
3235 QByteArray json = "{"
3236 "\"x\\u2090_1\": \"hello_1\","
3237 "\"y\\u2090_2\": \"hello_2\","
3238 "\"T\\u2090_3\": \"hello_3\","
3239 "\"xyz_4\": \"hello_4\","
3240 "\"abc_5\": \"hello_5\""
3241 "}";
3242
3243 QJsonParseError error;
3244 QJsonDocument doc = QJsonDocument::fromJson(json, error: &error);
3245 QCOMPARE(error.error, QJsonParseError::NoError);
3246 QJsonObject o = doc.object();
3247
3248 const auto keys = o.keys();
3249 QCOMPARE(keys.size(), 5);
3250 for (const QString &key : keys) {
3251 QString suffix = key.mid(position: key.indexOf(c: QLatin1Char('_')));
3252 QCOMPARE(o[key].toString(), QString("hello") + suffix);
3253 }
3254}
3255
3256void tst_QtJson::garbageAtEnd()
3257{
3258 QJsonParseError error;
3259 QJsonDocument doc = QJsonDocument::fromJson(json: "{},", error: &error);
3260 QCOMPARE(error.error, QJsonParseError::GarbageAtEnd);
3261 QCOMPARE(error.offset, 2);
3262 QVERIFY(doc.isEmpty());
3263
3264 doc = QJsonDocument::fromJson(json: "{} ", error: &error);
3265 QCOMPARE(error.error, QJsonParseError::NoError);
3266 QVERIFY(!doc.isEmpty());
3267}
3268
3269void tst_QtJson::removeNonLatinKey()
3270{
3271 const QString nonLatinKeyName = QString::fromUtf8(str: "Атрибут100500");
3272
3273 QJsonObject sourceObject;
3274
3275 sourceObject.insert(key: "code", value: 1);
3276 sourceObject.remove(key: "code");
3277
3278 sourceObject.insert(key: nonLatinKeyName, value: 1);
3279
3280 const QByteArray json = QJsonDocument(sourceObject).toJson();
3281 const QJsonObject restoredObject = QJsonDocument::fromJson(json).object();
3282
3283 QCOMPARE(sourceObject.keys(), restoredObject.keys());
3284 QVERIFY(sourceObject.contains(nonLatinKeyName));
3285 QVERIFY(restoredObject.contains(nonLatinKeyName));
3286}
3287
3288void tst_QtJson::documentFromVariant()
3289{
3290 // Test the valid forms of QJsonDocument::fromVariant.
3291
3292 QString string = QStringLiteral("value");
3293
3294 QStringList strList;
3295 strList.append(t: string);
3296
3297 QJsonDocument da1 = QJsonDocument::fromVariant(variant: QVariant(strList));
3298 QVERIFY(da1.isArray());
3299
3300 QVariantList list;
3301 list.append(t: string);
3302
3303 QJsonDocument da2 = QJsonDocument::fromVariant(variant: list);
3304 QVERIFY(da2.isArray());
3305
3306 // As JSON arrays they should be equal.
3307 QCOMPARE(da1.array(), da2.array());
3308
3309
3310 QMap <QString, QVariant> map;
3311 map["key"] = string;
3312
3313 QJsonDocument do1 = QJsonDocument::fromVariant(variant: QVariant(map));
3314 QVERIFY(do1.isObject());
3315
3316 QHash <QString, QVariant> hash;
3317 hash["key"] = string;
3318
3319 QJsonDocument do2 = QJsonDocument::fromVariant(variant: QVariant(hash));
3320 QVERIFY(do2.isObject());
3321
3322 // As JSON objects they should be equal.
3323 QCOMPARE(do1.object(), do2.object());
3324}
3325
3326void tst_QtJson::parseErrorOffset_data()
3327{
3328 QTest::addColumn<QByteArray>(name: "json");
3329 QTest::addColumn<int>(name: "errorOffset");
3330
3331 QTest::newRow(dataTag: "Trailing comma in object") << QByteArray("{ \"value\": false, }") << 19;
3332 QTest::newRow(dataTag: "Trailing comma in object plus whitespace") << QByteArray("{ \"value\": false, } ") << 19;
3333 QTest::newRow(dataTag: "Trailing comma in array") << QByteArray("[ false, ]") << 10;
3334 QTest::newRow(dataTag: "Trailing comma in array plus whitespace") << QByteArray("[ false, ] ") << 10;
3335 QTest::newRow(dataTag: "Missing value in object") << QByteArray("{ \"value\": , } ") << 12;
3336 QTest::newRow(dataTag: "Missing value in array") << QByteArray("[ \"value\" , , ] ") << 13;
3337 QTest::newRow(dataTag: "Leading comma in object") << QByteArray("{ , \"value\": false}") << 3;
3338 QTest::newRow(dataTag: "Leading comma in array") << QByteArray("[ , false]") << 3;
3339 QTest::newRow(dataTag: "Stray ,") << QByteArray(" , ") << 3;
3340 QTest::newRow(dataTag: "Stray [") << QByteArray(" [ ") << 5;
3341 QTest::newRow(dataTag: "Stray }") << QByteArray(" } ") << 3;
3342}
3343
3344void tst_QtJson::parseErrorOffset()
3345{
3346 QFETCH(QByteArray, json);
3347 QFETCH(int, errorOffset);
3348
3349 QJsonParseError error;
3350 QJsonDocument::fromJson(json, error: &error);
3351
3352 QVERIFY(error.error != QJsonParseError::NoError);
3353 QCOMPARE(error.offset, errorOffset);
3354}
3355
3356void tst_QtJson::implicitValueType()
3357{
3358 QJsonObject rootObject{
3359 {"object", QJsonObject{{"value", 42}}},
3360 {"array", QJsonArray{665, 666, 667}}
3361 };
3362
3363 QJsonValue objectValue = rootObject["object"];
3364 QCOMPARE(objectValue["value"].toInt(), 42);
3365 QCOMPARE(objectValue["missingValue"], QJsonValue(QJsonValue::Undefined));
3366 QCOMPARE(objectValue[123], QJsonValue(QJsonValue::Undefined));
3367 QCOMPARE(objectValue["missingValue"].toInt(123), 123);
3368
3369 QJsonValue arrayValue = rootObject["array"];
3370 QCOMPARE(arrayValue[1].toInt(), 666);
3371 QCOMPARE(arrayValue[-1], QJsonValue(QJsonValue::Undefined));
3372 QCOMPARE(arrayValue["asObject"], QJsonValue(QJsonValue::Undefined));
3373 QCOMPARE(arrayValue[-1].toInt(123), 123);
3374
3375 const QJsonObject constObject = rootObject;
3376 QCOMPARE(constObject["object"]["value"].toInt(), 42);
3377 QCOMPARE(constObject["array"][1].toInt(), 666);
3378
3379 QJsonValue objectAsValue(rootObject);
3380 QCOMPARE(objectAsValue["object"]["value"].toInt(), 42);
3381 QCOMPARE(objectAsValue["array"][1].toInt(), 666);
3382}
3383
3384void tst_QtJson::implicitDocumentType()
3385{
3386 QJsonDocument emptyDocument;
3387 QCOMPARE(emptyDocument["asObject"], QJsonValue(QJsonValue::Undefined));
3388 QCOMPARE(emptyDocument[123], QJsonValue(QJsonValue::Undefined));
3389
3390 QJsonDocument objectDocument(QJsonObject{{"value", 42}});
3391 QCOMPARE(objectDocument["value"].toInt(), 42);
3392 QCOMPARE(objectDocument["missingValue"], QJsonValue(QJsonValue::Undefined));
3393 QCOMPARE(objectDocument[123], QJsonValue(QJsonValue::Undefined));
3394 QCOMPARE(objectDocument["missingValue"].toInt(123), 123);
3395
3396 QJsonDocument arrayDocument(QJsonArray{665, 666, 667});
3397 QCOMPARE(arrayDocument[1].toInt(), 666);
3398 QCOMPARE(arrayDocument[-1], QJsonValue(QJsonValue::Undefined));
3399 QCOMPARE(arrayDocument["asObject"], QJsonValue(QJsonValue::Undefined));
3400 QCOMPARE(arrayDocument[-1].toInt(123), 123);
3401}
3402
3403void tst_QtJson::streamSerializationQJsonDocument_data()
3404{
3405 QTest::addColumn<QJsonDocument>(name: "document");
3406 QTest::newRow(dataTag: "empty") << QJsonDocument();
3407 QTest::newRow(dataTag: "object") << QJsonDocument(QJsonObject{{"value", 42}});
3408}
3409
3410void tst_QtJson::streamSerializationQJsonDocument()
3411{
3412 // Check interface only, implementation is tested through to and from
3413 // json functions.
3414 QByteArray buffer;
3415 QFETCH(QJsonDocument, document);
3416 QJsonDocument output;
3417 QDataStream save(&buffer, QIODevice::WriteOnly);
3418 save << document;
3419 QDataStream load(buffer);
3420 load >> output;
3421 QCOMPARE(output, document);
3422}
3423
3424void tst_QtJson::streamSerializationQJsonArray_data()
3425{
3426 QTest::addColumn<QJsonArray>(name: "array");
3427 QTest::newRow(dataTag: "empty") << QJsonArray();
3428 QTest::newRow(dataTag: "values") << QJsonArray{665, 666, 667};
3429}
3430
3431void tst_QtJson::streamSerializationQJsonArray()
3432{
3433 // Check interface only, implementation is tested through to and from
3434 // json functions.
3435 QByteArray buffer;
3436 QFETCH(QJsonArray, array);
3437 QJsonArray output;
3438 QDataStream save(&buffer, QIODevice::WriteOnly);
3439 save << array;
3440 QDataStream load(buffer);
3441 load >> output;
3442 QCOMPARE(output, array);
3443}
3444
3445void tst_QtJson::streamSerializationQJsonObject_data()
3446{
3447 QTest::addColumn<QJsonObject>(name: "object");
3448 QTest::newRow(dataTag: "empty") << QJsonObject();
3449 QTest::newRow(dataTag: "non-empty") << QJsonObject{{"foo", 665}, {"bar", 666}};
3450}
3451
3452void tst_QtJson::streamSerializationQJsonObject()
3453{
3454 // Check interface only, implementation is tested through to and from
3455 // json functions.
3456 QByteArray buffer;
3457 QFETCH(QJsonObject, object);
3458 QJsonObject output;
3459 QDataStream save(&buffer, QIODevice::WriteOnly);
3460 save << object;
3461 QDataStream load(buffer);
3462 load >> output;
3463 QCOMPARE(output, object);
3464}
3465
3466void tst_QtJson::streamSerializationQJsonValue_data()
3467{
3468 QTest::addColumn<QJsonValue>(name: "value");
3469 QTest::newRow(dataTag: "double") << QJsonValue{665};
3470 QTest::newRow(dataTag: "bool") << QJsonValue{true};
3471 QTest::newRow(dataTag: "string") << QJsonValue{QStringLiteral("bum")};
3472 QTest::newRow(dataTag: "array") << QJsonValue{QJsonArray{12,1,5,6,7}};
3473 QTest::newRow(dataTag: "object") << QJsonValue{QJsonObject{{"foo", 665}, {"bar", 666}}};
3474 // test json escape sequence
3475 QTest::newRow(dataTag: "array with 0xD800") << QJsonValue(QJsonArray{QString(0xD800)});
3476 QTest::newRow(dataTag: "array with 0xDF06,0xD834") << QJsonValue(QJsonArray{QString(0xDF06).append(c: 0xD834)});
3477}
3478
3479void tst_QtJson::streamSerializationQJsonValue()
3480{
3481 QByteArray buffer;
3482 QFETCH(QJsonValue, value);
3483 QJsonValue output;
3484 QDataStream save(&buffer, QIODevice::WriteOnly);
3485 save << value;
3486 QDataStream load(buffer);
3487 load >> output;
3488 QCOMPARE(output, value);
3489}
3490
3491void tst_QtJson::streamSerializationQJsonValueEmpty()
3492{
3493 QByteArray buffer;
3494 {
3495 QJsonValue undef{QJsonValue::Undefined};
3496 QDataStream save(&buffer, QIODevice::WriteOnly);
3497 save << undef;
3498 QDataStream load(buffer);
3499 QJsonValue output;
3500 load >> output;
3501 QVERIFY(output.isUndefined());
3502 }
3503 {
3504 QJsonValue null{QJsonValue::Null};
3505 QDataStream save(&buffer, QIODevice::WriteOnly);
3506 save << null;
3507 QDataStream load(buffer);
3508 QJsonValue output;
3509 load >> output;
3510 QVERIFY(output.isNull());
3511 }
3512}
3513
3514void tst_QtJson::streamVariantSerialization()
3515{
3516 // Check interface only, implementation is tested through to and from
3517 // json functions.
3518 QByteArray buffer;
3519 {
3520 QJsonDocument objectDoc(QJsonArray{665, 666, 667});
3521 QVariant output;
3522 QVariant variant(objectDoc);
3523 QDataStream save(&buffer, QIODevice::WriteOnly);
3524 save << variant;
3525 QDataStream load(buffer);
3526 load >> output;
3527 QCOMPARE(output.userType(), QMetaType::QJsonDocument);
3528 QCOMPARE(output.toJsonDocument(), objectDoc);
3529 }
3530 {
3531 QJsonArray array{665, 666, 667};
3532 QVariant output;
3533 QVariant variant(array);
3534 QDataStream save(&buffer, QIODevice::WriteOnly);
3535 save << variant;
3536 QDataStream load(buffer);
3537 load >> output;
3538 QCOMPARE(output.userType(), QMetaType::QJsonArray);
3539 QCOMPARE(output.toJsonArray(), array);
3540 }
3541 {
3542 QJsonObject obj{{"foo", 42}};
3543 QVariant output;
3544 QVariant variant(obj);
3545 QDataStream save(&buffer, QIODevice::WriteOnly);
3546 save << variant;
3547 QDataStream load(buffer);
3548 load >> output;
3549 QCOMPARE(output.userType(), QMetaType::QJsonObject);
3550 QCOMPARE(output.toJsonObject(), obj);
3551 }
3552 {
3553 QJsonValue value{42};
3554 QVariant output;
3555 QVariant variant(value);
3556 QDataStream save(&buffer, QIODevice::WriteOnly);
3557 save << variant;
3558 QDataStream load(buffer);
3559 load >> output;
3560 QCOMPARE(output.userType(), QMetaType::QJsonValue);
3561 QCOMPARE(output.toJsonValue(), value);
3562 }
3563}
3564
3565void tst_QtJson::escapeSurrogateCodePoints_data()
3566{
3567 QTest::addColumn<QString>(name: "str");
3568 QTest::addColumn<QByteArray>(name: "escStr");
3569 QTest::newRow(dataTag: "0xD800") << QString(0xD800) << QByteArray("\\ud800");
3570 QTest::newRow(dataTag: "0xDF06,0xD834") << QString(0xDF06).append(c: 0xD834) << QByteArray("\\udf06\\ud834");
3571}
3572
3573void tst_QtJson::escapeSurrogateCodePoints()
3574{
3575 QFETCH(QString, str);
3576 QFETCH(QByteArray, escStr);
3577 QJsonArray array;
3578 array.append(value: str);
3579 QByteArray buffer;
3580 QDataStream save(&buffer, QIODevice::WriteOnly);
3581 save << array;
3582 // verify the buffer has escaped values
3583 QVERIFY(buffer.contains(escStr));
3584}
3585
3586void tst_QtJson::fromToVariantConversions_data()
3587{
3588 QTest::addColumn<QVariant>(name: "variant");
3589 QTest::addColumn<QJsonValue>(name: "json");
3590 QTest::addColumn<QVariant>(name: "jsonToVariant");
3591
3592 QByteArray utf8("\xC4\x90\xC4\x81\xC5\xA3\xC3\xA2"); // Đāţâ
3593 QDateTime dt = QDateTime::currentDateTimeUtc();
3594 QUuid uuid = QUuid::createUuid();
3595
3596 constexpr double maxDouble = std::numeric_limits<double>::max();
3597 constexpr double minDouble = std::numeric_limits<double>::min();
3598
3599 QTest::newRow(dataTag: "default") << QVariant() << QJsonValue(QJsonValue::Null)
3600 << QVariant::fromValue(value: nullptr);
3601 QTest::newRow(dataTag: "nullptr") << QVariant::fromValue(value: nullptr) << QJsonValue(QJsonValue::Null)
3602 << QVariant::fromValue(value: nullptr);
3603 QTest::newRow(dataTag: "bool") << QVariant(true) << QJsonValue(true) << QVariant(true);
3604 QTest::newRow(dataTag: "int pos") << QVariant(123) << QJsonValue(123) << QVariant(qlonglong(123));
3605 QTest::newRow(dataTag: "int neg") << QVariant(-123) << QJsonValue(-123) << QVariant(qlonglong(-123));
3606 QTest::newRow(dataTag: "int big pos") << QVariant((1ll << 52) +1) << QJsonValue((1ll << 52) + 1)
3607 << QVariant(qlonglong((1ll << 52) + 1));
3608 QTest::newRow(dataTag: "int big neg") << QVariant(-(1ll << 52) + 1) << QJsonValue(-(1ll << 52) + 1)
3609 << QVariant(qlonglong(-(1ll << 52) + 1));
3610 QTest::newRow(dataTag: "double pos") << QVariant(123.) << QJsonValue(123.) << QVariant(qlonglong(123.));
3611 QTest::newRow(dataTag: "double neg") << QVariant(-123.) << QJsonValue(-123.)
3612 << QVariant(qlonglong(-123.));
3613 QTest::newRow(dataTag: "double big") << QVariant(maxDouble - 1000) << QJsonValue(maxDouble - 1000)
3614 << QVariant(maxDouble - 1000);
3615 QTest::newRow(dataTag: "double max") << QVariant(maxDouble) << QJsonValue(maxDouble)
3616 << QVariant(maxDouble);
3617 QTest::newRow(dataTag: "double min") << QVariant(minDouble) << QJsonValue(minDouble)
3618 << QVariant(minDouble);
3619 QTest::newRow(dataTag: "double big neg") << QVariant(1000 - maxDouble) << QJsonValue(1000 - maxDouble)
3620 << QVariant(1000 - maxDouble);
3621 QTest::newRow(dataTag: "double max neg") << QVariant(-maxDouble) << QJsonValue(-maxDouble)
3622 << QVariant(-maxDouble);
3623 QTest::newRow(dataTag: "double min neg") << QVariant(-minDouble) << QJsonValue(-minDouble)
3624 << QVariant(-minDouble);
3625
3626 QTest::newRow(dataTag: "string null") << QVariant(QString()) << QJsonValue(QString())
3627 << QVariant(QString());
3628 QTest::newRow(dataTag: "string empty") << QVariant(QString("")) << QJsonValue(QString(""))
3629 << QVariant(QString(""));
3630 QTest::newRow(dataTag: "string ascii") << QVariant(QString("Data")) << QJsonValue(QString("Data"))
3631 << QVariant(QString("Data"));
3632 QTest::newRow(dataTag: "string utf8") << QVariant(QString(utf8)) << QJsonValue(QString(utf8))
3633 << QVariant(QString(utf8));
3634
3635 QTest::newRow(dataTag: "bytearray null") << QVariant(QByteArray()) << QJsonValue(QJsonValue::Null)
3636 << QVariant::fromValue(value: nullptr);
3637 QTest::newRow(dataTag: "bytearray empty") << QVariant(QByteArray()) << QJsonValue(QJsonValue::Null)
3638 << QVariant::fromValue(value: nullptr);
3639 QTest::newRow(dataTag: "bytearray ascii") << QVariant(QByteArray("Data")) << QJsonValue(QString("Data"))
3640 << QVariant(QString("Data"));
3641 QTest::newRow(dataTag: "bytearray utf8") << QVariant(utf8) << QJsonValue(QString(utf8))
3642 << QVariant(QString(utf8));
3643
3644 QTest::newRow(dataTag: "datetime") << QVariant(dt) << QJsonValue(dt.toString(format: Qt::ISODateWithMs))
3645 << QVariant(dt.toString(format: Qt::ISODateWithMs));
3646 QTest::newRow(dataTag: "url") << QVariant(QUrl("http://example.com/{q}"))
3647 << QJsonValue("http://example.com/%7Bq%7D")
3648 << QVariant(QString("http://example.com/%7Bq%7D"));
3649 QTest::newRow(dataTag: "uuid") << QVariant(QUuid(uuid))
3650 << QJsonValue(uuid.toString(mode: QUuid::WithoutBraces))
3651 << QVariant(uuid.toString(mode: QUuid::WithoutBraces));
3652 QTest::newRow(dataTag: "regexp") << QVariant(QRegularExpression(".")) << QJsonValue(QJsonValue::Null)
3653 << QVariant::fromValue(value: nullptr);
3654
3655 QTest::newRow(dataTag: "inf") << QVariant(qInf()) << QJsonValue(QJsonValue::Null)
3656 << QVariant::fromValue(value: nullptr);
3657 QTest::newRow(dataTag: "-inf") << QVariant(-qInf()) << QJsonValue(QJsonValue::Null)
3658 << QVariant::fromValue(value: nullptr);
3659 QTest::newRow(dataTag: "NaN") << QVariant(qQNaN()) << QJsonValue(QJsonValue::Null)
3660 << QVariant::fromValue(value: nullptr);
3661
3662 const qulonglong ulongValue = (1ul << 63) + 1;
3663 const double uLongToDouble = ulongValue;
3664 qint64 n;
3665 if (convertDoubleTo(v: uLongToDouble, value: &n)) {
3666 QTest::newRow(dataTag: "ulonglong") << QVariant(ulongValue) << QJsonValue(uLongToDouble)
3667 << QVariant(n);
3668 } else {
3669 QTest::newRow(dataTag: "ulonglong") << QVariant(ulongValue) << QJsonValue(uLongToDouble)
3670 << QVariant(uLongToDouble);
3671 }
3672}
3673
3674void tst_QtJson::fromToVariantConversions()
3675{
3676 QFETCH(QVariant, variant);
3677 QFETCH(QJsonValue, json);
3678 QFETCH(QVariant, jsonToVariant);
3679
3680 QVariant variantFromJson(json);
3681 QVariant variantFromJsonArray(QJsonArray { json });
3682 QVariant variantFromJsonObject(QVariantMap { { "foo", variant } });
3683
3684 QJsonObject object { QPair<QString, QJsonValue>("foo", json) };
3685
3686 // QJsonValue <> QVariant
3687 {
3688 QCOMPARE(QJsonValue::fromVariant(variant), json);
3689
3690 // test the same for QVariant from QJsonValue/QJsonArray/QJsonObject
3691 QCOMPARE(QJsonValue::fromVariant(variantFromJson), json);
3692 QCOMPARE(QJsonValue::fromVariant(variantFromJsonArray), QJsonArray { json });
3693 QCOMPARE(QJsonValue::fromVariant(variantFromJsonObject), object);
3694
3695 // QJsonValue to variant
3696 QCOMPARE(json.toVariant(), jsonToVariant);
3697 QCOMPARE(json.toVariant().userType(), jsonToVariant.userType());
3698
3699 // variant to QJsonValue
3700 QCOMPARE(QVariant(json).toJsonValue(), json);
3701 }
3702
3703 // QJsonArray <> QVariantList
3704 {
3705 QCOMPARE(QJsonArray::fromVariantList(QVariantList { variant }), QJsonArray { json });
3706
3707 // test the same for QVariantList from QJsonValue/QJsonArray/QJsonObject
3708 QCOMPARE(QJsonArray::fromVariantList(QVariantList { variantFromJson }),
3709 QJsonArray { json });
3710 QCOMPARE(QJsonArray::fromVariantList(QVariantList { variantFromJsonArray }),
3711 QJsonArray {{ QJsonArray { json } }});
3712 QCOMPARE(QJsonArray::fromVariantList(QVariantList { variantFromJsonObject }),
3713 QJsonArray { object });
3714
3715 // QJsonArray to variant
3716 QCOMPARE(QJsonArray { json }.toVariantList(), QVariantList { jsonToVariant });
3717 // variant to QJsonArray
3718 QCOMPARE(QVariant(QJsonArray { json }).toJsonArray(), QJsonArray { json });
3719 }
3720
3721 // QJsonObject <> QVariantMap
3722 {
3723 QCOMPARE(QJsonObject::fromVariantMap(QVariantMap { { "foo", variant } }), object);
3724
3725 // test the same for QVariantMap from QJsonValue/QJsonArray/QJsonObject
3726 QCOMPARE(QJsonObject::fromVariantMap(QVariantMap { { "foo", variantFromJson } }), object);
3727
3728 QJsonObject nestedArray { QPair<QString, QJsonArray>("bar", QJsonArray { json }) };
3729 QJsonObject nestedObject { QPair<QString, QJsonObject>("bar", object) };
3730 QCOMPARE(QJsonObject::fromVariantMap(QVariantMap { { "bar", variantFromJsonArray } }),
3731 nestedArray);
3732 QCOMPARE(QJsonObject::fromVariantMap(QVariantMap { { "bar", variantFromJsonObject } }),
3733 nestedObject);
3734
3735 // QJsonObject to variant
3736 QCOMPARE(object.toVariantMap(), QVariantMap({ { "foo", jsonToVariant } }));
3737 // variant to QJsonObject
3738 QCOMPARE(QVariant(object).toJsonObject(), object);
3739 }
3740}
3741
3742void tst_QtJson::noLeakOnNameClash()
3743{
3744 QJsonDocument doc = QJsonDocument::fromJson(json: "{\"\":{\"\":0},\"\":0}");
3745 QVERIFY(!doc.isNull());
3746 const QJsonObject obj = doc.object();
3747
3748 // Removed the duplicate key.
3749 QCOMPARE(obj.length(), 1);
3750
3751 // Retained the last of the duplicates.
3752 const QJsonValue val = obj.begin().value();
3753 QVERIFY(val.isDouble());
3754 QCOMPARE(val.toDouble(), 0.0);
3755
3756 // It should not leak.
3757 // In particular it should not forget to deref the container for the inner object.
3758}
3759
3760QTEST_MAIN(tst_QtJson)
3761#include "tst_qtjson.moc"
3762

source code of qtbase/tests/auto/corelib/serialization/json/tst_qtjson.cpp