diff options
Diffstat (limited to 'json4cpp/tests/src/unit-comparison.cpp')
| -rw-r--r-- | json4cpp/tests/src/unit-comparison.cpp | 596 |
1 files changed, 596 insertions, 0 deletions
diff --git a/json4cpp/tests/src/unit-comparison.cpp b/json4cpp/tests/src/unit-comparison.cpp new file mode 100644 index 0000000000..befaa04042 --- /dev/null +++ b/json4cpp/tests/src/unit-comparison.cpp @@ -0,0 +1,596 @@ +// __ _____ _____ _____ +// __| | __| | | | 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 + +// cmake/test.cmake selects the C++ standard versions with which to build a +// unit test based on the presence of JSON_HAS_CPP_<VERSION> macros. +// When using macros that are only defined for particular versions of the standard +// (e.g., JSON_HAS_FILESYSTEM for C++17 and up), please mention the corresponding +// version macro in a comment close by, like this: +// JSON_HAS_CPP_<VERSION> (do not remove; see note at top of file) + +#include "doctest_compatibility.h" + +#define JSON_TESTS_PRIVATE +#include <nlohmann/json.hpp> +using nlohmann::json; + +#if JSON_HAS_THREE_WAY_COMPARISON +// this can be replaced with the doctest stl extension header in version 2.5 +namespace doctest +{ +template<> struct StringMaker<std::partial_ordering> +{ + static String convert(const std::partial_ordering& order) + { + if (order == std::partial_ordering::less) + { + return "std::partial_ordering::less"; + } + if (order == std::partial_ordering::equivalent) + { + return "std::partial_ordering::equivalent"; + } + if (order == std::partial_ordering::greater) + { + return "std::partial_ordering::greater"; + } + if (order == std::partial_ordering::unordered) + { + return "std::partial_ordering::unordered"; + } + return "{?}"; + } +}; +} // namespace doctest + +#endif + +namespace +{ +// helper function to check std::less<json::value_t> +// see https://en.cppreference.com/w/cpp/utility/functional/less +template <typename A, typename B, typename U = std::less<json::value_t>> +bool f(A a, B b, U u = U()) +{ + return u(a, b); +} +} // namespace + +TEST_CASE("lexicographical comparison operators") +{ + constexpr auto f_ = false; + constexpr auto _t = true; + constexpr auto nan = std::numeric_limits<json::number_float_t>::quiet_NaN(); +#if JSON_HAS_THREE_WAY_COMPARISON + constexpr auto lt = std::partial_ordering::less; + constexpr auto gt = std::partial_ordering::greater; + constexpr auto eq = std::partial_ordering::equivalent; + constexpr auto un = std::partial_ordering::unordered; +#endif + +#if JSON_HAS_THREE_WAY_COMPARISON + INFO("using 3-way comparison"); +#endif + +#if JSON_USE_LEGACY_DISCARDED_VALUE_COMPARISON + INFO("using legacy comparison"); +#endif + + //REQUIRE(std::numeric_limits<json::number_float_t>::has_quiet_NaN); + REQUIRE(std::isnan(nan)); + + SECTION("types") + { + std::vector<json::value_t> j_types = + { + json::value_t::null, + json::value_t::boolean, + json::value_t::number_integer, + json::value_t::number_unsigned, + json::value_t::number_float, + json::value_t::object, + json::value_t::array, + json::value_t::string, + json::value_t::binary, + json::value_t::discarded + }; + + std::vector<std::vector<bool>> expected_lt = + { + //0 1 2 3 4 5 6 7 8 9 + {f_, _t, _t, _t, _t, _t, _t, _t, _t, f_}, // 0 + {f_, f_, _t, _t, _t, _t, _t, _t, _t, f_}, // 1 + {f_, f_, f_, f_, f_, _t, _t, _t, _t, f_}, // 2 + {f_, f_, f_, f_, f_, _t, _t, _t, _t, f_}, // 3 + {f_, f_, f_, f_, f_, _t, _t, _t, _t, f_}, // 4 + {f_, f_, f_, f_, f_, f_, _t, _t, _t, f_}, // 5 + {f_, f_, f_, f_, f_, f_, f_, _t, _t, f_}, // 6 + {f_, f_, f_, f_, f_, f_, f_, f_, _t, f_}, // 7 + {f_, f_, f_, f_, f_, f_, f_, f_, f_, f_}, // 8 + {f_, f_, f_, f_, f_, f_, f_, f_, f_, f_}, // 9 + }; + + SECTION("comparison: less") + { + REQUIRE(expected_lt.size() == j_types.size()); + for (size_t i = 0; i < j_types.size(); ++i) + { + REQUIRE(expected_lt[i].size() == j_types.size()); + for (size_t j = 0; j < j_types.size(); ++j) + { + CAPTURE(i) + CAPTURE(j) + // check precomputed values +#if JSON_HAS_THREE_WAY_COMPARISON + // JSON_HAS_CPP_20 (do not remove; see note at top of file) + CHECK((j_types[i] < j_types[j]) == expected_lt[i][j]); +#else + CHECK(operator<(j_types[i], j_types[j]) == expected_lt[i][j]); +#endif + CHECK(f(j_types[i], j_types[j]) == expected_lt[i][j]); + } + } + } +#if JSON_HAS_THREE_WAY_COMPARISON + // JSON_HAS_CPP_20 (do not remove; see note at top of file) + SECTION("comparison: 3-way") + { + std::vector<std::vector<std::partial_ordering>> expected = + { + //0 1 2 3 4 5 6 7 8 9 + {eq, lt, lt, lt, lt, lt, lt, lt, lt, un}, // 0 + {gt, eq, lt, lt, lt, lt, lt, lt, lt, un}, // 1 + {gt, gt, eq, eq, eq, lt, lt, lt, lt, un}, // 2 + {gt, gt, eq, eq, eq, lt, lt, lt, lt, un}, // 3 + {gt, gt, eq, eq, eq, lt, lt, lt, lt, un}, // 4 + {gt, gt, gt, gt, gt, eq, lt, lt, lt, un}, // 5 + {gt, gt, gt, gt, gt, gt, eq, lt, lt, un}, // 6 + {gt, gt, gt, gt, gt, gt, gt, eq, lt, un}, // 7 + {gt, gt, gt, gt, gt, gt, gt, gt, eq, un}, // 8 + {un, un, un, un, un, un, un, un, un, un}, // 9 + }; + + // check expected partial_ordering against expected boolean + REQUIRE(expected.size() == expected_lt.size()); + for (size_t i = 0; i < expected.size(); ++i) + { + REQUIRE(expected[i].size() == expected_lt[i].size()); + for (size_t j = 0; j < expected[i].size(); ++j) + { + CAPTURE(i) + CAPTURE(j) + CHECK(std::is_lt(expected[i][j]) == expected_lt[i][j]); + } + } + + // check 3-way comparison against expected partial_ordering + REQUIRE(expected.size() == j_types.size()); + for (size_t i = 0; i < j_types.size(); ++i) + { + REQUIRE(expected[i].size() == j_types.size()); + for (size_t j = 0; j < j_types.size(); ++j) + { + CAPTURE(i) + CAPTURE(j) + CHECK((j_types[i] <=> j_types[j]) == expected[i][j]); // *NOPAD* + } + } + } +#endif + } + + SECTION("values") + { + json j_values = + { + nullptr, nullptr, // 0 1 + -17, 42, // 2 3 + 8u, 13u, // 4 5 + 3.14159, 23.42, // 6 7 + nan, nan, // 8 9 + "foo", "bar", // 10 11 + true, false, // 12 13 + {1, 2, 3}, {"one", "two", "three"}, // 14 15 + {{"first", 1}, {"second", 2}}, {{"a", "A"}, {"b", {"B"}}}, // 16 17 + json::binary({1, 2, 3}), json::binary({1, 2, 4}), // 18 19 + json(json::value_t::discarded), json(json::value_t::discarded) // 20 21 + }; + + std::vector<std::vector<bool>> expected_eq = + { + //0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 + {_t, _t, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_}, // 0 + {_t, _t, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_}, // 1 + {f_, f_, _t, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_}, // 2 + {f_, f_, f_, _t, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_}, // 3 + {f_, f_, f_, f_, _t, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_}, // 4 + {f_, f_, f_, f_, f_, _t, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_}, // 5 + {f_, f_, f_, f_, f_, f_, _t, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_}, // 6 + {f_, f_, f_, f_, f_, f_, f_, _t, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_}, // 7 + {f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_}, // 8 + {f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_}, // 9 + {f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, _t, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_}, // 10 + {f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, _t, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_}, // 11 + {f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, _t, f_, f_, f_, f_, f_, f_, f_, f_, f_}, // 12 + {f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, _t, f_, f_, f_, f_, f_, f_, f_, f_}, // 13 + {f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, _t, f_, f_, f_, f_, f_, f_, f_}, // 14 + {f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, _t, f_, f_, f_, f_, f_, f_}, // 15 + {f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, _t, f_, f_, f_, f_, f_}, // 16 + {f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, _t, f_, f_, f_, f_}, // 17 + {f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, _t, f_, f_, f_}, // 18 + {f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, _t, f_, f_}, // 19 + {f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_}, // 20 + {f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_}, // 21 + }; + + std::vector<std::vector<bool>> expected_lt = + { + //0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 + {f_, f_, _t, _t, _t, _t, _t, _t, _t, _t, _t, _t, _t, _t, _t, _t, _t, _t, _t, _t, f_, f_}, // 0 + {f_, f_, _t, _t, _t, _t, _t, _t, _t, _t, _t, _t, _t, _t, _t, _t, _t, _t, _t, _t, f_, f_}, // 1 + {f_, f_, f_, _t, _t, _t, _t, _t, f_, f_, _t, _t, f_, f_, _t, _t, _t, _t, _t, _t, f_, f_}, // 2 + {f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, _t, _t, f_, f_, _t, _t, _t, _t, _t, _t, f_, f_}, // 3 + {f_, f_, f_, _t, f_, _t, f_, _t, f_, f_, _t, _t, f_, f_, _t, _t, _t, _t, _t, _t, f_, f_}, // 4 + {f_, f_, f_, _t, f_, f_, f_, _t, f_, f_, _t, _t, f_, f_, _t, _t, _t, _t, _t, _t, f_, f_}, // 5 + {f_, f_, f_, _t, _t, _t, f_, _t, f_, f_, _t, _t, f_, f_, _t, _t, _t, _t, _t, _t, f_, f_}, // 6 + {f_, f_, f_, _t, f_, f_, f_, f_, f_, f_, _t, _t, f_, f_, _t, _t, _t, _t, _t, _t, f_, f_}, // 7 + {f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, _t, _t, f_, f_, _t, _t, _t, _t, _t, _t, f_, f_}, // 8 + {f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, _t, _t, f_, f_, _t, _t, _t, _t, _t, _t, f_, f_}, // 9 + {f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, _t, _t, f_, f_}, // 10 + {f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, _t, f_, f_, f_, f_, f_, f_, f_, _t, _t, f_, f_}, // 11 + {f_, f_, _t, _t, _t, _t, _t, _t, _t, _t, _t, _t, f_, f_, _t, _t, _t, _t, _t, _t, f_, f_}, // 12 + {f_, f_, _t, _t, _t, _t, _t, _t, _t, _t, _t, _t, _t, f_, _t, _t, _t, _t, _t, _t, f_, f_}, // 13 + {f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, _t, _t, f_, f_, f_, _t, f_, f_, _t, _t, f_, f_}, // 14 + {f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, _t, _t, f_, f_, f_, f_, f_, f_, _t, _t, f_, f_}, // 15 + {f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, _t, _t, f_, f_, _t, _t, f_, f_, _t, _t, f_, f_}, // 16 + {f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, _t, _t, f_, f_, _t, _t, _t, f_, _t, _t, f_, f_}, // 17 + {f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, _t, f_, f_}, // 18 + {f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_}, // 19 + {f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_}, // 20 + {f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_}, // 21 + }; + + SECTION("compares unordered") + { + std::vector<std::vector<bool>> expected = + { + //0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 + {f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, _t, _t}, // 0 + {f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, _t, _t}, // 1 + {f_, f_, f_, f_, f_, f_, f_, f_, _t, _t, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, _t, _t}, // 2 + {f_, f_, f_, f_, f_, f_, f_, f_, _t, _t, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, _t, _t}, // 3 + {f_, f_, f_, f_, f_, f_, f_, f_, _t, _t, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, _t, _t}, // 4 + {f_, f_, f_, f_, f_, f_, f_, f_, _t, _t, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, _t, _t}, // 5 + {f_, f_, f_, f_, f_, f_, f_, f_, _t, _t, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, _t, _t}, // 6 + {f_, f_, f_, f_, f_, f_, f_, f_, _t, _t, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, _t, _t}, // 7 + {f_, f_, _t, _t, _t, _t, _t, _t, _t, _t, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, _t, _t}, // 8 + {f_, f_, _t, _t, _t, _t, _t, _t, _t, _t, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, _t, _t}, // 9 + {f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, _t, _t}, // 10 + {f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, _t, _t}, // 11 + {f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, _t, _t}, // 12 + {f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, _t, _t}, // 13 + {f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, _t, _t}, // 14 + {f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, _t, _t}, // 15 + {f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, _t, _t}, // 16 + {f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, _t, _t}, // 17 + {f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, _t, _t}, // 18 + {f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, _t, _t}, // 19 + {_t, _t, _t, _t, _t, _t, _t, _t, _t, _t, _t, _t, _t, _t, _t, _t, _t, _t, _t, _t, _t, _t}, // 20 + {_t, _t, _t, _t, _t, _t, _t, _t, _t, _t, _t, _t, _t, _t, _t, _t, _t, _t, _t, _t, _t, _t}, // 21 + }; + + // check if two values compare unordered as expected + REQUIRE(expected.size() == j_values.size()); + for (size_t i = 0; i < j_values.size(); ++i) + { + REQUIRE(expected[i].size() == j_values.size()); + for (size_t j = 0; j < j_values.size(); ++j) + { + CAPTURE(i) + CAPTURE(j) + CHECK(json::compares_unordered(j_values[i], j_values[j]) == expected[i][j]); + } + } + } + +#if JSON_USE_LEGACY_DISCARDED_VALUE_COMPARISON + SECTION("compares unordered (inverse)") + { + std::vector<std::vector<bool>> expected = + { + //0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 + {f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_}, // 0 + {f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_}, // 1 + {f_, f_, f_, f_, f_, f_, f_, f_, _t, _t, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_}, // 2 + {f_, f_, f_, f_, f_, f_, f_, f_, _t, _t, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_}, // 3 + {f_, f_, f_, f_, f_, f_, f_, f_, _t, _t, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_}, // 4 + {f_, f_, f_, f_, f_, f_, f_, f_, _t, _t, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_}, // 5 + {f_, f_, f_, f_, f_, f_, f_, f_, _t, _t, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_}, // 6 + {f_, f_, f_, f_, f_, f_, f_, f_, _t, _t, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_}, // 7 + {f_, f_, _t, _t, _t, _t, _t, _t, _t, _t, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_}, // 8 + {f_, f_, _t, _t, _t, _t, _t, _t, _t, _t, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_}, // 9 + {f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_}, // 10 + {f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_}, // 11 + {f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_}, // 12 + {f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_}, // 13 + {f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_}, // 14 + {f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_}, // 15 + {f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_}, // 16 + {f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_}, // 17 + {f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_}, // 18 + {f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_}, // 19 + {f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_}, // 20 + {f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_}, // 21 + }; + + // check that two values compare unordered as expected (with legacy-mode enabled) + REQUIRE(expected.size() == j_values.size()); + for (size_t i = 0; i < j_values.size(); ++i) + { + REQUIRE(expected[i].size() == j_values.size()); + for (size_t j = 0; j < j_values.size(); ++j) + { + CAPTURE(i) + CAPTURE(j) + CAPTURE(j_values[i]) + CAPTURE(j_values[j]) + CHECK(json::compares_unordered(j_values[i], j_values[j], true) == expected[i][j]); + } + } + } +#endif + + SECTION("comparison: equal") + { + // check that two values compare equal + REQUIRE(expected_eq.size() == j_values.size()); + for (size_t i = 0; i < j_values.size(); ++i) + { + REQUIRE(expected_eq[i].size() == j_values.size()); + for (size_t j = 0; j < j_values.size(); ++j) + { + CAPTURE(i) + CAPTURE(j) + CHECK((j_values[i] == j_values[j]) == expected_eq[i][j]); + } + } + + // compare with null pointer + json j_null; + CHECK(j_null == nullptr); + CHECK(nullptr == j_null); + } + + SECTION("comparison: not equal") + { + // check that two values compare unequal as expected + for (size_t i = 0; i < j_values.size(); ++i) + { + for (size_t j = 0; j < j_values.size(); ++j) + { + CAPTURE(i) + CAPTURE(j) + + if (json::compares_unordered(j_values[i], j_values[j], true)) + { + // if two values compare unordered, + // check that the boolean comparison result is always false + CHECK_FALSE(j_values[i] != j_values[j]); + } + else + { + // otherwise, check that they compare according to their definition + // as the inverse of equal + CHECK((j_values[i] != j_values[j]) == !(j_values[i] == j_values[j])); + } + } + } + + // compare with null pointer + const json j_null; + CHECK((j_null != nullptr) == false); + CHECK((nullptr != j_null) == false); + CHECK((j_null != nullptr) == !(j_null == nullptr)); + CHECK((nullptr != j_null) == !(nullptr == j_null)); + } + + SECTION("comparison: less") + { + // check that two values compare less than as expected + REQUIRE(expected_lt.size() == j_values.size()); + for (size_t i = 0; i < j_values.size(); ++i) + { + REQUIRE(expected_lt[i].size() == j_values.size()); + for (size_t j = 0; j < j_values.size(); ++j) + { + CAPTURE(i) + CAPTURE(j) + CHECK((j_values[i] < j_values[j]) == expected_lt[i][j]); + } + } + } + + SECTION("comparison: less than or equal equal") + { + // check that two values compare less than or equal as expected + for (size_t i = 0; i < j_values.size(); ++i) + { + for (size_t j = 0; j < j_values.size(); ++j) + { + CAPTURE(i) + CAPTURE(j) + if (json::compares_unordered(j_values[i], j_values[j], true)) + { + // if two values compare unordered, + // check that the boolean comparison result is always false + CHECK_FALSE(j_values[i] <= j_values[j]); + } + else + { + // otherwise, check that they compare according to their definition + // as the inverse of less than with the operand order reversed + CHECK((j_values[i] <= j_values[j]) == !(j_values[j] < j_values[i])); + } + } + } + } + + SECTION("comparison: greater than") + { + // check that two values compare greater than as expected + for (size_t i = 0; i < j_values.size(); ++i) + { + for (size_t j = 0; j < j_values.size(); ++j) + { + CAPTURE(i) + CAPTURE(j) + if (json::compares_unordered(j_values[i], j_values[j])) + { + // if two values compare unordered, + // check that the boolean comparison result is always false + CHECK_FALSE(j_values[i] > j_values[j]); + } + else + { + // otherwise, check that they compare according to their definition + // as the inverse of less than or equal which is defined as + // the inverse of less than with the operand order reversed + CHECK((j_values[i] > j_values[j]) == !(j_values[i] <= j_values[j])); + CHECK((j_values[i] > j_values[j]) == !!(j_values[j] < j_values[i])); + } + } + } + } + + SECTION("comparison: greater than or equal") + { + // check that two values compare greater than or equal as expected + for (size_t i = 0; i < j_values.size(); ++i) + { + for (size_t j = 0; j < j_values.size(); ++j) + { + CAPTURE(i) + CAPTURE(j) + if (json::compares_unordered(j_values[i], j_values[j], true)) + { + // if two values compare unordered, + // check that the boolean result is always false + CHECK_FALSE(j_values[i] >= j_values[j]); + } + else + { + // otherwise, check that they compare according to their definition + // as the inverse of less than + CHECK((j_values[i] >= j_values[j]) == !(j_values[i] < j_values[j])); + } + } + } + } + +#if JSON_HAS_THREE_WAY_COMPARISON + // JSON_HAS_CPP_20 (do not remove; see note at top of file) + SECTION("comparison: 3-way") + { + std::vector<std::vector<std::partial_ordering>> expected = + { + //0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 + {eq, eq, lt, lt, lt, lt, lt, lt, lt, lt, lt, lt, lt, lt, lt, lt, lt, lt, lt, lt, un, un}, // 0 + {eq, eq, lt, lt, lt, lt, lt, lt, lt, lt, lt, lt, lt, lt, lt, lt, lt, lt, lt, lt, un, un}, // 1 + {gt, gt, eq, lt, lt, lt, lt, lt, un, un, lt, lt, gt, gt, lt, lt, lt, lt, lt, lt, un, un}, // 2 + {gt, gt, gt, eq, gt, gt, gt, gt, un, un, lt, lt, gt, gt, lt, lt, lt, lt, lt, lt, un, un}, // 3 + {gt, gt, gt, lt, eq, lt, gt, lt, un, un, lt, lt, gt, gt, lt, lt, lt, lt, lt, lt, un, un}, // 4 + {gt, gt, gt, lt, gt, eq, gt, lt, un, un, lt, lt, gt, gt, lt, lt, lt, lt, lt, lt, un, un}, // 5 + {gt, gt, gt, lt, lt, lt, eq, lt, un, un, lt, lt, gt, gt, lt, lt, lt, lt, lt, lt, un, un}, // 6 + {gt, gt, gt, lt, gt, gt, gt, eq, un, un, lt, lt, gt, gt, lt, lt, lt, lt, lt, lt, un, un}, // 7 + {gt, gt, un, un, un, un, un, un, un, un, lt, lt, gt, gt, lt, lt, lt, lt, lt, lt, un, un}, // 8 + {gt, gt, un, un, un, un, un, un, un, un, lt, lt, gt, gt, lt, lt, lt, lt, lt, lt, un, un}, // 9 + {gt, gt, gt, gt, gt, gt, gt, gt, gt, gt, eq, gt, gt, gt, gt, gt, gt, gt, lt, lt, un, un}, // 10 + {gt, gt, gt, gt, gt, gt, gt, gt, gt, gt, lt, eq, gt, gt, gt, gt, gt, gt, lt, lt, un, un}, // 11 + {gt, gt, lt, lt, lt, lt, lt, lt, lt, lt, lt, lt, eq, gt, lt, lt, lt, lt, lt, lt, un, un}, // 12 + {gt, gt, lt, lt, lt, lt, lt, lt, lt, lt, lt, lt, lt, eq, lt, lt, lt, lt, lt, lt, un, un}, // 13 + {gt, gt, gt, gt, gt, gt, gt, gt, gt, gt, lt, lt, gt, gt, eq, lt, gt, gt, lt, lt, un, un}, // 14 + {gt, gt, gt, gt, gt, gt, gt, gt, gt, gt, lt, lt, gt, gt, gt, eq, gt, gt, lt, lt, un, un}, // 15 + {gt, gt, gt, gt, gt, gt, gt, gt, gt, gt, lt, lt, gt, gt, lt, lt, eq, gt, lt, lt, un, un}, // 16 + {gt, gt, gt, gt, gt, gt, gt, gt, gt, gt, lt, lt, gt, gt, lt, lt, lt, eq, lt, lt, un, un}, // 17 + {gt, gt, gt, gt, gt, gt, gt, gt, gt, gt, gt, gt, gt, gt, gt, gt, gt, gt, eq, lt, un, un}, // 18 + {gt, gt, gt, gt, gt, gt, gt, gt, gt, gt, gt, gt, gt, gt, gt, gt, gt, gt, gt, eq, un, un}, // 19 + {un, un, un, un, un, un, un, un, un, un, un, un, un, un, un, un, un, un, un, un, un, un}, // 20 + {un, un, un, un, un, un, un, un, un, un, un, un, un, un, un, un, un, un, un, un, un, un}, // 21 + }; + + // check expected partial_ordering against expected booleans + REQUIRE(expected.size() == expected_eq.size()); + REQUIRE(expected.size() == expected_lt.size()); + for (size_t i = 0; i < expected.size(); ++i) + { + REQUIRE(expected[i].size() == expected_eq[i].size()); + REQUIRE(expected[i].size() == expected_lt[i].size()); + for (size_t j = 0; j < expected[i].size(); ++j) + { + CAPTURE(i) + CAPTURE(j) + CHECK(std::is_eq(expected[i][j]) == expected_eq[i][j]); + CHECK(std::is_lt(expected[i][j]) == expected_lt[i][j]); + if (std::is_gt(expected[i][j])) + { + CHECK((!expected_eq[i][j] && !expected_lt[i][j])); + } + } + } + + // check that two values compare according to their expected ordering + REQUIRE(expected.size() == j_values.size()); + for (size_t i = 0; i < j_values.size(); ++i) + { + REQUIRE(expected[i].size() == j_values.size()); + for (size_t j = 0; j < j_values.size(); ++j) + { + CAPTURE(i) + CAPTURE(j) + CHECK((j_values[i] <=> j_values[j]) == expected[i][j]); // *NOPAD* + } + } + } +#endif + } + +#if JSON_USE_LEGACY_DISCARDED_VALUE_COMPARISON + SECTION("parser callback regression") + { + SECTION("filter specific element") + { + const auto* s_object = R"( + { + "foo": 2, + "bar": { + "baz": 1 + } + } + )"; + const auto* s_array = R"( + [1,2,[3,4,5],4,5] + )"; + + const json j_object = json::parse(s_object, [](int /*unused*/, json::parse_event_t /*unused*/, const json & j) noexcept + { + // filter all number(2) elements + return j != json(2); + }); + + CHECK (j_object == json({{"bar", {{"baz", 1}}}})); + + const json j_array = json::parse(s_array, [](int /*unused*/, json::parse_event_t /*unused*/, const json & j) noexcept + { + return j != json(2); + }); + + CHECK (j_array == json({1, {3, 4, 5}, 4, 5})); + } + } +#endif +} |
