Merge branch 'develop' of https://github.com/nlohmann/json into bon8
Conflicts: docs/examples/to_bon8.cpp docs/examples/to_bon8.output docs/mkdocs/docs/api/basic_json/to_bon8.md include/nlohmann/detail/input/binary_reader.hpp include/nlohmann/detail/input/input_adapters.hpp include/nlohmann/detail/output/binary_writer.hpp single_include/nlohmann/json.hpp test/CMakeLists.txt tests/src/unit-binary_formats.cpp tests/src/unit-bon8.cpp
@@ -0,0 +1,137 @@
|
||||
cmake_minimum_required(VERSION 3.13)
|
||||
|
||||
option(JSON_Valgrind "Execute test suite with Valgrind." OFF)
|
||||
option(JSON_FastTests "Skip expensive/slow tests." OFF)
|
||||
|
||||
set(JSON_TestStandards "" CACHE STRING "The list of standards to test explicitly.")
|
||||
|
||||
include(test)
|
||||
|
||||
#############################################################################
|
||||
# override standard support
|
||||
#############################################################################
|
||||
|
||||
# Clang only supports C++17 starting from Clang 5.0
|
||||
if (CMAKE_CXX_COMPILER_ID STREQUAL "Clang" AND CMAKE_CXX_COMPILER_VERSION VERSION_LESS 5.0)
|
||||
unset(compiler_supports_cpp_17)
|
||||
endif()
|
||||
# MSVC 2015 (14.0) does not support C++17
|
||||
if (CMAKE_CXX_COMPILER_ID STREQUAL "MSVC" AND CMAKE_CXX_COMPILER_VERSION VERSION_LESS 19.1)
|
||||
unset(compiler_supports_cpp_17)
|
||||
endif()
|
||||
|
||||
# Clang C++20 support appears insufficient prior to Clang 9.0 (based on CI build failure)
|
||||
if (CMAKE_CXX_COMPILER_ID STREQUAL "Clang" AND CMAKE_CXX_COMPILER_VERSION VERSION_LESS 9.0)
|
||||
unset(compiler_supports_cpp_20)
|
||||
endif()
|
||||
# GCC started supporting C++20 features in 8.0 but a test for #3070 segfaults prior to 9.0
|
||||
if (CMAKE_CXX_COMPILER_ID STREQUAL "GNU" AND CMAKE_CXX_COMPILER_VERSION VERSION_LESS 9.0)
|
||||
unset(compiler_supports_cpp_20)
|
||||
endif()
|
||||
|
||||
#############################################################################
|
||||
# test_main library with shared code to speed up build and common settings
|
||||
#############################################################################
|
||||
|
||||
add_library(test_main OBJECT src/unit.cpp)
|
||||
target_compile_definitions(test_main PUBLIC
|
||||
DOCTEST_CONFIG_SUPER_FAST_ASSERTS
|
||||
JSON_TEST_KEEP_MACROS
|
||||
)
|
||||
target_compile_features(test_main PRIVATE cxx_std_11)
|
||||
target_compile_options(test_main PUBLIC
|
||||
$<$<CXX_COMPILER_ID:MSVC>:/EHsc;$<$<CONFIG:Release>:/Od>>
|
||||
# MSVC: Force to always compile with W4
|
||||
# Disable warning C4566: character represented by universal-character-name '\uFF01'
|
||||
# cannot be represented in the current code page (1252)
|
||||
# Disable warning C4996: 'nlohmann::basic_json<...>::operator <<': was declared deprecated
|
||||
$<$<CXX_COMPILER_ID:MSVC>:/W4 /wd4566 /wd4996>
|
||||
# https://github.com/nlohmann/json/issues/1114
|
||||
$<$<CXX_COMPILER_ID:MSVC>:/bigobj> $<$<BOOL:${MINGW}>:-Wa,-mbig-obj>
|
||||
|
||||
$<$<NOT:$<CXX_COMPILER_ID:MSVC>>:-Wno-deprecated;-Wno-float-equal>
|
||||
$<$<CXX_COMPILER_ID:GNU>:-Wno-deprecated-declarations>
|
||||
)
|
||||
target_include_directories(test_main PUBLIC
|
||||
thirdparty/doctest
|
||||
thirdparty/fifo_map
|
||||
${PROJECT_BINARY_DIR}/include
|
||||
)
|
||||
target_link_libraries(test_main PUBLIC ${NLOHMANN_JSON_TARGET_NAME})
|
||||
|
||||
#############################################################################
|
||||
# define test- and standard-specific build settings
|
||||
#############################################################################
|
||||
|
||||
if (CMAKE_CXX_COMPILER_ID STREQUAL "GNU"
|
||||
AND CMAKE_CXX_COMPILER_VERSION VERSION_GREATER_EQUAL 8.0
|
||||
AND CMAKE_CXX_COMPILER_VERSION VERSION_LESS 9.0 AND NOT MINGW)
|
||||
# fix for https://gcc.gnu.org/bugzilla/show_bug.cgi?id=90050
|
||||
json_test_set_test_options(all CXX_STANDARDS 17 LINK_LIBRARIES stdc++fs)
|
||||
endif()
|
||||
|
||||
if (CMAKE_CXX_COMPILER_ID STREQUAL "MSVC")
|
||||
# avoid stack overflow, see https://github.com/nlohmann/json/issues/2955
|
||||
json_test_set_test_options("test-cbor;test-msgpack;test-ubjson;test-bjdata" LINK_OPTIONS /STACK:4000000)
|
||||
endif()
|
||||
|
||||
# disable exceptions for test-disabled_exceptions
|
||||
json_test_set_test_options(test-disabled_exceptions COMPILE_DEFINITIONS JSON_NOEXCEPTION)
|
||||
if (CMAKE_CXX_COMPILER_ID STREQUAL "Clang" OR CMAKE_CXX_COMPILER_ID STREQUAL "AppleClang" OR CMAKE_CXX_COMPILER_ID STREQUAL "GNU")
|
||||
json_test_set_test_options(test-disabled_exceptions COMPILE_OPTIONS -fno-exceptions)
|
||||
elseif (CMAKE_CXX_COMPILER_ID STREQUAL "MSVC")
|
||||
# disabled due to https://github.com/nlohmann/json/discussions/2824
|
||||
#json_test_set_test_options(test-disabled_exceptions COMPILE_DEFINITIONS _HAS_EXCEPTIONS=0 COMPILE_OPTIONS /EH)
|
||||
endif()
|
||||
|
||||
#############################################################################
|
||||
# add unit tests
|
||||
#############################################################################
|
||||
|
||||
if("${JSON_TestStandards}" STREQUAL "")
|
||||
set(test_cxx_standards 11 14 17 20 23)
|
||||
unset(test_force)
|
||||
else()
|
||||
set(test_cxx_standards ${JSON_TestStandards})
|
||||
set(test_force FORCE)
|
||||
endif()
|
||||
|
||||
# Print selected standards marking unavailable ones with brackets
|
||||
set(msg_standards "")
|
||||
foreach(cxx_standard ${test_cxx_standards})
|
||||
if(compiler_supports_cpp_${cxx_standard})
|
||||
list(APPEND msg_standards ${cxx_standard})
|
||||
else()
|
||||
list(APPEND msg_standards [${cxx_standard}])
|
||||
endif()
|
||||
endforeach()
|
||||
string(JOIN " " msg_standards ${msg_standards})
|
||||
set(msg "Testing standards: ${msg_standards}")
|
||||
if(test_force)
|
||||
string(APPEND msg " (forced)")
|
||||
endif()
|
||||
message(STATUS "${msg}")
|
||||
|
||||
# *DO* use json_test_set_test_options() above this line
|
||||
|
||||
file(GLOB files src/unit-*.cpp)
|
||||
foreach(file ${files})
|
||||
json_test_add_test_for(${file} MAIN test_main CXX_STANDARDS ${test_cxx_standards} ${test_force})
|
||||
endforeach()
|
||||
|
||||
# *DO NOT* use json_test_set_test_options() below this line
|
||||
|
||||
#############################################################################
|
||||
# Test the generated build configs
|
||||
#############################################################################
|
||||
|
||||
# these tests depend on the generated file nlohmann_jsonConfig.cmake
|
||||
if (JSON_Install)
|
||||
add_subdirectory(cmake_import)
|
||||
add_subdirectory(cmake_import_minver)
|
||||
endif()
|
||||
|
||||
add_subdirectory(cmake_add_subdirectory)
|
||||
add_subdirectory(cmake_fetch_content)
|
||||
add_subdirectory(cmake_fetch_content2)
|
||||
add_subdirectory(cmake_target_include_directories)
|
||||
@@ -0,0 +1,32 @@
|
||||
##############################################################################
|
||||
# OSS-Fuzz
|
||||
##############################################################################
|
||||
|
||||
# The following targets realize the integration to OSS-Fuzz.
|
||||
# See <https://github.com/google/oss-fuzz/blob/master/projects/json/build.sh> for more information.
|
||||
|
||||
# additional flags
|
||||
CXXFLAGS += -std=c++11
|
||||
CPPFLAGS += -I ../single_include
|
||||
|
||||
FUZZER_ENGINE = src/fuzzer-driver_afl.cpp
|
||||
FUZZERS = parse_afl_fuzzer parse_bson_fuzzer parse_cbor_fuzzer parse_msgpack_fuzzer parse_ubjson_fuzzer parse_bjdata_fuzzer
|
||||
fuzzers: $(FUZZERS)
|
||||
|
||||
parse_afl_fuzzer:
|
||||
$(CXX) $(CXXFLAGS) $(CPPFLAGS) $(FUZZER_ENGINE) src/fuzzer-parse_json.cpp -o $@
|
||||
|
||||
parse_bson_fuzzer:
|
||||
$(CXX) $(CXXFLAGS) $(CPPFLAGS) $(FUZZER_ENGINE) src/fuzzer-parse_bson.cpp -o $@
|
||||
|
||||
parse_cbor_fuzzer:
|
||||
$(CXX) $(CXXFLAGS) $(CPPFLAGS) $(FUZZER_ENGINE) src/fuzzer-parse_cbor.cpp -o $@
|
||||
|
||||
parse_msgpack_fuzzer:
|
||||
$(CXX) $(CXXFLAGS) $(CPPFLAGS) $(FUZZER_ENGINE) src/fuzzer-parse_msgpack.cpp -o $@
|
||||
|
||||
parse_ubjson_fuzzer:
|
||||
$(CXX) $(CXXFLAGS) $(CPPFLAGS) $(FUZZER_ENGINE) src/fuzzer-parse_ubjson.cpp -o $@
|
||||
|
||||
parse_bjdata_fuzzer:
|
||||
$(CXX) $(CXXFLAGS) $(CPPFLAGS) $(FUZZER_ENGINE) src/fuzzer-parse_bjdata.cpp -o $@
|
||||
@@ -0,0 +1,34 @@
|
||||
cmake_minimum_required(VERSION 3.11)
|
||||
project(JSON_Benchmarks LANGUAGES CXX)
|
||||
|
||||
# set compiler flags
|
||||
if((CMAKE_CXX_COMPILER_ID MATCHES GNU) OR (CMAKE_CXX_COMPILER_ID MATCHES Clang))
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -flto -DNDEBUG -O3")
|
||||
endif()
|
||||
|
||||
# configure Google Benchmarks
|
||||
include(FetchContent)
|
||||
FetchContent_Declare(
|
||||
benchmark
|
||||
GIT_REPOSITORY https://github.com/google/benchmark.git
|
||||
GIT_TAG origin/main
|
||||
GIT_SHALLOW TRUE
|
||||
)
|
||||
|
||||
FetchContent_GetProperties(benchmark)
|
||||
if(NOT benchmark_POPULATED)
|
||||
FetchContent_Populate(benchmark)
|
||||
set(BENCHMARK_ENABLE_TESTING OFF CACHE INTERNAL "" FORCE)
|
||||
add_subdirectory(${benchmark_SOURCE_DIR} ${benchmark_BINARY_DIR})
|
||||
endif()
|
||||
|
||||
# download test data
|
||||
set(CMAKE_MODULE_PATH ${CMAKE_CURRENT_SOURCE_DIR}/../../cmake ${CMAKE_MODULE_PATH})
|
||||
include(download_test_data)
|
||||
|
||||
# benchmark binary
|
||||
add_executable(json_benchmarks src/benchmarks.cpp)
|
||||
target_compile_features(json_benchmarks PRIVATE cxx_std_11)
|
||||
target_link_libraries(json_benchmarks benchmark ${CMAKE_THREAD_LIBS_INIT})
|
||||
add_dependencies(json_benchmarks download_test_data)
|
||||
target_include_directories(json_benchmarks PRIVATE ${CMAKE_SOURCE_DIR}/../../single_include ${CMAKE_BINARY_DIR}/include)
|
||||
@@ -0,0 +1,110 @@
|
||||
#include "benchmark/benchmark.h"
|
||||
#include <nlohmann/json.hpp>
|
||||
#include <fstream>
|
||||
#include <test_data.hpp>
|
||||
|
||||
using json = nlohmann::json;
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
// parse JSON from file
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
static void ParseFile(benchmark::State& state, const char* filename)
|
||||
{
|
||||
while (state.KeepRunning())
|
||||
{
|
||||
state.PauseTiming();
|
||||
auto* f = new std::ifstream(filename);
|
||||
auto* j = new json();
|
||||
state.ResumeTiming();
|
||||
|
||||
*j = json::parse(*f);
|
||||
|
||||
state.PauseTiming();
|
||||
delete f;
|
||||
delete j;
|
||||
state.ResumeTiming();
|
||||
}
|
||||
|
||||
std::ifstream file(filename, std::ios::binary | std::ios::ate);
|
||||
state.SetBytesProcessed(state.iterations() * file.tellg());
|
||||
}
|
||||
BENCHMARK_CAPTURE(ParseFile, jeopardy, TEST_DATA_DIRECTORY "/jeopardy/jeopardy.json");
|
||||
BENCHMARK_CAPTURE(ParseFile, canada, TEST_DATA_DIRECTORY "/nativejson-benchmark/canada.json");
|
||||
BENCHMARK_CAPTURE(ParseFile, citm_catalog, TEST_DATA_DIRECTORY "/nativejson-benchmark/citm_catalog.json");
|
||||
BENCHMARK_CAPTURE(ParseFile, twitter, TEST_DATA_DIRECTORY "/nativejson-benchmark/twitter.json");
|
||||
BENCHMARK_CAPTURE(ParseFile, floats, TEST_DATA_DIRECTORY "/regression/floats.json");
|
||||
BENCHMARK_CAPTURE(ParseFile, signed_ints, TEST_DATA_DIRECTORY "/regression/signed_ints.json");
|
||||
BENCHMARK_CAPTURE(ParseFile, unsigned_ints, TEST_DATA_DIRECTORY "/regression/unsigned_ints.json");
|
||||
BENCHMARK_CAPTURE(ParseFile, small_signed_ints, TEST_DATA_DIRECTORY "/regression/small_signed_ints.json");
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
// parse JSON from string
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
static void ParseString(benchmark::State& state, const char* filename)
|
||||
{
|
||||
std::ifstream f(filename);
|
||||
std::string str((std::istreambuf_iterator<char>(f)), std::istreambuf_iterator<char>());
|
||||
|
||||
while (state.KeepRunning())
|
||||
{
|
||||
state.PauseTiming();
|
||||
auto* j = new json();
|
||||
state.ResumeTiming();
|
||||
|
||||
*j = json::parse(str);
|
||||
|
||||
state.PauseTiming();
|
||||
delete j;
|
||||
state.ResumeTiming();
|
||||
}
|
||||
|
||||
state.SetBytesProcessed(state.iterations() * str.size());
|
||||
}
|
||||
BENCHMARK_CAPTURE(ParseString, jeopardy, TEST_DATA_DIRECTORY "/jeopardy/jeopardy.json");
|
||||
BENCHMARK_CAPTURE(ParseString, canada, TEST_DATA_DIRECTORY "/nativejson-benchmark/canada.json");
|
||||
BENCHMARK_CAPTURE(ParseString, citm_catalog, TEST_DATA_DIRECTORY "/nativejson-benchmark/citm_catalog.json");
|
||||
BENCHMARK_CAPTURE(ParseString, twitter, TEST_DATA_DIRECTORY "/nativejson-benchmark/twitter.json");
|
||||
BENCHMARK_CAPTURE(ParseString, floats, TEST_DATA_DIRECTORY "/regression/floats.json");
|
||||
BENCHMARK_CAPTURE(ParseString, signed_ints, TEST_DATA_DIRECTORY "/regression/signed_ints.json");
|
||||
BENCHMARK_CAPTURE(ParseString, unsigned_ints, TEST_DATA_DIRECTORY "/regression/unsigned_ints.json");
|
||||
BENCHMARK_CAPTURE(ParseString, small_signed_ints, TEST_DATA_DIRECTORY "/regression/small_signed_ints.json");
|
||||
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
// serialize JSON
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
static void Dump(benchmark::State& state, const char* filename, int indent)
|
||||
{
|
||||
std::ifstream f(filename);
|
||||
std::string str((std::istreambuf_iterator<char>(f)), std::istreambuf_iterator<char>());
|
||||
json j = json::parse(str);
|
||||
|
||||
while (state.KeepRunning())
|
||||
{
|
||||
j.dump(indent);
|
||||
}
|
||||
|
||||
state.SetBytesProcessed(state.iterations() * j.dump(indent).size());
|
||||
}
|
||||
BENCHMARK_CAPTURE(Dump, jeopardy / -, TEST_DATA_DIRECTORY "/jeopardy/jeopardy.json", -1);
|
||||
BENCHMARK_CAPTURE(Dump, jeopardy / 4, TEST_DATA_DIRECTORY "/jeopardy/jeopardy.json", 4);
|
||||
BENCHMARK_CAPTURE(Dump, canada / -, TEST_DATA_DIRECTORY "/nativejson-benchmark/canada.json", -1);
|
||||
BENCHMARK_CAPTURE(Dump, canada / 4, TEST_DATA_DIRECTORY "/nativejson-benchmark/canada.json", 4);
|
||||
BENCHMARK_CAPTURE(Dump, citm_catalog / -, TEST_DATA_DIRECTORY "/nativejson-benchmark/citm_catalog.json", -1);
|
||||
BENCHMARK_CAPTURE(Dump, citm_catalog / 4, TEST_DATA_DIRECTORY "/nativejson-benchmark/citm_catalog.json", 4);
|
||||
BENCHMARK_CAPTURE(Dump, twitter / -, TEST_DATA_DIRECTORY "/nativejson-benchmark/twitter.json", -1);
|
||||
BENCHMARK_CAPTURE(Dump, twitter / 4, TEST_DATA_DIRECTORY "/nativejson-benchmark/twitter.json", 4);
|
||||
BENCHMARK_CAPTURE(Dump, floats / -, TEST_DATA_DIRECTORY "/regression/floats.json", -1);
|
||||
BENCHMARK_CAPTURE(Dump, floats / 4, TEST_DATA_DIRECTORY "/regression/floats.json", 4);
|
||||
BENCHMARK_CAPTURE(Dump, signed_ints / -, TEST_DATA_DIRECTORY "/regression/signed_ints.json", -1);
|
||||
BENCHMARK_CAPTURE(Dump, signed_ints / 4, TEST_DATA_DIRECTORY "/regression/signed_ints.json", 4);
|
||||
BENCHMARK_CAPTURE(Dump, unsigned_ints / -, TEST_DATA_DIRECTORY "/regression/unsigned_ints.json", -1);
|
||||
BENCHMARK_CAPTURE(Dump, unsigned_ints / 4, TEST_DATA_DIRECTORY "/regression/unsigned_ints.json", 4);
|
||||
BENCHMARK_CAPTURE(Dump, small_signed_ints / -, TEST_DATA_DIRECTORY "/regression/small_signed_ints.json", -1);
|
||||
BENCHMARK_CAPTURE(Dump, small_signed_ints / 4, TEST_DATA_DIRECTORY "/regression/small_signed_ints.json", 4);
|
||||
|
||||
|
||||
BENCHMARK_MAIN();
|
||||
@@ -0,0 +1,18 @@
|
||||
add_test(NAME cmake_add_subdirectory_configure
|
||||
COMMAND ${CMAKE_COMMAND}
|
||||
-G "${CMAKE_GENERATOR}"
|
||||
-DCMAKE_CXX_COMPILER=${CMAKE_CXX_COMPILER}
|
||||
-Dnlohmann_json_source=${PROJECT_SOURCE_DIR}
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/project
|
||||
)
|
||||
add_test(NAME cmake_add_subdirectory_build
|
||||
COMMAND ${CMAKE_COMMAND} --build .
|
||||
)
|
||||
set_tests_properties(cmake_add_subdirectory_configure PROPERTIES
|
||||
FIXTURES_SETUP cmake_add_subdirectory
|
||||
LABELS not_reproducible
|
||||
)
|
||||
set_tests_properties(cmake_add_subdirectory_build PROPERTIES
|
||||
FIXTURES_REQUIRED cmake_add_subdirectory
|
||||
LABELS not_reproducible
|
||||
)
|
||||
@@ -0,0 +1,20 @@
|
||||
cmake_minimum_required(VERSION 3.1)
|
||||
|
||||
project(DummyImport CXX)
|
||||
|
||||
set(JSON_BuildTests OFF CACHE INTERNAL "")
|
||||
add_subdirectory(${nlohmann_json_source}
|
||||
${CMAKE_CURRENT_BINARY_DIR}/nlohmann_json)
|
||||
|
||||
add_executable(with_namespace_target main.cpp)
|
||||
target_link_libraries(with_namespace_target nlohmann_json::nlohmann_json)
|
||||
|
||||
add_executable(without_namespace_target main.cpp)
|
||||
target_link_libraries(without_namespace_target nlohmann_json)
|
||||
|
||||
if(NOT MSVC)
|
||||
add_executable(without_exceptions main.cpp)
|
||||
target_link_libraries(without_exceptions nlohmann_json::nlohmann_json)
|
||||
target_compile_definitions(without_exceptions PRIVATE JSON_NOEXCEPTION)
|
||||
target_compile_options(without_exceptions PRIVATE -fno-exceptions)
|
||||
endif()
|
||||
@@ -0,0 +1,8 @@
|
||||
#include <nlohmann/json.hpp>
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
nlohmann::json j;
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
if (${CMAKE_VERSION} VERSION_GREATER "3.11.0")
|
||||
add_test(NAME cmake_fetch_content_configure
|
||||
COMMAND ${CMAKE_COMMAND}
|
||||
-G "${CMAKE_GENERATOR}"
|
||||
-DCMAKE_CXX_COMPILER=${CMAKE_CXX_COMPILER}
|
||||
-Dnlohmann_json_source=${PROJECT_SOURCE_DIR}
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/project
|
||||
)
|
||||
add_test(NAME cmake_fetch_content_build
|
||||
COMMAND ${CMAKE_COMMAND} --build .
|
||||
)
|
||||
set_tests_properties(cmake_fetch_content_configure PROPERTIES
|
||||
FIXTURES_SETUP cmake_fetch_content
|
||||
LABELS "git_required;not_reproducible"
|
||||
)
|
||||
set_tests_properties(cmake_fetch_content_build PROPERTIES
|
||||
FIXTURES_REQUIRED cmake_fetch_content
|
||||
LABELS "git_required;not_reproducible"
|
||||
)
|
||||
endif()
|
||||
@@ -0,0 +1,20 @@
|
||||
cmake_minimum_required(VERSION 3.11)
|
||||
|
||||
project(DummyImport CXX)
|
||||
|
||||
include(FetchContent)
|
||||
|
||||
get_filename_component(GIT_REPOSITORY_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/../../.. ABSOLUTE)
|
||||
FetchContent_Declare(json GIT_REPOSITORY ${GIT_REPOSITORY_DIRECTORY} GIT_TAG HEAD)
|
||||
|
||||
FetchContent_GetProperties(json)
|
||||
if(NOT json_POPULATED)
|
||||
FetchContent_Populate(json)
|
||||
add_subdirectory(${json_SOURCE_DIR} ${json_BINARY_DIR} EXCLUDE_FROM_ALL)
|
||||
endif()
|
||||
|
||||
add_executable(with_namespace_target main.cpp)
|
||||
target_link_libraries(with_namespace_target nlohmann_json::nlohmann_json)
|
||||
|
||||
add_executable(without_namespace_target main.cpp)
|
||||
target_link_libraries(without_namespace_target nlohmann_json)
|
||||
@@ -0,0 +1,8 @@
|
||||
#include <nlohmann/json.hpp>
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
nlohmann::json j;
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
if (${CMAKE_VERSION} VERSION_GREATER "3.14.0")
|
||||
add_test(NAME cmake_fetch_content2_configure
|
||||
COMMAND ${CMAKE_COMMAND}
|
||||
-G "${CMAKE_GENERATOR}"
|
||||
-DCMAKE_CXX_COMPILER=${CMAKE_CXX_COMPILER}
|
||||
-Dnlohmann_json_source=${PROJECT_SOURCE_DIR}
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/project
|
||||
)
|
||||
add_test(NAME cmake_fetch_content2_build
|
||||
COMMAND ${CMAKE_COMMAND} --build .
|
||||
)
|
||||
set_tests_properties(cmake_fetch_content2_configure PROPERTIES
|
||||
FIXTURES_SETUP cmake_fetch_content2
|
||||
LABELS "git_required;not_reproducible"
|
||||
)
|
||||
set_tests_properties(cmake_fetch_content2_build PROPERTIES
|
||||
FIXTURES_REQUIRED cmake_fetch_content2
|
||||
LABELS "git_required;not_reproducible"
|
||||
)
|
||||
endif()
|
||||
@@ -0,0 +1,15 @@
|
||||
cmake_minimum_required(VERSION 3.14)
|
||||
|
||||
project(DummyImport CXX)
|
||||
|
||||
include(FetchContent)
|
||||
|
||||
get_filename_component(GIT_REPOSITORY_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/../../.. ABSOLUTE)
|
||||
FetchContent_Declare(json GIT_REPOSITORY ${GIT_REPOSITORY_DIRECTORY} GIT_TAG HEAD)
|
||||
FetchContent_MakeAvailable(json)
|
||||
|
||||
add_executable(with_namespace_target main.cpp)
|
||||
target_link_libraries(with_namespace_target nlohmann_json::nlohmann_json)
|
||||
|
||||
add_executable(without_namespace_target main.cpp)
|
||||
target_link_libraries(without_namespace_target nlohmann_json)
|
||||
@@ -0,0 +1,8 @@
|
||||
#include <nlohmann/json.hpp>
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
nlohmann::json j;
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
add_test(NAME cmake_import_configure
|
||||
COMMAND ${CMAKE_COMMAND}
|
||||
-G "${CMAKE_GENERATOR}"
|
||||
-A "${CMAKE_GENERATOR_PLATFORM}"
|
||||
-DCMAKE_CXX_COMPILER=${CMAKE_CXX_COMPILER}
|
||||
-Dnlohmann_json_DIR=${PROJECT_BINARY_DIR}
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/project
|
||||
)
|
||||
add_test(NAME cmake_import_build
|
||||
COMMAND ${CMAKE_COMMAND} --build .
|
||||
)
|
||||
set_tests_properties(cmake_import_configure PROPERTIES
|
||||
FIXTURES_SETUP cmake_import
|
||||
LABELS not_reproducible
|
||||
)
|
||||
set_tests_properties(cmake_import_build PROPERTIES
|
||||
FIXTURES_REQUIRED cmake_import
|
||||
LABELS not_reproducible
|
||||
)
|
||||
@@ -0,0 +1,12 @@
|
||||
cmake_minimum_required(VERSION 3.1)
|
||||
|
||||
project(DummyImport CXX)
|
||||
|
||||
find_package(nlohmann_json REQUIRED)
|
||||
|
||||
add_executable(with_namespace_target main.cpp)
|
||||
target_link_libraries(with_namespace_target nlohmann_json::nlohmann_json)
|
||||
|
||||
add_executable(without_namespace_target main.cpp)
|
||||
target_link_libraries(without_namespace_target nlohmann_json)
|
||||
|
||||
@@ -0,0 +1,8 @@
|
||||
#include <nlohmann/json.hpp>
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
nlohmann::json j;
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
add_test(NAME cmake_import_minver_configure
|
||||
COMMAND ${CMAKE_COMMAND}
|
||||
-G "${CMAKE_GENERATOR}"
|
||||
-A "${CMAKE_GENERATOR_PLATFORM}"
|
||||
-DCMAKE_CXX_COMPILER=${CMAKE_CXX_COMPILER}
|
||||
-Dnlohmann_json_DIR=${PROJECT_BINARY_DIR}
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/project
|
||||
)
|
||||
add_test(NAME cmake_import_minver_build
|
||||
COMMAND ${CMAKE_COMMAND} --build .
|
||||
)
|
||||
set_tests_properties(cmake_import_minver_configure PROPERTIES
|
||||
FIXTURES_SETUP cmake_import_minver
|
||||
LABELS not_reproducible
|
||||
)
|
||||
set_tests_properties(cmake_import_minver_build PROPERTIES
|
||||
FIXTURES_REQUIRED cmake_import_minver
|
||||
LABELS not_reproducible
|
||||
)
|
||||
@@ -0,0 +1,8 @@
|
||||
cmake_minimum_required(VERSION 3.1)
|
||||
|
||||
project(DummyImportMinVer CXX)
|
||||
|
||||
find_package(nlohmann_json 3.2.0 REQUIRED)
|
||||
|
||||
add_executable(with_namespace_target main.cpp)
|
||||
target_link_libraries(with_namespace_target nlohmann_json::nlohmann_json)
|
||||
@@ -0,0 +1,8 @@
|
||||
#include <nlohmann/json.hpp>
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
nlohmann::json j;
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
add_test(NAME cmake_target_include_directories_configure
|
||||
COMMAND ${CMAKE_COMMAND}
|
||||
-G "${CMAKE_GENERATOR}"
|
||||
-DCMAKE_CXX_COMPILER=${CMAKE_CXX_COMPILER}
|
||||
-Dnlohmann_json_source=${PROJECT_SOURCE_DIR}
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/project
|
||||
)
|
||||
add_test(NAME cmake_target_include_directories_build
|
||||
COMMAND ${CMAKE_COMMAND} --build .
|
||||
)
|
||||
set_tests_properties(cmake_target_include_directories_configure PROPERTIES
|
||||
FIXTURES_SETUP cmake_target_include_directories
|
||||
LABELS not_reproducible
|
||||
)
|
||||
set_tests_properties(cmake_target_include_directories_build PROPERTIES
|
||||
FIXTURES_REQUIRED cmake_target_include_directories
|
||||
LABELS not_reproducible
|
||||
)
|
||||
@@ -0,0 +1,3 @@
|
||||
#include "Bar.hpp"
|
||||
|
||||
class Bar;
|
||||
@@ -0,0 +1,4 @@
|
||||
#include <nlohmann/json.hpp>
|
||||
#include "Foo.hpp"
|
||||
|
||||
class Bar : public Foo{};
|
||||
@@ -0,0 +1,21 @@
|
||||
cmake_minimum_required(VERSION 3.1)
|
||||
|
||||
project(DummyImport CXX)
|
||||
|
||||
add_executable(with_private_target main.cpp)
|
||||
target_include_directories(with_private_target PRIVATE ${nlohmann_json_source}/include)
|
||||
set_target_properties(with_private_target PROPERTIES CXX_STANDARD 11)
|
||||
|
||||
add_executable(with_private_system_target main.cpp)
|
||||
target_include_directories(with_private_system_target PRIVATE SYSTEM ${nlohmann_json_source}/include)
|
||||
set_target_properties(with_private_system_target PROPERTIES CXX_STANDARD 11)
|
||||
|
||||
# regression from https://github.com/nlohmann/json/discussions/2281
|
||||
add_library(Foo STATIC Foo.cpp Bar.cpp)
|
||||
target_include_directories(Foo PUBLIC ${CMAKE_CURRENT_SOURCE_DIR} ${nlohmann_json_source}/include)
|
||||
set_target_properties(Foo PROPERTIES CXX_STANDARD 11)
|
||||
|
||||
add_library(Bar STATIC Bar.cpp)
|
||||
target_link_libraries(Bar PRIVATE Foo)
|
||||
target_include_directories(Bar PUBLIC ${CMAKE_CURRENT_SOURCE_DIR} ${nlohmann_json_source}/include)
|
||||
set_target_properties(Bar PROPERTIES CXX_STANDARD 11)
|
||||
@@ -0,0 +1,3 @@
|
||||
#include "Foo.hpp"
|
||||
|
||||
class Foo;
|
||||
@@ -0,0 +1,4 @@
|
||||
#pragma once
|
||||
#include <nlohmann/json.hpp>
|
||||
|
||||
class Foo{};
|
||||
@@ -0,0 +1,8 @@
|
||||
#include <nlohmann/json.hpp>
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
nlohmann::json j;
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
cmake_minimum_required(VERSION 3.18)
|
||||
project(json_cuda LANGUAGES CUDA)
|
||||
|
||||
add_executable(json_cuda json_cuda.cu)
|
||||
target_include_directories(json_cuda PRIVATE ../../include)
|
||||
target_compile_features(json_cuda PUBLIC cuda_std_11)
|
||||
set_target_properties(json_cuda PROPERTIES
|
||||
CUDA_EXTENSIONS OFF
|
||||
CUDA_STANDARD_REQUIRED ON
|
||||
)
|
||||
@@ -0,0 +1,11 @@
|
||||
#include <nlohmann/json.hpp>
|
||||
|
||||
int main()
|
||||
{
|
||||
nlohmann::ordered_json json = {"Test"};
|
||||
json.dump();
|
||||
|
||||
// regression for #3013 (ordered_json::reset() compile error with nvcc)
|
||||
nlohmann::ordered_json metadata;
|
||||
metadata.erase("key");
|
||||
}
|
||||
|
After Width: | Height: | Size: 28 KiB |
|
After Width: | Height: | Size: 26 KiB |
@@ -0,0 +1,10 @@
|
||||
<table style="font-family: 'Trebuchet MS', 'Tahoma', 'Arial', 'Helvetica'">
|
||||
<tr><td style="width: 18ex"><b>Banner:</b></td><td>fuzz</td></tr>
|
||||
<tr><td><b>Directory:</b></td><td>fuzz-testing/out</td></tr>
|
||||
<tr><td><b>Generated on:</b></td><td>Mo 29 Aug 2016 22:14:22 CEST</td></tr>
|
||||
</table>
|
||||
<p>
|
||||
<img src="high_freq.png" width=1000 height=300><p>
|
||||
<img src="low_freq.png" width=1000 height=200><p>
|
||||
<img src="exec_speed.png" width=1000 height=200>
|
||||
|
||||
|
After Width: | Height: | Size: 12 KiB |
@@ -0,0 +1,31 @@
|
||||
Results of the latest benchmark from <https://github.com/miloyip/nativejson-benchmark>.
|
||||
|
||||
See <https://github.com/nlohmann/json/issues/307> for discussion.
|
||||
|
||||
Original post at 2016-09-09 to <json@yahoogroups.com>:
|
||||
|
||||
> Hi,
|
||||
>
|
||||
> This benchmark evaluated conformance, parse/stringify speed/memory, and
|
||||
> code size. It can also be viewed as a long list of open source C/C++ JSON
|
||||
> libraries.
|
||||
>
|
||||
> You can run the benchmark on your own machine by checkout this project.
|
||||
>
|
||||
> https://github.com/miloyip/nativejson-benchmark
|
||||
>
|
||||
> You can also view some sample results here:
|
||||
>
|
||||
> https://rawgit.com/miloyip/nativejson-benchmark/master/sample/conformance.html
|
||||
> https://rawgit.com/miloyip/nativejson-benchmark/master/sample/performance_Corei7-4980HQ@2.80GHz_mac64_clang7.0.html
|
||||
>
|
||||
> If you make a new library, you may use this for testing conformance and
|
||||
> performance. Afterwards, please submit a pull request.
|
||||
>
|
||||
> Enjoy!
|
||||
>
|
||||
> --
|
||||
> Milo Yip
|
||||
>
|
||||
> https://github.com/miloyip/
|
||||
> http://twitter.com/miloyip/
|
||||
@@ -0,0 +1,670 @@
|
||||
|
||||
|
||||
|
||||
|
||||
<!DOCTYPE html>
|
||||
<html lang="en" class="">
|
||||
<head prefix="og: http://ogp.me/ns# fb: http://ogp.me/ns/fb# object: http://ogp.me/ns/object# article: http://ogp.me/ns/article# profile: http://ogp.me/ns/profile#">
|
||||
<meta charset='utf-8'>
|
||||
|
||||
|
||||
<link crossorigin="anonymous" href="https://assets-cdn.github.com/assets/frameworks-3a71f36dec04358c4f2f42280fb2cf5c38856f935a3f609eab0a1ae31b1d635a.css" media="all" rel="stylesheet" />
|
||||
<link crossorigin="anonymous" href="https://assets-cdn.github.com/assets/github-5c885e880e980dc7f119393287b84906d930ccaff83f6bff8ae2c086b87ca4d8.css" media="all" rel="stylesheet" />
|
||||
|
||||
|
||||
<link crossorigin="anonymous" href="https://assets-cdn.github.com/assets/site-4ef7bbe907458c89cb1f7f5c5e6c4cd87e03acf66b1817325e644920d2a83330.css" media="all" rel="stylesheet" />
|
||||
|
||||
|
||||
<link as="script" href="https://assets-cdn.github.com/assets/frameworks-88471af1fec40ff9418efbe2ddd15b6896af8d772f8179004c254dffc25ea490.js" rel="preload" />
|
||||
|
||||
<link as="script" href="https://assets-cdn.github.com/assets/github-e18e11a943ff2eb9394c72d4ec8b76592c454915b5839ae177d422777a046e29.js" rel="preload" />
|
||||
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
||||
<meta http-equiv="Content-Language" content="en">
|
||||
<meta name="viewport" content="width=device-width">
|
||||
|
||||
<title>nativejson-benchmark/conformance_Nlohmann (C++11).md at master · miloyip/nativejson-benchmark · GitHub</title>
|
||||
<link rel="search" type="application/opensearchdescription+xml" href="/opensearch.xml" title="GitHub">
|
||||
<link rel="fluid-icon" href="https://github.com/fluidicon.png" title="GitHub">
|
||||
<link rel="apple-touch-icon" href="/apple-touch-icon.png">
|
||||
<link rel="apple-touch-icon" sizes="57x57" href="/apple-touch-icon-57x57.png">
|
||||
<link rel="apple-touch-icon" sizes="60x60" href="/apple-touch-icon-60x60.png">
|
||||
<link rel="apple-touch-icon" sizes="72x72" href="/apple-touch-icon-72x72.png">
|
||||
<link rel="apple-touch-icon" sizes="76x76" href="/apple-touch-icon-76x76.png">
|
||||
<link rel="apple-touch-icon" sizes="114x114" href="/apple-touch-icon-114x114.png">
|
||||
<link rel="apple-touch-icon" sizes="120x120" href="/apple-touch-icon-120x120.png">
|
||||
<link rel="apple-touch-icon" sizes="144x144" href="/apple-touch-icon-144x144.png">
|
||||
<link rel="apple-touch-icon" sizes="152x152" href="/apple-touch-icon-152x152.png">
|
||||
<link rel="apple-touch-icon" sizes="180x180" href="/apple-touch-icon-180x180.png">
|
||||
<meta property="fb:app_id" content="1401488693436528">
|
||||
|
||||
<meta content="https://avatars2.githubusercontent.com/u/1195774?v=3&s=400" name="twitter:image:src" /><meta content="@github" name="twitter:site" /><meta content="summary" name="twitter:card" /><meta content="miloyip/nativejson-benchmark" name="twitter:title" /><meta content="nativejson-benchmark - C/C++ JSON parser/generator benchmark" name="twitter:description" />
|
||||
<meta content="https://avatars2.githubusercontent.com/u/1195774?v=3&s=400" property="og:image" /><meta content="GitHub" property="og:site_name" /><meta content="object" property="og:type" /><meta content="miloyip/nativejson-benchmark" property="og:title" /><meta content="https://github.com/miloyip/nativejson-benchmark" property="og:url" /><meta content="nativejson-benchmark - C/C++ JSON parser/generator benchmark" property="og:description" />
|
||||
<meta name="browser-stats-url" content="https://api.github.com/_private/browser/stats">
|
||||
<meta name="browser-errors-url" content="https://api.github.com/_private/browser/errors">
|
||||
<link rel="assets" href="https://assets-cdn.github.com/">
|
||||
|
||||
<meta name="pjax-timeout" content="1000">
|
||||
|
||||
<meta name="request-id" content="D4563DA7:75ED:525C921:57D6FEBB" data-pjax-transient>
|
||||
|
||||
<meta name="msapplication-TileImage" content="/windows-tile.png">
|
||||
<meta name="msapplication-TileColor" content="#ffffff">
|
||||
<meta name="selected-link" value="repo_source" data-pjax-transient>
|
||||
|
||||
<meta name="google-site-verification" content="KT5gs8h0wvaagLKAVWq8bbeNwnZZK1r1XQysX3xurLU">
|
||||
<meta name="google-site-verification" content="ZzhVyEFwb7w3e0-uOTltm8Jsck2F5StVihD0exw2fsA">
|
||||
<meta name="google-analytics" content="UA-3769691-2">
|
||||
|
||||
<meta content="collector.githubapp.com" name="octolytics-host" /><meta content="github" name="octolytics-app-id" /><meta content="D4563DA7:75ED:525C921:57D6FEBB" name="octolytics-dimension-request_id" />
|
||||
<meta content="/<user-name>/<repo-name>/blob/show" data-pjax-transient="true" name="analytics-location" />
|
||||
|
||||
|
||||
|
||||
<meta class="js-ga-set" name="dimension1" content="Logged Out">
|
||||
|
||||
|
||||
|
||||
<meta name="hostname" content="github.com">
|
||||
<meta name="user-login" content="">
|
||||
|
||||
<meta name="expected-hostname" content="github.com">
|
||||
<meta name="js-proxy-site-detection-payload" content="N2RkMmY1ZjE1MTA4MzRhYTA5NDNkMjliNDU3OTA3ZTdlMGNmNDZjN2QyODBiZjM3MmYzMjFjNzY1ZjIwNjY4NHx7InJlbW90ZV9hZGRyZXNzIjoiMjEyLjg2LjYxLjE2NyIsInJlcXVlc3RfaWQiOiJENDU2M0RBNzo3NUVEOjUyNUM5MjE6NTdENkZFQkIiLCJ0aW1lc3RhbXAiOjE0NzM3MDc3MDh9">
|
||||
|
||||
|
||||
<link rel="mask-icon" href="https://assets-cdn.github.com/pinned-octocat.svg" color="#4078c0">
|
||||
<link rel="icon" type="image/x-icon" href="https://assets-cdn.github.com/favicon.ico">
|
||||
|
||||
<meta name="html-safe-nonce" content="deea0f406df2fb95709865c5ee80a255d8c47fa9">
|
||||
<meta content="736eea9d74cf34fe850d2180e8a5f0a1cc7bc0be" name="form-nonce" />
|
||||
|
||||
<meta http-equiv="x-pjax-version" content="f302977937abe3fe1c9a4d4bed913565">
|
||||
|
||||
|
||||
|
||||
<meta name="description" content="nativejson-benchmark - C/C++ JSON parser/generator benchmark">
|
||||
<meta name="go-import" content="github.com/miloyip/nativejson-benchmark git https://github.com/miloyip/nativejson-benchmark.git">
|
||||
|
||||
<meta content="1195774" name="octolytics-dimension-user_id" /><meta content="miloyip" name="octolytics-dimension-user_login" /><meta content="22976798" name="octolytics-dimension-repository_id" /><meta content="miloyip/nativejson-benchmark" name="octolytics-dimension-repository_nwo" /><meta content="true" name="octolytics-dimension-repository_public" /><meta content="false" name="octolytics-dimension-repository_is_fork" /><meta content="22976798" name="octolytics-dimension-repository_network_root_id" /><meta content="miloyip/nativejson-benchmark" name="octolytics-dimension-repository_network_root_nwo" />
|
||||
<link href="https://github.com/miloyip/nativejson-benchmark/commits/master.atom" rel="alternate" title="Recent Commits to nativejson-benchmark:master" type="application/atom+xml">
|
||||
|
||||
|
||||
<link rel="canonical" href="https://github.com/miloyip/nativejson-benchmark/blob/master/sample/conformance_Nlohmann%20(C%2B%2B11).md" data-pjax-transient>
|
||||
</head>
|
||||
|
||||
|
||||
<body class="logged-out env-production vis-public page-blob">
|
||||
<div id="js-pjax-loader-bar" class="pjax-loader-bar"><div class="progress"></div></div>
|
||||
<a href="#start-of-content" tabindex="1" class="accessibility-aid js-skip-to-content">Skip to content</a>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<header class="site-header js-details-container" role="banner">
|
||||
<div class="container-responsive">
|
||||
<a class="header-logo-invertocat" href="https://github.com/" aria-label="Homepage" data-ga-click="(Logged out) Header, go to homepage, icon:logo-wordmark">
|
||||
<svg aria-hidden="true" class="octicon octicon-mark-github" height="32" version="1.1" viewBox="0 0 16 16" width="32"><path d="M8 0C3.58 0 0 3.58 0 8c0 3.54 2.29 6.53 5.47 7.59.4.07.55-.17.55-.38 0-.19-.01-.82-.01-1.49-2.01.37-2.53-.49-2.69-.94-.09-.23-.48-.94-.82-1.13-.28-.15-.68-.52-.01-.53.63-.01 1.08.58 1.23.82.72 1.21 1.87.87 2.33.66.07-.52.28-.87.51-1.07-1.78-.2-3.64-.89-3.64-3.95 0-.87.31-1.59.82-2.15-.08-.2-.36-1.02.08-2.12 0 0 .67-.21 2.2.82.64-.18 1.32-.27 2-.27.68 0 1.36.09 2 .27 1.53-1.04 2.2-.82 2.2-.82.44 1.1.16 1.92.08 2.12.51.56.82 1.27.82 2.15 0 3.07-1.87 3.75-3.65 3.95.29.25.54.73.54 1.48 0 1.07-.01 1.93-.01 2.2 0 .21.15.46.55.38A8.013 8.013 0 0 0 16 8c0-4.42-3.58-8-8-8z"></path></svg>
|
||||
</a>
|
||||
|
||||
<button class="btn-link float-right site-header-toggle js-details-target" type="button" aria-label="Toggle navigation">
|
||||
<svg aria-hidden="true" class="octicon octicon-three-bars" height="24" version="1.1" viewBox="0 0 12 16" width="18"><path d="M11.41 9H.59C0 9 0 8.59 0 8c0-.59 0-1 .59-1H11.4c.59 0 .59.41.59 1 0 .59 0 1-.59 1h.01zm0-4H.59C0 5 0 4.59 0 4c0-.59 0-1 .59-1H11.4c.59 0 .59.41.59 1 0 .59 0 1-.59 1h.01zM.59 11H11.4c.59 0 .59.41.59 1 0 .59 0 1-.59 1H.59C0 13 0 12.59 0 12c0-.59 0-1 .59-1z"></path></svg>
|
||||
</button>
|
||||
|
||||
<div class="site-header-menu">
|
||||
<nav class="site-header-nav site-header-nav-main">
|
||||
<a href="/personal" class="js-selected-navigation-item nav-item nav-item-personal" data-ga-click="Header, click, Nav menu - item:personal" data-selected-links="/personal /personal">
|
||||
Personal
|
||||
</a> <a href="/open-source" class="js-selected-navigation-item nav-item nav-item-opensource" data-ga-click="Header, click, Nav menu - item:opensource" data-selected-links="/open-source /open-source">
|
||||
Open source
|
||||
</a> <a href="/business" class="js-selected-navigation-item nav-item nav-item-business" data-ga-click="Header, click, Nav menu - item:business" data-selected-links="/business /business/partners /business/features /business/customers /business">
|
||||
Business
|
||||
</a> <a href="/explore" class="js-selected-navigation-item nav-item nav-item-explore" data-ga-click="Header, click, Nav menu - item:explore" data-selected-links="/explore /trending /trending/developers /integrations /integrations/feature/code /integrations/feature/collaborate /integrations/feature/ship /explore">
|
||||
Explore
|
||||
</a> </nav>
|
||||
|
||||
<div class="site-header-actions">
|
||||
<a class="btn btn-primary site-header-actions-btn" href="/join?source=header-repo" data-ga-click="(Logged out) Header, clicked Sign up, text:sign-up">Sign up</a>
|
||||
<a class="btn site-header-actions-btn mr-2" href="/login?return_to=%2Fmiloyip%2Fnativejson-benchmark%2Fblob%2Fmaster%2Fsample%2Fconformance_Nlohmann%2520%28C%252B%252B11%29.md" data-ga-click="(Logged out) Header, clicked Sign in, text:sign-in">Sign in</a>
|
||||
</div>
|
||||
|
||||
<nav class="site-header-nav site-header-nav-secondary">
|
||||
<a class="nav-item" href="/pricing">Pricing</a>
|
||||
<a class="nav-item" href="/blog">Blog</a>
|
||||
<a class="nav-item" href="https://help.github.com">Support</a>
|
||||
<a class="nav-item header-search-link" href="https://github.com/search">Search GitHub</a>
|
||||
<div class="header-search scoped-search site-scoped-search js-site-search" role="search">
|
||||
<!-- </textarea> --><!-- '"` --><form accept-charset="UTF-8" action="/miloyip/nativejson-benchmark/search" class="js-site-search-form" data-scoped-search-url="/miloyip/nativejson-benchmark/search" data-unscoped-search-url="/search" method="get"><div style="margin:0;padding:0;display:inline"><input name="utf8" type="hidden" value="✓" /></div>
|
||||
<label class="form-control header-search-wrapper js-chromeless-input-container">
|
||||
<div class="header-search-scope">This repository</div>
|
||||
<input type="text"
|
||||
class="form-control header-search-input js-site-search-focus js-site-search-field is-clearable"
|
||||
data-hotkey="s"
|
||||
name="q"
|
||||
placeholder="Search"
|
||||
aria-label="Search this repository"
|
||||
data-unscoped-placeholder="Search GitHub"
|
||||
data-scoped-placeholder="Search"
|
||||
autocapitalize="off">
|
||||
</label>
|
||||
</form></div>
|
||||
|
||||
</nav>
|
||||
</div>
|
||||
</div>
|
||||
</header>
|
||||
|
||||
|
||||
|
||||
<div id="start-of-content" class="accessibility-aid"></div>
|
||||
|
||||
<div id="js-flash-container">
|
||||
</div>
|
||||
|
||||
|
||||
<div role="main">
|
||||
<div itemscope itemtype="http://schema.org/SoftwareSourceCode">
|
||||
<div id="js-repo-pjax-container" data-pjax-container>
|
||||
|
||||
<div class="pagehead repohead instapaper_ignore readability-menu experiment-repo-nav">
|
||||
<div class="container repohead-details-container">
|
||||
|
||||
|
||||
|
||||
<ul class="pagehead-actions">
|
||||
|
||||
<li>
|
||||
<a href="/login?return_to=%2Fmiloyip%2Fnativejson-benchmark"
|
||||
class="btn btn-sm btn-with-count tooltipped tooltipped-n"
|
||||
aria-label="You must be signed in to watch a repository" rel="nofollow">
|
||||
<svg aria-hidden="true" class="octicon octicon-eye" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path d="M8.06 2C3 2 0 8 0 8s3 6 8.06 6C13 14 16 8 16 8s-3-6-7.94-6zM8 12c-2.2 0-4-1.78-4-4 0-2.2 1.8-4 4-4 2.22 0 4 1.8 4 4 0 2.22-1.78 4-4 4zm2-4c0 1.11-.89 2-2 2-1.11 0-2-.89-2-2 0-1.11.89-2 2-2 1.11 0 2 .89 2 2z"></path></svg>
|
||||
Watch
|
||||
</a>
|
||||
<a class="social-count" href="/miloyip/nativejson-benchmark/watchers"
|
||||
aria-label="40 users are watching this repository">
|
||||
40
|
||||
</a>
|
||||
|
||||
</li>
|
||||
|
||||
<li>
|
||||
<a href="/login?return_to=%2Fmiloyip%2Fnativejson-benchmark"
|
||||
class="btn btn-sm btn-with-count tooltipped tooltipped-n"
|
||||
aria-label="You must be signed in to star a repository" rel="nofollow">
|
||||
<svg aria-hidden="true" class="octicon octicon-star" height="16" version="1.1" viewBox="0 0 14 16" width="14"><path d="M14 6l-4.9-.64L7 1 4.9 5.36 0 6l3.6 3.26L2.67 14 7 11.67 11.33 14l-.93-4.74z"></path></svg>
|
||||
Star
|
||||
</a>
|
||||
|
||||
<a class="social-count js-social-count" href="/miloyip/nativejson-benchmark/stargazers"
|
||||
aria-label="352 users starred this repository">
|
||||
352
|
||||
</a>
|
||||
|
||||
</li>
|
||||
|
||||
<li>
|
||||
<a href="/login?return_to=%2Fmiloyip%2Fnativejson-benchmark"
|
||||
class="btn btn-sm btn-with-count tooltipped tooltipped-n"
|
||||
aria-label="You must be signed in to fork a repository" rel="nofollow">
|
||||
<svg aria-hidden="true" class="octicon octicon-repo-forked" height="16" version="1.1" viewBox="0 0 10 16" width="10"><path d="M8 1a1.993 1.993 0 0 0-1 3.72V6L5 8 3 6V4.72A1.993 1.993 0 0 0 2 1a1.993 1.993 0 0 0-1 3.72V6.5l3 3v1.78A1.993 1.993 0 0 0 5 15a1.993 1.993 0 0 0 1-3.72V9.5l3-3V4.72A1.993 1.993 0 0 0 8 1zM2 4.2C1.34 4.2.8 3.65.8 3c0-.65.55-1.2 1.2-1.2.65 0 1.2.55 1.2 1.2 0 .65-.55 1.2-1.2 1.2zm3 10c-.66 0-1.2-.55-1.2-1.2 0-.65.55-1.2 1.2-1.2.65 0 1.2.55 1.2 1.2 0 .65-.55 1.2-1.2 1.2zm3-10c-.66 0-1.2-.55-1.2-1.2 0-.65.55-1.2 1.2-1.2.65 0 1.2.55 1.2 1.2 0 .65-.55 1.2-1.2 1.2z"></path></svg>
|
||||
Fork
|
||||
</a>
|
||||
|
||||
<a href="/miloyip/nativejson-benchmark/network" class="social-count"
|
||||
aria-label="59 users are forked this repository">
|
||||
59
|
||||
</a>
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
<h1 class="public ">
|
||||
<svg aria-hidden="true" class="octicon octicon-repo" height="16" version="1.1" viewBox="0 0 12 16" width="12"><path d="M4 9H3V8h1v1zm0-3H3v1h1V6zm0-2H3v1h1V4zm0-2H3v1h1V2zm8-1v12c0 .55-.45 1-1 1H6v2l-1.5-1.5L3 16v-2H1c-.55 0-1-.45-1-1V1c0-.55.45-1 1-1h10c.55 0 1 .45 1 1zm-1 10H1v2h2v-1h3v1h5v-2zm0-10H2v9h9V1z"></path></svg>
|
||||
<span class="author" itemprop="author"><a href="/miloyip" class="url fn" rel="author">miloyip</a></span><!--
|
||||
--><span class="path-divider">/</span><!--
|
||||
--><strong itemprop="name"><a href="/miloyip/nativejson-benchmark" data-pjax="#js-repo-pjax-container">nativejson-benchmark</a></strong>
|
||||
|
||||
</h1>
|
||||
|
||||
</div>
|
||||
<div class="container">
|
||||
|
||||
<nav class="reponav js-repo-nav js-sidenav-container-pjax"
|
||||
itemscope
|
||||
itemtype="http://schema.org/BreadcrumbList"
|
||||
role="navigation"
|
||||
data-pjax="#js-repo-pjax-container">
|
||||
|
||||
<span itemscope itemtype="http://schema.org/ListItem" itemprop="itemListElement">
|
||||
<a href="/miloyip/nativejson-benchmark" aria-selected="true" class="js-selected-navigation-item selected reponav-item" data-hotkey="g c" data-selected-links="repo_source repo_downloads repo_commits repo_releases repo_tags repo_branches /miloyip/nativejson-benchmark" itemprop="url">
|
||||
<svg aria-hidden="true" class="octicon octicon-code" height="16" version="1.1" viewBox="0 0 14 16" width="14"><path d="M9.5 3L8 4.5 11.5 8 8 11.5 9.5 13 14 8 9.5 3zm-5 0L0 8l4.5 5L6 11.5 2.5 8 6 4.5 4.5 3z"></path></svg>
|
||||
<span itemprop="name">Code</span>
|
||||
<meta itemprop="position" content="1">
|
||||
</a> </span>
|
||||
|
||||
<span itemscope itemtype="http://schema.org/ListItem" itemprop="itemListElement">
|
||||
<a href="/miloyip/nativejson-benchmark/issues" class="js-selected-navigation-item reponav-item" data-hotkey="g i" data-selected-links="repo_issues repo_labels repo_milestones /miloyip/nativejson-benchmark/issues" itemprop="url">
|
||||
<svg aria-hidden="true" class="octicon octicon-issue-opened" height="16" version="1.1" viewBox="0 0 14 16" width="14"><path d="M7 2.3c3.14 0 5.7 2.56 5.7 5.7s-2.56 5.7-5.7 5.7A5.71 5.71 0 0 1 1.3 8c0-3.14 2.56-5.7 5.7-5.7zM7 1C3.14 1 0 4.14 0 8s3.14 7 7 7 7-3.14 7-7-3.14-7-7-7zm1 3H6v5h2V4zm0 6H6v2h2v-2z"></path></svg>
|
||||
<span itemprop="name">Issues</span>
|
||||
<span class="counter">8</span>
|
||||
<meta itemprop="position" content="2">
|
||||
</a> </span>
|
||||
|
||||
<span itemscope itemtype="http://schema.org/ListItem" itemprop="itemListElement">
|
||||
<a href="/miloyip/nativejson-benchmark/pulls" class="js-selected-navigation-item reponav-item" data-hotkey="g p" data-selected-links="repo_pulls /miloyip/nativejson-benchmark/pulls" itemprop="url">
|
||||
<svg aria-hidden="true" class="octicon octicon-git-pull-request" height="16" version="1.1" viewBox="0 0 12 16" width="12"><path d="M11 11.28V5c-.03-.78-.34-1.47-.94-2.06C9.46 2.35 8.78 2.03 8 2H7V0L4 3l3 3V4h1c.27.02.48.11.69.31.21.2.3.42.31.69v6.28A1.993 1.993 0 0 0 10 15a1.993 1.993 0 0 0 1-3.72zm-1 2.92c-.66 0-1.2-.55-1.2-1.2 0-.65.55-1.2 1.2-1.2.65 0 1.2.55 1.2 1.2 0 .65-.55 1.2-1.2 1.2zM4 3c0-1.11-.89-2-2-2a1.993 1.993 0 0 0-1 3.72v6.56A1.993 1.993 0 0 0 2 15a1.993 1.993 0 0 0 1-3.72V4.72c.59-.34 1-.98 1-1.72zm-.8 10c0 .66-.55 1.2-1.2 1.2-.65 0-1.2-.55-1.2-1.2 0-.65.55-1.2 1.2-1.2.65 0 1.2.55 1.2 1.2zM2 4.2C1.34 4.2.8 3.65.8 3c0-.65.55-1.2 1.2-1.2.65 0 1.2.55 1.2 1.2 0 .65-.55 1.2-1.2 1.2z"></path></svg>
|
||||
<span itemprop="name">Pull requests</span>
|
||||
<span class="counter">1</span>
|
||||
<meta itemprop="position" content="3">
|
||||
</a> </span>
|
||||
|
||||
|
||||
|
||||
|
||||
<a href="/miloyip/nativejson-benchmark/pulse" class="js-selected-navigation-item reponav-item" data-selected-links="pulse /miloyip/nativejson-benchmark/pulse">
|
||||
<svg aria-hidden="true" class="octicon octicon-pulse" height="16" version="1.1" viewBox="0 0 14 16" width="14"><path d="M11.5 8L8.8 5.4 6.6 8.5 5.5 1.6 2.38 8H0v2h3.6l.9-1.8.9 5.4L9 8.5l1.6 1.5H14V8z"></path></svg>
|
||||
Pulse
|
||||
</a>
|
||||
<a href="/miloyip/nativejson-benchmark/graphs" class="js-selected-navigation-item reponav-item" data-selected-links="repo_graphs repo_contributors /miloyip/nativejson-benchmark/graphs">
|
||||
<svg aria-hidden="true" class="octicon octicon-graph" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path d="M16 14v1H0V0h1v14h15zM5 13H3V8h2v5zm4 0H7V3h2v10zm4 0h-2V6h2v7z"></path></svg>
|
||||
Graphs
|
||||
</a>
|
||||
|
||||
</nav>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="container new-discussion-timeline experiment-repo-nav">
|
||||
<div class="repository-content">
|
||||
|
||||
|
||||
|
||||
<a href="/miloyip/nativejson-benchmark/blob/95f27ebcf9a96c7ca4cee26467ed5420140090fb/sample/conformance_Nlohmann%20(C%2B%2B11).md" class="d-none js-permalink-shortcut" data-hotkey="y">Permalink</a>
|
||||
|
||||
<!-- blob contrib key: blob_contributors:v21:0bf9e3593dedd91db6c9dc69e13b7f95 -->
|
||||
|
||||
<div class="file-navigation js-zeroclipboard-container">
|
||||
|
||||
<div class="select-menu branch-select-menu js-menu-container js-select-menu float-left">
|
||||
<button class="btn btn-sm select-menu-button js-menu-target css-truncate" data-hotkey="w"
|
||||
|
||||
type="button" aria-label="Switch branches or tags" tabindex="0" aria-haspopup="true">
|
||||
<i>Branch:</i>
|
||||
<span class="js-select-button css-truncate-target">master</span>
|
||||
</button>
|
||||
|
||||
<div class="select-menu-modal-holder js-menu-content js-navigation-container" data-pjax aria-hidden="true">
|
||||
|
||||
<div class="select-menu-modal">
|
||||
<div class="select-menu-header">
|
||||
<svg aria-label="Close" class="octicon octicon-x js-menu-close" height="16" role="img" version="1.1" viewBox="0 0 12 16" width="12"><path d="M7.48 8l3.75 3.75-1.48 1.48L6 9.48l-3.75 3.75-1.48-1.48L4.52 8 .77 4.25l1.48-1.48L6 6.52l3.75-3.75 1.48 1.48z"></path></svg>
|
||||
<span class="select-menu-title">Switch branches/tags</span>
|
||||
</div>
|
||||
|
||||
<div class="select-menu-filters">
|
||||
<div class="select-menu-text-filter">
|
||||
<input type="text" aria-label="Filter branches/tags" id="context-commitish-filter-field" class="form-control js-filterable-field js-navigation-enable" placeholder="Filter branches/tags">
|
||||
</div>
|
||||
<div class="select-menu-tabs">
|
||||
<ul>
|
||||
<li class="select-menu-tab">
|
||||
<a href="#" data-tab-filter="branches" data-filter-placeholder="Filter branches/tags" class="js-select-menu-tab" role="tab">Branches</a>
|
||||
</li>
|
||||
<li class="select-menu-tab">
|
||||
<a href="#" data-tab-filter="tags" data-filter-placeholder="Find a tag…" class="js-select-menu-tab" role="tab">Tags</a>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="select-menu-list select-menu-tab-bucket js-select-menu-tab-bucket" data-tab-filter="branches" role="menu">
|
||||
|
||||
<div data-filterable-for="context-commitish-filter-field" data-filterable-type="substring">
|
||||
|
||||
|
||||
<a class="select-menu-item js-navigation-item js-navigation-open "
|
||||
href="/miloyip/nativejson-benchmark/blob/Stixjson/sample/conformance_Nlohmann%20(C++11).md"
|
||||
data-name="Stixjson"
|
||||
data-skip-pjax="true"
|
||||
rel="nofollow">
|
||||
<svg aria-hidden="true" class="octicon octicon-check select-menu-item-icon" height="16" version="1.1" viewBox="0 0 12 16" width="12"><path d="M12 5l-8 8-4-4 1.5-1.5L4 10l6.5-6.5z"></path></svg>
|
||||
<span class="select-menu-item-text css-truncate-target js-select-menu-filter-text">
|
||||
Stixjson
|
||||
</span>
|
||||
</a>
|
||||
<a class="select-menu-item js-navigation-item js-navigation-open "
|
||||
href="/miloyip/nativejson-benchmark/blob/ccan/sample/conformance_Nlohmann%20(C++11).md"
|
||||
data-name="ccan"
|
||||
data-skip-pjax="true"
|
||||
rel="nofollow">
|
||||
<svg aria-hidden="true" class="octicon octicon-check select-menu-item-icon" height="16" version="1.1" viewBox="0 0 12 16" width="12"><path d="M12 5l-8 8-4-4 1.5-1.5L4 10l6.5-6.5z"></path></svg>
|
||||
<span class="select-menu-item-text css-truncate-target js-select-menu-filter-text">
|
||||
ccan
|
||||
</span>
|
||||
</a>
|
||||
<a class="select-menu-item js-navigation-item js-navigation-open "
|
||||
href="/miloyip/nativejson-benchmark/blob/jbson/sample/conformance_Nlohmann%20(C++11).md"
|
||||
data-name="jbson"
|
||||
data-skip-pjax="true"
|
||||
rel="nofollow">
|
||||
<svg aria-hidden="true" class="octicon octicon-check select-menu-item-icon" height="16" version="1.1" viewBox="0 0 12 16" width="12"><path d="M12 5l-8 8-4-4 1.5-1.5L4 10l6.5-6.5z"></path></svg>
|
||||
<span class="select-menu-item-text css-truncate-target js-select-menu-filter-text">
|
||||
jbson
|
||||
</span>
|
||||
</a>
|
||||
<a class="select-menu-item js-navigation-item js-navigation-open "
|
||||
href="/miloyip/nativejson-benchmark/blob/jute/sample/conformance_Nlohmann%20(C++11).md"
|
||||
data-name="jute"
|
||||
data-skip-pjax="true"
|
||||
rel="nofollow">
|
||||
<svg aria-hidden="true" class="octicon octicon-check select-menu-item-icon" height="16" version="1.1" viewBox="0 0 12 16" width="12"><path d="M12 5l-8 8-4-4 1.5-1.5L4 10l6.5-6.5z"></path></svg>
|
||||
<span class="select-menu-item-text css-truncate-target js-select-menu-filter-text">
|
||||
jute
|
||||
</span>
|
||||
</a>
|
||||
<a class="select-menu-item js-navigation-item js-navigation-open "
|
||||
href="/miloyip/nativejson-benchmark/blob/lastjson/sample/conformance_Nlohmann%20(C++11).md"
|
||||
data-name="lastjson"
|
||||
data-skip-pjax="true"
|
||||
rel="nofollow">
|
||||
<svg aria-hidden="true" class="octicon octicon-check select-menu-item-icon" height="16" version="1.1" viewBox="0 0 12 16" width="12"><path d="M12 5l-8 8-4-4 1.5-1.5L4 10l6.5-6.5z"></path></svg>
|
||||
<span class="select-menu-item-text css-truncate-target js-select-menu-filter-text">
|
||||
lastjson
|
||||
</span>
|
||||
</a>
|
||||
<a class="select-menu-item js-navigation-item js-navigation-open "
|
||||
href="/miloyip/nativejson-benchmark/blob/libjson/sample/conformance_Nlohmann%20(C++11).md"
|
||||
data-name="libjson"
|
||||
data-skip-pjax="true"
|
||||
rel="nofollow">
|
||||
<svg aria-hidden="true" class="octicon octicon-check select-menu-item-icon" height="16" version="1.1" viewBox="0 0 12 16" width="12"><path d="M12 5l-8 8-4-4 1.5-1.5L4 10l6.5-6.5z"></path></svg>
|
||||
<span class="select-menu-item-text css-truncate-target js-select-menu-filter-text">
|
||||
libjson
|
||||
</span>
|
||||
</a>
|
||||
<a class="select-menu-item js-navigation-item js-navigation-open selected"
|
||||
href="/miloyip/nativejson-benchmark/blob/master/sample/conformance_Nlohmann%20(C++11).md"
|
||||
data-name="master"
|
||||
data-skip-pjax="true"
|
||||
rel="nofollow">
|
||||
<svg aria-hidden="true" class="octicon octicon-check select-menu-item-icon" height="16" version="1.1" viewBox="0 0 12 16" width="12"><path d="M12 5l-8 8-4-4 1.5-1.5L4 10l6.5-6.5z"></path></svg>
|
||||
<span class="select-menu-item-text css-truncate-target js-select-menu-filter-text">
|
||||
master
|
||||
</span>
|
||||
</a>
|
||||
<a class="select-menu-item js-navigation-item js-navigation-open "
|
||||
href="/miloyip/nativejson-benchmark/blob/qt/sample/conformance_Nlohmann%20(C++11).md"
|
||||
data-name="qt"
|
||||
data-skip-pjax="true"
|
||||
rel="nofollow">
|
||||
<svg aria-hidden="true" class="octicon octicon-check select-menu-item-icon" height="16" version="1.1" viewBox="0 0 12 16" width="12"><path d="M12 5l-8 8-4-4 1.5-1.5L4 10l6.5-6.5z"></path></svg>
|
||||
<span class="select-menu-item-text css-truncate-target js-select-menu-filter-text">
|
||||
qt
|
||||
</span>
|
||||
</a>
|
||||
<a class="select-menu-item js-navigation-item js-navigation-open "
|
||||
href="/miloyip/nativejson-benchmark/blob/tunnuz/sample/conformance_Nlohmann%20(C++11).md"
|
||||
data-name="tunnuz"
|
||||
data-skip-pjax="true"
|
||||
rel="nofollow">
|
||||
<svg aria-hidden="true" class="octicon octicon-check select-menu-item-icon" height="16" version="1.1" viewBox="0 0 12 16" width="12"><path d="M12 5l-8 8-4-4 1.5-1.5L4 10l6.5-6.5z"></path></svg>
|
||||
<span class="select-menu-item-text css-truncate-target js-select-menu-filter-text">
|
||||
tunnuz
|
||||
</span>
|
||||
</a>
|
||||
<a class="select-menu-item js-navigation-item js-navigation-open "
|
||||
href="/miloyip/nativejson-benchmark/blob/ujson/sample/conformance_Nlohmann%20(C++11).md"
|
||||
data-name="ujson"
|
||||
data-skip-pjax="true"
|
||||
rel="nofollow">
|
||||
<svg aria-hidden="true" class="octicon octicon-check select-menu-item-icon" height="16" version="1.1" viewBox="0 0 12 16" width="12"><path d="M12 5l-8 8-4-4 1.5-1.5L4 10l6.5-6.5z"></path></svg>
|
||||
<span class="select-menu-item-text css-truncate-target js-select-menu-filter-text">
|
||||
ujson
|
||||
</span>
|
||||
</a>
|
||||
</div>
|
||||
|
||||
<div class="select-menu-no-results">Nothing to show</div>
|
||||
</div>
|
||||
|
||||
<div class="select-menu-list select-menu-tab-bucket js-select-menu-tab-bucket" data-tab-filter="tags">
|
||||
<div data-filterable-for="context-commitish-filter-field" data-filterable-type="substring">
|
||||
|
||||
|
||||
<a class="select-menu-item js-navigation-item js-navigation-open "
|
||||
href="/miloyip/nativejson-benchmark/tree/v1.0.0/sample/conformance_Nlohmann%20(C%2B%2B11).md"
|
||||
data-name="v1.0.0"
|
||||
data-skip-pjax="true"
|
||||
rel="nofollow">
|
||||
<svg aria-hidden="true" class="octicon octicon-check select-menu-item-icon" height="16" version="1.1" viewBox="0 0 12 16" width="12"><path d="M12 5l-8 8-4-4 1.5-1.5L4 10l6.5-6.5z"></path></svg>
|
||||
<span class="select-menu-item-text css-truncate-target" title="v1.0.0">
|
||||
v1.0.0
|
||||
</span>
|
||||
</a>
|
||||
</div>
|
||||
|
||||
<div class="select-menu-no-results">Nothing to show</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="btn-group float-right">
|
||||
<a href="/miloyip/nativejson-benchmark/find/master"
|
||||
class="js-pjax-capture-input btn btn-sm"
|
||||
data-pjax
|
||||
data-hotkey="t">
|
||||
Find file
|
||||
</a>
|
||||
<button aria-label="Copy file path to clipboard" class="js-zeroclipboard btn btn-sm zeroclipboard-button tooltipped tooltipped-s" data-copied-hint="Copied!" type="button">Copy path</button>
|
||||
</div>
|
||||
<div class="breadcrumb js-zeroclipboard-target">
|
||||
<span class="repo-root js-repo-root"><span class="js-path-segment"><a href="/miloyip/nativejson-benchmark"><span>nativejson-benchmark</span></a></span></span><span class="separator">/</span><span class="js-path-segment"><a href="/miloyip/nativejson-benchmark/tree/master/sample"><span>sample</span></a></span><span class="separator">/</span><strong class="final-path">conformance_Nlohmann (C++11).md</strong>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
<div class="commit-tease">
|
||||
<span class="float-right">
|
||||
<a class="commit-tease-sha" href="/miloyip/nativejson-benchmark/commit/a4a9f10f41c515d6abb0f019ab9f5d021ed4bb9e" data-pjax>
|
||||
a4a9f10
|
||||
</a>
|
||||
<relative-time datetime="2016-09-09T03:15:21Z">Sep 9, 2016</relative-time>
|
||||
</span>
|
||||
<div>
|
||||
<img alt="@miloyip" class="avatar" height="20" src="https://avatars3.githubusercontent.com/u/1195774?v=3&s=40" width="20" />
|
||||
<a href="/miloyip" class="user-mention" rel="author">miloyip</a>
|
||||
<a href="/miloyip/nativejson-benchmark/commit/a4a9f10f41c515d6abb0f019ab9f5d021ed4bb9e" class="message" data-pjax="true" title="Update sample result for 41 libraries
|
||||
|
||||
Fixed #43">Update sample result for 41 libraries</a>
|
||||
</div>
|
||||
|
||||
<div class="commit-tease-contributors">
|
||||
<button type="button" class="btn-link muted-link contributors-toggle" data-facebox="#blob_contributors_box">
|
||||
<strong>1</strong>
|
||||
contributor
|
||||
</button>
|
||||
|
||||
</div>
|
||||
|
||||
<div id="blob_contributors_box" style="display:none">
|
||||
<h2 class="facebox-header" data-facebox-id="facebox-header">Users who have contributed to this file</h2>
|
||||
<ul class="facebox-user-list" data-facebox-id="facebox-description">
|
||||
<li class="facebox-user-list-item">
|
||||
<img alt="@miloyip" height="24" src="https://avatars1.githubusercontent.com/u/1195774?v=3&s=48" width="24" />
|
||||
<a href="/miloyip">miloyip</a>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="file">
|
||||
<div class="file-header">
|
||||
<div class="file-actions">
|
||||
|
||||
<div class="btn-group">
|
||||
<a href="/miloyip/nativejson-benchmark/raw/master/sample/conformance_Nlohmann%20(C%2B%2B11).md" class="btn btn-sm " id="raw-url">Raw</a>
|
||||
<a href="/miloyip/nativejson-benchmark/blame/master/sample/conformance_Nlohmann%20(C%2B%2B11).md" class="btn btn-sm js-update-url-with-hash">Blame</a>
|
||||
<a href="/miloyip/nativejson-benchmark/commits/master/sample/conformance_Nlohmann%20(C%2B%2B11).md" class="btn btn-sm " rel="nofollow">History</a>
|
||||
</div>
|
||||
|
||||
|
||||
<button type="button" class="btn-octicon disabled tooltipped tooltipped-nw"
|
||||
aria-label="You must be signed in to make or propose changes">
|
||||
<svg aria-hidden="true" class="octicon octicon-pencil" height="16" version="1.1" viewBox="0 0 14 16" width="14"><path d="M0 12v3h3l8-8-3-3-8 8zm3 2H1v-2h1v1h1v1zm10.3-9.3L12 6 9 3l1.3-1.3a.996.996 0 0 1 1.41 0l1.59 1.59c.39.39.39 1.02 0 1.41z"></path></svg>
|
||||
</button>
|
||||
<button type="button" class="btn-octicon btn-octicon-danger disabled tooltipped tooltipped-nw"
|
||||
aria-label="You must be signed in to make or propose changes">
|
||||
<svg aria-hidden="true" class="octicon octicon-trashcan" height="16" version="1.1" viewBox="0 0 12 16" width="12"><path d="M11 2H9c0-.55-.45-1-1-1H5c-.55 0-1 .45-1 1H2c-.55 0-1 .45-1 1v1c0 .55.45 1 1 1v9c0 .55.45 1 1 1h7c.55 0 1-.45 1-1V5c.55 0 1-.45 1-1V3c0-.55-.45-1-1-1zm-1 12H3V5h1v8h1V5h1v8h1V5h1v8h1V5h1v9zm1-10H2V3h9v1z"></path></svg>
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<div class="file-info">
|
||||
59 lines (37 sloc)
|
||||
<span class="file-info-divider"></span>
|
||||
545 Bytes
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
<div id="readme" class="readme blob instapaper_body">
|
||||
<article class="markdown-body entry-content" itemprop="text"><h1><a id="user-content-conformance-of-nlohmann-c11" class="anchor" href="#conformance-of-nlohmann-c11" aria-hidden="true"><svg aria-hidden="true" class="octicon octicon-link" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>Conformance of Nlohmann (C++11)</h1>
|
||||
|
||||
<h2><a id="user-content-1-parse-validation" class="anchor" href="#1-parse-validation" aria-hidden="true"><svg aria-hidden="true" class="octicon octicon-link" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>1. Parse Validation</h2>
|
||||
|
||||
<p>Summary: 34 of 34 are correct.</p>
|
||||
|
||||
<h2><a id="user-content-2-parse-double" class="anchor" href="#2-parse-double" aria-hidden="true"><svg aria-hidden="true" class="octicon octicon-link" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>2. Parse Double</h2>
|
||||
|
||||
<p>Summary: 66 of 66 are correct.</p>
|
||||
|
||||
<h2><a id="user-content-3-parse-string" class="anchor" href="#3-parse-string" aria-hidden="true"><svg aria-hidden="true" class="octicon octicon-link" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>3. Parse String</h2>
|
||||
|
||||
<p>Summary: 9 of 9 are correct.</p>
|
||||
|
||||
<h2><a id="user-content-4-roundtrip" class="anchor" href="#4-roundtrip" aria-hidden="true"><svg aria-hidden="true" class="octicon octicon-link" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>4. Roundtrip</h2>
|
||||
|
||||
<ul>
|
||||
<li>Fail:</li>
|
||||
</ul>
|
||||
|
||||
<div class="highlight highlight-source-js"><pre>[<span class="pl-c1">5e-324</span>]</pre></div>
|
||||
|
||||
<div class="highlight highlight-source-js"><pre>[<span class="pl-c1">4.94065645841247e-324</span>]</pre></div>
|
||||
|
||||
<ul>
|
||||
<li>Fail:</li>
|
||||
</ul>
|
||||
|
||||
<div class="highlight highlight-source-js"><pre>[<span class="pl-c1">2.225073858507201e-308</span>]</pre></div>
|
||||
|
||||
<div class="highlight highlight-source-js"><pre>[<span class="pl-c1">2.2250738585072e-308</span>]</pre></div>
|
||||
|
||||
<ul>
|
||||
<li>Fail:</li>
|
||||
</ul>
|
||||
|
||||
<div class="highlight highlight-source-js"><pre>[<span class="pl-c1">2.2250738585072014e-308</span>]</pre></div>
|
||||
|
||||
<div class="highlight highlight-source-js"><pre>[<span class="pl-c1">2.2250738585072e-308</span>]</pre></div>
|
||||
|
||||
<ul>
|
||||
<li>Fail:</li>
|
||||
</ul>
|
||||
|
||||
<div class="highlight highlight-source-js"><pre>[<span class="pl-c1">1.7976931348623157e308</span>]</pre></div>
|
||||
|
||||
<div class="highlight highlight-source-js"><pre>[<span class="pl-c1">1.79769313486232e+308</span>]</pre></div>
|
||||
|
||||
<p>Summary: 23 of 27 are correct.</p>
|
||||
</article>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
<button type="button" data-facebox="#jump-to-line" data-facebox-class="linejump" data-hotkey="l" class="d-none">Jump to Line</button>
|
||||
<div id="jump-to-line" style="display:none">
|
||||
<!-- </textarea> --><!-- '"` --><form accept-charset="UTF-8" action="" class="js-jump-to-line-form" method="get"><div style="margin:0;padding:0;display:inline"><input name="utf8" type="hidden" value="✓" /></div>
|
||||
<input class="form-control linejump-input js-jump-to-line-field" type="text" placeholder="Jump to line…" aria-label="Jump to line" autofocus>
|
||||
<button type="submit" class="btn">Go</button>
|
||||
</form></div>
|
||||
|
||||
</div>
|
||||
<div class="modal-backdrop js-touch-events"></div>
|
||||
</div>
|
||||
|
||||
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
<div class="container site-footer-container">
|
||||
<div class="site-footer" role="contentinfo">
|
||||
<ul class="site-footer-links float-right">
|
||||
<li><a href="https://github.com/contact" data-ga-click="Footer, go to contact, text:contact">Contact GitHub</a></li>
|
||||
<li><a href="https://developer.github.com" data-ga-click="Footer, go to api, text:api">API</a></li>
|
||||
<li><a href="https://training.github.com" data-ga-click="Footer, go to training, text:training">Training</a></li>
|
||||
<li><a href="https://shop.github.com" data-ga-click="Footer, go to shop, text:shop">Shop</a></li>
|
||||
<li><a href="https://github.com/blog" data-ga-click="Footer, go to blog, text:blog">Blog</a></li>
|
||||
<li><a href="https://github.com/about" data-ga-click="Footer, go to about, text:about">About</a></li>
|
||||
|
||||
</ul>
|
||||
|
||||
<a href="https://github.com" aria-label="Homepage" class="site-footer-mark" title="GitHub">
|
||||
<svg aria-hidden="true" class="octicon octicon-mark-github" height="24" version="1.1" viewBox="0 0 16 16" width="24"><path d="M8 0C3.58 0 0 3.58 0 8c0 3.54 2.29 6.53 5.47 7.59.4.07.55-.17.55-.38 0-.19-.01-.82-.01-1.49-2.01.37-2.53-.49-2.69-.94-.09-.23-.48-.94-.82-1.13-.28-.15-.68-.52-.01-.53.63-.01 1.08.58 1.23.82.72 1.21 1.87.87 2.33.66.07-.52.28-.87.51-1.07-1.78-.2-3.64-.89-3.64-3.95 0-.87.31-1.59.82-2.15-.08-.2-.36-1.02.08-2.12 0 0 .67-.21 2.2.82.64-.18 1.32-.27 2-.27.68 0 1.36.09 2 .27 1.53-1.04 2.2-.82 2.2-.82.44 1.1.16 1.92.08 2.12.51.56.82 1.27.82 2.15 0 3.07-1.87 3.75-3.65 3.95.29.25.54.73.54 1.48 0 1.07-.01 1.93-.01 2.2 0 .21.15.46.55.38A8.013 8.013 0 0 0 16 8c0-4.42-3.58-8-8-8z"></path></svg>
|
||||
</a>
|
||||
<ul class="site-footer-links">
|
||||
<li>© 2016 <span title="0.18611s from github-fe151-cp1-prd.iad.github.net">GitHub</span>, Inc.</li>
|
||||
<li><a href="https://github.com/site/terms" data-ga-click="Footer, go to terms, text:terms">Terms</a></li>
|
||||
<li><a href="https://github.com/site/privacy" data-ga-click="Footer, go to privacy, text:privacy">Privacy</a></li>
|
||||
<li><a href="https://github.com/security" data-ga-click="Footer, go to security, text:security">Security</a></li>
|
||||
<li><a href="https://status.github.com/" data-ga-click="Footer, go to status, text:status">Status</a></li>
|
||||
<li><a href="https://help.github.com" data-ga-click="Footer, go to help, text:help">Help</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<div id="ajax-error-message" class="ajax-error-message flash flash-error">
|
||||
<svg aria-hidden="true" class="octicon octicon-alert" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path d="M8.865 1.52c-.18-.31-.51-.5-.87-.5s-.69.19-.87.5L.275 13.5c-.18.31-.18.69 0 1 .19.31.52.5.87.5h13.7c.36 0 .69-.19.86-.5.17-.31.18-.69.01-1L8.865 1.52zM8.995 13h-2v-2h2v2zm0-3h-2V6h2v4z"></path></svg>
|
||||
<button type="button" class="flash-close js-flash-close js-ajax-error-dismiss" aria-label="Dismiss error">
|
||||
<svg aria-hidden="true" class="octicon octicon-x" height="16" version="1.1" viewBox="0 0 12 16" width="12"><path d="M7.48 8l3.75 3.75-1.48 1.48L6 9.48l-3.75 3.75-1.48-1.48L4.52 8 .77 4.25l1.48-1.48L6 6.52l3.75-3.75 1.48 1.48z"></path></svg>
|
||||
</button>
|
||||
You can't perform that action at this time.
|
||||
</div>
|
||||
|
||||
|
||||
<script crossorigin="anonymous" src="https://assets-cdn.github.com/assets/compat-40e365359d1c4db1e36a55be458e60f2b7c24d58b5a00ae13398480e7ba768e0.js"></script>
|
||||
<script crossorigin="anonymous" src="https://assets-cdn.github.com/assets/frameworks-88471af1fec40ff9418efbe2ddd15b6896af8d772f8179004c254dffc25ea490.js"></script>
|
||||
<script async="async" crossorigin="anonymous" src="https://assets-cdn.github.com/assets/github-e18e11a943ff2eb9394c72d4ec8b76592c454915b5839ae177d422777a046e29.js"></script>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<div class="js-stale-session-flash stale-session-flash flash flash-warn flash-banner d-none">
|
||||
<svg aria-hidden="true" class="octicon octicon-alert" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path d="M8.865 1.52c-.18-.31-.51-.5-.87-.5s-.69.19-.87.5L.275 13.5c-.18.31-.18.69 0 1 .19.31.52.5.87.5h13.7c.36 0 .69-.19.86-.5.17-.31.18-.69.01-1L8.865 1.52zM8.995 13h-2v-2h2v2zm0-3h-2V6h2v4z"></path></svg>
|
||||
<span class="signed-in-tab-flash">You signed in with another tab or window. <a href="">Reload</a> to refresh your session.</span>
|
||||
<span class="signed-out-tab-flash">You signed out in another tab or window. <a href="">Reload</a> to refresh your session.</span>
|
||||
</div>
|
||||
<div class="facebox" id="facebox" style="display:none;">
|
||||
<div class="facebox-popup">
|
||||
<div class="facebox-content" role="dialog" aria-labelledby="facebox-header" aria-describedby="facebox-description">
|
||||
</div>
|
||||
<button type="button" class="facebox-close js-facebox-close" aria-label="Close modal">
|
||||
<svg aria-hidden="true" class="octicon octicon-x" height="16" version="1.1" viewBox="0 0 12 16" width="12"><path d="M7.48 8l3.75 3.75-1.48 1.48L6 9.48l-3.75 3.75-1.48-1.48L4.52 8 .77 4.25l1.48-1.48L6 6.52l3.75-3.75 1.48 1.48z"></path></svg>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
|
||||
|
After Width: | Height: | Size: 166 KiB |
|
After Width: | Height: | Size: 192 KiB |
|
After Width: | Height: | Size: 146 KiB |
|
After Width: | Height: | Size: 136 KiB |
|
After Width: | Height: | Size: 98 KiB |
|
After Width: | Height: | Size: 182 KiB |
|
After Width: | Height: | Size: 31 KiB |
|
After Width: | Height: | Size: 22 KiB |
@@ -0,0 +1,10 @@
|
||||
<table style="font-family: 'Trebuchet MS', 'Tahoma', 'Arial', 'Helvetica'">
|
||||
<tr><td style="width: 18ex"><b>Banner:</b></td><td>fuzz</td></tr>
|
||||
<tr><td><b>Directory:</b></td><td>fuzz-testing/out</td></tr>
|
||||
<tr><td><b>Generated on:</b></td><td>Sun Oct 2 08:51:02 CEST 2016</td></tr>
|
||||
</table>
|
||||
<p>
|
||||
<img src="high_freq.png" width=1000 height=300><p>
|
||||
<img src="low_freq.png" width=1000 height=200><p>
|
||||
<img src="exec_speed.png" width=1000 height=200>
|
||||
|
||||
|
After Width: | Height: | Size: 14 KiB |
@@ -0,0 +1,38 @@
|
||||
/*
|
||||
__ _____ _____ _____
|
||||
__| | __| | | | JSON for Modern C++ (fuzz test support)
|
||||
| | |__ | | | | | | version 3.10.5
|
||||
|_____|_____|_____|_|___| https://github.com/nlohmann/json
|
||||
|
||||
This file implements a driver for American Fuzzy Lop (afl-fuzz). It relies on
|
||||
an implementation of the `LLVMFuzzerTestOneInput` function which processes a
|
||||
passed byte array.
|
||||
|
||||
Licensed under the MIT License <http://opensource.org/licenses/MIT>.
|
||||
*/
|
||||
|
||||
#include <vector> // for vector
|
||||
#include <cstdint> // for uint8_t
|
||||
#include <iostream> // for cin
|
||||
|
||||
extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size);
|
||||
|
||||
int main()
|
||||
{
|
||||
#ifdef __AFL_HAVE_MANUAL_CONTROL
|
||||
while (__AFL_LOOP(1000))
|
||||
{
|
||||
#endif
|
||||
// copy stdin to byte vector
|
||||
std::vector<uint8_t> vec;
|
||||
char c;
|
||||
while (std::cin.get(c))
|
||||
{
|
||||
vec.push_back(static_cast<uint8_t>(c));
|
||||
}
|
||||
|
||||
LLVMFuzzerTestOneInput(vec.data(), vec.size());
|
||||
#ifdef __AFL_HAVE_MANUAL_CONTROL
|
||||
}
|
||||
#endif
|
||||
}
|
||||
@@ -0,0 +1,84 @@
|
||||
/*
|
||||
__ _____ _____ _____
|
||||
__| | __| | | | JSON for Modern C++ (fuzz test support)
|
||||
| | |__ | | | | | | version 3.10.5
|
||||
|_____|_____|_____|_|___| https://github.com/nlohmann/json
|
||||
|
||||
This file implements a parser test suitable for fuzz testing. Given a byte
|
||||
array data, it performs the following steps:
|
||||
|
||||
- j1 = from_bjdata(data)
|
||||
- vec = to_bjdata(j1)
|
||||
- j2 = from_bjdata(vec)
|
||||
- assert(j1 == j2)
|
||||
- vec2 = to_bjdata(j1, use_size = true, use_type = false)
|
||||
- j3 = from_bjdata(vec2)
|
||||
- assert(j1 == j3)
|
||||
- vec3 = to_bjdata(j1, use_size = true, use_type = true)
|
||||
- j4 = from_bjdata(vec3)
|
||||
- assert(j1 == j4)
|
||||
|
||||
The provided function `LLVMFuzzerTestOneInput` can be used in different fuzzer
|
||||
drivers.
|
||||
|
||||
Licensed under the MIT License <http://opensource.org/licenses/MIT>.
|
||||
*/
|
||||
|
||||
#include <iostream>
|
||||
#include <sstream>
|
||||
#include <nlohmann/json.hpp>
|
||||
|
||||
using json = nlohmann::json;
|
||||
|
||||
// see http://llvm.org/docs/LibFuzzer.html
|
||||
extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size)
|
||||
{
|
||||
try
|
||||
{
|
||||
// step 1: parse input
|
||||
std::vector<uint8_t> vec1(data, data + size);
|
||||
json j1 = json::from_bjdata(vec1);
|
||||
|
||||
try
|
||||
{
|
||||
// step 2.1: round trip without adding size annotations to container types
|
||||
std::vector<uint8_t> vec2 = json::to_bjdata(j1, false, false);
|
||||
|
||||
// step 2.2: round trip with adding size annotations but without adding type annonations to container types
|
||||
std::vector<uint8_t> vec3 = json::to_bjdata(j1, true, false);
|
||||
|
||||
// step 2.3: round trip with adding size as well as type annotations to container types
|
||||
std::vector<uint8_t> vec4 = json::to_bjdata(j1, true, true);
|
||||
|
||||
// parse serialization
|
||||
json j2 = json::from_bjdata(vec2);
|
||||
json j3 = json::from_bjdata(vec3);
|
||||
json j4 = json::from_bjdata(vec4);
|
||||
|
||||
// serializations must match
|
||||
assert(json::to_bjdata(j2, false, false) == vec2);
|
||||
assert(json::to_bjdata(j3, true, false) == vec3);
|
||||
assert(json::to_bjdata(j4, true, true) == vec4);
|
||||
}
|
||||
catch (const json::parse_error&)
|
||||
{
|
||||
// parsing a BJData serialization must not fail
|
||||
assert(false);
|
||||
}
|
||||
}
|
||||
catch (const json::parse_error&)
|
||||
{
|
||||
// parse errors are ok, because input may be random bytes
|
||||
}
|
||||
catch (const json::type_error&)
|
||||
{
|
||||
// type errors can occur during parsing, too
|
||||
}
|
||||
catch (const json::out_of_range&)
|
||||
{
|
||||
// out of range errors may happen if provided sizes are excessive
|
||||
}
|
||||
|
||||
// return 0 - non-zero return values are reserved for future use
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,73 @@
|
||||
/*
|
||||
__ _____ _____ _____
|
||||
__| | __| | | | JSON for Modern C++ (fuzz test support)
|
||||
| | |__ | | | | | | version 3.10.5
|
||||
|_____|_____|_____|_|___| https://github.com/nlohmann/json
|
||||
|
||||
This file implements a parser test suitable for fuzz testing. Given a byte
|
||||
array data, it performs the following steps:
|
||||
|
||||
- j1 = from_bson(data)
|
||||
- vec = to_bson(j1)
|
||||
- j2 = from_bson(vec)
|
||||
- assert(j1 == j2)
|
||||
|
||||
The provided function `LLVMFuzzerTestOneInput` can be used in different fuzzer
|
||||
drivers.
|
||||
|
||||
Licensed under the MIT License <http://opensource.org/licenses/MIT>.
|
||||
*/
|
||||
|
||||
#include <iostream>
|
||||
#include <sstream>
|
||||
#include <nlohmann/json.hpp>
|
||||
|
||||
using json = nlohmann::json;
|
||||
|
||||
// see http://llvm.org/docs/LibFuzzer.html
|
||||
extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size)
|
||||
{
|
||||
try
|
||||
{
|
||||
// step 1: parse input
|
||||
std::vector<uint8_t> vec1(data, data + size);
|
||||
json j1 = json::from_bson(vec1);
|
||||
|
||||
if (j1.is_discarded())
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
// step 2: round trip
|
||||
std::vector<uint8_t> vec2 = json::to_bson(j1);
|
||||
|
||||
// parse serialization
|
||||
json j2 = json::from_bson(vec2);
|
||||
|
||||
// serializations must match
|
||||
assert(json::to_bson(j2) == vec2);
|
||||
}
|
||||
catch (const json::parse_error&)
|
||||
{
|
||||
// parsing a BSON serialization must not fail
|
||||
assert(false);
|
||||
}
|
||||
}
|
||||
catch (const json::parse_error&)
|
||||
{
|
||||
// parse errors are ok, because input may be random bytes
|
||||
}
|
||||
catch (const json::type_error&)
|
||||
{
|
||||
// type errors can occur during parsing, too
|
||||
}
|
||||
catch (const json::out_of_range&)
|
||||
{
|
||||
// out of range errors can occur during parsing, too
|
||||
}
|
||||
|
||||
// return 0 - non-zero return values are reserved for future use
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,68 @@
|
||||
/*
|
||||
__ _____ _____ _____
|
||||
__| | __| | | | JSON for Modern C++ (fuzz test support)
|
||||
| | |__ | | | | | | version 3.10.5
|
||||
|_____|_____|_____|_|___| https://github.com/nlohmann/json
|
||||
|
||||
This file implements a parser test suitable for fuzz testing. Given a byte
|
||||
array data, it performs the following steps:
|
||||
|
||||
- j1 = from_cbor(data)
|
||||
- vec = to_cbor(j1)
|
||||
- j2 = from_cbor(vec)
|
||||
- assert(j1 == j2)
|
||||
|
||||
The provided function `LLVMFuzzerTestOneInput` can be used in different fuzzer
|
||||
drivers.
|
||||
|
||||
Licensed under the MIT License <http://opensource.org/licenses/MIT>.
|
||||
*/
|
||||
|
||||
#include <iostream>
|
||||
#include <sstream>
|
||||
#include <nlohmann/json.hpp>
|
||||
|
||||
using json = nlohmann::json;
|
||||
|
||||
// see http://llvm.org/docs/LibFuzzer.html
|
||||
extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size)
|
||||
{
|
||||
try
|
||||
{
|
||||
// step 1: parse input
|
||||
std::vector<uint8_t> vec1(data, data + size);
|
||||
json j1 = json::from_cbor(vec1);
|
||||
|
||||
try
|
||||
{
|
||||
// step 2: round trip
|
||||
std::vector<uint8_t> vec2 = json::to_cbor(j1);
|
||||
|
||||
// parse serialization
|
||||
json j2 = json::from_cbor(vec2);
|
||||
|
||||
// serializations must match
|
||||
assert(json::to_cbor(j2) == vec2);
|
||||
}
|
||||
catch (const json::parse_error&)
|
||||
{
|
||||
// parsing a CBOR serialization must not fail
|
||||
assert(false);
|
||||
}
|
||||
}
|
||||
catch (const json::parse_error&)
|
||||
{
|
||||
// parse errors are ok, because input may be random bytes
|
||||
}
|
||||
catch (const json::type_error&)
|
||||
{
|
||||
// type errors can occur during parsing, too
|
||||
}
|
||||
catch (const json::out_of_range&)
|
||||
{
|
||||
// out of range errors can occur during parsing, too
|
||||
}
|
||||
|
||||
// return 0 - non-zero return values are reserved for future use
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,69 @@
|
||||
/*
|
||||
__ _____ _____ _____
|
||||
__| | __| | | | JSON for Modern C++ (fuzz test support)
|
||||
| | |__ | | | | | | version 3.10.5
|
||||
|_____|_____|_____|_|___| https://github.com/nlohmann/json
|
||||
|
||||
This file implements a parser test suitable for fuzz testing. Given a byte
|
||||
array data, it performs the following steps:
|
||||
|
||||
- j1 = parse(data)
|
||||
- s1 = serialize(j1)
|
||||
- j2 = parse(s1)
|
||||
- s2 = serialize(j2)
|
||||
- assert(s1 == s2)
|
||||
|
||||
The provided function `LLVMFuzzerTestOneInput` can be used in different fuzzer
|
||||
drivers.
|
||||
|
||||
Licensed under the MIT License <http://opensource.org/licenses/MIT>.
|
||||
*/
|
||||
|
||||
#include <iostream>
|
||||
#include <sstream>
|
||||
#include <nlohmann/json.hpp>
|
||||
|
||||
using json = nlohmann::json;
|
||||
|
||||
// see http://llvm.org/docs/LibFuzzer.html
|
||||
extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size)
|
||||
{
|
||||
try
|
||||
{
|
||||
// step 1: parse input
|
||||
json j1 = json::parse(data, data + size);
|
||||
|
||||
try
|
||||
{
|
||||
// step 2: round trip
|
||||
|
||||
// first serialization
|
||||
std::string s1 = j1.dump();
|
||||
|
||||
// parse serialization
|
||||
json j2 = json::parse(s1);
|
||||
|
||||
// second serialization
|
||||
std::string s2 = j2.dump();
|
||||
|
||||
// serializations must match
|
||||
assert(s1 == s2);
|
||||
}
|
||||
catch (const json::parse_error&)
|
||||
{
|
||||
// parsing a JSON serialization must not fail
|
||||
assert(false);
|
||||
}
|
||||
}
|
||||
catch (const json::parse_error&)
|
||||
{
|
||||
// parse errors are ok, because input may be random bytes
|
||||
}
|
||||
catch (const json::out_of_range&)
|
||||
{
|
||||
// out of range errors may happen if provided sizes are excessive
|
||||
}
|
||||
|
||||
// return 0 - non-zero return values are reserved for future use
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,68 @@
|
||||
/*
|
||||
__ _____ _____ _____
|
||||
__| | __| | | | JSON for Modern C++ (fuzz test support)
|
||||
| | |__ | | | | | | version 3.10.5
|
||||
|_____|_____|_____|_|___| https://github.com/nlohmann/json
|
||||
|
||||
This file implements a parser test suitable for fuzz testing. Given a byte
|
||||
array data, it performs the following steps:
|
||||
|
||||
- j1 = from_msgpack(data)
|
||||
- vec = to_msgpack(j1)
|
||||
- j2 = from_msgpack(vec)
|
||||
- assert(j1 == j2)
|
||||
|
||||
The provided function `LLVMFuzzerTestOneInput` can be used in different fuzzer
|
||||
drivers.
|
||||
|
||||
Licensed under the MIT License <http://opensource.org/licenses/MIT>.
|
||||
*/
|
||||
|
||||
#include <iostream>
|
||||
#include <sstream>
|
||||
#include <nlohmann/json.hpp>
|
||||
|
||||
using json = nlohmann::json;
|
||||
|
||||
// see http://llvm.org/docs/LibFuzzer.html
|
||||
extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size)
|
||||
{
|
||||
try
|
||||
{
|
||||
// step 1: parse input
|
||||
std::vector<uint8_t> vec1(data, data + size);
|
||||
json j1 = json::from_msgpack(vec1);
|
||||
|
||||
try
|
||||
{
|
||||
// step 2: round trip
|
||||
std::vector<uint8_t> vec2 = json::to_msgpack(j1);
|
||||
|
||||
// parse serialization
|
||||
json j2 = json::from_msgpack(vec2);
|
||||
|
||||
// serializations must match
|
||||
assert(json::to_msgpack(j2) == vec2);
|
||||
}
|
||||
catch (const json::parse_error&)
|
||||
{
|
||||
// parsing a MessagePack serialization must not fail
|
||||
assert(false);
|
||||
}
|
||||
}
|
||||
catch (const json::parse_error&)
|
||||
{
|
||||
// parse errors are ok, because input may be random bytes
|
||||
}
|
||||
catch (const json::type_error&)
|
||||
{
|
||||
// type errors can occur during parsing, too
|
||||
}
|
||||
catch (const json::out_of_range&)
|
||||
{
|
||||
// out of range errors may happen if provided sizes are excessive
|
||||
}
|
||||
|
||||
// return 0 - non-zero return values are reserved for future use
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,84 @@
|
||||
/*
|
||||
__ _____ _____ _____
|
||||
__| | __| | | | JSON for Modern C++ (fuzz test support)
|
||||
| | |__ | | | | | | version 3.10.5
|
||||
|_____|_____|_____|_|___| https://github.com/nlohmann/json
|
||||
|
||||
This file implements a parser test suitable for fuzz testing. Given a byte
|
||||
array data, it performs the following steps:
|
||||
|
||||
- j1 = from_ubjson(data)
|
||||
- vec = to_ubjson(j1)
|
||||
- j2 = from_ubjson(vec)
|
||||
- assert(j1 == j2)
|
||||
- vec2 = to_ubjson(j1, use_size = true, use_type = false)
|
||||
- j3 = from_ubjson(vec2)
|
||||
- assert(j1 == j3)
|
||||
- vec3 = to_ubjson(j1, use_size = true, use_type = true)
|
||||
- j4 = from_ubjson(vec3)
|
||||
- assert(j1 == j4)
|
||||
|
||||
The provided function `LLVMFuzzerTestOneInput` can be used in different fuzzer
|
||||
drivers.
|
||||
|
||||
Licensed under the MIT License <http://opensource.org/licenses/MIT>.
|
||||
*/
|
||||
|
||||
#include <iostream>
|
||||
#include <sstream>
|
||||
#include <nlohmann/json.hpp>
|
||||
|
||||
using json = nlohmann::json;
|
||||
|
||||
// see http://llvm.org/docs/LibFuzzer.html
|
||||
extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size)
|
||||
{
|
||||
try
|
||||
{
|
||||
// step 1: parse input
|
||||
std::vector<uint8_t> vec1(data, data + size);
|
||||
json j1 = json::from_ubjson(vec1);
|
||||
|
||||
try
|
||||
{
|
||||
// step 2.1: round trip without adding size annotations to container types
|
||||
std::vector<uint8_t> vec2 = json::to_ubjson(j1, false, false);
|
||||
|
||||
// step 2.2: round trip with adding size annotations but without adding type annonations to container types
|
||||
std::vector<uint8_t> vec3 = json::to_ubjson(j1, true, false);
|
||||
|
||||
// step 2.3: round trip with adding size as well as type annotations to container types
|
||||
std::vector<uint8_t> vec4 = json::to_ubjson(j1, true, true);
|
||||
|
||||
// parse serialization
|
||||
json j2 = json::from_ubjson(vec2);
|
||||
json j3 = json::from_ubjson(vec3);
|
||||
json j4 = json::from_ubjson(vec4);
|
||||
|
||||
// serializations must match
|
||||
assert(json::to_ubjson(j2, false, false) == vec2);
|
||||
assert(json::to_ubjson(j3, true, false) == vec3);
|
||||
assert(json::to_ubjson(j4, true, true) == vec4);
|
||||
}
|
||||
catch (const json::parse_error&)
|
||||
{
|
||||
// parsing a UBJSON serialization must not fail
|
||||
assert(false);
|
||||
}
|
||||
}
|
||||
catch (const json::parse_error&)
|
||||
{
|
||||
// parse errors are ok, because input may be random bytes
|
||||
}
|
||||
catch (const json::type_error&)
|
||||
{
|
||||
// type errors can occur during parsing, too
|
||||
}
|
||||
catch (const json::out_of_range&)
|
||||
{
|
||||
// out of range errors may happen if provided sizes are excessive
|
||||
}
|
||||
|
||||
// return 0 - non-zero return values are reserved for future use
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
#pragma once
|
||||
|
||||
#include <cstdint> // uint8_t
|
||||
#include <fstream> // ifstream, istreambuf_iterator, ios
|
||||
#include <vector> // vector
|
||||
|
||||
namespace utils
|
||||
{
|
||||
|
||||
inline std::vector<std::uint8_t> read_binary_file(const std::string& filename)
|
||||
{
|
||||
std::ifstream file(filename, std::ios::binary);
|
||||
file.unsetf(std::ios::skipws);
|
||||
|
||||
file.seekg(0, std::ios::end);
|
||||
const auto size = file.tellg();
|
||||
file.seekg(0, std::ios::beg);
|
||||
|
||||
std::vector<std::uint8_t> byte_vector;
|
||||
byte_vector.reserve(static_cast<std::size_t>(size));
|
||||
byte_vector.insert(byte_vector.begin(), std::istream_iterator<std::uint8_t>(file), std::istream_iterator<std::uint8_t>());
|
||||
return byte_vector;
|
||||
}
|
||||
|
||||
} // namespace utils
|
||||
@@ -0,0 +1,318 @@
|
||||
/*
|
||||
__ _____ _____ _____
|
||||
__| | __| | | | JSON for Modern C++ (test suite)
|
||||
| | |__ | | | | | | version 3.10.5
|
||||
|_____|_____|_____|_|___| https://github.com/nlohmann/json
|
||||
|
||||
Licensed under the MIT License <http://opensource.org/licenses/MIT>.
|
||||
SPDX-License-Identifier: MIT
|
||||
Copyright (c) 2013-2022 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 "doctest_compatibility.h"
|
||||
|
||||
#include <nlohmann/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.empty();
|
||||
}));
|
||||
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() && 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.empty();
|
||||
}));
|
||||
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(!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(!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(!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_WITH_AS(std::sort(j.begin(), j.end()), "[json.exception.invalid_iterator.209] cannot use offsets with object iterators", json::invalid_iterator&);
|
||||
}
|
||||
}
|
||||
|
||||
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"}));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,275 @@
|
||||
/*
|
||||
__ _____ _____ _____
|
||||
__| | __| | | | JSON for Modern C++ (test suite)
|
||||
| | |__ | | | | | | version 3.10.5
|
||||
|_____|_____|_____|_|___| https://github.com/nlohmann/json
|
||||
|
||||
Licensed under the MIT License <http://opensource.org/licenses/MIT>.
|
||||
SPDX-License-Identifier: MIT
|
||||
Copyright (c) 2013-2022 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 "doctest_compatibility.h"
|
||||
|
||||
#define JSON_TESTS_PRIVATE
|
||||
#include <nlohmann/json.hpp>
|
||||
using nlohmann::json;
|
||||
|
||||
namespace
|
||||
{
|
||||
// special test case to check if memory is leaked if constructor throws
|
||||
template<class T>
|
||||
struct bad_allocator : std::allocator<T>
|
||||
{
|
||||
using std::allocator<T>::allocator;
|
||||
|
||||
template<class... Args>
|
||||
void construct(T* /*unused*/, Args&& ... /*unused*/)
|
||||
{
|
||||
throw std::bad_alloc();
|
||||
}
|
||||
};
|
||||
} // namespace
|
||||
|
||||
TEST_CASE("bad_alloc")
|
||||
{
|
||||
SECTION("bad_alloc")
|
||||
{
|
||||
// create JSON type using the throwing allocator
|
||||
using bad_json = nlohmann::basic_json<std::map,
|
||||
std::vector,
|
||||
std::string,
|
||||
bool,
|
||||
std::int64_t,
|
||||
std::uint64_t,
|
||||
double,
|
||||
bad_allocator>;
|
||||
|
||||
// creating an object should throw
|
||||
CHECK_THROWS_AS(bad_json(bad_json::value_t::object), std::bad_alloc&);
|
||||
}
|
||||
}
|
||||
|
||||
namespace
|
||||
{
|
||||
bool next_construct_fails = false;
|
||||
bool next_destroy_fails = false;
|
||||
bool next_deallocate_fails = false;
|
||||
|
||||
template<class T>
|
||||
struct my_allocator : std::allocator<T>
|
||||
{
|
||||
using std::allocator<T>::allocator;
|
||||
|
||||
template<class... Args>
|
||||
void construct(T* p, Args&& ... args)
|
||||
{
|
||||
if (next_construct_fails)
|
||||
{
|
||||
next_construct_fails = false;
|
||||
throw std::bad_alloc();
|
||||
}
|
||||
|
||||
::new (reinterpret_cast<void*>(p)) T(std::forward<Args>(args)...);
|
||||
}
|
||||
|
||||
void deallocate(T* p, std::size_t n)
|
||||
{
|
||||
if (next_deallocate_fails)
|
||||
{
|
||||
next_deallocate_fails = false;
|
||||
throw std::bad_alloc();
|
||||
}
|
||||
|
||||
std::allocator<T>::deallocate(p, n);
|
||||
}
|
||||
|
||||
void destroy(T* p)
|
||||
{
|
||||
if (next_destroy_fails)
|
||||
{
|
||||
next_destroy_fails = false;
|
||||
throw std::bad_alloc();
|
||||
}
|
||||
|
||||
static_cast<void>(p); // fix MSVC's C4100 warning
|
||||
p->~T();
|
||||
}
|
||||
|
||||
template <class U>
|
||||
struct rebind
|
||||
{
|
||||
using other = my_allocator<U>;
|
||||
};
|
||||
};
|
||||
|
||||
// allows deletion of raw pointer, usually hold by json_value
|
||||
template<class T>
|
||||
void my_allocator_clean_up(T* p)
|
||||
{
|
||||
assert(p != nullptr);
|
||||
my_allocator<T> alloc;
|
||||
alloc.destroy(p);
|
||||
alloc.deallocate(p, 1);
|
||||
}
|
||||
} // namespace
|
||||
|
||||
TEST_CASE("controlled 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>;
|
||||
|
||||
SECTION("class json_value")
|
||||
{
|
||||
SECTION("json_value(value_t)")
|
||||
{
|
||||
SECTION("object")
|
||||
{
|
||||
next_construct_fails = false;
|
||||
auto t = my_json::value_t::object;
|
||||
CHECK_NOTHROW(my_allocator_clean_up(my_json::json_value(t).object));
|
||||
next_construct_fails = true;
|
||||
CHECK_THROWS_AS(my_json::json_value(t), std::bad_alloc&);
|
||||
next_construct_fails = false;
|
||||
}
|
||||
SECTION("array")
|
||||
{
|
||||
next_construct_fails = false;
|
||||
auto t = my_json::value_t::array;
|
||||
CHECK_NOTHROW(my_allocator_clean_up(my_json::json_value(t).array));
|
||||
next_construct_fails = true;
|
||||
CHECK_THROWS_AS(my_json::json_value(t), std::bad_alloc&);
|
||||
next_construct_fails = false;
|
||||
}
|
||||
SECTION("string")
|
||||
{
|
||||
next_construct_fails = false;
|
||||
auto t = my_json::value_t::string;
|
||||
CHECK_NOTHROW(my_allocator_clean_up(my_json::json_value(t).string));
|
||||
next_construct_fails = true;
|
||||
CHECK_THROWS_AS(my_json::json_value(t), std::bad_alloc&);
|
||||
next_construct_fails = false;
|
||||
}
|
||||
}
|
||||
|
||||
SECTION("json_value(const string_t&)")
|
||||
{
|
||||
next_construct_fails = false;
|
||||
my_json::string_t v("foo");
|
||||
CHECK_NOTHROW(my_allocator_clean_up(my_json::json_value(v).string));
|
||||
next_construct_fails = true;
|
||||
CHECK_THROWS_AS(my_json::json_value(v), std::bad_alloc&);
|
||||
next_construct_fails = false;
|
||||
}
|
||||
}
|
||||
|
||||
SECTION("class basic_json")
|
||||
{
|
||||
SECTION("basic_json(const CompatibleObjectType&)")
|
||||
{
|
||||
next_construct_fails = false;
|
||||
std::map<std::string, std::string> v {{"foo", "bar"}};
|
||||
CHECK_NOTHROW(my_json(v));
|
||||
next_construct_fails = true;
|
||||
CHECK_THROWS_AS(my_json(v), std::bad_alloc&);
|
||||
next_construct_fails = false;
|
||||
}
|
||||
|
||||
SECTION("basic_json(const CompatibleArrayType&)")
|
||||
{
|
||||
next_construct_fails = false;
|
||||
std::vector<std::string> v {"foo", "bar", "baz"};
|
||||
CHECK_NOTHROW(my_json(v));
|
||||
next_construct_fails = true;
|
||||
CHECK_THROWS_AS(my_json(v), std::bad_alloc&);
|
||||
next_construct_fails = false;
|
||||
}
|
||||
|
||||
SECTION("basic_json(const typename string_t::value_type*)")
|
||||
{
|
||||
next_construct_fails = false;
|
||||
CHECK_NOTHROW(my_json("foo"));
|
||||
next_construct_fails = true;
|
||||
CHECK_THROWS_AS(my_json("foo"), std::bad_alloc&);
|
||||
next_construct_fails = false;
|
||||
}
|
||||
|
||||
SECTION("basic_json(const typename string_t::value_type*)")
|
||||
{
|
||||
next_construct_fails = false;
|
||||
std::string s("foo");
|
||||
CHECK_NOTHROW(my_json(s));
|
||||
next_construct_fails = true;
|
||||
CHECK_THROWS_AS(my_json(s), std::bad_alloc&);
|
||||
next_construct_fails = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
namespace
|
||||
{
|
||||
template<class T>
|
||||
struct allocator_no_forward : std::allocator<T>
|
||||
{
|
||||
allocator_no_forward() = default;
|
||||
template <class U>
|
||||
allocator_no_forward(allocator_no_forward<U> /*unused*/) {}
|
||||
|
||||
template <class U>
|
||||
struct rebind
|
||||
{
|
||||
using other = allocator_no_forward<U>;
|
||||
};
|
||||
|
||||
template <class... Args>
|
||||
void construct(T* p, const Args& ... args) noexcept(noexcept(::new (static_cast<void*>(p)) T(args...)))
|
||||
{
|
||||
// force copy even if move is available
|
||||
::new (static_cast<void*>(p)) T(args...);
|
||||
}
|
||||
};
|
||||
} // namespace
|
||||
|
||||
TEST_CASE("bad my_allocator::construct")
|
||||
{
|
||||
SECTION("my_allocator::construct doesn't forward")
|
||||
{
|
||||
using bad_alloc_json = nlohmann::basic_json<std::map,
|
||||
std::vector,
|
||||
std::string,
|
||||
bool,
|
||||
std::int64_t,
|
||||
std::uint64_t,
|
||||
double,
|
||||
allocator_no_forward>;
|
||||
|
||||
bad_alloc_json j;
|
||||
j["test"] = bad_alloc_json::array_t();
|
||||
j["test"].push_back("should not leak");
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,344 @@
|
||||
/*
|
||||
__ _____ _____ _____
|
||||
__| | __| | | | JSON for Modern C++ (test suite)
|
||||
| | |__ | | | | | | version 3.10.5
|
||||
|_____|_____|_____|_|___| https://github.com/nlohmann/json
|
||||
|
||||
Licensed under the MIT License <http://opensource.org/licenses/MIT>.
|
||||
SPDX-License-Identifier: MIT
|
||||
Copyright (c) 2018 Vitaliy Manushkin <agri@akamo.info>.
|
||||
|
||||
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 "doctest_compatibility.h"
|
||||
|
||||
#include <nlohmann/json.hpp>
|
||||
|
||||
#include <string>
|
||||
#include <utility>
|
||||
|
||||
|
||||
/* forward declarations */
|
||||
class alt_string;
|
||||
bool operator<(const char* op1, const alt_string& op2) noexcept;
|
||||
void int_to_string(alt_string& target, std::size_t value);
|
||||
|
||||
/*
|
||||
* This is virtually a string class.
|
||||
* It covers std::string under the hood.
|
||||
*/
|
||||
class alt_string
|
||||
{
|
||||
public:
|
||||
using value_type = std::string::value_type;
|
||||
|
||||
static constexpr auto npos = static_cast<std::size_t>(-1);
|
||||
|
||||
alt_string(const char* str): str_impl(str) {}
|
||||
alt_string(const char* str, std::size_t count): str_impl(str, count) {}
|
||||
alt_string(size_t count, char chr): str_impl(count, chr) {}
|
||||
alt_string() = default;
|
||||
|
||||
template <typename...TParams>
|
||||
alt_string& append(TParams&& ...params)
|
||||
{
|
||||
str_impl.append(std::forward<TParams>(params)...);
|
||||
return *this;
|
||||
}
|
||||
|
||||
void push_back(char c)
|
||||
{
|
||||
str_impl.push_back(c);
|
||||
}
|
||||
|
||||
template <typename op_type>
|
||||
bool operator==(const op_type& op) const
|
||||
{
|
||||
return str_impl == op;
|
||||
}
|
||||
|
||||
bool operator==(const alt_string& op) const
|
||||
{
|
||||
return str_impl == op.str_impl;
|
||||
}
|
||||
|
||||
template <typename op_type>
|
||||
bool operator!=(const op_type& op) const
|
||||
{
|
||||
return str_impl != op;
|
||||
}
|
||||
|
||||
bool operator!=(const alt_string& op) const
|
||||
{
|
||||
return str_impl != op.str_impl;
|
||||
}
|
||||
|
||||
std::size_t size() const noexcept
|
||||
{
|
||||
return str_impl.size();
|
||||
}
|
||||
|
||||
void resize (std::size_t n)
|
||||
{
|
||||
str_impl.resize(n);
|
||||
}
|
||||
|
||||
void resize (std::size_t n, char c)
|
||||
{
|
||||
str_impl.resize(n, c);
|
||||
}
|
||||
|
||||
template <typename op_type>
|
||||
bool operator<(const op_type& op) const noexcept
|
||||
{
|
||||
return str_impl < op;
|
||||
}
|
||||
|
||||
bool operator<(const alt_string& op) const noexcept
|
||||
{
|
||||
return str_impl < op.str_impl;
|
||||
}
|
||||
|
||||
const char* c_str() const
|
||||
{
|
||||
return str_impl.c_str();
|
||||
}
|
||||
|
||||
char& operator[](std::size_t index)
|
||||
{
|
||||
return str_impl[index];
|
||||
}
|
||||
|
||||
const char& operator[](std::size_t index) const
|
||||
{
|
||||
return str_impl[index];
|
||||
}
|
||||
|
||||
char& back()
|
||||
{
|
||||
return str_impl.back();
|
||||
}
|
||||
|
||||
const char& back() const
|
||||
{
|
||||
return str_impl.back();
|
||||
}
|
||||
|
||||
void clear()
|
||||
{
|
||||
str_impl.clear();
|
||||
}
|
||||
|
||||
const value_type* data() const
|
||||
{
|
||||
return str_impl.data();
|
||||
}
|
||||
|
||||
bool empty() const
|
||||
{
|
||||
return str_impl.empty();
|
||||
}
|
||||
|
||||
std::size_t find(const alt_string& str, std::size_t pos = 0) const
|
||||
{
|
||||
return str_impl.find(str.str_impl, pos);
|
||||
}
|
||||
|
||||
std::size_t find_first_of(char c, std::size_t pos = 0) const
|
||||
{
|
||||
return str_impl.find_first_of(c, pos);
|
||||
}
|
||||
|
||||
alt_string substr(std::size_t pos = 0, std::size_t count = npos) const
|
||||
{
|
||||
std::string s = str_impl.substr(pos, count);
|
||||
return {s.data(), s.size()};
|
||||
}
|
||||
|
||||
alt_string& replace(std::size_t pos, std::size_t count, const alt_string& str)
|
||||
{
|
||||
str_impl.replace(pos, count, str.str_impl);
|
||||
return *this;
|
||||
}
|
||||
|
||||
private:
|
||||
std::string str_impl {};
|
||||
|
||||
friend bool ::operator<(const char* /*op1*/, const alt_string& /*op2*/) noexcept;
|
||||
};
|
||||
|
||||
void int_to_string(alt_string& target, std::size_t value)
|
||||
{
|
||||
target = std::to_string(value).c_str();
|
||||
}
|
||||
|
||||
using alt_json = nlohmann::basic_json <
|
||||
std::map,
|
||||
std::vector,
|
||||
alt_string,
|
||||
bool,
|
||||
std::int64_t,
|
||||
std::uint64_t,
|
||||
double,
|
||||
std::allocator,
|
||||
nlohmann::adl_serializer >;
|
||||
|
||||
|
||||
bool operator<(const char* op1, const alt_string& op2) noexcept
|
||||
{
|
||||
return op1 < op2.str_impl;
|
||||
}
|
||||
|
||||
TEST_CASE("alternative string type")
|
||||
{
|
||||
SECTION("dump")
|
||||
{
|
||||
{
|
||||
alt_json doc;
|
||||
doc["pi"] = 3.141;
|
||||
alt_string dump = doc.dump();
|
||||
CHECK(dump == R"({"pi":3.141})");
|
||||
}
|
||||
|
||||
{
|
||||
alt_json doc;
|
||||
doc["happy"] = true;
|
||||
alt_string dump = doc.dump();
|
||||
CHECK(dump == R"({"happy":true})");
|
||||
}
|
||||
|
||||
{
|
||||
alt_json doc;
|
||||
doc["name"] = "I'm Batman";
|
||||
alt_string dump = doc.dump();
|
||||
CHECK(dump == R"({"name":"I'm Batman"})");
|
||||
}
|
||||
|
||||
{
|
||||
alt_json doc;
|
||||
doc["nothing"] = nullptr;
|
||||
alt_string dump = doc.dump();
|
||||
CHECK(dump == R"({"nothing":null})");
|
||||
}
|
||||
|
||||
{
|
||||
alt_json doc;
|
||||
doc["answer"]["everything"] = 42;
|
||||
alt_string dump = doc.dump();
|
||||
CHECK(dump == R"({"answer":{"everything":42}})");
|
||||
}
|
||||
|
||||
{
|
||||
alt_json doc;
|
||||
doc["list"] = { 1, 0, 2 };
|
||||
alt_string dump = doc.dump();
|
||||
CHECK(dump == R"({"list":[1,0,2]})");
|
||||
}
|
||||
|
||||
{
|
||||
alt_json doc;
|
||||
doc["object"] = { {"currency", "USD"}, {"value", 42.99} };
|
||||
alt_string dump = doc.dump();
|
||||
CHECK(dump == R"({"object":{"currency":"USD","value":42.99}})");
|
||||
}
|
||||
}
|
||||
|
||||
SECTION("parse")
|
||||
{
|
||||
auto doc = alt_json::parse(R"({"foo": "bar"})");
|
||||
alt_string dump = doc.dump();
|
||||
CHECK(dump == R"({"foo":"bar"})");
|
||||
}
|
||||
|
||||
SECTION("items")
|
||||
{
|
||||
auto doc = alt_json::parse(R"({"foo": "bar"})");
|
||||
|
||||
for (const auto& item : doc.items())
|
||||
{
|
||||
CHECK(item.key() == "foo");
|
||||
CHECK(item.value() == "bar");
|
||||
}
|
||||
|
||||
auto doc_array = alt_json::parse(R"(["foo", "bar"])");
|
||||
|
||||
for (const auto& item : doc_array.items())
|
||||
{
|
||||
if (item.key() == "0" )
|
||||
{
|
||||
CHECK( item.value() == "foo" );
|
||||
}
|
||||
else if (item.key() == "1" )
|
||||
{
|
||||
CHECK(item.value() == "bar");
|
||||
}
|
||||
else
|
||||
{
|
||||
CHECK(false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
SECTION("equality")
|
||||
{
|
||||
alt_json doc;
|
||||
doc["Who are you?"] = "I'm Batman";
|
||||
|
||||
CHECK("I'm Batman" == doc["Who are you?"]);
|
||||
CHECK(doc["Who are you?"] == "I'm Batman");
|
||||
CHECK_FALSE("I'm Batman" != doc["Who are you?"]);
|
||||
CHECK_FALSE(doc["Who are you?"] != "I'm Batman");
|
||||
|
||||
CHECK("I'm Bruce Wayne" != doc["Who are you?"]);
|
||||
CHECK(doc["Who are you?"] != "I'm Bruce Wayne");
|
||||
CHECK_FALSE("I'm Bruce Wayne" == doc["Who are you?"]);
|
||||
CHECK_FALSE(doc["Who are you?"] == "I'm Bruce Wayne");
|
||||
|
||||
{
|
||||
const alt_json& const_doc = doc;
|
||||
|
||||
CHECK("I'm Batman" == const_doc["Who are you?"]);
|
||||
CHECK(const_doc["Who are you?"] == "I'm Batman");
|
||||
CHECK_FALSE("I'm Batman" != const_doc["Who are you?"]);
|
||||
CHECK_FALSE(const_doc["Who are you?"] != "I'm Batman");
|
||||
|
||||
CHECK("I'm Bruce Wayne" != const_doc["Who are you?"]);
|
||||
CHECK(const_doc["Who are you?"] != "I'm Bruce Wayne");
|
||||
CHECK_FALSE("I'm Bruce Wayne" == const_doc["Who are you?"]);
|
||||
CHECK_FALSE(const_doc["Who are you?"] == "I'm Bruce Wayne");
|
||||
}
|
||||
}
|
||||
|
||||
SECTION("JSON pointer")
|
||||
{
|
||||
// conversion from json to alt_json fails to compile (see #3425);
|
||||
// attempted fix(*) produces: [[['b','a','r'],['b','a','z']]] (with each char being an integer)
|
||||
// (*) disable implicit conversion for json_refs of any basic_json type
|
||||
// alt_json j = R"(
|
||||
// {
|
||||
// "foo": ["bar", "baz"]
|
||||
// }
|
||||
// )"_json;
|
||||
auto j = alt_json::parse(R"({"foo": ["bar", "baz"]})");
|
||||
|
||||
CHECK(j.at(alt_json::json_pointer("/foo/0")) == j["foo"][0]);
|
||||
CHECK(j.at(alt_json::json_pointer("/foo/1")) == j["foo"][1]);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,69 @@
|
||||
/*
|
||||
__ _____ _____ _____
|
||||
__| | __| | | | JSON for Modern C++ (test suite)
|
||||
| | |__ | | | | | | version 3.10.5
|
||||
|_____|_____|_____|_|___| https://github.com/nlohmann/json
|
||||
|
||||
Licensed under the MIT License <http://opensource.org/licenses/MIT>.
|
||||
SPDX-License-Identifier: MIT
|
||||
Copyright (c) 2013-2022 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 "doctest_compatibility.h"
|
||||
|
||||
// avoid warning when assert does not abort
|
||||
DOCTEST_GCC_SUPPRESS_WARNING_PUSH
|
||||
DOCTEST_GCC_SUPPRESS_WARNING("-Wstrict-overflow")
|
||||
DOCTEST_CLANG_SUPPRESS_WARNING_PUSH
|
||||
DOCTEST_CLANG_SUPPRESS_WARNING("-Wstrict-overflow")
|
||||
|
||||
/// global variable to record side effect of assert calls
|
||||
static int assert_counter;
|
||||
|
||||
/// set failure variable to true instead of calling assert(x)
|
||||
#define JSON_ASSERT(x) {if (!(x)) ++assert_counter; }
|
||||
|
||||
#include <nlohmann/json.hpp>
|
||||
using nlohmann::json;
|
||||
|
||||
// the test assumes exceptions to work
|
||||
#if !defined(JSON_NOEXCEPTION)
|
||||
TEST_CASE("JSON_ASSERT(x)")
|
||||
{
|
||||
SECTION("basic_json(first, second)")
|
||||
{
|
||||
assert_counter = 0;
|
||||
CHECK(assert_counter == 0);
|
||||
|
||||
json::iterator it;
|
||||
json j;
|
||||
|
||||
// in case assertions do not abort execution, an exception is thrown
|
||||
CHECK_THROWS_WITH_AS(json(it, j.end()), "[json.exception.invalid_iterator.201] iterators are not compatible", json::invalid_iterator);
|
||||
|
||||
// check that assertion actually happened
|
||||
CHECK(assert_counter == 1);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
DOCTEST_GCC_SUPPRESS_WARNING_POP
|
||||
DOCTEST_CLANG_SUPPRESS_WARNING_POP
|
||||
@@ -0,0 +1,202 @@
|
||||
/*
|
||||
__ _____ _____ _____
|
||||
__| | __| | | | JSON for Modern C++ (test suite)
|
||||
| | |__ | | | | | | version 3.10.2
|
||||
|_____|_____|_____|_|___| https://github.com/nlohmann/json
|
||||
|
||||
Licensed under the MIT License <http://opensource.org/licenses/MIT>.
|
||||
SPDX-License-Identifier: MIT
|
||||
Copyright (c) 2013-2019 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 "doctest_compatibility.h"
|
||||
|
||||
#include <nlohmann/json.hpp>
|
||||
using nlohmann::json;
|
||||
|
||||
#include <fstream>
|
||||
#include <test_data.hpp>
|
||||
|
||||
TEST_CASE("Binary Formats" * doctest::skip())
|
||||
{
|
||||
SECTION("canada.json")
|
||||
{
|
||||
const auto* filename = TEST_DATA_DIRECTORY "/nativejson-benchmark/canada.json";
|
||||
json j = json::parse(std::ifstream(filename));
|
||||
|
||||
const auto json_size = j.dump().size();
|
||||
const auto bson_size = json::to_bson(j).size();
|
||||
const auto cbor_size = json::to_cbor(j).size();
|
||||
const auto msgpack_size = json::to_msgpack(j).size();
|
||||
const auto ubjson_1_size = json::to_ubjson(j).size();
|
||||
const auto ubjson_2_size = json::to_ubjson(j, true).size();
|
||||
const auto ubjson_3_size = json::to_ubjson(j, true, true).size();
|
||||
const auto bon8_size = json::to_bon8(j).size();
|
||||
|
||||
CHECK(json_size == 2090303);
|
||||
CHECK(bson_size == 1794522);
|
||||
CHECK(cbor_size == 1055552);
|
||||
CHECK(msgpack_size == 1056145);
|
||||
CHECK(ubjson_1_size == 1112030);
|
||||
CHECK(ubjson_2_size == 1224148);
|
||||
CHECK(ubjson_3_size == 1169069);
|
||||
CHECK(bon8_size == 1055789);
|
||||
|
||||
CHECK((100.0 * double(json_size) / double(json_size)) == Approx(100.0));
|
||||
CHECK((100.0 * double(bson_size) / double(json_size)) == Approx(85.849));
|
||||
CHECK((100.0 * double(cbor_size) / double(json_size)) == Approx(50.497));
|
||||
CHECK((100.0 * double(msgpack_size) / double(json_size)) == Approx(50.526));
|
||||
CHECK((100.0 * double(ubjson_1_size) / double(json_size)) == Approx(53.199));
|
||||
CHECK((100.0 * double(ubjson_2_size) / double(json_size)) == Approx(58.563));
|
||||
CHECK((100.0 * double(ubjson_3_size) / double(json_size)) == Approx(55.928));
|
||||
CHECK((100.0 * double(bon8_size) / double(json_size)) == Approx(50.509));
|
||||
}
|
||||
|
||||
SECTION("twitter.json")
|
||||
{
|
||||
const auto* filename = TEST_DATA_DIRECTORY "/nativejson-benchmark/twitter.json";
|
||||
json j = json::parse(std::ifstream(filename));
|
||||
|
||||
const auto json_size = j.dump().size();
|
||||
const auto bson_size = json::to_bson(j).size();
|
||||
const auto cbor_size = json::to_cbor(j).size();
|
||||
const auto msgpack_size = json::to_msgpack(j).size();
|
||||
const auto ubjson_1_size = json::to_ubjson(j).size();
|
||||
const auto ubjson_2_size = json::to_ubjson(j, true).size();
|
||||
const auto ubjson_3_size = json::to_ubjson(j, true, true).size();
|
||||
const auto bon8_size = json::to_bon8(j).size();
|
||||
|
||||
CHECK(json_size == 466906);
|
||||
CHECK(bson_size == 444568);
|
||||
CHECK(cbor_size == 402814);
|
||||
CHECK(msgpack_size == 401510);
|
||||
CHECK(ubjson_1_size == 426160);
|
||||
CHECK(ubjson_2_size == 430788);
|
||||
CHECK(ubjson_3_size == 430798);
|
||||
CHECK(bon8_size == 391172);
|
||||
|
||||
CHECK((100.0 * double(json_size) / double(json_size)) == Approx(100.0));
|
||||
CHECK((100.0 * double(bson_size) / double(json_size)) == Approx(95.215));
|
||||
CHECK((100.0 * double(cbor_size) / double(json_size)) == Approx(86.273));
|
||||
CHECK((100.0 * double(msgpack_size) / double(json_size)) == Approx(85.993));
|
||||
CHECK((100.0 * double(ubjson_1_size) / double(json_size)) == Approx(91.273));
|
||||
CHECK((100.0 * double(ubjson_2_size) / double(json_size)) == Approx(92.264));
|
||||
CHECK((100.0 * double(ubjson_3_size) / double(json_size)) == Approx(92.266));
|
||||
CHECK((100.0 * double(bon8_size) / double(json_size)) == Approx(83.779));
|
||||
}
|
||||
|
||||
SECTION("citm_catalog.json")
|
||||
{
|
||||
const auto* filename = TEST_DATA_DIRECTORY "/nativejson-benchmark/citm_catalog.json";
|
||||
json j = json::parse(std::ifstream(filename));
|
||||
|
||||
const auto json_size = j.dump().size();
|
||||
const auto bson_size = json::to_bson(j).size();
|
||||
const auto cbor_size = json::to_cbor(j).size();
|
||||
const auto msgpack_size = json::to_msgpack(j).size();
|
||||
const auto ubjson_1_size = json::to_ubjson(j).size();
|
||||
const auto ubjson_2_size = json::to_ubjson(j, true).size();
|
||||
const auto ubjson_3_size = json::to_ubjson(j, true, true).size();
|
||||
const auto bon8_size = json::to_bon8(j).size();
|
||||
|
||||
CHECK(json_size == 500299);
|
||||
CHECK(bson_size == 479430);
|
||||
CHECK(cbor_size == 342373);
|
||||
CHECK(msgpack_size == 342473);
|
||||
CHECK(ubjson_1_size == 391463);
|
||||
CHECK(ubjson_2_size == 434239);
|
||||
CHECK(ubjson_3_size == 425073);
|
||||
CHECK(bon8_size == 317877);
|
||||
|
||||
CHECK((100.0 * double(json_size) / double(json_size)) == Approx(100.0));
|
||||
CHECK((100.0 * double(bson_size) / double(json_size)) == Approx(95.828));
|
||||
CHECK((100.0 * double(cbor_size) / double(json_size)) == Approx(68.433));
|
||||
CHECK((100.0 * double(msgpack_size) / double(json_size)) == Approx(68.453));
|
||||
CHECK((100.0 * double(ubjson_1_size) / double(json_size)) == Approx(78.245));
|
||||
CHECK((100.0 * double(ubjson_2_size) / double(json_size)) == Approx(86.795));
|
||||
CHECK((100.0 * double(ubjson_3_size) / double(json_size)) == Approx(84.963));
|
||||
CHECK((100.0 * double(bon8_size) / double(json_size)) == Approx(63.537));
|
||||
}
|
||||
|
||||
SECTION("jeopardy.json")
|
||||
{
|
||||
const auto* filename = TEST_DATA_DIRECTORY "/jeopardy/jeopardy.json";
|
||||
json j = json::parse(std::ifstream(filename));
|
||||
|
||||
const auto json_size = j.dump().size();
|
||||
const auto bson_size = json::to_bson({{"", j}}).size(); // wrap array in object for BSON
|
||||
const auto cbor_size = json::to_cbor(j).size();
|
||||
const auto msgpack_size = json::to_msgpack(j).size();
|
||||
const auto ubjson_1_size = json::to_ubjson(j).size();
|
||||
const auto ubjson_2_size = json::to_ubjson(j, true).size();
|
||||
const auto ubjson_3_size = json::to_ubjson(j, true, true).size();
|
||||
const auto bon8_size = json::to_bon8(j).size();
|
||||
|
||||
CHECK(json_size == 52508728);
|
||||
CHECK(bson_size == 56008520);
|
||||
CHECK(cbor_size == 46187320);
|
||||
CHECK(msgpack_size == 46158575);
|
||||
CHECK(ubjson_1_size == 50710965);
|
||||
CHECK(ubjson_2_size == 51144830);
|
||||
CHECK(ubjson_3_size == 49861422);
|
||||
CHECK(bon8_size == 45942080);
|
||||
|
||||
CHECK((100.0 * double(json_size) / double(json_size)) == Approx(100.0));
|
||||
CHECK((100.0 * double(bson_size) / double(json_size)) == Approx(106.665));
|
||||
CHECK((100.0 * double(cbor_size) / double(json_size)) == Approx(87.961));
|
||||
CHECK((100.0 * double(msgpack_size) / double(json_size)) == Approx(87.906));
|
||||
CHECK((100.0 * double(ubjson_1_size) / double(json_size)) == Approx(96.576));
|
||||
CHECK((100.0 * double(ubjson_2_size) / double(json_size)) == Approx(97.402));
|
||||
CHECK((100.0 * double(ubjson_3_size) / double(json_size)) == Approx(94.958));
|
||||
CHECK((100.0 * double(bon8_size) / double(json_size)) == Approx(87.494));
|
||||
}
|
||||
|
||||
SECTION("sample.json")
|
||||
{
|
||||
const auto* filename = TEST_DATA_DIRECTORY "/json_testsuite/sample.json";
|
||||
json j = json::parse(std::ifstream(filename));
|
||||
|
||||
const auto json_size = j.dump().size();
|
||||
// BSON cannot process the file as it contains code point U+0000
|
||||
const auto cbor_size = json::to_cbor(j).size();
|
||||
const auto msgpack_size = json::to_msgpack(j).size();
|
||||
const auto ubjson_1_size = json::to_ubjson(j).size();
|
||||
const auto ubjson_2_size = json::to_ubjson(j, true).size();
|
||||
const auto ubjson_3_size = json::to_ubjson(j, true, true).size();
|
||||
const auto bon8_size = json::to_bon8(j).size();
|
||||
|
||||
CHECK(json_size == 168677);
|
||||
CHECK(cbor_size == 147095);
|
||||
CHECK(msgpack_size == 147017);
|
||||
CHECK(ubjson_1_size == 148695);
|
||||
CHECK(ubjson_2_size == 150569);
|
||||
CHECK(ubjson_3_size == 150883);
|
||||
CHECK(bon8_size == 144463);
|
||||
|
||||
CHECK((100.0 * double(json_size) / double(json_size)) == Approx(100.0));
|
||||
CHECK((100.0 * double(cbor_size) / double(json_size)) == Approx(87.205));
|
||||
CHECK((100.0 * double(msgpack_size) / double(json_size)) == Approx(87.158));
|
||||
CHECK((100.0 * double(ubjson_1_size) / double(json_size)) == Approx(88.153));
|
||||
CHECK((100.0 * double(ubjson_2_size) / double(json_size)) == Approx(89.264));
|
||||
CHECK((100.0 * double(ubjson_3_size) / double(json_size)) == Approx(89.450));
|
||||
CHECK((100.0 * double(bon8_size) / double(json_size)) == Approx(85.644));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,899 @@
|
||||
/*
|
||||
__ _____ _____ _____
|
||||
__| | __| | | | JSON for Modern C++ (test suite)
|
||||
| | |__ | | | | | | version 3.10.2
|
||||
|_____|_____|_____|_|___| https://github.com/nlohmann/json
|
||||
|
||||
Licensed under the MIT License <http://opensource.org/licenses/MIT>.
|
||||
SPDX-License-Identifier: MIT
|
||||
Copyright (c) 2013-2019 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 "doctest_compatibility.h"
|
||||
|
||||
#include <nlohmann/json.hpp>
|
||||
using nlohmann::json;
|
||||
|
||||
#include <iostream>
|
||||
#include <fstream>
|
||||
#include <set>
|
||||
#include <test_data.hpp>
|
||||
#include "test_utils.hpp"
|
||||
|
||||
namespace
|
||||
{
|
||||
class SaxCountdown
|
||||
{
|
||||
public:
|
||||
explicit SaxCountdown(const int count) : events_left(count)
|
||||
{}
|
||||
|
||||
bool null()
|
||||
{
|
||||
return events_left-- > 0;
|
||||
}
|
||||
|
||||
bool boolean(bool /*unused*/)
|
||||
{
|
||||
return events_left-- > 0;
|
||||
}
|
||||
|
||||
bool number_integer(json::number_integer_t /*unused*/)
|
||||
{
|
||||
return events_left-- > 0;
|
||||
}
|
||||
|
||||
bool number_unsigned(json::number_unsigned_t /*unused*/)
|
||||
{
|
||||
return events_left-- > 0;
|
||||
}
|
||||
|
||||
bool number_float(json::number_float_t /*unused*/, const std::string& /*unused*/)
|
||||
{
|
||||
return events_left-- > 0;
|
||||
}
|
||||
|
||||
bool string(std::string& /*unused*/)
|
||||
{
|
||||
return events_left-- > 0;
|
||||
}
|
||||
|
||||
bool binary(std::vector<std::uint8_t>& /*unused*/)
|
||||
{
|
||||
return events_left-- > 0;
|
||||
}
|
||||
|
||||
bool start_object(std::size_t /*unused*/)
|
||||
{
|
||||
return events_left-- > 0;
|
||||
}
|
||||
|
||||
bool key(std::string& /*unused*/)
|
||||
{
|
||||
return events_left-- > 0;
|
||||
}
|
||||
|
||||
bool end_object()
|
||||
{
|
||||
return events_left-- > 0;
|
||||
}
|
||||
|
||||
bool start_array(std::size_t /*unused*/)
|
||||
{
|
||||
return events_left-- > 0;
|
||||
}
|
||||
|
||||
bool end_array()
|
||||
{
|
||||
return events_left-- > 0;
|
||||
}
|
||||
|
||||
bool parse_error(std::size_t /*unused*/, const std::string& /*unused*/, const json::exception& /*unused*/) // NOLINT(readability-convert-member-functions-to-static)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
private:
|
||||
int events_left = 0;
|
||||
};
|
||||
} // namespace
|
||||
|
||||
TEST_CASE("BON8")
|
||||
{
|
||||
SECTION("individual values")
|
||||
{
|
||||
SECTION("discarded")
|
||||
{
|
||||
// discarded values are not serialized
|
||||
json j = json::value_t::discarded;
|
||||
const auto result = json::to_bon8(j);
|
||||
CHECK(result.empty());
|
||||
}
|
||||
|
||||
SECTION("null")
|
||||
{
|
||||
json j = nullptr;
|
||||
std::vector<uint8_t> expected = {0xFA};
|
||||
const auto result = json::to_bon8(j);
|
||||
CHECK(result == expected);
|
||||
CHECK(json::from_bon8(result) == j);
|
||||
}
|
||||
|
||||
SECTION("boolean")
|
||||
{
|
||||
SECTION("true")
|
||||
{
|
||||
json j = true;
|
||||
std::vector<uint8_t> expected = {0xF9};
|
||||
const auto result = json::to_bon8(j);
|
||||
CHECK(result == expected);
|
||||
CHECK(json::from_bon8(result) == j);
|
||||
}
|
||||
|
||||
SECTION("false")
|
||||
{
|
||||
json j = false;
|
||||
std::vector<uint8_t> expected = {0xF8};
|
||||
const auto result = json::to_bon8(j);
|
||||
CHECK(result == expected);
|
||||
CHECK(json::from_bon8(result) == j);
|
||||
}
|
||||
}
|
||||
|
||||
SECTION("unsigned integers")
|
||||
{
|
||||
SECTION("0..39")
|
||||
{
|
||||
SECTION("0")
|
||||
{
|
||||
json j = 0U;
|
||||
std::vector<uint8_t> expected = {0x90};
|
||||
const auto result = json::to_bon8(j);
|
||||
CHECK(result == expected);
|
||||
CHECK(json::from_bon8(result) == j);
|
||||
}
|
||||
|
||||
SECTION("39")
|
||||
{
|
||||
json j = 39U;
|
||||
std::vector<uint8_t> expected = {0xB7};
|
||||
const auto result = json::to_bon8(j);
|
||||
CHECK(result == expected);
|
||||
CHECK(json::from_bon8(result) == j);
|
||||
}
|
||||
}
|
||||
|
||||
SECTION("40..3879")
|
||||
{
|
||||
SECTION("40")
|
||||
{
|
||||
json j = 40U;
|
||||
std::vector<uint8_t> expected = {0xC2, 0x00};
|
||||
const auto result = json::to_bon8(j);
|
||||
CHECK(result == expected);
|
||||
}
|
||||
|
||||
SECTION("3879")
|
||||
{
|
||||
json j = 3879U;
|
||||
std::vector<uint8_t> expected = {0xDF, 0x7F};
|
||||
const auto result = json::to_bon8(j);
|
||||
CHECK(result == expected);
|
||||
}
|
||||
}
|
||||
|
||||
SECTION("3880..524287")
|
||||
{
|
||||
SECTION("3880")
|
||||
{
|
||||
json j = 3880U;
|
||||
std::vector<uint8_t> expected = {0xE0, 0x00, 0x00};
|
||||
const auto result = json::to_bon8(j);
|
||||
CHECK(result == expected);
|
||||
}
|
||||
|
||||
SECTION("528167")
|
||||
{
|
||||
json j = 528167U;
|
||||
std::vector<uint8_t> expected = {0xEF, 0x7F, 0xFF};
|
||||
const auto result = json::to_bon8(j);
|
||||
CHECK(result == expected);
|
||||
}
|
||||
}
|
||||
|
||||
SECTION("528168..67637031")
|
||||
{
|
||||
SECTION("528168")
|
||||
{
|
||||
json j = 528168U;
|
||||
std::vector<uint8_t> expected = {0xF0, 0x00, 0x00, 0x00};
|
||||
const auto result = json::to_bon8(j);
|
||||
CHECK(result == expected);
|
||||
}
|
||||
|
||||
SECTION("67637031")
|
||||
{
|
||||
json j = 67637031U;
|
||||
std::vector<uint8_t> expected = {0xF7, 0x7F, 0xFF, 0xFF};
|
||||
const auto result = json::to_bon8(j);
|
||||
CHECK(result == expected);
|
||||
}
|
||||
}
|
||||
|
||||
SECTION("67637032..2147483647 (int32max)")
|
||||
{
|
||||
SECTION("67637032")
|
||||
{
|
||||
json j = 67637032U;
|
||||
std::vector<uint8_t> expected = {0x8C, 0x04, 0x08, 0x0F, 0x28};
|
||||
const auto result = json::to_bon8(j);
|
||||
CHECK(result == expected);
|
||||
CHECK(json::from_bon8(result) == j);
|
||||
}
|
||||
|
||||
SECTION("2147483647 (int32max)")
|
||||
{
|
||||
json j = 2147483647U;
|
||||
std::vector<uint8_t> expected = {0x8C, 0x7F, 0xFF, 0xFF, 0xFF};
|
||||
const auto result = json::to_bon8(j);
|
||||
CHECK(result == expected);
|
||||
CHECK(json::from_bon8(result) == j);
|
||||
}
|
||||
}
|
||||
|
||||
SECTION("2147483648..9223372036854775807 (int64max)")
|
||||
{
|
||||
SECTION("2147483648")
|
||||
{
|
||||
json j = 2147483648U;
|
||||
std::vector<uint8_t> expected = {0x8D, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00};
|
||||
const auto result = json::to_bon8(j);
|
||||
CHECK(result == expected);
|
||||
CHECK(json::from_bon8(result) == j);
|
||||
}
|
||||
|
||||
SECTION("9223372036854775807 (int64max)")
|
||||
{
|
||||
json j = 9223372036854775807U;
|
||||
std::vector<uint8_t> expected = {0x8D, 0x7F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF};
|
||||
const auto result = json::to_bon8(j);
|
||||
CHECK(result == expected);
|
||||
CHECK(json::from_bon8(result) == j);
|
||||
}
|
||||
}
|
||||
|
||||
SECTION("greater than int64max")
|
||||
{
|
||||
json j = 9223372036854775808U;
|
||||
CHECK_THROWS_WITH_AS(json::to_bon8(j), "[json.exception.out_of_range.407] integer number 9223372036854775808 cannot be represented by BON8 as it does not fit int64", json::out_of_range);
|
||||
}
|
||||
}
|
||||
|
||||
SECTION("signed integers")
|
||||
{
|
||||
SECTION("-9223372036854775808 (int64min)..-2147483649")
|
||||
{
|
||||
SECTION("-9223372036854775808")
|
||||
{
|
||||
json j = INT64_MIN;
|
||||
std::vector<uint8_t> expected = {0x8D, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
|
||||
const auto result = json::to_bon8(j);
|
||||
CHECK(result == expected);
|
||||
CHECK(json::from_bon8(result) == j);
|
||||
}
|
||||
|
||||
SECTION("-2147483649")
|
||||
{
|
||||
// cannot use -2147483649 directly, see https://developercommunity.visualstudio.com/t/-2147483648-c4146-error/141813#T-N229960
|
||||
json j = std::int64_t(-2147483647) - 2;
|
||||
std::vector<uint8_t> expected = {0x8D, 0xFF, 0xFF, 0xFF, 0xFF, 0x7F, 0xFF, 0xFF, 0xFF};
|
||||
const auto result = json::to_bon8(j);
|
||||
CHECK(result == expected);
|
||||
CHECK(json::from_bon8(result) == j);
|
||||
}
|
||||
}
|
||||
|
||||
SECTION("-2147483648 (int32min)..-33818507")
|
||||
{
|
||||
SECTION("-2147483648")
|
||||
{
|
||||
// cannot use -2147483648 directly, see https://developercommunity.visualstudio.com/t/-2147483648-c4146-error/141813#T-N229960
|
||||
json j = -2147483647 - 1;
|
||||
std::vector<uint8_t> expected = {0x8C, 0x80, 0x00, 0x00, 0x00};
|
||||
const auto result = json::to_bon8(j);
|
||||
CHECK(result == expected);
|
||||
CHECK(json::from_bon8(result) == j);
|
||||
}
|
||||
|
||||
SECTION("-33818507")
|
||||
{
|
||||
json j = -33818507;
|
||||
std::vector<uint8_t> expected = {0x8C, 0xFD, 0xFB, 0xF8, 0x75};
|
||||
const auto result = json::to_bon8(j);
|
||||
CHECK(result == expected);
|
||||
CHECK(json::from_bon8(result) == j);
|
||||
}
|
||||
}
|
||||
|
||||
SECTION("-33818506..-264075")
|
||||
{
|
||||
SECTION("-33818506")
|
||||
{
|
||||
json j = -33818506;
|
||||
std::vector<uint8_t> expected = {0xF7, 0xFF, 0xFF, 0xFF};
|
||||
const auto result = json::to_bon8(j);
|
||||
CHECK(result == expected);
|
||||
}
|
||||
|
||||
SECTION("-264075")
|
||||
{
|
||||
json j = -264075;
|
||||
std::vector<uint8_t> expected = {0xF0, 0xC0, 0x00, 0x00};
|
||||
const auto result = json::to_bon8(j);
|
||||
CHECK(result == expected);
|
||||
}
|
||||
}
|
||||
|
||||
SECTION("-264074..-1931")
|
||||
{
|
||||
SECTION("-264074")
|
||||
{
|
||||
json j = -264074;
|
||||
std::vector<uint8_t> expected = {0xEF, 0xFF, 0xFF};
|
||||
const auto result = json::to_bon8(j);
|
||||
CHECK(result == expected);
|
||||
}
|
||||
|
||||
SECTION("-1931")
|
||||
{
|
||||
json j = -1931;
|
||||
std::vector<uint8_t> expected = {0xE0, 0xC0, 0x00};
|
||||
const auto result = json::to_bon8(j);
|
||||
CHECK(result == expected);
|
||||
}
|
||||
}
|
||||
|
||||
SECTION("-1930..-11")
|
||||
{
|
||||
SECTION("-1930")
|
||||
{
|
||||
json j = -1930;
|
||||
std::vector<uint8_t> expected = {0xDF, 0xFF};
|
||||
const auto result = json::to_bon8(j);
|
||||
CHECK(result == expected);
|
||||
}
|
||||
|
||||
SECTION("-11")
|
||||
{
|
||||
json j = -11;
|
||||
std::vector<uint8_t> expected = {0xC2, 0xC0};
|
||||
const auto result = json::to_bon8(j);
|
||||
CHECK(result == expected);
|
||||
}
|
||||
}
|
||||
|
||||
SECTION("-10..-1")
|
||||
{
|
||||
SECTION("-10")
|
||||
{
|
||||
json j = -10;
|
||||
std::vector<uint8_t> expected = {0xC1};
|
||||
const auto result = json::to_bon8(j);
|
||||
CHECK(result == expected);
|
||||
CHECK(json::from_bon8(result) == j);
|
||||
}
|
||||
|
||||
SECTION("-1")
|
||||
{
|
||||
json j = -1;
|
||||
std::vector<uint8_t> expected = {0xB8};
|
||||
const auto result = json::to_bon8(j);
|
||||
CHECK(result == expected);
|
||||
CHECK(json::from_bon8(result) == j);
|
||||
}
|
||||
}
|
||||
|
||||
SECTION("0..39")
|
||||
{
|
||||
SECTION("0")
|
||||
{
|
||||
json j = 0;
|
||||
std::vector<uint8_t> expected = {0x90};
|
||||
const auto result = json::to_bon8(j);
|
||||
CHECK(result == expected);
|
||||
CHECK(json::from_bon8(result) == j);
|
||||
}
|
||||
|
||||
SECTION("39")
|
||||
{
|
||||
json j = 39;
|
||||
std::vector<uint8_t> expected = {0xB7};
|
||||
const auto result = json::to_bon8(j);
|
||||
CHECK(result == expected);
|
||||
CHECK(json::from_bon8(result) == j);
|
||||
}
|
||||
}
|
||||
|
||||
SECTION("40..3879")
|
||||
{
|
||||
SECTION("40")
|
||||
{
|
||||
json j = 40;
|
||||
std::vector<uint8_t> expected = {0xC2, 0x00};
|
||||
const auto result = json::to_bon8(j);
|
||||
CHECK(result == expected);
|
||||
}
|
||||
|
||||
SECTION("3879")
|
||||
{
|
||||
json j = 3879;
|
||||
std::vector<uint8_t> expected = {0xDF, 0x7F};
|
||||
const auto result = json::to_bon8(j);
|
||||
CHECK(result == expected);
|
||||
}
|
||||
}
|
||||
|
||||
SECTION("3880..524287")
|
||||
{
|
||||
SECTION("3880")
|
||||
{
|
||||
json j = 3880;
|
||||
std::vector<uint8_t> expected = {0xE0, 0x00, 0x00};
|
||||
const auto result = json::to_bon8(j);
|
||||
CHECK(result == expected);
|
||||
}
|
||||
|
||||
SECTION("528167")
|
||||
{
|
||||
json j = 528167;
|
||||
std::vector<uint8_t> expected = {0xEF, 0x7F, 0xFF};
|
||||
const auto result = json::to_bon8(j);
|
||||
CHECK(result == expected);
|
||||
}
|
||||
}
|
||||
|
||||
SECTION("528168..67637031")
|
||||
{
|
||||
SECTION("528168")
|
||||
{
|
||||
json j = 528168;
|
||||
std::vector<uint8_t> expected = {0xF0, 0x00, 0x00, 0x00};
|
||||
const auto result = json::to_bon8(j);
|
||||
CHECK(result == expected);
|
||||
}
|
||||
|
||||
SECTION("67637031")
|
||||
{
|
||||
json j = 67637031;
|
||||
std::vector<uint8_t> expected = {0xF7, 0x7F, 0xFF, 0xFF};
|
||||
const auto result = json::to_bon8(j);
|
||||
CHECK(result == expected);
|
||||
}
|
||||
}
|
||||
|
||||
SECTION("67637032..2147483647 (int32max)")
|
||||
{
|
||||
SECTION("67637032")
|
||||
{
|
||||
json j = 67637032;
|
||||
std::vector<uint8_t> expected = {0x8C, 0x04, 0x08, 0x0F, 0x28};
|
||||
const auto result = json::to_bon8(j);
|
||||
CHECK(result == expected);
|
||||
}
|
||||
|
||||
SECTION("2147483647 (int32max)")
|
||||
{
|
||||
json j = 2147483647;
|
||||
std::vector<uint8_t> expected = {0x8C, 0x7F, 0xFF, 0xFF, 0xFF};
|
||||
const auto result = json::to_bon8(j);
|
||||
CHECK(result == expected);
|
||||
}
|
||||
}
|
||||
|
||||
SECTION("2147483648..9223372036854775807 (int64max)")
|
||||
{
|
||||
SECTION("2147483648")
|
||||
{
|
||||
json j = 2147483648;
|
||||
std::vector<uint8_t> expected = {0x8D, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00};
|
||||
const auto result = json::to_bon8(j);
|
||||
CHECK(result == expected);
|
||||
}
|
||||
|
||||
SECTION("9223372036854775807 (int64max)")
|
||||
{
|
||||
json j = 9223372036854775807;
|
||||
std::vector<uint8_t> expected = {0x8D, 0x7F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF};
|
||||
const auto result = json::to_bon8(j);
|
||||
CHECK(result == expected);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
SECTION("floating-point numbers")
|
||||
{
|
||||
SECTION("special values")
|
||||
{
|
||||
SECTION("-1.0")
|
||||
{
|
||||
json j = -1.0;
|
||||
std::vector<uint8_t> expected = {0xFB};
|
||||
const auto result = json::to_bon8(j);
|
||||
CHECK(result == expected);
|
||||
CHECK(json::from_bon8(result) == j);
|
||||
}
|
||||
|
||||
SECTION("0.0")
|
||||
{
|
||||
json j = 0.0;
|
||||
std::vector<uint8_t> expected = {0xFC};
|
||||
const auto result = json::to_bon8(j);
|
||||
CHECK(result == expected);
|
||||
CHECK(json::from_bon8(result) == j);
|
||||
}
|
||||
|
||||
SECTION("1.0")
|
||||
{
|
||||
json j = 1.0;
|
||||
std::vector<uint8_t> expected = {0xFD};
|
||||
const auto result = json::to_bon8(j);
|
||||
CHECK(result == expected);
|
||||
CHECK(json::from_bon8(result) == j);
|
||||
}
|
||||
|
||||
SECTION("-0.0")
|
||||
{
|
||||
json j = -0.0;
|
||||
std::vector<uint8_t> expected = {0x8E, 0x80, 0x00, 0x00, 0x00};
|
||||
const auto result = json::to_bon8(j);
|
||||
CHECK(result == expected);
|
||||
CHECK(json::from_bon8(result) == j);
|
||||
}
|
||||
|
||||
SECTION("NAN")
|
||||
{
|
||||
json j = NAN;
|
||||
std::vector<uint8_t> expected = {0x8E, 0x7F, 0x80, 0x00, 0x01};
|
||||
const auto result = json::to_bon8(j);
|
||||
CHECK(result == expected);
|
||||
json::number_float_t d{json::from_bon8(result)};
|
||||
CHECK(std::isnan(d));
|
||||
}
|
||||
|
||||
SECTION("infinity")
|
||||
{
|
||||
json j = INFINITY;
|
||||
std::vector<uint8_t> expected = {0x8E, 0x7F, 0x80, 0x00, 0x00};
|
||||
const auto result = json::to_bon8(j);
|
||||
CHECK(result == expected);
|
||||
CHECK(json::from_bon8(result) == j);
|
||||
}
|
||||
|
||||
SECTION("-infinity")
|
||||
{
|
||||
json j = -INFINITY;
|
||||
std::vector<uint8_t> expected = {0x8E, 0xFF, 0x80, 0x00, 0x00};
|
||||
const auto result = json::to_bon8(j);
|
||||
CHECK(result == expected);
|
||||
CHECK(json::from_bon8(result) == j);
|
||||
}
|
||||
}
|
||||
|
||||
SECTION("floats")
|
||||
{
|
||||
SECTION("2.0")
|
||||
{
|
||||
json j = 2.0;
|
||||
std::vector<uint8_t> expected = {0x8E, 0x40, 0x00, 0x00, 0x00};
|
||||
const auto result = json::to_bon8(j);
|
||||
CHECK(result == expected);
|
||||
CHECK(json::from_bon8(result) == j);
|
||||
}
|
||||
}
|
||||
|
||||
SECTION("doubles")
|
||||
{
|
||||
SECTION("100000000.1")
|
||||
{
|
||||
json j = 100000000.1;
|
||||
std::vector<uint8_t> expected = {0x8F, 0x41, 0x97, 0xD7, 0x84, 0x00, 0x66, 0x66, 0x66};
|
||||
const auto result = json::to_bon8(j);
|
||||
CHECK(result == expected);
|
||||
CHECK(json::from_bon8(result) == j);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
SECTION("string")
|
||||
{
|
||||
SECTION("empty string")
|
||||
{
|
||||
json j = "";
|
||||
std::vector<uint8_t> expected = {0xFF};
|
||||
const auto result = json::to_bon8(j);
|
||||
CHECK(result == expected);
|
||||
CHECK(json::from_bon8(result) == j);
|
||||
}
|
||||
|
||||
SECTION("other strings")
|
||||
{
|
||||
json j = "This is a string.";
|
||||
std::vector<uint8_t> expected = {'T', 'h', 'i', 's', ' ', 'i', 's', ' ', 'a', ' ', 's', 't', 'r', 'i', 'n', 'g', '.', 0xFF};
|
||||
const auto result = json::to_bon8(j);
|
||||
CHECK(result == expected);
|
||||
CHECK(json::from_bon8(result) == j);
|
||||
}
|
||||
|
||||
SECTION("multi-byte, 2 bytes")
|
||||
{
|
||||
json j = "\xC2\xA3";
|
||||
std::vector<uint8_t> expected = {0xC2, 0xA3, 0xFF};
|
||||
const auto result = json::to_bon8(j);
|
||||
CHECK(result == expected);
|
||||
CHECK(json::from_bon8(result) == j);
|
||||
}
|
||||
|
||||
SECTION("multi-byte, 3 bytes")
|
||||
{
|
||||
json j = "\xEF\xB8\xBB";
|
||||
std::vector<uint8_t> expected = {0xEF, 0xB8, 0xBB, 0xFF};
|
||||
const auto result = json::to_bon8(j);
|
||||
CHECK(result == expected);
|
||||
CHECK(json::from_bon8(result) == j);
|
||||
}
|
||||
|
||||
SECTION("multi-byte, 4 bytes")
|
||||
{
|
||||
json j = "\xF0\x9F\x80\x84";
|
||||
std::vector<uint8_t> expected = {0xF0, 0x9F, 0x80, 0x84, 0xFF};
|
||||
const auto result = json::to_bon8(j);
|
||||
CHECK(result == expected);
|
||||
CHECK(json::from_bon8(result) == j);
|
||||
}
|
||||
|
||||
SECTION("invalid string")
|
||||
{
|
||||
std::vector<uint8_t> v = {0xF0, 0x9F, 0x80, 0x84};
|
||||
json j;
|
||||
CHECK_THROWS_WITH_AS(j = json::from_bon8(v), "[json.exception.parse_error.110] parse error at byte 5: syntax error while parsing BON8 string: unexpected end of input", json::parse_error);
|
||||
}
|
||||
}
|
||||
|
||||
SECTION("array")
|
||||
{
|
||||
SECTION("array with count")
|
||||
{
|
||||
SECTION("empty array")
|
||||
{
|
||||
json j = json::array();
|
||||
std::vector<uint8_t> expected = {0x80};
|
||||
const auto result = json::to_bon8(j);
|
||||
CHECK(result == expected);
|
||||
CHECK(json::from_bon8(result) == j);
|
||||
}
|
||||
|
||||
SECTION("[false]")
|
||||
{
|
||||
json j = {false};
|
||||
std::vector<uint8_t> expected = {0x81, 0xF8};
|
||||
const auto result = json::to_bon8(j);
|
||||
CHECK(result == expected);
|
||||
CHECK(json::from_bon8(result) == j);
|
||||
}
|
||||
|
||||
SECTION("[false, null]")
|
||||
{
|
||||
json j = {false, nullptr};
|
||||
std::vector<uint8_t> expected = {0x82, 0xF8, 0xFA};
|
||||
const auto result = json::to_bon8(j);
|
||||
CHECK(result == expected);
|
||||
CHECK(json::from_bon8(result) == j);
|
||||
}
|
||||
|
||||
SECTION("[false, null, true]")
|
||||
{
|
||||
json j = {false, nullptr, true};
|
||||
std::vector<uint8_t> expected = {0x83, 0xF8, 0xFA, 0xF9};
|
||||
const auto result = json::to_bon8(j);
|
||||
CHECK(result == expected);
|
||||
CHECK(json::from_bon8(result) == j);
|
||||
}
|
||||
|
||||
SECTION("[false, null, true, 1.0]")
|
||||
{
|
||||
json j = {false, nullptr, true, 1.0};
|
||||
std::vector<uint8_t> expected = {0x84, 0xF8, 0xFA, 0xF9, 0xFD};
|
||||
const auto result = json::to_bon8(j);
|
||||
CHECK(result == expected);
|
||||
CHECK(json::from_bon8(result) == j);
|
||||
}
|
||||
|
||||
SECTION("[\"s\", \"s\"]")
|
||||
{
|
||||
json j = {"s", "s"};
|
||||
std::vector<uint8_t> expected = {0x82, 's', 0xFF, 's', 0xFF};
|
||||
const auto result = json::to_bon8(j);
|
||||
CHECK(result == expected);
|
||||
}
|
||||
|
||||
SECTION("[\"\", \"s\"]")
|
||||
{
|
||||
json j = {"", "s"};
|
||||
std::vector<uint8_t> expected = {0x82, 0xFF, 's', 0xFF};
|
||||
const auto result = json::to_bon8(j);
|
||||
CHECK(result == expected);
|
||||
}
|
||||
|
||||
SECTION("[[[\"foo\"]]]")
|
||||
{
|
||||
json j = R"([[["foo"]]])"_json;
|
||||
std::vector<uint8_t> expected = {0x81, 0x81, 0x81, 'f', 'o', 'o', 0xFF};
|
||||
const auto result = json::to_bon8(j);
|
||||
CHECK(result == expected);
|
||||
CHECK(json::from_bon8(result) == j);
|
||||
}
|
||||
|
||||
SECTION("[[[1]]]")
|
||||
{
|
||||
json j = R"([[[1]]])"_json;
|
||||
std::vector<uint8_t> expected = {0x81, 0x81, 0x81, 0x91};
|
||||
const auto result = json::to_bon8(j);
|
||||
CHECK(result == expected);
|
||||
CHECK(json::from_bon8(result) == j);
|
||||
}
|
||||
|
||||
SECTION("[[[\"\"]]]")
|
||||
{
|
||||
json j = R"([[[""]]])"_json;
|
||||
std::vector<uint8_t> expected = {0x81, 0x81, 0x81, 0xFF};
|
||||
const auto result = json::to_bon8(j);
|
||||
CHECK(result == expected);
|
||||
CHECK(json::from_bon8(result) == j);
|
||||
}
|
||||
}
|
||||
|
||||
SECTION("array without count")
|
||||
{
|
||||
SECTION("[false, null, true, 1.0, [], 0.0]")
|
||||
{
|
||||
json j = {false, nullptr, true, 1.0, json::array(), 0.0};
|
||||
std::vector<uint8_t> expected = {0x85, 0xF8, 0xFA, 0xF9, 0xFD, 0x80, 0xFC, 0xFE};
|
||||
const auto result = json::to_bon8(j);
|
||||
CHECK(result == expected);
|
||||
CHECK(json::from_bon8(result) == j);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
SECTION("object")
|
||||
{
|
||||
SECTION("object with count")
|
||||
{
|
||||
SECTION("empty object")
|
||||
{
|
||||
json j = json::object();
|
||||
std::vector<uint8_t> expected = {0x86};
|
||||
const auto result = json::to_bon8(j);
|
||||
CHECK(result == expected);
|
||||
CHECK(json::from_bon8(result) == j);
|
||||
}
|
||||
|
||||
SECTION("{\"foo\": null}")
|
||||
{
|
||||
json j = {{"foo", nullptr}};
|
||||
std::vector<uint8_t> expected = {0x87, 'f', 'o', 'o', 0xFA};
|
||||
const auto result = json::to_bon8(j);
|
||||
CHECK(result == expected);
|
||||
CHECK(json::from_bon8(result) == j);
|
||||
}
|
||||
|
||||
SECTION("{\"\": true, \"foo\": null}")
|
||||
{
|
||||
json j = {{"", true}, {"foo", nullptr}};
|
||||
std::vector<uint8_t> expected = {0x88, 0xFF, 0xF9, 'f', 'o', 'o', 0xFA};
|
||||
const auto result = json::to_bon8(j);
|
||||
CHECK(result == expected);
|
||||
CHECK(json::from_bon8(result) == j);
|
||||
}
|
||||
|
||||
SECTION("{\"a\": \"\", \"c\": \"d\"}")
|
||||
{
|
||||
json j = {{"a", ""}, {"c", "d"}};
|
||||
std::vector<uint8_t> expected = {0x88, 'a', 0xFF, 0xFF, 'c', 0xFF, 'd', 0xFF};
|
||||
const auto result = json::to_bon8(j);
|
||||
CHECK(result == expected);
|
||||
}
|
||||
|
||||
SECTION("{\"a\": \"b\", \"c\": \"d\"}")
|
||||
{
|
||||
json j = {{"a", "b"}, {"c", "d"}};
|
||||
std::vector<uint8_t> expected = {0x88, 'a', 0xFF, 'b', 0xFF, 'c', 0xFF, 'd', 0xFF};
|
||||
const auto result = json::to_bon8(j);
|
||||
CHECK(result == expected);
|
||||
}
|
||||
}
|
||||
|
||||
SECTION("object without count")
|
||||
{
|
||||
SECTION("{\"one\": 1, \"two\": 2, \"three\": 3, \"four\": 4, \"five\": 5}")
|
||||
{
|
||||
json j = R"({"one": 1, "two": 2, "three": 3, "four": 4, "five": 5})"_json;
|
||||
std::vector<uint8_t> expected = {0x8b, 'f', 'i', 'v', 'e', 0x95, 'f', 'o', 'u', 'r', 0x94, 'o', 'n', 'e', 0x91, 't', 'h', 'r', 'e', 'e', 0x93, 't', 'w', 'o', 0x92, 0xFE};
|
||||
const auto result = json::to_bon8(j);
|
||||
CHECK(result == expected);
|
||||
CHECK(json::from_bon8(result) == j);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
SECTION("SAX aborts")
|
||||
{
|
||||
SECTION("start_array(len)")
|
||||
{
|
||||
std::vector<uint8_t> v = {0x80};
|
||||
SaxCountdown scp(0);
|
||||
CHECK(!json::sax_parse(v, &scp, json::input_format_t::bon8));
|
||||
}
|
||||
|
||||
SECTION("error in array with size")
|
||||
{
|
||||
std::vector<uint8_t> v = {0x81};
|
||||
SaxCountdown scp(1000);
|
||||
CHECK(!json::sax_parse(v, &scp, json::input_format_t::bon8));
|
||||
}
|
||||
|
||||
SECTION("error in array without size")
|
||||
{
|
||||
std::vector<uint8_t> v = {0x85};
|
||||
SaxCountdown scp(1000);
|
||||
CHECK(!json::sax_parse(v, &scp, json::input_format_t::bon8));
|
||||
}
|
||||
|
||||
SECTION("start_object(len)")
|
||||
{
|
||||
std::vector<uint8_t> v = {0x86};
|
||||
SaxCountdown scp(0);
|
||||
CHECK(!json::sax_parse(v, &scp, json::input_format_t::bon8));
|
||||
}
|
||||
|
||||
SECTION("key()")
|
||||
{
|
||||
std::vector<uint8_t> v = {0x87, 'f', 'o', 'o', 0xFF, 0xFA};
|
||||
SaxCountdown scp(1);
|
||||
CHECK(!json::sax_parse(v, &scp, json::input_format_t::bon8));
|
||||
}
|
||||
|
||||
SECTION("error in object with size")
|
||||
{
|
||||
std::vector<uint8_t> v = {0x87, 'f', 'o', 'o', 0xFF};
|
||||
SaxCountdown scp(1000);
|
||||
CHECK(!json::sax_parse(v, &scp, json::input_format_t::bon8));
|
||||
}
|
||||
|
||||
SECTION("error in object without size")
|
||||
{
|
||||
std::vector<uint8_t> v = {0x8B, 'f', 'o', 'o', 0xFF};
|
||||
SaxCountdown scp(1000);
|
||||
CHECK(!json::sax_parse(v, &scp, json::input_format_t::bon8));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,97 @@
|
||||
/*
|
||||
__ _____ _____ _____
|
||||
__| | __| | | | JSON for Modern C++ (test suite)
|
||||
| | |__ | | | | | | version 3.10.5
|
||||
|_____|_____|_____|_|___| https://github.com/nlohmann/json
|
||||
|
||||
Licensed under the MIT License <http://opensource.org/licenses/MIT>.
|
||||
SPDX-License-Identifier: MIT
|
||||
Copyright (c) 2013-2022 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 "doctest_compatibility.h"
|
||||
|
||||
#include <nlohmann/json.hpp>
|
||||
using nlohmann::json;
|
||||
|
||||
TEST_CASE("byte_container_with_subtype")
|
||||
{
|
||||
using subtype_type = nlohmann::byte_container_with_subtype<std::vector<std::uint8_t>>::subtype_type;
|
||||
|
||||
SECTION("empty container")
|
||||
{
|
||||
nlohmann::byte_container_with_subtype<std::vector<std::uint8_t>> container;
|
||||
|
||||
CHECK(!container.has_subtype());
|
||||
CHECK(container.subtype() == static_cast<subtype_type>(-1));
|
||||
|
||||
container.clear_subtype();
|
||||
CHECK(!container.has_subtype());
|
||||
CHECK(container.subtype() == static_cast<subtype_type>(-1));
|
||||
|
||||
container.set_subtype(42);
|
||||
CHECK(container.has_subtype());
|
||||
CHECK(container.subtype() == 42);
|
||||
}
|
||||
|
||||
SECTION("subtyped container")
|
||||
{
|
||||
nlohmann::byte_container_with_subtype<std::vector<std::uint8_t>> container({}, 42);
|
||||
CHECK(container.has_subtype());
|
||||
CHECK(container.subtype() == 42);
|
||||
|
||||
container.clear_subtype();
|
||||
CHECK(!container.has_subtype());
|
||||
CHECK(container.subtype() == static_cast<subtype_type>(-1));
|
||||
}
|
||||
|
||||
SECTION("comparisons")
|
||||
{
|
||||
std::vector<std::uint8_t> bytes = {{0xCA, 0xFE, 0xBA, 0xBE}};
|
||||
nlohmann::byte_container_with_subtype<std::vector<std::uint8_t>> container1;
|
||||
nlohmann::byte_container_with_subtype<std::vector<std::uint8_t>> container2({}, 42);
|
||||
nlohmann::byte_container_with_subtype<std::vector<std::uint8_t>> container3(bytes);
|
||||
nlohmann::byte_container_with_subtype<std::vector<std::uint8_t>> container4(bytes, 42);
|
||||
|
||||
CHECK(container1 == container1);
|
||||
CHECK(container1 != container2);
|
||||
CHECK(container1 != container3);
|
||||
CHECK(container1 != container4);
|
||||
CHECK(container2 != container1);
|
||||
CHECK(container2 == container2);
|
||||
CHECK(container2 != container3);
|
||||
CHECK(container2 != container4);
|
||||
CHECK(container3 != container1);
|
||||
CHECK(container3 != container2);
|
||||
CHECK(container3 == container3);
|
||||
CHECK(container3 != container4);
|
||||
CHECK(container4 != container1);
|
||||
CHECK(container4 != container2);
|
||||
CHECK(container4 != container3);
|
||||
CHECK(container4 == container4);
|
||||
|
||||
container3.clear();
|
||||
container4.clear();
|
||||
|
||||
CHECK(container1 == container3);
|
||||
CHECK(container2 == container4);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,563 @@
|
||||
/*
|
||||
__ _____ _____ _____
|
||||
__| | __| | | | JSON for Modern C++ (test suite)
|
||||
| | |__ | | | | | | version 3.10.5
|
||||
|_____|_____|_____|_|___| https://github.com/nlohmann/json
|
||||
|
||||
Licensed under the MIT License <http://opensource.org/licenses/MIT>.
|
||||
SPDX-License-Identifier: MIT
|
||||
Copyright (c) 2013-2022 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 "doctest_compatibility.h"
|
||||
|
||||
#include <nlohmann/json.hpp>
|
||||
using nlohmann::json;
|
||||
|
||||
TEST_CASE("capacity")
|
||||
{
|
||||
SECTION("empty()")
|
||||
{
|
||||
SECTION("boolean")
|
||||
{
|
||||
json j = true;
|
||||
const json j_const(j);
|
||||
|
||||
SECTION("result of empty")
|
||||
{
|
||||
CHECK(j.empty() == false);
|
||||
CHECK(j_const.empty() == false);
|
||||
}
|
||||
|
||||
SECTION("definition of empty")
|
||||
{
|
||||
CHECK(j.empty() == (j.begin() == j.end()));
|
||||
CHECK(j_const.empty() == (j_const.begin() == j_const.end()));
|
||||
}
|
||||
}
|
||||
|
||||
SECTION("string")
|
||||
{
|
||||
json j = "hello world";
|
||||
const json j_const(j);
|
||||
|
||||
SECTION("result of empty")
|
||||
{
|
||||
CHECK(j.empty() == false);
|
||||
CHECK(j_const.empty() == false);
|
||||
}
|
||||
|
||||
SECTION("definition of empty")
|
||||
{
|
||||
CHECK(j.empty() == (j.begin() == j.end()));
|
||||
CHECK(j_const.empty() == (j_const.begin() == j_const.end()));
|
||||
}
|
||||
}
|
||||
|
||||
SECTION("array")
|
||||
{
|
||||
SECTION("empty array")
|
||||
{
|
||||
json j = json::array();
|
||||
const json j_const(j);
|
||||
|
||||
SECTION("result of empty")
|
||||
{
|
||||
CHECK(j.empty() == true);
|
||||
CHECK(j_const.empty() == true);
|
||||
}
|
||||
|
||||
SECTION("definition of empty")
|
||||
{
|
||||
CHECK(j.empty() == (j.begin() == j.end()));
|
||||
CHECK(j_const.empty() == (j_const.begin() == j_const.end()));
|
||||
}
|
||||
}
|
||||
|
||||
SECTION("filled array")
|
||||
{
|
||||
json j = {1, 2, 3};
|
||||
const json j_const(j);
|
||||
|
||||
SECTION("result of empty")
|
||||
{
|
||||
CHECK(j.empty() == false);
|
||||
CHECK(j_const.empty() == false);
|
||||
}
|
||||
|
||||
SECTION("definition of empty")
|
||||
{
|
||||
CHECK(j.empty() == (j.begin() == j.end()));
|
||||
CHECK(j_const.empty() == (j_const.begin() == j_const.end()));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
SECTION("object")
|
||||
{
|
||||
SECTION("empty object")
|
||||
{
|
||||
json j = json::object();
|
||||
const json j_const(j);
|
||||
|
||||
SECTION("result of empty")
|
||||
{
|
||||
CHECK(j.empty() == true);
|
||||
CHECK(j_const.empty() == true);
|
||||
}
|
||||
|
||||
SECTION("definition of empty")
|
||||
{
|
||||
CHECK(j.empty() == (j.begin() == j.end()));
|
||||
CHECK(j_const.empty() == (j_const.begin() == j_const.end()));
|
||||
}
|
||||
}
|
||||
|
||||
SECTION("filled object")
|
||||
{
|
||||
json j = {{"one", 1}, {"two", 2}, {"three", 3}};
|
||||
const json j_const(j);
|
||||
|
||||
SECTION("result of empty")
|
||||
{
|
||||
CHECK(j.empty() == false);
|
||||
CHECK(j_const.empty() == false);
|
||||
}
|
||||
|
||||
SECTION("definition of empty")
|
||||
{
|
||||
CHECK(j.empty() == (j.begin() == j.end()));
|
||||
CHECK(j_const.empty() == (j_const.begin() == j_const.end()));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
SECTION("number (integer)")
|
||||
{
|
||||
json j = -23;
|
||||
const json j_const(j);
|
||||
|
||||
SECTION("result of empty")
|
||||
{
|
||||
CHECK(j.empty() == false);
|
||||
CHECK(j_const.empty() == false);
|
||||
}
|
||||
|
||||
SECTION("definition of empty")
|
||||
{
|
||||
CHECK(j.empty() == (j.begin() == j.end()));
|
||||
CHECK(j_const.empty() == (j_const.begin() == j_const.end()));
|
||||
}
|
||||
}
|
||||
|
||||
SECTION("number (unsigned)")
|
||||
{
|
||||
json j = 23u;
|
||||
const json j_const(j);
|
||||
|
||||
SECTION("result of empty")
|
||||
{
|
||||
CHECK(j.empty() == false);
|
||||
CHECK(j_const.empty() == false);
|
||||
}
|
||||
|
||||
SECTION("definition of empty")
|
||||
{
|
||||
CHECK(j.empty() == (j.begin() == j.end()));
|
||||
CHECK(j_const.empty() == (j_const.begin() == j_const.end()));
|
||||
}
|
||||
}
|
||||
|
||||
SECTION("number (float)")
|
||||
{
|
||||
json j = 23.42;
|
||||
const json j_const(j);
|
||||
|
||||
SECTION("result of empty")
|
||||
{
|
||||
CHECK(j.empty() == false);
|
||||
CHECK(j_const.empty() == false);
|
||||
}
|
||||
|
||||
SECTION("definition of empty")
|
||||
{
|
||||
CHECK(j.empty() == (j.begin() == j.end()));
|
||||
CHECK(j_const.empty() == (j_const.begin() == j_const.end()));
|
||||
}
|
||||
}
|
||||
|
||||
SECTION("null")
|
||||
{
|
||||
json j = nullptr;
|
||||
const json j_const(j);
|
||||
|
||||
SECTION("result of empty")
|
||||
{
|
||||
CHECK(j.empty() == true);
|
||||
CHECK(j_const.empty() == true);
|
||||
}
|
||||
|
||||
SECTION("definition of empty")
|
||||
{
|
||||
CHECK(j.empty() == (j.begin() == j.end()));
|
||||
CHECK(j_const.empty() == (j_const.begin() == j_const.end()));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
SECTION("size()")
|
||||
{
|
||||
SECTION("boolean")
|
||||
{
|
||||
json j = true;
|
||||
const 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";
|
||||
const 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();
|
||||
const 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};
|
||||
const 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();
|
||||
const 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}};
|
||||
const 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;
|
||||
const 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;
|
||||
const 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;
|
||||
const 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;
|
||||
const 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;
|
||||
const json j_const = true;
|
||||
|
||||
SECTION("result of max_size")
|
||||
{
|
||||
CHECK(j.max_size() == 1);
|
||||
CHECK(j_const.max_size() == 1);
|
||||
}
|
||||
}
|
||||
|
||||
SECTION("string")
|
||||
{
|
||||
json j = "hello world";
|
||||
const json j_const = "hello world";
|
||||
|
||||
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();
|
||||
const json j_const = json::array();
|
||||
|
||||
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};
|
||||
const json j_const = {1, 2, 3};
|
||||
|
||||
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();
|
||||
const json j_const = json::object();
|
||||
|
||||
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}};
|
||||
const json j_const = {{"one", 1}, {"two", 2}, {"three", 3}};
|
||||
|
||||
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;
|
||||
const json j_const = -23;
|
||||
|
||||
SECTION("result of max_size")
|
||||
{
|
||||
CHECK(j.max_size() == 1);
|
||||
CHECK(j_const.max_size() == 1);
|
||||
}
|
||||
}
|
||||
|
||||
SECTION("number (unsigned)")
|
||||
{
|
||||
json j = 23u;
|
||||
const json j_const = 23u;
|
||||
|
||||
SECTION("result of max_size")
|
||||
{
|
||||
CHECK(j.max_size() == 1);
|
||||
CHECK(j_const.max_size() == 1);
|
||||
}
|
||||
}
|
||||
|
||||
SECTION("number (float)")
|
||||
{
|
||||
json j = 23.42;
|
||||
const json j_const = 23.42;
|
||||
|
||||
SECTION("result of max_size")
|
||||
{
|
||||
CHECK(j.max_size() == 1);
|
||||
CHECK(j_const.max_size() == 1);
|
||||
}
|
||||
}
|
||||
|
||||
SECTION("null")
|
||||
{
|
||||
json j = nullptr;
|
||||
const json j_const = nullptr;
|
||||
|
||||
SECTION("result of max_size")
|
||||
{
|
||||
CHECK(j.max_size() == 0);
|
||||
CHECK(j_const.max_size() == 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,414 @@
|
||||
/*
|
||||
__ _____ _____ _____
|
||||
__| | __| | | | JSON for Modern C++ (test suite)
|
||||
| | |__ | | | | | | version 3.10.5
|
||||
|_____|_____|_____|_|___| https://github.com/nlohmann/json
|
||||
|
||||
Licensed under the MIT License <http://opensource.org/licenses/MIT>.
|
||||
SPDX-License-Identifier: MIT
|
||||
Copyright (c) 2013-2022 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 "doctest_compatibility.h"
|
||||
|
||||
#define JSON_TESTS_PRIVATE
|
||||
#include <nlohmann/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("copy constructor from non-const iterator")
|
||||
{
|
||||
SECTION("create from uninitialized iterator")
|
||||
{
|
||||
const json::iterator it {};
|
||||
json::const_iterator cit(it);
|
||||
}
|
||||
|
||||
SECTION("create from initialized iterator")
|
||||
{
|
||||
json j;
|
||||
const json::iterator it = j.begin();
|
||||
json::const_iterator cit(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_WITH_AS(*it, "[json.exception.invalid_iterator.214] cannot get value", json::invalid_iterator&);
|
||||
}
|
||||
|
||||
SECTION("number")
|
||||
{
|
||||
json j(17);
|
||||
json::const_iterator it = j.cbegin();
|
||||
CHECK(*it == json(17));
|
||||
it = j.cend();
|
||||
CHECK_THROWS_WITH_AS(*it, "[json.exception.invalid_iterator.214] cannot get value", json::invalid_iterator&);
|
||||
}
|
||||
|
||||
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_WITH_AS(std::string(it->type_name()), "[json.exception.invalid_iterator.214] cannot get value", json::invalid_iterator&);
|
||||
}
|
||||
|
||||
SECTION("number")
|
||||
{
|
||||
json j(17);
|
||||
json::const_iterator it = j.cbegin();
|
||||
CHECK(std::string(it->type_name()) == "number");
|
||||
it = j.cend();
|
||||
CHECK_THROWS_WITH_AS(std::string(it->type_name()), "[json.exception.invalid_iterator.214] cannot get value", json::invalid_iterator&);
|
||||
}
|
||||
|
||||
SECTION("object")
|
||||
{
|
||||
json j({{"foo", "bar"}});
|
||||
json::const_iterator it = j.cbegin();
|
||||
CHECK(std::string(it->type_name()) == "string");
|
||||
}
|
||||
|
||||
SECTION("array")
|
||||
{
|
||||
json j({1, 2, 3, 4});
|
||||
json::const_iterator it = j.cbegin();
|
||||
CHECK(std::string(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.m_it == 1));
|
||||
it++;
|
||||
CHECK((it.m_it.primitive_iterator.m_it != 0 && it.m_it.primitive_iterator.m_it != 1));
|
||||
}
|
||||
|
||||
SECTION("number")
|
||||
{
|
||||
json j(17);
|
||||
json::const_iterator it = j.cbegin();
|
||||
CHECK((it.m_it.primitive_iterator.m_it == 0));
|
||||
it++;
|
||||
CHECK((it.m_it.primitive_iterator.m_it == 1));
|
||||
it++;
|
||||
CHECK((it.m_it.primitive_iterator.m_it != 0 && it.m_it.primitive_iterator.m_it != 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.m_it == 1));
|
||||
++it;
|
||||
CHECK((it.m_it.primitive_iterator.m_it != 0 && it.m_it.primitive_iterator.m_it != 1));
|
||||
}
|
||||
|
||||
SECTION("number")
|
||||
{
|
||||
json j(17);
|
||||
json::const_iterator it = j.cbegin();
|
||||
CHECK((it.m_it.primitive_iterator.m_it == 0));
|
||||
++it;
|
||||
CHECK((it.m_it.primitive_iterator.m_it == 1));
|
||||
++it;
|
||||
CHECK((it.m_it.primitive_iterator.m_it != 0 && it.m_it.primitive_iterator.m_it != 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.m_it == 1));
|
||||
}
|
||||
|
||||
SECTION("number")
|
||||
{
|
||||
json j(17);
|
||||
json::const_iterator it = j.cend();
|
||||
CHECK((it.m_it.primitive_iterator.m_it == 1));
|
||||
it--;
|
||||
CHECK((it.m_it.primitive_iterator.m_it == 0));
|
||||
it--;
|
||||
CHECK((it.m_it.primitive_iterator.m_it != 0 && it.m_it.primitive_iterator.m_it != 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.m_it == 1));
|
||||
}
|
||||
|
||||
SECTION("number")
|
||||
{
|
||||
json j(17);
|
||||
json::const_iterator it = j.cend();
|
||||
CHECK((it.m_it.primitive_iterator.m_it == 1));
|
||||
--it;
|
||||
CHECK((it.m_it.primitive_iterator.m_it == 0));
|
||||
--it;
|
||||
CHECK((it.m_it.primitive_iterator.m_it != 0 && it.m_it.primitive_iterator.m_it != 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()));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,489 @@
|
||||
/*
|
||||
__ _____ _____ _____
|
||||
__| | __| | | | JSON for Modern C++ (test suite)
|
||||
| | |__ | | | | | | version 3.10.5
|
||||
|_____|_____|_____|_|___| https://github.com/nlohmann/json
|
||||
|
||||
Licensed under the MIT License <http://opensource.org/licenses/MIT>.
|
||||
SPDX-License-Identifier: MIT
|
||||
Copyright (c) 2013-2022 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 "doctest_compatibility.h"
|
||||
|
||||
#define JSON_TESTS_PRIVATE
|
||||
#include <nlohmann/json.hpp>
|
||||
using nlohmann::json;
|
||||
|
||||
template<typename Iter>
|
||||
using can_post_increment_temporary = decltype((std::declval<Iter>()++)++);
|
||||
|
||||
template<typename Iter>
|
||||
using can_post_decrement_temporary = decltype((std::declval<Iter>()--)--);
|
||||
|
||||
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_WITH_AS(*it, "[json.exception.invalid_iterator.214] cannot get value", json::invalid_iterator&);
|
||||
}
|
||||
|
||||
SECTION("number")
|
||||
{
|
||||
json j(17);
|
||||
json::iterator it = j.begin();
|
||||
CHECK(*it == json(17));
|
||||
it = j.end();
|
||||
CHECK_THROWS_WITH_AS(*it, "[json.exception.invalid_iterator.214] cannot get value", json::invalid_iterator&);
|
||||
}
|
||||
|
||||
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_WITH_AS(std::string(it->type_name()), "[json.exception.invalid_iterator.214] cannot get value", json::invalid_iterator&);
|
||||
}
|
||||
|
||||
SECTION("number")
|
||||
{
|
||||
json j(17);
|
||||
json::iterator it = j.begin();
|
||||
CHECK(std::string(it->type_name()) == "number");
|
||||
it = j.end();
|
||||
CHECK_THROWS_WITH_AS(std::string(it->type_name()), "[json.exception.invalid_iterator.214] cannot get value", json::invalid_iterator&);
|
||||
}
|
||||
|
||||
SECTION("object")
|
||||
{
|
||||
json j({{"foo", "bar"}});
|
||||
json::iterator it = j.begin();
|
||||
CHECK(std::string(it->type_name()) == "string");
|
||||
}
|
||||
|
||||
SECTION("array")
|
||||
{
|
||||
json j({1, 2, 3, 4});
|
||||
json::iterator it = j.begin();
|
||||
CHECK(std::string(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.m_it == 1));
|
||||
it++;
|
||||
CHECK((it.m_it.primitive_iterator.m_it != 0 && it.m_it.primitive_iterator.m_it != 1));
|
||||
}
|
||||
|
||||
SECTION("number")
|
||||
{
|
||||
json j(17);
|
||||
json::iterator it = j.begin();
|
||||
CHECK((it.m_it.primitive_iterator.m_it == 0));
|
||||
it++;
|
||||
CHECK((it.m_it.primitive_iterator.m_it == 1));
|
||||
it++;
|
||||
CHECK((it.m_it.primitive_iterator.m_it != 0 && it.m_it.primitive_iterator.m_it != 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.m_it == 1));
|
||||
++it;
|
||||
CHECK((it.m_it.primitive_iterator.m_it != 0 && it.m_it.primitive_iterator.m_it != 1));
|
||||
}
|
||||
|
||||
SECTION("number")
|
||||
{
|
||||
json j(17);
|
||||
json::iterator it = j.begin();
|
||||
CHECK((it.m_it.primitive_iterator.m_it == 0));
|
||||
++it;
|
||||
CHECK((it.m_it.primitive_iterator.m_it == 1));
|
||||
++it;
|
||||
CHECK((it.m_it.primitive_iterator.m_it != 0 && it.m_it.primitive_iterator.m_it != 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.m_it == 1));
|
||||
}
|
||||
|
||||
SECTION("number")
|
||||
{
|
||||
json j(17);
|
||||
json::iterator it = j.end();
|
||||
CHECK((it.m_it.primitive_iterator.m_it == 1));
|
||||
it--;
|
||||
CHECK((it.m_it.primitive_iterator.m_it == 0));
|
||||
it--;
|
||||
CHECK((it.m_it.primitive_iterator.m_it != 0 && it.m_it.primitive_iterator.m_it != 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.m_it == 1));
|
||||
}
|
||||
|
||||
SECTION("number")
|
||||
{
|
||||
json j(17);
|
||||
json::iterator it = j.end();
|
||||
CHECK((it.m_it.primitive_iterator.m_it == 1));
|
||||
--it;
|
||||
CHECK((it.m_it.primitive_iterator.m_it == 0));
|
||||
--it;
|
||||
CHECK((it.m_it.primitive_iterator.m_it != 0 && it.m_it.primitive_iterator.m_it != 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("equality-preserving")
|
||||
{
|
||||
SECTION("post-increment")
|
||||
{
|
||||
SECTION("primitive_iterator_t")
|
||||
{
|
||||
using Iter = nlohmann::detail::primitive_iterator_t;
|
||||
CHECK(std::is_same < decltype(std::declval<Iter&>()++), Iter >::value);
|
||||
}
|
||||
SECTION("iter_impl")
|
||||
{
|
||||
using Iter = nlohmann::detail::iter_impl<json>;
|
||||
CHECK(std::is_same < decltype(std::declval<Iter&>()++), Iter >::value);
|
||||
}
|
||||
SECTION("json_reverse_iterator")
|
||||
{
|
||||
using Base = nlohmann::detail::iter_impl<json>;
|
||||
using Iter = nlohmann::detail::json_reverse_iterator<Base>;
|
||||
CHECK(std::is_same < decltype(std::declval<Iter&>()++), Iter >::value);
|
||||
}
|
||||
}
|
||||
SECTION("post-decrement")
|
||||
{
|
||||
SECTION("primitive_iterator_t")
|
||||
{
|
||||
using Iter = nlohmann::detail::primitive_iterator_t;
|
||||
CHECK(std::is_same < decltype(std::declval<Iter&>()--), Iter >::value);
|
||||
}
|
||||
SECTION("iter_impl")
|
||||
{
|
||||
using Iter = nlohmann::detail::iter_impl<json>;
|
||||
CHECK(std::is_same < decltype(std::declval<Iter&>()--), Iter >::value );
|
||||
}
|
||||
SECTION("json_reverse_iterator")
|
||||
{
|
||||
using Base = nlohmann::detail::iter_impl<json>;
|
||||
using Iter = nlohmann::detail::json_reverse_iterator<Base>;
|
||||
CHECK(std::is_same < decltype(std::declval<Iter&>()--), Iter >::value );
|
||||
}
|
||||
}
|
||||
}
|
||||
// prevent "accidental mutation of a temporary object"
|
||||
SECTION("cert-dcl21-cpp")
|
||||
{
|
||||
using nlohmann::detail::is_detected;
|
||||
SECTION("post-increment")
|
||||
{
|
||||
SECTION("primitive_iterator_t")
|
||||
{
|
||||
using Iter = nlohmann::detail::primitive_iterator_t;
|
||||
CHECK_FALSE(is_detected<can_post_increment_temporary, Iter&>::value);
|
||||
}
|
||||
SECTION("iter_impl")
|
||||
{
|
||||
using Iter = nlohmann::detail::iter_impl<json>;
|
||||
CHECK_FALSE(is_detected<can_post_increment_temporary, Iter&>::value);
|
||||
}
|
||||
SECTION("json_reverse_iterator")
|
||||
{
|
||||
using Base = nlohmann::detail::iter_impl<json>;
|
||||
using Iter = nlohmann::detail::json_reverse_iterator<Base>;
|
||||
CHECK_FALSE(is_detected<can_post_increment_temporary, Iter&>::value);
|
||||
}
|
||||
}
|
||||
SECTION("post-decrement")
|
||||
{
|
||||
SECTION("primitive_iterator_t")
|
||||
{
|
||||
using Iter = nlohmann::detail::primitive_iterator_t;
|
||||
CHECK_FALSE(is_detected<can_post_decrement_temporary, Iter&>::value);
|
||||
}
|
||||
SECTION("iter_impl")
|
||||
{
|
||||
using Iter = nlohmann::detail::iter_impl<json>;
|
||||
CHECK_FALSE(is_detected<can_post_decrement_temporary, Iter&>::value);
|
||||
}
|
||||
SECTION("json_reverse_iterator")
|
||||
{
|
||||
using Base = nlohmann::detail::iter_impl<json>;
|
||||
using Iter = nlohmann::detail::json_reverse_iterator<Base>;
|
||||
CHECK_FALSE(is_detected<can_post_decrement_temporary, Iter&>::value);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,247 @@
|
||||
/*
|
||||
__ _____ _____ _____
|
||||
__| | __| | | | JSON for Modern C++ (test suite)
|
||||
| | |__ | | | | | | version 3.10.5
|
||||
|_____|_____|_____|_|___| https://github.com/nlohmann/json
|
||||
|
||||
Licensed under the MIT License <http://opensource.org/licenses/MIT>.
|
||||
SPDX-License-Identifier: MIT
|
||||
Copyright (c) 2013-2022 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 "doctest_compatibility.h"
|
||||
|
||||
#define JSON_TESTS_PRIVATE
|
||||
#include <nlohmann/json.hpp>
|
||||
using nlohmann::json;
|
||||
|
||||
namespace
|
||||
{
|
||||
// shortcut to scan a string literal
|
||||
json::lexer::token_type scan_string(const char* s, bool ignore_comments = false);
|
||||
json::lexer::token_type scan_string(const char* s, const bool ignore_comments)
|
||||
{
|
||||
auto ia = nlohmann::detail::input_adapter(s);
|
||||
return nlohmann::detail::lexer<json, decltype(ia)>(std::move(ia), ignore_comments).scan(); // NOLINT(hicpp-move-const-arg,performance-move-const-arg)
|
||||
}
|
||||
} // namespace
|
||||
|
||||
std::string get_error_message(const char* s, bool ignore_comments = false);
|
||||
std::string get_error_message(const char* s, const bool ignore_comments)
|
||||
{
|
||||
auto ia = nlohmann::detail::input_adapter(s);
|
||||
auto lexer = nlohmann::detail::lexer<json, decltype(ia)>(std::move(ia), ignore_comments); // NOLINT(hicpp-move-const-arg,performance-move-const-arg)
|
||||
lexer.scan();
|
||||
return lexer.get_error_message();
|
||||
}
|
||||
|
||||
TEST_CASE("lexer class")
|
||||
{
|
||||
SECTION("scan")
|
||||
{
|
||||
SECTION("structural characters")
|
||||
{
|
||||
CHECK((scan_string("[") == json::lexer::token_type::begin_array));
|
||||
CHECK((scan_string("]") == json::lexer::token_type::end_array));
|
||||
CHECK((scan_string("{") == json::lexer::token_type::begin_object));
|
||||
CHECK((scan_string("}") == json::lexer::token_type::end_object));
|
||||
CHECK((scan_string(",") == json::lexer::token_type::value_separator));
|
||||
CHECK((scan_string(":") == json::lexer::token_type::name_separator));
|
||||
}
|
||||
|
||||
SECTION("literal names")
|
||||
{
|
||||
CHECK((scan_string("null") == json::lexer::token_type::literal_null));
|
||||
CHECK((scan_string("true") == json::lexer::token_type::literal_true));
|
||||
CHECK((scan_string("false") == json::lexer::token_type::literal_false));
|
||||
}
|
||||
|
||||
SECTION("numbers")
|
||||
{
|
||||
CHECK((scan_string("0") == json::lexer::token_type::value_unsigned));
|
||||
CHECK((scan_string("1") == json::lexer::token_type::value_unsigned));
|
||||
CHECK((scan_string("2") == json::lexer::token_type::value_unsigned));
|
||||
CHECK((scan_string("3") == json::lexer::token_type::value_unsigned));
|
||||
CHECK((scan_string("4") == json::lexer::token_type::value_unsigned));
|
||||
CHECK((scan_string("5") == json::lexer::token_type::value_unsigned));
|
||||
CHECK((scan_string("6") == json::lexer::token_type::value_unsigned));
|
||||
CHECK((scan_string("7") == json::lexer::token_type::value_unsigned));
|
||||
CHECK((scan_string("8") == json::lexer::token_type::value_unsigned));
|
||||
CHECK((scan_string("9") == json::lexer::token_type::value_unsigned));
|
||||
|
||||
CHECK((scan_string("-0") == json::lexer::token_type::value_integer));
|
||||
CHECK((scan_string("-1") == json::lexer::token_type::value_integer));
|
||||
|
||||
CHECK((scan_string("1.1") == json::lexer::token_type::value_float));
|
||||
CHECK((scan_string("-1.1") == json::lexer::token_type::value_float));
|
||||
CHECK((scan_string("1E10") == json::lexer::token_type::value_float));
|
||||
}
|
||||
|
||||
SECTION("whitespace")
|
||||
{
|
||||
// result is end_of_input, because not token is following
|
||||
CHECK((scan_string(" ") == json::lexer::token_type::end_of_input));
|
||||
CHECK((scan_string("\t") == json::lexer::token_type::end_of_input));
|
||||
CHECK((scan_string("\n") == json::lexer::token_type::end_of_input));
|
||||
CHECK((scan_string("\r") == json::lexer::token_type::end_of_input));
|
||||
CHECK((scan_string(" \t\n\r\n\t ") == json::lexer::token_type::end_of_input));
|
||||
}
|
||||
}
|
||||
|
||||
SECTION("token_type_name")
|
||||
{
|
||||
CHECK((std::string(json::lexer::token_type_name(json::lexer::token_type::uninitialized)) == "<uninitialized>"));
|
||||
CHECK((std::string(json::lexer::token_type_name(json::lexer::token_type::literal_true)) == "true literal"));
|
||||
CHECK((std::string(json::lexer::token_type_name(json::lexer::token_type::literal_false)) == "false literal"));
|
||||
CHECK((std::string(json::lexer::token_type_name(json::lexer::token_type::literal_null)) == "null literal"));
|
||||
CHECK((std::string(json::lexer::token_type_name(json::lexer::token_type::value_string)) == "string literal"));
|
||||
CHECK((std::string(json::lexer::token_type_name(json::lexer::token_type::value_unsigned)) == "number literal"));
|
||||
CHECK((std::string(json::lexer::token_type_name(json::lexer::token_type::value_integer)) == "number literal"));
|
||||
CHECK((std::string(json::lexer::token_type_name(json::lexer::token_type::value_float)) == "number literal"));
|
||||
CHECK((std::string(json::lexer::token_type_name(json::lexer::token_type::begin_array)) == "'['"));
|
||||
CHECK((std::string(json::lexer::token_type_name(json::lexer::token_type::begin_object)) == "'{'"));
|
||||
CHECK((std::string(json::lexer::token_type_name(json::lexer::token_type::end_array)) == "']'"));
|
||||
CHECK((std::string(json::lexer::token_type_name(json::lexer::token_type::end_object)) == "'}'"));
|
||||
CHECK((std::string(json::lexer::token_type_name(json::lexer::token_type::name_separator)) == "':'"));
|
||||
CHECK((std::string(json::lexer::token_type_name(json::lexer::token_type::value_separator)) == "','"));
|
||||
CHECK((std::string(json::lexer::token_type_name(json::lexer::token_type::parse_error)) == "<parse error>"));
|
||||
CHECK((std::string(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)
|
||||
{
|
||||
// create string from the ASCII code
|
||||
const auto s = std::string(1, static_cast<char>(c));
|
||||
// store scan() result
|
||||
const auto res = scan_string(s.c_str());
|
||||
|
||||
CAPTURE(s)
|
||||
|
||||
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((res != json::lexer::token_type::parse_error));
|
||||
break;
|
||||
}
|
||||
|
||||
// whitespace
|
||||
case (' '):
|
||||
case ('\t'):
|
||||
case ('\n'):
|
||||
case ('\r'):
|
||||
{
|
||||
CHECK((res == json::lexer::token_type::end_of_input));
|
||||
break;
|
||||
}
|
||||
|
||||
// anything else is not expected
|
||||
default:
|
||||
{
|
||||
CHECK((res == json::lexer::token_type::parse_error));
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
SECTION("very large string")
|
||||
{
|
||||
// strings larger than 1024 bytes yield a resize of the lexer's yytext buffer
|
||||
std::string s("\"");
|
||||
s += std::string(2048, 'x');
|
||||
s += "\"";
|
||||
CHECK((scan_string(s.c_str()) == json::lexer::token_type::value_string));
|
||||
}
|
||||
|
||||
SECTION("fail on comments")
|
||||
{
|
||||
CHECK((scan_string("/", false) == json::lexer::token_type::parse_error));
|
||||
CHECK(get_error_message("/", false) == "invalid literal");
|
||||
|
||||
CHECK((scan_string("/!", false) == json::lexer::token_type::parse_error));
|
||||
CHECK(get_error_message("/!", false) == "invalid literal");
|
||||
CHECK((scan_string("/*", false) == json::lexer::token_type::parse_error));
|
||||
CHECK(get_error_message("/*", false) == "invalid literal");
|
||||
CHECK((scan_string("/**", false) == json::lexer::token_type::parse_error));
|
||||
CHECK(get_error_message("/**", false) == "invalid literal");
|
||||
|
||||
CHECK((scan_string("//", false) == json::lexer::token_type::parse_error));
|
||||
CHECK(get_error_message("//", false) == "invalid literal");
|
||||
CHECK((scan_string("/**/", false) == json::lexer::token_type::parse_error));
|
||||
CHECK(get_error_message("/**/", false) == "invalid literal");
|
||||
CHECK((scan_string("/** /", false) == json::lexer::token_type::parse_error));
|
||||
CHECK(get_error_message("/** /", false) == "invalid literal");
|
||||
|
||||
CHECK((scan_string("/***/", false) == json::lexer::token_type::parse_error));
|
||||
CHECK(get_error_message("/***/", false) == "invalid literal");
|
||||
CHECK((scan_string("/* true */", false) == json::lexer::token_type::parse_error));
|
||||
CHECK(get_error_message("/* true */", false) == "invalid literal");
|
||||
CHECK((scan_string("/*/**/", false) == json::lexer::token_type::parse_error));
|
||||
CHECK(get_error_message("/*/**/", false) == "invalid literal");
|
||||
CHECK((scan_string("/*/* */", false) == json::lexer::token_type::parse_error));
|
||||
CHECK(get_error_message("/*/* */", false) == "invalid literal");
|
||||
}
|
||||
|
||||
SECTION("ignore comments")
|
||||
{
|
||||
CHECK((scan_string("/", true) == json::lexer::token_type::parse_error));
|
||||
CHECK(get_error_message("/", true) == "invalid comment; expecting '/' or '*' after '/'");
|
||||
|
||||
CHECK((scan_string("/!", true) == json::lexer::token_type::parse_error));
|
||||
CHECK(get_error_message("/!", true) == "invalid comment; expecting '/' or '*' after '/'");
|
||||
CHECK((scan_string("/*", true) == json::lexer::token_type::parse_error));
|
||||
CHECK(get_error_message("/*", true) == "invalid comment; missing closing '*/'");
|
||||
CHECK((scan_string("/**", true) == json::lexer::token_type::parse_error));
|
||||
CHECK(get_error_message("/**", true) == "invalid comment; missing closing '*/'");
|
||||
|
||||
CHECK((scan_string("//", true) == json::lexer::token_type::end_of_input));
|
||||
CHECK((scan_string("/**/", true) == json::lexer::token_type::end_of_input));
|
||||
CHECK((scan_string("/** /", true) == json::lexer::token_type::parse_error));
|
||||
CHECK(get_error_message("/** /", true) == "invalid comment; missing closing '*/'");
|
||||
|
||||
CHECK((scan_string("/***/", true) == json::lexer::token_type::end_of_input));
|
||||
CHECK((scan_string("/* true */", true) == json::lexer::token_type::end_of_input));
|
||||
CHECK((scan_string("/*/**/", true) == json::lexer::token_type::end_of_input));
|
||||
CHECK((scan_string("/*/* */", true) == json::lexer::token_type::end_of_input));
|
||||
|
||||
CHECK((scan_string("//\n//\n", true) == json::lexer::token_type::end_of_input));
|
||||
CHECK((scan_string("/**//**//**/", true) == json::lexer::token_type::end_of_input));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,278 @@
|
||||
/*
|
||||
__ _____ _____ _____
|
||||
__| | __| | | | JSON for Modern C++ (test suite)
|
||||
| | |__ | | | | | | version 3.10.5
|
||||
|_____|_____|_____|_|___| https://github.com/nlohmann/json
|
||||
|
||||
Licensed under the MIT License <http://opensource.org/licenses/MIT>.
|
||||
SPDX-License-Identifier: MIT
|
||||
Copyright (c) 2013-2022 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 "doctest_compatibility.h"
|
||||
|
||||
#include <nlohmann/json.hpp>
|
||||
using nlohmann::json;
|
||||
|
||||
namespace
|
||||
{
|
||||
// helper function to check std::less<json::value_t>
|
||||
// see https://en.cppreference.com/w/cpp/utility/functional/less
|
||||
template <typename A, typename B, typename U = std::less<json::value_t>>
|
||||
bool f(A a, B b, U u = U())
|
||||
{
|
||||
return u(a, b);
|
||||
}
|
||||
} // namespace
|
||||
|
||||
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,
|
||||
json::value_t::binary
|
||||
};
|
||||
|
||||
SECTION("comparison: less")
|
||||
{
|
||||
std::vector<std::vector<bool>> expected =
|
||||
{
|
||||
{false, true, true, true, true, true, true, true, true},
|
||||
{false, false, true, true, true, true, true, true, true},
|
||||
{false, false, false, false, false, true, true, true, true},
|
||||
{false, false, false, false, false, true, true, true, true},
|
||||
{false, false, false, false, false, true, true, true, true},
|
||||
{false, false, false, false, false, false, true, true, true},
|
||||
{false, false, false, false, false, false, false, true, true},
|
||||
{false, false, false, false, false, false, false, false, true},
|
||||
{false, 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]);
|
||||
CHECK(f(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"}}},
|
||||
json::binary({1, 2, 3}), json::binary({1, 2, 4})
|
||||
};
|
||||
|
||||
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, false, false},
|
||||
{true, true, 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, 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, false, false, true, 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, 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, false, false, true, 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},
|
||||
{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, false, false, true, 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, 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, false, false, true, 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, 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, false, false, true, false},
|
||||
{false, 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)
|
||||
CAPTURE(j_values[i])
|
||||
CAPTURE(j_values[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 (const auto& v : j_values)
|
||||
{
|
||||
CHECK( (v == j_discarded) == false);
|
||||
CHECK( (j_discarded == v) == 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]) == !(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) == !(j_null == nullptr));
|
||||
CHECK( (nullptr != j_null) == !(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, true, true},
|
||||
{false, false, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true},
|
||||
{false, false, false, true, true, true, true, true, true, true, false, false, true, true, true, true, true, true},
|
||||
{false, false, false, false, false, false, false, false, true, true, false, false, true, true, true, true, true, true},
|
||||
{false, false, false, true, false, true, false, true, true, true, false, false, true, true, true, true, true, true},
|
||||
{false, false, false, true, false, false, false, true, true, true, false, false, true, true, true, true, true, true},
|
||||
{false, false, false, true, true, true, false, true, true, true, false, false, true, true, true, true, true, true},
|
||||
{false, false, false, true, false, false, false, false, true, true, false, false, true, true, true, true, true, true},
|
||||
{false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, true, true},
|
||||
{false, false, false, false, false, false, false, false, true, false, false, false, false, false, false, false, true, true},
|
||||
{false, false, true, true, true, true, true, true, true, true, false, false, true, true, true, true, true, true},
|
||||
{false, false, true, true, true, true, true, true, true, true, true, false, true, true, true, true, true, true},
|
||||
{false, false, false, false, false, false, false, false, true, true, false, false, false, true, false, false, true, true},
|
||||
{false, false, false, false, false, false, false, false, true, true, false, false, false, false, false, false, true, true},
|
||||
{false, false, false, false, false, false, false, false, true, true, false, false, true, true, false, false, true, true},
|
||||
{false, false, false, false, false, false, false, false, true, true, false, false, true, true, true, false, true, true},
|
||||
{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, false, false, false, false, false, false, false, false, false}
|
||||
};
|
||||
|
||||
for (size_t i = 0; i < j_values.size(); ++i)
|
||||
{
|
||||
for (size_t j = 0; j < j_values.size(); ++j)
|
||||
{
|
||||
// Skip comparing indicies 12 and 13, and 13 and 12 in C++20 pending fix
|
||||
// See issue #3207
|
||||
#if defined(JSON_HAS_CPP_20) || JSON_HAS_THREE_WAY_COMPARISON
|
||||
if ((i == 12 && j == 13) || (i == 13 && j == 12))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
#endif
|
||||
CAPTURE(i)
|
||||
CAPTURE(j)
|
||||
CAPTURE(j_values[i])
|
||||
CAPTURE(j_values[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]) == !(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]) == !(j_values[i] < j_values[j]) );
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,171 @@
|
||||
/*
|
||||
__ _____ _____ _____
|
||||
__| | __| | | | JSON for Modern C++ (test suite)
|
||||
| | |__ | | | | | | version 3.10.5
|
||||
|_____|_____|_____|_|___| https://github.com/nlohmann/json
|
||||
|
||||
Licensed under the MIT License <http://opensource.org/licenses/MIT>.
|
||||
SPDX-License-Identifier: MIT
|
||||
Copyright (c) 2013-2022 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 "doctest_compatibility.h"
|
||||
|
||||
#include <nlohmann/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(static_cast<json::size_type>((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_move_constructible<json>::value);
|
||||
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();
|
||||
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();
|
||||
swap(it1, it2);
|
||||
CHECK(it1 == j.end());
|
||||
CHECK(it2 == j.begin());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,207 @@
|
||||
/*
|
||||
__ _____ _____ _____
|
||||
__| | __| | | | JSON for Modern C++ (test suite)
|
||||
| | |__ | | | | | | version 3.10.5
|
||||
|_____|_____|_____|_|___| https://github.com/nlohmann/json
|
||||
|
||||
Licensed under the MIT License <http://opensource.org/licenses/MIT>.
|
||||
SPDX-License-Identifier: MIT
|
||||
Copyright (c) 2013-2022 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 "doctest_compatibility.h"
|
||||
|
||||
#include <nlohmann/json.hpp>
|
||||
using nlohmann::json;
|
||||
|
||||
TEST_CASE("other constructors and destructor")
|
||||
{
|
||||
SECTION("copy constructor")
|
||||
{
|
||||
SECTION("object")
|
||||
{
|
||||
json j {{"foo", 1}, {"bar", false}};
|
||||
json k(j); // NOLINT(performance-unnecessary-copy-initialization)
|
||||
CHECK(j == k);
|
||||
}
|
||||
|
||||
SECTION("array")
|
||||
{
|
||||
json j {"foo", 1, 42.23, false};
|
||||
json k(j); // NOLINT(performance-unnecessary-copy-initialization)
|
||||
CHECK(j == k);
|
||||
}
|
||||
|
||||
SECTION("null")
|
||||
{
|
||||
json j(nullptr);
|
||||
json k(j); // NOLINT(performance-unnecessary-copy-initialization)
|
||||
CHECK(j == k);
|
||||
}
|
||||
|
||||
SECTION("boolean")
|
||||
{
|
||||
json j(true);
|
||||
json k(j); // NOLINT(performance-unnecessary-copy-initialization)
|
||||
CHECK(j == k);
|
||||
}
|
||||
|
||||
SECTION("string")
|
||||
{
|
||||
json j("Hello world");
|
||||
json k(j); // NOLINT(performance-unnecessary-copy-initialization)
|
||||
CHECK(j == k);
|
||||
}
|
||||
|
||||
SECTION("number (integer)")
|
||||
{
|
||||
json j(42);
|
||||
json k(j); // NOLINT(performance-unnecessary-copy-initialization)
|
||||
CHECK(j == k);
|
||||
}
|
||||
|
||||
SECTION("number (unsigned)")
|
||||
{
|
||||
json j(42u);
|
||||
json k(j); // NOLINT(performance-unnecessary-copy-initialization)
|
||||
CHECK(j == k);
|
||||
}
|
||||
|
||||
SECTION("number (floating-point)")
|
||||
{
|
||||
json j(42.23);
|
||||
json k(j); // NOLINT(performance-unnecessary-copy-initialization)
|
||||
CHECK(j == k);
|
||||
}
|
||||
|
||||
SECTION("binary")
|
||||
{
|
||||
json j = json::binary({1, 2, 3});
|
||||
json k(j); // NOLINT(performance-unnecessary-copy-initialization)
|
||||
CHECK(j == k);
|
||||
}
|
||||
}
|
||||
|
||||
SECTION("move constructor")
|
||||
{
|
||||
json j {{"foo", "bar"}, {"baz", {1, 2, 3, 4}}, {"a", 42u}, {"b", 42.23}, {"c", nullptr}};
|
||||
CHECK(j.type() == json::value_t::object);
|
||||
json k(std::move(j));
|
||||
CHECK(k.type() == json::value_t::object);
|
||||
CHECK(j.type() == json::value_t::null); // NOLINT: access after move is OK here
|
||||
}
|
||||
|
||||
SECTION("copy assignment")
|
||||
{
|
||||
SECTION("object")
|
||||
{
|
||||
json j {{"foo", 1}, {"bar", false}};
|
||||
json k;
|
||||
k = j;
|
||||
CHECK(j == k);
|
||||
}
|
||||
|
||||
SECTION("array")
|
||||
{
|
||||
json j {"foo", 1, 42.23, false};
|
||||
json k;
|
||||
k = j;
|
||||
CHECK(j == k);
|
||||
}
|
||||
|
||||
SECTION("null")
|
||||
{
|
||||
json j(nullptr);
|
||||
json k;
|
||||
k = j;
|
||||
CHECK(j == k);
|
||||
}
|
||||
|
||||
SECTION("boolean")
|
||||
{
|
||||
json j(true);
|
||||
json k;
|
||||
k = j;
|
||||
CHECK(j == k);
|
||||
}
|
||||
|
||||
SECTION("string")
|
||||
{
|
||||
json j("Hello world");
|
||||
json k;
|
||||
k = j;
|
||||
CHECK(j == k);
|
||||
}
|
||||
|
||||
SECTION("number (integer)")
|
||||
{
|
||||
json j(42);
|
||||
json k;
|
||||
k = j;
|
||||
CHECK(j == k);
|
||||
}
|
||||
|
||||
SECTION("number (unsigned)")
|
||||
{
|
||||
json j(42u);
|
||||
json k;
|
||||
k = j;
|
||||
CHECK(j == k);
|
||||
}
|
||||
|
||||
SECTION("number (floating-point)")
|
||||
{
|
||||
json j(42.23);
|
||||
json k;
|
||||
k = j;
|
||||
CHECK(j == k);
|
||||
}
|
||||
|
||||
SECTION("binary")
|
||||
{
|
||||
json j = json::binary({1, 2, 3});
|
||||
json k;
|
||||
k = j;
|
||||
CHECK(j == k);
|
||||
}
|
||||
}
|
||||
|
||||
SECTION("destructor")
|
||||
{
|
||||
SECTION("object")
|
||||
{
|
||||
auto* j = new json {{"foo", 1}, {"bar", false}}; // NOLINT(cppcoreguidelines-owning-memory)
|
||||
delete j; // NOLINT(cppcoreguidelines-owning-memory)
|
||||
}
|
||||
|
||||
SECTION("array")
|
||||
{
|
||||
auto* j = new json {"foo", 1, 1u, false, 23.42}; // NOLINT(cppcoreguidelines-owning-memory)
|
||||
delete j; // NOLINT(cppcoreguidelines-owning-memory)
|
||||
}
|
||||
|
||||
SECTION("string")
|
||||
{
|
||||
auto* j = new json("Hello world"); // NOLINT(cppcoreguidelines-owning-memory)
|
||||
delete j; // NOLINT(cppcoreguidelines-owning-memory)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,226 @@
|
||||
/*
|
||||
__ _____ _____ _____
|
||||
__| | __| | | | JSON for Modern C++ (test suite)
|
||||
| | |__ | | | | | | version 3.10.5
|
||||
|_____|_____|_____|_|___| https://github.com/nlohmann/json
|
||||
|
||||
Licensed under the MIT License <http://opensource.org/licenses/MIT>.
|
||||
SPDX-License-Identifier: MIT
|
||||
Copyright (c) 2013-2022 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 "doctest_compatibility.h"
|
||||
|
||||
#define JSON_TESTS_PRIVATE
|
||||
#include <nlohmann/json.hpp>
|
||||
using nlohmann::json;
|
||||
|
||||
#include <sstream>
|
||||
|
||||
namespace
|
||||
{
|
||||
struct alt_string_iter
|
||||
{
|
||||
alt_string_iter() = default;
|
||||
alt_string_iter(const char* cstr)
|
||||
: impl(cstr)
|
||||
{}
|
||||
|
||||
void reserve(std::size_t s)
|
||||
{
|
||||
impl.reserve(s);
|
||||
}
|
||||
|
||||
template<typename Iter>
|
||||
void append(Iter first, Iter last)
|
||||
{
|
||||
impl.append(first, last);
|
||||
}
|
||||
|
||||
std::string::const_iterator begin() const
|
||||
{
|
||||
return impl.begin();
|
||||
}
|
||||
|
||||
std::string::const_iterator end() const
|
||||
{
|
||||
return impl.end();
|
||||
}
|
||||
|
||||
std::size_t size() const
|
||||
{
|
||||
return impl.size();
|
||||
}
|
||||
|
||||
alt_string_iter& operator+=(const char c)
|
||||
{
|
||||
impl += c;
|
||||
return *this;
|
||||
}
|
||||
|
||||
std::string impl{};
|
||||
};
|
||||
|
||||
struct alt_string_data
|
||||
{
|
||||
alt_string_data() = default;
|
||||
alt_string_data(const char* cstr)
|
||||
: impl(cstr)
|
||||
{}
|
||||
|
||||
void reserve(std::size_t s)
|
||||
{
|
||||
impl.reserve(s);
|
||||
}
|
||||
|
||||
void append(const char* p, std::size_t s)
|
||||
{
|
||||
impl.append(p, s);
|
||||
}
|
||||
|
||||
const char* data() const
|
||||
{
|
||||
return impl.data();
|
||||
}
|
||||
|
||||
std::size_t size() const
|
||||
{
|
||||
return impl.size();
|
||||
}
|
||||
|
||||
alt_string_data& operator+=(const char c)
|
||||
{
|
||||
impl += c;
|
||||
return *this;
|
||||
}
|
||||
|
||||
std::string impl{};
|
||||
};
|
||||
|
||||
void check_escaped(const char* original, const char* escaped = "", bool ensure_ascii = false);
|
||||
void check_escaped(const char* original, const char* escaped, const bool ensure_ascii)
|
||||
{
|
||||
std::stringstream ss;
|
||||
json::serializer s(nlohmann::detail::output_adapter<char>(ss), ' ');
|
||||
s.dump_escaped(original, ensure_ascii);
|
||||
CHECK(ss.str() == escaped);
|
||||
}
|
||||
} // namespace
|
||||
|
||||
TEST_CASE("convenience functions")
|
||||
{
|
||||
SECTION("type name as string")
|
||||
{
|
||||
CHECK(std::string(json(json::value_t::null).type_name()) == "null");
|
||||
CHECK(std::string(json(json::value_t::object).type_name()) == "object");
|
||||
CHECK(std::string(json(json::value_t::array).type_name()) == "array");
|
||||
CHECK(std::string(json(json::value_t::number_integer).type_name()) == "number");
|
||||
CHECK(std::string(json(json::value_t::number_unsigned).type_name()) == "number");
|
||||
CHECK(std::string(json(json::value_t::number_float).type_name()) == "number");
|
||||
CHECK(std::string(json(json::value_t::binary).type_name()) == "binary");
|
||||
CHECK(std::string(json(json::value_t::boolean).type_name()) == "boolean");
|
||||
CHECK(std::string(json(json::value_t::string).type_name()) == "string");
|
||||
CHECK(std::string(json(json::value_t::discarded).type_name()) == "discarded");
|
||||
}
|
||||
|
||||
SECTION("string escape")
|
||||
{
|
||||
check_escaped("\"", "\\\"");
|
||||
check_escaped("\\", "\\\\");
|
||||
check_escaped("\b", "\\b");
|
||||
check_escaped("\f", "\\f");
|
||||
check_escaped("\n", "\\n");
|
||||
check_escaped("\r", "\\r");
|
||||
check_escaped("\t", "\\t");
|
||||
|
||||
check_escaped("\x01", "\\u0001");
|
||||
check_escaped("\x02", "\\u0002");
|
||||
check_escaped("\x03", "\\u0003");
|
||||
check_escaped("\x04", "\\u0004");
|
||||
check_escaped("\x05", "\\u0005");
|
||||
check_escaped("\x06", "\\u0006");
|
||||
check_escaped("\x07", "\\u0007");
|
||||
check_escaped("\x08", "\\b");
|
||||
check_escaped("\x09", "\\t");
|
||||
check_escaped("\x0a", "\\n");
|
||||
check_escaped("\x0b", "\\u000b");
|
||||
check_escaped("\x0c", "\\f");
|
||||
check_escaped("\x0d", "\\r");
|
||||
check_escaped("\x0e", "\\u000e");
|
||||
check_escaped("\x0f", "\\u000f");
|
||||
check_escaped("\x10", "\\u0010");
|
||||
check_escaped("\x11", "\\u0011");
|
||||
check_escaped("\x12", "\\u0012");
|
||||
check_escaped("\x13", "\\u0013");
|
||||
check_escaped("\x14", "\\u0014");
|
||||
check_escaped("\x15", "\\u0015");
|
||||
check_escaped("\x16", "\\u0016");
|
||||
check_escaped("\x17", "\\u0017");
|
||||
check_escaped("\x18", "\\u0018");
|
||||
check_escaped("\x19", "\\u0019");
|
||||
check_escaped("\x1a", "\\u001a");
|
||||
check_escaped("\x1b", "\\u001b");
|
||||
check_escaped("\x1c", "\\u001c");
|
||||
check_escaped("\x1d", "\\u001d");
|
||||
check_escaped("\x1e", "\\u001e");
|
||||
check_escaped("\x1f", "\\u001f");
|
||||
|
||||
// invalid UTF-8 characters
|
||||
CHECK_THROWS_WITH_AS(check_escaped("ä\xA9ü"), "[json.exception.type_error.316] invalid UTF-8 byte at index 2: 0xA9", json::type_error&);
|
||||
|
||||
CHECK_THROWS_WITH_AS(check_escaped("\xC2"), "[json.exception.type_error.316] incomplete UTF-8 string; last byte: 0xC2", json::type_error&);
|
||||
}
|
||||
|
||||
SECTION("string concat")
|
||||
{
|
||||
using nlohmann::detail::concat;
|
||||
|
||||
const char* expected = "Hello, world!";
|
||||
alt_string_iter hello_iter{"Hello, "};
|
||||
alt_string_data hello_data{"Hello, "};
|
||||
std::string world = "world";
|
||||
|
||||
SECTION("std::string")
|
||||
{
|
||||
std::string str1 = concat(hello_iter, world, '!');
|
||||
std::string str2 = concat(hello_data, world, '!');
|
||||
std::string str3 = concat("Hello, ", world, '!');
|
||||
|
||||
CHECK(str1 == expected);
|
||||
CHECK(str2 == expected);
|
||||
CHECK(str3 == expected);
|
||||
}
|
||||
|
||||
SECTION("alt_string_iter")
|
||||
{
|
||||
alt_string_iter str = concat<alt_string_iter>(hello_iter, world, '!');
|
||||
|
||||
CHECK(str.impl == expected);
|
||||
}
|
||||
|
||||
SECTION("alt_string_data")
|
||||
{
|
||||
alt_string_data str = concat<alt_string_data>(hello_data, world, '!');
|
||||
|
||||
CHECK(str.impl == expected);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,266 @@
|
||||
/*
|
||||
__ _____ _____ _____
|
||||
__| | __| | | | JSON for Modern C++ (test suite)
|
||||
| | |__ | | | | | | version 3.10.5
|
||||
|_____|_____|_____|_|___| https://github.com/nlohmann/json
|
||||
|
||||
Licensed under the MIT License <http://opensource.org/licenses/MIT>.
|
||||
SPDX-License-Identifier: MIT
|
||||
Copyright (c) 2013-2022 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 "doctest_compatibility.h"
|
||||
|
||||
#ifdef JSON_DIAGNOSTICS
|
||||
#undef JSON_DIAGNOSTICS
|
||||
#endif
|
||||
|
||||
#define JSON_DIAGNOSTICS 1
|
||||
|
||||
#include <nlohmann/json.hpp>
|
||||
using nlohmann::json;
|
||||
|
||||
TEST_CASE("Better diagnostics")
|
||||
{
|
||||
SECTION("empty JSON Pointer")
|
||||
{
|
||||
json j = 1;
|
||||
std::string s;
|
||||
CHECK_THROWS_WITH_AS(s = j.get<std::string>(), "[json.exception.type_error.302] type must be string, but is number", json::type_error);
|
||||
}
|
||||
|
||||
SECTION("invalid type")
|
||||
{
|
||||
json j;
|
||||
j["a"]["b"]["c"] = 1;
|
||||
std::string s;
|
||||
CHECK_THROWS_WITH_AS(s = j["a"]["b"]["c"].get<std::string>(), "[json.exception.type_error.302] (/a/b/c) type must be string, but is number", json::type_error);
|
||||
}
|
||||
|
||||
SECTION("missing key")
|
||||
{
|
||||
json j;
|
||||
j["object"]["object"] = true;
|
||||
CHECK_THROWS_WITH_AS(j["object"].at("not_found"), "[json.exception.out_of_range.403] (/object) key 'not_found' not found", json::out_of_range);
|
||||
}
|
||||
|
||||
SECTION("array index out of range")
|
||||
{
|
||||
json j;
|
||||
j["array"][4] = true;
|
||||
CHECK_THROWS_WITH_AS(j["array"].at(5), "[json.exception.out_of_range.401] (/array) array index 5 is out of range", json::out_of_range);
|
||||
}
|
||||
|
||||
SECTION("array index at wrong type")
|
||||
{
|
||||
json j;
|
||||
j["array"][4] = true;
|
||||
CHECK_THROWS_WITH_AS(j["array"][4][5], "[json.exception.type_error.305] (/array/4) cannot use operator[] with a numeric argument with boolean", json::type_error);
|
||||
}
|
||||
|
||||
SECTION("wrong iterator")
|
||||
{
|
||||
json j;
|
||||
j["array"] = json::array();
|
||||
CHECK_THROWS_WITH_AS(j["array"].erase(j.begin()), "[json.exception.invalid_iterator.202] (/array) iterator does not fit current value", json::invalid_iterator);
|
||||
}
|
||||
|
||||
SECTION("JSON Pointer escaping")
|
||||
{
|
||||
json j;
|
||||
j["a/b"]["m~n"] = 1;
|
||||
std::string s;
|
||||
CHECK_THROWS_WITH_AS(s = j["a/b"]["m~n"].get<std::string>(), "[json.exception.type_error.302] (/a~1b/m~0n) type must be string, but is number", json::type_error);
|
||||
}
|
||||
|
||||
SECTION("Parse error")
|
||||
{
|
||||
json _;
|
||||
CHECK_THROWS_WITH_AS(_ = json::parse(""), "[json.exception.parse_error.101] parse error at line 1, column 1: syntax error while parsing value - unexpected end of input; expected '[', '{', or a literal", json::parse_error);
|
||||
}
|
||||
|
||||
SECTION("Wrong type in update()")
|
||||
{
|
||||
json j = {{"foo", "bar"}};
|
||||
json k = {{"bla", 1}};
|
||||
|
||||
CHECK_THROWS_WITH_AS(j.update(k["bla"].begin(), k["bla"].end()), "[json.exception.type_error.312] (/bla) cannot use update() with number", json::type_error);
|
||||
CHECK_THROWS_WITH_AS(j.update(k["bla"]), "[json.exception.type_error.312] (/bla) cannot use update() with number", json::type_error);
|
||||
}
|
||||
}
|
||||
|
||||
TEST_CASE("Regression tests for extended diagnostics")
|
||||
{
|
||||
SECTION("Regression test for https://github.com/nlohmann/json/pull/2562#pullrequestreview-574858448")
|
||||
{
|
||||
CHECK_THROWS_WITH_AS(json({"0", "0"})[1].get<int>(), "[json.exception.type_error.302] (/1) type must be number, but is string", json::type_error);
|
||||
CHECK_THROWS_WITH_AS(json({"0", "1"})[1].get<int>(), "[json.exception.type_error.302] (/1) type must be number, but is string", json::type_error);
|
||||
}
|
||||
|
||||
SECTION("Regression test for https://github.com/nlohmann/json/pull/2562/files/380a613f2b5d32425021129cd1f371ddcfd54ddf#r563259793")
|
||||
{
|
||||
json j;
|
||||
j["/foo"] = {1, 2, 3};
|
||||
CHECK_THROWS_WITH_AS(j.unflatten(), "[json.exception.type_error.315] (/~1foo) values in object must be primitive", json::type_error);
|
||||
}
|
||||
|
||||
SECTION("Regression test for issue #2838 - Assertion failure when inserting into arrays with JSON_DIAGNOSTICS set")
|
||||
{
|
||||
// void push_back(basic_json&& val)
|
||||
{
|
||||
json j_arr = json::array();
|
||||
j_arr.push_back(json::object());
|
||||
j_arr.push_back(json::object());
|
||||
j_arr.push_back(json::object());
|
||||
j_arr.push_back(json::object());
|
||||
json j_obj = json::object();
|
||||
j_obj["key"] = j_arr;
|
||||
}
|
||||
|
||||
// void push_back(const basic_json& val)
|
||||
{
|
||||
json j_arr = json::array();
|
||||
auto object = json::object();
|
||||
j_arr.push_back(object);
|
||||
j_arr.push_back(object);
|
||||
j_arr.push_back(object);
|
||||
j_arr.push_back(object);
|
||||
json j_obj = json::object();
|
||||
j_obj["key"] = j_arr;
|
||||
}
|
||||
|
||||
// reference emplace_back(Args&& ... args)
|
||||
{
|
||||
json j_arr = json::array();
|
||||
j_arr.emplace_back(json::object());
|
||||
j_arr.emplace_back(json::object());
|
||||
j_arr.emplace_back(json::object());
|
||||
j_arr.emplace_back(json::object());
|
||||
json j_obj = json::object();
|
||||
j_obj["key"] = j_arr;
|
||||
}
|
||||
|
||||
// iterator insert(const_iterator pos, const basic_json& val)
|
||||
{
|
||||
json j_arr = json::array();
|
||||
j_arr.insert(j_arr.begin(), json::object());
|
||||
j_arr.insert(j_arr.begin(), json::object());
|
||||
j_arr.insert(j_arr.begin(), json::object());
|
||||
j_arr.insert(j_arr.begin(), json::object());
|
||||
json j_obj = json::object();
|
||||
j_obj["key"] = j_arr;
|
||||
}
|
||||
|
||||
// iterator insert(const_iterator pos, size_type cnt, const basic_json& val)
|
||||
{
|
||||
json j_arr = json::array();
|
||||
j_arr.insert(j_arr.begin(), 2, json::object());
|
||||
json j_obj = json::object();
|
||||
j_obj["key"] = j_arr;
|
||||
}
|
||||
|
||||
// iterator insert(const_iterator pos, const_iterator first, const_iterator last)
|
||||
{
|
||||
json j_arr = json::array();
|
||||
json j_objects = {json::object(), json::object()};
|
||||
j_arr.insert(j_arr.begin(), j_objects.begin(), j_objects.end());
|
||||
json j_obj = json::object();
|
||||
j_obj["key"] = j_arr;
|
||||
}
|
||||
}
|
||||
|
||||
SECTION("Regression test for issue #2962 - JSON_DIAGNOSTICS assertion for ordered_json")
|
||||
{
|
||||
nlohmann::ordered_json j;
|
||||
nlohmann::ordered_json j2;
|
||||
const std::string value;
|
||||
j["first"] = value;
|
||||
j["second"] = value;
|
||||
j2["something"] = j;
|
||||
}
|
||||
|
||||
SECTION("Regression test for issue #3007 - Parent pointers properly set when using update()")
|
||||
{
|
||||
// void update(const_reference j)
|
||||
{
|
||||
json j = json::object();
|
||||
|
||||
{
|
||||
json j2 = json::object();
|
||||
j2["one"] = 1;
|
||||
|
||||
j.update(j2);
|
||||
}
|
||||
|
||||
// Must call operator[] on const element, otherwise m_parent gets updated.
|
||||
auto const& constJ = j;
|
||||
CHECK_THROWS_WITH_AS(constJ["one"].at(0), "[json.exception.type_error.304] (/one) cannot use at() with number", json::type_error);
|
||||
}
|
||||
|
||||
// void update(const_iterator first, const_iterator last)
|
||||
{
|
||||
json j = json::object();
|
||||
|
||||
{
|
||||
json j2 = json::object();
|
||||
j2["one"] = 1;
|
||||
|
||||
j.update(j2.begin(), j2.end());
|
||||
}
|
||||
|
||||
// Must call operator[] on const element, otherwise m_parent gets updated.
|
||||
auto const& constJ = j;
|
||||
CHECK_THROWS_WITH_AS(constJ["one"].at(0), "[json.exception.type_error.304] (/one) cannot use at() with number", json::type_error);
|
||||
}
|
||||
|
||||
// Code from #3007 triggering unwanted assertion without fix to update().
|
||||
{
|
||||
json root = json::array();
|
||||
json lower = json::object();
|
||||
|
||||
{
|
||||
json lowest = json::object();
|
||||
lowest["one"] = 1;
|
||||
|
||||
lower.update(lowest);
|
||||
}
|
||||
|
||||
root.push_back(lower);
|
||||
}
|
||||
}
|
||||
|
||||
SECTION("Regression test for issue #3032 - Yet another assertion failure when inserting into arrays with JSON_DIAGNOSTICS set")
|
||||
{
|
||||
// reference operator[](size_type idx)
|
||||
{
|
||||
json j_arr = json::array();
|
||||
j_arr[0] = 0;
|
||||
j_arr[1] = 1;
|
||||
j_arr[2] = 2;
|
||||
j_arr[3] = 3;
|
||||
j_arr[4] = 4;
|
||||
j_arr[5] = 5;
|
||||
j_arr[6] = 6;
|
||||
j_arr[7] = 7;
|
||||
json j_arr_copy = j_arr;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,72 @@
|
||||
/*
|
||||
__ _____ _____ _____
|
||||
__| | __| | | | JSON for Modern C++ (test suite)
|
||||
| | |__ | | | | | | version 3.10.5
|
||||
|_____|_____|_____|_|___| https://github.com/nlohmann/json
|
||||
|
||||
Licensed under the MIT License <http://opensource.org/licenses/MIT>.
|
||||
SPDX-License-Identifier: MIT
|
||||
Copyright (c) 2013-2022 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 "doctest_compatibility.h"
|
||||
|
||||
// disable -Wnoexcept as exceptions are switched off for this test suite
|
||||
DOCTEST_GCC_SUPPRESS_WARNING_PUSH
|
||||
DOCTEST_GCC_SUPPRESS_WARNING("-Wnoexcept")
|
||||
|
||||
#include <nlohmann/json.hpp>
|
||||
using json = nlohmann::json;
|
||||
|
||||
/////////////////////////////////////////////////////////////////////
|
||||
// for #2824
|
||||
/////////////////////////////////////////////////////////////////////
|
||||
|
||||
class sax_no_exception : public nlohmann::detail::json_sax_dom_parser<json>
|
||||
{
|
||||
public:
|
||||
explicit sax_no_exception(json& j) : nlohmann::detail::json_sax_dom_parser<json>(j, false) {}
|
||||
|
||||
static bool parse_error(std::size_t /*position*/, const std::string& /*last_token*/, const json::exception& ex)
|
||||
{
|
||||
error_string = new std::string(ex.what()); // NOLINT(cppcoreguidelines-owning-memory)
|
||||
return false;
|
||||
}
|
||||
|
||||
static std::string* error_string;
|
||||
};
|
||||
|
||||
std::string* sax_no_exception::error_string = nullptr;
|
||||
|
||||
TEST_CASE("Tests with disabled exceptions")
|
||||
{
|
||||
SECTION("issue #2824 - encoding of json::exception::what()")
|
||||
{
|
||||
json j;
|
||||
sax_no_exception sax(j);
|
||||
|
||||
CHECK (!json::sax_parse("xyz", &sax));
|
||||
CHECK(*sax_no_exception::error_string == "[json.exception.parse_error.101] parse error at line 1, column 1: syntax error while parsing value - invalid literal; last read: 'x'");
|
||||
delete sax_no_exception::error_string; // NOLINT(cppcoreguidelines-owning-memory)
|
||||
}
|
||||
}
|
||||
|
||||
DOCTEST_GCC_SUPPRESS_WARNING_POP
|
||||
@@ -0,0 +1,901 @@
|
||||
/*
|
||||
__ _____ _____ _____
|
||||
__| | __| | | | JSON for Modern C++ (test suite)
|
||||
| | |__ | | | | | | version 3.10.5
|
||||
|_____|_____|_____|_|___| https://github.com/nlohmann/json
|
||||
|
||||
Licensed under the MIT License <http://opensource.org/licenses/MIT>.
|
||||
SPDX-License-Identifier: MIT
|
||||
Copyright (c) 2013-2022 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 "doctest_compatibility.h"
|
||||
|
||||
#include <nlohmann/json.hpp>
|
||||
using nlohmann::json;
|
||||
|
||||
TEST_CASE("element access 1")
|
||||
{
|
||||
SECTION("array")
|
||||
{
|
||||
json j = {1, 1u, true, nullptr, "string", 42.23, json::object(), {1, 2, 3}};
|
||||
const json j_const = j;
|
||||
|
||||
SECTION("access specified element with bounds checking")
|
||||
{
|
||||
SECTION("access within bounds")
|
||||
{
|
||||
CHECK(j.at(0) == json(1));
|
||||
CHECK(j.at(1) == json(1u));
|
||||
CHECK(j.at(2) == json(true));
|
||||
CHECK(j.at(3) == json(nullptr));
|
||||
CHECK(j.at(4) == json("string"));
|
||||
CHECK(j.at(5) == json(42.23));
|
||||
CHECK(j.at(6) == json::object());
|
||||
CHECK(j.at(7) == json({1, 2, 3}));
|
||||
|
||||
CHECK(j_const.at(0) == json(1));
|
||||
CHECK(j_const.at(1) == json(1u));
|
||||
CHECK(j_const.at(2) == json(true));
|
||||
CHECK(j_const.at(3) == json(nullptr));
|
||||
CHECK(j_const.at(4) == json("string"));
|
||||
CHECK(j_const.at(5) == json(42.23));
|
||||
CHECK(j_const.at(6) == json::object());
|
||||
CHECK(j_const.at(7) == json({1, 2, 3}));
|
||||
}
|
||||
|
||||
SECTION("access outside bounds")
|
||||
{
|
||||
CHECK_THROWS_WITH_AS(j.at(8),
|
||||
"[json.exception.out_of_range.401] array index 8 is out of range", json::out_of_range&);
|
||||
CHECK_THROWS_WITH_AS(j_const.at(8),
|
||||
"[json.exception.out_of_range.401] array index 8 is out of range", json::out_of_range&);
|
||||
}
|
||||
|
||||
SECTION("access on non-array type")
|
||||
{
|
||||
SECTION("null")
|
||||
{
|
||||
json j_nonarray(json::value_t::null);
|
||||
const json j_nonarray_const(j_nonarray);
|
||||
|
||||
CHECK_THROWS_WITH_AS(j_nonarray.at(0), "[json.exception.type_error.304] cannot use at() with null", json::type_error&);
|
||||
CHECK_THROWS_WITH_AS(j_nonarray_const.at(0), "[json.exception.type_error.304] cannot use at() with null", json::type_error&);
|
||||
}
|
||||
|
||||
SECTION("boolean")
|
||||
{
|
||||
json j_nonarray(json::value_t::boolean);
|
||||
const json j_nonarray_const(j_nonarray);
|
||||
|
||||
CHECK_THROWS_WITH_AS(j_nonarray.at(0), "[json.exception.type_error.304] cannot use at() with boolean", json::type_error&);
|
||||
CHECK_THROWS_WITH_AS(j_nonarray_const.at(0), "[json.exception.type_error.304] cannot use at() with boolean", json::type_error&);
|
||||
}
|
||||
|
||||
SECTION("string")
|
||||
{
|
||||
json j_nonarray(json::value_t::string);
|
||||
const json j_nonarray_const(j_nonarray);
|
||||
|
||||
CHECK_THROWS_WITH_AS(j_nonarray.at(0), "[json.exception.type_error.304] cannot use at() with string", json::type_error&);
|
||||
CHECK_THROWS_WITH_AS(j_nonarray_const.at(0), "[json.exception.type_error.304] cannot use at() with string", json::type_error&);
|
||||
}
|
||||
|
||||
SECTION("object")
|
||||
{
|
||||
json j_nonarray(json::value_t::object);
|
||||
const json j_nonarray_const(j_nonarray);
|
||||
|
||||
CHECK_THROWS_WITH_AS(j_nonarray.at(0), "[json.exception.type_error.304] cannot use at() with object", json::type_error&);
|
||||
CHECK_THROWS_WITH_AS(j_nonarray_const.at(0), "[json.exception.type_error.304] cannot use at() with object", json::type_error&);
|
||||
}
|
||||
|
||||
SECTION("number (integer)")
|
||||
{
|
||||
json j_nonarray(json::value_t::number_integer);
|
||||
const json j_nonarray_const(j_nonarray);
|
||||
|
||||
CHECK_THROWS_WITH_AS(j_nonarray.at(0), "[json.exception.type_error.304] cannot use at() with number", json::type_error&);
|
||||
CHECK_THROWS_WITH_AS(j_nonarray_const.at(0), "[json.exception.type_error.304] cannot use at() with number", json::type_error&);
|
||||
}
|
||||
|
||||
SECTION("number (unsigned)")
|
||||
{
|
||||
json j_nonarray(json::value_t::number_unsigned);
|
||||
const json j_nonarray_const(j_nonarray);
|
||||
|
||||
CHECK_THROWS_WITH_AS(j_nonarray.at(0), "[json.exception.type_error.304] cannot use at() with number", json::type_error&);
|
||||
CHECK_THROWS_WITH_AS(j_nonarray_const.at(0), "[json.exception.type_error.304] cannot use at() with number", json::type_error&);
|
||||
}
|
||||
|
||||
SECTION("number (floating-point)")
|
||||
{
|
||||
json j_nonarray(json::value_t::number_float);
|
||||
const json j_nonarray_const(j_nonarray);
|
||||
|
||||
CHECK_THROWS_WITH_AS(j_nonarray.at(0), "[json.exception.type_error.304] cannot use at() with number", json::type_error&);
|
||||
CHECK_THROWS_WITH_AS(j_nonarray_const.at(0), "[json.exception.type_error.304] cannot use at() with number", json::type_error&);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
SECTION("front and back")
|
||||
{
|
||||
CHECK(j.front() == json(1));
|
||||
CHECK(j_const.front() == json(1));
|
||||
CHECK(j.back() == json({1, 2, 3}));
|
||||
CHECK(j_const.back() == json({1, 2, 3}));
|
||||
}
|
||||
|
||||
SECTION("access specified element")
|
||||
{
|
||||
SECTION("access within bounds")
|
||||
{
|
||||
CHECK(j[0] == json(1));
|
||||
CHECK(j[1] == json(1u));
|
||||
CHECK(j[2] == json(true));
|
||||
CHECK(j[3] == json(nullptr));
|
||||
CHECK(j[4] == json("string"));
|
||||
CHECK(j[5] == json(42.23));
|
||||
CHECK(j[6] == json::object());
|
||||
CHECK(j[7] == json({1, 2, 3}));
|
||||
|
||||
CHECK(j_const[0] == json(1));
|
||||
CHECK(j_const[1] == json(1u));
|
||||
CHECK(j_const[2] == json(true));
|
||||
CHECK(j_const[3] == json(nullptr));
|
||||
CHECK(j_const[4] == json("string"));
|
||||
CHECK(j_const[5] == json(42.23));
|
||||
CHECK(j_const[6] == json::object());
|
||||
CHECK(j_const[7] == json({1, 2, 3}));
|
||||
}
|
||||
|
||||
SECTION("access on non-array type")
|
||||
{
|
||||
SECTION("null")
|
||||
{
|
||||
SECTION("standard tests")
|
||||
{
|
||||
json j_nonarray(json::value_t::null);
|
||||
const json j_nonarray_const(j_nonarray);
|
||||
CHECK_NOTHROW(j_nonarray[0]);
|
||||
CHECK_THROWS_WITH_AS(j_nonarray_const[0], "[json.exception.type_error.305] cannot use operator[] with a numeric argument with null", json::type_error&);
|
||||
}
|
||||
|
||||
SECTION("implicit transformation to properly filled array")
|
||||
{
|
||||
json j_nonarray;
|
||||
j_nonarray[3] = 42;
|
||||
CHECK(j_nonarray == json({nullptr, nullptr, nullptr, 42}));
|
||||
}
|
||||
}
|
||||
|
||||
SECTION("boolean")
|
||||
{
|
||||
json j_nonarray(json::value_t::boolean);
|
||||
const json j_nonarray_const(j_nonarray);
|
||||
CHECK_THROWS_WITH_AS(j_nonarray[0], "[json.exception.type_error.305] cannot use operator[] with a numeric argument with boolean", json::type_error&);
|
||||
CHECK_THROWS_WITH_AS(j_nonarray_const[0], "[json.exception.type_error.305] cannot use operator[] with a numeric argument with boolean", json::type_error&);
|
||||
}
|
||||
|
||||
SECTION("string")
|
||||
{
|
||||
json j_nonarray(json::value_t::string);
|
||||
const json j_nonarray_const(j_nonarray);
|
||||
CHECK_THROWS_WITH_AS(j_nonarray[0], "[json.exception.type_error.305] cannot use operator[] with a numeric argument with string", json::type_error&);
|
||||
CHECK_THROWS_WITH_AS(j_nonarray_const[0], "[json.exception.type_error.305] cannot use operator[] with a numeric argument with string", json::type_error&);
|
||||
}
|
||||
|
||||
SECTION("object")
|
||||
{
|
||||
json j_nonarray(json::value_t::object);
|
||||
const json j_nonarray_const(j_nonarray);
|
||||
CHECK_THROWS_WITH_AS(j_nonarray[0], "[json.exception.type_error.305] cannot use operator[] with a numeric argument with object", json::type_error&);
|
||||
CHECK_THROWS_WITH_AS(j_nonarray_const[0], "[json.exception.type_error.305] cannot use operator[] with a numeric argument with object", json::type_error&);
|
||||
}
|
||||
|
||||
SECTION("number (integer)")
|
||||
{
|
||||
json j_nonarray(json::value_t::number_integer);
|
||||
const json j_nonarray_const(j_nonarray);
|
||||
CHECK_THROWS_WITH_AS(j_nonarray[0], "[json.exception.type_error.305] cannot use operator[] with a numeric argument with number", json::type_error&);
|
||||
CHECK_THROWS_WITH_AS(j_nonarray_const[0], "[json.exception.type_error.305] cannot use operator[] with a numeric argument with number", json::type_error&);
|
||||
}
|
||||
|
||||
SECTION("number (unsigned)")
|
||||
{
|
||||
json j_nonarray(json::value_t::number_unsigned);
|
||||
const json j_nonarray_const(j_nonarray);
|
||||
CHECK_THROWS_WITH_AS(j_nonarray[0], "[json.exception.type_error.305] cannot use operator[] with a numeric argument with number", json::type_error&);
|
||||
CHECK_THROWS_WITH_AS(j_nonarray_const[0], "[json.exception.type_error.305] cannot use operator[] with a numeric argument with number", json::type_error&);
|
||||
}
|
||||
|
||||
SECTION("number (floating-point)")
|
||||
{
|
||||
json j_nonarray(json::value_t::number_float);
|
||||
const json j_nonarray_const(j_nonarray);
|
||||
CHECK_THROWS_WITH_AS(j_nonarray[0], "[json.exception.type_error.305] cannot use operator[] with a numeric argument with number", json::type_error&);
|
||||
CHECK_THROWS_WITH_AS(j_nonarray_const[0], "[json.exception.type_error.305] cannot use operator[] with a numeric argument with number", json::type_error&);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
SECTION("remove specified element")
|
||||
{
|
||||
SECTION("remove element by index")
|
||||
{
|
||||
{
|
||||
json jarray = {1, 1u, true, nullptr, "string", 42.23, json::object(), {1, 2, 3}};
|
||||
jarray.erase(0);
|
||||
CHECK(jarray == json({1u, true, nullptr, "string", 42.23, json::object(), {1, 2, 3}}));
|
||||
}
|
||||
{
|
||||
json jarray = {1, 1u, true, nullptr, "string", 42.23, json::object(), {1, 2, 3}};
|
||||
jarray.erase(1);
|
||||
CHECK(jarray == json({1, true, nullptr, "string", 42.23, json::object(), {1, 2, 3}}));
|
||||
}
|
||||
{
|
||||
json jarray = {1, 1u, true, nullptr, "string", 42.23, json::object(), {1, 2, 3}};
|
||||
jarray.erase(2);
|
||||
CHECK(jarray == json({1, 1u, nullptr, "string", 42.23, json::object(), {1, 2, 3}}));
|
||||
}
|
||||
{
|
||||
json jarray = {1, 1u, true, nullptr, "string", 42.23, json::object(), {1, 2, 3}};
|
||||
jarray.erase(3);
|
||||
CHECK(jarray == json({1, 1u, true, "string", 42.23, json::object(), {1, 2, 3}}));
|
||||
}
|
||||
{
|
||||
json jarray = {1, 1u, true, nullptr, "string", 42.23, json::object(), {1, 2, 3}};
|
||||
jarray.erase(4);
|
||||
CHECK(jarray == json({1, 1u, true, nullptr, 42.23, json::object(), {1, 2, 3}}));
|
||||
}
|
||||
{
|
||||
json jarray = {1, 1u, true, nullptr, "string", 42.23, json::object(), {1, 2, 3}};
|
||||
jarray.erase(5);
|
||||
CHECK(jarray == json({1, 1u, true, nullptr, "string", json::object(), {1, 2, 3}}));
|
||||
}
|
||||
{
|
||||
json jarray = {1, 1u, true, nullptr, "string", 42.23, json::object(), {1, 2, 3}};
|
||||
jarray.erase(6);
|
||||
CHECK(jarray == json({1, 1u, true, nullptr, "string", 42.23, {1, 2, 3}}));
|
||||
}
|
||||
{
|
||||
json jarray = {1, 1u, true, nullptr, "string", 42.23, json::object(), {1, 2, 3}};
|
||||
jarray.erase(7);
|
||||
CHECK(jarray == json({1, 1u, true, nullptr, "string", 42.23, json::object()}));
|
||||
}
|
||||
{
|
||||
json jarray = {1, 1u, true, nullptr, "string", 42.23, json::object(), {1, 2, 3}};
|
||||
CHECK_THROWS_WITH_AS(jarray.erase(8), "[json.exception.out_of_range.401] array index 8 is out of range", json::out_of_range&);
|
||||
}
|
||||
}
|
||||
|
||||
SECTION("remove element by iterator")
|
||||
{
|
||||
SECTION("erase(begin())")
|
||||
{
|
||||
{
|
||||
json jarray = {1, 1u, true, nullptr, "string", 42.23, json::object(), {1, 2, 3}};
|
||||
json::iterator it2 = jarray.erase(jarray.begin());
|
||||
CHECK(jarray == json({1u, true, nullptr, "string", 42.23, json::object(), {1, 2, 3}}));
|
||||
CHECK(*it2 == json(1u));
|
||||
}
|
||||
{
|
||||
json jarray = {1, 1u, true, nullptr, "string", 42.23, json::object(), {1, 2, 3}};
|
||||
json::const_iterator it2 = jarray.erase(jarray.cbegin());
|
||||
CHECK(jarray == json({1u, true, nullptr, "string", 42.23, json::object(), {1, 2, 3}}));
|
||||
CHECK(*it2 == json(1u));
|
||||
}
|
||||
}
|
||||
|
||||
SECTION("erase(begin(), end())")
|
||||
{
|
||||
{
|
||||
json jarray = {1, 1u, true, nullptr, "string", 42.23, json::object(), {1, 2, 3}};
|
||||
json::iterator it2 = jarray.erase(jarray.begin(), jarray.end());
|
||||
CHECK(jarray == json::array());
|
||||
CHECK(it2 == jarray.end());
|
||||
}
|
||||
{
|
||||
json jarray = {1, 1u, true, nullptr, "string", 42.23, json::object(), {1, 2, 3}};
|
||||
json::const_iterator it2 = jarray.erase(jarray.cbegin(), jarray.cend());
|
||||
CHECK(jarray == json::array());
|
||||
CHECK(it2 == jarray.cend());
|
||||
}
|
||||
}
|
||||
|
||||
SECTION("erase(begin(), begin())")
|
||||
{
|
||||
{
|
||||
json jarray = {1, 1u, true, nullptr, "string", 42.23, json::object(), {1, 2, 3}};
|
||||
json::iterator it2 = jarray.erase(jarray.begin(), jarray.begin());
|
||||
CHECK(jarray == json({1, 1u, true, nullptr, "string", 42.23, json::object(), {1, 2, 3}}));
|
||||
CHECK(*it2 == json(1));
|
||||
}
|
||||
{
|
||||
json jarray = {1, 1u, true, nullptr, "string", 42.23, json::object(), {1, 2, 3}};
|
||||
json::const_iterator it2 = jarray.erase(jarray.cbegin(), jarray.cbegin());
|
||||
CHECK(jarray == json({1, 1u, true, nullptr, "string", 42.23, json::object(), {1, 2, 3}}));
|
||||
CHECK(*it2 == json(1));
|
||||
}
|
||||
}
|
||||
|
||||
SECTION("erase at offset")
|
||||
{
|
||||
{
|
||||
json jarray = {1, 1u, true, nullptr, "string", 42.23, json::object(), {1, 2, 3}};
|
||||
json::iterator it = jarray.begin() + 4;
|
||||
json::iterator it2 = jarray.erase(it);
|
||||
CHECK(jarray == json({1, 1u, true, nullptr, 42.23, json::object(), {1, 2, 3}}));
|
||||
CHECK(*it2 == json(42.23));
|
||||
}
|
||||
{
|
||||
json jarray = {1, 1u, true, nullptr, "string", 42.23, json::object(), {1, 2, 3}};
|
||||
json::const_iterator it = jarray.cbegin() + 4;
|
||||
json::const_iterator it2 = jarray.erase(it);
|
||||
CHECK(jarray == json({1, 1u, true, nullptr, 42.23, json::object(), {1, 2, 3}}));
|
||||
CHECK(*it2 == json(42.23));
|
||||
}
|
||||
}
|
||||
|
||||
SECTION("erase subrange")
|
||||
{
|
||||
{
|
||||
json jarray = {1, 1u, true, nullptr, "string", 42.23, json::object(), {1, 2, 3}};
|
||||
json::iterator it2 = jarray.erase(jarray.begin() + 3, jarray.begin() + 6);
|
||||
CHECK(jarray == json({1, 1u, true, json::object(), {1, 2, 3}}));
|
||||
CHECK(*it2 == json::object());
|
||||
}
|
||||
{
|
||||
json jarray = {1, 1u, true, nullptr, "string", 42.23, json::object(), {1, 2, 3}};
|
||||
json::const_iterator it2 = jarray.erase(jarray.cbegin() + 3, jarray.cbegin() + 6);
|
||||
CHECK(jarray == json({1, 1u, true, json::object(), {1, 2, 3}}));
|
||||
CHECK(*it2 == json::object());
|
||||
}
|
||||
}
|
||||
|
||||
SECTION("different arrays")
|
||||
{
|
||||
{
|
||||
json jarray = {1, 1u, true, nullptr, "string", 42.23, json::object(), {1, 2, 3}};
|
||||
json jarray2 = {"foo", "bar"};
|
||||
|
||||
CHECK_THROWS_WITH_AS(jarray.erase(jarray2.begin()),
|
||||
"[json.exception.invalid_iterator.202] iterator does not fit current value", json::invalid_iterator&);
|
||||
CHECK_THROWS_WITH_AS(jarray.erase(jarray.begin(), jarray2.end()),
|
||||
"[json.exception.invalid_iterator.203] iterators do not fit current value", json::invalid_iterator&);
|
||||
CHECK_THROWS_WITH_AS(jarray.erase(jarray2.begin(), jarray.end()),
|
||||
"[json.exception.invalid_iterator.203] iterators do not fit current value", json::invalid_iterator&);
|
||||
CHECK_THROWS_WITH_AS(jarray.erase(jarray2.begin(), jarray2.end()),
|
||||
"[json.exception.invalid_iterator.203] iterators do not fit current value", json::invalid_iterator&);
|
||||
}
|
||||
{
|
||||
json jarray = {1, 1u, true, nullptr, "string", 42.23, json::object(), {1, 2, 3}};
|
||||
json jarray2 = {"foo", "bar"};
|
||||
|
||||
CHECK_THROWS_WITH_AS(jarray.erase(jarray2.cbegin()),
|
||||
"[json.exception.invalid_iterator.202] iterator does not fit current value", json::invalid_iterator&);
|
||||
CHECK_THROWS_WITH_AS(jarray.erase(jarray.cbegin(), jarray2.cend()),
|
||||
"[json.exception.invalid_iterator.203] iterators do not fit current value", json::invalid_iterator&);
|
||||
CHECK_THROWS_WITH_AS(jarray.erase(jarray2.cbegin(), jarray.cend()),
|
||||
"[json.exception.invalid_iterator.203] iterators do not fit current value", json::invalid_iterator&);
|
||||
CHECK_THROWS_WITH_AS(jarray.erase(jarray2.cbegin(), jarray2.cend()),
|
||||
"[json.exception.invalid_iterator.203] iterators do not fit current value", json::invalid_iterator&);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
SECTION("remove element by index in non-array type")
|
||||
{
|
||||
SECTION("null")
|
||||
{
|
||||
json j_nonobject(json::value_t::null);
|
||||
CHECK_THROWS_WITH_AS(j_nonobject.erase(0), "[json.exception.type_error.307] cannot use erase() with null", json::type_error&);
|
||||
}
|
||||
|
||||
SECTION("boolean")
|
||||
{
|
||||
json j_nonobject(json::value_t::boolean);
|
||||
CHECK_THROWS_WITH_AS(j_nonobject.erase(0), "[json.exception.type_error.307] cannot use erase() with boolean", json::type_error&);
|
||||
}
|
||||
|
||||
SECTION("string")
|
||||
{
|
||||
json j_nonobject(json::value_t::string);
|
||||
CHECK_THROWS_WITH_AS(j_nonobject.erase(0), "[json.exception.type_error.307] cannot use erase() with string", json::type_error&);
|
||||
}
|
||||
|
||||
SECTION("object")
|
||||
{
|
||||
json j_nonobject(json::value_t::object);
|
||||
CHECK_THROWS_WITH_AS(j_nonobject.erase(0), "[json.exception.type_error.307] cannot use erase() with object", json::type_error&);
|
||||
}
|
||||
|
||||
SECTION("number (integer)")
|
||||
{
|
||||
json j_nonobject(json::value_t::number_integer);
|
||||
CHECK_THROWS_WITH_AS(j_nonobject.erase(0), "[json.exception.type_error.307] cannot use erase() with number", json::type_error&);
|
||||
}
|
||||
|
||||
SECTION("number (unsigned)")
|
||||
{
|
||||
json j_nonobject(json::value_t::number_unsigned);
|
||||
CHECK_THROWS_WITH_AS(j_nonobject.erase(0), "[json.exception.type_error.307] cannot use erase() with number", json::type_error&);
|
||||
}
|
||||
|
||||
SECTION("number (floating-point)")
|
||||
{
|
||||
json j_nonobject(json::value_t::number_float);
|
||||
CHECK_THROWS_WITH_AS(j_nonobject.erase(0), "[json.exception.type_error.307] cannot use erase() with number", json::type_error&);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
SECTION("other values")
|
||||
{
|
||||
SECTION("front and back")
|
||||
{
|
||||
SECTION("null")
|
||||
{
|
||||
{
|
||||
json j;
|
||||
CHECK_THROWS_WITH_AS(j.front(), "[json.exception.invalid_iterator.214] cannot get value", json::invalid_iterator&);
|
||||
CHECK_THROWS_WITH_AS(j.back(), "[json.exception.invalid_iterator.214] cannot get value", json::invalid_iterator&);
|
||||
}
|
||||
{
|
||||
const json j{};
|
||||
CHECK_THROWS_WITH_AS(j.front(), "[json.exception.invalid_iterator.214] cannot get value", json::invalid_iterator&);
|
||||
CHECK_THROWS_WITH_AS(j.back(), "[json.exception.invalid_iterator.214] cannot get value", json::invalid_iterator&);
|
||||
}
|
||||
}
|
||||
|
||||
SECTION("string")
|
||||
{
|
||||
{
|
||||
json j = "foo";
|
||||
CHECK(j.front() == j);
|
||||
CHECK(j.back() == j);
|
||||
}
|
||||
{
|
||||
const json j = "bar";
|
||||
CHECK(j.front() == j);
|
||||
CHECK(j.back() == j);
|
||||
}
|
||||
}
|
||||
|
||||
SECTION("number (boolean)")
|
||||
{
|
||||
{
|
||||
json j = false;
|
||||
CHECK(j.front() == j);
|
||||
CHECK(j.back() == j);
|
||||
}
|
||||
{
|
||||
const json j = true;
|
||||
CHECK(j.front() == j);
|
||||
CHECK(j.back() == j);
|
||||
}
|
||||
}
|
||||
|
||||
SECTION("number (integer)")
|
||||
{
|
||||
{
|
||||
json j = 17;
|
||||
CHECK(j.front() == j);
|
||||
CHECK(j.back() == j);
|
||||
}
|
||||
{
|
||||
const json j = 17;
|
||||
CHECK(j.front() == j);
|
||||
CHECK(j.back() == j);
|
||||
}
|
||||
}
|
||||
|
||||
SECTION("number (unsigned)")
|
||||
{
|
||||
{
|
||||
json j = 17u;
|
||||
CHECK(j.front() == j);
|
||||
CHECK(j.back() == j);
|
||||
}
|
||||
{
|
||||
const json j = 17u;
|
||||
CHECK(j.front() == j);
|
||||
CHECK(j.back() == j);
|
||||
}
|
||||
}
|
||||
|
||||
SECTION("number (floating point)")
|
||||
{
|
||||
{
|
||||
json j = 23.42;
|
||||
CHECK(j.front() == j);
|
||||
CHECK(j.back() == j);
|
||||
}
|
||||
{
|
||||
const json j = 23.42;
|
||||
CHECK(j.front() == j);
|
||||
CHECK(j.back() == j);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
SECTION("erase with one valid iterator")
|
||||
{
|
||||
SECTION("null")
|
||||
{
|
||||
{
|
||||
json j;
|
||||
CHECK_THROWS_WITH_AS(j.erase(j.begin()), "[json.exception.type_error.307] cannot use erase() with null", json::type_error&);
|
||||
}
|
||||
{
|
||||
json j;
|
||||
CHECK_THROWS_WITH_AS(j.erase(j.begin()),
|
||||
"[json.exception.type_error.307] cannot use erase() with null", json::type_error&);
|
||||
}
|
||||
}
|
||||
|
||||
SECTION("string")
|
||||
{
|
||||
{
|
||||
json j = "foo";
|
||||
json::iterator it = j.erase(j.begin());
|
||||
CHECK(j.type() == json::value_t::null);
|
||||
CHECK(it == j.end());
|
||||
}
|
||||
{
|
||||
json j = "bar";
|
||||
json::const_iterator it = j.erase(j.cbegin());
|
||||
CHECK(j.type() == json::value_t::null);
|
||||
CHECK(it == j.end());
|
||||
}
|
||||
}
|
||||
|
||||
SECTION("number (boolean)")
|
||||
{
|
||||
{
|
||||
json j = false;
|
||||
json::iterator it = j.erase(j.begin());
|
||||
CHECK(j.type() == json::value_t::null);
|
||||
CHECK(it == j.end());
|
||||
}
|
||||
{
|
||||
json j = true;
|
||||
json::const_iterator it = j.erase(j.cbegin());
|
||||
CHECK(j.type() == json::value_t::null);
|
||||
CHECK(it == j.end());
|
||||
}
|
||||
}
|
||||
|
||||
SECTION("number (integer)")
|
||||
{
|
||||
{
|
||||
json j = 17;
|
||||
json::iterator it = j.erase(j.begin());
|
||||
CHECK(j.type() == json::value_t::null);
|
||||
CHECK(it == j.end());
|
||||
}
|
||||
{
|
||||
json j = 17;
|
||||
json::const_iterator it = j.erase(j.cbegin());
|
||||
CHECK(j.type() == json::value_t::null);
|
||||
CHECK(it == j.end());
|
||||
}
|
||||
}
|
||||
|
||||
SECTION("number (unsigned)")
|
||||
{
|
||||
{
|
||||
json j = 17u;
|
||||
json::iterator it = j.erase(j.begin());
|
||||
CHECK(j.type() == json::value_t::null);
|
||||
CHECK(it == j.end());
|
||||
}
|
||||
{
|
||||
json j = 17u;
|
||||
json::const_iterator it = j.erase(j.cbegin());
|
||||
CHECK(j.type() == json::value_t::null);
|
||||
CHECK(it == j.end());
|
||||
}
|
||||
}
|
||||
|
||||
SECTION("number (floating point)")
|
||||
{
|
||||
{
|
||||
json j = 23.42;
|
||||
json::iterator it = j.erase(j.begin());
|
||||
CHECK(j.type() == json::value_t::null);
|
||||
CHECK(it == j.end());
|
||||
}
|
||||
{
|
||||
json j = 23.42;
|
||||
json::const_iterator it = j.erase(j.cbegin());
|
||||
CHECK(j.type() == json::value_t::null);
|
||||
CHECK(it == j.end());
|
||||
}
|
||||
}
|
||||
|
||||
SECTION("binary")
|
||||
{
|
||||
{
|
||||
json j = json::binary({1, 2, 3});
|
||||
json::iterator it = j.erase(j.begin());
|
||||
CHECK(j.type() == json::value_t::null);
|
||||
CHECK(it == j.end());
|
||||
}
|
||||
{
|
||||
json j = json::binary({1, 2, 3});
|
||||
json::const_iterator it = j.erase(j.cbegin());
|
||||
CHECK(j.type() == json::value_t::null);
|
||||
CHECK(it == j.end());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
SECTION("erase with one invalid iterator")
|
||||
{
|
||||
SECTION("string")
|
||||
{
|
||||
{
|
||||
json j = "foo";
|
||||
CHECK_THROWS_WITH_AS(j.erase(j.end()), "[json.exception.invalid_iterator.205] iterator out of range", json::invalid_iterator&);
|
||||
}
|
||||
{
|
||||
json j = "bar";
|
||||
CHECK_THROWS_WITH_AS(j.erase(j.cend()), "[json.exception.invalid_iterator.205] iterator out of range", json::invalid_iterator&);
|
||||
}
|
||||
}
|
||||
|
||||
SECTION("number (boolean)")
|
||||
{
|
||||
{
|
||||
json j = false;
|
||||
CHECK_THROWS_WITH_AS(j.erase(j.end()), "[json.exception.invalid_iterator.205] iterator out of range", json::invalid_iterator&);
|
||||
}
|
||||
{
|
||||
json j = true;
|
||||
CHECK_THROWS_WITH_AS(j.erase(j.cend()), "[json.exception.invalid_iterator.205] iterator out of range", json::invalid_iterator&);
|
||||
}
|
||||
}
|
||||
|
||||
SECTION("number (integer)")
|
||||
{
|
||||
{
|
||||
json j = 17;
|
||||
CHECK_THROWS_WITH_AS(j.erase(j.end()), "[json.exception.invalid_iterator.205] iterator out of range", json::invalid_iterator&);
|
||||
}
|
||||
{
|
||||
json j = 17;
|
||||
CHECK_THROWS_WITH_AS(j.erase(j.cend()), "[json.exception.invalid_iterator.205] iterator out of range", json::invalid_iterator&);
|
||||
}
|
||||
}
|
||||
|
||||
SECTION("number (unsigned)")
|
||||
{
|
||||
{
|
||||
json j = 17u;
|
||||
CHECK_THROWS_WITH_AS(j.erase(j.end()), "[json.exception.invalid_iterator.205] iterator out of range", json::invalid_iterator&);
|
||||
}
|
||||
{
|
||||
json j = 17u;
|
||||
CHECK_THROWS_WITH_AS(j.erase(j.cend()), "[json.exception.invalid_iterator.205] iterator out of range", json::invalid_iterator&);
|
||||
}
|
||||
}
|
||||
|
||||
SECTION("number (floating point)")
|
||||
{
|
||||
{
|
||||
json j = 23.42;
|
||||
CHECK_THROWS_WITH_AS(j.erase(j.end()), "[json.exception.invalid_iterator.205] iterator out of range", json::invalid_iterator&);
|
||||
}
|
||||
{
|
||||
json j = 23.42;
|
||||
CHECK_THROWS_WITH_AS(j.erase(j.cend()), "[json.exception.invalid_iterator.205] iterator out of range", json::invalid_iterator&);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
SECTION("erase with two valid iterators")
|
||||
{
|
||||
SECTION("null")
|
||||
{
|
||||
{
|
||||
json j;
|
||||
CHECK_THROWS_WITH_AS(j.erase(j.begin(), j.end()), "[json.exception.type_error.307] cannot use erase() with null", json::type_error&);
|
||||
}
|
||||
{
|
||||
json j;
|
||||
CHECK_THROWS_WITH_AS(j.erase(j.cbegin(), j.cend()), "[json.exception.type_error.307] cannot use erase() with null", json::type_error&);
|
||||
}
|
||||
}
|
||||
|
||||
SECTION("string")
|
||||
{
|
||||
{
|
||||
json j = "foo";
|
||||
json::iterator it = j.erase(j.begin(), j.end());
|
||||
CHECK(j.type() == json::value_t::null);
|
||||
CHECK(it == j.end());
|
||||
}
|
||||
{
|
||||
json j = "bar";
|
||||
json::const_iterator it = j.erase(j.cbegin(), j.cend());
|
||||
CHECK(j.type() == json::value_t::null);
|
||||
CHECK(it == j.end());
|
||||
}
|
||||
}
|
||||
|
||||
SECTION("number (boolean)")
|
||||
{
|
||||
{
|
||||
json j = false;
|
||||
json::iterator it = j.erase(j.begin(), j.end());
|
||||
CHECK(j.type() == json::value_t::null);
|
||||
CHECK(it == j.end());
|
||||
}
|
||||
{
|
||||
json j = true;
|
||||
json::const_iterator it = j.erase(j.cbegin(), j.cend());
|
||||
CHECK(j.type() == json::value_t::null);
|
||||
CHECK(it == j.end());
|
||||
}
|
||||
}
|
||||
|
||||
SECTION("number (integer)")
|
||||
{
|
||||
{
|
||||
json j = 17;
|
||||
json::iterator it = j.erase(j.begin(), j.end());
|
||||
CHECK(j.type() == json::value_t::null);
|
||||
CHECK(it == j.end());
|
||||
}
|
||||
{
|
||||
json j = 17;
|
||||
json::const_iterator it = j.erase(j.cbegin(), j.cend());
|
||||
CHECK(j.type() == json::value_t::null);
|
||||
CHECK(it == j.end());
|
||||
}
|
||||
}
|
||||
|
||||
SECTION("number (unsigned)")
|
||||
{
|
||||
{
|
||||
json j = 17u;
|
||||
json::iterator it = j.erase(j.begin(), j.end());
|
||||
CHECK(j.type() == json::value_t::null);
|
||||
CHECK(it == j.end());
|
||||
}
|
||||
{
|
||||
json j = 17u;
|
||||
json::const_iterator it = j.erase(j.cbegin(), j.cend());
|
||||
CHECK(j.type() == json::value_t::null);
|
||||
CHECK(it == j.end());
|
||||
}
|
||||
}
|
||||
|
||||
SECTION("number (floating point)")
|
||||
{
|
||||
{
|
||||
json j = 23.42;
|
||||
json::iterator it = j.erase(j.begin(), j.end());
|
||||
CHECK(j.type() == json::value_t::null);
|
||||
CHECK(it == j.end());
|
||||
}
|
||||
{
|
||||
json j = 23.42;
|
||||
json::const_iterator it = j.erase(j.cbegin(), j.cend());
|
||||
CHECK(j.type() == json::value_t::null);
|
||||
CHECK(it == j.end());
|
||||
}
|
||||
}
|
||||
|
||||
SECTION("binary")
|
||||
{
|
||||
{
|
||||
json j = json::binary({1, 2, 3});
|
||||
json::iterator it = j.erase(j.begin(), j.end());
|
||||
CHECK(j.type() == json::value_t::null);
|
||||
CHECK(it == j.end());
|
||||
}
|
||||
{
|
||||
json j = json::binary({1, 2, 3});
|
||||
json::const_iterator it = j.erase(j.cbegin(), j.cend());
|
||||
CHECK(j.type() == json::value_t::null);
|
||||
CHECK(it == j.end());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
SECTION("erase with two invalid iterators")
|
||||
{
|
||||
SECTION("string")
|
||||
{
|
||||
{
|
||||
json j = "foo";
|
||||
CHECK_THROWS_WITH_AS(j.erase(j.end(), j.end()), "[json.exception.invalid_iterator.204] iterators out of range", json::invalid_iterator&);
|
||||
CHECK_THROWS_WITH_AS(j.erase(j.begin(), j.begin()), "[json.exception.invalid_iterator.204] iterators out of range", json::invalid_iterator&);
|
||||
}
|
||||
{
|
||||
json j = "bar";
|
||||
CHECK_THROWS_WITH_AS(j.erase(j.cend(), j.cend()), "[json.exception.invalid_iterator.204] iterators out of range", json::invalid_iterator&);
|
||||
CHECK_THROWS_WITH_AS(j.erase(j.cbegin(), j.cbegin()), "[json.exception.invalid_iterator.204] iterators out of range", json::invalid_iterator&);
|
||||
}
|
||||
}
|
||||
|
||||
SECTION("number (boolean)")
|
||||
{
|
||||
{
|
||||
json j = false;
|
||||
CHECK_THROWS_WITH_AS(j.erase(j.end(), j.end()), "[json.exception.invalid_iterator.204] iterators out of range", json::invalid_iterator&);
|
||||
CHECK_THROWS_WITH_AS(j.erase(j.begin(), j.begin()), "[json.exception.invalid_iterator.204] iterators out of range", json::invalid_iterator&);
|
||||
}
|
||||
{
|
||||
json j = true;
|
||||
CHECK_THROWS_WITH_AS(j.erase(j.cend(), j.cend()), "[json.exception.invalid_iterator.204] iterators out of range", json::invalid_iterator&);
|
||||
CHECK_THROWS_WITH_AS(j.erase(j.cbegin(), j.cbegin()), "[json.exception.invalid_iterator.204] iterators out of range", json::invalid_iterator&);
|
||||
}
|
||||
}
|
||||
|
||||
SECTION("number (integer)")
|
||||
{
|
||||
{
|
||||
json j = 17;
|
||||
CHECK_THROWS_WITH_AS(j.erase(j.end(), j.end()), "[json.exception.invalid_iterator.204] iterators out of range", json::invalid_iterator&);
|
||||
CHECK_THROWS_WITH_AS(j.erase(j.begin(), j.begin()), "[json.exception.invalid_iterator.204] iterators out of range", json::invalid_iterator&);
|
||||
}
|
||||
{
|
||||
json j = 17;
|
||||
CHECK_THROWS_WITH_AS(j.erase(j.cend(), j.cend()), "[json.exception.invalid_iterator.204] iterators out of range", json::invalid_iterator&);
|
||||
CHECK_THROWS_WITH_AS(j.erase(j.cbegin(), j.cbegin()), "[json.exception.invalid_iterator.204] iterators out of range", json::invalid_iterator&);
|
||||
}
|
||||
}
|
||||
|
||||
SECTION("number (unsigned)")
|
||||
{
|
||||
{
|
||||
json j = 17u;
|
||||
CHECK_THROWS_WITH_AS(j.erase(j.end(), j.end()), "[json.exception.invalid_iterator.204] iterators out of range", json::invalid_iterator&);
|
||||
CHECK_THROWS_WITH_AS(j.erase(j.begin(), j.begin()), "[json.exception.invalid_iterator.204] iterators out of range", json::invalid_iterator&);
|
||||
}
|
||||
{
|
||||
json j = 17u;
|
||||
CHECK_THROWS_WITH_AS(j.erase(j.cend(), j.cend()), "[json.exception.invalid_iterator.204] iterators out of range", json::invalid_iterator&);
|
||||
CHECK_THROWS_WITH_AS(j.erase(j.cbegin(), j.cbegin()), "[json.exception.invalid_iterator.204] iterators out of range", json::invalid_iterator&);
|
||||
}
|
||||
}
|
||||
|
||||
SECTION("number (floating point)")
|
||||
{
|
||||
{
|
||||
json j = 23.42;
|
||||
CHECK_THROWS_WITH_AS(j.erase(j.end(), j.end()), "[json.exception.invalid_iterator.204] iterators out of range", json::invalid_iterator&);
|
||||
CHECK_THROWS_WITH_AS(j.erase(j.begin(), j.begin()), "[json.exception.invalid_iterator.204] iterators out of range", json::invalid_iterator&);
|
||||
}
|
||||
{
|
||||
json j = 23.42;
|
||||
CHECK_THROWS_WITH_AS(j.erase(j.cend(), j.cend()), "[json.exception.invalid_iterator.204] iterators out of range", json::invalid_iterator&);
|
||||
CHECK_THROWS_WITH_AS(j.erase(j.cbegin(), j.cbegin()), "[json.exception.invalid_iterator.204] iterators out of range", json::invalid_iterator&);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,134 @@
|
||||
/*
|
||||
__ _____ _____ _____
|
||||
__| | __| | | | JSON for Modern C++ (test suite)
|
||||
| | |__ | | | | | | version 3.10.5
|
||||
|_____|_____|_____|_|___| https://github.com/nlohmann/json
|
||||
|
||||
Licensed under the MIT License <http://opensource.org/licenses/MIT>.
|
||||
SPDX-License-Identifier: MIT
|
||||
Copyright (c) 2013-2022 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 "doctest_compatibility.h"
|
||||
|
||||
#include <nlohmann/json.hpp>
|
||||
using json = nlohmann::json;
|
||||
using ordered_json = nlohmann::ordered_json;
|
||||
|
||||
#include <set>
|
||||
|
||||
TEST_CASE("hash<nlohmann::json>")
|
||||
{
|
||||
// Collect hashes for different JSON values and make sure that they are distinct
|
||||
// We cannot compare against fixed values, because the implementation of
|
||||
// std::hash may differ between compilers.
|
||||
|
||||
std::set<std::size_t> hashes;
|
||||
|
||||
// null
|
||||
hashes.insert(std::hash<json> {}(json(nullptr)));
|
||||
|
||||
// boolean
|
||||
hashes.insert(std::hash<json> {}(json(true)));
|
||||
hashes.insert(std::hash<json> {}(json(false)));
|
||||
|
||||
// string
|
||||
hashes.insert(std::hash<json> {}(json("")));
|
||||
hashes.insert(std::hash<json> {}(json("foo")));
|
||||
|
||||
// number
|
||||
hashes.insert(std::hash<json> {}(json(0)));
|
||||
hashes.insert(std::hash<json> {}(json(static_cast<unsigned>(0))));
|
||||
|
||||
hashes.insert(std::hash<json> {}(json(-1)));
|
||||
hashes.insert(std::hash<json> {}(json(0.0)));
|
||||
hashes.insert(std::hash<json> {}(json(42.23)));
|
||||
|
||||
// array
|
||||
hashes.insert(std::hash<json> {}(json::array()));
|
||||
hashes.insert(std::hash<json> {}(json::array({1, 2, 3})));
|
||||
|
||||
// object
|
||||
hashes.insert(std::hash<json> {}(json::object()));
|
||||
hashes.insert(std::hash<json> {}(json::object({{"foo", "bar"}})));
|
||||
|
||||
// binary
|
||||
hashes.insert(std::hash<json> {}(json::binary({})));
|
||||
hashes.insert(std::hash<json> {}(json::binary({}, 0)));
|
||||
hashes.insert(std::hash<json> {}(json::binary({}, 42)));
|
||||
hashes.insert(std::hash<json> {}(json::binary({1, 2, 3})));
|
||||
hashes.insert(std::hash<json> {}(json::binary({1, 2, 3}, 0)));
|
||||
hashes.insert(std::hash<json> {}(json::binary({1, 2, 3}, 42)));
|
||||
|
||||
// discarded
|
||||
hashes.insert(std::hash<json> {}(json(json::value_t::discarded)));
|
||||
|
||||
CHECK(hashes.size() == 21);
|
||||
}
|
||||
|
||||
TEST_CASE("hash<nlohmann::ordered_json>")
|
||||
{
|
||||
// Collect hashes for different JSON values and make sure that they are distinct
|
||||
// We cannot compare against fixed values, because the implementation of
|
||||
// std::hash may differ between compilers.
|
||||
|
||||
std::set<std::size_t> hashes;
|
||||
|
||||
// null
|
||||
hashes.insert(std::hash<ordered_json> {}(ordered_json(nullptr)));
|
||||
|
||||
// boolean
|
||||
hashes.insert(std::hash<ordered_json> {}(ordered_json(true)));
|
||||
hashes.insert(std::hash<ordered_json> {}(ordered_json(false)));
|
||||
|
||||
// string
|
||||
hashes.insert(std::hash<ordered_json> {}(ordered_json("")));
|
||||
hashes.insert(std::hash<ordered_json> {}(ordered_json("foo")));
|
||||
|
||||
// number
|
||||
hashes.insert(std::hash<ordered_json> {}(ordered_json(0)));
|
||||
hashes.insert(std::hash<ordered_json> {}(ordered_json(static_cast<unsigned>(0))));
|
||||
|
||||
hashes.insert(std::hash<ordered_json> {}(ordered_json(-1)));
|
||||
hashes.insert(std::hash<ordered_json> {}(ordered_json(0.0)));
|
||||
hashes.insert(std::hash<ordered_json> {}(ordered_json(42.23)));
|
||||
|
||||
// array
|
||||
hashes.insert(std::hash<ordered_json> {}(ordered_json::array()));
|
||||
hashes.insert(std::hash<ordered_json> {}(ordered_json::array({1, 2, 3})));
|
||||
|
||||
// object
|
||||
hashes.insert(std::hash<ordered_json> {}(ordered_json::object()));
|
||||
hashes.insert(std::hash<ordered_json> {}(ordered_json::object({{"foo", "bar"}})));
|
||||
|
||||
// binary
|
||||
hashes.insert(std::hash<ordered_json> {}(ordered_json::binary({})));
|
||||
hashes.insert(std::hash<ordered_json> {}(ordered_json::binary({}, 0)));
|
||||
hashes.insert(std::hash<ordered_json> {}(ordered_json::binary({}, 42)));
|
||||
hashes.insert(std::hash<ordered_json> {}(ordered_json::binary({1, 2, 3})));
|
||||
hashes.insert(std::hash<ordered_json> {}(ordered_json::binary({1, 2, 3}, 0)));
|
||||
hashes.insert(std::hash<ordered_json> {}(ordered_json::binary({1, 2, 3}, 42)));
|
||||
|
||||
// discarded
|
||||
hashes.insert(std::hash<ordered_json> {}(ordered_json(ordered_json::value_t::discarded)));
|
||||
|
||||
CHECK(hashes.size() == 21);
|
||||
}
|
||||
@@ -0,0 +1,480 @@
|
||||
/*
|
||||
__ _____ _____ _____
|
||||
__| | __| | | | JSON for Modern C++ (test suite)
|
||||
| | |__ | | | | | | version 3.10.5
|
||||
|_____|_____|_____|_|___| https://github.com/nlohmann/json
|
||||
|
||||
Licensed under the MIT License <http://opensource.org/licenses/MIT>.
|
||||
SPDX-License-Identifier: MIT
|
||||
Copyright (c) 2013-2022 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 "doctest_compatibility.h"
|
||||
|
||||
#include <nlohmann/json.hpp>
|
||||
using nlohmann::json;
|
||||
|
||||
#include <fstream>
|
||||
#include <sstream>
|
||||
#include <test_data.hpp>
|
||||
|
||||
TEST_CASE("object inspection")
|
||||
{
|
||||
SECTION("convenience type checker")
|
||||
{
|
||||
SECTION("object")
|
||||
{
|
||||
json j {{"foo", 1}, {"bar", false}};
|
||||
CHECK(!j.is_null());
|
||||
CHECK(!j.is_boolean());
|
||||
CHECK(!j.is_number());
|
||||
CHECK(!j.is_number_integer());
|
||||
CHECK(!j.is_number_unsigned());
|
||||
CHECK(!j.is_number_float());
|
||||
CHECK(!j.is_binary());
|
||||
CHECK(j.is_object());
|
||||
CHECK(!j.is_array());
|
||||
CHECK(!j.is_string());
|
||||
CHECK(!j.is_discarded());
|
||||
CHECK(!j.is_primitive());
|
||||
CHECK(j.is_structured());
|
||||
}
|
||||
|
||||
SECTION("array")
|
||||
{
|
||||
json j {"foo", 1, 1u, 42.23, false};
|
||||
CHECK(!j.is_null());
|
||||
CHECK(!j.is_boolean());
|
||||
CHECK(!j.is_number());
|
||||
CHECK(!j.is_number_integer());
|
||||
CHECK(!j.is_number_unsigned());
|
||||
CHECK(!j.is_number_float());
|
||||
CHECK(!j.is_binary());
|
||||
CHECK(!j.is_object());
|
||||
CHECK(j.is_array());
|
||||
CHECK(!j.is_string());
|
||||
CHECK(!j.is_discarded());
|
||||
CHECK(!j.is_primitive());
|
||||
CHECK(j.is_structured());
|
||||
}
|
||||
|
||||
SECTION("null")
|
||||
{
|
||||
json j(nullptr);
|
||||
CHECK(j.is_null());
|
||||
CHECK(!j.is_boolean());
|
||||
CHECK(!j.is_number());
|
||||
CHECK(!j.is_number_integer());
|
||||
CHECK(!j.is_number_unsigned());
|
||||
CHECK(!j.is_number_float());
|
||||
CHECK(!j.is_binary());
|
||||
CHECK(!j.is_object());
|
||||
CHECK(!j.is_array());
|
||||
CHECK(!j.is_string());
|
||||
CHECK(!j.is_discarded());
|
||||
CHECK(j.is_primitive());
|
||||
CHECK(!j.is_structured());
|
||||
}
|
||||
|
||||
SECTION("boolean")
|
||||
{
|
||||
json j(true);
|
||||
CHECK(!j.is_null());
|
||||
CHECK(j.is_boolean());
|
||||
CHECK(!j.is_number());
|
||||
CHECK(!j.is_number_integer());
|
||||
CHECK(!j.is_number_unsigned());
|
||||
CHECK(!j.is_number_float());
|
||||
CHECK(!j.is_binary());
|
||||
CHECK(!j.is_object());
|
||||
CHECK(!j.is_array());
|
||||
CHECK(!j.is_string());
|
||||
CHECK(!j.is_discarded());
|
||||
CHECK(j.is_primitive());
|
||||
CHECK(!j.is_structured());
|
||||
}
|
||||
|
||||
SECTION("string")
|
||||
{
|
||||
json j("Hello world");
|
||||
CHECK(!j.is_null());
|
||||
CHECK(!j.is_boolean());
|
||||
CHECK(!j.is_number());
|
||||
CHECK(!j.is_number_integer());
|
||||
CHECK(!j.is_number_unsigned());
|
||||
CHECK(!j.is_number_float());
|
||||
CHECK(!j.is_binary());
|
||||
CHECK(!j.is_object());
|
||||
CHECK(!j.is_array());
|
||||
CHECK(j.is_string());
|
||||
CHECK(!j.is_discarded());
|
||||
CHECK(j.is_primitive());
|
||||
CHECK(!j.is_structured());
|
||||
}
|
||||
|
||||
SECTION("number (integer)")
|
||||
{
|
||||
json j(42);
|
||||
CHECK(!j.is_null());
|
||||
CHECK(!j.is_boolean());
|
||||
CHECK(j.is_number());
|
||||
CHECK(j.is_number_integer());
|
||||
CHECK(!j.is_number_unsigned());
|
||||
CHECK(!j.is_number_float());
|
||||
CHECK(!j.is_binary());
|
||||
CHECK(!j.is_object());
|
||||
CHECK(!j.is_array());
|
||||
CHECK(!j.is_string());
|
||||
CHECK(!j.is_discarded());
|
||||
CHECK(j.is_primitive());
|
||||
CHECK(!j.is_structured());
|
||||
}
|
||||
|
||||
SECTION("number (unsigned)")
|
||||
{
|
||||
json j(42u);
|
||||
CHECK(!j.is_null());
|
||||
CHECK(!j.is_boolean());
|
||||
CHECK(j.is_number());
|
||||
CHECK(j.is_number_integer());
|
||||
CHECK(j.is_number_unsigned());
|
||||
CHECK(!j.is_number_float());
|
||||
CHECK(!j.is_binary());
|
||||
CHECK(!j.is_object());
|
||||
CHECK(!j.is_array());
|
||||
CHECK(!j.is_string());
|
||||
CHECK(!j.is_discarded());
|
||||
CHECK(j.is_primitive());
|
||||
CHECK(!j.is_structured());
|
||||
}
|
||||
|
||||
SECTION("number (floating-point)")
|
||||
{
|
||||
json j(42.23);
|
||||
CHECK(!j.is_null());
|
||||
CHECK(!j.is_boolean());
|
||||
CHECK(j.is_number());
|
||||
CHECK(!j.is_number_integer());
|
||||
CHECK(!j.is_number_unsigned());
|
||||
CHECK(j.is_number_float());
|
||||
CHECK(!j.is_binary());
|
||||
CHECK(!j.is_object());
|
||||
CHECK(!j.is_array());
|
||||
CHECK(!j.is_string());
|
||||
CHECK(!j.is_discarded());
|
||||
CHECK(j.is_primitive());
|
||||
CHECK(!j.is_structured());
|
||||
}
|
||||
|
||||
SECTION("binary")
|
||||
{
|
||||
json j(json::value_t::binary);
|
||||
CHECK(!j.is_null());
|
||||
CHECK(!j.is_boolean());
|
||||
CHECK(!j.is_number());
|
||||
CHECK(!j.is_number_integer());
|
||||
CHECK(!j.is_number_unsigned());
|
||||
CHECK(!j.is_number_float());
|
||||
CHECK(j.is_binary());
|
||||
CHECK(!j.is_object());
|
||||
CHECK(!j.is_array());
|
||||
CHECK(!j.is_string());
|
||||
CHECK(!j.is_discarded());
|
||||
CHECK(j.is_primitive());
|
||||
CHECK(!j.is_structured());
|
||||
}
|
||||
|
||||
SECTION("discarded")
|
||||
{
|
||||
json j(json::value_t::discarded);
|
||||
CHECK(!j.is_null());
|
||||
CHECK(!j.is_boolean());
|
||||
CHECK(!j.is_number());
|
||||
CHECK(!j.is_number_integer());
|
||||
CHECK(!j.is_number_unsigned());
|
||||
CHECK(!j.is_number_float());
|
||||
CHECK(!j.is_binary());
|
||||
CHECK(!j.is_object());
|
||||
CHECK(!j.is_array());
|
||||
CHECK(!j.is_string());
|
||||
CHECK(j.is_discarded());
|
||||
CHECK(!j.is_primitive());
|
||||
CHECK(!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=1, space='\t'")
|
||||
{
|
||||
CHECK(j.dump(1, '\t') ==
|
||||
"{\n\t\"array\": [\n\t\t1,\n\t\t2,\n\t\t3,\n\t\t4\n\t],\n\t\"boolean\": false,\n\t\"null\": null,\n\t\"number\": 42,\n\t\"object\": {},\n\t\"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("indent=x")
|
||||
{
|
||||
CHECK(j.dump().size() == 94);
|
||||
CHECK(j.dump(1).size() == 127);
|
||||
CHECK(j.dump(2).size() == 142);
|
||||
CHECK(j.dump(512).size() == 7792);
|
||||
|
||||
// important test, because it yields a resize of the indent_string
|
||||
// inside the dump() function
|
||||
CHECK(j.dump(1024).size() == 15472);
|
||||
|
||||
const auto binary = json::binary({1, 2, 3}, 128);
|
||||
CHECK(binary.dump(1024).size() == 2086);
|
||||
}
|
||||
|
||||
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("dump with ensure_ascii and non-ASCII characters")
|
||||
{
|
||||
CHECK(json("ä").dump(-1, ' ', true) == "\"\\u00e4\"");
|
||||
CHECK(json("Ö").dump(-1, ' ', true) == "\"\\u00d6\"");
|
||||
CHECK(json("❤️").dump(-1, ' ', true) == "\"\\u2764\\ufe0f\"");
|
||||
}
|
||||
|
||||
SECTION("full Unicode escaping to ASCII")
|
||||
{
|
||||
SECTION("parsing yields the same JSON value")
|
||||
{
|
||||
std::ifstream f_escaped(TEST_DATA_DIRECTORY "/json_nlohmann_tests/all_unicode_ascii.json");
|
||||
std::ifstream f_unescaped(TEST_DATA_DIRECTORY "/json_nlohmann_tests/all_unicode.json");
|
||||
|
||||
json j1 = json::parse(f_escaped);
|
||||
json j2 = json::parse(f_unescaped);
|
||||
CHECK(j1 == j2);
|
||||
}
|
||||
|
||||
SECTION("dumping yields the same JSON text")
|
||||
{
|
||||
std::ifstream f_escaped(TEST_DATA_DIRECTORY "/json_nlohmann_tests/all_unicode_ascii.json");
|
||||
std::ifstream f_unescaped(TEST_DATA_DIRECTORY "/json_nlohmann_tests/all_unicode.json");
|
||||
|
||||
json value = json::parse(f_unescaped);
|
||||
std::string text = value.dump(4, ' ', true);
|
||||
|
||||
std::string expected((std::istreambuf_iterator<char>(f_escaped)),
|
||||
std::istreambuf_iterator<char>());
|
||||
CHECK(text == expected);
|
||||
}
|
||||
}
|
||||
|
||||
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.14159265358979;
|
||||
ss << j_number;
|
||||
|
||||
// check that precision has been overridden during serialization
|
||||
CHECK(ss.str() == "3.14159265358979");
|
||||
|
||||
// check that precision has been restored
|
||||
CHECK(ss.precision() == 3);
|
||||
}
|
||||
}
|
||||
|
||||
SECTION("round trips")
|
||||
{
|
||||
for (const auto& s :
|
||||
{"3.141592653589793", "1000000000000000010E5"
|
||||
})
|
||||
{
|
||||
json j1 = json::parse(s);
|
||||
std::string s1 = j1.dump();
|
||||
json j2 = json::parse(s1);
|
||||
std::string s2 = j2.dump();
|
||||
CHECK(s1 == s2);
|
||||
}
|
||||
}
|
||||
|
||||
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());
|
||||
}
|
||||
|
||||
SECTION("binary")
|
||||
{
|
||||
json j = json::binary({});
|
||||
json::value_t t = j;
|
||||
CHECK(t == j.type());
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,884 @@
|
||||
/*
|
||||
__ _____ _____ _____
|
||||
__| | __| | | | JSON for Modern C++ (test suite)
|
||||
| | |__ | | | | | | version 3.10.5
|
||||
|_____|_____|_____|_|___| https://github.com/nlohmann/json
|
||||
|
||||
Licensed under the MIT License <http://opensource.org/licenses/MIT>.
|
||||
SPDX-License-Identifier: MIT
|
||||
Copyright (c) 2013-2022 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 "doctest_compatibility.h"
|
||||
|
||||
#include <nlohmann/json.hpp>
|
||||
using nlohmann::json;
|
||||
|
||||
TEST_CASE("iterators 2")
|
||||
{
|
||||
SECTION("iterator comparisons")
|
||||
{
|
||||
json j_values = {nullptr, true, 42, 42u, 23.23, {{"one", 1}, {"two", 2}}, {1, 2, 3, 4, 5}, "Hello, world"};
|
||||
|
||||
for (json& j : j_values)
|
||||
{
|
||||
auto it1 = j.begin();
|
||||
auto it2 = j.begin();
|
||||
auto it3 = j.begin();
|
||||
++it2;
|
||||
++it3;
|
||||
++it3;
|
||||
auto it1_c = j.cbegin();
|
||||
auto it2_c = j.cbegin();
|
||||
auto it3_c = j.cbegin();
|
||||
++it2_c;
|
||||
++it3_c;
|
||||
++it3_c;
|
||||
|
||||
// comparison: equal
|
||||
{
|
||||
CHECK(it1 == it1);
|
||||
CHECK(!(it1 == it2));
|
||||
CHECK(!(it1 == it3));
|
||||
CHECK(!(it2 == it3));
|
||||
CHECK(it1_c == it1_c);
|
||||
CHECK(!(it1_c == it2_c));
|
||||
CHECK(!(it1_c == it3_c));
|
||||
CHECK(!(it2_c == it3_c));
|
||||
}
|
||||
|
||||
// comparison: not equal
|
||||
{
|
||||
// check definition
|
||||
CHECK( (it1 != it1) == !(it1 == it1) );
|
||||
CHECK( (it1 != it2) == !(it1 == it2) );
|
||||
CHECK( (it1 != it3) == !(it1 == it3) );
|
||||
CHECK( (it2 != it3) == !(it2 == it3) );
|
||||
CHECK( (it1_c != it1_c) == !(it1_c == it1_c) );
|
||||
CHECK( (it1_c != it2_c) == !(it1_c == it2_c) );
|
||||
CHECK( (it1_c != it3_c) == !(it1_c == it3_c) );
|
||||
CHECK( (it2_c != it3_c) == !(it2_c == it3_c) );
|
||||
}
|
||||
|
||||
// comparison: smaller
|
||||
{
|
||||
if (j.type() == json::value_t::object)
|
||||
{
|
||||
#if JSON_DIAGNOSTICS
|
||||
CHECK_THROWS_WITH_AS(it1 < it1, "[json.exception.invalid_iterator.213] (/5) cannot compare order of object iterators", json::invalid_iterator&);
|
||||
CHECK_THROWS_WITH_AS(it1 < it2, "[json.exception.invalid_iterator.213] (/5) cannot compare order of object iterators", json::invalid_iterator&);
|
||||
CHECK_THROWS_WITH_AS(it2 < it3, "[json.exception.invalid_iterator.213] (/5) cannot compare order of object iterators", json::invalid_iterator&);
|
||||
CHECK_THROWS_WITH_AS(it1 < it3, "[json.exception.invalid_iterator.213] (/5) cannot compare order of object iterators", json::invalid_iterator&);
|
||||
CHECK_THROWS_WITH_AS(it1_c < it1_c, "[json.exception.invalid_iterator.213] (/5) cannot compare order of object iterators", json::invalid_iterator&);
|
||||
CHECK_THROWS_WITH_AS(it1_c < it2_c, "[json.exception.invalid_iterator.213] (/5) cannot compare order of object iterators", json::invalid_iterator&);
|
||||
CHECK_THROWS_WITH_AS(it2_c < it3_c, "[json.exception.invalid_iterator.213] (/5) cannot compare order of object iterators", json::invalid_iterator&);
|
||||
CHECK_THROWS_WITH_AS(it1_c < it3_c, "[json.exception.invalid_iterator.213] (/5) cannot compare order of object iterators", json::invalid_iterator&);
|
||||
#else
|
||||
CHECK_THROWS_WITH_AS(it1 < it1, "[json.exception.invalid_iterator.213] cannot compare order of object iterators", json::invalid_iterator&);
|
||||
CHECK_THROWS_WITH_AS(it1 < it2, "[json.exception.invalid_iterator.213] cannot compare order of object iterators", json::invalid_iterator&);
|
||||
CHECK_THROWS_WITH_AS(it2 < it3, "[json.exception.invalid_iterator.213] cannot compare order of object iterators", json::invalid_iterator&);
|
||||
CHECK_THROWS_WITH_AS(it1 < it3, "[json.exception.invalid_iterator.213] cannot compare order of object iterators", json::invalid_iterator&);
|
||||
CHECK_THROWS_WITH_AS(it1_c < it1_c, "[json.exception.invalid_iterator.213] cannot compare order of object iterators", json::invalid_iterator&);
|
||||
CHECK_THROWS_WITH_AS(it1_c < it2_c, "[json.exception.invalid_iterator.213] cannot compare order of object iterators", json::invalid_iterator&);
|
||||
CHECK_THROWS_WITH_AS(it2_c < it3_c, "[json.exception.invalid_iterator.213] cannot compare order of object iterators", json::invalid_iterator&);
|
||||
CHECK_THROWS_WITH_AS(it1_c < it3_c, "[json.exception.invalid_iterator.213] cannot compare order of object iterators", json::invalid_iterator&);
|
||||
#endif
|
||||
}
|
||||
else
|
||||
{
|
||||
CHECK(!(it1 < it1));
|
||||
CHECK(it1 < it2);
|
||||
CHECK(it1 < it3);
|
||||
CHECK(it2 < it3);
|
||||
CHECK(!(it1_c < it1_c));
|
||||
CHECK(it1_c < it2_c);
|
||||
CHECK(it1_c < it3_c);
|
||||
CHECK(it2_c < it3_c);
|
||||
}
|
||||
}
|
||||
|
||||
// comparison: less than or equal
|
||||
{
|
||||
if (j.type() == json::value_t::object)
|
||||
{
|
||||
#if JSON_DIAGNOSTICS
|
||||
CHECK_THROWS_WITH_AS(it1 <= it1, "[json.exception.invalid_iterator.213] (/5) cannot compare order of object iterators", json::invalid_iterator&);
|
||||
CHECK_THROWS_WITH_AS(it1 <= it2, "[json.exception.invalid_iterator.213] (/5) cannot compare order of object iterators", json::invalid_iterator&);
|
||||
CHECK_THROWS_WITH_AS(it2 <= it3, "[json.exception.invalid_iterator.213] (/5) cannot compare order of object iterators", json::invalid_iterator&);
|
||||
CHECK_THROWS_WITH_AS(it1 <= it3, "[json.exception.invalid_iterator.213] (/5) cannot compare order of object iterators", json::invalid_iterator&);
|
||||
CHECK_THROWS_WITH_AS(it1_c <= it1_c, "[json.exception.invalid_iterator.213] (/5) cannot compare order of object iterators", json::invalid_iterator&);
|
||||
CHECK_THROWS_WITH_AS(it1_c <= it2_c, "[json.exception.invalid_iterator.213] (/5) cannot compare order of object iterators", json::invalid_iterator&);
|
||||
CHECK_THROWS_WITH_AS(it2_c <= it3_c, "[json.exception.invalid_iterator.213] (/5) cannot compare order of object iterators", json::invalid_iterator&);
|
||||
CHECK_THROWS_WITH_AS(it1_c <= it3_c, "[json.exception.invalid_iterator.213] (/5) cannot compare order of object iterators", json::invalid_iterator&);
|
||||
#else
|
||||
CHECK_THROWS_WITH_AS(it1 <= it1, "[json.exception.invalid_iterator.213] cannot compare order of object iterators", json::invalid_iterator&);
|
||||
CHECK_THROWS_WITH_AS(it1 <= it2, "[json.exception.invalid_iterator.213] cannot compare order of object iterators", json::invalid_iterator&);
|
||||
CHECK_THROWS_WITH_AS(it2 <= it3, "[json.exception.invalid_iterator.213] cannot compare order of object iterators", json::invalid_iterator&);
|
||||
CHECK_THROWS_WITH_AS(it1 <= it3, "[json.exception.invalid_iterator.213] cannot compare order of object iterators", json::invalid_iterator&);
|
||||
CHECK_THROWS_WITH_AS(it1_c <= it1_c, "[json.exception.invalid_iterator.213] cannot compare order of object iterators", json::invalid_iterator&);
|
||||
CHECK_THROWS_WITH_AS(it1_c <= it2_c, "[json.exception.invalid_iterator.213] cannot compare order of object iterators", json::invalid_iterator&);
|
||||
CHECK_THROWS_WITH_AS(it2_c <= it3_c, "[json.exception.invalid_iterator.213] cannot compare order of object iterators", json::invalid_iterator&);
|
||||
CHECK_THROWS_WITH_AS(it1_c <= it3_c, "[json.exception.invalid_iterator.213] cannot compare order of object iterators", json::invalid_iterator&);
|
||||
#endif
|
||||
}
|
||||
else
|
||||
{
|
||||
// check definition
|
||||
CHECK( (it1 <= it1) == !(it1 < it1) );
|
||||
CHECK( (it1 <= it2) == !(it2 < it1) );
|
||||
CHECK( (it1 <= it3) == !(it3 < it1) );
|
||||
CHECK( (it2 <= it3) == !(it3 < it2) );
|
||||
CHECK( (it1_c <= it1_c) == !(it1_c < it1_c) );
|
||||
CHECK( (it1_c <= it2_c) == !(it2_c < it1_c) );
|
||||
CHECK( (it1_c <= it3_c) == !(it3_c < it1_c) );
|
||||
CHECK( (it2_c <= it3_c) == !(it3_c < it2_c) );
|
||||
}
|
||||
}
|
||||
|
||||
// comparison: greater than
|
||||
{
|
||||
if (j.type() == json::value_t::object)
|
||||
{
|
||||
#if JSON_DIAGNOSTICS
|
||||
CHECK_THROWS_WITH_AS(it1 > it1, "[json.exception.invalid_iterator.213] (/5) cannot compare order of object iterators", json::invalid_iterator&);
|
||||
CHECK_THROWS_WITH_AS(it1 > it2, "[json.exception.invalid_iterator.213] (/5) cannot compare order of object iterators", json::invalid_iterator&);
|
||||
CHECK_THROWS_WITH_AS(it2 > it3, "[json.exception.invalid_iterator.213] (/5) cannot compare order of object iterators", json::invalid_iterator&);
|
||||
CHECK_THROWS_WITH_AS(it1 > it3, "[json.exception.invalid_iterator.213] (/5) cannot compare order of object iterators", json::invalid_iterator&);
|
||||
CHECK_THROWS_WITH_AS(it1_c > it1_c, "[json.exception.invalid_iterator.213] (/5) cannot compare order of object iterators", json::invalid_iterator&);
|
||||
CHECK_THROWS_WITH_AS(it1_c > it2_c, "[json.exception.invalid_iterator.213] (/5) cannot compare order of object iterators", json::invalid_iterator&);
|
||||
CHECK_THROWS_WITH_AS(it2_c > it3_c, "[json.exception.invalid_iterator.213] (/5) cannot compare order of object iterators", json::invalid_iterator&);
|
||||
CHECK_THROWS_WITH_AS(it1_c > it3_c, "[json.exception.invalid_iterator.213] (/5) cannot compare order of object iterators", json::invalid_iterator&);
|
||||
#else
|
||||
CHECK_THROWS_WITH_AS(it1 > it1, "[json.exception.invalid_iterator.213] cannot compare order of object iterators", json::invalid_iterator&);
|
||||
CHECK_THROWS_WITH_AS(it1 > it2, "[json.exception.invalid_iterator.213] cannot compare order of object iterators", json::invalid_iterator&);
|
||||
CHECK_THROWS_WITH_AS(it2 > it3, "[json.exception.invalid_iterator.213] cannot compare order of object iterators", json::invalid_iterator&);
|
||||
CHECK_THROWS_WITH_AS(it1 > it3, "[json.exception.invalid_iterator.213] cannot compare order of object iterators", json::invalid_iterator&);
|
||||
CHECK_THROWS_WITH_AS(it1_c > it1_c, "[json.exception.invalid_iterator.213] cannot compare order of object iterators", json::invalid_iterator&);
|
||||
CHECK_THROWS_WITH_AS(it1_c > it2_c, "[json.exception.invalid_iterator.213] cannot compare order of object iterators", json::invalid_iterator&);
|
||||
CHECK_THROWS_WITH_AS(it2_c > it3_c, "[json.exception.invalid_iterator.213] cannot compare order of object iterators", json::invalid_iterator&);
|
||||
CHECK_THROWS_WITH_AS(it1_c > it3_c, "[json.exception.invalid_iterator.213] cannot compare order of object iterators", json::invalid_iterator&);
|
||||
#endif
|
||||
}
|
||||
else
|
||||
{
|
||||
// check definition
|
||||
CHECK( (it1 > it1) == (it1 < it1) );
|
||||
CHECK( (it1 > it2) == (it2 < it1) );
|
||||
CHECK( (it1 > it3) == (it3 < it1) );
|
||||
CHECK( (it2 > it3) == (it3 < it2) );
|
||||
CHECK( (it1_c > it1_c) == (it1_c < it1_c) );
|
||||
CHECK( (it1_c > it2_c) == (it2_c < it1_c) );
|
||||
CHECK( (it1_c > it3_c) == (it3_c < it1_c) );
|
||||
CHECK( (it2_c > it3_c) == (it3_c < it2_c) );
|
||||
}
|
||||
}
|
||||
|
||||
// comparison: greater than or equal
|
||||
{
|
||||
if (j.type() == json::value_t::object)
|
||||
{
|
||||
#if JSON_DIAGNOSTICS
|
||||
CHECK_THROWS_WITH_AS(it1 >= it1, "[json.exception.invalid_iterator.213] (/5) cannot compare order of object iterators", json::invalid_iterator&);
|
||||
CHECK_THROWS_WITH_AS(it1 >= it2, "[json.exception.invalid_iterator.213] (/5) cannot compare order of object iterators", json::invalid_iterator&);
|
||||
CHECK_THROWS_WITH_AS(it2 >= it3, "[json.exception.invalid_iterator.213] (/5) cannot compare order of object iterators", json::invalid_iterator&);
|
||||
CHECK_THROWS_WITH_AS(it1 >= it3, "[json.exception.invalid_iterator.213] (/5) cannot compare order of object iterators", json::invalid_iterator&);
|
||||
CHECK_THROWS_WITH_AS(it1_c >= it1_c, "[json.exception.invalid_iterator.213] (/5) cannot compare order of object iterators", json::invalid_iterator&);
|
||||
CHECK_THROWS_WITH_AS(it1_c >= it2_c, "[json.exception.invalid_iterator.213] (/5) cannot compare order of object iterators", json::invalid_iterator&);
|
||||
CHECK_THROWS_WITH_AS(it2_c >= it3_c, "[json.exception.invalid_iterator.213] (/5) cannot compare order of object iterators", json::invalid_iterator&);
|
||||
CHECK_THROWS_WITH_AS(it1_c >= it3_c, "[json.exception.invalid_iterator.213] (/5) cannot compare order of object iterators", json::invalid_iterator&);
|
||||
#else
|
||||
CHECK_THROWS_WITH_AS(it1 >= it1, "[json.exception.invalid_iterator.213] cannot compare order of object iterators", json::invalid_iterator&);
|
||||
CHECK_THROWS_WITH_AS(it1 >= it2, "[json.exception.invalid_iterator.213] cannot compare order of object iterators", json::invalid_iterator&);
|
||||
CHECK_THROWS_WITH_AS(it2 >= it3, "[json.exception.invalid_iterator.213] cannot compare order of object iterators", json::invalid_iterator&);
|
||||
CHECK_THROWS_WITH_AS(it1 >= it3, "[json.exception.invalid_iterator.213] cannot compare order of object iterators", json::invalid_iterator&);
|
||||
CHECK_THROWS_WITH_AS(it1_c >= it1_c, "[json.exception.invalid_iterator.213] cannot compare order of object iterators", json::invalid_iterator&);
|
||||
CHECK_THROWS_WITH_AS(it1_c >= it2_c, "[json.exception.invalid_iterator.213] cannot compare order of object iterators", json::invalid_iterator&);
|
||||
CHECK_THROWS_WITH_AS(it2_c >= it3_c, "[json.exception.invalid_iterator.213] cannot compare order of object iterators", json::invalid_iterator&);
|
||||
CHECK_THROWS_WITH_AS(it1_c >= it3_c, "[json.exception.invalid_iterator.213] cannot compare order of object iterators", json::invalid_iterator&);
|
||||
#endif
|
||||
}
|
||||
else
|
||||
{
|
||||
// check definition
|
||||
CHECK( (it1 >= it1) == !(it1 < it1) );
|
||||
CHECK( (it1 >= it2) == !(it1 < it2) );
|
||||
CHECK( (it1 >= it3) == !(it1 < it3) );
|
||||
CHECK( (it2 >= it3) == !(it2 < it3) );
|
||||
CHECK( (it1_c >= it1_c) == !(it1_c < it1_c) );
|
||||
CHECK( (it1_c >= it2_c) == !(it1_c < it2_c) );
|
||||
CHECK( (it1_c >= it3_c) == !(it1_c < it3_c) );
|
||||
CHECK( (it2_c >= it3_c) == !(it2_c < it3_c) );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// check exceptions if different objects are compared
|
||||
for (auto j : j_values)
|
||||
{
|
||||
for (auto k : j_values)
|
||||
{
|
||||
if (j != k)
|
||||
{
|
||||
#if JSON_DIAGNOSTICS
|
||||
// the output differs in each loop, so we cannot fix a string for the expected exception
|
||||
#else
|
||||
CHECK_THROWS_WITH_AS(j.begin() == k.begin(), "[json.exception.invalid_iterator.212] cannot compare iterators of different containers", json::invalid_iterator&);
|
||||
CHECK_THROWS_WITH_AS(j.cbegin() == k.cbegin(), "[json.exception.invalid_iterator.212] cannot compare iterators of different containers", json::invalid_iterator&);
|
||||
CHECK_THROWS_WITH_AS(j.begin() < k.begin(), "[json.exception.invalid_iterator.212] cannot compare iterators of different containers", json::invalid_iterator&);
|
||||
CHECK_THROWS_WITH_AS(j.cbegin() < k.cbegin(), "[json.exception.invalid_iterator.212] cannot compare iterators of different containers", json::invalid_iterator&);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
SECTION("iterator arithmetic")
|
||||
{
|
||||
json j_object = {{"one", 1}, {"two", 2}, {"three", 3}};
|
||||
json j_array = {1, 2, 3, 4, 5, 6};
|
||||
json j_null = nullptr;
|
||||
json j_value = 42;
|
||||
|
||||
SECTION("addition and subtraction")
|
||||
{
|
||||
SECTION("object")
|
||||
{
|
||||
{
|
||||
auto it = j_object.begin();
|
||||
CHECK_THROWS_WITH_AS(it += 1, "[json.exception.invalid_iterator.209] cannot use offsets with object iterators", json::invalid_iterator&);
|
||||
}
|
||||
{
|
||||
auto it = j_object.cbegin();
|
||||
CHECK_THROWS_WITH_AS(it += 1, "[json.exception.invalid_iterator.209] cannot use offsets with object iterators", json::invalid_iterator&);
|
||||
}
|
||||
{
|
||||
auto it = j_object.begin();
|
||||
CHECK_THROWS_WITH_AS(it + 1, "[json.exception.invalid_iterator.209] cannot use offsets with object iterators", json::invalid_iterator&);
|
||||
}
|
||||
{
|
||||
auto it = j_object.cbegin();
|
||||
CHECK_THROWS_WITH_AS(it + 1, "[json.exception.invalid_iterator.209] cannot use offsets with object iterators", json::invalid_iterator&);
|
||||
}
|
||||
{
|
||||
auto it = j_object.begin();
|
||||
CHECK_THROWS_WITH_AS(1 + it, "[json.exception.invalid_iterator.209] cannot use offsets with object iterators", json::invalid_iterator&);
|
||||
}
|
||||
{
|
||||
auto it = j_object.cbegin();
|
||||
CHECK_THROWS_WITH_AS(1 + it, "[json.exception.invalid_iterator.209] cannot use offsets with object iterators", json::invalid_iterator&);
|
||||
}
|
||||
{
|
||||
auto it = j_object.begin();
|
||||
CHECK_THROWS_WITH_AS(it -= 1, "[json.exception.invalid_iterator.209] cannot use offsets with object iterators", json::invalid_iterator&);
|
||||
}
|
||||
{
|
||||
auto it = j_object.cbegin();
|
||||
CHECK_THROWS_WITH_AS(it -= 1, "[json.exception.invalid_iterator.209] cannot use offsets with object iterators", json::invalid_iterator&);
|
||||
}
|
||||
{
|
||||
auto it = j_object.begin();
|
||||
CHECK_THROWS_WITH_AS(it - 1, "[json.exception.invalid_iterator.209] cannot use offsets with object iterators", json::invalid_iterator&);
|
||||
}
|
||||
{
|
||||
auto it = j_object.cbegin();
|
||||
CHECK_THROWS_WITH_AS(it - 1, "[json.exception.invalid_iterator.209] cannot use offsets with object iterators", json::invalid_iterator&);
|
||||
}
|
||||
{
|
||||
auto it = j_object.begin();
|
||||
CHECK_THROWS_WITH_AS(it - it, "[json.exception.invalid_iterator.209] cannot use offsets with object iterators", json::invalid_iterator&);
|
||||
}
|
||||
{
|
||||
auto it = j_object.cbegin();
|
||||
CHECK_THROWS_WITH_AS(it - it, "[json.exception.invalid_iterator.209] cannot use offsets with object iterators", json::invalid_iterator&);
|
||||
}
|
||||
}
|
||||
|
||||
SECTION("array")
|
||||
{
|
||||
{
|
||||
auto it = j_array.begin();
|
||||
it += 3;
|
||||
CHECK((j_array.begin() + 3) == it);
|
||||
CHECK((3 + j_array.begin()) == it);
|
||||
CHECK((it - 3) == j_array.begin());
|
||||
CHECK((it - j_array.begin()) == 3);
|
||||
CHECK(*it == json(4));
|
||||
it -= 2;
|
||||
CHECK(*it == json(2));
|
||||
}
|
||||
{
|
||||
auto it = j_array.cbegin();
|
||||
it += 3;
|
||||
CHECK((j_array.cbegin() + 3) == it);
|
||||
CHECK((3 + j_array.cbegin()) == it);
|
||||
CHECK((it - 3) == j_array.cbegin());
|
||||
CHECK((it - j_array.cbegin()) == 3);
|
||||
CHECK(*it == json(4));
|
||||
it -= 2;
|
||||
CHECK(*it == json(2));
|
||||
}
|
||||
}
|
||||
|
||||
SECTION("null")
|
||||
{
|
||||
{
|
||||
auto it = j_null.begin();
|
||||
it += 3;
|
||||
CHECK((j_null.begin() + 3) == it);
|
||||
CHECK((3 + j_null.begin()) == it);
|
||||
CHECK((it - 3) == j_null.begin());
|
||||
CHECK((it - j_null.begin()) == 3);
|
||||
CHECK(it != j_null.end());
|
||||
it -= 3;
|
||||
CHECK(it == j_null.end());
|
||||
}
|
||||
{
|
||||
auto it = j_null.cbegin();
|
||||
it += 3;
|
||||
CHECK((j_null.cbegin() + 3) == it);
|
||||
CHECK((3 + j_null.cbegin()) == it);
|
||||
CHECK((it - 3) == j_null.cbegin());
|
||||
CHECK((it - j_null.cbegin()) == 3);
|
||||
CHECK(it != j_null.cend());
|
||||
it -= 3;
|
||||
CHECK(it == j_null.cend());
|
||||
}
|
||||
}
|
||||
|
||||
SECTION("value")
|
||||
{
|
||||
{
|
||||
auto it = j_value.begin();
|
||||
it += 3;
|
||||
CHECK((j_value.begin() + 3) == it);
|
||||
CHECK((3 + j_value.begin()) == it);
|
||||
CHECK((it - 3) == j_value.begin());
|
||||
CHECK((it - j_value.begin()) == 3);
|
||||
CHECK(it != j_value.end());
|
||||
it -= 3;
|
||||
CHECK(*it == json(42));
|
||||
}
|
||||
{
|
||||
auto it = j_value.cbegin();
|
||||
it += 3;
|
||||
CHECK((j_value.cbegin() + 3) == it);
|
||||
CHECK((3 + j_value.cbegin()) == it);
|
||||
CHECK((it - 3) == j_value.cbegin());
|
||||
CHECK((it - j_value.cbegin()) == 3);
|
||||
CHECK(it != j_value.cend());
|
||||
it -= 3;
|
||||
CHECK(*it == json(42));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
SECTION("subscript operator")
|
||||
{
|
||||
SECTION("object")
|
||||
{
|
||||
{
|
||||
auto it = j_object.begin();
|
||||
CHECK_THROWS_WITH_AS(it[0], "[json.exception.invalid_iterator.208] cannot use operator[] for object iterators", json::invalid_iterator&);
|
||||
CHECK_THROWS_WITH_AS(it[1], "[json.exception.invalid_iterator.208] cannot use operator[] for object iterators", json::invalid_iterator&);
|
||||
}
|
||||
{
|
||||
auto it = j_object.cbegin();
|
||||
CHECK_THROWS_WITH_AS(it[0], "[json.exception.invalid_iterator.208] cannot use operator[] for object iterators", json::invalid_iterator&);
|
||||
CHECK_THROWS_WITH_AS(it[1], "[json.exception.invalid_iterator.208] cannot use operator[] for object iterators", json::invalid_iterator&);
|
||||
}
|
||||
}
|
||||
|
||||
SECTION("array")
|
||||
{
|
||||
{
|
||||
auto it = j_array.begin();
|
||||
CHECK(it[0] == json(1));
|
||||
CHECK(it[1] == json(2));
|
||||
CHECK(it[2] == json(3));
|
||||
CHECK(it[3] == json(4));
|
||||
CHECK(it[4] == json(5));
|
||||
CHECK(it[5] == json(6));
|
||||
}
|
||||
{
|
||||
auto it = j_array.cbegin();
|
||||
CHECK(it[0] == json(1));
|
||||
CHECK(it[1] == json(2));
|
||||
CHECK(it[2] == json(3));
|
||||
CHECK(it[3] == json(4));
|
||||
CHECK(it[4] == json(5));
|
||||
CHECK(it[5] == json(6));
|
||||
}
|
||||
}
|
||||
|
||||
SECTION("null")
|
||||
{
|
||||
{
|
||||
auto it = j_null.begin();
|
||||
CHECK_THROWS_WITH_AS(it[0], "[json.exception.invalid_iterator.214] cannot get value", json::invalid_iterator&);
|
||||
CHECK_THROWS_WITH_AS(it[1], "[json.exception.invalid_iterator.214] cannot get value", json::invalid_iterator&);
|
||||
}
|
||||
{
|
||||
auto it = j_null.cbegin();
|
||||
CHECK_THROWS_WITH_AS(it[0], "[json.exception.invalid_iterator.214] cannot get value", json::invalid_iterator&);
|
||||
CHECK_THROWS_WITH_AS(it[1], "[json.exception.invalid_iterator.214] cannot get value", json::invalid_iterator&);
|
||||
}
|
||||
}
|
||||
|
||||
SECTION("value")
|
||||
{
|
||||
{
|
||||
auto it = j_value.begin();
|
||||
CHECK(it[0] == json(42));
|
||||
CHECK_THROWS_WITH_AS(it[1], "[json.exception.invalid_iterator.214] cannot get value", json::invalid_iterator&);
|
||||
}
|
||||
{
|
||||
auto it = j_value.cbegin();
|
||||
CHECK(it[0] == json(42));
|
||||
CHECK_THROWS_WITH_AS(it[1], "[json.exception.invalid_iterator.214] cannot get value", json::invalid_iterator&);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
SECTION("reverse iterator comparisons")
|
||||
{
|
||||
json j_values = {nullptr, true, 42, 42u, 23.23, {{"one", 1}, {"two", 2}}, {1, 2, 3, 4, 5}, "Hello, world"};
|
||||
|
||||
for (json& j : j_values)
|
||||
{
|
||||
auto it1 = j.rbegin();
|
||||
auto it2 = j.rbegin();
|
||||
auto it3 = j.rbegin();
|
||||
++it2;
|
||||
++it3;
|
||||
++it3;
|
||||
auto it1_c = j.crbegin();
|
||||
auto it2_c = j.crbegin();
|
||||
auto it3_c = j.crbegin();
|
||||
++it2_c;
|
||||
++it3_c;
|
||||
++it3_c;
|
||||
|
||||
// comparison: equal
|
||||
{
|
||||
CHECK(it1 == it1);
|
||||
CHECK(!(it1 == it2));
|
||||
CHECK(!(it1 == it3));
|
||||
CHECK(!(it2 == it3));
|
||||
CHECK(it1_c == it1_c);
|
||||
CHECK(!(it1_c == it2_c));
|
||||
CHECK(!(it1_c == it3_c));
|
||||
CHECK(!(it2_c == it3_c));
|
||||
}
|
||||
|
||||
// comparison: not equal
|
||||
{
|
||||
// check definition
|
||||
CHECK( (it1 != it1) == !(it1 == it1) );
|
||||
CHECK( (it1 != it2) == !(it1 == it2) );
|
||||
CHECK( (it1 != it3) == !(it1 == it3) );
|
||||
CHECK( (it2 != it3) == !(it2 == it3) );
|
||||
CHECK( (it1_c != it1_c) == !(it1_c == it1_c) );
|
||||
CHECK( (it1_c != it2_c) == !(it1_c == it2_c) );
|
||||
CHECK( (it1_c != it3_c) == !(it1_c == it3_c) );
|
||||
CHECK( (it2_c != it3_c) == !(it2_c == it3_c) );
|
||||
}
|
||||
|
||||
// comparison: smaller
|
||||
{
|
||||
if (j.type() == json::value_t::object)
|
||||
{
|
||||
#if JSON_DIAGNOSTICS
|
||||
CHECK_THROWS_WITH_AS(it1 < it1, "[json.exception.invalid_iterator.213] (/5) cannot compare order of object iterators", json::invalid_iterator&);
|
||||
CHECK_THROWS_WITH_AS(it1 < it2, "[json.exception.invalid_iterator.213] (/5) cannot compare order of object iterators", json::invalid_iterator&);
|
||||
CHECK_THROWS_WITH_AS(it2 < it3, "[json.exception.invalid_iterator.213] (/5) cannot compare order of object iterators", json::invalid_iterator&);
|
||||
CHECK_THROWS_WITH_AS(it1 < it3, "[json.exception.invalid_iterator.213] (/5) cannot compare order of object iterators", json::invalid_iterator&);
|
||||
CHECK_THROWS_WITH_AS(it1_c < it1_c, "[json.exception.invalid_iterator.213] (/5) cannot compare order of object iterators", json::invalid_iterator&);
|
||||
CHECK_THROWS_WITH_AS(it1_c < it2_c, "[json.exception.invalid_iterator.213] (/5) cannot compare order of object iterators", json::invalid_iterator&);
|
||||
CHECK_THROWS_WITH_AS(it2_c < it3_c, "[json.exception.invalid_iterator.213] (/5) cannot compare order of object iterators", json::invalid_iterator&);
|
||||
CHECK_THROWS_WITH_AS(it1_c < it3_c, "[json.exception.invalid_iterator.213] (/5) cannot compare order of object iterators", json::invalid_iterator&);
|
||||
#else
|
||||
CHECK_THROWS_WITH_AS(it1 < it1, "[json.exception.invalid_iterator.213] cannot compare order of object iterators", json::invalid_iterator&);
|
||||
CHECK_THROWS_WITH_AS(it1 < it2, "[json.exception.invalid_iterator.213] cannot compare order of object iterators", json::invalid_iterator&);
|
||||
CHECK_THROWS_WITH_AS(it2 < it3, "[json.exception.invalid_iterator.213] cannot compare order of object iterators", json::invalid_iterator&);
|
||||
CHECK_THROWS_WITH_AS(it1 < it3, "[json.exception.invalid_iterator.213] cannot compare order of object iterators", json::invalid_iterator&);
|
||||
CHECK_THROWS_WITH_AS(it1_c < it1_c, "[json.exception.invalid_iterator.213] cannot compare order of object iterators", json::invalid_iterator&);
|
||||
CHECK_THROWS_WITH_AS(it1_c < it2_c, "[json.exception.invalid_iterator.213] cannot compare order of object iterators", json::invalid_iterator&);
|
||||
CHECK_THROWS_WITH_AS(it2_c < it3_c, "[json.exception.invalid_iterator.213] cannot compare order of object iterators", json::invalid_iterator&);
|
||||
CHECK_THROWS_WITH_AS(it1_c < it3_c, "[json.exception.invalid_iterator.213] cannot compare order of object iterators", json::invalid_iterator&);
|
||||
#endif
|
||||
}
|
||||
else
|
||||
{
|
||||
CHECK(!(it1 < it1));
|
||||
CHECK(it1 < it2);
|
||||
CHECK(it1 < it3);
|
||||
CHECK(it2 < it3);
|
||||
CHECK(!(it1_c < it1_c));
|
||||
CHECK(it1_c < it2_c);
|
||||
CHECK(it1_c < it3_c);
|
||||
CHECK(it2_c < it3_c);
|
||||
}
|
||||
}
|
||||
|
||||
// comparison: less than or equal
|
||||
{
|
||||
if (j.type() == json::value_t::object)
|
||||
{
|
||||
#if JSON_DIAGNOSTICS
|
||||
CHECK_THROWS_WITH_AS(it1 <= it1, "[json.exception.invalid_iterator.213] (/5) cannot compare order of object iterators", json::invalid_iterator&);
|
||||
CHECK_THROWS_WITH_AS(it1 <= it2, "[json.exception.invalid_iterator.213] (/5) cannot compare order of object iterators", json::invalid_iterator&);
|
||||
CHECK_THROWS_WITH_AS(it2 <= it3, "[json.exception.invalid_iterator.213] (/5) cannot compare order of object iterators", json::invalid_iterator&);
|
||||
CHECK_THROWS_WITH_AS(it1 <= it3, "[json.exception.invalid_iterator.213] (/5) cannot compare order of object iterators", json::invalid_iterator&);
|
||||
CHECK_THROWS_WITH_AS(it1_c <= it1_c, "[json.exception.invalid_iterator.213] (/5) cannot compare order of object iterators", json::invalid_iterator&);
|
||||
CHECK_THROWS_WITH_AS(it1_c <= it2_c, "[json.exception.invalid_iterator.213] (/5) cannot compare order of object iterators", json::invalid_iterator&);
|
||||
CHECK_THROWS_WITH_AS(it2_c <= it3_c, "[json.exception.invalid_iterator.213] (/5) cannot compare order of object iterators", json::invalid_iterator&);
|
||||
CHECK_THROWS_WITH_AS(it1_c <= it3_c, "[json.exception.invalid_iterator.213] (/5) cannot compare order of object iterators", json::invalid_iterator&);
|
||||
#else
|
||||
CHECK_THROWS_WITH_AS(it1 <= it1, "[json.exception.invalid_iterator.213] cannot compare order of object iterators", json::invalid_iterator&);
|
||||
CHECK_THROWS_WITH_AS(it1 <= it2, "[json.exception.invalid_iterator.213] cannot compare order of object iterators", json::invalid_iterator&);
|
||||
CHECK_THROWS_WITH_AS(it2 <= it3, "[json.exception.invalid_iterator.213] cannot compare order of object iterators", json::invalid_iterator&);
|
||||
CHECK_THROWS_WITH_AS(it1 <= it3, "[json.exception.invalid_iterator.213] cannot compare order of object iterators", json::invalid_iterator&);
|
||||
CHECK_THROWS_WITH_AS(it1_c <= it1_c, "[json.exception.invalid_iterator.213] cannot compare order of object iterators", json::invalid_iterator&);
|
||||
CHECK_THROWS_WITH_AS(it1_c <= it2_c, "[json.exception.invalid_iterator.213] cannot compare order of object iterators", json::invalid_iterator&);
|
||||
CHECK_THROWS_WITH_AS(it2_c <= it3_c, "[json.exception.invalid_iterator.213] cannot compare order of object iterators", json::invalid_iterator&);
|
||||
CHECK_THROWS_WITH_AS(it1_c <= it3_c, "[json.exception.invalid_iterator.213] cannot compare order of object iterators", json::invalid_iterator&);
|
||||
#endif
|
||||
}
|
||||
else
|
||||
{
|
||||
// check definition
|
||||
CHECK( (it1 <= it1) == !(it1 < it1) );
|
||||
CHECK( (it1 <= it2) == !(it2 < it1) );
|
||||
CHECK( (it1 <= it3) == !(it3 < it1) );
|
||||
CHECK( (it2 <= it3) == !(it3 < it2) );
|
||||
CHECK( (it1_c <= it1_c) == !(it1_c < it1_c) );
|
||||
CHECK( (it1_c <= it2_c) == !(it2_c < it1_c) );
|
||||
CHECK( (it1_c <= it3_c) == !(it3_c < it1_c) );
|
||||
CHECK( (it2_c <= it3_c) == !(it3_c < it2_c) );
|
||||
}
|
||||
}
|
||||
|
||||
// comparison: greater than
|
||||
{
|
||||
if (j.type() == json::value_t::object)
|
||||
{
|
||||
#if JSON_DIAGNOSTICS
|
||||
CHECK_THROWS_WITH_AS(it1 > it1, "[json.exception.invalid_iterator.213] (/5) cannot compare order of object iterators", json::invalid_iterator&);
|
||||
CHECK_THROWS_WITH_AS(it1 > it2, "[json.exception.invalid_iterator.213] (/5) cannot compare order of object iterators", json::invalid_iterator&);
|
||||
CHECK_THROWS_WITH_AS(it2 > it3, "[json.exception.invalid_iterator.213] (/5) cannot compare order of object iterators", json::invalid_iterator&);
|
||||
CHECK_THROWS_WITH_AS(it1 > it3, "[json.exception.invalid_iterator.213] (/5) cannot compare order of object iterators", json::invalid_iterator&);
|
||||
CHECK_THROWS_WITH_AS(it1_c > it1_c, "[json.exception.invalid_iterator.213] (/5) cannot compare order of object iterators", json::invalid_iterator&);
|
||||
CHECK_THROWS_WITH_AS(it1_c > it2_c, "[json.exception.invalid_iterator.213] (/5) cannot compare order of object iterators", json::invalid_iterator&);
|
||||
CHECK_THROWS_WITH_AS(it2_c > it3_c, "[json.exception.invalid_iterator.213] (/5) cannot compare order of object iterators", json::invalid_iterator&);
|
||||
CHECK_THROWS_WITH_AS(it1_c > it3_c, "[json.exception.invalid_iterator.213] (/5) cannot compare order of object iterators", json::invalid_iterator&);
|
||||
#else
|
||||
CHECK_THROWS_WITH_AS(it1 > it1, "[json.exception.invalid_iterator.213] cannot compare order of object iterators", json::invalid_iterator&);
|
||||
CHECK_THROWS_WITH_AS(it1 > it2, "[json.exception.invalid_iterator.213] cannot compare order of object iterators", json::invalid_iterator&);
|
||||
CHECK_THROWS_WITH_AS(it2 > it3, "[json.exception.invalid_iterator.213] cannot compare order of object iterators", json::invalid_iterator&);
|
||||
CHECK_THROWS_WITH_AS(it1 > it3, "[json.exception.invalid_iterator.213] cannot compare order of object iterators", json::invalid_iterator&);
|
||||
CHECK_THROWS_WITH_AS(it1_c > it1_c, "[json.exception.invalid_iterator.213] cannot compare order of object iterators", json::invalid_iterator&);
|
||||
CHECK_THROWS_WITH_AS(it1_c > it2_c, "[json.exception.invalid_iterator.213] cannot compare order of object iterators", json::invalid_iterator&);
|
||||
CHECK_THROWS_WITH_AS(it2_c > it3_c, "[json.exception.invalid_iterator.213] cannot compare order of object iterators", json::invalid_iterator&);
|
||||
CHECK_THROWS_WITH_AS(it1_c > it3_c, "[json.exception.invalid_iterator.213] cannot compare order of object iterators", json::invalid_iterator&);
|
||||
#endif
|
||||
}
|
||||
else
|
||||
{
|
||||
// check definition
|
||||
CHECK( (it1 > it1) == (it1 < it1) );
|
||||
CHECK( (it1 > it2) == (it2 < it1) );
|
||||
CHECK( (it1 > it3) == (it3 < it1) );
|
||||
CHECK( (it2 > it3) == (it3 < it2) );
|
||||
CHECK( (it1_c > it1_c) == (it1_c < it1_c) );
|
||||
CHECK( (it1_c > it2_c) == (it2_c < it1_c) );
|
||||
CHECK( (it1_c > it3_c) == (it3_c < it1_c) );
|
||||
CHECK( (it2_c > it3_c) == (it3_c < it2_c) );
|
||||
}
|
||||
}
|
||||
|
||||
// comparison: greater than or equal
|
||||
{
|
||||
if (j.type() == json::value_t::object)
|
||||
{
|
||||
#if JSON_DIAGNOSTICS
|
||||
CHECK_THROWS_WITH_AS(it1 >= it1, "[json.exception.invalid_iterator.213] (/5) cannot compare order of object iterators", json::invalid_iterator&);
|
||||
CHECK_THROWS_WITH_AS(it1 >= it2, "[json.exception.invalid_iterator.213] (/5) cannot compare order of object iterators", json::invalid_iterator&);
|
||||
CHECK_THROWS_WITH_AS(it2 >= it3, "[json.exception.invalid_iterator.213] (/5) cannot compare order of object iterators", json::invalid_iterator&);
|
||||
CHECK_THROWS_WITH_AS(it1 >= it3, "[json.exception.invalid_iterator.213] (/5) cannot compare order of object iterators", json::invalid_iterator&);
|
||||
CHECK_THROWS_WITH_AS(it1_c >= it1_c, "[json.exception.invalid_iterator.213] (/5) cannot compare order of object iterators", json::invalid_iterator&);
|
||||
CHECK_THROWS_WITH_AS(it1_c >= it2_c, "[json.exception.invalid_iterator.213] (/5) cannot compare order of object iterators", json::invalid_iterator&);
|
||||
CHECK_THROWS_WITH_AS(it2_c >= it3_c, "[json.exception.invalid_iterator.213] (/5) cannot compare order of object iterators", json::invalid_iterator&);
|
||||
CHECK_THROWS_WITH_AS(it1_c >= it3_c, "[json.exception.invalid_iterator.213] (/5) cannot compare order of object iterators", json::invalid_iterator&);
|
||||
#else
|
||||
CHECK_THROWS_WITH_AS(it1 >= it1, "[json.exception.invalid_iterator.213] cannot compare order of object iterators", json::invalid_iterator&);
|
||||
CHECK_THROWS_WITH_AS(it1 >= it2, "[json.exception.invalid_iterator.213] cannot compare order of object iterators", json::invalid_iterator&);
|
||||
CHECK_THROWS_WITH_AS(it2 >= it3, "[json.exception.invalid_iterator.213] cannot compare order of object iterators", json::invalid_iterator&);
|
||||
CHECK_THROWS_WITH_AS(it1 >= it3, "[json.exception.invalid_iterator.213] cannot compare order of object iterators", json::invalid_iterator&);
|
||||
CHECK_THROWS_WITH_AS(it1_c >= it1_c, "[json.exception.invalid_iterator.213] cannot compare order of object iterators", json::invalid_iterator&);
|
||||
CHECK_THROWS_WITH_AS(it1_c >= it2_c, "[json.exception.invalid_iterator.213] cannot compare order of object iterators", json::invalid_iterator&);
|
||||
CHECK_THROWS_WITH_AS(it2_c >= it3_c, "[json.exception.invalid_iterator.213] cannot compare order of object iterators", json::invalid_iterator&);
|
||||
CHECK_THROWS_WITH_AS(it1_c >= it3_c, "[json.exception.invalid_iterator.213] cannot compare order of object iterators", json::invalid_iterator&);
|
||||
#endif
|
||||
}
|
||||
else
|
||||
{
|
||||
// check definition
|
||||
CHECK( (it1 >= it1) == !(it1 < it1) );
|
||||
CHECK( (it1 >= it2) == !(it1 < it2) );
|
||||
CHECK( (it1 >= it3) == !(it1 < it3) );
|
||||
CHECK( (it2 >= it3) == !(it2 < it3) );
|
||||
CHECK( (it1_c >= it1_c) == !(it1_c < it1_c) );
|
||||
CHECK( (it1_c >= it2_c) == !(it1_c < it2_c) );
|
||||
CHECK( (it1_c >= it3_c) == !(it1_c < it3_c) );
|
||||
CHECK( (it2_c >= it3_c) == !(it2_c < it3_c) );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// check exceptions if different objects are compared
|
||||
for (auto j : j_values)
|
||||
{
|
||||
for (auto k : j_values)
|
||||
{
|
||||
if (j != k)
|
||||
{
|
||||
#if JSON_DIAGNOSTICS
|
||||
// the output differs in each loop, so we cannot fix a string for the expected exception
|
||||
#else
|
||||
CHECK_THROWS_WITH_AS(j.rbegin() == k.rbegin(), "[json.exception.invalid_iterator.212] cannot compare iterators of different containers", json::invalid_iterator&);
|
||||
CHECK_THROWS_WITH_AS(j.crbegin() == k.crbegin(), "[json.exception.invalid_iterator.212] cannot compare iterators of different containers", json::invalid_iterator&);
|
||||
CHECK_THROWS_WITH_AS(j.rbegin() < k.rbegin(), "[json.exception.invalid_iterator.212] cannot compare iterators of different containers", json::invalid_iterator&);
|
||||
CHECK_THROWS_WITH_AS(j.crbegin() < k.crbegin(), "[json.exception.invalid_iterator.212] cannot compare iterators of different containers", json::invalid_iterator&);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
SECTION("reverse iterator arithmetic")
|
||||
{
|
||||
json j_object = {{"one", 1}, {"two", 2}, {"three", 3}};
|
||||
json j_array = {1, 2, 3, 4, 5, 6};
|
||||
json j_null = nullptr;
|
||||
json j_value = 42;
|
||||
|
||||
SECTION("addition and subtraction")
|
||||
{
|
||||
SECTION("object")
|
||||
{
|
||||
{
|
||||
auto it = j_object.rbegin();
|
||||
CHECK_THROWS_WITH_AS(it += 1, "[json.exception.invalid_iterator.209] cannot use offsets with object iterators", json::invalid_iterator&);
|
||||
}
|
||||
{
|
||||
auto it = j_object.crbegin();
|
||||
CHECK_THROWS_WITH_AS(it += 1, "[json.exception.invalid_iterator.209] cannot use offsets with object iterators", json::invalid_iterator&);
|
||||
}
|
||||
{
|
||||
auto it = j_object.rbegin();
|
||||
CHECK_THROWS_WITH_AS(it + 1, "[json.exception.invalid_iterator.209] cannot use offsets with object iterators", json::invalid_iterator&);
|
||||
}
|
||||
{
|
||||
auto it = j_object.crbegin();
|
||||
CHECK_THROWS_WITH_AS(it + 1, "[json.exception.invalid_iterator.209] cannot use offsets with object iterators", json::invalid_iterator&);
|
||||
}
|
||||
{
|
||||
auto it = j_object.rbegin();
|
||||
CHECK_THROWS_WITH_AS(1 + it, "[json.exception.invalid_iterator.209] cannot use offsets with object iterators", json::invalid_iterator&);
|
||||
}
|
||||
{
|
||||
auto it = j_object.crbegin();
|
||||
CHECK_THROWS_WITH_AS(1 + it, "[json.exception.invalid_iterator.209] cannot use offsets with object iterators", json::invalid_iterator&);
|
||||
}
|
||||
{
|
||||
auto it = j_object.rbegin();
|
||||
CHECK_THROWS_WITH_AS(it -= 1, "[json.exception.invalid_iterator.209] cannot use offsets with object iterators", json::invalid_iterator&);
|
||||
}
|
||||
{
|
||||
auto it = j_object.crbegin();
|
||||
CHECK_THROWS_WITH_AS(it -= 1, "[json.exception.invalid_iterator.209] cannot use offsets with object iterators", json::invalid_iterator&);
|
||||
}
|
||||
{
|
||||
auto it = j_object.rbegin();
|
||||
CHECK_THROWS_WITH_AS(it - 1, "[json.exception.invalid_iterator.209] cannot use offsets with object iterators", json::invalid_iterator&);
|
||||
}
|
||||
{
|
||||
auto it = j_object.crbegin();
|
||||
CHECK_THROWS_WITH_AS(it - 1, "[json.exception.invalid_iterator.209] cannot use offsets with object iterators", json::invalid_iterator&);
|
||||
}
|
||||
{
|
||||
auto it = j_object.rbegin();
|
||||
CHECK_THROWS_WITH_AS(it - it, "[json.exception.invalid_iterator.209] cannot use offsets with object iterators", json::invalid_iterator&);
|
||||
}
|
||||
{
|
||||
auto it = j_object.crbegin();
|
||||
CHECK_THROWS_WITH_AS(it - it, "[json.exception.invalid_iterator.209] cannot use offsets with object iterators", json::invalid_iterator&);
|
||||
}
|
||||
}
|
||||
|
||||
SECTION("array")
|
||||
{
|
||||
{
|
||||
auto it = j_array.rbegin();
|
||||
it += 3;
|
||||
CHECK((j_array.rbegin() + 3) == it);
|
||||
CHECK(json::reverse_iterator(3 + j_array.rbegin()) == it);
|
||||
CHECK((it - 3) == j_array.rbegin());
|
||||
CHECK((it - j_array.rbegin()) == 3);
|
||||
CHECK(*it == json(3));
|
||||
it -= 2;
|
||||
CHECK(*it == json(5));
|
||||
}
|
||||
{
|
||||
auto it = j_array.crbegin();
|
||||
it += 3;
|
||||
CHECK((j_array.crbegin() + 3) == it);
|
||||
CHECK(json::const_reverse_iterator(3 + j_array.crbegin()) == it);
|
||||
CHECK((it - 3) == j_array.crbegin());
|
||||
CHECK((it - j_array.crbegin()) == 3);
|
||||
CHECK(*it == json(3));
|
||||
it -= 2;
|
||||
CHECK(*it == json(5));
|
||||
}
|
||||
}
|
||||
|
||||
SECTION("null")
|
||||
{
|
||||
{
|
||||
auto it = j_null.rbegin();
|
||||
it += 3;
|
||||
CHECK((j_null.rbegin() + 3) == it);
|
||||
CHECK(json::reverse_iterator(3 + j_null.rbegin()) == it);
|
||||
CHECK((it - 3) == j_null.rbegin());
|
||||
CHECK((it - j_null.rbegin()) == 3);
|
||||
CHECK(it != j_null.rend());
|
||||
it -= 3;
|
||||
CHECK(it == j_null.rend());
|
||||
}
|
||||
{
|
||||
auto it = j_null.crbegin();
|
||||
it += 3;
|
||||
CHECK((j_null.crbegin() + 3) == it);
|
||||
CHECK(json::const_reverse_iterator(3 + j_null.crbegin()) == it);
|
||||
CHECK((it - 3) == j_null.crbegin());
|
||||
CHECK((it - j_null.crbegin()) == 3);
|
||||
CHECK(it != j_null.crend());
|
||||
it -= 3;
|
||||
CHECK(it == j_null.crend());
|
||||
}
|
||||
}
|
||||
|
||||
SECTION("value")
|
||||
{
|
||||
{
|
||||
auto it = j_value.rbegin();
|
||||
it += 3;
|
||||
CHECK((j_value.rbegin() + 3) == it);
|
||||
CHECK(json::reverse_iterator(3 + j_value.rbegin()) == it);
|
||||
CHECK((it - 3) == j_value.rbegin());
|
||||
CHECK((it - j_value.rbegin()) == 3);
|
||||
CHECK(it != j_value.rend());
|
||||
it -= 3;
|
||||
CHECK(*it == json(42));
|
||||
}
|
||||
{
|
||||
auto it = j_value.crbegin();
|
||||
it += 3;
|
||||
CHECK((j_value.crbegin() + 3) == it);
|
||||
CHECK(json::const_reverse_iterator(3 + j_value.crbegin()) == it);
|
||||
CHECK((it - 3) == j_value.crbegin());
|
||||
CHECK((it - j_value.crbegin()) == 3);
|
||||
CHECK(it != j_value.crend());
|
||||
it -= 3;
|
||||
CHECK(*it == json(42));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
SECTION("subscript operator")
|
||||
{
|
||||
SECTION("object")
|
||||
{
|
||||
{
|
||||
auto it = j_object.rbegin();
|
||||
CHECK_THROWS_WITH_AS(it[0], "[json.exception.invalid_iterator.209] cannot use offsets with object iterators", json::invalid_iterator&);
|
||||
CHECK_THROWS_WITH_AS(it[1], "[json.exception.invalid_iterator.209] cannot use offsets with object iterators", json::invalid_iterator&);
|
||||
}
|
||||
{
|
||||
auto it = j_object.crbegin();
|
||||
CHECK_THROWS_WITH_AS(it[0], "[json.exception.invalid_iterator.209] cannot use offsets with object iterators", json::invalid_iterator&);
|
||||
CHECK_THROWS_WITH_AS(it[1], "[json.exception.invalid_iterator.209] cannot use offsets with object iterators", json::invalid_iterator&);
|
||||
}
|
||||
}
|
||||
|
||||
SECTION("array")
|
||||
{
|
||||
{
|
||||
auto it = j_array.rbegin();
|
||||
CHECK(it[0] == json(6));
|
||||
CHECK(it[1] == json(5));
|
||||
CHECK(it[2] == json(4));
|
||||
CHECK(it[3] == json(3));
|
||||
CHECK(it[4] == json(2));
|
||||
CHECK(it[5] == json(1));
|
||||
}
|
||||
{
|
||||
auto it = j_array.crbegin();
|
||||
CHECK(it[0] == json(6));
|
||||
CHECK(it[1] == json(5));
|
||||
CHECK(it[2] == json(4));
|
||||
CHECK(it[3] == json(3));
|
||||
CHECK(it[4] == json(2));
|
||||
CHECK(it[5] == json(1));
|
||||
}
|
||||
}
|
||||
|
||||
SECTION("null")
|
||||
{
|
||||
{
|
||||
auto it = j_null.rbegin();
|
||||
CHECK_THROWS_WITH_AS(it[0], "[json.exception.invalid_iterator.214] cannot get value", json::invalid_iterator&);
|
||||
CHECK_THROWS_WITH_AS(it[1], "[json.exception.invalid_iterator.214] cannot get value", json::invalid_iterator&);
|
||||
}
|
||||
{
|
||||
auto it = j_null.crbegin();
|
||||
CHECK_THROWS_WITH_AS(it[0], "[json.exception.invalid_iterator.214] cannot get value", json::invalid_iterator&);
|
||||
CHECK_THROWS_WITH_AS(it[1], "[json.exception.invalid_iterator.214] cannot get value", json::invalid_iterator&);
|
||||
}
|
||||
}
|
||||
|
||||
SECTION("value")
|
||||
{
|
||||
{
|
||||
auto it = j_value.rbegin();
|
||||
CHECK(it[0] == json(42));
|
||||
CHECK_THROWS_WITH_AS(it[1], "[json.exception.invalid_iterator.214] cannot get value", json::invalid_iterator&);
|
||||
}
|
||||
{
|
||||
auto it = j_value.crbegin();
|
||||
CHECK(it[0] == json(42));
|
||||
CHECK_THROWS_WITH_AS(it[1], "[json.exception.invalid_iterator.214] cannot get value", json::invalid_iterator&);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,713 @@
|
||||
/*
|
||||
__ _____ _____ _____
|
||||
__| | __| | | | JSON for Modern C++ (test suite)
|
||||
| | |__ | | | | | | version 3.10.5
|
||||
|_____|_____|_____|_|___| https://github.com/nlohmann/json
|
||||
|
||||
Licensed under the MIT License <http://opensource.org/licenses/MIT>.
|
||||
SPDX-License-Identifier: MIT
|
||||
Copyright (c) 2013-2022 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 "doctest_compatibility.h"
|
||||
|
||||
#define JSON_TESTS_PRIVATE
|
||||
#include <nlohmann/json.hpp>
|
||||
using nlohmann::json;
|
||||
|
||||
TEST_CASE("JSON pointers")
|
||||
{
|
||||
SECTION("errors")
|
||||
{
|
||||
CHECK_THROWS_WITH_AS(json::json_pointer("foo"),
|
||||
"[json.exception.parse_error.107] parse error at byte 1: JSON pointer must be empty or begin with '/' - was: 'foo'", json::parse_error&);
|
||||
|
||||
CHECK_THROWS_WITH_AS(json::json_pointer("/~~"),
|
||||
"[json.exception.parse_error.108] parse error: escape character '~' must be followed with '0' or '1'", json::parse_error&);
|
||||
|
||||
CHECK_THROWS_WITH_AS(json::json_pointer("/~"),
|
||||
"[json.exception.parse_error.108] parse error: escape character '~' must be followed with '0' or '1'", json::parse_error&);
|
||||
|
||||
json::json_pointer p;
|
||||
CHECK_THROWS_WITH_AS(p.top(),
|
||||
"[json.exception.out_of_range.405] JSON pointer has no parent", json::out_of_range&);
|
||||
CHECK_THROWS_WITH_AS(p.pop_back(),
|
||||
"[json.exception.out_of_range.405] JSON pointer has no parent", json::out_of_range&);
|
||||
|
||||
SECTION("array index error")
|
||||
{
|
||||
json v = {1, 2, 3, 4};
|
||||
json::json_pointer ptr("/10e");
|
||||
CHECK_THROWS_WITH_AS(v[ptr],
|
||||
"[json.exception.out_of_range.404] unresolved reference token '10e'", json::out_of_range&);
|
||||
}
|
||||
}
|
||||
|
||||
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);
|
||||
CHECK(j.contains(json::json_pointer()));
|
||||
CHECK(j.contains(json::json_pointer("")));
|
||||
|
||||
// array access
|
||||
CHECK(j[json::json_pointer("/foo")] == j["foo"]);
|
||||
CHECK(j.contains(json::json_pointer("/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]);
|
||||
CHECK(j.contains(json::json_pointer("/foo/0")));
|
||||
CHECK(j.contains(json::json_pointer("/foo/1")));
|
||||
CHECK(!j.contains(json::json_pointer("/foo/3")));
|
||||
CHECK(!j.contains(json::json_pointer("/foo/+")));
|
||||
CHECK(!j.contains(json::json_pointer("/foo/1+2")));
|
||||
CHECK(!j.contains(json::json_pointer("/foo/-")));
|
||||
|
||||
// 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[""]);
|
||||
CHECK(j.contains(json::json_pointer("")));
|
||||
CHECK(j.contains(json::json_pointer("/")));
|
||||
|
||||
// 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"]);
|
||||
|
||||
// contains
|
||||
CHECK(j.contains(json::json_pointer("/ ")));
|
||||
CHECK(j.contains(json::json_pointer("/c%d")));
|
||||
CHECK(j.contains(json::json_pointer("/e^f")));
|
||||
CHECK(j.contains(json::json_pointer("/g|h")));
|
||||
CHECK(j.contains(json::json_pointer("/i\\j")));
|
||||
CHECK(j.contains(json::json_pointer("/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"]);
|
||||
CHECK(j.contains(json::json_pointer("/a~1b")));
|
||||
CHECK(j.contains(json::json_pointer("/m~0n")));
|
||||
|
||||
// unescaped access
|
||||
// access to nonexisting values yield object creation
|
||||
CHECK(!j.contains(json::json_pointer("/a/b")));
|
||||
CHECK_NOTHROW(j[json::json_pointer("/a/b")] = 42);
|
||||
CHECK(j.contains(json::json_pointer("/a/b")));
|
||||
CHECK(j["a"]["b"] == json(42));
|
||||
|
||||
CHECK(!j.contains(json::json_pointer("/a/c/1")));
|
||||
CHECK_NOTHROW(j[json::json_pointer("/a/c/1")] = 42);
|
||||
CHECK(j["a"]["c"] == json({nullptr, 42}));
|
||||
CHECK(j.contains(json::json_pointer("/a/c/1")));
|
||||
|
||||
CHECK(!j.contains(json::json_pointer("/a/d/-")));
|
||||
CHECK_NOTHROW(j[json::json_pointer("/a/d/-")] = 42);
|
||||
CHECK(!j.contains(json::json_pointer("/a/d/-")));
|
||||
CHECK(j["a"]["d"] == json::array({42}));
|
||||
// "/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_WITH_AS(j_primitive["/foo"_json_pointer],
|
||||
"[json.exception.out_of_range.404] unresolved reference token 'foo'", json::out_of_range&);
|
||||
CHECK_THROWS_WITH_AS(j_primitive.at("/foo"_json_pointer),
|
||||
"[json.exception.out_of_range.404] unresolved reference token 'foo'", json::out_of_range&);
|
||||
CHECK(!j_primitive.contains(json::json_pointer("/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_WITH_AS(j.at(json::json_pointer("/a/b")),
|
||||
"[json.exception.out_of_range.403] key 'a' not found", json::out_of_range&);
|
||||
|
||||
// unresolved access
|
||||
const json j_primitive = 1;
|
||||
CHECK_THROWS_WITH_AS(j_primitive["/foo"_json_pointer],
|
||||
"[json.exception.out_of_range.404] unresolved reference token 'foo'", json::out_of_range&);
|
||||
CHECK_THROWS_WITH_AS(j_primitive.at("/foo"_json_pointer),
|
||||
"[json.exception.out_of_range.404] unresolved reference token 'foo'", json::out_of_range&);
|
||||
}
|
||||
|
||||
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);
|
||||
CHECK(j.contains(""_json_pointer));
|
||||
|
||||
// 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]);
|
||||
CHECK(j.contains("/foo"_json_pointer));
|
||||
CHECK(j.contains("/foo/0"_json_pointer));
|
||||
CHECK(j.contains("/foo/1"_json_pointer));
|
||||
CHECK(!j.contains("/foo/-"_json_pointer));
|
||||
}
|
||||
}
|
||||
|
||||
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_WITH_AS(j["/01"_json_pointer],
|
||||
"[json.exception.parse_error.106] parse error: array index '01' must not begin with '0'", json::parse_error&);
|
||||
CHECK_THROWS_WITH_AS(j_const["/01"_json_pointer],
|
||||
"[json.exception.parse_error.106] parse error: array index '01' must not begin with '0'", json::parse_error&);
|
||||
CHECK_THROWS_WITH_AS(j.at("/01"_json_pointer),
|
||||
"[json.exception.parse_error.106] parse error: array index '01' must not begin with '0'", json::parse_error&);
|
||||
CHECK_THROWS_WITH_AS(j_const.at("/01"_json_pointer),
|
||||
"[json.exception.parse_error.106] parse error: array index '01' must not begin with '0'", json::parse_error&);
|
||||
|
||||
CHECK(!j.contains("/01"_json_pointer));
|
||||
CHECK(!j.contains("/01"_json_pointer));
|
||||
CHECK(!j_const.contains("/01"_json_pointer));
|
||||
CHECK(!j_const.contains("/01"_json_pointer));
|
||||
|
||||
// error with incorrect numbers
|
||||
CHECK_THROWS_WITH_AS(j["/one"_json_pointer] = 1,
|
||||
"[json.exception.parse_error.109] parse error: array index 'one' is not a number", json::parse_error&);
|
||||
CHECK_THROWS_WITH_AS(j_const["/one"_json_pointer] == 1,
|
||||
"[json.exception.parse_error.109] parse error: array index 'one' is not a number", json::parse_error&);
|
||||
|
||||
CHECK_THROWS_WITH_AS(j.at("/one"_json_pointer) = 1,
|
||||
"[json.exception.parse_error.109] parse error: array index 'one' is not a number", json::parse_error&);
|
||||
CHECK_THROWS_WITH_AS(j_const.at("/one"_json_pointer) == 1,
|
||||
"[json.exception.parse_error.109] parse error: array index 'one' is not a number", json::parse_error&);
|
||||
|
||||
CHECK_THROWS_WITH_AS(j["/+1"_json_pointer] = 1,
|
||||
"[json.exception.parse_error.109] parse error: array index '+1' is not a number", json::parse_error&);
|
||||
CHECK_THROWS_WITH_AS(j_const["/+1"_json_pointer] == 1,
|
||||
"[json.exception.parse_error.109] parse error: array index '+1' is not a number", json::parse_error&);
|
||||
|
||||
CHECK_THROWS_WITH_AS(j["/1+1"_json_pointer] = 1,
|
||||
"[json.exception.out_of_range.404] unresolved reference token '1+1'", json::out_of_range&);
|
||||
CHECK_THROWS_WITH_AS(j_const["/1+1"_json_pointer] == 1,
|
||||
"[json.exception.out_of_range.404] unresolved reference token '1+1'", json::out_of_range&);
|
||||
|
||||
{
|
||||
auto too_large_index = std::to_string((std::numeric_limits<unsigned long long>::max)()) + "1";
|
||||
json::json_pointer jp(std::string("/") + too_large_index);
|
||||
std::string throw_msg = std::string("[json.exception.out_of_range.404] unresolved reference token '") + too_large_index + "'";
|
||||
|
||||
CHECK_THROWS_WITH_AS(j[jp] = 1, throw_msg.c_str(), json::out_of_range&);
|
||||
CHECK_THROWS_WITH_AS(j_const[jp] == 1, throw_msg.c_str(), json::out_of_range&);
|
||||
}
|
||||
|
||||
// on some machines, the check below is not constant
|
||||
DOCTEST_MSVC_SUPPRESS_WARNING_PUSH
|
||||
DOCTEST_MSVC_SUPPRESS_WARNING(4127)
|
||||
|
||||
if (sizeof(typename json::size_type) < sizeof(unsigned long long))
|
||||
{
|
||||
auto size_type_max_uul = static_cast<unsigned long long>((std::numeric_limits<json::size_type>::max)());
|
||||
auto too_large_index = std::to_string(size_type_max_uul);
|
||||
json::json_pointer jp(std::string("/") + too_large_index);
|
||||
std::string throw_msg = std::string("[json.exception.out_of_range.410] array index ") + too_large_index + " exceeds size_type";
|
||||
|
||||
CHECK_THROWS_WITH_AS(j[jp] = 1, throw_msg.c_str(), json::out_of_range&);
|
||||
CHECK_THROWS_WITH_AS(j_const[jp] == 1, throw_msg.c_str(), json::out_of_range&);
|
||||
}
|
||||
|
||||
DOCTEST_MSVC_SUPPRESS_WARNING_POP
|
||||
|
||||
CHECK_THROWS_WITH_AS(j.at("/one"_json_pointer) = 1,
|
||||
"[json.exception.parse_error.109] parse error: array index 'one' is not a number", json::parse_error&);
|
||||
CHECK_THROWS_WITH_AS(j_const.at("/one"_json_pointer) == 1,
|
||||
"[json.exception.parse_error.109] parse error: array index 'one' is not a number", json::parse_error&);
|
||||
|
||||
CHECK(!j.contains("/one"_json_pointer));
|
||||
CHECK(!j.contains("/one"_json_pointer));
|
||||
CHECK(!j_const.contains("/one"_json_pointer));
|
||||
CHECK(!j_const.contains("/one"_json_pointer));
|
||||
|
||||
CHECK_THROWS_WITH_AS(json({{"/list/0", 1}, {"/list/1", 2}, {"/list/three", 3}}).unflatten(),
|
||||
"[json.exception.parse_error.109] parse error: array index 'three' is not a number", json::parse_error&);
|
||||
|
||||
// assign to "-"
|
||||
j["/-"_json_pointer] = 99;
|
||||
CHECK(j == json({1, 13, 3, 33, nullptr, 55, 99}));
|
||||
|
||||
// error when using "-" in const object
|
||||
CHECK_THROWS_WITH_AS(j_const["/-"_json_pointer],
|
||||
"[json.exception.out_of_range.402] array index '-' (3) is out of range", json::out_of_range&);
|
||||
CHECK(!j_const.contains("/-"_json_pointer));
|
||||
|
||||
// error when using "-" with at
|
||||
CHECK_THROWS_WITH_AS(j.at("/-"_json_pointer),
|
||||
"[json.exception.out_of_range.402] array index '-' (7) is out of range", json::out_of_range&);
|
||||
CHECK_THROWS_WITH_AS(j_const.at("/-"_json_pointer),
|
||||
"[json.exception.out_of_range.402] array index '-' (3) is out of range", json::out_of_range&);
|
||||
CHECK(!j_const.contains("/-"_json_pointer));
|
||||
}
|
||||
|
||||
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_WITH_AS(j.at("/3"_json_pointer),
|
||||
"[json.exception.out_of_range.401] array index 3 is out of range", json::out_of_range&);
|
||||
CHECK(!j.contains("/3"_json_pointer));
|
||||
|
||||
// assign to nonexisting index (with gap)
|
||||
CHECK_THROWS_WITH_AS(j.at("/5"_json_pointer),
|
||||
"[json.exception.out_of_range.401] array index 5 is out of range", json::out_of_range&);
|
||||
CHECK(!j.contains("/5"_json_pointer));
|
||||
|
||||
// assign to "-"
|
||||
CHECK_THROWS_WITH_AS(j["/-"_json_pointer],
|
||||
"[json.exception.out_of_range.402] array index '-' (3) is out of range", json::out_of_range&);
|
||||
CHECK_THROWS_WITH_AS(j.at("/-"_json_pointer),
|
||||
"[json.exception.out_of_range.402] array index '-' (3) is out of range", json::out_of_range&);
|
||||
CHECK(!j.contains("/-"_json_pointer));
|
||||
}
|
||||
}
|
||||
|
||||
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_WITH_AS(json(1).unflatten(),
|
||||
"[json.exception.type_error.314] only objects can be unflattened", json::type_error&);
|
||||
|
||||
// error for nonprimitve values
|
||||
#if JSON_DIAGNOSTICS
|
||||
CHECK_THROWS_WITH_AS(json({{"/1", {1, 2, 3}}}).unflatten(), "[json.exception.type_error.315] (/~11) values in object must be primitive", json::type_error&);
|
||||
#else
|
||||
CHECK_THROWS_WITH_AS(json({{"/1", {1, 2, 3}}}).unflatten(), "[json.exception.type_error.315] values in object must be primitive", json::type_error&);
|
||||
#endif
|
||||
|
||||
// error for conflicting values
|
||||
json j_error = {{"", 42}, {"/foo", 17}};
|
||||
CHECK_THROWS_WITH_AS(j_error.unflatten(),
|
||||
"[json.exception.type_error.313] invalid value to unflatten", json::type_error&);
|
||||
|
||||
// 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 (const 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);
|
||||
CHECK(std::string(json::json_pointer(ptr)) == ptr);
|
||||
}
|
||||
}
|
||||
|
||||
SECTION("conversion")
|
||||
{
|
||||
SECTION("array")
|
||||
{
|
||||
json j;
|
||||
// all numbers -> array
|
||||
j["/12"_json_pointer] = 0;
|
||||
CHECK(j.is_array());
|
||||
}
|
||||
|
||||
SECTION("object")
|
||||
{
|
||||
json j;
|
||||
// contains a number, but is not a number -> object
|
||||
j["/a12"_json_pointer] = 0;
|
||||
CHECK(j.is_object());
|
||||
}
|
||||
}
|
||||
|
||||
SECTION("empty, push, pop and parent")
|
||||
{
|
||||
const json j =
|
||||
{
|
||||
{"", "Hello"},
|
||||
{"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"}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
// empty json_pointer returns the root JSON-object
|
||||
auto ptr = ""_json_pointer;
|
||||
CHECK(ptr.empty());
|
||||
CHECK(j[ptr] == j);
|
||||
|
||||
// simple field access
|
||||
ptr.push_back("pi");
|
||||
CHECK(!ptr.empty());
|
||||
CHECK(j[ptr] == j["pi"]);
|
||||
|
||||
ptr.pop_back();
|
||||
CHECK(ptr.empty());
|
||||
CHECK(j[ptr] == j);
|
||||
|
||||
// object and children access
|
||||
const std::string answer("answer");
|
||||
ptr.push_back(answer);
|
||||
ptr.push_back("everything");
|
||||
CHECK(!ptr.empty());
|
||||
CHECK(j[ptr] == j["answer"]["everything"]);
|
||||
|
||||
// check access via const pointer
|
||||
const auto cptr = ptr;
|
||||
CHECK(cptr.back() == "everything");
|
||||
|
||||
ptr.pop_back();
|
||||
ptr.pop_back();
|
||||
CHECK(ptr.empty());
|
||||
CHECK(j[ptr] == j);
|
||||
|
||||
// push key which has to be encoded
|
||||
ptr.push_back("object");
|
||||
ptr.push_back("/");
|
||||
CHECK(j[ptr] == j["object"]["/"]);
|
||||
CHECK(ptr.to_string() == "/object/~1");
|
||||
|
||||
CHECK(j[ptr.parent_pointer()] == j["object"]);
|
||||
ptr = ptr.parent_pointer().parent_pointer();
|
||||
CHECK(ptr.empty());
|
||||
CHECK(j[ptr] == j);
|
||||
// parent-pointer of the empty json_pointer is empty
|
||||
ptr = ptr.parent_pointer();
|
||||
CHECK(ptr.empty());
|
||||
CHECK(j[ptr] == j);
|
||||
|
||||
CHECK_THROWS_WITH(ptr.pop_back(),
|
||||
"[json.exception.out_of_range.405] JSON pointer has no parent");
|
||||
}
|
||||
|
||||
SECTION("operators")
|
||||
{
|
||||
const json j =
|
||||
{
|
||||
{"", "Hello"},
|
||||
{"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"}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
// empty json_pointer returns the root JSON-object
|
||||
auto ptr = ""_json_pointer;
|
||||
CHECK(j[ptr] == j);
|
||||
|
||||
// simple field access
|
||||
ptr = ptr / "pi";
|
||||
CHECK(j[ptr] == j["pi"]);
|
||||
|
||||
ptr.pop_back();
|
||||
CHECK(j[ptr] == j);
|
||||
|
||||
// object and children access
|
||||
const std::string answer("answer");
|
||||
ptr /= answer;
|
||||
ptr = ptr / "everything";
|
||||
CHECK(j[ptr] == j["answer"]["everything"]);
|
||||
|
||||
ptr.pop_back();
|
||||
ptr.pop_back();
|
||||
CHECK(j[ptr] == j);
|
||||
|
||||
CHECK(ptr / ""_json_pointer == ptr);
|
||||
CHECK(j["/answer"_json_pointer / "/everything"_json_pointer] == j["answer"]["everything"]);
|
||||
|
||||
// list children access
|
||||
CHECK(j["/list"_json_pointer / 1] == j["list"][1]);
|
||||
|
||||
// push key which has to be encoded
|
||||
ptr /= "object";
|
||||
ptr = ptr / "/";
|
||||
CHECK(j[ptr] == j["object"]["/"]);
|
||||
CHECK(ptr.to_string() == "/object/~1");
|
||||
}
|
||||
|
||||
SECTION("equality comparison")
|
||||
{
|
||||
auto ptr1 = json::json_pointer("/foo/bar");
|
||||
auto ptr2 = json::json_pointer("/foo/bar");
|
||||
|
||||
CHECK(ptr1 == ptr2);
|
||||
CHECK_FALSE(ptr1 != ptr2);
|
||||
}
|
||||
|
||||
SECTION("backwards compatibility and mixing")
|
||||
{
|
||||
json j = R"(
|
||||
{
|
||||
"foo": ["bar", "baz"]
|
||||
}
|
||||
)"_json;
|
||||
|
||||
using nlohmann::ordered_json;
|
||||
using json_ptr_str = nlohmann::json_pointer<std::string>;
|
||||
using json_ptr_j = nlohmann::json_pointer<json>;
|
||||
using json_ptr_oj = nlohmann::json_pointer<ordered_json>;
|
||||
|
||||
CHECK(std::is_same<json_ptr_str::string_t, json::json_pointer::string_t>::value);
|
||||
CHECK(std::is_same<json_ptr_str::string_t, ordered_json::json_pointer::string_t>::value);
|
||||
CHECK(std::is_same<json_ptr_str::string_t, json_ptr_j::string_t>::value);
|
||||
CHECK(std::is_same<json_ptr_str::string_t, json_ptr_oj::string_t>::value);
|
||||
|
||||
json_ptr_str ptr{"/foo/0"};
|
||||
json_ptr_j ptr_j{"/foo/0"};
|
||||
json_ptr_oj ptr_oj{"/foo/0"};
|
||||
|
||||
CHECK(j.contains(ptr));
|
||||
CHECK(j.contains(ptr_j));
|
||||
CHECK(j.contains(ptr_oj));
|
||||
|
||||
CHECK(j.at(ptr) == j.at(ptr_j));
|
||||
CHECK(j.at(ptr) == j.at(ptr_oj));
|
||||
|
||||
CHECK(j[ptr] == j[ptr_j]);
|
||||
CHECK(j[ptr] == j[ptr_oj]);
|
||||
|
||||
CHECK(j.value(ptr, "x") == j.value(ptr_j, "x"));
|
||||
CHECK(j.value(ptr, "x") == j.value(ptr_oj, "x"));
|
||||
|
||||
CHECK(ptr == ptr_j);
|
||||
CHECK(ptr == ptr_oj);
|
||||
CHECK_FALSE(ptr != ptr_j);
|
||||
CHECK_FALSE(ptr != ptr_oj);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,50 @@
|
||||
/*
|
||||
__ _____ _____ _____
|
||||
__| | __| | | | JSON for Modern C++ (test suite)
|
||||
| | |__ | | | | | | version 3.10.5
|
||||
|_____|_____|_____|_|___| https://github.com/nlohmann/json
|
||||
|
||||
Licensed under the MIT License <http://opensource.org/licenses/MIT>.
|
||||
SPDX-License-Identifier: MIT
|
||||
Copyright (c) 2013-2022 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 "doctest_compatibility.h"
|
||||
|
||||
#include <nlohmann/json.hpp>
|
||||
using nlohmann::json;
|
||||
|
||||
#include <algorithm>
|
||||
|
||||
TEST_CASE("tests on very large JSONs")
|
||||
{
|
||||
SECTION("issue #1419 - Segmentation fault (stack overflow) due to unbounded recursion")
|
||||
{
|
||||
const auto depth = 5000000;
|
||||
|
||||
std::string s(static_cast<std::size_t>(2 * depth), '[');
|
||||
std::fill(s.begin() + depth, s.end(), ']');
|
||||
|
||||
json _;
|
||||
CHECK_NOTHROW(_ = nlohmann::json::parse(s));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,262 @@
|
||||
/*
|
||||
__ _____ _____ _____
|
||||
__| | __| | | | JSON for Modern C++ (test suite)
|
||||
| | |__ | | | | | | version 3.10.5
|
||||
|_____|_____|_____|_|___| https://github.com/nlohmann/json
|
||||
|
||||
Licensed under the MIT License <http://opensource.org/licenses/MIT>.
|
||||
SPDX-License-Identifier: MIT
|
||||
Copyright (c) 2013-2022 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 "doctest_compatibility.h"
|
||||
|
||||
#include <nlohmann/json.hpp>
|
||||
using nlohmann::json;
|
||||
|
||||
TEST_CASE("JSON Merge Patch")
|
||||
{
|
||||
SECTION("examples from RFC 7396")
|
||||
{
|
||||
SECTION("Section 1")
|
||||
{
|
||||
json document = R"({
|
||||
"a": "b",
|
||||
"c": {
|
||||
"d": "e",
|
||||
"f": "g"
|
||||
}
|
||||
})"_json;
|
||||
|
||||
json patch = R"({
|
||||
"a": "z",
|
||||
"c": {
|
||||
"f": null
|
||||
}
|
||||
})"_json;
|
||||
|
||||
json expected = R"({
|
||||
"a": "z",
|
||||
"c": {
|
||||
"d": "e"
|
||||
}
|
||||
})"_json;
|
||||
|
||||
document.merge_patch(patch);
|
||||
CHECK(document == expected);
|
||||
}
|
||||
|
||||
SECTION("Section 3")
|
||||
{
|
||||
json document = R"({
|
||||
"title": "Goodbye!",
|
||||
"author": {
|
||||
"givenName": "John",
|
||||
"familyName": "Doe"
|
||||
},
|
||||
"tags": [
|
||||
"example",
|
||||
"sample"
|
||||
],
|
||||
"content": "This will be unchanged"
|
||||
})"_json;
|
||||
|
||||
json patch = R"({
|
||||
"title": "Hello!",
|
||||
"phoneNumber": "+01-123-456-7890",
|
||||
"author": {
|
||||
"familyName": null
|
||||
},
|
||||
"tags": [
|
||||
"example"
|
||||
]
|
||||
})"_json;
|
||||
|
||||
json expected = R"({
|
||||
"title": "Hello!",
|
||||
"author": {
|
||||
"givenName": "John"
|
||||
},
|
||||
"tags": [
|
||||
"example"
|
||||
],
|
||||
"content": "This will be unchanged",
|
||||
"phoneNumber": "+01-123-456-7890"
|
||||
})"_json;
|
||||
|
||||
document.merge_patch(patch);
|
||||
CHECK(document == expected);
|
||||
}
|
||||
|
||||
SECTION("Appendix A")
|
||||
{
|
||||
SECTION("Example 1")
|
||||
{
|
||||
json original = R"({"a":"b"})"_json;
|
||||
json patch = R"({"a":"c"})"_json;
|
||||
json result = R"({"a":"c"})"_json;
|
||||
|
||||
original.merge_patch(patch);
|
||||
CHECK(original == result);
|
||||
}
|
||||
|
||||
SECTION("Example 2")
|
||||
{
|
||||
json original = R"({"a":"b"})"_json;
|
||||
json patch = R"({"b":"c"})"_json;
|
||||
json result = R"({"a":"b", "b":"c"})"_json;
|
||||
|
||||
original.merge_patch(patch);
|
||||
CHECK(original == result);
|
||||
}
|
||||
|
||||
SECTION("Example 3")
|
||||
{
|
||||
json original = R"({"a":"b"})"_json;
|
||||
json patch = R"({"a":null})"_json;
|
||||
json result = R"({})"_json;
|
||||
|
||||
original.merge_patch(patch);
|
||||
CHECK(original == result);
|
||||
}
|
||||
|
||||
SECTION("Example 4")
|
||||
{
|
||||
json original = R"({"a":"b","b":"c"})"_json;
|
||||
json patch = R"({"a":null})"_json;
|
||||
json result = R"({"b":"c"})"_json;
|
||||
|
||||
original.merge_patch(patch);
|
||||
CHECK(original == result);
|
||||
}
|
||||
|
||||
SECTION("Example 5")
|
||||
{
|
||||
json original = R"({"a":["b"]})"_json;
|
||||
json patch = R"({"a":"c"})"_json;
|
||||
json result = R"({"a":"c"})"_json;
|
||||
|
||||
original.merge_patch(patch);
|
||||
CHECK(original == result);
|
||||
}
|
||||
|
||||
SECTION("Example 6")
|
||||
{
|
||||
json original = R"({"a":"c"})"_json;
|
||||
json patch = R"({"a":["b"]})"_json;
|
||||
json result = R"({"a":["b"]})"_json;
|
||||
|
||||
original.merge_patch(patch);
|
||||
CHECK(original == result);
|
||||
}
|
||||
|
||||
SECTION("Example 7")
|
||||
{
|
||||
json original = R"({"a":{"b": "c"}})"_json;
|
||||
json patch = R"({"a":{"b":"d","c":null}})"_json;
|
||||
json result = R"({"a": {"b": "d"}})"_json;
|
||||
|
||||
original.merge_patch(patch);
|
||||
CHECK(original == result);
|
||||
}
|
||||
|
||||
SECTION("Example 8")
|
||||
{
|
||||
json original = R"({"a":[{"b":"c"}]})"_json;
|
||||
json patch = R"({"a":[1]})"_json;
|
||||
json result = R"({"a":[1]})"_json;
|
||||
|
||||
original.merge_patch(patch);
|
||||
CHECK(original == result);
|
||||
}
|
||||
|
||||
SECTION("Example 9")
|
||||
{
|
||||
json original = R"(["a","b"])"_json;
|
||||
json patch = R"(["c","d"])"_json;
|
||||
json result = R"(["c","d"])"_json;
|
||||
|
||||
original.merge_patch(patch);
|
||||
CHECK(original == result);
|
||||
}
|
||||
|
||||
SECTION("Example 10")
|
||||
{
|
||||
json original = R"({"a":"b"})"_json;
|
||||
json patch = R"(["c"])"_json;
|
||||
json result = R"(["c"])"_json;
|
||||
|
||||
original.merge_patch(patch);
|
||||
CHECK(original == result);
|
||||
}
|
||||
|
||||
SECTION("Example 11")
|
||||
{
|
||||
json original = R"({"a":"foo"})"_json;
|
||||
json patch = R"(null)"_json;
|
||||
json result = R"(null)"_json;
|
||||
|
||||
original.merge_patch(patch);
|
||||
CHECK(original == result);
|
||||
}
|
||||
|
||||
SECTION("Example 12")
|
||||
{
|
||||
json original = R"({"a":"foo"})"_json;
|
||||
json patch = R"("bar")"_json;
|
||||
json result = R"("bar")"_json;
|
||||
|
||||
original.merge_patch(patch);
|
||||
CHECK(original == result);
|
||||
}
|
||||
|
||||
SECTION("Example 13")
|
||||
{
|
||||
json original = R"({"e":null})"_json;
|
||||
json patch = R"({"a":1})"_json;
|
||||
json result = R"({"e":null,"a":1})"_json;
|
||||
|
||||
original.merge_patch(patch);
|
||||
CHECK(original == result);
|
||||
}
|
||||
|
||||
SECTION("Example 14")
|
||||
{
|
||||
json original = R"([1,2])"_json;
|
||||
json patch = R"({"a":"b","c":null})"_json;
|
||||
json result = R"({"a":"b"})"_json;
|
||||
|
||||
original.merge_patch(patch);
|
||||
CHECK(original == result);
|
||||
}
|
||||
|
||||
SECTION("Example 15")
|
||||
{
|
||||
json original = R"({})"_json;
|
||||
json patch = R"({"a":{"bb":{"ccc":null}}})"_json;
|
||||
json result = R"({"a":{"bb":{}}})"_json;
|
||||
|
||||
original.merge_patch(patch);
|
||||
CHECK(original == result);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,57 @@
|
||||
/*
|
||||
__ _____ _____ _____
|
||||
__| | __| | | | JSON for Modern C++ (test suite)
|
||||
| | |__ | | | | | | version 3.10.5
|
||||
|_____|_____|_____|_|___| https://github.com/nlohmann/json
|
||||
|
||||
Licensed under the MIT License <http://opensource.org/licenses/MIT>.
|
||||
SPDX-License-Identifier: MIT
|
||||
Copyright (c) 2013-2022 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 "doctest_compatibility.h"
|
||||
|
||||
#include <nlohmann/json.hpp>
|
||||
using nlohmann::json;
|
||||
|
||||
TEST_CASE("version information")
|
||||
{
|
||||
SECTION("meta()")
|
||||
{
|
||||
json j = json::meta();
|
||||
|
||||
CHECK(j["name"] == "JSON for Modern C++");
|
||||
CHECK(j["copyright"] == "(C) 2013-2022 Niels Lohmann");
|
||||
CHECK(j["url"] == "https://github.com/nlohmann/json");
|
||||
CHECK(j["version"] == json(
|
||||
{
|
||||
{"string", "3.10.5"},
|
||||
{"major", 3},
|
||||
{"minor", 10},
|
||||
{"patch", 5}
|
||||
}));
|
||||
|
||||
CHECK(j.find("platform") != j.end());
|
||||
CHECK(j.at("compiler").find("family") != j.at("compiler").end());
|
||||
CHECK(j.at("compiler").find("version") != j.at("compiler").end());
|
||||
CHECK(j.at("compiler").find("c++") != j.at("compiler").end());
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,973 @@
|
||||
/*
|
||||
__ _____ _____ _____
|
||||
__| | __| | | | JSON for Modern C++ (test suite)
|
||||
| | |__ | | | | | | version 3.10.5
|
||||
|_____|_____|_____|_|___| https://github.com/nlohmann/json
|
||||
|
||||
Licensed under the MIT License <http://opensource.org/licenses/MIT>.
|
||||
SPDX-License-Identifier: MIT
|
||||
Copyright (c) 2013-2022 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 "doctest_compatibility.h"
|
||||
|
||||
#include <nlohmann/json.hpp>
|
||||
using nlohmann::json;
|
||||
|
||||
TEST_CASE("modifiers")
|
||||
{
|
||||
SECTION("clear()")
|
||||
{
|
||||
SECTION("boolean")
|
||||
{
|
||||
json j = true;
|
||||
json k = j;
|
||||
|
||||
j.clear();
|
||||
CHECK(j == json(json::value_t::boolean));
|
||||
CHECK(j == json(k.type()));
|
||||
}
|
||||
|
||||
SECTION("string")
|
||||
{
|
||||
json j = "hello world";
|
||||
json k = j;
|
||||
|
||||
j.clear();
|
||||
CHECK(j == json(json::value_t::string));
|
||||
CHECK(j == json(k.type()));
|
||||
}
|
||||
|
||||
SECTION("array")
|
||||
{
|
||||
SECTION("empty array")
|
||||
{
|
||||
json j = json::array();
|
||||
json k = j;
|
||||
|
||||
j.clear();
|
||||
CHECK(j.empty());
|
||||
CHECK(j == json(json::value_t::array));
|
||||
CHECK(j == json(k.type()));
|
||||
}
|
||||
|
||||
SECTION("filled array")
|
||||
{
|
||||
json j = {1, 2, 3};
|
||||
json k = j;
|
||||
|
||||
j.clear();
|
||||
CHECK(j.empty());
|
||||
CHECK(j == json(json::value_t::array));
|
||||
CHECK(j == json(k.type()));
|
||||
}
|
||||
}
|
||||
|
||||
SECTION("object")
|
||||
{
|
||||
SECTION("empty object")
|
||||
{
|
||||
json j = json::object();
|
||||
json k = j;
|
||||
|
||||
j.clear();
|
||||
CHECK(j.empty());
|
||||
CHECK(j == json(json::value_t::object));
|
||||
CHECK(j == json(k.type()));
|
||||
}
|
||||
|
||||
SECTION("filled object")
|
||||
{
|
||||
json j = {{"one", 1}, {"two", 2}, {"three", 3}};
|
||||
json k = j;
|
||||
|
||||
j.clear();
|
||||
CHECK(j.empty());
|
||||
CHECK(j == json(json::value_t::object));
|
||||
CHECK(j == json(k.type()));
|
||||
}
|
||||
}
|
||||
|
||||
SECTION("binary")
|
||||
{
|
||||
SECTION("empty binary")
|
||||
{
|
||||
json j = json::binary({});
|
||||
json k = j;
|
||||
|
||||
j.clear();
|
||||
CHECK(!j.empty());
|
||||
CHECK(j == json(json::value_t::binary));
|
||||
CHECK(j == json(k.type()));
|
||||
}
|
||||
|
||||
SECTION("filled binary")
|
||||
{
|
||||
json j = json::binary({1, 2, 3, 4, 5});
|
||||
json k = j;
|
||||
|
||||
j.clear();
|
||||
CHECK(!j.empty());
|
||||
CHECK(j == json(json::value_t::binary));
|
||||
CHECK(j == json(k.type()));
|
||||
}
|
||||
}
|
||||
|
||||
SECTION("number (integer)")
|
||||
{
|
||||
json j = 23;
|
||||
json k = j;
|
||||
|
||||
j.clear();
|
||||
CHECK(j == json(json::value_t::number_integer));
|
||||
CHECK(j == json(k.type()));
|
||||
}
|
||||
|
||||
SECTION("number (unsigned)")
|
||||
{
|
||||
json j = 23u;
|
||||
json k = j;
|
||||
|
||||
j.clear();
|
||||
CHECK(j == json(json::value_t::number_integer));
|
||||
CHECK(j == json(k.type()));
|
||||
}
|
||||
|
||||
SECTION("number (float)")
|
||||
{
|
||||
json j = 23.42;
|
||||
json k = j;
|
||||
|
||||
j.clear();
|
||||
CHECK(j == json(json::value_t::number_float));
|
||||
CHECK(j == json(k.type()));
|
||||
}
|
||||
|
||||
SECTION("null")
|
||||
{
|
||||
json j = nullptr;
|
||||
json k = j;
|
||||
|
||||
j.clear();
|
||||
CHECK(j == json(json::value_t::null));
|
||||
CHECK(j == json(k.type()));
|
||||
}
|
||||
}
|
||||
|
||||
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_WITH_AS(j.push_back("Hello"), "[json.exception.type_error.308] cannot use push_back() with number", json::type_error&);
|
||||
}
|
||||
}
|
||||
|
||||
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_WITH_AS(j.push_back(k), "[json.exception.type_error.308] cannot use push_back() with number", json::type_error&);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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_WITH_AS(j.push_back(json::object_t::value_type({"one", 1})), "[json.exception.type_error.308] cannot use push_back() with number", json::type_error&);
|
||||
}
|
||||
}
|
||||
|
||||
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"}}));
|
||||
|
||||
// invalid values (no string/val pair)
|
||||
CHECK_THROWS_WITH_AS(j.push_back({1}), "[json.exception.type_error.308] cannot use push_back() with object", json::type_error&);
|
||||
CHECK_THROWS_WITH_AS(j.push_back({1, 2}), "[json.exception.type_error.308] cannot use push_back() with object", json::type_error&);
|
||||
CHECK_THROWS_WITH_AS(j.push_back({1, 2, 3, 4}), "[json.exception.type_error.308] cannot use push_back() with object", json::type_error&);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
SECTION("emplace_back()")
|
||||
{
|
||||
SECTION("to array")
|
||||
{
|
||||
SECTION("null")
|
||||
{
|
||||
json j;
|
||||
auto& x1 = j.emplace_back(1);
|
||||
CHECK(x1 == 1);
|
||||
auto& x2 = j.emplace_back(2);
|
||||
CHECK(x2 == 2);
|
||||
CHECK(j.type() == json::value_t::array);
|
||||
CHECK(j == json({1, 2}));
|
||||
}
|
||||
|
||||
SECTION("array")
|
||||
{
|
||||
json j = {1, 2, 3};
|
||||
auto& x = j.emplace_back("Hello");
|
||||
CHECK(x == "Hello");
|
||||
CHECK(j.type() == json::value_t::array);
|
||||
CHECK(j == json({1, 2, 3, "Hello"}));
|
||||
}
|
||||
|
||||
SECTION("multiple values")
|
||||
{
|
||||
json j;
|
||||
auto& x = j.emplace_back(3, "foo");
|
||||
CHECK(x == json({"foo", "foo", "foo"}));
|
||||
CHECK(j.type() == json::value_t::array);
|
||||
CHECK(j == json({{"foo", "foo", "foo"}}));
|
||||
}
|
||||
}
|
||||
|
||||
SECTION("other type")
|
||||
{
|
||||
json j = 1;
|
||||
CHECK_THROWS_WITH_AS(j.emplace_back("Hello"), "[json.exception.type_error.311] cannot use emplace_back() with number", json::type_error&);
|
||||
}
|
||||
}
|
||||
|
||||
SECTION("emplace()")
|
||||
{
|
||||
SECTION("to object")
|
||||
{
|
||||
SECTION("null")
|
||||
{
|
||||
// start with a null value
|
||||
json j;
|
||||
|
||||
// add a new key
|
||||
auto res1 = j.emplace("foo", "bar");
|
||||
CHECK(res1.second == true);
|
||||
CHECK(*res1.first == "bar");
|
||||
|
||||
// the null value is changed to an object
|
||||
CHECK(j.type() == json::value_t::object);
|
||||
|
||||
// add a new key
|
||||
auto res2 = j.emplace("baz", "bam");
|
||||
CHECK(res2.second == true);
|
||||
CHECK(*res2.first == "bam");
|
||||
|
||||
// we try to insert at given key - no change
|
||||
auto res3 = j.emplace("baz", "bad");
|
||||
CHECK(res3.second == false);
|
||||
CHECK(*res3.first == "bam");
|
||||
|
||||
// the final object
|
||||
CHECK(j == json({{"baz", "bam"}, {"foo", "bar"}}));
|
||||
}
|
||||
|
||||
SECTION("object")
|
||||
{
|
||||
// start with an object
|
||||
json j = {{"foo", "bar"}};
|
||||
|
||||
// add a new key
|
||||
auto res1 = j.emplace("baz", "bam");
|
||||
CHECK(res1.second == true);
|
||||
CHECK(*res1.first == "bam");
|
||||
|
||||
// add an existing key
|
||||
auto res2 = j.emplace("foo", "bad");
|
||||
CHECK(res2.second == false);
|
||||
CHECK(*res2.first == "bar");
|
||||
|
||||
// check final object
|
||||
CHECK(j == json({{"baz", "bam"}, {"foo", "bar"}}));
|
||||
}
|
||||
}
|
||||
|
||||
SECTION("other type")
|
||||
{
|
||||
json j = 1;
|
||||
CHECK_THROWS_WITH_AS(j.emplace("foo", "bar"), "[json.exception.type_error.311] cannot use emplace() with number", json::type_error&);
|
||||
}
|
||||
}
|
||||
|
||||
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_WITH_AS(j += "Hello", "[json.exception.type_error.308] cannot use push_back() with number", json::type_error&);
|
||||
}
|
||||
}
|
||||
|
||||
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_WITH_AS(j += k, "[json.exception.type_error.308] cannot use push_back() with number", json::type_error&);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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_WITH_AS(j += json::object_t::value_type({"one", 1}), "[json.exception.type_error.308] cannot use push_back() with number", json::type_error&);
|
||||
}
|
||||
}
|
||||
|
||||
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_WITH_AS((k += {1, 2, 3, 4}), "[json.exception.type_error.308] cannot use push_back() with object", json::type_error&);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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 it = j_array.insert(j_array.end(), 0, 5);
|
||||
CHECK(j_array.size() == 4);
|
||||
// the returned iterator points to the first inserted element;
|
||||
// there were 4 elements, so it should point to the 5th
|
||||
CHECK(it == j_array.begin() + 4);
|
||||
CHECK(j_array == json({1, 2, 3, 4}));
|
||||
}
|
||||
}
|
||||
|
||||
SECTION("range for array")
|
||||
{
|
||||
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_WITH_AS(j_array.insert(j_array.end(), j_array.begin(), j_array.end()), "[json.exception.invalid_iterator.211] passed iterators may not belong to container",
|
||||
json::invalid_iterator&);
|
||||
CHECK_THROWS_WITH_AS(j_array.insert(j_array.end(), j_other_array.begin(), j_other_array2.end()), "[json.exception.invalid_iterator.210] iterators do not fit",
|
||||
json::invalid_iterator&);
|
||||
}
|
||||
}
|
||||
|
||||
SECTION("range for object")
|
||||
{
|
||||
json j_object1 = {{"one", "eins"}, {"two", "zwei"}};
|
||||
json j_object2 = {{"eleven", "elf"}, {"seventeen", "siebzehn"}};
|
||||
|
||||
SECTION("proper usage")
|
||||
{
|
||||
j_object1.insert(j_object2.begin(), j_object2.end());
|
||||
CHECK(j_object1.size() == 4);
|
||||
}
|
||||
|
||||
SECTION("empty range")
|
||||
{
|
||||
j_object1.insert(j_object2.begin(), j_object2.begin());
|
||||
CHECK(j_object1.size() == 2);
|
||||
}
|
||||
|
||||
SECTION("invalid iterators")
|
||||
{
|
||||
json j_other_array2 = {"first", "second"};
|
||||
|
||||
CHECK_THROWS_WITH_AS(j_array.insert(j_object2.begin(), j_object2.end()), "[json.exception.type_error.309] cannot use insert() with array", json::type_error&);
|
||||
CHECK_THROWS_WITH_AS(j_object1.insert(j_object1.begin(), j_object2.end()), "[json.exception.invalid_iterator.210] iterators do not fit", json::invalid_iterator&);
|
||||
CHECK_THROWS_WITH_AS(j_object1.insert(j_array.begin(), j_array.end()), "[json.exception.invalid_iterator.202] iterators first and last must point to objects", json::invalid_iterator&);
|
||||
}
|
||||
}
|
||||
|
||||
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_WITH_AS(j_array.insert(j_another_array.end(), 10), "[json.exception.invalid_iterator.202] iterator does not fit current value", json::invalid_iterator&);
|
||||
CHECK_THROWS_WITH_AS(j_array.insert(j_another_array.end(), j_value), "[json.exception.invalid_iterator.202] iterator does not fit current value", json::invalid_iterator&);
|
||||
CHECK_THROWS_WITH_AS(j_array.insert(j_another_array.end(), 10, 11), "[json.exception.invalid_iterator.202] iterator does not fit current value", json::invalid_iterator&);
|
||||
CHECK_THROWS_WITH_AS(j_array.insert(j_another_array.end(), j_yet_another_array.begin(), j_yet_another_array.end()), "[json.exception.invalid_iterator.202] iterator does not fit current value", json::invalid_iterator&);
|
||||
CHECK_THROWS_WITH_AS(j_array.insert(j_another_array.end(), {1, 2, 3, 4}), "[json.exception.invalid_iterator.202] iterator does not fit current value", json::invalid_iterator&);
|
||||
}
|
||||
|
||||
SECTION("non-array type")
|
||||
{
|
||||
// call insert on a non-array type
|
||||
json j_nonarray = 3;
|
||||
json j_yet_another_array = {"first", "second"};
|
||||
CHECK_THROWS_WITH_AS(j_nonarray.insert(j_nonarray.end(), 10), "[json.exception.type_error.309] cannot use insert() with number", json::type_error&);
|
||||
CHECK_THROWS_WITH_AS(j_nonarray.insert(j_nonarray.end(), j_value), "[json.exception.type_error.309] cannot use insert() with number", json::type_error&);
|
||||
CHECK_THROWS_WITH_AS(j_nonarray.insert(j_nonarray.end(), 10, 11), "[json.exception.type_error.309] cannot use insert() with number", json::type_error&);
|
||||
CHECK_THROWS_WITH_AS(j_nonarray.insert(j_nonarray.end(), j_yet_another_array.begin(), j_yet_another_array.end()), "[json.exception.type_error.309] cannot use insert() with number", json::type_error&);
|
||||
CHECK_THROWS_WITH_AS(j_nonarray.insert(j_nonarray.end(), {1, 2, 3, 4}), "[json.exception.type_error.309] cannot use insert() with number", json::type_error&);
|
||||
}
|
||||
}
|
||||
|
||||
SECTION("update()")
|
||||
{
|
||||
SECTION("non-recursive (default)")
|
||||
{
|
||||
json j_object1 = {{"one", "eins"}, {"two", "zwei"}};
|
||||
json j_object2 = {{"three", "drei"}, {"two", "zwo"}};
|
||||
json j_array = {1, 2, 3, 4};
|
||||
|
||||
SECTION("const reference")
|
||||
{
|
||||
SECTION("proper usage")
|
||||
{
|
||||
j_object1.update(j_object2);
|
||||
CHECK(j_object1 == json({{"one", "eins"}, {"two", "zwo"}, {"three", "drei"}}));
|
||||
|
||||
json j_null;
|
||||
j_null.update(j_object2);
|
||||
CHECK(j_null == j_object2);
|
||||
}
|
||||
|
||||
SECTION("wrong types")
|
||||
{
|
||||
CHECK_THROWS_WITH_AS(j_array.update(j_object1), "[json.exception.type_error.312] cannot use update() with array", json::type_error&);
|
||||
|
||||
CHECK_THROWS_WITH_AS(j_object1.update(j_array), "[json.exception.type_error.312] cannot use update() with array", json::type_error&);
|
||||
}
|
||||
}
|
||||
|
||||
SECTION("iterator range")
|
||||
{
|
||||
SECTION("proper usage")
|
||||
{
|
||||
j_object1.update(j_object2.begin(), j_object2.end());
|
||||
CHECK(j_object1 == json({{"one", "eins"}, {"two", "zwo"}, {"three", "drei"}}));
|
||||
|
||||
json j_null;
|
||||
j_null.update(j_object2.begin(), j_object2.end());
|
||||
CHECK(j_null == j_object2);
|
||||
}
|
||||
|
||||
SECTION("empty range")
|
||||
{
|
||||
j_object1.update(j_object2.begin(), j_object2.begin());
|
||||
CHECK(j_object1 == json({{"one", "eins"}, {"two", "zwei"}}));
|
||||
}
|
||||
|
||||
SECTION("invalid iterators")
|
||||
{
|
||||
json j_other_array2 = {"first", "second"};
|
||||
|
||||
CHECK_THROWS_WITH_AS(j_array.update(j_object2.begin(), j_object2.end()), "[json.exception.type_error.312] cannot use update() with array", json::type_error&);
|
||||
CHECK_THROWS_WITH_AS(j_object1.update(j_object1.begin(), j_object2.end()), "[json.exception.invalid_iterator.210] iterators do not fit", json::invalid_iterator&);
|
||||
CHECK_THROWS_WITH_AS(j_object1.update(j_array.begin(), j_array.end()), "[json.exception.type_error.312] cannot use update() with array", json::type_error&);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
SECTION("recursive")
|
||||
{
|
||||
SECTION("const reference")
|
||||
{
|
||||
SECTION("extend object")
|
||||
{
|
||||
json j1 = {{"string", "s"}, {"numbers", {{"one", 1}}}};
|
||||
json j2 = {{"string", "t"}, {"numbers", {{"two", 2}}}};
|
||||
j1.update(j2, true);
|
||||
CHECK(j1 == json({{"string", "t"}, {"numbers", {{"one", 1}, {"two", 2}}}}));
|
||||
}
|
||||
|
||||
SECTION("replace object")
|
||||
{
|
||||
json j1 = {{"string", "s"}, {"numbers", {{"one", 1}}}};
|
||||
json j2 = {{"string", "t"}, {"numbers", 1}};
|
||||
j1.update(j2, true);
|
||||
CHECK(j1 == json({{"string", "t"}, {"numbers", 1}}));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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);
|
||||
|
||||
using std::swap;
|
||||
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_WITH_AS(j.swap(a), "[json.exception.type_error.310] cannot use swap() with number", json::type_error&);
|
||||
}
|
||||
}
|
||||
|
||||
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_WITH_AS(j.swap(o), "[json.exception.type_error.310] cannot use swap() with number", json::type_error&);
|
||||
}
|
||||
}
|
||||
|
||||
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_WITH_AS(j.swap(s), "[json.exception.type_error.310] cannot use swap() with number", json::type_error&);
|
||||
}
|
||||
}
|
||||
|
||||
SECTION("binary_t")
|
||||
{
|
||||
SECTION("binary_t type")
|
||||
{
|
||||
json j = json::binary({1, 2, 3, 4});
|
||||
json::binary_t s = {{5, 6, 7, 8}};
|
||||
|
||||
j.swap(s);
|
||||
|
||||
CHECK(j == json::binary({5, 6, 7, 8}));
|
||||
|
||||
j.swap(s);
|
||||
|
||||
CHECK(j == json::binary({1, 2, 3, 4}));
|
||||
}
|
||||
|
||||
SECTION("binary_t::container_type type")
|
||||
{
|
||||
json j = json::binary({1, 2, 3, 4});
|
||||
std::vector<std::uint8_t> s = {{5, 6, 7, 8}};
|
||||
|
||||
j.swap(s);
|
||||
|
||||
CHECK(j == json::binary({5, 6, 7, 8}));
|
||||
|
||||
j.swap(s);
|
||||
|
||||
CHECK(j == json::binary({1, 2, 3, 4}));
|
||||
}
|
||||
|
||||
SECTION("non-binary_t type")
|
||||
{
|
||||
json j = 17;
|
||||
json::binary_t s1 = {{1, 2, 3, 4}};
|
||||
std::vector<std::uint8_t> s2 = {{5, 6, 7, 8}};
|
||||
|
||||
CHECK_THROWS_WITH_AS(j.swap(s1), "[json.exception.type_error.310] cannot use swap() with number", json::type_error);
|
||||
CHECK_THROWS_WITH_AS(j.swap(s2), "[json.exception.type_error.310] cannot use swap() with number", json::type_error);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,103 @@
|
||||
/*
|
||||
__ _____ _____ _____
|
||||
__| | __| | | | JSON for Modern C++ (test suite)
|
||||
| | |__ | | | | | | version 3.10.5
|
||||
|_____|_____|_____|_|___| https://github.com/nlohmann/json
|
||||
|
||||
Licensed under the MIT License <http://opensource.org/licenses/MIT>.
|
||||
SPDX-License-Identifier: MIT
|
||||
Copyright (c) 2013-2022 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 "doctest_compatibility.h"
|
||||
|
||||
// disable -Wnoexcept due to struct pod_bis
|
||||
DOCTEST_GCC_SUPPRESS_WARNING_PUSH
|
||||
DOCTEST_GCC_SUPPRESS_WARNING("-Wnoexcept")
|
||||
|
||||
#include <nlohmann/json.hpp>
|
||||
|
||||
using nlohmann::json;
|
||||
|
||||
namespace
|
||||
{
|
||||
enum test
|
||||
{
|
||||
};
|
||||
|
||||
struct pod {};
|
||||
struct pod_bis {};
|
||||
|
||||
void to_json(json& /*unused*/, pod /*unused*/) noexcept;
|
||||
void to_json(json& /*unused*/, pod_bis /*unused*/);
|
||||
void from_json(const json& /*unused*/, pod /*unused*/) noexcept;
|
||||
void from_json(const json& /*unused*/, pod_bis /*unused*/);
|
||||
void to_json(json& /*unused*/, pod /*unused*/) noexcept {}
|
||||
void to_json(json& /*unused*/, pod_bis /*unused*/) {}
|
||||
void from_json(const json& /*unused*/, pod /*unused*/) noexcept {}
|
||||
void from_json(const json& /*unused*/, pod_bis /*unused*/) {}
|
||||
|
||||
json* j = nullptr;
|
||||
|
||||
static_assert(noexcept(json{}), "");
|
||||
static_assert(noexcept(nlohmann::to_json(*j, 2)), "");
|
||||
static_assert(noexcept(nlohmann::to_json(*j, 2.5)), "");
|
||||
static_assert(noexcept(nlohmann::to_json(*j, true)), "");
|
||||
static_assert(noexcept(nlohmann::to_json(*j, test{})), "");
|
||||
static_assert(noexcept(nlohmann::to_json(*j, pod{})), "");
|
||||
static_assert(!noexcept(nlohmann::to_json(*j, pod_bis{})), "");
|
||||
static_assert(noexcept(json(2)), "");
|
||||
static_assert(noexcept(json(test{})), "");
|
||||
static_assert(noexcept(json(pod{})), "");
|
||||
static_assert(noexcept(j->get<pod>()), "");
|
||||
static_assert(!noexcept(j->get<pod_bis>()), "");
|
||||
static_assert(noexcept(json(pod{})), "");
|
||||
} // namespace
|
||||
|
||||
TEST_CASE("runtime checks")
|
||||
{
|
||||
SECTION("nothrow-copy-constructible exceptions")
|
||||
{
|
||||
// for ERR60-CPP (https://github.com/nlohmann/json/issues/531):
|
||||
// Exceptions should be nothrow-copy-constructible. However, compilers
|
||||
// treat std::runtime_exception differently in this regard. Therefore,
|
||||
// we can only demand nothrow-copy-constructibility for our exceptions
|
||||
// if std::runtime_exception is.
|
||||
CHECK(std::is_nothrow_copy_constructible<json::exception>::value == std::is_nothrow_copy_constructible<std::runtime_error>::value);
|
||||
CHECK(std::is_nothrow_copy_constructible<json::parse_error>::value == std::is_nothrow_copy_constructible<std::runtime_error>::value);
|
||||
CHECK(std::is_nothrow_copy_constructible<json::invalid_iterator>::value == std::is_nothrow_copy_constructible<std::runtime_error>::value);
|
||||
CHECK(std::is_nothrow_copy_constructible<json::type_error>::value == std::is_nothrow_copy_constructible<std::runtime_error>::value);
|
||||
CHECK(std::is_nothrow_copy_constructible<json::out_of_range>::value == std::is_nothrow_copy_constructible<std::runtime_error>::value);
|
||||
CHECK(std::is_nothrow_copy_constructible<json::other_error>::value == std::is_nothrow_copy_constructible<std::runtime_error>::value);
|
||||
}
|
||||
|
||||
SECTION("silence -Wunneeded-internal-declaration errors")
|
||||
{
|
||||
j = nullptr;
|
||||
json j2;
|
||||
to_json(j2, pod());
|
||||
to_json(j2, pod_bis());
|
||||
from_json(j2, pod());
|
||||
from_json(j2, pod_bis());
|
||||
}
|
||||
}
|
||||
|
||||
DOCTEST_GCC_SUPPRESS_WARNING_POP
|
||||
@@ -0,0 +1,93 @@
|
||||
/*
|
||||
__ _____ _____ _____
|
||||
__| | __| | | | JSON for Modern C++ (test suite)
|
||||
| | |__ | | | | | | version 3.10.5
|
||||
|_____|_____|_____|_|___| https://github.com/nlohmann/json
|
||||
|
||||
Licensed under the MIT License <http://opensource.org/licenses/MIT>.
|
||||
SPDX-License-Identifier: MIT
|
||||
Copyright (c) 2013-2022 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 "doctest_compatibility.h"
|
||||
|
||||
#include <nlohmann/json.hpp>
|
||||
using nlohmann::json;
|
||||
using nlohmann::ordered_json;
|
||||
|
||||
|
||||
TEST_CASE("ordered_json")
|
||||
{
|
||||
json j;
|
||||
ordered_json oj;
|
||||
|
||||
j["element3"] = 3;
|
||||
j["element1"] = 1;
|
||||
j["element2"] = 2;
|
||||
|
||||
oj["element3"] = 3;
|
||||
oj["element1"] = 1;
|
||||
oj["element2"] = 2;
|
||||
|
||||
CHECK(j.dump() == "{\"element1\":1,\"element2\":2,\"element3\":3}");
|
||||
CHECK(oj.dump() == "{\"element3\":3,\"element1\":1,\"element2\":2}");
|
||||
|
||||
CHECK(j == json(oj));
|
||||
CHECK(ordered_json(json(oj)) == ordered_json(j));
|
||||
|
||||
j.erase("element1");
|
||||
oj.erase("element1");
|
||||
|
||||
CHECK(j.dump() == "{\"element2\":2,\"element3\":3}");
|
||||
CHECK(oj.dump() == "{\"element3\":3,\"element2\":2}");
|
||||
|
||||
// remove again and nothing changes
|
||||
j.erase("element1");
|
||||
oj.erase("element1");
|
||||
|
||||
CHECK(j.dump() == "{\"element2\":2,\"element3\":3}");
|
||||
CHECK(oj.dump() == "{\"element3\":3,\"element2\":2}");
|
||||
|
||||
// There are no dup keys cause constructor calls emplace...
|
||||
json multi {{"z", 1}, {"m", 2}, {"m", 3}, {"y", 4}, {"m", 5}};
|
||||
CHECK(multi.size() == 3);
|
||||
CHECK(multi.dump() == "{\"m\":2,\"y\":4,\"z\":1}");
|
||||
|
||||
ordered_json multi_ordered {{"z", 1}, {"m", 2}, {"m", 3}, {"y", 4}, {"m", 5}};
|
||||
CHECK(multi_ordered.size() == 3);
|
||||
CHECK(multi_ordered.dump() == "{\"z\":1,\"m\":2,\"y\":4}");
|
||||
CHECK(multi_ordered.erase("m") == 1);
|
||||
CHECK(multi_ordered.dump() == "{\"z\":1,\"y\":4}");
|
||||
|
||||
// Ranged insert test.
|
||||
// It seems that values shouldn't be overwritten. Only new values are added
|
||||
json j1 {{"c", 1}, {"b", 2}, {"a", 3}};
|
||||
const json j2 {{"c", 77}, {"d", 42}, {"a", 4}};
|
||||
j1.insert( j2.cbegin(), j2.cend() );
|
||||
CHECK(j1.size() == 4);
|
||||
CHECK(j1.dump() == "{\"a\":3,\"b\":2,\"c\":1,\"d\":42}");
|
||||
|
||||
ordered_json oj1 {{"c", 1}, {"b", 2}, {"a", 3}};
|
||||
const ordered_json oj2 {{"c", 77}, {"d", 42}, {"a", 4}};
|
||||
oj1.insert( oj2.cbegin(), oj2.cend() );
|
||||
CHECK(oj1.size() == 4);
|
||||
CHECK(oj1.dump() == "{\"c\":1,\"b\":2,\"a\":3,\"d\":42}");
|
||||
}
|
||||
@@ -0,0 +1,332 @@
|
||||
/*
|
||||
__ _____ _____ _____
|
||||
__| | __| | | | JSON for Modern C++ (test suite)
|
||||
| | |__ | | | | | | version 3.10.5
|
||||
|_____|_____|_____|_|___| https://github.com/nlohmann/json
|
||||
|
||||
Licensed under the MIT License <http://opensource.org/licenses/MIT>.
|
||||
SPDX-License-Identifier: MIT
|
||||
Copyright (c) 2013-2022 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 "doctest_compatibility.h"
|
||||
|
||||
#include <nlohmann/json.hpp>
|
||||
using nlohmann::ordered_map;
|
||||
|
||||
|
||||
TEST_CASE("ordered_map")
|
||||
{
|
||||
SECTION("constructor")
|
||||
{
|
||||
SECTION("constructor from iterator range")
|
||||
{
|
||||
std::map<std::string, std::string> m {{"eins", "one"}, {"zwei", "two"}, {"drei", "three"}};
|
||||
ordered_map<std::string, std::string> om(m.begin(), m.end());
|
||||
CHECK(om.size() == 3);
|
||||
}
|
||||
|
||||
SECTION("copy assignment")
|
||||
{
|
||||
std::map<std::string, std::string> m {{"eins", "one"}, {"zwei", "two"}, {"drei", "three"}};
|
||||
ordered_map<std::string, std::string> om(m.begin(), m.end());
|
||||
const auto com = om;
|
||||
om.clear(); // silence a warning by forbidding having "const auto& com = om;"
|
||||
CHECK(com.size() == 3);
|
||||
}
|
||||
}
|
||||
|
||||
SECTION("at")
|
||||
{
|
||||
std::map<std::string, std::string> m {{"eins", "one"}, {"zwei", "two"}, {"drei", "three"}};
|
||||
ordered_map<std::string, std::string> om(m.begin(), m.end());
|
||||
const auto com = om;
|
||||
|
||||
SECTION("with Key&&")
|
||||
{
|
||||
CHECK(om.at(std::string("eins")) == std::string("one"));
|
||||
CHECK(com.at(std::string("eins")) == std::string("one"));
|
||||
CHECK_THROWS_AS(om.at(std::string("vier")), std::out_of_range);
|
||||
CHECK_THROWS_AS(com.at(std::string("vier")), std::out_of_range);
|
||||
}
|
||||
|
||||
SECTION("with const Key&&")
|
||||
{
|
||||
const std::string eins = "eins";
|
||||
const std::string vier = "vier";
|
||||
CHECK(om.at(eins) == std::string("one"));
|
||||
CHECK(com.at(eins) == std::string("one"));
|
||||
CHECK_THROWS_AS(om.at(vier), std::out_of_range);
|
||||
CHECK_THROWS_AS(com.at(vier), std::out_of_range);
|
||||
}
|
||||
|
||||
SECTION("with string literal")
|
||||
{
|
||||
CHECK(om.at("eins") == std::string("one"));
|
||||
CHECK(com.at("eins") == std::string("one"));
|
||||
CHECK_THROWS_AS(om.at("vier"), std::out_of_range);
|
||||
CHECK_THROWS_AS(com.at("vier"), std::out_of_range);
|
||||
}
|
||||
}
|
||||
|
||||
SECTION("operator[]")
|
||||
{
|
||||
std::map<std::string, std::string> m {{"eins", "one"}, {"zwei", "two"}, {"drei", "three"}};
|
||||
ordered_map<std::string, std::string> om(m.begin(), m.end());
|
||||
const auto com = om;
|
||||
|
||||
SECTION("with Key&&")
|
||||
{
|
||||
CHECK(om[std::string("eins")] == std::string("one"));
|
||||
CHECK(com[std::string("eins")] == std::string("one"));
|
||||
|
||||
CHECK(om[std::string("vier")] == std::string(""));
|
||||
CHECK(om.size() == 4);
|
||||
}
|
||||
|
||||
SECTION("with const Key&&")
|
||||
{
|
||||
const std::string eins = "eins";
|
||||
const std::string vier = "vier";
|
||||
|
||||
CHECK(om[eins] == std::string("one"));
|
||||
CHECK(com[eins] == std::string("one"));
|
||||
|
||||
CHECK(om[vier] == std::string(""));
|
||||
CHECK(om.size() == 4);
|
||||
}
|
||||
|
||||
SECTION("with string literal")
|
||||
{
|
||||
CHECK(om["eins"] == std::string("one"));
|
||||
CHECK(com["eins"] == std::string("one"));
|
||||
|
||||
CHECK(om["vier"] == std::string(""));
|
||||
CHECK(om.size() == 4);
|
||||
}
|
||||
}
|
||||
|
||||
SECTION("erase")
|
||||
{
|
||||
ordered_map<std::string, std::string> om;
|
||||
om["eins"] = "one";
|
||||
om["zwei"] = "two";
|
||||
om["drei"] = "three";
|
||||
|
||||
{
|
||||
auto it = om.begin();
|
||||
CHECK(it->first == "eins");
|
||||
++it;
|
||||
CHECK(it->first == "zwei");
|
||||
++it;
|
||||
CHECK(it->first == "drei");
|
||||
++it;
|
||||
CHECK(it == om.end());
|
||||
}
|
||||
|
||||
SECTION("with Key&&")
|
||||
{
|
||||
CHECK(om.size() == 3);
|
||||
CHECK(om.erase(std::string("eins")) == 1);
|
||||
CHECK(om.size() == 2);
|
||||
CHECK(om.erase(std::string("vier")) == 0);
|
||||
CHECK(om.size() == 2);
|
||||
|
||||
auto it = om.begin();
|
||||
CHECK(it->first == "zwei");
|
||||
++it;
|
||||
CHECK(it->first == "drei");
|
||||
++it;
|
||||
CHECK(it == om.end());
|
||||
}
|
||||
|
||||
SECTION("with const Key&&")
|
||||
{
|
||||
const std::string eins = "eins";
|
||||
const std::string vier = "vier";
|
||||
CHECK(om.size() == 3);
|
||||
CHECK(om.erase(eins) == 1);
|
||||
CHECK(om.size() == 2);
|
||||
CHECK(om.erase(vier) == 0);
|
||||
CHECK(om.size() == 2);
|
||||
|
||||
auto it = om.begin();
|
||||
CHECK(it->first == "zwei");
|
||||
++it;
|
||||
CHECK(it->first == "drei");
|
||||
++it;
|
||||
CHECK(it == om.end());
|
||||
}
|
||||
|
||||
SECTION("with string literal")
|
||||
{
|
||||
CHECK(om.size() == 3);
|
||||
CHECK(om.erase("eins") == 1);
|
||||
CHECK(om.size() == 2);
|
||||
CHECK(om.erase("vier") == 0);
|
||||
CHECK(om.size() == 2);
|
||||
|
||||
auto it = om.begin();
|
||||
CHECK(it->first == "zwei");
|
||||
++it;
|
||||
CHECK(it->first == "drei");
|
||||
++it;
|
||||
CHECK(it == om.end());
|
||||
}
|
||||
|
||||
SECTION("with iterator")
|
||||
{
|
||||
CHECK(om.size() == 3);
|
||||
CHECK(om.begin()->first == "eins");
|
||||
CHECK(std::next(om.begin(), 1)->first == "zwei");
|
||||
CHECK(std::next(om.begin(), 2)->first == "drei");
|
||||
|
||||
auto it = om.erase(om.begin());
|
||||
CHECK(it->first == "zwei");
|
||||
CHECK(om.size() == 2);
|
||||
|
||||
auto it2 = om.begin();
|
||||
CHECK(it2->first == "zwei");
|
||||
++it2;
|
||||
CHECK(it2->first == "drei");
|
||||
++it2;
|
||||
CHECK(it2 == om.end());
|
||||
}
|
||||
|
||||
SECTION("with iterator pair")
|
||||
{
|
||||
SECTION("range in the middle")
|
||||
{
|
||||
// need more elements
|
||||
om["vier"] = "four";
|
||||
om["fünf"] = "five";
|
||||
|
||||
// delete "zwei" and "drei"
|
||||
auto it = om.erase(om.begin() + 1, om.begin() + 3);
|
||||
CHECK(it->first == "vier");
|
||||
CHECK(om.size() == 3);
|
||||
}
|
||||
|
||||
SECTION("range at the beginning")
|
||||
{
|
||||
// need more elements
|
||||
om["vier"] = "four";
|
||||
om["fünf"] = "five";
|
||||
|
||||
// delete "eins" and "zwei"
|
||||
auto it = om.erase(om.begin(), om.begin() + 2);
|
||||
CHECK(it->first == "drei");
|
||||
CHECK(om.size() == 3);
|
||||
}
|
||||
|
||||
SECTION("range at the end")
|
||||
{
|
||||
// need more elements
|
||||
om["vier"] = "four";
|
||||
om["fünf"] = "five";
|
||||
|
||||
// delete "vier" and "fünf"
|
||||
auto it = om.erase(om.begin() + 3, om.end());
|
||||
CHECK(it == om.end());
|
||||
CHECK(om.size() == 3);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
SECTION("count")
|
||||
{
|
||||
ordered_map<std::string, std::string> om;
|
||||
om["eins"] = "one";
|
||||
om["zwei"] = "two";
|
||||
om["drei"] = "three";
|
||||
|
||||
const std::string eins("eins");
|
||||
const std::string vier("vier");
|
||||
CHECK(om.count("eins") == 1);
|
||||
CHECK(om.count(std::string("eins")) == 1);
|
||||
CHECK(om.count(eins) == 1);
|
||||
CHECK(om.count("vier") == 0);
|
||||
CHECK(om.count(std::string("vier")) == 0);
|
||||
CHECK(om.count(vier) == 0);
|
||||
}
|
||||
|
||||
SECTION("find")
|
||||
{
|
||||
ordered_map<std::string, std::string> om;
|
||||
om["eins"] = "one";
|
||||
om["zwei"] = "two";
|
||||
om["drei"] = "three";
|
||||
const auto com = om;
|
||||
|
||||
const std::string eins("eins");
|
||||
const std::string vier("vier");
|
||||
CHECK(om.find("eins") == om.begin());
|
||||
CHECK(om.find(std::string("eins")) == om.begin());
|
||||
CHECK(om.find(eins) == om.begin());
|
||||
CHECK(om.find("vier") == om.end());
|
||||
CHECK(om.find(std::string("vier")) == om.end());
|
||||
CHECK(om.find(vier) == om.end());
|
||||
|
||||
CHECK(com.find("eins") == com.begin());
|
||||
CHECK(com.find(std::string("eins")) == com.begin());
|
||||
CHECK(com.find(eins) == com.begin());
|
||||
CHECK(com.find("vier") == com.end());
|
||||
CHECK(com.find(std::string("vier")) == com.end());
|
||||
CHECK(com.find(vier) == com.end());
|
||||
}
|
||||
|
||||
SECTION("insert")
|
||||
{
|
||||
ordered_map<std::string, std::string> om;
|
||||
om["eins"] = "one";
|
||||
om["zwei"] = "two";
|
||||
om["drei"] = "three";
|
||||
|
||||
SECTION("const value_type&")
|
||||
{
|
||||
ordered_map<std::string, std::string>::value_type vt1 {"eins", "1"};
|
||||
ordered_map<std::string, std::string>::value_type vt4 {"vier", "four"};
|
||||
|
||||
auto res1 = om.insert(vt1);
|
||||
CHECK(res1.first == om.begin());
|
||||
CHECK(res1.second == false);
|
||||
CHECK(om.size() == 3);
|
||||
|
||||
auto res4 = om.insert(vt4);
|
||||
CHECK(res4.first == om.begin() + 3);
|
||||
CHECK(res4.second == true);
|
||||
CHECK(om.size() == 4);
|
||||
}
|
||||
|
||||
SECTION("value_type&&")
|
||||
{
|
||||
auto res1 = om.insert({"eins", "1"});
|
||||
CHECK(res1.first == om.begin());
|
||||
CHECK(res1.second == false);
|
||||
CHECK(om.size() == 3);
|
||||
|
||||
auto res4 = om.insert({"vier", "four"});
|
||||
CHECK(res4.first == om.begin() + 3);
|
||||
CHECK(res4.second == true);
|
||||
CHECK(om.size() == 4);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,500 @@
|
||||
/*
|
||||
__ _____ _____ _____
|
||||
__| | __| | | | JSON for Modern C++ (test suite)
|
||||
| | |__ | | | | | | version 3.10.5
|
||||
|_____|_____|_____|_|___| https://github.com/nlohmann/json
|
||||
|
||||
Licensed under the MIT License <http://opensource.org/licenses/MIT>.
|
||||
SPDX-License-Identifier: MIT
|
||||
Copyright (c) 2013-2022 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 "doctest_compatibility.h"
|
||||
|
||||
#include <nlohmann/json.hpp>
|
||||
using nlohmann::json;
|
||||
|
||||
TEST_CASE("pointer access")
|
||||
{
|
||||
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(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(p3 == 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);
|
||||
CHECK(value.get_ptr<json::binary_t*>() == nullptr);
|
||||
}
|
||||
|
||||
SECTION("pointer access to const object_t")
|
||||
{
|
||||
using test_type = const json::object_t;
|
||||
const 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(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(p3 == value.get_ptr<const test_type* const>());
|
||||
CHECK(*p3 == value.get<test_type>());
|
||||
|
||||
// check if null pointers are returned correctly
|
||||
CHECK(value.get_ptr<const json::object_t*>() != nullptr);
|
||||
CHECK(value.get_ptr<const json::array_t*>() == nullptr);
|
||||
CHECK(value.get_ptr<const json::string_t*>() == nullptr);
|
||||
CHECK(value.get_ptr<const json::boolean_t*>() == nullptr);
|
||||
CHECK(value.get_ptr<const json::number_integer_t*>() == nullptr);
|
||||
CHECK(value.get_ptr<const json::number_unsigned_t*>() == nullptr);
|
||||
CHECK(value.get_ptr<const json::number_float_t*>() == nullptr);
|
||||
CHECK(value.get_ptr<const json::binary_t*>() == nullptr);
|
||||
}
|
||||
|
||||
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(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(p3 == 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);
|
||||
CHECK(value.get_ptr<json::binary_t*>() == nullptr);
|
||||
}
|
||||
|
||||
SECTION("pointer access to const array_t")
|
||||
{
|
||||
using test_type = const json::array_t;
|
||||
const 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(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(p3 == value.get_ptr<const test_type* const>());
|
||||
CHECK(*p3 == value.get<test_type>());
|
||||
|
||||
// check if null pointers are returned correctly
|
||||
CHECK(value.get_ptr<const json::object_t*>() == nullptr);
|
||||
CHECK(value.get_ptr<const json::array_t*>() != nullptr);
|
||||
CHECK(value.get_ptr<const json::string_t*>() == nullptr);
|
||||
CHECK(value.get_ptr<const json::boolean_t*>() == nullptr);
|
||||
CHECK(value.get_ptr<const json::number_integer_t*>() == nullptr);
|
||||
CHECK(value.get_ptr<const json::number_unsigned_t*>() == nullptr);
|
||||
CHECK(value.get_ptr<const json::number_float_t*>() == nullptr);
|
||||
CHECK(value.get_ptr<const json::binary_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(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(p3 == 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);
|
||||
CHECK(value.get_ptr<json::binary_t*>() == nullptr);
|
||||
}
|
||||
|
||||
SECTION("pointer access to const string_t")
|
||||
{
|
||||
using test_type = const json::string_t;
|
||||
const 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(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(p3 == value.get_ptr<const test_type* const>());
|
||||
CHECK(*p3 == value.get<test_type>());
|
||||
|
||||
// check if null pointers are returned correctly
|
||||
CHECK(value.get_ptr<const json::object_t*>() == nullptr);
|
||||
CHECK(value.get_ptr<const json::array_t*>() == nullptr);
|
||||
CHECK(value.get_ptr<const json::string_t*>() != nullptr);
|
||||
CHECK(value.get_ptr<const json::boolean_t*>() == nullptr);
|
||||
CHECK(value.get_ptr<const json::number_integer_t*>() == nullptr);
|
||||
CHECK(value.get_ptr<const json::number_unsigned_t*>() == nullptr);
|
||||
CHECK(value.get_ptr<const json::number_float_t*>() == nullptr);
|
||||
CHECK(value.get_ptr<const json::binary_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(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(p3 == 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);
|
||||
CHECK(value.get_ptr<json::binary_t*>() == nullptr);
|
||||
}
|
||||
|
||||
SECTION("pointer access to const boolean_t")
|
||||
{
|
||||
using test_type = const json::boolean_t;
|
||||
const 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(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(p3 == value.get_ptr<const test_type* const>());
|
||||
CHECK(*p3 == value.get<test_type>());
|
||||
|
||||
// check if null pointers are returned correctly
|
||||
CHECK(value.get_ptr<const json::object_t*>() == nullptr);
|
||||
CHECK(value.get_ptr<const json::array_t*>() == nullptr);
|
||||
CHECK(value.get_ptr<const json::string_t*>() == nullptr);
|
||||
CHECK(value.get_ptr<const json::boolean_t*>() != nullptr);
|
||||
CHECK(value.get_ptr<const json::number_integer_t*>() == nullptr);
|
||||
CHECK(value.get_ptr<const json::number_unsigned_t*>() == nullptr);
|
||||
CHECK(value.get_ptr<const json::number_float_t*>() == nullptr);
|
||||
CHECK(value.get_ptr<const json::binary_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(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(p3 == 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);
|
||||
CHECK(value.get_ptr<json::binary_t*>() == nullptr);
|
||||
}
|
||||
|
||||
SECTION("pointer access to const number_integer_t")
|
||||
{
|
||||
using test_type = const json::number_integer_t;
|
||||
const 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(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(p3 == value.get_ptr<const test_type* const>());
|
||||
CHECK(*p3 == value.get<test_type>());
|
||||
|
||||
// check if null pointers are returned correctly
|
||||
CHECK(value.get_ptr<const json::object_t*>() == nullptr);
|
||||
CHECK(value.get_ptr<const json::array_t*>() == nullptr);
|
||||
CHECK(value.get_ptr<const json::string_t*>() == nullptr);
|
||||
CHECK(value.get_ptr<const json::boolean_t*>() == nullptr);
|
||||
CHECK(value.get_ptr<const json::number_integer_t*>() != nullptr);
|
||||
CHECK(value.get_ptr<const json::number_unsigned_t*>() == nullptr);
|
||||
CHECK(value.get_ptr<const json::number_float_t*>() == nullptr);
|
||||
CHECK(value.get_ptr<const json::binary_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(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(p3 == 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);
|
||||
CHECK(value.get_ptr<json::binary_t*>() == nullptr);
|
||||
}
|
||||
|
||||
SECTION("pointer access to const number_unsigned_t")
|
||||
{
|
||||
using test_type = const json::number_unsigned_t;
|
||||
const 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(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(p3 == value.get_ptr<const test_type* const>());
|
||||
CHECK(*p3 == value.get<test_type>());
|
||||
|
||||
// check if null pointers are returned correctly
|
||||
CHECK(value.get_ptr<const json::object_t*>() == nullptr);
|
||||
CHECK(value.get_ptr<const json::array_t*>() == nullptr);
|
||||
CHECK(value.get_ptr<const json::string_t*>() == nullptr);
|
||||
CHECK(value.get_ptr<const json::boolean_t*>() == nullptr);
|
||||
CHECK(value.get_ptr<const json::number_integer_t*>() != nullptr);
|
||||
CHECK(value.get_ptr<const json::number_unsigned_t*>() != nullptr);
|
||||
CHECK(value.get_ptr<const json::number_float_t*>() == nullptr);
|
||||
CHECK(value.get_ptr<const json::binary_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(p2 == 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(p3 == 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);
|
||||
CHECK(value.get_ptr<json::binary_t*>() == nullptr);
|
||||
}
|
||||
|
||||
SECTION("pointer access to const number_float_t")
|
||||
{
|
||||
using test_type = const json::number_float_t;
|
||||
const 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(p2 == 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(p3 == 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<const json::object_t*>() == nullptr);
|
||||
CHECK(value.get_ptr<const json::array_t*>() == nullptr);
|
||||
CHECK(value.get_ptr<const json::string_t*>() == nullptr);
|
||||
CHECK(value.get_ptr<const json::boolean_t*>() == nullptr);
|
||||
CHECK(value.get_ptr<const json::number_integer_t*>() == nullptr);
|
||||
CHECK(value.get_ptr<const json::number_unsigned_t*>() == nullptr);
|
||||
CHECK(value.get_ptr<const json::number_float_t*>() != nullptr);
|
||||
CHECK(value.get_ptr<const json::binary_t*>() == nullptr);
|
||||
}
|
||||
|
||||
SECTION("pointer access to const binary_t")
|
||||
{
|
||||
using test_type = const json::binary_t;
|
||||
const json value = json::binary({1, 2, 3});
|
||||
|
||||
// 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(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(p3 == value.get_ptr<const test_type* const>());
|
||||
CHECK(*p3 == value.get<test_type>());
|
||||
|
||||
// check if null pointers are returned correctly
|
||||
CHECK(value.get_ptr<const json::object_t*>() == nullptr);
|
||||
CHECK(value.get_ptr<const json::array_t*>() == nullptr);
|
||||
CHECK(value.get_ptr<const json::string_t*>() == nullptr);
|
||||
CHECK(value.get_ptr<const json::boolean_t*>() == nullptr);
|
||||
CHECK(value.get_ptr<const json::number_integer_t*>() == nullptr);
|
||||
CHECK(value.get_ptr<const json::number_unsigned_t*>() == nullptr);
|
||||
CHECK(value.get_ptr<const json::number_float_t*>() == nullptr);
|
||||
CHECK(value.get_ptr<const json::binary_t*>() != nullptr);
|
||||
}
|
||||
|
||||
SECTION("pointer access to const binary_t")
|
||||
{
|
||||
using test_type = const json::binary_t;
|
||||
const json value = json::binary({});
|
||||
|
||||
// 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(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(p3 == value.get_ptr<const test_type* const>());
|
||||
CHECK(*p3 == value.get<test_type>());
|
||||
|
||||
// check if null pointers are returned correctly
|
||||
CHECK(value.get_ptr<const json::object_t*>() == nullptr);
|
||||
CHECK(value.get_ptr<const json::array_t*>() == nullptr);
|
||||
CHECK(value.get_ptr<const json::string_t*>() == nullptr);
|
||||
CHECK(value.get_ptr<const json::boolean_t*>() == nullptr);
|
||||
CHECK(value.get_ptr<const json::number_integer_t*>() == nullptr);
|
||||
CHECK(value.get_ptr<const json::number_unsigned_t*>() == nullptr);
|
||||
CHECK(value.get_ptr<const json::number_float_t*>() == nullptr);
|
||||
CHECK(value.get_ptr<const json::binary_t*>() != nullptr);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,323 @@
|
||||
/*
|
||||
__ _____ _____ _____
|
||||
__| | __| | | | JSON for Modern C++ (test suite)
|
||||
| | |__ | | | | | | version 3.10.5
|
||||
|_____|_____|_____|_|___| https://github.com/nlohmann/json
|
||||
|
||||
Licensed under the MIT License <http://opensource.org/licenses/MIT>.
|
||||
SPDX-License-Identifier: MIT
|
||||
Copyright (c) 2013-2022 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 "doctest_compatibility.h"
|
||||
|
||||
#include <nlohmann/json.hpp>
|
||||
using nlohmann::json;
|
||||
|
||||
#include <deque>
|
||||
#include <forward_list>
|
||||
#include <list>
|
||||
#include <set>
|
||||
#include <unordered_map>
|
||||
#include <unordered_set>
|
||||
#include <iostream>
|
||||
#include <sstream>
|
||||
#include <iomanip>
|
||||
|
||||
// local variable is initialized but not referenced
|
||||
DOCTEST_MSVC_SUPPRESS_WARNING_PUSH
|
||||
DOCTEST_MSVC_SUPPRESS_WARNING(4189)
|
||||
|
||||
TEST_CASE("README" * doctest::skip())
|
||||
{
|
||||
{
|
||||
// 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 = {{}};
|
||||
CHECK(empty_array_implicit.is_array());
|
||||
json empty_array_explicit = json::array();
|
||||
CHECK(empty_array_explicit.is_array());
|
||||
|
||||
// a way to express the empty object {}
|
||||
json empty_object_explicit = json::object();
|
||||
CHECK(empty_object_explicit.is_object());
|
||||
|
||||
// a way to express an _array_ of key/value pairs [["currency", "USD"], ["value", 42.99]]
|
||||
json array_not_object = json::array({ {"currency", "USD"}, {"value", 42.99} });
|
||||
CHECK(array_not_object.is_array());
|
||||
CHECK(array_not_object.size() == 2);
|
||||
CHECK(array_not_object[0].is_array());
|
||||
CHECK(array_not_object[1].is_array());
|
||||
}
|
||||
|
||||
{
|
||||
// create object from string literal
|
||||
json j = "{ \"happy\": true, \"pi\": 3.141 }"_json; // NOLINT(modernize-raw-string-literal)
|
||||
|
||||
// or even nicer with a raw string literal
|
||||
auto j2 = R"(
|
||||
{
|
||||
"happy": true,
|
||||
"pi": 3.141
|
||||
}
|
||||
)"_json;
|
||||
|
||||
// or explicitly
|
||||
auto j3 = json::parse(R"({"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);
|
||||
|
||||
// comparison
|
||||
bool x = (j == R"(["foo", 1, true])"_json); // true
|
||||
CHECK(x == true);
|
||||
|
||||
// iterate the array
|
||||
for (json::iterator it = j.begin(); it != j.end(); ++it) // NOLINT(modernize-loop-convert)
|
||||
{
|
||||
std::cout << *it << '\n';
|
||||
}
|
||||
|
||||
// range-based for
|
||||
for (auto& element : j)
|
||||
{
|
||||
std::cout << element << '\n';
|
||||
}
|
||||
|
||||
// getter/setter
|
||||
const auto tmp = j[0].get<std::string>();
|
||||
j[1] = 42;
|
||||
bool foo{j.at(2)};
|
||||
CHECK(foo == true);
|
||||
|
||||
// other stuff
|
||||
j.size(); // 3 entries
|
||||
j.empty(); // false
|
||||
j.type(); // json::value_t::array
|
||||
j.clear(); // the array is empty again
|
||||
|
||||
// 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); // both entries for "one" are used
|
||||
// maybe ["one", "two", "one", "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;
|
||||
auto s2 = js.get<std::string>();
|
||||
|
||||
// Booleans
|
||||
bool b1 = true;
|
||||
json jb = b1;
|
||||
bool b2{jb};
|
||||
CHECK(b2 == true);
|
||||
|
||||
// numbers
|
||||
int i = 42;
|
||||
json jn = i;
|
||||
double f{jn};
|
||||
CHECK(f == 42);
|
||||
|
||||
// etc.
|
||||
|
||||
std::string vs = js.get<std::string>();
|
||||
bool vb = jb.get<bool>();
|
||||
CHECK(vb == true);
|
||||
int vi = jn.get<int>();
|
||||
CHECK(vi == 42);
|
||||
|
||||
// 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
|
||||
auto res = 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);
|
||||
}
|
||||
}
|
||||
|
||||
DOCTEST_MSVC_SUPPRESS_WARNING_POP
|
||||
@@ -0,0 +1,268 @@
|
||||
/*
|
||||
__ _____ _____ _____
|
||||
__| | __| | | | JSON for Modern C++ (test suite)
|
||||
| | |__ | | | | | | version 3.10.5
|
||||
|_____|_____|_____|_|___| https://github.com/nlohmann/json
|
||||
|
||||
Licensed under the MIT License <http://opensource.org/licenses/MIT>.
|
||||
SPDX-License-Identifier: MIT
|
||||
Copyright (c) 2013-2022 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 "doctest_compatibility.h"
|
||||
|
||||
#include <nlohmann/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
|
||||
auto& p1 = value.get_ref<test_type&>();
|
||||
CHECK(&p1 == value.get_ptr<test_type*>());
|
||||
CHECK(p1 == value.get<test_type>());
|
||||
|
||||
const auto& 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_WITH_AS(value.get_ref<json::array_t&>(),
|
||||
"[json.exception.type_error.303] incompatible ReferenceType for get_ref, actual type is object", json::type_error&);
|
||||
CHECK_THROWS_WITH_AS(value.get_ref<json::string_t&>(),
|
||||
"[json.exception.type_error.303] incompatible ReferenceType for get_ref, actual type is object", json::type_error&);
|
||||
CHECK_THROWS_WITH_AS(value.get_ref<json::boolean_t&>(),
|
||||
"[json.exception.type_error.303] incompatible ReferenceType for get_ref, actual type is object", json::type_error&);
|
||||
CHECK_THROWS_WITH_AS(value.get_ref<json::number_integer_t&>(),
|
||||
"[json.exception.type_error.303] incompatible ReferenceType for get_ref, actual type is object", json::type_error&);
|
||||
CHECK_THROWS_WITH_AS(value.get_ref<json::number_unsigned_t&>(),
|
||||
"[json.exception.type_error.303] incompatible ReferenceType for get_ref, actual type is object", json::type_error&);
|
||||
CHECK_THROWS_WITH_AS(value.get_ref<json::number_float_t&>(),
|
||||
"[json.exception.type_error.303] incompatible ReferenceType for get_ref, actual type is object", json::type_error&);
|
||||
}
|
||||
|
||||
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 auto& 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
|
||||
auto& p1 = value.get_ref<test_type&>();
|
||||
CHECK(&p1 == value.get_ptr<test_type*>());
|
||||
CHECK(p1 == value.get<test_type>());
|
||||
|
||||
const auto& 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_WITH_AS(value.get_ref<json::object_t&>(),
|
||||
"[json.exception.type_error.303] incompatible ReferenceType for get_ref, actual type is array", json::type_error&);
|
||||
CHECK_NOTHROW(value.get_ref<json::array_t&>());
|
||||
CHECK_THROWS_WITH_AS(value.get_ref<json::string_t&>(),
|
||||
"[json.exception.type_error.303] incompatible ReferenceType for get_ref, actual type is array", json::type_error&);
|
||||
CHECK_THROWS_WITH_AS(value.get_ref<json::boolean_t&>(),
|
||||
"[json.exception.type_error.303] incompatible ReferenceType for get_ref, actual type is array", json::type_error&);
|
||||
CHECK_THROWS_WITH_AS(value.get_ref<json::number_integer_t&>(),
|
||||
"[json.exception.type_error.303] incompatible ReferenceType for get_ref, actual type is array", json::type_error&);
|
||||
CHECK_THROWS_WITH_AS(value.get_ref<json::number_unsigned_t&>(),
|
||||
"[json.exception.type_error.303] incompatible ReferenceType for get_ref, actual type is array", json::type_error&);
|
||||
CHECK_THROWS_WITH_AS(value.get_ref<json::number_float_t&>(),
|
||||
"[json.exception.type_error.303] incompatible ReferenceType for get_ref, actual type is array", json::type_error&);
|
||||
}
|
||||
|
||||
SECTION("reference access to string_t")
|
||||
{
|
||||
using test_type = json::string_t;
|
||||
json value = "hello";
|
||||
|
||||
// check if references are returned correctly
|
||||
auto& p1 = value.get_ref<test_type&>();
|
||||
CHECK(&p1 == value.get_ptr<test_type*>());
|
||||
CHECK(p1 == value.get<test_type>());
|
||||
|
||||
const auto& 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_WITH_AS(value.get_ref<json::object_t&>(),
|
||||
"[json.exception.type_error.303] incompatible ReferenceType for get_ref, actual type is string", json::type_error&);
|
||||
CHECK_THROWS_WITH_AS(value.get_ref<json::array_t&>(),
|
||||
"[json.exception.type_error.303] incompatible ReferenceType for get_ref, actual type is string", json::type_error&);
|
||||
CHECK_NOTHROW(value.get_ref<json::string_t&>());
|
||||
CHECK_THROWS_WITH_AS(value.get_ref<json::boolean_t&>(),
|
||||
"[json.exception.type_error.303] incompatible ReferenceType for get_ref, actual type is string", json::type_error&);
|
||||
CHECK_THROWS_WITH_AS(value.get_ref<json::number_integer_t&>(),
|
||||
"[json.exception.type_error.303] incompatible ReferenceType for get_ref, actual type is string", json::type_error&);
|
||||
CHECK_THROWS_WITH_AS(value.get_ref<json::number_unsigned_t&>(),
|
||||
"[json.exception.type_error.303] incompatible ReferenceType for get_ref, actual type is string", json::type_error&);
|
||||
CHECK_THROWS_WITH_AS(value.get_ref<json::number_float_t&>(),
|
||||
"[json.exception.type_error.303] incompatible ReferenceType for get_ref, actual type is string", json::type_error&);
|
||||
}
|
||||
|
||||
SECTION("reference access to boolean_t")
|
||||
{
|
||||
using test_type = json::boolean_t;
|
||||
json value = false;
|
||||
|
||||
// check if references are returned correctly
|
||||
auto& p1 = value.get_ref<test_type&>();
|
||||
CHECK(&p1 == value.get_ptr<test_type*>());
|
||||
CHECK(p1 == value.get<test_type>());
|
||||
|
||||
const auto& 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_WITH_AS(value.get_ref<json::object_t&>(),
|
||||
"[json.exception.type_error.303] incompatible ReferenceType for get_ref, actual type is boolean", json::type_error&);
|
||||
CHECK_THROWS_WITH_AS(value.get_ref<json::array_t&>(),
|
||||
"[json.exception.type_error.303] incompatible ReferenceType for get_ref, actual type is boolean", json::type_error&);
|
||||
CHECK_THROWS_WITH_AS(value.get_ref<json::string_t&>(),
|
||||
"[json.exception.type_error.303] incompatible ReferenceType for get_ref, actual type is boolean", json::type_error&);
|
||||
CHECK_NOTHROW(value.get_ref<json::boolean_t&>());
|
||||
CHECK_THROWS_WITH_AS(value.get_ref<json::number_integer_t&>(),
|
||||
"[json.exception.type_error.303] incompatible ReferenceType for get_ref, actual type is boolean", json::type_error&);
|
||||
CHECK_THROWS_WITH_AS(value.get_ref<json::number_unsigned_t&>(),
|
||||
"[json.exception.type_error.303] incompatible ReferenceType for get_ref, actual type is boolean", json::type_error&);
|
||||
CHECK_THROWS_WITH_AS(value.get_ref<json::number_float_t&>(),
|
||||
"[json.exception.type_error.303] incompatible ReferenceType for get_ref, actual type is boolean", json::type_error&);
|
||||
}
|
||||
|
||||
SECTION("reference access to number_integer_t")
|
||||
{
|
||||
using test_type = json::number_integer_t;
|
||||
json value = -23;
|
||||
|
||||
// check if references are returned correctly
|
||||
auto& p1 = value.get_ref<test_type&>();
|
||||
CHECK(&p1 == value.get_ptr<test_type*>());
|
||||
CHECK(p1 == value.get<test_type>());
|
||||
|
||||
const auto& 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_WITH_AS(value.get_ref<json::object_t&>(),
|
||||
"[json.exception.type_error.303] incompatible ReferenceType for get_ref, actual type is number", json::type_error&);
|
||||
CHECK_THROWS_WITH_AS(value.get_ref<json::array_t&>(),
|
||||
"[json.exception.type_error.303] incompatible ReferenceType for get_ref, actual type is number", json::type_error&);
|
||||
CHECK_THROWS_WITH_AS(value.get_ref<json::string_t&>(),
|
||||
"[json.exception.type_error.303] incompatible ReferenceType for get_ref, actual type is number", json::type_error&);
|
||||
CHECK_THROWS_WITH_AS(value.get_ref<json::boolean_t&>(),
|
||||
"[json.exception.type_error.303] incompatible ReferenceType for get_ref, actual type is number", json::type_error&);
|
||||
CHECK_NOTHROW(value.get_ref<json::number_integer_t&>());
|
||||
CHECK_THROWS_WITH_AS(value.get_ref<json::number_unsigned_t&>(),
|
||||
"[json.exception.type_error.303] incompatible ReferenceType for get_ref, actual type is number", json::type_error&);
|
||||
CHECK_THROWS_WITH_AS(value.get_ref<json::number_float_t&>(),
|
||||
"[json.exception.type_error.303] incompatible ReferenceType for get_ref, actual type is number", json::type_error&);
|
||||
}
|
||||
|
||||
SECTION("reference access to number_unsigned_t")
|
||||
{
|
||||
using test_type = json::number_unsigned_t;
|
||||
json value = 23u;
|
||||
|
||||
// check if references are returned correctly
|
||||
auto& p1 = value.get_ref<test_type&>();
|
||||
CHECK(&p1 == value.get_ptr<test_type*>());
|
||||
CHECK(p1 == value.get<test_type>());
|
||||
|
||||
const auto& 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_WITH_AS(value.get_ref<json::object_t&>(),
|
||||
"[json.exception.type_error.303] incompatible ReferenceType for get_ref, actual type is number", json::type_error&);
|
||||
CHECK_THROWS_WITH_AS(value.get_ref<json::array_t&>(),
|
||||
"[json.exception.type_error.303] incompatible ReferenceType for get_ref, actual type is number", json::type_error&);
|
||||
CHECK_THROWS_WITH_AS(value.get_ref<json::string_t&>(),
|
||||
"[json.exception.type_error.303] incompatible ReferenceType for get_ref, actual type is number", json::type_error&);
|
||||
CHECK_THROWS_WITH_AS(value.get_ref<json::boolean_t&>(),
|
||||
"[json.exception.type_error.303] incompatible ReferenceType for get_ref, actual type is number", json::type_error&);
|
||||
//CHECK_THROWS_WITH_AS(value.get_ref<json::number_integer_t&>(),
|
||||
// "[json.exception.type_error.303] incompatible ReferenceType for get_ref, actual type is number", json::type_error&);
|
||||
CHECK_NOTHROW(value.get_ref<json::number_unsigned_t&>());
|
||||
CHECK_THROWS_WITH_AS(value.get_ref<json::number_float_t&>(), "[json.exception.type_error.303] incompatible ReferenceType for get_ref, actual type is number", json::type_error&);
|
||||
}
|
||||
|
||||
SECTION("reference access to number_float_t")
|
||||
{
|
||||
using test_type = json::number_float_t;
|
||||
json value = 42.23;
|
||||
|
||||
// check if references are returned correctly
|
||||
auto& p1 = value.get_ref<test_type&>();
|
||||
CHECK(&p1 == value.get_ptr<test_type*>());
|
||||
CHECK(p1 == value.get<test_type>());
|
||||
|
||||
const auto& 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_WITH_AS(value.get_ref<json::object_t&>(), "[json.exception.type_error.303] incompatible ReferenceType for get_ref, actual type is number", json::type_error&);
|
||||
CHECK_THROWS_WITH_AS(value.get_ref<json::array_t&>(), "[json.exception.type_error.303] incompatible ReferenceType for get_ref, actual type is number", json::type_error&);
|
||||
CHECK_THROWS_WITH_AS(value.get_ref<json::string_t&>(), "[json.exception.type_error.303] incompatible ReferenceType for get_ref, actual type is number", json::type_error&);
|
||||
CHECK_THROWS_WITH_AS(value.get_ref<json::boolean_t&>(), "[json.exception.type_error.303] incompatible ReferenceType for get_ref, actual type is number", json::type_error&);
|
||||
CHECK_THROWS_WITH_AS(value.get_ref<json::number_integer_t&>(), "[json.exception.type_error.303] incompatible ReferenceType for get_ref, actual type is number", json::type_error&);
|
||||
CHECK_THROWS_WITH_AS(value.get_ref<json::number_unsigned_t&>(), "[json.exception.type_error.303] incompatible ReferenceType for get_ref, actual type is number", json::type_error&);
|
||||
CHECK_NOTHROW(value.get_ref<json::number_float_t&>());
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,878 @@
|
||||
/*
|
||||
__ _____ _____ _____
|
||||
__| | __| | | | JSON for Modern C++ (test suite)
|
||||
| | |__ | | | | | | version 3.10.5
|
||||
|_____|_____|_____|_|___| https://github.com/nlohmann/json
|
||||
|
||||
Licensed under the MIT License <http://opensource.org/licenses/MIT>.
|
||||
SPDX-License-Identifier: MIT
|
||||
Copyright (c) 2013-2022 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 "doctest_compatibility.h"
|
||||
|
||||
// for some reason including this after the json header leads to linker errors with VS 2017...
|
||||
#include <locale>
|
||||
|
||||
#define JSON_TESTS_PRIVATE
|
||||
#include <nlohmann/json.hpp>
|
||||
using json = nlohmann::json;
|
||||
using ordered_json = nlohmann::ordered_json;
|
||||
|
||||
#include <cstdio>
|
||||
#include <list>
|
||||
#include <type_traits>
|
||||
#include <utility>
|
||||
|
||||
#ifdef JSON_HAS_CPP_17
|
||||
#include <any>
|
||||
#include <variant>
|
||||
#endif
|
||||
|
||||
#if JSON_HAS_EXPERIMENTAL_FILESYSTEM
|
||||
// JSON_HAS_CPP_17 (magic keyword; do not remove)
|
||||
#include <experimental/filesystem>
|
||||
namespace nlohmann::detail
|
||||
{
|
||||
namespace std_fs = std::experimental::filesystem;
|
||||
} // namespace nlohmann::detail
|
||||
#elif JSON_HAS_FILESYSTEM
|
||||
#include <filesystem>
|
||||
namespace nlohmann::detail
|
||||
{
|
||||
namespace std_fs = std::filesystem;
|
||||
} // namespace nlohmann::detail
|
||||
#endif
|
||||
|
||||
#ifdef JSON_HAS_CPP_20
|
||||
#include <span>
|
||||
#endif
|
||||
|
||||
// NLOHMANN_JSON_SERIALIZE_ENUM uses a static std::pair
|
||||
DOCTEST_CLANG_SUPPRESS_WARNING_PUSH
|
||||
DOCTEST_CLANG_SUPPRESS_WARNING("-Wexit-time-destructors")
|
||||
|
||||
/////////////////////////////////////////////////////////////////////
|
||||
// for #1021
|
||||
/////////////////////////////////////////////////////////////////////
|
||||
|
||||
using float_json = nlohmann::basic_json<std::map, std::vector, std::string, bool, std::int64_t, std::uint64_t, float>;
|
||||
|
||||
/////////////////////////////////////////////////////////////////////
|
||||
// for #1647
|
||||
/////////////////////////////////////////////////////////////////////
|
||||
namespace
|
||||
{
|
||||
struct NonDefaultFromJsonStruct
|
||||
{};
|
||||
|
||||
inline bool operator==(NonDefaultFromJsonStruct const& /*unused*/, NonDefaultFromJsonStruct const& /*unused*/)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
enum class for_1647
|
||||
{
|
||||
one,
|
||||
two
|
||||
};
|
||||
|
||||
// NOLINTNEXTLINE(cppcoreguidelines-avoid-c-arrays,hicpp-avoid-c-arrays,modernize-avoid-c-arrays): this is a false positive
|
||||
NLOHMANN_JSON_SERIALIZE_ENUM(for_1647,
|
||||
{
|
||||
{for_1647::one, "one"},
|
||||
{for_1647::two, "two"},
|
||||
})
|
||||
} // namespace
|
||||
|
||||
/////////////////////////////////////////////////////////////////////
|
||||
// for #1299
|
||||
/////////////////////////////////////////////////////////////////////
|
||||
|
||||
struct Data
|
||||
{
|
||||
Data() = default;
|
||||
Data(std::string a_, std::string b_)
|
||||
: a(std::move(a_))
|
||||
, b(std::move(b_))
|
||||
{}
|
||||
std::string a{};
|
||||
std::string b{};
|
||||
};
|
||||
|
||||
void from_json(const json& j, Data& data);
|
||||
void from_json(const json& j, Data& data)
|
||||
{
|
||||
j["a"].get_to(data.a);
|
||||
j["b"].get_to(data.b);
|
||||
}
|
||||
|
||||
bool operator==(Data const& lhs, Data const& rhs);
|
||||
bool operator==(Data const& lhs, Data const& rhs)
|
||||
{
|
||||
return lhs.a == rhs.a && lhs.b == rhs.b;
|
||||
}
|
||||
|
||||
//bool operator!=(Data const& lhs, Data const& rhs)
|
||||
//{
|
||||
// return !(lhs == rhs);
|
||||
//}
|
||||
|
||||
namespace nlohmann
|
||||
{
|
||||
template<>
|
||||
struct adl_serializer<NonDefaultFromJsonStruct>
|
||||
{
|
||||
static NonDefaultFromJsonStruct from_json(json const& /*unused*/) noexcept
|
||||
{
|
||||
return {};
|
||||
}
|
||||
};
|
||||
} // namespace nlohmann
|
||||
|
||||
/////////////////////////////////////////////////////////////////////
|
||||
// for #1805
|
||||
/////////////////////////////////////////////////////////////////////
|
||||
|
||||
struct NotSerializableData
|
||||
{
|
||||
int mydata;
|
||||
float myfloat;
|
||||
};
|
||||
|
||||
/////////////////////////////////////////////////////////////////////
|
||||
// for #2574
|
||||
/////////////////////////////////////////////////////////////////////
|
||||
|
||||
struct NonDefaultConstructible
|
||||
{
|
||||
explicit NonDefaultConstructible(int a)
|
||||
: x(a)
|
||||
{}
|
||||
int x;
|
||||
};
|
||||
|
||||
namespace nlohmann
|
||||
{
|
||||
template<>
|
||||
struct adl_serializer<NonDefaultConstructible>
|
||||
{
|
||||
static NonDefaultConstructible from_json(json const& j)
|
||||
{
|
||||
return NonDefaultConstructible(j.get<int>());
|
||||
}
|
||||
};
|
||||
} // namespace nlohmann
|
||||
|
||||
/////////////////////////////////////////////////////////////////////
|
||||
// for #2824
|
||||
/////////////////////////////////////////////////////////////////////
|
||||
|
||||
class sax_no_exception : public nlohmann::detail::json_sax_dom_parser<json>
|
||||
{
|
||||
public:
|
||||
explicit sax_no_exception(json& j)
|
||||
: nlohmann::detail::json_sax_dom_parser<json>(j, false)
|
||||
{}
|
||||
|
||||
static bool parse_error(std::size_t /*position*/, const std::string& /*last_token*/, const json::exception& ex)
|
||||
{
|
||||
error_string = new std::string(ex.what()); // NOLINT(cppcoreguidelines-owning-memory)
|
||||
return false;
|
||||
}
|
||||
|
||||
static std::string* error_string;
|
||||
};
|
||||
|
||||
std::string* sax_no_exception::error_string = nullptr;
|
||||
|
||||
/////////////////////////////////////////////////////////////////////
|
||||
// for #2982
|
||||
/////////////////////////////////////////////////////////////////////
|
||||
|
||||
template<class T>
|
||||
class my_allocator : public std::allocator<T>
|
||||
{
|
||||
public:
|
||||
using std::allocator<T>::allocator;
|
||||
};
|
||||
|
||||
/////////////////////////////////////////////////////////////////////
|
||||
// for #3077
|
||||
/////////////////////////////////////////////////////////////////////
|
||||
|
||||
class FooAlloc
|
||||
{};
|
||||
|
||||
class Foo
|
||||
{
|
||||
public:
|
||||
explicit Foo(const FooAlloc& /* unused */ = FooAlloc()) {}
|
||||
|
||||
bool value = false;
|
||||
};
|
||||
|
||||
class FooBar
|
||||
{
|
||||
public:
|
||||
Foo foo{};
|
||||
};
|
||||
|
||||
inline void from_json(const nlohmann::json& j, FooBar& fb)
|
||||
{
|
||||
j.at("value").get_to(fb.foo.value);
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////////
|
||||
// for #3171
|
||||
/////////////////////////////////////////////////////////////////////
|
||||
|
||||
struct for_3171_base // NOLINT(cppcoreguidelines-special-member-functions)
|
||||
{
|
||||
for_3171_base(const std::string& /*unused*/ = {}) {}
|
||||
virtual ~for_3171_base() = default;
|
||||
|
||||
virtual void _from_json(const json& j)
|
||||
{
|
||||
j.at("str").get_to(str);
|
||||
}
|
||||
|
||||
std::string str{};
|
||||
};
|
||||
|
||||
struct for_3171_derived : public for_3171_base
|
||||
{
|
||||
for_3171_derived() = default;
|
||||
explicit for_3171_derived(const std::string& /*unused*/) { }
|
||||
};
|
||||
|
||||
inline void from_json(const json& j, for_3171_base& tb)
|
||||
{
|
||||
tb._from_json(j);
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////////
|
||||
// for #3312
|
||||
/////////////////////////////////////////////////////////////////////
|
||||
|
||||
#ifdef JSON_HAS_CPP_20
|
||||
struct for_3312
|
||||
{
|
||||
std::string name;
|
||||
};
|
||||
|
||||
inline void from_json(const json& j, for_3312& obj)
|
||||
{
|
||||
j.at("name").get_to(obj.name);
|
||||
}
|
||||
#endif
|
||||
|
||||
TEST_CASE("regression tests 2")
|
||||
{
|
||||
SECTION("issue #1001 - Fix memory leak during parser callback")
|
||||
{
|
||||
const auto* geojsonExample = R"(
|
||||
{ "type": "FeatureCollection",
|
||||
"features": [
|
||||
{ "type": "Feature",
|
||||
"geometry": {"type": "Point", "coordinates": [102.0, 0.5]},
|
||||
"properties": {"prop0": "value0"}
|
||||
},
|
||||
{ "type": "Feature",
|
||||
"geometry": {
|
||||
"type": "LineString",
|
||||
"coordinates": [
|
||||
[102.0, 0.0], [103.0, 1.0], [104.0, 0.0], [105.0, 1.0]
|
||||
]
|
||||
},
|
||||
"properties": {
|
||||
"prop0": "value0",
|
||||
"prop1": 0.0
|
||||
}
|
||||
},
|
||||
{ "type": "Feature",
|
||||
"geometry": {
|
||||
"type": "Polygon",
|
||||
"coordinates": [
|
||||
[ [100.0, 0.0], [101.0, 0.0], [101.0, 1.0],
|
||||
[100.0, 1.0], [100.0, 0.0] ]
|
||||
]
|
||||
},
|
||||
"properties": {
|
||||
"prop0": "value0",
|
||||
"prop1": {"this": "that"}
|
||||
}
|
||||
}
|
||||
]
|
||||
})";
|
||||
|
||||
json::parser_callback_t cb = [&](int /*level*/, json::parse_event_t event, json & parsed) noexcept
|
||||
{
|
||||
// skip uninteresting events
|
||||
if (event == json::parse_event_t::value && !parsed.is_primitive())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
switch (event)
|
||||
{
|
||||
case json::parse_event_t::key:
|
||||
{
|
||||
return true;
|
||||
}
|
||||
case json::parse_event_t::value:
|
||||
{
|
||||
return false;
|
||||
}
|
||||
case json::parse_event_t::object_start:
|
||||
{
|
||||
return true;
|
||||
}
|
||||
case json::parse_event_t::object_end:
|
||||
{
|
||||
return false;
|
||||
}
|
||||
case json::parse_event_t::array_start:
|
||||
{
|
||||
return true;
|
||||
}
|
||||
case json::parse_event_t::array_end:
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
default:
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
auto j = json::parse(geojsonExample, cb, true);
|
||||
CHECK(j == json());
|
||||
}
|
||||
|
||||
SECTION("issue #1021 - to/from_msgpack only works with standard typization")
|
||||
{
|
||||
float_json j = 1000.0;
|
||||
CHECK(float_json::from_cbor(float_json::to_cbor(j)) == j);
|
||||
CHECK(float_json::from_msgpack(float_json::to_msgpack(j)) == j);
|
||||
CHECK(float_json::from_ubjson(float_json::to_ubjson(j)) == j);
|
||||
|
||||
float_json j2 = {1000.0, 2000.0, 3000.0};
|
||||
CHECK(float_json::from_ubjson(float_json::to_ubjson(j2, true, true)) == j2);
|
||||
}
|
||||
|
||||
SECTION("issue #1045 - Using STL algorithms with JSON containers with expected results?")
|
||||
{
|
||||
json diffs = nlohmann::json::array();
|
||||
json m1{{"key1", 42}};
|
||||
json m2{{"key2", 42}};
|
||||
auto p1 = m1.items();
|
||||
auto p2 = m2.items();
|
||||
|
||||
using it_type = decltype(p1.begin());
|
||||
|
||||
std::set_difference(
|
||||
p1.begin(),
|
||||
p1.end(),
|
||||
p2.begin(),
|
||||
p2.end(),
|
||||
std::inserter(diffs, diffs.end()),
|
||||
[&](const it_type & e1, const it_type & e2) -> bool
|
||||
{
|
||||
using comper_pair = std::pair<std::string, decltype(e1.value())>; // Trying to avoid unneeded copy
|
||||
return comper_pair(e1.key(), e1.value()) < comper_pair(e2.key(), e2.value()); // Using pair comper
|
||||
});
|
||||
|
||||
CHECK(diffs.size() == 1); // Note the change here, was 2
|
||||
}
|
||||
|
||||
#ifdef JSON_HAS_CPP_17
|
||||
SECTION("issue #1292 - Serializing std::variant causes stack overflow")
|
||||
{
|
||||
static_assert(!std::is_constructible<json, std::variant<int, float>>::value, "unexpected value");
|
||||
}
|
||||
#endif
|
||||
|
||||
SECTION("issue #1299 - compile error in from_json converting to container "
|
||||
"with std::pair")
|
||||
{
|
||||
json j =
|
||||
{
|
||||
{"1", {{"a", "testa_1"}, {"b", "testb_1"}}},
|
||||
{"2", {{"a", "testa_2"}, {"b", "testb_2"}}},
|
||||
{"3", {{"a", "testa_3"}, {"b", "testb_3"}}},
|
||||
};
|
||||
|
||||
std::map<std::string, Data> expected
|
||||
{
|
||||
{"1", {"testa_1", "testb_1"}},
|
||||
{"2", {"testa_2", "testb_2"}},
|
||||
{"3", {"testa_3", "testb_3"}},
|
||||
};
|
||||
const auto data = j.get<decltype(expected)>();
|
||||
CHECK(expected == data);
|
||||
}
|
||||
|
||||
SECTION("issue #1445 - buffer overflow in dumping invalid utf-8 strings")
|
||||
{
|
||||
SECTION("a bunch of -1, ensure_ascii=true")
|
||||
{
|
||||
const auto length = 300;
|
||||
|
||||
json dump_test;
|
||||
dump_test["1"] = std::string(length, -1);
|
||||
|
||||
std::string expected = R"({"1":")";
|
||||
for (int i = 0; i < length; ++i)
|
||||
{
|
||||
expected += "\\ufffd";
|
||||
}
|
||||
expected += "\"}";
|
||||
|
||||
auto s = dump_test.dump(-1, ' ', true, nlohmann::json::error_handler_t::replace);
|
||||
CHECK(s == expected);
|
||||
}
|
||||
SECTION("a bunch of -2, ensure_ascii=false")
|
||||
{
|
||||
const auto length = 500;
|
||||
|
||||
json dump_test;
|
||||
dump_test["1"] = std::string(length, -2);
|
||||
|
||||
std::string expected = R"({"1":")";
|
||||
for (int i = 0; i < length; ++i)
|
||||
{
|
||||
expected += "\xEF\xBF\xBD";
|
||||
}
|
||||
expected += "\"}";
|
||||
|
||||
auto s = dump_test.dump(-1, ' ', false, nlohmann::json::error_handler_t::replace);
|
||||
CHECK(s == expected);
|
||||
}
|
||||
SECTION("test case in issue #1445")
|
||||
{
|
||||
nlohmann::json dump_test;
|
||||
const std::array<int, 108> data =
|
||||
{
|
||||
{109, 108, 103, 125, -122, -53, 115, 18, 3, 0, 102, 19, 1, 15, -110, 13, -3, -1, -81, 32, 2, 0, 0, 0, 0, 0, 0, 0, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -80, 2, 0, 0, 96, -118, 46, -116, 46, 109, -84, -87, 108, 14, 109, -24, -83, 13, -18, -51, -83, -52, -115, 14, 6, 32, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 64, 3, 0, 0, 0, 35, -74, -73, 55, 57, -128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 33, 0, 0, 0, -96, -54, -28, -26}
|
||||
};
|
||||
std::string s;
|
||||
for (int i : data)
|
||||
{
|
||||
s += static_cast<char>(i);
|
||||
}
|
||||
dump_test["1"] = s;
|
||||
dump_test.dump(-1, ' ', true, nlohmann::json::error_handler_t::replace);
|
||||
}
|
||||
}
|
||||
|
||||
SECTION("issue #1447 - Integer Overflow (OSS-Fuzz 12506)")
|
||||
{
|
||||
json j = json::parse("[-9223372036854775808]");
|
||||
CHECK(j.dump() == "[-9223372036854775808]");
|
||||
}
|
||||
|
||||
SECTION("issue #1708 - minimum value of int64_t can be outputted")
|
||||
{
|
||||
constexpr auto smallest = (std::numeric_limits<int64_t>::min)();
|
||||
json j = smallest;
|
||||
CHECK(j.dump() == std::to_string(smallest));
|
||||
}
|
||||
|
||||
SECTION("issue #1727 - Contains with non-const lvalue json_pointer picks the wrong overload")
|
||||
{
|
||||
json j = {{"root", {{"settings", {{"logging", true}}}}}};
|
||||
|
||||
auto jptr1 = "/root/settings/logging"_json_pointer;
|
||||
auto jptr2 = json::json_pointer{"/root/settings/logging"};
|
||||
|
||||
CHECK(j.contains(jptr1));
|
||||
CHECK(j.contains(jptr2));
|
||||
}
|
||||
|
||||
SECTION("issue #1647 - compile error when deserializing enum if both non-default from_json and non-member operator== exists for other type")
|
||||
{
|
||||
{
|
||||
json j;
|
||||
NonDefaultFromJsonStruct x(j);
|
||||
NonDefaultFromJsonStruct y;
|
||||
CHECK(x == y);
|
||||
}
|
||||
|
||||
auto val = nlohmann::json("one").get<for_1647>();
|
||||
CHECK(val == for_1647::one);
|
||||
json j = val;
|
||||
}
|
||||
|
||||
SECTION("issue #1715 - json::from_cbor does not respect allow_exceptions = false when input is string literal")
|
||||
{
|
||||
SECTION("string literal")
|
||||
{
|
||||
json cbor = json::from_cbor("B", true, false);
|
||||
CHECK(cbor.is_discarded());
|
||||
}
|
||||
|
||||
SECTION("string array")
|
||||
{
|
||||
const std::array<char, 2> input = {{'B', 0x00}};
|
||||
json cbor = json::from_cbor(input, true, false);
|
||||
CHECK(cbor.is_discarded());
|
||||
}
|
||||
|
||||
SECTION("std::string")
|
||||
{
|
||||
json cbor = json::from_cbor(std::string("B"), true, false);
|
||||
CHECK(cbor.is_discarded());
|
||||
}
|
||||
}
|
||||
|
||||
SECTION("issue #1805 - A pair<T1, T2> is json constructible only if T1 and T2 are json constructible")
|
||||
{
|
||||
static_assert(!std::is_constructible<json, std::pair<std::string, NotSerializableData>>::value, "unexpected result");
|
||||
static_assert(!std::is_constructible<json, std::pair<NotSerializableData, std::string>>::value, "unexpected result");
|
||||
static_assert(std::is_constructible<json, std::pair<int, std::string>>::value, "unexpected result");
|
||||
}
|
||||
SECTION("issue #1825 - A tuple<Args..> is json constructible only if all T in Args are json constructible")
|
||||
{
|
||||
static_assert(!std::is_constructible<json, std::tuple<std::string, NotSerializableData>>::value, "unexpected result");
|
||||
static_assert(!std::is_constructible<json, std::tuple<NotSerializableData, std::string>>::value, "unexpected result");
|
||||
static_assert(std::is_constructible<json, std::tuple<int, std::string>>::value, "unexpected result");
|
||||
}
|
||||
|
||||
SECTION("issue #1983 - JSON patch diff for op=add formation is not as per standard (RFC 6902)")
|
||||
{
|
||||
const auto source = R"({ "foo": [ "1", "2" ] })"_json;
|
||||
const auto target = R"({"foo": [ "1", "2", "3" ]})"_json;
|
||||
const auto result = json::diff(source, target);
|
||||
CHECK(result.dump() == R"([{"op":"add","path":"/foo/-","value":"3"}])");
|
||||
}
|
||||
|
||||
SECTION("issue #2067 - cannot serialize binary data to text JSON")
|
||||
{
|
||||
const std::array<unsigned char, 23> data = {{0x81, 0xA4, 0x64, 0x61, 0x74, 0x61, 0xC4, 0x0F, 0x33, 0x30, 0x30, 0x32, 0x33, 0x34, 0x30, 0x31, 0x30, 0x37, 0x30, 0x35, 0x30, 0x31, 0x30}};
|
||||
json j = json::from_msgpack(data.data(), data.size());
|
||||
CHECK_NOTHROW(
|
||||
j.dump(4, // Indent
|
||||
' ', // Indent char
|
||||
false, // Ensure ascii
|
||||
json::error_handler_t::strict // Error
|
||||
));
|
||||
}
|
||||
|
||||
SECTION("PR #2181 - regression bug with lvalue")
|
||||
{
|
||||
// see https://github.com/nlohmann/json/pull/2181#issuecomment-653326060
|
||||
json j{{"x", "test"}};
|
||||
std::string defval = "default value";
|
||||
auto val = j.value("x", defval);
|
||||
auto val2 = j.value("y", defval);
|
||||
}
|
||||
|
||||
SECTION("issue #2293 - eof doesn't cause parsing to stop")
|
||||
{
|
||||
std::vector<uint8_t> data =
|
||||
{
|
||||
0x7B,
|
||||
0x6F,
|
||||
0x62,
|
||||
0x6A,
|
||||
0x65,
|
||||
0x63,
|
||||
0x74,
|
||||
0x20,
|
||||
0x4F,
|
||||
0x42
|
||||
};
|
||||
json result = json::from_cbor(data, true, false);
|
||||
CHECK(result.is_discarded());
|
||||
}
|
||||
|
||||
SECTION("issue #2315 - json.update and vector<pair>does not work with ordered_json")
|
||||
{
|
||||
nlohmann::ordered_json jsonAnimals = {{"animal", "dog"}};
|
||||
nlohmann::ordered_json jsonCat = {{"animal", "cat"}};
|
||||
jsonAnimals.update(jsonCat);
|
||||
CHECK(jsonAnimals["animal"] == "cat");
|
||||
|
||||
auto jsonAnimals_parsed = nlohmann::ordered_json::parse(jsonAnimals.dump());
|
||||
CHECK(jsonAnimals == jsonAnimals_parsed);
|
||||
|
||||
std::vector<std::pair<std::string, int64_t>> intData = {std::make_pair("aaaa", 11),
|
||||
std::make_pair("bbb", 222)
|
||||
};
|
||||
nlohmann::ordered_json jsonObj;
|
||||
for (const auto& data : intData)
|
||||
{
|
||||
jsonObj[data.first] = data.second;
|
||||
}
|
||||
CHECK(jsonObj["aaaa"] == 11);
|
||||
CHECK(jsonObj["bbb"] == 222);
|
||||
}
|
||||
|
||||
SECTION("issue #2330 - ignore_comment=true fails on multiple consecutive lines starting with comments")
|
||||
{
|
||||
std::string ss = "//\n//\n{\n}\n";
|
||||
json j = json::parse(ss, nullptr, true, true);
|
||||
CHECK(j.dump() == "{}");
|
||||
}
|
||||
|
||||
#ifdef JSON_HAS_CPP_20
|
||||
SECTION("issue #2546 - parsing containers of std::byte")
|
||||
{
|
||||
const char DATA[] = R"("Hello, world!")"; // NOLINT(cppcoreguidelines-avoid-c-arrays,hicpp-avoid-c-arrays,modernize-avoid-c-arrays)
|
||||
const auto s = std::as_bytes(std::span(DATA));
|
||||
json j = json::parse(s);
|
||||
CHECK(j.dump() == "\"Hello, world!\"");
|
||||
}
|
||||
#endif
|
||||
|
||||
SECTION("issue #2574 - Deserialization to std::array, std::pair, and std::tuple with non-default constructable types fails")
|
||||
{
|
||||
SECTION("std::array")
|
||||
{
|
||||
{
|
||||
json j = {7, 4};
|
||||
auto arr = j.get<std::array<NonDefaultConstructible, 2>>();
|
||||
CHECK(arr[0].x == 7);
|
||||
CHECK(arr[1].x == 4);
|
||||
}
|
||||
|
||||
{
|
||||
json j = 7;
|
||||
CHECK_THROWS_AS((j.get<std::array<NonDefaultConstructible, 1>>()), json::type_error);
|
||||
}
|
||||
}
|
||||
|
||||
SECTION("std::pair")
|
||||
{
|
||||
{
|
||||
json j = {3, 8};
|
||||
auto p = j.get<std::pair<NonDefaultConstructible, NonDefaultConstructible>>();
|
||||
CHECK(p.first.x == 3);
|
||||
CHECK(p.second.x == 8);
|
||||
}
|
||||
|
||||
{
|
||||
json j = {4, 1};
|
||||
auto p = j.get<std::pair<int, NonDefaultConstructible>>();
|
||||
CHECK(p.first == 4);
|
||||
CHECK(p.second.x == 1);
|
||||
}
|
||||
|
||||
{
|
||||
json j = {6, 7};
|
||||
auto p = j.get<std::pair<NonDefaultConstructible, int>>();
|
||||
CHECK(p.first.x == 6);
|
||||
CHECK(p.second == 7);
|
||||
}
|
||||
|
||||
{
|
||||
json j = 7;
|
||||
CHECK_THROWS_AS((j.get<std::pair<NonDefaultConstructible, int>>()), json::type_error);
|
||||
}
|
||||
}
|
||||
|
||||
SECTION("std::tuple")
|
||||
{
|
||||
{
|
||||
json j = {9};
|
||||
auto t = j.get<std::tuple<NonDefaultConstructible>>();
|
||||
CHECK(std::get<0>(t).x == 9);
|
||||
}
|
||||
|
||||
{
|
||||
json j = {9, 8, 7};
|
||||
auto t = j.get<std::tuple<NonDefaultConstructible, int, NonDefaultConstructible>>();
|
||||
CHECK(std::get<0>(t).x == 9);
|
||||
CHECK(std::get<1>(t) == 8);
|
||||
CHECK(std::get<2>(t).x == 7);
|
||||
}
|
||||
|
||||
{
|
||||
json j = 7;
|
||||
CHECK_THROWS_AS((j.get<std::tuple<NonDefaultConstructible>>()), json::type_error);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
SECTION("issue #2865 - ASAN detects memory leaks")
|
||||
{
|
||||
// the code below is expected to not leak memory
|
||||
{
|
||||
nlohmann::json o;
|
||||
std::string s = "bar";
|
||||
|
||||
nlohmann::to_json(o["foo"], s);
|
||||
|
||||
nlohmann::json p = o;
|
||||
|
||||
// call to_json with a non-null JSON value
|
||||
nlohmann::to_json(p["foo"], s);
|
||||
}
|
||||
|
||||
{
|
||||
nlohmann::json o;
|
||||
std::string s = "bar";
|
||||
|
||||
nlohmann::to_json(o["foo"], s);
|
||||
|
||||
// call to_json with a non-null JSON value
|
||||
nlohmann::to_json(o["foo"], s);
|
||||
}
|
||||
}
|
||||
|
||||
SECTION("issue #2824 - encoding of json::exception::what()")
|
||||
{
|
||||
json j;
|
||||
sax_no_exception sax(j);
|
||||
|
||||
CHECK(!json::sax_parse("xyz", &sax));
|
||||
CHECK(*sax_no_exception::error_string == "[json.exception.parse_error.101] parse error at line 1, column 1: syntax error while parsing value - invalid literal; last read: 'x'");
|
||||
delete sax_no_exception::error_string; // NOLINT(cppcoreguidelines-owning-memory)
|
||||
}
|
||||
|
||||
SECTION("issue #2825 - Properly constrain the basic_json conversion operator")
|
||||
{
|
||||
static_assert(std::is_copy_assignable<nlohmann::ordered_json>::value, "ordered_json must be copy assignable");
|
||||
}
|
||||
|
||||
SECTION("issue #2958 - Inserting in unordered json using a pointer retains the leading slash")
|
||||
{
|
||||
std::string p = "/root";
|
||||
|
||||
json test1;
|
||||
test1[json::json_pointer(p)] = json::object();
|
||||
CHECK(test1.dump() == "{\"root\":{}}");
|
||||
|
||||
ordered_json test2;
|
||||
test2[ordered_json::json_pointer(p)] = json::object();
|
||||
CHECK(test2.dump() == "{\"root\":{}}");
|
||||
|
||||
// json::json_pointer and ordered_json::json_pointer are the same type; behave as above
|
||||
ordered_json test3;
|
||||
test3[json::json_pointer(p)] = json::object();
|
||||
CHECK(std::is_same<json::json_pointer::string_t, ordered_json::json_pointer::string_t>::value);
|
||||
CHECK(test3.dump() == "{\"root\":{}}");
|
||||
}
|
||||
|
||||
SECTION("issue #2982 - to_{binary format} does not provide a mechanism for specifying a custom allocator for the returned type")
|
||||
{
|
||||
std::vector<std::uint8_t, my_allocator<std::uint8_t>> my_vector;
|
||||
json j = {1, 2, 3, 4};
|
||||
json::to_cbor(j, my_vector);
|
||||
json k = json::from_cbor(my_vector);
|
||||
CHECK(j == k);
|
||||
}
|
||||
|
||||
#if JSON_HAS_FILESYSTEM || JSON_HAS_EXPERIMENTAL_FILESYSTEM
|
||||
SECTION("issue #3070 - Version 3.10.3 breaks backward-compatibility with 3.10.2 ")
|
||||
{
|
||||
nlohmann::detail::std_fs::path text_path("/tmp/text.txt");
|
||||
json j(text_path);
|
||||
|
||||
const auto j_path = j.get<nlohmann::detail::std_fs::path>();
|
||||
CHECK(j_path == text_path);
|
||||
|
||||
#if !defined(_MSC_VER) && !(defined(__GNUC__) && __GNUC__ == 8 && __GNUC_MINOR__ < 4)
|
||||
// works everywhere but on MSVC and GCC <8.4
|
||||
CHECK_THROWS_WITH_AS(nlohmann::detail::std_fs::path(json(1)), "[json.exception.type_error.302] type must be string, but is number", json::type_error);
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
|
||||
SECTION("issue #3077 - explicit constructor with default does not compile")
|
||||
{
|
||||
json j;
|
||||
j[0]["value"] = true;
|
||||
std::vector<FooBar> foo;
|
||||
j.get_to(foo);
|
||||
}
|
||||
|
||||
SECTION("issue #3108 - ordered_json doesn't support range based erase")
|
||||
{
|
||||
ordered_json j = {1, 2, 2, 4};
|
||||
|
||||
auto last = std::unique(j.begin(), j.end());
|
||||
j.erase(last, j.end());
|
||||
|
||||
CHECK(j.dump() == "[1,2,4]");
|
||||
|
||||
j.erase(std::remove_if(j.begin(), j.end(), [](const ordered_json & val)
|
||||
{
|
||||
return val == 2;
|
||||
}), j.end());
|
||||
|
||||
CHECK(j.dump() == "[1,4]");
|
||||
}
|
||||
|
||||
SECTION("issue #3343 - json and ordered_json are not interchangable")
|
||||
{
|
||||
json::object_t jobj({ { "product", "one" } });
|
||||
ordered_json::object_t ojobj({{"product", "one"}});
|
||||
|
||||
auto jit = jobj.begin();
|
||||
auto ojit = ojobj.begin();
|
||||
|
||||
CHECK(jit->first == ojit->first);
|
||||
CHECK(jit->second.get<std::string>() == ojit->second.get<std::string>());
|
||||
}
|
||||
|
||||
SECTION("issue #3171 - if class is_constructible from std::string wrong from_json overload is being selected, compilation failed")
|
||||
{
|
||||
json j{{ "str", "value"}};
|
||||
|
||||
// failed with: error: no match for ‘operator=’ (operand types are ‘for_3171_derived’ and ‘const nlohmann::basic_json<>::string_t’
|
||||
// {aka ‘const std::__cxx11::basic_string<char>’})
|
||||
// s = *j.template get_ptr<const typename BasicJsonType::string_t*>();
|
||||
auto td = j.get<for_3171_derived>();
|
||||
|
||||
CHECK(td.str == "value");
|
||||
}
|
||||
|
||||
#ifdef JSON_HAS_CPP_20
|
||||
SECTION("issue #3312 - Parse to custom class from unordered_json breaks on G++11.2.0 with C++20")
|
||||
{
|
||||
// see test for #3171
|
||||
ordered_json j = {{"name", "class"}};
|
||||
for_3312 obj{};
|
||||
|
||||
j.get_to(obj);
|
||||
|
||||
CHECK(obj.name == "class");
|
||||
}
|
||||
#endif
|
||||
|
||||
#if defined(JSON_HAS_CPP_17) && JSON_USE_IMPLICIT_CONVERSIONS
|
||||
SECTION("issue #3428 - Error occurred when converting nlohmann::json to std::any")
|
||||
{
|
||||
json j;
|
||||
std::any a1 = j;
|
||||
std::any&& a2 = j;
|
||||
|
||||
CHECK(a1.type() == typeid(j));
|
||||
CHECK(a2.type() == typeid(j));
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
DOCTEST_CLANG_SUPPRESS_WARNING_POP
|
||||