1 #include <boost/property_tree/json_parser/detail/parser.hpp>
2 #include <boost/property_tree/json_parser/detail/narrow_encoding.hpp>
3 #include <boost/property_tree/json_parser/detail/wide_encoding.hpp>
4 #include <boost/property_tree/json_parser/detail/standard_callbacks.hpp>
5 #include "prefixing_callbacks.hpp"
6
7 #include <boost/core/lightweight_test.hpp>
8
9 #include <boost/property_tree/ptree.hpp>
10 #include <boost/range/iterator_range.hpp>
11
12 #include <cassert>
13 #include <sstream>
14 #include <vector>
15 #include <algorithm>
16
17 using namespace boost::property_tree;
18
19 template <typename Ch> struct encoding;
20 template <> struct encoding<char>
21 : json_parser::detail::utf8_utf8_encoding
22 {};
23 template <> struct encoding<wchar_t>
24 : json_parser::detail::wide_wide_encoding
25 {};
26
27 template <typename Callbacks, typename Ch>
28 struct test_parser
29 {
30 Callbacks callbacks;
31 ::encoding<Ch> encoding;
32 typedef std::basic_string<Ch> string;
33 typedef basic_ptree<string, string> tree;
34 json_parser::detail::parser<Callbacks, ::encoding<Ch>,
35 typename string::const_iterator,
36 typename string::const_iterator>
37 parser;
38
test_parsertest_parser39 test_parser() : parser(callbacks, encoding) {}
40
parse_nulltest_parser41 bool parse_null(const string& input, string& output) {
42 parser.set_input("", input);
43 bool result = parser.parse_null();
44 if (result) {
45 parser.finish();
46 output = callbacks.output().data();
47 }
48 return result;
49 }
50
parse_booleantest_parser51 bool parse_boolean(const string& input, string& output) {
52 parser.set_input("", input);
53 bool result = parser.parse_boolean();
54 if (result) {
55 parser.finish();
56 output = callbacks.output().data();
57 }
58 return result;
59 }
60
parse_numbertest_parser61 bool parse_number(const string& input, string& output) {
62 parser.set_input("", input);
63 bool result = parser.parse_number();
64 if (result) {
65 parser.finish();
66 output = callbacks.output().data();
67 }
68 return result;
69 }
70
parse_stringtest_parser71 bool parse_string(const string& input, string& output) {
72 parser.set_input("", input);
73 bool result = parser.parse_string();
74 if (result) {
75 parser.finish();
76 output = callbacks.output().data();
77 }
78 return result;
79 }
80
parse_arraytest_parser81 bool parse_array(const string& input, tree& output) {
82 parser.set_input("", input);
83 bool result = parser.parse_array();
84 if (result) {
85 parser.finish();
86 output = callbacks.output();
87 }
88 return result;
89 }
90
parse_objecttest_parser91 bool parse_object(const string& input, tree& output) {
92 parser.set_input("", input);
93 bool result = parser.parse_object();
94 if (result) {
95 parser.finish();
96 output = callbacks.output();
97 }
98 return result;
99 }
100
parse_valuetest_parser101 void parse_value(const string& input, tree& output) {
102 parser.set_input("", input);
103 parser.parse_value();
104 parser.finish();
105 output = callbacks.output();
106 }
107 };
108
109 template <typename Ch>
110 struct standard_parser
111 : test_parser<
112 json_parser::detail::standard_callbacks<
113 basic_ptree<std::basic_string<Ch>, std::basic_string<Ch> > >,
114 Ch>
115 {};
116
117 template <typename Ch>
118 struct prefixing_parser
119 : test_parser<
120 prefixing_callbacks<
121 basic_ptree<std::basic_string<Ch>, std::basic_string<Ch> > >,
122 Ch>
123 {};
124
125 #define BOM_N "\xef\xbb\xbf"
126 #define BOM_W L"\xfeff"
127
128 static void
test_null_parse_result_is_input()129 test_null_parse_result_is_input()
130 {
131 std::string parsed;
132 standard_parser<char> p;
133 BOOST_TEST(p.parse_null("null", parsed));
134 BOOST_TEST_EQ("null", parsed);
135 }
136
137 static void
test_uses_traits_from_null()138 test_uses_traits_from_null()
139 {
140 std::string parsed;
141 prefixing_parser<char> p;
142 BOOST_TEST(p.parse_null("null", parsed));
143 BOOST_TEST_EQ("_:null", parsed);
144 }
145
146 static void
test_null_parse_skips_bom()147 test_null_parse_skips_bom()
148 {
149 std::string parsed;
150 standard_parser<char> p;
151 BOOST_TEST(p.parse_null(BOM_N "null", parsed));
152 BOOST_TEST_EQ("null", parsed);
153 }
154
155 static void
test_null_parse_result_is_input_w()156 test_null_parse_result_is_input_w()
157 {
158 std::wstring parsed;
159 standard_parser<wchar_t> p;
160 BOOST_TEST(p.parse_null(L"null", parsed));
161 BOOST_TEST(parsed == L"null");
162 }
163
164 static void
test_uses_traits_from_null_w()165 test_uses_traits_from_null_w()
166 {
167 std::wstring parsed;
168 prefixing_parser<wchar_t> p;
169 BOOST_TEST(p.parse_null(L"null", parsed));
170 BOOST_TEST(parsed == L"_:null");
171 }
172
173 static void
test_null_parse_skips_bom_w()174 test_null_parse_skips_bom_w()
175 {
176 std::wstring parsed;
177 standard_parser<wchar_t> p;
178 BOOST_TEST(p.parse_null(BOM_W L"null", parsed));
179 BOOST_TEST(parsed == L"null");
180 }
181
182 template<std::size_t N>
183 static void
test_boolean_parse_result_is_input_n(const std::string (& param)[N])184 test_boolean_parse_result_is_input_n(const std::string (¶m)[N])
185 {
186 for(std::size_t i = 0 ; i < N ; ++i)
187 {
188 std::string parsed;
189 standard_parser<char> p;
190 BOOST_TEST(p.parse_boolean(param[i], parsed));
191 BOOST_TEST_EQ(param[i], parsed);
192 }
193 }
194
195 const std::string
196 booleans_n[] = { "true", "false" };
197
198 static void
test_uses_traits_from_boolean_n()199 test_uses_traits_from_boolean_n()
200 {
201 std::string parsed;
202 prefixing_parser<char> p;
203 BOOST_TEST(p.parse_boolean("true", parsed));
204 BOOST_TEST_EQ("b:true", parsed);
205 }
206
207 template<std::size_t N>
208 static void
test_boolean_parse_result_is_input_w(const std::wstring (& param)[N])209 test_boolean_parse_result_is_input_w(const std::wstring (¶m)[N])
210 {
211 for(std::size_t i = 0 ; i < N ; ++i)
212 {
213 std::wstring parsed;
214 standard_parser<wchar_t> p;
215 BOOST_TEST(p.parse_boolean(param[i], parsed));
216 BOOST_TEST(param[i] == parsed);
217 }
218 }
219
220 const std::wstring
221 booleans_w[] = { L"true", L"false" };
222
223 static void
test_uses_traits_from_boolean_w()224 test_uses_traits_from_boolean_w()
225 {
226 std::wstring parsed;
227 prefixing_parser<wchar_t> p;
228 BOOST_TEST(p.parse_boolean(L"true", parsed));
229 BOOST_TEST(parsed == L"b:true");
230 }
231
232 template<std::size_t N>
233 static void
test_number_parse_result_is_input_n(std::string const (& param)[N])234 test_number_parse_result_is_input_n(std::string const (¶m)[N])
235 {
236 for(std::size_t i = 0 ; i < N ; ++i)
237 {
238 std::string parsed;
239 standard_parser<char> p;
240 BOOST_TEST(p.parse_number(param[i], parsed));
241 BOOST_TEST_EQ(param[i], parsed);
242 }
243 }
244
245 std::string const
246 numbers_n[] = {
247 "0",
248 "-0",
249 "1824",
250 "-0.1",
251 "123.142",
252 "1e+0",
253 "1E-0",
254 "1.1e134"
255 };
256
257 static void
test_uses_traits_from_number_n()258 test_uses_traits_from_number_n()
259 {
260 std::string parsed;
261 prefixing_parser<char> p;
262 BOOST_TEST(p.parse_number("12345", parsed));
263 BOOST_TEST_EQ("n:12345", parsed);
264 }
265
266 template<std::size_t N>
267 static void
test_number_parse_result_is_input_w(const std::wstring (& param)[N])268 test_number_parse_result_is_input_w(const std::wstring (¶m)[N])
269 {
270 for(std::size_t i = 0 ; i < N ; ++i)
271 {
272 std::wstring parsed;
273 standard_parser<wchar_t> p;
274 BOOST_TEST(p.parse_number(param[i], parsed));
275 BOOST_TEST(parsed == param[i]);
276 }
277 }
278
279 std::wstring const numbers_w[] = {
280 L"0",
281 L"-0",
282 L"1824",
283 L"-0.1",
284 L"123.142",
285 L"1e+0",
286 L"1E-0",
287 L"1.1e134"
288 };
289
290 static void
test_uses_traits_from_number_w()291 test_uses_traits_from_number_w()
292 {
293 std::wstring parsed;
294 prefixing_parser<wchar_t> p;
295 BOOST_TEST(p.parse_number(L"12345", parsed));
296 BOOST_TEST(parsed == L"n:12345");
297 }
298
299 struct string_input_n {
300 const char* encoded;
301 const char* expected;
302 };
303
304 template<std::size_t N>
test_string_parsed_correctly_n(string_input_n const (& param)[N])305 void test_string_parsed_correctly_n(string_input_n const (¶m)[N])
306 {
307 for(std::size_t i = 0 ; i < N ; ++i)
308 {
309 std::string parsed;
310 standard_parser<char> p;
311 BOOST_TEST(p.parse_string(param[i].encoded, parsed));
312 BOOST_TEST_EQ(param[i].expected, parsed);
313 }
314 }
315
316 const string_input_n strings_n[] = {
317 {"\"\"", ""},
318 {"\"abc\"", "abc"},
319 {"\"a\\nb\"", "a\nb"},
320 {"\"\\\"\"", "\""},
321 {"\"\\\\\"", "\\"},
322 {"\"\\/\"", "/"},
323 {"\"\\b\"", "\b"},
324 {"\"\\f\"", "\f"},
325 {"\"\\r\"", "\r"},
326 {"\"\\t\"", "\t"},
327 {"\"\\u0001\\u00f2\\u28Ec\"", "\x01" "\xC3\xB2" "\xE2\xA3\xAC"},
328 {"\"\\ud801\\udc37\"", "\xf0\x90\x90\xb7"}, // U+10437
329 {"\xef\xbb\xbf\"\"", ""} // BOM
330 };
331
332 static void
test_uses_string_callbacks()333 test_uses_string_callbacks()
334 {
335 std::string parsed;
336 prefixing_parser<char> p;
337 BOOST_TEST(p.parse_string("\"a\"", parsed));
338 BOOST_TEST_EQ("s:a", parsed);
339 }
340
341 struct string_input_w {
342 const wchar_t* encoded;
343 const wchar_t* expected;
344 };
345
346 template<std::size_t N>
347 void
test_string_parsed_correctly_w(string_input_w const (& param)[N])348 test_string_parsed_correctly_w(string_input_w const (¶m)[N])
349 {
350 for(std::size_t i = 0 ; i < N ; ++i)
351 {
352 std::wstring parsed;
353 standard_parser<wchar_t> p;
354 if(BOOST_TEST(p.parse_string(param[i].encoded, parsed)))
355 BOOST_TEST(param[i].expected == parsed);
356 }
357 }
358
359 const string_input_w strings_w[] = {
360 {L"\"\"", L""},
361 {L"\"abc\"", L"abc"},
362 {L"\"a\\nb\"", L"a\nb"},
363 {L"\"\\\"\"", L"\""},
364 {L"\"\\\\\"", L"\\"},
365 {L"\"\\/\"", L"/"},
366 {L"\"\\b\"", L"\b"},
367 {L"\"\\f\"", L"\f"},
368 {L"\"\\r\"", L"\r"},
369 {L"\"\\t\"", L"\t"},
370 {L"\"\\u0001\\u00f2\\u28Ec\"", L"\x0001" L"\x00F2" L"\x28EC"},
371 {L"\xfeff\"\"", L""} // BOM
372 };
373
374 static void
test_empty_array()375 test_empty_array()
376 {
377 ptree tree;
378 standard_parser<char> p;
379 const char* input = " [ ]";
380 BOOST_TEST(p.parse_array(input, tree));
381 BOOST_TEST_EQ("", tree.data());
382 BOOST_TEST_EQ(0u, tree.size());
383 }
384
385 static void
test_array_gets_tagged()386 test_array_gets_tagged()
387 {
388 wptree tree;
389 prefixing_parser<wchar_t> p;
390 const wchar_t* input = L" [ ]";
391 BOOST_TEST(p.parse_array(input, tree));
392 BOOST_TEST(tree.data() == L"a:");
393 BOOST_TEST_EQ(0u, tree.size());
394 }
395
396 static void
test_array_with_values()397 test_array_with_values()
398 {
399 wptree tree;
400 standard_parser<wchar_t> p;
401 const wchar_t* input = L"[\n"
402 L" 123, \"abc\" ,true ,\n"
403 L" null\n"
404 L" ]";
405 if(!BOOST_TEST(p.parse_array(input, tree)))
406 return;
407 if(!BOOST_TEST_EQ(4u, tree.size()))
408 return;
409 wptree::iterator it = tree.begin();
410 BOOST_TEST(it->first == L"");
411 BOOST_TEST(it->second.data() == L"123");
412 ++it;
413 BOOST_TEST(it->first == L"");
414 BOOST_TEST(it->second.data() == L"abc");
415 ++it;
416 BOOST_TEST(it->first == L"");
417 BOOST_TEST(it->second.data() == L"true");
418 ++it;
419 BOOST_TEST(it->first == L"");
420 BOOST_TEST(it->second.data() == L"null");
421 ++it;
422 BOOST_TEST(tree.end() == it);
423 }
424
425 static void
test_array_values_get_tagged()426 test_array_values_get_tagged()
427 {
428 ptree tree;
429 prefixing_parser<char> p;
430 const char* input = "[\n"
431 " 123, \"abc\" ,true ,\n"
432 " null\n"
433 " ]";
434 if(BOOST_TEST(p.parse_array(input, tree)))
435 if(BOOST_TEST_EQ(4u, tree.size()))
436 {
437 BOOST_TEST_EQ("a:", tree.data());
438 ptree::iterator it = tree.begin();
439 BOOST_TEST_EQ("", it->first);
440 BOOST_TEST_EQ("n:123", it->second.data());
441 ++it;
442 BOOST_TEST_EQ("", it->first);
443 BOOST_TEST_EQ("s:abc", it->second.data());
444 ++it;
445 BOOST_TEST_EQ("", it->first);
446 BOOST_TEST_EQ("b:true", it->second.data());
447 ++it;
448 BOOST_TEST_EQ("", it->first);
449 BOOST_TEST_EQ("_:null", it->second.data());
450 ++it;
451 BOOST_TEST(tree.end() == it);
452 }
453 }
454
455 static void
test_nested_array()456 test_nested_array()
457 {
458 ptree tree;
459 standard_parser<char> p;
460 const char* input = "[[1,2],3,[4,5]]";
461 if(!BOOST_TEST(p.parse_array(input, tree)))
462 return;
463 if(!BOOST_TEST_EQ(3u, tree.size()))
464 return;
465 ptree::iterator it = tree.begin();
466 BOOST_TEST_EQ("", it->first);
467 {
468 ptree& sub = it->second;
469 BOOST_TEST_EQ("", sub.data());
470 if(!BOOST_TEST_EQ(2u, sub.size()))
471 return;
472 ptree::iterator iit = sub.begin();
473 BOOST_TEST_EQ("", iit->first);
474 BOOST_TEST_EQ("1", iit->second.data());
475 ++iit;
476 BOOST_TEST_EQ("", iit->first);
477 BOOST_TEST_EQ("2", iit->second.data());
478 ++iit;
479 BOOST_TEST(sub.end() == iit);
480 }
481 ++it;
482 BOOST_TEST_EQ("", it->first);
483 BOOST_TEST_EQ("3", it->second.data());
484 ++it;
485 BOOST_TEST_EQ("", it->first);
486 {
487 ptree& sub = it->second;
488 BOOST_TEST_EQ("", sub.data());
489 if(!BOOST_TEST_EQ(2u, sub.size()))
490 return;
491 ptree::iterator iit = sub.begin();
492 BOOST_TEST_EQ("", iit->first);
493 BOOST_TEST_EQ("4", iit->second.data());
494 ++iit;
495 BOOST_TEST_EQ("", iit->first);
496 BOOST_TEST_EQ("5", iit->second.data());
497 ++iit;
498 BOOST_TEST(sub.end() == iit);
499 }
500 ++it;
501 BOOST_TEST(tree.end() == it);
502 }
503
504 static void
test_empty_object()505 test_empty_object()
506 {
507 ptree tree;
508 standard_parser<char> p;
509 const char* input = " { }";
510 if(BOOST_TEST(p.parse_object(input, tree)))
511 {
512 BOOST_TEST_EQ("", tree.data());
513 BOOST_TEST_EQ(0u, tree.size());
514 }
515 }
516
517 static void
test_object_gets_tagged()518 test_object_gets_tagged()
519 {
520 wptree tree;
521 prefixing_parser<wchar_t> p;
522 const wchar_t* input = L" { }";
523 if(BOOST_TEST(p.parse_object(input, tree)))
524 {
525 BOOST_TEST(tree.data() == L"o:");
526 BOOST_TEST_EQ(0u, tree.size());
527 }
528 }
529
530 static void
test_object_with_values()531 test_object_with_values()
532 {
533 wptree tree;
534 standard_parser<wchar_t> p;
535 const wchar_t* input = L"{\n"
536 L" \"1\":123, \"2\"\n"
537 L" :\"abc\" ,\"3\": true ,\n"
538 L" \"4\" : null\n"
539 L" }";
540 if(BOOST_TEST(p.parse_object(input, tree)))
541 if(BOOST_TEST_EQ(4u, tree.size()))
542 {
543 wptree::iterator it = tree.begin();
544 BOOST_TEST(it->first == L"1");
545 BOOST_TEST(it->second.data() == L"123");
546 ++it;
547 BOOST_TEST(it->first == L"2");
548 BOOST_TEST(it->second.data() == L"abc");
549 ++it;
550 BOOST_TEST(it->first == L"3");
551 BOOST_TEST(it->second.data() == L"true");
552 ++it;
553 BOOST_TEST(it->first == L"4");
554 BOOST_TEST(it->second.data() == L"null");
555 ++it;
556 BOOST_TEST(tree.end() == it);
557 }
558 }
559
560 static void
test_object_values_get_tagged()561 test_object_values_get_tagged()
562 {
563 ptree tree;
564 prefixing_parser<char> p;
565 const char* input = "{\n"
566 "\"1\": 123, \"2\": \"abc\" ,\"3\": true ,\n"
567 "\"4\": null\n"
568 "}";
569 if(BOOST_TEST(p.parse_object(input, tree)))
570 if(BOOST_TEST_EQ(4u, tree.size()))
571 {
572 BOOST_TEST_EQ("o:", tree.data());
573 ptree::iterator it = tree.begin();
574 BOOST_TEST_EQ("1", it->first);
575 BOOST_TEST_EQ("n:123", it->second.data());
576 ++it;
577 BOOST_TEST_EQ("2", it->first);
578 BOOST_TEST_EQ("s:abc", it->second.data());
579 ++it;
580 BOOST_TEST_EQ("3", it->first);
581 BOOST_TEST_EQ("b:true", it->second.data());
582 ++it;
583 BOOST_TEST_EQ("4", it->first);
584 BOOST_TEST_EQ("_:null", it->second.data());
585 ++it;
586 BOOST_TEST(tree.end() == it);
587 }
588 }
589
590 static void
test_nested_object()591 test_nested_object()
592 {
593 ptree tree;
594 standard_parser<char> p;
595 const char* input = "{\"a\":{\"b\":1,\"c\":2},\"d\":3,\"e\":{\"f\":4,\"g\":5}}";
596 if(!BOOST_TEST(p.parse_object(input, tree)))
597 return;
598 if(!BOOST_TEST_EQ(3u, tree.size()))
599 return;
600 ptree::iterator it = tree.begin();
601 BOOST_TEST_EQ("a", it->first);
602 {
603 ptree& sub = it->second;
604 BOOST_TEST_EQ("", sub.data());
605 if(!BOOST_TEST_EQ(2u, sub.size()))
606 return;
607 ptree::iterator iit = sub.begin();
608 BOOST_TEST_EQ("b", iit->first);
609 BOOST_TEST_EQ("1", iit->second.data());
610 ++iit;
611 BOOST_TEST_EQ("c", iit->first);
612 BOOST_TEST_EQ("2", iit->second.data());
613 ++iit;
614 BOOST_TEST(sub.end() == iit);
615 }
616 ++it;
617 BOOST_TEST_EQ("d", it->first);
618 BOOST_TEST_EQ("3", it->second.data());
619 ++it;
620 BOOST_TEST_EQ("e", it->first);
621 {
622 ptree& sub = it->second;
623 BOOST_TEST_EQ("", sub.data());
624 if(!BOOST_TEST_EQ(2u, sub.size()))
625 return;
626 ptree::iterator iit = sub.begin();
627 BOOST_TEST_EQ("f", iit->first);
628 BOOST_TEST_EQ("4", iit->second.data());
629 ++iit;
630 BOOST_TEST_EQ("g", iit->first);
631 BOOST_TEST_EQ("5", iit->second.data());
632 ++iit;
633 BOOST_TEST(sub.end() == iit);
634 }
635 ++it;
636 BOOST_TEST(tree.end() == it);
637 }
638
639 static void
test_array_in_object()640 test_array_in_object()
641 {
642 ptree tree;
643 standard_parser<char> p;
644 const char* input = "{\"a\":[1,2],\"b\":3,\"c\":[4,5]}";
645 if(!BOOST_TEST(p.parse_object(input, tree)))
646 return;
647 if(!BOOST_TEST_EQ(3u, tree.size()))
648 return;
649 ptree::iterator it = tree.begin();
650 BOOST_TEST_EQ("a", it->first);
651 {
652 ptree& sub = it->second;
653 BOOST_TEST_EQ("", sub.data());
654 if(BOOST_TEST_EQ(2u, sub.size()))
655 {
656 ptree::iterator iit = sub.begin();
657 BOOST_TEST_EQ("", iit->first);
658 BOOST_TEST_EQ("1", iit->second.data());
659 ++iit;
660 BOOST_TEST_EQ("", iit->first);
661 BOOST_TEST_EQ("2", iit->second.data());
662 ++iit;
663 BOOST_TEST(sub.end() == iit);
664 }
665 }
666 ++it;
667 BOOST_TEST_EQ("b", it->first);
668 BOOST_TEST_EQ("3", it->second.data());
669 ++it;
670 BOOST_TEST_EQ("c", it->first);
671 {
672 ptree& sub = it->second;
673 BOOST_TEST_EQ("", sub.data());
674 if(BOOST_TEST_EQ(2u, sub.size()))
675 {
676 ptree::iterator iit = sub.begin();
677 BOOST_TEST_EQ("", iit->first);
678 BOOST_TEST_EQ("4", iit->second.data());
679 ++iit;
680 BOOST_TEST_EQ("", iit->first);
681 BOOST_TEST_EQ("5", iit->second.data());
682 ++iit;
683 BOOST_TEST(sub.end() == iit);
684 }
685 }
686 ++it;
687 BOOST_TEST(tree.end() == it);
688 }
689
690 static void
test_object_in_array()691 test_object_in_array()
692 {
693 ptree tree;
694 standard_parser<char> p;
695 const char* input = "[{\"a\":1,\"b\":2},3,{\"c\":4,\"d\":5}]";
696 if(!BOOST_TEST(p.parse_array(input, tree)))
697 return;
698 if(!BOOST_TEST_EQ(3u, tree.size()))
699 return;
700 ptree::iterator it = tree.begin();
701 BOOST_TEST_EQ("", it->first);
702 {
703 ptree& sub = it->second;
704 BOOST_TEST_EQ("", sub.data());
705 if(BOOST_TEST_EQ(2u, sub.size()))
706 {
707 ptree::iterator iit = sub.begin();
708 BOOST_TEST_EQ("a", iit->first);
709 BOOST_TEST_EQ("1", iit->second.data());
710 ++iit;
711 BOOST_TEST_EQ("b", iit->first);
712 BOOST_TEST_EQ("2", iit->second.data());
713 ++iit;
714 BOOST_TEST(sub.end() == iit);
715 }
716 }
717 ++it;
718 BOOST_TEST_EQ("", it->first);
719 BOOST_TEST_EQ("3", it->second.data());
720 ++it;
721 BOOST_TEST_EQ("", it->first);
722 {
723 ptree& sub = it->second;
724 BOOST_TEST_EQ("", sub.data());
725 if(BOOST_TEST_EQ(2u, sub.size()))
726 {
727 ptree::iterator iit = sub.begin();
728 BOOST_TEST_EQ("c", iit->first);
729 BOOST_TEST_EQ("4", iit->second.data());
730 ++iit;
731 BOOST_TEST_EQ("d", iit->first);
732 BOOST_TEST_EQ("5", iit->second.data());
733 ++iit;
734 BOOST_TEST(sub.end() == iit);
735 }
736 }
737 ++it;
738 BOOST_TEST(tree.end() == it);
739 }
740
741 static void
test_parser_works_with_input_iterators()742 test_parser_works_with_input_iterators()
743 {
744 const char* input = " {\n"
745 " \"1\":123, \"2\"\n"
746 " :\"abc\" ,\"3\": true ,\n"
747 " \"4\" : null, \"5\" : [ 1, 23\n"
748 " , 456 ]\n"
749 " }";
750
751 std::istringstream is(input);
752 typedef std::istreambuf_iterator<char> iterator;
753 json_parser::detail::standard_callbacks<ptree> callbacks;
754 json_parser::detail::utf8_utf8_encoding encoding;
755 json_parser::detail::parser<json_parser::detail::standard_callbacks<ptree>,
756 json_parser::detail::utf8_utf8_encoding,
757 iterator, iterator>
758 p(callbacks, encoding);
759
760 p.set_input("", boost::make_iterator_range(iterator(is), iterator()));
761 p.parse_value();
762
763 const ptree& tree = callbacks.output();
764 if(!BOOST_TEST_EQ(5u, tree.size()))
765 return;
766 ptree::const_iterator it = tree.begin();
767 BOOST_TEST_EQ("1", it->first);
768 BOOST_TEST_EQ("123", it->second.data());
769 ++it;
770 BOOST_TEST_EQ("2", it->first);
771 BOOST_TEST_EQ("abc", it->second.data());
772 ++it;
773 BOOST_TEST_EQ("3", it->first);
774 BOOST_TEST_EQ("true", it->second.data());
775 ++it;
776 BOOST_TEST_EQ("4", it->first);
777 BOOST_TEST_EQ("null", it->second.data());
778 ++it;
779 BOOST_TEST_EQ("5", it->first);
780 {
781 const ptree& sub = it->second;
782 BOOST_TEST_EQ("", sub.data());
783 if(!BOOST_TEST_EQ(3u, sub.size()))
784 return;
785 ptree::const_iterator iit = sub.begin();
786 BOOST_TEST_EQ("", iit->first);
787 BOOST_TEST_EQ("1", iit->second.data());
788 ++iit;
789 BOOST_TEST_EQ("", iit->first);
790 BOOST_TEST_EQ("23", iit->second.data());
791 ++iit;
792 BOOST_TEST_EQ("", iit->first);
793 BOOST_TEST_EQ("456", iit->second.data());
794 ++iit;
795 BOOST_TEST(sub.end() == iit);
796 }
797 ++it;
798 BOOST_TEST(tree.end() == it);
799 }
800
801 struct bad_parse_n {
802 const char* json;
803 const char* message_substring;
804 };
805
806 template<std::size_t N>
test_parse_error_thrown_with_message_n(bad_parse_n const (& param)[N])807 void test_parse_error_thrown_with_message_n(bad_parse_n const (¶m)[N])
808 {
809 for(std::size_t i = 0 ; i < N ; ++i)
810 {
811 try {
812 standard_parser<char> p;
813 ptree dummy;
814 p.parse_value(param[i].json, dummy);
815 BOOST_ERROR("expected exception");
816 } catch (json_parser::json_parser_error& e) {
817 std::string message = e.message();
818 if(message.find(param[i].message_substring) ==
819 std::string::npos)
820 {
821 std::ostringstream ss;
822 ss << "bad error message on input '" << param[i].json
823 << "', need: '" << param[i].message_substring
824 << "' but found '" << message << "'";
825 BOOST_ERROR(ss.str().c_str());
826 }
827 }
828 }
829 }
830
831 const bad_parse_n errors_n[] = {
832 {"", "expected value"},
833 {"(", "expected value"},
834
835 {"n", "expected 'null'"},
836 {"nu", "expected 'null'"},
837 {"nul", "expected 'null'"},
838 {"n ", "expected 'null'"},
839 {"nu ", "expected 'null'"},
840 {"nul ", "expected 'null'"},
841 {"nx", "expected 'null'"},
842 {"nux", "expected 'null'"},
843 {"nulx", "expected 'null'"},
844
845 {"t", "expected 'true'"},
846 {"tr", "expected 'true'"},
847 {"tu", "expected 'true'"},
848 {"t ", "expected 'true'"},
849 {"tr ", "expected 'true'"},
850 {"tru ", "expected 'true'"},
851 {"tx", "expected 'true'"},
852 {"trx", "expected 'true'"},
853 {"trux", "expected 'true'"},
854
855 {"f", "expected 'false'"},
856 {"fa", "expected 'false'"},
857 {"fal", "expected 'false'"},
858 {"fals", "expected 'false'"},
859 {"f ", "expected 'false'"},
860 {"fa ", "expected 'false'"},
861 {"fal ", "expected 'false'"},
862 {"fals ", "expected 'false'"},
863 {"fx", "expected 'false'"},
864 {"fax", "expected 'false'"},
865 {"falx", "expected 'false'"},
866 {"falsx", "expected 'false'"},
867
868 {"-", "expected digits"},
869 {"01", "garbage after data"},
870 {"0.", "need at least one digit after '.'"},
871 {"0e", "need at least one digit in exponent"},
872 {"0e-", "need at least one digit in exponent"},
873
874 {"\"", "unterminated string"},
875 {"\"asd", "unterminated string"},
876 {"\"\n\"", "invalid code sequence"}, // control character
877 {"\"\xff\"", "invalid code sequence"}, // bad lead byte
878 {"\"\x80\"", "invalid code sequence"}, // stray trail byte
879 {"\"\xc0", "invalid code sequence"}, // eos after lead byte
880 {"\"\xc0\"", "invalid code sequence"}, // bad trail byte
881 {"\"\xc0m\"", "invalid code sequence"}, // also bad trail byte
882 {"\"\\", "invalid escape sequence"},
883 {"\"\\p\"", "invalid escape sequence"},
884 {"\"\\u", "invalid escape sequence"},
885 {"\"\\u\"", "invalid escape sequence"},
886 {"\"\\ug\"", "invalid escape sequence"},
887 {"\"\\u1\"", "invalid escape sequence"},
888 {"\"\\u1g\"", "invalid escape sequence"},
889 {"\"\\u11\"", "invalid escape sequence"},
890 {"\"\\u11g\"", "invalid escape sequence"},
891 {"\"\\u111\"", "invalid escape sequence"},
892 {"\"\\u111g\"", "invalid escape sequence"},
893 {"\"\\ude00\"", "stray low surrogate"},
894 {"\"\\ud900", "stray high surrogate"},
895 {"\"\\ud900foo\"", "stray high surrogate"},
896 {"\"\\ud900\\", "expected codepoint reference"},
897 {"\"\\ud900\\n\"", "expected codepoint reference"},
898 {"\"\\ud900\\u1000\"", "expected low surrogate"},
899
900 {"[", "expected value"},
901 {"[1", "expected ']' or ','"},
902 {"[1,", "expected value"},
903 {"[1,]", "expected value"},
904 {"[1}", "expected ']' or ','"},
905
906 {"{", "expected key string"},
907 {"{1:2}", "expected key string"},
908 {"{\"\"", "expected ':'"},
909 {"{\"\"}", "expected ':'"},
910 {"{\"\":", "expected value"},
911 {"{\"\":}", "expected value"},
912 {"{\"\":0", "expected '}' or ','"},
913 {"{\"\":0]", "expected '}' or ','"},
914 {"{\"\":0,", "expected key string"},
915 {"{\"\":0,}", "expected key string"},
916 };
917
918 struct bad_parse_w {
919 const wchar_t* json;
920 const char* message_substring;
921 };
922
923 struct do_narrow
924 {
operator ()do_narrow925 char operator()(std::wstring::value_type w) const
926 {
927 unsigned long u = static_cast<unsigned long>(w);
928 if (u < 32 || u > 126)
929 return '?';
930 else
931 return static_cast<char>(u);
932 }
933 };
934 static std::string
make_narrow(std::wstring const & in)935 make_narrow(std::wstring const& in)
936 {
937 std::string result(in.size(), ' ');
938 std::transform(in.begin(), in.end(), result.begin(), do_narrow());
939 return result;
940 }
941
942 template<std::size_t N>
943 void
test_parse_error_thrown_with_message_w(bad_parse_w const (& param)[N])944 test_parse_error_thrown_with_message_w(bad_parse_w const (¶m)[N])
945 {
946 for(std::size_t i = 0 ; i < N ; ++i)
947 {
948 try {
949 standard_parser<wchar_t> p;
950 wptree dummy;
951 p.parse_value(param[i].json, dummy);
952 BOOST_ERROR("expected exception");
953 } catch (json_parser::json_parser_error& e) {
954 std::string message = e.message();
955 if (message.find(param[i].message_substring) ==
956 std::string::npos)
957 {
958 std::ostringstream ss;
959 ss << "bad error message on input '" << make_narrow(param[i].json)
960 << "', need: '" << param[i].message_substring
961 << "' but found '" << message << "'";
962 BOOST_ERROR(ss.str().c_str());
963 }
964 }
965 }
966 }
967
968 const bad_parse_w
969 errors_w[] = {
970 {L"", "expected value"},
971 {L"(", "expected value"},
972
973 {L"n", "expected 'null'"},
974 {L"nu", "expected 'null'"},
975 {L"nul", "expected 'null'"},
976 {L"n ", "expected 'null'"},
977 {L"nu ", "expected 'null'"},
978 {L"nul ", "expected 'null'"},
979 {L"nx", "expected 'null'"},
980 {L"nux", "expected 'null'"},
981 {L"nulx", "expected 'null'"},
982
983 {L"t", "expected 'true'"},
984 {L"tr", "expected 'true'"},
985 {L"tu", "expected 'true'"},
986 {L"t ", "expected 'true'"},
987 {L"tr ", "expected 'true'"},
988 {L"tru ", "expected 'true'"},
989 {L"tx", "expected 'true'"},
990 {L"trx", "expected 'true'"},
991 {L"trux", "expected 'true'"},
992
993 {L"f", "expected 'false'"},
994 {L"fa", "expected 'false'"},
995 {L"fal", "expected 'false'"},
996 {L"fals", "expected 'false'"},
997 {L"f ", "expected 'false'"},
998 {L"fa ", "expected 'false'"},
999 {L"fal ", "expected 'false'"},
1000 {L"fals ", "expected 'false'"},
1001 {L"fx", "expected 'false'"},
1002 {L"fax", "expected 'false'"},
1003 {L"falx", "expected 'false'"},
1004 {L"falsx", "expected 'false'"},
1005
1006 {L"-", "expected digits"},
1007 {L"01", "garbage after data"},
1008 {L"0.", "need at least one digit after '.'"},
1009 {L"0e", "need at least one digit in exponent"},
1010 {L"0e-", "need at least one digit in exponent"},
1011
1012 {L"\"", "unterminated string"},
1013 {L"\"asd", "unterminated string"},
1014 {L"\"\n\"", "invalid code sequence"}, // control character
1015 // Encoding not known, so no UTF-16 encoding error tests.
1016 {L"\"\\", "invalid escape sequence"},
1017 {L"\"\\p\"", "invalid escape sequence"},
1018 {L"\"\\u", "invalid escape sequence"},
1019 {L"\"\\u\"", "invalid escape sequence"},
1020 {L"\"\\ug\"", "invalid escape sequence"},
1021 {L"\"\\u1\"", "invalid escape sequence"},
1022 {L"\"\\u1g\"", "invalid escape sequence"},
1023 {L"\"\\u11\"", "invalid escape sequence"},
1024 {L"\"\\u11g\"", "invalid escape sequence"},
1025 {L"\"\\u111\"", "invalid escape sequence"},
1026 {L"\"\\u111g\"", "invalid escape sequence"},
1027 {L"\"\\ude00\"", "stray low surrogate"},
1028 {L"\"\\ud900", "stray high surrogate"},
1029 {L"\"\\ud900foo\"", "stray high surrogate"},
1030 {L"\"\\ud900\\", "expected codepoint reference"},
1031 {L"\"\\ud900\\n\"", "expected codepoint reference"},
1032 {L"\"\\ud900\\u1000\"", "expected low surrogate"},
1033
1034 {L"[", "expected value"},
1035 {L"[1", "expected ']' or ','"},
1036 {L"[1,", "expected value"},
1037 {L"[1,]", "expected value"},
1038 {L"[1}", "expected ']' or ','"},
1039
1040 {L"{", "expected key string"},
1041 {L"{1:2}", "expected key string"},
1042 {L"{\"\"", "expected ':'"},
1043 {L"{\"\"}", "expected ':'"},
1044 {L"{\"\":", "expected value"},
1045 {L"{\"\":}", "expected value"},
1046 {L"{\"\":0", "expected '}' or ','"},
1047 {L"{\"\":0]", "expected '}' or ','"},
1048 {L"{\"\":0,", "expected key string"},
1049 {L"{\"\":0,}", "expected key string"},
1050 };
1051
main()1052 int main()
1053 {
1054 test_null_parse_result_is_input();
1055 test_uses_traits_from_null();
1056 test_null_parse_skips_bom();
1057 test_null_parse_result_is_input_w();
1058 test_null_parse_skips_bom_w();
1059 test_uses_traits_from_boolean_n();
1060 test_uses_traits_from_boolean_w();
1061 test_boolean_parse_result_is_input_n(booleans_n);
1062 test_boolean_parse_result_is_input_w(booleans_w);
1063 test_number_parse_result_is_input_n(numbers_n);
1064 test_number_parse_result_is_input_w(numbers_w);
1065 test_uses_traits_from_number_n();
1066 test_string_parsed_correctly_n(strings_n);
1067 test_string_parsed_correctly_w(strings_w);
1068 test_parse_error_thrown_with_message_n(errors_n);
1069 test_parse_error_thrown_with_message_w(errors_w);
1070 test_uses_string_callbacks();
1071 test_empty_array();
1072 test_array_with_values();
1073 test_array_values_get_tagged();
1074 test_nested_array();
1075 test_empty_object();
1076 test_object_gets_tagged();
1077 test_object_with_values();
1078 test_object_values_get_tagged();
1079 test_nested_object();
1080 test_array_in_object();
1081 test_object_in_array();
1082 test_parser_works_with_input_iterators();
1083 test_uses_traits_from_null_w();
1084 test_uses_traits_from_number_w();
1085 test_array_gets_tagged();
1086 return boost::report_errors();
1087 }
1088
1089 /*
1090 test_suite* init_unit_test_suite(int, char*[])
1091 {
1092 master_test_suite_t& ts = boost::unit_test::framework::master_test_suite();
1093 ts.add(ARRAY_TEST_CASE(boolean_parse_result_is_input_n, booleans_n));
1094 ts.add(ARRAY_TEST_CASE(boolean_parse_result_is_input_w, booleans_w));
1095 ts.add(ARRAY_TEST_CASE(number_parse_result_is_input_n, numbers_n));
1096 ts.add(ARRAY_TEST_CASE(number_parse_result_is_input_w, numbers_w));
1097 ts.add(ARRAY_TEST_CASE(string_parsed_correctly_n, strings_n));
1098 ts.add(ARRAY_TEST_CASE(string_parsed_correctly_w, strings_w));
1099 ts.add(ARRAY_TEST_CASE(parse_error_thrown_with_message_n, errors_n));
1100 ts.add(ARRAY_TEST_CASE(parse_error_thrown_with_message_w, errors_w));
1101
1102 return 0;
1103 }
1104 */