diff --git a/.travis.yml b/.travis.yml index b0cde48d..1ab50bfa 100644 --- a/.travis.yml +++ b/.travis.yml @@ -25,7 +25,7 @@ matrix: - touch src/json.hpp - make json_unit CXXFLAGS="-fprofile-arcs -ftest-coverage -std=c++11 -lstdc++" CXX=$COMPILER - test/json_unit "*" - - coveralls --exclude test/src/catch.hpp --exclude test/src/unit*.cpp --include src/json.hpp --gcov-options '\-lp' --gcov 'gcov-4.9' + - coveralls --exclude test/src/catch.hpp --exclude test/src/unit-algorithms.cpp --exclude test/src/unit-allocator.cpp --exclude test/src/unit-capacity.cpp --exclude test/src/unit-class_const_iterator.cpp --exclude test/src/unit-class_iterator.cpp --exclude test/src/unit-class_lexer.cpp --exclude test/src/unit-class_parser.cpp --exclude test/src/unit-comparison.cpp --exclude test/src/unit-concepts.cpp --exclude test/src/unit-constructor1.cpp --exclude test/src/unit-constructor2.cpp --exclude test/src/unit-convenience.cpp --exclude test/src/unit-conversions.cpp --exclude test/src/unit-deserialization.cpp --exclude test/src/unit-element_access1.cpp --exclude test/src/unit-element_access2.cpp --exclude test/src/unit-inspection.cpp --exclude test/src/unit-iterator_wrapper.cpp --exclude test/src/unit-iterators1.cpp --exclude test/src/unit-iterators2.cpp --exclude test/src/unit-json_patch.cpp --exclude test/src/unit-json_pointer.cpp --exclude test/src/unit-modifiers.cpp --exclude test/src/unit-pointer_access.cpp --exclude test/src/unit-readme.cpp --exclude test/src/unit-reference_access.cpp --exclude test/src/unit-regression.cpp --exclude test/src/unit-serialization.cpp --exclude test/src/unit-testsuites.cpp --exclude test/src/unit-unicode.cpp --include src/json.hpp --gcov-options '\-lp' --gcov 'gcov-4.9' env: COMPILER=g++-4.9 - os: linux diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index 696a7f3f..782d5b53 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -12,14 +12,17 @@ add_executable(${JSON_UNITTEST_TARGET_NAME} "src/unit-class_parser.cpp" "src/unit-comparison.cpp" "src/unit-concepts.cpp" - "src/unit-constructor.cpp" + "src/unit-constructor1.cpp" + "src/unit-constructor2.cpp" "src/unit-convenience.cpp" "src/unit-conversions.cpp" "src/unit-deserialization.cpp" - "src/unit-element_access.cpp" + "src/unit-element_access1.cpp" + "src/unit-element_access2.cpp" "src/unit-inspection.cpp" "src/unit-iterator_wrapper.cpp" - "src/unit-iterators.cpp" + "src/unit-iterators1.cpp" + "src/unit-iterators2.cpp" "src/unit-json_patch.cpp" "src/unit-json_pointer.cpp" "src/unit-modifiers.cpp" diff --git a/test/Makefile b/test/Makefile index 9edda2d2..7bc8274f 100644 --- a/test/Makefile +++ b/test/Makefile @@ -16,14 +16,17 @@ SOURCES = src/unit.cpp \ src/unit-class_parser.cpp \ src/unit-comparison.cpp \ src/unit-concepts.cpp \ - src/unit-constructor.cpp \ + src/unit-constructor1.cpp \ + src/unit-constructor2.cpp \ src/unit-convenience.cpp \ src/unit-conversions.cpp \ src/unit-deserialization.cpp \ - src/unit-element_access.cpp \ + src/unit-element_access1.cpp \ + src/unit-element_access2.cpp \ src/unit-inspection.cpp \ src/unit-iterator_wrapper.cpp \ - src/unit-iterators.cpp \ + src/unit-iterators1.cpp \ + src/unit-iterators2.cpp \ src/unit-json_patch.cpp \ src/unit-json_pointer.cpp \ src/unit-modifiers.cpp \ diff --git a/test/src/unit-constructor.cpp b/test/src/unit-constructor1.cpp similarity index 93% rename from test/src/unit-constructor.cpp rename to test/src/unit-constructor1.cpp index e4842a58..87728648 100644 --- a/test/src/unit-constructor.cpp +++ b/test/src/unit-constructor1.cpp @@ -1309,162 +1309,3 @@ TEST_CASE("constructors") } } } - -TEST_CASE("other constructors and destructor") -{ - SECTION("copy constructor") - { - SECTION("object") - { - json j {{"foo", 1}, {"bar", false}}; - json k(j); - CHECK(j == k); - } - - SECTION("array") - { - json j {"foo", 1, 42.23, false}; - json k(j); - CHECK(j == k); - } - - SECTION("null") - { - json j(nullptr); - json k(j); - CHECK(j == k); - } - - SECTION("boolean") - { - json j(true); - json k(j); - CHECK(j == k); - } - - SECTION("string") - { - json j("Hello world"); - json k(j); - CHECK(j == k); - } - - SECTION("number (integer)") - { - json j(42); - json k(j); - CHECK(j == k); - } - - SECTION("number (unsigned)") - { - json j(42u); - json k(j); - CHECK(j == k); - } - - SECTION("number (floating-point)") - { - json j(42.23); - json k(j); - CHECK(j == k); - } - } - - SECTION("move constructor") - { - json j {{"foo", "bar"}, {"baz", {1, 2, 3, 4}}, {"a", 42u}, {"b", 42.23}, {"c", nullptr}}; - CHECK(j.type() == json::value_t::object); - json k(std::move(j)); - CHECK(k.type() == json::value_t::object); - CHECK(j.type() == json::value_t::null); - } - - SECTION("copy assignment") - { - SECTION("object") - { - json j {{"foo", 1}, {"bar", false}}; - json k; - k = j; - CHECK(j == k); - } - - SECTION("array") - { - json j {"foo", 1, 42.23, false}; - json k; - k = j; - CHECK(j == k); - } - - SECTION("null") - { - json j(nullptr); - json k; - k = j; - CHECK(j == k); - } - - SECTION("boolean") - { - json j(true); - json k; - k = j; - CHECK(j == k); - } - - SECTION("string") - { - json j("Hello world"); - json k; - k = j; - CHECK(j == k); - } - - SECTION("number (integer)") - { - json j(42); - json k; - k = j; - CHECK(j == k); - } - - SECTION("number (unsigned)") - { - json j(42u); - json k; - k = j; - CHECK(j == k); - } - - SECTION("number (floating-point)") - { - json j(42.23); - json k; - k = j; - CHECK(j == k); - } - } - - SECTION("destructor") - { - SECTION("object") - { - auto j = new json {{"foo", 1}, {"bar", false}}; - delete j; - } - - SECTION("array") - { - auto j = new json {"foo", 1, 1u, false, 23.42}; - delete j; - } - - SECTION("string") - { - auto j = new json("Hello world"); - delete j; - } - } -} diff --git a/test/src/unit-constructor2.cpp b/test/src/unit-constructor2.cpp new file mode 100644 index 00000000..b5f1a5e3 --- /dev/null +++ b/test/src/unit-constructor2.cpp @@ -0,0 +1,191 @@ +/* + __ _____ _____ _____ + __| | __| | | | JSON for Modern C++ (test suite) +| | |__ | | | | | | version 2.0.2 +|_____|_____|_____|_|___| https://github.com/nlohmann/json + +Licensed under the MIT License . +Copyright (c) 2013-2016 Niels Lohmann . + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. +*/ + +#include "catch.hpp" + +#include "json.hpp" +using nlohmann::json; + +TEST_CASE("other constructors and destructor") +{ + SECTION("copy constructor") + { + SECTION("object") + { + json j {{"foo", 1}, {"bar", false}}; + json k(j); + CHECK(j == k); + } + + SECTION("array") + { + json j {"foo", 1, 42.23, false}; + json k(j); + CHECK(j == k); + } + + SECTION("null") + { + json j(nullptr); + json k(j); + CHECK(j == k); + } + + SECTION("boolean") + { + json j(true); + json k(j); + CHECK(j == k); + } + + SECTION("string") + { + json j("Hello world"); + json k(j); + CHECK(j == k); + } + + SECTION("number (integer)") + { + json j(42); + json k(j); + CHECK(j == k); + } + + SECTION("number (unsigned)") + { + json j(42u); + json k(j); + CHECK(j == k); + } + + SECTION("number (floating-point)") + { + json j(42.23); + json k(j); + CHECK(j == k); + } + } + + SECTION("move constructor") + { + json j {{"foo", "bar"}, {"baz", {1, 2, 3, 4}}, {"a", 42u}, {"b", 42.23}, {"c", nullptr}}; + CHECK(j.type() == json::value_t::object); + json k(std::move(j)); + CHECK(k.type() == json::value_t::object); + CHECK(j.type() == json::value_t::null); + } + + SECTION("copy assignment") + { + SECTION("object") + { + json j {{"foo", 1}, {"bar", false}}; + json k; + k = j; + CHECK(j == k); + } + + SECTION("array") + { + json j {"foo", 1, 42.23, false}; + json k; + k = j; + CHECK(j == k); + } + + SECTION("null") + { + json j(nullptr); + json k; + k = j; + CHECK(j == k); + } + + SECTION("boolean") + { + json j(true); + json k; + k = j; + CHECK(j == k); + } + + SECTION("string") + { + json j("Hello world"); + json k; + k = j; + CHECK(j == k); + } + + SECTION("number (integer)") + { + json j(42); + json k; + k = j; + CHECK(j == k); + } + + SECTION("number (unsigned)") + { + json j(42u); + json k; + k = j; + CHECK(j == k); + } + + SECTION("number (floating-point)") + { + json j(42.23); + json k; + k = j; + CHECK(j == k); + } + } + + SECTION("destructor") + { + SECTION("object") + { + auto j = new json {{"foo", 1}, {"bar", false}}; + delete j; + } + + SECTION("array") + { + auto j = new json {"foo", 1, 1u, false, 23.42}; + delete j; + } + + SECTION("string") + { + auto j = new json("Hello world"); + delete j; + } + } +} diff --git a/test/src/unit-element_access1.cpp b/test/src/unit-element_access1.cpp new file mode 100644 index 00000000..0e515a8e --- /dev/null +++ b/test/src/unit-element_access1.cpp @@ -0,0 +1,947 @@ +/* + __ _____ _____ _____ + __| | __| | | | JSON for Modern C++ (test suite) +| | |__ | | | | | | version 2.0.2 +|_____|_____|_____|_|___| https://github.com/nlohmann/json + +Licensed under the MIT License . +Copyright (c) 2013-2016 Niels Lohmann . + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. +*/ + +#include "catch.hpp" + +#include "json.hpp" +using nlohmann::json; + +TEST_CASE("element access 1") +{ + SECTION("array") + { + json j = {1, 1u, true, nullptr, "string", 42.23, json::object(), {1, 2, 3}}; + const json j_const = j; + + SECTION("access specified element with bounds checking") + { + SECTION("access within bounds") + { + CHECK(j.at(0) == json(1)); + CHECK(j.at(1) == json(1u)); + CHECK(j.at(2) == json(true)); + CHECK(j.at(3) == json(nullptr)); + CHECK(j.at(4) == json("string")); + CHECK(j.at(5) == json(42.23)); + CHECK(j.at(6) == json(json::object())); + CHECK(j.at(7) == json({1, 2, 3})); + + CHECK(j_const.at(0) == json(1)); + CHECK(j_const.at(1) == json(1u)); + CHECK(j_const.at(2) == json(true)); + CHECK(j_const.at(3) == json(nullptr)); + CHECK(j_const.at(4) == json("string")); + CHECK(j_const.at(5) == json(42.23)); + CHECK(j_const.at(6) == json(json::object())); + CHECK(j_const.at(7) == json({1, 2, 3})); + } + + SECTION("access outside bounds") + { + CHECK_THROWS_AS(j.at(8), std::out_of_range); + CHECK_THROWS_AS(j_const.at(8), std::out_of_range); + + CHECK_THROWS_WITH(j.at(8), "array index 8 is out of range"); + CHECK_THROWS_WITH(j_const.at(8), "array index 8 is out of range"); + } + + SECTION("access on non-array type") + { + SECTION("null") + { + json j_nonarray(json::value_t::null); + const json j_nonarray_const(j_nonarray); + CHECK_THROWS_AS(j_nonarray.at(0), std::domain_error); + CHECK_THROWS_AS(j_nonarray_const.at(0), std::domain_error); + + CHECK_THROWS_WITH(j_nonarray.at(0), "cannot use at() with null"); + CHECK_THROWS_WITH(j_nonarray_const.at(0), "cannot use at() with null"); + } + + SECTION("boolean") + { + json j_nonarray(json::value_t::boolean); + const json j_nonarray_const(j_nonarray); + CHECK_THROWS_AS(j_nonarray.at(0), std::domain_error); + CHECK_THROWS_AS(j_nonarray_const.at(0), std::domain_error); + + CHECK_THROWS_WITH(j_nonarray.at(0), "cannot use at() with boolean"); + CHECK_THROWS_WITH(j_nonarray_const.at(0), "cannot use at() with boolean"); + } + + SECTION("string") + { + json j_nonarray(json::value_t::string); + const json j_nonarray_const(j_nonarray); + CHECK_THROWS_AS(j_nonarray.at(0), std::domain_error); + CHECK_THROWS_AS(j_nonarray_const.at(0), std::domain_error); + + CHECK_THROWS_WITH(j_nonarray.at(0), "cannot use at() with string"); + CHECK_THROWS_WITH(j_nonarray_const.at(0), "cannot use at() with string"); + } + + SECTION("object") + { + json j_nonarray(json::value_t::object); + const json j_nonarray_const(j_nonarray); + CHECK_THROWS_AS(j_nonarray.at(0), std::domain_error); + CHECK_THROWS_AS(j_nonarray_const.at(0), std::domain_error); + + CHECK_THROWS_WITH(j_nonarray.at(0), "cannot use at() with object"); + CHECK_THROWS_WITH(j_nonarray_const.at(0), "cannot use at() with object"); + } + + SECTION("number (integer)") + { + json j_nonarray(json::value_t::number_integer); + const json j_nonarray_const(j_nonarray); + CHECK_THROWS_AS(j_nonarray.at(0), std::domain_error); + CHECK_THROWS_AS(j_nonarray_const.at(0), std::domain_error); + + CHECK_THROWS_WITH(j_nonarray.at(0), "cannot use at() with number"); + CHECK_THROWS_WITH(j_nonarray_const.at(0), "cannot use at() with number"); + } + + SECTION("number (unsigned)") + { + json j_nonarray(json::value_t::number_unsigned); + const json j_nonarray_const(j_nonarray); + CHECK_THROWS_AS(j_nonarray.at(0), std::domain_error); + CHECK_THROWS_AS(j_nonarray_const.at(0), std::domain_error); + + CHECK_THROWS_WITH(j_nonarray.at(0), "cannot use at() with number"); + CHECK_THROWS_WITH(j_nonarray_const.at(0), "cannot use at() with number"); + } + + SECTION("number (floating-point)") + { + json j_nonarray(json::value_t::number_float); + const json j_nonarray_const(j_nonarray); + CHECK_THROWS_AS(j_nonarray.at(0), std::domain_error); + CHECK_THROWS_AS(j_nonarray_const.at(0), std::domain_error); + + CHECK_THROWS_WITH(j_nonarray.at(0), "cannot use at() with number"); + CHECK_THROWS_WITH(j_nonarray_const.at(0), "cannot use at() with number"); + } + } + } + + SECTION("front and back") + { + CHECK(j.front() == json(1)); + CHECK(j_const.front() == json(1)); + CHECK(j.back() == json({1, 2, 3})); + CHECK(j_const.back() == json({1, 2, 3})); + } + + SECTION("access specified element") + { + SECTION("access within bounds") + { + CHECK(j[0] == json(1)); + CHECK(j[1] == json(1u)); + CHECK(j[2] == json(true)); + CHECK(j[3] == json(nullptr)); + CHECK(j[4] == json("string")); + CHECK(j[5] == json(42.23)); + CHECK(j[6] == json(json::object())); + CHECK(j[7] == json({1, 2, 3})); + + CHECK(j_const[0] == json(1)); + CHECK(j_const[1] == json(1u)); + CHECK(j_const[2] == json(true)); + CHECK(j_const[3] == json(nullptr)); + CHECK(j_const[4] == json("string")); + CHECK(j_const[5] == json(42.23)); + CHECK(j_const[6] == json(json::object())); + CHECK(j_const[7] == json({1, 2, 3})); + } + + SECTION("access on non-array type") + { + SECTION("null") + { + SECTION("standard tests") + { + json j_nonarray(json::value_t::null); + const json j_nonarray_const(j_nonarray); + CHECK_NOTHROW(j_nonarray[0]); + CHECK_THROWS_AS(j_nonarray_const[0], std::domain_error); + CHECK_THROWS_WITH(j_nonarray_const[0], "cannot use operator[] with null"); + } + + SECTION("implicit transformation to properly filled array") + { + json j_nonarray; + j_nonarray[3] = 42; + CHECK(j_nonarray == json({nullptr, nullptr, nullptr, 42})); + } + } + + SECTION("boolean") + { + json j_nonarray(json::value_t::boolean); + const json j_nonarray_const(j_nonarray); + CHECK_THROWS_AS(j_nonarray[0], std::domain_error); + CHECK_THROWS_AS(j_nonarray_const[0], std::domain_error); + CHECK_THROWS_WITH(j_nonarray[0], "cannot use operator[] with boolean"); + CHECK_THROWS_WITH(j_nonarray_const[0], "cannot use operator[] with boolean"); + } + + SECTION("string") + { + json j_nonarray(json::value_t::string); + const json j_nonarray_const(j_nonarray); + CHECK_THROWS_AS(j_nonarray[0], std::domain_error); + CHECK_THROWS_AS(j_nonarray_const[0], std::domain_error); + CHECK_THROWS_WITH(j_nonarray[0], "cannot use operator[] with string"); + CHECK_THROWS_WITH(j_nonarray_const[0], "cannot use operator[] with string"); + } + + SECTION("object") + { + json j_nonarray(json::value_t::object); + const json j_nonarray_const(j_nonarray); + CHECK_THROWS_AS(j_nonarray[0], std::domain_error); + CHECK_THROWS_AS(j_nonarray_const[0], std::domain_error); + CHECK_THROWS_WITH(j_nonarray[0], "cannot use operator[] with object"); + CHECK_THROWS_WITH(j_nonarray_const[0], "cannot use operator[] with object"); + } + + SECTION("number (integer)") + { + json j_nonarray(json::value_t::number_integer); + const json j_nonarray_const(j_nonarray); + CHECK_THROWS_AS(j_nonarray[0], std::domain_error); + CHECK_THROWS_AS(j_nonarray_const[0], std::domain_error); + CHECK_THROWS_WITH(j_nonarray[0], "cannot use operator[] with number"); + CHECK_THROWS_WITH(j_nonarray_const[0], "cannot use operator[] with number"); + } + + SECTION("number (unsigned)") + { + json j_nonarray(json::value_t::number_unsigned); + const json j_nonarray_const(j_nonarray); + CHECK_THROWS_AS(j_nonarray[0], std::domain_error); + CHECK_THROWS_AS(j_nonarray_const[0], std::domain_error); + CHECK_THROWS_WITH(j_nonarray[0], "cannot use operator[] with number"); + CHECK_THROWS_WITH(j_nonarray_const[0], "cannot use operator[] with number"); + } + + SECTION("number (floating-point)") + { + json j_nonarray(json::value_t::number_float); + const json j_nonarray_const(j_nonarray); + CHECK_THROWS_AS(j_nonarray[0], std::domain_error); + CHECK_THROWS_AS(j_nonarray_const[0], std::domain_error); + CHECK_THROWS_WITH(j_nonarray[0], "cannot use operator[] with number"); + CHECK_THROWS_WITH(j_nonarray_const[0], "cannot use operator[] with number"); + } + } + } + + SECTION("remove specified element") + { + SECTION("remove element by index") + { + { + json jarray = {1, 1u, true, nullptr, "string", 42.23, json::object(), {1, 2, 3}}; + jarray.erase(0); + CHECK(jarray == json({1u, true, nullptr, "string", 42.23, json::object(), {1, 2, 3}})); + } + { + json jarray = {1, 1u, true, nullptr, "string", 42.23, json::object(), {1, 2, 3}}; + jarray.erase(1); + CHECK(jarray == json({1, true, nullptr, "string", 42.23, json::object(), {1, 2, 3}})); + } + { + json jarray = {1, 1u, true, nullptr, "string", 42.23, json::object(), {1, 2, 3}}; + jarray.erase(2); + CHECK(jarray == json({1, 1u, nullptr, "string", 42.23, json::object(), {1, 2, 3}})); + } + { + json jarray = {1, 1u, true, nullptr, "string", 42.23, json::object(), {1, 2, 3}}; + jarray.erase(3); + CHECK(jarray == json({1, 1u, true, "string", 42.23, json::object(), {1, 2, 3}})); + } + { + json jarray = {1, 1u, true, nullptr, "string", 42.23, json::object(), {1, 2, 3}}; + jarray.erase(4); + CHECK(jarray == json({1, 1u, true, nullptr, 42.23, json::object(), {1, 2, 3}})); + } + { + json jarray = {1, 1u, true, nullptr, "string", 42.23, json::object(), {1, 2, 3}}; + jarray.erase(5); + CHECK(jarray == json({1, 1u, true, nullptr, "string", json::object(), {1, 2, 3}})); + } + { + json jarray = {1, 1u, true, nullptr, "string", 42.23, json::object(), {1, 2, 3}}; + jarray.erase(6); + CHECK(jarray == json({1, 1u, true, nullptr, "string", 42.23, {1, 2, 3}})); + } + { + json jarray = {1, 1u, true, nullptr, "string", 42.23, json::object(), {1, 2, 3}}; + jarray.erase(7); + CHECK(jarray == json({1, 1u, true, nullptr, "string", 42.23, json::object()})); + } + { + json jarray = {1, 1u, true, nullptr, "string", 42.23, json::object(), {1, 2, 3}}; + CHECK_THROWS_AS(jarray.erase(8), std::out_of_range); + CHECK_THROWS_WITH(jarray.erase(8), "array index 8 is out of range"); + } + } + + SECTION("remove element by iterator") + { + SECTION("erase(begin())") + { + { + json jarray = {1, 1u, true, nullptr, "string", 42.23, json::object(), {1, 2, 3}}; + json::iterator it2 = jarray.erase(jarray.begin()); + CHECK(jarray == json({1u, true, nullptr, "string", 42.23, json::object(), {1, 2, 3}})); + CHECK(*it2 == json(1u)); + } + { + json jarray = {1, 1u, true, nullptr, "string", 42.23, json::object(), {1, 2, 3}}; + json::const_iterator it2 = jarray.erase(jarray.cbegin()); + CHECK(jarray == json({1u, true, nullptr, "string", 42.23, json::object(), {1, 2, 3}})); + CHECK(*it2 == json(1u)); + } + } + + SECTION("erase(begin(), end())") + { + { + json jarray = {1, 1u, true, nullptr, "string", 42.23, json::object(), {1, 2, 3}}; + json::iterator it2 = jarray.erase(jarray.begin(), jarray.end()); + CHECK(jarray == json::array()); + CHECK(it2 == jarray.end()); + } + { + json jarray = {1, 1u, true, nullptr, "string", 42.23, json::object(), {1, 2, 3}}; + json::const_iterator it2 = jarray.erase(jarray.cbegin(), jarray.cend()); + CHECK(jarray == json::array()); + CHECK(it2 == jarray.cend()); + } + } + + SECTION("erase(begin(), begin())") + { + { + json jarray = {1, 1u, true, nullptr, "string", 42.23, json::object(), {1, 2, 3}}; + json::iterator it2 = jarray.erase(jarray.begin(), jarray.begin()); + CHECK(jarray == json({1, 1u, true, nullptr, "string", 42.23, json::object(), {1, 2, 3}})); + CHECK(*it2 == json(1)); + } + { + json jarray = {1, 1u, true, nullptr, "string", 42.23, json::object(), {1, 2, 3}}; + json::const_iterator it2 = jarray.erase(jarray.cbegin(), jarray.cbegin()); + CHECK(jarray == json({1, 1u, true, nullptr, "string", 42.23, json::object(), {1, 2, 3}})); + CHECK(*it2 == json(1)); + } + } + + SECTION("erase at offset") + { + { + json jarray = {1, 1u, true, nullptr, "string", 42.23, json::object(), {1, 2, 3}}; + json::iterator it = jarray.begin() + 4; + json::iterator it2 = jarray.erase(it); + CHECK(jarray == json({1, 1u, true, nullptr, 42.23, json::object(), {1, 2, 3}})); + CHECK(*it2 == json(42.23)); + } + { + json jarray = {1, 1u, true, nullptr, "string", 42.23, json::object(), {1, 2, 3}}; + json::const_iterator it = jarray.cbegin() + 4; + json::const_iterator it2 = jarray.erase(it); + CHECK(jarray == json({1, 1u, true, nullptr, 42.23, json::object(), {1, 2, 3}})); + CHECK(*it2 == json(42.23)); + } + } + + SECTION("erase subrange") + { + { + json jarray = {1, 1u, true, nullptr, "string", 42.23, json::object(), {1, 2, 3}}; + json::iterator it2 = jarray.erase(jarray.begin() + 3, jarray.begin() + 6); + CHECK(jarray == json({1, 1u, true, json::object(), {1, 2, 3}})); + CHECK(*it2 == json::object()); + } + { + json jarray = {1, 1u, true, nullptr, "string", 42.23, json::object(), {1, 2, 3}}; + json::const_iterator it2 = jarray.erase(jarray.cbegin() + 3, jarray.cbegin() + 6); + CHECK(jarray == json({1, 1u, true, json::object(), {1, 2, 3}})); + CHECK(*it2 == json::object()); + } + } + + SECTION("different arrays") + { + { + json jarray = {1, 1u, true, nullptr, "string", 42.23, json::object(), {1, 2, 3}}; + json jarray2 = {"foo", "bar"}; + CHECK_THROWS_AS(jarray.erase(jarray2.begin()), std::domain_error); + CHECK_THROWS_AS(jarray.erase(jarray.begin(), jarray2.end()), std::domain_error); + CHECK_THROWS_AS(jarray.erase(jarray2.begin(), jarray.end()), std::domain_error); + CHECK_THROWS_AS(jarray.erase(jarray2.begin(), jarray2.end()), std::domain_error); + + CHECK_THROWS_WITH(jarray.erase(jarray2.begin()), "iterator does not fit current value"); + CHECK_THROWS_WITH(jarray.erase(jarray.begin(), jarray2.end()), + "iterators do not fit current value"); + CHECK_THROWS_WITH(jarray.erase(jarray2.begin(), jarray.end()), + "iterators do not fit current value"); + CHECK_THROWS_WITH(jarray.erase(jarray2.begin(), jarray2.end()), + "iterators do not fit current value"); + } + { + json jarray = {1, 1u, true, nullptr, "string", 42.23, json::object(), {1, 2, 3}}; + json jarray2 = {"foo", "bar"}; + CHECK_THROWS_AS(jarray.erase(jarray2.cbegin()), std::domain_error); + CHECK_THROWS_AS(jarray.erase(jarray.cbegin(), jarray2.cend()), std::domain_error); + CHECK_THROWS_AS(jarray.erase(jarray2.cbegin(), jarray.cend()), std::domain_error); + CHECK_THROWS_AS(jarray.erase(jarray2.cbegin(), jarray2.cend()), std::domain_error); + + CHECK_THROWS_WITH(jarray.erase(jarray2.cbegin()), "iterator does not fit current value"); + CHECK_THROWS_WITH(jarray.erase(jarray.cbegin(), jarray2.cend()), + "iterators do not fit current value"); + CHECK_THROWS_WITH(jarray.erase(jarray2.cbegin(), jarray.cend()), + "iterators do not fit current value"); + CHECK_THROWS_WITH(jarray.erase(jarray2.cbegin(), jarray2.cend()), + "iterators do not fit current value"); + } + } + } + + SECTION("remove element by index in non-array type") + { + SECTION("null") + { + json j_nonobject(json::value_t::null); + CHECK_THROWS_AS(j_nonobject.erase(0), std::domain_error); + CHECK_THROWS_WITH(j_nonobject.erase(0), "cannot use erase() with null"); + } + + SECTION("boolean") + { + json j_nonobject(json::value_t::boolean); + CHECK_THROWS_AS(j_nonobject.erase(0), std::domain_error); + CHECK_THROWS_WITH(j_nonobject.erase(0), "cannot use erase() with boolean"); + } + + SECTION("string") + { + json j_nonobject(json::value_t::string); + CHECK_THROWS_AS(j_nonobject.erase(0), std::domain_error); + CHECK_THROWS_WITH(j_nonobject.erase(0), "cannot use erase() with string"); + } + + SECTION("object") + { + json j_nonobject(json::value_t::object); + CHECK_THROWS_AS(j_nonobject.erase(0), std::domain_error); + CHECK_THROWS_WITH(j_nonobject.erase(0), "cannot use erase() with object"); + } + + SECTION("number (integer)") + { + json j_nonobject(json::value_t::number_integer); + CHECK_THROWS_AS(j_nonobject.erase(0), std::domain_error); + CHECK_THROWS_WITH(j_nonobject.erase(0), "cannot use erase() with number"); + } + + SECTION("number (unsigned)") + { + json j_nonobject(json::value_t::number_unsigned); + CHECK_THROWS_AS(j_nonobject.erase(0), std::domain_error); + CHECK_THROWS_WITH(j_nonobject.erase(0), "cannot use erase() with number"); + } + + SECTION("number (floating-point)") + { + json j_nonobject(json::value_t::number_float); + CHECK_THROWS_AS(j_nonobject.erase(0), std::domain_error); + CHECK_THROWS_WITH(j_nonobject.erase(0), "cannot use erase() with number"); + } + } + } + } + + SECTION("other values") + { + SECTION("front and back") + { + SECTION("null") + { + { + json j; + CHECK_THROWS_AS(j.front(), std::out_of_range); + CHECK_THROWS_AS(j.back(), std::out_of_range); + CHECK_THROWS_WITH(j.front(), "cannot get value"); + CHECK_THROWS_WITH(j.back(), "cannot get value"); + } + { + const json j{}; + CHECK_THROWS_AS(j.front(), std::out_of_range); + CHECK_THROWS_AS(j.back(), std::out_of_range); + CHECK_THROWS_WITH(j.front(), "cannot get value"); + CHECK_THROWS_WITH(j.back(), "cannot get value"); + } + } + + SECTION("string") + { + { + json j = "foo"; + CHECK(j.front() == j); + CHECK(j.back() == j); + } + { + const json j = "bar"; + CHECK(j.front() == j); + CHECK(j.back() == j); + } + } + + SECTION("number (boolean)") + { + { + json j = false; + CHECK(j.front() == j); + CHECK(j.back() == j); + } + { + const json j = true; + CHECK(j.front() == j); + CHECK(j.back() == j); + } + } + + SECTION("number (integer)") + { + { + json j = 17; + CHECK(j.front() == j); + CHECK(j.back() == j); + } + { + const json j = 17; + CHECK(j.front() == j); + CHECK(j.back() == j); + } + } + + SECTION("number (unsigned)") + { + { + json j = 17u; + CHECK(j.front() == j); + CHECK(j.back() == j); + } + { + const json j = 17u; + CHECK(j.front() == j); + CHECK(j.back() == j); + } + } + + SECTION("number (floating point)") + { + { + json j = 23.42; + CHECK(j.front() == j); + CHECK(j.back() == j); + } + { + const json j = 23.42; + CHECK(j.front() == j); + CHECK(j.back() == j); + } + } + } + + SECTION("erase with one valid iterator") + { + SECTION("null") + { + { + json j; + CHECK_THROWS_AS(j.erase(j.begin()), std::domain_error); + CHECK_THROWS_WITH(j.erase(j.begin()), "cannot use erase() with null"); + } + { + json j; + CHECK_THROWS_AS(j.erase(j.cbegin()), std::domain_error); + CHECK_THROWS_WITH(j.erase(j.begin()), "cannot use erase() with null"); + } + } + + SECTION("string") + { + { + json j = "foo"; + json::iterator it = j.erase(j.begin()); + CHECK(j.type() == json::value_t::null); + CHECK(it == j.end()); + } + { + json j = "bar"; + json::const_iterator it = j.erase(j.cbegin()); + CHECK(j.type() == json::value_t::null); + CHECK(it == j.end()); + } + } + + SECTION("number (boolean)") + { + { + json j = false; + json::iterator it = j.erase(j.begin()); + CHECK(j.type() == json::value_t::null); + CHECK(it == j.end()); + } + { + json j = true; + json::const_iterator it = j.erase(j.cbegin()); + CHECK(j.type() == json::value_t::null); + CHECK(it == j.end()); + } + } + + SECTION("number (integer)") + { + { + json j = 17; + json::iterator it = j.erase(j.begin()); + CHECK(j.type() == json::value_t::null); + CHECK(it == j.end()); + } + { + json j = 17; + json::const_iterator it = j.erase(j.cbegin()); + CHECK(j.type() == json::value_t::null); + CHECK(it == j.end()); + } + } + + SECTION("number (unsigned)") + { + { + json j = 17u; + json::iterator it = j.erase(j.begin()); + CHECK(j.type() == json::value_t::null); + CHECK(it == j.end()); + } + { + json j = 17u; + json::const_iterator it = j.erase(j.cbegin()); + CHECK(j.type() == json::value_t::null); + CHECK(it == j.end()); + } + } + + SECTION("number (floating point)") + { + { + json j = 23.42; + json::iterator it = j.erase(j.begin()); + CHECK(j.type() == json::value_t::null); + CHECK(it == j.end()); + } + { + json j = 23.42; + json::const_iterator it = j.erase(j.cbegin()); + CHECK(j.type() == json::value_t::null); + CHECK(it == j.end()); + } + } + } + + SECTION("erase with one invalid iterator") + { + SECTION("string") + { + { + json j = "foo"; + CHECK_THROWS_AS(j.erase(j.end()), std::out_of_range); + CHECK_THROWS_WITH(j.erase(j.end()), "iterator out of range"); + } + { + json j = "bar"; + CHECK_THROWS_AS(j.erase(j.cend()), std::out_of_range); + CHECK_THROWS_WITH(j.erase(j.cend()), "iterator out of range"); + } + } + + SECTION("number (boolean)") + { + { + json j = false; + CHECK_THROWS_AS(j.erase(j.end()), std::out_of_range); + CHECK_THROWS_WITH(j.erase(j.end()), "iterator out of range"); + } + { + json j = true; + CHECK_THROWS_AS(j.erase(j.cend()), std::out_of_range); + CHECK_THROWS_WITH(j.erase(j.cend()), "iterator out of range"); + } + } + + SECTION("number (integer)") + { + { + json j = 17; + CHECK_THROWS_AS(j.erase(j.end()), std::out_of_range); + CHECK_THROWS_WITH(j.erase(j.end()), "iterator out of range"); + } + { + json j = 17; + CHECK_THROWS_AS(j.erase(j.cend()), std::out_of_range); + CHECK_THROWS_WITH(j.erase(j.cend()), "iterator out of range"); + } + } + + SECTION("number (unsigned)") + { + { + json j = 17u; + CHECK_THROWS_AS(j.erase(j.end()), std::out_of_range); + CHECK_THROWS_WITH(j.erase(j.end()), "iterator out of range"); + } + { + json j = 17u; + CHECK_THROWS_AS(j.erase(j.cend()), std::out_of_range); + CHECK_THROWS_WITH(j.erase(j.cend()), "iterator out of range"); + } + } + + SECTION("number (floating point)") + { + { + json j = 23.42; + CHECK_THROWS_AS(j.erase(j.end()), std::out_of_range); + CHECK_THROWS_WITH(j.erase(j.end()), "iterator out of range"); + } + { + json j = 23.42; + CHECK_THROWS_AS(j.erase(j.cend()), std::out_of_range); + CHECK_THROWS_WITH(j.erase(j.cend()), "iterator out of range"); + } + } + } + + SECTION("erase with two valid iterators") + { + SECTION("null") + { + { + json j; + CHECK_THROWS_AS(j.erase(j.begin(), j.end()), std::domain_error); + CHECK_THROWS_WITH(j.erase(j.begin(), j.end()), "cannot use erase() with null"); + } + { + json j; + CHECK_THROWS_AS(j.erase(j.cbegin(), j.cend()), std::domain_error); + CHECK_THROWS_WITH(j.erase(j.cbegin(), j.cend()), "cannot use erase() with null"); + } + } + + SECTION("string") + { + { + json j = "foo"; + json::iterator it = j.erase(j.begin(), j.end()); + CHECK(j.type() == json::value_t::null); + CHECK(it == j.end()); + } + { + json j = "bar"; + json::const_iterator it = j.erase(j.cbegin(), j.cend()); + CHECK(j.type() == json::value_t::null); + CHECK(it == j.end()); + } + } + + SECTION("number (boolean)") + { + { + json j = false; + json::iterator it = j.erase(j.begin(), j.end()); + CHECK(j.type() == json::value_t::null); + CHECK(it == j.end()); + } + { + json j = true; + json::const_iterator it = j.erase(j.cbegin(), j.cend()); + CHECK(j.type() == json::value_t::null); + CHECK(it == j.end()); + } + } + + SECTION("number (integer)") + { + { + json j = 17; + json::iterator it = j.erase(j.begin(), j.end()); + CHECK(j.type() == json::value_t::null); + CHECK(it == j.end()); + } + { + json j = 17; + json::const_iterator it = j.erase(j.cbegin(), j.cend()); + CHECK(j.type() == json::value_t::null); + CHECK(it == j.end()); + } + } + + SECTION("number (unsigned)") + { + { + json j = 17u; + json::iterator it = j.erase(j.begin(), j.end()); + CHECK(j.type() == json::value_t::null); + CHECK(it == j.end()); + } + { + json j = 17u; + json::const_iterator it = j.erase(j.cbegin(), j.cend()); + CHECK(j.type() == json::value_t::null); + CHECK(it == j.end()); + } + } + + SECTION("number (floating point)") + { + { + json j = 23.42; + json::iterator it = j.erase(j.begin(), j.end()); + CHECK(j.type() == json::value_t::null); + CHECK(it == j.end()); + } + { + json j = 23.42; + json::const_iterator it = j.erase(j.cbegin(), j.cend()); + CHECK(j.type() == json::value_t::null); + CHECK(it == j.end()); + } + } + } + + SECTION("erase with two invalid iterators") + { + SECTION("string") + { + { + json j = "foo"; + CHECK_THROWS_AS(j.erase(j.end(), j.end()), std::out_of_range); + CHECK_THROWS_AS(j.erase(j.begin(), j.begin()), std::out_of_range); + CHECK_THROWS_WITH(j.erase(j.end(), j.end()), "iterators out of range"); + CHECK_THROWS_WITH(j.erase(j.begin(), j.begin()), "iterators out of range"); + } + { + json j = "bar"; + CHECK_THROWS_AS(j.erase(j.cend(), j.cend()), std::out_of_range); + CHECK_THROWS_AS(j.erase(j.cbegin(), j.cbegin()), std::out_of_range); + CHECK_THROWS_WITH(j.erase(j.cend(), j.cend()), "iterators out of range"); + CHECK_THROWS_WITH(j.erase(j.cbegin(), j.cbegin()), "iterators out of range"); + } + } + + SECTION("number (boolean)") + { + { + json j = false; + CHECK_THROWS_AS(j.erase(j.end(), j.end()), std::out_of_range); + CHECK_THROWS_AS(j.erase(j.begin(), j.begin()), std::out_of_range); + CHECK_THROWS_WITH(j.erase(j.end(), j.end()), "iterators out of range"); + CHECK_THROWS_WITH(j.erase(j.begin(), j.begin()), "iterators out of range"); + } + { + json j = true; + CHECK_THROWS_AS(j.erase(j.cend(), j.cend()), std::out_of_range); + CHECK_THROWS_AS(j.erase(j.cbegin(), j.cbegin()), std::out_of_range); + CHECK_THROWS_WITH(j.erase(j.cend(), j.cend()), "iterators out of range"); + CHECK_THROWS_WITH(j.erase(j.cbegin(), j.cbegin()), "iterators out of range"); + } + } + + SECTION("number (integer)") + { + { + json j = 17; + CHECK_THROWS_AS(j.erase(j.end(), j.end()), std::out_of_range); + CHECK_THROWS_AS(j.erase(j.begin(), j.begin()), std::out_of_range); + CHECK_THROWS_WITH(j.erase(j.end(), j.end()), "iterators out of range"); + CHECK_THROWS_WITH(j.erase(j.begin(), j.begin()), "iterators out of range"); + } + { + json j = 17; + CHECK_THROWS_AS(j.erase(j.cend(), j.cend()), std::out_of_range); + CHECK_THROWS_AS(j.erase(j.cbegin(), j.cbegin()), std::out_of_range); + CHECK_THROWS_WITH(j.erase(j.cend(), j.cend()), "iterators out of range"); + CHECK_THROWS_WITH(j.erase(j.cbegin(), j.cbegin()), "iterators out of range"); + } + } + + SECTION("number (unsigned)") + { + { + json j = 17u; + CHECK_THROWS_AS(j.erase(j.end(), j.end()), std::out_of_range); + CHECK_THROWS_AS(j.erase(j.begin(), j.begin()), std::out_of_range); + CHECK_THROWS_WITH(j.erase(j.end(), j.end()), "iterators out of range"); + CHECK_THROWS_WITH(j.erase(j.begin(), j.begin()), "iterators out of range"); + } + { + json j = 17u; + CHECK_THROWS_AS(j.erase(j.cend(), j.cend()), std::out_of_range); + CHECK_THROWS_AS(j.erase(j.cbegin(), j.cbegin()), std::out_of_range); + CHECK_THROWS_WITH(j.erase(j.cend(), j.cend()), "iterators out of range"); + CHECK_THROWS_WITH(j.erase(j.cbegin(), j.cbegin()), "iterators out of range"); + } + } + + SECTION("number (floating point)") + { + { + json j = 23.42; + CHECK_THROWS_AS(j.erase(j.end(), j.end()), std::out_of_range); + CHECK_THROWS_AS(j.erase(j.begin(), j.begin()), std::out_of_range); + CHECK_THROWS_WITH(j.erase(j.end(), j.end()), "iterators out of range"); + CHECK_THROWS_WITH(j.erase(j.begin(), j.begin()), "iterators out of range"); + } + { + json j = 23.42; + CHECK_THROWS_AS(j.erase(j.cend(), j.cend()), std::out_of_range); + CHECK_THROWS_AS(j.erase(j.cbegin(), j.cbegin()), std::out_of_range); + CHECK_THROWS_WITH(j.erase(j.cend(), j.cend()), "iterators out of range"); + CHECK_THROWS_WITH(j.erase(j.cbegin(), j.cbegin()), "iterators out of range"); + } + } + } + } +} diff --git a/test/src/unit-element_access.cpp b/test/src/unit-element_access2.cpp similarity index 56% rename from test/src/unit-element_access.cpp rename to test/src/unit-element_access2.cpp index bd33e1e0..adadb726 100644 --- a/test/src/unit-element_access.cpp +++ b/test/src/unit-element_access2.cpp @@ -31,466 +31,8 @@ SOFTWARE. #include "json.hpp" using nlohmann::json; -TEST_CASE("element access") +TEST_CASE("element access 2") { - SECTION("array") - { - json j = {1, 1u, true, nullptr, "string", 42.23, json::object(), {1, 2, 3}}; - const json j_const = j; - - SECTION("access specified element with bounds checking") - { - SECTION("access within bounds") - { - CHECK(j.at(0) == json(1)); - CHECK(j.at(1) == json(1u)); - CHECK(j.at(2) == json(true)); - CHECK(j.at(3) == json(nullptr)); - CHECK(j.at(4) == json("string")); - CHECK(j.at(5) == json(42.23)); - CHECK(j.at(6) == json(json::object())); - CHECK(j.at(7) == json({1, 2, 3})); - - CHECK(j_const.at(0) == json(1)); - CHECK(j_const.at(1) == json(1u)); - CHECK(j_const.at(2) == json(true)); - CHECK(j_const.at(3) == json(nullptr)); - CHECK(j_const.at(4) == json("string")); - CHECK(j_const.at(5) == json(42.23)); - CHECK(j_const.at(6) == json(json::object())); - CHECK(j_const.at(7) == json({1, 2, 3})); - } - - SECTION("access outside bounds") - { - CHECK_THROWS_AS(j.at(8), std::out_of_range); - CHECK_THROWS_AS(j_const.at(8), std::out_of_range); - - CHECK_THROWS_WITH(j.at(8), "array index 8 is out of range"); - CHECK_THROWS_WITH(j_const.at(8), "array index 8 is out of range"); - } - - SECTION("access on non-array type") - { - SECTION("null") - { - json j_nonarray(json::value_t::null); - const json j_nonarray_const(j_nonarray); - CHECK_THROWS_AS(j_nonarray.at(0), std::domain_error); - CHECK_THROWS_AS(j_nonarray_const.at(0), std::domain_error); - - CHECK_THROWS_WITH(j_nonarray.at(0), "cannot use at() with null"); - CHECK_THROWS_WITH(j_nonarray_const.at(0), "cannot use at() with null"); - } - - SECTION("boolean") - { - json j_nonarray(json::value_t::boolean); - const json j_nonarray_const(j_nonarray); - CHECK_THROWS_AS(j_nonarray.at(0), std::domain_error); - CHECK_THROWS_AS(j_nonarray_const.at(0), std::domain_error); - - CHECK_THROWS_WITH(j_nonarray.at(0), "cannot use at() with boolean"); - CHECK_THROWS_WITH(j_nonarray_const.at(0), "cannot use at() with boolean"); - } - - SECTION("string") - { - json j_nonarray(json::value_t::string); - const json j_nonarray_const(j_nonarray); - CHECK_THROWS_AS(j_nonarray.at(0), std::domain_error); - CHECK_THROWS_AS(j_nonarray_const.at(0), std::domain_error); - - CHECK_THROWS_WITH(j_nonarray.at(0), "cannot use at() with string"); - CHECK_THROWS_WITH(j_nonarray_const.at(0), "cannot use at() with string"); - } - - SECTION("object") - { - json j_nonarray(json::value_t::object); - const json j_nonarray_const(j_nonarray); - CHECK_THROWS_AS(j_nonarray.at(0), std::domain_error); - CHECK_THROWS_AS(j_nonarray_const.at(0), std::domain_error); - - CHECK_THROWS_WITH(j_nonarray.at(0), "cannot use at() with object"); - CHECK_THROWS_WITH(j_nonarray_const.at(0), "cannot use at() with object"); - } - - SECTION("number (integer)") - { - json j_nonarray(json::value_t::number_integer); - const json j_nonarray_const(j_nonarray); - CHECK_THROWS_AS(j_nonarray.at(0), std::domain_error); - CHECK_THROWS_AS(j_nonarray_const.at(0), std::domain_error); - - CHECK_THROWS_WITH(j_nonarray.at(0), "cannot use at() with number"); - CHECK_THROWS_WITH(j_nonarray_const.at(0), "cannot use at() with number"); - } - - SECTION("number (unsigned)") - { - json j_nonarray(json::value_t::number_unsigned); - const json j_nonarray_const(j_nonarray); - CHECK_THROWS_AS(j_nonarray.at(0), std::domain_error); - CHECK_THROWS_AS(j_nonarray_const.at(0), std::domain_error); - - CHECK_THROWS_WITH(j_nonarray.at(0), "cannot use at() with number"); - CHECK_THROWS_WITH(j_nonarray_const.at(0), "cannot use at() with number"); - } - - SECTION("number (floating-point)") - { - json j_nonarray(json::value_t::number_float); - const json j_nonarray_const(j_nonarray); - CHECK_THROWS_AS(j_nonarray.at(0), std::domain_error); - CHECK_THROWS_AS(j_nonarray_const.at(0), std::domain_error); - - CHECK_THROWS_WITH(j_nonarray.at(0), "cannot use at() with number"); - CHECK_THROWS_WITH(j_nonarray_const.at(0), "cannot use at() with number"); - } - } - } - - SECTION("front and back") - { - CHECK(j.front() == json(1)); - CHECK(j_const.front() == json(1)); - CHECK(j.back() == json({1, 2, 3})); - CHECK(j_const.back() == json({1, 2, 3})); - } - - SECTION("access specified element") - { - SECTION("access within bounds") - { - CHECK(j[0] == json(1)); - CHECK(j[1] == json(1u)); - CHECK(j[2] == json(true)); - CHECK(j[3] == json(nullptr)); - CHECK(j[4] == json("string")); - CHECK(j[5] == json(42.23)); - CHECK(j[6] == json(json::object())); - CHECK(j[7] == json({1, 2, 3})); - - CHECK(j_const[0] == json(1)); - CHECK(j_const[1] == json(1u)); - CHECK(j_const[2] == json(true)); - CHECK(j_const[3] == json(nullptr)); - CHECK(j_const[4] == json("string")); - CHECK(j_const[5] == json(42.23)); - CHECK(j_const[6] == json(json::object())); - CHECK(j_const[7] == json({1, 2, 3})); - } - - SECTION("access on non-array type") - { - SECTION("null") - { - SECTION("standard tests") - { - json j_nonarray(json::value_t::null); - const json j_nonarray_const(j_nonarray); - CHECK_NOTHROW(j_nonarray[0]); - CHECK_THROWS_AS(j_nonarray_const[0], std::domain_error); - CHECK_THROWS_WITH(j_nonarray_const[0], "cannot use operator[] with null"); - } - - SECTION("implicit transformation to properly filled array") - { - json j_nonarray; - j_nonarray[3] = 42; - CHECK(j_nonarray == json({nullptr, nullptr, nullptr, 42})); - } - } - - SECTION("boolean") - { - json j_nonarray(json::value_t::boolean); - const json j_nonarray_const(j_nonarray); - CHECK_THROWS_AS(j_nonarray[0], std::domain_error); - CHECK_THROWS_AS(j_nonarray_const[0], std::domain_error); - CHECK_THROWS_WITH(j_nonarray[0], "cannot use operator[] with boolean"); - CHECK_THROWS_WITH(j_nonarray_const[0], "cannot use operator[] with boolean"); - } - - SECTION("string") - { - json j_nonarray(json::value_t::string); - const json j_nonarray_const(j_nonarray); - CHECK_THROWS_AS(j_nonarray[0], std::domain_error); - CHECK_THROWS_AS(j_nonarray_const[0], std::domain_error); - CHECK_THROWS_WITH(j_nonarray[0], "cannot use operator[] with string"); - CHECK_THROWS_WITH(j_nonarray_const[0], "cannot use operator[] with string"); - } - - SECTION("object") - { - json j_nonarray(json::value_t::object); - const json j_nonarray_const(j_nonarray); - CHECK_THROWS_AS(j_nonarray[0], std::domain_error); - CHECK_THROWS_AS(j_nonarray_const[0], std::domain_error); - CHECK_THROWS_WITH(j_nonarray[0], "cannot use operator[] with object"); - CHECK_THROWS_WITH(j_nonarray_const[0], "cannot use operator[] with object"); - } - - SECTION("number (integer)") - { - json j_nonarray(json::value_t::number_integer); - const json j_nonarray_const(j_nonarray); - CHECK_THROWS_AS(j_nonarray[0], std::domain_error); - CHECK_THROWS_AS(j_nonarray_const[0], std::domain_error); - CHECK_THROWS_WITH(j_nonarray[0], "cannot use operator[] with number"); - CHECK_THROWS_WITH(j_nonarray_const[0], "cannot use operator[] with number"); - } - - SECTION("number (unsigned)") - { - json j_nonarray(json::value_t::number_unsigned); - const json j_nonarray_const(j_nonarray); - CHECK_THROWS_AS(j_nonarray[0], std::domain_error); - CHECK_THROWS_AS(j_nonarray_const[0], std::domain_error); - CHECK_THROWS_WITH(j_nonarray[0], "cannot use operator[] with number"); - CHECK_THROWS_WITH(j_nonarray_const[0], "cannot use operator[] with number"); - } - - SECTION("number (floating-point)") - { - json j_nonarray(json::value_t::number_float); - const json j_nonarray_const(j_nonarray); - CHECK_THROWS_AS(j_nonarray[0], std::domain_error); - CHECK_THROWS_AS(j_nonarray_const[0], std::domain_error); - CHECK_THROWS_WITH(j_nonarray[0], "cannot use operator[] with number"); - CHECK_THROWS_WITH(j_nonarray_const[0], "cannot use operator[] with number"); - } - } - } - - SECTION("remove specified element") - { - SECTION("remove element by index") - { - { - json jarray = {1, 1u, true, nullptr, "string", 42.23, json::object(), {1, 2, 3}}; - jarray.erase(0); - CHECK(jarray == json({1u, true, nullptr, "string", 42.23, json::object(), {1, 2, 3}})); - } - { - json jarray = {1, 1u, true, nullptr, "string", 42.23, json::object(), {1, 2, 3}}; - jarray.erase(1); - CHECK(jarray == json({1, true, nullptr, "string", 42.23, json::object(), {1, 2, 3}})); - } - { - json jarray = {1, 1u, true, nullptr, "string", 42.23, json::object(), {1, 2, 3}}; - jarray.erase(2); - CHECK(jarray == json({1, 1u, nullptr, "string", 42.23, json::object(), {1, 2, 3}})); - } - { - json jarray = {1, 1u, true, nullptr, "string", 42.23, json::object(), {1, 2, 3}}; - jarray.erase(3); - CHECK(jarray == json({1, 1u, true, "string", 42.23, json::object(), {1, 2, 3}})); - } - { - json jarray = {1, 1u, true, nullptr, "string", 42.23, json::object(), {1, 2, 3}}; - jarray.erase(4); - CHECK(jarray == json({1, 1u, true, nullptr, 42.23, json::object(), {1, 2, 3}})); - } - { - json jarray = {1, 1u, true, nullptr, "string", 42.23, json::object(), {1, 2, 3}}; - jarray.erase(5); - CHECK(jarray == json({1, 1u, true, nullptr, "string", json::object(), {1, 2, 3}})); - } - { - json jarray = {1, 1u, true, nullptr, "string", 42.23, json::object(), {1, 2, 3}}; - jarray.erase(6); - CHECK(jarray == json({1, 1u, true, nullptr, "string", 42.23, {1, 2, 3}})); - } - { - json jarray = {1, 1u, true, nullptr, "string", 42.23, json::object(), {1, 2, 3}}; - jarray.erase(7); - CHECK(jarray == json({1, 1u, true, nullptr, "string", 42.23, json::object()})); - } - { - json jarray = {1, 1u, true, nullptr, "string", 42.23, json::object(), {1, 2, 3}}; - CHECK_THROWS_AS(jarray.erase(8), std::out_of_range); - CHECK_THROWS_WITH(jarray.erase(8), "array index 8 is out of range"); - } - } - - SECTION("remove element by iterator") - { - SECTION("erase(begin())") - { - { - json jarray = {1, 1u, true, nullptr, "string", 42.23, json::object(), {1, 2, 3}}; - json::iterator it2 = jarray.erase(jarray.begin()); - CHECK(jarray == json({1u, true, nullptr, "string", 42.23, json::object(), {1, 2, 3}})); - CHECK(*it2 == json(1u)); - } - { - json jarray = {1, 1u, true, nullptr, "string", 42.23, json::object(), {1, 2, 3}}; - json::const_iterator it2 = jarray.erase(jarray.cbegin()); - CHECK(jarray == json({1u, true, nullptr, "string", 42.23, json::object(), {1, 2, 3}})); - CHECK(*it2 == json(1u)); - } - } - - SECTION("erase(begin(), end())") - { - { - json jarray = {1, 1u, true, nullptr, "string", 42.23, json::object(), {1, 2, 3}}; - json::iterator it2 = jarray.erase(jarray.begin(), jarray.end()); - CHECK(jarray == json::array()); - CHECK(it2 == jarray.end()); - } - { - json jarray = {1, 1u, true, nullptr, "string", 42.23, json::object(), {1, 2, 3}}; - json::const_iterator it2 = jarray.erase(jarray.cbegin(), jarray.cend()); - CHECK(jarray == json::array()); - CHECK(it2 == jarray.cend()); - } - } - - SECTION("erase(begin(), begin())") - { - { - json jarray = {1, 1u, true, nullptr, "string", 42.23, json::object(), {1, 2, 3}}; - json::iterator it2 = jarray.erase(jarray.begin(), jarray.begin()); - CHECK(jarray == json({1, 1u, true, nullptr, "string", 42.23, json::object(), {1, 2, 3}})); - CHECK(*it2 == json(1)); - } - { - json jarray = {1, 1u, true, nullptr, "string", 42.23, json::object(), {1, 2, 3}}; - json::const_iterator it2 = jarray.erase(jarray.cbegin(), jarray.cbegin()); - CHECK(jarray == json({1, 1u, true, nullptr, "string", 42.23, json::object(), {1, 2, 3}})); - CHECK(*it2 == json(1)); - } - } - - SECTION("erase at offset") - { - { - json jarray = {1, 1u, true, nullptr, "string", 42.23, json::object(), {1, 2, 3}}; - json::iterator it = jarray.begin() + 4; - json::iterator it2 = jarray.erase(it); - CHECK(jarray == json({1, 1u, true, nullptr, 42.23, json::object(), {1, 2, 3}})); - CHECK(*it2 == json(42.23)); - } - { - json jarray = {1, 1u, true, nullptr, "string", 42.23, json::object(), {1, 2, 3}}; - json::const_iterator it = jarray.cbegin() + 4; - json::const_iterator it2 = jarray.erase(it); - CHECK(jarray == json({1, 1u, true, nullptr, 42.23, json::object(), {1, 2, 3}})); - CHECK(*it2 == json(42.23)); - } - } - - SECTION("erase subrange") - { - { - json jarray = {1, 1u, true, nullptr, "string", 42.23, json::object(), {1, 2, 3}}; - json::iterator it2 = jarray.erase(jarray.begin() + 3, jarray.begin() + 6); - CHECK(jarray == json({1, 1u, true, json::object(), {1, 2, 3}})); - CHECK(*it2 == json::object()); - } - { - json jarray = {1, 1u, true, nullptr, "string", 42.23, json::object(), {1, 2, 3}}; - json::const_iterator it2 = jarray.erase(jarray.cbegin() + 3, jarray.cbegin() + 6); - CHECK(jarray == json({1, 1u, true, json::object(), {1, 2, 3}})); - CHECK(*it2 == json::object()); - } - } - - SECTION("different arrays") - { - { - json jarray = {1, 1u, true, nullptr, "string", 42.23, json::object(), {1, 2, 3}}; - json jarray2 = {"foo", "bar"}; - CHECK_THROWS_AS(jarray.erase(jarray2.begin()), std::domain_error); - CHECK_THROWS_AS(jarray.erase(jarray.begin(), jarray2.end()), std::domain_error); - CHECK_THROWS_AS(jarray.erase(jarray2.begin(), jarray.end()), std::domain_error); - CHECK_THROWS_AS(jarray.erase(jarray2.begin(), jarray2.end()), std::domain_error); - - CHECK_THROWS_WITH(jarray.erase(jarray2.begin()), "iterator does not fit current value"); - CHECK_THROWS_WITH(jarray.erase(jarray.begin(), jarray2.end()), - "iterators do not fit current value"); - CHECK_THROWS_WITH(jarray.erase(jarray2.begin(), jarray.end()), - "iterators do not fit current value"); - CHECK_THROWS_WITH(jarray.erase(jarray2.begin(), jarray2.end()), - "iterators do not fit current value"); - } - { - json jarray = {1, 1u, true, nullptr, "string", 42.23, json::object(), {1, 2, 3}}; - json jarray2 = {"foo", "bar"}; - CHECK_THROWS_AS(jarray.erase(jarray2.cbegin()), std::domain_error); - CHECK_THROWS_AS(jarray.erase(jarray.cbegin(), jarray2.cend()), std::domain_error); - CHECK_THROWS_AS(jarray.erase(jarray2.cbegin(), jarray.cend()), std::domain_error); - CHECK_THROWS_AS(jarray.erase(jarray2.cbegin(), jarray2.cend()), std::domain_error); - - CHECK_THROWS_WITH(jarray.erase(jarray2.cbegin()), "iterator does not fit current value"); - CHECK_THROWS_WITH(jarray.erase(jarray.cbegin(), jarray2.cend()), - "iterators do not fit current value"); - CHECK_THROWS_WITH(jarray.erase(jarray2.cbegin(), jarray.cend()), - "iterators do not fit current value"); - CHECK_THROWS_WITH(jarray.erase(jarray2.cbegin(), jarray2.cend()), - "iterators do not fit current value"); - } - } - } - - SECTION("remove element by index in non-array type") - { - SECTION("null") - { - json j_nonobject(json::value_t::null); - CHECK_THROWS_AS(j_nonobject.erase(0), std::domain_error); - CHECK_THROWS_WITH(j_nonobject.erase(0), "cannot use erase() with null"); - } - - SECTION("boolean") - { - json j_nonobject(json::value_t::boolean); - CHECK_THROWS_AS(j_nonobject.erase(0), std::domain_error); - CHECK_THROWS_WITH(j_nonobject.erase(0), "cannot use erase() with boolean"); - } - - SECTION("string") - { - json j_nonobject(json::value_t::string); - CHECK_THROWS_AS(j_nonobject.erase(0), std::domain_error); - CHECK_THROWS_WITH(j_nonobject.erase(0), "cannot use erase() with string"); - } - - SECTION("object") - { - json j_nonobject(json::value_t::object); - CHECK_THROWS_AS(j_nonobject.erase(0), std::domain_error); - CHECK_THROWS_WITH(j_nonobject.erase(0), "cannot use erase() with object"); - } - - SECTION("number (integer)") - { - json j_nonobject(json::value_t::number_integer); - CHECK_THROWS_AS(j_nonobject.erase(0), std::domain_error); - CHECK_THROWS_WITH(j_nonobject.erase(0), "cannot use erase() with number"); - } - - SECTION("number (unsigned)") - { - json j_nonobject(json::value_t::number_unsigned); - CHECK_THROWS_AS(j_nonobject.erase(0), std::domain_error); - CHECK_THROWS_WITH(j_nonobject.erase(0), "cannot use erase() with number"); - } - - SECTION("number (floating-point)") - { - json j_nonobject(json::value_t::number_float); - CHECK_THROWS_AS(j_nonobject.erase(0), std::domain_error); - CHECK_THROWS_WITH(j_nonobject.erase(0), "cannot use erase() with number"); - } - } - } - } - SECTION("object") { json j = {{"integer", 1}, {"unsigned", 1u}, {"floating", 42.23}, {"null", nullptr}, {"string", "hello world"}, {"boolean", true}, {"object", json::object()}, {"array", {1, 2, 3}}}; @@ -1414,458 +956,4 @@ TEST_CASE("element access") } } } - - SECTION("other values") - { - SECTION("front and back") - { - SECTION("null") - { - { - json j; - CHECK_THROWS_AS(j.front(), std::out_of_range); - CHECK_THROWS_AS(j.back(), std::out_of_range); - CHECK_THROWS_WITH(j.front(), "cannot get value"); - CHECK_THROWS_WITH(j.back(), "cannot get value"); - } - { - const json j{}; - CHECK_THROWS_AS(j.front(), std::out_of_range); - CHECK_THROWS_AS(j.back(), std::out_of_range); - CHECK_THROWS_WITH(j.front(), "cannot get value"); - CHECK_THROWS_WITH(j.back(), "cannot get value"); - } - } - - SECTION("string") - { - { - json j = "foo"; - CHECK(j.front() == j); - CHECK(j.back() == j); - } - { - const json j = "bar"; - CHECK(j.front() == j); - CHECK(j.back() == j); - } - } - - SECTION("number (boolean)") - { - { - json j = false; - CHECK(j.front() == j); - CHECK(j.back() == j); - } - { - const json j = true; - CHECK(j.front() == j); - CHECK(j.back() == j); - } - } - - SECTION("number (integer)") - { - { - json j = 17; - CHECK(j.front() == j); - CHECK(j.back() == j); - } - { - const json j = 17; - CHECK(j.front() == j); - CHECK(j.back() == j); - } - } - - SECTION("number (unsigned)") - { - { - json j = 17u; - CHECK(j.front() == j); - CHECK(j.back() == j); - } - { - const json j = 17u; - CHECK(j.front() == j); - CHECK(j.back() == j); - } - } - - SECTION("number (floating point)") - { - { - json j = 23.42; - CHECK(j.front() == j); - CHECK(j.back() == j); - } - { - const json j = 23.42; - CHECK(j.front() == j); - CHECK(j.back() == j); - } - } - } - - SECTION("erase with one valid iterator") - { - SECTION("null") - { - { - json j; - CHECK_THROWS_AS(j.erase(j.begin()), std::domain_error); - CHECK_THROWS_WITH(j.erase(j.begin()), "cannot use erase() with null"); - } - { - json j; - CHECK_THROWS_AS(j.erase(j.cbegin()), std::domain_error); - CHECK_THROWS_WITH(j.erase(j.begin()), "cannot use erase() with null"); - } - } - - SECTION("string") - { - { - json j = "foo"; - json::iterator it = j.erase(j.begin()); - CHECK(j.type() == json::value_t::null); - CHECK(it == j.end()); - } - { - json j = "bar"; - json::const_iterator it = j.erase(j.cbegin()); - CHECK(j.type() == json::value_t::null); - CHECK(it == j.end()); - } - } - - SECTION("number (boolean)") - { - { - json j = false; - json::iterator it = j.erase(j.begin()); - CHECK(j.type() == json::value_t::null); - CHECK(it == j.end()); - } - { - json j = true; - json::const_iterator it = j.erase(j.cbegin()); - CHECK(j.type() == json::value_t::null); - CHECK(it == j.end()); - } - } - - SECTION("number (integer)") - { - { - json j = 17; - json::iterator it = j.erase(j.begin()); - CHECK(j.type() == json::value_t::null); - CHECK(it == j.end()); - } - { - json j = 17; - json::const_iterator it = j.erase(j.cbegin()); - CHECK(j.type() == json::value_t::null); - CHECK(it == j.end()); - } - } - - SECTION("number (unsigned)") - { - { - json j = 17u; - json::iterator it = j.erase(j.begin()); - CHECK(j.type() == json::value_t::null); - CHECK(it == j.end()); - } - { - json j = 17u; - json::const_iterator it = j.erase(j.cbegin()); - CHECK(j.type() == json::value_t::null); - CHECK(it == j.end()); - } - } - - SECTION("number (floating point)") - { - { - json j = 23.42; - json::iterator it = j.erase(j.begin()); - CHECK(j.type() == json::value_t::null); - CHECK(it == j.end()); - } - { - json j = 23.42; - json::const_iterator it = j.erase(j.cbegin()); - CHECK(j.type() == json::value_t::null); - CHECK(it == j.end()); - } - } - } - - SECTION("erase with one invalid iterator") - { - SECTION("string") - { - { - json j = "foo"; - CHECK_THROWS_AS(j.erase(j.end()), std::out_of_range); - CHECK_THROWS_WITH(j.erase(j.end()), "iterator out of range"); - } - { - json j = "bar"; - CHECK_THROWS_AS(j.erase(j.cend()), std::out_of_range); - CHECK_THROWS_WITH(j.erase(j.cend()), "iterator out of range"); - } - } - - SECTION("number (boolean)") - { - { - json j = false; - CHECK_THROWS_AS(j.erase(j.end()), std::out_of_range); - CHECK_THROWS_WITH(j.erase(j.end()), "iterator out of range"); - } - { - json j = true; - CHECK_THROWS_AS(j.erase(j.cend()), std::out_of_range); - CHECK_THROWS_WITH(j.erase(j.cend()), "iterator out of range"); - } - } - - SECTION("number (integer)") - { - { - json j = 17; - CHECK_THROWS_AS(j.erase(j.end()), std::out_of_range); - CHECK_THROWS_WITH(j.erase(j.end()), "iterator out of range"); - } - { - json j = 17; - CHECK_THROWS_AS(j.erase(j.cend()), std::out_of_range); - CHECK_THROWS_WITH(j.erase(j.cend()), "iterator out of range"); - } - } - - SECTION("number (unsigned)") - { - { - json j = 17u; - CHECK_THROWS_AS(j.erase(j.end()), std::out_of_range); - CHECK_THROWS_WITH(j.erase(j.end()), "iterator out of range"); - } - { - json j = 17u; - CHECK_THROWS_AS(j.erase(j.cend()), std::out_of_range); - CHECK_THROWS_WITH(j.erase(j.cend()), "iterator out of range"); - } - } - - SECTION("number (floating point)") - { - { - json j = 23.42; - CHECK_THROWS_AS(j.erase(j.end()), std::out_of_range); - CHECK_THROWS_WITH(j.erase(j.end()), "iterator out of range"); - } - { - json j = 23.42; - CHECK_THROWS_AS(j.erase(j.cend()), std::out_of_range); - CHECK_THROWS_WITH(j.erase(j.cend()), "iterator out of range"); - } - } - } - - SECTION("erase with two valid iterators") - { - SECTION("null") - { - { - json j; - CHECK_THROWS_AS(j.erase(j.begin(), j.end()), std::domain_error); - CHECK_THROWS_WITH(j.erase(j.begin(), j.end()), "cannot use erase() with null"); - } - { - json j; - CHECK_THROWS_AS(j.erase(j.cbegin(), j.cend()), std::domain_error); - CHECK_THROWS_WITH(j.erase(j.cbegin(), j.cend()), "cannot use erase() with null"); - } - } - - SECTION("string") - { - { - json j = "foo"; - json::iterator it = j.erase(j.begin(), j.end()); - CHECK(j.type() == json::value_t::null); - CHECK(it == j.end()); - } - { - json j = "bar"; - json::const_iterator it = j.erase(j.cbegin(), j.cend()); - CHECK(j.type() == json::value_t::null); - CHECK(it == j.end()); - } - } - - SECTION("number (boolean)") - { - { - json j = false; - json::iterator it = j.erase(j.begin(), j.end()); - CHECK(j.type() == json::value_t::null); - CHECK(it == j.end()); - } - { - json j = true; - json::const_iterator it = j.erase(j.cbegin(), j.cend()); - CHECK(j.type() == json::value_t::null); - CHECK(it == j.end()); - } - } - - SECTION("number (integer)") - { - { - json j = 17; - json::iterator it = j.erase(j.begin(), j.end()); - CHECK(j.type() == json::value_t::null); - CHECK(it == j.end()); - } - { - json j = 17; - json::const_iterator it = j.erase(j.cbegin(), j.cend()); - CHECK(j.type() == json::value_t::null); - CHECK(it == j.end()); - } - } - - SECTION("number (unsigned)") - { - { - json j = 17u; - json::iterator it = j.erase(j.begin(), j.end()); - CHECK(j.type() == json::value_t::null); - CHECK(it == j.end()); - } - { - json j = 17u; - json::const_iterator it = j.erase(j.cbegin(), j.cend()); - CHECK(j.type() == json::value_t::null); - CHECK(it == j.end()); - } - } - - SECTION("number (floating point)") - { - { - json j = 23.42; - json::iterator it = j.erase(j.begin(), j.end()); - CHECK(j.type() == json::value_t::null); - CHECK(it == j.end()); - } - { - json j = 23.42; - json::const_iterator it = j.erase(j.cbegin(), j.cend()); - CHECK(j.type() == json::value_t::null); - CHECK(it == j.end()); - } - } - } - - SECTION("erase with two invalid iterators") - { - SECTION("string") - { - { - json j = "foo"; - CHECK_THROWS_AS(j.erase(j.end(), j.end()), std::out_of_range); - CHECK_THROWS_AS(j.erase(j.begin(), j.begin()), std::out_of_range); - CHECK_THROWS_WITH(j.erase(j.end(), j.end()), "iterators out of range"); - CHECK_THROWS_WITH(j.erase(j.begin(), j.begin()), "iterators out of range"); - } - { - json j = "bar"; - CHECK_THROWS_AS(j.erase(j.cend(), j.cend()), std::out_of_range); - CHECK_THROWS_AS(j.erase(j.cbegin(), j.cbegin()), std::out_of_range); - CHECK_THROWS_WITH(j.erase(j.cend(), j.cend()), "iterators out of range"); - CHECK_THROWS_WITH(j.erase(j.cbegin(), j.cbegin()), "iterators out of range"); - } - } - - SECTION("number (boolean)") - { - { - json j = false; - CHECK_THROWS_AS(j.erase(j.end(), j.end()), std::out_of_range); - CHECK_THROWS_AS(j.erase(j.begin(), j.begin()), std::out_of_range); - CHECK_THROWS_WITH(j.erase(j.end(), j.end()), "iterators out of range"); - CHECK_THROWS_WITH(j.erase(j.begin(), j.begin()), "iterators out of range"); - } - { - json j = true; - CHECK_THROWS_AS(j.erase(j.cend(), j.cend()), std::out_of_range); - CHECK_THROWS_AS(j.erase(j.cbegin(), j.cbegin()), std::out_of_range); - CHECK_THROWS_WITH(j.erase(j.cend(), j.cend()), "iterators out of range"); - CHECK_THROWS_WITH(j.erase(j.cbegin(), j.cbegin()), "iterators out of range"); - } - } - - SECTION("number (integer)") - { - { - json j = 17; - CHECK_THROWS_AS(j.erase(j.end(), j.end()), std::out_of_range); - CHECK_THROWS_AS(j.erase(j.begin(), j.begin()), std::out_of_range); - CHECK_THROWS_WITH(j.erase(j.end(), j.end()), "iterators out of range"); - CHECK_THROWS_WITH(j.erase(j.begin(), j.begin()), "iterators out of range"); - } - { - json j = 17; - CHECK_THROWS_AS(j.erase(j.cend(), j.cend()), std::out_of_range); - CHECK_THROWS_AS(j.erase(j.cbegin(), j.cbegin()), std::out_of_range); - CHECK_THROWS_WITH(j.erase(j.cend(), j.cend()), "iterators out of range"); - CHECK_THROWS_WITH(j.erase(j.cbegin(), j.cbegin()), "iterators out of range"); - } - } - - SECTION("number (unsigned)") - { - { - json j = 17u; - CHECK_THROWS_AS(j.erase(j.end(), j.end()), std::out_of_range); - CHECK_THROWS_AS(j.erase(j.begin(), j.begin()), std::out_of_range); - CHECK_THROWS_WITH(j.erase(j.end(), j.end()), "iterators out of range"); - CHECK_THROWS_WITH(j.erase(j.begin(), j.begin()), "iterators out of range"); - } - { - json j = 17u; - CHECK_THROWS_AS(j.erase(j.cend(), j.cend()), std::out_of_range); - CHECK_THROWS_AS(j.erase(j.cbegin(), j.cbegin()), std::out_of_range); - CHECK_THROWS_WITH(j.erase(j.cend(), j.cend()), "iterators out of range"); - CHECK_THROWS_WITH(j.erase(j.cbegin(), j.cbegin()), "iterators out of range"); - } - } - - SECTION("number (floating point)") - { - { - json j = 23.42; - CHECK_THROWS_AS(j.erase(j.end(), j.end()), std::out_of_range); - CHECK_THROWS_AS(j.erase(j.begin(), j.begin()), std::out_of_range); - CHECK_THROWS_WITH(j.erase(j.end(), j.end()), "iterators out of range"); - CHECK_THROWS_WITH(j.erase(j.begin(), j.begin()), "iterators out of range"); - } - { - json j = 23.42; - CHECK_THROWS_AS(j.erase(j.cend(), j.cend()), std::out_of_range); - CHECK_THROWS_AS(j.erase(j.cbegin(), j.cbegin()), std::out_of_range); - CHECK_THROWS_WITH(j.erase(j.cend(), j.cend()), "iterators out of range"); - CHECK_THROWS_WITH(j.erase(j.cbegin(), j.cbegin()), "iterators out of range"); - } - } - } - } } diff --git a/test/src/unit-iterators.cpp b/test/src/unit-iterators1.cpp similarity index 55% rename from test/src/unit-iterators.cpp rename to test/src/unit-iterators1.cpp index 06dcb6aa..f8b4e6bd 100644 --- a/test/src/unit-iterators.cpp +++ b/test/src/unit-iterators1.cpp @@ -32,7 +32,7 @@ SOFTWARE. #include "json.hpp" using nlohmann::json; -TEST_CASE("iterators") +TEST_CASE("iterators 1") { SECTION("basic behavior") { @@ -1511,842 +1511,4 @@ TEST_CASE("iterators") } } } - - SECTION("iterator comparisons") - { - json j_values = {nullptr, true, 42, 42u, 23.23, {{"one", 1}, {"two", 2}}, {1, 2, 3, 4, 5}, "Hello, world"}; - - for (json& j : j_values) - { - auto it1 = j.begin(); - auto it2 = j.begin(); - auto it3 = j.begin(); - ++it2; - ++it3; - ++it3; - auto it1_c = j.cbegin(); - auto it2_c = j.cbegin(); - auto it3_c = j.cbegin(); - ++it2_c; - ++it3_c; - ++it3_c; - - // comparison: equal - { - CHECK(it1 == it1); - CHECK(not (it1 == it2)); - CHECK(not (it1 == it3)); - CHECK(not (it2 == it3)); - CHECK(it1_c == it1_c); - CHECK(not (it1_c == it2_c)); - CHECK(not (it1_c == it3_c)); - CHECK(not (it2_c == it3_c)); - } - - // comparison: not equal - { - // check definition - CHECK( (it1 != it1) == not(it1 == it1) ); - CHECK( (it1 != it2) == not(it1 == it2) ); - CHECK( (it1 != it3) == not(it1 == it3) ); - CHECK( (it2 != it3) == not(it2 == it3) ); - CHECK( (it1_c != it1_c) == not(it1_c == it1_c) ); - CHECK( (it1_c != it2_c) == not(it1_c == it2_c) ); - CHECK( (it1_c != it3_c) == not(it1_c == it3_c) ); - CHECK( (it2_c != it3_c) == not(it2_c == it3_c) ); - } - - // comparison: smaller - { - if (j.type() == json::value_t::object) - { - CHECK_THROWS_AS(it1 < it1, std::domain_error); - CHECK_THROWS_AS(it1 < it2, std::domain_error); - CHECK_THROWS_AS(it2 < it3, std::domain_error); - CHECK_THROWS_AS(it1 < it3, std::domain_error); - CHECK_THROWS_AS(it1_c < it1_c, std::domain_error); - CHECK_THROWS_AS(it1_c < it2_c, std::domain_error); - CHECK_THROWS_AS(it2_c < it3_c, std::domain_error); - CHECK_THROWS_AS(it1_c < it3_c, std::domain_error); - CHECK_THROWS_WITH(it1 < it1, "cannot compare order of object iterators"); - CHECK_THROWS_WITH(it1 < it2, "cannot compare order of object iterators"); - CHECK_THROWS_WITH(it2 < it3, "cannot compare order of object iterators"); - CHECK_THROWS_WITH(it1 < it3, "cannot compare order of object iterators"); - CHECK_THROWS_WITH(it1_c < it1_c, "cannot compare order of object iterators"); - CHECK_THROWS_WITH(it1_c < it2_c, "cannot compare order of object iterators"); - CHECK_THROWS_WITH(it2_c < it3_c, "cannot compare order of object iterators"); - CHECK_THROWS_WITH(it1_c < it3_c, "cannot compare order of object iterators"); - } - else - { - CHECK(not (it1 < it1)); - CHECK(it1 < it2); - CHECK(it1 < it3); - CHECK(it2 < it3); - CHECK(not (it1_c < it1_c)); - CHECK(it1_c < it2_c); - CHECK(it1_c < it3_c); - CHECK(it2_c < it3_c); - } - } - - // comparison: less than or equal - { - if (j.type() == json::value_t::object) - { - CHECK_THROWS_AS(it1 <= it1, std::domain_error); - CHECK_THROWS_AS(it1 <= it2, std::domain_error); - CHECK_THROWS_AS(it2 <= it3, std::domain_error); - CHECK_THROWS_AS(it1 <= it3, std::domain_error); - CHECK_THROWS_AS(it1_c <= it1_c, std::domain_error); - CHECK_THROWS_AS(it1_c <= it2_c, std::domain_error); - CHECK_THROWS_AS(it2_c <= it3_c, std::domain_error); - CHECK_THROWS_AS(it1_c <= it3_c, std::domain_error); - CHECK_THROWS_WITH(it1 <= it1, "cannot compare order of object iterators"); - CHECK_THROWS_WITH(it1 <= it2, "cannot compare order of object iterators"); - CHECK_THROWS_WITH(it2 <= it3, "cannot compare order of object iterators"); - CHECK_THROWS_WITH(it1 <= it3, "cannot compare order of object iterators"); - CHECK_THROWS_WITH(it1_c <= it1_c, "cannot compare order of object iterators"); - CHECK_THROWS_WITH(it1_c <= it2_c, "cannot compare order of object iterators"); - CHECK_THROWS_WITH(it2_c <= it3_c, "cannot compare order of object iterators"); - CHECK_THROWS_WITH(it1_c <= it3_c, "cannot compare order of object iterators"); - } - else - { - // check definition - CHECK( (it1 <= it1) == not(it1 < it1) ); - CHECK( (it1 <= it2) == not(it2 < it1) ); - CHECK( (it1 <= it3) == not(it3 < it1) ); - CHECK( (it2 <= it3) == not(it3 < it2) ); - CHECK( (it1_c <= it1_c) == not(it1_c < it1_c) ); - CHECK( (it1_c <= it2_c) == not(it2_c < it1_c) ); - CHECK( (it1_c <= it3_c) == not(it3_c < it1_c) ); - CHECK( (it2_c <= it3_c) == not(it3_c < it2_c) ); - } - } - - // comparison: greater than - { - if (j.type() == json::value_t::object) - { - CHECK_THROWS_AS(it1 > it1, std::domain_error); - CHECK_THROWS_AS(it1 > it2, std::domain_error); - CHECK_THROWS_AS(it2 > it3, std::domain_error); - CHECK_THROWS_AS(it1 > it3, std::domain_error); - CHECK_THROWS_AS(it1_c > it1_c, std::domain_error); - CHECK_THROWS_AS(it1_c > it2_c, std::domain_error); - CHECK_THROWS_AS(it2_c > it3_c, std::domain_error); - CHECK_THROWS_AS(it1_c > it3_c, std::domain_error); - CHECK_THROWS_WITH(it1 > it1, "cannot compare order of object iterators"); - CHECK_THROWS_WITH(it1 > it2, "cannot compare order of object iterators"); - CHECK_THROWS_WITH(it2 > it3, "cannot compare order of object iterators"); - CHECK_THROWS_WITH(it1 > it3, "cannot compare order of object iterators"); - CHECK_THROWS_WITH(it1_c > it1_c, "cannot compare order of object iterators"); - CHECK_THROWS_WITH(it1_c > it2_c, "cannot compare order of object iterators"); - CHECK_THROWS_WITH(it2_c > it3_c, "cannot compare order of object iterators"); - CHECK_THROWS_WITH(it1_c > it3_c, "cannot compare order of object iterators"); - } - else - { - // check definition - CHECK( (it1 > it1) == (it1 < it1) ); - CHECK( (it1 > it2) == (it2 < it1) ); - CHECK( (it1 > it3) == (it3 < it1) ); - CHECK( (it2 > it3) == (it3 < it2) ); - CHECK( (it1_c > it1_c) == (it1_c < it1_c) ); - CHECK( (it1_c > it2_c) == (it2_c < it1_c) ); - CHECK( (it1_c > it3_c) == (it3_c < it1_c) ); - CHECK( (it2_c > it3_c) == (it3_c < it2_c) ); - } - } - - // comparison: greater than or equal - { - if (j.type() == json::value_t::object) - { - CHECK_THROWS_AS(it1 >= it1, std::domain_error); - CHECK_THROWS_AS(it1 >= it2, std::domain_error); - CHECK_THROWS_AS(it2 >= it3, std::domain_error); - CHECK_THROWS_AS(it1 >= it3, std::domain_error); - CHECK_THROWS_AS(it1_c >= it1_c, std::domain_error); - CHECK_THROWS_AS(it1_c >= it2_c, std::domain_error); - CHECK_THROWS_AS(it2_c >= it3_c, std::domain_error); - CHECK_THROWS_AS(it1_c >= it3_c, std::domain_error); - CHECK_THROWS_WITH(it1 >= it1, "cannot compare order of object iterators"); - CHECK_THROWS_WITH(it1 >= it2, "cannot compare order of object iterators"); - CHECK_THROWS_WITH(it2 >= it3, "cannot compare order of object iterators"); - CHECK_THROWS_WITH(it1 >= it3, "cannot compare order of object iterators"); - CHECK_THROWS_WITH(it1_c >= it1_c, "cannot compare order of object iterators"); - CHECK_THROWS_WITH(it1_c >= it2_c, "cannot compare order of object iterators"); - CHECK_THROWS_WITH(it2_c >= it3_c, "cannot compare order of object iterators"); - CHECK_THROWS_WITH(it1_c >= it3_c, "cannot compare order of object iterators"); - } - else - { - // check definition - CHECK( (it1 >= it1) == not(it1 < it1) ); - CHECK( (it1 >= it2) == not(it1 < it2) ); - CHECK( (it1 >= it3) == not(it1 < it3) ); - CHECK( (it2 >= it3) == not(it2 < it3) ); - CHECK( (it1_c >= it1_c) == not(it1_c < it1_c) ); - CHECK( (it1_c >= it2_c) == not(it1_c < it2_c) ); - CHECK( (it1_c >= it3_c) == not(it1_c < it3_c) ); - CHECK( (it2_c >= it3_c) == not(it2_c < it3_c) ); - } - } - } - - // check exceptions if different objects are compared - for (auto j : j_values) - { - for (auto k : j_values) - { - if (j != k) - { - CHECK_THROWS_AS(j.begin() == k.begin(), std::domain_error); - CHECK_THROWS_AS(j.cbegin() == k.cbegin(), std::domain_error); - CHECK_THROWS_WITH(j.begin() == k.begin(), "cannot compare iterators of different containers"); - CHECK_THROWS_WITH(j.cbegin() == k.cbegin(), "cannot compare iterators of different containers"); - - CHECK_THROWS_AS(j.begin() < k.begin(), std::domain_error); - CHECK_THROWS_AS(j.cbegin() < k.cbegin(), std::domain_error); - CHECK_THROWS_WITH(j.begin() < k.begin(), "cannot compare iterators of different containers"); - CHECK_THROWS_WITH(j.cbegin() < k.cbegin(), "cannot compare iterators of different containers"); - } - } - } - } - - SECTION("iterator arithmetic") - { - json j_object = {{"one", 1}, {"two", 2}, {"three", 3}}; - json j_array = {1, 2, 3, 4, 5, 6}; - json j_null = nullptr; - json j_value = 42; - - SECTION("addition and subtraction") - { - SECTION("object") - { - { - auto it = j_object.begin(); - CHECK_THROWS_AS(it += 1, std::domain_error); - CHECK_THROWS_WITH(it += 1, "cannot use offsets with object iterators"); - } - { - auto it = j_object.cbegin(); - CHECK_THROWS_AS(it += 1, std::domain_error); - CHECK_THROWS_WITH(it += 1, "cannot use offsets with object iterators"); - } - { - auto it = j_object.begin(); - CHECK_THROWS_AS(it + 1, std::domain_error); - CHECK_THROWS_WITH(it + 1, "cannot use offsets with object iterators"); - } - { - auto it = j_object.cbegin(); - CHECK_THROWS_AS(it + 1, std::domain_error); - CHECK_THROWS_WITH(it + 1, "cannot use offsets with object iterators"); - } - { - auto it = j_object.begin(); - CHECK_THROWS_AS(it -= 1, std::domain_error); - CHECK_THROWS_WITH(it -= 1, "cannot use offsets with object iterators"); - } - { - auto it = j_object.cbegin(); - CHECK_THROWS_AS(it -= 1, std::domain_error); - CHECK_THROWS_WITH(it -= 1, "cannot use offsets with object iterators"); - } - { - auto it = j_object.begin(); - CHECK_THROWS_AS(it - 1, std::domain_error); - CHECK_THROWS_WITH(it - 1, "cannot use offsets with object iterators"); - } - { - auto it = j_object.cbegin(); - CHECK_THROWS_AS(it - 1, std::domain_error); - CHECK_THROWS_WITH(it - 1, "cannot use offsets with object iterators"); - } - { - auto it = j_object.begin(); - CHECK_THROWS_AS(it - it, std::domain_error); - CHECK_THROWS_WITH(it - it, "cannot use offsets with object iterators"); - } - { - auto it = j_object.cbegin(); - CHECK_THROWS_AS(it - it, std::domain_error); - CHECK_THROWS_WITH(it - it, "cannot use offsets with object iterators"); - } - } - - SECTION("array") - { - { - auto it = j_array.begin(); - it += 3; - CHECK((j_array.begin() + 3) == it); - CHECK((it - 3) == j_array.begin()); - CHECK((it - j_array.begin()) == 3); - CHECK(*it == json(4)); - it -= 2; - CHECK(*it == json(2)); - } - { - auto it = j_array.cbegin(); - it += 3; - CHECK((j_array.cbegin() + 3) == it); - CHECK((it - 3) == j_array.cbegin()); - CHECK((it - j_array.cbegin()) == 3); - CHECK(*it == json(4)); - it -= 2; - CHECK(*it == json(2)); - } - } - - SECTION("null") - { - { - auto it = j_null.begin(); - it += 3; - CHECK((j_null.begin() + 3) == it); - CHECK((it - 3) == j_null.begin()); - CHECK((it - j_null.begin()) == 3); - CHECK(it != j_null.end()); - it -= 3; - CHECK(it == j_null.end()); - } - { - auto it = j_null.cbegin(); - it += 3; - CHECK((j_null.cbegin() + 3) == it); - CHECK((it - 3) == j_null.cbegin()); - CHECK((it - j_null.cbegin()) == 3); - CHECK(it != j_null.cend()); - it -= 3; - CHECK(it == j_null.cend()); - } - } - - SECTION("value") - { - { - auto it = j_value.begin(); - it += 3; - CHECK((j_value.begin() + 3) == it); - CHECK((it - 3) == j_value.begin()); - CHECK((it - j_value.begin()) == 3); - CHECK(it != j_value.end()); - it -= 3; - CHECK(*it == json(42)); - } - { - auto it = j_value.cbegin(); - it += 3; - CHECK((j_value.cbegin() + 3) == it); - CHECK((it - 3) == j_value.cbegin()); - CHECK((it - j_value.cbegin()) == 3); - CHECK(it != j_value.cend()); - it -= 3; - CHECK(*it == json(42)); - } - } - } - - SECTION("subscript operator") - { - SECTION("object") - { - { - auto it = j_object.begin(); - CHECK_THROWS_AS(it[0], std::domain_error); - CHECK_THROWS_AS(it[1], std::domain_error); - CHECK_THROWS_WITH(it[0], "cannot use operator[] for object iterators"); - CHECK_THROWS_WITH(it[1], "cannot use operator[] for object iterators"); - } - { - auto it = j_object.cbegin(); - CHECK_THROWS_AS(it[0], std::domain_error); - CHECK_THROWS_AS(it[1], std::domain_error); - CHECK_THROWS_WITH(it[0], "cannot use operator[] for object iterators"); - CHECK_THROWS_WITH(it[1], "cannot use operator[] for object iterators"); - } - } - - SECTION("array") - { - { - auto it = j_array.begin(); - CHECK(it[0] == json(1)); - CHECK(it[1] == json(2)); - CHECK(it[2] == json(3)); - CHECK(it[3] == json(4)); - CHECK(it[4] == json(5)); - CHECK(it[5] == json(6)); - } - { - auto it = j_array.cbegin(); - CHECK(it[0] == json(1)); - CHECK(it[1] == json(2)); - CHECK(it[2] == json(3)); - CHECK(it[3] == json(4)); - CHECK(it[4] == json(5)); - CHECK(it[5] == json(6)); - } - } - - SECTION("null") - { - { - auto it = j_null.begin(); - CHECK_THROWS_AS(it[0], std::out_of_range); - CHECK_THROWS_AS(it[1], std::out_of_range); - CHECK_THROWS_WITH(it[0], "cannot get value"); - CHECK_THROWS_WITH(it[1], "cannot get value"); - } - { - auto it = j_null.cbegin(); - CHECK_THROWS_AS(it[0], std::out_of_range); - CHECK_THROWS_AS(it[1], std::out_of_range); - CHECK_THROWS_WITH(it[0], "cannot get value"); - CHECK_THROWS_WITH(it[1], "cannot get value"); - } - } - - SECTION("value") - { - { - auto it = j_value.begin(); - CHECK(it[0] == json(42)); - CHECK_THROWS_AS(it[1], std::out_of_range); - CHECK_THROWS_WITH(it[1], "cannot get value"); - } - { - auto it = j_value.cbegin(); - CHECK(it[0] == json(42)); - CHECK_THROWS_AS(it[1], std::out_of_range); - CHECK_THROWS_WITH(it[1], "cannot get value"); - } - } - } - } - - SECTION("reverse iterator comparisons") - { - json j_values = {nullptr, true, 42, 42u, 23.23, {{"one", 1}, {"two", 2}}, {1, 2, 3, 4, 5}, "Hello, world"}; - - for (json& j : j_values) - { - auto it1 = j.rbegin(); - auto it2 = j.rbegin(); - auto it3 = j.rbegin(); - ++it2; - ++it3; - ++it3; - auto it1_c = j.crbegin(); - auto it2_c = j.crbegin(); - auto it3_c = j.crbegin(); - ++it2_c; - ++it3_c; - ++it3_c; - - // comparison: equal - { - CHECK(it1 == it1); - CHECK(not (it1 == it2)); - CHECK(not (it1 == it3)); - CHECK(not (it2 == it3)); - CHECK(it1_c == it1_c); - CHECK(not (it1_c == it2_c)); - CHECK(not (it1_c == it3_c)); - CHECK(not (it2_c == it3_c)); - } - - // comparison: not equal - { - // check definition - CHECK( (it1 != it1) == not(it1 == it1) ); - CHECK( (it1 != it2) == not(it1 == it2) ); - CHECK( (it1 != it3) == not(it1 == it3) ); - CHECK( (it2 != it3) == not(it2 == it3) ); - CHECK( (it1_c != it1_c) == not(it1_c == it1_c) ); - CHECK( (it1_c != it2_c) == not(it1_c == it2_c) ); - CHECK( (it1_c != it3_c) == not(it1_c == it3_c) ); - CHECK( (it2_c != it3_c) == not(it2_c == it3_c) ); - } - - // comparison: smaller - { - if (j.type() == json::value_t::object) - { - CHECK_THROWS_AS(it1 < it1, std::domain_error); - CHECK_THROWS_AS(it1 < it2, std::domain_error); - CHECK_THROWS_AS(it2 < it3, std::domain_error); - CHECK_THROWS_AS(it1 < it3, std::domain_error); - CHECK_THROWS_AS(it1_c < it1_c, std::domain_error); - CHECK_THROWS_AS(it1_c < it2_c, std::domain_error); - CHECK_THROWS_AS(it2_c < it3_c, std::domain_error); - CHECK_THROWS_AS(it1_c < it3_c, std::domain_error); - CHECK_THROWS_WITH(it1 < it1, "cannot compare order of object iterators"); - CHECK_THROWS_WITH(it1 < it2, "cannot compare order of object iterators"); - CHECK_THROWS_WITH(it2 < it3, "cannot compare order of object iterators"); - CHECK_THROWS_WITH(it1 < it3, "cannot compare order of object iterators"); - CHECK_THROWS_WITH(it1_c < it1_c, "cannot compare order of object iterators"); - CHECK_THROWS_WITH(it1_c < it2_c, "cannot compare order of object iterators"); - CHECK_THROWS_WITH(it2_c < it3_c, "cannot compare order of object iterators"); - CHECK_THROWS_WITH(it1_c < it3_c, "cannot compare order of object iterators"); - } - else - { - CHECK(not (it1 < it1)); - CHECK(it1 < it2); - CHECK(it1 < it3); - CHECK(it2 < it3); - CHECK(not (it1_c < it1_c)); - CHECK(it1_c < it2_c); - CHECK(it1_c < it3_c); - CHECK(it2_c < it3_c); - } - } - - // comparison: less than or equal - { - if (j.type() == json::value_t::object) - { - CHECK_THROWS_AS(it1 <= it1, std::domain_error); - CHECK_THROWS_AS(it1 <= it2, std::domain_error); - CHECK_THROWS_AS(it2 <= it3, std::domain_error); - CHECK_THROWS_AS(it1 <= it3, std::domain_error); - CHECK_THROWS_AS(it1_c <= it1_c, std::domain_error); - CHECK_THROWS_AS(it1_c <= it2_c, std::domain_error); - CHECK_THROWS_AS(it2_c <= it3_c, std::domain_error); - CHECK_THROWS_AS(it1_c <= it3_c, std::domain_error); - CHECK_THROWS_WITH(it1 <= it1, "cannot compare order of object iterators"); - CHECK_THROWS_WITH(it1 <= it2, "cannot compare order of object iterators"); - CHECK_THROWS_WITH(it2 <= it3, "cannot compare order of object iterators"); - CHECK_THROWS_WITH(it1 <= it3, "cannot compare order of object iterators"); - CHECK_THROWS_WITH(it1_c <= it1_c, "cannot compare order of object iterators"); - CHECK_THROWS_WITH(it1_c <= it2_c, "cannot compare order of object iterators"); - CHECK_THROWS_WITH(it2_c <= it3_c, "cannot compare order of object iterators"); - CHECK_THROWS_WITH(it1_c <= it3_c, "cannot compare order of object iterators"); - } - else - { - // check definition - CHECK( (it1 <= it1) == not(it1 < it1) ); - CHECK( (it1 <= it2) == not(it2 < it1) ); - CHECK( (it1 <= it3) == not(it3 < it1) ); - CHECK( (it2 <= it3) == not(it3 < it2) ); - CHECK( (it1_c <= it1_c) == not(it1_c < it1_c) ); - CHECK( (it1_c <= it2_c) == not(it2_c < it1_c) ); - CHECK( (it1_c <= it3_c) == not(it3_c < it1_c) ); - CHECK( (it2_c <= it3_c) == not(it3_c < it2_c) ); - } - } - - // comparison: greater than - { - if (j.type() == json::value_t::object) - { - CHECK_THROWS_AS(it1 > it1, std::domain_error); - CHECK_THROWS_AS(it1 > it2, std::domain_error); - CHECK_THROWS_AS(it2 > it3, std::domain_error); - CHECK_THROWS_AS(it1 > it3, std::domain_error); - CHECK_THROWS_AS(it1_c > it1_c, std::domain_error); - CHECK_THROWS_AS(it1_c > it2_c, std::domain_error); - CHECK_THROWS_AS(it2_c > it3_c, std::domain_error); - CHECK_THROWS_AS(it1_c > it3_c, std::domain_error); - CHECK_THROWS_WITH(it1 > it1, "cannot compare order of object iterators"); - CHECK_THROWS_WITH(it1 > it2, "cannot compare order of object iterators"); - CHECK_THROWS_WITH(it2 > it3, "cannot compare order of object iterators"); - CHECK_THROWS_WITH(it1 > it3, "cannot compare order of object iterators"); - CHECK_THROWS_WITH(it1_c > it1_c, "cannot compare order of object iterators"); - CHECK_THROWS_WITH(it1_c > it2_c, "cannot compare order of object iterators"); - CHECK_THROWS_WITH(it2_c > it3_c, "cannot compare order of object iterators"); - CHECK_THROWS_WITH(it1_c > it3_c, "cannot compare order of object iterators"); - } - else - { - // check definition - CHECK( (it1 > it1) == (it1 < it1) ); - CHECK( (it1 > it2) == (it2 < it1) ); - CHECK( (it1 > it3) == (it3 < it1) ); - CHECK( (it2 > it3) == (it3 < it2) ); - CHECK( (it1_c > it1_c) == (it1_c < it1_c) ); - CHECK( (it1_c > it2_c) == (it2_c < it1_c) ); - CHECK( (it1_c > it3_c) == (it3_c < it1_c) ); - CHECK( (it2_c > it3_c) == (it3_c < it2_c) ); - } - } - - // comparison: greater than or equal - { - if (j.type() == json::value_t::object) - { - CHECK_THROWS_AS(it1 >= it1, std::domain_error); - CHECK_THROWS_AS(it1 >= it2, std::domain_error); - CHECK_THROWS_AS(it2 >= it3, std::domain_error); - CHECK_THROWS_AS(it1 >= it3, std::domain_error); - CHECK_THROWS_AS(it1_c >= it1_c, std::domain_error); - CHECK_THROWS_AS(it1_c >= it2_c, std::domain_error); - CHECK_THROWS_AS(it2_c >= it3_c, std::domain_error); - CHECK_THROWS_AS(it1_c >= it3_c, std::domain_error); - CHECK_THROWS_WITH(it1 >= it1, "cannot compare order of object iterators"); - CHECK_THROWS_WITH(it1 >= it2, "cannot compare order of object iterators"); - CHECK_THROWS_WITH(it2 >= it3, "cannot compare order of object iterators"); - CHECK_THROWS_WITH(it1 >= it3, "cannot compare order of object iterators"); - CHECK_THROWS_WITH(it1_c >= it1_c, "cannot compare order of object iterators"); - CHECK_THROWS_WITH(it1_c >= it2_c, "cannot compare order of object iterators"); - CHECK_THROWS_WITH(it2_c >= it3_c, "cannot compare order of object iterators"); - CHECK_THROWS_WITH(it1_c >= it3_c, "cannot compare order of object iterators"); - } - else - { - // check definition - CHECK( (it1 >= it1) == not(it1 < it1) ); - CHECK( (it1 >= it2) == not(it1 < it2) ); - CHECK( (it1 >= it3) == not(it1 < it3) ); - CHECK( (it2 >= it3) == not(it2 < it3) ); - CHECK( (it1_c >= it1_c) == not(it1_c < it1_c) ); - CHECK( (it1_c >= it2_c) == not(it1_c < it2_c) ); - CHECK( (it1_c >= it3_c) == not(it1_c < it3_c) ); - CHECK( (it2_c >= it3_c) == not(it2_c < it3_c) ); - } - } - } - - // check exceptions if different objects are compared - for (auto j : j_values) - { - for (auto k : j_values) - { - if (j != k) - { - CHECK_THROWS_AS(j.rbegin() == k.rbegin(), std::domain_error); - CHECK_THROWS_AS(j.crbegin() == k.crbegin(), std::domain_error); - CHECK_THROWS_WITH(j.rbegin() == k.rbegin(), "cannot compare iterators of different containers"); - CHECK_THROWS_WITH(j.crbegin() == k.crbegin(), "cannot compare iterators of different containers"); - - CHECK_THROWS_AS(j.rbegin() < k.rbegin(), std::domain_error); - CHECK_THROWS_AS(j.crbegin() < k.crbegin(), std::domain_error); - CHECK_THROWS_WITH(j.rbegin() < k.rbegin(), "cannot compare iterators of different containers"); - CHECK_THROWS_WITH(j.crbegin() < k.crbegin(), "cannot compare iterators of different containers"); - } - } - } - } - - SECTION("reverse iterator arithmetic") - { - json j_object = {{"one", 1}, {"two", 2}, {"three", 3}}; - json j_array = {1, 2, 3, 4, 5, 6}; - json j_null = nullptr; - json j_value = 42; - - SECTION("addition and subtraction") - { - SECTION("object") - { - { - auto it = j_object.rbegin(); - CHECK_THROWS_AS(it += 1, std::domain_error); - CHECK_THROWS_WITH(it += 1, "cannot use offsets with object iterators"); - } - { - auto it = j_object.crbegin(); - CHECK_THROWS_AS(it += 1, std::domain_error); - CHECK_THROWS_WITH(it += 1, "cannot use offsets with object iterators"); - } - { - auto it = j_object.rbegin(); - CHECK_THROWS_AS(it + 1, std::domain_error); - CHECK_THROWS_WITH(it + 1, "cannot use offsets with object iterators"); - } - { - auto it = j_object.crbegin(); - CHECK_THROWS_AS(it + 1, std::domain_error); - CHECK_THROWS_WITH(it + 1, "cannot use offsets with object iterators"); - } - { - auto it = j_object.rbegin(); - CHECK_THROWS_AS(it -= 1, std::domain_error); - CHECK_THROWS_WITH(it -= 1, "cannot use offsets with object iterators"); - } - { - auto it = j_object.crbegin(); - CHECK_THROWS_AS(it -= 1, std::domain_error); - CHECK_THROWS_WITH(it -= 1, "cannot use offsets with object iterators"); - } - { - auto it = j_object.rbegin(); - CHECK_THROWS_AS(it - 1, std::domain_error); - CHECK_THROWS_WITH(it - 1, "cannot use offsets with object iterators"); - } - { - auto it = j_object.crbegin(); - CHECK_THROWS_AS(it - 1, std::domain_error); - CHECK_THROWS_WITH(it - 1, "cannot use offsets with object iterators"); - } - { - auto it = j_object.rbegin(); - CHECK_THROWS_AS(it - it, std::domain_error); - CHECK_THROWS_WITH(it - it, "cannot use offsets with object iterators"); - } - { - auto it = j_object.crbegin(); - CHECK_THROWS_AS(it - it, std::domain_error); - CHECK_THROWS_WITH(it - it, "cannot use offsets with object iterators"); - } - } - - SECTION("array") - { - { - auto it = j_array.rbegin(); - it += 3; - CHECK((j_array.rbegin() + 3) == it); - CHECK((it - 3) == j_array.rbegin()); - CHECK((j_array.rbegin() - it) == 3); - CHECK(*it == json(3)); - it -= 2; - CHECK(*it == json(5)); - } - { - auto it = j_array.crbegin(); - it += 3; - CHECK((j_array.crbegin() + 3) == it); - CHECK((it - 3) == j_array.crbegin()); - CHECK((j_array.crbegin() - it) == 3); - CHECK(*it == json(3)); - it -= 2; - CHECK(*it == json(5)); - } - } - - SECTION("null") - { - { - auto it = j_null.rbegin(); - it += 3; - CHECK((j_null.rbegin() + 3) == it); - CHECK((it - 3) == j_null.rbegin()); - CHECK((j_null.rbegin() - it) == 3); - CHECK(it != j_null.rend()); - it -= 3; - CHECK(it == j_null.rend()); - } - { - auto it = j_null.crbegin(); - it += 3; - CHECK((j_null.crbegin() + 3) == it); - CHECK((it - 3) == j_null.crbegin()); - CHECK((j_null.crbegin() - it) == 3); - CHECK(it != j_null.crend()); - it -= 3; - CHECK(it == j_null.crend()); - } - } - - SECTION("value") - { - { - auto it = j_value.rbegin(); - it += 3; - CHECK((j_value.rbegin() + 3) == it); - CHECK((it - 3) == j_value.rbegin()); - CHECK((j_value.rbegin() - it) == 3); - CHECK(it != j_value.rend()); - it -= 3; - CHECK(*it == json(42)); - } - { - auto it = j_value.crbegin(); - it += 3; - CHECK((j_value.crbegin() + 3) == it); - CHECK((it - 3) == j_value.crbegin()); - CHECK((j_value.crbegin() - it) == 3); - CHECK(it != j_value.crend()); - it -= 3; - CHECK(*it == json(42)); - } - } - } - - SECTION("subscript operator") - { - SECTION("object") - { - { - auto it = j_object.rbegin(); - CHECK_THROWS_AS(it[0], std::domain_error); - CHECK_THROWS_AS(it[1], std::domain_error); - CHECK_THROWS_WITH(it[0], "cannot use offsets with object iterators"); - CHECK_THROWS_WITH(it[1], "cannot use offsets with object iterators"); - } - { - auto it = j_object.crbegin(); - CHECK_THROWS_AS(it[0], std::domain_error); - CHECK_THROWS_AS(it[1], std::domain_error); - CHECK_THROWS_WITH(it[0], "cannot use offsets with object iterators"); - CHECK_THROWS_WITH(it[1], "cannot use offsets with object iterators"); - } - } - - SECTION("array") - { - { - auto it = j_array.rbegin(); - CHECK(it[0] == json(6)); - CHECK(it[1] == json(5)); - CHECK(it[2] == json(4)); - CHECK(it[3] == json(3)); - CHECK(it[4] == json(2)); - CHECK(it[5] == json(1)); - } - { - auto it = j_array.crbegin(); - CHECK(it[0] == json(6)); - CHECK(it[1] == json(5)); - CHECK(it[2] == json(4)); - CHECK(it[3] == json(3)); - CHECK(it[4] == json(2)); - CHECK(it[5] == json(1)); - } - } - - SECTION("null") - { - { - auto it = j_null.rbegin(); - CHECK_THROWS_AS(it[0], std::out_of_range); - CHECK_THROWS_AS(it[1], std::out_of_range); - CHECK_THROWS_WITH(it[0], "cannot get value"); - CHECK_THROWS_WITH(it[1], "cannot get value"); - } - { - auto it = j_null.crbegin(); - CHECK_THROWS_AS(it[0], std::out_of_range); - CHECK_THROWS_AS(it[1], std::out_of_range); - CHECK_THROWS_WITH(it[0], "cannot get value"); - CHECK_THROWS_WITH(it[1], "cannot get value"); - } - } - - SECTION("value") - { - { - auto it = j_value.rbegin(); - CHECK(it[0] == json(42)); - CHECK_THROWS_AS(it[1], std::out_of_range); - CHECK_THROWS_WITH(it[1], "cannot get value"); - } - { - auto it = j_value.crbegin(); - CHECK(it[0] == json(42)); - CHECK_THROWS_AS(it[1], std::out_of_range); - CHECK_THROWS_WITH(it[1], "cannot get value"); - } - } - } - } } diff --git a/test/src/unit-iterators2.cpp b/test/src/unit-iterators2.cpp new file mode 100644 index 00000000..cc5d9818 --- /dev/null +++ b/test/src/unit-iterators2.cpp @@ -0,0 +1,873 @@ +/* + __ _____ _____ _____ + __| | __| | | | JSON for Modern C++ (test suite) +| | |__ | | | | | | version 2.0.2 +|_____|_____|_____|_|___| https://github.com/nlohmann/json + +Licensed under the MIT License . +Copyright (c) 2013-2016 Niels Lohmann . + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. +*/ + +#include "catch.hpp" + +#include "json.hpp" +using nlohmann::json; + +TEST_CASE("iterators 2") +{ + SECTION("iterator comparisons") + { + json j_values = {nullptr, true, 42, 42u, 23.23, {{"one", 1}, {"two", 2}}, {1, 2, 3, 4, 5}, "Hello, world"}; + + for (json& j : j_values) + { + auto it1 = j.begin(); + auto it2 = j.begin(); + auto it3 = j.begin(); + ++it2; + ++it3; + ++it3; + auto it1_c = j.cbegin(); + auto it2_c = j.cbegin(); + auto it3_c = j.cbegin(); + ++it2_c; + ++it3_c; + ++it3_c; + + // comparison: equal + { + CHECK(it1 == it1); + CHECK(not (it1 == it2)); + CHECK(not (it1 == it3)); + CHECK(not (it2 == it3)); + CHECK(it1_c == it1_c); + CHECK(not (it1_c == it2_c)); + CHECK(not (it1_c == it3_c)); + CHECK(not (it2_c == it3_c)); + } + + // comparison: not equal + { + // check definition + CHECK( (it1 != it1) == not(it1 == it1) ); + CHECK( (it1 != it2) == not(it1 == it2) ); + CHECK( (it1 != it3) == not(it1 == it3) ); + CHECK( (it2 != it3) == not(it2 == it3) ); + CHECK( (it1_c != it1_c) == not(it1_c == it1_c) ); + CHECK( (it1_c != it2_c) == not(it1_c == it2_c) ); + CHECK( (it1_c != it3_c) == not(it1_c == it3_c) ); + CHECK( (it2_c != it3_c) == not(it2_c == it3_c) ); + } + + // comparison: smaller + { + if (j.type() == json::value_t::object) + { + CHECK_THROWS_AS(it1 < it1, std::domain_error); + CHECK_THROWS_AS(it1 < it2, std::domain_error); + CHECK_THROWS_AS(it2 < it3, std::domain_error); + CHECK_THROWS_AS(it1 < it3, std::domain_error); + CHECK_THROWS_AS(it1_c < it1_c, std::domain_error); + CHECK_THROWS_AS(it1_c < it2_c, std::domain_error); + CHECK_THROWS_AS(it2_c < it3_c, std::domain_error); + CHECK_THROWS_AS(it1_c < it3_c, std::domain_error); + CHECK_THROWS_WITH(it1 < it1, "cannot compare order of object iterators"); + CHECK_THROWS_WITH(it1 < it2, "cannot compare order of object iterators"); + CHECK_THROWS_WITH(it2 < it3, "cannot compare order of object iterators"); + CHECK_THROWS_WITH(it1 < it3, "cannot compare order of object iterators"); + CHECK_THROWS_WITH(it1_c < it1_c, "cannot compare order of object iterators"); + CHECK_THROWS_WITH(it1_c < it2_c, "cannot compare order of object iterators"); + CHECK_THROWS_WITH(it2_c < it3_c, "cannot compare order of object iterators"); + CHECK_THROWS_WITH(it1_c < it3_c, "cannot compare order of object iterators"); + } + else + { + CHECK(not (it1 < it1)); + CHECK(it1 < it2); + CHECK(it1 < it3); + CHECK(it2 < it3); + CHECK(not (it1_c < it1_c)); + CHECK(it1_c < it2_c); + CHECK(it1_c < it3_c); + CHECK(it2_c < it3_c); + } + } + + // comparison: less than or equal + { + if (j.type() == json::value_t::object) + { + CHECK_THROWS_AS(it1 <= it1, std::domain_error); + CHECK_THROWS_AS(it1 <= it2, std::domain_error); + CHECK_THROWS_AS(it2 <= it3, std::domain_error); + CHECK_THROWS_AS(it1 <= it3, std::domain_error); + CHECK_THROWS_AS(it1_c <= it1_c, std::domain_error); + CHECK_THROWS_AS(it1_c <= it2_c, std::domain_error); + CHECK_THROWS_AS(it2_c <= it3_c, std::domain_error); + CHECK_THROWS_AS(it1_c <= it3_c, std::domain_error); + CHECK_THROWS_WITH(it1 <= it1, "cannot compare order of object iterators"); + CHECK_THROWS_WITH(it1 <= it2, "cannot compare order of object iterators"); + CHECK_THROWS_WITH(it2 <= it3, "cannot compare order of object iterators"); + CHECK_THROWS_WITH(it1 <= it3, "cannot compare order of object iterators"); + CHECK_THROWS_WITH(it1_c <= it1_c, "cannot compare order of object iterators"); + CHECK_THROWS_WITH(it1_c <= it2_c, "cannot compare order of object iterators"); + CHECK_THROWS_WITH(it2_c <= it3_c, "cannot compare order of object iterators"); + CHECK_THROWS_WITH(it1_c <= it3_c, "cannot compare order of object iterators"); + } + else + { + // check definition + CHECK( (it1 <= it1) == not(it1 < it1) ); + CHECK( (it1 <= it2) == not(it2 < it1) ); + CHECK( (it1 <= it3) == not(it3 < it1) ); + CHECK( (it2 <= it3) == not(it3 < it2) ); + CHECK( (it1_c <= it1_c) == not(it1_c < it1_c) ); + CHECK( (it1_c <= it2_c) == not(it2_c < it1_c) ); + CHECK( (it1_c <= it3_c) == not(it3_c < it1_c) ); + CHECK( (it2_c <= it3_c) == not(it3_c < it2_c) ); + } + } + + // comparison: greater than + { + if (j.type() == json::value_t::object) + { + CHECK_THROWS_AS(it1 > it1, std::domain_error); + CHECK_THROWS_AS(it1 > it2, std::domain_error); + CHECK_THROWS_AS(it2 > it3, std::domain_error); + CHECK_THROWS_AS(it1 > it3, std::domain_error); + CHECK_THROWS_AS(it1_c > it1_c, std::domain_error); + CHECK_THROWS_AS(it1_c > it2_c, std::domain_error); + CHECK_THROWS_AS(it2_c > it3_c, std::domain_error); + CHECK_THROWS_AS(it1_c > it3_c, std::domain_error); + CHECK_THROWS_WITH(it1 > it1, "cannot compare order of object iterators"); + CHECK_THROWS_WITH(it1 > it2, "cannot compare order of object iterators"); + CHECK_THROWS_WITH(it2 > it3, "cannot compare order of object iterators"); + CHECK_THROWS_WITH(it1 > it3, "cannot compare order of object iterators"); + CHECK_THROWS_WITH(it1_c > it1_c, "cannot compare order of object iterators"); + CHECK_THROWS_WITH(it1_c > it2_c, "cannot compare order of object iterators"); + CHECK_THROWS_WITH(it2_c > it3_c, "cannot compare order of object iterators"); + CHECK_THROWS_WITH(it1_c > it3_c, "cannot compare order of object iterators"); + } + else + { + // check definition + CHECK( (it1 > it1) == (it1 < it1) ); + CHECK( (it1 > it2) == (it2 < it1) ); + CHECK( (it1 > it3) == (it3 < it1) ); + CHECK( (it2 > it3) == (it3 < it2) ); + CHECK( (it1_c > it1_c) == (it1_c < it1_c) ); + CHECK( (it1_c > it2_c) == (it2_c < it1_c) ); + CHECK( (it1_c > it3_c) == (it3_c < it1_c) ); + CHECK( (it2_c > it3_c) == (it3_c < it2_c) ); + } + } + + // comparison: greater than or equal + { + if (j.type() == json::value_t::object) + { + CHECK_THROWS_AS(it1 >= it1, std::domain_error); + CHECK_THROWS_AS(it1 >= it2, std::domain_error); + CHECK_THROWS_AS(it2 >= it3, std::domain_error); + CHECK_THROWS_AS(it1 >= it3, std::domain_error); + CHECK_THROWS_AS(it1_c >= it1_c, std::domain_error); + CHECK_THROWS_AS(it1_c >= it2_c, std::domain_error); + CHECK_THROWS_AS(it2_c >= it3_c, std::domain_error); + CHECK_THROWS_AS(it1_c >= it3_c, std::domain_error); + CHECK_THROWS_WITH(it1 >= it1, "cannot compare order of object iterators"); + CHECK_THROWS_WITH(it1 >= it2, "cannot compare order of object iterators"); + CHECK_THROWS_WITH(it2 >= it3, "cannot compare order of object iterators"); + CHECK_THROWS_WITH(it1 >= it3, "cannot compare order of object iterators"); + CHECK_THROWS_WITH(it1_c >= it1_c, "cannot compare order of object iterators"); + CHECK_THROWS_WITH(it1_c >= it2_c, "cannot compare order of object iterators"); + CHECK_THROWS_WITH(it2_c >= it3_c, "cannot compare order of object iterators"); + CHECK_THROWS_WITH(it1_c >= it3_c, "cannot compare order of object iterators"); + } + else + { + // check definition + CHECK( (it1 >= it1) == not(it1 < it1) ); + CHECK( (it1 >= it2) == not(it1 < it2) ); + CHECK( (it1 >= it3) == not(it1 < it3) ); + CHECK( (it2 >= it3) == not(it2 < it3) ); + CHECK( (it1_c >= it1_c) == not(it1_c < it1_c) ); + CHECK( (it1_c >= it2_c) == not(it1_c < it2_c) ); + CHECK( (it1_c >= it3_c) == not(it1_c < it3_c) ); + CHECK( (it2_c >= it3_c) == not(it2_c < it3_c) ); + } + } + } + + // check exceptions if different objects are compared + for (auto j : j_values) + { + for (auto k : j_values) + { + if (j != k) + { + CHECK_THROWS_AS(j.begin() == k.begin(), std::domain_error); + CHECK_THROWS_AS(j.cbegin() == k.cbegin(), std::domain_error); + CHECK_THROWS_WITH(j.begin() == k.begin(), "cannot compare iterators of different containers"); + CHECK_THROWS_WITH(j.cbegin() == k.cbegin(), "cannot compare iterators of different containers"); + + CHECK_THROWS_AS(j.begin() < k.begin(), std::domain_error); + CHECK_THROWS_AS(j.cbegin() < k.cbegin(), std::domain_error); + CHECK_THROWS_WITH(j.begin() < k.begin(), "cannot compare iterators of different containers"); + CHECK_THROWS_WITH(j.cbegin() < k.cbegin(), "cannot compare iterators of different containers"); + } + } + } + } + + SECTION("iterator arithmetic") + { + json j_object = {{"one", 1}, {"two", 2}, {"three", 3}}; + json j_array = {1, 2, 3, 4, 5, 6}; + json j_null = nullptr; + json j_value = 42; + + SECTION("addition and subtraction") + { + SECTION("object") + { + { + auto it = j_object.begin(); + CHECK_THROWS_AS(it += 1, std::domain_error); + CHECK_THROWS_WITH(it += 1, "cannot use offsets with object iterators"); + } + { + auto it = j_object.cbegin(); + CHECK_THROWS_AS(it += 1, std::domain_error); + CHECK_THROWS_WITH(it += 1, "cannot use offsets with object iterators"); + } + { + auto it = j_object.begin(); + CHECK_THROWS_AS(it + 1, std::domain_error); + CHECK_THROWS_WITH(it + 1, "cannot use offsets with object iterators"); + } + { + auto it = j_object.cbegin(); + CHECK_THROWS_AS(it + 1, std::domain_error); + CHECK_THROWS_WITH(it + 1, "cannot use offsets with object iterators"); + } + { + auto it = j_object.begin(); + CHECK_THROWS_AS(it -= 1, std::domain_error); + CHECK_THROWS_WITH(it -= 1, "cannot use offsets with object iterators"); + } + { + auto it = j_object.cbegin(); + CHECK_THROWS_AS(it -= 1, std::domain_error); + CHECK_THROWS_WITH(it -= 1, "cannot use offsets with object iterators"); + } + { + auto it = j_object.begin(); + CHECK_THROWS_AS(it - 1, std::domain_error); + CHECK_THROWS_WITH(it - 1, "cannot use offsets with object iterators"); + } + { + auto it = j_object.cbegin(); + CHECK_THROWS_AS(it - 1, std::domain_error); + CHECK_THROWS_WITH(it - 1, "cannot use offsets with object iterators"); + } + { + auto it = j_object.begin(); + CHECK_THROWS_AS(it - it, std::domain_error); + CHECK_THROWS_WITH(it - it, "cannot use offsets with object iterators"); + } + { + auto it = j_object.cbegin(); + CHECK_THROWS_AS(it - it, std::domain_error); + CHECK_THROWS_WITH(it - it, "cannot use offsets with object iterators"); + } + } + + SECTION("array") + { + { + auto it = j_array.begin(); + it += 3; + CHECK((j_array.begin() + 3) == it); + CHECK((it - 3) == j_array.begin()); + CHECK((it - j_array.begin()) == 3); + CHECK(*it == json(4)); + it -= 2; + CHECK(*it == json(2)); + } + { + auto it = j_array.cbegin(); + it += 3; + CHECK((j_array.cbegin() + 3) == it); + CHECK((it - 3) == j_array.cbegin()); + CHECK((it - j_array.cbegin()) == 3); + CHECK(*it == json(4)); + it -= 2; + CHECK(*it == json(2)); + } + } + + SECTION("null") + { + { + auto it = j_null.begin(); + it += 3; + CHECK((j_null.begin() + 3) == it); + CHECK((it - 3) == j_null.begin()); + CHECK((it - j_null.begin()) == 3); + CHECK(it != j_null.end()); + it -= 3; + CHECK(it == j_null.end()); + } + { + auto it = j_null.cbegin(); + it += 3; + CHECK((j_null.cbegin() + 3) == it); + CHECK((it - 3) == j_null.cbegin()); + CHECK((it - j_null.cbegin()) == 3); + CHECK(it != j_null.cend()); + it -= 3; + CHECK(it == j_null.cend()); + } + } + + SECTION("value") + { + { + auto it = j_value.begin(); + it += 3; + CHECK((j_value.begin() + 3) == it); + CHECK((it - 3) == j_value.begin()); + CHECK((it - j_value.begin()) == 3); + CHECK(it != j_value.end()); + it -= 3; + CHECK(*it == json(42)); + } + { + auto it = j_value.cbegin(); + it += 3; + CHECK((j_value.cbegin() + 3) == it); + CHECK((it - 3) == j_value.cbegin()); + CHECK((it - j_value.cbegin()) == 3); + CHECK(it != j_value.cend()); + it -= 3; + CHECK(*it == json(42)); + } + } + } + + SECTION("subscript operator") + { + SECTION("object") + { + { + auto it = j_object.begin(); + CHECK_THROWS_AS(it[0], std::domain_error); + CHECK_THROWS_AS(it[1], std::domain_error); + CHECK_THROWS_WITH(it[0], "cannot use operator[] for object iterators"); + CHECK_THROWS_WITH(it[1], "cannot use operator[] for object iterators"); + } + { + auto it = j_object.cbegin(); + CHECK_THROWS_AS(it[0], std::domain_error); + CHECK_THROWS_AS(it[1], std::domain_error); + CHECK_THROWS_WITH(it[0], "cannot use operator[] for object iterators"); + CHECK_THROWS_WITH(it[1], "cannot use operator[] for object iterators"); + } + } + + SECTION("array") + { + { + auto it = j_array.begin(); + CHECK(it[0] == json(1)); + CHECK(it[1] == json(2)); + CHECK(it[2] == json(3)); + CHECK(it[3] == json(4)); + CHECK(it[4] == json(5)); + CHECK(it[5] == json(6)); + } + { + auto it = j_array.cbegin(); + CHECK(it[0] == json(1)); + CHECK(it[1] == json(2)); + CHECK(it[2] == json(3)); + CHECK(it[3] == json(4)); + CHECK(it[4] == json(5)); + CHECK(it[5] == json(6)); + } + } + + SECTION("null") + { + { + auto it = j_null.begin(); + CHECK_THROWS_AS(it[0], std::out_of_range); + CHECK_THROWS_AS(it[1], std::out_of_range); + CHECK_THROWS_WITH(it[0], "cannot get value"); + CHECK_THROWS_WITH(it[1], "cannot get value"); + } + { + auto it = j_null.cbegin(); + CHECK_THROWS_AS(it[0], std::out_of_range); + CHECK_THROWS_AS(it[1], std::out_of_range); + CHECK_THROWS_WITH(it[0], "cannot get value"); + CHECK_THROWS_WITH(it[1], "cannot get value"); + } + } + + SECTION("value") + { + { + auto it = j_value.begin(); + CHECK(it[0] == json(42)); + CHECK_THROWS_AS(it[1], std::out_of_range); + CHECK_THROWS_WITH(it[1], "cannot get value"); + } + { + auto it = j_value.cbegin(); + CHECK(it[0] == json(42)); + CHECK_THROWS_AS(it[1], std::out_of_range); + CHECK_THROWS_WITH(it[1], "cannot get value"); + } + } + } + } + + SECTION("reverse iterator comparisons") + { + json j_values = {nullptr, true, 42, 42u, 23.23, {{"one", 1}, {"two", 2}}, {1, 2, 3, 4, 5}, "Hello, world"}; + + for (json& j : j_values) + { + auto it1 = j.rbegin(); + auto it2 = j.rbegin(); + auto it3 = j.rbegin(); + ++it2; + ++it3; + ++it3; + auto it1_c = j.crbegin(); + auto it2_c = j.crbegin(); + auto it3_c = j.crbegin(); + ++it2_c; + ++it3_c; + ++it3_c; + + // comparison: equal + { + CHECK(it1 == it1); + CHECK(not (it1 == it2)); + CHECK(not (it1 == it3)); + CHECK(not (it2 == it3)); + CHECK(it1_c == it1_c); + CHECK(not (it1_c == it2_c)); + CHECK(not (it1_c == it3_c)); + CHECK(not (it2_c == it3_c)); + } + + // comparison: not equal + { + // check definition + CHECK( (it1 != it1) == not(it1 == it1) ); + CHECK( (it1 != it2) == not(it1 == it2) ); + CHECK( (it1 != it3) == not(it1 == it3) ); + CHECK( (it2 != it3) == not(it2 == it3) ); + CHECK( (it1_c != it1_c) == not(it1_c == it1_c) ); + CHECK( (it1_c != it2_c) == not(it1_c == it2_c) ); + CHECK( (it1_c != it3_c) == not(it1_c == it3_c) ); + CHECK( (it2_c != it3_c) == not(it2_c == it3_c) ); + } + + // comparison: smaller + { + if (j.type() == json::value_t::object) + { + CHECK_THROWS_AS(it1 < it1, std::domain_error); + CHECK_THROWS_AS(it1 < it2, std::domain_error); + CHECK_THROWS_AS(it2 < it3, std::domain_error); + CHECK_THROWS_AS(it1 < it3, std::domain_error); + CHECK_THROWS_AS(it1_c < it1_c, std::domain_error); + CHECK_THROWS_AS(it1_c < it2_c, std::domain_error); + CHECK_THROWS_AS(it2_c < it3_c, std::domain_error); + CHECK_THROWS_AS(it1_c < it3_c, std::domain_error); + CHECK_THROWS_WITH(it1 < it1, "cannot compare order of object iterators"); + CHECK_THROWS_WITH(it1 < it2, "cannot compare order of object iterators"); + CHECK_THROWS_WITH(it2 < it3, "cannot compare order of object iterators"); + CHECK_THROWS_WITH(it1 < it3, "cannot compare order of object iterators"); + CHECK_THROWS_WITH(it1_c < it1_c, "cannot compare order of object iterators"); + CHECK_THROWS_WITH(it1_c < it2_c, "cannot compare order of object iterators"); + CHECK_THROWS_WITH(it2_c < it3_c, "cannot compare order of object iterators"); + CHECK_THROWS_WITH(it1_c < it3_c, "cannot compare order of object iterators"); + } + else + { + CHECK(not (it1 < it1)); + CHECK(it1 < it2); + CHECK(it1 < it3); + CHECK(it2 < it3); + CHECK(not (it1_c < it1_c)); + CHECK(it1_c < it2_c); + CHECK(it1_c < it3_c); + CHECK(it2_c < it3_c); + } + } + + // comparison: less than or equal + { + if (j.type() == json::value_t::object) + { + CHECK_THROWS_AS(it1 <= it1, std::domain_error); + CHECK_THROWS_AS(it1 <= it2, std::domain_error); + CHECK_THROWS_AS(it2 <= it3, std::domain_error); + CHECK_THROWS_AS(it1 <= it3, std::domain_error); + CHECK_THROWS_AS(it1_c <= it1_c, std::domain_error); + CHECK_THROWS_AS(it1_c <= it2_c, std::domain_error); + CHECK_THROWS_AS(it2_c <= it3_c, std::domain_error); + CHECK_THROWS_AS(it1_c <= it3_c, std::domain_error); + CHECK_THROWS_WITH(it1 <= it1, "cannot compare order of object iterators"); + CHECK_THROWS_WITH(it1 <= it2, "cannot compare order of object iterators"); + CHECK_THROWS_WITH(it2 <= it3, "cannot compare order of object iterators"); + CHECK_THROWS_WITH(it1 <= it3, "cannot compare order of object iterators"); + CHECK_THROWS_WITH(it1_c <= it1_c, "cannot compare order of object iterators"); + CHECK_THROWS_WITH(it1_c <= it2_c, "cannot compare order of object iterators"); + CHECK_THROWS_WITH(it2_c <= it3_c, "cannot compare order of object iterators"); + CHECK_THROWS_WITH(it1_c <= it3_c, "cannot compare order of object iterators"); + } + else + { + // check definition + CHECK( (it1 <= it1) == not(it1 < it1) ); + CHECK( (it1 <= it2) == not(it2 < it1) ); + CHECK( (it1 <= it3) == not(it3 < it1) ); + CHECK( (it2 <= it3) == not(it3 < it2) ); + CHECK( (it1_c <= it1_c) == not(it1_c < it1_c) ); + CHECK( (it1_c <= it2_c) == not(it2_c < it1_c) ); + CHECK( (it1_c <= it3_c) == not(it3_c < it1_c) ); + CHECK( (it2_c <= it3_c) == not(it3_c < it2_c) ); + } + } + + // comparison: greater than + { + if (j.type() == json::value_t::object) + { + CHECK_THROWS_AS(it1 > it1, std::domain_error); + CHECK_THROWS_AS(it1 > it2, std::domain_error); + CHECK_THROWS_AS(it2 > it3, std::domain_error); + CHECK_THROWS_AS(it1 > it3, std::domain_error); + CHECK_THROWS_AS(it1_c > it1_c, std::domain_error); + CHECK_THROWS_AS(it1_c > it2_c, std::domain_error); + CHECK_THROWS_AS(it2_c > it3_c, std::domain_error); + CHECK_THROWS_AS(it1_c > it3_c, std::domain_error); + CHECK_THROWS_WITH(it1 > it1, "cannot compare order of object iterators"); + CHECK_THROWS_WITH(it1 > it2, "cannot compare order of object iterators"); + CHECK_THROWS_WITH(it2 > it3, "cannot compare order of object iterators"); + CHECK_THROWS_WITH(it1 > it3, "cannot compare order of object iterators"); + CHECK_THROWS_WITH(it1_c > it1_c, "cannot compare order of object iterators"); + CHECK_THROWS_WITH(it1_c > it2_c, "cannot compare order of object iterators"); + CHECK_THROWS_WITH(it2_c > it3_c, "cannot compare order of object iterators"); + CHECK_THROWS_WITH(it1_c > it3_c, "cannot compare order of object iterators"); + } + else + { + // check definition + CHECK( (it1 > it1) == (it1 < it1) ); + CHECK( (it1 > it2) == (it2 < it1) ); + CHECK( (it1 > it3) == (it3 < it1) ); + CHECK( (it2 > it3) == (it3 < it2) ); + CHECK( (it1_c > it1_c) == (it1_c < it1_c) ); + CHECK( (it1_c > it2_c) == (it2_c < it1_c) ); + CHECK( (it1_c > it3_c) == (it3_c < it1_c) ); + CHECK( (it2_c > it3_c) == (it3_c < it2_c) ); + } + } + + // comparison: greater than or equal + { + if (j.type() == json::value_t::object) + { + CHECK_THROWS_AS(it1 >= it1, std::domain_error); + CHECK_THROWS_AS(it1 >= it2, std::domain_error); + CHECK_THROWS_AS(it2 >= it3, std::domain_error); + CHECK_THROWS_AS(it1 >= it3, std::domain_error); + CHECK_THROWS_AS(it1_c >= it1_c, std::domain_error); + CHECK_THROWS_AS(it1_c >= it2_c, std::domain_error); + CHECK_THROWS_AS(it2_c >= it3_c, std::domain_error); + CHECK_THROWS_AS(it1_c >= it3_c, std::domain_error); + CHECK_THROWS_WITH(it1 >= it1, "cannot compare order of object iterators"); + CHECK_THROWS_WITH(it1 >= it2, "cannot compare order of object iterators"); + CHECK_THROWS_WITH(it2 >= it3, "cannot compare order of object iterators"); + CHECK_THROWS_WITH(it1 >= it3, "cannot compare order of object iterators"); + CHECK_THROWS_WITH(it1_c >= it1_c, "cannot compare order of object iterators"); + CHECK_THROWS_WITH(it1_c >= it2_c, "cannot compare order of object iterators"); + CHECK_THROWS_WITH(it2_c >= it3_c, "cannot compare order of object iterators"); + CHECK_THROWS_WITH(it1_c >= it3_c, "cannot compare order of object iterators"); + } + else + { + // check definition + CHECK( (it1 >= it1) == not(it1 < it1) ); + CHECK( (it1 >= it2) == not(it1 < it2) ); + CHECK( (it1 >= it3) == not(it1 < it3) ); + CHECK( (it2 >= it3) == not(it2 < it3) ); + CHECK( (it1_c >= it1_c) == not(it1_c < it1_c) ); + CHECK( (it1_c >= it2_c) == not(it1_c < it2_c) ); + CHECK( (it1_c >= it3_c) == not(it1_c < it3_c) ); + CHECK( (it2_c >= it3_c) == not(it2_c < it3_c) ); + } + } + } + + // check exceptions if different objects are compared + for (auto j : j_values) + { + for (auto k : j_values) + { + if (j != k) + { + CHECK_THROWS_AS(j.rbegin() == k.rbegin(), std::domain_error); + CHECK_THROWS_AS(j.crbegin() == k.crbegin(), std::domain_error); + CHECK_THROWS_WITH(j.rbegin() == k.rbegin(), "cannot compare iterators of different containers"); + CHECK_THROWS_WITH(j.crbegin() == k.crbegin(), "cannot compare iterators of different containers"); + + CHECK_THROWS_AS(j.rbegin() < k.rbegin(), std::domain_error); + CHECK_THROWS_AS(j.crbegin() < k.crbegin(), std::domain_error); + CHECK_THROWS_WITH(j.rbegin() < k.rbegin(), "cannot compare iterators of different containers"); + CHECK_THROWS_WITH(j.crbegin() < k.crbegin(), "cannot compare iterators of different containers"); + } + } + } + } + + SECTION("reverse iterator arithmetic") + { + json j_object = {{"one", 1}, {"two", 2}, {"three", 3}}; + json j_array = {1, 2, 3, 4, 5, 6}; + json j_null = nullptr; + json j_value = 42; + + SECTION("addition and subtraction") + { + SECTION("object") + { + { + auto it = j_object.rbegin(); + CHECK_THROWS_AS(it += 1, std::domain_error); + CHECK_THROWS_WITH(it += 1, "cannot use offsets with object iterators"); + } + { + auto it = j_object.crbegin(); + CHECK_THROWS_AS(it += 1, std::domain_error); + CHECK_THROWS_WITH(it += 1, "cannot use offsets with object iterators"); + } + { + auto it = j_object.rbegin(); + CHECK_THROWS_AS(it + 1, std::domain_error); + CHECK_THROWS_WITH(it + 1, "cannot use offsets with object iterators"); + } + { + auto it = j_object.crbegin(); + CHECK_THROWS_AS(it + 1, std::domain_error); + CHECK_THROWS_WITH(it + 1, "cannot use offsets with object iterators"); + } + { + auto it = j_object.rbegin(); + CHECK_THROWS_AS(it -= 1, std::domain_error); + CHECK_THROWS_WITH(it -= 1, "cannot use offsets with object iterators"); + } + { + auto it = j_object.crbegin(); + CHECK_THROWS_AS(it -= 1, std::domain_error); + CHECK_THROWS_WITH(it -= 1, "cannot use offsets with object iterators"); + } + { + auto it = j_object.rbegin(); + CHECK_THROWS_AS(it - 1, std::domain_error); + CHECK_THROWS_WITH(it - 1, "cannot use offsets with object iterators"); + } + { + auto it = j_object.crbegin(); + CHECK_THROWS_AS(it - 1, std::domain_error); + CHECK_THROWS_WITH(it - 1, "cannot use offsets with object iterators"); + } + { + auto it = j_object.rbegin(); + CHECK_THROWS_AS(it - it, std::domain_error); + CHECK_THROWS_WITH(it - it, "cannot use offsets with object iterators"); + } + { + auto it = j_object.crbegin(); + CHECK_THROWS_AS(it - it, std::domain_error); + CHECK_THROWS_WITH(it - it, "cannot use offsets with object iterators"); + } + } + + SECTION("array") + { + { + auto it = j_array.rbegin(); + it += 3; + CHECK((j_array.rbegin() + 3) == it); + CHECK((it - 3) == j_array.rbegin()); + CHECK((j_array.rbegin() - it) == 3); + CHECK(*it == json(3)); + it -= 2; + CHECK(*it == json(5)); + } + { + auto it = j_array.crbegin(); + it += 3; + CHECK((j_array.crbegin() + 3) == it); + CHECK((it - 3) == j_array.crbegin()); + CHECK((j_array.crbegin() - it) == 3); + CHECK(*it == json(3)); + it -= 2; + CHECK(*it == json(5)); + } + } + + SECTION("null") + { + { + auto it = j_null.rbegin(); + it += 3; + CHECK((j_null.rbegin() + 3) == it); + CHECK((it - 3) == j_null.rbegin()); + CHECK((j_null.rbegin() - it) == 3); + CHECK(it != j_null.rend()); + it -= 3; + CHECK(it == j_null.rend()); + } + { + auto it = j_null.crbegin(); + it += 3; + CHECK((j_null.crbegin() + 3) == it); + CHECK((it - 3) == j_null.crbegin()); + CHECK((j_null.crbegin() - it) == 3); + CHECK(it != j_null.crend()); + it -= 3; + CHECK(it == j_null.crend()); + } + } + + SECTION("value") + { + { + auto it = j_value.rbegin(); + it += 3; + CHECK((j_value.rbegin() + 3) == it); + CHECK((it - 3) == j_value.rbegin()); + CHECK((j_value.rbegin() - it) == 3); + CHECK(it != j_value.rend()); + it -= 3; + CHECK(*it == json(42)); + } + { + auto it = j_value.crbegin(); + it += 3; + CHECK((j_value.crbegin() + 3) == it); + CHECK((it - 3) == j_value.crbegin()); + CHECK((j_value.crbegin() - it) == 3); + CHECK(it != j_value.crend()); + it -= 3; + CHECK(*it == json(42)); + } + } + } + + SECTION("subscript operator") + { + SECTION("object") + { + { + auto it = j_object.rbegin(); + CHECK_THROWS_AS(it[0], std::domain_error); + CHECK_THROWS_AS(it[1], std::domain_error); + CHECK_THROWS_WITH(it[0], "cannot use offsets with object iterators"); + CHECK_THROWS_WITH(it[1], "cannot use offsets with object iterators"); + } + { + auto it = j_object.crbegin(); + CHECK_THROWS_AS(it[0], std::domain_error); + CHECK_THROWS_AS(it[1], std::domain_error); + CHECK_THROWS_WITH(it[0], "cannot use offsets with object iterators"); + CHECK_THROWS_WITH(it[1], "cannot use offsets with object iterators"); + } + } + + SECTION("array") + { + { + auto it = j_array.rbegin(); + CHECK(it[0] == json(6)); + CHECK(it[1] == json(5)); + CHECK(it[2] == json(4)); + CHECK(it[3] == json(3)); + CHECK(it[4] == json(2)); + CHECK(it[5] == json(1)); + } + { + auto it = j_array.crbegin(); + CHECK(it[0] == json(6)); + CHECK(it[1] == json(5)); + CHECK(it[2] == json(4)); + CHECK(it[3] == json(3)); + CHECK(it[4] == json(2)); + CHECK(it[5] == json(1)); + } + } + + SECTION("null") + { + { + auto it = j_null.rbegin(); + CHECK_THROWS_AS(it[0], std::out_of_range); + CHECK_THROWS_AS(it[1], std::out_of_range); + CHECK_THROWS_WITH(it[0], "cannot get value"); + CHECK_THROWS_WITH(it[1], "cannot get value"); + } + { + auto it = j_null.crbegin(); + CHECK_THROWS_AS(it[0], std::out_of_range); + CHECK_THROWS_AS(it[1], std::out_of_range); + CHECK_THROWS_WITH(it[0], "cannot get value"); + CHECK_THROWS_WITH(it[1], "cannot get value"); + } + } + + SECTION("value") + { + { + auto it = j_value.rbegin(); + CHECK(it[0] == json(42)); + CHECK_THROWS_AS(it[1], std::out_of_range); + CHECK_THROWS_WITH(it[1], "cannot get value"); + } + { + auto it = j_value.crbegin(); + CHECK(it[0] == json(42)); + CHECK_THROWS_AS(it[1], std::out_of_range); + CHECK_THROWS_WITH(it[1], "cannot get value"); + } + } + } + } +}