1 //     __ _____ _____ _____
2 //  __|  |   __|     |   | |  JSON for Modern C++ (supporting code)
3 // |  |  |__   |  |  | | | |  version 3.11.2
4 // |_____|_____|_____|_|___|  https://github.com/nlohmann/json
5 //
6 // SPDX-FileCopyrightText: 2013-2022 Niels Lohmann <https://nlohmann.me>
7 // SPDX-License-Identifier: MIT
8 
9 #include "doctest_compatibility.h"
10 
11 #define JSON_TESTS_PRIVATE
12 #include <nlohmann/json.hpp>
13 using nlohmann::json;
14 
15 template<typename Iter>
16 using can_post_increment_temporary = decltype((std::declval<Iter>()++)++);
17 
18 template<typename Iter>
19 using can_post_decrement_temporary = decltype((std::declval<Iter>()--)--);
20 
21 TEST_CASE("iterator class")
22 {
23     SECTION("construction")
24     {
25         SECTION("constructor")
26         {
27             SECTION("null")
28             {
29                 json j(json::value_t::null);
30                 json::iterator it(&j);
31             }
32 
33             SECTION("object")
34             {
35                 json j(json::value_t::object);
36                 json::iterator it(&j);
37             }
38 
39             SECTION("array")
40             {
41                 json j(json::value_t::array);
42                 json::iterator it(&j);
43             }
44         }
45 
46         SECTION("copy assignment")
47         {
48             json j(json::value_t::null);
49             json::iterator it(&j);
50             json::iterator it2(&j);
51             it2 = it;
52         }
53     }
54 
55     SECTION("initialization")
56     {
57         SECTION("set_begin")
58         {
59             SECTION("null")
60             {
61                 json j(json::value_t::null);
62                 json::iterator it(&j);
63                 it.set_begin();
64                 CHECK((it == j.begin()));
65             }
66 
67             SECTION("object")
68             {
69                 json j(json::value_t::object);
70                 json::iterator it(&j);
71                 it.set_begin();
72                 CHECK((it == j.begin()));
73             }
74 
75             SECTION("array")
76             {
77                 json j(json::value_t::array);
78                 json::iterator it(&j);
79                 it.set_begin();
80                 CHECK((it == j.begin()));
81             }
82         }
83 
84         SECTION("set_end")
85         {
86             SECTION("null")
87             {
88                 json j(json::value_t::null);
89                 json::iterator it(&j);
90                 it.set_end();
91                 CHECK((it == j.end()));
92             }
93 
94             SECTION("object")
95             {
96                 json j(json::value_t::object);
97                 json::iterator it(&j);
98                 it.set_end();
99                 CHECK((it == j.end()));
100             }
101 
102             SECTION("array")
103             {
104                 json j(json::value_t::array);
105                 json::iterator it(&j);
106                 it.set_end();
107                 CHECK((it == j.end()));
108             }
109         }
110     }
111 
112     SECTION("element access")
113     {
114         SECTION("operator*")
115         {
116             SECTION("null")
117             {
118                 json j(json::value_t::null);
119                 json::iterator it = j.begin();
120                 CHECK_THROWS_WITH_AS(*it, "[json.exception.invalid_iterator.214] cannot get value", json::invalid_iterator&);
121             }
122 
123             SECTION("number")
124             {
125                 json j(17);
126                 json::iterator it = j.begin();
127                 CHECK(*it == json(17));
128                 it = j.end();
129                 CHECK_THROWS_WITH_AS(*it, "[json.exception.invalid_iterator.214] cannot get value", json::invalid_iterator&);
130             }
131 
132             SECTION("object")
133             {
134                 json j({{"foo", "bar"}});
135                 json::iterator it = j.begin();
136                 CHECK(*it == json("bar"));
137             }
138 
139             SECTION("array")
140             {
141                 json j({1, 2, 3, 4});
142                 json::iterator it = j.begin();
143                 CHECK(*it == json(1));
144             }
145         }
146 
147         SECTION("operator->")
148         {
149             SECTION("null")
150             {
151                 json j(json::value_t::null);
152                 json::iterator it = j.begin();
153                 CHECK_THROWS_WITH_AS(std::string(it->type_name()), "[json.exception.invalid_iterator.214] cannot get value", json::invalid_iterator&);
154             }
155 
156             SECTION("number")
157             {
158                 json j(17);
159                 json::iterator it = j.begin();
160                 CHECK(std::string(it->type_name()) == "number");
161                 it = j.end();
162                 CHECK_THROWS_WITH_AS(std::string(it->type_name()), "[json.exception.invalid_iterator.214] cannot get value", json::invalid_iterator&);
163             }
164 
165             SECTION("object")
166             {
167                 json j({{"foo", "bar"}});
168                 json::iterator it = j.begin();
169                 CHECK(std::string(it->type_name()) == "string");
170             }
171 
172             SECTION("array")
173             {
174                 json j({1, 2, 3, 4});
175                 json::iterator it = j.begin();
176                 CHECK(std::string(it->type_name()) == "number");
177             }
178         }
179     }
180 
181     SECTION("increment/decrement")
182     {
183         SECTION("post-increment")
184         {
185             SECTION("null")
186             {
187                 json j(json::value_t::null);
188                 json::iterator it = j.begin();
189                 CHECK((it.m_it.primitive_iterator.m_it == 1));
190                 it++;
191                 CHECK((it.m_it.primitive_iterator.m_it != 0 && it.m_it.primitive_iterator.m_it != 1));
192             }
193 
194             SECTION("number")
195             {
196                 json j(17);
197                 json::iterator it = j.begin();
198                 CHECK((it.m_it.primitive_iterator.m_it == 0));
199                 it++;
200                 CHECK((it.m_it.primitive_iterator.m_it == 1));
201                 it++;
202                 CHECK((it.m_it.primitive_iterator.m_it != 0 && it.m_it.primitive_iterator.m_it != 1));
203             }
204 
205             SECTION("object")
206             {
207                 json j({{"foo", "bar"}});
208                 json::iterator it = j.begin();
209                 CHECK((it.m_it.object_iterator == it.m_object->m_value.object->begin()));
210                 it++;
211                 CHECK((it.m_it.object_iterator == it.m_object->m_value.object->end()));
212             }
213 
214             SECTION("array")
215             {
216                 json j({1, 2, 3, 4});
217                 json::iterator it = j.begin();
218                 CHECK((it.m_it.array_iterator == it.m_object->m_value.array->begin()));
219                 it++;
220                 CHECK((it.m_it.array_iterator != it.m_object->m_value.array->begin()));
221                 CHECK((it.m_it.array_iterator != it.m_object->m_value.array->end()));
222                 it++;
223                 CHECK((it.m_it.array_iterator != it.m_object->m_value.array->begin()));
224                 CHECK((it.m_it.array_iterator != it.m_object->m_value.array->end()));
225                 it++;
226                 CHECK((it.m_it.array_iterator != it.m_object->m_value.array->begin()));
227                 CHECK((it.m_it.array_iterator != it.m_object->m_value.array->end()));
228                 it++;
229                 CHECK((it.m_it.array_iterator != it.m_object->m_value.array->begin()));
230                 CHECK((it.m_it.array_iterator == it.m_object->m_value.array->end()));
231             }
232         }
233 
234         SECTION("pre-increment")
235         {
236             SECTION("null")
237             {
238                 json j(json::value_t::null);
239                 json::iterator it = j.begin();
240                 CHECK((it.m_it.primitive_iterator.m_it == 1));
241                 ++it;
242                 CHECK((it.m_it.primitive_iterator.m_it != 0 && it.m_it.primitive_iterator.m_it != 1));
243             }
244 
245             SECTION("number")
246             {
247                 json j(17);
248                 json::iterator it = j.begin();
249                 CHECK((it.m_it.primitive_iterator.m_it == 0));
250                 ++it;
251                 CHECK((it.m_it.primitive_iterator.m_it == 1));
252                 ++it;
253                 CHECK((it.m_it.primitive_iterator.m_it != 0 && it.m_it.primitive_iterator.m_it != 1));
254             }
255 
256             SECTION("object")
257             {
258                 json j({{"foo", "bar"}});
259                 json::iterator it = j.begin();
260                 CHECK((it.m_it.object_iterator == it.m_object->m_value.object->begin()));
261                 ++it;
262                 CHECK((it.m_it.object_iterator == it.m_object->m_value.object->end()));
263             }
264 
265             SECTION("array")
266             {
267                 json j({1, 2, 3, 4});
268                 json::iterator it = j.begin();
269                 CHECK((it.m_it.array_iterator == it.m_object->m_value.array->begin()));
270                 ++it;
271                 CHECK((it.m_it.array_iterator != it.m_object->m_value.array->begin()));
272                 CHECK((it.m_it.array_iterator != it.m_object->m_value.array->end()));
273                 ++it;
274                 CHECK((it.m_it.array_iterator != it.m_object->m_value.array->begin()));
275                 CHECK((it.m_it.array_iterator != it.m_object->m_value.array->end()));
276                 ++it;
277                 CHECK((it.m_it.array_iterator != it.m_object->m_value.array->begin()));
278                 CHECK((it.m_it.array_iterator != it.m_object->m_value.array->end()));
279                 ++it;
280                 CHECK((it.m_it.array_iterator != it.m_object->m_value.array->begin()));
281                 CHECK((it.m_it.array_iterator == it.m_object->m_value.array->end()));
282             }
283         }
284 
285         SECTION("post-decrement")
286         {
287             SECTION("null")
288             {
289                 json j(json::value_t::null);
290                 json::iterator it = j.end();
291                 CHECK((it.m_it.primitive_iterator.m_it == 1));
292             }
293 
294             SECTION("number")
295             {
296                 json j(17);
297                 json::iterator it = j.end();
298                 CHECK((it.m_it.primitive_iterator.m_it == 1));
299                 it--;
300                 CHECK((it.m_it.primitive_iterator.m_it == 0));
301                 it--;
302                 CHECK((it.m_it.primitive_iterator.m_it != 0 && it.m_it.primitive_iterator.m_it != 1));
303             }
304 
305             SECTION("object")
306             {
307                 json j({{"foo", "bar"}});
308                 json::iterator it = j.end();
309                 CHECK((it.m_it.object_iterator == it.m_object->m_value.object->end()));
310                 it--;
311                 CHECK((it.m_it.object_iterator == it.m_object->m_value.object->begin()));
312             }
313 
314             SECTION("array")
315             {
316                 json j({1, 2, 3, 4});
317                 json::iterator it = j.end();
318                 CHECK((it.m_it.array_iterator == it.m_object->m_value.array->end()));
319                 it--;
320                 CHECK((it.m_it.array_iterator != it.m_object->m_value.array->begin()));
321                 CHECK((it.m_it.array_iterator != it.m_object->m_value.array->end()));
322                 it--;
323                 CHECK((it.m_it.array_iterator != it.m_object->m_value.array->begin()));
324                 CHECK((it.m_it.array_iterator != it.m_object->m_value.array->end()));
325                 it--;
326                 CHECK((it.m_it.array_iterator != it.m_object->m_value.array->begin()));
327                 CHECK((it.m_it.array_iterator != it.m_object->m_value.array->end()));
328                 it--;
329                 CHECK((it.m_it.array_iterator == it.m_object->m_value.array->begin()));
330                 CHECK((it.m_it.array_iterator != it.m_object->m_value.array->end()));
331             }
332         }
333 
334         SECTION("pre-decrement")
335         {
336             SECTION("null")
337             {
338                 json j(json::value_t::null);
339                 json::iterator it = j.end();
340                 CHECK((it.m_it.primitive_iterator.m_it == 1));
341             }
342 
343             SECTION("number")
344             {
345                 json j(17);
346                 json::iterator it = j.end();
347                 CHECK((it.m_it.primitive_iterator.m_it == 1));
348                 --it;
349                 CHECK((it.m_it.primitive_iterator.m_it == 0));
350                 --it;
351                 CHECK((it.m_it.primitive_iterator.m_it != 0 && it.m_it.primitive_iterator.m_it != 1));
352             }
353 
354             SECTION("object")
355             {
356                 json j({{"foo", "bar"}});
357                 json::iterator it = j.end();
358                 CHECK((it.m_it.object_iterator == it.m_object->m_value.object->end()));
359                 --it;
360                 CHECK((it.m_it.object_iterator == it.m_object->m_value.object->begin()));
361             }
362 
363             SECTION("array")
364             {
365                 json j({1, 2, 3, 4});
366                 json::iterator it = j.end();
367                 CHECK((it.m_it.array_iterator == it.m_object->m_value.array->end()));
368                 --it;
369                 CHECK((it.m_it.array_iterator != it.m_object->m_value.array->begin()));
370                 CHECK((it.m_it.array_iterator != it.m_object->m_value.array->end()));
371                 --it;
372                 CHECK((it.m_it.array_iterator != it.m_object->m_value.array->begin()));
373                 CHECK((it.m_it.array_iterator != it.m_object->m_value.array->end()));
374                 --it;
375                 CHECK((it.m_it.array_iterator != it.m_object->m_value.array->begin()));
376                 CHECK((it.m_it.array_iterator != it.m_object->m_value.array->end()));
377                 --it;
378                 CHECK((it.m_it.array_iterator == it.m_object->m_value.array->begin()));
379                 CHECK((it.m_it.array_iterator != it.m_object->m_value.array->end()));
380             }
381         }
382     }
383     SECTION("equality-preserving")
384     {
385         SECTION("post-increment")
386         {
387             SECTION("primitive_iterator_t")
388             {
389                 using Iter = nlohmann::detail::primitive_iterator_t;
390                 CHECK(std::is_same < decltype(std::declval<Iter&>()++), Iter >::value);
391             }
392             SECTION("iter_impl")
393             {
394                 using Iter = nlohmann::detail::iter_impl<json>;
395                 CHECK(std::is_same < decltype(std::declval<Iter&>()++), Iter >::value);
396             }
397             SECTION("json_reverse_iterator")
398             {
399                 using Base = nlohmann::detail::iter_impl<json>;
400                 using Iter = nlohmann::detail::json_reverse_iterator<Base>;
401                 CHECK(std::is_same < decltype(std::declval<Iter&>()++), Iter >::value);
402             }
403         }
404         SECTION("post-decrement")
405         {
406             SECTION("primitive_iterator_t")
407             {
408                 using Iter = nlohmann::detail::primitive_iterator_t;
409                 CHECK(std::is_same < decltype(std::declval<Iter&>()--), Iter >::value);
410             }
411             SECTION("iter_impl")
412             {
413                 using Iter = nlohmann::detail::iter_impl<json>;
414                 CHECK(std::is_same < decltype(std::declval<Iter&>()--), Iter >::value );
415             }
416             SECTION("json_reverse_iterator")
417             {
418                 using Base = nlohmann::detail::iter_impl<json>;
419                 using Iter = nlohmann::detail::json_reverse_iterator<Base>;
420                 CHECK(std::is_same < decltype(std::declval<Iter&>()--), Iter >::value );
421             }
422         }
423     }
424     // prevent "accidental mutation of a temporary object"
425     SECTION("cert-dcl21-cpp")
426     {
427         using nlohmann::detail::is_detected;
428         SECTION("post-increment")
429         {
430             SECTION("primitive_iterator_t")
431             {
432                 using Iter = nlohmann::detail::primitive_iterator_t;
433                 CHECK_FALSE(is_detected<can_post_increment_temporary, Iter&>::value);
434             }
435             SECTION("iter_impl")
436             {
437                 using Iter = nlohmann::detail::iter_impl<json>;
438                 CHECK_FALSE(is_detected<can_post_increment_temporary, Iter&>::value);
439             }
440             SECTION("json_reverse_iterator")
441             {
442                 using Base = nlohmann::detail::iter_impl<json>;
443                 using Iter = nlohmann::detail::json_reverse_iterator<Base>;
444                 CHECK_FALSE(is_detected<can_post_increment_temporary, Iter&>::value);
445             }
446         }
447         SECTION("post-decrement")
448         {
449             SECTION("primitive_iterator_t")
450             {
451                 using Iter = nlohmann::detail::primitive_iterator_t;
452                 CHECK_FALSE(is_detected<can_post_decrement_temporary, Iter&>::value);
453             }
454             SECTION("iter_impl")
455             {
456                 using Iter = nlohmann::detail::iter_impl<json>;
457                 CHECK_FALSE(is_detected<can_post_decrement_temporary, Iter&>::value);
458             }
459             SECTION("json_reverse_iterator")
460             {
461                 using Base = nlohmann::detail::iter_impl<json>;
462                 using Iter = nlohmann::detail::json_reverse_iterator<Base>;
463                 CHECK_FALSE(is_detected<can_post_decrement_temporary, Iter&>::value);
464             }
465 
466         }
467     }
468 }
469