/*! @file @copyright The code is licensed under the MIT License , Copyright (c) 2013-2015 Niels Lohmann. @author Niels Lohmann @see https://github.com/nlohmann/json */ #define CATCH_CONFIG_MAIN #include "catch.hpp" #include "json.hpp" using nlohmann::json; #include #include #include #include #include #include #include #include #include #include TEST_CASE("constructors") { SECTION("create an empty value with a given type") { SECTION("null") { auto t = json::value_t::null; json j(t); CHECK(j.type() == t); } SECTION("object") { auto t = json::value_t::object; json j(t); CHECK(j.type() == t); } SECTION("array") { auto t = json::value_t::array; json j(t); CHECK(j.type() == t); } SECTION("boolean") { auto t = json::value_t::boolean; json j(t); CHECK(j.type() == t); } SECTION("string") { auto t = json::value_t::string; json j(t); CHECK(j.type() == t); } SECTION("number_integer") { auto t = json::value_t::number_integer; json j(t); CHECK(j.type() == t); } SECTION("number_float") { auto t = json::value_t::number_float; json j(t); CHECK(j.type() == t); } } SECTION("create a null object (implicitly)") { SECTION("no parameter") { json j{}; CHECK(j.type() == json::value_t::null); } } SECTION("create a null object (explicitly)") { SECTION("parameter") { json j(nullptr); CHECK(j.type() == json::value_t::null); } } SECTION("create an object (explicit)") { SECTION("empty object") { json::object_t o; json j(o); CHECK(j.type() == json::value_t::object); } SECTION("filled object") { json::object_t o {{"a", json(1)}, {"b", json(2.2)}, {"c", json(false)}, {"d", json("string")}, {"e", json()}}; json j(o); CHECK(j.type() == json::value_t::object); } } SECTION("create an object (implicit)") { // reference object json::object_t o_reference {{"a", json(1)}, {"b", json(2.2)}, {"c", json(false)}, {"d", json("string")}, {"e", json()}}; json j_reference(o_reference); SECTION("std::map") { std::map o {{"a", json(1)}, {"b", json(2.2)}, {"c", json(false)}, {"d", json("string")}, {"e", json()}}; json j(o); CHECK(j.type() == json::value_t::object); CHECK(j == j_reference); } SECTION("std::map") { std::map o {{"a", json(1)}, {"b", json(2.2)}, {"c", json(false)}, {"d", json("string")}, {"e", json()}}; json j(o); CHECK(j.type() == json::value_t::object); CHECK(j == j_reference); } SECTION("std::multimap") { std::multimap o {{"a", json(1)}, {"b", json(2.2)}, {"c", json(false)}, {"d", json("string")}, {"e", json()}}; json j(o); CHECK(j.type() == json::value_t::object); CHECK(j == j_reference); } SECTION("std::unordered_map") { std::unordered_map o {{"a", json(1)}, {"b", json(2.2)}, {"c", json(false)}, {"d", json("string")}, {"e", json()}}; json j(o); CHECK(j.type() == json::value_t::object); CHECK(j == j_reference); } SECTION("std::unordered_multimap") { std::unordered_multimap o {{"a", json(1)}, {"b", json(2.2)}, {"c", json(false)}, {"d", json("string")}, {"e", json()}}; json j(o); CHECK(j.type() == json::value_t::object); CHECK(j == j_reference); } SECTION("associative container literal") { json j({{"a", json(1)}, {"b", json(2.2)}, {"c", json(false)}, {"d", json("string")}, {"e", json()}}); CHECK(j.type() == json::value_t::object); CHECK(j == j_reference); } } SECTION("create an array (explicit)") { SECTION("empty array") { json::array_t a; json j(a); CHECK(j.type() == json::value_t::array); } SECTION("filled array") { json::array_t a {json(1), json(2.2), json(false), json("string"), json()}; json j(a); CHECK(j.type() == json::value_t::array); } } SECTION("create an array (implicit)") { // reference array json::array_t a_reference {json(1), json(2.2), json(false), json("string"), json()}; json j_reference(a_reference); SECTION("std::list") { std::list a {json(1), json(2.2), json(false), json("string"), json()}; json j(a); CHECK(j.type() == json::value_t::array); CHECK(j == j_reference); } SECTION("std::forward_list") { std::forward_list a {json(1), json(2.2), json(false), json("string"), json()}; json j(a); CHECK(j.type() == json::value_t::array); CHECK(j == j_reference); } SECTION("std::array") { std::array a {{json(1), json(2.2), json(false), json("string"), json()}}; json j(a); CHECK(j.type() == json::value_t::array); CHECK(j == j_reference); } SECTION("std::vector") { std::vector a {json(1), json(2.2), json(false), json("string"), json()}; json j(a); CHECK(j.type() == json::value_t::array); CHECK(j == j_reference); } SECTION("std::deque") { std::deque a {json(1), json(2.2), json(false), json("string"), json()}; json j(a); CHECK(j.type() == json::value_t::array); CHECK(j == j_reference); } SECTION("std::set") { std::set a {json(1), json(2.2), json(false), json("string"), json()}; json j(a); CHECK(j.type() == json::value_t::array); // we cannot really check for equality here } SECTION("std::unordered_set") { std::unordered_set a {json(1), json(2.2), json(false), json("string"), json()}; json j(a); CHECK(j.type() == json::value_t::array); // we cannot really check for equality here } SECTION("sequence container literal") { json j({json(1), json(2.2), json(false), json("string"), json()}); CHECK(j.type() == json::value_t::array); CHECK(j == j_reference); } } SECTION("create a string (explicit)") { SECTION("empty string") { json::string_t s; json j(s); CHECK(j.type() == json::value_t::string); } SECTION("filled string") { json::string_t s {"Hello world"}; json j(s); CHECK(j.type() == json::value_t::string); } } SECTION("create a string (implicit)") { // reference string json::string_t s_reference {"Hello world"}; json j_reference(s_reference); SECTION("std::string") { std::string s {"Hello world"}; json j(s); CHECK(j.type() == json::value_t::string); CHECK(j == j_reference); } SECTION("char[]") { char s[] {"Hello world"}; json j(s); CHECK(j.type() == json::value_t::string); CHECK(j == j_reference); } SECTION("const char*") { const char* s {"Hello world"}; json j(s); CHECK(j.type() == json::value_t::string); CHECK(j == j_reference); } SECTION("string literal") { json j("Hello world"); CHECK(j.type() == json::value_t::string); CHECK(j == j_reference); } } SECTION("create a boolean (explicit)") { SECTION("empty boolean") { json::boolean_t b{}; json j(b); CHECK(j.type() == json::value_t::boolean); } SECTION("filled boolean (true)") { json j(true); CHECK(j.type() == json::value_t::boolean); } SECTION("filled boolean (false)") { json j(false); CHECK(j.type() == json::value_t::boolean); } } SECTION("create an integer number (explicit)") { SECTION("uninitialized value") { json::number_integer_t n{}; json j(n); CHECK(j.type() == json::value_t::number_integer); } SECTION("initialized value") { json::number_integer_t n(42); json j(n); CHECK(j.type() == json::value_t::number_integer); } } SECTION("create an integer number (implicit)") { // reference object json::number_integer_t n_reference = 42; json j_reference(n_reference); SECTION("short") { short n = 42; json j(n); CHECK(j.type() == json::value_t::number_integer); CHECK(j == j_reference); } SECTION("unsigned short") { unsigned short n = 42; json j(n); CHECK(j.type() == json::value_t::number_integer); CHECK(j == j_reference); } SECTION("int") { int n = 42; json j(n); CHECK(j.type() == json::value_t::number_integer); CHECK(j == j_reference); } SECTION("unsigned int") { unsigned int n = 42; json j(n); CHECK(j.type() == json::value_t::number_integer); CHECK(j == j_reference); } SECTION("long") { long n = 42; json j(n); CHECK(j.type() == json::value_t::number_integer); CHECK(j == j_reference); } SECTION("unsigned long") { short n = 42; json j(n); CHECK(j.type() == json::value_t::number_integer); CHECK(j == j_reference); } SECTION("long long") { long long n = 42; json j(n); CHECK(j.type() == json::value_t::number_integer); CHECK(j == j_reference); } SECTION("unsigned long long") { unsigned long long n = 42; json j(n); CHECK(j.type() == json::value_t::number_integer); CHECK(j == j_reference); } SECTION("int8_t") { int8_t n = 42; json j(n); CHECK(j.type() == json::value_t::number_integer); CHECK(j == j_reference); } SECTION("int16_t") { int16_t n = 42; json j(n); CHECK(j.type() == json::value_t::number_integer); CHECK(j == j_reference); } SECTION("int32_t") { int32_t n = 42; json j(n); CHECK(j.type() == json::value_t::number_integer); CHECK(j == j_reference); } SECTION("int64_t") { int64_t n = 42; json j(n); CHECK(j.type() == json::value_t::number_integer); CHECK(j == j_reference); } SECTION("int_fast8_t") { int_fast8_t n = 42; json j(n); CHECK(j.type() == json::value_t::number_integer); CHECK(j == j_reference); } SECTION("int_fast16_t") { int_fast16_t n = 42; json j(n); CHECK(j.type() == json::value_t::number_integer); CHECK(j == j_reference); } SECTION("int_fast32_t") { int_fast32_t n = 42; json j(n); CHECK(j.type() == json::value_t::number_integer); CHECK(j == j_reference); } SECTION("int_fast64_t") { int_fast64_t n = 42; json j(n); CHECK(j.type() == json::value_t::number_integer); CHECK(j == j_reference); } SECTION("int_least8_t") { int_least8_t n = 42; json j(n); CHECK(j.type() == json::value_t::number_integer); CHECK(j == j_reference); } SECTION("int_least16_t") { int_least16_t n = 42; json j(n); CHECK(j.type() == json::value_t::number_integer); CHECK(j == j_reference); } SECTION("int_least32_t") { int_least32_t n = 42; json j(n); CHECK(j.type() == json::value_t::number_integer); CHECK(j == j_reference); } SECTION("int_least64_t") { int_least64_t n = 42; json j(n); CHECK(j.type() == json::value_t::number_integer); CHECK(j == j_reference); } SECTION("uint8_t") { uint8_t n = 42; json j(n); CHECK(j.type() == json::value_t::number_integer); CHECK(j == j_reference); } SECTION("uint16_t") { uint16_t n = 42; json j(n); CHECK(j.type() == json::value_t::number_integer); CHECK(j == j_reference); } SECTION("uint32_t") { uint32_t n = 42; json j(n); CHECK(j.type() == json::value_t::number_integer); CHECK(j == j_reference); } SECTION("uint64_t") { uint64_t n = 42; json j(n); CHECK(j.type() == json::value_t::number_integer); CHECK(j == j_reference); } SECTION("uint_fast8_t") { uint_fast8_t n = 42; json j(n); CHECK(j.type() == json::value_t::number_integer); CHECK(j == j_reference); } SECTION("uint_fast16_t") { uint_fast16_t n = 42; json j(n); CHECK(j.type() == json::value_t::number_integer); CHECK(j == j_reference); } SECTION("uint_fast32_t") { uint_fast32_t n = 42; json j(n); CHECK(j.type() == json::value_t::number_integer); CHECK(j == j_reference); } SECTION("uint_fast64_t") { uint_fast64_t n = 42; json j(n); CHECK(j.type() == json::value_t::number_integer); CHECK(j == j_reference); } SECTION("uint_least8_t") { uint_least8_t n = 42; json j(n); CHECK(j.type() == json::value_t::number_integer); CHECK(j == j_reference); } SECTION("uint_least16_t") { uint_least16_t n = 42; json j(n); CHECK(j.type() == json::value_t::number_integer); CHECK(j == j_reference); } SECTION("uint_least32_t") { uint_least32_t n = 42; json j(n); CHECK(j.type() == json::value_t::number_integer); CHECK(j == j_reference); } SECTION("uint_least64_t") { uint_least64_t n = 42; json j(n); CHECK(j.type() == json::value_t::number_integer); CHECK(j == j_reference); } SECTION("integer literal without suffix") { json j(42); CHECK(j.type() == json::value_t::number_integer); CHECK(j == j_reference); } SECTION("integer literal with u suffix") { json j(42u); CHECK(j.type() == json::value_t::number_integer); CHECK(j == j_reference); } SECTION("integer literal with l suffix") { json j(42l); CHECK(j.type() == json::value_t::number_integer); CHECK(j == j_reference); } SECTION("integer literal with ul suffix") { json j(42ul); CHECK(j.type() == json::value_t::number_integer); CHECK(j == j_reference); } SECTION("integer literal with ll suffix") { json j(42ll); CHECK(j.type() == json::value_t::number_integer); CHECK(j == j_reference); } SECTION("integer literal with ull suffix") { json j(42ull); CHECK(j.type() == json::value_t::number_integer); CHECK(j == j_reference); } } SECTION("create a floating-point number (explicit)") { SECTION("uninitialized value") { json::number_float_t n{}; json j(n); CHECK(j.type() == json::value_t::number_float); } SECTION("initialized value") { json::number_float_t n(42.23); json j(n); CHECK(j.type() == json::value_t::number_float); } } SECTION("create a floating-point number (implicit)") { // reference object json::number_float_t n_reference = 42.23; json j_reference(n_reference); SECTION("float") { float n = 42.23; json j(n); CHECK(j.type() == json::value_t::number_float); CHECK(j.m_value.number_float == Approx(j_reference.m_value.number_float)); } SECTION("double") { double n = 42.23; json j(n); CHECK(j.type() == json::value_t::number_float); CHECK(j.m_value.number_float == Approx(j_reference.m_value.number_float)); } SECTION("long double") { long double n = 42.23; json j(n); CHECK(j.type() == json::value_t::number_float); CHECK(j.m_value.number_float == Approx(j_reference.m_value.number_float)); } SECTION("floating-point literal without suffix") { json j(42.23); CHECK(j.type() == json::value_t::number_float); CHECK(j.m_value.number_float == Approx(j_reference.m_value.number_float)); } SECTION("integer literal with f suffix") { json j(42.23f); CHECK(j.type() == json::value_t::number_float); CHECK(j.m_value.number_float == Approx(j_reference.m_value.number_float)); } SECTION("integer literal with l suffix") { json j(42.23l); CHECK(j.type() == json::value_t::number_float); CHECK(j.m_value.number_float == Approx(j_reference.m_value.number_float)); } } SECTION("create a container (array or object) from an initializer list") { SECTION("empty initializer list") { SECTION("explicit") { std::initializer_list l; json j(l); CHECK(j.type() == json::value_t::object); } SECTION("implicit") { json j {}; CHECK(j.type() == json::value_t::null); } } SECTION("one element") { SECTION("array") { SECTION("explicit") { std::initializer_list l = {json(json::array_t())}; json j(l); CHECK(j.type() == json::value_t::array); } SECTION("implicit") { json j {json::array_t()}; CHECK(j.type() == json::value_t::array); } } SECTION("object") { SECTION("explicit") { std::initializer_list l = {json(json::object_t())}; json j(l); CHECK(j.type() == json::value_t::array); } SECTION("implicit") { json j {json::object_t()}; CHECK(j.type() == json::value_t::array); } } SECTION("string") { SECTION("explicit") { std::initializer_list l = {json("Hello world")}; json j(l); CHECK(j.type() == json::value_t::array); } SECTION("implicit") { json j {"Hello world"}; CHECK(j.type() == json::value_t::array); } } SECTION("boolean") { SECTION("explicit") { std::initializer_list l = {json(true)}; json j(l); CHECK(j.type() == json::value_t::array); } SECTION("implicit") { json j {true}; CHECK(j.type() == json::value_t::array); } } SECTION("number (integer)") { SECTION("explicit") { std::initializer_list l = {json(1)}; json j(l); CHECK(j.type() == json::value_t::array); } SECTION("implicit") { json j {1}; CHECK(j.type() == json::value_t::array); } } SECTION("number (floating-point)") { SECTION("explicit") { std::initializer_list l = {json(42.23)}; json j(l); CHECK(j.type() == json::value_t::array); } SECTION("implicit") { json j {42.23}; CHECK(j.type() == json::value_t::array); } } } SECTION("more elements") { SECTION("explicit") { std::initializer_list l = {1, 42.23, true, nullptr, json::object_t(), json::array_t()}; json j(l); CHECK(j.type() == json::value_t::array); } SECTION("implicit") { json j {1, 42.23, true, nullptr, json::object_t(), json::array_t()}; CHECK(j.type() == json::value_t::array); } } SECTION("implicit type deduction") { SECTION("object") { json j { {"one", 1}, {"two", 2.2}, {"three", false} }; CHECK(j.type() == json::value_t::object); } SECTION("array") { json j { {"one", 1}, {"two", 2.2}, {"three", false}, 13 }; CHECK(j.type() == json::value_t::array); } } SECTION("explicit type deduction") { SECTION("empty object") { json j = json::object(); CHECK(j.type() == json::value_t::object); } SECTION("object") { json j = json::object({ {"one", 1}, {"two", 2.2}, {"three", false} }); CHECK(j.type() == json::value_t::object); } SECTION("object with error") { CHECK_THROWS_AS(json::object({ {"one", 1}, {"two", 2.2}, {"three", false}, 13 }), std::logic_error); } SECTION("empty array") { json j = json::array(); CHECK(j.type() == json::value_t::array); } SECTION("array") { json j = json::array({ {"one", 1}, {"two", 2.2}, {"three", false} }); CHECK(j.type() == json::value_t::array); } } } } TEST_CASE("other constructors and destructor") { SECTION("copy constructor") { SECTION("object") { json j {{"foo", 1}, {"bar", false}}; json k(j); CHECK(j == k); } SECTION("array") { json j {"foo", 1, 42.23, false}; json k(j); CHECK(j == k); } SECTION("null") { json j(nullptr); json k(j); CHECK(j == k); } SECTION("boolean") { json j(true); json k(j); CHECK(j == k); } SECTION("string") { json j("Hello world"); json k(j); CHECK(j == k); } SECTION("number (integer)") { json j(42); json k(j); CHECK(j == k); } SECTION("number (floating-point)") { json j(42.23); json k(j); CHECK(j == k); } } SECTION("move constructor") { json j {{"foo", "bar"}, {"baz", {1, 2, 3, 4}}, {"a", 42.23}, {"b", nullptr}}; CHECK(j.type() == json::value_t::object); json k(std::move(j)); CHECK(k.type() == json::value_t::object); CHECK(j.type() == json::value_t::null); } SECTION("copy assignment") { SECTION("object") { json j {{"foo", 1}, {"bar", false}}; json k; k = j; CHECK(j == k); } SECTION("array") { json j {"foo", 1, 42.23, false}; json k; k = j; CHECK(j == k); } SECTION("null") { json j(nullptr); json k; k = j; CHECK(j == k); } SECTION("boolean") { json j(true); json k; k = j; CHECK(j == k); } SECTION("string") { json j("Hello world"); json k; k = j; CHECK(j == k); } SECTION("number (integer)") { json j(42); json k; k = j; CHECK(j == k); } SECTION("number (floating-point)") { json j(42.23); json k; k = j; CHECK(j == k); } } SECTION("destructor") { SECTION("object") { auto j = new json {{"foo", 1}, {"bar", false}}; delete j; } SECTION("array") { auto j = new json {"foo", 1, false, 23.42}; delete j; } SECTION("string") { auto j = new json("Hello world"); delete j; } } } TEST_CASE("object inspection") { SECTION("serialization") { json j {{"object", json::object()}, {"array", {1, 2, 3, 4}}, {"number", 42}, {"boolean", false}, {"null", nullptr}, {"string", "Hello world"} }; SECTION("no indent / indent=-1") { CHECK(j.dump() == "{\"array\":[1,2,3,4],\"boolean\":false,\"null\":null,\"number\":42,\"object\":{},\"string\":\"Hello world\"}"); CHECK(j.dump() == j.dump(-1)); } SECTION("indent=0") { CHECK(j.dump(0) == "{\n\"array\": [\n1,\n2,\n3,\n4\n],\n\"boolean\": false,\n\"null\": null,\n\"number\": 42,\n\"object\": {},\n\"string\": \"Hello world\"\n}"); } SECTION("indent=4") { CHECK(j.dump(4) == "{\n \"array\": [\n 1,\n 2,\n 3,\n 4\n ],\n \"boolean\": false,\n \"null\": null,\n \"number\": 42,\n \"object\": {},\n \"string\": \"Hello world\"\n}"); } SECTION("dump and floating-point numbers") { auto s = json(42.23).dump(); CHECK(s.find("42.23") != std::string::npos); } SECTION("dump and non-ASCII characters") { CHECK(json("ä").dump() == "\"ä\""); CHECK(json("Ö").dump() == "\"Ö\""); CHECK(json("❤️").dump() == "\"❤️\""); } } SECTION("return the type of the object (explicit)") { SECTION("null") { json j = nullptr; CHECK(j.type() == json::value_t::null); } SECTION("object") { json j = {{"foo", "bar"}}; CHECK(j.type() == json::value_t::object); } SECTION("array") { json j = {1, 2, 3, 4}; CHECK(j.type() == json::value_t::array); } SECTION("boolean") { json j = true; CHECK(j.type() == json::value_t::boolean); } SECTION("string") { json j = "Hello world"; CHECK(j.type() == json::value_t::string); } SECTION("number (integer)") { json j = 23; CHECK(j.type() == json::value_t::number_integer); } SECTION("number (floating-point)") { json j = 42.23; CHECK(j.type() == json::value_t::number_float); } } SECTION("return the type of the object (implicit)") { SECTION("null") { json j = nullptr; json::value_t t = j; CHECK(t == j.type()); } SECTION("object") { json j = {{"foo", "bar"}}; json::value_t t = j; CHECK(t == j.type()); } SECTION("array") { json j = {1, 2, 3, 4}; json::value_t t = j; CHECK(t == j.type()); } SECTION("boolean") { json j = true; json::value_t t = j; CHECK(t == j.type()); } SECTION("string") { json j = "Hello world"; json::value_t t = j; CHECK(t == j.type()); } SECTION("number (integer)") { json j = 23; json::value_t t = j; CHECK(t == j.type()); } SECTION("number (floating-point)") { json j = 42.23; json::value_t t = j; CHECK(t == j.type()); } } } TEST_CASE("value conversion") { SECTION("get an object (explicit)") { json::object_t o_reference = {{"object", json::object()}, {"array", {1, 2, 3, 4}}, {"number", 42}, {"boolean", false}, {"null", nullptr}, {"string", "Hello world"} }; json j(o_reference); SECTION("json::object_t") { json::object_t o = j.get(); CHECK(json(o) == j); } SECTION("std::map") { std::map o = j.get>(); CHECK(json(o) == j); } SECTION("std::multimap") { std::multimap o = j.get>(); CHECK(json(o) == j); } SECTION("std::unordered_map") { std::unordered_map o = j.get>(); CHECK(json(o) == j); } SECTION("std::unordered_multimap") { std::unordered_multimap o = j.get>(); CHECK(json(o) == j); } SECTION("exception in case of a non-object type") { CHECK_THROWS_AS(json(json::value_t::null).get(), std::logic_error); CHECK_THROWS_AS(json(json::value_t::array).get(), std::logic_error); CHECK_THROWS_AS(json(json::value_t::string).get(), std::logic_error); CHECK_THROWS_AS(json(json::value_t::boolean).get(), std::logic_error); CHECK_THROWS_AS(json(json::value_t::number_integer).get(), std::logic_error); CHECK_THROWS_AS(json(json::value_t::number_float).get(), std::logic_error); } } SECTION("get an object (implicit)") { json::object_t o_reference = {{"object", json::object()}, {"array", {1, 2, 3, 4}}, {"number", 42}, {"boolean", false}, {"null", nullptr}, {"string", "Hello world"} }; json j(o_reference); SECTION("json::object_t") { json::object_t o = j; CHECK(json(o) == j); } SECTION("std::map") { std::map o = j; CHECK(json(o) == j); } SECTION("std::multimap") { std::multimap o = j; CHECK(json(o) == j); } SECTION("std::unordered_map") { std::unordered_map o = j; CHECK(json(o) == j); } SECTION("std::unordered_multimap") { std::unordered_multimap o = j; CHECK(json(o) == j); } } SECTION("get an array (explicit)") { json::array_t a_reference {json(1), json(2.2), json(false), json("string"), json()}; json j(a_reference); SECTION("json::array_t") { json::array_t a = j.get(); CHECK(json(a) == j); } SECTION("std::list") { std::list a = j.get>(); CHECK(json(a) == j); } SECTION("std::forward_list") { std::forward_list a = j.get>(); CHECK(json(a) == j); } SECTION("std::vector") { std::vector a = j.get>(); CHECK(json(a) == j); } SECTION("std::deque") { std::deque a = j.get>(); CHECK(json(a) == j); } SECTION("exception in case of a non-array type") { CHECK_THROWS_AS(json(json::value_t::null).get(), std::logic_error); CHECK_THROWS_AS(json(json::value_t::object).get(), std::logic_error); CHECK_THROWS_AS(json(json::value_t::string).get(), std::logic_error); CHECK_THROWS_AS(json(json::value_t::boolean).get(), std::logic_error); CHECK_THROWS_AS(json(json::value_t::number_integer).get(), std::logic_error); CHECK_THROWS_AS(json(json::value_t::number_float).get(), std::logic_error); } } SECTION("get an array (implicit)") { json::array_t a_reference {json(1), json(2.2), json(false), json("string"), json()}; json j(a_reference); SECTION("json::array_t") { json::array_t a = j; CHECK(json(a) == j); } SECTION("std::list") { std::list a = j; CHECK(json(a) == j); } SECTION("std::forward_list") { std::forward_list a = j; CHECK(json(a) == j); } SECTION("std::vector") { std::vector a = j; CHECK(json(a) == j); } SECTION("std::deque") { std::deque a = j; CHECK(json(a) == j); } } SECTION("get a string (explicit)") { json::string_t s_reference {"Hello world"}; json j(s_reference); SECTION("string_t") { json::string_t s = j.get(); CHECK(json(s) == j); } SECTION("std::string") { std::string s = j.get(); CHECK(json(s) == j); } SECTION("exception in case of a non-string type") { CHECK_THROWS_AS(json(json::value_t::null).get(), std::logic_error); CHECK_THROWS_AS(json(json::value_t::object).get(), std::logic_error); CHECK_THROWS_AS(json(json::value_t::array).get(), std::logic_error); CHECK_THROWS_AS(json(json::value_t::boolean).get(), std::logic_error); CHECK_THROWS_AS(json(json::value_t::number_integer).get(), std::logic_error); CHECK_THROWS_AS(json(json::value_t::number_float).get(), std::logic_error); } } SECTION("get a string (implicit)") { json::string_t s_reference {"Hello world"}; json j(s_reference); SECTION("string_t") { json::string_t s = j; CHECK(json(s) == j); } SECTION("std::string") { std::string s = j; CHECK(json(s) == j); } } SECTION("get a boolean (explicit)") { json::boolean_t b_reference {true}; json j(b_reference); SECTION("boolean_t") { json::boolean_t b = j.get(); CHECK(json(b) == j); } SECTION("bool") { bool b = j.get(); CHECK(json(b) == j); } SECTION("exception in case of a non-string type") { CHECK_THROWS_AS(json(json::value_t::null).get(), std::logic_error); CHECK_THROWS_AS(json(json::value_t::object).get(), std::logic_error); CHECK_THROWS_AS(json(json::value_t::array).get(), std::logic_error); CHECK_THROWS_AS(json(json::value_t::string).get(), std::logic_error); CHECK_THROWS_AS(json(json::value_t::number_integer).get(), std::logic_error); CHECK_THROWS_AS(json(json::value_t::number_float).get(), std::logic_error); } } SECTION("get a boolean (implicit)") { json::boolean_t b_reference {true}; json j(b_reference); SECTION("boolean_t") { json::boolean_t b = j; CHECK(json(b) == j); } SECTION("bool") { bool b = j; CHECK(json(b) == j); } } SECTION("get an integer number (explicit)") { json::number_integer_t n_reference {42}; json j(n_reference); SECTION("number_integer_t") { json::number_integer_t n = j.get(); CHECK(json(n) == j); } SECTION("short") { short n = j.get(); CHECK(json(n) == j); } SECTION("unsigned short") { unsigned short n = j.get(); CHECK(json(n) == j); } SECTION("int") { int n = j.get(); CHECK(json(n) == j); } SECTION("unsigned int") { unsigned int n = j.get(); CHECK(json(n) == j); } SECTION("long") { long n = j.get(); CHECK(json(n) == j); } SECTION("unsigned long") { unsigned long n = j.get(); CHECK(json(n) == j); } SECTION("long long") { long long n = j.get(); CHECK(json(n) == j); } SECTION("unsigned long long") { unsigned long long n = j.get(); CHECK(json(n) == j); } SECTION("int8_t") { int8_t n = j.get(); CHECK(json(n) == j); } SECTION("int16_t") { int16_t n = j.get(); CHECK(json(n) == j); } SECTION("int32_t") { int32_t n = j.get(); CHECK(json(n) == j); } SECTION("int64_t") { int64_t n = j.get(); CHECK(json(n) == j); } SECTION("int8_fast_t") { int_fast8_t n = j.get(); CHECK(json(n) == j); } SECTION("int16_fast_t") { int_fast16_t n = j.get(); CHECK(json(n) == j); } SECTION("int32_fast_t") { int_fast32_t n = j.get(); CHECK(json(n) == j); } SECTION("int64_fast_t") { int_fast64_t n = j.get(); CHECK(json(n) == j); } SECTION("int8_least_t") { int_least8_t n = j.get(); CHECK(json(n) == j); } SECTION("int16_least_t") { int_least16_t n = j.get(); CHECK(json(n) == j); } SECTION("int32_least_t") { int_least32_t n = j.get(); CHECK(json(n) == j); } SECTION("int64_least_t") { int_least64_t n = j.get(); CHECK(json(n) == j); } SECTION("uint8_t") { uint8_t n = j.get(); CHECK(json(n) == j); } SECTION("uint16_t") { uint16_t n = j.get(); CHECK(json(n) == j); } SECTION("uint32_t") { uint32_t n = j.get(); CHECK(json(n) == j); } SECTION("uint64_t") { uint64_t n = j.get(); CHECK(json(n) == j); } SECTION("uint8_fast_t") { uint_fast8_t n = j.get(); CHECK(json(n) == j); } SECTION("uint16_fast_t") { uint_fast16_t n = j.get(); CHECK(json(n) == j); } SECTION("uint32_fast_t") { uint_fast32_t n = j.get(); CHECK(json(n) == j); } SECTION("uint64_fast_t") { uint_fast64_t n = j.get(); CHECK(json(n) == j); } SECTION("uint8_least_t") { uint_least8_t n = j.get(); CHECK(json(n) == j); } SECTION("uint16_least_t") { uint_least16_t n = j.get(); CHECK(json(n) == j); } SECTION("uint32_least_t") { uint_least32_t n = j.get(); CHECK(json(n) == j); } SECTION("uint64_least_t") { uint_least64_t n = j.get(); CHECK(json(n) == j); } SECTION("exception in case of a non-number type") { CHECK_THROWS_AS(json(json::value_t::null).get(), std::logic_error); CHECK_THROWS_AS(json(json::value_t::object).get(), std::logic_error); CHECK_THROWS_AS(json(json::value_t::array).get(), std::logic_error); CHECK_THROWS_AS(json(json::value_t::string).get(), std::logic_error); CHECK_THROWS_AS(json(json::value_t::boolean).get(), std::logic_error); CHECK_NOTHROW(json(json::value_t::number_float).get()); } } SECTION("get an integer number (implicit)") { json::number_integer_t n_reference {42}; json j(n_reference); SECTION("number_integer_t") { json::number_integer_t n = j.get(); CHECK(json(n) == j); } SECTION("short") { short n = j; CHECK(json(n) == j); } SECTION("unsigned short") { unsigned short n = j; CHECK(json(n) == j); } SECTION("int") { int n = j; CHECK(json(n) == j); } SECTION("unsigned int") { unsigned int n = j; CHECK(json(n) == j); } SECTION("long") { long n = j; CHECK(json(n) == j); } SECTION("unsigned long") { unsigned long n = j; CHECK(json(n) == j); } SECTION("long long") { long long n = j; CHECK(json(n) == j); } SECTION("unsigned long long") { unsigned long long n = j; CHECK(json(n) == j); } SECTION("int8_t") { int8_t n = j; CHECK(json(n) == j); } SECTION("int16_t") { int16_t n = j; CHECK(json(n) == j); } SECTION("int32_t") { int32_t n = j; CHECK(json(n) == j); } SECTION("int64_t") { int64_t n = j; CHECK(json(n) == j); } SECTION("int8_fast_t") { int_fast8_t n = j; CHECK(json(n) == j); } SECTION("int16_fast_t") { int_fast16_t n = j; CHECK(json(n) == j); } SECTION("int32_fast_t") { int_fast32_t n = j; CHECK(json(n) == j); } SECTION("int64_fast_t") { int_fast64_t n = j; CHECK(json(n) == j); } SECTION("int8_least_t") { int_least8_t n = j; CHECK(json(n) == j); } SECTION("int16_least_t") { int_least16_t n = j; CHECK(json(n) == j); } SECTION("int32_least_t") { int_least32_t n = j; CHECK(json(n) == j); } SECTION("int64_least_t") { int_least64_t n = j; CHECK(json(n) == j); } SECTION("uint8_t") { uint8_t n = j; CHECK(json(n) == j); } SECTION("uint16_t") { uint16_t n = j; CHECK(json(n) == j); } SECTION("uint32_t") { uint32_t n = j; CHECK(json(n) == j); } SECTION("uint64_t") { uint64_t n = j; CHECK(json(n) == j); } SECTION("uint8_fast_t") { uint_fast8_t n = j; CHECK(json(n) == j); } SECTION("uint16_fast_t") { uint_fast16_t n = j; CHECK(json(n) == j); } SECTION("uint32_fast_t") { uint_fast32_t n = j; CHECK(json(n) == j); } SECTION("uint64_fast_t") { uint_fast64_t n = j; CHECK(json(n) == j); } SECTION("uint8_least_t") { uint_least8_t n = j; CHECK(json(n) == j); } SECTION("uint16_least_t") { uint_least16_t n = j; CHECK(json(n) == j); } SECTION("uint32_least_t") { uint_least32_t n = j; CHECK(json(n) == j); } SECTION("uint64_least_t") { uint_least64_t n = j; CHECK(json(n) == j); } } SECTION("get a floating-point number (explicit)") { json::number_float_t n_reference {42.23}; json j(n_reference); SECTION("number_float_t") { json::number_float_t n = j.get(); CHECK(json(n).m_value.number_float == Approx(j.m_value.number_float)); } SECTION("float") { float n = j.get(); CHECK(json(n).m_value.number_float == Approx(j.m_value.number_float)); } SECTION("double") { double n = j.get(); CHECK(json(n).m_value.number_float == Approx(j.m_value.number_float)); } SECTION("exception in case of a non-string type") { CHECK_THROWS_AS(json(json::value_t::null).get(), std::logic_error); CHECK_THROWS_AS(json(json::value_t::object).get(), std::logic_error); CHECK_THROWS_AS(json(json::value_t::array).get(), std::logic_error); CHECK_THROWS_AS(json(json::value_t::string).get(), std::logic_error); CHECK_THROWS_AS(json(json::value_t::boolean).get(), std::logic_error); CHECK_NOTHROW(json(json::value_t::number_integer).get()); } } SECTION("get a floating-point number (implicit)") { json::number_float_t n_reference {42.23}; json j(n_reference); SECTION("number_float_t") { json::number_float_t n = j; CHECK(json(n).m_value.number_float == Approx(j.m_value.number_float)); } SECTION("float") { float n = j; CHECK(json(n).m_value.number_float == Approx(j.m_value.number_float)); } SECTION("double") { double n = j; CHECK(json(n).m_value.number_float == Approx(j.m_value.number_float)); } } } TEST_CASE("element access") { SECTION("array") { json j = {1, true, nullptr, "string", 42.23, json::object(), {1, 2, 3}}; const json j_const = j; SECTION("access specified element with bounds checking") { SECTION("access within bounds") { CHECK(j.at(0) == json(1)); CHECK(j.at(1) == json(true)); CHECK(j.at(2) == json(nullptr)); CHECK(j.at(3) == json("string")); CHECK(j.at(4) == json(42.23)); CHECK(j.at(5) == json(json::object())); CHECK(j.at(6) == json({1, 2, 3})); CHECK(j_const.at(0) == json(1)); CHECK(j_const.at(1) == json(true)); CHECK(j_const.at(2) == json(nullptr)); CHECK(j_const.at(3) == json("string")); CHECK(j_const.at(4) == json(42.23)); CHECK(j_const.at(5) == json(json::object())); CHECK(j_const.at(6) == json({1, 2, 3})); } SECTION("access outside bounds") { CHECK_THROWS_AS(j.at(7), std::out_of_range); CHECK_THROWS_AS(j_const.at(7), std::out_of_range); } SECTION("access on non-array type") { SECTION("null") { json j_nonarray(json::value_t::null); const json j_nonarray_const(j_nonarray); CHECK_THROWS_AS(j_nonarray.at(0), std::runtime_error); CHECK_THROWS_AS(j_nonarray_const.at(0), std::runtime_error); } SECTION("boolean") { json j_nonarray(json::value_t::boolean); const json j_nonarray_const(j_nonarray); CHECK_THROWS_AS(j_nonarray.at(0), std::runtime_error); CHECK_THROWS_AS(j_nonarray_const.at(0), std::runtime_error); } SECTION("string") { json j_nonarray(json::value_t::string); const json j_nonarray_const(j_nonarray); CHECK_THROWS_AS(j_nonarray.at(0), std::runtime_error); CHECK_THROWS_AS(j_nonarray_const.at(0), std::runtime_error); } SECTION("object") { json j_nonarray(json::value_t::object); const json j_nonarray_const(j_nonarray); CHECK_THROWS_AS(j_nonarray.at(0), std::runtime_error); CHECK_THROWS_AS(j_nonarray_const.at(0), std::runtime_error); } SECTION("number (integer)") { json j_nonarray(json::value_t::number_integer); const json j_nonarray_const(j_nonarray); CHECK_THROWS_AS(j_nonarray.at(0), std::runtime_error); CHECK_THROWS_AS(j_nonarray_const.at(0), std::runtime_error); } SECTION("number (floating-point)") { json j_nonarray(json::value_t::number_float); const json j_nonarray_const(j_nonarray); CHECK_THROWS_AS(j_nonarray.at(0), std::runtime_error); CHECK_THROWS_AS(j_nonarray_const.at(0), std::runtime_error); } } } SECTION("access specified element") { SECTION("access within bounds") { CHECK(j[0] == json(1)); CHECK(j[1] == json(true)); CHECK(j[2] == json(nullptr)); CHECK(j[3] == json("string")); CHECK(j[4] == json(42.23)); CHECK(j[5] == json(json::object())); CHECK(j[6] == json({1, 2, 3})); CHECK(j_const[0] == json(1)); CHECK(j_const[1] == json(true)); CHECK(j_const[2] == json(nullptr)); CHECK(j_const[3] == json("string")); CHECK(j_const[4] == json(42.23)); CHECK(j_const[5] == json(json::object())); CHECK(j_const[6] == json({1, 2, 3})); } SECTION("access on non-array type") { SECTION("null") { json j_nonarray(json::value_t::null); const json j_nonarray_const(j_nonarray); CHECK_THROWS_AS(j_nonarray[0], std::runtime_error); CHECK_THROWS_AS(j_nonarray_const[0], std::runtime_error); } SECTION("boolean") { json j_nonarray(json::value_t::boolean); const json j_nonarray_const(j_nonarray); CHECK_THROWS_AS(j_nonarray[0], std::runtime_error); CHECK_THROWS_AS(j_nonarray_const[0], std::runtime_error); } SECTION("string") { json j_nonarray(json::value_t::string); const json j_nonarray_const(j_nonarray); CHECK_THROWS_AS(j_nonarray[0], std::runtime_error); CHECK_THROWS_AS(j_nonarray_const[0], std::runtime_error); } SECTION("object") { json j_nonarray(json::value_t::object); const json j_nonarray_const(j_nonarray); CHECK_THROWS_AS(j_nonarray[0], std::runtime_error); CHECK_THROWS_AS(j_nonarray_const[0], std::runtime_error); } SECTION("number (integer)") { json j_nonarray(json::value_t::number_integer); const json j_nonarray_const(j_nonarray); CHECK_THROWS_AS(j_nonarray[0], std::runtime_error); CHECK_THROWS_AS(j_nonarray_const[0], std::runtime_error); } SECTION("number (floating-point)") { json j_nonarray(json::value_t::number_float); const json j_nonarray_const(j_nonarray); CHECK_THROWS_AS(j_nonarray[0], std::runtime_error); CHECK_THROWS_AS(j_nonarray_const[0], std::runtime_error); } } } } SECTION("object") { json j = {{"integer", 1}, {"floating", 42.23}, {"null", nullptr}, {"string", "hello world"}, {"boolean", true}, {"object", json::object()}, {"array", {1, 2, 3}}}; const json j_const = j; SECTION("access specified element with bounds checking") { SECTION("access within bounds") { CHECK(j.at("integer") == json(1)); CHECK(j.at("boolean") == json(true)); CHECK(j.at("null") == json(nullptr)); CHECK(j.at("string") == json("hello world")); CHECK(j.at("floating") == json(42.23)); CHECK(j.at("object") == json(json::object())); CHECK(j.at("array") == json({1, 2, 3})); CHECK(j_const.at("integer") == json(1)); CHECK(j_const.at("boolean") == json(true)); CHECK(j_const.at("null") == json(nullptr)); CHECK(j_const.at("string") == json("hello world")); CHECK(j_const.at("floating") == json(42.23)); CHECK(j_const.at("object") == json(json::object())); CHECK(j_const.at("array") == json({1, 2, 3})); } SECTION("access outside bounds") { CHECK_THROWS_AS(j.at("foo"), std::out_of_range); CHECK_THROWS_AS(j_const.at("foo"), std::out_of_range); } SECTION("access on non-object type") { SECTION("null") { json j_nonobject(json::value_t::null); const json j_nonobject_const(j_nonobject); CHECK_THROWS_AS(j_nonobject.at("foo"), std::runtime_error); CHECK_THROWS_AS(j_nonobject_const.at("foo"), std::runtime_error); } SECTION("boolean") { json j_nonobject(json::value_t::boolean); const json j_nonobject_const(j_nonobject); CHECK_THROWS_AS(j_nonobject.at("foo"), std::runtime_error); CHECK_THROWS_AS(j_nonobject_const.at("foo"), std::runtime_error); } SECTION("string") { json j_nonobject(json::value_t::string); const json j_nonobject_const(j_nonobject); CHECK_THROWS_AS(j_nonobject.at("foo"), std::runtime_error); CHECK_THROWS_AS(j_nonobject_const.at("foo"), std::runtime_error); } SECTION("array") { json j_nonobject(json::value_t::array); const json j_nonobject_const(j_nonobject); CHECK_THROWS_AS(j_nonobject.at("foo"), std::runtime_error); CHECK_THROWS_AS(j_nonobject_const.at("foo"), std::runtime_error); } SECTION("number (integer)") { json j_nonobject(json::value_t::number_integer); const json j_nonobject_const(j_nonobject); CHECK_THROWS_AS(j_nonobject.at("foo"), std::runtime_error); CHECK_THROWS_AS(j_nonobject_const.at("foo"), std::runtime_error); } SECTION("number (floating-point)") { json j_nonobject(json::value_t::number_float); const json j_nonobject_const(j_nonobject); CHECK_THROWS_AS(j_nonobject.at("foo"), std::runtime_error); CHECK_THROWS_AS(j_nonobject_const.at("foo"), std::runtime_error); } } } SECTION("access specified element") { SECTION("access within bounds") { CHECK(j["integer"] == json(1)); CHECK(j[json::object_t::key_type("integer")] == j["integer"]); CHECK(j_const["integer"] == json(1)); CHECK(j_const[json::object_t::key_type("integer")] == j["integer"]); CHECK(j["boolean"] == json(true)); CHECK(j[json::object_t::key_type("boolean")] == j["boolean"]); CHECK(j_const["boolean"] == json(true)); CHECK(j_const[json::object_t::key_type("boolean")] == j["boolean"]); CHECK(j["null"] == json(nullptr)); CHECK(j[json::object_t::key_type("null")] == j["null"]); CHECK(j_const["null"] == json(nullptr)); CHECK(j_const[json::object_t::key_type("null")] == j["null"]); CHECK(j["string"] == json("hello world")); CHECK(j[json::object_t::key_type("string")] == j["string"]); CHECK(j_const["string"] == json("hello world")); CHECK(j_const[json::object_t::key_type("string")] == j["string"]); CHECK(j["floating"] == json(42.23)); CHECK(j[json::object_t::key_type("floating")] == j["floating"]); CHECK(j_const["floating"] == json(42.23)); CHECK(j_const[json::object_t::key_type("floating")] == j["floating"]); CHECK(j["object"] == json(json::object())); CHECK(j[json::object_t::key_type("object")] == j["object"]); CHECK(j_const["object"] == json(json::object())); CHECK(j_const[json::object_t::key_type("object")] == j["object"]); CHECK(j["array"] == json({1, 2, 3})); CHECK(j[json::object_t::key_type("array")] == j["array"]); CHECK(j_const["array"] == json({1, 2, 3})); CHECK(j_const[json::object_t::key_type("array")] == j["array"]); } SECTION("access on non-object type") { SECTION("null") { json j_nonobject(json::value_t::null); json j_nonobject2(json::value_t::null); const json j_const_nonobject(j_nonobject); CHECK_NOTHROW(j_nonobject["foo"]); CHECK_NOTHROW(j_nonobject2[json::object_t::key_type("foo")]); CHECK_THROWS_AS(j_const_nonobject["foo"], std::runtime_error); CHECK_THROWS_AS(j_const_nonobject[json::object_t::key_type("foo")], std::runtime_error); } SECTION("boolean") { json j_nonobject(json::value_t::boolean); const json j_const_nonobject(j_nonobject); CHECK_THROWS_AS(j_nonobject["foo"], std::runtime_error); CHECK_THROWS_AS(j_nonobject[json::object_t::key_type("foo")], std::runtime_error); CHECK_THROWS_AS(j_const_nonobject["foo"], std::runtime_error); CHECK_THROWS_AS(j_const_nonobject[json::object_t::key_type("foo")], std::runtime_error); } SECTION("string") { json j_nonobject(json::value_t::string); const json j_const_nonobject(j_nonobject); CHECK_THROWS_AS(j_nonobject["foo"], std::runtime_error); CHECK_THROWS_AS(j_nonobject[json::object_t::key_type("foo")], std::runtime_error); CHECK_THROWS_AS(j_const_nonobject["foo"], std::runtime_error); CHECK_THROWS_AS(j_const_nonobject[json::object_t::key_type("foo")], std::runtime_error); } SECTION("array") { json j_nonobject(json::value_t::array); const json j_const_nonobject(j_nonobject); CHECK_THROWS_AS(j_nonobject["foo"], std::runtime_error); CHECK_THROWS_AS(j_nonobject[json::object_t::key_type("foo")], std::runtime_error); CHECK_THROWS_AS(j_const_nonobject["foo"], std::runtime_error); CHECK_THROWS_AS(j_const_nonobject[json::object_t::key_type("foo")], std::runtime_error); } SECTION("number (integer)") { json j_nonobject(json::value_t::number_integer); const json j_const_nonobject(j_nonobject); CHECK_THROWS_AS(j_nonobject["foo"], std::runtime_error); CHECK_THROWS_AS(j_nonobject[json::object_t::key_type("foo")], std::runtime_error); CHECK_THROWS_AS(j_const_nonobject["foo"], std::runtime_error); CHECK_THROWS_AS(j_const_nonobject[json::object_t::key_type("foo")], std::runtime_error); } SECTION("number (floating-point)") { json j_nonobject(json::value_t::number_float); const json j_const_nonobject(j_nonobject); CHECK_THROWS_AS(j_nonobject["foo"], std::runtime_error); CHECK_THROWS_AS(j_nonobject[json::object_t::key_type("foo")], std::runtime_error); CHECK_THROWS_AS(j_const_nonobject["foo"], std::runtime_error); CHECK_THROWS_AS(j_const_nonobject[json::object_t::key_type("foo")], std::runtime_error); } } } SECTION("find an element in an object") { SECTION("existing element") { for (auto key : {"integer", "floating", "null", "string", "boolean", "object", "array" }) { CHECK(j.find(key) != j.end()); CHECK(*j.find(key) == j.at(key)); CHECK(j_const.find(key) != j_const.end()); CHECK(*j_const.find(key) == j_const.at(key)); } } SECTION("nonexisting element") { CHECK(j.find("foo") == j.end()); CHECK(j_const.find("foo") == j_const.end()); } SECTION("all types") { SECTION("null") { json j_nonarray(json::value_t::null); const json j_nonarray_const(j_nonarray); CHECK(j_nonarray.find("foo") == j_nonarray.end()); CHECK(j_nonarray_const.find("foo") == j_nonarray_const.end()); } SECTION("string") { json j_nonarray(json::value_t::string); const json j_nonarray_const(j_nonarray); CHECK(j_nonarray.find("foo") == j_nonarray.end()); CHECK(j_nonarray_const.find("foo") == j_nonarray_const.end()); } SECTION("object") { json j_nonarray(json::value_t::object); const json j_nonarray_const(j_nonarray); CHECK(j_nonarray.find("foo") == j_nonarray.end()); CHECK(j_nonarray_const.find("foo") == j_nonarray_const.end()); } SECTION("array") { json j_nonarray(json::value_t::array); const json j_nonarray_const(j_nonarray); CHECK(j_nonarray.find("foo") == j_nonarray.end()); CHECK(j_nonarray_const.find("foo") == j_nonarray_const.end()); } SECTION("boolean") { json j_nonarray(json::value_t::boolean); const json j_nonarray_const(j_nonarray); CHECK(j_nonarray.find("foo") == j_nonarray.end()); CHECK(j_nonarray_const.find("foo") == j_nonarray_const.end()); } SECTION("number (integer)") { json j_nonarray(json::value_t::number_integer); const json j_nonarray_const(j_nonarray); CHECK(j_nonarray.find("foo") == j_nonarray.end()); CHECK(j_nonarray_const.find("foo") == j_nonarray_const.end()); } SECTION("number (floating-point)") { json j_nonarray(json::value_t::number_float); const json j_nonarray_const(j_nonarray); CHECK(j_nonarray.find("foo") == j_nonarray.end()); CHECK(j_nonarray_const.find("foo") == j_nonarray_const.end()); } } } } } TEST_CASE("iterators") { SECTION("uninitialized") { json::iterator it; CHECK(it.m_object == nullptr); json::const_iterator cit; CHECK(cit.m_object == nullptr); } SECTION("boolean") { json j = true; json j_const(j); SECTION("json + begin/end") { json::iterator it = j.begin(); CHECK(it != j.end()); CHECK(*it == j); it++; CHECK(it != j.begin()); CHECK(it == j.end()); it--; CHECK(it == j.begin()); CHECK(it != j.end()); CHECK(*it == j); ++it; CHECK(it != j.begin()); CHECK(it == j.end()); --it; CHECK(it == j.begin()); CHECK(it != j.end()); CHECK(*it == j); } SECTION("const json + begin/end") { json::const_iterator it = j_const.begin(); CHECK(it != j_const.end()); CHECK(*it == j_const); it++; CHECK(it != j_const.begin()); CHECK(it == j_const.end()); it--; CHECK(it == j_const.begin()); CHECK(it != j_const.end()); CHECK(*it == j_const); ++it; CHECK(it != j_const.begin()); CHECK(it == j_const.end()); --it; CHECK(it == j_const.begin()); CHECK(it != j_const.end()); CHECK(*it == j_const); } SECTION("json + cbegin/cend") { json::const_iterator it = j.cbegin(); CHECK(it != j.cend()); CHECK(*it == j); it++; CHECK(it != j.cbegin()); CHECK(it == j.cend()); it--; CHECK(it == j.cbegin()); CHECK(it != j.cend()); CHECK(*it == j); ++it; CHECK(it != j.cbegin()); CHECK(it == j.cend()); --it; CHECK(it == j.cbegin()); CHECK(it != j.cend()); CHECK(*it == j); } SECTION("const json + cbegin/cend") { json::const_iterator it = j_const.cbegin(); CHECK(it != j_const.cend()); CHECK(*it == j_const); it++; CHECK(it != j_const.cbegin()); CHECK(it == j_const.cend()); it--; CHECK(it == j_const.cbegin()); CHECK(it != j_const.cend()); CHECK(*it == j_const); ++it; CHECK(it != j_const.cbegin()); CHECK(it == j_const.cend()); --it; CHECK(it == j_const.cbegin()); CHECK(it != j_const.cend()); CHECK(*it == j_const); } SECTION("json + rbegin/rend") { json::reverse_iterator it = j.rbegin(); CHECK(it != j.rend()); CHECK(*it == j); it++; CHECK(it != j.rbegin()); CHECK(it == j.rend()); it--; CHECK(it == j.rbegin()); CHECK(it != j.rend()); CHECK(*it == j); ++it; CHECK(it != j.rbegin()); CHECK(it == j.rend()); --it; CHECK(it == j.rbegin()); CHECK(it != j.rend()); CHECK(*it == j); } SECTION("json + crbegin/crend") { json::const_reverse_iterator it = j.crbegin(); CHECK(it != j.crend()); CHECK(*it == j); it++; CHECK(it != j.crbegin()); CHECK(it == j.crend()); it--; CHECK(it == j.crbegin()); CHECK(it != j.crend()); CHECK(*it == j); ++it; CHECK(it != j.crbegin()); CHECK(it == j.crend()); --it; CHECK(it == j.crbegin()); CHECK(it != j.crend()); CHECK(*it == j); } SECTION("const json + crbegin/crend") { json::const_reverse_iterator it = j_const.crbegin(); CHECK(it != j_const.crend()); CHECK(*it == j_const); it++; CHECK(it != j_const.crbegin()); CHECK(it == j_const.crend()); it--; CHECK(it == j_const.crbegin()); CHECK(it != j_const.crend()); CHECK(*it == j_const); ++it; CHECK(it != j_const.crbegin()); CHECK(it == j_const.crend()); --it; CHECK(it == j_const.crbegin()); CHECK(it != j_const.crend()); CHECK(*it == j_const); } } SECTION("string") { json j = "hello world"; json j_const(j); SECTION("json + begin/end") { json::iterator it = j.begin(); CHECK(it != j.end()); CHECK(*it == j); it++; CHECK(it != j.begin()); CHECK(it == j.end()); it--; CHECK(it == j.begin()); CHECK(it != j.end()); CHECK(*it == j); ++it; CHECK(it != j.begin()); CHECK(it == j.end()); --it; CHECK(it == j.begin()); CHECK(it != j.end()); CHECK(*it == j); } SECTION("const json + begin/end") { json::const_iterator it = j_const.begin(); CHECK(it != j_const.end()); CHECK(*it == j_const); it++; CHECK(it != j_const.begin()); CHECK(it == j_const.end()); it--; CHECK(it == j_const.begin()); CHECK(it != j_const.end()); CHECK(*it == j_const); ++it; CHECK(it != j_const.begin()); CHECK(it == j_const.end()); --it; CHECK(it == j_const.begin()); CHECK(it != j_const.end()); CHECK(*it == j_const); } SECTION("json + cbegin/cend") { json::const_iterator it = j.cbegin(); CHECK(it != j.cend()); CHECK(*it == j); it++; CHECK(it != j.cbegin()); CHECK(it == j.cend()); it--; CHECK(it == j.cbegin()); CHECK(it != j.cend()); CHECK(*it == j); ++it; CHECK(it != j.cbegin()); CHECK(it == j.cend()); --it; CHECK(it == j.cbegin()); CHECK(it != j.cend()); CHECK(*it == j); } SECTION("const json + cbegin/cend") { json::const_iterator it = j_const.cbegin(); CHECK(it != j_const.cend()); CHECK(*it == j_const); it++; CHECK(it != j_const.cbegin()); CHECK(it == j_const.cend()); it--; CHECK(it == j_const.cbegin()); CHECK(it != j_const.cend()); CHECK(*it == j_const); ++it; CHECK(it != j_const.cbegin()); CHECK(it == j_const.cend()); --it; CHECK(it == j_const.cbegin()); CHECK(it != j_const.cend()); CHECK(*it == j_const); } SECTION("json + rbegin/rend") { json::reverse_iterator it = j.rbegin(); CHECK(it != j.rend()); CHECK(*it == j); it++; CHECK(it != j.rbegin()); CHECK(it == j.rend()); it--; CHECK(it == j.rbegin()); CHECK(it != j.rend()); CHECK(*it == j); ++it; CHECK(it != j.rbegin()); CHECK(it == j.rend()); --it; CHECK(it == j.rbegin()); CHECK(it != j.rend()); CHECK(*it == j); } SECTION("json + crbegin/crend") { json::const_reverse_iterator it = j.crbegin(); CHECK(it != j.crend()); CHECK(*it == j); it++; CHECK(it != j.crbegin()); CHECK(it == j.crend()); it--; CHECK(it == j.crbegin()); CHECK(it != j.crend()); CHECK(*it == j); ++it; CHECK(it != j.crbegin()); CHECK(it == j.crend()); --it; CHECK(it == j.crbegin()); CHECK(it != j.crend()); CHECK(*it == j); } SECTION("const json + crbegin/crend") { json::const_reverse_iterator it = j_const.crbegin(); CHECK(it != j_const.crend()); CHECK(*it == j_const); it++; CHECK(it != j_const.crbegin()); CHECK(it == j_const.crend()); it--; CHECK(it == j_const.crbegin()); CHECK(it != j_const.crend()); CHECK(*it == j_const); ++it; CHECK(it != j_const.crbegin()); CHECK(it == j_const.crend()); --it; CHECK(it == j_const.crbegin()); CHECK(it != j_const.crend()); CHECK(*it == j_const); } } SECTION("array") { json j = {1, 2, 3}; json j_const(j); SECTION("json + begin/end") { json::iterator it_begin = j.begin(); json::iterator it_end = j.end(); auto it = it_begin; CHECK(it != it_end); CHECK(*it == j[0]); it++; CHECK(it != it_begin); CHECK(it != it_end); CHECK(*it == j[1]); ++it; CHECK(it != it_begin); CHECK(it != it_end); CHECK(*it == j[2]); ++it; CHECK(it != it_begin); CHECK(it == it_end); } SECTION("const json + begin/end") { json::const_iterator it_begin = j_const.begin(); json::const_iterator it_end = j_const.end(); auto it = it_begin; CHECK(it != it_end); CHECK(*it == j_const[0]); it++; CHECK(it != it_begin); CHECK(it != it_end); CHECK(*it == j_const[1]); ++it; CHECK(it != it_begin); CHECK(it != it_end); CHECK(*it == j_const[2]); ++it; CHECK(it != it_begin); CHECK(it == it_end); } SECTION("json + cbegin/cend") { json::const_iterator it_begin = j.cbegin(); json::const_iterator it_end = j.cend(); auto it = it_begin; CHECK(it != it_end); CHECK(*it == j[0]); it++; CHECK(it != it_begin); CHECK(it != it_end); CHECK(*it == j[1]); ++it; CHECK(it != it_begin); CHECK(it != it_end); CHECK(*it == j[2]); ++it; CHECK(it != it_begin); CHECK(it == it_end); } SECTION("const json + cbegin/cend") { json::const_iterator it_begin = j_const.cbegin(); json::const_iterator it_end = j_const.cend(); auto it = it_begin; CHECK(it != it_end); CHECK(*it == j[0]); it++; CHECK(it != it_begin); CHECK(it != it_end); CHECK(*it == j[1]); ++it; CHECK(it != it_begin); CHECK(it != it_end); CHECK(*it == j[2]); ++it; CHECK(it != it_begin); CHECK(it == it_end); } SECTION("json + rbegin/rend") { json::reverse_iterator it_begin = j.rbegin(); json::reverse_iterator it_end = j.rend(); auto it = it_begin; CHECK(it != it_end); CHECK(*it == j[2]); it++; CHECK(it != it_begin); CHECK(it != it_end); CHECK(*it == j[1]); ++it; CHECK(it != it_begin); CHECK(it != it_end); CHECK(*it == j[0]); ++it; CHECK(it != it_begin); CHECK(it == it_end); } SECTION("json + crbegin/crend") { json::const_reverse_iterator it_begin = j.crbegin(); json::const_reverse_iterator it_end = j.crend(); auto it = it_begin; CHECK(it != it_end); CHECK(*it == j[2]); it++; CHECK(it != it_begin); CHECK(it != it_end); CHECK(*it == j[1]); ++it; CHECK(it != it_begin); CHECK(it != it_end); CHECK(*it == j[0]); ++it; CHECK(it != it_begin); CHECK(it == it_end); } SECTION("const json + crbegin/crend") { json::const_reverse_iterator it_begin = j_const.crbegin(); json::const_reverse_iterator it_end = j_const.crend(); auto it = it_begin; CHECK(it != it_end); CHECK(*it == j[2]); it++; CHECK(it != it_begin); CHECK(it != it_end); CHECK(*it == j[1]); ++it; CHECK(it != it_begin); CHECK(it != it_end); CHECK(*it == j[0]); ++it; CHECK(it != it_begin); CHECK(it == it_end); } } SECTION("object") { json j = {{"A", 1}, {"B", 2}, {"C", 3}}; json j_const(j); SECTION("json + begin/end") { json::iterator it_begin = j.begin(); json::iterator it_end = j.end(); auto it = it_begin; CHECK(it != it_end); CHECK(*it == j["A"]); it++; CHECK(it != it_begin); CHECK(it != it_end); CHECK(*it == j["B"]); ++it; CHECK(it != it_begin); CHECK(it != it_end); CHECK(*it == j["C"]); ++it; CHECK(it != it_begin); CHECK(it == it_end); } SECTION("const json + begin/end") { json::const_iterator it_begin = j_const.begin(); json::const_iterator it_end = j_const.end(); auto it = it_begin; CHECK(it != it_end); CHECK(*it == j_const["A"]); it++; CHECK(it != it_begin); CHECK(it != it_end); CHECK(*it == j_const["B"]); ++it; CHECK(it != it_begin); CHECK(it != it_end); CHECK(*it == j_const["C"]); ++it; CHECK(it != it_begin); CHECK(it == it_end); } SECTION("json + cbegin/cend") { json::const_iterator it_begin = j.cbegin(); json::const_iterator it_end = j.cend(); auto it = it_begin; CHECK(it != it_end); CHECK(*it == j["A"]); it++; CHECK(it != it_begin); CHECK(it != it_end); CHECK(*it == j["B"]); ++it; CHECK(it != it_begin); CHECK(it != it_end); CHECK(*it == j["C"]); ++it; CHECK(it != it_begin); CHECK(it == it_end); } SECTION("const json + cbegin/cend") { json::const_iterator it_begin = j_const.cbegin(); json::const_iterator it_end = j_const.cend(); auto it = it_begin; CHECK(it != it_end); CHECK(*it == j_const["A"]); it++; CHECK(it != it_begin); CHECK(it != it_end); CHECK(*it == j_const["B"]); ++it; CHECK(it != it_begin); CHECK(it != it_end); CHECK(*it == j_const["C"]); ++it; CHECK(it != it_begin); CHECK(it == it_end); } SECTION("json + rbegin/rend") { json::reverse_iterator it_begin = j.rbegin(); json::reverse_iterator it_end = j.rend(); auto it = it_begin; CHECK(it != it_end); CHECK(*it == j["C"]); it++; CHECK(it != it_begin); CHECK(it != it_end); CHECK(*it == j["B"]); ++it; CHECK(it != it_begin); CHECK(it != it_end); CHECK(*it == j["A"]); ++it; CHECK(it != it_begin); CHECK(it == it_end); } SECTION("json + crbegin/crend") { json::const_reverse_iterator it_begin = j.crbegin(); json::const_reverse_iterator it_end = j.crend(); auto it = it_begin; CHECK(it != it_end); CHECK(*it == j["C"]); it++; CHECK(it != it_begin); CHECK(it != it_end); CHECK(*it == j["B"]); ++it; CHECK(it != it_begin); CHECK(it != it_end); CHECK(*it == j["A"]); ++it; CHECK(it != it_begin); CHECK(it == it_end); } SECTION("const json + crbegin/crend") { json::const_reverse_iterator it_begin = j_const.crbegin(); json::const_reverse_iterator it_end = j_const.crend(); auto it = it_begin; CHECK(it != it_end); CHECK(*it == j["C"]); it++; CHECK(it != it_begin); CHECK(it != it_end); CHECK(*it == j["B"]); ++it; CHECK(it != it_begin); CHECK(it != it_end); CHECK(*it == j["A"]); ++it; CHECK(it != it_begin); CHECK(it == it_end); } } SECTION("number (integer)") { json j = 23; json j_const(j); SECTION("json + begin/end") { json::iterator it = j.begin(); CHECK(it != j.end()); CHECK(*it == j); it++; CHECK(it != j.begin()); CHECK(it == j.end()); it--; CHECK(it == j.begin()); CHECK(it != j.end()); CHECK(*it == j); ++it; CHECK(it != j.begin()); CHECK(it == j.end()); --it; CHECK(it == j.begin()); CHECK(it != j.end()); CHECK(*it == j); } SECTION("const json + begin/end") { json::const_iterator it = j_const.begin(); CHECK(it != j_const.end()); CHECK(*it == j_const); it++; CHECK(it != j_const.begin()); CHECK(it == j_const.end()); it--; CHECK(it == j_const.begin()); CHECK(it != j_const.end()); CHECK(*it == j_const); ++it; CHECK(it != j_const.begin()); CHECK(it == j_const.end()); --it; CHECK(it == j_const.begin()); CHECK(it != j_const.end()); CHECK(*it == j_const); } SECTION("json + cbegin/cend") { json::const_iterator it = j.cbegin(); CHECK(it != j.cend()); CHECK(*it == j); it++; CHECK(it != j.cbegin()); CHECK(it == j.cend()); it--; CHECK(it == j.cbegin()); CHECK(it != j.cend()); CHECK(*it == j); ++it; CHECK(it != j.cbegin()); CHECK(it == j.cend()); --it; CHECK(it == j.cbegin()); CHECK(it != j.cend()); CHECK(*it == j); } SECTION("const json + cbegin/cend") { json::const_iterator it = j_const.cbegin(); CHECK(it != j_const.cend()); CHECK(*it == j_const); it++; CHECK(it != j_const.cbegin()); CHECK(it == j_const.cend()); it--; CHECK(it == j_const.cbegin()); CHECK(it != j_const.cend()); CHECK(*it == j_const); ++it; CHECK(it != j_const.cbegin()); CHECK(it == j_const.cend()); --it; CHECK(it == j_const.cbegin()); CHECK(it != j_const.cend()); CHECK(*it == j_const); } SECTION("json + rbegin/rend") { json::reverse_iterator it = j.rbegin(); CHECK(it != j.rend()); CHECK(*it == j); it++; CHECK(it != j.rbegin()); CHECK(it == j.rend()); it--; CHECK(it == j.rbegin()); CHECK(it != j.rend()); CHECK(*it == j); ++it; CHECK(it != j.rbegin()); CHECK(it == j.rend()); --it; CHECK(it == j.rbegin()); CHECK(it != j.rend()); CHECK(*it == j); } SECTION("json + crbegin/crend") { json::const_reverse_iterator it = j.crbegin(); CHECK(it != j.crend()); CHECK(*it == j); it++; CHECK(it != j.crbegin()); CHECK(it == j.crend()); it--; CHECK(it == j.crbegin()); CHECK(it != j.crend()); CHECK(*it == j); ++it; CHECK(it != j.crbegin()); CHECK(it == j.crend()); --it; CHECK(it == j.crbegin()); CHECK(it != j.crend()); CHECK(*it == j); } SECTION("const json + crbegin/crend") { json::const_reverse_iterator it = j_const.crbegin(); CHECK(it != j_const.crend()); CHECK(*it == j_const); it++; CHECK(it != j_const.crbegin()); CHECK(it == j_const.crend()); it--; CHECK(it == j_const.crbegin()); CHECK(it != j_const.crend()); CHECK(*it == j_const); ++it; CHECK(it != j_const.crbegin()); CHECK(it == j_const.crend()); --it; CHECK(it == j_const.crbegin()); CHECK(it != j_const.crend()); CHECK(*it == j_const); } } SECTION("number (float)") { json j = 23.42; json j_const(j); SECTION("json + begin/end") { json::iterator it = j.begin(); CHECK(it != j.end()); CHECK(*it == j); it++; CHECK(it != j.begin()); CHECK(it == j.end()); it--; CHECK(it == j.begin()); CHECK(it != j.end()); CHECK(*it == j); ++it; CHECK(it != j.begin()); CHECK(it == j.end()); --it; CHECK(it == j.begin()); CHECK(it != j.end()); CHECK(*it == j); } SECTION("const json + begin/end") { json::const_iterator it = j_const.begin(); CHECK(it != j_const.end()); CHECK(*it == j_const); it++; CHECK(it != j_const.begin()); CHECK(it == j_const.end()); it--; CHECK(it == j_const.begin()); CHECK(it != j_const.end()); CHECK(*it == j_const); ++it; CHECK(it != j_const.begin()); CHECK(it == j_const.end()); --it; CHECK(it == j_const.begin()); CHECK(it != j_const.end()); CHECK(*it == j_const); } SECTION("json + cbegin/cend") { json::const_iterator it = j.cbegin(); CHECK(it != j.cend()); CHECK(*it == j); it++; CHECK(it != j.cbegin()); CHECK(it == j.cend()); it--; CHECK(it == j.cbegin()); CHECK(it != j.cend()); CHECK(*it == j); ++it; CHECK(it != j.cbegin()); CHECK(it == j.cend()); --it; CHECK(it == j.cbegin()); CHECK(it != j.cend()); CHECK(*it == j); } SECTION("const json + cbegin/cend") { json::const_iterator it = j_const.cbegin(); CHECK(it != j_const.cend()); CHECK(*it == j_const); it++; CHECK(it != j_const.cbegin()); CHECK(it == j_const.cend()); it--; CHECK(it == j_const.cbegin()); CHECK(it != j_const.cend()); CHECK(*it == j_const); ++it; CHECK(it != j_const.cbegin()); CHECK(it == j_const.cend()); --it; CHECK(it == j_const.cbegin()); CHECK(it != j_const.cend()); CHECK(*it == j_const); } SECTION("json + rbegin/rend") { json::reverse_iterator it = j.rbegin(); CHECK(it != j.rend()); CHECK(*it == j); it++; CHECK(it != j.rbegin()); CHECK(it == j.rend()); it--; CHECK(it == j.rbegin()); CHECK(it != j.rend()); CHECK(*it == j); ++it; CHECK(it != j.rbegin()); CHECK(it == j.rend()); --it; CHECK(it == j.rbegin()); CHECK(it != j.rend()); CHECK(*it == j); } SECTION("json + crbegin/crend") { json::const_reverse_iterator it = j.crbegin(); CHECK(it != j.crend()); CHECK(*it == j); it++; CHECK(it != j.crbegin()); CHECK(it == j.crend()); it--; CHECK(it == j.crbegin()); CHECK(it != j.crend()); CHECK(*it == j); ++it; CHECK(it != j.crbegin()); CHECK(it == j.crend()); --it; CHECK(it == j.crbegin()); CHECK(it != j.crend()); CHECK(*it == j); } SECTION("const json + crbegin/crend") { json::const_reverse_iterator it = j_const.crbegin(); CHECK(it != j_const.crend()); CHECK(*it == j_const); it++; CHECK(it != j_const.crbegin()); CHECK(it == j_const.crend()); it--; CHECK(it == j_const.crbegin()); CHECK(it != j_const.crend()); CHECK(*it == j_const); ++it; CHECK(it != j_const.crbegin()); CHECK(it == j_const.crend()); --it; CHECK(it == j_const.crbegin()); CHECK(it != j_const.crend()); CHECK(*it == j_const); } } SECTION("null") { json j = nullptr; json j_const(j); SECTION("json + begin/end") { json::iterator it = j.begin(); CHECK(it == j.end()); } SECTION("const json + begin/end") { json::const_iterator it_begin = j_const.begin(); json::const_iterator it_end = j_const.end(); CHECK(it_begin == it_end); } SECTION("json + cbegin/cend") { json::const_iterator it_begin = j.cbegin(); json::const_iterator it_end = j.cend(); CHECK(it_begin == it_end); } SECTION("const json + cbegin/cend") { json::const_iterator it_begin = j_const.cbegin(); json::const_iterator it_end = j_const.cend(); CHECK(it_begin == it_end); } SECTION("json + rbegin/rend") { json::reverse_iterator it = j.rbegin(); CHECK(it == j.rend()); } SECTION("json + crbegin/crend") { json::const_reverse_iterator it = j.crbegin(); CHECK(it == j.crend()); } SECTION("const json + crbegin/crend") { json::const_reverse_iterator it = j_const.crbegin(); CHECK(it == j_const.crend()); } } } TEST_CASE("capacity") { SECTION("empty()") { SECTION("boolean") { json j = true; json j_const(j); SECTION("result of empty") { CHECK(j.empty() == false); CHECK(j_const.empty() == false); } SECTION("definition of empty") { CHECK(j.begin() != j.end()); CHECK(j_const.begin() != j_const.end()); } } SECTION("string") { json j = "hello world"; json j_const(j); SECTION("result of empty") { CHECK(j.empty() == false); CHECK(j_const.empty() == false); } SECTION("definition of empty") { CHECK(j.begin() != j.end()); CHECK(j_const.begin() != j_const.end()); } } SECTION("array") { SECTION("empty array") { json j = json::array(); json j_const(j); SECTION("result of empty") { CHECK(j.empty() == true); CHECK(j_const.empty() == true); } SECTION("definition of empty") { CHECK(j.begin() == j.end()); CHECK(j_const.begin() == j_const.end()); } } SECTION("filled array") { json j = {1, 2, 3}; json j_const(j); SECTION("result of empty") { CHECK(j.empty() == false); CHECK(j_const.empty() == false); } SECTION("definition of empty") { CHECK(j.begin() != j.end()); CHECK(j_const.begin() != j_const.end()); } } } SECTION("object") { SECTION("empty object") { json j = json::object(); json j_const(j); SECTION("result of empty") { CHECK(j.empty() == true); CHECK(j_const.empty() == true); } SECTION("definition of empty") { CHECK(j.begin() == j.end()); CHECK(j_const.begin() == j_const.end()); } } SECTION("filled object") { json j = {{"one", 1}, {"two", 2}, {"three", 3}}; json j_const(j); SECTION("result of empty") { CHECK(j.empty() == false); CHECK(j_const.empty() == false); } SECTION("definition of empty") { CHECK(j.begin() != j.end()); CHECK(j_const.begin() != j_const.end()); } } } SECTION("number (integer)") { json j = 23; json j_const(j); SECTION("result of empty") { CHECK(j.empty() == false); CHECK(j_const.empty() == false); } SECTION("definition of empty") { CHECK(j.begin() != j.end()); CHECK(j_const.begin() != j_const.end()); } } SECTION("number (float)") { json j = 23.42; json j_const(j); SECTION("result of empty") { CHECK(j.empty() == false); CHECK(j_const.empty() == false); } SECTION("definition of empty") { CHECK(j.begin() != j.end()); CHECK(j_const.begin() != j_const.end()); } } SECTION("null") { json j = nullptr; json j_const(j); SECTION("result of empty") { CHECK(j.empty() == true); CHECK(j_const.empty() == true); } SECTION("definition of empty") { CHECK(j.begin() == j.end()); CHECK(j_const.begin() == j_const.end()); } } } SECTION("size()") { SECTION("boolean") { json j = true; json j_const(j); SECTION("result of size") { CHECK(j.size() == 1); CHECK(j_const.size() == 1); } SECTION("definition of size") { CHECK(std::distance(j.begin(), j.end()) == j.size()); CHECK(std::distance(j_const.begin(), j_const.end()) == j_const.size()); CHECK(std::distance(j.rbegin(), j.rend()) == j.size()); CHECK(std::distance(j_const.crbegin(), j_const.crend()) == j_const.size()); } } SECTION("string") { json j = "hello world"; json j_const(j); SECTION("result of size") { CHECK(j.size() == 1); CHECK(j_const.size() == 1); } SECTION("definition of size") { CHECK(std::distance(j.begin(), j.end()) == j.size()); CHECK(std::distance(j_const.begin(), j_const.end()) == j_const.size()); CHECK(std::distance(j.rbegin(), j.rend()) == j.size()); CHECK(std::distance(j_const.crbegin(), j_const.crend()) == j_const.size()); } } SECTION("array") { SECTION("empty array") { json j = json::array(); json j_const(j); SECTION("result of size") { CHECK(j.size() == 0); CHECK(j_const.size() == 0); } SECTION("definition of size") { CHECK(std::distance(j.begin(), j.end()) == j.size()); CHECK(std::distance(j_const.begin(), j_const.end()) == j_const.size()); CHECK(std::distance(j.rbegin(), j.rend()) == j.size()); CHECK(std::distance(j_const.crbegin(), j_const.crend()) == j_const.size()); } } SECTION("filled array") { json j = {1, 2, 3}; json j_const(j); SECTION("result of size") { CHECK(j.size() == 3); CHECK(j_const.size() == 3); } SECTION("definition of size") { CHECK(std::distance(j.begin(), j.end()) == j.size()); CHECK(std::distance(j_const.begin(), j_const.end()) == j_const.size()); CHECK(std::distance(j.rbegin(), j.rend()) == j.size()); CHECK(std::distance(j_const.crbegin(), j_const.crend()) == j_const.size()); } } } SECTION("object") { SECTION("empty object") { json j = json::object(); json j_const(j); SECTION("result of size") { CHECK(j.size() == 0); CHECK(j_const.size() == 0); } SECTION("definition of size") { CHECK(std::distance(j.begin(), j.end()) == j.size()); CHECK(std::distance(j_const.begin(), j_const.end()) == j_const.size()); CHECK(std::distance(j.rbegin(), j.rend()) == j.size()); CHECK(std::distance(j_const.crbegin(), j_const.crend()) == j_const.size()); } } SECTION("filled object") { json j = {{"one", 1}, {"two", 2}, {"three", 3}}; json j_const(j); SECTION("result of size") { CHECK(j.size() == 3); CHECK(j_const.size() == 3); } SECTION("definition of size") { CHECK(std::distance(j.begin(), j.end()) == j.size()); CHECK(std::distance(j_const.begin(), j_const.end()) == j_const.size()); CHECK(std::distance(j.rbegin(), j.rend()) == j.size()); CHECK(std::distance(j_const.crbegin(), j_const.crend()) == j_const.size()); } } } SECTION("number (integer)") { json j = 23; json j_const(j); SECTION("result of size") { CHECK(j.size() == 1); CHECK(j_const.size() == 1); } SECTION("definition of size") { CHECK(std::distance(j.begin(), j.end()) == j.size()); CHECK(std::distance(j_const.begin(), j_const.end()) == j_const.size()); CHECK(std::distance(j.rbegin(), j.rend()) == j.size()); CHECK(std::distance(j_const.crbegin(), j_const.crend()) == j_const.size()); } } SECTION("number (float)") { json j = 23.42; json j_const(j); SECTION("result of size") { CHECK(j.size() == 1); CHECK(j_const.size() == 1); } SECTION("definition of size") { CHECK(std::distance(j.begin(), j.end()) == j.size()); CHECK(std::distance(j_const.begin(), j_const.end()) == j_const.size()); CHECK(std::distance(j.rbegin(), j.rend()) == j.size()); CHECK(std::distance(j_const.crbegin(), j_const.crend()) == j_const.size()); } } SECTION("null") { json j = nullptr; json j_const(j); SECTION("result of size") { CHECK(j.size() == 0); CHECK(j_const.size() == 0); } SECTION("definition of size") { CHECK(std::distance(j.begin(), j.end()) == j.size()); CHECK(std::distance(j_const.begin(), j_const.end()) == j_const.size()); CHECK(std::distance(j.rbegin(), j.rend()) == j.size()); CHECK(std::distance(j_const.crbegin(), j_const.crend()) == j_const.size()); } } } SECTION("max_size()") { SECTION("boolean") { json j = true; json j_const(j); SECTION("result of max_size") { CHECK(j.max_size() == 1); CHECK(j_const.max_size() == 1); } } SECTION("string") { json j = "hello world"; json j_const(j); SECTION("result of max_size") { CHECK(j.max_size() == 1); CHECK(j_const.max_size() == 1); } } SECTION("array") { SECTION("empty array") { json j = json::array(); json j_const(j); SECTION("result of max_size") { CHECK(j.max_size() >= j.size()); CHECK(j_const.max_size() >= j_const.size()); } } SECTION("filled array") { json j = {1, 2, 3}; json j_const(j); SECTION("result of max_size") { CHECK(j.max_size() >= j.size()); CHECK(j_const.max_size() >= j_const.size()); } } } SECTION("object") { SECTION("empty object") { json j = json::object(); json j_const(j); SECTION("result of max_size") { CHECK(j.max_size() >= j.size()); CHECK(j_const.max_size() >= j_const.size()); } } SECTION("filled object") { json j = {{"one", 1}, {"two", 2}, {"three", 3}}; json j_const(j); SECTION("result of max_size") { CHECK(j.max_size() >= j.size()); CHECK(j_const.max_size() >= j_const.size()); } } } SECTION("number (integer)") { json j = 23; json j_const(j); SECTION("result of max_size") { CHECK(j.max_size() == 1); CHECK(j_const.max_size() == 1); } } SECTION("number (float)") { json j = 23.42; json j_const(j); SECTION("result of max_size") { CHECK(j.max_size() == 1); CHECK(j_const.max_size() == 1); } } SECTION("null") { json j = nullptr; json j_const(j); SECTION("result of max_size") { CHECK(j.max_size() == 0); CHECK(j_const.max_size() == 0); } } } } TEST_CASE("modifiers") { SECTION("clear()") { SECTION("boolean") { json j = true; j.clear(); CHECK(j == json(json::value_t::boolean)); } SECTION("string") { json j = "hello world"; j.clear(); CHECK(j == json(json::value_t::string)); } SECTION("array") { SECTION("empty array") { json j = json::array(); j.clear(); CHECK(j.empty()); CHECK(j == json(json::value_t::array)); } SECTION("filled array") { json j = {1, 2, 3}; j.clear(); CHECK(j.empty()); CHECK(j == json(json::value_t::array)); } } SECTION("object") { SECTION("empty object") { json j = json::object(); j.clear(); CHECK(j.empty()); CHECK(j == json(json::value_t::object)); } SECTION("filled object") { json j = {{"one", 1}, {"two", 2}, {"three", 3}}; j.clear(); CHECK(j.empty()); CHECK(j == json(json::value_t::object)); } } SECTION("number (integer)") { json j = 23; j.clear(); CHECK(j == json(json::value_t::number_integer)); } SECTION("number (float)") { json j = 23.42; j.clear(); CHECK(j == json(json::value_t::number_float)); } SECTION("null") { json j = nullptr; j.clear(); CHECK(j == json(json::value_t::null)); } } SECTION("push_back()") { SECTION("to array") { SECTION("json&&") { SECTION("null") { json j; j.push_back(1); j.push_back(2); CHECK(j.type() == json::value_t::array); CHECK(j == json({1, 2})); } SECTION("array") { json j = {1, 2, 3}; j.push_back("Hello"); CHECK(j.type() == json::value_t::array); CHECK(j == json({1, 2, 3, "Hello"})); } SECTION("other type") { json j = 1; CHECK_THROWS_AS(j.push_back("Hello"), std::runtime_error); } } SECTION("const json&") { SECTION("null") { json j; json k(1); j.push_back(k); j.push_back(k); CHECK(j.type() == json::value_t::array); CHECK(j == json({1, 1})); } SECTION("array") { json j = {1, 2, 3}; json k("Hello"); j.push_back(k); CHECK(j.type() == json::value_t::array); CHECK(j == json({1, 2, 3, "Hello"})); } SECTION("other type") { json j = 1; json k("Hello"); CHECK_THROWS_AS(j.push_back(k), std::runtime_error); } } } SECTION("to object") { SECTION("null") { json j; j.push_back(json::object_t::value_type({"one", 1})); j.push_back(json::object_t::value_type({"two", 2})); CHECK(j.type() == json::value_t::object); CHECK(j.size() == 2); CHECK(j["one"] == json(1)); CHECK(j["two"] == json(2)); } SECTION("object") { json j(json::value_t::object); j.push_back(json::object_t::value_type({"one", 1})); j.push_back(json::object_t::value_type({"two", 2})); CHECK(j.size() == 2); CHECK(j["one"] == json(1)); CHECK(j["two"] == json(2)); } SECTION("other type") { json j = 1; json k("Hello"); CHECK_THROWS_AS(j.push_back(json::object_t::value_type({"one", 1})), std::runtime_error); } } } SECTION("operator+=") { SECTION("to array") { SECTION("json&&") { SECTION("null") { json j; j += 1; j += 2; CHECK(j.type() == json::value_t::array); CHECK(j == json({1, 2})); } SECTION("array") { json j = {1, 2, 3}; j += "Hello"; CHECK(j.type() == json::value_t::array); CHECK(j == json({1, 2, 3, "Hello"})); } SECTION("other type") { json j = 1; CHECK_THROWS_AS(j += "Hello", std::runtime_error); } } SECTION("const json&") { SECTION("null") { json j; json k(1); j += k; j += k; CHECK(j.type() == json::value_t::array); CHECK(j == json({1, 1})); } SECTION("array") { json j = {1, 2, 3}; json k("Hello"); j += k; CHECK(j.type() == json::value_t::array); CHECK(j == json({1, 2, 3, "Hello"})); } SECTION("other type") { json j = 1; json k("Hello"); CHECK_THROWS_AS(j += k, std::runtime_error); } } } SECTION("to object") { SECTION("null") { json j; j += json::object_t::value_type({"one", 1}); j += json::object_t::value_type({"two", 2}); CHECK(j.type() == json::value_t::object); CHECK(j.size() == 2); CHECK(j["one"] == json(1)); CHECK(j["two"] == json(2)); } SECTION("object") { json j(json::value_t::object); j += json::object_t::value_type({"one", 1}); j += json::object_t::value_type({"two", 2}); CHECK(j.size() == 2); CHECK(j["one"] == json(1)); CHECK(j["two"] == json(2)); } SECTION("other type") { json j = 1; json k("Hello"); CHECK_THROWS_AS(j += json::object_t::value_type({"one", 1}), std::runtime_error); } } } SECTION("swap()") { SECTION("json") { SECTION("member swap") { json j("hello world"); json k(42.23); j.swap(k); CHECK(j == json(42.23)); CHECK(k == json("hello world")); } SECTION("nonmember swap") { json j("hello world"); json k(42.23); std::swap(j, k); CHECK(j == json(42.23)); CHECK(k == json("hello world")); } } SECTION("array_t") { SECTION("array_t type") { json j = {1, 2, 3, 4}; json::array_t a = {"foo", "bar", "baz"}; j.swap(a); CHECK(j == json({"foo", "bar", "baz"})); j.swap(a); CHECK(j == json({1, 2, 3, 4})); } SECTION("non-array_t type") { json j = 17; json::array_t a = {"foo", "bar", "baz"}; CHECK_THROWS_AS(j.swap(a), std::runtime_error); } } SECTION("object_t") { SECTION("object_t type") { json j = {{"one", 1}, {"two", 2}}; json::object_t o = {{"cow", "Kuh"}, {"chicken", "Huhn"}}; j.swap(o); CHECK(j == json({{"cow", "Kuh"}, {"chicken", "Huhn"}})); j.swap(o); CHECK(j == json({{"one", 1}, {"two", 2}})); } SECTION("non-object_t type") { json j = 17; json::object_t o = {{"cow", "Kuh"}, {"chicken", "Huhn"}}; CHECK_THROWS_AS(j.swap(o), std::runtime_error); } } SECTION("string_t") { SECTION("string_t type") { json j = "Hello world"; json::string_t s = "Hallo Welt"; j.swap(s); CHECK(j == json("Hallo Welt")); j.swap(s); CHECK(j == json("Hello world")); } SECTION("non-string_t type") { json j = 17; json::string_t s = "Hallo Welt"; CHECK_THROWS_AS(j.swap(s), std::runtime_error); } } } } TEST_CASE("lexicographical comparison operators") { json j_values = { nullptr, nullptr, 17, 42, 3.14159, 23.42, "foo", "bar", true, false, {1, 2, 3}, {"one", "two", "three"}, {{"first", 1}, {"second", 2}}, {{"a", "A"}, {"b", {"B"}}} }; SECTION("comparison: equal") { std::vector> expected = { {true, true, false, false, false, false, false, false, false, false, false, false, false, false}, {true, true, false, false, false, false, false, false, false, false, false, false, false, false}, {false, false, true, false, false, false, false, false, false, false, false, false, false, false}, {false, false, false, true, false, false, false, false, false, false, false, false, false, false}, {false, false, false, false, true, false, false, false, false, false, false, false, false, false}, {false, false, false, false, false, true, false, false, false, false, false, false, false, false}, {false, false, false, false, false, false, true, false, false, false, false, false, false, false}, {false, false, false, false, false, false, false, true, false, false, false, false, false, false}, {false, false, false, false, false, false, false, false, true, false, false, false, false, false}, {false, false, false, false, false, false, false, false, false, true, false, false, false, false}, {false, false, false, false, false, false, false, false, false, false, true, false, false, false}, {false, false, false, false, false, false, false, false, false, false, false, true, false, false}, {false, false, false, false, false, false, false, false, false, false, false, false, true, false}, {false, false, false, false, false, false, false, false, false, false, false, false, false, true} }; for (size_t i = 0; i < j_values.size(); ++i) { for (size_t j = 0; j < j_values.size(); ++j) { // check precomputed values CHECK( (j_values[i] == j_values[j]) == expected[i][j] ); } } } SECTION("comparison: not equal") { for (size_t i = 0; i < j_values.size(); ++i) { for (size_t j = 0; j < j_values.size(); ++j) { // check definition CHECK( (j_values[i] != j_values[j]) == not(j_values[i] == j_values[j]) ); } } } SECTION("comparison: less") { std::vector> expected = { {false, false, false, false, false, false, false, false, false, false, false, false, false, false}, {false, false, false, false, false, false, false, false, false, false, false, false, false, false}, {false, false, false, true, false, true, false, false, false, false, false, false, false, false}, {false, false, false, false, false, false, false, false, false, false, false, false, false, false}, {false, false, true, true, false, true, false, false, false, false, false, false, false, false}, {false, false, false, true, false, false, false, false, false, false, false, false, false, false}, {false, false, false, false, false, false, false, false, false, false, false, false, false, false}, {false, false, false, false, false, false, true, false, false, false, false, false, false, false}, {false, false, false, false, false, false, false, false, false, false, false, false, false, false}, {false, false, false, false, false, false, false, false, true, false, false, false, false, false}, {false, false, false, false, false, false, false, false, false, false, false, false, false, false}, {false, false, false, false, false, false, false, false, false, false, false, false, false, false}, {false, false, false, false, false, false, false, false, false, false, false, false, false, false}, {false, false, false, false, false, false, false, false, false, false, false, false, true, false} }; for (size_t i = 0; i < j_values.size(); ++i) { for (size_t j = 0; j < j_values.size(); ++j) { // check precomputed values CHECK( (j_values[i] < j_values[j]) == expected[i][j] ); } } } SECTION("comparison: less than or equal equal") { for (size_t i = 0; i < j_values.size(); ++i) { for (size_t j = 0; j < j_values.size(); ++j) { // check definition CHECK( (j_values[i] <= j_values[j]) == not(j_values[j] < j_values[i]) ); } } } SECTION("comparison: greater than") { for (size_t i = 0; i < j_values.size(); ++i) { for (size_t j = 0; j < j_values.size(); ++j) { // check definition CHECK( (j_values[i] > j_values[j]) == (j_values[j] < j_values[i]) ); } } } SECTION("comparison: greater than or equal") { for (size_t i = 0; i < j_values.size(); ++i) { for (size_t j = 0; j < j_values.size(); ++j) { // check definition CHECK( (j_values[i] >= j_values[j]) == not(j_values[i] < j_values[j]) ); } } } } TEST_CASE("serialization") { SECTION("operator<<") { SECTION("no given width") { std::stringstream ss; json j = {"foo", 1, 2, 3, false, {{"one", 1}}}; ss << j; CHECK(ss.str() == "[\"foo\",1,2,3,false,{\"one\":1}]"); } SECTION("given width") { std::stringstream ss; json j = {"foo", 1, 2, 3, false, {{"one", 1}}}; ss << std::setw(4) << j; CHECK(ss.str() == "[\n \"foo\",\n 1,\n 2,\n 3,\n false,\n {\n \"one\": 1\n }\n]"); } } SECTION("operator>>") { SECTION("no given width") { std::stringstream ss; json j = {"foo", 1, 2, 3, false, {{"one", 1}}}; j >> ss; CHECK(ss.str() == "[\"foo\",1,2,3,false,{\"one\":1}]"); } SECTION("given width") { std::stringstream ss; json j = {"foo", 1, 2, 3, false, {{"one", 1}}}; ss.width(4); j >> ss; CHECK(ss.str() == "[\n \"foo\",\n 1,\n 2,\n 3,\n false,\n {\n \"one\": 1\n }\n]"); } } } TEST_CASE("deserialization") { SECTION("string") { auto s = "[\"foo\",1,2,3,false,{\"one\":1}]"; json j = json::parse(s); CHECK(j == json({"foo", 1, 2, 3, false, {{"one", 1}}})); } SECTION("operator<<") { std::stringstream ss; ss << "[\"foo\",1,2,3,false,{\"one\":1}]"; json j; j << ss; CHECK(j == json({"foo", 1, 2, 3, false, {{"one", 1}}})); } SECTION("operator>>") { std::stringstream ss; ss << "[\"foo\",1,2,3,false,{\"one\":1}]"; json j; ss >> j; CHECK(j == json({"foo", 1, 2, 3, false, {{"one", 1}}})); } SECTION("user-defined string literal") { CHECK("[\"foo\",1,2,3,false,{\"one\":1}]"_json == json({"foo", 1, 2, 3, false, {{"one", 1}}})); } } TEST_CASE("iterator class") { SECTION("construction") { SECTION("constructor") { SECTION("null") { json j(json::value_t::null); json::iterator it(&j); } SECTION("object") { json j(json::value_t::object); json::iterator it(&j); } SECTION("array") { json j(json::value_t::array); json::iterator it(&j); } } SECTION("copy assignment") { json j(json::value_t::null); json::iterator it(&j); json::iterator it2(&j); it2 = it; } } SECTION("initialization") { SECTION("set_begin") { SECTION("null") { json j(json::value_t::null); json::iterator it(&j); it.set_begin(); CHECK(it == j.begin()); } SECTION("object") { json j(json::value_t::object); json::iterator it(&j); it.set_begin(); CHECK(it == j.begin()); } SECTION("array") { json j(json::value_t::array); json::iterator it(&j); it.set_begin(); CHECK(it == j.begin()); } } SECTION("set_end") { SECTION("null") { json j(json::value_t::null); json::iterator it(&j); it.set_end(); CHECK(it == j.end()); } SECTION("object") { json j(json::value_t::object); json::iterator it(&j); it.set_end(); CHECK(it == j.end()); } SECTION("array") { json j(json::value_t::array); json::iterator it(&j); it.set_end(); CHECK(it == j.end()); } } } SECTION("element access") { SECTION("operator*") { SECTION("null") { json j(json::value_t::null); json::iterator it = j.begin(); CHECK_THROWS_AS(*it, std::out_of_range); } SECTION("number") { json j(17); json::iterator it = j.begin(); CHECK(*it == json(17)); it = j.end(); CHECK_THROWS_AS(*it, std::out_of_range); } SECTION("object") { json j({{"foo", "bar"}}); json::iterator it = j.begin(); CHECK(*it == json("bar")); } SECTION("array") { json j({1, 2, 3, 4}); json::iterator it = j.begin(); CHECK(*it == json(1)); } } SECTION("operator->") { SECTION("null") { json j(json::value_t::null); json::iterator it = j.begin(); CHECK_THROWS_AS(it->type_name(), std::out_of_range); } SECTION("number") { json j(17); json::iterator it = j.begin(); CHECK(it->type_name() == "number"); it = j.end(); CHECK_THROWS_AS(it->type_name(), std::out_of_range); } SECTION("object") { json j({{"foo", "bar"}}); json::iterator it = j.begin(); CHECK(it->type_name() == "string"); } SECTION("array") { json j({1, 2, 3, 4}); json::iterator it = j.begin(); CHECK(it->type_name() == "number"); } } } SECTION("increment/decrement") { SECTION("post-increment") { SECTION("null") { json j(json::value_t::null); json::iterator it = j.begin(); CHECK(it.m_it.generic_iterator == json::generic_iterator_value::end); it++; CHECK(it.m_it.generic_iterator == json::generic_iterator_value::invalid); } SECTION("number") { json j(17); json::iterator it = j.begin(); CHECK(it.m_it.generic_iterator == json::generic_iterator_value::begin); it++; CHECK(it.m_it.generic_iterator == json::generic_iterator_value::end); it++; CHECK(it.m_it.generic_iterator == json::generic_iterator_value::invalid); } SECTION("object") { json j({{"foo", "bar"}}); json::iterator it = j.begin(); CHECK(it.m_it.object_iterator == it.m_object->m_value.object->begin()); it++; CHECK(it.m_it.object_iterator == it.m_object->m_value.object->end()); } SECTION("array") { json j({1, 2, 3, 4}); json::iterator it = j.begin(); CHECK(it.m_it.array_iterator == it.m_object->m_value.array->begin()); it++; CHECK(it.m_it.array_iterator != it.m_object->m_value.array->begin()); CHECK(it.m_it.array_iterator != it.m_object->m_value.array->end()); it++; CHECK(it.m_it.array_iterator != it.m_object->m_value.array->begin()); CHECK(it.m_it.array_iterator != it.m_object->m_value.array->end()); it++; CHECK(it.m_it.array_iterator != it.m_object->m_value.array->begin()); CHECK(it.m_it.array_iterator != it.m_object->m_value.array->end()); it++; CHECK(it.m_it.array_iterator != it.m_object->m_value.array->begin()); CHECK(it.m_it.array_iterator == it.m_object->m_value.array->end()); } } SECTION("pre-increment") { SECTION("null") { json j(json::value_t::null); json::iterator it = j.begin(); CHECK(it.m_it.generic_iterator == json::generic_iterator_value::end); ++it; CHECK(it.m_it.generic_iterator == json::generic_iterator_value::invalid); } SECTION("number") { json j(17); json::iterator it = j.begin(); CHECK(it.m_it.generic_iterator == json::generic_iterator_value::begin); ++it; CHECK(it.m_it.generic_iterator == json::generic_iterator_value::end); ++it; CHECK(it.m_it.generic_iterator == json::generic_iterator_value::invalid); } SECTION("object") { json j({{"foo", "bar"}}); json::iterator it = j.begin(); CHECK(it.m_it.object_iterator == it.m_object->m_value.object->begin()); ++it; CHECK(it.m_it.object_iterator == it.m_object->m_value.object->end()); } SECTION("array") { json j({1, 2, 3, 4}); json::iterator it = j.begin(); CHECK(it.m_it.array_iterator == it.m_object->m_value.array->begin()); ++it; CHECK(it.m_it.array_iterator != it.m_object->m_value.array->begin()); CHECK(it.m_it.array_iterator != it.m_object->m_value.array->end()); ++it; CHECK(it.m_it.array_iterator != it.m_object->m_value.array->begin()); CHECK(it.m_it.array_iterator != it.m_object->m_value.array->end()); ++it; CHECK(it.m_it.array_iterator != it.m_object->m_value.array->begin()); CHECK(it.m_it.array_iterator != it.m_object->m_value.array->end()); ++it; CHECK(it.m_it.array_iterator != it.m_object->m_value.array->begin()); CHECK(it.m_it.array_iterator == it.m_object->m_value.array->end()); } } SECTION("post-decrement") { SECTION("null") { json j(json::value_t::null); json::iterator it = j.end(); CHECK(it.m_it.generic_iterator == json::generic_iterator_value::end); it--; CHECK(it.m_it.generic_iterator == json::generic_iterator_value::invalid); } SECTION("number") { json j(17); json::iterator it = j.end(); CHECK(it.m_it.generic_iterator == json::generic_iterator_value::end); it--; CHECK(it.m_it.generic_iterator == json::generic_iterator_value::begin); it--; CHECK(it.m_it.generic_iterator == json::generic_iterator_value::invalid); } SECTION("object") { json j({{"foo", "bar"}}); json::iterator it = j.end(); CHECK(it.m_it.object_iterator == it.m_object->m_value.object->end()); it--; CHECK(it.m_it.object_iterator == it.m_object->m_value.object->begin()); } SECTION("array") { json j({1, 2, 3, 4}); json::iterator it = j.end(); CHECK(it.m_it.array_iterator == it.m_object->m_value.array->end()); it--; CHECK(it.m_it.array_iterator != it.m_object->m_value.array->begin()); CHECK(it.m_it.array_iterator != it.m_object->m_value.array->end()); it--; CHECK(it.m_it.array_iterator != it.m_object->m_value.array->begin()); CHECK(it.m_it.array_iterator != it.m_object->m_value.array->end()); it--; CHECK(it.m_it.array_iterator != it.m_object->m_value.array->begin()); CHECK(it.m_it.array_iterator != it.m_object->m_value.array->end()); it--; CHECK(it.m_it.array_iterator == it.m_object->m_value.array->begin()); CHECK(it.m_it.array_iterator != it.m_object->m_value.array->end()); } } SECTION("pre-decrement") { SECTION("null") { json j(json::value_t::null); json::iterator it = j.end(); CHECK(it.m_it.generic_iterator == json::generic_iterator_value::end); --it; CHECK(it.m_it.generic_iterator == json::generic_iterator_value::invalid); } SECTION("number") { json j(17); json::iterator it = j.end(); CHECK(it.m_it.generic_iterator == json::generic_iterator_value::end); --it; CHECK(it.m_it.generic_iterator == json::generic_iterator_value::begin); --it; CHECK(it.m_it.generic_iterator == json::generic_iterator_value::invalid); } SECTION("object") { json j({{"foo", "bar"}}); json::iterator it = j.end(); CHECK(it.m_it.object_iterator == it.m_object->m_value.object->end()); --it; CHECK(it.m_it.object_iterator == it.m_object->m_value.object->begin()); } SECTION("array") { json j({1, 2, 3, 4}); json::iterator it = j.end(); CHECK(it.m_it.array_iterator == it.m_object->m_value.array->end()); --it; CHECK(it.m_it.array_iterator != it.m_object->m_value.array->begin()); CHECK(it.m_it.array_iterator != it.m_object->m_value.array->end()); --it; CHECK(it.m_it.array_iterator != it.m_object->m_value.array->begin()); CHECK(it.m_it.array_iterator != it.m_object->m_value.array->end()); --it; CHECK(it.m_it.array_iterator != it.m_object->m_value.array->begin()); CHECK(it.m_it.array_iterator != it.m_object->m_value.array->end()); --it; CHECK(it.m_it.array_iterator == it.m_object->m_value.array->begin()); CHECK(it.m_it.array_iterator != it.m_object->m_value.array->end()); } } } SECTION("comparison") { json j_values = { nullptr, nullptr, 17, 42, 3.14159, 23.42, "foo", "bar", true, false, {1, 2, 3}, {"one", "two", "three"}, {{"first", 1}, {"second", 2}}, {{"a", "A"}, {"b", {"B"}}} }; SECTION("comparison: equal") { std::vector> expected = { {true, false, false, false, false, false, false, false, false, false, false, false, false, false}, {false, true, false, false, false, false, false, false, false, false, false, false, false, false}, {false, false, true, false, false, false, false, false, false, false, false, false, false, false}, {false, false, false, true, false, false, false, false, false, false, false, false, false, false}, {false, false, false, false, true, false, false, false, false, false, false, false, false, false}, {false, false, false, false, false, true, false, false, false, false, false, false, false, false}, {false, false, false, false, false, false, true, false, false, false, false, false, false, false}, {false, false, false, false, false, false, false, true, false, false, false, false, false, false}, {false, false, false, false, false, false, false, false, true, false, false, false, false, false}, {false, false, false, false, false, false, false, false, false, true, false, false, false, false}, {false, false, false, false, false, false, false, false, false, false, true, false, false, false}, {false, false, false, false, false, false, false, false, false, false, false, true, false, false}, {false, false, false, false, false, false, false, false, false, false, false, false, true, false}, {false, false, false, false, false, false, false, false, false, false, false, false, false, true} }; for (size_t i = 0; i < j_values.size(); ++i) { for (size_t j = 0; j < j_values.size(); ++j) { // check precomputed values CHECK( (j_values[i].begin() == j_values[j].begin()) == expected[i][j] ); } } } SECTION("comparison: not equal") { for (size_t i = 0; i < j_values.size(); ++i) { for (size_t j = 0; j < j_values.size(); ++j) { // check definition CHECK( (j_values[i].begin() != j_values[j].begin()) == not ((j_values[i].begin() == j_values[j].begin())) ); } } } } } TEST_CASE("const_iterator class") { SECTION("construction") { SECTION("constructor") { SECTION("null") { json j(json::value_t::null); json::const_iterator it(&j); } SECTION("object") { json j(json::value_t::object); json::const_iterator it(&j); } SECTION("array") { json j(json::value_t::array); json::const_iterator it(&j); } } SECTION("copy assignment") { json j(json::value_t::null); json::const_iterator it(&j); json::const_iterator it2(&j); it2 = it; } } SECTION("initialization") { SECTION("set_begin") { SECTION("null") { json j(json::value_t::null); json::const_iterator it(&j); it.set_begin(); CHECK(it == j.cbegin()); } SECTION("object") { json j(json::value_t::object); json::const_iterator it(&j); it.set_begin(); CHECK(it == j.cbegin()); } SECTION("array") { json j(json::value_t::array); json::const_iterator it(&j); it.set_begin(); CHECK(it == j.cbegin()); } } SECTION("set_end") { SECTION("null") { json j(json::value_t::null); json::const_iterator it(&j); it.set_end(); CHECK(it == j.cend()); } SECTION("object") { json j(json::value_t::object); json::const_iterator it(&j); it.set_end(); CHECK(it == j.cend()); } SECTION("array") { json j(json::value_t::array); json::const_iterator it(&j); it.set_end(); CHECK(it == j.cend()); } } } SECTION("element access") { SECTION("operator*") { SECTION("null") { json j(json::value_t::null); json::const_iterator it = j.cbegin(); CHECK_THROWS_AS(*it, std::out_of_range); } SECTION("number") { json j(17); json::const_iterator it = j.cbegin(); CHECK(*it == json(17)); it = j.cend(); CHECK_THROWS_AS(*it, std::out_of_range); } SECTION("object") { json j({{"foo", "bar"}}); json::const_iterator it = j.cbegin(); CHECK(*it == json("bar")); } SECTION("array") { json j({1, 2, 3, 4}); json::const_iterator it = j.cbegin(); CHECK(*it == json(1)); } } SECTION("operator->") { SECTION("null") { json j(json::value_t::null); json::const_iterator it = j.cbegin(); CHECK_THROWS_AS(it->type_name(), std::out_of_range); } SECTION("number") { json j(17); json::const_iterator it = j.cbegin(); CHECK(it->type_name() == "number"); it = j.cend(); CHECK_THROWS_AS(it->type_name(), std::out_of_range); } SECTION("object") { json j({{"foo", "bar"}}); json::const_iterator it = j.cbegin(); CHECK(it->type_name() == "string"); } SECTION("array") { json j({1, 2, 3, 4}); json::const_iterator it = j.cbegin(); CHECK(it->type_name() == "number"); } } } SECTION("increment/decrement") { SECTION("post-increment") { SECTION("null") { json j(json::value_t::null); json::const_iterator it = j.cbegin(); CHECK(it.m_it.generic_iterator == json::generic_iterator_value::end); it++; CHECK(it.m_it.generic_iterator == json::generic_iterator_value::invalid); } SECTION("number") { json j(17); json::const_iterator it = j.cbegin(); CHECK(it.m_it.generic_iterator == json::generic_iterator_value::begin); it++; CHECK(it.m_it.generic_iterator == json::generic_iterator_value::end); it++; CHECK(it.m_it.generic_iterator == json::generic_iterator_value::invalid); } SECTION("object") { json j({{"foo", "bar"}}); json::const_iterator it = j.cbegin(); CHECK(it.m_it.object_iterator == it.m_object->m_value.object->begin()); it++; CHECK(it.m_it.object_iterator == it.m_object->m_value.object->end()); } SECTION("array") { json j({1, 2, 3, 4}); json::const_iterator it = j.cbegin(); CHECK(it.m_it.array_iterator == it.m_object->m_value.array->begin()); it++; CHECK(it.m_it.array_iterator != it.m_object->m_value.array->begin()); CHECK(it.m_it.array_iterator != it.m_object->m_value.array->end()); it++; CHECK(it.m_it.array_iterator != it.m_object->m_value.array->begin()); CHECK(it.m_it.array_iterator != it.m_object->m_value.array->end()); it++; CHECK(it.m_it.array_iterator != it.m_object->m_value.array->begin()); CHECK(it.m_it.array_iterator != it.m_object->m_value.array->end()); it++; CHECK(it.m_it.array_iterator != it.m_object->m_value.array->begin()); CHECK(it.m_it.array_iterator == it.m_object->m_value.array->end()); } } SECTION("pre-increment") { SECTION("null") { json j(json::value_t::null); json::const_iterator it = j.cbegin(); CHECK(it.m_it.generic_iterator == json::generic_iterator_value::end); ++it; CHECK(it.m_it.generic_iterator == json::generic_iterator_value::invalid); } SECTION("number") { json j(17); json::const_iterator it = j.cbegin(); CHECK(it.m_it.generic_iterator == json::generic_iterator_value::begin); ++it; CHECK(it.m_it.generic_iterator == json::generic_iterator_value::end); ++it; CHECK(it.m_it.generic_iterator == json::generic_iterator_value::invalid); } SECTION("object") { json j({{"foo", "bar"}}); json::const_iterator it = j.cbegin(); CHECK(it.m_it.object_iterator == it.m_object->m_value.object->begin()); ++it; CHECK(it.m_it.object_iterator == it.m_object->m_value.object->end()); } SECTION("array") { json j({1, 2, 3, 4}); json::const_iterator it = j.cbegin(); CHECK(it.m_it.array_iterator == it.m_object->m_value.array->begin()); ++it; CHECK(it.m_it.array_iterator != it.m_object->m_value.array->begin()); CHECK(it.m_it.array_iterator != it.m_object->m_value.array->end()); ++it; CHECK(it.m_it.array_iterator != it.m_object->m_value.array->begin()); CHECK(it.m_it.array_iterator != it.m_object->m_value.array->end()); ++it; CHECK(it.m_it.array_iterator != it.m_object->m_value.array->begin()); CHECK(it.m_it.array_iterator != it.m_object->m_value.array->end()); ++it; CHECK(it.m_it.array_iterator != it.m_object->m_value.array->begin()); CHECK(it.m_it.array_iterator == it.m_object->m_value.array->end()); } } SECTION("post-decrement") { SECTION("null") { json j(json::value_t::null); json::const_iterator it = j.cend(); CHECK(it.m_it.generic_iterator == json::generic_iterator_value::end); it--; CHECK(it.m_it.generic_iterator == json::generic_iterator_value::invalid); } SECTION("number") { json j(17); json::const_iterator it = j.cend(); CHECK(it.m_it.generic_iterator == json::generic_iterator_value::end); it--; CHECK(it.m_it.generic_iterator == json::generic_iterator_value::begin); it--; CHECK(it.m_it.generic_iterator == json::generic_iterator_value::invalid); } SECTION("object") { json j({{"foo", "bar"}}); json::const_iterator it = j.cend(); CHECK(it.m_it.object_iterator == it.m_object->m_value.object->end()); it--; CHECK(it.m_it.object_iterator == it.m_object->m_value.object->begin()); } SECTION("array") { json j({1, 2, 3, 4}); json::const_iterator it = j.cend(); CHECK(it.m_it.array_iterator == it.m_object->m_value.array->end()); it--; CHECK(it.m_it.array_iterator != it.m_object->m_value.array->begin()); CHECK(it.m_it.array_iterator != it.m_object->m_value.array->end()); it--; CHECK(it.m_it.array_iterator != it.m_object->m_value.array->begin()); CHECK(it.m_it.array_iterator != it.m_object->m_value.array->end()); it--; CHECK(it.m_it.array_iterator != it.m_object->m_value.array->begin()); CHECK(it.m_it.array_iterator != it.m_object->m_value.array->end()); it--; CHECK(it.m_it.array_iterator == it.m_object->m_value.array->begin()); CHECK(it.m_it.array_iterator != it.m_object->m_value.array->end()); } } SECTION("pre-decrement") { SECTION("null") { json j(json::value_t::null); json::const_iterator it = j.cend(); CHECK(it.m_it.generic_iterator == json::generic_iterator_value::end); --it; CHECK(it.m_it.generic_iterator == json::generic_iterator_value::invalid); } SECTION("number") { json j(17); json::const_iterator it = j.cend(); CHECK(it.m_it.generic_iterator == json::generic_iterator_value::end); --it; CHECK(it.m_it.generic_iterator == json::generic_iterator_value::begin); --it; CHECK(it.m_it.generic_iterator == json::generic_iterator_value::invalid); } SECTION("object") { json j({{"foo", "bar"}}); json::const_iterator it = j.cend(); CHECK(it.m_it.object_iterator == it.m_object->m_value.object->end()); --it; CHECK(it.m_it.object_iterator == it.m_object->m_value.object->begin()); } SECTION("array") { json j({1, 2, 3, 4}); json::const_iterator it = j.cend(); CHECK(it.m_it.array_iterator == it.m_object->m_value.array->end()); --it; CHECK(it.m_it.array_iterator != it.m_object->m_value.array->begin()); CHECK(it.m_it.array_iterator != it.m_object->m_value.array->end()); --it; CHECK(it.m_it.array_iterator != it.m_object->m_value.array->begin()); CHECK(it.m_it.array_iterator != it.m_object->m_value.array->end()); --it; CHECK(it.m_it.array_iterator != it.m_object->m_value.array->begin()); CHECK(it.m_it.array_iterator != it.m_object->m_value.array->end()); --it; CHECK(it.m_it.array_iterator == it.m_object->m_value.array->begin()); CHECK(it.m_it.array_iterator != it.m_object->m_value.array->end()); } } } SECTION("comparison") { json j_values = { nullptr, nullptr, 17, 42, 3.14159, 23.42, "foo", "bar", true, false, {1, 2, 3}, {"one", "two", "three"}, {{"first", 1}, {"second", 2}}, {{"a", "A"}, {"b", {"B"}}} }; SECTION("comparison: equal") { std::vector> expected = { {true, false, false, false, false, false, false, false, false, false, false, false, false, false}, {false, true, false, false, false, false, false, false, false, false, false, false, false, false}, {false, false, true, false, false, false, false, false, false, false, false, false, false, false}, {false, false, false, true, false, false, false, false, false, false, false, false, false, false}, {false, false, false, false, true, false, false, false, false, false, false, false, false, false}, {false, false, false, false, false, true, false, false, false, false, false, false, false, false}, {false, false, false, false, false, false, true, false, false, false, false, false, false, false}, {false, false, false, false, false, false, false, true, false, false, false, false, false, false}, {false, false, false, false, false, false, false, false, true, false, false, false, false, false}, {false, false, false, false, false, false, false, false, false, true, false, false, false, false}, {false, false, false, false, false, false, false, false, false, false, true, false, false, false}, {false, false, false, false, false, false, false, false, false, false, false, true, false, false}, {false, false, false, false, false, false, false, false, false, false, false, false, true, false}, {false, false, false, false, false, false, false, false, false, false, false, false, false, true} }; for (size_t i = 0; i < j_values.size(); ++i) { for (size_t j = 0; j < j_values.size(); ++j) { // check precomputed values CHECK( (j_values[i].cbegin() == j_values[j].cbegin()) == expected[i][j] ); } } } SECTION("comparison: not equal") { for (size_t i = 0; i < j_values.size(); ++i) { for (size_t j = 0; j < j_values.size(); ++j) { // check definition CHECK( (j_values[i].cbegin() != j_values[j].cbegin()) == not ((j_values[i].cbegin() == j_values[j].cbegin())) ); } } } } } TEST_CASE("convenience functions") { SECTION("type name as string") { CHECK(json(json::value_t::null).type_name() == "null"); CHECK(json(json::value_t::object).type_name() == "object"); CHECK(json(json::value_t::array).type_name() == "array"); CHECK(json(json::value_t::number_integer).type_name() == "number"); CHECK(json(json::value_t::number_float).type_name() == "number"); CHECK(json(json::value_t::boolean).type_name() == "boolean"); CHECK(json(json::value_t::string).type_name() == "string"); } SECTION("string escape") { CHECK(json::escape_string("\"") == "\\\""); CHECK(json::escape_string("\\") == "\\\\"); CHECK(json::escape_string("\b") == "\\b"); CHECK(json::escape_string("\f") == "\\f"); CHECK(json::escape_string("\n") == "\\n"); CHECK(json::escape_string("\r") == "\\r"); CHECK(json::escape_string("\t") == "\\t"); CHECK(json::escape_string("\x01") == "\\u0001"); CHECK(json::escape_string("\x02") == "\\u0002"); CHECK(json::escape_string("\x03") == "\\u0003"); CHECK(json::escape_string("\x04") == "\\u0004"); CHECK(json::escape_string("\x05") == "\\u0005"); CHECK(json::escape_string("\x06") == "\\u0006"); CHECK(json::escape_string("\x07") == "\\u0007"); CHECK(json::escape_string("\x08") == "\\b"); CHECK(json::escape_string("\x09") == "\\t"); CHECK(json::escape_string("\x0a") == "\\n"); CHECK(json::escape_string("\x0b") == "\\u000b"); CHECK(json::escape_string("\x0c") == "\\f"); CHECK(json::escape_string("\x0d") == "\\r"); CHECK(json::escape_string("\x0e") == "\\u000e"); CHECK(json::escape_string("\x0f") == "\\u000f"); CHECK(json::escape_string("\x10") == "\\u0010"); CHECK(json::escape_string("\x11") == "\\u0011"); CHECK(json::escape_string("\x12") == "\\u0012"); CHECK(json::escape_string("\x13") == "\\u0013"); CHECK(json::escape_string("\x14") == "\\u0014"); CHECK(json::escape_string("\x15") == "\\u0015"); CHECK(json::escape_string("\x16") == "\\u0016"); CHECK(json::escape_string("\x17") == "\\u0017"); CHECK(json::escape_string("\x18") == "\\u0018"); CHECK(json::escape_string("\x19") == "\\u0019"); CHECK(json::escape_string("\x1a") == "\\u001a"); CHECK(json::escape_string("\x1b") == "\\u001b"); CHECK(json::escape_string("\x1c") == "\\u001c"); CHECK(json::escape_string("\x1d") == "\\u001d"); CHECK(json::escape_string("\x1e") == "\\u001e"); CHECK(json::escape_string("\x1f") == "\\u001f"); } } TEST_CASE("lexer class") { SECTION("scan") { SECTION("structural characters") { CHECK(json::lexer("[").scan() == json::lexer::token_type::begin_array); CHECK(json::lexer("]").scan() == json::lexer::token_type::end_array); CHECK(json::lexer("{").scan() == json::lexer::token_type::begin_object); CHECK(json::lexer("}").scan() == json::lexer::token_type::end_object); CHECK(json::lexer(",").scan() == json::lexer::token_type::value_separator); CHECK(json::lexer(":").scan() == json::lexer::token_type::name_separator); } SECTION("literal names") { CHECK(json::lexer("null").scan() == json::lexer::token_type::literal_null); CHECK(json::lexer("true").scan() == json::lexer::token_type::literal_true); CHECK(json::lexer("false").scan() == json::lexer::token_type::literal_false); } SECTION("numbers") { CHECK(json::lexer("0").scan() == json::lexer::token_type::value_number); CHECK(json::lexer("1").scan() == json::lexer::token_type::value_number); CHECK(json::lexer("2").scan() == json::lexer::token_type::value_number); CHECK(json::lexer("3").scan() == json::lexer::token_type::value_number); CHECK(json::lexer("4").scan() == json::lexer::token_type::value_number); CHECK(json::lexer("5").scan() == json::lexer::token_type::value_number); CHECK(json::lexer("6").scan() == json::lexer::token_type::value_number); CHECK(json::lexer("7").scan() == json::lexer::token_type::value_number); CHECK(json::lexer("8").scan() == json::lexer::token_type::value_number); CHECK(json::lexer("9").scan() == json::lexer::token_type::value_number); } SECTION("whitespace") { // result is end_of_input, because not token is following CHECK(json::lexer(" ").scan() == json::lexer::token_type::end_of_input); CHECK(json::lexer("\t").scan() == json::lexer::token_type::end_of_input); CHECK(json::lexer("\n").scan() == json::lexer::token_type::end_of_input); CHECK(json::lexer("\r").scan() == json::lexer::token_type::end_of_input); CHECK(json::lexer(" \t\n\r\n\t ").scan() == json::lexer::token_type::end_of_input); } } SECTION("token_type_name") { CHECK(json::lexer::token_type_name(json::lexer::token_type::uninitialized) == ""); CHECK(json::lexer::token_type_name(json::lexer::token_type::literal_true) == "true literal"); CHECK(json::lexer::token_type_name(json::lexer::token_type::literal_false) == "false literal"); CHECK(json::lexer::token_type_name(json::lexer::token_type::literal_null) == "null literal"); CHECK(json::lexer::token_type_name(json::lexer::token_type::value_string) == "string literal"); CHECK(json::lexer::token_type_name(json::lexer::token_type::value_number) == "number literal"); CHECK(json::lexer::token_type_name(json::lexer::token_type::begin_array) == "["); CHECK(json::lexer::token_type_name(json::lexer::token_type::begin_object) == "{"); CHECK(json::lexer::token_type_name(json::lexer::token_type::end_array) == "]"); CHECK(json::lexer::token_type_name(json::lexer::token_type::end_object) == "}"); CHECK(json::lexer::token_type_name(json::lexer::token_type::name_separator) == ":"); CHECK(json::lexer::token_type_name(json::lexer::token_type::value_separator) == ","); CHECK(json::lexer::token_type_name(json::lexer::token_type::parse_error) == ""); CHECK(json::lexer::token_type_name(json::lexer::token_type::end_of_input) == ""); } SECTION("parse errors on first character") { for (int c = 1; c < 128; ++c) { auto s = std::string(1, c); switch (c) { // single characters that are valid tokens case ('['): case (']'): case ('{'): case ('}'): case (','): case (':'): case ('0'): case ('1'): case ('2'): case ('3'): case ('4'): case ('5'): case ('6'): case ('7'): case ('8'): case ('9'): { CHECK(json::lexer(s.c_str()).scan() != json::lexer::token_type::parse_error); break; } // whitespace case (' '): case ('\t'): case ('\n'): case ('\r'): { CHECK(json::lexer(s.c_str()).scan() == json::lexer::token_type::end_of_input); break; } // anything else is not expected default: { CHECK(json::lexer(s.c_str()).scan() == json::lexer::token_type::parse_error); break; } } } } SECTION("to_unicode") { CHECK(json::lexer::to_unicode(0x1F4A9) == "💩"); CHECK_THROWS_AS(json::lexer::to_unicode(0x200000), std::out_of_range); } } TEST_CASE("parser class") { SECTION("parse") { SECTION("null") { CHECK(json::parser("null").parse() == json(nullptr)); } SECTION("true") { CHECK(json::parser("true").parse() == json(true)); } SECTION("false") { CHECK(json::parser("false").parse() == json(false)); } SECTION("array") { SECTION("empty array") { CHECK(json::parser("[]").parse() == json(json::value_t::array)); CHECK(json::parser("[ ]").parse() == json(json::value_t::array)); } SECTION("nonempty array") { CHECK(json::parser("[true, false, null]").parse() == json({true, false, nullptr})); } } SECTION("object") { SECTION("empty object") { CHECK(json::parser("{}").parse() == json(json::value_t::object)); CHECK(json::parser("{ }").parse() == json(json::value_t::object)); } SECTION("nonempty object") { CHECK(json::parser("{\"\": true, \"one\": 1, \"two\": null}").parse() == json({{"", true}, {"one", 1}, {"two", nullptr}})); } } SECTION("string") { // empty string CHECK(json::parser("\"\"").parse() == json(json::value_t::string)); SECTION("escaped") { // quotation mark CHECK(json::parser("\"\\\"\"").parse() == json("\\\"")); // reverse solidus CHECK(json::parser("\"\\\\\"").parse() == json("\\\\")); // solidus CHECK(json::parser("\"\\/\"").parse() == json("\\/")); // backspace CHECK(json::parser("\"\\b\"").parse() == json("\b")); // formfeed CHECK(json::parser("\"\\f\"").parse() == json("\f")); // newline CHECK(json::parser("\"\\n\"").parse() == json("\n")); // carriage return CHECK(json::parser("\"\\r\"").parse() == json("\r")); // horizontal tab CHECK(json::parser("\"\\t\"").parse() == json("\t")); CHECK(json::parser("\"\\u0001\"").parse().get() == "\x01"); CHECK(json::parser("\"\\u000a\"").parse().get() == "\n"); CHECK(json::parser("\"\\u00b0\"").parse().get() == "°"); CHECK(json::parser("\"\\u0c00\"").parse().get() == "ఀ"); CHECK(json::parser("\"\\ud000\"").parse().get() == "퀀"); CHECK(json::parser("\"\\u000E\"").parse().get() == "\x0E"); CHECK(json::parser("\"\\u00F0\"").parse().get() == "ð"); CHECK(json::parser("\"\\u0100\"").parse().get() == "Ā"); CHECK(json::parser("\"\\u2000\"").parse().get() == " "); CHECK(json::parser("\"\\uFFFF\"").parse().get() == "￿"); CHECK(json::parser("\"\\u20AC\"").parse().get() == "€"); CHECK(json::parser("\"€\"").parse().get() == "€"); CHECK(json::parser("\"🎈\"").parse().get() == "🎈"); CHECK(json::parse("\"\\ud80c\\udc60\"").get() == u8"\U00013060"); CHECK(json::parse("\"\\ud83c\\udf1e\"").get() == "🌞"); } } SECTION("number") { SECTION("integers") { SECTION("without exponent") { CHECK(json::parser("-128").parse() == json(-128)); CHECK(json::parser("-0").parse() == json(-0)); CHECK(json::parser("0").parse() == json(0)); CHECK(json::parser("128").parse() == json(128)); } SECTION("with exponent") { CHECK(json::parser("0e1").parse() == json(0e1)); CHECK(json::parser("0E1").parse() == json(0e1)); CHECK(json::parser("10000E-4").parse() == json(10000e-4)); CHECK(json::parser("10000E-3").parse() == json(10000e-3)); CHECK(json::parser("10000E-2").parse() == json(10000e-2)); CHECK(json::parser("10000E-1").parse() == json(10000e-1)); CHECK(json::parser("10000E0").parse() == json(10000e0)); CHECK(json::parser("10000E1").parse() == json(10000e1)); CHECK(json::parser("10000E2").parse() == json(10000e2)); CHECK(json::parser("10000E3").parse() == json(10000e3)); CHECK(json::parser("10000E4").parse() == json(10000e4)); CHECK(json::parser("10000e-4").parse() == json(10000e-4)); CHECK(json::parser("10000e-3").parse() == json(10000e-3)); CHECK(json::parser("10000e-2").parse() == json(10000e-2)); CHECK(json::parser("10000e-1").parse() == json(10000e-1)); CHECK(json::parser("10000e0").parse() == json(10000e0)); CHECK(json::parser("10000e1").parse() == json(10000e1)); CHECK(json::parser("10000e2").parse() == json(10000e2)); CHECK(json::parser("10000e3").parse() == json(10000e3)); CHECK(json::parser("10000e4").parse() == json(10000e4)); CHECK(json::parser("-0e1").parse() == json(-0e1)); CHECK(json::parser("-0E1").parse() == json(-0e1)); CHECK(json::parser("-0E123").parse() == json(-0e123)); } } SECTION("floating-point") { SECTION("without exponent") { CHECK(json::parser("-128.5").parse() == json(-128.5)); CHECK(json::parser("0.999").parse() == json(0.999)); CHECK(json::parser("128.5").parse() == json(128.5)); CHECK(json::parser("-0.0").parse() == json(-0.0)); } SECTION("with exponent") { CHECK(json::parser("-128.5E3").parse() == json(-128.5E3)); CHECK(json::parser("-128.5E-3").parse() == json(-128.5E-3)); CHECK(json::parser("-0.0e1").parse() == json(-0.0e1)); CHECK(json::parser("-0.0E1").parse() == json(-0.0e1)); } } SECTION("invalid numbers") { CHECK_THROWS_AS(json::parser("01").parse(), std::invalid_argument); CHECK_THROWS_AS(json::parser("--1").parse(), std::invalid_argument); CHECK_THROWS_AS(json::parser("1.").parse(), std::invalid_argument); CHECK_THROWS_AS(json::parser("1E").parse(), std::invalid_argument); CHECK_THROWS_AS(json::parser("1E-").parse(), std::invalid_argument); CHECK_THROWS_AS(json::parser("1.E1").parse(), std::invalid_argument); CHECK_THROWS_AS(json::parser("-1E").parse(), std::invalid_argument); CHECK_THROWS_AS(json::parser("-0E#").parse(), std::invalid_argument); CHECK_THROWS_AS(json::parser("-0E-#").parse(), std::invalid_argument); CHECK_THROWS_AS(json::parser("-0#").parse(), std::invalid_argument); CHECK_THROWS_AS(json::parser("-0.0:").parse(), std::invalid_argument); CHECK_THROWS_AS(json::parser("-0.0Z").parse(), std::invalid_argument); CHECK_THROWS_AS(json::parser("-0E123:").parse(), std::invalid_argument); CHECK_THROWS_AS(json::parser("-0e0-:").parse(), std::invalid_argument); CHECK_THROWS_AS(json::parser("-0e-:").parse(), std::invalid_argument); CHECK_THROWS_AS(json::parser("-0f").parse(), std::invalid_argument); } } } SECTION("parse errors") { // unexpected end of number CHECK_THROWS_AS(json::parser("0.").parse(), std::invalid_argument); CHECK_THROWS_AS(json::parser("-").parse(), std::invalid_argument); CHECK_THROWS_AS(json::parser("--").parse(), std::invalid_argument); CHECK_THROWS_AS(json::parser("-0.").parse(), std::invalid_argument); CHECK_THROWS_AS(json::parser("-.").parse(), std::invalid_argument); CHECK_THROWS_AS(json::parser("-:").parse(), std::invalid_argument); CHECK_THROWS_AS(json::parser("0.:").parse(), std::invalid_argument); CHECK_THROWS_AS(json::parser("e.").parse(), std::invalid_argument); CHECK_THROWS_AS(json::parser("1e.").parse(), std::invalid_argument); CHECK_THROWS_AS(json::parser("1e/").parse(), std::invalid_argument); CHECK_THROWS_AS(json::parser("1e:").parse(), std::invalid_argument); CHECK_THROWS_AS(json::parser("1E.").parse(), std::invalid_argument); CHECK_THROWS_AS(json::parser("1E/").parse(), std::invalid_argument); CHECK_THROWS_AS(json::parser("1E:").parse(), std::invalid_argument); // unexpected end of null CHECK_THROWS_AS(json::parser("n").parse(), std::invalid_argument); CHECK_THROWS_AS(json::parser("n").parse(), std::invalid_argument); CHECK_THROWS_AS(json::parser("nu").parse(), std::invalid_argument); CHECK_THROWS_AS(json::parser("nul").parse(), std::invalid_argument); // unexpected end of true CHECK_THROWS_AS(json::parser("t").parse(), std::invalid_argument); CHECK_THROWS_AS(json::parser("t").parse(), std::invalid_argument); CHECK_THROWS_AS(json::parser("tr").parse(), std::invalid_argument); CHECK_THROWS_AS(json::parser("tru").parse(), std::invalid_argument); // unexpected end of false CHECK_THROWS_AS(json::parser("f").parse(), std::invalid_argument); CHECK_THROWS_AS(json::parser("fa").parse(), std::invalid_argument); CHECK_THROWS_AS(json::parser("fal").parse(), std::invalid_argument); CHECK_THROWS_AS(json::parser("fals").parse(), std::invalid_argument); // unexpected end of array CHECK_THROWS_AS(json::parser("[").parse(), std::invalid_argument); CHECK_THROWS_AS(json::parser("[1").parse(), std::invalid_argument); CHECK_THROWS_AS(json::parser("[1,").parse(), std::invalid_argument); CHECK_THROWS_AS(json::parser("[1,]").parse(), std::invalid_argument); CHECK_THROWS_AS(json::parser("]").parse(), std::invalid_argument); // unexpected end of object CHECK_THROWS_AS(json::parser("{").parse(), std::invalid_argument); CHECK_THROWS_AS(json::parser("{\"foo\"").parse(), std::invalid_argument); CHECK_THROWS_AS(json::parser("{\"foo\":").parse(), std::invalid_argument); CHECK_THROWS_AS(json::parser("{\"foo\":}").parse(), std::invalid_argument); CHECK_THROWS_AS(json::parser("{\"foo\":1,}").parse(), std::invalid_argument); CHECK_THROWS_AS(json::parser("}").parse(), std::invalid_argument); // unexpected end of string CHECK_THROWS_AS(json::parser("\"").parse(), std::invalid_argument); CHECK_THROWS_AS(json::parser("\"\\\"").parse(), std::invalid_argument); CHECK_THROWS_AS(json::parser("\"\\u\"").parse(), std::invalid_argument); CHECK_THROWS_AS(json::parser("\"\\u0\"").parse(), std::invalid_argument); CHECK_THROWS_AS(json::parser("\"\\u01\"").parse(), std::invalid_argument); CHECK_THROWS_AS(json::parser("\"\\u012\"").parse(), std::invalid_argument); // invalid escapes for (int c = 1; c < 128; ++c) { auto s = std::string("\"\\") + std::string(1, c) + "\""; switch (c) { // valid escapes case ('"'): case ('\\'): case ('/'): case ('b'): case ('f'): case ('n'): case ('r'): case ('t'): { CHECK_NOTHROW(json::parser(s).parse()); break; } // \u must be followed with four numbers, so we skip it here case ('u'): { break; } // any other combination of backslash and character is invalid default: { CHECK_THROWS_AS(json::parser(s).parse(), std::invalid_argument); break; } } } // invalid \uxxxx escapes { // check whether character is a valid hex character const auto valid = [](int c) { switch (c) { case ('0'): case ('1'): case ('2'): case ('3'): case ('4'): case ('5'): case ('6'): case ('7'): case ('8'): case ('9'): case ('a'): case ('b'): case ('c'): case ('d'): case ('e'): case ('f'): case ('A'): case ('B'): case ('C'): case ('D'): case ('E'): case ('F'): { return true; } default: { return false; } } }; for (int c = 1; c < 128; ++c) { std::string s = "\"\\u"; // create a string with the iterated character at each position auto s1 = s + "000" + std::string(1, c) + "\""; auto s2 = s + "00" + std::string(1, c) + "0\""; auto s3 = s + "0" + std::string(1, c) + "00\""; auto s4 = s + std::string(1, c) + "000\""; if (valid(c)) { CHECK_NOTHROW(json::parser(s1).parse()); CHECK_NOTHROW(json::parser(s2).parse()); CHECK_NOTHROW(json::parser(s3).parse()); CHECK_NOTHROW(json::parser(s4).parse()); } else { CHECK_THROWS_AS(json::parser(s1).parse(), std::invalid_argument); CHECK_THROWS_AS(json::parser(s2).parse(), std::invalid_argument); CHECK_THROWS_AS(json::parser(s3).parse(), std::invalid_argument); CHECK_THROWS_AS(json::parser(s4).parse(), std::invalid_argument); } } } // missing part of a surrogate pair CHECK_THROWS_AS(json::parse("\"\\uD80C\""), std::invalid_argument); // invalid surrogate pair CHECK_THROWS_AS(json::parse("\"\\uD80C\\uD80C\""), std::invalid_argument); CHECK_THROWS_AS(json::parse("\"\\uD80C\\u0000\""), std::invalid_argument); CHECK_THROWS_AS(json::parse("\"\\uD80C\\uFFFF\""), std::invalid_argument); } } TEST_CASE("README", "[hide]") { { // create an empty structure (null) json j; // add a number that is stored as double (note the implicit conversion of j to an object) j["pi"] = 3.141; // add a Boolean that is stored as bool j["happy"] = true; // add a string that is stored as std::string j["name"] = "Niels"; // add another null object by passing nullptr j["nothing"] = nullptr; // add an object inside the object j["answer"]["everything"] = 42; // add an array that is stored as std::vector (using an initializer list) j["list"] = { 1, 0, 2 }; // add another object (using an initializer list of pairs) j["object"] = { {"currency", "USD"}, {"value", 42.99} }; // instead, you could also write (which looks very similar to the JSON above) json j2 = { {"pi", 3.141}, {"happy", true}, {"name", "Niels"}, {"nothing", nullptr}, { "answer", { {"everything", 42} } }, {"list", {1, 0, 2}}, { "object", { {"currency", "USD"}, {"value", 42.99} } } }; } { // ways to express the empty array [] json empty_array_implicit = {{}}; json empty_array_explicit = json::array(); // a way to express the empty object {} json empty_object_explicit = json::object(); // a way to express an _array_ of key/value pairs [["currency", "USD"], ["value", 42.99]] json array_not_object = { json::array({"currency", "USD"}), json::array({"value", 42.99}) }; } { // create object from string literal json j = "{ \"happy\": true, \"pi\": 3.141 }"_json; // or even nicer (thanks http://isocpp.org/blog/2015/01/json-for-modern-cpp) auto j2 = R"( { "happy": true, "pi": 3.141 } )"_json; // or explicitly auto j3 = json::parse("{ \"happy\": true, \"pi\": 3.141 }"); // explicit conversion to string std::string s = j.dump(); // {\"happy\":true,\"pi\":3.141} // serialization with pretty printing // pass in the amount of spaces to indent std::cout << j.dump(4) << std::endl; // { // "happy": true, // "pi": 3.141 // } std::cout << std::setw(2) << j << std::endl; } { // create an array using push_back json j; j.push_back("foo"); j.push_back(1); j.push_back(true); // iterate the array for (json::iterator it = j.begin(); it != j.end(); ++it) { std::cout << *it << '\n'; } // range-based for for (auto element : j) { std::cout << element << '\n'; } // getter/setter const std::string tmp = j[0]; j[1] = 42; bool foo = j.at(2); // other stuff j.size(); // 3 entries j.empty(); // false j.type(); // json::value_t::array j.clear(); // the array is empty again // comparison j == "[\"foo\", 1, true]"_json; // true // create an object json o; o["foo"] = 23; o["bar"] = false; o["baz"] = 3.141; // find an entry if (o.find("foo") != o.end()) { // there is an entry with key "foo" } } { std::vector c_vector {1, 2, 3, 4}; json j_vec(c_vector); // [1, 2, 3, 4] std::deque c_deque {1.2, 2.3, 3.4, 5.6}; json j_deque(c_deque); // [1.2, 2.3, 3.4, 5.6] std::list c_list {true, true, false, true}; json j_list(c_list); // [true, true, false, true] std::forward_list c_flist {12345678909876, 23456789098765, 34567890987654, 45678909876543}; json j_flist(c_flist); // [12345678909876, 23456789098765, 34567890987654, 45678909876543] std::array c_array {{1, 2, 3, 4}}; json j_array(c_array); // [1, 2, 3, 4] std::set c_set {"one", "two", "three", "four", "one"}; json j_set(c_set); // only one entry for "one" is used // ["four", "one", "three", "two"] std::unordered_set c_uset {"one", "two", "three", "four", "one"}; json j_uset(c_uset); // only one entry for "one" is used // maybe ["two", "three", "four", "one"] std::multiset c_mset {"one", "two", "one", "four"}; json j_mset(c_mset); // only one entry for "one" is used // maybe ["one", "two", "four"] std::unordered_multiset c_umset {"one", "two", "one", "four"}; json j_umset(c_umset); // both entries for "one" are used // maybe ["one", "two", "one", "four"] } { std::map c_map { {"one", 1}, {"two", 2}, {"three", 3} }; json j_map(c_map); // {"one": 1, "two": 2, "three": 3} std::unordered_map c_umap { {"one", 1.2}, {"two", 2.3}, {"three", 3.4} }; json j_umap(c_umap); // {"one": 1.2, "two": 2.3, "three": 3.4} std::multimap c_mmap { {"one", true}, {"two", true}, {"three", false}, {"three", true} }; json j_mmap(c_mmap); // only one entry for key "three" is used // maybe {"one": true, "two": true, "three": true} std::unordered_multimap c_ummap { {"one", true}, {"two", true}, {"three", false}, {"three", true} }; json j_ummap(c_ummap); // only one entry for key "three" is used // maybe {"one": true, "two": true, "three": true} } { /// strings std::string s1 = "Hello, world!"; json js = s1; std::string s2 = js; // Booleans bool b1 = true; json jb = b1; bool b2 = jb; // numbers int i = 42; json jn = i; double f = jn; // etc. std::string vs = js.get(); bool vb = jb.get(); int vi = jn.get(); // etc. } }