diff --git a/.github/CONTRIBUTING.md b/.github/CONTRIBUTING.md index 8dbacb78..4ae0cb2d 100644 --- a/.github/CONTRIBUTING.md +++ b/.github/CONTRIBUTING.md @@ -54,7 +54,7 @@ To make changes, you need to edit the following files: ## Please don't -- The C++11 support varies between different **compilers** and versions. Please note the [list of supported compilers](https://github.com/nlohmann/json/blob/master/README.md#supported-compilers). Some compilers like GCC 4.8 (and earlier), Clang 3.3 (and earlier), or Microsoft Visual Studio 13.0 and earlier are known not to work due to missing or incomplete C++11 support. Please refrain from proposing changes that work around these compiler's limitations with `#ifdef`s or other means. +- The C++11 support varies between different **compilers** and versions. Please note the [list of supported compilers](https://github.com/nlohmann/json/blob/master/README.md#supported-compilers). Some compilers like GCC 4.7 (and earlier), Clang 3.3 (and earlier), or Microsoft Visual Studio 13.0 and earlier are known not to work due to missing or incomplete C++11 support. Please refrain from proposing changes that work around these compiler's limitations with `#ifdef`s or other means. - Specifically, I am aware of compilation problems with **Microsoft Visual Studio** (there even is an [issue label](https://github.com/nlohmann/json/issues?utf8=✓&q=label%3A%22visual+studio%22+) for these kind of bugs). I understand that even in 2016, complete C++11 support isn't there yet. But please also understand that I do not want to drop features or uglify the code just to make Microsoft's sub-standard compiler happy. The past has shown that there are ways to express the functionality such that the code compiles with the most recent MSVC - unfortunately, this is not the main objective of the project. - Please refrain from proposing changes that would **break [JSON](http://json.org) conformance**. If you propose a conformant extension of JSON to be supported by the library, please motivate this extension. - We shall not extend the library to **support comments**. There is quite some [controversy](https://www.reddit.com/r/programming/comments/4v6chu/why_json_doesnt_support_comments_douglas_crockford/) around this topic, and there were quite some [issues](https://github.com/nlohmann/json/issues/376) on this. We believe that JSON is fine without comments. diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md index d75a67b4..f2c3af6a 100644 --- a/.github/PULL_REQUEST_TEMPLATE.md +++ b/.github/PULL_REQUEST_TEMPLATE.md @@ -13,7 +13,7 @@ Read the [Contribution Guidelines](https://github.com/nlohmann/json/blob/develop ## Please don't -- The C++11 support varies between different **compilers** and versions. Please note the [list of supported compilers](https://github.com/nlohmann/json/blob/master/README.md#supported-compilers). Some compilers like GCC 4.8 (and earlier), Clang 3.3 (and earlier), or Microsoft Visual Studio 13.0 and earlier are known not to work due to missing or incomplete C++11 support. Please refrain from proposing changes that work around these compiler's limitations with `#ifdef`s or other means. +- The C++11 support varies between different **compilers** and versions. Please note the [list of supported compilers](https://github.com/nlohmann/json/blob/master/README.md#supported-compilers). Some compilers like GCC 4.7 (and earlier), Clang 3.3 (and earlier), or Microsoft Visual Studio 13.0 and earlier are known not to work due to missing or incomplete C++11 support. Please refrain from proposing changes that work around these compiler's limitations with `#ifdef`s or other means. - Specifically, I am aware of compilation problems with **Microsoft Visual Studio** (there even is an [issue label](https://github.com/nlohmann/json/issues?utf8=✓&q=label%3A%22visual+studio%22+) for these kind of bugs). I understand that even in 2016, complete C++11 support isn't there yet. But please also understand that I do not want to drop features or uglify the code just to make Microsoft's sub-standard compiler happy. The past has shown that there are ways to express the functionality such that the code compiles with the most recent MSVC - unfortunately, this is not the main objective of the project. - Please refrain from proposing changes that would **break [JSON](http://json.org) conformance**. If you propose a conformant extension of JSON to be supported by the library, please motivate this extension. - Please do not open pull requests that address **multiple issues**. diff --git a/.travis.yml b/.travis.yml index e5f08353..4c539510 100644 --- a/.travis.yml +++ b/.travis.yml @@ -161,11 +161,22 @@ matrix: - os: osx osx_image: xcode9.4 + - os: osx + osx_image: xcode10 + # Linux / GCC - os: linux compiler: gcc - env: COMPILER=g++-4.9 + env: compiler=g++-4.8 + addons: + apt: + sources: ['ubuntu-toolchain-r-test'] + packages: ['g++-4.8', 'ninja-build'] + + - os: linux + compiler: gcc + env: compiler=g++-4.9 addons: apt: sources: ['ubuntu-toolchain-r-test'] diff --git a/CMakeLists.txt b/CMakeLists.txt index 99376704..e80d7a98 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -4,7 +4,7 @@ cmake_minimum_required(VERSION 3.8) ## PROJECT ## name and version ## -project(nlohmann_json VERSION 3.2.0 LANGUAGES CXX) +project(nlohmann_json VERSION 3.3.0 LANGUAGES CXX) ## ## INCLUDE @@ -86,10 +86,10 @@ include(CMakePackageConfigHelpers) write_basic_package_version_file( ${NLOHMANN_JSON_CMAKE_VERSION_CONFIG_FILE} COMPATIBILITY SameMajorVersion ) -configure_package_config_file( +configure_file( ${NLOHMANN_JSON_CMAKE_CONFIG_TEMPLATE} ${NLOHMANN_JSON_CMAKE_PROJECT_CONFIG_FILE} - INSTALL_DESTINATION ${NLOHMANN_JSON_CONFIG_INSTALL_DIR} + @ONLY ) install( @@ -121,4 +121,3 @@ install( NAMESPACE ${PROJECT_NAME}:: DESTINATION ${NLOHMANN_JSON_CONFIG_INSTALL_DIR} ) -export(PACKAGE ${PROJECT_NAME}) \ No newline at end of file diff --git a/ChangeLog.md b/ChangeLog.md index 0c6cc009..19b69d2a 100644 --- a/ChangeLog.md +++ b/ChangeLog.md @@ -1,7 +1,75 @@ # Change Log All notable changes to this project will be documented in this file. This project adheres to [Semantic Versioning](http://semver.org/). -## [v3.2.0](https://github.com/nlohmann/json/releases/tag/v3.2.0) (2018-08-18) +## [v3.3.0](https://github.com/nlohmann/json/releases/tag/v3.3.0) (2018-10-05) +[Full Changelog](https://github.com/nlohmann/json/compare/v3.2.0...v3.3.0) + +- When key is not found print the key name into error too [\#1273](https://github.com/nlohmann/json/issues/1273) +- Visual Studio 2017 15.8.5 "conditional expression is constant" warning on Line 1851 in json.hpp [\#1268](https://github.com/nlohmann/json/issues/1268) +- how can we get this working on WSL? [\#1264](https://github.com/nlohmann/json/issues/1264) +- Help needed [\#1259](https://github.com/nlohmann/json/issues/1259) +- A way to get to a JSON values "key" [\#1258](https://github.com/nlohmann/json/issues/1258) +- Two blackslashes on json output file [\#1253](https://github.com/nlohmann/json/issues/1253) +- Including nlohmann the badwrong way. [\#1250](https://github.com/nlohmann/json/issues/1250) +- how to build with clang? [\#1247](https://github.com/nlohmann/json/issues/1247) +- Cmake target\_link\_libraries unable to find nlohmann\_json since version 3.2.0 [\#1243](https://github.com/nlohmann/json/issues/1243) +- \[Question\] Access to end\(\) iterator reference [\#1242](https://github.com/nlohmann/json/issues/1242) +- Parsing different json format [\#1241](https://github.com/nlohmann/json/issues/1241) +- Parsing Multiple JSON Files [\#1240](https://github.com/nlohmann/json/issues/1240) +- Doesn't compile under C++17 [\#1239](https://github.com/nlohmann/json/issues/1239) +- Conversion operator for nlohmann::json is not SFINAE friendly [\#1237](https://github.com/nlohmann/json/issues/1237) +- Custom deserialization of number\_float\_t [\#1236](https://github.com/nlohmann/json/issues/1236) +- Move tests to a separate repo [\#1235](https://github.com/nlohmann/json/issues/1235) +- deprecated-declarations warnings when compiling tests with GCC 8.2.1. [\#1233](https://github.com/nlohmann/json/issues/1233) +- Incomplete type with json\_fwd.hpp [\#1232](https://github.com/nlohmann/json/issues/1232) +- Parse Error [\#1229](https://github.com/nlohmann/json/issues/1229) +- json::get function with argument [\#1227](https://github.com/nlohmann/json/issues/1227) +- questions regarding from\_json [\#1226](https://github.com/nlohmann/json/issues/1226) +- Lambda in unevaluated context [\#1225](https://github.com/nlohmann/json/issues/1225) +- NLohmann doesn't compile when enabling strict warning policies [\#1224](https://github.com/nlohmann/json/issues/1224) +- Creating array of objects [\#1223](https://github.com/nlohmann/json/issues/1223) +- Somewhat unhelpful error message "cannot use operator\[\] with object" [\#1220](https://github.com/nlohmann/json/issues/1220) +- single\_include json.hpp [\#1218](https://github.com/nlohmann/json/issues/1218) +- Maps with enum class keys which are convertible to JSON strings should be converted to JSON dictionaries [\#1217](https://github.com/nlohmann/json/issues/1217) +- Adding JSON Array to the Array [\#1216](https://github.com/nlohmann/json/issues/1216) +- Best way to output a vector of a given type to json [\#1215](https://github.com/nlohmann/json/issues/1215) +- compiler warning: double definition of macro JSON\_INTERNAL\_CATCH [\#1213](https://github.com/nlohmann/json/issues/1213) +- Compilation error when using MOCK\_METHOD1 from GMock and nlohmann::json [\#1212](https://github.com/nlohmann/json/issues/1212) +- Issues parsing a previously encoded binary \(non-UTF8\) string. [\#1211](https://github.com/nlohmann/json/issues/1211) +- Yet another ordering question: char \* and parse\(\) [\#1209](https://github.com/nlohmann/json/issues/1209) +- Error using gcc 8.1.0 on Ubuntu 14.04 [\#1207](https://github.com/nlohmann/json/issues/1207) +- "type must be string, but is " std::string\(j.type\_name\(\) [\#1206](https://github.com/nlohmann/json/issues/1206) +- Returning empty json object from a function of type const json& ? [\#1205](https://github.com/nlohmann/json/issues/1205) +- VS2017 compiler suggests using constexpr if [\#1204](https://github.com/nlohmann/json/issues/1204) +- Template instatiation error on compiling [\#1203](https://github.com/nlohmann/json/issues/1203) +- Soften the landing when dumping non-UTF8 strings \(type\_error.316 exception\) [\#1198](https://github.com/nlohmann/json/issues/1198) +- BUG - json dump field with unicode -\> array of ints \(instead of string\) [\#1197](https://github.com/nlohmann/json/issues/1197) +- Compile error using Code::Blocks // mingw-w64 GCC 8.1.0 - "Incomplete Type" [\#1193](https://github.com/nlohmann/json/issues/1193) +- SEGFAULT on arm target [\#1190](https://github.com/nlohmann/json/issues/1190) +- Compiler crash with old Clang [\#1179](https://github.com/nlohmann/json/issues/1179) +- Custom Precision on floating point numbers [\#1170](https://github.com/nlohmann/json/issues/1170) +- Can we have a json\_view class like std::string\_view? [\#1158](https://github.com/nlohmann/json/issues/1158) +- improve error handling [\#1152](https://github.com/nlohmann/json/issues/1152) +- We should remove static\_asserts [\#960](https://github.com/nlohmann/json/issues/960) + +- Fix warning C4127: conditional expression is constant [\#1272](https://github.com/nlohmann/json/pull/1272) ([antonioborondo](https://github.com/antonioborondo)) +- Turn off additional deprecation warnings for GCC. [\#1271](https://github.com/nlohmann/json/pull/1271) ([chuckatkins](https://github.com/chuckatkins)) +- docs: Add additional CMake documentation [\#1270](https://github.com/nlohmann/json/pull/1270) ([chuckatkins](https://github.com/chuckatkins)) +- unit-testsuites.cpp: fix hangup if file not found [\#1262](https://github.com/nlohmann/json/pull/1262) ([knilch0r](https://github.com/knilch0r)) +- Fix broken cmake imported target alias [\#1260](https://github.com/nlohmann/json/pull/1260) ([chuckatkins](https://github.com/chuckatkins)) +- GCC 48 [\#1257](https://github.com/nlohmann/json/pull/1257) ([henryiii](https://github.com/henryiii)) +- Add version and license to meson.build [\#1252](https://github.com/nlohmann/json/pull/1252) ([koponomarenko](https://github.com/koponomarenko)) +- \#1179 Reordered the code. It seems to stop clang 3.4.2 in RHEL 7 from crash… [\#1249](https://github.com/nlohmann/json/pull/1249) ([LEgregius](https://github.com/LEgregius)) +- Use a version check to provide backwards comatible CMake imported target names [\#1245](https://github.com/nlohmann/json/pull/1245) ([chuckatkins](https://github.com/chuckatkins)) +- Fix issue \#1237 [\#1238](https://github.com/nlohmann/json/pull/1238) ([theodelrieu](https://github.com/theodelrieu)) +- Add a get overload taking a parameter. [\#1231](https://github.com/nlohmann/json/pull/1231) ([theodelrieu](https://github.com/theodelrieu)) +- Move lambda out of unevaluated context [\#1230](https://github.com/nlohmann/json/pull/1230) ([mandreyel](https://github.com/mandreyel)) +- Remove static asserts [\#1228](https://github.com/nlohmann/json/pull/1228) ([theodelrieu](https://github.com/theodelrieu)) +- Better error 305 [\#1221](https://github.com/nlohmann/json/pull/1221) ([rivertam](https://github.com/rivertam)) +- Fix \#1213 [\#1214](https://github.com/nlohmann/json/pull/1214) ([simnalamburt](https://github.com/simnalamburt)) +- Export package to allow builds without installing [\#1202](https://github.com/nlohmann/json/pull/1202) ([dennisfischer](https://github.com/dennisfischer)) + +## [v3.2.0](https://github.com/nlohmann/json/releases/tag/v3.2.0) (2018-08-20) [Full Changelog](https://github.com/nlohmann/json/compare/v3.1.2...v3.2.0) - Am I doing this wrong? Getting an empty string [\#1199](https://github.com/nlohmann/json/issues/1199) @@ -964,7 +1032,6 @@ All notable changes to this project will be documented in this file. This projec - json::diff generates incorrect patch when removing multiple array elements. [\#269](https://github.com/nlohmann/json/issues/269) - Docs - What does Json\[key\] return? [\#267](https://github.com/nlohmann/json/issues/267) - Compiler Errors With JSON.hpp [\#265](https://github.com/nlohmann/json/issues/265) -- Throw exception instead of crashing my app [\#264](https://github.com/nlohmann/json/issues/264) - Ambiguous push\_back and operator+= overloads [\#263](https://github.com/nlohmann/json/issues/263) - Preseving order of items in json [\#262](https://github.com/nlohmann/json/issues/262) - '\' char problem in strings [\#261](https://github.com/nlohmann/json/issues/261) diff --git a/Makefile b/Makefile index bfb62349..135db65a 100644 --- a/Makefile +++ b/Makefile @@ -12,6 +12,7 @@ SRCS = include/nlohmann/json.hpp \ include/nlohmann/detail/input/json_sax.hpp \ include/nlohmann/detail/input/lexer.hpp \ include/nlohmann/detail/input/parser.hpp \ + include/nlohmann/detail/input/position_t.hpp \ include/nlohmann/detail/iterators/internal_iterator.hpp \ include/nlohmann/detail/iterators/iter_impl.hpp \ include/nlohmann/detail/iterators/iteration_proxy.hpp \ diff --git a/README.md b/README.md index f3bbf847..926b4d7e 100644 --- a/README.md +++ b/README.md @@ -5,6 +5,7 @@ [![Coverage Status](https://img.shields.io/coveralls/nlohmann/json.svg)](https://coveralls.io/r/nlohmann/json) [![Coverity Scan Build Status](https://scan.coverity.com/projects/5550/badge.svg)](https://scan.coverity.com/projects/nlohmann-json) [![Codacy Badge](https://api.codacy.com/project/badge/Grade/f3732b3327e34358a0e9d1fe9f661f08)](https://www.codacy.com/app/nlohmann/json?utm_source=github.com&utm_medium=referral&utm_content=nlohmann/json&utm_campaign=Badge_Grade) +[![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) [![Try online](https://img.shields.io/badge/try-online-blue.svg)](https://wandbox.org/permlink/TarF5pPn9NtHQjhf) [![Documentation](https://img.shields.io/badge/docs-doxygen-blue.svg)](http://nlohmann.github.io/json) [![GitHub license](https://img.shields.io/badge/license-MIT-blue.svg)](https://raw.githubusercontent.com/nlohmann/json/master/LICENSE.MIT) @@ -15,6 +16,8 @@ - [Design goals](#design-goals) - [Integration](#integration) + - [CMake](#cmake) + - [Package Managers](#package-managers) - [Examples](#examples) - [JSON as first-class data type](#json-as-first-class-data-type) - [Serialization / Deserialization](#serialization--deserialization) @@ -68,6 +71,71 @@ to the files you want to process JSON and set the necessary switches to enable C 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`. +### CMake + +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. + +#### 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: +```cmake +# CMakeLists.txt +find_package(nlohmann_json 3.2.0 REQUIRED) +... +add_library(foo ...) +... +target_link_libraries(foo 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: +```cmake +# Typically you don't care so much for a third party library's tests to be +# run from your own project's code. +set(JSON_BuildTests OFF CACHE INTERNAL "") + +# Don't use include(nlohmann_json/CMakeLists.txt) since that carries with it +# inintended 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) +``` + +#### 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: +``` 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() +... +``` +`thirdparty/nlohmann_json` is then a complete copy of this source tree. + ### Package Managers :beer: If you are using OS X and [Homebrew](http://brew.sh), just type `brew tap nlohmann/json` and `brew install nlohmann_json` and you're set. If you want the bleeding edge rather than the latest release, use `brew install nlohmann_json --HEAD`. @@ -226,12 +294,15 @@ json j_string = "this is a string"; std::string cpp_string = j_string; // retrieve the string value (explicit JSON to std::string conversion) auto cpp_string2 = j_string.get(); +// retrieve the string value (alternative explicit JSON to std::string conversion) +std::string cpp_string3; +j_string.get_to(cpp_string3); // retrieve the serialized value (explicit JSON serialization) std::string serialized_string = j_string.dump(); // output of original string -std::cout << cpp_string << " == " << cpp_string2 << " == " << j_string.get() << '\n'; +std::cout << cpp_string << " == " << cpp_string2 << " == " << cpp_string3 << " == " << j_string.get() << '\n'; // output of serialized value std::cout << j_string << " == " << serialized_string << std::endl; ``` @@ -642,15 +713,15 @@ namespace ns { } void from_json(const json& j, person& p) { - p.name = j.at("name").get(); - p.address = j.at("address").get(); - p.age = j.at("age").get(); + j.at("name").get_to(p.name); + j.at("address").get_to(p.address); + j.at("age").get_to(p.age); } } // namespace ns ``` That's all! When calling the `json` constructor with your type, your custom `to_json` method will be automatically called. -Likewise, when calling `get()`, the `from_json` method will be called. +Likewise, when calling `get()` or `get_to(your_type&)`, the `from_json` method will be called. Some important things: @@ -658,9 +729,8 @@ Some important things: * Those methods **MUST** be available (e.g., properly headers must be included) everywhere you use the implicit conversions. Look at [issue 1108](https://github.com/nlohmann/json/issues/1108) for errors that may occur otherwise. * When using `get()`, `your_type` **MUST** be [DefaultConstructible](https://en.cppreference.com/w/cpp/named_req/DefaultConstructible). (There is a way to bypass this requirement described later.) * In function `from_json`, use function [`at()`](https://nlohmann.github.io/json/classnlohmann_1_1basic__json_a93403e803947b86f4da2d1fb3345cf2c.html#a93403e803947b86f4da2d1fb3345cf2c) to access the object values rather than `operator[]`. In case a key does not exist, `at` throws an exception that you can handle, whereas `operator[]` exhibits undefined behavior. -* In case your type contains several `operator=` definitions, code like `your_variable = your_json;` [may not compile](https://github.com/nlohmann/json/issues/667). You need to write `your_variable = your_json.get();` instead. +* In case your type contains several `operator=` definitions, code like `your_variable = your_json;` [may not compile](https://github.com/nlohmann/json/issues/667). You need to write `your_variable = your_json.get();` or `your_json.get_to(your_variable);` instead. * You do not need to add serializers or deserializers for STL types like `std::vector`: the library already implements these. -* Be careful with the definition order of the `from_json`/`to_json` functions: If a type `B` has a member of type `A`, you **MUST** define `to_json(A)` before `to_json(B)`. Look at [issue 561](https://github.com/nlohmann/json/issues/561) for more details. #### How do I convert third-party types? @@ -842,7 +912,7 @@ json j_from_ubjson = json::from_ubjson(v_ubjson); Though it's 2018 already, the support for C++11 is still a bit sparse. Currently, the following compilers are known to work: -- GCC 4.9 - 8.2 (and possibly later) +- GCC 4.8 - 8.2 (and possibly later) - Clang 3.4 - 6.1 (and possibly later) - Intel C++ Compiler 17.0.2 (and possibly later) - Microsoft Visual C++ 2015 / Build Tools 14.0.25123.0 (and possibly later) @@ -852,7 +922,7 @@ I would be happy to learn about other compilers/versions. Please note: -- GCC 4.8 does not work because of two bugs ([55817](https://gcc.gnu.org/bugzilla/show_bug.cgi?id=55817) and [57824](https://gcc.gnu.org/bugzilla/show_bug.cgi?id=57824)) in the C++11 support. Note there is a [pull request](https://github.com/nlohmann/json/pull/212) to fix some of the issues. +- GCC 4.8 has a bug [57824](https://gcc.gnu.org/bugzilla/show_bug.cgi?id=57824)): multiline raw strings cannot be the arguments to macros. Don't use multiline raw strings directly in macros with this compiler. - Android defaults to using very old compilers and C++ libraries. To fix this, add the following to your `Application.mk`. This will switch to the LLVM C++ library, the Clang compiler, and enable C++11 and other features disabled by default. ``` @@ -871,6 +941,7 @@ The following compilers are currently used in continuous integration at [Travis] | Compiler | Operating System | Version String | |-----------------|------------------------------|----------------| +| GCC 4.8.5 | Ubuntu 14.04.5 LTS | g++-4.8 (Ubuntu 4.8.5-2ubuntu1~14.04.2) 4.8.5 | | GCC 4.9.4 | Ubuntu 14.04.1 LTS | g++-4.9 (Ubuntu 4.9.4-2ubuntu1~14.04.1) 4.9.4 | | GCC 5.5.0 | Ubuntu 14.04.1 LTS | g++-5 (Ubuntu 5.5.0-12ubuntu1~14.04) 5.5.0 20171010 | | GCC 6.4.0 | Ubuntu 14.04.1 LTS | g++-6 (Ubuntu 6.4.0-17ubuntu1~14.04) 6.4.0 20180424 | @@ -895,6 +966,7 @@ The following compilers are currently used in continuous integration at [Travis] | Clang Xcode 9.1 | OSX 10.12.6 | Apple LLVM version 9.0.0 (clang-900.0.38) | | Clang Xcode 9.2 | OSX 10.13.3 | Apple LLVM version 9.1.0 (clang-902.0.39.1) | | Clang Xcode 9.3 | OSX 10.13.3 | Apple LLVM version 9.1.0 (clang-902.0.39.2) | +| Clang Xcode 10.0 | OSX 10.13.3 | Apple LLVM version 10.0.0 (clang-1000.11.45.2) | | Visual Studio 14 2015 | Windows Server 2012 R2 (x64) | Microsoft (R) Build Engine version 14.0.25420.1, MSVC 19.0.24215.1 | | Visual Studio 2017 | Windows Server 2016 | Microsoft (R) Build Engine version 15.7.180.61344, MSVC 19.14.26433.0 | @@ -1045,7 +1117,7 @@ I deeply appreciate the help of the following people. - [Axel Huebl](https://github.com/ax3l) simplified a CMake check and added support for the [Spack package manager](https://spack.io). - [Carlos O'Ryan](https://github.com/coryan) fixed a typo. - [James Upjohn](https://github.com/jammehcow) fixed a version number in the compilers section. -- [Chuck Atkins](https://github.com/chuckatkins) adjusted the CMake files to the CMake packaging guidelines +- [Chuck Atkins](https://github.com/chuckatkins) adjusted the CMake files to the CMake packaging guidelines and provided documentation for the CMake integration. - [Jan Schöppach](https://github.com/dns13) fixed a typo. - [martin-mfg](https://github.com/martin-mfg) fixed a typo. - [Matthias Möller](https://github.com/TinyTinni) removed the dependency from `std::stringstream`. @@ -1056,6 +1128,16 @@ I deeply appreciate the help of the following people. - [grembo](https://github.com/grembo) fixed the test suite and re-enabled several test cases. - [Hyeon Kim](https://github.com/simnalamburt) introduced the macro `JSON_INTERNAL_CATCH` to control the exception handling inside the library. - [thyu](https://github.com/thyu) fixed a compiler warning. +- [David Guthrie](https://github.com/LEgregius) fixed a subtle compilation error with Clang 3.4.2. +- [Dennis Fischer](https://github.com/dennisfischer) allowed to call `find_package` without installing the library. +- [Hyeon Kim](https://github.com/simnalamburt) fixed an issue with a double macro definition. +- [Ben Berman](https://github.com/rivertam) made some error messages more understandable. +- [zakalibit](https://github.com/zakalibit) fixed a compilation problem with the Intel C++ compiler. +- [mandreyel](https://github.com/mandreyel) fixed a compilation problem. +- [Kostiantyn Ponomarenko](https://github.com/koponomarenko) added version and license information to the Meson build file. +- [Henry Schreiner](https://github.com/henryiii) added support for GCC 4.8. +- [knilch](https://github.com/knilch0r) made sure the test suite does not stall when run in the wrong directory. +- [Antonio Borondo](https://github.com/antonioborondo) fixed an MSVC 2017 warning. Thanks a lot for helping out! Please [let me know](mailto:mail@nlohmann.me) if I forgot someone. diff --git a/benchmarks/thirdparty/benchmark/CMakeLists.txt b/benchmarks/thirdparty/benchmark/CMakeLists.txt index aa082676..f8dd0497 100644 --- a/benchmarks/thirdparty/benchmark/CMakeLists.txt +++ b/benchmarks/thirdparty/benchmark/CMakeLists.txt @@ -140,7 +140,7 @@ else() if (GCC_RANLIB) set(CMAKE_RANLIB ${GCC_RANLIB}) endif() - elseif("${CMAKE_C_COMPILER_ID}" STREQUAL "Clang") + elseif("${CMAKE_C_COMPILER_ID}" MATCHES "Clang") include(llvm-toolchain) endif() endif() @@ -165,7 +165,7 @@ else() endif() if (BENCHMARK_USE_LIBCXX) - if ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "Clang") + if ("${CMAKE_CXX_COMPILER_ID}" MATCHES "Clang") add_cxx_compiler_flag(-stdlib=libc++) elseif ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "GNU" OR "${CMAKE_CXX_COMPILER_ID}" STREQUAL "Intel") diff --git a/benchmarks/thirdparty/benchmark/cmake/HandleGTest.cmake b/benchmarks/thirdparty/benchmark/cmake/HandleGTest.cmake index 77ffc4c5..d38e7eb9 100644 --- a/benchmarks/thirdparty/benchmark/cmake/HandleGTest.cmake +++ b/benchmarks/thirdparty/benchmark/cmake/HandleGTest.cmake @@ -7,7 +7,7 @@ macro(build_external_gtest) include(ExternalProject) set(GTEST_FLAGS "") if (BENCHMARK_USE_LIBCXX) - if ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "Clang") + if ("${CMAKE_CXX_COMPILER_ID}" MATCHES "Clang") list(APPEND GTEST_FLAGS -stdlib=libc++) else() message(WARNING "Unsupported compiler (${CMAKE_CXX_COMPILER}) when using libc++") diff --git a/cmake/config.cmake.in b/cmake/config.cmake.in index 8baabf07..9a17a7d7 100644 --- a/cmake/config.cmake.in +++ b/cmake/config.cmake.in @@ -1,5 +1,15 @@ -@PACKAGE_INIT@ +include(FindPackageHandleStandardArgs) +set(${CMAKE_FIND_PACKAGE_NAME}_CONFIG ${CMAKE_CURRENT_LIST_FILE}) +find_package_handle_standard_args(@PROJECT_NAME@ CONFIG_MODE) + if(NOT TARGET @PROJECT_NAME@::@NLOHMANN_JSON_TARGET_NAME@) include("${CMAKE_CURRENT_LIST_DIR}/@NLOHMANN_JSON_TARGETS_EXPORT_NAME@.cmake") + if((NOT TARGET @NLOHMANN_JSON_TARGET_NAME@) AND + (NOT @PROJECT_NAME@_FIND_VERSION OR + @PROJECT_NAME@_FIND_VERSION VERSION_LESS 3.2.0)) + add_library(@NLOHMANN_JSON_TARGET_NAME@ INTERFACE IMPORTED) + set_target_properties(@NLOHMANN_JSON_TARGET_NAME@ PROPERTIES + INTERFACE_LINK_LIBRARIES @PROJECT_NAME@::@NLOHMANN_JSON_TARGET_NAME@ + ) + endif() endif() -check_required_components("@PROJECT_NAME@") diff --git a/doc/Doxyfile b/doc/Doxyfile index f9512640..87d234ff 100644 --- a/doc/Doxyfile +++ b/doc/Doxyfile @@ -5,7 +5,7 @@ #--------------------------------------------------------------------------- DOXYFILE_ENCODING = UTF-8 PROJECT_NAME = "JSON for Modern C++" -PROJECT_NUMBER = 3.2.0 +PROJECT_NUMBER = 3.3.0 PROJECT_BRIEF = PROJECT_LOGO = OUTPUT_DIRECTORY = . diff --git a/doc/avatars.png b/doc/avatars.png index 4798d3ba..876802da 100644 Binary files a/doc/avatars.png and b/doc/avatars.png differ diff --git a/doc/examples/README.link b/doc/examples/README.link index a9d70c40..5b620f23 100644 --- a/doc/examples/README.link +++ b/doc/examples/README.link @@ -1 +1 @@ -online \ No newline at end of file +online \ No newline at end of file diff --git a/doc/examples/get_to.cpp b/doc/examples/get_to.cpp new file mode 100644 index 00000000..4705b172 --- /dev/null +++ b/doc/examples/get_to.cpp @@ -0,0 +1,60 @@ +#include +#include +#include + +using json = nlohmann::json; + +int main() +{ + // create a JSON value with different types + json json_types = + { + {"boolean", true}, + { + "number", { + {"integer", 42}, + {"floating-point", 17.23} + } + }, + {"string", "Hello, world!"}, + {"array", {1, 2, 3, 4, 5}}, + {"null", nullptr} + }; + + bool v1; + int v2; + short v3; + float v4; + int v5; + std::string v6; + std::vector v7; + std::unordered_map v8; + + + // use explicit conversions + json_types["boolean"].get_to(v1); + json_types["number"]["integer"].get_to(v2); + json_types["number"]["integer"].get_to(v3); + json_types["number"]["floating-point"].get_to(v4); + json_types["number"]["floating-point"].get_to(v5); + json_types["string"].get_to(v6); + json_types["array"].get_to(v7); + json_types.get_to(v8); + + // print the conversion results + std::cout << v1 << '\n'; + std::cout << v2 << ' ' << v3 << '\n'; + std::cout << v4 << ' ' << v5 << '\n'; + std::cout << v6 << '\n'; + + for (auto i : v7) + { + std::cout << i << ' '; + } + std::cout << "\n\n"; + + for (auto i : v8) + { + std::cout << i.first << ": " << i.second << '\n'; + } +} diff --git a/doc/examples/get_to.link b/doc/examples/get_to.link new file mode 100644 index 00000000..02a167b0 --- /dev/null +++ b/doc/examples/get_to.link @@ -0,0 +1 @@ +online \ No newline at end of file diff --git a/doc/examples/get_to.output b/doc/examples/get_to.output new file mode 100644 index 00000000..5cd9cd3a --- /dev/null +++ b/doc/examples/get_to.output @@ -0,0 +1,11 @@ +1 +42 42 +17.23 17 +Hello, world! +1 2 3 4 5 + +string: "Hello, world!" +number: {"floating-point":17.23,"integer":42} +null: null +boolean: true +array: [1,2,3,4,5] diff --git a/doc/examples/json_pointer.output b/doc/examples/json_pointer.output index 33e2cc68..9e027d6d 100644 --- a/doc/examples/json_pointer.output +++ b/doc/examples/json_pointer.output @@ -1,3 +1,3 @@ -[json.exception.parse_error.107] parse error at 1: JSON pointer must be empty or begin with '/' - was: 'foo' +[json.exception.parse_error.107] parse error at byte 1: JSON pointer must be empty or begin with '/' - was: 'foo' [json.exception.parse_error.108] parse error: escape character '~' must be followed with '0' or '1' [json.exception.parse_error.108] parse error: escape character '~' must be followed with '0' or '1' diff --git a/doc/examples/meta.output b/doc/examples/meta.output index 3683a17c..a21937f2 100644 --- a/doc/examples/meta.output +++ b/doc/examples/meta.output @@ -2,7 +2,7 @@ "compiler": { "c++": "201103", "family": "clang", - "version": "9.1.0 (clang-902.0.39.2)" + "version": "10.0.0 (clang-1000.10.43.1)" }, "copyright": "(C) 2013-2017 Niels Lohmann", "name": "JSON for Modern C++", @@ -10,8 +10,8 @@ "url": "https://github.com/nlohmann/json", "version": { "major": 3, - "minor": 2, + "minor": 3, "patch": 0, - "string": "3.2.0" + "string": "3.3.0" } } diff --git a/doc/examples/parse_error.output b/doc/examples/parse_error.output index 96ab5bb5..fe366ff8 100644 --- a/doc/examples/parse_error.output +++ b/doc/examples/parse_error.output @@ -1,3 +1,3 @@ -message: [json.exception.parse_error.101] parse error at 8: syntax error - unexpected ']'; expected '[', '{', or a literal +message: [json.exception.parse_error.101] parse error at line 1, column 8: syntax error while parsing value - unexpected ']'; expected '[', '{', or a literal exception id: 101 byte position of error: 8 diff --git a/doc/index.md b/doc/index.md index a2ad364b..53faa347 100644 --- a/doc/index.md +++ b/doc/index.md @@ -306,4 +306,4 @@ Note that this table only lists those exceptions thrown due to the type. For ins @author [Niels Lohmann](http://nlohmann.me) @see https://github.com/nlohmann/json to download the source code -@version 3.2.0 +@version 3.3.0 diff --git a/doc/json.gif b/doc/json.gif index 0c00d9fc..03cb06eb 100644 Binary files a/doc/json.gif and b/doc/json.gif differ diff --git a/include/nlohmann/adl_serializer.hpp b/include/nlohmann/adl_serializer.hpp index 0c28d1c7..35be76fd 100644 --- a/include/nlohmann/adl_serializer.hpp +++ b/include/nlohmann/adl_serializer.hpp @@ -46,4 +46,4 @@ struct adl_serializer ::nlohmann::to_json(j, std::forward(val)); } }; -} +} // namespace nlohmann diff --git a/include/nlohmann/detail/conversions/from_json.hpp b/include/nlohmann/detail/conversions/from_json.hpp index 2375d066..358b1c65 100644 --- a/include/nlohmann/detail/conversions/from_json.hpp +++ b/include/nlohmann/detail/conversions/from_json.hpp @@ -299,7 +299,7 @@ void from_json(const BasicJsonType& j, std::pair& p) } template -void from_json_tuple_impl(const BasicJsonType& j, Tuple& t, index_sequence) +void from_json_tuple_impl(const BasicJsonType& j, Tuple& t, index_sequence /*unused*/) { t = std::make_tuple(j.at(Idx).template get::type>()...); } @@ -358,7 +358,7 @@ struct from_json_fn return from_json(j, val); } }; -} +} // namespace detail /// namespace to hold default `from_json` function /// to see why this is required: @@ -366,5 +366,5 @@ struct from_json_fn namespace { constexpr const auto& from_json = detail::static_const::value; -} -} +} // namespace +} // namespace nlohmann diff --git a/include/nlohmann/detail/conversions/to_chars.hpp b/include/nlohmann/detail/conversions/to_chars.hpp index a13d258c..b32e1766 100644 --- a/include/nlohmann/detail/conversions/to_chars.hpp +++ b/include/nlohmann/detail/conversions/to_chars.hpp @@ -47,10 +47,9 @@ struct diyfp // f * 2^e { static constexpr int kPrecision = 64; // = q - uint64_t f; - int e; + uint64_t f = 0; + int e = 0; - constexpr diyfp() noexcept : f(0), e(0) {} constexpr diyfp(uint64_t f_, int e_) noexcept : f(f_), e(e_) {} /*! @@ -62,7 +61,7 @@ struct diyfp // f * 2^e assert(x.e == y.e); assert(x.f >= y.f); - return diyfp(x.f - y.f, x.e); + return {x.f - y.f, x.e}; } /*! @@ -127,7 +126,7 @@ struct diyfp // f * 2^e const uint64_t h = p3 + p2_hi + p1_hi + (Q >> 32); - return diyfp(h, x.e + y.e + 64); + return {h, x.e + y.e + 64}; } /*! @@ -158,7 +157,7 @@ struct diyfp // f * 2^e assert(delta >= 0); assert(((x.f << delta) >> delta) == x.f); - return diyfp(x.f << delta, target_exponent); + return {x.f << delta, target_exponent}; } }; @@ -461,7 +460,7 @@ inline cached_power get_cached_power_for_binary_exponent(int e) assert(e >= -1500); assert(e <= 1500); const int f = kAlpha - e - 1; - const int k = (f * 78913) / (1 << 18) + (f > 0); + const int k = (f * 78913) / (1 << 18) + static_cast(f > 0); const int index = (-kCachedPowersMinDecExp + k + (kCachedPowersDecStep - 1)) / kCachedPowersDecStep; assert(index >= 0); @@ -609,7 +608,7 @@ inline void grisu2_digit_gen(char* buffer, int& length, int& decimal_exponent, const diyfp one(uint64_t{1} << -M_plus.e, M_plus.e); - uint32_t p1 = static_cast(M_plus.f >> -one.e); // p1 = f div 2^-e (Since -e >= 32, p1 fits into a 32-bit int.) + auto p1 = static_cast(M_plus.f >> -one.e); // p1 = f div 2^-e (Since -e >= 32, p1 fits into a 32-bit int.) uint64_t p2 = M_plus.f & (one.f - 1); // p2 = f mod 2^-e // 1) @@ -928,7 +927,7 @@ inline char* append_exponent(char* buf, int e) *buf++ = '+'; } - uint32_t k = static_cast(e); + auto k = static_cast(e); if (k < 10) { // Always print at least two digits in the exponent. @@ -1046,7 +1045,7 @@ format. Returns an iterator pointing past-the-end of the decimal representation. @note The result is NOT null-terminated. */ template -char* to_chars(char* first, char* last, FloatType value) +char* to_chars(char* first, const char* last, FloatType value) { static_cast(last); // maybe unused - fix warning assert(std::isfinite(value)); diff --git a/include/nlohmann/detail/conversions/to_json.hpp b/include/nlohmann/detail/conversions/to_json.hpp index 0a802369..d274eadd 100644 --- a/include/nlohmann/detail/conversions/to_json.hpp +++ b/include/nlohmann/detail/conversions/to_json.hpp @@ -306,13 +306,13 @@ void to_json(BasicJsonType& j, const std::pair& p) // for https://github.com/nlohmann/json/pull/1134 template::iteration_proxy_internal>::value, int> = 0> -void to_json(BasicJsonType& j, T b) noexcept +void to_json(BasicJsonType& j, const T& b) { j = {{b.key(), b.value()}}; } template -void to_json_tuple_impl(BasicJsonType& j, const Tuple& t, index_sequence) +void to_json_tuple_impl(BasicJsonType& j, const Tuple& t, index_sequence /*unused*/) { j = {std::get(t)...}; } @@ -332,11 +332,11 @@ struct to_json_fn return to_json(j, std::forward(val)); } }; -} +} // namespace detail /// namespace to hold default `to_json` function namespace { constexpr const auto& to_json = detail::static_const::value; -} -} +} // namespace +} // namespace nlohmann diff --git a/include/nlohmann/detail/exceptions.hpp b/include/nlohmann/detail/exceptions.hpp index bab76b62..5b0420e2 100644 --- a/include/nlohmann/detail/exceptions.hpp +++ b/include/nlohmann/detail/exceptions.hpp @@ -4,6 +4,8 @@ #include // runtime_error #include // to_string +#include + namespace nlohmann { namespace detail @@ -115,15 +117,23 @@ class parse_error : public exception /*! @brief create a parse error exception @param[in] id_ the id of the exception - @param[in] byte_ the byte index where the error occurred (or 0 if the - position cannot be determined) + @param[in] position the position where the error occurred (or with + chars_read_total=0 if the position cannot be + determined) @param[in] what_arg the explanatory string @return parse_error object */ + static parse_error create(int id_, const position_t& pos, const std::string& what_arg) + { + std::string w = exception::name("parse_error", id_) + "parse error" + + position_string(pos) + ": " + what_arg; + return parse_error(id_, pos.chars_read_total, w.c_str()); + } + static parse_error create(int id_, std::size_t byte_, const std::string& what_arg) { std::string w = exception::name("parse_error", id_) + "parse error" + - (byte_ != 0 ? (" at " + std::to_string(byte_)) : "") + + (byte_ != 0 ? (" at byte " + std::to_string(byte_)) : "") + ": " + what_arg; return parse_error(id_, byte_, w.c_str()); } @@ -142,6 +152,12 @@ class parse_error : public exception private: parse_error(int id_, std::size_t byte_, const char* what_arg) : exception(id_, what_arg), byte(byte_) {} + + static std::string position_string(const position_t& pos) + { + return " at line " + std::to_string(pos.lines_read + 1) + + ", column " + std::to_string(pos.chars_read_current_line); + } }; /*! @@ -329,5 +345,5 @@ class other_error : public exception private: other_error(int id_, const char* what_arg) : exception(id_, what_arg) {} }; -} -} +} // namespace detail +} // namespace nlohmann diff --git a/include/nlohmann/detail/input/binary_reader.hpp b/include/nlohmann/detail/input/binary_reader.hpp index 8dfe3b98..c213d855 100644 --- a/include/nlohmann/detail/input/binary_reader.hpp +++ b/include/nlohmann/detail/input/binary_reader.hpp @@ -104,7 +104,8 @@ class binary_reader if (JSON_UNLIKELY(current != std::char_traits::eof())) { - return sax->parse_error(chars_read, get_token_string(), parse_error::create(110, chars_read, "expected end of input")); + return sax->parse_error(chars_read, get_token_string(), + parse_error::create(110, chars_read, exception_message(format, "expected end of input; last byte: 0x" + get_token_string(), "value"))); } } @@ -139,7 +140,7 @@ class binary_reader while (true) { get(); - if (JSON_UNLIKELY(not unexpect_eof())) + if (JSON_UNLIKELY(not unexpect_eof(input_format_t::bson, "cstring"))) { return false; } @@ -165,7 +166,7 @@ class binary_reader template bool get_bson_string(const NumberType len, string_t& result) { - return get_string(len - static_cast(1), result) + return get_string(input_format_t::bson, len - static_cast(1), result) && get() != std::char_traits::eof(); } @@ -195,14 +196,14 @@ class binary_reader case 0x01: // double { double number; - return get_number(number) + return get_number(input_format_t::bson, number) && sax->number_float(static_cast(number), ""); } case 0x02: // string { std::int32_t len; string_t value; - return get_number(len) + return get_number(input_format_t::bson, len) && get_bson_string(len, value) && sax->string(value); } @@ -213,13 +214,13 @@ class binary_reader case 0x10: // int32 { std::int32_t value; - return get_number(value) + return get_number(input_format_t::bson, value) && sax->number_integer(static_cast(value)); } case 0x12: // int64 { std::int64_t value; - return get_number(value) + return get_number(input_format_t::bson, value) && sax->number_integer(static_cast(value)); } case 0x0A: // null @@ -256,7 +257,7 @@ class binary_reader { while (auto element_type = get()) { - if (JSON_UNLIKELY(not unexpect_eof())) + if (JSON_UNLIKELY(not unexpect_eof(input_format_t::bson, "element list"))) { return false; } @@ -288,7 +289,7 @@ class binary_reader bool parse_bson_array() { std::int32_t documentSize; - get_number(documentSize); + get_number(input_format_t::bson, documentSize); if (JSON_UNLIKELY(not sax->start_array(-1))) { @@ -310,7 +311,7 @@ class binary_reader bool parse_bson_internal() { std::int32_t documentSize; - get_number(documentSize); + get_number(input_format_t::bson, documentSize); if (JSON_UNLIKELY(not sax->start_object(-1))) { @@ -338,7 +339,7 @@ class binary_reader { // EOF case std::char_traits::eof(): - return unexpect_eof(); + return unexpect_eof(input_format_t::cbor, "value"); // Integer 0x00..0x17 (0..23) case 0x00: @@ -370,25 +371,25 @@ class binary_reader case 0x18: // Unsigned integer (one-byte uint8_t follows) { uint8_t number; - return get_number(number) and sax->number_unsigned(number); + return get_number(input_format_t::cbor, number) and sax->number_unsigned(number); } case 0x19: // Unsigned integer (two-byte uint16_t follows) { uint16_t number; - return get_number(number) and sax->number_unsigned(number); + return get_number(input_format_t::cbor, number) and sax->number_unsigned(number); } case 0x1A: // Unsigned integer (four-byte uint32_t follows) { uint32_t number; - return get_number(number) and sax->number_unsigned(number); + return get_number(input_format_t::cbor, number) and sax->number_unsigned(number); } case 0x1B: // Unsigned integer (eight-byte uint64_t follows) { uint64_t number; - return get_number(number) and sax->number_unsigned(number); + return get_number(input_format_t::cbor, number) and sax->number_unsigned(number); } // Negative integer -1-0x00..-1-0x17 (-1..-24) @@ -421,25 +422,25 @@ class binary_reader case 0x38: // Negative integer (one-byte uint8_t follows) { uint8_t number; - return get_number(number) and sax->number_integer(static_cast(-1) - number); + return get_number(input_format_t::cbor, number) and sax->number_integer(static_cast(-1) - number); } case 0x39: // Negative integer -1-n (two-byte uint16_t follows) { uint16_t number; - return get_number(number) and sax->number_integer(static_cast(-1) - number); + return get_number(input_format_t::cbor, number) and sax->number_integer(static_cast(-1) - number); } case 0x3A: // Negative integer -1-n (four-byte uint32_t follows) { uint32_t number; - return get_number(number) and sax->number_integer(static_cast(-1) - number); + return get_number(input_format_t::cbor, number) and sax->number_integer(static_cast(-1) - number); } case 0x3B: // Negative integer -1-n (eight-byte uint64_t follows) { uint64_t number; - return get_number(number) and sax->number_integer(static_cast(-1) + return get_number(input_format_t::cbor, number) and sax->number_integer(static_cast(-1) - static_cast(number)); } @@ -508,25 +509,25 @@ class binary_reader case 0x98: // array (one-byte uint8_t for n follows) { uint8_t len; - return get_number(len) and get_cbor_array(static_cast(len)); + return get_number(input_format_t::cbor, len) and get_cbor_array(static_cast(len)); } case 0x99: // array (two-byte uint16_t for n follow) { uint16_t len; - return get_number(len) and get_cbor_array(static_cast(len)); + return get_number(input_format_t::cbor, len) and get_cbor_array(static_cast(len)); } case 0x9A: // array (four-byte uint32_t for n follow) { uint32_t len; - return get_number(len) and get_cbor_array(static_cast(len)); + return get_number(input_format_t::cbor, len) and get_cbor_array(static_cast(len)); } case 0x9B: // array (eight-byte uint64_t for n follow) { uint64_t len; - return get_number(len) and get_cbor_array(static_cast(len)); + return get_number(input_format_t::cbor, len) and get_cbor_array(static_cast(len)); } case 0x9F: // array (indefinite length) @@ -562,25 +563,25 @@ class binary_reader case 0xB8: // map (one-byte uint8_t for n follows) { uint8_t len; - return get_number(len) and get_cbor_object(static_cast(len)); + return get_number(input_format_t::cbor, len) and get_cbor_object(static_cast(len)); } case 0xB9: // map (two-byte uint16_t for n follow) { uint16_t len; - return get_number(len) and get_cbor_object(static_cast(len)); + return get_number(input_format_t::cbor, len) and get_cbor_object(static_cast(len)); } case 0xBA: // map (four-byte uint32_t for n follow) { uint32_t len; - return get_number(len) and get_cbor_object(static_cast(len)); + return get_number(input_format_t::cbor, len) and get_cbor_object(static_cast(len)); } case 0xBB: // map (eight-byte uint64_t for n follow) { uint64_t len; - return get_number(len) and get_cbor_object(static_cast(len)); + return get_number(input_format_t::cbor, len) and get_cbor_object(static_cast(len)); } case 0xBF: // map (indefinite length) @@ -597,17 +598,20 @@ class binary_reader case 0xF9: // Half-Precision Float (two-byte IEEE 754) { - const int byte1 = get(); - if (JSON_UNLIKELY(not unexpect_eof())) + const int byte1_raw = get(); + if (JSON_UNLIKELY(not unexpect_eof(input_format_t::cbor, "number"))) { return false; } - const int byte2 = get(); - if (JSON_UNLIKELY(not unexpect_eof())) + const int byte2_raw = get(); + if (JSON_UNLIKELY(not unexpect_eof(input_format_t::cbor, "number"))) { return false; } + const auto byte1 = static_cast(byte1_raw); + const auto byte2 = static_cast(byte2_raw); + // code from RFC 7049, Appendix D, Figure 3: // As half-precision floating-point numbers were only added // to IEEE 754 in 2008, today's programming platforms often @@ -643,19 +647,19 @@ class binary_reader case 0xFA: // Single-Precision Float (four-byte IEEE 754) { float number; - return get_number(number) and sax->number_float(static_cast(number), ""); + return get_number(input_format_t::cbor, number) and sax->number_float(static_cast(number), ""); } case 0xFB: // Double-Precision Float (eight-byte IEEE 754) { double number; - return get_number(number) and sax->number_float(static_cast(number), ""); + return get_number(input_format_t::cbor, number) and sax->number_float(static_cast(number), ""); } default: // anything else (0xFF is handled inside the other types) { auto last_token = get_token_string(); - return sax->parse_error(chars_read, last_token, parse_error::create(112, chars_read, "error reading CBOR; last byte: 0x" + last_token)); + return sax->parse_error(chars_read, last_token, parse_error::create(112, chars_read, exception_message(input_format_t::cbor, "invalid byte: 0x" + last_token, "value"))); } } } @@ -669,7 +673,7 @@ class binary_reader { // EOF case std::char_traits::eof(): - return unexpect_eof(); + return unexpect_eof(input_format_t::msgpack, "value"); // positive fixint case 0x00: @@ -890,61 +894,61 @@ class binary_reader case 0xCA: // float 32 { float number; - return get_number(number) and sax->number_float(static_cast(number), ""); + return get_number(input_format_t::msgpack, number) and sax->number_float(static_cast(number), ""); } case 0xCB: // float 64 { double number; - return get_number(number) and sax->number_float(static_cast(number), ""); + return get_number(input_format_t::msgpack, number) and sax->number_float(static_cast(number), ""); } case 0xCC: // uint 8 { uint8_t number; - return get_number(number) and sax->number_unsigned(number); + return get_number(input_format_t::msgpack, number) and sax->number_unsigned(number); } case 0xCD: // uint 16 { uint16_t number; - return get_number(number) and sax->number_unsigned(number); + return get_number(input_format_t::msgpack, number) and sax->number_unsigned(number); } case 0xCE: // uint 32 { uint32_t number; - return get_number(number) and sax->number_unsigned(number); + return get_number(input_format_t::msgpack, number) and sax->number_unsigned(number); } case 0xCF: // uint 64 { uint64_t number; - return get_number(number) and sax->number_unsigned(number); + return get_number(input_format_t::msgpack, number) and sax->number_unsigned(number); } case 0xD0: // int 8 { int8_t number; - return get_number(number) and sax->number_integer(number); + return get_number(input_format_t::msgpack, number) and sax->number_integer(number); } case 0xD1: // int 16 { int16_t number; - return get_number(number) and sax->number_integer(number); + return get_number(input_format_t::msgpack, number) and sax->number_integer(number); } case 0xD2: // int 32 { int32_t number; - return get_number(number) and sax->number_integer(number); + return get_number(input_format_t::msgpack, number) and sax->number_integer(number); } case 0xD3: // int 64 { int64_t number; - return get_number(number) and sax->number_integer(number); + return get_number(input_format_t::msgpack, number) and sax->number_integer(number); } case 0xD9: // str 8 @@ -958,25 +962,25 @@ class binary_reader case 0xDC: // array 16 { uint16_t len; - return get_number(len) and get_msgpack_array(static_cast(len)); + return get_number(input_format_t::msgpack, len) and get_msgpack_array(static_cast(len)); } case 0xDD: // array 32 { uint32_t len; - return get_number(len) and get_msgpack_array(static_cast(len)); + return get_number(input_format_t::msgpack, len) and get_msgpack_array(static_cast(len)); } case 0xDE: // map 16 { uint16_t len; - return get_number(len) and get_msgpack_object(static_cast(len)); + return get_number(input_format_t::msgpack, len) and get_msgpack_object(static_cast(len)); } case 0xDF: // map 32 { uint32_t len; - return get_number(len) and get_msgpack_object(static_cast(len)); + return get_number(input_format_t::msgpack, len) and get_msgpack_object(static_cast(len)); } // negative fixint @@ -1017,7 +1021,7 @@ class binary_reader default: // anything else { auto last_token = get_token_string(); - return sax->parse_error(chars_read, last_token, parse_error::create(112, chars_read, "error reading MessagePack; last byte: 0x" + last_token)); + return sax->parse_error(chars_read, last_token, parse_error::create(112, chars_read, exception_message(input_format_t::msgpack, "invalid byte: 0x" + last_token, "value"))); } } } @@ -1067,6 +1071,7 @@ class binary_reader @brief read a number from the input @tparam NumberType the type of the number + @param[in] format the current format (for diagnostics) @param[out] result number of type @a NumberType @return whether conversion completed @@ -1076,14 +1081,14 @@ class binary_reader (big endian) and therefore need reordering on little endian systems. */ template - bool get_number(NumberType& result) + bool get_number(const input_format_t format, NumberType& result) { // step 1: read input into array with system's byte order std::array vec; for (std::size_t i = 0; i < sizeof(NumberType); ++i) { get(); - if (JSON_UNLIKELY(not unexpect_eof())) + if (JSON_UNLIKELY(not unexpect_eof(format, "number"))) { return false; } @@ -1109,8 +1114,9 @@ class binary_reader @brief create a string by reading characters from the input @tparam NumberType the type of the number + @param[in] format the current format (for diagnostics) @param[in] len number of characters to read - @param[out] string created by reading @a len bytes + @param[out] result string created by reading @a len bytes @return whether string creation completed @@ -1119,13 +1125,13 @@ class binary_reader the input before we run out of string memory. */ template - bool get_string(const NumberType len, string_t& result) + bool get_string(const input_format_t format, const NumberType len, string_t& result) { bool success = true; - std::generate_n(std::back_inserter(result), len, [this, &success]() + std::generate_n(std::back_inserter(result), len, [this, &success, &format]() { get(); - if (JSON_UNLIKELY(not unexpect_eof())) + if (JSON_UNLIKELY(not unexpect_eof(format, "string"))) { success = false; } @@ -1147,7 +1153,7 @@ class binary_reader */ bool get_cbor_string(string_t& result) { - if (JSON_UNLIKELY(not unexpect_eof())) + if (JSON_UNLIKELY(not unexpect_eof(input_format_t::cbor, "string"))) { return false; } @@ -1180,31 +1186,31 @@ class binary_reader case 0x76: case 0x77: { - return get_string(current & 0x1F, result); + return get_string(input_format_t::cbor, current & 0x1F, result); } case 0x78: // UTF-8 string (one-byte uint8_t for n follows) { uint8_t len; - return get_number(len) and get_string(len, result); + return get_number(input_format_t::cbor, len) and get_string(input_format_t::cbor, len, result); } case 0x79: // UTF-8 string (two-byte uint16_t for n follow) { uint16_t len; - return get_number(len) and get_string(len, result); + return get_number(input_format_t::cbor, len) and get_string(input_format_t::cbor, len, result); } case 0x7A: // UTF-8 string (four-byte uint32_t for n follow) { uint32_t len; - return get_number(len) and get_string(len, result); + return get_number(input_format_t::cbor, len) and get_string(input_format_t::cbor, len, result); } case 0x7B: // UTF-8 string (eight-byte uint64_t for n follow) { uint64_t len; - return get_number(len) and get_string(len, result); + return get_number(input_format_t::cbor, len) and get_string(input_format_t::cbor, len, result); } case 0x7F: // UTF-8 string (indefinite length) @@ -1224,7 +1230,7 @@ class binary_reader default: { auto last_token = get_token_string(); - return sax->parse_error(chars_read, last_token, parse_error::create(113, chars_read, "expected a CBOR string; last byte: 0x" + last_token)); + return sax->parse_error(chars_read, last_token, parse_error::create(113, chars_read, exception_message(input_format_t::cbor, "expected length specification (0x60-0x7B) or indefinite string type (0x7F); last byte: 0x" + last_token, "string"))); } } } @@ -1242,6 +1248,7 @@ class binary_reader } if (len != std::size_t(-1)) + { for (std::size_t i = 0; i < len; ++i) { if (JSON_UNLIKELY(not parse_cbor_internal())) @@ -1249,6 +1256,7 @@ class binary_reader return false; } } + } else { while (get() != 0xFF) @@ -1325,7 +1333,7 @@ class binary_reader */ bool get_msgpack_string(string_t& result) { - if (JSON_UNLIKELY(not unexpect_eof())) + if (JSON_UNLIKELY(not unexpect_eof(input_format_t::msgpack, "string"))) { return false; } @@ -1366,31 +1374,31 @@ class binary_reader case 0xBE: case 0xBF: { - return get_string(current & 0x1F, result); + return get_string(input_format_t::msgpack, current & 0x1F, result); } case 0xD9: // str 8 { uint8_t len; - return get_number(len) and get_string(len, result); + return get_number(input_format_t::msgpack, len) and get_string(input_format_t::msgpack, len, result); } case 0xDA: // str 16 { uint16_t len; - return get_number(len) and get_string(len, result); + return get_number(input_format_t::msgpack, len) and get_string(input_format_t::msgpack, len, result); } case 0xDB: // str 32 { uint32_t len; - return get_number(len) and get_string(len, result); + return get_number(input_format_t::msgpack, len) and get_string(input_format_t::msgpack, len, result); } default: { auto last_token = get_token_string(); - return sax->parse_error(chars_read, last_token, parse_error::create(113, chars_read, "expected a MessagePack string; last byte: 0x" + last_token)); + return sax->parse_error(chars_read, last_token, parse_error::create(113, chars_read, exception_message(input_format_t::msgpack, "expected length specification (0xA0-0xBF, 0xD9-0xDB); last byte: 0x" + last_token, "string"))); } } } @@ -1468,7 +1476,7 @@ class binary_reader get(); // TODO: may we ignore N here? } - if (JSON_UNLIKELY(not unexpect_eof())) + if (JSON_UNLIKELY(not unexpect_eof(input_format_t::ubjson, "value"))) { return false; } @@ -1478,36 +1486,36 @@ class binary_reader case 'U': { uint8_t len; - return get_number(len) and get_string(len, result); + return get_number(input_format_t::ubjson, len) and get_string(input_format_t::ubjson, len, result); } case 'i': { int8_t len; - return get_number(len) and get_string(len, result); + return get_number(input_format_t::ubjson, len) and get_string(input_format_t::ubjson, len, result); } case 'I': { int16_t len; - return get_number(len) and get_string(len, result); + return get_number(input_format_t::ubjson, len) and get_string(input_format_t::ubjson, len, result); } case 'l': { int32_t len; - return get_number(len) and get_string(len, result); + return get_number(input_format_t::ubjson, len) and get_string(input_format_t::ubjson, len, result); } case 'L': { int64_t len; - return get_number(len) and get_string(len, result); + return get_number(input_format_t::ubjson, len) and get_string(input_format_t::ubjson, len, result); } default: auto last_token = get_token_string(); - return sax->parse_error(chars_read, last_token, parse_error::create(113, chars_read, "expected a UBJSON string; last byte: 0x" + last_token)); + return sax->parse_error(chars_read, last_token, parse_error::create(113, chars_read, exception_message(input_format_t::ubjson, "expected length type specification (U, i, I, l, L); last byte: 0x" + last_token, "string"))); } } @@ -1522,7 +1530,7 @@ class binary_reader case 'U': { uint8_t number; - if (JSON_UNLIKELY(not get_number(number))) + if (JSON_UNLIKELY(not get_number(input_format_t::ubjson, number))) { return false; } @@ -1533,7 +1541,7 @@ class binary_reader case 'i': { int8_t number; - if (JSON_UNLIKELY(not get_number(number))) + if (JSON_UNLIKELY(not get_number(input_format_t::ubjson, number))) { return false; } @@ -1544,7 +1552,7 @@ class binary_reader case 'I': { int16_t number; - if (JSON_UNLIKELY(not get_number(number))) + if (JSON_UNLIKELY(not get_number(input_format_t::ubjson, number))) { return false; } @@ -1555,7 +1563,7 @@ class binary_reader case 'l': { int32_t number; - if (JSON_UNLIKELY(not get_number(number))) + if (JSON_UNLIKELY(not get_number(input_format_t::ubjson, number))) { return false; } @@ -1566,7 +1574,7 @@ class binary_reader case 'L': { int64_t number; - if (JSON_UNLIKELY(not get_number(number))) + if (JSON_UNLIKELY(not get_number(input_format_t::ubjson, number))) { return false; } @@ -1577,7 +1585,7 @@ class binary_reader default: { auto last_token = get_token_string(); - return sax->parse_error(chars_read, last_token, parse_error::create(113, chars_read, "byte after '#' must denote a number type; last byte: 0x" + last_token)); + return sax->parse_error(chars_read, last_token, parse_error::create(113, chars_read, exception_message(input_format_t::ubjson, "expected length type specification (U, i, I, l, L) after '#'; last byte: 0x" + last_token, "size"))); } } } @@ -1602,7 +1610,7 @@ class binary_reader if (current == '$') { result.second = get(); // must not ignore 'N', because 'N' maybe the type - if (JSON_UNLIKELY(not unexpect_eof())) + if (JSON_UNLIKELY(not unexpect_eof(input_format_t::ubjson, "type"))) { return false; } @@ -1610,12 +1618,12 @@ class binary_reader get_ignore_noop(); if (JSON_UNLIKELY(current != '#')) { - if (JSON_UNLIKELY(not unexpect_eof())) + if (JSON_UNLIKELY(not unexpect_eof(input_format_t::ubjson, "value"))) { return false; } auto last_token = get_token_string(); - return sax->parse_error(chars_read, last_token, parse_error::create(112, chars_read, "expected '#' after UBJSON type information; last byte: 0x" + last_token)); + return sax->parse_error(chars_read, last_token, parse_error::create(112, chars_read, exception_message(input_format_t::ubjson, "expected '#' after type information; last byte: 0x" + last_token, "size"))); } return get_ubjson_size_value(result.first); @@ -1636,7 +1644,7 @@ class binary_reader switch (prefix) { case std::char_traits::eof(): // EOF - return unexpect_eof(); + return unexpect_eof(input_format_t::ubjson, "value"); case 'T': // true return sax->boolean(true); @@ -1649,56 +1657,56 @@ class binary_reader case 'U': { uint8_t number; - return get_number(number) and sax->number_unsigned(number); + return get_number(input_format_t::ubjson, number) and sax->number_unsigned(number); } case 'i': { int8_t number; - return get_number(number) and sax->number_integer(number); + return get_number(input_format_t::ubjson, number) and sax->number_integer(number); } case 'I': { int16_t number; - return get_number(number) and sax->number_integer(number); + return get_number(input_format_t::ubjson, number) and sax->number_integer(number); } case 'l': { int32_t number; - return get_number(number) and sax->number_integer(number); + return get_number(input_format_t::ubjson, number) and sax->number_integer(number); } case 'L': { int64_t number; - return get_number(number) and sax->number_integer(number); + return get_number(input_format_t::ubjson, number) and sax->number_integer(number); } case 'd': { float number; - return get_number(number) and sax->number_float(static_cast(number), ""); + return get_number(input_format_t::ubjson, number) and sax->number_float(static_cast(number), ""); } case 'D': { double number; - return get_number(number) and sax->number_float(static_cast(number), ""); + return get_number(input_format_t::ubjson, number) and sax->number_float(static_cast(number), ""); } case 'C': // char { get(); - if (JSON_UNLIKELY(not unexpect_eof())) + if (JSON_UNLIKELY(not unexpect_eof(input_format_t::ubjson, "char"))) { return false; } if (JSON_UNLIKELY(current > 127)) { auto last_token = get_token_string(); - return sax->parse_error(chars_read, last_token, parse_error::create(113, chars_read, "byte after 'C' must be in range 0x00..0x7F; last byte: 0x" + last_token)); + return sax->parse_error(chars_read, last_token, parse_error::create(113, chars_read, exception_message(input_format_t::ubjson, "byte after 'C' must be in range 0x00..0x7F; last byte: 0x" + last_token, "char"))); } string_t s(1, static_cast(current)); return sax->string(s); @@ -1719,7 +1727,7 @@ class binary_reader default: // anything else { auto last_token = get_token_string(); - return sax->parse_error(chars_read, last_token, parse_error::create(112, chars_read, "error reading UBJSON; last byte: 0x" + last_token)); + return sax->parse_error(chars_read, last_token, parse_error::create(112, chars_read, exception_message(input_format_t::ubjson, "invalid byte: 0x" + last_token, "value"))); } } } @@ -1862,13 +1870,16 @@ class binary_reader } /*! + @param[in] format the current format (for diagnostics) + @param[in] context further context information (for diagnostics) @return whether the last read character is not EOF */ - bool unexpect_eof() const + bool unexpect_eof(const input_format_t format, const char* context) const { if (JSON_UNLIKELY(current == std::char_traits::eof())) { - return sax->parse_error(chars_read, "", parse_error::create(110, chars_read, "unexpected end of input")); + return sax->parse_error(chars_read, "", + parse_error::create(110, chars_read, exception_message(format, "unexpected end of input", context))); } return true; } @@ -1884,6 +1895,45 @@ class binary_reader } private: + /*! + @param[in] format the current format + @param[in] detail a detailed error message + @param[in] context further contect information + @return a message string to use in the parse_error exceptions + */ + std::string exception_message(const input_format_t format, + const std::string& detail, + const std::string& context) const + { + std::string error_msg = "syntax error while parsing "; + + switch (format) + { + case input_format_t::cbor: + error_msg += "CBOR"; + break; + + case input_format_t::msgpack: + error_msg += "MessagePack"; + break; + + case input_format_t::ubjson: + error_msg += "UBJSON"; + break; + + case input_format_t::bson: + error_msg += "BSON"; + break; + + // LCOV_EXCL_START + default: + assert(false); + // LCOV_EXCL_STOP + } + + return error_msg + " " + context + ": " + detail; + } + /// input adapter input_adapter_t ia = nullptr; @@ -1899,5 +1949,5 @@ class binary_reader /// the SAX parser json_sax_t* sax = nullptr; }; -} -} +} // namespace detail +} // namespace nlohmann diff --git a/include/nlohmann/detail/input/input_adapters.hpp b/include/nlohmann/detail/input/input_adapters.hpp index a877984e..8b7852b8 100644 --- a/include/nlohmann/detail/input/input_adapters.hpp +++ b/include/nlohmann/detail/input/input_adapters.hpp @@ -71,6 +71,8 @@ class input_stream_adapter : public input_adapter_protocol // delete because of pointer members input_stream_adapter(const input_stream_adapter&) = delete; input_stream_adapter& operator=(input_stream_adapter&) = delete; + input_stream_adapter(input_stream_adapter&&) = delete; + input_stream_adapter& operator=(input_stream_adapter&&) = delete; // std::istream/std::streambuf use std::char_traits::to_int_type, to // ensure that std::char_traits::eof() and the character 0xFF do not @@ -97,6 +99,9 @@ class input_buffer_adapter : public input_adapter_protocol // delete because of pointer members input_buffer_adapter(const input_buffer_adapter&) = delete; input_buffer_adapter& operator=(input_buffer_adapter&) = delete; + input_buffer_adapter(input_buffer_adapter&&) = delete; + input_buffer_adapter& operator=(input_buffer_adapter&&) = delete; + ~input_buffer_adapter() override = default; std::char_traits::int_type get_character() noexcept override { @@ -115,38 +120,11 @@ class input_buffer_adapter : public input_adapter_protocol const char* const limit; }; -template -class wide_string_input_adapter : public input_adapter_protocol +template +struct wide_string_input_helper { - public: - explicit wide_string_input_adapter(const WideStringType& w) : str(w) {} - - std::char_traits::int_type get_character() noexcept override - { - // check if buffer needs to be filled - if (utf8_bytes_index == utf8_bytes_filled) - { - if (sizeof(typename WideStringType::value_type) == 2) - { - fill_buffer_utf16(); - } - else - { - fill_buffer_utf32(); - } - - assert(utf8_bytes_filled > 0); - assert(utf8_bytes_index == 0); - } - - // use buffer - assert(utf8_bytes_filled > 0); - assert(utf8_bytes_index < utf8_bytes_filled); - return utf8_bytes[utf8_bytes_index++]; - } - - private: - void fill_buffer_utf16() + // UTF-32 + static void fill_buffer(const WideStringType& str, size_t& current_wchar, std::array::int_type, 4>& utf8_bytes, size_t& utf8_bytes_index, size_t& utf8_bytes_filled) { utf8_bytes_index = 0; @@ -158,7 +136,62 @@ class wide_string_input_adapter : public input_adapter_protocol else { // get the current character - const int wc = static_cast(str[current_wchar++]); + const auto wc = static_cast(str[current_wchar++]); + + // UTF-32 to UTF-8 encoding + if (wc < 0x80) + { + utf8_bytes[0] = wc; + utf8_bytes_filled = 1; + } + else if (wc <= 0x7FF) + { + utf8_bytes[0] = 0xC0 | ((wc >> 6) & 0x1F); + utf8_bytes[1] = 0x80 | (wc & 0x3F); + utf8_bytes_filled = 2; + } + else if (wc <= 0xFFFF) + { + utf8_bytes[0] = 0xE0 | ((wc >> 12) & 0x0F); + utf8_bytes[1] = 0x80 | ((wc >> 6) & 0x3F); + utf8_bytes[2] = 0x80 | (wc & 0x3F); + utf8_bytes_filled = 3; + } + else if (wc <= 0x10FFFF) + { + utf8_bytes[0] = 0xF0 | ((wc >> 18) & 0x07); + utf8_bytes[1] = 0x80 | ((wc >> 12) & 0x3F); + utf8_bytes[2] = 0x80 | ((wc >> 6) & 0x3F); + utf8_bytes[3] = 0x80 | (wc & 0x3F); + utf8_bytes_filled = 4; + } + else + { + // unknown character + utf8_bytes[0] = wc; + utf8_bytes_filled = 1; + } + } + } +}; + +template +struct wide_string_input_helper +{ + // UTF-16 + static void fill_buffer(const WideStringType& str, size_t& current_wchar, std::array::int_type, 4>& utf8_bytes, size_t& utf8_bytes_index, size_t& utf8_bytes_filled) + { + utf8_bytes_index = 0; + + if (current_wchar == str.size()) + { + utf8_bytes[0] = std::char_traits::eof(); + utf8_bytes_filled = 1; + } + else + { + // get the current character + const auto wc = static_cast(str[current_wchar++]); // UTF-16 to UTF-8 encoding if (wc < 0x80) @@ -183,7 +216,7 @@ class wide_string_input_adapter : public input_adapter_protocol { if (current_wchar < str.size()) { - const int wc2 = static_cast(str[current_wchar++]); + const auto wc2 = static_cast(str[current_wchar++]); const int charcode = 0x10000 + (((wc & 0x3FF) << 10) | (wc2 & 0x3FF)); utf8_bytes[0] = 0xf0 | (charcode >> 18); utf8_bytes[1] = 0x80 | ((charcode >> 12) & 0x3F); @@ -201,58 +234,38 @@ class wide_string_input_adapter : public input_adapter_protocol } } } +}; - void fill_buffer_utf32() +template +class wide_string_input_adapter : public input_adapter_protocol +{ + public: + explicit wide_string_input_adapter(const WideStringType& w) : str(w) {} + + std::char_traits::int_type get_character() noexcept override { - utf8_bytes_index = 0; - - if (current_wchar == str.size()) + // check if buffer needs to be filled + if (utf8_bytes_index == utf8_bytes_filled) { - utf8_bytes[0] = std::char_traits::eof(); - utf8_bytes_filled = 1; - } - else - { - // get the current character - const int wc = static_cast(str[current_wchar++]); + fill_buffer(); - // UTF-32 to UTF-8 encoding - if (wc < 0x80) - { - utf8_bytes[0] = wc; - utf8_bytes_filled = 1; - } - else if (wc <= 0x7FF) - { - utf8_bytes[0] = 0xC0 | ((wc >> 6) & 0x1F); - utf8_bytes[1] = 0x80 | (wc & 0x3F); - utf8_bytes_filled = 2; - } - else if (wc <= 0xFFFF) - { - utf8_bytes[0] = 0xE0 | ((wc >> 12) & 0x0F); - utf8_bytes[1] = 0x80 | ((wc >> 6) & 0x3F); - utf8_bytes[2] = 0x80 | (wc & 0x3F); - utf8_bytes_filled = 3; - } - else if (wc <= 0x10FFFF) - { - utf8_bytes[0] = 0xF0 | ((wc >> 18 ) & 0x07); - utf8_bytes[1] = 0x80 | ((wc >> 12) & 0x3F); - utf8_bytes[2] = 0x80 | ((wc >> 6) & 0x3F); - utf8_bytes[3] = 0x80 | (wc & 0x3F); - utf8_bytes_filled = 4; - } - else - { - // unknown character - utf8_bytes[0] = wc; - utf8_bytes_filled = 1; - } + assert(utf8_bytes_filled > 0); + assert(utf8_bytes_index == 0); } + + // use buffer + assert(utf8_bytes_filled > 0); + assert(utf8_bytes_index < utf8_bytes_filled); + return utf8_bytes[utf8_bytes_index++]; } private: + template + void fill_buffer() + { + wide_string_input_helper::fill_buffer(str, current_wchar, utf8_bytes, utf8_bytes_index, utf8_bytes_filled); + } + /// the wstring to process const WideStringType& str; @@ -373,5 +386,5 @@ class input_adapter /// the actual adapter input_adapter_t ia = nullptr; }; -} -} +} // namespace detail +} // namespace nlohmann diff --git a/include/nlohmann/detail/input/json_sax.hpp b/include/nlohmann/detail/input/json_sax.hpp index 1705a861..153f75d2 100644 --- a/include/nlohmann/detail/input/json_sax.hpp +++ b/include/nlohmann/detail/input/json_sax.hpp @@ -113,7 +113,7 @@ struct json_sax @brief a parse error occurred @param[in] position the position in the input where the error occurs @param[in] last_token the last read token - @param[in] error_msg a detailed error message + @param[in] ex an exception object describing the error @return whether parsing should proceed (must return false) */ virtual bool parse_error(std::size_t position, @@ -181,7 +181,7 @@ class json_sax_dom_parser return true; } - bool number_float(number_float_t val, const string_t&) + bool number_float(number_float_t val, const string_t& /*unused*/) { handle_value(val); return true; @@ -238,7 +238,7 @@ class json_sax_dom_parser return true; } - bool parse_error(std::size_t, const std::string&, + bool parse_error(std::size_t /*unused*/, const std::string& /*unused*/, const detail::exception& ex) { errored = true; @@ -286,20 +286,19 @@ class json_sax_dom_parser root = BasicJsonType(std::forward(v)); return &root; } + + assert(ref_stack.back()->is_array() or ref_stack.back()->is_object()); + + if (ref_stack.back()->is_array()) + { + ref_stack.back()->m_value.array->emplace_back(std::forward(v)); + return &(ref_stack.back()->m_value.array->back()); + } else { - assert(ref_stack.back()->is_array() or ref_stack.back()->is_object()); - if (ref_stack.back()->is_array()) - { - ref_stack.back()->m_value.array->emplace_back(std::forward(v)); - return &(ref_stack.back()->m_value.array->back()); - } - else - { - assert(object_element); - *object_element = BasicJsonType(std::forward(v)); - return object_element; - } + assert(object_element); + *object_element = BasicJsonType(std::forward(v)); + return object_element; } } @@ -358,7 +357,7 @@ class json_sax_dom_callback_parser return true; } - bool number_float(number_float_t val, const string_t&) + bool number_float(number_float_t val, const string_t& /*unused*/) { handle_value(val); return true; @@ -496,7 +495,7 @@ class json_sax_dom_callback_parser return true; } - bool parse_error(std::size_t, const std::string&, + bool parse_error(std::size_t /*unused*/, const std::string& /*unused*/, const detail::exception& ex) { errored = true; @@ -574,37 +573,37 @@ class json_sax_dom_callback_parser root = std::move(value); return {true, &root}; } + + // skip this value if we already decided to skip the parent + // (https://github.com/nlohmann/json/issues/971#issuecomment-413678360) + if (not ref_stack.back()) + { + return {false, nullptr}; + } + + // we now only expect arrays and objects + assert(ref_stack.back()->is_array() or ref_stack.back()->is_object()); + + if (ref_stack.back()->is_array()) + { + ref_stack.back()->m_value.array->push_back(std::move(value)); + return {true, &(ref_stack.back()->m_value.array->back())}; + } else { - // skip this value if we already decided to skip the parent - // (https://github.com/nlohmann/json/issues/971#issuecomment-413678360) - if (not ref_stack.back()) + // check if we should store an element for the current key + assert(not key_keep_stack.empty()); + const bool store_element = key_keep_stack.back(); + key_keep_stack.pop_back(); + + if (not store_element) { return {false, nullptr}; } - assert(ref_stack.back()->is_array() or ref_stack.back()->is_object()); - if (ref_stack.back()->is_array()) - { - ref_stack.back()->m_value.array->push_back(std::move(value)); - return {true, &(ref_stack.back()->m_value.array->back())}; - } - else - { - // check if we should store an element for the current key - assert(not key_keep_stack.empty()); - const bool store_element = key_keep_stack.back(); - key_keep_stack.pop_back(); - - if (not store_element) - { - return {false, nullptr}; - } - - assert(object_element); - *object_element = std::move(value); - return {true, object_element}; - } + assert(object_element); + *object_element = std::move(value); + return {true, object_element}; } } @@ -642,37 +641,37 @@ class json_sax_acceptor return true; } - bool boolean(bool) + bool boolean(bool /*unused*/) { return true; } - bool number_integer(number_integer_t) + bool number_integer(number_integer_t /*unused*/) { return true; } - bool number_unsigned(number_unsigned_t) + bool number_unsigned(number_unsigned_t /*unused*/) { return true; } - bool number_float(number_float_t, const string_t&) + bool number_float(number_float_t /*unused*/, const string_t& /*unused*/) { return true; } - bool string(string_t&) + bool string(string_t& /*unused*/) { return true; } - bool start_object(std::size_t = std::size_t(-1)) + bool start_object(std::size_t /*unused*/ = std::size_t(-1)) { return true; } - bool key(string_t&) + bool key(string_t& /*unused*/) { return true; } @@ -682,7 +681,7 @@ class json_sax_acceptor return true; } - bool start_array(std::size_t = std::size_t(-1)) + bool start_array(std::size_t /*unused*/ = std::size_t(-1)) { return true; } @@ -692,11 +691,11 @@ class json_sax_acceptor return true; } - bool parse_error(std::size_t, const std::string&, const detail::exception&) + bool parse_error(std::size_t /*unused*/, const std::string& /*unused*/, const detail::exception& /*unused*/) { return false; } }; -} +} // namespace detail -} +} // namespace nlohmann diff --git a/include/nlohmann/detail/input/lexer.hpp b/include/nlohmann/detail/input/lexer.hpp index 44165ff0..dd474525 100644 --- a/include/nlohmann/detail/input/lexer.hpp +++ b/include/nlohmann/detail/input/lexer.hpp @@ -10,6 +10,7 @@ #include #include +#include namespace nlohmann { @@ -104,7 +105,10 @@ class lexer // delete because of pointer members lexer(const lexer&) = delete; + lexer(lexer&&) = delete; lexer& operator=(lexer&) = delete; + lexer& operator=(lexer&&) = delete; + ~lexer() = default; private: ///////////////////// @@ -393,39 +397,194 @@ class lexer // invalid control characters case 0x00: + { + error_message = "invalid string: control character U+0000 (NUL) must be escaped to \\u0000"; + return token_type::parse_error; + } + case 0x01: + { + error_message = "invalid string: control character U+0001 (SOH) must be escaped to \\u0001"; + return token_type::parse_error; + } + case 0x02: + { + error_message = "invalid string: control character U+0002 (STX) must be escaped to \\u0002"; + return token_type::parse_error; + } + case 0x03: + { + error_message = "invalid string: control character U+0003 (ETX) must be escaped to \\u0003"; + return token_type::parse_error; + } + case 0x04: + { + error_message = "invalid string: control character U+0004 (EOT) must be escaped to \\u0004"; + return token_type::parse_error; + } + case 0x05: + { + error_message = "invalid string: control character U+0005 (ENQ) must be escaped to \\u0005"; + return token_type::parse_error; + } + case 0x06: + { + error_message = "invalid string: control character U+0006 (ACK) must be escaped to \\u0006"; + return token_type::parse_error; + } + case 0x07: + { + error_message = "invalid string: control character U+0007 (BEL) must be escaped to \\u0007"; + return token_type::parse_error; + } + case 0x08: + { + error_message = "invalid string: control character U+0008 (BS) must be escaped to \\u0008 or \\b"; + return token_type::parse_error; + } + case 0x09: + { + error_message = "invalid string: control character U+0009 (HT) must be escaped to \\u0009 or \\t"; + return token_type::parse_error; + } + case 0x0A: + { + error_message = "invalid string: control character U+000A (LF) must be escaped to \\u000A or \\n"; + return token_type::parse_error; + } + case 0x0B: + { + error_message = "invalid string: control character U+000B (VT) must be escaped to \\u000B"; + return token_type::parse_error; + } + case 0x0C: + { + error_message = "invalid string: control character U+000C (FF) must be escaped to \\u000C or \\f"; + return token_type::parse_error; + } + case 0x0D: + { + error_message = "invalid string: control character U+000D (CR) must be escaped to \\u000D or \\r"; + return token_type::parse_error; + } + case 0x0E: + { + error_message = "invalid string: control character U+000E (SO) must be escaped to \\u000E"; + return token_type::parse_error; + } + case 0x0F: + { + error_message = "invalid string: control character U+000F (SI) must be escaped to \\u000F"; + return token_type::parse_error; + } + case 0x10: + { + error_message = "invalid string: control character U+0010 (DLE) must be escaped to \\u0010"; + return token_type::parse_error; + } + case 0x11: + { + error_message = "invalid string: control character U+0011 (DC1) must be escaped to \\u0011"; + return token_type::parse_error; + } + case 0x12: + { + error_message = "invalid string: control character U+0012 (DC2) must be escaped to \\u0012"; + return token_type::parse_error; + } + case 0x13: + { + error_message = "invalid string: control character U+0013 (DC3) must be escaped to \\u0013"; + return token_type::parse_error; + } + case 0x14: + { + error_message = "invalid string: control character U+0014 (DC4) must be escaped to \\u0014"; + return token_type::parse_error; + } + case 0x15: + { + error_message = "invalid string: control character U+0015 (NAK) must be escaped to \\u0015"; + return token_type::parse_error; + } + case 0x16: + { + error_message = "invalid string: control character U+0016 (SYN) must be escaped to \\u0016"; + return token_type::parse_error; + } + case 0x17: + { + error_message = "invalid string: control character U+0017 (ETB) must be escaped to \\u0017"; + return token_type::parse_error; + } + case 0x18: + { + error_message = "invalid string: control character U+0018 (CAN) must be escaped to \\u0018"; + return token_type::parse_error; + } + case 0x19: + { + error_message = "invalid string: control character U+0019 (EM) must be escaped to \\u0019"; + return token_type::parse_error; + } + case 0x1A: + { + error_message = "invalid string: control character U+001A (SUB) must be escaped to \\u001A"; + return token_type::parse_error; + } + case 0x1B: + { + error_message = "invalid string: control character U+001B (ESC) must be escaped to \\u001B"; + return token_type::parse_error; + } + case 0x1C: + { + error_message = "invalid string: control character U+001C (FS) must be escaped to \\u001C"; + return token_type::parse_error; + } + case 0x1D: + { + error_message = "invalid string: control character U+001D (GS) must be escaped to \\u001D"; + return token_type::parse_error; + } + case 0x1E: + { + error_message = "invalid string: control character U+001E (RS) must be escaped to \\u001E"; + return token_type::parse_error; + } + case 0x1F: { - error_message = "invalid string: control character must be escaped"; + error_message = "invalid string: control character U+001F (US) must be escaped to \\u001F"; return token_type::parse_error; } @@ -709,7 +868,7 @@ class lexer locale's decimal point is used instead of `.` to work with the locale-dependent converters. */ - token_type scan_number() + token_type scan_number() // lgtm [cpp/use-of-goto] { // reset token_buffer to store the number's bytes reset(); @@ -1082,7 +1241,9 @@ scan_number_done: */ std::char_traits::int_type get() { - ++chars_read; + ++position.chars_read_total; + ++position.chars_read_current_line; + if (next_unget) { // just reset the next_unget variable and work with current @@ -1097,6 +1258,13 @@ scan_number_done: { token_string.push_back(std::char_traits::to_char_type(current)); } + + if (current == '\n') + { + ++position.lines_read; + ++position.chars_read_current_line = 0; + } + return current; } @@ -1104,14 +1272,29 @@ scan_number_done: @brief unget current character (read it again on next get) We implement unget by setting variable next_unget to true. The input is not - changed - we just simulate ungetting by modifying chars_read and - token_string. The next call to get() will behave as if the unget character - is read again. + changed - we just simulate ungetting by modifying chars_read_total, + chars_read_current_line, and token_string. The next call to get() will + behave as if the unget character is read again. */ void unget() { next_unget = true; - --chars_read; + + --position.chars_read_total; + + // in case we "unget" a newline, we have to also decrement the lines_read + if (position.chars_read_current_line == 0) + { + if (position.lines_read > 0) + { + --position.lines_read; + } + } + else + { + --position.chars_read_current_line; + } + if (JSON_LIKELY(current != std::char_traits::eof())) { assert(token_string.size() != 0); @@ -1159,9 +1342,9 @@ scan_number_done: ///////////////////// /// return position of last read token - constexpr std::size_t get_position() const noexcept + constexpr position_t get_position() const noexcept { - return chars_read; + return position; } /// return the last read token (for errors only). Will never contain EOF @@ -1208,30 +1391,20 @@ scan_number_done: { if (get() == 0xEF) { - if (get() == 0xBB and get() == 0xBF) - { - // we completely parsed the BOM - return true; - } - else - { - // after reading 0xEF, an unexpected character followed - return false; - } - } - else - { - // the first character is not the beginning of the BOM; unget it to - // process is later - unget(); - return true; + // check if we completely parse the BOM + return get() == 0xBB and get() == 0xBF; } + + // the first character is not the beginning of the BOM; unget it to + // process is later + unget(); + return true; } token_type scan() { // initially, skip the BOM - if (chars_read == 0 and not skip_bom()) + if (position.chars_read_total == 0 and not skip_bom()) { error_message = "invalid BOM; must be 0xEF 0xBB 0xBF if given"; return token_type::parse_error; @@ -1309,8 +1482,8 @@ scan_number_done: /// whether the next get() call should just return current bool next_unget = false; - /// the number of characters read - std::size_t chars_read = 0; + /// the start position of the current token + position_t position; /// raw input token string (for error messages) std::vector token_string {}; @@ -1329,5 +1502,5 @@ scan_number_done: /// the decimal point const char decimal_point_char = '.'; }; -} -} +} // namespace detail +} // namespace nlohmann diff --git a/include/nlohmann/detail/input/parser.hpp b/include/nlohmann/detail/input/parser.hpp index 70d92a26..ac19bb8c 100644 --- a/include/nlohmann/detail/input/parser.hpp +++ b/include/nlohmann/detail/input/parser.hpp @@ -91,7 +91,8 @@ class parser { sdp.parse_error(m_lexer.get_position(), m_lexer.get_token_string(), - parse_error::create(101, m_lexer.get_position(), exception_message(token_type::end_of_input))); + parse_error::create(101, m_lexer.get_position(), + exception_message(token_type::end_of_input, "value"))); } // in case of an error, return discarded value @@ -119,7 +120,8 @@ class parser { sdp.parse_error(m_lexer.get_position(), m_lexer.get_token_string(), - parse_error::create(101, m_lexer.get_position(), exception_message(token_type::end_of_input))); + parse_error::create(101, m_lexer.get_position(), + exception_message(token_type::end_of_input, "value"))); } // in case of an error, return discarded value @@ -154,7 +156,8 @@ class parser { return sax->parse_error(m_lexer.get_position(), m_lexer.get_token_string(), - parse_error::create(101, m_lexer.get_position(), exception_message(token_type::end_of_input))); + parse_error::create(101, m_lexer.get_position(), + exception_message(token_type::end_of_input, "value"))); } return result; @@ -199,14 +202,12 @@ class parser { return sax->parse_error(m_lexer.get_position(), m_lexer.get_token_string(), - parse_error::create(101, m_lexer.get_position(), exception_message(token_type::value_string))); + parse_error::create(101, m_lexer.get_position(), + exception_message(token_type::value_string, "object key"))); } - else + if (JSON_UNLIKELY(not sax->key(m_lexer.get_string()))) { - if (JSON_UNLIKELY(not sax->key(m_lexer.get_string()))) - { - return false; - } + return false; } // parse separator (:) @@ -214,7 +215,8 @@ class parser { return sax->parse_error(m_lexer.get_position(), m_lexer.get_token_string(), - parse_error::create(101, m_lexer.get_position(), exception_message(token_type::name_separator))); + parse_error::create(101, m_lexer.get_position(), + exception_message(token_type::name_separator, "object separator"))); } // remember we are now inside an object @@ -328,14 +330,16 @@ class parser // using "uninitialized" to avoid "expected" message return sax->parse_error(m_lexer.get_position(), m_lexer.get_token_string(), - parse_error::create(101, m_lexer.get_position(), exception_message(token_type::uninitialized))); + parse_error::create(101, m_lexer.get_position(), + exception_message(token_type::uninitialized, "value"))); } default: // the last token was unexpected { return sax->parse_error(m_lexer.get_position(), m_lexer.get_token_string(), - parse_error::create(101, m_lexer.get_position(), exception_message(token_type::literal_or_value))); + parse_error::create(101, m_lexer.get_position(), + exception_message(token_type::literal_or_value, "value"))); } } } @@ -383,7 +387,8 @@ class parser { return sax->parse_error(m_lexer.get_position(), m_lexer.get_token_string(), - parse_error::create(101, m_lexer.get_position(), exception_message(token_type::end_array))); + parse_error::create(101, m_lexer.get_position(), + exception_message(token_type::end_array, "array"))); } } else // object @@ -396,7 +401,8 @@ class parser { return sax->parse_error(m_lexer.get_position(), m_lexer.get_token_string(), - parse_error::create(101, m_lexer.get_position(), exception_message(token_type::value_string))); + parse_error::create(101, m_lexer.get_position(), + exception_message(token_type::value_string, "object key"))); } else { @@ -411,7 +417,8 @@ class parser { return sax->parse_error(m_lexer.get_position(), m_lexer.get_token_string(), - parse_error::create(101, m_lexer.get_position(), exception_message(token_type::name_separator))); + parse_error::create(101, m_lexer.get_position(), + exception_message(token_type::name_separator, "object separator"))); } // parse values @@ -440,7 +447,8 @@ class parser { return sax->parse_error(m_lexer.get_position(), m_lexer.get_token_string(), - parse_error::create(101, m_lexer.get_position(), exception_message(token_type::end_object))); + parse_error::create(101, m_lexer.get_position(), + exception_message(token_type::end_object, "object"))); } } } @@ -453,9 +461,17 @@ class parser return (last_token = m_lexer.scan()); } - std::string exception_message(const token_type expected) + std::string exception_message(const token_type expected, const std::string& context) { - std::string error_msg = "syntax error - "; + std::string error_msg = "syntax error "; + + if (not context.empty()) + { + error_msg += "while parsing " + context + " "; + } + + error_msg += "- "; + if (last_token == token_type::parse_error) { error_msg += std::string(m_lexer.get_error_message()) + "; last read: '" + @@ -484,5 +500,5 @@ class parser /// whether to throw exceptions in case of errors const bool allow_exceptions = true; }; -} -} +} // namespace detail +} // namespace nlohmann diff --git a/include/nlohmann/detail/input/position_t.hpp b/include/nlohmann/detail/input/position_t.hpp new file mode 100644 index 00000000..37f4ab15 --- /dev/null +++ b/include/nlohmann/detail/input/position_t.hpp @@ -0,0 +1,27 @@ +#pragma once + +#include // size_t + +namespace nlohmann +{ +namespace detail +{ +/// struct to capture the start position of the current token +struct position_t +{ + /// the total number of characters read + std::size_t chars_read_total = 0; + /// the number of characters read in the current line + std::size_t chars_read_current_line = 0; + /// the number of lines read + std::size_t lines_read = 0; + + /// conversion to size_t to preserve SAX interface + constexpr operator size_t() const + { + return chars_read_total; + } +}; + +} +} diff --git a/include/nlohmann/detail/iterators/internal_iterator.hpp b/include/nlohmann/detail/iterators/internal_iterator.hpp index d9b8fb29..2c81f723 100644 --- a/include/nlohmann/detail/iterators/internal_iterator.hpp +++ b/include/nlohmann/detail/iterators/internal_iterator.hpp @@ -21,5 +21,5 @@ template struct internal_iterator /// generic iterator for all other types primitive_iterator_t primitive_iterator {}; }; -} -} +} // namespace detail +} // namespace nlohmann diff --git a/include/nlohmann/detail/iterators/iter_impl.hpp b/include/nlohmann/detail/iterators/iter_impl.hpp index adcd8a37..6674c064 100644 --- a/include/nlohmann/detail/iterators/iter_impl.hpp +++ b/include/nlohmann/detail/iterators/iter_impl.hpp @@ -610,5 +610,5 @@ class iter_impl /// the actual iterator of the associated instance internal_iterator::type> m_it; }; -} -} +} // namespace detail +} // namespace nlohmann diff --git a/include/nlohmann/detail/iterators/iteration_proxy.hpp b/include/nlohmann/detail/iterators/iteration_proxy.hpp index f5dbb2c7..d4f90502 100644 --- a/include/nlohmann/detail/iterators/iteration_proxy.hpp +++ b/include/nlohmann/detail/iterators/iteration_proxy.hpp @@ -39,9 +39,6 @@ template class iteration_proxy public: explicit iteration_proxy_internal(IteratorType it) noexcept : anchor(it) {} - iteration_proxy_internal(const iteration_proxy_internal&) = default; - iteration_proxy_internal& operator=(const iteration_proxy_internal&) = default; - /// dereference operator (needed for range-based for) iteration_proxy_internal& operator*() { @@ -124,5 +121,5 @@ template class iteration_proxy return iteration_proxy_internal(container.end()); } }; -} -} +} // namespace detail +} // namespace nlohmann diff --git a/include/nlohmann/detail/iterators/json_reverse_iterator.hpp b/include/nlohmann/detail/iterators/json_reverse_iterator.hpp index 2750de4a..f3b5b5db 100644 --- a/include/nlohmann/detail/iterators/json_reverse_iterator.hpp +++ b/include/nlohmann/detail/iterators/json_reverse_iterator.hpp @@ -115,5 +115,5 @@ class json_reverse_iterator : public std::reverse_iterator return it.operator * (); } }; -} -} +} // namespace detail +} // namespace nlohmann diff --git a/include/nlohmann/detail/iterators/primitive_iterator.hpp b/include/nlohmann/detail/iterators/primitive_iterator.hpp index db3f8975..28d6f1a6 100644 --- a/include/nlohmann/detail/iterators/primitive_iterator.hpp +++ b/include/nlohmann/detail/iterators/primitive_iterator.hpp @@ -116,5 +116,5 @@ class primitive_iterator_t return *this; } }; -} -} +} // namespace detail +} // namespace nlohmann diff --git a/include/nlohmann/detail/json_pointer.hpp b/include/nlohmann/detail/json_pointer.hpp index fce8001a..b2bc4727 100644 --- a/include/nlohmann/detail/json_pointer.hpp +++ b/include/nlohmann/detail/json_pointer.hpp @@ -506,11 +506,11 @@ class json_pointer std::size_t slash = reference_string.find_first_of('/', 1), // set the beginning of the first reference token start = 1; - // we can stop if start == string::npos+1 = 0 + // we can stop if start == 0 (if slash == std::string::npos) start != 0; // set the beginning of the next reference token // (will eventually be 0 if slash == std::string::npos) - start = slash + 1, + start = (slash == std::string::npos) ? 0 : slash + 1, // find next slash slash = reference_string.find_first_of('/', start)) { @@ -693,4 +693,4 @@ class json_pointer /// the reference tokens std::vector reference_tokens; }; -} +} // namespace nlohmann diff --git a/include/nlohmann/detail/json_ref.hpp b/include/nlohmann/detail/json_ref.hpp index 8285be22..c8dec733 100644 --- a/include/nlohmann/detail/json_ref.hpp +++ b/include/nlohmann/detail/json_ref.hpp @@ -3,6 +3,8 @@ #include #include +#include + namespace nlohmann { namespace detail @@ -25,15 +27,19 @@ class json_ref : owned_value(init), value_ref(&owned_value), is_rvalue(true) {} - template - json_ref(Args&& ... args) - : owned_value(std::forward(args)...), value_ref(&owned_value), is_rvalue(true) - {} + template < + class... Args, + enable_if_t::value, int> = 0 > + json_ref(Args && ... args) + : owned_value(std::forward(args)...), value_ref(&owned_value), + is_rvalue(true) {} // class should be movable only json_ref(json_ref&&) = default; json_ref(const json_ref&) = delete; json_ref& operator=(const json_ref&) = delete; + json_ref& operator=(json_ref&&) = delete; + ~json_ref() = default; value_type moved_or_copied() const { @@ -59,5 +65,5 @@ class json_ref value_type* value_ref = nullptr; const bool is_rvalue; }; -} -} +} // namespace detail +} // namespace nlohmann diff --git a/include/nlohmann/detail/macro_scope.hpp b/include/nlohmann/detail/macro_scope.hpp index 80fbece7..06805b1a 100644 --- a/include/nlohmann/detail/macro_scope.hpp +++ b/include/nlohmann/detail/macro_scope.hpp @@ -10,7 +10,7 @@ #error "unsupported Clang version - see https://github.com/nlohmann/json#supported-compilers" #endif #elif defined(__GNUC__) && !(defined(__ICC) || defined(__INTEL_COMPILER)) - #if (__GNUC__ * 10000 + __GNUC_MINOR__ * 100 + __GNUC_PATCHLEVEL__) < 40900 + #if (__GNUC__ * 10000 + __GNUC_MINOR__ * 100 + __GNUC_PATCHLEVEL__) < 40800 #error "unsupported GCC version - see https://github.com/nlohmann/json#supported-compilers" #endif #endif diff --git a/include/nlohmann/detail/meta/cpp_future.hpp b/include/nlohmann/detail/meta/cpp_future.hpp index fa7478b8..948cd4fb 100644 --- a/include/nlohmann/detail/meta/cpp_future.hpp +++ b/include/nlohmann/detail/meta/cpp_future.hpp @@ -59,5 +59,5 @@ struct static_const template constexpr T static_const::value; -} -} +} // namespace detail +} // namespace nlohmann diff --git a/include/nlohmann/detail/meta/detected.hpp b/include/nlohmann/detail/meta/detected.hpp index ed1d6ac7..c1bd5476 100644 --- a/include/nlohmann/detail/meta/detected.hpp +++ b/include/nlohmann/detail/meta/detected.hpp @@ -52,5 +52,5 @@ using is_detected_exact = std::is_same>; template class Op, class... Args> using is_detected_convertible = std::is_convertible, To>; -} -} +} // namespace detail +} // namespace nlohmann diff --git a/include/nlohmann/detail/meta/is_sax.hpp b/include/nlohmann/detail/meta/is_sax.hpp index b4e1f3fd..b610beab 100644 --- a/include/nlohmann/detail/meta/is_sax.hpp +++ b/include/nlohmann/detail/meta/is_sax.hpp @@ -137,5 +137,5 @@ public: "Missing/invalid function: bool parse_error(std::size_t, const " "std::string&, const exception&)"); }; -} -} +} // namespace detail +} // namespace nlohmann diff --git a/include/nlohmann/detail/meta/type_traits.hpp b/include/nlohmann/detail/meta/type_traits.hpp index b358de65..1a1a1744 100644 --- a/include/nlohmann/detail/meta/type_traits.hpp +++ b/include/nlohmann/detail/meta/type_traits.hpp @@ -65,6 +65,9 @@ using to_json_function = decltype(T::to_json(std::declval()...)); template using from_json_function = decltype(T::from_json(std::declval()...)); +template +using get_template_function = decltype(std::declval().template get()); + /////////////////// // is_ functions // /////////////////// @@ -185,8 +188,12 @@ struct is_compatible_integer_type CompatibleNumberIntegerType> {}; // trait checking if JSONSerializer::from_json(json const&, udt&) exists -template -struct has_from_json +template +struct has_from_json : std::false_type {}; + +template +struct has_from_json::value>> { using serializer = typename BasicJsonType::template json_serializer; @@ -197,8 +204,11 @@ struct has_from_json // This trait checks if JSONSerializer::from_json(json const&) exists // this overload is used for non-default-constructible user-defined-types +template +struct has_non_default_from_json : std::false_type {}; + template -struct has_non_default_from_json +struct has_non_default_from_json::value>> { using serializer = typename BasicJsonType::template json_serializer; @@ -208,8 +218,12 @@ struct has_non_default_from_json }; // This trait checks if BasicJsonType::json_serializer::to_json exists -template -struct has_to_json +// Do not evaluate the trait when T is a basic_json type, to avoid template instantiation infinite recursion. +template +struct has_to_json : std::false_type {}; + +template +struct has_to_json::value>> { using serializer = typename BasicJsonType::template json_serializer; @@ -233,5 +247,5 @@ struct is_compatible_type_impl < template struct is_compatible_type : is_compatible_type_impl {}; -} -} +} // namespace detail +} // namespace nlohmann diff --git a/include/nlohmann/detail/meta/void_t.hpp b/include/nlohmann/detail/meta/void_t.hpp index 2528ea84..a256f85a 100644 --- a/include/nlohmann/detail/meta/void_t.hpp +++ b/include/nlohmann/detail/meta/void_t.hpp @@ -9,5 +9,5 @@ template struct make_void using type = void; }; template using void_t = typename make_void::type; -} -} +} // namespace detail +} // namespace nlohmann diff --git a/include/nlohmann/detail/output/binary_writer.hpp b/include/nlohmann/detail/output/binary_writer.hpp index 24c08001..631acce2 100644 --- a/include/nlohmann/detail/output/binary_writer.hpp +++ b/include/nlohmann/detail/output/binary_writer.hpp @@ -540,9 +540,11 @@ class binary_writer case value_t::boolean: { if (add_prefix) + { oa->write_character(j.m_value.boolean ? static_cast('T') : static_cast('F')); + } break; } @@ -1075,7 +1077,7 @@ class binary_writer } else { - JSON_THROW(out_of_range::create(407, "number overflow serializing " + std::to_string(n))); + JSON_THROW(out_of_range::create(407, "integer number " + std::to_string(n) + " cannot be represented by UBJSON as it does not fit int64")); } } @@ -1129,7 +1131,7 @@ class binary_writer // LCOV_EXCL_START else { - JSON_THROW(out_of_range::create(407, "number overflow serializing " + std::to_string(n))); + JSON_THROW(out_of_range::create(407, "integer number " + std::to_string(n) + " cannot be represented by UBJSON as it does not fit int64")); } // LCOV_EXCL_STOP } @@ -1159,22 +1161,20 @@ class binary_writer { return 'i'; } - else if ((std::numeric_limits::min)() <= j.m_value.number_integer and j.m_value.number_integer <= (std::numeric_limits::max)()) + if ((std::numeric_limits::min)() <= j.m_value.number_integer and j.m_value.number_integer <= (std::numeric_limits::max)()) { return 'U'; } - else if ((std::numeric_limits::min)() <= j.m_value.number_integer and j.m_value.number_integer <= (std::numeric_limits::max)()) + if ((std::numeric_limits::min)() <= j.m_value.number_integer and j.m_value.number_integer <= (std::numeric_limits::max)()) { return 'I'; } - else if ((std::numeric_limits::min)() <= j.m_value.number_integer and j.m_value.number_integer <= (std::numeric_limits::max)()) + if ((std::numeric_limits::min)() <= j.m_value.number_integer and j.m_value.number_integer <= (std::numeric_limits::max)()) { return 'l'; } - else // no check and assume int64_t (see note above) - { - return 'L'; - } + // no check and assume int64_t (see note above) + return 'L'; } case value_t::number_unsigned: @@ -1183,22 +1183,20 @@ class binary_writer { return 'i'; } - else if (j.m_value.number_unsigned <= (std::numeric_limits::max)()) + if (j.m_value.number_unsigned <= (std::numeric_limits::max)()) { return 'U'; } - else if (j.m_value.number_unsigned <= (std::numeric_limits::max)()) + if (j.m_value.number_unsigned <= (std::numeric_limits::max)()) { return 'I'; } - else if (j.m_value.number_unsigned <= (std::numeric_limits::max)()) + if (j.m_value.number_unsigned <= (std::numeric_limits::max)()) { return 'l'; } - else // no check and assume int64_t (see note above) - { - return 'L'; - } + // no check and assume int64_t (see note above) + return 'L'; } case value_t::number_float: @@ -1218,32 +1216,32 @@ class binary_writer } } - static constexpr CharType get_cbor_float_prefix(float) + static constexpr CharType get_cbor_float_prefix(float /*unused*/) { return static_cast(0xFA); // Single-Precision Float } - static constexpr CharType get_cbor_float_prefix(double) + static constexpr CharType get_cbor_float_prefix(double /*unused*/) { return static_cast(0xFB); // Double-Precision Float } - static constexpr CharType get_msgpack_float_prefix(float) + static constexpr CharType get_msgpack_float_prefix(float /*unused*/) { return static_cast(0xCA); // float 32 } - static constexpr CharType get_msgpack_float_prefix(double) + static constexpr CharType get_msgpack_float_prefix(double /*unused*/) { return static_cast(0xCB); // float 64 } - static constexpr CharType get_ubjson_float_prefix(float) + static constexpr CharType get_ubjson_float_prefix(float /*unused*/) { return 'd'; // float 32 } - static constexpr CharType get_ubjson_float_prefix(double) + static constexpr CharType get_ubjson_float_prefix(double /*unused*/) { return 'D'; // float 64 } @@ -1255,5 +1253,5 @@ class binary_writer /// the output output_adapter_t oa = nullptr; }; -} -} +} // namespace detail +} // namespace nlohmann diff --git a/include/nlohmann/detail/output/output_adapters.hpp b/include/nlohmann/detail/output/output_adapters.hpp index ff86a6e1..0a37715c 100644 --- a/include/nlohmann/detail/output/output_adapters.hpp +++ b/include/nlohmann/detail/output/output_adapters.hpp @@ -109,5 +109,5 @@ class output_adapter private: output_adapter_t oa = nullptr; }; -} -} +} // namespace detail +} // namespace nlohmann diff --git a/include/nlohmann/detail/output/serializer.hpp b/include/nlohmann/detail/output/serializer.hpp index de3676ac..bb74a86e 100644 --- a/include/nlohmann/detail/output/serializer.hpp +++ b/include/nlohmann/detail/output/serializer.hpp @@ -53,6 +53,9 @@ class serializer // delete because of pointer members serializer(const serializer&) = delete; serializer& operator=(const serializer&) = delete; + serializer(serializer&&) = delete; + serializer& operator=(serializer&&) = delete; + ~serializer() = default; /*! @brief internal implementation of the serialization function @@ -442,7 +445,7 @@ class serializer return; } - const bool is_negative = (x <= 0) and (x != 0); // see issue #755 + const bool is_negative = std::is_same::value and not (x >= 0); // see issue #755 std::size_t i = 0; while (x != 0) @@ -627,5 +630,5 @@ class serializer /// the indentation string string_t indent_string; }; -} -} +} // namespace detail +} // namespace nlohmann diff --git a/include/nlohmann/detail/value_t.hpp b/include/nlohmann/detail/value_t.hpp index 326367c4..10d555b9 100644 --- a/include/nlohmann/detail/value_t.hpp +++ b/include/nlohmann/detail/value_t.hpp @@ -72,5 +72,5 @@ inline bool operator<(const value_t lhs, const value_t rhs) noexcept const auto r_index = static_cast(rhs); return l_index < order.size() and r_index < order.size() and order[l_index] < order[r_index]; } -} -} +} // namespace detail +} // namespace nlohmann diff --git a/include/nlohmann/json.hpp b/include/nlohmann/json.hpp index 64b32a7f..57d33162 100644 --- a/include/nlohmann/json.hpp +++ b/include/nlohmann/json.hpp @@ -1,7 +1,7 @@ /* __ _____ _____ _____ __| | __| | | | JSON for Modern C++ -| | |__ | | | | | | version 3.2.0 +| | |__ | | | | | | version 3.3.0 |_____|_____|_____|_|___| https://github.com/nlohmann/json Licensed under the MIT License . @@ -31,7 +31,7 @@ SOFTWARE. #define NLOHMANN_JSON_HPP #define NLOHMANN_JSON_VERSION_MAJOR 3 -#define NLOHMANN_JSON_VERSION_MINOR 2 +#define NLOHMANN_JSON_VERSION_MINOR 3 #define NLOHMANN_JSON_VERSION_PATCH 0 #include // all_of, find, for_each @@ -947,7 +947,7 @@ class basic_json object = nullptr; // silence warning, see #821 if (JSON_UNLIKELY(t == value_t::null)) { - JSON_THROW(other_error::create(500, "961c151d2e87f2686a955a9be24d316f1362bf21 3.2.0")); // LCOV_EXCL_LINE + JSON_THROW(other_error::create(500, "961c151d2e87f2686a955a9be24d316f1362bf21 3.3.0")); // LCOV_EXCL_LINE } break; } @@ -1866,7 +1866,7 @@ class basic_json @since version 1.0.0 */ - reference& operator=(basic_json other) noexcept ( + basic_json& operator=(basic_json other) noexcept ( std::is_nothrow_move_constructible::value and std::is_nothrow_move_assignable::value and std::is_nothrow_move_constructible::value and @@ -2624,51 +2624,50 @@ class basic_json } /*! - @brief get a pointer value (explicit) + @brief get a value (explicit) - Explicit pointer access to the internally stored JSON value. No copies are - made. + Explicit type conversion between the JSON value and a compatible value. + The value is filled into the input parameter by calling the @ref json_serializer + `from_json()` method. - @warning The pointer becomes invalid if the underlying JSON object - changes. + The function is equivalent to executing + @code {.cpp} + ValueType v; + JSONSerializer::from_json(*this, v); + @endcode - @tparam PointerType pointer type; must be a pointer to @ref array_t, @ref - object_t, @ref string_t, @ref boolean_t, @ref number_integer_t, - @ref number_unsigned_t, or @ref number_float_t. + This overloads is chosen if: + - @a ValueType is not @ref basic_json, + - @ref json_serializer has a `from_json()` method of the form + `void from_json(const basic_json&, ValueType&)`, and - @return pointer to the internally stored JSON value if the requested - pointer type @a PointerType fits to the JSON value; `nullptr` otherwise + @tparam ValueType the input parameter type. - @complexity Constant. + @return the input parameter, allowing chaining calls. - @liveexample{The example below shows how pointers to internal values of a - JSON value can be requested. Note that no type conversions are made and a - `nullptr` is returned if the value and the requested pointer type does not - match.,get__PointerType} + @throw what @ref json_serializer `from_json()` method throws - @sa @ref get_ptr() for explicit pointer-member access + @liveexample{The example below shows several conversions from JSON values + to other types. There a few things to note: (1) Floating-point numbers can + be converted to integers\, (2) A JSON array can be converted to a standard + `std::vector`\, (3) A JSON object can be converted to C++ + associative containers such as `std::unordered_map`.,get_to} - @since version 1.0.0 + @since version 3.3.0 */ - template::value, int>::type = 0> - PointerType get() noexcept + template::value and + detail::has_from_json::value, + int> = 0> + ValueType & get_to(ValueType& v) const noexcept(noexcept( + JSONSerializer::from_json(std::declval(), v))) { - // delegate the call to get_ptr - return get_ptr(); + JSONSerializer::from_json(*this, v); + return v; } - /*! - @brief get a pointer value (explicit) - @copydoc get() - */ - template::value, int>::type = 0> - constexpr const PointerType get() const noexcept - { - // delegate the call to get_ptr - return get_ptr(); - } /*! @brief get a pointer value (implicit) @@ -2698,23 +2697,8 @@ class basic_json */ template::value, int>::type = 0> - PointerType get_ptr() noexcept + auto get_ptr() noexcept -> decltype(std::declval().get_impl_ptr(std::declval())) { - // get the type of the PointerType (remove pointer and const) - using pointee_t = typename std::remove_const::type>::type>::type; - // make sure the type matches the allowed types - static_assert( - std::is_same::value - or std::is_same::value - or std::is_same::value - or std::is_same::value - or std::is_same::value - or std::is_same::value - or std::is_same::value - , "incompatible pointer type"); - // delegate the call to get_impl_ptr<>() return get_impl_ptr(static_cast(nullptr)); } @@ -2726,27 +2710,59 @@ class basic_json template::value and std::is_const::type>::value, int>::type = 0> - constexpr const PointerType get_ptr() const noexcept + constexpr auto get_ptr() const noexcept -> decltype(std::declval().get_impl_ptr(std::declval())) { - // get the type of the PointerType (remove pointer and const) - using pointee_t = typename std::remove_const::type>::type>::type; - // make sure the type matches the allowed types - static_assert( - std::is_same::value - or std::is_same::value - or std::is_same::value - or std::is_same::value - or std::is_same::value - or std::is_same::value - or std::is_same::value - , "incompatible pointer type"); - // delegate the call to get_impl_ptr<>() const return get_impl_ptr(static_cast(nullptr)); } + /*! + @brief get a pointer value (explicit) + + Explicit pointer access to the internally stored JSON value. No copies are + made. + + @warning The pointer becomes invalid if the underlying JSON object + changes. + + @tparam PointerType pointer type; must be a pointer to @ref array_t, @ref + object_t, @ref string_t, @ref boolean_t, @ref number_integer_t, + @ref number_unsigned_t, or @ref number_float_t. + + @return pointer to the internally stored JSON value if the requested + pointer type @a PointerType fits to the JSON value; `nullptr` otherwise + + @complexity Constant. + + @liveexample{The example below shows how pointers to internal values of a + JSON value can be requested. Note that no type conversions are made and a + `nullptr` is returned if the value and the requested pointer type does not + match.,get__PointerType} + + @sa @ref get_ptr() for explicit pointer-member access + + @since version 1.0.0 + */ + template::value, int>::type = 0> + auto get() noexcept -> decltype(std::declval().template get_ptr()) + { + // delegate the call to get_ptr + return get_ptr(); + } + + /*! + @brief get a pointer value (explicit) + @copydoc get() + */ + template::value, int>::type = 0> + constexpr auto get() const noexcept -> decltype(std::declval().template get_ptr()) + { + // delegate the call to get_ptr + return get_ptr(); + } + /*! @brief get a reference value (implicit) @@ -2828,12 +2844,14 @@ class basic_json not std::is_same>::value and not std::is_same::value and not detail::is_basic_json::value + #ifndef _MSC_VER // fix for issue #167 operator<< ambiguity under VS2015 and not std::is_same>::value #if defined(JSON_HAS_CPP_17) && defined(_MSC_VER) and _MSC_VER <= 1914 and not std::is_same::value #endif #endif + and detail::is_detected::value , int >::type = 0 > operator ValueType() const { @@ -3097,7 +3115,7 @@ class basic_json return m_value.array->operator[](idx); } - JSON_THROW(type_error::create(305, "cannot use operator[] with " + std::string(type_name()))); + JSON_THROW(type_error::create(305, "cannot use operator[] with a numeric argument with " + std::string(type_name()))); } /*! @@ -3127,7 +3145,7 @@ class basic_json return m_value.array->operator[](idx); } - JSON_THROW(type_error::create(305, "cannot use operator[] with " + std::string(type_name()))); + JSON_THROW(type_error::create(305, "cannot use operator[] with a numeric argument with " + std::string(type_name()))); } /*! @@ -3173,7 +3191,7 @@ class basic_json return m_value.object->operator[](key); } - JSON_THROW(type_error::create(305, "cannot use operator[] with " + std::string(type_name()))); + JSON_THROW(type_error::create(305, "cannot use operator[] with a string argument with " + std::string(type_name()))); } /*! @@ -3215,7 +3233,7 @@ class basic_json return m_value.object->find(key)->second; } - JSON_THROW(type_error::create(305, "cannot use operator[] with " + std::string(type_name()))); + JSON_THROW(type_error::create(305, "cannot use operator[] with a string argument with " + std::string(type_name()))); } /*! @@ -3262,7 +3280,7 @@ class basic_json return m_value.object->operator[](key); } - JSON_THROW(type_error::create(305, "cannot use operator[] with " + std::string(type_name()))); + JSON_THROW(type_error::create(305, "cannot use operator[] with a string argument with " + std::string(type_name()))); } /*! @@ -3305,7 +3323,7 @@ class basic_json return m_value.object->find(key)->second; } - JSON_THROW(type_error::create(305, "cannot use operator[] with " + std::string(type_name()))); + JSON_THROW(type_error::create(305, "cannot use operator[] with a string argument with " + std::string(type_name()))); } /*! @@ -4943,6 +4961,26 @@ class basic_json return {it, res.second}; } + /// Helper for insertion of an iterator + /// @note: This uses std::distance to support GCC 4.8, + /// see https://github.com/nlohmann/json/pull/1257 + template + iterator insert_iterator(const_iterator pos, Args&& ... args) + { + iterator result(this); + assert(m_value.array != nullptr); + + auto insert_pos = std::distance(m_value.array->begin(), pos.m_it.array_iterator); + m_value.array->insert(pos.m_it.array_iterator, std::forward(args)...); + result.m_it.array_iterator = m_value.array->begin() + insert_pos; + + // This could have been written as: + // result.m_it.array_iterator = m_value.array->insert(pos.m_it.array_iterator, cnt, val); + // but the return value of insert is missing in GCC 4.8, so it is written this way instead. + + return result; + } + /*! @brief inserts element @@ -4977,9 +5015,7 @@ class basic_json } // insert to array and return iterator - iterator result(this); - result.m_it.array_iterator = m_value.array->insert(pos.m_it.array_iterator, val); - return result; + return insert_iterator(pos, val); } JSON_THROW(type_error::create(309, "cannot use insert() with " + std::string(type_name()))); @@ -5030,9 +5066,7 @@ class basic_json } // insert to array and return iterator - iterator result(this); - result.m_it.array_iterator = m_value.array->insert(pos.m_it.array_iterator, cnt, val); - return result; + return insert_iterator(pos, cnt, val); } JSON_THROW(type_error::create(309, "cannot use insert() with " + std::string(type_name()))); @@ -5094,12 +5128,7 @@ class basic_json } // insert to array and return iterator - iterator result(this); - result.m_it.array_iterator = m_value.array->insert( - pos.m_it.array_iterator, - first.m_it.array_iterator, - last.m_it.array_iterator); - return result; + return insert_iterator(pos, first.m_it.array_iterator, last.m_it.array_iterator); } /*! @@ -5141,9 +5170,7 @@ class basic_json } // insert to array and return iterator - iterator result(this); - result.m_it.array_iterator = m_value.array->insert(pos.m_it.array_iterator, ilist.begin(), ilist.end()); - return result; + return insert_iterator(pos, ilist.begin(), ilist.end()); } /*! @@ -5972,6 +5999,8 @@ class basic_json @param[in] cb a parser callback function of type @ref parser_callback_t which is used to control the deserialization by filtering unwanted values (optional) + @param[in] allow_exceptions whether to throw exceptions in case of a + parse error (optional, true by default) @return result of the deserialization @@ -6367,7 +6396,7 @@ class basic_json vector in CBOR format.,to_cbor} @sa http://cbor.io - @sa @ref from_cbor(detail::input_adapter, const bool strict) for the + @sa @ref from_cbor(detail::input_adapter&&, const bool, const bool) for the analogous deserialization @sa @ref to_msgpack(const basic_json&) for the related MessagePack format @sa @ref to_ubjson(const basic_json&, const bool, const bool) for the @@ -6464,8 +6493,7 @@ class basic_json vector in MessagePack format.,to_msgpack} @sa http://msgpack.org - @sa @ref from_msgpack(const std::vector&, const size_t) for the - analogous deserialization + @sa @ref from_msgpack for the analogous deserialization @sa @ref to_cbor(const basic_json& for the related CBOR format @sa @ref to_ubjson(const basic_json&, const bool, const bool) for the related UBJSON format @@ -6562,7 +6590,7 @@ class basic_json vector in UBJSON format.,to_ubjson} @sa http://ubjson.org - @sa @ref from_ubjson(detail::input_adapter, const bool strict) for the + @sa @ref from_ubjson(detail::input_adapter&&, const bool, const bool) for the analogous deserialization @sa @ref to_cbor(const basic_json& for the related CBOR format @sa @ref to_msgpack(const basic_json&) for the related MessagePack format @@ -6758,14 +6786,14 @@ class basic_json @sa http://cbor.io @sa @ref to_cbor(const basic_json&) for the analogous serialization - @sa @ref from_msgpack(detail::input_adapter, const bool, const bool) for the + @sa @ref from_msgpack(detail::input_adapter&&, const bool, const bool) for the related MessagePack format - @sa @ref from_ubjson(detail::input_adapter, const bool, const bool) for the + @sa @ref from_ubjson(detail::input_adapter&&, const bool, const bool) for the related UBJSON format @since version 2.0.9; parameter @a start_index since 2.1.1; changed to consume input adapters, removed start_index parameter, and added - @a strict parameter since 3.0.0; added @allow_exceptions parameter + @a strict parameter since 3.0.0; added @a allow_exceptions parameter since 3.2.0 */ static basic_json from_cbor(detail::input_adapter&& i, @@ -6779,7 +6807,7 @@ class basic_json } /*! - @copydoc from_cbor(detail::input_adapter, const bool, const bool) + @copydoc from_cbor(detail::input_adapter&&, const bool, const bool) */ template::value, int> = 0> @@ -6861,16 +6889,16 @@ class basic_json @sa http://msgpack.org @sa @ref to_msgpack(const basic_json&) for the analogous serialization - @sa @ref from_cbor(detail::input_adapter, const bool, const bool) for the + @sa @ref from_cbor(detail::input_adapter&&, const bool, const bool) for the related CBOR format - @sa @ref from_ubjson(detail::input_adapter, const bool, const bool) for + @sa @ref from_ubjson(detail::input_adapter&&, const bool, const bool) for the related UBJSON format @sa @ref from_bson(detail::input_adapter, const bool, const bool) for the related BSON format @since version 2.0.9; parameter @a start_index since 2.1.1; changed to consume input adapters, removed start_index parameter, and added - @a strict parameter since 3.0.0; added @allow_exceptions parameter + @a strict parameter since 3.0.0; added @a allow_exceptions parameter since 3.2.0 */ static basic_json from_msgpack(detail::input_adapter&& i, @@ -6884,7 +6912,7 @@ class basic_json } /*! - @copydoc from_msgpack(detail::input_adapter, const bool, const bool) + @copydoc from_msgpack(detail::input_adapter&&, const bool, const bool) */ template::value, int> = 0> @@ -6948,14 +6976,14 @@ class basic_json @sa http://ubjson.org @sa @ref to_ubjson(const basic_json&, const bool, const bool) for the analogous serialization - @sa @ref from_cbor(detail::input_adapter, const bool, const bool) for the + @sa @ref from_cbor(detail::input_adapter&&, const bool, const bool) for the related CBOR format - @sa @ref from_msgpack(detail::input_adapter, const bool, const bool) for + @sa @ref from_msgpack(detail::input_adapter&&, const bool, const bool) for the related MessagePack format @sa @ref from_bson(detail::input_adapter, const bool, const bool) for the related BSON format - @since version 3.1.0; added @allow_exceptions parameter since 3.2.0 + @since version 3.1.0; added @a allow_exceptions parameter since 3.2.0 */ static basic_json from_ubjson(detail::input_adapter&& i, const bool strict = true, @@ -6968,7 +6996,7 @@ class basic_json } /*! - @copydoc from_ubjson(detail::input_adapter, const bool, const bool) + @copydoc from_ubjson(detail::input_adapter&&, const bool, const bool) */ template::value, int> = 0> @@ -7432,11 +7460,9 @@ class basic_json // avoid undefined behavior JSON_THROW(out_of_range::create(401, "array index " + std::to_string(idx) + " is out of range")); } - else - { - // default case: insert add offset - parent.insert(parent.begin() + static_cast(idx), val); - } + + // default case: insert add offset + parent.insert(parent.begin() + static_cast(idx), val); } break; } @@ -7861,19 +7887,6 @@ class basic_json // specialization of std::swap, and std::hash namespace std { -/*! -@brief exchanges the values of two JSON objects - -@since version 1.0.0 -*/ -template<> -inline void swap(nlohmann::json& j1, nlohmann::json& j2) noexcept( - is_nothrow_move_constructible::value and - is_nothrow_move_assignable::value -) -{ - j1.swap(j2); -} /// hash value for JSON objects template<> @@ -7909,6 +7922,20 @@ struct less< ::nlohmann::detail::value_t> } }; +/*! +@brief exchanges the values of two JSON objects + +@since version 1.0.0 +*/ +template<> +inline void swap(nlohmann::json& j1, nlohmann::json& j2) noexcept( + is_nothrow_move_constructible::value and + is_nothrow_move_assignable::value +) +{ + j1.swap(j2); +} + } // namespace std /*! diff --git a/include/nlohmann/json_fwd.hpp b/include/nlohmann/json_fwd.hpp index 5ff0d753..32abba91 100644 --- a/include/nlohmann/json_fwd.hpp +++ b/include/nlohmann/json_fwd.hpp @@ -59,6 +59,6 @@ uses the standard template types. @since version 1.0.0 */ using json = basic_json<>; -} +} // namespace nlohmann #endif diff --git a/meson.build b/meson.build index c79dcd3e..6935567b 100644 --- a/meson.build +++ b/meson.build @@ -1,9 +1,13 @@ -project('nlohmann_json', 'cpp') +project('nlohmann_json', + 'cpp', + version : '3.3.0', + license : 'MIT', +) nlohmann_json_dep = declare_dependency( - include_directories: include_directories('single_include') + include_directories: include_directories('single_include') ) nlohmann_json_multiple_headers = declare_dependency( - include_directories: include_directories('include') + include_directories: include_directories('include') ) diff --git a/single_include/nlohmann/json.hpp b/single_include/nlohmann/json.hpp index b5aaecf8..94a0be69 100644 --- a/single_include/nlohmann/json.hpp +++ b/single_include/nlohmann/json.hpp @@ -1,7 +1,7 @@ /* __ _____ _____ _____ __| | __| | | | JSON for Modern C++ -| | |__ | | | | | | version 3.2.0 +| | |__ | | | | | | version 3.3.0 |_____|_____|_____|_|___| https://github.com/nlohmann/json Licensed under the MIT License . @@ -31,7 +31,7 @@ SOFTWARE. #define NLOHMANN_JSON_HPP #define NLOHMANN_JSON_VERSION_MAJOR 3 -#define NLOHMANN_JSON_VERSION_MINOR 2 +#define NLOHMANN_JSON_VERSION_MINOR 3 #define NLOHMANN_JSON_VERSION_PATCH 0 #include // all_of, find, for_each @@ -108,7 +108,7 @@ uses the standard template types. @since version 1.0.0 */ using json = basic_json<>; -} +} // namespace nlohmann #endif @@ -125,7 +125,7 @@ using json = basic_json<>; #error "unsupported Clang version - see https://github.com/nlohmann/json#supported-compilers" #endif #elif defined(__GNUC__) && !(defined(__ICC) || defined(__INTEL_COMPILER)) - #if (__GNUC__ * 10000 + __GNUC_MINOR__ * 100 + __GNUC_PATCHLEVEL__) < 40900 + #if (__GNUC__ * 10000 + __GNUC_MINOR__ * 100 + __GNUC_PATCHLEVEL__) < 40800 #error "unsupported GCC version - see https://github.com/nlohmann/json#supported-compilers" #endif #endif @@ -280,8 +280,8 @@ struct static_const template constexpr T static_const::value; -} -} +} // namespace detail +} // namespace nlohmann // #include @@ -312,8 +312,8 @@ template struct make_void using type = void; }; template using void_t = typename make_void::type; -} -} +} // namespace detail +} // namespace nlohmann // http://en.cppreference.com/w/cpp/experimental/is_detected @@ -364,8 +364,8 @@ using is_detected_exact = std::is_same>; template class Op, class... Args> using is_detected_convertible = std::is_convertible, To>; -} -} +} // namespace detail +} // namespace nlohmann // #include @@ -425,6 +425,9 @@ using to_json_function = decltype(T::to_json(std::declval()...)); template using from_json_function = decltype(T::from_json(std::declval()...)); +template +using get_template_function = decltype(std::declval().template get()); + /////////////////// // is_ functions // /////////////////// @@ -545,8 +548,12 @@ struct is_compatible_integer_type CompatibleNumberIntegerType> {}; // trait checking if JSONSerializer::from_json(json const&, udt&) exists -template -struct has_from_json +template +struct has_from_json : std::false_type {}; + +template +struct has_from_json::value>> { using serializer = typename BasicJsonType::template json_serializer; @@ -557,8 +564,11 @@ struct has_from_json // This trait checks if JSONSerializer::from_json(json const&) exists // this overload is used for non-default-constructible user-defined-types +template +struct has_non_default_from_json : std::false_type {}; + template -struct has_non_default_from_json +struct has_non_default_from_json::value>> { using serializer = typename BasicJsonType::template json_serializer; @@ -568,8 +578,12 @@ struct has_non_default_from_json }; // This trait checks if BasicJsonType::json_serializer::to_json exists -template -struct has_to_json +// Do not evaluate the trait when T is a basic_json type, to avoid template instantiation infinite recursion. +template +struct has_to_json : std::false_type {}; + +template +struct has_to_json::value>> { using serializer = typename BasicJsonType::template json_serializer; @@ -593,8 +607,8 @@ struct is_compatible_type_impl < template struct is_compatible_type : is_compatible_type_impl {}; -} -} +} // namespace detail +} // namespace nlohmann // #include @@ -603,6 +617,36 @@ struct is_compatible_type #include // runtime_error #include // to_string +// #include + + +#include // size_t + +namespace nlohmann +{ +namespace detail +{ +/// struct to capture the start position of the current token +struct position_t +{ + /// the total number of characters read + std::size_t chars_read_total = 0; + /// the number of characters read in the current line + std::size_t chars_read_current_line = 0; + /// the number of lines read + std::size_t lines_read = 0; + + /// conversion to size_t to preserve SAX interface + constexpr operator size_t() const + { + return chars_read_total; + } +}; + +} +} + + namespace nlohmann { namespace detail @@ -714,15 +758,23 @@ class parse_error : public exception /*! @brief create a parse error exception @param[in] id_ the id of the exception - @param[in] byte_ the byte index where the error occurred (or 0 if the - position cannot be determined) + @param[in] position the position where the error occurred (or with + chars_read_total=0 if the position cannot be + determined) @param[in] what_arg the explanatory string @return parse_error object */ + static parse_error create(int id_, const position_t& pos, const std::string& what_arg) + { + std::string w = exception::name("parse_error", id_) + "parse error" + + position_string(pos) + ": " + what_arg; + return parse_error(id_, pos.chars_read_total, w.c_str()); + } + static parse_error create(int id_, std::size_t byte_, const std::string& what_arg) { std::string w = exception::name("parse_error", id_) + "parse error" + - (byte_ != 0 ? (" at " + std::to_string(byte_)) : "") + + (byte_ != 0 ? (" at byte " + std::to_string(byte_)) : "") + ": " + what_arg; return parse_error(id_, byte_, w.c_str()); } @@ -741,6 +793,12 @@ class parse_error : public exception private: parse_error(int id_, std::size_t byte_, const char* what_arg) : exception(id_, what_arg), byte(byte_) {} + + static std::string position_string(const position_t& pos) + { + return " at line " + std::to_string(pos.lines_read + 1) + + ", column " + std::to_string(pos.chars_read_current_line); + } }; /*! @@ -928,8 +986,8 @@ class other_error : public exception private: other_error(int id_, const char* what_arg) : exception(id_, what_arg) {} }; -} -} +} // namespace detail +} // namespace nlohmann // #include @@ -1006,8 +1064,8 @@ inline bool operator<(const value_t lhs, const value_t rhs) noexcept const auto r_index = static_cast(rhs); return l_index < order.size() and r_index < order.size() and order[l_index] < order[r_index]; } -} -} +} // namespace detail +} // namespace nlohmann // #include @@ -1316,7 +1374,7 @@ void from_json(const BasicJsonType& j, std::pair& p) } template -void from_json_tuple_impl(const BasicJsonType& j, Tuple& t, index_sequence) +void from_json_tuple_impl(const BasicJsonType& j, Tuple& t, index_sequence /*unused*/) { t = std::make_tuple(j.at(Idx).template get::type>()...); } @@ -1375,7 +1433,7 @@ struct from_json_fn return from_json(j, val); } }; -} +} // namespace detail /// namespace to hold default `from_json` function /// to see why this is required: @@ -1383,8 +1441,8 @@ struct from_json_fn namespace { constexpr const auto& from_json = detail::static_const::value; -} -} +} // namespace +} // namespace nlohmann // #include @@ -1446,9 +1504,6 @@ template class iteration_proxy public: explicit iteration_proxy_internal(IteratorType it) noexcept : anchor(it) {} - iteration_proxy_internal(const iteration_proxy_internal&) = default; - iteration_proxy_internal& operator=(const iteration_proxy_internal&) = default; - /// dereference operator (needed for range-based for) iteration_proxy_internal& operator*() { @@ -1531,8 +1586,8 @@ template class iteration_proxy return iteration_proxy_internal(container.end()); } }; -} -} +} // namespace detail +} // namespace nlohmann namespace nlohmann @@ -1828,13 +1883,13 @@ void to_json(BasicJsonType& j, const std::pair& p) // for https://github.com/nlohmann/json/pull/1134 template::iteration_proxy_internal>::value, int> = 0> -void to_json(BasicJsonType& j, T b) noexcept +void to_json(BasicJsonType& j, const T& b) { j = {{b.key(), b.value()}}; } template -void to_json_tuple_impl(BasicJsonType& j, const Tuple& t, index_sequence) +void to_json_tuple_impl(BasicJsonType& j, const Tuple& t, index_sequence /*unused*/) { j = {std::get(t)...}; } @@ -1854,14 +1909,14 @@ struct to_json_fn return to_json(j, std::forward(val)); } }; -} +} // namespace detail /// namespace to hold default `to_json` function namespace { constexpr const auto& to_json = detail::static_const::value; -} -} +} // namespace +} // namespace nlohmann // #include @@ -1938,6 +1993,8 @@ class input_stream_adapter : public input_adapter_protocol // delete because of pointer members input_stream_adapter(const input_stream_adapter&) = delete; input_stream_adapter& operator=(input_stream_adapter&) = delete; + input_stream_adapter(input_stream_adapter&&) = delete; + input_stream_adapter& operator=(input_stream_adapter&&) = delete; // std::istream/std::streambuf use std::char_traits::to_int_type, to // ensure that std::char_traits::eof() and the character 0xFF do not @@ -1964,6 +2021,9 @@ class input_buffer_adapter : public input_adapter_protocol // delete because of pointer members input_buffer_adapter(const input_buffer_adapter&) = delete; input_buffer_adapter& operator=(input_buffer_adapter&) = delete; + input_buffer_adapter(input_buffer_adapter&&) = delete; + input_buffer_adapter& operator=(input_buffer_adapter&&) = delete; + ~input_buffer_adapter() override = default; std::char_traits::int_type get_character() noexcept override { @@ -1982,38 +2042,11 @@ class input_buffer_adapter : public input_adapter_protocol const char* const limit; }; -template -class wide_string_input_adapter : public input_adapter_protocol +template +struct wide_string_input_helper { - public: - explicit wide_string_input_adapter(const WideStringType& w) : str(w) {} - - std::char_traits::int_type get_character() noexcept override - { - // check if buffer needs to be filled - if (utf8_bytes_index == utf8_bytes_filled) - { - if (sizeof(typename WideStringType::value_type) == 2) - { - fill_buffer_utf16(); - } - else - { - fill_buffer_utf32(); - } - - assert(utf8_bytes_filled > 0); - assert(utf8_bytes_index == 0); - } - - // use buffer - assert(utf8_bytes_filled > 0); - assert(utf8_bytes_index < utf8_bytes_filled); - return utf8_bytes[utf8_bytes_index++]; - } - - private: - void fill_buffer_utf16() + // UTF-32 + static void fill_buffer(const WideStringType& str, size_t& current_wchar, std::array::int_type, 4>& utf8_bytes, size_t& utf8_bytes_index, size_t& utf8_bytes_filled) { utf8_bytes_index = 0; @@ -2025,7 +2058,62 @@ class wide_string_input_adapter : public input_adapter_protocol else { // get the current character - const int wc = static_cast(str[current_wchar++]); + const auto wc = static_cast(str[current_wchar++]); + + // UTF-32 to UTF-8 encoding + if (wc < 0x80) + { + utf8_bytes[0] = wc; + utf8_bytes_filled = 1; + } + else if (wc <= 0x7FF) + { + utf8_bytes[0] = 0xC0 | ((wc >> 6) & 0x1F); + utf8_bytes[1] = 0x80 | (wc & 0x3F); + utf8_bytes_filled = 2; + } + else if (wc <= 0xFFFF) + { + utf8_bytes[0] = 0xE0 | ((wc >> 12) & 0x0F); + utf8_bytes[1] = 0x80 | ((wc >> 6) & 0x3F); + utf8_bytes[2] = 0x80 | (wc & 0x3F); + utf8_bytes_filled = 3; + } + else if (wc <= 0x10FFFF) + { + utf8_bytes[0] = 0xF0 | ((wc >> 18) & 0x07); + utf8_bytes[1] = 0x80 | ((wc >> 12) & 0x3F); + utf8_bytes[2] = 0x80 | ((wc >> 6) & 0x3F); + utf8_bytes[3] = 0x80 | (wc & 0x3F); + utf8_bytes_filled = 4; + } + else + { + // unknown character + utf8_bytes[0] = wc; + utf8_bytes_filled = 1; + } + } + } +}; + +template +struct wide_string_input_helper +{ + // UTF-16 + static void fill_buffer(const WideStringType& str, size_t& current_wchar, std::array::int_type, 4>& utf8_bytes, size_t& utf8_bytes_index, size_t& utf8_bytes_filled) + { + utf8_bytes_index = 0; + + if (current_wchar == str.size()) + { + utf8_bytes[0] = std::char_traits::eof(); + utf8_bytes_filled = 1; + } + else + { + // get the current character + const auto wc = static_cast(str[current_wchar++]); // UTF-16 to UTF-8 encoding if (wc < 0x80) @@ -2050,7 +2138,7 @@ class wide_string_input_adapter : public input_adapter_protocol { if (current_wchar < str.size()) { - const int wc2 = static_cast(str[current_wchar++]); + const auto wc2 = static_cast(str[current_wchar++]); const int charcode = 0x10000 + (((wc & 0x3FF) << 10) | (wc2 & 0x3FF)); utf8_bytes[0] = 0xf0 | (charcode >> 18); utf8_bytes[1] = 0x80 | ((charcode >> 12) & 0x3F); @@ -2068,58 +2156,38 @@ class wide_string_input_adapter : public input_adapter_protocol } } } +}; - void fill_buffer_utf32() +template +class wide_string_input_adapter : public input_adapter_protocol +{ + public: + explicit wide_string_input_adapter(const WideStringType& w) : str(w) {} + + std::char_traits::int_type get_character() noexcept override { - utf8_bytes_index = 0; - - if (current_wchar == str.size()) + // check if buffer needs to be filled + if (utf8_bytes_index == utf8_bytes_filled) { - utf8_bytes[0] = std::char_traits::eof(); - utf8_bytes_filled = 1; - } - else - { - // get the current character - const int wc = static_cast(str[current_wchar++]); + fill_buffer(); - // UTF-32 to UTF-8 encoding - if (wc < 0x80) - { - utf8_bytes[0] = wc; - utf8_bytes_filled = 1; - } - else if (wc <= 0x7FF) - { - utf8_bytes[0] = 0xC0 | ((wc >> 6) & 0x1F); - utf8_bytes[1] = 0x80 | (wc & 0x3F); - utf8_bytes_filled = 2; - } - else if (wc <= 0xFFFF) - { - utf8_bytes[0] = 0xE0 | ((wc >> 12) & 0x0F); - utf8_bytes[1] = 0x80 | ((wc >> 6) & 0x3F); - utf8_bytes[2] = 0x80 | (wc & 0x3F); - utf8_bytes_filled = 3; - } - else if (wc <= 0x10FFFF) - { - utf8_bytes[0] = 0xF0 | ((wc >> 18 ) & 0x07); - utf8_bytes[1] = 0x80 | ((wc >> 12) & 0x3F); - utf8_bytes[2] = 0x80 | ((wc >> 6) & 0x3F); - utf8_bytes[3] = 0x80 | (wc & 0x3F); - utf8_bytes_filled = 4; - } - else - { - // unknown character - utf8_bytes[0] = wc; - utf8_bytes_filled = 1; - } + assert(utf8_bytes_filled > 0); + assert(utf8_bytes_index == 0); } + + // use buffer + assert(utf8_bytes_filled > 0); + assert(utf8_bytes_index < utf8_bytes_filled); + return utf8_bytes[utf8_bytes_index++]; } private: + template + void fill_buffer() + { + wide_string_input_helper::fill_buffer(str, current_wchar, utf8_bytes, utf8_bytes_index, utf8_bytes_filled); + } + /// the wstring to process const WideStringType& str; @@ -2240,8 +2308,8 @@ class input_adapter /// the actual adapter input_adapter_t ia = nullptr; }; -} -} +} // namespace detail +} // namespace nlohmann // #include @@ -2258,6 +2326,8 @@ class input_adapter // #include +// #include + namespace nlohmann { @@ -2352,7 +2422,10 @@ class lexer // delete because of pointer members lexer(const lexer&) = delete; + lexer(lexer&&) = delete; lexer& operator=(lexer&) = delete; + lexer& operator=(lexer&&) = delete; + ~lexer() = default; private: ///////////////////// @@ -2641,39 +2714,194 @@ class lexer // invalid control characters case 0x00: + { + error_message = "invalid string: control character U+0000 (NUL) must be escaped to \\u0000"; + return token_type::parse_error; + } + case 0x01: + { + error_message = "invalid string: control character U+0001 (SOH) must be escaped to \\u0001"; + return token_type::parse_error; + } + case 0x02: + { + error_message = "invalid string: control character U+0002 (STX) must be escaped to \\u0002"; + return token_type::parse_error; + } + case 0x03: + { + error_message = "invalid string: control character U+0003 (ETX) must be escaped to \\u0003"; + return token_type::parse_error; + } + case 0x04: + { + error_message = "invalid string: control character U+0004 (EOT) must be escaped to \\u0004"; + return token_type::parse_error; + } + case 0x05: + { + error_message = "invalid string: control character U+0005 (ENQ) must be escaped to \\u0005"; + return token_type::parse_error; + } + case 0x06: + { + error_message = "invalid string: control character U+0006 (ACK) must be escaped to \\u0006"; + return token_type::parse_error; + } + case 0x07: + { + error_message = "invalid string: control character U+0007 (BEL) must be escaped to \\u0007"; + return token_type::parse_error; + } + case 0x08: + { + error_message = "invalid string: control character U+0008 (BS) must be escaped to \\u0008 or \\b"; + return token_type::parse_error; + } + case 0x09: + { + error_message = "invalid string: control character U+0009 (HT) must be escaped to \\u0009 or \\t"; + return token_type::parse_error; + } + case 0x0A: + { + error_message = "invalid string: control character U+000A (LF) must be escaped to \\u000A or \\n"; + return token_type::parse_error; + } + case 0x0B: + { + error_message = "invalid string: control character U+000B (VT) must be escaped to \\u000B"; + return token_type::parse_error; + } + case 0x0C: + { + error_message = "invalid string: control character U+000C (FF) must be escaped to \\u000C or \\f"; + return token_type::parse_error; + } + case 0x0D: + { + error_message = "invalid string: control character U+000D (CR) must be escaped to \\u000D or \\r"; + return token_type::parse_error; + } + case 0x0E: + { + error_message = "invalid string: control character U+000E (SO) must be escaped to \\u000E"; + return token_type::parse_error; + } + case 0x0F: + { + error_message = "invalid string: control character U+000F (SI) must be escaped to \\u000F"; + return token_type::parse_error; + } + case 0x10: + { + error_message = "invalid string: control character U+0010 (DLE) must be escaped to \\u0010"; + return token_type::parse_error; + } + case 0x11: + { + error_message = "invalid string: control character U+0011 (DC1) must be escaped to \\u0011"; + return token_type::parse_error; + } + case 0x12: + { + error_message = "invalid string: control character U+0012 (DC2) must be escaped to \\u0012"; + return token_type::parse_error; + } + case 0x13: + { + error_message = "invalid string: control character U+0013 (DC3) must be escaped to \\u0013"; + return token_type::parse_error; + } + case 0x14: + { + error_message = "invalid string: control character U+0014 (DC4) must be escaped to \\u0014"; + return token_type::parse_error; + } + case 0x15: + { + error_message = "invalid string: control character U+0015 (NAK) must be escaped to \\u0015"; + return token_type::parse_error; + } + case 0x16: + { + error_message = "invalid string: control character U+0016 (SYN) must be escaped to \\u0016"; + return token_type::parse_error; + } + case 0x17: + { + error_message = "invalid string: control character U+0017 (ETB) must be escaped to \\u0017"; + return token_type::parse_error; + } + case 0x18: + { + error_message = "invalid string: control character U+0018 (CAN) must be escaped to \\u0018"; + return token_type::parse_error; + } + case 0x19: + { + error_message = "invalid string: control character U+0019 (EM) must be escaped to \\u0019"; + return token_type::parse_error; + } + case 0x1A: + { + error_message = "invalid string: control character U+001A (SUB) must be escaped to \\u001A"; + return token_type::parse_error; + } + case 0x1B: + { + error_message = "invalid string: control character U+001B (ESC) must be escaped to \\u001B"; + return token_type::parse_error; + } + case 0x1C: + { + error_message = "invalid string: control character U+001C (FS) must be escaped to \\u001C"; + return token_type::parse_error; + } + case 0x1D: + { + error_message = "invalid string: control character U+001D (GS) must be escaped to \\u001D"; + return token_type::parse_error; + } + case 0x1E: + { + error_message = "invalid string: control character U+001E (RS) must be escaped to \\u001E"; + return token_type::parse_error; + } + case 0x1F: { - error_message = "invalid string: control character must be escaped"; + error_message = "invalid string: control character U+001F (US) must be escaped to \\u001F"; return token_type::parse_error; } @@ -2957,7 +3185,7 @@ class lexer locale's decimal point is used instead of `.` to work with the locale-dependent converters. */ - token_type scan_number() + token_type scan_number() // lgtm [cpp/use-of-goto] { // reset token_buffer to store the number's bytes reset(); @@ -3330,7 +3558,9 @@ scan_number_done: */ std::char_traits::int_type get() { - ++chars_read; + ++position.chars_read_total; + ++position.chars_read_current_line; + if (next_unget) { // just reset the next_unget variable and work with current @@ -3345,6 +3575,13 @@ scan_number_done: { token_string.push_back(std::char_traits::to_char_type(current)); } + + if (current == '\n') + { + ++position.lines_read; + ++position.chars_read_current_line = 0; + } + return current; } @@ -3352,14 +3589,29 @@ scan_number_done: @brief unget current character (read it again on next get) We implement unget by setting variable next_unget to true. The input is not - changed - we just simulate ungetting by modifying chars_read and - token_string. The next call to get() will behave as if the unget character - is read again. + changed - we just simulate ungetting by modifying chars_read_total, + chars_read_current_line, and token_string. The next call to get() will + behave as if the unget character is read again. */ void unget() { next_unget = true; - --chars_read; + + --position.chars_read_total; + + // in case we "unget" a newline, we have to also decrement the lines_read + if (position.chars_read_current_line == 0) + { + if (position.lines_read > 0) + { + --position.lines_read; + } + } + else + { + --position.chars_read_current_line; + } + if (JSON_LIKELY(current != std::char_traits::eof())) { assert(token_string.size() != 0); @@ -3407,9 +3659,9 @@ scan_number_done: ///////////////////// /// return position of last read token - constexpr std::size_t get_position() const noexcept + constexpr position_t get_position() const noexcept { - return chars_read; + return position; } /// return the last read token (for errors only). Will never contain EOF @@ -3456,30 +3708,20 @@ scan_number_done: { if (get() == 0xEF) { - if (get() == 0xBB and get() == 0xBF) - { - // we completely parsed the BOM - return true; - } - else - { - // after reading 0xEF, an unexpected character followed - return false; - } - } - else - { - // the first character is not the beginning of the BOM; unget it to - // process is later - unget(); - return true; + // check if we completely parse the BOM + return get() == 0xBB and get() == 0xBF; } + + // the first character is not the beginning of the BOM; unget it to + // process is later + unget(); + return true; } token_type scan() { // initially, skip the BOM - if (chars_read == 0 and not skip_bom()) + if (position.chars_read_total == 0 and not skip_bom()) { error_message = "invalid BOM; must be 0xEF 0xBB 0xBF if given"; return token_type::parse_error; @@ -3557,8 +3799,8 @@ scan_number_done: /// whether the next get() call should just return current bool next_unget = false; - /// the number of characters read - std::size_t chars_read = 0; + /// the start position of the current token + position_t position; /// raw input token string (for error messages) std::vector token_string {}; @@ -3577,8 +3819,8 @@ scan_number_done: /// the decimal point const char decimal_point_char = '.'; }; -} -} +} // namespace detail +} // namespace nlohmann // #include @@ -3736,8 +3978,8 @@ struct is_sax_static_asserts "Missing/invalid function: bool parse_error(std::size_t, const " "std::string&, const exception&)"); }; -} -} +} // namespace detail +} // namespace nlohmann // #include @@ -3859,7 +4101,7 @@ struct json_sax @brief a parse error occurred @param[in] position the position in the input where the error occurs @param[in] last_token the last read token - @param[in] error_msg a detailed error message + @param[in] ex an exception object describing the error @return whether parsing should proceed (must return false) */ virtual bool parse_error(std::size_t position, @@ -3927,7 +4169,7 @@ class json_sax_dom_parser return true; } - bool number_float(number_float_t val, const string_t&) + bool number_float(number_float_t val, const string_t& /*unused*/) { handle_value(val); return true; @@ -3984,7 +4226,7 @@ class json_sax_dom_parser return true; } - bool parse_error(std::size_t, const std::string&, + bool parse_error(std::size_t /*unused*/, const std::string& /*unused*/, const detail::exception& ex) { errored = true; @@ -4032,20 +4274,19 @@ class json_sax_dom_parser root = BasicJsonType(std::forward(v)); return &root; } + + assert(ref_stack.back()->is_array() or ref_stack.back()->is_object()); + + if (ref_stack.back()->is_array()) + { + ref_stack.back()->m_value.array->emplace_back(std::forward(v)); + return &(ref_stack.back()->m_value.array->back()); + } else { - assert(ref_stack.back()->is_array() or ref_stack.back()->is_object()); - if (ref_stack.back()->is_array()) - { - ref_stack.back()->m_value.array->emplace_back(std::forward(v)); - return &(ref_stack.back()->m_value.array->back()); - } - else - { - assert(object_element); - *object_element = BasicJsonType(std::forward(v)); - return object_element; - } + assert(object_element); + *object_element = BasicJsonType(std::forward(v)); + return object_element; } } @@ -4104,7 +4345,7 @@ class json_sax_dom_callback_parser return true; } - bool number_float(number_float_t val, const string_t&) + bool number_float(number_float_t val, const string_t& /*unused*/) { handle_value(val); return true; @@ -4242,7 +4483,7 @@ class json_sax_dom_callback_parser return true; } - bool parse_error(std::size_t, const std::string&, + bool parse_error(std::size_t /*unused*/, const std::string& /*unused*/, const detail::exception& ex) { errored = true; @@ -4320,37 +4561,37 @@ class json_sax_dom_callback_parser root = std::move(value); return {true, &root}; } + + // skip this value if we already decided to skip the parent + // (https://github.com/nlohmann/json/issues/971#issuecomment-413678360) + if (not ref_stack.back()) + { + return {false, nullptr}; + } + + // we now only expect arrays and objects + assert(ref_stack.back()->is_array() or ref_stack.back()->is_object()); + + if (ref_stack.back()->is_array()) + { + ref_stack.back()->m_value.array->push_back(std::move(value)); + return {true, &(ref_stack.back()->m_value.array->back())}; + } else { - // skip this value if we already decided to skip the parent - // (https://github.com/nlohmann/json/issues/971#issuecomment-413678360) - if (not ref_stack.back()) + // check if we should store an element for the current key + assert(not key_keep_stack.empty()); + const bool store_element = key_keep_stack.back(); + key_keep_stack.pop_back(); + + if (not store_element) { return {false, nullptr}; } - assert(ref_stack.back()->is_array() or ref_stack.back()->is_object()); - if (ref_stack.back()->is_array()) - { - ref_stack.back()->m_value.array->push_back(std::move(value)); - return {true, &(ref_stack.back()->m_value.array->back())}; - } - else - { - // check if we should store an element for the current key - assert(not key_keep_stack.empty()); - const bool store_element = key_keep_stack.back(); - key_keep_stack.pop_back(); - - if (not store_element) - { - return {false, nullptr}; - } - - assert(object_element); - *object_element = std::move(value); - return {true, object_element}; - } + assert(object_element); + *object_element = std::move(value); + return {true, object_element}; } } @@ -4388,37 +4629,37 @@ class json_sax_acceptor return true; } - bool boolean(bool) + bool boolean(bool /*unused*/) { return true; } - bool number_integer(number_integer_t) + bool number_integer(number_integer_t /*unused*/) { return true; } - bool number_unsigned(number_unsigned_t) + bool number_unsigned(number_unsigned_t /*unused*/) { return true; } - bool number_float(number_float_t, const string_t&) + bool number_float(number_float_t /*unused*/, const string_t& /*unused*/) { return true; } - bool string(string_t&) + bool string(string_t& /*unused*/) { return true; } - bool start_object(std::size_t = std::size_t(-1)) + bool start_object(std::size_t /*unused*/ = std::size_t(-1)) { return true; } - bool key(string_t&) + bool key(string_t& /*unused*/) { return true; } @@ -4428,7 +4669,7 @@ class json_sax_acceptor return true; } - bool start_array(std::size_t = std::size_t(-1)) + bool start_array(std::size_t /*unused*/ = std::size_t(-1)) { return true; } @@ -4438,14 +4679,14 @@ class json_sax_acceptor return true; } - bool parse_error(std::size_t, const std::string&, const detail::exception&) + bool parse_error(std::size_t /*unused*/, const std::string& /*unused*/, const detail::exception& /*unused*/) { return false; } }; -} +} // namespace detail -} +} // namespace nlohmann // #include @@ -4528,7 +4769,8 @@ class parser { sdp.parse_error(m_lexer.get_position(), m_lexer.get_token_string(), - parse_error::create(101, m_lexer.get_position(), exception_message(token_type::end_of_input))); + parse_error::create(101, m_lexer.get_position(), + exception_message(token_type::end_of_input, "value"))); } // in case of an error, return discarded value @@ -4556,7 +4798,8 @@ class parser { sdp.parse_error(m_lexer.get_position(), m_lexer.get_token_string(), - parse_error::create(101, m_lexer.get_position(), exception_message(token_type::end_of_input))); + parse_error::create(101, m_lexer.get_position(), + exception_message(token_type::end_of_input, "value"))); } // in case of an error, return discarded value @@ -4591,7 +4834,8 @@ class parser { return sax->parse_error(m_lexer.get_position(), m_lexer.get_token_string(), - parse_error::create(101, m_lexer.get_position(), exception_message(token_type::end_of_input))); + parse_error::create(101, m_lexer.get_position(), + exception_message(token_type::end_of_input, "value"))); } return result; @@ -4636,14 +4880,12 @@ class parser { return sax->parse_error(m_lexer.get_position(), m_lexer.get_token_string(), - parse_error::create(101, m_lexer.get_position(), exception_message(token_type::value_string))); + parse_error::create(101, m_lexer.get_position(), + exception_message(token_type::value_string, "object key"))); } - else + if (JSON_UNLIKELY(not sax->key(m_lexer.get_string()))) { - if (JSON_UNLIKELY(not sax->key(m_lexer.get_string()))) - { - return false; - } + return false; } // parse separator (:) @@ -4651,7 +4893,8 @@ class parser { return sax->parse_error(m_lexer.get_position(), m_lexer.get_token_string(), - parse_error::create(101, m_lexer.get_position(), exception_message(token_type::name_separator))); + parse_error::create(101, m_lexer.get_position(), + exception_message(token_type::name_separator, "object separator"))); } // remember we are now inside an object @@ -4765,14 +5008,16 @@ class parser // using "uninitialized" to avoid "expected" message return sax->parse_error(m_lexer.get_position(), m_lexer.get_token_string(), - parse_error::create(101, m_lexer.get_position(), exception_message(token_type::uninitialized))); + parse_error::create(101, m_lexer.get_position(), + exception_message(token_type::uninitialized, "value"))); } default: // the last token was unexpected { return sax->parse_error(m_lexer.get_position(), m_lexer.get_token_string(), - parse_error::create(101, m_lexer.get_position(), exception_message(token_type::literal_or_value))); + parse_error::create(101, m_lexer.get_position(), + exception_message(token_type::literal_or_value, "value"))); } } } @@ -4820,7 +5065,8 @@ class parser { return sax->parse_error(m_lexer.get_position(), m_lexer.get_token_string(), - parse_error::create(101, m_lexer.get_position(), exception_message(token_type::end_array))); + parse_error::create(101, m_lexer.get_position(), + exception_message(token_type::end_array, "array"))); } } else // object @@ -4833,7 +5079,8 @@ class parser { return sax->parse_error(m_lexer.get_position(), m_lexer.get_token_string(), - parse_error::create(101, m_lexer.get_position(), exception_message(token_type::value_string))); + parse_error::create(101, m_lexer.get_position(), + exception_message(token_type::value_string, "object key"))); } else { @@ -4848,7 +5095,8 @@ class parser { return sax->parse_error(m_lexer.get_position(), m_lexer.get_token_string(), - parse_error::create(101, m_lexer.get_position(), exception_message(token_type::name_separator))); + parse_error::create(101, m_lexer.get_position(), + exception_message(token_type::name_separator, "object separator"))); } // parse values @@ -4877,7 +5125,8 @@ class parser { return sax->parse_error(m_lexer.get_position(), m_lexer.get_token_string(), - parse_error::create(101, m_lexer.get_position(), exception_message(token_type::end_object))); + parse_error::create(101, m_lexer.get_position(), + exception_message(token_type::end_object, "object"))); } } } @@ -4890,9 +5139,17 @@ class parser return (last_token = m_lexer.scan()); } - std::string exception_message(const token_type expected) + std::string exception_message(const token_type expected, const std::string& context) { - std::string error_msg = "syntax error - "; + std::string error_msg = "syntax error "; + + if (not context.empty()) + { + error_msg += "while parsing " + context + " "; + } + + error_msg += "- "; + if (last_token == token_type::parse_error) { error_msg += std::string(m_lexer.get_error_message()) + "; last read: '" + @@ -4921,8 +5178,8 @@ class parser /// whether to throw exceptions in case of errors const bool allow_exceptions = true; }; -} -} +} // namespace detail +} // namespace nlohmann // #include @@ -5043,8 +5300,8 @@ class primitive_iterator_t return *this; } }; -} -} +} // namespace detail +} // namespace nlohmann // #include @@ -5071,8 +5328,8 @@ template struct internal_iterator /// generic iterator for all other types primitive_iterator_t primitive_iterator {}; }; -} -} +} // namespace detail +} // namespace nlohmann // #include @@ -5693,8 +5950,8 @@ class iter_impl /// the actual iterator of the associated instance internal_iterator::type> m_it; }; -} -} +} // namespace detail +} // namespace nlohmann // #include @@ -5816,8 +6073,8 @@ class json_reverse_iterator : public std::reverse_iterator return it.operator * (); } }; -} -} +} // namespace detail +} // namespace nlohmann // #include @@ -5931,8 +6188,8 @@ class output_adapter private: output_adapter_t oa = nullptr; }; -} -} +} // namespace detail +} // namespace nlohmann // #include @@ -6047,7 +6304,8 @@ class binary_reader if (JSON_UNLIKELY(current != std::char_traits::eof())) { - return sax->parse_error(chars_read, get_token_string(), parse_error::create(110, chars_read, "expected end of input")); + return sax->parse_error(chars_read, get_token_string(), + parse_error::create(110, chars_read, exception_message(format, "expected end of input; last byte: 0x" + get_token_string(), "value"))); } } @@ -6082,7 +6340,7 @@ class binary_reader while (true) { get(); - if (JSON_UNLIKELY(not unexpect_eof())) + if (JSON_UNLIKELY(not unexpect_eof(input_format_t::bson, "cstring"))) { return false; } @@ -6108,7 +6366,7 @@ class binary_reader template bool get_bson_string(const NumberType len, string_t& result) { - return get_string(len - static_cast(1), result) + return get_string(input_format_t::bson, len - static_cast(1), result) && get() != std::char_traits::eof(); } @@ -6138,14 +6396,14 @@ class binary_reader case 0x01: // double { double number; - return get_number(number) + return get_number(input_format_t::bson, number) && sax->number_float(static_cast(number), ""); } case 0x02: // string { std::int32_t len; string_t value; - return get_number(len) + return get_number(input_format_t::bson, len) && get_bson_string(len, value) && sax->string(value); } @@ -6156,13 +6414,13 @@ class binary_reader case 0x10: // int32 { std::int32_t value; - return get_number(value) + return get_number(input_format_t::bson, value) && sax->number_integer(static_cast(value)); } case 0x12: // int64 { std::int64_t value; - return get_number(value) + return get_number(input_format_t::bson, value) && sax->number_integer(static_cast(value)); } case 0x0A: // null @@ -6199,7 +6457,7 @@ class binary_reader { while (auto element_type = get()) { - if (JSON_UNLIKELY(not unexpect_eof())) + if (JSON_UNLIKELY(not unexpect_eof(input_format_t::bson, "element list"))) { return false; } @@ -6231,7 +6489,7 @@ class binary_reader bool parse_bson_array() { std::int32_t documentSize; - get_number(documentSize); + get_number(input_format_t::bson, documentSize); if (JSON_UNLIKELY(not sax->start_array(-1))) { @@ -6253,7 +6511,7 @@ class binary_reader bool parse_bson_internal() { std::int32_t documentSize; - get_number(documentSize); + get_number(input_format_t::bson, documentSize); if (JSON_UNLIKELY(not sax->start_object(-1))) { @@ -6281,7 +6539,7 @@ class binary_reader { // EOF case std::char_traits::eof(): - return unexpect_eof(); + return unexpect_eof(input_format_t::cbor, "value"); // Integer 0x00..0x17 (0..23) case 0x00: @@ -6313,25 +6571,25 @@ class binary_reader case 0x18: // Unsigned integer (one-byte uint8_t follows) { uint8_t number; - return get_number(number) and sax->number_unsigned(number); + return get_number(input_format_t::cbor, number) and sax->number_unsigned(number); } case 0x19: // Unsigned integer (two-byte uint16_t follows) { uint16_t number; - return get_number(number) and sax->number_unsigned(number); + return get_number(input_format_t::cbor, number) and sax->number_unsigned(number); } case 0x1A: // Unsigned integer (four-byte uint32_t follows) { uint32_t number; - return get_number(number) and sax->number_unsigned(number); + return get_number(input_format_t::cbor, number) and sax->number_unsigned(number); } case 0x1B: // Unsigned integer (eight-byte uint64_t follows) { uint64_t number; - return get_number(number) and sax->number_unsigned(number); + return get_number(input_format_t::cbor, number) and sax->number_unsigned(number); } // Negative integer -1-0x00..-1-0x17 (-1..-24) @@ -6364,25 +6622,25 @@ class binary_reader case 0x38: // Negative integer (one-byte uint8_t follows) { uint8_t number; - return get_number(number) and sax->number_integer(static_cast(-1) - number); + return get_number(input_format_t::cbor, number) and sax->number_integer(static_cast(-1) - number); } case 0x39: // Negative integer -1-n (two-byte uint16_t follows) { uint16_t number; - return get_number(number) and sax->number_integer(static_cast(-1) - number); + return get_number(input_format_t::cbor, number) and sax->number_integer(static_cast(-1) - number); } case 0x3A: // Negative integer -1-n (four-byte uint32_t follows) { uint32_t number; - return get_number(number) and sax->number_integer(static_cast(-1) - number); + return get_number(input_format_t::cbor, number) and sax->number_integer(static_cast(-1) - number); } case 0x3B: // Negative integer -1-n (eight-byte uint64_t follows) { uint64_t number; - return get_number(number) and sax->number_integer(static_cast(-1) + return get_number(input_format_t::cbor, number) and sax->number_integer(static_cast(-1) - static_cast(number)); } @@ -6451,25 +6709,25 @@ class binary_reader case 0x98: // array (one-byte uint8_t for n follows) { uint8_t len; - return get_number(len) and get_cbor_array(static_cast(len)); + return get_number(input_format_t::cbor, len) and get_cbor_array(static_cast(len)); } case 0x99: // array (two-byte uint16_t for n follow) { uint16_t len; - return get_number(len) and get_cbor_array(static_cast(len)); + return get_number(input_format_t::cbor, len) and get_cbor_array(static_cast(len)); } case 0x9A: // array (four-byte uint32_t for n follow) { uint32_t len; - return get_number(len) and get_cbor_array(static_cast(len)); + return get_number(input_format_t::cbor, len) and get_cbor_array(static_cast(len)); } case 0x9B: // array (eight-byte uint64_t for n follow) { uint64_t len; - return get_number(len) and get_cbor_array(static_cast(len)); + return get_number(input_format_t::cbor, len) and get_cbor_array(static_cast(len)); } case 0x9F: // array (indefinite length) @@ -6505,25 +6763,25 @@ class binary_reader case 0xB8: // map (one-byte uint8_t for n follows) { uint8_t len; - return get_number(len) and get_cbor_object(static_cast(len)); + return get_number(input_format_t::cbor, len) and get_cbor_object(static_cast(len)); } case 0xB9: // map (two-byte uint16_t for n follow) { uint16_t len; - return get_number(len) and get_cbor_object(static_cast(len)); + return get_number(input_format_t::cbor, len) and get_cbor_object(static_cast(len)); } case 0xBA: // map (four-byte uint32_t for n follow) { uint32_t len; - return get_number(len) and get_cbor_object(static_cast(len)); + return get_number(input_format_t::cbor, len) and get_cbor_object(static_cast(len)); } case 0xBB: // map (eight-byte uint64_t for n follow) { uint64_t len; - return get_number(len) and get_cbor_object(static_cast(len)); + return get_number(input_format_t::cbor, len) and get_cbor_object(static_cast(len)); } case 0xBF: // map (indefinite length) @@ -6540,17 +6798,20 @@ class binary_reader case 0xF9: // Half-Precision Float (two-byte IEEE 754) { - const int byte1 = get(); - if (JSON_UNLIKELY(not unexpect_eof())) + const int byte1_raw = get(); + if (JSON_UNLIKELY(not unexpect_eof(input_format_t::cbor, "number"))) { return false; } - const int byte2 = get(); - if (JSON_UNLIKELY(not unexpect_eof())) + const int byte2_raw = get(); + if (JSON_UNLIKELY(not unexpect_eof(input_format_t::cbor, "number"))) { return false; } + const auto byte1 = static_cast(byte1_raw); + const auto byte2 = static_cast(byte2_raw); + // code from RFC 7049, Appendix D, Figure 3: // As half-precision floating-point numbers were only added // to IEEE 754 in 2008, today's programming platforms often @@ -6586,19 +6847,19 @@ class binary_reader case 0xFA: // Single-Precision Float (four-byte IEEE 754) { float number; - return get_number(number) and sax->number_float(static_cast(number), ""); + return get_number(input_format_t::cbor, number) and sax->number_float(static_cast(number), ""); } case 0xFB: // Double-Precision Float (eight-byte IEEE 754) { double number; - return get_number(number) and sax->number_float(static_cast(number), ""); + return get_number(input_format_t::cbor, number) and sax->number_float(static_cast(number), ""); } default: // anything else (0xFF is handled inside the other types) { auto last_token = get_token_string(); - return sax->parse_error(chars_read, last_token, parse_error::create(112, chars_read, "error reading CBOR; last byte: 0x" + last_token)); + return sax->parse_error(chars_read, last_token, parse_error::create(112, chars_read, exception_message(input_format_t::cbor, "invalid byte: 0x" + last_token, "value"))); } } } @@ -6612,7 +6873,7 @@ class binary_reader { // EOF case std::char_traits::eof(): - return unexpect_eof(); + return unexpect_eof(input_format_t::msgpack, "value"); // positive fixint case 0x00: @@ -6833,61 +7094,61 @@ class binary_reader case 0xCA: // float 32 { float number; - return get_number(number) and sax->number_float(static_cast(number), ""); + return get_number(input_format_t::msgpack, number) and sax->number_float(static_cast(number), ""); } case 0xCB: // float 64 { double number; - return get_number(number) and sax->number_float(static_cast(number), ""); + return get_number(input_format_t::msgpack, number) and sax->number_float(static_cast(number), ""); } case 0xCC: // uint 8 { uint8_t number; - return get_number(number) and sax->number_unsigned(number); + return get_number(input_format_t::msgpack, number) and sax->number_unsigned(number); } case 0xCD: // uint 16 { uint16_t number; - return get_number(number) and sax->number_unsigned(number); + return get_number(input_format_t::msgpack, number) and sax->number_unsigned(number); } case 0xCE: // uint 32 { uint32_t number; - return get_number(number) and sax->number_unsigned(number); + return get_number(input_format_t::msgpack, number) and sax->number_unsigned(number); } case 0xCF: // uint 64 { uint64_t number; - return get_number(number) and sax->number_unsigned(number); + return get_number(input_format_t::msgpack, number) and sax->number_unsigned(number); } case 0xD0: // int 8 { int8_t number; - return get_number(number) and sax->number_integer(number); + return get_number(input_format_t::msgpack, number) and sax->number_integer(number); } case 0xD1: // int 16 { int16_t number; - return get_number(number) and sax->number_integer(number); + return get_number(input_format_t::msgpack, number) and sax->number_integer(number); } case 0xD2: // int 32 { int32_t number; - return get_number(number) and sax->number_integer(number); + return get_number(input_format_t::msgpack, number) and sax->number_integer(number); } case 0xD3: // int 64 { int64_t number; - return get_number(number) and sax->number_integer(number); + return get_number(input_format_t::msgpack, number) and sax->number_integer(number); } case 0xD9: // str 8 @@ -6901,25 +7162,25 @@ class binary_reader case 0xDC: // array 16 { uint16_t len; - return get_number(len) and get_msgpack_array(static_cast(len)); + return get_number(input_format_t::msgpack, len) and get_msgpack_array(static_cast(len)); } case 0xDD: // array 32 { uint32_t len; - return get_number(len) and get_msgpack_array(static_cast(len)); + return get_number(input_format_t::msgpack, len) and get_msgpack_array(static_cast(len)); } case 0xDE: // map 16 { uint16_t len; - return get_number(len) and get_msgpack_object(static_cast(len)); + return get_number(input_format_t::msgpack, len) and get_msgpack_object(static_cast(len)); } case 0xDF: // map 32 { uint32_t len; - return get_number(len) and get_msgpack_object(static_cast(len)); + return get_number(input_format_t::msgpack, len) and get_msgpack_object(static_cast(len)); } // negative fixint @@ -6960,7 +7221,7 @@ class binary_reader default: // anything else { auto last_token = get_token_string(); - return sax->parse_error(chars_read, last_token, parse_error::create(112, chars_read, "error reading MessagePack; last byte: 0x" + last_token)); + return sax->parse_error(chars_read, last_token, parse_error::create(112, chars_read, exception_message(input_format_t::msgpack, "invalid byte: 0x" + last_token, "value"))); } } } @@ -7010,6 +7271,7 @@ class binary_reader @brief read a number from the input @tparam NumberType the type of the number + @param[in] format the current format (for diagnostics) @param[out] result number of type @a NumberType @return whether conversion completed @@ -7019,14 +7281,14 @@ class binary_reader (big endian) and therefore need reordering on little endian systems. */ template - bool get_number(NumberType& result) + bool get_number(const input_format_t format, NumberType& result) { // step 1: read input into array with system's byte order std::array vec; for (std::size_t i = 0; i < sizeof(NumberType); ++i) { get(); - if (JSON_UNLIKELY(not unexpect_eof())) + if (JSON_UNLIKELY(not unexpect_eof(format, "number"))) { return false; } @@ -7052,8 +7314,9 @@ class binary_reader @brief create a string by reading characters from the input @tparam NumberType the type of the number + @param[in] format the current format (for diagnostics) @param[in] len number of characters to read - @param[out] string created by reading @a len bytes + @param[out] result string created by reading @a len bytes @return whether string creation completed @@ -7062,13 +7325,13 @@ class binary_reader the input before we run out of string memory. */ template - bool get_string(const NumberType len, string_t& result) + bool get_string(const input_format_t format, const NumberType len, string_t& result) { bool success = true; - std::generate_n(std::back_inserter(result), len, [this, &success]() + std::generate_n(std::back_inserter(result), len, [this, &success, &format]() { get(); - if (JSON_UNLIKELY(not unexpect_eof())) + if (JSON_UNLIKELY(not unexpect_eof(format, "string"))) { success = false; } @@ -7090,7 +7353,7 @@ class binary_reader */ bool get_cbor_string(string_t& result) { - if (JSON_UNLIKELY(not unexpect_eof())) + if (JSON_UNLIKELY(not unexpect_eof(input_format_t::cbor, "string"))) { return false; } @@ -7123,31 +7386,31 @@ class binary_reader case 0x76: case 0x77: { - return get_string(current & 0x1F, result); + return get_string(input_format_t::cbor, current & 0x1F, result); } case 0x78: // UTF-8 string (one-byte uint8_t for n follows) { uint8_t len; - return get_number(len) and get_string(len, result); + return get_number(input_format_t::cbor, len) and get_string(input_format_t::cbor, len, result); } case 0x79: // UTF-8 string (two-byte uint16_t for n follow) { uint16_t len; - return get_number(len) and get_string(len, result); + return get_number(input_format_t::cbor, len) and get_string(input_format_t::cbor, len, result); } case 0x7A: // UTF-8 string (four-byte uint32_t for n follow) { uint32_t len; - return get_number(len) and get_string(len, result); + return get_number(input_format_t::cbor, len) and get_string(input_format_t::cbor, len, result); } case 0x7B: // UTF-8 string (eight-byte uint64_t for n follow) { uint64_t len; - return get_number(len) and get_string(len, result); + return get_number(input_format_t::cbor, len) and get_string(input_format_t::cbor, len, result); } case 0x7F: // UTF-8 string (indefinite length) @@ -7167,7 +7430,7 @@ class binary_reader default: { auto last_token = get_token_string(); - return sax->parse_error(chars_read, last_token, parse_error::create(113, chars_read, "expected a CBOR string; last byte: 0x" + last_token)); + return sax->parse_error(chars_read, last_token, parse_error::create(113, chars_read, exception_message(input_format_t::cbor, "expected length specification (0x60-0x7B) or indefinite string type (0x7F); last byte: 0x" + last_token, "string"))); } } } @@ -7185,6 +7448,7 @@ class binary_reader } if (len != std::size_t(-1)) + { for (std::size_t i = 0; i < len; ++i) { if (JSON_UNLIKELY(not parse_cbor_internal())) @@ -7192,6 +7456,7 @@ class binary_reader return false; } } + } else { while (get() != 0xFF) @@ -7268,7 +7533,7 @@ class binary_reader */ bool get_msgpack_string(string_t& result) { - if (JSON_UNLIKELY(not unexpect_eof())) + if (JSON_UNLIKELY(not unexpect_eof(input_format_t::msgpack, "string"))) { return false; } @@ -7309,31 +7574,31 @@ class binary_reader case 0xBE: case 0xBF: { - return get_string(current & 0x1F, result); + return get_string(input_format_t::msgpack, current & 0x1F, result); } case 0xD9: // str 8 { uint8_t len; - return get_number(len) and get_string(len, result); + return get_number(input_format_t::msgpack, len) and get_string(input_format_t::msgpack, len, result); } case 0xDA: // str 16 { uint16_t len; - return get_number(len) and get_string(len, result); + return get_number(input_format_t::msgpack, len) and get_string(input_format_t::msgpack, len, result); } case 0xDB: // str 32 { uint32_t len; - return get_number(len) and get_string(len, result); + return get_number(input_format_t::msgpack, len) and get_string(input_format_t::msgpack, len, result); } default: { auto last_token = get_token_string(); - return sax->parse_error(chars_read, last_token, parse_error::create(113, chars_read, "expected a MessagePack string; last byte: 0x" + last_token)); + return sax->parse_error(chars_read, last_token, parse_error::create(113, chars_read, exception_message(input_format_t::msgpack, "expected length specification (0xA0-0xBF, 0xD9-0xDB); last byte: 0x" + last_token, "string"))); } } } @@ -7411,7 +7676,7 @@ class binary_reader get(); // TODO: may we ignore N here? } - if (JSON_UNLIKELY(not unexpect_eof())) + if (JSON_UNLIKELY(not unexpect_eof(input_format_t::ubjson, "value"))) { return false; } @@ -7421,36 +7686,36 @@ class binary_reader case 'U': { uint8_t len; - return get_number(len) and get_string(len, result); + return get_number(input_format_t::ubjson, len) and get_string(input_format_t::ubjson, len, result); } case 'i': { int8_t len; - return get_number(len) and get_string(len, result); + return get_number(input_format_t::ubjson, len) and get_string(input_format_t::ubjson, len, result); } case 'I': { int16_t len; - return get_number(len) and get_string(len, result); + return get_number(input_format_t::ubjson, len) and get_string(input_format_t::ubjson, len, result); } case 'l': { int32_t len; - return get_number(len) and get_string(len, result); + return get_number(input_format_t::ubjson, len) and get_string(input_format_t::ubjson, len, result); } case 'L': { int64_t len; - return get_number(len) and get_string(len, result); + return get_number(input_format_t::ubjson, len) and get_string(input_format_t::ubjson, len, result); } default: auto last_token = get_token_string(); - return sax->parse_error(chars_read, last_token, parse_error::create(113, chars_read, "expected a UBJSON string; last byte: 0x" + last_token)); + return sax->parse_error(chars_read, last_token, parse_error::create(113, chars_read, exception_message(input_format_t::ubjson, "expected length type specification (U, i, I, l, L); last byte: 0x" + last_token, "string"))); } } @@ -7465,7 +7730,7 @@ class binary_reader case 'U': { uint8_t number; - if (JSON_UNLIKELY(not get_number(number))) + if (JSON_UNLIKELY(not get_number(input_format_t::ubjson, number))) { return false; } @@ -7476,7 +7741,7 @@ class binary_reader case 'i': { int8_t number; - if (JSON_UNLIKELY(not get_number(number))) + if (JSON_UNLIKELY(not get_number(input_format_t::ubjson, number))) { return false; } @@ -7487,7 +7752,7 @@ class binary_reader case 'I': { int16_t number; - if (JSON_UNLIKELY(not get_number(number))) + if (JSON_UNLIKELY(not get_number(input_format_t::ubjson, number))) { return false; } @@ -7498,7 +7763,7 @@ class binary_reader case 'l': { int32_t number; - if (JSON_UNLIKELY(not get_number(number))) + if (JSON_UNLIKELY(not get_number(input_format_t::ubjson, number))) { return false; } @@ -7509,7 +7774,7 @@ class binary_reader case 'L': { int64_t number; - if (JSON_UNLIKELY(not get_number(number))) + if (JSON_UNLIKELY(not get_number(input_format_t::ubjson, number))) { return false; } @@ -7520,7 +7785,7 @@ class binary_reader default: { auto last_token = get_token_string(); - return sax->parse_error(chars_read, last_token, parse_error::create(113, chars_read, "byte after '#' must denote a number type; last byte: 0x" + last_token)); + return sax->parse_error(chars_read, last_token, parse_error::create(113, chars_read, exception_message(input_format_t::ubjson, "expected length type specification (U, i, I, l, L) after '#'; last byte: 0x" + last_token, "size"))); } } } @@ -7545,7 +7810,7 @@ class binary_reader if (current == '$') { result.second = get(); // must not ignore 'N', because 'N' maybe the type - if (JSON_UNLIKELY(not unexpect_eof())) + if (JSON_UNLIKELY(not unexpect_eof(input_format_t::ubjson, "type"))) { return false; } @@ -7553,12 +7818,12 @@ class binary_reader get_ignore_noop(); if (JSON_UNLIKELY(current != '#')) { - if (JSON_UNLIKELY(not unexpect_eof())) + if (JSON_UNLIKELY(not unexpect_eof(input_format_t::ubjson, "value"))) { return false; } auto last_token = get_token_string(); - return sax->parse_error(chars_read, last_token, parse_error::create(112, chars_read, "expected '#' after UBJSON type information; last byte: 0x" + last_token)); + return sax->parse_error(chars_read, last_token, parse_error::create(112, chars_read, exception_message(input_format_t::ubjson, "expected '#' after type information; last byte: 0x" + last_token, "size"))); } return get_ubjson_size_value(result.first); @@ -7579,7 +7844,7 @@ class binary_reader switch (prefix) { case std::char_traits::eof(): // EOF - return unexpect_eof(); + return unexpect_eof(input_format_t::ubjson, "value"); case 'T': // true return sax->boolean(true); @@ -7592,56 +7857,56 @@ class binary_reader case 'U': { uint8_t number; - return get_number(number) and sax->number_unsigned(number); + return get_number(input_format_t::ubjson, number) and sax->number_unsigned(number); } case 'i': { int8_t number; - return get_number(number) and sax->number_integer(number); + return get_number(input_format_t::ubjson, number) and sax->number_integer(number); } case 'I': { int16_t number; - return get_number(number) and sax->number_integer(number); + return get_number(input_format_t::ubjson, number) and sax->number_integer(number); } case 'l': { int32_t number; - return get_number(number) and sax->number_integer(number); + return get_number(input_format_t::ubjson, number) and sax->number_integer(number); } case 'L': { int64_t number; - return get_number(number) and sax->number_integer(number); + return get_number(input_format_t::ubjson, number) and sax->number_integer(number); } case 'd': { float number; - return get_number(number) and sax->number_float(static_cast(number), ""); + return get_number(input_format_t::ubjson, number) and sax->number_float(static_cast(number), ""); } case 'D': { double number; - return get_number(number) and sax->number_float(static_cast(number), ""); + return get_number(input_format_t::ubjson, number) and sax->number_float(static_cast(number), ""); } case 'C': // char { get(); - if (JSON_UNLIKELY(not unexpect_eof())) + if (JSON_UNLIKELY(not unexpect_eof(input_format_t::ubjson, "char"))) { return false; } if (JSON_UNLIKELY(current > 127)) { auto last_token = get_token_string(); - return sax->parse_error(chars_read, last_token, parse_error::create(113, chars_read, "byte after 'C' must be in range 0x00..0x7F; last byte: 0x" + last_token)); + return sax->parse_error(chars_read, last_token, parse_error::create(113, chars_read, exception_message(input_format_t::ubjson, "byte after 'C' must be in range 0x00..0x7F; last byte: 0x" + last_token, "char"))); } string_t s(1, static_cast(current)); return sax->string(s); @@ -7662,7 +7927,7 @@ class binary_reader default: // anything else { auto last_token = get_token_string(); - return sax->parse_error(chars_read, last_token, parse_error::create(112, chars_read, "error reading UBJSON; last byte: 0x" + last_token)); + return sax->parse_error(chars_read, last_token, parse_error::create(112, chars_read, exception_message(input_format_t::ubjson, "invalid byte: 0x" + last_token, "value"))); } } } @@ -7805,13 +8070,16 @@ class binary_reader } /*! + @param[in] format the current format (for diagnostics) + @param[in] context further context information (for diagnostics) @return whether the last read character is not EOF */ - bool unexpect_eof() const + bool unexpect_eof(const input_format_t format, const char* context) const { if (JSON_UNLIKELY(current == std::char_traits::eof())) { - return sax->parse_error(chars_read, "", parse_error::create(110, chars_read, "unexpected end of input")); + return sax->parse_error(chars_read, "", + parse_error::create(110, chars_read, exception_message(format, "unexpected end of input", context))); } return true; } @@ -7827,6 +8095,45 @@ class binary_reader } private: + /*! + @param[in] format the current format + @param[in] detail a detailed error message + @param[in] context further contect information + @return a message string to use in the parse_error exceptions + */ + std::string exception_message(const input_format_t format, + const std::string& detail, + const std::string& context) const + { + std::string error_msg = "syntax error while parsing "; + + switch (format) + { + case input_format_t::cbor: + error_msg += "CBOR"; + break; + + case input_format_t::msgpack: + error_msg += "MessagePack"; + break; + + case input_format_t::ubjson: + error_msg += "UBJSON"; + break; + + case input_format_t::bson: + error_msg += "BSON"; + break; + + // LCOV_EXCL_START + default: + assert(false); + // LCOV_EXCL_STOP + } + + return error_msg + " " + context + ": " + detail; + } + /// input adapter input_adapter_t ia = nullptr; @@ -7842,8 +8149,8 @@ class binary_reader /// the SAX parser json_sax_t* sax = nullptr; }; -} -} +} // namespace detail +} // namespace nlohmann // #include @@ -8390,9 +8697,11 @@ class binary_writer case value_t::boolean: { if (add_prefix) + { oa->write_character(j.m_value.boolean ? static_cast('T') : static_cast('F')); + } break; } @@ -8925,7 +9234,7 @@ class binary_writer } else { - JSON_THROW(out_of_range::create(407, "number overflow serializing " + std::to_string(n))); + JSON_THROW(out_of_range::create(407, "integer number " + std::to_string(n) + " cannot be represented by UBJSON as it does not fit int64")); } } @@ -8979,7 +9288,7 @@ class binary_writer // LCOV_EXCL_START else { - JSON_THROW(out_of_range::create(407, "number overflow serializing " + std::to_string(n))); + JSON_THROW(out_of_range::create(407, "integer number " + std::to_string(n) + " cannot be represented by UBJSON as it does not fit int64")); } // LCOV_EXCL_STOP } @@ -9009,22 +9318,20 @@ class binary_writer { return 'i'; } - else if ((std::numeric_limits::min)() <= j.m_value.number_integer and j.m_value.number_integer <= (std::numeric_limits::max)()) + if ((std::numeric_limits::min)() <= j.m_value.number_integer and j.m_value.number_integer <= (std::numeric_limits::max)()) { return 'U'; } - else if ((std::numeric_limits::min)() <= j.m_value.number_integer and j.m_value.number_integer <= (std::numeric_limits::max)()) + if ((std::numeric_limits::min)() <= j.m_value.number_integer and j.m_value.number_integer <= (std::numeric_limits::max)()) { return 'I'; } - else if ((std::numeric_limits::min)() <= j.m_value.number_integer and j.m_value.number_integer <= (std::numeric_limits::max)()) + if ((std::numeric_limits::min)() <= j.m_value.number_integer and j.m_value.number_integer <= (std::numeric_limits::max)()) { return 'l'; } - else // no check and assume int64_t (see note above) - { - return 'L'; - } + // no check and assume int64_t (see note above) + return 'L'; } case value_t::number_unsigned: @@ -9033,22 +9340,20 @@ class binary_writer { return 'i'; } - else if (j.m_value.number_unsigned <= (std::numeric_limits::max)()) + if (j.m_value.number_unsigned <= (std::numeric_limits::max)()) { return 'U'; } - else if (j.m_value.number_unsigned <= (std::numeric_limits::max)()) + if (j.m_value.number_unsigned <= (std::numeric_limits::max)()) { return 'I'; } - else if (j.m_value.number_unsigned <= (std::numeric_limits::max)()) + if (j.m_value.number_unsigned <= (std::numeric_limits::max)()) { return 'l'; } - else // no check and assume int64_t (see note above) - { - return 'L'; - } + // no check and assume int64_t (see note above) + return 'L'; } case value_t::number_float: @@ -9068,32 +9373,32 @@ class binary_writer } } - static constexpr CharType get_cbor_float_prefix(float) + static constexpr CharType get_cbor_float_prefix(float /*unused*/) { return static_cast(0xFA); // Single-Precision Float } - static constexpr CharType get_cbor_float_prefix(double) + static constexpr CharType get_cbor_float_prefix(double /*unused*/) { return static_cast(0xFB); // Double-Precision Float } - static constexpr CharType get_msgpack_float_prefix(float) + static constexpr CharType get_msgpack_float_prefix(float /*unused*/) { return static_cast(0xCA); // float 32 } - static constexpr CharType get_msgpack_float_prefix(double) + static constexpr CharType get_msgpack_float_prefix(double /*unused*/) { return static_cast(0xCB); // float 64 } - static constexpr CharType get_ubjson_float_prefix(float) + static constexpr CharType get_ubjson_float_prefix(float /*unused*/) { return 'd'; // float 32 } - static constexpr CharType get_ubjson_float_prefix(double) + static constexpr CharType get_ubjson_float_prefix(double /*unused*/) { return 'D'; // float 64 } @@ -9105,8 +9410,8 @@ class binary_writer /// the output output_adapter_t oa = nullptr; }; -} -} +} // namespace detail +} // namespace nlohmann // #include @@ -9176,10 +9481,9 @@ struct diyfp // f * 2^e { static constexpr int kPrecision = 64; // = q - uint64_t f; - int e; + uint64_t f = 0; + int e = 0; - constexpr diyfp() noexcept : f(0), e(0) {} constexpr diyfp(uint64_t f_, int e_) noexcept : f(f_), e(e_) {} /*! @@ -9191,7 +9495,7 @@ struct diyfp // f * 2^e assert(x.e == y.e); assert(x.f >= y.f); - return diyfp(x.f - y.f, x.e); + return {x.f - y.f, x.e}; } /*! @@ -9256,7 +9560,7 @@ struct diyfp // f * 2^e const uint64_t h = p3 + p2_hi + p1_hi + (Q >> 32); - return diyfp(h, x.e + y.e + 64); + return {h, x.e + y.e + 64}; } /*! @@ -9287,7 +9591,7 @@ struct diyfp // f * 2^e assert(delta >= 0); assert(((x.f << delta) >> delta) == x.f); - return diyfp(x.f << delta, target_exponent); + return {x.f << delta, target_exponent}; } }; @@ -9590,7 +9894,7 @@ inline cached_power get_cached_power_for_binary_exponent(int e) assert(e >= -1500); assert(e <= 1500); const int f = kAlpha - e - 1; - const int k = (f * 78913) / (1 << 18) + (f > 0); + const int k = (f * 78913) / (1 << 18) + static_cast(f > 0); const int index = (-kCachedPowersMinDecExp + k + (kCachedPowersDecStep - 1)) / kCachedPowersDecStep; assert(index >= 0); @@ -9738,7 +10042,7 @@ inline void grisu2_digit_gen(char* buffer, int& length, int& decimal_exponent, const diyfp one(uint64_t{1} << -M_plus.e, M_plus.e); - uint32_t p1 = static_cast(M_plus.f >> -one.e); // p1 = f div 2^-e (Since -e >= 32, p1 fits into a 32-bit int.) + auto p1 = static_cast(M_plus.f >> -one.e); // p1 = f div 2^-e (Since -e >= 32, p1 fits into a 32-bit int.) uint64_t p2 = M_plus.f & (one.f - 1); // p2 = f mod 2^-e // 1) @@ -10057,7 +10361,7 @@ inline char* append_exponent(char* buf, int e) *buf++ = '+'; } - uint32_t k = static_cast(e); + auto k = static_cast(e); if (k < 10) { // Always print at least two digits in the exponent. @@ -10175,7 +10479,7 @@ format. Returns an iterator pointing past-the-end of the decimal representation. @note The result is NOT null-terminated. */ template -char* to_chars(char* first, char* last, FloatType value) +char* to_chars(char* first, const char* last, FloatType value) { static_cast(last); // maybe unused - fix warning assert(std::isfinite(value)); @@ -10265,6 +10569,9 @@ class serializer // delete because of pointer members serializer(const serializer&) = delete; serializer& operator=(const serializer&) = delete; + serializer(serializer&&) = delete; + serializer& operator=(serializer&&) = delete; + ~serializer() = default; /*! @brief internal implementation of the serialization function @@ -10654,7 +10961,7 @@ class serializer return; } - const bool is_negative = (x <= 0) and (x != 0); // see issue #755 + const bool is_negative = std::is_same::value and not (x >= 0); // see issue #755 std::size_t i = 0; while (x != 0) @@ -10839,8 +11146,8 @@ class serializer /// the indentation string string_t indent_string; }; -} -} +} // namespace detail +} // namespace nlohmann // #include @@ -10848,6 +11155,9 @@ class serializer #include #include +// #include + + namespace nlohmann { namespace detail @@ -10870,15 +11180,19 @@ class json_ref : owned_value(init), value_ref(&owned_value), is_rvalue(true) {} - template - json_ref(Args&& ... args) - : owned_value(std::forward(args)...), value_ref(&owned_value), is_rvalue(true) - {} + template < + class... Args, + enable_if_t::value, int> = 0 > + json_ref(Args && ... args) + : owned_value(std::forward(args)...), value_ref(&owned_value), + is_rvalue(true) {} // class should be movable only json_ref(json_ref&&) = default; json_ref(const json_ref&) = delete; json_ref& operator=(const json_ref&) = delete; + json_ref& operator=(json_ref&&) = delete; + ~json_ref() = default; value_type moved_or_copied() const { @@ -10904,8 +11218,8 @@ class json_ref value_type* value_ref = nullptr; const bool is_rvalue; }; -} -} +} // namespace detail +} // namespace nlohmann // #include @@ -11419,11 +11733,11 @@ class json_pointer std::size_t slash = reference_string.find_first_of('/', 1), // set the beginning of the first reference token start = 1; - // we can stop if start == string::npos+1 = 0 + // we can stop if start == 0 (if slash == std::string::npos) start != 0; // set the beginning of the next reference token // (will eventually be 0 if slash == std::string::npos) - start = slash + 1, + start = (slash == std::string::npos) ? 0 : slash + 1, // find next slash slash = reference_string.find_first_of('/', start)) { @@ -11606,7 +11920,7 @@ class json_pointer /// the reference tokens std::vector reference_tokens; }; -} +} // namespace nlohmann // #include @@ -11659,7 +11973,7 @@ struct adl_serializer ::nlohmann::to_json(j, std::forward(val)); } }; -} +} // namespace nlohmann /*! @@ -12539,7 +12853,7 @@ class basic_json object = nullptr; // silence warning, see #821 if (JSON_UNLIKELY(t == value_t::null)) { - JSON_THROW(other_error::create(500, "961c151d2e87f2686a955a9be24d316f1362bf21 3.2.0")); // LCOV_EXCL_LINE + JSON_THROW(other_error::create(500, "961c151d2e87f2686a955a9be24d316f1362bf21 3.3.0")); // LCOV_EXCL_LINE } break; } @@ -13458,7 +13772,7 @@ class basic_json @since version 1.0.0 */ - reference& operator=(basic_json other) noexcept ( + basic_json& operator=(basic_json other) noexcept ( std::is_nothrow_move_constructible::value and std::is_nothrow_move_assignable::value and std::is_nothrow_move_constructible::value and @@ -14216,51 +14530,50 @@ class basic_json } /*! - @brief get a pointer value (explicit) + @brief get a value (explicit) - Explicit pointer access to the internally stored JSON value. No copies are - made. + Explicit type conversion between the JSON value and a compatible value. + The value is filled into the input parameter by calling the @ref json_serializer + `from_json()` method. - @warning The pointer becomes invalid if the underlying JSON object - changes. + The function is equivalent to executing + @code {.cpp} + ValueType v; + JSONSerializer::from_json(*this, v); + @endcode - @tparam PointerType pointer type; must be a pointer to @ref array_t, @ref - object_t, @ref string_t, @ref boolean_t, @ref number_integer_t, - @ref number_unsigned_t, or @ref number_float_t. + This overloads is chosen if: + - @a ValueType is not @ref basic_json, + - @ref json_serializer has a `from_json()` method of the form + `void from_json(const basic_json&, ValueType&)`, and - @return pointer to the internally stored JSON value if the requested - pointer type @a PointerType fits to the JSON value; `nullptr` otherwise + @tparam ValueType the input parameter type. - @complexity Constant. + @return the input parameter, allowing chaining calls. - @liveexample{The example below shows how pointers to internal values of a - JSON value can be requested. Note that no type conversions are made and a - `nullptr` is returned if the value and the requested pointer type does not - match.,get__PointerType} + @throw what @ref json_serializer `from_json()` method throws - @sa @ref get_ptr() for explicit pointer-member access + @liveexample{The example below shows several conversions from JSON values + to other types. There a few things to note: (1) Floating-point numbers can + be converted to integers\, (2) A JSON array can be converted to a standard + `std::vector`\, (3) A JSON object can be converted to C++ + associative containers such as `std::unordered_map`.,get_to} - @since version 1.0.0 + @since version 3.3.0 */ - template::value, int>::type = 0> - PointerType get() noexcept + template::value and + detail::has_from_json::value, + int> = 0> + ValueType & get_to(ValueType& v) const noexcept(noexcept( + JSONSerializer::from_json(std::declval(), v))) { - // delegate the call to get_ptr - return get_ptr(); + JSONSerializer::from_json(*this, v); + return v; } - /*! - @brief get a pointer value (explicit) - @copydoc get() - */ - template::value, int>::type = 0> - constexpr const PointerType get() const noexcept - { - // delegate the call to get_ptr - return get_ptr(); - } /*! @brief get a pointer value (implicit) @@ -14290,23 +14603,8 @@ class basic_json */ template::value, int>::type = 0> - PointerType get_ptr() noexcept + auto get_ptr() noexcept -> decltype(std::declval().get_impl_ptr(std::declval())) { - // get the type of the PointerType (remove pointer and const) - using pointee_t = typename std::remove_const::type>::type>::type; - // make sure the type matches the allowed types - static_assert( - std::is_same::value - or std::is_same::value - or std::is_same::value - or std::is_same::value - or std::is_same::value - or std::is_same::value - or std::is_same::value - , "incompatible pointer type"); - // delegate the call to get_impl_ptr<>() return get_impl_ptr(static_cast(nullptr)); } @@ -14318,27 +14616,59 @@ class basic_json template::value and std::is_const::type>::value, int>::type = 0> - constexpr const PointerType get_ptr() const noexcept + constexpr auto get_ptr() const noexcept -> decltype(std::declval().get_impl_ptr(std::declval())) { - // get the type of the PointerType (remove pointer and const) - using pointee_t = typename std::remove_const::type>::type>::type; - // make sure the type matches the allowed types - static_assert( - std::is_same::value - or std::is_same::value - or std::is_same::value - or std::is_same::value - or std::is_same::value - or std::is_same::value - or std::is_same::value - , "incompatible pointer type"); - // delegate the call to get_impl_ptr<>() const return get_impl_ptr(static_cast(nullptr)); } + /*! + @brief get a pointer value (explicit) + + Explicit pointer access to the internally stored JSON value. No copies are + made. + + @warning The pointer becomes invalid if the underlying JSON object + changes. + + @tparam PointerType pointer type; must be a pointer to @ref array_t, @ref + object_t, @ref string_t, @ref boolean_t, @ref number_integer_t, + @ref number_unsigned_t, or @ref number_float_t. + + @return pointer to the internally stored JSON value if the requested + pointer type @a PointerType fits to the JSON value; `nullptr` otherwise + + @complexity Constant. + + @liveexample{The example below shows how pointers to internal values of a + JSON value can be requested. Note that no type conversions are made and a + `nullptr` is returned if the value and the requested pointer type does not + match.,get__PointerType} + + @sa @ref get_ptr() for explicit pointer-member access + + @since version 1.0.0 + */ + template::value, int>::type = 0> + auto get() noexcept -> decltype(std::declval().template get_ptr()) + { + // delegate the call to get_ptr + return get_ptr(); + } + + /*! + @brief get a pointer value (explicit) + @copydoc get() + */ + template::value, int>::type = 0> + constexpr auto get() const noexcept -> decltype(std::declval().template get_ptr()) + { + // delegate the call to get_ptr + return get_ptr(); + } + /*! @brief get a reference value (implicit) @@ -14420,12 +14750,14 @@ class basic_json not std::is_same>::value and not std::is_same::value and not detail::is_basic_json::value + #ifndef _MSC_VER // fix for issue #167 operator<< ambiguity under VS2015 and not std::is_same>::value #if defined(JSON_HAS_CPP_17) && defined(_MSC_VER) and _MSC_VER <= 1914 and not std::is_same::value #endif #endif + and detail::is_detected::value , int >::type = 0 > operator ValueType() const { @@ -14689,7 +15021,7 @@ class basic_json return m_value.array->operator[](idx); } - JSON_THROW(type_error::create(305, "cannot use operator[] with " + std::string(type_name()))); + JSON_THROW(type_error::create(305, "cannot use operator[] with a numeric argument with " + std::string(type_name()))); } /*! @@ -14719,7 +15051,7 @@ class basic_json return m_value.array->operator[](idx); } - JSON_THROW(type_error::create(305, "cannot use operator[] with " + std::string(type_name()))); + JSON_THROW(type_error::create(305, "cannot use operator[] with a numeric argument with " + std::string(type_name()))); } /*! @@ -14765,7 +15097,7 @@ class basic_json return m_value.object->operator[](key); } - JSON_THROW(type_error::create(305, "cannot use operator[] with " + std::string(type_name()))); + JSON_THROW(type_error::create(305, "cannot use operator[] with a string argument with " + std::string(type_name()))); } /*! @@ -14807,7 +15139,7 @@ class basic_json return m_value.object->find(key)->second; } - JSON_THROW(type_error::create(305, "cannot use operator[] with " + std::string(type_name()))); + JSON_THROW(type_error::create(305, "cannot use operator[] with a string argument with " + std::string(type_name()))); } /*! @@ -14854,7 +15186,7 @@ class basic_json return m_value.object->operator[](key); } - JSON_THROW(type_error::create(305, "cannot use operator[] with " + std::string(type_name()))); + JSON_THROW(type_error::create(305, "cannot use operator[] with a string argument with " + std::string(type_name()))); } /*! @@ -14897,7 +15229,7 @@ class basic_json return m_value.object->find(key)->second; } - JSON_THROW(type_error::create(305, "cannot use operator[] with " + std::string(type_name()))); + JSON_THROW(type_error::create(305, "cannot use operator[] with a string argument with " + std::string(type_name()))); } /*! @@ -16535,6 +16867,26 @@ class basic_json return {it, res.second}; } + /// Helper for insertion of an iterator + /// @note: This uses std::distance to support GCC 4.8, + /// see https://github.com/nlohmann/json/pull/1257 + template + iterator insert_iterator(const_iterator pos, Args&& ... args) + { + iterator result(this); + assert(m_value.array != nullptr); + + auto insert_pos = std::distance(m_value.array->begin(), pos.m_it.array_iterator); + m_value.array->insert(pos.m_it.array_iterator, std::forward(args)...); + result.m_it.array_iterator = m_value.array->begin() + insert_pos; + + // This could have been written as: + // result.m_it.array_iterator = m_value.array->insert(pos.m_it.array_iterator, cnt, val); + // but the return value of insert is missing in GCC 4.8, so it is written this way instead. + + return result; + } + /*! @brief inserts element @@ -16569,9 +16921,7 @@ class basic_json } // insert to array and return iterator - iterator result(this); - result.m_it.array_iterator = m_value.array->insert(pos.m_it.array_iterator, val); - return result; + return insert_iterator(pos, val); } JSON_THROW(type_error::create(309, "cannot use insert() with " + std::string(type_name()))); @@ -16622,9 +16972,7 @@ class basic_json } // insert to array and return iterator - iterator result(this); - result.m_it.array_iterator = m_value.array->insert(pos.m_it.array_iterator, cnt, val); - return result; + return insert_iterator(pos, cnt, val); } JSON_THROW(type_error::create(309, "cannot use insert() with " + std::string(type_name()))); @@ -16686,12 +17034,7 @@ class basic_json } // insert to array and return iterator - iterator result(this); - result.m_it.array_iterator = m_value.array->insert( - pos.m_it.array_iterator, - first.m_it.array_iterator, - last.m_it.array_iterator); - return result; + return insert_iterator(pos, first.m_it.array_iterator, last.m_it.array_iterator); } /*! @@ -16733,9 +17076,7 @@ class basic_json } // insert to array and return iterator - iterator result(this); - result.m_it.array_iterator = m_value.array->insert(pos.m_it.array_iterator, ilist.begin(), ilist.end()); - return result; + return insert_iterator(pos, ilist.begin(), ilist.end()); } /*! @@ -17564,6 +17905,8 @@ class basic_json @param[in] cb a parser callback function of type @ref parser_callback_t which is used to control the deserialization by filtering unwanted values (optional) + @param[in] allow_exceptions whether to throw exceptions in case of a + parse error (optional, true by default) @return result of the deserialization @@ -17959,7 +18302,7 @@ class basic_json vector in CBOR format.,to_cbor} @sa http://cbor.io - @sa @ref from_cbor(detail::input_adapter, const bool strict) for the + @sa @ref from_cbor(detail::input_adapter&&, const bool, const bool) for the analogous deserialization @sa @ref to_msgpack(const basic_json&) for the related MessagePack format @sa @ref to_ubjson(const basic_json&, const bool, const bool) for the @@ -18056,8 +18399,7 @@ class basic_json vector in MessagePack format.,to_msgpack} @sa http://msgpack.org - @sa @ref from_msgpack(const std::vector&, const size_t) for the - analogous deserialization + @sa @ref from_msgpack for the analogous deserialization @sa @ref to_cbor(const basic_json& for the related CBOR format @sa @ref to_ubjson(const basic_json&, const bool, const bool) for the related UBJSON format @@ -18154,7 +18496,7 @@ class basic_json vector in UBJSON format.,to_ubjson} @sa http://ubjson.org - @sa @ref from_ubjson(detail::input_adapter, const bool strict) for the + @sa @ref from_ubjson(detail::input_adapter&&, const bool, const bool) for the analogous deserialization @sa @ref to_cbor(const basic_json& for the related CBOR format @sa @ref to_msgpack(const basic_json&) for the related MessagePack format @@ -18350,14 +18692,14 @@ class basic_json @sa http://cbor.io @sa @ref to_cbor(const basic_json&) for the analogous serialization - @sa @ref from_msgpack(detail::input_adapter, const bool, const bool) for the + @sa @ref from_msgpack(detail::input_adapter&&, const bool, const bool) for the related MessagePack format - @sa @ref from_ubjson(detail::input_adapter, const bool, const bool) for the + @sa @ref from_ubjson(detail::input_adapter&&, const bool, const bool) for the related UBJSON format @since version 2.0.9; parameter @a start_index since 2.1.1; changed to consume input adapters, removed start_index parameter, and added - @a strict parameter since 3.0.0; added @allow_exceptions parameter + @a strict parameter since 3.0.0; added @a allow_exceptions parameter since 3.2.0 */ static basic_json from_cbor(detail::input_adapter&& i, @@ -18371,7 +18713,7 @@ class basic_json } /*! - @copydoc from_cbor(detail::input_adapter, const bool, const bool) + @copydoc from_cbor(detail::input_adapter&&, const bool, const bool) */ template::value, int> = 0> @@ -18453,16 +18795,16 @@ class basic_json @sa http://msgpack.org @sa @ref to_msgpack(const basic_json&) for the analogous serialization - @sa @ref from_cbor(detail::input_adapter, const bool, const bool) for the + @sa @ref from_cbor(detail::input_adapter&&, const bool, const bool) for the related CBOR format - @sa @ref from_ubjson(detail::input_adapter, const bool, const bool) for + @sa @ref from_ubjson(detail::input_adapter&&, const bool, const bool) for the related UBJSON format @sa @ref from_bson(detail::input_adapter, const bool, const bool) for the related BSON format @since version 2.0.9; parameter @a start_index since 2.1.1; changed to consume input adapters, removed start_index parameter, and added - @a strict parameter since 3.0.0; added @allow_exceptions parameter + @a strict parameter since 3.0.0; added @a allow_exceptions parameter since 3.2.0 */ static basic_json from_msgpack(detail::input_adapter&& i, @@ -18476,7 +18818,7 @@ class basic_json } /*! - @copydoc from_msgpack(detail::input_adapter, const bool, const bool) + @copydoc from_msgpack(detail::input_adapter&&, const bool, const bool) */ template::value, int> = 0> @@ -18540,14 +18882,14 @@ class basic_json @sa http://ubjson.org @sa @ref to_ubjson(const basic_json&, const bool, const bool) for the analogous serialization - @sa @ref from_cbor(detail::input_adapter, const bool, const bool) for the + @sa @ref from_cbor(detail::input_adapter&&, const bool, const bool) for the related CBOR format - @sa @ref from_msgpack(detail::input_adapter, const bool, const bool) for + @sa @ref from_msgpack(detail::input_adapter&&, const bool, const bool) for the related MessagePack format @sa @ref from_bson(detail::input_adapter, const bool, const bool) for the related BSON format - @since version 3.1.0; added @allow_exceptions parameter since 3.2.0 + @since version 3.1.0; added @a allow_exceptions parameter since 3.2.0 */ static basic_json from_ubjson(detail::input_adapter&& i, const bool strict = true, @@ -18560,7 +18902,7 @@ class basic_json } /*! - @copydoc from_ubjson(detail::input_adapter, const bool, const bool) + @copydoc from_ubjson(detail::input_adapter&&, const bool, const bool) */ template::value, int> = 0> @@ -19024,11 +19366,9 @@ class basic_json // avoid undefined behavior JSON_THROW(out_of_range::create(401, "array index " + std::to_string(idx) + " is out of range")); } - else - { - // default case: insert add offset - parent.insert(parent.begin() + static_cast(idx), val); - } + + // default case: insert add offset + parent.insert(parent.begin() + static_cast(idx), val); } break; } @@ -19453,19 +19793,6 @@ class basic_json // specialization of std::swap, and std::hash namespace std { -/*! -@brief exchanges the values of two JSON objects - -@since version 1.0.0 -*/ -template<> -inline void swap(nlohmann::json& j1, nlohmann::json& j2) noexcept( - is_nothrow_move_constructible::value and - is_nothrow_move_assignable::value -) -{ - j1.swap(j2); -} /// hash value for JSON objects template<> @@ -19501,6 +19828,20 @@ struct less< ::nlohmann::detail::value_t> } }; +/*! +@brief exchanges the values of two JSON objects + +@since version 1.0.0 +*/ +template<> +inline void swap(nlohmann::json& j1, nlohmann::json& j2) noexcept( + is_nothrow_move_constructible::value and + is_nothrow_move_assignable::value +) +{ + j1.swap(j2); +} + } // namespace std /*! diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index c0f40728..04acdaab 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -96,22 +96,21 @@ foreach(file ${files}) string(REGEX REPLACE "unit-([^$]+)" "test-\\1" testcase ${file_basename}) add_executable(${testcase} $ ${file}) - set_target_properties(${testcase} PROPERTIES - COMPILE_DEFINITIONS "$<$:_SCL_SECURE_NO_WARNINGS>" - COMPILE_OPTIONS "$<$:/EHsc;$<$:/Od>>" + target_compile_definitions(${testcase} PRIVATE + CATCH_CONFIG_FAST_COMPILE + $<$:_SCL_SECURE_NO_WARNINGS> + ) + target_compile_options(${testcase} PRIVATE + $<$:/EHsc;$<$:/Od>> + $<$>:-Wno-deprecated;-Wno-float-equal> + $<$:-Wno-deprecated-declarations> + ) + target_include_directories(${testcase} PRIVATE + thirdparty/catch + thirdparty/fifo_map ) - - target_compile_definitions(${testcase} PRIVATE CATCH_CONFIG_FAST_COMPILE) - target_compile_features(${testcase} PRIVATE cxx_std_11) - target_include_directories(${testcase} PRIVATE "thirdparty/catch") - target_include_directories(${testcase} PRIVATE "thirdparty/fifo_map") - target_include_directories(${testcase} PRIVATE ${NLOHMANN_JSON_INCLUDE_BUILD_DIR}) target_link_libraries(${testcase} ${NLOHMANN_JSON_TARGET_NAME}) - if(NOT MSVC) - set_target_properties(${testcase} PROPERTIES COMPILE_FLAGS "${CMAKE_CXX_FLAGS} -Wno-deprecated -Wno-float-equal") - endif() - add_test(NAME "${testcase}_default" COMMAND ${testcase} ${CATCH_TEST_FILTER} WORKING_DIRECTORY ${CMAKE_SOURCE_DIR} @@ -131,5 +130,11 @@ foreach(file ${files}) ) set_tests_properties("${testcase}_valgrind" PROPERTIES LABELS "valgrind") endif() - endforeach() + +############################################################################# +# Test the generated build configs +############################################################################# +add_subdirectory(cmake_import) +add_subdirectory(cmake_import_minver) +add_subdirectory(cmake_add_subdirectory) diff --git a/test/cmake_add_subdirectory/CMakeLists.txt b/test/cmake_add_subdirectory/CMakeLists.txt new file mode 100644 index 00000000..ad04547e --- /dev/null +++ b/test/cmake_add_subdirectory/CMakeLists.txt @@ -0,0 +1,15 @@ +add_test(NAME cmake_add_subdirectory_configure + COMMAND ${CMAKE_COMMAND} + -G "${CMAKE_GENERATOR}" + -Dnlohmann_json_source=${PROJECT_SOURCE_DIR} + ${CMAKE_CURRENT_SOURCE_DIR}/project +) +add_test(NAME cmake_add_subdirectory_build + COMMAND ${CMAKE_COMMAND} --build . +) +set_tests_properties(cmake_add_subdirectory_configure PROPERTIES + FIXTURES_SETUP cmake_add_subdirectory +) +set_tests_properties(cmake_add_subdirectory_build PROPERTIES + FIXTURES_REQUIRED cmake_add_subdirectory +) diff --git a/test/cmake_add_subdirectory/project/CMakeLists.txt b/test/cmake_add_subdirectory/project/CMakeLists.txt new file mode 100644 index 00000000..2c5be183 --- /dev/null +++ b/test/cmake_add_subdirectory/project/CMakeLists.txt @@ -0,0 +1,13 @@ +cmake_minimum_required(VERSION 3.8) + +project(DummyImport CXX) + +set(JSON_BuildTests OFF CACHE INTERNAL "") +add_subdirectory(${nlohmann_json_source} + ${CMAKE_CURRENT_BINARY_DIR}/nlohmann_json) + +add_executable(with_namespace_target main.cpp) +target_link_libraries(with_namespace_target nlohmann_json::nlohmann_json) + +add_executable(without_namespace_target main.cpp) +target_link_libraries(without_namespace_target nlohmann_json) diff --git a/test/cmake_add_subdirectory/project/main.cpp b/test/cmake_add_subdirectory/project/main.cpp new file mode 100644 index 00000000..d2d118b8 --- /dev/null +++ b/test/cmake_add_subdirectory/project/main.cpp @@ -0,0 +1,8 @@ +#include + +int main(int argc, char **argv) +{ + nlohmann::json j; + + return 0; +} diff --git a/test/cmake_import/CMakeLists.txt b/test/cmake_import/CMakeLists.txt new file mode 100644 index 00000000..911c342c --- /dev/null +++ b/test/cmake_import/CMakeLists.txt @@ -0,0 +1,15 @@ +add_test(NAME cmake_import_configure + COMMAND ${CMAKE_COMMAND} + -G "${CMAKE_GENERATOR}" + -Dnlohmann_json_DIR=${PROJECT_BINARY_DIR} + ${CMAKE_CURRENT_SOURCE_DIR}/project +) +add_test(NAME cmake_import_build + COMMAND ${CMAKE_COMMAND} --build . +) +set_tests_properties(cmake_import_configure PROPERTIES + FIXTURES_SETUP cmake_import +) +set_tests_properties(cmake_import_build PROPERTIES + FIXTURES_REQUIRED cmake_import +) diff --git a/test/cmake_import/project/CMakeLists.txt b/test/cmake_import/project/CMakeLists.txt new file mode 100644 index 00000000..d268d72c --- /dev/null +++ b/test/cmake_import/project/CMakeLists.txt @@ -0,0 +1,12 @@ +cmake_minimum_required(VERSION 3.8) + +project(DummyImport CXX) + +find_package(nlohmann_json REQUIRED) + +add_executable(with_namespace_target main.cpp) +target_link_libraries(with_namespace_target nlohmann_json::nlohmann_json) + +add_executable(without_namespace_target main.cpp) +target_link_libraries(without_namespace_target nlohmann_json) + diff --git a/test/cmake_import/project/main.cpp b/test/cmake_import/project/main.cpp new file mode 100644 index 00000000..d2d118b8 --- /dev/null +++ b/test/cmake_import/project/main.cpp @@ -0,0 +1,8 @@ +#include + +int main(int argc, char **argv) +{ + nlohmann::json j; + + return 0; +} diff --git a/test/cmake_import_minver/CMakeLists.txt b/test/cmake_import_minver/CMakeLists.txt new file mode 100644 index 00000000..8cef2fab --- /dev/null +++ b/test/cmake_import_minver/CMakeLists.txt @@ -0,0 +1,15 @@ +add_test(NAME cmake_import_minver_configure + COMMAND ${CMAKE_COMMAND} + -G "${CMAKE_GENERATOR}" + -Dnlohmann_json_DIR=${PROJECT_BINARY_DIR} + ${CMAKE_CURRENT_SOURCE_DIR}/project +) +add_test(NAME cmake_import_minver_build + COMMAND ${CMAKE_COMMAND} --build . +) +set_tests_properties(cmake_import_minver_configure PROPERTIES + FIXTURES_SETUP cmake_import_minver +) +set_tests_properties(cmake_import_minver_build PROPERTIES + FIXTURES_REQUIRED cmake_import_minver +) diff --git a/test/cmake_import_minver/project/CMakeLists.txt b/test/cmake_import_minver/project/CMakeLists.txt new file mode 100644 index 00000000..eeef3296 --- /dev/null +++ b/test/cmake_import_minver/project/CMakeLists.txt @@ -0,0 +1,8 @@ +cmake_minimum_required(VERSION 3.8) + +project(DummyImportMinVer CXX) + +find_package(nlohmann_json 3.2.0 REQUIRED) + +add_executable(with_namespace_target main.cpp) +target_link_libraries(with_namespace_target nlohmann_json::nlohmann_json) diff --git a/test/cmake_import_minver/project/main.cpp b/test/cmake_import_minver/project/main.cpp new file mode 100644 index 00000000..d2d118b8 --- /dev/null +++ b/test/cmake_import_minver/project/main.cpp @@ -0,0 +1,8 @@ +#include + +int main(int argc, char **argv) +{ + nlohmann::json j; + + return 0; +} diff --git a/test/src/fuzzer-driver_afl.cpp b/test/src/fuzzer-driver_afl.cpp index dd01b749..6c23f830 100644 --- a/test/src/fuzzer-driver_afl.cpp +++ b/test/src/fuzzer-driver_afl.cpp @@ -1,7 +1,7 @@ /* __ _____ _____ _____ __| | __| | | | JSON for Modern C++ (fuzz test support) -| | |__ | | | | | | version 3.2.0 +| | |__ | | | | | | version 3.3.0 |_____|_____|_____|_|___| https://github.com/nlohmann/json This file implements a driver for American Fuzzy Lop (afl-fuzz). It relies on diff --git a/test/src/fuzzer-parse_cbor.cpp b/test/src/fuzzer-parse_cbor.cpp index 20050eb7..6dd310b0 100644 --- a/test/src/fuzzer-parse_cbor.cpp +++ b/test/src/fuzzer-parse_cbor.cpp @@ -1,7 +1,7 @@ /* __ _____ _____ _____ __| | __| | | | JSON for Modern C++ (fuzz test support) -| | |__ | | | | | | version 3.2.0 +| | |__ | | | | | | version 3.3.0 |_____|_____|_____|_|___| https://github.com/nlohmann/json This file implements a parser test suitable for fuzz testing. Given a byte diff --git a/test/src/fuzzer-parse_json.cpp b/test/src/fuzzer-parse_json.cpp index d159a709..ed586385 100644 --- a/test/src/fuzzer-parse_json.cpp +++ b/test/src/fuzzer-parse_json.cpp @@ -1,7 +1,7 @@ /* __ _____ _____ _____ __| | __| | | | JSON for Modern C++ (fuzz test support) -| | |__ | | | | | | version 3.2.0 +| | |__ | | | | | | version 3.3.0 |_____|_____|_____|_|___| https://github.com/nlohmann/json This file implements a parser test suitable for fuzz testing. Given a byte diff --git a/test/src/fuzzer-parse_msgpack.cpp b/test/src/fuzzer-parse_msgpack.cpp index 0421e134..2ddf21ee 100644 --- a/test/src/fuzzer-parse_msgpack.cpp +++ b/test/src/fuzzer-parse_msgpack.cpp @@ -1,7 +1,7 @@ /* __ _____ _____ _____ __| | __| | | | JSON for Modern C++ (fuzz test support) -| | |__ | | | | | | version 3.2.0 +| | |__ | | | | | | version 3.3.0 |_____|_____|_____|_|___| https://github.com/nlohmann/json This file implements a parser test suitable for fuzz testing. Given a byte diff --git a/test/src/fuzzer-parse_ubjson.cpp b/test/src/fuzzer-parse_ubjson.cpp index d20f0fe2..a573e300 100644 --- a/test/src/fuzzer-parse_ubjson.cpp +++ b/test/src/fuzzer-parse_ubjson.cpp @@ -1,7 +1,7 @@ /* __ _____ _____ _____ __| | __| | | | JSON for Modern C++ (fuzz test support) -| | |__ | | | | | | version 3.2.0 +| | |__ | | | | | | version 3.3.0 |_____|_____|_____|_|___| https://github.com/nlohmann/json This file implements a parser test suitable for fuzz testing. Given a byte diff --git a/test/src/unit-algorithms.cpp b/test/src/unit-algorithms.cpp index c525ff11..59eb3de7 100644 --- a/test/src/unit-algorithms.cpp +++ b/test/src/unit-algorithms.cpp @@ -1,7 +1,7 @@ /* __ _____ _____ _____ __| | __| | | | JSON for Modern C++ (test suite) -| | |__ | | | | | | version 3.2.0 +| | |__ | | | | | | version 3.3.0 |_____|_____|_____|_|___| https://github.com/nlohmann/json Licensed under the MIT License . diff --git a/test/src/unit-allocator.cpp b/test/src/unit-allocator.cpp index 8cf5160f..20708a4c 100644 --- a/test/src/unit-allocator.cpp +++ b/test/src/unit-allocator.cpp @@ -1,7 +1,7 @@ /* __ _____ _____ _____ __| | __| | | | JSON for Modern C++ (test suite) -| | |__ | | | | | | version 3.2.0 +| | |__ | | | | | | version 3.3.0 |_____|_____|_____|_|___| https://github.com/nlohmann/json Licensed under the MIT License . diff --git a/test/src/unit-alt-string.cpp b/test/src/unit-alt-string.cpp index 356835c0..99d85678 100644 --- a/test/src/unit-alt-string.cpp +++ b/test/src/unit-alt-string.cpp @@ -1,7 +1,7 @@ /* __ _____ _____ _____ __| | __| | | | JSON for Modern C++ (test suite) -| | |__ | | | | | | version 3.2.0 +| | |__ | | | | | | version 3.3.0 |_____|_____|_____|_|___| https://github.com/nlohmann/json Licensed under the MIT License . diff --git a/test/src/unit-bson.cpp b/test/src/unit-bson.cpp index f622ff30..13dfd52c 100644 --- a/test/src/unit-bson.cpp +++ b/test/src/unit-bson.cpp @@ -679,7 +679,8 @@ TEST_CASE("Incomplete BSON INPUT") }; CHECK_THROWS_WITH(json::from_bson(incomplete_bson), - "[json.exception.parse_error.110] parse error at 9: unexpected end of input"); + "[json.exception.parse_error.110] parse error at byte 9: syntax error while parsing BSON cstring: unexpected end of input"); + CHECK(json::from_bson(incomplete_bson, true, false).is_discarded()); SaxCountdown scp(0); @@ -695,7 +696,7 @@ TEST_CASE("Incomplete BSON INPUT 2") }; CHECK_THROWS_WITH(json::from_bson(incomplete_bson), - "[json.exception.parse_error.110] parse error at 6: unexpected end of input"); + "[json.exception.parse_error.110] parse error at byte 6: syntax error while parsing BSON cstring: unexpected end of input"); CHECK(json::from_bson(incomplete_bson, true, false).is_discarded()); SaxCountdown scp(0); @@ -717,7 +718,7 @@ TEST_CASE("Incomplete BSON INPUT 3") // missing input data... }; CHECK_THROWS_WITH(json::from_bson(incomplete_bson), - "[json.exception.parse_error.110] parse error at 28: unexpected end of input"); + "[json.exception.parse_error.110] parse error at byte 28: syntax error while parsing BSON element list: unexpected end of input"); CHECK(json::from_bson(incomplete_bson, true, false).is_discarded()); SaxCountdown scp(1); @@ -734,7 +735,7 @@ TEST_CASE("Incomplete BSON INPUT 4") }; CHECK_THROWS_WITH(json::from_bson(incomplete_bson), - "[json.exception.parse_error.110] parse error at 3: unexpected end of input"); + "[json.exception.parse_error.110] parse error at byte 3: syntax error while parsing BSON number: unexpected end of input"); CHECK(json::from_bson(incomplete_bson, true, false).is_discarded()); SaxCountdown scp(0); @@ -753,7 +754,7 @@ TEST_CASE("Unsupported BSON input") }; CHECK_THROWS_WITH(json::from_bson(bson), - "[json.exception.parse_error.114] parse error at 5: Unsupported BSON record type 0xFF"); + "[json.exception.parse_error.114] parse error at byte 5: Unsupported BSON record type 0xFF"); CHECK(json::from_bson(bson, true, false).is_discarded()); SaxCountdown scp(0); diff --git a/test/src/unit-capacity.cpp b/test/src/unit-capacity.cpp index 718d102a..cd4f9538 100644 --- a/test/src/unit-capacity.cpp +++ b/test/src/unit-capacity.cpp @@ -1,7 +1,7 @@ /* __ _____ _____ _____ __| | __| | | | JSON for Modern C++ (test suite) -| | |__ | | | | | | version 3.2.0 +| | |__ | | | | | | version 3.3.0 |_____|_____|_____|_|___| https://github.com/nlohmann/json Licensed under the MIT License . diff --git a/test/src/unit-cbor.cpp b/test/src/unit-cbor.cpp index 525c7630..d7f52ed8 100644 --- a/test/src/unit-cbor.cpp +++ b/test/src/unit-cbor.cpp @@ -1,7 +1,7 @@ /* __ _____ _____ _____ __| | __| | | | JSON for Modern C++ (test suite) -| | |__ | | | | | | version 3.2.0 +| | |__ | | | | | | version 3.3.0 |_____|_____|_____|_|___| https://github.com/nlohmann/json Licensed under the MIT License . @@ -831,14 +831,14 @@ TEST_CASE("CBOR") { CHECK_THROWS_AS(json::from_cbor(std::vector({0xf9})), json::parse_error&); CHECK_THROWS_WITH(json::from_cbor(std::vector({0xf9})), - "[json.exception.parse_error.110] parse error at 2: unexpected end of input"); + "[json.exception.parse_error.110] parse error at byte 2: syntax error while parsing CBOR number: unexpected end of input"); CHECK(json::from_cbor(std::vector({0xf9}), true, false).is_discarded()); } SECTION("only one byte follows") { CHECK_THROWS_AS(json::from_cbor(std::vector({0xf9, 0x7c})), json::parse_error&); CHECK_THROWS_WITH(json::from_cbor(std::vector({0xf9, 0x7c})), - "[json.exception.parse_error.110] parse error at 3: unexpected end of input"); + "[json.exception.parse_error.110] parse error at byte 3: syntax error while parsing CBOR number: unexpected end of input"); CHECK(json::from_cbor(std::vector({0xf9, 0x7c}), true, false).is_discarded()); } } @@ -1314,7 +1314,7 @@ TEST_CASE("CBOR") { CHECK_THROWS_AS(json::from_cbor(std::vector()), json::parse_error&); CHECK_THROWS_WITH(json::from_cbor(std::vector()), - "[json.exception.parse_error.110] parse error at 1: unexpected end of input"); + "[json.exception.parse_error.110] parse error at byte 1: syntax error while parsing CBOR value: unexpected end of input"); CHECK(json::from_cbor(std::vector(), true, false).is_discarded()); } @@ -1346,53 +1346,53 @@ TEST_CASE("CBOR") CHECK_THROWS_AS(json::from_cbor(std::vector({0xBF, 0x61, 0X61})), json::parse_error&); CHECK_THROWS_WITH(json::from_cbor(std::vector({0x18})), - "[json.exception.parse_error.110] parse error at 2: unexpected end of input"); + "[json.exception.parse_error.110] parse error at byte 2: syntax error while parsing CBOR number: unexpected end of input"); CHECK_THROWS_WITH(json::from_cbor(std::vector({0x19})), - "[json.exception.parse_error.110] parse error at 2: unexpected end of input"); + "[json.exception.parse_error.110] parse error at byte 2: syntax error while parsing CBOR number: unexpected end of input"); CHECK_THROWS_WITH(json::from_cbor(std::vector({0x19, 0x00})), - "[json.exception.parse_error.110] parse error at 3: unexpected end of input"); + "[json.exception.parse_error.110] parse error at byte 3: syntax error while parsing CBOR number: unexpected end of input"); CHECK_THROWS_WITH(json::from_cbor(std::vector({0x1a})), - "[json.exception.parse_error.110] parse error at 2: unexpected end of input"); + "[json.exception.parse_error.110] parse error at byte 2: syntax error while parsing CBOR number: unexpected end of input"); CHECK_THROWS_WITH(json::from_cbor(std::vector({0x1a, 0x00})), - "[json.exception.parse_error.110] parse error at 3: unexpected end of input"); + "[json.exception.parse_error.110] parse error at byte 3: syntax error while parsing CBOR number: unexpected end of input"); CHECK_THROWS_WITH(json::from_cbor(std::vector({0x1a, 0x00, 0x00})), - "[json.exception.parse_error.110] parse error at 4: unexpected end of input"); + "[json.exception.parse_error.110] parse error at byte 4: syntax error while parsing CBOR number: unexpected end of input"); CHECK_THROWS_WITH(json::from_cbor(std::vector({0x1a, 0x00, 0x00, 0x00})), - "[json.exception.parse_error.110] parse error at 5: unexpected end of input"); + "[json.exception.parse_error.110] parse error at byte 5: syntax error while parsing CBOR number: unexpected end of input"); CHECK_THROWS_WITH(json::from_cbor(std::vector({0x1b})), - "[json.exception.parse_error.110] parse error at 2: unexpected end of input"); + "[json.exception.parse_error.110] parse error at byte 2: syntax error while parsing CBOR number: unexpected end of input"); CHECK_THROWS_WITH(json::from_cbor(std::vector({0x1b, 0x00})), - "[json.exception.parse_error.110] parse error at 3: unexpected end of input"); + "[json.exception.parse_error.110] parse error at byte 3: syntax error while parsing CBOR number: unexpected end of input"); CHECK_THROWS_WITH(json::from_cbor(std::vector({0x1b, 0x00, 0x00})), - "[json.exception.parse_error.110] parse error at 4: unexpected end of input"); + "[json.exception.parse_error.110] parse error at byte 4: syntax error while parsing CBOR number: unexpected end of input"); CHECK_THROWS_WITH(json::from_cbor(std::vector({0x1b, 0x00, 0x00, 0x00})), - "[json.exception.parse_error.110] parse error at 5: unexpected end of input"); + "[json.exception.parse_error.110] parse error at byte 5: syntax error while parsing CBOR number: unexpected end of input"); CHECK_THROWS_WITH(json::from_cbor(std::vector({0x1b, 0x00, 0x00, 0x00, 0x00})), - "[json.exception.parse_error.110] parse error at 6: unexpected end of input"); + "[json.exception.parse_error.110] parse error at byte 6: syntax error while parsing CBOR number: unexpected end of input"); CHECK_THROWS_WITH(json::from_cbor(std::vector({0x1b, 0x00, 0x00, 0x00, 0x00, 0x00})), - "[json.exception.parse_error.110] parse error at 7: unexpected end of input"); + "[json.exception.parse_error.110] parse error at byte 7: syntax error while parsing CBOR number: unexpected end of input"); CHECK_THROWS_WITH(json::from_cbor(std::vector({0x1b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00})), - "[json.exception.parse_error.110] parse error at 8: unexpected end of input"); + "[json.exception.parse_error.110] parse error at byte 8: syntax error while parsing CBOR number: unexpected end of input"); CHECK_THROWS_WITH(json::from_cbor(std::vector({0x1b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00})), - "[json.exception.parse_error.110] parse error at 9: unexpected end of input"); + "[json.exception.parse_error.110] parse error at byte 9: syntax error while parsing CBOR number: unexpected end of input"); CHECK_THROWS_WITH(json::from_cbor(std::vector({0x62})), - "[json.exception.parse_error.110] parse error at 2: unexpected end of input"); + "[json.exception.parse_error.110] parse error at byte 2: syntax error while parsing CBOR string: unexpected end of input"); CHECK_THROWS_WITH(json::from_cbor(std::vector({0x62, 0x60})), - "[json.exception.parse_error.110] parse error at 3: unexpected end of input"); + "[json.exception.parse_error.110] parse error at byte 3: syntax error while parsing CBOR string: unexpected end of input"); CHECK_THROWS_WITH(json::from_cbor(std::vector({0x7F})), - "[json.exception.parse_error.110] parse error at 2: unexpected end of input"); + "[json.exception.parse_error.110] parse error at byte 2: syntax error while parsing CBOR string: unexpected end of input"); CHECK_THROWS_WITH(json::from_cbor(std::vector({0x7F, 0x60})), - "[json.exception.parse_error.110] parse error at 3: unexpected end of input"); + "[json.exception.parse_error.110] parse error at byte 3: syntax error while parsing CBOR string: unexpected end of input"); CHECK_THROWS_WITH(json::from_cbor(std::vector({0x82, 0x01})), - "[json.exception.parse_error.110] parse error at 3: unexpected end of input"); + "[json.exception.parse_error.110] parse error at byte 3: syntax error while parsing CBOR value: unexpected end of input"); CHECK_THROWS_WITH(json::from_cbor(std::vector({0x9F, 0x01})), - "[json.exception.parse_error.110] parse error at 3: unexpected end of input"); + "[json.exception.parse_error.110] parse error at byte 3: syntax error while parsing CBOR value: unexpected end of input"); CHECK_THROWS_WITH(json::from_cbor(std::vector({0xBF, 0x61, 0x61, 0xF5})), - "[json.exception.parse_error.110] parse error at 5: unexpected end of input"); + "[json.exception.parse_error.110] parse error at byte 5: syntax error while parsing CBOR string: unexpected end of input"); CHECK_THROWS_WITH(json::from_cbor(std::vector({0xA1, 0x61, 0x61})), - "[json.exception.parse_error.110] parse error at 4: unexpected end of input"); + "[json.exception.parse_error.110] parse error at byte 4: syntax error while parsing CBOR value: unexpected end of input"); CHECK_THROWS_WITH(json::from_cbor(std::vector({0xBF, 0x61, 0x61})), - "[json.exception.parse_error.110] parse error at 4: unexpected end of input"); + "[json.exception.parse_error.110] parse error at byte 4: syntax error while parsing CBOR value: unexpected end of input"); CHECK(json::from_cbor(std::vector({0x18}), true, false).is_discarded()); CHECK(json::from_cbor(std::vector({0x19}), true, false).is_discarded()); @@ -1426,12 +1426,12 @@ TEST_CASE("CBOR") { CHECK_THROWS_AS(json::from_cbor(std::vector({0x1c})), json::parse_error&); CHECK_THROWS_WITH(json::from_cbor(std::vector({0x1c})), - "[json.exception.parse_error.112] parse error at 1: error reading CBOR; last byte: 0x1C"); + "[json.exception.parse_error.112] parse error at byte 1: syntax error while parsing CBOR value: invalid byte: 0x1C"); CHECK(json::from_cbor(std::vector({0x1c}), true, false).is_discarded()); CHECK_THROWS_AS(json::from_cbor(std::vector({0xf8})), json::parse_error&); CHECK_THROWS_WITH(json::from_cbor(std::vector({0xf8})), - "[json.exception.parse_error.112] parse error at 1: error reading CBOR; last byte: 0xF8"); + "[json.exception.parse_error.112] parse error at byte 1: syntax error while parsing CBOR value: invalid byte: 0xF8"); CHECK(json::from_cbor(std::vector({0xf8}), true, false).is_discarded()); } @@ -1491,7 +1491,7 @@ TEST_CASE("CBOR") { CHECK_THROWS_AS(json::from_cbor(std::vector({0xa1, 0xff, 0x01})), json::parse_error&); CHECK_THROWS_WITH(json::from_cbor(std::vector({0xa1, 0xff, 0x01})), - "[json.exception.parse_error.113] parse error at 2: expected a CBOR string; last byte: 0xFF"); + "[json.exception.parse_error.113] parse error at byte 2: syntax error while parsing CBOR string: expected length specification (0x60-0x7B) or indefinite string type (0x7F); last byte: 0xFF"); CHECK(json::from_cbor(std::vector({0xa1, 0xff, 0x01}), true, false).is_discarded()); } @@ -1509,7 +1509,7 @@ TEST_CASE("CBOR") { CHECK_THROWS_AS(json::from_cbor(vec), json::parse_error&); CHECK_THROWS_WITH(json::from_cbor(vec), - "[json.exception.parse_error.110] parse error at 2: expected end of input"); + "[json.exception.parse_error.110] parse error at byte 2: syntax error while parsing CBOR value: expected end of input; last byte: 0xF6"); CHECK(json::from_cbor(vec, true, false).is_discarded()); } } diff --git a/test/src/unit-class_const_iterator.cpp b/test/src/unit-class_const_iterator.cpp index 783eb048..ea039cdc 100644 --- a/test/src/unit-class_const_iterator.cpp +++ b/test/src/unit-class_const_iterator.cpp @@ -1,7 +1,7 @@ /* __ _____ _____ _____ __| | __| | | | JSON for Modern C++ (test suite) -| | |__ | | | | | | version 3.2.0 +| | |__ | | | | | | version 3.3.0 |_____|_____|_____|_|___| https://github.com/nlohmann/json Licensed under the MIT License . diff --git a/test/src/unit-class_iterator.cpp b/test/src/unit-class_iterator.cpp index e8d530f7..459e0e1e 100644 --- a/test/src/unit-class_iterator.cpp +++ b/test/src/unit-class_iterator.cpp @@ -1,7 +1,7 @@ /* __ _____ _____ _____ __| | __| | | | JSON for Modern C++ (test suite) -| | |__ | | | | | | version 3.2.0 +| | |__ | | | | | | version 3.3.0 |_____|_____|_____|_|___| https://github.com/nlohmann/json Licensed under the MIT License . diff --git a/test/src/unit-class_lexer.cpp b/test/src/unit-class_lexer.cpp index 65859ad5..01aee242 100644 --- a/test/src/unit-class_lexer.cpp +++ b/test/src/unit-class_lexer.cpp @@ -1,7 +1,7 @@ /* __ _____ _____ _____ __| | __| | | | JSON for Modern C++ (test suite) -| | |__ | | | | | | version 3.2.0 +| | |__ | | | | | | version 3.3.0 |_____|_____|_____|_|___| https://github.com/nlohmann/json Licensed under the MIT License . diff --git a/test/src/unit-class_parser.cpp b/test/src/unit-class_parser.cpp index f9115f51..8d0b68d2 100644 --- a/test/src/unit-class_parser.cpp +++ b/test/src/unit-class_parser.cpp @@ -1,7 +1,7 @@ /* __ _____ _____ _____ __| | __| | | | JSON for Modern C++ (test suite) -| | |__ | | | | | | version 3.2.0 +| | |__ | | | | | | version 3.3.0 |_____|_____|_____|_|___| https://github.com/nlohmann/json Licensed under the MIT License . @@ -313,18 +313,18 @@ TEST_CASE("parser class") // error: tab in string CHECK_THROWS_AS(parser_helper("\"\t\""), json::parse_error&); CHECK_THROWS_WITH(parser_helper("\"\t\""), - "[json.exception.parse_error.101] parse error at 2: syntax error - invalid string: control character must be escaped; last read: '\"'"); + "[json.exception.parse_error.101] parse error at line 1, column 2: syntax error while parsing value - invalid string: control character U+0009 (HT) must be escaped to \\u0009 or \\t; last read: '\"'"); // error: newline in string CHECK_THROWS_AS(parser_helper("\"\n\""), json::parse_error&); CHECK_THROWS_AS(parser_helper("\"\r\""), json::parse_error&); CHECK_THROWS_WITH(parser_helper("\"\n\""), - "[json.exception.parse_error.101] parse error at 2: syntax error - invalid string: control character must be escaped; last read: '\"'"); + "[json.exception.parse_error.101] parse error at line 2, column 0: syntax error while parsing value - invalid string: control character U+000A (LF) must be escaped to \\u000A or \\n; last read: '\"'"); CHECK_THROWS_WITH(parser_helper("\"\r\""), - "[json.exception.parse_error.101] parse error at 2: syntax error - invalid string: control character must be escaped; last read: '\"'"); + "[json.exception.parse_error.101] parse error at line 1, column 2: syntax error while parsing value - invalid string: control character U+000D (CR) must be escaped to \\u000D or \\r; last read: '\"'"); // error: backspace in string CHECK_THROWS_AS(parser_helper("\"\b\""), json::parse_error&); CHECK_THROWS_WITH(parser_helper("\"\b\""), - "[json.exception.parse_error.101] parse error at 2: syntax error - invalid string: control character must be escaped; last read: '\"'"); + "[json.exception.parse_error.101] parse error at line 1, column 2: syntax error while parsing value - invalid string: control character U+0008 (BS) must be escaped to \\u0008 or \\b; last read: '\"'"); // improve code coverage CHECK_THROWS_AS(parser_helper("\uFF01"), json::parse_error&); CHECK_THROWS_AS(parser_helper("[-4:1,]"), json::parse_error&); @@ -361,38 +361,38 @@ TEST_CASE("parser class") CHECK_THROWS_AS(parser_helper("\"\x1d\""), json::parse_error&); CHECK_THROWS_AS(parser_helper("\"\x1e\""), json::parse_error&); CHECK_THROWS_AS(parser_helper("\"\x1f\""), json::parse_error&); - CHECK_THROWS_WITH(parser_helper("\"\x00\""), "[json.exception.parse_error.101] parse error at 2: syntax error - invalid string: missing closing quote; last read: '\"'"); - CHECK_THROWS_WITH(parser_helper("\"\x01\""), "[json.exception.parse_error.101] parse error at 2: syntax error - invalid string: control character must be escaped; last read: '\"'"); - CHECK_THROWS_WITH(parser_helper("\"\x02\""), "[json.exception.parse_error.101] parse error at 2: syntax error - invalid string: control character must be escaped; last read: '\"'"); - CHECK_THROWS_WITH(parser_helper("\"\x03\""), "[json.exception.parse_error.101] parse error at 2: syntax error - invalid string: control character must be escaped; last read: '\"'"); - CHECK_THROWS_WITH(parser_helper("\"\x04\""), "[json.exception.parse_error.101] parse error at 2: syntax error - invalid string: control character must be escaped; last read: '\"'"); - CHECK_THROWS_WITH(parser_helper("\"\x05\""), "[json.exception.parse_error.101] parse error at 2: syntax error - invalid string: control character must be escaped; last read: '\"'"); - CHECK_THROWS_WITH(parser_helper("\"\x06\""), "[json.exception.parse_error.101] parse error at 2: syntax error - invalid string: control character must be escaped; last read: '\"'"); - CHECK_THROWS_WITH(parser_helper("\"\x07\""), "[json.exception.parse_error.101] parse error at 2: syntax error - invalid string: control character must be escaped; last read: '\"'"); - CHECK_THROWS_WITH(parser_helper("\"\x08\""), "[json.exception.parse_error.101] parse error at 2: syntax error - invalid string: control character must be escaped; last read: '\"'"); - CHECK_THROWS_WITH(parser_helper("\"\x09\""), "[json.exception.parse_error.101] parse error at 2: syntax error - invalid string: control character must be escaped; last read: '\"'"); - CHECK_THROWS_WITH(parser_helper("\"\x0a\""), "[json.exception.parse_error.101] parse error at 2: syntax error - invalid string: control character must be escaped; last read: '\"'"); - CHECK_THROWS_WITH(parser_helper("\"\x0b\""), "[json.exception.parse_error.101] parse error at 2: syntax error - invalid string: control character must be escaped; last read: '\"'"); - CHECK_THROWS_WITH(parser_helper("\"\x0c\""), "[json.exception.parse_error.101] parse error at 2: syntax error - invalid string: control character must be escaped; last read: '\"'"); - CHECK_THROWS_WITH(parser_helper("\"\x0d\""), "[json.exception.parse_error.101] parse error at 2: syntax error - invalid string: control character must be escaped; last read: '\"'"); - CHECK_THROWS_WITH(parser_helper("\"\x0e\""), "[json.exception.parse_error.101] parse error at 2: syntax error - invalid string: control character must be escaped; last read: '\"'"); - CHECK_THROWS_WITH(parser_helper("\"\x0f\""), "[json.exception.parse_error.101] parse error at 2: syntax error - invalid string: control character must be escaped; last read: '\"'"); - CHECK_THROWS_WITH(parser_helper("\"\x10\""), "[json.exception.parse_error.101] parse error at 2: syntax error - invalid string: control character must be escaped; last read: '\"'"); - CHECK_THROWS_WITH(parser_helper("\"\x11\""), "[json.exception.parse_error.101] parse error at 2: syntax error - invalid string: control character must be escaped; last read: '\"'"); - CHECK_THROWS_WITH(parser_helper("\"\x12\""), "[json.exception.parse_error.101] parse error at 2: syntax error - invalid string: control character must be escaped; last read: '\"'"); - CHECK_THROWS_WITH(parser_helper("\"\x13\""), "[json.exception.parse_error.101] parse error at 2: syntax error - invalid string: control character must be escaped; last read: '\"'"); - CHECK_THROWS_WITH(parser_helper("\"\x14\""), "[json.exception.parse_error.101] parse error at 2: syntax error - invalid string: control character must be escaped; last read: '\"'"); - CHECK_THROWS_WITH(parser_helper("\"\x15\""), "[json.exception.parse_error.101] parse error at 2: syntax error - invalid string: control character must be escaped; last read: '\"'"); - CHECK_THROWS_WITH(parser_helper("\"\x16\""), "[json.exception.parse_error.101] parse error at 2: syntax error - invalid string: control character must be escaped; last read: '\"'"); - CHECK_THROWS_WITH(parser_helper("\"\x17\""), "[json.exception.parse_error.101] parse error at 2: syntax error - invalid string: control character must be escaped; last read: '\"'"); - CHECK_THROWS_WITH(parser_helper("\"\x18\""), "[json.exception.parse_error.101] parse error at 2: syntax error - invalid string: control character must be escaped; last read: '\"'"); - CHECK_THROWS_WITH(parser_helper("\"\x19\""), "[json.exception.parse_error.101] parse error at 2: syntax error - invalid string: control character must be escaped; last read: '\"'"); - CHECK_THROWS_WITH(parser_helper("\"\x1a\""), "[json.exception.parse_error.101] parse error at 2: syntax error - invalid string: control character must be escaped; last read: '\"'"); - CHECK_THROWS_WITH(parser_helper("\"\x1b\""), "[json.exception.parse_error.101] parse error at 2: syntax error - invalid string: control character must be escaped; last read: '\"'"); - CHECK_THROWS_WITH(parser_helper("\"\x1c\""), "[json.exception.parse_error.101] parse error at 2: syntax error - invalid string: control character must be escaped; last read: '\"'"); - CHECK_THROWS_WITH(parser_helper("\"\x1d\""), "[json.exception.parse_error.101] parse error at 2: syntax error - invalid string: control character must be escaped; last read: '\"'"); - CHECK_THROWS_WITH(parser_helper("\"\x1e\""), "[json.exception.parse_error.101] parse error at 2: syntax error - invalid string: control character must be escaped; last read: '\"'"); - CHECK_THROWS_WITH(parser_helper("\"\x1f\""), "[json.exception.parse_error.101] parse error at 2: syntax error - invalid string: control character must be escaped; last read: '\"'"); + CHECK_THROWS_WITH(parser_helper("\"\x00\""), "[json.exception.parse_error.101] parse error at line 1, column 2: syntax error while parsing value - invalid string: missing closing quote; last read: '\"'"); + CHECK_THROWS_WITH(parser_helper("\"\x01\""), "[json.exception.parse_error.101] parse error at line 1, column 2: syntax error while parsing value - invalid string: control character U+0001 (SOH) must be escaped to \\u0001; last read: '\"'"); + CHECK_THROWS_WITH(parser_helper("\"\x02\""), "[json.exception.parse_error.101] parse error at line 1, column 2: syntax error while parsing value - invalid string: control character U+0002 (STX) must be escaped to \\u0002; last read: '\"'"); + CHECK_THROWS_WITH(parser_helper("\"\x03\""), "[json.exception.parse_error.101] parse error at line 1, column 2: syntax error while parsing value - invalid string: control character U+0003 (ETX) must be escaped to \\u0003; last read: '\"'"); + CHECK_THROWS_WITH(parser_helper("\"\x04\""), "[json.exception.parse_error.101] parse error at line 1, column 2: syntax error while parsing value - invalid string: control character U+0004 (EOT) must be escaped to \\u0004; last read: '\"'"); + CHECK_THROWS_WITH(parser_helper("\"\x05\""), "[json.exception.parse_error.101] parse error at line 1, column 2: syntax error while parsing value - invalid string: control character U+0005 (ENQ) must be escaped to \\u0005; last read: '\"'"); + CHECK_THROWS_WITH(parser_helper("\"\x06\""), "[json.exception.parse_error.101] parse error at line 1, column 2: syntax error while parsing value - invalid string: control character U+0006 (ACK) must be escaped to \\u0006; last read: '\"'"); + CHECK_THROWS_WITH(parser_helper("\"\x07\""), "[json.exception.parse_error.101] parse error at line 1, column 2: syntax error while parsing value - invalid string: control character U+0007 (BEL) must be escaped to \\u0007; last read: '\"'"); + CHECK_THROWS_WITH(parser_helper("\"\x08\""), "[json.exception.parse_error.101] parse error at line 1, column 2: syntax error while parsing value - invalid string: control character U+0008 (BS) must be escaped to \\u0008 or \\b; last read: '\"'"); + CHECK_THROWS_WITH(parser_helper("\"\x09\""), "[json.exception.parse_error.101] parse error at line 1, column 2: syntax error while parsing value - invalid string: control character U+0009 (HT) must be escaped to \\u0009 or \\t; last read: '\"'"); + CHECK_THROWS_WITH(parser_helper("\"\x0a\""), "[json.exception.parse_error.101] parse error at line 2, column 0: syntax error while parsing value - invalid string: control character U+000A (LF) must be escaped to \\u000A or \\n; last read: '\"'"); + CHECK_THROWS_WITH(parser_helper("\"\x0b\""), "[json.exception.parse_error.101] parse error at line 1, column 2: syntax error while parsing value - invalid string: control character U+000B (VT) must be escaped to \\u000B; last read: '\"'"); + CHECK_THROWS_WITH(parser_helper("\"\x0c\""), "[json.exception.parse_error.101] parse error at line 1, column 2: syntax error while parsing value - invalid string: control character U+000C (FF) must be escaped to \\u000C or \\f; last read: '\"'"); + CHECK_THROWS_WITH(parser_helper("\"\x0d\""), "[json.exception.parse_error.101] parse error at line 1, column 2: syntax error while parsing value - invalid string: control character U+000D (CR) must be escaped to \\u000D or \\r; last read: '\"'"); + CHECK_THROWS_WITH(parser_helper("\"\x0e\""), "[json.exception.parse_error.101] parse error at line 1, column 2: syntax error while parsing value - invalid string: control character U+000E (SO) must be escaped to \\u000E; last read: '\"'"); + CHECK_THROWS_WITH(parser_helper("\"\x0f\""), "[json.exception.parse_error.101] parse error at line 1, column 2: syntax error while parsing value - invalid string: control character U+000F (SI) must be escaped to \\u000F; last read: '\"'"); + CHECK_THROWS_WITH(parser_helper("\"\x10\""), "[json.exception.parse_error.101] parse error at line 1, column 2: syntax error while parsing value - invalid string: control character U+0010 (DLE) must be escaped to \\u0010; last read: '\"'"); + CHECK_THROWS_WITH(parser_helper("\"\x11\""), "[json.exception.parse_error.101] parse error at line 1, column 2: syntax error while parsing value - invalid string: control character U+0011 (DC1) must be escaped to \\u0011; last read: '\"'"); + CHECK_THROWS_WITH(parser_helper("\"\x12\""), "[json.exception.parse_error.101] parse error at line 1, column 2: syntax error while parsing value - invalid string: control character U+0012 (DC2) must be escaped to \\u0012; last read: '\"'"); + CHECK_THROWS_WITH(parser_helper("\"\x13\""), "[json.exception.parse_error.101] parse error at line 1, column 2: syntax error while parsing value - invalid string: control character U+0013 (DC3) must be escaped to \\u0013; last read: '\"'"); + CHECK_THROWS_WITH(parser_helper("\"\x14\""), "[json.exception.parse_error.101] parse error at line 1, column 2: syntax error while parsing value - invalid string: control character U+0014 (DC4) must be escaped to \\u0014; last read: '\"'"); + CHECK_THROWS_WITH(parser_helper("\"\x15\""), "[json.exception.parse_error.101] parse error at line 1, column 2: syntax error while parsing value - invalid string: control character U+0015 (NAK) must be escaped to \\u0015; last read: '\"'"); + CHECK_THROWS_WITH(parser_helper("\"\x16\""), "[json.exception.parse_error.101] parse error at line 1, column 2: syntax error while parsing value - invalid string: control character U+0016 (SYN) must be escaped to \\u0016; last read: '\"'"); + CHECK_THROWS_WITH(parser_helper("\"\x17\""), "[json.exception.parse_error.101] parse error at line 1, column 2: syntax error while parsing value - invalid string: control character U+0017 (ETB) must be escaped to \\u0017; last read: '\"'"); + CHECK_THROWS_WITH(parser_helper("\"\x18\""), "[json.exception.parse_error.101] parse error at line 1, column 2: syntax error while parsing value - invalid string: control character U+0018 (CAN) must be escaped to \\u0018; last read: '\"'"); + CHECK_THROWS_WITH(parser_helper("\"\x19\""), "[json.exception.parse_error.101] parse error at line 1, column 2: syntax error while parsing value - invalid string: control character U+0019 (EM) must be escaped to \\u0019; last read: '\"'"); + CHECK_THROWS_WITH(parser_helper("\"\x1a\""), "[json.exception.parse_error.101] parse error at line 1, column 2: syntax error while parsing value - invalid string: control character U+001A (SUB) must be escaped to \\u001A; last read: '\"'"); + CHECK_THROWS_WITH(parser_helper("\"\x1b\""), "[json.exception.parse_error.101] parse error at line 1, column 2: syntax error while parsing value - invalid string: control character U+001B (ESC) must be escaped to \\u001B; last read: '\"'"); + CHECK_THROWS_WITH(parser_helper("\"\x1c\""), "[json.exception.parse_error.101] parse error at line 1, column 2: syntax error while parsing value - invalid string: control character U+001C (FS) must be escaped to \\u001C; last read: '\"'"); + CHECK_THROWS_WITH(parser_helper("\"\x1d\""), "[json.exception.parse_error.101] parse error at line 1, column 2: syntax error while parsing value - invalid string: control character U+001D (GS) must be escaped to \\u001D; last read: '\"'"); + CHECK_THROWS_WITH(parser_helper("\"\x1e\""), "[json.exception.parse_error.101] parse error at line 1, column 2: syntax error while parsing value - invalid string: control character U+001E (RS) must be escaped to \\u001E; last read: '\"'"); + CHECK_THROWS_WITH(parser_helper("\"\x1f\""), "[json.exception.parse_error.101] parse error at line 1, column 2: syntax error while parsing value - invalid string: control character U+001F (US) must be escaped to \\u001F; last read: '\"'"); SECTION("additional test for null byte") { @@ -403,7 +403,7 @@ TEST_CASE("parser class") std::string s = "\"1\""; s[1] = '\0'; CHECK_THROWS_AS(json::parse(s.begin(), s.end()), json::parse_error&); - CHECK_THROWS_WITH(json::parse(s.begin(), s.end()), "[json.exception.parse_error.101] parse error at 2: syntax error - invalid string: control character must be escaped; last read: '\"'"); + CHECK_THROWS_WITH(json::parse(s.begin(), s.end()), "[json.exception.parse_error.101] parse error at line 1, column 2: syntax error while parsing value - invalid string: control character U+0000 (NUL) must be escaped to \\u0000; last read: '\"'"); } } @@ -603,39 +603,39 @@ TEST_CASE("parser class") CHECK_THROWS_AS(parser_helper("+0"), json::parse_error&); CHECK_THROWS_WITH(parser_helper("01"), - "[json.exception.parse_error.101] parse error at 2: syntax error - unexpected number literal; expected end of input"); + "[json.exception.parse_error.101] parse error at line 1, column 2: syntax error while parsing value - unexpected number literal; expected end of input"); CHECK_THROWS_WITH(parser_helper("-01"), - "[json.exception.parse_error.101] parse error at 3: syntax error - unexpected number literal; expected end of input"); + "[json.exception.parse_error.101] parse error at line 1, column 3: syntax error while parsing value - unexpected number literal; expected end of input"); CHECK_THROWS_WITH(parser_helper("--1"), - "[json.exception.parse_error.101] parse error at 2: syntax error - invalid number; expected digit after '-'; last read: '--'"); + "[json.exception.parse_error.101] parse error at line 1, column 2: syntax error while parsing value - invalid number; expected digit after '-'; last read: '--'"); CHECK_THROWS_WITH(parser_helper("1."), - "[json.exception.parse_error.101] parse error at 3: syntax error - invalid number; expected digit after '.'; last read: '1.'"); + "[json.exception.parse_error.101] parse error at line 1, column 3: syntax error while parsing value - invalid number; expected digit after '.'; last read: '1.'"); CHECK_THROWS_WITH(parser_helper("1E"), - "[json.exception.parse_error.101] parse error at 3: syntax error - invalid number; expected '+', '-', or digit after exponent; last read: '1E'"); + "[json.exception.parse_error.101] parse error at line 1, column 3: syntax error while parsing value - invalid number; expected '+', '-', or digit after exponent; last read: '1E'"); CHECK_THROWS_WITH(parser_helper("1E-"), - "[json.exception.parse_error.101] parse error at 4: syntax error - invalid number; expected digit after exponent sign; last read: '1E-'"); + "[json.exception.parse_error.101] parse error at line 1, column 4: syntax error while parsing value - invalid number; expected digit after exponent sign; last read: '1E-'"); CHECK_THROWS_WITH(parser_helper("1.E1"), - "[json.exception.parse_error.101] parse error at 3: syntax error - invalid number; expected digit after '.'; last read: '1.E'"); + "[json.exception.parse_error.101] parse error at line 1, column 3: syntax error while parsing value - invalid number; expected digit after '.'; last read: '1.E'"); CHECK_THROWS_WITH(parser_helper("-1E"), - "[json.exception.parse_error.101] parse error at 4: syntax error - invalid number; expected '+', '-', or digit after exponent; last read: '-1E'"); + "[json.exception.parse_error.101] parse error at line 1, column 4: syntax error while parsing value - invalid number; expected '+', '-', or digit after exponent; last read: '-1E'"); CHECK_THROWS_WITH(parser_helper("-0E#"), - "[json.exception.parse_error.101] parse error at 4: syntax error - invalid number; expected '+', '-', or digit after exponent; last read: '-0E#'"); + "[json.exception.parse_error.101] parse error at line 1, column 4: syntax error while parsing value - invalid number; expected '+', '-', or digit after exponent; last read: '-0E#'"); CHECK_THROWS_WITH(parser_helper("-0E-#"), - "[json.exception.parse_error.101] parse error at 5: syntax error - invalid number; expected digit after exponent sign; last read: '-0E-#'"); + "[json.exception.parse_error.101] parse error at line 1, column 5: syntax error while parsing value - invalid number; expected digit after exponent sign; last read: '-0E-#'"); CHECK_THROWS_WITH(parser_helper("-0#"), - "[json.exception.parse_error.101] parse error at 3: syntax error - invalid literal; last read: '-0#'; expected end of input"); + "[json.exception.parse_error.101] parse error at line 1, column 3: syntax error while parsing value - invalid literal; last read: '-0#'; expected end of input"); CHECK_THROWS_WITH(parser_helper("-0.0:"), - "[json.exception.parse_error.101] parse error at 5: syntax error - unexpected ':'; expected end of input"); + "[json.exception.parse_error.101] parse error at line 1, column 5: syntax error while parsing value - unexpected ':'; expected end of input"); CHECK_THROWS_WITH(parser_helper("-0.0Z"), - "[json.exception.parse_error.101] parse error at 5: syntax error - invalid literal; last read: '-0.0Z'; expected end of input"); + "[json.exception.parse_error.101] parse error at line 1, column 5: syntax error while parsing value - invalid literal; last read: '-0.0Z'; expected end of input"); CHECK_THROWS_WITH(parser_helper("-0E123:"), - "[json.exception.parse_error.101] parse error at 7: syntax error - unexpected ':'; expected end of input"); + "[json.exception.parse_error.101] parse error at line 1, column 7: syntax error while parsing value - unexpected ':'; expected end of input"); CHECK_THROWS_WITH(parser_helper("-0e0-:"), - "[json.exception.parse_error.101] parse error at 6: syntax error - invalid number; expected digit after '-'; last read: '-:'; expected end of input"); + "[json.exception.parse_error.101] parse error at line 1, column 6: syntax error while parsing value - invalid number; expected digit after '-'; last read: '-:'; expected end of input"); CHECK_THROWS_WITH(parser_helper("-0e-:"), - "[json.exception.parse_error.101] parse error at 5: syntax error - invalid number; expected digit after exponent sign; last read: '-0e-:'"); + "[json.exception.parse_error.101] parse error at line 1, column 5: syntax error while parsing value - invalid number; expected digit after exponent sign; last read: '-0e-:'"); CHECK_THROWS_WITH(parser_helper("-0f"), - "[json.exception.parse_error.101] parse error at 4: syntax error - invalid literal; last read: '-0f'; expected end of input"); + "[json.exception.parse_error.101] parse error at line 1, column 4: syntax error while parsing value - invalid literal; last read: '-0f'; expected end of input"); } } } @@ -920,33 +920,33 @@ TEST_CASE("parser class") CHECK_THROWS_AS(parser_helper("1E/"), json::parse_error&); CHECK_THROWS_AS(parser_helper("1E:"), json::parse_error&); CHECK_THROWS_WITH(parser_helper("0."), - "[json.exception.parse_error.101] parse error at 3: syntax error - invalid number; expected digit after '.'; last read: '0.'"); + "[json.exception.parse_error.101] parse error at line 1, column 3: syntax error while parsing value - invalid number; expected digit after '.'; last read: '0.'"); CHECK_THROWS_WITH(parser_helper("-"), - "[json.exception.parse_error.101] parse error at 2: syntax error - invalid number; expected digit after '-'; last read: '-'"); + "[json.exception.parse_error.101] parse error at line 1, column 2: syntax error while parsing value - invalid number; expected digit after '-'; last read: '-'"); CHECK_THROWS_WITH(parser_helper("--"), - "[json.exception.parse_error.101] parse error at 2: syntax error - invalid number; expected digit after '-'; last read: '--'"); + "[json.exception.parse_error.101] parse error at line 1, column 2: syntax error while parsing value - invalid number; expected digit after '-'; last read: '--'"); CHECK_THROWS_WITH(parser_helper("-0."), - "[json.exception.parse_error.101] parse error at 4: syntax error - invalid number; expected digit after '.'; last read: '-0.'"); + "[json.exception.parse_error.101] parse error at line 1, column 4: syntax error while parsing value - invalid number; expected digit after '.'; last read: '-0.'"); CHECK_THROWS_WITH(parser_helper("-."), - "[json.exception.parse_error.101] parse error at 2: syntax error - invalid number; expected digit after '-'; last read: '-.'"); + "[json.exception.parse_error.101] parse error at line 1, column 2: syntax error while parsing value - invalid number; expected digit after '-'; last read: '-.'"); CHECK_THROWS_WITH(parser_helper("-:"), - "[json.exception.parse_error.101] parse error at 2: syntax error - invalid number; expected digit after '-'; last read: '-:'"); + "[json.exception.parse_error.101] parse error at line 1, column 2: syntax error while parsing value - invalid number; expected digit after '-'; last read: '-:'"); CHECK_THROWS_WITH(parser_helper("0.:"), - "[json.exception.parse_error.101] parse error at 3: syntax error - invalid number; expected digit after '.'; last read: '0.:'"); + "[json.exception.parse_error.101] parse error at line 1, column 3: syntax error while parsing value - invalid number; expected digit after '.'; last read: '0.:'"); CHECK_THROWS_WITH(parser_helper("e."), - "[json.exception.parse_error.101] parse error at 1: syntax error - invalid literal; last read: 'e'"); + "[json.exception.parse_error.101] parse error at line 1, column 1: syntax error while parsing value - invalid literal; last read: 'e'"); CHECK_THROWS_WITH(parser_helper("1e."), - "[json.exception.parse_error.101] parse error at 3: syntax error - invalid number; expected '+', '-', or digit after exponent; last read: '1e.'"); + "[json.exception.parse_error.101] parse error at line 1, column 3: syntax error while parsing value - invalid number; expected '+', '-', or digit after exponent; last read: '1e.'"); CHECK_THROWS_WITH(parser_helper("1e/"), - "[json.exception.parse_error.101] parse error at 3: syntax error - invalid number; expected '+', '-', or digit after exponent; last read: '1e/'"); + "[json.exception.parse_error.101] parse error at line 1, column 3: syntax error while parsing value - invalid number; expected '+', '-', or digit after exponent; last read: '1e/'"); CHECK_THROWS_WITH(parser_helper("1e:"), - "[json.exception.parse_error.101] parse error at 3: syntax error - invalid number; expected '+', '-', or digit after exponent; last read: '1e:'"); + "[json.exception.parse_error.101] parse error at line 1, column 3: syntax error while parsing value - invalid number; expected '+', '-', or digit after exponent; last read: '1e:'"); CHECK_THROWS_WITH(parser_helper("1E."), - "[json.exception.parse_error.101] parse error at 3: syntax error - invalid number; expected '+', '-', or digit after exponent; last read: '1E.'"); + "[json.exception.parse_error.101] parse error at line 1, column 3: syntax error while parsing value - invalid number; expected '+', '-', or digit after exponent; last read: '1E.'"); CHECK_THROWS_WITH(parser_helper("1E/"), - "[json.exception.parse_error.101] parse error at 3: syntax error - invalid number; expected '+', '-', or digit after exponent; last read: '1E/'"); + "[json.exception.parse_error.101] parse error at line 1, column 3: syntax error while parsing value - invalid number; expected '+', '-', or digit after exponent; last read: '1E/'"); CHECK_THROWS_WITH(parser_helper("1E:"), - "[json.exception.parse_error.101] parse error at 3: syntax error - invalid number; expected '+', '-', or digit after exponent; last read: '1E:'"); + "[json.exception.parse_error.101] parse error at line 1, column 3: syntax error while parsing value - invalid number; expected '+', '-', or digit after exponent; last read: '1E:'"); // unexpected end of null CHECK_THROWS_AS(parser_helper("n"), json::parse_error&); @@ -955,15 +955,15 @@ TEST_CASE("parser class") CHECK_THROWS_AS(parser_helper("nulk"), json::parse_error&); CHECK_THROWS_AS(parser_helper("nulm"), json::parse_error&); CHECK_THROWS_WITH(parser_helper("n"), - "[json.exception.parse_error.101] parse error at 2: syntax error - invalid literal; last read: 'n'"); + "[json.exception.parse_error.101] parse error at line 1, column 2: syntax error while parsing value - invalid literal; last read: 'n'"); CHECK_THROWS_WITH(parser_helper("nu"), - "[json.exception.parse_error.101] parse error at 3: syntax error - invalid literal; last read: 'nu'"); + "[json.exception.parse_error.101] parse error at line 1, column 3: syntax error while parsing value - invalid literal; last read: 'nu'"); CHECK_THROWS_WITH(parser_helper("nul"), - "[json.exception.parse_error.101] parse error at 4: syntax error - invalid literal; last read: 'nul'"); + "[json.exception.parse_error.101] parse error at line 1, column 4: syntax error while parsing value - invalid literal; last read: 'nul'"); CHECK_THROWS_WITH(parser_helper("nulk"), - "[json.exception.parse_error.101] parse error at 4: syntax error - invalid literal; last read: 'nulk'"); + "[json.exception.parse_error.101] parse error at line 1, column 4: syntax error while parsing value - invalid literal; last read: 'nulk'"); CHECK_THROWS_WITH(parser_helper("nulm"), - "[json.exception.parse_error.101] parse error at 4: syntax error - invalid literal; last read: 'nulm'"); + "[json.exception.parse_error.101] parse error at line 1, column 4: syntax error while parsing value - invalid literal; last read: 'nulm'"); // unexpected end of true CHECK_THROWS_AS(parser_helper("t"), json::parse_error&); @@ -972,15 +972,15 @@ TEST_CASE("parser class") CHECK_THROWS_AS(parser_helper("trud"), json::parse_error&); CHECK_THROWS_AS(parser_helper("truf"), json::parse_error&); CHECK_THROWS_WITH(parser_helper("t"), - "[json.exception.parse_error.101] parse error at 2: syntax error - invalid literal; last read: 't'"); + "[json.exception.parse_error.101] parse error at line 1, column 2: syntax error while parsing value - invalid literal; last read: 't'"); CHECK_THROWS_WITH(parser_helper("tr"), - "[json.exception.parse_error.101] parse error at 3: syntax error - invalid literal; last read: 'tr'"); + "[json.exception.parse_error.101] parse error at line 1, column 3: syntax error while parsing value - invalid literal; last read: 'tr'"); CHECK_THROWS_WITH(parser_helper("tru"), - "[json.exception.parse_error.101] parse error at 4: syntax error - invalid literal; last read: 'tru'"); + "[json.exception.parse_error.101] parse error at line 1, column 4: syntax error while parsing value - invalid literal; last read: 'tru'"); CHECK_THROWS_WITH(parser_helper("trud"), - "[json.exception.parse_error.101] parse error at 4: syntax error - invalid literal; last read: 'trud'"); + "[json.exception.parse_error.101] parse error at line 1, column 4: syntax error while parsing value - invalid literal; last read: 'trud'"); CHECK_THROWS_WITH(parser_helper("truf"), - "[json.exception.parse_error.101] parse error at 4: syntax error - invalid literal; last read: 'truf'"); + "[json.exception.parse_error.101] parse error at line 1, column 4: syntax error while parsing value - invalid literal; last read: 'truf'"); // unexpected end of false CHECK_THROWS_AS(parser_helper("f"), json::parse_error&); @@ -990,17 +990,17 @@ TEST_CASE("parser class") CHECK_THROWS_AS(parser_helper("falsd"), json::parse_error&); CHECK_THROWS_AS(parser_helper("falsf"), json::parse_error&); CHECK_THROWS_WITH(parser_helper("f"), - "[json.exception.parse_error.101] parse error at 2: syntax error - invalid literal; last read: 'f'"); + "[json.exception.parse_error.101] parse error at line 1, column 2: syntax error while parsing value - invalid literal; last read: 'f'"); CHECK_THROWS_WITH(parser_helper("fa"), - "[json.exception.parse_error.101] parse error at 3: syntax error - invalid literal; last read: 'fa'"); + "[json.exception.parse_error.101] parse error at line 1, column 3: syntax error while parsing value - invalid literal; last read: 'fa'"); CHECK_THROWS_WITH(parser_helper("fal"), - "[json.exception.parse_error.101] parse error at 4: syntax error - invalid literal; last read: 'fal'"); + "[json.exception.parse_error.101] parse error at line 1, column 4: syntax error while parsing value - invalid literal; last read: 'fal'"); CHECK_THROWS_WITH(parser_helper("fals"), - "[json.exception.parse_error.101] parse error at 5: syntax error - invalid literal; last read: 'fals'"); + "[json.exception.parse_error.101] parse error at line 1, column 5: syntax error while parsing value - invalid literal; last read: 'fals'"); CHECK_THROWS_WITH(parser_helper("falsd"), - "[json.exception.parse_error.101] parse error at 5: syntax error - invalid literal; last read: 'falsd'"); + "[json.exception.parse_error.101] parse error at line 1, column 5: syntax error while parsing value - invalid literal; last read: 'falsd'"); CHECK_THROWS_WITH(parser_helper("falsf"), - "[json.exception.parse_error.101] parse error at 5: syntax error - invalid literal; last read: 'falsf'"); + "[json.exception.parse_error.101] parse error at line 1, column 5: syntax error while parsing value - invalid literal; last read: 'falsf'"); // missing/unexpected end of array CHECK_THROWS_AS(parser_helper("["), json::parse_error&); @@ -1009,15 +1009,15 @@ TEST_CASE("parser class") CHECK_THROWS_AS(parser_helper("[1,]"), json::parse_error&); CHECK_THROWS_AS(parser_helper("]"), json::parse_error&); CHECK_THROWS_WITH(parser_helper("["), - "[json.exception.parse_error.101] parse error at 2: syntax error - unexpected end of input; expected '[', '{', or a literal"); + "[json.exception.parse_error.101] parse error at line 1, column 2: syntax error while parsing value - unexpected end of input; expected '[', '{', or a literal"); CHECK_THROWS_WITH(parser_helper("[1"), - "[json.exception.parse_error.101] parse error at 3: syntax error - unexpected end of input; expected ']'"); + "[json.exception.parse_error.101] parse error at line 1, column 3: syntax error while parsing array - unexpected end of input; expected ']'"); CHECK_THROWS_WITH(parser_helper("[1,"), - "[json.exception.parse_error.101] parse error at 4: syntax error - unexpected end of input; expected '[', '{', or a literal"); + "[json.exception.parse_error.101] parse error at line 1, column 4: syntax error while parsing value - unexpected end of input; expected '[', '{', or a literal"); CHECK_THROWS_WITH(parser_helper("[1,]"), - "[json.exception.parse_error.101] parse error at 4: syntax error - unexpected ']'; expected '[', '{', or a literal"); + "[json.exception.parse_error.101] parse error at line 1, column 4: syntax error while parsing value - unexpected ']'; expected '[', '{', or a literal"); CHECK_THROWS_WITH(parser_helper("]"), - "[json.exception.parse_error.101] parse error at 1: syntax error - unexpected ']'; expected '[', '{', or a literal"); + "[json.exception.parse_error.101] parse error at line 1, column 1: syntax error while parsing value - unexpected ']'; expected '[', '{', or a literal"); // missing/unexpected end of object CHECK_THROWS_AS(parser_helper("{"), json::parse_error&); @@ -1027,17 +1027,17 @@ TEST_CASE("parser class") CHECK_THROWS_AS(parser_helper("{\"foo\":1,}"), json::parse_error&); CHECK_THROWS_AS(parser_helper("}"), json::parse_error&); CHECK_THROWS_WITH(parser_helper("{"), - "[json.exception.parse_error.101] parse error at 2: syntax error - unexpected end of input; expected string literal"); + "[json.exception.parse_error.101] parse error at line 1, column 2: syntax error while parsing object key - unexpected end of input; expected string literal"); CHECK_THROWS_WITH(parser_helper("{\"foo\""), - "[json.exception.parse_error.101] parse error at 7: syntax error - unexpected end of input; expected ':'"); + "[json.exception.parse_error.101] parse error at line 1, column 7: syntax error while parsing object separator - unexpected end of input; expected ':'"); CHECK_THROWS_WITH(parser_helper("{\"foo\":"), - "[json.exception.parse_error.101] parse error at 8: syntax error - unexpected end of input; expected '[', '{', or a literal"); + "[json.exception.parse_error.101] parse error at line 1, column 8: syntax error while parsing value - unexpected end of input; expected '[', '{', or a literal"); CHECK_THROWS_WITH(parser_helper("{\"foo\":}"), - "[json.exception.parse_error.101] parse error at 8: syntax error - unexpected '}'; expected '[', '{', or a literal"); + "[json.exception.parse_error.101] parse error at line 1, column 8: syntax error while parsing value - unexpected '}'; expected '[', '{', or a literal"); CHECK_THROWS_WITH(parser_helper("{\"foo\":1,}"), - "[json.exception.parse_error.101] parse error at 10: syntax error - unexpected '}'; expected string literal"); + "[json.exception.parse_error.101] parse error at line 1, column 10: syntax error while parsing object key - unexpected '}'; expected string literal"); CHECK_THROWS_WITH(parser_helper("}"), - "[json.exception.parse_error.101] parse error at 1: syntax error - unexpected '}'; expected '[', '{', or a literal"); + "[json.exception.parse_error.101] parse error at line 1, column 1: syntax error while parsing value - unexpected '}'; expected '[', '{', or a literal"); // missing/unexpected end of string CHECK_THROWS_AS(parser_helper("\""), json::parse_error&); @@ -1051,25 +1051,25 @@ TEST_CASE("parser class") CHECK_THROWS_AS(parser_helper("\"\\u01"), json::parse_error&); CHECK_THROWS_AS(parser_helper("\"\\u012"), json::parse_error&); CHECK_THROWS_WITH(parser_helper("\""), - "[json.exception.parse_error.101] parse error at 2: syntax error - invalid string: missing closing quote; last read: '\"'"); + "[json.exception.parse_error.101] parse error at line 1, column 2: syntax error while parsing value - invalid string: missing closing quote; last read: '\"'"); CHECK_THROWS_WITH(parser_helper("\"\\\""), - "[json.exception.parse_error.101] parse error at 4: syntax error - invalid string: missing closing quote; last read: '\"\\\"'"); + "[json.exception.parse_error.101] parse error at line 1, column 4: syntax error while parsing value - invalid string: missing closing quote; last read: '\"\\\"'"); CHECK_THROWS_WITH(parser_helper("\"\\u\""), - "[json.exception.parse_error.101] parse error at 4: syntax error - invalid string: '\\u' must be followed by 4 hex digits; last read: '\"\\u\"'"); + "[json.exception.parse_error.101] parse error at line 1, column 4: syntax error while parsing value - invalid string: '\\u' must be followed by 4 hex digits; last read: '\"\\u\"'"); CHECK_THROWS_WITH(parser_helper("\"\\u0\""), - "[json.exception.parse_error.101] parse error at 5: syntax error - invalid string: '\\u' must be followed by 4 hex digits; last read: '\"\\u0\"'"); + "[json.exception.parse_error.101] parse error at line 1, column 5: syntax error while parsing value - invalid string: '\\u' must be followed by 4 hex digits; last read: '\"\\u0\"'"); CHECK_THROWS_WITH(parser_helper("\"\\u01\""), - "[json.exception.parse_error.101] parse error at 6: syntax error - invalid string: '\\u' must be followed by 4 hex digits; last read: '\"\\u01\"'"); + "[json.exception.parse_error.101] parse error at line 1, column 6: syntax error while parsing value - invalid string: '\\u' must be followed by 4 hex digits; last read: '\"\\u01\"'"); CHECK_THROWS_WITH(parser_helper("\"\\u012\""), - "[json.exception.parse_error.101] parse error at 7: syntax error - invalid string: '\\u' must be followed by 4 hex digits; last read: '\"\\u012\"'"); + "[json.exception.parse_error.101] parse error at line 1, column 7: syntax error while parsing value - invalid string: '\\u' must be followed by 4 hex digits; last read: '\"\\u012\"'"); CHECK_THROWS_WITH(parser_helper("\"\\u"), - "[json.exception.parse_error.101] parse error at 4: syntax error - invalid string: '\\u' must be followed by 4 hex digits; last read: '\"\\u'"); + "[json.exception.parse_error.101] parse error at line 1, column 4: syntax error while parsing value - invalid string: '\\u' must be followed by 4 hex digits; last read: '\"\\u'"); CHECK_THROWS_WITH(parser_helper("\"\\u0"), - "[json.exception.parse_error.101] parse error at 5: syntax error - invalid string: '\\u' must be followed by 4 hex digits; last read: '\"\\u0'"); + "[json.exception.parse_error.101] parse error at line 1, column 5: syntax error while parsing value - invalid string: '\\u' must be followed by 4 hex digits; last read: '\"\\u0'"); CHECK_THROWS_WITH(parser_helper("\"\\u01"), - "[json.exception.parse_error.101] parse error at 6: syntax error - invalid string: '\\u' must be followed by 4 hex digits; last read: '\"\\u01'"); + "[json.exception.parse_error.101] parse error at line 1, column 6: syntax error while parsing value - invalid string: '\\u' must be followed by 4 hex digits; last read: '\"\\u01'"); CHECK_THROWS_WITH(parser_helper("\"\\u012"), - "[json.exception.parse_error.101] parse error at 7: syntax error - invalid string: '\\u' must be followed by 4 hex digits; last read: '\"\\u012'"); + "[json.exception.parse_error.101] parse error at line 1, column 7: syntax error while parsing value - invalid string: '\\u' must be followed by 4 hex digits; last read: '\"\\u012'"); // invalid escapes for (int c = 1; c < 128; ++c) @@ -1106,7 +1106,7 @@ TEST_CASE("parser class") if (c > 0x1f) { CHECK_THROWS_WITH(parser_helper(s.c_str()), - "[json.exception.parse_error.101] parse error at 3: syntax error - invalid string: forbidden character after backslash; last read: '\"\\" + std::string(1, static_cast(c)) + "'"); + "[json.exception.parse_error.101] parse error at line 1, column 3: syntax error while parsing value - invalid string: forbidden character after backslash; last read: '\"\\" + std::string(1, static_cast(c)) + "'"); } break; } @@ -1182,7 +1182,7 @@ TEST_CASE("parser class") if (c > 0x1f) { CHECK_THROWS_WITH(parser_helper(s1.c_str()), - "[json.exception.parse_error.101] parse error at 7: syntax error - invalid string: '\\u' must be followed by 4 hex digits; last read: '" + s1.substr(0, 7) + "'"); + "[json.exception.parse_error.101] parse error at line 1, column 7: syntax error while parsing value - invalid string: '\\u' must be followed by 4 hex digits; last read: '" + s1.substr(0, 7) + "'"); } CAPTURE(s2); @@ -1191,7 +1191,7 @@ TEST_CASE("parser class") if (c > 0x1f) { CHECK_THROWS_WITH(parser_helper(s2.c_str()), - "[json.exception.parse_error.101] parse error at 6: syntax error - invalid string: '\\u' must be followed by 4 hex digits; last read: '" + s2.substr(0, 6) + "'"); + "[json.exception.parse_error.101] parse error at line 1, column 6: syntax error while parsing value - invalid string: '\\u' must be followed by 4 hex digits; last read: '" + s2.substr(0, 6) + "'"); } CAPTURE(s3); @@ -1200,7 +1200,7 @@ TEST_CASE("parser class") if (c > 0x1f) { CHECK_THROWS_WITH(parser_helper(s3.c_str()), - "[json.exception.parse_error.101] parse error at 5: syntax error - invalid string: '\\u' must be followed by 4 hex digits; last read: '" + s3.substr(0, 5) + "'"); + "[json.exception.parse_error.101] parse error at line 1, column 5: syntax error while parsing value - invalid string: '\\u' must be followed by 4 hex digits; last read: '" + s3.substr(0, 5) + "'"); } CAPTURE(s4); @@ -1209,7 +1209,7 @@ TEST_CASE("parser class") if (c > 0x1f) { CHECK_THROWS_WITH(parser_helper(s4.c_str()), - "[json.exception.parse_error.101] parse error at 4: syntax error - invalid string: '\\u' must be followed by 4 hex digits; last read: '" + s4.substr(0, 4) + "'"); + "[json.exception.parse_error.101] parse error at line 1, column 4: syntax error while parsing value - invalid string: '\\u' must be followed by 4 hex digits; last read: '" + s4.substr(0, 4) + "'"); } } } @@ -1218,17 +1218,17 @@ TEST_CASE("parser class") // missing part of a surrogate pair CHECK_THROWS_AS(json::parse("\"\\uD80C\""), json::parse_error&); CHECK_THROWS_WITH(json::parse("\"\\uD80C\""), - "[json.exception.parse_error.101] parse error at 8: syntax error - invalid string: surrogate U+DC00..U+DFFF must be followed by U+DC00..U+DFFF; last read: '\"\\uD80C\"'"); + "[json.exception.parse_error.101] parse error at line 1, column 8: syntax error while parsing value - invalid string: surrogate U+DC00..U+DFFF must be followed by U+DC00..U+DFFF; last read: '\"\\uD80C\"'"); // invalid surrogate pair CHECK_THROWS_AS(json::parse("\"\\uD80C\\uD80C\""), json::parse_error&); CHECK_THROWS_AS(json::parse("\"\\uD80C\\u0000\""), json::parse_error&); CHECK_THROWS_AS(json::parse("\"\\uD80C\\uFFFF\""), json::parse_error&); CHECK_THROWS_WITH(json::parse("\"\\uD80C\\uD80C\""), - "[json.exception.parse_error.101] parse error at 13: syntax error - invalid string: surrogate U+DC00..U+DFFF must be followed by U+DC00..U+DFFF; last read: '\"\\uD80C\\uD80C'"); + "[json.exception.parse_error.101] parse error at line 1, column 13: syntax error while parsing value - invalid string: surrogate U+DC00..U+DFFF must be followed by U+DC00..U+DFFF; last read: '\"\\uD80C\\uD80C'"); CHECK_THROWS_WITH(json::parse("\"\\uD80C\\u0000\""), - "[json.exception.parse_error.101] parse error at 13: syntax error - invalid string: surrogate U+DC00..U+DFFF must be followed by U+DC00..U+DFFF; last read: '\"\\uD80C\\u0000'"); + "[json.exception.parse_error.101] parse error at line 1, column 13: syntax error while parsing value - invalid string: surrogate U+DC00..U+DFFF must be followed by U+DC00..U+DFFF; last read: '\"\\uD80C\\u0000'"); CHECK_THROWS_WITH(json::parse("\"\\uD80C\\uFFFF\""), - "[json.exception.parse_error.101] parse error at 13: syntax error - invalid string: surrogate U+DC00..U+DFFF must be followed by U+DC00..U+DFFF; last read: '\"\\uD80C\\uFFFF'"); + "[json.exception.parse_error.101] parse error at line 1, column 13: syntax error while parsing value - invalid string: surrogate U+DC00..U+DFFF must be followed by U+DC00..U+DFFF; last read: '\"\\uD80C\\uFFFF'"); } SECTION("parse errors (accept)") @@ -1292,6 +1292,9 @@ TEST_CASE("parser class") CHECK(accept_helper("\"\\u01") == false); CHECK(accept_helper("\"\\u012") == false); + // unget of newline + CHECK(parser_helper("\n123\n") == 123); + // invalid escapes for (int c = 1; c < 128; ++c) { @@ -1419,11 +1422,11 @@ TEST_CASE("parser class") // test case to make sure no comma preceeds the first key CHECK_THROWS_AS(parser_helper("{,\"key\": false}"), json::parse_error&); CHECK_THROWS_WITH(parser_helper("{,\"key\": false}"), - "[json.exception.parse_error.101] parse error at 2: syntax error - unexpected ','; expected string literal"); + "[json.exception.parse_error.101] parse error at line 1, column 2: syntax error while parsing object key - unexpected ','; expected string literal"); // test case to make sure an object is properly closed CHECK_THROWS_AS(parser_helper("[{\"key\": false true]"), json::parse_error&); CHECK_THROWS_WITH(parser_helper("[{\"key\": false true]"), - "[json.exception.parse_error.101] parse error at 19: syntax error - unexpected true literal; expected '}'"); + "[json.exception.parse_error.101] parse error at line 1, column 19: syntax error while parsing object - unexpected true literal; expected '}'"); // test case to make sure the callback is properly evaluated after reading a key { @@ -1674,7 +1677,7 @@ TEST_CASE("parser class") CHECK_THROWS_AS(json::parse("{\"foo\": true:", cb), json::parse_error&); CHECK_THROWS_WITH(json::parse("{\"foo\": true:", cb), - "[json.exception.parse_error.101] parse error at 13: syntax error - unexpected ':'; expected '}'"); + "[json.exception.parse_error.101] parse error at line 1, column 13: syntax error while parsing object - unexpected ':'; expected '}'"); CHECK_THROWS_AS(json::parse("1.18973e+4932", cb), json::out_of_range&); CHECK_THROWS_WITH(json::parse("1.18973e+4932", cb), diff --git a/test/src/unit-comparison.cpp b/test/src/unit-comparison.cpp index 3da891b6..91c47453 100644 --- a/test/src/unit-comparison.cpp +++ b/test/src/unit-comparison.cpp @@ -1,7 +1,7 @@ /* __ _____ _____ _____ __| | __| | | | JSON for Modern C++ (test suite) -| | |__ | | | | | | version 3.2.0 +| | |__ | | | | | | version 3.3.0 |_____|_____|_____|_|___| https://github.com/nlohmann/json Licensed under the MIT License . diff --git a/test/src/unit-concepts.cpp b/test/src/unit-concepts.cpp index 95013c69..8ceb485b 100644 --- a/test/src/unit-concepts.cpp +++ b/test/src/unit-concepts.cpp @@ -1,7 +1,7 @@ /* __ _____ _____ _____ __| | __| | | | JSON for Modern C++ (test suite) -| | |__ | | | | | | version 3.2.0 +| | |__ | | | | | | version 3.3.0 |_____|_____|_____|_|___| https://github.com/nlohmann/json Licensed under the MIT License . diff --git a/test/src/unit-constructor1.cpp b/test/src/unit-constructor1.cpp index d6040fc3..e5a1eb44 100644 --- a/test/src/unit-constructor1.cpp +++ b/test/src/unit-constructor1.cpp @@ -1,7 +1,7 @@ /* __ _____ _____ _____ __| | __| | | | JSON for Modern C++ (test suite) -| | |__ | | | | | | version 3.2.0 +| | |__ | | | | | | version 3.3.0 |_____|_____|_____|_|___| https://github.com/nlohmann/json Licensed under the MIT License . diff --git a/test/src/unit-constructor2.cpp b/test/src/unit-constructor2.cpp index 14738023..4f5e11d3 100644 --- a/test/src/unit-constructor2.cpp +++ b/test/src/unit-constructor2.cpp @@ -1,7 +1,7 @@ /* __ _____ _____ _____ __| | __| | | | JSON for Modern C++ (test suite) -| | |__ | | | | | | version 3.2.0 +| | |__ | | | | | | version 3.3.0 |_____|_____|_____|_|___| https://github.com/nlohmann/json Licensed under the MIT License . diff --git a/test/src/unit-convenience.cpp b/test/src/unit-convenience.cpp index 08c0b162..bbb259b6 100644 --- a/test/src/unit-convenience.cpp +++ b/test/src/unit-convenience.cpp @@ -1,7 +1,7 @@ /* __ _____ _____ _____ __| | __| | | | JSON for Modern C++ (test suite) -| | |__ | | | | | | version 3.2.0 +| | |__ | | | | | | version 3.3.0 |_____|_____|_____|_|___| https://github.com/nlohmann/json Licensed under the MIT License . diff --git a/test/src/unit-conversions.cpp b/test/src/unit-conversions.cpp index fd09b230..8df21f3f 100644 --- a/test/src/unit-conversions.cpp +++ b/test/src/unit-conversions.cpp @@ -1,7 +1,7 @@ /* __ _____ _____ _____ __| | __| | | | JSON for Modern C++ (test suite) -| | |__ | | | | | | version 3.2.0 +| | |__ | | | | | | version 3.3.0 |_____|_____|_____|_|___| https://github.com/nlohmann/json Licensed under the MIT License . diff --git a/test/src/unit-deserialization.cpp b/test/src/unit-deserialization.cpp index 4f9970ab..8610cebd 100644 --- a/test/src/unit-deserialization.cpp +++ b/test/src/unit-deserialization.cpp @@ -1,7 +1,7 @@ /* __ _____ _____ _____ __| | __| | | | JSON for Modern C++ (test suite) -| | |__ | | | | | | version 3.2.0 +| | |__ | | | | | | version 3.3.0 |_____|_____|_____|_|___| https://github.com/nlohmann/json Licensed under the MIT License . @@ -267,7 +267,7 @@ TEST_CASE("deserialization") ss5 << "[\"foo\",1,2,3,false,{\"one\":1}"; CHECK_THROWS_AS(json::parse(ss1), json::parse_error&); CHECK_THROWS_WITH(json::parse(ss2), - "[json.exception.parse_error.101] parse error at 29: syntax error - unexpected end of input; expected ']'"); + "[json.exception.parse_error.101] parse error at line 1, column 29: syntax error while parsing array - unexpected end of input; expected ']'"); CHECK(not json::accept(ss3)); json j_error; @@ -291,7 +291,7 @@ TEST_CASE("deserialization") json::string_t s = "[\"foo\",1,2,3,false,{\"one\":1}"; CHECK_THROWS_AS(json::parse(s), json::parse_error&); CHECK_THROWS_WITH(json::parse(s), - "[json.exception.parse_error.101] parse error at 29: syntax error - unexpected end of input; expected ']'"); + "[json.exception.parse_error.101] parse error at line 1, column 29: syntax error while parsing array - unexpected end of input; expected ']'"); CHECK(not json::accept(s)); json j_error; @@ -318,7 +318,7 @@ TEST_CASE("deserialization") json j; CHECK_THROWS_AS(j << ss1, json::parse_error&); CHECK_THROWS_WITH(j << ss2, - "[json.exception.parse_error.101] parse error at 29: syntax error - unexpected end of input; expected ']'"); + "[json.exception.parse_error.101] parse error at line 1, column 29: syntax error while parsing array - unexpected end of input; expected ']'"); } SECTION("operator>>") @@ -329,14 +329,14 @@ TEST_CASE("deserialization") json j; CHECK_THROWS_AS(ss1 >> j, json::parse_error&); CHECK_THROWS_WITH(ss2 >> j, - "[json.exception.parse_error.101] parse error at 29: syntax error - unexpected end of input; expected ']'"); + "[json.exception.parse_error.101] parse error at line 1, column 29: syntax error while parsing array - unexpected end of input; expected ']'"); } SECTION("user-defined string literal") { CHECK_THROWS_AS("[\"foo\",1,2,3,false,{\"one\":1}"_json, json::parse_error&); CHECK_THROWS_WITH("[\"foo\",1,2,3,false,{\"one\":1}"_json, - "[json.exception.parse_error.101] parse error at 29: syntax error - unexpected end of input; expected ']'"); + "[json.exception.parse_error.101] parse error at line 1, column 29: syntax error while parsing array - unexpected end of input; expected ']'"); } } @@ -612,7 +612,7 @@ TEST_CASE("deserialization") uint8_t v[] = {'\"', 0x7F, 0xDF, 0x7F}; CHECK_THROWS_AS(json::parse(std::begin(v), std::end(v)), json::parse_error&); CHECK_THROWS_WITH(json::parse(std::begin(v), std::end(v)), - "[json.exception.parse_error.101] parse error at 4: syntax error - invalid string: ill-formed UTF-8 byte; last read: '\"\x7f\xdf\x7f'"); + "[json.exception.parse_error.101] parse error at line 1, column 4: syntax error while parsing value - invalid string: ill-formed UTF-8 byte; last read: '\"\x7f\xdf\x7f'"); CHECK(not json::accept(std::begin(v), std::end(v))); json j_error; @@ -799,11 +799,11 @@ TEST_CASE("deserialization") { CHECK_THROWS_AS(json::parse(bom), json::parse_error&); CHECK_THROWS_WITH(json::parse(bom), - "[json.exception.parse_error.101] parse error at 4: syntax error - unexpected end of input; expected '[', '{', or a literal"); + "[json.exception.parse_error.101] parse error at line 1, column 4: syntax error while parsing value - unexpected end of input; expected '[', '{', or a literal"); CHECK_THROWS_AS(json::parse(std::istringstream(bom)), json::parse_error&); CHECK_THROWS_WITH(json::parse(std::istringstream(bom)), - "[json.exception.parse_error.101] parse error at 4: syntax error - unexpected end of input; expected '[', '{', or a literal"); + "[json.exception.parse_error.101] parse error at line 1, column 4: syntax error while parsing value - unexpected end of input; expected '[', '{', or a literal"); SaxEventLogger l; CHECK(not json::sax_parse(bom, &l)); @@ -838,11 +838,11 @@ TEST_CASE("deserialization") { CHECK_THROWS_AS(json::parse(bom.substr(0, 2)), json::parse_error&); CHECK_THROWS_WITH(json::parse(bom.substr(0, 2)), - "[json.exception.parse_error.101] parse error at 3: syntax error - invalid BOM; must be 0xEF 0xBB 0xBF if given; last read: '\xEF\xBB'"); + "[json.exception.parse_error.101] parse error at line 1, column 3: syntax error while parsing value - invalid BOM; must be 0xEF 0xBB 0xBF if given; last read: '\xEF\xBB'"); CHECK_THROWS_AS(json::parse(std::istringstream(bom.substr(0, 2))), json::parse_error&); CHECK_THROWS_WITH(json::parse(std::istringstream(bom.substr(0, 2))), - "[json.exception.parse_error.101] parse error at 3: syntax error - invalid BOM; must be 0xEF 0xBB 0xBF if given; last read: '\xEF\xBB'"); + "[json.exception.parse_error.101] parse error at line 1, column 3: syntax error while parsing value - invalid BOM; must be 0xEF 0xBB 0xBF if given; last read: '\xEF\xBB'"); SaxEventLogger l1, l2; CHECK(not json::sax_parse(std::istringstream(bom.substr(0, 2)), &l1)); @@ -863,11 +863,11 @@ TEST_CASE("deserialization") { CHECK_THROWS_AS(json::parse(bom.substr(0, 1)), json::parse_error&); CHECK_THROWS_WITH(json::parse(bom.substr(0, 1)), - "[json.exception.parse_error.101] parse error at 2: syntax error - invalid BOM; must be 0xEF 0xBB 0xBF if given; last read: '\xEF'"); + "[json.exception.parse_error.101] parse error at line 1, column 2: syntax error while parsing value - invalid BOM; must be 0xEF 0xBB 0xBF if given; last read: '\xEF'"); CHECK_THROWS_AS(json::parse(std::istringstream(bom.substr(0, 1))), json::parse_error&); CHECK_THROWS_WITH(json::parse(std::istringstream(bom.substr(0, 1))), - "[json.exception.parse_error.101] parse error at 2: syntax error - invalid BOM; must be 0xEF 0xBB 0xBF if given; last read: '\xEF'"); + "[json.exception.parse_error.101] parse error at line 1, column 2: syntax error while parsing value - invalid BOM; must be 0xEF 0xBB 0xBF if given; last read: '\xEF'"); SaxEventLogger l1, l2; CHECK(not json::sax_parse(std::istringstream(bom.substr(0, 1)), &l1)); diff --git a/test/src/unit-element_access1.cpp b/test/src/unit-element_access1.cpp index 2954d696..96ee58b2 100644 --- a/test/src/unit-element_access1.cpp +++ b/test/src/unit-element_access1.cpp @@ -1,7 +1,7 @@ /* __ _____ _____ _____ __| | __| | | | JSON for Modern C++ (test suite) -| | |__ | | | | | | version 3.2.0 +| | |__ | | | | | | version 3.3.0 |_____|_____|_____|_|___| https://github.com/nlohmann/json Licensed under the MIT License . @@ -195,7 +195,7 @@ TEST_CASE("element access 1") const json j_nonarray_const(j_nonarray); CHECK_NOTHROW(j_nonarray[0]); CHECK_THROWS_AS(j_nonarray_const[0], json::type_error&); - CHECK_THROWS_WITH(j_nonarray_const[0], "[json.exception.type_error.305] cannot use operator[] with null"); + CHECK_THROWS_WITH(j_nonarray_const[0], "[json.exception.type_error.305] cannot use operator[] with a numeric argument with null"); } SECTION("implicit transformation to properly filled array") @@ -212,8 +212,8 @@ TEST_CASE("element access 1") const json j_nonarray_const(j_nonarray); CHECK_THROWS_AS(j_nonarray[0], json::type_error&); CHECK_THROWS_AS(j_nonarray_const[0], json::type_error&); - CHECK_THROWS_WITH(j_nonarray[0], "[json.exception.type_error.305] cannot use operator[] with boolean"); - CHECK_THROWS_WITH(j_nonarray_const[0], "[json.exception.type_error.305] cannot use operator[] with boolean"); + CHECK_THROWS_WITH(j_nonarray[0], "[json.exception.type_error.305] cannot use operator[] with a numeric argument with boolean"); + CHECK_THROWS_WITH(j_nonarray_const[0], "[json.exception.type_error.305] cannot use operator[] with a numeric argument with boolean"); } SECTION("string") @@ -222,8 +222,8 @@ TEST_CASE("element access 1") const json j_nonarray_const(j_nonarray); CHECK_THROWS_AS(j_nonarray[0], json::type_error&); CHECK_THROWS_AS(j_nonarray_const[0], json::type_error&); - CHECK_THROWS_WITH(j_nonarray[0], "[json.exception.type_error.305] cannot use operator[] with string"); - CHECK_THROWS_WITH(j_nonarray_const[0], "[json.exception.type_error.305] cannot use operator[] with string"); + CHECK_THROWS_WITH(j_nonarray[0], "[json.exception.type_error.305] cannot use operator[] with a numeric argument with string"); + CHECK_THROWS_WITH(j_nonarray_const[0], "[json.exception.type_error.305] cannot use operator[] with a numeric argument with string"); } SECTION("object") @@ -232,8 +232,8 @@ TEST_CASE("element access 1") const json j_nonarray_const(j_nonarray); CHECK_THROWS_AS(j_nonarray[0], json::type_error&); CHECK_THROWS_AS(j_nonarray_const[0], json::type_error&); - CHECK_THROWS_WITH(j_nonarray[0], "[json.exception.type_error.305] cannot use operator[] with object"); - CHECK_THROWS_WITH(j_nonarray_const[0], "[json.exception.type_error.305] cannot use operator[] with object"); + CHECK_THROWS_WITH(j_nonarray[0], "[json.exception.type_error.305] cannot use operator[] with a numeric argument with object"); + CHECK_THROWS_WITH(j_nonarray_const[0], "[json.exception.type_error.305] cannot use operator[] with a numeric argument with object"); } SECTION("number (integer)") @@ -242,8 +242,8 @@ TEST_CASE("element access 1") const json j_nonarray_const(j_nonarray); CHECK_THROWS_AS(j_nonarray[0], json::type_error&); CHECK_THROWS_AS(j_nonarray_const[0], json::type_error&); - CHECK_THROWS_WITH(j_nonarray[0], "[json.exception.type_error.305] cannot use operator[] with number"); - CHECK_THROWS_WITH(j_nonarray_const[0], "[json.exception.type_error.305] cannot use operator[] with number"); + CHECK_THROWS_WITH(j_nonarray[0], "[json.exception.type_error.305] cannot use operator[] with a numeric argument with number"); + CHECK_THROWS_WITH(j_nonarray_const[0], "[json.exception.type_error.305] cannot use operator[] with a numeric argument with number"); } SECTION("number (unsigned)") @@ -252,8 +252,8 @@ TEST_CASE("element access 1") const json j_nonarray_const(j_nonarray); CHECK_THROWS_AS(j_nonarray[0], json::type_error&); CHECK_THROWS_AS(j_nonarray_const[0], json::type_error&); - CHECK_THROWS_WITH(j_nonarray[0], "[json.exception.type_error.305] cannot use operator[] with number"); - CHECK_THROWS_WITH(j_nonarray_const[0], "[json.exception.type_error.305] cannot use operator[] with number"); + CHECK_THROWS_WITH(j_nonarray[0], "[json.exception.type_error.305] cannot use operator[] with a numeric argument with number"); + CHECK_THROWS_WITH(j_nonarray_const[0], "[json.exception.type_error.305] cannot use operator[] with a numeric argument with number"); } SECTION("number (floating-point)") @@ -262,8 +262,8 @@ TEST_CASE("element access 1") const json j_nonarray_const(j_nonarray); CHECK_THROWS_AS(j_nonarray[0], json::type_error&); CHECK_THROWS_AS(j_nonarray_const[0], json::type_error&); - CHECK_THROWS_WITH(j_nonarray[0], "[json.exception.type_error.305] cannot use operator[] with number"); - CHECK_THROWS_WITH(j_nonarray_const[0], "[json.exception.type_error.305] cannot use operator[] with number"); + CHECK_THROWS_WITH(j_nonarray[0], "[json.exception.type_error.305] cannot use operator[] with a numeric argument with number"); + CHECK_THROWS_WITH(j_nonarray_const[0], "[json.exception.type_error.305] cannot use operator[] with a numeric argument with number"); } } } diff --git a/test/src/unit-element_access2.cpp b/test/src/unit-element_access2.cpp index 41ec42be..c629a9ac 100644 --- a/test/src/unit-element_access2.cpp +++ b/test/src/unit-element_access2.cpp @@ -1,7 +1,7 @@ /* __ _____ _____ _____ __| | __| | | | JSON for Modern C++ (test suite) -| | |__ | | | | | | version 3.2.0 +| | |__ | | | | | | version 3.3.0 |_____|_____|_____|_|___| https://github.com/nlohmann/json Licensed under the MIT License . @@ -475,9 +475,9 @@ TEST_CASE("element access 2") CHECK_NOTHROW(j_nonobject2[json::object_t::key_type("foo")]); CHECK_THROWS_AS(j_const_nonobject["foo"], json::type_error&); CHECK_THROWS_AS(j_const_nonobject[json::object_t::key_type("foo")], json::type_error&); - CHECK_THROWS_WITH(j_const_nonobject["foo"], "[json.exception.type_error.305] cannot use operator[] with null"); + CHECK_THROWS_WITH(j_const_nonobject["foo"], "[json.exception.type_error.305] cannot use operator[] with a string argument with null"); CHECK_THROWS_WITH(j_const_nonobject[json::object_t::key_type("foo")], - "[json.exception.type_error.305] cannot use operator[] with null"); + "[json.exception.type_error.305] cannot use operator[] with a string argument with null"); } SECTION("boolean") @@ -489,13 +489,13 @@ TEST_CASE("element access 2") CHECK_THROWS_AS(j_const_nonobject["foo"], json::type_error&); CHECK_THROWS_AS(j_const_nonobject[json::object_t::key_type("foo")], json::type_error&); CHECK_THROWS_WITH(j_nonobject["foo"], - "[json.exception.type_error.305] cannot use operator[] with boolean"); + "[json.exception.type_error.305] cannot use operator[] with a string argument with boolean"); CHECK_THROWS_WITH(j_nonobject[json::object_t::key_type("foo")], - "[json.exception.type_error.305] cannot use operator[] with boolean"); + "[json.exception.type_error.305] cannot use operator[] with a string argument with boolean"); CHECK_THROWS_WITH(j_const_nonobject["foo"], - "[json.exception.type_error.305] cannot use operator[] with boolean"); + "[json.exception.type_error.305] cannot use operator[] with a string argument with boolean"); CHECK_THROWS_WITH(j_const_nonobject[json::object_t::key_type("foo")], - "[json.exception.type_error.305] cannot use operator[] with boolean"); + "[json.exception.type_error.305] cannot use operator[] with a string argument with boolean"); } SECTION("string") @@ -507,13 +507,13 @@ TEST_CASE("element access 2") CHECK_THROWS_AS(j_const_nonobject["foo"], json::type_error&); CHECK_THROWS_AS(j_const_nonobject[json::object_t::key_type("foo")], json::type_error&); CHECK_THROWS_WITH(j_nonobject["foo"], - "[json.exception.type_error.305] cannot use operator[] with string"); + "[json.exception.type_error.305] cannot use operator[] with a string argument with string"); CHECK_THROWS_WITH(j_nonobject[json::object_t::key_type("foo")], - "[json.exception.type_error.305] cannot use operator[] with string"); + "[json.exception.type_error.305] cannot use operator[] with a string argument with string"); CHECK_THROWS_WITH(j_const_nonobject["foo"], - "[json.exception.type_error.305] cannot use operator[] with string"); + "[json.exception.type_error.305] cannot use operator[] with a string argument with string"); CHECK_THROWS_WITH(j_const_nonobject[json::object_t::key_type("foo")], - "[json.exception.type_error.305] cannot use operator[] with string"); + "[json.exception.type_error.305] cannot use operator[] with a string argument with string"); } SECTION("array") @@ -525,12 +525,12 @@ TEST_CASE("element access 2") CHECK_THROWS_AS(j_const_nonobject["foo"], json::type_error&); CHECK_THROWS_AS(j_const_nonobject[json::object_t::key_type("foo")], json::type_error&); CHECK_THROWS_WITH(j_nonobject["foo"], - "[json.exception.type_error.305] cannot use operator[] with array"); - CHECK_THROWS_WITH(j_nonobject[json::object_t::key_type("foo")], "[json.exception.type_error.305] cannot use operator[] with array"); + "[json.exception.type_error.305] cannot use operator[] with a string argument with array"); + CHECK_THROWS_WITH(j_nonobject[json::object_t::key_type("foo")], "[json.exception.type_error.305] cannot use operator[] with a string argument with array"); CHECK_THROWS_WITH(j_const_nonobject["foo"], - "[json.exception.type_error.305] cannot use operator[] with array"); + "[json.exception.type_error.305] cannot use operator[] with a string argument with array"); CHECK_THROWS_WITH(j_const_nonobject[json::object_t::key_type("foo")], - "[json.exception.type_error.305] cannot use operator[] with array"); + "[json.exception.type_error.305] cannot use operator[] with a string argument with array"); } SECTION("number (integer)") @@ -542,13 +542,13 @@ TEST_CASE("element access 2") CHECK_THROWS_AS(j_const_nonobject["foo"], json::type_error&); CHECK_THROWS_AS(j_const_nonobject[json::object_t::key_type("foo")], json::type_error&); CHECK_THROWS_WITH(j_nonobject["foo"], - "[json.exception.type_error.305] cannot use operator[] with number"); + "[json.exception.type_error.305] cannot use operator[] with a string argument with number"); CHECK_THROWS_WITH(j_nonobject[json::object_t::key_type("foo")], - "[json.exception.type_error.305] cannot use operator[] with number"); + "[json.exception.type_error.305] cannot use operator[] with a string argument with number"); CHECK_THROWS_WITH(j_const_nonobject["foo"], - "[json.exception.type_error.305] cannot use operator[] with number"); + "[json.exception.type_error.305] cannot use operator[] with a string argument with number"); CHECK_THROWS_WITH(j_const_nonobject[json::object_t::key_type("foo")], - "[json.exception.type_error.305] cannot use operator[] with number"); + "[json.exception.type_error.305] cannot use operator[] with a string argument with number"); } SECTION("number (unsigned)") @@ -560,13 +560,13 @@ TEST_CASE("element access 2") CHECK_THROWS_AS(j_const_nonobject["foo"], json::type_error&); CHECK_THROWS_AS(j_const_nonobject[json::object_t::key_type("foo")], json::type_error&); CHECK_THROWS_WITH(j_nonobject["foo"], - "[json.exception.type_error.305] cannot use operator[] with number"); + "[json.exception.type_error.305] cannot use operator[] with a string argument with number"); CHECK_THROWS_WITH(j_nonobject[json::object_t::key_type("foo")], - "[json.exception.type_error.305] cannot use operator[] with number"); + "[json.exception.type_error.305] cannot use operator[] with a string argument with number"); CHECK_THROWS_WITH(j_const_nonobject["foo"], - "[json.exception.type_error.305] cannot use operator[] with number"); + "[json.exception.type_error.305] cannot use operator[] with a string argument with number"); CHECK_THROWS_WITH(j_const_nonobject[json::object_t::key_type("foo")], - "[json.exception.type_error.305] cannot use operator[] with number"); + "[json.exception.type_error.305] cannot use operator[] with a string argument with number"); } SECTION("number (floating-point)") @@ -578,13 +578,13 @@ TEST_CASE("element access 2") CHECK_THROWS_AS(j_const_nonobject["foo"], json::type_error&); CHECK_THROWS_AS(j_const_nonobject[json::object_t::key_type("foo")], json::type_error&); CHECK_THROWS_WITH(j_nonobject["foo"], - "[json.exception.type_error.305] cannot use operator[] with number"); + "[json.exception.type_error.305] cannot use operator[] with a string argument with number"); CHECK_THROWS_WITH(j_nonobject[json::object_t::key_type("foo")], - "[json.exception.type_error.305] cannot use operator[] with number"); + "[json.exception.type_error.305] cannot use operator[] with a string argument with number"); CHECK_THROWS_WITH(j_const_nonobject["foo"], - "[json.exception.type_error.305] cannot use operator[] with number"); + "[json.exception.type_error.305] cannot use operator[] with a string argument with number"); CHECK_THROWS_WITH(j_const_nonobject[json::object_t::key_type("foo")], - "[json.exception.type_error.305] cannot use operator[] with number"); + "[json.exception.type_error.305] cannot use operator[] with a string argument with number"); } } } diff --git a/test/src/unit-inspection.cpp b/test/src/unit-inspection.cpp index 8e42c6ec..007b304d 100644 --- a/test/src/unit-inspection.cpp +++ b/test/src/unit-inspection.cpp @@ -1,7 +1,7 @@ /* __ _____ _____ _____ __| | __| | | | JSON for Modern C++ (test suite) -| | |__ | | | | | | version 3.2.0 +| | |__ | | | | | | version 3.3.0 |_____|_____|_____|_|___| https://github.com/nlohmann/json Licensed under the MIT License . diff --git a/test/src/unit-items.cpp b/test/src/unit-items.cpp index 69637ee8..6c716eeb 100644 --- a/test/src/unit-items.cpp +++ b/test/src/unit-items.cpp @@ -1,7 +1,7 @@ /* __ _____ _____ _____ __| | __| | | | JSON for Modern C++ (test suite) -| | |__ | | | | | | version 3.2.0 +| | |__ | | | | | | version 3.3.0 |_____|_____|_____|_|___| https://github.com/nlohmann/json Licensed under the MIT License . diff --git a/test/src/unit-iterators1.cpp b/test/src/unit-iterators1.cpp index 8c3417d5..c911ce92 100644 --- a/test/src/unit-iterators1.cpp +++ b/test/src/unit-iterators1.cpp @@ -1,7 +1,7 @@ /* __ _____ _____ _____ __| | __| | | | JSON for Modern C++ (test suite) -| | |__ | | | | | | version 3.2.0 +| | |__ | | | | | | version 3.3.0 |_____|_____|_____|_|___| https://github.com/nlohmann/json Licensed under the MIT License . diff --git a/test/src/unit-iterators2.cpp b/test/src/unit-iterators2.cpp index 3d309b3c..2369cc47 100644 --- a/test/src/unit-iterators2.cpp +++ b/test/src/unit-iterators2.cpp @@ -1,7 +1,7 @@ /* __ _____ _____ _____ __| | __| | | | JSON for Modern C++ (test suite) -| | |__ | | | | | | version 3.2.0 +| | |__ | | | | | | version 3.3.0 |_____|_____|_____|_|___| https://github.com/nlohmann/json Licensed under the MIT License . diff --git a/test/src/unit-json_patch.cpp b/test/src/unit-json_patch.cpp index c7c62fe5..55f2eb7d 100644 --- a/test/src/unit-json_patch.cpp +++ b/test/src/unit-json_patch.cpp @@ -1,7 +1,7 @@ /* __ _____ _____ _____ __| | __| | | | JSON for Modern C++ (test suite) -| | |__ | | | | | | version 3.2.0 +| | |__ | | | | | | version 3.3.0 |_____|_____|_____|_|___| https://github.com/nlohmann/json Licensed under the MIT License . @@ -63,7 +63,7 @@ TEST_CASE("JSON patch") // is not an error, because "a" exists, and "b" will be added to // its value. CHECK_NOTHROW(doc1.patch(patch)); - CHECK(doc1.patch(patch) == R"( + auto doc1_ans = R"( { "a": { "foo": 1, @@ -72,7 +72,8 @@ TEST_CASE("JSON patch") } } } - )"_json); + )"_json; + CHECK(doc1.patch(patch) == doc1_ans); // It is an error in this document: json doc2 = R"({ "q": { "bar": 2 } })"_json; diff --git a/test/src/unit-json_pointer.cpp b/test/src/unit-json_pointer.cpp index 9f39493c..7f5605d9 100644 --- a/test/src/unit-json_pointer.cpp +++ b/test/src/unit-json_pointer.cpp @@ -1,7 +1,7 @@ /* __ _____ _____ _____ __| | __| | | | JSON for Modern C++ (test suite) -| | |__ | | | | | | version 3.2.0 +| | |__ | | | | | | version 3.3.0 |_____|_____|_____|_|___| https://github.com/nlohmann/json Licensed under the MIT License . @@ -39,7 +39,7 @@ TEST_CASE("JSON pointers") { CHECK_THROWS_AS(json::json_pointer("foo"), json::parse_error&); CHECK_THROWS_WITH(json::json_pointer("foo"), - "[json.exception.parse_error.107] parse error at 1: JSON pointer must be empty or begin with '/' - was: 'foo'"); + "[json.exception.parse_error.107] parse error at byte 1: JSON pointer must be empty or begin with '/' - was: 'foo'"); CHECK_THROWS_AS(json::json_pointer("/~~"), json::parse_error&); CHECK_THROWS_WITH(json::json_pointer("/~~"), diff --git a/test/src/unit-merge_patch.cpp b/test/src/unit-merge_patch.cpp index 15997e19..417e1dd4 100644 --- a/test/src/unit-merge_patch.cpp +++ b/test/src/unit-merge_patch.cpp @@ -1,7 +1,7 @@ /* __ _____ _____ _____ __| | __| | | | JSON for Modern C++ (test suite) -| | |__ | | | | | | version 3.2.0 +| | |__ | | | | | | version 3.3.0 |_____|_____|_____|_|___| https://github.com/nlohmann/json Licensed under the MIT License . diff --git a/test/src/unit-meta.cpp b/test/src/unit-meta.cpp index 1fd21dbf..36d31909 100644 --- a/test/src/unit-meta.cpp +++ b/test/src/unit-meta.cpp @@ -1,7 +1,7 @@ /* __ _____ _____ _____ __| | __| | | | JSON for Modern C++ (test suite) -| | |__ | | | | | | version 3.2.0 +| | |__ | | | | | | version 3.3.0 |_____|_____|_____|_|___| https://github.com/nlohmann/json Licensed under the MIT License . @@ -43,9 +43,9 @@ TEST_CASE("version information") CHECK(j["url"] == "https://github.com/nlohmann/json"); CHECK(j["version"] == json( { - {"string", "3.2.0"}, + {"string", "3.3.0"}, {"major", 3}, - {"minor", 2}, + {"minor", 3}, {"patch", 0} })); diff --git a/test/src/unit-modifiers.cpp b/test/src/unit-modifiers.cpp index a73e7cfb..5548db12 100644 --- a/test/src/unit-modifiers.cpp +++ b/test/src/unit-modifiers.cpp @@ -1,7 +1,7 @@ /* __ _____ _____ _____ __| | __| | | | JSON for Modern C++ (test suite) -| | |__ | | | | | | version 3.2.0 +| | |__ | | | | | | version 3.3.0 |_____|_____|_____|_|___| https://github.com/nlohmann/json Licensed under the MIT License . diff --git a/test/src/unit-msgpack.cpp b/test/src/unit-msgpack.cpp index 60892345..26d07963 100644 --- a/test/src/unit-msgpack.cpp +++ b/test/src/unit-msgpack.cpp @@ -1,7 +1,7 @@ /* __ _____ _____ _____ __| | __| | | | JSON for Modern C++ (test suite) -| | |__ | | | | | | version 3.2.0 +| | |__ | | | | | | version 3.3.0 |_____|_____|_____|_|___| https://github.com/nlohmann/json Licensed under the MIT License . @@ -1124,7 +1124,7 @@ TEST_CASE("MessagePack") { CHECK_THROWS_AS(json::from_msgpack(std::vector()), json::parse_error&); CHECK_THROWS_WITH(json::from_msgpack(std::vector()), - "[json.exception.parse_error.110] parse error at 1: unexpected end of input"); + "[json.exception.parse_error.110] parse error at byte 1: syntax error while parsing MessagePack value: unexpected end of input"); CHECK(json::from_msgpack(std::vector(), true, false).is_discarded()); } @@ -1151,43 +1151,43 @@ TEST_CASE("MessagePack") CHECK_THROWS_AS(json::from_msgpack(std::vector({0x81, 0xa1, 0x61})), json::parse_error&); CHECK_THROWS_WITH(json::from_msgpack(std::vector({0x87})), - "[json.exception.parse_error.110] parse error at 2: unexpected end of input"); + "[json.exception.parse_error.110] parse error at byte 2: syntax error while parsing MessagePack string: unexpected end of input"); CHECK_THROWS_WITH(json::from_msgpack(std::vector({0xcc})), - "[json.exception.parse_error.110] parse error at 2: unexpected end of input"); + "[json.exception.parse_error.110] parse error at byte 2: syntax error while parsing MessagePack number: unexpected end of input"); CHECK_THROWS_WITH(json::from_msgpack(std::vector({0xcd})), - "[json.exception.parse_error.110] parse error at 2: unexpected end of input"); + "[json.exception.parse_error.110] parse error at byte 2: syntax error while parsing MessagePack number: unexpected end of input"); CHECK_THROWS_WITH(json::from_msgpack(std::vector({0xcd, 0x00})), - "[json.exception.parse_error.110] parse error at 3: unexpected end of input"); + "[json.exception.parse_error.110] parse error at byte 3: syntax error while parsing MessagePack number: unexpected end of input"); CHECK_THROWS_WITH(json::from_msgpack(std::vector({0xce})), - "[json.exception.parse_error.110] parse error at 2: unexpected end of input"); + "[json.exception.parse_error.110] parse error at byte 2: syntax error while parsing MessagePack number: unexpected end of input"); CHECK_THROWS_WITH(json::from_msgpack(std::vector({0xce, 0x00})), - "[json.exception.parse_error.110] parse error at 3: unexpected end of input"); + "[json.exception.parse_error.110] parse error at byte 3: syntax error while parsing MessagePack number: unexpected end of input"); CHECK_THROWS_WITH(json::from_msgpack(std::vector({0xce, 0x00, 0x00})), - "[json.exception.parse_error.110] parse error at 4: unexpected end of input"); + "[json.exception.parse_error.110] parse error at byte 4: syntax error while parsing MessagePack number: unexpected end of input"); CHECK_THROWS_WITH(json::from_msgpack(std::vector({0xce, 0x00, 0x00, 0x00})), - "[json.exception.parse_error.110] parse error at 5: unexpected end of input"); + "[json.exception.parse_error.110] parse error at byte 5: syntax error while parsing MessagePack number: unexpected end of input"); CHECK_THROWS_WITH(json::from_msgpack(std::vector({0xcf})), - "[json.exception.parse_error.110] parse error at 2: unexpected end of input"); + "[json.exception.parse_error.110] parse error at byte 2: syntax error while parsing MessagePack number: unexpected end of input"); CHECK_THROWS_WITH(json::from_msgpack(std::vector({0xcf, 0x00})), - "[json.exception.parse_error.110] parse error at 3: unexpected end of input"); + "[json.exception.parse_error.110] parse error at byte 3: syntax error while parsing MessagePack number: unexpected end of input"); CHECK_THROWS_WITH(json::from_msgpack(std::vector({0xcf, 0x00, 0x00})), - "[json.exception.parse_error.110] parse error at 4: unexpected end of input"); + "[json.exception.parse_error.110] parse error at byte 4: syntax error while parsing MessagePack number: unexpected end of input"); CHECK_THROWS_WITH(json::from_msgpack(std::vector({0xcf, 0x00, 0x00, 0x00})), - "[json.exception.parse_error.110] parse error at 5: unexpected end of input"); + "[json.exception.parse_error.110] parse error at byte 5: syntax error while parsing MessagePack number: unexpected end of input"); CHECK_THROWS_WITH(json::from_msgpack(std::vector({0xcf, 0x00, 0x00, 0x00, 0x00})), - "[json.exception.parse_error.110] parse error at 6: unexpected end of input"); + "[json.exception.parse_error.110] parse error at byte 6: syntax error while parsing MessagePack number: unexpected end of input"); CHECK_THROWS_WITH(json::from_msgpack(std::vector({0xcf, 0x00, 0x00, 0x00, 0x00, 0x00})), - "[json.exception.parse_error.110] parse error at 7: unexpected end of input"); + "[json.exception.parse_error.110] parse error at byte 7: syntax error while parsing MessagePack number: unexpected end of input"); CHECK_THROWS_WITH(json::from_msgpack(std::vector({0xcf, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00})), - "[json.exception.parse_error.110] parse error at 8: unexpected end of input"); + "[json.exception.parse_error.110] parse error at byte 8: syntax error while parsing MessagePack number: unexpected end of input"); CHECK_THROWS_WITH(json::from_msgpack(std::vector({0xcf, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00})), - "[json.exception.parse_error.110] parse error at 9: unexpected end of input"); + "[json.exception.parse_error.110] parse error at byte 9: syntax error while parsing MessagePack number: unexpected end of input"); CHECK_THROWS_WITH(json::from_msgpack(std::vector({0xa5, 0x68, 0x65})), - "[json.exception.parse_error.110] parse error at 4: unexpected end of input"); + "[json.exception.parse_error.110] parse error at byte 4: syntax error while parsing MessagePack string: unexpected end of input"); CHECK_THROWS_WITH(json::from_msgpack(std::vector({0x92, 0x01})), - "[json.exception.parse_error.110] parse error at 3: unexpected end of input"); + "[json.exception.parse_error.110] parse error at byte 3: syntax error while parsing MessagePack value: unexpected end of input"); CHECK_THROWS_WITH(json::from_msgpack(std::vector({0x81, 0xa1, 0x61})), - "[json.exception.parse_error.110] parse error at 4: unexpected end of input"); + "[json.exception.parse_error.110] parse error at byte 4: syntax error while parsing MessagePack value: unexpected end of input"); CHECK(json::from_msgpack(std::vector({0x87}), true, false).is_discarded()); CHECK(json::from_msgpack(std::vector({0xcc}), true, false).is_discarded()); @@ -1216,12 +1216,12 @@ TEST_CASE("MessagePack") { CHECK_THROWS_AS(json::from_msgpack(std::vector({0xc1})), json::parse_error&); CHECK_THROWS_WITH(json::from_msgpack(std::vector({0xc1})), - "[json.exception.parse_error.112] parse error at 1: error reading MessagePack; last byte: 0xC1"); + "[json.exception.parse_error.112] parse error at byte 1: syntax error while parsing MessagePack value: invalid byte: 0xC1"); CHECK(json::from_msgpack(std::vector({0xc6}), true, false).is_discarded()); CHECK_THROWS_AS(json::from_msgpack(std::vector({0xc6})), json::parse_error&); CHECK_THROWS_WITH(json::from_msgpack(std::vector({0xc6})), - "[json.exception.parse_error.112] parse error at 1: error reading MessagePack; last byte: 0xC6"); + "[json.exception.parse_error.112] parse error at byte 1: syntax error while parsing MessagePack value: invalid byte: 0xC6"); CHECK(json::from_msgpack(std::vector({0xc6}), true, false).is_discarded()); } @@ -1249,7 +1249,7 @@ TEST_CASE("MessagePack") { CHECK_THROWS_AS(json::from_msgpack(std::vector({0x81, 0xff, 0x01})), json::parse_error&); CHECK_THROWS_WITH(json::from_msgpack(std::vector({0x81, 0xff, 0x01})), - "[json.exception.parse_error.113] parse error at 2: expected a MessagePack string; last byte: 0xFF"); + "[json.exception.parse_error.113] parse error at byte 2: syntax error while parsing MessagePack string: expected length specification (0xA0-0xBF, 0xD9-0xDB); last byte: 0xFF"); CHECK(json::from_msgpack(std::vector({0x81, 0xff, 0x01}), true, false).is_discarded()); } @@ -1266,7 +1266,7 @@ TEST_CASE("MessagePack") { CHECK_THROWS_AS(json::from_msgpack(vec), json::parse_error&); CHECK_THROWS_WITH(json::from_msgpack(vec), - "[json.exception.parse_error.110] parse error at 2: expected end of input"); + "[json.exception.parse_error.110] parse error at byte 2: syntax error while parsing MessagePack value: expected end of input; last byte: 0xC0"); CHECK(json::from_msgpack(vec, true, false).is_discarded()); } } diff --git a/test/src/unit-noexcept.cpp b/test/src/unit-noexcept.cpp index 72e89267..b7df80c8 100644 --- a/test/src/unit-noexcept.cpp +++ b/test/src/unit-noexcept.cpp @@ -1,7 +1,7 @@ /* __ _____ _____ _____ __| | __| | | | JSON for Modern C++ (test suite) -| | |__ | | | | | | version 3.2.0 +| | |__ | | | | | | version 3.3.0 |_____|_____|_____|_|___| https://github.com/nlohmann/json Licensed under the MIT License . diff --git a/test/src/unit-pointer_access.cpp b/test/src/unit-pointer_access.cpp index f34b0a7c..5dff33a6 100644 --- a/test/src/unit-pointer_access.cpp +++ b/test/src/unit-pointer_access.cpp @@ -1,7 +1,7 @@ /* __ _____ _____ _____ __| | __| | | | JSON for Modern C++ (test suite) -| | |__ | | | | | | version 3.2.0 +| | |__ | | | | | | version 3.3.0 |_____|_____|_____|_|___| https://github.com/nlohmann/json Licensed under the MIT License . diff --git a/test/src/unit-readme.cpp b/test/src/unit-readme.cpp index 5e3255ce..d9afa1d7 100644 --- a/test/src/unit-readme.cpp +++ b/test/src/unit-readme.cpp @@ -1,7 +1,7 @@ /* __ _____ _____ _____ __| | __| | | | JSON for Modern C++ (test suite) -| | |__ | | | | | | version 3.2.0 +| | |__ | | | | | | version 3.3.0 |_____|_____|_____|_|___| https://github.com/nlohmann/json Licensed under the MIT License . diff --git a/test/src/unit-reference_access.cpp b/test/src/unit-reference_access.cpp index 5bd20776..3288a14e 100644 --- a/test/src/unit-reference_access.cpp +++ b/test/src/unit-reference_access.cpp @@ -1,7 +1,7 @@ /* __ _____ _____ _____ __| | __| | | | JSON for Modern C++ (test suite) -| | |__ | | | | | | version 3.2.0 +| | |__ | | | | | | version 3.3.0 |_____|_____|_____|_|___| https://github.com/nlohmann/json Licensed under the MIT License . diff --git a/test/src/unit-regression.cpp b/test/src/unit-regression.cpp index 69c0cf29..259377aa 100644 --- a/test/src/unit-regression.cpp +++ b/test/src/unit-regression.cpp @@ -1,7 +1,7 @@ /* __ _____ _____ _____ __| | __| | | | JSON for Modern C++ (test suite) -| | |__ | | | | | | version 3.2.0 +| | |__ | | | | | | version 3.3.0 |_____|_____|_____|_|___| https://github.com/nlohmann/json Licensed under the MIT License . @@ -33,6 +33,14 @@ 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 +#endif + +#ifdef JSON_HAS_CPP_17 + #include +#endif + #include "fifo_map.hpp" #include @@ -725,7 +733,7 @@ TEST_CASE("regression tests") { std::ifstream f("file_not_found.json"); CHECK_THROWS_AS(json::parse(f), json::parse_error&); - CHECK_THROWS_WITH(json::parse(f), "[json.exception.parse_error.101] parse error at 1: syntax error - unexpected end of input; expected '[', '{', or a literal"); + CHECK_THROWS_WITH(json::parse(f), "[json.exception.parse_error.101] parse error at line 1, column 1: syntax error while parsing value - unexpected end of input; expected '[', '{', or a literal"); } SECTION("issue #367 - calling stream at EOF") @@ -741,7 +749,7 @@ TEST_CASE("regression tests") // a parse error because of the EOF. CHECK_THROWS_AS(ss >> j, json::parse_error&); CHECK_THROWS_WITH(ss >> j, - "[json.exception.parse_error.101] parse error at 1: syntax error - unexpected end of input; expected '[', '{', or a literal"); + "[json.exception.parse_error.101] parse error at line 1, column 1: syntax error while parsing value - unexpected end of input; expected '[', '{', or a literal"); } SECTION("issue #367 - behavior of operator>> should more closely resemble that of built-in overloads") @@ -752,7 +760,7 @@ TEST_CASE("regression tests") json j; CHECK_THROWS_AS(ss >> j, json::parse_error&); CHECK_THROWS_WITH(ss >> j, - "[json.exception.parse_error.101] parse error at 1: syntax error - unexpected end of input; expected '[', '{', or a literal"); + "[json.exception.parse_error.101] parse error at line 1, column 1: syntax error while parsing value - unexpected end of input; expected '[', '{', or a literal"); } SECTION("(whitespace)") @@ -762,7 +770,7 @@ TEST_CASE("regression tests") json j; CHECK_THROWS_AS(ss >> j, json::parse_error&); CHECK_THROWS_WITH(ss >> j, - "[json.exception.parse_error.101] parse error at 1: syntax error - unexpected end of input; expected '[', '{', or a literal"); + "[json.exception.parse_error.101] parse error at line 1, column 1: syntax error while parsing value - unexpected end of input; expected '[', '{', or a literal"); } SECTION("one value") @@ -775,7 +783,7 @@ TEST_CASE("regression tests") CHECK_THROWS_AS(ss >> j, json::parse_error&); CHECK_THROWS_WITH(ss >> j, - "[json.exception.parse_error.101] parse error at 1: syntax error - unexpected end of input; expected '[', '{', or a literal"); + "[json.exception.parse_error.101] parse error at line 1, column 1: syntax error while parsing value - unexpected end of input; expected '[', '{', or a literal"); } SECTION("one value + whitespace") @@ -788,7 +796,7 @@ TEST_CASE("regression tests") CHECK_THROWS_AS(ss >> j, json::parse_error&); CHECK_THROWS_WITH(ss >> j, - "[json.exception.parse_error.101] parse error at 1: syntax error - unexpected end of input; expected '[', '{', or a literal"); + "[json.exception.parse_error.101] parse error at line 1, column 1: syntax error while parsing value - unexpected end of input; expected '[', '{', or a literal"); } SECTION("whitespace + one value") @@ -801,7 +809,7 @@ TEST_CASE("regression tests") CHECK_THROWS_AS(ss >> j, json::parse_error&); CHECK_THROWS_WITH(ss >> j, - "[json.exception.parse_error.101] parse error at 1: syntax error - unexpected end of input; expected '[', '{', or a literal"); + "[json.exception.parse_error.101] parse error at line 1, column 1: syntax error while parsing value - unexpected end of input; expected '[', '{', or a literal"); } SECTION("three values") @@ -818,7 +826,7 @@ TEST_CASE("regression tests") CHECK_THROWS_AS(ss >> j, json::parse_error&); CHECK_THROWS_WITH(ss >> j, - "[json.exception.parse_error.101] parse error at 1: syntax error - unexpected end of input; expected '[', '{', or a literal"); + "[json.exception.parse_error.101] parse error at line 1, column 1: syntax error while parsing value - unexpected end of input; expected '[', '{', or a literal"); } SECTION("literals without whitespace") @@ -837,7 +845,7 @@ TEST_CASE("regression tests") CHECK_THROWS_AS(ss >> j, json::parse_error&); CHECK_THROWS_WITH(ss >> j, - "[json.exception.parse_error.101] parse error at 1: syntax error - unexpected end of input; expected '[', '{', or a literal"); + "[json.exception.parse_error.101] parse error at line 1, column 1: syntax error while parsing value - unexpected end of input; expected '[', '{', or a literal"); } SECTION("example from #529") @@ -852,7 +860,7 @@ TEST_CASE("regression tests") CHECK_THROWS_AS(ss >> j, json::parse_error&); CHECK_THROWS_WITH(ss >> j, - "[json.exception.parse_error.101] parse error at 1: syntax error - unexpected end of input; expected '[', '{', or a literal"); + "[json.exception.parse_error.101] parse error at line 1, column 1: syntax error while parsing value - unexpected end of input; expected '[', '{', or a literal"); } SECTION("second example from #529") @@ -922,7 +930,7 @@ TEST_CASE("regression tests") std::vector vec {0x65, 0xf5, 0x0a, 0x48, 0x21}; CHECK_THROWS_AS(json::from_cbor(vec), json::parse_error&); CHECK_THROWS_WITH(json::from_cbor(vec), - "[json.exception.parse_error.110] parse error at 6: unexpected end of input"); + "[json.exception.parse_error.110] parse error at byte 6: syntax error while parsing CBOR string: unexpected end of input"); } SECTION("issue #407 - Heap-buffer-overflow (OSS-Fuzz issue 343)") @@ -931,31 +939,31 @@ TEST_CASE("regression tests") std::vector vec1 {0xcb, 0x8f, 0x0a}; CHECK_THROWS_AS(json::from_msgpack(vec1), json::parse_error&); CHECK_THROWS_WITH(json::from_msgpack(vec1), - "[json.exception.parse_error.110] parse error at 4: unexpected end of input"); + "[json.exception.parse_error.110] parse error at byte 4: syntax error while parsing MessagePack number: unexpected end of input"); // related test case: incomplete float32 std::vector vec2 {0xca, 0x8f, 0x0a}; CHECK_THROWS_AS(json::from_msgpack(vec2), json::parse_error&); CHECK_THROWS_WITH(json::from_msgpack(vec2), - "[json.exception.parse_error.110] parse error at 4: unexpected end of input"); + "[json.exception.parse_error.110] parse error at byte 4: syntax error while parsing MessagePack number: unexpected end of input"); // related test case: incomplete Half-Precision Float (CBOR) std::vector vec3 {0xf9, 0x8f}; CHECK_THROWS_AS(json::from_cbor(vec3), json::parse_error&); CHECK_THROWS_WITH(json::from_cbor(vec3), - "[json.exception.parse_error.110] parse error at 3: unexpected end of input"); + "[json.exception.parse_error.110] parse error at byte 3: syntax error while parsing CBOR number: unexpected end of input"); // related test case: incomplete Single-Precision Float (CBOR) std::vector vec4 {0xfa, 0x8f, 0x0a}; CHECK_THROWS_AS(json::from_cbor(vec4), json::parse_error&); CHECK_THROWS_WITH(json::from_cbor(vec4), - "[json.exception.parse_error.110] parse error at 4: unexpected end of input"); + "[json.exception.parse_error.110] parse error at byte 4: syntax error while parsing CBOR number: unexpected end of input"); // related test case: incomplete Double-Precision Float (CBOR) std::vector vec5 {0xfb, 0x8f, 0x0a}; CHECK_THROWS_AS(json::from_cbor(vec5), json::parse_error&); CHECK_THROWS_WITH(json::from_cbor(vec5), - "[json.exception.parse_error.110] parse error at 4: unexpected end of input"); + "[json.exception.parse_error.110] parse error at byte 4: syntax error while parsing CBOR number: unexpected end of input"); } SECTION("issue #408 - Heap-buffer-overflow (OSS-Fuzz issue 344)") @@ -964,7 +972,7 @@ TEST_CASE("regression tests") std::vector vec1 {0x87}; CHECK_THROWS_AS(json::from_msgpack(vec1), json::parse_error&); CHECK_THROWS_WITH(json::from_msgpack(vec1), - "[json.exception.parse_error.110] parse error at 2: unexpected end of input"); + "[json.exception.parse_error.110] parse error at byte 2: syntax error while parsing MessagePack string: unexpected end of input"); // more test cases for MessagePack for (auto b : @@ -998,10 +1006,10 @@ TEST_CASE("regression tests") std::vector vec2; CHECK_THROWS_AS(json::from_cbor(vec2), json::parse_error&); CHECK_THROWS_WITH(json::from_cbor(vec2), - "[json.exception.parse_error.110] parse error at 1: unexpected end of input"); + "[json.exception.parse_error.110] parse error at byte 1: syntax error while parsing CBOR value: unexpected end of input"); CHECK_THROWS_AS(json::from_msgpack(vec2), json::parse_error&); CHECK_THROWS_WITH(json::from_msgpack(vec2), - "[json.exception.parse_error.110] parse error at 1: unexpected end of input"); + "[json.exception.parse_error.110] parse error at byte 1: syntax error while parsing MessagePack value: unexpected end of input"); } SECTION("issue #411 - Heap-buffer-overflow (OSS-Fuzz issue 366)") @@ -1010,19 +1018,19 @@ TEST_CASE("regression tests") std::vector vec1 {0x7f}; CHECK_THROWS_AS(json::from_cbor(vec1), json::parse_error&); CHECK_THROWS_WITH(json::from_cbor(vec1), - "[json.exception.parse_error.110] parse error at 2: unexpected end of input"); + "[json.exception.parse_error.110] parse error at byte 2: syntax error while parsing CBOR string: unexpected end of input"); // related test case: empty array (indefinite length) std::vector vec2 {0x9f}; CHECK_THROWS_AS(json::from_cbor(vec2), json::parse_error&); CHECK_THROWS_WITH(json::from_cbor(vec2), - "[json.exception.parse_error.110] parse error at 2: unexpected end of input"); + "[json.exception.parse_error.110] parse error at byte 2: syntax error while parsing CBOR value: unexpected end of input"); // related test case: empty map (indefinite length) std::vector vec3 {0xbf}; CHECK_THROWS_AS(json::from_cbor(vec3), json::parse_error&); CHECK_THROWS_WITH(json::from_cbor(vec3), - "[json.exception.parse_error.110] parse error at 2: unexpected end of input"); + "[json.exception.parse_error.110] parse error at byte 2: syntax error while parsing CBOR string: unexpected end of input"); } SECTION("issue #412 - Heap-buffer-overflow (OSS-Fuzz issue 367)") @@ -1050,25 +1058,25 @@ TEST_CASE("regression tests") }; CHECK_THROWS_AS(json::from_cbor(vec), json::parse_error&); CHECK_THROWS_WITH(json::from_cbor(vec), - "[json.exception.parse_error.113] parse error at 2: expected a CBOR string; last byte: 0x98"); + "[json.exception.parse_error.113] parse error at byte 2: syntax error while parsing CBOR string: expected length specification (0x60-0x7B) or indefinite string type (0x7F); last byte: 0x98"); // related test case: nonempty UTF-8 string (indefinite length) std::vector vec1 {0x7f, 0x61, 0x61}; CHECK_THROWS_AS(json::from_cbor(vec1), json::parse_error&); CHECK_THROWS_WITH(json::from_cbor(vec1), - "[json.exception.parse_error.110] parse error at 4: unexpected end of input"); + "[json.exception.parse_error.110] parse error at byte 4: syntax error while parsing CBOR string: unexpected end of input"); // related test case: nonempty array (indefinite length) std::vector vec2 {0x9f, 0x01}; CHECK_THROWS_AS(json::from_cbor(vec2), json::parse_error&); CHECK_THROWS_WITH(json::from_cbor(vec2), - "[json.exception.parse_error.110] parse error at 3: unexpected end of input"); + "[json.exception.parse_error.110] parse error at byte 3: syntax error while parsing CBOR value: unexpected end of input"); // related test case: nonempty map (indefinite length) std::vector vec3 {0xbf, 0x61, 0x61, 0x01}; CHECK_THROWS_AS(json::from_cbor(vec3), json::parse_error&); CHECK_THROWS_WITH(json::from_cbor(vec3), - "[json.exception.parse_error.110] parse error at 5: unexpected end of input"); + "[json.exception.parse_error.110] parse error at byte 5: syntax error while parsing CBOR string: unexpected end of input"); } SECTION("issue #414 - compare with literal 0)") @@ -1103,7 +1111,7 @@ TEST_CASE("regression tests") }; CHECK_THROWS_AS(json::from_cbor(vec1), json::parse_error&); CHECK_THROWS_WITH(json::from_cbor(vec1), - "[json.exception.parse_error.113] parse error at 13: expected a CBOR string; last byte: 0xB4"); + "[json.exception.parse_error.113] parse error at byte 13: syntax error while parsing CBOR string: expected length specification (0x60-0x7B) or indefinite string type (0x7F); last byte: 0xB4"); // related test case: double-precision std::vector vec2 @@ -1117,7 +1125,7 @@ TEST_CASE("regression tests") }; CHECK_THROWS_AS(json::from_cbor(vec2), json::parse_error&); CHECK_THROWS_WITH(json::from_cbor(vec2), - "[json.exception.parse_error.113] parse error at 13: expected a CBOR string; last byte: 0xB4"); + "[json.exception.parse_error.113] parse error at byte 13: syntax error while parsing CBOR string: expected length specification (0x60-0x7B) or indefinite string type (0x7F); last byte: 0xB4"); } SECTION("issue #452 - Heap-buffer-overflow (OSS-Fuzz issue 585)") @@ -1427,20 +1435,26 @@ TEST_CASE("regression tests") } })"_json; - CHECK_THROWS_AS(model.patch(R"([{"op": "move", - "from": "/one/two/three", - "path": "/a/b/c"}])"_json), json::out_of_range&); - CHECK_THROWS_WITH(model.patch(R"([{"op": "move", - "from": "/one/two/three", - "path": "/a/b/c"}])"_json), + auto p1 = R"([{"op": "move", + "from": "/one/two/three", + "path": "/a/b/c"}])"_json; + CHECK_THROWS_AS(model.patch(p1), json::out_of_range&); + + auto p2 = R"([{"op": "move", + "from": "/one/two/three", + "path": "/a/b/c"}])"_json; + CHECK_THROWS_WITH(model.patch(p2), "[json.exception.out_of_range.403] key 'a' not found"); - CHECK_THROWS_AS(model.patch(R"([{"op": "copy", + auto p3 = R"([{"op": "copy", + "from": "/one/two/three", + "path": "/a/b/c"}])"_json; + CHECK_THROWS_AS(model.patch(p3), json::out_of_range&); + + auto p4 = R"([{"op": "copy", "from": "/one/two/three", - "path": "/a/b/c"}])"_json), json::out_of_range&); - CHECK_THROWS_WITH(model.patch(R"([{"op": "copy", - "from": "/one/two/three", - "path": "/a/b/c"}])"_json), + "path": "/a/b/c"}])"_json; + CHECK_THROWS_WITH(model.patch(p4), "[json.exception.out_of_range.403] key 'a' not found"); } @@ -1643,4 +1657,12 @@ TEST_CASE("regression tests") CHECK(diffs.size() == 1); // Note the change here, was 2 } + +#ifdef JSON_HAS_CPP_17 + SECTION("issue #1292 - Serializing std::variant causes stack overflow") + { + static_assert( + not std::is_constructible>::value, ""); + } +#endif } diff --git a/test/src/unit-serialization.cpp b/test/src/unit-serialization.cpp index f2861c42..0eed7246 100644 --- a/test/src/unit-serialization.cpp +++ b/test/src/unit-serialization.cpp @@ -1,7 +1,7 @@ /* __ _____ _____ _____ __| | __| | | | JSON for Modern C++ (test suite) -| | |__ | | | | | | version 3.2.0 +| | |__ | | | | | | version 3.3.0 |_____|_____|_____|_|___| https://github.com/nlohmann/json Licensed under the MIT License . diff --git a/test/src/unit-testsuites.cpp b/test/src/unit-testsuites.cpp index 237eb34e..caa6ee3e 100644 --- a/test/src/unit-testsuites.cpp +++ b/test/src/unit-testsuites.cpp @@ -1,7 +1,7 @@ /* __ _____ _____ _____ __| | __| | | | JSON for Modern C++ (test suite) -| | |__ | | | | | | version 3.2.0 +| | |__ | | | | | | version 3.3.0 |_____|_____|_____|_|___| https://github.com/nlohmann/json Licensed under the MIT License . @@ -405,7 +405,7 @@ TEST_CASE("RFC 7159 examples") SECTION("13 Examples") { { - CHECK_NOTHROW(json(R"( + auto json_contents = R"( { "Image": { "Width": 800, @@ -420,11 +420,13 @@ TEST_CASE("RFC 7159 examples") "IDs": [116, 943, 234, 38793] } } - )")); + )"; + + CHECK_NOTHROW(json(json_contents)); } { - CHECK_NOTHROW(json(R"( + auto json_contents = R"( [ { "precision": "zip", @@ -446,7 +448,8 @@ TEST_CASE("RFC 7159 examples") "Zip": "94085", "Country": "US" } - ])")); + ])"; + CHECK_NOTHROW(json(json_contents)); } CHECK(json::parse("\"Hello world!\"") == json("Hello world!")); @@ -1343,13 +1346,11 @@ TEST_CASE("Big List of Naughty Strings") SECTION("roundtripping") { std::ifstream f("test/data/big-list-of-naughty-strings/blns.json"); + std::string line; - while (not f.eof()) + // read lines one by one, bail out on error or eof + while (getline(f, line)) { - // read line - std::string line; - getline(f, line); - // trim whitespace line = trim(line); diff --git a/test/src/unit-to_chars.cpp b/test/src/unit-to_chars.cpp index d4431765..f6016a6c 100644 --- a/test/src/unit-to_chars.cpp +++ b/test/src/unit-to_chars.cpp @@ -1,7 +1,7 @@ /* __ _____ _____ _____ __| | __| | | | JSON for Modern C++ (test suite) -| | |__ | | | | | | version 3.2.0 +| | |__ | | | | | | version 3.3.0 |_____|_____|_____|_|___| https://github.com/nlohmann/json Licensed under the MIT License . diff --git a/test/src/unit-ubjson.cpp b/test/src/unit-ubjson.cpp index abae230b..ba0d23da 100644 --- a/test/src/unit-ubjson.cpp +++ b/test/src/unit-ubjson.cpp @@ -1,7 +1,7 @@ /* __ _____ _____ _____ __| | __| | | | JSON for Modern C++ (test suite) -| | |__ | | | | | | version 3.2.0 +| | |__ | | | | | | version 3.3.0 |_____|_____|_____|_|___| https://github.com/nlohmann/json Licensed under the MIT License . @@ -1299,7 +1299,7 @@ TEST_CASE("UBJSON") { CHECK_THROWS_AS(json::from_ubjson(vec), json::parse_error&); CHECK_THROWS_WITH(json::from_ubjson(vec), - "[json.exception.parse_error.110] parse error at 2: expected end of input"); + "[json.exception.parse_error.110] parse error at byte 2: syntax error while parsing UBJSON value: expected end of input; last byte: 0x5A"); } } @@ -1308,7 +1308,7 @@ TEST_CASE("UBJSON") // larger than max int64 json j = 9223372036854775808llu; CHECK_THROWS_AS(json::to_ubjson(j), json::out_of_range&); - CHECK_THROWS_WITH(json::to_ubjson(j), "[json.exception.out_of_range.407] number overflow serializing 9223372036854775808"); + CHECK_THROWS_WITH(json::to_ubjson(j), "[json.exception.out_of_range.407] integer number 9223372036854775808 cannot be represented by UBJSON as it does not fit int64"); } SECTION("excessive size") @@ -1529,7 +1529,7 @@ TEST_CASE("UBJSON") { CHECK_THROWS_AS(json::from_ubjson(std::vector()), json::parse_error&); CHECK_THROWS_WITH(json::from_ubjson(std::vector()), - "[json.exception.parse_error.110] parse error at 1: unexpected end of input"); + "[json.exception.parse_error.110] parse error at byte 1: syntax error while parsing UBJSON value: unexpected end of input"); } SECTION("char") @@ -1538,14 +1538,14 @@ TEST_CASE("UBJSON") { std::vector v = {'C'}; CHECK_THROWS_AS(json::from_ubjson(v), json::parse_error&); - CHECK_THROWS_WITH(json::from_ubjson(v), "[json.exception.parse_error.110] parse error at 2: unexpected end of input"); + CHECK_THROWS_WITH(json::from_ubjson(v), "[json.exception.parse_error.110] parse error at byte 2: syntax error while parsing UBJSON char: unexpected end of input"); } SECTION("byte out of range") { std::vector v = {'C', 130}; CHECK_THROWS_AS(json::from_ubjson(v), json::parse_error&); - CHECK_THROWS_WITH(json::from_ubjson(v), "[json.exception.parse_error.113] parse error at 2: byte after 'C' must be in range 0x00..0x7F; last byte: 0x82"); + CHECK_THROWS_WITH(json::from_ubjson(v), "[json.exception.parse_error.113] parse error at byte 2: syntax error while parsing UBJSON char: byte after 'C' must be in range 0x00..0x7F; last byte: 0x82"); } } @@ -1555,14 +1555,14 @@ TEST_CASE("UBJSON") { std::vector v = {'S'}; CHECK_THROWS_AS(json::from_ubjson(v), json::parse_error&); - CHECK_THROWS_WITH(json::from_ubjson(v), "[json.exception.parse_error.110] parse error at 2: unexpected end of input"); + CHECK_THROWS_WITH(json::from_ubjson(v), "[json.exception.parse_error.110] parse error at byte 2: syntax error while parsing UBJSON value: unexpected end of input"); } SECTION("invalid byte") { std::vector v = {'S', '1', 'a'}; CHECK_THROWS_AS(json::from_ubjson(v), json::parse_error&); - CHECK_THROWS_WITH(json::from_ubjson(v), "[json.exception.parse_error.113] parse error at 2: expected a UBJSON string; last byte: 0x31"); + CHECK_THROWS_WITH(json::from_ubjson(v), "[json.exception.parse_error.113] parse error at byte 2: syntax error while parsing UBJSON string: expected length type specification (U, i, I, l, L); last byte: 0x31"); } } @@ -1572,7 +1572,7 @@ TEST_CASE("UBJSON") { std::vector v = {'[', '$', 'i', 2}; CHECK_THROWS_AS(json::from_ubjson(v), json::parse_error&); - CHECK_THROWS_WITH(json::from_ubjson(v), "[json.exception.parse_error.112] parse error at 4: expected '#' after UBJSON type information; last byte: 0x02"); + CHECK_THROWS_WITH(json::from_ubjson(v), "[json.exception.parse_error.112] parse error at byte 4: syntax error while parsing UBJSON size: expected '#' after type information; last byte: 0x02"); } } @@ -1580,17 +1580,17 @@ TEST_CASE("UBJSON") { std::vector vS = {'S'}; CHECK_THROWS_AS(json::from_ubjson(vS), json::parse_error&); - CHECK_THROWS_WITH(json::from_ubjson(vS), "[json.exception.parse_error.110] parse error at 2: unexpected end of input"); + CHECK_THROWS_WITH(json::from_ubjson(vS), "[json.exception.parse_error.110] parse error at byte 2: syntax error while parsing UBJSON value: unexpected end of input"); CHECK(json::from_ubjson(vS, true, false).is_discarded()); std::vector v = {'S', 'i', '2', 'a'}; CHECK_THROWS_AS(json::from_ubjson(v), json::parse_error&); - CHECK_THROWS_WITH(json::from_ubjson(v), "[json.exception.parse_error.110] parse error at 5: unexpected end of input"); + CHECK_THROWS_WITH(json::from_ubjson(v), "[json.exception.parse_error.110] parse error at byte 5: syntax error while parsing UBJSON string: unexpected end of input"); CHECK(json::from_ubjson(v, true, false).is_discarded()); std::vector vC = {'C'}; CHECK_THROWS_AS(json::from_ubjson(vC), json::parse_error&); - CHECK_THROWS_WITH(json::from_ubjson(vC), "[json.exception.parse_error.110] parse error at 2: unexpected end of input"); + CHECK_THROWS_WITH(json::from_ubjson(vC), "[json.exception.parse_error.110] parse error at byte 2: syntax error while parsing UBJSON char: unexpected end of input"); CHECK(json::from_ubjson(vC, true, false).is_discarded()); } @@ -1598,32 +1598,32 @@ TEST_CASE("UBJSON") { std::vector vU = {'[', '#', 'U'}; CHECK_THROWS_AS(json::from_ubjson(vU), json::parse_error&); - CHECK_THROWS_WITH(json::from_ubjson(vU), "[json.exception.parse_error.110] parse error at 4: unexpected end of input"); + CHECK_THROWS_WITH(json::from_ubjson(vU), "[json.exception.parse_error.110] parse error at byte 4: syntax error while parsing UBJSON number: unexpected end of input"); CHECK(json::from_ubjson(vU, true, false).is_discarded()); std::vector vi = {'[', '#', 'i'}; CHECK_THROWS_AS(json::from_ubjson(vi), json::parse_error&); - CHECK_THROWS_WITH(json::from_ubjson(vi), "[json.exception.parse_error.110] parse error at 4: unexpected end of input"); + CHECK_THROWS_WITH(json::from_ubjson(vi), "[json.exception.parse_error.110] parse error at byte 4: syntax error while parsing UBJSON number: unexpected end of input"); CHECK(json::from_ubjson(vi, true, false).is_discarded()); std::vector vI = {'[', '#', 'I'}; CHECK_THROWS_AS(json::from_ubjson(vI), json::parse_error&); - CHECK_THROWS_WITH(json::from_ubjson(vI), "[json.exception.parse_error.110] parse error at 4: unexpected end of input"); + CHECK_THROWS_WITH(json::from_ubjson(vI), "[json.exception.parse_error.110] parse error at byte 4: syntax error while parsing UBJSON number: unexpected end of input"); CHECK(json::from_ubjson(vI, true, false).is_discarded()); std::vector vl = {'[', '#', 'l'}; CHECK_THROWS_AS(json::from_ubjson(vl), json::parse_error&); - CHECK_THROWS_WITH(json::from_ubjson(vl), "[json.exception.parse_error.110] parse error at 4: unexpected end of input"); + CHECK_THROWS_WITH(json::from_ubjson(vl), "[json.exception.parse_error.110] parse error at byte 4: syntax error while parsing UBJSON number: unexpected end of input"); CHECK(json::from_ubjson(vl, true, false).is_discarded()); std::vector vL = {'[', '#', 'L'}; CHECK_THROWS_AS(json::from_ubjson(vL), json::parse_error&); - CHECK_THROWS_WITH(json::from_ubjson(vL), "[json.exception.parse_error.110] parse error at 4: unexpected end of input"); + CHECK_THROWS_WITH(json::from_ubjson(vL), "[json.exception.parse_error.110] parse error at byte 4: syntax error while parsing UBJSON number: unexpected end of input"); CHECK(json::from_ubjson(vL, true, false).is_discarded()); std::vector v0 = {'[', '#', 'T', ']'}; CHECK_THROWS_AS(json::from_ubjson(v0), json::parse_error&); - CHECK_THROWS_WITH(json::from_ubjson(v0), "[json.exception.parse_error.113] parse error at 3: byte after '#' must denote a number type; last byte: 0x54"); + CHECK_THROWS_WITH(json::from_ubjson(v0), "[json.exception.parse_error.113] parse error at byte 3: syntax error while parsing UBJSON size: expected length type specification (U, i, I, l, L) after '#'; last byte: 0x54"); CHECK(json::from_ubjson(v0, true, false).is_discarded()); } @@ -1631,17 +1631,17 @@ TEST_CASE("UBJSON") { std::vector v0 = {'[', '$'}; CHECK_THROWS_AS(json::from_ubjson(v0), json::parse_error&); - CHECK_THROWS_WITH(json::from_ubjson(v0), "[json.exception.parse_error.110] parse error at 3: unexpected end of input"); + CHECK_THROWS_WITH(json::from_ubjson(v0), "[json.exception.parse_error.110] parse error at byte 3: syntax error while parsing UBJSON type: unexpected end of input"); CHECK(json::from_ubjson(v0, true, false).is_discarded()); std::vector vi = {'[', '$', '#'}; CHECK_THROWS_AS(json::from_ubjson(vi), json::parse_error&); - CHECK_THROWS_WITH(json::from_ubjson(vi), "[json.exception.parse_error.110] parse error at 4: unexpected end of input"); + CHECK_THROWS_WITH(json::from_ubjson(vi), "[json.exception.parse_error.110] parse error at byte 4: syntax error while parsing UBJSON value: unexpected end of input"); CHECK(json::from_ubjson(vi, true, false).is_discarded()); std::vector vT = {'[', '$', 'T'}; CHECK_THROWS_AS(json::from_ubjson(vT), json::parse_error&); - CHECK_THROWS_WITH(json::from_ubjson(vT), "[json.exception.parse_error.110] parse error at 4: unexpected end of input"); + CHECK_THROWS_WITH(json::from_ubjson(vT), "[json.exception.parse_error.110] parse error at byte 4: syntax error while parsing UBJSON value: unexpected end of input"); CHECK(json::from_ubjson(vT, true, false).is_discarded()); } @@ -1649,17 +1649,17 @@ TEST_CASE("UBJSON") { std::vector vST = {'[', '$', 'i', '#', 'i', 2, 1}; CHECK_THROWS_AS(json::from_ubjson(vST), json::parse_error&); - CHECK_THROWS_WITH(json::from_ubjson(vST), "[json.exception.parse_error.110] parse error at 8: unexpected end of input"); + CHECK_THROWS_WITH(json::from_ubjson(vST), "[json.exception.parse_error.110] parse error at byte 8: syntax error while parsing UBJSON number: unexpected end of input"); CHECK(json::from_ubjson(vST, true, false).is_discarded()); std::vector vS = {'[', '#', 'i', 2, 'i', 1}; CHECK_THROWS_AS(json::from_ubjson(vS), json::parse_error&); - CHECK_THROWS_WITH(json::from_ubjson(vS), "[json.exception.parse_error.110] parse error at 7: unexpected end of input"); + CHECK_THROWS_WITH(json::from_ubjson(vS), "[json.exception.parse_error.110] parse error at byte 7: syntax error while parsing UBJSON value: unexpected end of input"); CHECK(json::from_ubjson(vS, true, false).is_discarded()); std::vector v = {'[', 'i', 2, 'i', 1}; CHECK_THROWS_AS(json::from_ubjson(v), json::parse_error&); - CHECK_THROWS_WITH(json::from_ubjson(v), "[json.exception.parse_error.110] parse error at 6: unexpected end of input"); + CHECK_THROWS_WITH(json::from_ubjson(v), "[json.exception.parse_error.110] parse error at byte 6: syntax error while parsing UBJSON value: unexpected end of input"); CHECK(json::from_ubjson(v, true, false).is_discarded()); } @@ -1667,42 +1667,42 @@ TEST_CASE("UBJSON") { std::vector vST = {'{', '$', 'i', '#', 'i', 2, 'i', 1, 'a', 1}; CHECK_THROWS_AS(json::from_ubjson(vST), json::parse_error&); - CHECK_THROWS_WITH(json::from_ubjson(vST), "[json.exception.parse_error.110] parse error at 11: unexpected end of input"); + CHECK_THROWS_WITH(json::from_ubjson(vST), "[json.exception.parse_error.110] parse error at byte 11: syntax error while parsing UBJSON value: unexpected end of input"); CHECK(json::from_ubjson(vST, true, false).is_discarded()); std::vector vT = {'{', '$', 'i', 'i', 1, 'a', 1}; CHECK_THROWS_AS(json::from_ubjson(vT), json::parse_error&); - CHECK_THROWS_WITH(json::from_ubjson(vT), "[json.exception.parse_error.112] parse error at 4: expected '#' after UBJSON type information; last byte: 0x69"); + CHECK_THROWS_WITH(json::from_ubjson(vT), "[json.exception.parse_error.112] parse error at byte 4: syntax error while parsing UBJSON size: expected '#' after type information; last byte: 0x69"); CHECK(json::from_ubjson(vT, true, false).is_discarded()); std::vector vS = {'{', '#', 'i', 2, 'i', 1, 'a', 'i', 1}; CHECK_THROWS_AS(json::from_ubjson(vS), json::parse_error&); - CHECK_THROWS_WITH(json::from_ubjson(vS), "[json.exception.parse_error.110] parse error at 10: unexpected end of input"); + CHECK_THROWS_WITH(json::from_ubjson(vS), "[json.exception.parse_error.110] parse error at byte 10: syntax error while parsing UBJSON value: unexpected end of input"); CHECK(json::from_ubjson(vS, true, false).is_discarded()); std::vector v = {'{', 'i', 1, 'a', 'i', 1}; CHECK_THROWS_AS(json::from_ubjson(v), json::parse_error&); - CHECK_THROWS_WITH(json::from_ubjson(v), "[json.exception.parse_error.110] parse error at 7: unexpected end of input"); + CHECK_THROWS_WITH(json::from_ubjson(v), "[json.exception.parse_error.110] parse error at byte 7: syntax error while parsing UBJSON value: unexpected end of input"); CHECK(json::from_ubjson(v, true, false).is_discarded()); std::vector v2 = {'{', 'i', 1, 'a', 'i', 1, 'i'}; CHECK_THROWS_AS(json::from_ubjson(v2), json::parse_error&); - CHECK_THROWS_WITH(json::from_ubjson(v2), "[json.exception.parse_error.110] parse error at 8: unexpected end of input"); + CHECK_THROWS_WITH(json::from_ubjson(v2), "[json.exception.parse_error.110] parse error at byte 8: syntax error while parsing UBJSON number: unexpected end of input"); CHECK(json::from_ubjson(v2, true, false).is_discarded()); std::vector v3 = {'{', 'i', 1, 'a'}; CHECK_THROWS_AS(json::from_ubjson(v3), json::parse_error&); - CHECK_THROWS_WITH(json::from_ubjson(v3), "[json.exception.parse_error.110] parse error at 5: unexpected end of input"); + CHECK_THROWS_WITH(json::from_ubjson(v3), "[json.exception.parse_error.110] parse error at byte 5: syntax error while parsing UBJSON value: unexpected end of input"); CHECK(json::from_ubjson(v3, true, false).is_discarded()); std::vector vST1 = {'{', '$', 'd', '#', 'i', 2, 'i', 1, 'a'}; CHECK_THROWS_AS(json::from_ubjson(vST1), json::parse_error&); - CHECK_THROWS_WITH(json::from_ubjson(vST1), "[json.exception.parse_error.110] parse error at 10: unexpected end of input"); + CHECK_THROWS_WITH(json::from_ubjson(vST1), "[json.exception.parse_error.110] parse error at byte 10: syntax error while parsing UBJSON number: unexpected end of input"); CHECK(json::from_ubjson(vST1, true, false).is_discarded()); std::vector vST2 = {'{', '#', 'i', 2, 'i', 1, 'a'}; CHECK_THROWS_AS(json::from_ubjson(vST2), json::parse_error&); - CHECK_THROWS_WITH(json::from_ubjson(vST2), "[json.exception.parse_error.110] parse error at 8: unexpected end of input"); + CHECK_THROWS_WITH(json::from_ubjson(vST2), "[json.exception.parse_error.110] parse error at byte 8: syntax error while parsing UBJSON value: unexpected end of input"); CHECK(json::from_ubjson(vST2, true, false).is_discarded()); } } diff --git a/test/src/unit-udt.cpp b/test/src/unit-udt.cpp index f59999ee..fbcf027d 100644 --- a/test/src/unit-udt.cpp +++ b/test/src/unit-udt.cpp @@ -1,7 +1,7 @@ /* __ _____ _____ _____ __| | __| | | | JSON for Modern C++ (test suite) -| | |__ | | | | | | version 3.2.0 +| | |__ | | | | | | version 3.3.0 |_____|_____|_____|_|___| https://github.com/nlohmann/json Licensed under the MIT License . @@ -298,6 +298,19 @@ TEST_CASE("basic usage", "[udt]") CHECK(book == parsed_book); } + SECTION("via explicit calls to get_to") + { + udt::person person; + udt::name name; + + json person_json = big_json["contacts"][0]["person"]; + CHECK(person_json.get_to(person) == sfinae_addict); + + // correct reference gets returned + person_json["name"].get_to(name).m_val = "new name"; + CHECK(name.m_val == "new name"); + } + SECTION("implicit conversions") { const udt::contact_book parsed_book = big_json; @@ -811,3 +824,9 @@ TEST_CASE("Issue #924") CHECK_NOTHROW(j.get()); CHECK_NOTHROW(j.get>()); } + +TEST_CASE("Issue #1237") +{ + struct non_convertible_type {}; + static_assert(not std::is_convertible::value, ""); +} diff --git a/test/src/unit-unicode.cpp b/test/src/unit-unicode.cpp index 083dec1f..4def1a3e 100644 --- a/test/src/unit-unicode.cpp +++ b/test/src/unit-unicode.cpp @@ -1,7 +1,7 @@ /* __ _____ _____ _____ __| | __| | | | JSON for Modern C++ (test suite) -| | |__ | | | | | | version 3.2.0 +| | |__ | | | | | | version 3.3.0 |_____|_____|_____|_|___| https://github.com/nlohmann/json Licensed under the MIT License . @@ -931,31 +931,31 @@ TEST_CASE("Unicode", "[hide]") { CHECK_THROWS_AS(json::parse("\"\\uDC00\\uDC00\""), json::parse_error&); CHECK_THROWS_WITH(json::parse("\"\\uDC00\\uDC00\""), - "[json.exception.parse_error.101] parse error at 7: syntax error - invalid string: surrogate U+DC00..U+DFFF must follow U+D800..U+DBFF; last read: '\"\\uDC00'"); + "[json.exception.parse_error.101] parse error at line 1, column 7: syntax error while parsing value - invalid string: surrogate U+DC00..U+DFFF must follow U+D800..U+DBFF; last read: '\"\\uDC00'"); CHECK_THROWS_AS(json::parse("\"\\uD7FF\\uDC00\""), json::parse_error&); CHECK_THROWS_WITH(json::parse("\"\\uD7FF\\uDC00\""), - "[json.exception.parse_error.101] parse error at 13: syntax error - invalid string: surrogate U+DC00..U+DFFF must follow U+D800..U+DBFF; last read: '\"\\uD7FF\\uDC00'"); + "[json.exception.parse_error.101] parse error at line 1, column 13: syntax error while parsing value - invalid string: surrogate U+DC00..U+DFFF must follow U+D800..U+DBFF; last read: '\"\\uD7FF\\uDC00'"); CHECK_THROWS_AS(json::parse("\"\\uD800]\""), json::parse_error&); CHECK_THROWS_WITH(json::parse("\"\\uD800]\""), - "[json.exception.parse_error.101] parse error at 8: syntax error - invalid string: surrogate U+DC00..U+DFFF must be followed by U+DC00..U+DFFF; last read: '\"\\uD800]'"); + "[json.exception.parse_error.101] parse error at line 1, column 8: syntax error while parsing value - invalid string: surrogate U+DC00..U+DFFF must be followed by U+DC00..U+DFFF; last read: '\"\\uD800]'"); CHECK_THROWS_AS(json::parse("\"\\uD800\\v\""), json::parse_error&); CHECK_THROWS_WITH(json::parse("\"\\uD800\\v\""), - "[json.exception.parse_error.101] parse error at 9: syntax error - invalid string: surrogate U+DC00..U+DFFF must be followed by U+DC00..U+DFFF; last read: '\"\\uD800\\v'"); + "[json.exception.parse_error.101] parse error at line 1, column 9: syntax error while parsing value - invalid string: surrogate U+DC00..U+DFFF must be followed by U+DC00..U+DFFF; last read: '\"\\uD800\\v'"); CHECK_THROWS_AS(json::parse("\"\\uD800\\u123\""), json::parse_error&); CHECK_THROWS_WITH(json::parse("\"\\uD800\\u123\""), - "[json.exception.parse_error.101] parse error at 13: syntax error - invalid string: '\\u' must be followed by 4 hex digits; last read: '\"\\uD800\\u123\"'"); + "[json.exception.parse_error.101] parse error at line 1, column 13: syntax error while parsing value - invalid string: '\\u' must be followed by 4 hex digits; last read: '\"\\uD800\\u123\"'"); CHECK_THROWS_AS(json::parse("\"\\uD800\\uDBFF\""), json::parse_error&); CHECK_THROWS_WITH(json::parse("\"\\uD800\\uDBFF\""), - "[json.exception.parse_error.101] parse error at 13: syntax error - invalid string: surrogate U+DC00..U+DFFF must be followed by U+DC00..U+DFFF; last read: '\"\\uD800\\uDBFF'"); + "[json.exception.parse_error.101] parse error at line 1, column 13: syntax error while parsing value - invalid string: surrogate U+DC00..U+DFFF must be followed by U+DC00..U+DFFF; last read: '\"\\uD800\\uDBFF'"); CHECK_THROWS_AS(json::parse("\"\\uD800\\uE000\""), json::parse_error&); CHECK_THROWS_WITH(json::parse("\"\\uD800\\uE000\""), - "[json.exception.parse_error.101] parse error at 13: syntax error - invalid string: surrogate U+DC00..U+DFFF must be followed by U+DC00..U+DFFF; last read: '\"\\uD800\\uE000'"); + "[json.exception.parse_error.101] parse error at line 1, column 13: syntax error while parsing value - invalid string: surrogate U+DC00..U+DFFF must be followed by U+DC00..U+DFFF; last read: '\"\\uD800\\uE000'"); } } diff --git a/test/src/unit-wstring.cpp b/test/src/unit-wstring.cpp index 3e83c932..9f59b9d0 100644 --- a/test/src/unit-wstring.cpp +++ b/test/src/unit-wstring.cpp @@ -1,7 +1,7 @@ /* __ _____ _____ _____ __| | __| | | | JSON for Modern C++ (test suite) -| | |__ | | | | | | version 3.2.0 +| | |__ | | | | | | version 3.3.0 |_____|_____|_____|_|___| https://github.com/nlohmann/json Licensed under the MIT License . diff --git a/test/src/unit.cpp b/test/src/unit.cpp index 4f26dbdd..1852b993 100644 --- a/test/src/unit.cpp +++ b/test/src/unit.cpp @@ -1,7 +1,7 @@ /* __ _____ _____ _____ __| | __| | | | JSON for Modern C++ (test suite) -| | |__ | | | | | | version 3.2.0 +| | |__ | | | | | | version 3.3.0 |_____|_____|_____|_|___| https://github.com/nlohmann/json Licensed under the MIT License .