split test suite in one file per test case

This commit is contained in:
Niels 2016-08-04 21:55:47 +02:00
parent 3944ecd470
commit d80329034e
31 changed files with 15291 additions and 14386 deletions

View file

@ -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
##########################################################################

View file

@ -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

View file

@ -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)

View 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"}));
}
}

View file

@ -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
View 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);
}
}
}
}

View 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());
}
}
}
}

View 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());
}
}
}
}

View 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");
}
}

View 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}));
}
}

View 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
View 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());
}
}
}
}

File diff suppressed because it is too large Load diff

View 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");
}
}

File diff suppressed because it is too large Load diff

View 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}}}));
}
}

File diff suppressed because it is too large Load diff

View 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());
}
}
}

View 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

File diff suppressed because it is too large Load diff

1217
test/src/unit-json_patch.cpp Normal file

File diff suppressed because it is too large Load diff

View 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
View 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");
}
}
}
}

View 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
View 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);
}
}

View 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&>());
}
}

View 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);
}
}

View 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]");
}
}
}

View 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
View 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);
}
}

File diff suppressed because it is too large Load diff