mirror of
https://github.com/nlohmann/json.git
synced 2026-10-01 14:15:50 +01:00
basic_json(first, last) treated value_t::binary like the structured types (array, object) in the range check, so it always copied the whole binary value regardless of the iterators, even for an empty range such as (b.end(), b.end()). The other primitive types (number, boolean, string) already reject such a range with invalid_iterator.204, and erase(first, last) already does the same for binary values, so this made the constructor inconsistent with both. Move case value_t::binary into the group of checked primitive types. Also update the two matching passages in basic_json.md that describe overload 7, and add a version-history note. Fixes #5670. Signed-off-by: Niels Lohmann <mail@nlohmann.me>
1669 lines
57 KiB
C++
1669 lines
57 KiB
C++
// __ _____ _____ _____
|
|
// __| | __| | | | JSON for Modern C++ (supporting code)
|
|
// | | |__ | | | | | | version 3.12.0
|
|
// |_____|_____|_____|_|___| https://github.com/nlohmann/json
|
|
//
|
|
// SPDX-FileCopyrightText: 2013-2026 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]);
|
|
}
|
|
|
|
SECTION("std::tuple tie")
|
|
{
|
|
const auto a = 1.0;
|
|
const auto* const b = "string";
|
|
const auto c = 42;
|
|
const auto d = std::vector<int> {0, 2};
|
|
const size_t e = 1234;
|
|
auto t = std::tie(a, b, c, d, e);
|
|
json const j(t);
|
|
|
|
double a_out = 0;
|
|
std::string b_out;
|
|
int c_out = 0;
|
|
std::vector<int> d_out;
|
|
int64_t e_out = 0;
|
|
auto t_out = std::tie(a_out, b_out, c_out, d_out, e_out);
|
|
j.get_to(t_out);
|
|
CHECK(a_out == a);
|
|
CHECK(b_out == b);
|
|
CHECK(c_out == c);
|
|
CHECK(d_out == d);
|
|
CHECK(e_out == e);
|
|
}
|
|
|
|
SECTION("std::tuple of references to elements")
|
|
{
|
|
const auto a = 1.0;
|
|
const auto* const b = "string";
|
|
const auto c = 42;
|
|
const size_t d = 1234;
|
|
const auto t = std::tie(a, b, c, d);
|
|
json const j(t);
|
|
|
|
auto t_out = j.get<std::tuple<const json::number_float_t&,
|
|
const json::string_t&,
|
|
const json::number_integer_t&,
|
|
const json::number_unsigned_t&>>();
|
|
CHECK(&std::get<0>(t_out) == j[0].get_ptr<const json::number_float_t*>());
|
|
CHECK(&std::get<1>(t_out) == j[1].get_ptr<const json::string_t*>());
|
|
CHECK(&std::get<2>(t_out) == j[2].get_ptr<const json::number_integer_t*>());
|
|
CHECK(&std::get<3>(t_out) == j[3].get_ptr<const json::number_unsigned_t*>());
|
|
CHECK(std::get<0>(t_out) == a);
|
|
CHECK(std::get<1>(t_out) == b);
|
|
CHECK(std::get<2>(t_out) == c);
|
|
CHECK(std::get<3>(t_out) == d);
|
|
}
|
|
|
|
SECTION("std::tuple mixed arithmetic types")
|
|
{
|
|
using j_float_t = json::number_float_t;
|
|
using j_int_t = json::number_integer_t;
|
|
using j_uint_t = json::number_unsigned_t;
|
|
const j_float_t a = 1.0;
|
|
const j_int_t b = 1234;
|
|
const j_uint_t c = 42;
|
|
json const j(std::tie(a, b, c, c));
|
|
|
|
auto t1 = j.get<std::tuple<j_int_t, j_uint_t, j_float_t, const j_uint_t&>>();
|
|
j_uint_t a2 = 0;
|
|
j_float_t b2 = 0;
|
|
j_int_t c2 = 0;
|
|
auto t2 = std::tie(a2, b2, c2);
|
|
j.get_to(t2);
|
|
|
|
CHECK(std::get<0>(t1) == static_cast<j_int_t>(a));
|
|
CHECK(std::get<1>(t1) == static_cast<j_uint_t>(b));
|
|
CHECK(std::get<2>(t1) == static_cast<j_float_t>(c));
|
|
// t1[3] exists only to force usage of the no-default-constructor version
|
|
CHECK(a2 == static_cast<j_uint_t>(a));
|
|
CHECK(b2 == static_cast<j_float_t>(b));
|
|
CHECK(c2 == static_cast<j_int_t>(c));
|
|
}
|
|
|
|
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[]")
|
|
{
|
|
const char s[] {"Hello world"}; // NOLINT(misc-const-correctness,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")
|
|
{
|
|
const 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")
|
|
{
|
|
const 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")
|
|
{
|
|
const 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};
|
|
const 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&);
|
|
}
|
|
}
|
|
|
|
SECTION("binary")
|
|
{
|
|
{
|
|
json j = json::binary({1, 2, 3});
|
|
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 = json::binary({1, 2, 3});
|
|
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&);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|