| // __ _____ _____ _____ |
| // __| | __| | | | JSON for Modern C++ (supporting code) |
| // | | |__ | | | | | | version 3.11.3 |
| // |_____|_____|_____|_|___| https://github.com/nlohmann/json |
| // |
| // Copyright (c) 2013-2022 Niels Lohmann <http://nlohmann.me>. |
| // SPDX-FileCopyrightText: 2013-2023 Niels Lohmann <https://nlohmann.me> |
| // SPDX-License-Identifier: MIT |
| |
| #include "doctest_compatibility.h" |
| |
| #include <nlohmann/json.hpp> |
| using nlohmann::json; |
| |
| TEST_CASE("modifiers") |
| { |
| SECTION("clear()") |
| { |
| SECTION("boolean") |
| { |
| json j = true; |
| json const k = j; |
| |
| j.clear(); |
| CHECK(j == json(json::value_t::boolean)); |
| CHECK(j == json(k.type())); |
| } |
| |
| SECTION("string") |
| { |
| json j = "hello world"; |
| json const k = j; |
| |
| j.clear(); |
| CHECK(j == json(json::value_t::string)); |
| CHECK(j == json(k.type())); |
| } |
| |
| SECTION("array") |
| { |
| SECTION("empty array") |
| { |
| json j = json::array(); |
| json const k = j; |
| |
| j.clear(); |
| CHECK(j.empty()); |
| CHECK(j == json(json::value_t::array)); |
| CHECK(j == json(k.type())); |
| } |
| |
| SECTION("filled array") |
| { |
| json j = { 1, 2, 3 }; |
| json const k = j; |
| |
| j.clear(); |
| CHECK(j.empty()); |
| CHECK(j == json(json::value_t::array)); |
| CHECK(j == json(k.type())); |
| } |
| } |
| |
| SECTION("object") |
| { |
| SECTION("empty object") |
| { |
| json j = json::object(); |
| json const k = j; |
| |
| j.clear(); |
| CHECK(j.empty()); |
| CHECK(j == json(json::value_t::object)); |
| CHECK(j == json(k.type())); |
| } |
| |
| SECTION("filled object") |
| { |
| json j = { { "one", 1 }, { "two", 2 }, { "three", 3 } }; |
| json const k = j; |
| |
| j.clear(); |
| CHECK(j.empty()); |
| CHECK(j == json(json::value_t::object)); |
| CHECK(j == json(k.type())); |
| } |
| } |
| |
| SECTION("binary") |
| { |
| SECTION("empty binary") |
| { |
| json j = json::binary({}); |
| json const k = j; |
| |
| j.clear(); |
| CHECK(!j.empty()); |
| CHECK(j == json(json::value_t::binary)); |
| CHECK(j == json(k.type())); |
| } |
| |
| SECTION("filled binary") |
| { |
| json j = json::binary({ 1, 2, 3, 4, 5 }); |
| json const k = j; |
| |
| j.clear(); |
| CHECK(!j.empty()); |
| CHECK(j == json(json::value_t::binary)); |
| CHECK(j == json(k.type())); |
| } |
| } |
| |
| SECTION("number (integer)") |
| { |
| json j = 23; |
| json const k = j; |
| |
| j.clear(); |
| CHECK(j == json(json::value_t::number_integer)); |
| CHECK(j == json(k.type())); |
| } |
| |
| SECTION("number (unsigned)") |
| { |
| json j = 23u; |
| json const k = j; |
| |
| j.clear(); |
| CHECK(j == json(json::value_t::number_integer)); |
| CHECK(j == json(k.type())); |
| } |
| |
| SECTION("number (float)") |
| { |
| json j = 23.42; |
| json const k = j; |
| |
| j.clear(); |
| CHECK(j == json(json::value_t::number_float)); |
| CHECK(j == json(k.type())); |
| } |
| |
| SECTION("null") |
| { |
| json j = nullptr; |
| json const k = j; |
| |
| j.clear(); |
| CHECK(j == json(json::value_t::null)); |
| CHECK(j == json(k.type())); |
| } |
| } |
| |
| 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_WITH_AS(j.push_back("Hello"), "[json.exception.type_error.308] cannot use push_back() with number", json::type_error&); |
| } |
| } |
| |
| SECTION("const json&") |
| { |
| SECTION("null") |
| { |
| json j; |
| json const 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 const 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 const k("Hello"); |
| CHECK_THROWS_WITH_AS(j.push_back(k), "[json.exception.type_error.308] cannot use push_back() with number", json::type_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 const k("Hello"); |
| CHECK_THROWS_WITH_AS(j.push_back(json::object_t::value_type({ "one", 1 })), |
| "[json.exception.type_error.308] cannot use push_back() with number", |
| json::type_error&); |
| } |
| } |
| |
| SECTION("with initializer_list") |
| { |
| SECTION("null") |
| { |
| json j; |
| j.push_back({ "foo", "bar" }); |
| CHECK(j == json::array({ { "foo", "bar" } })); |
| |
| json k; |
| k.push_back({ 1, 2, 3 }); |
| CHECK(k == json::array({ { 1, 2, 3 } })); |
| } |
| |
| SECTION("array") |
| { |
| json j = { 1, 2, 3 }; |
| j.push_back({ "foo", "bar" }); |
| CHECK(j == json({ 1, 2, 3, { "foo", "bar" } })); |
| |
| json k = { 1, 2, 3 }; |
| k.push_back({ 1, 2, 3 }); |
| CHECK(k == json({ 1, 2, 3, { 1, 2, 3 } })); |
| } |
| |
| SECTION("object") |
| { |
| json j = { { "key1", 1 } }; |
| j.push_back({ "key2", "bar" }); |
| CHECK(j == json({ { "key1", 1 }, { "key2", "bar" } })); |
| |
| // invalid values (no string/val pair) |
| CHECK_THROWS_WITH_AS(j.push_back({ 1 }), "[json.exception.type_error.308] cannot use push_back() with object", json::type_error&); |
| CHECK_THROWS_WITH_AS(j.push_back({ 1, 2 }), "[json.exception.type_error.308] cannot use push_back() with object", json::type_error&); |
| CHECK_THROWS_WITH_AS(j.push_back({ 1, 2, 3, 4 }), "[json.exception.type_error.308] cannot use push_back() with object", json::type_error&); |
| } |
| } |
| } |
| |
| SECTION("emplace_back()") |
| { |
| SECTION("to array") |
| { |
| SECTION("null") |
| { |
| json j; |
| auto& x1 = j.emplace_back(1); |
| CHECK(x1 == 1); |
| auto& x2 = j.emplace_back(2); |
| CHECK(x2 == 2); |
| CHECK(j.type() == json::value_t::array); |
| CHECK(j == json({ 1, 2 })); |
| } |
| |
| SECTION("array") |
| { |
| json j = { 1, 2, 3 }; |
| auto& x = j.emplace_back("Hello"); |
| CHECK(x == "Hello"); |
| CHECK(j.type() == json::value_t::array); |
| CHECK(j == json({ 1, 2, 3, "Hello" })); |
| } |
| |
| SECTION("multiple values") |
| { |
| json j; |
| auto& x = j.emplace_back(3, "foo"); |
| CHECK(x == json({ "foo", "foo", "foo" })); |
| CHECK(j.type() == json::value_t::array); |
| CHECK(j == json({ { "foo", "foo", "foo" } })); |
| } |
| } |
| |
| SECTION("other type") |
| { |
| json j = 1; |
| CHECK_THROWS_WITH_AS(j.emplace_back("Hello"), "[json.exception.type_error.311] cannot use emplace_back() with number", json::type_error&); |
| } |
| } |
| |
| SECTION("emplace()") |
| { |
| SECTION("to object") |
| { |
| SECTION("null") |
| { |
| // start with a null value |
| json j; |
| |
| // add a new key |
| auto res1 = j.emplace("foo", "bar"); |
| CHECK(res1.second == true); |
| CHECK(*res1.first == "bar"); |
| |
| // the null value is changed to an object |
| CHECK(j.type() == json::value_t::object); |
| |
| // add a new key |
| auto res2 = j.emplace("baz", "bam"); |
| CHECK(res2.second == true); |
| CHECK(*res2.first == "bam"); |
| |
| // we try to insert at given key - no change |
| auto res3 = j.emplace("baz", "bad"); |
| CHECK(res3.second == false); |
| CHECK(*res3.first == "bam"); |
| |
| // the final object |
| CHECK(j == json({ { "baz", "bam" }, { "foo", "bar" } })); |
| } |
| |
| SECTION("object") |
| { |
| // start with an object |
| json j = { { "foo", "bar" } }; |
| |
| // add a new key |
| auto res1 = j.emplace("baz", "bam"); |
| CHECK(res1.second == true); |
| CHECK(*res1.first == "bam"); |
| |
| // add an existing key |
| auto res2 = j.emplace("foo", "bad"); |
| CHECK(res2.second == false); |
| CHECK(*res2.first == "bar"); |
| |
| // check final object |
| CHECK(j == json({ { "baz", "bam" }, { "foo", "bar" } })); |
| } |
| } |
| |
| SECTION("other type") |
| { |
| json j = 1; |
| CHECK_THROWS_WITH_AS(j.emplace("foo", "bar"), "[json.exception.type_error.311] cannot use emplace() with number", json::type_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_WITH_AS(j += "Hello", "[json.exception.type_error.308] cannot use push_back() with number", json::type_error&); |
| } |
| } |
| |
| SECTION("const json&") |
| { |
| SECTION("null") |
| { |
| json j; |
| json const 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 const 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 const k("Hello"); |
| CHECK_THROWS_WITH_AS(j += k, "[json.exception.type_error.308] cannot use push_back() with number", json::type_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 const k("Hello"); |
| CHECK_THROWS_WITH_AS(j += json::object_t::value_type({ "one", 1 }), |
| "[json.exception.type_error.308] cannot use push_back() with number", |
| json::type_error&); |
| } |
| } |
| |
| SECTION("with initializer_list") |
| { |
| SECTION("null") |
| { |
| json j; |
| j += { "foo", "bar" }; |
| CHECK(j == json::array({ { "foo", "bar" } })); |
| |
| json k; |
| k += { 1, 2, 3 }; |
| CHECK(k == json::array({ { 1, 2, 3 } })); |
| } |
| |
| SECTION("array") |
| { |
| json j = { 1, 2, 3 }; |
| j += { "foo", "bar" }; |
| CHECK(j == json({ 1, 2, 3, { "foo", "bar" } })); |
| |
| json k = { 1, 2, 3 }; |
| k += { 1, 2, 3 }; |
| CHECK(k == json({ 1, 2, 3, { 1, 2, 3 } })); |
| } |
| |
| SECTION("object") |
| { |
| json j = { { "key1", 1 } }; |
| j += { "key2", "bar" }; |
| CHECK(j == json({ { "key1", 1 }, { "key2", "bar" } })); |
| |
| json k = { { "key1", 1 } }; |
| CHECK_THROWS_WITH_AS((k += { 1, 2, 3, 4 }), "[json.exception.type_error.308] cannot use push_back() with object", json::type_error&); |
| } |
| } |
| } |
| |
| SECTION("insert()") |
| { |
| json j_array = { 1, 2, 3, 4 }; |
| json j_value = 5; |
| |
| SECTION("value at position") |
| { |
| SECTION("insert before begin()") |
| { |
| auto it = j_array.insert(j_array.begin(), j_value); |
| CHECK(j_array.size() == 5); |
| CHECK(*it == j_value); |
| CHECK(j_array.begin() == it); |
| CHECK(j_array == json({ 5, 1, 2, 3, 4 })); |
| } |
| |
| SECTION("insert in the middle") |
| { |
| auto it = j_array.insert(j_array.begin() + 2, j_value); |
| CHECK(j_array.size() == 5); |
| CHECK(*it == j_value); |
| CHECK((it - j_array.begin()) == 2); |
| CHECK(j_array == json({ 1, 2, 5, 3, 4 })); |
| } |
| |
| SECTION("insert before end()") |
| { |
| auto it = j_array.insert(j_array.end(), j_value); |
| CHECK(j_array.size() == 5); |
| CHECK(*it == j_value); |
| CHECK((j_array.end() - it) == 1); |
| CHECK(j_array == json({ 1, 2, 3, 4, 5 })); |
| } |
| } |
| |
| SECTION("rvalue at position") |
| { |
| SECTION("insert before begin()") |
| { |
| auto it = j_array.insert(j_array.begin(), 5); |
| CHECK(j_array.size() == 5); |
| CHECK(*it == j_value); |
| CHECK(j_array.begin() == it); |
| CHECK(j_array == json({ 5, 1, 2, 3, 4 })); |
| } |
| |
| SECTION("insert in the middle") |
| { |
| auto it = j_array.insert(j_array.begin() + 2, 5); |
| CHECK(j_array.size() == 5); |
| CHECK(*it == j_value); |
| CHECK((it - j_array.begin()) == 2); |
| CHECK(j_array == json({ 1, 2, 5, 3, 4 })); |
| } |
| |
| SECTION("insert before end()") |
| { |
| auto it = j_array.insert(j_array.end(), 5); |
| CHECK(j_array.size() == 5); |
| CHECK(*it == j_value); |
| CHECK((j_array.end() - it) == 1); |
| CHECK(j_array == json({ 1, 2, 3, 4, 5 })); |
| } |
| } |
| |
| SECTION("copies at position") |
| { |
| SECTION("insert before begin()") |
| { |
| auto it = j_array.insert(j_array.begin(), 3, 5); |
| CHECK(j_array.size() == 7); |
| CHECK(*it == j_value); |
| CHECK(j_array.begin() == it); |
| CHECK(j_array == json({ 5, 5, 5, 1, 2, 3, 4 })); |
| } |
| |
| SECTION("insert in the middle") |
| { |
| auto it = j_array.insert(j_array.begin() + 2, 3, 5); |
| CHECK(j_array.size() == 7); |
| CHECK(*it == j_value); |
| CHECK((it - j_array.begin()) == 2); |
| CHECK(j_array == json({ 1, 2, 5, 5, 5, 3, 4 })); |
| } |
| |
| SECTION("insert before end()") |
| { |
| auto it = j_array.insert(j_array.end(), 3, 5); |
| CHECK(j_array.size() == 7); |
| CHECK(*it == j_value); |
| CHECK((j_array.end() - it) == 3); |
| CHECK(j_array == json({ 1, 2, 3, 4, 5, 5, 5 })); |
| } |
| |
| SECTION("insert nothing (count = 0)") |
| { |
| auto it = j_array.insert(j_array.end(), 0, 5); |
| CHECK(j_array.size() == 4); |
| // the returned iterator points to the first inserted element; |
| // there were 4 elements, so it should point to the 5th |
| CHECK(it == j_array.begin() + 4); |
| CHECK(j_array == json({ 1, 2, 3, 4 })); |
| } |
| } |
| |
| SECTION("range for array") |
| { |
| json j_other_array = { "first", "second" }; |
| |
| SECTION("proper usage") |
| { |
| auto it = j_array.insert(j_array.end(), j_other_array.begin(), j_other_array.end()); |
| CHECK(j_array.size() == 6); |
| CHECK(*it == *j_other_array.begin()); |
| CHECK((j_array.end() - it) == 2); |
| CHECK(j_array == json({ 1, 2, 3, 4, "first", "second" })); |
| } |
| |
| SECTION("empty range") |
| { |
| auto it = j_array.insert(j_array.end(), j_other_array.begin(), j_other_array.begin()); |
| CHECK(j_array.size() == 4); |
| CHECK(it == j_array.end()); |
| CHECK(j_array == json({ 1, 2, 3, 4 })); |
| } |
| |
| SECTION("invalid iterators") |
| { |
| json j_other_array2 = { "first", "second" }; |
| |
| CHECK_THROWS_WITH_AS(j_array.insert(j_array.end(), j_array.begin(), j_array.end()), |
| "[json.exception.invalid_iterator.211] passed iterators may not belong to container", |
| json::invalid_iterator&); |
| CHECK_THROWS_WITH_AS(j_array.insert(j_array.end(), j_other_array.begin(), j_other_array2.end()), |
| "[json.exception.invalid_iterator.210] iterators do not fit", |
| json::invalid_iterator&); |
| } |
| } |
| |
| SECTION("range for object") |
| { |
| json j_object1 = { { "one", "eins" }, { "two", "zwei" } }; |
| json j_object2 = { { "eleven", "elf" }, { "seventeen", "siebzehn" } }; |
| |
| SECTION("proper usage") |
| { |
| j_object1.insert(j_object2.begin(), j_object2.end()); |
| CHECK(j_object1.size() == 4); |
| } |
| |
| SECTION("empty range") |
| { |
| j_object1.insert(j_object2.begin(), j_object2.begin()); |
| CHECK(j_object1.size() == 2); |
| } |
| |
| SECTION("invalid iterators") |
| { |
| json const j_other_array2 = { "first", "second" }; |
| |
| CHECK_THROWS_WITH_AS(j_array.insert(j_object2.begin(), j_object2.end()), |
| "[json.exception.type_error.309] cannot use insert() with array", |
| json::type_error&); |
| CHECK_THROWS_WITH_AS(j_object1.insert(j_object1.begin(), j_object2.end()), |
| "[json.exception.invalid_iterator.210] iterators do not fit", |
| json::invalid_iterator&); |
| CHECK_THROWS_WITH_AS(j_object1.insert(j_array.begin(), j_array.end()), |
| "[json.exception.invalid_iterator.202] iterators first and last must point to objects", |
| json::invalid_iterator&); |
| } |
| } |
| |
| SECTION("initializer list at position") |
| { |
| SECTION("insert before begin()") |
| { |
| auto it = j_array.insert(j_array.begin(), { 7, 8, 9 }); |
| CHECK(j_array.size() == 7); |
| CHECK(*it == json(7)); |
| CHECK(j_array.begin() == it); |
| CHECK(j_array == json({ 7, 8, 9, 1, 2, 3, 4 })); |
| } |
| |
| SECTION("insert in the middle") |
| { |
| auto it = j_array.insert(j_array.begin() + 2, { 7, 8, 9 }); |
| CHECK(j_array.size() == 7); |
| CHECK(*it == json(7)); |
| CHECK((it - j_array.begin()) == 2); |
| CHECK(j_array == json({ 1, 2, 7, 8, 9, 3, 4 })); |
| } |
| |
| SECTION("insert before end()") |
| { |
| auto it = j_array.insert(j_array.end(), { 7, 8, 9 }); |
| CHECK(j_array.size() == 7); |
| CHECK(*it == json(7)); |
| CHECK((j_array.end() - it) == 3); |
| CHECK(j_array == json({ 1, 2, 3, 4, 7, 8, 9 })); |
| } |
| } |
| |
| SECTION("invalid iterator") |
| { |
| // pass iterator to a different array |
| json j_another_array = { 1, 2 }; |
| json j_yet_another_array = { "first", "second" }; |
| CHECK_THROWS_WITH_AS(j_array.insert(j_another_array.end(), 10), |
| "[json.exception.invalid_iterator.202] iterator does not fit current value", |
| json::invalid_iterator&); |
| CHECK_THROWS_WITH_AS(j_array.insert(j_another_array.end(), j_value), |
| "[json.exception.invalid_iterator.202] iterator does not fit current value", |
| json::invalid_iterator&); |
| CHECK_THROWS_WITH_AS(j_array.insert(j_another_array.end(), 10, 11), |
| "[json.exception.invalid_iterator.202] iterator does not fit current value", |
| json::invalid_iterator&); |
| CHECK_THROWS_WITH_AS(j_array.insert(j_another_array.end(), j_yet_another_array.begin(), j_yet_another_array.end()), |
| "[json.exception.invalid_iterator.202] iterator does not fit current value", |
| json::invalid_iterator&); |
| CHECK_THROWS_WITH_AS(j_array.insert(j_another_array.end(), { 1, 2, 3, 4 }), |
| "[json.exception.invalid_iterator.202] iterator does not fit current value", |
| json::invalid_iterator&); |
| } |
| |
| SECTION("non-array type") |
| { |
| // call insert on a non-array type |
| json j_nonarray = 3; |
| json j_yet_another_array = { "first", "second" }; |
| CHECK_THROWS_WITH_AS(j_nonarray.insert(j_nonarray.end(), 10), "[json.exception.type_error.309] cannot use insert() with number", json::type_error&); |
| CHECK_THROWS_WITH_AS(j_nonarray.insert(j_nonarray.end(), j_value), |
| "[json.exception.type_error.309] cannot use insert() with number", |
| json::type_error&); |
| CHECK_THROWS_WITH_AS(j_nonarray.insert(j_nonarray.end(), 10, 11), |
| "[json.exception.type_error.309] cannot use insert() with number", |
| json::type_error&); |
| CHECK_THROWS_WITH_AS(j_nonarray.insert(j_nonarray.end(), j_yet_another_array.begin(), j_yet_another_array.end()), |
| "[json.exception.type_error.309] cannot use insert() with number", |
| json::type_error&); |
| CHECK_THROWS_WITH_AS(j_nonarray.insert(j_nonarray.end(), { 1, 2, 3, 4 }), |
| "[json.exception.type_error.309] cannot use insert() with number", |
| json::type_error&); |
| } |
| } |
| |
| SECTION("update()") |
| { |
| SECTION("non-recursive (default)") |
| { |
| json j_object1 = { { "one", "eins" }, { "two", "zwei" } }; |
| json j_object2 = { { "three", "drei" }, { "two", "zwo" } }; |
| json j_array = { 1, 2, 3, 4 }; |
| |
| SECTION("const reference") |
| { |
| SECTION("proper usage") |
| { |
| j_object1.update(j_object2); |
| CHECK(j_object1 == json({ { "one", "eins" }, { "two", "zwo" }, { "three", "drei" } })); |
| |
| json j_null; |
| j_null.update(j_object2); |
| CHECK(j_null == j_object2); |
| } |
| |
| SECTION("wrong types") |
| { |
| CHECK_THROWS_WITH_AS(j_array.update(j_object1), "[json.exception.type_error.312] cannot use update() with array", json::type_error&); |
| |
| CHECK_THROWS_WITH_AS(j_object1.update(j_array), "[json.exception.type_error.312] cannot use update() with array", json::type_error&); |
| } |
| } |
| |
| SECTION("iterator range") |
| { |
| SECTION("proper usage") |
| { |
| j_object1.update(j_object2.begin(), j_object2.end()); |
| CHECK(j_object1 == json({ { "one", "eins" }, { "two", "zwo" }, { "three", "drei" } })); |
| |
| json j_null; |
| j_null.update(j_object2.begin(), j_object2.end()); |
| CHECK(j_null == j_object2); |
| } |
| |
| SECTION("empty range") |
| { |
| j_object1.update(j_object2.begin(), j_object2.begin()); |
| CHECK(j_object1 == json({ { "one", "eins" }, { "two", "zwei" } })); |
| } |
| |
| SECTION("invalid iterators") |
| { |
| json const j_other_array2 = { "first", "second" }; |
| |
| CHECK_THROWS_WITH_AS(j_array.update(j_object2.begin(), j_object2.end()), |
| "[json.exception.type_error.312] cannot use update() with array", |
| json::type_error&); |
| CHECK_THROWS_WITH_AS(j_object1.update(j_object1.begin(), j_object2.end()), |
| "[json.exception.invalid_iterator.210] iterators do not fit", |
| json::invalid_iterator&); |
| CHECK_THROWS_WITH_AS(j_object1.update(j_array.begin(), j_array.end()), |
| "[json.exception.type_error.312] cannot use update() with array", |
| json::type_error&); |
| } |
| } |
| } |
| |
| SECTION("recursive") |
| { |
| SECTION("const reference") |
| { |
| SECTION("extend object") |
| { |
| json j1 = { { "string", "s" }, { "numbers", { { "one", 1 } } } }; |
| json const j2 = { { "string", "t" }, { "numbers", { { "two", 2 } } } }; |
| j1.update(j2, true); |
| CHECK(j1 == json({ { "string", "t" }, { "numbers", { { "one", 1 }, { "two", 2 } } } })); |
| } |
| |
| SECTION("replace object") |
| { |
| json j1 = { { "string", "s" }, { "numbers", { { "one", 1 } } } }; |
| json const j2 = { { "string", "t" }, { "numbers", 1 } }; |
| j1.update(j2, true); |
| CHECK(j1 == json({ { "string", "t" }, { "numbers", 1 } })); |
| } |
| } |
| } |
| } |
| |
| 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); |
| |
| using std::swap; |
| 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_WITH_AS(j.swap(a), "[json.exception.type_error.310] cannot use swap(array_t&) with number", json::type_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_WITH_AS(j.swap(o), "[json.exception.type_error.310] cannot use swap(object_t&) with number", json::type_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_WITH_AS(j.swap(s), "[json.exception.type_error.310] cannot use swap(string_t&) with number", json::type_error&); |
| } |
| } |
| |
| SECTION("binary_t") |
| { |
| SECTION("binary_t type") |
| { |
| json j = json::binary({ 1, 2, 3, 4 }); |
| json::binary_t s = { { 5, 6, 7, 8 } }; |
| |
| j.swap(s); |
| |
| CHECK(j == json::binary({ 5, 6, 7, 8 })); |
| |
| j.swap(s); |
| |
| CHECK(j == json::binary({ 1, 2, 3, 4 })); |
| } |
| |
| SECTION("binary_t::container_type type") |
| { |
| json j = json::binary({ 1, 2, 3, 4 }); |
| std::vector<std::uint8_t> s = { { 5, 6, 7, 8 } }; |
| |
| j.swap(s); |
| |
| CHECK(j == json::binary({ 5, 6, 7, 8 })); |
| |
| j.swap(s); |
| |
| CHECK(j == json::binary({ 1, 2, 3, 4 })); |
| } |
| |
| SECTION("non-binary_t type") |
| { |
| json j = 17; |
| json::binary_t s1 = { { 1, 2, 3, 4 } }; |
| std::vector<std::uint8_t> s2 = { { 5, 6, 7, 8 } }; |
| |
| CHECK_THROWS_WITH_AS(j.swap(s1), "[json.exception.type_error.310] cannot use swap(binary_t&) with number", json::type_error); |
| CHECK_THROWS_WITH_AS(j.swap(s2), "[json.exception.type_error.310] cannot use swap(binary_t::container_type&) with number", json::type_error); |
| } |
| } |
| } |
| } |