split test suite in one file per test case
This commit is contained in:
parent
3944ecd470
commit
d80329034e
31 changed files with 15291 additions and 14386 deletions
3
Makefile
3
Makefile
|
@ -79,7 +79,8 @@ pretty:
|
|||
--indent-col1-comments --pad-oper --pad-header --align-pointer=type \
|
||||
--align-reference=type --add-brackets --convert-tabs --close-templates \
|
||||
--lineend=linux --preserve-date --suffix=none --formatted \
|
||||
src/json.hpp src/json.hpp.re2c test/src/unit.cpp test/src/fuzz.cpp benchmarks/benchmarks.cpp doc/examples/*.cpp
|
||||
src/json.hpp src/json.hpp.re2c test/src/*.cpp \
|
||||
benchmarks/benchmarks.cpp doc/examples/*.cpp
|
||||
|
||||
|
||||
##########################################################################
|
||||
|
|
|
@ -3,7 +3,33 @@ set(JSON_UNITTEST_TARGET_NAME "json_unit")
|
|||
add_executable(${JSON_UNITTEST_TARGET_NAME}
|
||||
"src/catch.hpp"
|
||||
"src/unit.cpp"
|
||||
"src/unit-runner.cpp"
|
||||
"src/unit-algorithms.cpp"
|
||||
"src/unit-allocator.cpp"
|
||||
"src/unit-capacity.cpp"
|
||||
"src/unit-class_const_iterator.cpp"
|
||||
"src/unit-class_iterator.cpp"
|
||||
"src/unit-class_lexer.cpp"
|
||||
"src/unit-class_parser.cpp"
|
||||
"src/unit-comparison.cpp"
|
||||
"src/unit-concepts.cpp"
|
||||
"src/unit-constructor.cpp"
|
||||
"src/unit-convenience.cpp"
|
||||
"src/unit-conversions.cpp"
|
||||
"src/unit-deserialization.cpp"
|
||||
"src/unit-element_access.cpp"
|
||||
"src/unit-inspection.cpp"
|
||||
"src/unit-iterator_wrapper.cpp"
|
||||
"src/unit-iterators.cpp"
|
||||
"src/unit-json_patch.cpp"
|
||||
"src/unit-json_pointer.cpp"
|
||||
"src/unit-modifiers.cpp"
|
||||
"src/unit-pointer_access.cpp"
|
||||
"src/unit-readme.cpp"
|
||||
"src/unit-reference_access.cpp"
|
||||
"src/unit-regression.cpp"
|
||||
"src/unit-serialization.cpp"
|
||||
"src/unit-testsuites.cpp"
|
||||
"src/unit-unicode.cpp"
|
||||
)
|
||||
|
||||
set_target_properties(${JSON_UNITTEST_TARGET_NAME} PROPERTIES
|
||||
|
|
|
@ -3,19 +3,49 @@
|
|||
##########################################################################
|
||||
|
||||
# additional flags
|
||||
CXXFLAGS += -std=c++11 -Wall -Wextra -pedantic -Weffc++ -Wcast-align -Wcast-qual -Wctor-dtor-privacy -Wdisabled-optimization -Wformat=2 -Winit-self -Wmissing-declarations -Wmissing-include-dirs -Wold-style-cast -Woverloaded-virtual -Wredundant-decls -Wshadow -Wsign-conversion -Wsign-promo -Wstrict-overflow=5 -Wswitch -Wundef -Wno-unused -Wnon-virtual-dtor -Wreorder -Wdeprecated -Wfloat-equal
|
||||
CXXFLAGS += -std=c++11 -Wall -Wextra -pedantic -Weffc++ -Wcast-align -Wcast-qual -Wctor-dtor-privacy -Wdisabled-optimization -Wformat=2 -Winit-self -Wmissing-declarations -Wmissing-include-dirs -Wold-style-cast -Woverloaded-virtual -Wredundant-decls -Wshadow -Wsign-conversion -Wsign-promo -Wstrict-overflow=5 -Wswitch -Wundef -Wno-unused -Wnon-virtual-dtor -Wreorder -Wdeprecated -Wno-keyword-macro -Wno-float-equal
|
||||
CPPFLAGS += -I ../src -I .
|
||||
|
||||
SOURCES = src/unit-runner.cpp src/unit.cpp
|
||||
SOURCES = src/unit.cpp \
|
||||
src/unit-algorithms.cpp \
|
||||
src/unit-allocator.cpp \
|
||||
src/unit-capacity.cpp \
|
||||
src/unit-class_const_iterator.cpp \
|
||||
src/unit-class_iterator.cpp \
|
||||
src/unit-class_lexer.cpp \
|
||||
src/unit-class_parser.cpp \
|
||||
src/unit-comparison.cpp \
|
||||
src/unit-concepts.cpp \
|
||||
src/unit-constructor.cpp \
|
||||
src/unit-convenience.cpp \
|
||||
src/unit-conversions.cpp \
|
||||
src/unit-deserialization.cpp \
|
||||
src/unit-element_access.cpp \
|
||||
src/unit-inspection.cpp \
|
||||
src/unit-iterator_wrapper.cpp \
|
||||
src/unit-iterators.cpp \
|
||||
src/unit-json_patch.cpp \
|
||||
src/unit-json_pointer.cpp \
|
||||
src/unit-modifiers.cpp \
|
||||
src/unit-pointer_access.cpp \
|
||||
src/unit-readme.cpp \
|
||||
src/unit-reference_access.cpp \
|
||||
src/unit-regression.cpp \
|
||||
src/unit-serialization.cpp \
|
||||
src/unit-unicode.cpp \
|
||||
src/unit-testsuites.cpp
|
||||
|
||||
OBJECTS = $(SOURCES:.cpp=.o)
|
||||
|
||||
all: json_unit
|
||||
|
||||
json_unit: $(OBJECTS) ../src/json.hpp src/catch.hpp
|
||||
$(CXX) $(CXXFLAGS) $(LDFLAGS) $(OBJECTS) -o $@
|
||||
@echo "[CXXLD] $@"
|
||||
@$(CXX) $(CXXFLAGS) $(LDFLAGS) $(OBJECTS) -o $@
|
||||
|
||||
%.o: %.cpp
|
||||
$(CXX) $(CXXFLAGS) $(CPPFLAGS) -c $< -o $@
|
||||
%.o: %.cpp ../src/json.hpp src/catch.hpp
|
||||
@echo "[CXX] $@"
|
||||
@$(CXX) $(CXXFLAGS) $(CPPFLAGS) -c $< -o $@
|
||||
|
||||
clean:
|
||||
rm -fr json_unit $(OBJECTS)
|
||||
|
|
318
test/src/unit-algorithms.cpp
Normal file
318
test/src/unit-algorithms.cpp
Normal file
|
@ -0,0 +1,318 @@
|
|||
/*
|
||||
__ _____ _____ _____
|
||||
__| | __| | | | JSON for Modern C++ (test suite)
|
||||
| | |__ | | | | | | version 2.0.2
|
||||
|_____|_____|_____|_|___| https://github.com/nlohmann/json
|
||||
|
||||
Licensed under the MIT License <http://opensource.org/licenses/MIT>.
|
||||
Copyright (c) 2013-2016 Niels Lohmann <http://nlohmann.me>.
|
||||
|
||||
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("algorithms")
|
||||
{
|
||||
json j_array = {13, 29, 3, {{"one", 1}, {"two", 2}}, true, false, {1, 2, 3}, "foo", "baz"};
|
||||
json j_object = {{"one", 1}, {"two", 2}};
|
||||
|
||||
SECTION("non-modifying sequence operations")
|
||||
{
|
||||
SECTION("std::all_of")
|
||||
{
|
||||
CHECK(std::all_of(j_array.begin(), j_array.end(), [](const json & value)
|
||||
{
|
||||
return value.size() > 0;
|
||||
}));
|
||||
CHECK(std::all_of(j_object.begin(), j_object.end(), [](const json & value)
|
||||
{
|
||||
return value.type() == json::value_t::number_integer;
|
||||
}));
|
||||
}
|
||||
|
||||
SECTION("std::any_of")
|
||||
{
|
||||
CHECK(std::any_of(j_array.begin(), j_array.end(), [](const json & value)
|
||||
{
|
||||
return value.is_string() and value.get<std::string>() == "foo";
|
||||
}));
|
||||
CHECK(std::any_of(j_object.begin(), j_object.end(), [](const json & value)
|
||||
{
|
||||
return value.get<int>() > 1;
|
||||
}));
|
||||
}
|
||||
|
||||
SECTION("std::none_of")
|
||||
{
|
||||
CHECK(std::none_of(j_array.begin(), j_array.end(), [](const json & value)
|
||||
{
|
||||
return value.size() == 0;
|
||||
}));
|
||||
CHECK(std::none_of(j_object.begin(), j_object.end(), [](const json & value)
|
||||
{
|
||||
return value.get<int>() <= 0;
|
||||
}));
|
||||
}
|
||||
|
||||
SECTION("std::for_each")
|
||||
{
|
||||
SECTION("reading")
|
||||
{
|
||||
int sum = 0;
|
||||
|
||||
std::for_each(j_array.cbegin(), j_array.cend(), [&sum](const json & value)
|
||||
{
|
||||
if (value.is_number())
|
||||
{
|
||||
sum += static_cast<int>(value);
|
||||
}
|
||||
});
|
||||
|
||||
CHECK(sum == 45);
|
||||
}
|
||||
|
||||
SECTION("writing")
|
||||
{
|
||||
auto add17 = [](json & value)
|
||||
{
|
||||
if (value.is_array())
|
||||
{
|
||||
value.push_back(17);
|
||||
}
|
||||
};
|
||||
|
||||
std::for_each(j_array.begin(), j_array.end(), add17);
|
||||
|
||||
CHECK(j_array[6] == json({1, 2, 3, 17}));
|
||||
}
|
||||
}
|
||||
|
||||
SECTION("std::count")
|
||||
{
|
||||
CHECK(std::count(j_array.begin(), j_array.end(), json(true)) == 1);
|
||||
}
|
||||
|
||||
SECTION("std::count_if")
|
||||
{
|
||||
CHECK(std::count_if(j_array.begin(), j_array.end(), [](const json & value)
|
||||
{
|
||||
return (value.is_number());
|
||||
}) == 3);
|
||||
CHECK(std::count_if(j_array.begin(), j_array.end(), [](const json&)
|
||||
{
|
||||
return true;
|
||||
}) == 9);
|
||||
}
|
||||
|
||||
SECTION("std::mismatch")
|
||||
{
|
||||
json j_array2 = {13, 29, 3, {{"one", 1}, {"two", 2}, {"three", 3}}, true, false, {1, 2, 3}, "foo", "baz"};
|
||||
auto res = std::mismatch(j_array.begin(), j_array.end(), j_array2.begin());
|
||||
CHECK(*res.first == json({{"one", 1}, {"two", 2}}));
|
||||
CHECK(*res.second == json({{"one", 1}, {"two", 2}, {"three", 3}}));
|
||||
}
|
||||
|
||||
SECTION("std::equal")
|
||||
{
|
||||
SECTION("using operator==")
|
||||
{
|
||||
CHECK(std::equal(j_array.begin(), j_array.end(), j_array.begin()));
|
||||
CHECK(std::equal(j_object.begin(), j_object.end(), j_object.begin()));
|
||||
CHECK(not std::equal(j_array.begin(), j_array.end(), j_object.begin()));
|
||||
}
|
||||
|
||||
SECTION("using user-defined comparison")
|
||||
{
|
||||
// compare objects only by size of its elements
|
||||
json j_array2 = {13, 29, 3, {"Hello", "World"}, true, false, {{"one", 1}, {"two", 2}, {"three", 3}}, "foo", "baz"};
|
||||
CHECK(not std::equal(j_array.begin(), j_array.end(), j_array2.begin()));
|
||||
CHECK(std::equal(j_array.begin(), j_array.end(), j_array2.begin(),
|
||||
[](const json & a, const json & b)
|
||||
{
|
||||
return (a.size() == b.size());
|
||||
}));
|
||||
}
|
||||
}
|
||||
|
||||
SECTION("std::find")
|
||||
{
|
||||
auto it = std::find(j_array.begin(), j_array.end(), json(false));
|
||||
CHECK(std::distance(j_array.begin(), it) == 5);
|
||||
}
|
||||
|
||||
SECTION("std::find_if")
|
||||
{
|
||||
auto it = std::find_if(j_array.begin(), j_array.end(),
|
||||
[](const json & value)
|
||||
{
|
||||
return value.is_boolean();
|
||||
});
|
||||
CHECK(std::distance(j_array.begin(), it) == 4);
|
||||
}
|
||||
|
||||
SECTION("std::find_if_not")
|
||||
{
|
||||
auto it = std::find_if_not(j_array.begin(), j_array.end(),
|
||||
[](const json & value)
|
||||
{
|
||||
return value.is_number();
|
||||
});
|
||||
CHECK(std::distance(j_array.begin(), it) == 3);
|
||||
}
|
||||
|
||||
SECTION("std::adjacent_find")
|
||||
{
|
||||
CHECK(std::adjacent_find(j_array.begin(), j_array.end()) == j_array.end());
|
||||
CHECK(std::adjacent_find(j_array.begin(), j_array.end(),
|
||||
[](const json & v1, const json & v2)
|
||||
{
|
||||
return v1.type() == v2.type();
|
||||
}) == j_array.begin());
|
||||
}
|
||||
}
|
||||
|
||||
SECTION("modifying sequence operations")
|
||||
{
|
||||
SECTION("std::reverse")
|
||||
{
|
||||
std::reverse(j_array.begin(), j_array.end());
|
||||
CHECK(j_array == json({"baz", "foo", {1, 2, 3}, false, true, {{"one", 1}, {"two", 2}}, 3, 29, 13}));
|
||||
}
|
||||
|
||||
SECTION("std::rotate")
|
||||
{
|
||||
std::rotate(j_array.begin(), j_array.begin() + 1, j_array.end());
|
||||
CHECK(j_array == json({29, 3, {{"one", 1}, {"two", 2}}, true, false, {1, 2, 3}, "foo", "baz", 13}));
|
||||
}
|
||||
|
||||
SECTION("std::partition")
|
||||
{
|
||||
auto it = std::partition(j_array.begin(), j_array.end(), [](const json & v)
|
||||
{
|
||||
return v.is_string();
|
||||
});
|
||||
CHECK(std::distance(j_array.begin(), it) == 2);
|
||||
CHECK(not it[2].is_string());
|
||||
}
|
||||
}
|
||||
|
||||
SECTION("sorting operations")
|
||||
{
|
||||
SECTION("std::sort")
|
||||
{
|
||||
SECTION("with standard comparison")
|
||||
{
|
||||
json j = {13, 29, 3, {{"one", 1}, {"two", 2}}, true, false, {1, 2, 3}, "foo", "baz", nullptr};
|
||||
std::sort(j.begin(), j.end());
|
||||
CHECK(j == json({nullptr, false, true, 3, 13, 29, {{"one", 1}, {"two", 2}}, {1, 2, 3}, "baz", "foo"}));
|
||||
}
|
||||
|
||||
SECTION("with user-defined comparison")
|
||||
{
|
||||
json j = {3, {{"one", 1}, {"two", 2}}, {1, 2, 3}, nullptr};
|
||||
std::sort(j.begin(), j.end(), [](const json & a, const json & b)
|
||||
{
|
||||
return a.size() < b.size();
|
||||
});
|
||||
CHECK(j == json({nullptr, 3, {{"one", 1}, {"two", 2}}, {1, 2, 3}}));
|
||||
}
|
||||
|
||||
SECTION("sorting an object")
|
||||
{
|
||||
json j({{"one", 1}, {"two", 2}});
|
||||
CHECK_THROWS_AS(std::sort(j.begin(), j.end()), std::domain_error);
|
||||
CHECK_THROWS_WITH(std::sort(j.begin(), j.end()), "cannot use offsets with object iterators");
|
||||
}
|
||||
}
|
||||
|
||||
SECTION("std::partial_sort")
|
||||
{
|
||||
json j = {13, 29, 3, {{"one", 1}, {"two", 2}}, true, false, {1, 2, 3}, "foo", "baz", nullptr};
|
||||
std::partial_sort(j.begin(), j.begin() + 4, j.end());
|
||||
CHECK(j == json({nullptr, false, true, 3, {{"one", 1}, {"two", 2}}, 29, {1, 2, 3}, "foo", "baz", 13}));
|
||||
}
|
||||
}
|
||||
|
||||
SECTION("set operations")
|
||||
{
|
||||
SECTION("std::merge")
|
||||
{
|
||||
{
|
||||
json j1 = {2, 4, 6, 8};
|
||||
json j2 = {1, 2, 3, 5, 7};
|
||||
json j3;
|
||||
|
||||
std::merge(j1.begin(), j1.end(), j2.begin(), j2.end(), std::back_inserter(j3));
|
||||
CHECK(j3 == json({1, 2, 2, 3, 4, 5, 6, 7, 8}));
|
||||
}
|
||||
}
|
||||
|
||||
SECTION("std::set_difference")
|
||||
{
|
||||
json j1 = {1, 2, 3, 4, 5, 6, 7, 8};
|
||||
json j2 = {1, 2, 3, 5, 7};
|
||||
json j3;
|
||||
|
||||
std::set_difference(j1.begin(), j1.end(), j2.begin(), j2.end(), std::back_inserter(j3));
|
||||
CHECK(j3 == json({4, 6, 8}));
|
||||
}
|
||||
|
||||
SECTION("std::set_intersection")
|
||||
{
|
||||
json j1 = {1, 2, 3, 4, 5, 6, 7, 8};
|
||||
json j2 = {1, 2, 3, 5, 7};
|
||||
json j3;
|
||||
|
||||
std::set_intersection(j1.begin(), j1.end(), j2.begin(), j2.end(), std::back_inserter(j3));
|
||||
CHECK(j3 == json({1, 2, 3, 5, 7}));
|
||||
}
|
||||
|
||||
SECTION("std::set_union")
|
||||
{
|
||||
json j1 = {2, 4, 6, 8};
|
||||
json j2 = {1, 2, 3, 5, 7};
|
||||
json j3;
|
||||
|
||||
std::set_union(j1.begin(), j1.end(), j2.begin(), j2.end(), std::back_inserter(j3));
|
||||
CHECK(j3 == json({1, 2, 3, 4, 5, 6, 7, 8}));
|
||||
}
|
||||
|
||||
SECTION("std::set_symmetric_difference")
|
||||
{
|
||||
json j1 = {2, 4, 6, 8};
|
||||
json j2 = {1, 2, 3, 5, 7};
|
||||
json j3;
|
||||
|
||||
std::set_symmetric_difference(j1.begin(), j1.end(), j2.begin(), j2.end(), std::back_inserter(j3));
|
||||
CHECK(j3 == json({1, 3, 4, 5, 6, 7, 8}));
|
||||
}
|
||||
}
|
||||
|
||||
SECTION("heap operations")
|
||||
{
|
||||
std::make_heap(j_array.begin(), j_array.end());
|
||||
CHECK(std::is_heap(j_array.begin(), j_array.end()));
|
||||
std::sort_heap(j_array.begin(), j_array.end());
|
||||
CHECK(j_array == json({false, true, 3, 13, 29, {{"one", 1}, {"two", 2}}, {1, 2, 3}, "baz", "foo"}));
|
||||
}
|
||||
}
|
|
@ -26,5 +26,38 @@ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|||
SOFTWARE.
|
||||
*/
|
||||
|
||||
#define CATCH_CONFIG_MAIN
|
||||
#include "catch.hpp"
|
||||
|
||||
#include "json.hpp"
|
||||
using nlohmann::json;
|
||||
|
||||
// special test case to check if memory is leaked if constructor throws
|
||||
|
||||
template<class T>
|
||||
struct my_allocator : std::allocator<T>
|
||||
{
|
||||
template<class... Args>
|
||||
void construct(T*, Args&& ...)
|
||||
{
|
||||
throw std::bad_alloc();
|
||||
}
|
||||
};
|
||||
|
||||
TEST_CASE("bad_alloc")
|
||||
{
|
||||
SECTION("bad_alloc")
|
||||
{
|
||||
// create JSON type using the throwing allocator
|
||||
using my_json = nlohmann::basic_json<std::map,
|
||||
std::vector,
|
||||
std::string,
|
||||
bool,
|
||||
std::int64_t,
|
||||
std::uint64_t,
|
||||
double,
|
||||
my_allocator>;
|
||||
|
||||
// creating an object should throw
|
||||
CHECK_THROWS_AS(my_json j(my_json::value_t::object), std::bad_alloc);
|
||||
}
|
||||
}
|
562
test/src/unit-capacity.cpp
Normal file
562
test/src/unit-capacity.cpp
Normal file
|
@ -0,0 +1,562 @@
|
|||
/*
|
||||
__ _____ _____ _____
|
||||
__| | __| | | | JSON for Modern C++ (test suite)
|
||||
| | |__ | | | | | | version 2.0.2
|
||||
|_____|_____|_____|_|___| https://github.com/nlohmann/json
|
||||
|
||||
Licensed under the MIT License <http://opensource.org/licenses/MIT>.
|
||||
Copyright (c) 2013-2016 Niels Lohmann <http://nlohmann.me>.
|
||||
|
||||
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("capacity")
|
||||
{
|
||||
SECTION("empty()")
|
||||
{
|
||||
SECTION("boolean")
|
||||
{
|
||||
json j = true;
|
||||
json j_const(j);
|
||||
|
||||
SECTION("result of empty")
|
||||
{
|
||||
CHECK(j.empty() == false);
|
||||
CHECK(j_const.empty() == false);
|
||||
}
|
||||
|
||||
SECTION("definition of empty")
|
||||
{
|
||||
CHECK(j.begin() != j.end());
|
||||
CHECK(j_const.begin() != j_const.end());
|
||||
}
|
||||
}
|
||||
|
||||
SECTION("string")
|
||||
{
|
||||
json j = "hello world";
|
||||
json j_const(j);
|
||||
|
||||
SECTION("result of empty")
|
||||
{
|
||||
CHECK(j.empty() == false);
|
||||
CHECK(j_const.empty() == false);
|
||||
}
|
||||
|
||||
SECTION("definition of empty")
|
||||
{
|
||||
CHECK(j.begin() != j.end());
|
||||
CHECK(j_const.begin() != j_const.end());
|
||||
}
|
||||
}
|
||||
|
||||
SECTION("array")
|
||||
{
|
||||
SECTION("empty array")
|
||||
{
|
||||
json j = json::array();
|
||||
json j_const(j);
|
||||
|
||||
SECTION("result of empty")
|
||||
{
|
||||
CHECK(j.empty() == true);
|
||||
CHECK(j_const.empty() == true);
|
||||
}
|
||||
|
||||
SECTION("definition of empty")
|
||||
{
|
||||
CHECK(j.begin() == j.end());
|
||||
CHECK(j_const.begin() == j_const.end());
|
||||
}
|
||||
}
|
||||
|
||||
SECTION("filled array")
|
||||
{
|
||||
json j = {1, 2, 3};
|
||||
json j_const(j);
|
||||
|
||||
SECTION("result of empty")
|
||||
{
|
||||
CHECK(j.empty() == false);
|
||||
CHECK(j_const.empty() == false);
|
||||
}
|
||||
|
||||
SECTION("definition of empty")
|
||||
{
|
||||
CHECK(j.begin() != j.end());
|
||||
CHECK(j_const.begin() != j_const.end());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
SECTION("object")
|
||||
{
|
||||
SECTION("empty object")
|
||||
{
|
||||
json j = json::object();
|
||||
json j_const(j);
|
||||
|
||||
SECTION("result of empty")
|
||||
{
|
||||
CHECK(j.empty() == true);
|
||||
CHECK(j_const.empty() == true);
|
||||
}
|
||||
|
||||
SECTION("definition of empty")
|
||||
{
|
||||
CHECK(j.begin() == j.end());
|
||||
CHECK(j_const.begin() == j_const.end());
|
||||
}
|
||||
}
|
||||
|
||||
SECTION("filled object")
|
||||
{
|
||||
json j = {{"one", 1}, {"two", 2}, {"three", 3}};
|
||||
json j_const(j);
|
||||
|
||||
SECTION("result of empty")
|
||||
{
|
||||
CHECK(j.empty() == false);
|
||||
CHECK(j_const.empty() == false);
|
||||
}
|
||||
|
||||
SECTION("definition of empty")
|
||||
{
|
||||
CHECK(j.begin() != j.end());
|
||||
CHECK(j_const.begin() != j_const.end());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
SECTION("number (integer)")
|
||||
{
|
||||
json j = 23;
|
||||
json j_const(j);
|
||||
|
||||
SECTION("result of empty")
|
||||
{
|
||||
CHECK(j.empty() == false);
|
||||
CHECK(j_const.empty() == false);
|
||||
}
|
||||
|
||||
SECTION("definition of empty")
|
||||
{
|
||||
CHECK(j.begin() != j.end());
|
||||
CHECK(j_const.begin() != j_const.end());
|
||||
}
|
||||
}
|
||||
|
||||
SECTION("number (unsigned)")
|
||||
{
|
||||
json j = 23u;
|
||||
json j_const(j);
|
||||
|
||||
SECTION("result of empty")
|
||||
{
|
||||
CHECK(j.empty() == false);
|
||||
CHECK(j_const.empty() == false);
|
||||
}
|
||||
|
||||
SECTION("definition of empty")
|
||||
{
|
||||
CHECK(j.begin() != j.end());
|
||||
CHECK(j_const.begin() != j_const.end());
|
||||
}
|
||||
}
|
||||
|
||||
SECTION("number (float)")
|
||||
{
|
||||
json j = 23.42;
|
||||
json j_const(j);
|
||||
|
||||
SECTION("result of empty")
|
||||
{
|
||||
CHECK(j.empty() == false);
|
||||
CHECK(j_const.empty() == false);
|
||||
}
|
||||
|
||||
SECTION("definition of empty")
|
||||
{
|
||||
CHECK(j.begin() != j.end());
|
||||
CHECK(j_const.begin() != j_const.end());
|
||||
}
|
||||
}
|
||||
|
||||
SECTION("null")
|
||||
{
|
||||
json j = nullptr;
|
||||
json j_const(j);
|
||||
|
||||
SECTION("result of empty")
|
||||
{
|
||||
CHECK(j.empty() == true);
|
||||
CHECK(j_const.empty() == true);
|
||||
}
|
||||
|
||||
SECTION("definition of empty")
|
||||
{
|
||||
CHECK(j.begin() == j.end());
|
||||
CHECK(j_const.begin() == j_const.end());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
SECTION("size()")
|
||||
{
|
||||
SECTION("boolean")
|
||||
{
|
||||
json j = true;
|
||||
json j_const(j);
|
||||
|
||||
SECTION("result of size")
|
||||
{
|
||||
CHECK(j.size() == 1);
|
||||
CHECK(j_const.size() == 1);
|
||||
}
|
||||
|
||||
SECTION("definition of size")
|
||||
{
|
||||
CHECK(std::distance(j.begin(), j.end()) == j.size());
|
||||
CHECK(std::distance(j_const.begin(), j_const.end()) == j_const.size());
|
||||
CHECK(std::distance(j.rbegin(), j.rend()) == j.size());
|
||||
CHECK(std::distance(j_const.crbegin(), j_const.crend()) == j_const.size());
|
||||
}
|
||||
}
|
||||
|
||||
SECTION("string")
|
||||
{
|
||||
json j = "hello world";
|
||||
json j_const(j);
|
||||
|
||||
SECTION("result of size")
|
||||
{
|
||||
CHECK(j.size() == 1);
|
||||
CHECK(j_const.size() == 1);
|
||||
}
|
||||
|
||||
SECTION("definition of size")
|
||||
{
|
||||
CHECK(std::distance(j.begin(), j.end()) == j.size());
|
||||
CHECK(std::distance(j_const.begin(), j_const.end()) == j_const.size());
|
||||
CHECK(std::distance(j.rbegin(), j.rend()) == j.size());
|
||||
CHECK(std::distance(j_const.crbegin(), j_const.crend()) == j_const.size());
|
||||
}
|
||||
}
|
||||
|
||||
SECTION("array")
|
||||
{
|
||||
SECTION("empty array")
|
||||
{
|
||||
json j = json::array();
|
||||
json j_const(j);
|
||||
|
||||
SECTION("result of size")
|
||||
{
|
||||
CHECK(j.size() == 0);
|
||||
CHECK(j_const.size() == 0);
|
||||
}
|
||||
|
||||
SECTION("definition of size")
|
||||
{
|
||||
CHECK(std::distance(j.begin(), j.end()) == j.size());
|
||||
CHECK(std::distance(j_const.begin(), j_const.end()) == j_const.size());
|
||||
CHECK(std::distance(j.rbegin(), j.rend()) == j.size());
|
||||
CHECK(std::distance(j_const.crbegin(), j_const.crend()) == j_const.size());
|
||||
}
|
||||
}
|
||||
|
||||
SECTION("filled array")
|
||||
{
|
||||
json j = {1, 2, 3};
|
||||
json j_const(j);
|
||||
|
||||
SECTION("result of size")
|
||||
{
|
||||
CHECK(j.size() == 3);
|
||||
CHECK(j_const.size() == 3);
|
||||
}
|
||||
|
||||
SECTION("definition of size")
|
||||
{
|
||||
CHECK(std::distance(j.begin(), j.end()) == j.size());
|
||||
CHECK(std::distance(j_const.begin(), j_const.end()) == j_const.size());
|
||||
CHECK(std::distance(j.rbegin(), j.rend()) == j.size());
|
||||
CHECK(std::distance(j_const.crbegin(), j_const.crend()) == j_const.size());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
SECTION("object")
|
||||
{
|
||||
SECTION("empty object")
|
||||
{
|
||||
json j = json::object();
|
||||
json j_const(j);
|
||||
|
||||
SECTION("result of size")
|
||||
{
|
||||
CHECK(j.size() == 0);
|
||||
CHECK(j_const.size() == 0);
|
||||
}
|
||||
|
||||
SECTION("definition of size")
|
||||
{
|
||||
CHECK(std::distance(j.begin(), j.end()) == j.size());
|
||||
CHECK(std::distance(j_const.begin(), j_const.end()) == j_const.size());
|
||||
CHECK(std::distance(j.rbegin(), j.rend()) == j.size());
|
||||
CHECK(std::distance(j_const.crbegin(), j_const.crend()) == j_const.size());
|
||||
}
|
||||
}
|
||||
|
||||
SECTION("filled object")
|
||||
{
|
||||
json j = {{"one", 1}, {"two", 2}, {"three", 3}};
|
||||
json j_const(j);
|
||||
|
||||
SECTION("result of size")
|
||||
{
|
||||
CHECK(j.size() == 3);
|
||||
CHECK(j_const.size() == 3);
|
||||
}
|
||||
|
||||
SECTION("definition of size")
|
||||
{
|
||||
CHECK(std::distance(j.begin(), j.end()) == j.size());
|
||||
CHECK(std::distance(j_const.begin(), j_const.end()) == j_const.size());
|
||||
CHECK(std::distance(j.rbegin(), j.rend()) == j.size());
|
||||
CHECK(std::distance(j_const.crbegin(), j_const.crend()) == j_const.size());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
SECTION("number (integer)")
|
||||
{
|
||||
json j = 23;
|
||||
json j_const(j);
|
||||
|
||||
SECTION("result of size")
|
||||
{
|
||||
CHECK(j.size() == 1);
|
||||
CHECK(j_const.size() == 1);
|
||||
}
|
||||
|
||||
SECTION("definition of size")
|
||||
{
|
||||
CHECK(std::distance(j.begin(), j.end()) == j.size());
|
||||
CHECK(std::distance(j_const.begin(), j_const.end()) == j_const.size());
|
||||
CHECK(std::distance(j.rbegin(), j.rend()) == j.size());
|
||||
CHECK(std::distance(j_const.crbegin(), j_const.crend()) == j_const.size());
|
||||
}
|
||||
}
|
||||
|
||||
SECTION("number (unsigned)")
|
||||
{
|
||||
json j = 23u;
|
||||
json j_const(j);
|
||||
|
||||
SECTION("result of size")
|
||||
{
|
||||
CHECK(j.size() == 1);
|
||||
CHECK(j_const.size() == 1);
|
||||
}
|
||||
|
||||
SECTION("definition of size")
|
||||
{
|
||||
CHECK(std::distance(j.begin(), j.end()) == j.size());
|
||||
CHECK(std::distance(j_const.begin(), j_const.end()) == j_const.size());
|
||||
CHECK(std::distance(j.rbegin(), j.rend()) == j.size());
|
||||
CHECK(std::distance(j_const.crbegin(), j_const.crend()) == j_const.size());
|
||||
}
|
||||
}
|
||||
|
||||
SECTION("number (float)")
|
||||
{
|
||||
json j = 23.42;
|
||||
json j_const(j);
|
||||
|
||||
SECTION("result of size")
|
||||
{
|
||||
CHECK(j.size() == 1);
|
||||
CHECK(j_const.size() == 1);
|
||||
}
|
||||
|
||||
SECTION("definition of size")
|
||||
{
|
||||
CHECK(std::distance(j.begin(), j.end()) == j.size());
|
||||
CHECK(std::distance(j_const.begin(), j_const.end()) == j_const.size());
|
||||
CHECK(std::distance(j.rbegin(), j.rend()) == j.size());
|
||||
CHECK(std::distance(j_const.crbegin(), j_const.crend()) == j_const.size());
|
||||
}
|
||||
}
|
||||
|
||||
SECTION("null")
|
||||
{
|
||||
json j = nullptr;
|
||||
json j_const(j);
|
||||
|
||||
SECTION("result of size")
|
||||
{
|
||||
CHECK(j.size() == 0);
|
||||
CHECK(j_const.size() == 0);
|
||||
}
|
||||
|
||||
SECTION("definition of size")
|
||||
{
|
||||
CHECK(std::distance(j.begin(), j.end()) == j.size());
|
||||
CHECK(std::distance(j_const.begin(), j_const.end()) == j_const.size());
|
||||
CHECK(std::distance(j.rbegin(), j.rend()) == j.size());
|
||||
CHECK(std::distance(j_const.crbegin(), j_const.crend()) == j_const.size());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
SECTION("max_size()")
|
||||
{
|
||||
SECTION("boolean")
|
||||
{
|
||||
json j = true;
|
||||
json j_const(j);
|
||||
|
||||
SECTION("result of max_size")
|
||||
{
|
||||
CHECK(j.max_size() == 1);
|
||||
CHECK(j_const.max_size() == 1);
|
||||
}
|
||||
}
|
||||
|
||||
SECTION("string")
|
||||
{
|
||||
json j = "hello world";
|
||||
json j_const(j);
|
||||
|
||||
SECTION("result of max_size")
|
||||
{
|
||||
CHECK(j.max_size() == 1);
|
||||
CHECK(j_const.max_size() == 1);
|
||||
}
|
||||
}
|
||||
|
||||
SECTION("array")
|
||||
{
|
||||
SECTION("empty array")
|
||||
{
|
||||
json j = json::array();
|
||||
json j_const(j);
|
||||
|
||||
SECTION("result of max_size")
|
||||
{
|
||||
CHECK(j.max_size() >= j.size());
|
||||
CHECK(j_const.max_size() >= j_const.size());
|
||||
}
|
||||
}
|
||||
|
||||
SECTION("filled array")
|
||||
{
|
||||
json j = {1, 2, 3};
|
||||
json j_const(j);
|
||||
|
||||
SECTION("result of max_size")
|
||||
{
|
||||
CHECK(j.max_size() >= j.size());
|
||||
CHECK(j_const.max_size() >= j_const.size());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
SECTION("object")
|
||||
{
|
||||
SECTION("empty object")
|
||||
{
|
||||
json j = json::object();
|
||||
json j_const(j);
|
||||
|
||||
SECTION("result of max_size")
|
||||
{
|
||||
CHECK(j.max_size() >= j.size());
|
||||
CHECK(j_const.max_size() >= j_const.size());
|
||||
}
|
||||
}
|
||||
|
||||
SECTION("filled object")
|
||||
{
|
||||
json j = {{"one", 1}, {"two", 2}, {"three", 3}};
|
||||
json j_const(j);
|
||||
|
||||
SECTION("result of max_size")
|
||||
{
|
||||
CHECK(j.max_size() >= j.size());
|
||||
CHECK(j_const.max_size() >= j_const.size());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
SECTION("number (integer)")
|
||||
{
|
||||
json j = 23;
|
||||
json j_const(j);
|
||||
|
||||
SECTION("result of max_size")
|
||||
{
|
||||
CHECK(j.max_size() == 1);
|
||||
CHECK(j_const.max_size() == 1);
|
||||
}
|
||||
}
|
||||
|
||||
SECTION("number (unsigned)")
|
||||
{
|
||||
json j = 23u;
|
||||
json j_const(j);
|
||||
|
||||
SECTION("result of max_size")
|
||||
{
|
||||
CHECK(j.max_size() == 1);
|
||||
CHECK(j_const.max_size() == 1);
|
||||
}
|
||||
}
|
||||
|
||||
SECTION("number (float)")
|
||||
{
|
||||
json j = 23.42;
|
||||
json j_const(j);
|
||||
|
||||
SECTION("result of max_size")
|
||||
{
|
||||
CHECK(j.max_size() == 1);
|
||||
CHECK(j_const.max_size() == 1);
|
||||
}
|
||||
}
|
||||
|
||||
SECTION("null")
|
||||
{
|
||||
json j = nullptr;
|
||||
json j_const(j);
|
||||
|
||||
SECTION("result of max_size")
|
||||
{
|
||||
CHECK(j.max_size() == 0);
|
||||
CHECK(j_const.max_size() == 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
401
test/src/unit-class_const_iterator.cpp
Normal file
401
test/src/unit-class_const_iterator.cpp
Normal file
|
@ -0,0 +1,401 @@
|
|||
/*
|
||||
__ _____ _____ _____
|
||||
__| | __| | | | JSON for Modern C++ (test suite)
|
||||
| | |__ | | | | | | version 2.0.2
|
||||
|_____|_____|_____|_|___| https://github.com/nlohmann/json
|
||||
|
||||
Licensed under the MIT License <http://opensource.org/licenses/MIT>.
|
||||
Copyright (c) 2013-2016 Niels Lohmann <http://nlohmann.me>.
|
||||
|
||||
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"
|
||||
|
||||
#define private public
|
||||
#include "json.hpp"
|
||||
using nlohmann::json;
|
||||
|
||||
TEST_CASE("const_iterator class")
|
||||
{
|
||||
SECTION("construction")
|
||||
{
|
||||
SECTION("constructor")
|
||||
{
|
||||
SECTION("null")
|
||||
{
|
||||
json j(json::value_t::null);
|
||||
json::const_iterator it(&j);
|
||||
}
|
||||
|
||||
SECTION("object")
|
||||
{
|
||||
json j(json::value_t::object);
|
||||
json::const_iterator it(&j);
|
||||
}
|
||||
|
||||
SECTION("array")
|
||||
{
|
||||
json j(json::value_t::array);
|
||||
json::const_iterator it(&j);
|
||||
}
|
||||
}
|
||||
|
||||
SECTION("copy assignment")
|
||||
{
|
||||
json j(json::value_t::null);
|
||||
json::const_iterator it(&j);
|
||||
json::const_iterator it2(&j);
|
||||
it2 = it;
|
||||
}
|
||||
}
|
||||
|
||||
SECTION("initialization")
|
||||
{
|
||||
SECTION("set_begin")
|
||||
{
|
||||
SECTION("null")
|
||||
{
|
||||
json j(json::value_t::null);
|
||||
json::const_iterator it(&j);
|
||||
it.set_begin();
|
||||
CHECK(it == j.cbegin());
|
||||
}
|
||||
|
||||
SECTION("object")
|
||||
{
|
||||
json j(json::value_t::object);
|
||||
json::const_iterator it(&j);
|
||||
it.set_begin();
|
||||
CHECK(it == j.cbegin());
|
||||
}
|
||||
|
||||
SECTION("array")
|
||||
{
|
||||
json j(json::value_t::array);
|
||||
json::const_iterator it(&j);
|
||||
it.set_begin();
|
||||
CHECK(it == j.cbegin());
|
||||
}
|
||||
}
|
||||
|
||||
SECTION("set_end")
|
||||
{
|
||||
SECTION("null")
|
||||
{
|
||||
json j(json::value_t::null);
|
||||
json::const_iterator it(&j);
|
||||
it.set_end();
|
||||
CHECK(it == j.cend());
|
||||
}
|
||||
|
||||
SECTION("object")
|
||||
{
|
||||
json j(json::value_t::object);
|
||||
json::const_iterator it(&j);
|
||||
it.set_end();
|
||||
CHECK(it == j.cend());
|
||||
}
|
||||
|
||||
SECTION("array")
|
||||
{
|
||||
json j(json::value_t::array);
|
||||
json::const_iterator it(&j);
|
||||
it.set_end();
|
||||
CHECK(it == j.cend());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
SECTION("element access")
|
||||
{
|
||||
SECTION("operator*")
|
||||
{
|
||||
SECTION("null")
|
||||
{
|
||||
json j(json::value_t::null);
|
||||
json::const_iterator it = j.cbegin();
|
||||
CHECK_THROWS_AS(*it, std::out_of_range);
|
||||
CHECK_THROWS_WITH(*it, "cannot get value");
|
||||
}
|
||||
|
||||
SECTION("number")
|
||||
{
|
||||
json j(17);
|
||||
json::const_iterator it = j.cbegin();
|
||||
CHECK(*it == json(17));
|
||||
it = j.cend();
|
||||
CHECK_THROWS_AS(*it, std::out_of_range);
|
||||
CHECK_THROWS_WITH(*it, "cannot get value");
|
||||
}
|
||||
|
||||
SECTION("object")
|
||||
{
|
||||
json j({{"foo", "bar"}});
|
||||
json::const_iterator it = j.cbegin();
|
||||
CHECK(*it == json("bar"));
|
||||
}
|
||||
|
||||
SECTION("array")
|
||||
{
|
||||
json j({1, 2, 3, 4});
|
||||
json::const_iterator it = j.cbegin();
|
||||
CHECK(*it == json(1));
|
||||
}
|
||||
}
|
||||
|
||||
SECTION("operator->")
|
||||
{
|
||||
SECTION("null")
|
||||
{
|
||||
json j(json::value_t::null);
|
||||
json::const_iterator it = j.cbegin();
|
||||
CHECK_THROWS_AS(it->type_name(), std::out_of_range);
|
||||
CHECK_THROWS_WITH(it->type_name(), "cannot get value");
|
||||
}
|
||||
|
||||
SECTION("number")
|
||||
{
|
||||
json j(17);
|
||||
json::const_iterator it = j.cbegin();
|
||||
CHECK(it->type_name() == "number");
|
||||
it = j.cend();
|
||||
CHECK_THROWS_AS(it->type_name(), std::out_of_range);
|
||||
CHECK_THROWS_WITH(it->type_name(), "cannot get value");
|
||||
}
|
||||
|
||||
SECTION("object")
|
||||
{
|
||||
json j({{"foo", "bar"}});
|
||||
json::const_iterator it = j.cbegin();
|
||||
CHECK(it->type_name() == "string");
|
||||
}
|
||||
|
||||
SECTION("array")
|
||||
{
|
||||
json j({1, 2, 3, 4});
|
||||
json::const_iterator it = j.cbegin();
|
||||
CHECK(it->type_name() == "number");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
SECTION("increment/decrement")
|
||||
{
|
||||
SECTION("post-increment")
|
||||
{
|
||||
SECTION("null")
|
||||
{
|
||||
json j(json::value_t::null);
|
||||
json::const_iterator it = j.cbegin();
|
||||
CHECK(it.m_it.primitive_iterator == 1);
|
||||
it++;
|
||||
CHECK((it.m_it.primitive_iterator != 0 and it.m_it.primitive_iterator != 1));
|
||||
}
|
||||
|
||||
SECTION("number")
|
||||
{
|
||||
json j(17);
|
||||
json::const_iterator it = j.cbegin();
|
||||
CHECK(it.m_it.primitive_iterator == 0);
|
||||
it++;
|
||||
CHECK(it.m_it.primitive_iterator == 1);
|
||||
it++;
|
||||
CHECK((it.m_it.primitive_iterator != 0 and it.m_it.primitive_iterator != 1));
|
||||
}
|
||||
|
||||
SECTION("object")
|
||||
{
|
||||
json j({{"foo", "bar"}});
|
||||
json::const_iterator it = j.cbegin();
|
||||
CHECK(it.m_it.object_iterator == it.m_object->m_value.object->begin());
|
||||
it++;
|
||||
CHECK(it.m_it.object_iterator == it.m_object->m_value.object->end());
|
||||
}
|
||||
|
||||
SECTION("array")
|
||||
{
|
||||
json j({1, 2, 3, 4});
|
||||
json::const_iterator it = j.cbegin();
|
||||
CHECK(it.m_it.array_iterator == it.m_object->m_value.array->begin());
|
||||
it++;
|
||||
CHECK(it.m_it.array_iterator != it.m_object->m_value.array->begin());
|
||||
CHECK(it.m_it.array_iterator != it.m_object->m_value.array->end());
|
||||
it++;
|
||||
CHECK(it.m_it.array_iterator != it.m_object->m_value.array->begin());
|
||||
CHECK(it.m_it.array_iterator != it.m_object->m_value.array->end());
|
||||
it++;
|
||||
CHECK(it.m_it.array_iterator != it.m_object->m_value.array->begin());
|
||||
CHECK(it.m_it.array_iterator != it.m_object->m_value.array->end());
|
||||
it++;
|
||||
CHECK(it.m_it.array_iterator != it.m_object->m_value.array->begin());
|
||||
CHECK(it.m_it.array_iterator == it.m_object->m_value.array->end());
|
||||
}
|
||||
}
|
||||
|
||||
SECTION("pre-increment")
|
||||
{
|
||||
SECTION("null")
|
||||
{
|
||||
json j(json::value_t::null);
|
||||
json::const_iterator it = j.cbegin();
|
||||
CHECK(it.m_it.primitive_iterator == 1);
|
||||
++it;
|
||||
CHECK((it.m_it.primitive_iterator != 0 and it.m_it.primitive_iterator != 1));
|
||||
}
|
||||
|
||||
SECTION("number")
|
||||
{
|
||||
json j(17);
|
||||
json::const_iterator it = j.cbegin();
|
||||
CHECK(it.m_it.primitive_iterator == 0);
|
||||
++it;
|
||||
CHECK(it.m_it.primitive_iterator == 1);
|
||||
++it;
|
||||
CHECK((it.m_it.primitive_iterator != 0 and it.m_it.primitive_iterator != 1));
|
||||
}
|
||||
|
||||
SECTION("object")
|
||||
{
|
||||
json j({{"foo", "bar"}});
|
||||
json::const_iterator it = j.cbegin();
|
||||
CHECK(it.m_it.object_iterator == it.m_object->m_value.object->begin());
|
||||
++it;
|
||||
CHECK(it.m_it.object_iterator == it.m_object->m_value.object->end());
|
||||
}
|
||||
|
||||
SECTION("array")
|
||||
{
|
||||
json j({1, 2, 3, 4});
|
||||
json::const_iterator it = j.cbegin();
|
||||
CHECK(it.m_it.array_iterator == it.m_object->m_value.array->begin());
|
||||
++it;
|
||||
CHECK(it.m_it.array_iterator != it.m_object->m_value.array->begin());
|
||||
CHECK(it.m_it.array_iterator != it.m_object->m_value.array->end());
|
||||
++it;
|
||||
CHECK(it.m_it.array_iterator != it.m_object->m_value.array->begin());
|
||||
CHECK(it.m_it.array_iterator != it.m_object->m_value.array->end());
|
||||
++it;
|
||||
CHECK(it.m_it.array_iterator != it.m_object->m_value.array->begin());
|
||||
CHECK(it.m_it.array_iterator != it.m_object->m_value.array->end());
|
||||
++it;
|
||||
CHECK(it.m_it.array_iterator != it.m_object->m_value.array->begin());
|
||||
CHECK(it.m_it.array_iterator == it.m_object->m_value.array->end());
|
||||
}
|
||||
}
|
||||
|
||||
SECTION("post-decrement")
|
||||
{
|
||||
SECTION("null")
|
||||
{
|
||||
json j(json::value_t::null);
|
||||
json::const_iterator it = j.cend();
|
||||
CHECK(it.m_it.primitive_iterator == 1);
|
||||
}
|
||||
|
||||
SECTION("number")
|
||||
{
|
||||
json j(17);
|
||||
json::const_iterator it = j.cend();
|
||||
CHECK(it.m_it.primitive_iterator == 1);
|
||||
it--;
|
||||
CHECK(it.m_it.primitive_iterator == 0);
|
||||
it--;
|
||||
CHECK((it.m_it.primitive_iterator != 0 and it.m_it.primitive_iterator != 1));
|
||||
}
|
||||
|
||||
SECTION("object")
|
||||
{
|
||||
json j({{"foo", "bar"}});
|
||||
json::const_iterator it = j.cend();
|
||||
CHECK(it.m_it.object_iterator == it.m_object->m_value.object->end());
|
||||
it--;
|
||||
CHECK(it.m_it.object_iterator == it.m_object->m_value.object->begin());
|
||||
}
|
||||
|
||||
SECTION("array")
|
||||
{
|
||||
json j({1, 2, 3, 4});
|
||||
json::const_iterator it = j.cend();
|
||||
CHECK(it.m_it.array_iterator == it.m_object->m_value.array->end());
|
||||
it--;
|
||||
CHECK(it.m_it.array_iterator != it.m_object->m_value.array->begin());
|
||||
CHECK(it.m_it.array_iterator != it.m_object->m_value.array->end());
|
||||
it--;
|
||||
CHECK(it.m_it.array_iterator != it.m_object->m_value.array->begin());
|
||||
CHECK(it.m_it.array_iterator != it.m_object->m_value.array->end());
|
||||
it--;
|
||||
CHECK(it.m_it.array_iterator != it.m_object->m_value.array->begin());
|
||||
CHECK(it.m_it.array_iterator != it.m_object->m_value.array->end());
|
||||
it--;
|
||||
CHECK(it.m_it.array_iterator == it.m_object->m_value.array->begin());
|
||||
CHECK(it.m_it.array_iterator != it.m_object->m_value.array->end());
|
||||
}
|
||||
}
|
||||
|
||||
SECTION("pre-decrement")
|
||||
{
|
||||
SECTION("null")
|
||||
{
|
||||
json j(json::value_t::null);
|
||||
json::const_iterator it = j.cend();
|
||||
CHECK(it.m_it.primitive_iterator == 1);
|
||||
}
|
||||
|
||||
SECTION("number")
|
||||
{
|
||||
json j(17);
|
||||
json::const_iterator it = j.cend();
|
||||
CHECK(it.m_it.primitive_iterator == 1);
|
||||
--it;
|
||||
CHECK(it.m_it.primitive_iterator == 0);
|
||||
--it;
|
||||
CHECK((it.m_it.primitive_iterator != 0 and it.m_it.primitive_iterator != 1));
|
||||
}
|
||||
|
||||
SECTION("object")
|
||||
{
|
||||
json j({{"foo", "bar"}});
|
||||
json::const_iterator it = j.cend();
|
||||
CHECK(it.m_it.object_iterator == it.m_object->m_value.object->end());
|
||||
--it;
|
||||
CHECK(it.m_it.object_iterator == it.m_object->m_value.object->begin());
|
||||
}
|
||||
|
||||
SECTION("array")
|
||||
{
|
||||
json j({1, 2, 3, 4});
|
||||
json::const_iterator it = j.cend();
|
||||
CHECK(it.m_it.array_iterator == it.m_object->m_value.array->end());
|
||||
--it;
|
||||
CHECK(it.m_it.array_iterator != it.m_object->m_value.array->begin());
|
||||
CHECK(it.m_it.array_iterator != it.m_object->m_value.array->end());
|
||||
--it;
|
||||
CHECK(it.m_it.array_iterator != it.m_object->m_value.array->begin());
|
||||
CHECK(it.m_it.array_iterator != it.m_object->m_value.array->end());
|
||||
--it;
|
||||
CHECK(it.m_it.array_iterator != it.m_object->m_value.array->begin());
|
||||
CHECK(it.m_it.array_iterator != it.m_object->m_value.array->end());
|
||||
--it;
|
||||
CHECK(it.m_it.array_iterator == it.m_object->m_value.array->begin());
|
||||
CHECK(it.m_it.array_iterator != it.m_object->m_value.array->end());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
401
test/src/unit-class_iterator.cpp
Normal file
401
test/src/unit-class_iterator.cpp
Normal file
|
@ -0,0 +1,401 @@
|
|||
/*
|
||||
__ _____ _____ _____
|
||||
__| | __| | | | JSON for Modern C++ (test suite)
|
||||
| | |__ | | | | | | version 2.0.2
|
||||
|_____|_____|_____|_|___| https://github.com/nlohmann/json
|
||||
|
||||
Licensed under the MIT License <http://opensource.org/licenses/MIT>.
|
||||
Copyright (c) 2013-2016 Niels Lohmann <http://nlohmann.me>.
|
||||
|
||||
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"
|
||||
|
||||
#define private public
|
||||
#include "json.hpp"
|
||||
using nlohmann::json;
|
||||
|
||||
TEST_CASE("iterator class")
|
||||
{
|
||||
SECTION("construction")
|
||||
{
|
||||
SECTION("constructor")
|
||||
{
|
||||
SECTION("null")
|
||||
{
|
||||
json j(json::value_t::null);
|
||||
json::iterator it(&j);
|
||||
}
|
||||
|
||||
SECTION("object")
|
||||
{
|
||||
json j(json::value_t::object);
|
||||
json::iterator it(&j);
|
||||
}
|
||||
|
||||
SECTION("array")
|
||||
{
|
||||
json j(json::value_t::array);
|
||||
json::iterator it(&j);
|
||||
}
|
||||
}
|
||||
|
||||
SECTION("copy assignment")
|
||||
{
|
||||
json j(json::value_t::null);
|
||||
json::iterator it(&j);
|
||||
json::iterator it2(&j);
|
||||
it2 = it;
|
||||
}
|
||||
}
|
||||
|
||||
SECTION("initialization")
|
||||
{
|
||||
SECTION("set_begin")
|
||||
{
|
||||
SECTION("null")
|
||||
{
|
||||
json j(json::value_t::null);
|
||||
json::iterator it(&j);
|
||||
it.set_begin();
|
||||
CHECK(it == j.begin());
|
||||
}
|
||||
|
||||
SECTION("object")
|
||||
{
|
||||
json j(json::value_t::object);
|
||||
json::iterator it(&j);
|
||||
it.set_begin();
|
||||
CHECK(it == j.begin());
|
||||
}
|
||||
|
||||
SECTION("array")
|
||||
{
|
||||
json j(json::value_t::array);
|
||||
json::iterator it(&j);
|
||||
it.set_begin();
|
||||
CHECK(it == j.begin());
|
||||
}
|
||||
}
|
||||
|
||||
SECTION("set_end")
|
||||
{
|
||||
SECTION("null")
|
||||
{
|
||||
json j(json::value_t::null);
|
||||
json::iterator it(&j);
|
||||
it.set_end();
|
||||
CHECK(it == j.end());
|
||||
}
|
||||
|
||||
SECTION("object")
|
||||
{
|
||||
json j(json::value_t::object);
|
||||
json::iterator it(&j);
|
||||
it.set_end();
|
||||
CHECK(it == j.end());
|
||||
}
|
||||
|
||||
SECTION("array")
|
||||
{
|
||||
json j(json::value_t::array);
|
||||
json::iterator it(&j);
|
||||
it.set_end();
|
||||
CHECK(it == j.end());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
SECTION("element access")
|
||||
{
|
||||
SECTION("operator*")
|
||||
{
|
||||
SECTION("null")
|
||||
{
|
||||
json j(json::value_t::null);
|
||||
json::iterator it = j.begin();
|
||||
CHECK_THROWS_AS(*it, std::out_of_range);
|
||||
CHECK_THROWS_WITH(*it, "cannot get value");
|
||||
}
|
||||
|
||||
SECTION("number")
|
||||
{
|
||||
json j(17);
|
||||
json::iterator it = j.begin();
|
||||
CHECK(*it == json(17));
|
||||
it = j.end();
|
||||
CHECK_THROWS_AS(*it, std::out_of_range);
|
||||
CHECK_THROWS_WITH(*it, "cannot get value");
|
||||
}
|
||||
|
||||
SECTION("object")
|
||||
{
|
||||
json j({{"foo", "bar"}});
|
||||
json::iterator it = j.begin();
|
||||
CHECK(*it == json("bar"));
|
||||
}
|
||||
|
||||
SECTION("array")
|
||||
{
|
||||
json j({1, 2, 3, 4});
|
||||
json::iterator it = j.begin();
|
||||
CHECK(*it == json(1));
|
||||
}
|
||||
}
|
||||
|
||||
SECTION("operator->")
|
||||
{
|
||||
SECTION("null")
|
||||
{
|
||||
json j(json::value_t::null);
|
||||
json::iterator it = j.begin();
|
||||
CHECK_THROWS_AS(it->type_name(), std::out_of_range);
|
||||
CHECK_THROWS_WITH(it->type_name(), "cannot get value");
|
||||
}
|
||||
|
||||
SECTION("number")
|
||||
{
|
||||
json j(17);
|
||||
json::iterator it = j.begin();
|
||||
CHECK(it->type_name() == "number");
|
||||
it = j.end();
|
||||
CHECK_THROWS_AS(it->type_name(), std::out_of_range);
|
||||
CHECK_THROWS_WITH(it->type_name(), "cannot get value");
|
||||
}
|
||||
|
||||
SECTION("object")
|
||||
{
|
||||
json j({{"foo", "bar"}});
|
||||
json::iterator it = j.begin();
|
||||
CHECK(it->type_name() == "string");
|
||||
}
|
||||
|
||||
SECTION("array")
|
||||
{
|
||||
json j({1, 2, 3, 4});
|
||||
json::iterator it = j.begin();
|
||||
CHECK(it->type_name() == "number");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
SECTION("increment/decrement")
|
||||
{
|
||||
SECTION("post-increment")
|
||||
{
|
||||
SECTION("null")
|
||||
{
|
||||
json j(json::value_t::null);
|
||||
json::iterator it = j.begin();
|
||||
CHECK(it.m_it.primitive_iterator == 1);
|
||||
it++;
|
||||
CHECK((it.m_it.primitive_iterator != 0 and it.m_it.primitive_iterator != 1));
|
||||
}
|
||||
|
||||
SECTION("number")
|
||||
{
|
||||
json j(17);
|
||||
json::iterator it = j.begin();
|
||||
CHECK(it.m_it.primitive_iterator == 0);
|
||||
it++;
|
||||
CHECK(it.m_it.primitive_iterator == 1);
|
||||
it++;
|
||||
CHECK((it.m_it.primitive_iterator != 0 and it.m_it.primitive_iterator != 1));
|
||||
}
|
||||
|
||||
SECTION("object")
|
||||
{
|
||||
json j({{"foo", "bar"}});
|
||||
json::iterator it = j.begin();
|
||||
CHECK(it.m_it.object_iterator == it.m_object->m_value.object->begin());
|
||||
it++;
|
||||
CHECK(it.m_it.object_iterator == it.m_object->m_value.object->end());
|
||||
}
|
||||
|
||||
SECTION("array")
|
||||
{
|
||||
json j({1, 2, 3, 4});
|
||||
json::iterator it = j.begin();
|
||||
CHECK(it.m_it.array_iterator == it.m_object->m_value.array->begin());
|
||||
it++;
|
||||
CHECK(it.m_it.array_iterator != it.m_object->m_value.array->begin());
|
||||
CHECK(it.m_it.array_iterator != it.m_object->m_value.array->end());
|
||||
it++;
|
||||
CHECK(it.m_it.array_iterator != it.m_object->m_value.array->begin());
|
||||
CHECK(it.m_it.array_iterator != it.m_object->m_value.array->end());
|
||||
it++;
|
||||
CHECK(it.m_it.array_iterator != it.m_object->m_value.array->begin());
|
||||
CHECK(it.m_it.array_iterator != it.m_object->m_value.array->end());
|
||||
it++;
|
||||
CHECK(it.m_it.array_iterator != it.m_object->m_value.array->begin());
|
||||
CHECK(it.m_it.array_iterator == it.m_object->m_value.array->end());
|
||||
}
|
||||
}
|
||||
|
||||
SECTION("pre-increment")
|
||||
{
|
||||
SECTION("null")
|
||||
{
|
||||
json j(json::value_t::null);
|
||||
json::iterator it = j.begin();
|
||||
CHECK(it.m_it.primitive_iterator == 1);
|
||||
++it;
|
||||
CHECK((it.m_it.primitive_iterator != 0 and it.m_it.primitive_iterator != 1));
|
||||
}
|
||||
|
||||
SECTION("number")
|
||||
{
|
||||
json j(17);
|
||||
json::iterator it = j.begin();
|
||||
CHECK(it.m_it.primitive_iterator == 0);
|
||||
++it;
|
||||
CHECK(it.m_it.primitive_iterator == 1);
|
||||
++it;
|
||||
CHECK((it.m_it.primitive_iterator != 0 and it.m_it.primitive_iterator != 1));
|
||||
}
|
||||
|
||||
SECTION("object")
|
||||
{
|
||||
json j({{"foo", "bar"}});
|
||||
json::iterator it = j.begin();
|
||||
CHECK(it.m_it.object_iterator == it.m_object->m_value.object->begin());
|
||||
++it;
|
||||
CHECK(it.m_it.object_iterator == it.m_object->m_value.object->end());
|
||||
}
|
||||
|
||||
SECTION("array")
|
||||
{
|
||||
json j({1, 2, 3, 4});
|
||||
json::iterator it = j.begin();
|
||||
CHECK(it.m_it.array_iterator == it.m_object->m_value.array->begin());
|
||||
++it;
|
||||
CHECK(it.m_it.array_iterator != it.m_object->m_value.array->begin());
|
||||
CHECK(it.m_it.array_iterator != it.m_object->m_value.array->end());
|
||||
++it;
|
||||
CHECK(it.m_it.array_iterator != it.m_object->m_value.array->begin());
|
||||
CHECK(it.m_it.array_iterator != it.m_object->m_value.array->end());
|
||||
++it;
|
||||
CHECK(it.m_it.array_iterator != it.m_object->m_value.array->begin());
|
||||
CHECK(it.m_it.array_iterator != it.m_object->m_value.array->end());
|
||||
++it;
|
||||
CHECK(it.m_it.array_iterator != it.m_object->m_value.array->begin());
|
||||
CHECK(it.m_it.array_iterator == it.m_object->m_value.array->end());
|
||||
}
|
||||
}
|
||||
|
||||
SECTION("post-decrement")
|
||||
{
|
||||
SECTION("null")
|
||||
{
|
||||
json j(json::value_t::null);
|
||||
json::iterator it = j.end();
|
||||
CHECK(it.m_it.primitive_iterator == 1);
|
||||
}
|
||||
|
||||
SECTION("number")
|
||||
{
|
||||
json j(17);
|
||||
json::iterator it = j.end();
|
||||
CHECK(it.m_it.primitive_iterator == 1);
|
||||
it--;
|
||||
CHECK(it.m_it.primitive_iterator == 0);
|
||||
it--;
|
||||
CHECK((it.m_it.primitive_iterator != 0 and it.m_it.primitive_iterator != 1));
|
||||
}
|
||||
|
||||
SECTION("object")
|
||||
{
|
||||
json j({{"foo", "bar"}});
|
||||
json::iterator it = j.end();
|
||||
CHECK(it.m_it.object_iterator == it.m_object->m_value.object->end());
|
||||
it--;
|
||||
CHECK(it.m_it.object_iterator == it.m_object->m_value.object->begin());
|
||||
}
|
||||
|
||||
SECTION("array")
|
||||
{
|
||||
json j({1, 2, 3, 4});
|
||||
json::iterator it = j.end();
|
||||
CHECK(it.m_it.array_iterator == it.m_object->m_value.array->end());
|
||||
it--;
|
||||
CHECK(it.m_it.array_iterator != it.m_object->m_value.array->begin());
|
||||
CHECK(it.m_it.array_iterator != it.m_object->m_value.array->end());
|
||||
it--;
|
||||
CHECK(it.m_it.array_iterator != it.m_object->m_value.array->begin());
|
||||
CHECK(it.m_it.array_iterator != it.m_object->m_value.array->end());
|
||||
it--;
|
||||
CHECK(it.m_it.array_iterator != it.m_object->m_value.array->begin());
|
||||
CHECK(it.m_it.array_iterator != it.m_object->m_value.array->end());
|
||||
it--;
|
||||
CHECK(it.m_it.array_iterator == it.m_object->m_value.array->begin());
|
||||
CHECK(it.m_it.array_iterator != it.m_object->m_value.array->end());
|
||||
}
|
||||
}
|
||||
|
||||
SECTION("pre-decrement")
|
||||
{
|
||||
SECTION("null")
|
||||
{
|
||||
json j(json::value_t::null);
|
||||
json::iterator it = j.end();
|
||||
CHECK(it.m_it.primitive_iterator == 1);
|
||||
}
|
||||
|
||||
SECTION("number")
|
||||
{
|
||||
json j(17);
|
||||
json::iterator it = j.end();
|
||||
CHECK(it.m_it.primitive_iterator == 1);
|
||||
--it;
|
||||
CHECK(it.m_it.primitive_iterator == 0);
|
||||
--it;
|
||||
CHECK((it.m_it.primitive_iterator != 0 and it.m_it.primitive_iterator != 1));
|
||||
}
|
||||
|
||||
SECTION("object")
|
||||
{
|
||||
json j({{"foo", "bar"}});
|
||||
json::iterator it = j.end();
|
||||
CHECK(it.m_it.object_iterator == it.m_object->m_value.object->end());
|
||||
--it;
|
||||
CHECK(it.m_it.object_iterator == it.m_object->m_value.object->begin());
|
||||
}
|
||||
|
||||
SECTION("array")
|
||||
{
|
||||
json j({1, 2, 3, 4});
|
||||
json::iterator it = j.end();
|
||||
CHECK(it.m_it.array_iterator == it.m_object->m_value.array->end());
|
||||
--it;
|
||||
CHECK(it.m_it.array_iterator != it.m_object->m_value.array->begin());
|
||||
CHECK(it.m_it.array_iterator != it.m_object->m_value.array->end());
|
||||
--it;
|
||||
CHECK(it.m_it.array_iterator != it.m_object->m_value.array->begin());
|
||||
CHECK(it.m_it.array_iterator != it.m_object->m_value.array->end());
|
||||
--it;
|
||||
CHECK(it.m_it.array_iterator != it.m_object->m_value.array->begin());
|
||||
CHECK(it.m_it.array_iterator != it.m_object->m_value.array->end());
|
||||
--it;
|
||||
CHECK(it.m_it.array_iterator == it.m_object->m_value.array->begin());
|
||||
CHECK(it.m_it.array_iterator != it.m_object->m_value.array->end());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
155
test/src/unit-class_lexer.cpp
Normal file
155
test/src/unit-class_lexer.cpp
Normal file
|
@ -0,0 +1,155 @@
|
|||
/*
|
||||
__ _____ _____ _____
|
||||
__| | __| | | | JSON for Modern C++ (test suite)
|
||||
| | |__ | | | | | | version 2.0.2
|
||||
|_____|_____|_____|_|___| https://github.com/nlohmann/json
|
||||
|
||||
Licensed under the MIT License <http://opensource.org/licenses/MIT>.
|
||||
Copyright (c) 2013-2016 Niels Lohmann <http://nlohmann.me>.
|
||||
|
||||
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"
|
||||
|
||||
#define private public
|
||||
#include "json.hpp"
|
||||
using nlohmann::json;
|
||||
|
||||
TEST_CASE("lexer class")
|
||||
{
|
||||
SECTION("scan")
|
||||
{
|
||||
SECTION("structural characters")
|
||||
{
|
||||
CHECK(json::lexer("[").scan() == json::lexer::token_type::begin_array);
|
||||
CHECK(json::lexer("]").scan() == json::lexer::token_type::end_array);
|
||||
CHECK(json::lexer("{").scan() == json::lexer::token_type::begin_object);
|
||||
CHECK(json::lexer("}").scan() == json::lexer::token_type::end_object);
|
||||
CHECK(json::lexer(",").scan() == json::lexer::token_type::value_separator);
|
||||
CHECK(json::lexer(":").scan() == json::lexer::token_type::name_separator);
|
||||
}
|
||||
|
||||
SECTION("literal names")
|
||||
{
|
||||
CHECK(json::lexer("null").scan() == json::lexer::token_type::literal_null);
|
||||
CHECK(json::lexer("true").scan() == json::lexer::token_type::literal_true);
|
||||
CHECK(json::lexer("false").scan() == json::lexer::token_type::literal_false);
|
||||
}
|
||||
|
||||
SECTION("numbers")
|
||||
{
|
||||
CHECK(json::lexer("0").scan() == json::lexer::token_type::value_number);
|
||||
CHECK(json::lexer("1").scan() == json::lexer::token_type::value_number);
|
||||
CHECK(json::lexer("2").scan() == json::lexer::token_type::value_number);
|
||||
CHECK(json::lexer("3").scan() == json::lexer::token_type::value_number);
|
||||
CHECK(json::lexer("4").scan() == json::lexer::token_type::value_number);
|
||||
CHECK(json::lexer("5").scan() == json::lexer::token_type::value_number);
|
||||
CHECK(json::lexer("6").scan() == json::lexer::token_type::value_number);
|
||||
CHECK(json::lexer("7").scan() == json::lexer::token_type::value_number);
|
||||
CHECK(json::lexer("8").scan() == json::lexer::token_type::value_number);
|
||||
CHECK(json::lexer("9").scan() == json::lexer::token_type::value_number);
|
||||
}
|
||||
|
||||
SECTION("whitespace")
|
||||
{
|
||||
// result is end_of_input, because not token is following
|
||||
CHECK(json::lexer(" ").scan() == json::lexer::token_type::end_of_input);
|
||||
CHECK(json::lexer("\t").scan() == json::lexer::token_type::end_of_input);
|
||||
CHECK(json::lexer("\n").scan() == json::lexer::token_type::end_of_input);
|
||||
CHECK(json::lexer("\r").scan() == json::lexer::token_type::end_of_input);
|
||||
CHECK(json::lexer(" \t\n\r\n\t ").scan() == json::lexer::token_type::end_of_input);
|
||||
}
|
||||
}
|
||||
|
||||
SECTION("token_type_name")
|
||||
{
|
||||
CHECK(json::lexer::token_type_name(json::lexer::token_type::uninitialized) == "<uninitialized>");
|
||||
CHECK(json::lexer::token_type_name(json::lexer::token_type::literal_true) == "true literal");
|
||||
CHECK(json::lexer::token_type_name(json::lexer::token_type::literal_false) == "false literal");
|
||||
CHECK(json::lexer::token_type_name(json::lexer::token_type::literal_null) == "null literal");
|
||||
CHECK(json::lexer::token_type_name(json::lexer::token_type::value_string) == "string literal");
|
||||
CHECK(json::lexer::token_type_name(json::lexer::token_type::value_number) == "number literal");
|
||||
CHECK(json::lexer::token_type_name(json::lexer::token_type::begin_array) == "'['");
|
||||
CHECK(json::lexer::token_type_name(json::lexer::token_type::begin_object) == "'{'");
|
||||
CHECK(json::lexer::token_type_name(json::lexer::token_type::end_array) == "']'");
|
||||
CHECK(json::lexer::token_type_name(json::lexer::token_type::end_object) == "'}'");
|
||||
CHECK(json::lexer::token_type_name(json::lexer::token_type::name_separator) == "':'");
|
||||
CHECK(json::lexer::token_type_name(json::lexer::token_type::value_separator) == "','");
|
||||
CHECK(json::lexer::token_type_name(json::lexer::token_type::parse_error) == "<parse error>");
|
||||
CHECK(json::lexer::token_type_name(json::lexer::token_type::end_of_input) == "end of input");
|
||||
}
|
||||
|
||||
SECTION("parse errors on first character")
|
||||
{
|
||||
for (int c = 1; c < 128; ++c)
|
||||
{
|
||||
auto s = std::string(1, c);
|
||||
|
||||
switch (c)
|
||||
{
|
||||
// single characters that are valid tokens
|
||||
case ('['):
|
||||
case (']'):
|
||||
case ('{'):
|
||||
case ('}'):
|
||||
case (','):
|
||||
case (':'):
|
||||
case ('0'):
|
||||
case ('1'):
|
||||
case ('2'):
|
||||
case ('3'):
|
||||
case ('4'):
|
||||
case ('5'):
|
||||
case ('6'):
|
||||
case ('7'):
|
||||
case ('8'):
|
||||
case ('9'):
|
||||
{
|
||||
CHECK(json::lexer(s.c_str()).scan() != json::lexer::token_type::parse_error);
|
||||
break;
|
||||
}
|
||||
|
||||
// whitespace
|
||||
case (' '):
|
||||
case ('\t'):
|
||||
case ('\n'):
|
||||
case ('\r'):
|
||||
{
|
||||
CHECK(json::lexer(s.c_str()).scan() == json::lexer::token_type::end_of_input);
|
||||
break;
|
||||
}
|
||||
|
||||
// anything else is not expected
|
||||
default:
|
||||
{
|
||||
CHECK(json::lexer(s.c_str()).scan() == json::lexer::token_type::parse_error);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
SECTION("to_unicode")
|
||||
{
|
||||
CHECK(json::lexer::to_unicode(0x1F4A9) == "💩");
|
||||
CHECK_THROWS_AS(json::lexer::to_unicode(0x200000), std::out_of_range);
|
||||
CHECK_THROWS_WITH(json::lexer::to_unicode(0x200000), "code points above 0x10FFFF are invalid");
|
||||
}
|
||||
}
|
753
test/src/unit-class_parser.cpp
Normal file
753
test/src/unit-class_parser.cpp
Normal file
|
@ -0,0 +1,753 @@
|
|||
/*
|
||||
__ _____ _____ _____
|
||||
__| | __| | | | JSON for Modern C++ (test suite)
|
||||
| | |__ | | | | | | version 2.0.2
|
||||
|_____|_____|_____|_|___| https://github.com/nlohmann/json
|
||||
|
||||
Licensed under the MIT License <http://opensource.org/licenses/MIT>.
|
||||
Copyright (c) 2013-2016 Niels Lohmann <http://nlohmann.me>.
|
||||
|
||||
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"
|
||||
|
||||
#define private public
|
||||
#include "json.hpp"
|
||||
using nlohmann::json;
|
||||
|
||||
TEST_CASE("parser class")
|
||||
{
|
||||
SECTION("parse")
|
||||
{
|
||||
SECTION("null")
|
||||
{
|
||||
CHECK(json::parser("null").parse() == json(nullptr));
|
||||
}
|
||||
|
||||
SECTION("true")
|
||||
{
|
||||
CHECK(json::parser("true").parse() == json(true));
|
||||
}
|
||||
|
||||
SECTION("false")
|
||||
{
|
||||
CHECK(json::parser("false").parse() == json(false));
|
||||
}
|
||||
|
||||
SECTION("array")
|
||||
{
|
||||
SECTION("empty array")
|
||||
{
|
||||
CHECK(json::parser("[]").parse() == json(json::value_t::array));
|
||||
CHECK(json::parser("[ ]").parse() == json(json::value_t::array));
|
||||
}
|
||||
|
||||
SECTION("nonempty array")
|
||||
{
|
||||
CHECK(json::parser("[true, false, null]").parse() == json({true, false, nullptr}));
|
||||
}
|
||||
}
|
||||
|
||||
SECTION("object")
|
||||
{
|
||||
SECTION("empty object")
|
||||
{
|
||||
CHECK(json::parser("{}").parse() == json(json::value_t::object));
|
||||
CHECK(json::parser("{ }").parse() == json(json::value_t::object));
|
||||
}
|
||||
|
||||
SECTION("nonempty object")
|
||||
{
|
||||
CHECK(json::parser("{\"\": true, \"one\": 1, \"two\": null}").parse() == json({{"", true}, {"one", 1}, {"two", nullptr}}));
|
||||
}
|
||||
}
|
||||
|
||||
SECTION("string")
|
||||
{
|
||||
// empty string
|
||||
CHECK(json::parser("\"\"").parse() == json(json::value_t::string));
|
||||
|
||||
SECTION("errors")
|
||||
{
|
||||
// error: tab in string
|
||||
CHECK_THROWS_AS(json::parser("\"\t\"").parse(), std::invalid_argument);
|
||||
CHECK_THROWS_WITH(json::parser("\"\t\"").parse(), "parse error - unexpected '\"'");
|
||||
// error: newline in string
|
||||
CHECK_THROWS_AS(json::parser("\"\n\"").parse(), std::invalid_argument);
|
||||
CHECK_THROWS_AS(json::parser("\"\r\"").parse(), std::invalid_argument);
|
||||
CHECK_THROWS_WITH(json::parser("\"\n\"").parse(), "parse error - unexpected '\"'");
|
||||
CHECK_THROWS_WITH(json::parser("\"\r\"").parse(), "parse error - unexpected '\"'");
|
||||
// error: backspace in string
|
||||
CHECK_THROWS_AS(json::parser("\"\b\"").parse(), std::invalid_argument);
|
||||
CHECK_THROWS_WITH(json::parser("\"\b\"").parse(), "parse error - unexpected '\"'");
|
||||
// improve code coverage
|
||||
CHECK_THROWS_AS(json::parser("\uFF01").parse(), std::invalid_argument);
|
||||
// unescaped control characters
|
||||
CHECK_THROWS_AS(json::parser("\"\x00\"").parse(), std::invalid_argument);
|
||||
CHECK_THROWS_AS(json::parser("\"\x01\"").parse(), std::invalid_argument);
|
||||
CHECK_THROWS_AS(json::parser("\"\x02\"").parse(), std::invalid_argument);
|
||||
CHECK_THROWS_AS(json::parser("\"\x03\"").parse(), std::invalid_argument);
|
||||
CHECK_THROWS_AS(json::parser("\"\x04\"").parse(), std::invalid_argument);
|
||||
CHECK_THROWS_AS(json::parser("\"\x05\"").parse(), std::invalid_argument);
|
||||
CHECK_THROWS_AS(json::parser("\"\x06\"").parse(), std::invalid_argument);
|
||||
CHECK_THROWS_AS(json::parser("\"\x07\"").parse(), std::invalid_argument);
|
||||
CHECK_THROWS_AS(json::parser("\"\x08\"").parse(), std::invalid_argument);
|
||||
CHECK_THROWS_AS(json::parser("\"\x09\"").parse(), std::invalid_argument);
|
||||
CHECK_THROWS_AS(json::parser("\"\x0a\"").parse(), std::invalid_argument);
|
||||
CHECK_THROWS_AS(json::parser("\"\x0b\"").parse(), std::invalid_argument);
|
||||
CHECK_THROWS_AS(json::parser("\"\x0c\"").parse(), std::invalid_argument);
|
||||
CHECK_THROWS_AS(json::parser("\"\x0d\"").parse(), std::invalid_argument);
|
||||
CHECK_THROWS_AS(json::parser("\"\x0e\"").parse(), std::invalid_argument);
|
||||
CHECK_THROWS_AS(json::parser("\"\x0f\"").parse(), std::invalid_argument);
|
||||
CHECK_THROWS_AS(json::parser("\"\x10\"").parse(), std::invalid_argument);
|
||||
CHECK_THROWS_AS(json::parser("\"\x11\"").parse(), std::invalid_argument);
|
||||
CHECK_THROWS_AS(json::parser("\"\x12\"").parse(), std::invalid_argument);
|
||||
CHECK_THROWS_AS(json::parser("\"\x13\"").parse(), std::invalid_argument);
|
||||
CHECK_THROWS_AS(json::parser("\"\x14\"").parse(), std::invalid_argument);
|
||||
CHECK_THROWS_AS(json::parser("\"\x15\"").parse(), std::invalid_argument);
|
||||
CHECK_THROWS_AS(json::parser("\"\x16\"").parse(), std::invalid_argument);
|
||||
CHECK_THROWS_AS(json::parser("\"\x17\"").parse(), std::invalid_argument);
|
||||
CHECK_THROWS_AS(json::parser("\"\x18\"").parse(), std::invalid_argument);
|
||||
CHECK_THROWS_AS(json::parser("\"\x19\"").parse(), std::invalid_argument);
|
||||
CHECK_THROWS_AS(json::parser("\"\x1a\"").parse(), std::invalid_argument);
|
||||
CHECK_THROWS_AS(json::parser("\"\x1b\"").parse(), std::invalid_argument);
|
||||
CHECK_THROWS_AS(json::parser("\"\x1c\"").parse(), std::invalid_argument);
|
||||
CHECK_THROWS_AS(json::parser("\"\x1d\"").parse(), std::invalid_argument);
|
||||
CHECK_THROWS_AS(json::parser("\"\x1e\"").parse(), std::invalid_argument);
|
||||
CHECK_THROWS_AS(json::parser("\"\x1f\"").parse(), std::invalid_argument);
|
||||
}
|
||||
|
||||
SECTION("escaped")
|
||||
{
|
||||
// quotation mark "\""
|
||||
auto r1 = R"("\"")"_json;
|
||||
CHECK(json::parser("\"\\\"\"").parse() == r1);
|
||||
// reverse solidus "\\"
|
||||
auto r2 = R"("\\")"_json;
|
||||
CHECK(json::parser("\"\\\\\"").parse() == r2);
|
||||
// solidus
|
||||
CHECK(json::parser("\"\\/\"").parse() == R"("/")"_json);
|
||||
// backspace
|
||||
CHECK(json::parser("\"\\b\"").parse() == json("\b"));
|
||||
// formfeed
|
||||
CHECK(json::parser("\"\\f\"").parse() == json("\f"));
|
||||
// newline
|
||||
CHECK(json::parser("\"\\n\"").parse() == json("\n"));
|
||||
// carriage return
|
||||
CHECK(json::parser("\"\\r\"").parse() == json("\r"));
|
||||
// horizontal tab
|
||||
CHECK(json::parser("\"\\t\"").parse() == json("\t"));
|
||||
|
||||
CHECK(json::parser("\"\\u0001\"").parse().get<json::string_t>() == "\x01");
|
||||
CHECK(json::parser("\"\\u000a\"").parse().get<json::string_t>() == "\n");
|
||||
CHECK(json::parser("\"\\u00b0\"").parse().get<json::string_t>() == "°");
|
||||
CHECK(json::parser("\"\\u0c00\"").parse().get<json::string_t>() == "ఀ");
|
||||
CHECK(json::parser("\"\\ud000\"").parse().get<json::string_t>() == "퀀");
|
||||
CHECK(json::parser("\"\\u000E\"").parse().get<json::string_t>() == "\x0E");
|
||||
CHECK(json::parser("\"\\u00F0\"").parse().get<json::string_t>() == "ð");
|
||||
CHECK(json::parser("\"\\u0100\"").parse().get<json::string_t>() == "Ā");
|
||||
CHECK(json::parser("\"\\u2000\"").parse().get<json::string_t>() == " ");
|
||||
CHECK(json::parser("\"\\uFFFF\"").parse().get<json::string_t>() == "");
|
||||
CHECK(json::parser("\"\\u20AC\"").parse().get<json::string_t>() == "€");
|
||||
CHECK(json::parser("\"€\"").parse().get<json::string_t>() == "€");
|
||||
CHECK(json::parser("\"🎈\"").parse().get<json::string_t>() == "🎈");
|
||||
|
||||
CHECK(json::parse("\"\\ud80c\\udc60\"").get<json::string_t>() == u8"\U00013060");
|
||||
CHECK(json::parse("\"\\ud83c\\udf1e\"").get<json::string_t>() == "🌞");
|
||||
}
|
||||
}
|
||||
|
||||
SECTION("number")
|
||||
{
|
||||
SECTION("integers")
|
||||
{
|
||||
SECTION("without exponent")
|
||||
{
|
||||
CHECK(json::parser("-128").parse() == json(-128));
|
||||
CHECK(json::parser("-0").parse() == json(-0));
|
||||
CHECK(json::parser("0").parse() == json(0));
|
||||
CHECK(json::parser("128").parse() == json(128));
|
||||
}
|
||||
|
||||
SECTION("with exponent")
|
||||
{
|
||||
CHECK(json::parser("0e1").parse() == json(0e1));
|
||||
CHECK(json::parser("0E1").parse() == json(0e1));
|
||||
|
||||
CHECK(json::parser("10000E-4").parse() == json(10000e-4));
|
||||
CHECK(json::parser("10000E-3").parse() == json(10000e-3));
|
||||
CHECK(json::parser("10000E-2").parse() == json(10000e-2));
|
||||
CHECK(json::parser("10000E-1").parse() == json(10000e-1));
|
||||
CHECK(json::parser("10000E0").parse() == json(10000e0));
|
||||
CHECK(json::parser("10000E1").parse() == json(10000e1));
|
||||
CHECK(json::parser("10000E2").parse() == json(10000e2));
|
||||
CHECK(json::parser("10000E3").parse() == json(10000e3));
|
||||
CHECK(json::parser("10000E4").parse() == json(10000e4));
|
||||
|
||||
CHECK(json::parser("10000e-4").parse() == json(10000e-4));
|
||||
CHECK(json::parser("10000e-3").parse() == json(10000e-3));
|
||||
CHECK(json::parser("10000e-2").parse() == json(10000e-2));
|
||||
CHECK(json::parser("10000e-1").parse() == json(10000e-1));
|
||||
CHECK(json::parser("10000e0").parse() == json(10000e0));
|
||||
CHECK(json::parser("10000e1").parse() == json(10000e1));
|
||||
CHECK(json::parser("10000e2").parse() == json(10000e2));
|
||||
CHECK(json::parser("10000e3").parse() == json(10000e3));
|
||||
CHECK(json::parser("10000e4").parse() == json(10000e4));
|
||||
|
||||
CHECK(json::parser("-0e1").parse() == json(-0e1));
|
||||
CHECK(json::parser("-0E1").parse() == json(-0e1));
|
||||
CHECK(json::parser("-0E123").parse() == json(-0e123));
|
||||
}
|
||||
|
||||
SECTION("edge cases")
|
||||
{
|
||||
// From RFC7159, Section 6:
|
||||
// Note that when such software is used, numbers that are
|
||||
// integers and are in the range [-(2**53)+1, (2**53)-1]
|
||||
// are interoperable in the sense that implementations will
|
||||
// agree exactly on their numeric values.
|
||||
|
||||
// -(2**53)+1
|
||||
CHECK(json::parser("-9007199254740991").parse().get<int64_t>() == -9007199254740991);
|
||||
// (2**53)-1
|
||||
CHECK(json::parser("9007199254740991").parse().get<int64_t>() == 9007199254740991);
|
||||
}
|
||||
|
||||
SECTION("over the edge cases") // issue #178 - Integer conversion to unsigned (incorrect handling of 64 bit integers)
|
||||
{
|
||||
// While RFC7159, Section 6 specifies a preference for support
|
||||
// for ranges in range of IEEE 754-2008 binary64 (double precision)
|
||||
// this does not accommodate 64 bit integers without loss of accuracy.
|
||||
// As 64 bit integers are now widely used in software, it is desirable
|
||||
// to expand support to to the full 64 bit (signed and unsigned) range
|
||||
// i.e. -(2**63) -> (2**64)-1.
|
||||
|
||||
// -(2**63) ** Note: compilers see negative literals as negated positive numbers (hence the -1))
|
||||
CHECK(json::parser("-9223372036854775808").parse().get<int64_t>() == -9223372036854775807 - 1);
|
||||
// (2**63)-1
|
||||
CHECK(json::parser("9223372036854775807").parse().get<int64_t>() == 9223372036854775807);
|
||||
// (2**64)-1
|
||||
CHECK(json::parser("18446744073709551615").parse().get<uint64_t>() == 18446744073709551615u);
|
||||
}
|
||||
}
|
||||
|
||||
SECTION("floating-point")
|
||||
{
|
||||
SECTION("without exponent")
|
||||
{
|
||||
CHECK(json::parser("-128.5").parse() == json(-128.5));
|
||||
CHECK(json::parser("0.999").parse() == json(0.999));
|
||||
CHECK(json::parser("128.5").parse() == json(128.5));
|
||||
CHECK(json::parser("-0.0").parse() == json(-0.0));
|
||||
}
|
||||
|
||||
SECTION("with exponent")
|
||||
{
|
||||
CHECK(json::parser("-128.5E3").parse() == json(-128.5E3));
|
||||
CHECK(json::parser("-128.5E-3").parse() == json(-128.5E-3));
|
||||
CHECK(json::parser("-0.0e1").parse() == json(-0.0e1));
|
||||
CHECK(json::parser("-0.0E1").parse() == json(-0.0e1));
|
||||
}
|
||||
}
|
||||
|
||||
SECTION("invalid numbers")
|
||||
{
|
||||
CHECK_THROWS_AS(json::parser("01").parse(), std::invalid_argument);
|
||||
CHECK_THROWS_AS(json::parser("--1").parse(), std::invalid_argument);
|
||||
CHECK_THROWS_AS(json::parser("1.").parse(), std::invalid_argument);
|
||||
CHECK_THROWS_AS(json::parser("1E").parse(), std::invalid_argument);
|
||||
CHECK_THROWS_AS(json::parser("1E-").parse(), std::invalid_argument);
|
||||
CHECK_THROWS_AS(json::parser("1.E1").parse(), std::invalid_argument);
|
||||
CHECK_THROWS_AS(json::parser("-1E").parse(), std::invalid_argument);
|
||||
CHECK_THROWS_AS(json::parser("-0E#").parse(), std::invalid_argument);
|
||||
CHECK_THROWS_AS(json::parser("-0E-#").parse(), std::invalid_argument);
|
||||
CHECK_THROWS_AS(json::parser("-0#").parse(), std::invalid_argument);
|
||||
CHECK_THROWS_AS(json::parser("-0.0:").parse(), std::invalid_argument);
|
||||
CHECK_THROWS_AS(json::parser("-0.0Z").parse(), std::invalid_argument);
|
||||
CHECK_THROWS_AS(json::parser("-0E123:").parse(), std::invalid_argument);
|
||||
CHECK_THROWS_AS(json::parser("-0e0-:").parse(), std::invalid_argument);
|
||||
CHECK_THROWS_AS(json::parser("-0e-:").parse(), std::invalid_argument);
|
||||
CHECK_THROWS_AS(json::parser("-0f").parse(), std::invalid_argument);
|
||||
|
||||
// numbers must not begin with "+"
|
||||
CHECK_THROWS_AS(json::parser("+1").parse(), std::invalid_argument);
|
||||
CHECK_THROWS_AS(json::parser("+0").parse(), std::invalid_argument);
|
||||
|
||||
CHECK_THROWS_WITH(json::parser("01").parse(),
|
||||
"parse error - unexpected number literal; expected end of input");
|
||||
CHECK_THROWS_WITH(json::parser("--1").parse(), "parse error - unexpected '-'");
|
||||
CHECK_THROWS_WITH(json::parser("1.").parse(),
|
||||
"parse error - unexpected '.'; expected end of input");
|
||||
CHECK_THROWS_WITH(json::parser("1E").parse(),
|
||||
"parse error - unexpected 'E'; expected end of input");
|
||||
CHECK_THROWS_WITH(json::parser("1E-").parse(),
|
||||
"parse error - unexpected 'E'; expected end of input");
|
||||
CHECK_THROWS_WITH(json::parser("1.E1").parse(),
|
||||
"parse error - unexpected '.'; expected end of input");
|
||||
CHECK_THROWS_WITH(json::parser("-1E").parse(),
|
||||
"parse error - unexpected 'E'; expected end of input");
|
||||
CHECK_THROWS_WITH(json::parser("-0E#").parse(),
|
||||
"parse error - unexpected 'E'; expected end of input");
|
||||
CHECK_THROWS_WITH(json::parser("-0E-#").parse(),
|
||||
"parse error - unexpected 'E'; expected end of input");
|
||||
CHECK_THROWS_WITH(json::parser("-0#").parse(),
|
||||
"parse error - unexpected '#'; expected end of input");
|
||||
CHECK_THROWS_WITH(json::parser("-0.0:").parse(),
|
||||
"parse error - unexpected ':'; expected end of input");
|
||||
CHECK_THROWS_WITH(json::parser("-0.0Z").parse(),
|
||||
"parse error - unexpected 'Z'; expected end of input");
|
||||
CHECK_THROWS_WITH(json::parser("-0E123:").parse(),
|
||||
"parse error - unexpected ':'; expected end of input");
|
||||
CHECK_THROWS_WITH(json::parser("-0e0-:").parse(),
|
||||
"parse error - unexpected '-'; expected end of input");
|
||||
CHECK_THROWS_WITH(json::parser("-0e-:").parse(),
|
||||
"parse error - unexpected 'e'; expected end of input");
|
||||
CHECK_THROWS_WITH(json::parser("-0f").parse(),
|
||||
"parse error - unexpected 'f'; expected end of input");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
SECTION("parse errors")
|
||||
{
|
||||
// unexpected end of number
|
||||
CHECK_THROWS_AS(json::parser("0.").parse(), std::invalid_argument);
|
||||
CHECK_THROWS_AS(json::parser("-").parse(), std::invalid_argument);
|
||||
CHECK_THROWS_AS(json::parser("--").parse(), std::invalid_argument);
|
||||
CHECK_THROWS_AS(json::parser("-0.").parse(), std::invalid_argument);
|
||||
CHECK_THROWS_AS(json::parser("-.").parse(), std::invalid_argument);
|
||||
CHECK_THROWS_AS(json::parser("-:").parse(), std::invalid_argument);
|
||||
CHECK_THROWS_AS(json::parser("0.:").parse(), std::invalid_argument);
|
||||
CHECK_THROWS_AS(json::parser("e.").parse(), std::invalid_argument);
|
||||
CHECK_THROWS_AS(json::parser("1e.").parse(), std::invalid_argument);
|
||||
CHECK_THROWS_AS(json::parser("1e/").parse(), std::invalid_argument);
|
||||
CHECK_THROWS_AS(json::parser("1e:").parse(), std::invalid_argument);
|
||||
CHECK_THROWS_AS(json::parser("1E.").parse(), std::invalid_argument);
|
||||
CHECK_THROWS_AS(json::parser("1E/").parse(), std::invalid_argument);
|
||||
CHECK_THROWS_AS(json::parser("1E:").parse(), std::invalid_argument);
|
||||
CHECK_THROWS_WITH(json::parser("0.").parse(),
|
||||
"parse error - unexpected '.'; expected end of input");
|
||||
CHECK_THROWS_WITH(json::parser("-").parse(), "parse error - unexpected '-'");
|
||||
CHECK_THROWS_WITH(json::parser("--").parse(),
|
||||
"parse error - unexpected '-'");
|
||||
CHECK_THROWS_WITH(json::parser("-0.").parse(),
|
||||
"parse error - unexpected '.'; expected end of input");
|
||||
CHECK_THROWS_WITH(json::parser("-.").parse(),
|
||||
"parse error - unexpected '-'");
|
||||
CHECK_THROWS_WITH(json::parser("-:").parse(),
|
||||
"parse error - unexpected '-'");
|
||||
CHECK_THROWS_WITH(json::parser("0.:").parse(),
|
||||
"parse error - unexpected '.'; expected end of input");
|
||||
CHECK_THROWS_WITH(json::parser("e.").parse(),
|
||||
"parse error - unexpected 'e'");
|
||||
CHECK_THROWS_WITH(json::parser("1e.").parse(),
|
||||
"parse error - unexpected 'e'; expected end of input");
|
||||
CHECK_THROWS_WITH(json::parser("1e/").parse(),
|
||||
"parse error - unexpected 'e'; expected end of input");
|
||||
CHECK_THROWS_WITH(json::parser("1e:").parse(),
|
||||
"parse error - unexpected 'e'; expected end of input");
|
||||
CHECK_THROWS_WITH(json::parser("1E.").parse(),
|
||||
"parse error - unexpected 'E'; expected end of input");
|
||||
CHECK_THROWS_WITH(json::parser("1E/").parse(),
|
||||
"parse error - unexpected 'E'; expected end of input");
|
||||
CHECK_THROWS_WITH(json::parser("1E:").parse(),
|
||||
"parse error - unexpected 'E'; expected end of input");
|
||||
|
||||
// unexpected end of null
|
||||
CHECK_THROWS_AS(json::parser("n").parse(), std::invalid_argument);
|
||||
CHECK_THROWS_AS(json::parser("nu").parse(), std::invalid_argument);
|
||||
CHECK_THROWS_AS(json::parser("nul").parse(), std::invalid_argument);
|
||||
CHECK_THROWS_WITH(json::parser("n").parse(), "parse error - unexpected 'n'");
|
||||
CHECK_THROWS_WITH(json::parser("nu").parse(),
|
||||
"parse error - unexpected 'n'");
|
||||
CHECK_THROWS_WITH(json::parser("nul").parse(),
|
||||
"parse error - unexpected 'n'");
|
||||
|
||||
// unexpected end of true
|
||||
CHECK_THROWS_AS(json::parser("t").parse(), std::invalid_argument);
|
||||
CHECK_THROWS_AS(json::parser("tr").parse(), std::invalid_argument);
|
||||
CHECK_THROWS_AS(json::parser("tru").parse(), std::invalid_argument);
|
||||
CHECK_THROWS_WITH(json::parser("t").parse(), "parse error - unexpected 't'");
|
||||
CHECK_THROWS_WITH(json::parser("tr").parse(),
|
||||
"parse error - unexpected 't'");
|
||||
CHECK_THROWS_WITH(json::parser("tru").parse(),
|
||||
"parse error - unexpected 't'");
|
||||
|
||||
// unexpected end of false
|
||||
CHECK_THROWS_AS(json::parser("f").parse(), std::invalid_argument);
|
||||
CHECK_THROWS_AS(json::parser("fa").parse(), std::invalid_argument);
|
||||
CHECK_THROWS_AS(json::parser("fal").parse(), std::invalid_argument);
|
||||
CHECK_THROWS_AS(json::parser("fals").parse(), std::invalid_argument);
|
||||
CHECK_THROWS_WITH(json::parser("f").parse(), "parse error - unexpected 'f'");
|
||||
CHECK_THROWS_WITH(json::parser("fa").parse(),
|
||||
"parse error - unexpected 'f'");
|
||||
CHECK_THROWS_WITH(json::parser("fal").parse(),
|
||||
"parse error - unexpected 'f'");
|
||||
CHECK_THROWS_WITH(json::parser("fals").parse(),
|
||||
"parse error - unexpected 'f'");
|
||||
|
||||
// missing/unexpected end of array
|
||||
CHECK_THROWS_AS(json::parser("[").parse(), std::invalid_argument);
|
||||
CHECK_THROWS_AS(json::parser("[1").parse(), std::invalid_argument);
|
||||
CHECK_THROWS_AS(json::parser("[1,").parse(), std::invalid_argument);
|
||||
CHECK_THROWS_AS(json::parser("[1,]").parse(), std::invalid_argument);
|
||||
CHECK_THROWS_AS(json::parser("]").parse(), std::invalid_argument);
|
||||
CHECK_THROWS_WITH(json::parser("[").parse(),
|
||||
"parse error - unexpected end of input");
|
||||
CHECK_THROWS_WITH(json::parser("[1").parse(),
|
||||
"parse error - unexpected end of input; expected ']'");
|
||||
CHECK_THROWS_WITH(json::parser("[1,").parse(),
|
||||
"parse error - unexpected end of input");
|
||||
CHECK_THROWS_WITH(json::parser("[1,]").parse(),
|
||||
"parse error - unexpected ']'");
|
||||
CHECK_THROWS_WITH(json::parser("]").parse(), "parse error - unexpected ']'");
|
||||
|
||||
// missing/unexpected end of object
|
||||
CHECK_THROWS_AS(json::parser("{").parse(), std::invalid_argument);
|
||||
CHECK_THROWS_AS(json::parser("{\"foo\"").parse(), std::invalid_argument);
|
||||
CHECK_THROWS_AS(json::parser("{\"foo\":").parse(), std::invalid_argument);
|
||||
CHECK_THROWS_AS(json::parser("{\"foo\":}").parse(), std::invalid_argument);
|
||||
CHECK_THROWS_AS(json::parser("{\"foo\":1,}").parse(), std::invalid_argument);
|
||||
CHECK_THROWS_AS(json::parser("}").parse(), std::invalid_argument);
|
||||
CHECK_THROWS_WITH(json::parser("{").parse(),
|
||||
"parse error - unexpected end of input; expected string literal");
|
||||
CHECK_THROWS_WITH(json::parser("{\"foo\"").parse(),
|
||||
"parse error - unexpected end of input; expected ':'");
|
||||
CHECK_THROWS_WITH(json::parser("{\"foo\":").parse(),
|
||||
"parse error - unexpected end of input");
|
||||
CHECK_THROWS_WITH(json::parser("{\"foo\":}").parse(),
|
||||
"parse error - unexpected '}'");
|
||||
CHECK_THROWS_WITH(json::parser("{\"foo\":1,}").parse(),
|
||||
"parse error - unexpected '}'; expected string literal");
|
||||
CHECK_THROWS_WITH(json::parser("}").parse(), "parse error - unexpected '}'");
|
||||
|
||||
// missing/unexpected end of string
|
||||
CHECK_THROWS_AS(json::parser("\"").parse(), std::invalid_argument);
|
||||
CHECK_THROWS_AS(json::parser("\"\\\"").parse(), std::invalid_argument);
|
||||
CHECK_THROWS_AS(json::parser("\"\\u\"").parse(), std::invalid_argument);
|
||||
CHECK_THROWS_AS(json::parser("\"\\u0\"").parse(), std::invalid_argument);
|
||||
CHECK_THROWS_AS(json::parser("\"\\u01\"").parse(), std::invalid_argument);
|
||||
CHECK_THROWS_AS(json::parser("\"\\u012\"").parse(), std::invalid_argument);
|
||||
CHECK_THROWS_WITH(json::parser("\"").parse(),
|
||||
"parse error - unexpected '\"'");
|
||||
CHECK_THROWS_WITH(json::parser("\"\\\"").parse(),
|
||||
"parse error - unexpected '\"'");
|
||||
CHECK_THROWS_WITH(json::parser("\"\\u\"").parse(),
|
||||
"parse error - unexpected '\"'");
|
||||
CHECK_THROWS_WITH(json::parser("\"\\u0\"").parse(),
|
||||
"parse error - unexpected '\"'");
|
||||
CHECK_THROWS_WITH(json::parser("\"\\u01\"").parse(),
|
||||
"parse error - unexpected '\"'");
|
||||
CHECK_THROWS_WITH(json::parser("\"\\u012\"").parse(),
|
||||
"parse error - unexpected '\"'");
|
||||
|
||||
// invalid escapes
|
||||
for (int c = 1; c < 128; ++c)
|
||||
{
|
||||
auto s = std::string("\"\\") + std::string(1, c) + "\"";
|
||||
|
||||
switch (c)
|
||||
{
|
||||
// valid escapes
|
||||
case ('"'):
|
||||
case ('\\'):
|
||||
case ('/'):
|
||||
case ('b'):
|
||||
case ('f'):
|
||||
case ('n'):
|
||||
case ('r'):
|
||||
case ('t'):
|
||||
{
|
||||
CHECK_NOTHROW(json::parser(s).parse());
|
||||
break;
|
||||
}
|
||||
|
||||
// \u must be followed with four numbers, so we skip it here
|
||||
case ('u'):
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
// any other combination of backslash and character is invalid
|
||||
default:
|
||||
{
|
||||
CHECK_THROWS_AS(json::parser(s).parse(), std::invalid_argument);
|
||||
CHECK_THROWS_WITH(json::parser(s).parse(), "parse error - unexpected '\"'");
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// invalid \uxxxx escapes
|
||||
{
|
||||
// check whether character is a valid hex character
|
||||
const auto valid = [](int c)
|
||||
{
|
||||
switch (c)
|
||||
{
|
||||
case ('0'):
|
||||
case ('1'):
|
||||
case ('2'):
|
||||
case ('3'):
|
||||
case ('4'):
|
||||
case ('5'):
|
||||
case ('6'):
|
||||
case ('7'):
|
||||
case ('8'):
|
||||
case ('9'):
|
||||
case ('a'):
|
||||
case ('b'):
|
||||
case ('c'):
|
||||
case ('d'):
|
||||
case ('e'):
|
||||
case ('f'):
|
||||
case ('A'):
|
||||
case ('B'):
|
||||
case ('C'):
|
||||
case ('D'):
|
||||
case ('E'):
|
||||
case ('F'):
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
default:
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
for (int c = 1; c < 128; ++c)
|
||||
{
|
||||
std::string s = "\"\\u";
|
||||
|
||||
// create a string with the iterated character at each position
|
||||
auto s1 = s + "000" + std::string(1, c) + "\"";
|
||||
auto s2 = s + "00" + std::string(1, c) + "0\"";
|
||||
auto s3 = s + "0" + std::string(1, c) + "00\"";
|
||||
auto s4 = s + std::string(1, c) + "000\"";
|
||||
|
||||
if (valid(c))
|
||||
{
|
||||
CHECK_NOTHROW(json::parser(s1).parse());
|
||||
CHECK_NOTHROW(json::parser(s2).parse());
|
||||
CHECK_NOTHROW(json::parser(s3).parse());
|
||||
CHECK_NOTHROW(json::parser(s4).parse());
|
||||
}
|
||||
else
|
||||
{
|
||||
CHECK_THROWS_AS(json::parser(s1).parse(), std::invalid_argument);
|
||||
CHECK_THROWS_AS(json::parser(s2).parse(), std::invalid_argument);
|
||||
CHECK_THROWS_AS(json::parser(s3).parse(), std::invalid_argument);
|
||||
CHECK_THROWS_AS(json::parser(s4).parse(), std::invalid_argument);
|
||||
|
||||
CHECK_THROWS_WITH(json::parser(s1).parse(), "parse error - unexpected '\"'");
|
||||
CHECK_THROWS_WITH(json::parser(s2).parse(), "parse error - unexpected '\"'");
|
||||
CHECK_THROWS_WITH(json::parser(s3).parse(), "parse error - unexpected '\"'");
|
||||
CHECK_THROWS_WITH(json::parser(s4).parse(), "parse error - unexpected '\"'");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// missing part of a surrogate pair
|
||||
CHECK_THROWS_AS(json::parse("\"\\uD80C\""), std::invalid_argument);
|
||||
CHECK_THROWS_WITH(json::parse("\"\\uD80C\""), "missing low surrogate");
|
||||
// invalid surrogate pair
|
||||
CHECK_THROWS_AS(json::parse("\"\\uD80C\\uD80C\""), std::invalid_argument);
|
||||
CHECK_THROWS_AS(json::parse("\"\\uD80C\\u0000\""), std::invalid_argument);
|
||||
CHECK_THROWS_AS(json::parse("\"\\uD80C\\uFFFF\""), std::invalid_argument);
|
||||
CHECK_THROWS_WITH(json::parse("\"\\uD80C\\uD80C\""),
|
||||
"missing or wrong low surrogate");
|
||||
CHECK_THROWS_WITH(json::parse("\"\\uD80C\\u0000\""),
|
||||
"missing or wrong low surrogate");
|
||||
CHECK_THROWS_WITH(json::parse("\"\\uD80C\\uFFFF\""),
|
||||
"missing or wrong low surrogate");
|
||||
}
|
||||
|
||||
SECTION("callback function")
|
||||
{
|
||||
auto s_object = R"(
|
||||
{
|
||||
"foo": 2,
|
||||
"bar": {
|
||||
"baz": 1
|
||||
}
|
||||
}
|
||||
)";
|
||||
|
||||
auto s_array = R"(
|
||||
[1,2,[3,4,5],4,5]
|
||||
)";
|
||||
|
||||
SECTION("filter nothing")
|
||||
{
|
||||
json j_object = json::parse(s_object, [](int, json::parse_event_t, const json&)
|
||||
{
|
||||
return true;
|
||||
});
|
||||
|
||||
CHECK (j_object == json({{"foo", 2}, {"bar", {{"baz", 1}}}}));
|
||||
|
||||
json j_array = json::parse(s_array, [](int, json::parse_event_t, const json&)
|
||||
{
|
||||
return true;
|
||||
});
|
||||
|
||||
CHECK (j_array == json({1, 2, {3, 4, 5}, 4, 5}));
|
||||
}
|
||||
|
||||
SECTION("filter everything")
|
||||
{
|
||||
json j_object = json::parse(s_object, [](int, json::parse_event_t, const json&)
|
||||
{
|
||||
return false;
|
||||
});
|
||||
|
||||
// the top-level object will be discarded, leaving a null
|
||||
CHECK (j_object.is_null());
|
||||
|
||||
json j_array = json::parse(s_array, [](int, json::parse_event_t, const json&)
|
||||
{
|
||||
return false;
|
||||
});
|
||||
|
||||
// the top-level array will be discarded, leaving a null
|
||||
CHECK (j_array.is_null());
|
||||
}
|
||||
|
||||
SECTION("filter specific element")
|
||||
{
|
||||
json j_object = json::parse(s_object, [](int, json::parse_event_t, const json & j)
|
||||
{
|
||||
// filter all number(2) elements
|
||||
if (j == json(2))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
return true;
|
||||
}
|
||||
});
|
||||
|
||||
CHECK (j_object == json({{"bar", {{"baz", 1}}}}));
|
||||
|
||||
json j_array = json::parse(s_array, [](int, json::parse_event_t, const json & j)
|
||||
{
|
||||
if (j == json(2))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
return true;
|
||||
}
|
||||
});
|
||||
|
||||
CHECK (j_array == json({1, {3, 4, 5}, 4, 5}));
|
||||
}
|
||||
|
||||
SECTION("filter specific events")
|
||||
{
|
||||
SECTION("first closing event")
|
||||
{
|
||||
{
|
||||
json j_object = json::parse(s_object, [](int, json::parse_event_t e, const json&)
|
||||
{
|
||||
static bool first = true;
|
||||
if (e == json::parse_event_t::object_end and first)
|
||||
{
|
||||
first = false;
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
return true;
|
||||
}
|
||||
});
|
||||
|
||||
// the first completed object will be discarded
|
||||
CHECK (j_object == json({{"foo", 2}}));
|
||||
}
|
||||
|
||||
{
|
||||
json j_array = json::parse(s_array, [](int, json::parse_event_t e, const json&)
|
||||
{
|
||||
static bool first = true;
|
||||
if (e == json::parse_event_t::array_end and first)
|
||||
{
|
||||
first = false;
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
return true;
|
||||
}
|
||||
});
|
||||
|
||||
// the first completed array will be discarded
|
||||
CHECK (j_array == json({1, 2, 4, 5}));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
SECTION("special cases")
|
||||
{
|
||||
// the following test cases cover the situation in which an empty
|
||||
// object and array is discarded only after the closing character
|
||||
// has been read
|
||||
|
||||
json j_empty_object = json::parse("{}", [](int, json::parse_event_t e, const json&)
|
||||
{
|
||||
if (e == json::parse_event_t::object_end)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
return true;
|
||||
}
|
||||
});
|
||||
CHECK(j_empty_object == json());
|
||||
|
||||
json j_empty_array = json::parse("[]", [](int, json::parse_event_t e, const json&)
|
||||
{
|
||||
if (e == json::parse_event_t::array_end)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
return true;
|
||||
}
|
||||
});
|
||||
CHECK(j_empty_array == json());
|
||||
}
|
||||
}
|
||||
|
||||
SECTION("copy constructor")
|
||||
{
|
||||
json::string_t* s = new json::string_t("[1,2,3,4]");
|
||||
json::parser p(*s);
|
||||
delete s;
|
||||
CHECK(p.parse() == json({1, 2, 3, 4}));
|
||||
}
|
||||
}
|
246
test/src/unit-comparison.cpp
Normal file
246
test/src/unit-comparison.cpp
Normal file
|
@ -0,0 +1,246 @@
|
|||
/*
|
||||
__ _____ _____ _____
|
||||
__| | __| | | | JSON for Modern C++ (test suite)
|
||||
| | |__ | | | | | | version 2.0.2
|
||||
|_____|_____|_____|_|___| https://github.com/nlohmann/json
|
||||
|
||||
Licensed under the MIT License <http://opensource.org/licenses/MIT>.
|
||||
Copyright (c) 2013-2016 Niels Lohmann <http://nlohmann.me>.
|
||||
|
||||
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("lexicographical comparison operators")
|
||||
{
|
||||
SECTION("types")
|
||||
{
|
||||
std::vector<json::value_t> j_types =
|
||||
{
|
||||
json::value_t::null,
|
||||
json::value_t::boolean,
|
||||
json::value_t::number_integer,
|
||||
json::value_t::number_unsigned,
|
||||
json::value_t::number_float,
|
||||
json::value_t::object,
|
||||
json::value_t::array,
|
||||
json::value_t::string
|
||||
};
|
||||
|
||||
SECTION("comparison: less")
|
||||
{
|
||||
std::vector<std::vector<bool>> expected =
|
||||
{
|
||||
{false, true, true, true, true, true, true, true},
|
||||
{false, false, true, true, true, true, true, true},
|
||||
{false, false, false, false, false, true, true, true},
|
||||
{false, false, false, false, false, true, true, true},
|
||||
{false, false, false, false, false, true, true, true},
|
||||
{false, false, false, false, false, false, true, true},
|
||||
{false, false, false, false, false, false, false, true},
|
||||
{false, false, false, false, false, false, false, false}
|
||||
};
|
||||
|
||||
for (size_t i = 0; i < j_types.size(); ++i)
|
||||
{
|
||||
for (size_t j = 0; j < j_types.size(); ++j)
|
||||
{
|
||||
CAPTURE(i);
|
||||
CAPTURE(j);
|
||||
// check precomputed values
|
||||
CHECK(operator<(j_types[i], j_types[j]) == expected[i][j]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
SECTION("values")
|
||||
{
|
||||
json j_values =
|
||||
{
|
||||
nullptr, nullptr,
|
||||
17, 42,
|
||||
8u, 13u,
|
||||
3.14159, 23.42,
|
||||
"foo", "bar",
|
||||
true, false,
|
||||
{1, 2, 3}, {"one", "two", "three"},
|
||||
{{"first", 1}, {"second", 2}}, {{"a", "A"}, {"b", {"B"}}}
|
||||
};
|
||||
|
||||
SECTION("comparison: equal")
|
||||
{
|
||||
std::vector<std::vector<bool>> expected =
|
||||
{
|
||||
{true, true, false, false, false, false, false, false, false, false, false, false, false, false, false, false},
|
||||
{true, true, false, false, false, false, false, false, false, false, false, false, false, false, false, false},
|
||||
{false, false, true, false, false, false, false, false, false, false, false, false, false, false, false, false},
|
||||
{false, false, false, true, false, false, false, false, false, false, false, false, false, false, false, false},
|
||||
{false, false, false, false, true, false, false, false, false, false, false, false, false, false, false, false},
|
||||
{false, false, false, false, false, true, false, false, false, false, false, false, false, false, false, false},
|
||||
{false, false, false, false, false, false, true, false, false, false, false, false, false, false, false, false},
|
||||
{false, false, false, false, false, false, false, true, false, false, false, false, false, false, false, false},
|
||||
{false, false, false, false, false, false, false, false, true, false, false, false, false, false, false, false},
|
||||
{false, false, false, false, false, false, false, false, false, true, false, false, false, false, false, false},
|
||||
{false, false, false, false, false, false, false, false, false, false, true, false, false, false, false, false},
|
||||
{false, false, false, false, false, false, false, false, false, false, false, true, false, false, false, false},
|
||||
{false, false, false, false, false, false, false, false, false, false, false, false, true, false, false, false},
|
||||
{false, false, false, false, false, false, false, false, false, false, false, false, false, true, false, false},
|
||||
{false, false, false, false, false, false, false, false, false, false, false, false, false, false, true, false},
|
||||
{false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, true}
|
||||
};
|
||||
|
||||
for (size_t i = 0; i < j_values.size(); ++i)
|
||||
{
|
||||
for (size_t j = 0; j < j_values.size(); ++j)
|
||||
{
|
||||
CAPTURE(i);
|
||||
CAPTURE(j);
|
||||
// check precomputed values
|
||||
CHECK( (j_values[i] == j_values[j]) == expected[i][j] );
|
||||
}
|
||||
}
|
||||
|
||||
// comparison with discarded elements
|
||||
json j_discarded(json::value_t::discarded);
|
||||
for (size_t i = 0; i < j_values.size(); ++i)
|
||||
{
|
||||
CHECK( (j_values[i] == j_discarded) == false);
|
||||
CHECK( (j_discarded == j_values[i]) == false);
|
||||
CHECK( (j_discarded == j_discarded) == false);
|
||||
}
|
||||
|
||||
// compare with null pointer
|
||||
json j_null;
|
||||
CHECK(j_null == nullptr);
|
||||
CHECK(nullptr == j_null);
|
||||
}
|
||||
|
||||
SECTION("comparison: not equal")
|
||||
{
|
||||
for (size_t i = 0; i < j_values.size(); ++i)
|
||||
{
|
||||
for (size_t j = 0; j < j_values.size(); ++j)
|
||||
{
|
||||
CAPTURE(i);
|
||||
CAPTURE(j);
|
||||
// check definition
|
||||
CHECK( (j_values[i] != j_values[j]) == not(j_values[i] == j_values[j]) );
|
||||
}
|
||||
}
|
||||
|
||||
// compare with null pointer
|
||||
json j_null;
|
||||
CHECK( (j_null != nullptr) == false);
|
||||
CHECK( (nullptr != j_null) == false);
|
||||
CHECK( (j_null != nullptr) == not(j_null == nullptr));
|
||||
CHECK( (nullptr != j_null) == not(nullptr == j_null));
|
||||
}
|
||||
|
||||
SECTION("comparison: less")
|
||||
{
|
||||
std::vector<std::vector<bool>> expected =
|
||||
{
|
||||
{false, false, true, true, true, true, true, true, true, true, true, true, true, true, true, true},
|
||||
{false, false, true, true, true, true, true, true, true, true, true, true, true, true, true, true},
|
||||
{false, false, false, true, false, false, false, true, true, true, false, false, true, true, true, true},
|
||||
{false, false, false, false, false, false, false, false, true, true, false, false, true, true, true, true},
|
||||
{false, false, true, true, false, true, false, true, true, true, false, false, true, true, true, true},
|
||||
{false, false, true, true, false, false, false, true, true, true, false, false, true, true, true, true},
|
||||
{false, false, true, true, true, true, false, true, true, true, false, false, true, true, true, true},
|
||||
{false, false, false, true, false, false, false, false, true, true, false, false, true, true, true, true},
|
||||
{false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false},
|
||||
{false, false, false, false, false, false, false, false, true, false, false, false, false, false, false, false},
|
||||
{false, false, true, true, true, true, true, true, true, true, false, false, true, true, true, true},
|
||||
{false, false, true, true, true, true, true, true, true, true, true, false, true, true, true, true},
|
||||
{false, false, false, false, false, false, false, false, true, true, false, false, false, true, false, false},
|
||||
{false, false, false, false, false, false, false, false, true, true, false, false, false, false, false, false},
|
||||
{false, false, false, false, false, false, false, false, true, true, false, false, true, true, false, false},
|
||||
{false, false, false, false, false, false, false, false, true, true, false, false, true, true, true, false}
|
||||
};
|
||||
|
||||
for (size_t i = 0; i < j_values.size(); ++i)
|
||||
{
|
||||
for (size_t j = 0; j < j_values.size(); ++j)
|
||||
{
|
||||
CAPTURE(i);
|
||||
CAPTURE(j);
|
||||
// check precomputed values
|
||||
CHECK( (j_values[i] < j_values[j]) == expected[i][j] );
|
||||
}
|
||||
}
|
||||
|
||||
// comparison with discarded elements
|
||||
json j_discarded(json::value_t::discarded);
|
||||
for (size_t i = 0; i < j_values.size(); ++i)
|
||||
{
|
||||
CAPTURE(i);
|
||||
CHECK( (j_values[i] < j_discarded) == false);
|
||||
CHECK( (j_discarded < j_values[i]) == false);
|
||||
CHECK( (j_discarded < j_discarded) == false);
|
||||
}
|
||||
}
|
||||
|
||||
SECTION("comparison: less than or equal equal")
|
||||
{
|
||||
for (size_t i = 0; i < j_values.size(); ++i)
|
||||
{
|
||||
for (size_t j = 0; j < j_values.size(); ++j)
|
||||
{
|
||||
CAPTURE(i);
|
||||
CAPTURE(j);
|
||||
// check definition
|
||||
CHECK( (j_values[i] <= j_values[j]) == not(j_values[j] < j_values[i]) );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
SECTION("comparison: greater than")
|
||||
{
|
||||
for (size_t i = 0; i < j_values.size(); ++i)
|
||||
{
|
||||
for (size_t j = 0; j < j_values.size(); ++j)
|
||||
{
|
||||
CAPTURE(i);
|
||||
CAPTURE(j);
|
||||
// check definition
|
||||
CHECK( (j_values[i] > j_values[j]) == (j_values[j] < j_values[i]) );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
SECTION("comparison: greater than or equal")
|
||||
{
|
||||
for (size_t i = 0; i < j_values.size(); ++i)
|
||||
{
|
||||
for (size_t j = 0; j < j_values.size(); ++j)
|
||||
{
|
||||
CAPTURE(i);
|
||||
CAPTURE(j);
|
||||
// check definition
|
||||
CHECK( (j_values[i] >= j_values[j]) == not(j_values[i] < j_values[j]) );
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
169
test/src/unit-concepts.cpp
Normal file
169
test/src/unit-concepts.cpp
Normal file
|
@ -0,0 +1,169 @@
|
|||
/*
|
||||
__ _____ _____ _____
|
||||
__| | __| | | | JSON for Modern C++ (test suite)
|
||||
| | |__ | | | | | | version 2.0.2
|
||||
|_____|_____|_____|_|___| https://github.com/nlohmann/json
|
||||
|
||||
Licensed under the MIT License <http://opensource.org/licenses/MIT>.
|
||||
Copyright (c) 2013-2016 Niels Lohmann <http://nlohmann.me>.
|
||||
|
||||
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("concepts")
|
||||
{
|
||||
SECTION("container requirements for json")
|
||||
{
|
||||
// X: container class: json
|
||||
// T: type of objects: json
|
||||
// a, b: values of type X: json
|
||||
|
||||
// TABLE 96 - Container Requirements
|
||||
|
||||
// X::value_type must return T
|
||||
CHECK((std::is_same<json::value_type, json>::value));
|
||||
|
||||
// X::reference must return lvalue of T
|
||||
CHECK((std::is_same<json::reference, json&>::value));
|
||||
|
||||
// X::const_reference must return const lvalue of T
|
||||
CHECK((std::is_same<json::const_reference, const json&>::value));
|
||||
|
||||
// X::iterator must return iterator whose value_type is T
|
||||
CHECK((std::is_same<json::iterator::value_type, json>::value));
|
||||
// X::iterator must meet the forward iterator requirements
|
||||
CHECK((std::is_base_of<std::forward_iterator_tag, typename std::iterator_traits<json::iterator>::iterator_category>::value));
|
||||
// X::iterator must be convertible to X::const_iterator
|
||||
CHECK((std::is_convertible<json::iterator, json::const_iterator>::value));
|
||||
|
||||
// X::const_iterator must return iterator whose value_type is T
|
||||
CHECK((std::is_same<json::const_iterator::value_type, json>::value));
|
||||
// X::const_iterator must meet the forward iterator requirements
|
||||
CHECK((std::is_base_of<std::forward_iterator_tag, typename std::iterator_traits<json::const_iterator>::iterator_category>::value));
|
||||
|
||||
// X::difference_type must return a signed integer
|
||||
CHECK((std::is_signed<json::difference_type>::value));
|
||||
// X::difference_type must be identical to X::iterator::difference_type
|
||||
CHECK((std::is_same<json::difference_type, json::iterator::difference_type>::value));
|
||||
// X::difference_type must be identical to X::const_iterator::difference_type
|
||||
CHECK((std::is_same<json::difference_type, json::const_iterator::difference_type>::value));
|
||||
|
||||
// X::size_type must return an unsigned integer
|
||||
CHECK((std::is_unsigned<json::size_type>::value));
|
||||
// X::size_type can represent any non-negative value of X::difference_type
|
||||
CHECK(std::numeric_limits<json::difference_type>::max() <=
|
||||
std::numeric_limits<json::size_type>::max());
|
||||
|
||||
// the expression "X u" has the post-condition "u.empty()"
|
||||
{
|
||||
json u;
|
||||
CHECK(u.empty());
|
||||
}
|
||||
|
||||
// the expression "X()" has the post-condition "X().empty()"
|
||||
CHECK(json().empty());
|
||||
}
|
||||
|
||||
SECTION("class json")
|
||||
{
|
||||
SECTION("DefaultConstructible")
|
||||
{
|
||||
CHECK(std::is_nothrow_default_constructible<json>::value);
|
||||
}
|
||||
|
||||
SECTION("MoveConstructible")
|
||||
{
|
||||
CHECK(std::is_nothrow_move_constructible<json>::value);
|
||||
}
|
||||
|
||||
SECTION("CopyConstructible")
|
||||
{
|
||||
CHECK(std::is_copy_constructible<json>::value);
|
||||
}
|
||||
|
||||
SECTION("MoveAssignable")
|
||||
{
|
||||
CHECK(std::is_nothrow_move_assignable<json>::value);
|
||||
}
|
||||
|
||||
SECTION("CopyAssignable")
|
||||
{
|
||||
CHECK(std::is_copy_assignable<json>::value);
|
||||
}
|
||||
|
||||
SECTION("Destructible")
|
||||
{
|
||||
CHECK(std::is_nothrow_destructible<json>::value);
|
||||
}
|
||||
|
||||
SECTION("StandardLayoutType")
|
||||
{
|
||||
CHECK(std::is_standard_layout<json>::value);
|
||||
}
|
||||
}
|
||||
|
||||
SECTION("class iterator")
|
||||
{
|
||||
SECTION("CopyConstructible")
|
||||
{
|
||||
CHECK(std::is_nothrow_copy_constructible<json::iterator>::value);
|
||||
CHECK(std::is_nothrow_copy_constructible<json::const_iterator>::value);
|
||||
}
|
||||
|
||||
SECTION("CopyAssignable")
|
||||
{
|
||||
// STL iterators used by json::iterator don't pass this test in Debug mode
|
||||
#if !defined(_MSC_VER) || (_ITERATOR_DEBUG_LEVEL == 0)
|
||||
CHECK(std::is_nothrow_copy_assignable<json::iterator>::value);
|
||||
CHECK(std::is_nothrow_copy_assignable<json::const_iterator>::value);
|
||||
#endif
|
||||
}
|
||||
|
||||
SECTION("Destructible")
|
||||
{
|
||||
CHECK(std::is_nothrow_destructible<json::iterator>::value);
|
||||
CHECK(std::is_nothrow_destructible<json::const_iterator>::value);
|
||||
}
|
||||
|
||||
SECTION("Swappable")
|
||||
{
|
||||
{
|
||||
json j {1, 2, 3};
|
||||
json::iterator it1 = j.begin();
|
||||
json::iterator it2 = j.end();
|
||||
std::swap(it1, it2);
|
||||
CHECK(it1 == j.end());
|
||||
CHECK(it2 == j.begin());
|
||||
}
|
||||
{
|
||||
json j {1, 2, 3};
|
||||
json::const_iterator it1 = j.cbegin();
|
||||
json::const_iterator it2 = j.cend();
|
||||
std::swap(it1, it2);
|
||||
CHECK(it1 == j.end());
|
||||
CHECK(it2 == j.begin());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
1470
test/src/unit-constructor.cpp
Normal file
1470
test/src/unit-constructor.cpp
Normal file
File diff suppressed because it is too large
Load diff
92
test/src/unit-convenience.cpp
Normal file
92
test/src/unit-convenience.cpp
Normal file
|
@ -0,0 +1,92 @@
|
|||
/*
|
||||
__ _____ _____ _____
|
||||
__| | __| | | | JSON for Modern C++ (test suite)
|
||||
| | |__ | | | | | | version 2.0.2
|
||||
|_____|_____|_____|_|___| https://github.com/nlohmann/json
|
||||
|
||||
Licensed under the MIT License <http://opensource.org/licenses/MIT>.
|
||||
Copyright (c) 2013-2016 Niels Lohmann <http://nlohmann.me>.
|
||||
|
||||
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"
|
||||
|
||||
#define private public
|
||||
#include "json.hpp"
|
||||
using nlohmann::json;
|
||||
|
||||
TEST_CASE("convenience functions")
|
||||
{
|
||||
SECTION("type name as string")
|
||||
{
|
||||
CHECK(json(json::value_t::null).type_name() == "null");
|
||||
CHECK(json(json::value_t::object).type_name() == "object");
|
||||
CHECK(json(json::value_t::array).type_name() == "array");
|
||||
CHECK(json(json::value_t::number_integer).type_name() == "number");
|
||||
CHECK(json(json::value_t::number_unsigned).type_name() == "number");
|
||||
CHECK(json(json::value_t::number_float).type_name() == "number");
|
||||
CHECK(json(json::value_t::boolean).type_name() == "boolean");
|
||||
CHECK(json(json::value_t::string).type_name() == "string");
|
||||
CHECK(json(json::value_t::discarded).type_name() == "discarded");
|
||||
}
|
||||
|
||||
SECTION("string escape")
|
||||
{
|
||||
CHECK(json::escape_string("\"") == "\\\"");
|
||||
CHECK(json::escape_string("\\") == "\\\\");
|
||||
CHECK(json::escape_string("\b") == "\\b");
|
||||
CHECK(json::escape_string("\f") == "\\f");
|
||||
CHECK(json::escape_string("\n") == "\\n");
|
||||
CHECK(json::escape_string("\r") == "\\r");
|
||||
CHECK(json::escape_string("\t") == "\\t");
|
||||
|
||||
CHECK(json::escape_string("\x01") == "\\u0001");
|
||||
CHECK(json::escape_string("\x02") == "\\u0002");
|
||||
CHECK(json::escape_string("\x03") == "\\u0003");
|
||||
CHECK(json::escape_string("\x04") == "\\u0004");
|
||||
CHECK(json::escape_string("\x05") == "\\u0005");
|
||||
CHECK(json::escape_string("\x06") == "\\u0006");
|
||||
CHECK(json::escape_string("\x07") == "\\u0007");
|
||||
CHECK(json::escape_string("\x08") == "\\b");
|
||||
CHECK(json::escape_string("\x09") == "\\t");
|
||||
CHECK(json::escape_string("\x0a") == "\\n");
|
||||
CHECK(json::escape_string("\x0b") == "\\u000b");
|
||||
CHECK(json::escape_string("\x0c") == "\\f");
|
||||
CHECK(json::escape_string("\x0d") == "\\r");
|
||||
CHECK(json::escape_string("\x0e") == "\\u000e");
|
||||
CHECK(json::escape_string("\x0f") == "\\u000f");
|
||||
CHECK(json::escape_string("\x10") == "\\u0010");
|
||||
CHECK(json::escape_string("\x11") == "\\u0011");
|
||||
CHECK(json::escape_string("\x12") == "\\u0012");
|
||||
CHECK(json::escape_string("\x13") == "\\u0013");
|
||||
CHECK(json::escape_string("\x14") == "\\u0014");
|
||||
CHECK(json::escape_string("\x15") == "\\u0015");
|
||||
CHECK(json::escape_string("\x16") == "\\u0016");
|
||||
CHECK(json::escape_string("\x17") == "\\u0017");
|
||||
CHECK(json::escape_string("\x18") == "\\u0018");
|
||||
CHECK(json::escape_string("\x19") == "\\u0019");
|
||||
CHECK(json::escape_string("\x1a") == "\\u001a");
|
||||
CHECK(json::escape_string("\x1b") == "\\u001b");
|
||||
CHECK(json::escape_string("\x1c") == "\\u001c");
|
||||
CHECK(json::escape_string("\x1d") == "\\u001d");
|
||||
CHECK(json::escape_string("\x1e") == "\\u001e");
|
||||
CHECK(json::escape_string("\x1f") == "\\u001f");
|
||||
}
|
||||
}
|
1014
test/src/unit-conversions.cpp
Normal file
1014
test/src/unit-conversions.cpp
Normal file
File diff suppressed because it is too large
Load diff
73
test/src/unit-deserialization.cpp
Normal file
73
test/src/unit-deserialization.cpp
Normal file
|
@ -0,0 +1,73 @@
|
|||
/*
|
||||
__ _____ _____ _____
|
||||
__| | __| | | | JSON for Modern C++ (test suite)
|
||||
| | |__ | | | | | | version 2.0.2
|
||||
|_____|_____|_____|_|___| https://github.com/nlohmann/json
|
||||
|
||||
Licensed under the MIT License <http://opensource.org/licenses/MIT>.
|
||||
Copyright (c) 2013-2016 Niels Lohmann <http://nlohmann.me>.
|
||||
|
||||
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("deserialization")
|
||||
{
|
||||
SECTION("stream")
|
||||
{
|
||||
std::stringstream ss;
|
||||
ss << "[\"foo\",1,2,3,false,{\"one\":1}]";
|
||||
json j = json::parse(ss);
|
||||
CHECK(j == json({"foo", 1, 2, 3, false, {{"one", 1}}}));
|
||||
}
|
||||
|
||||
SECTION("string")
|
||||
{
|
||||
auto s = "[\"foo\",1,2,3,false,{\"one\":1}]";
|
||||
json j = json::parse(s);
|
||||
CHECK(j == json({"foo", 1, 2, 3, false, {{"one", 1}}}));
|
||||
}
|
||||
|
||||
SECTION("operator<<")
|
||||
{
|
||||
std::stringstream ss;
|
||||
ss << "[\"foo\",1,2,3,false,{\"one\":1}]";
|
||||
json j;
|
||||
j << ss;
|
||||
CHECK(j == json({"foo", 1, 2, 3, false, {{"one", 1}}}));
|
||||
}
|
||||
|
||||
SECTION("operator>>")
|
||||
{
|
||||
std::stringstream ss;
|
||||
ss << "[\"foo\",1,2,3,false,{\"one\":1}]";
|
||||
json j;
|
||||
ss >> j;
|
||||
CHECK(j == json({"foo", 1, 2, 3, false, {{"one", 1}}}));
|
||||
}
|
||||
|
||||
SECTION("user-defined string literal")
|
||||
{
|
||||
CHECK("[\"foo\",1,2,3,false,{\"one\":1}]"_json == json({"foo", 1, 2, 3, false, {{"one", 1}}}));
|
||||
}
|
||||
}
|
1871
test/src/unit-element_access.cpp
Normal file
1871
test/src/unit-element_access.cpp
Normal file
File diff suppressed because it is too large
Load diff
373
test/src/unit-inspection.cpp
Normal file
373
test/src/unit-inspection.cpp
Normal file
|
@ -0,0 +1,373 @@
|
|||
/*
|
||||
__ _____ _____ _____
|
||||
__| | __| | | | JSON for Modern C++ (test suite)
|
||||
| | |__ | | | | | | version 2.0.2
|
||||
|_____|_____|_____|_|___| https://github.com/nlohmann/json
|
||||
|
||||
Licensed under the MIT License <http://opensource.org/licenses/MIT>.
|
||||
Copyright (c) 2013-2016 Niels Lohmann <http://nlohmann.me>.
|
||||
|
||||
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("object inspection")
|
||||
{
|
||||
SECTION("convenience type checker")
|
||||
{
|
||||
SECTION("object")
|
||||
{
|
||||
json j {{"foo", 1}, {"bar", false}};
|
||||
CHECK(not j.is_null());
|
||||
CHECK(not j.is_boolean());
|
||||
CHECK(not j.is_number());
|
||||
CHECK(not j.is_number_integer());
|
||||
CHECK(not j.is_number_unsigned());
|
||||
CHECK(not j.is_number_float());
|
||||
CHECK(j.is_object());
|
||||
CHECK(not j.is_array());
|
||||
CHECK(not j.is_string());
|
||||
CHECK(not j.is_discarded());
|
||||
CHECK(not j.is_primitive());
|
||||
CHECK(j.is_structured());
|
||||
}
|
||||
|
||||
SECTION("array")
|
||||
{
|
||||
json j {"foo", 1, 1u, 42.23, false};
|
||||
CHECK(not j.is_null());
|
||||
CHECK(not j.is_boolean());
|
||||
CHECK(not j.is_number());
|
||||
CHECK(not j.is_number_integer());
|
||||
CHECK(not j.is_number_unsigned());
|
||||
CHECK(not j.is_number_float());
|
||||
CHECK(not j.is_object());
|
||||
CHECK(j.is_array());
|
||||
CHECK(not j.is_string());
|
||||
CHECK(not j.is_discarded());
|
||||
CHECK(not j.is_primitive());
|
||||
CHECK(j.is_structured());
|
||||
}
|
||||
|
||||
SECTION("null")
|
||||
{
|
||||
json j(nullptr);
|
||||
CHECK(j.is_null());
|
||||
CHECK(not j.is_boolean());
|
||||
CHECK(not j.is_number());
|
||||
CHECK(not j.is_number_integer());
|
||||
CHECK(not j.is_number_unsigned());
|
||||
CHECK(not j.is_number_float());
|
||||
CHECK(not j.is_object());
|
||||
CHECK(not j.is_array());
|
||||
CHECK(not j.is_string());
|
||||
CHECK(not j.is_discarded());
|
||||
CHECK(j.is_primitive());
|
||||
CHECK(not j.is_structured());
|
||||
}
|
||||
|
||||
SECTION("boolean")
|
||||
{
|
||||
json j(true);
|
||||
CHECK(not j.is_null());
|
||||
CHECK(j.is_boolean());
|
||||
CHECK(not j.is_number());
|
||||
CHECK(not j.is_number_integer());
|
||||
CHECK(not j.is_number_unsigned());
|
||||
CHECK(not j.is_number_float());
|
||||
CHECK(not j.is_object());
|
||||
CHECK(not j.is_array());
|
||||
CHECK(not j.is_string());
|
||||
CHECK(not j.is_discarded());
|
||||
CHECK(j.is_primitive());
|
||||
CHECK(not j.is_structured());
|
||||
}
|
||||
|
||||
SECTION("string")
|
||||
{
|
||||
json j("Hello world");
|
||||
CHECK(not j.is_null());
|
||||
CHECK(not j.is_boolean());
|
||||
CHECK(not j.is_number());
|
||||
CHECK(not j.is_number_integer());
|
||||
CHECK(not j.is_number_unsigned());
|
||||
CHECK(not j.is_number_float());
|
||||
CHECK(not j.is_object());
|
||||
CHECK(not j.is_array());
|
||||
CHECK(j.is_string());
|
||||
CHECK(not j.is_discarded());
|
||||
CHECK(j.is_primitive());
|
||||
CHECK(not j.is_structured());
|
||||
}
|
||||
|
||||
SECTION("number (integer)")
|
||||
{
|
||||
json j(42);
|
||||
CHECK(not j.is_null());
|
||||
CHECK(not j.is_boolean());
|
||||
CHECK(j.is_number());
|
||||
CHECK(j.is_number_integer());
|
||||
CHECK(not j.is_number_unsigned());
|
||||
CHECK(not j.is_number_float());
|
||||
CHECK(not j.is_object());
|
||||
CHECK(not j.is_array());
|
||||
CHECK(not j.is_string());
|
||||
CHECK(not j.is_discarded());
|
||||
CHECK(j.is_primitive());
|
||||
CHECK(not j.is_structured());
|
||||
}
|
||||
|
||||
SECTION("number (unsigned)")
|
||||
{
|
||||
json j(42u);
|
||||
CHECK(not j.is_null());
|
||||
CHECK(not j.is_boolean());
|
||||
CHECK(j.is_number());
|
||||
CHECK(j.is_number_integer());
|
||||
CHECK(j.is_number_unsigned());
|
||||
CHECK(not j.is_number_float());
|
||||
CHECK(not j.is_object());
|
||||
CHECK(not j.is_array());
|
||||
CHECK(not j.is_string());
|
||||
CHECK(not j.is_discarded());
|
||||
CHECK(j.is_primitive());
|
||||
CHECK(not j.is_structured());
|
||||
}
|
||||
|
||||
SECTION("number (floating-point)")
|
||||
{
|
||||
json j(42.23);
|
||||
CHECK(not j.is_null());
|
||||
CHECK(not j.is_boolean());
|
||||
CHECK(j.is_number());
|
||||
CHECK(not j.is_number_integer());
|
||||
CHECK(not j.is_number_unsigned());
|
||||
CHECK(j.is_number_float());
|
||||
CHECK(not j.is_object());
|
||||
CHECK(not j.is_array());
|
||||
CHECK(not j.is_string());
|
||||
CHECK(not j.is_discarded());
|
||||
CHECK(j.is_primitive());
|
||||
CHECK(not j.is_structured());
|
||||
}
|
||||
|
||||
SECTION("discarded")
|
||||
{
|
||||
json j(json::value_t::discarded);
|
||||
CHECK(not j.is_null());
|
||||
CHECK(not j.is_boolean());
|
||||
CHECK(not j.is_number());
|
||||
CHECK(not j.is_number_integer());
|
||||
CHECK(not j.is_number_unsigned());
|
||||
CHECK(not j.is_number_float());
|
||||
CHECK(not j.is_object());
|
||||
CHECK(not j.is_array());
|
||||
CHECK(not j.is_string());
|
||||
CHECK(j.is_discarded());
|
||||
CHECK(not j.is_primitive());
|
||||
CHECK(not j.is_structured());
|
||||
}
|
||||
}
|
||||
|
||||
SECTION("serialization")
|
||||
{
|
||||
json j {{"object", json::object()}, {"array", {1, 2, 3, 4}}, {"number", 42}, {"boolean", false}, {"null", nullptr}, {"string", "Hello world"} };
|
||||
|
||||
SECTION("no indent / indent=-1")
|
||||
{
|
||||
CHECK(j.dump() ==
|
||||
"{\"array\":[1,2,3,4],\"boolean\":false,\"null\":null,\"number\":42,\"object\":{},\"string\":\"Hello world\"}");
|
||||
|
||||
CHECK(j.dump() == j.dump(-1));
|
||||
}
|
||||
|
||||
SECTION("indent=0")
|
||||
{
|
||||
CHECK(j.dump(0) ==
|
||||
"{\n\"array\": [\n1,\n2,\n3,\n4\n],\n\"boolean\": false,\n\"null\": null,\n\"number\": 42,\n\"object\": {},\n\"string\": \"Hello world\"\n}");
|
||||
}
|
||||
|
||||
SECTION("indent=4")
|
||||
{
|
||||
CHECK(j.dump(4) ==
|
||||
"{\n \"array\": [\n 1,\n 2,\n 3,\n 4\n ],\n \"boolean\": false,\n \"null\": null,\n \"number\": 42,\n \"object\": {},\n \"string\": \"Hello world\"\n}");
|
||||
}
|
||||
|
||||
SECTION("dump and floating-point numbers")
|
||||
{
|
||||
auto s = json(42.23).dump();
|
||||
CHECK(s.find("42.23") != std::string::npos);
|
||||
}
|
||||
|
||||
SECTION("dump and small floating-point numbers")
|
||||
{
|
||||
auto s = json(1.23456e-78).dump();
|
||||
CHECK(s.find("1.23456e-78") != std::string::npos);
|
||||
}
|
||||
|
||||
SECTION("dump and non-ASCII characters")
|
||||
{
|
||||
CHECK(json("ä").dump() == "\"ä\"");
|
||||
CHECK(json("Ö").dump() == "\"Ö\"");
|
||||
CHECK(json("❤️").dump() == "\"❤️\"");
|
||||
}
|
||||
|
||||
SECTION("serialization of discarded element")
|
||||
{
|
||||
json j_discarded(json::value_t::discarded);
|
||||
CHECK(j_discarded.dump() == "<discarded>");
|
||||
}
|
||||
|
||||
SECTION("check that precision is reset after serialization")
|
||||
{
|
||||
// create stringstream and set precision
|
||||
std::stringstream ss;
|
||||
ss.precision(3);
|
||||
ss << 3.141592653589793 << std::fixed;
|
||||
CHECK(ss.str() == "3.14");
|
||||
|
||||
// reset stringstream
|
||||
ss.str(std::string());
|
||||
|
||||
// use stringstream for JSON serialization
|
||||
json j_number = 3.141592653589793;
|
||||
ss << j_number;
|
||||
|
||||
// check that precision has been overridden during serialization
|
||||
CHECK(ss.str() == "3.141592653589793");
|
||||
|
||||
// check that precision has been restored
|
||||
CHECK(ss.precision() == 3);
|
||||
}
|
||||
}
|
||||
|
||||
SECTION("return the type of the object (explicit)")
|
||||
{
|
||||
SECTION("null")
|
||||
{
|
||||
json j = nullptr;
|
||||
CHECK(j.type() == json::value_t::null);
|
||||
}
|
||||
|
||||
SECTION("object")
|
||||
{
|
||||
json j = {{"foo", "bar"}};
|
||||
CHECK(j.type() == json::value_t::object);
|
||||
}
|
||||
|
||||
SECTION("array")
|
||||
{
|
||||
json j = {1, 2, 3, 4};
|
||||
CHECK(j.type() == json::value_t::array);
|
||||
}
|
||||
|
||||
SECTION("boolean")
|
||||
{
|
||||
json j = true;
|
||||
CHECK(j.type() == json::value_t::boolean);
|
||||
}
|
||||
|
||||
SECTION("string")
|
||||
{
|
||||
json j = "Hello world";
|
||||
CHECK(j.type() == json::value_t::string);
|
||||
}
|
||||
|
||||
SECTION("number (integer)")
|
||||
{
|
||||
json j = 23;
|
||||
CHECK(j.type() == json::value_t::number_integer);
|
||||
}
|
||||
|
||||
SECTION("number (unsigned)")
|
||||
{
|
||||
json j = 23u;
|
||||
CHECK(j.type() == json::value_t::number_unsigned);
|
||||
}
|
||||
|
||||
SECTION("number (floating-point)")
|
||||
{
|
||||
json j = 42.23;
|
||||
CHECK(j.type() == json::value_t::number_float);
|
||||
}
|
||||
}
|
||||
|
||||
SECTION("return the type of the object (implicit)")
|
||||
{
|
||||
SECTION("null")
|
||||
{
|
||||
json j = nullptr;
|
||||
json::value_t t = j;
|
||||
CHECK(t == j.type());
|
||||
}
|
||||
|
||||
SECTION("object")
|
||||
{
|
||||
json j = {{"foo", "bar"}};
|
||||
json::value_t t = j;
|
||||
CHECK(t == j.type());
|
||||
}
|
||||
|
||||
SECTION("array")
|
||||
{
|
||||
json j = {1, 2, 3, 4};
|
||||
json::value_t t = j;
|
||||
CHECK(t == j.type());
|
||||
}
|
||||
|
||||
SECTION("boolean")
|
||||
{
|
||||
json j = true;
|
||||
json::value_t t = j;
|
||||
CHECK(t == j.type());
|
||||
}
|
||||
|
||||
SECTION("string")
|
||||
{
|
||||
json j = "Hello world";
|
||||
json::value_t t = j;
|
||||
CHECK(t == j.type());
|
||||
}
|
||||
|
||||
SECTION("number (integer)")
|
||||
{
|
||||
json j = 23;
|
||||
json::value_t t = j;
|
||||
CHECK(t == j.type());
|
||||
}
|
||||
|
||||
SECTION("number (unsigned)")
|
||||
{
|
||||
json j = 23u;
|
||||
json::value_t t = j;
|
||||
CHECK(t == j.type());
|
||||
}
|
||||
|
||||
SECTION("number (floating-point)")
|
||||
{
|
||||
json j = 42.23;
|
||||
json::value_t t = j;
|
||||
CHECK(t == j.type());
|
||||
}
|
||||
}
|
||||
}
|
729
test/src/unit-iterator_wrapper.cpp
Normal file
729
test/src/unit-iterator_wrapper.cpp
Normal file
|
@ -0,0 +1,729 @@
|
|||
/*
|
||||
__ _____ _____ _____
|
||||
__| | __| | | | JSON for Modern C++ (test suite)
|
||||
| | |__ | | | | | | version 2.0.2
|
||||
|_____|_____|_____|_|___| https://github.com/nlohmann/json
|
||||
|
||||
Licensed under the MIT License <http://opensource.org/licenses/MIT>.
|
||||
Copyright (c) 2013-2016 Niels Lohmann <http://nlohmann.me>.
|
||||
|
||||
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("iterator_wrapper")
|
||||
{
|
||||
SECTION("object")
|
||||
{
|
||||
SECTION("value")
|
||||
{
|
||||
json j = {{"A", 1}, {"B", 2}};
|
||||
int counter = 1;
|
||||
|
||||
for (auto i : json::iterator_wrapper(j))
|
||||
{
|
||||
switch (counter++)
|
||||
{
|
||||
case 1:
|
||||
{
|
||||
CHECK(i.key() == "A");
|
||||
CHECK(i.value() == json(1));
|
||||
break;
|
||||
}
|
||||
|
||||
case 2:
|
||||
{
|
||||
CHECK(i.key() == "B");
|
||||
CHECK(i.value() == json(2));
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
CHECK(counter == 3);
|
||||
}
|
||||
|
||||
SECTION("reference")
|
||||
{
|
||||
json j = {{"A", 1}, {"B", 2}};
|
||||
int counter = 1;
|
||||
|
||||
for (auto& i : json::iterator_wrapper(j))
|
||||
{
|
||||
switch (counter++)
|
||||
{
|
||||
case 1:
|
||||
{
|
||||
CHECK(i.key() == "A");
|
||||
CHECK(i.value() == json(1));
|
||||
|
||||
// change the value
|
||||
i.value() = json(11);
|
||||
CHECK(i.value() == json(11));
|
||||
break;
|
||||
}
|
||||
|
||||
case 2:
|
||||
{
|
||||
CHECK(i.key() == "B");
|
||||
CHECK(i.value() == json(2));
|
||||
|
||||
// change the value
|
||||
i.value() = json(22);
|
||||
CHECK(i.value() == json(22));
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
CHECK(counter == 3);
|
||||
|
||||
// check if values where changed
|
||||
CHECK(j == json({{"A", 11}, {"B", 22}}));
|
||||
}
|
||||
|
||||
SECTION("const value")
|
||||
{
|
||||
json j = {{"A", 1}, {"B", 2}};
|
||||
int counter = 1;
|
||||
|
||||
for (const auto i : json::iterator_wrapper(j))
|
||||
{
|
||||
switch (counter++)
|
||||
{
|
||||
case 1:
|
||||
{
|
||||
CHECK(i.key() == "A");
|
||||
CHECK(i.value() == json(1));
|
||||
break;
|
||||
}
|
||||
|
||||
case 2:
|
||||
{
|
||||
CHECK(i.key() == "B");
|
||||
CHECK(i.value() == json(2));
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
CHECK(counter == 3);
|
||||
}
|
||||
|
||||
SECTION("const reference")
|
||||
{
|
||||
json j = {{"A", 1}, {"B", 2}};
|
||||
int counter = 1;
|
||||
|
||||
for (const auto& i : json::iterator_wrapper(j))
|
||||
{
|
||||
switch (counter++)
|
||||
{
|
||||
case 1:
|
||||
{
|
||||
CHECK(i.key() == "A");
|
||||
CHECK(i.value() == json(1));
|
||||
break;
|
||||
}
|
||||
|
||||
case 2:
|
||||
{
|
||||
CHECK(i.key() == "B");
|
||||
CHECK(i.value() == json(2));
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
CHECK(counter == 3);
|
||||
}
|
||||
}
|
||||
|
||||
SECTION("const object")
|
||||
{
|
||||
SECTION("value")
|
||||
{
|
||||
const json j = {{"A", 1}, {"B", 2}};
|
||||
int counter = 1;
|
||||
|
||||
for (auto i : json::iterator_wrapper(j))
|
||||
{
|
||||
switch (counter++)
|
||||
{
|
||||
case 1:
|
||||
{
|
||||
CHECK(i.key() == "A");
|
||||
CHECK(i.value() == json(1));
|
||||
break;
|
||||
}
|
||||
|
||||
case 2:
|
||||
{
|
||||
CHECK(i.key() == "B");
|
||||
CHECK(i.value() == json(2));
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
CHECK(counter == 3);
|
||||
}
|
||||
|
||||
SECTION("reference")
|
||||
{
|
||||
const json j = {{"A", 1}, {"B", 2}};
|
||||
int counter = 1;
|
||||
|
||||
for (auto& i : json::iterator_wrapper(j))
|
||||
{
|
||||
switch (counter++)
|
||||
{
|
||||
case 1:
|
||||
{
|
||||
CHECK(i.key() == "A");
|
||||
CHECK(i.value() == json(1));
|
||||
break;
|
||||
}
|
||||
|
||||
case 2:
|
||||
{
|
||||
CHECK(i.key() == "B");
|
||||
CHECK(i.value() == json(2));
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
CHECK(counter == 3);
|
||||
}
|
||||
|
||||
SECTION("const value")
|
||||
{
|
||||
const json j = {{"A", 1}, {"B", 2}};
|
||||
int counter = 1;
|
||||
|
||||
for (const auto i : json::iterator_wrapper(j))
|
||||
{
|
||||
switch (counter++)
|
||||
{
|
||||
case 1:
|
||||
{
|
||||
CHECK(i.key() == "A");
|
||||
CHECK(i.value() == json(1));
|
||||
break;
|
||||
}
|
||||
|
||||
case 2:
|
||||
{
|
||||
CHECK(i.key() == "B");
|
||||
CHECK(i.value() == json(2));
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
CHECK(counter == 3);
|
||||
}
|
||||
|
||||
SECTION("const reference")
|
||||
{
|
||||
const json j = {{"A", 1}, {"B", 2}};
|
||||
int counter = 1;
|
||||
|
||||
for (const auto& i : json::iterator_wrapper(j))
|
||||
{
|
||||
switch (counter++)
|
||||
{
|
||||
case 1:
|
||||
{
|
||||
CHECK(i.key() == "A");
|
||||
CHECK(i.value() == json(1));
|
||||
break;
|
||||
}
|
||||
|
||||
case 2:
|
||||
{
|
||||
CHECK(i.key() == "B");
|
||||
CHECK(i.value() == json(2));
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
CHECK(counter == 3);
|
||||
}
|
||||
}
|
||||
|
||||
SECTION("array")
|
||||
{
|
||||
SECTION("value")
|
||||
{
|
||||
json j = {"A", "B"};
|
||||
int counter = 1;
|
||||
|
||||
for (auto i : json::iterator_wrapper(j))
|
||||
{
|
||||
switch (counter++)
|
||||
{
|
||||
case 1:
|
||||
{
|
||||
CHECK(i.key() == "0");
|
||||
CHECK(i.value() == "A");
|
||||
break;
|
||||
}
|
||||
|
||||
case 2:
|
||||
{
|
||||
CHECK(i.key() == "1");
|
||||
CHECK(i.value() == "B");
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
CHECK(counter == 3);
|
||||
}
|
||||
|
||||
SECTION("reference")
|
||||
{
|
||||
json j = {"A", "B"};
|
||||
int counter = 1;
|
||||
|
||||
for (auto& i : json::iterator_wrapper(j))
|
||||
{
|
||||
switch (counter++)
|
||||
{
|
||||
case 1:
|
||||
{
|
||||
CHECK(i.key() == "0");
|
||||
CHECK(i.value() == "A");
|
||||
|
||||
// change the value
|
||||
i.value() = "AA";
|
||||
CHECK(i.value() == "AA");
|
||||
break;
|
||||
}
|
||||
|
||||
case 2:
|
||||
{
|
||||
CHECK(i.key() == "1");
|
||||
CHECK(i.value() == "B");
|
||||
|
||||
// change the value
|
||||
i.value() = "BB";
|
||||
CHECK(i.value() == "BB");
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
CHECK(counter == 3);
|
||||
|
||||
// check if values where changed
|
||||
CHECK(j == json({"AA", "BB"}));
|
||||
}
|
||||
|
||||
SECTION("const value")
|
||||
{
|
||||
json j = {"A", "B"};
|
||||
int counter = 1;
|
||||
|
||||
for (const auto i : json::iterator_wrapper(j))
|
||||
{
|
||||
switch (counter++)
|
||||
{
|
||||
case 1:
|
||||
{
|
||||
CHECK(i.key() == "0");
|
||||
CHECK(i.value() == "A");
|
||||
break;
|
||||
}
|
||||
|
||||
case 2:
|
||||
{
|
||||
CHECK(i.key() == "1");
|
||||
CHECK(i.value() == "B");
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
CHECK(counter == 3);
|
||||
}
|
||||
|
||||
SECTION("const reference")
|
||||
{
|
||||
json j = {"A", "B"};
|
||||
int counter = 1;
|
||||
|
||||
for (const auto& i : json::iterator_wrapper(j))
|
||||
{
|
||||
switch (counter++)
|
||||
{
|
||||
case 1:
|
||||
{
|
||||
CHECK(i.key() == "0");
|
||||
CHECK(i.value() == "A");
|
||||
break;
|
||||
}
|
||||
|
||||
case 2:
|
||||
{
|
||||
CHECK(i.key() == "1");
|
||||
CHECK(i.value() == "B");
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
CHECK(counter == 3);
|
||||
}
|
||||
}
|
||||
|
||||
SECTION("const array")
|
||||
{
|
||||
SECTION("value")
|
||||
{
|
||||
const json j = {"A", "B"};
|
||||
int counter = 1;
|
||||
|
||||
for (auto i : json::iterator_wrapper(j))
|
||||
{
|
||||
switch (counter++)
|
||||
{
|
||||
case 1:
|
||||
{
|
||||
CHECK(i.key() == "0");
|
||||
CHECK(i.value() == "A");
|
||||
break;
|
||||
}
|
||||
|
||||
case 2:
|
||||
{
|
||||
CHECK(i.key() == "1");
|
||||
CHECK(i.value() == "B");
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
CHECK(counter == 3);
|
||||
}
|
||||
|
||||
SECTION("reference")
|
||||
{
|
||||
const json j = {"A", "B"};
|
||||
int counter = 1;
|
||||
|
||||
for (auto& i : json::iterator_wrapper(j))
|
||||
{
|
||||
switch (counter++)
|
||||
{
|
||||
case 1:
|
||||
{
|
||||
CHECK(i.key() == "0");
|
||||
CHECK(i.value() == "A");
|
||||
break;
|
||||
}
|
||||
|
||||
case 2:
|
||||
{
|
||||
CHECK(i.key() == "1");
|
||||
CHECK(i.value() == "B");
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
CHECK(counter == 3);
|
||||
}
|
||||
|
||||
SECTION("const value")
|
||||
{
|
||||
const json j = {"A", "B"};
|
||||
int counter = 1;
|
||||
|
||||
for (const auto i : json::iterator_wrapper(j))
|
||||
{
|
||||
switch (counter++)
|
||||
{
|
||||
case 1:
|
||||
{
|
||||
CHECK(i.key() == "0");
|
||||
CHECK(i.value() == "A");
|
||||
break;
|
||||
}
|
||||
|
||||
case 2:
|
||||
{
|
||||
CHECK(i.key() == "1");
|
||||
CHECK(i.value() == "B");
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
CHECK(counter == 3);
|
||||
}
|
||||
|
||||
SECTION("const reference")
|
||||
{
|
||||
const json j = {"A", "B"};
|
||||
int counter = 1;
|
||||
|
||||
for (const auto& i : json::iterator_wrapper(j))
|
||||
{
|
||||
switch (counter++)
|
||||
{
|
||||
case 1:
|
||||
{
|
||||
CHECK(i.key() == "0");
|
||||
CHECK(i.value() == "A");
|
||||
break;
|
||||
}
|
||||
|
||||
case 2:
|
||||
{
|
||||
CHECK(i.key() == "1");
|
||||
CHECK(i.value() == "B");
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
CHECK(counter == 3);
|
||||
}
|
||||
}
|
||||
|
||||
SECTION("primitive")
|
||||
{
|
||||
SECTION("value")
|
||||
{
|
||||
json j = 1;
|
||||
int counter = 1;
|
||||
|
||||
for (auto i : json::iterator_wrapper(j))
|
||||
{
|
||||
++counter;
|
||||
CHECK(i.key() == "");
|
||||
CHECK(i.value() == json(1));
|
||||
}
|
||||
|
||||
CHECK(counter == 2);
|
||||
}
|
||||
|
||||
SECTION("reference")
|
||||
{
|
||||
json j = 1;
|
||||
int counter = 1;
|
||||
|
||||
for (auto& i : json::iterator_wrapper(j))
|
||||
{
|
||||
++counter;
|
||||
CHECK(i.key() == "");
|
||||
CHECK(i.value() == json(1));
|
||||
|
||||
// change value
|
||||
i.value() = json(2);
|
||||
}
|
||||
|
||||
CHECK(counter == 2);
|
||||
|
||||
// check if value has changed
|
||||
CHECK(j == json(2));
|
||||
}
|
||||
|
||||
SECTION("const value")
|
||||
{
|
||||
json j = 1;
|
||||
int counter = 1;
|
||||
|
||||
for (const auto i : json::iterator_wrapper(j))
|
||||
{
|
||||
++counter;
|
||||
CHECK(i.key() == "");
|
||||
CHECK(i.value() == json(1));
|
||||
}
|
||||
|
||||
CHECK(counter == 2);
|
||||
}
|
||||
|
||||
SECTION("const reference")
|
||||
{
|
||||
json j = 1;
|
||||
int counter = 1;
|
||||
|
||||
for (const auto& i : json::iterator_wrapper(j))
|
||||
{
|
||||
++counter;
|
||||
CHECK(i.key() == "");
|
||||
CHECK(i.value() == json(1));
|
||||
}
|
||||
|
||||
CHECK(counter == 2);
|
||||
}
|
||||
}
|
||||
|
||||
SECTION("const primitive")
|
||||
{
|
||||
SECTION("value")
|
||||
{
|
||||
const json j = 1;
|
||||
int counter = 1;
|
||||
|
||||
for (auto i : json::iterator_wrapper(j))
|
||||
{
|
||||
++counter;
|
||||
CHECK(i.key() == "");
|
||||
CHECK(i.value() == json(1));
|
||||
}
|
||||
|
||||
CHECK(counter == 2);
|
||||
}
|
||||
|
||||
SECTION("reference")
|
||||
{
|
||||
const json j = 1;
|
||||
int counter = 1;
|
||||
|
||||
for (auto& i : json::iterator_wrapper(j))
|
||||
{
|
||||
++counter;
|
||||
CHECK(i.key() == "");
|
||||
CHECK(i.value() == json(1));
|
||||
}
|
||||
|
||||
CHECK(counter == 2);
|
||||
}
|
||||
|
||||
SECTION("const value")
|
||||
{
|
||||
const json j = 1;
|
||||
int counter = 1;
|
||||
|
||||
for (const auto i : json::iterator_wrapper(j))
|
||||
{
|
||||
++counter;
|
||||
CHECK(i.key() == "");
|
||||
CHECK(i.value() == json(1));
|
||||
}
|
||||
|
||||
CHECK(counter == 2);
|
||||
}
|
||||
|
||||
SECTION("const reference")
|
||||
{
|
||||
const json j = 1;
|
||||
int counter = 1;
|
||||
|
||||
for (const auto& i : json::iterator_wrapper(j))
|
||||
{
|
||||
++counter;
|
||||
CHECK(i.key() == "");
|
||||
CHECK(i.value() == json(1));
|
||||
}
|
||||
|
||||
CHECK(counter == 2);
|
||||
}
|
||||
}
|
||||
}
|
2352
test/src/unit-iterators.cpp
Normal file
2352
test/src/unit-iterators.cpp
Normal file
File diff suppressed because it is too large
Load diff
1217
test/src/unit-json_patch.cpp
Normal file
1217
test/src/unit-json_patch.cpp
Normal file
File diff suppressed because it is too large
Load diff
388
test/src/unit-json_pointer.cpp
Normal file
388
test/src/unit-json_pointer.cpp
Normal file
|
@ -0,0 +1,388 @@
|
|||
/*
|
||||
__ _____ _____ _____
|
||||
__| | __| | | | JSON for Modern C++ (test suite)
|
||||
| | |__ | | | | | | version 2.0.2
|
||||
|_____|_____|_____|_|___| https://github.com/nlohmann/json
|
||||
|
||||
Licensed under the MIT License <http://opensource.org/licenses/MIT>.
|
||||
Copyright (c) 2013-2016 Niels Lohmann <http://nlohmann.me>.
|
||||
|
||||
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"
|
||||
|
||||
#define private public
|
||||
#include "json.hpp"
|
||||
using nlohmann::json;
|
||||
|
||||
TEST_CASE("JSON pointers")
|
||||
{
|
||||
SECTION("errors")
|
||||
{
|
||||
CHECK_THROWS_AS(json::json_pointer("foo"), std::domain_error);
|
||||
CHECK_THROWS_WITH(json::json_pointer("foo"), "JSON pointer must be empty or begin with '/'");
|
||||
|
||||
CHECK_THROWS_AS(json::json_pointer("/~~"), std::domain_error);
|
||||
CHECK_THROWS_WITH(json::json_pointer("/~~"), "escape error: '~' must be followed with '0' or '1'");
|
||||
|
||||
CHECK_THROWS_AS(json::json_pointer("/~"), std::domain_error);
|
||||
CHECK_THROWS_WITH(json::json_pointer("/~"), "escape error: '~' must be followed with '0' or '1'");
|
||||
|
||||
json::json_pointer p;
|
||||
CHECK_THROWS_AS(p.top(), std::domain_error);
|
||||
CHECK_THROWS_WITH(p.top(), "JSON pointer has no parent");
|
||||
CHECK_THROWS_AS(p.pop_back(), std::domain_error);
|
||||
CHECK_THROWS_WITH(p.pop_back(), "JSON pointer has no parent");
|
||||
}
|
||||
|
||||
SECTION("examples from RFC 6901")
|
||||
{
|
||||
SECTION("nonconst access")
|
||||
{
|
||||
json j = R"(
|
||||
{
|
||||
"foo": ["bar", "baz"],
|
||||
"": 0,
|
||||
"a/b": 1,
|
||||
"c%d": 2,
|
||||
"e^f": 3,
|
||||
"g|h": 4,
|
||||
"i\\j": 5,
|
||||
"k\"l": 6,
|
||||
" ": 7,
|
||||
"m~n": 8
|
||||
}
|
||||
)"_json;
|
||||
|
||||
// the whole document
|
||||
CHECK(j[json::json_pointer()] == j);
|
||||
CHECK(j[json::json_pointer("")] == j);
|
||||
|
||||
// array access
|
||||
CHECK(j[json::json_pointer("/foo")] == j["foo"]);
|
||||
CHECK(j[json::json_pointer("/foo/0")] == j["foo"][0]);
|
||||
CHECK(j[json::json_pointer("/foo/1")] == j["foo"][1]);
|
||||
CHECK(j["/foo/1"_json_pointer] == j["foo"][1]);
|
||||
|
||||
// checked array access
|
||||
CHECK(j.at(json::json_pointer("/foo/0")) == j["foo"][0]);
|
||||
CHECK(j.at(json::json_pointer("/foo/1")) == j["foo"][1]);
|
||||
|
||||
// empty string access
|
||||
CHECK(j[json::json_pointer("/")] == j[""]);
|
||||
|
||||
// other cases
|
||||
CHECK(j[json::json_pointer("/ ")] == j[" "]);
|
||||
CHECK(j[json::json_pointer("/c%d")] == j["c%d"]);
|
||||
CHECK(j[json::json_pointer("/e^f")] == j["e^f"]);
|
||||
CHECK(j[json::json_pointer("/g|h")] == j["g|h"]);
|
||||
CHECK(j[json::json_pointer("/i\\j")] == j["i\\j"]);
|
||||
CHECK(j[json::json_pointer("/k\"l")] == j["k\"l"]);
|
||||
|
||||
// checked access
|
||||
CHECK(j.at(json::json_pointer("/ ")) == j[" "]);
|
||||
CHECK(j.at(json::json_pointer("/c%d")) == j["c%d"]);
|
||||
CHECK(j.at(json::json_pointer("/e^f")) == j["e^f"]);
|
||||
CHECK(j.at(json::json_pointer("/g|h")) == j["g|h"]);
|
||||
CHECK(j.at(json::json_pointer("/i\\j")) == j["i\\j"]);
|
||||
CHECK(j.at(json::json_pointer("/k\"l")) == j["k\"l"]);
|
||||
|
||||
// escaped access
|
||||
CHECK(j[json::json_pointer("/a~1b")] == j["a/b"]);
|
||||
CHECK(j[json::json_pointer("/m~0n")] == j["m~n"]);
|
||||
|
||||
// unescaped access
|
||||
CHECK_THROWS_AS(j[json::json_pointer("/a/b")], std::out_of_range);
|
||||
CHECK_THROWS_WITH(j[json::json_pointer("/a/b")], "unresolved reference token 'b'");
|
||||
// "/a/b" works for JSON {"a": {"b": 42}}
|
||||
CHECK(json({{"a", {{"b", 42}}}})[json::json_pointer("/a/b")] == json(42));
|
||||
|
||||
// unresolved access
|
||||
json j_primitive = 1;
|
||||
CHECK_THROWS_AS(j_primitive["/foo"_json_pointer], std::out_of_range);
|
||||
CHECK_THROWS_WITH(j_primitive["/foo"_json_pointer], "unresolved reference token 'foo'");
|
||||
CHECK_THROWS_AS(j_primitive.at("/foo"_json_pointer), std::out_of_range);
|
||||
CHECK_THROWS_WITH(j_primitive.at("/foo"_json_pointer), "unresolved reference token 'foo'");
|
||||
}
|
||||
|
||||
SECTION("const access")
|
||||
{
|
||||
const json j = R"(
|
||||
{
|
||||
"foo": ["bar", "baz"],
|
||||
"": 0,
|
||||
"a/b": 1,
|
||||
"c%d": 2,
|
||||
"e^f": 3,
|
||||
"g|h": 4,
|
||||
"i\\j": 5,
|
||||
"k\"l": 6,
|
||||
" ": 7,
|
||||
"m~n": 8
|
||||
}
|
||||
)"_json;
|
||||
|
||||
// the whole document
|
||||
CHECK(j[json::json_pointer()] == j);
|
||||
CHECK(j[json::json_pointer("")] == j);
|
||||
|
||||
// array access
|
||||
CHECK(j[json::json_pointer("/foo")] == j["foo"]);
|
||||
CHECK(j[json::json_pointer("/foo/0")] == j["foo"][0]);
|
||||
CHECK(j[json::json_pointer("/foo/1")] == j["foo"][1]);
|
||||
CHECK(j["/foo/1"_json_pointer] == j["foo"][1]);
|
||||
|
||||
// checked array access
|
||||
CHECK(j.at(json::json_pointer("/foo/0")) == j["foo"][0]);
|
||||
CHECK(j.at(json::json_pointer("/foo/1")) == j["foo"][1]);
|
||||
|
||||
// empty string access
|
||||
CHECK(j[json::json_pointer("/")] == j[""]);
|
||||
|
||||
// other cases
|
||||
CHECK(j[json::json_pointer("/ ")] == j[" "]);
|
||||
CHECK(j[json::json_pointer("/c%d")] == j["c%d"]);
|
||||
CHECK(j[json::json_pointer("/e^f")] == j["e^f"]);
|
||||
CHECK(j[json::json_pointer("/g|h")] == j["g|h"]);
|
||||
CHECK(j[json::json_pointer("/i\\j")] == j["i\\j"]);
|
||||
CHECK(j[json::json_pointer("/k\"l")] == j["k\"l"]);
|
||||
|
||||
// checked access
|
||||
CHECK(j.at(json::json_pointer("/ ")) == j[" "]);
|
||||
CHECK(j.at(json::json_pointer("/c%d")) == j["c%d"]);
|
||||
CHECK(j.at(json::json_pointer("/e^f")) == j["e^f"]);
|
||||
CHECK(j.at(json::json_pointer("/g|h")) == j["g|h"]);
|
||||
CHECK(j.at(json::json_pointer("/i\\j")) == j["i\\j"]);
|
||||
CHECK(j.at(json::json_pointer("/k\"l")) == j["k\"l"]);
|
||||
|
||||
// escaped access
|
||||
CHECK(j[json::json_pointer("/a~1b")] == j["a/b"]);
|
||||
CHECK(j[json::json_pointer("/m~0n")] == j["m~n"]);
|
||||
|
||||
// unescaped access
|
||||
CHECK_THROWS_AS(j.at(json::json_pointer("/a/b")), std::out_of_range);
|
||||
CHECK_THROWS_WITH(j.at(json::json_pointer("/a/b")), "key 'a' not found");
|
||||
|
||||
// unresolved access
|
||||
const json j_primitive = 1;
|
||||
CHECK_THROWS_AS(j_primitive["/foo"_json_pointer], std::out_of_range);
|
||||
CHECK_THROWS_WITH(j_primitive["/foo"_json_pointer], "unresolved reference token 'foo'");
|
||||
CHECK_THROWS_AS(j_primitive.at("/foo"_json_pointer), std::out_of_range);
|
||||
CHECK_THROWS_WITH(j_primitive.at("/foo"_json_pointer), "unresolved reference token 'foo'");
|
||||
}
|
||||
|
||||
SECTION("user-defined string literal")
|
||||
{
|
||||
json j = R"(
|
||||
{
|
||||
"foo": ["bar", "baz"],
|
||||
"": 0,
|
||||
"a/b": 1,
|
||||
"c%d": 2,
|
||||
"e^f": 3,
|
||||
"g|h": 4,
|
||||
"i\\j": 5,
|
||||
"k\"l": 6,
|
||||
" ": 7,
|
||||
"m~n": 8
|
||||
}
|
||||
)"_json;
|
||||
|
||||
// the whole document
|
||||
CHECK(j[""_json_pointer] == j);
|
||||
|
||||
// array access
|
||||
CHECK(j["/foo"_json_pointer] == j["foo"]);
|
||||
CHECK(j["/foo/0"_json_pointer] == j["foo"][0]);
|
||||
CHECK(j["/foo/1"_json_pointer] == j["foo"][1]);
|
||||
}
|
||||
}
|
||||
|
||||
SECTION("array access")
|
||||
{
|
||||
SECTION("nonconst access")
|
||||
{
|
||||
json j = {1, 2, 3};
|
||||
const json j_const = j;
|
||||
|
||||
// check reading access
|
||||
CHECK(j["/0"_json_pointer] == j[0]);
|
||||
CHECK(j["/1"_json_pointer] == j[1]);
|
||||
CHECK(j["/2"_json_pointer] == j[2]);
|
||||
|
||||
// assign to existing index
|
||||
j["/1"_json_pointer] = 13;
|
||||
CHECK(j[1] == json(13));
|
||||
|
||||
// assign to nonexisting index
|
||||
j["/3"_json_pointer] = 33;
|
||||
CHECK(j[3] == json(33));
|
||||
|
||||
// assign to nonexisting index (with gap)
|
||||
j["/5"_json_pointer] = 55;
|
||||
CHECK(j == json({1, 13, 3, 33, nullptr, 55}));
|
||||
|
||||
// error with leading 0
|
||||
CHECK_THROWS_AS(j["/01"_json_pointer], std::domain_error);
|
||||
CHECK_THROWS_WITH(j["/01"_json_pointer], "array index must not begin with '0'");
|
||||
CHECK_THROWS_AS(j_const["/01"_json_pointer], std::domain_error);
|
||||
CHECK_THROWS_WITH(j_const["/01"_json_pointer], "array index must not begin with '0'");
|
||||
CHECK_THROWS_AS(j.at("/01"_json_pointer), std::domain_error);
|
||||
CHECK_THROWS_WITH(j.at("/01"_json_pointer), "array index must not begin with '0'");
|
||||
CHECK_THROWS_AS(j_const.at("/01"_json_pointer), std::domain_error);
|
||||
CHECK_THROWS_WITH(j_const.at("/01"_json_pointer), "array index must not begin with '0'");
|
||||
|
||||
// error with incorrect numbers
|
||||
CHECK_THROWS_AS(j["/one"_json_pointer] = 1, std::invalid_argument);
|
||||
|
||||
// assign to "-"
|
||||
j["/-"_json_pointer] = 99;
|
||||
CHECK(j == json({1, 13, 3, 33, nullptr, 55, 99}));
|
||||
|
||||
// error when using "-" in const object
|
||||
CHECK_THROWS_AS(j_const["/-"_json_pointer], std::out_of_range);
|
||||
CHECK_THROWS_WITH(j_const["/-"_json_pointer], "array index '-' (3) is out of range");
|
||||
|
||||
// error when using "-" with at
|
||||
CHECK_THROWS_AS(j.at("/-"_json_pointer), std::out_of_range);
|
||||
CHECK_THROWS_WITH(j.at("/-"_json_pointer), "array index '-' (7) is out of range");
|
||||
CHECK_THROWS_AS(j_const.at("/-"_json_pointer), std::out_of_range);
|
||||
CHECK_THROWS_WITH(j_const.at("/-"_json_pointer), "array index '-' (3) is out of range");
|
||||
}
|
||||
|
||||
SECTION("const access")
|
||||
{
|
||||
const json j = {1, 2, 3};
|
||||
|
||||
// check reading access
|
||||
CHECK(j["/0"_json_pointer] == j[0]);
|
||||
CHECK(j["/1"_json_pointer] == j[1]);
|
||||
CHECK(j["/2"_json_pointer] == j[2]);
|
||||
|
||||
// assign to nonexisting index
|
||||
CHECK_THROWS_AS(j.at("/3"_json_pointer), std::out_of_range);
|
||||
CHECK_THROWS_WITH(j.at("/3"_json_pointer), "array index 3 is out of range");
|
||||
|
||||
// assign to nonexisting index (with gap)
|
||||
CHECK_THROWS_AS(j.at("/5"_json_pointer), std::out_of_range);
|
||||
CHECK_THROWS_WITH(j.at("/5"_json_pointer), "array index 5 is out of range");
|
||||
|
||||
// assign to "-"
|
||||
CHECK_THROWS_AS(j["/-"_json_pointer], std::out_of_range);
|
||||
CHECK_THROWS_WITH(j["/-"_json_pointer], "array index '-' (3) is out of range");
|
||||
CHECK_THROWS_AS(j.at("/-"_json_pointer), std::out_of_range);
|
||||
CHECK_THROWS_WITH(j.at("/-"_json_pointer), "array index '-' (3) is out of range");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
SECTION("flatten")
|
||||
{
|
||||
json j =
|
||||
{
|
||||
{"pi", 3.141},
|
||||
{"happy", true},
|
||||
{"name", "Niels"},
|
||||
{"nothing", nullptr},
|
||||
{
|
||||
"answer", {
|
||||
{"everything", 42}
|
||||
}
|
||||
},
|
||||
{"list", {1, 0, 2}},
|
||||
{
|
||||
"object", {
|
||||
{"currency", "USD"},
|
||||
{"value", 42.99},
|
||||
{"", "empty string"},
|
||||
{"/", "slash"},
|
||||
{"~", "tilde"},
|
||||
{"~1", "tilde1"}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
json j_flatten =
|
||||
{
|
||||
{"/pi", 3.141},
|
||||
{"/happy", true},
|
||||
{"/name", "Niels"},
|
||||
{"/nothing", nullptr},
|
||||
{"/answer/everything", 42},
|
||||
{"/list/0", 1},
|
||||
{"/list/1", 0},
|
||||
{"/list/2", 2},
|
||||
{"/object/currency", "USD"},
|
||||
{"/object/value", 42.99},
|
||||
{"/object/", "empty string"},
|
||||
{"/object/~1", "slash"},
|
||||
{"/object/~0", "tilde"},
|
||||
{"/object/~01", "tilde1"}
|
||||
};
|
||||
|
||||
// check if flattened result is as expected
|
||||
CHECK(j.flatten() == j_flatten);
|
||||
|
||||
// check if unflattened result is as expected
|
||||
CHECK(j_flatten.unflatten() == j);
|
||||
|
||||
// error for nonobjects
|
||||
CHECK_THROWS_AS(json(1).unflatten(), std::domain_error);
|
||||
CHECK_THROWS_WITH(json(1).unflatten(), "only objects can be unflattened");
|
||||
|
||||
// error for nonprimitve values
|
||||
CHECK_THROWS_AS(json({{"/1", {1, 2, 3}}}).unflatten(), std::domain_error);
|
||||
CHECK_THROWS_WITH(json({{"/1", {1, 2, 3}}}).unflatten(), "values in object must be primitive");
|
||||
|
||||
// error for conflicting values
|
||||
json j_error = {{"", 42}, {"/foo", 17}};
|
||||
CHECK_THROWS_AS(j_error.unflatten(), std::domain_error);
|
||||
CHECK_THROWS_WITH(j_error.unflatten(), "invalid value to unflatten");
|
||||
|
||||
// explicit roundtrip check
|
||||
CHECK(j.flatten().unflatten() == j);
|
||||
|
||||
// roundtrip for primitive values
|
||||
json j_null;
|
||||
CHECK(j_null.flatten().unflatten() == j_null);
|
||||
json j_number = 42;
|
||||
CHECK(j_number.flatten().unflatten() == j_number);
|
||||
json j_boolean = false;
|
||||
CHECK(j_boolean.flatten().unflatten() == j_boolean);
|
||||
json j_string = "foo";
|
||||
CHECK(j_string.flatten().unflatten() == j_string);
|
||||
|
||||
// roundtrip for empty structured values (will be unflattened to null)
|
||||
json j_array(json::value_t::array);
|
||||
CHECK(j_array.flatten().unflatten() == json());
|
||||
json j_object(json::value_t::object);
|
||||
CHECK(j_object.flatten().unflatten() == json());
|
||||
}
|
||||
|
||||
SECTION("string representation")
|
||||
{
|
||||
for (auto ptr :
|
||||
{"", "/foo", "/foo/0", "/", "/a~1b", "/c%d", "/e^f", "/g|h", "/i\\j", "/k\"l", "/ ", "/m~0n"
|
||||
})
|
||||
{
|
||||
CHECK(json::json_pointer(ptr).to_string() == ptr);
|
||||
}
|
||||
}
|
||||
}
|
713
test/src/unit-modifiers.cpp
Normal file
713
test/src/unit-modifiers.cpp
Normal file
|
@ -0,0 +1,713 @@
|
|||
/*
|
||||
__ _____ _____ _____
|
||||
__| | __| | | | JSON for Modern C++ (test suite)
|
||||
| | |__ | | | | | | version 2.0.2
|
||||
|_____|_____|_____|_|___| https://github.com/nlohmann/json
|
||||
|
||||
Licensed under the MIT License <http://opensource.org/licenses/MIT>.
|
||||
Copyright (c) 2013-2016 Niels Lohmann <http://nlohmann.me>.
|
||||
|
||||
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("modifiers")
|
||||
{
|
||||
SECTION("clear()")
|
||||
{
|
||||
SECTION("boolean")
|
||||
{
|
||||
json j = true;
|
||||
|
||||
j.clear();
|
||||
CHECK(j == json(json::value_t::boolean));
|
||||
}
|
||||
|
||||
SECTION("string")
|
||||
{
|
||||
json j = "hello world";
|
||||
|
||||
j.clear();
|
||||
CHECK(j == json(json::value_t::string));
|
||||
}
|
||||
|
||||
SECTION("array")
|
||||
{
|
||||
SECTION("empty array")
|
||||
{
|
||||
json j = json::array();
|
||||
|
||||
j.clear();
|
||||
CHECK(j.empty());
|
||||
CHECK(j == json(json::value_t::array));
|
||||
}
|
||||
|
||||
SECTION("filled array")
|
||||
{
|
||||
json j = {1, 2, 3};
|
||||
|
||||
j.clear();
|
||||
CHECK(j.empty());
|
||||
CHECK(j == json(json::value_t::array));
|
||||
}
|
||||
}
|
||||
|
||||
SECTION("object")
|
||||
{
|
||||
SECTION("empty object")
|
||||
{
|
||||
json j = json::object();
|
||||
|
||||
j.clear();
|
||||
CHECK(j.empty());
|
||||
CHECK(j == json(json::value_t::object));
|
||||
}
|
||||
|
||||
SECTION("filled object")
|
||||
{
|
||||
json j = {{"one", 1}, {"two", 2}, {"three", 3}};
|
||||
|
||||
j.clear();
|
||||
CHECK(j.empty());
|
||||
CHECK(j == json(json::value_t::object));
|
||||
}
|
||||
}
|
||||
|
||||
SECTION("number (integer)")
|
||||
{
|
||||
json j = 23;
|
||||
|
||||
j.clear();
|
||||
CHECK(j == json(json::value_t::number_integer));
|
||||
}
|
||||
|
||||
SECTION("number (unsigned)")
|
||||
{
|
||||
json j = 23u;
|
||||
|
||||
j.clear();
|
||||
CHECK(j == json(json::value_t::number_integer));
|
||||
}
|
||||
|
||||
SECTION("number (float)")
|
||||
{
|
||||
json j = 23.42;
|
||||
|
||||
j.clear();
|
||||
CHECK(j == json(json::value_t::number_float));
|
||||
}
|
||||
|
||||
SECTION("null")
|
||||
{
|
||||
json j = nullptr;
|
||||
|
||||
j.clear();
|
||||
CHECK(j == json(json::value_t::null));
|
||||
}
|
||||
}
|
||||
|
||||
SECTION("push_back()")
|
||||
{
|
||||
SECTION("to array")
|
||||
{
|
||||
SECTION("json&&")
|
||||
{
|
||||
SECTION("null")
|
||||
{
|
||||
json j;
|
||||
j.push_back(1);
|
||||
j.push_back(2);
|
||||
CHECK(j.type() == json::value_t::array);
|
||||
CHECK(j == json({1, 2}));
|
||||
}
|
||||
|
||||
SECTION("array")
|
||||
{
|
||||
json j = {1, 2, 3};
|
||||
j.push_back("Hello");
|
||||
CHECK(j.type() == json::value_t::array);
|
||||
CHECK(j == json({1, 2, 3, "Hello"}));
|
||||
}
|
||||
|
||||
SECTION("other type")
|
||||
{
|
||||
json j = 1;
|
||||
CHECK_THROWS_AS(j.push_back("Hello"), std::domain_error);
|
||||
CHECK_THROWS_WITH(j.push_back("Hello"), "cannot use push_back() with number");
|
||||
}
|
||||
}
|
||||
|
||||
SECTION("const json&")
|
||||
{
|
||||
SECTION("null")
|
||||
{
|
||||
json j;
|
||||
json k(1);
|
||||
j.push_back(k);
|
||||
j.push_back(k);
|
||||
CHECK(j.type() == json::value_t::array);
|
||||
CHECK(j == json({1, 1}));
|
||||
}
|
||||
|
||||
SECTION("array")
|
||||
{
|
||||
json j = {1, 2, 3};
|
||||
json k("Hello");
|
||||
j.push_back(k);
|
||||
CHECK(j.type() == json::value_t::array);
|
||||
CHECK(j == json({1, 2, 3, "Hello"}));
|
||||
}
|
||||
|
||||
SECTION("other type")
|
||||
{
|
||||
json j = 1;
|
||||
json k("Hello");
|
||||
CHECK_THROWS_AS(j.push_back(k), std::domain_error);
|
||||
CHECK_THROWS_WITH(j.push_back(k), "cannot use push_back() with number");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
SECTION("to object")
|
||||
{
|
||||
SECTION("null")
|
||||
{
|
||||
json j;
|
||||
j.push_back(json::object_t::value_type({"one", 1}));
|
||||
j.push_back(json::object_t::value_type({"two", 2}));
|
||||
CHECK(j.type() == json::value_t::object);
|
||||
CHECK(j.size() == 2);
|
||||
CHECK(j["one"] == json(1));
|
||||
CHECK(j["two"] == json(2));
|
||||
}
|
||||
|
||||
SECTION("object")
|
||||
{
|
||||
json j(json::value_t::object);
|
||||
j.push_back(json::object_t::value_type({"one", 1}));
|
||||
j.push_back(json::object_t::value_type({"two", 2}));
|
||||
CHECK(j.size() == 2);
|
||||
CHECK(j["one"] == json(1));
|
||||
CHECK(j["two"] == json(2));
|
||||
}
|
||||
|
||||
SECTION("other type")
|
||||
{
|
||||
json j = 1;
|
||||
json k("Hello");
|
||||
CHECK_THROWS_AS(j.push_back(json::object_t::value_type({"one", 1})), std::domain_error);
|
||||
CHECK_THROWS_WITH(j.push_back(json::object_t::value_type({"one", 1})),
|
||||
"cannot use push_back() with number");
|
||||
}
|
||||
}
|
||||
|
||||
SECTION("with initializer_list")
|
||||
{
|
||||
SECTION("null")
|
||||
{
|
||||
json j;
|
||||
j.push_back({"foo", "bar"});
|
||||
CHECK(j == json::array({{"foo", "bar"}}));
|
||||
|
||||
json k;
|
||||
k.push_back({1, 2, 3});
|
||||
CHECK(k == json::array({{1, 2, 3}}));
|
||||
}
|
||||
|
||||
SECTION("array")
|
||||
{
|
||||
json j = {1, 2, 3};
|
||||
j.push_back({"foo", "bar"});
|
||||
CHECK(j == json({1, 2, 3, {"foo", "bar"}}));
|
||||
|
||||
json k = {1, 2, 3};
|
||||
k.push_back({1, 2, 3});
|
||||
CHECK(k == json({1, 2, 3, {1, 2, 3}}));
|
||||
}
|
||||
|
||||
SECTION("object")
|
||||
{
|
||||
json j = {{"key1", 1}};
|
||||
j.push_back({"key2", "bar"});
|
||||
CHECK(j == json({{"key1", 1}, {"key2", "bar"}}));
|
||||
|
||||
json k = {{"key1", 1}};
|
||||
CHECK_THROWS_AS(k.push_back({1, 2, 3, 4}), std::domain_error);
|
||||
CHECK_THROWS_WITH(k.push_back({1, 2, 3, 4}), "cannot use push_back() with object");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
SECTION("operator+=")
|
||||
{
|
||||
SECTION("to array")
|
||||
{
|
||||
SECTION("json&&")
|
||||
{
|
||||
SECTION("null")
|
||||
{
|
||||
json j;
|
||||
j += 1;
|
||||
j += 2;
|
||||
CHECK(j.type() == json::value_t::array);
|
||||
CHECK(j == json({1, 2}));
|
||||
}
|
||||
|
||||
SECTION("array")
|
||||
{
|
||||
json j = {1, 2, 3};
|
||||
j += "Hello";
|
||||
CHECK(j.type() == json::value_t::array);
|
||||
CHECK(j == json({1, 2, 3, "Hello"}));
|
||||
}
|
||||
|
||||
SECTION("other type")
|
||||
{
|
||||
json j = 1;
|
||||
CHECK_THROWS_AS(j += "Hello", std::domain_error);
|
||||
CHECK_THROWS_WITH(j += "Hello", "cannot use push_back() with number");
|
||||
}
|
||||
}
|
||||
|
||||
SECTION("const json&")
|
||||
{
|
||||
SECTION("null")
|
||||
{
|
||||
json j;
|
||||
json k(1);
|
||||
j += k;
|
||||
j += k;
|
||||
CHECK(j.type() == json::value_t::array);
|
||||
CHECK(j == json({1, 1}));
|
||||
}
|
||||
|
||||
SECTION("array")
|
||||
{
|
||||
json j = {1, 2, 3};
|
||||
json k("Hello");
|
||||
j += k;
|
||||
CHECK(j.type() == json::value_t::array);
|
||||
CHECK(j == json({1, 2, 3, "Hello"}));
|
||||
}
|
||||
|
||||
SECTION("other type")
|
||||
{
|
||||
json j = 1;
|
||||
json k("Hello");
|
||||
CHECK_THROWS_AS(j += k, std::domain_error);
|
||||
CHECK_THROWS_WITH(j += k, "cannot use push_back() with number");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
SECTION("to object")
|
||||
{
|
||||
SECTION("null")
|
||||
{
|
||||
json j;
|
||||
j += json::object_t::value_type({"one", 1});
|
||||
j += json::object_t::value_type({"two", 2});
|
||||
CHECK(j.type() == json::value_t::object);
|
||||
CHECK(j.size() == 2);
|
||||
CHECK(j["one"] == json(1));
|
||||
CHECK(j["two"] == json(2));
|
||||
}
|
||||
|
||||
SECTION("object")
|
||||
{
|
||||
json j(json::value_t::object);
|
||||
j += json::object_t::value_type({"one", 1});
|
||||
j += json::object_t::value_type({"two", 2});
|
||||
CHECK(j.size() == 2);
|
||||
CHECK(j["one"] == json(1));
|
||||
CHECK(j["two"] == json(2));
|
||||
}
|
||||
|
||||
SECTION("other type")
|
||||
{
|
||||
json j = 1;
|
||||
json k("Hello");
|
||||
CHECK_THROWS_AS(j += json::object_t::value_type({"one", 1}), std::domain_error);
|
||||
CHECK_THROWS_WITH(j += json::object_t::value_type({"one", 1}),
|
||||
"cannot use push_back() with number");
|
||||
}
|
||||
}
|
||||
|
||||
SECTION("with initializer_list")
|
||||
{
|
||||
SECTION("null")
|
||||
{
|
||||
json j;
|
||||
j += {"foo", "bar"};
|
||||
CHECK(j == json::array({{"foo", "bar"}}));
|
||||
|
||||
json k;
|
||||
k += {1, 2, 3};
|
||||
CHECK(k == json::array({{1, 2, 3}}));
|
||||
}
|
||||
|
||||
SECTION("array")
|
||||
{
|
||||
json j = {1, 2, 3};
|
||||
j += {"foo", "bar"};
|
||||
CHECK(j == json({1, 2, 3, {"foo", "bar"}}));
|
||||
|
||||
json k = {1, 2, 3};
|
||||
k += {1, 2, 3};
|
||||
CHECK(k == json({1, 2, 3, {1, 2, 3}}));
|
||||
}
|
||||
|
||||
SECTION("object")
|
||||
{
|
||||
json j = {{"key1", 1}};
|
||||
j += {"key2", "bar"};
|
||||
CHECK(j == json({{"key1", 1}, {"key2", "bar"}}));
|
||||
|
||||
json k = {{"key1", 1}};
|
||||
CHECK_THROWS_AS((k += {1, 2, 3, 4}), std::domain_error);
|
||||
CHECK_THROWS_WITH((k += {1, 2, 3, 4}), "cannot use push_back() with object");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
SECTION("insert")
|
||||
{
|
||||
json j_array = {1, 2, 3, 4};
|
||||
json j_value = 5;
|
||||
|
||||
SECTION("value at position")
|
||||
{
|
||||
SECTION("insert before begin()")
|
||||
{
|
||||
auto it = j_array.insert(j_array.begin(), j_value);
|
||||
CHECK(j_array.size() == 5);
|
||||
CHECK(*it == j_value);
|
||||
CHECK(j_array.begin() == it);
|
||||
CHECK(j_array == json({5, 1, 2, 3, 4}));
|
||||
}
|
||||
|
||||
SECTION("insert in the middle")
|
||||
{
|
||||
auto it = j_array.insert(j_array.begin() + 2, j_value);
|
||||
CHECK(j_array.size() == 5);
|
||||
CHECK(*it == j_value);
|
||||
CHECK((it - j_array.begin()) == 2);
|
||||
CHECK(j_array == json({1, 2, 5, 3, 4}));
|
||||
}
|
||||
|
||||
SECTION("insert before end()")
|
||||
{
|
||||
auto it = j_array.insert(j_array.end(), j_value);
|
||||
CHECK(j_array.size() == 5);
|
||||
CHECK(*it == j_value);
|
||||
CHECK((j_array.end() - it) == 1);
|
||||
CHECK(j_array == json({1, 2, 3, 4, 5}));
|
||||
}
|
||||
}
|
||||
|
||||
SECTION("rvalue at position")
|
||||
{
|
||||
SECTION("insert before begin()")
|
||||
{
|
||||
auto it = j_array.insert(j_array.begin(), 5);
|
||||
CHECK(j_array.size() == 5);
|
||||
CHECK(*it == j_value);
|
||||
CHECK(j_array.begin() == it);
|
||||
CHECK(j_array == json({5, 1, 2, 3, 4}));
|
||||
}
|
||||
|
||||
SECTION("insert in the middle")
|
||||
{
|
||||
auto it = j_array.insert(j_array.begin() + 2, 5);
|
||||
CHECK(j_array.size() == 5);
|
||||
CHECK(*it == j_value);
|
||||
CHECK((it - j_array.begin()) == 2);
|
||||
CHECK(j_array == json({1, 2, 5, 3, 4}));
|
||||
}
|
||||
|
||||
SECTION("insert before end()")
|
||||
{
|
||||
auto it = j_array.insert(j_array.end(), 5);
|
||||
CHECK(j_array.size() == 5);
|
||||
CHECK(*it == j_value);
|
||||
CHECK((j_array.end() - it) == 1);
|
||||
CHECK(j_array == json({1, 2, 3, 4, 5}));
|
||||
}
|
||||
}
|
||||
|
||||
SECTION("copies at position")
|
||||
{
|
||||
SECTION("insert before begin()")
|
||||
{
|
||||
auto it = j_array.insert(j_array.begin(), 3, 5);
|
||||
CHECK(j_array.size() == 7);
|
||||
CHECK(*it == j_value);
|
||||
CHECK(j_array.begin() == it);
|
||||
CHECK(j_array == json({5, 5, 5, 1, 2, 3, 4}));
|
||||
}
|
||||
|
||||
SECTION("insert in the middle")
|
||||
{
|
||||
auto it = j_array.insert(j_array.begin() + 2, 3, 5);
|
||||
CHECK(j_array.size() == 7);
|
||||
CHECK(*it == j_value);
|
||||
CHECK((it - j_array.begin()) == 2);
|
||||
CHECK(j_array == json({1, 2, 5, 5, 5, 3, 4}));
|
||||
}
|
||||
|
||||
SECTION("insert before end()")
|
||||
{
|
||||
auto it = j_array.insert(j_array.end(), 3, 5);
|
||||
CHECK(j_array.size() == 7);
|
||||
CHECK(*it == j_value);
|
||||
CHECK((j_array.end() - it) == 3);
|
||||
CHECK(j_array == json({1, 2, 3, 4, 5, 5, 5}));
|
||||
}
|
||||
|
||||
SECTION("insert nothing (count = 0)")
|
||||
{
|
||||
auto pos = j_array.end();
|
||||
auto it = j_array.insert(j_array.end(), 0, 5);
|
||||
CHECK(j_array.size() == 4);
|
||||
CHECK(it == pos);
|
||||
CHECK(j_array == json({1, 2, 3, 4}));
|
||||
}
|
||||
}
|
||||
|
||||
SECTION("range")
|
||||
{
|
||||
json j_other_array = {"first", "second"};
|
||||
|
||||
SECTION("proper usage")
|
||||
{
|
||||
auto it = j_array.insert(j_array.end(), j_other_array.begin(), j_other_array.end());
|
||||
CHECK(j_array.size() == 6);
|
||||
CHECK(*it == *j_other_array.begin());
|
||||
CHECK((j_array.end() - it) == 2);
|
||||
CHECK(j_array == json({1, 2, 3, 4, "first", "second"}));
|
||||
}
|
||||
|
||||
SECTION("empty range")
|
||||
{
|
||||
auto it = j_array.insert(j_array.end(), j_other_array.begin(), j_other_array.begin());
|
||||
CHECK(j_array.size() == 4);
|
||||
CHECK(it == j_array.end());
|
||||
CHECK(j_array == json({1, 2, 3, 4}));
|
||||
}
|
||||
|
||||
SECTION("invalid iterators")
|
||||
{
|
||||
json j_other_array2 = {"first", "second"};
|
||||
|
||||
CHECK_THROWS_AS(j_array.insert(j_array.end(), j_array.begin(), j_array.end()), std::domain_error);
|
||||
CHECK_THROWS_AS(j_array.insert(j_array.end(), j_other_array.begin(), j_other_array2.end()),
|
||||
std::domain_error);
|
||||
|
||||
CHECK_THROWS_WITH(j_array.insert(j_array.end(), j_array.begin(), j_array.end()),
|
||||
"passed iterators may not belong to container");
|
||||
CHECK_THROWS_WITH(j_array.insert(j_array.end(), j_other_array.begin(), j_other_array2.end()),
|
||||
"iterators do not fit");
|
||||
}
|
||||
}
|
||||
|
||||
SECTION("initializer list at position")
|
||||
{
|
||||
SECTION("insert before begin()")
|
||||
{
|
||||
auto it = j_array.insert(j_array.begin(), {7, 8, 9});
|
||||
CHECK(j_array.size() == 7);
|
||||
CHECK(*it == json(7));
|
||||
CHECK(j_array.begin() == it);
|
||||
CHECK(j_array == json({7, 8, 9, 1, 2, 3, 4}));
|
||||
}
|
||||
|
||||
SECTION("insert in the middle")
|
||||
{
|
||||
auto it = j_array.insert(j_array.begin() + 2, {7, 8, 9});
|
||||
CHECK(j_array.size() == 7);
|
||||
CHECK(*it == json(7));
|
||||
CHECK((it - j_array.begin()) == 2);
|
||||
CHECK(j_array == json({1, 2, 7, 8, 9, 3, 4}));
|
||||
}
|
||||
|
||||
SECTION("insert before end()")
|
||||
{
|
||||
auto it = j_array.insert(j_array.end(), {7, 8, 9});
|
||||
CHECK(j_array.size() == 7);
|
||||
CHECK(*it == json(7));
|
||||
CHECK((j_array.end() - it) == 3);
|
||||
CHECK(j_array == json({1, 2, 3, 4, 7, 8, 9}));
|
||||
}
|
||||
}
|
||||
|
||||
SECTION("invalid iterator")
|
||||
{
|
||||
// pass iterator to a different array
|
||||
json j_another_array = {1, 2};
|
||||
json j_yet_another_array = {"first", "second"};
|
||||
CHECK_THROWS_AS(j_array.insert(j_another_array.end(), 10), std::domain_error);
|
||||
CHECK_THROWS_AS(j_array.insert(j_another_array.end(), j_value), std::domain_error);
|
||||
CHECK_THROWS_AS(j_array.insert(j_another_array.end(), 10, 11), std::domain_error);
|
||||
CHECK_THROWS_AS(j_array.insert(j_another_array.end(), j_yet_another_array.begin(),
|
||||
j_yet_another_array.end()), std::domain_error);
|
||||
CHECK_THROWS_AS(j_array.insert(j_another_array.end(), {1, 2, 3, 4}), std::domain_error);
|
||||
|
||||
CHECK_THROWS_WITH(j_array.insert(j_another_array.end(), 10), "iterator does not fit current value");
|
||||
CHECK_THROWS_WITH(j_array.insert(j_another_array.end(), j_value),
|
||||
"iterator does not fit current value");
|
||||
CHECK_THROWS_WITH(j_array.insert(j_another_array.end(), 10, 11),
|
||||
"iterator does not fit current value");
|
||||
CHECK_THROWS_WITH(j_array.insert(j_another_array.end(), j_yet_another_array.begin(),
|
||||
j_yet_another_array.end()), "iterator does not fit current value");
|
||||
CHECK_THROWS_WITH(j_array.insert(j_another_array.end(), {1, 2, 3, 4}),
|
||||
"iterator does not fit current value");
|
||||
}
|
||||
|
||||
SECTION("non-array type")
|
||||
{
|
||||
// call insert on a non-array type
|
||||
json j_nonarray = 3;
|
||||
json j_yet_another_array = {"first", "second"};
|
||||
CHECK_THROWS_AS(j_nonarray.insert(j_nonarray.end(), 10), std::domain_error);
|
||||
CHECK_THROWS_AS(j_nonarray.insert(j_nonarray.end(), j_value), std::domain_error);
|
||||
CHECK_THROWS_AS(j_nonarray.insert(j_nonarray.end(), 10, 11), std::domain_error);
|
||||
CHECK_THROWS_AS(j_nonarray.insert(j_nonarray.end(), j_yet_another_array.begin(),
|
||||
j_yet_another_array.end()), std::domain_error);
|
||||
CHECK_THROWS_AS(j_nonarray.insert(j_nonarray.end(), {1, 2, 3, 4}), std::domain_error);
|
||||
|
||||
CHECK_THROWS_WITH(j_nonarray.insert(j_nonarray.end(), 10), "cannot use insert() with number");
|
||||
CHECK_THROWS_WITH(j_nonarray.insert(j_nonarray.end(), j_value), "cannot use insert() with number");
|
||||
CHECK_THROWS_WITH(j_nonarray.insert(j_nonarray.end(), 10, 11), "cannot use insert() with number");
|
||||
CHECK_THROWS_WITH(j_nonarray.insert(j_nonarray.end(), j_yet_another_array.begin(),
|
||||
j_yet_another_array.end()), "cannot use insert() with number");
|
||||
CHECK_THROWS_WITH(j_nonarray.insert(j_nonarray.end(), {1, 2, 3, 4}),
|
||||
"cannot use insert() with number");
|
||||
}
|
||||
}
|
||||
|
||||
SECTION("swap()")
|
||||
{
|
||||
SECTION("json")
|
||||
{
|
||||
SECTION("member swap")
|
||||
{
|
||||
json j("hello world");
|
||||
json k(42.23);
|
||||
|
||||
j.swap(k);
|
||||
|
||||
CHECK(j == json(42.23));
|
||||
CHECK(k == json("hello world"));
|
||||
}
|
||||
|
||||
SECTION("nonmember swap")
|
||||
{
|
||||
json j("hello world");
|
||||
json k(42.23);
|
||||
|
||||
std::swap(j, k);
|
||||
|
||||
CHECK(j == json(42.23));
|
||||
CHECK(k == json("hello world"));
|
||||
}
|
||||
}
|
||||
|
||||
SECTION("array_t")
|
||||
{
|
||||
SECTION("array_t type")
|
||||
{
|
||||
json j = {1, 2, 3, 4};
|
||||
json::array_t a = {"foo", "bar", "baz"};
|
||||
|
||||
j.swap(a);
|
||||
|
||||
CHECK(j == json({"foo", "bar", "baz"}));
|
||||
|
||||
j.swap(a);
|
||||
|
||||
CHECK(j == json({1, 2, 3, 4}));
|
||||
}
|
||||
|
||||
SECTION("non-array_t type")
|
||||
{
|
||||
json j = 17;
|
||||
json::array_t a = {"foo", "bar", "baz"};
|
||||
|
||||
CHECK_THROWS_AS(j.swap(a), std::domain_error);
|
||||
CHECK_THROWS_WITH(j.swap(a), "cannot use swap() with number");
|
||||
}
|
||||
}
|
||||
|
||||
SECTION("object_t")
|
||||
{
|
||||
SECTION("object_t type")
|
||||
{
|
||||
json j = {{"one", 1}, {"two", 2}};
|
||||
json::object_t o = {{"cow", "Kuh"}, {"chicken", "Huhn"}};
|
||||
|
||||
j.swap(o);
|
||||
|
||||
CHECK(j == json({{"cow", "Kuh"}, {"chicken", "Huhn"}}));
|
||||
|
||||
j.swap(o);
|
||||
|
||||
CHECK(j == json({{"one", 1}, {"two", 2}}));
|
||||
}
|
||||
|
||||
SECTION("non-object_t type")
|
||||
{
|
||||
json j = 17;
|
||||
json::object_t o = {{"cow", "Kuh"}, {"chicken", "Huhn"}};
|
||||
|
||||
CHECK_THROWS_AS(j.swap(o), std::domain_error);
|
||||
CHECK_THROWS_WITH(j.swap(o), "cannot use swap() with number");
|
||||
}
|
||||
}
|
||||
|
||||
SECTION("string_t")
|
||||
{
|
||||
SECTION("string_t type")
|
||||
{
|
||||
json j = "Hello world";
|
||||
json::string_t s = "Hallo Welt";
|
||||
|
||||
j.swap(s);
|
||||
|
||||
CHECK(j == json("Hallo Welt"));
|
||||
|
||||
j.swap(s);
|
||||
|
||||
CHECK(j == json("Hello world"));
|
||||
}
|
||||
|
||||
SECTION("non-string_t type")
|
||||
{
|
||||
json j = 17;
|
||||
json::string_t s = "Hallo Welt";
|
||||
|
||||
CHECK_THROWS_AS(j.swap(s), std::domain_error);
|
||||
CHECK_THROWS_WITH(j.swap(s), "cannot use swap() with number");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
263
test/src/unit-pointer_access.cpp
Normal file
263
test/src/unit-pointer_access.cpp
Normal file
|
@ -0,0 +1,263 @@
|
|||
/*
|
||||
__ _____ _____ _____
|
||||
__| | __| | | | JSON for Modern C++ (test suite)
|
||||
| | |__ | | | | | | version 2.0.2
|
||||
|_____|_____|_____|_|___| https://github.com/nlohmann/json
|
||||
|
||||
Licensed under the MIT License <http://opensource.org/licenses/MIT>.
|
||||
Copyright (c) 2013-2016 Niels Lohmann <http://nlohmann.me>.
|
||||
|
||||
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("pointer access")
|
||||
{
|
||||
// create a JSON value with different types
|
||||
json json_types =
|
||||
{
|
||||
{"boolean", true},
|
||||
{
|
||||
"number", {
|
||||
{"integer", 42},
|
||||
{"unsigned", 42u},
|
||||
{"floating-point", 17.23}
|
||||
}
|
||||
},
|
||||
{"string", "Hello, world!"},
|
||||
{"array", {1, 2, 3, 4, 5}},
|
||||
{"null", nullptr}
|
||||
};
|
||||
|
||||
SECTION("pointer access to object_t")
|
||||
{
|
||||
using test_type = json::object_t;
|
||||
json value = {{"one", 1}, {"two", 2}};
|
||||
|
||||
// check if pointers are returned correctly
|
||||
test_type* p1 = value.get_ptr<test_type*>();
|
||||
CHECK(p1 == value.get_ptr<test_type*>());
|
||||
CHECK(*p1 == value.get<test_type>());
|
||||
|
||||
const test_type* p2 = value.get_ptr<const test_type*>();
|
||||
CHECK(p1 == value.get_ptr<const test_type*>());
|
||||
CHECK(*p2 == value.get<test_type>());
|
||||
|
||||
const test_type* const p3 = value.get_ptr<const test_type* const>();
|
||||
CHECK(p1 == value.get_ptr<const test_type* const>());
|
||||
CHECK(*p3 == value.get<test_type>());
|
||||
|
||||
// check if null pointers are returned correctly
|
||||
CHECK(value.get_ptr<json::object_t*>() != nullptr);
|
||||
CHECK(value.get_ptr<json::array_t*>() == nullptr);
|
||||
CHECK(value.get_ptr<json::string_t*>() == nullptr);
|
||||
CHECK(value.get_ptr<json::boolean_t*>() == nullptr);
|
||||
CHECK(value.get_ptr<json::number_integer_t*>() == nullptr);
|
||||
CHECK(value.get_ptr<json::number_unsigned_t*>() == nullptr);
|
||||
CHECK(value.get_ptr<json::number_float_t*>() == nullptr);
|
||||
}
|
||||
|
||||
SECTION("pointer access to const object_t")
|
||||
{
|
||||
using test_type = json::object_t;
|
||||
const json value = {{"one", 1}, {"two", 2}};
|
||||
|
||||
// this should not compile
|
||||
// test_type* p1 = value.get_ptr<test_type*>();
|
||||
|
||||
// check if pointers are returned correctly
|
||||
const test_type* p2 = value.get_ptr<const test_type*>();
|
||||
CHECK(*p2 == value.get<test_type>());
|
||||
|
||||
const test_type* const p3 = value.get_ptr<const test_type* const>();
|
||||
CHECK(p2 == p3);
|
||||
}
|
||||
|
||||
SECTION("pointer access to array_t")
|
||||
{
|
||||
using test_type = json::array_t;
|
||||
json value = {1, 2, 3, 4};
|
||||
|
||||
// check if pointers are returned correctly
|
||||
test_type* p1 = value.get_ptr<test_type*>();
|
||||
CHECK(p1 == value.get_ptr<test_type*>());
|
||||
CHECK(*p1 == value.get<test_type>());
|
||||
|
||||
const test_type* p2 = value.get_ptr<const test_type*>();
|
||||
CHECK(p1 == value.get_ptr<const test_type*>());
|
||||
CHECK(*p2 == value.get<test_type>());
|
||||
|
||||
const test_type* const p3 = value.get_ptr<const test_type* const>();
|
||||
CHECK(p1 == value.get_ptr<const test_type* const>());
|
||||
CHECK(*p3 == value.get<test_type>());
|
||||
|
||||
// check if null pointers are returned correctly
|
||||
CHECK(value.get_ptr<json::object_t*>() == nullptr);
|
||||
CHECK(value.get_ptr<json::array_t*>() != nullptr);
|
||||
CHECK(value.get_ptr<json::string_t*>() == nullptr);
|
||||
CHECK(value.get_ptr<json::boolean_t*>() == nullptr);
|
||||
CHECK(value.get_ptr<json::number_integer_t*>() == nullptr);
|
||||
CHECK(value.get_ptr<json::number_unsigned_t*>() == nullptr);
|
||||
CHECK(value.get_ptr<json::number_float_t*>() == nullptr);
|
||||
}
|
||||
|
||||
SECTION("pointer access to string_t")
|
||||
{
|
||||
using test_type = json::string_t;
|
||||
json value = "hello";
|
||||
|
||||
// check if pointers are returned correctly
|
||||
test_type* p1 = value.get_ptr<test_type*>();
|
||||
CHECK(p1 == value.get_ptr<test_type*>());
|
||||
CHECK(*p1 == value.get<test_type>());
|
||||
|
||||
const test_type* p2 = value.get_ptr<const test_type*>();
|
||||
CHECK(p1 == value.get_ptr<const test_type*>());
|
||||
CHECK(*p2 == value.get<test_type>());
|
||||
|
||||
const test_type* const p3 = value.get_ptr<const test_type* const>();
|
||||
CHECK(p1 == value.get_ptr<const test_type* const>());
|
||||
CHECK(*p3 == value.get<test_type>());
|
||||
|
||||
// check if null pointers are returned correctly
|
||||
CHECK(value.get_ptr<json::object_t*>() == nullptr);
|
||||
CHECK(value.get_ptr<json::array_t*>() == nullptr);
|
||||
CHECK(value.get_ptr<json::string_t*>() != nullptr);
|
||||
CHECK(value.get_ptr<json::boolean_t*>() == nullptr);
|
||||
CHECK(value.get_ptr<json::number_integer_t*>() == nullptr);
|
||||
CHECK(value.get_ptr<json::number_unsigned_t*>() == nullptr);
|
||||
CHECK(value.get_ptr<json::number_float_t*>() == nullptr);
|
||||
}
|
||||
|
||||
SECTION("pointer access to boolean_t")
|
||||
{
|
||||
using test_type = json::boolean_t;
|
||||
json value = false;
|
||||
|
||||
// check if pointers are returned correctly
|
||||
test_type* p1 = value.get_ptr<test_type*>();
|
||||
CHECK(p1 == value.get_ptr<test_type*>());
|
||||
CHECK(*p1 == value.get<test_type>());
|
||||
|
||||
const test_type* p2 = value.get_ptr<const test_type*>();
|
||||
CHECK(p1 == value.get_ptr<const test_type*>());
|
||||
CHECK(*p2 == value.get<test_type>());
|
||||
|
||||
const test_type* const p3 = value.get_ptr<const test_type* const>();
|
||||
CHECK(p1 == value.get_ptr<const test_type* const>());
|
||||
CHECK(*p3 == value.get<test_type>());
|
||||
|
||||
// check if null pointers are returned correctly
|
||||
CHECK(value.get_ptr<json::object_t*>() == nullptr);
|
||||
CHECK(value.get_ptr<json::array_t*>() == nullptr);
|
||||
CHECK(value.get_ptr<json::string_t*>() == nullptr);
|
||||
CHECK(value.get_ptr<json::boolean_t*>() != nullptr);
|
||||
CHECK(value.get_ptr<json::number_integer_t*>() == nullptr);
|
||||
CHECK(value.get_ptr<json::number_unsigned_t*>() == nullptr);
|
||||
CHECK(value.get_ptr<json::number_float_t*>() == nullptr);
|
||||
}
|
||||
|
||||
SECTION("pointer access to number_integer_t")
|
||||
{
|
||||
using test_type = json::number_integer_t;
|
||||
json value = 23;
|
||||
|
||||
// check if pointers are returned correctly
|
||||
test_type* p1 = value.get_ptr<test_type*>();
|
||||
CHECK(p1 == value.get_ptr<test_type*>());
|
||||
CHECK(*p1 == value.get<test_type>());
|
||||
|
||||
const test_type* p2 = value.get_ptr<const test_type*>();
|
||||
CHECK(p1 == value.get_ptr<const test_type*>());
|
||||
CHECK(*p2 == value.get<test_type>());
|
||||
|
||||
const test_type* const p3 = value.get_ptr<const test_type* const>();
|
||||
CHECK(p1 == value.get_ptr<const test_type* const>());
|
||||
CHECK(*p3 == value.get<test_type>());
|
||||
|
||||
// check if null pointers are returned correctly
|
||||
CHECK(value.get_ptr<json::object_t*>() == nullptr);
|
||||
CHECK(value.get_ptr<json::array_t*>() == nullptr);
|
||||
CHECK(value.get_ptr<json::string_t*>() == nullptr);
|
||||
CHECK(value.get_ptr<json::boolean_t*>() == nullptr);
|
||||
CHECK(value.get_ptr<json::number_integer_t*>() != nullptr);
|
||||
CHECK(value.get_ptr<json::number_unsigned_t*>() == nullptr);
|
||||
CHECK(value.get_ptr<json::number_float_t*>() == nullptr);
|
||||
}
|
||||
|
||||
SECTION("pointer access to number_unsigned_t")
|
||||
{
|
||||
using test_type = json::number_unsigned_t;
|
||||
json value = 23u;
|
||||
|
||||
// check if pointers are returned correctly
|
||||
test_type* p1 = value.get_ptr<test_type*>();
|
||||
CHECK(p1 == value.get_ptr<test_type*>());
|
||||
CHECK(*p1 == value.get<test_type>());
|
||||
|
||||
const test_type* p2 = value.get_ptr<const test_type*>();
|
||||
CHECK(p1 == value.get_ptr<const test_type*>());
|
||||
CHECK(*p2 == value.get<test_type>());
|
||||
|
||||
const test_type* const p3 = value.get_ptr<const test_type* const>();
|
||||
CHECK(p1 == value.get_ptr<const test_type* const>());
|
||||
CHECK(*p3 == value.get<test_type>());
|
||||
|
||||
// check if null pointers are returned correctly
|
||||
CHECK(value.get_ptr<json::object_t*>() == nullptr);
|
||||
CHECK(value.get_ptr<json::array_t*>() == nullptr);
|
||||
CHECK(value.get_ptr<json::string_t*>() == nullptr);
|
||||
CHECK(value.get_ptr<json::boolean_t*>() == nullptr);
|
||||
CHECK(value.get_ptr<json::number_integer_t*>() != nullptr);
|
||||
CHECK(value.get_ptr<json::number_unsigned_t*>() != nullptr);
|
||||
CHECK(value.get_ptr<json::number_float_t*>() == nullptr);
|
||||
}
|
||||
|
||||
SECTION("pointer access to number_float_t")
|
||||
{
|
||||
using test_type = json::number_float_t;
|
||||
json value = 42.23;
|
||||
|
||||
// check if pointers are returned correctly
|
||||
test_type* p1 = value.get_ptr<test_type*>();
|
||||
CHECK(p1 == value.get_ptr<test_type*>());
|
||||
CHECK(*p1 == Approx(value.get<test_type>()));
|
||||
|
||||
const test_type* p2 = value.get_ptr<const test_type*>();
|
||||
CHECK(p1 == value.get_ptr<const test_type*>());
|
||||
CHECK(*p2 == Approx(value.get<test_type>()));
|
||||
|
||||
const test_type* const p3 = value.get_ptr<const test_type* const>();
|
||||
CHECK(p1 == value.get_ptr<const test_type* const>());
|
||||
CHECK(*p3 == Approx(value.get<test_type>()));
|
||||
|
||||
// check if null pointers are returned correctly
|
||||
CHECK(value.get_ptr<json::object_t*>() == nullptr);
|
||||
CHECK(value.get_ptr<json::array_t*>() == nullptr);
|
||||
CHECK(value.get_ptr<json::string_t*>() == nullptr);
|
||||
CHECK(value.get_ptr<json::boolean_t*>() == nullptr);
|
||||
CHECK(value.get_ptr<json::number_integer_t*>() == nullptr);
|
||||
CHECK(value.get_ptr<json::number_unsigned_t*>() == nullptr);
|
||||
CHECK(value.get_ptr<json::number_float_t*>() != nullptr);
|
||||
}
|
||||
}
|
299
test/src/unit-readme.cpp
Normal file
299
test/src/unit-readme.cpp
Normal file
|
@ -0,0 +1,299 @@
|
|||
/*
|
||||
__ _____ _____ _____
|
||||
__| | __| | | | JSON for Modern C++ (test suite)
|
||||
| | |__ | | | | | | version 2.0.2
|
||||
|_____|_____|_____|_|___| https://github.com/nlohmann/json
|
||||
|
||||
Licensed under the MIT License <http://opensource.org/licenses/MIT>.
|
||||
Copyright (c) 2013-2016 Niels Lohmann <http://nlohmann.me>.
|
||||
|
||||
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;
|
||||
|
||||
#include <deque>
|
||||
#include <forward_list>
|
||||
#include <list>
|
||||
#include <unordered_map>
|
||||
#include <unordered_set>
|
||||
|
||||
TEST_CASE("README", "[hide]")
|
||||
{
|
||||
{
|
||||
// redirect std::cout for the README file
|
||||
auto old_cout_buffer = std::cout.rdbuf();
|
||||
std::ostringstream new_stream;
|
||||
std::cout.rdbuf(new_stream.rdbuf());
|
||||
{
|
||||
// create an empty structure (null)
|
||||
json j;
|
||||
|
||||
// add a number that is stored as double (note the implicit conversion of j to an object)
|
||||
j["pi"] = 3.141;
|
||||
|
||||
// add a Boolean that is stored as bool
|
||||
j["happy"] = true;
|
||||
|
||||
// add a string that is stored as std::string
|
||||
j["name"] = "Niels";
|
||||
|
||||
// add another null object by passing nullptr
|
||||
j["nothing"] = nullptr;
|
||||
|
||||
// add an object inside the object
|
||||
j["answer"]["everything"] = 42;
|
||||
|
||||
// add an array that is stored as std::vector (using an initializer list)
|
||||
j["list"] = { 1, 0, 2 };
|
||||
|
||||
// add another object (using an initializer list of pairs)
|
||||
j["object"] = { {"currency", "USD"}, {"value", 42.99} };
|
||||
|
||||
// instead, you could also write (which looks very similar to the JSON above)
|
||||
json j2 =
|
||||
{
|
||||
{"pi", 3.141},
|
||||
{"happy", true},
|
||||
{"name", "Niels"},
|
||||
{"nothing", nullptr},
|
||||
{
|
||||
"answer", {
|
||||
{"everything", 42}
|
||||
}
|
||||
},
|
||||
{"list", {1, 0, 2}},
|
||||
{
|
||||
"object", {
|
||||
{"currency", "USD"},
|
||||
{"value", 42.99}
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
{
|
||||
// ways to express the empty array []
|
||||
json empty_array_implicit = {{}};
|
||||
json empty_array_explicit = json::array();
|
||||
|
||||
// a way to express the empty object {}
|
||||
json empty_object_explicit = json::object();
|
||||
|
||||
// a way to express an _array_ of key/value pairs [["currency", "USD"], ["value", 42.99]]
|
||||
json array_not_object = { json::array({"currency", "USD"}), json::array({"value", 42.99}) };
|
||||
}
|
||||
|
||||
{
|
||||
// create object from string literal
|
||||
json j = "{ \"happy\": true, \"pi\": 3.141 }"_json;
|
||||
|
||||
// or even nicer with a raw string literal
|
||||
auto j2 = R"(
|
||||
{
|
||||
"happy": true,
|
||||
"pi": 3.141
|
||||
}
|
||||
)"_json;
|
||||
|
||||
// or explicitly
|
||||
auto j3 = json::parse("{ \"happy\": true, \"pi\": 3.141 }");
|
||||
|
||||
// explicit conversion to string
|
||||
std::string s = j.dump(); // {\"happy\":true,\"pi\":3.141}
|
||||
|
||||
// serialization with pretty printing
|
||||
// pass in the amount of spaces to indent
|
||||
std::cout << j.dump(4) << std::endl;
|
||||
// {
|
||||
// "happy": true,
|
||||
// "pi": 3.141
|
||||
// }
|
||||
|
||||
std::cout << std::setw(2) << j << std::endl;
|
||||
}
|
||||
|
||||
{
|
||||
// create an array using push_back
|
||||
json j;
|
||||
j.push_back("foo");
|
||||
j.push_back(1);
|
||||
j.push_back(true);
|
||||
|
||||
// iterate the array
|
||||
for (json::iterator it = j.begin(); it != j.end(); ++it)
|
||||
{
|
||||
std::cout << *it << '\n';
|
||||
}
|
||||
|
||||
// range-based for
|
||||
for (auto element : j)
|
||||
{
|
||||
std::cout << element << '\n';
|
||||
}
|
||||
|
||||
// getter/setter
|
||||
const std::string tmp = j[0];
|
||||
j[1] = 42;
|
||||
bool foo = j.at(2);
|
||||
|
||||
// other stuff
|
||||
j.size(); // 3 entries
|
||||
j.empty(); // false
|
||||
j.type(); // json::value_t::array
|
||||
j.clear(); // the array is empty again
|
||||
|
||||
// comparison
|
||||
j == "[\"foo\", 1, true]"_json; // true
|
||||
|
||||
// create an object
|
||||
json o;
|
||||
o["foo"] = 23;
|
||||
o["bar"] = false;
|
||||
o["baz"] = 3.141;
|
||||
|
||||
// find an entry
|
||||
if (o.find("foo") != o.end())
|
||||
{
|
||||
// there is an entry with key "foo"
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
std::vector<int> c_vector {1, 2, 3, 4};
|
||||
json j_vec(c_vector);
|
||||
// [1, 2, 3, 4]
|
||||
|
||||
std::deque<float> c_deque {1.2f, 2.3f, 3.4f, 5.6f};
|
||||
json j_deque(c_deque);
|
||||
// [1.2, 2.3, 3.4, 5.6]
|
||||
|
||||
std::list<bool> c_list {true, true, false, true};
|
||||
json j_list(c_list);
|
||||
// [true, true, false, true]
|
||||
|
||||
std::forward_list<int64_t> c_flist {12345678909876, 23456789098765, 34567890987654, 45678909876543};
|
||||
json j_flist(c_flist);
|
||||
// [12345678909876, 23456789098765, 34567890987654, 45678909876543]
|
||||
|
||||
std::array<unsigned long, 4> c_array {{1, 2, 3, 4}};
|
||||
json j_array(c_array);
|
||||
// [1, 2, 3, 4]
|
||||
|
||||
std::set<std::string> c_set {"one", "two", "three", "four", "one"};
|
||||
json j_set(c_set); // only one entry for "one" is used
|
||||
// ["four", "one", "three", "two"]
|
||||
|
||||
std::unordered_set<std::string> c_uset {"one", "two", "three", "four", "one"};
|
||||
json j_uset(c_uset); // only one entry for "one" is used
|
||||
// maybe ["two", "three", "four", "one"]
|
||||
|
||||
std::multiset<std::string> c_mset {"one", "two", "one", "four"};
|
||||
json j_mset(c_mset); // only one entry for "one" is used
|
||||
// maybe ["one", "two", "four"]
|
||||
|
||||
std::unordered_multiset<std::string> c_umset {"one", "two", "one", "four"};
|
||||
json j_umset(c_umset); // both entries for "one" are used
|
||||
// maybe ["one", "two", "one", "four"]
|
||||
}
|
||||
|
||||
{
|
||||
std::map<std::string, int> c_map { {"one", 1}, {"two", 2}, {"three", 3} };
|
||||
json j_map(c_map);
|
||||
// {"one": 1, "two": 2, "three": 3}
|
||||
|
||||
std::unordered_map<const char*, float> c_umap { {"one", 1.2f}, {"two", 2.3f}, {"three", 3.4f} };
|
||||
json j_umap(c_umap);
|
||||
// {"one": 1.2, "two": 2.3, "three": 3.4}
|
||||
|
||||
std::multimap<std::string, bool> c_mmap { {"one", true}, {"two", true}, {"three", false}, {"three", true} };
|
||||
json j_mmap(c_mmap); // only one entry for key "three" is used
|
||||
// maybe {"one": true, "two": true, "three": true}
|
||||
|
||||
std::unordered_multimap<std::string, bool> c_ummap { {"one", true}, {"two", true}, {"three", false}, {"three", true} };
|
||||
json j_ummap(c_ummap); // only one entry for key "three" is used
|
||||
// maybe {"one": true, "two": true, "three": true}
|
||||
}
|
||||
|
||||
{
|
||||
// strings
|
||||
std::string s1 = "Hello, world!";
|
||||
json js = s1;
|
||||
std::string s2 = js;
|
||||
|
||||
// Booleans
|
||||
bool b1 = true;
|
||||
json jb = b1;
|
||||
bool b2 = jb;
|
||||
|
||||
// numbers
|
||||
int i = 42;
|
||||
json jn = i;
|
||||
double f = jn;
|
||||
|
||||
// etc.
|
||||
|
||||
std::string vs = js.get<std::string>();
|
||||
bool vb = jb.get<bool>();
|
||||
int vi = jn.get<int>();
|
||||
|
||||
// etc.
|
||||
}
|
||||
|
||||
{
|
||||
// a JSON value
|
||||
json j_original = R"({
|
||||
"baz": ["one", "two", "three"],
|
||||
"foo": "bar"
|
||||
})"_json;
|
||||
|
||||
// access members with a JSON pointer (RFC 6901)
|
||||
j_original["/baz/1"_json_pointer];
|
||||
// "two"
|
||||
|
||||
// a JSON patch (RFC 6902)
|
||||
json j_patch = R"([
|
||||
{ "op": "replace", "path": "/baz", "value": "boo" },
|
||||
{ "op": "add", "path": "/hello", "value": ["world"] },
|
||||
{ "op": "remove", "path": "/foo"}
|
||||
])"_json;
|
||||
|
||||
// apply the patch
|
||||
json j_result = j_original.patch(j_patch);
|
||||
// {
|
||||
// "baz": "boo",
|
||||
// "hello": ["world"]
|
||||
// }
|
||||
|
||||
// calculate a JSON patch from two JSON values
|
||||
json::diff(j_result, j_original);
|
||||
// [
|
||||
// { "op":" replace", "path": "/baz", "value": ["one", "two", "three"] },
|
||||
// { "op":"remove","path":"/hello" },
|
||||
// { "op":"add","path":"/foo","value":"bar" }
|
||||
// ]
|
||||
}
|
||||
|
||||
// restore old std::cout
|
||||
std::cout.rdbuf(old_cout_buffer);
|
||||
}
|
||||
}
|
202
test/src/unit-reference_access.cpp
Normal file
202
test/src/unit-reference_access.cpp
Normal file
|
@ -0,0 +1,202 @@
|
|||
/*
|
||||
__ _____ _____ _____
|
||||
__| | __| | | | JSON for Modern C++ (test suite)
|
||||
| | |__ | | | | | | version 2.0.2
|
||||
|_____|_____|_____|_|___| https://github.com/nlohmann/json
|
||||
|
||||
Licensed under the MIT License <http://opensource.org/licenses/MIT>.
|
||||
Copyright (c) 2013-2016 Niels Lohmann <http://nlohmann.me>.
|
||||
|
||||
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("reference access")
|
||||
{
|
||||
// create a JSON value with different types
|
||||
json json_types =
|
||||
{
|
||||
{"boolean", true},
|
||||
{
|
||||
"number", {
|
||||
{"integer", 42},
|
||||
{"floating-point", 17.23}
|
||||
}
|
||||
},
|
||||
{"string", "Hello, world!"},
|
||||
{"array", {1, 2, 3, 4, 5}},
|
||||
{"null", nullptr}
|
||||
};
|
||||
|
||||
SECTION("reference access to object_t")
|
||||
{
|
||||
using test_type = json::object_t;
|
||||
json value = {{"one", 1}, {"two", 2}};
|
||||
|
||||
// check if references are returned correctly
|
||||
test_type& p1 = value.get_ref<test_type&>();
|
||||
CHECK(&p1 == value.get_ptr<test_type*>());
|
||||
CHECK(p1 == value.get<test_type>());
|
||||
|
||||
const test_type& p2 = value.get_ref<const test_type&>();
|
||||
CHECK(&p2 == value.get_ptr<const test_type*>());
|
||||
CHECK(p2 == value.get<test_type>());
|
||||
|
||||
// check if mismatching references throw correctly
|
||||
CHECK_NOTHROW(value.get_ref<json::object_t&>());
|
||||
CHECK_THROWS(value.get_ref<json::array_t&>());
|
||||
CHECK_THROWS(value.get_ref<json::string_t&>());
|
||||
CHECK_THROWS(value.get_ref<json::boolean_t&>());
|
||||
CHECK_THROWS(value.get_ref<json::number_integer_t&>());
|
||||
CHECK_THROWS(value.get_ref<json::number_float_t&>());
|
||||
}
|
||||
|
||||
SECTION("const reference access to const object_t")
|
||||
{
|
||||
using test_type = json::object_t;
|
||||
const json value = {{"one", 1}, {"two", 2}};
|
||||
|
||||
// this should not compile
|
||||
// test_type& p1 = value.get_ref<test_type&>();
|
||||
|
||||
// check if references are returned correctly
|
||||
const test_type& p2 = value.get_ref<const test_type&>();
|
||||
CHECK(&p2 == value.get_ptr<const test_type*>());
|
||||
CHECK(p2 == value.get<test_type>());
|
||||
}
|
||||
|
||||
SECTION("reference access to array_t")
|
||||
{
|
||||
using test_type = json::array_t;
|
||||
json value = {1, 2, 3, 4};
|
||||
|
||||
// check if references are returned correctly
|
||||
test_type& p1 = value.get_ref<test_type&>();
|
||||
CHECK(&p1 == value.get_ptr<test_type*>());
|
||||
CHECK(p1 == value.get<test_type>());
|
||||
|
||||
const test_type& p2 = value.get_ref<const test_type&>();
|
||||
CHECK(&p2 == value.get_ptr<const test_type*>());
|
||||
CHECK(p2 == value.get<test_type>());
|
||||
|
||||
// check if mismatching references throw correctly
|
||||
CHECK_THROWS(value.get_ref<json::object_t&>());
|
||||
CHECK_NOTHROW(value.get_ref<json::array_t&>());
|
||||
CHECK_THROWS(value.get_ref<json::string_t&>());
|
||||
CHECK_THROWS(value.get_ref<json::boolean_t&>());
|
||||
CHECK_THROWS(value.get_ref<json::number_integer_t&>());
|
||||
CHECK_THROWS(value.get_ref<json::number_float_t&>());
|
||||
}
|
||||
|
||||
SECTION("reference access to string_t")
|
||||
{
|
||||
using test_type = json::string_t;
|
||||
json value = "hello";
|
||||
|
||||
// check if references are returned correctly
|
||||
test_type& p1 = value.get_ref<test_type&>();
|
||||
CHECK(&p1 == value.get_ptr<test_type*>());
|
||||
CHECK(p1 == value.get<test_type>());
|
||||
|
||||
const test_type& p2 = value.get_ref<const test_type&>();
|
||||
CHECK(&p2 == value.get_ptr<const test_type*>());
|
||||
CHECK(p2 == value.get<test_type>());
|
||||
|
||||
// check if mismatching references throw correctly
|
||||
CHECK_THROWS(value.get_ref<json::object_t&>());
|
||||
CHECK_THROWS(value.get_ref<json::array_t&>());
|
||||
CHECK_NOTHROW(value.get_ref<json::string_t&>());
|
||||
CHECK_THROWS(value.get_ref<json::boolean_t&>());
|
||||
CHECK_THROWS(value.get_ref<json::number_integer_t&>());
|
||||
CHECK_THROWS(value.get_ref<json::number_float_t&>());
|
||||
}
|
||||
|
||||
SECTION("reference access to boolean_t")
|
||||
{
|
||||
using test_type = json::boolean_t;
|
||||
json value = false;
|
||||
|
||||
// check if references are returned correctly
|
||||
test_type& p1 = value.get_ref<test_type&>();
|
||||
CHECK(&p1 == value.get_ptr<test_type*>());
|
||||
CHECK(p1 == value.get<test_type>());
|
||||
|
||||
const test_type& p2 = value.get_ref<const test_type&>();
|
||||
CHECK(&p2 == value.get_ptr<const test_type*>());
|
||||
CHECK(p2 == value.get<test_type>());
|
||||
|
||||
// check if mismatching references throw correctly
|
||||
CHECK_THROWS(value.get_ref<json::object_t&>());
|
||||
CHECK_THROWS(value.get_ref<json::array_t&>());
|
||||
CHECK_THROWS(value.get_ref<json::string_t&>());
|
||||
CHECK_NOTHROW(value.get_ref<json::boolean_t&>());
|
||||
CHECK_THROWS(value.get_ref<json::number_integer_t&>());
|
||||
CHECK_THROWS(value.get_ref<json::number_float_t&>());
|
||||
}
|
||||
|
||||
SECTION("reference access to number_integer_t")
|
||||
{
|
||||
using test_type = json::number_integer_t;
|
||||
json value = 23;
|
||||
|
||||
// check if references are returned correctly
|
||||
test_type& p1 = value.get_ref<test_type&>();
|
||||
CHECK(&p1 == value.get_ptr<test_type*>());
|
||||
CHECK(p1 == value.get<test_type>());
|
||||
|
||||
const test_type& p2 = value.get_ref<const test_type&>();
|
||||
CHECK(&p2 == value.get_ptr<const test_type*>());
|
||||
CHECK(p2 == value.get<test_type>());
|
||||
|
||||
// check if mismatching references throw correctly
|
||||
CHECK_THROWS(value.get_ref<json::object_t&>());
|
||||
CHECK_THROWS(value.get_ref<json::array_t&>());
|
||||
CHECK_THROWS(value.get_ref<json::string_t&>());
|
||||
CHECK_THROWS(value.get_ref<json::boolean_t&>());
|
||||
CHECK_NOTHROW(value.get_ref<json::number_integer_t&>());
|
||||
CHECK_THROWS(value.get_ref<json::number_float_t&>());
|
||||
}
|
||||
|
||||
SECTION("reference access to number_float_t")
|
||||
{
|
||||
using test_type = json::number_float_t;
|
||||
json value = 42.23;
|
||||
|
||||
// check if references are returned correctly
|
||||
test_type& p1 = value.get_ref<test_type&>();
|
||||
CHECK(&p1 == value.get_ptr<test_type*>());
|
||||
CHECK(p1 == value.get<test_type>());
|
||||
|
||||
const test_type& p2 = value.get_ref<const test_type&>();
|
||||
CHECK(&p2 == value.get_ptr<const test_type*>());
|
||||
CHECK(p2 == value.get<test_type>());
|
||||
|
||||
// check if mismatching references throw correctly
|
||||
CHECK_THROWS(value.get_ref<json::object_t&>());
|
||||
CHECK_THROWS(value.get_ref<json::array_t&>());
|
||||
CHECK_THROWS(value.get_ref<json::string_t&>());
|
||||
CHECK_THROWS(value.get_ref<json::boolean_t&>());
|
||||
CHECK_THROWS(value.get_ref<json::number_integer_t&>());
|
||||
CHECK_NOTHROW(value.get_ref<json::number_float_t&>());
|
||||
}
|
||||
}
|
443
test/src/unit-regression.cpp
Normal file
443
test/src/unit-regression.cpp
Normal file
|
@ -0,0 +1,443 @@
|
|||
/*
|
||||
__ _____ _____ _____
|
||||
__| | __| | | | JSON for Modern C++ (test suite)
|
||||
| | |__ | | | | | | version 2.0.2
|
||||
|_____|_____|_____|_|___| https://github.com/nlohmann/json
|
||||
|
||||
Licensed under the MIT License <http://opensource.org/licenses/MIT>.
|
||||
Copyright (c) 2013-2016 Niels Lohmann <http://nlohmann.me>.
|
||||
|
||||
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("regression tests")
|
||||
{
|
||||
SECTION("issue #60 - Double quotation mark is not parsed correctly")
|
||||
{
|
||||
SECTION("escape_dobulequote")
|
||||
{
|
||||
auto s = "[\"\\\"foo\\\"\"]";
|
||||
json j = json::parse(s);
|
||||
auto expected = R"(["\"foo\""])"_json;
|
||||
CHECK(j == expected);
|
||||
}
|
||||
}
|
||||
|
||||
SECTION("issue #70 - Handle infinity and NaN cases")
|
||||
{
|
||||
SECTION("NAN value")
|
||||
{
|
||||
CHECK(json(NAN) == json());
|
||||
CHECK(json(json::number_float_t(NAN)) == json());
|
||||
}
|
||||
|
||||
SECTION("infinity")
|
||||
{
|
||||
CHECK(json(INFINITY) == json());
|
||||
CHECK(json(json::number_float_t(INFINITY)) == json());
|
||||
}
|
||||
}
|
||||
|
||||
SECTION("pull request #71 - handle enum type")
|
||||
{
|
||||
enum { t = 0 };
|
||||
json j = json::array();
|
||||
j.push_back(t);
|
||||
|
||||
j.push_back(json::object(
|
||||
{
|
||||
{"game_type", t}
|
||||
}));
|
||||
}
|
||||
|
||||
SECTION("issue #76 - dump() / parse() not idempotent")
|
||||
{
|
||||
// create JSON object
|
||||
json fields;
|
||||
fields["one"] = std::string("one");
|
||||
fields["two"] = std::string("two three");
|
||||
fields["three"] = std::string("three \"four\"");
|
||||
|
||||
// create another JSON object by deserializing the serialization
|
||||
std::string payload = fields.dump();
|
||||
json parsed_fields = json::parse(payload);
|
||||
|
||||
// check individual fields to match both objects
|
||||
CHECK(parsed_fields["one"] == fields["one"]);
|
||||
CHECK(parsed_fields["two"] == fields["two"]);
|
||||
CHECK(parsed_fields["three"] == fields["three"]);
|
||||
|
||||
// check individual fields to match original input
|
||||
CHECK(parsed_fields["one"] == std::string("one"));
|
||||
CHECK(parsed_fields["two"] == std::string("two three"));
|
||||
CHECK(parsed_fields["three"] == std::string("three \"four\""));
|
||||
|
||||
// check equality of the objects
|
||||
CHECK(parsed_fields == fields);
|
||||
|
||||
// check equality of the serialized objects
|
||||
CHECK(fields.dump() == parsed_fields.dump());
|
||||
|
||||
// check everything in one line
|
||||
CHECK(fields == json::parse(fields.dump()));
|
||||
}
|
||||
|
||||
SECTION("issue #82 - lexer::get_number return NAN")
|
||||
{
|
||||
const auto content = R"(
|
||||
{
|
||||
"Test":"Test1",
|
||||
"Number":100,
|
||||
"Foo":42.42
|
||||
})";
|
||||
|
||||
std::stringstream ss;
|
||||
ss << content;
|
||||
json j;
|
||||
ss >> j;
|
||||
|
||||
std::string test = j["Test"];
|
||||
CHECK(test == "Test1");
|
||||
int number = j["Number"];
|
||||
CHECK(number == 100);
|
||||
float foo = j["Foo"];
|
||||
CHECK(foo == Approx(42.42));
|
||||
}
|
||||
|
||||
SECTION("issue #89 - nonstandard integer type")
|
||||
{
|
||||
// create JSON class with nonstandard integer number type
|
||||
using custom_json =
|
||||
nlohmann::basic_json<std::map, std::vector, std::string, bool, int32_t, uint32_t, float>;
|
||||
custom_json j;
|
||||
j["int_1"] = 1;
|
||||
// we need to cast to int to compile with Catch - the value is int32_t
|
||||
CHECK(static_cast<int>(j["int_1"]) == 1);
|
||||
|
||||
// tests for correct handling of non-standard integers that overflow the type selected by the user
|
||||
|
||||
// unsigned integer object creation - expected to wrap and still be stored as an integer
|
||||
j = 4294967296U; // 2^32
|
||||
CHECK(static_cast<int>(j.type()) == static_cast<int>(custom_json::value_t::number_unsigned));
|
||||
CHECK(j.get<uint32_t>() == 0); // Wrap
|
||||
|
||||
// unsigned integer parsing - expected to overflow and be stored as a float
|
||||
j = custom_json::parse("4294967296"); // 2^32
|
||||
CHECK(static_cast<int>(j.type()) == static_cast<int>(custom_json::value_t::number_float));
|
||||
CHECK(j.get<float>() == 4294967296.0f);
|
||||
|
||||
// integer object creation - expected to wrap and still be stored as an integer
|
||||
j = -2147483649LL; // -2^31-1
|
||||
CHECK(static_cast<int>(j.type()) == static_cast<int>(custom_json::value_t::number_integer));
|
||||
CHECK(j.get<int32_t>() == 2147483647); // Wrap
|
||||
|
||||
// integer parsing - expected to overflow and be stored as a float with rounding
|
||||
j = custom_json::parse("-2147483649"); // -2^31
|
||||
CHECK(static_cast<int>(j.type()) == static_cast<int>(custom_json::value_t::number_float));
|
||||
CHECK(j.get<float>() == -2147483650.0f);
|
||||
}
|
||||
|
||||
SECTION("issue #93 reverse_iterator operator inheritance problem")
|
||||
{
|
||||
{
|
||||
json a = {1, 2, 3};
|
||||
json::reverse_iterator rit = a.rbegin();
|
||||
++rit;
|
||||
CHECK(*rit == json(2));
|
||||
CHECK(rit.value() == json(2));
|
||||
}
|
||||
{
|
||||
json a = {1, 2, 3};
|
||||
json::reverse_iterator rit = ++a.rbegin();
|
||||
}
|
||||
{
|
||||
json a = {1, 2, 3};
|
||||
json::reverse_iterator rit = a.rbegin();
|
||||
++rit;
|
||||
json b = {0, 0, 0};
|
||||
std::transform(rit, a.rend(), b.rbegin(), [](json el)
|
||||
{
|
||||
return el;
|
||||
});
|
||||
CHECK(b == json({0, 1, 2}));
|
||||
}
|
||||
{
|
||||
json a = {1, 2, 3};
|
||||
json b = {0, 0, 0};
|
||||
std::transform(++a.rbegin(), a.rend(), b.rbegin(), [](json el)
|
||||
{
|
||||
return el;
|
||||
});
|
||||
CHECK(b == json({0, 1, 2}));
|
||||
}
|
||||
}
|
||||
|
||||
SECTION("issue #100 - failed to iterator json object with reverse_iterator")
|
||||
{
|
||||
json config =
|
||||
{
|
||||
{ "111", 111 },
|
||||
{ "112", 112 },
|
||||
{ "113", 113 }
|
||||
};
|
||||
|
||||
std::stringstream ss;
|
||||
|
||||
for (auto it = config.begin(); it != config.end(); ++it)
|
||||
{
|
||||
ss << it.key() << ": " << it.value() << '\n';
|
||||
}
|
||||
|
||||
for (auto it = config.rbegin(); it != config.rend(); ++it)
|
||||
{
|
||||
ss << it.key() << ": " << it.value() << '\n';
|
||||
}
|
||||
|
||||
CHECK(ss.str() == "111: 111\n112: 112\n113: 113\n113: 113\n112: 112\n111: 111\n");
|
||||
}
|
||||
|
||||
SECTION("issue #101 - binary string causes numbers to be dumped as hex")
|
||||
{
|
||||
int64_t number = 10;
|
||||
std::string bytes{"\x00" "asdf\n", 6};
|
||||
json j;
|
||||
j["int64"] = number;
|
||||
j["binary string"] = bytes;
|
||||
// make sure the number is really printed as decimal "10" and not as
|
||||
// hexadecimal "a"
|
||||
CHECK(j.dump() == "{\"binary string\":\"\\u0000asdf\\n\",\"int64\":10}");
|
||||
}
|
||||
|
||||
SECTION("issue #111 - subsequent unicode chars")
|
||||
{
|
||||
std::string bytes{0x7, 0x7};
|
||||
json j;
|
||||
j["string"] = bytes;
|
||||
CHECK(j["string"] == "\u0007\u0007");
|
||||
}
|
||||
|
||||
SECTION("issue #144 - implicit assignment to std::string fails")
|
||||
{
|
||||
json o = {{"name", "value"}};
|
||||
|
||||
std::string s1 = o["name"];
|
||||
CHECK(s1 == "value");
|
||||
|
||||
std::string s2;
|
||||
s2 = o["name"];
|
||||
|
||||
CHECK(s2 == "value");
|
||||
}
|
||||
|
||||
SECTION("issue #146 - character following a surrogate pair is skipped")
|
||||
{
|
||||
CHECK(json::parse("\"\\ud80c\\udc60abc\"").get<json::string_t>() == u8"\U00013060abc");
|
||||
}
|
||||
|
||||
SECTION("issue #171 - Cannot index by key of type static constexpr const char*")
|
||||
{
|
||||
json j;
|
||||
|
||||
// Non-const access with key as "char []"
|
||||
char array_key[] = "Key1";
|
||||
CHECK_NOTHROW(j[array_key] = 1);
|
||||
CHECK(j[array_key] == json(1));
|
||||
|
||||
// Non-const access with key as "const char[]"
|
||||
const char const_array_key[] = "Key2";
|
||||
CHECK_NOTHROW(j[const_array_key] = 2);
|
||||
CHECK(j[const_array_key] == json(2));
|
||||
|
||||
// Non-const access with key as "char *"
|
||||
char _ptr_key[] = "Key3";
|
||||
char* ptr_key = &_ptr_key[0];
|
||||
CHECK_NOTHROW(j[ptr_key] = 3);
|
||||
CHECK(j[ptr_key] == json(3));
|
||||
|
||||
// Non-const access with key as "const char *"
|
||||
const char* const_ptr_key = "Key4";
|
||||
CHECK_NOTHROW(j[const_ptr_key] = 4);
|
||||
CHECK(j[const_ptr_key] == json(4));
|
||||
|
||||
// Non-const access with key as "static constexpr const char *"
|
||||
static constexpr const char* constexpr_ptr_key = "Key5";
|
||||
CHECK_NOTHROW(j[constexpr_ptr_key] = 5);
|
||||
CHECK(j[constexpr_ptr_key] == json(5));
|
||||
|
||||
const json j_const = j;
|
||||
|
||||
// Const access with key as "char []"
|
||||
CHECK(j_const[array_key] == json(1));
|
||||
|
||||
// Const access with key as "const char[]"
|
||||
CHECK(j_const[const_array_key] == json(2));
|
||||
|
||||
// Const access with key as "char *"
|
||||
CHECK(j_const[ptr_key] == json(3));
|
||||
|
||||
// Const access with key as "const char *"
|
||||
CHECK(j_const[const_ptr_key] == json(4));
|
||||
|
||||
// Const access with key as "static constexpr const char *"
|
||||
CHECK(j_const[constexpr_ptr_key] == json(5));
|
||||
}
|
||||
|
||||
SECTION("issue #186 miloyip/nativejson-benchmark: floating-point parsing")
|
||||
{
|
||||
json j;
|
||||
|
||||
j = json::parse("-0.0");
|
||||
CHECK(j.get<double>() == -0.0);
|
||||
|
||||
j = json::parse("2.22507385850720113605740979670913197593481954635164564e-308");
|
||||
CHECK(j.get<double>() == 2.2250738585072009e-308);
|
||||
|
||||
j = json::parse("0.999999999999999944488848768742172978818416595458984374");
|
||||
CHECK(j.get<double>() == 0.99999999999999989);
|
||||
|
||||
j = json::parse("1.00000000000000011102230246251565404236316680908203126");
|
||||
CHECK(j.get<double>() == 1.00000000000000022);
|
||||
|
||||
j = json::parse("7205759403792793199999e-5");
|
||||
CHECK(j.get<double>() == 72057594037927928.0);
|
||||
|
||||
j = json::parse("922337203685477529599999e-5");
|
||||
CHECK(j.get<double>() == 9223372036854774784.0);
|
||||
|
||||
j = json::parse("1014120480182583464902367222169599999e-5");
|
||||
CHECK(j.get<double>() == 10141204801825834086073718800384.0);
|
||||
|
||||
j = json::parse("5708990770823839207320493820740630171355185151999e-3");
|
||||
CHECK(j.get<double>() == 5708990770823838890407843763683279797179383808.0);
|
||||
|
||||
// create JSON class with nonstandard float number type
|
||||
|
||||
// float
|
||||
nlohmann::basic_json<std::map, std::vector, std::string, bool, int32_t, uint32_t, float> j_float =
|
||||
1.23e25f;
|
||||
CHECK(j_float.get<float>() == 1.23e25f);
|
||||
|
||||
// double
|
||||
nlohmann::basic_json<std::map, std::vector, std::string, bool, int64_t, uint64_t, double> j_double =
|
||||
1.23e35f;
|
||||
CHECK(j_double.get<double>() == 1.23e35f);
|
||||
|
||||
// long double
|
||||
nlohmann::basic_json<std::map, std::vector, std::string, bool, int64_t, uint64_t, long double>
|
||||
j_long_double = 1.23e45L;
|
||||
CHECK(j_long_double.get<long double>() == 1.23e45L);
|
||||
}
|
||||
|
||||
SECTION("issue #228 - double values are serialized with commas as decimal points")
|
||||
{
|
||||
json j1a = 23.42;
|
||||
json j1b = json::parse("23.42");
|
||||
|
||||
json j2a = 2342e-2;
|
||||
//issue #230
|
||||
//json j2b = json::parse("2342e-2");
|
||||
|
||||
json j3a = 10E3;
|
||||
json j3b = json::parse("10E3");
|
||||
json j3c = json::parse("10e3");
|
||||
|
||||
// class to create a locale that would use a comma for decimals
|
||||
class CommaDecimalSeparator : public std::numpunct<char>
|
||||
{
|
||||
protected:
|
||||
char do_decimal_point() const
|
||||
{
|
||||
return ',';
|
||||
}
|
||||
};
|
||||
|
||||
// change locale to mess with decimal points
|
||||
std::locale::global(std::locale(std::locale(), new CommaDecimalSeparator));
|
||||
|
||||
CHECK(j1a.dump() == "23.42");
|
||||
CHECK(j1b.dump() == "23.42");
|
||||
|
||||
// check if locale is properly reset
|
||||
std::stringstream ss;
|
||||
ss.imbue(std::locale(std::locale(), new CommaDecimalSeparator));
|
||||
ss << 47.11;
|
||||
CHECK(ss.str() == "47,11");
|
||||
ss << j1a;
|
||||
CHECK(ss.str() == "47,1123.42");
|
||||
ss << 47.11;
|
||||
CHECK(ss.str() == "47,1123.4247,11");
|
||||
|
||||
CHECK(j2a.dump() == "23.42");
|
||||
//issue #230
|
||||
//CHECK(j2b.dump() == "23.42");
|
||||
|
||||
CHECK(j3a.dump() == "10000");
|
||||
CHECK(j3b.dump() == "10000");
|
||||
CHECK(j3c.dump() == "10000");
|
||||
//CHECK(j3b.dump() == "1E04"); // roundtrip error
|
||||
//CHECK(j3c.dump() == "1e04"); // roundtrip error
|
||||
}
|
||||
|
||||
SECTION("issue #233 - Can't use basic_json::iterator as a base iterator for std::move_iterator")
|
||||
{
|
||||
json source = {"a", "b", "c"};
|
||||
json expected = {"a", "b"};
|
||||
json dest;
|
||||
|
||||
std::copy_n(std::make_move_iterator(source.begin()), 2, std::back_inserter(dest));
|
||||
|
||||
CHECK(dest == expected);
|
||||
}
|
||||
|
||||
SECTION("issue #235 - ambiguous overload for 'push_back' and 'operator+='")
|
||||
{
|
||||
json data = {{"key", "value"}};
|
||||
data.push_back({"key2", "value2"});
|
||||
data += {"key3", "value3"};
|
||||
|
||||
CHECK(data == json({{"key", "value"}, {"key2", "value2"}, {"key3", "value3"}}));
|
||||
}
|
||||
|
||||
SECTION("issue #269 - diff generates incorrect patch when removing multiple array elements")
|
||||
{
|
||||
json doc = R"( { "arr1": [1, 2, 3, 4] } )"_json;
|
||||
json expected = R"( { "arr1": [1, 2] } )"_json;
|
||||
|
||||
// check roundtrip
|
||||
CHECK(doc.patch(json::diff(doc, expected)) == expected);
|
||||
}
|
||||
|
||||
SECTION("issue #283 - value() does not work with _json_pointer types")
|
||||
{
|
||||
json j =
|
||||
{
|
||||
{"object", {{"key1", 1}, {"key2", 2}}},
|
||||
};
|
||||
|
||||
int at_integer = j.at("/object/key2"_json_pointer);
|
||||
int val_integer = j.value("/object/key2"_json_pointer, 0);
|
||||
|
||||
CHECK(at_integer == val_integer);
|
||||
}
|
||||
}
|
76
test/src/unit-serialization.cpp
Normal file
76
test/src/unit-serialization.cpp
Normal file
|
@ -0,0 +1,76 @@
|
|||
/*
|
||||
__ _____ _____ _____
|
||||
__| | __| | | | JSON for Modern C++ (test suite)
|
||||
| | |__ | | | | | | version 2.0.2
|
||||
|_____|_____|_____|_|___| https://github.com/nlohmann/json
|
||||
|
||||
Licensed under the MIT License <http://opensource.org/licenses/MIT>.
|
||||
Copyright (c) 2013-2016 Niels Lohmann <http://nlohmann.me>.
|
||||
|
||||
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("serialization")
|
||||
{
|
||||
SECTION("operator<<")
|
||||
{
|
||||
SECTION("no given width")
|
||||
{
|
||||
std::stringstream ss;
|
||||
json j = {"foo", 1, 2, 3, false, {{"one", 1}}};
|
||||
ss << j;
|
||||
CHECK(ss.str() == "[\"foo\",1,2,3,false,{\"one\":1}]");
|
||||
}
|
||||
|
||||
SECTION("given width")
|
||||
{
|
||||
std::stringstream ss;
|
||||
json j = {"foo", 1, 2, 3, false, {{"one", 1}}};
|
||||
ss << std::setw(4) << j;
|
||||
CHECK(ss.str() ==
|
||||
"[\n \"foo\",\n 1,\n 2,\n 3,\n false,\n {\n \"one\": 1\n }\n]");
|
||||
}
|
||||
}
|
||||
|
||||
SECTION("operator>>")
|
||||
{
|
||||
SECTION("no given width")
|
||||
{
|
||||
std::stringstream ss;
|
||||
json j = {"foo", 1, 2, 3, false, {{"one", 1}}};
|
||||
j >> ss;
|
||||
CHECK(ss.str() == "[\"foo\",1,2,3,false,{\"one\":1}]");
|
||||
}
|
||||
|
||||
SECTION("given width")
|
||||
{
|
||||
std::stringstream ss;
|
||||
json j = {"foo", 1, 2, 3, false, {{"one", 1}}};
|
||||
ss.width(4);
|
||||
j >> ss;
|
||||
CHECK(ss.str() ==
|
||||
"[\n \"foo\",\n 1,\n 2,\n 3,\n false,\n {\n \"one\": 1\n }\n]");
|
||||
}
|
||||
}
|
||||
}
|
436
test/src/unit-testsuites.cpp
Normal file
436
test/src/unit-testsuites.cpp
Normal file
|
@ -0,0 +1,436 @@
|
|||
/*
|
||||
__ _____ _____ _____
|
||||
__| | __| | | | JSON for Modern C++ (test suite)
|
||||
| | |__ | | | | | | version 2.0.2
|
||||
|_____|_____|_____|_|___| https://github.com/nlohmann/json
|
||||
|
||||
Licensed under the MIT License <http://opensource.org/licenses/MIT>.
|
||||
Copyright (c) 2013-2016 Niels Lohmann <http://nlohmann.me>.
|
||||
|
||||
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;
|
||||
|
||||
#include <fstream>
|
||||
|
||||
TEST_CASE("compliance tests from json.org")
|
||||
{
|
||||
// test cases are from http://json.org/JSON_checker/
|
||||
|
||||
SECTION("expected failures")
|
||||
{
|
||||
for (auto filename :
|
||||
{
|
||||
//"test/data/json_tests/fail1.json",
|
||||
"test/data/json_tests/fail2.json",
|
||||
"test/data/json_tests/fail3.json",
|
||||
"test/data/json_tests/fail4.json",
|
||||
"test/data/json_tests/fail5.json",
|
||||
"test/data/json_tests/fail6.json",
|
||||
"test/data/json_tests/fail7.json",
|
||||
"test/data/json_tests/fail8.json",
|
||||
"test/data/json_tests/fail9.json",
|
||||
"test/data/json_tests/fail10.json",
|
||||
"test/data/json_tests/fail11.json",
|
||||
"test/data/json_tests/fail12.json",
|
||||
"test/data/json_tests/fail13.json",
|
||||
"test/data/json_tests/fail14.json",
|
||||
"test/data/json_tests/fail15.json",
|
||||
"test/data/json_tests/fail16.json",
|
||||
"test/data/json_tests/fail17.json",
|
||||
//"test/data/json_tests/fail18.json",
|
||||
"test/data/json_tests/fail19.json",
|
||||
"test/data/json_tests/fail20.json",
|
||||
"test/data/json_tests/fail21.json",
|
||||
"test/data/json_tests/fail22.json",
|
||||
"test/data/json_tests/fail23.json",
|
||||
"test/data/json_tests/fail24.json",
|
||||
"test/data/json_tests/fail25.json",
|
||||
"test/data/json_tests/fail26.json",
|
||||
"test/data/json_tests/fail27.json",
|
||||
"test/data/json_tests/fail28.json",
|
||||
"test/data/json_tests/fail29.json",
|
||||
"test/data/json_tests/fail30.json",
|
||||
"test/data/json_tests/fail31.json",
|
||||
"test/data/json_tests/fail32.json",
|
||||
"test/data/json_tests/fail33.json"
|
||||
})
|
||||
{
|
||||
CAPTURE(filename);
|
||||
json j;
|
||||
std::ifstream f(filename);
|
||||
CHECK_THROWS_AS(j << f, std::invalid_argument);
|
||||
}
|
||||
}
|
||||
|
||||
SECTION("expected passes")
|
||||
{
|
||||
for (auto filename :
|
||||
{
|
||||
"test/data/json_tests/pass1.json",
|
||||
"test/data/json_tests/pass2.json",
|
||||
"test/data/json_tests/pass3.json"
|
||||
})
|
||||
{
|
||||
CAPTURE(filename);
|
||||
json j;
|
||||
std::ifstream f(filename);
|
||||
CHECK_NOTHROW(j << f);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
TEST_CASE("compliance tests from nativejson-benchmark")
|
||||
{
|
||||
// test cases from https://github.com/miloyip/nativejson-benchmark/blob/master/src/main.cpp
|
||||
|
||||
SECTION("doubles")
|
||||
{
|
||||
auto TEST_DOUBLE = [](const std::string & json_string, const double expected)
|
||||
{
|
||||
CAPTURE(json_string);
|
||||
CAPTURE(expected);
|
||||
CHECK(json::parse(json_string)[0].get<double>() == Approx(expected));
|
||||
};
|
||||
|
||||
TEST_DOUBLE("[0.0]", 0.0);
|
||||
TEST_DOUBLE("[-0.0]", -0.0);
|
||||
TEST_DOUBLE("[1.0]", 1.0);
|
||||
TEST_DOUBLE("[-1.0]", -1.0);
|
||||
TEST_DOUBLE("[1.5]", 1.5);
|
||||
TEST_DOUBLE("[-1.5]", -1.5);
|
||||
TEST_DOUBLE("[3.1416]", 3.1416);
|
||||
TEST_DOUBLE("[1E10]", 1E10);
|
||||
TEST_DOUBLE("[1e10]", 1e10);
|
||||
TEST_DOUBLE("[1E+10]", 1E+10);
|
||||
TEST_DOUBLE("[1E-10]", 1E-10);
|
||||
TEST_DOUBLE("[-1E10]", -1E10);
|
||||
TEST_DOUBLE("[-1e10]", -1e10);
|
||||
TEST_DOUBLE("[-1E+10]", -1E+10);
|
||||
TEST_DOUBLE("[-1E-10]", -1E-10);
|
||||
TEST_DOUBLE("[1.234E+10]", 1.234E+10);
|
||||
TEST_DOUBLE("[1.234E-10]", 1.234E-10);
|
||||
TEST_DOUBLE("[1.79769e+308]", 1.79769e+308);
|
||||
TEST_DOUBLE("[2.22507e-308]", 2.22507e-308);
|
||||
TEST_DOUBLE("[-1.79769e+308]", -1.79769e+308);
|
||||
TEST_DOUBLE("[-2.22507e-308]", -2.22507e-308);
|
||||
TEST_DOUBLE("[4.9406564584124654e-324]", 4.9406564584124654e-324); // minimum denormal
|
||||
TEST_DOUBLE("[2.2250738585072009e-308]", 2.2250738585072009e-308); // Max subnormal double
|
||||
TEST_DOUBLE("[2.2250738585072014e-308]", 2.2250738585072014e-308); // Min normal positive double
|
||||
TEST_DOUBLE("[1.7976931348623157e+308]", 1.7976931348623157e+308); // Max double
|
||||
TEST_DOUBLE("[1e-10000]", 0.0); // must underflow
|
||||
TEST_DOUBLE("[18446744073709551616]",
|
||||
18446744073709551616.0); // 2^64 (max of uint64_t + 1, force to use double)
|
||||
TEST_DOUBLE("[-9223372036854775809]",
|
||||
-9223372036854775809.0); // -2^63 - 1(min of int64_t + 1, force to use double)
|
||||
TEST_DOUBLE("[0.9868011474609375]",
|
||||
0.9868011474609375); // https://github.com/miloyip/rapidjson/issues/120
|
||||
TEST_DOUBLE("[123e34]", 123e34); // Fast Path Cases In Disguise
|
||||
TEST_DOUBLE("[45913141877270640000.0]", 45913141877270640000.0);
|
||||
TEST_DOUBLE("[2.2250738585072011e-308]",
|
||||
2.2250738585072011e-308);
|
||||
//TEST_DOUBLE("[1e-00011111111111]", 0.0);
|
||||
//TEST_DOUBLE("[-1e-00011111111111]", -0.0);
|
||||
TEST_DOUBLE("[1e-214748363]", 0.0);
|
||||
TEST_DOUBLE("[1e-214748364]", 0.0);
|
||||
//TEST_DOUBLE("[1e-21474836311]", 0.0);
|
||||
TEST_DOUBLE("[0.017976931348623157e+310]", 1.7976931348623157e+308); // Max double in another form
|
||||
|
||||
// Since
|
||||
// abs((2^-1022 - 2^-1074) - 2.2250738585072012e-308) = 3.109754131239141401123495768877590405345064751974375599... ¡Á 10^-324
|
||||
// abs((2^-1022) - 2.2250738585072012e-308) = 1.830902327173324040642192159804623318305533274168872044... ¡Á 10 ^ -324
|
||||
// So 2.2250738585072012e-308 should round to 2^-1022 = 2.2250738585072014e-308
|
||||
TEST_DOUBLE("[2.2250738585072012e-308]",
|
||||
2.2250738585072014e-308);
|
||||
|
||||
// More closer to normal/subnormal boundary
|
||||
// boundary = 2^-1022 - 2^-1075 = 2.225073858507201136057409796709131975934819546351645648... ¡Á 10^-308
|
||||
TEST_DOUBLE("[2.22507385850720113605740979670913197593481954635164564e-308]",
|
||||
2.2250738585072009e-308);
|
||||
TEST_DOUBLE("[2.22507385850720113605740979670913197593481954635164565e-308]",
|
||||
2.2250738585072014e-308);
|
||||
|
||||
// 1.0 is in (1.0 - 2^-54, 1.0 + 2^-53)
|
||||
// 1.0 - 2^-54 = 0.999999999999999944488848768742172978818416595458984375
|
||||
TEST_DOUBLE("[0.999999999999999944488848768742172978818416595458984375]", 1.0); // round to even
|
||||
TEST_DOUBLE("[0.999999999999999944488848768742172978818416595458984374]",
|
||||
0.99999999999999989); // previous double
|
||||
TEST_DOUBLE("[0.999999999999999944488848768742172978818416595458984376]", 1.0); // next double
|
||||
// 1.0 + 2^-53 = 1.00000000000000011102230246251565404236316680908203125
|
||||
TEST_DOUBLE("[1.00000000000000011102230246251565404236316680908203125]", 1.0); // round to even
|
||||
TEST_DOUBLE("[1.00000000000000011102230246251565404236316680908203124]", 1.0); // previous double
|
||||
TEST_DOUBLE("[1.00000000000000011102230246251565404236316680908203126]",
|
||||
1.00000000000000022); // next double
|
||||
|
||||
// Numbers from https://github.com/floitsch/double-conversion/blob/master/test/cctest/test-strtod.cc
|
||||
|
||||
TEST_DOUBLE("[72057594037927928.0]", 72057594037927928.0);
|
||||
TEST_DOUBLE("[72057594037927936.0]", 72057594037927936.0);
|
||||
TEST_DOUBLE("[72057594037927932.0]", 72057594037927936.0);
|
||||
TEST_DOUBLE("[7205759403792793199999e-5]", 72057594037927928.0);
|
||||
TEST_DOUBLE("[7205759403792793200001e-5]", 72057594037927936.0);
|
||||
|
||||
TEST_DOUBLE("[9223372036854774784.0]", 9223372036854774784.0);
|
||||
TEST_DOUBLE("[9223372036854775808.0]", 9223372036854775808.0);
|
||||
TEST_DOUBLE("[9223372036854775296.0]", 9223372036854775808.0);
|
||||
TEST_DOUBLE("[922337203685477529599999e-5]", 9223372036854774784.0);
|
||||
TEST_DOUBLE("[922337203685477529600001e-5]", 9223372036854775808.0);
|
||||
|
||||
TEST_DOUBLE("[10141204801825834086073718800384]", 10141204801825834086073718800384.0);
|
||||
TEST_DOUBLE("[10141204801825835211973625643008]", 10141204801825835211973625643008.0);
|
||||
TEST_DOUBLE("[10141204801825834649023672221696]", 10141204801825835211973625643008.0);
|
||||
TEST_DOUBLE("[1014120480182583464902367222169599999e-5]", 10141204801825834086073718800384.0);
|
||||
TEST_DOUBLE("[1014120480182583464902367222169600001e-5]", 10141204801825835211973625643008.0);
|
||||
|
||||
TEST_DOUBLE("[5708990770823838890407843763683279797179383808]",
|
||||
5708990770823838890407843763683279797179383808.0);
|
||||
TEST_DOUBLE("[5708990770823839524233143877797980545530986496]",
|
||||
5708990770823839524233143877797980545530986496.0);
|
||||
TEST_DOUBLE("[5708990770823839207320493820740630171355185152]",
|
||||
5708990770823839524233143877797980545530986496.0);
|
||||
TEST_DOUBLE("[5708990770823839207320493820740630171355185151999e-3]",
|
||||
5708990770823838890407843763683279797179383808.0);
|
||||
TEST_DOUBLE("[5708990770823839207320493820740630171355185152001e-3]",
|
||||
5708990770823839524233143877797980545530986496.0);
|
||||
|
||||
{
|
||||
char n1e308[312]; // '1' followed by 308 '0'
|
||||
n1e308[0] = '[';
|
||||
n1e308[1] = '1';
|
||||
for (int j = 2; j < 310; j++)
|
||||
{
|
||||
n1e308[j] = '0';
|
||||
}
|
||||
n1e308[310] = ']';
|
||||
n1e308[311] = '\0';
|
||||
TEST_DOUBLE(n1e308, 1E308);
|
||||
}
|
||||
|
||||
// Cover trimming
|
||||
TEST_DOUBLE(
|
||||
"[2.22507385850720113605740979670913197593481954635164564802342610972482222202107694551652952390813508"
|
||||
"7914149158913039621106870086438694594645527657207407820621743379988141063267329253552286881372149012"
|
||||
"9811224514518898490572223072852551331557550159143974763979834118019993239625482890171070818506906306"
|
||||
"6665599493827577257201576306269066333264756530000924588831643303777979186961204949739037782970490505"
|
||||
"1080609940730262937128958950003583799967207254304360284078895771796150945516748243471030702609144621"
|
||||
"5722898802581825451803257070188608721131280795122334262883686223215037756666225039825343359745688844"
|
||||
"2390026549819838548794829220689472168983109969836584681402285424333066033985088644580400103493397042"
|
||||
"7567186443383770486037861622771738545623065874679014086723327636718751234567890123456789012345678901"
|
||||
"e-308]",
|
||||
2.2250738585072014e-308);
|
||||
}
|
||||
|
||||
SECTION("strings")
|
||||
{
|
||||
auto TEST_STRING = [](const std::string & json_string, const std::string & expected)
|
||||
{
|
||||
CAPTURE(json_string);
|
||||
CAPTURE(expected);
|
||||
CHECK(json::parse(json_string)[0].get<std::string>() == expected);
|
||||
};
|
||||
|
||||
TEST_STRING("[\"\"]", "");
|
||||
TEST_STRING("[\"Hello\"]", "Hello");
|
||||
TEST_STRING("[\"Hello\\nWorld\"]", "Hello\nWorld");
|
||||
//TEST_STRING("[\"Hello\\u0000World\"]", "Hello\0World");
|
||||
TEST_STRING("[\"\\\"\\\\/\\b\\f\\n\\r\\t\"]", "\"\\/\b\f\n\r\t");
|
||||
TEST_STRING("[\"\\u0024\"]", "\x24"); // Dollar sign U+0024
|
||||
TEST_STRING("[\"\\u00A2\"]", "\xC2\xA2"); // Cents sign U+00A2
|
||||
TEST_STRING("[\"\\u20AC\"]", "\xE2\x82\xAC"); // Euro sign U+20AC
|
||||
TEST_STRING("[\"\\uD834\\uDD1E\"]", "\xF0\x9D\x84\x9E"); // G clef sign U+1D11E
|
||||
}
|
||||
|
||||
SECTION("roundtrip")
|
||||
{
|
||||
// test cases are from https://github.com/miloyip/nativejson-benchmark/tree/master/test/data/roundtrip
|
||||
|
||||
for (auto filename :
|
||||
{
|
||||
"test/data/json_roundtrip/roundtrip01.json",
|
||||
"test/data/json_roundtrip/roundtrip02.json",
|
||||
"test/data/json_roundtrip/roundtrip03.json",
|
||||
"test/data/json_roundtrip/roundtrip04.json",
|
||||
"test/data/json_roundtrip/roundtrip05.json",
|
||||
"test/data/json_roundtrip/roundtrip06.json",
|
||||
"test/data/json_roundtrip/roundtrip07.json",
|
||||
"test/data/json_roundtrip/roundtrip08.json",
|
||||
"test/data/json_roundtrip/roundtrip09.json",
|
||||
"test/data/json_roundtrip/roundtrip10.json",
|
||||
"test/data/json_roundtrip/roundtrip11.json",
|
||||
"test/data/json_roundtrip/roundtrip12.json",
|
||||
"test/data/json_roundtrip/roundtrip13.json",
|
||||
"test/data/json_roundtrip/roundtrip14.json",
|
||||
"test/data/json_roundtrip/roundtrip15.json",
|
||||
"test/data/json_roundtrip/roundtrip16.json",
|
||||
"test/data/json_roundtrip/roundtrip17.json",
|
||||
"test/data/json_roundtrip/roundtrip18.json",
|
||||
"test/data/json_roundtrip/roundtrip19.json",
|
||||
"test/data/json_roundtrip/roundtrip20.json",
|
||||
"test/data/json_roundtrip/roundtrip21.json",
|
||||
"test/data/json_roundtrip/roundtrip22.json",
|
||||
"test/data/json_roundtrip/roundtrip23.json",
|
||||
//"test/data/json_roundtrip/roundtrip24.json", // roundtrip error
|
||||
//"test/data/json_roundtrip/roundtrip25.json", // roundtrip error
|
||||
//"test/data/json_roundtrip/roundtrip26.json", // roundtrip error
|
||||
//"test/data/json_roundtrip/roundtrip27.json", // roundtrip error
|
||||
//"test/data/json_roundtrip/roundtrip28.json", // roundtrip error
|
||||
"test/data/json_roundtrip/roundtrip29.json",
|
||||
//"test/data/json_roundtrip/roundtrip30.json", // roundtrip error
|
||||
//"test/data/json_roundtrip/roundtrip31.json", // roundtrip error
|
||||
"test/data/json_roundtrip/roundtrip32.json"
|
||||
})
|
||||
{
|
||||
CAPTURE(filename);
|
||||
std::ifstream f(filename);
|
||||
std::string json_string( (std::istreambuf_iterator<char>(f) ),
|
||||
(std::istreambuf_iterator<char>()) );
|
||||
|
||||
json j = json::parse(json_string);
|
||||
CHECK(j.dump() == json_string);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
TEST_CASE("test suite from json-test-suite")
|
||||
{
|
||||
SECTION("read all sample.json")
|
||||
{
|
||||
// read a file with all unicode characters stored as single-character
|
||||
// strings in a JSON array
|
||||
std::ifstream f("test/data/json_testsuite/sample.json");
|
||||
json j;
|
||||
CHECK_NOTHROW(j << f);
|
||||
|
||||
// the array has 3 elements
|
||||
CHECK(j.size() == 3);
|
||||
}
|
||||
}
|
||||
|
||||
TEST_CASE("json.org examples")
|
||||
{
|
||||
// here, we list all JSON values from http://json.org/example
|
||||
|
||||
SECTION("1.json")
|
||||
{
|
||||
std::ifstream f("test/data/json.org/1.json");
|
||||
json j;
|
||||
CHECK_NOTHROW(j << f);
|
||||
}
|
||||
|
||||
SECTION("2.json")
|
||||
{
|
||||
std::ifstream f("test/data/json.org/2.json");
|
||||
json j;
|
||||
CHECK_NOTHROW(j << f);
|
||||
}
|
||||
|
||||
SECTION("3.json")
|
||||
{
|
||||
std::ifstream f("test/data/json.org/3.json");
|
||||
json j;
|
||||
CHECK_NOTHROW(j << f);
|
||||
}
|
||||
|
||||
SECTION("4.json")
|
||||
{
|
||||
std::ifstream f("test/data/json.org/4.json");
|
||||
json j;
|
||||
CHECK_NOTHROW(j << f);
|
||||
}
|
||||
|
||||
SECTION("5.json")
|
||||
{
|
||||
std::ifstream f("test/data/json.org/5.json");
|
||||
json j;
|
||||
CHECK_NOTHROW(j << f);
|
||||
}
|
||||
}
|
||||
|
||||
TEST_CASE("RFC 7159 examples")
|
||||
{
|
||||
// here, we list all JSON values from the RFC 7159 document
|
||||
|
||||
SECTION("7. Strings")
|
||||
{
|
||||
CHECK(json::parse("\"\\u005C\"") == json("\\"));
|
||||
CHECK(json::parse("\"\\uD834\\uDD1E\"") == json("𝄞"));
|
||||
CHECK(json::parse("\"𝄞\"") == json("𝄞"));
|
||||
}
|
||||
|
||||
SECTION("8.3 String Comparison")
|
||||
{
|
||||
CHECK(json::parse("\"a\\b\"") == json::parse("\"a\u005Cb\""));
|
||||
}
|
||||
|
||||
SECTION("13 Examples")
|
||||
{
|
||||
{
|
||||
CHECK_NOTHROW(json(R"(
|
||||
{
|
||||
"Image": {
|
||||
"Width": 800,
|
||||
"Height": 600,
|
||||
"Title": "View from 15th Floor",
|
||||
"Thumbnail": {
|
||||
"Url": "http://www.example.com/image/481989943",
|
||||
"Height": 125,
|
||||
"Width": 100
|
||||
},
|
||||
"Animated" : false,
|
||||
"IDs": [116, 943, 234, 38793]
|
||||
}
|
||||
}
|
||||
)"));
|
||||
}
|
||||
|
||||
{
|
||||
CHECK_NOTHROW(json(R"(
|
||||
[
|
||||
{
|
||||
"precision": "zip",
|
||||
"Latitude": 37.7668,
|
||||
"Longitude": -122.3959,
|
||||
"Address": "",
|
||||
"City": "SAN FRANCISCO",
|
||||
"State": "CA",
|
||||
"Zip": "94107",
|
||||
"Country": "US"
|
||||
},
|
||||
{
|
||||
"precision": "zip",
|
||||
"Latitude": 37.371991,
|
||||
"Longitude": -122.026020,
|
||||
"Address": "",
|
||||
"City": "SUNNYVALE",
|
||||
"State": "CA",
|
||||
"Zip": "94085",
|
||||
"Country": "US"
|
||||
}
|
||||
])"));
|
||||
}
|
||||
|
||||
CHECK(json::parse("\"Hello world!\"") == json("Hello world!"));
|
||||
CHECK(json::parse("42") == json(42));
|
||||
CHECK(json::parse("true") == json(true));
|
||||
}
|
||||
}
|
176
test/src/unit-unicode.cpp
Normal file
176
test/src/unit-unicode.cpp
Normal file
|
@ -0,0 +1,176 @@
|
|||
/*
|
||||
__ _____ _____ _____
|
||||
__| | __| | | | JSON for Modern C++ (test suite)
|
||||
| | |__ | | | | | | version 2.0.2
|
||||
|_____|_____|_____|_|___| https://github.com/nlohmann/json
|
||||
|
||||
Licensed under the MIT License <http://opensource.org/licenses/MIT>.
|
||||
Copyright (c) 2013-2016 Niels Lohmann <http://nlohmann.me>.
|
||||
|
||||
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"
|
||||
|
||||
#define private public
|
||||
#include "json.hpp"
|
||||
using nlohmann::json;
|
||||
|
||||
#include <fstream>
|
||||
|
||||
TEST_CASE("Unicode", "[hide]")
|
||||
{
|
||||
SECTION("full enumeration of Unicode code points")
|
||||
{
|
||||
// create an escaped string from a code point
|
||||
const auto codepoint_to_unicode = [](std::size_t cp)
|
||||
{
|
||||
// copd points are represented as a six-character sequence: a
|
||||
// reverse solidus, followed by the lowercase letter u, followed
|
||||
// by four hexadecimal digits that encode the character's code
|
||||
// point
|
||||
std::stringstream ss;
|
||||
ss << "\\u" << std::setw(4) << std::setfill('0') << std::hex << cp;
|
||||
return ss.str();
|
||||
};
|
||||
|
||||
// generate all UTF-8 code points; in total, 1112064 code points are
|
||||
// generated: 0x1FFFFF code points - 2048 invalid values between
|
||||
// 0xD800 and 0xDFFF.
|
||||
for (std::size_t cp = 0; cp <= 0x10FFFFu; ++cp)
|
||||
{
|
||||
// The Unicode standard permanently reserves these code point
|
||||
// values for UTF-16 encoding of the high and low surrogates, and
|
||||
// they will never be assigned a character, so there should be no
|
||||
// reason to encode them. The official Unicode standard says that
|
||||
// no UTF forms, including UTF-16, can encode these code points.
|
||||
if (cp >= 0xD800u and cp <= 0xDFFFu)
|
||||
{
|
||||
// if we would not skip these code points, we would get a
|
||||
// "missing low surrogate" exception
|
||||
continue;
|
||||
}
|
||||
|
||||
// string to store the code point as in \uxxxx format
|
||||
std::string escaped_string;
|
||||
// string to store the code point as unescaped character sequence
|
||||
std::string unescaped_string;
|
||||
|
||||
if (cp < 0x10000u)
|
||||
{
|
||||
// code points in the Basic Multilingual Plane can be
|
||||
// represented with one \\uxxxx sequence
|
||||
escaped_string = codepoint_to_unicode(cp);
|
||||
|
||||
// All Unicode characters may be placed within the quotation
|
||||
// marks, except for the characters that must be escaped:
|
||||
// quotation mark, reverse solidus, and the control characters
|
||||
// (U+0000 through U+001F); we ignore these code points as
|
||||
// they are checked with codepoint_to_unicode.
|
||||
if (cp > 0x1f and cp != 0x22 and cp != 0x5c)
|
||||
{
|
||||
unescaped_string = json::lexer::to_unicode(cp);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// To escape an extended character that is not in the Basic
|
||||
// Multilingual Plane, the character is represented as a
|
||||
// 12-character sequence, encoding the UTF-16 surrogate pair
|
||||
const auto codepoint1 = 0xd800u + (((cp - 0x10000u) >> 10) & 0x3ffu);
|
||||
const auto codepoint2 = 0xdc00u + ((cp - 0x10000u) & 0x3ffu);
|
||||
escaped_string = codepoint_to_unicode(codepoint1);
|
||||
escaped_string += codepoint_to_unicode(codepoint2);
|
||||
unescaped_string += json::lexer::to_unicode(codepoint1, codepoint2);
|
||||
}
|
||||
|
||||
// all other code points are valid and must not yield parse errors
|
||||
CAPTURE(cp);
|
||||
CAPTURE(escaped_string);
|
||||
CAPTURE(unescaped_string);
|
||||
|
||||
json j1, j2, j3, j4;
|
||||
CHECK_NOTHROW(j1 = json::parse("\"" + escaped_string + "\""));
|
||||
CHECK_NOTHROW(j2 = json::parse(j1.dump()));
|
||||
CHECK(j1 == j2);
|
||||
|
||||
CHECK_NOTHROW(j3 = json::parse("\"" + unescaped_string + "\""));
|
||||
CHECK_NOTHROW(j4 = json::parse(j3.dump()));
|
||||
CHECK(j3 == j4);
|
||||
}
|
||||
}
|
||||
|
||||
SECTION("read all unicode characters")
|
||||
{
|
||||
// read a file with all unicode characters stored as single-character
|
||||
// strings in a JSON array
|
||||
std::ifstream f("test/data/json_nlohmann_tests/all_unicode.json");
|
||||
json j;
|
||||
CHECK_NOTHROW(j << f);
|
||||
|
||||
// the array has 1112064 + 1 elemnts (a terminating "null" value)
|
||||
// Note: 1112064 = 0x1FFFFF code points - 2048 invalid values between
|
||||
// 0xD800 and 0xDFFF.
|
||||
CHECK(j.size() == 1112065);
|
||||
|
||||
SECTION("check JSON Pointers")
|
||||
{
|
||||
for (auto s : j)
|
||||
{
|
||||
// skip non-string JSON values
|
||||
if (not s.is_string())
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
std::string ptr = s;
|
||||
|
||||
// tilde must be followed by 0 or 1
|
||||
if (ptr == "~")
|
||||
{
|
||||
ptr += "0";
|
||||
}
|
||||
|
||||
// JSON Pointers must begin with "/"
|
||||
ptr = "/" + ptr;
|
||||
|
||||
CHECK_NOTHROW(json::json_pointer("/" + ptr));
|
||||
|
||||
// check escape/unescape roundtrip
|
||||
auto escaped = json::json_pointer::escape(ptr);
|
||||
json::json_pointer::unescape(escaped);
|
||||
CHECK(escaped == ptr);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
SECTION("ignore byte-order-mark")
|
||||
{
|
||||
// read a file with a UTF-8 BOM
|
||||
std::ifstream f("test/data/json_nlohmann_tests/bom.json");
|
||||
json j;
|
||||
CHECK_NOTHROW(j << f);
|
||||
}
|
||||
|
||||
SECTION("error for incomplete/wrong BOM")
|
||||
{
|
||||
CHECK_THROWS_AS(json::parse("\xef\xbb"), std::invalid_argument);
|
||||
CHECK_THROWS_AS(json::parse("\xef\xbb\xbb"), std::invalid_argument);
|
||||
}
|
||||
}
|
14379
test/src/unit.cpp
14379
test/src/unit.cpp
File diff suppressed because it is too large
Load diff
Loading…
Reference in a new issue