1 /*
2     __ _____ _____ _____
3  __|  |   __|     |   | |  JSON for Modern C++ (test suite)
4 |  |  |__   |  |  | | | |  version 3.9.1
5 |_____|_____|_____|_|___|  https://github.com/nlohmann/json
6 
7 Licensed under the MIT License <http://opensource.org/licenses/MIT>.
8 SPDX-License-Identifier: MIT
9 Copyright (c) 2013-2019 Niels Lohmann <http://nlohmann.me>.
10 
11 Permission is hereby  granted, free of charge, to any  person obtaining a copy
12 of this software and associated  documentation files (the "Software"), to deal
13 in the Software  without restriction, including without  limitation the rights
14 to  use, copy,  modify, merge,  publish, distribute,  sublicense, and/or  sell
15 copies  of  the Software,  and  to  permit persons  to  whom  the Software  is
16 furnished to do so, subject to the following conditions:
17 
18 The above copyright notice and this permission notice shall be included in all
19 copies or substantial portions of the Software.
20 
21 THE SOFTWARE  IS PROVIDED "AS  IS", WITHOUT WARRANTY  OF ANY KIND,  EXPRESS OR
22 IMPLIED,  INCLUDING BUT  NOT  LIMITED TO  THE  WARRANTIES OF  MERCHANTABILITY,
23 FITNESS FOR  A PARTICULAR PURPOSE AND  NONINFRINGEMENT. IN NO EVENT  SHALL THE
24 AUTHORS  OR COPYRIGHT  HOLDERS  BE  LIABLE FOR  ANY  CLAIM,  DAMAGES OR  OTHER
25 LIABILITY, WHETHER IN AN ACTION OF  CONTRACT, TORT OR OTHERWISE, ARISING FROM,
26 OUT OF OR IN CONNECTION WITH THE SOFTWARE  OR THE USE OR OTHER DEALINGS IN THE
27 SOFTWARE.
28 */
29 
30 #include "doctest_compatibility.h"
31 
32 #include <nlohmann/json.hpp>
33 using nlohmann::json;
34 
35 TEST_CASE("algorithms")
36 {
37     json j_array = {13, 29, 3, {{"one", 1}, {"two", 2}}, true, false, {1, 2, 3}, "foo", "baz"};
38     json j_object = {{"one", 1}, {"two", 2}};
39 
40     SECTION("non-modifying sequence operations")
41     {
42         SECTION("std::all_of")
43         {
44             CHECK(std::all_of(j_array.begin(), j_array.end(), [](const json & value)
__anon345573800102(const json & value) 45             {
46                 return value.size() > 0;
47             }));
48             CHECK(std::all_of(j_object.begin(), j_object.end(), [](const json & value)
__anon345573800202(const json & value) 49             {
50                 return value.type() == json::value_t::number_integer;
51             }));
52         }
53 
54         SECTION("std::any_of")
55         {
56             CHECK(std::any_of(j_array.begin(), j_array.end(), [](const json & value)
__anon345573800302(const json & value) 57             {
58                 return value.is_string() && value.get<std::string>() == "foo";
59             }));
60             CHECK(std::any_of(j_object.begin(), j_object.end(), [](const json & value)
__anon345573800402(const json & value) 61             {
62                 return value.get<int>() > 1;
63             }));
64         }
65 
66         SECTION("std::none_of")
67         {
68             CHECK(std::none_of(j_array.begin(), j_array.end(), [](const json & value)
__anon345573800502(const json & value) 69             {
70                 return value.size() == 0;
71             }));
72             CHECK(std::none_of(j_object.begin(), j_object.end(), [](const json & value)
__anon345573800602(const json & value) 73             {
74                 return value.get<int>() <= 0;
75             }));
76         }
77 
78         SECTION("std::for_each")
79         {
80             SECTION("reading")
81             {
82                 int sum = 0;
83 
84                 std::for_each(j_array.cbegin(), j_array.cend(), [&sum](const json & value)
__anon345573800702(const json & value) 85                 {
86                     if (value.is_number())
87                     {
88                         sum += static_cast<int>(value);
89                     }
90                 });
91 
92                 CHECK(sum == 45);
93             }
94 
95             SECTION("writing")
96             {
97                 auto add17 = [](json & value)
__anon345573800802(json & value) 98                 {
99                     if (value.is_array())
100                     {
101                         value.push_back(17);
102                     }
103                 };
104 
105                 std::for_each(j_array.begin(), j_array.end(), add17);
106 
107                 CHECK(j_array[6] == json({1, 2, 3, 17}));
108             }
109         }
110 
111         SECTION("std::count")
112         {
113             CHECK(std::count(j_array.begin(), j_array.end(), json(true)) == 1);
114         }
115 
116         SECTION("std::count_if")
117         {
118             CHECK(std::count_if(j_array.begin(), j_array.end(), [](const json & value)
__anon345573800902(const json & value) 119             {
120                 return (value.is_number());
121             }) == 3);
122             CHECK(std::count_if(j_array.begin(), j_array.end(), [](const json&)
__anon345573800a02(const json&) 123             {
124                 return true;
125             }) == 9);
126         }
127 
128         SECTION("std::mismatch")
129         {
130             json j_array2 = {13, 29, 3, {{"one", 1}, {"two", 2}, {"three", 3}}, true, false, {1, 2, 3}, "foo", "baz"};
131             auto res = std::mismatch(j_array.begin(), j_array.end(), j_array2.begin());
132             CHECK(*res.first == json({{"one", 1}, {"two", 2}}));
133             CHECK(*res.second == json({{"one", 1}, {"two", 2}, {"three", 3}}));
134         }
135 
136         SECTION("std::equal")
137         {
138             SECTION("using operator==")
139             {
140                 CHECK(std::equal(j_array.begin(), j_array.end(), j_array.begin()));
141                 CHECK(std::equal(j_object.begin(), j_object.end(), j_object.begin()));
142                 CHECK(!std::equal(j_array.begin(), j_array.end(), j_object.begin()));
143             }
144 
145             SECTION("using user-defined comparison")
146             {
147                 // compare objects only by size of its elements
148                 json j_array2 = {13, 29, 3, {"Hello", "World"}, true, false, {{"one", 1}, {"two", 2}, {"three", 3}}, "foo", "baz"};
149                 CHECK(!std::equal(j_array.begin(), j_array.end(), j_array2.begin()));
150                 CHECK(std::equal(j_array.begin(), j_array.end(), j_array2.begin(),
151                                  [](const json & a, const json & b)
__anon345573800b02(const json & a, const json & b) 152                 {
153                     return (a.size() == b.size());
154                 }));
155             }
156         }
157 
158         SECTION("std::find")
159         {
160             auto it = std::find(j_array.begin(), j_array.end(), json(false));
161             CHECK(std::distance(j_array.begin(), it) == 5);
162         }
163 
164         SECTION("std::find_if")
165         {
166             auto it = std::find_if(j_array.begin(), j_array.end(),
167                                    [](const json & value)
__anon345573800c02(const json & value) 168             {
169                 return value.is_boolean();
170             });
171             CHECK(std::distance(j_array.begin(), it) == 4);
172         }
173 
174         SECTION("std::find_if_not")
175         {
176             auto it = std::find_if_not(j_array.begin(), j_array.end(),
177                                        [](const json & value)
__anon345573800d02(const json & value) 178             {
179                 return value.is_number();
180             });
181             CHECK(std::distance(j_array.begin(), it) == 3);
182         }
183 
184         SECTION("std::adjacent_find")
185         {
186             CHECK(std::adjacent_find(j_array.begin(), j_array.end()) == j_array.end());
187             CHECK(std::adjacent_find(j_array.begin(), j_array.end(),
188                                      [](const json & v1, const json & v2)
__anon345573800e02(const json & v1, const json & v2) 189             {
190                 return v1.type() == v2.type();
191             }) == j_array.begin());
192         }
193     }
194 
195     SECTION("modifying sequence operations")
196     {
197         SECTION("std::reverse")
198         {
199             std::reverse(j_array.begin(), j_array.end());
200             CHECK(j_array == json({"baz", "foo", {1, 2, 3}, false, true, {{"one", 1}, {"two", 2}}, 3, 29, 13}));
201         }
202 
203         SECTION("std::rotate")
204         {
205             std::rotate(j_array.begin(), j_array.begin() + 1, j_array.end());
206             CHECK(j_array == json({29, 3, {{"one", 1}, {"two", 2}}, true, false, {1, 2, 3}, "foo", "baz", 13}));
207         }
208 
209         SECTION("std::partition")
210         {
211             auto it = std::partition(j_array.begin(), j_array.end(), [](const json & v)
__anon345573800f02(const json & v) 212             {
213                 return v.is_string();
214             });
215             CHECK(std::distance(j_array.begin(), it) == 2);
216             CHECK(!it[2].is_string());
217         }
218     }
219 
220     SECTION("sorting operations")
221     {
222         SECTION("std::sort")
223         {
224             SECTION("with standard comparison")
225             {
226                 json j = {13, 29, 3, {{"one", 1}, {"two", 2}}, true, false, {1, 2, 3}, "foo", "baz", nullptr};
227                 std::sort(j.begin(), j.end());
228                 CHECK(j == json({nullptr, false, true, 3, 13, 29, {{"one", 1}, {"two", 2}}, {1, 2, 3}, "baz", "foo"}));
229             }
230 
231             SECTION("with user-defined comparison")
232             {
233                 json j = {3, {{"one", 1}, {"two", 2}}, {1, 2, 3}, nullptr};
234                 std::sort(j.begin(), j.end(), [](const json & a, const json & b)
__anon345573801002(const json & a, const json & b) 235                 {
236                     return a.size() < b.size();
237                 });
238                 CHECK(j == json({nullptr, 3, {{"one", 1}, {"two", 2}}, {1, 2, 3}}));
239             }
240 
241             SECTION("sorting an object")
242             {
243                 json j({{"one", 1}, {"two", 2}});
244                 CHECK_THROWS_AS(std::sort(j.begin(), j.end()), json::invalid_iterator&);
245                 CHECK_THROWS_WITH(std::sort(j.begin(), j.end()),
246                                   "[json.exception.invalid_iterator.209] cannot use offsets with object iterators");
247             }
248         }
249 
250         SECTION("std::partial_sort")
251         {
252             json j = {13, 29, 3, {{"one", 1}, {"two", 2}}, true, false, {1, 2, 3}, "foo", "baz", nullptr};
253             std::partial_sort(j.begin(), j.begin() + 4, j.end());
254             CHECK(j == json({nullptr, false, true, 3, {{"one", 1}, {"two", 2}}, 29, {1, 2, 3}, "foo", "baz", 13}));
255         }
256     }
257 
258     SECTION("set operations")
259     {
260         SECTION("std::merge")
261         {
262             {
263                 json j1 = {2, 4, 6, 8};
264                 json j2 = {1, 2, 3, 5, 7};
265                 json j3;
266 
267                 std::merge(j1.begin(), j1.end(), j2.begin(), j2.end(), std::back_inserter(j3));
268                 CHECK(j3 == json({1, 2, 2, 3, 4, 5, 6, 7, 8}));
269             }
270         }
271 
272         SECTION("std::set_difference")
273         {
274             json j1 = {1, 2, 3, 4, 5, 6, 7, 8};
275             json j2 = {1, 2, 3, 5, 7};
276             json j3;
277 
278             std::set_difference(j1.begin(), j1.end(), j2.begin(), j2.end(), std::back_inserter(j3));
279             CHECK(j3 == json({4, 6, 8}));
280         }
281 
282         SECTION("std::set_intersection")
283         {
284             json j1 = {1, 2, 3, 4, 5, 6, 7, 8};
285             json j2 = {1, 2, 3, 5, 7};
286             json j3;
287 
288             std::set_intersection(j1.begin(), j1.end(), j2.begin(), j2.end(), std::back_inserter(j3));
289             CHECK(j3 == json({1, 2, 3, 5, 7}));
290         }
291 
292         SECTION("std::set_union")
293         {
294             json j1 = {2, 4, 6, 8};
295             json j2 = {1, 2, 3, 5, 7};
296             json j3;
297 
298             std::set_union(j1.begin(), j1.end(), j2.begin(), j2.end(), std::back_inserter(j3));
299             CHECK(j3 == json({1, 2, 3, 4, 5, 6, 7, 8}));
300         }
301 
302         SECTION("std::set_symmetric_difference")
303         {
304             json j1 = {2, 4, 6, 8};
305             json j2 = {1, 2, 3, 5, 7};
306             json j3;
307 
308             std::set_symmetric_difference(j1.begin(), j1.end(), j2.begin(), j2.end(), std::back_inserter(j3));
309             CHECK(j3 == json({1, 3, 4, 5, 6, 7, 8}));
310         }
311     }
312 
313     SECTION("heap operations")
314     {
315         std::make_heap(j_array.begin(), j_array.end());
316         CHECK(std::is_heap(j_array.begin(), j_array.end()));
317         std::sort_heap(j_array.begin(), j_array.end());
318         CHECK(j_array == json({false, true, 3, 13, 29, {{"one", 1}, {"two", 2}}, {1, 2, 3}, "baz", "foo"}));
319     }
320 }
321