mirror of
https://github.com/nlohmann/json.git
synced 2026-10-17 11:38:14 +00:00
157 lines
5.3 KiB
C++
157 lines
5.3 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>
|
|
using nlohmann::json;
|
|
|
|
#include <cstddef>
|
|
#include <string>
|
|
#include <utility>
|
|
#include <vector>
|
|
|
|
// split from unit-large_json.cpp so that both run in parallel and stay below
|
|
// the ctest timeout under Valgrind
|
|
|
|
namespace
|
|
{
|
|
|
|
// The text of a value nested depth levels deep around the number 0. Level i is
|
|
// an array if pattern[i % pattern.size()] is '[', and otherwise an object with
|
|
// the single member "a", which every object type enumerates in the same order.
|
|
std::string nested_text(std::size_t depth, const std::string& pattern)
|
|
{
|
|
std::string text;
|
|
std::string closing;
|
|
for (std::size_t i = 0; i < depth; ++i)
|
|
{
|
|
const bool array = pattern[i % pattern.size()] == '[';
|
|
text += array ? "[" : "{\"a\":";
|
|
closing += array ? ']' : '}';
|
|
}
|
|
text += '0';
|
|
text.append(closing.rbegin(), closing.rend());
|
|
return text;
|
|
}
|
|
|
|
} // namespace
|
|
|
|
TEST_CASE("issue #5650 - stack overflow converting between specializations")
|
|
{
|
|
// deep enough to exhaust the call stack, but small enough to stay cheap:
|
|
// parsing is iterative, so building the values below costs little
|
|
const std::size_t depth = 100000;
|
|
|
|
const std::vector<std::string> patterns = {"[", "{", "[{"};
|
|
|
|
SECTION("json to ordered_json")
|
|
{
|
|
for (const auto& pattern : patterns)
|
|
{
|
|
CAPTURE(pattern)
|
|
const std::string text = nested_text(depth, pattern);
|
|
const json j = json::parse(text);
|
|
|
|
const nlohmann::ordered_json converted = j;
|
|
CHECK(converted.dump() == text);
|
|
}
|
|
}
|
|
|
|
SECTION("ordered_json to json")
|
|
{
|
|
for (const auto& pattern : patterns)
|
|
{
|
|
CAPTURE(pattern)
|
|
const std::string text = nested_text(depth, pattern);
|
|
const nlohmann::ordered_json o = nlohmann::ordered_json::parse(text);
|
|
|
|
const json converted = o;
|
|
CHECK(converted.dump() == text);
|
|
}
|
|
}
|
|
|
|
SECTION("get<ordered_json>()")
|
|
{
|
|
for (const auto& pattern : patterns)
|
|
{
|
|
CAPTURE(pattern)
|
|
const std::string text = nested_text(depth, pattern);
|
|
const json j = json::parse(text);
|
|
|
|
CHECK(j.get<nlohmann::ordered_json>().dump() == text);
|
|
}
|
|
}
|
|
|
|
SECTION("depths around the bound of the recursive descent")
|
|
{
|
|
for (std::size_t d = 1; d <= 300; ++d)
|
|
{
|
|
CAPTURE(d)
|
|
for (const auto& pattern : patterns)
|
|
{
|
|
CAPTURE(pattern)
|
|
const std::string text = nested_text(d, pattern);
|
|
const json j = json::parse(text);
|
|
|
|
const nlohmann::ordered_json converted = j;
|
|
CHECK(converted.dump() == text);
|
|
const json back = converted;
|
|
CHECK(back.dump() == text);
|
|
}
|
|
}
|
|
}
|
|
|
|
SECTION("values below the bound are converted as values above it")
|
|
{
|
|
// Bury a value below the bound, where it is converted without the
|
|
// call stack, and compare it with the same value converted on its
|
|
// own by the containers' range constructors. Its objects have
|
|
// members that the two object types enumerate in different orders.
|
|
const auto bury = [](nlohmann::ordered_json value)
|
|
{
|
|
for (std::size_t i = 0; i < 200; ++i)
|
|
{
|
|
value = nlohmann::ordered_json::array({std::move(value)});
|
|
}
|
|
return value;
|
|
};
|
|
const auto dig = [](const json & value)
|
|
{
|
|
const json* current = &value;
|
|
for (std::size_t i = 0; i < 200; ++i)
|
|
{
|
|
current = ¤t->at(0);
|
|
}
|
|
return current;
|
|
};
|
|
|
|
nlohmann::ordered_json value = nlohmann::ordered_json::object();
|
|
value["z"] = {1, -2, 3U, 4.5, true, nullptr, "six", nlohmann::ordered_json::binary({7, 8}, 9),
|
|
nlohmann::ordered_json::binary({10}), nlohmann::ordered_json::array(), nlohmann::ordered_json::object()
|
|
};
|
|
value["y"] = {{"x", {{"w", 1}, {"v", 2}}}, {"u", {3, {{"t", 4}, {"s", 5}}}}};
|
|
value["r"] = nlohmann::ordered_json::array({nlohmann::ordered_json(nlohmann::ordered_json::value_t::discarded)});
|
|
|
|
const json converted_above = value;
|
|
const json buried = bury(value);
|
|
const json& converted_below = *dig(buried);
|
|
|
|
CHECK(converted_below.dump() == converted_above.dump());
|
|
CHECK(converted_below.at("z").at(7).get_binary().subtype() == 9);
|
|
CHECK_FALSE(converted_below.at("z").at(8).get_binary().has_subtype());
|
|
CHECK(converted_below.at("r").at(0).is_discarded());
|
|
|
|
// a discarded value is never equal to anything, so compare the rest
|
|
value.erase("r");
|
|
const json without_discarded_above = value;
|
|
const json without_discarded_buried = bury(value);
|
|
CHECK(*dig(without_discarded_buried) == without_discarded_above);
|
|
}
|
|
}
|