mirror of
https://github.com/nlohmann/json.git
synced 2026-10-17 19:48:12 +00:00
Split the slowest Valgrind tests out of unit-large_json and unit-bjdata (#5862)
Signed-off-by: Niels Lohmann <mail@nlohmann.me>
This commit is contained in:
1 parent
cd6b428ef0
commit
0e95fe8200
8 files changed
+598
-467
No files matched your search
@@ -0,0 +1,156 @@
|
||||
// __ _____ _____ _____
|
||||
// __| | __| | | | 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);
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user