From ef556019be51ba3db32854e2a491b4ccb540a2c8 Mon Sep 17 00:00:00 2001 From: Niels Lohmann Date: Sun, 9 Jan 2022 14:32:38 +0100 Subject: [PATCH 01/18] :memo: overwork documentation --- .../operator_literal_json_pointer.md | 4 + doc/mkdocs/docs/api/json_pointer/index.md | 1 + doc/mkdocs/docs/features/json_pointer.md | 122 +++++++++++- doc/mkdocs/docs/integration/cmake.md | 174 ++++++++++-------- doc/mkdocs/docs/integration/example.cpp | 3 +- doc/mkdocs/docs/integration/index.md | 10 +- .../docs/integration/package_managers.md | 73 ++++---- 7 files changed, 265 insertions(+), 122 deletions(-) diff --git a/doc/mkdocs/docs/api/basic_json/operator_literal_json_pointer.md b/doc/mkdocs/docs/api/basic_json/operator_literal_json_pointer.md index 38c957e61..897ac07cd 100644 --- a/doc/mkdocs/docs/api/basic_json/operator_literal_json_pointer.md +++ b/doc/mkdocs/docs/api/basic_json/operator_literal_json_pointer.md @@ -43,6 +43,10 @@ Linear. --8<-- "examples/operator_literal_json_pointer.output" ``` +## See also + +- [json_pointer](../json_pointer/index.md) - type to represent JSON Pointers + ## Version history - Added in version 2.0.0. diff --git a/doc/mkdocs/docs/api/json_pointer/index.md b/doc/mkdocs/docs/api/json_pointer/index.md index 6ef9435fb..d95ed0ffb 100644 --- a/doc/mkdocs/docs/api/json_pointer/index.md +++ b/doc/mkdocs/docs/api/json_pointer/index.md @@ -29,6 +29,7 @@ are the base for JSON patches. ## See also +- [operator""_json_pointer](../basic_json/operator_literal_json_pointer.md) - user-defined string literal for JSON pointers - [RFC 6901](https://datatracker.ietf.org/doc/html/rfc6901) ## Version history diff --git a/doc/mkdocs/docs/features/json_pointer.md b/doc/mkdocs/docs/features/json_pointer.md index 8f5d60ec7..a7861ec7d 100644 --- a/doc/mkdocs/docs/features/json_pointer.md +++ b/doc/mkdocs/docs/features/json_pointer.md @@ -1,19 +1,123 @@ # JSON Pointer -The library supports **JSON Pointer** ([RFC 6901](https://tools.ietf.org/html/rfc6901)) as alternative means to address structured values. +## Introduction + +The library supports **JSON Pointer** ([RFC 6901](https://tools.ietf.org/html/rfc6901)) as alternative means to address +structured values. A JSON Pointer is a string that identifies a specific value withing a JSON document. + +Consider the following JSON document + +```json +{ + "array": ["A", "B", "C"], + "nested": { + "one": 1, + "two": 2, + "three": [true, false] + } +} +``` + +Then every value inside the JSON document can be idientified as follows: + +| JSON Pointer | JSON value | +|-------------------|----------------------------------------------------------------------------------| +| `/` | `#!json {"array":["A","B","C"],"nested":{"one":1,"two":2,"three":[true,false]}}` | +| `/array` | `#!json ["A","B","C"]` | +| `/array/0` | `#!json A` | +| `/array/1` | `#!json B` | +| `/array/2` | `#!json C` | +| `/nested` | `#!json {"one":1,"two":2,"three":[true,false]}` | +| `/nested/one` | `#!json 1` | +| `/nested/two` | `#!json 2` | +| `/nested/three` | `#!json [true,false]` | +| `/nested/three/0` | `#!json true` | +| `/nested/three/1` | `#!json false` | + +## JSON Pointer creation + +JSON Pointers can be created from a string: ```cpp -// a JSON value -json j_original = R"({ - "baz": ["one", "two", "three"], - "foo": "bar" -})"_json; +json::json_pointer p = "/nested/one"; +``` -// access members with a JSON pointer (RFC 6901) -j_original["/baz/1"_json_pointer]; -// "two" +Furthermore, a user-defined string literal can be used to achieve the same result: + +```cpp +auto p = "/nested/one"_json_pointer; +``` + +The escaping rules of [RFC 6901](https://tools.ietf.org/html/rfc6901) are implemented. See the +[constructor documentation](../api/json_pointer/json_pointer.md) for more information. + +## Value access + +JSON Pointers can be used in the [`at`](../api/basic_json/at.md), [`operator[]`](../api/basic_json/operator%5B%5D.md), +and [`value`](../api/basic_json/value.md) functions just like object keys or array indices. + +```cpp +// the JSON value from above +auto j = json::parse(R"({ + "array": ["A", "B", "C"], + "nested": { + "one": 1, + "two": 2, + "three": [true, false] + } +})"); + +// access values +auto val = j["/"_json_pointer]; // {"array":["A","B","C"],...} +auto val1 = j["/nested/one"_json_pointer]; // 1 +auto val2 = j.at[json::json_pointer("/nested/three/1")]; // false +auto val3 = j.value[json::json_pointer("/nested/four", 0)]; // 0 +``` + +## Flatten / unflatten + +The library implements a function [`flatten`](../api/basic_json/flatten.md) to convert any JSON document into a JSON +object where each key is a JSON Pointer and each value is a primitive JSON value (i.e., a string, boolean, number, or +null). + +```cpp +// the JSON value from above +auto j = json::parse(R"({ + "array": ["A", "B", "C"], + "nested": { + "one": 1, + "two": 2, + "three": [true, false] + } +})"); + +// create flattened value +auto j_flat = j.flatten(); +``` + +The resulting value `j_flat` is: + +```json +{ + "/array/0": "A", + "/array/1": "B", + "/array/2": "C", + "/nested/one": 1, + "/nested/two": 2, + "/nested/three/0": true, + "/nested/three/1": false +} +``` + +The reverse function, [`unflatten`](../api/basic_json/unflatten.md) recreates the original value. + +```cpp +auto j_original = j_flat.unflatten(); ``` ## See also - Class [`json_pointer`](../api/json_pointer/index.md) +- Function [`flatten`](../api/basic_json/flatten.md) +- Function [`unflatten`](../api/basic_json/unflatten.md) +- [JSON Patch](json_patch.md) diff --git a/doc/mkdocs/docs/integration/cmake.md b/doc/mkdocs/docs/integration/cmake.md index 9f1ecc95a..44aeb26e1 100644 --- a/doc/mkdocs/docs/integration/cmake.md +++ b/doc/mkdocs/docs/integration/cmake.md @@ -2,102 +2,124 @@ ## Integration -You can also use the `nlohmann_json::nlohmann_json` interface target in CMake. This target populates the appropriate usage requirements for `INTERFACE_INCLUDE_DIRECTORIES` to point to the appropriate include directories and `INTERFACE_COMPILE_FEATURES` for the necessary C++11 flags. +You can use the `nlohmann_json::nlohmann_json` interface target in CMake. This target populates the appropriate usage +requirements for [`INTERFACE_INCLUDE_DIRECTORIES`](https://cmake.org/cmake/help/latest/prop_tgt/INTERFACE_INCLUDE_DIRECTORIES.html) +to point to the appropriate include directories and [`INTERFACE_COMPILE_FEATURES`](https://cmake.org/cmake/help/latest/prop_tgt/INTERFACE_COMPILE_FEATURES.html) +for the necessary C++11 flags. ### External -To use this library from a CMake project, you can locate it directly with `find_package()` and use the namespaced imported target from the generated package configuration: +To use this library from a CMake project, you can locate it directly with [`find_package()`](https://cmake.org/cmake/help/latest/command/find_package.html) +and use the namespaced imported target from the generated package configuration: -```cmake -# CMakeLists.txt -find_package(nlohmann_json 3.2.0 REQUIRED) -... -add_library(foo ...) -... -target_link_libraries(foo PRIVATE nlohmann_json::nlohmann_json) -``` +!!! example -The package configuration file, `nlohmann_jsonConfig.cmake`, can be used either from an install tree or directly out of the build tree. + ```cmake title="CMakeLists.txt" + cmake_minimum_required(VERSION 3.1) + project(ExampleProject LANGUAGES CXX) + + find_package(nlohmann_json 3.10.5 REQUIRED) + + add_executable(example example.cpp) + target_link_libraries(example PRIVATE nlohmann_json::nlohmann_json) + ``` + +The package configuration file, `nlohmann_jsonConfig.cmake`, can be used either from an install tree or directly out of +the build tree. ### Embedded -To embed the library directly into an existing CMake project, place the entire source tree in a subdirectory and call `add_subdirectory()` in your `CMakeLists.txt` file: +To embed the library directly into an existing CMake project, place the entire source tree in a subdirectory and call +`add_subdirectory()` in your `CMakeLists.txt` file. -```cmake -# If you only include this third party in PRIVATE source files, you do not -# need to install it when your main project gets installed. -# set(JSON_Install OFF CACHE INTERNAL "") +!!! example -# Don't use include(nlohmann_json/CMakeLists.txt) since that carries with it -# unintended consequences that will break the build. It's generally -# discouraged (although not necessarily well documented as such) to use -# include(...) for pulling in other CMake projects anyways. -add_subdirectory(nlohmann_json) -... -add_library(foo ...) -... -target_link_libraries(foo PRIVATE nlohmann_json::nlohmann_json) -``` + ```cmake title="CMakeLists.txt" + cmake_minimum_required(VERSION 3.1) + project(ExampleProject LANGUAGES CXX) -### Embedded (FetchContent) + # If you only include this third party in PRIVATE source files, you do not need to install it + # when your main project gets installed. + set(JSON_Install OFF CACHE INTERNAL "") + + add_subdirectory(nlohmann_json) -Since CMake v3.11, -[FetchContent](https://cmake.org/cmake/help/v3.11/module/FetchContent.html) can -be used to automatically download the repository as a dependency at configure type. + add_executable(example example.cpp) + target_link_libraries(example PRIVATE nlohmann_json::nlohmann_json) + ``` -Example: -```cmake -include(FetchContent) +!!! note -FetchContent_Declare(json - GIT_REPOSITORY https://github.com/nlohmann/json - GIT_TAG v3.7.3) + Do not use `#!cmake include(nlohmann_json/CMakeLists.txt)`, since that carries with it unintended consequences that + will break the build. It is generally discouraged (although not necessarily well documented as such) to use + `#!cmake include(...)` for pulling in other CMake projects anyways. -FetchContent_GetProperties(json) -if(NOT json_POPULATED) - FetchContent_Populate(json) - add_subdirectory(${json_SOURCE_DIR} ${json_BINARY_DIR} EXCLUDE_FROM_ALL) -endif() - -target_link_libraries(foo PRIVATE nlohmann_json::nlohmann_json) -``` - -!!! Note - The repository download size is quite large. - You might want to depend on a smaller repository. For instance, you might want to replace the URL above by - . ### Supporting Both -To allow your project to support either an externally supplied or an embedded JSON library, you can use a pattern akin to the following: +To allow your project to support either an externally supplied or an embedded JSON library, you can use a pattern akin +to the following. -``` cmake -# Top level CMakeLists.txt -project(FOO) -... -option(FOO_USE_EXTERNAL_JSON "Use an external JSON library" OFF) -... -add_subdirectory(thirdparty) -... -add_library(foo ...) -... -# Note that the namespaced target will always be available regardless of the -# import method -target_link_libraries(foo PRIVATE nlohmann_json::nlohmann_json) -``` -```cmake -# thirdparty/CMakeLists.txt -... -if(FOO_USE_EXTERNAL_JSON) - find_package(nlohmann_json 3.2.0 REQUIRED) -else() - set(JSON_BuildTests OFF CACHE INTERNAL "") - add_subdirectory(nlohmann_json) -endif() -... -``` +!!! example -`thirdparty/nlohmann_json` is then a complete copy of this source tree. + ```cmake title="CMakeLists.txt" + project(ExampleProject LANGUAGES CXX) + + option(EXAMPLE_USE_EXTERNAL_JSON "Use an external JSON library" OFF) + + add_subdirectory(thirdparty) + + add_executable(example example.cpp) + + # Note that the namespaced target will always be available regardless of the import method + target_link_libraries(example PRIVATE nlohmann_json::nlohmann_json) + ``` + + ```cmake title="thirdparty/CMakeLists.txt" + if(EXAMPLE_USE_EXTERNAL_JSON) + find_package(nlohmann_json 3.10.5 REQUIRED) + else() + set(JSON_BuildTests OFF CACHE INTERNAL "") + add_subdirectory(nlohmann_json) + endif() + ``` + + `thirdparty/nlohmann_json` is then a complete copy of this source tree. + + +### FetchContent + +Since CMake v3.11, [FetchContent](https://cmake.org/cmake/help/v3.11/module/FetchContent.html) can be used to +automatically download the repository as a dependency at configure type. + +!!! example + + ```cmake title="CMakeLists.txt" + cmake_minimum_required(VERSION 3.11) + project(ExampleProject LANGUAGES CXX) + + include(FetchContent) + + FetchContent_Declare(json + GIT_REPOSITORY https://github.com/nlohmann/json + GIT_TAG v3.10.5 + ) + + FetchContent_GetProperties(json) + if(NOT json_POPULATED) + FetchContent_Populate(json) + add_subdirectory(${json_SOURCE_DIR} ${json_BINARY_DIR} EXCLUDE_FROM_ALL) + endif() + + add_executable(example example.cpp) + target_link_libraries(example PRIVATE nlohmann_json::nlohmann_json) + ``` + +!!! Note + + The repository download size is quite large. You might want to depend on a + smaller repository. For instance, you might want to replace the URL in the example by + . ## CMake Options diff --git a/doc/mkdocs/docs/integration/example.cpp b/doc/mkdocs/docs/integration/example.cpp index e5a31be4b..1a7ac4de2 100644 --- a/doc/mkdocs/docs/integration/example.cpp +++ b/doc/mkdocs/docs/integration/example.cpp @@ -1,9 +1,10 @@ #include #include +#include using json = nlohmann::json; int main() { - std::cout << json::meta() << std::endl; + std::cout << std::setw(4) << json::meta() << std::endl; } diff --git a/doc/mkdocs/docs/integration/index.md b/doc/mkdocs/docs/integration/index.md index 5ee4ff721..bfa94ae8a 100644 --- a/doc/mkdocs/docs/integration/index.md +++ b/doc/mkdocs/docs/integration/index.md @@ -1,6 +1,7 @@ # Header only -[`json.hpp`](https://github.com/nlohmann/json/blob/develop/single_include/nlohmann/json.hpp) is the single required file in `single_include/nlohmann` or [released here](https://github.com/nlohmann/json/releases). You need to add +[`json.hpp`](https://github.com/nlohmann/json/blob/develop/single_include/nlohmann/json.hpp) is the single required +file in `single_include/nlohmann` or [released here](https://github.com/nlohmann/json/releases). You need to add ```cpp #include @@ -9,6 +10,9 @@ using json = nlohmann::json; ``` -to the files you want to process JSON and set the necessary switches to enable C++11 (e.g., `-std=c++11` for GCC and Clang). +to the files you want to process JSON and set the necessary switches to enable C++11 (e.g., `-std=c++11` for GCC and +Clang). -You can further use file [`include/nlohmann/json_fwd.hpp`](https://github.com/nlohmann/json/blob/develop/include/nlohmann/json_fwd.hpp) for forward-declarations. The installation of `json_fwd.hpp` (as part of CMake's install step), can be achieved by setting `-DJSON_MultipleHeaders=ON`. +You can further use file [`include/nlohmann/json_fwd.hpp`](https://github.com/nlohmann/json/blob/develop/include/nlohmann/json_fwd.hpp) +for forward-declarations. The installation of `json_fwd.hpp` (as part of CMake's install step), can be achieved by +setting `-DJSON_MultipleHeaders=ON`. diff --git a/doc/mkdocs/docs/integration/package_managers.md b/doc/mkdocs/docs/integration/package_managers.md index d98005da9..c2fb1a7f4 100644 --- a/doc/mkdocs/docs/integration/package_managers.md +++ b/doc/mkdocs/docs/integration/package_managers.md @@ -6,6 +6,12 @@ Throughout this page, we will describe how to compile the example file `example. --8<-- "integration/example.cpp" ``` +When executed, this program should create output similar to + +```json +--8<-- "../../examples/meta.output" +``` + ## Homebrew If you are using OS X and [Homebrew](http://brew.sh), just type @@ -26,11 +32,9 @@ instead. See [nlohmann-json](https://formulae.brew.sh/formula/nlohmann-json) for 1. Create the following file: - === "example.cpp" - - ```cpp - --8<-- "integration/example.cpp" - ``` + ```cpp title="example.cpp" + --8<-- "integration/example.cpp" + ``` 2. Install the package @@ -50,6 +54,8 @@ instead. See [nlohmann-json](https://formulae.brew.sh/formula/nlohmann-json) for clang++ example.cpp -I/usr/local/Cellar/nlohmann-json/3.7.3/include -std=c++11 -o example ``` +:material-update: The [formula](https://formulae.brew.sh/formula/nlohmann-json) is updated automatically. + ## Meson If you are using the [Meson Build System](http://mesonbuild.com), add this source tree as a [meson subproject](https://mesonbuild.com/Subprojects.html#using-a-subproject). You may also use the `include.zip` published in this project's [Releases](https://github.com/nlohmann/json/releases) to reduce the size of the vendored source tree. Alternatively, you can get a wrap file by downloading it from [Meson WrapDB](https://wrapdb.mesonbuild.com/nlohmann_json), or simply use `meson wrap install nlohmann_json`. Please see the meson project for any issues regarding the packaging. @@ -64,24 +70,17 @@ If you are using [Conan](https://www.conan.io/) to manage your dependencies, mer 1. Create the following files: - === "Conanfile.txt" - - ```ini - --8<-- "integration/conan/Conanfile.txt" - ``` + ```ini title="Conanfile.txt" + --8<-- "integration/conan/Conanfile.txt" + ``` - === "CMakeLists.txt" - - ```cmake - --8<-- "integration/conan/CMakeLists.txt" - ``` - - === "example.cpp" - - ```cpp - --8<-- "integration/conan/example.cpp" - ``` + ```cmake title="CMakeLists.txt" + --8<-- "integration/conan/CMakeLists.txt" + ``` + ```cpp title="example.cpp" + --8<-- "integration/conan/example.cpp" + ``` 2. Build: @@ -93,6 +92,8 @@ If you are using [Conan](https://www.conan.io/) to manage your dependencies, mer cmake --build . ``` +:material-update: The [package](https://conan.io/center/nlohmann_json) is updated automatically. + ## Spack If you are using [Spack](https://www.spack.io/) to manage your dependencies, you can use the [`nlohmann-json` package](https://spack.readthedocs.io/en/latest/package_list.html#nlohmann-json). Please see the [spack project](https://github.com/spack/spack) for any issues regarding the packaging. @@ -113,17 +114,13 @@ If you are using [vcpkg](https://github.com/Microsoft/vcpkg/) on your project fo 1. Create the following files: - === "CMakeLists.txt" - - ```cmake - --8<-- "integration/vcpkg/CMakeLists.txt" - ``` - - === "example.cpp" - - ```cpp - --8<-- "integration/vcpkg/example.cpp" - ``` + ```cmake title="CMakeLists.txt" + --8<-- "integration/vcpkg/CMakeLists.txt" + ``` + + ```cpp title="example.cpp" + --8<-- "integration/vcpkg/example.cpp" + ``` 2. Install package: @@ -146,6 +143,8 @@ If you are using [vcpkg](https://github.com/Microsoft/vcpkg/) on your project fo If you are using [cget](http://cget.readthedocs.io/en/latest/), you can install the latest development version with `cget install nlohmann/json`. A specific version can be installed with `cget install nlohmann/json@v3.1.0`. Also, the multiple header version can be installed by adding the `-DJSON_MultipleHeaders=ON` flag (i.e., `cget install nlohmann/json -DJSON_MultipleHeaders=ON`). +:material-update: cget reads directly from the [GitHub repository](https://github.com/nlohmann/json) and is always up-to-date. + ## CocoaPods If you are using [CocoaPods](https://cocoapods.org), you can use the library by adding pod `"nlohmann_json", '~>3.1.2'` to your podfile (see [an example](https://bitbucket.org/benman/nlohmann_json-cocoapod/src/master/)). Please file issues [here](https://bitbucket.org/benman/nlohmann_json-cocoapod/issues?status=new&status=open). @@ -162,19 +161,27 @@ If you are using [conda](https://conda.io/), you can use the package [nlohmann_j If you are using [MSYS2](http://www.msys2.org/), you can use the [mingw-w64-nlohmann-json](https://packages.msys2.org/base/mingw-w64-nlohmann-json) package, just type `pacman -S mingw-w64-i686-nlohmann-json` or `pacman -S mingw-w64-x86_64-nlohmann-json` for installation. Please file issues [here](https://github.com/msys2/MINGW-packages/issues/new?title=%5Bnlohmann-json%5D) if you experience problems with the packages. +:material-update: The [package](https://packages.msys2.org/base/mingw-w64-nlohmann-json) is updated automatically. + ## MacPorts If you are using [MacPorts](https://ports.macports.org), execute `sudo port install nlohmann-json` to install the [nlohmann-json](https://ports.macports.org/port/nlohmann-json/) package. +:material-update: The [package](https://ports.macports.org/port/nlohmann-json/) is updated automatically. + ## build2 -If you are using [`build2`](https://build2.org), you can use the [`nlohmann-json`](https://cppget.org/nlohmann-json) package from the public repository http://cppget.org or directly from the [package's sources repository](https://github.com/build2-packaging/nlohmann-json). In your project's `manifest` file, just add `depends: nlohmann-json` (probably with some [version constraints](https://build2.org/build2-toolchain/doc/build2-toolchain-intro.xhtml#guide-add-remove-deps)). If you are not familiar with using dependencies in `build2`, [please read this introduction](https://build2.org/build2-toolchain/doc/build2-toolchain-intro.xhtml). +If you are using [`build2`](https://build2.org), you can use the [`nlohmann-json`](https://cppget.org/nlohmann-json) package from the public repository or directly from the [package's sources repository](https://github.com/build2-packaging/nlohmann-json). In your project's `manifest` file, just add `depends: nlohmann-json` (probably with some [version constraints](https://build2.org/build2-toolchain/doc/build2-toolchain-intro.xhtml#guide-add-remove-deps)). If you are not familiar with using dependencies in `build2`, [please read this introduction](https://build2.org/build2-toolchain/doc/build2-toolchain-intro.xhtml). Please file issues [here](https://github.com/build2-packaging/nlohmann-json) if you experience problems with the packages. +:material-update: The [package](https://cppget.org/nlohmann-json) is updated automatically. + ## wsjcpp If you are using [`wsjcpp`](http://wsjcpp.org), you can use the command `wsjcpp install "https://github.com/nlohmann/json:develop"` to get the latest version. Note you can change the branch ":develop" to an existing tag or another branch. +:material-update: wsjcpp reads directly from the [GitHub repository](https://github.com/nlohmann/json) and is always up-to-date. + ## CPM.cmake If you are using [`CPM.cmake`](https://github.com/TheLartians/CPM.cmake), you can check this [`example`](https://github.com/TheLartians/CPM.cmake/tree/master/examples/json). After [adding CPM script](https://github.com/TheLartians/CPM.cmake#adding-cpm) to your project, implement the following snippet to your CMake: From c6740d7d58a209da8960c961ee07bfb0e841e44e Mon Sep 17 00:00:00 2001 From: Niels Lohmann Date: Tue, 11 Jan 2022 21:46:40 +0100 Subject: [PATCH 02/18] :memo: add documentation for default behavior for macros --- doc/mkdocs/docs/features/macros.md | 116 ++++++++++++++++++++++++++++- 1 file changed, 112 insertions(+), 4 deletions(-) diff --git a/doc/mkdocs/docs/features/macros.md b/doc/mkdocs/docs/features/macros.md index d324a1325..d02bd8083 100644 --- a/doc/mkdocs/docs/features/macros.md +++ b/doc/mkdocs/docs/features/macros.md @@ -4,16 +4,41 @@ Some aspects of the library can be configured by defining preprocessor macros be ## `JSON_ASSERT(x)` -The default value is `#!cpp assert(x)`. +This marco controls which code is executed for runtime assertions of the libraries. + +!!! info "Default behavior" + + The default value is [`#!cpp assert(x)`](https://en.cppreference.com/w/cpp/error/assert). + + ```cpp + #define JSON_ASSERT(x) assert(x) + ``` ## `JSON_CATCH_USER(exception)` -This macro overrides `#!cpp catch` calls inside the library. The argument is the type of the exception to catch. As of -version 3.8.0, the library only catches `std::out_of_range` exceptions internally to rethrow them as -[`json::out_of_range`](../home/exceptions.md#out-of-range) exceptions. The macro is always followed by a scope. +This macro overrides [`#!cpp catch`](https://en.cppreference.com/w/cpp/language/try_catch) calls inside the library. +The argument is the type of the exception to catch. As of version 3.8.0, the library only catches `std::out_of_range` +exceptions internally to rethrow them as [`json::out_of_range`](../home/exceptions.md#out-of-range) exceptions. The +macro is always followed by a scope. See [Switch off exceptions](../home/exceptions.md#switch-off-exceptions) for an example. +!!! info "Default behavior" + + When exceptions are enabled, the default value is + [`#!cpp catch(exception)`](https://en.cppreference.com/w/cpp/language/try_catch). + + ```cpp + #define JSON_CATCH_USER(exception) catch(exception) + ``` + + When exceptions are switched off by the compiler, the default value is `#!cpp if (false)` to make the catch block + unreachable. + + ```cpp + #define JSON_CATCH_USER(exception) if (false) + ``` + ## `JSON_DIAGNOSTICS` This macro enables extended diagnostics for exception messages. Possible values are `1` to enable or `0` to disable @@ -26,6 +51,12 @@ that enabling this macro increases the size of every JSON value by one pointer a The diagnostics messages can also be controlled with the CMake option `JSON_Diagnostics` (`OFF` by default) which sets `JSON_DIAGNOSTICS` accordingly. +!!! info "Default behavior" + + ```cpp + #define JSON_DIAGNOSTICS 0 + ``` + ## `JSON_HAS_CPP_11`, `JSON_HAS_CPP_14`, `JSON_HAS_CPP_17`, `JSON_HAS_CPP_20` The library targets C++11, but also supports some features introduced in later C++ versions (e.g., `std::string_view` @@ -34,6 +65,11 @@ standard. By defining any of these symbols, the internal check is overridden and unconditionally assumed. This can be helpful for compilers that only implement parts of the standard and would be detected incorrectly. +!!! info "Default behavior" + + The default value is detected based on the preprocessor macros `#!cpp __cplusplus`, `#!cpp _HAS_CXX17`, or + `#!cpp _MSVC_LANG`. + ## `JSON_HAS_FILESYSTEM`, `JSON_HAS_EXPERIMENTAL_FILESYSTEM` When compiling with C++17, the library provides conversions from and to `std::filesystem::path`. As compiler support @@ -41,12 +77,29 @@ for filesystem is limited, the library tries to detect whether ``/`s or ``/`std::experimental::filesystem` (`JSON_HAS_EXPERIMENTAL_FILESYSTEM`) should be used. To override the built-in check, define `JSON_HAS_FILESYSTEM` or `JSON_HAS_EXPERIMENTAL_FILESYSTEM` to `1`. +!!! info "Default behavior" + + The default value is detected based on the preprocessor macros `#!cpp __cpp_lib_filesystem`, + `#!cpp __cpp_lib_experimental_filesystem`, `#!cpp __has_include()`, or + `#!cpp __has_include()`. + +Note that older compilers or older versions of libstd++ also require the library `stdc++fs` to be linked to for +filesystem support. + ## `JSON_NOEXCEPTION` Exceptions can be switched off by defining the symbol `JSON_NOEXCEPTION`. When defining `JSON_NOEXCEPTION`, `#!cpp try` is replaced by `#!cpp if (true)`, `#!cpp catch` is replaced by `#!cpp if (false)`, and `#!cpp throw` is replaced by `#!cpp std::abort()`. +!!! info "Default behavior" + + By default, the macro is not defined. + + ```cpp + #undef JSON_NOEXCEPTION + ``` + The same effect is achieved by setting the compiler flag `-fno-exceptions`. Note the explanatory [`what()`](https://en.cppreference.com/w/cpp/error/exception/what) string of exceptions is not @@ -58,23 +111,72 @@ When defined, headers ``, ``, ``, ``, and ` Date: Wed, 12 Jan 2022 21:43:22 +0100 Subject: [PATCH 03/18] Fix a typo (#3265) --- doc/mkdocs/docs/features/macros.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/mkdocs/docs/features/macros.md b/doc/mkdocs/docs/features/macros.md index d02bd8083..533a01e20 100644 --- a/doc/mkdocs/docs/features/macros.md +++ b/doc/mkdocs/docs/features/macros.md @@ -4,7 +4,7 @@ Some aspects of the library can be configured by defining preprocessor macros be ## `JSON_ASSERT(x)` -This marco controls which code is executed for runtime assertions of the libraries. +This macro controls which code is executed for runtime assertions of the libraries. !!! info "Default behavior" From b772649624c53177cbd9e89129a08609ed6d6f5a Mon Sep 17 00:00:00 2001 From: Niels Lohmann Date: Tue, 25 Jan 2022 19:53:02 +0100 Subject: [PATCH 04/18] Add maintainer targets to create source archive (#3289) * :hammer: add script to create xz archive --- Makefile | 36 ++++++++++++++++++++++-------------- 1 file changed, 22 insertions(+), 14 deletions(-) diff --git a/Makefile b/Makefile index 43db74d85..597c609cb 100644 --- a/Makefile +++ b/Makefile @@ -4,9 +4,6 @@ # configuration ########################################################################## -# directory to recent compiler binaries -COMPILER_DIR=/usr/local/opt/llvm/bin - # find GNU sed to use `-i` parameter SED:=$(shell command -v gsed || which sed) @@ -62,6 +59,7 @@ run_benchmarks: cd cmake-build-benchmarks ; ninja cd cmake-build-benchmarks ; ./json_benchmarks + ########################################################################## # fuzzing ########################################################################## @@ -135,6 +133,7 @@ pvs_studio: cd cmake-build-pvs-studio ; plog-converter -a'GA:1,2;64:1;CS' -t fullhtml PVS-Studio.log -o pvs open cmake-build-pvs-studio/pvs/index.html + ########################################################################## # Code format and source amalgamation ########################################################################## @@ -203,20 +202,29 @@ ChangeLog.md: # Release files ########################################################################## -# Create the files for a release and add signatures and hashes. We use `-X` to make the resulting ZIP file -# reproducible, see . +# Create a tar.gz archive that contains sufficient files to be used as CMake project (e.g., using FetchContent). The +# archive is created according to the advices of . +json.tar.xz: + mkdir json + rsync -R $(shell find LICENSE.MIT nlohmann_json.natvis CMakeLists.txt cmake/*.in include single_include -type f) json + gtar --sort=name --mtime="@$(shell git log -1 --pretty=%ct)" --owner=0 --group=0 --numeric-owner --pax-option=exthdr.name=%d/PaxHeaders/%f,delete=atime,delete=ctime --create --file - json | xz --compress -9e --threads=2 - > json.tar.xz + rm -fr json -release: +# We use `-X` to make the resulting ZIP file reproducible, see +# . +include.zip: + zip -9 --recurse-paths -X include.zip $(SRCS) $(AMALGAMATED_FILE) meson.build LICENSE.MIT + +# Create the files for a release and add signatures and hashes. +release: include.zip json.tar.xz rm -fr release_files mkdir release_files - zip -9 --recurse-paths -X include.zip $(SRCS) $(AMALGAMATED_FILE) meson.build LICENSE.MIT gpg --armor --detach-sig include.zip - mv include.zip include.zip.asc release_files gpg --armor --detach-sig $(AMALGAMATED_FILE) + gpg --armor --detach-sig json.tar.xz cp $(AMALGAMATED_FILE) release_files - mv $(AMALGAMATED_FILE).asc release_files - cd release_files ; shasum -a 256 json.hpp > hashes.txt - cd release_files ; shasum -a 256 include.zip >> hashes.txt + mv $(AMALGAMATED_FILE).asc json.tar.xz json.tar.xz.asc include.zip include.zip.asc release_files + cd release_files ; shasum -a 256 json.hpp include.zip json.tar.xz > hashes.txt ########################################################################## @@ -225,12 +233,12 @@ release: # clean up clean: - rm -fr json_unit json_benchmarks fuzz fuzz-testing *.dSYM test/*.dSYM oclint_report.html + rm -fr fuzz fuzz-testing *.dSYM test/*.dSYM rm -fr benchmarks/files/numbers/*.json - rm -fr cmake-3.1.0-Darwin64.tar.gz cmake-3.1.0-Darwin64 - rm -fr cmake-build-benchmarks cmake-build-pedantic fuzz-testing cmake-build-clang-analyze cmake-build-pvs-studio cmake-build-infer cmake_build + rm -fr cmake-build-benchmarks fuzz-testing cmake-build-pvs-studio release_files $(MAKE) clean -Cdoc + ########################################################################## # Thirdparty code ########################################################################## From 4d4c2730365084f2a68fb7a01110ae66fad059a3 Mon Sep 17 00:00:00 2001 From: Thomas Braun Date: Wed, 26 Jan 2022 09:57:23 +0100 Subject: [PATCH 05/18] .github/workflows/windows.yml: Add support for Visual Studio 2022 (#3295) * .github/workflows/windows.yml: Add support for Visual Studio 2022 This is available in github actions since some time now [1]. [1]: https://github.com/actions/virtual-environments/issues/3949 * README.md: Add VS 2022 [skip ci] The version and the build engine version (aka MSBuild version) were taken from [1]. [1]: https://github.com/actions/virtual-environments/blob/win22/20220116.1/images/win/Windows2022-Readme.md --- .github/workflows/windows.yml | 32 ++++++++++++++++++++++++++++++++ README.md | 2 ++ 2 files changed, 34 insertions(+) diff --git a/.github/workflows/windows.yml b/.github/workflows/windows.yml index 597da4774..9d0989a51 100644 --- a/.github/workflows/windows.yml +++ b/.github/workflows/windows.yml @@ -95,6 +95,38 @@ jobs: - name: test run: cd build ; ctest -j 10 -C Release --output-on-failure + msvc2022: + runs-on: windows-2022 + strategy: + matrix: + build_type: [Debug, Release] + architecture: [Win32, x64] + + steps: + - uses: actions/checkout@v2 + - name: cmake + run: cmake -S . -B build -G "Visual Studio 17 2022" -A ${{ matrix.architecture }} -DJSON_BuildTests=On -DCMAKE_CXX_FLAGS="/W4 /WX" + if: matrix.build_type == 'Release' + - name: cmake + run: cmake -S . -B build -G "Visual Studio 17 2022" -A ${{ matrix.architecture }} -DJSON_BuildTests=On -DJSON_FastTests=ON -DCMAKE_CXX_FLAGS="/W4 /WX" + if: matrix.build_type == 'Debug' + - name: build + run: cmake --build build --config ${{ matrix.build_type }} --parallel 10 + - name: test + run: cd build ; ctest -j 10 -C ${{ matrix.build_type }} --output-on-failure + + msvc2022_latest: + runs-on: windows-2022 + + steps: + - uses: actions/checkout@v2 + - name: cmake + run: cmake -S . -B build -G "Visual Studio 17 2022" -DJSON_BuildTests=On -DCMAKE_CXX_FLAGS="/permissive- /std:c++latest /utf-8 /W4 /WX" + - name: build + run: cmake --build build --config Release --parallel 10 + - name: test + run: cd build ; ctest -j 10 -C Release --output-on-failure + clang: runs-on: windows-latest strategy: diff --git a/README.md b/README.md index 313296323..a9a6b7d1b 100644 --- a/README.md +++ b/README.md @@ -1045,6 +1045,7 @@ Though it's 2022 already, the support for C++11 is still a bit sparse. Currently - Microsoft Visual C++ 2015 / Build Tools 14.0.25123.0 (and possibly later) - Microsoft Visual C++ 2017 / Build Tools 15.5.180.51428 (and possibly later) - Microsoft Visual C++ 2019 / Build Tools 16.3.1+1def00d3d (and possibly later) +- Microsoft Visual C++ 2022 / Build Tools 19.30.30709.0 (and possibly later) I would be happy to learn about other compilers/versions. @@ -1119,6 +1120,7 @@ The following compilers are currently used in continuous integration at [AppVeyo | Visual Studio 15 2017 MSVC 19.16.27045.0 (Build Engine version 15.9.21+g9802d43bc3 for .NET Framework) | Windows-10.0.14393 | GitHub Actions | | Visual Studio 16 2019 MSVC 19.28.29912.0 (Build Engine version 16.9.0+57a23d249 for .NET Framework) | Windows-10.0.17763 | GitHub Actions | | Visual Studio 16 2019 MSVC 19.28.29912.0 (Build Engine version 16.9.0+57a23d249 for .NET Framework) | Windows-10.0.17763 | AppVeyor | +| Visual Studio 17 2022 MSVC 19.30.30709.0 (Build Engine version 17.0.31804.368 for .NET Framework) | Windows-10.0.20348 | GitHub Actions | ## Integration From c11f98228dac03fdddc89e5991861fc306874ef9 Mon Sep 17 00:00:00 2001 From: Niels Lohmann Date: Sun, 30 Jan 2022 13:05:18 +0100 Subject: [PATCH 06/18] :memo: document FetchContent --- README.md | 12 +++++------- doc/mkdocs/docs/integration/cmake.md | 19 ++++++++++++++----- 2 files changed, 19 insertions(+), 12 deletions(-) diff --git a/README.md b/README.md index a9a6b7d1b..b8a143c15 100644 --- a/README.md +++ b/README.md @@ -1185,15 +1185,15 @@ target_link_libraries(foo PRIVATE nlohmann_json::nlohmann_json) Since CMake v3.11, [FetchContent](https://cmake.org/cmake/help/v3.11/module/FetchContent.html) can -be used to automatically download the repository as a dependency at configure time. +be used to automatically download a release as a dependency at configure time. Example: ```cmake include(FetchContent) FetchContent_Declare(json - GIT_REPOSITORY https://github.com/nlohmann/json.git - GIT_TAG v3.7.3) + URL https://github.com/nlohmann/json/releases/download/v3.10.5/json.tar.xz +) FetchContent_GetProperties(json) if(NOT json_POPULATED) @@ -1204,10 +1204,8 @@ endif() target_link_libraries(foo PRIVATE nlohmann_json::nlohmann_json) ``` -**Note**: The repository https://github.com/nlohmann/json download size is huge. -It contains all the dataset used for the benchmarks. You might want to depend on -a smaller repository. For instance, you might want to replace the URL above by -https://github.com/ArthurSonzogni/nlohmann_json_cmake_fetchcontent +**Note**: It is recommended to use the URL approach described above which is supported as of version 3.10.0. See + for more information. #### Supporting Both diff --git a/doc/mkdocs/docs/integration/cmake.md b/doc/mkdocs/docs/integration/cmake.md index 44aeb26e1..dbb8c2d66 100644 --- a/doc/mkdocs/docs/integration/cmake.md +++ b/doc/mkdocs/docs/integration/cmake.md @@ -90,7 +90,7 @@ to the following. ### FetchContent Since CMake v3.11, [FetchContent](https://cmake.org/cmake/help/v3.11/module/FetchContent.html) can be used to -automatically download the repository as a dependency at configure type. +automatically download a release as a dependency at configure type. !!! example @@ -101,8 +101,7 @@ automatically download the repository as a dependency at configure type. include(FetchContent) FetchContent_Declare(json - GIT_REPOSITORY https://github.com/nlohmann/json - GIT_TAG v3.10.5 + URL https://github.com/nlohmann/json/releases/download/v3.10.5/json.tar.xz ) FetchContent_GetProperties(json) @@ -117,8 +116,18 @@ automatically download the repository as a dependency at configure type. !!! Note - The repository download size is quite large. You might want to depend on a - smaller repository. For instance, you might want to replace the URL in the example by + It is recommended to use the URL approach described above which is supported as of version 3.10.0. It is also + possible to pass the Git repository like + + ```cmake + FetchContent_Declare(json + GIT_REPOSITORY https://github.com/nlohmann/json + GIT_TAG v3.10.5 + ) + ``` + + However, the repository download size is quite large. You might want to depend on + a smaller repository. For instance, you might want to replace the URL in the example by . ## CMake Options From eec79d4e8a306d0dc389d6ab7294478249069e51 Mon Sep 17 00:00:00 2001 From: pketelsen Date: Sun, 30 Jan 2022 22:06:50 +0100 Subject: [PATCH 07/18] Add macros NLOHMANN_DEFINE_TYPE_INTRUSIVE_WITH_DEFAULT and ..._NON_INTRUSIVE_WITH_DEFAULT (#3143) * Added new macros NLOHMANN_DEFINE_TYPE_INTRUSIVE_WITH_DEFAULT and NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE_WITH_DEFAULT. * Updated docs for NLOHMANN_DEFINE_TYPE_INTRUSIVE_WITH_DEFAULT and NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE_WITH_DEFAULT accordingly * Rephrased docs for NLOHMANN_DEFINE_TYPE_INTRUSIVE_WITH_DEFAULT and NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE_WITH_DEFAULT * Updated docs for NLOHMANN_DEFINE_TYPE_INTRUSIVE_WITH_DEFAULT and NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE_WITH_DEFAULT * Renamed default_obj in to avoid name clashes * Added test for serialization of default constructed object * Add const to getters for macro tests Co-authored-by: Chaoya Li --- doc/mkdocs/docs/features/arbitrary_types.md | 20 ++-- doc/mkdocs/docs/features/macros.md | 12 ++- include/nlohmann/detail/macro_scope.hpp | 9 ++ single_include/nlohmann/json.hpp | 9 ++ test/src/unit-udt_macro.cpp | 107 +++++++++++++++++++- 5 files changed, 145 insertions(+), 12 deletions(-) diff --git a/doc/mkdocs/docs/features/arbitrary_types.md b/doc/mkdocs/docs/features/arbitrary_types.md index fe80dc701..67e8a4554 100644 --- a/doc/mkdocs/docs/features/arbitrary_types.md +++ b/doc/mkdocs/docs/features/arbitrary_types.md @@ -85,29 +85,31 @@ Some important things: If you just want to serialize/deserialize some structs, the `to_json`/`from_json` functions can be a lot of boilerplate. -There are two macros to make your life easier as long as you (1) want to use a JSON object as serialization and (2) want to use the member variable names as object keys in that object: +There are four macros to make your life easier as long as you (1) want to use a JSON object as serialization and (2) want to use the member variable names as object keys in that object: -- `NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE(name, member1, member2, ...)` is to be defined inside the namespace of the class/struct to create code for. -- `NLOHMANN_DEFINE_TYPE_INTRUSIVE(name, member1, member2, ...)` is to be defined inside the class/struct to create code for. This macro can also access private members. +- `NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE(name, member1, member2, ...)` is to be defined inside the namespace of the class/struct to create code for. It will throw an exception in `from_json()` due to a missing value in the JSON object. +- `NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE_WITH_DEFAULT(name, member1, member2, ...)` is to be defined inside the namespace of the class/struct to create code for. It will not throw an exception in `from_json()` due to a missing value in the JSON object, but fills in values from object which is default-constructed by the type. +- `NLOHMANN_DEFINE_TYPE_INTRUSIVE(name, member1, member2, ...)` is to be defined inside the class/struct to create code for. This macro can also access private members. It will throw an exception in `from_json()` due to a missing value in the JSON object. +- `NLOHMANN_DEFINE_TYPE_INTRUSIVE_WITH_DEFAULT(name, member1, member2, ...)` is to be defined inside the class/struct to create code for. This macro can also access private members. It will not throw an exception in `from_json()` due to a missing value in the JSON object, but fills in values from object which is default-constructed by the type. -In both macros, the first parameter is the name of the class/struct, and all remaining parameters name the members. +In all macros, the first parameter is the name of the class/struct, and all remaining parameters name the members. You can read more docs about them starting from [here](macros.md#nlohmann_define_type_intrusivetype-member). !!! note - At most 64 member variables can be passed to `NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE` or `NLOHMANN_DEFINE_TYPE_INTRUSIVE`. + At most 64 member variables can be passed to these macros. ??? example The `to_json`/`from_json` functions for the `person` struct above can be created with: - + ```cpp namespace ns { NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE(person, name, address, age) } ``` - + Here is an example with private members, where `NLOHMANN_DEFINE_TYPE_INTRUSIVE` is needed: - + ```cpp namespace ns { class address { @@ -115,7 +117,7 @@ In both macros, the first parameter is the name of the class/struct, and all rem std::string street; int housenumber; int postcode; - + public: NLOHMANN_DEFINE_TYPE_INTRUSIVE(address, street, housenumber, postcode) }; diff --git a/doc/mkdocs/docs/features/macros.md b/doc/mkdocs/docs/features/macros.md index 533a01e20..3d2203e72 100644 --- a/doc/mkdocs/docs/features/macros.md +++ b/doc/mkdocs/docs/features/macros.md @@ -186,12 +186,12 @@ When defined to `0`, implicit conversions are switched off. By default, implicit ??? example This is an example for an implicit conversion: - + ```cpp json j = "Hello, world!"; std::string s = j; ``` - + When `JSON_USE_IMPLICIT_CONVERSIONS` is defined to `0`, the code above does no longer compile. Instead, it must be written like this: @@ -220,6 +220,10 @@ The first parameter is the name of the class/struct, and all remaining parameter See [Simplify your life with macros](arbitrary_types.md#simplify-your-life-with-macros) for an example. +## `NLOHMANN_DEFINE_TYPE_INTRUSIVE_WITH_DEFAULT(type, member...)` + +This macro is similar to `NLOHMANN_DEFINE_TYPE_INTRUSIVE`. It will not throw an exception in `from_json()` due to a missing value in the JSON object, but can throw due to a mismatched type. In order to support that it requires that the type be default constructible. The `from_json()` function default constructs an object and uses its values as the defaults when calling the `value()` function. + ## `NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE(type, member...)` This macro can be used to simplify the serialization/deserialization of types if (1) want to use a JSON object as @@ -231,6 +235,10 @@ first parameter is the name of the class/struct, and all remaining parameters na See [Simplify your life with macros](arbitrary_types.md#simplify-your-life-with-macros) for an example. +## `NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE_WITH_DEFAULT(type, member...)` + +This macro is similar to `NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE`. It will not throw an exception in `from_json()` due to a missing value in the JSON object, but can throw due to a mismatched type. In order to support that it requires that the type be default constructible. The `from_json()` function default constructs an object and uses its values as the defaults when calling the `value()` function. + ## `NLOHMANN_JSON_SERIALIZE_ENUM(type, ...)` This macro simplifies the serialization/deserialization of enum types. See diff --git a/include/nlohmann/detail/macro_scope.hpp b/include/nlohmann/detail/macro_scope.hpp index bcb70e911..87f964353 100644 --- a/include/nlohmann/detail/macro_scope.hpp +++ b/include/nlohmann/detail/macro_scope.hpp @@ -334,6 +334,7 @@ #define NLOHMANN_JSON_TO(v1) nlohmann_json_j[#v1] = nlohmann_json_t.v1; #define NLOHMANN_JSON_FROM(v1) nlohmann_json_j.at(#v1).get_to(nlohmann_json_t.v1); +#define NLOHMANN_JSON_FROM_WITH_DEFAULT(v1) nlohmann_json_t.v1 = nlohmann_json_j.value(#v1, nlohmann_json_default_obj.v1); /*! @brief macro @@ -344,6 +345,10 @@ friend void to_json(nlohmann::json& nlohmann_json_j, const Type& nlohmann_json_t) { NLOHMANN_JSON_EXPAND(NLOHMANN_JSON_PASTE(NLOHMANN_JSON_TO, __VA_ARGS__)) } \ friend void from_json(const nlohmann::json& nlohmann_json_j, Type& nlohmann_json_t) { NLOHMANN_JSON_EXPAND(NLOHMANN_JSON_PASTE(NLOHMANN_JSON_FROM, __VA_ARGS__)) } +#define NLOHMANN_DEFINE_TYPE_INTRUSIVE_WITH_DEFAULT(Type, ...) \ + friend void to_json(nlohmann::json& nlohmann_json_j, const Type& nlohmann_json_t) { NLOHMANN_JSON_EXPAND(NLOHMANN_JSON_PASTE(NLOHMANN_JSON_TO, __VA_ARGS__)) } \ + friend void from_json(const nlohmann::json& nlohmann_json_j, Type& nlohmann_json_t) { Type nlohmann_json_default_obj; NLOHMANN_JSON_EXPAND(NLOHMANN_JSON_PASTE(NLOHMANN_JSON_FROM_WITH_DEFAULT, __VA_ARGS__)) } + /*! @brief macro @def NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE @@ -353,6 +358,10 @@ inline void to_json(nlohmann::json& nlohmann_json_j, const Type& nlohmann_json_t) { NLOHMANN_JSON_EXPAND(NLOHMANN_JSON_PASTE(NLOHMANN_JSON_TO, __VA_ARGS__)) } \ inline void from_json(const nlohmann::json& nlohmann_json_j, Type& nlohmann_json_t) { NLOHMANN_JSON_EXPAND(NLOHMANN_JSON_PASTE(NLOHMANN_JSON_FROM, __VA_ARGS__)) } +#define NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE_WITH_DEFAULT(Type, ...) \ + inline void to_json(nlohmann::json& nlohmann_json_j, const Type& nlohmann_json_t) { NLOHMANN_JSON_EXPAND(NLOHMANN_JSON_PASTE(NLOHMANN_JSON_TO, __VA_ARGS__)) } \ + inline void from_json(const nlohmann::json& nlohmann_json_j, Type& nlohmann_json_t) { Type nlohmann_json_default_obj; NLOHMANN_JSON_EXPAND(NLOHMANN_JSON_PASTE(NLOHMANN_JSON_FROM_WITH_DEFAULT, __VA_ARGS__)) } + // inspired from https://stackoverflow.com/a/26745591 // allows to call any std function as if (e.g. with begin): diff --git a/single_include/nlohmann/json.hpp b/single_include/nlohmann/json.hpp index 92308c557..e40e3b05b 100644 --- a/single_include/nlohmann/json.hpp +++ b/single_include/nlohmann/json.hpp @@ -2631,6 +2631,7 @@ using is_detected_convertible = #define NLOHMANN_JSON_TO(v1) nlohmann_json_j[#v1] = nlohmann_json_t.v1; #define NLOHMANN_JSON_FROM(v1) nlohmann_json_j.at(#v1).get_to(nlohmann_json_t.v1); +#define NLOHMANN_JSON_FROM_WITH_DEFAULT(v1) nlohmann_json_t.v1 = nlohmann_json_j.value(#v1, nlohmann_json_default_obj.v1); /*! @brief macro @@ -2641,6 +2642,10 @@ using is_detected_convertible = friend void to_json(nlohmann::json& nlohmann_json_j, const Type& nlohmann_json_t) { NLOHMANN_JSON_EXPAND(NLOHMANN_JSON_PASTE(NLOHMANN_JSON_TO, __VA_ARGS__)) } \ friend void from_json(const nlohmann::json& nlohmann_json_j, Type& nlohmann_json_t) { NLOHMANN_JSON_EXPAND(NLOHMANN_JSON_PASTE(NLOHMANN_JSON_FROM, __VA_ARGS__)) } +#define NLOHMANN_DEFINE_TYPE_INTRUSIVE_WITH_DEFAULT(Type, ...) \ + friend void to_json(nlohmann::json& nlohmann_json_j, const Type& nlohmann_json_t) { NLOHMANN_JSON_EXPAND(NLOHMANN_JSON_PASTE(NLOHMANN_JSON_TO, __VA_ARGS__)) } \ + friend void from_json(const nlohmann::json& nlohmann_json_j, Type& nlohmann_json_t) { Type nlohmann_json_default_obj; NLOHMANN_JSON_EXPAND(NLOHMANN_JSON_PASTE(NLOHMANN_JSON_FROM_WITH_DEFAULT, __VA_ARGS__)) } + /*! @brief macro @def NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE @@ -2650,6 +2655,10 @@ using is_detected_convertible = inline void to_json(nlohmann::json& nlohmann_json_j, const Type& nlohmann_json_t) { NLOHMANN_JSON_EXPAND(NLOHMANN_JSON_PASTE(NLOHMANN_JSON_TO, __VA_ARGS__)) } \ inline void from_json(const nlohmann::json& nlohmann_json_j, Type& nlohmann_json_t) { NLOHMANN_JSON_EXPAND(NLOHMANN_JSON_PASTE(NLOHMANN_JSON_FROM, __VA_ARGS__)) } +#define NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE_WITH_DEFAULT(Type, ...) \ + inline void to_json(nlohmann::json& nlohmann_json_j, const Type& nlohmann_json_t) { NLOHMANN_JSON_EXPAND(NLOHMANN_JSON_PASTE(NLOHMANN_JSON_TO, __VA_ARGS__)) } \ + inline void from_json(const nlohmann::json& nlohmann_json_j, Type& nlohmann_json_t) { Type nlohmann_json_default_obj; NLOHMANN_JSON_EXPAND(NLOHMANN_JSON_PASTE(NLOHMANN_JSON_FROM_WITH_DEFAULT, __VA_ARGS__)) } + // inspired from https://stackoverflow.com/a/26745591 // allows to call any std function as if (e.g. with begin): diff --git a/test/src/unit-udt_macro.cpp b/test/src/unit-udt_macro.cpp index 5aef22797..1762d08da 100644 --- a/test/src/unit-udt_macro.cpp +++ b/test/src/unit-udt_macro.cpp @@ -59,6 +59,42 @@ class person_with_private_data NLOHMANN_DEFINE_TYPE_INTRUSIVE(person_with_private_data, age, name, metadata) }; +class person_with_private_data_2 +{ + private: + std::string name{}; + int age = 0; + json metadata = nullptr; + + public: + bool operator==(const person_with_private_data_2& rhs) const + { + return name == rhs.name && age == rhs.age && metadata == rhs.metadata; + } + + person_with_private_data_2() = default; + person_with_private_data_2(std::string name_, int age_, json metadata_) + : name(std::move(name_)) + , age(age_) + , metadata(std::move(metadata_)) + {} + + std::string getName() const + { + return name; + } + int getAge() const + { + return age; + } + json getMetadata() const + { + return metadata; + } + + NLOHMANN_DEFINE_TYPE_INTRUSIVE_WITH_DEFAULT(person_with_private_data_2, age, name, metadata) +}; + class person_without_private_data_1 { public: @@ -103,6 +139,41 @@ class person_without_private_data_2 NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE(person_without_private_data_2, age, name, metadata) +class person_without_private_data_3 +{ + public: + std::string name{}; + int age = 0; + json metadata = nullptr; + + bool operator==(const person_without_private_data_3& rhs) const + { + return name == rhs.name && age == rhs.age && metadata == rhs.metadata; + } + + person_without_private_data_3() = default; + person_without_private_data_3(std::string name_, int age_, json metadata_) + : name(std::move(name_)) + , age(age_) + , metadata(std::move(metadata_)) + {} + + std::string getName() const + { + return name; + } + int getAge() const + { + return age; + } + json getMetadata() const + { + return metadata; + } +}; + +NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE_WITH_DEFAULT(person_without_private_data_3, age, name, metadata) + class person_with_private_alphabet { public: @@ -231,7 +302,7 @@ NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE(person_with_public_alphabet, a, b, c, d, e, f } // namespace persons -TEST_CASE_TEMPLATE("Serialization/deserialization via NLOHMANN_DEFINE_TYPE_INTRUSIVE", T, +TEST_CASE_TEMPLATE("Serialization/deserialization via NLOHMANN_DEFINE_TYPE_INTRUSIVE and NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE", T, persons::person_with_private_data, persons::person_without_private_data_1, persons::person_without_private_data_2) @@ -257,6 +328,40 @@ TEST_CASE_TEMPLATE("Serialization/deserialization via NLOHMANN_DEFINE_TYPE_INTRU } } +TEST_CASE_TEMPLATE("Serialization/deserialization via NLOHMANN_DEFINE_TYPE_INTRUSIVE_WITH_DEFAULT and NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE_WITH_DEFAULT", T, + persons::person_with_private_data_2, + persons::person_without_private_data_3) +{ + SECTION("person with default values") + { + // serialization of default constructed object + T p0; + CHECK(json(p0).dump() == "{\"age\":0,\"metadata\":null,\"name\":\"\"}"); + + // serialization + T p1("Erik", 1, {{"haircuts", 2}}); + CHECK(json(p1).dump() == "{\"age\":1,\"metadata\":{\"haircuts\":2},\"name\":\"Erik\"}"); + + // deserialization + auto p2 = json(p1).get(); + CHECK(p2 == p1); + + // roundtrip + CHECK(T(json(p1)) == p1); + CHECK(json(T(json(p1))) == json(p1)); + + // check default value in case of missing field + json j = json(p1); + j.erase("name"); + j.erase("age"); + j.erase("metadata"); + T p3 = j.get(); + CHECK(p3.getName() == ""); + CHECK(p3.getAge() == 0); + CHECK(p3.getMetadata() == nullptr); + } +} + TEST_CASE_TEMPLATE("Serialization/deserialization of classes with 26 public/private member variables via NLOHMANN_DEFINE_TYPE_INTRUSIVE and NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE", T, persons::person_with_private_alphabet, persons::person_with_public_alphabet) From eb2182414749825be086c825edb5229e5c28503d Mon Sep 17 00:00:00 2001 From: Niels Lohmann Date: Tue, 8 Feb 2022 22:12:49 +0100 Subject: [PATCH 08/18] :memo: replace Doxygen links --- README.md | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index b8a143c15..89676cf37 100644 --- a/README.md +++ b/README.md @@ -10,7 +10,7 @@ [![Language grade: C/C++](https://img.shields.io/lgtm/grade/cpp/g/nlohmann/json.svg?logo=lgtm&logoWidth=18)](https://lgtm.com/projects/g/nlohmann/json/context:cpp) [![Fuzzing Status](https://oss-fuzz-build-logs.storage.googleapis.com/badges/json.svg)](https://bugs.chromium.org/p/oss-fuzz/issues/list?sort=-opened&can=1&q=proj:json) [![Try online](https://img.shields.io/badge/try-online-blue.svg)](https://wandbox.org/permlink/1mp10JbaANo6FUc7) -[![Documentation](https://img.shields.io/badge/docs-doxygen-blue.svg)](https://nlohmann.github.io/json/doxygen/index.html) +[![Documentation](https://img.shields.io/badge/docs-mkdocs-blue.svg)](https://json.nlohmann.me) [![GitHub license](https://img.shields.io/badge/license-MIT-blue.svg)](https://raw.githubusercontent.com/nlohmann/json/master/LICENSE.MIT) [![GitHub Releases](https://img.shields.io/github/release/nlohmann/json.svg)](https://github.com/nlohmann/json/releases) [![GitHub Downloads](https://img.shields.io/github/downloads/nlohmann/json/total)](https://github.com/nlohmann/json/releases) @@ -85,7 +85,7 @@ Thanks everyone! :books: If you want to **learn more** about how to use the library, check out the rest of the [**README**](#examples), have a look at [**code examples**](https://github.com/nlohmann/json/tree/develop/doc/examples), or browse through the [**help pages**](https://json.nlohmann.me). -:construction: If you want to understand the **API** better, check out the [**API Reference**](https://json.nlohmann.me/api/basic_json/) or the [**Doxygen documentation**](https://json.nlohmann.me/doxygen/index.html). +:construction: If you want to understand the **API** better, check out the [**API Reference**](https://json.nlohmann.me/api/basic_json/). :bug: If you found a **bug**, please check the [**FAQ**](https://json.nlohmann.me/home/faq/) if it is a known issue or the result of a design decision. Please also have a look at the [**issue list**](https://github.com/nlohmann/json/issues) before you [**create a new issue**](https://github.com/nlohmann/json/issues/new/choose). Please provide as much information as possible to help us understand and reproduce your issue. @@ -1624,13 +1624,14 @@ The library itself consists of a single header file licensed under the MIT licen - [**Coverity Scan**](https://scan.coverity.com) for [static analysis](https://scan.coverity.com/projects/nlohmann-json) - [**cppcheck**](http://cppcheck.sourceforge.net) for static analysis - [**doctest**](https://github.com/onqtam/doctest) for the unit tests -- [**Doxygen**](https://www.doxygen.nl/index.html) to generate [documentation](https://nlohmann.github.io/json/doxygen/index.html) - [**git-update-ghpages**](https://github.com/rstacruz/git-update-ghpages) to upload the documentation to gh-pages - [**GitHub Changelog Generator**](https://github.com/skywinder/github-changelog-generator) to generate the [ChangeLog](https://github.com/nlohmann/json/blob/develop/ChangeLog.md) - [**Google Benchmark**](https://github.com/google/benchmark) to implement the benchmarks - [**Hedley**](https://nemequ.github.io/hedley/) to avoid re-inventing several compiler-agnostic feature macros - [**lcov**](http://ltp.sourceforge.net/coverage/lcov.php) to process coverage information and create an HTML view - [**libFuzzer**](https://llvm.org/docs/LibFuzzer.html) to implement fuzz testing for OSS-Fuzz +- [**Material for MkDocs**](https://squidfunk.github.io/mkdocs-material/) for the style of the documentation site +- [**MkDocs**](https://www.mkdocs.org) for the documentation site - [**OSS-Fuzz**](https://github.com/google/oss-fuzz) for continuous fuzz testing of the library ([project repository](https://github.com/google/oss-fuzz/tree/master/projects/json)) - [**Probot**](https://probot.github.io) for automating maintainer tasks such as closing stale issues, requesting missing information, or detecting toxic comments. - [**Valgrind**](https://valgrind.org) to check for correct memory management From d8a63291cbe50411a2c513d06f3ae7c8c1a43c33 Mon Sep 17 00:00:00 2001 From: Niels Lohmann Date: Sat, 12 Feb 2022 15:45:51 +0100 Subject: [PATCH 09/18] :memo: add note on parsing ordered_json #3325 (#3326) --- doc/mkdocs/docs/features/object_order.md | 59 ++++++++++++++++++++++++ 1 file changed, 59 insertions(+) diff --git a/doc/mkdocs/docs/features/object_order.md b/doc/mkdocs/docs/features/object_order.md index 86bb253ba..0768f8020 100644 --- a/doc/mkdocs/docs/features/object_order.md +++ b/doc/mkdocs/docs/features/object_order.md @@ -2,6 +2,8 @@ The [JSON standard](https://tools.ietf.org/html/rfc8259.html) defines objects as "an unordered collection of zero or more name/value pairs". As such, an implementation does not need to preserve any specific order of object keys. +## Default behavior: sort keys + The default type `nlohmann::json` uses a `std::map` to store JSON objects, and thus stores object keys **sorted alphabetically**. ??? example @@ -33,6 +35,8 @@ The default type `nlohmann::json` uses a `std::map` to store JSON objects, and t } ``` +## Alternative behavior: preserve insertion order + If you do want to preserve the **insertion order**, you can try the type [`nlohmann::ordered_json`](https://github.com/nlohmann/json/issues/2179). ??? example @@ -65,3 +69,58 @@ If you do want to preserve the **insertion order**, you can try the type [`nlohm ``` Alternatively, you can use a more sophisticated ordered map like [`tsl::ordered_map`](https://github.com/Tessil/ordered-map) ([integration](https://github.com/nlohmann/json/issues/546#issuecomment-304447518)) or [`nlohmann::fifo_map`](https://github.com/nlohmann/fifo_map) ([integration](https://github.com/nlohmann/json/issues/485#issuecomment-333652309)). + +### Notes on parsing + +Note that you also need to call the right [`parse`](../api/basic_json/parse.md) function when reading from a file. +Assume file `input.json` contains the JSON object above: + +```json +{ + "one": 1, + "two": 2, + "three": 3 +} +``` + +!!! success "Right way" + + The following code correctly calls the `parse` function from `nlohmann::ordered_json`: + + ```cpp + std::ifstream i("input.json"); + auto j = nlohmann::ordered_json::parse(i); + std::cout << j.dump(2) << std::endl; + ``` + + The output will be: + + ```json + { + "one": 1, + "two": 2, + "three": 3 + } + ``` + +??? failure "Wrong way" + + The following code incorrectly calls the `parse` function from `nlohmann::json` which does not preserve the + insertion order, but sorts object keys. Assigning the result to `nlohmann::ordered_json` compiles, but does not + restore the order from the input file. + + ```cpp + std::ifstream i("input.json"); + nlohmann::ordered_json j = nlohmann::json::parse(i); + std::cout << j.dump(2) << std::endl; + ``` + + The output will be: + + ```json + { + "one": 1, + "three": 3 + "two": 2, + } + ``` From e4643d1f1b03fc7a1d7b65f17e012ca93680cad8 Mon Sep 17 00:00:00 2001 From: Faruk D <144492+fdiblen@users.noreply.github.com> Date: Fri, 18 Feb 2022 18:11:44 +0100 Subject: [PATCH 10/18] Fix CITATION.cff and add automatic validation of your citation metadata (#3320) * Update CITATION.cff cffversion to 1.2.0 * Fix CITATION.cff date-released Co-authored-by: Abel Soares Siqueira --- CITATION.cff | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/CITATION.cff b/CITATION.cff index 7c28d04fd..40a1d26a2 100644 --- a/CITATION.cff +++ b/CITATION.cff @@ -1,6 +1,6 @@ -cff-version: 1.1.0 +cff-version: 1.2.0 message: "If you use this software, please cite it as below." -authors: +authors: - family-names: Lohmann given-names: Niels orcid: https://orcid.org/0000-0001-9037-795X @@ -8,7 +8,7 @@ authors: website: https://nlohmann.me title: "JSON for Modern C++" version: 3.10.5 -date-released: 2022 +date-released: 2022-01-03 license: MIT repository-code: "https://github.com/nlohmann" url: https://json.nlohmann.me From d1e57df48ba72083697d45720a3a0bec227e0f5e Mon Sep 17 00:00:00 2001 From: Florian Albrechtskirchinger Date: Sun, 6 Mar 2022 13:54:00 +0100 Subject: [PATCH 11/18] Fix and update CI (#3368) * CI: add workflow_dispatch trigger * CI: change msvc2019*/clang* runners to windows-2019 GitHub updated their runners. windows-latest is now based on Windows Server 2022 and comes with different tool versions. MSVC 2019 is still available via the windows-2019 runner. --- .github/workflows/codeql-analysis.yml | 1 + .github/workflows/macos.yml | 1 + .github/workflows/ubuntu.yml | 1 + .github/workflows/windows.yml | 9 +++++---- 4 files changed, 8 insertions(+), 4 deletions(-) diff --git a/.github/workflows/codeql-analysis.yml b/.github/workflows/codeql-analysis.yml index 20275feac..01b333497 100644 --- a/.github/workflows/codeql-analysis.yml +++ b/.github/workflows/codeql-analysis.yml @@ -9,6 +9,7 @@ on: pull_request: schedule: - cron: '0 19 * * 1' + workflow_dispatch: jobs: CodeQL-Build: diff --git a/.github/workflows/macos.yml b/.github/workflows/macos.yml index f653e2b6b..6a378f13f 100644 --- a/.github/workflows/macos.yml +++ b/.github/workflows/macos.yml @@ -7,6 +7,7 @@ on: - master - release/* pull_request: + workflow_dispatch: jobs: xcode: diff --git a/.github/workflows/ubuntu.yml b/.github/workflows/ubuntu.yml index eb544007e..634545a4f 100644 --- a/.github/workflows/ubuntu.yml +++ b/.github/workflows/ubuntu.yml @@ -7,6 +7,7 @@ on: - master - release/* pull_request: + workflow_dispatch: jobs: ci_test_clang: diff --git a/.github/workflows/windows.yml b/.github/workflows/windows.yml index 9d0989a51..e8ca95d51 100644 --- a/.github/workflows/windows.yml +++ b/.github/workflows/windows.yml @@ -7,6 +7,7 @@ on: - master - release/* pull_request: + workflow_dispatch: jobs: mingw: @@ -64,7 +65,7 @@ jobs: run: cd build ; ctest -j 10 -C Release --output-on-failure msvc2019: - runs-on: windows-latest + runs-on: windows-2019 strategy: matrix: build_type: [Debug, Release] @@ -84,7 +85,7 @@ jobs: run: cd build ; ctest -j 10 -C ${{ matrix.build_type }} --output-on-failure msvc2019_latest: - runs-on: windows-latest + runs-on: windows-2019 steps: - uses: actions/checkout@v2 @@ -128,7 +129,7 @@ jobs: run: cd build ; ctest -j 10 -C Release --output-on-failure clang: - runs-on: windows-latest + runs-on: windows-2019 strategy: matrix: version: [11, 12] @@ -145,7 +146,7 @@ jobs: run: cd build ; ctest -j 10 -C Debug --exclude-regex "test-unicode" --output-on-failure clang-cl-11: - runs-on: windows-latest + runs-on: windows-2019 strategy: matrix: architecture: [Win32, x64] From c6d8892e5d1bac2803b53063fe3e3c23efe46574 Mon Sep 17 00:00:00 2001 From: Niels Lohmann Date: Sun, 6 Mar 2022 15:33:05 +0100 Subject: [PATCH 12/18] FetchContent_MakeAvailable (#3351) * :wrench: use FetchContent_MakeAvailable * :green_heart: fix test names --- README.md | 11 ++-------- doc/mkdocs/docs/integration/cmake.md | 11 ++-------- test/CMakeLists.txt | 1 + test/cmake_fetch_content2/CMakeLists.txt | 20 +++++++++++++++++++ .../project/CMakeLists.txt | 15 ++++++++++++++ test/cmake_fetch_content2/project/main.cpp | 8 ++++++++ 6 files changed, 48 insertions(+), 18 deletions(-) create mode 100644 test/cmake_fetch_content2/CMakeLists.txt create mode 100644 test/cmake_fetch_content2/project/CMakeLists.txt create mode 100644 test/cmake_fetch_content2/project/main.cpp diff --git a/README.md b/README.md index 89676cf37..c6babb64e 100644 --- a/README.md +++ b/README.md @@ -1191,15 +1191,8 @@ Example: ```cmake include(FetchContent) -FetchContent_Declare(json - URL https://github.com/nlohmann/json/releases/download/v3.10.5/json.tar.xz -) - -FetchContent_GetProperties(json) -if(NOT json_POPULATED) - FetchContent_Populate(json) - add_subdirectory(${json_SOURCE_DIR} ${json_BINARY_DIR} EXCLUDE_FROM_ALL) -endif() +FetchContent_Declare(json URL https://github.com/nlohmann/json/releases/download/v3.10.5/json.tar.xz) +FetchContent_MakeAvailable(json) target_link_libraries(foo PRIVATE nlohmann_json::nlohmann_json) ``` diff --git a/doc/mkdocs/docs/integration/cmake.md b/doc/mkdocs/docs/integration/cmake.md index dbb8c2d66..2247ba009 100644 --- a/doc/mkdocs/docs/integration/cmake.md +++ b/doc/mkdocs/docs/integration/cmake.md @@ -100,15 +100,8 @@ automatically download a release as a dependency at configure type. include(FetchContent) - FetchContent_Declare(json - URL https://github.com/nlohmann/json/releases/download/v3.10.5/json.tar.xz - ) - - FetchContent_GetProperties(json) - if(NOT json_POPULATED) - FetchContent_Populate(json) - add_subdirectory(${json_SOURCE_DIR} ${json_BINARY_DIR} EXCLUDE_FROM_ALL) - endif() + FetchContent_Declare(json URL https://github.com/nlohmann/json/releases/download/v3.10.5/json.tar.xz) + FetchContent_MakeAvailable(json) add_executable(example example.cpp) target_link_libraries(example PRIVATE nlohmann_json::nlohmann_json) diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index 4c741f274..c29662134 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -170,4 +170,5 @@ endif() add_subdirectory(cmake_add_subdirectory) add_subdirectory(cmake_fetch_content) +add_subdirectory(cmake_fetch_content2) add_subdirectory(cmake_target_include_directories) diff --git a/test/cmake_fetch_content2/CMakeLists.txt b/test/cmake_fetch_content2/CMakeLists.txt new file mode 100644 index 000000000..40e75e832 --- /dev/null +++ b/test/cmake_fetch_content2/CMakeLists.txt @@ -0,0 +1,20 @@ +if (${CMAKE_VERSION} VERSION_GREATER "3.14.0") + add_test(NAME cmake_fetch_content2_configure + COMMAND ${CMAKE_COMMAND} + -G "${CMAKE_GENERATOR}" + -DCMAKE_CXX_COMPILER=${CMAKE_CXX_COMPILER} + -Dnlohmann_json_source=${PROJECT_SOURCE_DIR} + ${CMAKE_CURRENT_SOURCE_DIR}/project + ) + add_test(NAME cmake_fetch_content2_build + COMMAND ${CMAKE_COMMAND} --build . + ) + set_tests_properties(cmake_fetch_content2_configure PROPERTIES + FIXTURES_SETUP cmake_fetch_content2 + LABELS "git_required;not_reproducible" + ) + set_tests_properties(cmake_fetch_content2_build PROPERTIES + FIXTURES_REQUIRED cmake_fetch_content2 + LABELS "git_required;not_reproducible" + ) +endif() diff --git a/test/cmake_fetch_content2/project/CMakeLists.txt b/test/cmake_fetch_content2/project/CMakeLists.txt new file mode 100644 index 000000000..734b9cc0e --- /dev/null +++ b/test/cmake_fetch_content2/project/CMakeLists.txt @@ -0,0 +1,15 @@ +cmake_minimum_required(VERSION 3.14) + +project(DummyImport CXX) + +include(FetchContent) + +get_filename_component(GIT_REPOSITORY_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/../../.. ABSOLUTE) +FetchContent_Declare(json GIT_REPOSITORY ${GIT_REPOSITORY_DIRECTORY} GIT_TAG HEAD) +FetchContent_MakeAvailable(json) + +add_executable(with_namespace_target main.cpp) +target_link_libraries(with_namespace_target nlohmann_json::nlohmann_json) + +add_executable(without_namespace_target main.cpp) +target_link_libraries(without_namespace_target nlohmann_json) diff --git a/test/cmake_fetch_content2/project/main.cpp b/test/cmake_fetch_content2/project/main.cpp new file mode 100644 index 000000000..d2d118b85 --- /dev/null +++ b/test/cmake_fetch_content2/project/main.cpp @@ -0,0 +1,8 @@ +#include + +int main(int argc, char **argv) +{ + nlohmann::json j; + + return 0; +} From 0fd95d2e28dd739434ab3733d5bf86b2ff942035 Mon Sep 17 00:00:00 2001 From: Florian Albrechtskirchinger Date: Mon, 7 Mar 2022 13:41:35 +0100 Subject: [PATCH 13/18] Fix ordered_map ctor with initializer_list (#3370) One of the ordered_map constructors was incorrectly accepting a std::initializer_list instead of std::initializer_list. Add regression test. Fixes #3343. --- include/nlohmann/ordered_map.hpp | 2 +- single_include/nlohmann/json.hpp | 2 +- test/src/unit-regression2.cpp | 12 ++++++++++++ 3 files changed, 14 insertions(+), 2 deletions(-) diff --git a/include/nlohmann/ordered_map.hpp b/include/nlohmann/ordered_map.hpp index bfcf89a40..709bc5fd5 100644 --- a/include/nlohmann/ordered_map.hpp +++ b/include/nlohmann/ordered_map.hpp @@ -34,7 +34,7 @@ template , template ordered_map(It first, It last, const Allocator& alloc = Allocator()) : Container{first, last, alloc} {} - ordered_map(std::initializer_list init, const Allocator& alloc = Allocator() ) + ordered_map(std::initializer_list init, const Allocator& alloc = Allocator() ) : Container{init, alloc} {} std::pair emplace(const key_type& key, T&& t) diff --git a/single_include/nlohmann/json.hpp b/single_include/nlohmann/json.hpp index e40e3b05b..ec33a847a 100644 --- a/single_include/nlohmann/json.hpp +++ b/single_include/nlohmann/json.hpp @@ -17070,7 +17070,7 @@ template , template ordered_map(It first, It last, const Allocator& alloc = Allocator()) : Container{first, last, alloc} {} - ordered_map(std::initializer_list init, const Allocator& alloc = Allocator() ) + ordered_map(std::initializer_list init, const Allocator& alloc = Allocator() ) : Container{init, alloc} {} std::pair emplace(const key_type& key, T&& t) diff --git a/test/src/unit-regression2.cpp b/test/src/unit-regression2.cpp index 52db3589c..6249db63e 100644 --- a/test/src/unit-regression2.cpp +++ b/test/src/unit-regression2.cpp @@ -835,6 +835,18 @@ TEST_CASE("regression tests 2") CHECK(j.dump() == "[1,4]"); } + + SECTION("issue #3343 - json and ordered_json are not interchangable") + { + json::object_t jobj({ { "product", "one" } }); + ordered_json::object_t ojobj({{"product", "one"}}); + + auto jit = jobj.begin(); + auto ojit = ojobj.begin(); + + CHECK(jit->first == ojit->first); + CHECK(jit->second.get() == ojit->second.get()); + } } DOCTEST_CLANG_SUPPRESS_WARNING_POP From 8d7b5b6a287b08af3a495c36ad97ce8a4a899930 Mon Sep 17 00:00:00 2001 From: Andrea Cocito <39852324+puffetto@users.noreply.github.com> Date: Mon, 7 Mar 2022 13:43:50 +0100 Subject: [PATCH 14/18] Add clarification to avoid misunderstanding that cause #3360 (#3378) * Update macros.md Typos, typos --- doc/mkdocs/docs/features/macros.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/doc/mkdocs/docs/features/macros.md b/doc/mkdocs/docs/features/macros.md index 3d2203e72..cade9d5bc 100644 --- a/doc/mkdocs/docs/features/macros.md +++ b/doc/mkdocs/docs/features/macros.md @@ -51,6 +51,8 @@ that enabling this macro increases the size of every JSON value by one pointer a The diagnostics messages can also be controlled with the CMake option `JSON_Diagnostics` (`OFF` by default) which sets `JSON_DIAGNOSTICS` accordingly. +WARNING: As this macro changes the definition of the json object, it MUST be defined in the same way globally, even across different compilation units; do NOT link together code compiled with and without JSON_DIAGNOSTICS defined as this is a violation of the One Definition Rule and will cause undefined behaviour. + !!! info "Default behavior" ```cpp From 4a6e6ca8c7a63802fb15d95ee8aafff310e3a6de Mon Sep 17 00:00:00 2001 From: Niels Lohmann Date: Mon, 7 Mar 2022 13:48:24 +0100 Subject: [PATCH 15/18] :memo: update documentation --- doc/mkdocs/docs/features/macros.md | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/doc/mkdocs/docs/features/macros.md b/doc/mkdocs/docs/features/macros.md index cade9d5bc..9994c5dcd 100644 --- a/doc/mkdocs/docs/features/macros.md +++ b/doc/mkdocs/docs/features/macros.md @@ -51,7 +51,11 @@ that enabling this macro increases the size of every JSON value by one pointer a The diagnostics messages can also be controlled with the CMake option `JSON_Diagnostics` (`OFF` by default) which sets `JSON_DIAGNOSTICS` accordingly. -WARNING: As this macro changes the definition of the json object, it MUST be defined in the same way globally, even across different compilation units; do NOT link together code compiled with and without JSON_DIAGNOSTICS defined as this is a violation of the One Definition Rule and will cause undefined behaviour. +!!! warning + + As this macro changes the definition of the `basic_json` object, it MUST be defined in the same way globally, even + across different compilation units; DO NOT link together code compiled with different definitions of + `JSON_DIAGNOSTICS` as this is a violation of the One Definition Rule and will cause undefined behaviour. !!! info "Default behavior" From f208a9c19b6c158826aa00b6d0642be29104c18a Mon Sep 17 00:00:00 2001 From: Florian Albrechtskirchinger Date: Mon, 7 Mar 2022 22:19:28 +0100 Subject: [PATCH 16/18] Fix C++20/gcc-12 issues (Part 1) (#3379) * :wrench: use proper GCC binary * :wrench: add more GCC warning flags * :alembic: try fix from https://github.com/nlohmann/json/issues/3138#issuecomment-1015562666 * Fix custom allocator test build failures (C++20) Allocator tests fail to compile in C++20 mode with clang+MS STL due to missing copy constructors. * Fix test build failures due to missing noexcept (gcc-12) * alt_string has multiple member functions that should be marked noexcept. * nlohmann::ordered_map constructors can be noexcept. Compilation failures result from the warning flag -Werror=noexcept and gcc-12. * Disable broken comparison tests in C++20 mode Co-authored-by: Niels Lohmann --- cmake/ci.cmake | 27 ++++++++++++++++++++------- include/nlohmann/json.hpp | 1 + include/nlohmann/ordered_map.hpp | 3 ++- single_include/nlohmann/json.hpp | 4 +++- test/src/unit-allocator.cpp | 2 ++ test/src/unit-alt-string.cpp | 4 ++-- test/src/unit-comparison.cpp | 12 ++++++++++++ test/src/unit-regression2.cpp | 7 +++++-- 8 files changed, 47 insertions(+), 13 deletions(-) diff --git a/cmake/ci.cmake b/cmake/ci.cmake index d0b989c80..9a8136165 100644 --- a/cmake/ci.cmake +++ b/cmake/ci.cmake @@ -30,7 +30,7 @@ execute_process(COMMAND ${CPPCHECK_TOOL} --version OUTPUT_VARIABLE CPPCHECK_TOOL string(REGEX MATCH "[0-9]+(\\.[0-9]+)+" CPPCHECK_TOOL_VERSION "${CPPCHECK_TOOL_VERSION}") message(STATUS "🔖 Cppcheck ${CPPCHECK_TOOL_VERSION} (${CPPCHECK_TOOL})") -find_program(GCC_TOOL NAMES g++-HEAD g++-11 g++-latest) +find_program(GCC_TOOL NAMES g++-latest g++-HEAD g++-11) execute_process(COMMAND ${GCC_TOOL} --version OUTPUT_VARIABLE GCC_TOOL_VERSION ERROR_VARIABLE GCC_TOOL_VERSION) string(REGEX MATCH "[0-9]+(\\.[0-9]+)+" GCC_TOOL_VERSION "${GCC_TOOL_VERSION}") message(STATUS "🔖 GCC ${GCC_TOOL_VERSION} (${GCC_TOOL})") @@ -111,6 +111,7 @@ set(CLANG_CXXFLAGS "-std=c++11 \ -Wno-reserved-identifier \ ") +# Warning flags determined for GCC 12.0 (experimental) with https://github.com/nlohmann/gcc_flags: # Ignored GCC warnings: # -Wno-abi-tag We do not care about ABI tags. # -Wno-aggregate-return The library uses aggregate returns. @@ -150,16 +151,22 @@ set(GCC_CXXFLAGS "-std=c++11 \ -Wanalyzer-shift-count-negative \ -Wanalyzer-shift-count-overflow \ -Wanalyzer-stale-setjmp-buffer \ + -Wanalyzer-tainted-allocation-size \ -Wanalyzer-tainted-array-index \ + -Wanalyzer-tainted-divisor \ + -Wanalyzer-tainted-offset \ + -Wanalyzer-tainted-size \ -Wanalyzer-too-complex \ -Wanalyzer-unsafe-call-within-signal-handler \ -Wanalyzer-use-after-free \ -Wanalyzer-use-of-pointer-in-stale-stack-frame \ + -Wanalyzer-use-of-uninitialized-value \ -Wanalyzer-write-to-const \ -Wanalyzer-write-to-string-literal \ -Warith-conversion \ -Warray-bounds \ -Warray-bounds=2 \ + -Warray-compare \ -Warray-parameter=2 \ -Wattribute-alias=2 \ -Wattribute-warning \ @@ -170,10 +177,15 @@ set(GCC_CXXFLAGS "-std=c++11 \ -Wbuiltin-macro-redefined \ -Wc++0x-compat \ -Wc++11-compat \ + -Wc++11-extensions \ -Wc++14-compat \ + -Wc++14-extensions \ -Wc++17-compat \ + -Wc++17-extensions \ -Wc++1z-compat \ -Wc++20-compat \ + -Wc++20-extensions \ + -Wc++23-extensions \ -Wc++2a-compat \ -Wcannot-profile \ -Wcast-align \ @@ -191,6 +203,7 @@ set(GCC_CXXFLAGS "-std=c++11 \ -Wconditionally-supported \ -Wconversion \ -Wconversion-null \ + -Wcoverage-invalid-line-number \ -Wcoverage-mismatch \ -Wcpp \ -Wctad-maybe-unsupported \ @@ -215,21 +228,16 @@ set(GCC_CXXFLAGS "-std=c++11 \ -Wendif-labels \ -Wenum-compare \ -Wenum-conversion \ + -Wexceptions \ -Wexpansion-to-defined \ -Wextra \ -Wextra-semi \ -Wfloat-conversion \ -Wfloat-equal \ - -Wformat-contains-nul \ -Wformat-diag \ - -Wformat-extra-args \ - -Wformat-nonliteral \ -Wformat-overflow=2 \ - -Wformat-security \ -Wformat-signedness \ -Wformat-truncation=2 \ - -Wformat-y2k \ - -Wformat-zero-length \ -Wformat=2 \ -Wframe-address \ -Wfree-nonheap-object \ @@ -239,12 +247,15 @@ set(GCC_CXXFLAGS "-std=c++11 \ -Wignored-qualifiers \ -Wimplicit-fallthrough=5 \ -Winaccessible-base \ + -Winfinite-recursion \ -Winherited-variadic-ctor \ -Winit-list-lifetime \ -Winit-self \ -Winline \ -Wint-in-bool-context \ -Wint-to-pointer-cast \ + -Winterference-size \ + -Winvalid-imported-macros \ -Winvalid-memory-model \ -Winvalid-offsetof \ -Winvalid-pch \ @@ -267,6 +278,7 @@ set(GCC_CXXFLAGS "-std=c++11 \ -Wmissing-field-initializers \ -Wmissing-include-dirs \ -Wmissing-profile \ + -Wmissing-requires \ -Wmultichar \ -Wmultiple-inheritance \ -Wmultistatement-macros \ @@ -282,6 +294,7 @@ set(GCC_CXXFLAGS "-std=c++11 \ -Wnull-dereference \ -Wodr \ -Wold-style-cast \ + -Wopenacc-parallelism \ -Wopenmp-simd \ -Woverflow \ -Woverlength-strings \ diff --git a/include/nlohmann/json.hpp b/include/nlohmann/json.hpp index a79be2dbd..6bf77d507 100644 --- a/include/nlohmann/json.hpp +++ b/include/nlohmann/json.hpp @@ -1872,6 +1872,7 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec template < typename ValueType, typename std::enable_if < detail::conjunction < detail::negation>, + detail::negation>, detail::negation>>, detail::negation>, detail::negation>, diff --git a/include/nlohmann/ordered_map.hpp b/include/nlohmann/ordered_map.hpp index 709bc5fd5..5a7da074b 100644 --- a/include/nlohmann/ordered_map.hpp +++ b/include/nlohmann/ordered_map.hpp @@ -30,7 +30,8 @@ template , // Explicit constructors instead of `using Container::Container` // otherwise older compilers choke on it (GCC <= 5.5, xcode <= 9.4) - ordered_map(const Allocator& alloc = Allocator()) : Container{alloc} {} + ordered_map() noexcept(noexcept(Container())) : Container{} {} + explicit ordered_map(const Allocator& alloc) noexcept(noexcept(Container(alloc))) : Container{alloc} {} template ordered_map(It first, It last, const Allocator& alloc = Allocator()) : Container{first, last, alloc} {} diff --git a/single_include/nlohmann/json.hpp b/single_include/nlohmann/json.hpp index ec33a847a..48999920d 100644 --- a/single_include/nlohmann/json.hpp +++ b/single_include/nlohmann/json.hpp @@ -17066,7 +17066,8 @@ template , // Explicit constructors instead of `using Container::Container` // otherwise older compilers choke on it (GCC <= 5.5, xcode <= 9.4) - ordered_map(const Allocator& alloc = Allocator()) : Container{alloc} {} + ordered_map() noexcept(noexcept(Container())) : Container{} {} + explicit ordered_map(const Allocator& alloc) noexcept(noexcept(Container(alloc))) : Container{alloc} {} template ordered_map(It first, It last, const Allocator& alloc = Allocator()) : Container{first, last, alloc} {} @@ -19052,6 +19053,7 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec template < typename ValueType, typename std::enable_if < detail::conjunction < detail::negation>, + detail::negation>, detail::negation>>, detail::negation>, detail::negation>, diff --git a/test/src/unit-allocator.cpp b/test/src/unit-allocator.cpp index 2671212f5..268ae54df 100644 --- a/test/src/unit-allocator.cpp +++ b/test/src/unit-allocator.cpp @@ -39,6 +39,8 @@ namespace template struct bad_allocator : std::allocator { + using std::allocator::allocator; + template void construct(T* /*unused*/, Args&& ... /*unused*/) { diff --git a/test/src/unit-alt-string.cpp b/test/src/unit-alt-string.cpp index 2c599a451..7da69dea1 100644 --- a/test/src/unit-alt-string.cpp +++ b/test/src/unit-alt-string.cpp @@ -104,12 +104,12 @@ class alt_string } template - bool operator<(const op_type& op) const + bool operator<(const op_type& op) const noexcept { return str_impl < op; } - bool operator<(const alt_string& op) const + bool operator<(const alt_string& op) const noexcept { return str_impl < op.str_impl; } diff --git a/test/src/unit-comparison.cpp b/test/src/unit-comparison.cpp index 4feccef44..f4853f585 100644 --- a/test/src/unit-comparison.cpp +++ b/test/src/unit-comparison.cpp @@ -32,6 +32,10 @@ SOFTWARE. #include using nlohmann::json; +#if (defined(__cplusplus) && __cplusplus >= 202002L) || (defined(_MSVC_LANG) && _MSVC_LANG >= 202002L) + #define JSON_HAS_CPP_20 +#endif + namespace { // helper function to check std::less @@ -205,6 +209,14 @@ TEST_CASE("lexicographical comparison operators") { for (size_t j = 0; j < j_values.size(); ++j) { + // Skip comparing indicies 12 and 13, and 13 and 12 in C++20 pending fix + // See issue #3207 +#ifdef JSON_HAS_CPP_20 + if ((i == 12 && j == 13) || (i == 13 && j == 12)) + { + continue; + } +#endif CAPTURE(i) CAPTURE(j) CAPTURE(j_values[i]) diff --git a/test/src/unit-regression2.cpp b/test/src/unit-regression2.cpp index 6249db63e..8c6e41193 100644 --- a/test/src/unit-regression2.cpp +++ b/test/src/unit-regression2.cpp @@ -271,7 +271,10 @@ std::string* sax_no_exception::error_string = nullptr; template class my_allocator : public std::allocator -{}; +{ + public: + using std::allocator::allocator; +}; ///////////////////////////////////////////////////////////////////// // for #3077 @@ -338,7 +341,7 @@ TEST_CASE("regression tests 2") ] })"; - json::parser_callback_t cb = [&](int /*level*/, json::parse_event_t event, json & parsed) + json::parser_callback_t cb = [&](int /*level*/, json::parse_event_t event, json & parsed) noexcept { // skip uninteresting events if (event == json::parse_event_t::value && !parsed.is_primitive()) From 700b95f4473cac1d900b807541daad0ca3d98f52 Mon Sep 17 00:00:00 2001 From: Florian Albrechtskirchinger Date: Tue, 8 Mar 2022 10:10:50 +0100 Subject: [PATCH 17/18] Make iterator operator++/--(int) equality-preserving (#3332) Commit f28fc22 introduced const qualifiers on post-(inc-/dec-)rement operators of iterators. These qualifiers prevent the use of basic_json in place of std::ranges::range, which requires the post-increment operator to be equality-preserving. These changes appear to be the result of ICC compiler suggestions, and no further explanation is discernible from the PR discussion (#858). Further testing revealed, that clang-tidy also suggests adding const to prevent "accidental mutation of a temporary object". As an alternative, this commit partially reverts f28fc22, removing all added const qualifiers from return types and adds lvalue reference qualifiers to the operator member functions instead. Unit tests ensure the operators remain equality-preserving and accidental mutation of temporaries following post-(inc-/dec-)rement is prohibited. Fixes #3331. --- .../nlohmann/detail/iterators/iter_impl.hpp | 4 +- .../iterators/json_reverse_iterator.hpp | 4 +- .../detail/iterators/primitive_iterator.hpp | 4 +- single_include/nlohmann/json.hpp | 12 +-- test/src/unit-class_iterator.cpp | 91 +++++++++++++++++++ 5 files changed, 103 insertions(+), 12 deletions(-) diff --git a/include/nlohmann/detail/iterators/iter_impl.hpp b/include/nlohmann/detail/iterators/iter_impl.hpp index 434a62d3e..d8060786e 100644 --- a/include/nlohmann/detail/iterators/iter_impl.hpp +++ b/include/nlohmann/detail/iterators/iter_impl.hpp @@ -352,7 +352,7 @@ class iter_impl // NOLINT(cppcoreguidelines-special-member-functions,hicpp-speci @brief post-increment (it++) @pre The iterator is initialized; i.e. `m_object != nullptr`. */ - iter_impl const operator++(int) // NOLINT(readability-const-return-type) + iter_impl operator++(int)& // NOLINT(cert-dcl21-cpp) { auto result = *this; ++(*this); @@ -403,7 +403,7 @@ class iter_impl // NOLINT(cppcoreguidelines-special-member-functions,hicpp-speci @brief post-decrement (it--) @pre The iterator is initialized; i.e. `m_object != nullptr`. */ - iter_impl const operator--(int) // NOLINT(readability-const-return-type) + iter_impl operator--(int)& // NOLINT(cert-dcl21-cpp) { auto result = *this; --(*this); diff --git a/include/nlohmann/detail/iterators/json_reverse_iterator.hpp b/include/nlohmann/detail/iterators/json_reverse_iterator.hpp index e787fdbcd..65bb327a5 100644 --- a/include/nlohmann/detail/iterators/json_reverse_iterator.hpp +++ b/include/nlohmann/detail/iterators/json_reverse_iterator.hpp @@ -48,7 +48,7 @@ class json_reverse_iterator : public std::reverse_iterator explicit json_reverse_iterator(const base_iterator& it) noexcept : base_iterator(it) {} /// post-increment (it++) - json_reverse_iterator const operator++(int) // NOLINT(readability-const-return-type) + json_reverse_iterator operator++(int)& // NOLINT(cert-dcl21-cpp) { return static_cast(base_iterator::operator++(1)); } @@ -60,7 +60,7 @@ class json_reverse_iterator : public std::reverse_iterator } /// post-decrement (it--) - json_reverse_iterator const operator--(int) // NOLINT(readability-const-return-type) + json_reverse_iterator operator--(int)& // NOLINT(cert-dcl21-cpp) { return static_cast(base_iterator::operator--(1)); } diff --git a/include/nlohmann/detail/iterators/primitive_iterator.hpp b/include/nlohmann/detail/iterators/primitive_iterator.hpp index 15aa2f08a..03bc37e2c 100644 --- a/include/nlohmann/detail/iterators/primitive_iterator.hpp +++ b/include/nlohmann/detail/iterators/primitive_iterator.hpp @@ -87,7 +87,7 @@ class primitive_iterator_t return *this; } - primitive_iterator_t const operator++(int) noexcept // NOLINT(readability-const-return-type) + primitive_iterator_t operator++(int)& noexcept // NOLINT(cert-dcl21-cpp) { auto result = *this; ++m_it; @@ -100,7 +100,7 @@ class primitive_iterator_t return *this; } - primitive_iterator_t const operator--(int) noexcept // NOLINT(readability-const-return-type) + primitive_iterator_t operator--(int)& noexcept // NOLINT(cert-dcl21-cpp) { auto result = *this; --m_it; diff --git a/single_include/nlohmann/json.hpp b/single_include/nlohmann/json.hpp index 48999920d..05000fbba 100644 --- a/single_include/nlohmann/json.hpp +++ b/single_include/nlohmann/json.hpp @@ -11308,7 +11308,7 @@ class primitive_iterator_t return *this; } - primitive_iterator_t const operator++(int) noexcept // NOLINT(readability-const-return-type) + primitive_iterator_t operator++(int)& noexcept // NOLINT(cert-dcl21-cpp) { auto result = *this; ++m_it; @@ -11321,7 +11321,7 @@ class primitive_iterator_t return *this; } - primitive_iterator_t const operator--(int) noexcept // NOLINT(readability-const-return-type) + primitive_iterator_t operator--(int)& noexcept // NOLINT(cert-dcl21-cpp) { auto result = *this; --m_it; @@ -11728,7 +11728,7 @@ class iter_impl // NOLINT(cppcoreguidelines-special-member-functions,hicpp-speci @brief post-increment (it++) @pre The iterator is initialized; i.e. `m_object != nullptr`. */ - iter_impl const operator++(int) // NOLINT(readability-const-return-type) + iter_impl operator++(int)& // NOLINT(cert-dcl21-cpp) { auto result = *this; ++(*this); @@ -11779,7 +11779,7 @@ class iter_impl // NOLINT(cppcoreguidelines-special-member-functions,hicpp-speci @brief post-decrement (it--) @pre The iterator is initialized; i.e. `m_object != nullptr`. */ - iter_impl const operator--(int) // NOLINT(readability-const-return-type) + iter_impl operator--(int)& // NOLINT(cert-dcl21-cpp) { auto result = *this; --(*this); @@ -12167,7 +12167,7 @@ class json_reverse_iterator : public std::reverse_iterator explicit json_reverse_iterator(const base_iterator& it) noexcept : base_iterator(it) {} /// post-increment (it++) - json_reverse_iterator const operator++(int) // NOLINT(readability-const-return-type) + json_reverse_iterator operator++(int)& // NOLINT(cert-dcl21-cpp) { return static_cast(base_iterator::operator++(1)); } @@ -12179,7 +12179,7 @@ class json_reverse_iterator : public std::reverse_iterator } /// post-decrement (it--) - json_reverse_iterator const operator--(int) // NOLINT(readability-const-return-type) + json_reverse_iterator operator--(int)& // NOLINT(cert-dcl21-cpp) { return static_cast(base_iterator::operator--(1)); } diff --git a/test/src/unit-class_iterator.cpp b/test/src/unit-class_iterator.cpp index 0e159fc38..e3a972f97 100644 --- a/test/src/unit-class_iterator.cpp +++ b/test/src/unit-class_iterator.cpp @@ -33,6 +33,12 @@ SOFTWARE. #include using nlohmann::json; +template +using can_post_increment_temporary = decltype((std::declval()++)++); + +template +using can_post_decrement_temporary = decltype((std::declval()--)--); + TEST_CASE("iterator class") { SECTION("construction") @@ -399,4 +405,89 @@ TEST_CASE("iterator class") } } } + SECTION("equality-preserving") + { + SECTION("post-increment") + { + SECTION("primitive_iterator_t") + { + using Iter = nlohmann::detail::primitive_iterator_t; + CHECK(std::is_same < decltype(std::declval()++), Iter >::value); + } + SECTION("iter_impl") + { + using Iter = nlohmann::detail::iter_impl; + CHECK(std::is_same < decltype(std::declval()++), Iter >::value); + } + SECTION("json_reverse_iterator") + { + using Base = nlohmann::detail::iter_impl; + using Iter = nlohmann::detail::json_reverse_iterator; + CHECK(std::is_same < decltype(std::declval()++), Iter >::value); + } + } + SECTION("post-decrement") + { + SECTION("primitive_iterator_t") + { + using Iter = nlohmann::detail::primitive_iterator_t; + CHECK(std::is_same < decltype(std::declval()--), Iter >::value); + } + SECTION("iter_impl") + { + using Iter = nlohmann::detail::iter_impl; + CHECK(std::is_same < decltype(std::declval()--), Iter >::value ); + } + SECTION("json_reverse_iterator") + { + using Base = nlohmann::detail::iter_impl; + using Iter = nlohmann::detail::json_reverse_iterator; + CHECK(std::is_same < decltype(std::declval()--), Iter >::value ); + } + } + } + // prevent "accidental mutation of a temporary object" + SECTION("cert-dcl21-cpp") + { + using nlohmann::detail::is_detected; + SECTION("post-increment") + { + SECTION("primitive_iterator_t") + { + using Iter = nlohmann::detail::primitive_iterator_t; + CHECK_FALSE(is_detected::value); + } + SECTION("iter_impl") + { + using Iter = nlohmann::detail::iter_impl; + CHECK_FALSE(is_detected::value); + } + SECTION("json_reverse_iterator") + { + using Base = nlohmann::detail::iter_impl; + using Iter = nlohmann::detail::json_reverse_iterator; + CHECK_FALSE(is_detected::value); + } + } + SECTION("post-decrement") + { + SECTION("primitive_iterator_t") + { + using Iter = nlohmann::detail::primitive_iterator_t; + CHECK_FALSE(is_detected::value); + } + SECTION("iter_impl") + { + using Iter = nlohmann::detail::iter_impl; + CHECK_FALSE(is_detected::value); + } + SECTION("json_reverse_iterator") + { + using Base = nlohmann::detail::iter_impl; + using Iter = nlohmann::detail::json_reverse_iterator; + CHECK_FALSE(is_detected::value); + } + + } + } } From ad103e5b454a7e9ae2170d2cfdba5aa60979c9cd Mon Sep 17 00:00:00 2001 From: Florian Albrechtskirchinger Date: Thu, 24 Mar 2022 07:54:07 +0100 Subject: [PATCH 18/18] Improve unit testing (Part 1) (#3380) * Refactor unit test creation Add functions for creating tests and to supply test- and standard-specific build settings. Raises minimum CMake version to 3.13 in test directory. json_test_add_test_for( MAIN
[CXX_STANDARDS ...] [FORCE]) Given a unit-foo.cpp, produces test-foo_cpp if C++ standard is supported by the compiler and thesource file contains JSON_HAS_CPP_. Use FORCE to create the test regardless of the file containing JSON_HAS_CPP_. Test targets are linked against
. CXX_STANDARDS defaults to "11". json_test_set_test_options( all| [CXX_STANDARDS all|...] [COMPILE_DEFINITIONS ...] [COMPILE_FEATURES ...] [COMPILE_OPTIONS ...] [LINK_LIBRARIES ...] [LINK_OPTIONS ...]) Supply test- and standard-specific build settings. Specify multiple tests using a list e.g., "test-foo;test-bar". Must be called BEFORE the test is created. * Use CMAKE_MODULE_PATH * Don't undef some macros if JSON_TEST_KEEP_MACROS is defined * Use JSON_TEST_KEEP_MACROS Incidentally enables the regression tests for #2546 and #3070. A CHECK_THROWS_WITH_AS in #3070 was disabled which is tracked in #3377 and a line in from_json(..., std_fs::path&) was marked with LCOV_EXCL_LINE. * Add three-way comparison feature test macro * Disable broken comparison if JSON_HAS_THREE_WAY_COMPARISON * Fix redefinition of inline constexpr statics Redelcaration of inline constexpr static data members in namespace scope was deprecated in C++17. Fixes -Werror=deprecated compilation failures. * Fix more test build failures due to missing noexcept * CI: update cmake_flags test to use CMake 3.13 in test directory Also change default for JSON_BuildTests option to depend on CMake version. * CI: turn *_CXXFLAGS into CMake lists * CI: use JSON_TestStandards to set CXX_STANDARD * CI: pass extra CXXFLAGS to standards tests --- .github/workflows/macos.yml | 2 +- CMakeLists.txt | 11 +- benchmarks/CMakeLists.txt | 2 +- cmake/ci.cmake | 703 +++++++++--------- cmake/test.cmake | 204 +++++ .../nlohmann/detail/conversions/from_json.hpp | 3 +- include/nlohmann/detail/macro_scope.hpp | 9 + include/nlohmann/detail/macro_unscope.hpp | 20 +- include/nlohmann/detail/meta/cpp_future.hpp | 8 +- single_include/nlohmann/json.hpp | 40 +- test/CMakeLists.txt | 230 +++--- test/src/unit-alt-string.cpp | 6 +- test/src/unit-cbor.cpp | 2 +- test/src/unit-class_parser.cpp | 28 +- test/src/unit-comparison.cpp | 6 +- test/src/unit-conversions.cpp | 7 - test/src/unit-items.cpp | 7 - test/src/unit-regression1.cpp | 4 - test/src/unit-regression2.cpp | 67 +- test/src/unit-ubjson.cpp | 4 +- 20 files changed, 756 insertions(+), 607 deletions(-) create mode 100644 cmake/test.cmake diff --git a/.github/workflows/macos.yml b/.github/workflows/macos.yml index 6a378f13f..d01502bf5 100644 --- a/.github/workflows/macos.yml +++ b/.github/workflows/macos.yml @@ -38,7 +38,7 @@ jobs: steps: - uses: actions/checkout@v2 - name: cmake - run: cmake -S . -B build -D CMAKE_BUILD_TYPE=Debug -DJSON_BuildTests=On -DCMAKE_CXX_STANDARD=${{ matrix.standard }} -DCMAKE_CXX_STANDARD_REQUIRED=ON + run: cmake -S . -B build -D CMAKE_BUILD_TYPE=Debug -DJSON_BuildTests=On -DJSON_TestStandards=${{ matrix.standard }} - name: build run: cmake --build build --parallel 10 - name: test diff --git a/CMakeLists.txt b/CMakeLists.txt index b93c6e47f..68bba9cf4 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -19,6 +19,7 @@ endif() ## INCLUDE ## ## +set(CMAKE_MODULE_PATH ${CMAKE_CURRENT_SOURCE_DIR}/cmake ${CMAKE_MODULE_PATH}) include(ExternalProject) ## @@ -30,7 +31,13 @@ if (POLICY CMP0077) cmake_policy(SET CMP0077 NEW) endif () -option(JSON_BuildTests "Build the unit tests when BUILD_TESTING is enabled." ${MAIN_PROJECT}) +# VERSION_GREATER_EQUAL is not available in CMake 3.1 +if(${MAIN_PROJECT} AND (${CMAKE_VERSION} VERSION_EQUAL 3.13 OR ${CMAKE_VERSION} VERSION_GREATER 3.13)) + set(JSON_BuildTests_INIT ON) +else() + set(JSON_BuildTests_INIT OFF) +endif() +option(JSON_BuildTests "Build the unit tests when BUILD_TESTING is enabled." ${JSON_BuildTests_INIT}) option(JSON_CI "Enable CI build targets." OFF) option(JSON_Diagnostics "Use extended diagnostic messages." OFF) option(JSON_ImplicitConversions "Enable implicit conversions." ON) @@ -39,7 +46,7 @@ option(JSON_MultipleHeaders "Use non-amalgamated version of the library." OF option(JSON_SystemInclude "Include as system headers (skip for clang-tidy)." OFF) if (JSON_CI) - include(cmake/ci.cmake) + include(ci) endif () ## diff --git a/benchmarks/CMakeLists.txt b/benchmarks/CMakeLists.txt index 1243f54ea..325904d12 100644 --- a/benchmarks/CMakeLists.txt +++ b/benchmarks/CMakeLists.txt @@ -23,7 +23,7 @@ if(NOT benchmark_POPULATED) endif() # download test data -include(${CMAKE_SOURCE_DIR}/../cmake/download_test_data.cmake) +include(download_test_data) # benchmark binary add_executable(json_benchmarks src/benchmarks.cpp) diff --git a/cmake/ci.cmake b/cmake/ci.cmake index 9a8136165..b9078b625 100644 --- a/cmake/ci.cmake +++ b/cmake/ci.cmake @@ -98,18 +98,18 @@ file(GLOB_RECURSE SRC_FILES ${PROJECT_SOURCE_DIR}/include/nlohmann/*.hpp) # -Wno-weak-vtables The library is header-only. # -Wreserved-identifier See https://github.com/onqtam/doctest/issues/536. -set(CLANG_CXXFLAGS "-std=c++11 \ - -Werror \ - -Weverything \ - -Wno-c++98-compat \ - -Wno-c++98-compat-pedantic \ - -Wno-deprecated-declarations \ - -Wno-extra-semi-stmt \ - -Wno-padded \ - -Wno-covered-switch-default \ - -Wno-weak-vtables \ - -Wno-reserved-identifier \ -") +set(CLANG_CXXFLAGS + -Werror + -Weverything + -Wno-c++98-compat + -Wno-c++98-compat-pedantic + -Wno-deprecated-declarations + -Wno-extra-semi-stmt + -Wno-padded + -Wno-covered-switch-default + -Wno-weak-vtables + -Wno-reserved-identifier +) # Warning flags determined for GCC 12.0 (experimental) with https://github.com/nlohmann/gcc_flags: # Ignored GCC warnings: @@ -121,295 +121,295 @@ set(CLANG_CXXFLAGS "-std=c++11 \ # -Wno-system-headers We do not care about warnings in system headers. # -Wno-templates The library uses templates. -set(GCC_CXXFLAGS "-std=c++11 \ - -pedantic \ - -Werror \ - --all-warnings \ - --extra-warnings \ - -W \ - -WNSObject-attribute \ - -Wno-abi-tag \ - -Waddress \ - -Waddress-of-packed-member \ - -Wno-aggregate-return \ - -Waggressive-loop-optimizations \ - -Waligned-new=all \ - -Wall \ - -Walloc-zero \ - -Walloca \ - -Wanalyzer-double-fclose \ - -Wanalyzer-double-free \ - -Wanalyzer-exposure-through-output-file \ - -Wanalyzer-file-leak \ - -Wanalyzer-free-of-non-heap \ - -Wanalyzer-malloc-leak \ - -Wanalyzer-mismatching-deallocation \ - -Wanalyzer-null-argument \ - -Wanalyzer-null-dereference \ - -Wanalyzer-possible-null-argument \ - -Wanalyzer-possible-null-dereference \ - -Wanalyzer-shift-count-negative \ - -Wanalyzer-shift-count-overflow \ - -Wanalyzer-stale-setjmp-buffer \ - -Wanalyzer-tainted-allocation-size \ - -Wanalyzer-tainted-array-index \ - -Wanalyzer-tainted-divisor \ - -Wanalyzer-tainted-offset \ - -Wanalyzer-tainted-size \ - -Wanalyzer-too-complex \ - -Wanalyzer-unsafe-call-within-signal-handler \ - -Wanalyzer-use-after-free \ - -Wanalyzer-use-of-pointer-in-stale-stack-frame \ - -Wanalyzer-use-of-uninitialized-value \ - -Wanalyzer-write-to-const \ - -Wanalyzer-write-to-string-literal \ - -Warith-conversion \ - -Warray-bounds \ - -Warray-bounds=2 \ - -Warray-compare \ - -Warray-parameter=2 \ - -Wattribute-alias=2 \ - -Wattribute-warning \ - -Wattributes \ - -Wbool-compare \ - -Wbool-operation \ - -Wbuiltin-declaration-mismatch \ - -Wbuiltin-macro-redefined \ - -Wc++0x-compat \ - -Wc++11-compat \ - -Wc++11-extensions \ - -Wc++14-compat \ - -Wc++14-extensions \ - -Wc++17-compat \ - -Wc++17-extensions \ - -Wc++1z-compat \ - -Wc++20-compat \ - -Wc++20-extensions \ - -Wc++23-extensions \ - -Wc++2a-compat \ - -Wcannot-profile \ - -Wcast-align \ - -Wcast-align=strict \ - -Wcast-function-type \ - -Wcast-qual \ - -Wcatch-value=3 \ - -Wchar-subscripts \ - -Wclass-conversion \ - -Wclass-memaccess \ - -Wclobbered \ - -Wcomma-subscript \ - -Wcomment \ - -Wcomments \ - -Wconditionally-supported \ - -Wconversion \ - -Wconversion-null \ - -Wcoverage-invalid-line-number \ - -Wcoverage-mismatch \ - -Wcpp \ - -Wctad-maybe-unsupported \ - -Wctor-dtor-privacy \ - -Wdangling-else \ - -Wdate-time \ - -Wdelete-incomplete \ - -Wdelete-non-virtual-dtor \ - -Wdeprecated \ - -Wdeprecated-copy \ - -Wdeprecated-copy-dtor \ - -Wdeprecated-declarations \ - -Wdeprecated-enum-enum-conversion \ - -Wdeprecated-enum-float-conversion \ - -Wdisabled-optimization \ - -Wdiv-by-zero \ - -Wdouble-promotion \ - -Wduplicated-branches \ - -Wduplicated-cond \ - -Weffc++ \ - -Wempty-body \ - -Wendif-labels \ - -Wenum-compare \ - -Wenum-conversion \ - -Wexceptions \ - -Wexpansion-to-defined \ - -Wextra \ - -Wextra-semi \ - -Wfloat-conversion \ - -Wfloat-equal \ - -Wformat-diag \ - -Wformat-overflow=2 \ - -Wformat-signedness \ - -Wformat-truncation=2 \ - -Wformat=2 \ - -Wframe-address \ - -Wfree-nonheap-object \ - -Whsa \ - -Wif-not-aligned \ - -Wignored-attributes \ - -Wignored-qualifiers \ - -Wimplicit-fallthrough=5 \ - -Winaccessible-base \ - -Winfinite-recursion \ - -Winherited-variadic-ctor \ - -Winit-list-lifetime \ - -Winit-self \ - -Winline \ - -Wint-in-bool-context \ - -Wint-to-pointer-cast \ - -Winterference-size \ - -Winvalid-imported-macros \ - -Winvalid-memory-model \ - -Winvalid-offsetof \ - -Winvalid-pch \ - -Wliteral-suffix \ - -Wlogical-not-parentheses \ - -Wlogical-op \ - -Wno-long-long \ - -Wlto-type-mismatch \ - -Wmain \ - -Wmaybe-uninitialized \ - -Wmemset-elt-size \ - -Wmemset-transposed-args \ - -Wmisleading-indentation \ - -Wmismatched-dealloc \ - -Wmismatched-new-delete \ - -Wmismatched-tags \ - -Wmissing-attributes \ - -Wmissing-braces \ - -Wmissing-declarations \ - -Wmissing-field-initializers \ - -Wmissing-include-dirs \ - -Wmissing-profile \ - -Wmissing-requires \ - -Wmultichar \ - -Wmultiple-inheritance \ - -Wmultistatement-macros \ - -Wno-namespaces \ - -Wnarrowing \ - -Wnoexcept \ - -Wnoexcept-type \ - -Wnon-template-friend \ - -Wnon-virtual-dtor \ - -Wnonnull \ - -Wnonnull-compare \ - -Wnormalized=nfkc \ - -Wnull-dereference \ - -Wodr \ - -Wold-style-cast \ - -Wopenacc-parallelism \ - -Wopenmp-simd \ - -Woverflow \ - -Woverlength-strings \ - -Woverloaded-virtual \ - -Wpacked \ - -Wpacked-bitfield-compat \ - -Wpacked-not-aligned \ - -Wno-padded \ - -Wparentheses \ - -Wpedantic \ - -Wpessimizing-move \ - -Wplacement-new=2 \ - -Wpmf-conversions \ - -Wpointer-arith \ - -Wpointer-compare \ - -Wpragmas \ - -Wprio-ctor-dtor \ - -Wpsabi \ - -Wrange-loop-construct \ - -Wredundant-decls \ - -Wredundant-move \ - -Wredundant-tags \ - -Wregister \ - -Wreorder \ - -Wrestrict \ - -Wreturn-local-addr \ - -Wreturn-type \ - -Wscalar-storage-order \ - -Wsequence-point \ - -Wshadow=compatible-local \ - -Wshadow=global \ - -Wshadow=local \ - -Wshift-count-negative \ - -Wshift-count-overflow \ - -Wshift-negative-value \ - -Wshift-overflow=2 \ - -Wsign-compare \ - -Wsign-conversion \ - -Wsign-promo \ - -Wsized-deallocation \ - -Wsizeof-array-argument \ - -Wsizeof-array-div \ - -Wsizeof-pointer-div \ - -Wsizeof-pointer-memaccess \ - -Wstack-protector \ - -Wstrict-aliasing \ - -Wstrict-aliasing=3 \ - -Wstrict-null-sentinel \ - -Wstrict-overflow \ - -Wstrict-overflow=5 \ - -Wstring-compare \ - -Wstringop-overflow=4 \ - -Wstringop-overread \ - -Wstringop-truncation \ - -Wsubobject-linkage \ - -Wsuggest-attribute=cold \ - -Wsuggest-attribute=const \ - -Wsuggest-attribute=format \ - -Wsuggest-attribute=malloc \ - -Wsuggest-attribute=noreturn \ - -Wsuggest-attribute=pure \ - -Wsuggest-final-methods \ - -Wsuggest-final-types \ - -Wsuggest-override \ - -Wswitch \ - -Wswitch-bool \ - -Wswitch-default \ - -Wswitch-enum \ - -Wswitch-outside-range \ - -Wswitch-unreachable \ - -Wsync-nand \ - -Wsynth \ - -Wno-system-headers \ - -Wtautological-compare \ - -Wno-templates \ - -Wterminate \ - -Wtrampolines \ - -Wtrigraphs \ - -Wtsan \ - -Wtype-limits \ - -Wundef \ - -Wuninitialized \ - -Wunknown-pragmas \ - -Wunreachable-code \ - -Wunsafe-loop-optimizations \ - -Wunused \ - -Wunused-but-set-parameter \ - -Wunused-but-set-variable \ - -Wunused-const-variable=2 \ - -Wunused-function \ - -Wunused-label \ - -Wunused-local-typedefs \ - -Wunused-macros \ - -Wunused-parameter \ - -Wunused-result \ - -Wunused-value \ - -Wunused-variable \ - -Wuseless-cast \ - -Wvarargs \ - -Wvariadic-macros \ - -Wvector-operation-performance \ - -Wvexing-parse \ - -Wvirtual-inheritance \ - -Wvirtual-move-assign \ - -Wvla \ - -Wvla-parameter \ - -Wvolatile \ - -Wvolatile-register-var \ - -Wwrite-strings \ - -Wzero-as-null-pointer-constant \ - -Wzero-length-bounds \ -") +set(GCC_CXXFLAGS + -pedantic + -Werror + --all-warnings + --extra-warnings + -W + -WNSObject-attribute + -Wno-abi-tag + -Waddress + -Waddress-of-packed-member + -Wno-aggregate-return + -Waggressive-loop-optimizations + -Waligned-new=all + -Wall + -Walloc-zero + -Walloca + -Wanalyzer-double-fclose + -Wanalyzer-double-free + -Wanalyzer-exposure-through-output-file + -Wanalyzer-file-leak + -Wanalyzer-free-of-non-heap + -Wanalyzer-malloc-leak + -Wanalyzer-mismatching-deallocation + -Wanalyzer-null-argument + -Wanalyzer-null-dereference + -Wanalyzer-possible-null-argument + -Wanalyzer-possible-null-dereference + -Wanalyzer-shift-count-negative + -Wanalyzer-shift-count-overflow + -Wanalyzer-stale-setjmp-buffer + -Wanalyzer-tainted-allocation-size + -Wanalyzer-tainted-array-index + -Wanalyzer-tainted-divisor + -Wanalyzer-tainted-offset + -Wanalyzer-tainted-size + -Wanalyzer-too-complex + -Wanalyzer-unsafe-call-within-signal-handler + -Wanalyzer-use-after-free + -Wanalyzer-use-of-pointer-in-stale-stack-frame + -Wanalyzer-use-of-uninitialized-value + -Wanalyzer-write-to-const + -Wanalyzer-write-to-string-literal + -Warith-conversion + -Warray-bounds + -Warray-bounds=2 + -Warray-compare + -Warray-parameter=2 + -Wattribute-alias=2 + -Wattribute-warning + -Wattributes + -Wbool-compare + -Wbool-operation + -Wbuiltin-declaration-mismatch + -Wbuiltin-macro-redefined + -Wc++0x-compat + -Wc++11-compat + -Wc++11-extensions + -Wc++14-compat + -Wc++14-extensions + -Wc++17-compat + -Wc++17-extensions + -Wc++1z-compat + -Wc++20-compat + -Wc++20-extensions + -Wc++23-extensions + -Wc++2a-compat + -Wcannot-profile + -Wcast-align + -Wcast-align=strict + -Wcast-function-type + -Wcast-qual + -Wcatch-value=3 + -Wchar-subscripts + -Wclass-conversion + -Wclass-memaccess + -Wclobbered + -Wcomma-subscript + -Wcomment + -Wcomments + -Wconditionally-supported + -Wconversion + -Wconversion-null + -Wcoverage-invalid-line-number + -Wcoverage-mismatch + -Wcpp + -Wctad-maybe-unsupported + -Wctor-dtor-privacy + -Wdangling-else + -Wdate-time + -Wdelete-incomplete + -Wdelete-non-virtual-dtor + -Wdeprecated + -Wdeprecated-copy + -Wdeprecated-copy-dtor + -Wdeprecated-declarations + -Wdeprecated-enum-enum-conversion + -Wdeprecated-enum-float-conversion + -Wdisabled-optimization + -Wdiv-by-zero + -Wdouble-promotion + -Wduplicated-branches + -Wduplicated-cond + -Weffc++ + -Wempty-body + -Wendif-labels + -Wenum-compare + -Wenum-conversion + -Wexceptions + -Wexpansion-to-defined + -Wextra + -Wextra-semi + -Wfloat-conversion + -Wfloat-equal + -Wformat-diag + -Wformat-overflow=2 + -Wformat-signedness + -Wformat-truncation=2 + -Wformat=2 + -Wframe-address + -Wfree-nonheap-object + -Whsa + -Wif-not-aligned + -Wignored-attributes + -Wignored-qualifiers + -Wimplicit-fallthrough=5 + -Winaccessible-base + -Winfinite-recursion + -Winherited-variadic-ctor + -Winit-list-lifetime + -Winit-self + -Winline + -Wint-in-bool-context + -Wint-to-pointer-cast + -Winterference-size + -Winvalid-imported-macros + -Winvalid-memory-model + -Winvalid-offsetof + -Winvalid-pch + -Wliteral-suffix + -Wlogical-not-parentheses + -Wlogical-op + -Wno-long-long + -Wlto-type-mismatch + -Wmain + -Wmaybe-uninitialized + -Wmemset-elt-size + -Wmemset-transposed-args + -Wmisleading-indentation + -Wmismatched-dealloc + -Wmismatched-new-delete + -Wmismatched-tags + -Wmissing-attributes + -Wmissing-braces + -Wmissing-declarations + -Wmissing-field-initializers + -Wmissing-include-dirs + -Wmissing-profile + -Wmissing-requires + -Wmultichar + -Wmultiple-inheritance + -Wmultistatement-macros + -Wno-namespaces + -Wnarrowing + -Wnoexcept + -Wnoexcept-type + -Wnon-template-friend + -Wnon-virtual-dtor + -Wnonnull + -Wnonnull-compare + -Wnormalized=nfkc + -Wnull-dereference + -Wodr + -Wold-style-cast + -Wopenacc-parallelism + -Wopenmp-simd + -Woverflow + -Woverlength-strings + -Woverloaded-virtual + -Wpacked + -Wpacked-bitfield-compat + -Wpacked-not-aligned + -Wno-padded + -Wparentheses + -Wpedantic + -Wpessimizing-move + -Wplacement-new=2 + -Wpmf-conversions + -Wpointer-arith + -Wpointer-compare + -Wpragmas + -Wprio-ctor-dtor + -Wpsabi + -Wrange-loop-construct + -Wredundant-decls + -Wredundant-move + -Wredundant-tags + -Wregister + -Wreorder + -Wrestrict + -Wreturn-local-addr + -Wreturn-type + -Wscalar-storage-order + -Wsequence-point + -Wshadow=compatible-local + -Wshadow=global + -Wshadow=local + -Wshift-count-negative + -Wshift-count-overflow + -Wshift-negative-value + -Wshift-overflow=2 + -Wsign-compare + -Wsign-conversion + -Wsign-promo + -Wsized-deallocation + -Wsizeof-array-argument + -Wsizeof-array-div + -Wsizeof-pointer-div + -Wsizeof-pointer-memaccess + -Wstack-protector + -Wstrict-aliasing + -Wstrict-aliasing=3 + -Wstrict-null-sentinel + -Wstrict-overflow + -Wstrict-overflow=5 + -Wstring-compare + -Wstringop-overflow=4 + -Wstringop-overread + -Wstringop-truncation + -Wsubobject-linkage + -Wsuggest-attribute=cold + -Wsuggest-attribute=const + -Wsuggest-attribute=format + -Wsuggest-attribute=malloc + -Wsuggest-attribute=noreturn + -Wsuggest-attribute=pure + -Wsuggest-final-methods + -Wsuggest-final-types + -Wsuggest-override + -Wswitch + -Wswitch-bool + -Wswitch-default + -Wswitch-enum + -Wswitch-outside-range + -Wswitch-unreachable + -Wsync-nand + -Wsynth + -Wno-system-headers + -Wtautological-compare + -Wno-templates + -Wterminate + -Wtrampolines + -Wtrigraphs + -Wtsan + -Wtype-limits + -Wundef + -Wuninitialized + -Wunknown-pragmas + -Wunreachable-code + -Wunsafe-loop-optimizations + -Wunused + -Wunused-but-set-parameter + -Wunused-but-set-variable + -Wunused-const-variable=2 + -Wunused-function + -Wunused-label + -Wunused-local-typedefs + -Wunused-macros + -Wunused-parameter + -Wunused-result + -Wunused-value + -Wunused-variable + -Wuseless-cast + -Wvarargs + -Wvariadic-macros + -Wvector-operation-performance + -Wvexing-parse + -Wvirtual-inheritance + -Wvirtual-move-assign + -Wvla + -Wvla-parameter + -Wvolatile + -Wvolatile-register-var + -Wwrite-strings + -Wzero-as-null-pointer-constant + -Wzero-length-bounds +) add_custom_target(ci_test_gcc - COMMAND CXX=${GCC_TOOL} CXXFLAGS=${GCC_CXXFLAGS} ${CMAKE_COMMAND} + COMMAND CXX=${GCC_TOOL} CXXFLAGS="${GCC_CXXFLAGS}" ${CMAKE_COMMAND} -DCMAKE_BUILD_TYPE=Debug -GNinja -DJSON_BuildTests=ON -DJSON_MultipleHeaders=ON -S${PROJECT_SOURCE_DIR} -B${PROJECT_BINARY_DIR}/build_gcc @@ -419,7 +419,7 @@ add_custom_target(ci_test_gcc ) add_custom_target(ci_test_clang - COMMAND CXX=${CLANG_TOOL} CXXFLAGS=${CLANG_CXXFLAGS} ${CMAKE_COMMAND} + COMMAND CXX=${CLANG_TOOL} CXXFLAGS="${CLANG_CXXFLAGS}" ${CMAKE_COMMAND} -DCMAKE_BUILD_TYPE=Debug -GNinja -DJSON_BuildTests=ON -DJSON_MultipleHeaders=ON -S${PROJECT_SOURCE_DIR} -B${PROJECT_BINARY_DIR}/build_clang @@ -434,10 +434,10 @@ add_custom_target(ci_test_clang foreach(CXX_STANDARD 11 14 17 20) add_custom_target(ci_test_gcc_cxx${CXX_STANDARD} - COMMAND CXX=${GCC_TOOL} ${CMAKE_COMMAND} + COMMAND CXX=${GCC_TOOL} CXXFLAGS="${GCC_CXXFLAGS}" ${CMAKE_COMMAND} -DCMAKE_BUILD_TYPE=Debug -GNinja - -DCMAKE_CXX_STANDARD=${CXX_STANDARD} -DCMAKE_CXX_STANDARD_REQUIRED=ON -DJSON_BuildTests=ON -DJSON_FastTests=ON + -DJSON_TestStandards=${CXX_STANDARD} -S${PROJECT_SOURCE_DIR} -B${PROJECT_BINARY_DIR}/build_gcc_cxx${CXX_STANDARD} COMMAND ${CMAKE_COMMAND} --build ${PROJECT_BINARY_DIR}/build_gcc_cxx${CXX_STANDARD} COMMAND cd ${PROJECT_BINARY_DIR}/build_gcc_cxx${CXX_STANDARD} && ${CMAKE_CTEST_COMMAND} --parallel ${N} --output-on-failure @@ -445,10 +445,10 @@ foreach(CXX_STANDARD 11 14 17 20) ) add_custom_target(ci_test_clang_cxx${CXX_STANDARD} - COMMAND CXX=${CLANG_TOOL} ${CMAKE_COMMAND} + COMMAND CXX=${CLANG_TOOL} CXXFLAGS="${CLANG_CXXFLAGS}" ${CMAKE_COMMAND} -DCMAKE_BUILD_TYPE=Debug -GNinja - -DCMAKE_CXX_STANDARD=${CXX_STANDARD} -DCMAKE_CXX_STANDARD_REQUIRED=ON - -DJSON_BuildTests=ON + -DJSON_BuildTests=ON -DJSON_FastTests=ON + -DJSON_TestStandards=${CXX_STANDARD} -S${PROJECT_SOURCE_DIR} -B${PROJECT_BINARY_DIR}/build_clang_cxx${CXX_STANDARD} COMMAND ${CMAKE_COMMAND} --build ${PROJECT_BINARY_DIR}/build_clang_cxx${CXX_STANDARD} COMMAND cd ${PROJECT_BINARY_DIR}/build_clang_cxx${CXX_STANDARD} && ${CMAKE_CTEST_COMMAND} --parallel ${N} --output-on-failure @@ -769,50 +769,67 @@ add_custom_target(ci_benchmarks # CMake flags ############################################################################### -if (APPLE) - set(CMAKE_310_BINARY ${PROJECT_BINARY_DIR}/cmake-3.1.0-Darwin64/CMake.app/Contents/bin/cmake) - add_custom_command( - OUTPUT ${CMAKE_310_BINARY} - COMMAND wget https://github.com/Kitware/CMake/releases/download/v3.1.0/cmake-3.1.0-Darwin64.tar.gz - COMMAND tar xfz cmake-3.1.0-Darwin64.tar.gz - COMMAND rm cmake-3.1.0-Darwin64.tar.gz - WORKING_DIRECTORY ${PROJECT_BINARY_DIR} - COMMENT "Download CMake 3.1.0" - ) -else() - set(CMAKE_310_BINARY ${PROJECT_BINARY_DIR}/cmake-3.1.0-Linux-x86_64/bin/cmake) - add_custom_command( - OUTPUT ${CMAKE_310_BINARY} - COMMAND wget https://github.com/Kitware/CMake/releases/download/v3.1.0/cmake-3.1.0-Linux-x86_64.tar.gz - COMMAND tar xfz cmake-3.1.0-Linux-x86_64.tar.gz - COMMAND rm cmake-3.1.0-Linux-x86_64.tar.gz - WORKING_DIRECTORY ${PROJECT_BINARY_DIR} - COMMENT "Download CMake 3.1.0" - ) -endif() +function(ci_get_cmake version var) + if (APPLE) + set(${var} ${PROJECT_BINARY_DIR}/cmake-${version}-Darwin64/CMake.app/Contents/bin/cmake) + add_custom_command( + OUTPUT ${${var}} + COMMAND wget -nc https://github.com/Kitware/CMake/releases/download/v${version}/cmake-${version}-Darwin64.tar.gz + COMMAND tar xfz cmake-${version}-Darwin64.tar.gz + COMMAND rm cmake-${version}-Darwin64.tar.gz + WORKING_DIRECTORY ${PROJECT_BINARY_DIR} + COMMENT "Download CMake ${version}" + ) + else() + set(${var} ${PROJECT_BINARY_DIR}/cmake-${version}-Linux-x86_64/bin/cmake) + add_custom_command( + OUTPUT ${${var}} + COMMAND wget -nc https://github.com/Kitware/CMake/releases/download/v${version}/cmake-${version}-Linux-x86_64.tar.gz + COMMAND tar xfz cmake-${version}-Linux-x86_64.tar.gz + COMMAND rm cmake-${version}-Linux-x86_64.tar.gz + WORKING_DIRECTORY ${PROJECT_BINARY_DIR} + COMMENT "Download CMake ${version}" + ) + endif() + set(${var} ${${var}} PARENT_SCOPE) +endfunction() -set(JSON_CMAKE_FLAGS "JSON_BuildTests;JSON_Install;JSON_MultipleHeaders;JSON_ImplicitConversions;JSON_Valgrind;JSON_Diagnostics;JSON_SystemInclude") +ci_get_cmake(3.1.0 CMAKE_3_1_0_BINARY) +ci_get_cmake(3.13.0 CMAKE_3_13_0_BINARY) -foreach(JSON_CMAKE_FLAG ${JSON_CMAKE_FLAGS}) - string(TOLOWER "ci_cmake_flag_${JSON_CMAKE_FLAG}" JSON_CMAKE_FLAG_TARGET) - add_custom_target("${JSON_CMAKE_FLAG_TARGET}" - COMMENT "Check CMake flag ${JSON_CMAKE_FLAG} (CMake ${CMAKE_VERSION})" +set(JSON_CMAKE_FLAGS_3_1_0 "JSON_Install;JSON_MultipleHeaders;JSON_ImplicitConversions;JSON_Valgrind;JSON_Diagnostics;JSON_SystemInclude") +set(JSON_CMAKE_FLAGS_3_13_0 "JSON_BuildTests") + +function(ci_add_cmake_flags_targets flag min_version) + string(TOLOWER "ci_cmake_flag_${flag}" flag_target) + string(REPLACE . _ min_version_var ${min_version}) + set(cmake_binary ${CMAKE_${min_version_var}_BINARY}) + add_custom_target(${flag_target} + COMMENT "Check CMake flag ${flag} (CMake ${CMAKE_VERSION})" COMMAND ${CMAKE_COMMAND} -Werror=dev - -D${JSON_CMAKE_FLAG}=ON - -S${PROJECT_SOURCE_DIR} -B${PROJECT_BINARY_DIR}/build_${JSON_CMAKE_FLAG_TARGET} + -D${flag}=ON + -S${PROJECT_SOURCE_DIR} -B${PROJECT_BINARY_DIR}/build_${flag_target} ) - add_custom_target("${JSON_CMAKE_FLAG_TARGET}_31" - COMMENT "Check CMake flag ${JSON_CMAKE_FLAG} (CMake 3.1)" - COMMAND mkdir ${PROJECT_BINARY_DIR}/build_${JSON_CMAKE_FLAG_TARGET}_31 - COMMAND cd ${PROJECT_BINARY_DIR}/build_${JSON_CMAKE_FLAG_TARGET}_31 && ${CMAKE_310_BINARY} - -Werror=dev ${PROJECT_SOURCE_DIR} - -D${JSON_CMAKE_FLAG}=ON - -DCMAKE_CXX_COMPILE_FEATURES="cxx_range_for" -DCMAKE_CXX_FLAGS="-std=gnu++11" - DEPENDS ${CMAKE_310_BINARY} + add_custom_target(${flag_target}_${min_version_var} + COMMENT "Check CMake flag ${JSON_CMAKE_FLAG} (CMake ${min_version})" + COMMAND mkdir -pv ${PROJECT_BINARY_DIR}/build_${flag_target}_${min_version_var} + COMMAND cd ${PROJECT_BINARY_DIR}/build_${flag_target}_${min_version_var} + && ${cmake_binary} -Werror=dev ${PROJECT_SOURCE_DIR} -D${flag}=ON + DEPENDS ${cmake_binary} ) - list(APPEND JSON_CMAKE_FLAG_TARGETS ${JSON_CMAKE_FLAG_TARGET} ${JSON_CMAKE_FLAG_TARGET}_31) - list(APPEND JSON_CMAKE_FLAG_BUILD_DIRS ${PROJECT_BINARY_DIR}/build_${JSON_CMAKE_FLAG_TARGET} ${PROJECT_BINARY_DIR}/build_${JSON_CMAKE_FLAG_TARGET}_31) + list(APPEND JSON_CMAKE_FLAG_TARGETS ${JSON_CMAKE_FLAG_TARGET} ${flag_target}_${min_version_var}) + list(APPEND JSON_CMAKE_FLAG_BUILD_DIRS ${PROJECT_BINARY_DIR}/build_${flag_target} ${PROJECT_BINARY_DIR}/build_${flag_target}_${min_version_var}) + set(JSON_CMAKE_FLAG_TARGETS ${JSON_CMAKE_FLAG_TARGETS} PARENT_SCOPE) + set(JSON_CMAKE_FLAG_BUILD_DIRS ${JSON_CMAKE_FLAG_BUILD_DIRS} PARENT_SCOPE) +endfunction() + +foreach(JSON_CMAKE_FLAG ${JSON_CMAKE_FLAGS_3_1_0}) + ci_add_cmake_flags_targets(${JSON_CMAKE_FLAG} 3.1.0) +endforeach() + +foreach(JSON_CMAKE_FLAG ${JSON_CMAKE_FLAGS_3_13_0}) + ci_add_cmake_flags_targets(${JSON_CMAKE_FLAG} 3.13.0) endforeach() add_custom_target(ci_cmake_flags diff --git a/cmake/test.cmake b/cmake/test.cmake new file mode 100644 index 000000000..1d146646b --- /dev/null +++ b/cmake/test.cmake @@ -0,0 +1,204 @@ +set(_json_test_cmake_list_file ${CMAKE_CURRENT_LIST_FILE}) + +############################################################################# +# download test data +############################################################################# + +include(download_test_data) + +# test fixture to download test data +add_test(NAME "download_test_data" COMMAND ${CMAKE_COMMAND} --build ${CMAKE_BINARY_DIR} + --target download_test_data +) +set_tests_properties(download_test_data PROPERTIES FIXTURES_SETUP TEST_DATA) + +if(JSON_Valgrind) + find_program(CMAKE_MEMORYCHECK_COMMAND valgrind) + message(STATUS "Executing test suite with Valgrind (${CMAKE_MEMORYCHECK_COMMAND})") + set(memcheck_command "${CMAKE_MEMORYCHECK_COMMAND} ${CMAKE_MEMORYCHECK_COMMAND_OPTIONS} --error-exitcode=1 --leak-check=full") + separate_arguments(memcheck_command) +endif() + +############################################################################# +# detect standard support +############################################################################# + +# C++11 is the minimum required +set(compiler_supports_cpp_11 TRUE) + +foreach(feature ${CMAKE_CXX_COMPILE_FEATURES}) + if (${feature} STREQUAL cxx_std_14) + set(compiler_supports_cpp_14 TRUE) + elseif (${feature} STREQUAL cxx_std_17) + set(compiler_supports_cpp_17 TRUE) + elseif (${feature} STREQUAL cxx_std_20) + set(compiler_supports_cpp_20 TRUE) + elseif (${feature} STREQUAL cxx_std_23) + set(compiler_supports_cpp_23 TRUE) + endif() +endforeach() + +############################################################################# +# test functions +############################################################################# + +############################################################################# +# json_test_set_test_options( +# all| +# [CXX_STANDARDS all|...] +# [COMPILE_DEFINITIONS ...] +# [COMPILE_FEATURES ...] +# [COMPILE_OPTIONS ...] +# [LINK_LIBRARIES ...] +# [LINK_OPTIONS ...]) +# +# Supply test- and standard-specific build settings. +# Specify multiple tests using a list e.g., "test-foo;test-bar". +# +# Must be called BEFORE the test is created. +############################################################################# + +function(json_test_set_test_options tests) + cmake_parse_arguments(args "" "" + "CXX_STANDARDS;COMPILE_DEFINITIONS;COMPILE_FEATURES;COMPILE_OPTIONS;LINK_LIBRARIES;LINK_OPTIONS" + ${ARGN}) + + if(NOT args_CXX_STANDARDS) + set(args_CXX_STANDARDS "all") + endif() + + foreach(test ${tests}) + if("${test}" STREQUAL "all") + set(test "") + endif() + + foreach(cxx_standard ${args_CXX_STANDARDS}) + if("${cxx_standard}" STREQUAL "all") + if("${test}" STREQUAL "") + message(FATAL_ERROR "Not supported. Change defaults in: ${_json_test_cmake_list_file}") + endif() + set(test_interface _json_test_interface_${test}) + else() + set(test_interface _json_test_interface_${test}_cpp_${cxx_standard}) + endif() + + if(NOT TARGET ${test_interface}) + add_library(${test_interface} INTERFACE) + endif() + + target_compile_definitions(${test_interface} INTERFACE ${args_COMPILE_DEFINITIONS}) + target_compile_features(${test_interface} INTERFACE ${args_COMPILE_FEATURES}) + target_compile_options(${test_interface} INTERFACE ${args_COMPILE_OPTIONS}) + target_link_libraries (${test_interface} INTERFACE ${args_LINK_LIBRARIES}) + target_link_options(${test_interface} INTERFACE ${args_LINK_OPTIONS}) + endforeach() + endforeach() +endfunction() + +# for internal use by json_test_add_test_for() +function(_json_test_add_test test_name file main cxx_standard) + set(test_target ${test_name}_cpp${cxx_standard}) + + if(TARGET ${test_target}) + message(FATAL_ERROR "Target ${test_target} has already been added.") + endif() + + add_executable(${test_target} ${file}) + target_link_libraries(${test_target} PRIVATE ${main}) + + # set and require C++ standard + set_target_properties(${test_target} PROPERTIES + CXX_STANDARD ${cxx_standard} + CXX_STANDARD_REQUIRED ON + ) + + # apply standard-specific build settings + if(TARGET _json_test_interface__cpp_${cxx_standard}) + target_link_libraries(${test_target} PRIVATE _json_test_interface__cpp_${cxx_standard}) + endif() + + # apply test-specific build settings + if(TARGET _json_test_interface_${test_name}) + target_link_libraries(${test_target} PRIVATE _json_test_interface_${test_name}) + endif() + + # apply test- and standard-specific build settings + if(TARGET _json_test_interface_${test_name}_cpp_${cxx_standard}) + target_link_libraries(${test_target} PRIVATE + _json_test_interface_${test_name}_cpp_${cxx_standard} + ) + endif() + + if (JSON_FastTests) + add_test(NAME ${test_target} + COMMAND ${test_target} ${DOCTEST_TEST_FILTER} + WORKING_DIRECTORY ${CMAKE_SOURCE_DIR} + ) + else() + add_test(NAME ${test_target} + COMMAND ${test_target} ${DOCTEST_TEST_FILTER} --no-skip + WORKING_DIRECTORY ${CMAKE_SOURCE_DIR} + ) + endif() + set_tests_properties(${test_target} PROPERTIES LABELS "all" FIXTURES_REQUIRED TEST_DATA) + + if(JSON_Valgrind) + add_test(NAME ${test_target}_valgrind + COMMAND ${memcheck_command} $ ${DOCTEST_TEST_FILTER} + WORKING_DIRECTORY ${CMAKE_SOURCE_DIR} + ) + set_tests_properties(${test_target}_valgrind PROPERTIES + LABELS "valgrind" FIXTURES_REQUIRED TEST_DATA + ) + endif() +endfunction() + +############################################################################# +# json_test_add_test_for( +# +# MAIN
+# [CXX_STANDARDS ...] [FORCE]) +# +# Given a unit-foo.cpp, produces +# +# test-foo_cpp +# +# if C++ standard is supported by the compiler and the +# source file contains JSON_HAS_CPP_. +# Use FORCE to create the test regardless of the file containing +# JSON_HAS_CPP_. +# Test targets are linked against
. +# CXX_STANDARDS defaults to "11". +############################################################################# + +function(json_test_add_test_for file) + cmake_parse_arguments(args "FORCE" "MAIN" "CXX_STANDARDS" ${ARGN}) + + get_filename_component(file_basename ${file} NAME_WE) + string(REGEX REPLACE "unit-([^$]+)" "test-\\1" test_name ${file_basename}) + + if("${args_MAIN}" STREQUAL "") + message(FATAL_ERROR "Required argument MAIN
missing.") + endif() + + if("${args_CXX_STANDARDS}" STREQUAL "") + set(args_CXX_STANDARDS 11) + endif() + + file(READ ${file} file_content) + foreach(cxx_standard ${args_CXX_STANDARDS}) + if(NOT compiler_supports_cpp_${cxx_standard}) + continue() + endif() + + # add unconditionally if C++11 (default) or forced + if(NOT ("${cxx_standard}" STREQUAL 11 OR args_FORCE)) + string(FIND "${file_content}" JSON_HAS_CPP_${cxx_standard} has_cpp_found) + if(${has_cpp_found} EQUAL -1) + continue() + endif() + endif() + + _json_test_add_test(${test_name} ${file} ${args_MAIN} ${cxx_standard}) + endforeach() +endfunction() diff --git a/include/nlohmann/detail/conversions/from_json.hpp b/include/nlohmann/detail/conversions/from_json.hpp index 207d3e302..fbb176879 100644 --- a/include/nlohmann/detail/conversions/from_json.hpp +++ b/include/nlohmann/detail/conversions/from_json.hpp @@ -464,7 +464,8 @@ void from_json(const BasicJsonType& j, std_fs::path& p) { if (JSON_HEDLEY_UNLIKELY(!j.is_string())) { - JSON_THROW(type_error::create(302, "type must be string, but is " + std::string(j.type_name()), j)); + // Not tested because of #3377 (related #3070) + JSON_THROW(type_error::create(302, "type must be string, but is " + std::string(j.type_name()), j)); // LCOV_EXCL_LINE } p = *j.template get_ptr(); } diff --git a/include/nlohmann/detail/macro_scope.hpp b/include/nlohmann/detail/macro_scope.hpp index 87f964353..f636b908a 100644 --- a/include/nlohmann/detail/macro_scope.hpp +++ b/include/nlohmann/detail/macro_scope.hpp @@ -97,6 +97,15 @@ #define JSON_HAS_FILESYSTEM 0 #endif +#ifndef JSON_HAS_THREE_WAY_COMPARISON + #if defined(__cpp_lib_three_way_comparison) && __cpp_lib_three_way_comparison >= 201907L \ + && defined(__cpp_impl_three_way_comparison)&& __cpp_impl_three_way_comparison >= 201907L + #define JSON_HAS_THREE_WAY_COMPARISON 1 + #else + #define JSON_HAS_THREE_WAY_COMPARISON 0 + #endif +#endif + // disable documentation warnings on clang #if defined(__clang__) #pragma clang diagnostic push diff --git a/include/nlohmann/detail/macro_unscope.hpp b/include/nlohmann/detail/macro_unscope.hpp index 1a29fb5e0..377d3f11d 100644 --- a/include/nlohmann/detail/macro_unscope.hpp +++ b/include/nlohmann/detail/macro_unscope.hpp @@ -8,19 +8,23 @@ // clean up #undef JSON_ASSERT #undef JSON_INTERNAL_CATCH -#undef JSON_CATCH #undef JSON_THROW -#undef JSON_TRY #undef JSON_PRIVATE_UNLESS_TESTED -#undef JSON_HAS_CPP_11 -#undef JSON_HAS_CPP_14 -#undef JSON_HAS_CPP_17 -#undef JSON_HAS_CPP_20 -#undef JSON_HAS_FILESYSTEM -#undef JSON_HAS_EXPERIMENTAL_FILESYSTEM #undef NLOHMANN_BASIC_JSON_TPL_DECLARATION #undef NLOHMANN_BASIC_JSON_TPL #undef JSON_EXPLICIT #undef NLOHMANN_CAN_CALL_STD_FUNC_IMPL +#ifndef JSON_TEST_KEEP_MACROS + #undef JSON_CATCH + #undef JSON_TRY + #undef JSON_HAS_CPP_11 + #undef JSON_HAS_CPP_14 + #undef JSON_HAS_CPP_17 + #undef JSON_HAS_CPP_20 + #undef JSON_HAS_FILESYSTEM + #undef JSON_HAS_EXPERIMENTAL_FILESYSTEM + #undef JSON_HAS_THREE_WAY_COMPARISON +#endif + #include diff --git a/include/nlohmann/detail/meta/cpp_future.hpp b/include/nlohmann/detail/meta/cpp_future.hpp index 147f2fa35..ef2da370d 100644 --- a/include/nlohmann/detail/meta/cpp_future.hpp +++ b/include/nlohmann/detail/meta/cpp_future.hpp @@ -147,8 +147,12 @@ struct static_const static constexpr T value{}; }; -template -constexpr T static_const::value; // NOLINT(readability-redundant-declaration) +#ifndef JSON_HAS_CPP_17 + + template + constexpr T static_const::value; // NOLINT(readability-redundant-declaration) + +#endif } // namespace detail } // namespace nlohmann diff --git a/single_include/nlohmann/json.hpp b/single_include/nlohmann/json.hpp index 05000fbba..71f6814ad 100644 --- a/single_include/nlohmann/json.hpp +++ b/single_include/nlohmann/json.hpp @@ -2394,6 +2394,15 @@ using is_detected_convertible = #define JSON_HAS_FILESYSTEM 0 #endif +#ifndef JSON_HAS_THREE_WAY_COMPARISON + #if defined(__cpp_lib_three_way_comparison) && __cpp_lib_three_way_comparison >= 201907L \ + && defined(__cpp_impl_three_way_comparison)&& __cpp_impl_three_way_comparison >= 201907L + #define JSON_HAS_THREE_WAY_COMPARISON 1 + #else + #define JSON_HAS_THREE_WAY_COMPARISON 0 + #endif +#endif + // disable documentation warnings on clang #if defined(__clang__) #pragma clang diagnostic push @@ -3182,8 +3191,12 @@ struct static_const static constexpr T value{}; }; -template -constexpr T static_const::value; // NOLINT(readability-redundant-declaration) +#ifndef JSON_HAS_CPP_17 + + template + constexpr T static_const::value; // NOLINT(readability-redundant-declaration) + +#endif } // namespace detail } // namespace nlohmann @@ -4266,7 +4279,8 @@ void from_json(const BasicJsonType& j, std_fs::path& p) { if (JSON_HEDLEY_UNLIKELY(!j.is_string())) { - JSON_THROW(type_error::create(302, "type must be string, but is " + std::string(j.type_name()), j)); + // Not tested because of #3377 (related #3070) + JSON_THROW(type_error::create(302, "type must be string, but is " + std::string(j.type_name()), j)); // LCOV_EXCL_LINE } p = *j.template get_ptr(); } @@ -21939,21 +21953,25 @@ inline nlohmann::json::json_pointer operator "" _json_pointer(const char* s, std // clean up #undef JSON_ASSERT #undef JSON_INTERNAL_CATCH -#undef JSON_CATCH #undef JSON_THROW -#undef JSON_TRY #undef JSON_PRIVATE_UNLESS_TESTED -#undef JSON_HAS_CPP_11 -#undef JSON_HAS_CPP_14 -#undef JSON_HAS_CPP_17 -#undef JSON_HAS_CPP_20 -#undef JSON_HAS_FILESYSTEM -#undef JSON_HAS_EXPERIMENTAL_FILESYSTEM #undef NLOHMANN_BASIC_JSON_TPL_DECLARATION #undef NLOHMANN_BASIC_JSON_TPL #undef JSON_EXPLICIT #undef NLOHMANN_CAN_CALL_STD_FUNC_IMPL +#ifndef JSON_TEST_KEEP_MACROS + #undef JSON_CATCH + #undef JSON_TRY + #undef JSON_HAS_CPP_11 + #undef JSON_HAS_CPP_14 + #undef JSON_HAS_CPP_17 + #undef JSON_HAS_CPP_20 + #undef JSON_HAS_FILESYSTEM + #undef JSON_HAS_EXPERIMENTAL_FILESYSTEM + #undef JSON_HAS_THREE_WAY_COMPARISON +#endif + // #include diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index c29662134..90c325861 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -1,163 +1,131 @@ +cmake_minimum_required(VERSION 3.13) + option(JSON_Valgrind "Execute test suite with Valgrind." OFF) option(JSON_FastTests "Skip expensive/slow tests." OFF) -# download test data -include(${CMAKE_CURRENT_SOURCE_DIR}/../cmake/download_test_data.cmake) +set(JSON_TestStandards "" CACHE STRING "The list of standards to test explicitly.") -# test fixture to download test data -add_test(NAME "download_test_data" COMMAND ${CMAKE_COMMAND} --build ${CMAKE_BINARY_DIR} --target download_test_data) -set_tests_properties(download_test_data PROPERTIES FIXTURES_SETUP TEST_DATA) +include(test) -if(JSON_Valgrind) - find_program(CMAKE_MEMORYCHECK_COMMAND valgrind) - message(STATUS "Executing test suite with Valgrind (${CMAKE_MEMORYCHECK_COMMAND})") - set(memcheck_command "${CMAKE_MEMORYCHECK_COMMAND} ${CMAKE_MEMORYCHECK_COMMAND_OPTIONS} --error-exitcode=1 --leak-check=full") - separate_arguments(memcheck_command) +############################################################################# +# override standard support +############################################################################# + +# compiling json.hpp in C++14 mode fails with Clang <4.0 +if (CMAKE_CXX_COMPILER_ID STREQUAL "Clang" AND CMAKE_CXX_COMPILER_VERSION VERSION_LESS 4.0) + unset(compiler_supports_cpp_14) endif() -############################################################################# -# doctest library with the main function to speed up build -############################################################################# - -add_library(doctest_main OBJECT src/unit.cpp) -set_target_properties(doctest_main PROPERTIES - COMPILE_DEFINITIONS "$<$:_SCL_SECURE_NO_WARNINGS>" - COMPILE_OPTIONS "$<$:/EHsc;$<$:/Od>>" -) -if (${CMAKE_VERSION} VERSION_LESS "3.8.0") - target_compile_features(doctest_main PUBLIC cxx_range_for) -else() - target_compile_features(doctest_main PUBLIC cxx_std_11) -endif() -target_include_directories(doctest_main PRIVATE "thirdparty/doctest") - -# https://stackoverflow.com/questions/2368811/how-to-set-warning-level-in-cmake -if(MSVC) - # Force to always compile with W4 - if(CMAKE_CXX_FLAGS MATCHES "/W[0-4]") - string(REGEX REPLACE "/W[0-4]" "/W4" CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS}") - else() - set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /W4") - endif() - - # Disable warning C4566: character represented by universal-character-name '\uFF01' cannot be represented in the current code page (1252) - # Disable warning C4996: 'nlohmann::basic_json::operator <<': was declared deprecated - set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /wd4566 /wd4996") - - # https://github.com/nlohmann/json/issues/1114 - set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} /bigobj") -endif() - -############################################################################# -# one executable for each unit test file -############################################################################# - -# check if compiler supports C++17 -foreach(feature ${CMAKE_CXX_COMPILE_FEATURES}) - if (${feature} STREQUAL cxx_std_17) - set(compiler_supports_cpp_17 TRUE) - endif() -endforeach() # Clang only supports C++17 starting from Clang 5.0 -if ("${CMAKE_CXX_COMPILER_ID}" MATCHES "Clang" AND CMAKE_CXX_COMPILER_VERSION VERSION_LESS 5.0) +if (CMAKE_CXX_COMPILER_ID STREQUAL "Clang" AND CMAKE_CXX_COMPILER_VERSION VERSION_LESS 5.0) unset(compiler_supports_cpp_17) endif() # MSVC 2015 (14.0) does not support C++17 -if ("${CMAKE_CXX_COMPILER_ID}" MATCHES "MSVC" AND CMAKE_CXX_COMPILER_VERSION VERSION_LESS 19.1) +if (CMAKE_CXX_COMPILER_ID STREQUAL "MSVC" AND CMAKE_CXX_COMPILER_VERSION VERSION_LESS 19.1) unset(compiler_supports_cpp_17) endif() -file(GLOB files src/unit-*.cpp) +# Clang C++20 support appears insufficient prior to Clang 9.0 (based on CI build failure) +if (CMAKE_CXX_COMPILER_ID STREQUAL "Clang" AND CMAKE_CXX_COMPILER_VERSION VERSION_LESS 9.0) + unset(compiler_supports_cpp_20) +endif() +# GCC started supporting C++20 features in 8.0 but a test for #3070 segfaults prior to 9.0 +if (CMAKE_CXX_COMPILER_ID STREQUAL "GNU" AND CMAKE_CXX_COMPILER_VERSION VERSION_LESS 9.0) + unset(compiler_supports_cpp_20) +endif() -foreach(file ${files}) - get_filename_component(file_basename ${file} NAME_WE) - string(REGEX REPLACE "unit-([^$]+)" "test-\\1" testcase ${file_basename}) +############################################################################# +# test_main library with shared code to speed up build and common settings +############################################################################# - add_executable(${testcase} $ ${file}) - target_compile_definitions(${testcase} PRIVATE DOCTEST_CONFIG_SUPER_FAST_ASSERTS) - target_compile_options(${testcase} PRIVATE - $<$:/EHsc;$<$:/Od>> - $<$>:-Wno-deprecated;-Wno-float-equal> - $<$:-Wno-deprecated-declarations> - ) - target_include_directories(${testcase} PRIVATE ${CMAKE_BINARY_DIR}/include thirdparty/doctest thirdparty/fifo_map) - target_link_libraries(${testcase} PRIVATE ${NLOHMANN_JSON_TARGET_NAME}) +add_library(test_main OBJECT src/unit.cpp) +target_compile_definitions(test_main PUBLIC + DOCTEST_CONFIG_SUPER_FAST_ASSERTS + JSON_TEST_KEEP_MACROS +) +target_compile_features(test_main PRIVATE cxx_std_11) +target_compile_options(test_main PUBLIC + $<$:/EHsc;$<$:/Od>> + # MSVC: Force to always compile with W4 + # Disable warning C4566: character represented by universal-character-name '\uFF01' + # cannot be represented in the current code page (1252) + # Disable warning C4996: 'nlohmann::basic_json<...>::operator <<': was declared deprecated + $<$:/W4 /wd4566 /wd4996> + # https://github.com/nlohmann/json/issues/1114 + $<$:/bigobj> $<$:-Wa,-mbig-obj> - # add a copy with C++17 compilation - if (compiler_supports_cpp_17) - file(READ ${file} FILE_CONTENT) - string(FIND "${FILE_CONTENT}" "JSON_HAS_CPP_17" CPP_17_FOUND) - if(NOT ${CPP_17_FOUND} EQUAL -1) - add_executable(${testcase}_cpp17 $ ${file}) - target_compile_definitions(${testcase}_cpp17 PRIVATE DOCTEST_CONFIG_SUPER_FAST_ASSERTS) - target_compile_options(${testcase}_cpp17 PRIVATE - $<$:/EHsc;$<$:/Od>> - $<$>:-Wno-deprecated;-Wno-float-equal> - $<$:-Wno-deprecated-declarations> - ) - target_include_directories(${testcase}_cpp17 PRIVATE ${CMAKE_BINARY_DIR}/include thirdparty/doctest thirdparty/fifo_map) - target_link_libraries(${testcase}_cpp17 PRIVATE ${NLOHMANN_JSON_TARGET_NAME}) - target_compile_features(${testcase}_cpp17 PRIVATE cxx_std_17) + $<$>:-Wno-deprecated;-Wno-float-equal> + $<$:-Wno-deprecated-declarations> +) +target_include_directories(test_main PUBLIC + thirdparty/doctest + thirdparty/fifo_map + ${PROJECT_BINARY_DIR}/include +) +target_link_libraries(test_main PUBLIC ${NLOHMANN_JSON_TARGET_NAME}) - if (CMAKE_CXX_COMPILER_ID STREQUAL "GNU" AND CMAKE_CXX_COMPILER_VERSION VERSION_GREATER_EQUAL 8.0 AND CMAKE_CXX_COMPILER_VERSION VERSION_LESS 9.0 AND NOT MINGW) - # fix for https://gcc.gnu.org/bugzilla/show_bug.cgi?id=90050 - target_link_libraries(${testcase}_cpp17 PRIVATE stdc++fs) - endif() +############################################################################# +# define test- and standard-specific build settings +############################################################################# - if (JSON_FastTests) - add_test(NAME "${testcase}_cpp17" - COMMAND ${testcase}_cpp17 ${DOCTEST_TEST_FILTER} - WORKING_DIRECTORY ${CMAKE_SOURCE_DIR} - ) - else() - add_test(NAME "${testcase}_cpp17" - COMMAND ${testcase}_cpp17 ${DOCTEST_TEST_FILTER} --no-skip - WORKING_DIRECTORY ${CMAKE_SOURCE_DIR} - ) - endif() - set_tests_properties("${testcase}_cpp17" PROPERTIES LABELS "all" FIXTURES_REQUIRED TEST_DATA) - endif() - endif() +if (CMAKE_CXX_COMPILER_ID STREQUAL "GNU" + AND CMAKE_CXX_COMPILER_VERSION VERSION_GREATER_EQUAL 8.0 + AND CMAKE_CXX_COMPILER_VERSION VERSION_LESS 9.0 AND NOT MINGW) + # fix for https://gcc.gnu.org/bugzilla/show_bug.cgi?id=90050 + json_test_set_test_options(all CXX_STANDARDS 17 LINK_LIBRARIES stdc++fs) +endif() - if (JSON_FastTests) - add_test(NAME "${testcase}" - COMMAND ${testcase} ${DOCTEST_TEST_FILTER} - WORKING_DIRECTORY ${CMAKE_SOURCE_DIR} - ) - else() - add_test(NAME "${testcase}" - COMMAND ${testcase} ${DOCTEST_TEST_FILTER} --no-skip - WORKING_DIRECTORY ${CMAKE_SOURCE_DIR} - ) - endif() - set_tests_properties("${testcase}" PROPERTIES LABELS "all" FIXTURES_REQUIRED TEST_DATA) - - if(JSON_Valgrind) - add_test(NAME "${testcase}_valgrind" - COMMAND ${memcheck_command} ${CMAKE_CURRENT_BINARY_DIR}/${testcase} ${DOCTEST_TEST_FILTER} - WORKING_DIRECTORY ${CMAKE_SOURCE_DIR} - ) - set_tests_properties("${testcase}_valgrind" PROPERTIES LABELS "valgrind" FIXTURES_REQUIRED TEST_DATA) - endif() -endforeach() +if (CMAKE_CXX_COMPILER_ID STREQUAL "MSVC") + # avoid stack overflow, see https://github.com/nlohmann/json/issues/2955 + json_test_set_test_options("test-cbor;test-msgpack;test-ubjson" LINK_OPTIONS /STACK:4000000) +endif() # disable exceptions for test-disabled_exceptions -target_compile_definitions(test-disabled_exceptions PUBLIC JSON_NOEXCEPTION) +json_test_set_test_options(test-disabled_exceptions COMPILE_DEFINITIONS JSON_NOEXCEPTION) if (CMAKE_CXX_COMPILER_ID STREQUAL "Clang" OR CMAKE_CXX_COMPILER_ID STREQUAL "AppleClang" OR CMAKE_CXX_COMPILER_ID STREQUAL "GNU") - target_compile_options(test-disabled_exceptions PUBLIC -fno-exceptions) +json_test_set_test_options(test-disabled_exceptions COMPILE_OPTIONS -fno-exceptions) elseif (CMAKE_CXX_COMPILER_ID STREQUAL "MSVC") # disabled due to https://github.com/nlohmann/json/discussions/2824 - #target_compile_options(test-disabled_exceptions PUBLIC /EH) - #target_compile_definitions(test-disabled_exceptions PUBLIC _HAS_EXCEPTIONS=0) + #json_test_set_test_options(test-disabled_exceptions COMPILE_DEFINITIONS _HAS_EXCEPTIONS=0 COMPILE_OPTIONS /EH) endif() -# avoid stack overflow, see https://github.com/nlohmann/json/issues/2955 -if (CMAKE_CXX_COMPILER_ID STREQUAL "MSVC") - set_property(TARGET test-cbor APPEND_STRING PROPERTY LINK_FLAGS " /STACK:4000000") - set_property(TARGET test-msgpack APPEND_STRING PROPERTY LINK_FLAGS " /STACK:4000000") - set_property(TARGET test-ubjson APPEND_STRING PROPERTY LINK_FLAGS " /STACK:4000000") +############################################################################# +# add unit tests +############################################################################# + +if("${JSON_TestStandards}" STREQUAL "") + set(test_cxx_standards 11 14 17 20 23) + unset(test_force) +else() + set(test_cxx_standards ${JSON_TestStandards}) + set(test_force FORCE) endif() +# Print selected standards marking unavailable ones with brackets +set(msg_standards "") +foreach(cxx_standard ${test_cxx_standards}) + if(compiler_supports_cpp_${cxx_standard}) + list(APPEND msg_standards ${cxx_standard}) + else() + list(APPEND msg_standards [${cxx_standard}]) + endif() +endforeach() +string(JOIN " " msg_standards ${msg_standards}) +set(msg "Testing standards: ${msg_standards}") +if(test_force) + string(APPEND msg " (forced)") +endif() +message(STATUS "${msg}") + +# *DO* use json_test_set_test_options() above this line + +file(GLOB files src/unit-*.cpp) +foreach(file ${files}) + json_test_add_test_for(${file} MAIN test_main CXX_STANDARDS ${test_cxx_standards} ${test_force}) +endforeach() + +# *DO NOT* use json_test_set_test_options() below this line + ############################################################################# # Test the generated build configs ############################################################################# diff --git a/test/src/unit-alt-string.cpp b/test/src/unit-alt-string.cpp index 7da69dea1..bcde18b75 100644 --- a/test/src/unit-alt-string.cpp +++ b/test/src/unit-alt-string.cpp @@ -37,7 +37,7 @@ SOFTWARE. /* forward declarations */ class alt_string; -bool operator<(const char* op1, const alt_string& op2); +bool operator<(const char* op1, const alt_string& op2) noexcept; void int_to_string(alt_string& target, std::size_t value); /* @@ -152,7 +152,7 @@ class alt_string private: std::string str_impl {}; - friend bool ::operator<(const char* /*op1*/, const alt_string& /*op2*/); + friend bool ::operator<(const char* /*op1*/, const alt_string& /*op2*/) noexcept; }; void int_to_string(alt_string& target, std::size_t value) @@ -172,7 +172,7 @@ using alt_json = nlohmann::basic_json < nlohmann::adl_serializer >; -bool operator<(const char* op1, const alt_string& op2) +bool operator<(const char* op1, const alt_string& op2) noexcept { return op1 < op2.str_impl; } diff --git a/test/src/unit-cbor.cpp b/test/src/unit-cbor.cpp index 59ff2af01..4c23e821e 100644 --- a/test/src/unit-cbor.cpp +++ b/test/src/unit-cbor.cpp @@ -1609,7 +1609,7 @@ TEST_CASE("CBOR") // callback to set binary_seen to true if a binary value was seen bool binary_seen = false; - auto callback = [&binary_seen](int /*depth*/, json::parse_event_t /*event*/, json & parsed) + auto callback = [&binary_seen](int /*depth*/, json::parse_event_t /*event*/, json & parsed) noexcept { if (parsed.is_binary()) { diff --git a/test/src/unit-class_parser.cpp b/test/src/unit-class_parser.cpp index 78fc7dd55..dcbdc7f66 100644 --- a/test/src/unit-class_parser.cpp +++ b/test/src/unit-class_parser.cpp @@ -267,7 +267,7 @@ bool accept_helper(const std::string& s) CHECK(json::parser(nlohmann::detail::input_adapter(s)).accept(false) == !el.errored); // 5. parse with simple callback - json::parser_callback_t cb = [](int /*unused*/, json::parse_event_t /*unused*/, json& /*unused*/) + json::parser_callback_t cb = [](int /*unused*/, json::parse_event_t /*unused*/, json& /*unused*/) noexcept { return true; }; @@ -1499,7 +1499,7 @@ TEST_CASE("parser class") // test case to make sure the callback is properly evaluated after reading a key { - json::parser_callback_t cb = [](int /*unused*/, json::parse_event_t event, json& /*unused*/) + json::parser_callback_t cb = [](int /*unused*/, json::parse_event_t event, json& /*unused*/) noexcept { return event != json::parse_event_t::key; }; @@ -1538,14 +1538,14 @@ TEST_CASE("parser class") SECTION("filter nothing") { - json j_object = json::parse(s_object, [](int /*unused*/, json::parse_event_t /*unused*/, const json& /*unused*/) + json j_object = json::parse(s_object, [](int /*unused*/, json::parse_event_t /*unused*/, const json& /*unused*/) noexcept { return true; }); CHECK (j_object == json({{"foo", 2}, {"bar", {{"baz", 1}}}})); - json j_array = json::parse(s_array, [](int /*unused*/, json::parse_event_t /*unused*/, const json& /*unused*/) + json j_array = json::parse(s_array, [](int /*unused*/, json::parse_event_t /*unused*/, const json& /*unused*/) noexcept { return true; }); @@ -1555,7 +1555,7 @@ TEST_CASE("parser class") SECTION("filter everything") { - json j_object = json::parse(s_object, [](int /*unused*/, json::parse_event_t /*unused*/, const json& /*unused*/) + json j_object = json::parse(s_object, [](int /*unused*/, json::parse_event_t /*unused*/, const json& /*unused*/) noexcept { return false; }); @@ -1563,7 +1563,7 @@ TEST_CASE("parser class") // the top-level object will be discarded, leaving a null CHECK (j_object.is_null()); - json j_array = json::parse(s_array, [](int /*unused*/, json::parse_event_t /*unused*/, const json& /*unused*/) + json j_array = json::parse(s_array, [](int /*unused*/, json::parse_event_t /*unused*/, const json& /*unused*/) noexcept { return false; }); @@ -1574,7 +1574,7 @@ TEST_CASE("parser class") SECTION("filter specific element") { - json j_object = json::parse(s_object, [](int /*unused*/, json::parse_event_t /*unused*/, const json & j) + json j_object = json::parse(s_object, [](int /*unused*/, json::parse_event_t /*unused*/, const json & j) noexcept { // filter all number(2) elements return j != json(2); @@ -1582,7 +1582,7 @@ TEST_CASE("parser class") CHECK (j_object == json({{"bar", {{"baz", 1}}}})); - json j_array = json::parse(s_array, [](int /*unused*/, json::parse_event_t /*unused*/, const json & j) + json j_array = json::parse(s_array, [](int /*unused*/, json::parse_event_t /*unused*/, const json & j) noexcept { return j != json(2); }); @@ -1601,7 +1601,7 @@ TEST_CASE("parser class") CHECK (j_filtered1.size() == 2); CHECK (j_filtered1 == json({1, {{"qux", "baz"}}})); - json j_filtered2 = json::parse(structured_array, [](int /*unused*/, json::parse_event_t e, const json& /*parsed*/) + json j_filtered2 = json::parse(structured_array, [](int /*unused*/, json::parse_event_t e, const json& /*parsed*/) noexcept { return e != json::parse_event_t::object_end; }); @@ -1616,7 +1616,7 @@ TEST_CASE("parser class") SECTION("first closing event") { { - json j_object = json::parse(s_object, [](int /*unused*/, json::parse_event_t e, const json& /*unused*/) + json j_object = json::parse(s_object, [](int /*unused*/, json::parse_event_t e, const json& /*unused*/) noexcept { static bool first = true; if (e == json::parse_event_t::object_end && first) @@ -1633,7 +1633,7 @@ TEST_CASE("parser class") } { - json j_array = json::parse(s_array, [](int /*unused*/, json::parse_event_t e, const json& /*unused*/) + json j_array = json::parse(s_array, [](int /*unused*/, json::parse_event_t e, const json& /*unused*/) noexcept { static bool first = true; if (e == json::parse_event_t::array_end && first) @@ -1657,13 +1657,13 @@ TEST_CASE("parser class") // object and array is discarded only after the closing character // has been read - json j_empty_object = json::parse("{}", [](int /*unused*/, json::parse_event_t e, const json& /*unused*/) + json j_empty_object = json::parse("{}", [](int /*unused*/, json::parse_event_t e, const json& /*unused*/) noexcept { return e != json::parse_event_t::object_end; }); CHECK(j_empty_object == json()); - json j_empty_array = json::parse("[]", [](int /*unused*/, json::parse_event_t e, const json& /*unused*/) + json j_empty_array = json::parse("[]", [](int /*unused*/, json::parse_event_t e, const json& /*unused*/) noexcept { return e != json::parse_event_t::array_end; }); @@ -1731,7 +1731,7 @@ TEST_CASE("parser class") { SECTION("parser with callback") { - json::parser_callback_t cb = [](int /*unused*/, json::parse_event_t /*unused*/, json& /*unused*/) + json::parser_callback_t cb = [](int /*unused*/, json::parse_event_t /*unused*/, json& /*unused*/) noexcept { return true; }; diff --git a/test/src/unit-comparison.cpp b/test/src/unit-comparison.cpp index f4853f585..6c94add60 100644 --- a/test/src/unit-comparison.cpp +++ b/test/src/unit-comparison.cpp @@ -32,10 +32,6 @@ SOFTWARE. #include using nlohmann::json; -#if (defined(__cplusplus) && __cplusplus >= 202002L) || (defined(_MSVC_LANG) && _MSVC_LANG >= 202002L) - #define JSON_HAS_CPP_20 -#endif - namespace { // helper function to check std::less @@ -211,7 +207,7 @@ TEST_CASE("lexicographical comparison operators") { // Skip comparing indicies 12 and 13, and 13 and 12 in C++20 pending fix // See issue #3207 -#ifdef JSON_HAS_CPP_20 +#if defined(JSON_HAS_CPP_20) || JSON_HAS_THREE_WAY_COMPARISON if ((i == 12 && j == 13) || (i == 13 && j == 12)) { continue; diff --git a/test/src/unit-conversions.cpp b/test/src/unit-conversions.cpp index 092d5b8c3..d5cae7f29 100644 --- a/test/src/unit-conversions.cpp +++ b/test/src/unit-conversions.cpp @@ -41,13 +41,6 @@ using nlohmann::json; #include #include -#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 - // NLOHMANN_JSON_SERIALIZE_ENUM uses a static std::pair DOCTEST_CLANG_SUPPRESS_WARNING_PUSH DOCTEST_CLANG_SUPPRESS_WARNING("-Wexit-time-destructors") diff --git a/test/src/unit-items.cpp b/test/src/unit-items.cpp index f9021feb7..fa40f46d9 100644 --- a/test/src/unit-items.cpp +++ b/test/src/unit-items.cpp @@ -32,13 +32,6 @@ SOFTWARE. #include using nlohmann::json; -#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 - // This test suite uses range for loops where values are copied. This is inefficient in usual code, but required to achieve 100% coverage. DOCTEST_GCC_SUPPRESS_WARNING_PUSH DOCTEST_GCC_SUPPRESS_WARNING("-Wrange-loop-construct") diff --git a/test/src/unit-regression1.cpp b/test/src/unit-regression1.cpp index 8991b82af..2d22b5791 100644 --- a/test/src/unit-regression1.cpp +++ b/test/src/unit-regression1.cpp @@ -42,10 +42,6 @@ using nlohmann::json; #include #include -#if (defined(__cplusplus) && __cplusplus >= 201703L) || (defined(_HAS_CXX17) && _HAS_CXX17 == 1) // fix for issue #464 - #define JSON_HAS_CPP_17 -#endif - #ifdef JSON_HAS_CPP_17 #include #endif diff --git a/test/src/unit-regression2.cpp b/test/src/unit-regression2.cpp index 8c6e41193..b8cc5107b 100644 --- a/test/src/unit-regression2.cpp +++ b/test/src/unit-regression2.cpp @@ -42,70 +42,8 @@ using ordered_json = nlohmann::ordered_json; #include #include -#if (defined(__cplusplus) && __cplusplus >= 201703L) || (defined(_HAS_CXX17) && _HAS_CXX17 == 1) // fix for issue #464 - #define JSON_HAS_CPP_17 -#endif - #ifdef JSON_HAS_CPP_17 #include - - #if !defined(JSON_HAS_FILESYSTEM) && !defined(JSON_HAS_EXPERIMENTAL_FILESYSTEM) - #if defined(__cpp_lib_filesystem) - #define JSON_HAS_FILESYSTEM 1 - #elif defined(__cpp_lib_experimental_filesystem) - #define JSON_HAS_EXPERIMENTAL_FILESYSTEM 1 - #elif !defined(__has_include) - #define JSON_HAS_EXPERIMENTAL_FILESYSTEM 1 - #elif __has_include() - #define JSON_HAS_FILESYSTEM 1 - #elif __has_include() - #define JSON_HAS_EXPERIMENTAL_FILESYSTEM 1 - #endif - - // std::filesystem does not work on MinGW GCC 8: https://sourceforge.net/p/mingw-w64/bugs/737/ - #if defined(__MINGW32__) && defined(__GNUC__) && __GNUC__ == 8 - #undef JSON_HAS_FILESYSTEM - #undef JSON_HAS_EXPERIMENTAL_FILESYSTEM - #endif - - // no filesystem support before GCC 8: https://en.cppreference.com/w/cpp/compiler_support - #if defined(__GNUC__) && __GNUC__ < 8 && !defined(__clang__) - #undef JSON_HAS_FILESYSTEM - #undef JSON_HAS_EXPERIMENTAL_FILESYSTEM - #endif - - // no filesystem support before Clang 7: https://en.cppreference.com/w/cpp/compiler_support - #if defined(__clang_major__) && __clang_major__ < 7 - #undef JSON_HAS_FILESYSTEM - #undef JSON_HAS_EXPERIMENTAL_FILESYSTEM - #endif - - // no filesystem support before MSVC 19.14: https://en.cppreference.com/w/cpp/compiler_support - #if defined(_MSC_VER) && _MSC_VER < 1940 - #undef JSON_HAS_FILESYSTEM - #undef JSON_HAS_EXPERIMENTAL_FILESYSTEM - #endif - - // no filesystem support before iOS 13 - #if defined(__IPHONE_OS_VERSION_MIN_REQUIRED) && __IPHONE_OS_VERSION_MIN_REQUIRED < 130000 - #undef JSON_HAS_FILESYSTEM - #undef JSON_HAS_EXPERIMENTAL_FILESYSTEM - #endif - - // no filesystem support before macOS Catalina - #if defined(__MAC_OS_X_VERSION_MIN_REQUIRED) && __MAC_OS_X_VERSION_MIN_REQUIRED < 101500 - #undef JSON_HAS_FILESYSTEM - #undef JSON_HAS_EXPERIMENTAL_FILESYSTEM - #endif - #endif -#endif - -#ifndef JSON_HAS_EXPERIMENTAL_FILESYSTEM - #define JSON_HAS_EXPERIMENTAL_FILESYSTEM 0 -#endif - -#ifndef JSON_HAS_FILESYSTEM - #define JSON_HAS_FILESYSTEM 0 #endif #if JSON_HAS_EXPERIMENTAL_FILESYSTEM @@ -656,7 +594,7 @@ TEST_CASE("regression tests 2") #ifdef JSON_HAS_CPP_20 SECTION("issue #2546 - parsing containers of std::byte") { - const char DATA[] = R"("Hello, world!")"; + const char DATA[] = R"("Hello, world!")"; // NOLINT(cppcoreguidelines-avoid-c-arrays,hicpp-avoid-c-arrays,modernize-avoid-c-arrays) const auto s = std::as_bytes(std::span(DATA)); json j = json::parse(s); CHECK(j.dump() == "\"Hello, world!\""); @@ -810,7 +748,8 @@ TEST_CASE("regression tests 2") const auto j_path = j.get(); CHECK(j_path == text_path); - CHECK_THROWS_WITH_AS(nlohmann::detail::std_fs::path(json(1)), "[json.exception.type_error.302] type must be string, but is number", json::type_error); + // Disabled pending resolution of #3377 + // CHECK_THROWS_WITH_AS(nlohmann::detail::std_fs::path(json(1)), "[json.exception.type_error.302] type must be string, but is number", json::type_error); } #endif diff --git a/test/src/unit-ubjson.cpp b/test/src/unit-ubjson.cpp index 84568f818..b5657284c 100644 --- a/test/src/unit-ubjson.cpp +++ b/test/src/unit-ubjson.cpp @@ -1610,7 +1610,7 @@ TEST_CASE("UBJSON") CHECK_THROWS_AS(_ = json::from_ubjson(v_ubjson), json::out_of_range&); json j; - nlohmann::detail::json_sax_dom_callback_parser scp(j, [](int /*unused*/, json::parse_event_t /*unused*/, const json& /*unused*/) + nlohmann::detail::json_sax_dom_callback_parser scp(j, [](int /*unused*/, json::parse_event_t /*unused*/, const json& /*unused*/) noexcept { return true; }); @@ -1624,7 +1624,7 @@ TEST_CASE("UBJSON") CHECK_THROWS_AS(_ = json::from_ubjson(v_ubjson), json::out_of_range&); json j; - nlohmann::detail::json_sax_dom_callback_parser scp(j, [](int /*unused*/, json::parse_event_t /*unused*/, const json& /*unused*/) + nlohmann::detail::json_sax_dom_callback_parser scp(j, [](int /*unused*/, json::parse_event_t /*unused*/, const json& /*unused*/) noexcept { return true; });