diff --git a/CMakeLists.txt b/CMakeLists.txt index ad15ef1..75dbdf0 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -47,11 +47,11 @@ target_include_directories(jsoncpp SYSTEM PRIVATE thirdparty/jsoncpp-0.9.4/inclu set_target_properties(jsoncpp PROPERTIES ARCHIVE_OUTPUT_DIRECTORY ${PROJECT_BINARY_DIR}/thirdparty/jsoncpp-0.9.4) add_library(json11 - thirdparty/json11-2016-01-26/json11.cpp + thirdparty/json11-ec4e452/json11.cpp ) -target_include_directories(json11 SYSTEM PRIVATE thirdparty/json11-2016-01-26) -set_target_properties(json11 PROPERTIES ARCHIVE_OUTPUT_DIRECTORY ${PROJECT_BINARY_DIR}/thirdparty/json11-2016-01-26) +target_include_directories(json11 SYSTEM PRIVATE thirdparty/json11-ec4e452) +set_target_properties(json11 PROPERTIES ARCHIVE_OUTPUT_DIRECTORY ${PROJECT_BINARY_DIR}/thirdparty/json11-ec4e452) # Build local gtest set(gtest_force_shared_crt ON) @@ -61,7 +61,7 @@ add_subdirectory(thirdparty/gtest-1.7.0) include_directories(include) include_directories(SYSTEM thirdparty/gtest-1.7.0/include - thirdparty/json11-2016-01-26 + thirdparty/json11-ec4e452 thirdparty/jsoncpp-0.9.4/include thirdparty/rapidjson-1.0.2/include thirdparty/picojson-1.3.0 diff --git a/thirdparty/json11-2016-01-26/.gitignore b/thirdparty/json11-2016-01-26/.gitignore deleted file mode 100644 index 9daeafb..0000000 --- a/thirdparty/json11-2016-01-26/.gitignore +++ /dev/null @@ -1 +0,0 @@ -test diff --git a/thirdparty/json11-2016-01-26/CMakeLists.txt b/thirdparty/json11-2016-01-26/CMakeLists.txt deleted file mode 100644 index ba8edd5..0000000 --- a/thirdparty/json11-2016-01-26/CMakeLists.txt +++ /dev/null @@ -1,21 +0,0 @@ -project(json11) - -cmake_minimum_required(VERSION 2.8) - -enable_testing() - -add_definitions( - -std=c++11 - -fno-rtti - -fno-exceptions - -Wall - -Wextra - -Werror) - -set(json11_SRCS json11.cpp) - -add_library(json11 STATIC ${json11_SRCS}) - -add_test(json11_test json11_test) - -add_executable(json11_test ${json11_SRCS} test.cpp) diff --git a/thirdparty/json11-2016-01-26/Makefile b/thirdparty/json11-2016-01-26/Makefile deleted file mode 100644 index 5a6adc6..0000000 --- a/thirdparty/json11-2016-01-26/Makefile +++ /dev/null @@ -1,7 +0,0 @@ -test: json11.cpp json11.hpp test.cpp - $(CXX) -O -std=c++11 json11.cpp test.cpp -o test -fno-rtti -fno-exceptions - -clean: - if [ -e test ]; then rm test; fi - -.PHONY: clean diff --git a/thirdparty/json11-2016-01-26/test.cpp b/thirdparty/json11-2016-01-26/test.cpp deleted file mode 100644 index bd60705..0000000 --- a/thirdparty/json11-2016-01-26/test.cpp +++ /dev/null @@ -1,205 +0,0 @@ -#include -#include -#include -#include -#include -#include "json11.hpp" -#include -#include -#include -#include - -using namespace json11; -using std::string; - -// Check that Json has the properties we want. -#include -#define CHECK_TRAIT(x) static_assert(std::x::value, #x) -CHECK_TRAIT(is_nothrow_constructible); -CHECK_TRAIT(is_nothrow_default_constructible); -CHECK_TRAIT(is_copy_constructible); -CHECK_TRAIT(is_nothrow_move_constructible); -CHECK_TRAIT(is_copy_assignable); -CHECK_TRAIT(is_nothrow_move_assignable); -CHECK_TRAIT(is_nothrow_destructible); - -void parse_from_stdin() { - string buf; - string line; - while (std::getline(std::cin, line)) { - buf += line + "\n"; - } - - string err; - auto json = Json::parse(buf, err); - if (!err.empty()) { - printf("Failed: %s\n", err.c_str()); - } else { - printf("Result: %s\n", json.dump().c_str()); - } -} - -int main(int argc, char **argv) { - if (argc == 2 && argv[1] == string("--stdin")) { - parse_from_stdin(); - return 0; - } - - const string simple_test = - R"({"k1":"v1", "k2":42, "k3":["a",123,true,false,null]})"; - - string err; - auto json = Json::parse(simple_test, err); - - std::cout << "k1: " << json["k1"].string_value() << "\n"; - std::cout << "k3: " << json["k3"].dump() << "\n"; - - for (auto &k : json["k3"].array_items()) { - std::cout << " - " << k.dump() << "\n"; - } - - const string comment_test = R"({ - // comment /* with nested comment */ - "a": 1, - // comment - // continued - "b": "text", - /* multi - line - comment */ - // and single-line comment - "c": [1, 2, 3] - })"; - - string err_comment; - auto json_comment = Json::parse( - comment_test, err_comment, JsonParse::COMMENTS); - if (!err_comment.empty()) { - printf("Failed: %s\n", err_comment.c_str()); - } else { - printf("Result: %s\n", json_comment.dump().c_str()); - } - - string failing_comment_test = R"({ - /* bad comment - "a": 1, - })"; - - string err_failing_comment; - auto json_failing_comment = Json::parse( - failing_comment_test, err_failing_comment, JsonParse::COMMENTS); - if (!err_failing_comment.empty()) { - printf("Failed: %s\n", err_failing_comment.c_str()); - } else { - printf("Result: %s\n", json_failing_comment.dump().c_str()); - } - - failing_comment_test = R"({ - / / bad comment })"; - - json_failing_comment = Json::parse( - failing_comment_test, err_failing_comment, JsonParse::COMMENTS); - if (!err_failing_comment.empty()) { - printf("Failed: %s\n", err_failing_comment.c_str()); - } else { - printf("Result: %s\n", json_failing_comment.dump().c_str()); - } - - failing_comment_test = R"({// bad comment })"; - - json_failing_comment = Json::parse( - failing_comment_test, err_failing_comment, JsonParse::COMMENTS); - if (!err_failing_comment.empty()) { - printf("Failed: %s\n", err_failing_comment.c_str()); - } else { - printf("Result: %s\n", json_failing_comment.dump().c_str()); - } - - failing_comment_test = R"({ - "a": 1 - }/)"; - - json_failing_comment = Json::parse( - failing_comment_test, err_failing_comment, JsonParse::COMMENTS); - if (!err_failing_comment.empty()) { - printf("Failed: %s\n", err_failing_comment.c_str()); - } else { - printf("Result: %s\n", json_failing_comment.dump().c_str()); - } - - failing_comment_test = R"({/* bad - comment *})"; - - json_failing_comment = Json::parse( - failing_comment_test, err_failing_comment, JsonParse::COMMENTS); - if (!err_failing_comment.empty()) { - printf("Failed: %s\n", err_failing_comment.c_str()); - } else { - printf("Result: %s\n", json_failing_comment.dump().c_str()); - } - - std::list l1 { 1, 2, 3 }; - std::vector l2 { 1, 2, 3 }; - std::set l3 { 1, 2, 3 }; - assert(Json(l1) == Json(l2)); - assert(Json(l2) == Json(l3)); - - std::map m1 { { "k1", "v1" }, { "k2", "v2" } }; - std::unordered_map m2 { { "k1", "v1" }, { "k2", "v2" } }; - assert(Json(m1) == Json(m2)); - - // Json literals - Json obj = Json::object({ - { "k1", "v1" }, - { "k2", 42.0 }, - { "k3", Json::array({ "a", 123.0, true, false, nullptr }) }, - }); - - std::cout << "obj: " << obj.dump() << "\n"; - - assert(Json("a").number_value() == 0); - assert(Json("a").string_value() == "a"); - assert(Json().number_value() == 0); - - assert(obj == json); - assert(Json(42) == Json(42.0)); - assert(Json(42) != Json(42.1)); - - const string unicode_escape_test = - R"([ "blah\ud83d\udca9blah\ud83dblah\udca9blah\u0000blah\u1234" ])"; - - const char utf8[] = "blah" "\xf0\x9f\x92\xa9" "blah" "\xed\xa0\xbd" "blah" - "\xed\xb2\xa9" "blah" "\0" "blah" "\xe1\x88\xb4"; - - Json uni = Json::parse(unicode_escape_test, err); - assert(uni[0].string_value().size() == (sizeof utf8) - 1); - assert(std::memcmp(uni[0].string_value().data(), utf8, sizeof utf8) == 0); - - // Demonstrates the behavior change in Xcode 7 / Clang 3.7 described - // here: https://llvm.org/bugs/show_bug.cgi?id=23812 - Json nested_array = Json::array { Json::array { 1, 2, 3 } }; - assert(nested_array.is_array()); - assert(nested_array.array_items().size() == 1); - assert(nested_array.array_items()[0].is_array()); - assert(nested_array.array_items()[0].array_items().size() == 3); - - Json my_json = Json::object { - { "key1", "value1" }, - { "key2", false }, - { "key3", Json::array { 1, 2, 3 } }, - }; - std::string json_str = my_json.dump(); - printf("%s\n", json_str.c_str()); - - class Point { - public: - int x; - int y; - Point (int x, int y) : x(x), y(y) {} - Json to_json() const { return Json::array { x, y }; } - }; - - std::vector points = { { 1, 2 }, { 10, 20 }, { 100, 200 } }; - std::string points_json = Json(points).dump(); - printf("%s\n", points_json.c_str()); -} diff --git a/thirdparty/json11-ec4e452/.gitignore b/thirdparty/json11-ec4e452/.gitignore new file mode 100755 index 0000000..e959b6f --- /dev/null +++ b/thirdparty/json11-ec4e452/.gitignore @@ -0,0 +1,12 @@ +# generated files +test +libjson11.a +json11.pc + +# Cmake +CMakeCache.txt +CTestTestfile.cmake +CMakeFiles +CMakeScripts +cmake_install.cmake +install_manifest.txt \ No newline at end of file diff --git a/thirdparty/json11-ec4e452/CMakeLists.txt b/thirdparty/json11-ec4e452/CMakeLists.txt new file mode 100755 index 0000000..819c36f --- /dev/null +++ b/thirdparty/json11-ec4e452/CMakeLists.txt @@ -0,0 +1,57 @@ +cmake_minimum_required(VERSION 2.8) +if (CMAKE_VERSION VERSION_LESS "3") + project(json11 CXX) +else() + cmake_policy(SET CMP0048 NEW) + project(json11 VERSION 1.0.0 LANGUAGES CXX) +endif() + +enable_testing() + +option(JSON11_BUILD_TESTS "Build unit tests" OFF) +option(JSON11_ENABLE_DR1467_CANARY "Enable canary test for DR 1467" OFF) + +if(CMAKE_VERSION VERSION_LESS "3") + add_definitions(-std=c++11) +else() + set(CMAKE_CXX_STANDARD 11) + set(CMAKE_CXX_STANDARD_REQUIRED ON) +endif() + +if(CMAKE_INSTALL_PREFIX_INITIALIZED_TO_DEFAULT) + set(CMAKE_INSTALL_PREFIX /usr) +endif() + +add_library(json11 json11.cpp) +target_include_directories(json11 PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}) +target_compile_options(json11 + PRIVATE -fPIC -fno-rtti -fno-exceptions -Wall) + +# Set warning flags, which may vary per platform +include(CheckCXXCompilerFlag) +set(_possible_warnings_flags /W4 /WX -Wextra -Werror) +foreach(_warning_flag in ${_possible_warnings_flags}) + CHECK_CXX_COMPILER_FLAG(_warning_flag _flag_supported) + if(${_flag_supported}) + target_compile_options(json11 PRIVATE ${_warning_flag}) + endif() +endforeach() + +configure_file("json11.pc.in" "json11.pc" @ONLY) + +if (JSON11_BUILD_TESTS) + + # enable test for DR1467, described here: https://llvm.org/bugs/show_bug.cgi?id=23812 + if(JSON11_ENABLE_DR1467_CANARY) + add_definitions(-D JSON11_ENABLE_DR1467_CANARY=1) + else() + add_definitions(-D JSON11_ENABLE_DR1467_CANARY=0) + endif() + + add_executable(json11_test test.cpp) + target_link_libraries(json11_test json11) +endif() + +install(TARGETS json11 DESTINATION lib/${CMAKE_LIBRARY_ARCHITECTURE}) +install(FILES "${CMAKE_CURRENT_SOURCE_DIR}/json11.hpp" DESTINATION include/${CMAKE_LIBRARY_ARCHITECTURE}) +install(FILES "${CMAKE_CURRENT_BINARY_DIR}/json11.pc" DESTINATION lib/${CMAKE_LIBRARY_ARCHITECTURE}/pkgconfig) diff --git a/thirdparty/json11-2016-01-26/LICENSE.txt b/thirdparty/json11-ec4e452/LICENSE.txt old mode 100644 new mode 100755 similarity index 100% rename from thirdparty/json11-2016-01-26/LICENSE.txt rename to thirdparty/json11-ec4e452/LICENSE.txt diff --git a/thirdparty/json11-ec4e452/Makefile b/thirdparty/json11-ec4e452/Makefile new file mode 100755 index 0000000..f946bdd --- /dev/null +++ b/thirdparty/json11-ec4e452/Makefile @@ -0,0 +1,15 @@ +# Environment variable to enable or disable code which demonstrates the behavior change +# in Xcode 7 / Clang 3.7, introduced by DR1467 and described here: +# https://llvm.org/bugs/show_bug.cgi?id=23812 +# Defaults to on in order to act as a warning to anyone who's unaware of the issue. +ifneq ($(JSON11_ENABLE_DR1467_CANARY),) +CANARY_ARGS = -DJSON11_ENABLE_DR1467_CANARY=$(JSON11_ENABLE_DR1467_CANARY) +endif + +test: json11.cpp json11.hpp test.cpp + $(CXX) $(CANARY_ARGS) -O -std=c++11 json11.cpp test.cpp -o test -fno-rtti -fno-exceptions + +clean: + if [ -e test ]; then rm test; fi + +.PHONY: clean diff --git a/thirdparty/json11-2016-01-26/README.md b/thirdparty/json11-ec4e452/README.md old mode 100644 new mode 100755 similarity index 100% rename from thirdparty/json11-2016-01-26/README.md rename to thirdparty/json11-ec4e452/README.md diff --git a/thirdparty/json11-2016-01-26/json11.cpp b/thirdparty/json11-ec4e452/json11.cpp old mode 100644 new mode 100755 similarity index 94% rename from thirdparty/json11-2016-01-26/json11.cpp rename to thirdparty/json11-ec4e452/json11.cpp index 38fd4c8..9647846 --- a/thirdparty/json11-2016-01-26/json11.cpp +++ b/thirdparty/json11-ec4e452/json11.cpp @@ -37,11 +37,20 @@ using std::make_shared; using std::initializer_list; using std::move; +/* Helper for representing null - just a do-nothing struct, plus comparison + * operators so the helpers in JsonValue work. We can't use nullptr_t because + * it may not be orderable. + */ +struct NullStruct { + bool operator==(NullStruct) const { return true; } + bool operator<(NullStruct) const { return false; } +}; + /* * * * * * * * * * * * * * * * * * * * * Serialization */ -static void dump(std::nullptr_t, string &out) { +static void dump(NullStruct, string &out) { out += "null"; } @@ -208,9 +217,9 @@ public: explicit JsonObject(Json::object &&value) : Value(move(value)) {} }; -class JsonNull final : public Value { +class JsonNull final : public Value { public: - JsonNull() : Value(nullptr) {} + JsonNull() : Value({}) {} }; /* * * * * * * * * * * * * * * * * * * * @@ -291,6 +300,8 @@ const Json & JsonArray::operator[] (size_t i) const { */ bool Json::operator== (const Json &other) const { + if (m_ptr == other.m_ptr) + return true; if (m_ptr->type() != other.m_ptr->type()) return false; @@ -298,6 +309,8 @@ bool Json::operator== (const Json &other) const { } bool Json::operator< (const Json &other) const { + if (m_ptr == other.m_ptr) + return false; if (m_ptr->type() != other.m_ptr->type()) return m_ptr->type() < other.m_ptr->type(); @@ -326,11 +339,12 @@ static inline bool in_range(long x, long lower, long upper) { return (x >= lower && x <= upper); } +namespace { /* JsonParser * * Object that tracks all state of an in-progress parse. */ -struct JsonParser { +struct JsonParser final { /* State */ @@ -374,38 +388,31 @@ struct JsonParser { if (str[i] == '/') { i++; if (i == str.size()) - return fail("unexpected end of input inside comment", 0); + return fail("unexpected end of input after start of comment", false); if (str[i] == '/') { // inline comment i++; - if (i == str.size()) - return fail("unexpected end of input inside inline comment", 0); - // advance until next line - while (str[i] != '\n') { + // advance until next line, or end of input + while (i < str.size() && str[i] != '\n') { i++; - if (i == str.size()) - return fail("unexpected end of input inside inline comment", 0); } comment_found = true; } else if (str[i] == '*') { // multiline comment i++; if (i > str.size()-2) - return fail("unexpected end of input inside multi-line comment", 0); + return fail("unexpected end of input inside multi-line comment", false); // advance until closing tokens while (!(str[i] == '*' && str[i+1] == '/')) { i++; if (i > str.size()-2) return fail( - "unexpected end of input inside multi-line comment", 0); + "unexpected end of input inside multi-line comment", false); } i += 2; - if (i == str.size()) - return fail( - "unexpected end of input inside multi-line comment", 0); comment_found = true; } else - return fail("malformed comment", 0); + return fail("malformed comment", false); } return comment_found; } @@ -420,6 +427,7 @@ struct JsonParser { bool comment_found = false; do { comment_found = consume_comment(); + if (failed) return; consume_whitespace(); } while(comment_found); @@ -433,8 +441,9 @@ struct JsonParser { */ char get_next_token() { consume_garbage(); + if (failed) return (char)0; if (i == str.size()) - return fail("unexpected end of input", 0); + return fail("unexpected end of input", (char)0); return str[i++]; } @@ -508,7 +517,7 @@ struct JsonParser { if (esc.length() < 4) { return fail("bad \\u escape: " + esc, ""); } - for (int j = 0; j < 4; j++) { + for (size_t j = 0; j < 4; j++) { if (!in_range(esc[j], 'a', 'f') && !in_range(esc[j], 'A', 'F') && !in_range(esc[j], '0', '9')) return fail("bad \\u escape: " + esc, ""); @@ -718,6 +727,7 @@ struct JsonParser { return fail("expected value, got " + esc(ch)); } }; +}//namespace { Json Json::parse(const string &in, string &err, JsonParse strategy) { JsonParser parser { in, 0, err, false, strategy }; @@ -725,6 +735,8 @@ Json Json::parse(const string &in, string &err, JsonParse strategy) { // Check for any trailing garbage parser.consume_garbage(); + if (parser.failed) + return Json(); if (parser.i != in.size()) return parser.fail("unexpected trailing " + esc(in[parser.i])); @@ -733,15 +745,22 @@ Json Json::parse(const string &in, string &err, JsonParse strategy) { // Documented in json11.hpp vector Json::parse_multi(const string &in, + std::string::size_type &parser_stop_pos, string &err, JsonParse strategy) { JsonParser parser { in, 0, err, false, strategy }; - + parser_stop_pos = 0; vector json_vec; while (parser.i != in.size() && !parser.failed) { json_vec.push_back(parser.parse_json(0)); + if (parser.failed) + break; + // Check for another object parser.consume_garbage(); + if (parser.failed) + break; + parser_stop_pos = parser.i; } return json_vec; } diff --git a/thirdparty/json11-2016-01-26/json11.hpp b/thirdparty/json11-ec4e452/json11.hpp old mode 100644 new mode 100755 similarity index 91% rename from thirdparty/json11-2016-01-26/json11.hpp rename to thirdparty/json11-ec4e452/json11.hpp index a99e241..0c47d05 --- a/thirdparty/json11-2016-01-26/json11.hpp +++ b/thirdparty/json11-ec4e452/json11.hpp @@ -56,6 +56,18 @@ #include #include +#ifdef _MSC_VER + #if _MSC_VER <= 1800 // VS 2013 + #ifndef noexcept + #define noexcept throw() + #endif + + #ifndef snprintf + #define snprintf _snprintf_s + #endif + #endif +#endif + namespace json11 { enum JsonParse { @@ -95,14 +107,14 @@ public: // Implicit constructor: map-like objects (std::map, std::unordered_map, etc) template ::value - && std::is_constructible::value, + std::is_constructible().begin()->first)>::value + && std::is_constructible().begin()->second)>::value, int>::type = 0> Json(const M & m) : Json(object(m.begin(), m.end())) {} // Implicit constructor: vector-like objects (std::list, std::vector, std::set, etc) template ::value, + std::is_constructible().begin())>::value, int>::type = 0> Json(const V & v) : Json(array(v.begin(), v.end())) {} @@ -165,9 +177,18 @@ public: // Parse multiple objects, concatenated or separated by whitespace static std::vector parse_multi( const std::string & in, + std::string::size_type & parser_stop_pos, std::string & err, JsonParse strategy = JsonParse::STANDARD); + static inline std::vector parse_multi( + const std::string & in, + std::string & err, + JsonParse strategy = JsonParse::STANDARD) { + std::string::size_type parser_stop_pos; + return parse_multi(in, parser_stop_pos, err, strategy); + } + bool operator== (const Json &rhs) const; bool operator< (const Json &rhs) const; bool operator!= (const Json &rhs) const { return !(*this == rhs); } diff --git a/thirdparty/json11-ec4e452/json11.pc.in b/thirdparty/json11-ec4e452/json11.pc.in new file mode 100755 index 0000000..63fb241 --- /dev/null +++ b/thirdparty/json11-ec4e452/json11.pc.in @@ -0,0 +1,9 @@ +prefix=@CMAKE_INSTALL_PREFIX@ +libdir=${prefix}/lib/@CMAKE_LIBRARY_ARCHITECTURE@ +includedir=${prefix}/include/@CMAKE_LIBRARY_ARCHITECTURE@ + +Name: @PROJECT_NAME@ +Description: json11 is a tiny JSON library for C++11, providing JSON parsing and serialization. +Version: @PROJECT_VERSION@ +Libs: -L${libdir} -ljson11 +Cflags: -I${includedir} diff --git a/thirdparty/json11-ec4e452/test.cpp b/thirdparty/json11-ec4e452/test.cpp new file mode 100755 index 0000000..ab2e2b9 --- /dev/null +++ b/thirdparty/json11-ec4e452/test.cpp @@ -0,0 +1,281 @@ +/* + * Define JSON11_TEST_CUSTOM_CONFIG to 1 if you want to build this tester into + * your own unit-test framework rather than a stand-alone program. By setting + * The values of the variables included below, you can insert your own custom + * code into this file as it builds, in order to make it into a test case for + * your favorite framework. + */ +#if !JSON11_TEST_CUSTOM_CONFIG +#define JSON11_TEST_CPP_PREFIX_CODE +#define JSON11_TEST_CPP_SUFFIX_CODE +#define JSON11_TEST_STANDALONE_MAIN 1 +#define JSON11_TEST_CASE(name) static void name() +#define JSON11_TEST_ASSERT(b) assert(b) +#ifdef NDEBUG +#undef NDEBUG//at now assert will work even in Release build +#endif +#endif // JSON11_TEST_CUSTOM_CONFIG + +/* + * Enable or disable code which demonstrates the behavior change in Xcode 7 / Clang 3.7, + * introduced by DR1467 and described here: https://github.com/dropbox/json11/issues/86 + * Defaults to off since it doesn't appear the standards committee is likely to act + * on this, so it needs to be considered normal behavior. + */ +#ifndef JSON11_ENABLE_DR1467_CANARY +#define JSON11_ENABLE_DR1467_CANARY 0 +#endif + +/* + * Beginning of standard source file, which makes use of the customizations above. + */ +#include +#include +#include +#include +#include +#include +#include "json11.hpp" +#include +#include +#include +#include +#include + +// Insert user-defined prefix code (includes, function declarations, etc) +// to set up a custom test suite +JSON11_TEST_CPP_PREFIX_CODE + +using namespace json11; +using std::string; + +// Check that Json has the properties we want. +#define CHECK_TRAIT(x) static_assert(std::x::value, #x) +CHECK_TRAIT(is_nothrow_constructible); +CHECK_TRAIT(is_nothrow_default_constructible); +CHECK_TRAIT(is_copy_constructible); +CHECK_TRAIT(is_nothrow_move_constructible); +CHECK_TRAIT(is_copy_assignable); +CHECK_TRAIT(is_nothrow_move_assignable); +CHECK_TRAIT(is_nothrow_destructible); + +JSON11_TEST_CASE(json11_test) { + const string simple_test = + R"({"k1":"v1", "k2":42, "k3":["a",123,true,false,null]})"; + + string err; + const auto json = Json::parse(simple_test, err); + + std::cout << "k1: " << json["k1"].string_value() << "\n"; + std::cout << "k3: " << json["k3"].dump() << "\n"; + + for (auto &k : json["k3"].array_items()) { + std::cout << " - " << k.dump() << "\n"; + } + + string comment_test = R"({ + // comment /* with nested comment */ + "a": 1, + // comment + // continued + "b": "text", + /* multi + line + comment + // line-comment-inside-multiline-comment + */ + // and single-line comment + // and single-line comment /* multiline inside single line */ + "c": [1, 2, 3] + // and single-line comment at end of object + })"; + + string err_comment; + auto json_comment = Json::parse( + comment_test, err_comment, JsonParse::COMMENTS); + JSON11_TEST_ASSERT(!json_comment.is_null()); + JSON11_TEST_ASSERT(err_comment.empty()); + + comment_test = "{\"a\": 1}//trailing line comment"; + json_comment = Json::parse( + comment_test, err_comment, JsonParse::COMMENTS); + JSON11_TEST_ASSERT(!json_comment.is_null()); + JSON11_TEST_ASSERT(err_comment.empty()); + + comment_test = "{\"a\": 1}/*trailing multi-line comment*/"; + json_comment = Json::parse( + comment_test, err_comment, JsonParse::COMMENTS); + JSON11_TEST_ASSERT(!json_comment.is_null()); + JSON11_TEST_ASSERT(err_comment.empty()); + + string failing_comment_test = "{\n/* unterminated comment\n\"a\": 1,\n}"; + string err_failing_comment; + auto json_failing_comment = Json::parse( + failing_comment_test, err_failing_comment, JsonParse::COMMENTS); + JSON11_TEST_ASSERT(json_failing_comment.is_null()); + JSON11_TEST_ASSERT(!err_failing_comment.empty()); + + failing_comment_test = "{\n/* unterminated trailing comment }"; + json_failing_comment = Json::parse( + failing_comment_test, err_failing_comment, JsonParse::COMMENTS); + JSON11_TEST_ASSERT(json_failing_comment.is_null()); + JSON11_TEST_ASSERT(!err_failing_comment.empty()); + + failing_comment_test = "{\n/ / bad comment }"; + json_failing_comment = Json::parse( + failing_comment_test, err_failing_comment, JsonParse::COMMENTS); + JSON11_TEST_ASSERT(json_failing_comment.is_null()); + JSON11_TEST_ASSERT(!err_failing_comment.empty()); + + failing_comment_test = "{// bad comment }"; + json_failing_comment = Json::parse( + failing_comment_test, err_failing_comment, JsonParse::COMMENTS); + JSON11_TEST_ASSERT(json_failing_comment.is_null()); + JSON11_TEST_ASSERT(!err_failing_comment.empty()); + + failing_comment_test = "{\n\"a\": 1\n}/"; + json_failing_comment = Json::parse( + failing_comment_test, err_failing_comment, JsonParse::COMMENTS); + JSON11_TEST_ASSERT(json_failing_comment.is_null()); + JSON11_TEST_ASSERT(!err_failing_comment.empty()); + + failing_comment_test = "{/* bad\ncomment *}"; + json_failing_comment = Json::parse( + failing_comment_test, err_failing_comment, JsonParse::COMMENTS); + JSON11_TEST_ASSERT(json_failing_comment.is_null()); + JSON11_TEST_ASSERT(!err_failing_comment.empty()); + + std::list l1 { 1, 2, 3 }; + std::vector l2 { 1, 2, 3 }; + std::set l3 { 1, 2, 3 }; + JSON11_TEST_ASSERT(Json(l1) == Json(l2)); + JSON11_TEST_ASSERT(Json(l2) == Json(l3)); + + std::map m1 { { "k1", "v1" }, { "k2", "v2" } }; + std::unordered_map m2 { { "k1", "v1" }, { "k2", "v2" } }; + JSON11_TEST_ASSERT(Json(m1) == Json(m2)); + + // Json literals + const Json obj = Json::object({ + { "k1", "v1" }, + { "k2", 42.0 }, + { "k3", Json::array({ "a", 123.0, true, false, nullptr }) }, + }); + + std::cout << "obj: " << obj.dump() << "\n"; + JSON11_TEST_ASSERT(obj.dump() == "{\"k1\": \"v1\", \"k2\": 42, \"k3\": [\"a\", 123, true, false, null]}"); + + JSON11_TEST_ASSERT(Json("a").number_value() == 0); + JSON11_TEST_ASSERT(Json("a").string_value() == "a"); + JSON11_TEST_ASSERT(Json().number_value() == 0); + + JSON11_TEST_ASSERT(obj == json); + JSON11_TEST_ASSERT(Json(42) == Json(42.0)); + JSON11_TEST_ASSERT(Json(42) != Json(42.1)); + + const string unicode_escape_test = + R"([ "blah\ud83d\udca9blah\ud83dblah\udca9blah\u0000blah\u1234" ])"; + + const char utf8[] = "blah" "\xf0\x9f\x92\xa9" "blah" "\xed\xa0\xbd" "blah" + "\xed\xb2\xa9" "blah" "\0" "blah" "\xe1\x88\xb4"; + + Json uni = Json::parse(unicode_escape_test, err); + JSON11_TEST_ASSERT(uni[0].string_value().size() == (sizeof utf8) - 1); + JSON11_TEST_ASSERT(std::memcmp(uni[0].string_value().data(), utf8, sizeof utf8) == 0); + + // Demonstrates the behavior change in Xcode 7 / Clang 3.7, introduced by DR1467 + // and described here: https://llvm.org/bugs/show_bug.cgi?id=23812 + if (JSON11_ENABLE_DR1467_CANARY) { + Json nested_array = Json::array { Json::array { 1, 2, 3 } }; + JSON11_TEST_ASSERT(nested_array.is_array()); + JSON11_TEST_ASSERT(nested_array.array_items().size() == 1); + JSON11_TEST_ASSERT(nested_array.array_items()[0].is_array()); + JSON11_TEST_ASSERT(nested_array.array_items()[0].array_items().size() == 3); + } + + { + const std::string good_json = R"( {"k1" : "v1"})"; + const std::string bad_json1 = good_json + " {"; + const std::string bad_json2 = good_json + R"({"k2":"v2", "k3":[)"; + struct TestMultiParse { + std::string input; + std::string::size_type expect_parser_stop_pos; + size_t expect_not_empty_elms_count; + Json expect_parse_res; + } tests[] = { + {" {", 0, 0, {}}, + {good_json, good_json.size(), 1, Json(std::map{ { "k1", "v1" } })}, + {bad_json1, good_json.size() + 1, 1, Json(std::map{ { "k1", "v1" } })}, + {bad_json2, good_json.size(), 1, Json(std::map{ { "k1", "v1" } })}, + {"{}", 2, 1, Json::object{}}, + }; + for (const auto &tst : tests) { + std::string::size_type parser_stop_pos; + std::string err; + auto res = Json::parse_multi(tst.input, parser_stop_pos, err); + JSON11_TEST_ASSERT(parser_stop_pos == tst.expect_parser_stop_pos); + JSON11_TEST_ASSERT( + (size_t)std::count_if(res.begin(), res.end(), + [](const Json& j) { return !j.is_null(); }) + == tst.expect_not_empty_elms_count); + if (!res.empty()) { + JSON11_TEST_ASSERT(tst.expect_parse_res == res[0]); + } + } + } + + Json my_json = Json::object { + { "key1", "value1" }, + { "key2", false }, + { "key3", Json::array { 1, 2, 3 } }, + }; + std::string json_obj_str = my_json.dump(); + std::cout << "json_obj_str: " << json_obj_str << "\n"; + JSON11_TEST_ASSERT(json_obj_str == "{\"key1\": \"value1\", \"key2\": false, \"key3\": [1, 2, 3]}"); + + class Point { + public: + int x; + int y; + Point (int x, int y) : x(x), y(y) {} + Json to_json() const { return Json::array { x, y }; } + }; + + std::vector points = { { 1, 2 }, { 10, 20 }, { 100, 200 } }; + std::string points_json = Json(points).dump(); + std::cout << "points_json: " << points_json << "\n"; + JSON11_TEST_ASSERT(points_json == "[[1, 2], [10, 20], [100, 200]]"); +} + +#if JSON11_TEST_STANDALONE_MAIN + +static void parse_from_stdin() { + string buf; + string line; + while (std::getline(std::cin, line)) { + buf += line + "\n"; + } + + string err; + auto json = Json::parse(buf, err); + if (!err.empty()) { + printf("Failed: %s\n", err.c_str()); + } else { + printf("Result: %s\n", json.dump().c_str()); + } +} + +int main(int argc, char **argv) { + if (argc == 2 && argv[1] == string("--stdin")) { + parse_from_stdin(); + return 0; + } + + json11_test(); +} + +#endif // JSON11_TEST_STANDALONE_MAIN + +// Insert user-defined suffix code (function definitions, etc) +// to set up a custom test suite +JSON11_TEST_CPP_SUFFIX_CODE