annotate 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
rev   line source
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