]> git.proxmox.com Git - ceph.git/blob - ceph/src/boost/libs/property_tree/test/test_json_parser2.cpp
add subtree-ish sources for 12.0.3
[ceph.git] / ceph / src / boost / libs / property_tree / test / test_json_parser2.cpp
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 #define BOOST_TEST_NO_MAIN
8 #include <boost/test/unit_test.hpp>
9 #include <boost/test/parameterized_test.hpp>
10
11 #include <boost/property_tree/ptree.hpp>
12 #include <boost/range/iterator_range.hpp>
13
14 #include <cassert>
15 #include <sstream>
16 #include <vector>
17
18 using namespace boost::property_tree;
19
20 template <typename Ch> struct encoding;
21 template <> struct encoding<char>
22 : json_parser::detail::utf8_utf8_encoding
23 {};
24 template <> struct encoding<wchar_t>
25 : json_parser::detail::wide_wide_encoding
26 {};
27
28 template <typename Callbacks, typename Ch>
29 struct test_parser
30 {
31 Callbacks callbacks;
32 ::encoding<Ch> encoding;
33 typedef std::basic_string<Ch> string;
34 typedef basic_ptree<string, string> tree;
35 json_parser::detail::parser<Callbacks, ::encoding<Ch>,
36 typename string::const_iterator,
37 typename string::const_iterator>
38 parser;
39
40 test_parser() : parser(callbacks, encoding) {}
41
42 bool parse_null(const string& input, string& output) {
43 parser.set_input("", input);
44 bool result = parser.parse_null();
45 if (result) {
46 parser.finish();
47 output = callbacks.output().data();
48 }
49 return result;
50 }
51
52 bool parse_boolean(const string& input, string& output) {
53 parser.set_input("", input);
54 bool result = parser.parse_boolean();
55 if (result) {
56 parser.finish();
57 output = callbacks.output().data();
58 }
59 return result;
60 }
61
62 bool parse_number(const string& input, string& output) {
63 parser.set_input("", input);
64 bool result = parser.parse_number();
65 if (result) {
66 parser.finish();
67 output = callbacks.output().data();
68 }
69 return result;
70 }
71
72 bool parse_string(const string& input, string& output) {
73 parser.set_input("", input);
74 bool result = parser.parse_string();
75 if (result) {
76 parser.finish();
77 output = callbacks.output().data();
78 }
79 return result;
80 }
81
82 bool parse_array(const string& input, tree& output) {
83 parser.set_input("", input);
84 bool result = parser.parse_array();
85 if (result) {
86 parser.finish();
87 output = callbacks.output();
88 }
89 return result;
90 }
91
92 bool parse_object(const string& input, tree& output) {
93 parser.set_input("", input);
94 bool result = parser.parse_object();
95 if (result) {
96 parser.finish();
97 output = callbacks.output();
98 }
99 return result;
100 }
101
102 void parse_value(const string& input, tree& output) {
103 parser.set_input("", input);
104 parser.parse_value();
105 parser.finish();
106 output = callbacks.output();
107 }
108 };
109
110 template <typename Ch>
111 struct standard_parser
112 : test_parser<
113 json_parser::detail::standard_callbacks<
114 basic_ptree<std::basic_string<Ch>, std::basic_string<Ch> > >,
115 Ch>
116 {};
117
118 template <typename Ch>
119 struct prefixing_parser
120 : test_parser<
121 prefixing_callbacks<
122 basic_ptree<std::basic_string<Ch>, std::basic_string<Ch> > >,
123 Ch>
124 {};
125
126 #define BOM_N "\xef\xbb\xbf"
127 #define BOM_W L"\xfeff"
128
129 namespace boost { namespace test_tools { namespace tt_detail {
130 template<>
131 struct print_log_value<std::wstring> {
132 void operator()(std::ostream& os, const std::wstring& s) {
133 print_log_value<const wchar_t*>()(os, s.c_str());
134 }
135 };
136 }}}
137 BOOST_TEST_DONT_PRINT_LOG_VALUE(ptree::iterator)
138 BOOST_TEST_DONT_PRINT_LOG_VALUE(ptree::const_iterator)
139 BOOST_TEST_DONT_PRINT_LOG_VALUE(wptree::iterator)
140 BOOST_TEST_DONT_PRINT_LOG_VALUE(wptree::const_iterator)
141
142 BOOST_AUTO_TEST_CASE(null_parse_result_is_input) {
143 std::string parsed;
144 standard_parser<char> p;
145 BOOST_REQUIRE(p.parse_null("null", parsed));
146 BOOST_CHECK_EQUAL("null", parsed);
147 }
148
149 BOOST_AUTO_TEST_CASE(uses_traits_from_null)
150 {
151 std::string parsed;
152 prefixing_parser<char> p;
153 BOOST_REQUIRE(p.parse_null("null", parsed));
154 BOOST_CHECK_EQUAL("_:null", parsed);
155 }
156
157 BOOST_AUTO_TEST_CASE(null_parse_skips_bom) {
158 std::string parsed;
159 standard_parser<char> p;
160 BOOST_REQUIRE(p.parse_null(BOM_N "null", parsed));
161 BOOST_CHECK_EQUAL("null", parsed);
162 }
163
164 BOOST_AUTO_TEST_CASE(null_parse_result_is_input_w) {
165 std::wstring parsed;
166 standard_parser<wchar_t> p;
167 BOOST_REQUIRE(p.parse_null(L"null", parsed));
168 BOOST_CHECK_EQUAL(L"null", parsed);
169 }
170
171 BOOST_AUTO_TEST_CASE(uses_traits_from_null_w)
172 {
173 std::wstring parsed;
174 prefixing_parser<wchar_t> p;
175 BOOST_REQUIRE(p.parse_null(L"null", parsed));
176 BOOST_CHECK_EQUAL(L"_:null", parsed);
177 }
178
179 BOOST_AUTO_TEST_CASE(null_parse_skips_bom_w) {
180 std::wstring parsed;
181 standard_parser<wchar_t> p;
182 BOOST_REQUIRE(p.parse_null(BOM_W L"null", parsed));
183 BOOST_CHECK_EQUAL(L"null", parsed);
184 }
185
186 void boolean_parse_result_is_input_n(const char* param) {
187 std::string parsed;
188 standard_parser<char> p;
189 BOOST_REQUIRE(p.parse_boolean(param, parsed));
190 BOOST_CHECK_EQUAL(param, parsed);
191 }
192
193 const char* const booleans_n[] = { "true", "false" };
194
195 BOOST_AUTO_TEST_CASE(uses_traits_from_boolean_n)
196 {
197 std::string parsed;
198 prefixing_parser<char> p;
199 BOOST_REQUIRE(p.parse_boolean("true", parsed));
200 BOOST_CHECK_EQUAL("b:true", parsed);
201 }
202
203 void boolean_parse_result_is_input_w(const wchar_t* param) {
204 std::wstring parsed;
205 standard_parser<wchar_t> p;
206 BOOST_REQUIRE(p.parse_boolean(param, parsed));
207 BOOST_CHECK_EQUAL(param, parsed);
208 }
209
210 const wchar_t* const booleans_w[] = { L"true", L"false" };
211
212 BOOST_AUTO_TEST_CASE(uses_traits_from_boolean_w)
213 {
214 std::wstring parsed;
215 prefixing_parser<wchar_t> p;
216 BOOST_REQUIRE(p.parse_boolean(L"true", parsed));
217 BOOST_CHECK_EQUAL(L"b:true", parsed);
218 }
219
220 void number_parse_result_is_input_n(const char* param) {
221 std::string parsed;
222 standard_parser<char> p;
223 BOOST_REQUIRE(p.parse_number(param, parsed));
224 BOOST_CHECK_EQUAL(param, parsed);
225 }
226
227 const char* const numbers_n[] = {
228 "0",
229 "-0",
230 "1824",
231 "-0.1",
232 "123.142",
233 "1e+0",
234 "1E-0",
235 "1.1e134"
236 };
237
238 BOOST_AUTO_TEST_CASE(uses_traits_from_number_n)
239 {
240 std::string parsed;
241 prefixing_parser<char> p;
242 BOOST_REQUIRE(p.parse_number("12345", parsed));
243 BOOST_CHECK_EQUAL("n:12345", parsed);
244 }
245
246 void number_parse_result_is_input_w(const wchar_t* param) {
247 std::wstring parsed;
248 standard_parser<wchar_t> p;
249 BOOST_REQUIRE(p.parse_number(param, parsed));
250 BOOST_CHECK_EQUAL(param, parsed);
251 }
252
253 const wchar_t* const numbers_w[] = {
254 L"0",
255 L"-0",
256 L"1824",
257 L"-0.1",
258 L"123.142",
259 L"1e+0",
260 L"1E-0",
261 L"1.1e134"
262 };
263
264 BOOST_AUTO_TEST_CASE(uses_traits_from_number_w)
265 {
266 std::wstring parsed;
267 prefixing_parser<wchar_t> p;
268 BOOST_REQUIRE(p.parse_number(L"12345", parsed));
269 BOOST_CHECK_EQUAL(L"n:12345", parsed);
270 }
271
272 struct string_input_n {
273 const char* encoded;
274 const char* expected;
275 };
276
277 void string_parsed_correctly_n(string_input_n param) {
278 std::string parsed;
279 standard_parser<char> p;
280 BOOST_REQUIRE(p.parse_string(param.encoded, parsed));
281 BOOST_CHECK_EQUAL(param.expected, parsed);
282 }
283
284 const string_input_n strings_n[] = {
285 {"\"\"", ""},
286 {"\"abc\"", "abc"},
287 {"\"a\\nb\"", "a\nb"},
288 {"\"\\\"\"", "\""},
289 {"\"\\\\\"", "\\"},
290 {"\"\\/\"", "/"},
291 {"\"\\b\"", "\b"},
292 {"\"\\f\"", "\f"},
293 {"\"\\r\"", "\r"},
294 {"\"\\t\"", "\t"},
295 {"\"\\u0001\\u00f2\\u28Ec\"", "\x01" "\xC3\xB2" "\xE2\xA3\xAC"},
296 {"\"\\ud801\\udc37\"", "\xf0\x90\x90\xb7"}, // U+10437
297 {"\xef\xbb\xbf\"\"", ""} // BOM
298 };
299
300 BOOST_AUTO_TEST_CASE(uses_string_callbacks)
301 {
302 std::string parsed;
303 prefixing_parser<char> p;
304 BOOST_REQUIRE(p.parse_string("\"a\"", parsed));
305 BOOST_CHECK_EQUAL("s:a", parsed);
306 }
307
308 struct string_input_w {
309 const wchar_t* encoded;
310 const wchar_t* expected;
311 };
312
313 void string_parsed_correctly_w(string_input_w param) {
314 std::wstring parsed;
315 standard_parser<wchar_t> p;
316 BOOST_REQUIRE(p.parse_string(param.encoded, parsed));
317 BOOST_CHECK_EQUAL(param.expected, parsed);
318 }
319
320 const string_input_w strings_w[] = {
321 {L"\"\"", L""},
322 {L"\"abc\"", L"abc"},
323 {L"\"a\\nb\"", L"a\nb"},
324 {L"\"\\\"\"", L"\""},
325 {L"\"\\\\\"", L"\\"},
326 {L"\"\\/\"", L"/"},
327 {L"\"\\b\"", L"\b"},
328 {L"\"\\f\"", L"\f"},
329 {L"\"\\r\"", L"\r"},
330 {L"\"\\t\"", L"\t"},
331 {L"\"\\u0001\\u00f2\\u28Ec\"", L"\x0001" L"\x00F2" L"\x28EC"},
332 {L"\xfeff\"\"", L""} // BOM
333 };
334
335 BOOST_AUTO_TEST_CASE(empty_array) {
336 ptree tree;
337 standard_parser<char> p;
338 const char* input = " [ ]";
339 BOOST_REQUIRE(p.parse_array(input, tree));
340 BOOST_CHECK_EQUAL("", tree.data());
341 BOOST_CHECK_EQUAL(0u, tree.size());
342 }
343
344 BOOST_AUTO_TEST_CASE(array_gets_tagged) {
345 wptree tree;
346 prefixing_parser<wchar_t> p;
347 const wchar_t* input = L" [ ]";
348 BOOST_REQUIRE(p.parse_array(input, tree));
349 BOOST_CHECK_EQUAL(L"a:", tree.data());
350 BOOST_CHECK_EQUAL(0u, tree.size());
351 }
352
353 BOOST_AUTO_TEST_CASE(array_with_values) {
354 wptree tree;
355 standard_parser<wchar_t> p;
356 const wchar_t* input = L"[\n"
357 L" 123, \"abc\" ,true ,\n"
358 L" null\n"
359 L" ]";
360 BOOST_REQUIRE(p.parse_array(input, tree));
361 BOOST_REQUIRE_EQUAL(4u, tree.size());
362 wptree::iterator it = tree.begin();
363 BOOST_CHECK_EQUAL(L"", it->first);
364 BOOST_CHECK_EQUAL(L"123", it->second.data());
365 ++it;
366 BOOST_CHECK_EQUAL(L"", it->first);
367 BOOST_CHECK_EQUAL(L"abc", it->second.data());
368 ++it;
369 BOOST_CHECK_EQUAL(L"", it->first);
370 BOOST_CHECK_EQUAL(L"true", it->second.data());
371 ++it;
372 BOOST_CHECK_EQUAL(L"", it->first);
373 BOOST_CHECK_EQUAL(L"null", it->second.data());
374 ++it;
375 BOOST_CHECK_EQUAL(tree.end(), it);
376 }
377
378 BOOST_AUTO_TEST_CASE(array_values_get_tagged) {
379 ptree tree;
380 prefixing_parser<char> p;
381 const char* input = "[\n"
382 " 123, \"abc\" ,true ,\n"
383 " null\n"
384 " ]";
385 BOOST_REQUIRE(p.parse_array(input, tree));
386 BOOST_REQUIRE_EQUAL(4u, tree.size());
387 BOOST_CHECK_EQUAL("a:", tree.data());
388 ptree::iterator it = tree.begin();
389 BOOST_CHECK_EQUAL("", it->first);
390 BOOST_CHECK_EQUAL("n:123", it->second.data());
391 ++it;
392 BOOST_CHECK_EQUAL("", it->first);
393 BOOST_CHECK_EQUAL("s:abc", it->second.data());
394 ++it;
395 BOOST_CHECK_EQUAL("", it->first);
396 BOOST_CHECK_EQUAL("b:true", it->second.data());
397 ++it;
398 BOOST_CHECK_EQUAL("", it->first);
399 BOOST_CHECK_EQUAL("_:null", it->second.data());
400 ++it;
401 BOOST_CHECK_EQUAL(tree.end(), it);
402 }
403
404 BOOST_AUTO_TEST_CASE(nested_array) {
405 ptree tree;
406 standard_parser<char> p;
407 const char* input = "[[1,2],3,[4,5]]";
408 BOOST_REQUIRE(p.parse_array(input, tree));
409 BOOST_REQUIRE_EQUAL(3u, tree.size());
410 ptree::iterator it = tree.begin();
411 BOOST_CHECK_EQUAL("", it->first);
412 {
413 ptree& sub = it->second;
414 BOOST_CHECK_EQUAL("", sub.data());
415 BOOST_REQUIRE_EQUAL(2u, sub.size());
416 ptree::iterator iit = sub.begin();
417 BOOST_CHECK_EQUAL("", iit->first);
418 BOOST_CHECK_EQUAL("1", iit->second.data());
419 ++iit;
420 BOOST_CHECK_EQUAL("", iit->first);
421 BOOST_CHECK_EQUAL("2", iit->second.data());
422 ++iit;
423 BOOST_CHECK_EQUAL(sub.end(), iit);
424 }
425 ++it;
426 BOOST_CHECK_EQUAL("", it->first);
427 BOOST_CHECK_EQUAL("3", it->second.data());
428 ++it;
429 BOOST_CHECK_EQUAL("", it->first);
430 {
431 ptree& sub = it->second;
432 BOOST_CHECK_EQUAL("", sub.data());
433 BOOST_REQUIRE_EQUAL(2u, sub.size());
434 ptree::iterator iit = sub.begin();
435 BOOST_CHECK_EQUAL("", iit->first);
436 BOOST_CHECK_EQUAL("4", iit->second.data());
437 ++iit;
438 BOOST_CHECK_EQUAL("", iit->first);
439 BOOST_CHECK_EQUAL("5", iit->second.data());
440 ++iit;
441 BOOST_CHECK_EQUAL(sub.end(), iit);
442 }
443 ++it;
444 BOOST_CHECK_EQUAL(tree.end(), it);
445 }
446
447 BOOST_AUTO_TEST_CASE(empty_object) {
448 ptree tree;
449 standard_parser<char> p;
450 const char* input = " { }";
451 BOOST_REQUIRE(p.parse_object(input, tree));
452 BOOST_CHECK_EQUAL("", tree.data());
453 BOOST_CHECK_EQUAL(0u, tree.size());
454 }
455
456 BOOST_AUTO_TEST_CASE(object_gets_tagged) {
457 wptree tree;
458 prefixing_parser<wchar_t> p;
459 const wchar_t* input = L" { }";
460 BOOST_REQUIRE(p.parse_object(input, tree));
461 BOOST_CHECK_EQUAL(L"o:", tree.data());
462 BOOST_CHECK_EQUAL(0u, tree.size());
463 }
464
465 BOOST_AUTO_TEST_CASE(object_with_values) {
466 wptree tree;
467 standard_parser<wchar_t> p;
468 const wchar_t* input = L"{\n"
469 L" \"1\":123, \"2\"\n"
470 L" :\"abc\" ,\"3\": true ,\n"
471 L" \"4\" : null\n"
472 L" }";
473 BOOST_REQUIRE(p.parse_object(input, tree));
474 BOOST_REQUIRE_EQUAL(4u, tree.size());
475 wptree::iterator it = tree.begin();
476 BOOST_CHECK_EQUAL(L"1", it->first);
477 BOOST_CHECK_EQUAL(L"123", it->second.data());
478 ++it;
479 BOOST_CHECK_EQUAL(L"2", it->first);
480 BOOST_CHECK_EQUAL(L"abc", it->second.data());
481 ++it;
482 BOOST_CHECK_EQUAL(L"3", it->first);
483 BOOST_CHECK_EQUAL(L"true", it->second.data());
484 ++it;
485 BOOST_CHECK_EQUAL(L"4", it->first);
486 BOOST_CHECK_EQUAL(L"null", it->second.data());
487 ++it;
488 BOOST_CHECK_EQUAL(tree.end(), it);
489 }
490
491 BOOST_AUTO_TEST_CASE(object_values_get_tagged) {
492 ptree tree;
493 prefixing_parser<char> p;
494 const char* input = "{\n"
495 "\"1\": 123, \"2\": \"abc\" ,\"3\": true ,\n"
496 "\"4\": null\n"
497 "}";
498 BOOST_REQUIRE(p.parse_object(input, tree));
499 BOOST_REQUIRE_EQUAL(4u, tree.size());
500 BOOST_CHECK_EQUAL("o:", tree.data());
501 ptree::iterator it = tree.begin();
502 BOOST_CHECK_EQUAL("1", it->first);
503 BOOST_CHECK_EQUAL("n:123", it->second.data());
504 ++it;
505 BOOST_CHECK_EQUAL("2", it->first);
506 BOOST_CHECK_EQUAL("s:abc", it->second.data());
507 ++it;
508 BOOST_CHECK_EQUAL("3", it->first);
509 BOOST_CHECK_EQUAL("b:true", it->second.data());
510 ++it;
511 BOOST_CHECK_EQUAL("4", it->first);
512 BOOST_CHECK_EQUAL("_:null", it->second.data());
513 ++it;
514 BOOST_CHECK_EQUAL(tree.end(), it);
515 }
516
517 BOOST_AUTO_TEST_CASE(nested_object) {
518 ptree tree;
519 standard_parser<char> p;
520 const char* input = "{\"a\":{\"b\":1,\"c\":2},\"d\":3,\"e\":{\"f\":4,\"g\":5}}";
521 BOOST_REQUIRE(p.parse_object(input, tree));
522 BOOST_REQUIRE_EQUAL(3u, tree.size());
523 ptree::iterator it = tree.begin();
524 BOOST_CHECK_EQUAL("a", it->first);
525 {
526 ptree& sub = it->second;
527 BOOST_CHECK_EQUAL("", sub.data());
528 BOOST_REQUIRE_EQUAL(2u, sub.size());
529 ptree::iterator iit = sub.begin();
530 BOOST_CHECK_EQUAL("b", iit->first);
531 BOOST_CHECK_EQUAL("1", iit->second.data());
532 ++iit;
533 BOOST_CHECK_EQUAL("c", iit->first);
534 BOOST_CHECK_EQUAL("2", iit->second.data());
535 ++iit;
536 BOOST_CHECK_EQUAL(sub.end(), iit);
537 }
538 ++it;
539 BOOST_CHECK_EQUAL("d", it->first);
540 BOOST_CHECK_EQUAL("3", it->second.data());
541 ++it;
542 BOOST_CHECK_EQUAL("e", it->first);
543 {
544 ptree& sub = it->second;
545 BOOST_CHECK_EQUAL("", sub.data());
546 BOOST_REQUIRE_EQUAL(2u, sub.size());
547 ptree::iterator iit = sub.begin();
548 BOOST_CHECK_EQUAL("f", iit->first);
549 BOOST_CHECK_EQUAL("4", iit->second.data());
550 ++iit;
551 BOOST_CHECK_EQUAL("g", iit->first);
552 BOOST_CHECK_EQUAL("5", iit->second.data());
553 ++iit;
554 BOOST_CHECK_EQUAL(sub.end(), iit);
555 }
556 ++it;
557 BOOST_CHECK_EQUAL(tree.end(), it);
558 }
559
560 BOOST_AUTO_TEST_CASE(array_in_object) {
561 ptree tree;
562 standard_parser<char> p;
563 const char* input = "{\"a\":[1,2],\"b\":3,\"c\":[4,5]}";
564 BOOST_REQUIRE(p.parse_object(input, tree));
565 BOOST_REQUIRE_EQUAL(3u, tree.size());
566 ptree::iterator it = tree.begin();
567 BOOST_CHECK_EQUAL("a", it->first);
568 {
569 ptree& sub = it->second;
570 BOOST_CHECK_EQUAL("", sub.data());
571 BOOST_REQUIRE_EQUAL(2u, sub.size());
572 ptree::iterator iit = sub.begin();
573 BOOST_CHECK_EQUAL("", iit->first);
574 BOOST_CHECK_EQUAL("1", iit->second.data());
575 ++iit;
576 BOOST_CHECK_EQUAL("", iit->first);
577 BOOST_CHECK_EQUAL("2", iit->second.data());
578 ++iit;
579 BOOST_CHECK_EQUAL(sub.end(), iit);
580 }
581 ++it;
582 BOOST_CHECK_EQUAL("b", it->first);
583 BOOST_CHECK_EQUAL("3", it->second.data());
584 ++it;
585 BOOST_CHECK_EQUAL("c", it->first);
586 {
587 ptree& sub = it->second;
588 BOOST_CHECK_EQUAL("", sub.data());
589 BOOST_REQUIRE_EQUAL(2u, sub.size());
590 ptree::iterator iit = sub.begin();
591 BOOST_CHECK_EQUAL("", iit->first);
592 BOOST_CHECK_EQUAL("4", iit->second.data());
593 ++iit;
594 BOOST_CHECK_EQUAL("", iit->first);
595 BOOST_CHECK_EQUAL("5", iit->second.data());
596 ++iit;
597 BOOST_CHECK_EQUAL(sub.end(), iit);
598 }
599 ++it;
600 BOOST_CHECK_EQUAL(tree.end(), it);
601 }
602
603 BOOST_AUTO_TEST_CASE(object_in_array) {
604 ptree tree;
605 standard_parser<char> p;
606 const char* input = "[{\"a\":1,\"b\":2},3,{\"c\":4,\"d\":5}]";
607 BOOST_REQUIRE(p.parse_array(input, tree));
608 BOOST_REQUIRE_EQUAL(3u, tree.size());
609 ptree::iterator it = tree.begin();
610 BOOST_CHECK_EQUAL("", it->first);
611 {
612 ptree& sub = it->second;
613 BOOST_CHECK_EQUAL("", sub.data());
614 BOOST_REQUIRE_EQUAL(2u, sub.size());
615 ptree::iterator iit = sub.begin();
616 BOOST_CHECK_EQUAL("a", iit->first);
617 BOOST_CHECK_EQUAL("1", iit->second.data());
618 ++iit;
619 BOOST_CHECK_EQUAL("b", iit->first);
620 BOOST_CHECK_EQUAL("2", iit->second.data());
621 ++iit;
622 BOOST_CHECK_EQUAL(sub.end(), iit);
623 }
624 ++it;
625 BOOST_CHECK_EQUAL("", it->first);
626 BOOST_CHECK_EQUAL("3", it->second.data());
627 ++it;
628 BOOST_CHECK_EQUAL("", it->first);
629 {
630 ptree& sub = it->second;
631 BOOST_CHECK_EQUAL("", sub.data());
632 BOOST_REQUIRE_EQUAL(2u, sub.size());
633 ptree::iterator iit = sub.begin();
634 BOOST_CHECK_EQUAL("c", iit->first);
635 BOOST_CHECK_EQUAL("4", iit->second.data());
636 ++iit;
637 BOOST_CHECK_EQUAL("d", iit->first);
638 BOOST_CHECK_EQUAL("5", iit->second.data());
639 ++iit;
640 BOOST_CHECK_EQUAL(sub.end(), iit);
641 }
642 ++it;
643 BOOST_CHECK_EQUAL(tree.end(), it);
644 }
645
646 BOOST_AUTO_TEST_CASE(parser_works_with_input_iterators) {
647 const char* input = " {\n"
648 " \"1\":123, \"2\"\n"
649 " :\"abc\" ,\"3\": true ,\n"
650 " \"4\" : null, \"5\" : [ 1, 23\n"
651 " , 456 ]\n"
652 " }";
653
654 std::istringstream is(input);
655 typedef std::istreambuf_iterator<char> iterator;
656 json_parser::detail::standard_callbacks<ptree> callbacks;
657 json_parser::detail::utf8_utf8_encoding encoding;
658 json_parser::detail::parser<json_parser::detail::standard_callbacks<ptree>,
659 json_parser::detail::utf8_utf8_encoding,
660 iterator, iterator>
661 p(callbacks, encoding);
662
663 p.set_input("", boost::make_iterator_range(iterator(is), iterator()));
664 p.parse_value();
665
666 const ptree& tree = callbacks.output();
667 BOOST_REQUIRE_EQUAL(5u, tree.size());
668 ptree::const_iterator it = tree.begin();
669 BOOST_CHECK_EQUAL("1", it->first);
670 BOOST_CHECK_EQUAL("123", it->second.data());
671 ++it;
672 BOOST_CHECK_EQUAL("2", it->first);
673 BOOST_CHECK_EQUAL("abc", it->second.data());
674 ++it;
675 BOOST_CHECK_EQUAL("3", it->first);
676 BOOST_CHECK_EQUAL("true", it->second.data());
677 ++it;
678 BOOST_CHECK_EQUAL("4", it->first);
679 BOOST_CHECK_EQUAL("null", it->second.data());
680 ++it;
681 BOOST_CHECK_EQUAL("5", it->first);
682 {
683 const ptree& sub = it->second;
684 BOOST_CHECK_EQUAL("", sub.data());
685 BOOST_REQUIRE_EQUAL(3u, sub.size());
686 ptree::const_iterator iit = sub.begin();
687 BOOST_CHECK_EQUAL("", iit->first);
688 BOOST_CHECK_EQUAL("1", iit->second.data());
689 ++iit;
690 BOOST_CHECK_EQUAL("", iit->first);
691 BOOST_CHECK_EQUAL("23", iit->second.data());
692 ++iit;
693 BOOST_CHECK_EQUAL("", iit->first);
694 BOOST_CHECK_EQUAL("456", iit->second.data());
695 ++iit;
696 BOOST_CHECK_EQUAL(sub.end(), iit);
697 }
698 ++it;
699 BOOST_CHECK_EQUAL(tree.end(), it);
700 }
701
702 struct bad_parse_n {
703 const char* json;
704 const char* message_substring;
705 };
706
707 void parse_error_thrown_with_message_n(bad_parse_n param) {
708 try {
709 standard_parser<char> p;
710 ptree dummy;
711 p.parse_value(param.json, dummy);
712 BOOST_FAIL("expected exception");
713 } catch (json_parser::json_parser_error& e) {
714 std::string message = e.message();
715 BOOST_CHECK_MESSAGE(message.find(param.message_substring) !=
716 std::string::npos,
717 "bad error message on input '" << param.json
718 << "', need: '" << param.message_substring
719 << "' but found '" << message << "'");
720 }
721 }
722
723 const bad_parse_n errors_n[] = {
724 {"", "expected value"},
725 {"(", "expected value"},
726
727 {"n", "expected 'null'"},
728 {"nu", "expected 'null'"},
729 {"nul", "expected 'null'"},
730 {"n ", "expected 'null'"},
731 {"nu ", "expected 'null'"},
732 {"nul ", "expected 'null'"},
733 {"nx", "expected 'null'"},
734 {"nux", "expected 'null'"},
735 {"nulx", "expected 'null'"},
736
737 {"t", "expected 'true'"},
738 {"tr", "expected 'true'"},
739 {"tu", "expected 'true'"},
740 {"t ", "expected 'true'"},
741 {"tr ", "expected 'true'"},
742 {"tru ", "expected 'true'"},
743 {"tx", "expected 'true'"},
744 {"trx", "expected 'true'"},
745 {"trux", "expected 'true'"},
746
747 {"f", "expected 'false'"},
748 {"fa", "expected 'false'"},
749 {"fal", "expected 'false'"},
750 {"fals", "expected 'false'"},
751 {"f ", "expected 'false'"},
752 {"fa ", "expected 'false'"},
753 {"fal ", "expected 'false'"},
754 {"fals ", "expected 'false'"},
755 {"fx", "expected 'false'"},
756 {"fax", "expected 'false'"},
757 {"falx", "expected 'false'"},
758 {"falsx", "expected 'false'"},
759
760 {"-", "expected digits"},
761 {"01", "garbage after data"},
762 {"0.", "need at least one digit after '.'"},
763 {"0e", "need at least one digit in exponent"},
764 {"0e-", "need at least one digit in exponent"},
765
766 {"\"", "unterminated string"},
767 {"\"asd", "unterminated string"},
768 {"\"\n\"", "invalid code sequence"}, // control character
769 {"\"\xff\"", "invalid code sequence"}, // bad lead byte
770 {"\"\x80\"", "invalid code sequence"}, // stray trail byte
771 {"\"\xc0", "invalid code sequence"}, // eos after lead byte
772 {"\"\xc0\"", "invalid code sequence"}, // bad trail byte
773 {"\"\xc0m\"", "invalid code sequence"}, // also bad trail byte
774 {"\"\\", "invalid escape sequence"},
775 {"\"\\p\"", "invalid escape sequence"},
776 {"\"\\u", "invalid escape sequence"},
777 {"\"\\u\"", "invalid escape sequence"},
778 {"\"\\ug\"", "invalid escape sequence"},
779 {"\"\\u1\"", "invalid escape sequence"},
780 {"\"\\u1g\"", "invalid escape sequence"},
781 {"\"\\u11\"", "invalid escape sequence"},
782 {"\"\\u11g\"", "invalid escape sequence"},
783 {"\"\\u111\"", "invalid escape sequence"},
784 {"\"\\u111g\"", "invalid escape sequence"},
785 {"\"\\ude00\"", "stray low surrogate"},
786 {"\"\\ud900", "stray high surrogate"},
787 {"\"\\ud900foo\"", "stray high surrogate"},
788 {"\"\\ud900\\", "expected codepoint reference"},
789 {"\"\\ud900\\n\"", "expected codepoint reference"},
790 {"\"\\ud900\\u1000\"", "expected low surrogate"},
791
792 {"[", "expected value"},
793 {"[1", "expected ']' or ','"},
794 {"[1,", "expected value"},
795 {"[1,]", "expected value"},
796 {"[1}", "expected ']' or ','"},
797
798 {"{", "expected key string"},
799 {"{1:2}", "expected key string"},
800 {"{\"\"", "expected ':'"},
801 {"{\"\"}", "expected ':'"},
802 {"{\"\":", "expected value"},
803 {"{\"\":}", "expected value"},
804 {"{\"\":0", "expected '}' or ','"},
805 {"{\"\":0]", "expected '}' or ','"},
806 {"{\"\":0,", "expected key string"},
807 {"{\"\":0,}", "expected key string"},
808 };
809
810 struct bad_parse_w {
811 const wchar_t* json;
812 const char* message_substring;
813 };
814
815 void parse_error_thrown_with_message_w(bad_parse_w param) {
816 try {
817 standard_parser<wchar_t> p;
818 wptree dummy;
819 p.parse_value(param.json, dummy);
820 BOOST_FAIL("expected exception");
821 } catch (json_parser::json_parser_error& e) {
822 std::string message = e.message();
823 BOOST_CHECK_MESSAGE(message.find(param.message_substring) !=
824 std::string::npos,
825 "bad error message on input '" << param.json
826 << "', need: '" << param.message_substring
827 << "' but found '" << message << "'");
828 }
829 }
830
831 const bad_parse_w errors_w[] = {
832 {L"", "expected value"},
833 {L"(", "expected value"},
834
835 {L"n", "expected 'null'"},
836 {L"nu", "expected 'null'"},
837 {L"nul", "expected 'null'"},
838 {L"n ", "expected 'null'"},
839 {L"nu ", "expected 'null'"},
840 {L"nul ", "expected 'null'"},
841 {L"nx", "expected 'null'"},
842 {L"nux", "expected 'null'"},
843 {L"nulx", "expected 'null'"},
844
845 {L"t", "expected 'true'"},
846 {L"tr", "expected 'true'"},
847 {L"tu", "expected 'true'"},
848 {L"t ", "expected 'true'"},
849 {L"tr ", "expected 'true'"},
850 {L"tru ", "expected 'true'"},
851 {L"tx", "expected 'true'"},
852 {L"trx", "expected 'true'"},
853 {L"trux", "expected 'true'"},
854
855 {L"f", "expected 'false'"},
856 {L"fa", "expected 'false'"},
857 {L"fal", "expected 'false'"},
858 {L"fals", "expected 'false'"},
859 {L"f ", "expected 'false'"},
860 {L"fa ", "expected 'false'"},
861 {L"fal ", "expected 'false'"},
862 {L"fals ", "expected 'false'"},
863 {L"fx", "expected 'false'"},
864 {L"fax", "expected 'false'"},
865 {L"falx", "expected 'false'"},
866 {L"falsx", "expected 'false'"},
867
868 {L"-", "expected digits"},
869 {L"01", "garbage after data"},
870 {L"0.", "need at least one digit after '.'"},
871 {L"0e", "need at least one digit in exponent"},
872 {L"0e-", "need at least one digit in exponent"},
873
874 {L"\"", "unterminated string"},
875 {L"\"asd", "unterminated string"},
876 {L"\"\n\"", "invalid code sequence"}, // control character
877 // Encoding not known, so no UTF-16 encoding error tests.
878 {L"\"\\", "invalid escape sequence"},
879 {L"\"\\p\"", "invalid escape sequence"},
880 {L"\"\\u", "invalid escape sequence"},
881 {L"\"\\u\"", "invalid escape sequence"},
882 {L"\"\\ug\"", "invalid escape sequence"},
883 {L"\"\\u1\"", "invalid escape sequence"},
884 {L"\"\\u1g\"", "invalid escape sequence"},
885 {L"\"\\u11\"", "invalid escape sequence"},
886 {L"\"\\u11g\"", "invalid escape sequence"},
887 {L"\"\\u111\"", "invalid escape sequence"},
888 {L"\"\\u111g\"", "invalid escape sequence"},
889 {L"\"\\ude00\"", "stray low surrogate"},
890 {L"\"\\ud900", "stray high surrogate"},
891 {L"\"\\ud900foo\"", "stray high surrogate"},
892 {L"\"\\ud900\\", "expected codepoint reference"},
893 {L"\"\\ud900\\n\"", "expected codepoint reference"},
894 {L"\"\\ud900\\u1000\"", "expected low surrogate"},
895
896 {L"[", "expected value"},
897 {L"[1", "expected ']' or ','"},
898 {L"[1,", "expected value"},
899 {L"[1,]", "expected value"},
900 {L"[1}", "expected ']' or ','"},
901
902 {L"{", "expected key string"},
903 {L"{1:2}", "expected key string"},
904 {L"{\"\"", "expected ':'"},
905 {L"{\"\"}", "expected ':'"},
906 {L"{\"\":", "expected value"},
907 {L"{\"\":}", "expected value"},
908 {L"{\"\":0", "expected '}' or ','"},
909 {L"{\"\":0]", "expected '}' or ','"},
910 {L"{\"\":0,", "expected key string"},
911 {L"{\"\":0,}", "expected key string"},
912 };
913
914 template <typename T, std::size_t N>
915 std::size_t arraysize(T(&)[N]) { return N; }
916
917 #define ARRAY_TEST_CASE(fn, a) \
918 BOOST_PARAM_TEST_CASE(fn, (a), (a) + arraysize((a)))
919
920 using namespace boost::unit_test;
921
922 test_suite* init_unit_test_suite(int, char*[])
923 {
924 master_test_suite_t& ts = boost::unit_test::framework::master_test_suite();
925 ts.add(ARRAY_TEST_CASE(boolean_parse_result_is_input_n, booleans_n));
926 ts.add(ARRAY_TEST_CASE(boolean_parse_result_is_input_w, booleans_w));
927 ts.add(ARRAY_TEST_CASE(number_parse_result_is_input_n, numbers_n));
928 ts.add(ARRAY_TEST_CASE(number_parse_result_is_input_w, numbers_w));
929 ts.add(ARRAY_TEST_CASE(string_parsed_correctly_n, strings_n));
930 ts.add(ARRAY_TEST_CASE(string_parsed_correctly_w, strings_w));
931 ts.add(ARRAY_TEST_CASE(parse_error_thrown_with_message_n, errors_n));
932 ts.add(ARRAY_TEST_CASE(parse_error_thrown_with_message_w, errors_w));
933
934 return 0;
935 }