blob: bbd5760575d955a47e5fba58169e83223f06573f [file] [log] [blame]
// __ _____ _____ _____
// __| | __| | | | 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&);
}
}
}
}
}
}