7f69c4968ee7b5ead14130aa9370774b891a510e
[folly.git] / folly / test / JsonTest.cpp
1 /*
2  * Copyright 2016 Facebook, Inc.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *   http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 #include <limits>
17
18 #include <boost/next_prior.hpp>
19 #include <folly/json.h>
20 #include <gtest/gtest.h>
21
22 using folly::dynamic;
23 using folly::parseJson;
24 using folly::toJson;
25
26 TEST(Json, Unicode) {
27   auto val = parseJson("\"I \u2665 UTF-8\"");
28   EXPECT_EQ("I \u2665 UTF-8", val.asString());
29   val = parseJson("\"I \\u2665 UTF-8\"");
30   EXPECT_EQ("I \u2665 UTF-8", val.asString());
31   val = parseJson("\"I \U0001D11E playing in G-clef\"");
32   EXPECT_EQ("I \U0001D11E playing in G-clef", val.asString());
33
34   val = parseJson("\"I \\uD834\\uDD1E playing in G-clef\"");
35   EXPECT_EQ("I \U0001D11E playing in G-clef", val.asString());
36 }
37
38 TEST(Json, Parse) {
39   auto num = parseJson("12");
40   EXPECT_TRUE(num.isInt());
41   EXPECT_EQ(num, 12);
42   num = parseJson("12e5");
43   EXPECT_TRUE(num.isDouble());
44   EXPECT_EQ(num, 12e5);
45   auto numAs1 = num.asDouble();
46   EXPECT_EQ(numAs1, 12e5);
47   EXPECT_EQ(num, 12e5);
48   EXPECT_EQ(num, 1200000);
49
50   auto largeNumber = parseJson("4611686018427387904");
51   EXPECT_TRUE(largeNumber.isInt());
52   EXPECT_EQ(largeNumber, 4611686018427387904L);
53
54   auto negative = parseJson("-123");
55   EXPECT_EQ(negative, -123);
56
57   auto bfalse = parseJson("false");
58   auto btrue = parseJson("true");
59   EXPECT_EQ(bfalse, false);
60   EXPECT_EQ(btrue, true);
61
62   auto null = parseJson("null");
63   EXPECT_TRUE(null == nullptr);
64
65   auto doub1 = parseJson("12.0");
66   auto doub2 = parseJson("12e2");
67   EXPECT_EQ(doub1, 12.0);
68   EXPECT_EQ(doub2, 12e2);
69   EXPECT_EQ(std::numeric_limits<double>::infinity(),
70             parseJson("Infinity").asDouble());
71   EXPECT_EQ(-std::numeric_limits<double>::infinity(),
72             parseJson("-Infinity").asDouble());
73   EXPECT_TRUE(std::isnan(parseJson("NaN").asDouble()));
74
75   // case matters
76   EXPECT_THROW(parseJson("infinity"), std::runtime_error);
77   EXPECT_THROW(parseJson("inf"), std::runtime_error);
78   EXPECT_THROW(parseJson("Inf"), std::runtime_error);
79   EXPECT_THROW(parseJson("INF"), std::runtime_error);
80   EXPECT_THROW(parseJson("nan"), std::runtime_error);
81   EXPECT_THROW(parseJson("NAN"), std::runtime_error);
82
83   auto array = parseJson(
84     "[12,false, false  , null , [12e4,32, [], 12]]");
85   EXPECT_EQ(array.size(), 5);
86   if (array.size() == 5) {
87     EXPECT_EQ(boost::prior(array.end())->size(), 4);
88   }
89
90   EXPECT_THROW(parseJson("\n[12,\n\nnotvalidjson"),
91                std::runtime_error);
92
93   EXPECT_THROW(parseJson("12e2e2"),
94                std::runtime_error);
95
96   EXPECT_THROW(parseJson("{\"foo\":12,\"bar\":42} \"something\""),
97                std::runtime_error);
98
99   dynamic value = dynamic::object
100     ("foo", "bar")
101     ("junk", 12)
102     ("another", 32.2)
103     ("a",
104       dynamic::array(
105         dynamic::object("a", "b")
106                        ("c", "d"),
107         12.5,
108         "Yo Dawg",
109         dynamic::array("heh"),
110         nullptr
111       )
112     )
113     ;
114
115   // Print then parse and get the same thing, hopefully.
116   EXPECT_EQ(value, parseJson(toJson(value)));
117
118
119   // Test an object with non-string values.
120   dynamic something = parseJson(
121     "{\"old_value\":40,\"changed\":true,\"opened\":false}");
122   dynamic expected = dynamic::object
123     ("old_value", 40)
124     ("changed", true)
125     ("opened", false);
126   EXPECT_EQ(something, expected);
127 }
128
129 TEST(Json, ParseTrailingComma) {
130   folly::json::serialization_opts on, off;
131   on.allow_trailing_comma = true;
132   off.allow_trailing_comma = false;
133
134   dynamic arr = dynamic::array(1, 2);
135   EXPECT_EQ(arr, parseJson("[1, 2]", on));
136   EXPECT_EQ(arr, parseJson("[1, 2,]", on));
137   EXPECT_EQ(arr, parseJson("[1, 2, ]", on));
138   EXPECT_EQ(arr, parseJson("[1, 2 , ]", on));
139   EXPECT_EQ(arr, parseJson("[1, 2 ,]", on));
140   EXPECT_THROW(parseJson("[1, 2,]", off), std::runtime_error);
141
142   dynamic obj = dynamic::object("a", 1);
143   EXPECT_EQ(obj, parseJson("{\"a\": 1}", on));
144   EXPECT_EQ(obj, parseJson("{\"a\": 1,}", on));
145   EXPECT_EQ(obj, parseJson("{\"a\": 1, }", on));
146   EXPECT_EQ(obj, parseJson("{\"a\": 1 , }", on));
147   EXPECT_EQ(obj, parseJson("{\"a\": 1 ,}", on));
148   EXPECT_THROW(parseJson("{\"a\":1,}", off), std::runtime_error);
149 }
150
151 TEST(Json, BoolConversion) {
152   EXPECT_TRUE(parseJson("42").asBool());
153 }
154
155 TEST(Json, JavascriptSafe) {
156   auto badDouble = (1ll << 63ll) + 1;
157   dynamic badDyn = badDouble;
158   EXPECT_EQ(folly::toJson(badDouble), folly::to<folly::fbstring>(badDouble));
159   folly::json::serialization_opts opts;
160   opts.javascript_safe = true;
161   EXPECT_ANY_THROW(folly::json::serialize(badDouble, opts));
162
163   auto okDouble = 1ll << 63ll;
164   dynamic okDyn = okDouble;
165   EXPECT_EQ(folly::toJson(okDouble), folly::to<folly::fbstring>(okDouble));
166 }
167
168 TEST(Json, Produce) {
169   auto value = parseJson(R"( "f\"oo" )");
170   EXPECT_EQ(toJson(value), R"("f\"oo")");
171   value = parseJson("\"Control code: \001 \002 \x1f\"");
172   EXPECT_EQ(toJson(value), R"("Control code: \u0001 \u0002 \u001f")");
173
174   // We're not allowed to have non-string keys in json.
175   EXPECT_THROW(toJson(dynamic::object("abc", "xyz")(42.33, "asd")),
176                std::runtime_error);
177
178   // Check Infinity/Nan
179   folly::json::serialization_opts opts;
180   opts.allow_nan_inf = true;
181   EXPECT_EQ("Infinity",
182             folly::json::serialize(parseJson("Infinity"), opts).toStdString());
183   EXPECT_EQ("NaN",
184             folly::json::serialize(parseJson("NaN"), opts).toStdString());
185 }
186
187 TEST(Json, JsonEscape) {
188   folly::json::serialization_opts opts;
189   EXPECT_EQ(
190     folly::json::serialize("\b\f\n\r\x01\t\\\"/\v\a", opts),
191     R"("\b\f\n\r\u0001\t\\\"/\u000b\u0007")");
192 }
193
194 TEST(Json, JsonNonAsciiEncoding) {
195   folly::json::serialization_opts opts;
196   opts.encode_non_ascii = true;
197
198   // simple tests
199   EXPECT_EQ(folly::json::serialize("\x1f", opts), R"("\u001f")");
200   EXPECT_EQ(folly::json::serialize("\xc2\xa2", opts), R"("\u00a2")");
201   EXPECT_EQ(folly::json::serialize("\xe2\x82\xac", opts), R"("\u20ac")");
202
203   // multiple unicode encodings
204   EXPECT_EQ(
205     folly::json::serialize("\x1f\xe2\x82\xac", opts),
206     R"("\u001f\u20ac")");
207   EXPECT_EQ(
208     folly::json::serialize("\x1f\xc2\xa2\xe2\x82\xac", opts),
209     R"("\u001f\u00a2\u20ac")");
210   EXPECT_EQ(
211     folly::json::serialize("\xc2\x80\xef\xbf\xbf", opts),
212     R"("\u0080\uffff")");
213   EXPECT_EQ(
214     folly::json::serialize("\xe0\xa0\x80\xdf\xbf", opts),
215     R"("\u0800\u07ff")");
216
217   // first possible sequence of a certain length
218   EXPECT_EQ(folly::json::serialize("\xc2\x80", opts), R"("\u0080")");
219   EXPECT_EQ(folly::json::serialize("\xe0\xa0\x80", opts), R"("\u0800")");
220
221   // last possible sequence of a certain length
222   EXPECT_EQ(folly::json::serialize("\xdf\xbf", opts), R"("\u07ff")");
223   EXPECT_EQ(folly::json::serialize("\xef\xbf\xbf", opts), R"("\uffff")");
224
225   // other boundary conditions
226   EXPECT_EQ(folly::json::serialize("\xed\x9f\xbf", opts), R"("\ud7ff")");
227   EXPECT_EQ(folly::json::serialize("\xee\x80\x80", opts), R"("\ue000")");
228   EXPECT_EQ(folly::json::serialize("\xef\xbf\xbd", opts), R"("\ufffd")");
229
230   // incomplete sequences
231   EXPECT_ANY_THROW(folly::json::serialize("a\xed\x9f", opts));
232   EXPECT_ANY_THROW(folly::json::serialize("b\xee\x80", opts));
233   EXPECT_ANY_THROW(folly::json::serialize("c\xef\xbf", opts));
234
235   // impossible bytes
236   EXPECT_ANY_THROW(folly::json::serialize("\xfe", opts));
237   EXPECT_ANY_THROW(folly::json::serialize("\xff", opts));
238
239   // Sample overlong sequences
240   EXPECT_ANY_THROW(folly::json::serialize("\xc0\xaf", opts));
241   EXPECT_ANY_THROW(folly::json::serialize("\xe0\x80\xaf", opts));
242
243   // Maximum overlong sequences
244   EXPECT_ANY_THROW(folly::json::serialize("\xc1\xbf", opts));
245   EXPECT_ANY_THROW(folly::json::serialize("\x30\x9f\xbf", opts));
246
247   // illegal code positions
248   EXPECT_ANY_THROW(folly::json::serialize("\xed\xa0\x80", opts));
249   EXPECT_ANY_THROW(folly::json::serialize("\xed\xbf\xbf", opts));
250
251   // Overlong representation of NUL character
252   EXPECT_ANY_THROW(folly::json::serialize("\xc0\x80", opts));
253   EXPECT_ANY_THROW(folly::json::serialize("\xe0\x80\x80", opts));
254
255   // Longer than 3 byte encodings
256   EXPECT_ANY_THROW(folly::json::serialize("\xf4\x8f\xbf\xbf", opts));
257   EXPECT_ANY_THROW(folly::json::serialize("\xed\xaf\xbf\xed\xbf\xbf", opts));
258 }
259
260 TEST(Json, UTF8Retention) {
261
262   // test retention with valid utf8 strings
263   folly::fbstring input = "\u2665";
264   folly::fbstring jsonInput = folly::toJson(input);
265   folly::fbstring output = folly::parseJson(jsonInput).asString();
266   folly::fbstring jsonOutput = folly::toJson(output);
267
268   EXPECT_EQ(input, output);
269   EXPECT_EQ(jsonInput, jsonOutput);
270
271   // test retention with invalid utf8 - note that non-ascii chars are retained
272   // as is, and no unicode encoding is attempted so no exception is thrown.
273   EXPECT_EQ(
274     folly::toJson("a\xe0\xa0\x80z\xc0\x80"),
275     "\"a\xe0\xa0\x80z\xc0\x80\""
276   );
277 }
278
279 TEST(Json, UTF8EncodeNonAsciiRetention) {
280
281   folly::json::serialization_opts opts;
282   opts.encode_non_ascii = true;
283
284   // test encode_non_ascii valid utf8 strings
285   folly::fbstring input = "\u2665";
286   folly::fbstring jsonInput = folly::json::serialize(input, opts);
287   folly::fbstring output = folly::parseJson(jsonInput).asString();
288   folly::fbstring jsonOutput = folly::json::serialize(output, opts);
289
290   EXPECT_EQ(input, output);
291   EXPECT_EQ(jsonInput, jsonOutput);
292
293   // test encode_non_ascii with invalid utf8 - note that an attempt to encode
294   // non-ascii to unicode will result is a utf8 validation and throw exceptions.
295   EXPECT_ANY_THROW(folly::json::serialize("a\xe0\xa0\x80z\xc0\x80", opts));
296   EXPECT_ANY_THROW(folly::json::serialize("a\xe0\xa0\x80z\xe0\x80\x80", opts));
297 }
298
299 TEST(Json, UTF8Validation) {
300   folly::json::serialization_opts opts;
301   opts.validate_utf8 = true;
302
303   // test validate_utf8 valid utf8 strings - note that we only validate the
304   // for utf8 but don't encode non-ascii to unicode so they are retained as is.
305   EXPECT_EQ(folly::json::serialize("a\xc2\x80z", opts), "\"a\xc2\x80z\"");
306   EXPECT_EQ(
307     folly::json::serialize("a\xe0\xa0\x80z", opts),
308     "\"a\xe0\xa0\x80z\"");
309   EXPECT_EQ(
310     folly::json::serialize("a\xe0\xa0\x80m\xc2\x80z", opts),
311     "\"a\xe0\xa0\x80m\xc2\x80z\"");
312
313   // test validate_utf8 with invalid utf8
314   EXPECT_ANY_THROW(folly::json::serialize("a\xe0\xa0\x80z\xc0\x80", opts));
315   EXPECT_ANY_THROW(folly::json::serialize("a\xe0\xa0\x80z\xe0\x80\x80", opts));
316
317   opts.skip_invalid_utf8 = true;
318   EXPECT_EQ(folly::json::serialize("a\xe0\xa0\x80z\xc0\x80", opts),
319             "\"a\xe0\xa0\x80z\ufffd\ufffd\"");
320   EXPECT_EQ(folly::json::serialize("a\xe0\xa0\x80z\xc0\x80\x80", opts),
321             "\"a\xe0\xa0\x80z\ufffd\ufffd\ufffd\"");
322   EXPECT_EQ(folly::json::serialize("z\xc0\x80z\xe0\xa0\x80", opts),
323             "\"z\ufffd\ufffdz\xe0\xa0\x80\"");
324
325   opts.encode_non_ascii = true;
326   EXPECT_EQ(folly::json::serialize("a\xe0\xa0\x80z\xc0\x80", opts),
327             "\"a\\u0800z\\ufffd\\ufffd\"");
328   EXPECT_EQ(folly::json::serialize("a\xe0\xa0\x80z\xc0\x80\x80", opts),
329             "\"a\\u0800z\\ufffd\\ufffd\\ufffd\"");
330   EXPECT_EQ(folly::json::serialize("z\xc0\x80z\xe0\xa0\x80", opts),
331             "\"z\\ufffd\\ufffdz\\u0800\"");
332
333 }
334
335
336 TEST(Json, ParseNonStringKeys) {
337   // test string keys
338   EXPECT_EQ("a", parseJson("{\"a\":[]}").items().begin()->first.asString());
339
340   // check that we don't allow non-string keys as this violates the
341   // strict JSON spec (though it is emitted by the output of
342   // folly::dynamic with operator <<).
343   EXPECT_THROW(parseJson("{1:[]}"), std::runtime_error);
344
345   // check that we can parse colloquial JSON if the option is set
346   folly::json::serialization_opts opts;
347   opts.allow_non_string_keys = true;
348
349   auto val = parseJson("{1:[]}", opts);
350   EXPECT_EQ(1, val.items().begin()->first.asInt());
351
352
353   // test we can still read in strings
354   auto sval = parseJson("{\"a\":[]}", opts);
355   EXPECT_EQ("a", sval.items().begin()->first.asString());
356
357   // test we can read in doubles
358   auto dval = parseJson("{1.5:[]}", opts);
359   EXPECT_EQ(1.5, dval.items().begin()->first.asDouble());
360 }
361
362 TEST(Json, ParseDoubleFallback) {
363   // default behavior
364   EXPECT_THROW(parseJson("{\"a\":847605071342477600000000000000}"),
365       std::range_error);
366   EXPECT_THROW(parseJson("{\"a\":-9223372036854775809}"),
367       std::range_error);
368   EXPECT_THROW(parseJson("{\"a\":9223372036854775808}"),
369       std::range_error);
370   EXPECT_EQ(std::numeric_limits<int64_t>::min(),
371       parseJson("{\"a\":-9223372036854775808}").items().begin()
372         ->second.asInt());
373   EXPECT_EQ(std::numeric_limits<int64_t>::max(),
374       parseJson("{\"a\":9223372036854775807}").items().begin()->second.asInt());
375   // with double_fallback
376   folly::json::serialization_opts opts;
377   opts.double_fallback = true;
378   EXPECT_EQ(847605071342477600000000000000.0,
379       parseJson("{\"a\":847605071342477600000000000000}",
380         opts).items().begin()->second.asDouble());
381   EXPECT_EQ(847605071342477600000000000000.0,
382       parseJson("{\"a\": 847605071342477600000000000000}",
383         opts).items().begin()->second.asDouble());
384   EXPECT_EQ(847605071342477600000000000000.0,
385       parseJson("{\"a\":847605071342477600000000000000 }",
386         opts).items().begin()->second.asDouble());
387   EXPECT_EQ(847605071342477600000000000000.0,
388       parseJson("{\"a\": 847605071342477600000000000000 }",
389         opts).items().begin()->second.asDouble());
390   EXPECT_EQ(std::numeric_limits<int64_t>::min(),
391       parseJson("{\"a\":-9223372036854775808}",
392         opts).items().begin()->second.asInt());
393   EXPECT_EQ(std::numeric_limits<int64_t>::max(),
394       parseJson("{\"a\":9223372036854775807}",
395         opts).items().begin()->second.asInt());
396   // show that some precision gets lost
397   EXPECT_EQ(847605071342477612345678900000.0,
398       parseJson("{\"a\":847605071342477612345678912345}",
399         opts).items().begin()->second.asDouble());
400 }
401
402 TEST(Json, ParseNumbersAsStrings) {
403   folly::json::serialization_opts opts;
404   opts.parse_numbers_as_strings = true;
405   auto parse = [&](folly::fbstring number) {
406     return parseJson(number, opts).asString();
407   };
408
409   EXPECT_EQ("0", parse("0"));
410   EXPECT_EQ("1234", parse("1234"));
411   EXPECT_EQ("3.00", parse("3.00"));
412   EXPECT_EQ("3.14", parse("3.14"));
413   EXPECT_EQ("0.1234", parse("0.1234"));
414   EXPECT_EQ("0.0", parse("0.0"));
415   EXPECT_EQ("46845131213548676854213265486468451312135486768542132",
416       parse("46845131213548676854213265486468451312135486768542132"));
417   EXPECT_EQ("-468451312135486768542132654864684513121354867685.5e4",
418       parse("-468451312135486768542132654864684513121354867685.5e4"));
419   EXPECT_EQ("6.62607004e-34", parse("6.62607004e-34"));
420   EXPECT_EQ("6.62607004E+34", parse("6.62607004E+34"));
421   EXPECT_EQ("Infinity", parse("Infinity"));
422   EXPECT_EQ("-Infinity", parse("-Infinity"));
423   EXPECT_EQ("NaN", parse("NaN"));
424
425   EXPECT_THROW(parse("ThisIsWrong"), std::runtime_error);
426   EXPECT_THROW(parse("34-2"), std::runtime_error);
427   EXPECT_THROW(parse(""), std::runtime_error);
428   EXPECT_THROW(parse("-"), std::runtime_error);
429   EXPECT_THROW(parse("34-e2"), std::runtime_error);
430   EXPECT_THROW(parse("34e2.4"), std::runtime_error);
431   EXPECT_THROW(parse("infinity"), std::runtime_error);
432   EXPECT_THROW(parse("nan"), std::runtime_error);
433 }
434
435 TEST(Json, SortKeys) {
436   folly::json::serialization_opts opts_on, opts_off;
437   opts_on.sort_keys = true;
438   opts_off.sort_keys = false;
439
440   dynamic value = dynamic::object
441     ("foo", "bar")
442     ("junk", 12)
443     ("another", 32.2)
444     ("a",
445       dynamic::array(
446         dynamic::object("a", "b")
447                        ("c", "d"),
448         12.5,
449         "Yo Dawg",
450         dynamic::array("heh"),
451         nullptr
452       )
453     )
454     ;
455
456   std::string sorted_keys =
457     R"({"a":[{"a":"b","c":"d"},12.5,"Yo Dawg",["heh"],null],)"
458     R"("another":32.2,"foo":"bar","junk":12})";
459
460   EXPECT_EQ(value, parseJson(folly::json::serialize(value, opts_on)));
461   EXPECT_EQ(value, parseJson(folly::json::serialize(value, opts_off)));
462
463   EXPECT_EQ(sorted_keys, folly::json::serialize(value, opts_on));
464 }
465
466 TEST(Json, PrintTo) {
467   std::ostringstream oss;
468
469   dynamic value = dynamic::object
470     ("foo", "bar")
471     ("junk", 12)
472     ("another", 32.2)
473     (true, false) // include non-string keys
474     (false, true)
475     (2, 3)
476     (0, 1)
477     (1, 2)
478     (1.5, 2.25)
479     (0.5, 0.25)
480     (0, 1)
481     (1, 2)
482     ("a",
483       dynamic::array(
484         dynamic::object("a", "b")
485                        ("c", "d"),
486         12.5,
487         "Yo Dawg",
488         dynamic::array("heh"),
489         nullptr
490       )
491     )
492     ;
493
494   std::string expected =
495       R"({
496   false : true,
497   true : false,
498   0.5 : 0.25,
499   1.5 : 2.25,
500   0 : 1,
501   1 : 2,
502   2 : 3,
503   "a" : [
504     {
505       "a" : "b",
506       "c" : "d"
507     },
508     12.5,
509     "Yo Dawg",
510     [
511       "heh"
512     ],
513     null
514   ],
515   "another" : 32.2,
516   "foo" : "bar",
517   "junk" : 12
518 })";
519   PrintTo(value, &oss);
520   EXPECT_EQ(expected, oss.str());
521 }