mirror of
https://github.com/nlohmann/json.git
synced 2026-10-10 00:17:13 +00:00
Merge branch 'develop' into claude/test-compilation-speed-993125
Signed-off-by: Niels Lohmann <mail@nlohmann.me>
This commit is contained in:
17 files changed
+1080
-413
No files matched your search
@@ -0,0 +1,75 @@
|
||||
// __ _____ _____ _____
|
||||
// __| | __| | | | 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
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <map>
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <utility>
|
||||
#include <nlohmann/json.hpp>
|
||||
|
||||
namespace custom_object_key_test
|
||||
{
|
||||
class key
|
||||
{
|
||||
public:
|
||||
key() = default;
|
||||
|
||||
key(const char* value)
|
||||
: m_value(value)
|
||||
{}
|
||||
|
||||
key(std::string value)
|
||||
: m_value(std::move(value))
|
||||
{}
|
||||
|
||||
operator std::string() const
|
||||
{
|
||||
return m_value;
|
||||
}
|
||||
|
||||
// Required by JSON_DIAGNOSTICS, which reads object keys through data()
|
||||
// when building the path of an exception.
|
||||
const char* data() const noexcept
|
||||
{
|
||||
return m_value.data();
|
||||
}
|
||||
|
||||
friend bool operator<(const key& lhs, const key& rhs)
|
||||
{
|
||||
return lhs.m_value < rhs.m_value;
|
||||
}
|
||||
|
||||
private:
|
||||
std::string m_value;
|
||||
};
|
||||
|
||||
template<typename Key, typename Value, typename Compare, typename Allocator>
|
||||
class object
|
||||
: public std::map <
|
||||
key,
|
||||
Value,
|
||||
std::less<key>, // NOLINT(modernize-use-transparent-functors)
|
||||
typename std::allocator_traits<Allocator>::template rebind_alloc <
|
||||
std::pair<const key, Value >>>
|
||||
{
|
||||
private:
|
||||
using allocator_type =
|
||||
typename std::allocator_traits<Allocator>::template rebind_alloc <
|
||||
std::pair<const key, Value >>;
|
||||
|
||||
using base_type =
|
||||
std::map<key, Value, std::less<key>, allocator_type>; // NOLINT(modernize-use-transparent-functors)
|
||||
|
||||
public:
|
||||
using base_type::base_type;
|
||||
};
|
||||
|
||||
using json = nlohmann::basic_json<object>;
|
||||
} // namespace custom_object_key_test
|
||||
@@ -12,7 +12,11 @@
|
||||
#include <nlohmann/json.hpp>
|
||||
using nlohmann::json;
|
||||
|
||||
#include <array>
|
||||
#include <map>
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
namespace
|
||||
@@ -55,6 +59,53 @@ std::string dump_and_parse(const std::string& raw, eh error_handler)
|
||||
return json::parse(json(raw).dump(-1, ' ', false, error_handler)).get<std::string>();
|
||||
}
|
||||
|
||||
// an object key type that is not string_t, but converts implicitly to it;
|
||||
// data() is only used when JSON_DIAGNOSTICS is enabled
|
||||
DOCTEST_CLANG_SUPPRESS_WARNING_PUSH
|
||||
DOCTEST_CLANG_SUPPRESS_WARNING("-Wunused-member-function")
|
||||
class converting_key
|
||||
{
|
||||
public:
|
||||
converting_key(const char* s) : m_value(s) {} // NOLINT(google-explicit-constructor,hicpp-explicit-conversions)
|
||||
converting_key(std::string s) : m_value(std::move(s)) {} // NOLINT(google-explicit-constructor,hicpp-explicit-conversions)
|
||||
|
||||
// the conversion yields a temporary string_t
|
||||
operator std::string() const // NOLINT(google-explicit-constructor,hicpp-explicit-conversions)
|
||||
{
|
||||
return m_value;
|
||||
}
|
||||
|
||||
// read by the exception messages when JSON_DIAGNOSTICS is enabled
|
||||
const char* data() const noexcept
|
||||
{
|
||||
return m_value.data();
|
||||
}
|
||||
|
||||
friend bool operator<(const converting_key& lhs, const converting_key& rhs)
|
||||
{
|
||||
return lhs.m_value < rhs.m_value;
|
||||
}
|
||||
|
||||
private:
|
||||
std::string m_value;
|
||||
};
|
||||
DOCTEST_CLANG_SUPPRESS_WARNING_POP
|
||||
|
||||
// ObjectType using converting_key; the Key template argument is ignored
|
||||
template<typename Key, typename Value, typename Compare, typename Allocator>
|
||||
class converting_key_object : public std::map<converting_key, Value, std::less<converting_key>, // NOLINT(modernize-use-transparent-functors)
|
||||
typename std::allocator_traits<Allocator>::template rebind_alloc<std::pair<const converting_key, Value>>>
|
||||
{
|
||||
using base_type = std::map<converting_key, Value, std::less<converting_key>, // NOLINT(modernize-use-transparent-functors)
|
||||
typename std::allocator_traits<Allocator>::template rebind_alloc<std::pair<const converting_key, Value>>>;
|
||||
|
||||
public:
|
||||
using base_type::base_type;
|
||||
using base_type::operator=;
|
||||
};
|
||||
|
||||
using converting_key_json = nlohmann::basic_json<converting_key_object>;
|
||||
|
||||
} // namespace
|
||||
|
||||
TEST_CASE("UTF-8 error_handler for the binary readers and writers")
|
||||
@@ -370,3 +421,109 @@ TEST_CASE("UTF-8 error_handler for the binary readers and writers")
|
||||
CHECK(json::from_bson(bson_bytes)["k"].get<std::string>() == ill_formed_cases()[0].bytes);
|
||||
}
|
||||
}
|
||||
|
||||
// The UBJSON and BJData writers bind the (possibly sanitized) key to a const
|
||||
// string_t&. If key_type is not string_t but converts to it, the converted
|
||||
// temporary must outlive that reference; this was a use-after-scope found by
|
||||
// AddressSanitizer. Keys exceed the small string optimization on purpose.
|
||||
TEST_CASE("UBJSON and BJData writers with an object_t whose key_type is not string_t")
|
||||
{
|
||||
const std::string long_prefix(70, 'k');
|
||||
|
||||
SECTION("well-formed keys, every error_handler")
|
||||
{
|
||||
const std::string key1 = long_prefix + "-first";
|
||||
const std::string key2 = long_prefix + "-second";
|
||||
|
||||
converting_key_json::object_t o;
|
||||
o.emplace(converting_key(key1), 1);
|
||||
o.emplace(converting_key(key2), "value");
|
||||
const converting_key_json v(std::move(o));
|
||||
|
||||
json expected;
|
||||
expected[key1] = 1;
|
||||
expected[key2] = "value";
|
||||
|
||||
const std::array<std::pair<bool, bool>, 3> combos = {{{false, false}, {true, false}, {true, true}}};
|
||||
for (const auto h : all_handlers())
|
||||
{
|
||||
CAPTURE(static_cast<int>(h))
|
||||
for (const auto& combo : combos)
|
||||
{
|
||||
const bool use_count = combo.first;
|
||||
const bool use_type = combo.second;
|
||||
CAPTURE(use_count)
|
||||
CAPTURE(use_type)
|
||||
|
||||
CHECK(json::from_ubjson(converting_key_json::to_ubjson(v, use_count, use_type, h)) == expected);
|
||||
CHECK(json::from_bjdata(converting_key_json::to_bjdata(v, use_count, use_type, json::bjdata_version_t::draft2, h)) == expected);
|
||||
CHECK(json::from_bjdata(converting_key_json::to_bjdata(v, use_count, use_type, json::bjdata_version_t::draft3, h)) == expected);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
SECTION("ill-formed keys")
|
||||
{
|
||||
for (const auto& c : ill_formed_cases())
|
||||
{
|
||||
CAPTURE(c.name)
|
||||
const std::string key = long_prefix + c.bytes;
|
||||
|
||||
converting_key_json::object_t o;
|
||||
o.emplace(converting_key(key), 1);
|
||||
const converting_key_json v(std::move(o));
|
||||
|
||||
CHECK_THROWS_AS(converting_key_json::to_ubjson(v, false, false, eh::strict), converting_key_json::type_error&);
|
||||
CHECK_THROWS_AS(converting_key_json::to_bjdata(v, false, false, json::bjdata_version_t::draft2, eh::strict), converting_key_json::type_error&);
|
||||
|
||||
for (const auto h :
|
||||
{
|
||||
eh::replace, eh::ignore
|
||||
})
|
||||
{
|
||||
CAPTURE(static_cast<int>(h))
|
||||
const std::string expected = dump_and_parse(key, h);
|
||||
|
||||
CHECK(json::from_ubjson(converting_key_json::to_ubjson(v, false, false, h)).begin().key() == expected);
|
||||
CHECK(json::from_bjdata(converting_key_json::to_bjdata(v, false, false, json::bjdata_version_t::draft2, h)).begin().key() == expected);
|
||||
}
|
||||
|
||||
CHECK(json::from_ubjson(converting_key_json::to_ubjson(v, false, false, eh::keep)).begin().key() == key);
|
||||
CHECK(json::from_bjdata(converting_key_json::to_bjdata(v, false, false, json::bjdata_version_t::draft2, eh::keep)).begin().key() == key);
|
||||
}
|
||||
}
|
||||
|
||||
SECTION("nested deeper than the recursion limit")
|
||||
{
|
||||
// wrap the previous value, innermost first
|
||||
converting_key_json v = 42;
|
||||
json expected = 42;
|
||||
for (int i = 199; i >= 0; --i)
|
||||
{
|
||||
const std::string key = "level-" + std::to_string(i) + "-" + std::string(64, 'x');
|
||||
|
||||
converting_key_json::object_t o;
|
||||
o.emplace(converting_key(key), std::move(v));
|
||||
v = converting_key_json(std::move(o));
|
||||
|
||||
json e;
|
||||
e[key] = std::move(expected);
|
||||
expected = std::move(e);
|
||||
}
|
||||
|
||||
for (const auto h : all_handlers())
|
||||
{
|
||||
CAPTURE(static_cast<int>(h))
|
||||
for (const bool use_count :
|
||||
{
|
||||
false, true
|
||||
})
|
||||
{
|
||||
CAPTURE(use_count)
|
||||
|
||||
CHECK(json::from_ubjson(converting_key_json::to_ubjson(v, use_count, false, h)) == expected);
|
||||
CHECK(json::from_bjdata(converting_key_json::to_bjdata(v, use_count, false, json::bjdata_version_t::draft2, h)) == expected);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -46,9 +46,7 @@ class huge_binary_t : public std::vector<std::uint8_t>
|
||||
}
|
||||
};
|
||||
|
||||
using huge_binary_json = nlohmann::basic_json <
|
||||
std::map, std::vector, std::string, bool, std::int64_t, std::uint64_t,
|
||||
double, std::allocator, nlohmann::adl_serializer, huge_binary_t, void >;
|
||||
using huge_binary_json = nlohmann::json::with_binary_t<huge_binary_t>;
|
||||
|
||||
// a string type that can be made to report a size beyond INT32_MAX without
|
||||
// allocating that much memory, so BSON length overflow can be tested for
|
||||
@@ -96,9 +94,7 @@ class huge_string_t : public std::string
|
||||
bool pretend_huge = false;
|
||||
};
|
||||
|
||||
using huge_string_json = nlohmann::basic_json <
|
||||
std::map, std::vector, huge_string_t, bool, std::int64_t, std::uint64_t,
|
||||
double, std::allocator, nlohmann::adl_serializer, std::vector<std::uint8_t>, void >;
|
||||
using huge_string_json = nlohmann::json::with_string_t<huge_string_t>;
|
||||
} // namespace
|
||||
|
||||
TEST_CASE("BSON")
|
||||
|
||||
@@ -28,6 +28,7 @@ using nlohmann::json;
|
||||
#include "make_test_data_available.hpp"
|
||||
#include "round_trip_corpus.hpp"
|
||||
#include "test_utils.hpp"
|
||||
#include "custom_object_key_type.hpp"
|
||||
#include "sax_countdown.hpp"
|
||||
using utils::SaxCountdown;
|
||||
|
||||
@@ -3357,3 +3358,55 @@ TEST_CASE("CBOR large strings and binaries (chunked reader)")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
TEST_CASE("CBOR supports custom object key types")
|
||||
{
|
||||
using custom_json = custom_object_key_test::json;
|
||||
using custom_key = custom_object_key_test::key;
|
||||
|
||||
custom_json::object_t object;
|
||||
object.emplace(custom_key{"short"}, 1);
|
||||
object.emplace(
|
||||
custom_key{"a key longer than twenty-three characters"},
|
||||
2);
|
||||
|
||||
const custom_json value(std::move(object));
|
||||
const auto encoded = custom_json::to_cbor(value);
|
||||
|
||||
CHECK(nlohmann::json::from_cbor(encoded) == nlohmann::json
|
||||
{
|
||||
{"short", 1},
|
||||
{"a key longer than twenty-three characters", 2}
|
||||
});
|
||||
}
|
||||
|
||||
TEST_CASE("CBOR supports custom object key types nested deeper than the recursion depth limit")
|
||||
{
|
||||
// below detail::recursion_depth_limit(), keys are written by
|
||||
// write_cbor_iterative instead of write_cbor
|
||||
using custom_json = custom_object_key_test::json;
|
||||
using custom_key = custom_object_key_test::key;
|
||||
|
||||
const std::size_t depth = nlohmann::detail::recursion_depth_limit() + 10;
|
||||
|
||||
custom_json value = 1;
|
||||
nlohmann::json expected = 1;
|
||||
for (std::size_t i = 0; i < depth; ++i)
|
||||
{
|
||||
// alternate short keys with ones long enough to need a length byte
|
||||
const std::string name = (i % 2 == 0) ? "k" + std::to_string(i)
|
||||
: "a key longer than thirty-one characters " + std::to_string(i);
|
||||
|
||||
custom_json::object_t object;
|
||||
object.emplace(custom_key{name}, std::move(value));
|
||||
value = custom_json(std::move(object));
|
||||
|
||||
nlohmann::json::object_t expected_object;
|
||||
expected_object.emplace(name, std::move(expected));
|
||||
expected = nlohmann::json(std::move(expected_object));
|
||||
}
|
||||
|
||||
const auto encoded = custom_json::to_cbor(value);
|
||||
CHECK(encoded == nlohmann::json::to_cbor(expected));
|
||||
CHECK(nlohmann::json::from_cbor(encoded) == expected);
|
||||
}
|
||||
@@ -400,20 +400,7 @@ class base_class_with_hidden_members
|
||||
std::size_t m_size = 42;
|
||||
};
|
||||
|
||||
using json_with_hidden_base_members =
|
||||
nlohmann::basic_json <
|
||||
std::map,
|
||||
std::vector,
|
||||
std::string,
|
||||
bool,
|
||||
std::int64_t,
|
||||
std::uint64_t,
|
||||
double,
|
||||
std::allocator,
|
||||
nlohmann::adl_serializer,
|
||||
std::vector<std::uint8_t>,
|
||||
base_class_with_hidden_members
|
||||
>;
|
||||
using json_with_hidden_base_members = nlohmann::json::with_base_class_t<base_class_with_hidden_members>;
|
||||
|
||||
TEST_CASE("JSON Node as_base_class")
|
||||
{
|
||||
@@ -459,19 +446,7 @@ struct const_member_base
|
||||
const int id = 7; // NOLINT(misc-non-private-member-variables-in-classes)
|
||||
};
|
||||
|
||||
using json_with_const_base = nlohmann::basic_json <
|
||||
std::map,
|
||||
std::vector,
|
||||
std::string,
|
||||
bool,
|
||||
std::int64_t,
|
||||
std::uint64_t,
|
||||
double,
|
||||
std::allocator,
|
||||
nlohmann::adl_serializer,
|
||||
std::vector<std::uint8_t>,
|
||||
const_member_base
|
||||
>;
|
||||
using json_with_const_base = nlohmann::json::with_base_class_t<const_member_base>;
|
||||
|
||||
// build an array nested @a depth levels deep, with the innermost value 1;
|
||||
// every level is constructed (never assigned), since const_member_base does
|
||||
|
||||
@@ -25,9 +25,7 @@
|
||||
#include <vector>
|
||||
|
||||
// a BinaryType whose value type is not an integer type at all
|
||||
using byte_binary_json = nlohmann::basic_json <
|
||||
std::map, std::vector, std::string, bool, std::int64_t, std::uint64_t,
|
||||
double, std::allocator, nlohmann::adl_serializer, std::vector<std::byte>, void >;
|
||||
using byte_binary_json = nlohmann::json::with_binary_t<std::vector<std::byte>>;
|
||||
|
||||
TEST_CASE("binary type whose value type is not std::uint8_t (C++17)")
|
||||
{
|
||||
|
||||
@@ -22,9 +22,7 @@ namespace
|
||||
|
||||
// a BinaryType whose value type is signed: the elements must still be
|
||||
// processed as the numbers 0..255
|
||||
using char_binary_json = nlohmann::basic_json <
|
||||
std::map, std::vector, std::string, bool, std::int64_t, std::uint64_t,
|
||||
double, std::allocator, nlohmann::adl_serializer, std::vector<char>, void >;
|
||||
using char_binary_json = nlohmann::json::with_binary_t<std::vector<char>>;
|
||||
|
||||
} // namespace
|
||||
|
||||
|
||||
@@ -920,3 +920,114 @@ TEST_CASE("unescaping keeps a '~' that does not start an escape sequence")
|
||||
nlohmann::detail::unescape(s);
|
||||
CHECK(s == "~/~");
|
||||
}
|
||||
|
||||
TEST_CASE("flatten of structured values")
|
||||
{
|
||||
SECTION("values nested too deeply for the call stack (#5393)")
|
||||
{
|
||||
// flatten() used to recurse once per nesting level
|
||||
const std::size_t depth = 100000;
|
||||
for (const bool objects :
|
||||
{
|
||||
false, true
|
||||
})
|
||||
{
|
||||
CAPTURE(objects)
|
||||
std::string text;
|
||||
std::string path;
|
||||
for (std::size_t i = 0; i < depth; ++i)
|
||||
{
|
||||
text += objects ? "{\"a\":" : "[";
|
||||
path += objects ? "/a" : "/0";
|
||||
}
|
||||
text += "0";
|
||||
text += std::string(depth, objects ? '}' : ']');
|
||||
const auto value = json::parse(text);
|
||||
|
||||
const auto flat = value.flatten();
|
||||
REQUIRE(flat.size() == 1);
|
||||
REQUIRE(flat.begin().key().size() == path.size());
|
||||
CHECK(flat.begin().key() == path);
|
||||
CHECK(flat.begin().value() == 0);
|
||||
|
||||
// unflatten() is linear in the depth, so the value roundtrips
|
||||
CHECK(flat.unflatten() == value);
|
||||
}
|
||||
}
|
||||
|
||||
SECTION("unflatten of a deeply nested pointer")
|
||||
{
|
||||
const std::size_t depth = 100000;
|
||||
for (const bool objects :
|
||||
{
|
||||
false, true
|
||||
})
|
||||
{
|
||||
CAPTURE(objects)
|
||||
std::string path;
|
||||
for (std::size_t i = 0; i < depth; ++i)
|
||||
{
|
||||
path += objects ? "/a" : "/0";
|
||||
}
|
||||
|
||||
json flat = json::object();
|
||||
flat[path] = 1;
|
||||
const json value = flat.unflatten();
|
||||
|
||||
// walk down iteratively
|
||||
std::size_t levels = 0;
|
||||
const json* current = &value;
|
||||
while (objects ? current->is_object() : current->is_array())
|
||||
{
|
||||
REQUIRE(current->size() == 1);
|
||||
current = objects ? ¤t->at("a") : ¤t->at(0);
|
||||
++levels;
|
||||
}
|
||||
CHECK(levels == depth);
|
||||
CHECK(*current == 1);
|
||||
}
|
||||
}
|
||||
|
||||
SECTION("unflatten does not depend on the iteration order")
|
||||
{
|
||||
// the "0" key comes after its sibling in iteration order
|
||||
const nlohmann::ordered_json flat_array = nlohmann::ordered_json::parse(R"({"/a/1": 2, "/a/0": 1})");
|
||||
CHECK(flat_array.unflatten() == nlohmann::ordered_json::parse(R"({"a": [1, 2]})"));
|
||||
|
||||
const nlohmann::ordered_json flat_object = nlohmann::ordered_json::parse(R"({"/b/1": 2})");
|
||||
CHECK(flat_object.unflatten() == nlohmann::ordered_json::parse(R"({"b": {"1": 2}})"));
|
||||
}
|
||||
|
||||
SECTION("objects and arrays interleaved")
|
||||
{
|
||||
const json value =
|
||||
{
|
||||
{"a", {1, {{"b", json::array()}, {"c", json::object()}}, json::array({{{"x~/", {true, nullptr}}}})}},
|
||||
{"a/b", {{"~", 1}}},
|
||||
{"z", "s"}
|
||||
};
|
||||
|
||||
const json expected =
|
||||
{
|
||||
{"/a/0", 1},
|
||||
{"/a/1/b", nullptr},
|
||||
{"/a/1/c", nullptr},
|
||||
{"/a/2/0/x~0~1/0", true},
|
||||
{"/a/2/0/x~0~1/1", nullptr},
|
||||
{"/a~1b/~0", 1},
|
||||
{"/z", "s"}
|
||||
};
|
||||
|
||||
CHECK(value.flatten() == expected);
|
||||
}
|
||||
|
||||
SECTION("order of the entries of an ordered_json")
|
||||
{
|
||||
const auto value = nlohmann::ordered_json::parse(
|
||||
R"({"z":"s","a/b":{"~":1,"k":[]},"a":[1,{"c":{},"b":[]},[{"x~/":[true,null],"w":2}]]})");
|
||||
|
||||
const auto flat = value.flatten();
|
||||
CHECK(flat.dump() ==
|
||||
R"({"/z":"s","/a~1b/~0":1,"/a~1b/k":null,"/a/0":1,"/a/1/c":null,"/a/1/b":null,"/a/2/0/x~0~1/0":true,"/a/2/0/x~0~1/1":null,"/a/2/0/w":2})");
|
||||
}
|
||||
}
|
||||
+59
-46
@@ -31,6 +31,7 @@ using nlohmann::json;
|
||||
#include "make_test_data_available.hpp"
|
||||
#include "round_trip_corpus.hpp"
|
||||
#include "test_utils.hpp"
|
||||
#include "custom_object_key_type.hpp"
|
||||
#include "sax_countdown.hpp"
|
||||
using utils::SaxCountdown;
|
||||
|
||||
@@ -2201,10 +2202,7 @@ struct huge_array : std::vector<T, A>
|
||||
}
|
||||
};
|
||||
|
||||
using huge_array_json = nlohmann::basic_json <
|
||||
std::map, huge_array, std::string, bool, std::int64_t, std::uint64_t,
|
||||
double, std::allocator, nlohmann::adl_serializer,
|
||||
std::vector<std::uint8_t>, void >;
|
||||
using huge_array_json = nlohmann::json::with_array_t<huge_array>;
|
||||
|
||||
TEST_CASE("MessagePack Size above uint32 for array")
|
||||
{
|
||||
@@ -2249,18 +2247,7 @@ template<typename K, typename V,
|
||||
}
|
||||
};
|
||||
|
||||
using huge_object_json = nlohmann::basic_json <
|
||||
huge_map,
|
||||
std::vector,
|
||||
std::string,
|
||||
bool,
|
||||
std::int64_t,
|
||||
std::uint64_t,
|
||||
double,
|
||||
std::allocator,
|
||||
nlohmann::adl_serializer,
|
||||
std::vector<std::uint8_t>,
|
||||
void >;
|
||||
using huge_object_json = nlohmann::json::with_object_t<huge_map>;
|
||||
|
||||
TEST_CASE("MessagePack Size above uint32 for object")
|
||||
{
|
||||
@@ -2295,18 +2282,7 @@ struct msgpack_huge_string : std::string
|
||||
}
|
||||
};
|
||||
|
||||
using msgpack_huge_string_json = nlohmann::basic_json <
|
||||
std::map,
|
||||
std::vector,
|
||||
msgpack_huge_string,
|
||||
bool,
|
||||
std::int64_t,
|
||||
std::uint64_t,
|
||||
double,
|
||||
std::allocator,
|
||||
nlohmann::adl_serializer,
|
||||
std::vector<std::uint8_t>,
|
||||
void >;
|
||||
using msgpack_huge_string_json = nlohmann::json::with_string_t<msgpack_huge_string>;
|
||||
|
||||
TEST_CASE("MessagePack Size above uint32 for string")
|
||||
{
|
||||
@@ -2329,18 +2305,7 @@ struct msgpack_huge_binary : std::vector<std::uint8_t>
|
||||
}
|
||||
};
|
||||
|
||||
using msgpack_huge_binary_json = nlohmann::basic_json <
|
||||
std::map,
|
||||
std::vector,
|
||||
std::string,
|
||||
bool,
|
||||
std::int64_t,
|
||||
std::uint64_t,
|
||||
double,
|
||||
std::allocator,
|
||||
nlohmann::adl_serializer,
|
||||
msgpack_huge_binary,
|
||||
void >;
|
||||
using msgpack_huge_binary_json = nlohmann::json::with_binary_t<msgpack_huge_binary>;
|
||||
|
||||
TEST_CASE("MessagePack Size above uint32 for binary")
|
||||
{
|
||||
@@ -2390,14 +2355,10 @@ class beyond_uint32_string_t : public std::string
|
||||
}
|
||||
};
|
||||
|
||||
using beyond_uint32_string_json = nlohmann::basic_json <
|
||||
std::map, std::vector, beyond_uint32_string_t, bool, std::int64_t, std::uint64_t,
|
||||
double, std::allocator, nlohmann::adl_serializer, std::vector<std::uint8_t>, void >;
|
||||
using beyond_uint32_string_json = nlohmann::json::with_string_t<beyond_uint32_string_t>;
|
||||
#endif
|
||||
|
||||
using beyond_uint32_binary_json = nlohmann::basic_json <
|
||||
std::map, std::vector, std::string, bool, std::int64_t, std::uint64_t,
|
||||
double, std::allocator, nlohmann::adl_serializer, beyond_uint32_binary_t, void >;
|
||||
using beyond_uint32_binary_json = nlohmann::json::with_binary_t<beyond_uint32_binary_t>;
|
||||
} // namespace
|
||||
|
||||
TEST_CASE("MessagePack lengths beyond UINT32_MAX cannot be serialized")
|
||||
@@ -2522,3 +2483,55 @@ TEST_CASE("MessagePack large strings and binaries (chunked reader)")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
TEST_CASE("MessagePack supports custom object key types")
|
||||
{
|
||||
using custom_json = custom_object_key_test::json;
|
||||
using custom_key = custom_object_key_test::key;
|
||||
|
||||
custom_json::object_t object;
|
||||
object.emplace(custom_key{"short"}, 1);
|
||||
object.emplace(
|
||||
custom_key{"a key longer than thirty-one characters"},
|
||||
2);
|
||||
|
||||
const custom_json value(std::move(object));
|
||||
const auto encoded = custom_json::to_msgpack(value);
|
||||
|
||||
CHECK(nlohmann::json::from_msgpack(encoded) == nlohmann::json
|
||||
{
|
||||
{"short", 1},
|
||||
{"a key longer than thirty-one characters", 2}
|
||||
});
|
||||
}
|
||||
|
||||
TEST_CASE("MessagePack supports custom object key types nested deeper than the recursion depth limit")
|
||||
{
|
||||
// below detail::recursion_depth_limit(), keys are written by
|
||||
// write_msgpack_iterative instead of write_msgpack
|
||||
using custom_json = custom_object_key_test::json;
|
||||
using custom_key = custom_object_key_test::key;
|
||||
|
||||
const std::size_t depth = nlohmann::detail::recursion_depth_limit() + 10;
|
||||
|
||||
custom_json value = 1;
|
||||
nlohmann::json expected = 1;
|
||||
for (std::size_t i = 0; i < depth; ++i)
|
||||
{
|
||||
// alternate short keys with ones long enough to need a length byte
|
||||
const std::string name = (i % 2 == 0) ? "k" + std::to_string(i)
|
||||
: "a key longer than thirty-one characters " + std::to_string(i);
|
||||
|
||||
custom_json::object_t object;
|
||||
object.emplace(custom_key{name}, std::move(value));
|
||||
value = custom_json(std::move(object));
|
||||
|
||||
nlohmann::json::object_t expected_object;
|
||||
expected_object.emplace(name, std::move(expected));
|
||||
expected = nlohmann::json(std::move(expected_object));
|
||||
}
|
||||
|
||||
const auto encoded = custom_json::to_msgpack(value);
|
||||
CHECK(encoded == nlohmann::json::to_msgpack(expected));
|
||||
CHECK(nlohmann::json::from_msgpack(encoded) == expected);
|
||||
}
|
||||
@@ -219,16 +219,7 @@ void int_to_string(alt_string& target, std::size_t value)
|
||||
target = std::to_string(value).c_str();
|
||||
}
|
||||
|
||||
using ordered_json2_alt_json = nlohmann::basic_json <
|
||||
std::map,
|
||||
std::vector,
|
||||
alt_string,
|
||||
bool,
|
||||
std::int64_t,
|
||||
std::uint64_t,
|
||||
double,
|
||||
std::allocator,
|
||||
nlohmann::adl_serializer >;
|
||||
using ordered_json2_alt_json = nlohmann::json::with_string_t<alt_string>;
|
||||
|
||||
bool operator<(const char* op1, const alt_string& op2) noexcept
|
||||
{
|
||||
|
||||
Reference in new issue
Block a user