mirror of
https://github.com/nlohmann/json.git
synced 2026-10-04 13:40:33 +00:00
Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
42a22d2d5e | ||
|
|
45db371915 | ||
|
|
5d47284e6c | ||
|
|
3173c28dac | ||
|
|
e8239afff1 | ||
|
|
fd0261d909 | ||
|
|
fa2465b325 | ||
|
|
ee7c0ce71c | ||
|
|
2b29ca1812 |
@@ -107,7 +107,7 @@ jobs:
|
||||
container: ubuntu:24.04
|
||||
strategy:
|
||||
matrix:
|
||||
target: [ci_cmake_flags, ci_test_diagnostics, ci_test_diagnostic_positions, ci_test_noexceptions, ci_test_noimplicitconversions, ci_test_legacycomparison, ci_test_noglobaludls, ci_test_disableenumserialization, ci_test_disabletuplereferenceconversion, ci_test_skiplibraryversioncheck, ci_test_simdutf, ci_test_strict_nul_handling, ci_test_delete_deprecated_functions, ci_test_no_thread_local]
|
||||
target: [ci_cmake_flags, ci_test_diagnostics, ci_test_diagnostic_positions, ci_test_noexceptions, ci_test_noimplicitconversions, ci_test_legacycomparison, ci_test_noglobaludls, ci_test_disableenumserialization, ci_test_disabletuplereferenceconversion, ci_test_skiplibraryversioncheck, ci_test_simdutf, ci_test_strict_nul_handling, ci_test_no_thread_local]
|
||||
steps:
|
||||
- name: Install build-essential
|
||||
run: apt-get update ; apt-get install -y build-essential unzip wget git
|
||||
|
||||
@@ -57,6 +57,7 @@ cc_library(
|
||||
"include/nlohmann/detail/meta/type_traits.hpp",
|
||||
"include/nlohmann/detail/meta/void_t.hpp",
|
||||
"include/nlohmann/detail/output/binary_writer.hpp",
|
||||
"include/nlohmann/detail/output/error_handler.hpp",
|
||||
"include/nlohmann/detail/output/output_adapters.hpp",
|
||||
"include/nlohmann/detail/output/serializer.hpp",
|
||||
"include/nlohmann/detail/recursion_depth_limit.hpp",
|
||||
|
||||
@@ -62,7 +62,6 @@ option(JSON_MultipleHeaders "Use non-amalgamated version of the l
|
||||
option(JSON_SystemInclude "Include as system headers (skip for clang-tidy)." OFF)
|
||||
option(JSON_StrictNulHandling "Build with strict NUL-byte handling enabled." OFF)
|
||||
option(JSON_StrictBinaryUTF8 "Build with UTF-8 checks in the CBOR, UBJSON, BJData, and BSON writers enabled." OFF)
|
||||
option(JSON_DeleteDeprecatedFunctions "Delete the deprecated functions instead of only deprecating them." OFF)
|
||||
|
||||
if (JSON_CI)
|
||||
include(ci)
|
||||
@@ -124,10 +123,6 @@ if (JSON_StrictBinaryUTF8)
|
||||
message(STATUS "Strict UTF-8 checks in binary writers enabled (JSON_STRICT_BINARY_UTF8=1)")
|
||||
endif()
|
||||
|
||||
if (JSON_DeleteDeprecatedFunctions)
|
||||
message(STATUS "Deprecated functions are deleted (JSON_DELETE_DEPRECATED_FUNCTIONS=1)")
|
||||
endif()
|
||||
|
||||
if (JSON_Diagnostic_Positions)
|
||||
message(STATUS "Diagnostic positions enabled (JSON_DIAGNOSTIC_POSITIONS=1)")
|
||||
endif()
|
||||
@@ -164,7 +159,6 @@ target_compile_definitions(
|
||||
$<$<BOOL:${JSON_LegacyDiscardedValueComparison}>:JSON_USE_LEGACY_DISCARDED_VALUE_COMPARISON=1>
|
||||
$<$<BOOL:${JSON_StrictNulHandling}>:JSON_STRICT_NUL_HANDLING=1>
|
||||
$<$<BOOL:${JSON_StrictBinaryUTF8}>:JSON_STRICT_BINARY_UTF8=1>
|
||||
$<$<BOOL:${JSON_DeleteDeprecatedFunctions}>:JSON_DELETE_DEPRECATED_FUNCTIONS=1>
|
||||
)
|
||||
|
||||
target_include_directories(
|
||||
|
||||
+8
-18
@@ -249,20 +249,6 @@ add_custom_target(ci_test_strict_nul_handling
|
||||
COMMENT "Compile and test with strict NUL-byte handling enabled"
|
||||
)
|
||||
|
||||
###############################################################################
|
||||
# Delete the deprecated functions.
|
||||
###############################################################################
|
||||
|
||||
add_custom_target(ci_test_delete_deprecated_functions
|
||||
COMMAND ${CMAKE_COMMAND}
|
||||
-DCMAKE_BUILD_TYPE=Debug -GNinja
|
||||
-DJSON_BuildTests=ON -DJSON_FastTests=ON -DJSON_DeleteDeprecatedFunctions=ON
|
||||
-S${PROJECT_SOURCE_DIR} -B${PROJECT_BINARY_DIR}/build_delete_deprecated_functions
|
||||
COMMAND ${CMAKE_COMMAND} --build ${PROJECT_BINARY_DIR}/build_delete_deprecated_functions
|
||||
COMMAND cd ${PROJECT_BINARY_DIR}/build_delete_deprecated_functions && ${CMAKE_CTEST_COMMAND} --parallel ${N} --output-on-failure
|
||||
COMMENT "Compile and test with the deprecated functions deleted"
|
||||
)
|
||||
|
||||
###############################################################################
|
||||
# Disable global UDLs.
|
||||
###############################################################################
|
||||
@@ -610,8 +596,9 @@ foreach(SRC_FILE ${SRC_FILES})
|
||||
add_executable(single_${RELATIVE_SRC_FILE} EXCLUDE_FROM_ALL ${PROJECT_BINARY_DIR}/src_single/${RELATIVE_SRC_FILE}.cpp)
|
||||
target_include_directories(single_${RELATIVE_SRC_FILE} PRIVATE ${PROJECT_SOURCE_DIR}/include)
|
||||
target_compile_features(single_${RELATIVE_SRC_FILE} PRIVATE cxx_std_11)
|
||||
if(RELATIVE_SRC_FILE STREQUAL "json")
|
||||
# see below: report json.hpp's diagnostics without --error, so they do not fail the build
|
||||
if(RELATIVE_SRC_FILE STREQUAL "json" OR RELATIVE_SRC_FILE STREQUAL "json_literals")
|
||||
# see below: report the diagnostics of json.hpp and json_literals.hpp without --error, so they
|
||||
# do not fail the build
|
||||
set_property(TARGET single_${RELATIVE_SRC_FILE} PROPERTY CXX_INCLUDE_WHAT_YOU_USE ${IWYU_TOOL} -Xiwyu --max_line_length=300)
|
||||
else()
|
||||
set_property(TARGET single_${RELATIVE_SRC_FILE} PROPERTY CXX_INCLUDE_WHAT_YOU_USE "${iwyu_path_and_options}")
|
||||
@@ -625,7 +612,10 @@ foreach(SRC_FILE ${SRC_FILES})
|
||||
# reporting its diagnostics (informational, via CXX_INCLUDE_WHAT_YOU_USE above) but exclude it
|
||||
# from the hard gate below so a fresh IWYU/compiler combination does not fail this target on a
|
||||
# nondeterministic suggestion for a header that already re-exports everything on purpose.
|
||||
if(NOT RELATIVE_SRC_FILE STREQUAL "json")
|
||||
# json_literals.hpp and json.hpp include each other on purpose (json.hpp includes it at its end
|
||||
# unless JSON_NO_AUTOMATIC_UDLS is defined), and IWYU, not following the cycle, suggests replacing
|
||||
# json.hpp with json_fwd.hpp although the literals need the complete basic_json; exclude it, too.
|
||||
if(NOT RELATIVE_SRC_FILE STREQUAL "json" AND NOT RELATIVE_SRC_FILE STREQUAL "json_literals")
|
||||
list(APPEND single_binaries_tus src_single/${RELATIVE_SRC_FILE}.cpp)
|
||||
endif()
|
||||
endforeach()
|
||||
@@ -715,7 +705,7 @@ ci_get_cmake(4.0.0 CMAKE_4_0_0_BINARY)
|
||||
# the tests require CMake 3.13 or later, so they are excluded for CMake 3.5.0
|
||||
set(JSON_CMAKE_FLAGS_3_5_0 JSON_Diagnostics JSON_Diagnostic_Positions JSON_GlobalUDLs JSON_ImplicitConversions JSON_DisableEnumSerialization
|
||||
JSON_LegacyDiscardedValueComparison JSON_Install JSON_MultipleHeaders JSON_SystemInclude JSON_Valgrind
|
||||
JSON_StrictNulHandling JSON_StrictBinaryUTF8 JSON_DeleteDeprecatedFunctions)
|
||||
JSON_StrictNulHandling JSON_StrictBinaryUTF8)
|
||||
set(JSON_CMAKE_FLAGS_3_31_6 JSON_BuildTests ${JSON_CMAKE_FLAGS_3_5_0})
|
||||
set(JSON_CMAKE_FLAGS_4_0_0 JSON_BuildTests ${JSON_CMAKE_FLAGS_3_5_0})
|
||||
|
||||
|
||||
@@ -219,7 +219,6 @@ INSERT INTO searchIndex(name, type, path) VALUES ('Supported Macros', 'Guide', '
|
||||
INSERT INTO searchIndex(name, type, path) VALUES ('JSON_ASSERT', 'Macro', 'api/macros/json_assert/index.html');
|
||||
INSERT INTO searchIndex(name, type, path) VALUES ('JSON_BRACE_INIT_COPY_SEMANTICS', 'Macro', 'api/macros/json_brace_init_copy_semantics/index.html');
|
||||
INSERT INTO searchIndex(name, type, path) VALUES ('JSON_CATCH_USER', 'Macro', 'api/macros/json_throw_user/index.html');
|
||||
INSERT INTO searchIndex(name, type, path) VALUES ('JSON_DELETE_DEPRECATED_FUNCTIONS', 'Macro', 'api/macros/json_delete_deprecated_functions/index.html');
|
||||
INSERT INTO searchIndex(name, type, path) VALUES ('JSON_DIAGNOSTICS', 'Macro', 'api/macros/json_diagnostics/index.html');
|
||||
INSERT INTO searchIndex(name, type, path) VALUES ('JSON_DIAGNOSTIC_POSITIONS', 'Macro', 'api/macros/json_diagnostic_positions/index.html');
|
||||
INSERT INTO searchIndex(name, type, path) VALUES ('JSON_DISABLE_ENUM_SERIALIZATION', 'Macro', 'api/macros/json_disable_enum_serialization/index.html');
|
||||
|
||||
@@ -120,12 +120,3 @@ Linear in the size of the input.
|
||||
- Extended container support (1) to include types with lvalue-only ADL `begin`/`end` (matching `std::begin`/`std::end` semantics) in version 3.13.0.
|
||||
- Extended overload (2) to accept heterogeneous iterator+sentinel pairs (C++20 ranges support) in version 3.13.0.
|
||||
- Added `error_handler` parameter in version 3.13.0.
|
||||
|
||||
!!! warning "Deprecation"
|
||||
|
||||
- Overload (2) replaces calls to `from_bjdata` with a pointer and a length as first two parameters, which has been
|
||||
deprecated in version 3.13.0. This overload will be removed in version 4.0.0. Please replace all calls like
|
||||
`#!cpp from_bjdata(ptr, len, ...);` with `#!cpp from_bjdata(ptr, ptr+len, ...);`.
|
||||
|
||||
You should be warned by your compiler with a `-Wdeprecated-declarations` warning if you are using a deprecated
|
||||
function.
|
||||
|
||||
@@ -106,12 +106,3 @@ Linear in the size of the input.
|
||||
## Version history
|
||||
|
||||
- Added in version 3.13.0.
|
||||
|
||||
!!! warning "Deprecation"
|
||||
|
||||
- Overload (2) replaces calls to `from_bon8` with a pointer and a length as first two parameters, which has been
|
||||
deprecated in version 3.13.0. This overload will be removed in version 4.0.0. Please replace all calls like
|
||||
`#!cpp from_bon8(ptr, len, ...);` with `#!cpp from_bon8(ptr, ptr+len, ...);`.
|
||||
|
||||
You should be warned by your compiler with a `-Wdeprecated-declarations` warning if you are using a deprecated
|
||||
function.
|
||||
|
||||
@@ -59,11 +59,6 @@ header. See also the [macro overview page](../../features/macros.md).
|
||||
- [**JSON_DISABLE_TUPLE_REFERENCE_CONVERSION**](json_disable_tuple_reference_conversion.md) - switch off conversion from a one-element tuple of a JSON reference
|
||||
- [**JSON_USE_IMPLICIT_CONVERSIONS**](json_use_implicit_conversions.md) - control implicit conversions
|
||||
|
||||
## Deprecated functions
|
||||
|
||||
- [**JSON_DELETE_DEPRECATED_FUNCTIONS**](json_delete_deprecated_functions.md) - opt in to deleting the deprecated
|
||||
functions ahead of their removal in version 4.0.0
|
||||
|
||||
## Comparison behavior
|
||||
|
||||
- [**JSON_USE_LEGACY_DISCARDED_VALUE_COMPARISON**](json_use_legacy_discarded_value_comparison.md) -
|
||||
|
||||
@@ -1,96 +0,0 @@
|
||||
# JSON_DELETE_DEPRECATED_FUNCTIONS
|
||||
|
||||
```cpp
|
||||
#define JSON_DELETE_DEPRECATED_FUNCTIONS /* value */
|
||||
```
|
||||
|
||||
When defined to `1`, all [deprecated functions](../../community/roadmap.md#removal-of-deprecated-functions) of the
|
||||
library are declared as deleted (`= delete`) instead of only being marked as deprecated. Code that still calls one of
|
||||
them no longer compiles. This way, you can find all calls that need to be replaced before version 4.0.0 removes these
|
||||
functions; the [migration guide](../../integration/migration_guide.md#replace-deprecated-functions) describes how.
|
||||
|
||||
A deleted function, unlike a removed one, still takes part in overload resolution. A call that would select it
|
||||
therefore fails to compile instead of silently selecting another overload. This matters for the deprecated
|
||||
`from_*(ptr, len)` overloads of [`from_cbor`](../basic_json/from_cbor.md), [`from_msgpack`](../basic_json/from_msgpack.md),
|
||||
[`from_ubjson`](../basic_json/from_ubjson.md), [`from_bjdata`](../basic_json/from_bjdata.md),
|
||||
[`from_bon8`](../basic_json/from_bon8.md), and [`from_bson`](../basic_json/from_bson.md): without them, a call like
|
||||
`from_cbor(ptr, len)` would compile, read `ptr` as a NUL-terminated string, and convert `len` to the `strict` parameter.
|
||||
|
||||
The macro does not affect the deprecated legacy comparison of discarded values, which is controlled by
|
||||
[`JSON_USE_LEGACY_DISCARDED_VALUE_COMPARISON`](json_use_legacy_discarded_value_comparison.md).
|
||||
|
||||
## Default definition
|
||||
|
||||
The default value is `0` (disabled, the deprecated functions can still be called, and the compiler warns about it).
|
||||
|
||||
```cpp
|
||||
#define JSON_DELETE_DEPRECATED_FUNCTIONS 0
|
||||
```
|
||||
|
||||
## Notes
|
||||
|
||||
!!! info "CMake option"
|
||||
|
||||
The macro can also be set with the CMake option
|
||||
[`JSON_DeleteDeprecatedFunctions`](../../integration/cmake.md#json_deletedeprecatedfunctions) (`OFF` by default).
|
||||
|
||||
!!! warning "Opt-in only"
|
||||
|
||||
This macro must be defined **before** including `<nlohmann/json.hpp>`. Defining it after the include has no
|
||||
effect. Define it for the whole project to avoid different declarations of the same class in different
|
||||
translation units.
|
||||
|
||||
!!! note "ABI compatibility"
|
||||
|
||||
The macro only turns calls that compile into calls that do not; it does not change the layout or the behavior of
|
||||
any type. Its value is therefore not encoded in the [namespace](../../features/namespace.md).
|
||||
|
||||
## Examples
|
||||
|
||||
??? example "Example: default behavior (macro not defined)"
|
||||
|
||||
Without the macro, the deprecated overload is called, and the compiler warns about it:
|
||||
|
||||
```cpp
|
||||
#include <nlohmann/json.hpp>
|
||||
|
||||
using json = nlohmann::json;
|
||||
|
||||
int main()
|
||||
{
|
||||
const std::vector<std::uint8_t> v = {0x82, 0x01, 0x02};
|
||||
auto j = json::from_cbor(v.data(), v.size());
|
||||
// warning: 'from_cbor' is deprecated: Since 3.8.0; use from_cbor(ptr, ptr + len)
|
||||
}
|
||||
```
|
||||
|
||||
??? example "Example: deleted deprecated functions (macro defined to 1)"
|
||||
|
||||
With the macro, the call does not compile:
|
||||
|
||||
```cpp
|
||||
#define JSON_DELETE_DEPRECATED_FUNCTIONS 1
|
||||
#include <nlohmann/json.hpp>
|
||||
|
||||
using json = nlohmann::json;
|
||||
|
||||
int main()
|
||||
{
|
||||
const std::vector<std::uint8_t> v = {0x82, 0x01, 0x02};
|
||||
auto j = json::from_cbor(v.data(), v.size());
|
||||
// error: call to deleted function 'from_cbor'
|
||||
}
|
||||
```
|
||||
|
||||
## See also
|
||||
|
||||
- [Roadmap: removal of deprecated functions](../../community/roadmap.md#removal-of-deprecated-functions) - the
|
||||
deprecated functions and the version they were deprecated in
|
||||
- [Migration guide: replace deprecated functions](../../integration/migration_guide.md#replace-deprecated-functions) -
|
||||
how to replace each deprecated function
|
||||
|
||||
## Version history
|
||||
|
||||
- Added in version 3.13.0.
|
||||
- Planned to be removed in version 4.0.0, which removes the deprecated functions. The deprecated `from_*(ptr, len)`
|
||||
overloads stay deleted in version 4.0.0.
|
||||
@@ -112,4 +112,3 @@ The default value is `0` (disabled — existing behavior is preserved).
|
||||
## Version history
|
||||
|
||||
- Added in version 3.13.0.
|
||||
- Planned to become the default (with the macro removed) in version 4.0.0.
|
||||
|
||||
@@ -44,7 +44,7 @@ By default, implicit conversions are enabled.
|
||||
|
||||
## Examples
|
||||
|
||||
??? example "Example: implicit and explicit conversions"
|
||||
??? example "Example: implicit conversion"
|
||||
|
||||
This is an example for an implicit conversion:
|
||||
|
||||
|
||||
@@ -64,8 +64,6 @@ The following macros guard changes that are planned to become the default in ver
|
||||
| [`JSON_PRECISE_STREAM_POSITION`](../api/macros/json_precise_stream_position.md) | `0` | `1`: reading from a stream does not consume the character after a number | – | 3.13.0 |
|
||||
| [`JSON_STRICT_NUL_HANDLING`](../api/macros/json_strict_nul_handling.md) | `0` | `1`: a NUL byte in the input is a parse error instead of the end of input | [`JSON_StrictNulHandling`](../integration/cmake.md#json_strictnulhandling) | 3.13.0 |
|
||||
| [`JSON_STRICT_BINARY_UTF8`](../api/macros/json_strict_binary_utf8.md) | `0` | `1`: `to_cbor`, `to_ubjson`, `to_bjdata`, and `to_bson` throw for strings that are not valid UTF-8 by default | [`JSON_StrictBinaryUTF8`](../integration/cmake.md#json_strictbinaryutf8) | 3.13.0 |
|
||||
| [`JSON_DISABLE_TUPLE_REFERENCE_CONVERSION`](../api/macros/json_disable_tuple_reference_conversion.md) | `0` | `1`: a `basic_json` value can no longer be created from a one-element tuple of a reference to it, such as `std::forward_as_tuple(j)`| [`JSON_DisableTupleReferenceConversion`](../integration/cmake.md#json_disabletuplereferenceconversion) | 3.13.0 |
|
||||
| [`JSON_DELETE_DEPRECATED_FUNCTIONS`](../api/macros/json_delete_deprecated_functions.md) | `0` | removed: the deprecated functions are removed (see below); the `from_*(ptr, len)` overloads stay deleted | [`JSON_DeleteDeprecatedFunctions`](../integration/cmake.md#json_deletedeprecatedfunctions) | 3.13.0 |
|
||||
|
||||
For example, the following makes a 3.x release behave like version 4.0 with respect to these changes:
|
||||
|
||||
@@ -77,8 +75,6 @@ For example, the following makes a 3.x release behave like version 4.0 with resp
|
||||
#define JSON_PRECISE_STREAM_POSITION 1
|
||||
#define JSON_STRICT_NUL_HANDLING 1
|
||||
#define JSON_STRICT_BINARY_UTF8 1
|
||||
#define JSON_DISABLE_TUPLE_REFERENCE_CONVERSION 1
|
||||
#define JSON_DELETE_DEPRECATED_FUNCTIONS 1
|
||||
#include <nlohmann/json.hpp>
|
||||
```
|
||||
|
||||
@@ -88,13 +84,8 @@ way to achieve this.
|
||||
### Removal of deprecated functions
|
||||
|
||||
Version 4.0 will remove all deprecated functions. Compiling with deprecation warnings enabled shows which of them your
|
||||
code still uses. Defining [`JSON_DELETE_DEPRECATED_FUNCTIONS`](../api/macros/json_delete_deprecated_functions.md) to
|
||||
`1` turns these warnings into errors, as the deprecated functions are then deleted. The
|
||||
[migration guide](../integration/migration_guide.md#replace-deprecated-functions) shows how to replace each of them.
|
||||
|
||||
The `from_*` overloads taking a pointer and a length are not removed in version 4.0, but stay deleted. Without them, a
|
||||
call like `from_cbor(ptr, len)` would still compile: it would read `ptr` as a NUL-terminated string and convert `len`
|
||||
to the `strict` parameter.
|
||||
code still uses. The [migration guide](../integration/migration_guide.md#replace-deprecated-functions) shows how to
|
||||
replace each of them.
|
||||
|
||||
| Deprecated | Since | Migration |
|
||||
|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|--------|----------------------------------------------------------------------------------|
|
||||
@@ -106,7 +97,6 @@ to the `strict` parameter.
|
||||
| [`json_pointer::operator string_t`](../api/json_pointer/operator_string_t.md) | 3.11.0 | [JSON Pointers](../integration/migration_guide.md#json-pointers) |
|
||||
| [`json_pointer`](../api/json_pointer/index.md) with a `basic_json` type as template argument, and the overloads of `value`, `contains`, `operator[]`, and `at` accepting such a pointer | 3.11.0 | [JSON Pointers](../integration/migration_guide.md#json-pointers) |
|
||||
| Comparing a [`json_pointer`](../api/json_pointer/index.md) with a string via [`operator==`](../api/json_pointer/operator_eq.md) or [`operator!=`](../api/json_pointer/operator_ne.md) | 3.11.2 | [JSON Pointers](../integration/migration_guide.md#json-pointers) |
|
||||
| [`from_bjdata`](../api/basic_json/from_bjdata.md) and [`from_bon8`](../api/basic_json/from_bon8.md) with `(ptr, len)` | 3.13.0 | [Parsing](../integration/migration_guide.md#parsing) |
|
||||
|
||||
The deprecated legacy comparison of discarded values is controlled by a macro and therefore listed in the table above.
|
||||
|
||||
|
||||
@@ -23,17 +23,6 @@ This macro overrides [`#!cpp catch`](https://en.cppreference.com/w/cpp/language/
|
||||
|
||||
See [full documentation of `JSON_CATCH_USER(exception)`](../api/macros/json_throw_user.md).
|
||||
|
||||
## `JSON_DELETE_DEPRECATED_FUNCTIONS`
|
||||
|
||||
When defined to `1`, all deprecated functions are declared as deleted instead of only being marked as deprecated, so
|
||||
code that still calls them no longer compiles. This way, you can find all calls that need to be replaced before version
|
||||
4.0.0 removes these functions.
|
||||
|
||||
The macro can also be set with the CMake option
|
||||
[`JSON_DeleteDeprecatedFunctions`](../integration/cmake.md#json_deletedeprecatedfunctions) (`OFF` by default).
|
||||
|
||||
See [full documentation of `JSON_DELETE_DEPRECATED_FUNCTIONS`](../api/macros/json_delete_deprecated_functions.md).
|
||||
|
||||
## `JSON_DIAGNOSTICS`
|
||||
|
||||
This macro enables extended diagnostics for exception messages. Possible values are `1` to enable or `0` to disable
|
||||
@@ -97,8 +86,7 @@ See [full documentation of `JSON_DISABLE_ENUM_SERIALIZATION`](../api/macros/json
|
||||
## `JSON_DISABLE_TUPLE_REFERENCE_CONVERSION`
|
||||
|
||||
When defined to `1`, a JSON value can no longer be created from a one-element `std::tuple` holding a reference to a JSON
|
||||
value, such as the result of `std::forward_as_tuple(j)`. This lets `std::tuple` convert such tuples element-wise. This
|
||||
is planned to become the default in version 4.0.0.
|
||||
value, such as the result of `std::forward_as_tuple(j)`. This lets `std::tuple` convert such tuples element-wise.
|
||||
|
||||
See [full documentation of `JSON_DISABLE_TUPLE_REFERENCE_CONVERSION`](../api/macros/json_disable_tuple_reference_conversion.md).
|
||||
|
||||
|
||||
@@ -132,12 +132,6 @@ Build the unit tests when [`BUILD_TESTING`](https://cmake.org/cmake/help/latest/
|
||||
|
||||
Enable CI build targets. The exact targets are used during the several CI steps and are subject to change without notice. This option is `OFF` by default.
|
||||
|
||||
### `JSON_DeleteDeprecatedFunctions`
|
||||
|
||||
Delete the deprecated functions instead of only deprecating them by defining the macro
|
||||
[`JSON_DELETE_DEPRECATED_FUNCTIONS`](../api/macros/json_delete_deprecated_functions.md). This option is `OFF` by
|
||||
default.
|
||||
|
||||
### `JSON_Diagnostics`
|
||||
|
||||
Enable [extended diagnostic messages](../home/exceptions.md#extended-diagnostic-messages) by defining macro [`JSON_DIAGNOSTICS`](../api/macros/json_diagnostics.md). This option is `OFF` by default.
|
||||
|
||||
@@ -14,13 +14,6 @@ deprecations are annotated with
|
||||
[`HEDLEY_DEPRECATED_FOR`](https://nemequ.github.io/hedley/api-reference.html#HEDLEY_DEPRECATED_FOR) to report which
|
||||
function to use instead.
|
||||
|
||||
!!! tip "Find all calls of deprecated functions"
|
||||
|
||||
Define [`JSON_DELETE_DEPRECATED_FUNCTIONS`](../api/macros/json_delete_deprecated_functions.md) to `1` (or set the
|
||||
CMake option [`JSON_DeleteDeprecatedFunctions`](cmake.md#json_deletedeprecatedfunctions)) to delete all deprecated
|
||||
functions. Every remaining call then fails to compile, even if deprecation warnings are disabled, so your code is
|
||||
ready for version 4.0.0 once it compiles with the macro.
|
||||
|
||||
### Parsing
|
||||
|
||||
- Function `friend std::istream& operator<<(basic_json&, std::istream&)` is deprecated since 3.0.0. Please use
|
||||
@@ -48,10 +41,8 @@ function to use instead.
|
||||
[`from_ubjson`](../api/basic_json/from_ubjson.md), and [`from_bson`](../api/basic_json/from_bson.md)) via initializer
|
||||
lists is deprecated since 3.8.0. Instead, pass two iterators; for instance, call `from_cbor(ptr, ptr+len)` instead of
|
||||
`from_cbor({ptr, len})`. Likewise, passing a pointer and a length as two separate arguments to `from_cbor`,
|
||||
`from_msgpack`, `from_ubjson`, and `from_bson` is deprecated since 3.8.0, and to
|
||||
[`from_bjdata`](../api/basic_json/from_bjdata.md) and [`from_bon8`](../api/basic_json/from_bon8.md) since 3.13.0; call
|
||||
`from_cbor(ptr, ptr+len)` instead of `from_cbor(ptr, len)`. These overloads will not be removed in version 4.0.0, but
|
||||
deleted, so a call like `from_cbor(ptr, len)` cannot compile and convert `len` to the `strict` parameter.
|
||||
`from_msgpack`, `from_ubjson`, and `from_bson` is deprecated since 3.8.0; call `from_cbor(ptr, ptr+len)` instead of
|
||||
`from_cbor(ptr, len)`.
|
||||
|
||||
=== "Deprecated"
|
||||
|
||||
|
||||
@@ -292,7 +292,6 @@ nav:
|
||||
- 'JSON_BRACE_INIT_COPY_SEMANTICS': api/macros/json_brace_init_copy_semantics.md
|
||||
- 'JSON_CATCH_USER, JSON_THROW_USER, JSON_TRY_USER': api/macros/json_throw_user.md
|
||||
- 'JSON_DIAGNOSTICS': api/macros/json_diagnostics.md
|
||||
- 'JSON_DELETE_DEPRECATED_FUNCTIONS': api/macros/json_delete_deprecated_functions.md
|
||||
- 'JSON_DIAGNOSTIC_POSITIONS': api/macros/json_diagnostic_positions.md
|
||||
- 'JSON_DISABLE_ENUM_SERIALIZATION': api/macros/json_disable_enum_serialization.md
|
||||
- 'JSON_DISABLE_TUPLE_REFERENCE_CONVERSION': api/macros/json_disable_tuple_reference_conversion.md
|
||||
|
||||
@@ -110,15 +110,15 @@ class binary_reader
|
||||
|
||||
@param[in] adapter input adapter to read from
|
||||
@param[in] format the binary format to parse
|
||||
@param[in] error_handler how to treat text strings and object keys that
|
||||
@param[in] error_handler_ how to treat text strings and object keys that
|
||||
are not well-formed UTF-8; none of the supported formats
|
||||
requires a decoder to reject those, so the default is to
|
||||
@ref error_handler_t::keep them unchanged, as every binary
|
||||
reader did before this parameter existed
|
||||
*/
|
||||
explicit binary_reader(InputAdapterType&& adapter, const input_format_t format = input_format_t::json,
|
||||
const error_handler_t error_handler = error_handler_t::keep) noexcept
|
||||
: ia(std::move(adapter)), input_format(format), error_handler(error_handler)
|
||||
const error_handler_t error_handler_ = error_handler_t::keep) noexcept
|
||||
: ia(std::move(adapter)), input_format(format), error_handler(error_handler_)
|
||||
{
|
||||
(void)detail::is_sax_static_asserts<SAX, BasicJsonType> {};
|
||||
}
|
||||
|
||||
@@ -79,15 +79,11 @@ class json_pointer
|
||||
|
||||
/// @brief return a string representation of the JSON pointer
|
||||
/// @sa https://json.nlohmann.me/api/json_pointer/operator_string_t/
|
||||
#if JSON_DELETE_DEPRECATED_FUNCTIONS
|
||||
operator string_t() const = delete;
|
||||
#else
|
||||
JSON_HEDLEY_DEPRECATED_FOR(3.11.0, to_string())
|
||||
operator string_t() const
|
||||
{
|
||||
return to_string();
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifndef JSON_NO_IO
|
||||
/// @brief write string representation of the JSON pointer to stream
|
||||
@@ -326,6 +322,8 @@ class json_pointer
|
||||
typename BasicJsonType::size_type idx{};
|
||||
switch (parse_array_index<BasicJsonType>(s, idx))
|
||||
{
|
||||
// the branches differ in their messages, not after JSON_THROW's expansion
|
||||
// NOLINTNEXTLINE(bugprone-branch-clone)
|
||||
case array_index_status::leading_zero:
|
||||
JSON_THROW(detail::parse_error::create(106, 0, detail::concat("array index '", s, "' must not begin with '0'"), nullptr));
|
||||
case array_index_status::not_a_number:
|
||||
@@ -689,6 +687,8 @@ class json_pointer
|
||||
typename BasicJsonType::size_type idx{};
|
||||
switch (parse_array_index<BasicJsonType>(reference_token, idx))
|
||||
{
|
||||
// the branches differ in their messages, not after JSON_THROW's expansion
|
||||
// NOLINTNEXTLINE(bugprone-branch-clone)
|
||||
case array_index_status::leading_zero:
|
||||
JSON_THROW(detail::parse_error::create(106, 0, detail::concat("array index '", reference_token, "' must not begin with '0'"), nullptr));
|
||||
case array_index_status::not_a_number:
|
||||
@@ -1020,15 +1020,11 @@ class json_pointer
|
||||
|
||||
/// @brief compares JSON pointer and string for equality
|
||||
/// @sa https://json.nlohmann.me/api/json_pointer/operator_eq/
|
||||
#if JSON_DELETE_DEPRECATED_FUNCTIONS
|
||||
bool operator==(const string_t& rhs) const = delete;
|
||||
#else
|
||||
JSON_HEDLEY_DEPRECATED_FOR(3.11.2, operator==(json_pointer))
|
||||
bool operator==(const string_t& rhs) const
|
||||
{
|
||||
return *this == json_pointer(rhs);
|
||||
}
|
||||
#endif
|
||||
|
||||
/// @brief 3-way compares two JSON pointers
|
||||
template<typename RefStringTypeRhs>
|
||||
@@ -1103,31 +1099,21 @@ inline bool operator==(const json_pointer<RefStringTypeLhs>& lhs,
|
||||
|
||||
template<typename RefStringTypeLhs,
|
||||
typename StringType = typename json_pointer<RefStringTypeLhs>::string_t>
|
||||
#if JSON_DELETE_DEPRECATED_FUNCTIONS
|
||||
inline bool operator==(const json_pointer<RefStringTypeLhs>& lhs,
|
||||
const StringType& rhs) = delete;
|
||||
#else
|
||||
JSON_HEDLEY_DEPRECATED_FOR(3.11.2, operator==(json_pointer, json_pointer))
|
||||
inline bool operator==(const json_pointer<RefStringTypeLhs>& lhs,
|
||||
const StringType& rhs)
|
||||
{
|
||||
return lhs == json_pointer<RefStringTypeLhs>(rhs);
|
||||
}
|
||||
#endif
|
||||
|
||||
template<typename RefStringTypeRhs,
|
||||
typename StringType = typename json_pointer<RefStringTypeRhs>::string_t>
|
||||
#if JSON_DELETE_DEPRECATED_FUNCTIONS
|
||||
inline bool operator==(const StringType& lhs,
|
||||
const json_pointer<RefStringTypeRhs>& rhs) = delete;
|
||||
#else
|
||||
JSON_HEDLEY_DEPRECATED_FOR(3.11.2, operator==(json_pointer, json_pointer))
|
||||
inline bool operator==(const StringType& lhs,
|
||||
const json_pointer<RefStringTypeRhs>& rhs)
|
||||
{
|
||||
return json_pointer<RefStringTypeRhs>(lhs) == rhs;
|
||||
}
|
||||
#endif
|
||||
|
||||
template<typename RefStringTypeLhs, typename RefStringTypeRhs>
|
||||
inline bool operator!=(const json_pointer<RefStringTypeLhs>& lhs,
|
||||
@@ -1138,31 +1124,21 @@ inline bool operator!=(const json_pointer<RefStringTypeLhs>& lhs,
|
||||
|
||||
template<typename RefStringTypeLhs,
|
||||
typename StringType = typename json_pointer<RefStringTypeLhs>::string_t>
|
||||
#if JSON_DELETE_DEPRECATED_FUNCTIONS
|
||||
inline bool operator!=(const json_pointer<RefStringTypeLhs>& lhs,
|
||||
const StringType& rhs) = delete;
|
||||
#else
|
||||
JSON_HEDLEY_DEPRECATED_FOR(3.11.2, operator!=(json_pointer, json_pointer))
|
||||
inline bool operator!=(const json_pointer<RefStringTypeLhs>& lhs,
|
||||
const StringType& rhs)
|
||||
{
|
||||
return !(lhs == rhs);
|
||||
}
|
||||
#endif
|
||||
|
||||
template<typename RefStringTypeRhs,
|
||||
typename StringType = typename json_pointer<RefStringTypeRhs>::string_t>
|
||||
#if JSON_DELETE_DEPRECATED_FUNCTIONS
|
||||
inline bool operator!=(const StringType& lhs,
|
||||
const json_pointer<RefStringTypeRhs>& rhs) = delete;
|
||||
#else
|
||||
JSON_HEDLEY_DEPRECATED_FOR(3.11.2, operator!=(json_pointer, json_pointer))
|
||||
inline bool operator!=(const StringType& lhs,
|
||||
const json_pointer<RefStringTypeRhs>& rhs)
|
||||
{
|
||||
return !(lhs == rhs);
|
||||
}
|
||||
#endif
|
||||
|
||||
template<typename RefStringTypeLhs, typename RefStringTypeRhs>
|
||||
inline bool operator<(const json_pointer<RefStringTypeLhs>& lhs,
|
||||
|
||||
@@ -888,10 +888,6 @@
|
||||
#define JSON_DISABLE_ENUM_SERIALIZATION 0
|
||||
#endif
|
||||
|
||||
#ifndef JSON_DELETE_DEPRECATED_FUNCTIONS
|
||||
#define JSON_DELETE_DEPRECATED_FUNCTIONS 0
|
||||
#endif
|
||||
|
||||
#ifndef JSON_DISABLE_TUPLE_REFERENCE_CONVERSION
|
||||
#define JSON_DISABLE_TUPLE_REFERENCE_CONVERSION 0
|
||||
#endif
|
||||
|
||||
@@ -43,7 +43,6 @@
|
||||
#undef JSON_PRECISE_STREAM_POSITION
|
||||
#undef JSON_STRICT_NUL_HANDLING
|
||||
#undef JSON_STRICT_BINARY_UTF8
|
||||
#undef JSON_DELETE_DEPRECATED_FUNCTIONS
|
||||
#endif
|
||||
|
||||
#include <nlohmann/thirdparty/hedley/hedley_undef.hpp>
|
||||
|
||||
@@ -2260,18 +2260,18 @@ class binary_writer
|
||||
switch (error_handler)
|
||||
{
|
||||
case error_handler_t::keep:
|
||||
return s;
|
||||
return s; // NOLINT(bugprone-return-const-ref-from-parameter): callers pass lvalues that outlive the call
|
||||
|
||||
case error_handler_t::strict:
|
||||
check_utf8(s, context);
|
||||
return s;
|
||||
return s; // NOLINT(bugprone-return-const-ref-from-parameter): callers pass lvalues that outlive the call
|
||||
|
||||
case error_handler_t::replace:
|
||||
case error_handler_t::ignore:
|
||||
default:
|
||||
if (is_valid_utf8(s))
|
||||
{
|
||||
return s;
|
||||
return s; // NOLINT(bugprone-return-const-ref-from-parameter): callers pass lvalues that outlive the call
|
||||
}
|
||||
storage = sanitize_utf8(s, error_handler);
|
||||
return storage;
|
||||
|
||||
@@ -706,6 +706,11 @@ class serializer
|
||||
@a ensure_ascii is a template parameter here so that the branch on it is
|
||||
resolved once, outside the loop; see @ref dump_escaped.
|
||||
*/
|
||||
#ifdef JSON_HEDLEY_MSVC_VERSION
|
||||
#pragma warning(push)
|
||||
// EnsureAscii is a template parameter; C++11 has no if constexpr
|
||||
#pragma warning(disable : 4127) // conditional expression is constant
|
||||
#endif
|
||||
template<bool EnsureAscii>
|
||||
void dump_escaped_impl(const string_t& s)
|
||||
{
|
||||
@@ -1055,6 +1060,9 @@ class serializer
|
||||
}
|
||||
}
|
||||
}
|
||||
#ifdef JSON_HEDLEY_MSVC_VERSION
|
||||
#pragma warning(pop)
|
||||
#endif
|
||||
|
||||
private:
|
||||
/*!
|
||||
|
||||
+36
-167
@@ -1048,6 +1048,7 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
|
||||
never name it to call this constructor itself.
|
||||
*/
|
||||
basic_json(copy_construct_tag /*unused*/, const basic_json& src)
|
||||
noexcept(std::is_nothrow_copy_constructible<json_base_class_t>::value)
|
||||
: json_base_class_t(src)
|
||||
#if JSON_DIAGNOSTIC_POSITIONS
|
||||
, start_position(src.start_position)
|
||||
@@ -1442,7 +1443,7 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
|
||||
be destroyed.
|
||||
*/
|
||||
template<typename BasicJsonType>
|
||||
void convert_iteratively(const BasicJsonType& val)
|
||||
void convert_iteratively(const BasicJsonType& val, std::true_type /*unused*/)
|
||||
{
|
||||
using other_const_iterator = typename BasicJsonType::const_iterator;
|
||||
|
||||
@@ -1536,21 +1537,38 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
|
||||
|
||||
if (JSON_HEDLEY_LIKELY(guard.okay()))
|
||||
{
|
||||
// every element comes back to the converting constructor
|
||||
if (val.is_object())
|
||||
{
|
||||
using other_object_t = typename BasicJsonType::object_t;
|
||||
JSONSerializer<other_object_t>::to_json(*this, val.template get_ref<const other_object_t&>());
|
||||
}
|
||||
else
|
||||
{
|
||||
using other_array_t = typename BasicJsonType::array_t;
|
||||
JSONSerializer<other_array_t>::to_json(*this, val.template get_ref<const other_array_t&>());
|
||||
}
|
||||
convert_by_serializers(val);
|
||||
return;
|
||||
}
|
||||
|
||||
convert_iteratively(val);
|
||||
// the iterative conversion needs to construct this object type's keys
|
||||
// from those of @a val; if it cannot, neither can the range constructor,
|
||||
// and the serializers convert @a val some other way (see #3425)
|
||||
convert_iteratively(val, std::is_constructible<typename object_t::key_type, const typename BasicJsonType::string_t&> {});
|
||||
}
|
||||
|
||||
/// @brief convert the object or array @a val with the serializers; every
|
||||
/// element comes back to the converting constructor
|
||||
template<typename BasicJsonType>
|
||||
void convert_by_serializers(const BasicJsonType& val)
|
||||
{
|
||||
if (val.is_object())
|
||||
{
|
||||
using other_object_t = typename BasicJsonType::object_t;
|
||||
JSONSerializer<other_object_t>::to_json(*this, val.template get_ref<const other_object_t&>());
|
||||
}
|
||||
else
|
||||
{
|
||||
using other_array_t = typename BasicJsonType::array_t;
|
||||
JSONSerializer<other_array_t>::to_json(*this, val.template get_ref<const other_array_t&>());
|
||||
}
|
||||
}
|
||||
|
||||
/// @brief convert @a val whose keys cannot be converted, see @ref convert_structured
|
||||
template<typename BasicJsonType>
|
||||
void convert_iteratively(const BasicJsonType& val, std::false_type /*unused*/)
|
||||
{
|
||||
convert_by_serializers(val);
|
||||
}
|
||||
|
||||
|
||||
@@ -1624,15 +1642,15 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
|
||||
static compare_result compare_leaves(const_reference lhs, const_reference rhs, std::true_type /*ordered*/) noexcept
|
||||
{
|
||||
const std::partial_ordering order = lhs <=> rhs; // *NOPAD*
|
||||
if (order == 0)
|
||||
if (std::is_eq(order))
|
||||
{
|
||||
return compare_result::equal;
|
||||
}
|
||||
if (order < 0)
|
||||
if (std::is_lt(order))
|
||||
{
|
||||
return compare_result::less;
|
||||
}
|
||||
if (order > 0)
|
||||
if (std::is_gt(order))
|
||||
{
|
||||
return compare_result::greater;
|
||||
}
|
||||
@@ -3470,30 +3488,22 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
|
||||
detail::is_basic_json<BasicJsonType>::value
|
||||
&& detail::is_getable<basic_json_t, ValueType>::value
|
||||
&& !std::is_same<value_t, detail::uncvref_t<ValueType>>::value, int > = 0 >
|
||||
#if JSON_DELETE_DEPRECATED_FUNCTIONS
|
||||
ValueType value(const ::nlohmann::json_pointer<BasicJsonType>& ptr, const ValueType& default_value) const = delete;
|
||||
#else
|
||||
JSON_HEDLEY_DEPRECATED_FOR(3.11.0, basic_json::json_pointer or nlohmann::json_pointer<basic_json::string_t>) // NOLINT(readability/alt_tokens)
|
||||
ValueType value(const ::nlohmann::json_pointer<BasicJsonType>& ptr, const ValueType& default_value) const
|
||||
{
|
||||
return value(ptr.convert(), default_value);
|
||||
}
|
||||
#endif
|
||||
|
||||
template < class ValueType, class BasicJsonType, class ReturnType = typename value_return_type<ValueType>::type,
|
||||
detail::enable_if_t <
|
||||
detail::is_basic_json<BasicJsonType>::value
|
||||
&& detail::is_getable<basic_json_t, ReturnType>::value
|
||||
&& !std::is_same<value_t, detail::uncvref_t<ValueType>>::value, int > = 0 >
|
||||
#if JSON_DELETE_DEPRECATED_FUNCTIONS
|
||||
ReturnType value(const ::nlohmann::json_pointer<BasicJsonType>& ptr, ValueType && default_value) const = delete;
|
||||
#else
|
||||
JSON_HEDLEY_DEPRECATED_FOR(3.11.0, basic_json::json_pointer or nlohmann::json_pointer<basic_json::string_t>) // NOLINT(readability/alt_tokens)
|
||||
ReturnType value(const ::nlohmann::json_pointer<BasicJsonType>& ptr, ValueType && default_value) const
|
||||
{
|
||||
return value(ptr.convert(), std::forward<ValueType>(default_value));
|
||||
}
|
||||
#endif
|
||||
|
||||
/// @brief access the first element
|
||||
/// @sa https://json.nlohmann.me/api/basic_json/front/
|
||||
@@ -3849,15 +3859,11 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
|
||||
|
||||
template<typename BasicJsonType, detail::enable_if_t<detail::is_basic_json<BasicJsonType>::value, int> = 0>
|
||||
JSON_HEDLEY_WARN_UNUSED_RESULT
|
||||
#if JSON_DELETE_DEPRECATED_FUNCTIONS
|
||||
bool contains(const typename ::nlohmann::json_pointer<BasicJsonType>& ptr) const = delete;
|
||||
#else
|
||||
JSON_HEDLEY_DEPRECATED_FOR(3.11.0, basic_json::json_pointer or nlohmann::json_pointer<basic_json::string_t>) // NOLINT(readability/alt_tokens)
|
||||
bool contains(const typename ::nlohmann::json_pointer<BasicJsonType>& ptr) const
|
||||
{
|
||||
return ptr.contains(this);
|
||||
}
|
||||
#endif
|
||||
|
||||
/// @}
|
||||
|
||||
@@ -3966,30 +3972,22 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
|
||||
/// @deprecated This function is deprecated since 3.1.0 and will be removed in
|
||||
/// version 4.0.0 of the library. Please use @ref items() instead;
|
||||
/// that is, replace `json::iterator_wrapper(j)` with `j.items()`.
|
||||
#if JSON_DELETE_DEPRECATED_FUNCTIONS
|
||||
static iteration_proxy<iterator> iterator_wrapper(reference ref) noexcept = delete;
|
||||
#else
|
||||
JSON_HEDLEY_DEPRECATED_FOR(3.1.0, items())
|
||||
static iteration_proxy<iterator> iterator_wrapper(reference ref) noexcept
|
||||
{
|
||||
return ref.items();
|
||||
}
|
||||
#endif
|
||||
|
||||
/// @brief wrapper to access iterator member functions in range-based for
|
||||
/// @sa https://json.nlohmann.me/api/basic_json/items/
|
||||
/// @deprecated This function is deprecated since 3.1.0 and will be removed in
|
||||
/// version 4.0.0 of the library. Please use @ref items() instead;
|
||||
/// that is, replace `json::iterator_wrapper(j)` with `j.items()`.
|
||||
#if JSON_DELETE_DEPRECATED_FUNCTIONS
|
||||
static iteration_proxy<const_iterator> iterator_wrapper(const_reference ref) noexcept = delete;
|
||||
#else
|
||||
JSON_HEDLEY_DEPRECATED_FOR(3.1.0, items())
|
||||
static iteration_proxy<const_iterator> iterator_wrapper(const_reference ref) noexcept
|
||||
{
|
||||
return ref.items();
|
||||
}
|
||||
#endif
|
||||
|
||||
/// @brief helper to access iterator member functions in range-based for
|
||||
/// @sa https://json.nlohmann.me/api/basic_json/items/
|
||||
@@ -5078,7 +5076,7 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
|
||||
/// @sa https://json.nlohmann.me/api/basic_json/operator_le/
|
||||
template<typename ScalarType>
|
||||
requires std::is_scalar_v<ScalarType>
|
||||
friend bool operator<=(ScalarType lhs, const_reference rhs) noexcept
|
||||
friend bool operator<=(ScalarType lhs, const_reference rhs) noexcept(std::is_nothrow_constructible<basic_json, ScalarType>::value)
|
||||
{
|
||||
return basic_json(lhs) <= rhs;
|
||||
}
|
||||
@@ -5087,7 +5085,7 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
|
||||
/// @sa https://json.nlohmann.me/api/basic_json/operator_ge/
|
||||
template<typename ScalarType>
|
||||
requires std::is_scalar_v<ScalarType>
|
||||
friend bool operator>=(ScalarType lhs, const_reference rhs) noexcept
|
||||
friend bool operator>=(ScalarType lhs, const_reference rhs) noexcept(std::is_nothrow_constructible<basic_json, ScalarType>::value)
|
||||
{
|
||||
return basic_json(lhs) >= rhs;
|
||||
}
|
||||
@@ -5305,15 +5303,11 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
|
||||
/// version 4.0.0 of the library. Please use
|
||||
/// operator<<(std::ostream&, const basic_json&) instead; that is,
|
||||
/// replace calls like `j >> o;` with `o << j;`.
|
||||
#if JSON_DELETE_DEPRECATED_FUNCTIONS
|
||||
friend std::ostream& operator>>(const basic_json& j, std::ostream& o) = delete;
|
||||
#else
|
||||
JSON_HEDLEY_DEPRECATED_FOR(3.0.0, operator<<(std::ostream&, const basic_json&))
|
||||
friend std::ostream& operator>>(const basic_json& j, std::ostream& o)
|
||||
{
|
||||
return o << j;
|
||||
}
|
||||
#endif
|
||||
#endif // JSON_NO_IO
|
||||
/// @}
|
||||
|
||||
@@ -5359,13 +5353,6 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
|
||||
}
|
||||
|
||||
JSON_HEDLEY_WARN_UNUSED_RESULT
|
||||
#if JSON_DELETE_DEPRECATED_FUNCTIONS
|
||||
static basic_json parse(detail::span_input_adapter&& i,
|
||||
parser_callback_t cb = nullptr,
|
||||
const bool allow_exceptions = true,
|
||||
const bool ignore_comments = false,
|
||||
const bool ignore_trailing_commas = false) = delete;
|
||||
#else
|
||||
JSON_HEDLEY_DEPRECATED_FOR(3.8.0, parse(ptr, ptr + len))
|
||||
static basic_json parse(detail::span_input_adapter&& i,
|
||||
parser_callback_t cb = nullptr,
|
||||
@@ -5378,7 +5365,6 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
|
||||
p.parse(true, result);
|
||||
return result;
|
||||
}
|
||||
#endif
|
||||
|
||||
/// @brief check if the input is valid JSON
|
||||
/// @sa https://json.nlohmann.me/api/basic_json/accept/
|
||||
@@ -5404,11 +5390,6 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
|
||||
}
|
||||
|
||||
JSON_HEDLEY_WARN_UNUSED_RESULT
|
||||
#if JSON_DELETE_DEPRECATED_FUNCTIONS
|
||||
static bool accept(detail::span_input_adapter&& i,
|
||||
const bool ignore_comments = false,
|
||||
const bool ignore_trailing_commas = false) = delete;
|
||||
#else
|
||||
JSON_HEDLEY_DEPRECATED_FOR(3.8.0, accept(ptr, ptr + len))
|
||||
static bool accept(detail::span_input_adapter&& i,
|
||||
const bool ignore_comments = false,
|
||||
@@ -5416,7 +5397,6 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
|
||||
{
|
||||
return parser(i.get(), nullptr, false, ignore_comments, ignore_trailing_commas, true).accept(true);
|
||||
}
|
||||
#endif
|
||||
|
||||
/// @brief generate SAX events
|
||||
/// @sa https://json.nlohmann.me/api/basic_json/sax_parse/
|
||||
@@ -5470,14 +5450,6 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
|
||||
#pragma clang diagnostic ignored "-Wdocumentation-deprecated-sync"
|
||||
#endif
|
||||
template <typename SAX>
|
||||
#if JSON_DELETE_DEPRECATED_FUNCTIONS
|
||||
JSON_HEDLEY_NON_NULL(2)
|
||||
static bool sax_parse(detail::span_input_adapter&& i, SAX* sax,
|
||||
input_format_t format = input_format_t::json,
|
||||
const bool strict = true,
|
||||
const bool ignore_comments = false,
|
||||
const bool ignore_trailing_commas = false) = delete;
|
||||
#else
|
||||
JSON_HEDLEY_DEPRECATED_FOR(3.8.0, sax_parse(ptr, ptr + len, ...))
|
||||
JSON_HEDLEY_NON_NULL(2)
|
||||
static bool sax_parse(detail::span_input_adapter&& i, SAX* sax,
|
||||
@@ -5493,7 +5465,6 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
|
||||
// NOLINTNEXTLINE(hicpp-move-const-arg,performance-move-const-arg)
|
||||
: detail::binary_reader<basic_json, decltype(ia), SAX>(std::move(ia), format).sax_parse(sax, strict);
|
||||
}
|
||||
#endif
|
||||
#if defined(__clang__)
|
||||
#pragma clang diagnostic pop
|
||||
#endif
|
||||
@@ -5504,15 +5475,11 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
|
||||
/// version 4.0.0 of the library. Please use
|
||||
/// operator>>(std::istream&, basic_json&) instead; that is,
|
||||
/// replace calls like `j << i;` with `i >> j;`.
|
||||
#if JSON_DELETE_DEPRECATED_FUNCTIONS
|
||||
friend std::istream& operator<<(basic_json& j, std::istream& i) = delete;
|
||||
#else
|
||||
JSON_HEDLEY_DEPRECATED_FOR(3.0.0, operator>>(std::istream&, basic_json&))
|
||||
friend std::istream& operator<<(basic_json& j, std::istream& i)
|
||||
{
|
||||
return operator>>(i, j);
|
||||
}
|
||||
#endif
|
||||
|
||||
/// @brief deserialize from stream
|
||||
/// @sa https://json.nlohmann.me/api/operator_gtgt/
|
||||
@@ -5855,12 +5822,6 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
|
||||
|
||||
template<typename T>
|
||||
JSON_HEDLEY_WARN_UNUSED_RESULT
|
||||
#if JSON_DELETE_DEPRECATED_FUNCTIONS
|
||||
static basic_json from_cbor(const T* ptr, std::size_t len,
|
||||
const bool strict = true,
|
||||
const bool allow_exceptions = true,
|
||||
const cbor_tag_handler_t tag_handler = cbor_tag_handler_t::error) = delete;
|
||||
#else
|
||||
JSON_HEDLEY_DEPRECATED_FOR(3.8.0, from_cbor(ptr, ptr + len))
|
||||
static basic_json from_cbor(const T* ptr, std::size_t len,
|
||||
const bool strict = true,
|
||||
@@ -5869,15 +5830,8 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
|
||||
{
|
||||
return from_cbor(ptr, ptr + len, strict, allow_exceptions, tag_handler);
|
||||
}
|
||||
#endif
|
||||
|
||||
JSON_HEDLEY_WARN_UNUSED_RESULT
|
||||
#if JSON_DELETE_DEPRECATED_FUNCTIONS
|
||||
static basic_json from_cbor(detail::span_input_adapter&& i,
|
||||
const bool strict = true,
|
||||
const bool allow_exceptions = true,
|
||||
const cbor_tag_handler_t tag_handler = cbor_tag_handler_t::error) = delete;
|
||||
#else
|
||||
JSON_HEDLEY_DEPRECATED_FOR(3.8.0, from_cbor(ptr, ptr + len))
|
||||
static basic_json from_cbor(detail::span_input_adapter&& i,
|
||||
const bool strict = true,
|
||||
@@ -5886,7 +5840,6 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
|
||||
{
|
||||
return from_binary_impl(i.get(), input_format_t::cbor, strict, allow_exceptions, error_handler_t::keep, tag_handler);
|
||||
}
|
||||
#endif
|
||||
|
||||
/// @brief create a JSON value from an input in MessagePack format
|
||||
/// @sa https://json.nlohmann.me/api/basic_json/from_msgpack/
|
||||
@@ -5915,11 +5868,6 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
|
||||
|
||||
template<typename T>
|
||||
JSON_HEDLEY_WARN_UNUSED_RESULT
|
||||
#if JSON_DELETE_DEPRECATED_FUNCTIONS
|
||||
static basic_json from_msgpack(const T* ptr, std::size_t len,
|
||||
const bool strict = true,
|
||||
const bool allow_exceptions = true) = delete;
|
||||
#else
|
||||
JSON_HEDLEY_DEPRECATED_FOR(3.8.0, from_msgpack(ptr, ptr + len))
|
||||
static basic_json from_msgpack(const T* ptr, std::size_t len,
|
||||
const bool strict = true,
|
||||
@@ -5927,14 +5875,8 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
|
||||
{
|
||||
return from_msgpack(ptr, ptr + len, strict, allow_exceptions);
|
||||
}
|
||||
#endif
|
||||
|
||||
JSON_HEDLEY_WARN_UNUSED_RESULT
|
||||
#if JSON_DELETE_DEPRECATED_FUNCTIONS
|
||||
static basic_json from_msgpack(detail::span_input_adapter&& i,
|
||||
const bool strict = true,
|
||||
const bool allow_exceptions = true) = delete;
|
||||
#else
|
||||
JSON_HEDLEY_DEPRECATED_FOR(3.8.0, from_msgpack(ptr, ptr + len))
|
||||
static basic_json from_msgpack(detail::span_input_adapter&& i,
|
||||
const bool strict = true,
|
||||
@@ -5942,7 +5884,6 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
|
||||
{
|
||||
return from_binary_impl(i.get(), input_format_t::msgpack, strict, allow_exceptions);
|
||||
}
|
||||
#endif
|
||||
|
||||
/// @brief create a JSON value from an input in UBJSON format
|
||||
/// @sa https://json.nlohmann.me/api/basic_json/from_ubjson/
|
||||
@@ -5971,11 +5912,6 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
|
||||
|
||||
template<typename T>
|
||||
JSON_HEDLEY_WARN_UNUSED_RESULT
|
||||
#if JSON_DELETE_DEPRECATED_FUNCTIONS
|
||||
static basic_json from_ubjson(const T* ptr, std::size_t len,
|
||||
const bool strict = true,
|
||||
const bool allow_exceptions = true) = delete;
|
||||
#else
|
||||
JSON_HEDLEY_DEPRECATED_FOR(3.8.0, from_ubjson(ptr, ptr + len))
|
||||
static basic_json from_ubjson(const T* ptr, std::size_t len,
|
||||
const bool strict = true,
|
||||
@@ -5983,14 +5919,8 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
|
||||
{
|
||||
return from_ubjson(ptr, ptr + len, strict, allow_exceptions);
|
||||
}
|
||||
#endif
|
||||
|
||||
JSON_HEDLEY_WARN_UNUSED_RESULT
|
||||
#if JSON_DELETE_DEPRECATED_FUNCTIONS
|
||||
static basic_json from_ubjson(detail::span_input_adapter&& i,
|
||||
const bool strict = true,
|
||||
const bool allow_exceptions = true) = delete;
|
||||
#else
|
||||
JSON_HEDLEY_DEPRECATED_FOR(3.8.0, from_ubjson(ptr, ptr + len))
|
||||
static basic_json from_ubjson(detail::span_input_adapter&& i,
|
||||
const bool strict = true,
|
||||
@@ -5998,7 +5928,6 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
|
||||
{
|
||||
return from_binary_impl(i.get(), input_format_t::ubjson, strict, allow_exceptions);
|
||||
}
|
||||
#endif
|
||||
|
||||
/// @brief create a JSON value from an input in BJData format
|
||||
/// @sa https://json.nlohmann.me/api/basic_json/from_bjdata/
|
||||
@@ -6025,22 +5954,6 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
|
||||
return from_binary_impl(detail::input_adapter(std::move(first), std::move(last)), input_format_t::bjdata, strict, allow_exceptions, error_handler);
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
JSON_HEDLEY_WARN_UNUSED_RESULT
|
||||
#if JSON_DELETE_DEPRECATED_FUNCTIONS
|
||||
static basic_json from_bjdata(const T* ptr, std::size_t len,
|
||||
const bool strict = true,
|
||||
const bool allow_exceptions = true) = delete;
|
||||
#else
|
||||
JSON_HEDLEY_DEPRECATED_FOR(3.13.0, from_bjdata(ptr, ptr + len))
|
||||
static basic_json from_bjdata(const T* ptr, std::size_t len,
|
||||
const bool strict = true,
|
||||
const bool allow_exceptions = true)
|
||||
{
|
||||
return from_bjdata(ptr, ptr + len, strict, allow_exceptions);
|
||||
}
|
||||
#endif
|
||||
|
||||
/// @brief create a JSON value from an input in BON8 format
|
||||
/// @sa https://json.nlohmann.me/api/basic_json/from_bon8/
|
||||
template<typename InputType>
|
||||
@@ -6064,22 +5977,6 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
|
||||
return from_binary_impl(detail::input_adapter(std::move(first), std::move(last)), input_format_t::bon8, strict, allow_exceptions);
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
JSON_HEDLEY_WARN_UNUSED_RESULT
|
||||
#if JSON_DELETE_DEPRECATED_FUNCTIONS
|
||||
static basic_json from_bon8(const T* ptr, std::size_t len,
|
||||
const bool strict = true,
|
||||
const bool allow_exceptions = true) = delete;
|
||||
#else
|
||||
JSON_HEDLEY_DEPRECATED_FOR(3.13.0, from_bon8(ptr, ptr + len))
|
||||
static basic_json from_bon8(const T* ptr, std::size_t len,
|
||||
const bool strict = true,
|
||||
const bool allow_exceptions = true)
|
||||
{
|
||||
return from_bon8(ptr, ptr + len, strict, allow_exceptions);
|
||||
}
|
||||
#endif
|
||||
|
||||
/// @brief create a JSON value from an input in BSON format
|
||||
/// @sa https://json.nlohmann.me/api/basic_json/from_bson/
|
||||
template<typename InputType>
|
||||
@@ -6107,11 +6004,6 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
|
||||
|
||||
template<typename T>
|
||||
JSON_HEDLEY_WARN_UNUSED_RESULT
|
||||
#if JSON_DELETE_DEPRECATED_FUNCTIONS
|
||||
static basic_json from_bson(const T* ptr, std::size_t len,
|
||||
const bool strict = true,
|
||||
const bool allow_exceptions = true) = delete;
|
||||
#else
|
||||
JSON_HEDLEY_DEPRECATED_FOR(3.8.0, from_bson(ptr, ptr + len))
|
||||
static basic_json from_bson(const T* ptr, std::size_t len,
|
||||
const bool strict = true,
|
||||
@@ -6119,14 +6011,8 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
|
||||
{
|
||||
return from_bson(ptr, ptr + len, strict, allow_exceptions);
|
||||
}
|
||||
#endif
|
||||
|
||||
JSON_HEDLEY_WARN_UNUSED_RESULT
|
||||
#if JSON_DELETE_DEPRECATED_FUNCTIONS
|
||||
static basic_json from_bson(detail::span_input_adapter&& i,
|
||||
const bool strict = true,
|
||||
const bool allow_exceptions = true) = delete;
|
||||
#else
|
||||
JSON_HEDLEY_DEPRECATED_FOR(3.8.0, from_bson(ptr, ptr + len))
|
||||
static basic_json from_bson(detail::span_input_adapter&& i,
|
||||
const bool strict = true,
|
||||
@@ -6134,7 +6020,6 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
|
||||
{
|
||||
return from_binary_impl(i.get(), input_format_t::bson, strict, allow_exceptions);
|
||||
}
|
||||
#endif
|
||||
/// @}
|
||||
|
||||
//////////////////////////
|
||||
@@ -6152,15 +6037,11 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
|
||||
}
|
||||
|
||||
template<typename BasicJsonType, detail::enable_if_t<detail::is_basic_json<BasicJsonType>::value, int> = 0>
|
||||
#if JSON_DELETE_DEPRECATED_FUNCTIONS
|
||||
reference operator[](const ::nlohmann::json_pointer<BasicJsonType>& ptr) = delete;
|
||||
#else
|
||||
JSON_HEDLEY_DEPRECATED_FOR(3.11.0, basic_json::json_pointer or nlohmann::json_pointer<basic_json::string_t>) // NOLINT(readability/alt_tokens)
|
||||
reference operator[](const ::nlohmann::json_pointer<BasicJsonType>& ptr)
|
||||
{
|
||||
return ptr.get_unchecked(this);
|
||||
}
|
||||
#endif
|
||||
|
||||
/// @brief access specified element via JSON Pointer
|
||||
/// @sa https://json.nlohmann.me/api/basic_json/operator%5B%5D/
|
||||
@@ -6170,15 +6051,11 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
|
||||
}
|
||||
|
||||
template<typename BasicJsonType, detail::enable_if_t<detail::is_basic_json<BasicJsonType>::value, int> = 0>
|
||||
#if JSON_DELETE_DEPRECATED_FUNCTIONS
|
||||
const_reference operator[](const ::nlohmann::json_pointer<BasicJsonType>& ptr) const = delete;
|
||||
#else
|
||||
JSON_HEDLEY_DEPRECATED_FOR(3.11.0, basic_json::json_pointer or nlohmann::json_pointer<basic_json::string_t>) // NOLINT(readability/alt_tokens)
|
||||
const_reference operator[](const ::nlohmann::json_pointer<BasicJsonType>& ptr) const
|
||||
{
|
||||
return ptr.get_unchecked(this);
|
||||
}
|
||||
#endif
|
||||
|
||||
/// @brief access specified element via JSON Pointer
|
||||
/// @sa https://json.nlohmann.me/api/basic_json/at/
|
||||
@@ -6188,15 +6065,11 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
|
||||
}
|
||||
|
||||
template<typename BasicJsonType, detail::enable_if_t<detail::is_basic_json<BasicJsonType>::value, int> = 0>
|
||||
#if JSON_DELETE_DEPRECATED_FUNCTIONS
|
||||
reference at(const ::nlohmann::json_pointer<BasicJsonType>& ptr) = delete;
|
||||
#else
|
||||
JSON_HEDLEY_DEPRECATED_FOR(3.11.0, basic_json::json_pointer or nlohmann::json_pointer<basic_json::string_t>) // NOLINT(readability/alt_tokens)
|
||||
reference at(const ::nlohmann::json_pointer<BasicJsonType>& ptr)
|
||||
{
|
||||
return ptr.get_checked(this);
|
||||
}
|
||||
#endif
|
||||
|
||||
/// @brief access specified element via JSON Pointer
|
||||
/// @sa https://json.nlohmann.me/api/basic_json/at/
|
||||
@@ -6206,15 +6079,11 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
|
||||
}
|
||||
|
||||
template<typename BasicJsonType, detail::enable_if_t<detail::is_basic_json<BasicJsonType>::value, int> = 0>
|
||||
#if JSON_DELETE_DEPRECATED_FUNCTIONS
|
||||
const_reference at(const ::nlohmann::json_pointer<BasicJsonType>& ptr) const = delete;
|
||||
#else
|
||||
JSON_HEDLEY_DEPRECATED_FOR(3.11.0, basic_json::json_pointer or nlohmann::json_pointer<basic_json::string_t>) // NOLINT(readability/alt_tokens)
|
||||
const_reference at(const ::nlohmann::json_pointer<BasicJsonType>& ptr) const
|
||||
{
|
||||
return ptr.get_checked(this);
|
||||
}
|
||||
#endif
|
||||
|
||||
/// @brief return flattened JSON value
|
||||
/// @sa https://json.nlohmann.me/api/basic_json/flatten/
|
||||
|
||||
@@ -12,7 +12,7 @@
|
||||
#include <functional> // equal_to, less
|
||||
#include <initializer_list> // initializer_list
|
||||
#include <iterator> // input_iterator_tag, iterator_traits
|
||||
#include <memory> // allocator
|
||||
#include <memory> // allocator // IWYU pragma: keep
|
||||
#include <new> // for operator new (placement new)
|
||||
#include <stdexcept> // for out_of_range
|
||||
#include <tuple> // forward_as_tuple
|
||||
@@ -78,7 +78,7 @@ private:
|
||||
/// @brief find the entry for @a key, for either constness of @a self
|
||||
/// @note the single place that performs the linear key search
|
||||
template<typename Self, typename KeyType>
|
||||
static auto find_impl(Self& self, KeyType&& key) -> decltype(self.begin())
|
||||
static auto find_impl(Self& self, const KeyType& key) -> decltype(self.begin())
|
||||
{
|
||||
for (auto it = self.begin(); it != self.end(); ++it)
|
||||
{
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -3214,10 +3214,6 @@ JSON_HEDLEY_DIAGNOSTIC_POP
|
||||
#define JSON_DISABLE_ENUM_SERIALIZATION 0
|
||||
#endif
|
||||
|
||||
#ifndef JSON_DELETE_DEPRECATED_FUNCTIONS
|
||||
#define JSON_DELETE_DEPRECATED_FUNCTIONS 0
|
||||
#endif
|
||||
|
||||
#ifndef JSON_DISABLE_TUPLE_REFERENCE_CONVERSION
|
||||
#define JSON_DISABLE_TUPLE_REFERENCE_CONVERSION 0
|
||||
#endif
|
||||
@@ -13700,15 +13696,15 @@ class binary_reader
|
||||
|
||||
@param[in] adapter input adapter to read from
|
||||
@param[in] format the binary format to parse
|
||||
@param[in] error_handler how to treat text strings and object keys that
|
||||
@param[in] error_handler_ how to treat text strings and object keys that
|
||||
are not well-formed UTF-8; none of the supported formats
|
||||
requires a decoder to reject those, so the default is to
|
||||
@ref error_handler_t::keep them unchanged, as every binary
|
||||
reader did before this parameter existed
|
||||
*/
|
||||
explicit binary_reader(InputAdapterType&& adapter, const input_format_t format = input_format_t::json,
|
||||
const error_handler_t error_handler = error_handler_t::keep) noexcept
|
||||
: ia(std::move(adapter)), input_format(format), error_handler(error_handler)
|
||||
const error_handler_t error_handler_ = error_handler_t::keep) noexcept
|
||||
: ia(std::move(adapter)), input_format(format), error_handler(error_handler_)
|
||||
{
|
||||
(void)detail::is_sax_static_asserts<SAX, BasicJsonType> {};
|
||||
}
|
||||
@@ -19759,15 +19755,11 @@ class json_pointer
|
||||
|
||||
/// @brief return a string representation of the JSON pointer
|
||||
/// @sa https://json.nlohmann.me/api/json_pointer/operator_string_t/
|
||||
#if JSON_DELETE_DEPRECATED_FUNCTIONS
|
||||
operator string_t() const = delete;
|
||||
#else
|
||||
JSON_HEDLEY_DEPRECATED_FOR(3.11.0, to_string())
|
||||
operator string_t() const
|
||||
{
|
||||
return to_string();
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifndef JSON_NO_IO
|
||||
/// @brief write string representation of the JSON pointer to stream
|
||||
@@ -20006,6 +19998,8 @@ class json_pointer
|
||||
typename BasicJsonType::size_type idx{};
|
||||
switch (parse_array_index<BasicJsonType>(s, idx))
|
||||
{
|
||||
// the branches differ in their messages, not after JSON_THROW's expansion
|
||||
// NOLINTNEXTLINE(bugprone-branch-clone)
|
||||
case array_index_status::leading_zero:
|
||||
JSON_THROW(detail::parse_error::create(106, 0, detail::concat("array index '", s, "' must not begin with '0'"), nullptr));
|
||||
case array_index_status::not_a_number:
|
||||
@@ -20369,6 +20363,8 @@ class json_pointer
|
||||
typename BasicJsonType::size_type idx{};
|
||||
switch (parse_array_index<BasicJsonType>(reference_token, idx))
|
||||
{
|
||||
// the branches differ in their messages, not after JSON_THROW's expansion
|
||||
// NOLINTNEXTLINE(bugprone-branch-clone)
|
||||
case array_index_status::leading_zero:
|
||||
JSON_THROW(detail::parse_error::create(106, 0, detail::concat("array index '", reference_token, "' must not begin with '0'"), nullptr));
|
||||
case array_index_status::not_a_number:
|
||||
@@ -20700,15 +20696,11 @@ class json_pointer
|
||||
|
||||
/// @brief compares JSON pointer and string for equality
|
||||
/// @sa https://json.nlohmann.me/api/json_pointer/operator_eq/
|
||||
#if JSON_DELETE_DEPRECATED_FUNCTIONS
|
||||
bool operator==(const string_t& rhs) const = delete;
|
||||
#else
|
||||
JSON_HEDLEY_DEPRECATED_FOR(3.11.2, operator==(json_pointer))
|
||||
bool operator==(const string_t& rhs) const
|
||||
{
|
||||
return *this == json_pointer(rhs);
|
||||
}
|
||||
#endif
|
||||
|
||||
/// @brief 3-way compares two JSON pointers
|
||||
template<typename RefStringTypeRhs>
|
||||
@@ -20783,31 +20775,21 @@ inline bool operator==(const json_pointer<RefStringTypeLhs>& lhs,
|
||||
|
||||
template<typename RefStringTypeLhs,
|
||||
typename StringType = typename json_pointer<RefStringTypeLhs>::string_t>
|
||||
#if JSON_DELETE_DEPRECATED_FUNCTIONS
|
||||
inline bool operator==(const json_pointer<RefStringTypeLhs>& lhs,
|
||||
const StringType& rhs) = delete;
|
||||
#else
|
||||
JSON_HEDLEY_DEPRECATED_FOR(3.11.2, operator==(json_pointer, json_pointer))
|
||||
inline bool operator==(const json_pointer<RefStringTypeLhs>& lhs,
|
||||
const StringType& rhs)
|
||||
{
|
||||
return lhs == json_pointer<RefStringTypeLhs>(rhs);
|
||||
}
|
||||
#endif
|
||||
|
||||
template<typename RefStringTypeRhs,
|
||||
typename StringType = typename json_pointer<RefStringTypeRhs>::string_t>
|
||||
#if JSON_DELETE_DEPRECATED_FUNCTIONS
|
||||
inline bool operator==(const StringType& lhs,
|
||||
const json_pointer<RefStringTypeRhs>& rhs) = delete;
|
||||
#else
|
||||
JSON_HEDLEY_DEPRECATED_FOR(3.11.2, operator==(json_pointer, json_pointer))
|
||||
inline bool operator==(const StringType& lhs,
|
||||
const json_pointer<RefStringTypeRhs>& rhs)
|
||||
{
|
||||
return json_pointer<RefStringTypeRhs>(lhs) == rhs;
|
||||
}
|
||||
#endif
|
||||
|
||||
template<typename RefStringTypeLhs, typename RefStringTypeRhs>
|
||||
inline bool operator!=(const json_pointer<RefStringTypeLhs>& lhs,
|
||||
@@ -20818,31 +20800,21 @@ inline bool operator!=(const json_pointer<RefStringTypeLhs>& lhs,
|
||||
|
||||
template<typename RefStringTypeLhs,
|
||||
typename StringType = typename json_pointer<RefStringTypeLhs>::string_t>
|
||||
#if JSON_DELETE_DEPRECATED_FUNCTIONS
|
||||
inline bool operator!=(const json_pointer<RefStringTypeLhs>& lhs,
|
||||
const StringType& rhs) = delete;
|
||||
#else
|
||||
JSON_HEDLEY_DEPRECATED_FOR(3.11.2, operator!=(json_pointer, json_pointer))
|
||||
inline bool operator!=(const json_pointer<RefStringTypeLhs>& lhs,
|
||||
const StringType& rhs)
|
||||
{
|
||||
return !(lhs == rhs);
|
||||
}
|
||||
#endif
|
||||
|
||||
template<typename RefStringTypeRhs,
|
||||
typename StringType = typename json_pointer<RefStringTypeRhs>::string_t>
|
||||
#if JSON_DELETE_DEPRECATED_FUNCTIONS
|
||||
inline bool operator!=(const StringType& lhs,
|
||||
const json_pointer<RefStringTypeRhs>& rhs) = delete;
|
||||
#else
|
||||
JSON_HEDLEY_DEPRECATED_FOR(3.11.2, operator!=(json_pointer, json_pointer))
|
||||
inline bool operator!=(const StringType& lhs,
|
||||
const json_pointer<RefStringTypeRhs>& rhs)
|
||||
{
|
||||
return !(lhs == rhs);
|
||||
}
|
||||
#endif
|
||||
|
||||
template<typename RefStringTypeLhs, typename RefStringTypeRhs>
|
||||
inline bool operator<(const json_pointer<RefStringTypeLhs>& lhs,
|
||||
@@ -23517,18 +23489,18 @@ class binary_writer
|
||||
switch (error_handler)
|
||||
{
|
||||
case error_handler_t::keep:
|
||||
return s;
|
||||
return s; // NOLINT(bugprone-return-const-ref-from-parameter): callers pass lvalues that outlive the call
|
||||
|
||||
case error_handler_t::strict:
|
||||
check_utf8(s, context);
|
||||
return s;
|
||||
return s; // NOLINT(bugprone-return-const-ref-from-parameter): callers pass lvalues that outlive the call
|
||||
|
||||
case error_handler_t::replace:
|
||||
case error_handler_t::ignore:
|
||||
default:
|
||||
if (is_valid_utf8(s))
|
||||
{
|
||||
return s;
|
||||
return s; // NOLINT(bugprone-return-const-ref-from-parameter): callers pass lvalues that outlive the call
|
||||
}
|
||||
storage = sanitize_utf8(s, error_handler);
|
||||
return storage;
|
||||
@@ -25713,6 +25685,11 @@ class serializer
|
||||
@a ensure_ascii is a template parameter here so that the branch on it is
|
||||
resolved once, outside the loop; see @ref dump_escaped.
|
||||
*/
|
||||
#ifdef JSON_HEDLEY_MSVC_VERSION
|
||||
#pragma warning(push)
|
||||
// EnsureAscii is a template parameter; C++11 has no if constexpr
|
||||
#pragma warning(disable : 4127) // conditional expression is constant
|
||||
#endif
|
||||
template<bool EnsureAscii>
|
||||
void dump_escaped_impl(const string_t& s)
|
||||
{
|
||||
@@ -26062,6 +26039,9 @@ class serializer
|
||||
}
|
||||
}
|
||||
}
|
||||
#ifdef JSON_HEDLEY_MSVC_VERSION
|
||||
#pragma warning(pop)
|
||||
#endif
|
||||
|
||||
private:
|
||||
/*!
|
||||
@@ -26644,7 +26624,7 @@ NLOHMANN_JSON_NAMESPACE_END
|
||||
#include <functional> // equal_to, less
|
||||
#include <initializer_list> // initializer_list
|
||||
#include <iterator> // input_iterator_tag, iterator_traits
|
||||
#include <memory> // allocator
|
||||
#include <memory> // allocator // IWYU pragma: keep
|
||||
#include <new> // for operator new (placement new)
|
||||
#include <stdexcept> // for out_of_range
|
||||
#include <tuple> // forward_as_tuple
|
||||
@@ -26713,7 +26693,7 @@ private:
|
||||
/// @brief find the entry for @a key, for either constness of @a self
|
||||
/// @note the single place that performs the linear key search
|
||||
template<typename Self, typename KeyType>
|
||||
static auto find_impl(Self& self, KeyType&& key) -> decltype(self.begin())
|
||||
static auto find_impl(Self& self, const KeyType& key) -> decltype(self.begin())
|
||||
{
|
||||
for (auto it = self.begin(); it != self.end(); ++it)
|
||||
{
|
||||
@@ -28017,6 +27997,7 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
|
||||
never name it to call this constructor itself.
|
||||
*/
|
||||
basic_json(copy_construct_tag /*unused*/, const basic_json& src)
|
||||
noexcept(std::is_nothrow_copy_constructible<json_base_class_t>::value)
|
||||
: json_base_class_t(src)
|
||||
#if JSON_DIAGNOSTIC_POSITIONS
|
||||
, start_position(src.start_position)
|
||||
@@ -28411,7 +28392,7 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
|
||||
be destroyed.
|
||||
*/
|
||||
template<typename BasicJsonType>
|
||||
void convert_iteratively(const BasicJsonType& val)
|
||||
void convert_iteratively(const BasicJsonType& val, std::true_type /*unused*/)
|
||||
{
|
||||
using other_const_iterator = typename BasicJsonType::const_iterator;
|
||||
|
||||
@@ -28505,21 +28486,38 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
|
||||
|
||||
if (JSON_HEDLEY_LIKELY(guard.okay()))
|
||||
{
|
||||
// every element comes back to the converting constructor
|
||||
if (val.is_object())
|
||||
{
|
||||
using other_object_t = typename BasicJsonType::object_t;
|
||||
JSONSerializer<other_object_t>::to_json(*this, val.template get_ref<const other_object_t&>());
|
||||
}
|
||||
else
|
||||
{
|
||||
using other_array_t = typename BasicJsonType::array_t;
|
||||
JSONSerializer<other_array_t>::to_json(*this, val.template get_ref<const other_array_t&>());
|
||||
}
|
||||
convert_by_serializers(val);
|
||||
return;
|
||||
}
|
||||
|
||||
convert_iteratively(val);
|
||||
// the iterative conversion needs to construct this object type's keys
|
||||
// from those of @a val; if it cannot, neither can the range constructor,
|
||||
// and the serializers convert @a val some other way (see #3425)
|
||||
convert_iteratively(val, std::is_constructible<typename object_t::key_type, const typename BasicJsonType::string_t&> {});
|
||||
}
|
||||
|
||||
/// @brief convert the object or array @a val with the serializers; every
|
||||
/// element comes back to the converting constructor
|
||||
template<typename BasicJsonType>
|
||||
void convert_by_serializers(const BasicJsonType& val)
|
||||
{
|
||||
if (val.is_object())
|
||||
{
|
||||
using other_object_t = typename BasicJsonType::object_t;
|
||||
JSONSerializer<other_object_t>::to_json(*this, val.template get_ref<const other_object_t&>());
|
||||
}
|
||||
else
|
||||
{
|
||||
using other_array_t = typename BasicJsonType::array_t;
|
||||
JSONSerializer<other_array_t>::to_json(*this, val.template get_ref<const other_array_t&>());
|
||||
}
|
||||
}
|
||||
|
||||
/// @brief convert @a val whose keys cannot be converted, see @ref convert_structured
|
||||
template<typename BasicJsonType>
|
||||
void convert_iteratively(const BasicJsonType& val, std::false_type /*unused*/)
|
||||
{
|
||||
convert_by_serializers(val);
|
||||
}
|
||||
|
||||
|
||||
@@ -28593,15 +28591,15 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
|
||||
static compare_result compare_leaves(const_reference lhs, const_reference rhs, std::true_type /*ordered*/) noexcept
|
||||
{
|
||||
const std::partial_ordering order = lhs <=> rhs; // *NOPAD*
|
||||
if (order == 0)
|
||||
if (std::is_eq(order))
|
||||
{
|
||||
return compare_result::equal;
|
||||
}
|
||||
if (order < 0)
|
||||
if (std::is_lt(order))
|
||||
{
|
||||
return compare_result::less;
|
||||
}
|
||||
if (order > 0)
|
||||
if (std::is_gt(order))
|
||||
{
|
||||
return compare_result::greater;
|
||||
}
|
||||
@@ -30439,30 +30437,22 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
|
||||
detail::is_basic_json<BasicJsonType>::value
|
||||
&& detail::is_getable<basic_json_t, ValueType>::value
|
||||
&& !std::is_same<value_t, detail::uncvref_t<ValueType>>::value, int > = 0 >
|
||||
#if JSON_DELETE_DEPRECATED_FUNCTIONS
|
||||
ValueType value(const ::nlohmann::json_pointer<BasicJsonType>& ptr, const ValueType& default_value) const = delete;
|
||||
#else
|
||||
JSON_HEDLEY_DEPRECATED_FOR(3.11.0, basic_json::json_pointer or nlohmann::json_pointer<basic_json::string_t>) // NOLINT(readability/alt_tokens)
|
||||
ValueType value(const ::nlohmann::json_pointer<BasicJsonType>& ptr, const ValueType& default_value) const
|
||||
{
|
||||
return value(ptr.convert(), default_value);
|
||||
}
|
||||
#endif
|
||||
|
||||
template < class ValueType, class BasicJsonType, class ReturnType = typename value_return_type<ValueType>::type,
|
||||
detail::enable_if_t <
|
||||
detail::is_basic_json<BasicJsonType>::value
|
||||
&& detail::is_getable<basic_json_t, ReturnType>::value
|
||||
&& !std::is_same<value_t, detail::uncvref_t<ValueType>>::value, int > = 0 >
|
||||
#if JSON_DELETE_DEPRECATED_FUNCTIONS
|
||||
ReturnType value(const ::nlohmann::json_pointer<BasicJsonType>& ptr, ValueType && default_value) const = delete;
|
||||
#else
|
||||
JSON_HEDLEY_DEPRECATED_FOR(3.11.0, basic_json::json_pointer or nlohmann::json_pointer<basic_json::string_t>) // NOLINT(readability/alt_tokens)
|
||||
ReturnType value(const ::nlohmann::json_pointer<BasicJsonType>& ptr, ValueType && default_value) const
|
||||
{
|
||||
return value(ptr.convert(), std::forward<ValueType>(default_value));
|
||||
}
|
||||
#endif
|
||||
|
||||
/// @brief access the first element
|
||||
/// @sa https://json.nlohmann.me/api/basic_json/front/
|
||||
@@ -30818,15 +30808,11 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
|
||||
|
||||
template<typename BasicJsonType, detail::enable_if_t<detail::is_basic_json<BasicJsonType>::value, int> = 0>
|
||||
JSON_HEDLEY_WARN_UNUSED_RESULT
|
||||
#if JSON_DELETE_DEPRECATED_FUNCTIONS
|
||||
bool contains(const typename ::nlohmann::json_pointer<BasicJsonType>& ptr) const = delete;
|
||||
#else
|
||||
JSON_HEDLEY_DEPRECATED_FOR(3.11.0, basic_json::json_pointer or nlohmann::json_pointer<basic_json::string_t>) // NOLINT(readability/alt_tokens)
|
||||
bool contains(const typename ::nlohmann::json_pointer<BasicJsonType>& ptr) const
|
||||
{
|
||||
return ptr.contains(this);
|
||||
}
|
||||
#endif
|
||||
|
||||
/// @}
|
||||
|
||||
@@ -30935,30 +30921,22 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
|
||||
/// @deprecated This function is deprecated since 3.1.0 and will be removed in
|
||||
/// version 4.0.0 of the library. Please use @ref items() instead;
|
||||
/// that is, replace `json::iterator_wrapper(j)` with `j.items()`.
|
||||
#if JSON_DELETE_DEPRECATED_FUNCTIONS
|
||||
static iteration_proxy<iterator> iterator_wrapper(reference ref) noexcept = delete;
|
||||
#else
|
||||
JSON_HEDLEY_DEPRECATED_FOR(3.1.0, items())
|
||||
static iteration_proxy<iterator> iterator_wrapper(reference ref) noexcept
|
||||
{
|
||||
return ref.items();
|
||||
}
|
||||
#endif
|
||||
|
||||
/// @brief wrapper to access iterator member functions in range-based for
|
||||
/// @sa https://json.nlohmann.me/api/basic_json/items/
|
||||
/// @deprecated This function is deprecated since 3.1.0 and will be removed in
|
||||
/// version 4.0.0 of the library. Please use @ref items() instead;
|
||||
/// that is, replace `json::iterator_wrapper(j)` with `j.items()`.
|
||||
#if JSON_DELETE_DEPRECATED_FUNCTIONS
|
||||
static iteration_proxy<const_iterator> iterator_wrapper(const_reference ref) noexcept = delete;
|
||||
#else
|
||||
JSON_HEDLEY_DEPRECATED_FOR(3.1.0, items())
|
||||
static iteration_proxy<const_iterator> iterator_wrapper(const_reference ref) noexcept
|
||||
{
|
||||
return ref.items();
|
||||
}
|
||||
#endif
|
||||
|
||||
/// @brief helper to access iterator member functions in range-based for
|
||||
/// @sa https://json.nlohmann.me/api/basic_json/items/
|
||||
@@ -32047,7 +32025,7 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
|
||||
/// @sa https://json.nlohmann.me/api/basic_json/operator_le/
|
||||
template<typename ScalarType>
|
||||
requires std::is_scalar_v<ScalarType>
|
||||
friend bool operator<=(ScalarType lhs, const_reference rhs) noexcept
|
||||
friend bool operator<=(ScalarType lhs, const_reference rhs) noexcept(std::is_nothrow_constructible<basic_json, ScalarType>::value)
|
||||
{
|
||||
return basic_json(lhs) <= rhs;
|
||||
}
|
||||
@@ -32056,7 +32034,7 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
|
||||
/// @sa https://json.nlohmann.me/api/basic_json/operator_ge/
|
||||
template<typename ScalarType>
|
||||
requires std::is_scalar_v<ScalarType>
|
||||
friend bool operator>=(ScalarType lhs, const_reference rhs) noexcept
|
||||
friend bool operator>=(ScalarType lhs, const_reference rhs) noexcept(std::is_nothrow_constructible<basic_json, ScalarType>::value)
|
||||
{
|
||||
return basic_json(lhs) >= rhs;
|
||||
}
|
||||
@@ -32274,15 +32252,11 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
|
||||
/// version 4.0.0 of the library. Please use
|
||||
/// operator<<(std::ostream&, const basic_json&) instead; that is,
|
||||
/// replace calls like `j >> o;` with `o << j;`.
|
||||
#if JSON_DELETE_DEPRECATED_FUNCTIONS
|
||||
friend std::ostream& operator>>(const basic_json& j, std::ostream& o) = delete;
|
||||
#else
|
||||
JSON_HEDLEY_DEPRECATED_FOR(3.0.0, operator<<(std::ostream&, const basic_json&))
|
||||
friend std::ostream& operator>>(const basic_json& j, std::ostream& o)
|
||||
{
|
||||
return o << j;
|
||||
}
|
||||
#endif
|
||||
#endif // JSON_NO_IO
|
||||
/// @}
|
||||
|
||||
@@ -32328,13 +32302,6 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
|
||||
}
|
||||
|
||||
JSON_HEDLEY_WARN_UNUSED_RESULT
|
||||
#if JSON_DELETE_DEPRECATED_FUNCTIONS
|
||||
static basic_json parse(detail::span_input_adapter&& i,
|
||||
parser_callback_t cb = nullptr,
|
||||
const bool allow_exceptions = true,
|
||||
const bool ignore_comments = false,
|
||||
const bool ignore_trailing_commas = false) = delete;
|
||||
#else
|
||||
JSON_HEDLEY_DEPRECATED_FOR(3.8.0, parse(ptr, ptr + len))
|
||||
static basic_json parse(detail::span_input_adapter&& i,
|
||||
parser_callback_t cb = nullptr,
|
||||
@@ -32347,7 +32314,6 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
|
||||
p.parse(true, result);
|
||||
return result;
|
||||
}
|
||||
#endif
|
||||
|
||||
/// @brief check if the input is valid JSON
|
||||
/// @sa https://json.nlohmann.me/api/basic_json/accept/
|
||||
@@ -32373,11 +32339,6 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
|
||||
}
|
||||
|
||||
JSON_HEDLEY_WARN_UNUSED_RESULT
|
||||
#if JSON_DELETE_DEPRECATED_FUNCTIONS
|
||||
static bool accept(detail::span_input_adapter&& i,
|
||||
const bool ignore_comments = false,
|
||||
const bool ignore_trailing_commas = false) = delete;
|
||||
#else
|
||||
JSON_HEDLEY_DEPRECATED_FOR(3.8.0, accept(ptr, ptr + len))
|
||||
static bool accept(detail::span_input_adapter&& i,
|
||||
const bool ignore_comments = false,
|
||||
@@ -32385,7 +32346,6 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
|
||||
{
|
||||
return parser(i.get(), nullptr, false, ignore_comments, ignore_trailing_commas, true).accept(true);
|
||||
}
|
||||
#endif
|
||||
|
||||
/// @brief generate SAX events
|
||||
/// @sa https://json.nlohmann.me/api/basic_json/sax_parse/
|
||||
@@ -32439,14 +32399,6 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
|
||||
#pragma clang diagnostic ignored "-Wdocumentation-deprecated-sync"
|
||||
#endif
|
||||
template <typename SAX>
|
||||
#if JSON_DELETE_DEPRECATED_FUNCTIONS
|
||||
JSON_HEDLEY_NON_NULL(2)
|
||||
static bool sax_parse(detail::span_input_adapter&& i, SAX* sax,
|
||||
input_format_t format = input_format_t::json,
|
||||
const bool strict = true,
|
||||
const bool ignore_comments = false,
|
||||
const bool ignore_trailing_commas = false) = delete;
|
||||
#else
|
||||
JSON_HEDLEY_DEPRECATED_FOR(3.8.0, sax_parse(ptr, ptr + len, ...))
|
||||
JSON_HEDLEY_NON_NULL(2)
|
||||
static bool sax_parse(detail::span_input_adapter&& i, SAX* sax,
|
||||
@@ -32462,7 +32414,6 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
|
||||
// NOLINTNEXTLINE(hicpp-move-const-arg,performance-move-const-arg)
|
||||
: detail::binary_reader<basic_json, decltype(ia), SAX>(std::move(ia), format).sax_parse(sax, strict);
|
||||
}
|
||||
#endif
|
||||
#if defined(__clang__)
|
||||
#pragma clang diagnostic pop
|
||||
#endif
|
||||
@@ -32473,15 +32424,11 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
|
||||
/// version 4.0.0 of the library. Please use
|
||||
/// operator>>(std::istream&, basic_json&) instead; that is,
|
||||
/// replace calls like `j << i;` with `i >> j;`.
|
||||
#if JSON_DELETE_DEPRECATED_FUNCTIONS
|
||||
friend std::istream& operator<<(basic_json& j, std::istream& i) = delete;
|
||||
#else
|
||||
JSON_HEDLEY_DEPRECATED_FOR(3.0.0, operator>>(std::istream&, basic_json&))
|
||||
friend std::istream& operator<<(basic_json& j, std::istream& i)
|
||||
{
|
||||
return operator>>(i, j);
|
||||
}
|
||||
#endif
|
||||
|
||||
/// @brief deserialize from stream
|
||||
/// @sa https://json.nlohmann.me/api/operator_gtgt/
|
||||
@@ -32824,12 +32771,6 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
|
||||
|
||||
template<typename T>
|
||||
JSON_HEDLEY_WARN_UNUSED_RESULT
|
||||
#if JSON_DELETE_DEPRECATED_FUNCTIONS
|
||||
static basic_json from_cbor(const T* ptr, std::size_t len,
|
||||
const bool strict = true,
|
||||
const bool allow_exceptions = true,
|
||||
const cbor_tag_handler_t tag_handler = cbor_tag_handler_t::error) = delete;
|
||||
#else
|
||||
JSON_HEDLEY_DEPRECATED_FOR(3.8.0, from_cbor(ptr, ptr + len))
|
||||
static basic_json from_cbor(const T* ptr, std::size_t len,
|
||||
const bool strict = true,
|
||||
@@ -32838,15 +32779,8 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
|
||||
{
|
||||
return from_cbor(ptr, ptr + len, strict, allow_exceptions, tag_handler);
|
||||
}
|
||||
#endif
|
||||
|
||||
JSON_HEDLEY_WARN_UNUSED_RESULT
|
||||
#if JSON_DELETE_DEPRECATED_FUNCTIONS
|
||||
static basic_json from_cbor(detail::span_input_adapter&& i,
|
||||
const bool strict = true,
|
||||
const bool allow_exceptions = true,
|
||||
const cbor_tag_handler_t tag_handler = cbor_tag_handler_t::error) = delete;
|
||||
#else
|
||||
JSON_HEDLEY_DEPRECATED_FOR(3.8.0, from_cbor(ptr, ptr + len))
|
||||
static basic_json from_cbor(detail::span_input_adapter&& i,
|
||||
const bool strict = true,
|
||||
@@ -32855,7 +32789,6 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
|
||||
{
|
||||
return from_binary_impl(i.get(), input_format_t::cbor, strict, allow_exceptions, error_handler_t::keep, tag_handler);
|
||||
}
|
||||
#endif
|
||||
|
||||
/// @brief create a JSON value from an input in MessagePack format
|
||||
/// @sa https://json.nlohmann.me/api/basic_json/from_msgpack/
|
||||
@@ -32884,11 +32817,6 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
|
||||
|
||||
template<typename T>
|
||||
JSON_HEDLEY_WARN_UNUSED_RESULT
|
||||
#if JSON_DELETE_DEPRECATED_FUNCTIONS
|
||||
static basic_json from_msgpack(const T* ptr, std::size_t len,
|
||||
const bool strict = true,
|
||||
const bool allow_exceptions = true) = delete;
|
||||
#else
|
||||
JSON_HEDLEY_DEPRECATED_FOR(3.8.0, from_msgpack(ptr, ptr + len))
|
||||
static basic_json from_msgpack(const T* ptr, std::size_t len,
|
||||
const bool strict = true,
|
||||
@@ -32896,14 +32824,8 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
|
||||
{
|
||||
return from_msgpack(ptr, ptr + len, strict, allow_exceptions);
|
||||
}
|
||||
#endif
|
||||
|
||||
JSON_HEDLEY_WARN_UNUSED_RESULT
|
||||
#if JSON_DELETE_DEPRECATED_FUNCTIONS
|
||||
static basic_json from_msgpack(detail::span_input_adapter&& i,
|
||||
const bool strict = true,
|
||||
const bool allow_exceptions = true) = delete;
|
||||
#else
|
||||
JSON_HEDLEY_DEPRECATED_FOR(3.8.0, from_msgpack(ptr, ptr + len))
|
||||
static basic_json from_msgpack(detail::span_input_adapter&& i,
|
||||
const bool strict = true,
|
||||
@@ -32911,7 +32833,6 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
|
||||
{
|
||||
return from_binary_impl(i.get(), input_format_t::msgpack, strict, allow_exceptions);
|
||||
}
|
||||
#endif
|
||||
|
||||
/// @brief create a JSON value from an input in UBJSON format
|
||||
/// @sa https://json.nlohmann.me/api/basic_json/from_ubjson/
|
||||
@@ -32940,11 +32861,6 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
|
||||
|
||||
template<typename T>
|
||||
JSON_HEDLEY_WARN_UNUSED_RESULT
|
||||
#if JSON_DELETE_DEPRECATED_FUNCTIONS
|
||||
static basic_json from_ubjson(const T* ptr, std::size_t len,
|
||||
const bool strict = true,
|
||||
const bool allow_exceptions = true) = delete;
|
||||
#else
|
||||
JSON_HEDLEY_DEPRECATED_FOR(3.8.0, from_ubjson(ptr, ptr + len))
|
||||
static basic_json from_ubjson(const T* ptr, std::size_t len,
|
||||
const bool strict = true,
|
||||
@@ -32952,14 +32868,8 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
|
||||
{
|
||||
return from_ubjson(ptr, ptr + len, strict, allow_exceptions);
|
||||
}
|
||||
#endif
|
||||
|
||||
JSON_HEDLEY_WARN_UNUSED_RESULT
|
||||
#if JSON_DELETE_DEPRECATED_FUNCTIONS
|
||||
static basic_json from_ubjson(detail::span_input_adapter&& i,
|
||||
const bool strict = true,
|
||||
const bool allow_exceptions = true) = delete;
|
||||
#else
|
||||
JSON_HEDLEY_DEPRECATED_FOR(3.8.0, from_ubjson(ptr, ptr + len))
|
||||
static basic_json from_ubjson(detail::span_input_adapter&& i,
|
||||
const bool strict = true,
|
||||
@@ -32967,7 +32877,6 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
|
||||
{
|
||||
return from_binary_impl(i.get(), input_format_t::ubjson, strict, allow_exceptions);
|
||||
}
|
||||
#endif
|
||||
|
||||
/// @brief create a JSON value from an input in BJData format
|
||||
/// @sa https://json.nlohmann.me/api/basic_json/from_bjdata/
|
||||
@@ -32994,22 +32903,6 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
|
||||
return from_binary_impl(detail::input_adapter(std::move(first), std::move(last)), input_format_t::bjdata, strict, allow_exceptions, error_handler);
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
JSON_HEDLEY_WARN_UNUSED_RESULT
|
||||
#if JSON_DELETE_DEPRECATED_FUNCTIONS
|
||||
static basic_json from_bjdata(const T* ptr, std::size_t len,
|
||||
const bool strict = true,
|
||||
const bool allow_exceptions = true) = delete;
|
||||
#else
|
||||
JSON_HEDLEY_DEPRECATED_FOR(3.13.0, from_bjdata(ptr, ptr + len))
|
||||
static basic_json from_bjdata(const T* ptr, std::size_t len,
|
||||
const bool strict = true,
|
||||
const bool allow_exceptions = true)
|
||||
{
|
||||
return from_bjdata(ptr, ptr + len, strict, allow_exceptions);
|
||||
}
|
||||
#endif
|
||||
|
||||
/// @brief create a JSON value from an input in BON8 format
|
||||
/// @sa https://json.nlohmann.me/api/basic_json/from_bon8/
|
||||
template<typename InputType>
|
||||
@@ -33033,22 +32926,6 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
|
||||
return from_binary_impl(detail::input_adapter(std::move(first), std::move(last)), input_format_t::bon8, strict, allow_exceptions);
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
JSON_HEDLEY_WARN_UNUSED_RESULT
|
||||
#if JSON_DELETE_DEPRECATED_FUNCTIONS
|
||||
static basic_json from_bon8(const T* ptr, std::size_t len,
|
||||
const bool strict = true,
|
||||
const bool allow_exceptions = true) = delete;
|
||||
#else
|
||||
JSON_HEDLEY_DEPRECATED_FOR(3.13.0, from_bon8(ptr, ptr + len))
|
||||
static basic_json from_bon8(const T* ptr, std::size_t len,
|
||||
const bool strict = true,
|
||||
const bool allow_exceptions = true)
|
||||
{
|
||||
return from_bon8(ptr, ptr + len, strict, allow_exceptions);
|
||||
}
|
||||
#endif
|
||||
|
||||
/// @brief create a JSON value from an input in BSON format
|
||||
/// @sa https://json.nlohmann.me/api/basic_json/from_bson/
|
||||
template<typename InputType>
|
||||
@@ -33076,11 +32953,6 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
|
||||
|
||||
template<typename T>
|
||||
JSON_HEDLEY_WARN_UNUSED_RESULT
|
||||
#if JSON_DELETE_DEPRECATED_FUNCTIONS
|
||||
static basic_json from_bson(const T* ptr, std::size_t len,
|
||||
const bool strict = true,
|
||||
const bool allow_exceptions = true) = delete;
|
||||
#else
|
||||
JSON_HEDLEY_DEPRECATED_FOR(3.8.0, from_bson(ptr, ptr + len))
|
||||
static basic_json from_bson(const T* ptr, std::size_t len,
|
||||
const bool strict = true,
|
||||
@@ -33088,14 +32960,8 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
|
||||
{
|
||||
return from_bson(ptr, ptr + len, strict, allow_exceptions);
|
||||
}
|
||||
#endif
|
||||
|
||||
JSON_HEDLEY_WARN_UNUSED_RESULT
|
||||
#if JSON_DELETE_DEPRECATED_FUNCTIONS
|
||||
static basic_json from_bson(detail::span_input_adapter&& i,
|
||||
const bool strict = true,
|
||||
const bool allow_exceptions = true) = delete;
|
||||
#else
|
||||
JSON_HEDLEY_DEPRECATED_FOR(3.8.0, from_bson(ptr, ptr + len))
|
||||
static basic_json from_bson(detail::span_input_adapter&& i,
|
||||
const bool strict = true,
|
||||
@@ -33103,7 +32969,6 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
|
||||
{
|
||||
return from_binary_impl(i.get(), input_format_t::bson, strict, allow_exceptions);
|
||||
}
|
||||
#endif
|
||||
/// @}
|
||||
|
||||
//////////////////////////
|
||||
@@ -33121,15 +32986,11 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
|
||||
}
|
||||
|
||||
template<typename BasicJsonType, detail::enable_if_t<detail::is_basic_json<BasicJsonType>::value, int> = 0>
|
||||
#if JSON_DELETE_DEPRECATED_FUNCTIONS
|
||||
reference operator[](const ::nlohmann::json_pointer<BasicJsonType>& ptr) = delete;
|
||||
#else
|
||||
JSON_HEDLEY_DEPRECATED_FOR(3.11.0, basic_json::json_pointer or nlohmann::json_pointer<basic_json::string_t>) // NOLINT(readability/alt_tokens)
|
||||
reference operator[](const ::nlohmann::json_pointer<BasicJsonType>& ptr)
|
||||
{
|
||||
return ptr.get_unchecked(this);
|
||||
}
|
||||
#endif
|
||||
|
||||
/// @brief access specified element via JSON Pointer
|
||||
/// @sa https://json.nlohmann.me/api/basic_json/operator%5B%5D/
|
||||
@@ -33139,15 +33000,11 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
|
||||
}
|
||||
|
||||
template<typename BasicJsonType, detail::enable_if_t<detail::is_basic_json<BasicJsonType>::value, int> = 0>
|
||||
#if JSON_DELETE_DEPRECATED_FUNCTIONS
|
||||
const_reference operator[](const ::nlohmann::json_pointer<BasicJsonType>& ptr) const = delete;
|
||||
#else
|
||||
JSON_HEDLEY_DEPRECATED_FOR(3.11.0, basic_json::json_pointer or nlohmann::json_pointer<basic_json::string_t>) // NOLINT(readability/alt_tokens)
|
||||
const_reference operator[](const ::nlohmann::json_pointer<BasicJsonType>& ptr) const
|
||||
{
|
||||
return ptr.get_unchecked(this);
|
||||
}
|
||||
#endif
|
||||
|
||||
/// @brief access specified element via JSON Pointer
|
||||
/// @sa https://json.nlohmann.me/api/basic_json/at/
|
||||
@@ -33157,15 +33014,11 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
|
||||
}
|
||||
|
||||
template<typename BasicJsonType, detail::enable_if_t<detail::is_basic_json<BasicJsonType>::value, int> = 0>
|
||||
#if JSON_DELETE_DEPRECATED_FUNCTIONS
|
||||
reference at(const ::nlohmann::json_pointer<BasicJsonType>& ptr) = delete;
|
||||
#else
|
||||
JSON_HEDLEY_DEPRECATED_FOR(3.11.0, basic_json::json_pointer or nlohmann::json_pointer<basic_json::string_t>) // NOLINT(readability/alt_tokens)
|
||||
reference at(const ::nlohmann::json_pointer<BasicJsonType>& ptr)
|
||||
{
|
||||
return ptr.get_checked(this);
|
||||
}
|
||||
#endif
|
||||
|
||||
/// @brief access specified element via JSON Pointer
|
||||
/// @sa https://json.nlohmann.me/api/basic_json/at/
|
||||
@@ -33175,15 +33028,11 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
|
||||
}
|
||||
|
||||
template<typename BasicJsonType, detail::enable_if_t<detail::is_basic_json<BasicJsonType>::value, int> = 0>
|
||||
#if JSON_DELETE_DEPRECATED_FUNCTIONS
|
||||
const_reference at(const ::nlohmann::json_pointer<BasicJsonType>& ptr) const = delete;
|
||||
#else
|
||||
JSON_HEDLEY_DEPRECATED_FOR(3.11.0, basic_json::json_pointer or nlohmann::json_pointer<basic_json::string_t>) // NOLINT(readability/alt_tokens)
|
||||
const_reference at(const ::nlohmann::json_pointer<BasicJsonType>& ptr) const
|
||||
{
|
||||
return ptr.get_checked(this);
|
||||
}
|
||||
#endif
|
||||
|
||||
/// @brief return flattened JSON value
|
||||
/// @sa https://json.nlohmann.me/api/basic_json/flatten/
|
||||
@@ -34343,7 +34192,6 @@ struct formatter<nlohmann::NLOHMANN_BASIC_JSON_TPL, char> // NOLINT(cert-dcl58-c
|
||||
#undef JSON_PRECISE_STREAM_POSITION
|
||||
#undef JSON_STRICT_NUL_HANDLING
|
||||
#undef JSON_STRICT_BINARY_UTF8
|
||||
#undef JSON_DELETE_DEPRECATED_FUNCTIONS
|
||||
#endif
|
||||
|
||||
// #include <nlohmann/thirdparty/hedley/hedley_undef.hpp>
|
||||
|
||||
@@ -10,7 +10,8 @@
|
||||
|
||||
#include <cstdint> // uint8_t
|
||||
#include <cstddef> // size_t
|
||||
#include <fstream> // ifstream, istreambuf_iterator, ios
|
||||
#include <fstream> // ifstream, ios
|
||||
#include <iterator> // istream_iterator
|
||||
#include <vector> // vector
|
||||
|
||||
namespace utils
|
||||
|
||||
@@ -567,7 +567,7 @@ struct allocator_no_forward : std::allocator<T>
|
||||
{
|
||||
allocator_no_forward() = default;
|
||||
template <class U>
|
||||
allocator_no_forward(allocator_no_forward<U> /*unused*/) {}
|
||||
allocator_no_forward(const allocator_no_forward<U>& /*unused*/) {}
|
||||
|
||||
template <class U>
|
||||
struct rebind
|
||||
|
||||
@@ -7,6 +7,7 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
#include "doctest_compatibility.h"
|
||||
#include "test_utils.hpp"
|
||||
|
||||
#include <nlohmann/json.hpp>
|
||||
using nlohmann::json;
|
||||
@@ -25,18 +26,27 @@ struct ill_formed_case
|
||||
|
||||
// RFC 3629 ill-formed sequences used throughout this file, plus one
|
||||
// well-formed sequence for contrast
|
||||
const std::vector<ill_formed_case> ill_formed_cases =
|
||||
std::vector<ill_formed_case> ill_formed_cases()
|
||||
{
|
||||
{"overlong", "\xC0\xAE"},
|
||||
{"lone_0xFF", "\xFF"},
|
||||
{"truncated", "\xE2\x82"},
|
||||
{"surrogate", "\xED\xA0\x80"},
|
||||
};
|
||||
return
|
||||
{
|
||||
{"overlong", "\xC0\xAE"},
|
||||
{"lone_0xFF", "\xFF"},
|
||||
{"truncated", "\xE2\x82"},
|
||||
{"surrogate", "\xED\xA0\x80"},
|
||||
};
|
||||
}
|
||||
|
||||
const std::string valid_sequence = "\xC3\xA9"; // U+00E9, "é"
|
||||
std::string valid_sequence()
|
||||
{
|
||||
return "\xC3\xA9"; // U+00E9, "é"
|
||||
}
|
||||
|
||||
using eh = json::error_handler_t;
|
||||
const std::vector<eh> all_handlers = {eh::strict, eh::replace, eh::ignore, eh::keep};
|
||||
std::vector<eh> all_handlers()
|
||||
{
|
||||
return {eh::strict, eh::replace, eh::ignore, eh::keep};
|
||||
}
|
||||
|
||||
// what dump()+parse() produces for a sanitizing error_handler; this is the
|
||||
// ground truth every binary writer/reader is checked against
|
||||
@@ -51,9 +61,9 @@ TEST_CASE("UTF-8 error_handler for the binary readers and writers")
|
||||
{
|
||||
SECTION("writers: string value")
|
||||
{
|
||||
for (const auto& c : ill_formed_cases)
|
||||
for (const auto& c : ill_formed_cases())
|
||||
{
|
||||
CAPTURE(c.name);
|
||||
CAPTURE(c.name)
|
||||
const json jval = c.bytes;
|
||||
|
||||
CHECK_THROWS_AS(json::to_cbor(jval, eh::strict), json::type_error&);
|
||||
@@ -71,7 +81,7 @@ TEST_CASE("UTF-8 error_handler for the binary readers and writers")
|
||||
eh::replace, eh::ignore
|
||||
})
|
||||
{
|
||||
CAPTURE(static_cast<int>(h));
|
||||
CAPTURE(static_cast<int>(h))
|
||||
const std::string expected = dump_and_parse(c.bytes, h);
|
||||
|
||||
CHECK(json::from_cbor(json::to_cbor(jval, h)).get<std::string>() == expected);
|
||||
@@ -103,9 +113,9 @@ TEST_CASE("UTF-8 error_handler for the binary readers and writers")
|
||||
|
||||
SECTION("writers: object key")
|
||||
{
|
||||
for (const auto& c : ill_formed_cases)
|
||||
for (const auto& c : ill_formed_cases())
|
||||
{
|
||||
CAPTURE(c.name);
|
||||
CAPTURE(c.name)
|
||||
json jobj;
|
||||
jobj[c.bytes] = 1;
|
||||
|
||||
@@ -120,7 +130,7 @@ TEST_CASE("UTF-8 error_handler for the binary readers and writers")
|
||||
eh::replace, eh::ignore
|
||||
})
|
||||
{
|
||||
CAPTURE(static_cast<int>(h));
|
||||
CAPTURE(static_cast<int>(h))
|
||||
const std::string expected = dump_and_parse(c.bytes, h);
|
||||
|
||||
CHECK(json::from_cbor(json::to_cbor(jobj, h)).begin().key() == expected);
|
||||
@@ -141,9 +151,9 @@ TEST_CASE("UTF-8 error_handler for the binary readers and writers")
|
||||
|
||||
SECTION("readers: string value")
|
||||
{
|
||||
for (const auto& c : ill_formed_cases)
|
||||
for (const auto& c : ill_formed_cases())
|
||||
{
|
||||
CAPTURE(c.name);
|
||||
CAPTURE(c.name)
|
||||
|
||||
// bytes produced the lenient (keep) way, as any binary reader
|
||||
// accepted them before this parameter existed
|
||||
@@ -166,15 +176,15 @@ TEST_CASE("UTF-8 error_handler for the binary readers and writers")
|
||||
CHECK(json::from_bson(bson_bytes)["k"].get<std::string>() == c.bytes);
|
||||
|
||||
// strict: parse_error.113, discarded (not thrown) when allow_exceptions is false
|
||||
CHECK_THROWS_AS(json::from_cbor(cbor_bytes, true, true, json::cbor_tag_handler_t::error, eh::strict), json::parse_error&);
|
||||
CHECK_THROWS_AS(utils::ignore_return_value(json::from_cbor(cbor_bytes, true, true, json::cbor_tag_handler_t::error, eh::strict)), json::parse_error&);
|
||||
CHECK(json::from_cbor(cbor_bytes, true, false, json::cbor_tag_handler_t::error, eh::strict).is_discarded());
|
||||
CHECK_THROWS_AS(json::from_msgpack(msgpack_bytes, true, true, eh::strict), json::parse_error&);
|
||||
CHECK_THROWS_AS(utils::ignore_return_value(json::from_msgpack(msgpack_bytes, true, true, eh::strict)), json::parse_error&);
|
||||
CHECK(json::from_msgpack(msgpack_bytes, true, false, eh::strict).is_discarded());
|
||||
CHECK_THROWS_AS(json::from_ubjson(ubjson_bytes, true, true, eh::strict), json::parse_error&);
|
||||
CHECK_THROWS_AS(utils::ignore_return_value(json::from_ubjson(ubjson_bytes, true, true, eh::strict)), json::parse_error&);
|
||||
CHECK(json::from_ubjson(ubjson_bytes, true, false, eh::strict).is_discarded());
|
||||
CHECK_THROWS_AS(json::from_bjdata(bjdata_bytes, true, true, eh::strict), json::parse_error&);
|
||||
CHECK_THROWS_AS(utils::ignore_return_value(json::from_bjdata(bjdata_bytes, true, true, eh::strict)), json::parse_error&);
|
||||
CHECK(json::from_bjdata(bjdata_bytes, true, false, eh::strict).is_discarded());
|
||||
CHECK_THROWS_AS(json::from_bson(bson_bytes, true, true, eh::strict), json::parse_error&);
|
||||
CHECK_THROWS_AS(utils::ignore_return_value(json::from_bson(bson_bytes, true, true, eh::strict)), json::parse_error&);
|
||||
CHECK(json::from_bson(bson_bytes, true, false, eh::strict).is_discarded());
|
||||
|
||||
// replace / ignore: match what dump() would have sanitized the same bytes to
|
||||
@@ -183,7 +193,7 @@ TEST_CASE("UTF-8 error_handler for the binary readers and writers")
|
||||
eh::replace, eh::ignore
|
||||
})
|
||||
{
|
||||
CAPTURE(static_cast<int>(h));
|
||||
CAPTURE(static_cast<int>(h))
|
||||
const std::string expected = dump_and_parse(c.bytes, h);
|
||||
|
||||
CHECK(json::from_cbor(cbor_bytes, true, true, json::cbor_tag_handler_t::error, h).get<std::string>() == expected);
|
||||
@@ -197,9 +207,9 @@ TEST_CASE("UTF-8 error_handler for the binary readers and writers")
|
||||
|
||||
SECTION("readers: object key")
|
||||
{
|
||||
for (const auto& c : ill_formed_cases)
|
||||
for (const auto& c : ill_formed_cases())
|
||||
{
|
||||
CAPTURE(c.name);
|
||||
CAPTURE(c.name)
|
||||
|
||||
json jobj;
|
||||
jobj[c.bytes] = 1;
|
||||
@@ -215,18 +225,18 @@ TEST_CASE("UTF-8 error_handler for the binary readers and writers")
|
||||
CHECK(json::from_bjdata(bjdata_bytes).begin().key() == c.bytes);
|
||||
CHECK(json::from_bson(bson_bytes).begin().key() == c.bytes);
|
||||
|
||||
CHECK_THROWS_AS(json::from_cbor(cbor_bytes, true, true, json::cbor_tag_handler_t::error, eh::strict), json::parse_error&);
|
||||
CHECK_THROWS_AS(json::from_msgpack(msgpack_bytes, true, true, eh::strict), json::parse_error&);
|
||||
CHECK_THROWS_AS(json::from_ubjson(ubjson_bytes, true, true, eh::strict), json::parse_error&);
|
||||
CHECK_THROWS_AS(json::from_bjdata(bjdata_bytes, true, true, eh::strict), json::parse_error&);
|
||||
CHECK_THROWS_AS(json::from_bson(bson_bytes, true, true, eh::strict), json::parse_error&);
|
||||
CHECK_THROWS_AS(utils::ignore_return_value(json::from_cbor(cbor_bytes, true, true, json::cbor_tag_handler_t::error, eh::strict)), json::parse_error&);
|
||||
CHECK_THROWS_AS(utils::ignore_return_value(json::from_msgpack(msgpack_bytes, true, true, eh::strict)), json::parse_error&);
|
||||
CHECK_THROWS_AS(utils::ignore_return_value(json::from_ubjson(ubjson_bytes, true, true, eh::strict)), json::parse_error&);
|
||||
CHECK_THROWS_AS(utils::ignore_return_value(json::from_bjdata(bjdata_bytes, true, true, eh::strict)), json::parse_error&);
|
||||
CHECK_THROWS_AS(utils::ignore_return_value(json::from_bson(bson_bytes, true, true, eh::strict)), json::parse_error&);
|
||||
|
||||
for (const auto h :
|
||||
{
|
||||
eh::replace, eh::ignore
|
||||
})
|
||||
{
|
||||
CAPTURE(static_cast<int>(h));
|
||||
CAPTURE(static_cast<int>(h))
|
||||
const std::string expected = dump_and_parse(c.bytes, h);
|
||||
|
||||
CHECK(json::from_cbor(cbor_bytes, true, true, json::cbor_tag_handler_t::error, h).begin().key() == expected);
|
||||
@@ -240,30 +250,30 @@ TEST_CASE("UTF-8 error_handler for the binary readers and writers")
|
||||
|
||||
SECTION("well-formed UTF-8 is unaffected by error_handler")
|
||||
{
|
||||
const json jval = valid_sequence;
|
||||
const json jval = valid_sequence();
|
||||
json jobj;
|
||||
jobj[valid_sequence] = valid_sequence;
|
||||
jobj[valid_sequence()] = valid_sequence();
|
||||
|
||||
for (const auto h : all_handlers)
|
||||
for (const auto h : all_handlers())
|
||||
{
|
||||
CAPTURE(static_cast<int>(h));
|
||||
CAPTURE(static_cast<int>(h))
|
||||
|
||||
CHECK(json::from_cbor(json::to_cbor(jval, h)).get<std::string>() == valid_sequence);
|
||||
CHECK(json::from_msgpack(json::to_msgpack(jval, h)).get<std::string>() == valid_sequence);
|
||||
CHECK(json::from_ubjson(json::to_ubjson(jval, false, false, h)).get<std::string>() == valid_sequence);
|
||||
CHECK(json::from_bjdata(json::to_bjdata(jval, false, false, json::bjdata_version_t::draft2, h)).get<std::string>() == valid_sequence);
|
||||
CHECK(json::from_bson(json::to_bson(jobj, h)).begin().key() == valid_sequence);
|
||||
CHECK(json::from_cbor(json::to_cbor(jval, h)).get<std::string>() == valid_sequence());
|
||||
CHECK(json::from_msgpack(json::to_msgpack(jval, h)).get<std::string>() == valid_sequence());
|
||||
CHECK(json::from_ubjson(json::to_ubjson(jval, false, false, h)).get<std::string>() == valid_sequence());
|
||||
CHECK(json::from_bjdata(json::to_bjdata(jval, false, false, json::bjdata_version_t::draft2, h)).get<std::string>() == valid_sequence());
|
||||
CHECK(json::from_bson(json::to_bson(jobj, h)).begin().key() == valid_sequence());
|
||||
|
||||
CHECK(json::from_cbor(json::to_cbor(jval, eh::keep), true, true, json::cbor_tag_handler_t::error, h).get<std::string>() == valid_sequence);
|
||||
CHECK(json::from_msgpack(json::to_msgpack(jval), true, true, h).get<std::string>() == valid_sequence);
|
||||
CHECK(json::from_cbor(json::to_cbor(jval, eh::keep), true, true, json::cbor_tag_handler_t::error, h).get<std::string>() == valid_sequence());
|
||||
CHECK(json::from_msgpack(json::to_msgpack(jval), true, true, h).get<std::string>() == valid_sequence());
|
||||
}
|
||||
}
|
||||
|
||||
SECTION("dump() with error_handler_t::keep writes raw bytes as is")
|
||||
{
|
||||
for (const auto& c : ill_formed_cases)
|
||||
for (const auto& c : ill_formed_cases())
|
||||
{
|
||||
CAPTURE(c.name);
|
||||
CAPTURE(c.name)
|
||||
|
||||
const json jval = c.bytes;
|
||||
const std::string dumped = jval.dump(-1, ' ', false, eh::keep);
|
||||
@@ -276,10 +286,10 @@ TEST_CASE("UTF-8 error_handler for the binary readers and writers")
|
||||
|
||||
// well-formed characters around an ill-formed sequence are still
|
||||
// escaped as usual under ensure_ascii
|
||||
const json mixed = valid_sequence + ill_formed_cases[1].bytes; // "é" + lone 0xFF
|
||||
const json mixed = valid_sequence() + ill_formed_cases()[1].bytes; // "é" + lone 0xFF
|
||||
const std::string dumped_mixed = mixed.dump(-1, ' ', true, eh::keep);
|
||||
CHECK(dumped_mixed.find("\\u00e9") != std::string::npos);
|
||||
CHECK(dumped_mixed.find(ill_formed_cases[1].bytes) != std::string::npos);
|
||||
CHECK(dumped_mixed.find(ill_formed_cases()[1].bytes) != std::string::npos);
|
||||
|
||||
// the byte that ends an ill-formed sequence is read again, so a quote,
|
||||
// a backslash, or a control character after it is still escaped, and
|
||||
@@ -289,7 +299,7 @@ TEST_CASE("UTF-8 error_handler for the binary readers and writers")
|
||||
false, true
|
||||
})
|
||||
{
|
||||
CAPTURE(ensure_ascii);
|
||||
CAPTURE(ensure_ascii)
|
||||
CHECK(json("\xC3\"").dump(-1, ' ', ensure_ascii, eh::keep) == "\"\xC3\\\"\"");
|
||||
CHECK(json("\xC3\\").dump(-1, ' ', ensure_ascii, eh::keep) == "\"\xC3\\\\\"");
|
||||
CHECK(json("\xC3\n").dump(-1, ' ', ensure_ascii, eh::keep) == "\"\xC3\\n\"");
|
||||
@@ -303,12 +313,12 @@ TEST_CASE("UTF-8 error_handler for the binary readers and writers")
|
||||
|
||||
SECTION("to_msgpack defaults to keep; to_bon8 is not affected by error_handler")
|
||||
{
|
||||
const json jval = ill_formed_cases[1].bytes; // lone 0xFF
|
||||
const json jval = ill_formed_cases()[1].bytes; // lone 0xFF
|
||||
|
||||
// to_msgpack's error_handler defaults to keep, as MessagePack's spec
|
||||
// allows any bytes in a str, so the bytes are passed through
|
||||
CHECK(json::to_msgpack(jval) == json::to_msgpack(jval, eh::keep));
|
||||
CHECK(json::from_msgpack(json::to_msgpack(jval)).get<std::string>() == ill_formed_cases[1].bytes);
|
||||
CHECK(json::from_msgpack(json::to_msgpack(jval)).get<std::string>() == ill_formed_cases()[1].bytes);
|
||||
|
||||
// the diagnostics context of an ill-formed key is the object
|
||||
json jobj;
|
||||
@@ -322,14 +332,14 @@ TEST_CASE("UTF-8 error_handler for the binary readers and writers")
|
||||
|
||||
SECTION("allow_exceptions=false with error_handler_t::strict discards the value")
|
||||
{
|
||||
const auto bytes = json::to_cbor(json(ill_formed_cases[0].bytes), eh::keep);
|
||||
const auto bytes = json::to_cbor(json(ill_formed_cases()[0].bytes), eh::keep);
|
||||
const json result = json::from_cbor(bytes, true, false, json::cbor_tag_handler_t::error, eh::strict);
|
||||
CHECK(result.is_discarded());
|
||||
}
|
||||
|
||||
SECTION("default parameters are unchanged")
|
||||
{
|
||||
const json jval = ill_formed_cases[0].bytes;
|
||||
const json jval = ill_formed_cases()[0].bytes;
|
||||
|
||||
// to_*: the default error_handler is keep, so ill-formed bytes are
|
||||
// written unchanged, exactly as in release 3.12.0 (it is strict only
|
||||
@@ -347,16 +357,16 @@ TEST_CASE("UTF-8 error_handler for the binary readers and writers")
|
||||
// from_*: the default error_handler is keep, so ill-formed bytes are
|
||||
// still accepted unchanged, exactly as in release 3.12.0
|
||||
const auto cbor_bytes = json::to_cbor(jval, eh::keep);
|
||||
CHECK(json::from_cbor(cbor_bytes).get<std::string>() == ill_formed_cases[0].bytes);
|
||||
CHECK(json::from_cbor(cbor_bytes).get<std::string>() == ill_formed_cases()[0].bytes);
|
||||
const auto ubjson_bytes = json::to_ubjson(jval, false, false, eh::keep);
|
||||
CHECK(json::from_ubjson(ubjson_bytes).get<std::string>() == ill_formed_cases[0].bytes);
|
||||
CHECK(json::from_ubjson(ubjson_bytes).get<std::string>() == ill_formed_cases()[0].bytes);
|
||||
const auto bjdata_bytes = json::to_bjdata(jval, false, false, json::bjdata_version_t::draft2, eh::keep);
|
||||
CHECK(json::from_bjdata(bjdata_bytes).get<std::string>() == ill_formed_cases[0].bytes);
|
||||
CHECK(json::from_bjdata(bjdata_bytes).get<std::string>() == ill_formed_cases()[0].bytes);
|
||||
const auto msgpack_bytes = json::to_msgpack(jval);
|
||||
CHECK(json::from_msgpack(msgpack_bytes).get<std::string>() == ill_formed_cases[0].bytes);
|
||||
CHECK(json::from_msgpack(msgpack_bytes).get<std::string>() == ill_formed_cases()[0].bytes);
|
||||
json bson_obj;
|
||||
bson_obj["k"] = jval;
|
||||
const auto bson_bytes = json::to_bson(bson_obj, eh::keep);
|
||||
CHECK(json::from_bson(bson_bytes)["k"].get<std::string>() == ill_formed_cases[0].bytes);
|
||||
CHECK(json::from_bson(bson_bytes)["k"].get<std::string>() == ill_formed_cases()[0].bytes);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -83,21 +83,45 @@ TEST_CASE("JSON_STRICT_BINARY_UTF8 (see #5529, #5651)")
|
||||
// any bytes reach the output adapter (the BSON document length
|
||||
// prefix must be known up front, so nothing is written incrementally)
|
||||
std::vector<std::uint8_t> out{0x42}; // a sentinel byte the writer must not touch
|
||||
CHECK_THROWS_WITH_AS(json::to_bson(json{{"s", "\xFF"}}, nlohmann::detail::output_adapter<std::uint8_t>(out)), "[json.exception.type_error.316] invalid UTF-8 byte at index 0: 0xFF", json::type_error&);
|
||||
#if JSON_DIAGNOSTICS
|
||||
CHECK_THROWS_WITH_AS(json::to_bson(json {{"s", "\xFF"}}, nlohmann::detail::output_adapter<std::uint8_t>(out)), "[json.exception.type_error.316] (/s) invalid UTF-8 byte at index 0: 0xFF", json::type_error&);
|
||||
#else
|
||||
CHECK_THROWS_WITH_AS(json::to_bson(json {{"s", "\xFF"}}, nlohmann::detail::output_adapter<std::uint8_t>(out)), "[json.exception.type_error.316] invalid UTF-8 byte at index 0: 0xFF", json::type_error&);
|
||||
#endif
|
||||
CHECK(out == std::vector<std::uint8_t> {0x42});
|
||||
|
||||
CHECK_THROWS_WITH_AS(json::to_bson(json{{"s", "\xFF"}}), "[json.exception.type_error.316] invalid UTF-8 byte at index 0: 0xFF", json::type_error&);
|
||||
#if JSON_DIAGNOSTICS
|
||||
CHECK_THROWS_WITH_AS(json::to_bson(json {{"s", "\xFF"}}), "[json.exception.type_error.316] (/s) invalid UTF-8 byte at index 0: 0xFF", json::type_error&);
|
||||
#else
|
||||
CHECK_THROWS_WITH_AS(json::to_bson(json {{"s", "\xFF"}}), "[json.exception.type_error.316] invalid UTF-8 byte at index 0: 0xFF", json::type_error&);
|
||||
#endif
|
||||
// a truncated multi-byte sequence
|
||||
CHECK_THROWS_WITH_AS(json::to_bson(json{{"s", "\xC3"}}), "[json.exception.type_error.316] invalid UTF-8 byte at index 0: 0xC3", json::type_error&);
|
||||
#if JSON_DIAGNOSTICS
|
||||
CHECK_THROWS_WITH_AS(json::to_bson(json {{"s", "\xC3"}}), "[json.exception.type_error.316] (/s) invalid UTF-8 byte at index 0: 0xC3", json::type_error&);
|
||||
#else
|
||||
CHECK_THROWS_WITH_AS(json::to_bson(json {{"s", "\xC3"}}), "[json.exception.type_error.316] invalid UTF-8 byte at index 0: 0xC3", json::type_error&);
|
||||
#endif
|
||||
// an encoded surrogate half (U+D800)
|
||||
CHECK_THROWS_WITH_AS(json::to_bson(json{{"s", "\xED\xA0\x80"}}), "[json.exception.type_error.316] invalid UTF-8 byte at index 0: 0xED", json::type_error&);
|
||||
#if JSON_DIAGNOSTICS
|
||||
CHECK_THROWS_WITH_AS(json::to_bson(json {{"s", "\xED\xA0\x80"}}), "[json.exception.type_error.316] (/s) invalid UTF-8 byte at index 0: 0xED", json::type_error&);
|
||||
#else
|
||||
CHECK_THROWS_WITH_AS(json::to_bson(json {{"s", "\xED\xA0\x80"}}), "[json.exception.type_error.316] invalid UTF-8 byte at index 0: 0xED", json::type_error&);
|
||||
#endif
|
||||
// an overlong encoding of '.'
|
||||
CHECK_THROWS_WITH_AS(json::to_bson(json{{"s", "\xC0\xAF"}}), "[json.exception.type_error.316] invalid UTF-8 byte at index 0: 0xC0", json::type_error&);
|
||||
#if JSON_DIAGNOSTICS
|
||||
CHECK_THROWS_WITH_AS(json::to_bson(json {{"s", "\xC0\xAF"}}), "[json.exception.type_error.316] (/s) invalid UTF-8 byte at index 0: 0xC0", json::type_error&);
|
||||
#else
|
||||
CHECK_THROWS_WITH_AS(json::to_bson(json {{"s", "\xC0\xAF"}}), "[json.exception.type_error.316] invalid UTF-8 byte at index 0: 0xC0", json::type_error&);
|
||||
#endif
|
||||
|
||||
// an object key with ill-formed UTF-8 is rejected as well; unlike
|
||||
// the reader (which never validates element names), the writer
|
||||
// checks both string values and object keys
|
||||
CHECK_THROWS_WITH_AS(json::to_bson(json{{"\xFF", 1}}), "[json.exception.type_error.316] invalid UTF-8 byte at index 0: 0xFF", json::type_error&);
|
||||
#if JSON_DIAGNOSTICS
|
||||
CHECK_THROWS_WITH_AS(json::to_bson(json {{"\xFF", 1}}), "[json.exception.type_error.316] (/\xFF) invalid UTF-8 byte at index 0: 0xFF", json::type_error&);
|
||||
#else
|
||||
CHECK_THROWS_WITH_AS(json::to_bson(json {{"\xFF", 1}}), "[json.exception.type_error.316] invalid UTF-8 byte at index 0: 0xFF", json::type_error&);
|
||||
#endif
|
||||
}
|
||||
|
||||
SECTION("an explicit error_handler overrides the default")
|
||||
|
||||
@@ -9,14 +9,6 @@
|
||||
#include "doctest_compatibility.h"
|
||||
|
||||
#define JSON_TESTS_PRIVATE
|
||||
// capture whether JSON_DELETE_DEPRECATED_FUNCTIONS was enabled on the command
|
||||
// line *before* including json.hpp, since the library #undefs it once the header
|
||||
// has been fully processed (see include/nlohmann/detail/macro_unscope.hpp); the
|
||||
// tests of deprecated functions are skipped if these functions are deleted
|
||||
#if defined(JSON_DELETE_DEPRECATED_FUNCTIONS) && (JSON_DELETE_DEPRECATED_FUNCTIONS == 1)
|
||||
#define JSON_TEST_DEPRECATED_FUNCTIONS_DELETED
|
||||
#endif
|
||||
|
||||
#include <nlohmann/json.hpp>
|
||||
using nlohmann::json;
|
||||
|
||||
@@ -3929,7 +3921,7 @@ TEST_CASE("Universal Binary JSON Specification Examples 1")
|
||||
CHECK_NOTHROW(j = json::from_bjdata(v));
|
||||
REQUIRE(j.is_string());
|
||||
CHECK(j.get_ref<const json::string_t&>() == std::string("\xc0\xae"));
|
||||
CHECK_THROWS_AS(j.dump(), json::type_error&);
|
||||
CHECK_THROWS_AS(utils::ignore_return_value(j.dump()), json::type_error&);
|
||||
CHECK(json::from_bjdata(json::to_bjdata(j)) == j);
|
||||
|
||||
// the same bytes as an object key round-trip as well
|
||||
@@ -4498,33 +4490,3 @@ TEST_CASE("BJData roundtrips" * doctest::skip())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
TEST_CASE("issue #5648 - from_bjdata(ptr, len) must read len bytes, not treat ptr as a C string")
|
||||
{
|
||||
// to_bjdata() encodes the integer 0 as the two bytes 'i' 0x00 (a BJData
|
||||
// type marker followed by the value byte 0x00), so the packed data
|
||||
// below contains a 0x00 byte before its end.
|
||||
const json j = {{"a", 0}};
|
||||
const std::vector<std::uint8_t> packed = json::to_bjdata(j);
|
||||
bool contains_nul = false;
|
||||
for (const auto byte : packed)
|
||||
{
|
||||
contains_nul |= (byte == 0x00);
|
||||
}
|
||||
REQUIRE(contains_nul);
|
||||
|
||||
#ifndef JSON_TEST_DEPRECATED_FUNCTIONS_DELETED
|
||||
// before the fix, from_bjdata had no (ptr, len) overload, so this call
|
||||
// bound to from_bjdata(InputType&&, bool strict) instead: ptr was read
|
||||
// as a NUL-terminated C string (stopping at the embedded 0x00 byte), and
|
||||
// len was silently converted to the strict flag. The deprecated
|
||||
// overload added for this issue forwards to from_bjdata(ptr, ptr + len,
|
||||
// ...) instead, like from_ubjson's deprecated (ptr, len) overload does.
|
||||
json result;
|
||||
CHECK_NOTHROW(result = json::from_bjdata(packed.data(), packed.size()));
|
||||
CHECK(result == j);
|
||||
|
||||
// len must not collapse into the strict flag either
|
||||
CHECK(json::from_bjdata(packed.data(), packed.size(), false) == j);
|
||||
#endif
|
||||
}
|
||||
|
||||
+2
-38
@@ -8,14 +8,6 @@
|
||||
|
||||
#include "doctest_compatibility.h"
|
||||
|
||||
// capture whether JSON_DELETE_DEPRECATED_FUNCTIONS was enabled on the command
|
||||
// line *before* including json.hpp, since the library #undefs it once the header
|
||||
// has been fully processed (see include/nlohmann/detail/macro_unscope.hpp); the
|
||||
// tests of deprecated functions are skipped if these functions are deleted
|
||||
#if defined(JSON_DELETE_DEPRECATED_FUNCTIONS) && (JSON_DELETE_DEPRECATED_FUNCTIONS == 1)
|
||||
#define JSON_TEST_DEPRECATED_FUNCTIONS_DELETED
|
||||
#endif
|
||||
|
||||
#include <nlohmann/json.hpp>
|
||||
using nlohmann::json;
|
||||
#ifdef JSON_TEST_NO_GLOBAL_UDLS
|
||||
@@ -794,6 +786,7 @@ TEST_CASE("Parse BON8 directly from a file using iterator and sentinel")
|
||||
CHECK((parsed.is_object() || parsed.is_array()));
|
||||
}
|
||||
|
||||
#if !defined(JSON_NOEXCEPTION) // corpus values that do not survive the round trip are skipped by catching the exception
|
||||
TEST_CASE("BON8 round-trip invariants")
|
||||
{
|
||||
// This checks what the parse_bon8_fuzzer driver checks (see
|
||||
@@ -826,6 +819,7 @@ TEST_CASE("BON8 round-trip invariants")
|
||||
CHECK(json::to_bon8(j2) == vec);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
TEST_CASE("BON8 roundtrips" * doctest::skip())
|
||||
{
|
||||
@@ -1020,36 +1014,6 @@ TEST_CASE("BON8 roundtrips" * doctest::skip())
|
||||
}
|
||||
}
|
||||
|
||||
TEST_CASE("issue #5648 - from_bon8(ptr, len) must read len bytes, not treat ptr as a C string")
|
||||
{
|
||||
// to_bon8() encodes the integer 40 as the two bytes 0xC2 0x00 (a BON8
|
||||
// lead byte followed by a continuation byte of 0x00), so the packed data
|
||||
// below contains a 0x00 byte before its end.
|
||||
const json j = {{"a", 40}, {"b", "x"}};
|
||||
const std::vector<std::uint8_t> packed = json::to_bon8(j);
|
||||
bool contains_nul = false;
|
||||
for (const auto byte : packed)
|
||||
{
|
||||
contains_nul |= (byte == 0x00);
|
||||
}
|
||||
REQUIRE(contains_nul);
|
||||
|
||||
#ifndef JSON_TEST_DEPRECATED_FUNCTIONS_DELETED
|
||||
// before the fix, from_bon8 had no (ptr, len) overload, so this call
|
||||
// bound to from_bon8(InputType&&, bool strict) instead: ptr was read as
|
||||
// a NUL-terminated C string (stopping at the embedded 0x00 byte), and
|
||||
// len was silently converted to the strict flag. The deprecated
|
||||
// overload added for this issue forwards to from_bon8(ptr, ptr + len,
|
||||
// ...) instead, like from_cbor's deprecated (ptr, len) overload does.
|
||||
json result;
|
||||
CHECK_NOTHROW(result = json::from_bon8(packed.data(), packed.size()));
|
||||
CHECK(result == j);
|
||||
|
||||
// len must not collapse into the strict flag either
|
||||
CHECK(json::from_bon8(packed.data(), packed.size(), false) == j);
|
||||
#endif
|
||||
}
|
||||
|
||||
#ifdef JSON_HAS_CPP_17
|
||||
TEST_CASE("BON8 with std::byte")
|
||||
{
|
||||
|
||||
+3
-13
@@ -8,14 +8,6 @@
|
||||
|
||||
#include "doctest_compatibility.h"
|
||||
|
||||
// capture whether JSON_DELETE_DEPRECATED_FUNCTIONS was enabled on the command
|
||||
// line *before* including json.hpp, since the library #undefs it once the header
|
||||
// has been fully processed (see include/nlohmann/detail/macro_unscope.hpp); the
|
||||
// tests of deprecated functions are skipped if these functions are deleted
|
||||
#if defined(JSON_DELETE_DEPRECATED_FUNCTIONS) && (JSON_DELETE_DEPRECATED_FUNCTIONS == 1)
|
||||
#define JSON_TEST_DEPRECATED_FUNCTIONS_DELETED
|
||||
#endif
|
||||
|
||||
#include <nlohmann/json.hpp>
|
||||
using nlohmann::json;
|
||||
|
||||
@@ -70,6 +62,8 @@ class huge_string_t : public std::string
|
||||
{
|
||||
public:
|
||||
using std::string::string;
|
||||
// inheriting std::string's constructors does not inherit its default constructor
|
||||
huge_string_t() = default;
|
||||
huge_string_t(const std::string& s) : std::string(s) {} // NOLINT(google-explicit-constructor,hicpp-explicit-conversions)
|
||||
|
||||
// returns a copy of @a s whose size() pretends to be huge
|
||||
@@ -182,7 +176,7 @@ TEST_CASE("BSON")
|
||||
REQUIRE(j.contains("s"));
|
||||
CHECK(j["s"].get_ref<const json::string_t&>() == std::string("\xc0\xae"));
|
||||
// dump() still requires valid UTF-8 and throws for such a value
|
||||
CHECK_THROWS_AS(j.dump(), json::type_error&);
|
||||
CHECK_THROWS_AS(utils::ignore_return_value(j.dump()), json::type_error&);
|
||||
// to_bson() writes the bytes back unchanged, as before 3.13.0,
|
||||
// unless JSON_STRICT_BINARY_UTF8 is enabled (see unit-binary_utf8_strict.cpp)
|
||||
CHECK(json::from_bson(json::to_bson(j)) == j);
|
||||
@@ -1267,10 +1261,8 @@ TEST_CASE("BSON input that cannot be read is discarded by every overload")
|
||||
CHECK_THROWS_AS(_ = json::from_bson(input.begin(), input.end()), json::parse_error&);
|
||||
CHECK(json::from_bson(input, true, false).is_discarded());
|
||||
CHECK(json::from_bson(input.begin(), input.end(), true, false).is_discarded());
|
||||
#ifndef JSON_TEST_DEPRECATED_FUNCTIONS_DELETED
|
||||
CHECK(json::from_bson(input.data(), input.size(), true, false).is_discarded());
|
||||
CHECK(json::from_bson({input.data(), input.size()}, true, false).is_discarded());
|
||||
#endif
|
||||
}
|
||||
|
||||
TEST_CASE("BSON SAX parsing stops at every event")
|
||||
@@ -1748,7 +1740,6 @@ TEST_CASE("BSON roundtrips" * doctest::skip())
|
||||
CHECK(j1 == j2);
|
||||
}
|
||||
|
||||
#ifndef JSON_TEST_DEPRECATED_FUNCTIONS_DELETED
|
||||
{
|
||||
INFO_WITH_TEMP(filename + ": uint8_t* and size");
|
||||
// parse JSON file
|
||||
@@ -1763,7 +1754,6 @@ TEST_CASE("BSON roundtrips" * doctest::skip())
|
||||
// compare parsed JSON values
|
||||
CHECK(j1 == j2);
|
||||
}
|
||||
#endif
|
||||
|
||||
{
|
||||
INFO_WITH_TEMP(filename + ": output to output adapters");
|
||||
|
||||
+5
-15
@@ -8,14 +8,6 @@
|
||||
|
||||
#include "doctest_compatibility.h"
|
||||
|
||||
// capture whether JSON_DELETE_DEPRECATED_FUNCTIONS was enabled on the command
|
||||
// line *before* including json.hpp, since the library #undefs it once the header
|
||||
// has been fully processed (see include/nlohmann/detail/macro_unscope.hpp); the
|
||||
// tests of deprecated functions are skipped if these functions are deleted
|
||||
#if defined(JSON_DELETE_DEPRECATED_FUNCTIONS) && (JSON_DELETE_DEPRECATED_FUNCTIONS == 1)
|
||||
#define JSON_TEST_DEPRECATED_FUNCTIONS_DELETED
|
||||
#endif
|
||||
|
||||
#include <nlohmann/json.hpp>
|
||||
using nlohmann::json;
|
||||
|
||||
@@ -1828,7 +1820,7 @@ TEST_CASE("CBOR")
|
||||
// dump() still requires valid UTF-8 and throws for such a value,
|
||||
// unless an error handler that replaces or ignores the bytes is
|
||||
// passed
|
||||
CHECK_THROWS_AS(j_value.dump(), json::type_error&);
|
||||
CHECK_THROWS_AS(utils::ignore_return_value(j_value.dump()), json::type_error&);
|
||||
// to_cbor() writes the bytes back unchanged, as before 3.13.0,
|
||||
// unless JSON_STRICT_BINARY_UTF8 is enabled (see unit-binary_utf8_strict.cpp)
|
||||
CHECK(json::from_cbor(json::to_cbor(j_value)) == j_value);
|
||||
@@ -1886,13 +1878,13 @@ TEST_CASE("CBOR")
|
||||
// a truncated code point is kept as is
|
||||
CHECK_NOTHROW(_ = json::from_cbor(std::vector<uint8_t>({0x7f, 0x61, 0xc3, 0xff})));
|
||||
CHECK(_ == "\xc3");
|
||||
CHECK_THROWS_AS(_.dump(), json::type_error&);
|
||||
CHECK_THROWS_AS(utils::ignore_return_value(_.dump()), json::type_error&);
|
||||
CHECK(json::from_cbor(json::to_cbor(_)) == _);
|
||||
|
||||
// an ill-formed later chunk is kept after valid ones
|
||||
CHECK_NOTHROW(_ = json::from_cbor(std::vector<uint8_t>({0x7f, 0x62, 0xc3, 0xa9, 0x62, 0xc0, 0xae, 0xff})));
|
||||
CHECK(_ == "\xc3\xa9\xc0\xae");
|
||||
CHECK_THROWS_AS(_.dump(), json::type_error&);
|
||||
CHECK_THROWS_AS(utils::ignore_return_value(_.dump()), json::type_error&);
|
||||
|
||||
// valid multi-byte chunks are accepted
|
||||
CHECK(json::from_cbor(std::vector<uint8_t>({0x7f, 0x62, 0xc3, 0xa9, 0x62, 0xc3, 0xb6, 0xff})) == "\xc3\xa9\xc3\xb6");
|
||||
@@ -2223,10 +2215,8 @@ TEST_CASE("CBOR input that cannot be read is discarded by every overload")
|
||||
CHECK_THROWS_AS(_ = json::from_cbor(input.begin(), input.end()), json::parse_error&);
|
||||
CHECK(json::from_cbor(input, true, false).is_discarded());
|
||||
CHECK(json::from_cbor(input.begin(), input.end(), true, false).is_discarded());
|
||||
#ifndef JSON_TEST_DEPRECATED_FUNCTIONS_DELETED
|
||||
CHECK(json::from_cbor(input.data(), input.size(), true, false).is_discarded());
|
||||
CHECK(json::from_cbor({input.data(), input.size()}, true, false).is_discarded());
|
||||
#endif
|
||||
|
||||
// a string that ends early, read through iterators that are not
|
||||
// contiguous and have to be copied from one element at a time
|
||||
@@ -2400,6 +2390,7 @@ TEST_CASE("issue #5405 - array reserve for definite-length CBOR arrays")
|
||||
}
|
||||
}
|
||||
|
||||
#if !defined(JSON_NOEXCEPTION) // corpus values that do not survive the round trip are skipped by catching the exception
|
||||
TEST_CASE("CBOR round-trip invariants")
|
||||
{
|
||||
// This checks what the parse_cbor_fuzzer driver checks (see
|
||||
@@ -2432,6 +2423,7 @@ TEST_CASE("CBOR round-trip invariants")
|
||||
CHECK(json::to_cbor(j2) == vec);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
TEST_CASE("CBOR roundtrips" * doctest::skip())
|
||||
{
|
||||
@@ -2621,14 +2613,12 @@ TEST_CASE("CBOR roundtrips" * doctest::skip())
|
||||
CHECK(j1 == j2);
|
||||
}
|
||||
|
||||
#ifndef JSON_TEST_DEPRECATED_FUNCTIONS_DELETED
|
||||
{
|
||||
INFO_WITH_TEMP(filename + ": uint8_t* and size");
|
||||
json j2;
|
||||
CHECK_NOTHROW(j2 = json::from_cbor({packed.data(), packed.size()}));
|
||||
CHECK(j1 == j2);
|
||||
}
|
||||
#endif
|
||||
|
||||
{
|
||||
INFO_WITH_TEMP(filename + ": output to output adapters");
|
||||
|
||||
@@ -2704,9 +2704,9 @@ TEST_CASE("diagnostic positions: value lifetime, input adapters, and SAX")
|
||||
CHECK(b["b"].end_pos() == nested_end);
|
||||
|
||||
// the moved-from value is reset to a null and reports npos
|
||||
CHECK(a.is_null()); // NOLINT(bugprone-use-after-move,clang-analyzer-cplusplus.Move)
|
||||
CHECK(a.start_pos() == std::string::npos); // NOLINT(bugprone-use-after-move,clang-analyzer-cplusplus.Move)
|
||||
CHECK(a.end_pos() == std::string::npos); // NOLINT(bugprone-use-after-move,clang-analyzer-cplusplus.Move)
|
||||
CHECK(a.is_null()); // NOLINT(bugprone-use-after-move,hicpp-invalid-access-moved,clang-analyzer-cplusplus.Move)
|
||||
CHECK(a.start_pos() == std::string::npos); // NOLINT(bugprone-use-after-move,hicpp-invalid-access-moved,clang-analyzer-cplusplus.Move)
|
||||
CHECK(a.end_pos() == std::string::npos); // NOLINT(bugprone-use-after-move,hicpp-invalid-access-moved,clang-analyzer-cplusplus.Move)
|
||||
}
|
||||
|
||||
SECTION("swap() exchanges positions along with values")
|
||||
|
||||
@@ -969,7 +969,7 @@ TEST_CASE("copying an object preserves its comparator's state")
|
||||
|
||||
for (const std::size_t depth : std::vector<std::size_t> {0, 127, 128, 200})
|
||||
{
|
||||
CAPTURE(depth);
|
||||
CAPTURE(depth)
|
||||
|
||||
key_case_json original = object;
|
||||
for (std::size_t i = 0; i < depth; ++i)
|
||||
@@ -1138,7 +1138,7 @@ TEST_CASE("operator<=> of binary values with a different subtype does not depend
|
||||
// and must still agree with the levels that do
|
||||
for (const std::size_t depth : std::vector<std::size_t> {0, 127, 128, 200})
|
||||
{
|
||||
CAPTURE(depth);
|
||||
CAPTURE(depth)
|
||||
const json x = deep(a, depth);
|
||||
const json y = deep(b, depth);
|
||||
CHECK((x <=> y) == std::partial_ordering::less); // *NOPAD*
|
||||
|
||||
@@ -15,11 +15,6 @@
|
||||
|
||||
#include "doctest_compatibility.h"
|
||||
|
||||
// skip tests if JSON_DisableEnumSerialization=ON (#4384)
|
||||
#if defined(JSON_DISABLE_ENUM_SERIALIZATION) && (JSON_DISABLE_ENUM_SERIALIZATION == 1)
|
||||
#define SKIP_TESTS_FOR_ENUM_SERIALIZATION
|
||||
#endif
|
||||
|
||||
#define JSON_TESTS_PRIVATE
|
||||
#include <nlohmann/json.hpp>
|
||||
using nlohmann::json;
|
||||
@@ -1259,808 +1254,8 @@ TEST_CASE("value conversion")
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
SECTION("get a binary value (explicit)")
|
||||
{
|
||||
json::binary_t const n_reference{{1, 2, 3}};
|
||||
json j(n_reference);
|
||||
|
||||
SECTION("binary_t")
|
||||
{
|
||||
json::binary_t const b = j.get<json::binary_t>();
|
||||
CHECK(*json(b).m_data.m_value.binary == *j.m_data.m_value.binary);
|
||||
}
|
||||
|
||||
SECTION("get_binary()")
|
||||
{
|
||||
SECTION("non-const")
|
||||
{
|
||||
auto& b = j.get_binary();
|
||||
CHECK(*json(b).m_data.m_value.binary == *j.m_data.m_value.binary);
|
||||
}
|
||||
|
||||
SECTION("non-const")
|
||||
{
|
||||
const json j_const = j; // NOLINT(performance-unnecessary-copy-initialization)
|
||||
const auto& b = j_const.get_binary();
|
||||
CHECK(*json(b).m_data.m_value.binary == *j.m_data.m_value.binary);
|
||||
}
|
||||
}
|
||||
|
||||
SECTION("exception in case of a non-string type")
|
||||
{
|
||||
json j_null(json::value_t::null);
|
||||
json j_object(json::value_t::object);
|
||||
json j_array(json::value_t::array);
|
||||
json j_string(json::value_t::string);
|
||||
json j_boolean(json::value_t::boolean);
|
||||
const json j_null_const(json::value_t::null);
|
||||
const json j_object_const(json::value_t::object);
|
||||
const json j_array_const(json::value_t::array);
|
||||
const json j_string_const(json::value_t::string);
|
||||
const json j_boolean_const(json::value_t::boolean);
|
||||
|
||||
CHECK_THROWS_WITH_AS(j_null.get<json::binary_t>(),
|
||||
"[json.exception.type_error.302] type must be binary, but is null",
|
||||
json::type_error&);
|
||||
CHECK_THROWS_WITH_AS(j_object.get<json::binary_t>(),
|
||||
"[json.exception.type_error.302] type must be binary, but is object",
|
||||
json::type_error&);
|
||||
CHECK_THROWS_WITH_AS(j_array.get<json::binary_t>(),
|
||||
"[json.exception.type_error.302] type must be binary, but is array",
|
||||
json::type_error&);
|
||||
CHECK_THROWS_WITH_AS(j_string.get<json::binary_t>(),
|
||||
"[json.exception.type_error.302] type must be binary, but is string",
|
||||
json::type_error&);
|
||||
CHECK_THROWS_WITH_AS(j_boolean.get<json::binary_t>(),
|
||||
"[json.exception.type_error.302] type must be binary, but is boolean",
|
||||
json::type_error&);
|
||||
|
||||
CHECK_THROWS_WITH_AS(j_null_const.get<json::binary_t>(),
|
||||
"[json.exception.type_error.302] type must be binary, but is null",
|
||||
json::type_error&);
|
||||
CHECK_THROWS_WITH_AS(j_object_const.get<json::binary_t>(),
|
||||
"[json.exception.type_error.302] type must be binary, but is object",
|
||||
json::type_error&);
|
||||
CHECK_THROWS_WITH_AS(j_array_const.get<json::binary_t>(),
|
||||
"[json.exception.type_error.302] type must be binary, but is array",
|
||||
json::type_error&);
|
||||
CHECK_THROWS_WITH_AS(j_string_const.get<json::binary_t>(),
|
||||
"[json.exception.type_error.302] type must be binary, but is string",
|
||||
json::type_error&);
|
||||
CHECK_THROWS_WITH_AS(j_boolean_const.get<json::binary_t>(),
|
||||
"[json.exception.type_error.302] type must be binary, but is boolean",
|
||||
json::type_error&);
|
||||
|
||||
CHECK_THROWS_WITH_AS(j_null.get_binary(),
|
||||
"[json.exception.type_error.302] type must be binary, but is null",
|
||||
json::type_error&);
|
||||
CHECK_THROWS_WITH_AS(j_object.get_binary(),
|
||||
"[json.exception.type_error.302] type must be binary, but is object",
|
||||
json::type_error&);
|
||||
CHECK_THROWS_WITH_AS(j_array.get_binary(),
|
||||
"[json.exception.type_error.302] type must be binary, but is array",
|
||||
json::type_error&);
|
||||
CHECK_THROWS_WITH_AS(j_string.get_binary(),
|
||||
"[json.exception.type_error.302] type must be binary, but is string",
|
||||
json::type_error&);
|
||||
CHECK_THROWS_WITH_AS(j_boolean.get_binary(),
|
||||
"[json.exception.type_error.302] type must be binary, but is boolean",
|
||||
json::type_error&);
|
||||
|
||||
CHECK_THROWS_WITH_AS(j_null_const.get_binary(),
|
||||
"[json.exception.type_error.302] type must be binary, but is null",
|
||||
json::type_error&);
|
||||
CHECK_THROWS_WITH_AS(j_object_const.get_binary(),
|
||||
"[json.exception.type_error.302] type must be binary, but is object",
|
||||
json::type_error&);
|
||||
CHECK_THROWS_WITH_AS(j_array_const.get_binary(),
|
||||
"[json.exception.type_error.302] type must be binary, but is array",
|
||||
json::type_error&);
|
||||
CHECK_THROWS_WITH_AS(j_string_const.get_binary(),
|
||||
"[json.exception.type_error.302] type must be binary, but is string",
|
||||
json::type_error&);
|
||||
CHECK_THROWS_WITH_AS(j_boolean_const.get_binary(),
|
||||
"[json.exception.type_error.302] type must be binary, but is boolean",
|
||||
json::type_error&);
|
||||
}
|
||||
}
|
||||
|
||||
#if JSON_USE_IMPLICIT_CONVERSIONS
|
||||
SECTION("get a binary value (implicit)")
|
||||
{
|
||||
json::binary_t const n_reference{{1, 2, 3}};
|
||||
json const j(n_reference);
|
||||
|
||||
SECTION("binary_t")
|
||||
{
|
||||
json::binary_t const b = j;
|
||||
CHECK(*json(b).m_data.m_value.binary == *j.m_data.m_value.binary);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifndef SKIP_TESTS_FOR_ENUM_SERIALIZATION
|
||||
SECTION("get an enum")
|
||||
{
|
||||
enum c_enum { value_1, value_2 }; // NOLINT(cppcoreguidelines-use-enum-class)
|
||||
enum class cpp_enum { value_1, value_2 };
|
||||
|
||||
CHECK(json(value_1).get<c_enum>() == value_1);
|
||||
CHECK(json(cpp_enum::value_1).get<cpp_enum>() == cpp_enum::value_1);
|
||||
}
|
||||
|
||||
SECTION("get an enum with underlying type bool (#5671)")
|
||||
{
|
||||
enum class bool_enum : bool { off, on };
|
||||
|
||||
CHECK(json(bool_enum::off).get<bool_enum>() == bool_enum::off);
|
||||
CHECK(json(bool_enum::on).get<bool_enum>() == bool_enum::on);
|
||||
}
|
||||
#endif
|
||||
|
||||
SECTION("more involved conversions")
|
||||
{
|
||||
SECTION("object-like STL containers")
|
||||
{
|
||||
json const j1 = {{"one", 1}, {"two", 2}, {"three", 3}};
|
||||
json const j2 = {{"one", 1u}, {"two", 2u}, {"three", 3u}};
|
||||
json const j3 = {{"one", 1.1}, {"two", 2.2}, {"three", 3.3}};
|
||||
json const j4 = {{"one", true}, {"two", false}, {"three", true}};
|
||||
json const j5 = {{"one", "eins"}, {"two", "zwei"}, {"three", "drei"}};
|
||||
|
||||
SECTION("std::map")
|
||||
{
|
||||
CHECK(j1.get<std::map<std::string, int>>() == (std::map<std::string, int> {{"one", 1}, {"two", 2}, {"three", 3}}));
|
||||
CHECK(j2.get<std::map<std::string, unsigned int>>() == (std::map<std::string, unsigned int> {{"one", 1u}, {"two", 2u}, {"three", 3u}}));
|
||||
CHECK(j3.get<std::map<std::string, double>>() == (std::map<std::string, double> {{"one", 1.1}, {"two", 2.2}, {"three", 3.3}}));
|
||||
CHECK(j4.get<std::map<std::string, bool>>() == (std::map<std::string, bool> {{"one", true}, {"two", false}, {"three", true}}));
|
||||
CHECK(j5.get<std::map<std::string, std::string>>() == (std::map<std::string, std::string> {{"one", "eins"}, {"two", "zwei"}, {"three", "drei"}}));
|
||||
}
|
||||
|
||||
SECTION("std::unordered_map")
|
||||
{
|
||||
CHECK(j1.get<std::unordered_map<std::string, int>>() == (std::unordered_map<std::string, int> {{"one", 1}, {"two", 2}, {"three", 3}}));
|
||||
CHECK(j2.get<std::unordered_map<std::string, unsigned int>>() == (std::unordered_map<std::string, unsigned int> {{"one", 1u}, {"two", 2u}, {"three", 3u}}));
|
||||
CHECK(j3.get<std::unordered_map<std::string, double>>() == (std::unordered_map<std::string, double> {{"one", 1.1}, {"two", 2.2}, {"three", 3.3}}));
|
||||
CHECK(j4.get<std::unordered_map<std::string, bool>>() == (std::unordered_map<std::string, bool> {{"one", true}, {"two", false}, {"three", true}}));
|
||||
const auto m5 = j5.get<std::unordered_map<std::string, std::string>>();
|
||||
CHECK(m5 == (std::unordered_map<std::string, std::string> {{"one", "eins"}, {"two", "zwei"}, {"three", "drei"}}));
|
||||
CHECK(m5.at("one") == "eins");
|
||||
}
|
||||
|
||||
SECTION("reserve is called on containers that support it (#5406)")
|
||||
{
|
||||
// build a larger object so that a missing/incorrect reserve()
|
||||
// call would be more likely to corrupt or drop elements
|
||||
json j_large;
|
||||
for (int i = 0; i < 100; ++i)
|
||||
{
|
||||
j_large[std::to_string(i)] = i;
|
||||
}
|
||||
|
||||
SECTION("std::unordered_map (supports reserve)")
|
||||
{
|
||||
const auto m = j_large.get<std::unordered_map<std::string, int>>();
|
||||
CHECK(m.size() == 100);
|
||||
for (int i = 0; i < 100; ++i)
|
||||
{
|
||||
CHECK(m.at(std::to_string(i)) == i);
|
||||
}
|
||||
}
|
||||
|
||||
SECTION("std::map (no reserve, fallback path)")
|
||||
{
|
||||
const auto m = j_large.get<std::map<std::string, int>>();
|
||||
CHECK(m.size() == 100);
|
||||
for (int i = 0; i < 100; ++i)
|
||||
{
|
||||
CHECK(m.at(std::to_string(i)) == i);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
SECTION("std::multimap")
|
||||
{
|
||||
CHECK(j1.get<std::multimap<std::string, int>>() == (std::multimap<std::string, int> {{"one", 1}, {"two", 2}, {"three", 3}}));
|
||||
CHECK(j2.get<std::multimap<std::string, unsigned int>>() == (std::multimap<std::string, unsigned int> {{"one", 1u}, {"two", 2u}, {"three", 3u}}));
|
||||
CHECK(j3.get<std::multimap<std::string, double>>() == (std::multimap<std::string, double> {{"one", 1.1}, {"two", 2.2}, {"three", 3.3}}));
|
||||
CHECK(j4.get<std::multimap<std::string, bool>>() == (std::multimap<std::string, bool> {{"one", true}, {"two", false}, {"three", true}}));
|
||||
const auto m5 = j5.get<std::multimap<std::string, std::string>>();
|
||||
CHECK(m5 == (std::multimap<std::string, std::string> {{"one", "eins"}, {"two", "zwei"}, {"three", "drei"}}));
|
||||
CHECK(m5.find("one")->second == "eins");
|
||||
}
|
||||
|
||||
SECTION("std::unordered_multimap")
|
||||
{
|
||||
CHECK(j1.get<std::unordered_multimap<std::string, int>>() == (std::unordered_multimap<std::string, int> {{"one", 1}, {"two", 2}, {"three", 3}}));
|
||||
CHECK(j2.get<std::unordered_multimap<std::string, unsigned int>>() == (std::unordered_multimap<std::string, unsigned int> {{"one", 1u}, {"two", 2u}, {"three", 3u}}));
|
||||
CHECK(j3.get<std::unordered_multimap<std::string, double>>() == (std::unordered_multimap<std::string, double> {{"one", 1.1}, {"two", 2.2}, {"three", 3.3}}));
|
||||
CHECK(j4.get<std::unordered_multimap<std::string, bool>>() == (std::unordered_multimap<std::string, bool> {{"one", true}, {"two", false}, {"three", true}}));
|
||||
const auto m5 = j5.get<std::unordered_multimap<std::string, std::string>>();
|
||||
CHECK(m5 == (std::unordered_multimap<std::string, std::string> {{"one", "eins"}, {"two", "zwei"}, {"three", "drei"}}));
|
||||
CHECK(m5.find("one")->second == "eins");
|
||||
}
|
||||
|
||||
SECTION("exception in case of a non-object type")
|
||||
{
|
||||
CHECK_THROWS_WITH_AS(
|
||||
(json().get<std::map<std::string, int>>()),
|
||||
"[json.exception.type_error.302] type must be object, but is null", json::type_error&);
|
||||
}
|
||||
}
|
||||
|
||||
SECTION("array-like STL containers")
|
||||
{
|
||||
json const j1 = {1, 2, 3, 4};
|
||||
json const j2 = {1u, 2u, 3u, 4u};
|
||||
json const j3 = {1.2, 2.3, 3.4, 4.5};
|
||||
json const j4 = {true, false, true};
|
||||
json const j5 = {"one", "two", "three"};
|
||||
|
||||
SECTION("std::list")
|
||||
{
|
||||
CHECK(j1.get<std::list<int>>() == (std::list<int> {1, 2, 3, 4}));
|
||||
CHECK(j2.get<std::list<unsigned int>>() == (std::list<unsigned int> {1u, 2u, 3u, 4u}));
|
||||
CHECK(j3.get<std::list<double>>() == (std::list<double> {1.2, 2.3, 3.4, 4.5}));
|
||||
CHECK(j4.get<std::list<bool>>() == (std::list<bool> {true, false, true}));
|
||||
CHECK(j5.get<std::list<std::string>>() == (std::list<std::string> {"one", "two", "three"}));
|
||||
}
|
||||
|
||||
SECTION("std::forward_list")
|
||||
{
|
||||
CHECK(j1.get<std::forward_list<int>>() == (std::forward_list<int> {1, 2, 3, 4}));
|
||||
CHECK(j2.get<std::forward_list<unsigned int>>() == (std::forward_list<unsigned int> {1u, 2u, 3u, 4u}));
|
||||
CHECK(j3.get<std::forward_list<double>>() == (std::forward_list<double> {1.2, 2.3, 3.4, 4.5}));
|
||||
CHECK(j4.get<std::forward_list<bool>>() == (std::forward_list<bool> {true, false, true}));
|
||||
CHECK(j5.get<std::forward_list<std::string>>() == (std::forward_list<std::string> {"one", "two", "three"}));
|
||||
}
|
||||
|
||||
SECTION("std::array")
|
||||
{
|
||||
CHECK(j1.get<std::array<int, 4>>() == (std::array<int, 4> {{1, 2, 3, 4}}));
|
||||
// only the first 3 elements of j2 are converted, since the target array is smaller
|
||||
CHECK(j2.get<std::array<unsigned int, 3>>() == (std::array<unsigned int, 3> {{1u, 2u, 3u}}));
|
||||
CHECK(j3.get<std::array<double, 4>>() == (std::array<double, 4> {{1.2, 2.3, 3.4, 4.5}}));
|
||||
CHECK(j4.get<std::array<bool, 3>>() == (std::array<bool, 3> {{true, false, true}}));
|
||||
CHECK(j5.get<std::array<std::string, 3>>() == (std::array<std::string, 3> {{"one", "two", "three"}}));
|
||||
|
||||
SECTION("std::array is larger than JSON")
|
||||
{
|
||||
std::array<int, 6> arr6 = {{1, 2, 3, 4, 5, 6}};
|
||||
CHECK_THROWS_WITH_AS(j1.get_to(arr6), "[json.exception.out_of_range.401] "
|
||||
"array index 4 is out of range", json::out_of_range&);
|
||||
}
|
||||
|
||||
SECTION("std::array is smaller than JSON")
|
||||
{
|
||||
std::array<int, 2> arr2 = {{8, 9}};
|
||||
j1.get_to(arr2);
|
||||
CHECK(arr2[0] == 1);
|
||||
CHECK(arr2[1] == 2);
|
||||
}
|
||||
}
|
||||
|
||||
SECTION("std::valarray")
|
||||
{
|
||||
// valarray has no operator== that returns bool, so compare via a vector copy
|
||||
const auto v1 = j1.get<std::valarray<int>>();
|
||||
CHECK((std::vector<int>(std::begin(v1), std::end(v1)) == std::vector<int> {1, 2, 3, 4}));
|
||||
const auto v2 = j2.get<std::valarray<unsigned int>>();
|
||||
CHECK((std::vector<unsigned int>(std::begin(v2), std::end(v2)) == std::vector<unsigned int> {1u, 2u, 3u, 4u}));
|
||||
const auto v3 = j3.get<std::valarray<double>>();
|
||||
CHECK((std::vector<double>(std::begin(v3), std::end(v3)) == std::vector<double> {1.2, 2.3, 3.4, 4.5}));
|
||||
const auto v4 = j4.get<std::valarray<bool>>();
|
||||
CHECK((std::vector<bool>(std::begin(v4), std::end(v4)) == std::vector<bool> {true, false, true}));
|
||||
const auto v5 = j5.get<std::valarray<std::string>>();
|
||||
CHECK((std::vector<std::string>(std::begin(v5), std::end(v5)) == std::vector<std::string> {"one", "two", "three"}));
|
||||
}
|
||||
|
||||
SECTION("std::vector")
|
||||
{
|
||||
CHECK(j1.get<std::vector<int>>() == (std::vector<int> {1, 2, 3, 4}));
|
||||
CHECK(j2.get<std::vector<unsigned int>>() == (std::vector<unsigned int> {1u, 2u, 3u, 4u}));
|
||||
CHECK(j3.get<std::vector<double>>() == (std::vector<double> {1.2, 2.3, 3.4, 4.5}));
|
||||
CHECK(j4.get<std::vector<bool>>() == (std::vector<bool> {true, false, true}));
|
||||
CHECK(j5.get<std::vector<std::string>>() == (std::vector<std::string> {"one", "two", "three"}));
|
||||
}
|
||||
|
||||
SECTION("std::deque")
|
||||
{
|
||||
CHECK(j1.get<std::deque<int>>() == (std::deque<int> {1, 2, 3, 4}));
|
||||
CHECK(j2.get<std::deque<unsigned int>>() == (std::deque<unsigned int> {1u, 2u, 3u, 4u}));
|
||||
CHECK(j3.get<std::deque<double>>() == (std::deque<double> {1.2, 2.3, 3.4, 4.5}));
|
||||
CHECK(j4.get<std::deque<bool>>() == (std::deque<bool> {true, false, true}));
|
||||
CHECK(j5.get<std::deque<std::string>>() == (std::deque<std::string> {"one", "two", "three"}));
|
||||
}
|
||||
|
||||
SECTION("std::set")
|
||||
{
|
||||
CHECK(j1.get<std::set<int>>() == (std::set<int> {1, 2, 3, 4}));
|
||||
CHECK(j2.get<std::set<unsigned int>>() == (std::set<unsigned int> {1u, 2u, 3u, 4u}));
|
||||
CHECK(j3.get<std::set<double>>() == (std::set<double> {1.2, 2.3, 3.4, 4.5}));
|
||||
CHECK(j4.get<std::set<bool>>() == (std::set<bool> {true, false, true}));
|
||||
CHECK(j5.get<std::set<std::string>>() == (std::set<std::string> {"one", "two", "three"}));
|
||||
}
|
||||
|
||||
SECTION("std::unordered_set")
|
||||
{
|
||||
CHECK(j1.get<std::unordered_set<int>>() == (std::unordered_set<int> {1, 2, 3, 4}));
|
||||
CHECK(j2.get<std::unordered_set<unsigned int>>() == (std::unordered_set<unsigned int> {1u, 2u, 3u, 4u}));
|
||||
CHECK(j3.get<std::unordered_set<double>>() == (std::unordered_set<double> {1.2, 2.3, 3.4, 4.5}));
|
||||
CHECK(j4.get<std::unordered_set<bool>>() == (std::unordered_set<bool> {true, false, true}));
|
||||
CHECK(j5.get<std::unordered_set<std::string>>() == (std::unordered_set<std::string> {"one", "two", "three"}));
|
||||
}
|
||||
|
||||
SECTION("std::map (array of pairs)")
|
||||
{
|
||||
const std::map<int, int> m{{0, 1}, {1, 2}, {2, 3}};
|
||||
json const j6 = m;
|
||||
|
||||
auto m2 = j6.get<std::map<int, int>>();
|
||||
CHECK(m == m2);
|
||||
|
||||
json const j7 = {0, 1, 2, 3};
|
||||
json const j8 = 2;
|
||||
#if JSON_DIAGNOSTICS
|
||||
CHECK_THROWS_WITH_AS((j7.get<std::map<int, int>>()),
|
||||
"[json.exception.type_error.302] (/0) type must be array, "
|
||||
"but is number", json::type_error&);
|
||||
#else
|
||||
CHECK_THROWS_WITH_AS((j7.get<std::map<int, int>>()),
|
||||
"[json.exception.type_error.302] type must be array, "
|
||||
"but is number", json::type_error&);
|
||||
#endif
|
||||
CHECK_THROWS_WITH_AS((j8.get<std::map<int, int>>()),
|
||||
"[json.exception.type_error.302] type must be array, "
|
||||
"but is number", json::type_error&);
|
||||
|
||||
SECTION("superfluous entries")
|
||||
{
|
||||
json const j9 = {{0, 1, 2}, {1, 2, 3}, {2, 3, 4}};
|
||||
m2 = j9.get<std::map<int, int>>();
|
||||
CHECK(m == m2);
|
||||
}
|
||||
}
|
||||
|
||||
SECTION("std::unordered_map (array of pairs)")
|
||||
{
|
||||
const std::unordered_map<int, int> m{{0, 1}, {1, 2}, {2, 3}};
|
||||
json const j6 = m;
|
||||
|
||||
auto m2 = j6.get<std::unordered_map<int, int>>();
|
||||
CHECK(m == m2);
|
||||
|
||||
json const j7 = {0, 1, 2, 3};
|
||||
json const j8 = 2;
|
||||
#if JSON_DIAGNOSTICS
|
||||
CHECK_THROWS_WITH_AS((j7.get<std::unordered_map<int, int>>()),
|
||||
"[json.exception.type_error.302] (/0) type must be array, "
|
||||
"but is number", json::type_error&);
|
||||
#else
|
||||
CHECK_THROWS_WITH_AS((j7.get<std::unordered_map<int, int>>()),
|
||||
"[json.exception.type_error.302] type must be array, "
|
||||
"but is number", json::type_error&);
|
||||
#endif
|
||||
CHECK_THROWS_WITH_AS((j8.get<std::unordered_map<int, int>>()),
|
||||
"[json.exception.type_error.302] type must be array, "
|
||||
"but is number", json::type_error&);
|
||||
|
||||
SECTION("superfluous entries")
|
||||
{
|
||||
json const j9{{0, 1, 2}, {1, 2, 3}, {2, 3, 4}};
|
||||
m2 = j9.get<std::unordered_map<int, int>>();
|
||||
CHECK(m == m2);
|
||||
}
|
||||
}
|
||||
|
||||
SECTION("exception in case of a non-object type")
|
||||
{
|
||||
// does type really must be an array? or it rather must not be null?
|
||||
// that's what I thought when other test like this one broke
|
||||
CHECK_THROWS_WITH_AS(
|
||||
(json().get<std::list<int>>()),
|
||||
"[json.exception.type_error.302] type must be array, but is null", json::type_error&);
|
||||
CHECK_THROWS_WITH_AS(
|
||||
(json().get<std::vector<int>>()),
|
||||
"[json.exception.type_error.302] type must be array, but is null", json::type_error&);
|
||||
CHECK_THROWS_WITH_AS(
|
||||
(json().get<std::vector<json>>()),
|
||||
"[json.exception.type_error.302] type must be array, but is null", json::type_error&);
|
||||
CHECK_THROWS_WITH_AS(
|
||||
(json().get<std::list<json>>()),
|
||||
"[json.exception.type_error.302] type must be array, but is null", json::type_error&);
|
||||
CHECK_THROWS_WITH_AS(
|
||||
(json().get<std::valarray<int>>()),
|
||||
"[json.exception.type_error.302] type must be array, but is null", json::type_error&);
|
||||
CHECK_THROWS_WITH_AS(
|
||||
(json().get<std::map<int, int>>()),
|
||||
"[json.exception.type_error.302] type must be array, but is null", json::type_error&);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
enum class cards {kreuz, pik, herz, karo};
|
||||
|
||||
// NOLINTNEXTLINE(misc-use-internal-linkage,misc-const-correctness) - false positive
|
||||
NLOHMANN_JSON_SERIALIZE_ENUM(cards,
|
||||
{
|
||||
{cards::kreuz, "kreuz"},
|
||||
{cards::pik, "pik"},
|
||||
{cards::pik, "puk"}, // second entry for cards::puk; will not be used
|
||||
{cards::herz, "herz"},
|
||||
{cards::karo, "karo"}
|
||||
})
|
||||
|
||||
enum TaskState // NOLINT(cert-int09-c,readability-enum-initial-value,cppcoreguidelines-use-enum-class)
|
||||
{
|
||||
TS_STOPPED,
|
||||
TS_RUNNING,
|
||||
TS_COMPLETED,
|
||||
TS_INVALID = -1,
|
||||
};
|
||||
|
||||
// NOLINTNEXTLINE(misc-const-correctness,misc-use-internal-linkage) - false positive
|
||||
NLOHMANN_JSON_SERIALIZE_ENUM(TaskState,
|
||||
{
|
||||
{TS_INVALID, nullptr},
|
||||
{TS_STOPPED, "stopped"},
|
||||
{TS_RUNNING, "running"},
|
||||
{TS_COMPLETED, "completed"},
|
||||
})
|
||||
|
||||
TEST_CASE("JSON to enum mapping")
|
||||
{
|
||||
SECTION("enum class")
|
||||
{
|
||||
// enum -> json
|
||||
CHECK(json(cards::kreuz) == "kreuz");
|
||||
CHECK(json(cards::pik) == "pik");
|
||||
CHECK(json(cards::herz) == "herz");
|
||||
CHECK(json(cards::karo) == "karo");
|
||||
|
||||
// json -> enum
|
||||
CHECK(cards::kreuz == json("kreuz"));
|
||||
CHECK(cards::pik == json("pik"));
|
||||
CHECK(cards::herz == json("herz"));
|
||||
CHECK(cards::karo == json("karo"));
|
||||
|
||||
// invalid json -> first enum
|
||||
CHECK(cards::kreuz == json("what?").get<cards>());
|
||||
}
|
||||
|
||||
SECTION("traditional enum")
|
||||
{
|
||||
// enum -> json
|
||||
CHECK(json(TS_STOPPED) == "stopped");
|
||||
CHECK(json(TS_RUNNING) == "running");
|
||||
CHECK(json(TS_COMPLETED) == "completed");
|
||||
CHECK(json(TS_INVALID) == json());
|
||||
|
||||
// json -> enum
|
||||
CHECK(TS_STOPPED == json("stopped"));
|
||||
CHECK(TS_RUNNING == json("running"));
|
||||
CHECK(TS_COMPLETED == json("completed"));
|
||||
CHECK(TS_INVALID == json());
|
||||
|
||||
// invalid json -> first enum
|
||||
CHECK(TS_INVALID == json("what?").get<TaskState>());
|
||||
}
|
||||
}
|
||||
|
||||
enum class strict_cards {kreuz, pik, herz, karo, andere}; // andere not included in mapping
|
||||
|
||||
// NOLINTNEXTLINE(misc-use-internal-linkage,misc-const-correctness) - false positive
|
||||
NLOHMANN_JSON_SERIALIZE_ENUM_STRICT(strict_cards,
|
||||
{
|
||||
{strict_cards::kreuz, "kreuz"},
|
||||
{strict_cards::pik, "pik"},
|
||||
{strict_cards::pik, "puk"}, // second entry for cards::pik; will not be used
|
||||
{strict_cards::herz, "herz"},
|
||||
{strict_cards::karo, "karo"}
|
||||
})
|
||||
|
||||
enum StrictTaskState // NOLINT(cert-int09-c,readability-enum-initial-value,cppcoreguidelines-use-enum-class)
|
||||
{
|
||||
STRICT_TS_STOPPED,
|
||||
STRICT_TS_RUNNING,
|
||||
STRICT_TS_COMPLETED,
|
||||
STRICT_TS_OTHER, // STRICT_TS_OTHER not in mapping
|
||||
STRICT_TS_INVALID = -1,
|
||||
};
|
||||
|
||||
// NOLINTNEXTLINE(misc-const-correctness,misc-use-internal-linkage) - false positive
|
||||
NLOHMANN_JSON_SERIALIZE_ENUM_STRICT(StrictTaskState,
|
||||
{
|
||||
{STRICT_TS_INVALID, nullptr},
|
||||
{STRICT_TS_STOPPED, "stopped"},
|
||||
{STRICT_TS_RUNNING, "running"},
|
||||
{STRICT_TS_COMPLETED, "completed"},
|
||||
})
|
||||
|
||||
// regression test for #5708 item 2: NLOHMANN_JSON_SERIALIZE_ENUM_STRICT must not rely on
|
||||
// unqualified lookup of a helper name that a user's own namespace may also declare
|
||||
namespace ns_with_colliding_name
|
||||
{
|
||||
// NOLINTNEXTLINE(misc-use-internal-linkage) - used to shadow the library's internal helper name
|
||||
inline void templated_json_throw(int /*unused*/) {}
|
||||
|
||||
enum class colliding_enum { a, b };
|
||||
|
||||
// NOLINTNEXTLINE(misc-use-internal-linkage,misc-const-correctness,cppcoreguidelines-avoid-c-arrays,hicpp-avoid-c-arrays,modernize-avoid-c-arrays) - false positive
|
||||
NLOHMANN_JSON_SERIALIZE_ENUM_STRICT(colliding_enum,
|
||||
{
|
||||
{colliding_enum::a, "a"},
|
||||
{colliding_enum::b, "b"}
|
||||
})
|
||||
} // namespace ns_with_colliding_name
|
||||
|
||||
TEST_CASE("NLOHMANN_JSON_SERIALIZE_ENUM_STRICT in a namespace with a colliding name")
|
||||
{
|
||||
using ns_with_colliding_name::colliding_enum;
|
||||
|
||||
CHECK(json(colliding_enum::a) == "a");
|
||||
CHECK(colliding_enum::b == json("b"));
|
||||
|
||||
json _;
|
||||
CHECK_THROWS_WITH_AS(_ = json("nope").get<colliding_enum>(), "[json.exception.out_of_range.410] enum value out of range for colliding_enum: \"nope\"", json::out_of_range&);
|
||||
}
|
||||
|
||||
TEST_CASE("Strict JSON to enum mapping")
|
||||
{
|
||||
SECTION("enum class")
|
||||
{
|
||||
// enum -> json
|
||||
CHECK(json(strict_cards::kreuz) == "kreuz");
|
||||
CHECK(json(strict_cards::pik) == "pik");
|
||||
CHECK(json(strict_cards::herz) == "herz");
|
||||
CHECK(json(strict_cards::karo) == "karo");
|
||||
|
||||
// json -> enum
|
||||
CHECK(json("kreuz").get<strict_cards>() == strict_cards::kreuz);
|
||||
CHECK(json("pik").get<strict_cards>() == strict_cards::pik);
|
||||
CHECK(json("herz").get<strict_cards>() == strict_cards::herz);
|
||||
CHECK(json("karo").get<strict_cards>() == strict_cards::karo);
|
||||
|
||||
// comparison of enum and json
|
||||
CHECK(strict_cards::kreuz == json("kreuz"));
|
||||
CHECK(strict_cards::pik == json("pik"));
|
||||
CHECK(strict_cards::herz == json("herz"));
|
||||
CHECK(strict_cards::karo == json("karo"));
|
||||
|
||||
// invalid json -> exception thrown
|
||||
json _;
|
||||
CHECK_THROWS_WITH_AS(_ = json("what?").get<strict_cards>(), "[json.exception.out_of_range.410] enum value out of range for strict_cards: \"what?\"", json::out_of_range&);
|
||||
|
||||
// conversion of unmapped enum -> exception thrown
|
||||
CHECK_THROWS_WITH_AS(json(strict_cards::andere), "[json.exception.out_of_range.410] enum value out of range for strict_cards", json::out_of_range&);
|
||||
|
||||
// comparing an unmapped enum with json throws the same exception
|
||||
// (the scalar comparison operators used to be noexcept, so this
|
||||
// called std::terminate)
|
||||
CHECK_THROWS_WITH_AS(static_cast<void>(strict_cards::andere == json("andere")), "[json.exception.out_of_range.410] enum value out of range for strict_cards", json::out_of_range&);
|
||||
CHECK_THROWS_WITH_AS(static_cast<void>(json("andere") != strict_cards::andere), "[json.exception.out_of_range.410] enum value out of range for strict_cards", json::out_of_range&);
|
||||
|
||||
// invalid UTF-8 -> out_of_range.410, not the type_error.316 thrown while building the
|
||||
// message (regression test for #5667); such strings can reach get<Enum>() unvalidated,
|
||||
// e.g. from from_cbor()/from_msgpack() (#5529)
|
||||
const json j_invalid_utf8 = "\xFF";
|
||||
CHECK_THROWS_WITH_AS(_ = j_invalid_utf8.get<strict_cards>(), "[json.exception.out_of_range.410] enum value out of range for strict_cards: \"\xEF\xBF\xBD\"", json::out_of_range&);
|
||||
}
|
||||
|
||||
SECTION("traditional enum")
|
||||
{
|
||||
// enum -> json
|
||||
CHECK(json(STRICT_TS_STOPPED) == "stopped");
|
||||
CHECK(json(STRICT_TS_RUNNING) == "running");
|
||||
CHECK(json(STRICT_TS_COMPLETED) == "completed");
|
||||
CHECK(json(STRICT_TS_INVALID) == json());
|
||||
|
||||
// json -> enum
|
||||
CHECK(json("stopped").get<StrictTaskState>() == STRICT_TS_STOPPED);
|
||||
CHECK(json("running").get<StrictTaskState>() == STRICT_TS_RUNNING);
|
||||
CHECK(json("completed").get<StrictTaskState>() == STRICT_TS_COMPLETED);
|
||||
CHECK(json().get<StrictTaskState>() == STRICT_TS_INVALID);
|
||||
|
||||
// comparison of enum and json
|
||||
CHECK(STRICT_TS_STOPPED == json("stopped"));
|
||||
CHECK(STRICT_TS_RUNNING == json("running"));
|
||||
CHECK(STRICT_TS_COMPLETED == json("completed"));
|
||||
CHECK(STRICT_TS_INVALID == json());
|
||||
|
||||
// invalid json -> exception thrown
|
||||
json _;
|
||||
CHECK_THROWS_WITH_AS(_ = json("what?").get<StrictTaskState>(), "[json.exception.out_of_range.410] enum value out of range for StrictTaskState: \"what?\"", json::out_of_range&);
|
||||
|
||||
// conversion of unmapped enum -> exception thrown
|
||||
CHECK_THROWS_WITH_AS(json(STRICT_TS_OTHER), "[json.exception.out_of_range.410] enum value out of range for StrictTaskState", json::out_of_range&);
|
||||
|
||||
// comparing an unmapped enum with json throws the same exception
|
||||
CHECK_THROWS_WITH_AS(static_cast<void>(STRICT_TS_OTHER < json("x")), "[json.exception.out_of_range.410] enum value out of range for StrictTaskState", json::out_of_range&);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#ifdef JSON_HAS_CPP_17
|
||||
#if JSON_HAS_FILESYSTEM || JSON_HAS_EXPERIMENTAL_FILESYSTEM
|
||||
TEST_CASE("std::filesystem::path")
|
||||
{
|
||||
SECTION("ascii")
|
||||
{
|
||||
json const j_string = "Path";
|
||||
auto p = j_string.template get<nlohmann::detail::std_fs::path>();
|
||||
json const j_path = p;
|
||||
|
||||
CHECK(j_path.template get<std::string>() ==
|
||||
j_string.template get<std::string>());
|
||||
}
|
||||
|
||||
SECTION("utf-8")
|
||||
{
|
||||
json const j_string = "P\xc4\x9b\xc5\xa1ina";
|
||||
auto p = j_string.template get<nlohmann::detail::std_fs::path>();
|
||||
json const j_path = p;
|
||||
|
||||
CHECK(j_path.template get<std::string>() ==
|
||||
j_string.template get<std::string>());
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
// the ADL to_json overload for std::u8string only exists under the same guard
|
||||
// as std::filesystem::path support (it is otherwise only reached indirectly,
|
||||
// via std::filesystem::path::u8string()) -- mirror both #if conditions from
|
||||
// include/nlohmann/detail/conversions/to_json.hpp exactly
|
||||
#if JSON_HAS_FILESYSTEM || JSON_HAS_EXPERIMENTAL_FILESYSTEM
|
||||
#if defined(__cpp_lib_char8_t)
|
||||
TEST_CASE("std::u8string")
|
||||
{
|
||||
SECTION("ascii")
|
||||
{
|
||||
const std::u8string s = u8"Path";
|
||||
json const j = s;
|
||||
|
||||
CHECK(j.template get<std::string>() == "Path");
|
||||
}
|
||||
|
||||
SECTION("utf-8")
|
||||
{
|
||||
// use \u universal-character-names (rather than raw \x byte escapes
|
||||
// or literal non-ASCII source bytes) to compose the multi-byte UTF-8
|
||||
// encoding -- MSVC treats \x escapes used that way inside a u8
|
||||
// literal as a nonstandard extension (warning C5321), which some of
|
||||
// our CI configs promote to an error; \u is portable and produces
|
||||
// the exact same encoded bytes without depending on the source
|
||||
// file's encoding
|
||||
const std::u8string s = u8"P\u011B\u0161ina";
|
||||
json const j = s;
|
||||
|
||||
CHECK(j.template get<std::string>() == "P\xc4\x9b\xc5\xa1ina");
|
||||
}
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#if !defined(JSON_NOEXCEPTION)
|
||||
namespace
|
||||
{
|
||||
// a type whose to_json reports an error by throwing, used below to check that
|
||||
// converting a std::optional<T> to JSON propagates an exception thrown while
|
||||
// converting its contained value instead of calling std::terminate (#5642)
|
||||
struct throwing_to_json_type {};
|
||||
|
||||
[[noreturn]] void to_json(json& /*unused*/, const throwing_to_json_type& /*unused*/)
|
||||
{
|
||||
throw std::runtime_error("cannot serialize throwing_to_json_type");
|
||||
}
|
||||
} // namespace
|
||||
#endif
|
||||
|
||||
TEST_CASE("std::optional")
|
||||
{
|
||||
SECTION("null")
|
||||
{
|
||||
const json j_null;
|
||||
const std::optional<std::string> opt_null;
|
||||
|
||||
CHECK(json(opt_null) == j_null);
|
||||
CHECK(j_null.get<std::optional<std::string>>() == std::nullopt);
|
||||
|
||||
// Constructing std::optional<T> directly from JSON null throws because
|
||||
// std::optional's own converting constructor is chosen over basic_json's
|
||||
// operator T(). This is a language-level limitation (std::optional<T> is
|
||||
// constructible from T, and T is constructible from basic_json via the
|
||||
// operator); there is no SFINAE path that distinguishes "call from inside
|
||||
// std::optional's constructor" from "direct call". Use get<std::optional<T>>()
|
||||
// or get_to() instead for correct null handling. See #4864 and #5246.
|
||||
CHECK_THROWS_WITH_AS(std::optional<std::string>(j_null),
|
||||
"[json.exception.type_error.302] type must be string, but is null", json::type_error&);
|
||||
CHECK_THROWS_WITH_AS(std::optional<int>(j_null),
|
||||
"[json.exception.type_error.302] type must be number, but is null", json::type_error&);
|
||||
|
||||
// Assignment goes through the same overload resolution as direct
|
||||
// construction, so it throws for the same reason. This relies on
|
||||
// basic_json's implicit conversion operator, so it only applies
|
||||
// when JSON_USE_IMPLICIT_CONVERSIONS is enabled (the default).
|
||||
#if JSON_USE_IMPLICIT_CONVERSIONS
|
||||
std::optional<std::string> opt_assign;
|
||||
CHECK_THROWS_WITH_AS(opt_assign = j_null,
|
||||
"[json.exception.type_error.302] type must be string, but is null", json::type_error&);
|
||||
#endif
|
||||
|
||||
// get_to() is the correct way to obtain std::nullopt from a JSON null.
|
||||
std::optional<std::string> opt_get_to = "placeholder";
|
||||
j_null.get_to(opt_get_to);
|
||||
CHECK(opt_get_to == std::nullopt);
|
||||
}
|
||||
|
||||
SECTION("string")
|
||||
{
|
||||
json j_string = "string";
|
||||
std::optional<std::string> opt_string = "string";
|
||||
|
||||
CHECK(json(opt_string) == j_string);
|
||||
CHECK(std::optional<std::string>(j_string) == opt_string);
|
||||
// false positive: Infer attributes the destruction of the temporaries above to opt_string
|
||||
// @infer-ignore USE_AFTER_DELETE
|
||||
}
|
||||
|
||||
SECTION("bool")
|
||||
{
|
||||
json j_bool = true;
|
||||
std::optional<bool> opt_bool = true;
|
||||
|
||||
CHECK(json(opt_bool) == j_bool);
|
||||
CHECK(std::optional<bool>(j_bool) == opt_bool);
|
||||
}
|
||||
|
||||
SECTION("number")
|
||||
{
|
||||
json j_number = 1;
|
||||
std::optional<int> opt_int = 1;
|
||||
|
||||
CHECK(json(opt_int) == j_number);
|
||||
CHECK(j_number.get<std::optional<int>>() == opt_int);
|
||||
}
|
||||
|
||||
SECTION("array")
|
||||
{
|
||||
json j_array = {1, 2, nullptr};
|
||||
std::vector<std::optional<int>> opt_array = {{1, 2, std::nullopt}};
|
||||
|
||||
CHECK(json(opt_array) == j_array);
|
||||
CHECK(j_array.get<std::vector<std::optional<int>>>() == opt_array);
|
||||
}
|
||||
|
||||
SECTION("object")
|
||||
{
|
||||
json j_object = {{"one", 1}, {"two", 2}, {"zero", nullptr}};
|
||||
std::map<std::string, std::optional<int>> opt_object {{"one", 1}, {"two", 2}, {"zero", std::nullopt}};
|
||||
|
||||
CHECK(json(opt_object) == j_object);
|
||||
CHECK(std::map<std::string, std::optional<int>>(j_object) == opt_object);
|
||||
}
|
||||
|
||||
#if !defined(JSON_NOEXCEPTION)
|
||||
SECTION("exception from contained value's to_json propagates (#5642)")
|
||||
{
|
||||
// to_json(BasicJsonType&, const std::optional<T>&) must not be
|
||||
// noexcept: it calls T's to_json, which may throw (a user-defined
|
||||
// to_json that reports an error, or std::bad_alloc for T =
|
||||
// std::string/vector/json). Before the fix, this called
|
||||
// std::terminate() instead of letting the exception propagate.
|
||||
const std::optional<throwing_to_json_type> opt = throwing_to_json_type{};
|
||||
CHECK_THROWS_WITH_AS(json(opt), "cannot serialize throwing_to_json_type", std::runtime_error&);
|
||||
|
||||
// the conversion is noexcept exactly when converting the contained value is
|
||||
static_assert(!std::is_nothrow_constructible<json, const std::optional<throwing_to_json_type>&>::value);
|
||||
static_assert(std::is_nothrow_constructible<json, const std::optional<int>&>::value);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef JSON_HAS_CPP_17
|
||||
#undef JSON_HAS_CPP_17
|
||||
#endif
|
||||
@@ -0,0 +1,868 @@
|
||||
// __ _____ _____ _____
|
||||
// __| | __| | | | JSON for Modern C++ (supporting code)
|
||||
// | | |__ | | | | | | version 3.12.0
|
||||
// |_____|_____|_____|_|___| https://github.com/nlohmann/json
|
||||
//
|
||||
// SPDX-FileCopyrightText: 2013-2026 Niels Lohmann <https://nlohmann.me>
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
// cmake/test.cmake selects the C++ standard versions with which to build a
|
||||
// unit test based on the presence of JSON_HAS_CPP_<VERSION> macros.
|
||||
// When using macros that are only defined for particular versions of the standard
|
||||
// (e.g., JSON_HAS_FILESYSTEM for C++17 and up), please mention the corresponding
|
||||
// version macro in a comment close by, like this:
|
||||
// JSON_HAS_CPP_<VERSION> (do not remove; see note at top of file)
|
||||
|
||||
#include "doctest_compatibility.h"
|
||||
|
||||
// skip tests if JSON_DisableEnumSerialization=ON (#4384)
|
||||
#if defined(JSON_DISABLE_ENUM_SERIALIZATION) && (JSON_DISABLE_ENUM_SERIALIZATION == 1)
|
||||
#define SKIP_TESTS_FOR_ENUM_SERIALIZATION
|
||||
#endif
|
||||
|
||||
#define JSON_TESTS_PRIVATE
|
||||
#include <nlohmann/json.hpp>
|
||||
using nlohmann::json;
|
||||
|
||||
#include <deque>
|
||||
#include <forward_list>
|
||||
#include <list>
|
||||
#include <set>
|
||||
#include <unordered_map>
|
||||
#include <unordered_set>
|
||||
#include <valarray>
|
||||
|
||||
// NLOHMANN_JSON_SERIALIZE_ENUM uses a static std::pair
|
||||
DOCTEST_CLANG_SUPPRESS_WARNING_PUSH
|
||||
DOCTEST_CLANG_SUPPRESS_WARNING("-Wexit-time-destructors")
|
||||
|
||||
#if (defined(__cplusplus) && __cplusplus >= 201703L) || (defined(_HAS_CXX17) && _HAS_CXX17 == 1) // fix for issue #464
|
||||
#define JSON_HAS_CPP_17
|
||||
#define JSON_HAS_CPP_14
|
||||
#elif (defined(__cplusplus) && __cplusplus >= 201402L) || (defined(_HAS_CXX14) && _HAS_CXX14 == 1)
|
||||
#define JSON_HAS_CPP_14
|
||||
#endif
|
||||
|
||||
#ifdef JSON_HAS_CPP_17
|
||||
#if __has_include(<optional>)
|
||||
#include <optional>
|
||||
#elif __has_include(<experimental/optional>)
|
||||
#include <experimental/optional>
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#if defined(JSON_HAS_CPP_17)
|
||||
#include <string_view>
|
||||
#endif
|
||||
|
||||
TEST_CASE("value conversion")
|
||||
{
|
||||
SECTION("get a binary value (explicit)")
|
||||
{
|
||||
json::binary_t const n_reference{{1, 2, 3}};
|
||||
json j(n_reference);
|
||||
|
||||
SECTION("binary_t")
|
||||
{
|
||||
json::binary_t const b = j.get<json::binary_t>();
|
||||
CHECK(*json(b).m_data.m_value.binary == *j.m_data.m_value.binary);
|
||||
}
|
||||
|
||||
SECTION("get_binary()")
|
||||
{
|
||||
SECTION("non-const")
|
||||
{
|
||||
auto& b = j.get_binary();
|
||||
CHECK(*json(b).m_data.m_value.binary == *j.m_data.m_value.binary);
|
||||
}
|
||||
|
||||
SECTION("non-const")
|
||||
{
|
||||
const json j_const = j; // NOLINT(performance-unnecessary-copy-initialization)
|
||||
const auto& b = j_const.get_binary();
|
||||
CHECK(*json(b).m_data.m_value.binary == *j.m_data.m_value.binary);
|
||||
}
|
||||
}
|
||||
|
||||
SECTION("exception in case of a non-string type")
|
||||
{
|
||||
json j_null(json::value_t::null);
|
||||
json j_object(json::value_t::object);
|
||||
json j_array(json::value_t::array);
|
||||
json j_string(json::value_t::string);
|
||||
json j_boolean(json::value_t::boolean);
|
||||
const json j_null_const(json::value_t::null);
|
||||
const json j_object_const(json::value_t::object);
|
||||
const json j_array_const(json::value_t::array);
|
||||
const json j_string_const(json::value_t::string);
|
||||
const json j_boolean_const(json::value_t::boolean);
|
||||
|
||||
CHECK_THROWS_WITH_AS(j_null.get<json::binary_t>(),
|
||||
"[json.exception.type_error.302] type must be binary, but is null",
|
||||
json::type_error&);
|
||||
CHECK_THROWS_WITH_AS(j_object.get<json::binary_t>(),
|
||||
"[json.exception.type_error.302] type must be binary, but is object",
|
||||
json::type_error&);
|
||||
CHECK_THROWS_WITH_AS(j_array.get<json::binary_t>(),
|
||||
"[json.exception.type_error.302] type must be binary, but is array",
|
||||
json::type_error&);
|
||||
CHECK_THROWS_WITH_AS(j_string.get<json::binary_t>(),
|
||||
"[json.exception.type_error.302] type must be binary, but is string",
|
||||
json::type_error&);
|
||||
CHECK_THROWS_WITH_AS(j_boolean.get<json::binary_t>(),
|
||||
"[json.exception.type_error.302] type must be binary, but is boolean",
|
||||
json::type_error&);
|
||||
|
||||
CHECK_THROWS_WITH_AS(j_null_const.get<json::binary_t>(),
|
||||
"[json.exception.type_error.302] type must be binary, but is null",
|
||||
json::type_error&);
|
||||
CHECK_THROWS_WITH_AS(j_object_const.get<json::binary_t>(),
|
||||
"[json.exception.type_error.302] type must be binary, but is object",
|
||||
json::type_error&);
|
||||
CHECK_THROWS_WITH_AS(j_array_const.get<json::binary_t>(),
|
||||
"[json.exception.type_error.302] type must be binary, but is array",
|
||||
json::type_error&);
|
||||
CHECK_THROWS_WITH_AS(j_string_const.get<json::binary_t>(),
|
||||
"[json.exception.type_error.302] type must be binary, but is string",
|
||||
json::type_error&);
|
||||
CHECK_THROWS_WITH_AS(j_boolean_const.get<json::binary_t>(),
|
||||
"[json.exception.type_error.302] type must be binary, but is boolean",
|
||||
json::type_error&);
|
||||
|
||||
CHECK_THROWS_WITH_AS(j_null.get_binary(),
|
||||
"[json.exception.type_error.302] type must be binary, but is null",
|
||||
json::type_error&);
|
||||
CHECK_THROWS_WITH_AS(j_object.get_binary(),
|
||||
"[json.exception.type_error.302] type must be binary, but is object",
|
||||
json::type_error&);
|
||||
CHECK_THROWS_WITH_AS(j_array.get_binary(),
|
||||
"[json.exception.type_error.302] type must be binary, but is array",
|
||||
json::type_error&);
|
||||
CHECK_THROWS_WITH_AS(j_string.get_binary(),
|
||||
"[json.exception.type_error.302] type must be binary, but is string",
|
||||
json::type_error&);
|
||||
CHECK_THROWS_WITH_AS(j_boolean.get_binary(),
|
||||
"[json.exception.type_error.302] type must be binary, but is boolean",
|
||||
json::type_error&);
|
||||
|
||||
CHECK_THROWS_WITH_AS(j_null_const.get_binary(),
|
||||
"[json.exception.type_error.302] type must be binary, but is null",
|
||||
json::type_error&);
|
||||
CHECK_THROWS_WITH_AS(j_object_const.get_binary(),
|
||||
"[json.exception.type_error.302] type must be binary, but is object",
|
||||
json::type_error&);
|
||||
CHECK_THROWS_WITH_AS(j_array_const.get_binary(),
|
||||
"[json.exception.type_error.302] type must be binary, but is array",
|
||||
json::type_error&);
|
||||
CHECK_THROWS_WITH_AS(j_string_const.get_binary(),
|
||||
"[json.exception.type_error.302] type must be binary, but is string",
|
||||
json::type_error&);
|
||||
CHECK_THROWS_WITH_AS(j_boolean_const.get_binary(),
|
||||
"[json.exception.type_error.302] type must be binary, but is boolean",
|
||||
json::type_error&);
|
||||
}
|
||||
}
|
||||
|
||||
#if JSON_USE_IMPLICIT_CONVERSIONS
|
||||
SECTION("get a binary value (implicit)")
|
||||
{
|
||||
json::binary_t const n_reference{{1, 2, 3}};
|
||||
json const j(n_reference);
|
||||
|
||||
SECTION("binary_t")
|
||||
{
|
||||
json::binary_t const b = j;
|
||||
CHECK(*json(b).m_data.m_value.binary == *j.m_data.m_value.binary);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifndef SKIP_TESTS_FOR_ENUM_SERIALIZATION
|
||||
SECTION("get an enum")
|
||||
{
|
||||
enum c_enum { value_1, value_2 }; // NOLINT(cppcoreguidelines-use-enum-class)
|
||||
enum class cpp_enum { value_1, value_2 };
|
||||
|
||||
CHECK(json(value_1).get<c_enum>() == value_1);
|
||||
CHECK(json(cpp_enum::value_1).get<cpp_enum>() == cpp_enum::value_1);
|
||||
}
|
||||
|
||||
SECTION("get an enum with underlying type bool (#5671)")
|
||||
{
|
||||
enum class bool_enum : bool { off, on };
|
||||
|
||||
CHECK(json(bool_enum::off).get<bool_enum>() == bool_enum::off);
|
||||
CHECK(json(bool_enum::on).get<bool_enum>() == bool_enum::on);
|
||||
}
|
||||
#endif
|
||||
|
||||
SECTION("more involved conversions")
|
||||
{
|
||||
SECTION("object-like STL containers")
|
||||
{
|
||||
json const j1 = {{"one", 1}, {"two", 2}, {"three", 3}};
|
||||
json const j2 = {{"one", 1u}, {"two", 2u}, {"three", 3u}};
|
||||
json const j3 = {{"one", 1.1}, {"two", 2.2}, {"three", 3.3}};
|
||||
json const j4 = {{"one", true}, {"two", false}, {"three", true}};
|
||||
json const j5 = {{"one", "eins"}, {"two", "zwei"}, {"three", "drei"}};
|
||||
|
||||
SECTION("std::map")
|
||||
{
|
||||
CHECK(j1.get<std::map<std::string, int>>() == (std::map<std::string, int> {{"one", 1}, {"two", 2}, {"three", 3}}));
|
||||
CHECK(j2.get<std::map<std::string, unsigned int>>() == (std::map<std::string, unsigned int> {{"one", 1u}, {"two", 2u}, {"three", 3u}}));
|
||||
CHECK(j3.get<std::map<std::string, double>>() == (std::map<std::string, double> {{"one", 1.1}, {"two", 2.2}, {"three", 3.3}}));
|
||||
CHECK(j4.get<std::map<std::string, bool>>() == (std::map<std::string, bool> {{"one", true}, {"two", false}, {"three", true}}));
|
||||
CHECK(j5.get<std::map<std::string, std::string>>() == (std::map<std::string, std::string> {{"one", "eins"}, {"two", "zwei"}, {"three", "drei"}}));
|
||||
}
|
||||
|
||||
SECTION("std::unordered_map")
|
||||
{
|
||||
CHECK(j1.get<std::unordered_map<std::string, int>>() == (std::unordered_map<std::string, int> {{"one", 1}, {"two", 2}, {"three", 3}}));
|
||||
CHECK(j2.get<std::unordered_map<std::string, unsigned int>>() == (std::unordered_map<std::string, unsigned int> {{"one", 1u}, {"two", 2u}, {"three", 3u}}));
|
||||
CHECK(j3.get<std::unordered_map<std::string, double>>() == (std::unordered_map<std::string, double> {{"one", 1.1}, {"two", 2.2}, {"three", 3.3}}));
|
||||
CHECK(j4.get<std::unordered_map<std::string, bool>>() == (std::unordered_map<std::string, bool> {{"one", true}, {"two", false}, {"three", true}}));
|
||||
const auto m5 = j5.get<std::unordered_map<std::string, std::string>>();
|
||||
CHECK(m5 == (std::unordered_map<std::string, std::string> {{"one", "eins"}, {"two", "zwei"}, {"three", "drei"}}));
|
||||
CHECK(m5.at("one") == "eins");
|
||||
}
|
||||
|
||||
SECTION("reserve is called on containers that support it (#5406)")
|
||||
{
|
||||
// build a larger object so that a missing/incorrect reserve()
|
||||
// call would be more likely to corrupt or drop elements
|
||||
json j_large;
|
||||
for (int i = 0; i < 100; ++i)
|
||||
{
|
||||
j_large[std::to_string(i)] = i;
|
||||
}
|
||||
|
||||
SECTION("std::unordered_map (supports reserve)")
|
||||
{
|
||||
const auto m = j_large.get<std::unordered_map<std::string, int>>();
|
||||
CHECK(m.size() == 100);
|
||||
for (int i = 0; i < 100; ++i)
|
||||
{
|
||||
CHECK(m.at(std::to_string(i)) == i);
|
||||
}
|
||||
}
|
||||
|
||||
SECTION("std::map (no reserve, fallback path)")
|
||||
{
|
||||
const auto m = j_large.get<std::map<std::string, int>>();
|
||||
CHECK(m.size() == 100);
|
||||
for (int i = 0; i < 100; ++i)
|
||||
{
|
||||
CHECK(m.at(std::to_string(i)) == i);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
SECTION("std::multimap")
|
||||
{
|
||||
CHECK(j1.get<std::multimap<std::string, int>>() == (std::multimap<std::string, int> {{"one", 1}, {"two", 2}, {"three", 3}}));
|
||||
CHECK(j2.get<std::multimap<std::string, unsigned int>>() == (std::multimap<std::string, unsigned int> {{"one", 1u}, {"two", 2u}, {"three", 3u}}));
|
||||
CHECK(j3.get<std::multimap<std::string, double>>() == (std::multimap<std::string, double> {{"one", 1.1}, {"two", 2.2}, {"three", 3.3}}));
|
||||
CHECK(j4.get<std::multimap<std::string, bool>>() == (std::multimap<std::string, bool> {{"one", true}, {"two", false}, {"three", true}}));
|
||||
const auto m5 = j5.get<std::multimap<std::string, std::string>>();
|
||||
CHECK(m5 == (std::multimap<std::string, std::string> {{"one", "eins"}, {"two", "zwei"}, {"three", "drei"}}));
|
||||
CHECK(m5.find("one")->second == "eins");
|
||||
}
|
||||
|
||||
SECTION("std::unordered_multimap")
|
||||
{
|
||||
CHECK(j1.get<std::unordered_multimap<std::string, int>>() == (std::unordered_multimap<std::string, int> {{"one", 1}, {"two", 2}, {"three", 3}}));
|
||||
CHECK(j2.get<std::unordered_multimap<std::string, unsigned int>>() == (std::unordered_multimap<std::string, unsigned int> {{"one", 1u}, {"two", 2u}, {"three", 3u}}));
|
||||
CHECK(j3.get<std::unordered_multimap<std::string, double>>() == (std::unordered_multimap<std::string, double> {{"one", 1.1}, {"two", 2.2}, {"three", 3.3}}));
|
||||
CHECK(j4.get<std::unordered_multimap<std::string, bool>>() == (std::unordered_multimap<std::string, bool> {{"one", true}, {"two", false}, {"three", true}}));
|
||||
const auto m5 = j5.get<std::unordered_multimap<std::string, std::string>>();
|
||||
CHECK(m5 == (std::unordered_multimap<std::string, std::string> {{"one", "eins"}, {"two", "zwei"}, {"three", "drei"}}));
|
||||
CHECK(m5.find("one")->second == "eins");
|
||||
}
|
||||
|
||||
SECTION("exception in case of a non-object type")
|
||||
{
|
||||
CHECK_THROWS_WITH_AS(
|
||||
(json().get<std::map<std::string, int>>()),
|
||||
"[json.exception.type_error.302] type must be object, but is null", json::type_error&);
|
||||
}
|
||||
}
|
||||
|
||||
SECTION("array-like STL containers")
|
||||
{
|
||||
json const j1 = {1, 2, 3, 4};
|
||||
json const j2 = {1u, 2u, 3u, 4u};
|
||||
json const j3 = {1.2, 2.3, 3.4, 4.5};
|
||||
json const j4 = {true, false, true};
|
||||
json const j5 = {"one", "two", "three"};
|
||||
|
||||
SECTION("std::list")
|
||||
{
|
||||
CHECK(j1.get<std::list<int>>() == (std::list<int> {1, 2, 3, 4}));
|
||||
CHECK(j2.get<std::list<unsigned int>>() == (std::list<unsigned int> {1u, 2u, 3u, 4u}));
|
||||
CHECK(j3.get<std::list<double>>() == (std::list<double> {1.2, 2.3, 3.4, 4.5}));
|
||||
CHECK(j4.get<std::list<bool>>() == (std::list<bool> {true, false, true}));
|
||||
CHECK(j5.get<std::list<std::string>>() == (std::list<std::string> {"one", "two", "three"}));
|
||||
}
|
||||
|
||||
SECTION("std::forward_list")
|
||||
{
|
||||
CHECK(j1.get<std::forward_list<int>>() == (std::forward_list<int> {1, 2, 3, 4}));
|
||||
CHECK(j2.get<std::forward_list<unsigned int>>() == (std::forward_list<unsigned int> {1u, 2u, 3u, 4u}));
|
||||
CHECK(j3.get<std::forward_list<double>>() == (std::forward_list<double> {1.2, 2.3, 3.4, 4.5}));
|
||||
CHECK(j4.get<std::forward_list<bool>>() == (std::forward_list<bool> {true, false, true}));
|
||||
CHECK(j5.get<std::forward_list<std::string>>() == (std::forward_list<std::string> {"one", "two", "three"}));
|
||||
}
|
||||
|
||||
SECTION("std::array")
|
||||
{
|
||||
CHECK(j1.get<std::array<int, 4>>() == (std::array<int, 4> {{1, 2, 3, 4}}));
|
||||
// only the first 3 elements of j2 are converted, since the target array is smaller
|
||||
CHECK(j2.get<std::array<unsigned int, 3>>() == (std::array<unsigned int, 3> {{1u, 2u, 3u}}));
|
||||
CHECK(j3.get<std::array<double, 4>>() == (std::array<double, 4> {{1.2, 2.3, 3.4, 4.5}}));
|
||||
CHECK(j4.get<std::array<bool, 3>>() == (std::array<bool, 3> {{true, false, true}}));
|
||||
CHECK(j5.get<std::array<std::string, 3>>() == (std::array<std::string, 3> {{"one", "two", "three"}}));
|
||||
|
||||
SECTION("std::array is larger than JSON")
|
||||
{
|
||||
std::array<int, 6> arr6 = {{1, 2, 3, 4, 5, 6}};
|
||||
CHECK_THROWS_WITH_AS(j1.get_to(arr6), "[json.exception.out_of_range.401] "
|
||||
"array index 4 is out of range", json::out_of_range&);
|
||||
}
|
||||
|
||||
SECTION("std::array is smaller than JSON")
|
||||
{
|
||||
std::array<int, 2> arr2 = {{8, 9}};
|
||||
j1.get_to(arr2);
|
||||
CHECK(arr2[0] == 1);
|
||||
CHECK(arr2[1] == 2);
|
||||
}
|
||||
}
|
||||
|
||||
SECTION("std::valarray")
|
||||
{
|
||||
// valarray has no operator== that returns bool, so compare via a vector copy
|
||||
const auto v1 = j1.get<std::valarray<int>>();
|
||||
CHECK((std::vector<int>(std::begin(v1), std::end(v1)) == std::vector<int> {1, 2, 3, 4}));
|
||||
const auto v2 = j2.get<std::valarray<unsigned int>>();
|
||||
CHECK((std::vector<unsigned int>(std::begin(v2), std::end(v2)) == std::vector<unsigned int> {1u, 2u, 3u, 4u}));
|
||||
const auto v3 = j3.get<std::valarray<double>>();
|
||||
CHECK((std::vector<double>(std::begin(v3), std::end(v3)) == std::vector<double> {1.2, 2.3, 3.4, 4.5}));
|
||||
const auto v4 = j4.get<std::valarray<bool>>();
|
||||
CHECK((std::vector<bool>(std::begin(v4), std::end(v4)) == std::vector<bool> {true, false, true}));
|
||||
const auto v5 = j5.get<std::valarray<std::string>>();
|
||||
CHECK((std::vector<std::string>(std::begin(v5), std::end(v5)) == std::vector<std::string> {"one", "two", "three"}));
|
||||
}
|
||||
|
||||
SECTION("std::vector")
|
||||
{
|
||||
CHECK(j1.get<std::vector<int>>() == (std::vector<int> {1, 2, 3, 4}));
|
||||
CHECK(j2.get<std::vector<unsigned int>>() == (std::vector<unsigned int> {1u, 2u, 3u, 4u}));
|
||||
CHECK(j3.get<std::vector<double>>() == (std::vector<double> {1.2, 2.3, 3.4, 4.5}));
|
||||
CHECK(j4.get<std::vector<bool>>() == (std::vector<bool> {true, false, true}));
|
||||
CHECK(j5.get<std::vector<std::string>>() == (std::vector<std::string> {"one", "two", "three"}));
|
||||
}
|
||||
|
||||
SECTION("std::deque")
|
||||
{
|
||||
CHECK(j1.get<std::deque<int>>() == (std::deque<int> {1, 2, 3, 4}));
|
||||
CHECK(j2.get<std::deque<unsigned int>>() == (std::deque<unsigned int> {1u, 2u, 3u, 4u}));
|
||||
CHECK(j3.get<std::deque<double>>() == (std::deque<double> {1.2, 2.3, 3.4, 4.5}));
|
||||
CHECK(j4.get<std::deque<bool>>() == (std::deque<bool> {true, false, true}));
|
||||
CHECK(j5.get<std::deque<std::string>>() == (std::deque<std::string> {"one", "two", "three"}));
|
||||
}
|
||||
|
||||
SECTION("std::set")
|
||||
{
|
||||
CHECK(j1.get<std::set<int>>() == (std::set<int> {1, 2, 3, 4}));
|
||||
CHECK(j2.get<std::set<unsigned int>>() == (std::set<unsigned int> {1u, 2u, 3u, 4u}));
|
||||
CHECK(j3.get<std::set<double>>() == (std::set<double> {1.2, 2.3, 3.4, 4.5}));
|
||||
CHECK(j4.get<std::set<bool>>() == (std::set<bool> {true, false, true}));
|
||||
CHECK(j5.get<std::set<std::string>>() == (std::set<std::string> {"one", "two", "three"}));
|
||||
}
|
||||
|
||||
SECTION("std::unordered_set")
|
||||
{
|
||||
CHECK(j1.get<std::unordered_set<int>>() == (std::unordered_set<int> {1, 2, 3, 4}));
|
||||
CHECK(j2.get<std::unordered_set<unsigned int>>() == (std::unordered_set<unsigned int> {1u, 2u, 3u, 4u}));
|
||||
CHECK(j3.get<std::unordered_set<double>>() == (std::unordered_set<double> {1.2, 2.3, 3.4, 4.5}));
|
||||
CHECK(j4.get<std::unordered_set<bool>>() == (std::unordered_set<bool> {true, false, true}));
|
||||
CHECK(j5.get<std::unordered_set<std::string>>() == (std::unordered_set<std::string> {"one", "two", "three"}));
|
||||
}
|
||||
|
||||
SECTION("std::map (array of pairs)")
|
||||
{
|
||||
const std::map<int, int> m{{0, 1}, {1, 2}, {2, 3}};
|
||||
json const j6 = m;
|
||||
|
||||
auto m2 = j6.get<std::map<int, int>>();
|
||||
CHECK(m == m2);
|
||||
|
||||
json const j7 = {0, 1, 2, 3};
|
||||
json const j8 = 2;
|
||||
#if JSON_DIAGNOSTICS
|
||||
CHECK_THROWS_WITH_AS((j7.get<std::map<int, int>>()),
|
||||
"[json.exception.type_error.302] (/0) type must be array, "
|
||||
"but is number", json::type_error&);
|
||||
#else
|
||||
CHECK_THROWS_WITH_AS((j7.get<std::map<int, int>>()),
|
||||
"[json.exception.type_error.302] type must be array, "
|
||||
"but is number", json::type_error&);
|
||||
#endif
|
||||
CHECK_THROWS_WITH_AS((j8.get<std::map<int, int>>()),
|
||||
"[json.exception.type_error.302] type must be array, "
|
||||
"but is number", json::type_error&);
|
||||
|
||||
SECTION("superfluous entries")
|
||||
{
|
||||
json const j9 = {{0, 1, 2}, {1, 2, 3}, {2, 3, 4}};
|
||||
m2 = j9.get<std::map<int, int>>();
|
||||
CHECK(m == m2);
|
||||
}
|
||||
}
|
||||
|
||||
SECTION("std::unordered_map (array of pairs)")
|
||||
{
|
||||
const std::unordered_map<int, int> m{{0, 1}, {1, 2}, {2, 3}};
|
||||
json const j6 = m;
|
||||
|
||||
auto m2 = j6.get<std::unordered_map<int, int>>();
|
||||
CHECK(m == m2);
|
||||
|
||||
json const j7 = {0, 1, 2, 3};
|
||||
json const j8 = 2;
|
||||
#if JSON_DIAGNOSTICS
|
||||
CHECK_THROWS_WITH_AS((j7.get<std::unordered_map<int, int>>()),
|
||||
"[json.exception.type_error.302] (/0) type must be array, "
|
||||
"but is number", json::type_error&);
|
||||
#else
|
||||
CHECK_THROWS_WITH_AS((j7.get<std::unordered_map<int, int>>()),
|
||||
"[json.exception.type_error.302] type must be array, "
|
||||
"but is number", json::type_error&);
|
||||
#endif
|
||||
CHECK_THROWS_WITH_AS((j8.get<std::unordered_map<int, int>>()),
|
||||
"[json.exception.type_error.302] type must be array, "
|
||||
"but is number", json::type_error&);
|
||||
|
||||
SECTION("superfluous entries")
|
||||
{
|
||||
json const j9{{0, 1, 2}, {1, 2, 3}, {2, 3, 4}};
|
||||
m2 = j9.get<std::unordered_map<int, int>>();
|
||||
CHECK(m == m2);
|
||||
}
|
||||
}
|
||||
|
||||
SECTION("exception in case of a non-object type")
|
||||
{
|
||||
// does type really must be an array? or it rather must not be null?
|
||||
// that's what I thought when other test like this one broke
|
||||
CHECK_THROWS_WITH_AS(
|
||||
(json().get<std::list<int>>()),
|
||||
"[json.exception.type_error.302] type must be array, but is null", json::type_error&);
|
||||
CHECK_THROWS_WITH_AS(
|
||||
(json().get<std::vector<int>>()),
|
||||
"[json.exception.type_error.302] type must be array, but is null", json::type_error&);
|
||||
CHECK_THROWS_WITH_AS(
|
||||
(json().get<std::vector<json>>()),
|
||||
"[json.exception.type_error.302] type must be array, but is null", json::type_error&);
|
||||
CHECK_THROWS_WITH_AS(
|
||||
(json().get<std::list<json>>()),
|
||||
"[json.exception.type_error.302] type must be array, but is null", json::type_error&);
|
||||
CHECK_THROWS_WITH_AS(
|
||||
(json().get<std::valarray<int>>()),
|
||||
"[json.exception.type_error.302] type must be array, but is null", json::type_error&);
|
||||
CHECK_THROWS_WITH_AS(
|
||||
(json().get<std::map<int, int>>()),
|
||||
"[json.exception.type_error.302] type must be array, but is null", json::type_error&);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
enum class cards {kreuz, pik, herz, karo};
|
||||
|
||||
// NOLINTNEXTLINE(misc-use-internal-linkage,misc-const-correctness) - false positive
|
||||
NLOHMANN_JSON_SERIALIZE_ENUM(cards,
|
||||
{
|
||||
{cards::kreuz, "kreuz"},
|
||||
{cards::pik, "pik"},
|
||||
{cards::pik, "puk"}, // second entry for cards::puk; will not be used
|
||||
{cards::herz, "herz"},
|
||||
{cards::karo, "karo"}
|
||||
})
|
||||
|
||||
enum TaskState // NOLINT(cert-int09-c,readability-enum-initial-value,cppcoreguidelines-use-enum-class)
|
||||
{
|
||||
TS_STOPPED,
|
||||
TS_RUNNING,
|
||||
TS_COMPLETED,
|
||||
TS_INVALID = -1,
|
||||
};
|
||||
|
||||
// NOLINTNEXTLINE(misc-const-correctness,misc-use-internal-linkage) - false positive
|
||||
NLOHMANN_JSON_SERIALIZE_ENUM(TaskState,
|
||||
{
|
||||
{TS_INVALID, nullptr},
|
||||
{TS_STOPPED, "stopped"},
|
||||
{TS_RUNNING, "running"},
|
||||
{TS_COMPLETED, "completed"},
|
||||
})
|
||||
|
||||
TEST_CASE("JSON to enum mapping")
|
||||
{
|
||||
SECTION("enum class")
|
||||
{
|
||||
// enum -> json
|
||||
CHECK(json(cards::kreuz) == "kreuz");
|
||||
CHECK(json(cards::pik) == "pik");
|
||||
CHECK(json(cards::herz) == "herz");
|
||||
CHECK(json(cards::karo) == "karo");
|
||||
|
||||
// json -> enum
|
||||
CHECK(cards::kreuz == json("kreuz"));
|
||||
CHECK(cards::pik == json("pik"));
|
||||
CHECK(cards::herz == json("herz"));
|
||||
CHECK(cards::karo == json("karo"));
|
||||
|
||||
// invalid json -> first enum
|
||||
CHECK(cards::kreuz == json("what?").get<cards>());
|
||||
}
|
||||
|
||||
SECTION("traditional enum")
|
||||
{
|
||||
// enum -> json
|
||||
CHECK(json(TS_STOPPED) == "stopped");
|
||||
CHECK(json(TS_RUNNING) == "running");
|
||||
CHECK(json(TS_COMPLETED) == "completed");
|
||||
CHECK(json(TS_INVALID) == json());
|
||||
|
||||
// json -> enum
|
||||
CHECK(TS_STOPPED == json("stopped"));
|
||||
CHECK(TS_RUNNING == json("running"));
|
||||
CHECK(TS_COMPLETED == json("completed"));
|
||||
CHECK(TS_INVALID == json());
|
||||
|
||||
// invalid json -> first enum
|
||||
CHECK(TS_INVALID == json("what?").get<TaskState>());
|
||||
}
|
||||
}
|
||||
|
||||
enum class strict_cards {kreuz, pik, herz, karo, andere}; // andere not included in mapping
|
||||
|
||||
// NOLINTNEXTLINE(misc-use-internal-linkage,misc-const-correctness) - false positive
|
||||
NLOHMANN_JSON_SERIALIZE_ENUM_STRICT(strict_cards,
|
||||
{
|
||||
{strict_cards::kreuz, "kreuz"},
|
||||
{strict_cards::pik, "pik"},
|
||||
{strict_cards::pik, "puk"}, // second entry for cards::pik; will not be used
|
||||
{strict_cards::herz, "herz"},
|
||||
{strict_cards::karo, "karo"}
|
||||
})
|
||||
|
||||
enum StrictTaskState // NOLINT(cert-int09-c,readability-enum-initial-value,cppcoreguidelines-use-enum-class)
|
||||
{
|
||||
STRICT_TS_STOPPED,
|
||||
STRICT_TS_RUNNING,
|
||||
STRICT_TS_COMPLETED,
|
||||
STRICT_TS_OTHER, // STRICT_TS_OTHER not in mapping
|
||||
STRICT_TS_INVALID = -1,
|
||||
};
|
||||
|
||||
// NOLINTNEXTLINE(misc-const-correctness,misc-use-internal-linkage) - false positive
|
||||
NLOHMANN_JSON_SERIALIZE_ENUM_STRICT(StrictTaskState,
|
||||
{
|
||||
{STRICT_TS_INVALID, nullptr},
|
||||
{STRICT_TS_STOPPED, "stopped"},
|
||||
{STRICT_TS_RUNNING, "running"},
|
||||
{STRICT_TS_COMPLETED, "completed"},
|
||||
})
|
||||
|
||||
// regression test for #5708 item 2: NLOHMANN_JSON_SERIALIZE_ENUM_STRICT must not rely on
|
||||
// unqualified lookup of a helper name that a user's own namespace may also declare
|
||||
namespace ns_with_colliding_name
|
||||
{
|
||||
// NOLINTNEXTLINE(misc-use-internal-linkage) - used to shadow the library's internal helper name
|
||||
inline void templated_json_throw(int /*unused*/) {}
|
||||
|
||||
enum class colliding_enum { a, b };
|
||||
|
||||
// NOLINTNEXTLINE(misc-use-internal-linkage,misc-const-correctness,cppcoreguidelines-avoid-c-arrays,hicpp-avoid-c-arrays,modernize-avoid-c-arrays) - false positive
|
||||
NLOHMANN_JSON_SERIALIZE_ENUM_STRICT(colliding_enum,
|
||||
{
|
||||
{colliding_enum::a, "a"},
|
||||
{colliding_enum::b, "b"}
|
||||
})
|
||||
} // namespace ns_with_colliding_name
|
||||
|
||||
TEST_CASE("NLOHMANN_JSON_SERIALIZE_ENUM_STRICT in a namespace with a colliding name")
|
||||
{
|
||||
using ns_with_colliding_name::colliding_enum;
|
||||
|
||||
CHECK(json(colliding_enum::a) == "a");
|
||||
CHECK(colliding_enum::b == json("b"));
|
||||
|
||||
json _;
|
||||
CHECK_THROWS_WITH_AS(_ = json("nope").get<colliding_enum>(), "[json.exception.out_of_range.410] enum value out of range for colliding_enum: \"nope\"", json::out_of_range&);
|
||||
}
|
||||
|
||||
TEST_CASE("Strict JSON to enum mapping")
|
||||
{
|
||||
SECTION("enum class")
|
||||
{
|
||||
// enum -> json
|
||||
CHECK(json(strict_cards::kreuz) == "kreuz");
|
||||
CHECK(json(strict_cards::pik) == "pik");
|
||||
CHECK(json(strict_cards::herz) == "herz");
|
||||
CHECK(json(strict_cards::karo) == "karo");
|
||||
|
||||
// json -> enum
|
||||
CHECK(json("kreuz").get<strict_cards>() == strict_cards::kreuz);
|
||||
CHECK(json("pik").get<strict_cards>() == strict_cards::pik);
|
||||
CHECK(json("herz").get<strict_cards>() == strict_cards::herz);
|
||||
CHECK(json("karo").get<strict_cards>() == strict_cards::karo);
|
||||
|
||||
// comparison of enum and json
|
||||
CHECK(strict_cards::kreuz == json("kreuz"));
|
||||
CHECK(strict_cards::pik == json("pik"));
|
||||
CHECK(strict_cards::herz == json("herz"));
|
||||
CHECK(strict_cards::karo == json("karo"));
|
||||
|
||||
// invalid json -> exception thrown
|
||||
json _;
|
||||
CHECK_THROWS_WITH_AS(_ = json("what?").get<strict_cards>(), "[json.exception.out_of_range.410] enum value out of range for strict_cards: \"what?\"", json::out_of_range&);
|
||||
|
||||
// conversion of unmapped enum -> exception thrown
|
||||
CHECK_THROWS_WITH_AS(json(strict_cards::andere), "[json.exception.out_of_range.410] enum value out of range for strict_cards", json::out_of_range&);
|
||||
|
||||
// comparing an unmapped enum with json throws the same exception
|
||||
// (the scalar comparison operators used to be noexcept, so this
|
||||
// called std::terminate)
|
||||
CHECK_THROWS_WITH_AS(static_cast<void>(strict_cards::andere == json("andere")), "[json.exception.out_of_range.410] enum value out of range for strict_cards", json::out_of_range&);
|
||||
CHECK_THROWS_WITH_AS(static_cast<void>(json("andere") != strict_cards::andere), "[json.exception.out_of_range.410] enum value out of range for strict_cards", json::out_of_range&);
|
||||
|
||||
// invalid UTF-8 -> out_of_range.410, not the type_error.316 thrown while building the
|
||||
// message (regression test for #5667); such strings can reach get<Enum>() unvalidated,
|
||||
// e.g. from from_cbor()/from_msgpack() (#5529)
|
||||
const json j_invalid_utf8 = "\xFF";
|
||||
CHECK_THROWS_WITH_AS(_ = j_invalid_utf8.get<strict_cards>(), "[json.exception.out_of_range.410] enum value out of range for strict_cards: \"\xEF\xBF\xBD\"", json::out_of_range&);
|
||||
}
|
||||
|
||||
SECTION("traditional enum")
|
||||
{
|
||||
// enum -> json
|
||||
CHECK(json(STRICT_TS_STOPPED) == "stopped");
|
||||
CHECK(json(STRICT_TS_RUNNING) == "running");
|
||||
CHECK(json(STRICT_TS_COMPLETED) == "completed");
|
||||
CHECK(json(STRICT_TS_INVALID) == json());
|
||||
|
||||
// json -> enum
|
||||
CHECK(json("stopped").get<StrictTaskState>() == STRICT_TS_STOPPED);
|
||||
CHECK(json("running").get<StrictTaskState>() == STRICT_TS_RUNNING);
|
||||
CHECK(json("completed").get<StrictTaskState>() == STRICT_TS_COMPLETED);
|
||||
CHECK(json().get<StrictTaskState>() == STRICT_TS_INVALID);
|
||||
|
||||
// comparison of enum and json
|
||||
CHECK(STRICT_TS_STOPPED == json("stopped"));
|
||||
CHECK(STRICT_TS_RUNNING == json("running"));
|
||||
CHECK(STRICT_TS_COMPLETED == json("completed"));
|
||||
CHECK(STRICT_TS_INVALID == json());
|
||||
|
||||
// invalid json -> exception thrown
|
||||
json _;
|
||||
CHECK_THROWS_WITH_AS(_ = json("what?").get<StrictTaskState>(), "[json.exception.out_of_range.410] enum value out of range for StrictTaskState: \"what?\"", json::out_of_range&);
|
||||
|
||||
// conversion of unmapped enum -> exception thrown
|
||||
CHECK_THROWS_WITH_AS(json(STRICT_TS_OTHER), "[json.exception.out_of_range.410] enum value out of range for StrictTaskState", json::out_of_range&);
|
||||
|
||||
// comparing an unmapped enum with json throws the same exception
|
||||
CHECK_THROWS_WITH_AS(static_cast<void>(STRICT_TS_OTHER < json("x")), "[json.exception.out_of_range.410] enum value out of range for StrictTaskState", json::out_of_range&);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#ifdef JSON_HAS_CPP_17
|
||||
#if JSON_HAS_FILESYSTEM || JSON_HAS_EXPERIMENTAL_FILESYSTEM
|
||||
TEST_CASE("std::filesystem::path")
|
||||
{
|
||||
SECTION("ascii")
|
||||
{
|
||||
json const j_string = "Path";
|
||||
auto p = j_string.template get<nlohmann::detail::std_fs::path>();
|
||||
json const j_path = p;
|
||||
|
||||
CHECK(j_path.template get<std::string>() ==
|
||||
j_string.template get<std::string>());
|
||||
}
|
||||
|
||||
SECTION("utf-8")
|
||||
{
|
||||
json const j_string = "P\xc4\x9b\xc5\xa1ina";
|
||||
auto p = j_string.template get<nlohmann::detail::std_fs::path>();
|
||||
json const j_path = p;
|
||||
|
||||
CHECK(j_path.template get<std::string>() ==
|
||||
j_string.template get<std::string>());
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
// the ADL to_json overload for std::u8string only exists under the same guard
|
||||
// as std::filesystem::path support (it is otherwise only reached indirectly,
|
||||
// via std::filesystem::path::u8string()) -- mirror both #if conditions from
|
||||
// include/nlohmann/detail/conversions/to_json.hpp exactly
|
||||
#if JSON_HAS_FILESYSTEM || JSON_HAS_EXPERIMENTAL_FILESYSTEM
|
||||
#if defined(__cpp_lib_char8_t)
|
||||
TEST_CASE("std::u8string")
|
||||
{
|
||||
SECTION("ascii")
|
||||
{
|
||||
const std::u8string s = u8"Path";
|
||||
json const j = s;
|
||||
|
||||
CHECK(j.template get<std::string>() == "Path");
|
||||
}
|
||||
|
||||
SECTION("utf-8")
|
||||
{
|
||||
// use \u universal-character-names (rather than raw \x byte escapes
|
||||
// or literal non-ASCII source bytes) to compose the multi-byte UTF-8
|
||||
// encoding -- MSVC treats \x escapes used that way inside a u8
|
||||
// literal as a nonstandard extension (warning C5321), which some of
|
||||
// our CI configs promote to an error; \u is portable and produces
|
||||
// the exact same encoded bytes without depending on the source
|
||||
// file's encoding
|
||||
const std::u8string s = u8"P\u011B\u0161ina";
|
||||
json const j = s;
|
||||
|
||||
CHECK(j.template get<std::string>() == "P\xc4\x9b\xc5\xa1ina");
|
||||
}
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#if !defined(JSON_NOEXCEPTION)
|
||||
namespace
|
||||
{
|
||||
// a type whose to_json reports an error by throwing, used below to check that
|
||||
// converting a std::optional<T> to JSON propagates an exception thrown while
|
||||
// converting its contained value instead of calling std::terminate (#5642)
|
||||
struct throwing_to_json_type {};
|
||||
|
||||
[[noreturn]] void to_json(json& /*unused*/, const throwing_to_json_type& /*unused*/)
|
||||
{
|
||||
throw std::runtime_error("cannot serialize throwing_to_json_type");
|
||||
}
|
||||
} // namespace
|
||||
#endif
|
||||
|
||||
TEST_CASE("std::optional")
|
||||
{
|
||||
SECTION("null")
|
||||
{
|
||||
const json j_null;
|
||||
const std::optional<std::string> opt_null;
|
||||
|
||||
CHECK(json(opt_null) == j_null);
|
||||
CHECK(j_null.get<std::optional<std::string>>() == std::nullopt);
|
||||
|
||||
// Constructing std::optional<T> directly from JSON null throws because
|
||||
// std::optional's own converting constructor is chosen over basic_json's
|
||||
// operator T(). This is a language-level limitation (std::optional<T> is
|
||||
// constructible from T, and T is constructible from basic_json via the
|
||||
// operator); there is no SFINAE path that distinguishes "call from inside
|
||||
// std::optional's constructor" from "direct call". Use get<std::optional<T>>()
|
||||
// or get_to() instead for correct null handling. See #4864 and #5246.
|
||||
CHECK_THROWS_WITH_AS(std::optional<std::string>(j_null),
|
||||
"[json.exception.type_error.302] type must be string, but is null", json::type_error&);
|
||||
CHECK_THROWS_WITH_AS(std::optional<int>(j_null),
|
||||
"[json.exception.type_error.302] type must be number, but is null", json::type_error&);
|
||||
|
||||
// Assignment goes through the same overload resolution as direct
|
||||
// construction, so it throws for the same reason. This relies on
|
||||
// basic_json's implicit conversion operator, so it only applies
|
||||
// when JSON_USE_IMPLICIT_CONVERSIONS is enabled (the default).
|
||||
#if JSON_USE_IMPLICIT_CONVERSIONS
|
||||
std::optional<std::string> opt_assign;
|
||||
CHECK_THROWS_WITH_AS(opt_assign = j_null,
|
||||
"[json.exception.type_error.302] type must be string, but is null", json::type_error&);
|
||||
#endif
|
||||
|
||||
// get_to() is the correct way to obtain std::nullopt from a JSON null.
|
||||
std::optional<std::string> opt_get_to = "placeholder";
|
||||
j_null.get_to(opt_get_to);
|
||||
CHECK(opt_get_to == std::nullopt);
|
||||
}
|
||||
|
||||
SECTION("string")
|
||||
{
|
||||
json j_string = "string";
|
||||
std::optional<std::string> opt_string = "string";
|
||||
|
||||
CHECK(json(opt_string) == j_string);
|
||||
CHECK(std::optional<std::string>(j_string) == opt_string);
|
||||
// false positive: Infer attributes the destruction of the temporaries above to opt_string
|
||||
// @infer-ignore USE_AFTER_DELETE
|
||||
}
|
||||
|
||||
SECTION("bool")
|
||||
{
|
||||
json j_bool = true;
|
||||
std::optional<bool> opt_bool = true;
|
||||
|
||||
CHECK(json(opt_bool) == j_bool);
|
||||
CHECK(std::optional<bool>(j_bool) == opt_bool);
|
||||
}
|
||||
|
||||
SECTION("number")
|
||||
{
|
||||
json j_number = 1;
|
||||
std::optional<int> opt_int = 1;
|
||||
|
||||
CHECK(json(opt_int) == j_number);
|
||||
CHECK(j_number.get<std::optional<int>>() == opt_int);
|
||||
}
|
||||
|
||||
SECTION("array")
|
||||
{
|
||||
json j_array = {1, 2, nullptr};
|
||||
std::vector<std::optional<int>> opt_array = {{1, 2, std::nullopt}};
|
||||
|
||||
CHECK(json(opt_array) == j_array);
|
||||
CHECK(j_array.get<std::vector<std::optional<int>>>() == opt_array);
|
||||
}
|
||||
|
||||
SECTION("object")
|
||||
{
|
||||
json j_object = {{"one", 1}, {"two", 2}, {"zero", nullptr}};
|
||||
std::map<std::string, std::optional<int>> opt_object {{"one", 1}, {"two", 2}, {"zero", std::nullopt}};
|
||||
|
||||
CHECK(json(opt_object) == j_object);
|
||||
CHECK(std::map<std::string, std::optional<int>>(j_object) == opt_object);
|
||||
}
|
||||
|
||||
#if !defined(JSON_NOEXCEPTION)
|
||||
SECTION("exception from contained value's to_json propagates (#5642)")
|
||||
{
|
||||
// to_json(BasicJsonType&, const std::optional<T>&) must not be
|
||||
// noexcept: it calls T's to_json, which may throw (a user-defined
|
||||
// to_json that reports an error, or std::bad_alloc for T =
|
||||
// std::string/vector/json). Before the fix, this called
|
||||
// std::terminate() instead of letting the exception propagate.
|
||||
const std::optional<throwing_to_json_type> opt = throwing_to_json_type{};
|
||||
CHECK_THROWS_WITH_AS(json(opt), "cannot serialize throwing_to_json_type", std::runtime_error&);
|
||||
|
||||
// the conversion is noexcept exactly when converting the contained value is
|
||||
static_assert(!std::is_nothrow_constructible<json, const std::optional<throwing_to_json_type>&>::value);
|
||||
static_assert(std::is_nothrow_constructible<json, const std::optional<int>&>::value);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef JSON_HAS_CPP_17
|
||||
#undef JSON_HAS_CPP_17
|
||||
#endif
|
||||
|
||||
#ifdef JSON_HAS_CPP_14
|
||||
#undef JSON_HAS_CPP_14
|
||||
#endif
|
||||
DOCTEST_CLANG_SUPPRESS_WARNING_POP
|
||||
@@ -505,7 +505,7 @@ static json_with_const_base make_nested_array(std::size_t depth)
|
||||
{
|
||||
if (depth == 0)
|
||||
{
|
||||
return json_with_const_base(1);
|
||||
return json_with_const_base(1); // NOLINT(modernize-return-braced-init-list): {1} would be an array
|
||||
}
|
||||
return json_with_const_base::array({make_nested_array(depth - 1)});
|
||||
}
|
||||
|
||||
@@ -1,214 +0,0 @@
|
||||
// __ _____ _____ _____
|
||||
// __| | __| | | | JSON for Modern C++ (supporting code)
|
||||
// | | |__ | | | | | | version 3.12.0
|
||||
// |_____|_____|_____|_|___| https://github.com/nlohmann/json
|
||||
//
|
||||
// SPDX-FileCopyrightText: 2013-2026 Niels Lohmann <https://nlohmann.me>
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
#include "doctest_compatibility.h"
|
||||
|
||||
// This file tests the opt-in JSON_DELETE_DEPRECATED_FUNCTIONS, so it defines the
|
||||
// macro itself instead of relying on the build configuration.
|
||||
#ifdef JSON_DELETE_DEPRECATED_FUNCTIONS
|
||||
#undef JSON_DELETE_DEPRECATED_FUNCTIONS
|
||||
#endif
|
||||
#define JSON_DELETE_DEPRECATED_FUNCTIONS 1
|
||||
|
||||
#include <nlohmann/json.hpp>
|
||||
using nlohmann::json;
|
||||
|
||||
#include <cstddef>
|
||||
#include <cstdint>
|
||||
#include <istream>
|
||||
#include <ostream>
|
||||
#include <string>
|
||||
#include <type_traits>
|
||||
#include <utility>
|
||||
|
||||
namespace
|
||||
{
|
||||
template<typename...>
|
||||
struct make_void
|
||||
{
|
||||
using type = void;
|
||||
};
|
||||
|
||||
template<typename... Ts>
|
||||
using void_t = typename make_void<Ts...>::type;
|
||||
|
||||
// A deleted function is still found by overload resolution, but naming it in an
|
||||
// unevaluated operand is ill-formed, so each of the following traits is false
|
||||
// exactly if the expression selects a deleted (or no) function.
|
||||
#define JSON_TEST_DETECT(name, expr) \
|
||||
template<typename J, typename = void> \
|
||||
struct name : std::false_type {}; \
|
||||
template<typename J> \
|
||||
struct name<J, void_t<decltype(expr)>> : std::true_type {}
|
||||
|
||||
using ptr_t = const std::uint8_t*;
|
||||
|
||||
JSON_TEST_DETECT(from_cbor_ptr_len, J::from_cbor(std::declval<ptr_t>(), std::declval<std::size_t>()));
|
||||
JSON_TEST_DETECT(from_msgpack_ptr_len, J::from_msgpack(std::declval<ptr_t>(), std::declval<std::size_t>()));
|
||||
JSON_TEST_DETECT(from_ubjson_ptr_len, J::from_ubjson(std::declval<ptr_t>(), std::declval<std::size_t>()));
|
||||
JSON_TEST_DETECT(from_bjdata_ptr_len, J::from_bjdata(std::declval<ptr_t>(), std::declval<std::size_t>()));
|
||||
JSON_TEST_DETECT(from_bon8_ptr_len, J::from_bon8(std::declval<ptr_t>(), std::declval<std::size_t>()));
|
||||
JSON_TEST_DETECT(from_bson_ptr_len, J::from_bson(std::declval<ptr_t>(), std::declval<std::size_t>()));
|
||||
|
||||
JSON_TEST_DETECT(from_cbor_ptr_ptr, J::from_cbor(std::declval<ptr_t>(), std::declval<ptr_t>()));
|
||||
JSON_TEST_DETECT(from_msgpack_ptr_ptr, J::from_msgpack(std::declval<ptr_t>(), std::declval<ptr_t>()));
|
||||
JSON_TEST_DETECT(from_ubjson_ptr_ptr, J::from_ubjson(std::declval<ptr_t>(), std::declval<ptr_t>()));
|
||||
JSON_TEST_DETECT(from_bjdata_ptr_ptr, J::from_bjdata(std::declval<ptr_t>(), std::declval<ptr_t>()));
|
||||
JSON_TEST_DETECT(from_bon8_ptr_ptr, J::from_bon8(std::declval<ptr_t>(), std::declval<ptr_t>()));
|
||||
JSON_TEST_DETECT(from_bson_ptr_ptr, J::from_bson(std::declval<ptr_t>(), std::declval<ptr_t>()));
|
||||
|
||||
JSON_TEST_DETECT(from_cbor_init_list, J::from_cbor({std::declval<ptr_t>(), std::declval<std::size_t>()}));
|
||||
JSON_TEST_DETECT(from_msgpack_init_list, J::from_msgpack({std::declval<ptr_t>(), std::declval<std::size_t>()}));
|
||||
JSON_TEST_DETECT(from_ubjson_init_list, J::from_ubjson({std::declval<ptr_t>(), std::declval<std::size_t>()}));
|
||||
JSON_TEST_DETECT(from_bson_init_list, J::from_bson({std::declval<ptr_t>(), std::declval<std::size_t>()}));
|
||||
|
||||
JSON_TEST_DETECT(parse_init_list, J::parse({std::declval<ptr_t>(), std::declval<std::size_t>()}));
|
||||
JSON_TEST_DETECT(accept_init_list, J::accept({std::declval<ptr_t>(), std::declval<std::size_t>()}));
|
||||
JSON_TEST_DETECT(sax_parse_init_list, J::sax_parse({std::declval<ptr_t>(), std::declval<std::size_t>()}, std::declval<nlohmann::json_sax<J>*>()));
|
||||
JSON_TEST_DETECT(parse_ptr_ptr, J::parse(std::declval<ptr_t>(), std::declval<ptr_t>()));
|
||||
|
||||
JSON_TEST_DETECT(iterator_wrapper, J::iterator_wrapper(std::declval<J&>()));
|
||||
JSON_TEST_DETECT(iterator_wrapper_const, J::iterator_wrapper(std::declval<const J&>()));
|
||||
JSON_TEST_DETECT(items, std::declval<J&>().items());
|
||||
|
||||
JSON_TEST_DETECT(json_ltlt_istream, std::declval<J&>() << std::declval<std::istream&>());
|
||||
JSON_TEST_DETECT(istream_gtgt_json, std::declval<std::istream&>() >> std::declval<J&>());
|
||||
JSON_TEST_DETECT(json_gtgt_ostream, std::declval<const J&>() >> std::declval<std::ostream&>());
|
||||
JSON_TEST_DETECT(ostream_ltlt_json, std::declval<std::ostream&>() << std::declval<const J&>());
|
||||
|
||||
JSON_TEST_DETECT(ptr_eq_ptr, std::declval<const typename J::json_pointer&>() == std::declval<const typename J::json_pointer&>());
|
||||
JSON_TEST_DETECT(ptr_ne_ptr, std::declval<const typename J::json_pointer&>() != std::declval<const typename J::json_pointer&>());
|
||||
JSON_TEST_DETECT(ptr_eq_string, std::declval<const typename J::json_pointer&>() == std::declval<const std::string&>());
|
||||
JSON_TEST_DETECT(string_eq_ptr, std::declval<const std::string&>() == std::declval<const typename J::json_pointer&>());
|
||||
JSON_TEST_DETECT(ptr_eq_c_string, std::declval<const typename J::json_pointer&>() == std::declval<const char*>());
|
||||
JSON_TEST_DETECT(c_string_eq_ptr, std::declval<const char*>() == std::declval<const typename J::json_pointer&>());
|
||||
JSON_TEST_DETECT(ptr_ne_string, std::declval<const typename J::json_pointer&>() != std::declval<const std::string&>());
|
||||
JSON_TEST_DETECT(string_ne_ptr, std::declval<const std::string&>() != std::declval<const typename J::json_pointer&>());
|
||||
JSON_TEST_DETECT(ptr_to_string, std::declval<const typename J::json_pointer&>().to_string());
|
||||
|
||||
// json_pointer with a basic_json type as template argument
|
||||
template<typename J>
|
||||
using legacy_ptr_t = const nlohmann::json_pointer<J>& ;
|
||||
JSON_TEST_DETECT(legacy_ptr_value, std::declval<const J&>().value(std::declval<legacy_ptr_t<J>>(), 0));
|
||||
JSON_TEST_DETECT(legacy_ptr_value_rvalue, std::declval<const J&>().value(std::declval<legacy_ptr_t<J>>(), std::string()));
|
||||
JSON_TEST_DETECT(legacy_ptr_contains, std::declval<const J&>().contains(std::declval<legacy_ptr_t<J>>()));
|
||||
JSON_TEST_DETECT(legacy_ptr_subscript, std::declval<J&>()[std::declval<legacy_ptr_t<J>>()]);
|
||||
JSON_TEST_DETECT(legacy_ptr_subscript_const, std::declval<const J&>()[std::declval<legacy_ptr_t<J>>()]);
|
||||
JSON_TEST_DETECT(legacy_ptr_at, std::declval<J&>().at(std::declval<legacy_ptr_t<J>>()));
|
||||
JSON_TEST_DETECT(legacy_ptr_at_const, std::declval<const J&>().at(std::declval<legacy_ptr_t<J>>()));
|
||||
JSON_TEST_DETECT(ptr_value, std::declval<const J&>().value(std::declval<const typename J::json_pointer&>(), 0));
|
||||
JSON_TEST_DETECT(ptr_at, std::declval<J&>().at(std::declval<const typename J::json_pointer&>()));
|
||||
|
||||
#undef JSON_TEST_DETECT
|
||||
} // namespace
|
||||
|
||||
TEST_CASE("JSON_DELETE_DEPRECATED_FUNCTIONS")
|
||||
{
|
||||
SECTION("from_* with a pointer and a length")
|
||||
{
|
||||
// the overloads are deleted rather than removed, so the length cannot
|
||||
// silently bind to the strict parameter of from_*(InputType&&, bool)
|
||||
CHECK_FALSE(from_cbor_ptr_len<json>::value);
|
||||
CHECK_FALSE(from_msgpack_ptr_len<json>::value);
|
||||
CHECK_FALSE(from_ubjson_ptr_len<json>::value);
|
||||
CHECK_FALSE(from_bjdata_ptr_len<json>::value);
|
||||
CHECK_FALSE(from_bon8_ptr_len<json>::value);
|
||||
CHECK_FALSE(from_bson_ptr_len<json>::value);
|
||||
|
||||
// the replacement
|
||||
CHECK(from_cbor_ptr_ptr<json>::value);
|
||||
CHECK(from_msgpack_ptr_ptr<json>::value);
|
||||
CHECK(from_ubjson_ptr_ptr<json>::value);
|
||||
CHECK(from_bjdata_ptr_ptr<json>::value);
|
||||
CHECK(from_bon8_ptr_ptr<json>::value);
|
||||
CHECK(from_bson_ptr_ptr<json>::value);
|
||||
}
|
||||
|
||||
SECTION("initializer lists of a pointer and a length")
|
||||
{
|
||||
CHECK_FALSE(from_cbor_init_list<json>::value);
|
||||
CHECK_FALSE(from_msgpack_init_list<json>::value);
|
||||
CHECK_FALSE(from_ubjson_init_list<json>::value);
|
||||
CHECK_FALSE(from_bson_init_list<json>::value);
|
||||
CHECK_FALSE(parse_init_list<json>::value);
|
||||
CHECK_FALSE(accept_init_list<json>::value);
|
||||
CHECK_FALSE(sax_parse_init_list<json>::value);
|
||||
|
||||
// the replacement
|
||||
CHECK(parse_ptr_ptr<json>::value);
|
||||
}
|
||||
|
||||
SECTION("iterator_wrapper")
|
||||
{
|
||||
CHECK_FALSE(iterator_wrapper<json>::value);
|
||||
CHECK_FALSE(iterator_wrapper_const<json>::value);
|
||||
|
||||
// the replacement
|
||||
CHECK(items<json>::value);
|
||||
}
|
||||
|
||||
SECTION("stream operators with reversed operands")
|
||||
{
|
||||
CHECK_FALSE(json_ltlt_istream<json>::value);
|
||||
CHECK_FALSE(json_gtgt_ostream<json>::value);
|
||||
|
||||
// the replacement
|
||||
CHECK(istream_gtgt_json<json>::value);
|
||||
CHECK(ostream_ltlt_json<json>::value);
|
||||
}
|
||||
|
||||
SECTION("json_pointer")
|
||||
{
|
||||
// conversion to a string
|
||||
CHECK_FALSE(std::is_constructible<std::string, json::json_pointer>::value);
|
||||
CHECK_FALSE(std::is_convertible<json::json_pointer, std::string>::value);
|
||||
|
||||
// comparison with a string
|
||||
CHECK_FALSE(ptr_eq_string<json>::value);
|
||||
CHECK_FALSE(string_eq_ptr<json>::value);
|
||||
CHECK_FALSE(ptr_eq_c_string<json>::value);
|
||||
CHECK_FALSE(c_string_eq_ptr<json>::value);
|
||||
CHECK_FALSE(ptr_ne_string<json>::value);
|
||||
CHECK_FALSE(string_ne_ptr<json>::value);
|
||||
|
||||
// the replacement
|
||||
CHECK(ptr_to_string<json>::value);
|
||||
CHECK(ptr_eq_ptr<json>::value);
|
||||
CHECK(ptr_ne_ptr<json>::value);
|
||||
}
|
||||
|
||||
SECTION("json_pointer with a basic_json type as template argument")
|
||||
{
|
||||
CHECK_FALSE(legacy_ptr_value<json>::value);
|
||||
CHECK_FALSE(legacy_ptr_value_rvalue<json>::value);
|
||||
CHECK_FALSE(legacy_ptr_contains<json>::value);
|
||||
CHECK_FALSE(legacy_ptr_subscript<json>::value);
|
||||
CHECK_FALSE(legacy_ptr_subscript_const<json>::value);
|
||||
CHECK_FALSE(legacy_ptr_at<json>::value);
|
||||
CHECK_FALSE(legacy_ptr_at_const<json>::value);
|
||||
|
||||
// the replacement
|
||||
CHECK(ptr_value<json>::value);
|
||||
CHECK(ptr_at<json>::value);
|
||||
}
|
||||
|
||||
SECTION("the non-deprecated functions still work")
|
||||
{
|
||||
const json j = {{"a", {1, 2}}};
|
||||
const auto cbor = json::to_cbor(j);
|
||||
CHECK(json::from_cbor(cbor.data(), cbor.data() + cbor.size()) == j);
|
||||
|
||||
const json::json_pointer ptr("/a/1");
|
||||
CHECK(ptr == json::json_pointer("/a/1"));
|
||||
CHECK(ptr.to_string() == "/a/1");
|
||||
CHECK(j[ptr] == 2);
|
||||
CHECK(j.at(ptr) == 2);
|
||||
CHECK(j.value(ptr, 0) == 2);
|
||||
CHECK(j.contains(ptr));
|
||||
}
|
||||
}
|
||||
@@ -16,14 +16,6 @@
|
||||
#define JSON_TEST_STRICT_NUL_HANDLING_ENABLED 1
|
||||
#endif
|
||||
|
||||
// capture whether JSON_DELETE_DEPRECATED_FUNCTIONS was enabled on the command
|
||||
// line *before* including json.hpp, since the library #undefs it once the header
|
||||
// has been fully processed (see include/nlohmann/detail/macro_unscope.hpp); the
|
||||
// tests of deprecated functions are skipped if these functions are deleted
|
||||
#if defined(JSON_DELETE_DEPRECATED_FUNCTIONS) && (JSON_DELETE_DEPRECATED_FUNCTIONS == 1)
|
||||
#define JSON_TEST_DEPRECATED_FUNCTIONS_DELETED
|
||||
#endif
|
||||
|
||||
#include <nlohmann/json.hpp>
|
||||
using nlohmann::json;
|
||||
#ifdef JSON_TEST_NO_GLOBAL_UDLS
|
||||
@@ -299,7 +291,6 @@ TEST_CASE("deserialization")
|
||||
}));
|
||||
}
|
||||
|
||||
#ifndef JSON_TEST_DEPRECATED_FUNCTIONS_DELETED
|
||||
SECTION("operator<<")
|
||||
{
|
||||
std::stringstream ss;
|
||||
@@ -308,7 +299,6 @@ TEST_CASE("deserialization")
|
||||
j << ss;
|
||||
CHECK(j == json({"foo", 1, 2, 3, false, {{"one", 1}}}));
|
||||
}
|
||||
#endif
|
||||
|
||||
SECTION("operator>>")
|
||||
{
|
||||
@@ -433,7 +423,6 @@ TEST_CASE("deserialization")
|
||||
CHECK_THROWS_WITH_AS(_ = json::parse(nullptr), "[json.exception.parse_error.101] parse error: attempting to parse an empty input; check that your input string or stream contains the expected JSON", json::parse_error&);
|
||||
}
|
||||
|
||||
#ifndef JSON_TEST_DEPRECATED_FUNCTIONS_DELETED
|
||||
SECTION("operator<<")
|
||||
{
|
||||
std::stringstream ss;
|
||||
@@ -441,7 +430,6 @@ TEST_CASE("deserialization")
|
||||
json j;
|
||||
CHECK_THROWS_WITH_AS(j << ss, "[json.exception.parse_error.101] parse error at line 1, column 29: syntax error while parsing array - unexpected end of input; expected ']'", json::parse_error&);
|
||||
}
|
||||
#endif
|
||||
|
||||
SECTION("operator>>")
|
||||
{
|
||||
@@ -1160,9 +1148,9 @@ TEST_CASE("deserialization")
|
||||
{
|
||||
std::istringstream s(bom + "123 456");
|
||||
json j;
|
||||
s >> j;
|
||||
j << s;
|
||||
CHECK(j == 123);
|
||||
s >> j;
|
||||
j << s;
|
||||
CHECK(j == 456);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -14,6 +14,9 @@ DOCTEST_GCC_SUPPRESS_WARNING("-Wnoexcept")
|
||||
|
||||
#include <nlohmann/json.hpp>
|
||||
using json = nlohmann::json;
|
||||
#ifdef JSON_TEST_NO_GLOBAL_UDLS
|
||||
using namespace nlohmann::literals; // NOLINT(google-build-using-namespace)
|
||||
#endif
|
||||
|
||||
/////////////////////////////////////////////////////////////////////
|
||||
// for #2824
|
||||
|
||||
@@ -1963,8 +1963,8 @@ TEST_CASE("operator[] with user-defined std::string_view-convertible types")
|
||||
};
|
||||
|
||||
json j = {{"foo", "from_class"}, {"bar", "from_struct"}};
|
||||
TestClass foo_obj;
|
||||
TestStruct bar_obj;
|
||||
const TestClass foo_obj;
|
||||
const TestStruct bar_obj;
|
||||
|
||||
SECTION("read access")
|
||||
{
|
||||
@@ -2005,6 +2005,10 @@ TEST_CASE("keys convertible to std::string_view work with all lookup functions (
|
||||
// 3.12.0, such a key worked with at, the const operator[], find, count and
|
||||
// contains via the conversion to std::string; #4958 made the KeyType&&
|
||||
// templates win overload resolution for it instead, and those then failed
|
||||
// the lookups pick the conversion to std::string_view, which leaves the one
|
||||
// to std::string unused; it has to exist to reproduce the ambiguity
|
||||
DOCTEST_CLANG_SUPPRESS_WARNING_PUSH
|
||||
DOCTEST_CLANG_SUPPRESS_WARNING("-Wunused-member-function")
|
||||
struct DualKey
|
||||
{
|
||||
operator std::string() const
|
||||
@@ -2016,6 +2020,7 @@ TEST_CASE("keys convertible to std::string_view work with all lookup functions (
|
||||
return "a";
|
||||
}
|
||||
};
|
||||
DOCTEST_CLANG_SUPPRESS_WARNING_POP
|
||||
|
||||
SECTION("nlohmann::json")
|
||||
{
|
||||
|
||||
@@ -8,14 +8,6 @@
|
||||
|
||||
#include "doctest_compatibility.h"
|
||||
|
||||
// capture whether JSON_DELETE_DEPRECATED_FUNCTIONS was enabled on the command
|
||||
// line *before* including json.hpp, since the library #undefs it once the header
|
||||
// has been fully processed (see include/nlohmann/detail/macro_unscope.hpp); the
|
||||
// tests of deprecated functions are skipped if these functions are deleted
|
||||
#if defined(JSON_DELETE_DEPRECATED_FUNCTIONS) && (JSON_DELETE_DEPRECATED_FUNCTIONS == 1)
|
||||
#define JSON_TEST_DEPRECATED_FUNCTIONS_DELETED
|
||||
#endif
|
||||
|
||||
#include <nlohmann/json.hpp>
|
||||
using nlohmann::json;
|
||||
|
||||
@@ -27,7 +19,6 @@ DOCTEST_GCC_SUPPRESS_WARNING_PUSH
|
||||
DOCTEST_CLANG_SUPPRESS_WARNING_PUSH
|
||||
DOCTEST_CLANG_SUPPRESS_WARNING("-Wrange-loop-construct")
|
||||
|
||||
#ifndef JSON_TEST_DEPRECATED_FUNCTIONS_DELETED
|
||||
TEST_CASE("iterator_wrapper")
|
||||
{
|
||||
SECTION("object")
|
||||
@@ -724,7 +715,6 @@ TEST_CASE("iterator_wrapper")
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
TEST_CASE("items()")
|
||||
{
|
||||
|
||||
@@ -9,14 +9,6 @@
|
||||
#include "doctest_compatibility.h"
|
||||
|
||||
#define JSON_TESTS_PRIVATE
|
||||
// capture whether JSON_DELETE_DEPRECATED_FUNCTIONS was enabled on the command
|
||||
// line *before* including json.hpp, since the library #undefs it once the header
|
||||
// has been fully processed (see include/nlohmann/detail/macro_unscope.hpp); the
|
||||
// tests of deprecated functions are skipped if these functions are deleted
|
||||
#if defined(JSON_DELETE_DEPRECATED_FUNCTIONS) && (JSON_DELETE_DEPRECATED_FUNCTIONS == 1)
|
||||
#define JSON_TEST_DEPRECATED_FUNCTIONS_DELETED
|
||||
#endif
|
||||
|
||||
#include <nlohmann/json.hpp>
|
||||
using nlohmann::json;
|
||||
#ifdef JSON_TEST_NO_GLOBAL_UDLS
|
||||
@@ -572,9 +564,7 @@ TEST_CASE("JSON pointers")
|
||||
std::stringstream ss;
|
||||
ss << ptr;
|
||||
CHECK(ptr.to_string() == ptr_str);
|
||||
#ifndef JSON_TEST_DEPRECATED_FUNCTIONS_DELETED
|
||||
CHECK(std::string(ptr) == ptr_str);
|
||||
#endif
|
||||
CHECK(ss.str() == ptr_str);
|
||||
}
|
||||
}
|
||||
@@ -754,6 +744,8 @@ TEST_CASE("JSON pointers")
|
||||
|
||||
SECTION("equality comparison")
|
||||
{
|
||||
const char* ptr_cpstring = "/foo/bar";
|
||||
const char ptr_castring[] = "/foo/bar"; // NOLINT(misc-const-correctness,hicpp-avoid-c-arrays,modernize-avoid-c-arrays,cppcoreguidelines-avoid-c-arrays)
|
||||
std::string ptr_string{"/foo/bar"};
|
||||
auto ptr1 = json::json_pointer(ptr_string);
|
||||
auto ptr2 = json::json_pointer(ptr_string);
|
||||
@@ -763,12 +755,6 @@ TEST_CASE("JSON pointers")
|
||||
|
||||
CHECK(ptr1 == ptr2);
|
||||
|
||||
CHECK_FALSE(ptr1 != ptr2);
|
||||
|
||||
#ifndef JSON_TEST_DEPRECATED_FUNCTIONS_DELETED
|
||||
const char* ptr_cpstring = "/foo/bar";
|
||||
const char ptr_castring[] = "/foo/bar"; // NOLINT(misc-const-correctness,hicpp-avoid-c-arrays,modernize-avoid-c-arrays,cppcoreguidelines-avoid-c-arrays)
|
||||
|
||||
CHECK(ptr1 == "/foo/bar");
|
||||
CHECK(ptr1 == ptr_cpstring);
|
||||
CHECK(ptr1 == ptr_castring);
|
||||
@@ -779,6 +765,8 @@ TEST_CASE("JSON pointers")
|
||||
CHECK(ptr_castring == ptr1);
|
||||
CHECK(ptr_string == ptr1);
|
||||
|
||||
CHECK_FALSE(ptr1 != ptr2);
|
||||
|
||||
CHECK_FALSE(ptr1 != "/foo/bar");
|
||||
CHECK_FALSE(ptr1 != ptr_cpstring);
|
||||
CHECK_FALSE(ptr1 != ptr_castring);
|
||||
@@ -800,7 +788,6 @@ TEST_CASE("JSON pointers")
|
||||
CHECK_THROWS_WITH_AS("/~~" == ptr1,
|
||||
"[json.exception.parse_error.108] parse error: escape character '~' must be followed with '0' or '1'", json::parse_error&);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
SECTION("less-than comparison")
|
||||
@@ -852,7 +839,6 @@ TEST_CASE("JSON pointers")
|
||||
json_ptr_j ptr_j{ptr_string};
|
||||
json_ptr_oj ptr_oj{ptr_string};
|
||||
|
||||
#ifndef JSON_TEST_DEPRECATED_FUNCTIONS_DELETED
|
||||
CHECK(j.contains(ptr));
|
||||
CHECK(j.contains(ptr_j));
|
||||
CHECK(j.contains(ptr_oj));
|
||||
@@ -865,7 +851,6 @@ TEST_CASE("JSON pointers")
|
||||
|
||||
CHECK(j.value(ptr, "x") == j.value(ptr_j, "x"));
|
||||
CHECK(j.value(ptr, "x") == j.value(ptr_oj, "x"));
|
||||
#endif
|
||||
|
||||
CHECK(ptr == ptr_j);
|
||||
CHECK(ptr == ptr_oj);
|
||||
|
||||
@@ -1162,6 +1162,7 @@ TEST_CASE("update() on deeply nested values")
|
||||
|
||||
TEST_CASE("update() with an argument that aliases *this (#5641)")
|
||||
{
|
||||
#if !defined(JSON_NOEXCEPTION) // checks which exception is thrown, and that nothing changed
|
||||
SECTION("the target is checked before the argument, as before the copy")
|
||||
{
|
||||
json j = 1;
|
||||
@@ -1172,6 +1173,7 @@ TEST_CASE("update() with an argument that aliases *this (#5641)")
|
||||
CHECK_THROWS_WITH_AS(k.update(json::array()), "[json.exception.type_error.312] cannot use update() with array", json::type_error&);
|
||||
CHECK(k == json::object());
|
||||
}
|
||||
#endif
|
||||
|
||||
SECTION("const reference")
|
||||
{
|
||||
|
||||
@@ -8,14 +8,6 @@
|
||||
|
||||
#include "doctest_compatibility.h"
|
||||
|
||||
// capture whether JSON_DELETE_DEPRECATED_FUNCTIONS was enabled on the command
|
||||
// line *before* including json.hpp, since the library #undefs it once the header
|
||||
// has been fully processed (see include/nlohmann/detail/macro_unscope.hpp); the
|
||||
// tests of deprecated functions are skipped if these functions are deleted
|
||||
#if defined(JSON_DELETE_DEPRECATED_FUNCTIONS) && (JSON_DELETE_DEPRECATED_FUNCTIONS == 1)
|
||||
#define JSON_TEST_DEPRECATED_FUNCTIONS_DELETED
|
||||
#endif
|
||||
|
||||
#include <nlohmann/json.hpp>
|
||||
using nlohmann::json;
|
||||
#ifdef JSON_TEST_NO_GLOBAL_UDLS
|
||||
@@ -1568,7 +1560,7 @@ TEST_CASE("MessagePack")
|
||||
// dump() still requires valid UTF-8 and throws for such a value,
|
||||
// unless an error handler that replaces or ignores the bytes is
|
||||
// passed
|
||||
CHECK_THROWS_AS(j_value.dump(), json::type_error&);
|
||||
CHECK_THROWS_AS(utils::ignore_return_value(j_value.dump()), json::type_error&);
|
||||
|
||||
// the same bytes as an object key round-trip as well
|
||||
const std::vector<uint8_t> ill_formed_key = {0x81, 0xa2, 0xc0, 0xae, 0x01};
|
||||
@@ -1803,10 +1795,8 @@ TEST_CASE("MessagePack input that cannot be read is discarded by every overload"
|
||||
CHECK_THROWS_AS(_ = json::from_msgpack(input.begin(), input.end()), json::parse_error&);
|
||||
CHECK(json::from_msgpack(input, true, false).is_discarded());
|
||||
CHECK(json::from_msgpack(input.begin(), input.end(), true, false).is_discarded());
|
||||
#ifndef JSON_TEST_DEPRECATED_FUNCTIONS_DELETED
|
||||
CHECK(json::from_msgpack(input.data(), input.size(), true, false).is_discarded());
|
||||
CHECK(json::from_msgpack({input.data(), input.size()}, true, false).is_discarded());
|
||||
#endif
|
||||
}
|
||||
|
||||
TEST_CASE("MessagePack SAX parsing stops at every event")
|
||||
@@ -2109,14 +2099,12 @@ TEST_CASE("MessagePack roundtrips" * doctest::skip())
|
||||
CHECK(j1 == j2);
|
||||
}
|
||||
|
||||
#ifndef JSON_TEST_DEPRECATED_FUNCTIONS_DELETED
|
||||
{
|
||||
INFO_WITH_TEMP(filename + ": uint8_t* and size");
|
||||
json j2;
|
||||
CHECK_NOTHROW(j2 = json::from_msgpack({packed.data(), packed.size()}));
|
||||
CHECK(j1 == j2);
|
||||
}
|
||||
#endif
|
||||
|
||||
{
|
||||
INFO_WITH_TEMP(filename + ": output to output adapters");
|
||||
|
||||
@@ -430,8 +430,8 @@ TEST_CASE("ordered_map")
|
||||
|
||||
SECTION("with T& (lvalue)")
|
||||
{
|
||||
std::string one = "1";
|
||||
std::string four = "four";
|
||||
std::string one = "1"; // NOLINT(misc-const-correctness): emplace must accept a non-const lvalue
|
||||
std::string four = "four"; // NOLINT(misc-const-correctness): see above
|
||||
|
||||
auto res1 = om.emplace("eins", one);
|
||||
CHECK(res1.first == om.begin());
|
||||
@@ -467,7 +467,7 @@ TEST_CASE("ordered_map")
|
||||
SECTION("with key of key_type (non-template overload)")
|
||||
{
|
||||
const std::string key_vier{"vier"};
|
||||
std::string four = "four";
|
||||
std::string four = "four"; // NOLINT(misc-const-correctness): emplace must accept a non-const lvalue
|
||||
|
||||
auto res4 = om.emplace(key_vier, four);
|
||||
CHECK(res4.first == om.begin() + 3);
|
||||
|
||||
@@ -569,7 +569,7 @@ TEST_CASE("regression tests 2")
|
||||
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}};
|
||||
const json j = json::from_msgpack(data.begin(), data.end());
|
||||
const json j = json::from_msgpack(data.data(), data.size());
|
||||
// dump() is nodiscard; this only checks that dumping does not throw
|
||||
CHECK_NOTHROW(
|
||||
utils::ignore_return_value(
|
||||
|
||||
@@ -8,14 +8,6 @@
|
||||
|
||||
#include "doctest_compatibility.h"
|
||||
|
||||
// capture whether JSON_DELETE_DEPRECATED_FUNCTIONS was enabled on the command
|
||||
// line *before* including json.hpp, since the library #undefs it once the header
|
||||
// has been fully processed (see include/nlohmann/detail/macro_unscope.hpp); the
|
||||
// tests of deprecated functions are skipped if these functions are deleted
|
||||
#if defined(JSON_DELETE_DEPRECATED_FUNCTIONS) && (JSON_DELETE_DEPRECATED_FUNCTIONS == 1)
|
||||
#define JSON_TEST_DEPRECATED_FUNCTIONS_DELETED
|
||||
#endif
|
||||
|
||||
#include <nlohmann/json.hpp>
|
||||
using nlohmann::json;
|
||||
|
||||
@@ -56,7 +48,6 @@ TEST_CASE("serialization")
|
||||
}
|
||||
}
|
||||
|
||||
#ifndef JSON_TEST_DEPRECATED_FUNCTIONS_DELETED
|
||||
SECTION("operator>>")
|
||||
{
|
||||
SECTION("no given width")
|
||||
@@ -88,7 +79,6 @@ TEST_CASE("serialization")
|
||||
"[\n\t\"foo\",\n\t1,\n\t2,\n\t3,\n\tfalse,\n\t{\n\t\t\"one\": 1\n\t}\n]");
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
SECTION("dump")
|
||||
{
|
||||
|
||||
@@ -8,14 +8,6 @@
|
||||
|
||||
#include "doctest_compatibility.h"
|
||||
|
||||
// capture whether JSON_DELETE_DEPRECATED_FUNCTIONS was enabled on the command
|
||||
// line *before* including json.hpp, since the library #undefs it once the header
|
||||
// has been fully processed (see include/nlohmann/detail/macro_unscope.hpp); the
|
||||
// tests of deprecated functions are skipped if these functions are deleted
|
||||
#if defined(JSON_DELETE_DEPRECATED_FUNCTIONS) && (JSON_DELETE_DEPRECATED_FUNCTIONS == 1)
|
||||
#define JSON_TEST_DEPRECATED_FUNCTIONS_DELETED
|
||||
#endif
|
||||
|
||||
#include <nlohmann/json.hpp>
|
||||
using nlohmann::json;
|
||||
|
||||
@@ -2220,10 +2212,8 @@ TEST_CASE("UBJSON input that cannot be read is discarded by every overload")
|
||||
CHECK_THROWS_AS(_ = json::from_ubjson(input.begin(), input.end()), json::parse_error&);
|
||||
CHECK(json::from_ubjson(input, true, false).is_discarded());
|
||||
CHECK(json::from_ubjson(input.begin(), input.end(), true, false).is_discarded());
|
||||
#ifndef JSON_TEST_DEPRECATED_FUNCTIONS_DELETED
|
||||
CHECK(json::from_ubjson(input.data(), input.size(), true, false).is_discarded());
|
||||
CHECK(json::from_ubjson({input.data(), input.size()}, true, false).is_discarded());
|
||||
#endif
|
||||
}
|
||||
|
||||
TEST_CASE("UBJSON SAX parsing stops at every event")
|
||||
@@ -2530,7 +2520,7 @@ TEST_CASE("Universal Binary JSON Specification Examples 1")
|
||||
CHECK_NOTHROW(j = json::from_ubjson(v));
|
||||
REQUIRE(j.is_string());
|
||||
CHECK(j.get_ref<const json::string_t&>() == std::string("\xc0\xae"));
|
||||
CHECK_THROWS_AS(j.dump(), json::type_error&);
|
||||
CHECK_THROWS_AS(utils::ignore_return_value(j.dump()), json::type_error&);
|
||||
CHECK(json::from_ubjson(json::to_ubjson(j)) == j);
|
||||
|
||||
// the same bytes as an object key round-trip as well
|
||||
@@ -2971,14 +2961,12 @@ TEST_CASE("UBJSON roundtrips" * doctest::skip())
|
||||
CHECK(j1 == j2);
|
||||
}
|
||||
|
||||
#ifndef JSON_TEST_DEPRECATED_FUNCTIONS_DELETED
|
||||
{
|
||||
INFO_WITH_TEMP(filename + ": uint8_t* and size");
|
||||
json j2;
|
||||
CHECK_NOTHROW(j2 = json::from_ubjson({packed.data(), packed.size()}));
|
||||
CHECK(j1 == j2);
|
||||
}
|
||||
#endif
|
||||
|
||||
{
|
||||
INFO_WITH_TEMP(filename + ": output to output adapters");
|
||||
|
||||
@@ -37,10 +37,10 @@ TEST_CASE("wide strings")
|
||||
// 32-bit wchar_t first encodes it as an ill-formed three-byte
|
||||
// sequence (rejected one byte later, at column 3)
|
||||
const char* const error_low_surrogate = sizeof(wchar_t) == 2
|
||||
? "[json.exception.parse_error.101] parse error at line 1, column 2: syntax error while parsing value - invalid string: ill-formed UTF-8 byte; last read: '\"<U+0000>'"
|
||||
? "[json.exception.parse_error.101] parse error at line 1, column 2: syntax error while parsing value - invalid string: ill-formed UTF-8 byte; last read: '\"\xFF'"
|
||||
: "[json.exception.parse_error.101] parse error at line 1, column 3: syntax error while parsing value - invalid string: ill-formed UTF-8 byte; last read: '\"\xED\xB0'";
|
||||
const char* const error_high_surrogate = sizeof(wchar_t) == 2
|
||||
? "[json.exception.parse_error.101] parse error at line 1, column 2: syntax error while parsing value - invalid string: ill-formed UTF-8 byte; last read: '\"<U+0000>'"
|
||||
? "[json.exception.parse_error.101] parse error at line 1, column 2: syntax error while parsing value - invalid string: ill-formed UTF-8 byte; last read: '\"\xFF'"
|
||||
: "[json.exception.parse_error.101] parse error at line 1, column 3: syntax error while parsing value - invalid string: ill-formed UTF-8 byte; last read: '\"\xED\xA0'";
|
||||
|
||||
// a lone low surrogate cannot start a pair
|
||||
|
||||
Reference in New Issue
Block a user