1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
3 /* This Source Code Form is subject to the terms of the Mozilla Public
4 * License, v. 2.0. If a copy of the MPL was not distributed with this file,
5 * You can obtain one at http://mozilla.org/MPL/2.0/. */
7 #include "mozilla/Assertions.h"
8 #include "mozilla/JSONWriter.h"
9 #include "mozilla/UniquePtr.h"
14 using mozilla::JSONWriteFunc
;
15 using mozilla::JSONWriter
;
16 using mozilla::MakeStringSpan
;
17 using mozilla::MakeUnique
;
20 // This writes all the output into a big buffer.
21 struct StringWriteFunc final
: public JSONWriteFunc
{
24 void Write(const mozilla::Span
<const char>& aStr
) final
{
25 mString
.append(aStr
.data(), aStr
.size());
29 void Check(JSONWriter
& aWriter
, const char* aExpected
) {
30 JSONWriteFunc
& func
= aWriter
.WriteFunc();
31 const std::string
& actual
= static_cast<StringWriteFunc
&>(func
).mString
;
32 if (strcmp(aExpected
, actual
.c_str()) != 0) {
34 "---- EXPECTED ----\n<<<%s>>>\n"
35 "---- ACTUAL ----\n<<<%s>>>\n",
36 aExpected
, actual
.c_str());
37 MOZ_RELEASE_ASSERT(false, "expected and actual output don't match");
41 // Note: to convert actual output into |expected| strings that C++ can handle,
42 // apply the following substitutions, in order, to each line.
43 // - s/\\/\\\\/g # escapes backslashes
44 // - s/"/\\"/g # escapes quotes
45 // - s/$/\\n\\/ # adds a newline and string continuation char to each line
47 void TestBasicProperties() {
48 const char* expected
=
56 \"int3\": -123456789000,\n\
57 \"double1\": 1.2345,\n\
60 \"double4\": 1.1111111111111111e+21,\n\
62 \"string2\": \"1234\",\n\
63 \"string3\": \"hello\",\n\
64 \"string4\": \"\\\" \\\\ \\u0007 \\b \\t \\n \\u000b \\f \\r\",\n\
65 \"string5\": \"hello\",\n\
66 \"string6\": \"\\\" \\\\ \\u0007 \\b \\t \",\n\
67 \"span1\": \"buf1\",\n\
68 \"span2\": \"buf2\",\n\
69 \"span3\": \"buf3\",\n\
70 \"span4\": \"buf\\n4\",\n\
71 \"span5\": \"MakeStringSpan\",\n\
72 \"len 0 array, multi-line\": [\n\
74 \"len 0 array, single-line\": [],\n\
78 \"len 5 array, multi-line\": [\n\
85 \"len 3 array, single-line\": [1, [{}, 2, []], 3],\n\
86 \"len 0 object, multi-line\": {\n\
88 \"len 0 object, single-line\": {},\n\
89 \"len 1 object\": {\n\
92 \"len 5 object\": {\n\
99 \"len 3 object, single-line\": {\"a\": 1, \"b\": [{}, 2, []], \"c\": 3}\n\
103 JSONWriter
w(MakeUnique
<StringWriteFunc
>());
107 w
.NullProperty("null");
109 w
.BoolProperty("bool1", true);
110 w
.BoolProperty("bool2", false);
112 w
.IntProperty("int1", 123);
113 w
.IntProperty("int2", -0x7b);
114 w
.IntProperty("int3", -123456789000ll);
116 w
.DoubleProperty("double1", 1.2345);
117 w
.DoubleProperty("double2", -3);
118 w
.DoubleProperty("double3", 1e-7);
119 w
.DoubleProperty("double4", 1.1111111111111111e+21);
121 w
.StringProperty("string1", "");
122 w
.StringProperty("string2", "1234");
123 w
.StringProperty("string3", "hello");
124 w
.StringProperty("string4", "\" \\ \a \b \t \n \v \f \r");
125 w
.StringProperty("string5", "hello\0cut"); // '\0' marks the end.
126 w
.StringProperty("string6", "\" \\ \a \b \t \0 \n \v \f \r");
128 const char buf1
[] = {'b', 'u', 'f', '1'};
129 w
.StringProperty("span1", buf1
);
130 const char buf2
[] = {'b', 'u', 'f', '2', '\0'};
131 w
.StringProperty("span2", buf2
);
132 const char buf3
[] = {'b', 'u', 'f', '3', '\0', '?'};
133 w
.StringProperty("span3", buf3
);
134 const char buf4
[] = {'b', 'u', 'f', '\n', '4', '\0', '?'};
135 w
.StringProperty("span4", buf4
);
136 w
.StringProperty("span5", MakeStringSpan("MakeStringSpan"));
138 w
.StartArrayProperty("len 0 array, multi-line", w
.MultiLineStyle
);
141 w
.StartArrayProperty("len 0 array, single-line", w
.SingleLineStyle
);
144 w
.StartArrayProperty("len 1 array");
148 w
.StartArrayProperty("len 5 array, multi-line", w
.MultiLineStyle
);
158 w
.StartArrayProperty("len 3 array, single-line", w
.SingleLineStyle
);
161 w
.StartArrayElement();
163 w
.StartObjectElement(w
.SingleLineStyle
);
168 w
.StartArrayElement(w
.MultiLineStyle
); // style overridden from above
176 w
.StartObjectProperty("len 0 object, multi-line");
179 w
.StartObjectProperty("len 0 object, single-line", w
.SingleLineStyle
);
182 w
.StartObjectProperty("len 1 object");
183 { w
.IntProperty("one", 1); }
186 w
.StartObjectProperty("len 5 object");
188 w
.IntProperty("one", 1);
189 w
.IntProperty("two", 2);
190 w
.IntProperty("three", 3);
191 w
.IntProperty("four", 4);
192 w
.IntProperty("five", 5);
196 w
.StartObjectProperty("len 3 object, single-line", w
.SingleLineStyle
);
198 w
.IntProperty("a", 1);
199 w
.StartArrayProperty("b");
201 w
.StartObjectElement();
206 w
.StartArrayElement(w
.SingleLineStyle
);
210 w
.IntProperty("c", 3);
219 void TestBasicElements() {
220 const char* expected
=
233 1.1111111111111111e+21,\n\
237 \"\\\" \\\\ \\u0007 \\b \\t \\n \\u000b \\f \\r\",\n\
239 \"\\\" \\\\ \\u0007 \\b \\t \",\n\
244 \"MakeStringSpan\",\n\
258 [1, [{}, 2, []], 3],\n\
272 {\"a\": 1, \"b\": [{}, 2, []], \"c\": 3}\n\
277 JSONWriter
w(MakeUnique
<StringWriteFunc
>());
280 w
.StartArrayProperty("array");
285 w
.BoolElement(false);
289 w
.IntElement(-123456789000ll);
291 w
.DoubleElement(1.2345);
293 w
.DoubleElement(1e-7);
294 w
.DoubleElement(1.1111111111111111e+21);
297 w
.StringElement("1234");
298 w
.StringElement("hello");
299 w
.StringElement("\" \\ \a \b \t \n \v \f \r");
300 w
.StringElement("hello\0cut"); // '\0' marks the end.
301 w
.StringElement("\" \\ \a \b \t \0 \n \v \f \r");
303 const char buf1
[] = {'b', 'u', 'f', '1'};
304 w
.StringElement(buf1
);
305 const char buf2
[] = {'b', 'u', 'f', '2', '\0'};
306 w
.StringElement(buf2
);
307 const char buf3
[] = {'b', 'u', 'f', '3', '\0', '?'};
308 w
.StringElement(buf3
);
309 const char buf4
[] = {'b', 'u', 'f', '\n', '4', '\0', '?'};
310 w
.StringElement(buf4
);
311 w
.StringElement(MakeStringSpan("MakeStringSpan"));
313 w
.StartArrayElement();
316 w
.StartArrayElement(w
.SingleLineStyle
);
319 w
.StartArrayElement();
323 w
.StartArrayElement();
333 w
.StartArrayElement(w
.SingleLineStyle
);
336 w
.StartArrayElement();
338 w
.StartObjectElement(w
.SingleLineStyle
);
343 w
.StartArrayElement(w
.MultiLineStyle
); // style overridden from above
351 w
.StartObjectElement();
354 w
.StartObjectElement(w
.SingleLineStyle
);
357 w
.StartObjectElement();
358 { w
.IntProperty("one", 1); }
361 w
.StartObjectElement();
363 w
.IntProperty("one", 1);
364 w
.IntProperty("two", 2);
365 w
.IntProperty("three", 3);
366 w
.IntProperty("four", 4);
367 w
.IntProperty("five", 5);
371 w
.StartObjectElement(w
.SingleLineStyle
);
373 w
.IntProperty("a", 1);
374 w
.StartArrayProperty("b");
376 w
.StartObjectElement();
381 w
.StartArrayElement(w
.SingleLineStyle
);
385 w
.IntProperty("c", 3);
395 void TestOneLineObject() {
396 const char* expected
=
398 {\"i\": 1, \"array\": [null, [{}], {\"o\": {}}, \"s\"], \"d\": 3.33}\n\
401 JSONWriter
w(MakeUnique
<StringWriteFunc
>());
403 w
.Start(w
.SingleLineStyle
);
405 w
.IntProperty("i", 1);
407 w
.StartArrayProperty("array");
411 w
.StartArrayElement(w
.MultiLineStyle
); // style overridden from above
413 w
.StartObjectElement();
418 w
.StartObjectElement();
420 w
.StartObjectProperty("o");
425 w
.StringElement("s");
429 w
.DoubleProperty("d", 3.33);
436 void TestOneLineJson() {
437 const char* expected
=
439 {\"i\":1,\"array\":[null,[{}],{\"o\":{}},\"s\"],\"d\":3.33}\
442 StringWriteFunc func
;
443 JSONWriter
w(func
, JSONWriter::SingleLineStyle
);
445 w
.Start(w
.MultiLineStyle
); // style overridden from above
447 w
.IntProperty("i", 1);
449 w
.StartArrayProperty("array");
453 w
.StartArrayElement(w
.MultiLineStyle
); // style overridden from above
455 w
.StartObjectElement();
460 w
.StartObjectElement();
462 w
.StartObjectProperty("o");
467 w
.StringElement("s");
471 w
.DoubleProperty("d", 3.33);
473 w
.End(); // No newline in this case.
478 void TestStringEscaping() {
479 // This test uses hexadecimal character escapes because UTF8 literals cause
480 // problems for some compilers (see bug 1069726).
481 const char* expected
=
484 \"ascii\": \"\x7F~}|{zyxwvutsrqponmlkjihgfedcba`_^]\\\\[ZYXWVUTSRQPONMLKJIHGFEDCBA@?>=<;:9876543210/.-,+*)('&%$#\\\"! \\u001f\\u001e\\u001d\\u001c\\u001b\\u001a\\u0019\\u0018\\u0017\\u0016\\u0015\\u0014\\u0013\\u0012\\u0011\\u0010\\u000f\\u000e\\r\\f\\u000b\\n\\t\\b\\u0007\\u0006\\u0005\\u0004\\u0003\\u0002\\u0001\",\n\
485 \"\xD9\x85\xD8\xB1\xD8\xAD\xD8\xA8\xD8\xA7 \xD9\x87\xD9\x86\xD8\xA7\xD9\x83\": true,\n\
486 \"\xD5\xA2\xD5\xA1\xD6\x80\xD5\xA5\xD6\x82 \xD5\xB9\xD5\xAF\xD5\xA1\": -123,\n\
487 \"\xE4\xBD\xA0\xE5\xA5\xBD\": 1.234,\n\
488 \"\xCE\xB3\xCE\xB5\xCE\xB9\xCE\xB1 \xCE\xB5\xCE\xBA\xCE\xB5\xCE\xAF\": \"\xD8\xB3\xD9\x84\xD8\xA7\xD9\x85\",\n\
489 \"hall\xC3\xB3 \xC3\xBE"
491 \"\xE3\x81\x93\xE3\x82\x93\xE3\x81\xAB\xE3\x81\xA1\xE3\x81\xAF\": {\n\
492 \"\xD0\xBF\xD1\x80\xD0\xB8\xD0\xB2\xD0\xB5\xD1\x82\": [\n\
498 JSONWriter
w(MakeUnique
<StringWriteFunc
>());
500 // Test the string escaping behaviour.
503 // Test all 127 ascii values. Do it in reverse order so that the 0
504 // at the end serves as the null char.
506 for (int i
= 0; i
< 128; i
++) {
509 w
.StringProperty("ascii", buf
);
511 // Test lots of unicode stuff. Note that this file is encoded as UTF-8.
513 "\xD9\x85\xD8\xB1\xD8\xAD\xD8\xA8\xD8\xA7 "
514 "\xD9\x87\xD9\x86\xD8\xA7\xD9\x83",
517 "\xD5\xA2\xD5\xA1\xD6\x80\xD5\xA5\xD6\x82 \xD5\xB9\xD5\xAF\xD5\xA1",
519 w
.DoubleProperty("\xE4\xBD\xA0\xE5\xA5\xBD", 1.234);
521 "\xCE\xB3\xCE\xB5\xCE\xB9\xCE\xB1 \xCE\xB5\xCE\xBA\xCE\xB5\xCE\xAF",
522 "\xD8\xB3\xD9\x84\xD8\xA7\xD9\x85");
524 "hall\xC3\xB3 \xC3\xBE"
527 w
.StartObjectProperty(
528 "\xE3\x81\x93\xE3\x82\x93\xE3\x81\xAB\xE3\x81\xA1\xE3\x81\xAF");
530 w
.StartArrayProperty("\xD0\xBF\xD1\x80\xD0\xB8\xD0\xB2\xD0\xB5\xD1\x82");
540 void TestDeepNesting() {
541 const char* expected
=
587 JSONWriter
w(MakeUnique
<StringWriteFunc
>());
591 static const int n
= 10;
592 for (int i
= 0; i
< n
; i
++) {
593 w
.StartArrayProperty("a");
594 w
.StartObjectElement();
596 for (int i
= 0; i
< n
; i
++) {
606 void TestEscapedPropertyNames() {
607 const char* expected
=
609 {\"i\\t\": 1, \"array\\t\": [null, [{}], {\"o\\t\": {}}, \"s\"], \"d\": 3.33}\n\
612 JSONWriter
w(MakeUnique
<StringWriteFunc
>());
614 w
.Start(w
.SingleLineStyle
);
616 w
.IntProperty("i\t\0cut", 1); // '\0' marks the end.
618 w
.StartArrayProperty("array\t");
622 w
.StartArrayElement(w
.MultiLineStyle
); // style overridden from above
624 w
.StartObjectElement();
629 w
.StartObjectElement();
631 w
.StartObjectProperty("o\t");
636 w
.StringElement("s");
640 w
.DoubleProperty("d\0\t", 3.33);
648 TestBasicProperties();
652 TestStringEscaping();
654 TestEscapedPropertyNames();