From ffb14ca07dda71a4a67856095412a7559ef15600 Mon Sep 17 00:00:00 2001 From: Niels Lohmann Date: Wed, 30 Sep 2026 18:17:52 +0200 Subject: [PATCH] Turn the #972 fifo_map regression test into a real test The #972 regression test in unit-regression1.cpp only built a my_json array from a string literal (the original crash) and had no CHECK, so the fifo_map object type it exists to demonstrate was never exercised. Meanwhile the docs recommend fifo_map for keeping object keys in insertion order (object_order.md, template_parameters.md), and nothing tested that recommendation. Extend the section: after the original array assignment, parse an object with my_json::parse() (not via the "..."_json UDL, which returns a plain nlohmann::json and would exercise the cross-basic_json conversion constructor instead of the parser's own key insertion - and, as tried locally, does not keep fifo order for this stateful comparator) and check that dump() keeps insertion order, and that it survives erase() and inserting a new key. Also narrow thirdparty/fifo_map off the include path of every other test-* target: it was a PUBLIC include directory of test_main, even though unit-regression1.cpp is its only user. Add a small fifo_map_include INTERFACE library with that include directory and attach it to test-regression1 only via json_test_set_test_options(). Verified locally (test-regression1_cpp11, default build and -fsanitize=address,undefined): the new checks pass; `git grep fifo_map tests` still only finds unit-regression1.cpp and the vendored header. Closes #5714 item 7. Signed-off-by: Niels Lohmann --- tests/CMakeLists.txt | 10 +++++++++- tests/src/unit-regression1.cpp | 16 ++++++++++++++++ 2 files changed, 25 insertions(+), 1 deletion(-) diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index 40a97d3b0..430d80eff 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -94,10 +94,15 @@ target_compile_options(test_main PUBLIC $<$:-diag-disable=1786>) target_include_directories(test_main PUBLIC thirdparty/doctest - thirdparty/fifo_map ${PROJECT_BINARY_DIR}/include) target_link_libraries(test_main PUBLIC ${NLOHMANN_JSON_TARGET_NAME}) +# thirdparty/fifo_map is only used by the #972 regression test, so only +# test-regression1 needs it on its include path (see json_test_set_test_options +# below), rather than every test-* target via test_main. +add_library(fifo_map_include INTERFACE) +target_include_directories(fifo_map_include INTERFACE thirdparty/fifo_map) + ############################################################################# # define test- and standard-specific build settings ############################################################################# @@ -131,6 +136,9 @@ json_test_set_test_options(test-disabled_exceptions # raise timeout of expensive Unicode test json_test_set_test_options(test-unicode4 TEST_PROPERTIES TIMEOUT 3000) +# only the #972 regression test needs thirdparty/fifo_map on its include path +json_test_set_test_options(test-regression1 LINK_LIBRARIES fifo_map_include) + ############################################################################# # add unit tests ############################################################################# diff --git a/tests/src/unit-regression1.cpp b/tests/src/unit-regression1.cpp index 43cd18438..8f0d4c747 100644 --- a/tests/src/unit-regression1.cpp +++ b/tests/src/unit-regression1.cpp @@ -1482,7 +1482,23 @@ TEST_CASE("regression tests 1") SECTION("issue #972 - Segmentation fault on G++ when trying to assign json string literal to custom json type") { + // this assignment used to crash outright my_json const foo = R"([1, 2, 3])"_json; + + // fifo_map is the adapter the docs recommend for keeping object keys + // in insertion order (see docs/mkdocs/docs/features/object_order.md + // and docs/mkdocs/docs/features/types/template_parameters.md); check + // that recommendation actually holds, including through erase() and + // inserting a new key. The comparator is stateful, so this avoids + // deep copies of "order" (see #1763, #5649). + my_json order = my_json::parse(R"({"z":1,"a":2,"m":{"y":1,"b":2}})"); + CHECK(order.dump() == R"({"z":1,"a":2,"m":{"y":1,"b":2}})"); + + order.erase("z"); + CHECK(order.dump() == R"({"a":2,"m":{"y":1,"b":2}})"); + + order["new_key"] = 3; + CHECK(order.dump() == R"({"a":2,"m":{"y":1,"b":2},"new_key":3})"); } SECTION("issue #977 - Assigning between different json types")