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