Update embedded version of json11 so that tests can be built using clang 4+

This commit is contained in:
Tristan Penman 2017-09-23 09:36:01 +10:00
parent 29c566dea4
commit 665741110c
14 changed files with 441 additions and 261 deletions

View File

@ -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) set_target_properties(jsoncpp PROPERTIES ARCHIVE_OUTPUT_DIRECTORY ${PROJECT_BINARY_DIR}/thirdparty/jsoncpp-0.9.4)
add_library(json11 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) target_include_directories(json11 SYSTEM PRIVATE thirdparty/json11-ec4e452)
set_target_properties(json11 PROPERTIES ARCHIVE_OUTPUT_DIRECTORY ${PROJECT_BINARY_DIR}/thirdparty/json11-2016-01-26) set_target_properties(json11 PROPERTIES ARCHIVE_OUTPUT_DIRECTORY ${PROJECT_BINARY_DIR}/thirdparty/json11-ec4e452)
# Build local gtest # Build local gtest
set(gtest_force_shared_crt ON) set(gtest_force_shared_crt ON)
@ -61,7 +61,7 @@ add_subdirectory(thirdparty/gtest-1.7.0)
include_directories(include) include_directories(include)
include_directories(SYSTEM include_directories(SYSTEM
thirdparty/gtest-1.7.0/include thirdparty/gtest-1.7.0/include
thirdparty/json11-2016-01-26 thirdparty/json11-ec4e452
thirdparty/jsoncpp-0.9.4/include thirdparty/jsoncpp-0.9.4/include
thirdparty/rapidjson-1.0.2/include thirdparty/rapidjson-1.0.2/include
thirdparty/picojson-1.3.0 thirdparty/picojson-1.3.0

View File

@ -1 +0,0 @@
test

View File

@ -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)

View File

@ -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

View File

@ -1,205 +0,0 @@
#include <string>
#include <cstdio>
#include <cstring>
#include <iostream>
#include <sstream>
#include "json11.hpp"
#include <cassert>
#include <list>
#include <set>
#include <unordered_map>
using namespace json11;
using std::string;
// Check that Json has the properties we want.
#include <type_traits>
#define CHECK_TRAIT(x) static_assert(std::x::value, #x)
CHECK_TRAIT(is_nothrow_constructible<Json>);
CHECK_TRAIT(is_nothrow_default_constructible<Json>);
CHECK_TRAIT(is_copy_constructible<Json>);
CHECK_TRAIT(is_nothrow_move_constructible<Json>);
CHECK_TRAIT(is_copy_assignable<Json>);
CHECK_TRAIT(is_nothrow_move_assignable<Json>);
CHECK_TRAIT(is_nothrow_destructible<Json>);
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<int> l1 { 1, 2, 3 };
std::vector<int> l2 { 1, 2, 3 };
std::set<int> l3 { 1, 2, 3 };
assert(Json(l1) == Json(l2));
assert(Json(l2) == Json(l3));
std::map<string, string> m1 { { "k1", "v1" }, { "k2", "v2" } };
std::unordered_map<string, string> 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<Point> points = { { 1, 2 }, { 10, 20 }, { 100, 200 } };
std::string points_json = Json(points).dump();
printf("%s\n", points_json.c_str());
}

12
thirdparty/json11-ec4e452/.gitignore vendored Executable file
View File

@ -0,0 +1,12 @@
# generated files
test
libjson11.a
json11.pc
# Cmake
CMakeCache.txt
CTestTestfile.cmake
CMakeFiles
CMakeScripts
cmake_install.cmake
install_manifest.txt

57
thirdparty/json11-ec4e452/CMakeLists.txt vendored Executable file
View File

@ -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)

View File

15
thirdparty/json11-ec4e452/Makefile vendored Executable file
View File

@ -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

View File

View File

@ -37,11 +37,20 @@ using std::make_shared;
using std::initializer_list; using std::initializer_list;
using std::move; 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 * Serialization
*/ */
static void dump(std::nullptr_t, string &out) { static void dump(NullStruct, string &out) {
out += "null"; out += "null";
} }
@ -208,9 +217,9 @@ public:
explicit JsonObject(Json::object &&value) : Value(move(value)) {} explicit JsonObject(Json::object &&value) : Value(move(value)) {}
}; };
class JsonNull final : public Value<Json::NUL, std::nullptr_t> { class JsonNull final : public Value<Json::NUL, NullStruct> {
public: 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 { bool Json::operator== (const Json &other) const {
if (m_ptr == other.m_ptr)
return true;
if (m_ptr->type() != other.m_ptr->type()) if (m_ptr->type() != other.m_ptr->type())
return false; return false;
@ -298,6 +309,8 @@ bool Json::operator== (const Json &other) const {
} }
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()) if (m_ptr->type() != other.m_ptr->type())
return 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); return (x >= lower && x <= upper);
} }
namespace {
/* JsonParser /* JsonParser
* *
* Object that tracks all state of an in-progress parse. * Object that tracks all state of an in-progress parse.
*/ */
struct JsonParser { struct JsonParser final {
/* State /* State
*/ */
@ -374,38 +388,31 @@ struct JsonParser {
if (str[i] == '/') { if (str[i] == '/') {
i++; i++;
if (i == str.size()) 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 if (str[i] == '/') { // inline comment
i++; i++;
if (i == str.size()) // advance until next line, or end of input
return fail("unexpected end of input inside inline comment", 0); while (i < str.size() && str[i] != '\n') {
// advance until next line
while (str[i] != '\n') {
i++; i++;
if (i == str.size())
return fail("unexpected end of input inside inline comment", 0);
} }
comment_found = true; comment_found = true;
} }
else if (str[i] == '*') { // multiline comment else if (str[i] == '*') { // multiline comment
i++; i++;
if (i > str.size()-2) 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 // advance until closing tokens
while (!(str[i] == '*' && str[i+1] == '/')) { while (!(str[i] == '*' && str[i+1] == '/')) {
i++; i++;
if (i > str.size()-2) if (i > str.size()-2)
return fail( return fail(
"unexpected end of input inside multi-line comment", 0); "unexpected end of input inside multi-line comment", false);
} }
i += 2; i += 2;
if (i == str.size())
return fail(
"unexpected end of input inside multi-line comment", 0);
comment_found = true; comment_found = true;
} }
else else
return fail("malformed comment", 0); return fail("malformed comment", false);
} }
return comment_found; return comment_found;
} }
@ -420,6 +427,7 @@ struct JsonParser {
bool comment_found = false; bool comment_found = false;
do { do {
comment_found = consume_comment(); comment_found = consume_comment();
if (failed) return;
consume_whitespace(); consume_whitespace();
} }
while(comment_found); while(comment_found);
@ -433,8 +441,9 @@ struct JsonParser {
*/ */
char get_next_token() { char get_next_token() {
consume_garbage(); consume_garbage();
if (failed) return (char)0;
if (i == str.size()) if (i == str.size())
return fail("unexpected end of input", 0); return fail("unexpected end of input", (char)0);
return str[i++]; return str[i++];
} }
@ -508,7 +517,7 @@ struct JsonParser {
if (esc.length() < 4) { if (esc.length() < 4) {
return fail("bad \\u escape: " + esc, ""); 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') if (!in_range(esc[j], 'a', 'f') && !in_range(esc[j], 'A', 'F')
&& !in_range(esc[j], '0', '9')) && !in_range(esc[j], '0', '9'))
return fail("bad \\u escape: " + esc, ""); return fail("bad \\u escape: " + esc, "");
@ -718,6 +727,7 @@ struct JsonParser {
return fail("expected value, got " + esc(ch)); return fail("expected value, got " + esc(ch));
} }
}; };
}//namespace {
Json Json::parse(const string &in, string &err, JsonParse strategy) { Json Json::parse(const string &in, string &err, JsonParse strategy) {
JsonParser parser { in, 0, err, false, 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 // Check for any trailing garbage
parser.consume_garbage(); parser.consume_garbage();
if (parser.failed)
return Json();
if (parser.i != in.size()) if (parser.i != in.size())
return parser.fail("unexpected trailing " + esc(in[parser.i])); 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 // Documented in json11.hpp
vector<Json> Json::parse_multi(const string &in, vector<Json> Json::parse_multi(const string &in,
std::string::size_type &parser_stop_pos,
string &err, string &err,
JsonParse strategy) { JsonParse strategy) {
JsonParser parser { in, 0, err, false, strategy }; JsonParser parser { in, 0, err, false, strategy };
parser_stop_pos = 0;
vector<Json> json_vec; vector<Json> json_vec;
while (parser.i != in.size() && !parser.failed) { while (parser.i != in.size() && !parser.failed) {
json_vec.push_back(parser.parse_json(0)); json_vec.push_back(parser.parse_json(0));
if (parser.failed)
break;
// Check for another object // Check for another object
parser.consume_garbage(); parser.consume_garbage();
if (parser.failed)
break;
parser_stop_pos = parser.i;
} }
return json_vec; return json_vec;
} }

View File

@ -56,6 +56,18 @@
#include <memory> #include <memory>
#include <initializer_list> #include <initializer_list>
#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 { namespace json11 {
enum JsonParse { enum JsonParse {
@ -95,14 +107,14 @@ public:
// Implicit constructor: map-like objects (std::map, std::unordered_map, etc) // Implicit constructor: map-like objects (std::map, std::unordered_map, etc)
template <class M, typename std::enable_if< template <class M, typename std::enable_if<
std::is_constructible<std::string, typename M::key_type>::value std::is_constructible<std::string, decltype(std::declval<M>().begin()->first)>::value
&& std::is_constructible<Json, typename M::mapped_type>::value, && std::is_constructible<Json, decltype(std::declval<M>().begin()->second)>::value,
int>::type = 0> int>::type = 0>
Json(const M & m) : Json(object(m.begin(), m.end())) {} Json(const M & m) : Json(object(m.begin(), m.end())) {}
// Implicit constructor: vector-like objects (std::list, std::vector, std::set, etc) // Implicit constructor: vector-like objects (std::list, std::vector, std::set, etc)
template <class V, typename std::enable_if< template <class V, typename std::enable_if<
std::is_constructible<Json, typename V::value_type>::value, std::is_constructible<Json, decltype(*std::declval<V>().begin())>::value,
int>::type = 0> int>::type = 0>
Json(const V & v) : Json(array(v.begin(), v.end())) {} Json(const V & v) : Json(array(v.begin(), v.end())) {}
@ -165,9 +177,18 @@ public:
// Parse multiple objects, concatenated or separated by whitespace // Parse multiple objects, concatenated or separated by whitespace
static std::vector<Json> parse_multi( static std::vector<Json> parse_multi(
const std::string & in, const std::string & in,
std::string::size_type & parser_stop_pos,
std::string & err, std::string & err,
JsonParse strategy = JsonParse::STANDARD); JsonParse strategy = JsonParse::STANDARD);
static inline std::vector<Json> 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; bool operator< (const Json &rhs) const;
bool operator!= (const Json &rhs) const { return !(*this == rhs); } bool operator!= (const Json &rhs) const { return !(*this == rhs); }

9
thirdparty/json11-ec4e452/json11.pc.in vendored Executable file
View File

@ -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}

281
thirdparty/json11-ec4e452/test.cpp vendored Executable file
View File

@ -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 <cassert>
#include <string>
#include <cstdio>
#include <cstring>
#include <iostream>
#include <sstream>
#include "json11.hpp"
#include <list>
#include <set>
#include <unordered_map>
#include <algorithm>
#include <type_traits>
// 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<Json>);
CHECK_TRAIT(is_nothrow_default_constructible<Json>);
CHECK_TRAIT(is_copy_constructible<Json>);
CHECK_TRAIT(is_nothrow_move_constructible<Json>);
CHECK_TRAIT(is_copy_assignable<Json>);
CHECK_TRAIT(is_nothrow_move_assignable<Json>);
CHECK_TRAIT(is_nothrow_destructible<Json>);
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<int> l1 { 1, 2, 3 };
std::vector<int> l2 { 1, 2, 3 };
std::set<int> l3 { 1, 2, 3 };
JSON11_TEST_ASSERT(Json(l1) == Json(l2));
JSON11_TEST_ASSERT(Json(l2) == Json(l3));
std::map<string, string> m1 { { "k1", "v1" }, { "k2", "v2" } };
std::unordered_map<string, string> 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<string, string>{ { "k1", "v1" } })},
{bad_json1, good_json.size() + 1, 1, Json(std::map<string, string>{ { "k1", "v1" } })},
{bad_json2, good_json.size(), 1, Json(std::map<string, string>{ { "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<Point> 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