diff --git a/tests/src/sax_countdown.hpp b/tests/src/sax_countdown.hpp new file mode 100644 index 000000000..a4e80c90c --- /dev/null +++ b/tests/src/sax_countdown.hpp @@ -0,0 +1,99 @@ +// __ _____ _____ _____ +// __| | __| | | | 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 + +#pragma once + +#include +#include +#include +#include + +#include + +namespace utils +{ +/// a SAX event consumer that stops accepting events after a fixed count, +/// used by the binary-format tests to check behavior when the SAX consumer +/// rejects an event partway through parsing +class SaxCountdown +{ + public: + using json = nlohmann::json; + + explicit SaxCountdown(const int count) : events_left(count) + {} + + bool null() + { + return events_left-- > 0; + } + + bool boolean(bool /*unused*/) + { + return events_left-- > 0; + } + + bool number_integer(json::number_integer_t /*unused*/) + { + return events_left-- > 0; + } + + bool number_unsigned(json::number_unsigned_t /*unused*/) + { + return events_left-- > 0; + } + + bool number_float(json::number_float_t /*unused*/, const std::string& /*unused*/) + { + return events_left-- > 0; + } + + bool string(std::string& /*unused*/) + { + return events_left-- > 0; + } + + bool binary(std::vector& /*unused*/) + { + return events_left-- > 0; + } + + bool start_object(std::size_t /*unused*/) + { + return events_left-- > 0; + } + + bool key(std::string& /*unused*/) + { + return events_left-- > 0; + } + + bool end_object() + { + return events_left-- > 0; + } + + bool start_array(std::size_t /*unused*/) + { + return events_left-- > 0; + } + + bool end_array() + { + return events_left-- > 0; + } + + bool parse_error(std::size_t /*unused*/, const std::string& /*unused*/, const json::exception& /*unused*/) // NOLINT(readability-convert-member-functions-to-static) + { + return false; + } + + private: + int events_left = 0; +}; +} // namespace utils diff --git a/tests/src/unit-32bit.cpp b/tests/src/unit-32bit.cpp index aead04205..97549c999 100644 --- a/tests/src/unit-32bit.cpp +++ b/tests/src/unit-32bit.cpp @@ -12,80 +12,11 @@ using nlohmann::json; #include // SIZE_MAX -#include // numeric_limits -template -struct trait_test_arg -{ - using of_type = OfType; - using type = T; - static constexpr bool min_in_range = MinInRange; - static constexpr bool max_in_range = MaxInRange; -}; - -TEST_CASE_TEMPLATE_DEFINE("value_in_range_of trait", T, value_in_range_of_test) // NOLINT(readability-math-missing-parentheses) -{ - using nlohmann::detail::value_in_range_of; - - using of_type = typename T::of_type; - using type = typename T::type; - constexpr bool min_in_range = T::min_in_range; - constexpr bool max_in_range = T::max_in_range; - - type const val_min = std::numeric_limits::min(); - type const val_min2 = val_min + 1; - type const val_max = std::numeric_limits::max(); - type const val_max2 = val_max - 1; - - REQUIRE(CHAR_BIT == 8); - - std::string of_type_str; - if (std::is_unsigned::value) - { - of_type_str += "u"; - } - of_type_str += "int"; - of_type_str += std::to_string(sizeof(of_type) * 8); - - INFO("of_type := ", of_type_str); - - std::string type_str; - if (std::is_unsigned::value) - { - type_str += "u"; - } - type_str += "int"; - type_str += std::to_string(sizeof(type) * 8); - - INFO("type := ", type_str); - - CAPTURE(val_min); - CAPTURE(min_in_range); - CAPTURE(val_max); - CAPTURE(max_in_range); - - if (min_in_range) - { - CHECK(value_in_range_of(val_min)); - CHECK(value_in_range_of(val_min2)); - } - else - { - CHECK_FALSE(value_in_range_of(val_min)); - CHECK_FALSE(value_in_range_of(val_min2)); - } - - if (max_in_range) - { - CHECK(value_in_range_of(val_max)); - CHECK(value_in_range_of(val_max2)); - } - else - { - CHECK_FALSE(value_in_range_of(val_max)); - CHECK_FALSE(value_in_range_of(val_max2)); - } -} +// JSON_32bitTest=ONLY builds only this file, so it must keep its own +// include of the shared trait/TEST_CASE_TEMPLATE_DEFINE rather than relying +// on unit-bjdata.cpp to provide it +#include "value_in_range_of_test.hpp" TEST_CASE("32bit") { diff --git a/tests/src/unit-bjdata.cpp b/tests/src/unit-bjdata.cpp index a58507c15..f6e646c50 100644 --- a/tests/src/unit-bjdata.cpp +++ b/tests/src/unit-bjdata.cpp @@ -21,158 +21,13 @@ using nlohmann::json; #include "make_test_data_available.hpp" #include "round_trip_corpus.hpp" #include "test_utils.hpp" +#include "sax_countdown.hpp" +using utils::SaxCountdown; -namespace -{ -class SaxCountdown -{ - public: - explicit SaxCountdown(const int count) : events_left(count) - {} - bool null() - { - return events_left-- > 0; - } - - bool boolean(bool /*unused*/) - { - return events_left-- > 0; - } - - bool number_integer(json::number_integer_t /*unused*/) - { - return events_left-- > 0; - } - - bool number_unsigned(json::number_unsigned_t /*unused*/) - { - return events_left-- > 0; - } - - bool number_float(json::number_float_t /*unused*/, const std::string& /*unused*/) - { - return events_left-- > 0; - } - - bool string(std::string& /*unused*/) - { - return events_left-- > 0; - } - - bool binary(std::vector& /*unused*/) - { - return events_left-- > 0; - } - - bool start_object(std::size_t /*unused*/) - { - return events_left-- > 0; - } - - bool key(std::string& /*unused*/) - { - return events_left-- > 0; - } - - bool end_object() - { - return events_left-- > 0; - } - - bool start_array(std::size_t /*unused*/) - { - return events_left-- > 0; - } - - bool end_array() - { - return events_left-- > 0; - } - - bool parse_error(std::size_t /*unused*/, const std::string& /*unused*/, const json::exception& /*unused*/) // NOLINT(readability-convert-member-functions-to-static) - { - return false; - } - - private: - int events_left = 0; -}; -} // namespace - -// at some point in the future, a unit test dedicated to type traits might be a good idea -template -struct trait_test_arg -{ - using of_type = OfType; - using type = T; - static constexpr bool min_in_range = MinInRange; - static constexpr bool max_in_range = MaxInRange; -}; - -TEST_CASE_TEMPLATE_DEFINE("value_in_range_of trait", T, value_in_range_of_test) // NOLINT(readability-math-missing-parentheses) -{ - using nlohmann::detail::value_in_range_of; - - using of_type = typename T::of_type; - using type = typename T::type; - constexpr bool min_in_range = T::min_in_range; - constexpr bool max_in_range = T::max_in_range; - - type const val_min = std::numeric_limits::min(); - type const val_min2 = val_min + 1; - type const val_max = std::numeric_limits::max(); - type const val_max2 = val_max - 1; - - REQUIRE(CHAR_BIT == 8); - - std::string of_type_str; - if (std::is_unsigned::value) - { - of_type_str += "u"; - } - of_type_str += "int"; - of_type_str += std::to_string(sizeof(of_type) * 8); - - INFO("of_type := ", of_type_str); - - std::string type_str; - if (std::is_unsigned::value) - { - type_str += "u"; - } - type_str += "int"; - type_str += std::to_string(sizeof(type) * 8); - - INFO("type := ", type_str); - - CAPTURE(val_min); - CAPTURE(min_in_range); - CAPTURE(val_max); - CAPTURE(max_in_range); - - if (min_in_range) - { - CHECK(value_in_range_of(val_min)); - CHECK(value_in_range_of(val_min2)); - } - else - { - CHECK_FALSE(value_in_range_of(val_min)); - CHECK_FALSE(value_in_range_of(val_min2)); - } - - if (max_in_range) - { - CHECK(value_in_range_of(val_max)); - CHECK(value_in_range_of(val_max2)); - } - else - { - CHECK_FALSE(value_in_range_of(val_max)); - CHECK_FALSE(value_in_range_of(val_max2)); - } -} +// trait_test_arg and the "value_in_range_of trait" TEST_CASE_TEMPLATE_DEFINE +// are shared with unit-32bit.cpp +#include "value_in_range_of_test.hpp" // NOLINTNEXTLINE(bugprone-throwing-static-initialization) TEST_CASE_TEMPLATE_INVOKE(value_in_range_of_test, \ diff --git a/tests/src/unit-bon8.cpp b/tests/src/unit-bon8.cpp index 030e1d5c3..c2aeb3db8 100644 --- a/tests/src/unit-bon8.cpp +++ b/tests/src/unit-bon8.cpp @@ -22,84 +22,11 @@ using nlohmann::json; #include #include "make_test_data_available.hpp" #include "test_utils.hpp" +#include "sax_countdown.hpp" +using utils::SaxCountdown; namespace { -class SaxCountdown -{ - public: - explicit SaxCountdown(const int count) : events_left(count) - {} - - bool null() - { - return events_left-- > 0; - } - - bool boolean(bool /*unused*/) - { - return events_left-- > 0; - } - - bool number_integer(json::number_integer_t /*unused*/) - { - return events_left-- > 0; - } - - bool number_unsigned(json::number_unsigned_t /*unused*/) - { - return events_left-- > 0; - } - - bool number_float(json::number_float_t /*unused*/, const std::string& /*unused*/) - { - return events_left-- > 0; - } - - bool string(std::string& /*unused*/) - { - return events_left-- > 0; - } - - bool binary(std::vector& /*unused*/) - { - return events_left-- > 0; - } - - bool start_object(std::size_t /*unused*/) - { - return events_left-- > 0; - } - - bool key(std::string& /*unused*/) - { - return events_left-- > 0; - } - - bool end_object() - { - return events_left-- > 0; - } - - bool start_array(std::size_t /*unused*/) - { - return events_left-- > 0; - } - - bool end_array() - { - return events_left-- > 0; - } - - bool parse_error(std::size_t /*unused*/, const std::string& /*unused*/, const json::exception& /*unused*/) // NOLINT(readability-convert-member-functions-to-static) - { - return false; - } - - private: - int events_left = 0; -}; - using bytes = std::vector; /// @return the string with the given bytes diff --git a/tests/src/unit-bson.cpp b/tests/src/unit-bson.cpp index 292ff4dc1..7652a21b3 100644 --- a/tests/src/unit-bson.cpp +++ b/tests/src/unit-bson.cpp @@ -18,6 +18,8 @@ using nlohmann::json; #include #include "make_test_data_available.hpp" #include "test_utils.hpp" +#include "sax_countdown.hpp" +using utils::SaxCountdown; namespace { @@ -857,83 +859,6 @@ TEST_CASE("BSON input/output_adapters") } } -namespace -{ -class SaxCountdown -{ - public: - explicit SaxCountdown(const int count) : events_left(count) - {} - - bool null() - { - return events_left-- > 0; - } - - bool boolean(bool /*unused*/) - { - return events_left-- > 0; - } - - bool number_integer(json::number_integer_t /*unused*/) - { - return events_left-- > 0; - } - - bool number_unsigned(json::number_unsigned_t /*unused*/) - { - return events_left-- > 0; - } - - bool number_float(json::number_float_t /*unused*/, const std::string& /*unused*/) - { - return events_left-- > 0; - } - - bool string(std::string& /*unused*/) - { - return events_left-- > 0; - } - - bool binary(std::vector& /*unused*/) - { - return events_left-- > 0; - } - - bool start_object(std::size_t /*unused*/) - { - return events_left-- > 0; - } - - bool key(std::string& /*unused*/) - { - return events_left-- > 0; - } - - bool end_object() - { - return events_left-- > 0; - } - - bool start_array(std::size_t /*unused*/) - { - return events_left-- > 0; - } - - bool end_array() - { - return events_left-- > 0; - } - - bool parse_error(std::size_t /*unused*/, const std::string& /*unused*/, const json::exception& /*unused*/) // NOLINT(readability-convert-member-functions-to-static) - { - return false; - } - - private: - int events_left = 0; -}; -} // namespace TEST_CASE("Incomplete BSON Input") { diff --git a/tests/src/unit-cbor.cpp b/tests/src/unit-cbor.cpp index bdd9a98f1..e76e28b5c 100644 --- a/tests/src/unit-cbor.cpp +++ b/tests/src/unit-cbor.cpp @@ -19,84 +19,9 @@ using nlohmann::json; #include #include "make_test_data_available.hpp" #include "test_utils.hpp" +#include "sax_countdown.hpp" +using utils::SaxCountdown; -namespace -{ -class SaxCountdown -{ - public: - explicit SaxCountdown(const int count) : events_left(count) - {} - - bool null() - { - return events_left-- > 0; - } - - bool boolean(bool /*unused*/) - { - return events_left-- > 0; - } - - bool number_integer(json::number_integer_t /*unused*/) - { - return events_left-- > 0; - } - - bool number_unsigned(json::number_unsigned_t /*unused*/) - { - return events_left-- > 0; - } - - bool number_float(json::number_float_t /*unused*/, const std::string& /*unused*/) - { - return events_left-- > 0; - } - - bool string(std::string& /*unused*/) - { - return events_left-- > 0; - } - - bool binary(std::vector& /*unused*/) - { - return events_left-- > 0; - } - - bool start_object(std::size_t /*unused*/) - { - return events_left-- > 0; - } - - bool key(std::string& /*unused*/) - { - return events_left-- > 0; - } - - bool end_object() - { - return events_left-- > 0; - } - - bool start_array(std::size_t /*unused*/) - { - return events_left-- > 0; - } - - bool end_array() - { - return events_left-- > 0; - } - - bool parse_error(std::size_t /*unused*/, const std::string& /*unused*/, const json::exception& /*unused*/) // NOLINT(readability-convert-member-functions-to-static) - { - return false; - } - - private: - int events_left = 0; -}; -} // namespace TEST_CASE("CBOR") { diff --git a/tests/src/unit-msgpack.cpp b/tests/src/unit-msgpack.cpp index 498dec859..ae7b458a9 100644 --- a/tests/src/unit-msgpack.cpp +++ b/tests/src/unit-msgpack.cpp @@ -22,84 +22,9 @@ using nlohmann::json; #include #include "make_test_data_available.hpp" #include "test_utils.hpp" +#include "sax_countdown.hpp" +using utils::SaxCountdown; -namespace -{ -class SaxCountdown -{ - public: - explicit SaxCountdown(const int count) : events_left(count) - {} - - bool null() - { - return events_left-- > 0; - } - - bool boolean(bool /*unused*/) - { - return events_left-- > 0; - } - - bool number_integer(json::number_integer_t /*unused*/) - { - return events_left-- > 0; - } - - bool number_unsigned(json::number_unsigned_t /*unused*/) - { - return events_left-- > 0; - } - - bool number_float(json::number_float_t /*unused*/, const std::string& /*unused*/) - { - return events_left-- > 0; - } - - bool string(std::string& /*unused*/) - { - return events_left-- > 0; - } - - bool binary(std::vector& /*unused*/) - { - return events_left-- > 0; - } - - bool start_object(std::size_t /*unused*/) - { - return events_left-- > 0; - } - - bool key(std::string& /*unused*/) - { - return events_left-- > 0; - } - - bool end_object() - { - return events_left-- > 0; - } - - bool start_array(std::size_t /*unused*/) - { - return events_left-- > 0; - } - - bool end_array() - { - return events_left-- > 0; - } - - bool parse_error(std::size_t /*unused*/, const std::string& /*unused*/, const json::exception& /*unused*/) // NOLINT(readability-convert-member-functions-to-static) - { - return false; - } - - private: - int events_left = 0; -}; -} // namespace TEST_CASE("MessagePack") { diff --git a/tests/src/unit-regression2.cpp b/tests/src/unit-regression2.cpp index c466958bf..ff870123f 100644 --- a/tests/src/unit-regression2.cpp +++ b/tests/src/unit-regression2.cpp @@ -199,28 +199,6 @@ struct adl_serializer }; } // namespace nlohmann -///////////////////////////////////////////////////////////////////// -// for #2824 -///////////////////////////////////////////////////////////////////// - -class sax_no_exception : public nlohmann::detail::json_sax_dom_parser -{ - public: - explicit sax_no_exception(json& j) - : nlohmann::detail::json_sax_dom_parser(j, false) - {} - - static bool parse_error(std::size_t /*position*/, const std::string& /*last_token*/, const json::exception& ex) - { - error_string = new std::string(ex.what()); // NOLINT(cppcoreguidelines-owning-memory) - return false; - } - - static std::string* error_string; -}; - -std::string* sax_no_exception::error_string = nullptr; - ///////////////////////////////////////////////////////////////////// // for #2982 ///////////////////////////////////////////////////////////////////// @@ -723,16 +701,6 @@ TEST_CASE("regression tests 2") } } - SECTION("issue #2824 - encoding of json::exception::what()") - { - json j; - sax_no_exception sax(j); - - CHECK(!json::sax_parse("xyz", &sax)); - CHECK(*sax_no_exception::error_string == "[json.exception.parse_error.101] parse error at line 1, column 1: syntax error while parsing value - invalid literal; last read: 'x'"); - delete sax_no_exception::error_string; // NOLINT(cppcoreguidelines-owning-memory) - } - SECTION("issue #2825 - Properly constrain the basic_json conversion operator") { static_assert(std::is_copy_assignable::value, "ordered_json must be copy assignable"); diff --git a/tests/src/unit-ubjson.cpp b/tests/src/unit-ubjson.cpp index c315fac94..87ff78d36 100644 --- a/tests/src/unit-ubjson.cpp +++ b/tests/src/unit-ubjson.cpp @@ -17,84 +17,9 @@ using nlohmann::json; #include "make_test_data_available.hpp" #include "round_trip_corpus.hpp" #include "test_utils.hpp" +#include "sax_countdown.hpp" +using utils::SaxCountdown; -namespace -{ -class SaxCountdown -{ - public: - explicit SaxCountdown(const int count) : events_left(count) - {} - - bool null() - { - return events_left-- > 0; - } - - bool boolean(bool /*unused*/) - { - return events_left-- > 0; - } - - bool number_integer(json::number_integer_t /*unused*/) - { - return events_left-- > 0; - } - - bool number_unsigned(json::number_unsigned_t /*unused*/) - { - return events_left-- > 0; - } - - bool number_float(json::number_float_t /*unused*/, const std::string& /*unused*/) - { - return events_left-- > 0; - } - - bool string(std::string& /*unused*/) - { - return events_left-- > 0; - } - - bool binary(std::vector& /*unused*/) - { - return events_left-- > 0; - } - - bool start_object(std::size_t /*unused*/) - { - return events_left-- > 0; - } - - bool key(std::string& /*unused*/) - { - return events_left-- > 0; - } - - bool end_object() - { - return events_left-- > 0; - } - - bool start_array(std::size_t /*unused*/) - { - return events_left-- > 0; - } - - bool end_array() - { - return events_left-- > 0; - } - - bool parse_error(std::size_t /*unused*/, const std::string& /*unused*/, const json::exception& /*unused*/) // NOLINT(readability-convert-member-functions-to-static) - { - return false; - } - - private: - int events_left = 0; -}; -} // namespace TEST_CASE("UBJSON") { diff --git a/tests/src/value_in_range_of_test.hpp b/tests/src/value_in_range_of_test.hpp new file mode 100644 index 000000000..067aef41b --- /dev/null +++ b/tests/src/value_in_range_of_test.hpp @@ -0,0 +1,92 @@ +// __ _____ _____ _____ +// __| | __| | | | 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 + +#pragma once + +// shared between unit-32bit.cpp (which must keep including this header, +// because JSON_32bitTest=ONLY builds only that file) and unit-bjdata.cpp + +#include // CHAR_BIT +#include +#include +#include + +#include + +template +struct trait_test_arg +{ + using of_type = OfType; + using type = T; + static constexpr bool min_in_range = MinInRange; + static constexpr bool max_in_range = MaxInRange; +}; + +TEST_CASE_TEMPLATE_DEFINE("value_in_range_of trait", T, value_in_range_of_test) // NOLINT(readability-math-missing-parentheses) +{ + using nlohmann::detail::value_in_range_of; + + using of_type = typename T::of_type; + using type = typename T::type; + constexpr bool min_in_range = T::min_in_range; + constexpr bool max_in_range = T::max_in_range; + + type const val_min = std::numeric_limits::min(); + type const val_min2 = val_min + 1; + type const val_max = std::numeric_limits::max(); + type const val_max2 = val_max - 1; + + REQUIRE(CHAR_BIT == 8); + + std::string of_type_str; + if (std::is_unsigned::value) + { + of_type_str += "u"; + } + of_type_str += "int"; + of_type_str += std::to_string(sizeof(of_type) * 8); + + INFO("of_type := ", of_type_str); + + std::string type_str; + if (std::is_unsigned::value) + { + type_str += "u"; + } + type_str += "int"; + type_str += std::to_string(sizeof(type) * 8); + + INFO("type := ", type_str); + + CAPTURE(val_min); + CAPTURE(min_in_range); + CAPTURE(val_max); + CAPTURE(max_in_range); + + if (min_in_range) + { + CHECK(value_in_range_of(val_min)); + CHECK(value_in_range_of(val_min2)); + } + else + { + CHECK_FALSE(value_in_range_of(val_min)); + CHECK_FALSE(value_in_range_of(val_min2)); + } + + if (max_in_range) + { + CHECK(value_in_range_of(val_max)); + CHECK(value_in_range_of(val_max2)); + } + else + { + CHECK_FALSE(value_in_range_of(val_max)); + CHECK_FALSE(value_in_range_of(val_max2)); + } +}