json/test/unit.cpp
2015-02-13 20:27:27 +01:00

5346 lines
163 KiB
C++

/*!
@file
@copyright The code is licensed under the MIT License
<http://opensource.org/licenses/MIT>,
Copyright (c) 2013-2015 Niels Lohmann.
@author Niels Lohmann <http://nlohmann.me>
@see https://github.com/nlohmann/json
*/
#define CATCH_CONFIG_MAIN
#include "catch.hpp"
#include "json.hpp"
using nlohmann::json;
#include <array>
#include <deque>
#include <forward_list>
#include <iomanip>
#include <list>
#include <map>
#include <set>
#include <string>
#include <unordered_map>
#include <unordered_set>
#include <vector>
TEST_CASE("constructors")
{
SECTION("create an empty value with a given type")
{
SECTION("null")
{
auto t = json::value_t::null;
json j(t);
CHECK(j.type() == t);
}
SECTION("object")
{
auto t = json::value_t::object;
json j(t);
CHECK(j.type() == t);
}
SECTION("array")
{
auto t = json::value_t::array;
json j(t);
CHECK(j.type() == t);
}
SECTION("boolean")
{
auto t = json::value_t::boolean;
json j(t);
CHECK(j.type() == t);
}
SECTION("string")
{
auto t = json::value_t::string;
json j(t);
CHECK(j.type() == t);
}
SECTION("number_integer")
{
auto t = json::value_t::number_integer;
json j(t);
CHECK(j.type() == t);
}
SECTION("number_float")
{
auto t = json::value_t::number_float;
json j(t);
CHECK(j.type() == t);
}
}
SECTION("create a null object (implicitly)")
{
SECTION("no parameter")
{
json j{};
CHECK(j.type() == json::value_t::null);
}
}
SECTION("create a null object (explicitly)")
{
SECTION("parameter")
{
json j(nullptr);
CHECK(j.type() == json::value_t::null);
}
}
SECTION("create an object (explicit)")
{
SECTION("empty object")
{
json::object_t o;
json j(o);
CHECK(j.type() == json::value_t::object);
}
SECTION("filled object")
{
json::object_t o {{"a", json(1)}, {"b", json(2.2)}, {"c", json(false)}, {"d", json("string")}, {"e", json()}};
json j(o);
CHECK(j.type() == json::value_t::object);
}
}
SECTION("create an object (implicit)")
{
// reference object
json::object_t o_reference {{"a", json(1)}, {"b", json(2.2)}, {"c", json(false)}, {"d", json("string")}, {"e", json()}};
json j_reference(o_reference);
SECTION("std::map<std::string, json>")
{
std::map<std::string, json> o {{"a", json(1)}, {"b", json(2.2)}, {"c", json(false)}, {"d", json("string")}, {"e", json()}};
json j(o);
CHECK(j.type() == json::value_t::object);
CHECK(j == j_reference);
}
SECTION("std::map<const char*, json>")
{
std::map<const char*, json> o {{"a", json(1)}, {"b", json(2.2)}, {"c", json(false)}, {"d", json("string")}, {"e", json()}};
json j(o);
CHECK(j.type() == json::value_t::object);
CHECK(j == j_reference);
}
SECTION("std::multimap<std::string, json>")
{
std::multimap<std::string, json> o {{"a", json(1)}, {"b", json(2.2)}, {"c", json(false)}, {"d", json("string")}, {"e", json()}};
json j(o);
CHECK(j.type() == json::value_t::object);
CHECK(j == j_reference);
}
SECTION("std::unordered_map<std::string, json>")
{
std::unordered_map<std::string, json> o {{"a", json(1)}, {"b", json(2.2)}, {"c", json(false)}, {"d", json("string")}, {"e", json()}};
json j(o);
CHECK(j.type() == json::value_t::object);
CHECK(j == j_reference);
}
SECTION("std::unordered_multimap<std::string, json>")
{
std::unordered_multimap<std::string, json> o {{"a", json(1)}, {"b", json(2.2)}, {"c", json(false)}, {"d", json("string")}, {"e", json()}};
json j(o);
CHECK(j.type() == json::value_t::object);
CHECK(j == j_reference);
}
SECTION("associative container literal")
{
json j({{"a", json(1)}, {"b", json(2.2)}, {"c", json(false)}, {"d", json("string")}, {"e", json()}});
CHECK(j.type() == json::value_t::object);
CHECK(j == j_reference);
}
}
SECTION("create an array (explicit)")
{
SECTION("empty array")
{
json::array_t a;
json j(a);
CHECK(j.type() == json::value_t::array);
}
SECTION("filled array")
{
json::array_t a {json(1), json(2.2), json(false), json("string"), json()};
json j(a);
CHECK(j.type() == json::value_t::array);
}
}
SECTION("create an array (implicit)")
{
// reference array
json::array_t a_reference {json(1), json(2.2), json(false), json("string"), json()};
json j_reference(a_reference);
SECTION("std::list<json>")
{
std::list<json> a {json(1), json(2.2), json(false), json("string"), json()};
json j(a);
CHECK(j.type() == json::value_t::array);
CHECK(j == j_reference);
}
SECTION("std::forward_list<json>")
{
std::forward_list<json> a {json(1), json(2.2), json(false), json("string"), json()};
json j(a);
CHECK(j.type() == json::value_t::array);
CHECK(j == j_reference);
}
SECTION("std::array<json, 5>")
{
std::array<json, 5> a {{json(1), json(2.2), json(false), json("string"), json()}};
json j(a);
CHECK(j.type() == json::value_t::array);
CHECK(j == j_reference);
}
SECTION("std::vector<json>")
{
std::vector<json> a {json(1), json(2.2), json(false), json("string"), json()};
json j(a);
CHECK(j.type() == json::value_t::array);
CHECK(j == j_reference);
}
SECTION("std::deque<json>")
{
std::deque<json> a {json(1), json(2.2), json(false), json("string"), json()};
json j(a);
CHECK(j.type() == json::value_t::array);
CHECK(j == j_reference);
}
SECTION("std::set<json>")
{
std::set<json> a {json(1), json(2.2), json(false), json("string"), json()};
json 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> a {json(1), json(2.2), json(false), json("string"), json()};
json j(a);
CHECK(j.type() == json::value_t::array);
// we cannot really check for equality here
}
SECTION("sequence container literal")
{
json j({json(1), 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 s;
json j(s);
CHECK(j.type() == json::value_t::string);
}
SECTION("filled string")
{
json::string_t s {"Hello world"};
json j(s);
CHECK(j.type() == json::value_t::string);
}
}
SECTION("create a string (implicit)")
{
// reference string
json::string_t s_reference {"Hello world"};
json j_reference(s_reference);
SECTION("std::string")
{
std::string s {"Hello world"};
json j(s);
CHECK(j.type() == json::value_t::string);
CHECK(j == j_reference);
}
SECTION("char[]")
{
char s[] {"Hello world"};
json j(s);
CHECK(j.type() == json::value_t::string);
CHECK(j == j_reference);
}
SECTION("const char*")
{
const char* s {"Hello world"};
json j(s);
CHECK(j.type() == json::value_t::string);
CHECK(j == j_reference);
}
SECTION("string literal")
{
json 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 b{};
json j(b);
CHECK(j.type() == json::value_t::boolean);
}
SECTION("filled boolean (true)")
{
json j(true);
CHECK(j.type() == json::value_t::boolean);
}
SECTION("filled boolean (false)")
{
json j(false);
CHECK(j.type() == json::value_t::boolean);
}
}
SECTION("create an integer number (explicit)")
{
SECTION("uninitialized value")
{
json::number_integer_t n{};
json j(n);
CHECK(j.type() == json::value_t::number_integer);
}
SECTION("initialized value")
{
json::number_integer_t n(42);
json j(n);
CHECK(j.type() == json::value_t::number_integer);
}
}
SECTION("create an integer number (implicit)")
{
// reference object
json::number_integer_t n_reference = 42;
json j_reference(n_reference);
SECTION("short")
{
short n = 42;
json j(n);
CHECK(j.type() == json::value_t::number_integer);
CHECK(j == j_reference);
}
SECTION("unsigned short")
{
unsigned short n = 42;
json j(n);
CHECK(j.type() == json::value_t::number_integer);
CHECK(j == j_reference);
}
SECTION("int")
{
int n = 42;
json j(n);
CHECK(j.type() == json::value_t::number_integer);
CHECK(j == j_reference);
}
SECTION("unsigned int")
{
unsigned int n = 42;
json j(n);
CHECK(j.type() == json::value_t::number_integer);
CHECK(j == j_reference);
}
SECTION("long")
{
long n = 42;
json j(n);
CHECK(j.type() == json::value_t::number_integer);
CHECK(j == j_reference);
}
SECTION("unsigned long")
{
short n = 42;
json j(n);
CHECK(j.type() == json::value_t::number_integer);
CHECK(j == j_reference);
}
SECTION("long long")
{
long long n = 42;
json j(n);
CHECK(j.type() == json::value_t::number_integer);
CHECK(j == j_reference);
}
SECTION("unsigned long long")
{
unsigned long long n = 42;
json j(n);
CHECK(j.type() == json::value_t::number_integer);
CHECK(j == j_reference);
}
SECTION("int8_t")
{
int8_t n = 42;
json j(n);
CHECK(j.type() == json::value_t::number_integer);
CHECK(j == j_reference);
}
SECTION("int16_t")
{
int16_t n = 42;
json j(n);
CHECK(j.type() == json::value_t::number_integer);
CHECK(j == j_reference);
}
SECTION("int32_t")
{
int32_t n = 42;
json j(n);
CHECK(j.type() == json::value_t::number_integer);
CHECK(j == j_reference);
}
SECTION("int64_t")
{
int64_t n = 42;
json j(n);
CHECK(j.type() == json::value_t::number_integer);
CHECK(j == j_reference);
}
SECTION("int_fast8_t")
{
int_fast8_t n = 42;
json j(n);
CHECK(j.type() == json::value_t::number_integer);
CHECK(j == j_reference);
}
SECTION("int_fast16_t")
{
int_fast16_t n = 42;
json j(n);
CHECK(j.type() == json::value_t::number_integer);
CHECK(j == j_reference);
}
SECTION("int_fast32_t")
{
int_fast32_t n = 42;
json j(n);
CHECK(j.type() == json::value_t::number_integer);
CHECK(j == j_reference);
}
SECTION("int_fast64_t")
{
int_fast64_t n = 42;
json j(n);
CHECK(j.type() == json::value_t::number_integer);
CHECK(j == j_reference);
}
SECTION("int_least8_t")
{
int_least8_t n = 42;
json j(n);
CHECK(j.type() == json::value_t::number_integer);
CHECK(j == j_reference);
}
SECTION("int_least16_t")
{
int_least16_t n = 42;
json j(n);
CHECK(j.type() == json::value_t::number_integer);
CHECK(j == j_reference);
}
SECTION("int_least32_t")
{
int_least32_t n = 42;
json j(n);
CHECK(j.type() == json::value_t::number_integer);
CHECK(j == j_reference);
}
SECTION("int_least64_t")
{
int_least64_t n = 42;
json j(n);
CHECK(j.type() == json::value_t::number_integer);
CHECK(j == j_reference);
}
SECTION("uint8_t")
{
uint8_t n = 42;
json j(n);
CHECK(j.type() == json::value_t::number_integer);
CHECK(j == j_reference);
}
SECTION("uint16_t")
{
uint16_t n = 42;
json j(n);
CHECK(j.type() == json::value_t::number_integer);
CHECK(j == j_reference);
}
SECTION("uint32_t")
{
uint32_t n = 42;
json j(n);
CHECK(j.type() == json::value_t::number_integer);
CHECK(j == j_reference);
}
SECTION("uint64_t")
{
uint64_t n = 42;
json j(n);
CHECK(j.type() == json::value_t::number_integer);
CHECK(j == j_reference);
}
SECTION("uint_fast8_t")
{
uint_fast8_t n = 42;
json j(n);
CHECK(j.type() == json::value_t::number_integer);
CHECK(j == j_reference);
}
SECTION("uint_fast16_t")
{
uint_fast16_t n = 42;
json j(n);
CHECK(j.type() == json::value_t::number_integer);
CHECK(j == j_reference);
}
SECTION("uint_fast32_t")
{
uint_fast32_t n = 42;
json j(n);
CHECK(j.type() == json::value_t::number_integer);
CHECK(j == j_reference);
}
SECTION("uint_fast64_t")
{
uint_fast64_t n = 42;
json j(n);
CHECK(j.type() == json::value_t::number_integer);
CHECK(j == j_reference);
}
SECTION("uint_least8_t")
{
uint_least8_t n = 42;
json j(n);
CHECK(j.type() == json::value_t::number_integer);
CHECK(j == j_reference);
}
SECTION("uint_least16_t")
{
uint_least16_t n = 42;
json j(n);
CHECK(j.type() == json::value_t::number_integer);
CHECK(j == j_reference);
}
SECTION("uint_least32_t")
{
uint_least32_t n = 42;
json j(n);
CHECK(j.type() == json::value_t::number_integer);
CHECK(j == j_reference);
}
SECTION("uint_least64_t")
{
uint_least64_t n = 42;
json j(n);
CHECK(j.type() == json::value_t::number_integer);
CHECK(j == j_reference);
}
SECTION("integer literal without suffix")
{
json 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_integer);
CHECK(j == j_reference);
}
SECTION("integer literal with l suffix")
{
json 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_integer);
CHECK(j == j_reference);
}
SECTION("integer literal with ll suffix")
{
json 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_integer);
CHECK(j == j_reference);
}
}
SECTION("create a floating-point number (explicit)")
{
SECTION("uninitialized value")
{
json::number_float_t n{};
json j(n);
CHECK(j.type() == json::value_t::number_float);
}
SECTION("initialized value")
{
json::number_float_t n(42.23);
json j(n);
CHECK(j.type() == json::value_t::number_float);
}
}
SECTION("create a floating-point number (implicit)")
{
// reference object
json::number_float_t n_reference = 42.23;
json j_reference(n_reference);
SECTION("float")
{
float n = 42.23;
json j(n);
CHECK(j.type() == json::value_t::number_float);
CHECK(j.m_value.number_float == Approx(j_reference.m_value.number_float));
}
SECTION("double")
{
double n = 42.23;
json j(n);
CHECK(j.type() == json::value_t::number_float);
CHECK(j.m_value.number_float == Approx(j_reference.m_value.number_float));
}
SECTION("long double")
{
long double n = 42.23;
json j(n);
CHECK(j.type() == json::value_t::number_float);
CHECK(j.m_value.number_float == Approx(j_reference.m_value.number_float));
}
SECTION("floating-point literal without suffix")
{
json j(42.23);
CHECK(j.type() == json::value_t::number_float);
CHECK(j.m_value.number_float == Approx(j_reference.m_value.number_float));
}
SECTION("integer literal with f suffix")
{
json j(42.23f);
CHECK(j.type() == json::value_t::number_float);
CHECK(j.m_value.number_float == Approx(j_reference.m_value.number_float));
}
SECTION("integer literal with l suffix")
{
json j(42.23l);
CHECK(j.type() == json::value_t::number_float);
CHECK(j.m_value.number_float == Approx(j_reference.m_value.number_float));
}
}
SECTION("create a container (array or object) from an initializer list")
{
SECTION("empty initializer list")
{
SECTION("explicit")
{
std::initializer_list<json> l;
json j(l);
CHECK(j.type() == json::value_t::object);
}
SECTION("implicit")
{
json j {};
CHECK(j.type() == json::value_t::null);
}
}
SECTION("one element")
{
SECTION("array")
{
SECTION("explicit")
{
std::initializer_list<json> l = {json(json::array_t())};
json j(l);
CHECK(j.type() == json::value_t::array);
}
SECTION("implicit")
{
json j {json::array_t()};
CHECK(j.type() == json::value_t::array);
}
}
SECTION("object")
{
SECTION("explicit")
{
std::initializer_list<json> l = {json(json::object_t())};
json j(l);
CHECK(j.type() == json::value_t::array);
}
SECTION("implicit")
{
json j {json::object_t()};
CHECK(j.type() == json::value_t::array);
}
}
SECTION("string")
{
SECTION("explicit")
{
std::initializer_list<json> l = {json("Hello world")};
json j(l);
CHECK(j.type() == json::value_t::array);
}
SECTION("implicit")
{
json j {"Hello world"};
CHECK(j.type() == json::value_t::array);
}
}
SECTION("boolean")
{
SECTION("explicit")
{
std::initializer_list<json> l = {json(true)};
json j(l);
CHECK(j.type() == json::value_t::array);
}
SECTION("implicit")
{
json j {true};
CHECK(j.type() == json::value_t::array);
}
}
SECTION("number (integer)")
{
SECTION("explicit")
{
std::initializer_list<json> l = {json(1)};
json j(l);
CHECK(j.type() == json::value_t::array);
}
SECTION("implicit")
{
json j {1};
CHECK(j.type() == json::value_t::array);
}
}
SECTION("number (floating-point)")
{
SECTION("explicit")
{
std::initializer_list<json> l = {json(42.23)};
json j(l);
CHECK(j.type() == json::value_t::array);
}
SECTION("implicit")
{
json j {42.23};
CHECK(j.type() == json::value_t::array);
}
}
}
SECTION("more elements")
{
SECTION("explicit")
{
std::initializer_list<json> l = {1, 42.23, true, nullptr, json::object_t(), json::array_t()};
json j(l);
CHECK(j.type() == json::value_t::array);
}
SECTION("implicit")
{
json j {1, 42.23, true, nullptr, json::object_t(), json::array_t()};
CHECK(j.type() == json::value_t::array);
}
}
SECTION("implicit type deduction")
{
SECTION("object")
{
json j { {"one", 1}, {"two", 2.2}, {"three", false} };
CHECK(j.type() == json::value_t::object);
}
SECTION("array")
{
json j { {"one", 1}, {"two", 2.2}, {"three", false}, 13 };
CHECK(j.type() == json::value_t::array);
}
}
SECTION("explicit type deduction")
{
SECTION("empty object")
{
json j = json::object();
CHECK(j.type() == json::value_t::object);
}
SECTION("object")
{
json j = json::object({ {"one", 1}, {"two", 2.2}, {"three", false} });
CHECK(j.type() == json::value_t::object);
}
SECTION("object with error")
{
CHECK_THROWS_AS(json::object({ {"one", 1}, {"two", 2.2}, {"three", false}, 13 }), std::logic_error);
}
SECTION("empty array")
{
json j = json::array();
CHECK(j.type() == json::value_t::array);
}
SECTION("array")
{
json j = json::array({ {"one", 1}, {"two", 2.2}, {"three", false} });
CHECK(j.type() == json::value_t::array);
}
}
}
}
TEST_CASE("other constructors and destructor")
{
SECTION("copy constructor")
{
SECTION("object")
{
json j {{"foo", 1}, {"bar", false}};
json k(j);
CHECK(j == k);
}
SECTION("array")
{
json j {"foo", 1, 42.23, false};
json k(j);
CHECK(j == k);
}
SECTION("null")
{
json j(nullptr);
json k(j);
CHECK(j == k);
}
SECTION("boolean")
{
json j(true);
json k(j);
CHECK(j == k);
}
SECTION("string")
{
json j("Hello world");
json k(j);
CHECK(j == k);
}
SECTION("number (integer)")
{
json j(42);
json k(j);
CHECK(j == k);
}
SECTION("number (floating-point)")
{
json j(42.23);
json k(j);
CHECK(j == k);
}
}
SECTION("move constructor")
{
json j {{"foo", "bar"}, {"baz", {1, 2, 3, 4}}, {"a", 42.23}, {"b", nullptr}};
CHECK(j.type() == json::value_t::object);
json k(std::move(j));
CHECK(k.type() == json::value_t::object);
CHECK(j.type() == json::value_t::null);
}
SECTION("copy assignment")
{
SECTION("object")
{
json j {{"foo", 1}, {"bar", false}};
json k;
k = j;
CHECK(j == k);
}
SECTION("array")
{
json j {"foo", 1, 42.23, false};
json k;
k = j;
CHECK(j == k);
}
SECTION("null")
{
json j(nullptr);
json k;
k = j;
CHECK(j == k);
}
SECTION("boolean")
{
json j(true);
json k;
k = j;
CHECK(j == k);
}
SECTION("string")
{
json j("Hello world");
json k;
k = j;
CHECK(j == k);
}
SECTION("number (integer)")
{
json j(42);
json k;
k = j;
CHECK(j == k);
}
SECTION("number (floating-point)")
{
json j(42.23);
json k;
k = j;
CHECK(j == k);
}
}
SECTION("destructor")
{
SECTION("object")
{
auto j = new json {{"foo", 1}, {"bar", false}};
delete j;
}
SECTION("array")
{
auto j = new json {"foo", 1, false, 23.42};
delete j;
}
SECTION("string")
{
auto j = new json("Hello world");
delete j;
}
}
}
TEST_CASE("object inspection")
{
SECTION("serialization")
{
json j {{"object", json::object()}, {"array", {1, 2, 3, 4}}, {"number", 42}, {"boolean", false}, {"null", nullptr}, {"string", "Hello world"} };
SECTION("no indent / indent=-1")
{
CHECK(j.dump() ==
"{\"array\":[1,2,3,4],\"boolean\":false,\"null\":null,\"number\":42,\"object\":{},\"string\":\"Hello world\"}");
CHECK(j.dump() == j.dump(-1));
}
SECTION("indent=0")
{
CHECK(j.dump(0) ==
"{\n\"array\": [\n1,\n2,\n3,\n4\n],\n\"boolean\": false,\n\"null\": null,\n\"number\": 42,\n\"object\": {},\n\"string\": \"Hello world\"\n}");
}
SECTION("indent=4")
{
CHECK(j.dump(4) ==
"{\n \"array\": [\n 1,\n 2,\n 3,\n 4\n ],\n \"boolean\": false,\n \"null\": null,\n \"number\": 42,\n \"object\": {},\n \"string\": \"Hello world\"\n}");
}
SECTION("dump and floating-point numbers")
{
auto s = json(42.23).dump();
CHECK(s.find("42.23") != std::string::npos);
}
}
SECTION("return the type of the object (explicit)")
{
SECTION("null")
{
json j = nullptr;
CHECK(j.type() == json::value_t::null);
}
SECTION("object")
{
json j = {{"foo", "bar"}};
CHECK(j.type() == json::value_t::object);
}
SECTION("array")
{
json j = {1, 2, 3, 4};
CHECK(j.type() == json::value_t::array);
}
SECTION("boolean")
{
json j = true;
CHECK(j.type() == json::value_t::boolean);
}
SECTION("string")
{
json j = "Hello world";
CHECK(j.type() == json::value_t::string);
}
SECTION("number (integer)")
{
json j = 23;
CHECK(j.type() == json::value_t::number_integer);
}
SECTION("number (floating-point)")
{
json j = 42.23;
CHECK(j.type() == json::value_t::number_float);
}
}
SECTION("return the type of the object (implicit)")
{
SECTION("null")
{
json j = nullptr;
json::value_t t = j;
CHECK(t == j.type());
}
SECTION("object")
{
json j = {{"foo", "bar"}};
json::value_t t = j;
CHECK(t == j.type());
}
SECTION("array")
{
json j = {1, 2, 3, 4};
json::value_t t = j;
CHECK(t == j.type());
}
SECTION("boolean")
{
json j = true;
json::value_t t = j;
CHECK(t == j.type());
}
SECTION("string")
{
json j = "Hello world";
json::value_t t = j;
CHECK(t == j.type());
}
SECTION("number (integer)")
{
json j = 23;
json::value_t t = j;
CHECK(t == j.type());
}
SECTION("number (floating-point)")
{
json j = 42.23;
json::value_t t = j;
CHECK(t == j.type());
}
}
}
TEST_CASE("value conversion")
{
SECTION("get an object (explicit)")
{
json::object_t o_reference = {{"object", json::object()}, {"array", {1, 2, 3, 4}}, {"number", 42}, {"boolean", false}, {"null", nullptr}, {"string", "Hello world"} };
json j(o_reference);
SECTION("json::object_t")
{
json::object_t o = j.get<json::object_t>();
CHECK(json(o) == j);
}
SECTION("std::map<std::string, json>")
{
std::map<std::string, json> o = j.get<std::map<std::string, json>>();
CHECK(json(o) == j);
}
SECTION("std::multimap<std::string, json>")
{
std::multimap<std::string, json> o = j.get<std::multimap<std::string, json>>();
CHECK(json(o) == j);
}
SECTION("std::unordered_map<std::string, json>")
{
std::unordered_map<std::string, json> o = j.get<std::unordered_map<std::string, json>>();
CHECK(json(o) == j);
}
SECTION("std::unordered_multimap<std::string, json>")
{
std::unordered_multimap<std::string, json> o = j.get<std::unordered_multimap<std::string, json>>();
CHECK(json(o) == j);
}
SECTION("exception in case of a non-object type")
{
CHECK_THROWS_AS(json(json::value_t::null).get<json::object_t>(), std::logic_error);
CHECK_THROWS_AS(json(json::value_t::array).get<json::object_t>(), std::logic_error);
CHECK_THROWS_AS(json(json::value_t::string).get<json::object_t>(), std::logic_error);
CHECK_THROWS_AS(json(json::value_t::boolean).get<json::object_t>(), std::logic_error);
CHECK_THROWS_AS(json(json::value_t::number_integer).get<json::object_t>(), std::logic_error);
CHECK_THROWS_AS(json(json::value_t::number_float).get<json::object_t>(), std::logic_error);
}
}
SECTION("get an object (implicit)")
{
json::object_t o_reference = {{"object", json::object()}, {"array", {1, 2, 3, 4}}, {"number", 42}, {"boolean", false}, {"null", nullptr}, {"string", "Hello world"} };
json j(o_reference);
SECTION("json::object_t")
{
json::object_t o = j;
CHECK(json(o) == j);
}
SECTION("std::map<std::string, json>")
{
std::map<std::string, json> o = j;
CHECK(json(o) == j);
}
SECTION("std::multimap<std::string, json>")
{
std::multimap<std::string, json> o = j;
CHECK(json(o) == j);
}
SECTION("std::unordered_map<std::string, json>")
{
std::unordered_map<std::string, json> o = j;
CHECK(json(o) == j);
}
SECTION("std::unordered_multimap<std::string, json>")
{
std::unordered_multimap<std::string, json> o = j;
CHECK(json(o) == j);
}
}
SECTION("get an array (explicit)")
{
json::array_t a_reference {json(1), json(2.2), json(false), json("string"), json()};
json j(a_reference);
SECTION("json::array_t")
{
json::array_t a = j.get<json::array_t>();
CHECK(json(a) == j);
}
SECTION("std::list<json>")
{
std::list<json> a = j.get<std::list<json>>();
CHECK(json(a) == j);
}
SECTION("std::forward_list<json>")
{
std::forward_list<json> a = j.get<std::forward_list<json>>();
CHECK(json(a) == j);
}
SECTION("std::vector<json>")
{
std::vector<json> a = j.get<std::vector<json>>();
CHECK(json(a) == j);
}
SECTION("std::deque<json>")
{
std::deque<json> a = j.get<std::deque<json>>();
CHECK(json(a) == j);
}
SECTION("exception in case of a non-array type")
{
CHECK_THROWS_AS(json(json::value_t::null).get<json::array_t>(), std::logic_error);
CHECK_THROWS_AS(json(json::value_t::object).get<json::array_t>(), std::logic_error);
CHECK_THROWS_AS(json(json::value_t::string).get<json::array_t>(), std::logic_error);
CHECK_THROWS_AS(json(json::value_t::boolean).get<json::array_t>(), std::logic_error);
CHECK_THROWS_AS(json(json::value_t::number_integer).get<json::array_t>(), std::logic_error);
CHECK_THROWS_AS(json(json::value_t::number_float).get<json::array_t>(), std::logic_error);
}
}
SECTION("get an array (implicit)")
{
json::array_t a_reference {json(1), json(2.2), json(false), json("string"), json()};
json j(a_reference);
SECTION("json::array_t")
{
json::array_t a = j;
CHECK(json(a) == j);
}
SECTION("std::list<json>")
{
std::list<json> a = j;
CHECK(json(a) == j);
}
SECTION("std::forward_list<json>")
{
std::forward_list<json> a = j;
CHECK(json(a) == j);
}
SECTION("std::vector<json>")
{
std::vector<json> a = j;
CHECK(json(a) == j);
}
SECTION("std::deque<json>")
{
std::deque<json> a = j;
CHECK(json(a) == j);
}
}
SECTION("get a string (explicit)")
{
json::string_t s_reference {"Hello world"};
json j(s_reference);
SECTION("string_t")
{
json::string_t s = j.get<json::string_t>();
CHECK(json(s) == j);
}
SECTION("std::string")
{
std::string s = j.get<std::string>();
CHECK(json(s) == j);
}
SECTION("exception in case of a non-string type")
{
CHECK_THROWS_AS(json(json::value_t::null).get<json::string_t>(), std::logic_error);
CHECK_THROWS_AS(json(json::value_t::object).get<json::string_t>(), std::logic_error);
CHECK_THROWS_AS(json(json::value_t::array).get<json::string_t>(), std::logic_error);
CHECK_THROWS_AS(json(json::value_t::boolean).get<json::string_t>(), std::logic_error);
CHECK_THROWS_AS(json(json::value_t::number_integer).get<json::string_t>(), std::logic_error);
CHECK_THROWS_AS(json(json::value_t::number_float).get<json::string_t>(), std::logic_error);
}
}
SECTION("get a string (implicit)")
{
json::string_t s_reference {"Hello world"};
json j(s_reference);
SECTION("string_t")
{
json::string_t s = j;
CHECK(json(s) == j);
}
SECTION("std::string")
{
std::string s = j;
CHECK(json(s) == j);
}
}
SECTION("get a boolean (explicit)")
{
json::boolean_t b_reference {true};
json j(b_reference);
SECTION("boolean_t")
{
json::boolean_t b = j.get<json::boolean_t>();
CHECK(json(b) == j);
}
SECTION("bool")
{
bool b = j.get<bool>();
CHECK(json(b) == j);
}
SECTION("exception in case of a non-string type")
{
CHECK_THROWS_AS(json(json::value_t::null).get<json::boolean_t>(), std::logic_error);
CHECK_THROWS_AS(json(json::value_t::object).get<json::boolean_t>(), std::logic_error);
CHECK_THROWS_AS(json(json::value_t::array).get<json::boolean_t>(), std::logic_error);
CHECK_THROWS_AS(json(json::value_t::string).get<json::boolean_t>(), std::logic_error);
CHECK_THROWS_AS(json(json::value_t::number_integer).get<json::boolean_t>(), std::logic_error);
CHECK_THROWS_AS(json(json::value_t::number_float).get<json::boolean_t>(), std::logic_error);
}
}
SECTION("get a boolean (implicit)")
{
json::boolean_t b_reference {true};
json j(b_reference);
SECTION("boolean_t")
{
json::boolean_t b = j;
CHECK(json(b) == j);
}
SECTION("bool")
{
bool b = j;
CHECK(json(b) == j);
}
}
SECTION("get an integer number (explicit)")
{
json::number_integer_t n_reference {42};
json j(n_reference);
SECTION("number_integer_t")
{
json::number_integer_t n = j.get<json::number_integer_t>();
CHECK(json(n) == j);
}
SECTION("short")
{
short n = j.get<short>();
CHECK(json(n) == j);
}
SECTION("unsigned short")
{
unsigned short n = j.get<unsigned short>();
CHECK(json(n) == j);
}
SECTION("int")
{
int n = j.get<int>();
CHECK(json(n) == j);
}
SECTION("unsigned int")
{
unsigned int n = j.get<unsigned int>();
CHECK(json(n) == j);
}
SECTION("long")
{
long n = j.get<long>();
CHECK(json(n) == j);
}
SECTION("unsigned long")
{
unsigned long n = j.get<unsigned long>();
CHECK(json(n) == j);
}
SECTION("long long")
{
long long n = j.get<long long>();
CHECK(json(n) == j);
}
SECTION("unsigned long long")
{
unsigned long long n = j.get<unsigned long long>();
CHECK(json(n) == j);
}
SECTION("int8_t")
{
int8_t n = j.get<int8_t>();
CHECK(json(n) == j);
}
SECTION("int16_t")
{
int16_t n = j.get<int16_t>();
CHECK(json(n) == j);
}
SECTION("int32_t")
{
int32_t n = j.get<int32_t>();
CHECK(json(n) == j);
}
SECTION("int64_t")
{
int64_t n = j.get<int64_t>();
CHECK(json(n) == j);
}
SECTION("int8_fast_t")
{
int_fast8_t n = j.get<int_fast8_t>();
CHECK(json(n) == j);
}
SECTION("int16_fast_t")
{
int_fast16_t n = j.get<int_fast16_t>();
CHECK(json(n) == j);
}
SECTION("int32_fast_t")
{
int_fast32_t n = j.get<int_fast32_t>();
CHECK(json(n) == j);
}
SECTION("int64_fast_t")
{
int_fast64_t n = j.get<int_fast64_t>();
CHECK(json(n) == j);
}
SECTION("int8_least_t")
{
int_least8_t n = j.get<int_least8_t>();
CHECK(json(n) == j);
}
SECTION("int16_least_t")
{
int_least16_t n = j.get<int_least16_t>();
CHECK(json(n) == j);
}
SECTION("int32_least_t")
{
int_least32_t n = j.get<int_least32_t>();
CHECK(json(n) == j);
}
SECTION("int64_least_t")
{
int_least64_t n = j.get<int_least64_t>();
CHECK(json(n) == j);
}
SECTION("uint8_t")
{
uint8_t n = j.get<uint8_t>();
CHECK(json(n) == j);
}
SECTION("uint16_t")
{
uint16_t n = j.get<uint16_t>();
CHECK(json(n) == j);
}
SECTION("uint32_t")
{
uint32_t n = j.get<uint32_t>();
CHECK(json(n) == j);
}
SECTION("uint64_t")
{
uint64_t n = j.get<uint64_t>();
CHECK(json(n) == j);
}
SECTION("uint8_fast_t")
{
uint_fast8_t n = j.get<uint_fast8_t>();
CHECK(json(n) == j);
}
SECTION("uint16_fast_t")
{
uint_fast16_t n = j.get<uint_fast16_t>();
CHECK(json(n) == j);
}
SECTION("uint32_fast_t")
{
uint_fast32_t n = j.get<uint_fast32_t>();
CHECK(json(n) == j);
}
SECTION("uint64_fast_t")
{
uint_fast64_t n = j.get<uint_fast64_t>();
CHECK(json(n) == j);
}
SECTION("uint8_least_t")
{
uint_least8_t n = j.get<uint_least8_t>();
CHECK(json(n) == j);
}
SECTION("uint16_least_t")
{
uint_least16_t n = j.get<uint_least16_t>();
CHECK(json(n) == j);
}
SECTION("uint32_least_t")
{
uint_least32_t n = j.get<uint_least32_t>();
CHECK(json(n) == j);
}
SECTION("uint64_least_t")
{
uint_least64_t n = j.get<uint_least64_t>();
CHECK(json(n) == j);
}
SECTION("exception in case of a non-number type")
{
CHECK_THROWS_AS(json(json::value_t::null).get<json::number_integer_t>(), std::logic_error);
CHECK_THROWS_AS(json(json::value_t::object).get<json::number_integer_t>(), std::logic_error);
CHECK_THROWS_AS(json(json::value_t::array).get<json::number_integer_t>(), std::logic_error);
CHECK_THROWS_AS(json(json::value_t::string).get<json::number_integer_t>(), std::logic_error);
CHECK_THROWS_AS(json(json::value_t::boolean).get<json::number_integer_t>(), std::logic_error);
CHECK_NOTHROW(json(json::value_t::number_float).get<json::number_integer_t>());
}
}
SECTION("get an integer number (implicit)")
{
json::number_integer_t n_reference {42};
json j(n_reference);
SECTION("number_integer_t")
{
json::number_integer_t n = j.get<json::number_integer_t>();
CHECK(json(n) == j);
}
SECTION("short")
{
short n = j;
CHECK(json(n) == j);
}
SECTION("unsigned short")
{
unsigned short n = j;
CHECK(json(n) == j);
}
SECTION("int")
{
int n = j;
CHECK(json(n) == j);
}
SECTION("unsigned int")
{
unsigned int n = j;
CHECK(json(n) == j);
}
SECTION("long")
{
long n = j;
CHECK(json(n) == j);
}
SECTION("unsigned long")
{
unsigned long n = j;
CHECK(json(n) == j);
}
SECTION("long long")
{
long long n = j;
CHECK(json(n) == j);
}
SECTION("unsigned long long")
{
unsigned long long n = j;
CHECK(json(n) == j);
}
SECTION("int8_t")
{
int8_t n = j;
CHECK(json(n) == j);
}
SECTION("int16_t")
{
int16_t n = j;
CHECK(json(n) == j);
}
SECTION("int32_t")
{
int32_t n = j;
CHECK(json(n) == j);
}
SECTION("int64_t")
{
int64_t n = j;
CHECK(json(n) == j);
}
SECTION("int8_fast_t")
{
int_fast8_t n = j;
CHECK(json(n) == j);
}
SECTION("int16_fast_t")
{
int_fast16_t n = j;
CHECK(json(n) == j);
}
SECTION("int32_fast_t")
{
int_fast32_t n = j;
CHECK(json(n) == j);
}
SECTION("int64_fast_t")
{
int_fast64_t n = j;
CHECK(json(n) == j);
}
SECTION("int8_least_t")
{
int_least8_t n = j;
CHECK(json(n) == j);
}
SECTION("int16_least_t")
{
int_least16_t n = j;
CHECK(json(n) == j);
}
SECTION("int32_least_t")
{
int_least32_t n = j;
CHECK(json(n) == j);
}
SECTION("int64_least_t")
{
int_least64_t n = j;
CHECK(json(n) == j);
}
SECTION("uint8_t")
{
uint8_t n = j;
CHECK(json(n) == j);
}
SECTION("uint16_t")
{
uint16_t n = j;
CHECK(json(n) == j);
}
SECTION("uint32_t")
{
uint32_t n = j;
CHECK(json(n) == j);
}
SECTION("uint64_t")
{
uint64_t n = j;
CHECK(json(n) == j);
}
SECTION("uint8_fast_t")
{
uint_fast8_t n = j;
CHECK(json(n) == j);
}
SECTION("uint16_fast_t")
{
uint_fast16_t n = j;
CHECK(json(n) == j);
}
SECTION("uint32_fast_t")
{
uint_fast32_t n = j;
CHECK(json(n) == j);
}
SECTION("uint64_fast_t")
{
uint_fast64_t n = j;
CHECK(json(n) == j);
}
SECTION("uint8_least_t")
{
uint_least8_t n = j;
CHECK(json(n) == j);
}
SECTION("uint16_least_t")
{
uint_least16_t n = j;
CHECK(json(n) == j);
}
SECTION("uint32_least_t")
{
uint_least32_t n = j;
CHECK(json(n) == j);
}
SECTION("uint64_least_t")
{
uint_least64_t n = j;
CHECK(json(n) == j);
}
}
SECTION("get a floating-point number (explicit)")
{
json::number_float_t n_reference {42.23};
json j(n_reference);
SECTION("number_float_t")
{
json::number_float_t n = j.get<json::number_float_t>();
CHECK(json(n).m_value.number_float == Approx(j.m_value.number_float));
}
SECTION("float")
{
float n = j.get<float>();
CHECK(json(n).m_value.number_float == Approx(j.m_value.number_float));
}
SECTION("double")
{
double n = j.get<double>();
CHECK(json(n).m_value.number_float == Approx(j.m_value.number_float));
}
SECTION("exception in case of a non-string type")
{
CHECK_THROWS_AS(json(json::value_t::null).get<json::number_float_t>(), std::logic_error);
CHECK_THROWS_AS(json(json::value_t::object).get<json::number_float_t>(), std::logic_error);
CHECK_THROWS_AS(json(json::value_t::array).get<json::number_float_t>(), std::logic_error);
CHECK_THROWS_AS(json(json::value_t::string).get<json::number_float_t>(), std::logic_error);
CHECK_THROWS_AS(json(json::value_t::boolean).get<json::number_float_t>(), std::logic_error);
CHECK_NOTHROW(json(json::value_t::number_integer).get<json::number_float_t>());
}
}
SECTION("get a floating-point number (implicit)")
{
json::number_float_t n_reference {42.23};
json j(n_reference);
SECTION("number_float_t")
{
json::number_float_t n = j;
CHECK(json(n).m_value.number_float == Approx(j.m_value.number_float));
}
SECTION("float")
{
float n = j;
CHECK(json(n).m_value.number_float == Approx(j.m_value.number_float));
}
SECTION("double")
{
double n = j;
CHECK(json(n).m_value.number_float == Approx(j.m_value.number_float));
}
}
}
TEST_CASE("element access")
{
SECTION("array")
{
json j = {1, true, nullptr, "string", 42.23, json::object(), {1, 2, 3}};
const json j_const = j;
SECTION("access specified element with bounds checking")
{
SECTION("access within bounds")
{
CHECK(j.at(0) == json(1));
CHECK(j.at(1) == json(true));
CHECK(j.at(2) == json(nullptr));
CHECK(j.at(3) == json("string"));
CHECK(j.at(4) == json(42.23));
CHECK(j.at(5) == json(json::object()));
CHECK(j.at(6) == json({1, 2, 3}));
CHECK(j_const.at(0) == json(1));
CHECK(j_const.at(1) == json(true));
CHECK(j_const.at(2) == json(nullptr));
CHECK(j_const.at(3) == json("string"));
CHECK(j_const.at(4) == json(42.23));
CHECK(j_const.at(5) == json(json::object()));
CHECK(j_const.at(6) == json({1, 2, 3}));
}
SECTION("access outside bounds")
{
CHECK_THROWS_AS(j.at(7), std::out_of_range);
CHECK_THROWS_AS(j_const.at(7), std::out_of_range);
}
SECTION("access on non-array type")
{
SECTION("null")
{
json j_nonarray(json::value_t::null);
const json j_nonarray_const(j_nonarray);
CHECK_THROWS_AS(j_nonarray.at(0), std::runtime_error);
CHECK_THROWS_AS(j_nonarray_const.at(0), std::runtime_error);
}
SECTION("boolean")
{
json j_nonarray(json::value_t::boolean);
const json j_nonarray_const(j_nonarray);
CHECK_THROWS_AS(j_nonarray.at(0), std::runtime_error);
CHECK_THROWS_AS(j_nonarray_const.at(0), std::runtime_error);
}
SECTION("string")
{
json j_nonarray(json::value_t::string);
const json j_nonarray_const(j_nonarray);
CHECK_THROWS_AS(j_nonarray.at(0), std::runtime_error);
CHECK_THROWS_AS(j_nonarray_const.at(0), std::runtime_error);
}
SECTION("object")
{
json j_nonarray(json::value_t::object);
const json j_nonarray_const(j_nonarray);
CHECK_THROWS_AS(j_nonarray.at(0), std::runtime_error);
CHECK_THROWS_AS(j_nonarray_const.at(0), std::runtime_error);
}
SECTION("number (integer)")
{
json j_nonarray(json::value_t::number_integer);
const json j_nonarray_const(j_nonarray);
CHECK_THROWS_AS(j_nonarray.at(0), std::runtime_error);
CHECK_THROWS_AS(j_nonarray_const.at(0), std::runtime_error);
}
SECTION("number (floating-point)")
{
json j_nonarray(json::value_t::number_float);
const json j_nonarray_const(j_nonarray);
CHECK_THROWS_AS(j_nonarray.at(0), std::runtime_error);
CHECK_THROWS_AS(j_nonarray_const.at(0), std::runtime_error);
}
}
}
SECTION("access specified element")
{
SECTION("access within bounds")
{
CHECK(j[0] == json(1));
CHECK(j[1] == json(true));
CHECK(j[2] == json(nullptr));
CHECK(j[3] == json("string"));
CHECK(j[4] == json(42.23));
CHECK(j[5] == json(json::object()));
CHECK(j[6] == json({1, 2, 3}));
CHECK(j_const[0] == json(1));
CHECK(j_const[1] == json(true));
CHECK(j_const[2] == json(nullptr));
CHECK(j_const[3] == json("string"));
CHECK(j_const[4] == json(42.23));
CHECK(j_const[5] == json(json::object()));
CHECK(j_const[6] == json({1, 2, 3}));
}
SECTION("access on non-array type")
{
SECTION("null")
{
json j_nonarray(json::value_t::null);
const json j_nonarray_const(j_nonarray);
CHECK_THROWS_AS(j_nonarray[0], std::runtime_error);
CHECK_THROWS_AS(j_nonarray_const[0], std::runtime_error);
}
SECTION("boolean")
{
json j_nonarray(json::value_t::boolean);
const json j_nonarray_const(j_nonarray);
CHECK_THROWS_AS(j_nonarray[0], std::runtime_error);
CHECK_THROWS_AS(j_nonarray_const[0], std::runtime_error);
}
SECTION("string")
{
json j_nonarray(json::value_t::string);
const json j_nonarray_const(j_nonarray);
CHECK_THROWS_AS(j_nonarray[0], std::runtime_error);
CHECK_THROWS_AS(j_nonarray_const[0], std::runtime_error);
}
SECTION("object")
{
json j_nonarray(json::value_t::object);
const json j_nonarray_const(j_nonarray);
CHECK_THROWS_AS(j_nonarray[0], std::runtime_error);
CHECK_THROWS_AS(j_nonarray_const[0], std::runtime_error);
}
SECTION("number (integer)")
{
json j_nonarray(json::value_t::number_integer);
const json j_nonarray_const(j_nonarray);
CHECK_THROWS_AS(j_nonarray[0], std::runtime_error);
CHECK_THROWS_AS(j_nonarray_const[0], std::runtime_error);
}
SECTION("number (floating-point)")
{
json j_nonarray(json::value_t::number_float);
const json j_nonarray_const(j_nonarray);
CHECK_THROWS_AS(j_nonarray[0], std::runtime_error);
CHECK_THROWS_AS(j_nonarray_const[0], std::runtime_error);
}
}
}
}
SECTION("object")
{
json j = {{"integer", 1}, {"floating", 42.23}, {"null", nullptr}, {"string", "hello world"}, {"boolean", true}, {"object", json::object()}, {"array", {1, 2, 3}}};
const json j_const = j;
SECTION("access specified element with bounds checking")
{
SECTION("access within bounds")
{
CHECK(j.at("integer") == json(1));
CHECK(j.at("boolean") == json(true));
CHECK(j.at("null") == json(nullptr));
CHECK(j.at("string") == json("hello world"));
CHECK(j.at("floating") == json(42.23));
CHECK(j.at("object") == json(json::object()));
CHECK(j.at("array") == json({1, 2, 3}));
CHECK(j_const.at("integer") == json(1));
CHECK(j_const.at("boolean") == json(true));
CHECK(j_const.at("null") == json(nullptr));
CHECK(j_const.at("string") == json("hello world"));
CHECK(j_const.at("floating") == json(42.23));
CHECK(j_const.at("object") == json(json::object()));
CHECK(j_const.at("array") == json({1, 2, 3}));
}
SECTION("access outside bounds")
{
CHECK_THROWS_AS(j.at("foo"), std::out_of_range);
CHECK_THROWS_AS(j_const.at("foo"), std::out_of_range);
}
SECTION("access on non-object type")
{
SECTION("null")
{
json j_nonobject(json::value_t::null);
const json j_nonobject_const(j_nonobject);
CHECK_THROWS_AS(j_nonobject.at("foo"), std::runtime_error);
CHECK_THROWS_AS(j_nonobject_const.at("foo"), std::runtime_error);
}
SECTION("boolean")
{
json j_nonobject(json::value_t::boolean);
const json j_nonobject_const(j_nonobject);
CHECK_THROWS_AS(j_nonobject.at("foo"), std::runtime_error);
CHECK_THROWS_AS(j_nonobject_const.at("foo"), std::runtime_error);
}
SECTION("string")
{
json j_nonobject(json::value_t::string);
const json j_nonobject_const(j_nonobject);
CHECK_THROWS_AS(j_nonobject.at("foo"), std::runtime_error);
CHECK_THROWS_AS(j_nonobject_const.at("foo"), std::runtime_error);
}
SECTION("array")
{
json j_nonobject(json::value_t::array);
const json j_nonobject_const(j_nonobject);
CHECK_THROWS_AS(j_nonobject.at("foo"), std::runtime_error);
CHECK_THROWS_AS(j_nonobject_const.at("foo"), std::runtime_error);
}
SECTION("number (integer)")
{
json j_nonobject(json::value_t::number_integer);
const json j_nonobject_const(j_nonobject);
CHECK_THROWS_AS(j_nonobject.at("foo"), std::runtime_error);
CHECK_THROWS_AS(j_nonobject_const.at("foo"), std::runtime_error);
}
SECTION("number (floating-point)")
{
json j_nonobject(json::value_t::number_float);
const json j_nonobject_const(j_nonobject);
CHECK_THROWS_AS(j_nonobject.at("foo"), std::runtime_error);
CHECK_THROWS_AS(j_nonobject_const.at("foo"), std::runtime_error);
}
}
}
SECTION("access specified element")
{
SECTION("access within bounds")
{
CHECK(j["integer"] == json(1));
CHECK(j[json::object_t::key_type("integer")] == j["integer"]);
CHECK(j["boolean"] == json(true));
CHECK(j[json::object_t::key_type("boolean")] == j["boolean"]);
CHECK(j["null"] == json(nullptr));
CHECK(j[json::object_t::key_type("null")] == j["null"]);
CHECK(j["string"] == json("hello world"));
CHECK(j[json::object_t::key_type("string")] == j["string"]);
CHECK(j["floating"] == json(42.23));
CHECK(j[json::object_t::key_type("floating")] == j["floating"]);
CHECK(j["object"] == json(json::object()));
CHECK(j[json::object_t::key_type("object")] == j["object"]);
CHECK(j["array"] == json({1, 2, 3}));
CHECK(j[json::object_t::key_type("array")] == j["array"]);
}
SECTION("access on non-object type")
{
SECTION("null")
{
json j_nonobject(json::value_t::null);
CHECK_THROWS_AS(j_nonobject["foo"], std::runtime_error);
CHECK_THROWS_AS(j_nonobject[json::object_t::key_type("foo")], std::runtime_error);
}
SECTION("boolean")
{
json j_nonobject(json::value_t::boolean);
CHECK_THROWS_AS(j_nonobject["foo"], std::runtime_error);
CHECK_THROWS_AS(j_nonobject[json::object_t::key_type("foo")], std::runtime_error);
}
SECTION("string")
{
json j_nonobject(json::value_t::string);
CHECK_THROWS_AS(j_nonobject["foo"], std::runtime_error);
CHECK_THROWS_AS(j_nonobject[json::object_t::key_type("foo")], std::runtime_error);
}
SECTION("array")
{
json j_nonobject(json::value_t::array);
CHECK_THROWS_AS(j_nonobject["foo"], std::runtime_error);
CHECK_THROWS_AS(j_nonobject[json::object_t::key_type("foo")], std::runtime_error);
}
SECTION("number (integer)")
{
json j_nonobject(json::value_t::number_integer);
CHECK_THROWS_AS(j_nonobject["foo"], std::runtime_error);
CHECK_THROWS_AS(j_nonobject[json::object_t::key_type("foo")], std::runtime_error);
}
SECTION("number (floating-point)")
{
json j_nonobject(json::value_t::number_float);
CHECK_THROWS_AS(j_nonobject["foo"], std::runtime_error);
CHECK_THROWS_AS(j_nonobject[json::object_t::key_type("foo")], std::runtime_error);
}
}
}
SECTION("find an element in an object")
{
SECTION("existing element")
{
for (auto key :
{"integer", "floating", "null", "string", "boolean", "object", "array"
})
{
CHECK(j.find(key) != j.end());
CHECK(*j.find(key) == j.at(key));
CHECK(j_const.find(key) != j_const.end());
CHECK(*j_const.find(key) == j_const.at(key));
}
}
SECTION("nonexisting element")
{
CHECK(j.find("foo") == j.end());
CHECK(j_const.find("foo") == j_const.end());
}
SECTION("all types")
{
SECTION("null")
{
json j_nonarray(json::value_t::null);
const json j_nonarray_const(j_nonarray);
CHECK(j_nonarray.find("foo") == j_nonarray.end());
CHECK(j_nonarray_const.find("foo") == j_nonarray_const.end());
}
SECTION("string")
{
json j_nonarray(json::value_t::string);
const json j_nonarray_const(j_nonarray);
CHECK(j_nonarray.find("foo") == j_nonarray.end());
CHECK(j_nonarray_const.find("foo") == j_nonarray_const.end());
}
SECTION("object")
{
json j_nonarray(json::value_t::object);
const json j_nonarray_const(j_nonarray);
CHECK(j_nonarray.find("foo") == j_nonarray.end());
CHECK(j_nonarray_const.find("foo") == j_nonarray_const.end());
}
SECTION("array")
{
json j_nonarray(json::value_t::array);
const json j_nonarray_const(j_nonarray);
CHECK(j_nonarray.find("foo") == j_nonarray.end());
CHECK(j_nonarray_const.find("foo") == j_nonarray_const.end());
}
SECTION("boolean")
{
json j_nonarray(json::value_t::boolean);
const json j_nonarray_const(j_nonarray);
CHECK(j_nonarray.find("foo") == j_nonarray.end());
CHECK(j_nonarray_const.find("foo") == j_nonarray_const.end());
}
SECTION("number (integer)")
{
json j_nonarray(json::value_t::number_integer);
const json j_nonarray_const(j_nonarray);
CHECK(j_nonarray.find("foo") == j_nonarray.end());
CHECK(j_nonarray_const.find("foo") == j_nonarray_const.end());
}
SECTION("number (floating-point)")
{
json j_nonarray(json::value_t::number_float);
const json j_nonarray_const(j_nonarray);
CHECK(j_nonarray.find("foo") == j_nonarray.end());
CHECK(j_nonarray_const.find("foo") == j_nonarray_const.end());
}
}
}
}
}
TEST_CASE("iterators")
{
SECTION("boolean")
{
json j = true;
json j_const(j);
SECTION("json + begin/end")
{
json::iterator it = j.begin();
CHECK(it != j.end());
CHECK(*it == j);
it++;
CHECK(it != j.begin());
CHECK(it == j.end());
it--;
CHECK(it == j.begin());
CHECK(it != j.end());
CHECK(*it == j);
++it;
CHECK(it != j.begin());
CHECK(it == j.end());
--it;
CHECK(it == j.begin());
CHECK(it != j.end());
CHECK(*it == j);
}
SECTION("const json + begin/end")
{
json::const_iterator it = j_const.begin();
CHECK(it != j_const.end());
CHECK(*it == j_const);
it++;
CHECK(it != j_const.begin());
CHECK(it == j_const.end());
it--;
CHECK(it == j_const.begin());
CHECK(it != j_const.end());
CHECK(*it == j_const);
++it;
CHECK(it != j_const.begin());
CHECK(it == j_const.end());
--it;
CHECK(it == j_const.begin());
CHECK(it != j_const.end());
CHECK(*it == j_const);
}
SECTION("json + cbegin/cend")
{
json::const_iterator it = j.cbegin();
CHECK(it != j.cend());
CHECK(*it == j);
it++;
CHECK(it != j.cbegin());
CHECK(it == j.cend());
it--;
CHECK(it == j.cbegin());
CHECK(it != j.cend());
CHECK(*it == j);
++it;
CHECK(it != j.cbegin());
CHECK(it == j.cend());
--it;
CHECK(it == j.cbegin());
CHECK(it != j.cend());
CHECK(*it == j);
}
SECTION("const json + cbegin/cend")
{
json::const_iterator it = j_const.cbegin();
CHECK(it != j_const.cend());
CHECK(*it == j_const);
it++;
CHECK(it != j_const.cbegin());
CHECK(it == j_const.cend());
it--;
CHECK(it == j_const.cbegin());
CHECK(it != j_const.cend());
CHECK(*it == j_const);
++it;
CHECK(it != j_const.cbegin());
CHECK(it == j_const.cend());
--it;
CHECK(it == j_const.cbegin());
CHECK(it != j_const.cend());
CHECK(*it == j_const);
}
}
SECTION("string")
{
json j = "hello world";
json j_const(j);
SECTION("json + begin/end")
{
json::iterator it = j.begin();
CHECK(it != j.end());
CHECK(*it == j);
it++;
CHECK(it != j.begin());
CHECK(it == j.end());
it--;
CHECK(it == j.begin());
CHECK(it != j.end());
CHECK(*it == j);
++it;
CHECK(it != j.begin());
CHECK(it == j.end());
--it;
CHECK(it == j.begin());
CHECK(it != j.end());
CHECK(*it == j);
}
SECTION("const json + begin/end")
{
json::const_iterator it = j_const.begin();
CHECK(it != j_const.end());
CHECK(*it == j_const);
it++;
CHECK(it != j_const.begin());
CHECK(it == j_const.end());
it--;
CHECK(it == j_const.begin());
CHECK(it != j_const.end());
CHECK(*it == j_const);
++it;
CHECK(it != j_const.begin());
CHECK(it == j_const.end());
--it;
CHECK(it == j_const.begin());
CHECK(it != j_const.end());
CHECK(*it == j_const);
}
SECTION("json + cbegin/cend")
{
json::const_iterator it = j.cbegin();
CHECK(it != j.cend());
CHECK(*it == j);
it++;
CHECK(it != j.cbegin());
CHECK(it == j.cend());
it--;
CHECK(it == j.cbegin());
CHECK(it != j.cend());
CHECK(*it == j);
++it;
CHECK(it != j.cbegin());
CHECK(it == j.cend());
--it;
CHECK(it == j.cbegin());
CHECK(it != j.cend());
CHECK(*it == j);
}
SECTION("const json + cbegin/cend")
{
json::const_iterator it = j_const.cbegin();
CHECK(it != j_const.cend());
CHECK(*it == j_const);
it++;
CHECK(it != j_const.cbegin());
CHECK(it == j_const.cend());
it--;
CHECK(it == j_const.cbegin());
CHECK(it != j_const.cend());
CHECK(*it == j_const);
++it;
CHECK(it != j_const.cbegin());
CHECK(it == j_const.cend());
--it;
CHECK(it == j_const.cbegin());
CHECK(it != j_const.cend());
CHECK(*it == j_const);
}
}
SECTION("array")
{
json j = {1, 2, 3};
json j_const(j);
SECTION("json + begin/end")
{
json::iterator it_begin = j.begin();
json::iterator it_end = j.end();
auto it = it_begin;
CHECK(it != it_end);
it++;
CHECK(it != it_begin);
CHECK(it != it_end);
++it;
CHECK(it != it_begin);
CHECK(it != it_end);
++it;
CHECK(it != it_begin);
CHECK(it == it_end);
}
SECTION("const json + begin/end")
{
json::const_iterator it_begin = j_const.begin();
json::const_iterator it_end = j_const.end();
auto it = it_begin;
CHECK(it != it_end);
it++;
CHECK(it != it_begin);
CHECK(it != it_end);
++it;
CHECK(it != it_begin);
CHECK(it != it_end);
++it;
CHECK(it != it_begin);
CHECK(it == it_end);
}
SECTION("json + cbegin/cend")
{
json::const_iterator it_begin = j.cbegin();
json::const_iterator it_end = j.cend();
auto it = it_begin;
CHECK(it != it_end);
it++;
CHECK(it != it_begin);
CHECK(it != it_end);
++it;
CHECK(it != it_begin);
CHECK(it != it_end);
++it;
CHECK(it != it_begin);
CHECK(it == it_end);
}
SECTION("const json + cbegin/cend")
{
json::const_iterator it_begin = j.cbegin();
json::const_iterator it_end = j.cend();
auto it = it_begin;
CHECK(it != it_end);
it++;
CHECK(it != it_begin);
CHECK(it != it_end);
++it;
CHECK(it != it_begin);
CHECK(it != it_end);
++it;
CHECK(it != it_begin);
CHECK(it == it_end);
}
}
SECTION("object")
{
json j = {{"one", 1}, {"two", 2}, {"three", 3}};
json j_const(j);
SECTION("json + begin/end")
{
json::iterator it_begin = j.begin();
json::iterator it_end = j.end();
auto it = it_begin;
CHECK(it != it_end);
it++;
CHECK(it != it_begin);
CHECK(it != it_end);
++it;
CHECK(it != it_begin);
CHECK(it != it_end);
++it;
CHECK(it != it_begin);
CHECK(it == it_end);
}
SECTION("const json + begin/end")
{
json::const_iterator it_begin = j_const.begin();
json::const_iterator it_end = j_const.end();
auto it = it_begin;
CHECK(it != it_end);
it++;
CHECK(it != it_begin);
CHECK(it != it_end);
++it;
CHECK(it != it_begin);
CHECK(it != it_end);
++it;
CHECK(it != it_begin);
CHECK(it == it_end);
}
SECTION("json + cbegin/cend")
{
json::const_iterator it_begin = j.cbegin();
json::const_iterator it_end = j.cend();
auto it = it_begin;
CHECK(it != it_end);
it++;
CHECK(it != it_begin);
CHECK(it != it_end);
++it;
CHECK(it != it_begin);
CHECK(it != it_end);
++it;
CHECK(it != it_begin);
CHECK(it == it_end);
}
SECTION("const json + cbegin/cend")
{
json::const_iterator it_begin = j.cbegin();
json::const_iterator it_end = j.cend();
auto it = it_begin;
CHECK(it != it_end);
it++;
CHECK(it != it_begin);
CHECK(it != it_end);
++it;
CHECK(it != it_begin);
CHECK(it != it_end);
++it;
CHECK(it != it_begin);
CHECK(it == it_end);
}
}
SECTION("number (integer)")
{
json j = 23;
json j_const(j);
SECTION("json + begin/end")
{
json::iterator it = j.begin();
CHECK(it != j.end());
CHECK(*it == j);
it++;
CHECK(it != j.begin());
CHECK(it == j.end());
it--;
CHECK(it == j.begin());
CHECK(it != j.end());
CHECK(*it == j);
++it;
CHECK(it != j.begin());
CHECK(it == j.end());
--it;
CHECK(it == j.begin());
CHECK(it != j.end());
CHECK(*it == j);
}
SECTION("const json + begin/end")
{
json::const_iterator it = j_const.begin();
CHECK(it != j_const.end());
CHECK(*it == j_const);
it++;
CHECK(it != j_const.begin());
CHECK(it == j_const.end());
it--;
CHECK(it == j_const.begin());
CHECK(it != j_const.end());
CHECK(*it == j_const);
++it;
CHECK(it != j_const.begin());
CHECK(it == j_const.end());
--it;
CHECK(it == j_const.begin());
CHECK(it != j_const.end());
CHECK(*it == j_const);
}
SECTION("json + cbegin/cend")
{
json::const_iterator it = j.cbegin();
CHECK(it != j.cend());
CHECK(*it == j);
it++;
CHECK(it != j.cbegin());
CHECK(it == j.cend());
it--;
CHECK(it == j.cbegin());
CHECK(it != j.cend());
CHECK(*it == j);
++it;
CHECK(it != j.cbegin());
CHECK(it == j.cend());
--it;
CHECK(it == j.cbegin());
CHECK(it != j.cend());
CHECK(*it == j);
}
SECTION("const json + cbegin/cend")
{
json::const_iterator it = j_const.cbegin();
CHECK(it != j_const.cend());
CHECK(*it == j_const);
it++;
CHECK(it != j_const.cbegin());
CHECK(it == j_const.cend());
it--;
CHECK(it == j_const.cbegin());
CHECK(it != j_const.cend());
CHECK(*it == j_const);
++it;
CHECK(it != j_const.cbegin());
CHECK(it == j_const.cend());
--it;
CHECK(it == j_const.cbegin());
CHECK(it != j_const.cend());
CHECK(*it == j_const);
}
}
SECTION("number (float)")
{
json j = 23.42;
json j_const(j);
SECTION("json + begin/end")
{
json::iterator it = j.begin();
CHECK(it != j.end());
CHECK(*it == j);
it++;
CHECK(it != j.begin());
CHECK(it == j.end());
it--;
CHECK(it == j.begin());
CHECK(it != j.end());
CHECK(*it == j);
++it;
CHECK(it != j.begin());
CHECK(it == j.end());
--it;
CHECK(it == j.begin());
CHECK(it != j.end());
CHECK(*it == j);
}
SECTION("const json + begin/end")
{
json::const_iterator it = j_const.begin();
CHECK(it != j_const.end());
CHECK(*it == j_const);
it++;
CHECK(it != j_const.begin());
CHECK(it == j_const.end());
it--;
CHECK(it == j_const.begin());
CHECK(it != j_const.end());
CHECK(*it == j_const);
++it;
CHECK(it != j_const.begin());
CHECK(it == j_const.end());
--it;
CHECK(it == j_const.begin());
CHECK(it != j_const.end());
CHECK(*it == j_const);
}
SECTION("json + cbegin/cend")
{
json::const_iterator it = j.cbegin();
CHECK(it != j.cend());
CHECK(*it == j);
it++;
CHECK(it != j.cbegin());
CHECK(it == j.cend());
it--;
CHECK(it == j.cbegin());
CHECK(it != j.cend());
CHECK(*it == j);
++it;
CHECK(it != j.cbegin());
CHECK(it == j.cend());
--it;
CHECK(it == j.cbegin());
CHECK(it != j.cend());
CHECK(*it == j);
}
SECTION("const json + cbegin/cend")
{
json::const_iterator it = j_const.cbegin();
CHECK(it != j_const.cend());
CHECK(*it == j_const);
it++;
CHECK(it != j_const.cbegin());
CHECK(it == j_const.cend());
it--;
CHECK(it == j_const.cbegin());
CHECK(it != j_const.cend());
CHECK(*it == j_const);
++it;
CHECK(it != j_const.cbegin());
CHECK(it == j_const.cend());
--it;
CHECK(it == j_const.cbegin());
CHECK(it != j_const.cend());
CHECK(*it == j_const);
}
}
SECTION("null")
{
json j = nullptr;
json j_const(j);
SECTION("json + begin/end")
{
json::iterator it = j.begin();
CHECK(it == j.end());
}
SECTION("const json + begin/end")
{
json::const_iterator it_begin = j_const.begin();
json::const_iterator it_end = j_const.end();
CHECK(it_begin == it_end);
}
SECTION("json + cbegin/cend")
{
json::const_iterator it_begin = j.cbegin();
json::const_iterator it_end = j.cend();
CHECK(it_begin == it_end);
}
SECTION("const json + cbegin/cend")
{
json::const_iterator it_begin = j_const.cbegin();
json::const_iterator it_end = j_const.cend();
CHECK(it_begin == it_end);
}
}
}
TEST_CASE("capacity")
{
SECTION("empty()")
{
SECTION("boolean")
{
json j = true;
json j_const(j);
SECTION("result of empty")
{
CHECK(j.empty() == false);
CHECK(j_const.empty() == false);
}
SECTION("definition of empty")
{
CHECK(j.begin() != j.end());
CHECK(j_const.begin() != j_const.end());
}
}
SECTION("string")
{
json j = "hello world";
json j_const(j);
SECTION("result of empty")
{
CHECK(j.empty() == false);
CHECK(j_const.empty() == false);
}
SECTION("definition of empty")
{
CHECK(j.begin() != j.end());
CHECK(j_const.begin() != j_const.end());
}
}
SECTION("array")
{
SECTION("empty array")
{
json j = json::array();
json j_const(j);
SECTION("result of empty")
{
CHECK(j.empty() == true);
CHECK(j_const.empty() == true);
}
SECTION("definition of empty")
{
CHECK(j.begin() == j.end());
CHECK(j_const.begin() == j_const.end());
}
}
SECTION("filled array")
{
json j = {1, 2, 3};
json j_const(j);
SECTION("result of empty")
{
CHECK(j.empty() == false);
CHECK(j_const.empty() == false);
}
SECTION("definition of empty")
{
CHECK(j.begin() != j.end());
CHECK(j_const.begin() != j_const.end());
}
}
}
SECTION("object")
{
SECTION("empty object")
{
json j = json::object();
json j_const(j);
SECTION("result of empty")
{
CHECK(j.empty() == true);
CHECK(j_const.empty() == true);
}
SECTION("definition of empty")
{
CHECK(j.begin() == j.end());
CHECK(j_const.begin() == j_const.end());
}
}
SECTION("filled object")
{
json j = {{"one", 1}, {"two", 2}, {"three", 3}};
json j_const(j);
SECTION("result of empty")
{
CHECK(j.empty() == false);
CHECK(j_const.empty() == false);
}
SECTION("definition of empty")
{
CHECK(j.begin() != j.end());
CHECK(j_const.begin() != j_const.end());
}
}
}
SECTION("number (integer)")
{
json j = 23;
json j_const(j);
SECTION("result of empty")
{
CHECK(j.empty() == false);
CHECK(j_const.empty() == false);
}
SECTION("definition of empty")
{
CHECK(j.begin() != j.end());
CHECK(j_const.begin() != j_const.end());
}
}
SECTION("number (float)")
{
json j = 23.42;
json j_const(j);
SECTION("result of empty")
{
CHECK(j.empty() == false);
CHECK(j_const.empty() == false);
}
SECTION("definition of empty")
{
CHECK(j.begin() != j.end());
CHECK(j_const.begin() != j_const.end());
}
}
SECTION("null")
{
json j = nullptr;
json j_const(j);
SECTION("result of empty")
{
CHECK(j.empty() == true);
CHECK(j_const.empty() == true);
}
SECTION("definition of empty")
{
CHECK(j.begin() == j.end());
CHECK(j_const.begin() == j_const.end());
}
}
}
SECTION("size()")
{
SECTION("boolean")
{
json j = true;
json j_const(j);
SECTION("result of size")
{
CHECK(j.size() == 1);
CHECK(j_const.size() == 1);
}
SECTION("definition of size")
{
CHECK(std::distance(j.begin(), j.end()) == j.size());
CHECK(std::distance(j_const.begin(), j_const.end()) == j_const.size());
}
}
SECTION("string")
{
json j = "hello world";
json j_const(j);
SECTION("result of size")
{
CHECK(j.size() == 1);
CHECK(j_const.size() == 1);
}
SECTION("definition of size")
{
CHECK(std::distance(j.begin(), j.end()) == j.size());
CHECK(std::distance(j_const.begin(), j_const.end()) == j_const.size());
}
}
SECTION("array")
{
SECTION("empty array")
{
json j = json::array();
json j_const(j);
SECTION("result of size")
{
CHECK(j.size() == 0);
CHECK(j_const.size() == 0);
}
SECTION("definition of size")
{
CHECK(std::distance(j.begin(), j.end()) == j.size());
CHECK(std::distance(j_const.begin(), j_const.end()) == j_const.size());
}
}
SECTION("filled array")
{
json j = {1, 2, 3};
json j_const(j);
SECTION("result of size")
{
CHECK(j.size() == 3);
CHECK(j_const.size() == 3);
}
SECTION("definition of size")
{
CHECK(std::distance(j.begin(), j.end()) == j.size());
CHECK(std::distance(j_const.begin(), j_const.end()) == j_const.size());
}
}
}
SECTION("object")
{
SECTION("empty object")
{
json j = json::object();
json j_const(j);
SECTION("result of size")
{
CHECK(j.size() == 0);
CHECK(j_const.size() == 0);
}
SECTION("definition of size")
{
CHECK(std::distance(j.begin(), j.end()) == j.size());
CHECK(std::distance(j_const.begin(), j_const.end()) == j_const.size());
}
}
SECTION("filled object")
{
json j = {{"one", 1}, {"two", 2}, {"three", 3}};
json j_const(j);
SECTION("result of size")
{
CHECK(j.size() == 3);
CHECK(j_const.size() == 3);
}
SECTION("definition of size")
{
CHECK(std::distance(j.begin(), j.end()) == j.size());
CHECK(std::distance(j_const.begin(), j_const.end()) == j_const.size());
}
}
}
SECTION("number (integer)")
{
json j = 23;
json j_const(j);
SECTION("result of size")
{
CHECK(j.size() == 1);
CHECK(j_const.size() == 1);
}
SECTION("definition of size")
{
CHECK(std::distance(j.begin(), j.end()) == j.size());
CHECK(std::distance(j_const.begin(), j_const.end()) == j_const.size());
}
}
SECTION("number (float)")
{
json j = 23.42;
json j_const(j);
SECTION("result of size")
{
CHECK(j.size() == 1);
CHECK(j_const.size() == 1);
}
SECTION("definition of size")
{
CHECK(std::distance(j.begin(), j.end()) == j.size());
CHECK(std::distance(j_const.begin(), j_const.end()) == j_const.size());
}
}
SECTION("null")
{
json j = nullptr;
json j_const(j);
SECTION("result of size")
{
CHECK(j.size() == 0);
CHECK(j_const.size() == 0);
}
SECTION("definition of size")
{
CHECK(std::distance(j.begin(), j.end()) == j.size());
CHECK(std::distance(j_const.begin(), j_const.end()) == j_const.size());
}
}
}
SECTION("max_size()")
{
SECTION("boolean")
{
json j = true;
json j_const(j);
SECTION("result of max_size")
{
CHECK(j.max_size() == 1);
CHECK(j_const.max_size() == 1);
}
}
SECTION("string")
{
json j = "hello world";
json j_const(j);
SECTION("result of max_size")
{
CHECK(j.max_size() == 1);
CHECK(j_const.max_size() == 1);
}
}
SECTION("array")
{
SECTION("empty array")
{
json j = json::array();
json j_const(j);
SECTION("result of max_size")
{
CHECK(j.max_size() >= j.size());
CHECK(j_const.max_size() >= j_const.size());
}
}
SECTION("filled array")
{
json j = {1, 2, 3};
json j_const(j);
SECTION("result of max_size")
{
CHECK(j.max_size() >= j.size());
CHECK(j_const.max_size() >= j_const.size());
}
}
}
SECTION("object")
{
SECTION("empty object")
{
json j = json::object();
json j_const(j);
SECTION("result of max_size")
{
CHECK(j.max_size() >= j.size());
CHECK(j_const.max_size() >= j_const.size());
}
}
SECTION("filled object")
{
json j = {{"one", 1}, {"two", 2}, {"three", 3}};
json j_const(j);
SECTION("result of max_size")
{
CHECK(j.max_size() >= j.size());
CHECK(j_const.max_size() >= j_const.size());
}
}
}
SECTION("number (integer)")
{
json j = 23;
json j_const(j);
SECTION("result of max_size")
{
CHECK(j.max_size() == 1);
CHECK(j_const.max_size() == 1);
}
}
SECTION("number (float)")
{
json j = 23.42;
json j_const(j);
SECTION("result of max_size")
{
CHECK(j.max_size() == 1);
CHECK(j_const.max_size() == 1);
}
}
SECTION("null")
{
json j = nullptr;
json j_const(j);
SECTION("result of max_size")
{
CHECK(j.max_size() == 0);
CHECK(j_const.max_size() == 0);
}
}
}
}
TEST_CASE("modifiers")
{
SECTION("clear()")
{
SECTION("boolean")
{
json j = true;
j.clear();
CHECK(j == json(json::value_t::boolean));
}
SECTION("string")
{
json j = "hello world";
j.clear();
CHECK(j == json(json::value_t::string));
}
SECTION("array")
{
SECTION("empty array")
{
json j = json::array();
j.clear();
CHECK(j.empty());
CHECK(j == json(json::value_t::array));
}
SECTION("filled array")
{
json j = {1, 2, 3};
j.clear();
CHECK(j.empty());
CHECK(j == json(json::value_t::array));
}
}
SECTION("object")
{
SECTION("empty object")
{
json j = json::object();
j.clear();
CHECK(j.empty());
CHECK(j == json(json::value_t::object));
}
SECTION("filled object")
{
json j = {{"one", 1}, {"two", 2}, {"three", 3}};
j.clear();
CHECK(j.empty());
CHECK(j == json(json::value_t::object));
}
}
SECTION("number (integer)")
{
json j = 23;
j.clear();
CHECK(j == json(json::value_t::number_integer));
}
SECTION("number (float)")
{
json j = 23.42;
j.clear();
CHECK(j == json(json::value_t::number_float));
}
SECTION("null")
{
json j = nullptr;
j.clear();
CHECK(j == json(json::value_t::null));
}
}
SECTION("push_back()")
{
SECTION("to array")
{
SECTION("json&&")
{
SECTION("null")
{
json j;
j.push_back(1);
j.push_back(2);
CHECK(j.type() == json::value_t::array);
CHECK(j == json({1, 2}));
}
SECTION("array")
{
json j = {1, 2, 3};
j.push_back("Hello");
CHECK(j.type() == json::value_t::array);
CHECK(j == json({1, 2, 3, "Hello"}));
}
SECTION("other type")
{
json j = 1;
CHECK_THROWS_AS(j.push_back("Hello"), std::runtime_error);
}
}
SECTION("const json&")
{
SECTION("null")
{
json j;
json k(1);
j.push_back(k);
j.push_back(k);
CHECK(j.type() == json::value_t::array);
CHECK(j == json({1, 1}));
}
SECTION("array")
{
json j = {1, 2, 3};
json k("Hello");
j.push_back(k);
CHECK(j.type() == json::value_t::array);
CHECK(j == json({1, 2, 3, "Hello"}));
}
SECTION("other type")
{
json j = 1;
json k("Hello");
CHECK_THROWS_AS(j.push_back(k), std::runtime_error);
}
}
}
SECTION("to object")
{
SECTION("null")
{
json j;
j.push_back(json::object_t::value_type({"one", 1}));
j.push_back(json::object_t::value_type({"two", 2}));
CHECK(j.type() == json::value_t::object);
CHECK(j.size() == 2);
CHECK(j["one"] == json(1));
CHECK(j["two"] == json(2));
}
SECTION("object")
{
json j(json::value_t::object);
j.push_back(json::object_t::value_type({"one", 1}));
j.push_back(json::object_t::value_type({"two", 2}));
CHECK(j.size() == 2);
CHECK(j["one"] == json(1));
CHECK(j["two"] == json(2));
}
SECTION("other type")
{
json j = 1;
json k("Hello");
CHECK_THROWS_AS(j.push_back(json::object_t::value_type({"one", 1})), std::runtime_error);
}
}
}
SECTION("operator+=")
{
SECTION("to array")
{
SECTION("json&&")
{
SECTION("null")
{
json j;
j += 1;
j += 2;
CHECK(j.type() == json::value_t::array);
CHECK(j == json({1, 2}));
}
SECTION("array")
{
json j = {1, 2, 3};
j += "Hello";
CHECK(j.type() == json::value_t::array);
CHECK(j == json({1, 2, 3, "Hello"}));
}
SECTION("other type")
{
json j = 1;
CHECK_THROWS_AS(j += "Hello", std::runtime_error);
}
}
SECTION("const json&")
{
SECTION("null")
{
json j;
json k(1);
j += k;
j += k;
CHECK(j.type() == json::value_t::array);
CHECK(j == json({1, 1}));
}
SECTION("array")
{
json j = {1, 2, 3};
json k("Hello");
j += k;
CHECK(j.type() == json::value_t::array);
CHECK(j == json({1, 2, 3, "Hello"}));
}
SECTION("other type")
{
json j = 1;
json k("Hello");
CHECK_THROWS_AS(j += k, std::runtime_error);
}
}
}
SECTION("to object")
{
SECTION("null")
{
json j;
j += json::object_t::value_type({"one", 1});
j += json::object_t::value_type({"two", 2});
CHECK(j.type() == json::value_t::object);
CHECK(j.size() == 2);
CHECK(j["one"] == json(1));
CHECK(j["two"] == json(2));
}
SECTION("object")
{
json j(json::value_t::object);
j += json::object_t::value_type({"one", 1});
j += json::object_t::value_type({"two", 2});
CHECK(j.size() == 2);
CHECK(j["one"] == json(1));
CHECK(j["two"] == json(2));
}
SECTION("other type")
{
json j = 1;
json k("Hello");
CHECK_THROWS_AS(j += json::object_t::value_type({"one", 1}), std::runtime_error);
}
}
}
SECTION("swap()")
{
SECTION("json")
{
SECTION("member swap")
{
json j("hello world");
json k(42.23);
j.swap(k);
CHECK(j == json(42.23));
CHECK(k == json("hello world"));
}
SECTION("nonmember swap")
{
json j("hello world");
json k(42.23);
std::swap(j, k);
CHECK(j == json(42.23));
CHECK(k == json("hello world"));
}
}
SECTION("array_t")
{
SECTION("array_t type")
{
json j = {1, 2, 3, 4};
json::array_t a = {"foo", "bar", "baz"};
j.swap(a);
CHECK(j == json({"foo", "bar", "baz"}));
j.swap(a);
CHECK(j == json({1, 2, 3, 4}));
}
SECTION("non-array_t type")
{
json j = 17;
json::array_t a = {"foo", "bar", "baz"};
CHECK_THROWS_AS(j.swap(a), std::runtime_error);
}
}
SECTION("object_t")
{
SECTION("object_t type")
{
json j = {{"one", 1}, {"two", 2}};
json::object_t o = {{"cow", "Kuh"}, {"chicken", "Huhn"}};
j.swap(o);
CHECK(j == json({{"cow", "Kuh"}, {"chicken", "Huhn"}}));
j.swap(o);
CHECK(j == json({{"one", 1}, {"two", 2}}));
}
SECTION("non-object_t type")
{
json j = 17;
json::object_t o = {{"cow", "Kuh"}, {"chicken", "Huhn"}};
CHECK_THROWS_AS(j.swap(o), std::runtime_error);
}
}
SECTION("string_t")
{
SECTION("string_t type")
{
json j = "Hello world";
json::string_t s = "Hallo Welt";
j.swap(s);
CHECK(j == json("Hallo Welt"));
j.swap(s);
CHECK(j == json("Hello world"));
}
SECTION("non-string_t type")
{
json j = 17;
json::string_t s = "Hallo Welt";
CHECK_THROWS_AS(j.swap(s), std::runtime_error);
}
}
}
}
TEST_CASE("lexicographical comparison operators")
{
json j_values =
{
nullptr, nullptr,
17, 42,
3.14159, 23.42,
"foo", "bar",
true, false,
{1, 2, 3}, {"one", "two", "three"},
{{"first", 1}, {"second", 2}}, {{"a", "A"}, {"b", {"B"}}}
};
SECTION("comparison: equal")
{
std::vector<std::vector<bool>> expected =
{
{true, true, false, false, false, false, false, false, false, false, false, false, false, false},
{true, true, false, false, false, false, false, false, false, false, false, false, false, false},
{false, false, true, false, false, false, false, false, false, false, false, false, false, false},
{false, false, false, true, false, false, false, false, false, false, false, false, false, false},
{false, false, false, false, true, false, false, false, false, false, false, false, false, false},
{false, false, false, false, false, true, false, false, false, false, false, false, false, false},
{false, false, false, false, false, false, true, false, false, false, false, false, false, false},
{false, false, false, false, false, false, false, true, false, false, false, false, false, false},
{false, false, false, false, false, false, false, false, true, false, false, false, false, false},
{false, false, false, false, false, false, false, false, false, true, false, false, false, false},
{false, false, false, false, false, false, false, false, false, false, true, false, false, false},
{false, false, false, false, false, false, false, false, false, false, false, true, false, false},
{false, false, false, false, false, false, false, false, false, false, false, false, true, false},
{false, false, false, false, false, false, false, false, false, false, false, false, false, true}
};
for (size_t i = 0; i < j_values.size(); ++i)
{
for (size_t j = 0; j < j_values.size(); ++j)
{
// check precomputed values
CHECK( (j_values[i] == j_values[j]) == expected[i][j] );
}
}
}
SECTION("comparison: not equal")
{
for (size_t i = 0; i < j_values.size(); ++i)
{
for (size_t j = 0; j < j_values.size(); ++j)
{
// check definition
CHECK( (j_values[i] != j_values[j]) == not(j_values[i] == j_values[j]) );
}
}
}
SECTION("comparison: less")
{
std::vector<std::vector<bool>> expected =
{
{false, false, false, false, false, false, false, false, false, false, false, false, false, false},
{false, false, false, false, false, false, false, false, false, false, false, false, false, false},
{false, false, false, true, false, true, false, false, false, false, false, false, false, false},
{false, false, false, false, false, false, false, false, false, false, false, false, false, false},
{false, false, true, true, false, true, false, false, false, false, false, false, false, false},
{false, false, false, true, false, false, false, false, false, false, false, false, false, false},
{false, false, false, false, false, false, false, false, false, false, false, false, false, false},
{false, false, false, false, false, false, true, false, false, false, false, false, false, false},
{false, false, false, false, false, false, false, false, false, false, false, false, false, false},
{false, false, false, false, false, false, false, false, true, false, false, false, false, false},
{false, false, false, false, false, false, false, false, false, false, false, false, false, false},
{false, false, false, false, false, false, false, false, false, false, false, false, false, false},
{false, false, false, false, false, false, false, false, false, false, false, false, false, false},
{false, false, false, false, false, false, false, false, false, false, false, false, true, false}
};
for (size_t i = 0; i < j_values.size(); ++i)
{
for (size_t j = 0; j < j_values.size(); ++j)
{
// check precomputed values
CHECK( (j_values[i] < j_values[j]) == expected[i][j] );
}
}
}
SECTION("comparison: less than or equal equal")
{
for (size_t i = 0; i < j_values.size(); ++i)
{
for (size_t j = 0; j < j_values.size(); ++j)
{
// check definition
CHECK( (j_values[i] <= j_values[j]) == not(j_values[j] < j_values[i]) );
}
}
}
SECTION("comparison: greater than")
{
for (size_t i = 0; i < j_values.size(); ++i)
{
for (size_t j = 0; j < j_values.size(); ++j)
{
// check definition
CHECK( (j_values[i] > j_values[j]) == (j_values[j] < j_values[i]) );
}
}
}
SECTION("comparison: greater than or equal")
{
for (size_t i = 0; i < j_values.size(); ++i)
{
for (size_t j = 0; j < j_values.size(); ++j)
{
// check definition
CHECK( (j_values[i] >= j_values[j]) == not(j_values[i] < j_values[j]) );
}
}
}
}
TEST_CASE("serialization")
{
SECTION("operator<<")
{
SECTION("no given width")
{
std::stringstream ss;
json j = {"foo", 1, 2, 3, false, {{"one", 1}}};
ss << j;
CHECK(ss.str() == "[\"foo\",1,2,3,false,{\"one\":1}]");
}
SECTION("given width")
{
std::stringstream ss;
json j = {"foo", 1, 2, 3, false, {{"one", 1}}};
ss << std::setw(4) << j;
CHECK(ss.str() ==
"[\n \"foo\",\n 1,\n 2,\n 3,\n false,\n {\n \"one\": 1\n }\n]");
}
}
SECTION("operator>>")
{
SECTION("no given width")
{
std::stringstream ss;
json j = {"foo", 1, 2, 3, false, {{"one", 1}}};
j >> ss;
CHECK(ss.str() == "[\"foo\",1,2,3,false,{\"one\":1}]");
}
SECTION("given width")
{
std::stringstream ss;
json j = {"foo", 1, 2, 3, false, {{"one", 1}}};
ss.width(4);
j >> ss;
CHECK(ss.str() ==
"[\n \"foo\",\n 1,\n 2,\n 3,\n false,\n {\n \"one\": 1\n }\n]");
}
}
}
TEST_CASE("deserialization")
{
SECTION("string")
{
auto s = "[\"foo\",1,2,3,false,{\"one\":1}]";
json j = json::parse(s);
CHECK(j == json({"foo", 1, 2, 3, false, {{"one", 1}}}));
}
SECTION("operator<<")
{
std::stringstream ss;
ss << "[\"foo\",1,2,3,false,{\"one\":1}]";
json j;
j << ss;
CHECK(j == json({"foo", 1, 2, 3, false, {{"one", 1}}}));
}
SECTION("operator>>")
{
std::stringstream ss;
ss << "[\"foo\",1,2,3,false,{\"one\":1}]";
json j;
ss >> j;
CHECK(j == json({"foo", 1, 2, 3, false, {{"one", 1}}}));
}
SECTION("user-defined string literal")
{
CHECK("[\"foo\",1,2,3,false,{\"one\":1}]"_json == json({"foo", 1, 2, 3, false, {{"one", 1}}}));
}
}
TEST_CASE("iterator class")
{
SECTION("construction")
{
SECTION("constructor")
{
SECTION("null")
{
json j(json::value_t::null);
json::iterator it(&j);
}
SECTION("object")
{
json j(json::value_t::object);
json::iterator it(&j);
}
SECTION("array")
{
json j(json::value_t::array);
json::iterator it(&j);
}
}
SECTION("copy assignment")
{
json j(json::value_t::null);
json::iterator it(&j);
json::iterator it2(&j);
it2 = it;
}
}
SECTION("initialization")
{
SECTION("set_begin")
{
SECTION("null")
{
json j(json::value_t::null);
json::iterator it(&j);
it.set_begin();
CHECK(it == j.begin());
}
SECTION("object")
{
json j(json::value_t::object);
json::iterator it(&j);
it.set_begin();
CHECK(it == j.begin());
}
SECTION("array")
{
json j(json::value_t::array);
json::iterator it(&j);
it.set_begin();
CHECK(it == j.begin());
}
}
SECTION("set_end")
{
SECTION("null")
{
json j(json::value_t::null);
json::iterator it(&j);
it.set_end();
CHECK(it == j.end());
}
SECTION("object")
{
json j(json::value_t::object);
json::iterator it(&j);
it.set_end();
CHECK(it == j.end());
}
SECTION("array")
{
json j(json::value_t::array);
json::iterator it(&j);
it.set_end();
CHECK(it == j.end());
}
}
}
SECTION("element access")
{
SECTION("operator*")
{
SECTION("null")
{
json j(json::value_t::null);
json::iterator it = j.begin();
CHECK_THROWS_AS(*it, std::out_of_range);
}
SECTION("number")
{
json j(17);
json::iterator it = j.begin();
CHECK(*it == json(17));
it = j.end();
CHECK_THROWS_AS(*it, std::out_of_range);
}
SECTION("object")
{
json j({{"foo", "bar"}});
json::iterator it = j.begin();
CHECK(*it == json("bar"));
}
SECTION("array")
{
json j({1, 2, 3, 4});
json::iterator it = j.begin();
CHECK(*it == json(1));
}
}
SECTION("operator->")
{
SECTION("null")
{
json j(json::value_t::null);
json::iterator it = j.begin();
CHECK_THROWS_AS(it->type_name(), std::out_of_range);
}
SECTION("number")
{
json j(17);
json::iterator it = j.begin();
CHECK(it->type_name() == "number");
it = j.end();
CHECK_THROWS_AS(it->type_name(), std::out_of_range);
}
SECTION("object")
{
json j({{"foo", "bar"}});
json::iterator it = j.begin();
CHECK(it->type_name() == "string");
}
SECTION("array")
{
json j({1, 2, 3, 4});
json::iterator it = j.begin();
CHECK(it->type_name() == "number");
}
}
}
SECTION("increment/decrement")
{
SECTION("post-increment")
{
SECTION("null")
{
json j(json::value_t::null);
json::iterator it = j.begin();
CHECK(it.m_it.generic_iterator == json::generic_iterator_value::end);
it++;
CHECK(it.m_it.generic_iterator == json::generic_iterator_value::invalid);
}
SECTION("number")
{
json j(17);
json::iterator it = j.begin();
CHECK(it.m_it.generic_iterator == json::generic_iterator_value::begin);
it++;
CHECK(it.m_it.generic_iterator == json::generic_iterator_value::end);
it++;
CHECK(it.m_it.generic_iterator == json::generic_iterator_value::invalid);
}
SECTION("object")
{
json j({{"foo", "bar"}});
json::iterator it = j.begin();
CHECK(it.m_it.object_iterator == it.m_object->m_value.object->begin());
it++;
CHECK(it.m_it.object_iterator == it.m_object->m_value.object->end());
}
SECTION("array")
{
json j({1, 2, 3, 4});
json::iterator it = j.begin();
CHECK(it.m_it.array_iterator == it.m_object->m_value.array->begin());
it++;
CHECK(it.m_it.array_iterator != it.m_object->m_value.array->begin());
CHECK(it.m_it.array_iterator != it.m_object->m_value.array->end());
it++;
CHECK(it.m_it.array_iterator != it.m_object->m_value.array->begin());
CHECK(it.m_it.array_iterator != it.m_object->m_value.array->end());
it++;
CHECK(it.m_it.array_iterator != it.m_object->m_value.array->begin());
CHECK(it.m_it.array_iterator != it.m_object->m_value.array->end());
it++;
CHECK(it.m_it.array_iterator != it.m_object->m_value.array->begin());
CHECK(it.m_it.array_iterator == it.m_object->m_value.array->end());
}
}
SECTION("pre-increment")
{
SECTION("null")
{
json j(json::value_t::null);
json::iterator it = j.begin();
CHECK(it.m_it.generic_iterator == json::generic_iterator_value::end);
++it;
CHECK(it.m_it.generic_iterator == json::generic_iterator_value::invalid);
}
SECTION("number")
{
json j(17);
json::iterator it = j.begin();
CHECK(it.m_it.generic_iterator == json::generic_iterator_value::begin);
++it;
CHECK(it.m_it.generic_iterator == json::generic_iterator_value::end);
++it;
CHECK(it.m_it.generic_iterator == json::generic_iterator_value::invalid);
}
SECTION("object")
{
json j({{"foo", "bar"}});
json::iterator it = j.begin();
CHECK(it.m_it.object_iterator == it.m_object->m_value.object->begin());
++it;
CHECK(it.m_it.object_iterator == it.m_object->m_value.object->end());
}
SECTION("array")
{
json j({1, 2, 3, 4});
json::iterator it = j.begin();
CHECK(it.m_it.array_iterator == it.m_object->m_value.array->begin());
++it;
CHECK(it.m_it.array_iterator != it.m_object->m_value.array->begin());
CHECK(it.m_it.array_iterator != it.m_object->m_value.array->end());
++it;
CHECK(it.m_it.array_iterator != it.m_object->m_value.array->begin());
CHECK(it.m_it.array_iterator != it.m_object->m_value.array->end());
++it;
CHECK(it.m_it.array_iterator != it.m_object->m_value.array->begin());
CHECK(it.m_it.array_iterator != it.m_object->m_value.array->end());
++it;
CHECK(it.m_it.array_iterator != it.m_object->m_value.array->begin());
CHECK(it.m_it.array_iterator == it.m_object->m_value.array->end());
}
}
SECTION("post-decrement")
{
SECTION("null")
{
json j(json::value_t::null);
json::iterator it = j.end();
CHECK(it.m_it.generic_iterator == json::generic_iterator_value::end);
it--;
CHECK(it.m_it.generic_iterator == json::generic_iterator_value::invalid);
}
SECTION("number")
{
json j(17);
json::iterator it = j.end();
CHECK(it.m_it.generic_iterator == json::generic_iterator_value::end);
it--;
CHECK(it.m_it.generic_iterator == json::generic_iterator_value::begin);
it--;
CHECK(it.m_it.generic_iterator == json::generic_iterator_value::invalid);
}
SECTION("object")
{
json j({{"foo", "bar"}});
json::iterator it = j.end();
CHECK(it.m_it.object_iterator == it.m_object->m_value.object->end());
it--;
CHECK(it.m_it.object_iterator == it.m_object->m_value.object->begin());
}
SECTION("array")
{
json j({1, 2, 3, 4});
json::iterator it = j.end();
CHECK(it.m_it.array_iterator == it.m_object->m_value.array->end());
it--;
CHECK(it.m_it.array_iterator != it.m_object->m_value.array->begin());
CHECK(it.m_it.array_iterator != it.m_object->m_value.array->end());
it--;
CHECK(it.m_it.array_iterator != it.m_object->m_value.array->begin());
CHECK(it.m_it.array_iterator != it.m_object->m_value.array->end());
it--;
CHECK(it.m_it.array_iterator != it.m_object->m_value.array->begin());
CHECK(it.m_it.array_iterator != it.m_object->m_value.array->end());
it--;
CHECK(it.m_it.array_iterator == it.m_object->m_value.array->begin());
CHECK(it.m_it.array_iterator != it.m_object->m_value.array->end());
}
}
SECTION("pre-decrement")
{
SECTION("null")
{
json j(json::value_t::null);
json::iterator it = j.end();
CHECK(it.m_it.generic_iterator == json::generic_iterator_value::end);
--it;
CHECK(it.m_it.generic_iterator == json::generic_iterator_value::invalid);
}
SECTION("number")
{
json j(17);
json::iterator it = j.end();
CHECK(it.m_it.generic_iterator == json::generic_iterator_value::end);
--it;
CHECK(it.m_it.generic_iterator == json::generic_iterator_value::begin);
--it;
CHECK(it.m_it.generic_iterator == json::generic_iterator_value::invalid);
}
SECTION("object")
{
json j({{"foo", "bar"}});
json::iterator it = j.end();
CHECK(it.m_it.object_iterator == it.m_object->m_value.object->end());
--it;
CHECK(it.m_it.object_iterator == it.m_object->m_value.object->begin());
}
SECTION("array")
{
json j({1, 2, 3, 4});
json::iterator it = j.end();
CHECK(it.m_it.array_iterator == it.m_object->m_value.array->end());
--it;
CHECK(it.m_it.array_iterator != it.m_object->m_value.array->begin());
CHECK(it.m_it.array_iterator != it.m_object->m_value.array->end());
--it;
CHECK(it.m_it.array_iterator != it.m_object->m_value.array->begin());
CHECK(it.m_it.array_iterator != it.m_object->m_value.array->end());
--it;
CHECK(it.m_it.array_iterator != it.m_object->m_value.array->begin());
CHECK(it.m_it.array_iterator != it.m_object->m_value.array->end());
--it;
CHECK(it.m_it.array_iterator == it.m_object->m_value.array->begin());
CHECK(it.m_it.array_iterator != it.m_object->m_value.array->end());
}
}
}
SECTION("comparison")
{
json j_values =
{
nullptr, nullptr,
17, 42,
3.14159, 23.42,
"foo", "bar",
true, false,
{1, 2, 3}, {"one", "two", "three"},
{{"first", 1}, {"second", 2}}, {{"a", "A"}, {"b", {"B"}}}
};
SECTION("comparison: equal")
{
std::vector<std::vector<bool>> expected =
{
{true, false, false, false, false, false, false, false, false, false, false, false, false, false},
{false, true, false, false, false, false, false, false, false, false, false, false, false, false},
{false, false, true, false, false, false, false, false, false, false, false, false, false, false},
{false, false, false, true, false, false, false, false, false, false, false, false, false, false},
{false, false, false, false, true, false, false, false, false, false, false, false, false, false},
{false, false, false, false, false, true, false, false, false, false, false, false, false, false},
{false, false, false, false, false, false, true, false, false, false, false, false, false, false},
{false, false, false, false, false, false, false, true, false, false, false, false, false, false},
{false, false, false, false, false, false, false, false, true, false, false, false, false, false},
{false, false, false, false, false, false, false, false, false, true, false, false, false, false},
{false, false, false, false, false, false, false, false, false, false, true, false, false, false},
{false, false, false, false, false, false, false, false, false, false, false, true, false, false},
{false, false, false, false, false, false, false, false, false, false, false, false, true, false},
{false, false, false, false, false, false, false, false, false, false, false, false, false, true}
};
for (size_t i = 0; i < j_values.size(); ++i)
{
for (size_t j = 0; j < j_values.size(); ++j)
{
// check precomputed values
CHECK( (j_values[i].begin() == j_values[j].begin()) == expected[i][j] );
}
}
}
SECTION("comparison: not equal")
{
for (size_t i = 0; i < j_values.size(); ++i)
{
for (size_t j = 0; j < j_values.size(); ++j)
{
// check definition
CHECK( (j_values[i].begin() != j_values[j].begin()) == not ((j_values[i].begin() ==
j_values[j].begin())) );
}
}
}
}
}
TEST_CASE("const_iterator class")
{
SECTION("construction")
{
SECTION("constructor")
{
SECTION("null")
{
json j(json::value_t::null);
json::const_iterator it(&j);
}
SECTION("object")
{
json j(json::value_t::object);
json::const_iterator it(&j);
}
SECTION("array")
{
json j(json::value_t::array);
json::const_iterator it(&j);
}
}
SECTION("copy assignment")
{
json j(json::value_t::null);
json::const_iterator it(&j);
json::const_iterator it2(&j);
it2 = it;
}
}
SECTION("initialization")
{
SECTION("set_begin")
{
SECTION("null")
{
json j(json::value_t::null);
json::const_iterator it(&j);
it.set_begin();
CHECK(it == j.cbegin());
}
SECTION("object")
{
json j(json::value_t::object);
json::const_iterator it(&j);
it.set_begin();
CHECK(it == j.cbegin());
}
SECTION("array")
{
json j(json::value_t::array);
json::const_iterator it(&j);
it.set_begin();
CHECK(it == j.cbegin());
}
}
SECTION("set_end")
{
SECTION("null")
{
json j(json::value_t::null);
json::const_iterator it(&j);
it.set_end();
CHECK(it == j.cend());
}
SECTION("object")
{
json j(json::value_t::object);
json::const_iterator it(&j);
it.set_end();
CHECK(it == j.cend());
}
SECTION("array")
{
json j(json::value_t::array);
json::const_iterator it(&j);
it.set_end();
CHECK(it == j.cend());
}
}
}
SECTION("element access")
{
SECTION("operator*")
{
SECTION("null")
{
json j(json::value_t::null);
json::const_iterator it = j.cbegin();
CHECK_THROWS_AS(*it, std::out_of_range);
}
SECTION("number")
{
json j(17);
json::const_iterator it = j.cbegin();
CHECK(*it == json(17));
it = j.cend();
CHECK_THROWS_AS(*it, std::out_of_range);
}
SECTION("object")
{
json j({{"foo", "bar"}});
json::const_iterator it = j.cbegin();
CHECK(*it == json("bar"));
}
SECTION("array")
{
json j({1, 2, 3, 4});
json::const_iterator it = j.cbegin();
CHECK(*it == json(1));
}
}
SECTION("operator->")
{
SECTION("null")
{
json j(json::value_t::null);
json::const_iterator it = j.cbegin();
CHECK_THROWS_AS(it->type_name(), std::out_of_range);
}
SECTION("number")
{
json j(17);
json::const_iterator it = j.cbegin();
CHECK(it->type_name() == "number");
it = j.cend();
CHECK_THROWS_AS(it->type_name(), std::out_of_range);
}
SECTION("object")
{
json j({{"foo", "bar"}});
json::const_iterator it = j.cbegin();
CHECK(it->type_name() == "string");
}
SECTION("array")
{
json j({1, 2, 3, 4});
json::const_iterator it = j.cbegin();
CHECK(it->type_name() == "number");
}
}
}
SECTION("increment/decrement")
{
SECTION("post-increment")
{
SECTION("null")
{
json j(json::value_t::null);
json::const_iterator it = j.cbegin();
CHECK(it.m_it.generic_iterator == json::generic_iterator_value::end);
it++;
CHECK(it.m_it.generic_iterator == json::generic_iterator_value::invalid);
}
SECTION("number")
{
json j(17);
json::const_iterator it = j.cbegin();
CHECK(it.m_it.generic_iterator == json::generic_iterator_value::begin);
it++;
CHECK(it.m_it.generic_iterator == json::generic_iterator_value::end);
it++;
CHECK(it.m_it.generic_iterator == json::generic_iterator_value::invalid);
}
SECTION("object")
{
json j({{"foo", "bar"}});
json::const_iterator it = j.cbegin();
CHECK(it.m_it.object_iterator == it.m_object->m_value.object->begin());
it++;
CHECK(it.m_it.object_iterator == it.m_object->m_value.object->end());
}
SECTION("array")
{
json j({1, 2, 3, 4});
json::const_iterator it = j.cbegin();
CHECK(it.m_it.array_iterator == it.m_object->m_value.array->begin());
it++;
CHECK(it.m_it.array_iterator != it.m_object->m_value.array->begin());
CHECK(it.m_it.array_iterator != it.m_object->m_value.array->end());
it++;
CHECK(it.m_it.array_iterator != it.m_object->m_value.array->begin());
CHECK(it.m_it.array_iterator != it.m_object->m_value.array->end());
it++;
CHECK(it.m_it.array_iterator != it.m_object->m_value.array->begin());
CHECK(it.m_it.array_iterator != it.m_object->m_value.array->end());
it++;
CHECK(it.m_it.array_iterator != it.m_object->m_value.array->begin());
CHECK(it.m_it.array_iterator == it.m_object->m_value.array->end());
}
}
SECTION("pre-increment")
{
SECTION("null")
{
json j(json::value_t::null);
json::const_iterator it = j.cbegin();
CHECK(it.m_it.generic_iterator == json::generic_iterator_value::end);
++it;
CHECK(it.m_it.generic_iterator == json::generic_iterator_value::invalid);
}
SECTION("number")
{
json j(17);
json::const_iterator it = j.cbegin();
CHECK(it.m_it.generic_iterator == json::generic_iterator_value::begin);
++it;
CHECK(it.m_it.generic_iterator == json::generic_iterator_value::end);
++it;
CHECK(it.m_it.generic_iterator == json::generic_iterator_value::invalid);
}
SECTION("object")
{
json j({{"foo", "bar"}});
json::const_iterator it = j.cbegin();
CHECK(it.m_it.object_iterator == it.m_object->m_value.object->begin());
++it;
CHECK(it.m_it.object_iterator == it.m_object->m_value.object->end());
}
SECTION("array")
{
json j({1, 2, 3, 4});
json::const_iterator it = j.cbegin();
CHECK(it.m_it.array_iterator == it.m_object->m_value.array->begin());
++it;
CHECK(it.m_it.array_iterator != it.m_object->m_value.array->begin());
CHECK(it.m_it.array_iterator != it.m_object->m_value.array->end());
++it;
CHECK(it.m_it.array_iterator != it.m_object->m_value.array->begin());
CHECK(it.m_it.array_iterator != it.m_object->m_value.array->end());
++it;
CHECK(it.m_it.array_iterator != it.m_object->m_value.array->begin());
CHECK(it.m_it.array_iterator != it.m_object->m_value.array->end());
++it;
CHECK(it.m_it.array_iterator != it.m_object->m_value.array->begin());
CHECK(it.m_it.array_iterator == it.m_object->m_value.array->end());
}
}
SECTION("post-decrement")
{
SECTION("null")
{
json j(json::value_t::null);
json::const_iterator it = j.cend();
CHECK(it.m_it.generic_iterator == json::generic_iterator_value::end);
it--;
CHECK(it.m_it.generic_iterator == json::generic_iterator_value::invalid);
}
SECTION("number")
{
json j(17);
json::const_iterator it = j.cend();
CHECK(it.m_it.generic_iterator == json::generic_iterator_value::end);
it--;
CHECK(it.m_it.generic_iterator == json::generic_iterator_value::begin);
it--;
CHECK(it.m_it.generic_iterator == json::generic_iterator_value::invalid);
}
SECTION("object")
{
json j({{"foo", "bar"}});
json::const_iterator it = j.cend();
CHECK(it.m_it.object_iterator == it.m_object->m_value.object->end());
it--;
CHECK(it.m_it.object_iterator == it.m_object->m_value.object->begin());
}
SECTION("array")
{
json j({1, 2, 3, 4});
json::const_iterator it = j.cend();
CHECK(it.m_it.array_iterator == it.m_object->m_value.array->end());
it--;
CHECK(it.m_it.array_iterator != it.m_object->m_value.array->begin());
CHECK(it.m_it.array_iterator != it.m_object->m_value.array->end());
it--;
CHECK(it.m_it.array_iterator != it.m_object->m_value.array->begin());
CHECK(it.m_it.array_iterator != it.m_object->m_value.array->end());
it--;
CHECK(it.m_it.array_iterator != it.m_object->m_value.array->begin());
CHECK(it.m_it.array_iterator != it.m_object->m_value.array->end());
it--;
CHECK(it.m_it.array_iterator == it.m_object->m_value.array->begin());
CHECK(it.m_it.array_iterator != it.m_object->m_value.array->end());
}
}
SECTION("pre-decrement")
{
SECTION("null")
{
json j(json::value_t::null);
json::const_iterator it = j.cend();
CHECK(it.m_it.generic_iterator == json::generic_iterator_value::end);
--it;
CHECK(it.m_it.generic_iterator == json::generic_iterator_value::invalid);
}
SECTION("number")
{
json j(17);
json::const_iterator it = j.cend();
CHECK(it.m_it.generic_iterator == json::generic_iterator_value::end);
--it;
CHECK(it.m_it.generic_iterator == json::generic_iterator_value::begin);
--it;
CHECK(it.m_it.generic_iterator == json::generic_iterator_value::invalid);
}
SECTION("object")
{
json j({{"foo", "bar"}});
json::const_iterator it = j.cend();
CHECK(it.m_it.object_iterator == it.m_object->m_value.object->end());
--it;
CHECK(it.m_it.object_iterator == it.m_object->m_value.object->begin());
}
SECTION("array")
{
json j({1, 2, 3, 4});
json::const_iterator it = j.cend();
CHECK(it.m_it.array_iterator == it.m_object->m_value.array->end());
--it;
CHECK(it.m_it.array_iterator != it.m_object->m_value.array->begin());
CHECK(it.m_it.array_iterator != it.m_object->m_value.array->end());
--it;
CHECK(it.m_it.array_iterator != it.m_object->m_value.array->begin());
CHECK(it.m_it.array_iterator != it.m_object->m_value.array->end());
--it;
CHECK(it.m_it.array_iterator != it.m_object->m_value.array->begin());
CHECK(it.m_it.array_iterator != it.m_object->m_value.array->end());
--it;
CHECK(it.m_it.array_iterator == it.m_object->m_value.array->begin());
CHECK(it.m_it.array_iterator != it.m_object->m_value.array->end());
}
}
}
SECTION("comparison")
{
json j_values =
{
nullptr, nullptr,
17, 42,
3.14159, 23.42,
"foo", "bar",
true, false,
{1, 2, 3}, {"one", "two", "three"},
{{"first", 1}, {"second", 2}}, {{"a", "A"}, {"b", {"B"}}}
};
SECTION("comparison: equal")
{
std::vector<std::vector<bool>> expected =
{
{true, false, false, false, false, false, false, false, false, false, false, false, false, false},
{false, true, false, false, false, false, false, false, false, false, false, false, false, false},
{false, false, true, false, false, false, false, false, false, false, false, false, false, false},
{false, false, false, true, false, false, false, false, false, false, false, false, false, false},
{false, false, false, false, true, false, false, false, false, false, false, false, false, false},
{false, false, false, false, false, true, false, false, false, false, false, false, false, false},
{false, false, false, false, false, false, true, false, false, false, false, false, false, false},
{false, false, false, false, false, false, false, true, false, false, false, false, false, false},
{false, false, false, false, false, false, false, false, true, false, false, false, false, false},
{false, false, false, false, false, false, false, false, false, true, false, false, false, false},
{false, false, false, false, false, false, false, false, false, false, true, false, false, false},
{false, false, false, false, false, false, false, false, false, false, false, true, false, false},
{false, false, false, false, false, false, false, false, false, false, false, false, true, false},
{false, false, false, false, false, false, false, false, false, false, false, false, false, true}
};
for (size_t i = 0; i < j_values.size(); ++i)
{
for (size_t j = 0; j < j_values.size(); ++j)
{
// check precomputed values
CHECK( (j_values[i].cbegin() == j_values[j].cbegin()) == expected[i][j] );
}
}
}
SECTION("comparison: not equal")
{
for (size_t i = 0; i < j_values.size(); ++i)
{
for (size_t j = 0; j < j_values.size(); ++j)
{
// check definition
CHECK( (j_values[i].cbegin() != j_values[j].cbegin()) == not ((j_values[i].cbegin() ==
j_values[j].cbegin())) );
}
}
}
}
}
TEST_CASE("convenience functions")
{
SECTION("type name as string")
{
CHECK(json(json::value_t::null).type_name() == "null");
CHECK(json(json::value_t::object).type_name() == "object");
CHECK(json(json::value_t::array).type_name() == "array");
CHECK(json(json::value_t::number_integer).type_name() == "number");
CHECK(json(json::value_t::number_float).type_name() == "number");
CHECK(json(json::value_t::boolean).type_name() == "boolean");
CHECK(json(json::value_t::string).type_name() == "string");
}
SECTION("string escape")
{
CHECK(json::escape_string("\"") == "\\\"");
CHECK(json::escape_string("\\") == "\\\\");
CHECK(json::escape_string("\b") == "\\b");
CHECK(json::escape_string("\f") == "\\f");
CHECK(json::escape_string("\n") == "\\n");
CHECK(json::escape_string("\r") == "\\r");
CHECK(json::escape_string("\t") == "\\t");
CHECK(json::escape_string("\x01") == "\\u0001");
CHECK(json::escape_string("\x02") == "\\u0002");
CHECK(json::escape_string("\x03") == "\\u0003");
CHECK(json::escape_string("\x04") == "\\u0004");
CHECK(json::escape_string("\x05") == "\\u0005");
CHECK(json::escape_string("\x06") == "\\u0006");
CHECK(json::escape_string("\x07") == "\\u0007");
CHECK(json::escape_string("\x08") == "\\b");
CHECK(json::escape_string("\x09") == "\\t");
CHECK(json::escape_string("\x0a") == "\\n");
CHECK(json::escape_string("\x0b") == "\\u000b");
CHECK(json::escape_string("\x0c") == "\\f");
CHECK(json::escape_string("\x0d") == "\\r");
CHECK(json::escape_string("\x0e") == "\\u000e");
CHECK(json::escape_string("\x0f") == "\\u000f");
CHECK(json::escape_string("\x10") == "\\u0010");
CHECK(json::escape_string("\x11") == "\\u0011");
CHECK(json::escape_string("\x12") == "\\u0012");
CHECK(json::escape_string("\x13") == "\\u0013");
CHECK(json::escape_string("\x14") == "\\u0014");
CHECK(json::escape_string("\x15") == "\\u0015");
CHECK(json::escape_string("\x16") == "\\u0016");
CHECK(json::escape_string("\x17") == "\\u0017");
CHECK(json::escape_string("\x18") == "\\u0018");
CHECK(json::escape_string("\x19") == "\\u0019");
CHECK(json::escape_string("\x1a") == "\\u001a");
CHECK(json::escape_string("\x1b") == "\\u001b");
CHECK(json::escape_string("\x1c") == "\\u001c");
CHECK(json::escape_string("\x1d") == "\\u001d");
CHECK(json::escape_string("\x1e") == "\\u001e");
CHECK(json::escape_string("\x1f") == "\\u001f");
}
}
TEST_CASE("lexer class")
{
SECTION("scan")
{
SECTION("structural characters")
{
CHECK(json::lexer("[").scan() == json::lexer::token_type::begin_array);
CHECK(json::lexer("]").scan() == json::lexer::token_type::end_array);
CHECK(json::lexer("{").scan() == json::lexer::token_type::begin_object);
CHECK(json::lexer("}").scan() == json::lexer::token_type::end_object);
CHECK(json::lexer(",").scan() == json::lexer::token_type::value_separator);
CHECK(json::lexer(":").scan() == json::lexer::token_type::name_separator);
}
SECTION("literal names")
{
CHECK(json::lexer("null").scan() == json::lexer::token_type::literal_null);
CHECK(json::lexer("true").scan() == json::lexer::token_type::literal_true);
CHECK(json::lexer("false").scan() == json::lexer::token_type::literal_false);
}
SECTION("numbers")
{
CHECK(json::lexer("0").scan() == json::lexer::token_type::value_number);
CHECK(json::lexer("1").scan() == json::lexer::token_type::value_number);
CHECK(json::lexer("2").scan() == json::lexer::token_type::value_number);
CHECK(json::lexer("3").scan() == json::lexer::token_type::value_number);
CHECK(json::lexer("4").scan() == json::lexer::token_type::value_number);
CHECK(json::lexer("5").scan() == json::lexer::token_type::value_number);
CHECK(json::lexer("6").scan() == json::lexer::token_type::value_number);
CHECK(json::lexer("7").scan() == json::lexer::token_type::value_number);
CHECK(json::lexer("8").scan() == json::lexer::token_type::value_number);
CHECK(json::lexer("9").scan() == json::lexer::token_type::value_number);
}
SECTION("whitespace")
{
// result is end_of_input, because not token is following
CHECK(json::lexer(" ").scan() == json::lexer::token_type::end_of_input);
CHECK(json::lexer("\t").scan() == json::lexer::token_type::end_of_input);
CHECK(json::lexer("\n").scan() == json::lexer::token_type::end_of_input);
CHECK(json::lexer("\r").scan() == json::lexer::token_type::end_of_input);
CHECK(json::lexer(" \t\n\r\n\t ").scan() == json::lexer::token_type::end_of_input);
}
}
SECTION("token_type_name")
{
CHECK(json::lexer::token_type_name(json::lexer::token_type::uninitialized) == "<uninitialized>");
CHECK(json::lexer::token_type_name(json::lexer::token_type::literal_true) == "true literal");
CHECK(json::lexer::token_type_name(json::lexer::token_type::literal_false) == "false literal");
CHECK(json::lexer::token_type_name(json::lexer::token_type::literal_null) == "null literal");
CHECK(json::lexer::token_type_name(json::lexer::token_type::value_string) == "string literal");
CHECK(json::lexer::token_type_name(json::lexer::token_type::value_number) == "number literal");
CHECK(json::lexer::token_type_name(json::lexer::token_type::begin_array) == "[");
CHECK(json::lexer::token_type_name(json::lexer::token_type::begin_object) == "{");
CHECK(json::lexer::token_type_name(json::lexer::token_type::end_array) == "]");
CHECK(json::lexer::token_type_name(json::lexer::token_type::end_object) == "}");
CHECK(json::lexer::token_type_name(json::lexer::token_type::name_separator) == ":");
CHECK(json::lexer::token_type_name(json::lexer::token_type::value_separator) == ",");
CHECK(json::lexer::token_type_name(json::lexer::token_type::parse_error) == "<parse error>");
CHECK(json::lexer::token_type_name(json::lexer::token_type::end_of_input) == "<end of input>");
}
SECTION("parse errors on first character")
{
for (int c = 1; c < 128; ++c)
{
auto s = std::string(1, c);
switch (c)
{
// single characters that are valid tokens
case ('['):
case (']'):
case ('{'):
case ('}'):
case (','):
case (':'):
case ('0'):
case ('1'):
case ('2'):
case ('3'):
case ('4'):
case ('5'):
case ('6'):
case ('7'):
case ('8'):
case ('9'):
{
CHECK(json::lexer(s.c_str()).scan() != json::lexer::token_type::parse_error);
break;
}
// whitespace
case (' '):
case ('\t'):
case ('\n'):
case ('\r'):
{
CHECK(json::lexer(s.c_str()).scan() == json::lexer::token_type::end_of_input);
break;
}
// anything else is not expected
default:
{
CHECK(json::lexer(s.c_str()).scan() == json::lexer::token_type::parse_error);
break;
}
}
}
}
}
TEST_CASE("parser class")
{
SECTION("parse")
{
SECTION("null")
{
CHECK(json::parser("null").parse() == json(nullptr));
}
SECTION("true")
{
CHECK(json::parser("true").parse() == json(true));
}
SECTION("false")
{
CHECK(json::parser("false").parse() == json(false));
}
SECTION("array")
{
SECTION("empty array")
{
CHECK(json::parser("[]").parse() == json(json::value_t::array));
CHECK(json::parser("[ ]").parse() == json(json::value_t::array));
}
SECTION("nonempty array")
{
CHECK(json::parser("[true, false, null]").parse() == json({true, false, nullptr}));
}
}
SECTION("object")
{
SECTION("empty object")
{
CHECK(json::parser("{}").parse() == json(json::value_t::object));
CHECK(json::parser("{ }").parse() == json(json::value_t::object));
}
SECTION("nonempty object")
{
CHECK(json::parser("{\"\": true, \"one\": 1, \"two\": null}").parse() == json({{"", true}, {"one", 1}, {"two", nullptr}}));
}
}
SECTION("string")
{
// empty string
CHECK(json::parser("\"\"").parse() == json(json::value_t::string));
SECTION("escaped")
{
// quotation mark
CHECK(json::parser("\"\\\"\"").parse() == json("\\\""));
// reverse solidus
CHECK(json::parser("\"\\\\\"").parse() == json("\\\\"));
// solidus
CHECK(json::parser("\"\\/\"").parse() == json("\\/"));
// backspace
CHECK(json::parser("\"\\b\"").parse() == json("\\b"));
// formfeed
CHECK(json::parser("\"\\f\"").parse() == json("\\f"));
// newline
CHECK(json::parser("\"\\n\"").parse() == json("\\n"));
// carriage return
CHECK(json::parser("\"\\r\"").parse() == json("\\r"));
// horizontal tab
CHECK(json::parser("\"\\t\"").parse() == json("\\t"));
CHECK(json::parser("\"\\u0000\"").parse() == json("\\u0000"));
CHECK(json::parser("\"\\u000a\"").parse() == json("\\u000a"));
CHECK(json::parser("\"\\u00b0\"").parse() == json("\\u00b0"));
CHECK(json::parser("\"\\u0c00\"").parse() == json("\\u0c00"));
CHECK(json::parser("\"\\ud000\"").parse() == json("\\ud000"));
CHECK(json::parser("\"\\u0000\"").parse() == json("\\u0000"));
CHECK(json::parser("\"\\u000E\"").parse() == json("\\u000E"));
CHECK(json::parser("\"\\u00F0\"").parse() == json("\\u00F0"));
CHECK(json::parser("\"\\u0100\"").parse() == json("\\u0100"));
CHECK(json::parser("\"\\u2000\"").parse() == json("\\u2000"));
CHECK(json::parser("\"\\uFFFF\"").parse() == json("\\uFFFF"));
}
}
SECTION("number")
{
SECTION("integers")
{
SECTION("without exponent")
{
CHECK(json::parser("-128").parse() == json(-128));
CHECK(json::parser("-0").parse() == json(-0));
CHECK(json::parser("0").parse() == json(0));
CHECK(json::parser("128").parse() == json(128));
}
SECTION("with exponent")
{
CHECK(json::parser("0e1").parse() == json(0e1));
CHECK(json::parser("0E1").parse() == json(0e1));
CHECK(json::parser("10000E-4").parse() == json(10000e-4));
CHECK(json::parser("10000E-3").parse() == json(10000e-3));
CHECK(json::parser("10000E-2").parse() == json(10000e-2));
CHECK(json::parser("10000E-1").parse() == json(10000e-1));
CHECK(json::parser("10000E0").parse() == json(10000e0));
CHECK(json::parser("10000E1").parse() == json(10000e1));
CHECK(json::parser("10000E2").parse() == json(10000e2));
CHECK(json::parser("10000E3").parse() == json(10000e3));
CHECK(json::parser("10000E4").parse() == json(10000e4));
CHECK(json::parser("10000e-4").parse() == json(10000e-4));
CHECK(json::parser("10000e-3").parse() == json(10000e-3));
CHECK(json::parser("10000e-2").parse() == json(10000e-2));
CHECK(json::parser("10000e-1").parse() == json(10000e-1));
CHECK(json::parser("10000e0").parse() == json(10000e0));
CHECK(json::parser("10000e1").parse() == json(10000e1));
CHECK(json::parser("10000e2").parse() == json(10000e2));
CHECK(json::parser("10000e3").parse() == json(10000e3));
CHECK(json::parser("10000e4").parse() == json(10000e4));
CHECK(json::parser("-0e1").parse() == json(-0e1));
CHECK(json::parser("-0E1").parse() == json(-0e1));
CHECK(json::parser("-0E123").parse() == json(-0e123));
}
}
SECTION("floating-point")
{
SECTION("without exponent")
{
CHECK(json::parser("-128.5").parse() == json(-128.5));
CHECK(json::parser("0.999").parse() == json(0.999));
CHECK(json::parser("128.5").parse() == json(128.5));
CHECK(json::parser("-0.0").parse() == json(-0.0));
}
SECTION("with exponent")
{
CHECK(json::parser("-128.5E3").parse() == json(-128.5E3));
CHECK(json::parser("-128.5E-3").parse() == json(-128.5E-3));
CHECK(json::parser("-0.0e1").parse() == json(-0.0e1));
CHECK(json::parser("-0.0E1").parse() == json(-0.0e1));
}
}
SECTION("invalid numbers")
{
CHECK_THROWS_AS(json::parser("01").parse(), std::invalid_argument);
CHECK_THROWS_AS(json::parser("--1").parse(), std::invalid_argument);
CHECK_THROWS_AS(json::parser("1.").parse(), std::invalid_argument);
CHECK_THROWS_AS(json::parser("1E").parse(), std::invalid_argument);
CHECK_THROWS_AS(json::parser("1E-").parse(), std::invalid_argument);
CHECK_THROWS_AS(json::parser("1.E1").parse(), std::invalid_argument);
CHECK_THROWS_AS(json::parser("-1E").parse(), std::invalid_argument);
CHECK_THROWS_AS(json::parser("-0E#").parse(), std::invalid_argument);
CHECK_THROWS_AS(json::parser("-0E-#").parse(), std::invalid_argument);
CHECK_THROWS_AS(json::parser("-0#").parse(), std::invalid_argument);
CHECK_THROWS_AS(json::parser("-0.0:").parse(), std::invalid_argument);
CHECK_THROWS_AS(json::parser("-0.0Z").parse(), std::invalid_argument);
CHECK_THROWS_AS(json::parser("-0E123:").parse(), std::invalid_argument);
CHECK_THROWS_AS(json::parser("-0e0-:").parse(), std::invalid_argument);
CHECK_THROWS_AS(json::parser("-0e-:").parse(), std::invalid_argument);
CHECK_THROWS_AS(json::parser("-0f").parse(), std::invalid_argument);
}
}
}
SECTION("parse errors")
{
// unexpected end of number
CHECK_THROWS_AS(json::parser("0.").parse(), std::invalid_argument);
CHECK_THROWS_AS(json::parser("-").parse(), std::invalid_argument);
CHECK_THROWS_AS(json::parser("--").parse(), std::invalid_argument);
CHECK_THROWS_AS(json::parser("-0.").parse(), std::invalid_argument);
CHECK_THROWS_AS(json::parser("-.").parse(), std::invalid_argument);
CHECK_THROWS_AS(json::parser("-:").parse(), std::invalid_argument);
CHECK_THROWS_AS(json::parser("0.:").parse(), std::invalid_argument);
CHECK_THROWS_AS(json::parser("e.").parse(), std::invalid_argument);
CHECK_THROWS_AS(json::parser("1e.").parse(), std::invalid_argument);
CHECK_THROWS_AS(json::parser("1e/").parse(), std::invalid_argument);
CHECK_THROWS_AS(json::parser("1e:").parse(), std::invalid_argument);
CHECK_THROWS_AS(json::parser("1E.").parse(), std::invalid_argument);
CHECK_THROWS_AS(json::parser("1E/").parse(), std::invalid_argument);
CHECK_THROWS_AS(json::parser("1E:").parse(), std::invalid_argument);
// unexpected end of null
CHECK_THROWS_AS(json::parser("n").parse(), std::invalid_argument);
CHECK_THROWS_AS(json::parser("n").parse(), std::invalid_argument);
CHECK_THROWS_AS(json::parser("nu").parse(), std::invalid_argument);
CHECK_THROWS_AS(json::parser("nul").parse(), std::invalid_argument);
// unexpected end of true
CHECK_THROWS_AS(json::parser("t").parse(), std::invalid_argument);
CHECK_THROWS_AS(json::parser("t").parse(), std::invalid_argument);
CHECK_THROWS_AS(json::parser("tr").parse(), std::invalid_argument);
CHECK_THROWS_AS(json::parser("tru").parse(), std::invalid_argument);
// unexpected end of false
CHECK_THROWS_AS(json::parser("f").parse(), std::invalid_argument);
CHECK_THROWS_AS(json::parser("fa").parse(), std::invalid_argument);
CHECK_THROWS_AS(json::parser("fal").parse(), std::invalid_argument);
CHECK_THROWS_AS(json::parser("fals").parse(), std::invalid_argument);
// unexpected end of array
CHECK_THROWS_AS(json::parser("[").parse(), std::invalid_argument);
CHECK_THROWS_AS(json::parser("[1").parse(), std::invalid_argument);
CHECK_THROWS_AS(json::parser("[1,").parse(), std::invalid_argument);
CHECK_THROWS_AS(json::parser("[1,]").parse(), std::invalid_argument);
CHECK_THROWS_AS(json::parser("]").parse(), std::invalid_argument);
// unexpected end of object
CHECK_THROWS_AS(json::parser("{").parse(), std::invalid_argument);
CHECK_THROWS_AS(json::parser("{\"foo\"").parse(), std::invalid_argument);
CHECK_THROWS_AS(json::parser("{\"foo\":").parse(), std::invalid_argument);
CHECK_THROWS_AS(json::parser("{\"foo\":}").parse(), std::invalid_argument);
CHECK_THROWS_AS(json::parser("{\"foo\":1,}").parse(), std::invalid_argument);
CHECK_THROWS_AS(json::parser("}").parse(), std::invalid_argument);
// unexpected end of string
CHECK_THROWS_AS(json::parser("\"").parse(), std::invalid_argument);
CHECK_THROWS_AS(json::parser("\"\\\"").parse(), std::invalid_argument);
CHECK_THROWS_AS(json::parser("\"\\u\"").parse(), std::invalid_argument);
CHECK_THROWS_AS(json::parser("\"\\u0\"").parse(), std::invalid_argument);
CHECK_THROWS_AS(json::parser("\"\\u01\"").parse(), std::invalid_argument);
CHECK_THROWS_AS(json::parser("\"\\u012\"").parse(), std::invalid_argument);
// invalid escapes
for (int c = 1; c < 128; ++c)
{
auto s = std::string("\"\\") + std::string(1, c) + "\"";
switch (c)
{
// valid escapes
case ('"'):
case ('\\'):
case ('/'):
case ('b'):
case ('f'):
case ('n'):
case ('r'):
case ('t'):
{
CHECK_NOTHROW(json::parser(s).parse());
break;
}
// \u must be followed with four numbers, so we skip it here
case ('u'):
{
break;
}
// any other combination of backslash and character is invalid
default:
{
CHECK_THROWS_AS(json::parser(s).parse(), std::invalid_argument);
break;
}
}
}
// invalid \uxxxx escapes
{
// check whether character is a valid hex character
const auto valid = [](int c)
{
switch (c)
{
case ('0'):
case ('1'):
case ('2'):
case ('3'):
case ('4'):
case ('5'):
case ('6'):
case ('7'):
case ('8'):
case ('9'):
case ('a'):
case ('b'):
case ('c'):
case ('d'):
case ('e'):
case ('f'):
case ('A'):
case ('B'):
case ('C'):
case ('D'):
case ('E'):
case ('F'):
{
return true;
}
default:
{
return false;
}
}
};
for (int c = 1; c < 128; ++c)
{
std::string s = "\"\\u";
// create a string with the iterated character at each position
auto s1 = s + "000" + std::string(1, c) + "\"";
auto s2 = s + "00" + std::string(1, c) + "0\"";
auto s3 = s + "0" + std::string(1, c) + "00\"";
auto s4 = s + std::string(1, c) + "000\"";
if (valid(c))
{
CHECK_NOTHROW(json::parser(s1).parse());
CHECK_NOTHROW(json::parser(s2).parse());
CHECK_NOTHROW(json::parser(s3).parse());
CHECK_NOTHROW(json::parser(s4).parse());
}
else
{
CHECK_THROWS_AS(json::parser(s1).parse(), std::invalid_argument);
CHECK_THROWS_AS(json::parser(s2).parse(), std::invalid_argument);
CHECK_THROWS_AS(json::parser(s3).parse(), std::invalid_argument);
CHECK_THROWS_AS(json::parser(s4).parse(), std::invalid_argument);
}
}
}
}
}