Move the MessagePack SAX tests into unit-sax_parse.cpp

With develop's latest changes, the MinGW Debug object of unit-msgpack.cpp
has 33134 COFF sections on its own and 33411 with this PR, more than the
32767 that the MinGW linker of the "clang (20.1.8)" job can relocate. Its
sax_parse calls, all with utils::SaxCountdown, instantiate a parser and
binary reader of their own; moving those tests into unit-sax_parse.cpp
brings the object down to 32271 sections (unit-sax_parse: 20678).

The moved tests are unchanged: the "SAX aborts" sections, the user-defined
SAX consumer of #5405, the deep value read through the SAX interface (#5104),
and "MessagePack SAX parsing stops at every event".

Signed-off-by: Niels Lohmann <mail@nlohmann.me>
This commit is contained in:
Niels Lohmann committed 2026-10-09 23:35:38 +02:00
1 parent b7b75aac8a
commit 466e56d92d
3 files changed
+83 -80

No files matched your search

-75
View File
@@ -32,8 +32,6 @@ using nlohmann::json;
#include "round_trip_corpus.hpp"
#include "test_utils.hpp"
#include "custom_object_key_type.hpp"
#include "sax_countdown.hpp"
using utils::SaxCountdown;
TEST_CASE("MessagePack")
@@ -1646,30 +1644,6 @@ TEST_CASE("MessagePack")
}
}
}
SECTION("SAX aborts")
{
SECTION("start_array(len)")
{
std::vector<uint8_t> const v = {0x93, 0x01, 0x02, 0x03};
SaxCountdown scp(0);
CHECK(!json::sax_parse(v, &scp, json::input_format_t::msgpack));
}
SECTION("start_object(len)")
{
std::vector<uint8_t> const v = {0x81, 0xa3, 0x66, 0x6F, 0x6F, 0xc2};
SaxCountdown scp(0);
CHECK(!json::sax_parse(v, &scp, json::input_format_t::msgpack));
}
SECTION("key()")
{
std::vector<uint8_t> const v = {0x81, 0xa3, 0x66, 0x6F, 0x6F, 0xc2};
SaxCountdown scp(1);
CHECK(!json::sax_parse(v, &scp, json::input_format_t::msgpack));
}
}
}
TEST_CASE("issue #5405 - array reserve for definite-length MessagePack arrays")
@@ -1740,21 +1714,6 @@ TEST_CASE("issue #5405 - array reserve for definite-length MessagePack arrays")
CHECK(json::from_msgpack(packed) == j);
}
}
SECTION("a user-defined SAX consumer is unaffected by the internal DOM reserve optimization")
{
// the reserve() call is local to json_sax_dom_parser / json_sax_dom_callback_parser;
// a custom SAX consumer that does not touch a DOM array sees identical events
json j = json::array();
for (int i = 0; i < 100; ++i)
{
j.push_back(i);
}
const auto packed = json::to_msgpack(j);
SaxCountdown scp(1000000); // large enough to never trigger an abort
CHECK(json::sax_parse(packed, &scp, json::input_format_t::msgpack));
}
}
TEST_CASE("regression test - MessagePack ext type rejects a subtype that doesn't fit a single byte")
@@ -1793,15 +1752,6 @@ TEST_CASE("MessagePack nesting does not consume the call stack")
CHECK(json::from_msgpack(input, true, false).is_discarded());
}
SECTION("a well-formed deep value is read through the SAX interface")
{
std::vector<uint8_t> input(300000, 0x91);
input.push_back(0x01); // innermost value
SaxCountdown accept_all(600001);
CHECK(json::sax_parse(input, &accept_all, json::input_format_t::msgpack));
}
SECTION("a well-formed deep value is read into a value")
{
const std::size_t depth = 10000;
@@ -1849,31 +1799,6 @@ TEST_CASE("MessagePack input that cannot be read is discarded by every overload"
#endif
}
TEST_CASE("MessagePack SAX parsing stops at every event")
{
// Containers are opened and closed by the loop that reads them; a SAX
// handler that rejects any event - including the end of a nested
// container - must stop the parse right there.
const auto count_events = [](const std::vector<std::uint8_t>& input)
{
int events = 0;
while (true)
{
SaxCountdown scp(events);
if (json::sax_parse(input, &scp, json::input_format_t::msgpack))
{
return events;
}
++events;
REQUIRE(events < 1000);
}
};
// 20 events: every container kind closes inside another one
const json j = json::parse(R"({"a": [1, {"b": []}], "c": {"d": [[2]]}})");
CHECK(count_events(json::to_msgpack(j)) == 20);
}
TEST_CASE("single MessagePack roundtrip")
{
SECTION("sample.json")
+81 -3
View File
@@ -9,9 +9,9 @@
/////////////////////////////////////////////////////////////////////
// Tests that call basic_json::sax_parse have a file of their own: every
// sax_parse call instantiates the parser and binary reader that recover from
// errors (see #3989), and in unit-regression2.cpp and unit-regression3.cpp
// this made the objects too large for the MinGW linker to relocate (see
// #5511).
// errors (see #3989), and in unit-regression2.cpp, unit-regression3.cpp, and
// unit-msgpack.cpp this made the objects too large for the MinGW linker to
// relocate (see #5511).
/////////////////////////////////////////////////////////////////////
#include "doctest_compatibility.h"
@@ -36,6 +36,9 @@ using json = nlohmann::json;
#include <utility>
#include <vector>
#include "sax_countdown.hpp"
using utils::SaxCountdown;
// a narrow number_float_t, so that a double read from binary input can
// overflow it
using float_json = nlohmann::basic_json<std::map, std::vector, std::string, bool, std::int64_t, std::uint64_t, float>;
@@ -687,4 +690,79 @@ TEST_CASE("issue #5676 - SAX parsing of CBOR tags")
#endif
}
TEST_CASE("MessagePack SAX aborts")
{
SECTION("start_array(len)")
{
std::vector<uint8_t> const v = {0x93, 0x01, 0x02, 0x03};
SaxCountdown scp(0);
CHECK(!json::sax_parse(v, &scp, json::input_format_t::msgpack));
}
SECTION("start_object(len)")
{
std::vector<uint8_t> const v = {0x81, 0xa3, 0x66, 0x6F, 0x6F, 0xc2};
SaxCountdown scp(0);
CHECK(!json::sax_parse(v, &scp, json::input_format_t::msgpack));
}
SECTION("key()")
{
std::vector<uint8_t> const v = {0x81, 0xa3, 0x66, 0x6F, 0x6F, 0xc2};
SaxCountdown scp(1);
CHECK(!json::sax_parse(v, &scp, json::input_format_t::msgpack));
}
}
TEST_CASE("issue #5405 - a user-defined SAX consumer is unaffected by the internal DOM reserve optimization")
{
// the reserve() call is local to json_sax_dom_parser / json_sax_dom_callback_parser;
// a custom SAX consumer that does not touch a DOM array sees identical events
json j = json::array();
for (int i = 0; i < 100; ++i)
{
j.push_back(i);
}
const auto packed = json::to_msgpack(j);
SaxCountdown scp(1000000); // large enough to never trigger an abort
CHECK(json::sax_parse(packed, &scp, json::input_format_t::msgpack));
}
TEST_CASE("MessagePack nesting does not consume the call stack - SAX interface")
{
// see the test case of the same name in unit-msgpack.cpp (#5104)
std::vector<uint8_t> input(300000, 0x91);
input.push_back(0x01); // innermost value
SaxCountdown accept_all(600001);
CHECK(json::sax_parse(input, &accept_all, json::input_format_t::msgpack));
}
TEST_CASE("MessagePack SAX parsing stops at every event")
{
// Containers are opened and closed by the loop that reads them; a SAX
// handler that rejects any event - including the end of a nested
// container - must stop the parse right there.
const auto count_events = [](const std::vector<std::uint8_t>& input)
{
int events = 0;
while (true)
{
SaxCountdown scp(events);
if (json::sax_parse(input, &scp, json::input_format_t::msgpack))
{
return events;
}
++events;
REQUIRE(events < 1000);
}
};
// 20 events: every container kind closes inside another one
const json j = json::parse(R"({"a": [1, {"b": []}], "c": {"d": [[2]]}})");
CHECK(count_events(json::to_msgpack(j)) == 20);
}
DOCTEST_CLANG_SUPPRESS_WARNING_POP