blob: c69be14e9a770b548276811df1f29a65e402c088 [file] [log] [blame] [edit]
// __ _____ _____ _____
// __| | __| | | | JSON for Modern C++ (supporting code)
// | | |__ | | | | | | version 3.11.3
// |_____|_____|_____|_|___| https://github.com/nlohmann/json
//
// SPDX-FileCopyrightText: 2013-2023 Niels Lohmann <https://nlohmann.me>
// SPDX-License-Identifier: MIT
#include "doctest_compatibility.h"
#define JSON_TESTS_PRIVATE
#include <nlohmann/json.hpp>
using nlohmann::json;
#include <deque>
#include <forward_list>
#include <fstream>
#include <list>
#include <set>
#include <unordered_map>
#include <unordered_set>
#include <valarray>
TEST_CASE("constructors")
{
SECTION("create an empty value with a given type")
{
SECTION("null")
{
auto const t = json::value_t::null;
json const j(t);
CHECK(j.type() == t);
}
SECTION("discarded")
{
auto const t = json::value_t::discarded;
json const j(t);
CHECK(j.type() == t);
}
SECTION("object")
{
auto const t = json::value_t::object;
json const j(t);
CHECK(j.type() == t);
}
SECTION("array")
{
auto const t = json::value_t::array;
json const j(t);
CHECK(j.type() == t);
}
SECTION("boolean")
{
auto const t = json::value_t::boolean;
json const j(t);
CHECK(j.type() == t);
CHECK(j == false);
}
SECTION("string")
{
auto const t = json::value_t::string;
json const j(t);
CHECK(j.type() == t);
CHECK(j == "");
}
SECTION("number_integer")
{
auto const t = json::value_t::number_integer;
json const j(t);
CHECK(j.type() == t);
CHECK(j == 0);
}
SECTION("number_unsigned")
{
auto const t = json::value_t::number_unsigned;
json const j(t);
CHECK(j.type() == t);
CHECK(j == 0);
}
SECTION("number_float")
{
auto const t = json::value_t::number_float;
json const j(t);
CHECK(j.type() == t);
CHECK(j == 0.0);
}
SECTION("binary")
{
auto const t = json::value_t::binary;
json const j(t);
CHECK(j.type() == t);
CHECK(j == json::binary({}));
}
}
SECTION("create a null object (implicitly)")
{
SECTION("no parameter")
{
json const j{};
CHECK(j.type() == json::value_t::null);
}
}
SECTION("create a null object (explicitly)")
{
SECTION("parameter")
{
json const j(nullptr);
CHECK(j.type() == json::value_t::null);
}
}
SECTION("create an object (explicit)")
{
SECTION("empty object")
{
json::object_t const o{};
json const j(o);
CHECK(j.type() == json::value_t::object);
}
SECTION("filled object")
{
json::object_t const o{ { "a", json(1) }, { "b", json(1u) }, { "c", json(2.2) }, { "d", json(false) }, { "e", json("string") }, { "f", json() } };
json const j(o);
CHECK(j.type() == json::value_t::object);
}
}
SECTION("create an object (implicit)")
{
// reference object
json::object_t const o_reference{ { "a", json(1) }, { "b", json(1u) }, { "c", json(2.2) },
{ "d", json(false) }, { "e", json("string") }, { "f", json() } };
json const j_reference(o_reference);
SECTION("std::map<json::string_t, json>")
{
std::map<json::string_t, json> const o{ { "a", json(1) }, { "b", json(1u) }, { "c", json(2.2) },
{ "d", json(false) }, { "e", json("string") }, { "f", json() } };
json const j(o);
CHECK(j.type() == json::value_t::object);
CHECK(j == j_reference);
}
SECTION("std::map<std::string, std::string> #600")
{
const std::map<std::string, std::string> m{
{ "a", "b" },
{ "c", "d" },
{ "e", "f" },
};
json const j(m);
CHECK((j.get<decltype(m)>() == m));
}
SECTION("std::map<const char*, json>")
{
std::map<const char*, json> const o{ { "a", json(1) }, { "b", json(1u) }, { "c", json(2.2) },
{ "d", json(false) }, { "e", json("string") }, { "f", json() } };
json const j(o);
CHECK(j.type() == json::value_t::object);
CHECK(j == j_reference);
}
SECTION("std::multimap<json::string_t, json>")
{
std::multimap<json::string_t, json> const o{ { "a", json(1) }, { "b", json(1u) }, { "c", json(2.2) },
{ "d", json(false) }, { "e", json("string") }, { "f", json() } };
json const j(o);
CHECK(j.type() == json::value_t::object);
CHECK(j == j_reference);
}
SECTION("std::unordered_map<json::string_t, json>")
{
std::unordered_map<json::string_t, json> const o{ { "a", json(1) }, { "b", json(1u) }, { "c", json(2.2) },
{ "d", json(false) }, { "e", json("string") }, { "f", json() } };
json const j(o);
CHECK(j.type() == json::value_t::object);
CHECK(j == j_reference);
}
SECTION("std::unordered_multimap<json::string_t, json>")
{
std::unordered_multimap<json::string_t, json> const o{ { "a", json(1) }, { "b", json(1u) }, { "c", json(2.2) },
{ "d", json(false) }, { "e", json("string") }, { "f", json() } };
json const j(o);
CHECK(j.type() == json::value_t::object);
CHECK(j == j_reference);
}
SECTION("associative container literal")
{
json const j({ { "a", json(1) }, { "b", json(1u) }, { "c", json(2.2) }, { "d", json(false) }, { "e", json("string") }, { "f", json() } });
CHECK(j.type() == json::value_t::object);
CHECK(j == j_reference);
}
}
SECTION("create an array (explicit)")
{
SECTION("empty array")
{
json::array_t const a{};
json const j(a);
CHECK(j.type() == json::value_t::array);
}
SECTION("filled array")
{
json::array_t const a{ json(1), json(1u), json(2.2), json(false), json("string"), json() };
json const j(a);
CHECK(j.type() == json::value_t::array);
}
}
SECTION("create an array (implicit)")
{
// reference array
json::array_t const a_reference{ json(1), json(1u), json(2.2), json(false), json("string"), json() };
json const j_reference(a_reference);
SECTION("std::list<json>")
{
std::list<json> const a{ json(1), json(1u), json(2.2), json(false), json("string"), json() };
json const j(a);
CHECK(j.type() == json::value_t::array);
CHECK(j == j_reference);
}
SECTION("std::pair")
{
std::pair<float, std::string> const p{ 1.0f, "string" };
json const j(p);
CHECK(j.type() == json::value_t::array);
CHECK(j.get<decltype(p)>() == p);
REQUIRE(j.size() == 2);
CHECK(j[0] == std::get<0>(p));
CHECK(j[1] == std::get<1>(p));
}
SECTION("std::pair with discarded values")
{
json const j{ 1, 2.0, "string" };
const auto p = j.get<std::pair<int, float>>();
CHECK(p.first == j[0]);
CHECK(p.second == j[1]);
}
SECTION("std::tuple")
{
const auto t = std::make_tuple(1.0, std::string{ "string" }, 42, std::vector<int>{ 0, 1 });
json const j(t);
CHECK(j.type() == json::value_t::array);
REQUIRE(j.size() == 4);
CHECK(j.get<decltype(t)>() == t);
CHECK(j[0] == std::get<0>(t));
CHECK(j[1] == std::get<1>(t));
CHECK(j[2] == std::get<2>(t));
CHECK(j[3][0] == 0);
CHECK(j[3][1] == 1);
}
SECTION("std::tuple with discarded values")
{
json const j{ 1, 2.0, "string", 42 };
const auto t = j.get<std::tuple<int, float, std::string>>();
CHECK(std::get<0>(t) == j[0]);
CHECK(std::get<1>(t) == j[1]);
// CHECK(std::get<2>(t) == j[2]); // commented out due to CI issue, see https://github.com/nlohmann/json/pull/3985 and https://github.com/nlohmann/json/issues/4025
}
SECTION("std::pair/tuple/array failures")
{
json const j{ 1 };
CHECK_THROWS_WITH_AS((j.get<std::pair<int, int>>()), "[json.exception.out_of_range.401] array index 1 is out of range", json::out_of_range&);
CHECK_THROWS_WITH_AS((j.get<std::tuple<int, int>>()), "[json.exception.out_of_range.401] array index 1 is out of range", json::out_of_range&);
CHECK_THROWS_WITH_AS((j.get<std::array<int, 3>>()), "[json.exception.out_of_range.401] array index 1 is out of range", json::out_of_range&);
}
SECTION("std::forward_list<json>")
{
std::forward_list<json> const a{ json(1), json(1u), json(2.2), json(false), json("string"), json() };
json const j(a);
CHECK(j.type() == json::value_t::array);
CHECK(j == j_reference);
}
SECTION("std::array<json, 6>")
{
std::array<json, 6> const a{ { json(1), json(1u), json(2.2), json(false), json("string"), json() } };
json const j(a);
CHECK(j.type() == json::value_t::array);
CHECK(j == j_reference);
const auto a2 = j.get<std::array<json, 6>>();
CHECK(a2 == a);
}
SECTION("std::valarray<int>")
{
std::valarray<int> const va = { 1, 2, 3, 4, 5 };
json const j(va);
CHECK(j.type() == json::value_t::array);
CHECK(j == json({ 1, 2, 3, 4, 5 }));
auto jva = j.get<std::valarray<int>>();
CHECK(jva.size() == va.size());
for (size_t i = 0; i < jva.size(); ++i)
{
CHECK(va[i] == jva[i]);
}
}
SECTION("std::valarray<double>")
{
std::valarray<double> const va = { 1.2, 2.3, 3.4, 4.5, 5.6 };
json const j(va);
CHECK(j.type() == json::value_t::array);
CHECK(j == json({ 1.2, 2.3, 3.4, 4.5, 5.6 }));
auto jva = j.get<std::valarray<double>>();
CHECK(jva.size() == va.size());
for (size_t i = 0; i < jva.size(); ++i)
{
CHECK(va[i] == jva[i]);
}
}
SECTION("std::vector<json>")
{
std::vector<json> const a{ json(1), json(1u), json(2.2), json(false), json("string"), json() };
json const j(a);
CHECK(j.type() == json::value_t::array);
CHECK(j == j_reference);
}
SECTION("std::deque<json>")
{
std::deque<json> const a{ json(1), json(1u), json(2.2), json(false), json("string"), json() };
json const j(a);
CHECK(j.type() == json::value_t::array);
CHECK(j == j_reference);
}
SECTION("std::set<json>")
{
std::set<json> const a{ json(1), json(1u), json(2.2), json(false), json("string"), json() };
json const j(a);
CHECK(j.type() == json::value_t::array);
// we cannot really check for equality here
}
SECTION("std::unordered_set<json>")
{
std::unordered_set<json> const a{ json(1), json(1u), json(2.2), json(false), json("string"), json() };
json const j(a);
CHECK(j.type() == json::value_t::array);
// we cannot really check for equality here
}
SECTION("sequence container literal")
{
json const j({ json(1), json(1u), 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 const s{};
json const j(s);
CHECK(j.type() == json::value_t::string);
}
SECTION("filled string")
{
json::string_t const s{ "Hello world" };
json const j(s);
CHECK(j.type() == json::value_t::string);
}
}
SECTION("create a string (implicit)")
{
// reference string
json::string_t const s_reference{ "Hello world" };
json const j_reference(s_reference);
SECTION("std::string")
{
std::string const s{ "Hello world" };
json const j(s);
CHECK(j.type() == json::value_t::string);
CHECK(j == j_reference);
}
SECTION("char[]")
{
char const s[]{ "Hello world" }; // NOLINT(cppcoreguidelines-avoid-c-arrays,hicpp-avoid-c-arrays,modernize-avoid-c-arrays)
json const j(s);
CHECK(j.type() == json::value_t::string);
CHECK(j == j_reference);
}
SECTION("const char*")
{
const char* s{ "Hello world" };
json const j(s);
CHECK(j.type() == json::value_t::string);
CHECK(j == j_reference);
}
SECTION("string literal")
{
json const 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 const b{};
json const j(b);
CHECK(j.type() == json::value_t::boolean);
}
SECTION("filled boolean (true)")
{
json const j(true);
CHECK(j.type() == json::value_t::boolean);
}
SECTION("filled boolean (false)")
{
json const j(false);
CHECK(j.type() == json::value_t::boolean);
}
SECTION("from std::vector<bool>::reference")
{
std::vector<bool> v{ true };
json const j(v[0]);
CHECK(std::is_same<decltype(v[0]), std::vector<bool>::reference>::value);
CHECK(j.type() == json::value_t::boolean);
}
SECTION("from std::vector<bool>::const_reference")
{
const std::vector<bool> v{ true };
json const j(v[0]);
CHECK(std::is_same<decltype(v[0]), std::vector<bool>::const_reference>::value);
CHECK(j.type() == json::value_t::boolean);
}
}
SECTION("create a binary (explicit)")
{
SECTION("empty binary")
{
json::binary_t const b{};
json const j(b);
CHECK(j.type() == json::value_t::binary);
}
SECTION("filled binary")
{
json::binary_t const b({ 1, 2, 3 });
json const j(b);
CHECK(j.type() == json::value_t::binary);
}
}
SECTION("create an integer number (explicit)")
{
SECTION("uninitialized value")
{
json::number_integer_t const n{};
json const j(n);
CHECK(j.type() == json::value_t::number_integer);
}
SECTION("initialized value")
{
json::number_integer_t const n(42);
json const j(n);
CHECK(j.type() == json::value_t::number_integer);
}
}
SECTION("create an integer number (implicit)")
{
// reference objects
json::number_integer_t const n_reference = 42;
json const j_reference(n_reference);
json::number_unsigned_t const n_unsigned_reference = 42;
json const j_unsigned_reference(n_unsigned_reference);
SECTION("short")
{
short const n = 42;
json const j(n);
CHECK(j.type() == json::value_t::number_integer);
CHECK(j == j_reference);
}
SECTION("unsigned short")
{
unsigned short const n = 42;
json const j(n);
CHECK(j.type() == json::value_t::number_unsigned);
CHECK(j == j_unsigned_reference);
}
SECTION("int")
{
int const n = 42;
json const j(n);
CHECK(j.type() == json::value_t::number_integer);
CHECK(j == j_reference);
}
SECTION("unsigned int")
{
unsigned int const n = 42;
json const j(n);
CHECK(j.type() == json::value_t::number_unsigned);
CHECK(j == j_unsigned_reference);
}
SECTION("long")
{
long const n = 42;
json const j(n);
CHECK(j.type() == json::value_t::number_integer);
CHECK(j == j_reference);
}
SECTION("unsigned long")
{
unsigned long const n = 42;
json const j(n);
CHECK(j.type() == json::value_t::number_unsigned);
CHECK(j == j_unsigned_reference);
}
SECTION("long long")
{
long long const n = 42;
json const j(n);
CHECK(j.type() == json::value_t::number_integer);
CHECK(j == j_reference);
}
SECTION("unsigned long long")
{
unsigned long long const n = 42;
json const j(n);
CHECK(j.type() == json::value_t::number_unsigned);
CHECK(j == j_unsigned_reference);
}
SECTION("int8_t")
{
int8_t const n = 42;
json const j(n);
CHECK(j.type() == json::value_t::number_integer);
CHECK(j == j_reference);
}
SECTION("int16_t")
{
int16_t const n = 42;
json const j(n);
CHECK(j.type() == json::value_t::number_integer);
CHECK(j == j_reference);
}
SECTION("int32_t")
{
int32_t const n = 42;
json const j(n);
CHECK(j.type() == json::value_t::number_integer);
CHECK(j == j_reference);
}
SECTION("int64_t")
{
int64_t const n = 42;
json const j(n);
CHECK(j.type() == json::value_t::number_integer);
CHECK(j == j_reference);
}
SECTION("int_fast8_t")
{
int_fast8_t const n = 42;
json const j(n);
CHECK(j.type() == json::value_t::number_integer);
CHECK(j == j_reference);
}
SECTION("int_fast16_t")
{
int_fast16_t const n = 42;
json const j(n);
CHECK(j.type() == json::value_t::number_integer);
CHECK(j == j_reference);
}
SECTION("int_fast32_t")
{
int_fast32_t const n = 42;
json const j(n);
CHECK(j.type() == json::value_t::number_integer);
CHECK(j == j_reference);
}
SECTION("int_fast64_t")
{
int_fast64_t const n = 42;
json const j(n);
CHECK(j.type() == json::value_t::number_integer);
CHECK(j == j_reference);
}
SECTION("int_least8_t")
{
int_least8_t const n = 42;
json const j(n);
CHECK(j.type() == json::value_t::number_integer);
CHECK(j == j_reference);
}
SECTION("int_least16_t")
{
int_least16_t const n = 42;
json const j(n);
CHECK(j.type() == json::value_t::number_integer);
CHECK(j == j_reference);
}
SECTION("int_least32_t")
{
int_least32_t const n = 42;
json const j(n);
CHECK(j.type() == json::value_t::number_integer);
CHECK(j == j_reference);
}
SECTION("int_least64_t")
{
int_least64_t const n = 42;
json const j(n);
CHECK(j.type() == json::value_t::number_integer);
CHECK(j == j_reference);
}
SECTION("uint8_t")
{
uint8_t const n = 42;
json const j(n);
CHECK(j.type() == json::value_t::number_unsigned);
CHECK(j == j_unsigned_reference);
}
SECTION("uint16_t")
{
uint16_t const n = 42;
json const j(n);
CHECK(j.type() == json::value_t::number_unsigned);
CHECK(j == j_unsigned_reference);
}
SECTION("uint32_t")
{
uint32_t const n = 42;
json const j(n);
CHECK(j.type() == json::value_t::number_unsigned);
CHECK(j == j_unsigned_reference);
}
SECTION("uint64_t")
{
uint64_t const n = 42;
json const j(n);
CHECK(j.type() == json::value_t::number_unsigned);
CHECK(j == j_unsigned_reference);
}
SECTION("uint_fast8_t")
{
uint_fast8_t const n = 42;
json const j(n);
CHECK(j.type() == json::value_t::number_unsigned);
CHECK(j == j_unsigned_reference);
}
SECTION("uint_fast16_t")
{
uint_fast16_t const n = 42;
json const j(n);
CHECK(j.type() == json::value_t::number_unsigned);
CHECK(j == j_unsigned_reference);
}
SECTION("uint_fast32_t")
{
uint_fast32_t const n = 42;
json const j(n);
CHECK(j.type() == json::value_t::number_unsigned);
CHECK(j == j_unsigned_reference);
}
SECTION("uint_fast64_t")
{
uint_fast64_t const n = 42;
json const j(n);
CHECK(j.type() == json::value_t::number_unsigned);
CHECK(j == j_unsigned_reference);
}
SECTION("uint_least8_t")
{
uint_least8_t const n = 42;
json const j(n);
CHECK(j.type() == json::value_t::number_unsigned);
CHECK(j == j_unsigned_reference);
}
SECTION("uint_least16_t")
{
uint_least16_t const n = 42;
json const j(n);
CHECK(j.type() == json::value_t::number_unsigned);
CHECK(j == j_unsigned_reference);
}
SECTION("uint_least32_t")
{
uint_least32_t const n = 42;
json const j(n);
CHECK(j.type() == json::value_t::number_unsigned);
CHECK(j == j_unsigned_reference);
}
SECTION("uint_least64_t")
{
uint_least64_t const n = 42;
json const j(n);
CHECK(j.type() == json::value_t::number_unsigned);
CHECK(j == j_unsigned_reference);
}
SECTION("integer literal without suffix")
{
json const 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_unsigned);
CHECK(j == j_unsigned_reference);
}
SECTION("integer literal with l suffix")
{
json const 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_unsigned);
CHECK(j == j_unsigned_reference);
}
SECTION("integer literal with ll suffix")
{
json const 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_unsigned);
CHECK(j == j_unsigned_reference);
}
}
SECTION("create a floating-point number (explicit)")
{
SECTION("uninitialized value")
{
json::number_float_t const n{};
json const j(n);
CHECK(j.type() == json::value_t::number_float);
}
SECTION("initialized value")
{
json::number_float_t const n(42.23);
json const j(n);
CHECK(j.type() == json::value_t::number_float);
}
SECTION("NaN")
{
// NaN is stored properly, but serialized to null
json::number_float_t const n(std::numeric_limits<json::number_float_t>::quiet_NaN());
json const j(n);
CHECK(j.type() == json::value_t::number_float);
// check round trip of NaN
json::number_float_t const d{ j };
CHECK((std::isnan(d) && std::isnan(n)) == true);
// check that NaN is serialized to null
CHECK(j.dump() == "null");
}
SECTION("infinity")
{
// infinity is stored properly, but serialized to null
json::number_float_t const n(std::numeric_limits<json::number_float_t>::infinity());
json const j(n);
CHECK(j.type() == json::value_t::number_float);
// check round trip of infinity
json::number_float_t const d{ j };
CHECK(d == n);
// check that inf is serialized to null
CHECK(j.dump() == "null");
}
}
SECTION("create a floating-point number (implicit)")
{
// reference object
json::number_float_t const n_reference = 42.23;
json const j_reference(n_reference);
SECTION("float")
{
float const n = 42.23f;
json const j(n);
CHECK(j.type() == json::value_t::number_float);
CHECK(j.m_data.m_value.number_float == Approx(j_reference.m_data.m_value.number_float));
}
SECTION("double")
{
double const n = 42.23;
json const j(n);
CHECK(j.type() == json::value_t::number_float);
CHECK(j.m_data.m_value.number_float == Approx(j_reference.m_data.m_value.number_float));
}
SECTION("long double")
{
long double const n = 42.23L;
json const j(n);
CHECK(j.type() == json::value_t::number_float);
CHECK(j.m_data.m_value.number_float == Approx(j_reference.m_data.m_value.number_float));
}
SECTION("floating-point literal without suffix")
{
json const j(42.23);
CHECK(j.type() == json::value_t::number_float);
CHECK(j.m_data.m_value.number_float == Approx(j_reference.m_data.m_value.number_float));
}
SECTION("integer literal with f suffix")
{
json const j(42.23f);
CHECK(j.type() == json::value_t::number_float);
CHECK(j.m_data.m_value.number_float == Approx(j_reference.m_data.m_value.number_float));
}
SECTION("integer literal with l suffix")
{
json const j(42.23L);
CHECK(j.type() == json::value_t::number_float);
CHECK(j.m_data.m_value.number_float == Approx(j_reference.m_data.m_value.number_float));
}
}
SECTION("create a container (array or object) from an initializer list")
{
SECTION("empty initializer list")
{
SECTION("explicit")
{
json const j(json::initializer_list_t{});
CHECK(j.type() == json::value_t::object);
}
SECTION("implicit")
{
json const j{};
CHECK(j.type() == json::value_t::null);
}
}
SECTION("one element")
{
SECTION("array")
{
SECTION("explicit")
{
json const j(json::initializer_list_t{ json(json::array_t()) });
CHECK(j.type() == json::value_t::array);
}
SECTION("implicit")
{
json const j{ json::array_t() };
CHECK(j.type() == json::value_t::array);
}
}
SECTION("object")
{
SECTION("explicit")
{
json const j(json::initializer_list_t{ json(json::object_t()) });
CHECK(j.type() == json::value_t::array);
}
SECTION("implicit")
{
json const j{ json::object_t() };
CHECK(j.type() == json::value_t::array);
}
}
SECTION("string")
{
SECTION("explicit")
{
json const j(json::initializer_list_t{ json("Hello world") });
CHECK(j.type() == json::value_t::array);
}
SECTION("implicit")
{
json const j{ "Hello world" };
CHECK(j.type() == json::value_t::array);
}
}
SECTION("boolean")
{
SECTION("explicit")
{
json const j(json::initializer_list_t{ json(true) });
CHECK(j.type() == json::value_t::array);
}
SECTION("implicit")
{
json const j{ true };
CHECK(j.type() == json::value_t::array);
}
}
SECTION("number (integer)")
{
SECTION("explicit")
{
json const j(json::initializer_list_t{ json(1) });
CHECK(j.type() == json::value_t::array);
}
SECTION("implicit")
{
json const j{ 1 };
CHECK(j.type() == json::value_t::array);
}
}
SECTION("number (unsigned)")
{
SECTION("explicit")
{
json const j(json::initializer_list_t{ json(1u) });
CHECK(j.type() == json::value_t::array);
}
SECTION("implicit")
{
json const j{ 1u };
CHECK(j.type() == json::value_t::array);
}
}
SECTION("number (floating-point)")
{
SECTION("explicit")
{
json const j(json::initializer_list_t{ json(42.23) });
CHECK(j.type() == json::value_t::array);
}
SECTION("implicit")
{
json const j{ 42.23 };
CHECK(j.type() == json::value_t::array);
}
}
}
SECTION("more elements")
{
SECTION("explicit")
{
json const j(json::initializer_list_t{ 1, 1u, 42.23, true, nullptr, json::object_t(), json::array_t() });
CHECK(j.type() == json::value_t::array);
}
SECTION("implicit")
{
json const j{ 1, 1u, 42.23, true, nullptr, json::object_t(), json::array_t() };
CHECK(j.type() == json::value_t::array);
}
}
SECTION("implicit type deduction")
{
SECTION("object")
{
json const j{ { "one", 1 }, { "two", 1u }, { "three", 2.2 }, { "four", false } };
CHECK(j.type() == json::value_t::object);
}
SECTION("array")
{
json const j{ { "one", 1 }, { "two", 1u }, { "three", 2.2 }, { "four", false }, 13 };
CHECK(j.type() == json::value_t::array);
}
}
SECTION("explicit type deduction")
{
SECTION("empty object")
{
json const j = json::object();
CHECK(j.type() == json::value_t::object);
}
SECTION("object")
{
json const j = json::object({ { "one", 1 }, { "two", 1u }, { "three", 2.2 }, { "four", false } });
CHECK(j.type() == json::value_t::object);
}
SECTION("object with error")
{
json _;
CHECK_THROWS_WITH_AS(_ = json::object({ { "one", 1 }, { "two", 1u }, { "three", 2.2 }, { "four", false }, 13 }),
"[json.exception.type_error.301] cannot create object from initializer list",
json::type_error&);
}
SECTION("empty array")
{
json const j = json::array();
CHECK(j.type() == json::value_t::array);
}
SECTION("array")
{
json const j = json::array({ { "one", 1 }, { "two", 1u }, { "three", 2.2 }, { "four", false } });
CHECK(j.type() == json::value_t::array);
}
}
SECTION("move from initializer_list")
{
SECTION("string")
{
SECTION("constructor with implicit types (array)")
{
// This should break through any short string optimization in std::string
std::string source(1024, '!');
const auto* source_addr = source.data();
json j = { std::move(source) };
const auto* target_addr = j[0].get_ref<std::string const&>().data();
const bool success = (target_addr == source_addr);
CHECK(success);
}
SECTION("constructor with implicit types (object)")
{
// This should break through any short string optimization in std::string
std::string source(1024, '!');
const auto* source_addr = source.data();
json j = { { "key", std::move(source) } };
const auto* target_addr = j["key"].get_ref<std::string const&>().data();
const bool success = (target_addr == source_addr);
CHECK(success);
}
SECTION("constructor with implicit types (object key)")
{
// This should break through any short string optimization in std::string
std::string source(1024, '!');
const auto* source_addr = source.data();
json j = { { std::move(source), 42 } };
const auto* target_addr = j.get_ref<json::object_t&>().begin()->first.data();
const bool success = (target_addr == source_addr);
CHECK(success);
}
}
SECTION("array")
{
SECTION("constructor with implicit types (array)")
{
json::array_t source = { 1, 2, 3 };
const auto* source_addr = source.data();
json j{ std::move(source) };
const auto* target_addr = j[0].get_ref<json::array_t const&>().data();
const bool success = (target_addr == source_addr);
CHECK(success);
}
SECTION("constructor with implicit types (object)")
{
json::array_t source = { 1, 2, 3 };
const auto* source_addr = source.data();
json const j{ { "key", std::move(source) } };
const auto* target_addr = j["key"].get_ref<json::array_t const&>().data();
const bool success = (target_addr == source_addr);
CHECK(success);
}
SECTION("assignment with implicit types (array)")
{
json::array_t source = { 1, 2, 3 };
const auto* source_addr = source.data();
json j = { std::move(source) };
const auto* target_addr = j[0].get_ref<json::array_t const&>().data();
const bool success = (target_addr == source_addr);
CHECK(success);
}
SECTION("assignment with implicit types (object)")
{
json::array_t source = { 1, 2, 3 };
const auto* source_addr = source.data();
json j = { { "key", std::move(source) } };
const auto* target_addr = j["key"].get_ref<json::array_t const&>().data();
const bool success = (target_addr == source_addr);
CHECK(success);
}
}
SECTION("object")
{
SECTION("constructor with implicit types (array)")
{
json::object_t source = { { "hello", "world" } };
const json* source_addr = &source.at("hello");
json j{ std::move(source) };
CHECK(&(j[0].get_ref<json::object_t const&>().at("hello")) == source_addr);
}
SECTION("constructor with implicit types (object)")
{
json::object_t source = { { "hello", "world" } };
const json* source_addr = &source.at("hello");
json j{ { "key", std::move(source) } };
CHECK(&(j["key"].get_ref<json::object_t const&>().at("hello")) == source_addr);
}
SECTION("assignment with implicit types (array)")
{
json::object_t source = { { "hello", "world" } };
const json* source_addr = &source.at("hello");
json j = { std::move(source) };
CHECK(&(j[0].get_ref<json::object_t const&>().at("hello")) == source_addr);
}
SECTION("assignment with implicit types (object)")
{
json::object_t source = { { "hello", "world" } };
const json* source_addr = &source.at("hello");
json j = { { "key", std::move(source) } };
CHECK(&(j["key"].get_ref<json::object_t const&>().at("hello")) == source_addr);
}
}
SECTION("json")
{
SECTION("constructor with implicit types (array)")
{
json source{ 1, 2, 3 };
const json* source_addr = &source[0];
json j{ std::move(source), {} };
CHECK(&j[0][0] == source_addr);
}
SECTION("constructor with implicit types (object)")
{
json source{ 1, 2, 3 };
const json* source_addr = &source[0];
json j{ { "key", std::move(source) } };
CHECK(&j["key"][0] == source_addr);
}
SECTION("assignment with implicit types (array)")
{
json source{ 1, 2, 3 };
const json* source_addr = &source[0];
json j = { std::move(source), {} };
CHECK(&j[0][0] == source_addr);
}
SECTION("assignment with implicit types (object)")
{
json source{ 1, 2, 3 };
const json* source_addr = &source[0];
json j = { { "key", std::move(source) } };
CHECK(&j["key"][0] == source_addr);
}
}
}
}
SECTION("create an array of n copies of a given value")
{
SECTION("cnt = 0")
{
json const v = { 1, "foo", 34.23, { 1, 2, 3 }, { { "A", 1 }, { "B", 2u } } };
json const arr(0, v);
CHECK(arr.size() == 0);
}
SECTION("cnt = 1")
{
json const v = { 1, "foo", 34.23, { 1, 2, 3 }, { { "A", 1 }, { "B", 2u } } };
json const arr(1, v);
CHECK(arr.size() == 1);
for (const auto& x : arr)
{
CHECK(x == v);
}
}
SECTION("cnt = 3")
{
json const v = { 1, "foo", 34.23, { 1, 2, 3 }, { { "A", 1 }, { "B", 2u } } };
json const arr(3, v);
CHECK(arr.size() == 3);
for (const auto& x : arr)
{
CHECK(x == v);
}
}
}
SECTION("create a JSON container from an iterator range")
{
SECTION("object")
{
SECTION("json(begin(), end())")
{
{
json jobject = { { "a", "a" }, { "b", 1 }, { "c", 17u } };
json const j_new(jobject.begin(), jobject.end());
CHECK(j_new == jobject);
}
{
json jobject = { { "a", "a" }, { "b", 1 }, { "c", 17u } };
json const j_new(jobject.cbegin(), jobject.cend());
CHECK(j_new == jobject);
}
}
SECTION("json(begin(), begin())")
{
{
json jobject = { { "a", "a" }, { "b", 1 }, { "c", 17u } };
json const j_new(jobject.begin(), jobject.begin());
CHECK(j_new == json::object());
}
{
json const jobject = { { "a", "a" }, { "b", 1 }, { "c", 17u } };
json const j_new(jobject.cbegin(), jobject.cbegin());
CHECK(j_new == json::object());
}
}
SECTION("construct from subrange")
{
json const jobject = { { "a", "a" }, { "b", 1 }, { "c", 17u }, { "d", false }, { "e", true } };
json const j_new(jobject.find("b"), jobject.find("e"));
CHECK(j_new == json({ { "b", 1 }, { "c", 17u }, { "d", false } }));
}
SECTION("incompatible iterators")
{
{
json jobject = { { "a", "a" }, { "b", 1 }, { "c", 17u }, { "d", false }, { "e", true } };
json jobject2 = { { "a", "a" }, { "b", 1 }, { "c", 17u } };
CHECK_THROWS_WITH_AS(json(jobject.begin(), jobject2.end()),
"[json.exception.invalid_iterator.201] iterators are not compatible",
json::invalid_iterator&);
CHECK_THROWS_WITH_AS(json(jobject2.begin(), jobject.end()),
"[json.exception.invalid_iterator.201] iterators are not compatible",
json::invalid_iterator&);
}
{
json const jobject = { { "a", "a" }, { "b", 1 }, { "c", 17u }, { "d", false }, { "e", true } };
json const jobject2 = { { "a", "a" }, { "b", 1 }, { "c", 17u } };
CHECK_THROWS_WITH_AS(json(jobject.cbegin(), jobject2.cend()),
"[json.exception.invalid_iterator.201] iterators are not compatible",
json::invalid_iterator&);
CHECK_THROWS_WITH_AS(json(jobject2.cbegin(), jobject.cend()),
"[json.exception.invalid_iterator.201] iterators are not compatible",
json::invalid_iterator&);
}
}
}
SECTION("array")
{
SECTION("json(begin(), end())")
{
{
json jarray = { 1, 2, 3, 4, 5 };
json const j_new(jarray.begin(), jarray.end());
CHECK(j_new == jarray);
}
{
json const jarray = { 1, 2, 3, 4, 5 };
json const j_new(jarray.cbegin(), jarray.cend());
CHECK(j_new == jarray);
}
}
SECTION("json(begin(), begin())")
{
{
json jarray = { 1, 2, 3, 4, 5 };
json j_new(jarray.begin(), jarray.begin());
CHECK(j_new == json::array());
}
{
json const jarray = { 1, 2, 3, 4, 5 };
json const j_new(jarray.cbegin(), jarray.cbegin());
CHECK(j_new == json::array());
}
}
SECTION("construct from subrange")
{
{
json jarray = { 1, 2, 3, 4, 5 };
json const j_new(jarray.begin() + 1, jarray.begin() + 3);
CHECK(j_new == json({ 2, 3 }));
}
{
json const jarray = { 1, 2, 3, 4, 5 };
json const j_new(jarray.cbegin() + 1, jarray.cbegin() + 3);
CHECK(j_new == json({ 2, 3 }));
}
}
SECTION("incompatible iterators")
{
{
json jarray = { 1, 2, 3, 4 };
json jarray2 = { 2, 3, 4, 5 };
CHECK_THROWS_WITH_AS(json(jarray.begin(), jarray2.end()),
"[json.exception.invalid_iterator.201] iterators are not compatible",
json::invalid_iterator&);
CHECK_THROWS_WITH_AS(json(jarray2.begin(), jarray.end()),
"[json.exception.invalid_iterator.201] iterators are not compatible",
json::invalid_iterator&);
}
{
json const jarray = { 1, 2, 3, 4 };
json const jarray2 = { 2, 3, 4, 5 };
CHECK_THROWS_WITH_AS(json(jarray.cbegin(), jarray2.cend()),
"[json.exception.invalid_iterator.201] iterators are not compatible",
json::invalid_iterator&);
CHECK_THROWS_WITH_AS(json(jarray2.cbegin(), jarray.cend()),
"[json.exception.invalid_iterator.201] iterators are not compatible",
json::invalid_iterator&);
}
}
}
SECTION("other values")
{
SECTION("construct with two valid iterators")
{
SECTION("null")
{
{
json j;
CHECK_THROWS_WITH_AS(json(j.begin(), j.end()),
"[json.exception.invalid_iterator.206] cannot construct with iterators from null",
json::invalid_iterator&);
}
{
json const j;
CHECK_THROWS_WITH_AS(json(j.cbegin(), j.cend()),
"[json.exception.invalid_iterator.206] cannot construct with iterators from null",
json::invalid_iterator&);
}
}
SECTION("string")
{
{
json j = "foo";
json const j_new(j.begin(), j.end());
CHECK(j == j_new);
}
{
json const j = "bar";
json const j_new(j.cbegin(), j.cend());
CHECK(j == j_new);
}
}
SECTION("number (boolean)")
{
{
json j = false;
json const j_new(j.begin(), j.end());
CHECK(j == j_new);
}
{
json const j = true;
json const j_new(j.cbegin(), j.cend());
CHECK(j == j_new);
}
}
SECTION("number (integer)")
{
{
json j = 17;
json const j_new(j.begin(), j.end());
CHECK(j == j_new);
}
{
json const j = 17;
json const j_new(j.cbegin(), j.cend());
CHECK(j == j_new);
}
}
SECTION("number (unsigned)")
{
{
json j = 17u;
json const j_new(j.begin(), j.end());
CHECK(j == j_new);
}
{
json const j = 17u;
json const j_new(j.cbegin(), j.cend());
CHECK(j == j_new);
}
}
SECTION("number (floating point)")
{
{
json j = 23.42;
json const j_new(j.begin(), j.end());
CHECK(j == j_new);
}
{
json const j = 23.42;
json const j_new(j.cbegin(), j.cend());
CHECK(j == j_new);
}
}
SECTION("binary")
{
{
json j = json::binary({ 1, 2, 3 });
json const j_new(j.begin(), j.end());
CHECK((j == j_new));
}
{
json const j = json::binary({ 1, 2, 3 });
json const j_new(j.cbegin(), j.cend());
CHECK((j == j_new));
}
}
}
SECTION("construct with two invalid iterators")
{
SECTION("string")
{
{
json j = "foo";
CHECK_THROWS_WITH_AS(json(j.end(), j.end()), "[json.exception.invalid_iterator.204] iterators out of range", json::invalid_iterator&);
CHECK_THROWS_WITH_AS(json(j.begin(), j.begin()),
"[json.exception.invalid_iterator.204] iterators out of range",
json::invalid_iterator&);
}
{
json const j = "bar";
CHECK_THROWS_WITH_AS(json(j.cend(), j.cend()), "[json.exception.invalid_iterator.204] iterators out of range", json::invalid_iterator&);
CHECK_THROWS_WITH_AS(json(j.cbegin(), j.cbegin()),
"[json.exception.invalid_iterator.204] iterators out of range",
json::invalid_iterator&);
}
}
SECTION("number (boolean)")
{
{
json j = false;
CHECK_THROWS_WITH_AS(json(j.end(), j.end()), "[json.exception.invalid_iterator.204] iterators out of range", json::invalid_iterator&);
CHECK_THROWS_WITH_AS(json(j.begin(), j.begin()),
"[json.exception.invalid_iterator.204] iterators out of range",
json::invalid_iterator&);
}
{
json const j = true;
CHECK_THROWS_WITH_AS(json(j.cend(), j.cend()), "[json.exception.invalid_iterator.204] iterators out of range", json::invalid_iterator&);
CHECK_THROWS_WITH_AS(json(j.cbegin(), j.cbegin()),
"[json.exception.invalid_iterator.204] iterators out of range",
json::invalid_iterator&);
}
}
SECTION("number (integer)")
{
{
json j = 17;
CHECK_THROWS_WITH_AS(json(j.end(), j.end()), "[json.exception.invalid_iterator.204] iterators out of range", json::invalid_iterator&);
CHECK_THROWS_WITH_AS(json(j.begin(), j.begin()),
"[json.exception.invalid_iterator.204] iterators out of range",
json::invalid_iterator&);
}
{
json const j = 17;
CHECK_THROWS_WITH_AS(json(j.cend(), j.cend()), "[json.exception.invalid_iterator.204] iterators out of range", json::invalid_iterator&);
CHECK_THROWS_WITH_AS(json(j.cbegin(), j.cbegin()),
"[json.exception.invalid_iterator.204] iterators out of range",
json::invalid_iterator&);
}
}
SECTION("number (integer)")
{
{
json j = 17u;
CHECK_THROWS_WITH_AS(json(j.end(), j.end()), "[json.exception.invalid_iterator.204] iterators out of range", json::invalid_iterator&);
CHECK_THROWS_WITH_AS(json(j.begin(), j.begin()),
"[json.exception.invalid_iterator.204] iterators out of range",
json::invalid_iterator&);
}
{
json const j = 17u;
CHECK_THROWS_WITH_AS(json(j.cend(), j.cend()), "[json.exception.invalid_iterator.204] iterators out of range", json::invalid_iterator&);
CHECK_THROWS_WITH_AS(json(j.cbegin(), j.cbegin()),
"[json.exception.invalid_iterator.204] iterators out of range",
json::invalid_iterator&);
}
}
SECTION("number (floating point)")
{
{
json j = 23.42;
CHECK_THROWS_WITH_AS(json(j.end(), j.end()), "[json.exception.invalid_iterator.204] iterators out of range", json::invalid_iterator&);
CHECK_THROWS_WITH_AS(json(j.begin(), j.begin()),
"[json.exception.invalid_iterator.204] iterators out of range",
json::invalid_iterator&);
}
{
json const j = 23.42;
CHECK_THROWS_WITH_AS(json(j.cend(), j.cend()), "[json.exception.invalid_iterator.204] iterators out of range", json::invalid_iterator&);
CHECK_THROWS_WITH_AS(json(j.cbegin(), j.cbegin()),
"[json.exception.invalid_iterator.204] iterators out of range",
json::invalid_iterator&);
}
}
}
}
}
}