mirror of
https://github.com/nlohmann/json.git
synced 2026-10-28 19:45:22 +00:00
Two changes roughly halve the CPU time needed to build the unit tests (clang 21: ~300 s -> ~150 s, GCC 16: ~750-820 s -> ~395-420 s, Debug): - Move the C++14/17/20-dependent tests into separate unit-<name>-cpp<N>.cpp files. A test file is built for every standard whose JSON_HAS_CPP_<N> macro it mentions, so far whole large files were rebuilt for C++14/17/20 because of a few #ifdef sections. The main files are now built for C++11 only; the ci_test_*_cxx<N> jobs still build every file for every standard. - Add the CMake option JSON_TestUnityBuild (ON by default, OFF with MinGW): compatible test files are compiled in batches as one translation unit so they share the template instantiations of the library. Each file keeps its own CTest test, which runs the batch executable filtered to that file's test cases. The binary-format tests form an explicit group; the rest is batched by JSON_TestUnityBatchSize. Fix the name clashes that merging files exposed, document the rules for test files in tests/README.md, and point CONTRIBUTING.md to it. Signed-off-by: Niels Lohmann <mail@nlohmann.me>
1402 lines
75 KiB
C++
1402 lines
75 KiB
C++
// __ _____ _____ _____
|
|
// __| | __| | | | JSON for Modern C++ (supporting code)
|
|
// | | |__ | | | | | | version 3.12.0
|
|
// |_____|_____|_____|_|___| https://github.com/nlohmann/json
|
|
//
|
|
// SPDX-FileCopyrightText: 2013-2026 Niels Lohmann <https://nlohmann.me>
|
|
// SPDX-License-Identifier: MIT
|
|
|
|
#include "doctest_compatibility.h"
|
|
|
|
#include <nlohmann/json.hpp>
|
|
#ifdef JSON_TEST_NO_GLOBAL_UDLS
|
|
using namespace nlohmann::literals; // NOLINT(google-build-using-namespace)
|
|
#endif
|
|
|
|
// used to check at compile time (via is_detected) whether a call is well-formed; see
|
|
// https://github.com/nlohmann/json/issues/5657
|
|
//
|
|
// note: an integer *literal* (rather than a std::declval<T>() of integral type T) is required to
|
|
// reproduce the bug, because only a null pointer constant--an integer literal with value zero, not
|
|
// merely a runtime value that happens to be zero--implicitly converts to a null const char*; that is
|
|
// why can_call_*_with_0 below hard-code the literal 0 instead of taking it as a template argument
|
|
template<typename BasicJsonType, typename T>
|
|
using can_call_find = decltype(std::declval<BasicJsonType>().find(std::declval<T>()));
|
|
|
|
template<typename BasicJsonType, typename T>
|
|
using can_call_count = decltype(std::declval<BasicJsonType>().count(std::declval<T>()));
|
|
|
|
template<typename BasicJsonType, typename T>
|
|
using can_call_contains = decltype(std::declval<BasicJsonType>().contains(std::declval<T>()));
|
|
|
|
template<typename BasicJsonType, typename KeyType, typename ValueType>
|
|
using can_call_value = decltype(std::declval<BasicJsonType>().value(std::declval<KeyType>(), std::declval<ValueType>()));
|
|
|
|
template<typename BasicJsonType>
|
|
using can_call_find_with_0 = decltype(std::declval<BasicJsonType>().find(0));
|
|
|
|
template<typename BasicJsonType>
|
|
using can_call_count_with_0 = decltype(std::declval<BasicJsonType>().count(0));
|
|
|
|
template<typename BasicJsonType>
|
|
using can_call_contains_with_0 = decltype(std::declval<BasicJsonType>().contains(0));
|
|
|
|
template<typename BasicJsonType>
|
|
using can_call_contains_with_0L = decltype(std::declval<BasicJsonType>().contains(0L));
|
|
|
|
template<typename BasicJsonType>
|
|
using can_call_value_with_0 = decltype(std::declval<BasicJsonType>().value(0, 1));
|
|
|
|
TEST_CASE_TEMPLATE("element access 2", Json, nlohmann::json, nlohmann::ordered_json) // NOLINT(readability-math-missing-parentheses, bugprone-throwing-static-initialization)
|
|
{
|
|
SECTION("object")
|
|
{
|
|
Json j = {{"integer", 1}, {"unsigned", 1u}, {"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("unsigned") == Json(1u));
|
|
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::object());
|
|
CHECK(j.at("array") == Json({1, 2, 3}));
|
|
|
|
CHECK(j_const.at("integer") == Json(1));
|
|
CHECK(j_const.at("unsigned") == Json(1u));
|
|
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::object());
|
|
CHECK(j_const.at("array") == Json({1, 2, 3}));
|
|
}
|
|
|
|
SECTION("access outside bounds")
|
|
{
|
|
CHECK_THROWS_WITH_AS(j.at("foo"), "[json.exception.out_of_range.403] key 'foo' not found", typename Json::out_of_range&);
|
|
CHECK_THROWS_WITH_AS(j_const.at("foo"), "[json.exception.out_of_range.403] key 'foo' not found", typename Json::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); // NOLINT(performance-unnecessary-copy-initialization)
|
|
CHECK_THROWS_WITH_AS(j_nonobject.at("foo"), "[json.exception.type_error.304] cannot use at() with null", typename Json::type_error&);
|
|
CHECK_THROWS_WITH_AS(j_nonobject_const.at("foo"), "[json.exception.type_error.304] cannot use at() with null", typename Json::type_error&);
|
|
}
|
|
|
|
SECTION("boolean")
|
|
{
|
|
Json j_nonobject(Json::value_t::boolean);
|
|
const Json j_nonobject_const(j_nonobject); // NOLINT(performance-unnecessary-copy-initialization)
|
|
CHECK_THROWS_WITH_AS(j_nonobject.at("foo"), "[json.exception.type_error.304] cannot use at() with boolean", typename Json::type_error&);
|
|
CHECK_THROWS_WITH_AS(j_nonobject_const.at("foo"), "[json.exception.type_error.304] cannot use at() with boolean", typename Json::type_error&);
|
|
}
|
|
|
|
SECTION("string")
|
|
{
|
|
Json j_nonobject(Json::value_t::string);
|
|
const Json j_nonobject_const(j_nonobject); // NOLINT(performance-unnecessary-copy-initialization)
|
|
CHECK_THROWS_WITH_AS(j_nonobject.at("foo"), "[json.exception.type_error.304] cannot use at() with string", typename Json::type_error&);
|
|
CHECK_THROWS_WITH_AS(j_nonobject_const.at("foo"), "[json.exception.type_error.304] cannot use at() with string", typename Json::type_error&);
|
|
}
|
|
|
|
SECTION("array")
|
|
{
|
|
Json j_nonobject(Json::value_t::array);
|
|
const Json j_nonobject_const(j_nonobject); // NOLINT(performance-unnecessary-copy-initialization)
|
|
CHECK_THROWS_WITH_AS(j_nonobject.at("foo"), "[json.exception.type_error.304] cannot use at() with array", typename Json::type_error&);
|
|
CHECK_THROWS_WITH_AS(j_nonobject_const.at("foo"), "[json.exception.type_error.304] cannot use at() with array", typename Json::type_error&);
|
|
}
|
|
|
|
SECTION("number (integer)")
|
|
{
|
|
Json j_nonobject(Json::value_t::number_integer);
|
|
const Json j_nonobject_const(j_nonobject); // NOLINT(performance-unnecessary-copy-initialization)
|
|
CHECK_THROWS_WITH_AS(j_nonobject.at("foo"), "[json.exception.type_error.304] cannot use at() with number", typename Json::type_error&);
|
|
CHECK_THROWS_WITH_AS(j_nonobject_const.at("foo"), "[json.exception.type_error.304] cannot use at() with number", typename Json::type_error&);
|
|
}
|
|
|
|
SECTION("number (unsigned)")
|
|
{
|
|
Json j_nonobject(Json::value_t::number_unsigned);
|
|
const Json j_nonobject_const(j_nonobject); // NOLINT(performance-unnecessary-copy-initialization)
|
|
CHECK_THROWS_WITH_AS(j_nonobject.at("foo"), "[json.exception.type_error.304] cannot use at() with number", typename Json::type_error&);
|
|
CHECK_THROWS_WITH_AS(j_nonobject_const.at("foo"), "[json.exception.type_error.304] cannot use at() with number", typename Json::type_error&);
|
|
}
|
|
|
|
SECTION("number (floating-point)")
|
|
{
|
|
Json j_nonobject(Json::value_t::number_float);
|
|
const Json j_nonobject_const(j_nonobject); // NOLINT(performance-unnecessary-copy-initialization)
|
|
CHECK_THROWS_WITH_AS(j_nonobject.at("foo"), "[json.exception.type_error.304] cannot use at() with number", typename Json::type_error&);
|
|
CHECK_THROWS_WITH_AS(j_nonobject_const.at("foo"), "[json.exception.type_error.304] cannot use at() with number", typename Json::type_error&);
|
|
}
|
|
}
|
|
}
|
|
|
|
SECTION("access specified element with default value")
|
|
{
|
|
SECTION("given a key")
|
|
{
|
|
SECTION("access existing value")
|
|
{
|
|
CHECK(j.value("integer", 2) == 1);
|
|
CHECK(j.value("integer", 1.0) == Approx(1));
|
|
CHECK(j.value("unsigned", 2) == 1u);
|
|
CHECK(j.value("unsigned", 1.0) == Approx(1u));
|
|
CHECK(j.value("null", Json(1)) == Json());
|
|
CHECK(j.value("boolean", false) == true);
|
|
CHECK(j.value("string", "bar") == "hello world");
|
|
CHECK(j.value("string", std::string("bar")) == "hello world");
|
|
CHECK(j.value("floating", 12.34) == Approx(42.23));
|
|
CHECK(j.value("floating", 12) == 42);
|
|
CHECK(j.value("object", Json({{"foo", "bar"}})) == Json::object());
|
|
CHECK(j.value("array", Json({10, 100})) == Json({1, 2, 3}));
|
|
|
|
CHECK(j_const.value("integer", 2) == 1);
|
|
CHECK(j_const.value("integer", 1.0) == Approx(1));
|
|
CHECK(j_const.value("unsigned", 2) == 1u);
|
|
CHECK(j_const.value("unsigned", 1.0) == Approx(1u));
|
|
CHECK(j_const.value("boolean", false) == true);
|
|
CHECK(j_const.value("string", "bar") == "hello world");
|
|
CHECK(j_const.value("string", std::string("bar")) == "hello world");
|
|
CHECK(j_const.value("floating", 12.34) == Approx(42.23));
|
|
CHECK(j_const.value("floating", 12) == 42);
|
|
CHECK(j_const.value("object", Json({{"foo", "bar"}})) == Json::object());
|
|
CHECK(j_const.value("array", Json({10, 100})) == Json({1, 2, 3}));
|
|
}
|
|
|
|
SECTION("access non-existing value")
|
|
{
|
|
CHECK(j.value("_", 2) == 2);
|
|
CHECK(j.value("_", 2u) == 2u);
|
|
CHECK(j.value("_", false) == false);
|
|
CHECK(j.value("_", "bar") == "bar");
|
|
CHECK(j.value("_", 12.34) == Approx(12.34));
|
|
CHECK(j.value("_", Json({{"foo", "bar"}})) == Json({{"foo", "bar"}}));
|
|
CHECK(j.value("_", Json({10, 100})) == Json({10, 100}));
|
|
|
|
CHECK(j_const.value("_", 2) == 2);
|
|
CHECK(j_const.value("_", 2u) == 2u);
|
|
CHECK(j_const.value("_", false) == false);
|
|
CHECK(j_const.value("_", "bar") == "bar");
|
|
CHECK(j_const.value("_", 12.34) == Approx(12.34));
|
|
CHECK(j_const.value("_", Json({{"foo", "bar"}})) == Json({{"foo", "bar"}}));
|
|
CHECK(j_const.value("_", Json({10, 100})) == Json({10, 100}));
|
|
}
|
|
|
|
SECTION("access on non-object type")
|
|
{
|
|
SECTION("null")
|
|
{
|
|
Json j_nonobject(Json::value_t::null);
|
|
const Json j_nonobject_const(Json::value_t::null);
|
|
CHECK_THROWS_WITH_AS(j_nonobject.value("foo", 1), "[json.exception.type_error.306] cannot use value() with null", typename Json::type_error&);
|
|
CHECK_THROWS_WITH_AS(j_nonobject_const.value("foo", 1), "[json.exception.type_error.306] cannot use value() with null", typename Json::type_error&);
|
|
}
|
|
|
|
SECTION("boolean")
|
|
{
|
|
Json j_nonobject(Json::value_t::boolean);
|
|
const Json j_nonobject_const(Json::value_t::boolean);
|
|
CHECK_THROWS_WITH_AS(j_nonobject.value("foo", 1), "[json.exception.type_error.306] cannot use value() with boolean", typename Json::type_error&);
|
|
CHECK_THROWS_WITH_AS(j_nonobject_const.value("foo", 1), "[json.exception.type_error.306] cannot use value() with boolean", typename Json::type_error&);
|
|
}
|
|
|
|
SECTION("string")
|
|
{
|
|
Json j_nonobject(Json::value_t::string);
|
|
const Json j_nonobject_const(Json::value_t::string);
|
|
CHECK_THROWS_WITH_AS(j_nonobject.value("foo", 1), "[json.exception.type_error.306] cannot use value() with string", typename Json::type_error&);
|
|
CHECK_THROWS_WITH_AS(j_nonobject_const.value("foo", 1), "[json.exception.type_error.306] cannot use value() with string", typename Json::type_error&);
|
|
}
|
|
|
|
SECTION("array")
|
|
{
|
|
Json j_nonobject(Json::value_t::array);
|
|
const Json j_nonobject_const(Json::value_t::array);
|
|
CHECK_THROWS_WITH_AS(j_nonobject.value("foo", 1), "[json.exception.type_error.306] cannot use value() with array", typename Json::type_error&);
|
|
CHECK_THROWS_WITH_AS(j_nonobject_const.value("foo", 1), "[json.exception.type_error.306] cannot use value() with array", typename Json::type_error&);
|
|
}
|
|
|
|
SECTION("number (integer)")
|
|
{
|
|
Json j_nonobject(Json::value_t::number_integer);
|
|
const Json j_nonobject_const(Json::value_t::number_integer);
|
|
CHECK_THROWS_WITH_AS(j_nonobject.value("foo", 1), "[json.exception.type_error.306] cannot use value() with number", typename Json::type_error&);
|
|
CHECK_THROWS_WITH_AS(j_nonobject_const.value("foo", 1), "[json.exception.type_error.306] cannot use value() with number", typename Json::type_error&);
|
|
}
|
|
|
|
SECTION("number (unsigned)")
|
|
{
|
|
Json j_nonobject(Json::value_t::number_unsigned);
|
|
const Json j_nonobject_const(Json::value_t::number_unsigned);
|
|
CHECK_THROWS_WITH_AS(j_nonobject.value("foo", 1), "[json.exception.type_error.306] cannot use value() with number", typename Json::type_error&);
|
|
CHECK_THROWS_WITH_AS(j_nonobject_const.value("foo", 1), "[json.exception.type_error.306] cannot use value() with number", typename Json::type_error&);
|
|
}
|
|
|
|
SECTION("number (floating-point)")
|
|
{
|
|
Json j_nonobject(Json::value_t::number_float);
|
|
const Json j_nonobject_const(Json::value_t::number_float);
|
|
CHECK_THROWS_WITH_AS(j_nonobject.value("foo", 1), "[json.exception.type_error.306] cannot use value() with number", typename Json::type_error&);
|
|
CHECK_THROWS_WITH_AS(j_nonobject_const.value("foo", 1), "[json.exception.type_error.306] cannot use value() with number", typename Json::type_error&);
|
|
}
|
|
}
|
|
}
|
|
|
|
SECTION("given a JSON pointer")
|
|
{
|
|
SECTION("access existing value")
|
|
{
|
|
CHECK(j.value("/integer"_json_pointer, 2) == 1);
|
|
CHECK(j.value("/integer"_json_pointer, 1.0) == Approx(1));
|
|
CHECK(j.value("/unsigned"_json_pointer, 2) == 1u);
|
|
CHECK(j.value("/unsigned"_json_pointer, 1.0) == Approx(1u));
|
|
CHECK(j.value("/null"_json_pointer, Json(1)) == Json());
|
|
CHECK(j.value("/boolean"_json_pointer, false) == true);
|
|
CHECK(j.value("/string"_json_pointer, "bar") == "hello world");
|
|
CHECK(j.value("/string"_json_pointer, std::string("bar")) == "hello world");
|
|
CHECK(j.value("/floating"_json_pointer, 12.34) == Approx(42.23));
|
|
CHECK(j.value("/floating"_json_pointer, 12) == 42);
|
|
CHECK(j.value("/object"_json_pointer, Json({{"foo", "bar"}})) == Json::object());
|
|
CHECK(j.value("/array"_json_pointer, Json({10, 100})) == Json({1, 2, 3}));
|
|
|
|
CHECK(j_const.value("/integer"_json_pointer, 2) == 1);
|
|
CHECK(j_const.value("/integer"_json_pointer, 1.0) == Approx(1));
|
|
CHECK(j_const.value("/unsigned"_json_pointer, 2) == 1u);
|
|
CHECK(j_const.value("/unsigned"_json_pointer, 1.0) == Approx(1u));
|
|
CHECK(j_const.value("/boolean"_json_pointer, false) == true);
|
|
CHECK(j_const.value("/string"_json_pointer, "bar") == "hello world");
|
|
CHECK(j_const.value("/string"_json_pointer, std::string("bar")) == "hello world");
|
|
CHECK(j_const.value("/floating"_json_pointer, 12.34) == Approx(42.23));
|
|
CHECK(j_const.value("/floating"_json_pointer, 12) == 42);
|
|
CHECK(j_const.value("/object"_json_pointer, Json({{"foo", "bar"}})) == Json::object());
|
|
CHECK(j_const.value("/array"_json_pointer, Json({10, 100})) == Json({1, 2, 3}));
|
|
}
|
|
|
|
SECTION("access on non-object type")
|
|
{
|
|
SECTION("null")
|
|
{
|
|
Json j_nonobject(Json::value_t::null);
|
|
const Json j_nonobject_const(Json::value_t::null);
|
|
CHECK_THROWS_WITH_AS(j_nonobject.value("/foo"_json_pointer, 1), "[json.exception.type_error.306] cannot use value() with null", typename Json::type_error&);
|
|
CHECK_THROWS_WITH_AS(j_nonobject_const.value("/foo"_json_pointer, 1), "[json.exception.type_error.306] cannot use value() with null", typename Json::type_error&);
|
|
}
|
|
|
|
SECTION("boolean")
|
|
{
|
|
Json j_nonobject(Json::value_t::boolean);
|
|
const Json j_nonobject_const(Json::value_t::boolean);
|
|
CHECK_THROWS_WITH_AS(j_nonobject.value("/foo"_json_pointer, 1), "[json.exception.type_error.306] cannot use value() with boolean", typename Json::type_error&);
|
|
CHECK_THROWS_WITH_AS(j_nonobject_const.value("/foo"_json_pointer, 1), "[json.exception.type_error.306] cannot use value() with boolean", typename Json::type_error&);
|
|
}
|
|
|
|
SECTION("string")
|
|
{
|
|
Json j_nonobject(Json::value_t::string);
|
|
const Json j_nonobject_const(Json::value_t::string);
|
|
CHECK_THROWS_WITH_AS(j_nonobject.value("/foo"_json_pointer, 1), "[json.exception.type_error.306] cannot use value() with string", typename Json::type_error&);
|
|
CHECK_THROWS_WITH_AS(j_nonobject_const.value("/foo"_json_pointer, 1), "[json.exception.type_error.306] cannot use value() with string", typename Json::type_error&);
|
|
}
|
|
|
|
SECTION("number (integer)")
|
|
{
|
|
Json j_nonobject(Json::value_t::number_integer);
|
|
const Json j_nonobject_const(Json::value_t::number_integer);
|
|
CHECK_THROWS_WITH_AS(j_nonobject.value("/foo"_json_pointer, 1), "[json.exception.type_error.306] cannot use value() with number", typename Json::type_error&);
|
|
CHECK_THROWS_WITH_AS(j_nonobject_const.value("/foo"_json_pointer, 1), "[json.exception.type_error.306] cannot use value() with number", typename Json::type_error&);
|
|
}
|
|
|
|
SECTION("number (unsigned)")
|
|
{
|
|
Json j_nonobject(Json::value_t::number_unsigned);
|
|
const Json j_nonobject_const(Json::value_t::number_unsigned);
|
|
CHECK_THROWS_WITH_AS(j_nonobject.value("/foo"_json_pointer, 1), "[json.exception.type_error.306] cannot use value() with number", typename Json::type_error&);
|
|
CHECK_THROWS_WITH_AS(j_nonobject_const.value("/foo"_json_pointer, 1), "[json.exception.type_error.306] cannot use value() with number", typename Json::type_error&);
|
|
}
|
|
|
|
SECTION("number (floating-point)")
|
|
{
|
|
Json j_nonobject(Json::value_t::number_float);
|
|
const Json j_nonobject_const(Json::value_t::number_float);
|
|
CHECK_THROWS_WITH_AS(j_nonobject.value("/foo"_json_pointer, 1), "[json.exception.type_error.306] cannot use value() with number", typename Json::type_error&);
|
|
CHECK_THROWS_WITH_AS(j_nonobject_const.value("/foo"_json_pointer, 1), "[json.exception.type_error.306] cannot use value() with number", typename Json::type_error&);
|
|
}
|
|
}
|
|
|
|
SECTION("access on array type")
|
|
{
|
|
Json j_array = Json::array({j});
|
|
const Json j_array_const = Json::array({j});
|
|
|
|
CHECK(j_array.value("/0/integer"_json_pointer, 2) == 1);
|
|
CHECK(j_array.value("/0/integer"_json_pointer, 1.0) == Approx(1));
|
|
CHECK(j_array.value("/0/unsigned"_json_pointer, 2) == 1u);
|
|
CHECK(j_array.value("/0/unsigned"_json_pointer, 1.0) == Approx(1u));
|
|
CHECK(j_array.value("/0/null"_json_pointer, Json(1)) == Json());
|
|
CHECK(j_array.value("/0/boolean"_json_pointer, false) == true);
|
|
CHECK(j_array.value("/0/string"_json_pointer, "bar") == "hello world");
|
|
CHECK(j_array.value("/0/string"_json_pointer, std::string("bar")) == "hello world");
|
|
CHECK(j_array.value("/0/floating"_json_pointer, 12.34) == Approx(42.23));
|
|
CHECK(j_array.value("/0/floating"_json_pointer, 12) == 42);
|
|
CHECK(j_array.value("/0/object"_json_pointer, Json({{"foo", "bar"}})) == Json::object());
|
|
CHECK(j_array.value("/0/array"_json_pointer, Json({10, 100})) == Json({1, 2, 3}));
|
|
|
|
CHECK(j_array_const.value("/0/integer"_json_pointer, 2) == 1);
|
|
CHECK(j_array_const.value("/0/integer"_json_pointer, 1.0) == Approx(1));
|
|
CHECK(j_array_const.value("/0/unsigned"_json_pointer, 2) == 1u);
|
|
CHECK(j_array_const.value("/0/unsigned"_json_pointer, 1.0) == Approx(1u));
|
|
CHECK(j_array_const.value("/0/boolean"_json_pointer, false) == true);
|
|
CHECK(j_array_const.value("/0/string"_json_pointer, "bar") == "hello world");
|
|
CHECK(j_array_const.value("/0/string"_json_pointer, std::string("bar")) == "hello world");
|
|
CHECK(j_array_const.value("/0/floating"_json_pointer, 12.34) == Approx(42.23));
|
|
CHECK(j_array_const.value("/0/floating"_json_pointer, 12) == 42);
|
|
CHECK(j_array_const.value("/0/object"_json_pointer, Json({{"foo", "bar"}})) == Json::object());
|
|
CHECK(j_array_const.value("/0/array"_json_pointer, Json({10, 100})) == Json({1, 2, 3}));
|
|
|
|
// Test out-of-range array index
|
|
CHECK(j_array.value("/10"_json_pointer, 42) == 42);
|
|
CHECK(j_array_const.value("/10"_json_pointer, 42) == 42);
|
|
|
|
// Test "-" index (append position is invalid)
|
|
CHECK(j_array.value("/-"_json_pointer, 42) == 42);
|
|
CHECK(j_array_const.value("/-"_json_pointer, 42) == 42);
|
|
|
|
// Test an index with a non-digit after a valid leading digit; this is
|
|
// out_of_range (not parse_error) and must not throw (see #5672)
|
|
CHECK(j_array.value("/1a"_json_pointer, 42) == 42);
|
|
CHECK(j_array_const.value("/1a"_json_pointer, 42) == 42);
|
|
|
|
// Test the empty reference token (JSON pointer "/"); see #5672
|
|
CHECK(j_array.value("/"_json_pointer, 42) == 42);
|
|
CHECK(j_array_const.value("/"_json_pointer, 42) == 42);
|
|
|
|
// Test an index whose magnitude does not fit into size_type (see #5672)
|
|
CHECK(j_array.value("/99999999999999999999999"_json_pointer, 42) == 42);
|
|
CHECK(j_array_const.value("/99999999999999999999999"_json_pointer, 42) == 42);
|
|
CHECK(j_array.value("/18446744073709551615"_json_pointer, 42) == 42);
|
|
CHECK(j_array_const.value("/18446744073709551615"_json_pointer, 42) == 42);
|
|
|
|
#if !defined(JSON_NOEXCEPTION)
|
|
// Test malformed index (non-numeric) throws parse_error
|
|
CHECK_THROWS_WITH_AS(j_array.value("/foo"_json_pointer, 1), "[json.exception.parse_error.109] parse error: array index 'foo' is not a number", typename Json::parse_error&);
|
|
CHECK_THROWS_WITH_AS(j_array_const.value("/foo"_json_pointer, 1), "[json.exception.parse_error.109] parse error: array index 'foo' is not a number", typename Json::parse_error&);
|
|
|
|
// Test leading-zero index throws parse_error
|
|
CHECK_THROWS_WITH_AS(j_array.value("/01"_json_pointer, 1), "[json.exception.parse_error.106] parse error: array index '01' must not begin with '0'", typename Json::parse_error&);
|
|
CHECK_THROWS_WITH_AS(j_array_const.value("/01"_json_pointer, 1), "[json.exception.parse_error.106] parse error: array index '01' must not begin with '0'", typename Json::parse_error&);
|
|
#endif
|
|
}
|
|
}
|
|
}
|
|
|
|
SECTION("non-const operator[]")
|
|
{
|
|
{
|
|
Json j_null;
|
|
CHECK(j_null.is_null());
|
|
j_null["key"] = 1;
|
|
CHECK(j_null.is_object());
|
|
CHECK(j_null.size() == 1);
|
|
j_null["key"] = 2;
|
|
CHECK(j_null.size() == 1);
|
|
}
|
|
}
|
|
|
|
SECTION("front and back")
|
|
{
|
|
if (std::is_same<Json, nlohmann::ordered_json>::value)
|
|
{
|
|
// "integer" is the first key
|
|
CHECK(j.front() == Json(1));
|
|
CHECK(j_const.front() == Json(1));
|
|
// "array" is last key
|
|
CHECK(j.back() == Json({1, 2, 3}));
|
|
CHECK(j_const.back() == Json({1, 2, 3}));
|
|
}
|
|
else
|
|
{
|
|
// "array" is the smallest key
|
|
CHECK(j.front() == Json({1, 2, 3}));
|
|
CHECK(j_const.front() == Json({1, 2, 3}));
|
|
// "unsigned" is the largest key
|
|
CHECK(j.back() == Json(1u));
|
|
CHECK(j_const.back() == Json(1u));
|
|
}
|
|
}
|
|
|
|
SECTION("access specified element")
|
|
{
|
|
SECTION("access within bounds")
|
|
{
|
|
CHECK(j["integer"] == Json(1));
|
|
CHECK(j[typename Json::object_t::key_type("integer")] == j["integer"]);
|
|
|
|
CHECK(j["unsigned"] == Json(1u));
|
|
CHECK(j[typename Json::object_t::key_type("unsigned")] == j["unsigned"]);
|
|
|
|
CHECK(j["boolean"] == Json(true));
|
|
CHECK(j[typename Json::object_t::key_type("boolean")] == j["boolean"]);
|
|
|
|
CHECK(j["null"] == Json(nullptr));
|
|
CHECK(j[typename Json::object_t::key_type("null")] == j["null"]);
|
|
|
|
CHECK(j["string"] == Json("hello world"));
|
|
CHECK(j[typename Json::object_t::key_type("string")] == j["string"]);
|
|
|
|
CHECK(j["floating"] == Json(42.23));
|
|
CHECK(j[typename Json::object_t::key_type("floating")] == j["floating"]);
|
|
|
|
CHECK(j["object"] == Json::object());
|
|
CHECK(j[typename Json::object_t::key_type("object")] == j["object"]);
|
|
|
|
CHECK(j["array"] == Json({1, 2, 3}));
|
|
CHECK(j[typename Json::object_t::key_type("array")] == j["array"]);
|
|
|
|
CHECK(j_const["integer"] == Json(1));
|
|
CHECK(j_const[typename Json::object_t::key_type("integer")] == j["integer"]);
|
|
|
|
CHECK(j_const["boolean"] == Json(true));
|
|
CHECK(j_const[typename Json::object_t::key_type("boolean")] == j["boolean"]);
|
|
|
|
CHECK(j_const["null"] == Json(nullptr));
|
|
CHECK(j_const[typename Json::object_t::key_type("null")] == j["null"]);
|
|
|
|
CHECK(j_const["string"] == Json("hello world"));
|
|
CHECK(j_const[typename Json::object_t::key_type("string")] == j["string"]);
|
|
|
|
CHECK(j_const["floating"] == Json(42.23));
|
|
CHECK(j_const[typename Json::object_t::key_type("floating")] == j["floating"]);
|
|
|
|
CHECK(j_const["object"] == Json::object());
|
|
CHECK(j_const[typename Json::object_t::key_type("object")] == j["object"]);
|
|
|
|
CHECK(j_const["array"] == Json({1, 2, 3}));
|
|
CHECK(j_const[typename Json::object_t::key_type("array")] == j["array"]);
|
|
}
|
|
|
|
SECTION("access on non-object type")
|
|
{
|
|
SECTION("null")
|
|
{
|
|
Json j_nonobject(Json::value_t::null);
|
|
Json j_nonobject2(Json::value_t::null);
|
|
const Json j_const_nonobject(j_nonobject);
|
|
|
|
CHECK_NOTHROW(j_nonobject["foo"]);
|
|
CHECK_NOTHROW(j_nonobject2[typename Json::object_t::key_type("foo")]);
|
|
CHECK_THROWS_WITH_AS(j_const_nonobject["foo"], "[json.exception.type_error.305] cannot use operator[] with a string argument with null", typename Json::type_error&);
|
|
CHECK_THROWS_WITH_AS(j_const_nonobject[typename Json::object_t::key_type("foo")], "[json.exception.type_error.305] cannot use operator[] with a string argument with null", typename Json::type_error&);
|
|
}
|
|
|
|
SECTION("boolean")
|
|
{
|
|
Json j_nonobject(Json::value_t::boolean);
|
|
const Json j_const_nonobject(j_nonobject);
|
|
CHECK_THROWS_WITH_AS(j_nonobject["foo"],
|
|
"[json.exception.type_error.305] cannot use operator[] with a string argument with boolean", typename Json::type_error&);
|
|
CHECK_THROWS_WITH_AS(j_nonobject[typename Json::object_t::key_type("foo")],
|
|
"[json.exception.type_error.305] cannot use operator[] with a string argument with boolean", typename Json::type_error&);
|
|
CHECK_THROWS_WITH_AS(j_const_nonobject["foo"],
|
|
"[json.exception.type_error.305] cannot use operator[] with a string argument with boolean", typename Json::type_error&);
|
|
CHECK_THROWS_WITH_AS(j_const_nonobject[typename Json::object_t::key_type("foo")],
|
|
"[json.exception.type_error.305] cannot use operator[] with a string argument with boolean", typename Json::type_error&);
|
|
}
|
|
|
|
SECTION("string")
|
|
{
|
|
Json j_nonobject(Json::value_t::string);
|
|
const Json j_const_nonobject(j_nonobject);
|
|
CHECK_THROWS_WITH_AS(j_nonobject["foo"],
|
|
"[json.exception.type_error.305] cannot use operator[] with a string argument with string", typename Json::type_error&);
|
|
CHECK_THROWS_WITH_AS(j_nonobject[typename Json::object_t::key_type("foo")],
|
|
"[json.exception.type_error.305] cannot use operator[] with a string argument with string", typename Json::type_error&);
|
|
CHECK_THROWS_WITH_AS(j_const_nonobject["foo"],
|
|
"[json.exception.type_error.305] cannot use operator[] with a string argument with string", typename Json::type_error&);
|
|
CHECK_THROWS_WITH_AS(j_const_nonobject[typename Json::object_t::key_type("foo")],
|
|
"[json.exception.type_error.305] cannot use operator[] with a string argument with string", typename Json::type_error&);
|
|
}
|
|
|
|
SECTION("array")
|
|
{
|
|
Json j_nonobject(Json::value_t::array);
|
|
const Json j_const_nonobject(j_nonobject);
|
|
CHECK_THROWS_WITH_AS(j_nonobject["foo"],
|
|
"[json.exception.type_error.305] cannot use operator[] with a string argument with array", typename Json::type_error&);
|
|
CHECK_THROWS_WITH_AS(j_nonobject[typename Json::object_t::key_type("foo")], "[json.exception.type_error.305] cannot use operator[] with a string argument with array", typename Json::type_error&);
|
|
CHECK_THROWS_WITH_AS(j_const_nonobject["foo"],
|
|
"[json.exception.type_error.305] cannot use operator[] with a string argument with array", typename Json::type_error&);
|
|
CHECK_THROWS_WITH_AS(j_const_nonobject[typename Json::object_t::key_type("foo")],
|
|
"[json.exception.type_error.305] cannot use operator[] with a string argument with array", typename Json::type_error&);
|
|
}
|
|
|
|
SECTION("number (integer)")
|
|
{
|
|
Json j_nonobject(Json::value_t::number_integer);
|
|
const Json j_const_nonobject(j_nonobject);
|
|
CHECK_THROWS_WITH_AS(j_nonobject["foo"],
|
|
"[json.exception.type_error.305] cannot use operator[] with a string argument with number", typename Json::type_error&);
|
|
CHECK_THROWS_WITH_AS(j_nonobject[typename Json::object_t::key_type("foo")],
|
|
"[json.exception.type_error.305] cannot use operator[] with a string argument with number", typename Json::type_error&);
|
|
CHECK_THROWS_WITH_AS(j_const_nonobject["foo"],
|
|
"[json.exception.type_error.305] cannot use operator[] with a string argument with number", typename Json::type_error&);
|
|
CHECK_THROWS_WITH_AS(j_const_nonobject[typename Json::object_t::key_type("foo")],
|
|
"[json.exception.type_error.305] cannot use operator[] with a string argument with number", typename Json::type_error&);
|
|
}
|
|
|
|
SECTION("number (unsigned)")
|
|
{
|
|
Json j_nonobject(Json::value_t::number_unsigned);
|
|
const Json j_const_nonobject(j_nonobject);
|
|
CHECK_THROWS_WITH_AS(j_nonobject["foo"],
|
|
"[json.exception.type_error.305] cannot use operator[] with a string argument with number", typename Json::type_error&);
|
|
CHECK_THROWS_WITH_AS(j_nonobject[typename Json::object_t::key_type("foo")],
|
|
"[json.exception.type_error.305] cannot use operator[] with a string argument with number", typename Json::type_error&);
|
|
CHECK_THROWS_WITH_AS(j_const_nonobject["foo"],
|
|
"[json.exception.type_error.305] cannot use operator[] with a string argument with number", typename Json::type_error&);
|
|
CHECK_THROWS_WITH_AS(j_const_nonobject[typename Json::object_t::key_type("foo")],
|
|
"[json.exception.type_error.305] cannot use operator[] with a string argument with number", typename Json::type_error&);
|
|
}
|
|
|
|
SECTION("number (floating-point)")
|
|
{
|
|
Json j_nonobject(Json::value_t::number_float);
|
|
const Json j_const_nonobject(j_nonobject);
|
|
CHECK_THROWS_WITH_AS(j_nonobject["foo"],
|
|
"[json.exception.type_error.305] cannot use operator[] with a string argument with number", typename Json::type_error&);
|
|
CHECK_THROWS_WITH_AS(j_nonobject[typename Json::object_t::key_type("foo")],
|
|
"[json.exception.type_error.305] cannot use operator[] with a string argument with number", typename Json::type_error&);
|
|
CHECK_THROWS_WITH_AS(j_const_nonobject["foo"],
|
|
"[json.exception.type_error.305] cannot use operator[] with a string argument with number", typename Json::type_error&);
|
|
CHECK_THROWS_WITH_AS(j_const_nonobject[typename Json::object_t::key_type("foo")],
|
|
"[json.exception.type_error.305] cannot use operator[] with a string argument with number", typename Json::type_error&);
|
|
}
|
|
}
|
|
}
|
|
|
|
SECTION("remove specified element")
|
|
{
|
|
SECTION("remove element by key")
|
|
{
|
|
CHECK(j.find("integer") != j.end());
|
|
CHECK(j.erase("integer") == 1);
|
|
CHECK(j.find("integer") == j.end());
|
|
CHECK(j.erase("integer") == 0);
|
|
|
|
CHECK(j.find("unsigned") != j.end());
|
|
CHECK(j.erase("unsigned") == 1);
|
|
CHECK(j.find("unsigned") == j.end());
|
|
CHECK(j.erase("unsigned") == 0);
|
|
|
|
CHECK(j.find("boolean") != j.end());
|
|
CHECK(j.erase("boolean") == 1);
|
|
CHECK(j.find("boolean") == j.end());
|
|
CHECK(j.erase("boolean") == 0);
|
|
|
|
CHECK(j.find("null") != j.end());
|
|
CHECK(j.erase("null") == 1);
|
|
CHECK(j.find("null") == j.end());
|
|
CHECK(j.erase("null") == 0);
|
|
|
|
CHECK(j.find("string") != j.end());
|
|
CHECK(j.erase("string") == 1);
|
|
CHECK(j.find("string") == j.end());
|
|
CHECK(j.erase("string") == 0);
|
|
|
|
CHECK(j.find("floating") != j.end());
|
|
CHECK(j.erase("floating") == 1);
|
|
CHECK(j.find("floating") == j.end());
|
|
CHECK(j.erase("floating") == 0);
|
|
|
|
CHECK(j.find("object") != j.end());
|
|
CHECK(j.erase("object") == 1);
|
|
CHECK(j.find("object") == j.end());
|
|
CHECK(j.erase("object") == 0);
|
|
|
|
CHECK(j.find("array") != j.end());
|
|
CHECK(j.erase("array") == 1);
|
|
CHECK(j.find("array") == j.end());
|
|
CHECK(j.erase("array") == 0);
|
|
}
|
|
|
|
SECTION("remove element by iterator")
|
|
{
|
|
SECTION("erase(begin())")
|
|
{
|
|
{
|
|
Json jobject = {{"a", "a"}, {"b", 1}, {"c", 17u}};
|
|
typename Json::iterator const it2 = jobject.erase(jobject.begin());
|
|
CHECK(jobject == Json({{"b", 1}, {"c", 17u}}));
|
|
CHECK(*it2 == Json(1));
|
|
}
|
|
{
|
|
Json jobject = {{"a", "a"}, {"b", 1}, {"c", 17u}};
|
|
typename Json::const_iterator const it2 = jobject.erase(jobject.cbegin());
|
|
CHECK(jobject == Json({{"b", 1}, {"c", 17u}}));
|
|
CHECK(*it2 == Json(1));
|
|
}
|
|
}
|
|
|
|
SECTION("erase(begin(), end())")
|
|
{
|
|
{
|
|
Json jobject = {{"a", "a"}, {"b", 1}, {"c", 17u}};
|
|
const typename Json::iterator it2 = jobject.erase(jobject.begin(), jobject.end());
|
|
CHECK(jobject == Json::object());
|
|
CHECK(it2 == jobject.end());
|
|
}
|
|
{
|
|
Json jobject = {{"a", "a"}, {"b", 1}, {"c", 17u}};
|
|
const typename Json::const_iterator it2 = jobject.erase(jobject.cbegin(), jobject.cend());
|
|
CHECK(jobject == Json::object());
|
|
CHECK(it2 == jobject.cend());
|
|
}
|
|
}
|
|
|
|
SECTION("erase(begin(), begin())")
|
|
{
|
|
{
|
|
Json jobject = {{"a", "a"}, {"b", 1}, {"c", 17u}};
|
|
typename Json::iterator const it2 = jobject.erase(jobject.begin(), jobject.begin());
|
|
CHECK(jobject == Json({{"a", "a"}, {"b", 1}, {"c", 17u}}));
|
|
CHECK(*it2 == Json("a"));
|
|
}
|
|
{
|
|
Json jobject = {{"a", "a"}, {"b", 1}, {"c", 17u}};
|
|
typename Json::const_iterator const it2 = jobject.erase(jobject.cbegin(), jobject.cbegin());
|
|
CHECK(jobject == Json({{"a", "a"}, {"b", 1}, {"c", 17u}}));
|
|
CHECK(*it2 == Json("a"));
|
|
}
|
|
}
|
|
|
|
SECTION("erase at offset")
|
|
{
|
|
{
|
|
Json jobject = {{"a", "a"}, {"b", 1}, {"c", 17u}};
|
|
typename Json::iterator const it = jobject.find("b");
|
|
typename Json::iterator const it2 = jobject.erase(it);
|
|
CHECK(jobject == Json({{"a", "a"}, {"c", 17u}}));
|
|
CHECK(*it2 == Json(17));
|
|
}
|
|
{
|
|
Json jobject = {{"a", "a"}, {"b", 1}, {"c", 17u}};
|
|
typename Json::const_iterator const it = jobject.find("b");
|
|
typename Json::const_iterator const it2 = jobject.erase(it);
|
|
CHECK(jobject == Json({{"a", "a"}, {"c", 17u}}));
|
|
CHECK(*it2 == Json(17));
|
|
}
|
|
}
|
|
|
|
SECTION("erase subrange")
|
|
{
|
|
{
|
|
Json jobject = {{"a", "a"}, {"b", 1}, {"c", 17u}, {"d", false}, {"e", true}};
|
|
typename Json::iterator const it2 = jobject.erase(jobject.find("b"), jobject.find("e"));
|
|
CHECK(jobject == Json({{"a", "a"}, {"e", true}}));
|
|
CHECK(*it2 == Json(true));
|
|
}
|
|
{
|
|
Json jobject = {{"a", "a"}, {"b", 1}, {"c", 17u}, {"d", false}, {"e", true}};
|
|
typename Json::const_iterator const it2 = jobject.erase(jobject.find("b"), jobject.find("e"));
|
|
CHECK(jobject == Json({{"a", "a"}, {"e", true}}));
|
|
CHECK(*it2 == Json(true));
|
|
}
|
|
}
|
|
|
|
SECTION("different objects")
|
|
{
|
|
{
|
|
Json jobject = {{"a", "a"}, {"b", 1}, {"c", 17u}, {"d", false}, {"e", true}};
|
|
Json jobject2 = {{"a", "a"}, {"b", 1}, {"c", 17u}};
|
|
CHECK_THROWS_WITH_AS(jobject.erase(jobject2.begin()),
|
|
"[json.exception.invalid_iterator.202] iterator does not fit current value", typename Json::invalid_iterator&);
|
|
CHECK_THROWS_WITH_AS(jobject.erase(jobject.begin(), jobject2.end()),
|
|
"[json.exception.invalid_iterator.203] iterators do not fit current value", typename Json::invalid_iterator&);
|
|
CHECK_THROWS_WITH_AS(jobject.erase(jobject2.begin(), jobject.end()),
|
|
"[json.exception.invalid_iterator.203] iterators do not fit current value", typename Json::invalid_iterator&);
|
|
CHECK_THROWS_WITH_AS(jobject.erase(jobject2.begin(), jobject2.end()),
|
|
"[json.exception.invalid_iterator.203] iterators do not fit current value", typename Json::invalid_iterator&);
|
|
}
|
|
{
|
|
Json jobject = {{"a", "a"}, {"b", 1}, {"c", 17u}, {"d", false}, {"e", true}};
|
|
Json jobject2 = {{"a", "a"}, {"b", 1}, {"c", 17u}};
|
|
CHECK_THROWS_WITH_AS(jobject.erase(jobject2.cbegin()),
|
|
"[json.exception.invalid_iterator.202] iterator does not fit current value", typename Json::invalid_iterator&);
|
|
CHECK_THROWS_WITH_AS(jobject.erase(jobject.cbegin(), jobject2.cend()),
|
|
"[json.exception.invalid_iterator.203] iterators do not fit current value", typename Json::invalid_iterator&);
|
|
CHECK_THROWS_WITH_AS(jobject.erase(jobject2.cbegin(), jobject.cend()),
|
|
"[json.exception.invalid_iterator.203] iterators do not fit current value", typename Json::invalid_iterator&);
|
|
CHECK_THROWS_WITH_AS(jobject.erase(jobject2.cbegin(), jobject2.cend()),
|
|
"[json.exception.invalid_iterator.203] iterators do not fit current value", typename Json::invalid_iterator&);
|
|
}
|
|
}
|
|
}
|
|
|
|
SECTION("remove element by key in non-object type")
|
|
{
|
|
SECTION("null")
|
|
{
|
|
Json j_nonobject(Json::value_t::null);
|
|
CHECK_THROWS_WITH_AS(j_nonobject.erase("foo"), "[json.exception.type_error.307] cannot use erase() with null", typename Json::type_error&);
|
|
}
|
|
|
|
SECTION("boolean")
|
|
{
|
|
Json j_nonobject(Json::value_t::boolean);
|
|
CHECK_THROWS_WITH_AS(j_nonobject.erase("foo"), "[json.exception.type_error.307] cannot use erase() with boolean", typename Json::type_error&);
|
|
}
|
|
|
|
SECTION("string")
|
|
{
|
|
Json j_nonobject(Json::value_t::string);
|
|
CHECK_THROWS_WITH_AS(j_nonobject.erase("foo"), "[json.exception.type_error.307] cannot use erase() with string", typename Json::type_error&);
|
|
}
|
|
|
|
SECTION("array")
|
|
{
|
|
Json j_nonobject(Json::value_t::array);
|
|
CHECK_THROWS_WITH_AS(j_nonobject.erase("foo"), "[json.exception.type_error.307] cannot use erase() with array", typename Json::type_error&);
|
|
}
|
|
|
|
SECTION("number (integer)")
|
|
{
|
|
Json j_nonobject(Json::value_t::number_integer);
|
|
CHECK_THROWS_WITH_AS(j_nonobject.erase("foo"), "[json.exception.type_error.307] cannot use erase() with number", typename Json::type_error&);
|
|
}
|
|
|
|
SECTION("number (floating-point)")
|
|
{
|
|
Json j_nonobject(Json::value_t::number_float);
|
|
CHECK_THROWS_WITH_AS(j_nonobject.erase("foo"), "[json.exception.type_error.307] cannot use erase() with number", typename Json::type_error&);
|
|
}
|
|
}
|
|
}
|
|
|
|
SECTION("find an element in an object")
|
|
{
|
|
SECTION("existing element")
|
|
{
|
|
for (const auto* key :
|
|
{"integer", "unsigned", "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 (unsigned)")
|
|
{
|
|
Json j_nonarray(Json::value_t::number_unsigned);
|
|
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());
|
|
}
|
|
}
|
|
}
|
|
|
|
SECTION("count keys in an object")
|
|
{
|
|
SECTION("existing element")
|
|
{
|
|
for (const auto* key :
|
|
{"integer", "unsigned", "floating", "null", "string", "boolean", "object", "array"
|
|
})
|
|
{
|
|
CHECK(j.count(key) == 1);
|
|
CHECK(j_const.count(key) == 1);
|
|
}
|
|
}
|
|
|
|
SECTION("nonexisting element")
|
|
{
|
|
CHECK(j.count("foo") == 0);
|
|
CHECK(j_const.count("foo") == 0);
|
|
}
|
|
|
|
SECTION("all types")
|
|
{
|
|
SECTION("null")
|
|
{
|
|
Json j_nonobject(Json::value_t::null);
|
|
const Json j_nonobject_const(Json::value_t::null);
|
|
|
|
CHECK(j_nonobject.count("foo") == 0);
|
|
CHECK(j_nonobject_const.count("foo") == 0);
|
|
}
|
|
|
|
SECTION("string")
|
|
{
|
|
Json j_nonobject(Json::value_t::string);
|
|
const Json j_nonobject_const(Json::value_t::string);
|
|
|
|
CHECK(j_nonobject.count("foo") == 0);
|
|
CHECK(j_nonobject_const.count("foo") == 0);
|
|
}
|
|
|
|
SECTION("object")
|
|
{
|
|
Json j_nonobject(Json::value_t::object);
|
|
const Json j_nonobject_const(Json::value_t::object);
|
|
|
|
CHECK(j_nonobject.count("foo") == 0);
|
|
CHECK(j_nonobject_const.count("foo") == 0);
|
|
}
|
|
|
|
SECTION("array")
|
|
{
|
|
Json j_nonobject(Json::value_t::array);
|
|
const Json j_nonobject_const(Json::value_t::array);
|
|
|
|
CHECK(j_nonobject.count("foo") == 0);
|
|
CHECK(j_nonobject_const.count("foo") == 0);
|
|
}
|
|
|
|
SECTION("boolean")
|
|
{
|
|
Json j_nonobject(Json::value_t::boolean);
|
|
const Json j_nonobject_const(Json::value_t::boolean);
|
|
|
|
CHECK(j_nonobject.count("foo") == 0);
|
|
CHECK(j_nonobject_const.count("foo") == 0);
|
|
}
|
|
|
|
SECTION("number (integer)")
|
|
{
|
|
Json j_nonobject(Json::value_t::number_integer);
|
|
const Json j_nonobject_const(Json::value_t::number_integer);
|
|
|
|
CHECK(j_nonobject.count("foo") == 0);
|
|
CHECK(j_nonobject_const.count("foo") == 0);
|
|
}
|
|
|
|
SECTION("number (unsigned)")
|
|
{
|
|
Json j_nonobject(Json::value_t::number_unsigned);
|
|
const Json j_nonobject_const(Json::value_t::number_unsigned);
|
|
|
|
CHECK(j_nonobject.count("foo") == 0);
|
|
CHECK(j_nonobject_const.count("foo") == 0);
|
|
}
|
|
|
|
SECTION("number (floating-point)")
|
|
{
|
|
Json j_nonobject(Json::value_t::number_float);
|
|
const Json j_nonobject_const(Json::value_t::number_float);
|
|
|
|
CHECK(j_nonobject.count("foo") == 0);
|
|
CHECK(j_nonobject_const.count("foo") == 0);
|
|
}
|
|
}
|
|
}
|
|
|
|
SECTION("check existence of key in an object")
|
|
{
|
|
SECTION("existing element")
|
|
{
|
|
for (const auto* key :
|
|
{"integer", "unsigned", "floating", "null", "string", "boolean", "object", "array"
|
|
})
|
|
{
|
|
CHECK(j.contains(key) == true);
|
|
CHECK(j_const.contains(key) == true);
|
|
}
|
|
}
|
|
|
|
SECTION("nonexisting element")
|
|
{
|
|
CHECK(j.contains("foo") == false);
|
|
CHECK(j_const.contains("foo") == false);
|
|
}
|
|
|
|
SECTION("all types")
|
|
{
|
|
SECTION("null")
|
|
{
|
|
Json j_nonobject(Json::value_t::null);
|
|
const Json j_nonobject_const(Json::value_t::null);
|
|
|
|
CHECK(j_nonobject.contains("foo") == false);
|
|
CHECK(j_nonobject_const.contains("foo") == false);
|
|
}
|
|
|
|
SECTION("string")
|
|
{
|
|
Json j_nonobject(Json::value_t::string);
|
|
const Json j_nonobject_const(Json::value_t::string);
|
|
|
|
CHECK(j_nonobject.contains("foo") == false);
|
|
CHECK(j_nonobject_const.contains("foo") == false);
|
|
}
|
|
|
|
SECTION("object")
|
|
{
|
|
Json j_nonobject(Json::value_t::object);
|
|
const Json j_nonobject_const(Json::value_t::object);
|
|
|
|
CHECK(j_nonobject.contains("foo") == false);
|
|
CHECK(j_nonobject_const.contains("foo") == false);
|
|
}
|
|
|
|
SECTION("array")
|
|
{
|
|
Json j_nonobject(Json::value_t::array);
|
|
const Json j_nonobject_const(Json::value_t::array);
|
|
|
|
CHECK(j_nonobject.contains("foo") == false);
|
|
CHECK(j_nonobject_const.contains("foo") == false);
|
|
}
|
|
|
|
SECTION("boolean")
|
|
{
|
|
Json j_nonobject(Json::value_t::boolean);
|
|
const Json j_nonobject_const(Json::value_t::boolean);
|
|
|
|
CHECK(j_nonobject.contains("foo") == false);
|
|
CHECK(j_nonobject_const.contains("foo") == false);
|
|
}
|
|
|
|
SECTION("number (integer)")
|
|
{
|
|
Json j_nonobject(Json::value_t::number_integer);
|
|
const Json j_nonobject_const(Json::value_t::number_integer);
|
|
|
|
CHECK(j_nonobject.contains("foo") == false);
|
|
CHECK(j_nonobject_const.contains("foo") == false);
|
|
}
|
|
|
|
SECTION("number (unsigned)")
|
|
{
|
|
Json j_nonobject(Json::value_t::number_unsigned);
|
|
const Json j_nonobject_const(Json::value_t::number_unsigned);
|
|
|
|
CHECK(j_nonobject.contains("foo") == false);
|
|
CHECK(j_nonobject_const.contains("foo") == false);
|
|
}
|
|
|
|
SECTION("number (floating-point)")
|
|
{
|
|
Json j_nonobject(Json::value_t::number_float);
|
|
const Json j_nonobject_const(Json::value_t::number_float);
|
|
CHECK(j_nonobject.contains("foo") == false);
|
|
CHECK(j_nonobject_const.contains("foo") == false);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
SECTION("integral keys for object lookup are rejected at compile time")
|
|
{
|
|
// https://github.com/nlohmann/json/issues/5657: an integer literal like 0 is a null pointer
|
|
// constant, which used to convert to a null const char* and from there--via undefined
|
|
// behavior in the std::string constructor--to key_type, so contains(0), find(0), and
|
|
// count(0) used to compile and then crash instead of failing to compile
|
|
using nlohmann::detail::is_detected;
|
|
|
|
// MSVC 2015 does not treat selecting a deleted function in decltype as
|
|
// a substitution failure, so it detects the deleted overloads as
|
|
// callable; calling them still fails to compile
|
|
#if !(defined(_MSC_VER) && _MSC_VER < 1910)
|
|
CHECK_FALSE(is_detected<can_call_find_with_0, Json&>::value);
|
|
CHECK_FALSE(is_detected<can_call_find_with_0, const Json&>::value);
|
|
CHECK_FALSE(is_detected<can_call_count_with_0, Json&>::value);
|
|
CHECK_FALSE(is_detected<can_call_contains_with_0, Json&>::value);
|
|
// value(0, ...) is only affected in C++11, where the comparator is not transparent; with a
|
|
// transparent comparator (C++14 and later), int is already rejected for lacking a
|
|
// comparison with the key type, independently of this fix
|
|
CHECK_FALSE(is_detected<can_call_value_with_0, const Json&>::value);
|
|
|
|
// another integral literal type must be rejected as well, not just int
|
|
CHECK_FALSE(is_detected<can_call_contains_with_0L, Json&>::value);
|
|
#endif
|
|
|
|
// the valid overloads must remain callable
|
|
CHECK(is_detected<can_call_find, Json&, const char*>::value);
|
|
CHECK(is_detected<can_call_find, Json&, std::string>::value);
|
|
CHECK(is_detected<can_call_count, Json&, const char*>::value);
|
|
CHECK(is_detected<can_call_contains, Json&, const char*>::value);
|
|
CHECK(is_detected<can_call_contains, Json&, typename Json::json_pointer>::value);
|
|
CHECK(is_detected<can_call_value, const Json&, const char*, int>::value);
|
|
CHECK(is_detected<can_call_value, const Json&, typename Json::json_pointer, int>::value);
|
|
|
|
// the neighboring size_type overloads for array access are unaffected by the new
|
|
// integral-key overloads above (at(), operator[](), and erase() take a size_type)
|
|
Json arr = {10, 20, 30};
|
|
const Json arr_const = arr;
|
|
CHECK(arr.at(0) == 10);
|
|
CHECK(arr_const.at(0) == 10);
|
|
CHECK(arr[0] == 10);
|
|
CHECK(arr_const[0] == 10);
|
|
arr.erase(0);
|
|
CHECK(arr.size() == 2);
|
|
}
|
|
}
|
|
|
|
#if !defined(JSON_NOEXCEPTION)
|
|
TEST_CASE_TEMPLATE("element access 2 (throwing tests)", Json, nlohmann::json, nlohmann::ordered_json) // NOLINT(readability-math-missing-parentheses, bugprone-throwing-static-initialization)
|
|
{
|
|
SECTION("object")
|
|
{
|
|
Json j = {{"integer", 1}, {"unsigned", 1u}, {"floating", 42.23}, {"null", nullptr}, {"string", "hello world"}, {"boolean", true}, {"object", Json::object()}, {"array", {1, 2, 3}}};
|
|
const Json j_const = {{"integer", 1}, {"unsigned", 1u}, {"floating", 42.23}, {"null", nullptr}, {"string", "hello world"}, {"boolean", true}, {"object", Json::object()}, {"array", {1, 2, 3}}};
|
|
|
|
SECTION("access specified element with default value")
|
|
{
|
|
SECTION("given a JSON pointer")
|
|
{
|
|
SECTION("access non-existing value")
|
|
{
|
|
CHECK(j.value("/not/existing"_json_pointer, 2) == 2);
|
|
CHECK(j.value("/not/existing"_json_pointer, 2u) == 2u);
|
|
CHECK(j.value("/not/existing"_json_pointer, false) == false);
|
|
CHECK(j.value("/not/existing"_json_pointer, "bar") == "bar");
|
|
CHECK(j.value("/not/existing"_json_pointer, 12.34) == Approx(12.34));
|
|
CHECK(j.value("/not/existing"_json_pointer, Json({{"foo", "bar"}})) == Json({{"foo", "bar"}}));
|
|
CHECK(j.value("/not/existing"_json_pointer, Json({10, 100})) == Json({10, 100}));
|
|
|
|
// an array index that is out of range, too large to be
|
|
// represented, or "-", and a token below a scalar
|
|
CHECK(j.value("/array/3"_json_pointer, 2) == 2);
|
|
CHECK(j.value("/array/-"_json_pointer, 2) == 2);
|
|
CHECK(j.value("/array/99999999999999999999999999"_json_pointer, 2) == 2);
|
|
CHECK(j.value("/integer/0"_json_pointer, 2) == 2);
|
|
CHECK(j.value("/string/x"_json_pointer, 2) == 2);
|
|
CHECK(j.value("/null/x"_json_pointer, 2) == 2);
|
|
CHECK(j.value("/array/0"_json_pointer, 2) == 1);
|
|
|
|
CHECK(j_const.value("/not/existing"_json_pointer, 2) == 2);
|
|
CHECK(j_const.value("/not/existing"_json_pointer, 2u) == 2u);
|
|
CHECK(j_const.value("/not/existing"_json_pointer, false) == false);
|
|
CHECK(j_const.value("/not/existing"_json_pointer, "bar") == "bar");
|
|
CHECK(j_const.value("/not/existing"_json_pointer, 12.34) == Approx(12.34));
|
|
CHECK(j_const.value("/not/existing"_json_pointer, Json({{"foo", "bar"}})) == Json({{"foo", "bar"}}));
|
|
CHECK(j_const.value("/not/existing"_json_pointer, Json({10, 100})) == Json({10, 100}));
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
#endif
|
|
|
|
// TODO(falbrechtskirchinger) merge with the other test case; clean up
|
|
TEST_CASE_TEMPLATE("element access 2 (additional value() tests)", Json, nlohmann::json, nlohmann::ordered_json) // NOLINT(readability-math-missing-parentheses, bugprone-throwing-static-initialization)
|
|
{
|
|
using string_t = typename Json::string_t;
|
|
using number_integer_t = typename Json::number_integer_t;
|
|
|
|
// test assumes string_t and object_t::key_type are the same
|
|
REQUIRE(std::is_same<string_t, typename Json::object_t::key_type>::value);
|
|
|
|
Json j
|
|
{
|
|
{"foo", "bar"},
|
|
{"baz", 42}
|
|
};
|
|
|
|
const char* cpstr = "default";
|
|
const char castr[] = "default"; // NOLINT(hicpp-avoid-c-arrays,modernize-avoid-c-arrays,cppcoreguidelines-avoid-c-arrays)
|
|
string_t const str = "default";
|
|
|
|
number_integer_t integer = 69;
|
|
std::size_t size = 69;
|
|
|
|
SECTION("deduced ValueType")
|
|
{
|
|
SECTION("literal key")
|
|
{
|
|
CHECK(j.value("foo", "default") == "bar");
|
|
CHECK(j.value("foo", cpstr) == "bar");
|
|
CHECK(j.value("foo", castr) == "bar");
|
|
CHECK(j.value("foo", str) == "bar");
|
|
// this test is in fact different from the one below,
|
|
// because of 0 considering const char * overloads
|
|
// whereas any other number does not
|
|
CHECK(j.value("baz", 0) == 42);
|
|
CHECK(j.value("baz", 47) == 42);
|
|
CHECK(j.value("baz", integer) == 42);
|
|
CHECK(j.value("baz", size) == 42);
|
|
|
|
CHECK(j.value("bar", "default") == "default");
|
|
CHECK(j.value("bar", 0) == 0);
|
|
CHECK(j.value("bar", 47) == 47);
|
|
CHECK(j.value("bar", integer) == integer);
|
|
CHECK(j.value("bar", size) == size);
|
|
|
|
CHECK_THROWS_WITH_AS(Json().value("foo", "default"), "[json.exception.type_error.306] cannot use value() with null", typename Json::type_error&);
|
|
CHECK_THROWS_WITH_AS(Json().value("foo", str), "[json.exception.type_error.306] cannot use value() with null", typename Json::type_error&);
|
|
}
|
|
|
|
SECTION("const char * key")
|
|
{
|
|
const char* key = "foo";
|
|
const char* key2 = "baz";
|
|
const char* key_notfound = "bar";
|
|
|
|
CHECK(j.value(key, "default") == "bar");
|
|
CHECK(j.value(key, cpstr) == "bar");
|
|
CHECK(j.value(key, castr) == "bar");
|
|
CHECK(j.value(key, str) == "bar");
|
|
CHECK(j.value(key2, 0) == 42);
|
|
CHECK(j.value(key2, 47) == 42);
|
|
CHECK(j.value(key2, integer) == 42);
|
|
CHECK(j.value(key2, size) == 42);
|
|
|
|
CHECK(j.value(key_notfound, "default") == "default");
|
|
CHECK(j.value(key_notfound, 0) == 0);
|
|
CHECK(j.value(key_notfound, 47) == 47);
|
|
CHECK(j.value(key_notfound, integer) == integer);
|
|
CHECK(j.value(key_notfound, size) == size);
|
|
|
|
CHECK_THROWS_WITH_AS(Json().value(key, "default"), "[json.exception.type_error.306] cannot use value() with null", typename Json::type_error&);
|
|
CHECK_THROWS_WITH_AS(Json().value(key, str), "[json.exception.type_error.306] cannot use value() with null", typename Json::type_error&);
|
|
}
|
|
|
|
SECTION("const char(&)[] key")
|
|
{
|
|
const char key[] = "foo"; // NOLINT(misc-const-correctness,hicpp-avoid-c-arrays,modernize-avoid-c-arrays,cppcoreguidelines-avoid-c-arrays)
|
|
const char key2[] = "baz"; // NOLINT(misc-const-correctness,hicpp-avoid-c-arrays,modernize-avoid-c-arrays,cppcoreguidelines-avoid-c-arrays)
|
|
const char key_notfound[] = "bar"; // NOLINT(misc-const-correctness,hicpp-avoid-c-arrays,modernize-avoid-c-arrays,cppcoreguidelines-avoid-c-arrays)
|
|
|
|
CHECK(j.value(key, "default") == "bar");
|
|
CHECK(j.value(key, cpstr) == "bar");
|
|
CHECK(j.value(key, castr) == "bar");
|
|
CHECK(j.value(key, str) == "bar");
|
|
CHECK(j.value(key2, 0) == 42);
|
|
CHECK(j.value(key2, 47) == 42);
|
|
CHECK(j.value(key2, integer) == 42);
|
|
CHECK(j.value(key2, size) == 42);
|
|
|
|
CHECK(j.value(key_notfound, "default") == "default");
|
|
CHECK(j.value(key_notfound, 0) == 0);
|
|
CHECK(j.value(key_notfound, 47) == 47);
|
|
CHECK(j.value(key_notfound, integer) == integer);
|
|
CHECK(j.value(key_notfound, size) == size);
|
|
|
|
CHECK_THROWS_WITH_AS(Json().value(key, "default"), "[json.exception.type_error.306] cannot use value() with null", typename Json::type_error&);
|
|
CHECK_THROWS_WITH_AS(Json().value(key, str), "[json.exception.type_error.306] cannot use value() with null", typename Json::type_error&);
|
|
}
|
|
|
|
SECTION("string_t/object_t::key_type key")
|
|
{
|
|
string_t const key = "foo";
|
|
string_t const key2 = "baz";
|
|
string_t const key_notfound = "bar";
|
|
|
|
CHECK(j.value(key, "default") == "bar");
|
|
CHECK(j.value(key, cpstr) == "bar");
|
|
CHECK(j.value(key, castr) == "bar");
|
|
CHECK(j.value(key, str) == "bar");
|
|
CHECK(j.value(key2, 0) == 42);
|
|
CHECK(j.value(key2, 47) == 42);
|
|
CHECK(j.value(key2, integer) == 42);
|
|
CHECK(j.value(key2, size) == 42);
|
|
|
|
CHECK(j.value(key_notfound, "default") == "default");
|
|
CHECK(j.value(key_notfound, 0) == 0);
|
|
CHECK(j.value(key_notfound, 47) == 47);
|
|
CHECK(j.value(key_notfound, integer) == integer);
|
|
CHECK(j.value(key_notfound, size) == size);
|
|
|
|
CHECK_THROWS_WITH_AS(Json().value(key, "default"), "[json.exception.type_error.306] cannot use value() with null", typename Json::type_error&);
|
|
CHECK_THROWS_WITH_AS(Json().value(key, str), "[json.exception.type_error.306] cannot use value() with null", typename Json::type_error&);
|
|
}
|
|
}
|
|
|
|
SECTION("explicit ValueType")
|
|
{
|
|
SECTION("literal key")
|
|
{
|
|
CHECK(j.template value<string_t>("foo", "default") == "bar");
|
|
CHECK(j.template value<string_t>("foo", cpstr) == "bar");
|
|
CHECK(j.template value<string_t>("foo", castr) == "bar");
|
|
CHECK(j.template value<string_t>("foo", str) == "bar");
|
|
CHECK(j.template value<number_integer_t>("baz", 0) == 42);
|
|
CHECK(j.template value<number_integer_t>("baz", 47) == 42);
|
|
CHECK(j.template value<number_integer_t>("baz", integer) == 42);
|
|
CHECK(j.template value<std::size_t>("baz", 0) == 42);
|
|
CHECK(j.template value<std::size_t>("baz", 47) == 42);
|
|
CHECK(j.template value<std::size_t>("baz", size) == 42);
|
|
|
|
CHECK(j.template value<string_t>("bar", "default") == "default");
|
|
CHECK(j.template value<number_integer_t>("bar", 0) == 0);
|
|
CHECK(j.template value<number_integer_t>("bar", 47) == 47);
|
|
CHECK(j.template value<number_integer_t>("bar", integer) == integer);
|
|
CHECK(j.template value<std::size_t>("bar", 0) == 0);
|
|
CHECK(j.template value<std::size_t>("bar", 47) == 47);
|
|
CHECK(j.template value<std::size_t>("bar", size) == size);
|
|
|
|
CHECK_THROWS_WITH_AS(Json().template value<string_t>("foo", "default"), "[json.exception.type_error.306] cannot use value() with null", typename Json::type_error&);
|
|
CHECK_THROWS_WITH_AS(Json().template value<string_t>("foo", str), "[json.exception.type_error.306] cannot use value() with null", typename Json::type_error&);
|
|
}
|
|
|
|
SECTION("const char * key")
|
|
{
|
|
const char* key = "foo";
|
|
const char* key2 = "baz";
|
|
const char* key_notfound = "bar";
|
|
|
|
CHECK(j.template value<string_t>(key, "default") == "bar");
|
|
CHECK(j.template value<string_t>(key, cpstr) == "bar");
|
|
CHECK(j.template value<string_t>(key, castr) == "bar");
|
|
CHECK(j.template value<string_t>(key, str) == "bar");
|
|
CHECK(j.template value<number_integer_t>(key2, 0) == 42);
|
|
CHECK(j.template value<number_integer_t>(key2, 47) == 42);
|
|
CHECK(j.template value<number_integer_t>(key2, integer) == 42);
|
|
CHECK(j.template value<std::size_t>(key2, 0) == 42);
|
|
CHECK(j.template value<std::size_t>(key2, 47) == 42);
|
|
CHECK(j.template value<std::size_t>(key2, size) == 42);
|
|
|
|
CHECK(j.template value<string_t>(key_notfound, "default") == "default");
|
|
CHECK(j.template value<number_integer_t>(key_notfound, 0) == 0);
|
|
CHECK(j.template value<number_integer_t>(key_notfound, 47) == 47);
|
|
CHECK(j.template value<number_integer_t>(key_notfound, integer) == integer);
|
|
CHECK(j.template value<std::size_t>(key_notfound, 0) == 0);
|
|
CHECK(j.template value<std::size_t>(key_notfound, 47) == 47);
|
|
CHECK(j.template value<std::size_t>(key_notfound, size) == size);
|
|
|
|
CHECK_THROWS_WITH_AS(Json().template value<string_t>(key, "default"), "[json.exception.type_error.306] cannot use value() with null", typename Json::type_error&);
|
|
CHECK_THROWS_WITH_AS(Json().template value<string_t>(key, str), "[json.exception.type_error.306] cannot use value() with null", typename Json::type_error&);
|
|
}
|
|
|
|
SECTION("const char(&)[] key")
|
|
{
|
|
const char key[] = "foo"; // NOLINT(misc-const-correctness,hicpp-avoid-c-arrays,modernize-avoid-c-arrays,cppcoreguidelines-avoid-c-arrays)
|
|
const char key2[] = "baz"; // NOLINT(misc-const-correctness,hicpp-avoid-c-arrays,modernize-avoid-c-arrays,cppcoreguidelines-avoid-c-arrays)
|
|
const char key_notfound[] = "bar"; // NOLINT(misc-const-correctness,hicpp-avoid-c-arrays,modernize-avoid-c-arrays,cppcoreguidelines-avoid-c-arrays)
|
|
|
|
CHECK(j.template value<string_t>(key, "default") == "bar");
|
|
CHECK(j.template value<string_t>(key, cpstr) == "bar");
|
|
CHECK(j.template value<string_t>(key, castr) == "bar");
|
|
CHECK(j.template value<string_t>(key, str) == "bar");
|
|
CHECK(j.template value<number_integer_t>(key2, 0) == 42);
|
|
CHECK(j.template value<number_integer_t>(key2, 47) == 42);
|
|
CHECK(j.template value<number_integer_t>(key2, integer) == 42);
|
|
CHECK(j.template value<std::size_t>(key2, 0) == 42);
|
|
CHECK(j.template value<std::size_t>(key2, 47) == 42);
|
|
CHECK(j.template value<std::size_t>(key2, size) == 42);
|
|
|
|
CHECK(j.template value<string_t>(key_notfound, "default") == "default");
|
|
CHECK(j.template value<number_integer_t>(key_notfound, 0) == 0);
|
|
CHECK(j.template value<number_integer_t>(key_notfound, 47) == 47);
|
|
CHECK(j.template value<number_integer_t>(key_notfound, integer) == integer);
|
|
CHECK(j.template value<std::size_t>(key_notfound, 0) == 0);
|
|
CHECK(j.template value<std::size_t>(key_notfound, 47) == 47);
|
|
CHECK(j.template value<std::size_t>(key_notfound, size) == size);
|
|
|
|
CHECK_THROWS_WITH_AS(Json().template value<string_t>(key, "default"), "[json.exception.type_error.306] cannot use value() with null", typename Json::type_error&);
|
|
CHECK_THROWS_WITH_AS(Json().template value<string_t>(key, str), "[json.exception.type_error.306] cannot use value() with null", typename Json::type_error&);
|
|
}
|
|
|
|
SECTION("string_t/object_t::key_type key")
|
|
{
|
|
string_t const key = "foo";
|
|
string_t const key2 = "baz";
|
|
string_t const key_notfound = "bar";
|
|
|
|
CHECK(j.template value<string_t>(key, "default") == "bar");
|
|
CHECK(j.template value<string_t>(key, cpstr) == "bar");
|
|
CHECK(j.template value<string_t>(key, castr) == "bar");
|
|
CHECK(j.template value<string_t>(key, str) == "bar");
|
|
CHECK(j.template value<number_integer_t>(key2, 0) == 42);
|
|
CHECK(j.template value<number_integer_t>(key2, 47) == 42);
|
|
CHECK(j.template value<std::size_t>(key2, 0) == 42);
|
|
CHECK(j.template value<std::size_t>(key2, 47) == 42);
|
|
|
|
CHECK(j.template value<string_t>(key_notfound, "default") == "default");
|
|
CHECK(j.template value<number_integer_t>(key_notfound, 0) == 0);
|
|
CHECK(j.template value<number_integer_t>(key_notfound, 47) == 47);
|
|
CHECK(j.template value<std::size_t>(key_notfound, 0) == 0);
|
|
CHECK(j.template value<std::size_t>(key_notfound, 47) == 47);
|
|
|
|
CHECK_THROWS_WITH_AS(Json().template value<string_t>(key, "default"), "[json.exception.type_error.306] cannot use value() with null", typename Json::type_error&);
|
|
CHECK_THROWS_WITH_AS(Json().template value<string_t>(key, str), "[json.exception.type_error.306] cannot use value() with null", typename Json::type_error&);
|
|
}
|
|
}
|
|
}
|
|
|