ENH: option to enable strict container size checks added, default is disabled
ENH: test cases adapted for strict size checks option MNT: updated amalgamation header
This commit is contained in:
parent
748f4ec227
commit
0358aac8ff
@ -25,6 +25,7 @@ option(JSON_BuildTests "Build the unit tests when BUILD_TESTING is enabled." ON)
|
||||
option(JSON_Install "Install CMake targets during install step." ON)
|
||||
option(JSON_MultipleHeaders "Use non-amalgamated version of the library." OFF)
|
||||
option(JSON_ImplicitConversions "Enable implicit conversions." ON)
|
||||
option(JSON_StrictContainerSize "Enable strict size checks for container conversions." OFF)
|
||||
|
||||
##
|
||||
## CONFIGURATION
|
||||
@ -70,6 +71,7 @@ target_compile_definitions(
|
||||
${NLOHMANN_JSON_TARGET_NAME}
|
||||
INTERFACE
|
||||
JSON_USE_IMPLICIT_CONVERSIONS=$<BOOL:${JSON_ImplicitConversions}>
|
||||
JSON_USE_STRICT_CONTAINER_SIZE=$<BOOL:${JSON_StrictContainerSize}>
|
||||
)
|
||||
|
||||
target_include_directories(
|
||||
|
||||
@ -164,6 +164,7 @@ template<typename BasicJsonType, typename T, std::size_t N>
|
||||
auto from_json(const BasicJsonType& j, T (&arr)[N])
|
||||
-> decltype(j.template get<T>(), void())
|
||||
{
|
||||
#if JSON_USE_STRICT_CONTAINER_SIZE
|
||||
if (JSON_HEDLEY_UNLIKELY(!j.is_array()))
|
||||
{
|
||||
JSON_THROW(type_error::create(302, "type must be array, but is " + std::string(j.type_name())));
|
||||
@ -172,6 +173,7 @@ auto from_json(const BasicJsonType& j, T (&arr)[N])
|
||||
{
|
||||
JSON_THROW(type_error::create(302, "array size must be " + std::to_string(N) + ", but is " + std::to_string(j.size())));
|
||||
}
|
||||
#endif
|
||||
for (std::size_t i = 0; i < N; ++i)
|
||||
{
|
||||
arr[i] = j.at(i).template get<T>();
|
||||
@ -189,11 +191,13 @@ auto from_json_array_impl(const BasicJsonType& j, std::array<T, N>& arr,
|
||||
priority_tag<2> /*unused*/)
|
||||
-> decltype(j.template get<T>(), void())
|
||||
{
|
||||
#if JSON_USE_STRICT_CONTAINER_SIZE
|
||||
// array type check done in from_json already, only check size
|
||||
if (JSON_HEDLEY_UNLIKELY(j.size() != N))
|
||||
{
|
||||
JSON_THROW(type_error::create(302, "array size must be " + std::to_string(N) + ", but is " + std::to_string(j.size())));
|
||||
}
|
||||
#endif
|
||||
for (std::size_t i = 0; i < N; ++i)
|
||||
{
|
||||
arr[i] = j.at(i).template get<T>();
|
||||
@ -339,6 +343,7 @@ void from_json(const BasicJsonType& j, ArithmeticType& val)
|
||||
template<typename BasicJsonType, typename A1, typename A2>
|
||||
void from_json(const BasicJsonType& j, std::pair<A1, A2>& p)
|
||||
{
|
||||
#if JSON_USE_STRICT_CONTAINER_SIZE
|
||||
if (JSON_HEDLEY_UNLIKELY(!j.is_array()))
|
||||
{
|
||||
JSON_THROW(type_error::create(302, "type must be array, but is " + std::string(j.type_name())));
|
||||
@ -347,12 +352,14 @@ void from_json(const BasicJsonType& j, std::pair<A1, A2>& p)
|
||||
{
|
||||
JSON_THROW(type_error::create(302, "array size must be 2, but is " + std::to_string(j.size())));
|
||||
}
|
||||
#endif
|
||||
p = {j.at(0).template get<A1>(), j.at(1).template get<A2>()};
|
||||
}
|
||||
|
||||
template<typename BasicJsonType, typename Tuple, std::size_t... Idx>
|
||||
void from_json_tuple_impl(const BasicJsonType& j, Tuple& t, index_sequence<Idx...> /*unused*/)
|
||||
{
|
||||
#if JSON_USE_STRICT_CONTAINER_SIZE
|
||||
if (JSON_HEDLEY_UNLIKELY(!j.is_array()))
|
||||
{
|
||||
JSON_THROW(type_error::create(302, "type must be array, but is " + std::string(j.type_name())));
|
||||
@ -361,6 +368,7 @@ void from_json_tuple_impl(const BasicJsonType& j, Tuple& t, index_sequence<Idx..
|
||||
{
|
||||
JSON_THROW(type_error::create(302, "array size must be " + std::to_string(sizeof...(Idx)) + ", but is " + std::to_string(j.size())));
|
||||
}
|
||||
#endif
|
||||
t = std::make_tuple(j.at(Idx).template get<typename std::tuple_element<Idx, Tuple>::type>()...);
|
||||
}
|
||||
|
||||
|
||||
@ -294,3 +294,7 @@
|
||||
#else
|
||||
#define JSON_EXPLICIT explicit
|
||||
#endif
|
||||
|
||||
#ifndef JSON_USE_STRICT_CONTAINER_SIZE
|
||||
#define JSON_USE_STRICT_CONTAINER_SIZE 0
|
||||
#endif
|
||||
|
||||
@ -2312,6 +2312,10 @@ JSON_HEDLEY_DIAGNOSTIC_POP
|
||||
#define JSON_EXPLICIT explicit
|
||||
#endif
|
||||
|
||||
#ifndef JSON_USE_STRICT_CONTAINER_SIZE
|
||||
#define JSON_USE_STRICT_CONTAINER_SIZE 0
|
||||
#endif
|
||||
|
||||
|
||||
namespace nlohmann
|
||||
{
|
||||
@ -3564,6 +3568,7 @@ template<typename BasicJsonType, typename T, std::size_t N>
|
||||
auto from_json(const BasicJsonType& j, T (&arr)[N])
|
||||
-> decltype(j.template get<T>(), void())
|
||||
{
|
||||
#if JSON_USE_STRICT_CONTAINER_SIZE
|
||||
if (JSON_HEDLEY_UNLIKELY(!j.is_array()))
|
||||
{
|
||||
JSON_THROW(type_error::create(302, "type must be array, but is " + std::string(j.type_name())));
|
||||
@ -3572,6 +3577,7 @@ auto from_json(const BasicJsonType& j, T (&arr)[N])
|
||||
{
|
||||
JSON_THROW(type_error::create(302, "array size must be " + std::to_string(N) + ", but is " + std::to_string(j.size())));
|
||||
}
|
||||
#endif
|
||||
for (std::size_t i = 0; i < N; ++i)
|
||||
{
|
||||
arr[i] = j.at(i).template get<T>();
|
||||
@ -3589,11 +3595,13 @@ auto from_json_array_impl(const BasicJsonType& j, std::array<T, N>& arr,
|
||||
priority_tag<2> /*unused*/)
|
||||
-> decltype(j.template get<T>(), void())
|
||||
{
|
||||
#if JSON_USE_STRICT_CONTAINER_SIZE
|
||||
// array type check done in from_json already, only check size
|
||||
if (JSON_HEDLEY_UNLIKELY(j.size() != N))
|
||||
{
|
||||
JSON_THROW(type_error::create(302, "array size must be " + std::to_string(N) + ", but is " + std::to_string(j.size())));
|
||||
}
|
||||
#endif
|
||||
for (std::size_t i = 0; i < N; ++i)
|
||||
{
|
||||
arr[i] = j.at(i).template get<T>();
|
||||
@ -3739,6 +3747,7 @@ void from_json(const BasicJsonType& j, ArithmeticType& val)
|
||||
template<typename BasicJsonType, typename A1, typename A2>
|
||||
void from_json(const BasicJsonType& j, std::pair<A1, A2>& p)
|
||||
{
|
||||
#if JSON_USE_STRICT_CONTAINER_SIZE
|
||||
if (JSON_HEDLEY_UNLIKELY(!j.is_array()))
|
||||
{
|
||||
JSON_THROW(type_error::create(302, "type must be array, but is " + std::string(j.type_name())));
|
||||
@ -3747,12 +3756,14 @@ void from_json(const BasicJsonType& j, std::pair<A1, A2>& p)
|
||||
{
|
||||
JSON_THROW(type_error::create(302, "array size must be 2, but is " + std::to_string(j.size())));
|
||||
}
|
||||
#endif
|
||||
p = {j.at(0).template get<A1>(), j.at(1).template get<A2>()};
|
||||
}
|
||||
|
||||
template<typename BasicJsonType, typename Tuple, std::size_t... Idx>
|
||||
void from_json_tuple_impl(const BasicJsonType& j, Tuple& t, index_sequence<Idx...> /*unused*/)
|
||||
{
|
||||
#if JSON_USE_STRICT_CONTAINER_SIZE
|
||||
if (JSON_HEDLEY_UNLIKELY(!j.is_array()))
|
||||
{
|
||||
JSON_THROW(type_error::create(302, "type must be array, but is " + std::string(j.type_name())));
|
||||
@ -3761,6 +3772,7 @@ void from_json_tuple_impl(const BasicJsonType& j, Tuple& t, index_sequence<Idx..
|
||||
{
|
||||
JSON_THROW(type_error::create(302, "array size must be " + std::to_string(sizeof...(Idx)) + ", but is " + std::to_string(j.size())));
|
||||
}
|
||||
#endif
|
||||
t = std::make_tuple(j.at(Idx).template get<typename std::tuple_element<Idx, Tuple>::type>()...);
|
||||
}
|
||||
|
||||
|
||||
@ -269,6 +269,17 @@ TEST_CASE("constructors")
|
||||
CHECK(j[1] == std::get<1>(p));
|
||||
}
|
||||
|
||||
#if !(JSON_USE_STRICT_CONTAINER_SIZE)
|
||||
SECTION("std::pair with discarded values")
|
||||
{
|
||||
json j{1, 2.0, "string"};
|
||||
|
||||
const auto p = j.get<std::pair<int, float>>();
|
||||
CHECK(p.first == j[0]);
|
||||
CHECK(p.second == j[1]);
|
||||
}
|
||||
#endif
|
||||
|
||||
SECTION("std::tuple")
|
||||
{
|
||||
const auto t = std::make_tuple(1.0, std::string{"string"}, 42, std::vector<int> {0, 1});
|
||||
@ -284,8 +295,21 @@ TEST_CASE("constructors")
|
||||
CHECK(j[3][1] == 1);
|
||||
}
|
||||
|
||||
#if !(JSON_USE_STRICT_CONTAINER_SIZE)
|
||||
SECTION("std::tuple with discarded values")
|
||||
{
|
||||
json j{1, 2.0, "string", 42};
|
||||
|
||||
const auto t = j.get<std::tuple<int, float, std::string>>();
|
||||
CHECK(std::get<0>(t) == j[0]);
|
||||
CHECK(std::get<1>(t) == j[1]);
|
||||
CHECK(std::get<2>(t) == j[2]);
|
||||
}
|
||||
#endif
|
||||
|
||||
SECTION("std::pair/tuple/array failures")
|
||||
{
|
||||
#if JSON_USE_STRICT_CONTAINER_SIZE
|
||||
json j1{1};
|
||||
json j2{1, 2, 3};
|
||||
|
||||
@ -301,6 +325,16 @@ TEST_CASE("constructors")
|
||||
CHECK_THROWS_WITH((j1.get<std::array<int, 3>>()), "[json.exception.type_error.302] array size must be 3, but is 1");
|
||||
CHECK_THROWS_AS((j2.get<std::array<int, 1>>()), json::type_error&);
|
||||
CHECK_THROWS_WITH((j2.get<std::array<int, 1>>()), "[json.exception.type_error.302] array size must be 1, but is 3");
|
||||
#else
|
||||
json j{1};
|
||||
|
||||
CHECK_THROWS_AS((j.get<std::pair<int, int>>()), json::out_of_range&);
|
||||
CHECK_THROWS_WITH((j.get<std::pair<int, int>>()), "[json.exception.out_of_range.401] array index 1 is out of range");
|
||||
CHECK_THROWS_AS((j.get<std::tuple<int, int>>()), json::out_of_range&);
|
||||
CHECK_THROWS_WITH((j.get<std::tuple<int, int>>()), "[json.exception.out_of_range.401] array index 1 is out of range");
|
||||
CHECK_THROWS_AS((j.get<std::array<int, 3>>()), json::out_of_range&);
|
||||
CHECK_THROWS_WITH((j.get<std::array<int, 3>>()), "[json.exception.out_of_range.401] array index 1 is out of range");
|
||||
#endif
|
||||
}
|
||||
|
||||
SECTION("std::forward_list<json>")
|
||||
|
||||
@ -405,18 +405,30 @@ TEST_CASE("value conversion")
|
||||
{
|
||||
json j1 = {1, 2, 3, 4};
|
||||
int arr6[] = {1, 2, 3, 4, 5, 6};
|
||||
#if JSON_USE_STRICT_CONTAINER_SIZE
|
||||
CHECK_THROWS_AS(j1.get_to(arr6), json::type_error&);
|
||||
CHECK_THROWS_WITH(j1.get_to(arr6), "[json.exception.type_error.302] "
|
||||
"array size must be 6, but is 4");
|
||||
#else
|
||||
CHECK_THROWS_AS(j1.get_to(arr6), json::out_of_range&);
|
||||
CHECK_THROWS_WITH(j1.get_to(arr6), "[json.exception.out_of_range.401] "
|
||||
"array index 4 is out of range");
|
||||
#endif
|
||||
}
|
||||
|
||||
SECTION("built-in array is smaller than JSON")
|
||||
{
|
||||
json j1 = {1, 2, 3, 4};
|
||||
int arr2[] = {8, 9};
|
||||
#if JSON_USE_STRICT_CONTAINER_SIZE
|
||||
CHECK_THROWS_AS(j1.get_to(arr2), json::type_error&);
|
||||
CHECK_THROWS_WITH(j1.get_to(arr2), "[json.exception.type_error.302] "
|
||||
"array size must be 2, but is 4");
|
||||
#else
|
||||
j1.get_to(arr2);
|
||||
CHECK(arr2[0] == 1);
|
||||
CHECK(arr2[1] == 2);
|
||||
#endif
|
||||
}
|
||||
|
||||
SECTION("built-in array from non-array type")
|
||||
@ -424,8 +436,13 @@ TEST_CASE("value conversion")
|
||||
json j1;
|
||||
int arr2[] = {8, 9};
|
||||
CHECK_THROWS_AS(j1.get_to(arr2), json::type_error&);
|
||||
#if JSON_USE_STRICT_CONTAINER_SIZE
|
||||
CHECK_THROWS_WITH(j1.get_to(arr2), "[json.exception.type_error.302] "
|
||||
"type must be array, but is null");
|
||||
#else
|
||||
CHECK_THROWS_WITH(j1.get_to(arr2), "[json.exception.type_error.304] "
|
||||
"cannot use at() with null");
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
@ -1525,17 +1542,29 @@ TEST_CASE("value conversion")
|
||||
SECTION("std::array is larger than JSON")
|
||||
{
|
||||
std::array<int, 6> arr6 = {{1, 2, 3, 4, 5, 6}};
|
||||
#if JSON_USE_STRICT_CONTAINER_SIZE
|
||||
CHECK_THROWS_AS(j1.get_to(arr6), json::type_error&);
|
||||
CHECK_THROWS_WITH(j1.get_to(arr6), "[json.exception.type_error.302] "
|
||||
"array size must be 6, but is 4");
|
||||
#else
|
||||
CHECK_THROWS_AS(j1.get_to(arr6), json::out_of_range&);
|
||||
CHECK_THROWS_WITH(j1.get_to(arr6), "[json.exception.out_of_range.401] "
|
||||
"array index 4 is out of range");
|
||||
#endif
|
||||
}
|
||||
|
||||
SECTION("std::array is smaller than JSON")
|
||||
{
|
||||
std::array<int, 2> arr2 = {{8, 9}};
|
||||
#if JSON_USE_STRICT_CONTAINER_SIZE
|
||||
CHECK_THROWS_AS(j1.get_to(arr2), json::type_error&);
|
||||
CHECK_THROWS_WITH(j1.get_to(arr2), "[json.exception.type_error.302] "
|
||||
"array size must be 2, but is 4");
|
||||
#else
|
||||
j1.get_to(arr2);
|
||||
CHECK(arr2[0] == 1);
|
||||
CHECK(arr2[1] == 2);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
@ -1703,18 +1732,30 @@ TEST_CASE("value conversion")
|
||||
|
||||
SECTION("std::pair is larger than JSON")
|
||||
{
|
||||
std::pair<int, int> p;
|
||||
std::pair<int, int> p(8, 9);
|
||||
#if JSON_USE_STRICT_CONTAINER_SIZE
|
||||
CHECK_THROWS_AS(j10.get_to(p), json::type_error&);
|
||||
CHECK_THROWS_WITH(j10.get_to(p), "[json.exception.type_error.302] "
|
||||
"array size must be 2, but is 1");
|
||||
#else
|
||||
CHECK_THROWS_AS(j10.get_to(p), json::out_of_range&);
|
||||
CHECK_THROWS_WITH(j10.get_to(p), "[json.exception.out_of_range.401] "
|
||||
"array index 1 is out of range");
|
||||
#endif
|
||||
}
|
||||
|
||||
SECTION("std::pair is smaller than JSON")
|
||||
{
|
||||
std::pair<int, int> p;
|
||||
std::pair<int, int> p(8, 9);
|
||||
#if JSON_USE_STRICT_CONTAINER_SIZE
|
||||
CHECK_THROWS_AS(j9.get_to(p), json::type_error&);
|
||||
CHECK_THROWS_WITH(j9.get_to(p), "[json.exception.type_error.302] "
|
||||
"array size must be 2, but is 3");
|
||||
#else
|
||||
j9.get_to(p);
|
||||
CHECK(p.first == 1);
|
||||
CHECK(p.second == 2);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
@ -1733,18 +1774,30 @@ TEST_CASE("value conversion")
|
||||
|
||||
SECTION("std::tuple is larger than JSON")
|
||||
{
|
||||
std::tuple<int, int> t;
|
||||
std::tuple<int, int> t(8, 9);
|
||||
#if JSON_USE_STRICT_CONTAINER_SIZE
|
||||
CHECK_THROWS_AS(j10.get_to(t), json::type_error&);
|
||||
CHECK_THROWS_WITH(j10.get_to(t), "[json.exception.type_error.302] "
|
||||
"array size must be 2, but is 1");
|
||||
#else
|
||||
CHECK_THROWS_AS(j10.get_to(t), json::out_of_range&);
|
||||
CHECK_THROWS_WITH(j10.get_to(t), "[json.exception.out_of_range.401] "
|
||||
"array index 1 is out of range");
|
||||
#endif
|
||||
}
|
||||
|
||||
SECTION("std::tuple is smaller than JSON")
|
||||
{
|
||||
std::tuple<int, int> t;
|
||||
std::tuple<int, int> t(8, 9);
|
||||
#if JSON_USE_STRICT_CONTAINER_SIZE
|
||||
CHECK_THROWS_AS(j9.get_to(t), json::type_error&);
|
||||
CHECK_THROWS_WITH(j9.get_to(t), "[json.exception.type_error.302] "
|
||||
"array size must be 2, but is 3");
|
||||
#else
|
||||
j9.get_to(t);
|
||||
CHECK(std::get<0>(t) == 1);
|
||||
CHECK(std::get<1>(t) == 2);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
@ -1753,12 +1806,21 @@ TEST_CASE("value conversion")
|
||||
CHECK_THROWS_AS((json().get<std::pair<int, int>>()), json::type_error&);
|
||||
CHECK_THROWS_AS((json().get<std::tuple<int, int>>()), json::type_error&);
|
||||
|
||||
#if JSON_USE_STRICT_CONTAINER_SIZE
|
||||
CHECK_THROWS_WITH(
|
||||
(json().get<std::pair<int, int>>()),
|
||||
"[json.exception.type_error.302] type must be array, but is null");
|
||||
CHECK_THROWS_WITH(
|
||||
(json().get<std::tuple<int, int>>()),
|
||||
"[json.exception.type_error.302] type must be array, but is null");
|
||||
#else
|
||||
CHECK_THROWS_WITH(
|
||||
(json().get<std::pair<int, int>>()),
|
||||
"[json.exception.type_error.304] cannot use at() with null");
|
||||
CHECK_THROWS_WITH(
|
||||
(json().get<std::tuple<int, int>>()),
|
||||
"[json.exception.type_error.304] cannot use at() with null");
|
||||
#endif
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Loading…
Reference in New Issue
Block a user