diff --git a/.github/workflows/windows.yml b/.github/workflows/windows.yml index 855d8af95..c5220e66c 100644 --- a/.github/workflows/windows.yml +++ b/.github/workflows/windows.yml @@ -166,6 +166,13 @@ jobs: # link, but the binaries clang 11.0.1 and clang 18.1.8 then produce crash # before doctest prints its first line - 39 of 102 tests on clang 18. # Keep the objects small by splitting the test files instead. + # Objects with more than 65535 sections fail to link with "relocation + # truncated to fit: IMAGE_REL_AMD64_REL32 against `.rdata'": the MinGW + # linker stores the section an associative COMDAT section belongs to in + # 16 bits (x_associated in binutils' include/coff/internal.h), so it + # discards the jump tables of inline functions together with the wrong + # function. Each basic_json specialization a test file instantiates adds + # many sections, so test a second one in a file of its own. - name: Run CMake run: cmake -S . -B build ^ -DCMAKE_CXX_COMPILER="C:/Program Files/LLVM/bin/clang++.exe" ^ diff --git a/tests/src/unit-cbor.cpp b/tests/src/unit-cbor.cpp index 9b57d0664..9ee371495 100644 --- a/tests/src/unit-cbor.cpp +++ b/tests/src/unit-cbor.cpp @@ -28,7 +28,6 @@ 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; @@ -3358,55 +3357,3 @@ 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); -} diff --git a/tests/src/unit-custom-object-key-type.cpp b/tests/src/unit-custom-object-key-type.cpp new file mode 100644 index 000000000..9c64ebce0 --- /dev/null +++ b/tests/src/unit-custom-object-key-type.cpp @@ -0,0 +1,127 @@ +// __ _____ _____ _____ +// __| | __| | | | JSON for Modern C++ (supporting code) +// | | |__ | | | | | | version 3.12.0 +// |_____|_____|_____|_|___| https://github.com/nlohmann/json +// +// SPDX-FileCopyrightText: 2013-2026 Niels Lohmann +// SPDX-License-Identifier: MIT + +#include "doctest_compatibility.h" + +#include + +#include +#include +#include + +#include "custom_object_key_type.hpp" + +// These tests instantiate a second basic_json specialization. They live in +// their own file rather than in unit-cbor.cpp and unit-msgpack.cpp to keep +// those objects below 65535 sections: the MinGW linker stores the section a +// COMDAT section is associated with in 16 bits, so it misplaces the jump +// tables of larger objects (see the clang job in windows.yml). + +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); +} + +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); +} diff --git a/tests/src/unit-msgpack.cpp b/tests/src/unit-msgpack.cpp index 5a1c2d4b3..39e88838a 100644 --- a/tests/src/unit-msgpack.cpp +++ b/tests/src/unit-msgpack.cpp @@ -31,7 +31,6 @@ 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; @@ -2483,55 +2482,3 @@ 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); -}