• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 #include "doctest_compatibility.h"
10 
11 #include <algorithm>
12 #include <nlohmann/json.hpp>
13 using nlohmann::json;
14 
15 TEST_CASE("algorithms")
16 {
17     json j_array = {13, 29, 3, {{"one", 1}, {"two", 2}}, true, false, {1, 2, 3}, "foo", "baz"};
18     json j_object = {{"one", 1}, {"two", 2}};
19 
20     SECTION("non-modifying sequence operations")
21     {
22         SECTION("std::all_of")
23         {
24             CHECK(std::all_of(j_array.begin(), j_array.end(), [](const json & value)
__anon65bee81c0102(const json & value) 25             {
26                 return !value.empty();
27             }));
28             CHECK(std::all_of(j_object.begin(), j_object.end(), [](const json & value)
__anon65bee81c0202(const json & value) 29             {
30                 return value.type() == json::value_t::number_integer;
31             }));
32         }
33 
34         SECTION("std::any_of")
35         {
36             CHECK(std::any_of(j_array.begin(), j_array.end(), [](const json & value)
__anon65bee81c0302(const json & value) 37             {
38                 return value.is_string() && value.get<std::string>() == "foo";
39             }));
40             CHECK(std::any_of(j_object.begin(), j_object.end(), [](const json & value)
__anon65bee81c0402(const json & value) 41             {
42                 return value.get<int>() > 1;
43             }));
44         }
45 
46         SECTION("std::none_of")
47         {
48             CHECK(std::none_of(j_array.begin(), j_array.end(), [](const json & value)
__anon65bee81c0502(const json & value) 49             {
50                 return value.empty();
51             }));
52             CHECK(std::none_of(j_object.begin(), j_object.end(), [](const json & value)
__anon65bee81c0602(const json & value) 53             {
54                 return value.get<int>() <= 0;
55             }));
56         }
57 
58         SECTION("std::for_each")
59         {
60             SECTION("reading")
61             {
62                 int sum = 0;
63 
64                 std::for_each(j_array.cbegin(), j_array.cend(), [&sum](const json & value)
__anon65bee81c0702(const json & value) 65                 {
66                     if (value.is_number())
67                     {
68                         sum += static_cast<int>(value);
69                     }
70                 });
71 
72                 CHECK(sum == 45);
73             }
74 
75             SECTION("writing")
76             {
77                 auto add17 = [](json & value)
__anon65bee81c0802(json & value) 78                 {
79                     if (value.is_array())
80                     {
81                         value.push_back(17);
82                     }
83                 };
84 
85                 std::for_each(j_array.begin(), j_array.end(), add17);
86 
87                 CHECK(j_array[6] == json({1, 2, 3, 17}));
88             }
89         }
90 
91         SECTION("std::count")
92         {
93             CHECK(std::count(j_array.begin(), j_array.end(), json(true)) == 1);
94         }
95 
96         SECTION("std::count_if")
97         {
98             CHECK(std::count_if(j_array.begin(), j_array.end(), [](const json & value)
__anon65bee81c0902(const json & value) 99             {
100                 return (value.is_number());
101             }) == 3);
102             CHECK(std::count_if(j_array.begin(), j_array.end(), [](const json&)
__anon65bee81c0a02(const json&) 103             {
104                 return true;
105             }) == 9);
106         }
107 
108         SECTION("std::mismatch")
109         {
110             json j_array2 = {13, 29, 3, {{"one", 1}, {"two", 2}, {"three", 3}}, true, false, {1, 2, 3}, "foo", "baz"};
111             auto res = std::mismatch(j_array.begin(), j_array.end(), j_array2.begin());
112             CHECK(*res.first == json({{"one", 1}, {"two", 2}}));
113             CHECK(*res.second == json({{"one", 1}, {"two", 2}, {"three", 3}}));
114         }
115 
116         SECTION("std::equal")
117         {
118             SECTION("using operator==")
119             {
120                 CHECK(std::equal(j_array.begin(), j_array.end(), j_array.begin()));
121                 CHECK(std::equal(j_object.begin(), j_object.end(), j_object.begin()));
122                 CHECK(!std::equal(j_array.begin(), j_array.end(), j_object.begin()));
123             }
124 
125             SECTION("using user-defined comparison")
126             {
127                 // compare objects only by size of its elements
128                 json j_array2 = {13, 29, 3, {"Hello", "World"}, true, false, {{"one", 1}, {"two", 2}, {"three", 3}}, "foo", "baz"};
129                 CHECK(!std::equal(j_array.begin(), j_array.end(), j_array2.begin()));
130                 CHECK(std::equal(j_array.begin(), j_array.end(), j_array2.begin(),
131                                  [](const json & a, const json & b)
__anon65bee81c0b02(const json & a, const json & b) 132                 {
133                     return (a.size() == b.size());
134                 }));
135             }
136         }
137 
138         SECTION("std::find")
139         {
140             auto it = std::find(j_array.begin(), j_array.end(), json(false));
141             CHECK(std::distance(j_array.begin(), it) == 5);
142         }
143 
144         SECTION("std::find_if")
145         {
146             auto it = std::find_if(j_array.begin(), j_array.end(),
147                                    [](const json & value)
__anon65bee81c0c02(const json & value) 148             {
149                 return value.is_boolean();
150             });
151             CHECK(std::distance(j_array.begin(), it) == 4);
152         }
153 
154         SECTION("std::find_if_not")
155         {
156             auto it = std::find_if_not(j_array.begin(), j_array.end(),
157                                        [](const json & value)
__anon65bee81c0d02(const json & value) 158             {
159                 return value.is_number();
160             });
161             CHECK(std::distance(j_array.begin(), it) == 3);
162         }
163 
164         SECTION("std::adjacent_find")
165         {
166             CHECK(std::adjacent_find(j_array.begin(), j_array.end()) == j_array.end());
167             CHECK(std::adjacent_find(j_array.begin(), j_array.end(),
168                                      [](const json & v1, const json & v2)
__anon65bee81c0e02(const json & v1, const json & v2) 169             {
170                 return v1.type() == v2.type();
171             }) == j_array.begin());
172         }
173     }
174 
175     SECTION("modifying sequence operations")
176     {
177         SECTION("std::reverse")
178         {
179             std::reverse(j_array.begin(), j_array.end());
180             CHECK(j_array == json({"baz", "foo", {1, 2, 3}, false, true, {{"one", 1}, {"two", 2}}, 3, 29, 13}));
181         }
182 
183         SECTION("std::rotate")
184         {
185             std::rotate(j_array.begin(), j_array.begin() + 1, j_array.end());
186             CHECK(j_array == json({29, 3, {{"one", 1}, {"two", 2}}, true, false, {1, 2, 3}, "foo", "baz", 13}));
187         }
188 
189         SECTION("std::partition")
190         {
191             auto it = std::partition(j_array.begin(), j_array.end(), [](const json & v)
__anon65bee81c0f02(const json & v) 192             {
193                 return v.is_string();
194             });
195             CHECK(std::distance(j_array.begin(), it) == 2);
196             CHECK(!it[2].is_string());
197         }
198     }
199 
200     SECTION("sorting operations")
201     {
202         SECTION("std::sort")
203         {
204             SECTION("with standard comparison")
205             {
206                 json j = {13, 29, 3, {{"one", 1}, {"two", 2}}, true, false, {1, 2, 3}, "foo", "baz", nullptr};
207                 std::sort(j.begin(), j.end());
208                 CHECK(j == json({nullptr, false, true, 3, 13, 29, {{"one", 1}, {"two", 2}}, {1, 2, 3}, "baz", "foo"}));
209             }
210 
211             SECTION("with user-defined comparison")
212             {
213                 json j = {3, {{"one", 1}, {"two", 2}}, {1, 2, 3}, nullptr};
214                 std::sort(j.begin(), j.end(), [](const json & a, const json & b)
__anon65bee81c1002(const json & a, const json & b) 215                 {
216                     return a.size() < b.size();
217                 });
218                 CHECK(j == json({nullptr, 3, {{"one", 1}, {"two", 2}}, {1, 2, 3}}));
219             }
220 
221             SECTION("sorting an object")
222             {
223                 json j({{"one", 1}, {"two", 2}});
224                 CHECK_THROWS_WITH_AS(std::sort(j.begin(), j.end()), "[json.exception.invalid_iterator.209] cannot use offsets with object iterators", json::invalid_iterator&);
225             }
226         }
227 
228         SECTION("std::partial_sort")
229         {
230             json j = {13, 29, 3, {{"one", 1}, {"two", 2}}, true, false, {1, 2, 3}, "foo", "baz", nullptr};
231             std::partial_sort(j.begin(), j.begin() + 4, j.end());
232             CHECK(j == json({nullptr, false, true, 3, {{"one", 1}, {"two", 2}}, 29, {1, 2, 3}, "foo", "baz", 13}));
233         }
234     }
235 
236     SECTION("set operations")
237     {
238         SECTION("std::merge")
239         {
240             {
241                 json j1 = {2, 4, 6, 8};
242                 json j2 = {1, 2, 3, 5, 7};
243                 json j3;
244 
245                 std::merge(j1.begin(), j1.end(), j2.begin(), j2.end(), std::back_inserter(j3));
246                 CHECK(j3 == json({1, 2, 2, 3, 4, 5, 6, 7, 8}));
247             }
248         }
249 
250         SECTION("std::set_difference")
251         {
252             json j1 = {1, 2, 3, 4, 5, 6, 7, 8};
253             json j2 = {1, 2, 3, 5, 7};
254             json j3;
255 
256             std::set_difference(j1.begin(), j1.end(), j2.begin(), j2.end(), std::back_inserter(j3));
257             CHECK(j3 == json({4, 6, 8}));
258         }
259 
260         SECTION("std::set_intersection")
261         {
262             json j1 = {1, 2, 3, 4, 5, 6, 7, 8};
263             json j2 = {1, 2, 3, 5, 7};
264             json j3;
265 
266             std::set_intersection(j1.begin(), j1.end(), j2.begin(), j2.end(), std::back_inserter(j3));
267             CHECK(j3 == json({1, 2, 3, 5, 7}));
268         }
269 
270         SECTION("std::set_union")
271         {
272             json j1 = {2, 4, 6, 8};
273             json j2 = {1, 2, 3, 5, 7};
274             json j3;
275 
276             std::set_union(j1.begin(), j1.end(), j2.begin(), j2.end(), std::back_inserter(j3));
277             CHECK(j3 == json({1, 2, 3, 4, 5, 6, 7, 8}));
278         }
279 
280         SECTION("std::set_symmetric_difference")
281         {
282             json j1 = {2, 4, 6, 8};
283             json j2 = {1, 2, 3, 5, 7};
284             json j3;
285 
286             std::set_symmetric_difference(j1.begin(), j1.end(), j2.begin(), j2.end(), std::back_inserter(j3));
287             CHECK(j3 == json({1, 3, 4, 5, 6, 7, 8}));
288         }
289     }
290 
291     SECTION("heap operations")
292     {
293         std::make_heap(j_array.begin(), j_array.end());
294         CHECK(std::is_heap(j_array.begin(), j_array.end()));
295         std::sort_heap(j_array.begin(), j_array.end());
296         CHECK(j_array == json({false, true, 3, 13, 29, {{"one", 1}, {"two", 2}}, {1, 2, 3}, "baz", "foo"}));
297     }
298 
299     SECTION("iota")
300     {
301         SECTION("int")
302         {
303             json json_arr = {0, 5, 2, 4, 10, 20, 30, 40, 50, 1};
304             std::iota(json_arr.begin(), json_arr.end(), 0);
305             CHECK(json_arr == json({0, 1, 2, 3, 4, 5, 6, 7, 8, 9}));
306         }
307         SECTION("double")
308         {
309             json json_arr = {0.5, 1.5, 1.3, 4.1, 10.2, 20.5, 30.6, 40.1, 50.22, 1.5};
310             std::iota(json_arr.begin(), json_arr.end(), 0.5);
311             CHECK(json_arr == json({0.5, 1.5, 2.5, 3.5, 4.5, 5.5, 6.5, 7.5, 8.5, 9.5}));
312         }
313 
314         SECTION("char")
315         {
316             json json_arr = {'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', '0', '1'};
317             std::iota(json_arr.begin(), json_arr.end(), '0');
318             CHECK(json_arr == json({'0', '1', '2', '3', '4', '5', '6', '7', '8', '9'}));
319         }
320     }
321 
322     SECTION("copy")
323     {
324         SECTION("copy without if")
325         {
326             json dest_arr;
327             const json source_arr = {1, 2, 3, 4};
328 
329             std::copy(source_arr.begin(), source_arr.end(), std::back_inserter(dest_arr));
330 
331             CHECK(dest_arr == source_arr);
332         }
333         SECTION("copy if")
334         {
335             json dest_arr;
336             const json source_arr = {0, 3, 6, 9, 12, 15, 20};
337 
338             std::copy_if(source_arr.begin(), source_arr.end(), std::back_inserter(dest_arr), [](const json & _value)
__anon65bee81c1102(const json & _value) 339             {
340                 return _value.get<int>() % 3 == 0;
341             });
342             CHECK(dest_arr == json({0, 3, 6, 9, 12, 15}));
343         }
344         SECTION("copy n")
345         {
346             const json source_arr = {0, 1, 2, 3, 4, 5, 6, 7};
347             json dest_arr;
348             const unsigned char numToCopy = 2;
349 
350             std::copy_n(source_arr.begin(), numToCopy, std::back_inserter(dest_arr));
351             CHECK(dest_arr == json{0, 1});
352 
353         }
354         SECTION("copy n chars")
355         {
356             const json source_arr = {'1', '2', '3', '4', '5', '6', '7'};
357             json dest_arr;
358             const unsigned char numToCopy = 4;
359 
360             std::copy_n(source_arr.begin(), numToCopy, std::back_inserter(dest_arr));
361             CHECK(dest_arr == json{'1', '2', '3', '4'});
362         }
363     }
364 
365 }
366