1 // __ _____ _____ _____
2 // __| | __| | | | JSON for Modern C++ (supporting code)
3 // | | |__ | | | | | | version 3.11.3
4 // |_____|_____|_____|_|___| https://github.com/nlohmann/json
5 //
6 // SPDX-FileCopyrightText: 2013-2023 Niels Lohmann <https://nlohmann.me>
7 // SPDX-License-Identifier: MIT
8
9 // cmake/test.cmake selects the C++ standard versions with which to build a
10 // unit test based on the presence of JSON_HAS_CPP_<VERSION> macros.
11 // When using macros that are only defined for particular versions of the standard
12 // (e.g., JSON_HAS_FILESYSTEM for C++17 and up), please mention the corresponding
13 // version macro in a comment close by, like this:
14 // JSON_HAS_CPP_<VERSION> (do not remove; see note at top of file)
15
16 #include "doctest_compatibility.h"
17
18 #define JSON_TESTS_PRIVATE
19 #include <nlohmann/json.hpp>
20 using nlohmann::json;
21
22 #if JSON_HAS_THREE_WAY_COMPARISON
23 // this can be replaced with the doctest stl extension header in version 2.5
24 namespace doctest
25 {
26 template<> struct StringMaker<std::partial_ordering>
27 {
convertdoctest::StringMaker28 static String convert(const std::partial_ordering& order)
29 {
30 if (order == std::partial_ordering::less)
31 {
32 return "std::partial_ordering::less";
33 }
34 if (order == std::partial_ordering::equivalent)
35 {
36 return "std::partial_ordering::equivalent";
37 }
38 if (order == std::partial_ordering::greater)
39 {
40 return "std::partial_ordering::greater";
41 }
42 if (order == std::partial_ordering::unordered)
43 {
44 return "std::partial_ordering::unordered";
45 }
46 return "{?}";
47 }
48 };
49 } // namespace doctest
50
51 #endif
52
53 namespace
54 {
55 // helper function to check std::less<json::value_t>
56 // see https://en.cppreference.com/w/cpp/utility/functional/less
57 template <typename A, typename B, typename U = std::less<json::value_t>>
f(A a,B b,U u=U ())58 bool f(A a, B b, U u = U())
59 {
60 return u(a, b);
61 }
62 } // namespace
63
64 TEST_CASE("lexicographical comparison operators")
65 {
66 constexpr auto f_ = false;
67 constexpr auto _t = true;
68 constexpr auto nan = std::numeric_limits<json::number_float_t>::quiet_NaN();
69 #if JSON_HAS_THREE_WAY_COMPARISON
70 constexpr auto lt = std::partial_ordering::less;
71 constexpr auto gt = std::partial_ordering::greater;
72 constexpr auto eq = std::partial_ordering::equivalent;
73 constexpr auto un = std::partial_ordering::unordered;
74 #endif
75
76 #if JSON_HAS_THREE_WAY_COMPARISON
77 INFO("using 3-way comparison");
78 #endif
79
80 #if JSON_USE_LEGACY_DISCARDED_VALUE_COMPARISON
81 INFO("using legacy comparison");
82 #endif
83
84 //REQUIRE(std::numeric_limits<json::number_float_t>::has_quiet_NaN);
85 REQUIRE(std::isnan(nan));
86
87 SECTION("types")
88 {
89 std::vector<json::value_t> j_types =
90 {
91 json::value_t::null,
92 json::value_t::boolean,
93 json::value_t::number_integer,
94 json::value_t::number_unsigned,
95 json::value_t::number_float,
96 json::value_t::object,
97 json::value_t::array,
98 json::value_t::string,
99 json::value_t::binary,
100 json::value_t::discarded
101 };
102
103 std::vector<std::vector<bool>> expected_lt =
104 {
105 //0 1 2 3 4 5 6 7 8 9
106 {f_, _t, _t, _t, _t, _t, _t, _t, _t, f_}, // 0
107 {f_, f_, _t, _t, _t, _t, _t, _t, _t, f_}, // 1
108 {f_, f_, f_, f_, f_, _t, _t, _t, _t, f_}, // 2
109 {f_, f_, f_, f_, f_, _t, _t, _t, _t, f_}, // 3
110 {f_, f_, f_, f_, f_, _t, _t, _t, _t, f_}, // 4
111 {f_, f_, f_, f_, f_, f_, _t, _t, _t, f_}, // 5
112 {f_, f_, f_, f_, f_, f_, f_, _t, _t, f_}, // 6
113 {f_, f_, f_, f_, f_, f_, f_, f_, _t, f_}, // 7
114 {f_, f_, f_, f_, f_, f_, f_, f_, f_, f_}, // 8
115 {f_, f_, f_, f_, f_, f_, f_, f_, f_, f_}, // 9
116 };
117
118 SECTION("comparison: less")
119 {
120 REQUIRE(expected_lt.size() == j_types.size());
121 for (size_t i = 0; i < j_types.size(); ++i)
122 {
123 REQUIRE(expected_lt[i].size() == j_types.size());
124 for (size_t j = 0; j < j_types.size(); ++j)
125 {
126 CAPTURE(i)
127 CAPTURE(j)
128 // check precomputed values
129 #if JSON_HAS_THREE_WAY_COMPARISON
130 // JSON_HAS_CPP_20 (do not remove; see note at top of file)
131 CHECK((j_types[i] < j_types[j]) == expected_lt[i][j]);
132 #else
133 CHECK(operator<(j_types[i], j_types[j]) == expected_lt[i][j]);
134 #endif
135 CHECK(f(j_types[i], j_types[j]) == expected_lt[i][j]);
136 }
137 }
138 }
139 #if JSON_HAS_THREE_WAY_COMPARISON
140 // JSON_HAS_CPP_20 (do not remove; see note at top of file)
141 SECTION("comparison: 3-way")
142 {
143 std::vector<std::vector<std::partial_ordering>> expected =
144 {
145 //0 1 2 3 4 5 6 7 8 9
146 {eq, lt, lt, lt, lt, lt, lt, lt, lt, un}, // 0
147 {gt, eq, lt, lt, lt, lt, lt, lt, lt, un}, // 1
148 {gt, gt, eq, eq, eq, lt, lt, lt, lt, un}, // 2
149 {gt, gt, eq, eq, eq, lt, lt, lt, lt, un}, // 3
150 {gt, gt, eq, eq, eq, lt, lt, lt, lt, un}, // 4
151 {gt, gt, gt, gt, gt, eq, lt, lt, lt, un}, // 5
152 {gt, gt, gt, gt, gt, gt, eq, lt, lt, un}, // 6
153 {gt, gt, gt, gt, gt, gt, gt, eq, lt, un}, // 7
154 {gt, gt, gt, gt, gt, gt, gt, gt, eq, un}, // 8
155 {un, un, un, un, un, un, un, un, un, un}, // 9
156 };
157
158 // check expected partial_ordering against expected boolean
159 REQUIRE(expected.size() == expected_lt.size());
160 for (size_t i = 0; i < expected.size(); ++i)
161 {
162 REQUIRE(expected[i].size() == expected_lt[i].size());
163 for (size_t j = 0; j < expected[i].size(); ++j)
164 {
165 CAPTURE(i)
166 CAPTURE(j)
167 CHECK(std::is_lt(expected[i][j]) == expected_lt[i][j]);
168 }
169 }
170
171 // check 3-way comparison against expected partial_ordering
172 REQUIRE(expected.size() == j_types.size());
173 for (size_t i = 0; i < j_types.size(); ++i)
174 {
175 REQUIRE(expected[i].size() == j_types.size());
176 for (size_t j = 0; j < j_types.size(); ++j)
177 {
178 CAPTURE(i)
179 CAPTURE(j)
180 CHECK((j_types[i] <=> j_types[j]) == expected[i][j]); // *NOPAD*
181 }
182 }
183 }
184 #endif
185 }
186
187 SECTION("values")
188 {
189 json j_values =
190 {
191 nullptr, nullptr, // 0 1
192 -17, 42, // 2 3
193 8u, 13u, // 4 5
194 3.14159, 23.42, // 6 7
195 nan, nan, // 8 9
196 "foo", "bar", // 10 11
197 true, false, // 12 13
198 {1, 2, 3}, {"one", "two", "three"}, // 14 15
199 {{"first", 1}, {"second", 2}}, {{"a", "A"}, {"b", {"B"}}}, // 16 17
200 json::binary({1, 2, 3}), json::binary({1, 2, 4}), // 18 19
201 json(json::value_t::discarded), json(json::value_t::discarded) // 20 21
202 };
203
204 std::vector<std::vector<bool>> expected_eq =
205 {
206 //0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
207 {_t, _t, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_}, // 0
208 {_t, _t, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_}, // 1
209 {f_, f_, _t, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_}, // 2
210 {f_, f_, f_, _t, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_}, // 3
211 {f_, f_, f_, f_, _t, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_}, // 4
212 {f_, f_, f_, f_, f_, _t, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_}, // 5
213 {f_, f_, f_, f_, f_, f_, _t, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_}, // 6
214 {f_, f_, f_, f_, f_, f_, f_, _t, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_}, // 7
215 {f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_}, // 8
216 {f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_}, // 9
217 {f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, _t, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_}, // 10
218 {f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, _t, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_}, // 11
219 {f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, _t, f_, f_, f_, f_, f_, f_, f_, f_, f_}, // 12
220 {f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, _t, f_, f_, f_, f_, f_, f_, f_, f_}, // 13
221 {f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, _t, f_, f_, f_, f_, f_, f_, f_}, // 14
222 {f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, _t, f_, f_, f_, f_, f_, f_}, // 15
223 {f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, _t, f_, f_, f_, f_, f_}, // 16
224 {f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, _t, f_, f_, f_, f_}, // 17
225 {f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, _t, f_, f_, f_}, // 18
226 {f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, _t, f_, f_}, // 19
227 {f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_}, // 20
228 {f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_}, // 21
229 };
230
231 std::vector<std::vector<bool>> expected_lt =
232 {
233 //0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
234 {f_, f_, _t, _t, _t, _t, _t, _t, _t, _t, _t, _t, _t, _t, _t, _t, _t, _t, _t, _t, f_, f_}, // 0
235 {f_, f_, _t, _t, _t, _t, _t, _t, _t, _t, _t, _t, _t, _t, _t, _t, _t, _t, _t, _t, f_, f_}, // 1
236 {f_, f_, f_, _t, _t, _t, _t, _t, f_, f_, _t, _t, f_, f_, _t, _t, _t, _t, _t, _t, f_, f_}, // 2
237 {f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, _t, _t, f_, f_, _t, _t, _t, _t, _t, _t, f_, f_}, // 3
238 {f_, f_, f_, _t, f_, _t, f_, _t, f_, f_, _t, _t, f_, f_, _t, _t, _t, _t, _t, _t, f_, f_}, // 4
239 {f_, f_, f_, _t, f_, f_, f_, _t, f_, f_, _t, _t, f_, f_, _t, _t, _t, _t, _t, _t, f_, f_}, // 5
240 {f_, f_, f_, _t, _t, _t, f_, _t, f_, f_, _t, _t, f_, f_, _t, _t, _t, _t, _t, _t, f_, f_}, // 6
241 {f_, f_, f_, _t, f_, f_, f_, f_, f_, f_, _t, _t, f_, f_, _t, _t, _t, _t, _t, _t, f_, f_}, // 7
242 {f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, _t, _t, f_, f_, _t, _t, _t, _t, _t, _t, f_, f_}, // 8
243 {f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, _t, _t, f_, f_, _t, _t, _t, _t, _t, _t, f_, f_}, // 9
244 {f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, _t, _t, f_, f_}, // 10
245 {f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, _t, f_, f_, f_, f_, f_, f_, f_, _t, _t, f_, f_}, // 11
246 {f_, f_, _t, _t, _t, _t, _t, _t, _t, _t, _t, _t, f_, f_, _t, _t, _t, _t, _t, _t, f_, f_}, // 12
247 {f_, f_, _t, _t, _t, _t, _t, _t, _t, _t, _t, _t, _t, f_, _t, _t, _t, _t, _t, _t, f_, f_}, // 13
248 {f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, _t, _t, f_, f_, f_, _t, f_, f_, _t, _t, f_, f_}, // 14
249 {f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, _t, _t, f_, f_, f_, f_, f_, f_, _t, _t, f_, f_}, // 15
250 {f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, _t, _t, f_, f_, _t, _t, f_, f_, _t, _t, f_, f_}, // 16
251 {f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, _t, _t, f_, f_, _t, _t, _t, f_, _t, _t, f_, f_}, // 17
252 {f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, _t, f_, f_}, // 18
253 {f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_}, // 19
254 {f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_}, // 20
255 {f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_}, // 21
256 };
257
258 SECTION("compares unordered")
259 {
260 std::vector<std::vector<bool>> expected =
261 {
262 //0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
263 {f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, _t, _t}, // 0
264 {f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, _t, _t}, // 1
265 {f_, f_, f_, f_, f_, f_, f_, f_, _t, _t, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, _t, _t}, // 2
266 {f_, f_, f_, f_, f_, f_, f_, f_, _t, _t, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, _t, _t}, // 3
267 {f_, f_, f_, f_, f_, f_, f_, f_, _t, _t, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, _t, _t}, // 4
268 {f_, f_, f_, f_, f_, f_, f_, f_, _t, _t, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, _t, _t}, // 5
269 {f_, f_, f_, f_, f_, f_, f_, f_, _t, _t, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, _t, _t}, // 6
270 {f_, f_, f_, f_, f_, f_, f_, f_, _t, _t, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, _t, _t}, // 7
271 {f_, f_, _t, _t, _t, _t, _t, _t, _t, _t, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, _t, _t}, // 8
272 {f_, f_, _t, _t, _t, _t, _t, _t, _t, _t, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, _t, _t}, // 9
273 {f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, _t, _t}, // 10
274 {f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, _t, _t}, // 11
275 {f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, _t, _t}, // 12
276 {f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, _t, _t}, // 13
277 {f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, _t, _t}, // 14
278 {f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, _t, _t}, // 15
279 {f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, _t, _t}, // 16
280 {f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, _t, _t}, // 17
281 {f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, _t, _t}, // 18
282 {f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, _t, _t}, // 19
283 {_t, _t, _t, _t, _t, _t, _t, _t, _t, _t, _t, _t, _t, _t, _t, _t, _t, _t, _t, _t, _t, _t}, // 20
284 {_t, _t, _t, _t, _t, _t, _t, _t, _t, _t, _t, _t, _t, _t, _t, _t, _t, _t, _t, _t, _t, _t}, // 21
285 };
286
287 // check if two values compare unordered as expected
288 REQUIRE(expected.size() == j_values.size());
289 for (size_t i = 0; i < j_values.size(); ++i)
290 {
291 REQUIRE(expected[i].size() == j_values.size());
292 for (size_t j = 0; j < j_values.size(); ++j)
293 {
294 CAPTURE(i)
295 CAPTURE(j)
296 CHECK(json::compares_unordered(j_values[i], j_values[j]) == expected[i][j]);
297 }
298 }
299 }
300
301 #if JSON_USE_LEGACY_DISCARDED_VALUE_COMPARISON
302 SECTION("compares unordered (inverse)")
303 {
304 std::vector<std::vector<bool>> expected =
305 {
306 //0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
307 {f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_}, // 0
308 {f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_}, // 1
309 {f_, f_, f_, f_, f_, f_, f_, f_, _t, _t, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_}, // 2
310 {f_, f_, f_, f_, f_, f_, f_, f_, _t, _t, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_}, // 3
311 {f_, f_, f_, f_, f_, f_, f_, f_, _t, _t, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_}, // 4
312 {f_, f_, f_, f_, f_, f_, f_, f_, _t, _t, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_}, // 5
313 {f_, f_, f_, f_, f_, f_, f_, f_, _t, _t, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_}, // 6
314 {f_, f_, f_, f_, f_, f_, f_, f_, _t, _t, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_}, // 7
315 {f_, f_, _t, _t, _t, _t, _t, _t, _t, _t, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_}, // 8
316 {f_, f_, _t, _t, _t, _t, _t, _t, _t, _t, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_}, // 9
317 {f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_}, // 10
318 {f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_}, // 11
319 {f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_}, // 12
320 {f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_}, // 13
321 {f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_}, // 14
322 {f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_}, // 15
323 {f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_}, // 16
324 {f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_}, // 17
325 {f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_}, // 18
326 {f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_}, // 19
327 {f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_}, // 20
328 {f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_}, // 21
329 };
330
331 // check that two values compare unordered as expected (with legacy-mode enabled)
332 REQUIRE(expected.size() == j_values.size());
333 for (size_t i = 0; i < j_values.size(); ++i)
334 {
335 REQUIRE(expected[i].size() == j_values.size());
336 for (size_t j = 0; j < j_values.size(); ++j)
337 {
338 CAPTURE(i)
339 CAPTURE(j)
340 CAPTURE(j_values[i])
341 CAPTURE(j_values[j])
342 CHECK(json::compares_unordered(j_values[i], j_values[j], true) == expected[i][j]);
343 }
344 }
345 }
346 #endif
347
348 SECTION("comparison: equal")
349 {
350 // check that two values compare equal
351 REQUIRE(expected_eq.size() == j_values.size());
352 for (size_t i = 0; i < j_values.size(); ++i)
353 {
354 REQUIRE(expected_eq[i].size() == j_values.size());
355 for (size_t j = 0; j < j_values.size(); ++j)
356 {
357 CAPTURE(i)
358 CAPTURE(j)
359 CHECK((j_values[i] == j_values[j]) == expected_eq[i][j]);
360 }
361 }
362
363 // compare with null pointer
364 json j_null;
365 CHECK(j_null == nullptr);
366 CHECK(nullptr == j_null);
367 }
368
369 SECTION("comparison: not equal")
370 {
371 // check that two values compare unequal as expected
372 for (size_t i = 0; i < j_values.size(); ++i)
373 {
374 for (size_t j = 0; j < j_values.size(); ++j)
375 {
376 CAPTURE(i)
377 CAPTURE(j)
378
379 if (json::compares_unordered(j_values[i], j_values[j], true))
380 {
381 // if two values compare unordered,
382 // check that the boolean comparison result is always false
383 CHECK_FALSE(j_values[i] != j_values[j]);
384 }
385 else
386 {
387 // otherwise, check that they compare according to their definition
388 // as the inverse of equal
389 CHECK((j_values[i] != j_values[j]) == !(j_values[i] == j_values[j]));
390 }
391 }
392 }
393
394 // compare with null pointer
395 const json j_null;
396 CHECK((j_null != nullptr) == false);
397 CHECK((nullptr != j_null) == false);
398 CHECK((j_null != nullptr) == !(j_null == nullptr));
399 CHECK((nullptr != j_null) == !(nullptr == j_null));
400 }
401
402 SECTION("comparison: less")
403 {
404 // check that two values compare less than as expected
405 REQUIRE(expected_lt.size() == j_values.size());
406 for (size_t i = 0; i < j_values.size(); ++i)
407 {
408 REQUIRE(expected_lt[i].size() == j_values.size());
409 for (size_t j = 0; j < j_values.size(); ++j)
410 {
411 CAPTURE(i)
412 CAPTURE(j)
413 CHECK((j_values[i] < j_values[j]) == expected_lt[i][j]);
414 }
415 }
416 }
417
418 SECTION("comparison: less than or equal equal")
419 {
420 // check that two values compare less than or equal as expected
421 for (size_t i = 0; i < j_values.size(); ++i)
422 {
423 for (size_t j = 0; j < j_values.size(); ++j)
424 {
425 CAPTURE(i)
426 CAPTURE(j)
427 if (json::compares_unordered(j_values[i], j_values[j], true))
428 {
429 // if two values compare unordered,
430 // check that the boolean comparison result is always false
431 CHECK_FALSE(j_values[i] <= j_values[j]);
432 }
433 else
434 {
435 // otherwise, check that they compare according to their definition
436 // as the inverse of less than with the operand order reversed
437 CHECK((j_values[i] <= j_values[j]) == !(j_values[j] < j_values[i]));
438 }
439 }
440 }
441 }
442
443 SECTION("comparison: greater than")
444 {
445 // check that two values compare greater than as expected
446 for (size_t i = 0; i < j_values.size(); ++i)
447 {
448 for (size_t j = 0; j < j_values.size(); ++j)
449 {
450 CAPTURE(i)
451 CAPTURE(j)
452 if (json::compares_unordered(j_values[i], j_values[j]))
453 {
454 // if two values compare unordered,
455 // check that the boolean comparison result is always false
456 CHECK_FALSE(j_values[i] > j_values[j]);
457 }
458 else
459 {
460 // otherwise, check that they compare according to their definition
461 // as the inverse of less than or equal which is defined as
462 // the inverse of less than with the operand order reversed
463 CHECK((j_values[i] > j_values[j]) == !(j_values[i] <= j_values[j]));
464 CHECK((j_values[i] > j_values[j]) == !!(j_values[j] < j_values[i]));
465 }
466 }
467 }
468 }
469
470 SECTION("comparison: greater than or equal")
471 {
472 // check that two values compare greater than or equal as expected
473 for (size_t i = 0; i < j_values.size(); ++i)
474 {
475 for (size_t j = 0; j < j_values.size(); ++j)
476 {
477 CAPTURE(i)
478 CAPTURE(j)
479 if (json::compares_unordered(j_values[i], j_values[j], true))
480 {
481 // if two values compare unordered,
482 // check that the boolean result is always false
483 CHECK_FALSE(j_values[i] >= j_values[j]);
484 }
485 else
486 {
487 // otherwise, check that they compare according to their definition
488 // as the inverse of less than
489 CHECK((j_values[i] >= j_values[j]) == !(j_values[i] < j_values[j]));
490 }
491 }
492 }
493 }
494
495 #if JSON_HAS_THREE_WAY_COMPARISON
496 // JSON_HAS_CPP_20 (do not remove; see note at top of file)
497 SECTION("comparison: 3-way")
498 {
499 std::vector<std::vector<std::partial_ordering>> expected =
500 {
501 //0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
502 {eq, eq, lt, lt, lt, lt, lt, lt, lt, lt, lt, lt, lt, lt, lt, lt, lt, lt, lt, lt, un, un}, // 0
503 {eq, eq, lt, lt, lt, lt, lt, lt, lt, lt, lt, lt, lt, lt, lt, lt, lt, lt, lt, lt, un, un}, // 1
504 {gt, gt, eq, lt, lt, lt, lt, lt, un, un, lt, lt, gt, gt, lt, lt, lt, lt, lt, lt, un, un}, // 2
505 {gt, gt, gt, eq, gt, gt, gt, gt, un, un, lt, lt, gt, gt, lt, lt, lt, lt, lt, lt, un, un}, // 3
506 {gt, gt, gt, lt, eq, lt, gt, lt, un, un, lt, lt, gt, gt, lt, lt, lt, lt, lt, lt, un, un}, // 4
507 {gt, gt, gt, lt, gt, eq, gt, lt, un, un, lt, lt, gt, gt, lt, lt, lt, lt, lt, lt, un, un}, // 5
508 {gt, gt, gt, lt, lt, lt, eq, lt, un, un, lt, lt, gt, gt, lt, lt, lt, lt, lt, lt, un, un}, // 6
509 {gt, gt, gt, lt, gt, gt, gt, eq, un, un, lt, lt, gt, gt, lt, lt, lt, lt, lt, lt, un, un}, // 7
510 {gt, gt, un, un, un, un, un, un, un, un, lt, lt, gt, gt, lt, lt, lt, lt, lt, lt, un, un}, // 8
511 {gt, gt, un, un, un, un, un, un, un, un, lt, lt, gt, gt, lt, lt, lt, lt, lt, lt, un, un}, // 9
512 {gt, gt, gt, gt, gt, gt, gt, gt, gt, gt, eq, gt, gt, gt, gt, gt, gt, gt, lt, lt, un, un}, // 10
513 {gt, gt, gt, gt, gt, gt, gt, gt, gt, gt, lt, eq, gt, gt, gt, gt, gt, gt, lt, lt, un, un}, // 11
514 {gt, gt, lt, lt, lt, lt, lt, lt, lt, lt, lt, lt, eq, gt, lt, lt, lt, lt, lt, lt, un, un}, // 12
515 {gt, gt, lt, lt, lt, lt, lt, lt, lt, lt, lt, lt, lt, eq, lt, lt, lt, lt, lt, lt, un, un}, // 13
516 {gt, gt, gt, gt, gt, gt, gt, gt, gt, gt, lt, lt, gt, gt, eq, lt, gt, gt, lt, lt, un, un}, // 14
517 {gt, gt, gt, gt, gt, gt, gt, gt, gt, gt, lt, lt, gt, gt, gt, eq, gt, gt, lt, lt, un, un}, // 15
518 {gt, gt, gt, gt, gt, gt, gt, gt, gt, gt, lt, lt, gt, gt, lt, lt, eq, gt, lt, lt, un, un}, // 16
519 {gt, gt, gt, gt, gt, gt, gt, gt, gt, gt, lt, lt, gt, gt, lt, lt, lt, eq, lt, lt, un, un}, // 17
520 {gt, gt, gt, gt, gt, gt, gt, gt, gt, gt, gt, gt, gt, gt, gt, gt, gt, gt, eq, lt, un, un}, // 18
521 {gt, gt, gt, gt, gt, gt, gt, gt, gt, gt, gt, gt, gt, gt, gt, gt, gt, gt, gt, eq, un, un}, // 19
522 {un, un, un, un, un, un, un, un, un, un, un, un, un, un, un, un, un, un, un, un, un, un}, // 20
523 {un, un, un, un, un, un, un, un, un, un, un, un, un, un, un, un, un, un, un, un, un, un}, // 21
524 };
525
526 // check expected partial_ordering against expected booleans
527 REQUIRE(expected.size() == expected_eq.size());
528 REQUIRE(expected.size() == expected_lt.size());
529 for (size_t i = 0; i < expected.size(); ++i)
530 {
531 REQUIRE(expected[i].size() == expected_eq[i].size());
532 REQUIRE(expected[i].size() == expected_lt[i].size());
533 for (size_t j = 0; j < expected[i].size(); ++j)
534 {
535 CAPTURE(i)
536 CAPTURE(j)
537 CHECK(std::is_eq(expected[i][j]) == expected_eq[i][j]);
538 CHECK(std::is_lt(expected[i][j]) == expected_lt[i][j]);
539 if (std::is_gt(expected[i][j]))
540 {
541 CHECK((!expected_eq[i][j] && !expected_lt[i][j]));
542 }
543 }
544 }
545
546 // check that two values compare according to their expected ordering
547 REQUIRE(expected.size() == j_values.size());
548 for (size_t i = 0; i < j_values.size(); ++i)
549 {
550 REQUIRE(expected[i].size() == j_values.size());
551 for (size_t j = 0; j < j_values.size(); ++j)
552 {
553 CAPTURE(i)
554 CAPTURE(j)
555 CHECK((j_values[i] <=> j_values[j]) == expected[i][j]); // *NOPAD*
556 }
557 }
558 }
559 #endif
560 }
561
562 #if JSON_USE_LEGACY_DISCARDED_VALUE_COMPARISON
563 SECTION("parser callback regression")
564 {
565 SECTION("filter specific element")
566 {
567 const auto* s_object = R"(
568 {
569 "foo": 2,
570 "bar": {
571 "baz": 1
572 }
573 }
574 )";
575 const auto* s_array = R"(
576 [1,2,[3,4,5],4,5]
577 )";
578
579 json j_object = json::parse(s_object, [](int /*unused*/, json::parse_event_t /*unused*/, const json & j) noexcept
__anon7556009d0202(int , json::parse_event_t , const json & j) 580 {
581 // filter all number(2) elements
582 return j != json(2);
583 });
584
585 CHECK (j_object == json({{"bar", {{"baz", 1}}}}));
586
587 json j_array = json::parse(s_array, [](int /*unused*/, json::parse_event_t /*unused*/, const json & j) noexcept
__anon7556009d0302(int , json::parse_event_t , const json & j) 588 {
589 return j != json(2);
590 });
591
592 CHECK (j_array == json({1, {3, 4, 5}, 4, 5}));
593 }
594 }
595 #endif
596 }
597