Mercurial > hg > piper-cpp
comparison ext/json11/test.cpp @ 242:d607ae858682
Update json11 code
author | Chris Cannam <cannam@all-day-breakfast.com> |
---|---|
date | Tue, 13 Jun 2017 17:16:03 +0100 |
parents | bf8e3e7dd7de |
children |
comparison
equal
deleted
inserted
replaced
241:fdab0a246298 | 242:d607ae858682 |
---|---|
1 /* | |
2 * Define JSON11_TEST_CUSTOM_CONFIG to 1 if you want to build this tester into | |
3 * your own unit-test framework rather than a stand-alone program. By setting | |
4 * The values of the variables included below, you can insert your own custom | |
5 * code into this file as it builds, in order to make it into a test case for | |
6 * your favorite framework. | |
7 */ | |
8 #if !JSON11_TEST_CUSTOM_CONFIG | |
9 #define JSON11_TEST_CPP_PREFIX_CODE | |
10 #define JSON11_TEST_CPP_SUFFIX_CODE | |
11 #define JSON11_TEST_STANDALONE_MAIN 1 | |
12 #define JSON11_TEST_CASE(name) static void name() | |
13 #define JSON11_TEST_ASSERT(b) assert(b) | |
14 #ifdef NDEBUG | |
15 #undef NDEBUG//at now assert will work even in Release build | |
16 #endif | |
17 #endif // JSON11_TEST_CUSTOM_CONFIG | |
18 | |
19 /* | |
20 * Enable or disable code which demonstrates the behavior change in Xcode 7 / Clang 3.7, | |
21 * introduced by DR1467 and described here: https://github.com/dropbox/json11/issues/86 | |
22 * Defaults to off since it doesn't appear the standards committee is likely to act | |
23 * on this, so it needs to be considered normal behavior. | |
24 */ | |
25 #ifndef JSON11_ENABLE_DR1467_CANARY | |
26 #define JSON11_ENABLE_DR1467_CANARY 0 | |
27 #endif | |
28 | |
29 /* | |
30 * Beginning of standard source file, which makes use of the customizations above. | |
31 */ | |
32 #include <cassert> | |
1 #include <string> | 33 #include <string> |
2 #include <cstdio> | 34 #include <cstdio> |
3 #include <cstring> | 35 #include <cstring> |
4 #include <iostream> | 36 #include <iostream> |
5 #include <sstream> | 37 #include <sstream> |
6 #include "json11.hpp" | 38 #include "json11.hpp" |
7 #include <cassert> | |
8 #include <list> | 39 #include <list> |
9 #include <set> | 40 #include <set> |
10 #include <unordered_map> | 41 #include <unordered_map> |
42 #include <algorithm> | |
43 #include <type_traits> | |
44 | |
45 // Insert user-defined prefix code (includes, function declarations, etc) | |
46 // to set up a custom test suite | |
47 JSON11_TEST_CPP_PREFIX_CODE | |
11 | 48 |
12 using namespace json11; | 49 using namespace json11; |
13 using std::string; | 50 using std::string; |
14 | 51 |
15 // Check that Json has the properties we want. | 52 // Check that Json has the properties we want. |
16 #include <type_traits> | |
17 #define CHECK_TRAIT(x) static_assert(std::x::value, #x) | 53 #define CHECK_TRAIT(x) static_assert(std::x::value, #x) |
18 CHECK_TRAIT(is_nothrow_constructible<Json>); | 54 CHECK_TRAIT(is_nothrow_constructible<Json>); |
19 CHECK_TRAIT(is_nothrow_default_constructible<Json>); | 55 CHECK_TRAIT(is_nothrow_default_constructible<Json>); |
20 CHECK_TRAIT(is_copy_constructible<Json>); | 56 CHECK_TRAIT(is_copy_constructible<Json>); |
21 CHECK_TRAIT(is_nothrow_move_constructible<Json>); | 57 CHECK_TRAIT(is_nothrow_move_constructible<Json>); |
22 CHECK_TRAIT(is_copy_assignable<Json>); | 58 CHECK_TRAIT(is_copy_assignable<Json>); |
23 CHECK_TRAIT(is_nothrow_move_assignable<Json>); | 59 CHECK_TRAIT(is_nothrow_move_assignable<Json>); |
24 CHECK_TRAIT(is_nothrow_destructible<Json>); | 60 CHECK_TRAIT(is_nothrow_destructible<Json>); |
25 | 61 |
26 void parse_from_stdin() { | 62 JSON11_TEST_CASE(json11_test) { |
27 string buf; | |
28 string line; | |
29 while (std::getline(std::cin, line)) { | |
30 buf += line + "\n"; | |
31 } | |
32 | |
33 string err; | |
34 auto json = Json::parse(buf, err); | |
35 if (!err.empty()) { | |
36 printf("Failed: %s\n", err.c_str()); | |
37 } else { | |
38 printf("Result: %s\n", json.dump().c_str()); | |
39 } | |
40 } | |
41 | |
42 int main(int argc, char **argv) { | |
43 if (argc == 2 && argv[1] == string("--stdin")) { | |
44 parse_from_stdin(); | |
45 return 0; | |
46 } | |
47 | |
48 const string simple_test = | 63 const string simple_test = |
49 R"({"k1":"v1", "k2":42, "k3":["a",123,true,false,null]})"; | 64 R"({"k1":"v1", "k2":42, "k3":["a",123,true,false,null]})"; |
50 | 65 |
51 string err; | 66 string err; |
52 auto json = Json::parse(simple_test, err); | 67 const auto json = Json::parse(simple_test, err); |
53 | 68 |
54 std::cout << "k1: " << json["k1"].string_value() << "\n"; | 69 std::cout << "k1: " << json["k1"].string_value() << "\n"; |
55 std::cout << "k3: " << json["k3"].dump() << "\n"; | 70 std::cout << "k3: " << json["k3"].dump() << "\n"; |
56 | 71 |
57 for (auto &k : json["k3"].array_items()) { | 72 for (auto &k : json["k3"].array_items()) { |
58 std::cout << " - " << k.dump() << "\n"; | 73 std::cout << " - " << k.dump() << "\n"; |
59 } | 74 } |
60 | 75 |
61 const string comment_test = R"({ | 76 string comment_test = R"({ |
62 // comment /* with nested comment */ | 77 // comment /* with nested comment */ |
63 "a": 1, | 78 "a": 1, |
64 // comment | 79 // comment |
65 // continued | 80 // continued |
66 "b": "text", | 81 "b": "text", |
67 /* multi | 82 /* multi |
68 line | 83 line |
69 comment */ | 84 comment |
85 // line-comment-inside-multiline-comment | |
86 */ | |
70 // and single-line comment | 87 // and single-line comment |
88 // and single-line comment /* multiline inside single line */ | |
71 "c": [1, 2, 3] | 89 "c": [1, 2, 3] |
90 // and single-line comment at end of object | |
72 })"; | 91 })"; |
73 | 92 |
74 string err_comment; | 93 string err_comment; |
75 auto json_comment = Json::parse( | 94 auto json_comment = Json::parse( |
76 comment_test, err_comment, JsonParse::COMMENTS); | 95 comment_test, err_comment, JsonParse::COMMENTS); |
77 if (!err_comment.empty()) { | 96 JSON11_TEST_ASSERT(!json_comment.is_null()); |
78 printf("Failed: %s\n", err_comment.c_str()); | 97 JSON11_TEST_ASSERT(err_comment.empty()); |
79 } else { | 98 |
80 printf("Result: %s\n", json_comment.dump().c_str()); | 99 comment_test = "{\"a\": 1}//trailing line comment"; |
81 } | 100 json_comment = Json::parse( |
82 | 101 comment_test, err_comment, JsonParse::COMMENTS); |
83 string failing_comment_test = R"({ | 102 JSON11_TEST_ASSERT(!json_comment.is_null()); |
84 /* bad comment | 103 JSON11_TEST_ASSERT(err_comment.empty()); |
85 "a": 1, | 104 |
86 })"; | 105 comment_test = "{\"a\": 1}/*trailing multi-line comment*/"; |
87 | 106 json_comment = Json::parse( |
107 comment_test, err_comment, JsonParse::COMMENTS); | |
108 JSON11_TEST_ASSERT(!json_comment.is_null()); | |
109 JSON11_TEST_ASSERT(err_comment.empty()); | |
110 | |
111 string failing_comment_test = "{\n/* unterminated comment\n\"a\": 1,\n}"; | |
88 string err_failing_comment; | 112 string err_failing_comment; |
89 auto json_failing_comment = Json::parse( | 113 auto json_failing_comment = Json::parse( |
90 failing_comment_test, err_failing_comment, JsonParse::COMMENTS); | 114 failing_comment_test, err_failing_comment, JsonParse::COMMENTS); |
91 if (!err_failing_comment.empty()) { | 115 JSON11_TEST_ASSERT(json_failing_comment.is_null()); |
92 printf("Failed: %s\n", err_failing_comment.c_str()); | 116 JSON11_TEST_ASSERT(!err_failing_comment.empty()); |
93 } else { | 117 |
94 printf("Result: %s\n", json_failing_comment.dump().c_str()); | 118 failing_comment_test = "{\n/* unterminated trailing comment }"; |
95 } | 119 json_failing_comment = Json::parse( |
96 | 120 failing_comment_test, err_failing_comment, JsonParse::COMMENTS); |
97 failing_comment_test = R"({ | 121 JSON11_TEST_ASSERT(json_failing_comment.is_null()); |
98 / / bad comment })"; | 122 JSON11_TEST_ASSERT(!err_failing_comment.empty()); |
99 | 123 |
100 json_failing_comment = Json::parse( | 124 failing_comment_test = "{\n/ / bad comment }"; |
101 failing_comment_test, err_failing_comment, JsonParse::COMMENTS); | 125 json_failing_comment = Json::parse( |
102 if (!err_failing_comment.empty()) { | 126 failing_comment_test, err_failing_comment, JsonParse::COMMENTS); |
103 printf("Failed: %s\n", err_failing_comment.c_str()); | 127 JSON11_TEST_ASSERT(json_failing_comment.is_null()); |
104 } else { | 128 JSON11_TEST_ASSERT(!err_failing_comment.empty()); |
105 printf("Result: %s\n", json_failing_comment.dump().c_str()); | 129 |
106 } | 130 failing_comment_test = "{// bad comment }"; |
107 | 131 json_failing_comment = Json::parse( |
108 failing_comment_test = R"({// bad comment })"; | 132 failing_comment_test, err_failing_comment, JsonParse::COMMENTS); |
109 | 133 JSON11_TEST_ASSERT(json_failing_comment.is_null()); |
110 json_failing_comment = Json::parse( | 134 JSON11_TEST_ASSERT(!err_failing_comment.empty()); |
111 failing_comment_test, err_failing_comment, JsonParse::COMMENTS); | 135 |
112 if (!err_failing_comment.empty()) { | 136 failing_comment_test = "{\n\"a\": 1\n}/"; |
113 printf("Failed: %s\n", err_failing_comment.c_str()); | 137 json_failing_comment = Json::parse( |
114 } else { | 138 failing_comment_test, err_failing_comment, JsonParse::COMMENTS); |
115 printf("Result: %s\n", json_failing_comment.dump().c_str()); | 139 JSON11_TEST_ASSERT(json_failing_comment.is_null()); |
116 } | 140 JSON11_TEST_ASSERT(!err_failing_comment.empty()); |
117 | 141 |
118 failing_comment_test = R"({ | 142 failing_comment_test = "{/* bad\ncomment *}"; |
119 "a": 1 | 143 json_failing_comment = Json::parse( |
120 }/)"; | 144 failing_comment_test, err_failing_comment, JsonParse::COMMENTS); |
121 | 145 JSON11_TEST_ASSERT(json_failing_comment.is_null()); |
122 json_failing_comment = Json::parse( | 146 JSON11_TEST_ASSERT(!err_failing_comment.empty()); |
123 failing_comment_test, err_failing_comment, JsonParse::COMMENTS); | |
124 if (!err_failing_comment.empty()) { | |
125 printf("Failed: %s\n", err_failing_comment.c_str()); | |
126 } else { | |
127 printf("Result: %s\n", json_failing_comment.dump().c_str()); | |
128 } | |
129 | |
130 failing_comment_test = R"({/* bad | |
131 comment *})"; | |
132 | |
133 json_failing_comment = Json::parse( | |
134 failing_comment_test, err_failing_comment, JsonParse::COMMENTS); | |
135 if (!err_failing_comment.empty()) { | |
136 printf("Failed: %s\n", err_failing_comment.c_str()); | |
137 } else { | |
138 printf("Result: %s\n", json_failing_comment.dump().c_str()); | |
139 } | |
140 | 147 |
141 std::list<int> l1 { 1, 2, 3 }; | 148 std::list<int> l1 { 1, 2, 3 }; |
142 std::vector<int> l2 { 1, 2, 3 }; | 149 std::vector<int> l2 { 1, 2, 3 }; |
143 std::set<int> l3 { 1, 2, 3 }; | 150 std::set<int> l3 { 1, 2, 3 }; |
144 assert(Json(l1) == Json(l2)); | 151 JSON11_TEST_ASSERT(Json(l1) == Json(l2)); |
145 assert(Json(l2) == Json(l3)); | 152 JSON11_TEST_ASSERT(Json(l2) == Json(l3)); |
146 | 153 |
147 std::map<string, string> m1 { { "k1", "v1" }, { "k2", "v2" } }; | 154 std::map<string, string> m1 { { "k1", "v1" }, { "k2", "v2" } }; |
148 std::unordered_map<string, string> m2 { { "k1", "v1" }, { "k2", "v2" } }; | 155 std::unordered_map<string, string> m2 { { "k1", "v1" }, { "k2", "v2" } }; |
149 assert(Json(m1) == Json(m2)); | 156 JSON11_TEST_ASSERT(Json(m1) == Json(m2)); |
150 | 157 |
151 // Json literals | 158 // Json literals |
152 Json obj = Json::object({ | 159 const Json obj = Json::object({ |
153 { "k1", "v1" }, | 160 { "k1", "v1" }, |
154 { "k2", 42.0 }, | 161 { "k2", 42.0 }, |
155 { "k3", Json::array({ "a", 123.0, true, false, nullptr }) }, | 162 { "k3", Json::array({ "a", 123.0, true, false, nullptr }) }, |
156 }); | 163 }); |
157 | 164 |
158 std::cout << "obj: " << obj.dump() << "\n"; | 165 std::cout << "obj: " << obj.dump() << "\n"; |
159 | 166 JSON11_TEST_ASSERT(obj.dump() == "{\"k1\": \"v1\", \"k2\": 42, \"k3\": [\"a\", 123, true, false, null]}"); |
160 assert(Json("a").number_value() == 0); | 167 |
161 assert(Json("a").string_value() == "a"); | 168 JSON11_TEST_ASSERT(Json("a").number_value() == 0); |
162 assert(Json().number_value() == 0); | 169 JSON11_TEST_ASSERT(Json("a").string_value() == "a"); |
163 | 170 JSON11_TEST_ASSERT(Json().number_value() == 0); |
164 assert(obj == json); | 171 |
165 assert(Json(42) == Json(42.0)); | 172 JSON11_TEST_ASSERT(obj == json); |
166 assert(Json(42) != Json(42.1)); | 173 JSON11_TEST_ASSERT(Json(42) == Json(42.0)); |
174 JSON11_TEST_ASSERT(Json(42) != Json(42.1)); | |
167 | 175 |
168 const string unicode_escape_test = | 176 const string unicode_escape_test = |
169 R"([ "blah\ud83d\udca9blah\ud83dblah\udca9blah\u0000blah\u1234" ])"; | 177 R"([ "blah\ud83d\udca9blah\ud83dblah\udca9blah\u0000blah\u1234" ])"; |
170 | 178 |
171 const char utf8[] = "blah" "\xf0\x9f\x92\xa9" "blah" "\xed\xa0\xbd" "blah" | 179 const char utf8[] = "blah" "\xf0\x9f\x92\xa9" "blah" "\xed\xa0\xbd" "blah" |
172 "\xed\xb2\xa9" "blah" "\0" "blah" "\xe1\x88\xb4"; | 180 "\xed\xb2\xa9" "blah" "\0" "blah" "\xe1\x88\xb4"; |
173 | 181 |
174 Json uni = Json::parse(unicode_escape_test, err); | 182 Json uni = Json::parse(unicode_escape_test, err); |
175 assert(uni[0].string_value().size() == (sizeof utf8) - 1); | 183 JSON11_TEST_ASSERT(uni[0].string_value().size() == (sizeof utf8) - 1); |
176 assert(std::memcmp(uni[0].string_value().data(), utf8, sizeof utf8) == 0); | 184 JSON11_TEST_ASSERT(std::memcmp(uni[0].string_value().data(), utf8, sizeof utf8) == 0); |
177 | 185 |
178 // Demonstrates the behavior change in Xcode 7 / Clang 3.7 described | 186 // Demonstrates the behavior change in Xcode 7 / Clang 3.7, introduced by DR1467 |
179 // here: https://llvm.org/bugs/show_bug.cgi?id=23812 | 187 // and described here: https://llvm.org/bugs/show_bug.cgi?id=23812 |
180 Json nested_array = Json::array { Json::array { 1, 2, 3 } }; | 188 if (JSON11_ENABLE_DR1467_CANARY) { |
181 assert(nested_array.is_array()); | 189 Json nested_array = Json::array { Json::array { 1, 2, 3 } }; |
182 assert(nested_array.array_items().size() == 1); | 190 JSON11_TEST_ASSERT(nested_array.is_array()); |
183 assert(nested_array.array_items()[0].is_array()); | 191 JSON11_TEST_ASSERT(nested_array.array_items().size() == 1); |
184 assert(nested_array.array_items()[0].array_items().size() == 3); | 192 JSON11_TEST_ASSERT(nested_array.array_items()[0].is_array()); |
193 JSON11_TEST_ASSERT(nested_array.array_items()[0].array_items().size() == 3); | |
194 } | |
195 | |
196 { | |
197 const std::string good_json = R"( {"k1" : "v1"})"; | |
198 const std::string bad_json1 = good_json + " {"; | |
199 const std::string bad_json2 = good_json + R"({"k2":"v2", "k3":[)"; | |
200 struct TestMultiParse { | |
201 std::string input; | |
202 std::string::size_type expect_parser_stop_pos; | |
203 size_t expect_not_empty_elms_count; | |
204 Json expect_parse_res; | |
205 } tests[] = { | |
206 {" {", 0, 0, {}}, | |
207 {good_json, good_json.size(), 1, Json(std::map<string, string>{ { "k1", "v1" } })}, | |
208 {bad_json1, good_json.size() + 1, 1, Json(std::map<string, string>{ { "k1", "v1" } })}, | |
209 {bad_json2, good_json.size(), 1, Json(std::map<string, string>{ { "k1", "v1" } })}, | |
210 {"{}", 2, 1, Json::object{}}, | |
211 }; | |
212 for (const auto &tst : tests) { | |
213 std::string::size_type parser_stop_pos; | |
214 std::string err; | |
215 auto res = Json::parse_multi(tst.input, parser_stop_pos, err); | |
216 JSON11_TEST_ASSERT(parser_stop_pos == tst.expect_parser_stop_pos); | |
217 JSON11_TEST_ASSERT( | |
218 (size_t)std::count_if(res.begin(), res.end(), | |
219 [](const Json& j) { return !j.is_null(); }) | |
220 == tst.expect_not_empty_elms_count); | |
221 if (!res.empty()) { | |
222 JSON11_TEST_ASSERT(tst.expect_parse_res == res[0]); | |
223 } | |
224 } | |
225 } | |
185 | 226 |
186 Json my_json = Json::object { | 227 Json my_json = Json::object { |
187 { "key1", "value1" }, | 228 { "key1", "value1" }, |
188 { "key2", false }, | 229 { "key2", false }, |
189 { "key3", Json::array { 1, 2, 3 } }, | 230 { "key3", Json::array { 1, 2, 3 } }, |
190 }; | 231 }; |
191 std::string json_str = my_json.dump(); | 232 std::string json_obj_str = my_json.dump(); |
192 printf("%s\n", json_str.c_str()); | 233 std::cout << "json_obj_str: " << json_obj_str << "\n"; |
234 JSON11_TEST_ASSERT(json_obj_str == "{\"key1\": \"value1\", \"key2\": false, \"key3\": [1, 2, 3]}"); | |
193 | 235 |
194 class Point { | 236 class Point { |
195 public: | 237 public: |
196 int x; | 238 int x; |
197 int y; | 239 int y; |
199 Json to_json() const { return Json::array { x, y }; } | 241 Json to_json() const { return Json::array { x, y }; } |
200 }; | 242 }; |
201 | 243 |
202 std::vector<Point> points = { { 1, 2 }, { 10, 20 }, { 100, 200 } }; | 244 std::vector<Point> points = { { 1, 2 }, { 10, 20 }, { 100, 200 } }; |
203 std::string points_json = Json(points).dump(); | 245 std::string points_json = Json(points).dump(); |
204 printf("%s\n", points_json.c_str()); | 246 std::cout << "points_json: " << points_json << "\n"; |
247 JSON11_TEST_ASSERT(points_json == "[[1, 2], [10, 20], [100, 200]]"); | |
205 } | 248 } |
249 | |
250 #if JSON11_TEST_STANDALONE_MAIN | |
251 | |
252 static void parse_from_stdin() { | |
253 string buf; | |
254 string line; | |
255 while (std::getline(std::cin, line)) { | |
256 buf += line + "\n"; | |
257 } | |
258 | |
259 string err; | |
260 auto json = Json::parse(buf, err); | |
261 if (!err.empty()) { | |
262 printf("Failed: %s\n", err.c_str()); | |
263 } else { | |
264 printf("Result: %s\n", json.dump().c_str()); | |
265 } | |
266 } | |
267 | |
268 int main(int argc, char **argv) { | |
269 if (argc == 2 && argv[1] == string("--stdin")) { | |
270 parse_from_stdin(); | |
271 return 0; | |
272 } | |
273 | |
274 json11_test(); | |
275 } | |
276 | |
277 #endif // JSON11_TEST_STANDALONE_MAIN | |
278 | |
279 // Insert user-defined suffix code (function definitions, etc) | |
280 // to set up a custom test suite | |
281 JSON11_TEST_CPP_SUFFIX_CODE |