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