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