#include #include #include static const std::string JSON = "{\"foo\" : {\"bar\" : 2}," " \"goo\" : 1," " \"bool\" : true," " \"string\" : \"a string\"," " \"string_with_null\" : \"a string\\u0000with\\u0000null\"," " \"null\" : null," " \"real\" : 3.1415," " \"vec\" : [1, 2], " " \"string_vec\" : [\"one\", \"two\\u0000null\"], " " \"nested\" : {" " \"foo\" : \"bar\"" " }" "}"; namespace leatherman { namespace json_container { TEST_CASE("JsonContainer::JsonContainer - passing JSON string", "[data]") { std::string json_value {}; SECTION("it should instantiate by passing any JSON value") { SECTION("object") { json_value = JSON; } SECTION("array") { SECTION("of numbers") { json_value = "[1, 2, 3]"; } SECTION("of booleans") { json_value = "[true, true]"; } SECTION("of strings") { json_value = "[\"spam\", \"eggs\", \"foo\"]"; } SECTION("of objects") { json_value = "[" + JSON + ",\n" + JSON + "]"; } SECTION("of arrays") { json_value = "[[1, 2, 3], [\"spam\", \"eggs\", \"foo\"]]"; } SECTION("of values of different types") { json_value = "[1, \"spam\",\n" + JSON + "]"; } } SECTION("std::string instance containing an empty JSON string") { json_value = "\"\""; } SECTION("string") { json_value = "\"foo\""; } SECTION("number - int") { json_value = "42"; } SECTION("number - float") { json_value = "3.14159"; } SECTION("boolean - true") { json_value = "true"; } SECTION("boolean - false") { json_value = "false"; } SECTION("null") { json_value = "null"; } REQUIRE_NOTHROW(JsonContainer { json_value }); } SECTION("it should throw a data_parse_error in case of empty string") { json_value = ""; REQUIRE_THROWS_AS(JsonContainer { json_value }, data_parse_error); } SECTION("it should throw a data_parse_error in case of invalid JSON") { SECTION("bad object") { json_value = "{\"foo\" : \"bar\", 42}"; } SECTION("bad key") { json_value = "{42 : \"bar\"}"; } SECTION("bad array") { json_value = "1, 2, 3"; } REQUIRE_THROWS_AS(JsonContainer { json_value }, data_parse_error); } } TEST_CASE("JsonContainer::get for object entries", "[data]") { JsonContainer data { JSON }; SECTION("it can get a root value") { REQUIRE(data.get("goo") == 1); } SECTION("it can get a nested value") { REQUIRE(data.get({"foo", "bar"}) == 2); } SECTION("it can get a bool value") { REQUIRE(data.get("bool") == true); } SECTION("it can get a string value") { REQUIRE(data.get("string") == "a string"); } SECTION("it can get a string value containing null character(s)") { REQUIRE(data.get("string_with_null") == std::string("a string\0with\0null", 18)); } SECTION("it can get a double value") { REQUIRE(data.get("real") == 3.1415); } SECTION("it can get a vector") { std::vector tmp { 1, 2 }; std::vector result { data.get>("vec") }; REQUIRE(tmp.size() == result.size()); REQUIRE(tmp[0] == result[0]); REQUIRE(tmp[1] == result[1]); } SECTION("it can get a string vector") { std::vector tmp { "one", { "two\0null", 8 } }; std::vector result { data.get>("string_vec") }; REQUIRE(tmp.size() == result.size()); REQUIRE(tmp[0] == result[0]); REQUIRE(tmp[1] == result[1]); } SECTION("it can get the root object") { REQUIRE(data.get().get("goo") == 1); } SECTION("it should behave correctly given a null value") { REQUIRE(data.get("null") == ""); REQUIRE(data.get("null") == 0); REQUIRE(data.get("null") == false); } SECTION("it can get the root entry") { SECTION("array of numbers") { JsonContainer data_array { "[1, 2, 3]" }; auto array = data_array.get>(); std::vector expected_array { 1, 2, 3 }; REQUIRE(array == expected_array); } SECTION("object") { auto object = data.get(); REQUIRE(object.get("goo") == 1); } SECTION("number") { JsonContainer data_number { "42" }; auto number = data_number.get(); REQUIRE(number == 42); } } SECTION("it throws a data_key_error in case of unknown object entry") { SECTION("unknown root object entry") { REQUIRE_THROWS_AS(data.get("unknown"), data_key_error); } SECTION("unknown nested object entry") { REQUIRE_THROWS_AS(data.get({ "nested", "unknown" }), data_key_error); } } SECTION("it throws a data_type_error in case of mismatch") { SECTION("root entry") { SECTION("not a boolean") { REQUIRE_THROWS_AS(data.get("string"), data_type_error); } SECTION("not an integer") { REQUIRE_THROWS_AS(data.get("real"), data_type_error); } SECTION("not a double") { REQUIRE_THROWS_AS(data.get("goo"), data_type_error); } SECTION("not a string") { REQUIRE_THROWS_AS(data.get("real"), data_type_error); } SECTION("array mismatches") { SECTION("not an array") { REQUIRE_THROWS_AS(data.get>("goo"), data_type_error); } SECTION("mismatch type on array entry") { REQUIRE_THROWS_AS(data.get("goo"), data_type_error); } } } SECTION("nested entry") { data.set({ "foo", "spam" }, JsonContainer { JSON }); SECTION("not a boolean") { REQUIRE_THROWS_AS(data.get({ "foo", "spam", "string" }), data_type_error); } SECTION("not an integer") { REQUIRE_THROWS_AS(data.get({ "foo", "spam", "real" }), data_type_error); } SECTION("not a double") { REQUIRE_THROWS_AS(data.get({ "foo", "spam", "goo" }), data_type_error); } SECTION("not a string") { REQUIRE_THROWS_AS(data.get({ "foo", "spam", "real" }), data_type_error); } SECTION("array mismatches") { SECTION("not an array") { REQUIRE_THROWS_AS( data.get>({ "foo", "spam", "goo" }), data_type_error); } SECTION("mismatch type on array entry") { REQUIRE_THROWS_AS(data.get({ "foo", "spam", "goo" }), data_type_error); } } } } SECTION("it can always return a JsonContainer instance of an entry") { SECTION("scalars") { SECTION("boolean") { REQUIRE(data.get("bool").get() == true); } SECTION("integer") { REQUIRE(data.get("goo").get() == 1); } SECTION("double") { REQUIRE(data.get("real").get() == 3.1415); } SECTION("string") { REQUIRE(data.get("string").get() == "a string"); } } SECTION("object") { REQUIRE(data.get("nested").get("foo") == "bar"); } SECTION("array") { std::vector expected_array {1, 2}; REQUIRE(data.get("vec").get>() == expected_array); } } SECTION("it can access array entries") { SECTION("it throws a data_type_error in case of type mismatch") { SECTION("root entry") { JsonContainer a { "[1, 2, 3]" }; REQUIRE_THROWS_AS(a.get(1), data_type_error); } SECTION("object entry") { REQUIRE_THROWS_AS(data.get("vec", 1), data_type_error); } } SECTION("it throws a data_index_error in case of index out of bounds") { SECTION("root entry") { JsonContainer a { "[1, 2, 3]" }; REQUIRE_THROWS_AS(a.get(10), data_index_error); } SECTION("object entry") { REQUIRE_THROWS_AS(data.get("vec", 10), data_index_error); } } SECTION("it can get a value") { SECTION("boolean") { JsonContainer b { "[false, false, true, false]" }; REQUIRE_FALSE(b.get(3)); } SECTION("integer") { JsonContainer i { "[1, 2, 3]" }; REQUIRE(i.get(1) == 2); } SECTION("double") { JsonContainer d { "[3.14, 2.718]" }; REQUIRE(d.get(1) == 2.718); } SECTION("string") { JsonContainer s { "[\"one\", \"two\"]" }; REQUIRE(s.get(1) == "two"); } SECTION("object") { JsonContainer o { "[ {\"spam\":\"eggs\"}, {\"foo\":\"bar\"} ]" }; auto retrieved_o = o.get(0); REQUIRE(retrieved_o.size() == 1u); REQUIRE(retrieved_o.get("spam") == "eggs"); } SECTION("array") { JsonContainer a { "[ [1, 2], [false, true], [\"ab\", \"cd\"] ]" }; std::vector e_a { false, true }; REQUIRE(a.get>(1) == e_a); } } SECTION("array with values of different types") { JsonContainer a { "[ 1, \"foo\", true, [2.718, 3.14], 42, 42.0, " "{\"spam\":\"eggs\"} ]" }; SECTION("boolean") { REQUIRE(a.get(2)); } SECTION("integer") { REQUIRE(a.get(0) == 1); } SECTION("double") { REQUIRE(a.get(5) == 42.0); } SECTION("string") { REQUIRE(a.get(1) == "foo"); } SECTION("object") { auto retrieved_o = a.get(6); REQUIRE(retrieved_o.size() == 1u); REQUIRE(retrieved_o.get("spam") == "eggs"); } SECTION("array") { std::vector expected_array { 2.718, 3.14 }; REQUIRE(a.get>(3) == expected_array); } } } } TEST_CASE("JsonContainer::getWithDefault", "[data]") { JsonContainer data { JSON }; JsonContainer data_a { "[1, 2, 3]" }; std::vector ints { 1, 2, 3 }; std::vector doubles { 1.0, 2.0, 3.0 }; std::vector bools { false, true, false }; std::vector strings { "foo", "bar", "baz" }; SECTION("it can provide a default value if a root entry key is not found") { REQUIRE(data.getWithDefault("dne", 42) == 42); REQUIRE(data.getWithDefault("dne", 42.0) == 42.0); REQUIRE(data.getWithDefault("dne", true) == true); REQUIRE(data.getWithDefault("dne", "foo") == "foo"); REQUIRE(data.getWithDefault>("dne", ints) == ints); REQUIRE(data.getWithDefault>("dne", doubles) == doubles); REQUIRE(data.getWithDefault>("dne", bools) == bools); REQUIRE(data.getWithDefault>("dne", strings) == strings); } SECTION("throw a data_type_error if the root entry is not an object") { REQUIRE_THROWS_AS(data_a.getWithDefault("foo", 42), data_type_error); } SECTION("it can provide a default value if a nested key is not found") { JsonContainer lv_2 {}; lv_2.set("entry_3", data); JsonContainer lv_1 {}; lv_1.set("entry_2", lv_2); std::vector missing_entry { "entry_2", "entry_3", "dne" }; REQUIRE(lv_1.getWithDefault(missing_entry, 42) == 42); REQUIRE(lv_1.getWithDefault(missing_entry, 42.0) == 42.0); REQUIRE(lv_1.getWithDefault(missing_entry, true) == true); REQUIRE(lv_1.getWithDefault(missing_entry, "foo") == "foo"); REQUIRE(lv_1.getWithDefault>(missing_entry, ints) == ints); REQUIRE(lv_1.getWithDefault>(missing_entry, doubles) == doubles); REQUIRE(lv_1.getWithDefault>(missing_entry, bools) == bools); REQUIRE(lv_1.getWithDefault>(missing_entry, strings) == strings); } SECTION("throw a data_type_error if the parent of a nested entry is not an object") { JsonContainer more_data_a {}; more_data_a.set>("ints_entry", ints); REQUIRE_THROWS_AS(more_data_a.getWithDefault({ "ints_entry", "foo" }, 42), data_type_error); } } TEST_CASE("JsonContainer::toString", "[data]") { SECTION("root entry") { SECTION("object") { JsonContainer o {}; o.set("spam", "eggs"); REQUIRE(o.toString() == "{\"spam\":\"eggs\"}"); } SECTION("array") { JsonContainer a { "[1, 2, 3]" }; REQUIRE(a.toString() == "[1,2,3]"); } SECTION("multi type array") { JsonContainer mt_a { "[1, false, \"s\"]" }; REQUIRE(mt_a.toString() == "[1,false,\"s\"]"); } SECTION("scalar") { JsonContainer s { "42" }; REQUIRE(s.toString() == "42"); } } JsonContainer data { JSON }; SECTION("root object entry") { REQUIRE(data.toString("goo") == "1"); } SECTION("nested object entry") { REQUIRE(data.toString({ "nested", "foo" }) == "\"bar\""); } } TEST_CASE("JsonContainer::toPrettyString", "[data]") { SECTION("does not throw when the root is") { SECTION("a string") { JsonContainer data_s { "\"some text\"" }; REQUIRE_NOTHROW(data_s.toPrettyString()); } SECTION("an array") { JsonContainer data_a { "[1, 2, 3]" }; REQUIRE_NOTHROW(data_a.toPrettyString()); } SECTION("an object") { JsonContainer data_o { JSON }; REQUIRE_NOTHROW(data_o.toPrettyString()); } SECTION("an object containing nested objects with an array") { JsonContainer data_ooa {}; JsonContainer tmp {}; tmp.set>("bar", { 1, 2, 3 }); JsonContainer tmp_two {}; tmp_two.set("spam", tmp); tmp_two.set>("beans", { 55, 56, 57 }); JsonContainer tmp_three {}; tmp_three.set("eggs", tmp_two); data_ooa.set("foo", tmp_three); REQUIRE_NOTHROW(data_ooa.toPrettyString()); } } } TEST_CASE("JsonContainer::empty", "[data]") { SECTION("works correctly for an empty JsonContainer instance") { JsonContainer data {}; REQUIRE(data.empty()); } SECTION("works correctly if the root is an empty array") { JsonContainer data { "[]" }; REQUIRE(data.empty()); } SECTION("works correctly for an non-empty JsonContainer instance") { JsonContainer data {}; data.set("spam", 1); REQUIRE_FALSE(data.empty()); } SECTION("works correctly if the root is an non-empty array") { JsonContainer data { "[1, 2, 3]" }; REQUIRE_FALSE(data.empty()); } } TEST_CASE("JsonContainer::size", "[data]") { SECTION("works correctly on the root (no key argument)") { SECTION("empty object") { JsonContainer data {}; REQUIRE(data.size() == 0u); } SECTION("the root is an empty array") { JsonContainer data { "[]" }; REQUIRE(data.size() == 0u); } SECTION("non-empty singleton object") { JsonContainer data {}; data.set("spam", 1); REQUIRE(data.size() == 1u); } SECTION("non-empty multi element object") { JsonContainer bigger_data { JSON }; REQUIRE(bigger_data.size() == 10u); } SECTION("non-empty array") { JsonContainer data { "[1, 2, 3]" }; REQUIRE(data.size() == 3u); } } JsonContainer data { JSON }; SECTION("works correctly on an object entry") { SECTION("entry is a scalar") { REQUIRE(data.size("goo") == 0u); } SECTION("entry is an object") { REQUIRE(data.size("foo") == 1u); } SECTION("entry is an array") { REQUIRE(data.size("vec") == 2u); } } SECTION("works correctly on a nested entry") { data.set({ "foo", "spam" }, JsonContainer { JSON }); SECTION("entry is a scalar") { REQUIRE(data.size({ "foo", "spam", "goo" }) == 0u); } SECTION("entry is an object") { REQUIRE(data.size({ "foo", "spam", "nested" }) == 1u); } SECTION("entry is an array") { REQUIRE(data.size({ "foo", "spam", "vec" }) == 2u); } } } TEST_CASE("JsonContainer::includes", "[data]") { SECTION("does not throw for an empty JsonContainer instance") { JsonContainer data {}; REQUIRE_FALSE(data.includes("foo")); } SECTION("it should not throw if the root is not a JSON object") { JsonContainer data { "[1, 2, 3]" }; REQUIRE_FALSE(data.includes("foo")); } SECTION("Document/object lookups") { JsonContainer msg { JSON }; REQUIRE(msg.includes("foo") == true); REQUIRE(msg.includes({ "foo", "bar" }) == true); REQUIRE(msg.includes({ "foo", "baz" }) == false); } SECTION("Non object/document lookups") { JsonContainer msg { "\"foo\"" }; REQUIRE(msg.includes({ "bar", "bar" }) == false); REQUIRE(msg.includes("foo") == false); } } TEST_CASE("JsonContainer::set", "[data]") { JsonContainer msg {}; SECTION("it should add a new pair to the root") { msg.set("foo", 4); REQUIRE(msg.get("foo") == 4); } SECTION("it allows the creation of a nested structure") { msg.set({"level1", "level21"}, 0); msg.set("bool1", true); msg.set({"level1", "level22"}, "a string"); msg.set("level11", "different string"); REQUIRE(msg.get({ "level1", "level21" }) == 0); REQUIRE(msg.get("bool1") == true); REQUIRE(msg.get({"level1", "level22"}) == "a string"); REQUIRE(msg.get("level11") == "different string"); } SECTION("it allows resetting an integer value") { msg.set("i entry", 0); REQUIRE(msg.includes("i entry")); REQUIRE(msg.get("i entry") == 0); msg.set("i entry", 5); REQUIRE(msg.get("i entry") == 5); } SECTION("it allows resetting a double value") { msg.set("d entry", 3.14159); REQUIRE(msg.includes("d entry")); REQUIRE(msg.get("d entry") == 3.14159); msg.set("d entry", 2.71828); REQUIRE(msg.get("d entry") == 2.71828); } SECTION("it allows resetting a boolean value") { msg.set("b entry", true); REQUIRE(msg.includes("b entry")); REQUIRE(msg.get("b entry") == true); msg.set("b entry", false); REQUIRE(msg.get("b entry") == false); } SECTION("it allows resetting a string value") { msg.set("s entry", "bar"); REQUIRE(msg.includes("s entry")); REQUIRE(msg.get("s entry") == "bar"); msg.set("s entry", "spam"); REQUIRE(msg.get("s entry") == "spam"); } SECTION("it allows resetting a string vector value") { std::vector s_v { "foo", "bar" }; msg.set>("s_v entry", s_v); REQUIRE(msg.includes("s_v entry")); REQUIRE(msg.get>("s_v entry") == s_v); std::vector s_v_other { "spam", "eggs" }; msg.set>("s_v entry", s_v_other); REQUIRE(msg.get>("s_v entry") == s_v_other); } SECTION("it allows resetting a JsonContainer value") { JsonContainer d {}; d.set("i", 1); msg.set("d_c entry", d); auto i_entry = msg.get("d_c entry"); // Expecting msg = { "d_c entry" : {"i" : 1} } REQUIRE(msg.includes("d_c entry")); REQUIRE(i_entry.get("i") == 1); JsonContainer d_other {}; d_other.set("b", true); msg.set("d_c entry", d_other); auto b_entry = msg.get("d_c entry"); // Expecting msg = { "d_c entry" : {"b" : true} } REQUIRE(b_entry.get("b")); } SECTION("it can set a key to a vector") { std::vector strings { "foo", "bar" }; msg.set>("sv", strings); std::vector ints { 4, 2 }; msg.set>("iv", ints); std::vector bools { true, false }; msg.set>("bv", bools); std::vector doubles { 0.00, 9.99 }; msg.set>("dv", doubles); REQUIRE(msg.get>("sv")[0] == "foo"); REQUIRE(msg.get>("sv")[1] == "bar"); REQUIRE(msg.get>("iv")[0] == 4); REQUIRE(msg.get>("iv")[1] == 2); REQUIRE(msg.get>("bv")[0] == true); REQUIRE(msg.get>("bv")[1] == false); REQUIRE(msg.get>("dv")[0] == 0.00); REQUIRE(msg.get>("dv")[1] == 9.99); } SECTION("it should throw a data_key_error in case root is not an object") { std::string json_array { "[1, 2, 3]" }; JsonContainer data_array { json_array }; REQUIRE_THROWS_AS(data_array.set("foo", "bar"), data_key_error); } SECTION("it should throw a data_key_error in case a known inner key is not " "associated with a JSON object") { JsonContainer d_c { JSON }; REQUIRE_THROWS_AS(d_c.set({ "vec", "foo" }, "bar"), data_key_error); } } TEST_CASE("JsonContainer::keys", "[data]") { SECTION("It returns a vector of keys") { JsonContainer data { "{ \"a\" : 1, " " \"b\" : 2, " " \"c\\u0000null\" : 2}" }; std::vector expected_keys { "a", "b", { "c\0null", 6 } }; REQUIRE(data.keys() == expected_keys); } SECTION("It returns an empty vector when the JsonContainer is empty") { JsonContainer data {}; REQUIRE(data.keys().size() == 0u); } SECTION("It returns an empty vector when the JsonContainer is an array") { JsonContainer data_array { "[1, 2, 3]" }; REQUIRE(data_array.keys().size() == 0u); } } TEST_CASE("JsonContainer::type", "[data]") { JsonContainer data {}; SECTION("When no key is passed it retrieves the type of the root value") { SECTION("array") { JsonContainer data_array { "[1, 2, 3]" }; REQUIRE(data_array.type() == DataType::Array); } SECTION("object") { data.set("b_entry", false); REQUIRE(data.type() == DataType::Object); } SECTION("integer") { JsonContainer data_number { "42" }; REQUIRE(data_number.type() == DataType::Int); } } SECTION("When a single key is passed") { SECTION("it throws a data_key_error if the key is unknown") { REQUIRE_THROWS_AS(data.type("foo"), data_key_error); } SECTION("it can distinguish a Bool (false) value") { data.set("b_entry", false); REQUIRE(data.type("b_entry") == DataType::Bool); } SECTION("it can distinguish a Bool (true) value") { data.set("b_entry", true); REQUIRE(data.type("b_entry") == DataType::Bool); } SECTION("it can distinguish an Object (JsonContainer) value") { JsonContainer tmp {}; tmp.set("eggs", "spam"); data.set("obj_entry", tmp); REQUIRE(data.type("obj_entry") == DataType::Object); } SECTION("it can distinguish an Array value") { std::vector tmp { "one", "two", "three" }; data.set>("array_entry", tmp); REQUIRE(data.type("array_entry") == DataType::Array); } SECTION("it can distinguish a String value") { data.set("eggs", "spam"); REQUIRE(data.type("eggs") == DataType::String); } SECTION("it can distinguish an Int value") { data.set("int_entry", 42); REQUIRE(data.type("int_entry") == DataType::Int); } SECTION("it can distinguish a Double value") { SECTION("defined by set") { data.set("d_entry", 2.71828); REQUIRE(data.type("d_entry") == DataType::Double); } SECTION("defined by JSON string given to the ctor") { JsonContainer data_number { "2.71828" }; REQUIRE(data_number.type() == DataType::Double); } } SECTION("it can distinguish a null value") { JsonContainer data_with_null { "{\"the_null\" : null}" }; REQUIRE(data_with_null.type("the_null") == DataType::Null); } } SECTION("When multiple keys are passed") { JsonContainer tmp {}; data.set("stuff", tmp); SECTION("it throws a data_key_error if a key is unknown") { REQUIRE_THROWS_AS(data.type({ "stuff", "bar" }), data_key_error); } SECTION("it can distinguish a Bool (false) value") { data.set({ "stuff", "b_entry" }, false); REQUIRE(data.type({ "stuff", "b_entry" }) == DataType::Bool); } SECTION("it can distinguish a Bool (true) value") { data.set({ "stuff", "b_entry" }, true); REQUIRE(data.type({ "stuff", "b_entry" }) == DataType::Bool); } SECTION("it can distinguish an Object (JsonContainer) value") { JsonContainer tmp {}; tmp.set("eggs", "spam"); data.set({ "stuff", "obj_entry" }, tmp); REQUIRE(data.type({ "stuff", "obj_entry" }) == DataType::Object); } SECTION("it can distinguish an Array value") { std::vector tmp { "one", "two", "three" }; data.set>({ "stuff", "array_entry" }, tmp); REQUIRE(data.type({ "stuff", "array_entry" }) == DataType::Array); } SECTION("it can distinguish a String value") { data.set({ "stuff", "eggs" }, "spam"); REQUIRE(data.type({ "stuff", "eggs" }) == DataType::String); } SECTION("it can distinguish an Int value") { data.set({ "stuff", "int_entry" }, 42); REQUIRE(data.type({ "stuff", "int_entry" }) == DataType::Int); } SECTION("it can distinguish a Double value") { data.set({ "stuff", "d_entry" }, 2.71828); REQUIRE(data.type({ "stuff", "d_entry" }) == DataType::Double); } SECTION("it can distinguish a null value") { JsonContainer data_with_null { "{\"the_null\" : null}" }; data.set({ "stuff", "more_stuff" }, data_with_null); auto data_type = data.type({ "stuff", "more_stuff", "the_null" }); REQUIRE(data_type == DataType::Null); } } } TEST_CASE("JsonContainer::type for arrays entries", "[data]") { JsonContainer data { "[false, -42, 3.14, \"spam\", {\"foo\" : [3, true]}, " "[1, 2, 3, 4] ]" }; SECTION("root entry") { SECTION("array") { JsonContainer not_an_aray { JSON }; REQUIRE_THROWS_AS(not_an_aray.type(1), data_type_error); } SECTION("array with values of different types") { JsonContainer data_array { "[1, \"spam\", false]" }; REQUIRE(data_array.type() == DataType::Array); } SECTION("boolean") { REQUIRE(data.type(0) == DataType::Bool); } SECTION("integer") { REQUIRE(data.type(1) == DataType::Int); } SECTION("double") { REQUIRE(data.type(2) == DataType::Double); } SECTION("string") { REQUIRE(data.type(3) == DataType::String); } SECTION("object") { REQUIRE(data.type(4) == DataType::Object); } SECTION("array") { REQUIRE(data.type(5) == DataType::Array); } } SECTION("object entry") { JsonContainer o { JSON }; o.set("multi type array", data); SECTION("container") { REQUIRE(o.type("multi type array") == DataType::Array); } SECTION("double") { REQUIRE(o.type("multi type array", 2) == DataType::Double); } SECTION("string") { REQUIRE(o.type("multi type array", 3) == DataType::String); } } SECTION("nested entry") { JsonContainer o { JSON }; o.set({ "nested", "multi type array" }, data); SECTION("container") { REQUIRE(o.type({ "nested", "multi type array" }) == DataType::Array); } SECTION("double") { REQUIRE(o.type({ "nested", "multi type array" }, 2) == DataType::Double); } SECTION("string") { REQUIRE(o.type({ "nested", "multi type array" }, 3) == DataType::String); } } } }} // namespace leatherman::json_container