// __ _____ _____ _____ // __| | __| | | | JSON for Modern C++ (supporting code) // | | |__ | | | | | | version 3.12.0 // |_____|_____|_____|_|___| https://github.com/nlohmann/json // // SPDX-FileCopyrightText: 2013-2026 Niels Lohmann // SPDX-License-Identifier: MIT #include "doctest_compatibility.h" #include #include #include using nlohmann::json; TEST_CASE("other constructors and destructor") { SECTION("copy constructor") { SECTION("object") { const json j {{"foo", 1}, {"bar", false}}; json k(j); // NOLINT(performance-unnecessary-copy-initialization) CHECK(j == k); } SECTION("array") { const json j {"foo", 1, 42.23, false}; json k(j); // NOLINT(performance-unnecessary-copy-initialization) CHECK(j == k); } SECTION("null") { const json j(nullptr); json k(j); // NOLINT(performance-unnecessary-copy-initialization) CHECK(j == k); } SECTION("boolean") { const json j(true); json k(j); // NOLINT(performance-unnecessary-copy-initialization) CHECK(j == k); } SECTION("string") { const json j("Hello world"); json k(j); // NOLINT(performance-unnecessary-copy-initialization) CHECK(j == k); } SECTION("number (integer)") { const json j(42); json k(j); // NOLINT(performance-unnecessary-copy-initialization) CHECK(j == k); } SECTION("number (unsigned)") { const json j(42u); json k(j); // NOLINT(performance-unnecessary-copy-initialization) CHECK(j == k); } SECTION("number (floating-point)") { const json j(42.23); json k(j); // NOLINT(performance-unnecessary-copy-initialization) CHECK(j == k); } SECTION("binary") { const json j = json::binary({1, 2, 3}); json k(j); // NOLINT(performance-unnecessary-copy-initialization) CHECK(j == k); } } SECTION("move constructor") { json j {{"foo", "bar"}, {"baz", {1, 2, 3, 4}}, {"a", 42u}, {"b", 42.23}, {"c", nullptr}}; CHECK(j.type() == json::value_t::object); const json k(std::move(j)); CHECK(k.type() == json::value_t::object); CHECK(j.type() == json::value_t::null); // NOLINT(bugprone-use-after-move,hicpp-invalid-access-moved,clang-analyzer-cplusplus.Move) access after move is OK here } SECTION("copy assignment") { SECTION("object") { const json j {{"foo", 1}, {"bar", false}}; json k; k = j; CHECK(j == k); } SECTION("array") { const json j {"foo", 1, 42.23, false}; json k; k = j; CHECK(j == k); } SECTION("null") { const json j(nullptr); json k; k = j; CHECK(j == k); } SECTION("boolean") { const json j(true); json k; k = j; CHECK(j == k); } SECTION("string") { const json j("Hello world"); json k; k = j; CHECK(j == k); } SECTION("number (integer)") { const json j(42); json k; k = j; CHECK(j == k); } SECTION("number (unsigned)") { const json j(42u); json k; k = j; CHECK(j == k); } SECTION("number (floating-point)") { const json j(42.23); json k; k = j; CHECK(j == k); } SECTION("binary") { const json j = json::binary({1, 2, 3}); json k; k = j; CHECK(j == k); } } SECTION("destructor") { SECTION("object") { auto* j = new json {{"foo", 1}, {"bar", false}}; // NOLINT(cppcoreguidelines-owning-memory) delete j; // NOLINT(cppcoreguidelines-owning-memory) } SECTION("array") { auto* j = new json {"foo", 1, 1u, false, 23.42}; // NOLINT(cppcoreguidelines-owning-memory) delete j; // NOLINT(cppcoreguidelines-owning-memory) } SECTION("string") { auto* j = new json("Hello world"); // NOLINT(cppcoreguidelines-owning-memory) delete j; // NOLINT(cppcoreguidelines-owning-memory) } } } TEST_CASE("copy constructor and destructor across value types") { SECTION("copy of a scalar is independent of the source") { const json src_null = nullptr; const json src_bool = true; const json src_int = -7; const json src_uint = 7u; const json src_float = 2.5; json c_null(src_null); json c_bool(src_bool); json c_int(src_int); json c_uint(src_uint); json c_float(src_float); CHECK(c_null.is_null()); CHECK(c_bool == true); CHECK(c_int == -7); CHECK(c_uint == 7u); CHECK(c_float == 2.5); c_int = 8; c_float = 3.5; CHECK(src_int == -7); CHECK(src_float == 2.5); } SECTION("copy of an owning value, then mutate the copy") { const json src_string = "hello"; const json src_array = {1, 2, 3}; const json src_object = {{"a", 1}, {"b", {{"c", 2}}}}; const json src_binary = json::binary({1, 2, 3}); json c_string(src_string); json c_array(src_array); json c_object(src_object); json c_binary(src_binary); CHECK(c_string == src_string); CHECK(c_array == src_array); CHECK(c_object == src_object); CHECK(c_binary == src_binary); c_string.get_ref() += " world"; c_array.push_back(4); c_object["b"]["c"] = 3; c_object["d"] = 4; c_binary.get_binary().push_back(4); CHECK(src_string == "hello"); CHECK(src_array.size() == 3); CHECK(src_object["b"]["c"] == 2); CHECK_FALSE(src_object.contains("d")); CHECK(src_binary.get_binary().size() == 3); CHECK(c_string == "hello world"); CHECK(c_array.size() == 4); CHECK(c_object["b"]["c"] == 3); CHECK(c_binary.get_binary().size() == 4); } SECTION("copy keeps parent pointers valid (JSON_DIAGNOSTICS)") { const json src = {{"a", {1, 2}}, {"b", "x"}}; json c(src); c["a"].push_back(3); CHECK(c["a"].size() == 3); CHECK(src["a"].size() == 2); } SECTION("vector of mixed types: build, copy, and destroy") { { std::vector v; for (int i = 0; i < 70; ++i) { switch (i % 9) { case 0: v.emplace_back(nullptr); break; case 1: v.emplace_back(i % 2 == 0); break; case 2: v.emplace_back(-i); break; case 3: v.emplace_back(static_cast(i)); break; case 4: v.emplace_back(i * 0.5); break; case 5: v.emplace_back(std::string(static_cast(i), 'x')); break; case 6: v.emplace_back(json::array({i, "s", nullptr})); break; case 7: v.emplace_back(json::object({{"k", i}})); break; default: v.emplace_back(json::binary({1, 2, 3})); break; } } REQUIRE(v.size() == 70); std::vector copy(v); CHECK(copy == v); // mutating the copy leaves the original alone copy[5] = "changed"; copy[6].push_back(1); CHECK(copy != v); CHECK(v[5] == std::string(5, 'x')); CHECK(v[6].size() == 3); v.erase(v.begin(), v.begin() + 10); CHECK(v.size() == 60); } // destroying the discarded and default-constructed values std::vector w(4); w.emplace_back(json::value_t::discarded); w.emplace_back(json::value_t::object); w.emplace_back(json::value_t::array); w.emplace_back(json::value_t::string); w.emplace_back(json::value_t::binary); CHECK(w.size() == 9); } }