2 * Copyright 2012 Facebook, Inc.
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
8 * http://www.apache.org/licenses/LICENSE-2.0
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.
17 #include "folly/json.h"
18 #include <gtest/gtest.h>
19 #include <gflags/gflags.h>
23 #include <boost/next_prior.hpp>
24 #include "folly/Benchmark.h"
27 using folly::parseJson;
31 auto val = parseJson("\"I \u2665 UTF-8\"");
32 EXPECT_EQ("I \u2665 UTF-8", val.asString());
33 val = parseJson("\"I \\u2665 UTF-8\"");
34 EXPECT_EQ("I \u2665 UTF-8", val.asString());
35 val = parseJson("\"I \U0001D11E playing in G-clef\"");
36 EXPECT_EQ("I \U0001D11E playing in G-clef", val.asString());
38 val = parseJson("\"I \\uD834\\uDD1E playing in G-clef\"");
39 EXPECT_EQ("I \U0001D11E playing in G-clef", val.asString());
43 auto num = parseJson("12");
44 EXPECT_TRUE(num.isInt());
46 num = parseJson("12e5");
47 EXPECT_TRUE(num.isDouble());
49 auto numAs1 = num.asDouble();
50 EXPECT_EQ(numAs1, 12e5);
52 EXPECT_EQ(num, 1200000);
54 auto largeNumber = parseJson("4611686018427387904");
55 EXPECT_TRUE(largeNumber.isInt());
56 EXPECT_EQ(largeNumber, 4611686018427387904L);
58 auto negative = parseJson("-123");
59 EXPECT_EQ(negative, -123);
61 auto bfalse = parseJson("false");
62 auto btrue = parseJson("true");
63 EXPECT_EQ(bfalse, false);
64 EXPECT_EQ(btrue, true);
66 auto null = parseJson("null");
67 EXPECT_TRUE(null == nullptr);
69 auto doub1 = parseJson("12.0");
70 auto doub2 = parseJson("12e2");
71 EXPECT_EQ(doub1, 12.0);
72 EXPECT_EQ(doub2, 12e2);
73 EXPECT_EQ(std::numeric_limits<double>::infinity(),
74 parseJson("Infinity").asDouble());
75 EXPECT_EQ(-std::numeric_limits<double>::infinity(),
76 parseJson("-Infinity").asDouble());
77 EXPECT_TRUE(std::isnan(parseJson("NaN").asDouble()));
78 EXPECT_THROW(parseJson("infinity"), std::runtime_error);
79 EXPECT_THROW(parseJson("inf"), std::runtime_error);
80 EXPECT_THROW(parseJson("nan"), std::runtime_error);
82 auto array = parseJson(
83 "[12,false, false , null , [12e4,32, [], 12]]");
84 EXPECT_EQ(array.size(), 5);
85 if (array.size() == 5) {
86 EXPECT_EQ(boost::prior(array.end())->size(), 4);
91 parseJson("\n[12,\n\nnotvalidjson");
92 } catch (const std::exception& e) {
100 } catch (const std::exception& e) {
107 parseJson("{\"foo\":12,\"bar\":42} \"something\"");
108 } catch (const std::exception& e) {
114 dynamic anotherVal = dynamic::object
120 dynamic::object("a", "b")
130 // Print then parse and get the same thing, hopefully.
131 auto value = parseJson(toJson(anotherVal));
132 EXPECT_EQ(value, anotherVal);
134 // Test an object with non-string values.
135 dynamic something = folly::parseJson(
136 "{\"old_value\":40,\"changed\":true,\"opened\":false}");
137 dynamic expected = dynamic::object
141 EXPECT_EQ(something, expected);
144 TEST(Json, JavascriptSafe) {
145 auto badDouble = (1ll << 63ll) + 1;
146 dynamic badDyn = badDouble;
147 EXPECT_EQ(folly::toJson(badDouble), folly::to<folly::fbstring>(badDouble));
148 folly::json::serialization_opts opts;
149 opts.javascript_safe = true;
150 EXPECT_ANY_THROW(folly::json::serialize(badDouble, opts));
152 auto okDouble = 1ll << 63ll;
153 dynamic okDyn = okDouble;
154 EXPECT_EQ(folly::toJson(okDouble), folly::to<folly::fbstring>(okDouble));
157 TEST(Json, Produce) {
158 auto value = parseJson(R"( "f\"oo" )");
159 EXPECT_EQ(toJson(value), R"("f\"oo")");
160 value = parseJson("\"Control code: \001 \002 \x1f\"");
161 EXPECT_EQ(toJson(value), R"("Control code: \u0001 \u0002 \u001f")");
165 dynamic d = dynamic::object;
168 auto str = toJson(d);
169 } catch (std::exception const& e) {
170 // We're not allowed to have non-string keys in json.
176 TEST(Json, JsonNonAsciiEncoding) {
177 folly::json::serialization_opts opts;
178 opts.encode_non_ascii = true;
181 EXPECT_EQ(folly::json::serialize("\x1f", opts), R"("\u001f")");
182 EXPECT_EQ(folly::json::serialize("\xc2\xa2", opts), R"("\u00a2")");
183 EXPECT_EQ(folly::json::serialize("\xe2\x82\xac", opts), R"("\u20ac")");
185 // multiple unicode encodings
187 folly::json::serialize("\x1f\xe2\x82\xac", opts),
188 R"("\u001f\u20ac")");
190 folly::json::serialize("\x1f\xc2\xa2\xe2\x82\xac", opts),
191 R"("\u001f\u00a2\u20ac")");
193 folly::json::serialize("\xc2\x80\xef\xbf\xbf", opts),
194 R"("\u0080\uffff")");
196 folly::json::serialize("\xe0\xa0\x80\xdf\xbf", opts),
197 R"("\u0800\u07ff")");
199 // first possible sequence of a certain length
200 EXPECT_EQ(folly::json::serialize("\xc2\x80", opts), R"("\u0080")");
201 EXPECT_EQ(folly::json::serialize("\xe0\xa0\x80", opts), R"("\u0800")");
203 // last possible sequence of a certain length
204 EXPECT_EQ(folly::json::serialize("\xdf\xbf", opts), R"("\u07ff")");
205 EXPECT_EQ(folly::json::serialize("\xef\xbf\xbf", opts), R"("\uffff")");
207 // other boundary conditions
208 EXPECT_EQ(folly::json::serialize("\xed\x9f\xbf", opts), R"("\ud7ff")");
209 EXPECT_EQ(folly::json::serialize("\xee\x80\x80", opts), R"("\ue000")");
210 EXPECT_EQ(folly::json::serialize("\xef\xbf\xbd", opts), R"("\ufffd")");
212 // incomplete sequences
213 EXPECT_ANY_THROW(folly::json::serialize("a\xed\x9f", opts));
214 EXPECT_ANY_THROW(folly::json::serialize("b\xee\x80", opts));
215 EXPECT_ANY_THROW(folly::json::serialize("c\xef\xbf", opts));
218 EXPECT_ANY_THROW(folly::json::serialize("\xfe", opts));
219 EXPECT_ANY_THROW(folly::json::serialize("\xff", opts));
221 // Sample overlong sequences
222 EXPECT_ANY_THROW(folly::json::serialize("\xc0\xaf", opts));
223 EXPECT_ANY_THROW(folly::json::serialize("\xe0\x80\xaf", opts));
225 // Maximum overlong sequences
226 EXPECT_ANY_THROW(folly::json::serialize("\xc1\xbf", opts));
227 EXPECT_ANY_THROW(folly::json::serialize("\x30\x9f\xbf", opts));
229 // illegal code positions
230 EXPECT_ANY_THROW(folly::json::serialize("\xed\xa0\x80", opts));
231 EXPECT_ANY_THROW(folly::json::serialize("\xed\xbf\xbf", opts));
233 // Overlong representation of NUL character
234 EXPECT_ANY_THROW(folly::json::serialize("\xc0\x80", opts));
235 EXPECT_ANY_THROW(folly::json::serialize("\xe0\x80\x80", opts));
237 // Longer than 3 byte encodings
238 EXPECT_ANY_THROW(folly::json::serialize("\xf4\x8f\xbf\xbf", opts));
239 EXPECT_ANY_THROW(folly::json::serialize("\xed\xaf\xbf\xed\xbf\xbf", opts));
242 TEST(Json, UTF8Validation) {
243 folly::json::serialization_opts opts;
244 opts.validate_utf8 = true;
246 // valid utf8 strings
247 EXPECT_EQ(folly::json::serialize("a\xc2\x80z", opts), R"("a\u00c2\u0080z")");
249 folly::json::serialize("a\xe0\xa0\x80z", opts),
250 R"("a\u00e0\u00a0\u0080z")");
252 folly::json::serialize("a\xe0\xa0\x80m\xc2\x80z", opts),
253 R"("a\u00e0\u00a0\u0080m\u00c2\u0080z")");
255 // test with invalid utf8
256 EXPECT_ANY_THROW(folly::json::serialize("a\xe0\xa0\x80z\xc0\x80", opts));
257 EXPECT_ANY_THROW(folly::json::serialize("a\xe0\xa0\x80z\xe0\x80\x80", opts));
260 BENCHMARK(jsonSerialize, iters) {
261 folly::json::serialization_opts opts;
262 for (int i = 0; i < iters; ++i) {
263 folly::json::serialize(
264 "qwerty \xc2\x80 \xef\xbf\xbf poiuy"
265 "qwerty \xc2\x80 \xef\xbf\xbf poiuy"
266 "qwerty \xc2\x80 \xef\xbf\xbf poiuy"
267 "qwerty \xc2\x80 \xef\xbf\xbf poiuy"
268 "qwerty \xc2\x80 \xef\xbf\xbf poiuy"
269 "qwerty \xc2\x80 \xef\xbf\xbf poiuy"
270 "qwerty \xc2\x80 \xef\xbf\xbf poiuy"
271 "qwerty \xc2\x80 \xef\xbf\xbf poiuy"
272 "qwerty \xc2\x80 \xef\xbf\xbf poiuy"
273 "qwerty \xc2\x80 \xef\xbf\xbf poiuy",
278 BENCHMARK(jsonSerializeWithNonAsciiEncoding, iters) {
279 folly::json::serialization_opts opts;
280 opts.encode_non_ascii = true;
282 for (int i = 0; i < iters; ++i) {
283 folly::json::serialize(
284 "qwerty \xc2\x80 \xef\xbf\xbf poiuy"
285 "qwerty \xc2\x80 \xef\xbf\xbf poiuy"
286 "qwerty \xc2\x80 \xef\xbf\xbf poiuy"
287 "qwerty \xc2\x80 \xef\xbf\xbf poiuy"
288 "qwerty \xc2\x80 \xef\xbf\xbf poiuy"
289 "qwerty \xc2\x80 \xef\xbf\xbf poiuy"
290 "qwerty \xc2\x80 \xef\xbf\xbf poiuy"
291 "qwerty \xc2\x80 \xef\xbf\xbf poiuy"
292 "qwerty \xc2\x80 \xef\xbf\xbf poiuy"
293 "qwerty \xc2\x80 \xef\xbf\xbf poiuy",
298 BENCHMARK(jsonSerializeWithUtf8Validation, iters) {
299 folly::json::serialization_opts opts;
300 opts.validate_utf8 = true;
302 for (int i = 0; i < iters; ++i) {
303 folly::json::serialize(
304 "qwerty \xc2\x80 \xef\xbf\xbf poiuy"
305 "qwerty \xc2\x80 \xef\xbf\xbf poiuy"
306 "qwerty \xc2\x80 \xef\xbf\xbf poiuy"
307 "qwerty \xc2\x80 \xef\xbf\xbf poiuy"
308 "qwerty \xc2\x80 \xef\xbf\xbf poiuy"
309 "qwerty \xc2\x80 \xef\xbf\xbf poiuy"
310 "qwerty \xc2\x80 \xef\xbf\xbf poiuy"
311 "qwerty \xc2\x80 \xef\xbf\xbf poiuy"
312 "qwerty \xc2\x80 \xef\xbf\xbf poiuy"
313 "qwerty \xc2\x80 \xef\xbf\xbf poiuy",
318 BENCHMARK(parseSmallStringWithUtf, iters) {
319 for (int i = 0; i < iters << 4; ++i) {
320 parseJson("\"I \\u2665 UTF-8 thjasdhkjh blah blah blah\"");
324 BENCHMARK(parseNormalString, iters) {
325 for (int i = 0; i < iters << 4; ++i) {
326 parseJson("\"akjhfk jhkjlakjhfk jhkjlakjhfk jhkjl akjhfk\"");
330 BENCHMARK(parseBigString, iters) {
331 for (int i = 0; i < iters; ++i) {
333 "akjhfk jhkjlakjhfk jhkjlakjhfk jhkjl akjhfk"
334 "akjhfk jhkjlakjhfk jhkjlakjhfk jhkjl akjhfk"
335 "akjhfk jhkjlakjhfk jhkjlakjhfk jhkjl akjhfk"
336 "akjhfk jhkjlakjhfk jhkjlakjhfk jhkjl akjhfk"
337 "akjhfk jhkjlakjhfk jhkjlakjhfk jhkjl akjhfk"
338 "akjhfk jhkjlakjhfk jhkjlakjhfk jhkjl akjhfk"
339 "akjhfk jhkjlakjhfk jhkjlakjhfk jhkjl akjhfk"
340 "akjhfk jhkjlakjhfk jhkjlakjhfk jhkjl akjhfk"
341 "akjhfk jhkjlakjhfk jhkjlakjhfk jhkjl akjhfk"
342 "akjhfk jhkjlakjhfk jhkjlakjhfk jhkjl akjhfk"
343 "akjhfk jhkjlakjhfk jhkjlakjhfk jhkjl akjhfk"
348 int main(int argc, char** argv) {
349 testing::InitGoogleTest(&argc, argv);
350 google::ParseCommandLineFlags(&argc, &argv, true);
351 if (FLAGS_benchmark) {
352 folly::runBenchmarks();
354 return RUN_ALL_TESTS();