From 4f27004dd55c3b7327045f713a2a60e9b98eccc5 Mon Sep 17 00:00:00 2001 From: emvivre Date: Tue, 22 Sep 2015 16:57:18 +0200 Subject: [PATCH 01/61] remove invalid parameter '-stdlib=libc++' in CMakeLists.txt --- CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index a1fb47e8f..16e9f960e 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -16,7 +16,7 @@ if(MSVC) add_definitions(-D_SCL_SECURE_NO_WARNINGS) else(MSVC) set(CMAKE_CXX_FLAGS - "-std=c++11 -stdlib=libc++" + "-std=c++11" ) endif(MSVC) From 746c1a7142ab0a8b26284187563a7b712245315a Mon Sep 17 00:00:00 2001 From: Niels Date: Sat, 17 Oct 2015 12:51:59 +0200 Subject: [PATCH 02/61] cleanup --- README.md | 1 + src/json.hpp | 2 +- src/json.hpp.re2c | 2 +- test/unit.cpp | 2 +- 4 files changed, 4 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index d27b78a7c..76c32d447 100644 --- a/README.md +++ b/README.md @@ -379,6 +379,7 @@ I deeply appreciate the help of the following people. - [Colin Hirsch](https://github.com/ColinH) took care of a small namespace issue. - [Huu Nguyen](https://github.com/whoshuu) correct a variable name in the documentation. - [Silverweed](https://github.com/silverweed) overloaded `parse()` to accept an rvalue reference. +- [dariomt](https://github.com/dariomt) fixed a subtlety in MSVC type support. Thanks a lot for helping out! diff --git a/src/json.hpp b/src/json.hpp index 7e174d720..f3f97ed30 100644 --- a/src/json.hpp +++ b/src/json.hpp @@ -586,7 +586,7 @@ class basic_json private: /// helper for exception-safe object creation template - static T* create( Args&& ... args ) + static T* create(Args&& ... args) { AllocatorType alloc; auto deleter = [&](T * object) diff --git a/src/json.hpp.re2c b/src/json.hpp.re2c index 0ffddd503..ea4034a17 100644 --- a/src/json.hpp.re2c +++ b/src/json.hpp.re2c @@ -589,7 +589,7 @@ class basic_json static T* create(Args&& ... args) { AllocatorType alloc; - auto deleter = [&](T* object) + auto deleter = [&](T * object) { alloc.deallocate(object, 1); }; diff --git a/test/unit.cpp b/test/unit.cpp index 75753c992..c9c1d2e0f 100644 --- a/test/unit.cpp +++ b/test/unit.cpp @@ -9228,7 +9228,7 @@ TEST_CASE("concepts") SECTION("CopyAssignable") { -// STL iterators used by json::iterator don't pass this test in Debug mode + // STL iterators used by json::iterator don't pass this test in Debug mode #if !defined(_MSC_VER) || (_ITERATOR_DEBUG_LEVEL == 0) CHECK(std::is_nothrow_copy_assignable::value); CHECK(std::is_nothrow_copy_assignable::value); From 8162a6e3a38407d57f37f84347301a510eb4db03 Mon Sep 17 00:00:00 2001 From: dariomt Date: Mon, 19 Oct 2015 12:26:38 +0200 Subject: [PATCH 03/61] Apply same change to the re2c file --- src/json.hpp.re2c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/json.hpp.re2c b/src/json.hpp.re2c index 0ffddd503..8a1bea760 100644 --- a/src/json.hpp.re2c +++ b/src/json.hpp.re2c @@ -2385,7 +2385,7 @@ class basic_json template::value - and std::is_const::value + and std::is_const< typename std::remove_pointer::type >::value , int>::type = 0> const PointerType get_ptr() const noexcept { From 652e1caa7669f5d7f679367d202d8c2eff8f4160 Mon Sep 17 00:00:00 2001 From: dariomt Date: Mon, 19 Oct 2015 12:34:10 +0200 Subject: [PATCH 04/61] Apply same change to the re2c file --- src/json.hpp.re2c | 6 ------ 1 file changed, 6 deletions(-) diff --git a/src/json.hpp.re2c b/src/json.hpp.re2c index 0ffddd503..fbdc5a9e9 100644 --- a/src/json.hpp.re2c +++ b/src/json.hpp.re2c @@ -5729,12 +5729,6 @@ class basic_json return anchor != o.anchor; } - /// stream operator - friend std::ostream& operator<<(std::ostream& o, const iterator_wrapper_internal& w) - { - return o << w.value(); - } - /// return key of the iterator typename basic_json::string_t key() const { From ec7a1d834773f9fee90d8ae908a0c9933c5646fc Mon Sep 17 00:00:00 2001 From: Robert Marki Date: Fri, 13 Nov 2015 12:49:26 +0100 Subject: [PATCH 05/61] Fix character skipping after a surrogate pair In a string the first character following a surrogate pair is skipped by the lexer, but the rest of the string is parsed as usual. --- src/json.hpp | 4 ++-- src/json.hpp.re2c | 4 ++-- test/unit.cpp | 5 +++++ 3 files changed, 9 insertions(+), 4 deletions(-) diff --git a/src/json.hpp b/src/json.hpp index 4423c28cb..1e3cd11fd 100644 --- a/src/json.hpp +++ b/src/json.hpp @@ -6856,8 +6856,8 @@ basic_json_parser_59: auto codepoint2 = std::strtoul(std::string(reinterpret_cast (i + 7), 4).c_str(), nullptr, 16); result += to_unicode(codepoint, codepoint2); - // skip the next 11 characters (xxxx\uyyyy) - i += 11; + // skip the next 10 characters (xxxx\uyyyy) + i += 10; } else { diff --git a/src/json.hpp.re2c b/src/json.hpp.re2c index 2fa1a5256..84559240b 100644 --- a/src/json.hpp.re2c +++ b/src/json.hpp.re2c @@ -6162,8 +6162,8 @@ class basic_json auto codepoint2 = std::strtoul(std::string(reinterpret_cast (i + 7), 4).c_str(), nullptr, 16); result += to_unicode(codepoint, codepoint2); - // skip the next 11 characters (xxxx\uyyyy) - i += 11; + // skip the next 10 characters (xxxx\uyyyy) + i += 10; } else { diff --git a/test/unit.cpp b/test/unit.cpp index c9c1d2e0f..86f3a1cef 100644 --- a/test/unit.cpp +++ b/test/unit.cpp @@ -10205,4 +10205,9 @@ TEST_CASE("regression tests") j["string"] = bytes; CHECK(j["string"] == "\u0007\u0007"); } + + SECTION("character following a surrogate pair is skipped") + { + CHECK(json::parse("\"\\ud80c\\udc60abc\"").get() == u8"\U00013060abc"); + } } From 14d8a91f7349baefa83cabc96113a12b9d9848a9 Mon Sep 17 00:00:00 2001 From: Jett Date: Thu, 19 Nov 2015 00:17:36 -0600 Subject: [PATCH 06/61] Replace sprintf with hex function, this fixes #149 --- src/json.hpp | 16 ++++++++++++---- src/json.hpp.re2c | 16 ++++++++++++---- 2 files changed, 24 insertions(+), 8 deletions(-) diff --git a/src/json.hpp b/src/json.hpp index 1e3cd11fd..f985a9bfd 100644 --- a/src/json.hpp +++ b/src/json.hpp @@ -4677,11 +4677,19 @@ class basic_json { if (c >= 0x00 and c <= 0x1f) { + // convert a number 0..15 to its hex representation (0..f) + auto hexify = [](const char v) -> char + { + return (v < 10) ? ('0' + v) : ('a' + v - 10); + }; + // print character c as \uxxxx - sprintf(&result[pos + 1], "u%04x", int(c)); - pos += 6; - // overwrite trailing null character - result[pos] = '\\'; + for(const char m : { 'u', '0', '0', hexify(c >> 4), hexify(c & 0x0f) }) + { + result[++pos] = m; + } + + ++pos; } else { diff --git a/src/json.hpp.re2c b/src/json.hpp.re2c index 84559240b..833cf4c74 100644 --- a/src/json.hpp.re2c +++ b/src/json.hpp.re2c @@ -4677,11 +4677,19 @@ class basic_json { if (c >= 0x00 and c <= 0x1f) { + // convert a number 0..15 to its hex representation (0..f) + auto hexify = [](const char v) -> char + { + return (v < 10) ? ('0' + v) : ('a' + v - 10); + }; + // print character c as \uxxxx - sprintf(&result[pos + 1], "u%04x", int(c)); - pos += 6; - // overwrite trailing null character - result[pos] = '\\'; + for(const char m : { 'u', '0', '0', hexify(c >> 4), hexify(c & 0x0f) }) + { + result[++pos] = m; + } + + ++pos; } else { From 6f8e36ac3dd7d3e0587297d6ecdc8e1b19a863b6 Mon Sep 17 00:00:00 2001 From: Niels Date: Sun, 6 Dec 2015 17:33:47 +0100 Subject: [PATCH 07/61] fixes #136 --- README.md | 1 + src/json.hpp | 20 +++++++++++++++++++- src/json.hpp.re2c | 19 +++++++++++++++++++ 3 files changed, 39 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 76c32d447..0a382e7eb 100644 --- a/README.md +++ b/README.md @@ -380,6 +380,7 @@ I deeply appreciate the help of the following people. - [Huu Nguyen](https://github.com/whoshuu) correct a variable name in the documentation. - [Silverweed](https://github.com/silverweed) overloaded `parse()` to accept an rvalue reference. - [dariomt](https://github.com/dariomt) fixed a subtlety in MSVC type support. +- [ZahlGraf](https://github.com/ZahlGraf) added a workaround that allows compilation using Android NDK. Thanks a lot for helping out! diff --git a/src/json.hpp b/src/json.hpp index 1e3cd11fd..aa262ae3f 100644 --- a/src/json.hpp +++ b/src/json.hpp @@ -70,6 +70,25 @@ Class @ref nlohmann::basic_json is a good entry point for the documentation. using ssize_t = SSIZE_T; #endif +// workaround for Android NDK (see https://github.com/nlohmann/json/issues/136) +#ifdef __ANDROID__ +namespace std +{ +template +std::string to_string(T v) +{ + std::ostringstream ss; + ss << v; + return ss.str(); +} + +inline long double strtold(const char* str, char** str_end) +{ + return strtod(str, str_end); +} +} +#endif + /*! @brief namespace for Niels Lohmann @see https://github.com/nlohmann @@ -6009,7 +6028,6 @@ class basic_json 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, }; - if ((m_limit - m_cursor) < 5) { yyfill(); // LCOV_EXCL_LINE; diff --git a/src/json.hpp.re2c b/src/json.hpp.re2c index 84559240b..88391d61d 100644 --- a/src/json.hpp.re2c +++ b/src/json.hpp.re2c @@ -70,6 +70,25 @@ Class @ref nlohmann::basic_json is a good entry point for the documentation. using ssize_t = SSIZE_T; #endif +// workaround for Android NDK (see https://github.com/nlohmann/json/issues/136) +#ifdef __ANDROID__ +namespace std +{ +template +std::string to_string(T v) +{ + std::ostringstream ss; + ss << v; + return ss.str(); +} + +inline long double strtold(const char* str, char** str_end) +{ + return strtod(str, str_end); +} +} +#endif + /*! @brief namespace for Niels Lohmann @see https://github.com/nlohmann From 72476b4226764500345948301e204e2506c018a2 Mon Sep 17 00:00:00 2001 From: Niels Date: Mon, 7 Dec 2015 20:38:13 +0100 Subject: [PATCH 08/61] cleanup after #153 --- README.md | 1 + src/json.hpp | 2 +- src/json.hpp.re2c | 2 +- 3 files changed, 3 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 0a382e7eb..f3028a4a4 100644 --- a/README.md +++ b/README.md @@ -381,6 +381,7 @@ I deeply appreciate the help of the following people. - [Silverweed](https://github.com/silverweed) overloaded `parse()` to accept an rvalue reference. - [dariomt](https://github.com/dariomt) fixed a subtlety in MSVC type support. - [ZahlGraf](https://github.com/ZahlGraf) added a workaround that allows compilation using Android NDK. +- [Eau Claire](https://github.com/whackashoe) replaced a function that was marked as unsafe by Visual Studio. Thanks a lot for helping out! diff --git a/src/json.hpp b/src/json.hpp index 3e8c873f2..5cc02ecca 100644 --- a/src/json.hpp +++ b/src/json.hpp @@ -2404,7 +2404,7 @@ class basic_json template::value - and std::is_const< typename std::remove_pointer::type >::value + and std::is_const::type>::value , int>::type = 0> const PointerType get_ptr() const noexcept { diff --git a/src/json.hpp.re2c b/src/json.hpp.re2c index a69991498..cb7bb487f 100644 --- a/src/json.hpp.re2c +++ b/src/json.hpp.re2c @@ -2404,7 +2404,7 @@ class basic_json template::value - and std::is_const< typename std::remove_pointer::type >::value + and std::is_const::type>::value , int>::type = 0> const PointerType get_ptr() const noexcept { From 22bc022745991d782069d471f9843542750418fe Mon Sep 17 00:00:00 2001 From: Niels Date: Mon, 7 Dec 2015 21:05:21 +0100 Subject: [PATCH 09/61] added change from #140 --- README.md | 1 + src/json.hpp | 6 ++++-- src/json.hpp.re2c | 6 ++++-- 3 files changed, 9 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index f3028a4a4..47d201cf4 100644 --- a/README.md +++ b/README.md @@ -382,6 +382,7 @@ I deeply appreciate the help of the following people. - [dariomt](https://github.com/dariomt) fixed a subtlety in MSVC type support. - [ZahlGraf](https://github.com/ZahlGraf) added a workaround that allows compilation using Android NDK. - [Eau Claire](https://github.com/whackashoe) replaced a function that was marked as unsafe by Visual Studio. +- [406345](https://github.com/406345) fixed two small warnings. Thanks a lot for helping out! diff --git a/src/json.hpp b/src/json.hpp index 5cc02ecca..bd2b69668 100644 --- a/src/json.hpp +++ b/src/json.hpp @@ -4703,7 +4703,9 @@ class basic_json }; // print character c as \uxxxx - for(const char m : { 'u', '0', '0', hexify(c >> 4), hexify(c & 0x0f) }) + for (const char m : + { 'u', '0', '0', hexify(c >> 4), hexify(c & 0x0f) + }) { result[++pos] = m; } @@ -4937,7 +4939,7 @@ class basic_json static constexpr difference_type end_value = begin_value + 1; /// iterator as signed integer type - difference_type m_it = std::numeric_limits::min(); + difference_type m_it = std::numeric_limits::denorm_min(); }; /*! diff --git a/src/json.hpp.re2c b/src/json.hpp.re2c index cb7bb487f..fcca777f7 100644 --- a/src/json.hpp.re2c +++ b/src/json.hpp.re2c @@ -4703,7 +4703,9 @@ class basic_json }; // print character c as \uxxxx - for(const char m : { 'u', '0', '0', hexify(c >> 4), hexify(c & 0x0f) }) + for (const char m : + { 'u', '0', '0', hexify(c >> 4), hexify(c & 0x0f) + }) { result[++pos] = m; } @@ -4937,7 +4939,7 @@ class basic_json static constexpr difference_type end_value = begin_value + 1; /// iterator as signed integer type - difference_type m_it = std::numeric_limits::min(); + difference_type m_it = std::numeric_limits::denorm_min(); }; /*! From d6771ac79d8453d68fa99a93978f35264565a305 Mon Sep 17 00:00:00 2001 From: Niels Date: Mon, 7 Dec 2015 21:50:27 +0100 Subject: [PATCH 10/61] corrected a username --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 47d201cf4..24e37eafe 100644 --- a/README.md +++ b/README.md @@ -381,7 +381,7 @@ I deeply appreciate the help of the following people. - [Silverweed](https://github.com/silverweed) overloaded `parse()` to accept an rvalue reference. - [dariomt](https://github.com/dariomt) fixed a subtlety in MSVC type support. - [ZahlGraf](https://github.com/ZahlGraf) added a workaround that allows compilation using Android NDK. -- [Eau Claire](https://github.com/whackashoe) replaced a function that was marked as unsafe by Visual Studio. +- [whackashoe](https://github.com/whackashoe) replaced a function that was marked as unsafe by Visual Studio. - [406345](https://github.com/406345) fixed two small warnings. Thanks a lot for helping out! From e0d334c4f1fcea802ef9d869984e6ffebe828fdf Mon Sep 17 00:00:00 2001 From: Niels Date: Mon, 7 Dec 2015 21:53:32 +0100 Subject: [PATCH 11/61] added a comment (see #109) --- README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/README.md b/README.md index 24e37eafe..168410147 100644 --- a/README.md +++ b/README.md @@ -46,6 +46,8 @@ Though it's 2015 already, the support for C++11 is still a bit sparse. Currently - Clang 3.4 - 3.7 - Microsoft Visual C++ 14.0 RC +Note using GCC 4.8, the unit tests cannot be compiled due to a [bug in the preprocessor](https://gcc.gnu.org/bugzilla/show_bug.cgi?id=55971). + I would be happy to learn about other compilers/versions. ## Examples From 9da8770f3acab1d804d71b5b397fdf1fcb8f69e5 Mon Sep 17 00:00:00 2001 From: Niels Date: Mon, 7 Dec 2015 22:27:53 +0100 Subject: [PATCH 12/61] ignore UTF-8 byte order mark (fixes #152) --- src/json.hpp | 444 ++++++++++++++++-------------- src/json.hpp.re2c | 28 +- test/json_nlohmann_tests/bom.json | 3 + test/unit.cpp | 8 + 4 files changed, 271 insertions(+), 212 deletions(-) create mode 100644 test/json_nlohmann_tests/bom.json diff --git a/src/json.hpp b/src/json.hpp index bd2b69668..236499753 100644 --- a/src/json.hpp +++ b/src/json.hpp @@ -4437,6 +4437,8 @@ class basic_json LL(1) parser. The complexity can be higher if the parser callback function @a cb has a super-linear complexity. + @note A UTF-8 byte order mark is silently ignored. + @liveexample{The example below demonstrates the parse function with and without callback function.,parse__string__parser_callback_t} @@ -4462,6 +4464,8 @@ class basic_json LL(1) parser. The complexity can be higher if the parser callback function @a cb has a super-linear complexity. + @note A UTF-8 byte order mark is silently ignored. + @liveexample{The example below demonstrates the parse function with and without callback function.,parse__istream__parser_callback_t} @@ -4491,6 +4495,8 @@ class basic_json @complexity Linear in the length of the input. The parser is a predictive LL(1) parser. + @note A UTF-8 byte order mark is silently ignored. + @liveexample{The example below shows how a JSON value is constructed by reading a serialization from a stream.,operator_deserialize} @@ -6043,7 +6049,7 @@ class basic_json yyfill(); // LCOV_EXCL_LINE; } yych = *m_cursor; - if (yych <= '9') + if (yych <= ':') { if (yych <= ' ') { @@ -6051,11 +6057,11 @@ class basic_json { if (yych <= 0x00) { - goto basic_json_parser_27; + goto basic_json_parser_28; } if (yych <= 0x08) { - goto basic_json_parser_29; + goto basic_json_parser_30; } if (yych >= '\n') { @@ -6070,7 +6076,7 @@ class basic_json } if (yych <= 0x1F) { - goto basic_json_parser_29; + goto basic_json_parser_30; } } } @@ -6080,86 +6086,100 @@ class basic_json { if (yych == '"') { - goto basic_json_parser_26; + goto basic_json_parser_27; } if (yych <= '+') { - goto basic_json_parser_29; + goto basic_json_parser_30; } - goto basic_json_parser_14; + goto basic_json_parser_16; } else { - if (yych <= '-') - { - goto basic_json_parser_22; - } if (yych <= '/') { - goto basic_json_parser_29; + if (yych <= '-') + { + goto basic_json_parser_23; + } + goto basic_json_parser_30; } - if (yych <= '0') + else { - goto basic_json_parser_23; + if (yych <= '0') + { + goto basic_json_parser_24; + } + if (yych <= '9') + { + goto basic_json_parser_26; + } + goto basic_json_parser_18; } - goto basic_json_parser_25; } } } else { - if (yych <= 'm') + if (yych <= 'n') { - if (yych <= '\\') + if (yych <= ']') { - if (yych <= ':') - { - goto basic_json_parser_16; - } if (yych == '[') - { - goto basic_json_parser_6; - } - goto basic_json_parser_29; - } - else - { - if (yych <= ']') { goto basic_json_parser_8; } + if (yych <= '\\') + { + goto basic_json_parser_30; + } + goto basic_json_parser_10; + } + else + { if (yych == 'f') { - goto basic_json_parser_21; + goto basic_json_parser_22; } - goto basic_json_parser_29; + if (yych <= 'm') + { + goto basic_json_parser_30; + } + goto basic_json_parser_20; } } else { - if (yych <= 'z') + if (yych <= '{') { - if (yych <= 'n') - { - goto basic_json_parser_18; - } if (yych == 't') { - goto basic_json_parser_20; + goto basic_json_parser_21; } - goto basic_json_parser_29; + if (yych <= 'z') + { + goto basic_json_parser_30; + } + goto basic_json_parser_12; } else { - if (yych <= '{') + if (yych <= '}') { - goto basic_json_parser_10; + if (yych <= '|') + { + goto basic_json_parser_30; + } + goto basic_json_parser_14; } - if (yych == '}') + else { - goto basic_json_parser_12; + if (yych == 0xEF) + { + goto basic_json_parser_6; + } + goto basic_json_parser_30; } - goto basic_json_parser_29; } } } @@ -6185,154 +6205,162 @@ basic_json_parser_5: } goto basic_json_parser_3; basic_json_parser_6: - ++m_cursor; + yyaccept = 0; + yych = *(m_marker = ++m_cursor); + if (yych == 0xBB) { - return token_type::begin_array; + goto basic_json_parser_64; + } +basic_json_parser_7: + { + return token_type::parse_error; } basic_json_parser_8: ++m_cursor; { - return token_type::end_array; + return token_type::begin_array; } basic_json_parser_10: ++m_cursor; { - return token_type::begin_object; + return token_type::end_array; } basic_json_parser_12: ++m_cursor; { - return token_type::end_object; + return token_type::begin_object; } basic_json_parser_14: ++m_cursor; { - return token_type::value_separator; + return token_type::end_object; } basic_json_parser_16: ++m_cursor; { - return token_type::name_separator; + return token_type::value_separator; } basic_json_parser_18: - yyaccept = 0; - yych = *(m_marker = ++m_cursor); - if (yych == 'u') + ++m_cursor; { - goto basic_json_parser_59; - } -basic_json_parser_19: - { - return token_type::parse_error; + return token_type::name_separator; } basic_json_parser_20: + yyaccept = 0; + yych = *(m_marker = ++m_cursor); + if (yych == 'u') + { + goto basic_json_parser_60; + } + goto basic_json_parser_7; +basic_json_parser_21: yyaccept = 0; yych = *(m_marker = ++m_cursor); if (yych == 'r') { - goto basic_json_parser_55; + goto basic_json_parser_56; } - goto basic_json_parser_19; -basic_json_parser_21: + goto basic_json_parser_7; +basic_json_parser_22: yyaccept = 0; yych = *(m_marker = ++m_cursor); if (yych == 'a') { - goto basic_json_parser_50; + goto basic_json_parser_51; } - goto basic_json_parser_19; -basic_json_parser_22: + goto basic_json_parser_7; +basic_json_parser_23: yych = *++m_cursor; if (yych <= '/') { - goto basic_json_parser_19; + goto basic_json_parser_7; } if (yych <= '0') { - goto basic_json_parser_49; + goto basic_json_parser_50; } if (yych <= '9') { - goto basic_json_parser_40; + goto basic_json_parser_41; } - goto basic_json_parser_19; -basic_json_parser_23: + goto basic_json_parser_7; +basic_json_parser_24: yyaccept = 1; yych = *(m_marker = ++m_cursor); if (yych <= 'D') { if (yych == '.') { - goto basic_json_parser_42; + goto basic_json_parser_43; } } else { if (yych <= 'E') { - goto basic_json_parser_43; + goto basic_json_parser_44; } if (yych == 'e') { - goto basic_json_parser_43; + goto basic_json_parser_44; } } -basic_json_parser_24: +basic_json_parser_25: { return token_type::value_number; } -basic_json_parser_25: +basic_json_parser_26: yyaccept = 1; yych = *(m_marker = ++m_cursor); - goto basic_json_parser_41; -basic_json_parser_26: + goto basic_json_parser_42; +basic_json_parser_27: yyaccept = 0; yych = *(m_marker = ++m_cursor); if (yych <= 0x0F) { - goto basic_json_parser_19; + goto basic_json_parser_7; } - goto basic_json_parser_31; -basic_json_parser_27: + goto basic_json_parser_32; +basic_json_parser_28: ++m_cursor; { return token_type::end_of_input; } -basic_json_parser_29: - yych = *++m_cursor; - goto basic_json_parser_19; basic_json_parser_30: + yych = *++m_cursor; + goto basic_json_parser_7; +basic_json_parser_31: ++m_cursor; if (m_limit <= m_cursor) { yyfill(); // LCOV_EXCL_LINE; } yych = *m_cursor; -basic_json_parser_31: +basic_json_parser_32: if (yybm[0 + yych] & 64) { - goto basic_json_parser_30; + goto basic_json_parser_31; } if (yych <= 0x0F) { - goto basic_json_parser_32; + goto basic_json_parser_33; } if (yych <= '"') { - goto basic_json_parser_34; + goto basic_json_parser_35; } - goto basic_json_parser_33; -basic_json_parser_32: + goto basic_json_parser_34; +basic_json_parser_33: m_cursor = m_marker; if (yyaccept == 0) { - goto basic_json_parser_19; + goto basic_json_parser_7; } else { - goto basic_json_parser_24; + goto basic_json_parser_25; } -basic_json_parser_33: +basic_json_parser_34: ++m_cursor; if (m_limit <= m_cursor) { @@ -6345,13 +6373,13 @@ basic_json_parser_33: { if (yych == '"') { - goto basic_json_parser_30; + goto basic_json_parser_31; } if (yych <= '.') { - goto basic_json_parser_32; + goto basic_json_parser_33; } - goto basic_json_parser_30; + goto basic_json_parser_31; } else { @@ -6359,17 +6387,17 @@ basic_json_parser_33: { if (yych <= '[') { - goto basic_json_parser_32; + goto basic_json_parser_33; } - goto basic_json_parser_30; + goto basic_json_parser_31; } else { if (yych == 'b') { - goto basic_json_parser_30; + goto basic_json_parser_31; } - goto basic_json_parser_32; + goto basic_json_parser_33; } } } @@ -6379,13 +6407,13 @@ basic_json_parser_33: { if (yych <= 'f') { - goto basic_json_parser_30; + goto basic_json_parser_31; } if (yych == 'n') { - goto basic_json_parser_30; + goto basic_json_parser_31; } - goto basic_json_parser_32; + goto basic_json_parser_33; } else { @@ -6393,62 +6421,29 @@ basic_json_parser_33: { if (yych <= 'r') { - goto basic_json_parser_30; + goto basic_json_parser_31; } - goto basic_json_parser_32; + goto basic_json_parser_33; } else { if (yych <= 't') { - goto basic_json_parser_30; + goto basic_json_parser_31; } if (yych <= 'u') { - goto basic_json_parser_36; + goto basic_json_parser_37; } - goto basic_json_parser_32; + goto basic_json_parser_33; } } } -basic_json_parser_34: +basic_json_parser_35: ++m_cursor; { return token_type::value_string; } -basic_json_parser_36: - ++m_cursor; - if (m_limit <= m_cursor) - { - yyfill(); // LCOV_EXCL_LINE; - } - yych = *m_cursor; - if (yych <= '@') - { - if (yych <= '/') - { - goto basic_json_parser_32; - } - if (yych >= ':') - { - goto basic_json_parser_32; - } - } - else - { - if (yych <= 'F') - { - goto basic_json_parser_37; - } - if (yych <= '`') - { - goto basic_json_parser_32; - } - if (yych >= 'g') - { - goto basic_json_parser_32; - } - } basic_json_parser_37: ++m_cursor; if (m_limit <= m_cursor) @@ -6460,11 +6455,11 @@ basic_json_parser_37: { if (yych <= '/') { - goto basic_json_parser_32; + goto basic_json_parser_33; } if (yych >= ':') { - goto basic_json_parser_32; + goto basic_json_parser_33; } } else @@ -6475,11 +6470,11 @@ basic_json_parser_37: } if (yych <= '`') { - goto basic_json_parser_32; + goto basic_json_parser_33; } if (yych >= 'g') { - goto basic_json_parser_32; + goto basic_json_parser_33; } } basic_json_parser_38: @@ -6493,11 +6488,11 @@ basic_json_parser_38: { if (yych <= '/') { - goto basic_json_parser_32; + goto basic_json_parser_33; } if (yych >= ':') { - goto basic_json_parser_32; + goto basic_json_parser_33; } } else @@ -6508,11 +6503,11 @@ basic_json_parser_38: } if (yych <= '`') { - goto basic_json_parser_32; + goto basic_json_parser_33; } if (yych >= 'g') { - goto basic_json_parser_32; + goto basic_json_parser_33; } } basic_json_parser_39: @@ -6526,31 +6521,64 @@ basic_json_parser_39: { if (yych <= '/') { - goto basic_json_parser_32; + goto basic_json_parser_33; } - if (yych <= '9') + if (yych >= ':') { - goto basic_json_parser_30; + goto basic_json_parser_33; } - goto basic_json_parser_32; } else { if (yych <= 'F') { - goto basic_json_parser_30; + goto basic_json_parser_40; } if (yych <= '`') { - goto basic_json_parser_32; + goto basic_json_parser_33; + } + if (yych >= 'g') + { + goto basic_json_parser_33; + } + } +basic_json_parser_40: + ++m_cursor; + if (m_limit <= m_cursor) + { + yyfill(); // LCOV_EXCL_LINE; + } + yych = *m_cursor; + if (yych <= '@') + { + if (yych <= '/') + { + goto basic_json_parser_33; + } + if (yych <= '9') + { + goto basic_json_parser_31; + } + goto basic_json_parser_33; + } + else + { + if (yych <= 'F') + { + goto basic_json_parser_31; + } + if (yych <= '`') + { + goto basic_json_parser_33; } if (yych <= 'f') { - goto basic_json_parser_30; + goto basic_json_parser_31; } - goto basic_json_parser_32; + goto basic_json_parser_33; } -basic_json_parser_40: +basic_json_parser_41: yyaccept = 1; m_marker = ++m_cursor; if ((m_limit - m_cursor) < 3) @@ -6558,77 +6586,77 @@ basic_json_parser_40: yyfill(); // LCOV_EXCL_LINE; } yych = *m_cursor; -basic_json_parser_41: +basic_json_parser_42: if (yybm[0 + yych] & 128) { - goto basic_json_parser_40; + goto basic_json_parser_41; } if (yych <= 'D') { if (yych != '.') { - goto basic_json_parser_24; + goto basic_json_parser_25; } } else { if (yych <= 'E') { - goto basic_json_parser_43; + goto basic_json_parser_44; } if (yych == 'e') { - goto basic_json_parser_43; + goto basic_json_parser_44; } - goto basic_json_parser_24; + goto basic_json_parser_25; } -basic_json_parser_42: +basic_json_parser_43: yych = *++m_cursor; if (yych <= '/') { - goto basic_json_parser_32; + goto basic_json_parser_33; } if (yych <= '9') { - goto basic_json_parser_47; + goto basic_json_parser_48; } - goto basic_json_parser_32; -basic_json_parser_43: + goto basic_json_parser_33; +basic_json_parser_44: yych = *++m_cursor; if (yych <= ',') { if (yych != '+') { - goto basic_json_parser_32; + goto basic_json_parser_33; } } else { if (yych <= '-') { - goto basic_json_parser_44; + goto basic_json_parser_45; } if (yych <= '/') { - goto basic_json_parser_32; + goto basic_json_parser_33; } if (yych <= '9') { - goto basic_json_parser_45; + goto basic_json_parser_46; } - goto basic_json_parser_32; + goto basic_json_parser_33; } -basic_json_parser_44: +basic_json_parser_45: yych = *++m_cursor; if (yych <= '/') { - goto basic_json_parser_32; + goto basic_json_parser_33; } if (yych >= ':') { - goto basic_json_parser_32; + goto basic_json_parser_33; } -basic_json_parser_45: +basic_json_parser_46: ++m_cursor; if (m_limit <= m_cursor) { @@ -6637,14 +6665,14 @@ basic_json_parser_45: yych = *m_cursor; if (yych <= '/') { - goto basic_json_parser_24; + goto basic_json_parser_25; } if (yych <= '9') { - goto basic_json_parser_45; + goto basic_json_parser_46; } - goto basic_json_parser_24; -basic_json_parser_47: + goto basic_json_parser_25; +basic_json_parser_48: yyaccept = 1; m_marker = ++m_cursor; if ((m_limit - m_cursor) < 3) @@ -6656,99 +6684,109 @@ basic_json_parser_47: { if (yych <= '/') { - goto basic_json_parser_24; + goto basic_json_parser_25; } if (yych <= '9') { - goto basic_json_parser_47; + goto basic_json_parser_48; } - goto basic_json_parser_24; + goto basic_json_parser_25; } else { if (yych <= 'E') { - goto basic_json_parser_43; + goto basic_json_parser_44; } if (yych == 'e') { - goto basic_json_parser_43; + goto basic_json_parser_44; } - goto basic_json_parser_24; + goto basic_json_parser_25; } -basic_json_parser_49: +basic_json_parser_50: yyaccept = 1; yych = *(m_marker = ++m_cursor); if (yych <= 'D') { if (yych == '.') { - goto basic_json_parser_42; + goto basic_json_parser_43; } - goto basic_json_parser_24; + goto basic_json_parser_25; } else { if (yych <= 'E') { - goto basic_json_parser_43; + goto basic_json_parser_44; } if (yych == 'e') { - goto basic_json_parser_43; + goto basic_json_parser_44; } - goto basic_json_parser_24; + goto basic_json_parser_25; } -basic_json_parser_50: +basic_json_parser_51: yych = *++m_cursor; if (yych != 'l') { - goto basic_json_parser_32; + goto basic_json_parser_33; } yych = *++m_cursor; if (yych != 's') { - goto basic_json_parser_32; + goto basic_json_parser_33; } yych = *++m_cursor; if (yych != 'e') { - goto basic_json_parser_32; + goto basic_json_parser_33; } ++m_cursor; { return token_type::literal_false; } -basic_json_parser_55: +basic_json_parser_56: yych = *++m_cursor; if (yych != 'u') { - goto basic_json_parser_32; + goto basic_json_parser_33; } yych = *++m_cursor; if (yych != 'e') { - goto basic_json_parser_32; + goto basic_json_parser_33; } ++m_cursor; { return token_type::literal_true; } -basic_json_parser_59: +basic_json_parser_60: yych = *++m_cursor; if (yych != 'l') { - goto basic_json_parser_32; + goto basic_json_parser_33; } yych = *++m_cursor; if (yych != 'l') { - goto basic_json_parser_32; + goto basic_json_parser_33; } ++m_cursor; { return token_type::literal_null; } +basic_json_parser_64: + yych = *++m_cursor; + if (yych != 0xBF) + { + goto basic_json_parser_33; + } + ++m_cursor; + { + return scan(); + } } diff --git a/src/json.hpp.re2c b/src/json.hpp.re2c index fcca777f7..da03e0fa3 100644 --- a/src/json.hpp.re2c +++ b/src/json.hpp.re2c @@ -4437,6 +4437,8 @@ class basic_json LL(1) parser. The complexity can be higher if the parser callback function @a cb has a super-linear complexity. + @note A UTF-8 byte order mark is silently ignored. + @liveexample{The example below demonstrates the parse function with and without callback function.,parse__string__parser_callback_t} @@ -4462,6 +4464,8 @@ class basic_json LL(1) parser. The complexity can be higher if the parser callback function @a cb has a super-linear complexity. + @note A UTF-8 byte order mark is silently ignored. + @liveexample{The example below demonstrates the parse function with and without callback function.,parse__istream__parser_callback_t} @@ -4491,6 +4495,8 @@ class basic_json @complexity Linear in the length of the input. The parser is a predictive LL(1) parser. + @note A UTF-8 byte order mark is silently ignored. + @liveexample{The example below shows how a JSON value is constructed by reading a serialization from a stream.,operator_deserialize} @@ -6000,20 +6006,24 @@ class basic_json m_start = m_cursor; /*!re2c - re2c:define:YYCTYPE = lexer_char_t; - re2c:define:YYCURSOR = m_cursor; - re2c:define:YYLIMIT = m_limit; - re2c:define:YYMARKER = m_marker; - re2c:define:YYFILL = "yyfill(); // LCOV_EXCL_LINE"; + re2c:define:YYCTYPE = lexer_char_t; + re2c:define:YYCURSOR = m_cursor; + re2c:define:YYLIMIT = m_limit; + re2c:define:YYMARKER = m_marker; + re2c:define:YYFILL = "yyfill(); // LCOV_EXCL_LINE"; re2c:yyfill:parameter = 0; - re2c:indent:string = " "; - re2c:indent:top = 1; - re2c:labelprefix = "basic_json_parser_"; + re2c:indent:string = " "; + re2c:indent:top = 1; + re2c:labelprefix = "basic_json_parser_"; - // whitespace + // ignore whitespace ws = [ \t\n\r]+; ws { return scan(); } + // ignore byte-order-mark + bom = "\xEF\xBB\xBF"; + bom { return scan(); } + // structural characters "[" { return token_type::begin_array; } "]" { return token_type::end_array; } diff --git a/test/json_nlohmann_tests/bom.json b/test/json_nlohmann_tests/bom.json new file mode 100644 index 000000000..9d02f600b --- /dev/null +++ b/test/json_nlohmann_tests/bom.json @@ -0,0 +1,3 @@ +{ + "foo": true +} diff --git a/test/unit.cpp b/test/unit.cpp index 86f3a1cef..56287764d 100644 --- a/test/unit.cpp +++ b/test/unit.cpp @@ -10022,6 +10022,14 @@ TEST_CASE("Unicode", "[hide]") // the array has 1112064 + 1 elemnts (a terminating "null" value) CHECK(j.size() == 1112065); } + + SECTION("ignore byte-order-mark") + { + // read a file with a UTF-8 BOM + std::ifstream f("test/json_nlohmann_tests/bom.json"); + json j; + CHECK_NOTHROW(j << f); + } } TEST_CASE("regression tests") From c767f464bb3df5db6992a8cc5974cfb3f91959ca Mon Sep 17 00:00:00 2001 From: Niels Date: Tue, 8 Dec 2015 18:12:34 +0100 Subject: [PATCH 13/61] dropped GCC 4.8 support (due to #110) --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 168410147..827dd2575 100644 --- a/README.md +++ b/README.md @@ -42,7 +42,7 @@ to the files you want to use JSON objects. That's it. Do not forget to set the n Though it's 2015 already, the support for C++11 is still a bit sparse. Currently, the following compilers are known to work: -- GCC 4.8 - 5.2 +- GCC 4.9 - 5.2 - Clang 3.4 - 3.7 - Microsoft Visual C++ 14.0 RC From a70a7a8001f4d5e1d0ac2b652ba5c1ba04a4b648 Mon Sep 17 00:00:00 2001 From: Niels Date: Sun, 13 Dec 2015 11:26:55 +0100 Subject: [PATCH 14/61] fixed #135: operator[] now only works on nonconst JSON objects --- README.md | 8 +++---- src/json.hpp | 57 ----------------------------------------------- src/json.hpp.re2c | 57 ----------------------------------------------- test/unit.cpp | 26 --------------------- 4 files changed, 3 insertions(+), 145 deletions(-) diff --git a/README.md b/README.md index 827dd2575..a4093fa2a 100644 --- a/README.md +++ b/README.md @@ -42,11 +42,9 @@ to the files you want to use JSON objects. That's it. Do not forget to set the n Though it's 2015 already, the support for C++11 is still a bit sparse. Currently, the following compilers are known to work: -- GCC 4.9 - 5.2 -- Clang 3.4 - 3.7 -- Microsoft Visual C++ 14.0 RC - -Note using GCC 4.8, the unit tests cannot be compiled due to a [bug in the preprocessor](https://gcc.gnu.org/bugzilla/show_bug.cgi?id=55971). +- GCC 4.9 - 5.2 (and possible later) +- Clang 3.4 - 3.7 (and possible later) +- Microsoft Visual C++ 14.0 RC (and possible later) I would be happy to learn about other compilers/versions. diff --git a/src/json.hpp b/src/json.hpp index 236499753..a2053ad04 100644 --- a/src/json.hpp +++ b/src/json.hpp @@ -2691,33 +2691,6 @@ class basic_json Returns a reference to the element at with specified key @a key. - @param[in] key key of the element to access - - @return reference to the element at key @a key - - @throw std::domain_error if JSON is not an object or null - - @complexity Logarithmic in the size of the container. - - @liveexample{The example below shows how object elements can be read using - the [] operator.,operatorarray__key_type_const} - */ - const_reference operator[](const typename object_t::key_type& key) const - { - // at only works for objects - if (m_type != value_t::object) - { - throw std::domain_error("cannot use operator[] with " + type_name()); - } - - return m_value.object->operator[](key); - } - - /*! - @brief access specified object element - - Returns a reference to the element at with specified key @a key. - @note If @a key is not found in the object, then it is silently added to the object and filled with a `null` value to make `key` a valid reference. In case the value was `null` before, it is converted to an object. @@ -2754,36 +2727,6 @@ class basic_json return m_value.object->operator[](key); } - /*! - @brief access specified object element - - Returns a reference to the element at with specified key @a key. - - @note This function is required for compatibility reasons with Clang. - - @param[in] key key of the element to access - - @return reference to the element at key @a key - - @throw std::domain_error if JSON is not an object or null - - @complexity Logarithmic in the size of the container. - - @liveexample{The example below shows how object elements can be read using - the [] operator.,operatorarray__key_type_const} - */ - template - const_reference operator[](const T (&key)[n]) const - { - // at only works for objects - if (m_type != value_t::object) - { - throw std::domain_error("cannot use operator[] with " + type_name()); - } - - return m_value.object->operator[](key); - } - /*! @brief access the first element diff --git a/src/json.hpp.re2c b/src/json.hpp.re2c index da03e0fa3..4f056f34a 100644 --- a/src/json.hpp.re2c +++ b/src/json.hpp.re2c @@ -2691,33 +2691,6 @@ class basic_json Returns a reference to the element at with specified key @a key. - @param[in] key key of the element to access - - @return reference to the element at key @a key - - @throw std::domain_error if JSON is not an object or null - - @complexity Logarithmic in the size of the container. - - @liveexample{The example below shows how object elements can be read using - the [] operator.,operatorarray__key_type_const} - */ - const_reference operator[](const typename object_t::key_type& key) const - { - // at only works for objects - if (m_type != value_t::object) - { - throw std::domain_error("cannot use operator[] with " + type_name()); - } - - return m_value.object->operator[](key); - } - - /*! - @brief access specified object element - - Returns a reference to the element at with specified key @a key. - @note If @a key is not found in the object, then it is silently added to the object and filled with a `null` value to make `key` a valid reference. In case the value was `null` before, it is converted to an object. @@ -2754,36 +2727,6 @@ class basic_json return m_value.object->operator[](key); } - /*! - @brief access specified object element - - Returns a reference to the element at with specified key @a key. - - @note This function is required for compatibility reasons with Clang. - - @param[in] key key of the element to access - - @return reference to the element at key @a key - - @throw std::domain_error if JSON is not an object or null - - @complexity Logarithmic in the size of the container. - - @liveexample{The example below shows how object elements can be read using - the [] operator.,operatorarray__key_type_const} - */ - template - const_reference operator[](const T (&key)[n]) const - { - // at only works for objects - if (m_type != value_t::object) - { - throw std::domain_error("cannot use operator[] with " + type_name()); - } - - return m_value.object->operator[](key); - } - /*! @brief access the first element diff --git a/test/unit.cpp b/test/unit.cpp index 56287764d..efc71ff5f 100644 --- a/test/unit.cpp +++ b/test/unit.cpp @@ -3098,38 +3098,24 @@ TEST_CASE("element access") { CHECK(j["integer"] == json(1)); CHECK(j[json::object_t::key_type("integer")] == j["integer"]); - CHECK(j_const["integer"] == json(1)); - CHECK(j_const[json::object_t::key_type("integer")] == j["integer"]); CHECK(j["boolean"] == json(true)); CHECK(j[json::object_t::key_type("boolean")] == j["boolean"]); - CHECK(j_const["boolean"] == json(true)); - CHECK(j_const[json::object_t::key_type("boolean")] == j["boolean"]); CHECK(j["null"] == json(nullptr)); CHECK(j[json::object_t::key_type("null")] == j["null"]); - CHECK(j_const["null"] == json(nullptr)); - CHECK(j_const[json::object_t::key_type("null")] == j["null"]); CHECK(j["string"] == json("hello world")); CHECK(j[json::object_t::key_type("string")] == j["string"]); - CHECK(j_const["string"] == json("hello world")); - CHECK(j_const[json::object_t::key_type("string")] == j["string"]); CHECK(j["floating"] == json(42.23)); CHECK(j[json::object_t::key_type("floating")] == j["floating"]); - CHECK(j_const["floating"] == json(42.23)); - CHECK(j_const[json::object_t::key_type("floating")] == j["floating"]); CHECK(j["object"] == json(json::object())); CHECK(j[json::object_t::key_type("object")] == j["object"]); - CHECK(j_const["object"] == json(json::object())); - CHECK(j_const[json::object_t::key_type("object")] == j["object"]); CHECK(j["array"] == json({1, 2, 3})); CHECK(j[json::object_t::key_type("array")] == j["array"]); - CHECK(j_const["array"] == json({1, 2, 3})); - CHECK(j_const[json::object_t::key_type("array")] == j["array"]); } SECTION("access on non-object type") @@ -3141,8 +3127,6 @@ TEST_CASE("element access") const json j_const_nonobject(j_nonobject); CHECK_NOTHROW(j_nonobject["foo"]); CHECK_NOTHROW(j_nonobject2[json::object_t::key_type("foo")]); - CHECK_THROWS_AS(j_const_nonobject["foo"], std::domain_error); - CHECK_THROWS_AS(j_const_nonobject[json::object_t::key_type("foo")], std::domain_error); } SECTION("boolean") @@ -3151,8 +3135,6 @@ TEST_CASE("element access") const json j_const_nonobject(j_nonobject); CHECK_THROWS_AS(j_nonobject["foo"], std::domain_error); CHECK_THROWS_AS(j_nonobject[json::object_t::key_type("foo")], std::domain_error); - CHECK_THROWS_AS(j_const_nonobject["foo"], std::domain_error); - CHECK_THROWS_AS(j_const_nonobject[json::object_t::key_type("foo")], std::domain_error); } SECTION("string") @@ -3161,8 +3143,6 @@ TEST_CASE("element access") const json j_const_nonobject(j_nonobject); CHECK_THROWS_AS(j_nonobject["foo"], std::domain_error); CHECK_THROWS_AS(j_nonobject[json::object_t::key_type("foo")], std::domain_error); - CHECK_THROWS_AS(j_const_nonobject["foo"], std::domain_error); - CHECK_THROWS_AS(j_const_nonobject[json::object_t::key_type("foo")], std::domain_error); } SECTION("array") @@ -3171,8 +3151,6 @@ TEST_CASE("element access") const json j_const_nonobject(j_nonobject); CHECK_THROWS_AS(j_nonobject["foo"], std::domain_error); CHECK_THROWS_AS(j_nonobject[json::object_t::key_type("foo")], std::domain_error); - CHECK_THROWS_AS(j_const_nonobject["foo"], std::domain_error); - CHECK_THROWS_AS(j_const_nonobject[json::object_t::key_type("foo")], std::domain_error); } SECTION("number (integer)") @@ -3181,8 +3159,6 @@ TEST_CASE("element access") const json j_const_nonobject(j_nonobject); CHECK_THROWS_AS(j_nonobject["foo"], std::domain_error); CHECK_THROWS_AS(j_nonobject[json::object_t::key_type("foo")], std::domain_error); - CHECK_THROWS_AS(j_const_nonobject["foo"], std::domain_error); - CHECK_THROWS_AS(j_const_nonobject[json::object_t::key_type("foo")], std::domain_error); } SECTION("number (floating-point)") @@ -3191,8 +3167,6 @@ TEST_CASE("element access") const json j_const_nonobject(j_nonobject); CHECK_THROWS_AS(j_nonobject["foo"], std::domain_error); CHECK_THROWS_AS(j_nonobject[json::object_t::key_type("foo")], std::domain_error); - CHECK_THROWS_AS(j_const_nonobject["foo"], std::domain_error); - CHECK_THROWS_AS(j_const_nonobject[json::object_t::key_type("foo")], std::domain_error); } } } From 258f04c561a140effe6b3309f4ecf6f38999ae3a Mon Sep 17 00:00:00 2001 From: Niels Date: Mon, 14 Dec 2015 16:32:37 +0100 Subject: [PATCH 15/61] fixed #154 (no more warnings for incomplete switches) --- Makefile | 2 +- src/json.hpp | 582 ++++++++++++++++++++++++++++------------------ src/json.hpp.re2c | 582 ++++++++++++++++++++++++++++------------------ test/unit.cpp | 40 ++++ 4 files changed, 745 insertions(+), 461 deletions(-) diff --git a/Makefile b/Makefile index 71a1175fd..a83015153 100644 --- a/Makefile +++ b/Makefile @@ -17,7 +17,7 @@ clean: ########################################################################## # additional flags -FLAGS = -Wall -Wextra -pedantic -Weffc++ -Wcast-align -Wcast-qual -Wctor-dtor-privacy -Wdisabled-optimization -Wformat=2 -Winit-self -Wmissing-declarations -Wmissing-include-dirs -Wold-style-cast -Woverloaded-virtual -Wredundant-decls -Wshadow -Wsign-conversion -Wsign-promo -Wstrict-overflow=5 -Wswitch -Wundef -Wno-unused -Wnon-virtual-dtor -Wreorder -Wdeprecated -Wfloat-equal +FLAGS = -Wall -Wextra -pedantic -Weffc++ -Wcast-align -Wcast-qual -Wctor-dtor-privacy -Wdisabled-optimization -Wformat=2 -Winit-self -Wmissing-declarations -Wmissing-include-dirs -Wold-style-cast -Woverloaded-virtual -Wredundant-decls -Wshadow -Wsign-conversion -Wsign-promo -Wstrict-overflow=5 -Wswitch -Wswitch-enum -Wswitch-default -Wundef -Wno-unused -Wnon-virtual-dtor -Wreorder -Wdeprecated -Wfloat-equal # build unit tests json_unit: test/unit.cpp src/json.hpp test/catch.hpp diff --git a/src/json.hpp b/src/json.hpp index a2053ad04..7c2ea01cf 100644 --- a/src/json.hpp +++ b/src/json.hpp @@ -650,47 +650,48 @@ class basic_json { switch (t) { - case (value_t::null): - case (value_t::discarded): - { - break; - } - - case (value_t::object): + case value_t::object: { object = create(); break; } - case (value_t::array): + case value_t::array: { array = create(); break; } - case (value_t::string): + case value_t::string: { string = create(""); break; } - case (value_t::boolean): + case value_t::boolean: { boolean = boolean_t(false); break; } - case (value_t::number_integer): + case value_t::number_integer: { number_integer = number_integer_t(0); break; } - case (value_t::number_float): + case value_t::number_float: { number_float = number_float_t(0.0); break; } + + case value_t::null: + case value_t::discarded: + default: + { + break; + } } } @@ -1481,9 +1482,9 @@ class basic_json // check if iterator range is complete for primitive values switch (m_type) { - case value_t::number_integer: - case value_t::number_float: case value_t::boolean: + case value_t::number_float: + case value_t::number_integer: case value_t::string: { if (not first.m_it.primitive_iterator.is_begin() or not last.m_it.primitive_iterator.is_end()) @@ -1493,6 +1494,10 @@ class basic_json break; } + case value_t::array: + case value_t::discarded: + case value_t::null: + case value_t::object: default: { break; @@ -1537,6 +1542,8 @@ class basic_json break; } + case value_t::discarded: + case value_t::null: default: { throw std::domain_error("cannot use construct with iterators from " + first.m_object->type_name()); @@ -1571,47 +1578,48 @@ class basic_json { switch (m_type) { - case (value_t::null): - case (value_t::discarded): - { - break; - } - - case (value_t::object): + case value_t::object: { m_value = *other.m_value.object; break; } - case (value_t::array): + case value_t::array: { m_value = *other.m_value.array; break; } - case (value_t::string): + case value_t::string: { m_value = *other.m_value.string; break; } - case (value_t::boolean): + case value_t::boolean: { m_value = other.m_value.boolean; break; } - case (value_t::number_integer): + case value_t::number_integer: { m_value = other.m_value.number_integer; break; } - case (value_t::number_float): + case value_t::number_float: { m_value = other.m_value.number_float; break; } + + case value_t::discarded: + case value_t::null: + default: + { + break; + } } } @@ -1687,7 +1695,7 @@ class basic_json { switch (m_type) { - case (value_t::object): + case value_t::object: { AllocatorType alloc; alloc.destroy(m_value.object); @@ -1695,7 +1703,7 @@ class basic_json break; } - case (value_t::array): + case value_t::array: { AllocatorType alloc; alloc.destroy(m_value.array); @@ -1703,7 +1711,7 @@ class basic_json break; } - case (value_t::string): + case value_t::string: { AllocatorType alloc; alloc.destroy(m_value.string); @@ -1711,6 +1719,11 @@ class basic_json break; } + case value_t::boolean: + case value_t::discarded: + case value_t::null: + case value_t::number_float: + case value_t::number_integer: default: { // all other types need no specific destructor @@ -2014,32 +2027,26 @@ class basic_json , int>::type = 0> T get_impl(T*) const { - switch (m_type) + if (m_type == value_t::object) { - case (value_t::object): - { - return T(m_value.object->begin(), m_value.object->end()); - } - default: - { - throw std::domain_error("type must be object, but is " + type_name()); - } + return T(m_value.object->begin(), m_value.object->end()); + } + else + { + throw std::domain_error("type must be object, but is " + type_name()); } } /// get an object (explicit) object_t get_impl(object_t*) const { - switch (m_type) + if (m_type == value_t::object) { - case (value_t::object): - { - return *(m_value.object); - } - default: - { - throw std::domain_error("type must be object, but is " + type_name()); - } + return *(m_value.object); + } + else + { + throw std::domain_error("type must be object, but is " + type_name()); } } @@ -2054,22 +2061,19 @@ class basic_json , int>::type = 0> T get_impl(T*) const { - switch (m_type) + if (m_type == value_t::array) { - case (value_t::array): + T to_vector; + std::transform(m_value.array->begin(), m_value.array->end(), + std::inserter(to_vector, to_vector.end()), [](basic_json i) { - T to_vector; - std::transform(m_value.array->begin(), m_value.array->end(), - std::inserter(to_vector, to_vector.end()), [](basic_json i) - { - return i.get(); - }); - return to_vector; - } - default: - { - throw std::domain_error("type must be array, but is " + type_name()); - } + return i.get(); + }); + return to_vector; + } + else + { + throw std::domain_error("type must be array, but is " + type_name()); } } @@ -2081,23 +2085,20 @@ class basic_json , int>::type = 0> std::vector get_impl(std::vector*) const { - switch (m_type) + if (m_type == value_t::array) { - case (value_t::array): + std::vector to_vector; + to_vector.reserve(m_value.array->size()); + std::transform(m_value.array->begin(), m_value.array->end(), + std::inserter(to_vector, to_vector.end()), [](basic_json i) { - std::vector to_vector; - to_vector.reserve(m_value.array->size()); - std::transform(m_value.array->begin(), m_value.array->end(), - std::inserter(to_vector, to_vector.end()), [](basic_json i) - { - return i.get(); - }); - return to_vector; - } - default: - { - throw std::domain_error("type must be array, but is " + type_name()); - } + return i.get(); + }); + return to_vector; + } + else + { + throw std::domain_error("type must be array, but is " + type_name()); } } @@ -2109,32 +2110,26 @@ class basic_json , int>::type = 0> T get_impl(T*) const { - switch (m_type) + if (m_type == value_t::array) { - case (value_t::array): - { - return T(m_value.array->begin(), m_value.array->end()); - } - default: - { - throw std::domain_error("type must be array, but is " + type_name()); - } + return T(m_value.array->begin(), m_value.array->end()); + } + else + { + throw std::domain_error("type must be array, but is " + type_name()); } } /// get an array (explicit) array_t get_impl(array_t*) const { - switch (m_type) + if (m_type == value_t::array) { - case (value_t::array): - { - return *(m_value.array); - } - default: - { - throw std::domain_error("type must be array, but is " + type_name()); - } + return *(m_value.array); + } + else + { + throw std::domain_error("type must be array, but is " + type_name()); } } @@ -2145,16 +2140,13 @@ class basic_json , int>::type = 0> T get_impl(T*) const { - switch (m_type) + if (m_type == value_t::string) { - case (value_t::string): - { - return *m_value.string; - } - default: - { - throw std::domain_error("type must be string, but is " + type_name()); - } + return *m_value.string; + } + else + { + throw std::domain_error("type must be string, but is " + type_name()); } } @@ -2167,14 +2159,22 @@ class basic_json { switch (m_type) { - case (value_t::number_integer): + case value_t::number_integer: { return static_cast(m_value.number_integer); } - case (value_t::number_float): + + case value_t::number_float: { return static_cast(m_value.number_float); } + + case value_t::array: + case value_t::boolean: + case value_t::discarded: + case value_t::null: + case value_t::object: + case value_t::string: default: { throw std::domain_error("type must be number, but is " + type_name()); @@ -2185,16 +2185,13 @@ class basic_json /// get a boolean (explicit) boolean_t get_impl(boolean_t*) const { - switch (m_type) + if (m_type == value_t::boolean) { - case (value_t::boolean): - { - return m_value.boolean; - } - default: - { - throw std::domain_error("type must be boolean, but is " + type_name()); - } + return m_value.boolean; + } + else + { + throw std::domain_error("type must be boolean, but is " + type_name()); } } @@ -2845,9 +2842,9 @@ class basic_json switch (m_type) { - case value_t::number_integer: - case value_t::number_float: case value_t::boolean: + case value_t::number_float: + case value_t::number_integer: case value_t::string: { if (not pos.m_it.primitive_iterator.is_begin()) @@ -2877,6 +2874,8 @@ class basic_json break; } + case value_t::discarded: + case value_t::null: default: { throw std::domain_error("cannot use erase() with " + type_name()); @@ -2938,9 +2937,9 @@ class basic_json switch (m_type) { - case value_t::number_integer: - case value_t::number_float: case value_t::boolean: + case value_t::number_float: + case value_t::number_integer: case value_t::string: { if (not first.m_it.primitive_iterator.is_begin() or not last.m_it.primitive_iterator.is_end()) @@ -2972,6 +2971,8 @@ class basic_json break; } + case value_t::discarded: + case value_t::null: default: { throw std::domain_error("cannot use erase with " + type_name()); @@ -3364,21 +3365,26 @@ class basic_json { switch (m_type) { - case (value_t::null): + case value_t::null: { return true; } - case (value_t::array): + case value_t::array: { return m_value.array->empty(); } - case (value_t::object): + case value_t::object: { return m_value.object->empty(); } + case basic_json::value_t::boolean: + case basic_json::value_t::discarded: + case basic_json::value_t::number_float: + case basic_json::value_t::number_integer: + case basic_json::value_t::string: default: { // all other types are nonempty @@ -3418,21 +3424,26 @@ class basic_json { switch (m_type) { - case (value_t::null): + case value_t::null: { return 0; } - case (value_t::array): + case value_t::array: { return m_value.array->size(); } - case (value_t::object): + case value_t::object: { return m_value.object->size(); } + case value_t::boolean: + case value_t::discarded: + case value_t::number_float: + case value_t::number_integer: + case value_t::string: default: { // all other types have size 1 @@ -3475,16 +3486,22 @@ class basic_json { switch (m_type) { - case (value_t::array): + case value_t::array: { return m_value.array->max_size(); } - case (value_t::object): + case value_t::object: { return m_value.object->max_size(); } + case basic_json::value_t::boolean: + case basic_json::value_t::discarded: + case basic_json::value_t::null: + case basic_json::value_t::number_float: + case basic_json::value_t::number_integer: + case basic_json::value_t::string: default: { // all other types have max_size() == size() @@ -3530,47 +3547,48 @@ class basic_json { switch (m_type) { - case (value_t::null): - case (value_t::discarded): - { - break; - } - - case (value_t::number_integer): + case value_t::number_integer: { m_value.number_integer = 0; break; } - case (value_t::number_float): + case value_t::number_float: { m_value.number_float = 0.0; break; } - case (value_t::boolean): + case value_t::boolean: { m_value.boolean = false; break; } - case (value_t::string): + case value_t::string: { m_value.string->clear(); break; } - case (value_t::array): + case value_t::array: { m_value.array->clear(); break; } - case (value_t::object): + case value_t::object: { m_value.object->clear(); break; } + + case value_t::discarded: + case value_t::null: + default: + { + break; + } } } @@ -4067,21 +4085,23 @@ class basic_json { switch (lhs_type) { - case (value_t::array): + case value_t::array: return *lhs.m_value.array == *rhs.m_value.array; - case (value_t::object): + case value_t::object: return *lhs.m_value.object == *rhs.m_value.object; - case (value_t::null): + case value_t::null: return true; - case (value_t::string): + case value_t::string: return *lhs.m_value.string == *rhs.m_value.string; - case (value_t::boolean): + case value_t::boolean: return lhs.m_value.boolean == rhs.m_value.boolean; - case (value_t::number_integer): + case value_t::number_integer: return lhs.m_value.number_integer == rhs.m_value.number_integer; - case (value_t::number_float): + case value_t::number_float: return approx(lhs.m_value.number_float, rhs.m_value.number_float); - case (value_t::discarded): + case value_t::discarded: + return false; + default: return false; } } @@ -4208,21 +4228,23 @@ class basic_json { switch (lhs_type) { - case (value_t::array): + case value_t::array: return *lhs.m_value.array < *rhs.m_value.array; - case (value_t::object): + case value_t::object: return *lhs.m_value.object < *rhs.m_value.object; - case (value_t::null): + case value_t::null: return false; - case (value_t::string): + case value_t::string: return *lhs.m_value.string < *rhs.m_value.string; - case (value_t::boolean): + case value_t::boolean: return lhs.m_value.boolean < rhs.m_value.boolean; - case (value_t::number_integer): + case value_t::number_integer: return lhs.m_value.number_integer < rhs.m_value.number_integer; - case (value_t::number_float): + case value_t::number_float: return lhs.m_value.number_float < rhs.m_value.number_float; - case (value_t::discarded): + case value_t::discarded: + return false; + default: return false; } } @@ -4475,36 +4497,38 @@ class basic_json { switch (m_type) { - case (value_t::null): + case value_t::null: { return "null"; } - case (value_t::object): + case value_t::object: { return "object"; } - case (value_t::array): + case value_t::array: { return "array"; } - case (value_t::string): + case value_t::string: { return "string"; } - case (value_t::boolean): + case value_t::boolean: { return "boolean"; } - case (value_t::discarded): + case value_t::discarded: { return "discarded"; } + case value_t::number_float: + case value_t::number_integer: default: { return "number"; @@ -4699,7 +4723,7 @@ class basic_json switch (m_type) { - case (value_t::object): + case value_t::object: { if (m_value.object->empty()) { @@ -4739,7 +4763,7 @@ class basic_json return; } - case (value_t::array): + case value_t::array: { if (m_value.array->empty()) { @@ -4777,25 +4801,25 @@ class basic_json return; } - case (value_t::string): + case value_t::string: { o << string_t("\"") << escape_string(*m_value.string) << "\""; return; } - case (value_t::boolean): + case value_t::boolean: { o << (m_value.boolean ? "true" : "false"); return; } - case (value_t::number_integer): + case value_t::number_integer: { o << m_value.number_integer; return; } - case (value_t::number_float): + case value_t::number_float: { // 15 digits of precision allows round-trip IEEE 754 // string->double->string; to be safe, we read this value from @@ -4804,17 +4828,22 @@ class basic_json return; } - case (value_t::discarded): + case value_t::discarded: { o << ""; return; } - default: + case value_t::null: { o << "null"; return; } + + default: + { + return; + } } } @@ -4950,16 +4979,24 @@ class basic_json { switch (m_object->m_type) { - case (basic_json::value_t::object): + case basic_json::value_t::object: { m_it.object_iterator = typename object_t::iterator(); break; } - case (basic_json::value_t::array): + + case basic_json::value_t::array: { m_it.array_iterator = typename array_t::iterator(); break; } + + case basic_json::value_t::boolean: + case basic_json::value_t::discarded: + case basic_json::value_t::null: + case basic_json::value_t::number_float: + case basic_json::value_t::number_integer: + case basic_json::value_t::string: default: { m_it.primitive_iterator = primitive_iterator_t(); @@ -4973,18 +5010,24 @@ class basic_json { switch (m_object->m_type) { - case (basic_json::value_t::object): + case basic_json::value_t::object: { m_it.object_iterator = other.m_it.object_iterator; break; } - case (basic_json::value_t::array): + case basic_json::value_t::array: { m_it.array_iterator = other.m_it.array_iterator; break; } + case value_t::boolean: + case value_t::discarded: + case value_t::null: + case value_t::number_float: + case value_t::number_integer: + case value_t::string: default: { m_it.primitive_iterator = other.m_it.primitive_iterator; @@ -5017,25 +5060,30 @@ class basic_json { switch (m_object->m_type) { - case (basic_json::value_t::object): + case basic_json::value_t::object: { m_it.object_iterator = m_object->m_value.object->begin(); break; } - case (basic_json::value_t::array): + case basic_json::value_t::array: { m_it.array_iterator = m_object->m_value.array->begin(); break; } - case (basic_json::value_t::null): + case basic_json::value_t::null: { // set to end so begin()==end() is true: null is empty m_it.primitive_iterator.set_end(); break; } + case basic_json::value_t::boolean: + case basic_json::value_t::discarded: + case basic_json::value_t::number_float: + case basic_json::value_t::number_integer: + case basic_json::value_t::string: default: { m_it.primitive_iterator.set_begin(); @@ -5049,18 +5097,24 @@ class basic_json { switch (m_object->m_type) { - case (basic_json::value_t::object): + case basic_json::value_t::object: { m_it.object_iterator = m_object->m_value.object->end(); break; } - case (basic_json::value_t::array): + case basic_json::value_t::array: { m_it.array_iterator = m_object->m_value.array->end(); break; } + case basic_json::value_t::boolean: + case basic_json::value_t::discarded: + case basic_json::value_t::null: + case basic_json::value_t::number_float: + case basic_json::value_t::number_integer: + case basic_json::value_t::string: default: { m_it.primitive_iterator.set_end(); @@ -5075,21 +5129,26 @@ class basic_json { switch (m_object->m_type) { - case (basic_json::value_t::object): + case basic_json::value_t::object: { return m_it.object_iterator->second; } - case (basic_json::value_t::array): + case basic_json::value_t::array: { return *m_it.array_iterator; } - case (basic_json::value_t::null): + case basic_json::value_t::null: { throw std::out_of_range("cannot get value"); } + case value_t::boolean: + case value_t::discarded: + case value_t::number_float: + case value_t::number_integer: + case value_t::string: default: { if (m_it.primitive_iterator.is_begin()) @@ -5109,16 +5168,22 @@ class basic_json { switch (m_object->m_type) { - case (basic_json::value_t::object): + case basic_json::value_t::object: { return &(m_it.object_iterator->second); } - case (basic_json::value_t::array): + case basic_json::value_t::array: { return &*m_it.array_iterator; } + case basic_json::value_t::boolean: + case basic_json::value_t::discarded: + case basic_json::value_t::null: + case basic_json::value_t::number_float: + case basic_json::value_t::number_integer: + case basic_json::value_t::string: default: { if (m_it.primitive_iterator.is_begin()) @@ -5147,18 +5212,24 @@ class basic_json { switch (m_object->m_type) { - case (basic_json::value_t::object): + case basic_json::value_t::object: { ++m_it.object_iterator; break; } - case (basic_json::value_t::array): + case basic_json::value_t::array: { ++m_it.array_iterator; break; } + case value_t::boolean: + case value_t::discarded: + case value_t::null: + case value_t::number_float: + case value_t::number_integer: + case value_t::string: default: { ++m_it.primitive_iterator; @@ -5183,18 +5254,24 @@ class basic_json { switch (m_object->m_type) { - case (basic_json::value_t::object): + case basic_json::value_t::object: { --m_it.object_iterator; break; } - case (basic_json::value_t::array): + case basic_json::value_t::array: { --m_it.array_iterator; break; } + case value_t::boolean: + case value_t::discarded: + case value_t::null: + case value_t::number_float: + case value_t::number_integer: + case value_t::string: default: { --m_it.primitive_iterator; @@ -5216,16 +5293,22 @@ class basic_json switch (m_object->m_type) { - case (basic_json::value_t::object): + case basic_json::value_t::object: { return (m_it.object_iterator == other.m_it.object_iterator); } - case (basic_json::value_t::array): + case basic_json::value_t::array: { return (m_it.array_iterator == other.m_it.array_iterator); } + case value_t::boolean: + case value_t::discarded: + case value_t::null: + case value_t::number_float: + case value_t::number_integer: + case value_t::string: default: { return (m_it.primitive_iterator == other.m_it.primitive_iterator); @@ -5250,16 +5333,22 @@ class basic_json switch (m_object->m_type) { - case (basic_json::value_t::object): + case basic_json::value_t::object: { throw std::domain_error("cannot use operator< for object iterators"); } - case (basic_json::value_t::array): + case basic_json::value_t::array: { return (m_it.array_iterator < other.m_it.array_iterator); } + case basic_json::value_t::boolean: + case basic_json::value_t::discarded: + case basic_json::value_t::null: + case basic_json::value_t::number_float: + case basic_json::value_t::number_integer: + case basic_json::value_t::string: default: { return (m_it.primitive_iterator < other.m_it.primitive_iterator); @@ -5290,17 +5379,23 @@ class basic_json { switch (m_object->m_type) { - case (basic_json::value_t::object): + case basic_json::value_t::object: { throw std::domain_error("cannot use operator+= for object iterators"); } - case (basic_json::value_t::array): + case basic_json::value_t::array: { m_it.array_iterator += i; break; } + case basic_json::value_t::boolean: + case basic_json::value_t::discarded: + case basic_json::value_t::null: + case basic_json::value_t::number_float: + case basic_json::value_t::number_integer: + case basic_json::value_t::string: default: { m_it.primitive_iterator += i; @@ -5338,16 +5433,22 @@ class basic_json { switch (m_object->m_type) { - case (basic_json::value_t::object): + case basic_json::value_t::object: { throw std::domain_error("cannot use operator- for object iterators"); } - case (basic_json::value_t::array): + case basic_json::value_t::array: { return m_it.array_iterator - other.m_it.array_iterator; } + case basic_json::value_t::boolean: + case basic_json::value_t::discarded: + case basic_json::value_t::null: + case basic_json::value_t::number_float: + case basic_json::value_t::number_integer: + case basic_json::value_t::string: default: { return m_it.primitive_iterator - other.m_it.primitive_iterator; @@ -5360,21 +5461,26 @@ class basic_json { switch (m_object->m_type) { - case (basic_json::value_t::object): + case basic_json::value_t::object: { throw std::domain_error("cannot use operator[] for object iterators"); } - case (basic_json::value_t::array): + case basic_json::value_t::array: { return *(m_it.array_iterator + n); } - case (basic_json::value_t::null): + case basic_json::value_t::null: { throw std::out_of_range("cannot get value"); } + case basic_json::value_t::boolean: + case basic_json::value_t::discarded: + case basic_json::value_t::number_float: + case basic_json::value_t::number_integer: + case basic_json::value_t::string: default: { if (m_it.primitive_iterator == -n) @@ -5392,17 +5498,13 @@ class basic_json /// return the key of an object iterator typename object_t::key_type key() const { - switch (m_object->m_type) + if (m_object->m_type == basic_json::value_t::object) { - case (basic_json::value_t::object): - { - return m_it.object_iterator->first; - } - - default: - { - throw std::domain_error("cannot use key() for non-object iterators"); - } + return m_it.object_iterator->first; + } + else + { + throw std::domain_error("cannot use key() for non-object iterators"); } } @@ -5713,18 +5815,24 @@ class basic_json switch (anchor.m_object->type()) { /// use integer array index as key - case (value_t::array): + case value_t::array: { return std::to_string(array_index); } /// use key from the object - case (value_t::object): + case value_t::object: { return anchor.key(); } /// use an empty key for all primitive types + case value_t::boolean: + case value_t::discarded: + case value_t::null: + case value_t::number_float: + case value_t::number_integer: + case value_t::string: default: { return ""; @@ -5899,34 +6007,36 @@ class basic_json { switch (t) { - case (token_type::uninitialized): + case token_type::uninitialized: return ""; - case (token_type::literal_true): + case token_type::literal_true: return "true literal"; - case (token_type::literal_false): + case token_type::literal_false: return "false literal"; - case (token_type::literal_null): + case token_type::literal_null: return "null literal"; - case (token_type::value_string): + case token_type::value_string: return "string literal"; - case (token_type::value_number): + case token_type::value_number: return "number literal"; - case (token_type::begin_array): + case token_type::begin_array: return "["; - case (token_type::begin_object): + case token_type::begin_object: return "{"; - case (token_type::end_array): + case token_type::end_array: return "]"; - case (token_type::end_object): + case token_type::end_object: return "}"; - case (token_type::name_separator): + case token_type::name_separator: return ":"; - case (token_type::value_separator): + case token_type::value_separator: return ","; - case (token_type::end_of_input): + case token_type::end_of_input: return ""; - default: + case token_type::parse_error: return ""; + default: + return ""; } } @@ -6877,6 +6987,11 @@ basic_json_parser_64: } break; } + + default: + { + break; + } } } else @@ -6978,7 +7093,7 @@ basic_json_parser_64: switch (last_token) { - case (lexer::token_type::begin_object): + case lexer::token_type::begin_object: { if (keep and (not callback or (keep = callback(depth++, parse_event_t::object_start, result)))) { @@ -7056,7 +7171,7 @@ basic_json_parser_64: return result; } - case (lexer::token_type::begin_array): + case lexer::token_type::begin_array: { if (keep and (not callback or (keep = callback(depth++, parse_event_t::array_start, result)))) { @@ -7111,14 +7226,14 @@ basic_json_parser_64: return result; } - case (lexer::token_type::literal_null): + case lexer::token_type::literal_null: { get_token(); result.m_type = value_t::null; break; } - case (lexer::token_type::value_string): + case lexer::token_type::value_string: { const auto s = m_lexer.get_string(); get_token(); @@ -7126,7 +7241,7 @@ basic_json_parser_64: break; } - case (lexer::token_type::literal_true): + case lexer::token_type::literal_true: { get_token(); result.m_type = value_t::boolean; @@ -7134,7 +7249,7 @@ basic_json_parser_64: break; } - case (lexer::token_type::literal_false): + case lexer::token_type::literal_false: { get_token(); result.m_type = value_t::boolean; @@ -7142,7 +7257,7 @@ basic_json_parser_64: break; } - case (lexer::token_type::value_number): + case lexer::token_type::value_number: { auto float_val = m_lexer.get_number(); @@ -7173,6 +7288,13 @@ basic_json_parser_64: break; } + case lexer::token_type::end_array: + case lexer::token_type::end_object: + case lexer::token_type::end_of_input: + case lexer::token_type::name_separator: + case lexer::token_type::parse_error: + case lexer::token_type::uninitialized: + case lexer::token_type::value_separator: default: { // the last token was unexpected diff --git a/src/json.hpp.re2c b/src/json.hpp.re2c index 4f056f34a..efb05221d 100644 --- a/src/json.hpp.re2c +++ b/src/json.hpp.re2c @@ -650,47 +650,48 @@ class basic_json { switch (t) { - case (value_t::null): - case (value_t::discarded): - { - break; - } - - case (value_t::object): + case value_t::object: { object = create(); break; } - case (value_t::array): + case value_t::array: { array = create(); break; } - case (value_t::string): + case value_t::string: { string = create(""); break; } - case (value_t::boolean): + case value_t::boolean: { boolean = boolean_t(false); break; } - case (value_t::number_integer): + case value_t::number_integer: { number_integer = number_integer_t(0); break; } - case (value_t::number_float): + case value_t::number_float: { number_float = number_float_t(0.0); break; } + + case value_t::null: + case value_t::discarded: + default: + { + break; + } } } @@ -1481,9 +1482,9 @@ class basic_json // check if iterator range is complete for primitive values switch (m_type) { - case value_t::number_integer: - case value_t::number_float: case value_t::boolean: + case value_t::number_float: + case value_t::number_integer: case value_t::string: { if (not first.m_it.primitive_iterator.is_begin() or not last.m_it.primitive_iterator.is_end()) @@ -1493,6 +1494,10 @@ class basic_json break; } + case value_t::array: + case value_t::discarded: + case value_t::null: + case value_t::object: default: { break; @@ -1537,6 +1542,8 @@ class basic_json break; } + case value_t::discarded: + case value_t::null: default: { throw std::domain_error("cannot use construct with iterators from " + first.m_object->type_name()); @@ -1571,47 +1578,48 @@ class basic_json { switch (m_type) { - case (value_t::null): - case (value_t::discarded): - { - break; - } - - case (value_t::object): + case value_t::object: { m_value = *other.m_value.object; break; } - case (value_t::array): + case value_t::array: { m_value = *other.m_value.array; break; } - case (value_t::string): + case value_t::string: { m_value = *other.m_value.string; break; } - case (value_t::boolean): + case value_t::boolean: { m_value = other.m_value.boolean; break; } - case (value_t::number_integer): + case value_t::number_integer: { m_value = other.m_value.number_integer; break; } - case (value_t::number_float): + case value_t::number_float: { m_value = other.m_value.number_float; break; } + + case value_t::discarded: + case value_t::null: + default: + { + break; + } } } @@ -1687,7 +1695,7 @@ class basic_json { switch (m_type) { - case (value_t::object): + case value_t::object: { AllocatorType alloc; alloc.destroy(m_value.object); @@ -1695,7 +1703,7 @@ class basic_json break; } - case (value_t::array): + case value_t::array: { AllocatorType alloc; alloc.destroy(m_value.array); @@ -1703,7 +1711,7 @@ class basic_json break; } - case (value_t::string): + case value_t::string: { AllocatorType alloc; alloc.destroy(m_value.string); @@ -1711,6 +1719,11 @@ class basic_json break; } + case value_t::boolean: + case value_t::discarded: + case value_t::null: + case value_t::number_float: + case value_t::number_integer: default: { // all other types need no specific destructor @@ -2014,32 +2027,26 @@ class basic_json , int>::type = 0> T get_impl(T*) const { - switch (m_type) + if (m_type == value_t::object) { - case (value_t::object): - { - return T(m_value.object->begin(), m_value.object->end()); - } - default: - { - throw std::domain_error("type must be object, but is " + type_name()); - } + return T(m_value.object->begin(), m_value.object->end()); + } + else + { + throw std::domain_error("type must be object, but is " + type_name()); } } /// get an object (explicit) object_t get_impl(object_t*) const { - switch (m_type) + if (m_type == value_t::object) { - case (value_t::object): - { - return *(m_value.object); - } - default: - { - throw std::domain_error("type must be object, but is " + type_name()); - } + return *(m_value.object); + } + else + { + throw std::domain_error("type must be object, but is " + type_name()); } } @@ -2054,22 +2061,19 @@ class basic_json , int>::type = 0> T get_impl(T*) const { - switch (m_type) + if (m_type == value_t::array) { - case (value_t::array): + T to_vector; + std::transform(m_value.array->begin(), m_value.array->end(), + std::inserter(to_vector, to_vector.end()), [](basic_json i) { - T to_vector; - std::transform(m_value.array->begin(), m_value.array->end(), - std::inserter(to_vector, to_vector.end()), [](basic_json i) - { - return i.get(); - }); - return to_vector; - } - default: - { - throw std::domain_error("type must be array, but is " + type_name()); - } + return i.get(); + }); + return to_vector; + } + else + { + throw std::domain_error("type must be array, but is " + type_name()); } } @@ -2081,23 +2085,20 @@ class basic_json , int>::type = 0> std::vector get_impl(std::vector*) const { - switch (m_type) + if (m_type == value_t::array) { - case (value_t::array): + std::vector to_vector; + to_vector.reserve(m_value.array->size()); + std::transform(m_value.array->begin(), m_value.array->end(), + std::inserter(to_vector, to_vector.end()), [](basic_json i) { - std::vector to_vector; - to_vector.reserve(m_value.array->size()); - std::transform(m_value.array->begin(), m_value.array->end(), - std::inserter(to_vector, to_vector.end()), [](basic_json i) - { - return i.get(); - }); - return to_vector; - } - default: - { - throw std::domain_error("type must be array, but is " + type_name()); - } + return i.get(); + }); + return to_vector; + } + else + { + throw std::domain_error("type must be array, but is " + type_name()); } } @@ -2109,32 +2110,26 @@ class basic_json , int>::type = 0> T get_impl(T*) const { - switch (m_type) + if (m_type == value_t::array) { - case (value_t::array): - { - return T(m_value.array->begin(), m_value.array->end()); - } - default: - { - throw std::domain_error("type must be array, but is " + type_name()); - } + return T(m_value.array->begin(), m_value.array->end()); + } + else + { + throw std::domain_error("type must be array, but is " + type_name()); } } /// get an array (explicit) array_t get_impl(array_t*) const { - switch (m_type) + if (m_type == value_t::array) { - case (value_t::array): - { - return *(m_value.array); - } - default: - { - throw std::domain_error("type must be array, but is " + type_name()); - } + return *(m_value.array); + } + else + { + throw std::domain_error("type must be array, but is " + type_name()); } } @@ -2145,16 +2140,13 @@ class basic_json , int>::type = 0> T get_impl(T*) const { - switch (m_type) + if (m_type == value_t::string) { - case (value_t::string): - { - return *m_value.string; - } - default: - { - throw std::domain_error("type must be string, but is " + type_name()); - } + return *m_value.string; + } + else + { + throw std::domain_error("type must be string, but is " + type_name()); } } @@ -2167,14 +2159,22 @@ class basic_json { switch (m_type) { - case (value_t::number_integer): + case value_t::number_integer: { return static_cast(m_value.number_integer); } - case (value_t::number_float): + + case value_t::number_float: { return static_cast(m_value.number_float); } + + case value_t::array: + case value_t::boolean: + case value_t::discarded: + case value_t::null: + case value_t::object: + case value_t::string: default: { throw std::domain_error("type must be number, but is " + type_name()); @@ -2185,16 +2185,13 @@ class basic_json /// get a boolean (explicit) boolean_t get_impl(boolean_t*) const { - switch (m_type) + if (m_type == value_t::boolean) { - case (value_t::boolean): - { - return m_value.boolean; - } - default: - { - throw std::domain_error("type must be boolean, but is " + type_name()); - } + return m_value.boolean; + } + else + { + throw std::domain_error("type must be boolean, but is " + type_name()); } } @@ -2845,9 +2842,9 @@ class basic_json switch (m_type) { - case value_t::number_integer: - case value_t::number_float: case value_t::boolean: + case value_t::number_float: + case value_t::number_integer: case value_t::string: { if (not pos.m_it.primitive_iterator.is_begin()) @@ -2877,6 +2874,8 @@ class basic_json break; } + case value_t::discarded: + case value_t::null: default: { throw std::domain_error("cannot use erase() with " + type_name()); @@ -2938,9 +2937,9 @@ class basic_json switch (m_type) { - case value_t::number_integer: - case value_t::number_float: case value_t::boolean: + case value_t::number_float: + case value_t::number_integer: case value_t::string: { if (not first.m_it.primitive_iterator.is_begin() or not last.m_it.primitive_iterator.is_end()) @@ -2972,6 +2971,8 @@ class basic_json break; } + case value_t::discarded: + case value_t::null: default: { throw std::domain_error("cannot use erase with " + type_name()); @@ -3364,21 +3365,26 @@ class basic_json { switch (m_type) { - case (value_t::null): + case value_t::null: { return true; } - case (value_t::array): + case value_t::array: { return m_value.array->empty(); } - case (value_t::object): + case value_t::object: { return m_value.object->empty(); } + case basic_json::value_t::boolean: + case basic_json::value_t::discarded: + case basic_json::value_t::number_float: + case basic_json::value_t::number_integer: + case basic_json::value_t::string: default: { // all other types are nonempty @@ -3418,21 +3424,26 @@ class basic_json { switch (m_type) { - case (value_t::null): + case value_t::null: { return 0; } - case (value_t::array): + case value_t::array: { return m_value.array->size(); } - case (value_t::object): + case value_t::object: { return m_value.object->size(); } + case value_t::boolean: + case value_t::discarded: + case value_t::number_float: + case value_t::number_integer: + case value_t::string: default: { // all other types have size 1 @@ -3475,16 +3486,22 @@ class basic_json { switch (m_type) { - case (value_t::array): + case value_t::array: { return m_value.array->max_size(); } - case (value_t::object): + case value_t::object: { return m_value.object->max_size(); } + case basic_json::value_t::boolean: + case basic_json::value_t::discarded: + case basic_json::value_t::null: + case basic_json::value_t::number_float: + case basic_json::value_t::number_integer: + case basic_json::value_t::string: default: { // all other types have max_size() == size() @@ -3530,47 +3547,48 @@ class basic_json { switch (m_type) { - case (value_t::null): - case (value_t::discarded): - { - break; - } - - case (value_t::number_integer): + case value_t::number_integer: { m_value.number_integer = 0; break; } - case (value_t::number_float): + case value_t::number_float: { m_value.number_float = 0.0; break; } - case (value_t::boolean): + case value_t::boolean: { m_value.boolean = false; break; } - case (value_t::string): + case value_t::string: { m_value.string->clear(); break; } - case (value_t::array): + case value_t::array: { m_value.array->clear(); break; } - case (value_t::object): + case value_t::object: { m_value.object->clear(); break; } + + case value_t::discarded: + case value_t::null: + default: + { + break; + } } } @@ -4067,21 +4085,23 @@ class basic_json { switch (lhs_type) { - case (value_t::array): + case value_t::array: return *lhs.m_value.array == *rhs.m_value.array; - case (value_t::object): + case value_t::object: return *lhs.m_value.object == *rhs.m_value.object; - case (value_t::null): + case value_t::null: return true; - case (value_t::string): + case value_t::string: return *lhs.m_value.string == *rhs.m_value.string; - case (value_t::boolean): + case value_t::boolean: return lhs.m_value.boolean == rhs.m_value.boolean; - case (value_t::number_integer): + case value_t::number_integer: return lhs.m_value.number_integer == rhs.m_value.number_integer; - case (value_t::number_float): + case value_t::number_float: return approx(lhs.m_value.number_float, rhs.m_value.number_float); - case (value_t::discarded): + case value_t::discarded: + return false; + default: return false; } } @@ -4208,21 +4228,23 @@ class basic_json { switch (lhs_type) { - case (value_t::array): + case value_t::array: return *lhs.m_value.array < *rhs.m_value.array; - case (value_t::object): + case value_t::object: return *lhs.m_value.object < *rhs.m_value.object; - case (value_t::null): + case value_t::null: return false; - case (value_t::string): + case value_t::string: return *lhs.m_value.string < *rhs.m_value.string; - case (value_t::boolean): + case value_t::boolean: return lhs.m_value.boolean < rhs.m_value.boolean; - case (value_t::number_integer): + case value_t::number_integer: return lhs.m_value.number_integer < rhs.m_value.number_integer; - case (value_t::number_float): + case value_t::number_float: return lhs.m_value.number_float < rhs.m_value.number_float; - case (value_t::discarded): + case value_t::discarded: + return false; + default: return false; } } @@ -4475,36 +4497,38 @@ class basic_json { switch (m_type) { - case (value_t::null): + case value_t::null: { return "null"; } - case (value_t::object): + case value_t::object: { return "object"; } - case (value_t::array): + case value_t::array: { return "array"; } - case (value_t::string): + case value_t::string: { return "string"; } - case (value_t::boolean): + case value_t::boolean: { return "boolean"; } - case (value_t::discarded): + case value_t::discarded: { return "discarded"; } + case value_t::number_float: + case value_t::number_integer: default: { return "number"; @@ -4699,7 +4723,7 @@ class basic_json switch (m_type) { - case (value_t::object): + case value_t::object: { if (m_value.object->empty()) { @@ -4739,7 +4763,7 @@ class basic_json return; } - case (value_t::array): + case value_t::array: { if (m_value.array->empty()) { @@ -4777,25 +4801,25 @@ class basic_json return; } - case (value_t::string): + case value_t::string: { o << string_t("\"") << escape_string(*m_value.string) << "\""; return; } - case (value_t::boolean): + case value_t::boolean: { o << (m_value.boolean ? "true" : "false"); return; } - case (value_t::number_integer): + case value_t::number_integer: { o << m_value.number_integer; return; } - case (value_t::number_float): + case value_t::number_float: { // 15 digits of precision allows round-trip IEEE 754 // string->double->string; to be safe, we read this value from @@ -4804,17 +4828,22 @@ class basic_json return; } - case (value_t::discarded): + case value_t::discarded: { o << ""; return; } - default: + case value_t::null: { o << "null"; return; } + + default: + { + return; + } } } @@ -4950,16 +4979,24 @@ class basic_json { switch (m_object->m_type) { - case (basic_json::value_t::object): + case basic_json::value_t::object: { m_it.object_iterator = typename object_t::iterator(); break; } - case (basic_json::value_t::array): + + case basic_json::value_t::array: { m_it.array_iterator = typename array_t::iterator(); break; } + + case basic_json::value_t::boolean: + case basic_json::value_t::discarded: + case basic_json::value_t::null: + case basic_json::value_t::number_float: + case basic_json::value_t::number_integer: + case basic_json::value_t::string: default: { m_it.primitive_iterator = primitive_iterator_t(); @@ -4973,18 +5010,24 @@ class basic_json { switch (m_object->m_type) { - case (basic_json::value_t::object): + case basic_json::value_t::object: { m_it.object_iterator = other.m_it.object_iterator; break; } - case (basic_json::value_t::array): + case basic_json::value_t::array: { m_it.array_iterator = other.m_it.array_iterator; break; } + case value_t::boolean: + case value_t::discarded: + case value_t::null: + case value_t::number_float: + case value_t::number_integer: + case value_t::string: default: { m_it.primitive_iterator = other.m_it.primitive_iterator; @@ -5017,25 +5060,30 @@ class basic_json { switch (m_object->m_type) { - case (basic_json::value_t::object): + case basic_json::value_t::object: { m_it.object_iterator = m_object->m_value.object->begin(); break; } - case (basic_json::value_t::array): + case basic_json::value_t::array: { m_it.array_iterator = m_object->m_value.array->begin(); break; } - case (basic_json::value_t::null): + case basic_json::value_t::null: { // set to end so begin()==end() is true: null is empty m_it.primitive_iterator.set_end(); break; } + case basic_json::value_t::boolean: + case basic_json::value_t::discarded: + case basic_json::value_t::number_float: + case basic_json::value_t::number_integer: + case basic_json::value_t::string: default: { m_it.primitive_iterator.set_begin(); @@ -5049,18 +5097,24 @@ class basic_json { switch (m_object->m_type) { - case (basic_json::value_t::object): + case basic_json::value_t::object: { m_it.object_iterator = m_object->m_value.object->end(); break; } - case (basic_json::value_t::array): + case basic_json::value_t::array: { m_it.array_iterator = m_object->m_value.array->end(); break; } + case basic_json::value_t::boolean: + case basic_json::value_t::discarded: + case basic_json::value_t::null: + case basic_json::value_t::number_float: + case basic_json::value_t::number_integer: + case basic_json::value_t::string: default: { m_it.primitive_iterator.set_end(); @@ -5075,21 +5129,26 @@ class basic_json { switch (m_object->m_type) { - case (basic_json::value_t::object): + case basic_json::value_t::object: { return m_it.object_iterator->second; } - case (basic_json::value_t::array): + case basic_json::value_t::array: { return *m_it.array_iterator; } - case (basic_json::value_t::null): + case basic_json::value_t::null: { throw std::out_of_range("cannot get value"); } + case value_t::boolean: + case value_t::discarded: + case value_t::number_float: + case value_t::number_integer: + case value_t::string: default: { if (m_it.primitive_iterator.is_begin()) @@ -5109,16 +5168,22 @@ class basic_json { switch (m_object->m_type) { - case (basic_json::value_t::object): + case basic_json::value_t::object: { return &(m_it.object_iterator->second); } - case (basic_json::value_t::array): + case basic_json::value_t::array: { return &*m_it.array_iterator; } + case basic_json::value_t::boolean: + case basic_json::value_t::discarded: + case basic_json::value_t::null: + case basic_json::value_t::number_float: + case basic_json::value_t::number_integer: + case basic_json::value_t::string: default: { if (m_it.primitive_iterator.is_begin()) @@ -5147,18 +5212,24 @@ class basic_json { switch (m_object->m_type) { - case (basic_json::value_t::object): + case basic_json::value_t::object: { ++m_it.object_iterator; break; } - case (basic_json::value_t::array): + case basic_json::value_t::array: { ++m_it.array_iterator; break; } + case value_t::boolean: + case value_t::discarded: + case value_t::null: + case value_t::number_float: + case value_t::number_integer: + case value_t::string: default: { ++m_it.primitive_iterator; @@ -5183,18 +5254,24 @@ class basic_json { switch (m_object->m_type) { - case (basic_json::value_t::object): + case basic_json::value_t::object: { --m_it.object_iterator; break; } - case (basic_json::value_t::array): + case basic_json::value_t::array: { --m_it.array_iterator; break; } + case value_t::boolean: + case value_t::discarded: + case value_t::null: + case value_t::number_float: + case value_t::number_integer: + case value_t::string: default: { --m_it.primitive_iterator; @@ -5216,16 +5293,22 @@ class basic_json switch (m_object->m_type) { - case (basic_json::value_t::object): + case basic_json::value_t::object: { return (m_it.object_iterator == other.m_it.object_iterator); } - case (basic_json::value_t::array): + case basic_json::value_t::array: { return (m_it.array_iterator == other.m_it.array_iterator); } + case value_t::boolean: + case value_t::discarded: + case value_t::null: + case value_t::number_float: + case value_t::number_integer: + case value_t::string: default: { return (m_it.primitive_iterator == other.m_it.primitive_iterator); @@ -5250,16 +5333,22 @@ class basic_json switch (m_object->m_type) { - case (basic_json::value_t::object): + case basic_json::value_t::object: { throw std::domain_error("cannot use operator< for object iterators"); } - case (basic_json::value_t::array): + case basic_json::value_t::array: { return (m_it.array_iterator < other.m_it.array_iterator); } + case basic_json::value_t::boolean: + case basic_json::value_t::discarded: + case basic_json::value_t::null: + case basic_json::value_t::number_float: + case basic_json::value_t::number_integer: + case basic_json::value_t::string: default: { return (m_it.primitive_iterator < other.m_it.primitive_iterator); @@ -5290,17 +5379,23 @@ class basic_json { switch (m_object->m_type) { - case (basic_json::value_t::object): + case basic_json::value_t::object: { throw std::domain_error("cannot use operator+= for object iterators"); } - case (basic_json::value_t::array): + case basic_json::value_t::array: { m_it.array_iterator += i; break; } + case basic_json::value_t::boolean: + case basic_json::value_t::discarded: + case basic_json::value_t::null: + case basic_json::value_t::number_float: + case basic_json::value_t::number_integer: + case basic_json::value_t::string: default: { m_it.primitive_iterator += i; @@ -5338,16 +5433,22 @@ class basic_json { switch (m_object->m_type) { - case (basic_json::value_t::object): + case basic_json::value_t::object: { throw std::domain_error("cannot use operator- for object iterators"); } - case (basic_json::value_t::array): + case basic_json::value_t::array: { return m_it.array_iterator - other.m_it.array_iterator; } + case basic_json::value_t::boolean: + case basic_json::value_t::discarded: + case basic_json::value_t::null: + case basic_json::value_t::number_float: + case basic_json::value_t::number_integer: + case basic_json::value_t::string: default: { return m_it.primitive_iterator - other.m_it.primitive_iterator; @@ -5360,21 +5461,26 @@ class basic_json { switch (m_object->m_type) { - case (basic_json::value_t::object): + case basic_json::value_t::object: { throw std::domain_error("cannot use operator[] for object iterators"); } - case (basic_json::value_t::array): + case basic_json::value_t::array: { return *(m_it.array_iterator + n); } - case (basic_json::value_t::null): + case basic_json::value_t::null: { throw std::out_of_range("cannot get value"); } + case basic_json::value_t::boolean: + case basic_json::value_t::discarded: + case basic_json::value_t::number_float: + case basic_json::value_t::number_integer: + case basic_json::value_t::string: default: { if (m_it.primitive_iterator == -n) @@ -5392,17 +5498,13 @@ class basic_json /// return the key of an object iterator typename object_t::key_type key() const { - switch (m_object->m_type) + if (m_object->m_type == basic_json::value_t::object) { - case (basic_json::value_t::object): - { - return m_it.object_iterator->first; - } - - default: - { - throw std::domain_error("cannot use key() for non-object iterators"); - } + return m_it.object_iterator->first; + } + else + { + throw std::domain_error("cannot use key() for non-object iterators"); } } @@ -5713,18 +5815,24 @@ class basic_json switch (anchor.m_object->type()) { /// use integer array index as key - case (value_t::array): + case value_t::array: { return std::to_string(array_index); } /// use key from the object - case (value_t::object): + case value_t::object: { return anchor.key(); } /// use an empty key for all primitive types + case value_t::boolean: + case value_t::discarded: + case value_t::null: + case value_t::number_float: + case value_t::number_integer: + case value_t::string: default: { return ""; @@ -5899,34 +6007,36 @@ class basic_json { switch (t) { - case (token_type::uninitialized): + case token_type::uninitialized: return ""; - case (token_type::literal_true): + case token_type::literal_true: return "true literal"; - case (token_type::literal_false): + case token_type::literal_false: return "false literal"; - case (token_type::literal_null): + case token_type::literal_null: return "null literal"; - case (token_type::value_string): + case token_type::value_string: return "string literal"; - case (token_type::value_number): + case token_type::value_number: return "number literal"; - case (token_type::begin_array): + case token_type::begin_array: return "["; - case (token_type::begin_object): + case token_type::begin_object: return "{"; - case (token_type::end_array): + case token_type::end_array: return "]"; - case (token_type::end_object): + case token_type::end_object: return "}"; - case (token_type::name_separator): + case token_type::name_separator: return ":"; - case (token_type::value_separator): + case token_type::value_separator: return ","; - case (token_type::end_of_input): + case token_type::end_of_input: return ""; - default: + case token_type::parse_error: return ""; + default: + return ""; } } @@ -6156,6 +6266,11 @@ class basic_json } break; } + + default: + { + break; + } } } else @@ -6257,7 +6372,7 @@ class basic_json switch (last_token) { - case (lexer::token_type::begin_object): + case lexer::token_type::begin_object: { if (keep and (not callback or (keep = callback(depth++, parse_event_t::object_start, result)))) { @@ -6335,7 +6450,7 @@ class basic_json return result; } - case (lexer::token_type::begin_array): + case lexer::token_type::begin_array: { if (keep and (not callback or (keep = callback(depth++, parse_event_t::array_start, result)))) { @@ -6390,14 +6505,14 @@ class basic_json return result; } - case (lexer::token_type::literal_null): + case lexer::token_type::literal_null: { get_token(); result.m_type = value_t::null; break; } - case (lexer::token_type::value_string): + case lexer::token_type::value_string: { const auto s = m_lexer.get_string(); get_token(); @@ -6405,7 +6520,7 @@ class basic_json break; } - case (lexer::token_type::literal_true): + case lexer::token_type::literal_true: { get_token(); result.m_type = value_t::boolean; @@ -6413,7 +6528,7 @@ class basic_json break; } - case (lexer::token_type::literal_false): + case lexer::token_type::literal_false: { get_token(); result.m_type = value_t::boolean; @@ -6421,7 +6536,7 @@ class basic_json break; } - case (lexer::token_type::value_number): + case lexer::token_type::value_number: { auto float_val = m_lexer.get_number(); @@ -6452,6 +6567,13 @@ class basic_json break; } + case lexer::token_type::end_array: + case lexer::token_type::end_object: + case lexer::token_type::end_of_input: + case lexer::token_type::name_separator: + case lexer::token_type::parse_error: + case lexer::token_type::uninitialized: + case lexer::token_type::value_separator: default: { // the last token was unexpected diff --git a/test/unit.cpp b/test/unit.cpp index efc71ff5f..37baf50c1 100644 --- a/test/unit.cpp +++ b/test/unit.cpp @@ -9263,6 +9263,11 @@ TEST_CASE("iterator_wrapper") CHECK(i.value() == json(2)); break; } + + default: + { + break; + } } } @@ -9291,6 +9296,11 @@ TEST_CASE("iterator_wrapper") CHECK(i.value() == json(2)); break; } + + default: + { + break; + } } } @@ -9319,6 +9329,11 @@ TEST_CASE("iterator_wrapper") CHECK(i.value() == json(2)); break; } + + default: + { + break; + } } } @@ -9347,6 +9362,11 @@ TEST_CASE("iterator_wrapper") CHECK(i.value() == json(2)); break; } + + default: + { + break; + } } } @@ -9378,6 +9398,11 @@ TEST_CASE("iterator_wrapper") CHECK(i.value() == "B"); break; } + + default: + { + break; + } } } @@ -9406,6 +9431,11 @@ TEST_CASE("iterator_wrapper") CHECK(i.value() == "B"); break; } + + default: + { + break; + } } } @@ -9434,6 +9464,11 @@ TEST_CASE("iterator_wrapper") CHECK(i.value() == "B"); break; } + + default: + { + break; + } } } @@ -9462,6 +9497,11 @@ TEST_CASE("iterator_wrapper") CHECK(i.value() == "B"); break; } + + default: + { + break; + } } } From 5bc1b65676209236e3c943f72bd5090aa8542b6c Mon Sep 17 00:00:00 2001 From: Niels Date: Mon, 14 Dec 2015 16:58:49 +0100 Subject: [PATCH 16/61] clean up (for #154) --- Makefile | 2 +- src/json.hpp | 149 ---------------------------------------------- src/json.hpp.re2c | 149 ---------------------------------------------- 3 files changed, 1 insertion(+), 299 deletions(-) diff --git a/Makefile b/Makefile index a83015153..71a1175fd 100644 --- a/Makefile +++ b/Makefile @@ -17,7 +17,7 @@ clean: ########################################################################## # additional flags -FLAGS = -Wall -Wextra -pedantic -Weffc++ -Wcast-align -Wcast-qual -Wctor-dtor-privacy -Wdisabled-optimization -Wformat=2 -Winit-self -Wmissing-declarations -Wmissing-include-dirs -Wold-style-cast -Woverloaded-virtual -Wredundant-decls -Wshadow -Wsign-conversion -Wsign-promo -Wstrict-overflow=5 -Wswitch -Wswitch-enum -Wswitch-default -Wundef -Wno-unused -Wnon-virtual-dtor -Wreorder -Wdeprecated -Wfloat-equal +FLAGS = -Wall -Wextra -pedantic -Weffc++ -Wcast-align -Wcast-qual -Wctor-dtor-privacy -Wdisabled-optimization -Wformat=2 -Winit-self -Wmissing-declarations -Wmissing-include-dirs -Wold-style-cast -Woverloaded-virtual -Wredundant-decls -Wshadow -Wsign-conversion -Wsign-promo -Wstrict-overflow=5 -Wswitch -Wundef -Wno-unused -Wnon-virtual-dtor -Wreorder -Wdeprecated -Wfloat-equal # build unit tests json_unit: test/unit.cpp src/json.hpp test/catch.hpp diff --git a/src/json.hpp b/src/json.hpp index 7c2ea01cf..2b9a5a0d1 100644 --- a/src/json.hpp +++ b/src/json.hpp @@ -686,8 +686,6 @@ class basic_json break; } - case value_t::null: - case value_t::discarded: default: { break; @@ -1494,10 +1492,6 @@ class basic_json break; } - case value_t::array: - case value_t::discarded: - case value_t::null: - case value_t::object: default: { break; @@ -1542,8 +1536,6 @@ class basic_json break; } - case value_t::discarded: - case value_t::null: default: { throw std::domain_error("cannot use construct with iterators from " + first.m_object->type_name()); @@ -1614,8 +1606,6 @@ class basic_json break; } - case value_t::discarded: - case value_t::null: default: { break; @@ -1719,11 +1709,6 @@ class basic_json break; } - case value_t::boolean: - case value_t::discarded: - case value_t::null: - case value_t::number_float: - case value_t::number_integer: default: { // all other types need no specific destructor @@ -2169,12 +2154,6 @@ class basic_json return static_cast(m_value.number_float); } - case value_t::array: - case value_t::boolean: - case value_t::discarded: - case value_t::null: - case value_t::object: - case value_t::string: default: { throw std::domain_error("type must be number, but is " + type_name()); @@ -2874,8 +2853,6 @@ class basic_json break; } - case value_t::discarded: - case value_t::null: default: { throw std::domain_error("cannot use erase() with " + type_name()); @@ -2971,8 +2948,6 @@ class basic_json break; } - case value_t::discarded: - case value_t::null: default: { throw std::domain_error("cannot use erase with " + type_name()); @@ -3380,11 +3355,6 @@ class basic_json return m_value.object->empty(); } - case basic_json::value_t::boolean: - case basic_json::value_t::discarded: - case basic_json::value_t::number_float: - case basic_json::value_t::number_integer: - case basic_json::value_t::string: default: { // all other types are nonempty @@ -3439,11 +3409,6 @@ class basic_json return m_value.object->size(); } - case value_t::boolean: - case value_t::discarded: - case value_t::number_float: - case value_t::number_integer: - case value_t::string: default: { // all other types have size 1 @@ -3496,12 +3461,6 @@ class basic_json return m_value.object->max_size(); } - case basic_json::value_t::boolean: - case basic_json::value_t::discarded: - case basic_json::value_t::null: - case basic_json::value_t::number_float: - case basic_json::value_t::number_integer: - case basic_json::value_t::string: default: { // all other types have max_size() == size() @@ -3583,8 +3542,6 @@ class basic_json break; } - case value_t::discarded: - case value_t::null: default: { break; @@ -4099,8 +4056,6 @@ class basic_json return lhs.m_value.number_integer == rhs.m_value.number_integer; case value_t::number_float: return approx(lhs.m_value.number_float, rhs.m_value.number_float); - case value_t::discarded: - return false; default: return false; } @@ -4242,8 +4197,6 @@ class basic_json return lhs.m_value.number_integer < rhs.m_value.number_integer; case value_t::number_float: return lhs.m_value.number_float < rhs.m_value.number_float; - case value_t::discarded: - return false; default: return false; } @@ -4527,8 +4480,6 @@ class basic_json return "discarded"; } - case value_t::number_float: - case value_t::number_integer: default: { return "number"; @@ -4839,11 +4790,6 @@ class basic_json o << "null"; return; } - - default: - { - return; - } } } @@ -4991,12 +4937,6 @@ class basic_json break; } - case basic_json::value_t::boolean: - case basic_json::value_t::discarded: - case basic_json::value_t::null: - case basic_json::value_t::number_float: - case basic_json::value_t::number_integer: - case basic_json::value_t::string: default: { m_it.primitive_iterator = primitive_iterator_t(); @@ -5022,12 +4962,6 @@ class basic_json break; } - case value_t::boolean: - case value_t::discarded: - case value_t::null: - case value_t::number_float: - case value_t::number_integer: - case value_t::string: default: { m_it.primitive_iterator = other.m_it.primitive_iterator; @@ -5079,11 +5013,6 @@ class basic_json break; } - case basic_json::value_t::boolean: - case basic_json::value_t::discarded: - case basic_json::value_t::number_float: - case basic_json::value_t::number_integer: - case basic_json::value_t::string: default: { m_it.primitive_iterator.set_begin(); @@ -5109,12 +5038,6 @@ class basic_json break; } - case basic_json::value_t::boolean: - case basic_json::value_t::discarded: - case basic_json::value_t::null: - case basic_json::value_t::number_float: - case basic_json::value_t::number_integer: - case basic_json::value_t::string: default: { m_it.primitive_iterator.set_end(); @@ -5144,11 +5067,6 @@ class basic_json throw std::out_of_range("cannot get value"); } - case value_t::boolean: - case value_t::discarded: - case value_t::number_float: - case value_t::number_integer: - case value_t::string: default: { if (m_it.primitive_iterator.is_begin()) @@ -5178,12 +5096,6 @@ class basic_json return &*m_it.array_iterator; } - case basic_json::value_t::boolean: - case basic_json::value_t::discarded: - case basic_json::value_t::null: - case basic_json::value_t::number_float: - case basic_json::value_t::number_integer: - case basic_json::value_t::string: default: { if (m_it.primitive_iterator.is_begin()) @@ -5224,12 +5136,6 @@ class basic_json break; } - case value_t::boolean: - case value_t::discarded: - case value_t::null: - case value_t::number_float: - case value_t::number_integer: - case value_t::string: default: { ++m_it.primitive_iterator; @@ -5266,12 +5172,6 @@ class basic_json break; } - case value_t::boolean: - case value_t::discarded: - case value_t::null: - case value_t::number_float: - case value_t::number_integer: - case value_t::string: default: { --m_it.primitive_iterator; @@ -5303,12 +5203,6 @@ class basic_json return (m_it.array_iterator == other.m_it.array_iterator); } - case value_t::boolean: - case value_t::discarded: - case value_t::null: - case value_t::number_float: - case value_t::number_integer: - case value_t::string: default: { return (m_it.primitive_iterator == other.m_it.primitive_iterator); @@ -5343,12 +5237,6 @@ class basic_json return (m_it.array_iterator < other.m_it.array_iterator); } - case basic_json::value_t::boolean: - case basic_json::value_t::discarded: - case basic_json::value_t::null: - case basic_json::value_t::number_float: - case basic_json::value_t::number_integer: - case basic_json::value_t::string: default: { return (m_it.primitive_iterator < other.m_it.primitive_iterator); @@ -5390,12 +5278,6 @@ class basic_json break; } - case basic_json::value_t::boolean: - case basic_json::value_t::discarded: - case basic_json::value_t::null: - case basic_json::value_t::number_float: - case basic_json::value_t::number_integer: - case basic_json::value_t::string: default: { m_it.primitive_iterator += i; @@ -5443,12 +5325,6 @@ class basic_json return m_it.array_iterator - other.m_it.array_iterator; } - case basic_json::value_t::boolean: - case basic_json::value_t::discarded: - case basic_json::value_t::null: - case basic_json::value_t::number_float: - case basic_json::value_t::number_integer: - case basic_json::value_t::string: default: { return m_it.primitive_iterator - other.m_it.primitive_iterator; @@ -5476,11 +5352,6 @@ class basic_json throw std::out_of_range("cannot get value"); } - case basic_json::value_t::boolean: - case basic_json::value_t::discarded: - case basic_json::value_t::number_float: - case basic_json::value_t::number_integer: - case basic_json::value_t::string: default: { if (m_it.primitive_iterator == -n) @@ -5827,12 +5698,6 @@ class basic_json } /// use an empty key for all primitive types - case value_t::boolean: - case value_t::discarded: - case value_t::null: - case value_t::number_float: - case value_t::number_integer: - case value_t::string: default: { return ""; @@ -6035,8 +5900,6 @@ class basic_json return ""; case token_type::parse_error: return ""; - default: - return ""; } } @@ -6987,11 +6850,6 @@ basic_json_parser_64: } break; } - - default: - { - break; - } } } else @@ -7288,13 +7146,6 @@ basic_json_parser_64: break; } - case lexer::token_type::end_array: - case lexer::token_type::end_object: - case lexer::token_type::end_of_input: - case lexer::token_type::name_separator: - case lexer::token_type::parse_error: - case lexer::token_type::uninitialized: - case lexer::token_type::value_separator: default: { // the last token was unexpected diff --git a/src/json.hpp.re2c b/src/json.hpp.re2c index efb05221d..81efdc092 100644 --- a/src/json.hpp.re2c +++ b/src/json.hpp.re2c @@ -686,8 +686,6 @@ class basic_json break; } - case value_t::null: - case value_t::discarded: default: { break; @@ -1494,10 +1492,6 @@ class basic_json break; } - case value_t::array: - case value_t::discarded: - case value_t::null: - case value_t::object: default: { break; @@ -1542,8 +1536,6 @@ class basic_json break; } - case value_t::discarded: - case value_t::null: default: { throw std::domain_error("cannot use construct with iterators from " + first.m_object->type_name()); @@ -1614,8 +1606,6 @@ class basic_json break; } - case value_t::discarded: - case value_t::null: default: { break; @@ -1719,11 +1709,6 @@ class basic_json break; } - case value_t::boolean: - case value_t::discarded: - case value_t::null: - case value_t::number_float: - case value_t::number_integer: default: { // all other types need no specific destructor @@ -2169,12 +2154,6 @@ class basic_json return static_cast(m_value.number_float); } - case value_t::array: - case value_t::boolean: - case value_t::discarded: - case value_t::null: - case value_t::object: - case value_t::string: default: { throw std::domain_error("type must be number, but is " + type_name()); @@ -2874,8 +2853,6 @@ class basic_json break; } - case value_t::discarded: - case value_t::null: default: { throw std::domain_error("cannot use erase() with " + type_name()); @@ -2971,8 +2948,6 @@ class basic_json break; } - case value_t::discarded: - case value_t::null: default: { throw std::domain_error("cannot use erase with " + type_name()); @@ -3380,11 +3355,6 @@ class basic_json return m_value.object->empty(); } - case basic_json::value_t::boolean: - case basic_json::value_t::discarded: - case basic_json::value_t::number_float: - case basic_json::value_t::number_integer: - case basic_json::value_t::string: default: { // all other types are nonempty @@ -3439,11 +3409,6 @@ class basic_json return m_value.object->size(); } - case value_t::boolean: - case value_t::discarded: - case value_t::number_float: - case value_t::number_integer: - case value_t::string: default: { // all other types have size 1 @@ -3496,12 +3461,6 @@ class basic_json return m_value.object->max_size(); } - case basic_json::value_t::boolean: - case basic_json::value_t::discarded: - case basic_json::value_t::null: - case basic_json::value_t::number_float: - case basic_json::value_t::number_integer: - case basic_json::value_t::string: default: { // all other types have max_size() == size() @@ -3583,8 +3542,6 @@ class basic_json break; } - case value_t::discarded: - case value_t::null: default: { break; @@ -4099,8 +4056,6 @@ class basic_json return lhs.m_value.number_integer == rhs.m_value.number_integer; case value_t::number_float: return approx(lhs.m_value.number_float, rhs.m_value.number_float); - case value_t::discarded: - return false; default: return false; } @@ -4242,8 +4197,6 @@ class basic_json return lhs.m_value.number_integer < rhs.m_value.number_integer; case value_t::number_float: return lhs.m_value.number_float < rhs.m_value.number_float; - case value_t::discarded: - return false; default: return false; } @@ -4527,8 +4480,6 @@ class basic_json return "discarded"; } - case value_t::number_float: - case value_t::number_integer: default: { return "number"; @@ -4839,11 +4790,6 @@ class basic_json o << "null"; return; } - - default: - { - return; - } } } @@ -4991,12 +4937,6 @@ class basic_json break; } - case basic_json::value_t::boolean: - case basic_json::value_t::discarded: - case basic_json::value_t::null: - case basic_json::value_t::number_float: - case basic_json::value_t::number_integer: - case basic_json::value_t::string: default: { m_it.primitive_iterator = primitive_iterator_t(); @@ -5022,12 +4962,6 @@ class basic_json break; } - case value_t::boolean: - case value_t::discarded: - case value_t::null: - case value_t::number_float: - case value_t::number_integer: - case value_t::string: default: { m_it.primitive_iterator = other.m_it.primitive_iterator; @@ -5079,11 +5013,6 @@ class basic_json break; } - case basic_json::value_t::boolean: - case basic_json::value_t::discarded: - case basic_json::value_t::number_float: - case basic_json::value_t::number_integer: - case basic_json::value_t::string: default: { m_it.primitive_iterator.set_begin(); @@ -5109,12 +5038,6 @@ class basic_json break; } - case basic_json::value_t::boolean: - case basic_json::value_t::discarded: - case basic_json::value_t::null: - case basic_json::value_t::number_float: - case basic_json::value_t::number_integer: - case basic_json::value_t::string: default: { m_it.primitive_iterator.set_end(); @@ -5144,11 +5067,6 @@ class basic_json throw std::out_of_range("cannot get value"); } - case value_t::boolean: - case value_t::discarded: - case value_t::number_float: - case value_t::number_integer: - case value_t::string: default: { if (m_it.primitive_iterator.is_begin()) @@ -5178,12 +5096,6 @@ class basic_json return &*m_it.array_iterator; } - case basic_json::value_t::boolean: - case basic_json::value_t::discarded: - case basic_json::value_t::null: - case basic_json::value_t::number_float: - case basic_json::value_t::number_integer: - case basic_json::value_t::string: default: { if (m_it.primitive_iterator.is_begin()) @@ -5224,12 +5136,6 @@ class basic_json break; } - case value_t::boolean: - case value_t::discarded: - case value_t::null: - case value_t::number_float: - case value_t::number_integer: - case value_t::string: default: { ++m_it.primitive_iterator; @@ -5266,12 +5172,6 @@ class basic_json break; } - case value_t::boolean: - case value_t::discarded: - case value_t::null: - case value_t::number_float: - case value_t::number_integer: - case value_t::string: default: { --m_it.primitive_iterator; @@ -5303,12 +5203,6 @@ class basic_json return (m_it.array_iterator == other.m_it.array_iterator); } - case value_t::boolean: - case value_t::discarded: - case value_t::null: - case value_t::number_float: - case value_t::number_integer: - case value_t::string: default: { return (m_it.primitive_iterator == other.m_it.primitive_iterator); @@ -5343,12 +5237,6 @@ class basic_json return (m_it.array_iterator < other.m_it.array_iterator); } - case basic_json::value_t::boolean: - case basic_json::value_t::discarded: - case basic_json::value_t::null: - case basic_json::value_t::number_float: - case basic_json::value_t::number_integer: - case basic_json::value_t::string: default: { return (m_it.primitive_iterator < other.m_it.primitive_iterator); @@ -5390,12 +5278,6 @@ class basic_json break; } - case basic_json::value_t::boolean: - case basic_json::value_t::discarded: - case basic_json::value_t::null: - case basic_json::value_t::number_float: - case basic_json::value_t::number_integer: - case basic_json::value_t::string: default: { m_it.primitive_iterator += i; @@ -5443,12 +5325,6 @@ class basic_json return m_it.array_iterator - other.m_it.array_iterator; } - case basic_json::value_t::boolean: - case basic_json::value_t::discarded: - case basic_json::value_t::null: - case basic_json::value_t::number_float: - case basic_json::value_t::number_integer: - case basic_json::value_t::string: default: { return m_it.primitive_iterator - other.m_it.primitive_iterator; @@ -5476,11 +5352,6 @@ class basic_json throw std::out_of_range("cannot get value"); } - case basic_json::value_t::boolean: - case basic_json::value_t::discarded: - case basic_json::value_t::number_float: - case basic_json::value_t::number_integer: - case basic_json::value_t::string: default: { if (m_it.primitive_iterator == -n) @@ -5827,12 +5698,6 @@ class basic_json } /// use an empty key for all primitive types - case value_t::boolean: - case value_t::discarded: - case value_t::null: - case value_t::number_float: - case value_t::number_integer: - case value_t::string: default: { return ""; @@ -6035,8 +5900,6 @@ class basic_json return ""; case token_type::parse_error: return ""; - default: - return ""; } } @@ -6266,11 +6129,6 @@ class basic_json } break; } - - default: - { - break; - } } } else @@ -6567,13 +6425,6 @@ class basic_json break; } - case lexer::token_type::end_array: - case lexer::token_type::end_object: - case lexer::token_type::end_of_input: - case lexer::token_type::name_separator: - case lexer::token_type::parse_error: - case lexer::token_type::uninitialized: - case lexer::token_type::value_separator: default: { // the last token was unexpected From 2ba901bbf6ae105355d9c7c772adf73ce9f4cd11 Mon Sep 17 00:00:00 2001 From: Niels Date: Mon, 14 Dec 2015 21:23:21 +0100 Subject: [PATCH 17/61] cleanup --- README.md | 2 +- src/json.hpp | 233 ++++++++++++++++++++++++++-------------------- src/json.hpp.re2c | 233 ++++++++++++++++++++++++++-------------------- 3 files changed, 261 insertions(+), 207 deletions(-) diff --git a/README.md b/README.md index a4093fa2a..a3f7c869d 100644 --- a/README.md +++ b/README.md @@ -395,7 +395,7 @@ $ make $ ./json_unit "*" =============================================================================== -All tests passed (3341774 assertions in 27 test cases) +All tests passed (3341803 assertions in 28 test cases) ``` For more information, have a look at the file [.travis.yml](https://github.com/nlohmann/json/blob/master/.travis.yml). diff --git a/src/json.hpp b/src/json.hpp index 2b9a5a0d1..75ab3f5b4 100644 --- a/src/json.hpp +++ b/src/json.hpp @@ -1290,8 +1290,8 @@ class basic_json // is a string for (const auto& element : init) { - if (element.m_type != value_t::array or element.size() != 2 - or element[0].m_type != value_t::string) + if (not element.is_array() or element.size() != 2 + or not element[0].is_string()) { // we found an element that makes it impossible to use the // initializer list as object @@ -2012,7 +2012,7 @@ class basic_json , int>::type = 0> T get_impl(T*) const { - if (m_type == value_t::object) + if (is_object()) { return T(m_value.object->begin(), m_value.object->end()); } @@ -2025,7 +2025,7 @@ class basic_json /// get an object (explicit) object_t get_impl(object_t*) const { - if (m_type == value_t::object) + if (is_object()) { return *(m_value.object); } @@ -2046,7 +2046,7 @@ class basic_json , int>::type = 0> T get_impl(T*) const { - if (m_type == value_t::array) + if (is_array()) { T to_vector; std::transform(m_value.array->begin(), m_value.array->end(), @@ -2070,7 +2070,7 @@ class basic_json , int>::type = 0> std::vector get_impl(std::vector*) const { - if (m_type == value_t::array) + if (is_array()) { std::vector to_vector; to_vector.reserve(m_value.array->size()); @@ -2095,7 +2095,7 @@ class basic_json , int>::type = 0> T get_impl(T*) const { - if (m_type == value_t::array) + if (is_array()) { return T(m_value.array->begin(), m_value.array->end()); } @@ -2108,7 +2108,7 @@ class basic_json /// get an array (explicit) array_t get_impl(array_t*) const { - if (m_type == value_t::array) + if (is_array()) { return *(m_value.array); } @@ -2125,7 +2125,7 @@ class basic_json , int>::type = 0> T get_impl(T*) const { - if (m_type == value_t::string) + if (is_string()) { return *m_value.string; } @@ -2164,7 +2164,7 @@ class basic_json /// get a boolean (explicit) boolean_t get_impl(boolean_t*) const { - if (m_type == value_t::boolean) + if (is_boolean()) { return m_value.boolean; } @@ -2454,12 +2454,14 @@ class basic_json reference at(size_type idx) { // at only works for arrays - if (m_type != value_t::array) + if (is_array()) + { + return m_value.array->at(idx); + } + else { throw std::domain_error("cannot use at() with " + type_name()); } - - return m_value.array->at(idx); } /*! @@ -2484,12 +2486,14 @@ class basic_json const_reference at(size_type idx) const { // at only works for arrays - if (m_type != value_t::array) + if (is_array()) + { + return m_value.array->at(idx); + } + else { throw std::domain_error("cannot use at() with " + type_name()); } - - return m_value.array->at(idx); } /*! @@ -2514,12 +2518,14 @@ class basic_json reference at(const typename object_t::key_type& key) { // at only works for objects - if (m_type != value_t::object) + if (is_object()) + { + return m_value.object->at(key); + } + else { throw std::domain_error("cannot use at() with " + type_name()); } - - return m_value.object->at(key); } /*! @@ -2544,12 +2550,14 @@ class basic_json const_reference at(const typename object_t::key_type& key) const { // at only works for objects - if (m_type != value_t::object) + if (is_object()) + { + return m_value.object->at(key); + } + else { throw std::domain_error("cannot use at() with " + type_name()); } - - return m_value.object->at(key); } /*! @@ -2577,24 +2585,26 @@ class basic_json reference operator[](size_type idx) { // implicitly convert null to object - if (m_type == value_t::null) + if (is_null()) { m_type = value_t::array; m_value.array = create(); } // [] only works for arrays - if (m_type != value_t::array) + if (is_array()) + { + for (size_t i = m_value.array->size(); i <= idx; ++i) + { + m_value.array->push_back(basic_json()); + } + + return m_value.array->operator[](idx); + } + else { throw std::domain_error("cannot use operator[] with " + type_name()); } - - for (size_t i = m_value.array->size(); i <= idx; ++i) - { - m_value.array->push_back(basic_json()); - } - - return m_value.array->operator[](idx); } /*! @@ -2616,12 +2626,14 @@ class basic_json const_reference operator[](size_type idx) const { // at only works for arrays - if (m_type != value_t::array) + if (is_array()) + { + return m_value.array->operator[](idx); + } + else { throw std::domain_error("cannot use operator[] with " + type_name()); } - - return m_value.array->operator[](idx); } /*! @@ -2647,19 +2659,21 @@ class basic_json reference operator[](const typename object_t::key_type& key) { // implicitly convert null to object - if (m_type == value_t::null) + if (is_null()) { m_type = value_t::object; m_value.object = create(); } // [] only works for objects - if (m_type != value_t::object) + if (is_object()) + { + return m_value.object->operator[](key); + } + else { throw std::domain_error("cannot use operator[] with " + type_name()); } - - return m_value.object->operator[](key); } /*! @@ -2688,19 +2702,21 @@ class basic_json reference operator[](const T (&key)[n]) { // implicitly convert null to object - if (m_type == value_t::null) + if (is_null()) { m_type = value_t::object; m_value = value_t::object; } // at only works for objects - if (m_type != value_t::object) + if (is_object()) + { + return m_value.object->operator[](key); + } + else { throw std::domain_error("cannot use operator[] with " + type_name()); } - - return m_value.object->operator[](key); } /*! @@ -2831,7 +2847,7 @@ class basic_json throw std::out_of_range("iterator out of range"); } - if (m_type == value_t::string) + if (is_string()) { delete m_value.string; m_value.string = nullptr; @@ -2924,7 +2940,7 @@ class basic_json throw std::out_of_range("iterators out of range"); } - if (m_type == value_t::string) + if (is_string()) { delete m_value.string; m_value.string = nullptr; @@ -2977,12 +2993,14 @@ class basic_json size_type erase(const typename object_t::key_type& key) { // this erase only works for objects - if (m_type != value_t::object) + if (is_object()) + { + return m_value.object->erase(key); + } + else { throw std::domain_error("cannot use erase() with " + type_name()); } - - return m_value.object->erase(key); } /*! @@ -3002,17 +3020,19 @@ class basic_json void erase(const size_type idx) { // this erase only works for arrays - if (m_type != value_t::array) + if (is_array()) + { + if (idx >= size()) + { + throw std::out_of_range("index out of range"); + } + + m_value.array->erase(m_value.array->begin() + static_cast(idx)); + } + else { throw std::domain_error("cannot use erase() with " + type_name()); } - - if (idx >= size()) - { - throw std::out_of_range("index out of range"); - } - - m_value.array->erase(m_value.array->begin() + static_cast(idx)); } /*! @@ -3034,7 +3054,7 @@ class basic_json { auto result = end(); - if (m_type == value_t::object) + if (is_object()) { result.m_it.object_iterator = m_value.object->find(key); } @@ -3050,7 +3070,7 @@ class basic_json { auto result = cend(); - if (m_type == value_t::object) + if (is_object()) { result.m_it.object_iterator = m_value.object->find(key); } @@ -3077,7 +3097,7 @@ class basic_json size_type count(typename object_t::key_type key) const { // return 0 for all nonobject types - return (m_type == value_t::object) ? m_value.object->count(key) : 0; + return (is_object()) ? m_value.object->count(key) : 0; } /// @} @@ -3569,13 +3589,13 @@ class basic_json void push_back(basic_json&& value) { // push_back only works for null objects or arrays - if (not(m_type == value_t::null or m_type == value_t::array)) + if (not(is_null() or is_array())) { throw std::domain_error("cannot use push_back() with " + type_name()); } // transform null object into an array - if (m_type == value_t::null) + if (is_null()) { m_type = value_t::array; m_value = value_t::array; @@ -3604,13 +3624,13 @@ class basic_json void push_back(const basic_json& value) { // push_back only works for null objects or arrays - if (not(m_type == value_t::null or m_type == value_t::array)) + if (not(is_null() or is_array())) { throw std::domain_error("cannot use push_back() with " + type_name()); } // transform null object into an array - if (m_type == value_t::null) + if (is_null()) { m_type = value_t::array; m_value = value_t::array; @@ -3651,13 +3671,13 @@ class basic_json void push_back(const typename object_t::value_type& value) { // push_back only works for null objects or objects - if (not(m_type == value_t::null or m_type == value_t::object)) + if (not(is_null() or is_object())) { throw std::domain_error("cannot use push_back() with " + type_name()); } // transform null object into an object - if (m_type == value_t::null) + if (is_null()) { m_type = value_t::object; m_value = value_t::object; @@ -3698,21 +3718,23 @@ class basic_json iterator insert(const_iterator pos, const basic_json& value) { // insert only works for arrays - if (m_type != value_t::array) + if (is_array()) + { + // check if iterator pos fits to this JSON value + if (pos.m_object != this) + { + throw std::domain_error("iterator does not fit current value"); + } + + // insert to array and return iterator + iterator result(this); + result.m_it.array_iterator = m_value.array->insert(pos.m_it.array_iterator, value); + return result; + } + else { throw std::domain_error("cannot use insert() with " + type_name()); } - - // check if iterator pos fits to this JSON value - if (pos.m_object != this) - { - throw std::domain_error("iterator does not fit current value"); - } - - // insert to array and return iterator - iterator result(this); - result.m_it.array_iterator = m_value.array->insert(pos.m_it.array_iterator, value); - return result; } /*! @@ -3747,21 +3769,23 @@ class basic_json iterator insert(const_iterator pos, size_type count, const basic_json& value) { // insert only works for arrays - if (m_type != value_t::array) + if (is_array()) + { + // check if iterator pos fits to this JSON value + if (pos.m_object != this) + { + throw std::domain_error("iterator does not fit current value"); + } + + // insert to array and return iterator + iterator result(this); + result.m_it.array_iterator = m_value.array->insert(pos.m_it.array_iterator, count, value); + return result; + } + else { throw std::domain_error("cannot use insert() with " + type_name()); } - - // check if iterator pos fits to this JSON value - if (pos.m_object != this) - { - throw std::domain_error("iterator does not fit current value"); - } - - // insert to array and return iterator - iterator result(this); - result.m_it.array_iterator = m_value.array->insert(pos.m_it.array_iterator, count, value); - return result; } /*! @@ -3791,7 +3815,7 @@ class basic_json iterator insert(const_iterator pos, const_iterator first, const_iterator last) { // insert only works for arrays - if (m_type != value_t::array) + if (not is_array()) { throw std::domain_error("cannot use insert() with " + type_name()); } @@ -3841,7 +3865,7 @@ class basic_json iterator insert(const_iterator pos, std::initializer_list ilist) { // insert only works for arrays - if (m_type != value_t::array) + if (not is_array()) { throw std::domain_error("cannot use insert() with " + type_name()); } @@ -3904,13 +3928,14 @@ class basic_json void swap(array_t& other) { // swap only works for arrays - if (m_type != value_t::array) + if (is_array()) + { + std::swap(*(m_value.array), other); + } + else { throw std::domain_error("cannot use swap() with " + type_name()); } - - // swap arrays - std::swap(*(m_value.array), other); } /*! @@ -3933,13 +3958,14 @@ class basic_json void swap(object_t& other) { // swap only works for objects - if (m_type != value_t::object) + if (is_object()) + { + std::swap(*(m_value.object), other); + } + else { throw std::domain_error("cannot use swap() with " + type_name()); } - - // swap objects - std::swap(*(m_value.object), other); } /*! @@ -3962,13 +3988,14 @@ class basic_json void swap(string_t& other) { // swap only works for strings - if (m_type != value_t::string) + if (is_string()) + { + std::swap(*(m_value.string), other); + } + else { throw std::domain_error("cannot use swap() with " + type_name()); } - - // swap strings - std::swap(*(m_value.string), other); } /// @} @@ -5369,7 +5396,7 @@ class basic_json /// return the key of an object iterator typename object_t::key_type key() const { - if (m_object->m_type == basic_json::value_t::object) + if (m_object->is_object()) { return m_it.object_iterator->first; } diff --git a/src/json.hpp.re2c b/src/json.hpp.re2c index 81efdc092..6c419a890 100644 --- a/src/json.hpp.re2c +++ b/src/json.hpp.re2c @@ -1290,8 +1290,8 @@ class basic_json // is a string for (const auto& element : init) { - if (element.m_type != value_t::array or element.size() != 2 - or element[0].m_type != value_t::string) + if (not element.is_array() or element.size() != 2 + or not element[0].is_string()) { // we found an element that makes it impossible to use the // initializer list as object @@ -2012,7 +2012,7 @@ class basic_json , int>::type = 0> T get_impl(T*) const { - if (m_type == value_t::object) + if (is_object()) { return T(m_value.object->begin(), m_value.object->end()); } @@ -2025,7 +2025,7 @@ class basic_json /// get an object (explicit) object_t get_impl(object_t*) const { - if (m_type == value_t::object) + if (is_object()) { return *(m_value.object); } @@ -2046,7 +2046,7 @@ class basic_json , int>::type = 0> T get_impl(T*) const { - if (m_type == value_t::array) + if (is_array()) { T to_vector; std::transform(m_value.array->begin(), m_value.array->end(), @@ -2070,7 +2070,7 @@ class basic_json , int>::type = 0> std::vector get_impl(std::vector*) const { - if (m_type == value_t::array) + if (is_array()) { std::vector to_vector; to_vector.reserve(m_value.array->size()); @@ -2095,7 +2095,7 @@ class basic_json , int>::type = 0> T get_impl(T*) const { - if (m_type == value_t::array) + if (is_array()) { return T(m_value.array->begin(), m_value.array->end()); } @@ -2108,7 +2108,7 @@ class basic_json /// get an array (explicit) array_t get_impl(array_t*) const { - if (m_type == value_t::array) + if (is_array()) { return *(m_value.array); } @@ -2125,7 +2125,7 @@ class basic_json , int>::type = 0> T get_impl(T*) const { - if (m_type == value_t::string) + if (is_string()) { return *m_value.string; } @@ -2164,7 +2164,7 @@ class basic_json /// get a boolean (explicit) boolean_t get_impl(boolean_t*) const { - if (m_type == value_t::boolean) + if (is_boolean()) { return m_value.boolean; } @@ -2454,12 +2454,14 @@ class basic_json reference at(size_type idx) { // at only works for arrays - if (m_type != value_t::array) + if (is_array()) + { + return m_value.array->at(idx); + } + else { throw std::domain_error("cannot use at() with " + type_name()); } - - return m_value.array->at(idx); } /*! @@ -2484,12 +2486,14 @@ class basic_json const_reference at(size_type idx) const { // at only works for arrays - if (m_type != value_t::array) + if (is_array()) + { + return m_value.array->at(idx); + } + else { throw std::domain_error("cannot use at() with " + type_name()); } - - return m_value.array->at(idx); } /*! @@ -2514,12 +2518,14 @@ class basic_json reference at(const typename object_t::key_type& key) { // at only works for objects - if (m_type != value_t::object) + if (is_object()) + { + return m_value.object->at(key); + } + else { throw std::domain_error("cannot use at() with " + type_name()); } - - return m_value.object->at(key); } /*! @@ -2544,12 +2550,14 @@ class basic_json const_reference at(const typename object_t::key_type& key) const { // at only works for objects - if (m_type != value_t::object) + if (is_object()) + { + return m_value.object->at(key); + } + else { throw std::domain_error("cannot use at() with " + type_name()); } - - return m_value.object->at(key); } /*! @@ -2577,24 +2585,26 @@ class basic_json reference operator[](size_type idx) { // implicitly convert null to object - if (m_type == value_t::null) + if (is_null()) { m_type = value_t::array; m_value.array = create(); } // [] only works for arrays - if (m_type != value_t::array) + if (is_array()) + { + for (size_t i = m_value.array->size(); i <= idx; ++i) + { + m_value.array->push_back(basic_json()); + } + + return m_value.array->operator[](idx); + } + else { throw std::domain_error("cannot use operator[] with " + type_name()); } - - for (size_t i = m_value.array->size(); i <= idx; ++i) - { - m_value.array->push_back(basic_json()); - } - - return m_value.array->operator[](idx); } /*! @@ -2616,12 +2626,14 @@ class basic_json const_reference operator[](size_type idx) const { // at only works for arrays - if (m_type != value_t::array) + if (is_array()) + { + return m_value.array->operator[](idx); + } + else { throw std::domain_error("cannot use operator[] with " + type_name()); } - - return m_value.array->operator[](idx); } /*! @@ -2647,19 +2659,21 @@ class basic_json reference operator[](const typename object_t::key_type& key) { // implicitly convert null to object - if (m_type == value_t::null) + if (is_null()) { m_type = value_t::object; m_value.object = create(); } // [] only works for objects - if (m_type != value_t::object) + if (is_object()) + { + return m_value.object->operator[](key); + } + else { throw std::domain_error("cannot use operator[] with " + type_name()); } - - return m_value.object->operator[](key); } /*! @@ -2688,19 +2702,21 @@ class basic_json reference operator[](const T (&key)[n]) { // implicitly convert null to object - if (m_type == value_t::null) + if (is_null()) { m_type = value_t::object; m_value = value_t::object; } // at only works for objects - if (m_type != value_t::object) + if (is_object()) + { + return m_value.object->operator[](key); + } + else { throw std::domain_error("cannot use operator[] with " + type_name()); } - - return m_value.object->operator[](key); } /*! @@ -2831,7 +2847,7 @@ class basic_json throw std::out_of_range("iterator out of range"); } - if (m_type == value_t::string) + if (is_string()) { delete m_value.string; m_value.string = nullptr; @@ -2924,7 +2940,7 @@ class basic_json throw std::out_of_range("iterators out of range"); } - if (m_type == value_t::string) + if (is_string()) { delete m_value.string; m_value.string = nullptr; @@ -2977,12 +2993,14 @@ class basic_json size_type erase(const typename object_t::key_type& key) { // this erase only works for objects - if (m_type != value_t::object) + if (is_object()) + { + return m_value.object->erase(key); + } + else { throw std::domain_error("cannot use erase() with " + type_name()); } - - return m_value.object->erase(key); } /*! @@ -3002,17 +3020,19 @@ class basic_json void erase(const size_type idx) { // this erase only works for arrays - if (m_type != value_t::array) + if (is_array()) + { + if (idx >= size()) + { + throw std::out_of_range("index out of range"); + } + + m_value.array->erase(m_value.array->begin() + static_cast(idx)); + } + else { throw std::domain_error("cannot use erase() with " + type_name()); } - - if (idx >= size()) - { - throw std::out_of_range("index out of range"); - } - - m_value.array->erase(m_value.array->begin() + static_cast(idx)); } /*! @@ -3034,7 +3054,7 @@ class basic_json { auto result = end(); - if (m_type == value_t::object) + if (is_object()) { result.m_it.object_iterator = m_value.object->find(key); } @@ -3050,7 +3070,7 @@ class basic_json { auto result = cend(); - if (m_type == value_t::object) + if (is_object()) { result.m_it.object_iterator = m_value.object->find(key); } @@ -3077,7 +3097,7 @@ class basic_json size_type count(typename object_t::key_type key) const { // return 0 for all nonobject types - return (m_type == value_t::object) ? m_value.object->count(key) : 0; + return (is_object()) ? m_value.object->count(key) : 0; } /// @} @@ -3569,13 +3589,13 @@ class basic_json void push_back(basic_json&& value) { // push_back only works for null objects or arrays - if (not(m_type == value_t::null or m_type == value_t::array)) + if (not(is_null() or is_array())) { throw std::domain_error("cannot use push_back() with " + type_name()); } // transform null object into an array - if (m_type == value_t::null) + if (is_null()) { m_type = value_t::array; m_value = value_t::array; @@ -3604,13 +3624,13 @@ class basic_json void push_back(const basic_json& value) { // push_back only works for null objects or arrays - if (not(m_type == value_t::null or m_type == value_t::array)) + if (not(is_null() or is_array())) { throw std::domain_error("cannot use push_back() with " + type_name()); } // transform null object into an array - if (m_type == value_t::null) + if (is_null()) { m_type = value_t::array; m_value = value_t::array; @@ -3651,13 +3671,13 @@ class basic_json void push_back(const typename object_t::value_type& value) { // push_back only works for null objects or objects - if (not(m_type == value_t::null or m_type == value_t::object)) + if (not(is_null() or is_object())) { throw std::domain_error("cannot use push_back() with " + type_name()); } // transform null object into an object - if (m_type == value_t::null) + if (is_null()) { m_type = value_t::object; m_value = value_t::object; @@ -3698,21 +3718,23 @@ class basic_json iterator insert(const_iterator pos, const basic_json& value) { // insert only works for arrays - if (m_type != value_t::array) + if (is_array()) + { + // check if iterator pos fits to this JSON value + if (pos.m_object != this) + { + throw std::domain_error("iterator does not fit current value"); + } + + // insert to array and return iterator + iterator result(this); + result.m_it.array_iterator = m_value.array->insert(pos.m_it.array_iterator, value); + return result; + } + else { throw std::domain_error("cannot use insert() with " + type_name()); } - - // check if iterator pos fits to this JSON value - if (pos.m_object != this) - { - throw std::domain_error("iterator does not fit current value"); - } - - // insert to array and return iterator - iterator result(this); - result.m_it.array_iterator = m_value.array->insert(pos.m_it.array_iterator, value); - return result; } /*! @@ -3747,21 +3769,23 @@ class basic_json iterator insert(const_iterator pos, size_type count, const basic_json& value) { // insert only works for arrays - if (m_type != value_t::array) + if (is_array()) + { + // check if iterator pos fits to this JSON value + if (pos.m_object != this) + { + throw std::domain_error("iterator does not fit current value"); + } + + // insert to array and return iterator + iterator result(this); + result.m_it.array_iterator = m_value.array->insert(pos.m_it.array_iterator, count, value); + return result; + } + else { throw std::domain_error("cannot use insert() with " + type_name()); } - - // check if iterator pos fits to this JSON value - if (pos.m_object != this) - { - throw std::domain_error("iterator does not fit current value"); - } - - // insert to array and return iterator - iterator result(this); - result.m_it.array_iterator = m_value.array->insert(pos.m_it.array_iterator, count, value); - return result; } /*! @@ -3791,7 +3815,7 @@ class basic_json iterator insert(const_iterator pos, const_iterator first, const_iterator last) { // insert only works for arrays - if (m_type != value_t::array) + if (not is_array()) { throw std::domain_error("cannot use insert() with " + type_name()); } @@ -3841,7 +3865,7 @@ class basic_json iterator insert(const_iterator pos, std::initializer_list ilist) { // insert only works for arrays - if (m_type != value_t::array) + if (not is_array()) { throw std::domain_error("cannot use insert() with " + type_name()); } @@ -3904,13 +3928,14 @@ class basic_json void swap(array_t& other) { // swap only works for arrays - if (m_type != value_t::array) + if (is_array()) + { + std::swap(*(m_value.array), other); + } + else { throw std::domain_error("cannot use swap() with " + type_name()); } - - // swap arrays - std::swap(*(m_value.array), other); } /*! @@ -3933,13 +3958,14 @@ class basic_json void swap(object_t& other) { // swap only works for objects - if (m_type != value_t::object) + if (is_object()) + { + std::swap(*(m_value.object), other); + } + else { throw std::domain_error("cannot use swap() with " + type_name()); } - - // swap objects - std::swap(*(m_value.object), other); } /*! @@ -3962,13 +3988,14 @@ class basic_json void swap(string_t& other) { // swap only works for strings - if (m_type != value_t::string) + if (is_string()) + { + std::swap(*(m_value.string), other); + } + else { throw std::domain_error("cannot use swap() with " + type_name()); } - - // swap strings - std::swap(*(m_value.string), other); } /// @} @@ -5369,7 +5396,7 @@ class basic_json /// return the key of an object iterator typename object_t::key_type key() const { - if (m_object->m_type == basic_json::value_t::object) + if (m_object->is_object()) { return m_it.object_iterator->first; } From cd04a7d3e952385617d43fd412d90fece7b586e9 Mon Sep 17 00:00:00 2001 From: Niels Date: Tue, 15 Dec 2015 08:38:54 +0100 Subject: [PATCH 18/61] fix for #133 added value() function to get object value at given key or a default value if key does not exist --- README.md | 2 +- doc/examples/basic_json__value.cpp | 29 ++++++++ doc/examples/basic_json__value.link | 1 + doc/examples/basic_json__value.output | 1 + src/json.hpp | 102 +++++++++++++++++++++++++- src/json.hpp.re2c | 102 +++++++++++++++++++++++++- test/unit.cpp | 95 ++++++++++++++++++++++++ 7 files changed, 325 insertions(+), 7 deletions(-) create mode 100644 doc/examples/basic_json__value.cpp create mode 100644 doc/examples/basic_json__value.link create mode 100644 doc/examples/basic_json__value.output diff --git a/README.md b/README.md index a3f7c869d..a77961f22 100644 --- a/README.md +++ b/README.md @@ -395,7 +395,7 @@ $ make $ ./json_unit "*" =============================================================================== -All tests passed (3341803 assertions in 28 test cases) +All tests passed (3341846 assertions in 28 test cases) ``` For more information, have a look at the file [.travis.yml](https://github.com/nlohmann/json/blob/master/.travis.yml). diff --git a/doc/examples/basic_json__value.cpp b/doc/examples/basic_json__value.cpp new file mode 100644 index 000000000..37081791e --- /dev/null +++ b/doc/examples/basic_json__value.cpp @@ -0,0 +1,29 @@ +#include + +using namespace nlohmann; + +int main() +{ + // create a JSON object with different entry types + json j = + { + {"integer", 1}, + {"floating", 42.23}, + {"string", "hello world"}, + {"boolean", true}, + {"object", {{"key1", 1}, {"key2", 2}}}, + {"array", {1, 2, 3}} + }; + + // access existing values + int v_integer = j.value("integer", 0); + double v_floating = j.value("floating", 47.11); + + // access nonexisting values and rely on default value + std::string v_string = j.value("nonexisting", "oops"); + bool v_boolean = j.value("nonexisting", false); + + // output values + std::cout << std::boolalpha << v_integer << " " << v_floating + << " " << v_string << " " << v_boolean << "\n"; +} diff --git a/doc/examples/basic_json__value.link b/doc/examples/basic_json__value.link new file mode 100644 index 000000000..6698c8917 --- /dev/null +++ b/doc/examples/basic_json__value.link @@ -0,0 +1 @@ +online \ No newline at end of file diff --git a/doc/examples/basic_json__value.output b/doc/examples/basic_json__value.output new file mode 100644 index 000000000..dfc40e58c --- /dev/null +++ b/doc/examples/basic_json__value.output @@ -0,0 +1 @@ +1 42.23 oops false diff --git a/src/json.hpp b/src/json.hpp index 75ab3f5b4..782657e11 100644 --- a/src/json.hpp +++ b/src/json.hpp @@ -2514,6 +2514,10 @@ class basic_json @liveexample{The example below shows how object elements can be read and written using at.,at__object_t_key_type} + + @sa @ref operator[](const typename object_t::key_type&) for unchecked + access by reference + @sa @ref value() for access by value with a default value */ reference at(const typename object_t::key_type& key) { @@ -2546,6 +2550,10 @@ class basic_json @liveexample{The example below shows how object elements can be read using at.,at__object_t_key_type_const} + + @sa @ref operator[](const typename object_t::key_type&) for unchecked + access by reference + @sa @ref value() for access by value with a default value */ const_reference at(const typename object_t::key_type& key) const { @@ -2655,6 +2663,10 @@ class basic_json @liveexample{The example below shows how object elements can be read and written using the [] operator.,operatorarray__key_type} + + @sa @ref at(const typename object_t::key_type&) for access by reference + with range checking + @sa @ref value() for access by value with a default value */ reference operator[](const typename object_t::key_type& key) { @@ -2697,6 +2709,10 @@ class basic_json @liveexample{The example below shows how object elements can be read and written using the [] operator.,operatorarray__key_type} + + @sa @ref at(const typename object_t::key_type&) for access by reference + with range checking + @sa @ref value() for access by value with a default value */ template reference operator[](const T (&key)[n]) @@ -2719,6 +2735,86 @@ class basic_json } } + /*! + @brief access specified object element with default value + + Returns either a copy of an object's element at the specified key @a key or + a given default value if no element with key @a key exists. + + The function is basically equivalent to executing + @code{.cpp} + try { + return at(key); + } catch(std::out_of_range) { + return default_value; + } + @endcode + + @note Unlike @ref at(const typename object_t::key_type&), this function + does not throw if the given key @a key was not found. + + @note Unlike @ref operator[](const typename object_t::key_type& key), this + function does not implicitly add an element to the position defined by @a + key. This function is furthermore also applicable to const objects. + + @param[in] key key of the element to access + @param[in] default_value the value to return if @a key is not found + + @tparam ValueType type compatible to JSON values, for instance `int` for + JSON integer numbers, `bool` for JSON booleans, or `std::vector` types for + JSON arrays. Note the type of the expected value at @a key and the default + value @a default_value must be compatible. + + @return copy of the element at key @a key or @a default_value if @a key + is not found + + @throw std::domain_error if JSON is not an object + + @complexity Logarithmic in the size of the container. + + @liveexample{The example below shows how object elements can be queried + with a default value.,basic_json__value} + + @sa @ref at(const typename object_t::key_type&) for access by reference + with range checking + @sa @ref operator[](const typename object_t::key_type&) for unchecked + access by reference + */ + template ::value + , int>::type = 0> + ValueType value(const typename object_t::key_type& key, ValueType default_value) const + { + // at only works for objects + if (is_object()) + { + // if key is found, return value and given default value otherwise + const auto it = find(key); + if (it != end()) + { + return *it; + } + else + { + return default_value; + } + } + else + { + throw std::domain_error("cannot use value() with " + type_name()); + } + } + + /*! + // overload for a default value of type const char* + @copydoc basic_json::value() + */ + string_t value(const typename object_t::key_type& key, const char* default_value) const + { + return value(key, string_t(default_value)); + } + /*! @brief access the first element @@ -5660,9 +5756,9 @@ class basic_json /*! @brief wrapper to access iterator member functions in range-based for - This class allows to access @ref key() and @ref value() during range-based - for loops. In these loops, a reference to the JSON values is returned, so - there is no access to the underlying iterator. + This class allows to access @ref iterator::key() and @ref iterator::value() + during range-based for loops. In these loops, a reference to the JSON + values is returned, so there is no access to the underlying iterator. */ class iterator_wrapper { diff --git a/src/json.hpp.re2c b/src/json.hpp.re2c index 6c419a890..682abb1c3 100644 --- a/src/json.hpp.re2c +++ b/src/json.hpp.re2c @@ -2514,6 +2514,10 @@ class basic_json @liveexample{The example below shows how object elements can be read and written using at.,at__object_t_key_type} + + @sa @ref operator[](const typename object_t::key_type&) for unchecked + access by reference + @sa @ref value() for access by value with a default value */ reference at(const typename object_t::key_type& key) { @@ -2546,6 +2550,10 @@ class basic_json @liveexample{The example below shows how object elements can be read using at.,at__object_t_key_type_const} + + @sa @ref operator[](const typename object_t::key_type&) for unchecked + access by reference + @sa @ref value() for access by value with a default value */ const_reference at(const typename object_t::key_type& key) const { @@ -2655,6 +2663,10 @@ class basic_json @liveexample{The example below shows how object elements can be read and written using the [] operator.,operatorarray__key_type} + + @sa @ref at(const typename object_t::key_type&) for access by reference + with range checking + @sa @ref value() for access by value with a default value */ reference operator[](const typename object_t::key_type& key) { @@ -2697,6 +2709,10 @@ class basic_json @liveexample{The example below shows how object elements can be read and written using the [] operator.,operatorarray__key_type} + + @sa @ref at(const typename object_t::key_type&) for access by reference + with range checking + @sa @ref value() for access by value with a default value */ template reference operator[](const T (&key)[n]) @@ -2719,6 +2735,86 @@ class basic_json } } + /*! + @brief access specified object element with default value + + Returns either a copy of an object's element at the specified key @a key or + a given default value if no element with key @a key exists. + + The function is basically equivalent to executing + @code{.cpp} + try { + return at(key); + } catch(std::out_of_range) { + return default_value; + } + @endcode + + @note Unlike @ref at(const typename object_t::key_type&), this function + does not throw if the given key @a key was not found. + + @note Unlike @ref operator[](const typename object_t::key_type& key), this + function does not implicitly add an element to the position defined by @a + key. This function is furthermore also applicable to const objects. + + @param[in] key key of the element to access + @param[in] default_value the value to return if @a key is not found + + @tparam ValueType type compatible to JSON values, for instance `int` for + JSON integer numbers, `bool` for JSON booleans, or `std::vector` types for + JSON arrays. Note the type of the expected value at @a key and the default + value @a default_value must be compatible. + + @return copy of the element at key @a key or @a default_value if @a key + is not found + + @throw std::domain_error if JSON is not an object + + @complexity Logarithmic in the size of the container. + + @liveexample{The example below shows how object elements can be queried + with a default value.,basic_json__value} + + @sa @ref at(const typename object_t::key_type&) for access by reference + with range checking + @sa @ref operator[](const typename object_t::key_type&) for unchecked + access by reference + */ + template ::value + , int>::type = 0> + ValueType value(const typename object_t::key_type& key, ValueType default_value) const + { + // at only works for objects + if (is_object()) + { + // if key is found, return value and given default value otherwise + const auto it = find(key); + if (it != end()) + { + return *it; + } + else + { + return default_value; + } + } + else + { + throw std::domain_error("cannot use value() with " + type_name()); + } + } + + /*! + // overload for a default value of type const char* + @copydoc basic_json::value() + */ + string_t value(const typename object_t::key_type& key, const char* default_value) const + { + return value(key, string_t(default_value)); + } + /*! @brief access the first element @@ -5660,9 +5756,9 @@ class basic_json /*! @brief wrapper to access iterator member functions in range-based for - This class allows to access @ref key() and @ref value() during range-based - for loops. In these loops, a reference to the JSON values is returned, so - there is no access to the underlying iterator. + This class allows to access @ref iterator::key() and @ref iterator::value() + during range-based for loops. In these loops, a reference to the JSON + values is returned, so there is no access to the underlying iterator. */ class iterator_wrapper { diff --git a/test/unit.cpp b/test/unit.cpp index 37baf50c1..8826d835e 100644 --- a/test/unit.cpp +++ b/test/unit.cpp @@ -3082,6 +3082,101 @@ TEST_CASE("element access") } } + SECTION("access specified element with default value") + { + SECTION("access existing value") + { + CHECK(j.value("integer", 2) == 1); + CHECK(j.value("integer", 1.0) == Approx(1)); + CHECK(j.value("null", json(1)) == json()); + CHECK(j.value("boolean", false) == true); + CHECK(j.value("string", "bar") == "hello world"); + CHECK(j.value("string", std::string("bar")) == "hello world"); + CHECK(j.value("floating", 12.34) == Approx(42.23)); + CHECK(j.value("floating", 12) == 42); + CHECK(j.value("object", json({{"foo", "bar"}})) == json(json::object())); + CHECK(j.value("array", json({10, 100})) == json({1, 2, 3})); + + CHECK(j_const.value("integer", 2) == 1); + CHECK(j_const.value("integer", 1.0) == Approx(1)); + CHECK(j_const.value("boolean", false) == true); + CHECK(j_const.value("string", "bar") == "hello world"); + CHECK(j_const.value("string", std::string("bar")) == "hello world"); + CHECK(j_const.value("floating", 12.34) == Approx(42.23)); + CHECK(j_const.value("floating", 12) == 42); + CHECK(j_const.value("object", json({{"foo", "bar"}})) == json(json::object())); + CHECK(j_const.value("array", json({10, 100})) == json({1, 2, 3})); + } + + SECTION("access non-existing value") + { + CHECK(j.value("_", 2) == 2); + CHECK(j.value("_", false) == false); + CHECK(j.value("_", "bar") == "bar"); + CHECK(j.value("_", 12.34) == Approx(12.34)); + CHECK(j.value("_", json({{"foo", "bar"}})) == json({{"foo", "bar"}})); + CHECK(j.value("_", json({10, 100})) == json({10, 100})); + + CHECK(j_const.value("_", 2) == 2); + CHECK(j_const.value("_", false) == false); + CHECK(j_const.value("_", "bar") == "bar"); + CHECK(j_const.value("_", 12.34) == Approx(12.34)); + CHECK(j_const.value("_", json({{"foo", "bar"}})) == json({{"foo", "bar"}})); + CHECK(j_const.value("_", json({10, 100})) == json({10, 100})); + } + + SECTION("access on non-object type") + { + SECTION("null") + { + json j_nonobject(json::value_t::null); + const json j_nonobject_const(j_nonobject); + CHECK_THROWS_AS(j_nonobject.value("foo", 1), std::domain_error); + CHECK_THROWS_AS(j_nonobject_const.value("foo", 1), std::domain_error); + } + + SECTION("boolean") + { + json j_nonobject(json::value_t::boolean); + const json j_nonobject_const(j_nonobject); + CHECK_THROWS_AS(j_nonobject.value("foo", 1), std::domain_error); + CHECK_THROWS_AS(j_nonobject_const.value("foo", 1), std::domain_error); + } + + SECTION("string") + { + json j_nonobject(json::value_t::string); + const json j_nonobject_const(j_nonobject); + CHECK_THROWS_AS(j_nonobject.value("foo", 1), std::domain_error); + CHECK_THROWS_AS(j_nonobject_const.value("foo", 1), std::domain_error); + } + + SECTION("array") + { + json j_nonobject(json::value_t::array); + const json j_nonobject_const(j_nonobject); + CHECK_THROWS_AS(j_nonobject.value("foo", 1), std::domain_error); + CHECK_THROWS_AS(j_nonobject_const.value("foo", 1), std::domain_error); + } + + SECTION("number (integer)") + { + json j_nonobject(json::value_t::number_integer); + const json j_nonobject_const(j_nonobject); + CHECK_THROWS_AS(j_nonobject.value("foo", 1), std::domain_error); + CHECK_THROWS_AS(j_nonobject_const.value("foo", 1), std::domain_error); + } + + SECTION("number (floating-point)") + { + json j_nonobject(json::value_t::number_float); + const json j_nonobject_const(j_nonobject); + CHECK_THROWS_AS(j_nonobject.value("foo", 1), std::domain_error); + CHECK_THROWS_AS(j_nonobject_const.value("foo", 1), std::domain_error); + } + } + } + SECTION("front and back") { // "array" is the smallest key From 1df5d726d95dec49cec35c6e57301b01e25cc30a Mon Sep 17 00:00:00 2001 From: Niels Date: Tue, 15 Dec 2015 18:34:07 +0100 Subject: [PATCH 19/61] undid the fix for #136 --- README.md | 9 ++++++--- src/json.hpp | 19 ------------------- src/json.hpp.re2c | 19 ------------------- 3 files changed, 6 insertions(+), 41 deletions(-) diff --git a/README.md b/README.md index a77961f22..cd9be0d32 100644 --- a/README.md +++ b/README.md @@ -42,12 +42,15 @@ to the files you want to use JSON objects. That's it. Do not forget to set the n Though it's 2015 already, the support for C++11 is still a bit sparse. Currently, the following compilers are known to work: -- GCC 4.9 - 5.2 (and possible later) -- Clang 3.4 - 3.7 (and possible later) -- Microsoft Visual C++ 14.0 RC (and possible later) +- GCC 4.9 - 5.2 (and possibly later) +- Clang 3.4 - 3.7 (and possibly later) +- Microsoft Visual C++ 14.0 RC (and possibly later) I would be happy to learn about other compilers/versions. +For GCC running on MinGW or Android SDK, the error `'to_string' is not a member of 'std'` (or similarly, for `strtod`) may occur. Note this is not an issue with the code, but rather with the compiler itself. Please refer to [this site](http://tehsausage.com/mingw-to-string) and [this discussion](https://github.com/nlohmann/json/issues/136) for information on how to fix this bug. + + ## Examples Here are some examples to give you an idea how to use the class. diff --git a/src/json.hpp b/src/json.hpp index 782657e11..3e9c9a3da 100644 --- a/src/json.hpp +++ b/src/json.hpp @@ -70,25 +70,6 @@ Class @ref nlohmann::basic_json is a good entry point for the documentation. using ssize_t = SSIZE_T; #endif -// workaround for Android NDK (see https://github.com/nlohmann/json/issues/136) -#ifdef __ANDROID__ -namespace std -{ -template -std::string to_string(T v) -{ - std::ostringstream ss; - ss << v; - return ss.str(); -} - -inline long double strtold(const char* str, char** str_end) -{ - return strtod(str, str_end); -} -} -#endif - /*! @brief namespace for Niels Lohmann @see https://github.com/nlohmann diff --git a/src/json.hpp.re2c b/src/json.hpp.re2c index 682abb1c3..383ddda77 100644 --- a/src/json.hpp.re2c +++ b/src/json.hpp.re2c @@ -70,25 +70,6 @@ Class @ref nlohmann::basic_json is a good entry point for the documentation. using ssize_t = SSIZE_T; #endif -// workaround for Android NDK (see https://github.com/nlohmann/json/issues/136) -#ifdef __ANDROID__ -namespace std -{ -template -std::string to_string(T v) -{ - std::ostringstream ss; - ss << v; - return ss.str(); -} - -inline long double strtold(const char* str, char** str_end) -{ - return strtod(str, str_end); -} -} -#endif - /*! @brief namespace for Niels Lohmann @see https://github.com/nlohmann From a615598b14664e95816ab845dcfc3c4dbce104c3 Mon Sep 17 00:00:00 2001 From: Niels Date: Tue, 15 Dec 2015 19:42:32 +0100 Subject: [PATCH 20/61] cleanup documentation; started added versions --- src/json.hpp | 200 +++++++++++++++++++++++++++++++++++----------- src/json.hpp.re2c | 200 +++++++++++++++++++++++++++++++++++----------- 2 files changed, 304 insertions(+), 96 deletions(-) diff --git a/src/json.hpp b/src/json.hpp index 3e9c9a3da..cb2a803b2 100644 --- a/src/json.hpp +++ b/src/json.hpp @@ -314,10 +314,12 @@ class basic_json #### Storage - Objects are stored as pointers in a `basic_json` type. That is, for any + Objects are stored as pointers in a @ref basic_json type. That is, for any access to object values, a pointer of type `object_t*` must be dereferenced. - @sa array_t + @sa @ref array_t -- type for an array value + + @since version 1.0 */ using object_t = ObjectType>; @@ -402,9 +408,11 @@ class basic_json #### Storage - String values are stored as pointers in a `basic_json` type. That is, for - any access to string values, a pointer of type `string_t*` must be + String values are stored as pointers in a @ref basic_json type. That is, + for any access to string values, a pointer of type `string_t*` must be dereferenced. + + @since version 1.0 */ using string_t = StringType; @@ -428,7 +436,9 @@ class basic_json #### Storage - Boolean values are stored directly inside a `basic_json` type. + Boolean values are stored directly inside a @ref basic_json type. + + @since version 1.0 */ using boolean_t = BooleanType; @@ -492,7 +502,11 @@ class basic_json #### Storage - Integer number values are stored directly inside a `basic_json` type. + Integer number values are stored directly inside a @ref basic_json type. + + @sa @ref number_float_t -- type for number values (floating-point) + + @since version 1.0 */ using number_integer_t = NumberIntegerType; @@ -552,7 +566,12 @@ class basic_json #### Storage - Floating-point number values are stored directly inside a `basic_json` type. + Floating-point number values are stored directly inside a @ref basic_json + type. + + @sa @ref number_integer_t -- type for number values (integer) + + @since version 1.0 */ using number_float_t = NumberFloatType; @@ -567,8 +586,11 @@ class basic_json @brief the JSON type enumeration This enumeration collects the different JSON types. It is internally used - to distinguish the stored values, and the functions is_null, is_object, - is_array, is_string, is_boolean, is_number, and is_discarded rely on it. + to distinguish the stored values, and the functions @ref is_null(), @ref + is_object(), @ref is_array(), @ref is_string(), @ref is_boolean(), @ref + is_number(), and @ref is_discarded() rely on it. + + @since version 1.0 */ enum class value_t : uint8_t { @@ -602,7 +624,13 @@ class basic_json // JSON value storage // //////////////////////// - /// a JSON value + /*! + @brief a JSON value + + The actual storage for a JSON value of the @ref basic_json class. + + @since version 1.0 + */ union json_value { /// object (stored with pointer to save storage) @@ -704,6 +732,8 @@ class basic_json This enumeration lists the parser events that can trigger calling a callback function of type @ref parser_callback_t during parsing. + + @since version 1.0 */ enum class parse_event_t : uint8_t { @@ -767,9 +797,10 @@ class basic_json @sa @ref parse(std::istream&, parser_callback_t) or @ref parse(const string_t&, parser_callback_t) for examples + + @since version 1.0 */ - using parser_callback_t = std::function; + using parser_callback_t = std::function; ////////////////// @@ -800,6 +831,14 @@ class basic_json @liveexample{The following code shows the constructor for different @ref value_t values,basic_json__value_t} + + @sa @ref basic_json(std::nullptr_t) -- create a `null` value + @sa @ref basic_json(boolean_t value) -- create a boolean value + @sa @ref basic_json(const string_t&) -- create a string value + @sa @ref basic_json(const object_t&) -- create a object value + @sa @ref basic_json(const array_t&) -- create a array value + + @since version 1.0 */ basic_json(const value_t value) : m_type(value), m_value(value) @@ -820,7 +859,9 @@ class basic_json @liveexample{The following code shows the constructor for a `null` JSON value.,basic_json} - @sa basic_json(std::nullptr_t) + @sa @ref basic_json(std::nullptr_t) -- create a `null` value + + @since version 1.0 */ basic_json() noexcept = default; @@ -838,7 +879,10 @@ class basic_json @liveexample{The following code shows the constructor with null pointer parameter.,basic_json__nullptr_t} - @sa basic_json() + @sa @ref basic_json() -- default constructor (implicitly creating a `null` + value) + + @since version 1.0 */ basic_json(std::nullptr_t) noexcept : basic_json(value_t::null) @@ -858,7 +902,10 @@ class basic_json @liveexample{The following code shows the constructor with an @ref object_t parameter.,basic_json__object_t} - @sa basic_json(const CompatibleObjectType&) + @sa @ref basic_json(const CompatibleObjectType&) -- create an object value + from a compatible STL container + + @since version 1.0 */ basic_json(const object_t& value) : m_type(value_t::object), m_value(value) @@ -883,7 +930,9 @@ class basic_json @liveexample{The following code shows the constructor with several compatible object type parameters.,basic_json__CompatibleObjectType} - @sa basic_json(const object_t&) + @sa @ref basic_json(const object_t&) -- create an object value + + @since version 1.0 */ template ) - create a JSON - array value from an initializer list - @sa basic_json object(std::initializer_list) - create a JSON - object value from an initializer list + @sa @ref array(std::initializer_list) - create a JSON array + value from an initializer list + @sa @ref object(std::initializer_list) - create a JSON object + value from an initializer list + + @since version 1.0 */ basic_json(std::initializer_list init, bool type_deduction = true, @@ -1343,10 +1433,12 @@ class basic_json @liveexample{The following code shows an example for the @ref array function.,array} - @sa basic_json(std::initializer_list, bool, value_t) - create a - JSON value from an initializer list - @sa basic_json object(std::initializer_list) - create a JSON - object value from an initializer list + @sa @ref basic_json(std::initializer_list, bool, value_t) -- + create a JSON value from an initializer list + @sa @ref object(std::initializer_list) -- create a JSON object + value from an initializer list + + @since version 1.0 */ static basic_json array(std::initializer_list init = std::initializer_list()) @@ -1362,29 +1454,31 @@ class basic_json the initializer list is empty, the empty object `{}` is created. @note This function is only added for symmetry reasons. In contrast to the - related function @ref basic_json array(std::initializer_list), - there are no cases which can only be expressed by this function. That is, - any initializer list @a init can also be passed to the initializer list - constructor @ref basic_json(std::initializer_list, bool, - value_t). + related function @ref array(std::initializer_list), there are + no cases which can only be expressed by this function. That is, any + initializer list @a init can also be passed to the initializer list + constructor + @ref basic_json(std::initializer_list, bool, value_t). @param[in] init initializer list to create an object from (optional) @return JSON object value @throw std::domain_error if @a init is not a pair whose first elements are - strings; thrown by @ref basic_json(std::initializer_list, bool, - value_t) + strings; thrown by + @ref basic_json(std::initializer_list, bool, value_t) @complexity Linear in the size of @a init. @liveexample{The following code shows an example for the @ref object function.,object} - @sa basic_json(std::initializer_list, bool, value_t) - create a - JSON value from an initializer list - @sa basic_json array(std::initializer_list) - create a JSON - array value from an initializer list + @sa @ref basic_json(std::initializer_list, bool, value_t) -- + create a JSON value from an initializer list + @sa @ref array(std::initializer_list) -- create a JSON array + value from an initializer list + + @since version 1.0 */ static basic_json object(std::initializer_list init = std::initializer_list()) @@ -1407,6 +1501,8 @@ class basic_json @liveexample{The following code shows examples for the @ref basic_json(size_type\, const basic_json&) constructor.,basic_json__size_type_basic_json} + + @since version 1.0 */ basic_json(size_type count, const basic_json& value) : m_type(value_t::array) @@ -1443,6 +1539,8 @@ class basic_json @liveexample{The example below shows several ways to create JSON values by specifying a subrange with iterators.,basic_json__InputIt_InputIt} + + @since version 1.0 */ template >; @@ -402,9 +408,11 @@ class basic_json #### Storage - String values are stored as pointers in a `basic_json` type. That is, for - any access to string values, a pointer of type `string_t*` must be + String values are stored as pointers in a @ref basic_json type. That is, + for any access to string values, a pointer of type `string_t*` must be dereferenced. + + @since version 1.0 */ using string_t = StringType; @@ -428,7 +436,9 @@ class basic_json #### Storage - Boolean values are stored directly inside a `basic_json` type. + Boolean values are stored directly inside a @ref basic_json type. + + @since version 1.0 */ using boolean_t = BooleanType; @@ -492,7 +502,11 @@ class basic_json #### Storage - Integer number values are stored directly inside a `basic_json` type. + Integer number values are stored directly inside a @ref basic_json type. + + @sa @ref number_float_t -- type for number values (floating-point) + + @since version 1.0 */ using number_integer_t = NumberIntegerType; @@ -552,7 +566,12 @@ class basic_json #### Storage - Floating-point number values are stored directly inside a `basic_json` type. + Floating-point number values are stored directly inside a @ref basic_json + type. + + @sa @ref number_integer_t -- type for number values (integer) + + @since version 1.0 */ using number_float_t = NumberFloatType; @@ -567,8 +586,11 @@ class basic_json @brief the JSON type enumeration This enumeration collects the different JSON types. It is internally used - to distinguish the stored values, and the functions is_null, is_object, - is_array, is_string, is_boolean, is_number, and is_discarded rely on it. + to distinguish the stored values, and the functions @ref is_null(), @ref + is_object(), @ref is_array(), @ref is_string(), @ref is_boolean(), @ref + is_number(), and @ref is_discarded() rely on it. + + @since version 1.0 */ enum class value_t : uint8_t { @@ -602,7 +624,13 @@ class basic_json // JSON value storage // //////////////////////// - /// a JSON value + /*! + @brief a JSON value + + The actual storage for a JSON value of the @ref basic_json class. + + @since version 1.0 + */ union json_value { /// object (stored with pointer to save storage) @@ -704,6 +732,8 @@ class basic_json This enumeration lists the parser events that can trigger calling a callback function of type @ref parser_callback_t during parsing. + + @since version 1.0 */ enum class parse_event_t : uint8_t { @@ -767,9 +797,10 @@ class basic_json @sa @ref parse(std::istream&, parser_callback_t) or @ref parse(const string_t&, parser_callback_t) for examples + + @since version 1.0 */ - using parser_callback_t = std::function; + using parser_callback_t = std::function; ////////////////// @@ -800,6 +831,14 @@ class basic_json @liveexample{The following code shows the constructor for different @ref value_t values,basic_json__value_t} + + @sa @ref basic_json(std::nullptr_t) -- create a `null` value + @sa @ref basic_json(boolean_t value) -- create a boolean value + @sa @ref basic_json(const string_t&) -- create a string value + @sa @ref basic_json(const object_t&) -- create a object value + @sa @ref basic_json(const array_t&) -- create a array value + + @since version 1.0 */ basic_json(const value_t value) : m_type(value), m_value(value) @@ -820,7 +859,9 @@ class basic_json @liveexample{The following code shows the constructor for a `null` JSON value.,basic_json} - @sa basic_json(std::nullptr_t) + @sa @ref basic_json(std::nullptr_t) -- create a `null` value + + @since version 1.0 */ basic_json() noexcept = default; @@ -838,7 +879,10 @@ class basic_json @liveexample{The following code shows the constructor with null pointer parameter.,basic_json__nullptr_t} - @sa basic_json() + @sa @ref basic_json() -- default constructor (implicitly creating a `null` + value) + + @since version 1.0 */ basic_json(std::nullptr_t) noexcept : basic_json(value_t::null) @@ -858,7 +902,10 @@ class basic_json @liveexample{The following code shows the constructor with an @ref object_t parameter.,basic_json__object_t} - @sa basic_json(const CompatibleObjectType&) + @sa @ref basic_json(const CompatibleObjectType&) -- create an object value + from a compatible STL container + + @since version 1.0 */ basic_json(const object_t& value) : m_type(value_t::object), m_value(value) @@ -883,7 +930,9 @@ class basic_json @liveexample{The following code shows the constructor with several compatible object type parameters.,basic_json__CompatibleObjectType} - @sa basic_json(const object_t&) + @sa @ref basic_json(const object_t&) -- create an object value + + @since version 1.0 */ template ) - create a JSON - array value from an initializer list - @sa basic_json object(std::initializer_list) - create a JSON - object value from an initializer list + @sa @ref array(std::initializer_list) - create a JSON array + value from an initializer list + @sa @ref object(std::initializer_list) - create a JSON object + value from an initializer list + + @since version 1.0 */ basic_json(std::initializer_list init, bool type_deduction = true, @@ -1343,10 +1433,12 @@ class basic_json @liveexample{The following code shows an example for the @ref array function.,array} - @sa basic_json(std::initializer_list, bool, value_t) - create a - JSON value from an initializer list - @sa basic_json object(std::initializer_list) - create a JSON - object value from an initializer list + @sa @ref basic_json(std::initializer_list, bool, value_t) -- + create a JSON value from an initializer list + @sa @ref object(std::initializer_list) -- create a JSON object + value from an initializer list + + @since version 1.0 */ static basic_json array(std::initializer_list init = std::initializer_list()) @@ -1362,29 +1454,31 @@ class basic_json the initializer list is empty, the empty object `{}` is created. @note This function is only added for symmetry reasons. In contrast to the - related function @ref basic_json array(std::initializer_list), - there are no cases which can only be expressed by this function. That is, - any initializer list @a init can also be passed to the initializer list - constructor @ref basic_json(std::initializer_list, bool, - value_t). + related function @ref array(std::initializer_list), there are + no cases which can only be expressed by this function. That is, any + initializer list @a init can also be passed to the initializer list + constructor + @ref basic_json(std::initializer_list, bool, value_t). @param[in] init initializer list to create an object from (optional) @return JSON object value @throw std::domain_error if @a init is not a pair whose first elements are - strings; thrown by @ref basic_json(std::initializer_list, bool, - value_t) + strings; thrown by + @ref basic_json(std::initializer_list, bool, value_t) @complexity Linear in the size of @a init. @liveexample{The following code shows an example for the @ref object function.,object} - @sa basic_json(std::initializer_list, bool, value_t) - create a - JSON value from an initializer list - @sa basic_json array(std::initializer_list) - create a JSON - array value from an initializer list + @sa @ref basic_json(std::initializer_list, bool, value_t) -- + create a JSON value from an initializer list + @sa @ref array(std::initializer_list) -- create a JSON array + value from an initializer list + + @since version 1.0 */ static basic_json object(std::initializer_list init = std::initializer_list()) @@ -1407,6 +1501,8 @@ class basic_json @liveexample{The following code shows examples for the @ref basic_json(size_type\, const basic_json&) constructor.,basic_json__size_type_basic_json} + + @since version 1.0 */ basic_json(size_type count, const basic_json& value) : m_type(value_t::array) @@ -1443,6 +1539,8 @@ class basic_json @liveexample{The example below shows several ways to create JSON values by specifying a subrange with iterators.,basic_json__InputIt_InputIt} + + @since version 1.0 */ template Date: Wed, 16 Dec 2015 12:09:59 +0100 Subject: [PATCH 21/61] fix for #127 --- src/json.hpp.re2c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/json.hpp.re2c b/src/json.hpp.re2c index 9c0644865..41963fd48 100644 --- a/src/json.hpp.re2c +++ b/src/json.hpp.re2c @@ -2382,8 +2382,7 @@ class basic_json Explicit pointer access to the internally stored JSON value. No copies are made. - @warning Writing data to the pointee of the result yields an undefined - state. + @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, or @ref From fb972e845b4beddbe6f7023ee1a0ceaeaf478b16 Mon Sep 17 00:00:00 2001 From: Niels Date: Wed, 16 Dec 2015 12:10:12 +0100 Subject: [PATCH 22/61] show reference to source code in documentation --- doc/Doxyfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/Doxyfile b/doc/Doxyfile index b03aa7913..a7e5fbc67 100644 --- a/doc/Doxyfile +++ b/doc/Doxyfile @@ -121,7 +121,7 @@ USE_MDFILE_AS_MAINPAGE = #--------------------------------------------------------------------------- # Configuration options related to source browsing #--------------------------------------------------------------------------- -SOURCE_BROWSER = NO +SOURCE_BROWSER = YES INLINE_SOURCES = NO STRIP_CODE_COMMENTS = YES REFERENCED_BY_RELATION = NO From 07033f67a597ddf6608b865f8c4b8cb03eb16aa6 Mon Sep 17 00:00:00 2001 From: Niels Date: Thu, 17 Dec 2015 15:49:33 +0100 Subject: [PATCH 23/61] some cleanup and more documentation --- src/json.hpp | 589 +++++++++++++++++++++++++++------------------- src/json.hpp.re2c | 586 +++++++++++++++++++++++++++------------------ 2 files changed, 703 insertions(+), 472 deletions(-) diff --git a/src/json.hpp b/src/json.hpp index cb2a803b2..3fb7eb638 100644 --- a/src/json.hpp +++ b/src/json.hpp @@ -7,32 +7,32 @@ header-only JSON class. Class @ref nlohmann::basic_json is a good entry point for the documentation. @copyright The code is licensed under the [MIT - License](http://opensource.org/licenses/MIT): -
- Copyright © 2013-2015 Niels Lohmann. -
- Permission is hereby granted, free of charge, to any person - obtaining a copy of this software and associated documentation files - (the "Software"), to deal in the Software without restriction, - including without limitation the rights to use, copy, modify, merge, - publish, distribute, sublicense, and/or sell copies of the Software, - and to permit persons to whom the Software is furnished to do so, - subject to the following conditions: -
- The above copyright notice and this permission notice shall be - included in all copies or substantial portions of the Software. -
- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - SOFTWARE. + License](http://opensource.org/licenses/MIT): +
+ Copyright © 2013-2015 Niels Lohmann. +
+ Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: +
+ The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. +
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + SOFTWARE. @author [Niels Lohmann](http://nlohmann.me) @see https://github.com/nlohmann/json to download the source code + +@version 1.0 */ #ifndef NLOHMANN_JSON_HPP @@ -73,6 +73,7 @@ Class @ref nlohmann::basic_json is a good entry point for the documentation. /*! @brief namespace for Niels Lohmann @see https://github.com/nlohmann +@since version 1.0 */ namespace nlohmann { @@ -80,6 +81,7 @@ namespace nlohmann /*! @brief unnamed namespace with internal helper functions +@since version 1.0 */ namespace { @@ -168,6 +170,10 @@ default) @endinternal @see RFC 7159 + +@since version 1.0 + +@nosubgrouping */ template < template class ObjectType = std::map, @@ -261,10 +267,16 @@ class basic_json > where a name is a string and a value is a string, number, boolean, null, > object, or array. - To store objects in C++, a type is defined by the template parameters @a - ObjectType which chooses the container (e.g., `std::map` or - `std::unordered_map`), @a StringType which chooses the type of the keys or - names, and @a AllocatorType which chooses the allocator to use. + To store objects in C++, a type is defined by the template parameters + described below. + + @tparam ObjectType the container to store objects (e.g., `std::map` or + `std::unordered_map`) + @tparam StringType the type of the keys or names (e.g., `std::string`). The + comparison function `std::less` is used to order elements + inside the container. + @tparam AllocatorType the allocator to use for objects (e.g., + `std::allocator`) #### Default type @@ -333,9 +345,12 @@ class basic_json [RFC 7159](http://rfc7159.net/rfc7159) describes JSON arrays as follows: > An array is an ordered sequence of zero or more values. - To store objects in C++, a type is defined by the template parameters @a - ArrayType which chooses the container (e.g., `std::vector` or `std::list`) - and @a AllocatorType which chooses the allocator to use. + To store objects in C++, a type is defined by the template parameters + explained below. + + @tparam ArrayType container type to store arrays (e.g., `std::vector` or + `std::list`) + @tparam AllocatorType allocator to use for arrays (e.g., `std::allocator`) #### Default type @@ -376,11 +391,12 @@ class basic_json [RFC 7159](http://rfc7159.net/rfc7159) describes JSON strings as follows: > A string is a sequence of zero or more Unicode characters. - To store objects in C++, a type is defined by the template parameters @a - StringType which chooses the container (e.g., `std::string`) to use. + To store objects in C++, a type is defined by the template parameter + described below. Unicode values are split by the JSON class into byte-sized + characters during deserialization. - Unicode values are split by the JSON class into byte-sized characters - during deserialization. + @tparam StringType the container to store strings (e.g., `std::string`). + Note this container is used for keys/names in objects, see @ref object_t. #### Default type @@ -775,17 +791,17 @@ class basic_json parse_event_t::array_end | the parser read `]` and finished processing a JSON array | depth of the parent of the JSON array | the parsed JSON array parse_event_t::value | the parser finished reading a JSON value | depth of the value | the parsed JSON value - Discarding a value (i.e., returning `false`) has different effects depending on the - context in which function was called: + Discarding a value (i.e., returning `false`) has different effects + depending on the context in which function was called: - Discarded values in structured types are skipped. That is, the parser will behave as if the discarded value was never read. - In case a value outside a structured type is skipped, it is replaced with `null`. This case happens if the top-level element is skipped. - @param[in] depth the depth of the recursion during parsing + @param[in] depth the depth of the recursion during parsing - @param[in] event an event of type parse_event_t indicating the context in + @param[in] event an event of type parse_event_t indicating the context in the callback function has been called @param[in,out] parsed the current intermediate parse result; note that @@ -807,6 +823,9 @@ class basic_json // constructors // ////////////////// + /// @name constructors and destructors + /// @{ + /*! @brief create an empty value with a given type @@ -837,6 +856,10 @@ class basic_json @sa @ref basic_json(const string_t&) -- create a string value @sa @ref basic_json(const object_t&) -- create a object value @sa @ref basic_json(const array_t&) -- create a array value + @sa @ref basic_json(const number_float_t) -- create a number + (floating-point) value + @sa @ref basic_json(const number_integer_t) -- create a number (integer) + value @since version 1.0 */ @@ -871,7 +894,7 @@ class basic_json Create a `null` JSON value. This is the explicitly version of the `null` value constructor as it takes a null pointer as parameter. It allows to create `null` values by explicitly assigning a @c nullptr to a JSON value. - The passed null pointer itself is not read - it is only used to choose the + The passed null pointer itself is not read -- it is only used to choose the right constructor. @complexity Constant. @@ -1343,9 +1366,9 @@ class basic_json @liveexample{The example below shows how JSON values are created from initializer lists,basic_json__list_init_t} - @sa @ref array(std::initializer_list) - create a JSON array + @sa @ref array(std::initializer_list) -- create a JSON array value from an initializer list - @sa @ref object(std::initializer_list) - create a JSON object + @sa @ref object(std::initializer_list) -- create a JSON object value from an initializer list @since version 1.0 @@ -1357,8 +1380,8 @@ class basic_json // the initializer list could describe an object bool is_object = true; - // check if each element is an array with two elements whose first element - // is a string + // check if each element is an array with two elements whose first + // element is a string for (const auto& element : init) { if (not element.is_array() or element.size() != 2 @@ -1418,9 +1441,9 @@ class basic_json basic_json(std::initializer_list, bool, value_t)). These cases are: 1. creating an array whose elements are all pairs whose first element is a - string - in this case, the initializer list constructor would create an + string -- in this case, the initializer list constructor would create an object, taking the first elements as keys - 2. creating an empty array - passing the empty initializer list to the + 2. creating an empty array -- passing the empty initializer list to the initializer list constructor yields an empty object @param[in] init initializer list with JSON values to create an array from @@ -1739,6 +1762,8 @@ class basic_json creates a copy of value `a` which is then swapped with `b`. Finally\, the copy of `a` (which is the null value after the swap) is destroyed.,basic_json__copyassignment} + + @since version 1.0 */ reference& operator=(basic_json other) noexcept ( std::is_nothrow_move_constructible::value and @@ -1802,6 +1827,7 @@ class basic_json } } + /// @} public: /////////////////////// @@ -1831,6 +1857,8 @@ class basic_json parameters to the result of the serializaion.,dump} @see https://docs.python.org/2/library/json.html#json.dump + + @since version 1.0 */ string_t dump(const int indent = -1) const { @@ -1860,6 +1888,8 @@ class basic_json @liveexample{The following code exemplifies @ref type() for all JSON types.,type} + + @since version 1.0 */ value_t type() const noexcept { @@ -1879,6 +1909,8 @@ class basic_json @liveexample{The following code exemplifies @ref is_primitive for all JSON types.,is_primitive} + + @since version 1.0 */ bool is_primitive() const noexcept { @@ -1897,6 +1929,8 @@ class basic_json @liveexample{The following code exemplifies @ref is_structured for all JSON types.,is_structured} + + @since version 1.0 */ bool is_structured() const noexcept { @@ -1914,6 +1948,8 @@ class basic_json @liveexample{The following code exemplifies @ref is_null for all JSON types.,is_null} + + @since version 1.0 */ bool is_null() const noexcept { @@ -1931,6 +1967,8 @@ class basic_json @liveexample{The following code exemplifies @ref is_boolean for all JSON types.,is_boolean} + + @since version 1.0 */ bool is_boolean() const noexcept { @@ -1943,12 +1981,18 @@ class basic_json This function returns true iff the JSON value is a number. This includes both integer and floating-point values. - @return `true` if type is number, `false` otherwise. + @return `true` if type is number (regardless whether integer or + floating-type), `false` otherwise. @complexity Constant. @liveexample{The following code exemplifies @ref is_number for all JSON types.,is_number} + + @sa @ref is_number_integer() -- check if value is an integer number + @sa @ref is_number_float() -- check if value is a floating-point number + + @since version 1.0 */ bool is_number() const noexcept { @@ -1967,6 +2011,11 @@ class basic_json @liveexample{The following code exemplifies @ref is_number_integer for all JSON types.,is_number_integer} + + @sa @ref is_number() -- check if value is a number + @sa @ref is_number_float() -- check if value is a floating-point number + + @since version 1.0 */ bool is_number_integer() const noexcept { @@ -1985,6 +2034,11 @@ class basic_json @liveexample{The following code exemplifies @ref is_number_float for all JSON types.,is_number_float} + + @sa @ref is_number() -- check if value is number + @sa @ref is_number_integer() -- check if value is an integer number + + @since version 1.0 */ bool is_number_float() const noexcept { @@ -2002,6 +2056,8 @@ class basic_json @liveexample{The following code exemplifies @ref is_object for all JSON types.,is_object} + + @since version 1.0 */ bool is_object() const noexcept { @@ -2019,6 +2075,8 @@ class basic_json @liveexample{The following code exemplifies @ref is_array for all JSON types.,is_array} + + @since version 1.0 */ bool is_array() const noexcept { @@ -2036,6 +2094,8 @@ class basic_json @liveexample{The following code exemplifies @ref is_string for all JSON types.,is_string} + + @since version 1.0 */ bool is_string() const noexcept { @@ -2058,6 +2118,8 @@ class basic_json @liveexample{The following code exemplifies @ref is_discarded for all JSON types.,is_discarded} + + @since version 1.0 */ bool is_discarded() const noexcept { @@ -2076,6 +2138,8 @@ class basic_json @liveexample{The following code exemplifies the value_t operator for all JSON types.,operator__value_t} + + @since version 1.0 */ operator value_t() const noexcept { @@ -2097,27 +2161,17 @@ class basic_json , int>::type = 0> T get_impl(T*) const { - if (is_object()) - { - return T(m_value.object->begin(), m_value.object->end()); - } - else - { - throw std::domain_error("type must be object, but is " + type_name()); - } + return is_object() + ? T(m_value.object->begin(), m_value.object->end()) + : throw std::domain_error("type must be object, but is " + type_name()); } /// get an object (explicit) object_t get_impl(object_t*) const { - if (is_object()) - { - return *(m_value.object); - } - else - { - throw std::domain_error("type must be object, but is " + type_name()); - } + return is_object() + ? *(m_value.object) + : throw std::domain_error("type must be object, but is " + type_name()); } /// get an array (explicit) @@ -2180,27 +2234,17 @@ class basic_json , int>::type = 0> T get_impl(T*) const { - if (is_array()) - { - return T(m_value.array->begin(), m_value.array->end()); - } - else - { - throw std::domain_error("type must be array, but is " + type_name()); - } + return is_array() + ? T(m_value.array->begin(), m_value.array->end()) + : throw std::domain_error("type must be array, but is " + type_name()); } /// get an array (explicit) array_t get_impl(array_t*) const { - if (is_array()) - { - return *(m_value.array); - } - else - { - throw std::domain_error("type must be array, but is " + type_name()); - } + return is_array() + ? *(m_value.array) + : throw std::domain_error("type must be array, but is " + type_name()); } /// get a string (explicit) @@ -2210,14 +2254,9 @@ class basic_json , int>::type = 0> T get_impl(T*) const { - if (is_string()) - { - return *m_value.string; - } - else - { - throw std::domain_error("type must be string, but is " + type_name()); - } + return is_string() + ? *m_value.string + : throw std::domain_error("type must be string, but is " + type_name()); } /// get a number (explicit) @@ -2249,14 +2288,9 @@ class basic_json /// get a boolean (explicit) boolean_t get_impl(boolean_t*) const { - if (is_boolean()) - { - return m_value.boolean; - } - else - { - throw std::domain_error("type must be boolean, but is " + type_name()); - } + return is_boolean() + ? m_value.boolean + : throw std::domain_error("type must be boolean, but is " + type_name()); } /// get a pointer to the value (object) @@ -2366,6 +2400,8 @@ class basic_json @sa @ref operator ValueType() const for implicit conversion @sa @ref get() for pointer-member access + + @since version 1.0 */ template`\, (3) A JSON object can be converted to C++ assiciative containers such as `std::unordered_map`.,operator__ValueType} + + @since version 1.0 */ templateat(idx); - } - else - { - throw std::domain_error("cannot use at() with " + type_name()); - } + return is_array() + ? m_value.array->at(idx) + : throw std::domain_error("cannot use at() with " + type_name()); } /*! @@ -2567,18 +2605,15 @@ class basic_json @liveexample{The example below shows how array elements can be read using at.,at__size_type_const} + + @since version 1.0 */ const_reference at(size_type idx) const { // at only works for arrays - if (is_array()) - { - return m_value.array->at(idx); - } - else - { - throw std::domain_error("cannot use at() with " + type_name()); - } + return is_array() + ? m_value.array->at(idx) + : throw std::domain_error("cannot use at() with " + type_name()); } /*! @@ -2603,18 +2638,15 @@ class basic_json @sa @ref operator[](const typename object_t::key_type&) for unchecked access by reference @sa @ref value() for access by value with a default value + + @since version 1.0 */ reference at(const typename object_t::key_type& key) { // at only works for objects - if (is_object()) - { - return m_value.object->at(key); - } - else - { - throw std::domain_error("cannot use at() with " + type_name()); - } + return is_object() + ? m_value.object->at(key) + : throw std::domain_error("cannot use at() with " + type_name()); } /*! @@ -2639,18 +2671,15 @@ class basic_json @sa @ref operator[](const typename object_t::key_type&) for unchecked access by reference @sa @ref value() for access by value with a default value + + @since version 1.0 */ const_reference at(const typename object_t::key_type& key) const { // at only works for objects - if (is_object()) - { - return m_value.object->at(key); - } - else - { - throw std::domain_error("cannot use at() with " + type_name()); - } + return is_object() + ? m_value.object->at(key) + : throw std::domain_error("cannot use at() with " + type_name()); } /*! @@ -2674,6 +2703,8 @@ class basic_json @liveexample{The example below shows how array elements can be read and written using [] operator. Note the addition of `null` values.,operatorarray__size_type} + + @since version 1.0 */ reference operator[](size_type idx) { @@ -2715,18 +2746,15 @@ class basic_json @liveexample{The example below shows how array elements can be read using the [] operator.,operatorarray__size_type_const} + + @since version 1.0 */ const_reference operator[](size_type idx) const { // at only works for arrays - if (is_array()) - { - return m_value.array->operator[](idx); - } - else - { - throw std::domain_error("cannot use operator[] with " + type_name()); - } + return is_array() + ? m_value.array->operator[](idx) + : throw std::domain_error("cannot use operator[] with " + type_name()); } /*! @@ -2752,6 +2780,8 @@ class basic_json @sa @ref at(const typename object_t::key_type&) for access by reference with range checking @sa @ref value() for access by value with a default value + + @since version 1.0 */ reference operator[](const typename object_t::key_type& key) { @@ -2763,14 +2793,9 @@ class basic_json } // [] only works for objects - if (is_object()) - { - return m_value.object->operator[](key); - } - else - { - throw std::domain_error("cannot use operator[] with " + type_name()); - } + return is_object() + ? m_value.object->operator[](key) + : throw std::domain_error("cannot use operator[] with " + type_name()); } /*! @@ -2798,6 +2823,8 @@ class basic_json @sa @ref at(const typename object_t::key_type&) for access by reference with range checking @sa @ref value() for access by value with a default value + + @since version 1.0 */ template reference operator[](const T (&key)[n]) @@ -2810,14 +2837,9 @@ class basic_json } // at only works for objects - if (is_object()) - { - return m_value.object->operator[](key); - } - else - { - throw std::domain_error("cannot use operator[] with " + type_name()); - } + return is_object() + ? m_value.object->operator[](key) + : throw std::domain_error("cannot use operator[] with " + type_name()); } /*! @@ -2864,6 +2886,8 @@ class basic_json with range checking @sa @ref operator[](const typename object_t::key_type&) for unchecked access by reference + + @since version 1.0 */ template erase(key); - } - else - { - throw std::domain_error("cannot use erase() with " + type_name()); - } + return is_object() + ? m_value.object->erase(key) + : throw std::domain_error("cannot use erase() with " + type_name()); } /*! @@ -3197,6 +3245,14 @@ class basic_json @complexity Linear in distance between @a idx and the end of the container. @liveexample{The example shows the effect of erase.,erase__size_type} + + @sa @ref erase(InteratorType) -- removes the element at a given position + @sa @ref erase(InteratorType, InteratorType) -- removes the elements in the + given range + @sa @ref erase(const typename object_t::key_type&) -- remvoes the element + from an object at the given key + + @since version 1.0 */ void erase(const size_type idx) { @@ -3230,6 +3286,8 @@ class basic_json @complexity Logarithmic in the size of the JSON object. @liveexample{The example shows how find is used.,find__key_type} + + @since version 1.0 */ iterator find(typename object_t::key_type key) { @@ -3274,11 +3332,13 @@ class basic_json @complexity Logarithmic in the size of the JSON object. @liveexample{The example shows how count is used.,count} + + @since version 1.0 */ size_type count(typename object_t::key_type key) const { // return 0 for all nonobject types - return (is_object()) ? m_value.object->count(key) : 0; + return is_object() ? m_value.object->count(key) : 0; } /// @} @@ -3306,6 +3366,8 @@ class basic_json - The complexity is constant. @liveexample{The following code shows an example for @ref begin.,begin} + + @since version 1.0 */ iterator begin() { @@ -3338,6 +3400,8 @@ class basic_json - Has the semantics of `const_cast(*this).begin()`. @liveexample{The following code shows an example for @ref cbegin.,cbegin} + + @since version 1.0 */ const_iterator cbegin() const { @@ -3361,6 +3425,8 @@ class basic_json - The complexity is constant. @liveexample{The following code shows an example for @ref end.,end} + + @since version 1.0 */ iterator end() { @@ -3393,6 +3459,8 @@ class basic_json - Has the semantics of `const_cast(*this).end()`. @liveexample{The following code shows an example for @ref cend.,cend} + + @since version 1.0 */ const_iterator cend() const { @@ -3415,6 +3483,8 @@ class basic_json - Has the semantics of `reverse_iterator(end())`. @liveexample{The following code shows an example for @ref rbegin.,rbegin} + + @since version 1.0 */ reverse_iterator rbegin() { @@ -3444,6 +3514,8 @@ class basic_json - Has the semantics of `reverse_iterator(begin())`. @liveexample{The following code shows an example for @ref rend.,rend} + + @since version 1.0 */ reverse_iterator rend() { @@ -3473,6 +3545,8 @@ class basic_json - Has the semantics of `const_cast(*this).rbegin()`. @liveexample{The following code shows an example for @ref crbegin.,crbegin} + + @since version 1.0 */ const_reverse_iterator crbegin() const { @@ -3494,6 +3568,8 @@ class basic_json - Has the semantics of `const_cast(*this).rend()`. @liveexample{The following code shows an example for @ref crend.,crend} + + @since version 1.0 */ const_reverse_iterator crend() const { @@ -3527,8 +3603,8 @@ class basic_json array | result of function array_t::empty() @complexity Constant, as long as @ref array_t and @ref object_t satisfy the - Container concept; that is, their empty() functions have - constant complexity. + Container concept; that is, their empty() functions have constant + complexity. @requirement This function satisfies the Container requirements: - The complexity is constant. @@ -3536,6 +3612,8 @@ class basic_json @liveexample{The following code uses @ref empty to check if a @ref json object contains any elements.,empty} + + @since version 1.0 */ bool empty() const noexcept { @@ -3543,6 +3621,7 @@ class basic_json { case value_t::null: { + // null values are empty return true; } @@ -3590,6 +3669,8 @@ class basic_json @liveexample{The following code calls @ref size on the different value types.,size} + + @since version 1.0 */ size_type size() const noexcept { @@ -3597,6 +3678,7 @@ class basic_json { case value_t::null: { + // null values are empty return 0; } @@ -3647,6 +3729,8 @@ class basic_json @liveexample{The following code calls @ref max_size on the different value types. Note the output is implementation specific.,max_size} + + @since version 1.0 */ size_type max_size() const noexcept { @@ -3702,6 +3786,8 @@ class basic_json @liveexample{The example below shows the effect of @ref clear to different JSON types.,clear} + + @since version 1.0 */ void clear() noexcept { @@ -3766,6 +3852,8 @@ class basic_json @liveexample{The example shows how `push_back` and `+=` can be used to add elements to a JSON array. Note how the `null` value was silently converted to a JSON array.,push_back} + + @since version 1.0 */ void push_back(basic_json&& value) { @@ -3848,6 +3936,8 @@ class basic_json @liveexample{The example shows how `push_back` and `+=` can be used to add elements to a JSON object. Note how the `null` value was silently converted to a JSON object.,push_back__object_t__value} + + @since version 1.0 */ void push_back(const typename object_t::value_type& value) { @@ -3895,6 +3985,8 @@ class basic_json container. @liveexample{The example shows how insert is used.,insert} + + @since version 1.0 */ iterator insert(const_iterator pos, const basic_json& value) { @@ -3946,6 +4038,8 @@ class basic_json and end of the container. @liveexample{The example shows how insert is used.,insert__count} + + @since version 1.0 */ iterator insert(const_iterator pos, size_type count, const basic_json& value) { @@ -3992,6 +4086,8 @@ class basic_json distance between @a pos and end of the container. @liveexample{The example shows how insert is used.,insert__range} + + @since version 1.0 */ iterator insert(const_iterator pos, const_iterator first, const_iterator last) { @@ -4009,7 +4105,7 @@ class basic_json if (first.m_object != last.m_object) { - throw std::domain_error("iterators does not fit"); + throw std::domain_error("iterators do not fit"); } if (first.m_object == this or last.m_object == this) @@ -4019,8 +4115,10 @@ 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); + 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; } @@ -4042,6 +4140,8 @@ class basic_json pos and end of the container. @liveexample{The example shows how insert is used.,insert__ilist} + + @since version 1.0 */ iterator insert(const_iterator pos, std::initializer_list ilist) { @@ -4077,6 +4177,8 @@ class basic_json @liveexample{The example below shows how JSON arrays can be swapped.,swap__reference} + + @since version 1.0 */ void swap(reference other) noexcept ( std::is_nothrow_move_constructible::value and @@ -4105,6 +4207,8 @@ class basic_json @liveexample{The example below shows how JSON values can be swapped.,swap__array_t} + + @since version 1.0 */ void swap(array_t& other) { @@ -4135,6 +4239,8 @@ class basic_json @liveexample{The example below shows how JSON values can be swapped.,swap__object_t} + + @since version 1.0 */ void swap(object_t& other) { @@ -4165,6 +4271,8 @@ class basic_json @liveexample{The example below shows how JSON values can be swapped.,swap__string_t} + + @since version 1.0 */ void swap(string_t& other) { @@ -4196,6 +4304,8 @@ class basic_json Returns an ordering that is similar to Python: - order: null < boolean < number < object < array < string - furthermore, each type is not smaller than itself + + @since version 1.0 */ friend bool operator<(const value_t lhs, const value_t rhs) { @@ -4240,6 +4350,8 @@ class basic_json @liveexample{The example demonstrates comparing several JSON types.,operator__equal} + + @since version 1.0 */ friend bool operator==(const_reference lhs, const_reference rhs) noexcept { @@ -4296,6 +4408,8 @@ class basic_json @liveexample{The example compares several JSON types to the null pointer. ,operator__equal__nullptr_t} + + @since version 1.0 */ friend bool operator==(const_reference v, std::nullptr_t) noexcept { @@ -4324,6 +4438,8 @@ class basic_json @liveexample{The example demonstrates comparing several JSON types.,operator__notequal} + + @since version 1.0 */ friend bool operator!=(const_reference lhs, const_reference rhs) noexcept { @@ -4345,6 +4461,8 @@ class basic_json @liveexample{The example compares several JSON types to the null pointer. ,operator__notequal__nullptr_t} + + @since version 1.0 */ friend bool operator!=(const_reference v, std::nullptr_t) noexcept { @@ -4381,6 +4499,8 @@ class basic_json @liveexample{The example demonstrates comparing several JSON types.,operator__less} + + @since version 1.0 */ friend bool operator<(const_reference lhs, const_reference rhs) noexcept { @@ -4440,6 +4560,8 @@ class basic_json @liveexample{The example demonstrates comparing several JSON types.,operator__greater} + + @since version 1.0 */ friend bool operator<=(const_reference lhs, const_reference rhs) noexcept { @@ -4460,6 +4582,8 @@ class basic_json @liveexample{The example demonstrates comparing several JSON types.,operator__lessequal} + + @since version 1.0 */ friend bool operator>(const_reference lhs, const_reference rhs) noexcept { @@ -4480,6 +4604,8 @@ class basic_json @liveexample{The example demonstrates comparing several JSON types.,operator__greaterequal} + + @since version 1.0 */ friend bool operator>=(const_reference lhs, const_reference rhs) noexcept { @@ -4515,6 +4641,8 @@ class basic_json @liveexample{The example below shows the serialization with different parameters to `width` to adjust the indentation level.,operator_serialize} + + @since version 1.0 */ friend std::ostream& operator<<(std::ostream& o, const basic_json& j) { @@ -4568,8 +4696,10 @@ class basic_json @liveexample{The example below demonstrates the parse function with and without callback function.,parse__string__parser_callback_t} - @sa parse(std::istream&, parser_callback_t) for a version that reads from - an input stream + @sa @ref parse(std::istream&, parser_callback_t) for a version that reads + from an input stream + + @since version 1.0 */ static basic_json parse(const string_t& s, parser_callback_t cb = nullptr) { @@ -4595,14 +4725,19 @@ class basic_json @liveexample{The example below demonstrates the parse function with and without callback function.,parse__istream__parser_callback_t} - @sa parse(const string_t&, parser_callback_t) for a version that reads + @sa @ref parse(const string_t&, parser_callback_t) for a version that reads from a string + + @since version 1.0 */ static basic_json parse(std::istream& i, parser_callback_t cb = nullptr) { return parser(i, cb).parse(); } + /*! + @copydoc parse(std::istream&, parser_callback_t) + */ static basic_json parse(std::istream&& i, parser_callback_t cb = nullptr) { return parser(i, cb).parse(); @@ -4628,6 +4763,8 @@ class basic_json @sa parse(std::istream&, parser_callback_t) for a variant with a parser callback function to filter values while parsing + + @since version 1.0 */ friend std::istream& operator<<(basic_json& j, std::istream& i) { @@ -4659,39 +4796,19 @@ class basic_json switch (m_type) { case value_t::null: - { return "null"; - } - case value_t::object: - { return "object"; - } - case value_t::array: - { return "array"; - } - case value_t::string: - { return "string"; - } - case value_t::boolean: - { return "boolean"; - } - case value_t::discarded: - { return "discarded"; - } - default: - { return "number"; - } } } @@ -4874,7 +4991,9 @@ class basic_json @param[in] indent_step the indent level @param[in] current_indent the current indent level (only used internally) */ - void dump(std::ostream& o, const bool pretty_print, const unsigned int indent_step, + void dump(std::ostream& o, + const bool pretty_print, + const unsigned int indent_step, const unsigned int current_indent = 0) const { // variable to hold indentation for recursive calls @@ -5107,6 +5226,8 @@ class basic_json - [RandomAccessIterator](http://en.cppreference.com/w/cpp/concept/RandomAccessIterator): The iterator that can be moved to point (forward and backward) to any element in constant time. + + @since version 1.0 */ class const_iterator : public std::iterator { @@ -5277,14 +5398,9 @@ class basic_json default: { - if (m_it.primitive_iterator.is_begin()) - { - return *m_object; - } - else - { - throw std::out_of_range("cannot get value"); - } + return m_it.primitive_iterator.is_begin() + ? *m_object + : throw std::out_of_range("cannot get value"); } } } @@ -5306,14 +5422,9 @@ class basic_json default: { - if (m_it.primitive_iterator.is_begin()) - { - return m_object; - } - else - { - throw std::out_of_range("cannot get value"); - } + return m_it.primitive_iterator.is_begin() + ? m_object + : throw std::out_of_range("cannot get value"); } } } @@ -5323,7 +5434,6 @@ class basic_json { auto result = *this; ++(*this); - return result; } @@ -5359,7 +5469,6 @@ class basic_json { auto result = *this; --(*this); - return result; } @@ -5562,14 +5671,9 @@ class basic_json default: { - if (m_it.primitive_iterator == -n) - { - return *m_object; - } - else - { - throw std::out_of_range("cannot get value"); - } + return (m_it.primitive_iterator == -n) + ? *m_object + : throw std::out_of_range("cannot get value"); } } } @@ -5577,14 +5681,9 @@ class basic_json /// return the key of an object iterator typename object_t::key_type key() const { - if (m_object->is_object()) - { - return m_it.object_iterator->first; - } - else - { - throw std::domain_error("cannot use key() for non-object iterators"); - } + return m_object->is_object() + ? m_it.object_iterator->first + : throw std::domain_error("cannot use key() for non-object iterators"); } /// return the value of an iterator @@ -5609,6 +5708,8 @@ class basic_json element in constant time. - [OutputIterator](http://en.cppreference.com/w/cpp/concept/OutputIterator): It is possible to write to the pointed-to element. + + @since version 1.0 */ class iterator : public const_iterator { @@ -5745,6 +5846,8 @@ class basic_json - [OutputIterator](http://en.cppreference.com/w/cpp/concept/OutputIterator): It is possible to write to the pointed-to element (only if @a Base is @ref iterator). + + @since version 1.0 */ template class json_reverse_iterator : public std::reverse_iterator @@ -5893,19 +5996,19 @@ class basic_json { switch (anchor.m_object->type()) { - /// use integer array index as key + // use integer array index as key case value_t::array: { return std::to_string(array_index); } - /// use key from the object + // use key from the object case value_t::object: { return anchor.key(); } - /// use an empty key for all primitive types + // use an empty key for all primitive types default: { return ""; @@ -5961,8 +6064,8 @@ class basic_json literal_true, ///< the "true" literal literal_false, ///< the "false" literal literal_null, ///< the "null" literal - value_string, ///< a string - use get_string() for actual value - value_number, ///< a number - use get_number() for actual value + value_string, ///< a string -- use get_string() for actual value + value_number, ///< a number -- use get_number() for actual value begin_array, ///< the character for array begin "[" begin_object, ///< the character for object begin "{" end_array, ///< the character for array end "]" @@ -7119,6 +7222,8 @@ basic_json_parser_64: /*! @brief syntax analysis + + This class implements a recursive decent parser. */ class parser { @@ -7341,13 +7446,13 @@ basic_json_parser_64: const auto int_val = static_cast(float_val); if (approx(float_val, static_cast(int_val))) { - // we basic_json not lose precision -> return int + // we would not lose precision -> return int result.m_type = value_t::number_integer; result.m_value = int_val; } else { - // we would lose precision -> returnfloat + // we would lose precision -> return float result.m_type = value_t::number_float; result.m_value = static_cast(float_val); } @@ -7421,6 +7526,8 @@ basic_json_parser_64: This type is the default specialization of the @ref basic_json class which uses the standard template types. + +@since version 1.0 */ using json = basic_json<>; } @@ -7435,6 +7542,8 @@ namespace std { /*! @brief exchanges the values of two JSON objects + +@since version 1.0 */ template <> inline void swap(nlohmann::json& j1, @@ -7450,7 +7559,11 @@ inline void swap(nlohmann::json& j1, template <> struct hash { - /// return a hash value for a JSON object + /*! + @brief return a hash value for a JSON object + + @since version 1.0 + */ std::size_t operator()(const nlohmann::json& j) const { // a naive hashing via the string representation @@ -7469,6 +7582,8 @@ no parse error occurred. @param[in] s a string representation of a JSON object @return a JSON object + +@since version 1.0 */ inline nlohmann::json operator "" _json(const char* s, std::size_t) { diff --git a/src/json.hpp.re2c b/src/json.hpp.re2c index 41963fd48..0efd7490f 100644 --- a/src/json.hpp.re2c +++ b/src/json.hpp.re2c @@ -7,32 +7,32 @@ header-only JSON class. Class @ref nlohmann::basic_json is a good entry point for the documentation. @copyright The code is licensed under the [MIT - License](http://opensource.org/licenses/MIT): -
- Copyright © 2013-2015 Niels Lohmann. -
- Permission is hereby granted, free of charge, to any person - obtaining a copy of this software and associated documentation files - (the "Software"), to deal in the Software without restriction, - including without limitation the rights to use, copy, modify, merge, - publish, distribute, sublicense, and/or sell copies of the Software, - and to permit persons to whom the Software is furnished to do so, - subject to the following conditions: -
- The above copyright notice and this permission notice shall be - included in all copies or substantial portions of the Software. -
- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - SOFTWARE. + License](http://opensource.org/licenses/MIT): +
+ Copyright © 2013-2015 Niels Lohmann. +
+ Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: +
+ The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. +
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + SOFTWARE. @author [Niels Lohmann](http://nlohmann.me) @see https://github.com/nlohmann/json to download the source code + +@version 1.0 */ #ifndef NLOHMANN_JSON_HPP @@ -73,6 +73,7 @@ Class @ref nlohmann::basic_json is a good entry point for the documentation. /*! @brief namespace for Niels Lohmann @see https://github.com/nlohmann +@since version 1.0 */ namespace nlohmann { @@ -80,6 +81,7 @@ namespace nlohmann /*! @brief unnamed namespace with internal helper functions +@since version 1.0 */ namespace { @@ -168,6 +170,10 @@ default) @endinternal @see RFC 7159 + +@since version 1.0 + +@nosubgrouping */ template < template class ObjectType = std::map, @@ -261,10 +267,16 @@ class basic_json > where a name is a string and a value is a string, number, boolean, null, > object, or array. - To store objects in C++, a type is defined by the template parameters @a - ObjectType which chooses the container (e.g., `std::map` or - `std::unordered_map`), @a StringType which chooses the type of the keys or - names, and @a AllocatorType which chooses the allocator to use. + To store objects in C++, a type is defined by the template parameters + described below. + + @tparam ObjectType the container to store objects (e.g., `std::map` or + `std::unordered_map`) + @tparam StringType the type of the keys or names (e.g., `std::string`). The + comparison function `std::less` is used to order elements + inside the container. + @tparam AllocatorType the allocator to use for objects (e.g., + `std::allocator`) #### Default type @@ -333,9 +345,12 @@ class basic_json [RFC 7159](http://rfc7159.net/rfc7159) describes JSON arrays as follows: > An array is an ordered sequence of zero or more values. - To store objects in C++, a type is defined by the template parameters @a - ArrayType which chooses the container (e.g., `std::vector` or `std::list`) - and @a AllocatorType which chooses the allocator to use. + To store objects in C++, a type is defined by the template parameters + explained below. + + @tparam ArrayType container type to store arrays (e.g., `std::vector` or + `std::list`) + @tparam AllocatorType allocator to use for arrays (e.g., `std::allocator`) #### Default type @@ -376,11 +391,12 @@ class basic_json [RFC 7159](http://rfc7159.net/rfc7159) describes JSON strings as follows: > A string is a sequence of zero or more Unicode characters. - To store objects in C++, a type is defined by the template parameters @a - StringType which chooses the container (e.g., `std::string`) to use. + To store objects in C++, a type is defined by the template parameter + described below. Unicode values are split by the JSON class into byte-sized + characters during deserialization. - Unicode values are split by the JSON class into byte-sized characters - during deserialization. + @tparam StringType the container to store strings (e.g., `std::string`). + Note this container is used for keys/names in objects, see @ref object_t. #### Default type @@ -775,17 +791,17 @@ class basic_json parse_event_t::array_end | the parser read `]` and finished processing a JSON array | depth of the parent of the JSON array | the parsed JSON array parse_event_t::value | the parser finished reading a JSON value | depth of the value | the parsed JSON value - Discarding a value (i.e., returning `false`) has different effects depending on the - context in which function was called: + Discarding a value (i.e., returning `false`) has different effects + depending on the context in which function was called: - Discarded values in structured types are skipped. That is, the parser will behave as if the discarded value was never read. - In case a value outside a structured type is skipped, it is replaced with `null`. This case happens if the top-level element is skipped. - @param[in] depth the depth of the recursion during parsing + @param[in] depth the depth of the recursion during parsing - @param[in] event an event of type parse_event_t indicating the context in + @param[in] event an event of type parse_event_t indicating the context in the callback function has been called @param[in,out] parsed the current intermediate parse result; note that @@ -807,6 +823,9 @@ class basic_json // constructors // ////////////////// + /// @name constructors and destructors + /// @{ + /*! @brief create an empty value with a given type @@ -837,6 +856,10 @@ class basic_json @sa @ref basic_json(const string_t&) -- create a string value @sa @ref basic_json(const object_t&) -- create a object value @sa @ref basic_json(const array_t&) -- create a array value + @sa @ref basic_json(const number_float_t) -- create a number + (floating-point) value + @sa @ref basic_json(const number_integer_t) -- create a number (integer) + value @since version 1.0 */ @@ -871,7 +894,7 @@ class basic_json Create a `null` JSON value. This is the explicitly version of the `null` value constructor as it takes a null pointer as parameter. It allows to create `null` values by explicitly assigning a @c nullptr to a JSON value. - The passed null pointer itself is not read - it is only used to choose the + The passed null pointer itself is not read -- it is only used to choose the right constructor. @complexity Constant. @@ -1343,9 +1366,9 @@ class basic_json @liveexample{The example below shows how JSON values are created from initializer lists,basic_json__list_init_t} - @sa @ref array(std::initializer_list) - create a JSON array + @sa @ref array(std::initializer_list) -- create a JSON array value from an initializer list - @sa @ref object(std::initializer_list) - create a JSON object + @sa @ref object(std::initializer_list) -- create a JSON object value from an initializer list @since version 1.0 @@ -1357,8 +1380,8 @@ class basic_json // the initializer list could describe an object bool is_object = true; - // check if each element is an array with two elements whose first element - // is a string + // check if each element is an array with two elements whose first + // element is a string for (const auto& element : init) { if (not element.is_array() or element.size() != 2 @@ -1418,9 +1441,9 @@ class basic_json basic_json(std::initializer_list, bool, value_t)). These cases are: 1. creating an array whose elements are all pairs whose first element is a - string - in this case, the initializer list constructor would create an + string -- in this case, the initializer list constructor would create an object, taking the first elements as keys - 2. creating an empty array - passing the empty initializer list to the + 2. creating an empty array -- passing the empty initializer list to the initializer list constructor yields an empty object @param[in] init initializer list with JSON values to create an array from @@ -1739,6 +1762,8 @@ class basic_json creates a copy of value `a` which is then swapped with `b`. Finally\, the copy of `a` (which is the null value after the swap) is destroyed.,basic_json__copyassignment} + + @since version 1.0 */ reference& operator=(basic_json other) noexcept ( std::is_nothrow_move_constructible::value and @@ -1802,6 +1827,7 @@ class basic_json } } + /// @} public: /////////////////////// @@ -1831,6 +1857,8 @@ class basic_json parameters to the result of the serializaion.,dump} @see https://docs.python.org/2/library/json.html#json.dump + + @since version 1.0 */ string_t dump(const int indent = -1) const { @@ -1860,6 +1888,8 @@ class basic_json @liveexample{The following code exemplifies @ref type() for all JSON types.,type} + + @since version 1.0 */ value_t type() const noexcept { @@ -1879,6 +1909,8 @@ class basic_json @liveexample{The following code exemplifies @ref is_primitive for all JSON types.,is_primitive} + + @since version 1.0 */ bool is_primitive() const noexcept { @@ -1897,6 +1929,8 @@ class basic_json @liveexample{The following code exemplifies @ref is_structured for all JSON types.,is_structured} + + @since version 1.0 */ bool is_structured() const noexcept { @@ -1914,6 +1948,8 @@ class basic_json @liveexample{The following code exemplifies @ref is_null for all JSON types.,is_null} + + @since version 1.0 */ bool is_null() const noexcept { @@ -1931,6 +1967,8 @@ class basic_json @liveexample{The following code exemplifies @ref is_boolean for all JSON types.,is_boolean} + + @since version 1.0 */ bool is_boolean() const noexcept { @@ -1943,12 +1981,18 @@ class basic_json This function returns true iff the JSON value is a number. This includes both integer and floating-point values. - @return `true` if type is number, `false` otherwise. + @return `true` if type is number (regardless whether integer or + floating-type), `false` otherwise. @complexity Constant. @liveexample{The following code exemplifies @ref is_number for all JSON types.,is_number} + + @sa @ref is_number_integer() -- check if value is an integer number + @sa @ref is_number_float() -- check if value is a floating-point number + + @since version 1.0 */ bool is_number() const noexcept { @@ -1967,6 +2011,11 @@ class basic_json @liveexample{The following code exemplifies @ref is_number_integer for all JSON types.,is_number_integer} + + @sa @ref is_number() -- check if value is a number + @sa @ref is_number_float() -- check if value is a floating-point number + + @since version 1.0 */ bool is_number_integer() const noexcept { @@ -1985,6 +2034,11 @@ class basic_json @liveexample{The following code exemplifies @ref is_number_float for all JSON types.,is_number_float} + + @sa @ref is_number() -- check if value is number + @sa @ref is_number_integer() -- check if value is an integer number + + @since version 1.0 */ bool is_number_float() const noexcept { @@ -2002,6 +2056,8 @@ class basic_json @liveexample{The following code exemplifies @ref is_object for all JSON types.,is_object} + + @since version 1.0 */ bool is_object() const noexcept { @@ -2019,6 +2075,8 @@ class basic_json @liveexample{The following code exemplifies @ref is_array for all JSON types.,is_array} + + @since version 1.0 */ bool is_array() const noexcept { @@ -2036,6 +2094,8 @@ class basic_json @liveexample{The following code exemplifies @ref is_string for all JSON types.,is_string} + + @since version 1.0 */ bool is_string() const noexcept { @@ -2058,6 +2118,8 @@ class basic_json @liveexample{The following code exemplifies @ref is_discarded for all JSON types.,is_discarded} + + @since version 1.0 */ bool is_discarded() const noexcept { @@ -2076,6 +2138,8 @@ class basic_json @liveexample{The following code exemplifies the value_t operator for all JSON types.,operator__value_t} + + @since version 1.0 */ operator value_t() const noexcept { @@ -2097,27 +2161,17 @@ class basic_json , int>::type = 0> T get_impl(T*) const { - if (is_object()) - { - return T(m_value.object->begin(), m_value.object->end()); - } - else - { - throw std::domain_error("type must be object, but is " + type_name()); - } + return is_object() + ? T(m_value.object->begin(), m_value.object->end()) + : throw std::domain_error("type must be object, but is " + type_name()); } /// get an object (explicit) object_t get_impl(object_t*) const { - if (is_object()) - { - return *(m_value.object); - } - else - { - throw std::domain_error("type must be object, but is " + type_name()); - } + return is_object() + ? *(m_value.object) + : throw std::domain_error("type must be object, but is " + type_name()); } /// get an array (explicit) @@ -2180,27 +2234,17 @@ class basic_json , int>::type = 0> T get_impl(T*) const { - if (is_array()) - { - return T(m_value.array->begin(), m_value.array->end()); - } - else - { - throw std::domain_error("type must be array, but is " + type_name()); - } + return is_array() + ? T(m_value.array->begin(), m_value.array->end()) + : throw std::domain_error("type must be array, but is " + type_name()); } /// get an array (explicit) array_t get_impl(array_t*) const { - if (is_array()) - { - return *(m_value.array); - } - else - { - throw std::domain_error("type must be array, but is " + type_name()); - } + return is_array() + ? *(m_value.array) + : throw std::domain_error("type must be array, but is " + type_name()); } /// get a string (explicit) @@ -2210,14 +2254,9 @@ class basic_json , int>::type = 0> T get_impl(T*) const { - if (is_string()) - { - return *m_value.string; - } - else - { - throw std::domain_error("type must be string, but is " + type_name()); - } + return is_string() + ? *m_value.string + : throw std::domain_error("type must be string, but is " + type_name()); } /// get a number (explicit) @@ -2249,14 +2288,9 @@ class basic_json /// get a boolean (explicit) boolean_t get_impl(boolean_t*) const { - if (is_boolean()) - { - return m_value.boolean; - } - else - { - throw std::domain_error("type must be boolean, but is " + type_name()); - } + return is_boolean() + ? m_value.boolean + : throw std::domain_error("type must be boolean, but is " + type_name()); } /// get a pointer to the value (object) @@ -2366,6 +2400,8 @@ class basic_json @sa @ref operator ValueType() const for implicit conversion @sa @ref get() for pointer-member access + + @since version 1.0 */ template`\, (3) A JSON object can be converted to C++ assiciative containers such as `std::unordered_map`.,operator__ValueType} + + @since version 1.0 */ templateat(idx); - } - else - { - throw std::domain_error("cannot use at() with " + type_name()); - } + return is_array() + ? m_value.array->at(idx) + : throw std::domain_error("cannot use at() with " + type_name()); } /*! @@ -2566,18 +2605,15 @@ class basic_json @liveexample{The example below shows how array elements can be read using at.,at__size_type_const} + + @since version 1.0 */ const_reference at(size_type idx) const { // at only works for arrays - if (is_array()) - { - return m_value.array->at(idx); - } - else - { - throw std::domain_error("cannot use at() with " + type_name()); - } + return is_array() + ? m_value.array->at(idx) + : throw std::domain_error("cannot use at() with " + type_name()); } /*! @@ -2602,18 +2638,15 @@ class basic_json @sa @ref operator[](const typename object_t::key_type&) for unchecked access by reference @sa @ref value() for access by value with a default value + + @since version 1.0 */ reference at(const typename object_t::key_type& key) { // at only works for objects - if (is_object()) - { - return m_value.object->at(key); - } - else - { - throw std::domain_error("cannot use at() with " + type_name()); - } + return is_object() + ? m_value.object->at(key) + : throw std::domain_error("cannot use at() with " + type_name()); } /*! @@ -2638,18 +2671,15 @@ class basic_json @sa @ref operator[](const typename object_t::key_type&) for unchecked access by reference @sa @ref value() for access by value with a default value + + @since version 1.0 */ const_reference at(const typename object_t::key_type& key) const { // at only works for objects - if (is_object()) - { - return m_value.object->at(key); - } - else - { - throw std::domain_error("cannot use at() with " + type_name()); - } + return is_object() + ? m_value.object->at(key) + : throw std::domain_error("cannot use at() with " + type_name()); } /*! @@ -2673,6 +2703,8 @@ class basic_json @liveexample{The example below shows how array elements can be read and written using [] operator. Note the addition of `null` values.,operatorarray__size_type} + + @since version 1.0 */ reference operator[](size_type idx) { @@ -2714,18 +2746,15 @@ class basic_json @liveexample{The example below shows how array elements can be read using the [] operator.,operatorarray__size_type_const} + + @since version 1.0 */ const_reference operator[](size_type idx) const { // at only works for arrays - if (is_array()) - { - return m_value.array->operator[](idx); - } - else - { - throw std::domain_error("cannot use operator[] with " + type_name()); - } + return is_array() + ? m_value.array->operator[](idx) + : throw std::domain_error("cannot use operator[] with " + type_name()); } /*! @@ -2751,6 +2780,8 @@ class basic_json @sa @ref at(const typename object_t::key_type&) for access by reference with range checking @sa @ref value() for access by value with a default value + + @since version 1.0 */ reference operator[](const typename object_t::key_type& key) { @@ -2762,14 +2793,9 @@ class basic_json } // [] only works for objects - if (is_object()) - { - return m_value.object->operator[](key); - } - else - { - throw std::domain_error("cannot use operator[] with " + type_name()); - } + return is_object() + ? m_value.object->operator[](key) + : throw std::domain_error("cannot use operator[] with " + type_name()); } /*! @@ -2797,6 +2823,8 @@ class basic_json @sa @ref at(const typename object_t::key_type&) for access by reference with range checking @sa @ref value() for access by value with a default value + + @since version 1.0 */ template reference operator[](const T (&key)[n]) @@ -2809,14 +2837,9 @@ class basic_json } // at only works for objects - if (is_object()) - { - return m_value.object->operator[](key); - } - else - { - throw std::domain_error("cannot use operator[] with " + type_name()); - } + return is_object() + ? m_value.object->operator[](key) + : throw std::domain_error("cannot use operator[] with " + type_name()); } /*! @@ -2863,6 +2886,8 @@ class basic_json with range checking @sa @ref operator[](const typename object_t::key_type&) for unchecked access by reference + + @since version 1.0 */ template erase(key); - } - else - { - throw std::domain_error("cannot use erase() with " + type_name()); - } + return is_object() + ? m_value.object->erase(key) + : throw std::domain_error("cannot use erase() with " + type_name()); } /*! @@ -3196,6 +3245,14 @@ class basic_json @complexity Linear in distance between @a idx and the end of the container. @liveexample{The example shows the effect of erase.,erase__size_type} + + @sa @ref erase(InteratorType) -- removes the element at a given position + @sa @ref erase(InteratorType, InteratorType) -- removes the elements in the + given range + @sa @ref erase(const typename object_t::key_type&) -- remvoes the element + from an object at the given key + + @since version 1.0 */ void erase(const size_type idx) { @@ -3229,6 +3286,8 @@ class basic_json @complexity Logarithmic in the size of the JSON object. @liveexample{The example shows how find is used.,find__key_type} + + @since version 1.0 */ iterator find(typename object_t::key_type key) { @@ -3273,11 +3332,13 @@ class basic_json @complexity Logarithmic in the size of the JSON object. @liveexample{The example shows how count is used.,count} + + @since version 1.0 */ size_type count(typename object_t::key_type key) const { // return 0 for all nonobject types - return (is_object()) ? m_value.object->count(key) : 0; + return is_object() ? m_value.object->count(key) : 0; } /// @} @@ -3305,6 +3366,8 @@ class basic_json - The complexity is constant. @liveexample{The following code shows an example for @ref begin.,begin} + + @since version 1.0 */ iterator begin() { @@ -3337,6 +3400,8 @@ class basic_json - Has the semantics of `const_cast(*this).begin()`. @liveexample{The following code shows an example for @ref cbegin.,cbegin} + + @since version 1.0 */ const_iterator cbegin() const { @@ -3360,6 +3425,8 @@ class basic_json - The complexity is constant. @liveexample{The following code shows an example for @ref end.,end} + + @since version 1.0 */ iterator end() { @@ -3392,6 +3459,8 @@ class basic_json - Has the semantics of `const_cast(*this).end()`. @liveexample{The following code shows an example for @ref cend.,cend} + + @since version 1.0 */ const_iterator cend() const { @@ -3414,6 +3483,8 @@ class basic_json - Has the semantics of `reverse_iterator(end())`. @liveexample{The following code shows an example for @ref rbegin.,rbegin} + + @since version 1.0 */ reverse_iterator rbegin() { @@ -3443,6 +3514,8 @@ class basic_json - Has the semantics of `reverse_iterator(begin())`. @liveexample{The following code shows an example for @ref rend.,rend} + + @since version 1.0 */ reverse_iterator rend() { @@ -3472,6 +3545,8 @@ class basic_json - Has the semantics of `const_cast(*this).rbegin()`. @liveexample{The following code shows an example for @ref crbegin.,crbegin} + + @since version 1.0 */ const_reverse_iterator crbegin() const { @@ -3493,6 +3568,8 @@ class basic_json - Has the semantics of `const_cast(*this).rend()`. @liveexample{The following code shows an example for @ref crend.,crend} + + @since version 1.0 */ const_reverse_iterator crend() const { @@ -3526,8 +3603,8 @@ class basic_json array | result of function array_t::empty() @complexity Constant, as long as @ref array_t and @ref object_t satisfy the - Container concept; that is, their empty() functions have - constant complexity. + Container concept; that is, their empty() functions have constant + complexity. @requirement This function satisfies the Container requirements: - The complexity is constant. @@ -3535,6 +3612,8 @@ class basic_json @liveexample{The following code uses @ref empty to check if a @ref json object contains any elements.,empty} + + @since version 1.0 */ bool empty() const noexcept { @@ -3542,6 +3621,7 @@ class basic_json { case value_t::null: { + // null values are empty return true; } @@ -3589,6 +3669,8 @@ class basic_json @liveexample{The following code calls @ref size on the different value types.,size} + + @since version 1.0 */ size_type size() const noexcept { @@ -3596,6 +3678,7 @@ class basic_json { case value_t::null: { + // null values are empty return 0; } @@ -3646,6 +3729,8 @@ class basic_json @liveexample{The following code calls @ref max_size on the different value types. Note the output is implementation specific.,max_size} + + @since version 1.0 */ size_type max_size() const noexcept { @@ -3701,6 +3786,8 @@ class basic_json @liveexample{The example below shows the effect of @ref clear to different JSON types.,clear} + + @since version 1.0 */ void clear() noexcept { @@ -3765,6 +3852,8 @@ class basic_json @liveexample{The example shows how `push_back` and `+=` can be used to add elements to a JSON array. Note how the `null` value was silently converted to a JSON array.,push_back} + + @since version 1.0 */ void push_back(basic_json&& value) { @@ -3847,6 +3936,8 @@ class basic_json @liveexample{The example shows how `push_back` and `+=` can be used to add elements to a JSON object. Note how the `null` value was silently converted to a JSON object.,push_back__object_t__value} + + @since version 1.0 */ void push_back(const typename object_t::value_type& value) { @@ -3894,6 +3985,8 @@ class basic_json container. @liveexample{The example shows how insert is used.,insert} + + @since version 1.0 */ iterator insert(const_iterator pos, const basic_json& value) { @@ -3945,6 +4038,8 @@ class basic_json and end of the container. @liveexample{The example shows how insert is used.,insert__count} + + @since version 1.0 */ iterator insert(const_iterator pos, size_type count, const basic_json& value) { @@ -3991,6 +4086,8 @@ class basic_json distance between @a pos and end of the container. @liveexample{The example shows how insert is used.,insert__range} + + @since version 1.0 */ iterator insert(const_iterator pos, const_iterator first, const_iterator last) { @@ -4008,7 +4105,7 @@ class basic_json if (first.m_object != last.m_object) { - throw std::domain_error("iterators does not fit"); + throw std::domain_error("iterators do not fit"); } if (first.m_object == this or last.m_object == this) @@ -4018,8 +4115,10 @@ 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); + 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; } @@ -4041,6 +4140,8 @@ class basic_json pos and end of the container. @liveexample{The example shows how insert is used.,insert__ilist} + + @since version 1.0 */ iterator insert(const_iterator pos, std::initializer_list ilist) { @@ -4076,6 +4177,8 @@ class basic_json @liveexample{The example below shows how JSON arrays can be swapped.,swap__reference} + + @since version 1.0 */ void swap(reference other) noexcept ( std::is_nothrow_move_constructible::value and @@ -4104,6 +4207,8 @@ class basic_json @liveexample{The example below shows how JSON values can be swapped.,swap__array_t} + + @since version 1.0 */ void swap(array_t& other) { @@ -4134,6 +4239,8 @@ class basic_json @liveexample{The example below shows how JSON values can be swapped.,swap__object_t} + + @since version 1.0 */ void swap(object_t& other) { @@ -4164,6 +4271,8 @@ class basic_json @liveexample{The example below shows how JSON values can be swapped.,swap__string_t} + + @since version 1.0 */ void swap(string_t& other) { @@ -4195,6 +4304,8 @@ class basic_json Returns an ordering that is similar to Python: - order: null < boolean < number < object < array < string - furthermore, each type is not smaller than itself + + @since version 1.0 */ friend bool operator<(const value_t lhs, const value_t rhs) { @@ -4239,6 +4350,8 @@ class basic_json @liveexample{The example demonstrates comparing several JSON types.,operator__equal} + + @since version 1.0 */ friend bool operator==(const_reference lhs, const_reference rhs) noexcept { @@ -4295,6 +4408,8 @@ class basic_json @liveexample{The example compares several JSON types to the null pointer. ,operator__equal__nullptr_t} + + @since version 1.0 */ friend bool operator==(const_reference v, std::nullptr_t) noexcept { @@ -4323,6 +4438,8 @@ class basic_json @liveexample{The example demonstrates comparing several JSON types.,operator__notequal} + + @since version 1.0 */ friend bool operator!=(const_reference lhs, const_reference rhs) noexcept { @@ -4344,6 +4461,8 @@ class basic_json @liveexample{The example compares several JSON types to the null pointer. ,operator__notequal__nullptr_t} + + @since version 1.0 */ friend bool operator!=(const_reference v, std::nullptr_t) noexcept { @@ -4380,6 +4499,8 @@ class basic_json @liveexample{The example demonstrates comparing several JSON types.,operator__less} + + @since version 1.0 */ friend bool operator<(const_reference lhs, const_reference rhs) noexcept { @@ -4439,6 +4560,8 @@ class basic_json @liveexample{The example demonstrates comparing several JSON types.,operator__greater} + + @since version 1.0 */ friend bool operator<=(const_reference lhs, const_reference rhs) noexcept { @@ -4459,6 +4582,8 @@ class basic_json @liveexample{The example demonstrates comparing several JSON types.,operator__lessequal} + + @since version 1.0 */ friend bool operator>(const_reference lhs, const_reference rhs) noexcept { @@ -4479,6 +4604,8 @@ class basic_json @liveexample{The example demonstrates comparing several JSON types.,operator__greaterequal} + + @since version 1.0 */ friend bool operator>=(const_reference lhs, const_reference rhs) noexcept { @@ -4514,6 +4641,8 @@ class basic_json @liveexample{The example below shows the serialization with different parameters to `width` to adjust the indentation level.,operator_serialize} + + @since version 1.0 */ friend std::ostream& operator<<(std::ostream& o, const basic_json& j) { @@ -4567,8 +4696,10 @@ class basic_json @liveexample{The example below demonstrates the parse function with and without callback function.,parse__string__parser_callback_t} - @sa parse(std::istream&, parser_callback_t) for a version that reads from - an input stream + @sa @ref parse(std::istream&, parser_callback_t) for a version that reads + from an input stream + + @since version 1.0 */ static basic_json parse(const string_t& s, parser_callback_t cb = nullptr) { @@ -4594,14 +4725,19 @@ class basic_json @liveexample{The example below demonstrates the parse function with and without callback function.,parse__istream__parser_callback_t} - @sa parse(const string_t&, parser_callback_t) for a version that reads + @sa @ref parse(const string_t&, parser_callback_t) for a version that reads from a string + + @since version 1.0 */ static basic_json parse(std::istream& i, parser_callback_t cb = nullptr) { return parser(i, cb).parse(); } + /*! + @copydoc parse(std::istream&, parser_callback_t) + */ static basic_json parse(std::istream&& i, parser_callback_t cb = nullptr) { return parser(i, cb).parse(); @@ -4627,6 +4763,8 @@ class basic_json @sa parse(std::istream&, parser_callback_t) for a variant with a parser callback function to filter values while parsing + + @since version 1.0 */ friend std::istream& operator<<(basic_json& j, std::istream& i) { @@ -4658,39 +4796,19 @@ class basic_json switch (m_type) { case value_t::null: - { return "null"; - } - case value_t::object: - { return "object"; - } - case value_t::array: - { return "array"; - } - case value_t::string: - { return "string"; - } - case value_t::boolean: - { return "boolean"; - } - case value_t::discarded: - { return "discarded"; - } - default: - { return "number"; - } } } @@ -4873,7 +4991,9 @@ class basic_json @param[in] indent_step the indent level @param[in] current_indent the current indent level (only used internally) */ - void dump(std::ostream& o, const bool pretty_print, const unsigned int indent_step, + void dump(std::ostream& o, + const bool pretty_print, + const unsigned int indent_step, const unsigned int current_indent = 0) const { // variable to hold indentation for recursive calls @@ -5106,6 +5226,8 @@ class basic_json - [RandomAccessIterator](http://en.cppreference.com/w/cpp/concept/RandomAccessIterator): The iterator that can be moved to point (forward and backward) to any element in constant time. + + @since version 1.0 */ class const_iterator : public std::iterator { @@ -5276,14 +5398,9 @@ class basic_json default: { - if (m_it.primitive_iterator.is_begin()) - { - return *m_object; - } - else - { - throw std::out_of_range("cannot get value"); - } + return m_it.primitive_iterator.is_begin() + ? *m_object + : throw std::out_of_range("cannot get value"); } } } @@ -5305,14 +5422,9 @@ class basic_json default: { - if (m_it.primitive_iterator.is_begin()) - { - return m_object; - } - else - { - throw std::out_of_range("cannot get value"); - } + return m_it.primitive_iterator.is_begin() + ? m_object + : throw std::out_of_range("cannot get value"); } } } @@ -5322,7 +5434,6 @@ class basic_json { auto result = *this; ++(*this); - return result; } @@ -5358,7 +5469,6 @@ class basic_json { auto result = *this; --(*this); - return result; } @@ -5561,14 +5671,9 @@ class basic_json default: { - if (m_it.primitive_iterator == -n) - { - return *m_object; - } - else - { - throw std::out_of_range("cannot get value"); - } + return (m_it.primitive_iterator == -n) + ? *m_object + : throw std::out_of_range("cannot get value"); } } } @@ -5576,14 +5681,9 @@ class basic_json /// return the key of an object iterator typename object_t::key_type key() const { - if (m_object->is_object()) - { - return m_it.object_iterator->first; - } - else - { - throw std::domain_error("cannot use key() for non-object iterators"); - } + return m_object->is_object() + ? m_it.object_iterator->first + : throw std::domain_error("cannot use key() for non-object iterators"); } /// return the value of an iterator @@ -5608,6 +5708,8 @@ class basic_json element in constant time. - [OutputIterator](http://en.cppreference.com/w/cpp/concept/OutputIterator): It is possible to write to the pointed-to element. + + @since version 1.0 */ class iterator : public const_iterator { @@ -5744,6 +5846,8 @@ class basic_json - [OutputIterator](http://en.cppreference.com/w/cpp/concept/OutputIterator): It is possible to write to the pointed-to element (only if @a Base is @ref iterator). + + @since version 1.0 */ template class json_reverse_iterator : public std::reverse_iterator @@ -5892,19 +5996,19 @@ class basic_json { switch (anchor.m_object->type()) { - /// use integer array index as key + // use integer array index as key case value_t::array: { return std::to_string(array_index); } - /// use key from the object + // use key from the object case value_t::object: { return anchor.key(); } - /// use an empty key for all primitive types + // use an empty key for all primitive types default: { return ""; @@ -5960,8 +6064,8 @@ class basic_json literal_true, ///< the "true" literal literal_false, ///< the "false" literal literal_null, ///< the "null" literal - value_string, ///< a string - use get_string() for actual value - value_number, ///< a number - use get_number() for actual value + value_string, ///< a string -- use get_string() for actual value + value_number, ///< a number -- use get_number() for actual value begin_array, ///< the character for array begin "[" begin_object, ///< the character for object begin "{" end_array, ///< the character for array end "]" @@ -6397,6 +6501,8 @@ class basic_json /*! @brief syntax analysis + + This class implements a recursive decent parser. */ class parser { @@ -6619,13 +6725,13 @@ class basic_json const auto int_val = static_cast(float_val); if (approx(float_val, static_cast(int_val))) { - // we basic_json not lose precision -> return int + // we would not lose precision -> return int result.m_type = value_t::number_integer; result.m_value = int_val; } else { - // we would lose precision -> returnfloat + // we would lose precision -> return float result.m_type = value_t::number_float; result.m_value = static_cast(float_val); } @@ -6699,6 +6805,8 @@ class basic_json This type is the default specialization of the @ref basic_json class which uses the standard template types. + +@since version 1.0 */ using json = basic_json<>; } @@ -6713,6 +6821,8 @@ namespace std { /*! @brief exchanges the values of two JSON objects + +@since version 1.0 */ template <> inline void swap(nlohmann::json& j1, @@ -6728,7 +6838,11 @@ inline void swap(nlohmann::json& j1, template <> struct hash { - /// return a hash value for a JSON object + /*! + @brief return a hash value for a JSON object + + @since version 1.0 + */ std::size_t operator()(const nlohmann::json& j) const { // a naive hashing via the string representation @@ -6747,6 +6861,8 @@ no parse error occurred. @param[in] s a string representation of a JSON object @return a JSON object + +@since version 1.0 */ inline nlohmann::json operator "" _json(const char* s, std::size_t) { From ac4d4a0f66192fa25a56b2d505130ed6a961fd68 Mon Sep 17 00:00:00 2001 From: Niels Date: Thu, 17 Dec 2015 16:22:15 +0100 Subject: [PATCH 24/61] fixed compilation error and fixed shadow warnings --- src/json.hpp | 400 ++++++++++++++++++++++++++++------------------ src/json.hpp.re2c | 400 ++++++++++++++++++++++++++++------------------ 2 files changed, 490 insertions(+), 310 deletions(-) diff --git a/src/json.hpp b/src/json.hpp index 3fb7eb638..fc0665394 100644 --- a/src/json.hpp +++ b/src/json.hpp @@ -841,7 +841,7 @@ class basic_json object | `{}` array | `[]` - @param[in] value the type of the value to create + @param[in] value_type the type of the value to create @complexity Constant. @@ -863,8 +863,8 @@ class basic_json @since version 1.0 */ - basic_json(const value_t value) - : m_type(value), m_value(value) + basic_json(const value_t value_type) + : m_type(value_type), m_value(value_type) {} /*! @@ -916,9 +916,9 @@ class basic_json Create an object JSON value with a given content. - @param[in] value a value for the object + @param[in] val a value for the object - @complexity Linear in the size of the passed @a value. + @complexity Linear in the size of the passed @a val. @throw std::bad_alloc if allocation for object value fails @@ -930,8 +930,8 @@ class basic_json @since version 1.0 */ - basic_json(const object_t& value) - : m_type(value_t::object), m_value(value) + basic_json(const object_t& val) + : m_type(value_t::object), m_value(val) {} /*! @@ -944,9 +944,9 @@ class basic_json @tparam CompatibleObjectType an object type whose `key_type` and `value_type` is compatible to @ref object_t - @param[in] value a value for the object + @param[in] val a value for the object - @complexity Linear in the size of the passed @a value. + @complexity Linear in the size of the passed @a val. @throw std::bad_alloc if allocation for object value fails @@ -962,12 +962,12 @@ class basic_json std::is_constructible::value and std::is_constructible::value, int>::type = 0> - basic_json(const CompatibleObjectType& value) + basic_json(const CompatibleObjectType& val) : m_type(value_t::object) { using std::begin; using std::end; - m_value.object = create(begin(value), end(value)); + m_value.object = create(begin(val), end(val)); } /*! @@ -975,9 +975,9 @@ class basic_json Create an array JSON value with a given content. - @param[in] value a value for the array + @param[in] val a value for the array - @complexity Linear in the size of the passed @a value. + @complexity Linear in the size of the passed @a val. @throw std::bad_alloc if allocation for array value fails @@ -989,8 +989,8 @@ class basic_json @since version 1.0 */ - basic_json(const array_t& value) - : m_type(value_t::array), m_value(value) + basic_json(const array_t& val) + : m_type(value_t::array), m_value(val) {} /*! @@ -1003,9 +1003,9 @@ class basic_json @tparam CompatibleArrayType an object type whose `value_type` is compatible to @ref array_t - @param[in] value a value for the array + @param[in] val a value for the array - @complexity Linear in the size of the passed @a value. + @complexity Linear in the size of the passed @a val. @throw std::bad_alloc if allocation for array value fails @@ -1026,12 +1026,12 @@ class basic_json not std::is_same::value and std::is_constructible::value, int>::type = 0> - basic_json(const CompatibleArrayType& value) + basic_json(const CompatibleArrayType& val) : m_type(value_t::array) { using std::begin; using std::end; - m_value.array = create(begin(value), end(value)); + m_value.array = create(begin(val), end(val)); } /*! @@ -1039,9 +1039,9 @@ class basic_json Create an string JSON value with a given content. - @param[in] value a value for the string + @param[in] val a value for the string - @complexity Linear in the size of the passed @a value. + @complexity Linear in the size of the passed @a val. @throw std::bad_alloc if allocation for string value fails @@ -1055,8 +1055,8 @@ class basic_json @since version 1.0 */ - basic_json(const string_t& value) - : m_type(value_t::string), m_value(value) + basic_json(const string_t& val) + : m_type(value_t::string), m_value(val) {} /*! @@ -1064,9 +1064,9 @@ class basic_json Create a string JSON value with a given content. - @param[in] value a literal value for the string + @param[in] val a literal value for the string - @complexity Linear in the size of the passed @a value. + @complexity Linear in the size of the passed @a val. @throw std::bad_alloc if allocation for string value fails @@ -1079,8 +1079,8 @@ class basic_json @since version 1.0 */ - basic_json(const typename string_t::value_type* value) - : basic_json(string_t(value)) + basic_json(const typename string_t::value_type* val) + : basic_json(string_t(val)) {} /*! @@ -1088,12 +1088,12 @@ class basic_json Create a string JSON value with a given content. - @param[in] value a value for the string + @param[in] val a value for the string @tparam CompatibleStringType an string type which is compatible to @ref string_t - @complexity Linear in the size of the passed @a value. + @complexity Linear in the size of the passed @a val. @throw std::bad_alloc if allocation for string value fails @@ -1110,8 +1110,8 @@ class basic_json std::enable_if< std::is_constructible::value, int>::type = 0> - basic_json(const CompatibleStringType& value) - : basic_json(string_t(value)) + basic_json(const CompatibleStringType& val) + : basic_json(string_t(val)) {} /*! @@ -1119,7 +1119,7 @@ class basic_json Creates a JSON boolean type from a given value. - @param[in] value a boolean value to store + @param[in] val a boolean value to store @complexity Constant. @@ -1128,8 +1128,8 @@ class basic_json @since version 1.0 */ - basic_json(boolean_t value) - : m_type(value_t::boolean), m_value(value) + basic_json(boolean_t val) + : m_type(value_t::boolean), m_value(val) {} /*! @@ -1140,7 +1140,7 @@ class basic_json @tparam T helper type to compare number_integer_t and int (not visible in) the interface. - @param[in] value an integer to create a JSON number from + @param[in] val an integer to create a JSON number from @note This constructor would have the same signature as @ref basic_json(const int value), so we need to switch this one off in case @@ -1162,8 +1162,8 @@ class basic_json not (std::is_same::value) and std::is_same::value , int>::type = 0> - basic_json(const number_integer_t value) - : m_type(value_t::number_integer), m_value(value) + basic_json(const number_integer_t val) + : m_type(value_t::number_integer), m_value(val) {} /*! @@ -1171,7 +1171,7 @@ class basic_json Create an integer number JSON value with a given content. - @param[in] value an integer to create a JSON number from + @param[in] val an integer to create a JSON number from @note This constructor allows to pass enums directly to a constructor. As C++ has no way of specifying the type of an anonymous enum explicitly, we @@ -1191,9 +1191,9 @@ class basic_json @since version 1.0 */ - basic_json(const int value) + basic_json(const int val) : m_type(value_t::number_integer), - m_value(static_cast(value)) + m_value(static_cast(val)) {} /*! @@ -1207,7 +1207,7 @@ class basic_json @tparam CompatibleNumberIntegerType an integer type which is compatible to @ref number_integer_t. - @param[in] value an integer to create a JSON number from + @param[in] val an integer to create a JSON number from @complexity Constant. @@ -1226,9 +1226,9 @@ class basic_json std::is_constructible::value and std::numeric_limits::is_integer, CompatibleNumberIntegerType>::type = 0> - basic_json(const CompatibleNumberIntegerType value) noexcept + basic_json(const CompatibleNumberIntegerType val) noexcept : m_type(value_t::number_integer), - m_value(static_cast(value)) + m_value(static_cast(val)) {} /*! @@ -1236,13 +1236,13 @@ class basic_json Create a floating-point number JSON value with a given content. - @param[in] value a floating-point value to create a JSON number from + @param[in] val a floating-point value to create a JSON number from @note RFC 7159 , section 6 disallows NaN values: > Numeric values that cannot be represented in the grammar below (such > as Infinity and NaN) are not permitted. - In case the parameter @a value is not a number, a JSON null value is + In case the parameter @a val is not a number, a JSON null value is created instead. @complexity Constant. @@ -1255,11 +1255,11 @@ class basic_json @since version 1.0 */ - basic_json(const number_float_t value) - : m_type(value_t::number_float), m_value(value) + basic_json(const number_float_t val) + : m_type(value_t::number_float), m_value(val) { // replace infinity and NAN by null - if (not std::isfinite(value)) + if (not std::isfinite(val)) { m_type = value_t::null; m_value = json_value(); @@ -1276,13 +1276,13 @@ class basic_json @tparam CompatibleNumberFloatType a floating-point type which is compatible to @ref number_float_t. - @param[in] value a floating-point to create a JSON number from + @param[in] val a floating-point to create a JSON number from @note RFC 7159 , section 6 disallows NaN values: > Numeric values that cannot be represented in the grammar below (such > as Infinity and NaN) are not permitted. - In case the parameter @a value is not a number, a JSON null value is + In case the parameter @a val is not a number, a JSON null value is created instead. @complexity Constant. @@ -1301,8 +1301,8 @@ class basic_json std::is_constructible::value and std::is_floating_point::value>::type > - basic_json(const CompatibleNumberFloatType value) noexcept - : basic_json(number_float_t(value)) + basic_json(const CompatibleNumberFloatType val) noexcept + : basic_json(number_float_t(val)) {} /*! @@ -1378,7 +1378,7 @@ class basic_json value_t manual_type = value_t::array) { // the initializer list could describe an object - bool is_object = true; + bool is_an_object = true; // check if each element is an array with two elements whose first // element is a string @@ -1389,7 +1389,7 @@ class basic_json { // we found an element that makes it impossible to use the // initializer list as object - is_object = false; + is_an_object = false; break; } } @@ -1400,17 +1400,17 @@ class basic_json // if array is wanted, do not create an object though possible if (manual_type == value_t::array) { - is_object = false; + is_an_object = false; } // if object is wanted but impossible, throw an exception - if (manual_type == value_t::object and not is_object) + if (manual_type == value_t::object and not is_an_object) { throw std::domain_error("cannot create object from initializer list"); } } - if (is_object) + if (is_an_object) { // the initializer list is a list of pairs -> create object m_type = value_t::object; @@ -1512,14 +1512,14 @@ class basic_json /*! @brief construct an array with count copies of given value - Constructs a JSON array value by creating @a count copies of a passed - value. In case @a count is `0`, an empty array is created. As postcondition, - `std::distance(begin(),end()) == count` holds. + Constructs a JSON array value by creating @a cnt copies of a passed + value. In case @a cnt is `0`, an empty array is created. As postcondition, + `std::distance(begin(),end()) == cnt` holds. - @param[in] count the number of JSON copies of @a value to create - @param[in] value the JSON value to copy + @param[in] cnt the number of JSON copies of @a val to create + @param[in] val the JSON value to copy - @complexity Linear in @a count. + @complexity Linear in @a cnt. @liveexample{The following code shows examples for the @ref basic_json(size_type\, const basic_json&) @@ -1527,10 +1527,10 @@ class basic_json @since version 1.0 */ - basic_json(size_type count, const basic_json& value) + basic_json(size_type cnt, const basic_json& val) : m_type(value_t::array) { - m_value.array = create(count, value); + m_value.array = create(cnt, val); } /*! @@ -2161,17 +2161,27 @@ class basic_json , int>::type = 0> T get_impl(T*) const { - return is_object() - ? T(m_value.object->begin(), m_value.object->end()) - : throw std::domain_error("type must be object, but is " + type_name()); + if (is_object()) + { + return T(m_value.object->begin(), m_value.object->end()); + } + else + { + throw std::domain_error("type must be object, but is " + type_name()); + } } /// get an object (explicit) object_t get_impl(object_t*) const { - return is_object() - ? *(m_value.object) - : throw std::domain_error("type must be object, but is " + type_name()); + if (is_object()) + { + return *(m_value.object); + } + else + { + throw std::domain_error("type must be object, but is " + type_name()); + } } /// get an array (explicit) @@ -2234,17 +2244,27 @@ class basic_json , int>::type = 0> T get_impl(T*) const { - return is_array() - ? T(m_value.array->begin(), m_value.array->end()) - : throw std::domain_error("type must be array, but is " + type_name()); + if (is_array()) + { + return T(m_value.array->begin(), m_value.array->end()); + } + else + { + throw std::domain_error("type must be array, but is " + type_name()); + } } /// get an array (explicit) array_t get_impl(array_t*) const { - return is_array() - ? *(m_value.array) - : throw std::domain_error("type must be array, but is " + type_name()); + if (is_array()) + { + return *(m_value.array); + } + else + { + throw std::domain_error("type must be array, but is " + type_name()); + } } /// get a string (explicit) @@ -2254,9 +2274,14 @@ class basic_json , int>::type = 0> T get_impl(T*) const { - return is_string() - ? *m_value.string - : throw std::domain_error("type must be string, but is " + type_name()); + if (is_string()) + { + return *m_value.string; + } + else + { + throw std::domain_error("type must be string, but is " + type_name()); + } } /// get a number (explicit) @@ -2288,9 +2313,14 @@ class basic_json /// get a boolean (explicit) boolean_t get_impl(boolean_t*) const { - return is_boolean() - ? m_value.boolean - : throw std::domain_error("type must be boolean, but is " + type_name()); + if (is_boolean()) + { + return m_value.boolean; + } + else + { + throw std::domain_error("type must be boolean, but is " + type_name()); + } } /// get a pointer to the value (object) @@ -2582,9 +2612,14 @@ class basic_json reference at(size_type idx) { // at only works for arrays - return is_array() - ? m_value.array->at(idx) - : throw std::domain_error("cannot use at() with " + type_name()); + if (is_array()) + { + return m_value.array->at(idx); + } + else + { + throw std::domain_error("cannot use at() with " + type_name()); + } } /*! @@ -2611,9 +2646,14 @@ class basic_json const_reference at(size_type idx) const { // at only works for arrays - return is_array() - ? m_value.array->at(idx) - : throw std::domain_error("cannot use at() with " + type_name()); + if (is_array()) + { + return m_value.array->at(idx); + } + else + { + throw std::domain_error("cannot use at() with " + type_name()); + } } /*! @@ -2644,9 +2684,14 @@ class basic_json reference at(const typename object_t::key_type& key) { // at only works for objects - return is_object() - ? m_value.object->at(key) - : throw std::domain_error("cannot use at() with " + type_name()); + if (is_object()) + { + return m_value.object->at(key); + } + else + { + throw std::domain_error("cannot use at() with " + type_name()); + } } /*! @@ -2677,9 +2722,14 @@ class basic_json const_reference at(const typename object_t::key_type& key) const { // at only works for objects - return is_object() - ? m_value.object->at(key) - : throw std::domain_error("cannot use at() with " + type_name()); + if (is_object()) + { + return m_value.object->at(key); + } + else + { + throw std::domain_error("cannot use at() with " + type_name()); + } } /*! @@ -2752,9 +2802,14 @@ class basic_json const_reference operator[](size_type idx) const { // at only works for arrays - return is_array() - ? m_value.array->operator[](idx) - : throw std::domain_error("cannot use operator[] with " + type_name()); + if (is_array()) + { + return m_value.array->operator[](idx); + } + else + { + throw std::domain_error("cannot use operator[] with " + type_name()); + } } /*! @@ -2793,9 +2848,14 @@ class basic_json } // [] only works for objects - return is_object() - ? m_value.object->operator[](key) - : throw std::domain_error("cannot use operator[] with " + type_name()); + if (is_object()) + { + return m_value.object->operator[](key); + } + else + { + throw std::domain_error("cannot use operator[] with " + type_name()); + } } /*! @@ -2837,9 +2897,14 @@ class basic_json } // at only works for objects - return is_object() - ? m_value.object->operator[](key) - : throw std::domain_error("cannot use operator[] with " + type_name()); + if (is_object()) + { + return m_value.object->operator[](key); + } + else + { + throw std::domain_error("cannot use operator[] with " + type_name()); + } } /*! @@ -3227,9 +3292,14 @@ class basic_json size_type erase(const typename object_t::key_type& key) { // this erase only works for objects - return is_object() - ? m_value.object->erase(key) - : throw std::domain_error("cannot use erase() with " + type_name()); + if (is_object()) + { + return m_value.object->erase(key); + } + else + { + throw std::domain_error("cannot use erase() with " + type_name()); + } } /*! @@ -3839,11 +3909,11 @@ class basic_json /*! @brief add an object to an array - Appends the given element @a value to the end of the JSON value. If the + Appends the given element @a val to the end of the JSON value. If the function is called on a JSON null value, an empty array is created before - appending @a value. + appending @a val. - @param value the value to add to the JSON array + @param val the value to add to the JSON array @throw std::domain_error when called on a type other than JSON array or null @@ -3855,7 +3925,7 @@ class basic_json @since version 1.0 */ - void push_back(basic_json&& value) + void push_back(basic_json&& val) { // push_back only works for null objects or arrays if (not(is_null() or is_array())) @@ -3871,18 +3941,18 @@ class basic_json } // add element to array (move semantics) - m_value.array->push_back(std::move(value)); + m_value.array->push_back(std::move(val)); // invalidate object - value.m_type = value_t::null; + val.m_type = value_t::null; } /*! @brief add an object to an array @copydoc push_back(basic_json&&) */ - reference operator+=(basic_json&& value) + reference operator+=(basic_json&& val) { - push_back(std::move(value)); + push_back(std::move(val)); return *this; } @@ -3890,7 +3960,7 @@ class basic_json @brief add an object to an array @copydoc push_back(basic_json&&) */ - void push_back(const basic_json& value) + void push_back(const basic_json& val) { // push_back only works for null objects or arrays if (not(is_null() or is_array())) @@ -3906,27 +3976,27 @@ class basic_json } // add element to array - m_value.array->push_back(value); + m_value.array->push_back(val); } /*! @brief add an object to an array @copydoc push_back(basic_json&&) */ - reference operator+=(const basic_json& value) + reference operator+=(const basic_json& val) { - push_back(value); + push_back(val); return *this; } /*! @brief add an object to an object - Inserts the given element @a value to the JSON object. If the function is + Inserts the given element @a val to the JSON object. If the function is called on a JSON null value, an empty object is created before inserting @a - value. + val. - @param[in] value the value to add to the JSON object + @param[in] val the value to add to the JSON object @throw std::domain_error when called on a type other than JSON object or null @@ -3939,7 +4009,7 @@ class basic_json @since version 1.0 */ - void push_back(const typename object_t::value_type& value) + void push_back(const typename object_t::value_type& val) { // push_back only works for null objects or objects if (not(is_null() or is_object())) @@ -3955,28 +4025,28 @@ class basic_json } // add element to array - m_value.object->insert(value); + m_value.object->insert(val); } /*! @brief add an object to an object @copydoc push_back(const typename object_t::value_type&) */ - reference operator+=(const typename object_t::value_type& value) + reference operator+=(const typename object_t::value_type& val) { - push_back(value); - return operator[](value.first); + push_back(val); + return operator[](val.first); } /*! @brief inserts element - Inserts element @a value before iterator @a pos. + Inserts element @a val before iterator @a pos. @param[in] pos iterator before which the content will be inserted; may be the end() iterator - @param[in] value element to insert - @return iterator pointing to the inserted @a value. + @param[in] val element to insert + @return iterator pointing to the inserted @a val. @throw std::domain_error if called on JSON values other than arrays @throw std::domain_error if @a pos is not an iterator of *this @@ -3988,7 +4058,7 @@ class basic_json @since version 1.0 */ - iterator insert(const_iterator pos, const basic_json& value) + iterator insert(const_iterator pos, const basic_json& val) { // insert only works for arrays if (is_array()) @@ -4001,7 +4071,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, value); + result.m_it.array_iterator = m_value.array->insert(pos.m_it.array_iterator, val); return result; } else @@ -4014,34 +4084,34 @@ class basic_json @brief inserts element @copydoc insert(const_iterator, const basic_json&) */ - iterator insert(const_iterator pos, basic_json&& value) + iterator insert(const_iterator pos, basic_json&& val) { - return insert(pos, value); + return insert(pos, val); } /*! @brief inserts elements - Inserts @a count copies of @a value before iterator @a pos. + Inserts @a cnt copies of @a val before iterator @a pos. @param[in] pos iterator before which the content will be inserted; may be the end() iterator - @param[in] count number of copies of @a value to insert - @param[in] value element to insert + @param[in] cnt number of copies of @a val to insert + @param[in] val element to insert @return iterator pointing to the first element inserted, or @a pos if - `count==0` + `cnt==0` @throw std::domain_error if called on JSON values other than arrays @throw std::domain_error if @a pos is not an iterator of *this - @complexity Linear in @a count plus linear in the distance between @a pos + @complexity Linear in @a cnt plus linear in the distance between @a pos and end of the container. @liveexample{The example shows how insert is used.,insert__count} @since version 1.0 */ - iterator insert(const_iterator pos, size_type count, const basic_json& value) + iterator insert(const_iterator pos, size_type cnt, const basic_json& val) { // insert only works for arrays if (is_array()) @@ -4054,7 +4124,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, count, value); + result.m_it.array_iterator = m_value.array->insert(pos.m_it.array_iterator, cnt, val); return result; } else @@ -5398,9 +5468,14 @@ class basic_json default: { - return m_it.primitive_iterator.is_begin() - ? *m_object - : throw std::out_of_range("cannot get value"); + if (m_it.primitive_iterator.is_begin()) + { + return *m_object; + } + else + { + throw std::out_of_range("cannot get value"); + } } } } @@ -5422,9 +5497,14 @@ class basic_json default: { - return m_it.primitive_iterator.is_begin() - ? m_object - : throw std::out_of_range("cannot get value"); + if (m_it.primitive_iterator.is_begin()) + { + return m_object; + } + else + { + throw std::out_of_range("cannot get value"); + } } } } @@ -5671,9 +5751,14 @@ class basic_json default: { - return (m_it.primitive_iterator == -n) - ? *m_object - : throw std::out_of_range("cannot get value"); + if (m_it.primitive_iterator == -n) + { + return *m_object; + } + else + { + throw std::out_of_range("cannot get value"); + } } } } @@ -5681,9 +5766,14 @@ class basic_json /// return the key of an object iterator typename object_t::key_type key() const { - return m_object->is_object() - ? m_it.object_iterator->first - : throw std::domain_error("cannot use key() for non-object iterators"); + if (m_object->is_object()) + { + return m_it.object_iterator->first; + } + else + { + throw std::domain_error("cannot use key() for non-object iterators"); + } } /// return the value of an iterator @@ -6207,10 +6297,10 @@ class basic_json return ":"; case token_type::value_separator: return ","; - case token_type::end_of_input: - return ""; case token_type::parse_error: return ""; + case token_type::end_of_input: + return ""; } } diff --git a/src/json.hpp.re2c b/src/json.hpp.re2c index 0efd7490f..9727e2794 100644 --- a/src/json.hpp.re2c +++ b/src/json.hpp.re2c @@ -841,7 +841,7 @@ class basic_json object | `{}` array | `[]` - @param[in] value the type of the value to create + @param[in] value_type the type of the value to create @complexity Constant. @@ -863,8 +863,8 @@ class basic_json @since version 1.0 */ - basic_json(const value_t value) - : m_type(value), m_value(value) + basic_json(const value_t value_type) + : m_type(value_type), m_value(value_type) {} /*! @@ -916,9 +916,9 @@ class basic_json Create an object JSON value with a given content. - @param[in] value a value for the object + @param[in] val a value for the object - @complexity Linear in the size of the passed @a value. + @complexity Linear in the size of the passed @a val. @throw std::bad_alloc if allocation for object value fails @@ -930,8 +930,8 @@ class basic_json @since version 1.0 */ - basic_json(const object_t& value) - : m_type(value_t::object), m_value(value) + basic_json(const object_t& val) + : m_type(value_t::object), m_value(val) {} /*! @@ -944,9 +944,9 @@ class basic_json @tparam CompatibleObjectType an object type whose `key_type` and `value_type` is compatible to @ref object_t - @param[in] value a value for the object + @param[in] val a value for the object - @complexity Linear in the size of the passed @a value. + @complexity Linear in the size of the passed @a val. @throw std::bad_alloc if allocation for object value fails @@ -962,12 +962,12 @@ class basic_json std::is_constructible::value and std::is_constructible::value, int>::type = 0> - basic_json(const CompatibleObjectType& value) + basic_json(const CompatibleObjectType& val) : m_type(value_t::object) { using std::begin; using std::end; - m_value.object = create(begin(value), end(value)); + m_value.object = create(begin(val), end(val)); } /*! @@ -975,9 +975,9 @@ class basic_json Create an array JSON value with a given content. - @param[in] value a value for the array + @param[in] val a value for the array - @complexity Linear in the size of the passed @a value. + @complexity Linear in the size of the passed @a val. @throw std::bad_alloc if allocation for array value fails @@ -989,8 +989,8 @@ class basic_json @since version 1.0 */ - basic_json(const array_t& value) - : m_type(value_t::array), m_value(value) + basic_json(const array_t& val) + : m_type(value_t::array), m_value(val) {} /*! @@ -1003,9 +1003,9 @@ class basic_json @tparam CompatibleArrayType an object type whose `value_type` is compatible to @ref array_t - @param[in] value a value for the array + @param[in] val a value for the array - @complexity Linear in the size of the passed @a value. + @complexity Linear in the size of the passed @a val. @throw std::bad_alloc if allocation for array value fails @@ -1026,12 +1026,12 @@ class basic_json not std::is_same::value and std::is_constructible::value, int>::type = 0> - basic_json(const CompatibleArrayType& value) + basic_json(const CompatibleArrayType& val) : m_type(value_t::array) { using std::begin; using std::end; - m_value.array = create(begin(value), end(value)); + m_value.array = create(begin(val), end(val)); } /*! @@ -1039,9 +1039,9 @@ class basic_json Create an string JSON value with a given content. - @param[in] value a value for the string + @param[in] val a value for the string - @complexity Linear in the size of the passed @a value. + @complexity Linear in the size of the passed @a val. @throw std::bad_alloc if allocation for string value fails @@ -1055,8 +1055,8 @@ class basic_json @since version 1.0 */ - basic_json(const string_t& value) - : m_type(value_t::string), m_value(value) + basic_json(const string_t& val) + : m_type(value_t::string), m_value(val) {} /*! @@ -1064,9 +1064,9 @@ class basic_json Create a string JSON value with a given content. - @param[in] value a literal value for the string + @param[in] val a literal value for the string - @complexity Linear in the size of the passed @a value. + @complexity Linear in the size of the passed @a val. @throw std::bad_alloc if allocation for string value fails @@ -1079,8 +1079,8 @@ class basic_json @since version 1.0 */ - basic_json(const typename string_t::value_type* value) - : basic_json(string_t(value)) + basic_json(const typename string_t::value_type* val) + : basic_json(string_t(val)) {} /*! @@ -1088,12 +1088,12 @@ class basic_json Create a string JSON value with a given content. - @param[in] value a value for the string + @param[in] val a value for the string @tparam CompatibleStringType an string type which is compatible to @ref string_t - @complexity Linear in the size of the passed @a value. + @complexity Linear in the size of the passed @a val. @throw std::bad_alloc if allocation for string value fails @@ -1110,8 +1110,8 @@ class basic_json std::enable_if< std::is_constructible::value, int>::type = 0> - basic_json(const CompatibleStringType& value) - : basic_json(string_t(value)) + basic_json(const CompatibleStringType& val) + : basic_json(string_t(val)) {} /*! @@ -1119,7 +1119,7 @@ class basic_json Creates a JSON boolean type from a given value. - @param[in] value a boolean value to store + @param[in] val a boolean value to store @complexity Constant. @@ -1128,8 +1128,8 @@ class basic_json @since version 1.0 */ - basic_json(boolean_t value) - : m_type(value_t::boolean), m_value(value) + basic_json(boolean_t val) + : m_type(value_t::boolean), m_value(val) {} /*! @@ -1140,7 +1140,7 @@ class basic_json @tparam T helper type to compare number_integer_t and int (not visible in) the interface. - @param[in] value an integer to create a JSON number from + @param[in] val an integer to create a JSON number from @note This constructor would have the same signature as @ref basic_json(const int value), so we need to switch this one off in case @@ -1162,8 +1162,8 @@ class basic_json not (std::is_same::value) and std::is_same::value , int>::type = 0> - basic_json(const number_integer_t value) - : m_type(value_t::number_integer), m_value(value) + basic_json(const number_integer_t val) + : m_type(value_t::number_integer), m_value(val) {} /*! @@ -1171,7 +1171,7 @@ class basic_json Create an integer number JSON value with a given content. - @param[in] value an integer to create a JSON number from + @param[in] val an integer to create a JSON number from @note This constructor allows to pass enums directly to a constructor. As C++ has no way of specifying the type of an anonymous enum explicitly, we @@ -1191,9 +1191,9 @@ class basic_json @since version 1.0 */ - basic_json(const int value) + basic_json(const int val) : m_type(value_t::number_integer), - m_value(static_cast(value)) + m_value(static_cast(val)) {} /*! @@ -1207,7 +1207,7 @@ class basic_json @tparam CompatibleNumberIntegerType an integer type which is compatible to @ref number_integer_t. - @param[in] value an integer to create a JSON number from + @param[in] val an integer to create a JSON number from @complexity Constant. @@ -1226,9 +1226,9 @@ class basic_json std::is_constructible::value and std::numeric_limits::is_integer, CompatibleNumberIntegerType>::type = 0> - basic_json(const CompatibleNumberIntegerType value) noexcept + basic_json(const CompatibleNumberIntegerType val) noexcept : m_type(value_t::number_integer), - m_value(static_cast(value)) + m_value(static_cast(val)) {} /*! @@ -1236,13 +1236,13 @@ class basic_json Create a floating-point number JSON value with a given content. - @param[in] value a floating-point value to create a JSON number from + @param[in] val a floating-point value to create a JSON number from @note RFC 7159 , section 6 disallows NaN values: > Numeric values that cannot be represented in the grammar below (such > as Infinity and NaN) are not permitted. - In case the parameter @a value is not a number, a JSON null value is + In case the parameter @a val is not a number, a JSON null value is created instead. @complexity Constant. @@ -1255,11 +1255,11 @@ class basic_json @since version 1.0 */ - basic_json(const number_float_t value) - : m_type(value_t::number_float), m_value(value) + basic_json(const number_float_t val) + : m_type(value_t::number_float), m_value(val) { // replace infinity and NAN by null - if (not std::isfinite(value)) + if (not std::isfinite(val)) { m_type = value_t::null; m_value = json_value(); @@ -1276,13 +1276,13 @@ class basic_json @tparam CompatibleNumberFloatType a floating-point type which is compatible to @ref number_float_t. - @param[in] value a floating-point to create a JSON number from + @param[in] val a floating-point to create a JSON number from @note RFC 7159 , section 6 disallows NaN values: > Numeric values that cannot be represented in the grammar below (such > as Infinity and NaN) are not permitted. - In case the parameter @a value is not a number, a JSON null value is + In case the parameter @a val is not a number, a JSON null value is created instead. @complexity Constant. @@ -1301,8 +1301,8 @@ class basic_json std::is_constructible::value and std::is_floating_point::value>::type > - basic_json(const CompatibleNumberFloatType value) noexcept - : basic_json(number_float_t(value)) + basic_json(const CompatibleNumberFloatType val) noexcept + : basic_json(number_float_t(val)) {} /*! @@ -1378,7 +1378,7 @@ class basic_json value_t manual_type = value_t::array) { // the initializer list could describe an object - bool is_object = true; + bool is_an_object = true; // check if each element is an array with two elements whose first // element is a string @@ -1389,7 +1389,7 @@ class basic_json { // we found an element that makes it impossible to use the // initializer list as object - is_object = false; + is_an_object = false; break; } } @@ -1400,17 +1400,17 @@ class basic_json // if array is wanted, do not create an object though possible if (manual_type == value_t::array) { - is_object = false; + is_an_object = false; } // if object is wanted but impossible, throw an exception - if (manual_type == value_t::object and not is_object) + if (manual_type == value_t::object and not is_an_object) { throw std::domain_error("cannot create object from initializer list"); } } - if (is_object) + if (is_an_object) { // the initializer list is a list of pairs -> create object m_type = value_t::object; @@ -1512,14 +1512,14 @@ class basic_json /*! @brief construct an array with count copies of given value - Constructs a JSON array value by creating @a count copies of a passed - value. In case @a count is `0`, an empty array is created. As postcondition, - `std::distance(begin(),end()) == count` holds. + Constructs a JSON array value by creating @a cnt copies of a passed + value. In case @a cnt is `0`, an empty array is created. As postcondition, + `std::distance(begin(),end()) == cnt` holds. - @param[in] count the number of JSON copies of @a value to create - @param[in] value the JSON value to copy + @param[in] cnt the number of JSON copies of @a val to create + @param[in] val the JSON value to copy - @complexity Linear in @a count. + @complexity Linear in @a cnt. @liveexample{The following code shows examples for the @ref basic_json(size_type\, const basic_json&) @@ -1527,10 +1527,10 @@ class basic_json @since version 1.0 */ - basic_json(size_type count, const basic_json& value) + basic_json(size_type cnt, const basic_json& val) : m_type(value_t::array) { - m_value.array = create(count, value); + m_value.array = create(cnt, val); } /*! @@ -2161,17 +2161,27 @@ class basic_json , int>::type = 0> T get_impl(T*) const { - return is_object() - ? T(m_value.object->begin(), m_value.object->end()) - : throw std::domain_error("type must be object, but is " + type_name()); + if (is_object()) + { + return T(m_value.object->begin(), m_value.object->end()); + } + else + { + throw std::domain_error("type must be object, but is " + type_name()); + } } /// get an object (explicit) object_t get_impl(object_t*) const { - return is_object() - ? *(m_value.object) - : throw std::domain_error("type must be object, but is " + type_name()); + if (is_object()) + { + return *(m_value.object); + } + else + { + throw std::domain_error("type must be object, but is " + type_name()); + } } /// get an array (explicit) @@ -2234,17 +2244,27 @@ class basic_json , int>::type = 0> T get_impl(T*) const { - return is_array() - ? T(m_value.array->begin(), m_value.array->end()) - : throw std::domain_error("type must be array, but is " + type_name()); + if (is_array()) + { + return T(m_value.array->begin(), m_value.array->end()); + } + else + { + throw std::domain_error("type must be array, but is " + type_name()); + } } /// get an array (explicit) array_t get_impl(array_t*) const { - return is_array() - ? *(m_value.array) - : throw std::domain_error("type must be array, but is " + type_name()); + if (is_array()) + { + return *(m_value.array); + } + else + { + throw std::domain_error("type must be array, but is " + type_name()); + } } /// get a string (explicit) @@ -2254,9 +2274,14 @@ class basic_json , int>::type = 0> T get_impl(T*) const { - return is_string() - ? *m_value.string - : throw std::domain_error("type must be string, but is " + type_name()); + if (is_string()) + { + return *m_value.string; + } + else + { + throw std::domain_error("type must be string, but is " + type_name()); + } } /// get a number (explicit) @@ -2288,9 +2313,14 @@ class basic_json /// get a boolean (explicit) boolean_t get_impl(boolean_t*) const { - return is_boolean() - ? m_value.boolean - : throw std::domain_error("type must be boolean, but is " + type_name()); + if (is_boolean()) + { + return m_value.boolean; + } + else + { + throw std::domain_error("type must be boolean, but is " + type_name()); + } } /// get a pointer to the value (object) @@ -2582,9 +2612,14 @@ class basic_json reference at(size_type idx) { // at only works for arrays - return is_array() - ? m_value.array->at(idx) - : throw std::domain_error("cannot use at() with " + type_name()); + if (is_array()) + { + return m_value.array->at(idx); + } + else + { + throw std::domain_error("cannot use at() with " + type_name()); + } } /*! @@ -2611,9 +2646,14 @@ class basic_json const_reference at(size_type idx) const { // at only works for arrays - return is_array() - ? m_value.array->at(idx) - : throw std::domain_error("cannot use at() with " + type_name()); + if (is_array()) + { + return m_value.array->at(idx); + } + else + { + throw std::domain_error("cannot use at() with " + type_name()); + } } /*! @@ -2644,9 +2684,14 @@ class basic_json reference at(const typename object_t::key_type& key) { // at only works for objects - return is_object() - ? m_value.object->at(key) - : throw std::domain_error("cannot use at() with " + type_name()); + if (is_object()) + { + return m_value.object->at(key); + } + else + { + throw std::domain_error("cannot use at() with " + type_name()); + } } /*! @@ -2677,9 +2722,14 @@ class basic_json const_reference at(const typename object_t::key_type& key) const { // at only works for objects - return is_object() - ? m_value.object->at(key) - : throw std::domain_error("cannot use at() with " + type_name()); + if (is_object()) + { + return m_value.object->at(key); + } + else + { + throw std::domain_error("cannot use at() with " + type_name()); + } } /*! @@ -2752,9 +2802,14 @@ class basic_json const_reference operator[](size_type idx) const { // at only works for arrays - return is_array() - ? m_value.array->operator[](idx) - : throw std::domain_error("cannot use operator[] with " + type_name()); + if (is_array()) + { + return m_value.array->operator[](idx); + } + else + { + throw std::domain_error("cannot use operator[] with " + type_name()); + } } /*! @@ -2793,9 +2848,14 @@ class basic_json } // [] only works for objects - return is_object() - ? m_value.object->operator[](key) - : throw std::domain_error("cannot use operator[] with " + type_name()); + if (is_object()) + { + return m_value.object->operator[](key); + } + else + { + throw std::domain_error("cannot use operator[] with " + type_name()); + } } /*! @@ -2837,9 +2897,14 @@ class basic_json } // at only works for objects - return is_object() - ? m_value.object->operator[](key) - : throw std::domain_error("cannot use operator[] with " + type_name()); + if (is_object()) + { + return m_value.object->operator[](key); + } + else + { + throw std::domain_error("cannot use operator[] with " + type_name()); + } } /*! @@ -3227,9 +3292,14 @@ class basic_json size_type erase(const typename object_t::key_type& key) { // this erase only works for objects - return is_object() - ? m_value.object->erase(key) - : throw std::domain_error("cannot use erase() with " + type_name()); + if (is_object()) + { + return m_value.object->erase(key); + } + else + { + throw std::domain_error("cannot use erase() with " + type_name()); + } } /*! @@ -3839,11 +3909,11 @@ class basic_json /*! @brief add an object to an array - Appends the given element @a value to the end of the JSON value. If the + Appends the given element @a val to the end of the JSON value. If the function is called on a JSON null value, an empty array is created before - appending @a value. + appending @a val. - @param value the value to add to the JSON array + @param val the value to add to the JSON array @throw std::domain_error when called on a type other than JSON array or null @@ -3855,7 +3925,7 @@ class basic_json @since version 1.0 */ - void push_back(basic_json&& value) + void push_back(basic_json&& val) { // push_back only works for null objects or arrays if (not(is_null() or is_array())) @@ -3871,18 +3941,18 @@ class basic_json } // add element to array (move semantics) - m_value.array->push_back(std::move(value)); + m_value.array->push_back(std::move(val)); // invalidate object - value.m_type = value_t::null; + val.m_type = value_t::null; } /*! @brief add an object to an array @copydoc push_back(basic_json&&) */ - reference operator+=(basic_json&& value) + reference operator+=(basic_json&& val) { - push_back(std::move(value)); + push_back(std::move(val)); return *this; } @@ -3890,7 +3960,7 @@ class basic_json @brief add an object to an array @copydoc push_back(basic_json&&) */ - void push_back(const basic_json& value) + void push_back(const basic_json& val) { // push_back only works for null objects or arrays if (not(is_null() or is_array())) @@ -3906,27 +3976,27 @@ class basic_json } // add element to array - m_value.array->push_back(value); + m_value.array->push_back(val); } /*! @brief add an object to an array @copydoc push_back(basic_json&&) */ - reference operator+=(const basic_json& value) + reference operator+=(const basic_json& val) { - push_back(value); + push_back(val); return *this; } /*! @brief add an object to an object - Inserts the given element @a value to the JSON object. If the function is + Inserts the given element @a val to the JSON object. If the function is called on a JSON null value, an empty object is created before inserting @a - value. + val. - @param[in] value the value to add to the JSON object + @param[in] val the value to add to the JSON object @throw std::domain_error when called on a type other than JSON object or null @@ -3939,7 +4009,7 @@ class basic_json @since version 1.0 */ - void push_back(const typename object_t::value_type& value) + void push_back(const typename object_t::value_type& val) { // push_back only works for null objects or objects if (not(is_null() or is_object())) @@ -3955,28 +4025,28 @@ class basic_json } // add element to array - m_value.object->insert(value); + m_value.object->insert(val); } /*! @brief add an object to an object @copydoc push_back(const typename object_t::value_type&) */ - reference operator+=(const typename object_t::value_type& value) + reference operator+=(const typename object_t::value_type& val) { - push_back(value); - return operator[](value.first); + push_back(val); + return operator[](val.first); } /*! @brief inserts element - Inserts element @a value before iterator @a pos. + Inserts element @a val before iterator @a pos. @param[in] pos iterator before which the content will be inserted; may be the end() iterator - @param[in] value element to insert - @return iterator pointing to the inserted @a value. + @param[in] val element to insert + @return iterator pointing to the inserted @a val. @throw std::domain_error if called on JSON values other than arrays @throw std::domain_error if @a pos is not an iterator of *this @@ -3988,7 +4058,7 @@ class basic_json @since version 1.0 */ - iterator insert(const_iterator pos, const basic_json& value) + iterator insert(const_iterator pos, const basic_json& val) { // insert only works for arrays if (is_array()) @@ -4001,7 +4071,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, value); + result.m_it.array_iterator = m_value.array->insert(pos.m_it.array_iterator, val); return result; } else @@ -4014,34 +4084,34 @@ class basic_json @brief inserts element @copydoc insert(const_iterator, const basic_json&) */ - iterator insert(const_iterator pos, basic_json&& value) + iterator insert(const_iterator pos, basic_json&& val) { - return insert(pos, value); + return insert(pos, val); } /*! @brief inserts elements - Inserts @a count copies of @a value before iterator @a pos. + Inserts @a cnt copies of @a val before iterator @a pos. @param[in] pos iterator before which the content will be inserted; may be the end() iterator - @param[in] count number of copies of @a value to insert - @param[in] value element to insert + @param[in] cnt number of copies of @a val to insert + @param[in] val element to insert @return iterator pointing to the first element inserted, or @a pos if - `count==0` + `cnt==0` @throw std::domain_error if called on JSON values other than arrays @throw std::domain_error if @a pos is not an iterator of *this - @complexity Linear in @a count plus linear in the distance between @a pos + @complexity Linear in @a cnt plus linear in the distance between @a pos and end of the container. @liveexample{The example shows how insert is used.,insert__count} @since version 1.0 */ - iterator insert(const_iterator pos, size_type count, const basic_json& value) + iterator insert(const_iterator pos, size_type cnt, const basic_json& val) { // insert only works for arrays if (is_array()) @@ -4054,7 +4124,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, count, value); + result.m_it.array_iterator = m_value.array->insert(pos.m_it.array_iterator, cnt, val); return result; } else @@ -5398,9 +5468,14 @@ class basic_json default: { - return m_it.primitive_iterator.is_begin() - ? *m_object - : throw std::out_of_range("cannot get value"); + if (m_it.primitive_iterator.is_begin()) + { + return *m_object; + } + else + { + throw std::out_of_range("cannot get value"); + } } } } @@ -5422,9 +5497,14 @@ class basic_json default: { - return m_it.primitive_iterator.is_begin() - ? m_object - : throw std::out_of_range("cannot get value"); + if (m_it.primitive_iterator.is_begin()) + { + return m_object; + } + else + { + throw std::out_of_range("cannot get value"); + } } } } @@ -5671,9 +5751,14 @@ class basic_json default: { - return (m_it.primitive_iterator == -n) - ? *m_object - : throw std::out_of_range("cannot get value"); + if (m_it.primitive_iterator == -n) + { + return *m_object; + } + else + { + throw std::out_of_range("cannot get value"); + } } } } @@ -5681,9 +5766,14 @@ class basic_json /// return the key of an object iterator typename object_t::key_type key() const { - return m_object->is_object() - ? m_it.object_iterator->first - : throw std::domain_error("cannot use key() for non-object iterators"); + if (m_object->is_object()) + { + return m_it.object_iterator->first; + } + else + { + throw std::domain_error("cannot use key() for non-object iterators"); + } } /// return the value of an iterator @@ -6207,10 +6297,10 @@ class basic_json return ":"; case token_type::value_separator: return ","; - case token_type::end_of_input: - return ""; case token_type::parse_error: return ""; + case token_type::end_of_input: + return ""; } } From 1adb9d62dd8b676914f7f9f6f6493381d72b7193 Mon Sep 17 00:00:00 2001 From: Niels Date: Thu, 17 Dec 2015 16:52:38 +0100 Subject: [PATCH 25/61] fixed #156 --- src/json.hpp | 5 +++++ src/json.hpp.re2c | 5 +++++ 2 files changed, 10 insertions(+) diff --git a/src/json.hpp b/src/json.hpp index fc0665394..9de73ddf1 100644 --- a/src/json.hpp +++ b/src/json.hpp @@ -6301,6 +6301,11 @@ class basic_json return ""; case token_type::end_of_input: return ""; + default: + { + // catch non-enum values + return "unknown token"; // LCOV_EXCL_LINE + } } } diff --git a/src/json.hpp.re2c b/src/json.hpp.re2c index 9727e2794..5cee92f4b 100644 --- a/src/json.hpp.re2c +++ b/src/json.hpp.re2c @@ -6301,6 +6301,11 @@ class basic_json return ""; case token_type::end_of_input: return ""; + default: + { + // catch non-enum values + return "unknown token"; // LCOV_EXCL_LINE + } } } From 457bfc2401028a9eb42b738401935d3ad1e1d984 Mon Sep 17 00:00:00 2001 From: Niels Date: Sun, 20 Dec 2015 15:30:07 +0100 Subject: [PATCH 26/61] work on #144 --- README.md | 2 +- src/json.hpp | 6 +++++- src/json.hpp.re2c | 6 +++++- test/unit.cpp | 13 +++++++++++++ 4 files changed, 24 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index cd9be0d32..b671f3571 100644 --- a/README.md +++ b/README.md @@ -398,7 +398,7 @@ $ make $ ./json_unit "*" =============================================================================== -All tests passed (3341846 assertions in 28 test cases) +All tests passed (3341848 assertions in 28 test cases) ``` For more information, have a look at the file [.travis.yml](https://github.com/nlohmann/json/blob/master/.travis.yml). diff --git a/src/json.hpp b/src/json.hpp index 9de73ddf1..6bfb44bff 100644 --- a/src/json.hpp +++ b/src/json.hpp @@ -2550,7 +2550,9 @@ class basic_json @tparam ValueType non-pointer type compatible to the JSON value, for instance `int` for JSON integer numbers, `bool` for JSON booleans, or - `std::vector` types for JSON arrays + `std::vector` types for JSON arrays. The character type of @ref string_t + as well as an initializer list of this type is excluded to avoid + ambiguities as these types implicitly convert to `std::string`. @return copy of the JSON value, converted to type @a ValueType @@ -2571,6 +2573,8 @@ class basic_json template::value + and not std::is_same::value + and not std::is_same>::value , int>::type = 0> operator ValueType() const { diff --git a/src/json.hpp.re2c b/src/json.hpp.re2c index 5cee92f4b..3ab1dfce1 100644 --- a/src/json.hpp.re2c +++ b/src/json.hpp.re2c @@ -2550,7 +2550,9 @@ class basic_json @tparam ValueType non-pointer type compatible to the JSON value, for instance `int` for JSON integer numbers, `bool` for JSON booleans, or - `std::vector` types for JSON arrays + `std::vector` types for JSON arrays. The character type of @ref string_t + as well as an initializer list of this type is excluded to avoid + ambiguities as these types implicitly convert to `std::string`. @return copy of the JSON value, converted to type @a ValueType @@ -2571,6 +2573,8 @@ class basic_json template::value + and not std::is_same::value + and not std::is_same>::value , int>::type = 0> operator ValueType() const { diff --git a/test/unit.cpp b/test/unit.cpp index 8826d835e..b143f31b5 100644 --- a/test/unit.cpp +++ b/test/unit.cpp @@ -10323,6 +10323,19 @@ TEST_CASE("regression tests") CHECK(j["string"] == "\u0007\u0007"); } + SECTION("issue #144 - implicit assignment to std::string fails") + { + json o = {{"name", "value"}}; + + std::string s1 = o["name"]; + CHECK(s1 == "value"); + + std::string s2; + s2 = o["name"]; + + CHECK(s2 == "value"); + } + SECTION("character following a surrogate pair is skipped") { CHECK(json::parse("\"\\ud80c\\udc60abc\"").get() == u8"\U00013060abc"); From 9def0186be05ecf01d4b576d4ac10d4dd88a849b Mon Sep 17 00:00:00 2001 From: Niels Date: Sun, 20 Dec 2015 15:42:01 +0100 Subject: [PATCH 27/61] upgraded Catch to v1.3.1 --- test/catch.hpp | 2645 +++++++++++++++++++++++++++++++----------------- 1 file changed, 1716 insertions(+), 929 deletions(-) diff --git a/test/catch.hpp b/test/catch.hpp index de61226cf..e2774f0be 100644 --- a/test/catch.hpp +++ b/test/catch.hpp @@ -1,6 +1,6 @@ /* - * Catch v1.2.1 - * Generated: 2015-06-30 18:23:27.961086 + * Catch v1.3.1 + * Generated: 2015-12-09 18:10:29.846134 * ---------------------------------------------------------- * This file has been merged from multiple headers. Please don't edit it directly * Copyright (c) 2012 Two Blue Cubes Ltd. All rights reserved. @@ -21,8 +21,6 @@ // #included from: internal/catch_suppress_warnings.h -#define TWOBLUECUBES_CATCH_SUPPRESS_WARNINGS_H_INCLUDED - #ifdef __clang__ # ifdef __ICC // icpc defines the __clang__ macro # pragma warning(push) @@ -37,6 +35,7 @@ # pragma clang diagnostic ignored "-Wc++98-compat" # pragma clang diagnostic ignored "-Wc++98-compat-pedantic" # pragma clang diagnostic ignored "-Wswitch-enum" +# pragma clang diagnostic ignored "-Wcovered-switch-default" # endif #elif defined __GNUC__ # pragma GCC diagnostic ignored "-Wvariadic-macros" @@ -44,7 +43,6 @@ # pragma GCC diagnostic push # pragma GCC diagnostic ignored "-Wpadded" #endif - #if defined(CATCH_CONFIG_MAIN) || defined(CATCH_CONFIG_RUNNER) # define CATCH_IMPL #endif @@ -84,11 +82,19 @@ // CATCH_CONFIG_CPP11_GENERATED_METHODS : The delete and default keywords for compiler generated methods // CATCH_CONFIG_CPP11_IS_ENUM : std::is_enum is supported? // CATCH_CONFIG_CPP11_TUPLE : std::tuple is supported +// CATCH_CONFIG_CPP11_LONG_LONG : is long long supported? +// CATCH_CONFIG_CPP11_OVERRIDE : is override supported? +// CATCH_CONFIG_CPP11_UNIQUE_PTR : is unique_ptr supported (otherwise use auto_ptr) // CATCH_CONFIG_CPP11_OR_GREATER : Is C++11 supported? // CATCH_CONFIG_VARIADIC_MACROS : are variadic macros supported? +// **************** +// Note to maintainers: if new toggles are added please document them +// in configuration.md, too +// **************** + // In general each macro has a _NO_ form // (e.g. CATCH_CONFIG_CPP11_NO_NULLPTR) which disables the feature. // Many features, at point of detection, define an _INTERNAL_ macro, so they @@ -130,10 +136,13 @@ // GCC #ifdef __GNUC__ -#if __GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6 && defined(__GXX_EXPERIMENTAL_CXX0X__) ) +#if __GNUC__ == 4 && __GNUC_MINOR__ >= 6 && defined(__GXX_EXPERIMENTAL_CXX0X__) # define CATCH_INTERNAL_CONFIG_CPP11_NULLPTR #endif +// - otherwise more recent versions define __cplusplus >= 201103L +// and will get picked up below + #endif // __GNUC__ //////////////////////////////////////////////////////////////////////////////// @@ -142,6 +151,7 @@ #if (_MSC_VER >= 1600) # define CATCH_INTERNAL_CONFIG_CPP11_NULLPTR +# define CATCH_INTERNAL_CONFIG_CPP11_UNIQUE_PTR #endif #if (_MSC_VER >= 1900 ) // (VC++ 13 (VS2015)) @@ -151,6 +161,8 @@ #endif // _MSC_VER +//////////////////////////////////////////////////////////////////////////////// + // Use variadic macros if the compiler supports them #if ( defined _MSC_VER && _MSC_VER > 1400 && !defined __EDGE__) || \ ( defined __WAVE__ && __WAVE_HAS_VARIADICS ) || \ @@ -165,7 +177,7 @@ // C++ language feature support // catch all support for C++11 -#if (__cplusplus >= 201103L) +#if defined(__cplusplus) && __cplusplus >= 201103L # define CATCH_CPP11_OR_GREATER @@ -193,6 +205,17 @@ # define CATCH_INTERNAL_CONFIG_VARIADIC_MACROS # endif +# if !defined(CATCH_INTERNAL_CONFIG_CPP11_LONG_LONG) +# define CATCH_INTERNAL_CONFIG_CPP11_LONG_LONG +# endif + +# if !defined(CATCH_INTERNAL_CONFIG_CPP11_OVERRIDE) +# define CATCH_INTERNAL_CONFIG_CPP11_OVERRIDE +# endif +# if !defined(CATCH_INTERNAL_CONFIG_CPP11_UNIQUE_PTR) +# define CATCH_INTERNAL_CONFIG_CPP11_UNIQUE_PTR +# endif + #endif // __cplusplus >= 201103L // Now set the actual defines based on the above + anything the user has configured @@ -212,7 +235,16 @@ # define CATCH_CONFIG_CPP11_TUPLE #endif #if defined(CATCH_INTERNAL_CONFIG_VARIADIC_MACROS) && !defined(CATCH_CONFIG_NO_VARIADIC_MACROS) && !defined(CATCH_CONFIG_VARIADIC_MACROS) -#define CATCH_CONFIG_VARIADIC_MACROS +# define CATCH_CONFIG_VARIADIC_MACROS +#endif +#if defined(CATCH_INTERNAL_CONFIG_CPP11_LONG_LONG) && !defined(CATCH_CONFIG_NO_LONG_LONG) && !defined(CATCH_CONFIG_CPP11_LONG_LONG) && !defined(CATCH_CONFIG_NO_CPP11) +# define CATCH_CONFIG_CPP11_LONG_LONG +#endif +#if defined(CATCH_INTERNAL_CONFIG_CPP11_OVERRIDE) && !defined(CATCH_CONFIG_NO_OVERRIDE) && !defined(CATCH_CONFIG_CPP11_OVERRIDE) && !defined(CATCH_CONFIG_NO_CPP11) +# define CATCH_CONFIG_CPP11_OVERRIDE +#endif +#if defined(CATCH_INTERNAL_CONFIG_CPP11_UNIQUE_PTR) && !defined(CATCH_CONFIG_NO_UNIQUE_PTR) && !defined(CATCH_CONFIG_CPP11_UNIQUE_PTR) && !defined(CATCH_CONFIG_NO_CPP11) +# define CATCH_CONFIG_CPP11_UNIQUE_PTR #endif // noexcept support: @@ -224,8 +256,36 @@ # define CATCH_NOEXCEPT_IS(x) #endif +// nullptr support +#ifdef CATCH_CONFIG_CPP11_NULLPTR +# define CATCH_NULL nullptr +#else +# define CATCH_NULL NULL +#endif + +// override support +#ifdef CATCH_CONFIG_CPP11_OVERRIDE +# define CATCH_OVERRIDE override +#else +# define CATCH_OVERRIDE +#endif + +// unique_ptr support +#ifdef CATCH_CONFIG_CPP11_UNIQUE_PTR +# define CATCH_AUTO_PTR( T ) std::unique_ptr +#else +# define CATCH_AUTO_PTR( T ) std::auto_ptr +#endif + namespace Catch { + struct IConfig; + + struct CaseSensitive { enum Choice { + Yes, + No + }; }; + class NonCopyable { #ifdef CATCH_CONFIG_CPP11_GENERATED_METHODS NonCopyable( NonCopyable const& ) = delete; @@ -312,6 +372,9 @@ namespace Catch { void throwLogicError( std::string const& message, SourceLineInfo const& locationInfo ); + void seedRng( IConfig const& config ); + unsigned int rngSeed(); + // Use this in variadic streaming macros to allow // >> +StreamEndStop // as well as @@ -397,7 +460,7 @@ namespace Catch { template class Ptr { public: - Ptr() : m_p( NULL ){} + Ptr() : m_p( CATCH_NULL ){} Ptr( T* p ) : m_p( p ){ if( m_p ) m_p->addRef(); @@ -413,7 +476,7 @@ namespace Catch { void reset() { if( m_p ) m_p->release(); - m_p = NULL; + m_p = CATCH_NULL; } Ptr& operator = ( T* p ){ Ptr temp( p ); @@ -426,12 +489,11 @@ namespace Catch { return *this; } void swap( Ptr& other ) { std::swap( m_p, other.m_p ); } - T* get() { return m_p; } - const T* get() const{ return m_p; } + T* get() const{ return m_p; } T& operator*() const { return *m_p; } T* operator->() const { return m_p; } - bool operator !() const { return m_p == NULL; } - operator SafeBool::type() const { return SafeBool::makeSafe( m_p != NULL ); } + bool operator !() const { return m_p == CATCH_NULL; } + operator SafeBool::type() const { return SafeBool::makeSafe( m_p != CATCH_NULL ); } private: T* m_p; @@ -528,9 +590,13 @@ namespace Catch { struct ITestCaseRegistry { virtual ~ITestCaseRegistry(); virtual std::vector const& getAllTests() const = 0; - virtual void getFilteredTests( TestSpec const& testSpec, IConfig const& config, std::vector& matchingTestCases, bool negated = false ) const = 0; - + virtual std::vector const& getAllTestsSorted( IConfig const& config ) const = 0; }; + + bool matchTest( TestCase const& testCase, TestSpec const& testSpec, IConfig const& config ); + std::vector filterTests( std::vector const& testCases, TestSpec const& testSpec, IConfig const& config ); + std::vector const& getAllTestCasesSorted( IConfig const& config ); + } namespace Catch { @@ -563,27 +629,32 @@ struct NameAndDesc { const char* description; }; +void registerTestCase + ( ITestCase* testCase, + char const* className, + NameAndDesc const& nameAndDesc, + SourceLineInfo const& lineInfo ); + struct AutoReg { - AutoReg( TestFunction function, - SourceLineInfo const& lineInfo, - NameAndDesc const& nameAndDesc ); + AutoReg + ( TestFunction function, + SourceLineInfo const& lineInfo, + NameAndDesc const& nameAndDesc ); template - AutoReg( void (C::*method)(), - char const* className, - NameAndDesc const& nameAndDesc, - SourceLineInfo const& lineInfo ) { - registerTestCase( new MethodTestCase( method ), - className, - nameAndDesc, - lineInfo ); - } + AutoReg + ( void (C::*method)(), + char const* className, + NameAndDesc const& nameAndDesc, + SourceLineInfo const& lineInfo ) { - void registerTestCase( ITestCase* testCase, - char const* className, - NameAndDesc const& nameAndDesc, - SourceLineInfo const& lineInfo ); + registerTestCase + ( new MethodTestCase( method ), + className, + nameAndDesc, + lineInfo ); + } ~AutoReg(); @@ -592,6 +663,11 @@ private: void operator= ( AutoReg const& ); }; +void registerTestCaseFunction + ( TestFunction function, + SourceLineInfo const& lineInfo, + NameAndDesc const& nameAndDesc ); + } // end namespace Catch #ifdef CATCH_CONFIG_VARIADIC_MACROS @@ -615,6 +691,10 @@ private: } \ void INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_S_T____ )::test() + /////////////////////////////////////////////////////////////////////////////// + #define INTERNAL_CATCH_REGISTER_TESTCASE( Function, ... ) \ + Catch::AutoReg( Function, CATCH_INTERNAL_LINEINFO, Catch::NameAndDesc( __VA_ARGS__ ) ); + #else /////////////////////////////////////////////////////////////////////////////// #define INTERNAL_CATCH_TESTCASE( Name, Desc ) \ @@ -636,6 +716,9 @@ private: } \ void INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_S_T____ )::test() + /////////////////////////////////////////////////////////////////////////////// + #define INTERNAL_CATCH_REGISTER_TESTCASE( Function, Name, Desc ) \ + Catch::AutoReg( Function, CATCH_INTERNAL_LINEINFO, Catch::NameAndDesc( Name, Desc ) ); #endif // #included from: internal/catch_capture.hpp @@ -758,6 +841,323 @@ namespace Catch { } // end namespace Catch +// #included from: catch_matchers.hpp +#define TWOBLUECUBES_CATCH_MATCHERS_HPP_INCLUDED + +namespace Catch { +namespace Matchers { + namespace Impl { + + namespace Generic { + template class AllOf; + template class AnyOf; + template class Not; + } + + template + struct Matcher : SharedImpl + { + typedef ExpressionT ExpressionType; + + virtual ~Matcher() {} + virtual Ptr clone() const = 0; + virtual bool match( ExpressionT const& expr ) const = 0; + virtual std::string toString() const = 0; + + Generic::AllOf operator && ( Matcher const& other ) const; + Generic::AnyOf operator || ( Matcher const& other ) const; + Generic::Not operator ! () const; + }; + + template + struct MatcherImpl : Matcher { + + virtual Ptr > clone() const { + return Ptr >( new DerivedT( static_cast( *this ) ) ); + } + }; + + namespace Generic { + template + class Not : public MatcherImpl, ExpressionT> { + public: + explicit Not( Matcher const& matcher ) : m_matcher(matcher.clone()) {} + Not( Not const& other ) : m_matcher( other.m_matcher ) {} + + virtual bool match( ExpressionT const& expr ) const CATCH_OVERRIDE { + return !m_matcher->match( expr ); + } + + virtual std::string toString() const CATCH_OVERRIDE { + return "not " + m_matcher->toString(); + } + private: + Ptr< Matcher > m_matcher; + }; + + template + class AllOf : public MatcherImpl, ExpressionT> { + public: + + AllOf() {} + AllOf( AllOf const& other ) : m_matchers( other.m_matchers ) {} + + AllOf& add( Matcher const& matcher ) { + m_matchers.push_back( matcher.clone() ); + return *this; + } + virtual bool match( ExpressionT const& expr ) const + { + for( std::size_t i = 0; i < m_matchers.size(); ++i ) + if( !m_matchers[i]->match( expr ) ) + return false; + return true; + } + virtual std::string toString() const { + std::ostringstream oss; + oss << "( "; + for( std::size_t i = 0; i < m_matchers.size(); ++i ) { + if( i != 0 ) + oss << " and "; + oss << m_matchers[i]->toString(); + } + oss << " )"; + return oss.str(); + } + + AllOf operator && ( Matcher const& other ) const { + AllOf allOfExpr( *this ); + allOfExpr.add( other ); + return allOfExpr; + } + + private: + std::vector > > m_matchers; + }; + + template + class AnyOf : public MatcherImpl, ExpressionT> { + public: + + AnyOf() {} + AnyOf( AnyOf const& other ) : m_matchers( other.m_matchers ) {} + + AnyOf& add( Matcher const& matcher ) { + m_matchers.push_back( matcher.clone() ); + return *this; + } + virtual bool match( ExpressionT const& expr ) const + { + for( std::size_t i = 0; i < m_matchers.size(); ++i ) + if( m_matchers[i]->match( expr ) ) + return true; + return false; + } + virtual std::string toString() const { + std::ostringstream oss; + oss << "( "; + for( std::size_t i = 0; i < m_matchers.size(); ++i ) { + if( i != 0 ) + oss << " or "; + oss << m_matchers[i]->toString(); + } + oss << " )"; + return oss.str(); + } + + AnyOf operator || ( Matcher const& other ) const { + AnyOf anyOfExpr( *this ); + anyOfExpr.add( other ); + return anyOfExpr; + } + + private: + std::vector > > m_matchers; + }; + + } // namespace Generic + + template + Generic::AllOf Matcher::operator && ( Matcher const& other ) const { + Generic::AllOf allOfExpr; + allOfExpr.add( *this ); + allOfExpr.add( other ); + return allOfExpr; + } + + template + Generic::AnyOf Matcher::operator || ( Matcher const& other ) const { + Generic::AnyOf anyOfExpr; + anyOfExpr.add( *this ); + anyOfExpr.add( other ); + return anyOfExpr; + } + + template + Generic::Not Matcher::operator ! () const { + return Generic::Not( *this ); + } + + namespace StdString { + + inline std::string makeString( std::string const& str ) { return str; } + inline std::string makeString( const char* str ) { return str ? std::string( str ) : std::string(); } + + struct CasedString + { + CasedString( std::string const& str, CaseSensitive::Choice caseSensitivity ) + : m_caseSensitivity( caseSensitivity ), + m_str( adjustString( str ) ) + {} + std::string adjustString( std::string const& str ) const { + return m_caseSensitivity == CaseSensitive::No + ? toLower( str ) + : str; + + } + std::string toStringSuffix() const + { + return m_caseSensitivity == CaseSensitive::No + ? " (case insensitive)" + : ""; + } + CaseSensitive::Choice m_caseSensitivity; + std::string m_str; + }; + + struct Equals : MatcherImpl { + Equals( std::string const& str, CaseSensitive::Choice caseSensitivity = CaseSensitive::Yes ) + : m_data( str, caseSensitivity ) + {} + Equals( Equals const& other ) : m_data( other.m_data ){} + + virtual ~Equals(); + + virtual bool match( std::string const& expr ) const { + return m_data.m_str == m_data.adjustString( expr );; + } + virtual std::string toString() const { + return "equals: \"" + m_data.m_str + "\"" + m_data.toStringSuffix(); + } + + CasedString m_data; + }; + + struct Contains : MatcherImpl { + Contains( std::string const& substr, CaseSensitive::Choice caseSensitivity = CaseSensitive::Yes ) + : m_data( substr, caseSensitivity ){} + Contains( Contains const& other ) : m_data( other.m_data ){} + + virtual ~Contains(); + + virtual bool match( std::string const& expr ) const { + return m_data.adjustString( expr ).find( m_data.m_str ) != std::string::npos; + } + virtual std::string toString() const { + return "contains: \"" + m_data.m_str + "\"" + m_data.toStringSuffix(); + } + + CasedString m_data; + }; + + struct StartsWith : MatcherImpl { + StartsWith( std::string const& substr, CaseSensitive::Choice caseSensitivity = CaseSensitive::Yes ) + : m_data( substr, caseSensitivity ){} + + StartsWith( StartsWith const& other ) : m_data( other.m_data ){} + + virtual ~StartsWith(); + + virtual bool match( std::string const& expr ) const { + return m_data.adjustString( expr ).find( m_data.m_str ) == 0; + } + virtual std::string toString() const { + return "starts with: \"" + m_data.m_str + "\"" + m_data.toStringSuffix(); + } + + CasedString m_data; + }; + + struct EndsWith : MatcherImpl { + EndsWith( std::string const& substr, CaseSensitive::Choice caseSensitivity = CaseSensitive::Yes ) + : m_data( substr, caseSensitivity ){} + EndsWith( EndsWith const& other ) : m_data( other.m_data ){} + + virtual ~EndsWith(); + + virtual bool match( std::string const& expr ) const { + return m_data.adjustString( expr ).find( m_data.m_str ) == expr.size() - m_data.m_str.size(); + } + virtual std::string toString() const { + return "ends with: \"" + m_data.m_str + "\"" + m_data.toStringSuffix(); + } + + CasedString m_data; + }; + } // namespace StdString + } // namespace Impl + + // The following functions create the actual matcher objects. + // This allows the types to be inferred + template + inline Impl::Generic::Not Not( Impl::Matcher const& m ) { + return Impl::Generic::Not( m ); + } + + template + inline Impl::Generic::AllOf AllOf( Impl::Matcher const& m1, + Impl::Matcher const& m2 ) { + return Impl::Generic::AllOf().add( m1 ).add( m2 ); + } + template + inline Impl::Generic::AllOf AllOf( Impl::Matcher const& m1, + Impl::Matcher const& m2, + Impl::Matcher const& m3 ) { + return Impl::Generic::AllOf().add( m1 ).add( m2 ).add( m3 ); + } + template + inline Impl::Generic::AnyOf AnyOf( Impl::Matcher const& m1, + Impl::Matcher const& m2 ) { + return Impl::Generic::AnyOf().add( m1 ).add( m2 ); + } + template + inline Impl::Generic::AnyOf AnyOf( Impl::Matcher const& m1, + Impl::Matcher const& m2, + Impl::Matcher const& m3 ) { + return Impl::Generic::AnyOf().add( m1 ).add( m2 ).add( m3 ); + } + + inline Impl::StdString::Equals Equals( std::string const& str, CaseSensitive::Choice caseSensitivity = CaseSensitive::Yes ) { + return Impl::StdString::Equals( str, caseSensitivity ); + } + inline Impl::StdString::Equals Equals( const char* str, CaseSensitive::Choice caseSensitivity = CaseSensitive::Yes ) { + return Impl::StdString::Equals( Impl::StdString::makeString( str ), caseSensitivity ); + } + inline Impl::StdString::Contains Contains( std::string const& substr, CaseSensitive::Choice caseSensitivity = CaseSensitive::Yes ) { + return Impl::StdString::Contains( substr, caseSensitivity ); + } + inline Impl::StdString::Contains Contains( const char* substr, CaseSensitive::Choice caseSensitivity = CaseSensitive::Yes ) { + return Impl::StdString::Contains( Impl::StdString::makeString( substr ), caseSensitivity ); + } + inline Impl::StdString::StartsWith StartsWith( std::string const& substr ) { + return Impl::StdString::StartsWith( substr ); + } + inline Impl::StdString::StartsWith StartsWith( const char* substr ) { + return Impl::StdString::StartsWith( Impl::StdString::makeString( substr ) ); + } + inline Impl::StdString::EndsWith EndsWith( std::string const& substr ) { + return Impl::StdString::EndsWith( substr ); + } + inline Impl::StdString::EndsWith EndsWith( const char* substr ) { + return Impl::StdString::EndsWith( Impl::StdString::makeString( substr ) ); + } + +} // namespace Matchers + +using namespace Matchers; + +} // namespace Catch + namespace Catch { struct TestFailureException{}; @@ -784,7 +1184,8 @@ namespace Catch { ResultBuilder( char const* macroName, SourceLineInfo const& lineInfo, char const* capturedExpression, - ResultDisposition::Flags resultDisposition ); + ResultDisposition::Flags resultDisposition, + char const* secondArg = "" ); template ExpressionLhs operator <= ( T const& operand ); @@ -813,6 +1214,9 @@ namespace Catch { void useActiveException( ResultDisposition::Flags resultDisposition = ResultDisposition::Normal ); void captureResult( ResultWas::OfType resultType ); void captureExpression(); + void captureExpectedException( std::string const& expectedMessage ); + void captureExpectedException( Matchers::Impl::Matcher const& matcher ); + void handleResult( AssertionResult const& result ); void react(); bool shouldDebugBreak() const; bool allowThrows() const; @@ -991,13 +1395,51 @@ namespace Internal { return Evaluator::evaluate( lhs, reinterpret_cast( rhs ) ); } +#ifdef CATCH_CONFIG_CPP11_LONG_LONG + // long long to unsigned X + template bool compare( long long lhs, unsigned int rhs ) { + return applyEvaluator( static_cast( lhs ), rhs ); + } + template bool compare( long long lhs, unsigned long rhs ) { + return applyEvaluator( static_cast( lhs ), rhs ); + } + template bool compare( long long lhs, unsigned long long rhs ) { + return applyEvaluator( static_cast( lhs ), rhs ); + } + template bool compare( long long lhs, unsigned char rhs ) { + return applyEvaluator( static_cast( lhs ), rhs ); + } + + // unsigned long long to X + template bool compare( unsigned long long lhs, int rhs ) { + return applyEvaluator( static_cast( lhs ), rhs ); + } + template bool compare( unsigned long long lhs, long rhs ) { + return applyEvaluator( static_cast( lhs ), rhs ); + } + template bool compare( unsigned long long lhs, long long rhs ) { + return applyEvaluator( static_cast( lhs ), rhs ); + } + template bool compare( unsigned long long lhs, char rhs ) { + return applyEvaluator( static_cast( lhs ), rhs ); + } + + // pointer to long long (when comparing against NULL) + template bool compare( long long lhs, T* rhs ) { + return Evaluator::evaluate( reinterpret_cast( lhs ), rhs ); + } + template bool compare( T* lhs, long long rhs ) { + return Evaluator::evaluate( lhs, reinterpret_cast( rhs ) ); + } +#endif // CATCH_CONFIG_CPP11_LONG_LONG + #ifdef CATCH_CONFIG_CPP11_NULLPTR // pointer to nullptr_t (when comparing against nullptr) template bool compare( std::nullptr_t, T* rhs ) { - return Evaluator::evaluate( NULL, rhs ); + return Evaluator::evaluate( nullptr, rhs ); } template bool compare( T* lhs, std::nullptr_t ) { - return Evaluator::evaluate( lhs, NULL ); + return Evaluator::evaluate( lhs, nullptr ); } #endif // CATCH_CONFIG_CPP11_NULLPTR @@ -1095,6 +1537,11 @@ std::string toString( char value ); std::string toString( signed char value ); std::string toString( unsigned char value ); +#ifdef CATCH_CONFIG_CPP11_LONG_LONG +std::string toString( long long value ); +std::string toString( unsigned long long value ); +#endif + #ifdef CATCH_CONFIG_CPP11_NULLPTR std::string toString( std::nullptr_t ); #endif @@ -1107,7 +1554,7 @@ std::string toString( std::nullptr_t ); namespace Detail { - extern std::string unprintableString; + extern const std::string unprintableString; struct BorgType { template BorgType( T const& ); @@ -1190,7 +1637,7 @@ struct StringMaker { template static std::string convert( U* p ) { if( !p ) - return INTERNAL_CATCH_STRINGIFY( NULL ); + return "NULL"; else return Detail::rawMemoryToString( p ); } @@ -1200,7 +1647,7 @@ template struct StringMaker { static std::string convert( R C::* p ) { if( !p ) - return INTERNAL_CATCH_STRINGIFY( NULL ); + return "NULL"; else return Detail::rawMemoryToString( p ); } @@ -1472,6 +1919,7 @@ namespace Catch { class AssertionResult; struct AssertionInfo; struct SectionInfo; + struct SectionEndInfo; struct MessageInfo; class ScopedMessageBuilder; struct Counts; @@ -1483,7 +1931,8 @@ namespace Catch { virtual void assertionEnded( AssertionResult const& result ) = 0; virtual bool sectionStarted( SectionInfo const& sectionInfo, Counts& assertions ) = 0; - virtual void sectionEnded( SectionInfo const& name, Counts const& assertions, double _durationInSeconds ) = 0; + virtual void sectionEnded( SectionEndInfo const& endInfo ) = 0; + virtual void sectionEndedEarly( SectionEndInfo const& endInfo ) = 0; virtual void pushScopedMessage( MessageInfo const& message ) = 0; virtual void popScopedMessage( MessageInfo const& message ) = 0; @@ -1604,16 +2053,16 @@ namespace Catch { } while( Catch::alwaysFalse() ) /////////////////////////////////////////////////////////////////////////////// -#define INTERNAL_CATCH_THROWS( expr, resultDisposition, macroName ) \ +#define INTERNAL_CATCH_THROWS( expr, resultDisposition, matcher, macroName ) \ do { \ - Catch::ResultBuilder __catchResult( macroName, CATCH_INTERNAL_LINEINFO, #expr, resultDisposition ); \ + Catch::ResultBuilder __catchResult( macroName, CATCH_INTERNAL_LINEINFO, #expr, resultDisposition, #matcher ); \ if( __catchResult.allowThrows() ) \ try { \ expr; \ __catchResult.captureResult( Catch::ResultWas::DidntThrowException ); \ } \ catch( ... ) { \ - __catchResult.captureResult( Catch::ResultWas::Ok ); \ + __catchResult.captureExpectedException( matcher ); \ } \ else \ __catchResult.captureResult( Catch::ResultWas::Ok ); \ @@ -1668,12 +2117,12 @@ namespace Catch { do { \ Catch::ResultBuilder __catchResult( macroName, CATCH_INTERNAL_LINEINFO, #arg " " #matcher, resultDisposition ); \ try { \ - std::string matcherAsString = ::Catch::Matchers::matcher.toString(); \ + std::string matcherAsString = (matcher).toString(); \ __catchResult \ .setLhs( Catch::toString( arg ) ) \ .setRhs( matcherAsString == Catch::Detail::unprintableString ? #matcher : matcherAsString ) \ .setOp( "matches" ) \ - .setResultType( ::Catch::Matchers::matcher.match( arg ) ); \ + .setResultType( (matcher).match( arg ) ); \ __catchResult.captureExpression(); \ } catch( ... ) { \ __catchResult.useActiveException( resultDisposition | Catch::ResultDisposition::ContinueOnFailure ); \ @@ -1687,21 +2136,6 @@ namespace Catch { // #included from: catch_section_info.h #define TWOBLUECUBES_CATCH_SECTION_INFO_H_INCLUDED -namespace Catch { - - struct SectionInfo { - SectionInfo - ( SourceLineInfo const& _lineInfo, - std::string const& _name, - std::string const& _description = std::string() ); - - std::string name; - std::string description; - SourceLineInfo lineInfo; - }; - -} // end namespace Catch - // #included from: catch_totals.hpp #define TWOBLUECUBES_CATCH_TOTALS_HPP_INCLUDED @@ -1772,6 +2206,31 @@ namespace Catch { }; } +namespace Catch { + + struct SectionInfo { + SectionInfo + ( SourceLineInfo const& _lineInfo, + std::string const& _name, + std::string const& _description = std::string() ); + + std::string name; + std::string description; + SourceLineInfo lineInfo; + }; + + struct SectionEndInfo { + SectionEndInfo( SectionInfo const& _sectionInfo, Counts const& _prevAssertions, double _durationInSeconds ) + : sectionInfo( _sectionInfo ), prevAssertions( _prevAssertions ), durationInSeconds( _durationInSeconds ) + {} + + SectionInfo sectionInfo; + Counts prevAssertions; + double durationInSeconds; + }; + +} // end namespace Catch + // #included from: catch_timer.h #define TWOBLUECUBES_CATCH_TIMER_H_INCLUDED @@ -2012,6 +2471,8 @@ using namespace Generators; #define TWOBLUECUBES_CATCH_INTERFACES_EXCEPTION_H_INCLUDED #include +#include + // #included from: catch_interfaces_registry_hub.h #define TWOBLUECUBES_CATCH_INTERFACES_REGISTRY_HUB_H_INCLUDED @@ -2036,7 +2497,8 @@ namespace Catch { struct IMutableRegistryHub { virtual ~IMutableRegistryHub(); - virtual void registerReporter( std::string const& name, IReporterFactory* factory ) = 0; + virtual void registerReporter( std::string const& name, Ptr const& factory ) = 0; + virtual void registerListener( Ptr const& factory ) = 0; virtual void registerTest( TestCase const& testInfo ) = 0; virtual void registerTranslator( const IExceptionTranslator* translator ) = 0; }; @@ -2048,14 +2510,16 @@ namespace Catch { } - namespace Catch { typedef std::string(*exceptionTranslateFunction)(); + struct IExceptionTranslator; + typedef std::vector ExceptionTranslators; + struct IExceptionTranslator { virtual ~IExceptionTranslator(); - virtual std::string translate() const = 0; + virtual std::string translate( ExceptionTranslators::const_iterator it, ExceptionTranslators::const_iterator itEnd ) const = 0; }; struct IExceptionTranslatorRegistry { @@ -2073,9 +2537,12 @@ namespace Catch { : m_translateFunction( translateFunction ) {} - virtual std::string translate() const { + virtual std::string translate( ExceptionTranslators::const_iterator it, ExceptionTranslators::const_iterator itEnd ) const CATCH_OVERRIDE { try { - throw; + if( it == itEnd ) + throw; + else + return (*it)->translate( it+1, itEnd ); } catch( T& ex ) { return m_translateFunction( ex ); @@ -2182,231 +2649,6 @@ inline std::string toString( Detail::Approx const& value ) { } // end namespace Catch -// #included from: internal/catch_matchers.hpp -#define TWOBLUECUBES_CATCH_MATCHERS_HPP_INCLUDED - -namespace Catch { -namespace Matchers { - namespace Impl { - - template - struct Matcher : SharedImpl - { - typedef ExpressionT ExpressionType; - - virtual ~Matcher() {} - virtual Ptr clone() const = 0; - virtual bool match( ExpressionT const& expr ) const = 0; - virtual std::string toString() const = 0; - }; - - template - struct MatcherImpl : Matcher { - - virtual Ptr > clone() const { - return Ptr >( new DerivedT( static_cast( *this ) ) ); - } - }; - - namespace Generic { - - template - class AllOf : public MatcherImpl, ExpressionT> { - public: - - AllOf() {} - AllOf( AllOf const& other ) : m_matchers( other.m_matchers ) {} - - AllOf& add( Matcher const& matcher ) { - m_matchers.push_back( matcher.clone() ); - return *this; - } - virtual bool match( ExpressionT const& expr ) const - { - for( std::size_t i = 0; i < m_matchers.size(); ++i ) - if( !m_matchers[i]->match( expr ) ) - return false; - return true; - } - virtual std::string toString() const { - std::ostringstream oss; - oss << "( "; - for( std::size_t i = 0; i < m_matchers.size(); ++i ) { - if( i != 0 ) - oss << " and "; - oss << m_matchers[i]->toString(); - } - oss << " )"; - return oss.str(); - } - - private: - std::vector > > m_matchers; - }; - - template - class AnyOf : public MatcherImpl, ExpressionT> { - public: - - AnyOf() {} - AnyOf( AnyOf const& other ) : m_matchers( other.m_matchers ) {} - - AnyOf& add( Matcher const& matcher ) { - m_matchers.push_back( matcher.clone() ); - return *this; - } - virtual bool match( ExpressionT const& expr ) const - { - for( std::size_t i = 0; i < m_matchers.size(); ++i ) - if( m_matchers[i]->match( expr ) ) - return true; - return false; - } - virtual std::string toString() const { - std::ostringstream oss; - oss << "( "; - for( std::size_t i = 0; i < m_matchers.size(); ++i ) { - if( i != 0 ) - oss << " or "; - oss << m_matchers[i]->toString(); - } - oss << " )"; - return oss.str(); - } - - private: - std::vector > > m_matchers; - }; - - } - - namespace StdString { - - inline std::string makeString( std::string const& str ) { return str; } - inline std::string makeString( const char* str ) { return str ? std::string( str ) : std::string(); } - - struct Equals : MatcherImpl { - Equals( std::string const& str ) : m_str( str ){} - Equals( Equals const& other ) : m_str( other.m_str ){} - - virtual ~Equals(); - - virtual bool match( std::string const& expr ) const { - return m_str == expr; - } - virtual std::string toString() const { - return "equals: \"" + m_str + "\""; - } - - std::string m_str; - }; - - struct Contains : MatcherImpl { - Contains( std::string const& substr ) : m_substr( substr ){} - Contains( Contains const& other ) : m_substr( other.m_substr ){} - - virtual ~Contains(); - - virtual bool match( std::string const& expr ) const { - return expr.find( m_substr ) != std::string::npos; - } - virtual std::string toString() const { - return "contains: \"" + m_substr + "\""; - } - - std::string m_substr; - }; - - struct StartsWith : MatcherImpl { - StartsWith( std::string const& substr ) : m_substr( substr ){} - StartsWith( StartsWith const& other ) : m_substr( other.m_substr ){} - - virtual ~StartsWith(); - - virtual bool match( std::string const& expr ) const { - return expr.find( m_substr ) == 0; - } - virtual std::string toString() const { - return "starts with: \"" + m_substr + "\""; - } - - std::string m_substr; - }; - - struct EndsWith : MatcherImpl { - EndsWith( std::string const& substr ) : m_substr( substr ){} - EndsWith( EndsWith const& other ) : m_substr( other.m_substr ){} - - virtual ~EndsWith(); - - virtual bool match( std::string const& expr ) const { - return expr.find( m_substr ) == expr.size() - m_substr.size(); - } - virtual std::string toString() const { - return "ends with: \"" + m_substr + "\""; - } - - std::string m_substr; - }; - } // namespace StdString - } // namespace Impl - - // The following functions create the actual matcher objects. - // This allows the types to be inferred - template - inline Impl::Generic::AllOf AllOf( Impl::Matcher const& m1, - Impl::Matcher const& m2 ) { - return Impl::Generic::AllOf().add( m1 ).add( m2 ); - } - template - inline Impl::Generic::AllOf AllOf( Impl::Matcher const& m1, - Impl::Matcher const& m2, - Impl::Matcher const& m3 ) { - return Impl::Generic::AllOf().add( m1 ).add( m2 ).add( m3 ); - } - template - inline Impl::Generic::AnyOf AnyOf( Impl::Matcher const& m1, - Impl::Matcher const& m2 ) { - return Impl::Generic::AnyOf().add( m1 ).add( m2 ); - } - template - inline Impl::Generic::AnyOf AnyOf( Impl::Matcher const& m1, - Impl::Matcher const& m2, - Impl::Matcher const& m3 ) { - return Impl::Generic::AnyOf().add( m1 ).add( m2 ).add( m3 ); - } - - inline Impl::StdString::Equals Equals( std::string const& str ) { - return Impl::StdString::Equals( str ); - } - inline Impl::StdString::Equals Equals( const char* str ) { - return Impl::StdString::Equals( Impl::StdString::makeString( str ) ); - } - inline Impl::StdString::Contains Contains( std::string const& substr ) { - return Impl::StdString::Contains( substr ); - } - inline Impl::StdString::Contains Contains( const char* substr ) { - return Impl::StdString::Contains( Impl::StdString::makeString( substr ) ); - } - inline Impl::StdString::StartsWith StartsWith( std::string const& substr ) { - return Impl::StdString::StartsWith( substr ); - } - inline Impl::StdString::StartsWith StartsWith( const char* substr ) { - return Impl::StdString::StartsWith( Impl::StdString::makeString( substr ) ); - } - inline Impl::StdString::EndsWith EndsWith( std::string const& substr ) { - return Impl::StdString::EndsWith( substr ); - } - inline Impl::StdString::EndsWith EndsWith( const char* substr ) { - return Impl::StdString::EndsWith( Impl::StdString::makeString( substr ) ); - } - -} // namespace Matchers - -using namespace Matchers; - -} // namespace Catch - // #included from: internal/catch_interfaces_tag_alias_registry.h #define TWOBLUECUBES_CATCH_INTERFACES_TAG_ALIAS_REGISTRY_H_INCLUDED @@ -2440,12 +2682,12 @@ namespace Catch { template class Option { public: - Option() : nullableValue( NULL ) {} + Option() : nullableValue( CATCH_NULL ) {} Option( T const& _value ) : nullableValue( new( storage ) T( _value ) ) {} Option( Option const& _other ) - : nullableValue( _other ? new( storage ) T( *_other ) : NULL ) + : nullableValue( _other ? new( storage ) T( *_other ) : CATCH_NULL ) {} ~Option() { @@ -2469,7 +2711,7 @@ namespace Catch { void reset() { if( nullableValue ) nullableValue->~T(); - nullableValue = NULL; + nullableValue = CATCH_NULL; } T& operator*() { return *nullableValue; } @@ -2481,10 +2723,10 @@ namespace Catch { return nullableValue ? *nullableValue : defaultValue; } - bool some() const { return nullableValue != NULL; } - bool none() const { return nullableValue == NULL; } + bool some() const { return nullableValue != CATCH_NULL; } + bool none() const { return nullableValue == CATCH_NULL; } - bool operator !() const { return nullableValue == NULL; } + bool operator !() const { return nullableValue == CATCH_NULL; } operator SafeBool::type() const { return SafeBool::makeSafe( some() ); } @@ -2542,6 +2784,8 @@ namespace Catch { TestCaseInfo( TestCaseInfo const& other ); + friend void setTags( TestCaseInfo& testCaseInfo, std::set const& tags ); + bool isHidden() const; bool throws() const; bool okToFail() const; @@ -2654,7 +2898,7 @@ namespace Catch { inline size_t registerTestMethods() { size_t noTestMethods = 0; - int noClasses = objc_getClassList( NULL, 0 ); + int noClasses = objc_getClassList( CATCH_NULL, 0 ); Class* classes = (CATCH_UNSAFE_UNRETAINED Class *)malloc( sizeof(Class) * noClasses); objc_getClassList( classes, noClasses ); @@ -2796,7 +3040,7 @@ return @ desc; \ #pragma clang diagnostic ignored "-Wweak-vtables" #endif -// #included from: ../catch_runner.hpp +// #included from: ../catch_session.hpp #define TWOBLUECUBES_CATCH_RUNNER_HPP_INCLUDED // #included from: internal/catch_commandline.hpp @@ -2821,6 +3065,67 @@ return @ desc; \ #pragma clang diagnostic ignored "-Wpadded" #endif +// #included from: catch_wildcard_pattern.hpp +#define TWOBLUECUBES_CATCH_WILDCARD_PATTERN_HPP_INCLUDED + +namespace Catch +{ + class WildcardPattern { + enum WildcardPosition { + NoWildcard = 0, + WildcardAtStart = 1, + WildcardAtEnd = 2, + WildcardAtBothEnds = WildcardAtStart | WildcardAtEnd + }; + + public: + + WildcardPattern( std::string const& pattern, CaseSensitive::Choice caseSensitivity ) + : m_caseSensitivity( caseSensitivity ), + m_wildcard( NoWildcard ), + m_pattern( adjustCase( pattern ) ) + { + if( startsWith( m_pattern, "*" ) ) { + m_pattern = m_pattern.substr( 1 ); + m_wildcard = WildcardAtStart; + } + if( endsWith( m_pattern, "*" ) ) { + m_pattern = m_pattern.substr( 0, m_pattern.size()-1 ); + m_wildcard = static_cast( m_wildcard | WildcardAtEnd ); + } + } + virtual ~WildcardPattern(); + virtual bool matches( std::string const& str ) const { + switch( m_wildcard ) { + case NoWildcard: + return m_pattern == adjustCase( str ); + case WildcardAtStart: + return endsWith( adjustCase( str ), m_pattern ); + case WildcardAtEnd: + return startsWith( adjustCase( str ), m_pattern ); + case WildcardAtBothEnds: + return contains( adjustCase( str ), m_pattern ); + } + +#ifdef __clang__ +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wunreachable-code" +#endif + throw std::logic_error( "Unknown enum" ); +#ifdef __clang__ +#pragma clang diagnostic pop +#endif + } + private: + std::string adjustCase( std::string const& str ) const { + return m_caseSensitivity == CaseSensitive::No ? toLower( str ) : str; + } + CaseSensitive::Choice m_caseSensitivity; + WildcardPosition m_wildcard; + std::string m_pattern; + }; +} + #include #include @@ -2832,50 +3137,18 @@ namespace Catch { virtual bool matches( TestCaseInfo const& testCase ) const = 0; }; class NamePattern : public Pattern { - enum WildcardPosition { - NoWildcard = 0, - WildcardAtStart = 1, - WildcardAtEnd = 2, - WildcardAtBothEnds = WildcardAtStart | WildcardAtEnd - }; - public: - NamePattern( std::string const& name ) : m_name( toLower( name ) ), m_wildcard( NoWildcard ) { - if( startsWith( m_name, "*" ) ) { - m_name = m_name.substr( 1 ); - m_wildcard = WildcardAtStart; - } - if( endsWith( m_name, "*" ) ) { - m_name = m_name.substr( 0, m_name.size()-1 ); - m_wildcard = static_cast( m_wildcard | WildcardAtEnd ); - } - } + NamePattern( std::string const& name ) + : m_wildcardPattern( toLower( name ), CaseSensitive::No ) + {} virtual ~NamePattern(); virtual bool matches( TestCaseInfo const& testCase ) const { - switch( m_wildcard ) { - case NoWildcard: - return m_name == toLower( testCase.name ); - case WildcardAtStart: - return endsWith( toLower( testCase.name ), m_name ); - case WildcardAtEnd: - return startsWith( toLower( testCase.name ), m_name ); - case WildcardAtBothEnds: - return contains( toLower( testCase.name ), m_name ); - } - -#ifdef __clang__ -#pragma clang diagnostic push -#pragma clang diagnostic ignored "-Wunreachable-code" -#endif - throw std::logic_error( "Unknown enum" ); -#ifdef __clang__ -#pragma clang diagnostic pop -#endif + return m_wildcardPattern.matches( toLower( testCase.name ) ); } private: - std::string m_name; - WildcardPosition m_wildcard; + WildcardPattern m_wildcardPattern; }; + class TagPattern : public Pattern { public: TagPattern( std::string const& tag ) : m_tag( toLower( tag ) ) {} @@ -2886,6 +3159,7 @@ namespace Catch { private: std::string m_tag; }; + class ExcludedPattern : public Pattern { public: ExcludedPattern( Ptr const& underlyingPattern ) : m_underlyingPattern( underlyingPattern ) {} @@ -3083,28 +3357,62 @@ namespace Catch { // #included from: catch_stream.h #define TWOBLUECUBES_CATCH_STREAM_H_INCLUDED -#include +// #included from: catch_streambuf.h +#define TWOBLUECUBES_CATCH_STREAMBUF_H_INCLUDED -#ifdef __clang__ -#pragma clang diagnostic ignored "-Wpadded" -#endif +#include namespace Catch { - class Stream { + class StreamBufBase : public std::streambuf { public: - Stream(); - Stream( std::streambuf* _streamBuf, bool _isOwned ); - void release(); - - std::streambuf* streamBuf; - - private: - bool isOwned; + virtual ~StreamBufBase() CATCH_NOEXCEPT; }; +} + +#include +#include +#include + +namespace Catch { std::ostream& cout(); std::ostream& cerr(); + + struct IStream { + virtual ~IStream() CATCH_NOEXCEPT; + virtual std::ostream& stream() const = 0; + }; + + class FileStream : public IStream { + mutable std::ofstream m_ofs; + public: + FileStream( std::string const& filename ); + virtual ~FileStream() CATCH_NOEXCEPT; + public: // IStream + virtual std::ostream& stream() const CATCH_OVERRIDE; + }; + + class CoutStream : public IStream { + mutable std::ostream m_os; + public: + CoutStream(); + virtual ~CoutStream() CATCH_NOEXCEPT; + + public: // IStream + virtual std::ostream& stream() const CATCH_OVERRIDE; + }; + + class DebugOutStream : public IStream { + std::auto_ptr m_streamBuf; + mutable std::ostream m_os; + public: + DebugOutStream(); + virtual ~DebugOutStream() CATCH_NOEXCEPT; + + public: // IStream + virtual std::ostream& stream() const CATCH_OVERRIDE; + }; } #include @@ -3132,6 +3440,7 @@ namespace Catch { showHelp( false ), showInvisibles( false ), forceColour( false ), + filenamesAsTags( false ), abortAfter( -1 ), rngSeed( 0 ), verbosity( Verbosity::Normal ), @@ -3151,6 +3460,7 @@ namespace Catch { bool showHelp; bool showInvisibles; bool forceColour; + bool filenamesAsTags; int abortAfter; unsigned int rngSeed; @@ -3160,11 +3470,11 @@ namespace Catch { ShowDurations::OrNot showDurations; RunTests::InWhatOrder runOrder; - std::string reporterName; std::string outputFilename; std::string name; std::string processName; + std::vector reporterNames; std::vector testsOrTags; }; @@ -3176,12 +3486,11 @@ namespace Catch { public: Config() - : m_os( Catch::cout().rdbuf() ) {} Config( ConfigData const& data ) : m_data( data ), - m_os( Catch::cout().rdbuf() ) + m_stream( openStream() ) { if( !data.testsOrTags.empty() ) { TestSpecParser parser( ITagAliasRegistry::get() ); @@ -3192,12 +3501,6 @@ namespace Catch { } virtual ~Config() { - m_os.rdbuf( Catch::cout().rdbuf() ); - m_stream.release(); - } - - void setFilename( std::string const& filename ) { - m_data.outputFilename = filename; } std::string const& getFilename() const { @@ -3213,18 +3516,7 @@ namespace Catch { bool shouldDebugBreak() const { return m_data.shouldDebugBreak; } - void setStreamBuf( std::streambuf* buf ) { - m_os.rdbuf( buf ? buf : Catch::cout().rdbuf() ); - } - - void useStream( std::string const& streamName ) { - Stream stream = createStream( streamName ); - setStreamBuf( stream.streamBuf ); - m_stream.release(); - m_stream = stream; - } - - std::string getReporterName() const { return m_data.reporterName; } + std::vector getReporterNames() const { return m_data.reporterNames; } int abortAfter() const { return m_data.abortAfter; } @@ -3235,7 +3527,7 @@ namespace Catch { // IConfig interface virtual bool allowThrows() const { return !m_data.noThrow; } - virtual std::ostream& stream() const { return m_os; } + virtual std::ostream& stream() const { return m_stream->stream(); } virtual std::string name() const { return m_data.name.empty() ? m_data.processName : m_data.name; } virtual bool includeSuccessfulResults() const { return m_data.showSuccessfulTests; } virtual bool warnAboutMissingAssertions() const { return m_data.warnings & WarnAbout::NoAssertions; } @@ -3245,10 +3537,22 @@ namespace Catch { virtual bool forceColour() const { return m_data.forceColour; } private: + + IStream const* openStream() { + if( m_data.outputFilename.empty() ) + return new CoutStream(); + else if( m_data.outputFilename[0] == '%' ) { + if( m_data.outputFilename == "%debug" ) + return new DebugOutStream(); + else + throw std::domain_error( "Unrecognised stream: " + m_data.outputFilename ); + } + else + return new FileStream( m_data.outputFilename ); + } ConfigData m_data; - Stream m_stream; - mutable std::ostream m_os; + std::auto_ptr m_stream; TestSpec m_testSpec; }; @@ -3517,11 +3821,11 @@ namespace Clara { template class BoundArgFunction { public: - BoundArgFunction() : functionObj( NULL ) {} + BoundArgFunction() : functionObj( CATCH_NULL ) {} BoundArgFunction( IArgFunction* _functionObj ) : functionObj( _functionObj ) {} - BoundArgFunction( BoundArgFunction const& other ) : functionObj( other.functionObj ? other.functionObj->clone() : NULL ) {} + BoundArgFunction( BoundArgFunction const& other ) : functionObj( other.functionObj ? other.functionObj->clone() : CATCH_NULL ) {} BoundArgFunction& operator = ( BoundArgFunction const& other ) { - IArgFunction* newFunctionObj = other.functionObj ? other.functionObj->clone() : NULL; + IArgFunction* newFunctionObj = other.functionObj ? other.functionObj->clone() : CATCH_NULL; delete functionObj; functionObj = newFunctionObj; return *this; @@ -3537,7 +3841,7 @@ namespace Clara { bool takesArg() const { return functionObj->takesArg(); } bool isSet() const { - return functionObj != NULL; + return functionObj != CATCH_NULL; } private: IArgFunction* functionObj; @@ -3755,12 +4059,7 @@ namespace Clara { } }; - // NOTE: std::auto_ptr is deprecated in c++11/c++0x -#if defined(__cplusplus) && __cplusplus > 199711L - typedef std::unique_ptr ArgAutoPtr; -#else - typedef std::auto_ptr ArgAutoPtr; -#endif + typedef CATCH_AUTO_PTR( Arg ) ArgAutoPtr; friend void addOptName( Arg& arg, std::string const& optName ) { @@ -3836,8 +4135,8 @@ namespace Clara { m_arg->description = description; return *this; } - ArgBuilder& detail( std::string const& detail ) { - m_arg->detail = detail; + ArgBuilder& detail( std::string const& _detail ) { + m_arg->detail = _detail; return *this; } @@ -3920,14 +4219,14 @@ namespace Clara { maxWidth = (std::max)( maxWidth, it->commands().size() ); for( it = itBegin; it != itEnd; ++it ) { - Detail::Text usage( it->commands(), Detail::TextAttributes() + Detail::Text usageText( it->commands(), Detail::TextAttributes() .setWidth( maxWidth+indent ) .setIndent( indent ) ); Detail::Text desc( it->description, Detail::TextAttributes() .setWidth( width - maxWidth - 3 ) ); - for( std::size_t i = 0; i < (std::max)( usage.size(), desc.size() ); ++i ) { - std::string usageCol = i < usage.size() ? usage[i] : ""; + for( std::size_t i = 0; i < (std::max)( usageText.size(), desc.size() ); ++i ) { + std::string usageCol = i < usageText.size() ? usageText[i] : ""; os << usageCol; if( i < desc.size() && !desc[i].empty() ) @@ -4133,6 +4432,7 @@ namespace Catch { config.abortAfter = x; } inline void addTestOrTags( ConfigData& config, std::string const& _testSpec ) { config.testsOrTags.push_back( _testSpec ); } + inline void addReporterName( ConfigData& config, std::string const& _reporterName ) { config.reporterNames.push_back( _reporterName ); } inline void addWarning( ConfigData& config, std::string const& _warning ) { if( _warning == "NoAssertions" ) @@ -4226,7 +4526,7 @@ namespace Catch { cli["-r"]["--reporter"] // .placeholder( "name[:filename]" ) .describe( "reporter to use (defaults to console)" ) - .bind( &ConfigData::reporterName, "name" ); + .bind( &addReporterName, "name" ); cli["-n"]["--name"] .describe( "suite name" ) @@ -4263,6 +4563,10 @@ namespace Catch { .describe( "load test names to run from a file" ) .bind( &loadTestNamesFromFile, "filename" ); + cli["-#"]["--filenames-as-tags"] + .describe( "adds a tag for the filename" ) + .bind( &ConfigData::filenamesAsTags ); + // Less common commands which don't have a short form cli["--list-test-names-only"] .describe( "list all/matching test cases names only" ) @@ -4520,18 +4824,18 @@ namespace Catch { namespace Catch { struct ReporterConfig { - explicit ReporterConfig( Ptr const& _fullConfig ) + explicit ReporterConfig( Ptr const& _fullConfig ) : m_stream( &_fullConfig->stream() ), m_fullConfig( _fullConfig ) {} - ReporterConfig( Ptr const& _fullConfig, std::ostream& _stream ) + ReporterConfig( Ptr const& _fullConfig, std::ostream& _stream ) : m_stream( &_stream ), m_fullConfig( _fullConfig ) {} std::ostream& stream() const { return *m_stream; } - Ptr fullConfig() const { return m_fullConfig; } + Ptr fullConfig() const { return m_fullConfig; } private: std::ostream* m_stream; - Ptr m_fullConfig; + Ptr m_fullConfig; }; struct ReporterPreferences { @@ -4733,6 +5037,7 @@ namespace Catch // The return value indicates if the messages buffer should be cleared: virtual bool assertionEnded( AssertionStats const& assertionStats ) = 0; + virtual void sectionEnded( SectionStats const& sectionStats ) = 0; virtual void testCaseEnded( TestCaseStats const& testCaseStats ) = 0; virtual void testGroupEnded( TestGroupStats const& testGroupStats ) = 0; @@ -4741,20 +5046,24 @@ namespace Catch virtual void skipTest( TestCaseInfo const& testInfo ) = 0; }; - struct IReporterFactory { + struct IReporterFactory : IShared { virtual ~IReporterFactory(); virtual IStreamingReporter* create( ReporterConfig const& config ) const = 0; virtual std::string getDescription() const = 0; }; struct IReporterRegistry { - typedef std::map FactoryMap; + typedef std::map > FactoryMap; + typedef std::vector > Listeners; virtual ~IReporterRegistry(); - virtual IStreamingReporter* create( std::string const& name, Ptr const& config ) const = 0; + virtual IStreamingReporter* create( std::string const& name, Ptr const& config ) const = 0; virtual FactoryMap const& getFactories() const = 0; + virtual Listeners const& getListeners() const = 0; }; + Ptr addReporter( Ptr const& existingReporter, Ptr const& additionalReporter ); + } #include @@ -4777,8 +5086,7 @@ namespace Catch { nameAttr.setInitialIndent( 2 ).setIndent( 4 ); tagsAttr.setIndent( 6 ); - std::vector matchedTestCases; - getRegistryHub().getTestCaseRegistry().getFilteredTests( testSpec, config, matchedTestCases ); + std::vector matchedTestCases = filterTests( getAllTestCasesSorted( config ), testSpec, config ); for( std::vector::const_iterator it = matchedTestCases.begin(), itEnd = matchedTestCases.end(); it != itEnd; ++it ) { @@ -4806,8 +5114,7 @@ namespace Catch { if( !config.testSpec().hasFilters() ) testSpec = TestSpecParser( ITagAliasRegistry::get() ).parse( "*" ).testSpec(); std::size_t matchedTests = 0; - std::vector matchedTestCases; - getRegistryHub().getTestCaseRegistry().getFilteredTests( testSpec, config, matchedTestCases ); + std::vector matchedTestCases = filterTests( getAllTestCasesSorted( config ), testSpec, config ); for( std::vector::const_iterator it = matchedTestCases.begin(), itEnd = matchedTestCases.end(); it != itEnd; ++it ) { @@ -4847,8 +5154,7 @@ namespace Catch { std::map tagCounts; - std::vector matchedTestCases; - getRegistryHub().getTestCaseRegistry().getFilteredTests( testSpec, config, matchedTestCases ); + std::vector matchedTestCases = filterTests( getAllTestCasesSorted( config ), testSpec, config ); for( std::vector::const_iterator it = matchedTestCases.begin(), itEnd = matchedTestCases.end(); it != itEnd; ++it ) { @@ -4919,7 +5225,7 @@ namespace Catch { } // end namespace Catch -// #included from: internal/catch_runner_impl.hpp +// #included from: internal/catch_run_context.hpp #define TWOBLUECUBES_CATCH_RUNNER_IMPL_HPP_INCLUDED // #included from: catch_test_case_tracker.hpp @@ -4928,137 +5234,300 @@ namespace Catch { #include #include #include +#include namespace Catch { -namespace SectionTracking { +namespace TestCaseTracking { - class TrackedSection { + struct ITracker : SharedImpl<> { + virtual ~ITracker(); - typedef std::map TrackedSections; + // static queries + virtual std::string name() const = 0; + + // dynamic queries + virtual bool isComplete() const = 0; // Successfully completed or failed + virtual bool isSuccessfullyCompleted() const = 0; + virtual bool isOpen() const = 0; // Started but not complete + virtual bool hasChildren() const = 0; + + virtual ITracker& parent() = 0; + + // actions + virtual void close() = 0; // Successfully complete + virtual void fail() = 0; + virtual void markAsNeedingAnotherRun() = 0; + + virtual void addChild( Ptr const& child ) = 0; + virtual ITracker* findChild( std::string const& name ) = 0; + virtual void openChild() = 0; + }; + + class TrackerContext { - public: enum RunState { NotStarted, Executing, - ExecutingChildren, - Completed + CompletedCycle }; - TrackedSection( std::string const& name, TrackedSection* parent ) - : m_name( name ), m_runState( NotStarted ), m_parent( parent ) + Ptr m_rootTracker; + ITracker* m_currentTracker; + RunState m_runState; + + public: + + static TrackerContext& instance() { + static TrackerContext s_instance; + return s_instance; + } + + TrackerContext() + : m_currentTracker( CATCH_NULL ), + m_runState( NotStarted ) {} - RunState runState() const { return m_runState; } + ITracker& startRun(); - TrackedSection* findChild( std::string const& childName ); - TrackedSection* acquireChild( std::string const& childName ); - - void enter() { - if( m_runState == NotStarted ) - m_runState = Executing; + void endRun() { + m_rootTracker.reset(); + m_currentTracker = CATCH_NULL; + m_runState = NotStarted; } - void leave(); - TrackedSection* getParent() { - return m_parent; + void startCycle() { + m_currentTracker = m_rootTracker.get(); + m_runState = Executing; } - bool hasChildren() const { + void completeCycle() { + m_runState = CompletedCycle; + } + + bool completedCycle() const { + return m_runState == CompletedCycle; + } + ITracker& currentTracker() { + return *m_currentTracker; + } + void setCurrentTracker( ITracker* tracker ) { + m_currentTracker = tracker; + } + }; + + class TrackerBase : public ITracker { + protected: + enum CycleState { + NotStarted, + Executing, + ExecutingChildren, + NeedsAnotherRun, + CompletedSuccessfully, + Failed + }; + class TrackerHasName { + std::string m_name; + public: + TrackerHasName( std::string const& name ) : m_name( name ) {} + bool operator ()( Ptr const& tracker ) { + return tracker->name() == m_name; + } + }; + typedef std::vector > Children; + std::string m_name; + TrackerContext& m_ctx; + ITracker* m_parent; + Children m_children; + CycleState m_runState; + public: + TrackerBase( std::string const& name, TrackerContext& ctx, ITracker* parent ) + : m_name( name ), + m_ctx( ctx ), + m_parent( parent ), + m_runState( NotStarted ) + {} + virtual ~TrackerBase(); + + virtual std::string name() const CATCH_OVERRIDE { + return m_name; + } + virtual bool isComplete() const CATCH_OVERRIDE { + return m_runState == CompletedSuccessfully || m_runState == Failed; + } + virtual bool isSuccessfullyCompleted() const CATCH_OVERRIDE { + return m_runState == CompletedSuccessfully; + } + virtual bool isOpen() const CATCH_OVERRIDE { + return m_runState != NotStarted && !isComplete(); + } + virtual bool hasChildren() const CATCH_OVERRIDE { return !m_children.empty(); } - private: - std::string m_name; - RunState m_runState; - TrackedSections m_children; - TrackedSection* m_parent; - }; + virtual void addChild( Ptr const& child ) CATCH_OVERRIDE { + m_children.push_back( child ); + } - inline TrackedSection* TrackedSection::findChild( std::string const& childName ) { - TrackedSections::iterator it = m_children.find( childName ); - return it != m_children.end() - ? &it->second - : NULL; - } - inline TrackedSection* TrackedSection::acquireChild( std::string const& childName ) { - if( TrackedSection* child = findChild( childName ) ) - return child; - m_children.insert( std::make_pair( childName, TrackedSection( childName, this ) ) ); - return findChild( childName ); - } - inline void TrackedSection::leave() { - for( TrackedSections::const_iterator it = m_children.begin(), itEnd = m_children.end(); - it != itEnd; - ++it ) - if( it->second.runState() != Completed ) { + virtual ITracker* findChild( std::string const& name ) CATCH_OVERRIDE { + Children::const_iterator it = std::find_if( m_children.begin(), m_children.end(), TrackerHasName( name ) ); + return( it != m_children.end() ) + ? it->get() + : CATCH_NULL; + } + virtual ITracker& parent() CATCH_OVERRIDE { + assert( m_parent ); // Should always be non-null except for root + return *m_parent; + } + + virtual void openChild() CATCH_OVERRIDE { + if( m_runState != ExecutingChildren ) { m_runState = ExecutingChildren; - return; + if( m_parent ) + m_parent->openChild(); } - m_runState = Completed; - } - - class TestCaseTracker { - public: - TestCaseTracker( std::string const& testCaseName ) - : m_testCase( testCaseName, NULL ), - m_currentSection( &m_testCase ), - m_completedASectionThisRun( false ) - {} - - bool enterSection( std::string const& name ) { - TrackedSection* child = m_currentSection->acquireChild( name ); - if( m_completedASectionThisRun || child->runState() == TrackedSection::Completed ) - return false; - - m_currentSection = child; - m_currentSection->enter(); - return true; } - void leaveSection() { - m_currentSection->leave(); - m_currentSection = m_currentSection->getParent(); - assert( m_currentSection != NULL ); - m_completedASectionThisRun = true; + void open() { + m_runState = Executing; + moveToThis(); + if( m_parent ) + m_parent->openChild(); } - bool currentSectionHasChildren() const { - return m_currentSection->hasChildren(); - } - bool isCompleted() const { - return m_testCase.runState() == TrackedSection::Completed; - } + virtual void close() CATCH_OVERRIDE { - class Guard { - public: - Guard( TestCaseTracker& tracker ) : m_tracker( tracker ) { - m_tracker.enterTestCase(); + // Close any still open children (e.g. generators) + while( &m_ctx.currentTracker() != this ) + m_ctx.currentTracker().close(); + + switch( m_runState ) { + case NotStarted: + case CompletedSuccessfully: + case Failed: + throw std::logic_error( "Illogical state" ); + + case NeedsAnotherRun: + break;; + + case Executing: + m_runState = CompletedSuccessfully; + break; + case ExecutingChildren: + if( m_children.empty() || m_children.back()->isComplete() ) + m_runState = CompletedSuccessfully; + break; + + default: + throw std::logic_error( "Unexpected state" ); } - ~Guard() { - m_tracker.leaveTestCase(); - } - private: - Guard( Guard const& ); - void operator = ( Guard const& ); - TestCaseTracker& m_tracker; - }; - + moveToParent(); + m_ctx.completeCycle(); + } + virtual void fail() CATCH_OVERRIDE { + m_runState = Failed; + if( m_parent ) + m_parent->markAsNeedingAnotherRun(); + moveToParent(); + m_ctx.completeCycle(); + } + virtual void markAsNeedingAnotherRun() CATCH_OVERRIDE { + m_runState = NeedsAnotherRun; + } private: - void enterTestCase() { - m_currentSection = &m_testCase; - m_completedASectionThisRun = false; - m_testCase.enter(); + void moveToParent() { + assert( m_parent ); + m_ctx.setCurrentTracker( m_parent ); } - void leaveTestCase() { - m_testCase.leave(); + void moveToThis() { + m_ctx.setCurrentTracker( this ); } - - TrackedSection m_testCase; - TrackedSection* m_currentSection; - bool m_completedASectionThisRun; }; -} // namespace SectionTracking + class SectionTracker : public TrackerBase { + public: + SectionTracker( std::string const& name, TrackerContext& ctx, ITracker* parent ) + : TrackerBase( name, ctx, parent ) + {} + virtual ~SectionTracker(); -using SectionTracking::TestCaseTracker; + static SectionTracker& acquire( TrackerContext& ctx, std::string const& name ) { + SectionTracker* section = CATCH_NULL; + + ITracker& currentTracker = ctx.currentTracker(); + if( ITracker* childTracker = currentTracker.findChild( name ) ) { + section = dynamic_cast( childTracker ); + assert( section ); + } + else { + section = new SectionTracker( name, ctx, ¤tTracker ); + currentTracker.addChild( section ); + } + if( !ctx.completedCycle() && !section->isComplete() ) { + + section->open(); + } + return *section; + } + }; + + class IndexTracker : public TrackerBase { + int m_size; + int m_index; + public: + IndexTracker( std::string const& name, TrackerContext& ctx, ITracker* parent, int size ) + : TrackerBase( name, ctx, parent ), + m_size( size ), + m_index( -1 ) + {} + virtual ~IndexTracker(); + + static IndexTracker& acquire( TrackerContext& ctx, std::string const& name, int size ) { + IndexTracker* tracker = CATCH_NULL; + + ITracker& currentTracker = ctx.currentTracker(); + if( ITracker* childTracker = currentTracker.findChild( name ) ) { + tracker = dynamic_cast( childTracker ); + assert( tracker ); + } + else { + tracker = new IndexTracker( name, ctx, ¤tTracker, size ); + currentTracker.addChild( tracker ); + } + + if( !ctx.completedCycle() && !tracker->isComplete() ) { + if( tracker->m_runState != ExecutingChildren && tracker->m_runState != NeedsAnotherRun ) + tracker->moveNext(); + tracker->open(); + } + + return *tracker; + } + + int index() const { return m_index; } + + void moveNext() { + m_index++; + m_children.clear(); + } + + virtual void close() CATCH_OVERRIDE { + TrackerBase::close(); + if( m_runState == CompletedSuccessfully && m_index < m_size-1 ) + m_runState = Executing; + } + }; + + inline ITracker& TrackerContext::startRun() { + m_rootTracker = new SectionTracker( "{root}", *this, CATCH_NULL ); + m_currentTracker = CATCH_NULL; + m_runState = Executing; + return *m_rootTracker; + } + +} // namespace TestCaseTracking + +using TestCaseTracking::ITracker; +using TestCaseTracking::TrackerContext; +using TestCaseTracking::SectionTracker; +using TestCaseTracking::IndexTracker; } // namespace Catch @@ -5174,15 +5643,12 @@ namespace Catch { public: - explicit RunContext( Ptr const& config, Ptr const& reporter ) - : m_runInfo( config->name() ), + explicit RunContext( Ptr const& _config, Ptr const& reporter ) + : m_runInfo( _config->name() ), m_context( getCurrentMutableContext() ), - m_activeTestCase( NULL ), - m_config( config ), - m_reporter( reporter ), - m_prevRunner( m_context.getRunner() ), - m_prevResultCapture( m_context.getResultCapture() ), - m_prevConfig( m_context.getConfig() ) + m_activeTestCase( CATCH_NULL ), + m_config( _config ), + m_reporter( reporter ) { m_context.setRunner( this ); m_context.setConfig( m_config ); @@ -5192,10 +5658,6 @@ namespace Catch { virtual ~RunContext() { m_reporter->testRunEnded( TestRunStats( m_runInfo, m_totals, aborting() ) ); - m_context.setRunner( m_prevRunner ); - m_context.setConfig( NULL ); - m_context.setResultCapture( m_prevResultCapture ); - m_context.setConfig( m_prevConfig ); } void testGroupStarting( std::string const& testSpec, std::size_t groupIndex, std::size_t groupsCount ) { @@ -5216,14 +5678,17 @@ namespace Catch { m_reporter->testCaseStarting( testInfo ); m_activeTestCase = &testCase; - m_testCaseTracker = TestCaseTracker( testInfo.name ); do { + m_trackerContext.startRun(); do { + m_trackerContext.startCycle(); + m_testCaseTracker = &SectionTracker::acquire( m_trackerContext, testInfo.name ); runCurrentTest( redirectedCout, redirectedCerr ); } - while( !m_testCaseTracker->isCompleted() && !aborting() ); + while( !m_testCaseTracker->isSuccessfullyCompleted() && !aborting() ); } + // !TBD: deprecated - this will be replaced by indexed trackers while( getCurrentContext().advanceGeneratorsForCurrentTest() && !aborting() ); Totals deltaTotals = m_totals.delta( prevTotals ); @@ -5234,8 +5699,8 @@ namespace Catch { redirectedCerr, aborting() ) ); - m_activeTestCase = NULL; - m_testCaseTracker.reset(); + m_activeTestCase = CATCH_NULL; + m_testCaseTracker = CATCH_NULL; return deltaTotals; } @@ -5270,8 +5735,10 @@ namespace Catch { std::ostringstream oss; oss << sectionInfo.name << "@" << sectionInfo.lineInfo; - if( !m_testCaseTracker->enterSection( oss.str() ) ) + ITracker& sectionTracker = SectionTracker::acquire( m_trackerContext, oss.str() ); + if( !sectionTracker.isOpen() ) return false; + m_activeSections.push_back( §ionTracker ); m_lastAssertionInfo.lineInfo = sectionInfo.lineInfo; @@ -5282,30 +5749,40 @@ namespace Catch { return true; } bool testForMissingAssertions( Counts& assertions ) { - if( assertions.total() != 0 || - !m_config->warnAboutMissingAssertions() || - m_testCaseTracker->currentSectionHasChildren() ) + if( assertions.total() != 0 ) + return false; + if( !m_config->warnAboutMissingAssertions() ) + return false; + if( m_trackerContext.currentTracker().hasChildren() ) return false; m_totals.assertions.failed++; assertions.failed++; return true; } - virtual void sectionEnded( SectionInfo const& info, Counts const& prevAssertions, double _durationInSeconds ) { - if( std::uncaught_exception() ) { - m_unfinishedSections.push_back( UnfinishedSections( info, prevAssertions, _durationInSeconds ) ); - return; - } - - Counts assertions = m_totals.assertions - prevAssertions; + virtual void sectionEnded( SectionEndInfo const& endInfo ) { + Counts assertions = m_totals.assertions - endInfo.prevAssertions; bool missingAssertions = testForMissingAssertions( assertions ); - m_testCaseTracker->leaveSection(); + if( !m_activeSections.empty() ) { + m_activeSections.back()->close(); + m_activeSections.pop_back(); + } - m_reporter->sectionEnded( SectionStats( info, assertions, _durationInSeconds, missingAssertions ) ); + m_reporter->sectionEnded( SectionStats( endInfo.sectionInfo, assertions, endInfo.durationInSeconds, missingAssertions ) ); m_messages.clear(); } + virtual void sectionEndedEarly( SectionEndInfo const& endInfo ) { + if( m_unfinishedSections.empty() ) + m_activeSections.back()->fail(); + else + m_activeSections.back()->close(); + m_activeSections.pop_back(); + + m_unfinishedSections.push_back( endInfo ); + } + virtual void pushScopedMessage( MessageInfo const& message ) { m_messages.push_back( message ); } @@ -5371,7 +5848,8 @@ namespace Catch { double duration = 0; try { m_lastAssertionInfo = AssertionInfo( "TEST_CASE", testCaseInfo.lineInfo, "", ResultDisposition::Normal ); - TestCaseTracker::Guard guard( *m_testCaseTracker ); + + seedRng( *m_config ); Timer timer; timer.start(); @@ -5391,6 +5869,7 @@ namespace Catch { catch(...) { makeUnexpectedResultBuilder().useActiveException(); } + m_testCaseTracker->close(); handleUnfinishedSections(); m_messages.clear(); @@ -5425,39 +5904,29 @@ namespace Catch { void handleUnfinishedSections() { // If sections ended prematurely due to an exception we stored their // infos here so we can tear them down outside the unwind process. - for( std::vector::const_reverse_iterator it = m_unfinishedSections.rbegin(), + for( std::vector::const_reverse_iterator it = m_unfinishedSections.rbegin(), itEnd = m_unfinishedSections.rend(); it != itEnd; ++it ) - sectionEnded( it->info, it->prevAssertions, it->durationInSeconds ); + sectionEnded( *it ); m_unfinishedSections.clear(); } - struct UnfinishedSections { - UnfinishedSections( SectionInfo const& _info, Counts const& _prevAssertions, double _durationInSeconds ) - : info( _info ), prevAssertions( _prevAssertions ), durationInSeconds( _durationInSeconds ) - {} - - SectionInfo info; - Counts prevAssertions; - double durationInSeconds; - }; - TestRunInfo m_runInfo; IMutableContext& m_context; TestCase const* m_activeTestCase; - Option m_testCaseTracker; + ITracker* m_testCaseTracker; + ITracker* m_currentSectionTracker; AssertionResult m_lastResult; Ptr m_config; Totals m_totals; Ptr m_reporter; std::vector m_messages; - IRunner* m_prevRunner; - IResultCapture* m_prevResultCapture; - Ptr m_prevConfig; AssertionInfo m_lastAssertionInfo; - std::vector m_unfinishedSections; + std::vector m_unfinishedSections; + std::vector m_activeSections; + TrackerContext m_trackerContext; }; IResultCapture& getResultCapture() { @@ -5505,89 +5974,87 @@ namespace Catch { namespace Catch { - class Runner { + Ptr createReporter( std::string const& reporterName, Ptr const& config ) { + Ptr reporter = getRegistryHub().getReporterRegistry().create( reporterName, config.get() ); + if( !reporter ) { + std::ostringstream oss; + oss << "No reporter registered with name: '" << reporterName << "'"; + throw std::domain_error( oss.str() ); + } + return reporter; + } - public: - Runner( Ptr const& config ) - : m_config( config ) - { - openStream(); - makeReporter(); + Ptr makeReporter( Ptr const& config ) { + std::vector reporters = config->getReporterNames(); + if( reporters.empty() ) + reporters.push_back( "console" ); + + Ptr reporter; + for( std::vector::const_iterator it = reporters.begin(), itEnd = reporters.end(); + it != itEnd; + ++it ) + reporter = addReporter( reporter, createReporter( *it, config ) ); + return reporter; + } + Ptr addListeners( Ptr const& config, Ptr reporters ) { + IReporterRegistry::Listeners listeners = getRegistryHub().getReporterRegistry().getListeners(); + for( IReporterRegistry::Listeners::const_iterator it = listeners.begin(), itEnd = listeners.end(); + it != itEnd; + ++it ) + reporters = addReporter(reporters, (*it)->create( ReporterConfig( config ) ) ); + return reporters; + } + + Totals runTests( Ptr const& config ) { + + Ptr iconfig = config.get(); + + Ptr reporter = makeReporter( config ); + reporter = addListeners( iconfig, reporter ); + + RunContext context( iconfig, reporter ); + + Totals totals; + + context.testGroupStarting( config->name(), 1, 1 ); + + TestSpec testSpec = config->testSpec(); + if( !testSpec.hasFilters() ) + testSpec = TestSpecParser( ITagAliasRegistry::get() ).parse( "~[.]" ).testSpec(); // All not hidden tests + + std::vector const& allTestCases = getAllTestCasesSorted( *iconfig ); + for( std::vector::const_iterator it = allTestCases.begin(), itEnd = allTestCases.end(); + it != itEnd; + ++it ) { + if( !context.aborting() && matchTest( *it, testSpec, *iconfig ) ) + totals += context.runTest( *it ); + else + reporter->skipTest( *it ); } - Totals runTests() { + context.testGroupEnded( iconfig->name(), totals, 1, 1 ); + return totals; + } - RunContext context( m_config.get(), m_reporter ); + void applyFilenamesAsTags( IConfig const& config ) { + std::vector const& tests = getAllTestCasesSorted( config ); + for(std::size_t i = 0; i < tests.size(); ++i ) { + TestCase& test = const_cast( tests[i] ); + std::set tags = test.tags; - Totals totals; + std::string filename = test.lineInfo.file; + std::string::size_type lastSlash = filename.find_last_of( "\\/" ); + if( lastSlash != std::string::npos ) + filename = filename.substr( lastSlash+1 ); - context.testGroupStarting( "all tests", 1, 1 ); // deprecated? + std::string::size_type lastDot = filename.find_last_of( "." ); + if( lastDot != std::string::npos ) + filename = filename.substr( 0, lastDot ); - TestSpec testSpec = m_config->testSpec(); - if( !testSpec.hasFilters() ) - testSpec = TestSpecParser( ITagAliasRegistry::get() ).parse( "~[.]" ).testSpec(); // All not hidden tests - - std::vector testCases; - getRegistryHub().getTestCaseRegistry().getFilteredTests( testSpec, *m_config, testCases ); - - int testsRunForGroup = 0; - for( std::vector::const_iterator it = testCases.begin(), itEnd = testCases.end(); - it != itEnd; - ++it ) { - testsRunForGroup++; - if( m_testsAlreadyRun.find( *it ) == m_testsAlreadyRun.end() ) { - - if( context.aborting() ) - break; - - totals += context.runTest( *it ); - m_testsAlreadyRun.insert( *it ); - } - } - std::vector skippedTestCases; - getRegistryHub().getTestCaseRegistry().getFilteredTests( testSpec, *m_config, skippedTestCases, true ); - - for( std::vector::const_iterator it = skippedTestCases.begin(), itEnd = skippedTestCases.end(); - it != itEnd; - ++it ) - m_reporter->skipTest( *it ); - - context.testGroupEnded( "all tests", totals, 1, 1 ); - return totals; + tags.insert( "#" + filename ); + setTags( test, tags ); } - - private: - void openStream() { - // Open output file, if specified - if( !m_config->getFilename().empty() ) { - m_ofs.open( m_config->getFilename().c_str() ); - if( m_ofs.fail() ) { - std::ostringstream oss; - oss << "Unable to open file: '" << m_config->getFilename() << "'"; - throw std::domain_error( oss.str() ); - } - m_config->setStreamBuf( m_ofs.rdbuf() ); - } - } - void makeReporter() { - std::string reporterName = m_config->getReporterName().empty() - ? "console" - : m_config->getReporterName(); - - m_reporter = getRegistryHub().getReporterRegistry().create( reporterName, m_config.get() ); - if( !m_reporter ) { - std::ostringstream oss; - oss << "No reporter registered with name: '" << reporterName << "'"; - throw std::domain_error( oss.str() ); - } - } - - private: - Ptr m_config; - std::ofstream m_ofs; - Ptr m_reporter; - std::set m_testsAlreadyRun; - }; + } class Session : NonCopyable { static bool alreadyInstantiated; @@ -5616,7 +6083,7 @@ namespace Catch { Catch::cout() << "For more detail usage please see the project docs\n" << std::endl; } - int applyCommandLine( int argc, char* const argv[], OnUnusedOptions::DoWhat unusedOptionBehaviour = OnUnusedOptions::Fail ) { + int applyCommandLine( int argc, char const* const argv[], OnUnusedOptions::DoWhat unusedOptionBehaviour = OnUnusedOptions::Fail ) { try { m_cli.setThrowOnUnrecognisedTokens( unusedOptionBehaviour == OnUnusedOptions::Fail ); m_unusedTokens = m_cli.parseInto( argc, argv, m_configData ); @@ -5643,7 +6110,7 @@ namespace Catch { m_config.reset(); } - int run( int argc, char* const argv[] ) { + int run( int argc, char const* const argv[] ) { int returnCode = applyCommandLine( argc, argv ); if( returnCode == 0 ) @@ -5659,15 +6126,16 @@ namespace Catch { { config(); // Force config to be constructed - std::srand( m_configData.rngSeed ); + seedRng( *m_config ); - Runner runner( m_config ); + if( m_configData.filenamesAsTags ) + applyFilenamesAsTags( *m_config ); // Handle list request if( Option listed = list( config() ) ) return static_cast( *listed ); - return static_cast( runner.runTests().assertions.failed ); + return static_cast( runTests( m_config ).assertions.failed ); } catch( std::exception& ex ) { Catch::cerr() << ex.what() << std::endl; @@ -5689,7 +6157,6 @@ namespace Catch { m_config = new Config( m_configData ); return *m_config; } - private: Clara::CommandLine m_cli; std::vector m_unusedTokens; @@ -5715,16 +6182,76 @@ namespace Catch { namespace Catch { - class TestRegistry : public ITestCaseRegistry { - struct LexSort { - bool operator() (TestCase i,TestCase j) const { return (i sortTests( IConfig const& config, std::vector const& unsortedTestCases ) { + + std::vector sorted = unsortedTestCases; + + switch( config.runOrder() ) { + case RunTests::InLexicographicalOrder: + std::sort( sorted.begin(), sorted.end(), LexSort() ); + break; + case RunTests::InRandomOrder: + { + seedRng( config ); + + RandomNumberGenerator rng; + std::random_shuffle( sorted.begin(), sorted.end(), rng ); + } + break; + case RunTests::InDeclarationOrder: + // already in declaration order + break; + } + return sorted; + } + bool matchTest( TestCase const& testCase, TestSpec const& testSpec, IConfig const& config ) { + return testSpec.matches( testCase ) && ( config.allowThrows() || !testCase.throws() ); + } + + void enforceNoDuplicateTestCases( std::vector const& functions ) { + std::set seenFunctions; + for( std::vector::const_iterator it = functions.begin(), itEnd = functions.end(); + it != itEnd; + ++it ) { + std::pair::const_iterator, bool> prev = seenFunctions.insert( *it ); + if( !prev.second ){ + Catch::cerr() + << Colour( Colour::Red ) + << "error: TEST_CASE( \"" << it->name << "\" ) already defined.\n" + << "\tFirst seen at " << prev.first->getTestCaseInfo().lineInfo << "\n" + << "\tRedefined at " << it->getTestCaseInfo().lineInfo << std::endl; + exit(1); + } + } + } + + std::vector filterTests( std::vector const& testCases, TestSpec const& testSpec, IConfig const& config ) { + std::vector filtered; + filtered.reserve( testCases.size() ); + for( std::vector::const_iterator it = testCases.begin(), itEnd = testCases.end(); + it != itEnd; + ++it ) + if( matchTest( *it, testSpec, config ) ) + filtered.push_back( *it ); + return filtered; + } + std::vector const& getAllTestCasesSorted( IConfig const& config ) { + return getRegistryHub().getTestCaseRegistry().getAllTestsSorted( config ); + } + + class TestRegistry : public ITestCaseRegistry { public: - TestRegistry() : m_unnamedCount( 0 ) {} + TestRegistry() + : m_currentSortOrder( RunTests::InDeclarationOrder ), + m_unnamedCount( 0 ) + {} virtual ~TestRegistry(); virtual void registerTest( TestCase const& testCase ) { @@ -5734,69 +6261,29 @@ namespace Catch { oss << "Anonymous test case " << ++m_unnamedCount; return registerTest( testCase.withName( oss.str() ) ); } - - if( m_functions.find( testCase ) == m_functions.end() ) { - m_functions.insert( testCase ); - m_functionsInOrder.push_back( testCase ); - if( !testCase.isHidden() ) - m_nonHiddenFunctions.push_back( testCase ); - } - else { - TestCase const& prev = *m_functions.find( testCase ); - { - Colour colourGuard( Colour::Red ); - Catch::cerr() << "error: TEST_CASE( \"" << name << "\" ) already defined.\n" - << "\tFirst seen at " << prev.getTestCaseInfo().lineInfo << "\n" - << "\tRedefined at " << testCase.getTestCaseInfo().lineInfo << std::endl; - } - exit(1); - } + m_functions.push_back( testCase ); } virtual std::vector const& getAllTests() const { - return m_functionsInOrder; + return m_functions; } + virtual std::vector const& getAllTestsSorted( IConfig const& config ) const { + if( m_sortedFunctions.empty() ) + enforceNoDuplicateTestCases( m_functions ); - virtual std::vector const& getAllNonHiddenTests() const { - return m_nonHiddenFunctions; - } - - virtual void getFilteredTests( TestSpec const& testSpec, IConfig const& config, std::vector& matchingTestCases, bool negated = false ) const { - - for( std::vector::const_iterator it = m_functionsInOrder.begin(), - itEnd = m_functionsInOrder.end(); - it != itEnd; - ++it ) { - bool includeTest = testSpec.matches( *it ) && ( config.allowThrows() || !it->throws() ); - if( includeTest != negated ) - matchingTestCases.push_back( *it ); + if( m_currentSortOrder != config.runOrder() || m_sortedFunctions.empty() ) { + m_sortedFunctions = sortTests( config, m_functions ); + m_currentSortOrder = config.runOrder(); } - sortTests( config, matchingTestCases ); + return m_sortedFunctions; } private: - - static void sortTests( IConfig const& config, std::vector& matchingTestCases ) { - - switch( config.runOrder() ) { - case RunTests::InLexicographicalOrder: - std::sort( matchingTestCases.begin(), matchingTestCases.end(), LexSort() ); - break; - case RunTests::InRandomOrder: - { - RandomNumberGenerator rng; - std::random_shuffle( matchingTestCases.begin(), matchingTestCases.end(), rng ); - } - break; - case RunTests::InDeclarationOrder: - // already in declaration order - break; - } - } - std::set m_functions; - std::vector m_functionsInOrder; - std::vector m_nonHiddenFunctions; + std::vector m_functions; + mutable RunTests::InWhatOrder m_currentSortOrder; + mutable std::vector m_sortedFunctions; size_t m_unnamedCount; + std::ios_base::Init m_ostreamInit; // Forces cout/ cerr to be initialised }; /////////////////////////////////////////////////////////////////////////// @@ -5829,29 +6316,38 @@ namespace Catch { return className; } - /////////////////////////////////////////////////////////////////////////// + void registerTestCase + ( ITestCase* testCase, + char const* classOrQualifiedMethodName, + NameAndDesc const& nameAndDesc, + SourceLineInfo const& lineInfo ) { - AutoReg::AutoReg( TestFunction function, - SourceLineInfo const& lineInfo, - NameAndDesc const& nameAndDesc ) { + getMutableRegistryHub().registerTest + ( makeTestCase + ( testCase, + extractClassName( classOrQualifiedMethodName ), + nameAndDesc.name, + nameAndDesc.description, + lineInfo ) ); + } + void registerTestCaseFunction + ( TestFunction function, + SourceLineInfo const& lineInfo, + NameAndDesc const& nameAndDesc ) { registerTestCase( new FreeFunctionTestCase( function ), "", nameAndDesc, lineInfo ); } - AutoReg::~AutoReg() {} + /////////////////////////////////////////////////////////////////////////// - void AutoReg::registerTestCase( ITestCase* testCase, - char const* classOrQualifiedMethodName, - NameAndDesc const& nameAndDesc, - SourceLineInfo const& lineInfo ) { - - getMutableRegistryHub().registerTest - ( makeTestCase( testCase, - extractClassName( classOrQualifiedMethodName ), - nameAndDesc.name, - nameAndDesc.description, - lineInfo ) ); + AutoReg::AutoReg + ( TestFunction function, + SourceLineInfo const& lineInfo, + NameAndDesc const& nameAndDesc ) { + registerTestCaseFunction( function, lineInfo, nameAndDesc ); } + AutoReg::~AutoReg() {} + } // end namespace Catch // #included from: catch_reporter_registry.hpp @@ -5865,27 +6361,32 @@ namespace Catch { public: - virtual ~ReporterRegistry() { - deleteAllValues( m_factories ); - } + virtual ~ReporterRegistry() CATCH_OVERRIDE {} - virtual IStreamingReporter* create( std::string const& name, Ptr const& config ) const { + virtual IStreamingReporter* create( std::string const& name, Ptr const& config ) const CATCH_OVERRIDE { FactoryMap::const_iterator it = m_factories.find( name ); if( it == m_factories.end() ) - return NULL; + return CATCH_NULL; return it->second->create( ReporterConfig( config ) ); } - void registerReporter( std::string const& name, IReporterFactory* factory ) { + void registerReporter( std::string const& name, Ptr const& factory ) { m_factories.insert( std::make_pair( name, factory ) ); } + void registerListener( Ptr const& factory ) { + m_listeners.push_back( factory ); + } - FactoryMap const& getFactories() const { + virtual FactoryMap const& getFactories() const CATCH_OVERRIDE { return m_factories; } + virtual Listeners const& getListeners() const CATCH_OVERRIDE { + return m_listeners; + } private: FactoryMap m_factories; + Listeners m_listeners; }; } @@ -5913,13 +6414,13 @@ namespace Catch { #ifdef __OBJC__ // In Objective-C try objective-c exceptions first @try { - throw; + return tryTranslators(); } @catch (NSException *exception) { return Catch::toString( [exception description] ); } #else - throw; + return tryTranslators(); #endif } catch( TestFailureException& ) { @@ -5935,20 +6436,15 @@ namespace Catch { return msg; } catch(...) { - return tryTranslators( m_translators.begin() ); + return "Unknown exception"; } } - std::string tryTranslators( std::vector::const_iterator it ) const { - if( it == m_translators.end() ) - return "Unknown exception"; - - try { - return (*it)->translate(); - } - catch(...) { - return tryTranslators( it+1 ); - } + std::string tryTranslators() const { + if( m_translators.empty() ) + throw; + else + return m_translators[0]->translate( m_translators.begin()+1, m_translators.end() ); } private: @@ -5968,24 +6464,27 @@ namespace Catch { public: // IRegistryHub RegistryHub() { } - virtual IReporterRegistry const& getReporterRegistry() const { + virtual IReporterRegistry const& getReporterRegistry() const CATCH_OVERRIDE { return m_reporterRegistry; } - virtual ITestCaseRegistry const& getTestCaseRegistry() const { + virtual ITestCaseRegistry const& getTestCaseRegistry() const CATCH_OVERRIDE { return m_testCaseRegistry; } - virtual IExceptionTranslatorRegistry& getExceptionTranslatorRegistry() { + virtual IExceptionTranslatorRegistry& getExceptionTranslatorRegistry() CATCH_OVERRIDE { return m_exceptionTranslatorRegistry; } public: // IMutableRegistryHub - virtual void registerReporter( std::string const& name, IReporterFactory* factory ) { + virtual void registerReporter( std::string const& name, Ptr const& factory ) CATCH_OVERRIDE { m_reporterRegistry.registerReporter( name, factory ); } - virtual void registerTest( TestCase const& testInfo ) { + virtual void registerListener( Ptr const& factory ) CATCH_OVERRIDE { + m_reporterRegistry.registerListener( factory ); + } + virtual void registerTest( TestCase const& testInfo ) CATCH_OVERRIDE { m_testCaseRegistry.registerTest( testInfo ); } - virtual void registerTranslator( const IExceptionTranslator* translator ) { + virtual void registerTranslator( const IExceptionTranslator* translator ) CATCH_OVERRIDE { m_exceptionTranslatorRegistry.registerTranslator( translator ); } @@ -5997,7 +6496,7 @@ namespace Catch { // Single, global, instance inline RegistryHub*& getTheRegistryHub() { - static RegistryHub* theRegistryHub = NULL; + static RegistryHub* theRegistryHub = CATCH_NULL; if( !theRegistryHub ) theRegistryHub = new RegistryHub(); return theRegistryHub; @@ -6012,7 +6511,7 @@ namespace Catch { } void cleanUp() { delete getTheRegistryHub(); - getTheRegistryHub() = NULL; + getTheRegistryHub() = CATCH_NULL; cleanUpContext(); } std::string translateActiveException() { @@ -6048,19 +6547,6 @@ namespace Catch { // #included from: catch_stream.hpp #define TWOBLUECUBES_CATCH_STREAM_HPP_INCLUDED -// #included from: catch_streambuf.h -#define TWOBLUECUBES_CATCH_STREAMBUF_H_INCLUDED - -#include - -namespace Catch { - - class StreamBufBase : public std::streambuf { - public: - virtual ~StreamBufBase() CATCH_NOEXCEPT; - }; -} - #include #include #include @@ -6105,6 +6591,19 @@ namespace Catch { /////////////////////////////////////////////////////////////////////////// + FileStream::FileStream( std::string const& filename ) { + m_ofs.open( filename.c_str() ); + if( m_ofs.fail() ) { + std::ostringstream oss; + oss << "Unable to open file: '" << filename << "'"; + throw std::domain_error( oss.str() ); + } + } + + std::ostream& FileStream::stream() const { + return m_ofs; + } + struct OutputDebugWriter { void operator()( std::string const&str ) { @@ -6112,23 +6611,26 @@ namespace Catch { } }; - Stream::Stream() - : streamBuf( NULL ), isOwned( false ) + DebugOutStream::DebugOutStream() + : m_streamBuf( new StreamBufImpl() ), + m_os( m_streamBuf.get() ) {} - Stream::Stream( std::streambuf* _streamBuf, bool _isOwned ) - : streamBuf( _streamBuf ), isOwned( _isOwned ) - {} - - void Stream::release() { - if( isOwned ) { - delete streamBuf; - streamBuf = NULL; - isOwned = false; - } + std::ostream& DebugOutStream::stream() const { + return m_os; } -#ifndef CATCH_CONFIG_NOSTDOUT // If you #define this you must implement this functions + // Store the streambuf from cout up-front because + // cout may get redirected when running tests + CoutStream::CoutStream() + : m_os( Catch::cout().rdbuf() ) + {} + + std::ostream& CoutStream::stream() const { + return m_os; + } + +#ifndef CATCH_CONFIG_NOSTDOUT // If you #define this you must implement these functions std::ostream& cout() { return std::cout; } @@ -6142,7 +6644,7 @@ namespace Catch { class Context : public IMutableContext { - Context() : m_config( NULL ), m_runner( NULL ), m_resultCapture( NULL ) {} + Context() : m_config( CATCH_NULL ), m_runner( CATCH_NULL ), m_resultCapture( CATCH_NULL ) {} Context( Context const& ); void operator=( Context const& ); @@ -6188,7 +6690,7 @@ namespace Catch { m_generatorsByTestName.find( testName ); return it != m_generatorsByTestName.end() ? it->second - : NULL; + : CATCH_NULL; } IGeneratorsForTest& getGeneratorsForCurrentTest() { @@ -6209,7 +6711,7 @@ namespace Catch { }; namespace { - Context* currentContext = NULL; + Context* currentContext = CATCH_NULL; } IMutableContext& getCurrentMutableContext() { if( !currentContext ) @@ -6220,17 +6722,9 @@ namespace Catch { return getCurrentMutableContext(); } - Stream createStream( std::string const& streamName ) { - if( streamName == "stdout" ) return Stream( Catch::cout().rdbuf(), false ); - if( streamName == "stderr" ) return Stream( Catch::cerr().rdbuf(), false ); - if( streamName == "debug" ) return Stream( new StreamBufImpl, true ); - - throw std::domain_error( "Unknown stream: " + streamName ); - } - void cleanUpContext() { delete currentContext; - currentContext = NULL; + currentContext = CATCH_NULL; } } @@ -6286,12 +6780,13 @@ namespace { { CONSOLE_SCREEN_BUFFER_INFO csbiInfo; GetConsoleScreenBufferInfo( stdoutHandle, &csbiInfo ); - originalAttributes = csbiInfo.wAttributes; + originalForegroundAttributes = csbiInfo.wAttributes & ~( BACKGROUND_GREEN | BACKGROUND_RED | BACKGROUND_BLUE | BACKGROUND_INTENSITY ); + originalBackgroundAttributes = csbiInfo.wAttributes & ~( FOREGROUND_GREEN | FOREGROUND_RED | FOREGROUND_BLUE | FOREGROUND_INTENSITY ); } virtual void use( Colour::Code _colourCode ) { switch( _colourCode ) { - case Colour::None: return setTextAttribute( originalAttributes ); + case Colour::None: return setTextAttribute( originalForegroundAttributes ); case Colour::White: return setTextAttribute( FOREGROUND_GREEN | FOREGROUND_RED | FOREGROUND_BLUE ); case Colour::Red: return setTextAttribute( FOREGROUND_RED ); case Colour::Green: return setTextAttribute( FOREGROUND_GREEN ); @@ -6311,10 +6806,11 @@ namespace { private: void setTextAttribute( WORD _textAttribute ) { - SetConsoleTextAttribute( stdoutHandle, _textAttribute ); + SetConsoleTextAttribute( stdoutHandle, _textAttribute | originalBackgroundAttributes ); } HANDLE stdoutHandle; - WORD originalAttributes; + WORD originalForegroundAttributes; + WORD originalBackgroundAttributes; }; IColourImpl* platformColourInstance() { @@ -6640,6 +7136,21 @@ namespace Catch { return TestCase( _testCase, info ); } + void setTags( TestCaseInfo& testCaseInfo, std::set const& tags ) + { + testCaseInfo.tags = tags; + testCaseInfo.lcaseTags.clear(); + + std::ostringstream oss; + for( std::set::const_iterator it = tags.begin(), itEnd = tags.end(); it != itEnd; ++it ) { + oss << "[" << *it << "]"; + std::string lcaseTag = toLower( *it ); + testCaseInfo.properties = static_cast( testCaseInfo.properties | parseSpecialTag( lcaseTag ) ); + testCaseInfo.lcaseTags.insert( lcaseTag ); + } + testCaseInfo.tagsAsString = oss.str(); + } + TestCaseInfo::TestCaseInfo( std::string const& _name, std::string const& _className, std::string const& _description, @@ -6648,18 +7159,10 @@ namespace Catch { : name( _name ), className( _className ), description( _description ), - tags( _tags ), lineInfo( _lineInfo ), properties( None ) { - std::ostringstream oss; - for( std::set::const_iterator it = _tags.begin(), itEnd = _tags.end(); it != itEnd; ++it ) { - oss << "[" << *it << "]"; - std::string lcaseTag = toLower( *it ); - properties = static_cast( properties | parseSpecialTag( lcaseTag ) ); - lcaseTags.insert( lcaseTag ); - } - tagsAsString = oss.str(); + setTags( *this, _tags ); } TestCaseInfo::TestCaseInfo( TestCaseInfo const& other ) @@ -6767,7 +7270,7 @@ namespace Catch { return os; } - Version libraryVersion( 1, 2, 1, "", 0 ); + Version libraryVersion( 1, 3, 1, "", 0 ); } @@ -6960,7 +7463,7 @@ namespace Catch { #else uint64_t getCurrentTicks() { timeval t; - gettimeofday(&t,NULL); + gettimeofday(&t,CATCH_NULL); return static_cast( t.tv_sec ) * 1000000ull + static_cast( t.tv_usec ); } #endif @@ -7059,6 +7562,14 @@ namespace Catch { return line < other.line || ( line == other.line && file < other.file ); } + void seedRng( IConfig const& config ) { + if( config.rngSeed() != 0 ) + std::srand( config.rngSeed() ); + } + unsigned int rngSeed() { + return getCurrentContext().getConfig()->rngSeed(); + } + std::ostream& operator << ( std::ostream& os, SourceLineInfo const& info ) { #ifndef __GNUG__ os << info.file << "(" << info.line << ")"; @@ -7098,8 +7609,13 @@ namespace Catch { } Section::~Section() { - if( m_sectionIncluded ) - getResultCapture().sectionEnded( m_info, m_assertions, m_timer.getElapsedSeconds() ); + if( m_sectionIncluded ) { + SectionEndInfo endInfo( m_info, m_assertions, m_timer.getElapsedSeconds() ); + if( std::uncaught_exception() ) + getResultCapture().sectionEndedEarly( endInfo ); + else + getResultCapture().sectionEnded( endInfo ); + } } // This indicates whether the section should be executed or not @@ -7151,7 +7667,7 @@ namespace Catch { // Call sysctl. size = sizeof(info); - if( sysctl(mib, sizeof(mib) / sizeof(*mib), &info, &size, NULL, 0) != 0 ) { + if( sysctl(mib, sizeof(mib) / sizeof(*mib), &info, &size, CATCH_NULL, 0) != 0 ) { Catch::cerr() << "\n** Call to sysctl failed - unable to determine if debugger is active **\n" << std::endl; return false; } @@ -7205,9 +7721,11 @@ namespace Catch { namespace Detail { - std::string unprintableString = "{?}"; + const std::string unprintableString = "{?}"; namespace { + const int hexThreshold = 255; + struct Endianness { enum Arch { Big, Little }; @@ -7289,7 +7807,7 @@ std::string toString( wchar_t* const value ) std::string toString( int value ) { std::ostringstream oss; oss << value; - if( value >= 255 ) + if( value > Detail::hexThreshold ) oss << " (0x" << std::hex << value << ")"; return oss.str(); } @@ -7297,7 +7815,7 @@ std::string toString( int value ) { std::string toString( unsigned long value ) { std::ostringstream oss; oss << value; - if( value >= 255 ) + if( value > Detail::hexThreshold ) oss << " (0x" << std::hex << value << ")"; return oss.str(); } @@ -7347,6 +7865,23 @@ std::string toString( unsigned char value ) { return toString( static_cast( value ) ); } +#ifdef CATCH_CONFIG_CPP11_LONG_LONG +std::string toString( long long value ) { + std::ostringstream oss; + oss << value; + if( value > Detail::hexThreshold ) + oss << " (0x" << std::hex << value << ")"; + return oss.str(); +} +std::string toString( unsigned long long value ) { + std::ostringstream oss; + oss << value; + if( value > Detail::hexThreshold ) + oss << " (0x" << std::hex << value << ")"; + return oss.str(); +} +#endif + #ifdef CATCH_CONFIG_CPP11_NULLPTR std::string toString( std::nullptr_t ) { return "nullptr"; @@ -7376,11 +7911,17 @@ std::string toString( std::nullptr_t ) { namespace Catch { + std::string capturedExpressionWithSecondArgument( std::string const& capturedExpression, std::string const& secondArg ) { + return secondArg.empty() || secondArg == "\"\"" + ? capturedExpression + : capturedExpression + ", " + secondArg; + } ResultBuilder::ResultBuilder( char const* macroName, SourceLineInfo const& lineInfo, char const* capturedExpression, - ResultDisposition::Flags resultDisposition ) - : m_assertionInfo( macroName, lineInfo, capturedExpression, resultDisposition ), + ResultDisposition::Flags resultDisposition, + char const* secondArg ) + : m_assertionInfo( macroName, lineInfo, capturedExpressionWithSecondArgument( capturedExpression, secondArg ), resultDisposition ), m_shouldDebugBreak( false ), m_shouldThrow( false ) {} @@ -7421,9 +7962,35 @@ namespace Catch { setResultType( resultType ); captureExpression(); } + void ResultBuilder::captureExpectedException( std::string const& expectedMessage ) { + if( expectedMessage.empty() ) + captureExpectedException( Matchers::Impl::Generic::AllOf() ); + else + captureExpectedException( Matchers::Equals( expectedMessage ) ); + } + + void ResultBuilder::captureExpectedException( Matchers::Impl::Matcher const& matcher ) { + + assert( m_exprComponents.testFalse == false ); + AssertionResultData data = m_data; + data.resultType = ResultWas::Ok; + data.reconstructedExpression = m_assertionInfo.capturedExpression; + + std::string actualMessage = Catch::translateActiveException(); + if( !matcher.match( actualMessage ) ) { + data.resultType = ResultWas::ExpressionFailed; + data.reconstructedExpression = actualMessage; + } + AssertionResult result( m_assertionInfo, data ); + handleResult( result ); + } void ResultBuilder::captureExpression() { AssertionResult result = build(); + handleResult( result ); + } + void ResultBuilder::handleResult( AssertionResult const& result ) + { getResultCapture().assertionEnded( result ); if( !result.isOk() ) { @@ -7576,6 +8143,137 @@ namespace Catch { } // end namespace Catch +// #included from: ../reporters/catch_reporter_multi.hpp +#define TWOBLUECUBES_CATCH_REPORTER_MULTI_HPP_INCLUDED + +namespace Catch { + +class MultipleReporters : public SharedImpl { + typedef std::vector > Reporters; + Reporters m_reporters; + +public: + void add( Ptr const& reporter ) { + m_reporters.push_back( reporter ); + } + +public: // IStreamingReporter + + virtual ReporterPreferences getPreferences() const CATCH_OVERRIDE { + return m_reporters[0]->getPreferences(); + } + + virtual void noMatchingTestCases( std::string const& spec ) CATCH_OVERRIDE { + for( Reporters::const_iterator it = m_reporters.begin(), itEnd = m_reporters.end(); + it != itEnd; + ++it ) + (*it)->noMatchingTestCases( spec ); + } + + virtual void testRunStarting( TestRunInfo const& testRunInfo ) CATCH_OVERRIDE { + for( Reporters::const_iterator it = m_reporters.begin(), itEnd = m_reporters.end(); + it != itEnd; + ++it ) + (*it)->testRunStarting( testRunInfo ); + } + + virtual void testGroupStarting( GroupInfo const& groupInfo ) CATCH_OVERRIDE { + for( Reporters::const_iterator it = m_reporters.begin(), itEnd = m_reporters.end(); + it != itEnd; + ++it ) + (*it)->testGroupStarting( groupInfo ); + } + + virtual void testCaseStarting( TestCaseInfo const& testInfo ) CATCH_OVERRIDE { + for( Reporters::const_iterator it = m_reporters.begin(), itEnd = m_reporters.end(); + it != itEnd; + ++it ) + (*it)->testCaseStarting( testInfo ); + } + + virtual void sectionStarting( SectionInfo const& sectionInfo ) CATCH_OVERRIDE { + for( Reporters::const_iterator it = m_reporters.begin(), itEnd = m_reporters.end(); + it != itEnd; + ++it ) + (*it)->sectionStarting( sectionInfo ); + } + + virtual void assertionStarting( AssertionInfo const& assertionInfo ) CATCH_OVERRIDE { + for( Reporters::const_iterator it = m_reporters.begin(), itEnd = m_reporters.end(); + it != itEnd; + ++it ) + (*it)->assertionStarting( assertionInfo ); + } + + // The return value indicates if the messages buffer should be cleared: + virtual bool assertionEnded( AssertionStats const& assertionStats ) CATCH_OVERRIDE { + bool clearBuffer = false; + for( Reporters::const_iterator it = m_reporters.begin(), itEnd = m_reporters.end(); + it != itEnd; + ++it ) + clearBuffer |= (*it)->assertionEnded( assertionStats ); + return clearBuffer; + } + + virtual void sectionEnded( SectionStats const& sectionStats ) CATCH_OVERRIDE { + for( Reporters::const_iterator it = m_reporters.begin(), itEnd = m_reporters.end(); + it != itEnd; + ++it ) + (*it)->sectionEnded( sectionStats ); + } + + virtual void testCaseEnded( TestCaseStats const& testCaseStats ) CATCH_OVERRIDE { + for( Reporters::const_iterator it = m_reporters.begin(), itEnd = m_reporters.end(); + it != itEnd; + ++it ) + (*it)->testCaseEnded( testCaseStats ); + } + + virtual void testGroupEnded( TestGroupStats const& testGroupStats ) CATCH_OVERRIDE { + for( Reporters::const_iterator it = m_reporters.begin(), itEnd = m_reporters.end(); + it != itEnd; + ++it ) + (*it)->testGroupEnded( testGroupStats ); + } + + virtual void testRunEnded( TestRunStats const& testRunStats ) CATCH_OVERRIDE { + for( Reporters::const_iterator it = m_reporters.begin(), itEnd = m_reporters.end(); + it != itEnd; + ++it ) + (*it)->testRunEnded( testRunStats ); + } + + virtual void skipTest( TestCaseInfo const& testInfo ) CATCH_OVERRIDE { + for( Reporters::const_iterator it = m_reporters.begin(), itEnd = m_reporters.end(); + it != itEnd; + ++it ) + (*it)->skipTest( testInfo ); + } +}; + +Ptr addReporter( Ptr const& existingReporter, Ptr const& additionalReporter ) { + Ptr resultingReporter; + + if( existingReporter ) { + MultipleReporters* multi = dynamic_cast( existingReporter.get() ); + if( !multi ) { + multi = new MultipleReporters; + resultingReporter = Ptr( multi ); + if( existingReporter ) + multi->add( existingReporter ); + } + else + resultingReporter = existingReporter; + multi->add( additionalReporter ); + } + else + resultingReporter = additionalReporter; + + return resultingReporter; +} + +} // end namespace Catch + // #included from: ../reporters/catch_reporter_xml.hpp #define TWOBLUECUBES_CATCH_REPORTER_XML_HPP_INCLUDED @@ -7591,47 +8289,53 @@ namespace Catch { StreamingReporterBase( ReporterConfig const& _config ) : m_config( _config.fullConfig() ), stream( _config.stream() ) - {} + { + m_reporterPrefs.shouldRedirectStdOut = false; + } - virtual ~StreamingReporterBase(); + virtual ReporterPreferences getPreferences() const CATCH_OVERRIDE { + return m_reporterPrefs; + } - virtual void noMatchingTestCases( std::string const& ) {} + virtual ~StreamingReporterBase() CATCH_OVERRIDE; - virtual void testRunStarting( TestRunInfo const& _testRunInfo ) { + virtual void noMatchingTestCases( std::string const& ) CATCH_OVERRIDE {} + + virtual void testRunStarting( TestRunInfo const& _testRunInfo ) CATCH_OVERRIDE { currentTestRunInfo = _testRunInfo; } - virtual void testGroupStarting( GroupInfo const& _groupInfo ) { + virtual void testGroupStarting( GroupInfo const& _groupInfo ) CATCH_OVERRIDE { currentGroupInfo = _groupInfo; } - virtual void testCaseStarting( TestCaseInfo const& _testInfo ) { + virtual void testCaseStarting( TestCaseInfo const& _testInfo ) CATCH_OVERRIDE { currentTestCaseInfo = _testInfo; } - virtual void sectionStarting( SectionInfo const& _sectionInfo ) { + virtual void sectionStarting( SectionInfo const& _sectionInfo ) CATCH_OVERRIDE { m_sectionStack.push_back( _sectionInfo ); } - virtual void sectionEnded( SectionStats const& /* _sectionStats */ ) { + virtual void sectionEnded( SectionStats const& /* _sectionStats */ ) CATCH_OVERRIDE { m_sectionStack.pop_back(); } - virtual void testCaseEnded( TestCaseStats const& /* _testCaseStats */ ) { + virtual void testCaseEnded( TestCaseStats const& /* _testCaseStats */ ) CATCH_OVERRIDE { currentTestCaseInfo.reset(); } - virtual void testGroupEnded( TestGroupStats const& /* _testGroupStats */ ) { + virtual void testGroupEnded( TestGroupStats const& /* _testGroupStats */ ) CATCH_OVERRIDE { currentGroupInfo.reset(); } - virtual void testRunEnded( TestRunStats const& /* _testRunStats */ ) { + virtual void testRunEnded( TestRunStats const& /* _testRunStats */ ) CATCH_OVERRIDE { currentTestCaseInfo.reset(); currentGroupInfo.reset(); currentTestRunInfo.reset(); } - virtual void skipTest( TestCaseInfo const& ) { + virtual void skipTest( TestCaseInfo const& ) CATCH_OVERRIDE { // Don't do anything with this by default. // It can optionally be overridden in the derived class. } - Ptr m_config; + Ptr m_config; std::ostream& stream; LazyStat currentTestRunInfo; @@ -7639,6 +8343,7 @@ namespace Catch { LazyStat currentTestCaseInfo; std::vector m_sectionStack; + ReporterPreferences m_reporterPrefs; }; struct CumulativeReporterBase : SharedImpl { @@ -7689,15 +8394,21 @@ namespace Catch { CumulativeReporterBase( ReporterConfig const& _config ) : m_config( _config.fullConfig() ), stream( _config.stream() ) - {} + { + m_reporterPrefs.shouldRedirectStdOut = false; + } ~CumulativeReporterBase(); - virtual void testRunStarting( TestRunInfo const& ) {} - virtual void testGroupStarting( GroupInfo const& ) {} + virtual ReporterPreferences getPreferences() const CATCH_OVERRIDE { + return m_reporterPrefs; + } - virtual void testCaseStarting( TestCaseInfo const& ) {} + virtual void testRunStarting( TestRunInfo const& ) CATCH_OVERRIDE {} + virtual void testGroupStarting( GroupInfo const& ) CATCH_OVERRIDE {} - virtual void sectionStarting( SectionInfo const& sectionInfo ) { + virtual void testCaseStarting( TestCaseInfo const& ) CATCH_OVERRIDE {} + + virtual void sectionStarting( SectionInfo const& sectionInfo ) CATCH_OVERRIDE { SectionStats incompleteStats( sectionInfo, Counts(), 0, false ); Ptr node; if( m_sectionStack.empty() ) { @@ -7722,7 +8433,7 @@ namespace Catch { m_deepestSection = node; } - virtual void assertionStarting( AssertionInfo const& ) {} + virtual void assertionStarting( AssertionInfo const& ) CATCH_OVERRIDE {} virtual bool assertionEnded( AssertionStats const& assertionStats ) { assert( !m_sectionStack.empty() ); @@ -7730,13 +8441,13 @@ namespace Catch { sectionNode.assertions.push_back( assertionStats ); return true; } - virtual void sectionEnded( SectionStats const& sectionStats ) { + virtual void sectionEnded( SectionStats const& sectionStats ) CATCH_OVERRIDE { assert( !m_sectionStack.empty() ); SectionNode& node = *m_sectionStack.back(); node.stats = sectionStats; m_sectionStack.pop_back(); } - virtual void testCaseEnded( TestCaseStats const& testCaseStats ) { + virtual void testCaseEnded( TestCaseStats const& testCaseStats ) CATCH_OVERRIDE { Ptr node = new TestCaseNode( testCaseStats ); assert( m_sectionStack.size() == 0 ); node->children.push_back( m_rootSection ); @@ -7747,12 +8458,12 @@ namespace Catch { m_deepestSection->stdOut = testCaseStats.stdOut; m_deepestSection->stdErr = testCaseStats.stdErr; } - virtual void testGroupEnded( TestGroupStats const& testGroupStats ) { + virtual void testGroupEnded( TestGroupStats const& testGroupStats ) CATCH_OVERRIDE { Ptr node = new TestGroupNode( testGroupStats ); node->children.swap( m_testCases ); m_testGroups.push_back( node ); } - virtual void testRunEnded( TestRunStats const& testRunStats ) { + virtual void testRunEnded( TestRunStats const& testRunStats ) CATCH_OVERRIDE { Ptr node = new TestRunNode( testRunStats ); node->children.swap( m_testGroups ); m_testRuns.push_back( node ); @@ -7760,9 +8471,9 @@ namespace Catch { } virtual void testRunEndedCumulative() = 0; - virtual void skipTest( TestCaseInfo const& ) {} + virtual void skipTest( TestCaseInfo const& ) CATCH_OVERRIDE {} - Ptr m_config; + Ptr m_config; std::ostream& stream; std::vector m_assertions; std::vector > > m_sections; @@ -7774,6 +8485,7 @@ namespace Catch { Ptr m_rootSection; Ptr m_deepestSection; std::vector > m_sectionStack; + ReporterPreferences m_reporterPrefs; }; @@ -7787,6 +8499,17 @@ namespace Catch { return line; } + struct TestEventListenerBase : StreamingReporterBase { + TestEventListenerBase( ReporterConfig const& _config ) + : StreamingReporterBase( _config ) + {} + + virtual void assertionStarting( AssertionInfo const& ) CATCH_OVERRIDE {} + virtual bool assertionEnded( AssertionStats const& ) CATCH_OVERRIDE { + return false; + } + }; + } // end namespace Catch // #included from: ../internal/catch_reporter_registrars.hpp @@ -7817,7 +8540,7 @@ namespace Catch { template class ReporterRegistrar { - class ReporterFactory : public IReporterFactory { + class ReporterFactory : public SharedImpl { // *** Please Note ***: // - If you end up here looking at a compiler error because it's trying to register @@ -7845,22 +8568,102 @@ namespace Catch { getMutableRegistryHub().registerReporter( name, new ReporterFactory() ); } }; + + template + class ListenerRegistrar { + + class ListenerFactory : public SharedImpl { + + virtual IStreamingReporter* create( ReporterConfig const& config ) const { + return new T( config ); + } + virtual std::string getDescription() const { + return ""; + } + }; + + public: + + ListenerRegistrar() { + getMutableRegistryHub().registerListener( new ListenerFactory() ); + } + }; } #define INTERNAL_CATCH_REGISTER_LEGACY_REPORTER( name, reporterType ) \ namespace{ Catch::LegacyReporterRegistrar catch_internal_RegistrarFor##reporterType( name ); } + #define INTERNAL_CATCH_REGISTER_REPORTER( name, reporterType ) \ namespace{ Catch::ReporterRegistrar catch_internal_RegistrarFor##reporterType( name ); } +#define INTERNAL_CATCH_REGISTER_LISTENER( listenerType ) \ + namespace{ Catch::ListenerRegistrar catch_internal_RegistrarFor##listenerType; } + // #included from: ../internal/catch_xmlwriter.hpp #define TWOBLUECUBES_CATCH_XMLWRITER_HPP_INCLUDED #include #include #include +#include namespace Catch { + class XmlEncode { + public: + enum ForWhat { ForTextNodes, ForAttributes }; + + XmlEncode( std::string const& str, ForWhat forWhat = ForTextNodes ) + : m_str( str ), + m_forWhat( forWhat ) + {} + + void encodeTo( std::ostream& os ) const { + + // Apostrophe escaping not necessary if we always use " to write attributes + // (see: http://www.w3.org/TR/xml/#syntax) + + for( std::size_t i = 0; i < m_str.size(); ++ i ) { + char c = m_str[i]; + switch( c ) { + case '<': os << "<"; break; + case '&': os << "&"; break; + + case '>': + // See: http://www.w3.org/TR/xml/#syntax + if( i > 2 && m_str[i-1] == ']' && m_str[i-2] == ']' ) + os << ">"; + else + os << c; + break; + + case '\"': + if( m_forWhat == ForAttributes ) + os << """; + else + os << c; + break; + + default: + // Escape control chars - based on contribution by @espenalb in PR #465 + if ( ( c < '\x09' ) || ( c > '\x0D' && c < '\x20') || c=='\x7F' ) + os << "&#x" << std::uppercase << std::hex << static_cast( c ); + else + os << c; + } + } + } + + friend std::ostream& operator << ( std::ostream& os, XmlEncode const& xmlEncode ) { + xmlEncode.encodeTo( os ); + return os; + } + + private: + std::string m_str; + ForWhat m_forWhat; + }; + class XmlWriter { public: @@ -7872,7 +8675,7 @@ namespace Catch { ScopedElement( ScopedElement const& other ) : m_writer( other.m_writer ){ - other.m_writer = NULL; + other.m_writer = CATCH_NULL; } ~ScopedElement() { @@ -7943,11 +8746,8 @@ namespace Catch { } XmlWriter& writeAttribute( std::string const& name, std::string const& attribute ) { - if( !name.empty() && !attribute.empty() ) { - stream() << " " << name << "=\""; - writeEncodedText( attribute ); - stream() << "\""; - } + if( !name.empty() && !attribute.empty() ) + stream() << " " << name << "=\"" << XmlEncode( attribute, XmlEncode::ForAttributes ) << "\""; return *this; } @@ -7958,9 +8758,9 @@ namespace Catch { template XmlWriter& writeAttribute( std::string const& name, T const& attribute ) { - if( !name.empty() ) - stream() << " " << name << "=\"" << attribute << "\""; - return *this; + std::ostringstream oss; + oss << attribute; + return writeAttribute( name, oss.str() ); } XmlWriter& writeText( std::string const& text, bool indent = true ) { @@ -7969,7 +8769,7 @@ namespace Catch { ensureTagClosed(); if( tagWasOpen && indent ) stream() << m_indent; - writeEncodedText( text ); + stream() << XmlEncode( text ); m_needsNewline = true; } return *this; @@ -8014,30 +8814,6 @@ namespace Catch { } } - void writeEncodedText( std::string const& text ) { - static const char* charsToEncode = "<&\""; - std::string mtext = text; - std::string::size_type pos = mtext.find_first_of( charsToEncode ); - while( pos != std::string::npos ) { - stream() << mtext.substr( 0, pos ); - - switch( mtext[pos] ) { - case '<': - stream() << "<"; - break; - case '&': - stream() << "&"; - break; - case '\"': - stream() << """; - break; - } - mtext = mtext.substr( pos+1 ); - pos = mtext.find_first_of( charsToEncode ); - } - stream() << mtext; - } - bool m_tagIsOpen; bool m_needsNewline; std::vector m_tags; @@ -8046,32 +8822,44 @@ namespace Catch { }; } +// #included from: catch_reenable_warnings.h + +#define TWOBLUECUBES_CATCH_REENABLE_WARNINGS_H_INCLUDED + +#ifdef __clang__ +# ifdef __ICC // icpc defines the __clang__ macro +# pragma warning(pop) +# else +# pragma clang diagnostic pop +# endif +#elif defined __GNUC__ +# pragma GCC diagnostic pop +#endif + + namespace Catch { class XmlReporter : public StreamingReporterBase { public: XmlReporter( ReporterConfig const& _config ) : StreamingReporterBase( _config ), m_sectionDepth( 0 ) - {} + { + m_reporterPrefs.shouldRedirectStdOut = true; + } - virtual ~XmlReporter(); + virtual ~XmlReporter() CATCH_OVERRIDE; static std::string getDescription() { return "Reports test results as an XML document"; } public: // StreamingReporterBase - virtual ReporterPreferences getPreferences() const { - ReporterPreferences prefs; - prefs.shouldRedirectStdOut = true; - return prefs; - } - virtual void noMatchingTestCases( std::string const& s ) { + virtual void noMatchingTestCases( std::string const& s ) CATCH_OVERRIDE { StreamingReporterBase::noMatchingTestCases( s ); } - virtual void testRunStarting( TestRunInfo const& testInfo ) { + virtual void testRunStarting( TestRunInfo const& testInfo ) CATCH_OVERRIDE { StreamingReporterBase::testRunStarting( testInfo ); m_xml.setStream( stream ); m_xml.startElement( "Catch" ); @@ -8079,13 +8867,13 @@ namespace Catch { m_xml.writeAttribute( "name", m_config->name() ); } - virtual void testGroupStarting( GroupInfo const& groupInfo ) { + virtual void testGroupStarting( GroupInfo const& groupInfo ) CATCH_OVERRIDE { StreamingReporterBase::testGroupStarting( groupInfo ); m_xml.startElement( "Group" ) .writeAttribute( "name", groupInfo.name ); } - virtual void testCaseStarting( TestCaseInfo const& testInfo ) { + virtual void testCaseStarting( TestCaseInfo const& testInfo ) CATCH_OVERRIDE { StreamingReporterBase::testCaseStarting(testInfo); m_xml.startElement( "TestCase" ).writeAttribute( "name", trim( testInfo.name ) ); @@ -8093,7 +8881,7 @@ namespace Catch { m_testCaseTimer.start(); } - virtual void sectionStarting( SectionInfo const& sectionInfo ) { + virtual void sectionStarting( SectionInfo const& sectionInfo ) CATCH_OVERRIDE { StreamingReporterBase::sectionStarting( sectionInfo ); if( m_sectionDepth++ > 0 ) { m_xml.startElement( "Section" ) @@ -8102,9 +8890,9 @@ namespace Catch { } } - virtual void assertionStarting( AssertionInfo const& ) { } + virtual void assertionStarting( AssertionInfo const& ) CATCH_OVERRIDE { } - virtual bool assertionEnded( AssertionStats const& assertionStats ) { + virtual bool assertionEnded( AssertionStats const& assertionStats ) CATCH_OVERRIDE { const AssertionResult& assertionResult = assertionStats.assertionResult; // Print any info messages in tags. @@ -8175,7 +8963,7 @@ namespace Catch { return true; } - virtual void sectionEnded( SectionStats const& sectionStats ) { + virtual void sectionEnded( SectionStats const& sectionStats ) CATCH_OVERRIDE { StreamingReporterBase::sectionEnded( sectionStats ); if( --m_sectionDepth > 0 ) { XmlWriter::ScopedElement e = m_xml.scopedElement( "OverallResults" ); @@ -8190,7 +8978,7 @@ namespace Catch { } } - virtual void testCaseEnded( TestCaseStats const& testCaseStats ) { + virtual void testCaseEnded( TestCaseStats const& testCaseStats ) CATCH_OVERRIDE { StreamingReporterBase::testCaseEnded( testCaseStats ); XmlWriter::ScopedElement e = m_xml.scopedElement( "OverallResult" ); e.writeAttribute( "success", testCaseStats.totals.assertions.allOk() ); @@ -8201,7 +8989,7 @@ namespace Catch { m_xml.endElement(); } - virtual void testGroupEnded( TestGroupStats const& testGroupStats ) { + virtual void testGroupEnded( TestGroupStats const& testGroupStats ) CATCH_OVERRIDE { StreamingReporterBase::testGroupEnded( testGroupStats ); // TODO: Check testGroupStats.aborting and act accordingly. m_xml.scopedElement( "OverallResults" ) @@ -8211,7 +8999,7 @@ namespace Catch { m_xml.endElement(); } - virtual void testRunEnded( TestRunStats const& testRunStats ) { + virtual void testRunEnded( TestRunStats const& testRunStats ) CATCH_OVERRIDE { StreamingReporterBase::testRunEnded( testRunStats ); m_xml.scopedElement( "OverallResults" ) .writeAttribute( "successes", testRunStats.totals.assertions.passed ) @@ -8242,28 +9030,24 @@ namespace Catch { JunitReporter( ReporterConfig const& _config ) : CumulativeReporterBase( _config ), xml( _config.stream() ) - {} + { + m_reporterPrefs.shouldRedirectStdOut = true; + } - ~JunitReporter(); + virtual ~JunitReporter() CATCH_OVERRIDE; static std::string getDescription() { return "Reports test results in an XML format that looks like Ant's junitreport target"; } - virtual void noMatchingTestCases( std::string const& /*spec*/ ) {} + virtual void noMatchingTestCases( std::string const& /*spec*/ ) CATCH_OVERRIDE {} - virtual ReporterPreferences getPreferences() const { - ReporterPreferences prefs; - prefs.shouldRedirectStdOut = true; - return prefs; - } - - virtual void testRunStarting( TestRunInfo const& runInfo ) { + virtual void testRunStarting( TestRunInfo const& runInfo ) CATCH_OVERRIDE { CumulativeReporterBase::testRunStarting( runInfo ); xml.startElement( "testsuites" ); } - virtual void testGroupStarting( GroupInfo const& groupInfo ) { + virtual void testGroupStarting( GroupInfo const& groupInfo ) CATCH_OVERRIDE { suiteTimer.start(); stdOutForSuite.str(""); stdErrForSuite.str(""); @@ -8271,25 +9055,25 @@ namespace Catch { CumulativeReporterBase::testGroupStarting( groupInfo ); } - virtual bool assertionEnded( AssertionStats const& assertionStats ) { + virtual bool assertionEnded( AssertionStats const& assertionStats ) CATCH_OVERRIDE { if( assertionStats.assertionResult.getResultType() == ResultWas::ThrewException ) unexpectedExceptions++; return CumulativeReporterBase::assertionEnded( assertionStats ); } - virtual void testCaseEnded( TestCaseStats const& testCaseStats ) { + virtual void testCaseEnded( TestCaseStats const& testCaseStats ) CATCH_OVERRIDE { stdOutForSuite << testCaseStats.stdOut; stdErrForSuite << testCaseStats.stdErr; CumulativeReporterBase::testCaseEnded( testCaseStats ); } - virtual void testGroupEnded( TestGroupStats const& testGroupStats ) { + virtual void testGroupEnded( TestGroupStats const& testGroupStats ) CATCH_OVERRIDE { double suiteTime = suiteTimer.getElapsedSeconds(); CumulativeReporterBase::testGroupEnded( testGroupStats ); writeGroup( *m_testGroups.back(), suiteTime ); } - virtual void testRunEndedCumulative() { + virtual void testRunEndedCumulative() CATCH_OVERRIDE { xml.endElement(); } @@ -8454,24 +9238,19 @@ namespace Catch { m_headerPrinted( false ) {} - virtual ~ConsoleReporter(); + virtual ~ConsoleReporter() CATCH_OVERRIDE; static std::string getDescription() { return "Reports test results as plain lines of text"; } - virtual ReporterPreferences getPreferences() const { - ReporterPreferences prefs; - prefs.shouldRedirectStdOut = false; - return prefs; - } - virtual void noMatchingTestCases( std::string const& spec ) { + virtual void noMatchingTestCases( std::string const& spec ) CATCH_OVERRIDE { stream << "No test cases matched '" << spec << "'" << std::endl; } - virtual void assertionStarting( AssertionInfo const& ) { + virtual void assertionStarting( AssertionInfo const& ) CATCH_OVERRIDE { } - virtual bool assertionEnded( AssertionStats const& _assertionStats ) { + virtual bool assertionEnded( AssertionStats const& _assertionStats ) CATCH_OVERRIDE { AssertionResult const& result = _assertionStats.assertionResult; bool printInfoMessages = true; @@ -8491,11 +9270,11 @@ namespace Catch { return true; } - virtual void sectionStarting( SectionInfo const& _sectionInfo ) { + virtual void sectionStarting( SectionInfo const& _sectionInfo ) CATCH_OVERRIDE { m_headerPrinted = false; StreamingReporterBase::sectionStarting( _sectionInfo ); } - virtual void sectionEnded( SectionStats const& _sectionStats ) { + virtual void sectionEnded( SectionStats const& _sectionStats ) CATCH_OVERRIDE { if( _sectionStats.missingAssertions ) { lazyPrint(); Colour colour( Colour::ResultError ); @@ -8517,11 +9296,11 @@ namespace Catch { StreamingReporterBase::sectionEnded( _sectionStats ); } - virtual void testCaseEnded( TestCaseStats const& _testCaseStats ) { + virtual void testCaseEnded( TestCaseStats const& _testCaseStats ) CATCH_OVERRIDE { StreamingReporterBase::testCaseEnded( _testCaseStats ); m_headerPrinted = false; } - virtual void testGroupEnded( TestGroupStats const& _testGroupStats ) { + virtual void testGroupEnded( TestGroupStats const& _testGroupStats ) CATCH_OVERRIDE { if( currentGroupInfo.used ) { printSummaryDivider(); stream << "Summary for group '" << _testGroupStats.groupInfo.name << "':\n"; @@ -8530,7 +9309,7 @@ namespace Catch { } StreamingReporterBase::testGroupEnded( _testGroupStats ); } - virtual void testRunEnded( TestRunStats const& _testRunStats ) { + virtual void testRunEnded( TestRunStats const& _testRunStats ) CATCH_OVERRIDE { printTotalsDivider( _testRunStats.totals ); printTotals( _testRunStats.totals ); stream << std::endl; @@ -9169,8 +9948,14 @@ namespace Catch { } // end namespace Catch namespace Catch { + // These are all here to avoid warnings about not having any out of line + // virtual methods NonCopyable::~NonCopyable() {} IShared::~IShared() {} + IStream::~IStream() CATCH_NOEXCEPT {} + FileStream::~FileStream() CATCH_NOEXCEPT {} + CoutStream::~CoutStream() CATCH_NOEXCEPT {} + DebugOutStream::~DebugOutStream() CATCH_NOEXCEPT {} StreamBufBase::~StreamBufBase() CATCH_NOEXCEPT {} IContext::~IContext() {} IResultCapture::~IResultCapture() {} @@ -9204,6 +9989,7 @@ namespace Catch { FreeFunctionTestCase::~FreeFunctionTestCase() {} IGeneratorInfo::~IGeneratorInfo() {} IGeneratorsForTest::~IGeneratorsForTest() {} + WildcardPattern::~WildcardPattern() {} TestSpec::Pattern::~Pattern() {} TestSpec::NamePattern::~NamePattern() {} TestSpec::TagPattern::~TagPattern() {} @@ -9215,6 +10001,13 @@ namespace Catch { Matchers::Impl::StdString::EndsWith::~EndsWith() {} void Config::dummy() {} + + namespace TestCaseTracking { + ITracker::~ITracker() {} + TrackerBase::~TrackerBase() {} + SectionTracker::~SectionTracker() {} + IndexTracker::~IndexTracker() {} + } } #ifdef __clang__ @@ -9230,7 +10023,7 @@ namespace Catch { #ifndef __OBJC__ // Standard C/C++ main entry point -int main (int argc, char * const argv[]) { +int main (int argc, char * argv[]) { return Catch::Session().run( argc, argv ); } @@ -9268,8 +10061,9 @@ int main (int argc, char * const argv[]) { #define CATCH_REQUIRE( expr ) INTERNAL_CATCH_TEST( expr, Catch::ResultDisposition::Normal, "CATCH_REQUIRE" ) #define CATCH_REQUIRE_FALSE( expr ) INTERNAL_CATCH_TEST( expr, Catch::ResultDisposition::Normal | Catch::ResultDisposition::FalseTest, "CATCH_REQUIRE_FALSE" ) -#define CATCH_REQUIRE_THROWS( expr ) INTERNAL_CATCH_THROWS( expr, Catch::ResultDisposition::Normal, "CATCH_REQUIRE_THROWS" ) +#define CATCH_REQUIRE_THROWS( expr ) INTERNAL_CATCH_THROWS( expr, Catch::ResultDisposition::Normal, "", "CATCH_REQUIRE_THROWS" ) #define CATCH_REQUIRE_THROWS_AS( expr, exceptionType ) INTERNAL_CATCH_THROWS_AS( expr, exceptionType, Catch::ResultDisposition::Normal, "CATCH_REQUIRE_THROWS_AS" ) +#define CATCH_REQUIRE_THROWS_WITH( expr, matcher ) INTERNAL_CATCH_THROWS( expr, Catch::ResultDisposition::Normal, matcher, "CATCH_REQUIRE_THROWS_WITH" ) #define CATCH_REQUIRE_NOTHROW( expr ) INTERNAL_CATCH_NO_THROW( expr, Catch::ResultDisposition::Normal, "CATCH_REQUIRE_NOTHROW" ) #define CATCH_CHECK( expr ) INTERNAL_CATCH_TEST( expr, Catch::ResultDisposition::ContinueOnFailure, "CATCH_CHECK" ) @@ -9280,6 +10074,7 @@ int main (int argc, char * const argv[]) { #define CATCH_CHECK_THROWS( expr ) INTERNAL_CATCH_THROWS( expr, Catch::ResultDisposition::ContinueOnFailure, "CATCH_CHECK_THROWS" ) #define CATCH_CHECK_THROWS_AS( expr, exceptionType ) INTERNAL_CATCH_THROWS_AS( expr, exceptionType, Catch::ResultDisposition::ContinueOnFailure, "CATCH_CHECK_THROWS_AS" ) +#define CATCH_CHECK_THROWS_WITH( expr, matcher ) INTERNAL_CATCH_THROWS( expr, Catch::ResultDisposition::ContinueOnFailure, matcher, "CATCH_CHECK_THROWS_WITH" ) #define CATCH_CHECK_NOTHROW( expr ) INTERNAL_CATCH_NO_THROW( expr, Catch::ResultDisposition::ContinueOnFailure, "CATCH_CHECK_NOTHROW" ) #define CHECK_THAT( arg, matcher ) INTERNAL_CHECK_THAT( arg, matcher, Catch::ResultDisposition::ContinueOnFailure, "CATCH_CHECK_THAT" ) @@ -9295,6 +10090,7 @@ int main (int argc, char * const argv[]) { #define CATCH_TEST_CASE( ... ) INTERNAL_CATCH_TESTCASE( __VA_ARGS__ ) #define CATCH_TEST_CASE_METHOD( className, ... ) INTERNAL_CATCH_TEST_CASE_METHOD( className, __VA_ARGS__ ) #define CATCH_METHOD_AS_TEST_CASE( method, ... ) INTERNAL_CATCH_METHOD_AS_TEST_CASE( method, __VA_ARGS__ ) + #define CATCH_REGISTER_TEST_CASE( ... ) INTERNAL_CATCH_REGISTER_TESTCASE( __VA_ARGS__ ) #define CATCH_SECTION( ... ) INTERNAL_CATCH_SECTION( __VA_ARGS__ ) #define CATCH_FAIL( ... ) INTERNAL_CATCH_MSG( Catch::ResultWas::ExplicitFailure, Catch::ResultDisposition::Normal, "CATCH_FAIL", __VA_ARGS__ ) #define CATCH_SUCCEED( ... ) INTERNAL_CATCH_MSG( Catch::ResultWas::Ok, Catch::ResultDisposition::ContinueOnFailure, "CATCH_SUCCEED", __VA_ARGS__ ) @@ -9302,6 +10098,7 @@ int main (int argc, char * const argv[]) { #define CATCH_TEST_CASE( name, description ) INTERNAL_CATCH_TESTCASE( name, description ) #define CATCH_TEST_CASE_METHOD( className, name, description ) INTERNAL_CATCH_TEST_CASE_METHOD( className, name, description ) #define CATCH_METHOD_AS_TEST_CASE( method, name, description ) INTERNAL_CATCH_METHOD_AS_TEST_CASE( method, name, description ) + #define CATCH_REGISTER_TEST_CASE( function, name, description ) INTERNAL_CATCH_REGISTER_TESTCASE( function, name, description ) #define CATCH_SECTION( name, description ) INTERNAL_CATCH_SECTION( name, description ) #define CATCH_FAIL( msg ) INTERNAL_CATCH_MSG( Catch::ResultWas::ExplicitFailure, Catch::ResultDisposition::Normal, "CATCH_FAIL", msg ) #define CATCH_SUCCEED( msg ) INTERNAL_CATCH_MSG( Catch::ResultWas::Ok, Catch::ResultDisposition::ContinueOnFailure, "CATCH_SUCCEED", msg ) @@ -9321,11 +10118,11 @@ int main (int argc, char * const argv[]) { #define CATCH_SCENARIO( name, tags ) CATCH_TEST_CASE( "Scenario: " name, tags ) #define CATCH_SCENARIO_METHOD( className, name, tags ) INTERNAL_CATCH_TEST_CASE_METHOD( className, "Scenario: " name, tags ) #endif -#define CATCH_GIVEN( desc ) CATCH_SECTION( "Given: " desc, "" ) -#define CATCH_WHEN( desc ) CATCH_SECTION( " When: " desc, "" ) -#define CATCH_AND_WHEN( desc ) CATCH_SECTION( " And: " desc, "" ) -#define CATCH_THEN( desc ) CATCH_SECTION( " Then: " desc, "" ) -#define CATCH_AND_THEN( desc ) CATCH_SECTION( " And: " desc, "" ) +#define CATCH_GIVEN( desc ) CATCH_SECTION( std::string( "Given: ") + desc, "" ) +#define CATCH_WHEN( desc ) CATCH_SECTION( std::string( " When: ") + desc, "" ) +#define CATCH_AND_WHEN( desc ) CATCH_SECTION( std::string( " And: ") + desc, "" ) +#define CATCH_THEN( desc ) CATCH_SECTION( std::string( " Then: ") + desc, "" ) +#define CATCH_AND_THEN( desc ) CATCH_SECTION( std::string( " And: ") + desc, "" ) // If CATCH_CONFIG_PREFIX_ALL is not defined then the CATCH_ prefix is not required #else @@ -9333,8 +10130,9 @@ int main (int argc, char * const argv[]) { #define REQUIRE( expr ) INTERNAL_CATCH_TEST( expr, Catch::ResultDisposition::Normal, "REQUIRE" ) #define REQUIRE_FALSE( expr ) INTERNAL_CATCH_TEST( expr, Catch::ResultDisposition::Normal | Catch::ResultDisposition::FalseTest, "REQUIRE_FALSE" ) -#define REQUIRE_THROWS( expr ) INTERNAL_CATCH_THROWS( expr, Catch::ResultDisposition::Normal, "REQUIRE_THROWS" ) +#define REQUIRE_THROWS( expr ) INTERNAL_CATCH_THROWS( expr, Catch::ResultDisposition::Normal, "", "REQUIRE_THROWS" ) #define REQUIRE_THROWS_AS( expr, exceptionType ) INTERNAL_CATCH_THROWS_AS( expr, exceptionType, Catch::ResultDisposition::Normal, "REQUIRE_THROWS_AS" ) +#define REQUIRE_THROWS_WITH( expr, matcher ) INTERNAL_CATCH_THROWS( expr, Catch::ResultDisposition::Normal, matcher, "REQUIRE_THROWS_WITH" ) #define REQUIRE_NOTHROW( expr ) INTERNAL_CATCH_NO_THROW( expr, Catch::ResultDisposition::Normal, "REQUIRE_NOTHROW" ) #define CHECK( expr ) INTERNAL_CATCH_TEST( expr, Catch::ResultDisposition::ContinueOnFailure, "CHECK" ) @@ -9343,8 +10141,9 @@ int main (int argc, char * const argv[]) { #define CHECKED_ELSE( expr ) INTERNAL_CATCH_ELSE( expr, Catch::ResultDisposition::ContinueOnFailure, "CHECKED_ELSE" ) #define CHECK_NOFAIL( expr ) INTERNAL_CATCH_TEST( expr, Catch::ResultDisposition::ContinueOnFailure | Catch::ResultDisposition::SuppressFail, "CHECK_NOFAIL" ) -#define CHECK_THROWS( expr ) INTERNAL_CATCH_THROWS( expr, Catch::ResultDisposition::ContinueOnFailure, "CHECK_THROWS" ) +#define CHECK_THROWS( expr ) INTERNAL_CATCH_THROWS( expr, Catch::ResultDisposition::ContinueOnFailure, "", "CHECK_THROWS" ) #define CHECK_THROWS_AS( expr, exceptionType ) INTERNAL_CATCH_THROWS_AS( expr, exceptionType, Catch::ResultDisposition::ContinueOnFailure, "CHECK_THROWS_AS" ) +#define CHECK_THROWS_WITH( expr, matcher ) INTERNAL_CATCH_THROWS( expr, Catch::ResultDisposition::ContinueOnFailure, matcher, "CHECK_THROWS_WITH" ) #define CHECK_NOTHROW( expr ) INTERNAL_CATCH_NO_THROW( expr, Catch::ResultDisposition::ContinueOnFailure, "CHECK_NOTHROW" ) #define CHECK_THAT( arg, matcher ) INTERNAL_CHECK_THAT( arg, matcher, Catch::ResultDisposition::ContinueOnFailure, "CHECK_THAT" ) @@ -9360,6 +10159,7 @@ int main (int argc, char * const argv[]) { #define TEST_CASE( ... ) INTERNAL_CATCH_TESTCASE( __VA_ARGS__ ) #define TEST_CASE_METHOD( className, ... ) INTERNAL_CATCH_TEST_CASE_METHOD( className, __VA_ARGS__ ) #define METHOD_AS_TEST_CASE( method, ... ) INTERNAL_CATCH_METHOD_AS_TEST_CASE( method, __VA_ARGS__ ) + #define REGISTER_TEST_CASE( ... ) INTERNAL_CATCH_REGISTER_TESTCASE( __VA_ARGS__ ) #define SECTION( ... ) INTERNAL_CATCH_SECTION( __VA_ARGS__ ) #define FAIL( ... ) INTERNAL_CATCH_MSG( Catch::ResultWas::ExplicitFailure, Catch::ResultDisposition::Normal, "FAIL", __VA_ARGS__ ) #define SUCCEED( ... ) INTERNAL_CATCH_MSG( Catch::ResultWas::Ok, Catch::ResultDisposition::ContinueOnFailure, "SUCCEED", __VA_ARGS__ ) @@ -9367,6 +10167,7 @@ int main (int argc, char * const argv[]) { #define TEST_CASE( name, description ) INTERNAL_CATCH_TESTCASE( name, description ) #define TEST_CASE_METHOD( className, name, description ) INTERNAL_CATCH_TEST_CASE_METHOD( className, name, description ) #define METHOD_AS_TEST_CASE( method, name, description ) INTERNAL_CATCH_METHOD_AS_TEST_CASE( method, name, description ) + #define REGISTER_TEST_CASE( ... ) INTERNAL_CATCH_REGISTER_TESTCASE( __VA_ARGS__ ) #define SECTION( name, description ) INTERNAL_CATCH_SECTION( name, description ) #define FAIL( msg ) INTERNAL_CATCH_MSG( Catch::ResultWas::ExplicitFailure, Catch::ResultDisposition::Normal, "FAIL", msg ) #define SUCCEED( msg ) INTERNAL_CATCH_MSG( Catch::ResultWas::Ok, Catch::ResultDisposition::ContinueOnFailure, "SUCCEED", msg ) @@ -9390,27 +10191,13 @@ int main (int argc, char * const argv[]) { #define SCENARIO( name, tags ) TEST_CASE( "Scenario: " name, tags ) #define SCENARIO_METHOD( className, name, tags ) INTERNAL_CATCH_TEST_CASE_METHOD( className, "Scenario: " name, tags ) #endif -#define GIVEN( desc ) SECTION( " Given: " desc, "" ) -#define WHEN( desc ) SECTION( " When: " desc, "" ) -#define AND_WHEN( desc ) SECTION( "And when: " desc, "" ) -#define THEN( desc ) SECTION( " Then: " desc, "" ) -#define AND_THEN( desc ) SECTION( " And: " desc, "" ) +#define GIVEN( desc ) SECTION( std::string(" Given: ") + desc, "" ) +#define WHEN( desc ) SECTION( std::string(" When: ") + desc, "" ) +#define AND_WHEN( desc ) SECTION( std::string("And when: ") + desc, "" ) +#define THEN( desc ) SECTION( std::string(" Then: ") + desc, "" ) +#define AND_THEN( desc ) SECTION( std::string(" And: ") + desc, "" ) using Catch::Detail::Approx; -// #included from: internal/catch_reenable_warnings.h - -#define TWOBLUECUBES_CATCH_REENABLE_WARNINGS_H_INCLUDED - -#ifdef __clang__ -# ifdef __ICC // icpc defines the __clang__ macro -# pragma warning(pop) -# else -# pragma clang diagnostic pop -# endif -#elif defined __GNUC__ -# pragma GCC diagnostic pop -#endif - #endif // TWOBLUECUBES_SINGLE_INCLUDE_CATCH_HPP_INCLUDED From 4351698c839b9aafd5fb82513d87469a25f55022 Mon Sep 17 00:00:00 2001 From: Niels Date: Mon, 21 Dec 2015 08:42:42 +0100 Subject: [PATCH 28/61] re-adding const version operator[] (#135, #159) It was a good idea to implement a const version of operator[] it in the first place. I was a pity that this implementation was flawed. It was a mistake to remove the const version completely. This commit re-introduces the const version. My apologies for all the inconvenience. --- .../operatorarray__key_type_const.cpp | 2 +- .../operatorarray__key_type_const.link | 2 +- src/json.hpp | 81 +++++++++++++++++++ src/json.hpp.re2c | 81 +++++++++++++++++++ test/unit.cpp | 33 ++++++++ 5 files changed, 197 insertions(+), 2 deletions(-) diff --git a/doc/examples/operatorarray__key_type_const.cpp b/doc/examples/operatorarray__key_type_const.cpp index 6d0c91412..a59cca58b 100644 --- a/doc/examples/operatorarray__key_type_const.cpp +++ b/doc/examples/operatorarray__key_type_const.cpp @@ -5,7 +5,7 @@ using namespace nlohmann; int main() { // create a JSON object - json object = + const json object = { {"one", 1}, {"two", 2}, {"three", 2.9} }; diff --git a/doc/examples/operatorarray__key_type_const.link b/doc/examples/operatorarray__key_type_const.link index 0f03498a9..7e740a1b8 100644 --- a/doc/examples/operatorarray__key_type_const.link +++ b/doc/examples/operatorarray__key_type_const.link @@ -1 +1 @@ -online \ No newline at end of file +online \ No newline at end of file diff --git a/src/json.hpp b/src/json.hpp index 6bfb44bff..e11bae2d5 100644 --- a/src/json.hpp +++ b/src/json.hpp @@ -2862,6 +2862,45 @@ class basic_json } } + /*! + @brief read-only access specified object element + + Returns a const reference to the element at with specified key @a key. No + bounds checking is performed. + + @warning If the element with key @a key does not exist, the behavior is + undefined. + + @param[in] key key of the element to access + + @return const reference to the element at key @a key + + @throw std::domain_error if JSON is not an object + + @complexity Logarithmic in the size of the container. + + @liveexample{The example below shows how object elements can be read using + the [] operator.,operatorarray__key_type_const} + + @sa @ref at(const typename object_t::key_type&) for access by reference + with range checking + @sa @ref value() for access by value with a default value + + @since version 1.0 + */ + const_reference operator[](const typename object_t::key_type& key) const + { + // [] only works for objects + if (is_object()) + { + return m_value.object->find(key)->second; + } + else + { + throw std::domain_error("cannot use operator[] with " + type_name()); + } + } + /*! @brief access specified object element @@ -2911,6 +2950,48 @@ class basic_json } } + /*! + @brief read-only access specified object element + + Returns a const reference to the element at with specified key @a key. No + bounds checking is performed. + + @warning If the element with key @a key does not exist, the behavior is + undefined. + + @note This function is required for compatibility reasons with Clang. + + @param[in] key key of the element to access + + @return const reference to the element at key @a key + + @throw std::domain_error if JSON is not an object + + @complexity Logarithmic in the size of the container. + + @liveexample{The example below shows how object elements can be read using + the [] operator.,operatorarray__key_type_const} + + @sa @ref at(const typename object_t::key_type&) for access by reference + with range checking + @sa @ref value() for access by value with a default value + + @since version 1.0 + */ + template + const_reference operator[](const T (&key)[n]) const + { + // at only works for objects + if (is_object()) + { + return m_value.object->find(key)->second; + } + else + { + throw std::domain_error("cannot use operator[] with " + type_name()); + } + } + /*! @brief access specified object element with default value diff --git a/src/json.hpp.re2c b/src/json.hpp.re2c index 3ab1dfce1..119ec5c2a 100644 --- a/src/json.hpp.re2c +++ b/src/json.hpp.re2c @@ -2862,6 +2862,45 @@ class basic_json } } + /*! + @brief read-only access specified object element + + Returns a const reference to the element at with specified key @a key. No + bounds checking is performed. + + @warning If the element with key @a key does not exist, the behavior is + undefined. + + @param[in] key key of the element to access + + @return const reference to the element at key @a key + + @throw std::domain_error if JSON is not an object + + @complexity Logarithmic in the size of the container. + + @liveexample{The example below shows how object elements can be read using + the [] operator.,operatorarray__key_type_const} + + @sa @ref at(const typename object_t::key_type&) for access by reference + with range checking + @sa @ref value() for access by value with a default value + + @since version 1.0 + */ + const_reference operator[](const typename object_t::key_type& key) const + { + // [] only works for objects + if (is_object()) + { + return m_value.object->find(key)->second; + } + else + { + throw std::domain_error("cannot use operator[] with " + type_name()); + } + } + /*! @brief access specified object element @@ -2911,6 +2950,48 @@ class basic_json } } + /*! + @brief read-only access specified object element + + Returns a const reference to the element at with specified key @a key. No + bounds checking is performed. + + @warning If the element with key @a key does not exist, the behavior is + undefined. + + @note This function is required for compatibility reasons with Clang. + + @param[in] key key of the element to access + + @return const reference to the element at key @a key + + @throw std::domain_error if JSON is not an object + + @complexity Logarithmic in the size of the container. + + @liveexample{The example below shows how object elements can be read using + the [] operator.,operatorarray__key_type_const} + + @sa @ref at(const typename object_t::key_type&) for access by reference + with range checking + @sa @ref value() for access by value with a default value + + @since version 1.0 + */ + template + const_reference operator[](const T (&key)[n]) const + { + // at only works for objects + if (is_object()) + { + return m_value.object->find(key)->second; + } + else + { + throw std::domain_error("cannot use operator[] with " + type_name()); + } + } + /*! @brief access specified object element with default value diff --git a/test/unit.cpp b/test/unit.cpp index b143f31b5..e52128ce8 100644 --- a/test/unit.cpp +++ b/test/unit.cpp @@ -3211,6 +3211,27 @@ TEST_CASE("element access") CHECK(j["array"] == json({1, 2, 3})); CHECK(j[json::object_t::key_type("array")] == j["array"]); + + CHECK(j_const["integer"] == json(1)); + CHECK(j_const[json::object_t::key_type("integer")] == j["integer"]); + + CHECK(j_const["boolean"] == json(true)); + CHECK(j_const[json::object_t::key_type("boolean")] == j["boolean"]); + + CHECK(j_const["null"] == json(nullptr)); + CHECK(j_const[json::object_t::key_type("null")] == j["null"]); + + CHECK(j_const["string"] == json("hello world")); + CHECK(j_const[json::object_t::key_type("string")] == j["string"]); + + CHECK(j_const["floating"] == json(42.23)); + CHECK(j_const[json::object_t::key_type("floating")] == j["floating"]); + + CHECK(j_const["object"] == json(json::object())); + CHECK(j_const[json::object_t::key_type("object")] == j["object"]); + + CHECK(j_const["array"] == json({1, 2, 3})); + CHECK(j_const[json::object_t::key_type("array")] == j["array"]); } SECTION("access on non-object type") @@ -3222,6 +3243,8 @@ TEST_CASE("element access") const json j_const_nonobject(j_nonobject); CHECK_NOTHROW(j_nonobject["foo"]); CHECK_NOTHROW(j_nonobject2[json::object_t::key_type("foo")]); + CHECK_THROWS_AS(j_const_nonobject["foo"], std::domain_error); + CHECK_THROWS_AS(j_const_nonobject[json::object_t::key_type("foo")], std::domain_error); } SECTION("boolean") @@ -3230,6 +3253,8 @@ TEST_CASE("element access") const json j_const_nonobject(j_nonobject); CHECK_THROWS_AS(j_nonobject["foo"], std::domain_error); CHECK_THROWS_AS(j_nonobject[json::object_t::key_type("foo")], std::domain_error); + CHECK_THROWS_AS(j_const_nonobject["foo"], std::domain_error); + CHECK_THROWS_AS(j_const_nonobject[json::object_t::key_type("foo")], std::domain_error); } SECTION("string") @@ -3238,6 +3263,8 @@ TEST_CASE("element access") const json j_const_nonobject(j_nonobject); CHECK_THROWS_AS(j_nonobject["foo"], std::domain_error); CHECK_THROWS_AS(j_nonobject[json::object_t::key_type("foo")], std::domain_error); + CHECK_THROWS_AS(j_const_nonobject["foo"], std::domain_error); + CHECK_THROWS_AS(j_const_nonobject[json::object_t::key_type("foo")], std::domain_error); } SECTION("array") @@ -3246,6 +3273,8 @@ TEST_CASE("element access") const json j_const_nonobject(j_nonobject); CHECK_THROWS_AS(j_nonobject["foo"], std::domain_error); CHECK_THROWS_AS(j_nonobject[json::object_t::key_type("foo")], std::domain_error); + CHECK_THROWS_AS(j_const_nonobject["foo"], std::domain_error); + CHECK_THROWS_AS(j_const_nonobject[json::object_t::key_type("foo")], std::domain_error); } SECTION("number (integer)") @@ -3254,6 +3283,8 @@ TEST_CASE("element access") const json j_const_nonobject(j_nonobject); CHECK_THROWS_AS(j_nonobject["foo"], std::domain_error); CHECK_THROWS_AS(j_nonobject[json::object_t::key_type("foo")], std::domain_error); + CHECK_THROWS_AS(j_const_nonobject["foo"], std::domain_error); + CHECK_THROWS_AS(j_const_nonobject[json::object_t::key_type("foo")], std::domain_error); } SECTION("number (floating-point)") @@ -3262,6 +3293,8 @@ TEST_CASE("element access") const json j_const_nonobject(j_nonobject); CHECK_THROWS_AS(j_nonobject["foo"], std::domain_error); CHECK_THROWS_AS(j_nonobject[json::object_t::key_type("foo")], std::domain_error); + CHECK_THROWS_AS(j_const_nonobject["foo"], std::domain_error); + CHECK_THROWS_AS(j_const_nonobject[json::object_t::key_type("foo")], std::domain_error); } } } From 67c2d90a2177df204b2b50e8d6010fa5210bbcb6 Mon Sep 17 00:00:00 2001 From: Niels Date: Tue, 22 Dec 2015 13:27:40 +0100 Subject: [PATCH 29/61] working on #160 --- README.md | 2 +- doc/examples/at__object_t_key_type.cpp | 4 +- doc/examples/at__object_t_key_type.link | 2 +- doc/examples/at__object_t_key_type.output | 2 +- doc/examples/at__size_type.cpp | 4 +- doc/examples/at__size_type.link | 2 +- doc/examples/at__size_type.output | 2 +- src/json.hpp | 60 ++++++++-- src/json.hpp.re2c | 60 ++++++++-- test/unit.cpp | 140 ++++++++++++++++++++++ 10 files changed, 245 insertions(+), 33 deletions(-) diff --git a/README.md b/README.md index b671f3571..11d350efd 100644 --- a/README.md +++ b/README.md @@ -398,7 +398,7 @@ $ make $ ./json_unit "*" =============================================================================== -All tests passed (3341848 assertions in 28 test cases) +All tests passed (3341888 assertions in 28 test cases) ``` For more information, have a look at the file [.travis.yml](https://github.com/nlohmann/json/blob/master/.travis.yml). diff --git a/doc/examples/at__object_t_key_type.cpp b/doc/examples/at__object_t_key_type.cpp index 85de56565..29c24c0ce 100644 --- a/doc/examples/at__object_t_key_type.cpp +++ b/doc/examples/at__object_t_key_type.cpp @@ -26,8 +26,8 @@ int main() { object.at("the fast") = "il rapido"; } - catch (std::out_of_range) + catch (std::out_of_range& e) { - std::cout << "out of range" << '\n'; + std::cout << "out of range: " << e.what() << '\n'; } } diff --git a/doc/examples/at__object_t_key_type.link b/doc/examples/at__object_t_key_type.link index 1f4956378..beba6a0fb 100644 --- a/doc/examples/at__object_t_key_type.link +++ b/doc/examples/at__object_t_key_type.link @@ -1 +1 @@ -online \ No newline at end of file +online \ No newline at end of file diff --git a/doc/examples/at__object_t_key_type.output b/doc/examples/at__object_t_key_type.output index 90ccb1cdb..79cff2d7f 100644 --- a/doc/examples/at__object_t_key_type.output +++ b/doc/examples/at__object_t_key_type.output @@ -1,3 +1,3 @@ "il brutto" {"the bad":"il cattivo","the good":"il buono","the ugly":"il brutto"} -out of range +out of range: key 'the fast' not found diff --git a/doc/examples/at__size_type.cpp b/doc/examples/at__size_type.cpp index 5195005ee..617485bf0 100644 --- a/doc/examples/at__size_type.cpp +++ b/doc/examples/at__size_type.cpp @@ -21,8 +21,8 @@ int main() { array.at(5) = "sixth"; } - catch (std::out_of_range) + catch (std::out_of_range& e) { - std::cout << "out of range" << '\n'; + std::cout << "out of range: " << e.what() << '\n'; } } diff --git a/doc/examples/at__size_type.link b/doc/examples/at__size_type.link index 49830f7b0..a5ce10e4d 100644 --- a/doc/examples/at__size_type.link +++ b/doc/examples/at__size_type.link @@ -1 +1 @@ -online \ No newline at end of file +online \ No newline at end of file diff --git a/doc/examples/at__size_type.output b/doc/examples/at__size_type.output index 93748f7f3..d1f68bdb8 100644 --- a/doc/examples/at__size_type.output +++ b/doc/examples/at__size_type.output @@ -1,3 +1,3 @@ "third" ["first","second","third","fourth"] -out of range +out of range: array index 5 is out of range diff --git a/src/json.hpp b/src/json.hpp index e11bae2d5..ee6b1743b 100644 --- a/src/json.hpp +++ b/src/json.hpp @@ -2602,9 +2602,10 @@ class basic_json @return reference to the element at index @a idx - @throw std::domain_error if JSON is not an array + @throw std::domain_error if the JSON value is not an array; example: + `"cannot use at() with string"` @throw std::out_of_range if the index @a idx is out of range of the array; - that is, `idx >= size()` + that is, `idx >= size()`; example: `"array index 7 is out of range"` @complexity Constant. @@ -2618,7 +2619,15 @@ class basic_json // at only works for arrays if (is_array()) { - return m_value.array->at(idx); + try + { + return m_value.array->at(idx); + } + catch (std::out_of_range& e) + { + // create better exception explanation + throw std::out_of_range("array index " + std::to_string(idx) + " is out of range"); + } } else { @@ -2636,9 +2645,10 @@ class basic_json @return const reference to the element at index @a idx - @throw std::domain_error if JSON is not an array + @throw std::domain_error if the JSON value is not an array; example: + `"cannot use at() with string"` @throw std::out_of_range if the index @a idx is out of range of the array; - that is, `idx >= size()` + that is, `idx >= size()`; example: `"array index 7 is out of range"` @complexity Constant. @@ -2652,7 +2662,15 @@ class basic_json // at only works for arrays if (is_array()) { - return m_value.array->at(idx); + try + { + return m_value.array->at(idx); + } + catch (std::out_of_range& e) + { + // create better exception explanation + throw std::out_of_range("array index " + std::to_string(idx) + " is out of range"); + } } else { @@ -2670,9 +2688,10 @@ class basic_json @return reference to the element at key @a key - @throw std::domain_error if JSON is not an object + @throw std::domain_error if the JSON value is not an object; example: + `"cannot use at() with boolean"` @throw std::out_of_range if the key @a key is is not stored in the object; - that is, `find(key) == end()` + that is, `find(key) == end()`; example: `"key "the fast" not found"` @complexity Logarithmic in the size of the container. @@ -2690,7 +2709,15 @@ class basic_json // at only works for objects if (is_object()) { - return m_value.object->at(key); + try + { + return m_value.object->at(key); + } + catch (std::out_of_range& e) + { + // create better exception explanation + throw std::out_of_range("key '" + key + "' not found"); + } } else { @@ -2708,9 +2735,10 @@ class basic_json @return const reference to the element at key @a key - @throw std::domain_error if JSON is not an object + @throw std::domain_error if the JSON value is not an object; example: + `"cannot use at() with boolean"` @throw std::out_of_range if the key @a key is is not stored in the object; - that is, `find(key) == end()` + that is, `find(key) == end()`; example: `"key "the fast" not found"` @complexity Logarithmic in the size of the container. @@ -2728,7 +2756,15 @@ class basic_json // at only works for objects if (is_object()) { - return m_value.object->at(key); + try + { + return m_value.object->at(key); + } + catch (std::out_of_range& e) + { + // create better exception explanation + throw std::out_of_range("key '" + key + "' not found"); + } } else { diff --git a/src/json.hpp.re2c b/src/json.hpp.re2c index 119ec5c2a..cea396d62 100644 --- a/src/json.hpp.re2c +++ b/src/json.hpp.re2c @@ -2602,9 +2602,10 @@ class basic_json @return reference to the element at index @a idx - @throw std::domain_error if JSON is not an array + @throw std::domain_error if the JSON value is not an array; example: + `"cannot use at() with string"` @throw std::out_of_range if the index @a idx is out of range of the array; - that is, `idx >= size()` + that is, `idx >= size()`; example: `"array index 7 is out of range"` @complexity Constant. @@ -2618,7 +2619,15 @@ class basic_json // at only works for arrays if (is_array()) { - return m_value.array->at(idx); + try + { + return m_value.array->at(idx); + } + catch (std::out_of_range& e) + { + // create better exception explanation + throw std::out_of_range("array index " + std::to_string(idx) + " is out of range"); + } } else { @@ -2636,9 +2645,10 @@ class basic_json @return const reference to the element at index @a idx - @throw std::domain_error if JSON is not an array + @throw std::domain_error if the JSON value is not an array; example: + `"cannot use at() with string"` @throw std::out_of_range if the index @a idx is out of range of the array; - that is, `idx >= size()` + that is, `idx >= size()`; example: `"array index 7 is out of range"` @complexity Constant. @@ -2652,7 +2662,15 @@ class basic_json // at only works for arrays if (is_array()) { - return m_value.array->at(idx); + try + { + return m_value.array->at(idx); + } + catch (std::out_of_range& e) + { + // create better exception explanation + throw std::out_of_range("array index " + std::to_string(idx) + " is out of range"); + } } else { @@ -2670,9 +2688,10 @@ class basic_json @return reference to the element at key @a key - @throw std::domain_error if JSON is not an object + @throw std::domain_error if the JSON value is not an object; example: + `"cannot use at() with boolean"` @throw std::out_of_range if the key @a key is is not stored in the object; - that is, `find(key) == end()` + that is, `find(key) == end()`; example: `"key "the fast" not found"` @complexity Logarithmic in the size of the container. @@ -2690,7 +2709,15 @@ class basic_json // at only works for objects if (is_object()) { - return m_value.object->at(key); + try + { + return m_value.object->at(key); + } + catch (std::out_of_range& e) + { + // create better exception explanation + throw std::out_of_range("key '" + key + "' not found"); + } } else { @@ -2708,9 +2735,10 @@ class basic_json @return const reference to the element at key @a key - @throw std::domain_error if JSON is not an object + @throw std::domain_error if the JSON value is not an object; example: + `"cannot use at() with boolean"` @throw std::out_of_range if the key @a key is is not stored in the object; - that is, `find(key) == end()` + that is, `find(key) == end()`; example: `"key "the fast" not found"` @complexity Logarithmic in the size of the container. @@ -2728,7 +2756,15 @@ class basic_json // at only works for objects if (is_object()) { - return m_value.object->at(key); + try + { + return m_value.object->at(key); + } + catch (std::out_of_range& e) + { + // create better exception explanation + throw std::out_of_range("key '" + key + "' not found"); + } } else { diff --git a/test/unit.cpp b/test/unit.cpp index e52128ce8..3a89e94fa 100644 --- a/test/unit.cpp +++ b/test/unit.cpp @@ -2662,6 +2662,16 @@ TEST_CASE("element access") { CHECK_THROWS_AS(j.at(7), std::out_of_range); CHECK_THROWS_AS(j_const.at(7), std::out_of_range); + + // exception name + try + { + j.at(7); + } + catch (std::out_of_range& e) + { + CHECK(std::string(e.what()) == "array index 7 is out of range"); + } } SECTION("access on non-array type") @@ -2672,6 +2682,16 @@ TEST_CASE("element access") const json j_nonarray_const(j_nonarray); CHECK_THROWS_AS(j_nonarray.at(0), std::domain_error); CHECK_THROWS_AS(j_nonarray_const.at(0), std::domain_error); + + // exception name + try + { + j_nonarray.at(0); + } + catch (std::domain_error& e) + { + CHECK(std::string(e.what()) == "cannot use at() with null"); + } } SECTION("boolean") @@ -2680,6 +2700,16 @@ TEST_CASE("element access") const json j_nonarray_const(j_nonarray); CHECK_THROWS_AS(j_nonarray.at(0), std::domain_error); CHECK_THROWS_AS(j_nonarray_const.at(0), std::domain_error); + + // exception name + try + { + j_nonarray.at(0); + } + catch (std::domain_error& e) + { + CHECK(std::string(e.what()) == "cannot use at() with boolean"); + } } SECTION("string") @@ -2688,6 +2718,16 @@ TEST_CASE("element access") const json j_nonarray_const(j_nonarray); CHECK_THROWS_AS(j_nonarray.at(0), std::domain_error); CHECK_THROWS_AS(j_nonarray_const.at(0), std::domain_error); + + // exception name + try + { + j_nonarray.at(0); + } + catch (std::domain_error& e) + { + CHECK(std::string(e.what()) == "cannot use at() with string"); + } } SECTION("object") @@ -2696,6 +2736,16 @@ TEST_CASE("element access") const json j_nonarray_const(j_nonarray); CHECK_THROWS_AS(j_nonarray.at(0), std::domain_error); CHECK_THROWS_AS(j_nonarray_const.at(0), std::domain_error); + + // exception name + try + { + j_nonarray.at(0); + } + catch (std::domain_error& e) + { + CHECK(std::string(e.what()) == "cannot use at() with object"); + } } SECTION("number (integer)") @@ -2704,6 +2754,16 @@ TEST_CASE("element access") const json j_nonarray_const(j_nonarray); CHECK_THROWS_AS(j_nonarray.at(0), std::domain_error); CHECK_THROWS_AS(j_nonarray_const.at(0), std::domain_error); + + // exception name + try + { + j_nonarray.at(0); + } + catch (std::domain_error& e) + { + CHECK(std::string(e.what()) == "cannot use at() with number"); + } } SECTION("number (floating-point)") @@ -2712,6 +2772,16 @@ TEST_CASE("element access") const json j_nonarray_const(j_nonarray); CHECK_THROWS_AS(j_nonarray.at(0), std::domain_error); CHECK_THROWS_AS(j_nonarray_const.at(0), std::domain_error); + + // exception name + try + { + j_nonarray.at(0); + } + catch (std::domain_error& e) + { + CHECK(std::string(e.what()) == "cannot use at() with number"); + } } } } @@ -3028,6 +3098,16 @@ TEST_CASE("element access") { CHECK_THROWS_AS(j.at("foo"), std::out_of_range); CHECK_THROWS_AS(j_const.at("foo"), std::out_of_range); + + // exception name + try + { + j.at("foo"); + } + catch (std::out_of_range& e) + { + CHECK(std::string(e.what()) == "key 'foo' not found"); + } } SECTION("access on non-object type") @@ -3038,6 +3118,16 @@ TEST_CASE("element access") const json j_nonobject_const(j_nonobject); CHECK_THROWS_AS(j_nonobject.at("foo"), std::domain_error); CHECK_THROWS_AS(j_nonobject_const.at("foo"), std::domain_error); + + // exception name + try + { + j_nonobject.at("foo"); + } + catch (std::domain_error& e) + { + CHECK(std::string(e.what()) == "cannot use at() with null"); + } } SECTION("boolean") @@ -3046,6 +3136,16 @@ TEST_CASE("element access") const json j_nonobject_const(j_nonobject); CHECK_THROWS_AS(j_nonobject.at("foo"), std::domain_error); CHECK_THROWS_AS(j_nonobject_const.at("foo"), std::domain_error); + + // exception name + try + { + j_nonobject.at("foo"); + } + catch (std::domain_error& e) + { + CHECK(std::string(e.what()) == "cannot use at() with boolean"); + } } SECTION("string") @@ -3054,6 +3154,16 @@ TEST_CASE("element access") const json j_nonobject_const(j_nonobject); CHECK_THROWS_AS(j_nonobject.at("foo"), std::domain_error); CHECK_THROWS_AS(j_nonobject_const.at("foo"), std::domain_error); + + // exception name + try + { + j_nonobject.at("foo"); + } + catch (std::domain_error& e) + { + CHECK(std::string(e.what()) == "cannot use at() with string"); + } } SECTION("array") @@ -3062,6 +3172,16 @@ TEST_CASE("element access") const json j_nonobject_const(j_nonobject); CHECK_THROWS_AS(j_nonobject.at("foo"), std::domain_error); CHECK_THROWS_AS(j_nonobject_const.at("foo"), std::domain_error); + + // exception name + try + { + j_nonobject.at("foo"); + } + catch (std::domain_error& e) + { + CHECK(std::string(e.what()) == "cannot use at() with array"); + } } SECTION("number (integer)") @@ -3070,6 +3190,16 @@ TEST_CASE("element access") const json j_nonobject_const(j_nonobject); CHECK_THROWS_AS(j_nonobject.at("foo"), std::domain_error); CHECK_THROWS_AS(j_nonobject_const.at("foo"), std::domain_error); + + // exception name + try + { + j_nonobject.at("foo"); + } + catch (std::domain_error& e) + { + CHECK(std::string(e.what()) == "cannot use at() with number"); + } } SECTION("number (floating-point)") @@ -3078,6 +3208,16 @@ TEST_CASE("element access") const json j_nonobject_const(j_nonobject); CHECK_THROWS_AS(j_nonobject.at("foo"), std::domain_error); CHECK_THROWS_AS(j_nonobject_const.at("foo"), std::domain_error); + + // exception name + try + { + j_nonobject.at("foo"); + } + catch (std::domain_error& e) + { + CHECK(std::string(e.what()) == "cannot use at() with number"); + } } } } From 00f9296db517b2617f004d78cb35f9fba37a655c Mon Sep 17 00:00:00 2001 From: Niels Date: Tue, 22 Dec 2015 18:07:51 +0100 Subject: [PATCH 30/61] some cleanup for #83 --- src/json.hpp | 4 ++-- src/json.hpp.re2c | 4 ++-- test/unit.cpp | 22 ++++++++++++++++++++++ 3 files changed, 26 insertions(+), 4 deletions(-) diff --git a/src/json.hpp b/src/json.hpp index ee6b1743b..a2760d605 100644 --- a/src/json.hpp +++ b/src/json.hpp @@ -6163,7 +6163,7 @@ class basic_json { private: /// the container to iterate - basic_json& container; + typename basic_json::reference container; /// the type of the iterator to use while iteration using json_iterator = decltype(std::begin(container)); @@ -6236,7 +6236,7 @@ class basic_json public: /// construct iterator wrapper from a container - iterator_wrapper(basic_json& cont) + iterator_wrapper(typename basic_json::reference cont) : container(cont) {} diff --git a/src/json.hpp.re2c b/src/json.hpp.re2c index cea396d62..44fc320ff 100644 --- a/src/json.hpp.re2c +++ b/src/json.hpp.re2c @@ -6163,7 +6163,7 @@ class basic_json { private: /// the container to iterate - basic_json& container; + typename basic_json::reference container; /// the type of the iterator to use while iteration using json_iterator = decltype(std::begin(container)); @@ -6236,7 +6236,7 @@ class basic_json public: /// construct iterator wrapper from a container - iterator_wrapper(basic_json& cont) + iterator_wrapper(typename basic_json::reference cont) : container(cont) {} diff --git a/test/unit.cpp b/test/unit.cpp index 3a89e94fa..c7ce8a478 100644 --- a/test/unit.cpp +++ b/test/unit.cpp @@ -9555,6 +9555,10 @@ TEST_CASE("iterator_wrapper") { CHECK(i.key() == "A"); CHECK(i.value() == json(1)); + + // change the value + i.value() = json(11); + CHECK(i.value() == json(11)); break; } @@ -9562,6 +9566,10 @@ TEST_CASE("iterator_wrapper") { CHECK(i.key() == "B"); CHECK(i.value() == json(2)); + + // change the value + i.value() = json(22); + CHECK(i.value() == json(22)); break; } @@ -9573,6 +9581,9 @@ TEST_CASE("iterator_wrapper") } CHECK(counter == 3); + + // check if values where changed + CHECK(j == json({{"A", 11}, {"B", 22}})); } SECTION("const value") @@ -9690,6 +9701,10 @@ TEST_CASE("iterator_wrapper") { CHECK(i.key() == "0"); CHECK(i.value() == "A"); + + // change the value + i.value() = "AA"; + CHECK(i.value() == "AA"); break; } @@ -9697,6 +9712,10 @@ TEST_CASE("iterator_wrapper") { CHECK(i.key() == "1"); CHECK(i.value() == "B"); + + // change the value + i.value() = "BB"; + CHECK(i.value() == "BB"); break; } @@ -9708,6 +9727,9 @@ TEST_CASE("iterator_wrapper") } CHECK(counter == 3); + + // check if values where changed + CHECK(j == json({"AA", "BB"})); } SECTION("const value") From 70493a10d1e128dc7c614dee869afb5d5f57f495 Mon Sep 17 00:00:00 2001 From: Niels Date: Wed, 23 Dec 2015 08:21:29 +0100 Subject: [PATCH 31/61] iterator_wrapper for const objects (#83) --- README.md | 2 +- src/json.hpp | 72 ++++++---- src/json.hpp.re2c | 72 ++++++---- test/unit.cpp | 341 +++++++++++++++++++++++++++++++++++++++++++++- 4 files changed, 431 insertions(+), 56 deletions(-) diff --git a/README.md b/README.md index 11d350efd..3d5d93bc7 100644 --- a/README.md +++ b/README.md @@ -398,7 +398,7 @@ $ make $ ./json_unit "*" =============================================================================== -All tests passed (3341888 assertions in 28 test cases) +All tests passed (3341947 assertions in 28 test cases) ``` For more information, have a look at the file [.travis.yml](https://github.com/nlohmann/json/blob/master/.travis.yml). diff --git a/src/json.hpp b/src/json.hpp index a2760d605..ef5076533 100644 --- a/src/json.hpp +++ b/src/json.hpp @@ -6152,43 +6152,35 @@ class basic_json } }; - /*! - @brief wrapper to access iterator member functions in range-based for - This class allows to access @ref iterator::key() and @ref iterator::value() - during range-based for loops. In these loops, a reference to the JSON - values is returned, so there is no access to the underlying iterator. - */ - class iterator_wrapper + private: + /// proxy class for the iterator_wrapper functions + template + class iteration_proxy { private: - /// the container to iterate - typename basic_json::reference container; - /// the type of the iterator to use while iteration - using json_iterator = decltype(std::begin(container)); - - /// internal iterator wrapper - class iterator_wrapper_internal + /// helper class for iteration + class iteration_proxy_internal { private: /// the iterator - json_iterator anchor; + IteratorType anchor; /// an index for arrays size_t array_index = 0; public: - /// construct wrapper given an iterator - iterator_wrapper_internal(json_iterator i) : anchor(i) + iteration_proxy_internal(IteratorType it) + : anchor(it) {} /// dereference operator (needed for range-based for) - iterator_wrapper_internal& operator*() + iteration_proxy_internal& operator*() { return *this; } /// increment operator (needed for range-based for) - iterator_wrapper_internal& operator++() + iteration_proxy_internal& operator++() { ++anchor; ++array_index; @@ -6197,7 +6189,7 @@ class basic_json } /// inequality operator (needed for range-based for) - bool operator!= (const iterator_wrapper_internal& o) + bool operator!= (const iteration_proxy_internal& o) { return anchor != o.anchor; } @@ -6228,31 +6220,57 @@ class basic_json } /// return value of the iterator - typename json_iterator::reference value() const + typename IteratorType::reference value() const { return anchor.value(); } }; + /// the container to iterate + typename IteratorType::reference container; + public: - /// construct iterator wrapper from a container - iterator_wrapper(typename basic_json::reference cont) + /// construct iteration proxy from a container + iteration_proxy(typename IteratorType::reference cont) : container(cont) {} /// return iterator begin (needed for range-based for) - iterator_wrapper_internal begin() + iteration_proxy_internal begin() { - return iterator_wrapper_internal(container.begin()); + return iteration_proxy_internal(container.begin()); } /// return iterator end (needed for range-based for) - iterator_wrapper_internal end() + iteration_proxy_internal end() { - return iterator_wrapper_internal(container.end()); + return iteration_proxy_internal(container.end()); } }; + public: + /*! + @brief wrapper to access iterator member functions in range-based for + + This functuion allows to access @ref iterator::key() and @ref + iterator::value() during range-based for loops. In these loops, a reference + to the JSON values is returned, so there is no access to the underlying + iterator. + */ + static iteration_proxy iterator_wrapper(reference cont) + { + return iteration_proxy(cont); + } + + /*! + @copydoc iterator_wrapper(reference) + */ + static iteration_proxy iterator_wrapper(const_reference cont) + { + return iteration_proxy(cont); + } + + private: ////////////////////// // lexer and parser // diff --git a/src/json.hpp.re2c b/src/json.hpp.re2c index 44fc320ff..d3d9f15a9 100644 --- a/src/json.hpp.re2c +++ b/src/json.hpp.re2c @@ -6152,43 +6152,35 @@ class basic_json } }; - /*! - @brief wrapper to access iterator member functions in range-based for - This class allows to access @ref iterator::key() and @ref iterator::value() - during range-based for loops. In these loops, a reference to the JSON - values is returned, so there is no access to the underlying iterator. - */ - class iterator_wrapper + private: + /// proxy class for the iterator_wrapper functions + template + class iteration_proxy { private: - /// the container to iterate - typename basic_json::reference container; - /// the type of the iterator to use while iteration - using json_iterator = decltype(std::begin(container)); - - /// internal iterator wrapper - class iterator_wrapper_internal + /// helper class for iteration + class iteration_proxy_internal { private: /// the iterator - json_iterator anchor; + IteratorType anchor; /// an index for arrays size_t array_index = 0; public: - /// construct wrapper given an iterator - iterator_wrapper_internal(json_iterator i) : anchor(i) + iteration_proxy_internal(IteratorType it) + : anchor(it) {} /// dereference operator (needed for range-based for) - iterator_wrapper_internal& operator*() + iteration_proxy_internal& operator*() { return *this; } /// increment operator (needed for range-based for) - iterator_wrapper_internal& operator++() + iteration_proxy_internal& operator++() { ++anchor; ++array_index; @@ -6197,7 +6189,7 @@ class basic_json } /// inequality operator (needed for range-based for) - bool operator!= (const iterator_wrapper_internal& o) + bool operator!= (const iteration_proxy_internal& o) { return anchor != o.anchor; } @@ -6228,31 +6220,57 @@ class basic_json } /// return value of the iterator - typename json_iterator::reference value() const + typename IteratorType::reference value() const { return anchor.value(); } }; + /// the container to iterate + typename IteratorType::reference container; + public: - /// construct iterator wrapper from a container - iterator_wrapper(typename basic_json::reference cont) + /// construct iteration proxy from a container + iteration_proxy(typename IteratorType::reference cont) : container(cont) {} /// return iterator begin (needed for range-based for) - iterator_wrapper_internal begin() + iteration_proxy_internal begin() { - return iterator_wrapper_internal(container.begin()); + return iteration_proxy_internal(container.begin()); } /// return iterator end (needed for range-based for) - iterator_wrapper_internal end() + iteration_proxy_internal end() { - return iterator_wrapper_internal(container.end()); + return iteration_proxy_internal(container.end()); } }; + public: + /*! + @brief wrapper to access iterator member functions in range-based for + + This functuion allows to access @ref iterator::key() and @ref + iterator::value() during range-based for loops. In these loops, a reference + to the JSON values is returned, so there is no access to the underlying + iterator. + */ + static iteration_proxy iterator_wrapper(reference cont) + { + return iteration_proxy(cont); + } + + /*! + @copydoc iterator_wrapper(reference) + */ + static iteration_proxy iterator_wrapper(const_reference cont) + { + return iteration_proxy(cont); + } + + private: ////////////////////// // lexer and parser // diff --git a/test/unit.cpp b/test/unit.cpp index c7ce8a478..7b4323d39 100644 --- a/test/unit.cpp +++ b/test/unit.cpp @@ -9653,6 +9653,141 @@ TEST_CASE("iterator_wrapper") } } + SECTION("const object") + { + SECTION("value") + { + const json j = {{"A", 1}, {"B", 2}}; + int counter = 1; + + for (auto i : json::iterator_wrapper(j)) + { + switch (counter++) + { + case 1: + { + CHECK(i.key() == "A"); + CHECK(i.value() == json(1)); + break; + } + + case 2: + { + CHECK(i.key() == "B"); + CHECK(i.value() == json(2)); + break; + } + + default: + { + break; + } + } + } + + CHECK(counter == 3); + } + + SECTION("reference") + { + const json j = {{"A", 1}, {"B", 2}}; + int counter = 1; + + for (auto& i : json::iterator_wrapper(j)) + { + switch (counter++) + { + case 1: + { + CHECK(i.key() == "A"); + CHECK(i.value() == json(1)); + break; + } + + case 2: + { + CHECK(i.key() == "B"); + CHECK(i.value() == json(2)); + break; + } + + default: + { + break; + } + } + } + + CHECK(counter == 3); + } + + SECTION("const value") + { + const json j = {{"A", 1}, {"B", 2}}; + int counter = 1; + + for (const auto i : json::iterator_wrapper(j)) + { + switch (counter++) + { + case 1: + { + CHECK(i.key() == "A"); + CHECK(i.value() == json(1)); + break; + } + + case 2: + { + CHECK(i.key() == "B"); + CHECK(i.value() == json(2)); + break; + } + + default: + { + break; + } + } + } + + CHECK(counter == 3); + } + + SECTION("const reference") + { + const json j = {{"A", 1}, {"B", 2}}; + int counter = 1; + + for (const auto& i : json::iterator_wrapper(j)) + { + switch (counter++) + { + case 1: + { + CHECK(i.key() == "A"); + CHECK(i.value() == json(1)); + break; + } + + case 2: + { + CHECK(i.key() == "B"); + CHECK(i.value() == json(2)); + break; + } + + default: + { + break; + } + } + } + + CHECK(counter == 3); + } + } + SECTION("array") { SECTION("value") @@ -9799,6 +9934,141 @@ TEST_CASE("iterator_wrapper") } } + SECTION("const array") + { + SECTION("value") + { + const json j = {"A", "B"}; + int counter = 1; + + for (auto i : json::iterator_wrapper(j)) + { + switch (counter++) + { + case 1: + { + CHECK(i.key() == "0"); + CHECK(i.value() == "A"); + break; + } + + case 2: + { + CHECK(i.key() == "1"); + CHECK(i.value() == "B"); + break; + } + + default: + { + break; + } + } + } + + CHECK(counter == 3); + } + + SECTION("reference") + { + const json j = {"A", "B"}; + int counter = 1; + + for (auto& i : json::iterator_wrapper(j)) + { + switch (counter++) + { + case 1: + { + CHECK(i.key() == "0"); + CHECK(i.value() == "A"); + break; + } + + case 2: + { + CHECK(i.key() == "1"); + CHECK(i.value() == "B"); + break; + } + + default: + { + break; + } + } + } + + CHECK(counter == 3); + } + + SECTION("const value") + { + const json j = {"A", "B"}; + int counter = 1; + + for (const auto i : json::iterator_wrapper(j)) + { + switch (counter++) + { + case 1: + { + CHECK(i.key() == "0"); + CHECK(i.value() == "A"); + break; + } + + case 2: + { + CHECK(i.key() == "1"); + CHECK(i.value() == "B"); + break; + } + + default: + { + break; + } + } + } + + CHECK(counter == 3); + } + + SECTION("const reference") + { + const json j = {"A", "B"}; + int counter = 1; + + for (const auto& i : json::iterator_wrapper(j)) + { + switch (counter++) + { + case 1: + { + CHECK(i.key() == "0"); + CHECK(i.value() == "A"); + break; + } + + case 2: + { + CHECK(i.key() == "1"); + CHECK(i.value() == "B"); + break; + } + + default: + { + break; + } + } + } + + CHECK(counter == 3); + } + } + SECTION("primitive") { SECTION("value") @@ -9826,9 +10096,15 @@ TEST_CASE("iterator_wrapper") ++counter; CHECK(i.key() == ""); CHECK(i.value() == json(1)); + + // change value + i.value() = json(2); } CHECK(counter == 2); + + // check if value has changed + CHECK(j == json(2)); } SECTION("const value") @@ -9846,7 +10122,7 @@ TEST_CASE("iterator_wrapper") CHECK(counter == 2); } - SECTION("reference") + SECTION("const reference") { json j = 1; int counter = 1; @@ -9861,6 +10137,69 @@ TEST_CASE("iterator_wrapper") CHECK(counter == 2); } } + + SECTION("const primitive") + { + SECTION("value") + { + const json j = 1; + int counter = 1; + + for (auto i : json::iterator_wrapper(j)) + { + ++counter; + CHECK(i.key() == ""); + CHECK(i.value() == json(1)); + } + + CHECK(counter == 2); + } + + SECTION("reference") + { + const json j = 1; + int counter = 1; + + for (auto& i : json::iterator_wrapper(j)) + { + ++counter; + CHECK(i.key() == ""); + CHECK(i.value() == json(1)); + } + + CHECK(counter == 2); + } + + SECTION("const value") + { + const json j = 1; + int counter = 1; + + for (const auto i : json::iterator_wrapper(j)) + { + ++counter; + CHECK(i.key() == ""); + CHECK(i.value() == json(1)); + } + + CHECK(counter == 2); + } + + SECTION("const reference") + { + const json j = 1; + int counter = 1; + + for (const auto& i : json::iterator_wrapper(j)) + { + ++counter; + CHECK(i.key() == ""); + CHECK(i.value() == json(1)); + } + + CHECK(counter == 2); + } + } } TEST_CASE("compliance tests from json.org") From fcbd984e0fcfe1fae75ec6338d6d08f3e93f4c34 Mon Sep 17 00:00:00 2001 From: Niels Date: Wed, 23 Dec 2015 08:44:34 +0100 Subject: [PATCH 32/61] cleanup --- src/json.hpp | 48 +++++++++++++++++++++++++---------------------- src/json.hpp.re2c | 48 +++++++++++++++++++++++++---------------------- 2 files changed, 52 insertions(+), 44 deletions(-) diff --git a/src/json.hpp b/src/json.hpp index ef5076533..54b802c22 100644 --- a/src/json.hpp +++ b/src/json.hpp @@ -3767,6 +3767,32 @@ class basic_json return const_reverse_iterator(cbegin()); } + private: + // forward declaration + template class iteration_proxy; + + public: + /*! + @brief wrapper to access iterator member functions in range-based for + + This functuion allows to access @ref iterator::key() and @ref + iterator::value() during range-based for loops. In these loops, a reference + to the JSON values is returned, so there is no access to the underlying + iterator. + */ + static iteration_proxy iterator_wrapper(reference cont) + { + return iteration_proxy(cont); + } + + /*! + @copydoc iterator_wrapper(reference) + */ + static iteration_proxy iterator_wrapper(const_reference cont) + { + return iteration_proxy(cont); + } + /// @} @@ -6248,28 +6274,6 @@ class basic_json } }; - public: - /*! - @brief wrapper to access iterator member functions in range-based for - - This functuion allows to access @ref iterator::key() and @ref - iterator::value() during range-based for loops. In these loops, a reference - to the JSON values is returned, so there is no access to the underlying - iterator. - */ - static iteration_proxy iterator_wrapper(reference cont) - { - return iteration_proxy(cont); - } - - /*! - @copydoc iterator_wrapper(reference) - */ - static iteration_proxy iterator_wrapper(const_reference cont) - { - return iteration_proxy(cont); - } - private: ////////////////////// diff --git a/src/json.hpp.re2c b/src/json.hpp.re2c index d3d9f15a9..053713823 100644 --- a/src/json.hpp.re2c +++ b/src/json.hpp.re2c @@ -3767,6 +3767,32 @@ class basic_json return const_reverse_iterator(cbegin()); } + private: + // forward declaration + template class iteration_proxy; + + public: + /*! + @brief wrapper to access iterator member functions in range-based for + + This functuion allows to access @ref iterator::key() and @ref + iterator::value() during range-based for loops. In these loops, a reference + to the JSON values is returned, so there is no access to the underlying + iterator. + */ + static iteration_proxy iterator_wrapper(reference cont) + { + return iteration_proxy(cont); + } + + /*! + @copydoc iterator_wrapper(reference) + */ + static iteration_proxy iterator_wrapper(const_reference cont) + { + return iteration_proxy(cont); + } + /// @} @@ -6248,28 +6274,6 @@ class basic_json } }; - public: - /*! - @brief wrapper to access iterator member functions in range-based for - - This functuion allows to access @ref iterator::key() and @ref - iterator::value() during range-based for loops. In these loops, a reference - to the JSON values is returned, so there is no access to the underlying - iterator. - */ - static iteration_proxy iterator_wrapper(reference cont) - { - return iteration_proxy(cont); - } - - /*! - @copydoc iterator_wrapper(reference) - */ - static iteration_proxy iterator_wrapper(const_reference cont) - { - return iteration_proxy(cont); - } - private: ////////////////////// From 8620583cf97041ae5cc3624649d6d5aa9cb53090 Mon Sep 17 00:00:00 2001 From: Niels Date: Wed, 23 Dec 2015 12:05:57 +0100 Subject: [PATCH 33/61] cleanup --- src/json.hpp | 203 ++++++++++++++++++++++++---------------------- src/json.hpp.re2c | 203 ++++++++++++++++++++++++---------------------- 2 files changed, 208 insertions(+), 198 deletions(-) diff --git a/src/json.hpp b/src/json.hpp index 54b802c22..b483ca6c9 100644 --- a/src/json.hpp +++ b/src/json.hpp @@ -3779,6 +3779,9 @@ class basic_json iterator::value() during range-based for loops. In these loops, a reference to the JSON values is returned, so there is no access to the underlying iterator. + + @note The name of this function is not yet final and may change in the + future. */ static iteration_proxy iterator_wrapper(reference cont) { @@ -5432,6 +5435,100 @@ class basic_json {} }; + /// proxy class for the iterator_wrapper functions + template + class iteration_proxy + { + private: + /// helper class for iteration + class iteration_proxy_internal + { + private: + /// the iterator + IteratorType anchor; + /// an index for arrays (used to create key names) + size_t array_index = 0; + + public: + iteration_proxy_internal(IteratorType it) + : anchor(it) + {} + + /// dereference operator (needed for range-based for) + iteration_proxy_internal& operator*() + { + return *this; + } + + /// increment operator (needed for range-based for) + iteration_proxy_internal& operator++() + { + ++anchor; + ++array_index; + + return *this; + } + + /// inequality operator (needed for range-based for) + bool operator!= (const iteration_proxy_internal& o) + { + return anchor != o.anchor; + } + + /// return key of the iterator + typename basic_json::string_t key() const + { + switch (anchor.m_object->type()) + { + // use integer array index as key + case value_t::array: + { + return std::to_string(array_index); + } + + // use key from the object + case value_t::object: + { + return anchor.key(); + } + + // use an empty key for all primitive types + default: + { + return ""; + } + } + } + + /// return value of the iterator + typename IteratorType::reference value() const + { + return anchor.value(); + } + }; + + /// the container to iterate + typename IteratorType::reference container; + + public: + /// construct iteration proxy from a container + iteration_proxy(typename IteratorType::reference cont) + : container(cont) + {} + + /// return iterator begin (needed for range-based for) + iteration_proxy_internal begin() + { + return iteration_proxy_internal(container.begin()); + } + + /// return iterator end (needed for range-based for) + iteration_proxy_internal end() + { + return iteration_proxy_internal(container.end()); + } + }; + public: /*! @brief a const random access iterator for the @ref basic_json class @@ -5959,7 +6056,8 @@ class basic_json iterator() = default; /// constructor for a given JSON instance - iterator(pointer object) noexcept : base_iterator(object) + iterator(pointer object) noexcept + : base_iterator(object) {} /// copy constructor @@ -6097,10 +6195,13 @@ class basic_json /// create reverse iterator from iterator json_reverse_iterator(const typename base_iterator::iterator_type& it) - : base_iterator(it) {} + : base_iterator(it) + {} /// create reverse iterator from base class - json_reverse_iterator(const base_iterator& it) : base_iterator(it) {} + json_reverse_iterator(const base_iterator& it) + : base_iterator(it) + {} /// post-increment (it++) json_reverse_iterator operator++(int) @@ -6179,102 +6280,6 @@ class basic_json }; - private: - /// proxy class for the iterator_wrapper functions - template - class iteration_proxy - { - private: - /// helper class for iteration - class iteration_proxy_internal - { - private: - /// the iterator - IteratorType anchor; - /// an index for arrays - size_t array_index = 0; - - public: - iteration_proxy_internal(IteratorType it) - : anchor(it) - {} - - /// dereference operator (needed for range-based for) - iteration_proxy_internal& operator*() - { - return *this; - } - - /// increment operator (needed for range-based for) - iteration_proxy_internal& operator++() - { - ++anchor; - ++array_index; - - return *this; - } - - /// inequality operator (needed for range-based for) - bool operator!= (const iteration_proxy_internal& o) - { - return anchor != o.anchor; - } - - /// return key of the iterator - typename basic_json::string_t key() const - { - switch (anchor.m_object->type()) - { - // use integer array index as key - case value_t::array: - { - return std::to_string(array_index); - } - - // use key from the object - case value_t::object: - { - return anchor.key(); - } - - // use an empty key for all primitive types - default: - { - return ""; - } - } - } - - /// return value of the iterator - typename IteratorType::reference value() const - { - return anchor.value(); - } - }; - - /// the container to iterate - typename IteratorType::reference container; - - public: - /// construct iteration proxy from a container - iteration_proxy(typename IteratorType::reference cont) - : container(cont) - {} - - /// return iterator begin (needed for range-based for) - iteration_proxy_internal begin() - { - return iteration_proxy_internal(container.begin()); - } - - /// return iterator end (needed for range-based for) - iteration_proxy_internal end() - { - return iteration_proxy_internal(container.end()); - } - }; - - private: ////////////////////// // lexer and parser // diff --git a/src/json.hpp.re2c b/src/json.hpp.re2c index 053713823..2feab1040 100644 --- a/src/json.hpp.re2c +++ b/src/json.hpp.re2c @@ -3779,6 +3779,9 @@ class basic_json iterator::value() during range-based for loops. In these loops, a reference to the JSON values is returned, so there is no access to the underlying iterator. + + @note The name of this function is not yet final and may change in the + future. */ static iteration_proxy iterator_wrapper(reference cont) { @@ -5432,6 +5435,100 @@ class basic_json {} }; + /// proxy class for the iterator_wrapper functions + template + class iteration_proxy + { + private: + /// helper class for iteration + class iteration_proxy_internal + { + private: + /// the iterator + IteratorType anchor; + /// an index for arrays (used to create key names) + size_t array_index = 0; + + public: + iteration_proxy_internal(IteratorType it) + : anchor(it) + {} + + /// dereference operator (needed for range-based for) + iteration_proxy_internal& operator*() + { + return *this; + } + + /// increment operator (needed for range-based for) + iteration_proxy_internal& operator++() + { + ++anchor; + ++array_index; + + return *this; + } + + /// inequality operator (needed for range-based for) + bool operator!= (const iteration_proxy_internal& o) + { + return anchor != o.anchor; + } + + /// return key of the iterator + typename basic_json::string_t key() const + { + switch (anchor.m_object->type()) + { + // use integer array index as key + case value_t::array: + { + return std::to_string(array_index); + } + + // use key from the object + case value_t::object: + { + return anchor.key(); + } + + // use an empty key for all primitive types + default: + { + return ""; + } + } + } + + /// return value of the iterator + typename IteratorType::reference value() const + { + return anchor.value(); + } + }; + + /// the container to iterate + typename IteratorType::reference container; + + public: + /// construct iteration proxy from a container + iteration_proxy(typename IteratorType::reference cont) + : container(cont) + {} + + /// return iterator begin (needed for range-based for) + iteration_proxy_internal begin() + { + return iteration_proxy_internal(container.begin()); + } + + /// return iterator end (needed for range-based for) + iteration_proxy_internal end() + { + return iteration_proxy_internal(container.end()); + } + }; + public: /*! @brief a const random access iterator for the @ref basic_json class @@ -5959,7 +6056,8 @@ class basic_json iterator() = default; /// constructor for a given JSON instance - iterator(pointer object) noexcept : base_iterator(object) + iterator(pointer object) noexcept + : base_iterator(object) {} /// copy constructor @@ -6097,10 +6195,13 @@ class basic_json /// create reverse iterator from iterator json_reverse_iterator(const typename base_iterator::iterator_type& it) - : base_iterator(it) {} + : base_iterator(it) + {} /// create reverse iterator from base class - json_reverse_iterator(const base_iterator& it) : base_iterator(it) {} + json_reverse_iterator(const base_iterator& it) + : base_iterator(it) + {} /// post-increment (it++) json_reverse_iterator operator++(int) @@ -6179,102 +6280,6 @@ class basic_json }; - private: - /// proxy class for the iterator_wrapper functions - template - class iteration_proxy - { - private: - /// helper class for iteration - class iteration_proxy_internal - { - private: - /// the iterator - IteratorType anchor; - /// an index for arrays - size_t array_index = 0; - - public: - iteration_proxy_internal(IteratorType it) - : anchor(it) - {} - - /// dereference operator (needed for range-based for) - iteration_proxy_internal& operator*() - { - return *this; - } - - /// increment operator (needed for range-based for) - iteration_proxy_internal& operator++() - { - ++anchor; - ++array_index; - - return *this; - } - - /// inequality operator (needed for range-based for) - bool operator!= (const iteration_proxy_internal& o) - { - return anchor != o.anchor; - } - - /// return key of the iterator - typename basic_json::string_t key() const - { - switch (anchor.m_object->type()) - { - // use integer array index as key - case value_t::array: - { - return std::to_string(array_index); - } - - // use key from the object - case value_t::object: - { - return anchor.key(); - } - - // use an empty key for all primitive types - default: - { - return ""; - } - } - } - - /// return value of the iterator - typename IteratorType::reference value() const - { - return anchor.value(); - } - }; - - /// the container to iterate - typename IteratorType::reference container; - - public: - /// construct iteration proxy from a container - iteration_proxy(typename IteratorType::reference cont) - : container(cont) - {} - - /// return iterator begin (needed for range-based for) - iteration_proxy_internal begin() - { - return iteration_proxy_internal(container.begin()); - } - - /// return iterator end (needed for range-based for) - iteration_proxy_internal end() - { - return iteration_proxy_internal(container.end()); - } - }; - - private: ////////////////////// // lexer and parser // From 76e5e29eda2ff9d065e52d5cfe06ced51bd3c253 Mon Sep 17 00:00:00 2001 From: Niels Date: Fri, 25 Dec 2015 11:46:18 +0100 Subject: [PATCH 34/61] overworked exceptions and tests (#160) --- README.md | 4 +- src/json.hpp | 90 ++++--- src/json.hpp.re2c | 90 ++++--- test/unit.cpp | 612 ++++++++++++++++++++++++++++++++++++---------- 4 files changed, 595 insertions(+), 201 deletions(-) diff --git a/README.md b/README.md index 3d5d93bc7..42c49dd2f 100644 --- a/README.md +++ b/README.md @@ -42,8 +42,8 @@ to the files you want to use JSON objects. That's it. Do not forget to set the n Though it's 2015 already, the support for C++11 is still a bit sparse. Currently, the following compilers are known to work: -- GCC 4.9 - 5.2 (and possibly later) -- Clang 3.4 - 3.7 (and possibly later) +- GCC 4.9 - 6.0 (and possibly later) +- Clang 3.4 - 3.8 (and possibly later) - Microsoft Visual C++ 14.0 RC (and possibly later) I would be happy to learn about other compilers/versions. diff --git a/src/json.hpp b/src/json.hpp index b483ca6c9..b5db4fe6d 100644 --- a/src/json.hpp +++ b/src/json.hpp @@ -1359,7 +1359,8 @@ class basic_json @throw std::domain_error if @a type_deduction is `false`, @a manual_type is `value_t::object`, but @a init contains an element which is not a pair - whose first element is a string + whose first element is a string; example: `"cannot create object from + initializer list"` @complexity Linear in the size of the initializer list @a init. @@ -1552,11 +1553,13 @@ class basic_json @param[in] last end of the range to copy from (excluded) @throw std::domain_error if iterators are not compatible; that is, do not - belong to the same JSON value + belong to the same JSON value; example: `"iterators are not compatible"` @throw std::out_of_range if iterators are for a primitive type (number, - boolean, or string) where an out of range error can be detected easily + boolean, or string) where an out of range error can be detected easily; + example: `"iterators out of range"` @throw std::bad_alloc if allocation for object, array, or string fails - @throw std::domain_error if called with a null value + @throw std::domain_error if called with a null value; example: `"cannot use + construct with iterators from null"` @complexity Linear in distance between @a first and @a last. @@ -2412,7 +2415,7 @@ class basic_json @return copy of the JSON value, converted to type @a ValueType @throw std::domain_error in case passed type @a ValueType is incompatible - to JSON + to JSON; example: `"type must be object, but is null"` @complexity Linear in the size of the JSON value. @@ -2785,7 +2788,8 @@ class basic_json @return reference to the element at index @a idx - @throw std::domain_error if JSON is not an array or null + @throw std::domain_error if JSON is not an array or null; example: `"cannot + use operator[] with null"` @complexity Constant if @a idx is in the range of the array. Otherwise linear in `idx - size()`. @@ -2830,7 +2834,8 @@ class basic_json @return const reference to the element at index @a idx - @throw std::domain_error if JSON is not an array + @throw std::domain_error if JSON is not an array; example: `"cannot use + operator[] with null"` @complexity Constant. @@ -2865,7 +2870,8 @@ class basic_json @return reference to the element at key @a key - @throw std::domain_error if JSON is not an object or null + @throw std::domain_error if JSON is not an object or null; example: + `"cannot use operator[] with null"` @complexity Logarithmic in the size of the container. @@ -2911,7 +2917,8 @@ class basic_json @return const reference to the element at key @a key - @throw std::domain_error if JSON is not an object + @throw std::domain_error if JSON is not an object; example: `"cannot use + operator[] with null"` @complexity Logarithmic in the size of the container. @@ -2952,7 +2959,8 @@ class basic_json @return reference to the element at key @a key - @throw std::domain_error if JSON is not an object or null + @throw std::domain_error if JSON is not an object or null; example: + `"cannot use operator[] with null"` @complexity Logarithmic in the size of the container. @@ -3001,7 +3009,8 @@ class basic_json @return const reference to the element at key @a key - @throw std::domain_error if JSON is not an object + @throw std::domain_error if JSON is not an object; example: `"cannot use + operator[] with null"` @complexity Logarithmic in the size of the container. @@ -3061,7 +3070,8 @@ class basic_json @return copy of the element at key @a key or @a default_value if @a key is not found - @throw std::domain_error if JSON is not an object + @throw std::domain_error if JSON is not an object; example: `"cannot use + value() with null"` @complexity Logarithmic in the size of the container. @@ -3199,11 +3209,13 @@ class basic_json @tparam InteratorType an @ref iterator or @ref const_iterator - @throw std::domain_error if called on a `null` value + @throw std::domain_error if called on a `null` value; example: `"cannot use + erase() with null"` @throw std::domain_error if called on an iterator which does not belong to - the current JSON value + the current JSON value; example: `"iterator does not fit current value"` @throw std::out_of_range if called on a primitive type with invalid - iterator (i.e., any iterator which is not end()) + iterator (i.e., any iterator which is not end()); example: `"iterator out + of range"` @complexity The complexity depends on the type: - objects: amortized constant @@ -3300,11 +3312,13 @@ class basic_json @tparam InteratorType an @ref iterator or @ref const_iterator - @throw std::domain_error if called on a `null` value + @throw std::domain_error if called on a `null` value; example: `"cannot use + erase() with null"` @throw std::domain_error if called on iterators which does not belong to - the current JSON value + the current JSON value; example: `"iterators do not fit current value"` @throw std::out_of_range if called on a primitive type with invalid - iterators (i.e., if `first != begin()` and `last != end()`) + iterators (i.e., if `first != begin()` and `last != end()`); example: + `"iterators out of range"` @complexity The complexity depends on the type: - objects: `log(size()) + std::distance(first, last)` @@ -3378,7 +3392,7 @@ class basic_json default: { - throw std::domain_error("cannot use erase with " + type_name()); + throw std::domain_error("cannot use erase() with " + type_name()); } } @@ -3396,7 +3410,8 @@ class basic_json type, the return value will always be `0` (@a key was not found) or `1` (@a key was found). - @throw std::domain_error when called on a type other than JSON object + @throw std::domain_error when called on a type other than JSON object; + example: `"cannot use erase() with null"` @complexity `log(size()) + count(key)` @@ -3430,8 +3445,10 @@ class basic_json @param[in] idx index of the element to remove - @throw std::domain_error when called on a type other than JSON array - @throw std::out_of_range when `idx >= size()` + @throw std::domain_error when called on a type other than JSON array; + example: `"cannot use erase() with null"` + @throw std::out_of_range when `idx >= size()`; example: `"index out of + range"` @complexity Linear in distance between @a idx and the end of the container. @@ -4065,7 +4082,8 @@ class basic_json @param val the value to add to the JSON array - @throw std::domain_error when called on a type other than JSON array or null + @throw std::domain_error when called on a type other than JSON array or + null; example: `"cannot use push_back() with number"` @complexity Amortized constant. @@ -4149,7 +4167,7 @@ class basic_json @param[in] val the value to add to the JSON object @throw std::domain_error when called on a type other than JSON object or - null + null; example: `"cannot use push_back() with number"` @complexity Logarithmic in the size of the container, O(log(`size()`)). @@ -4199,7 +4217,8 @@ class basic_json @return iterator pointing to the inserted @a val. @throw std::domain_error if called on JSON values other than arrays - @throw std::domain_error if @a pos is not an iterator of *this + @throw std::domain_error if @a pos is not an iterator of *this; example: + `"iterator does not fit current value"` @complexity Constant plus linear in the distance between pos and end of the container. @@ -4252,7 +4271,8 @@ class basic_json `cnt==0` @throw std::domain_error if called on JSON values other than arrays - @throw std::domain_error if @a pos is not an iterator of *this + @throw std::domain_error if @a pos is not an iterator of *this; example: + `"iterator does not fit current value"` @complexity Linear in @a cnt plus linear in the distance between @a pos and end of the container. @@ -4294,11 +4314,14 @@ class basic_json @param[in] last end of the range of elements to insert @throw std::domain_error if called on JSON values other than arrays - @throw std::domain_error if @a pos is not an iterator of *this + @throw std::domain_error if @a pos is not an iterator of *this; example: + `"iterator does not fit current value"` @throw std::domain_error if @a first and @a last do not belong to the same - JSON value + JSON value; example: `"iterators do not fit"` @throw std::domain_error if @a first or @a last are iterators into - container for which insert is called + container for which insert is called; example: `"passed iterators may not + belong to container"` + @return iterator pointing to the first element inserted, or @a pos if `first==last` @@ -4352,7 +4375,8 @@ class basic_json @param[in] ilist initializer list to insert the values from @throw std::domain_error if called on JSON values other than arrays - @throw std::domain_error if @a pos is not an iterator of *this + @throw std::domain_error if @a pos is not an iterator of *this; example: + `"iterator does not fit current value"` @return iterator pointing to the first element inserted, or @a pos if `ilist` is empty @@ -5870,7 +5894,7 @@ class basic_json { case basic_json::value_t::object: { - throw std::domain_error("cannot use operator< for object iterators"); + throw std::domain_error("cannot compare order of object iterators"); } case basic_json::value_t::array: @@ -5910,7 +5934,7 @@ class basic_json { case basic_json::value_t::object: { - throw std::domain_error("cannot use operator+= for object iterators"); + throw std::domain_error("cannot use offsets with object iterators"); } case basic_json::value_t::array: @@ -5958,7 +5982,7 @@ class basic_json { case basic_json::value_t::object: { - throw std::domain_error("cannot use operator- for object iterators"); + throw std::domain_error("cannot use offsets with object iterators"); } case basic_json::value_t::array: diff --git a/src/json.hpp.re2c b/src/json.hpp.re2c index 2feab1040..24ab27572 100644 --- a/src/json.hpp.re2c +++ b/src/json.hpp.re2c @@ -1359,7 +1359,8 @@ class basic_json @throw std::domain_error if @a type_deduction is `false`, @a manual_type is `value_t::object`, but @a init contains an element which is not a pair - whose first element is a string + whose first element is a string; example: `"cannot create object from + initializer list"` @complexity Linear in the size of the initializer list @a init. @@ -1552,11 +1553,13 @@ class basic_json @param[in] last end of the range to copy from (excluded) @throw std::domain_error if iterators are not compatible; that is, do not - belong to the same JSON value + belong to the same JSON value; example: `"iterators are not compatible"` @throw std::out_of_range if iterators are for a primitive type (number, - boolean, or string) where an out of range error can be detected easily + boolean, or string) where an out of range error can be detected easily; + example: `"iterators out of range"` @throw std::bad_alloc if allocation for object, array, or string fails - @throw std::domain_error if called with a null value + @throw std::domain_error if called with a null value; example: `"cannot use + construct with iterators from null"` @complexity Linear in distance between @a first and @a last. @@ -2412,7 +2415,7 @@ class basic_json @return copy of the JSON value, converted to type @a ValueType @throw std::domain_error in case passed type @a ValueType is incompatible - to JSON + to JSON; example: `"type must be object, but is null"` @complexity Linear in the size of the JSON value. @@ -2785,7 +2788,8 @@ class basic_json @return reference to the element at index @a idx - @throw std::domain_error if JSON is not an array or null + @throw std::domain_error if JSON is not an array or null; example: `"cannot + use operator[] with null"` @complexity Constant if @a idx is in the range of the array. Otherwise linear in `idx - size()`. @@ -2830,7 +2834,8 @@ class basic_json @return const reference to the element at index @a idx - @throw std::domain_error if JSON is not an array + @throw std::domain_error if JSON is not an array; example: `"cannot use + operator[] with null"` @complexity Constant. @@ -2865,7 +2870,8 @@ class basic_json @return reference to the element at key @a key - @throw std::domain_error if JSON is not an object or null + @throw std::domain_error if JSON is not an object or null; example: + `"cannot use operator[] with null"` @complexity Logarithmic in the size of the container. @@ -2911,7 +2917,8 @@ class basic_json @return const reference to the element at key @a key - @throw std::domain_error if JSON is not an object + @throw std::domain_error if JSON is not an object; example: `"cannot use + operator[] with null"` @complexity Logarithmic in the size of the container. @@ -2952,7 +2959,8 @@ class basic_json @return reference to the element at key @a key - @throw std::domain_error if JSON is not an object or null + @throw std::domain_error if JSON is not an object or null; example: + `"cannot use operator[] with null"` @complexity Logarithmic in the size of the container. @@ -3001,7 +3009,8 @@ class basic_json @return const reference to the element at key @a key - @throw std::domain_error if JSON is not an object + @throw std::domain_error if JSON is not an object; example: `"cannot use + operator[] with null"` @complexity Logarithmic in the size of the container. @@ -3061,7 +3070,8 @@ class basic_json @return copy of the element at key @a key or @a default_value if @a key is not found - @throw std::domain_error if JSON is not an object + @throw std::domain_error if JSON is not an object; example: `"cannot use + value() with null"` @complexity Logarithmic in the size of the container. @@ -3199,11 +3209,13 @@ class basic_json @tparam InteratorType an @ref iterator or @ref const_iterator - @throw std::domain_error if called on a `null` value + @throw std::domain_error if called on a `null` value; example: `"cannot use + erase() with null"` @throw std::domain_error if called on an iterator which does not belong to - the current JSON value + the current JSON value; example: `"iterator does not fit current value"` @throw std::out_of_range if called on a primitive type with invalid - iterator (i.e., any iterator which is not end()) + iterator (i.e., any iterator which is not end()); example: `"iterator out + of range"` @complexity The complexity depends on the type: - objects: amortized constant @@ -3300,11 +3312,13 @@ class basic_json @tparam InteratorType an @ref iterator or @ref const_iterator - @throw std::domain_error if called on a `null` value + @throw std::domain_error if called on a `null` value; example: `"cannot use + erase() with null"` @throw std::domain_error if called on iterators which does not belong to - the current JSON value + the current JSON value; example: `"iterators do not fit current value"` @throw std::out_of_range if called on a primitive type with invalid - iterators (i.e., if `first != begin()` and `last != end()`) + iterators (i.e., if `first != begin()` and `last != end()`); example: + `"iterators out of range"` @complexity The complexity depends on the type: - objects: `log(size()) + std::distance(first, last)` @@ -3378,7 +3392,7 @@ class basic_json default: { - throw std::domain_error("cannot use erase with " + type_name()); + throw std::domain_error("cannot use erase() with " + type_name()); } } @@ -3396,7 +3410,8 @@ class basic_json type, the return value will always be `0` (@a key was not found) or `1` (@a key was found). - @throw std::domain_error when called on a type other than JSON object + @throw std::domain_error when called on a type other than JSON object; + example: `"cannot use erase() with null"` @complexity `log(size()) + count(key)` @@ -3430,8 +3445,10 @@ class basic_json @param[in] idx index of the element to remove - @throw std::domain_error when called on a type other than JSON array - @throw std::out_of_range when `idx >= size()` + @throw std::domain_error when called on a type other than JSON array; + example: `"cannot use erase() with null"` + @throw std::out_of_range when `idx >= size()`; example: `"index out of + range"` @complexity Linear in distance between @a idx and the end of the container. @@ -4065,7 +4082,8 @@ class basic_json @param val the value to add to the JSON array - @throw std::domain_error when called on a type other than JSON array or null + @throw std::domain_error when called on a type other than JSON array or + null; example: `"cannot use push_back() with number"` @complexity Amortized constant. @@ -4149,7 +4167,7 @@ class basic_json @param[in] val the value to add to the JSON object @throw std::domain_error when called on a type other than JSON object or - null + null; example: `"cannot use push_back() with number"` @complexity Logarithmic in the size of the container, O(log(`size()`)). @@ -4199,7 +4217,8 @@ class basic_json @return iterator pointing to the inserted @a val. @throw std::domain_error if called on JSON values other than arrays - @throw std::domain_error if @a pos is not an iterator of *this + @throw std::domain_error if @a pos is not an iterator of *this; example: + `"iterator does not fit current value"` @complexity Constant plus linear in the distance between pos and end of the container. @@ -4252,7 +4271,8 @@ class basic_json `cnt==0` @throw std::domain_error if called on JSON values other than arrays - @throw std::domain_error if @a pos is not an iterator of *this + @throw std::domain_error if @a pos is not an iterator of *this; example: + `"iterator does not fit current value"` @complexity Linear in @a cnt plus linear in the distance between @a pos and end of the container. @@ -4294,11 +4314,14 @@ class basic_json @param[in] last end of the range of elements to insert @throw std::domain_error if called on JSON values other than arrays - @throw std::domain_error if @a pos is not an iterator of *this + @throw std::domain_error if @a pos is not an iterator of *this; example: + `"iterator does not fit current value"` @throw std::domain_error if @a first and @a last do not belong to the same - JSON value + JSON value; example: `"iterators do not fit"` @throw std::domain_error if @a first or @a last are iterators into - container for which insert is called + container for which insert is called; example: `"passed iterators may not + belong to container"` + @return iterator pointing to the first element inserted, or @a pos if `first==last` @@ -4352,7 +4375,8 @@ class basic_json @param[in] ilist initializer list to insert the values from @throw std::domain_error if called on JSON values other than arrays - @throw std::domain_error if @a pos is not an iterator of *this + @throw std::domain_error if @a pos is not an iterator of *this; example: + `"iterator does not fit current value"` @return iterator pointing to the first element inserted, or @a pos if `ilist` is empty @@ -5870,7 +5894,7 @@ class basic_json { case basic_json::value_t::object: { - throw std::domain_error("cannot use operator< for object iterators"); + throw std::domain_error("cannot compare order of object iterators"); } case basic_json::value_t::array: @@ -5910,7 +5934,7 @@ class basic_json { case basic_json::value_t::object: { - throw std::domain_error("cannot use operator+= for object iterators"); + throw std::domain_error("cannot use offsets with object iterators"); } case basic_json::value_t::array: @@ -5958,7 +5982,7 @@ class basic_json { case basic_json::value_t::object: { - throw std::domain_error("cannot use operator- for object iterators"); + throw std::domain_error("cannot use offsets with object iterators"); } case basic_json::value_t::array: diff --git a/test/unit.cpp b/test/unit.cpp index 7b4323d39..0f0d745d4 100644 --- a/test/unit.cpp +++ b/test/unit.cpp @@ -10,6 +10,9 @@ #define CATCH_CONFIG_MAIN #include "catch.hpp" +// macro to check exception names (see https://github.com/philsquared/Catch/issues/563) +#define CHECK_THROWS_NAME(block, exception, name) { try { block; } catch ( exception &e ) { CHECK(e.what() == std::string(name)); } } + #include #include #include @@ -895,6 +898,8 @@ TEST_CASE("constructors") SECTION("object with error") { CHECK_THROWS_AS(json::object({ {"one", 1}, {"two", 2.2}, {"three", false}, 13 }), std::logic_error); + CHECK_THROWS_NAME(json::object({ {"one", 1}, {"two", 2.2}, {"three", false}, 13 }), + std::logic_error, "cannot create object from initializer list"); } SECTION("empty array") @@ -968,12 +973,20 @@ TEST_CASE("constructors") json jobject2 = {{"a", "a"}, {"b", 1}, {"c", 17}}; CHECK_THROWS_AS(json(jobject.begin(), jobject2.end()), std::domain_error); CHECK_THROWS_AS(json(jobject2.begin(), jobject.end()), std::domain_error); + CHECK_THROWS_NAME(json(jobject.begin(), jobject2.end()), std::domain_error, + "iterators are not compatible"); + CHECK_THROWS_NAME(json(jobject2.begin(), jobject.end()), std::domain_error, + "iterators are not compatible"); } { json jobject = {{"a", "a"}, {"b", 1}, {"c", 17}, {"d", false}, {"e", true}}; json jobject2 = {{"a", "a"}, {"b", 1}, {"c", 17}}; CHECK_THROWS_AS(json(jobject.cbegin(), jobject2.cend()), std::domain_error); CHECK_THROWS_AS(json(jobject2.cbegin(), jobject.cend()), std::domain_error); + CHECK_THROWS_NAME(json(jobject.cbegin(), jobject2.cend()), std::domain_error, + "iterators are not compatible"); + CHECK_THROWS_NAME(json(jobject2.cbegin(), jobject.cend()), std::domain_error, + "iterators are not compatible"); } } } @@ -1029,12 +1042,20 @@ TEST_CASE("constructors") json jarray2 = {2, 3, 4, 5}; CHECK_THROWS_AS(json(jarray.begin(), jarray2.end()), std::domain_error); CHECK_THROWS_AS(json(jarray2.begin(), jarray.end()), std::domain_error); + CHECK_THROWS_NAME(json(jarray.begin(), jarray2.end()), std::domain_error, + "iterators are not compatible"); + CHECK_THROWS_NAME(json(jarray2.begin(), jarray.end()), std::domain_error, + "iterators are not compatible"); } { json jarray = {1, 2, 3, 4}; json jarray2 = {2, 3, 4, 5}; CHECK_THROWS_AS(json(jarray.cbegin(), jarray2.cend()), std::domain_error); CHECK_THROWS_AS(json(jarray2.cbegin(), jarray.cend()), std::domain_error); + CHECK_THROWS_NAME(json(jarray.cbegin(), jarray2.cend()), std::domain_error, + "iterators are not compatible"); + CHECK_THROWS_NAME(json(jarray2.cbegin(), jarray.cend()), std::domain_error, + "iterators are not compatible"); } } } @@ -1048,10 +1069,14 @@ TEST_CASE("constructors") { json j; CHECK_THROWS_AS(json(j.begin(), j.end()), std::domain_error); + CHECK_THROWS_NAME(json(j.begin(), j.end()), std::domain_error, + "cannot use construct with iterators from null"); } { json j; CHECK_THROWS_AS(json(j.cbegin(), j.cend()), std::domain_error); + CHECK_THROWS_NAME(json(j.cbegin(), j.cend()), std::domain_error, + "cannot use construct with iterators from null"); } } @@ -1120,11 +1145,15 @@ TEST_CASE("constructors") json j = "foo"; CHECK_THROWS_AS(json(j.end(), j.end()), std::out_of_range); CHECK_THROWS_AS(json(j.begin(), j.begin()), std::out_of_range); + CHECK_THROWS_NAME(json(j.end(), j.end()), std::out_of_range, "iterators out of range"); + CHECK_THROWS_NAME(json(j.begin(), j.begin()), std::out_of_range, "iterators out of range"); } { json j = "bar"; CHECK_THROWS_AS(json(j.cend(), j.cend()), std::out_of_range); CHECK_THROWS_AS(json(j.cbegin(), j.cbegin()), std::out_of_range); + CHECK_THROWS_NAME(json(j.cend(), j.cend()), std::out_of_range, "iterators out of range"); + CHECK_THROWS_NAME(json(j.cbegin(), j.cbegin()), std::out_of_range, "iterators out of range"); } } @@ -1134,11 +1163,15 @@ TEST_CASE("constructors") json j = false; CHECK_THROWS_AS(json(j.end(), j.end()), std::out_of_range); CHECK_THROWS_AS(json(j.begin(), j.begin()), std::out_of_range); + CHECK_THROWS_NAME(json(j.end(), j.end()), std::out_of_range, "iterators out of range"); + CHECK_THROWS_NAME(json(j.begin(), j.begin()), std::out_of_range, "iterators out of range"); } { json j = true; CHECK_THROWS_AS(json(j.cend(), j.cend()), std::out_of_range); CHECK_THROWS_AS(json(j.cbegin(), j.cbegin()), std::out_of_range); + CHECK_THROWS_NAME(json(j.cend(), j.cend()), std::out_of_range, "iterators out of range"); + CHECK_THROWS_NAME(json(j.cbegin(), j.cbegin()), std::out_of_range, "iterators out of range"); } } @@ -1148,11 +1181,15 @@ TEST_CASE("constructors") json j = 17; CHECK_THROWS_AS(json(j.end(), j.end()), std::out_of_range); CHECK_THROWS_AS(json(j.begin(), j.begin()), std::out_of_range); + CHECK_THROWS_NAME(json(j.end(), j.end()), std::out_of_range, "iterators out of range"); + CHECK_THROWS_NAME(json(j.begin(), j.begin()), std::out_of_range, "iterators out of range"); } { json j = 17; CHECK_THROWS_AS(json(j.cend(), j.cend()), std::out_of_range); CHECK_THROWS_AS(json(j.cbegin(), j.cbegin()), std::out_of_range); + CHECK_THROWS_NAME(json(j.cend(), j.cend()), std::out_of_range, "iterators out of range"); + CHECK_THROWS_NAME(json(j.cbegin(), j.cbegin()), std::out_of_range, "iterators out of range"); } } @@ -1162,11 +1199,15 @@ TEST_CASE("constructors") json j = 23.42; CHECK_THROWS_AS(json(j.end(), j.end()), std::out_of_range); CHECK_THROWS_AS(json(j.begin(), j.begin()), std::out_of_range); + CHECK_THROWS_NAME(json(j.end(), j.end()), std::out_of_range, "iterators out of range"); + CHECK_THROWS_NAME(json(j.begin(), j.begin()), std::out_of_range, "iterators out of range"); } { json j = 23.42; CHECK_THROWS_AS(json(j.cend(), j.cend()), std::out_of_range); CHECK_THROWS_AS(json(j.cbegin(), j.cbegin()), std::out_of_range); + CHECK_THROWS_NAME(json(j.cend(), j.cend()), std::out_of_range, "iterators out of range"); + CHECK_THROWS_NAME(json(j.cbegin(), j.cbegin()), std::out_of_range, "iterators out of range"); } } } @@ -1645,6 +1686,19 @@ TEST_CASE("value conversion") CHECK_THROWS_AS(json(json::value_t::boolean).get(), std::logic_error); CHECK_THROWS_AS(json(json::value_t::number_integer).get(), std::logic_error); CHECK_THROWS_AS(json(json::value_t::number_float).get(), std::logic_error); + + CHECK_THROWS_NAME(json(json::value_t::null).get(), std::logic_error, + "type must be object, but is null"); + CHECK_THROWS_NAME(json(json::value_t::array).get(), std::logic_error, + "type must be object, but is array"); + CHECK_THROWS_NAME(json(json::value_t::string).get(), std::logic_error, + "type must be object, but is string"); + CHECK_THROWS_NAME(json(json::value_t::boolean).get(), std::logic_error, + "type must be object, but is boolean"); + CHECK_THROWS_NAME(json(json::value_t::number_integer).get(), std::logic_error, + "type must be object, but is number"); + CHECK_THROWS_NAME(json(json::value_t::number_float).get(), std::logic_error, + "type must be object, but is number"); } } @@ -1727,6 +1781,19 @@ TEST_CASE("value conversion") CHECK_THROWS_AS(json(json::value_t::boolean).get(), std::logic_error); CHECK_THROWS_AS(json(json::value_t::number_integer).get(), std::logic_error); CHECK_THROWS_AS(json(json::value_t::number_float).get(), std::logic_error); + + CHECK_THROWS_NAME(json(json::value_t::null).get(), std::logic_error, + "type must be array, but is null"); + CHECK_THROWS_NAME(json(json::value_t::object).get(), std::logic_error, + "type must be array, but is object"); + CHECK_THROWS_NAME(json(json::value_t::string).get(), std::logic_error, + "type must be array, but is string"); + CHECK_THROWS_NAME(json(json::value_t::boolean).get(), std::logic_error, + "type must be array, but is boolean"); + CHECK_THROWS_NAME(json(json::value_t::number_integer).get(), std::logic_error, + "type must be array, but is number"); + CHECK_THROWS_NAME(json(json::value_t::number_float).get(), std::logic_error, + "type must be array, but is number"); } } @@ -1791,6 +1858,19 @@ TEST_CASE("value conversion") CHECK_THROWS_AS(json(json::value_t::boolean).get(), std::logic_error); CHECK_THROWS_AS(json(json::value_t::number_integer).get(), std::logic_error); CHECK_THROWS_AS(json(json::value_t::number_float).get(), std::logic_error); + + CHECK_THROWS_NAME(json(json::value_t::null).get(), std::logic_error, + "type must be string, but is null"); + CHECK_THROWS_NAME(json(json::value_t::object).get(), std::logic_error, + "type must be string, but is object"); + CHECK_THROWS_NAME(json(json::value_t::array).get(), std::logic_error, + "type must be string, but is array"); + CHECK_THROWS_NAME(json(json::value_t::boolean).get(), std::logic_error, + "type must be string, but is boolean"); + CHECK_THROWS_NAME(json(json::value_t::number_integer).get(), std::logic_error, + "type must be string, but is number"); + CHECK_THROWS_NAME(json(json::value_t::number_float).get(), std::logic_error, + "type must be string, but is number"); } } @@ -1837,6 +1917,19 @@ TEST_CASE("value conversion") CHECK_THROWS_AS(json(json::value_t::string).get(), std::logic_error); CHECK_THROWS_AS(json(json::value_t::number_integer).get(), std::logic_error); CHECK_THROWS_AS(json(json::value_t::number_float).get(), std::logic_error); + + CHECK_THROWS_NAME(json(json::value_t::null).get(), std::logic_error, + "type must be boolean, but is null"); + CHECK_THROWS_NAME(json(json::value_t::object).get(), std::logic_error, + "type must be boolean, but is object"); + CHECK_THROWS_NAME(json(json::value_t::array).get(), std::logic_error, + "type must be boolean, but is array"); + CHECK_THROWS_NAME(json(json::value_t::string).get(), std::logic_error, + "type must be boolean, but is string"); + CHECK_THROWS_NAME(json(json::value_t::number_integer).get(), std::logic_error, + "type must be boolean, but is number"); + CHECK_THROWS_NAME(json(json::value_t::number_float).get(), std::logic_error, + "type must be boolean, but is number"); } } @@ -2068,6 +2161,18 @@ TEST_CASE("value conversion") CHECK_THROWS_AS(json(json::value_t::array).get(), std::logic_error); CHECK_THROWS_AS(json(json::value_t::string).get(), std::logic_error); CHECK_THROWS_AS(json(json::value_t::boolean).get(), std::logic_error); + + CHECK_THROWS_NAME(json(json::value_t::null).get(), std::logic_error, + "type must be number, but is null"); + CHECK_THROWS_NAME(json(json::value_t::object).get(), std::logic_error, + "type must be number, but is object"); + CHECK_THROWS_NAME(json(json::value_t::array).get(), std::logic_error, + "type must be number, but is array"); + CHECK_THROWS_NAME(json(json::value_t::string).get(), std::logic_error, + "type must be number, but is string"); + CHECK_THROWS_NAME(json(json::value_t::boolean).get(), std::logic_error, + "type must be number, but is boolean"); + CHECK_NOTHROW(json(json::value_t::number_float).get()); } } @@ -2306,6 +2411,18 @@ TEST_CASE("value conversion") CHECK_THROWS_AS(json(json::value_t::array).get(), std::logic_error); CHECK_THROWS_AS(json(json::value_t::string).get(), std::logic_error); CHECK_THROWS_AS(json(json::value_t::boolean).get(), std::logic_error); + + CHECK_THROWS_NAME(json(json::value_t::null).get(), std::logic_error, + "type must be number, but is null"); + CHECK_THROWS_NAME(json(json::value_t::object).get(), std::logic_error, + "type must be number, but is object"); + CHECK_THROWS_NAME(json(json::value_t::array).get(), std::logic_error, + "type must be number, but is array"); + CHECK_THROWS_NAME(json(json::value_t::string).get(), std::logic_error, + "type must be number, but is string"); + CHECK_THROWS_NAME(json(json::value_t::boolean).get(), std::logic_error, + "type must be number, but is boolean"); + CHECK_NOTHROW(json(json::value_t::number_integer).get()); } } @@ -2381,6 +2498,8 @@ TEST_CASE("value conversion") SECTION("exception in case of a non-object type") { CHECK_THROWS_AS((json().get>()), std::logic_error); + CHECK_THROWS_NAME((json().get>()), std::logic_error, + "type must be object, but is null"); } } @@ -2445,6 +2564,15 @@ TEST_CASE("value conversion") CHECK_THROWS_AS((json().get>()), std::logic_error); CHECK_THROWS_AS((json().get>()), std::logic_error); CHECK_THROWS_AS((json().get>()), std::logic_error); + + CHECK_THROWS_NAME((json().get>()), std::logic_error, + "type must be array, but is null"); + CHECK_THROWS_NAME((json().get>()), std::logic_error, + "type must be array, but is null"); + CHECK_THROWS_NAME((json().get>()), std::logic_error, + "type must be array, but is null"); + CHECK_THROWS_NAME((json().get>()), std::logic_error, + "type must be array, but is null"); } } } @@ -2663,15 +2791,8 @@ TEST_CASE("element access") CHECK_THROWS_AS(j.at(7), std::out_of_range); CHECK_THROWS_AS(j_const.at(7), std::out_of_range); - // exception name - try - { - j.at(7); - } - catch (std::out_of_range& e) - { - CHECK(std::string(e.what()) == "array index 7 is out of range"); - } + CHECK_THROWS_NAME(j.at(7), std::out_of_range, "array index 7 is out of range"); + CHECK_THROWS_NAME(j_const.at(7), std::out_of_range, "array index 7 is out of range"); } SECTION("access on non-array type") @@ -2683,15 +2804,8 @@ TEST_CASE("element access") CHECK_THROWS_AS(j_nonarray.at(0), std::domain_error); CHECK_THROWS_AS(j_nonarray_const.at(0), std::domain_error); - // exception name - try - { - j_nonarray.at(0); - } - catch (std::domain_error& e) - { - CHECK(std::string(e.what()) == "cannot use at() with null"); - } + CHECK_THROWS_NAME(j_nonarray.at(0), std::domain_error, "cannot use at() with null"); + CHECK_THROWS_NAME(j_nonarray_const.at(0), std::domain_error, "cannot use at() with null"); } SECTION("boolean") @@ -2701,15 +2815,8 @@ TEST_CASE("element access") CHECK_THROWS_AS(j_nonarray.at(0), std::domain_error); CHECK_THROWS_AS(j_nonarray_const.at(0), std::domain_error); - // exception name - try - { - j_nonarray.at(0); - } - catch (std::domain_error& e) - { - CHECK(std::string(e.what()) == "cannot use at() with boolean"); - } + CHECK_THROWS_NAME(j_nonarray.at(0), std::domain_error, "cannot use at() with boolean"); + CHECK_THROWS_NAME(j_nonarray_const.at(0), std::domain_error, "cannot use at() with boolean"); } SECTION("string") @@ -2719,15 +2826,8 @@ TEST_CASE("element access") CHECK_THROWS_AS(j_nonarray.at(0), std::domain_error); CHECK_THROWS_AS(j_nonarray_const.at(0), std::domain_error); - // exception name - try - { - j_nonarray.at(0); - } - catch (std::domain_error& e) - { - CHECK(std::string(e.what()) == "cannot use at() with string"); - } + CHECK_THROWS_NAME(j_nonarray.at(0), std::domain_error, "cannot use at() with string"); + CHECK_THROWS_NAME(j_nonarray_const.at(0), std::domain_error, "cannot use at() with string"); } SECTION("object") @@ -2737,15 +2837,8 @@ TEST_CASE("element access") CHECK_THROWS_AS(j_nonarray.at(0), std::domain_error); CHECK_THROWS_AS(j_nonarray_const.at(0), std::domain_error); - // exception name - try - { - j_nonarray.at(0); - } - catch (std::domain_error& e) - { - CHECK(std::string(e.what()) == "cannot use at() with object"); - } + CHECK_THROWS_NAME(j_nonarray.at(0), std::domain_error, "cannot use at() with object"); + CHECK_THROWS_NAME(j_nonarray_const.at(0), std::domain_error, "cannot use at() with object"); } SECTION("number (integer)") @@ -2755,15 +2848,8 @@ TEST_CASE("element access") CHECK_THROWS_AS(j_nonarray.at(0), std::domain_error); CHECK_THROWS_AS(j_nonarray_const.at(0), std::domain_error); - // exception name - try - { - j_nonarray.at(0); - } - catch (std::domain_error& e) - { - CHECK(std::string(e.what()) == "cannot use at() with number"); - } + CHECK_THROWS_NAME(j_nonarray.at(0), std::domain_error, "cannot use at() with number"); + CHECK_THROWS_NAME(j_nonarray_const.at(0), std::domain_error, "cannot use at() with number"); } SECTION("number (floating-point)") @@ -2773,15 +2859,8 @@ TEST_CASE("element access") CHECK_THROWS_AS(j_nonarray.at(0), std::domain_error); CHECK_THROWS_AS(j_nonarray_const.at(0), std::domain_error); - // exception name - try - { - j_nonarray.at(0); - } - catch (std::domain_error& e) - { - CHECK(std::string(e.what()) == "cannot use at() with number"); - } + CHECK_THROWS_NAME(j_nonarray.at(0), std::domain_error, "cannot use at() with number"); + CHECK_THROWS_NAME(j_nonarray_const.at(0), std::domain_error, "cannot use at() with number"); } } } @@ -2825,6 +2904,7 @@ TEST_CASE("element access") const json j_nonarray_const(j_nonarray); CHECK_NOTHROW(j_nonarray[0]); CHECK_THROWS_AS(j_nonarray_const[0], std::domain_error); + CHECK_THROWS_NAME(j_nonarray_const[0], std::domain_error, "cannot use operator[] with null"); } SECTION("implicit transformation to properly filled array") @@ -2841,6 +2921,8 @@ TEST_CASE("element access") const json j_nonarray_const(j_nonarray); CHECK_THROWS_AS(j_nonarray[0], std::domain_error); CHECK_THROWS_AS(j_nonarray_const[0], std::domain_error); + CHECK_THROWS_NAME(j_nonarray[0], std::domain_error, "cannot use operator[] with boolean"); + CHECK_THROWS_NAME(j_nonarray_const[0], std::domain_error, "cannot use operator[] with boolean"); } SECTION("string") @@ -2849,6 +2931,8 @@ TEST_CASE("element access") const json j_nonarray_const(j_nonarray); CHECK_THROWS_AS(j_nonarray[0], std::domain_error); CHECK_THROWS_AS(j_nonarray_const[0], std::domain_error); + CHECK_THROWS_NAME(j_nonarray[0], std::domain_error, "cannot use operator[] with string"); + CHECK_THROWS_NAME(j_nonarray_const[0], std::domain_error, "cannot use operator[] with string"); } SECTION("object") @@ -2857,6 +2941,8 @@ TEST_CASE("element access") const json j_nonarray_const(j_nonarray); CHECK_THROWS_AS(j_nonarray[0], std::domain_error); CHECK_THROWS_AS(j_nonarray_const[0], std::domain_error); + CHECK_THROWS_NAME(j_nonarray[0], std::domain_error, "cannot use operator[] with object"); + CHECK_THROWS_NAME(j_nonarray_const[0], std::domain_error, "cannot use operator[] with object"); } SECTION("number (integer)") @@ -2865,6 +2951,8 @@ TEST_CASE("element access") const json j_nonarray_const(j_nonarray); CHECK_THROWS_AS(j_nonarray[0], std::domain_error); CHECK_THROWS_AS(j_nonarray_const[0], std::domain_error); + CHECK_THROWS_NAME(j_nonarray[0], std::domain_error, "cannot use operator[] with number"); + CHECK_THROWS_NAME(j_nonarray_const[0], std::domain_error, "cannot use operator[] with number"); } SECTION("number (floating-point)") @@ -2873,6 +2961,8 @@ TEST_CASE("element access") const json j_nonarray_const(j_nonarray); CHECK_THROWS_AS(j_nonarray[0], std::domain_error); CHECK_THROWS_AS(j_nonarray_const[0], std::domain_error); + CHECK_THROWS_NAME(j_nonarray[0], std::domain_error, "cannot use operator[] with number"); + CHECK_THROWS_NAME(j_nonarray_const[0], std::domain_error, "cannot use operator[] with number"); } } } @@ -2919,6 +3009,7 @@ TEST_CASE("element access") { json jarray = {1, true, nullptr, "string", 42.23, json::object(), {1, 2, 3}}; CHECK_THROWS_AS(jarray.erase(7), std::out_of_range); + CHECK_THROWS_NAME(jarray.erase(7), std::out_of_range, "index out of range"); } } @@ -3015,6 +3106,15 @@ TEST_CASE("element access") CHECK_THROWS_AS(jarray.erase(jarray.begin(), jarray2.end()), std::domain_error); CHECK_THROWS_AS(jarray.erase(jarray2.begin(), jarray.end()), std::domain_error); CHECK_THROWS_AS(jarray.erase(jarray2.begin(), jarray2.end()), std::domain_error); + + CHECK_THROWS_NAME(jarray.erase(jarray2.begin()), std::domain_error, + "iterator does not fit current value"); + CHECK_THROWS_NAME(jarray.erase(jarray.begin(), jarray2.end()), std::domain_error, + "iterators do not fit current value"); + CHECK_THROWS_NAME(jarray.erase(jarray2.begin(), jarray.end()), std::domain_error, + "iterators do not fit current value"); + CHECK_THROWS_NAME(jarray.erase(jarray2.begin(), jarray2.end()), std::domain_error, + "iterators do not fit current value"); } { json jarray = {1, true, nullptr, "string", 42.23, json::object(), {1, 2, 3}}; @@ -3023,6 +3123,15 @@ TEST_CASE("element access") CHECK_THROWS_AS(jarray.erase(jarray.cbegin(), jarray2.cend()), std::domain_error); CHECK_THROWS_AS(jarray.erase(jarray2.cbegin(), jarray.cend()), std::domain_error); CHECK_THROWS_AS(jarray.erase(jarray2.cbegin(), jarray2.cend()), std::domain_error); + + CHECK_THROWS_NAME(jarray.erase(jarray2.cbegin()), std::domain_error, + "iterator does not fit current value"); + CHECK_THROWS_NAME(jarray.erase(jarray.cbegin(), jarray2.cend()), std::domain_error, + "iterators do not fit current value"); + CHECK_THROWS_NAME(jarray.erase(jarray2.cbegin(), jarray.cend()), std::domain_error, + "iterators do not fit current value"); + CHECK_THROWS_NAME(jarray.erase(jarray2.cbegin(), jarray2.cend()), std::domain_error, + "iterators do not fit current value"); } } } @@ -3033,36 +3142,42 @@ TEST_CASE("element access") { json j_nonobject(json::value_t::null); CHECK_THROWS_AS(j_nonobject.erase(0), std::domain_error); + CHECK_THROWS_NAME(j_nonobject.erase(0), std::domain_error, "cannot use erase() with null"); } SECTION("boolean") { json j_nonobject(json::value_t::boolean); CHECK_THROWS_AS(j_nonobject.erase(0), std::domain_error); + CHECK_THROWS_NAME(j_nonobject.erase(0), std::domain_error, "cannot use erase() with boolean"); } SECTION("string") { json j_nonobject(json::value_t::string); CHECK_THROWS_AS(j_nonobject.erase(0), std::domain_error); + CHECK_THROWS_NAME(j_nonobject.erase(0), std::domain_error, "cannot use erase() with string"); } SECTION("object") { json j_nonobject(json::value_t::object); CHECK_THROWS_AS(j_nonobject.erase(0), std::domain_error); + CHECK_THROWS_NAME(j_nonobject.erase(0), std::domain_error, "cannot use erase() with object"); } SECTION("number (integer)") { json j_nonobject(json::value_t::number_integer); CHECK_THROWS_AS(j_nonobject.erase(0), std::domain_error); + CHECK_THROWS_NAME(j_nonobject.erase(0), std::domain_error, "cannot use erase() with number"); } SECTION("number (floating-point)") { json j_nonobject(json::value_t::number_float); CHECK_THROWS_AS(j_nonobject.erase(0), std::domain_error); + CHECK_THROWS_NAME(j_nonobject.erase(0), std::domain_error, "cannot use erase() with number"); } } } @@ -3098,16 +3213,8 @@ TEST_CASE("element access") { CHECK_THROWS_AS(j.at("foo"), std::out_of_range); CHECK_THROWS_AS(j_const.at("foo"), std::out_of_range); - - // exception name - try - { - j.at("foo"); - } - catch (std::out_of_range& e) - { - CHECK(std::string(e.what()) == "key 'foo' not found"); - } + CHECK_THROWS_NAME(j.at("foo"), std::out_of_range, "key 'foo' not found"); + CHECK_THROWS_NAME(j_const.at("foo"), std::out_of_range, "key 'foo' not found"); } SECTION("access on non-object type") @@ -3118,16 +3225,8 @@ TEST_CASE("element access") const json j_nonobject_const(j_nonobject); CHECK_THROWS_AS(j_nonobject.at("foo"), std::domain_error); CHECK_THROWS_AS(j_nonobject_const.at("foo"), std::domain_error); - - // exception name - try - { - j_nonobject.at("foo"); - } - catch (std::domain_error& e) - { - CHECK(std::string(e.what()) == "cannot use at() with null"); - } + CHECK_THROWS_NAME(j_nonobject.at("foo"), std::domain_error, "cannot use at() with null"); + CHECK_THROWS_NAME(j_nonobject_const.at("foo"), std::domain_error, "cannot use at() with null"); } SECTION("boolean") @@ -3136,16 +3235,8 @@ TEST_CASE("element access") const json j_nonobject_const(j_nonobject); CHECK_THROWS_AS(j_nonobject.at("foo"), std::domain_error); CHECK_THROWS_AS(j_nonobject_const.at("foo"), std::domain_error); - - // exception name - try - { - j_nonobject.at("foo"); - } - catch (std::domain_error& e) - { - CHECK(std::string(e.what()) == "cannot use at() with boolean"); - } + CHECK_THROWS_NAME(j_nonobject.at("foo"), std::domain_error, "cannot use at() with boolean"); + CHECK_THROWS_NAME(j_nonobject_const.at("foo"), std::domain_error, "cannot use at() with boolean"); } SECTION("string") @@ -3154,16 +3245,8 @@ TEST_CASE("element access") const json j_nonobject_const(j_nonobject); CHECK_THROWS_AS(j_nonobject.at("foo"), std::domain_error); CHECK_THROWS_AS(j_nonobject_const.at("foo"), std::domain_error); - - // exception name - try - { - j_nonobject.at("foo"); - } - catch (std::domain_error& e) - { - CHECK(std::string(e.what()) == "cannot use at() with string"); - } + CHECK_THROWS_NAME(j_nonobject.at("foo"), std::domain_error, "cannot use at() with string"); + CHECK_THROWS_NAME(j_nonobject_const.at("foo"), std::domain_error, "cannot use at() with string"); } SECTION("array") @@ -3172,16 +3255,8 @@ TEST_CASE("element access") const json j_nonobject_const(j_nonobject); CHECK_THROWS_AS(j_nonobject.at("foo"), std::domain_error); CHECK_THROWS_AS(j_nonobject_const.at("foo"), std::domain_error); - - // exception name - try - { - j_nonobject.at("foo"); - } - catch (std::domain_error& e) - { - CHECK(std::string(e.what()) == "cannot use at() with array"); - } + CHECK_THROWS_NAME(j_nonobject.at("foo"), std::domain_error, "cannot use at() with array"); + CHECK_THROWS_NAME(j_nonobject_const.at("foo"), std::domain_error, "cannot use at() with array"); } SECTION("number (integer)") @@ -3190,16 +3265,8 @@ TEST_CASE("element access") const json j_nonobject_const(j_nonobject); CHECK_THROWS_AS(j_nonobject.at("foo"), std::domain_error); CHECK_THROWS_AS(j_nonobject_const.at("foo"), std::domain_error); - - // exception name - try - { - j_nonobject.at("foo"); - } - catch (std::domain_error& e) - { - CHECK(std::string(e.what()) == "cannot use at() with number"); - } + CHECK_THROWS_NAME(j_nonobject.at("foo"), std::domain_error, "cannot use at() with number"); + CHECK_THROWS_NAME(j_nonobject_const.at("foo"), std::domain_error, "cannot use at() with number"); } SECTION("number (floating-point)") @@ -3208,16 +3275,8 @@ TEST_CASE("element access") const json j_nonobject_const(j_nonobject); CHECK_THROWS_AS(j_nonobject.at("foo"), std::domain_error); CHECK_THROWS_AS(j_nonobject_const.at("foo"), std::domain_error); - - // exception name - try - { - j_nonobject.at("foo"); - } - catch (std::domain_error& e) - { - CHECK(std::string(e.what()) == "cannot use at() with number"); - } + CHECK_THROWS_NAME(j_nonobject.at("foo"), std::domain_error, "cannot use at() with number"); + CHECK_THROWS_NAME(j_nonobject_const.at("foo"), std::domain_error, "cannot use at() with number"); } } } @@ -3273,6 +3332,9 @@ TEST_CASE("element access") const json j_nonobject_const(j_nonobject); CHECK_THROWS_AS(j_nonobject.value("foo", 1), std::domain_error); CHECK_THROWS_AS(j_nonobject_const.value("foo", 1), std::domain_error); + CHECK_THROWS_NAME(j_nonobject.value("foo", 1), std::domain_error, "cannot use value() with null"); + CHECK_THROWS_NAME(j_nonobject_const.value("foo", 1), std::domain_error, + "cannot use value() with null"); } SECTION("boolean") @@ -3281,6 +3343,10 @@ TEST_CASE("element access") const json j_nonobject_const(j_nonobject); CHECK_THROWS_AS(j_nonobject.value("foo", 1), std::domain_error); CHECK_THROWS_AS(j_nonobject_const.value("foo", 1), std::domain_error); + CHECK_THROWS_NAME(j_nonobject.value("foo", 1), std::domain_error, + "cannot use value() with boolean"); + CHECK_THROWS_NAME(j_nonobject_const.value("foo", 1), std::domain_error, + "cannot use value() with boolean"); } SECTION("string") @@ -3289,6 +3355,9 @@ TEST_CASE("element access") const json j_nonobject_const(j_nonobject); CHECK_THROWS_AS(j_nonobject.value("foo", 1), std::domain_error); CHECK_THROWS_AS(j_nonobject_const.value("foo", 1), std::domain_error); + CHECK_THROWS_NAME(j_nonobject.value("foo", 1), std::domain_error, "cannot use value() with string"); + CHECK_THROWS_NAME(j_nonobject_const.value("foo", 1), std::domain_error, + "cannot use value() with string"); } SECTION("array") @@ -3297,6 +3366,9 @@ TEST_CASE("element access") const json j_nonobject_const(j_nonobject); CHECK_THROWS_AS(j_nonobject.value("foo", 1), std::domain_error); CHECK_THROWS_AS(j_nonobject_const.value("foo", 1), std::domain_error); + CHECK_THROWS_NAME(j_nonobject.value("foo", 1), std::domain_error, "cannot use value() with array"); + CHECK_THROWS_NAME(j_nonobject_const.value("foo", 1), std::domain_error, + "cannot use value() with array"); } SECTION("number (integer)") @@ -3305,6 +3377,9 @@ TEST_CASE("element access") const json j_nonobject_const(j_nonobject); CHECK_THROWS_AS(j_nonobject.value("foo", 1), std::domain_error); CHECK_THROWS_AS(j_nonobject_const.value("foo", 1), std::domain_error); + CHECK_THROWS_NAME(j_nonobject.value("foo", 1), std::domain_error, "cannot use value() with number"); + CHECK_THROWS_NAME(j_nonobject_const.value("foo", 1), std::domain_error, + "cannot use value() with number"); } SECTION("number (floating-point)") @@ -3313,6 +3388,9 @@ TEST_CASE("element access") const json j_nonobject_const(j_nonobject); CHECK_THROWS_AS(j_nonobject.value("foo", 1), std::domain_error); CHECK_THROWS_AS(j_nonobject_const.value("foo", 1), std::domain_error); + CHECK_THROWS_NAME(j_nonobject.value("foo", 1), std::domain_error, "cannot use value() with number"); + CHECK_THROWS_NAME(j_nonobject_const.value("foo", 1), std::domain_error, + "cannot use value() with number"); } } } @@ -3385,6 +3463,9 @@ TEST_CASE("element access") CHECK_NOTHROW(j_nonobject2[json::object_t::key_type("foo")]); CHECK_THROWS_AS(j_const_nonobject["foo"], std::domain_error); CHECK_THROWS_AS(j_const_nonobject[json::object_t::key_type("foo")], std::domain_error); + CHECK_THROWS_NAME(j_const_nonobject["foo"], std::domain_error, "cannot use operator[] with null"); + CHECK_THROWS_NAME(j_const_nonobject[json::object_t::key_type("foo")], std::domain_error, + "cannot use operator[] with null"); } SECTION("boolean") @@ -3395,6 +3476,13 @@ TEST_CASE("element access") CHECK_THROWS_AS(j_nonobject[json::object_t::key_type("foo")], std::domain_error); CHECK_THROWS_AS(j_const_nonobject["foo"], std::domain_error); CHECK_THROWS_AS(j_const_nonobject[json::object_t::key_type("foo")], std::domain_error); + CHECK_THROWS_NAME(j_nonobject["foo"], std::domain_error, "cannot use operator[] with boolean"); + CHECK_THROWS_NAME(j_nonobject[json::object_t::key_type("foo")], std::domain_error, + "cannot use operator[] with boolean"); + CHECK_THROWS_NAME(j_const_nonobject["foo"], std::domain_error, + "cannot use operator[] with boolean"); + CHECK_THROWS_NAME(j_const_nonobject[json::object_t::key_type("foo")], std::domain_error, + "cannot use operator[] with boolean"); } SECTION("string") @@ -3405,6 +3493,12 @@ TEST_CASE("element access") CHECK_THROWS_AS(j_nonobject[json::object_t::key_type("foo")], std::domain_error); CHECK_THROWS_AS(j_const_nonobject["foo"], std::domain_error); CHECK_THROWS_AS(j_const_nonobject[json::object_t::key_type("foo")], std::domain_error); + CHECK_THROWS_NAME(j_nonobject["foo"], std::domain_error, "cannot use operator[] with string"); + CHECK_THROWS_NAME(j_nonobject[json::object_t::key_type("foo")], std::domain_error, + "cannot use operator[] with string"); + CHECK_THROWS_NAME(j_const_nonobject["foo"], std::domain_error, "cannot use operator[] with string"); + CHECK_THROWS_NAME(j_const_nonobject[json::object_t::key_type("foo")], std::domain_error, + "cannot use operator[] with string"); } SECTION("array") @@ -3415,6 +3509,12 @@ TEST_CASE("element access") CHECK_THROWS_AS(j_nonobject[json::object_t::key_type("foo")], std::domain_error); CHECK_THROWS_AS(j_const_nonobject["foo"], std::domain_error); CHECK_THROWS_AS(j_const_nonobject[json::object_t::key_type("foo")], std::domain_error); + CHECK_THROWS_NAME(j_nonobject["foo"], std::domain_error, "cannot use operator[] with array"); + CHECK_THROWS_NAME(j_nonobject[json::object_t::key_type("foo")], std::domain_error, + "cannot use operator[] with array"); + CHECK_THROWS_NAME(j_const_nonobject["foo"], std::domain_error, "cannot use operator[] with array"); + CHECK_THROWS_NAME(j_const_nonobject[json::object_t::key_type("foo")], std::domain_error, + "cannot use operator[] with array"); } SECTION("number (integer)") @@ -3425,6 +3525,12 @@ TEST_CASE("element access") CHECK_THROWS_AS(j_nonobject[json::object_t::key_type("foo")], std::domain_error); CHECK_THROWS_AS(j_const_nonobject["foo"], std::domain_error); CHECK_THROWS_AS(j_const_nonobject[json::object_t::key_type("foo")], std::domain_error); + CHECK_THROWS_NAME(j_nonobject["foo"], std::domain_error, "cannot use operator[] with number"); + CHECK_THROWS_NAME(j_nonobject[json::object_t::key_type("foo")], std::domain_error, + "cannot use operator[] with number"); + CHECK_THROWS_NAME(j_const_nonobject["foo"], std::domain_error, "cannot use operator[] with number"); + CHECK_THROWS_NAME(j_const_nonobject[json::object_t::key_type("foo")], std::domain_error, + "cannot use operator[] with number"); } SECTION("number (floating-point)") @@ -3435,6 +3541,12 @@ TEST_CASE("element access") CHECK_THROWS_AS(j_nonobject[json::object_t::key_type("foo")], std::domain_error); CHECK_THROWS_AS(j_const_nonobject["foo"], std::domain_error); CHECK_THROWS_AS(j_const_nonobject[json::object_t::key_type("foo")], std::domain_error); + CHECK_THROWS_NAME(j_nonobject["foo"], std::domain_error, "cannot use operator[] with number"); + CHECK_THROWS_NAME(j_nonobject[json::object_t::key_type("foo")], std::domain_error, + "cannot use operator[] with number"); + CHECK_THROWS_NAME(j_const_nonobject["foo"], std::domain_error, "cannot use operator[] with number"); + CHECK_THROWS_NAME(j_const_nonobject[json::object_t::key_type("foo")], std::domain_error, + "cannot use operator[] with number"); } } } @@ -3572,6 +3684,14 @@ TEST_CASE("element access") CHECK_THROWS_AS(jobject.erase(jobject.begin(), jobject2.end()), std::domain_error); CHECK_THROWS_AS(jobject.erase(jobject2.begin(), jobject.end()), std::domain_error); CHECK_THROWS_AS(jobject.erase(jobject2.begin(), jobject2.end()), std::domain_error); + CHECK_THROWS_NAME(jobject.erase(jobject2.begin()), std::domain_error, + "iterator does not fit current value"); + CHECK_THROWS_NAME(jobject.erase(jobject.begin(), jobject2.end()), std::domain_error, + "iterators do not fit current value"); + CHECK_THROWS_NAME(jobject.erase(jobject2.begin(), jobject.end()), std::domain_error, + "iterators do not fit current value"); + CHECK_THROWS_NAME(jobject.erase(jobject2.begin(), jobject2.end()), std::domain_error, + "iterators do not fit current value"); } { json jobject = {{"a", "a"}, {"b", 1}, {"c", 17}, {"d", false}, {"e", true}}; @@ -3580,6 +3700,14 @@ TEST_CASE("element access") CHECK_THROWS_AS(jobject.erase(jobject.cbegin(), jobject2.cend()), std::domain_error); CHECK_THROWS_AS(jobject.erase(jobject2.cbegin(), jobject.cend()), std::domain_error); CHECK_THROWS_AS(jobject.erase(jobject2.cbegin(), jobject2.cend()), std::domain_error); + CHECK_THROWS_NAME(jobject.erase(jobject2.cbegin()), std::domain_error, + "iterator does not fit current value"); + CHECK_THROWS_NAME(jobject.erase(jobject.cbegin(), jobject2.cend()), std::domain_error, + "iterators do not fit current value"); + CHECK_THROWS_NAME(jobject.erase(jobject2.cbegin(), jobject.cend()), std::domain_error, + "iterators do not fit current value"); + CHECK_THROWS_NAME(jobject.erase(jobject2.cbegin(), jobject2.cend()), std::domain_error, + "iterators do not fit current value"); } } } @@ -3590,36 +3718,42 @@ TEST_CASE("element access") { json j_nonobject(json::value_t::null); CHECK_THROWS_AS(j_nonobject.erase("foo"), std::domain_error); + CHECK_THROWS_NAME(j_nonobject.erase("foo"), std::domain_error, "cannot use erase() with null"); } SECTION("boolean") { json j_nonobject(json::value_t::boolean); CHECK_THROWS_AS(j_nonobject.erase("foo"), std::domain_error); + CHECK_THROWS_NAME(j_nonobject.erase("foo"), std::domain_error, "cannot use erase() with boolean"); } SECTION("string") { json j_nonobject(json::value_t::string); CHECK_THROWS_AS(j_nonobject.erase("foo"), std::domain_error); + CHECK_THROWS_NAME(j_nonobject.erase("foo"), std::domain_error, "cannot use erase() with string"); } SECTION("array") { json j_nonobject(json::value_t::array); CHECK_THROWS_AS(j_nonobject.erase("foo"), std::domain_error); + CHECK_THROWS_NAME(j_nonobject.erase("foo"), std::domain_error, "cannot use erase() with array"); } SECTION("number (integer)") { json j_nonobject(json::value_t::number_integer); CHECK_THROWS_AS(j_nonobject.erase("foo"), std::domain_error); + CHECK_THROWS_NAME(j_nonobject.erase("foo"), std::domain_error, "cannot use erase() with number"); } SECTION("number (floating-point)") { json j_nonobject(json::value_t::number_float); CHECK_THROWS_AS(j_nonobject.erase("foo"), std::domain_error); + CHECK_THROWS_NAME(j_nonobject.erase("foo"), std::domain_error, "cannot use erase() with number"); } } } @@ -3795,11 +3929,15 @@ TEST_CASE("element access") json j; CHECK_THROWS_AS(j.front(), std::out_of_range); CHECK_THROWS_AS(j.back(), std::out_of_range); + CHECK_THROWS_NAME(j.front(), std::out_of_range, "cannot get value"); + CHECK_THROWS_NAME(j.back(), std::out_of_range, "cannot get value"); } { const json j{}; CHECK_THROWS_AS(j.front(), std::out_of_range); CHECK_THROWS_AS(j.back(), std::out_of_range); + CHECK_THROWS_NAME(j.front(), std::out_of_range, "cannot get value"); + CHECK_THROWS_NAME(j.back(), std::out_of_range, "cannot get value"); } } @@ -3809,11 +3947,15 @@ TEST_CASE("element access") json j = "foo"; CHECK(j.front() == j); CHECK(j.back() == j); + CHECK_THROWS_NAME(j.front(), std::out_of_range, "cannot get value"); + CHECK_THROWS_NAME(j.back(), std::out_of_range, "cannot get value"); } { const json j = "bar"; CHECK(j.front() == j); CHECK(j.back() == j); + CHECK_THROWS_NAME(j.front(), std::out_of_range, "cannot get value"); + CHECK_THROWS_NAME(j.back(), std::out_of_range, "cannot get value"); } } @@ -3823,11 +3965,15 @@ TEST_CASE("element access") json j = false; CHECK(j.front() == j); CHECK(j.back() == j); + CHECK_THROWS_NAME(j.front(), std::out_of_range, "cannot get value"); + CHECK_THROWS_NAME(j.back(), std::out_of_range, "cannot get value"); } { const json j = true; CHECK(j.front() == j); CHECK(j.back() == j); + CHECK_THROWS_NAME(j.front(), std::out_of_range, "cannot get value"); + CHECK_THROWS_NAME(j.back(), std::out_of_range, "cannot get value"); } } @@ -3837,11 +3983,15 @@ TEST_CASE("element access") json j = 17; CHECK(j.front() == j); CHECK(j.back() == j); + CHECK_THROWS_NAME(j.front(), std::out_of_range, "cannot get value"); + CHECK_THROWS_NAME(j.back(), std::out_of_range, "cannot get value"); } { const json j = 17; CHECK(j.front() == j); CHECK(j.back() == j); + CHECK_THROWS_NAME(j.front(), std::out_of_range, "cannot get value"); + CHECK_THROWS_NAME(j.back(), std::out_of_range, "cannot get value"); } } @@ -3851,11 +4001,15 @@ TEST_CASE("element access") json j = 23.42; CHECK(j.front() == j); CHECK(j.back() == j); + CHECK_THROWS_NAME(j.front(), std::out_of_range, "cannot get value"); + CHECK_THROWS_NAME(j.back(), std::out_of_range, "cannot get value"); } { const json j = 23.42; CHECK(j.front() == j); CHECK(j.back() == j); + CHECK_THROWS_NAME(j.front(), std::out_of_range, "cannot get value"); + CHECK_THROWS_NAME(j.back(), std::out_of_range, "cannot get value"); } } } @@ -3867,10 +4021,12 @@ TEST_CASE("element access") { json j; CHECK_THROWS_AS(j.erase(j.begin()), std::domain_error); + CHECK_THROWS_NAME(j.erase(j.begin()), std::domain_error, "cannot use erase() with null"); } { json j; CHECK_THROWS_AS(j.erase(j.cbegin()), std::domain_error); + CHECK_THROWS_NAME(j.erase(j.begin()), std::domain_error, "cannot use erase() with null"); } } @@ -3946,10 +4102,12 @@ TEST_CASE("element access") { json j = "foo"; CHECK_THROWS_AS(j.erase(j.end()), std::out_of_range); + CHECK_THROWS_NAME(j.erase(j.end()), std::out_of_range, "iterator out of range"); } { json j = "bar"; CHECK_THROWS_AS(j.erase(j.cend()), std::out_of_range); + CHECK_THROWS_NAME(j.erase(j.cend()), std::out_of_range, "iterator out of range"); } } @@ -3958,10 +4116,12 @@ TEST_CASE("element access") { json j = false; CHECK_THROWS_AS(j.erase(j.end()), std::out_of_range); + CHECK_THROWS_NAME(j.erase(j.end()), std::out_of_range, "iterator out of range"); } { json j = true; CHECK_THROWS_AS(j.erase(j.cend()), std::out_of_range); + CHECK_THROWS_NAME(j.erase(j.cend()), std::out_of_range, "iterator out of range"); } } @@ -3970,10 +4130,12 @@ TEST_CASE("element access") { json j = 17; CHECK_THROWS_AS(j.erase(j.end()), std::out_of_range); + CHECK_THROWS_NAME(j.erase(j.end()), std::out_of_range, "iterator out of range"); } { json j = 17; CHECK_THROWS_AS(j.erase(j.cend()), std::out_of_range); + CHECK_THROWS_NAME(j.erase(j.cend()), std::out_of_range, "iterator out of range"); } } @@ -3982,10 +4144,12 @@ TEST_CASE("element access") { json j = 23.42; CHECK_THROWS_AS(j.erase(j.end()), std::out_of_range); + CHECK_THROWS_NAME(j.erase(j.end()), std::out_of_range, "iterator out of range"); } { json j = 23.42; CHECK_THROWS_AS(j.erase(j.cend()), std::out_of_range); + CHECK_THROWS_NAME(j.erase(j.cend()), std::out_of_range, "iterator out of range"); } } } @@ -3997,10 +4161,12 @@ TEST_CASE("element access") { json j; CHECK_THROWS_AS(j.erase(j.begin(), j.end()), std::domain_error); + CHECK_THROWS_NAME(j.erase(j.begin(), j.end()), std::domain_error, "cannot use erase() with null"); } { json j; CHECK_THROWS_AS(j.erase(j.cbegin(), j.cend()), std::domain_error); + CHECK_THROWS_NAME(j.erase(j.cbegin(), j.cend()), std::domain_error, "cannot use erase() with null"); } } @@ -4077,11 +4243,15 @@ TEST_CASE("element access") json j = "foo"; CHECK_THROWS_AS(j.erase(j.end(), j.end()), std::out_of_range); CHECK_THROWS_AS(j.erase(j.begin(), j.begin()), std::out_of_range); + CHECK_THROWS_NAME(j.erase(j.end(), j.end()), std::out_of_range, "iterators out of range"); + CHECK_THROWS_NAME(j.erase(j.begin(), j.begin()), std::out_of_range, "iterators out of range"); } { json j = "bar"; CHECK_THROWS_AS(j.erase(j.cend(), j.cend()), std::out_of_range); CHECK_THROWS_AS(j.erase(j.cbegin(), j.cbegin()), std::out_of_range); + CHECK_THROWS_NAME(j.erase(j.cend(), j.cend()), std::out_of_range, "iterators out of range"); + CHECK_THROWS_NAME(j.erase(j.cbegin(), j.cbegin()), std::out_of_range, "iterators out of range"); } } @@ -4091,11 +4261,15 @@ TEST_CASE("element access") json j = false; CHECK_THROWS_AS(j.erase(j.end(), j.end()), std::out_of_range); CHECK_THROWS_AS(j.erase(j.begin(), j.begin()), std::out_of_range); + CHECK_THROWS_NAME(j.erase(j.end(), j.end()), std::out_of_range, "iterators out of range"); + CHECK_THROWS_NAME(j.erase(j.begin(), j.begin()), std::out_of_range, "iterators out of range"); } { json j = true; CHECK_THROWS_AS(j.erase(j.cend(), j.cend()), std::out_of_range); CHECK_THROWS_AS(j.erase(j.cbegin(), j.cbegin()), std::out_of_range); + CHECK_THROWS_NAME(j.erase(j.cend(), j.cend()), std::out_of_range, "iterators out of range"); + CHECK_THROWS_NAME(j.erase(j.cbegin(), j.cbegin()), std::out_of_range, "iterators out of range"); } } @@ -4105,11 +4279,15 @@ TEST_CASE("element access") json j = 17; CHECK_THROWS_AS(j.erase(j.end(), j.end()), std::out_of_range); CHECK_THROWS_AS(j.erase(j.begin(), j.begin()), std::out_of_range); + CHECK_THROWS_NAME(j.erase(j.end(), j.end()), std::out_of_range, "iterators out of range"); + CHECK_THROWS_NAME(j.erase(j.begin(), j.begin()), std::out_of_range, "iterators out of range"); } { json j = 17; CHECK_THROWS_AS(j.erase(j.cend(), j.cend()), std::out_of_range); CHECK_THROWS_AS(j.erase(j.cbegin(), j.cbegin()), std::out_of_range); + CHECK_THROWS_NAME(j.erase(j.cend(), j.cend()), std::out_of_range, "iterators out of range"); + CHECK_THROWS_NAME(j.erase(j.cbegin(), j.cbegin()), std::out_of_range, "iterators out of range"); } } @@ -4119,11 +4297,15 @@ TEST_CASE("element access") json j = 23.42; CHECK_THROWS_AS(j.erase(j.end(), j.end()), std::out_of_range); CHECK_THROWS_AS(j.erase(j.begin(), j.begin()), std::out_of_range); + CHECK_THROWS_NAME(j.erase(j.end(), j.end()), std::out_of_range, "iterators out of range"); + CHECK_THROWS_NAME(j.erase(j.begin(), j.begin()), std::out_of_range, "iterators out of range"); } { json j = 23.42; CHECK_THROWS_AS(j.erase(j.cend(), j.cend()), std::out_of_range); CHECK_THROWS_AS(j.erase(j.cbegin(), j.cbegin()), std::out_of_range); + CHECK_THROWS_NAME(j.erase(j.cend(), j.cend()), std::out_of_range, "iterators out of range"); + CHECK_THROWS_NAME(j.erase(j.cbegin(), j.cbegin()), std::out_of_range, "iterators out of range"); } } } @@ -4328,8 +4510,10 @@ TEST_CASE("iterators") auto it = j.begin(); auto cit = j_const.cbegin(); CHECK_THROWS_AS(it.key(), std::domain_error); + CHECK_THROWS_NAME(it.key(), std::domain_error, "cannot use key() for non-object iterators"); CHECK(it.value() == json(true)); CHECK_THROWS_AS(cit.key(), std::domain_error); + CHECK_THROWS_NAME(cit.key(), std::domain_error, "cannot use key() for non-object iterators"); CHECK(cit.value() == json(true)); auto rit = j.rend(); @@ -4338,6 +4522,10 @@ TEST_CASE("iterators") CHECK_THROWS_AS(rit.value(), std::out_of_range); CHECK_THROWS_AS(crit.key(), std::domain_error); CHECK_THROWS_AS(crit.value(), std::out_of_range); + CHECK_THROWS_NAME(rit.key(), std::domain_error, "cannot use key() for non-object iterators"); + CHECK_THROWS_NAME(rit.value(), std::out_of_range, "cannot get value"); + CHECK_THROWS_NAME(crit.key(), std::domain_error, "cannot use key() for non-object iterators"); + CHECK_THROWS_NAME(crit.value(), std::out_of_range, "cannot get value"); } } @@ -4526,8 +4714,10 @@ TEST_CASE("iterators") auto it = j.begin(); auto cit = j_const.cbegin(); CHECK_THROWS_AS(it.key(), std::domain_error); + CHECK_THROWS_NAME(it.key(), std::domain_error, "cannot use key() for non-object iterators"); CHECK(it.value() == json("hello world")); CHECK_THROWS_AS(cit.key(), std::domain_error); + CHECK_THROWS_NAME(cit.key(), std::domain_error, "cannot use key() for non-object iterators"); CHECK(cit.value() == json("hello world")); auto rit = j.rend(); @@ -4536,6 +4726,10 @@ TEST_CASE("iterators") CHECK_THROWS_AS(rit.value(), std::out_of_range); CHECK_THROWS_AS(crit.key(), std::domain_error); CHECK_THROWS_AS(crit.value(), std::out_of_range); + CHECK_THROWS_NAME(rit.key(), std::domain_error, "cannot use key() for non-object iterators"); + CHECK_THROWS_NAME(rit.value(), std::out_of_range, "cannot get value"); + CHECK_THROWS_NAME(crit.key(), std::domain_error, "cannot use key() for non-object iterators"); + CHECK_THROWS_NAME(crit.value(), std::out_of_range, "cannot get value"); } } @@ -4717,8 +4911,10 @@ TEST_CASE("iterators") auto it = j.begin(); auto cit = j_const.cbegin(); CHECK_THROWS_AS(it.key(), std::domain_error); + CHECK_THROWS_NAME(it.key(), std::domain_error, "cannot use key() for non-object iterators"); CHECK(it.value() == json(1)); CHECK_THROWS_AS(cit.key(), std::domain_error); + CHECK_THROWS_NAME(cit.key(), std::domain_error, "cannot use key() for non-object iterators"); CHECK(cit.value() == json(1)); } } @@ -5092,8 +5288,10 @@ TEST_CASE("iterators") auto it = j.begin(); auto cit = j_const.cbegin(); CHECK_THROWS_AS(it.key(), std::domain_error); + CHECK_THROWS_NAME(it.key(), std::domain_error, "cannot use key() for non-object iterators"); CHECK(it.value() == json(23)); CHECK_THROWS_AS(cit.key(), std::domain_error); + CHECK_THROWS_NAME(cit.key(), std::domain_error, "cannot use key() for non-object iterators"); CHECK(cit.value() == json(23)); auto rit = j.rend(); @@ -5102,6 +5300,10 @@ TEST_CASE("iterators") CHECK_THROWS_AS(rit.value(), std::out_of_range); CHECK_THROWS_AS(crit.key(), std::domain_error); CHECK_THROWS_AS(crit.value(), std::out_of_range); + CHECK_THROWS_NAME(rit.key(), std::domain_error, "cannot use key() for non-object iterators"); + CHECK_THROWS_NAME(rit.value(), std::out_of_range, "cannot get value"); + CHECK_THROWS_NAME(crit.key(), std::domain_error, "cannot use key() for non-object iterators"); + CHECK_THROWS_NAME(crit.value(), std::out_of_range, "cannot get value"); } } @@ -5290,8 +5492,10 @@ TEST_CASE("iterators") auto it = j.begin(); auto cit = j_const.cbegin(); CHECK_THROWS_AS(it.key(), std::domain_error); + CHECK_THROWS_NAME(it.key(), std::domain_error, "cannot use key() for non-object iterators"); CHECK(it.value() == json(23.42)); CHECK_THROWS_AS(cit.key(), std::domain_error); + CHECK_THROWS_NAME(cit.key(), std::domain_error, "cannot use key() for non-object iterators"); CHECK(cit.value() == json(23.42)); auto rit = j.rend(); @@ -5300,6 +5504,10 @@ TEST_CASE("iterators") CHECK_THROWS_AS(rit.value(), std::out_of_range); CHECK_THROWS_AS(crit.key(), std::domain_error); CHECK_THROWS_AS(crit.value(), std::out_of_range); + CHECK_THROWS_NAME(rit.key(), std::domain_error, "cannot use key() for non-object iterators"); + CHECK_THROWS_NAME(rit.value(), std::out_of_range, "cannot get value"); + CHECK_THROWS_NAME(crit.key(), std::domain_error, "cannot use key() for non-object iterators"); + CHECK_THROWS_NAME(crit.value(), std::out_of_range, "cannot get value"); } } @@ -5361,6 +5569,10 @@ TEST_CASE("iterators") CHECK_THROWS_AS(it.value(), std::out_of_range); CHECK_THROWS_AS(cit.key(), std::domain_error); CHECK_THROWS_AS(cit.value(), std::out_of_range); + CHECK_THROWS_NAME(it.key(), std::domain_error, "cannot use key() for non-object iterators"); + CHECK_THROWS_NAME(it.value(), std::out_of_range, "cannot get value"); + CHECK_THROWS_NAME(cit.key(), std::domain_error, "cannot use key() for non-object iterators"); + CHECK_THROWS_NAME(cit.value(), std::out_of_range, "cannot get value"); auto rit = j.rend(); auto crit = j.crend(); @@ -5368,6 +5580,10 @@ TEST_CASE("iterators") CHECK_THROWS_AS(rit.value(), std::out_of_range); CHECK_THROWS_AS(crit.key(), std::domain_error); CHECK_THROWS_AS(crit.value(), std::out_of_range); + CHECK_THROWS_NAME(rit.key(), std::domain_error, "cannot use key() for non-object iterators"); + CHECK_THROWS_NAME(rit.value(), std::out_of_range, "cannot get value"); + CHECK_THROWS_NAME(crit.key(), std::domain_error, "cannot use key() for non-object iterators"); + CHECK_THROWS_NAME(crit.value(), std::out_of_range, "cannot get value"); } } } @@ -5428,6 +5644,14 @@ TEST_CASE("iterators") CHECK_THROWS_AS(it1_c < it2_c, std::domain_error); CHECK_THROWS_AS(it2_c < it3_c, std::domain_error); CHECK_THROWS_AS(it1_c < it3_c, std::domain_error); + CHECK_THROWS_NAME(it1 < it1, std::domain_error, "cannot compare order of object iterators"); + CHECK_THROWS_NAME(it1 < it2, std::domain_error, "cannot compare order of object iterators"); + CHECK_THROWS_NAME(it2 < it3, std::domain_error, "cannot compare order of object iterators"); + CHECK_THROWS_NAME(it1 < it3, std::domain_error, "cannot compare order of object iterators"); + CHECK_THROWS_NAME(it1_c < it1_c, std::domain_error, "cannot compare order of object iterators"); + CHECK_THROWS_NAME(it1_c < it2_c, std::domain_error, "cannot compare order of object iterators"); + CHECK_THROWS_NAME(it2_c < it3_c, std::domain_error, "cannot compare order of object iterators"); + CHECK_THROWS_NAME(it1_c < it3_c, std::domain_error, "cannot compare order of object iterators"); } else { @@ -5454,6 +5678,14 @@ TEST_CASE("iterators") CHECK_THROWS_AS(it1_c <= it2_c, std::domain_error); CHECK_THROWS_AS(it2_c <= it3_c, std::domain_error); CHECK_THROWS_AS(it1_c <= it3_c, std::domain_error); + CHECK_THROWS_NAME(it1 <= it1, std::domain_error, "cannot compare order of object iterators"); + CHECK_THROWS_NAME(it1 <= it2, std::domain_error, "cannot compare order of object iterators"); + CHECK_THROWS_NAME(it2 <= it3, std::domain_error, "cannot compare order of object iterators"); + CHECK_THROWS_NAME(it1 <= it3, std::domain_error, "cannot compare order of object iterators"); + CHECK_THROWS_NAME(it1_c <= it1_c, std::domain_error, "cannot compare order of object iterators"); + CHECK_THROWS_NAME(it1_c <= it2_c, std::domain_error, "cannot compare order of object iterators"); + CHECK_THROWS_NAME(it2_c <= it3_c, std::domain_error, "cannot compare order of object iterators"); + CHECK_THROWS_NAME(it1_c <= it3_c, std::domain_error, "cannot compare order of object iterators"); } else { @@ -5481,6 +5713,14 @@ TEST_CASE("iterators") CHECK_THROWS_AS(it1_c > it2_c, std::domain_error); CHECK_THROWS_AS(it2_c > it3_c, std::domain_error); CHECK_THROWS_AS(it1_c > it3_c, std::domain_error); + CHECK_THROWS_NAME(it1 > it1, std::domain_error, "cannot compare order of object iterators"); + CHECK_THROWS_NAME(it1 > it2, std::domain_error, "cannot compare order of object iterators"); + CHECK_THROWS_NAME(it2 > it3, std::domain_error, "cannot compare order of object iterators"); + CHECK_THROWS_NAME(it1 > it3, std::domain_error, "cannot compare order of object iterators"); + CHECK_THROWS_NAME(it1_c > it1_c, std::domain_error, "cannot compare order of object iterators"); + CHECK_THROWS_NAME(it1_c > it2_c, std::domain_error, "cannot compare order of object iterators"); + CHECK_THROWS_NAME(it2_c > it3_c, std::domain_error, "cannot compare order of object iterators"); + CHECK_THROWS_NAME(it1_c > it3_c, std::domain_error, "cannot compare order of object iterators"); } else { @@ -5508,6 +5748,14 @@ TEST_CASE("iterators") CHECK_THROWS_AS(it1_c >= it2_c, std::domain_error); CHECK_THROWS_AS(it2_c >= it3_c, std::domain_error); CHECK_THROWS_AS(it1_c >= it3_c, std::domain_error); + CHECK_THROWS_NAME(it1 >= it1, std::domain_error, "cannot compare order of object iterators"); + CHECK_THROWS_NAME(it1 >= it2, std::domain_error, "cannot compare order of object iterators"); + CHECK_THROWS_NAME(it2 >= it3, std::domain_error, "cannot compare order of object iterators"); + CHECK_THROWS_NAME(it1 >= it3, std::domain_error, "cannot compare order of object iterators"); + CHECK_THROWS_NAME(it1_c >= it1_c, std::domain_error, "cannot compare order of object iterators"); + CHECK_THROWS_NAME(it1_c >= it2_c, std::domain_error, "cannot compare order of object iterators"); + CHECK_THROWS_NAME(it2_c >= it3_c, std::domain_error, "cannot compare order of object iterators"); + CHECK_THROWS_NAME(it1_c >= it3_c, std::domain_error, "cannot compare order of object iterators"); } else { @@ -5533,9 +5781,17 @@ TEST_CASE("iterators") { CHECK_THROWS_AS(j.begin() == k.begin(), std::domain_error); CHECK_THROWS_AS(j.cbegin() == k.cbegin(), std::domain_error); + CHECK_THROWS_NAME(j.begin() == k.begin(), std::domain_error, + "cannot compare iterators of different containers"); + CHECK_THROWS_NAME(j.cbegin() == k.cbegin(), std::domain_error, + "cannot compare iterators of different containers"); CHECK_THROWS_AS(j.begin() < k.begin(), std::domain_error); CHECK_THROWS_AS(j.cbegin() < k.cbegin(), std::domain_error); + CHECK_THROWS_NAME(j.begin() < k.begin(), std::domain_error, + "cannot compare iterators of different containers"); + CHECK_THROWS_NAME(j.cbegin() < k.cbegin(), std::domain_error, + "cannot compare iterators of different containers"); } } } @@ -5555,42 +5811,52 @@ TEST_CASE("iterators") { auto it = j_object.begin(); CHECK_THROWS_AS(it += 1, std::domain_error); + CHECK_THROWS_NAME(it += 1, std::domain_error, "cannot use offsets with object iterators"); } { auto it = j_object.cbegin(); CHECK_THROWS_AS(it += 1, std::domain_error); + CHECK_THROWS_NAME(it += 1, std::domain_error, "cannot use offsets with object iterators"); } { auto it = j_object.begin(); CHECK_THROWS_AS(it + 1, std::domain_error); + CHECK_THROWS_NAME(it + 1, std::domain_error, "cannot use offsets with object iterators"); } { auto it = j_object.cbegin(); CHECK_THROWS_AS(it + 1, std::domain_error); + CHECK_THROWS_NAME(it + 1, std::domain_error, "cannot use offsets with object iterators"); } { auto it = j_object.begin(); CHECK_THROWS_AS(it -= 1, std::domain_error); + CHECK_THROWS_NAME(it -= 1, std::domain_error, "cannot use offsets with object iterators"); } { auto it = j_object.cbegin(); CHECK_THROWS_AS(it -= 1, std::domain_error); + CHECK_THROWS_NAME(it -= 1, std::domain_error, "cannot use offsets with object iterators"); } { auto it = j_object.begin(); CHECK_THROWS_AS(it - 1, std::domain_error); + CHECK_THROWS_NAME(it - 1, std::domain_error, "cannot use offsets with object iterators"); } { auto it = j_object.cbegin(); CHECK_THROWS_AS(it - 1, std::domain_error); + CHECK_THROWS_NAME(it - 1, std::domain_error, "cannot use offsets with object iterators"); } { auto it = j_object.begin(); CHECK_THROWS_AS(it - it, std::domain_error); + CHECK_THROWS_NAME(it - it, std::domain_error, "cannot use offsets with object iterators"); } { auto it = j_object.cbegin(); CHECK_THROWS_AS(it - it, std::domain_error); + CHECK_THROWS_NAME(it - it, std::domain_error, "cannot use offsets with object iterators"); } } @@ -6693,6 +6959,16 @@ TEST_CASE("modifiers") { json j = 1; CHECK_THROWS_AS(j.push_back("Hello"), std::domain_error); + + // exception name + try + { + j.push_back("Hello"); + } + catch (std::domain_error& e) + { + CHECK(e.what() == std::string("cannot use push_back() with number")); + } } } @@ -6722,6 +6998,16 @@ TEST_CASE("modifiers") json j = 1; json k("Hello"); CHECK_THROWS_AS(j.push_back(k), std::domain_error); + + // exception name + try + { + j.push_back(k); + } + catch (std::domain_error& e) + { + CHECK(e.what() == std::string("cannot use push_back() with number")); + } } } } @@ -6754,6 +7040,16 @@ TEST_CASE("modifiers") json j = 1; json k("Hello"); CHECK_THROWS_AS(j.push_back(json::object_t::value_type({"one", 1})), std::domain_error); + + // exception name + try + { + j.push_back(k); + } + catch (std::domain_error& e) + { + CHECK(e.what() == std::string("cannot use push_back() with number")); + } } } } @@ -6785,6 +7081,16 @@ TEST_CASE("modifiers") { json j = 1; CHECK_THROWS_AS(j += "Hello", std::domain_error); + + // exception name + try + { + j += "Hello"; + } + catch (std::domain_error& e) + { + CHECK(e.what() == std::string("cannot use push_back() with number")); + } } } @@ -6814,6 +7120,16 @@ TEST_CASE("modifiers") json j = 1; json k("Hello"); CHECK_THROWS_AS(j += k, std::domain_error); + + // exception name + try + { + j += k; + } + catch (std::domain_error& e) + { + CHECK(e.what() == std::string("cannot use push_back() with number")); + } } } } @@ -6846,6 +7162,17 @@ TEST_CASE("modifiers") json j = 1; json k("Hello"); CHECK_THROWS_AS(j += json::object_t::value_type({"one", 1}), std::domain_error); + + + // exception name + try + { + j += json::object_t::value_type({"one", 1}); + } + catch (std::domain_error& e) + { + CHECK(e.what() == std::string("cannot use push_back() with number")); + } } } } @@ -6982,6 +7309,25 @@ TEST_CASE("modifiers") CHECK_THROWS_AS(j_array.insert(j_array.end(), j_array.begin(), j_array.end()), std::domain_error); CHECK_THROWS_AS(j_array.insert(j_array.end(), j_other_array.begin(), j_other_array2.end()), std::domain_error); + + // exception names + try + { + j_array.insert(j_array.end(), j_array.begin(), j_array.end()); + } + catch (std::domain_error& e) + { + CHECK(e.what() == std::string("passed iterators may not belong to container")); + } + + try + { + j_array.insert(j_array.end(), j_other_array.begin(), j_other_array2.end()); + } + catch (std::domain_error& e) + { + CHECK(e.what() == std::string("iterators do not fit")); + } } } From dc8ab92552025775264ecf410561a430236b895e Mon Sep 17 00:00:00 2001 From: Niels Date: Fri, 25 Dec 2015 13:04:40 +0100 Subject: [PATCH 35/61] more tests for exceptions (#160) --- src/json.hpp | 6 +- src/json.hpp.re2c | 6 +- test/unit.cpp | 307 +++++++++++++++++++++++++++++++++------------- 3 files changed, 229 insertions(+), 90 deletions(-) diff --git a/src/json.hpp b/src/json.hpp index b5db4fe6d..253bb3111 100644 --- a/src/json.hpp +++ b/src/json.hpp @@ -6371,7 +6371,8 @@ class basic_json @param[in] codepoint1 the code point (can be high surrogate) @param[in] codepoint2 the code point (can be low surrogate or 0) @return string representation of the code point - @throw std::out_of_range if code point is >0x10ffff + @throw std::out_of_range if code point is >0x10ffff; example: `"code + points above 0x10FFFF are invalid"` @throw std::invalid_argument if the low surrogate is invalid @see @@ -7765,8 +7766,7 @@ basic_json_parser_64: { std::string error_msg = "parse error - unexpected \'"; error_msg += m_lexer.get_token(); - error_msg += "\' ("; - error_msg += lexer::token_type_name(last_token) + ")"; + error_msg += "\'"; throw std::invalid_argument(error_msg); } } diff --git a/src/json.hpp.re2c b/src/json.hpp.re2c index 24ab27572..84ceccc3b 100644 --- a/src/json.hpp.re2c +++ b/src/json.hpp.re2c @@ -6371,7 +6371,8 @@ class basic_json @param[in] codepoint1 the code point (can be high surrogate) @param[in] codepoint2 the code point (can be low surrogate or 0) @return string representation of the code point - @throw std::out_of_range if code point is >0x10ffff + @throw std::out_of_range if code point is >0x10ffff; example: `"code + points above 0x10FFFF are invalid"` @throw std::invalid_argument if the low surrogate is invalid @see @@ -7044,8 +7045,7 @@ class basic_json { std::string error_msg = "parse error - unexpected \'"; error_msg += m_lexer.get_token(); - error_msg += "\' ("; - error_msg += lexer::token_type_name(last_token) + ")"; + error_msg += "\'"; throw std::invalid_argument(error_msg); } } diff --git a/test/unit.cpp b/test/unit.cpp index 0f0d745d4..57f6adb4d 100644 --- a/test/unit.cpp +++ b/test/unit.cpp @@ -5941,11 +5941,15 @@ TEST_CASE("iterators") auto it = j_object.begin(); CHECK_THROWS_AS(it[0], std::domain_error); CHECK_THROWS_AS(it[1], std::domain_error); + CHECK_THROWS_NAME(it[0], std::domain_error, "cannot use operator[] for object iterators"); + CHECK_THROWS_NAME(it[1], std::domain_error, "cannot use operator[] for object iterators"); } { auto it = j_object.cbegin(); CHECK_THROWS_AS(it[0], std::domain_error); CHECK_THROWS_AS(it[1], std::domain_error); + CHECK_THROWS_NAME(it[0], std::domain_error, "cannot use operator[] for object iterators"); + CHECK_THROWS_NAME(it[1], std::domain_error, "cannot use operator[] for object iterators"); } } @@ -5977,11 +5981,15 @@ TEST_CASE("iterators") auto it = j_null.begin(); CHECK_THROWS_AS(it[0], std::out_of_range); CHECK_THROWS_AS(it[1], std::out_of_range); + CHECK_THROWS_NAME(it[0], std::out_of_range, "cannot get value"); + CHECK_THROWS_NAME(it[1], std::out_of_range, "cannot get value"); } { auto it = j_null.cbegin(); CHECK_THROWS_AS(it[0], std::out_of_range); CHECK_THROWS_AS(it[1], std::out_of_range); + CHECK_THROWS_NAME(it[0], std::out_of_range, "cannot get value"); + CHECK_THROWS_NAME(it[1], std::out_of_range, "cannot get value"); } } @@ -5991,11 +5999,13 @@ TEST_CASE("iterators") auto it = j_value.begin(); CHECK(it[0] == json(42)); CHECK_THROWS_AS(it[1], std::out_of_range); + CHECK_THROWS_NAME(it[1], std::out_of_range, "cannot get value"); } { auto it = j_value.cbegin(); CHECK(it[0] == json(42)); CHECK_THROWS_AS(it[1], std::out_of_range); + CHECK_THROWS_NAME(it[1], std::out_of_range, "cannot get value"); } } } @@ -6057,6 +6067,14 @@ TEST_CASE("iterators") CHECK_THROWS_AS(it1_c < it2_c, std::domain_error); CHECK_THROWS_AS(it2_c < it3_c, std::domain_error); CHECK_THROWS_AS(it1_c < it3_c, std::domain_error); + CHECK_THROWS_NAME(it1 < it1, std::domain_error, "cannot compare order of object iterators"); + CHECK_THROWS_NAME(it1 < it2, std::domain_error, "cannot compare order of object iterators"); + CHECK_THROWS_NAME(it2 < it3, std::domain_error, "cannot compare order of object iterators"); + CHECK_THROWS_NAME(it1 < it3, std::domain_error, "cannot compare order of object iterators"); + CHECK_THROWS_NAME(it1_c < it1_c, std::domain_error, "cannot compare order of object iterators"); + CHECK_THROWS_NAME(it1_c < it2_c, std::domain_error, "cannot compare order of object iterators"); + CHECK_THROWS_NAME(it2_c < it3_c, std::domain_error, "cannot compare order of object iterators"); + CHECK_THROWS_NAME(it1_c < it3_c, std::domain_error, "cannot compare order of object iterators"); } else { @@ -6083,6 +6101,14 @@ TEST_CASE("iterators") CHECK_THROWS_AS(it1_c <= it2_c, std::domain_error); CHECK_THROWS_AS(it2_c <= it3_c, std::domain_error); CHECK_THROWS_AS(it1_c <= it3_c, std::domain_error); + CHECK_THROWS_NAME(it1 <= it1, std::domain_error, "cannot compare order of object iterators"); + CHECK_THROWS_NAME(it1 <= it2, std::domain_error, "cannot compare order of object iterators"); + CHECK_THROWS_NAME(it2 <= it3, std::domain_error, "cannot compare order of object iterators"); + CHECK_THROWS_NAME(it1 <= it3, std::domain_error, "cannot compare order of object iterators"); + CHECK_THROWS_NAME(it1_c <= it1_c, std::domain_error, "cannot compare order of object iterators"); + CHECK_THROWS_NAME(it1_c <= it2_c, std::domain_error, "cannot compare order of object iterators"); + CHECK_THROWS_NAME(it2_c <= it3_c, std::domain_error, "cannot compare order of object iterators"); + CHECK_THROWS_NAME(it1_c <= it3_c, std::domain_error, "cannot compare order of object iterators"); } else { @@ -6110,6 +6136,14 @@ TEST_CASE("iterators") CHECK_THROWS_AS(it1_c > it2_c, std::domain_error); CHECK_THROWS_AS(it2_c > it3_c, std::domain_error); CHECK_THROWS_AS(it1_c > it3_c, std::domain_error); + CHECK_THROWS_NAME(it1 > it1, std::domain_error, "cannot compare order of object iterators"); + CHECK_THROWS_NAME(it1 > it2, std::domain_error, "cannot compare order of object iterators"); + CHECK_THROWS_NAME(it2 > it3, std::domain_error, "cannot compare order of object iterators"); + CHECK_THROWS_NAME(it1 > it3, std::domain_error, "cannot compare order of object iterators"); + CHECK_THROWS_NAME(it1_c > it1_c, std::domain_error, "cannot compare order of object iterators"); + CHECK_THROWS_NAME(it1_c > it2_c, std::domain_error, "cannot compare order of object iterators"); + CHECK_THROWS_NAME(it2_c > it3_c, std::domain_error, "cannot compare order of object iterators"); + CHECK_THROWS_NAME(it1_c > it3_c, std::domain_error, "cannot compare order of object iterators"); } else { @@ -6137,6 +6171,14 @@ TEST_CASE("iterators") CHECK_THROWS_AS(it1_c >= it2_c, std::domain_error); CHECK_THROWS_AS(it2_c >= it3_c, std::domain_error); CHECK_THROWS_AS(it1_c >= it3_c, std::domain_error); + CHECK_THROWS_NAME(it1 >= it1, std::domain_error, "cannot compare order of object iterators"); + CHECK_THROWS_NAME(it1 >= it2, std::domain_error, "cannot compare order of object iterators"); + CHECK_THROWS_NAME(it2 >= it3, std::domain_error, "cannot compare order of object iterators"); + CHECK_THROWS_NAME(it1 >= it3, std::domain_error, "cannot compare order of object iterators"); + CHECK_THROWS_NAME(it1_c >= it1_c, std::domain_error, "cannot compare order of object iterators"); + CHECK_THROWS_NAME(it1_c >= it2_c, std::domain_error, "cannot compare order of object iterators"); + CHECK_THROWS_NAME(it2_c >= it3_c, std::domain_error, "cannot compare order of object iterators"); + CHECK_THROWS_NAME(it1_c >= it3_c, std::domain_error, "cannot compare order of object iterators"); } else { @@ -6162,9 +6204,17 @@ TEST_CASE("iterators") { CHECK_THROWS_AS(j.rbegin() == k.rbegin(), std::domain_error); CHECK_THROWS_AS(j.crbegin() == k.crbegin(), std::domain_error); + CHECK_THROWS_NAME(j.rbegin() == k.rbegin(), std::domain_error, + "cannot compare iterators of different containers"); + CHECK_THROWS_NAME(j.crbegin() == k.crbegin(), std::domain_error, + "cannot compare iterators of different containers"); CHECK_THROWS_AS(j.rbegin() < k.rbegin(), std::domain_error); CHECK_THROWS_AS(j.crbegin() < k.crbegin(), std::domain_error); + CHECK_THROWS_NAME(j.rbegin() < k.rbegin(), std::domain_error, + "cannot compare iterators of different containers"); + CHECK_THROWS_NAME(j.crbegin() < k.crbegin(), std::domain_error, + "cannot compare iterators of different containers"); } } } @@ -6184,42 +6234,52 @@ TEST_CASE("iterators") { auto it = j_object.rbegin(); CHECK_THROWS_AS(it += 1, std::domain_error); + CHECK_THROWS_NAME(it += 1, std::domain_error, "cannot use offsets with object iterators"); } { auto it = j_object.crbegin(); CHECK_THROWS_AS(it += 1, std::domain_error); + CHECK_THROWS_NAME(it += 1, std::domain_error, "cannot use offsets with object iterators"); } { auto it = j_object.rbegin(); CHECK_THROWS_AS(it + 1, std::domain_error); + CHECK_THROWS_NAME(it + 1, std::domain_error, "cannot use offsets with object iterators"); } { auto it = j_object.crbegin(); CHECK_THROWS_AS(it + 1, std::domain_error); + CHECK_THROWS_NAME(it + 1, std::domain_error, "cannot use offsets with object iterators"); } { auto it = j_object.rbegin(); CHECK_THROWS_AS(it -= 1, std::domain_error); + CHECK_THROWS_NAME(it -= 1, std::domain_error, "cannot use offsets with object iterators"); } { auto it = j_object.crbegin(); CHECK_THROWS_AS(it -= 1, std::domain_error); + CHECK_THROWS_NAME(it -= 1, std::domain_error, "cannot use offsets with object iterators"); } { auto it = j_object.rbegin(); CHECK_THROWS_AS(it - 1, std::domain_error); + CHECK_THROWS_NAME(it - 1, std::domain_error, "cannot use offsets with object iterators"); } { auto it = j_object.crbegin(); CHECK_THROWS_AS(it - 1, std::domain_error); + CHECK_THROWS_NAME(it - 1, std::domain_error, "cannot use offsets with object iterators"); } { auto it = j_object.rbegin(); CHECK_THROWS_AS(it - it, std::domain_error); + CHECK_THROWS_NAME(it - it, std::domain_error, "cannot use offsets with object iterators"); } { auto it = j_object.crbegin(); CHECK_THROWS_AS(it - it, std::domain_error); + CHECK_THROWS_NAME(it - it, std::domain_error, "cannot use offsets with object iterators"); } } @@ -6304,11 +6364,15 @@ TEST_CASE("iterators") auto it = j_object.rbegin(); CHECK_THROWS_AS(it[0], std::domain_error); CHECK_THROWS_AS(it[1], std::domain_error); + CHECK_THROWS_NAME(it[0], std::domain_error, "cannot use offsets with object iterators"); + CHECK_THROWS_NAME(it[1], std::domain_error, "cannot use offsets with object iterators"); } { auto it = j_object.crbegin(); CHECK_THROWS_AS(it[0], std::domain_error); CHECK_THROWS_AS(it[1], std::domain_error); + CHECK_THROWS_NAME(it[0], std::domain_error, "cannot use offsets with object iterators"); + CHECK_THROWS_NAME(it[1], std::domain_error, "cannot use offsets with object iterators"); } } @@ -6340,11 +6404,15 @@ TEST_CASE("iterators") auto it = j_null.rbegin(); CHECK_THROWS_AS(it[0], std::out_of_range); CHECK_THROWS_AS(it[1], std::out_of_range); + CHECK_THROWS_NAME(it[0], std::out_of_range, "cannot get value"); + CHECK_THROWS_NAME(it[1], std::out_of_range, "cannot get value"); } { auto it = j_null.crbegin(); CHECK_THROWS_AS(it[0], std::out_of_range); CHECK_THROWS_AS(it[1], std::out_of_range); + CHECK_THROWS_NAME(it[0], std::out_of_range, "cannot get value"); + CHECK_THROWS_NAME(it[1], std::out_of_range, "cannot get value"); } } @@ -6354,11 +6422,13 @@ TEST_CASE("iterators") auto it = j_value.rbegin(); CHECK(it[0] == json(42)); CHECK_THROWS_AS(it[1], std::out_of_range); + CHECK_THROWS_NAME(it[1], std::out_of_range, "cannot get value"); } { auto it = j_value.crbegin(); CHECK(it[0] == json(42)); CHECK_THROWS_AS(it[1], std::out_of_range); + CHECK_THROWS_NAME(it[1], std::out_of_range, "cannot get value"); } } } @@ -6959,16 +7029,7 @@ TEST_CASE("modifiers") { json j = 1; CHECK_THROWS_AS(j.push_back("Hello"), std::domain_error); - - // exception name - try - { - j.push_back("Hello"); - } - catch (std::domain_error& e) - { - CHECK(e.what() == std::string("cannot use push_back() with number")); - } + CHECK_THROWS_NAME(j.push_back("Hello"), std::domain_error, "cannot use push_back() with number"); } } @@ -6998,16 +7059,7 @@ TEST_CASE("modifiers") json j = 1; json k("Hello"); CHECK_THROWS_AS(j.push_back(k), std::domain_error); - - // exception name - try - { - j.push_back(k); - } - catch (std::domain_error& e) - { - CHECK(e.what() == std::string("cannot use push_back() with number")); - } + CHECK_THROWS_NAME(j.push_back(k), std::domain_error, "cannot use push_back() with number"); } } } @@ -7040,16 +7092,8 @@ TEST_CASE("modifiers") json j = 1; json k("Hello"); CHECK_THROWS_AS(j.push_back(json::object_t::value_type({"one", 1})), std::domain_error); - - // exception name - try - { - j.push_back(k); - } - catch (std::domain_error& e) - { - CHECK(e.what() == std::string("cannot use push_back() with number")); - } + CHECK_THROWS_NAME(j.push_back(json::object_t::value_type({"one", 1})), std::domain_error, + "cannot use push_back() with number"); } } } @@ -7081,16 +7125,7 @@ TEST_CASE("modifiers") { json j = 1; CHECK_THROWS_AS(j += "Hello", std::domain_error); - - // exception name - try - { - j += "Hello"; - } - catch (std::domain_error& e) - { - CHECK(e.what() == std::string("cannot use push_back() with number")); - } + CHECK_THROWS_NAME(j += "Hello", std::domain_error, "cannot use push_back() with number"); } } @@ -7120,16 +7155,7 @@ TEST_CASE("modifiers") json j = 1; json k("Hello"); CHECK_THROWS_AS(j += k, std::domain_error); - - // exception name - try - { - j += k; - } - catch (std::domain_error& e) - { - CHECK(e.what() == std::string("cannot use push_back() with number")); - } + CHECK_THROWS_NAME(j += k, std::domain_error, "cannot use push_back() with number"); } } } @@ -7162,17 +7188,8 @@ TEST_CASE("modifiers") json j = 1; json k("Hello"); CHECK_THROWS_AS(j += json::object_t::value_type({"one", 1}), std::domain_error); - - - // exception name - try - { - j += json::object_t::value_type({"one", 1}); - } - catch (std::domain_error& e) - { - CHECK(e.what() == std::string("cannot use push_back() with number")); - } + CHECK_THROWS_NAME(j += json::object_t::value_type({"one", 1}), std::domain_error, + "cannot use push_back() with number"); } } } @@ -7310,24 +7327,10 @@ TEST_CASE("modifiers") CHECK_THROWS_AS(j_array.insert(j_array.end(), j_other_array.begin(), j_other_array2.end()), std::domain_error); - // exception names - try - { - j_array.insert(j_array.end(), j_array.begin(), j_array.end()); - } - catch (std::domain_error& e) - { - CHECK(e.what() == std::string("passed iterators may not belong to container")); - } - - try - { - j_array.insert(j_array.end(), j_other_array.begin(), j_other_array2.end()); - } - catch (std::domain_error& e) - { - CHECK(e.what() == std::string("iterators do not fit")); - } + CHECK_THROWS_NAME(j_array.insert(j_array.end(), j_array.begin(), j_array.end()), std::domain_error, + "passed iterators may not belong to container"); + CHECK_THROWS_NAME(j_array.insert(j_array.end(), j_other_array.begin(), j_other_array2.end()), + std::domain_error, "iterators do not fit"); } } @@ -7372,6 +7375,17 @@ TEST_CASE("modifiers") CHECK_THROWS_AS(j_array.insert(j_another_array.end(), j_yet_another_array.begin(), j_yet_another_array.end()), std::domain_error); CHECK_THROWS_AS(j_array.insert(j_another_array.end(), {1, 2, 3, 4}), std::domain_error); + + CHECK_THROWS_NAME(j_array.insert(j_another_array.end(), 10), std::domain_error, + "iterator does not fit current value"); + CHECK_THROWS_NAME(j_array.insert(j_another_array.end(), j_value), std::domain_error, + "iterator does not fit current value"); + CHECK_THROWS_NAME(j_array.insert(j_another_array.end(), 10, 11), std::domain_error, + "iterator does not fit current value"); + CHECK_THROWS_NAME(j_array.insert(j_another_array.end(), j_yet_another_array.begin(), + j_yet_another_array.end()), std::domain_error, "iterator does not fit current value"); + CHECK_THROWS_NAME(j_array.insert(j_another_array.end(), {1, 2, 3, 4}), std::domain_error, + "iterator does not fit current value"); } SECTION("non-array type") @@ -7385,6 +7399,17 @@ TEST_CASE("modifiers") CHECK_THROWS_AS(j_nonarray.insert(j_nonarray.end(), j_yet_another_array.begin(), j_yet_another_array.end()), std::domain_error); CHECK_THROWS_AS(j_nonarray.insert(j_nonarray.end(), {1, 2, 3, 4}), std::domain_error); + + CHECK_THROWS_NAME(j_nonarray.insert(j_nonarray.end(), 10), std::domain_error, + "cannot use insert() with number"); + CHECK_THROWS_NAME(j_nonarray.insert(j_nonarray.end(), j_value), std::domain_error, + "cannot use insert() with number"); + CHECK_THROWS_NAME(j_nonarray.insert(j_nonarray.end(), 10, 11), std::domain_error, + "cannot use insert() with number"); + CHECK_THROWS_NAME(j_nonarray.insert(j_nonarray.end(), j_yet_another_array.begin(), + j_yet_another_array.end()), std::domain_error, "cannot use insert() with number"); + CHECK_THROWS_NAME(j_nonarray.insert(j_nonarray.end(), {1, 2, 3, 4}), std::domain_error, + "cannot use insert() with number"); } } @@ -7437,6 +7462,7 @@ TEST_CASE("modifiers") json::array_t a = {"foo", "bar", "baz"}; CHECK_THROWS_AS(j.swap(a), std::domain_error); + CHECK_THROWS_NAME(j.swap(a), std::domain_error, "cannot use swap() with number"); } } @@ -7462,6 +7488,7 @@ TEST_CASE("modifiers") json::object_t o = {{"cow", "Kuh"}, {"chicken", "Huhn"}}; CHECK_THROWS_AS(j.swap(o), std::domain_error); + CHECK_THROWS_NAME(j.swap(o), std::domain_error, "cannot use swap() with number"); } } @@ -7487,6 +7514,7 @@ TEST_CASE("modifiers") json::string_t s = "Hallo Welt"; CHECK_THROWS_AS(j.swap(s), std::domain_error); + CHECK_THROWS_NAME(j.swap(s), std::domain_error, "cannot use swap() with number"); } } } @@ -7871,6 +7899,7 @@ TEST_CASE("iterator class") json j(json::value_t::null); json::iterator it = j.begin(); CHECK_THROWS_AS(*it, std::out_of_range); + CHECK_THROWS_NAME(*it, std::out_of_range, "cannot get value"); } SECTION("number") @@ -7880,6 +7909,7 @@ TEST_CASE("iterator class") CHECK(*it == json(17)); it = j.end(); CHECK_THROWS_AS(*it, std::out_of_range); + CHECK_THROWS_NAME(*it, std::out_of_range, "cannot get value"); } SECTION("object") @@ -7904,6 +7934,7 @@ TEST_CASE("iterator class") json j(json::value_t::null); json::iterator it = j.begin(); CHECK_THROWS_AS(it->type_name(), std::out_of_range); + CHECK_THROWS_NAME(it->type_name(), std::out_of_range, "cannot get value"); } SECTION("number") @@ -7913,6 +7944,7 @@ TEST_CASE("iterator class") CHECK(it->type_name() == "number"); it = j.end(); CHECK_THROWS_AS(it->type_name(), std::out_of_range); + CHECK_THROWS_NAME(it->type_name(), std::out_of_range, "cannot get value"); } SECTION("object") @@ -8235,6 +8267,7 @@ TEST_CASE("const_iterator class") json j(json::value_t::null); json::const_iterator it = j.cbegin(); CHECK_THROWS_AS(*it, std::out_of_range); + CHECK_THROWS_NAME(*it, std::out_of_range, "cannot get value"); } SECTION("number") @@ -8244,6 +8277,7 @@ TEST_CASE("const_iterator class") CHECK(*it == json(17)); it = j.cend(); CHECK_THROWS_AS(*it, std::out_of_range); + CHECK_THROWS_NAME(*it, std::out_of_range, "cannot get value"); } SECTION("object") @@ -8268,6 +8302,7 @@ TEST_CASE("const_iterator class") json j(json::value_t::null); json::const_iterator it = j.cbegin(); CHECK_THROWS_AS(it->type_name(), std::out_of_range); + CHECK_THROWS_NAME(it->type_name(), std::out_of_range, "cannot get value"); } SECTION("number") @@ -8277,6 +8312,7 @@ TEST_CASE("const_iterator class") CHECK(it->type_name() == "number"); it = j.cend(); CHECK_THROWS_AS(it->type_name(), std::out_of_range); + CHECK_THROWS_NAME(it->type_name(), std::out_of_range, "cannot get value"); } SECTION("object") @@ -8675,6 +8711,8 @@ TEST_CASE("lexer class") { CHECK(json::lexer::to_unicode(0x1F4A9) == "💩"); CHECK_THROWS_AS(json::lexer::to_unicode(0x200000), std::out_of_range); + CHECK_THROWS_NAME(json::lexer::to_unicode(0x200000), std::out_of_range, + "code points above 0x10FFFF are invalid"); } } @@ -8734,11 +8772,19 @@ TEST_CASE("parser class") { // error: tab in string CHECK_THROWS_AS(json::parser("\"\t\"").parse(), std::invalid_argument); + CHECK_THROWS_NAME(json::parser("\"\t\"").parse(), std::invalid_argument, + "parse error - unexpected '\"'"); // error: newline in string CHECK_THROWS_AS(json::parser("\"\n\"").parse(), std::invalid_argument); CHECK_THROWS_AS(json::parser("\"\r\"").parse(), std::invalid_argument); + CHECK_THROWS_NAME(json::parser("\"\n\"").parse(), std::invalid_argument, + "parse error - unexpected '\"'"); + CHECK_THROWS_NAME(json::parser("\"\r\"").parse(), std::invalid_argument, + "parse error - unexpected '\"'"); // error: backspace in string CHECK_THROWS_AS(json::parser("\"\b\"").parse(), std::invalid_argument); + CHECK_THROWS_NAME(json::parser("\"\b\"").parse(), std::invalid_argument, + "parse error - unexpected '\"'"); } SECTION("escaped") @@ -8875,6 +8921,39 @@ TEST_CASE("parser class") CHECK_THROWS_AS(json::parser("-0e0-:").parse(), std::invalid_argument); CHECK_THROWS_AS(json::parser("-0e-:").parse(), std::invalid_argument); CHECK_THROWS_AS(json::parser("-0f").parse(), std::invalid_argument); + + CHECK_THROWS_NAME(json::parser("01").parse(), std::invalid_argument, + "parse error - 0 is not a number"); + CHECK_THROWS_NAME(json::parser("--1").parse(), std::invalid_argument, + "parse error - unexpected '-'"); + CHECK_THROWS_NAME(json::parser("1.").parse(), std::invalid_argument, + "parse error - 1 is not a number"); + CHECK_THROWS_NAME(json::parser("1E").parse(), std::invalid_argument, + "parse error - unexpected 'E' (); expected "); + CHECK_THROWS_NAME(json::parser("1E-").parse(), std::invalid_argument, + "parse error - unexpected 'E' (); expected "); + CHECK_THROWS_NAME(json::parser("1.E1").parse(), std::invalid_argument, + "parse error - 1 is not a number"); + CHECK_THROWS_NAME(json::parser("-1E").parse(), std::invalid_argument, + "parse error - unexpected 'E' (); expected "); + CHECK_THROWS_NAME(json::parser("-0E#").parse(), std::invalid_argument, + "parse error - unexpected 'E' (); expected "); + CHECK_THROWS_NAME(json::parser("-0E-#").parse(), std::invalid_argument, + "parse error - unexpected 'E' (); expected "); + CHECK_THROWS_NAME(json::parser("-0#").parse(), std::invalid_argument, + "parse error - unexpected '#' (); expected "); + CHECK_THROWS_NAME(json::parser("-0.0:").parse(), std::invalid_argument, + "parse error - unexpected ':' (:); expected "); + CHECK_THROWS_NAME(json::parser("-0.0Z").parse(), std::invalid_argument, + "parse error - unexpected 'Z' (); expected "); + CHECK_THROWS_NAME(json::parser("-0E123:").parse(), std::invalid_argument, + "parse error - unexpected ':' (:); expected "); + CHECK_THROWS_NAME(json::parser("-0e0-:").parse(), std::invalid_argument, + "parse error - unexpected '-' (); expected "); + CHECK_THROWS_NAME(json::parser("-0e-:").parse(), std::invalid_argument, + "parse error - unexpected 'e' (); expected "); + CHECK_THROWS_NAME(json::parser("-0f").parse(), std::invalid_argument, + "parse error - unexpected 'f' (); expected "); } } } @@ -8899,44 +8978,89 @@ TEST_CASE("parser class") // unexpected end of null CHECK_THROWS_AS(json::parser("n").parse(), std::invalid_argument); - CHECK_THROWS_AS(json::parser("n").parse(), std::invalid_argument); CHECK_THROWS_AS(json::parser("nu").parse(), std::invalid_argument); CHECK_THROWS_AS(json::parser("nul").parse(), std::invalid_argument); + CHECK_THROWS_NAME(json::parser("n").parse(), std::invalid_argument, "parse error - unexpected 'n'"); + CHECK_THROWS_NAME(json::parser("nu").parse(), std::invalid_argument, + "parse error - unexpected 'n'"); + CHECK_THROWS_NAME(json::parser("nul").parse(), std::invalid_argument, + "parse error - unexpected 'n'"); // unexpected end of true CHECK_THROWS_AS(json::parser("t").parse(), std::invalid_argument); - CHECK_THROWS_AS(json::parser("t").parse(), std::invalid_argument); CHECK_THROWS_AS(json::parser("tr").parse(), std::invalid_argument); CHECK_THROWS_AS(json::parser("tru").parse(), std::invalid_argument); + CHECK_THROWS_NAME(json::parser("t").parse(), std::invalid_argument, "parse error - unexpected 't'"); + CHECK_THROWS_NAME(json::parser("tr").parse(), std::invalid_argument, + "parse error - unexpected 't'"); + CHECK_THROWS_NAME(json::parser("tru").parse(), std::invalid_argument, + "parse error - unexpected 't'"); // unexpected end of false CHECK_THROWS_AS(json::parser("f").parse(), std::invalid_argument); CHECK_THROWS_AS(json::parser("fa").parse(), std::invalid_argument); CHECK_THROWS_AS(json::parser("fal").parse(), std::invalid_argument); CHECK_THROWS_AS(json::parser("fals").parse(), std::invalid_argument); + CHECK_THROWS_NAME(json::parser("f").parse(), std::invalid_argument, "parse error - unexpected 'f'"); + CHECK_THROWS_NAME(json::parser("fa").parse(), std::invalid_argument, + "parse error - unexpected 'f'"); + CHECK_THROWS_NAME(json::parser("fal").parse(), std::invalid_argument, + "parse error - unexpected 'f'"); + CHECK_THROWS_NAME(json::parser("fals").parse(), std::invalid_argument, + "parse error - unexpected 'f'"); - // unexpected end of array + // missing/unexpected end of array + // TODO: Better error messages - "parse error - unexpected '" just ends CHECK_THROWS_AS(json::parser("[").parse(), std::invalid_argument); CHECK_THROWS_AS(json::parser("[1").parse(), std::invalid_argument); CHECK_THROWS_AS(json::parser("[1,").parse(), std::invalid_argument); CHECK_THROWS_AS(json::parser("[1,]").parse(), std::invalid_argument); CHECK_THROWS_AS(json::parser("]").parse(), std::invalid_argument); + CHECK_THROWS_NAME(json::parser("[").parse(), std::invalid_argument, "parse error - unexpected '"); + CHECK_THROWS_NAME(json::parser("[1").parse(), std::invalid_argument, "parse error - unexpected '"); + CHECK_THROWS_NAME(json::parser("[1,").parse(), std::invalid_argument, "parse error - unexpected '"); + CHECK_THROWS_NAME(json::parser("[1,]").parse(), std::invalid_argument, + "parse error - unexpected ']'"); + CHECK_THROWS_NAME(json::parser("]").parse(), std::invalid_argument, "parse error - unexpected ']'"); - // unexpected end of object + // missing/unexpected end of object + // TODO: Better error messages - "parse error - unexpected '" just ends CHECK_THROWS_AS(json::parser("{").parse(), std::invalid_argument); CHECK_THROWS_AS(json::parser("{\"foo\"").parse(), std::invalid_argument); CHECK_THROWS_AS(json::parser("{\"foo\":").parse(), std::invalid_argument); CHECK_THROWS_AS(json::parser("{\"foo\":}").parse(), std::invalid_argument); CHECK_THROWS_AS(json::parser("{\"foo\":1,}").parse(), std::invalid_argument); CHECK_THROWS_AS(json::parser("}").parse(), std::invalid_argument); + CHECK_THROWS_NAME(json::parser("{").parse(), std::invalid_argument, "parse error - unexpected '"); + CHECK_THROWS_NAME(json::parser("{\"foo\"").parse(), std::invalid_argument, + "parse error - unexpected '"); + CHECK_THROWS_NAME(json::parser("{\"foo\":").parse(), std::invalid_argument, + "parse error - unexpected '"); + CHECK_THROWS_NAME(json::parser("{\"foo\":}").parse(), std::invalid_argument, + "parse error - unexpected '}'"); + CHECK_THROWS_NAME(json::parser("{\"foo\":1,}").parse(), std::invalid_argument, + "parse error - unexpected '}' (}); expected string literal"); + CHECK_THROWS_NAME(json::parser("}").parse(), std::invalid_argument, "parse error - unexpected '}'"); - // unexpected end of string + // missing/unexpected end of string CHECK_THROWS_AS(json::parser("\"").parse(), std::invalid_argument); CHECK_THROWS_AS(json::parser("\"\\\"").parse(), std::invalid_argument); CHECK_THROWS_AS(json::parser("\"\\u\"").parse(), std::invalid_argument); CHECK_THROWS_AS(json::parser("\"\\u0\"").parse(), std::invalid_argument); CHECK_THROWS_AS(json::parser("\"\\u01\"").parse(), std::invalid_argument); CHECK_THROWS_AS(json::parser("\"\\u012\"").parse(), std::invalid_argument); + CHECK_THROWS_NAME(json::parser("\"").parse(), std::invalid_argument, + "parse error - unexpected '\"'"); + CHECK_THROWS_NAME(json::parser("\"\\\"").parse(), std::invalid_argument, + "parse error - unexpected '\"'"); + CHECK_THROWS_NAME(json::parser("\"\\u\"").parse(), std::invalid_argument, + "parse error - unexpected '\"'"); + CHECK_THROWS_NAME(json::parser("\"\\u0\"").parse(), std::invalid_argument, + "parse error - unexpected '\"'"); + CHECK_THROWS_NAME(json::parser("\"\\u01\"").parse(), std::invalid_argument, + "parse error - unexpected '\"'"); + CHECK_THROWS_NAME(json::parser("\"\\u012\"").parse(), std::invalid_argument, + "parse error - unexpected '\"'"); // invalid escapes for (int c = 1; c < 128; ++c) @@ -8969,6 +9093,7 @@ TEST_CASE("parser class") default: { CHECK_THROWS_AS(json::parser(s).parse(), std::invalid_argument); + CHECK_THROWS_NAME(json::parser(s).parse(), std::invalid_argument, "parse error - unexpected '\"'"); break; } } @@ -9037,16 +9162,28 @@ TEST_CASE("parser class") CHECK_THROWS_AS(json::parser(s2).parse(), std::invalid_argument); CHECK_THROWS_AS(json::parser(s3).parse(), std::invalid_argument); CHECK_THROWS_AS(json::parser(s4).parse(), std::invalid_argument); + + CHECK_THROWS_NAME(json::parser(s1).parse(), std::invalid_argument, "parse error - unexpected '\"'"); + CHECK_THROWS_NAME(json::parser(s2).parse(), std::invalid_argument, "parse error - unexpected '\"'"); + CHECK_THROWS_NAME(json::parser(s3).parse(), std::invalid_argument, "parse error - unexpected '\"'"); + CHECK_THROWS_NAME(json::parser(s4).parse(), std::invalid_argument, "parse error - unexpected '\"'"); } } } // missing part of a surrogate pair CHECK_THROWS_AS(json::parse("\"\\uD80C\""), std::invalid_argument); + CHECK_THROWS_NAME(json::parse("\"\\uD80C\""), std::invalid_argument, "missing low surrogate"); // invalid surrogate pair CHECK_THROWS_AS(json::parse("\"\\uD80C\\uD80C\""), std::invalid_argument); CHECK_THROWS_AS(json::parse("\"\\uD80C\\u0000\""), std::invalid_argument); CHECK_THROWS_AS(json::parse("\"\\uD80C\\uFFFF\""), std::invalid_argument); + CHECK_THROWS_NAME(json::parse("\"\\uD80C\\uD80C\""), std::invalid_argument, + "missing or wrong low surrogate"); + CHECK_THROWS_NAME(json::parse("\"\\uD80C\\u0000\""), std::invalid_argument, + "missing or wrong low surrogate"); + CHECK_THROWS_NAME(json::parse("\"\\uD80C\\uFFFF\""), std::invalid_argument, + "missing or wrong low surrogate"); } SECTION("callback function") @@ -9639,6 +9776,8 @@ TEST_CASE("algorithms") { json j({{"one", 1}, {"two", 2}}); CHECK_THROWS_AS(std::sort(j.begin(), j.end()), std::domain_error); + CHECK_THROWS_NAME(std::sort(j.begin(), j.end()), std::domain_error, + "cannot use offsets with object iterators"); } } From d6b8830e03d25fdb52defd616ee9779624f52d1b Mon Sep 17 00:00:00 2001 From: Niels Date: Sat, 26 Dec 2015 13:17:32 +0100 Subject: [PATCH 36/61] more work on exceptions (#160) --- README.md | 2 +- src/json.hpp | 28 ++++++++-------- src/json.hpp.re2c | 30 ++++++++--------- test/unit.cpp | 85 +++++++++++++++++++++++++++++++---------------- 4 files changed, 87 insertions(+), 58 deletions(-) diff --git a/README.md b/README.md index 42c49dd2f..8c1ea449d 100644 --- a/README.md +++ b/README.md @@ -398,7 +398,7 @@ $ make $ ./json_unit "*" =============================================================================== -All tests passed (3341947 assertions in 28 test cases) +All tests passed (3343239 assertions in 28 test cases) ``` For more information, have a look at the file [.travis.yml](https://github.com/nlohmann/json/blob/master/.travis.yml). diff --git a/src/json.hpp b/src/json.hpp index 253bb3111..dbb18576e 100644 --- a/src/json.hpp +++ b/src/json.hpp @@ -6459,21 +6459,21 @@ class basic_json case token_type::value_number: return "number literal"; case token_type::begin_array: - return "["; + return "'['"; case token_type::begin_object: - return "{"; + return "'{'"; case token_type::end_array: - return "]"; + return "']'"; case token_type::end_object: - return "}"; + return "'}'"; case token_type::name_separator: - return ":"; + return "':'"; case token_type::value_separator: - return ","; + return "','"; case token_type::parse_error: return ""; case token_type::end_of_input: - return ""; + return "end of input"; default: { // catch non-enum values @@ -7752,10 +7752,10 @@ basic_json_parser_64: { if (t != last_token) { - std::string error_msg = "parse error - unexpected \'"; - error_msg += m_lexer.get_token(); - error_msg += "\' (" + lexer::token_type_name(last_token); - error_msg += "); expected " + lexer::token_type_name(t); + std::string error_msg = "parse error - unexpected "; + error_msg += (last_token == lexer::token_type::parse_error ? ("'" + m_lexer.get_token() + "'") : + lexer::token_type_name(last_token)); + error_msg += "; expected " + lexer::token_type_name(t); throw std::invalid_argument(error_msg); } } @@ -7764,9 +7764,9 @@ basic_json_parser_64: { if (t == last_token) { - std::string error_msg = "parse error - unexpected \'"; - error_msg += m_lexer.get_token(); - error_msg += "\'"; + std::string error_msg = "parse error - unexpected "; + error_msg += (last_token == lexer::token_type::parse_error ? ("'" + m_lexer.get_token() + "'") : + lexer::token_type_name(last_token)); throw std::invalid_argument(error_msg); } } diff --git a/src/json.hpp.re2c b/src/json.hpp.re2c index 84ceccc3b..9ef7f3300 100644 --- a/src/json.hpp.re2c +++ b/src/json.hpp.re2c @@ -6441,7 +6441,7 @@ class basic_json return result; } - /// return name of values of type token_type + /// return name of values of type token_type (only used for errors) static std::string token_type_name(token_type t) { switch (t) @@ -6459,21 +6459,21 @@ class basic_json case token_type::value_number: return "number literal"; case token_type::begin_array: - return "["; + return "'['"; case token_type::begin_object: - return "{"; + return "'{'"; case token_type::end_array: - return "]"; + return "']'"; case token_type::end_object: - return "}"; + return "'}'"; case token_type::name_separator: - return ":"; + return "':'"; case token_type::value_separator: - return ","; + return "','"; case token_type::parse_error: return ""; case token_type::end_of_input: - return ""; + return "end of input"; default: { // catch non-enum values @@ -7031,10 +7031,10 @@ class basic_json { if (t != last_token) { - std::string error_msg = "parse error - unexpected \'"; - error_msg += m_lexer.get_token(); - error_msg += "\' (" + lexer::token_type_name(last_token); - error_msg += "); expected " + lexer::token_type_name(t); + std::string error_msg = "parse error - unexpected "; + error_msg += (last_token == lexer::token_type::parse_error ? ("'" + m_lexer.get_token() + "'") : + lexer::token_type_name(last_token)); + error_msg += "; expected " + lexer::token_type_name(t); throw std::invalid_argument(error_msg); } } @@ -7043,9 +7043,9 @@ class basic_json { if (t == last_token) { - std::string error_msg = "parse error - unexpected \'"; - error_msg += m_lexer.get_token(); - error_msg += "\'"; + std::string error_msg = "parse error - unexpected "; + error_msg += (last_token == lexer::token_type::parse_error ? ("'" + m_lexer.get_token() + "'") : + lexer::token_type_name(last_token)); throw std::invalid_argument(error_msg); } } diff --git a/test/unit.cpp b/test/unit.cpp index 57f6adb4d..6386fd695 100644 --- a/test/unit.cpp +++ b/test/unit.cpp @@ -8647,14 +8647,14 @@ TEST_CASE("lexer class") CHECK(json::lexer::token_type_name(json::lexer::token_type::literal_null) == "null literal"); CHECK(json::lexer::token_type_name(json::lexer::token_type::value_string) == "string literal"); CHECK(json::lexer::token_type_name(json::lexer::token_type::value_number) == "number literal"); - CHECK(json::lexer::token_type_name(json::lexer::token_type::begin_array) == "["); - CHECK(json::lexer::token_type_name(json::lexer::token_type::begin_object) == "{"); - CHECK(json::lexer::token_type_name(json::lexer::token_type::end_array) == "]"); - CHECK(json::lexer::token_type_name(json::lexer::token_type::end_object) == "}"); - CHECK(json::lexer::token_type_name(json::lexer::token_type::name_separator) == ":"); - CHECK(json::lexer::token_type_name(json::lexer::token_type::value_separator) == ","); + CHECK(json::lexer::token_type_name(json::lexer::token_type::begin_array) == "'['"); + CHECK(json::lexer::token_type_name(json::lexer::token_type::begin_object) == "'{'"); + CHECK(json::lexer::token_type_name(json::lexer::token_type::end_array) == "']'"); + CHECK(json::lexer::token_type_name(json::lexer::token_type::end_object) == "'}'"); + CHECK(json::lexer::token_type_name(json::lexer::token_type::name_separator) == "':'"); + CHECK(json::lexer::token_type_name(json::lexer::token_type::value_separator) == "','"); CHECK(json::lexer::token_type_name(json::lexer::token_type::parse_error) == ""); - CHECK(json::lexer::token_type_name(json::lexer::token_type::end_of_input) == ""); + CHECK(json::lexer::token_type_name(json::lexer::token_type::end_of_input) == "end of input"); } SECTION("parse errors on first character") @@ -8929,31 +8929,31 @@ TEST_CASE("parser class") CHECK_THROWS_NAME(json::parser("1.").parse(), std::invalid_argument, "parse error - 1 is not a number"); CHECK_THROWS_NAME(json::parser("1E").parse(), std::invalid_argument, - "parse error - unexpected 'E' (); expected "); + "parse error - unexpected 'E'; expected end of input"); CHECK_THROWS_NAME(json::parser("1E-").parse(), std::invalid_argument, - "parse error - unexpected 'E' (); expected "); + "parse error - unexpected 'E'; expected end of input"); CHECK_THROWS_NAME(json::parser("1.E1").parse(), std::invalid_argument, "parse error - 1 is not a number"); CHECK_THROWS_NAME(json::parser("-1E").parse(), std::invalid_argument, - "parse error - unexpected 'E' (); expected "); + "parse error - unexpected 'E'; expected end of input"); CHECK_THROWS_NAME(json::parser("-0E#").parse(), std::invalid_argument, - "parse error - unexpected 'E' (); expected "); + "parse error - unexpected 'E'; expected end of input"); CHECK_THROWS_NAME(json::parser("-0E-#").parse(), std::invalid_argument, - "parse error - unexpected 'E' (); expected "); + "parse error - unexpected 'E'; expected end of input"); CHECK_THROWS_NAME(json::parser("-0#").parse(), std::invalid_argument, - "parse error - unexpected '#' (); expected "); + "parse error - unexpected '#'; expected end of input"); CHECK_THROWS_NAME(json::parser("-0.0:").parse(), std::invalid_argument, - "parse error - unexpected ':' (:); expected "); + "parse error - unexpected ':'; expected end of input"); CHECK_THROWS_NAME(json::parser("-0.0Z").parse(), std::invalid_argument, - "parse error - unexpected 'Z' (); expected "); + "parse error - unexpected 'Z'; expected end of input"); CHECK_THROWS_NAME(json::parser("-0E123:").parse(), std::invalid_argument, - "parse error - unexpected ':' (:); expected "); + "parse error - unexpected ':'; expected end of input"); CHECK_THROWS_NAME(json::parser("-0e0-:").parse(), std::invalid_argument, - "parse error - unexpected '-' (); expected "); + "parse error - unexpected '-'; expected end of input"); CHECK_THROWS_NAME(json::parser("-0e-:").parse(), std::invalid_argument, - "parse error - unexpected 'e' (); expected "); + "parse error - unexpected 'e'; expected end of input"); CHECK_THROWS_NAME(json::parser("-0f").parse(), std::invalid_argument, - "parse error - unexpected 'f' (); expected "); + "parse error - unexpected 'f'; expected end of input"); } } } @@ -8975,6 +8975,33 @@ TEST_CASE("parser class") CHECK_THROWS_AS(json::parser("1E.").parse(), std::invalid_argument); CHECK_THROWS_AS(json::parser("1E/").parse(), std::invalid_argument); CHECK_THROWS_AS(json::parser("1E:").parse(), std::invalid_argument); + CHECK_THROWS_NAME(json::parser("0.").parse(), std::invalid_argument, + "parse error - 0 is not a number"); + CHECK_THROWS_NAME(json::parser("-").parse(), std::invalid_argument, "parse error - unexpected '-'"); + CHECK_THROWS_NAME(json::parser("--").parse(), std::invalid_argument, + "parse error - unexpected '-'"); + CHECK_THROWS_NAME(json::parser("-0.").parse(), std::invalid_argument, + "parse error - -0 is not a number"); + CHECK_THROWS_NAME(json::parser("-.").parse(), std::invalid_argument, + "parse error - unexpected '-'"); + CHECK_THROWS_NAME(json::parser("-:").parse(), std::invalid_argument, + "parse error - unexpected '-'"); + CHECK_THROWS_NAME(json::parser("0.:").parse(), std::invalid_argument, + "parse error - 0 is not a number"); + CHECK_THROWS_NAME(json::parser("e.").parse(), std::invalid_argument, + "parse error - unexpected 'e'"); + CHECK_THROWS_NAME(json::parser("1e.").parse(), std::invalid_argument, + "parse error - unexpected 'e'; expected end of input"); + CHECK_THROWS_NAME(json::parser("1e/").parse(), std::invalid_argument, + "parse error - unexpected 'e'; expected end of input"); + CHECK_THROWS_NAME(json::parser("1e:").parse(), std::invalid_argument, + "parse error - unexpected 'e'; expected end of input"); + CHECK_THROWS_NAME(json::parser("1E.").parse(), std::invalid_argument, + "parse error - unexpected 'E'; expected end of input"); + CHECK_THROWS_NAME(json::parser("1E/").parse(), std::invalid_argument, + "parse error - unexpected 'E'; expected end of input"); + CHECK_THROWS_NAME(json::parser("1E:").parse(), std::invalid_argument, + "parse error - unexpected 'E'; expected end of input"); // unexpected end of null CHECK_THROWS_AS(json::parser("n").parse(), std::invalid_argument); @@ -9010,36 +9037,38 @@ TEST_CASE("parser class") "parse error - unexpected 'f'"); // missing/unexpected end of array - // TODO: Better error messages - "parse error - unexpected '" just ends CHECK_THROWS_AS(json::parser("[").parse(), std::invalid_argument); CHECK_THROWS_AS(json::parser("[1").parse(), std::invalid_argument); CHECK_THROWS_AS(json::parser("[1,").parse(), std::invalid_argument); CHECK_THROWS_AS(json::parser("[1,]").parse(), std::invalid_argument); CHECK_THROWS_AS(json::parser("]").parse(), std::invalid_argument); - CHECK_THROWS_NAME(json::parser("[").parse(), std::invalid_argument, "parse error - unexpected '"); - CHECK_THROWS_NAME(json::parser("[1").parse(), std::invalid_argument, "parse error - unexpected '"); - CHECK_THROWS_NAME(json::parser("[1,").parse(), std::invalid_argument, "parse error - unexpected '"); + CHECK_THROWS_NAME(json::parser("[").parse(), std::invalid_argument, + "parse error - unexpected end of input"); + CHECK_THROWS_NAME(json::parser("[1").parse(), std::invalid_argument, + "parse error - unexpected end of input; expected ']'"); + CHECK_THROWS_NAME(json::parser("[1,").parse(), std::invalid_argument, + "parse error - unexpected end of input"); CHECK_THROWS_NAME(json::parser("[1,]").parse(), std::invalid_argument, "parse error - unexpected ']'"); CHECK_THROWS_NAME(json::parser("]").parse(), std::invalid_argument, "parse error - unexpected ']'"); // missing/unexpected end of object - // TODO: Better error messages - "parse error - unexpected '" just ends CHECK_THROWS_AS(json::parser("{").parse(), std::invalid_argument); CHECK_THROWS_AS(json::parser("{\"foo\"").parse(), std::invalid_argument); CHECK_THROWS_AS(json::parser("{\"foo\":").parse(), std::invalid_argument); CHECK_THROWS_AS(json::parser("{\"foo\":}").parse(), std::invalid_argument); CHECK_THROWS_AS(json::parser("{\"foo\":1,}").parse(), std::invalid_argument); CHECK_THROWS_AS(json::parser("}").parse(), std::invalid_argument); - CHECK_THROWS_NAME(json::parser("{").parse(), std::invalid_argument, "parse error - unexpected '"); + CHECK_THROWS_NAME(json::parser("{").parse(), std::invalid_argument, + "parse error - unexpected end of input; expected string literal"); CHECK_THROWS_NAME(json::parser("{\"foo\"").parse(), std::invalid_argument, - "parse error - unexpected '"); + "parse error - unexpected end of input; expected ':'"); CHECK_THROWS_NAME(json::parser("{\"foo\":").parse(), std::invalid_argument, - "parse error - unexpected '"); + "parse error - unexpected end of input"); CHECK_THROWS_NAME(json::parser("{\"foo\":}").parse(), std::invalid_argument, "parse error - unexpected '}'"); CHECK_THROWS_NAME(json::parser("{\"foo\":1,}").parse(), std::invalid_argument, - "parse error - unexpected '}' (}); expected string literal"); + "parse error - unexpected '}'; expected string literal"); CHECK_THROWS_NAME(json::parser("}").parse(), std::invalid_argument, "parse error - unexpected '}'"); // missing/unexpected end of string From 7371c71d2a579419cdc138ac4a323ebdf9d1421c Mon Sep 17 00:00:00 2001 From: Niels Date: Sun, 27 Dec 2015 15:30:30 +0100 Subject: [PATCH 37/61] using CHECK_THROWS_WITH to check exceptions (#160) --- src/json.hpp | 2 +- test/unit.cpp | 972 +++++++++++++++++++++++--------------------------- 2 files changed, 452 insertions(+), 522 deletions(-) diff --git a/src/json.hpp b/src/json.hpp index dbb18576e..7c8be3d4e 100644 --- a/src/json.hpp +++ b/src/json.hpp @@ -6441,7 +6441,7 @@ class basic_json return result; } - /// return name of values of type token_type + /// return name of values of type token_type (only used for errors) static std::string token_type_name(token_type t) { switch (t) diff --git a/test/unit.cpp b/test/unit.cpp index 6386fd695..ebf3fb2a3 100644 --- a/test/unit.cpp +++ b/test/unit.cpp @@ -10,9 +10,6 @@ #define CATCH_CONFIG_MAIN #include "catch.hpp" -// macro to check exception names (see https://github.com/philsquared/Catch/issues/563) -#define CHECK_THROWS_NAME(block, exception, name) { try { block; } catch ( exception &e ) { CHECK(e.what() == std::string(name)); } } - #include #include #include @@ -898,8 +895,8 @@ TEST_CASE("constructors") SECTION("object with error") { CHECK_THROWS_AS(json::object({ {"one", 1}, {"two", 2.2}, {"three", false}, 13 }), std::logic_error); - CHECK_THROWS_NAME(json::object({ {"one", 1}, {"two", 2.2}, {"three", false}, 13 }), - std::logic_error, "cannot create object from initializer list"); + CHECK_THROWS_WITH(json::object({ {"one", 1}, {"two", 2.2}, {"three", false}, 13 }), + "cannot create object from initializer list"); } SECTION("empty array") @@ -973,20 +970,16 @@ TEST_CASE("constructors") json jobject2 = {{"a", "a"}, {"b", 1}, {"c", 17}}; CHECK_THROWS_AS(json(jobject.begin(), jobject2.end()), std::domain_error); CHECK_THROWS_AS(json(jobject2.begin(), jobject.end()), std::domain_error); - CHECK_THROWS_NAME(json(jobject.begin(), jobject2.end()), std::domain_error, - "iterators are not compatible"); - CHECK_THROWS_NAME(json(jobject2.begin(), jobject.end()), std::domain_error, - "iterators are not compatible"); + CHECK_THROWS_WITH(json(jobject.begin(), jobject2.end()), "iterators are not compatible"); + CHECK_THROWS_WITH(json(jobject2.begin(), jobject.end()), "iterators are not compatible"); } { json jobject = {{"a", "a"}, {"b", 1}, {"c", 17}, {"d", false}, {"e", true}}; json jobject2 = {{"a", "a"}, {"b", 1}, {"c", 17}}; CHECK_THROWS_AS(json(jobject.cbegin(), jobject2.cend()), std::domain_error); CHECK_THROWS_AS(json(jobject2.cbegin(), jobject.cend()), std::domain_error); - CHECK_THROWS_NAME(json(jobject.cbegin(), jobject2.cend()), std::domain_error, - "iterators are not compatible"); - CHECK_THROWS_NAME(json(jobject2.cbegin(), jobject.cend()), std::domain_error, - "iterators are not compatible"); + CHECK_THROWS_WITH(json(jobject.cbegin(), jobject2.cend()), "iterators are not compatible"); + CHECK_THROWS_WITH(json(jobject2.cbegin(), jobject.cend()), "iterators are not compatible"); } } } @@ -1042,20 +1035,16 @@ TEST_CASE("constructors") json jarray2 = {2, 3, 4, 5}; CHECK_THROWS_AS(json(jarray.begin(), jarray2.end()), std::domain_error); CHECK_THROWS_AS(json(jarray2.begin(), jarray.end()), std::domain_error); - CHECK_THROWS_NAME(json(jarray.begin(), jarray2.end()), std::domain_error, - "iterators are not compatible"); - CHECK_THROWS_NAME(json(jarray2.begin(), jarray.end()), std::domain_error, - "iterators are not compatible"); + CHECK_THROWS_WITH(json(jarray.begin(), jarray2.end()), "iterators are not compatible"); + CHECK_THROWS_WITH(json(jarray2.begin(), jarray.end()), "iterators are not compatible"); } { json jarray = {1, 2, 3, 4}; json jarray2 = {2, 3, 4, 5}; CHECK_THROWS_AS(json(jarray.cbegin(), jarray2.cend()), std::domain_error); CHECK_THROWS_AS(json(jarray2.cbegin(), jarray.cend()), std::domain_error); - CHECK_THROWS_NAME(json(jarray.cbegin(), jarray2.cend()), std::domain_error, - "iterators are not compatible"); - CHECK_THROWS_NAME(json(jarray2.cbegin(), jarray.cend()), std::domain_error, - "iterators are not compatible"); + CHECK_THROWS_WITH(json(jarray.cbegin(), jarray2.cend()), "iterators are not compatible"); + CHECK_THROWS_WITH(json(jarray2.cbegin(), jarray.cend()), "iterators are not compatible"); } } } @@ -1069,14 +1058,12 @@ TEST_CASE("constructors") { json j; CHECK_THROWS_AS(json(j.begin(), j.end()), std::domain_error); - CHECK_THROWS_NAME(json(j.begin(), j.end()), std::domain_error, - "cannot use construct with iterators from null"); + CHECK_THROWS_WITH(json(j.begin(), j.end()), "cannot use construct with iterators from null"); } { json j; CHECK_THROWS_AS(json(j.cbegin(), j.cend()), std::domain_error); - CHECK_THROWS_NAME(json(j.cbegin(), j.cend()), std::domain_error, - "cannot use construct with iterators from null"); + CHECK_THROWS_WITH(json(j.cbegin(), j.cend()), "cannot use construct with iterators from null"); } } @@ -1145,15 +1132,15 @@ TEST_CASE("constructors") json j = "foo"; CHECK_THROWS_AS(json(j.end(), j.end()), std::out_of_range); CHECK_THROWS_AS(json(j.begin(), j.begin()), std::out_of_range); - CHECK_THROWS_NAME(json(j.end(), j.end()), std::out_of_range, "iterators out of range"); - CHECK_THROWS_NAME(json(j.begin(), j.begin()), std::out_of_range, "iterators out of range"); + CHECK_THROWS_WITH(json(j.end(), j.end()), "iterators out of range"); + CHECK_THROWS_WITH(json(j.begin(), j.begin()), "iterators out of range"); } { json j = "bar"; CHECK_THROWS_AS(json(j.cend(), j.cend()), std::out_of_range); CHECK_THROWS_AS(json(j.cbegin(), j.cbegin()), std::out_of_range); - CHECK_THROWS_NAME(json(j.cend(), j.cend()), std::out_of_range, "iterators out of range"); - CHECK_THROWS_NAME(json(j.cbegin(), j.cbegin()), std::out_of_range, "iterators out of range"); + CHECK_THROWS_WITH(json(j.cend(), j.cend()), "iterators out of range"); + CHECK_THROWS_WITH(json(j.cbegin(), j.cbegin()), "iterators out of range"); } } @@ -1163,15 +1150,15 @@ TEST_CASE("constructors") json j = false; CHECK_THROWS_AS(json(j.end(), j.end()), std::out_of_range); CHECK_THROWS_AS(json(j.begin(), j.begin()), std::out_of_range); - CHECK_THROWS_NAME(json(j.end(), j.end()), std::out_of_range, "iterators out of range"); - CHECK_THROWS_NAME(json(j.begin(), j.begin()), std::out_of_range, "iterators out of range"); + CHECK_THROWS_WITH(json(j.end(), j.end()), "iterators out of range"); + CHECK_THROWS_WITH(json(j.begin(), j.begin()), "iterators out of range"); } { json j = true; CHECK_THROWS_AS(json(j.cend(), j.cend()), std::out_of_range); CHECK_THROWS_AS(json(j.cbegin(), j.cbegin()), std::out_of_range); - CHECK_THROWS_NAME(json(j.cend(), j.cend()), std::out_of_range, "iterators out of range"); - CHECK_THROWS_NAME(json(j.cbegin(), j.cbegin()), std::out_of_range, "iterators out of range"); + CHECK_THROWS_WITH(json(j.cend(), j.cend()), "iterators out of range"); + CHECK_THROWS_WITH(json(j.cbegin(), j.cbegin()), "iterators out of range"); } } @@ -1181,15 +1168,15 @@ TEST_CASE("constructors") json j = 17; CHECK_THROWS_AS(json(j.end(), j.end()), std::out_of_range); CHECK_THROWS_AS(json(j.begin(), j.begin()), std::out_of_range); - CHECK_THROWS_NAME(json(j.end(), j.end()), std::out_of_range, "iterators out of range"); - CHECK_THROWS_NAME(json(j.begin(), j.begin()), std::out_of_range, "iterators out of range"); + CHECK_THROWS_WITH(json(j.end(), j.end()), "iterators out of range"); + CHECK_THROWS_WITH(json(j.begin(), j.begin()), "iterators out of range"); } { json j = 17; CHECK_THROWS_AS(json(j.cend(), j.cend()), std::out_of_range); CHECK_THROWS_AS(json(j.cbegin(), j.cbegin()), std::out_of_range); - CHECK_THROWS_NAME(json(j.cend(), j.cend()), std::out_of_range, "iterators out of range"); - CHECK_THROWS_NAME(json(j.cbegin(), j.cbegin()), std::out_of_range, "iterators out of range"); + CHECK_THROWS_WITH(json(j.cend(), j.cend()), "iterators out of range"); + CHECK_THROWS_WITH(json(j.cbegin(), j.cbegin()), "iterators out of range"); } } @@ -1199,15 +1186,15 @@ TEST_CASE("constructors") json j = 23.42; CHECK_THROWS_AS(json(j.end(), j.end()), std::out_of_range); CHECK_THROWS_AS(json(j.begin(), j.begin()), std::out_of_range); - CHECK_THROWS_NAME(json(j.end(), j.end()), std::out_of_range, "iterators out of range"); - CHECK_THROWS_NAME(json(j.begin(), j.begin()), std::out_of_range, "iterators out of range"); + CHECK_THROWS_WITH(json(j.end(), j.end()), "iterators out of range"); + CHECK_THROWS_WITH(json(j.begin(), j.begin()), "iterators out of range"); } { json j = 23.42; CHECK_THROWS_AS(json(j.cend(), j.cend()), std::out_of_range); CHECK_THROWS_AS(json(j.cbegin(), j.cbegin()), std::out_of_range); - CHECK_THROWS_NAME(json(j.cend(), j.cend()), std::out_of_range, "iterators out of range"); - CHECK_THROWS_NAME(json(j.cbegin(), j.cbegin()), std::out_of_range, "iterators out of range"); + CHECK_THROWS_WITH(json(j.cend(), j.cend()), "iterators out of range"); + CHECK_THROWS_WITH(json(j.cbegin(), j.cbegin()), "iterators out of range"); } } } @@ -1687,17 +1674,17 @@ TEST_CASE("value conversion") CHECK_THROWS_AS(json(json::value_t::number_integer).get(), std::logic_error); CHECK_THROWS_AS(json(json::value_t::number_float).get(), std::logic_error); - CHECK_THROWS_NAME(json(json::value_t::null).get(), std::logic_error, + CHECK_THROWS_WITH(json(json::value_t::null).get(), "type must be object, but is null"); - CHECK_THROWS_NAME(json(json::value_t::array).get(), std::logic_error, + CHECK_THROWS_WITH(json(json::value_t::array).get(), "type must be object, but is array"); - CHECK_THROWS_NAME(json(json::value_t::string).get(), std::logic_error, + CHECK_THROWS_WITH(json(json::value_t::string).get(), "type must be object, but is string"); - CHECK_THROWS_NAME(json(json::value_t::boolean).get(), std::logic_error, + CHECK_THROWS_WITH(json(json::value_t::boolean).get(), "type must be object, but is boolean"); - CHECK_THROWS_NAME(json(json::value_t::number_integer).get(), std::logic_error, + CHECK_THROWS_WITH(json(json::value_t::number_integer).get(), "type must be object, but is number"); - CHECK_THROWS_NAME(json(json::value_t::number_float).get(), std::logic_error, + CHECK_THROWS_WITH(json(json::value_t::number_float).get(), "type must be object, but is number"); } } @@ -1782,17 +1769,17 @@ TEST_CASE("value conversion") CHECK_THROWS_AS(json(json::value_t::number_integer).get(), std::logic_error); CHECK_THROWS_AS(json(json::value_t::number_float).get(), std::logic_error); - CHECK_THROWS_NAME(json(json::value_t::null).get(), std::logic_error, + CHECK_THROWS_WITH(json(json::value_t::null).get(), "type must be array, but is null"); - CHECK_THROWS_NAME(json(json::value_t::object).get(), std::logic_error, + CHECK_THROWS_WITH(json(json::value_t::object).get(), "type must be array, but is object"); - CHECK_THROWS_NAME(json(json::value_t::string).get(), std::logic_error, + CHECK_THROWS_WITH(json(json::value_t::string).get(), "type must be array, but is string"); - CHECK_THROWS_NAME(json(json::value_t::boolean).get(), std::logic_error, + CHECK_THROWS_WITH(json(json::value_t::boolean).get(), "type must be array, but is boolean"); - CHECK_THROWS_NAME(json(json::value_t::number_integer).get(), std::logic_error, + CHECK_THROWS_WITH(json(json::value_t::number_integer).get(), "type must be array, but is number"); - CHECK_THROWS_NAME(json(json::value_t::number_float).get(), std::logic_error, + CHECK_THROWS_WITH(json(json::value_t::number_float).get(), "type must be array, but is number"); } } @@ -1859,17 +1846,17 @@ TEST_CASE("value conversion") CHECK_THROWS_AS(json(json::value_t::number_integer).get(), std::logic_error); CHECK_THROWS_AS(json(json::value_t::number_float).get(), std::logic_error); - CHECK_THROWS_NAME(json(json::value_t::null).get(), std::logic_error, + CHECK_THROWS_WITH(json(json::value_t::null).get(), "type must be string, but is null"); - CHECK_THROWS_NAME(json(json::value_t::object).get(), std::logic_error, + CHECK_THROWS_WITH(json(json::value_t::object).get(), "type must be string, but is object"); - CHECK_THROWS_NAME(json(json::value_t::array).get(), std::logic_error, + CHECK_THROWS_WITH(json(json::value_t::array).get(), "type must be string, but is array"); - CHECK_THROWS_NAME(json(json::value_t::boolean).get(), std::logic_error, + CHECK_THROWS_WITH(json(json::value_t::boolean).get(), "type must be string, but is boolean"); - CHECK_THROWS_NAME(json(json::value_t::number_integer).get(), std::logic_error, + CHECK_THROWS_WITH(json(json::value_t::number_integer).get(), "type must be string, but is number"); - CHECK_THROWS_NAME(json(json::value_t::number_float).get(), std::logic_error, + CHECK_THROWS_WITH(json(json::value_t::number_float).get(), "type must be string, but is number"); } } @@ -1918,17 +1905,17 @@ TEST_CASE("value conversion") CHECK_THROWS_AS(json(json::value_t::number_integer).get(), std::logic_error); CHECK_THROWS_AS(json(json::value_t::number_float).get(), std::logic_error); - CHECK_THROWS_NAME(json(json::value_t::null).get(), std::logic_error, + CHECK_THROWS_WITH(json(json::value_t::null).get(), "type must be boolean, but is null"); - CHECK_THROWS_NAME(json(json::value_t::object).get(), std::logic_error, + CHECK_THROWS_WITH(json(json::value_t::object).get(), "type must be boolean, but is object"); - CHECK_THROWS_NAME(json(json::value_t::array).get(), std::logic_error, + CHECK_THROWS_WITH(json(json::value_t::array).get(), "type must be boolean, but is array"); - CHECK_THROWS_NAME(json(json::value_t::string).get(), std::logic_error, + CHECK_THROWS_WITH(json(json::value_t::string).get(), "type must be boolean, but is string"); - CHECK_THROWS_NAME(json(json::value_t::number_integer).get(), std::logic_error, + CHECK_THROWS_WITH(json(json::value_t::number_integer).get(), "type must be boolean, but is number"); - CHECK_THROWS_NAME(json(json::value_t::number_float).get(), std::logic_error, + CHECK_THROWS_WITH(json(json::value_t::number_float).get(), "type must be boolean, but is number"); } } @@ -2162,15 +2149,15 @@ TEST_CASE("value conversion") CHECK_THROWS_AS(json(json::value_t::string).get(), std::logic_error); CHECK_THROWS_AS(json(json::value_t::boolean).get(), std::logic_error); - CHECK_THROWS_NAME(json(json::value_t::null).get(), std::logic_error, + CHECK_THROWS_WITH(json(json::value_t::null).get(), "type must be number, but is null"); - CHECK_THROWS_NAME(json(json::value_t::object).get(), std::logic_error, + CHECK_THROWS_WITH(json(json::value_t::object).get(), "type must be number, but is object"); - CHECK_THROWS_NAME(json(json::value_t::array).get(), std::logic_error, + CHECK_THROWS_WITH(json(json::value_t::array).get(), "type must be number, but is array"); - CHECK_THROWS_NAME(json(json::value_t::string).get(), std::logic_error, + CHECK_THROWS_WITH(json(json::value_t::string).get(), "type must be number, but is string"); - CHECK_THROWS_NAME(json(json::value_t::boolean).get(), std::logic_error, + CHECK_THROWS_WITH(json(json::value_t::boolean).get(), "type must be number, but is boolean"); CHECK_NOTHROW(json(json::value_t::number_float).get()); @@ -2412,15 +2399,15 @@ TEST_CASE("value conversion") CHECK_THROWS_AS(json(json::value_t::string).get(), std::logic_error); CHECK_THROWS_AS(json(json::value_t::boolean).get(), std::logic_error); - CHECK_THROWS_NAME(json(json::value_t::null).get(), std::logic_error, + CHECK_THROWS_WITH(json(json::value_t::null).get(), "type must be number, but is null"); - CHECK_THROWS_NAME(json(json::value_t::object).get(), std::logic_error, + CHECK_THROWS_WITH(json(json::value_t::object).get(), "type must be number, but is object"); - CHECK_THROWS_NAME(json(json::value_t::array).get(), std::logic_error, + CHECK_THROWS_WITH(json(json::value_t::array).get(), "type must be number, but is array"); - CHECK_THROWS_NAME(json(json::value_t::string).get(), std::logic_error, + CHECK_THROWS_WITH(json(json::value_t::string).get(), "type must be number, but is string"); - CHECK_THROWS_NAME(json(json::value_t::boolean).get(), std::logic_error, + CHECK_THROWS_WITH(json(json::value_t::boolean).get(), "type must be number, but is boolean"); CHECK_NOTHROW(json(json::value_t::number_integer).get()); @@ -2498,8 +2485,7 @@ TEST_CASE("value conversion") SECTION("exception in case of a non-object type") { CHECK_THROWS_AS((json().get>()), std::logic_error); - CHECK_THROWS_NAME((json().get>()), std::logic_error, - "type must be object, but is null"); + CHECK_THROWS_WITH((json().get>()), "type must be object, but is null"); } } @@ -2565,14 +2551,10 @@ TEST_CASE("value conversion") CHECK_THROWS_AS((json().get>()), std::logic_error); CHECK_THROWS_AS((json().get>()), std::logic_error); - CHECK_THROWS_NAME((json().get>()), std::logic_error, - "type must be array, but is null"); - CHECK_THROWS_NAME((json().get>()), std::logic_error, - "type must be array, but is null"); - CHECK_THROWS_NAME((json().get>()), std::logic_error, - "type must be array, but is null"); - CHECK_THROWS_NAME((json().get>()), std::logic_error, - "type must be array, but is null"); + CHECK_THROWS_WITH((json().get>()), "type must be array, but is null"); + CHECK_THROWS_WITH((json().get>()), "type must be array, but is null"); + CHECK_THROWS_WITH((json().get>()), "type must be array, but is null"); + CHECK_THROWS_WITH((json().get>()), "type must be array, but is null"); } } } @@ -2791,8 +2773,8 @@ TEST_CASE("element access") CHECK_THROWS_AS(j.at(7), std::out_of_range); CHECK_THROWS_AS(j_const.at(7), std::out_of_range); - CHECK_THROWS_NAME(j.at(7), std::out_of_range, "array index 7 is out of range"); - CHECK_THROWS_NAME(j_const.at(7), std::out_of_range, "array index 7 is out of range"); + CHECK_THROWS_WITH(j.at(7), "array index 7 is out of range"); + CHECK_THROWS_WITH(j_const.at(7), "array index 7 is out of range"); } SECTION("access on non-array type") @@ -2804,8 +2786,8 @@ TEST_CASE("element access") CHECK_THROWS_AS(j_nonarray.at(0), std::domain_error); CHECK_THROWS_AS(j_nonarray_const.at(0), std::domain_error); - CHECK_THROWS_NAME(j_nonarray.at(0), std::domain_error, "cannot use at() with null"); - CHECK_THROWS_NAME(j_nonarray_const.at(0), std::domain_error, "cannot use at() with null"); + CHECK_THROWS_WITH(j_nonarray.at(0), "cannot use at() with null"); + CHECK_THROWS_WITH(j_nonarray_const.at(0), "cannot use at() with null"); } SECTION("boolean") @@ -2815,8 +2797,8 @@ TEST_CASE("element access") CHECK_THROWS_AS(j_nonarray.at(0), std::domain_error); CHECK_THROWS_AS(j_nonarray_const.at(0), std::domain_error); - CHECK_THROWS_NAME(j_nonarray.at(0), std::domain_error, "cannot use at() with boolean"); - CHECK_THROWS_NAME(j_nonarray_const.at(0), std::domain_error, "cannot use at() with boolean"); + CHECK_THROWS_WITH(j_nonarray.at(0), "cannot use at() with boolean"); + CHECK_THROWS_WITH(j_nonarray_const.at(0), "cannot use at() with boolean"); } SECTION("string") @@ -2826,8 +2808,8 @@ TEST_CASE("element access") CHECK_THROWS_AS(j_nonarray.at(0), std::domain_error); CHECK_THROWS_AS(j_nonarray_const.at(0), std::domain_error); - CHECK_THROWS_NAME(j_nonarray.at(0), std::domain_error, "cannot use at() with string"); - CHECK_THROWS_NAME(j_nonarray_const.at(0), std::domain_error, "cannot use at() with string"); + CHECK_THROWS_WITH(j_nonarray.at(0), "cannot use at() with string"); + CHECK_THROWS_WITH(j_nonarray_const.at(0), "cannot use at() with string"); } SECTION("object") @@ -2837,8 +2819,8 @@ TEST_CASE("element access") CHECK_THROWS_AS(j_nonarray.at(0), std::domain_error); CHECK_THROWS_AS(j_nonarray_const.at(0), std::domain_error); - CHECK_THROWS_NAME(j_nonarray.at(0), std::domain_error, "cannot use at() with object"); - CHECK_THROWS_NAME(j_nonarray_const.at(0), std::domain_error, "cannot use at() with object"); + CHECK_THROWS_WITH(j_nonarray.at(0), "cannot use at() with object"); + CHECK_THROWS_WITH(j_nonarray_const.at(0), "cannot use at() with object"); } SECTION("number (integer)") @@ -2848,8 +2830,8 @@ TEST_CASE("element access") CHECK_THROWS_AS(j_nonarray.at(0), std::domain_error); CHECK_THROWS_AS(j_nonarray_const.at(0), std::domain_error); - CHECK_THROWS_NAME(j_nonarray.at(0), std::domain_error, "cannot use at() with number"); - CHECK_THROWS_NAME(j_nonarray_const.at(0), std::domain_error, "cannot use at() with number"); + CHECK_THROWS_WITH(j_nonarray.at(0), "cannot use at() with number"); + CHECK_THROWS_WITH(j_nonarray_const.at(0), "cannot use at() with number"); } SECTION("number (floating-point)") @@ -2859,8 +2841,8 @@ TEST_CASE("element access") CHECK_THROWS_AS(j_nonarray.at(0), std::domain_error); CHECK_THROWS_AS(j_nonarray_const.at(0), std::domain_error); - CHECK_THROWS_NAME(j_nonarray.at(0), std::domain_error, "cannot use at() with number"); - CHECK_THROWS_NAME(j_nonarray_const.at(0), std::domain_error, "cannot use at() with number"); + CHECK_THROWS_WITH(j_nonarray.at(0), "cannot use at() with number"); + CHECK_THROWS_WITH(j_nonarray_const.at(0), "cannot use at() with number"); } } } @@ -2904,7 +2886,7 @@ TEST_CASE("element access") const json j_nonarray_const(j_nonarray); CHECK_NOTHROW(j_nonarray[0]); CHECK_THROWS_AS(j_nonarray_const[0], std::domain_error); - CHECK_THROWS_NAME(j_nonarray_const[0], std::domain_error, "cannot use operator[] with null"); + CHECK_THROWS_WITH(j_nonarray_const[0], "cannot use operator[] with null"); } SECTION("implicit transformation to properly filled array") @@ -2921,8 +2903,8 @@ TEST_CASE("element access") const json j_nonarray_const(j_nonarray); CHECK_THROWS_AS(j_nonarray[0], std::domain_error); CHECK_THROWS_AS(j_nonarray_const[0], std::domain_error); - CHECK_THROWS_NAME(j_nonarray[0], std::domain_error, "cannot use operator[] with boolean"); - CHECK_THROWS_NAME(j_nonarray_const[0], std::domain_error, "cannot use operator[] with boolean"); + CHECK_THROWS_WITH(j_nonarray[0], "cannot use operator[] with boolean"); + CHECK_THROWS_WITH(j_nonarray_const[0], "cannot use operator[] with boolean"); } SECTION("string") @@ -2931,8 +2913,8 @@ TEST_CASE("element access") const json j_nonarray_const(j_nonarray); CHECK_THROWS_AS(j_nonarray[0], std::domain_error); CHECK_THROWS_AS(j_nonarray_const[0], std::domain_error); - CHECK_THROWS_NAME(j_nonarray[0], std::domain_error, "cannot use operator[] with string"); - CHECK_THROWS_NAME(j_nonarray_const[0], std::domain_error, "cannot use operator[] with string"); + CHECK_THROWS_WITH(j_nonarray[0], "cannot use operator[] with string"); + CHECK_THROWS_WITH(j_nonarray_const[0], "cannot use operator[] with string"); } SECTION("object") @@ -2941,8 +2923,8 @@ TEST_CASE("element access") const json j_nonarray_const(j_nonarray); CHECK_THROWS_AS(j_nonarray[0], std::domain_error); CHECK_THROWS_AS(j_nonarray_const[0], std::domain_error); - CHECK_THROWS_NAME(j_nonarray[0], std::domain_error, "cannot use operator[] with object"); - CHECK_THROWS_NAME(j_nonarray_const[0], std::domain_error, "cannot use operator[] with object"); + CHECK_THROWS_WITH(j_nonarray[0], "cannot use operator[] with object"); + CHECK_THROWS_WITH(j_nonarray_const[0], "cannot use operator[] with object"); } SECTION("number (integer)") @@ -2951,8 +2933,8 @@ TEST_CASE("element access") const json j_nonarray_const(j_nonarray); CHECK_THROWS_AS(j_nonarray[0], std::domain_error); CHECK_THROWS_AS(j_nonarray_const[0], std::domain_error); - CHECK_THROWS_NAME(j_nonarray[0], std::domain_error, "cannot use operator[] with number"); - CHECK_THROWS_NAME(j_nonarray_const[0], std::domain_error, "cannot use operator[] with number"); + CHECK_THROWS_WITH(j_nonarray[0], "cannot use operator[] with number"); + CHECK_THROWS_WITH(j_nonarray_const[0], "cannot use operator[] with number"); } SECTION("number (floating-point)") @@ -2961,8 +2943,8 @@ TEST_CASE("element access") const json j_nonarray_const(j_nonarray); CHECK_THROWS_AS(j_nonarray[0], std::domain_error); CHECK_THROWS_AS(j_nonarray_const[0], std::domain_error); - CHECK_THROWS_NAME(j_nonarray[0], std::domain_error, "cannot use operator[] with number"); - CHECK_THROWS_NAME(j_nonarray_const[0], std::domain_error, "cannot use operator[] with number"); + CHECK_THROWS_WITH(j_nonarray[0], "cannot use operator[] with number"); + CHECK_THROWS_WITH(j_nonarray_const[0], "cannot use operator[] with number"); } } } @@ -3009,7 +2991,7 @@ TEST_CASE("element access") { json jarray = {1, true, nullptr, "string", 42.23, json::object(), {1, 2, 3}}; CHECK_THROWS_AS(jarray.erase(7), std::out_of_range); - CHECK_THROWS_NAME(jarray.erase(7), std::out_of_range, "index out of range"); + CHECK_THROWS_WITH(jarray.erase(7), "index out of range"); } } @@ -3107,13 +3089,12 @@ TEST_CASE("element access") CHECK_THROWS_AS(jarray.erase(jarray2.begin(), jarray.end()), std::domain_error); CHECK_THROWS_AS(jarray.erase(jarray2.begin(), jarray2.end()), std::domain_error); - CHECK_THROWS_NAME(jarray.erase(jarray2.begin()), std::domain_error, - "iterator does not fit current value"); - CHECK_THROWS_NAME(jarray.erase(jarray.begin(), jarray2.end()), std::domain_error, + CHECK_THROWS_WITH(jarray.erase(jarray2.begin()), "iterator does not fit current value"); + CHECK_THROWS_WITH(jarray.erase(jarray.begin(), jarray2.end()), "iterators do not fit current value"); - CHECK_THROWS_NAME(jarray.erase(jarray2.begin(), jarray.end()), std::domain_error, + CHECK_THROWS_WITH(jarray.erase(jarray2.begin(), jarray.end()), "iterators do not fit current value"); - CHECK_THROWS_NAME(jarray.erase(jarray2.begin(), jarray2.end()), std::domain_error, + CHECK_THROWS_WITH(jarray.erase(jarray2.begin(), jarray2.end()), "iterators do not fit current value"); } { @@ -3124,13 +3105,12 @@ TEST_CASE("element access") CHECK_THROWS_AS(jarray.erase(jarray2.cbegin(), jarray.cend()), std::domain_error); CHECK_THROWS_AS(jarray.erase(jarray2.cbegin(), jarray2.cend()), std::domain_error); - CHECK_THROWS_NAME(jarray.erase(jarray2.cbegin()), std::domain_error, - "iterator does not fit current value"); - CHECK_THROWS_NAME(jarray.erase(jarray.cbegin(), jarray2.cend()), std::domain_error, + CHECK_THROWS_WITH(jarray.erase(jarray2.cbegin()), "iterator does not fit current value"); + CHECK_THROWS_WITH(jarray.erase(jarray.cbegin(), jarray2.cend()), "iterators do not fit current value"); - CHECK_THROWS_NAME(jarray.erase(jarray2.cbegin(), jarray.cend()), std::domain_error, + CHECK_THROWS_WITH(jarray.erase(jarray2.cbegin(), jarray.cend()), "iterators do not fit current value"); - CHECK_THROWS_NAME(jarray.erase(jarray2.cbegin(), jarray2.cend()), std::domain_error, + CHECK_THROWS_WITH(jarray.erase(jarray2.cbegin(), jarray2.cend()), "iterators do not fit current value"); } } @@ -3142,42 +3122,42 @@ TEST_CASE("element access") { json j_nonobject(json::value_t::null); CHECK_THROWS_AS(j_nonobject.erase(0), std::domain_error); - CHECK_THROWS_NAME(j_nonobject.erase(0), std::domain_error, "cannot use erase() with null"); + CHECK_THROWS_WITH(j_nonobject.erase(0), "cannot use erase() with null"); } SECTION("boolean") { json j_nonobject(json::value_t::boolean); CHECK_THROWS_AS(j_nonobject.erase(0), std::domain_error); - CHECK_THROWS_NAME(j_nonobject.erase(0), std::domain_error, "cannot use erase() with boolean"); + CHECK_THROWS_WITH(j_nonobject.erase(0), "cannot use erase() with boolean"); } SECTION("string") { json j_nonobject(json::value_t::string); CHECK_THROWS_AS(j_nonobject.erase(0), std::domain_error); - CHECK_THROWS_NAME(j_nonobject.erase(0), std::domain_error, "cannot use erase() with string"); + CHECK_THROWS_WITH(j_nonobject.erase(0), "cannot use erase() with string"); } SECTION("object") { json j_nonobject(json::value_t::object); CHECK_THROWS_AS(j_nonobject.erase(0), std::domain_error); - CHECK_THROWS_NAME(j_nonobject.erase(0), std::domain_error, "cannot use erase() with object"); + CHECK_THROWS_WITH(j_nonobject.erase(0), "cannot use erase() with object"); } SECTION("number (integer)") { json j_nonobject(json::value_t::number_integer); CHECK_THROWS_AS(j_nonobject.erase(0), std::domain_error); - CHECK_THROWS_NAME(j_nonobject.erase(0), std::domain_error, "cannot use erase() with number"); + CHECK_THROWS_WITH(j_nonobject.erase(0), "cannot use erase() with number"); } SECTION("number (floating-point)") { json j_nonobject(json::value_t::number_float); CHECK_THROWS_AS(j_nonobject.erase(0), std::domain_error); - CHECK_THROWS_NAME(j_nonobject.erase(0), std::domain_error, "cannot use erase() with number"); + CHECK_THROWS_WITH(j_nonobject.erase(0), "cannot use erase() with number"); } } } @@ -3213,8 +3193,8 @@ TEST_CASE("element access") { CHECK_THROWS_AS(j.at("foo"), std::out_of_range); CHECK_THROWS_AS(j_const.at("foo"), std::out_of_range); - CHECK_THROWS_NAME(j.at("foo"), std::out_of_range, "key 'foo' not found"); - CHECK_THROWS_NAME(j_const.at("foo"), std::out_of_range, "key 'foo' not found"); + CHECK_THROWS_WITH(j.at("foo"), "key 'foo' not found"); + CHECK_THROWS_WITH(j_const.at("foo"), "key 'foo' not found"); } SECTION("access on non-object type") @@ -3225,8 +3205,8 @@ TEST_CASE("element access") const json j_nonobject_const(j_nonobject); CHECK_THROWS_AS(j_nonobject.at("foo"), std::domain_error); CHECK_THROWS_AS(j_nonobject_const.at("foo"), std::domain_error); - CHECK_THROWS_NAME(j_nonobject.at("foo"), std::domain_error, "cannot use at() with null"); - CHECK_THROWS_NAME(j_nonobject_const.at("foo"), std::domain_error, "cannot use at() with null"); + CHECK_THROWS_WITH(j_nonobject.at("foo"), "cannot use at() with null"); + CHECK_THROWS_WITH(j_nonobject_const.at("foo"), "cannot use at() with null"); } SECTION("boolean") @@ -3235,8 +3215,8 @@ TEST_CASE("element access") const json j_nonobject_const(j_nonobject); CHECK_THROWS_AS(j_nonobject.at("foo"), std::domain_error); CHECK_THROWS_AS(j_nonobject_const.at("foo"), std::domain_error); - CHECK_THROWS_NAME(j_nonobject.at("foo"), std::domain_error, "cannot use at() with boolean"); - CHECK_THROWS_NAME(j_nonobject_const.at("foo"), std::domain_error, "cannot use at() with boolean"); + CHECK_THROWS_WITH(j_nonobject.at("foo"), "cannot use at() with boolean"); + CHECK_THROWS_WITH(j_nonobject_const.at("foo"), "cannot use at() with boolean"); } SECTION("string") @@ -3245,8 +3225,8 @@ TEST_CASE("element access") const json j_nonobject_const(j_nonobject); CHECK_THROWS_AS(j_nonobject.at("foo"), std::domain_error); CHECK_THROWS_AS(j_nonobject_const.at("foo"), std::domain_error); - CHECK_THROWS_NAME(j_nonobject.at("foo"), std::domain_error, "cannot use at() with string"); - CHECK_THROWS_NAME(j_nonobject_const.at("foo"), std::domain_error, "cannot use at() with string"); + CHECK_THROWS_WITH(j_nonobject.at("foo"), "cannot use at() with string"); + CHECK_THROWS_WITH(j_nonobject_const.at("foo"), "cannot use at() with string"); } SECTION("array") @@ -3255,8 +3235,8 @@ TEST_CASE("element access") const json j_nonobject_const(j_nonobject); CHECK_THROWS_AS(j_nonobject.at("foo"), std::domain_error); CHECK_THROWS_AS(j_nonobject_const.at("foo"), std::domain_error); - CHECK_THROWS_NAME(j_nonobject.at("foo"), std::domain_error, "cannot use at() with array"); - CHECK_THROWS_NAME(j_nonobject_const.at("foo"), std::domain_error, "cannot use at() with array"); + CHECK_THROWS_WITH(j_nonobject.at("foo"), "cannot use at() with array"); + CHECK_THROWS_WITH(j_nonobject_const.at("foo"), "cannot use at() with array"); } SECTION("number (integer)") @@ -3265,8 +3245,8 @@ TEST_CASE("element access") const json j_nonobject_const(j_nonobject); CHECK_THROWS_AS(j_nonobject.at("foo"), std::domain_error); CHECK_THROWS_AS(j_nonobject_const.at("foo"), std::domain_error); - CHECK_THROWS_NAME(j_nonobject.at("foo"), std::domain_error, "cannot use at() with number"); - CHECK_THROWS_NAME(j_nonobject_const.at("foo"), std::domain_error, "cannot use at() with number"); + CHECK_THROWS_WITH(j_nonobject.at("foo"), "cannot use at() with number"); + CHECK_THROWS_WITH(j_nonobject_const.at("foo"), "cannot use at() with number"); } SECTION("number (floating-point)") @@ -3275,8 +3255,8 @@ TEST_CASE("element access") const json j_nonobject_const(j_nonobject); CHECK_THROWS_AS(j_nonobject.at("foo"), std::domain_error); CHECK_THROWS_AS(j_nonobject_const.at("foo"), std::domain_error); - CHECK_THROWS_NAME(j_nonobject.at("foo"), std::domain_error, "cannot use at() with number"); - CHECK_THROWS_NAME(j_nonobject_const.at("foo"), std::domain_error, "cannot use at() with number"); + CHECK_THROWS_WITH(j_nonobject.at("foo"), "cannot use at() with number"); + CHECK_THROWS_WITH(j_nonobject_const.at("foo"), "cannot use at() with number"); } } } @@ -3332,9 +3312,8 @@ TEST_CASE("element access") const json j_nonobject_const(j_nonobject); CHECK_THROWS_AS(j_nonobject.value("foo", 1), std::domain_error); CHECK_THROWS_AS(j_nonobject_const.value("foo", 1), std::domain_error); - CHECK_THROWS_NAME(j_nonobject.value("foo", 1), std::domain_error, "cannot use value() with null"); - CHECK_THROWS_NAME(j_nonobject_const.value("foo", 1), std::domain_error, - "cannot use value() with null"); + CHECK_THROWS_WITH(j_nonobject.value("foo", 1), "cannot use value() with null"); + CHECK_THROWS_WITH(j_nonobject_const.value("foo", 1), "cannot use value() with null"); } SECTION("boolean") @@ -3343,10 +3322,8 @@ TEST_CASE("element access") const json j_nonobject_const(j_nonobject); CHECK_THROWS_AS(j_nonobject.value("foo", 1), std::domain_error); CHECK_THROWS_AS(j_nonobject_const.value("foo", 1), std::domain_error); - CHECK_THROWS_NAME(j_nonobject.value("foo", 1), std::domain_error, - "cannot use value() with boolean"); - CHECK_THROWS_NAME(j_nonobject_const.value("foo", 1), std::domain_error, - "cannot use value() with boolean"); + CHECK_THROWS_WITH(j_nonobject.value("foo", 1), "cannot use value() with boolean"); + CHECK_THROWS_WITH(j_nonobject_const.value("foo", 1), "cannot use value() with boolean"); } SECTION("string") @@ -3355,9 +3332,8 @@ TEST_CASE("element access") const json j_nonobject_const(j_nonobject); CHECK_THROWS_AS(j_nonobject.value("foo", 1), std::domain_error); CHECK_THROWS_AS(j_nonobject_const.value("foo", 1), std::domain_error); - CHECK_THROWS_NAME(j_nonobject.value("foo", 1), std::domain_error, "cannot use value() with string"); - CHECK_THROWS_NAME(j_nonobject_const.value("foo", 1), std::domain_error, - "cannot use value() with string"); + CHECK_THROWS_WITH(j_nonobject.value("foo", 1), "cannot use value() with string"); + CHECK_THROWS_WITH(j_nonobject_const.value("foo", 1), "cannot use value() with string"); } SECTION("array") @@ -3366,9 +3342,8 @@ TEST_CASE("element access") const json j_nonobject_const(j_nonobject); CHECK_THROWS_AS(j_nonobject.value("foo", 1), std::domain_error); CHECK_THROWS_AS(j_nonobject_const.value("foo", 1), std::domain_error); - CHECK_THROWS_NAME(j_nonobject.value("foo", 1), std::domain_error, "cannot use value() with array"); - CHECK_THROWS_NAME(j_nonobject_const.value("foo", 1), std::domain_error, - "cannot use value() with array"); + CHECK_THROWS_WITH(j_nonobject.value("foo", 1), "cannot use value() with array"); + CHECK_THROWS_WITH(j_nonobject_const.value("foo", 1), "cannot use value() with array"); } SECTION("number (integer)") @@ -3377,9 +3352,8 @@ TEST_CASE("element access") const json j_nonobject_const(j_nonobject); CHECK_THROWS_AS(j_nonobject.value("foo", 1), std::domain_error); CHECK_THROWS_AS(j_nonobject_const.value("foo", 1), std::domain_error); - CHECK_THROWS_NAME(j_nonobject.value("foo", 1), std::domain_error, "cannot use value() with number"); - CHECK_THROWS_NAME(j_nonobject_const.value("foo", 1), std::domain_error, - "cannot use value() with number"); + CHECK_THROWS_WITH(j_nonobject.value("foo", 1), "cannot use value() with number"); + CHECK_THROWS_WITH(j_nonobject_const.value("foo", 1), "cannot use value() with number"); } SECTION("number (floating-point)") @@ -3388,9 +3362,8 @@ TEST_CASE("element access") const json j_nonobject_const(j_nonobject); CHECK_THROWS_AS(j_nonobject.value("foo", 1), std::domain_error); CHECK_THROWS_AS(j_nonobject_const.value("foo", 1), std::domain_error); - CHECK_THROWS_NAME(j_nonobject.value("foo", 1), std::domain_error, "cannot use value() with number"); - CHECK_THROWS_NAME(j_nonobject_const.value("foo", 1), std::domain_error, - "cannot use value() with number"); + CHECK_THROWS_WITH(j_nonobject.value("foo", 1), "cannot use value() with number"); + CHECK_THROWS_WITH(j_nonobject_const.value("foo", 1), "cannot use value() with number"); } } } @@ -3463,8 +3436,8 @@ TEST_CASE("element access") CHECK_NOTHROW(j_nonobject2[json::object_t::key_type("foo")]); CHECK_THROWS_AS(j_const_nonobject["foo"], std::domain_error); CHECK_THROWS_AS(j_const_nonobject[json::object_t::key_type("foo")], std::domain_error); - CHECK_THROWS_NAME(j_const_nonobject["foo"], std::domain_error, "cannot use operator[] with null"); - CHECK_THROWS_NAME(j_const_nonobject[json::object_t::key_type("foo")], std::domain_error, + CHECK_THROWS_WITH(j_const_nonobject["foo"], "cannot use operator[] with null"); + CHECK_THROWS_WITH(j_const_nonobject[json::object_t::key_type("foo")], "cannot use operator[] with null"); } @@ -3476,12 +3449,11 @@ TEST_CASE("element access") CHECK_THROWS_AS(j_nonobject[json::object_t::key_type("foo")], std::domain_error); CHECK_THROWS_AS(j_const_nonobject["foo"], std::domain_error); CHECK_THROWS_AS(j_const_nonobject[json::object_t::key_type("foo")], std::domain_error); - CHECK_THROWS_NAME(j_nonobject["foo"], std::domain_error, "cannot use operator[] with boolean"); - CHECK_THROWS_NAME(j_nonobject[json::object_t::key_type("foo")], std::domain_error, + CHECK_THROWS_WITH(j_nonobject["foo"], "cannot use operator[] with boolean"); + CHECK_THROWS_WITH(j_nonobject[json::object_t::key_type("foo")], "cannot use operator[] with boolean"); - CHECK_THROWS_NAME(j_const_nonobject["foo"], std::domain_error, - "cannot use operator[] with boolean"); - CHECK_THROWS_NAME(j_const_nonobject[json::object_t::key_type("foo")], std::domain_error, + CHECK_THROWS_WITH(j_const_nonobject["foo"], "cannot use operator[] with boolean"); + CHECK_THROWS_WITH(j_const_nonobject[json::object_t::key_type("foo")], "cannot use operator[] with boolean"); } @@ -3493,11 +3465,11 @@ TEST_CASE("element access") CHECK_THROWS_AS(j_nonobject[json::object_t::key_type("foo")], std::domain_error); CHECK_THROWS_AS(j_const_nonobject["foo"], std::domain_error); CHECK_THROWS_AS(j_const_nonobject[json::object_t::key_type("foo")], std::domain_error); - CHECK_THROWS_NAME(j_nonobject["foo"], std::domain_error, "cannot use operator[] with string"); - CHECK_THROWS_NAME(j_nonobject[json::object_t::key_type("foo")], std::domain_error, + CHECK_THROWS_WITH(j_nonobject["foo"], "cannot use operator[] with string"); + CHECK_THROWS_WITH(j_nonobject[json::object_t::key_type("foo")], "cannot use operator[] with string"); - CHECK_THROWS_NAME(j_const_nonobject["foo"], std::domain_error, "cannot use operator[] with string"); - CHECK_THROWS_NAME(j_const_nonobject[json::object_t::key_type("foo")], std::domain_error, + CHECK_THROWS_WITH(j_const_nonobject["foo"], "cannot use operator[] with string"); + CHECK_THROWS_WITH(j_const_nonobject[json::object_t::key_type("foo")], "cannot use operator[] with string"); } @@ -3509,11 +3481,10 @@ TEST_CASE("element access") CHECK_THROWS_AS(j_nonobject[json::object_t::key_type("foo")], std::domain_error); CHECK_THROWS_AS(j_const_nonobject["foo"], std::domain_error); CHECK_THROWS_AS(j_const_nonobject[json::object_t::key_type("foo")], std::domain_error); - CHECK_THROWS_NAME(j_nonobject["foo"], std::domain_error, "cannot use operator[] with array"); - CHECK_THROWS_NAME(j_nonobject[json::object_t::key_type("foo")], std::domain_error, - "cannot use operator[] with array"); - CHECK_THROWS_NAME(j_const_nonobject["foo"], std::domain_error, "cannot use operator[] with array"); - CHECK_THROWS_NAME(j_const_nonobject[json::object_t::key_type("foo")], std::domain_error, + CHECK_THROWS_WITH(j_nonobject["foo"], "cannot use operator[] with array"); + CHECK_THROWS_WITH(j_nonobject[json::object_t::key_type("foo")], "cannot use operator[] with array"); + CHECK_THROWS_WITH(j_const_nonobject["foo"], "cannot use operator[] with array"); + CHECK_THROWS_WITH(j_const_nonobject[json::object_t::key_type("foo")], "cannot use operator[] with array"); } @@ -3525,11 +3496,11 @@ TEST_CASE("element access") CHECK_THROWS_AS(j_nonobject[json::object_t::key_type("foo")], std::domain_error); CHECK_THROWS_AS(j_const_nonobject["foo"], std::domain_error); CHECK_THROWS_AS(j_const_nonobject[json::object_t::key_type("foo")], std::domain_error); - CHECK_THROWS_NAME(j_nonobject["foo"], std::domain_error, "cannot use operator[] with number"); - CHECK_THROWS_NAME(j_nonobject[json::object_t::key_type("foo")], std::domain_error, + CHECK_THROWS_WITH(j_nonobject["foo"], "cannot use operator[] with number"); + CHECK_THROWS_WITH(j_nonobject[json::object_t::key_type("foo")], "cannot use operator[] with number"); - CHECK_THROWS_NAME(j_const_nonobject["foo"], std::domain_error, "cannot use operator[] with number"); - CHECK_THROWS_NAME(j_const_nonobject[json::object_t::key_type("foo")], std::domain_error, + CHECK_THROWS_WITH(j_const_nonobject["foo"], "cannot use operator[] with number"); + CHECK_THROWS_WITH(j_const_nonobject[json::object_t::key_type("foo")], "cannot use operator[] with number"); } @@ -3541,11 +3512,11 @@ TEST_CASE("element access") CHECK_THROWS_AS(j_nonobject[json::object_t::key_type("foo")], std::domain_error); CHECK_THROWS_AS(j_const_nonobject["foo"], std::domain_error); CHECK_THROWS_AS(j_const_nonobject[json::object_t::key_type("foo")], std::domain_error); - CHECK_THROWS_NAME(j_nonobject["foo"], std::domain_error, "cannot use operator[] with number"); - CHECK_THROWS_NAME(j_nonobject[json::object_t::key_type("foo")], std::domain_error, + CHECK_THROWS_WITH(j_nonobject["foo"], "cannot use operator[] with number"); + CHECK_THROWS_WITH(j_nonobject[json::object_t::key_type("foo")], "cannot use operator[] with number"); - CHECK_THROWS_NAME(j_const_nonobject["foo"], std::domain_error, "cannot use operator[] with number"); - CHECK_THROWS_NAME(j_const_nonobject[json::object_t::key_type("foo")], std::domain_error, + CHECK_THROWS_WITH(j_const_nonobject["foo"], "cannot use operator[] with number"); + CHECK_THROWS_WITH(j_const_nonobject[json::object_t::key_type("foo")], "cannot use operator[] with number"); } } @@ -3684,13 +3655,12 @@ TEST_CASE("element access") CHECK_THROWS_AS(jobject.erase(jobject.begin(), jobject2.end()), std::domain_error); CHECK_THROWS_AS(jobject.erase(jobject2.begin(), jobject.end()), std::domain_error); CHECK_THROWS_AS(jobject.erase(jobject2.begin(), jobject2.end()), std::domain_error); - CHECK_THROWS_NAME(jobject.erase(jobject2.begin()), std::domain_error, - "iterator does not fit current value"); - CHECK_THROWS_NAME(jobject.erase(jobject.begin(), jobject2.end()), std::domain_error, + CHECK_THROWS_WITH(jobject.erase(jobject2.begin()), "iterator does not fit current value"); + CHECK_THROWS_WITH(jobject.erase(jobject.begin(), jobject2.end()), "iterators do not fit current value"); - CHECK_THROWS_NAME(jobject.erase(jobject2.begin(), jobject.end()), std::domain_error, + CHECK_THROWS_WITH(jobject.erase(jobject2.begin(), jobject.end()), "iterators do not fit current value"); - CHECK_THROWS_NAME(jobject.erase(jobject2.begin(), jobject2.end()), std::domain_error, + CHECK_THROWS_WITH(jobject.erase(jobject2.begin(), jobject2.end()), "iterators do not fit current value"); } { @@ -3700,13 +3670,12 @@ TEST_CASE("element access") CHECK_THROWS_AS(jobject.erase(jobject.cbegin(), jobject2.cend()), std::domain_error); CHECK_THROWS_AS(jobject.erase(jobject2.cbegin(), jobject.cend()), std::domain_error); CHECK_THROWS_AS(jobject.erase(jobject2.cbegin(), jobject2.cend()), std::domain_error); - CHECK_THROWS_NAME(jobject.erase(jobject2.cbegin()), std::domain_error, - "iterator does not fit current value"); - CHECK_THROWS_NAME(jobject.erase(jobject.cbegin(), jobject2.cend()), std::domain_error, + CHECK_THROWS_WITH(jobject.erase(jobject2.cbegin()), "iterator does not fit current value"); + CHECK_THROWS_WITH(jobject.erase(jobject.cbegin(), jobject2.cend()), "iterators do not fit current value"); - CHECK_THROWS_NAME(jobject.erase(jobject2.cbegin(), jobject.cend()), std::domain_error, + CHECK_THROWS_WITH(jobject.erase(jobject2.cbegin(), jobject.cend()), "iterators do not fit current value"); - CHECK_THROWS_NAME(jobject.erase(jobject2.cbegin(), jobject2.cend()), std::domain_error, + CHECK_THROWS_WITH(jobject.erase(jobject2.cbegin(), jobject2.cend()), "iterators do not fit current value"); } } @@ -3718,42 +3687,42 @@ TEST_CASE("element access") { json j_nonobject(json::value_t::null); CHECK_THROWS_AS(j_nonobject.erase("foo"), std::domain_error); - CHECK_THROWS_NAME(j_nonobject.erase("foo"), std::domain_error, "cannot use erase() with null"); + CHECK_THROWS_WITH(j_nonobject.erase("foo"), "cannot use erase() with null"); } SECTION("boolean") { json j_nonobject(json::value_t::boolean); CHECK_THROWS_AS(j_nonobject.erase("foo"), std::domain_error); - CHECK_THROWS_NAME(j_nonobject.erase("foo"), std::domain_error, "cannot use erase() with boolean"); + CHECK_THROWS_WITH(j_nonobject.erase("foo"), "cannot use erase() with boolean"); } SECTION("string") { json j_nonobject(json::value_t::string); CHECK_THROWS_AS(j_nonobject.erase("foo"), std::domain_error); - CHECK_THROWS_NAME(j_nonobject.erase("foo"), std::domain_error, "cannot use erase() with string"); + CHECK_THROWS_WITH(j_nonobject.erase("foo"), "cannot use erase() with string"); } SECTION("array") { json j_nonobject(json::value_t::array); CHECK_THROWS_AS(j_nonobject.erase("foo"), std::domain_error); - CHECK_THROWS_NAME(j_nonobject.erase("foo"), std::domain_error, "cannot use erase() with array"); + CHECK_THROWS_WITH(j_nonobject.erase("foo"), "cannot use erase() with array"); } SECTION("number (integer)") { json j_nonobject(json::value_t::number_integer); CHECK_THROWS_AS(j_nonobject.erase("foo"), std::domain_error); - CHECK_THROWS_NAME(j_nonobject.erase("foo"), std::domain_error, "cannot use erase() with number"); + CHECK_THROWS_WITH(j_nonobject.erase("foo"), "cannot use erase() with number"); } SECTION("number (floating-point)") { json j_nonobject(json::value_t::number_float); CHECK_THROWS_AS(j_nonobject.erase("foo"), std::domain_error); - CHECK_THROWS_NAME(j_nonobject.erase("foo"), std::domain_error, "cannot use erase() with number"); + CHECK_THROWS_WITH(j_nonobject.erase("foo"), "cannot use erase() with number"); } } } @@ -3929,15 +3898,15 @@ TEST_CASE("element access") json j; CHECK_THROWS_AS(j.front(), std::out_of_range); CHECK_THROWS_AS(j.back(), std::out_of_range); - CHECK_THROWS_NAME(j.front(), std::out_of_range, "cannot get value"); - CHECK_THROWS_NAME(j.back(), std::out_of_range, "cannot get value"); + CHECK_THROWS_WITH(j.front(), "cannot get value"); + CHECK_THROWS_WITH(j.back(), "cannot get value"); } { const json j{}; CHECK_THROWS_AS(j.front(), std::out_of_range); CHECK_THROWS_AS(j.back(), std::out_of_range); - CHECK_THROWS_NAME(j.front(), std::out_of_range, "cannot get value"); - CHECK_THROWS_NAME(j.back(), std::out_of_range, "cannot get value"); + CHECK_THROWS_WITH(j.front(), "cannot get value"); + CHECK_THROWS_WITH(j.back(), "cannot get value"); } } @@ -3947,15 +3916,11 @@ TEST_CASE("element access") json j = "foo"; CHECK(j.front() == j); CHECK(j.back() == j); - CHECK_THROWS_NAME(j.front(), std::out_of_range, "cannot get value"); - CHECK_THROWS_NAME(j.back(), std::out_of_range, "cannot get value"); } { const json j = "bar"; CHECK(j.front() == j); CHECK(j.back() == j); - CHECK_THROWS_NAME(j.front(), std::out_of_range, "cannot get value"); - CHECK_THROWS_NAME(j.back(), std::out_of_range, "cannot get value"); } } @@ -3965,15 +3930,11 @@ TEST_CASE("element access") json j = false; CHECK(j.front() == j); CHECK(j.back() == j); - CHECK_THROWS_NAME(j.front(), std::out_of_range, "cannot get value"); - CHECK_THROWS_NAME(j.back(), std::out_of_range, "cannot get value"); } { const json j = true; CHECK(j.front() == j); CHECK(j.back() == j); - CHECK_THROWS_NAME(j.front(), std::out_of_range, "cannot get value"); - CHECK_THROWS_NAME(j.back(), std::out_of_range, "cannot get value"); } } @@ -3983,15 +3944,11 @@ TEST_CASE("element access") json j = 17; CHECK(j.front() == j); CHECK(j.back() == j); - CHECK_THROWS_NAME(j.front(), std::out_of_range, "cannot get value"); - CHECK_THROWS_NAME(j.back(), std::out_of_range, "cannot get value"); } { const json j = 17; CHECK(j.front() == j); CHECK(j.back() == j); - CHECK_THROWS_NAME(j.front(), std::out_of_range, "cannot get value"); - CHECK_THROWS_NAME(j.back(), std::out_of_range, "cannot get value"); } } @@ -4001,15 +3958,11 @@ TEST_CASE("element access") json j = 23.42; CHECK(j.front() == j); CHECK(j.back() == j); - CHECK_THROWS_NAME(j.front(), std::out_of_range, "cannot get value"); - CHECK_THROWS_NAME(j.back(), std::out_of_range, "cannot get value"); } { const json j = 23.42; CHECK(j.front() == j); CHECK(j.back() == j); - CHECK_THROWS_NAME(j.front(), std::out_of_range, "cannot get value"); - CHECK_THROWS_NAME(j.back(), std::out_of_range, "cannot get value"); } } } @@ -4021,12 +3974,12 @@ TEST_CASE("element access") { json j; CHECK_THROWS_AS(j.erase(j.begin()), std::domain_error); - CHECK_THROWS_NAME(j.erase(j.begin()), std::domain_error, "cannot use erase() with null"); + CHECK_THROWS_WITH(j.erase(j.begin()), "cannot use erase() with null"); } { json j; CHECK_THROWS_AS(j.erase(j.cbegin()), std::domain_error); - CHECK_THROWS_NAME(j.erase(j.begin()), std::domain_error, "cannot use erase() with null"); + CHECK_THROWS_WITH(j.erase(j.begin()), "cannot use erase() with null"); } } @@ -4102,12 +4055,12 @@ TEST_CASE("element access") { json j = "foo"; CHECK_THROWS_AS(j.erase(j.end()), std::out_of_range); - CHECK_THROWS_NAME(j.erase(j.end()), std::out_of_range, "iterator out of range"); + CHECK_THROWS_WITH(j.erase(j.end()), "iterator out of range"); } { json j = "bar"; CHECK_THROWS_AS(j.erase(j.cend()), std::out_of_range); - CHECK_THROWS_NAME(j.erase(j.cend()), std::out_of_range, "iterator out of range"); + CHECK_THROWS_WITH(j.erase(j.cend()), "iterator out of range"); } } @@ -4116,12 +4069,12 @@ TEST_CASE("element access") { json j = false; CHECK_THROWS_AS(j.erase(j.end()), std::out_of_range); - CHECK_THROWS_NAME(j.erase(j.end()), std::out_of_range, "iterator out of range"); + CHECK_THROWS_WITH(j.erase(j.end()), "iterator out of range"); } { json j = true; CHECK_THROWS_AS(j.erase(j.cend()), std::out_of_range); - CHECK_THROWS_NAME(j.erase(j.cend()), std::out_of_range, "iterator out of range"); + CHECK_THROWS_WITH(j.erase(j.cend()), "iterator out of range"); } } @@ -4130,12 +4083,12 @@ TEST_CASE("element access") { json j = 17; CHECK_THROWS_AS(j.erase(j.end()), std::out_of_range); - CHECK_THROWS_NAME(j.erase(j.end()), std::out_of_range, "iterator out of range"); + CHECK_THROWS_WITH(j.erase(j.end()), "iterator out of range"); } { json j = 17; CHECK_THROWS_AS(j.erase(j.cend()), std::out_of_range); - CHECK_THROWS_NAME(j.erase(j.cend()), std::out_of_range, "iterator out of range"); + CHECK_THROWS_WITH(j.erase(j.cend()), "iterator out of range"); } } @@ -4144,12 +4097,12 @@ TEST_CASE("element access") { json j = 23.42; CHECK_THROWS_AS(j.erase(j.end()), std::out_of_range); - CHECK_THROWS_NAME(j.erase(j.end()), std::out_of_range, "iterator out of range"); + CHECK_THROWS_WITH(j.erase(j.end()), "iterator out of range"); } { json j = 23.42; CHECK_THROWS_AS(j.erase(j.cend()), std::out_of_range); - CHECK_THROWS_NAME(j.erase(j.cend()), std::out_of_range, "iterator out of range"); + CHECK_THROWS_WITH(j.erase(j.cend()), "iterator out of range"); } } } @@ -4161,12 +4114,12 @@ TEST_CASE("element access") { json j; CHECK_THROWS_AS(j.erase(j.begin(), j.end()), std::domain_error); - CHECK_THROWS_NAME(j.erase(j.begin(), j.end()), std::domain_error, "cannot use erase() with null"); + CHECK_THROWS_WITH(j.erase(j.begin(), j.end()), "cannot use erase() with null"); } { json j; CHECK_THROWS_AS(j.erase(j.cbegin(), j.cend()), std::domain_error); - CHECK_THROWS_NAME(j.erase(j.cbegin(), j.cend()), std::domain_error, "cannot use erase() with null"); + CHECK_THROWS_WITH(j.erase(j.cbegin(), j.cend()), "cannot use erase() with null"); } } @@ -4243,15 +4196,15 @@ TEST_CASE("element access") json j = "foo"; CHECK_THROWS_AS(j.erase(j.end(), j.end()), std::out_of_range); CHECK_THROWS_AS(j.erase(j.begin(), j.begin()), std::out_of_range); - CHECK_THROWS_NAME(j.erase(j.end(), j.end()), std::out_of_range, "iterators out of range"); - CHECK_THROWS_NAME(j.erase(j.begin(), j.begin()), std::out_of_range, "iterators out of range"); + CHECK_THROWS_WITH(j.erase(j.end(), j.end()), "iterators out of range"); + CHECK_THROWS_WITH(j.erase(j.begin(), j.begin()), "iterators out of range"); } { json j = "bar"; CHECK_THROWS_AS(j.erase(j.cend(), j.cend()), std::out_of_range); CHECK_THROWS_AS(j.erase(j.cbegin(), j.cbegin()), std::out_of_range); - CHECK_THROWS_NAME(j.erase(j.cend(), j.cend()), std::out_of_range, "iterators out of range"); - CHECK_THROWS_NAME(j.erase(j.cbegin(), j.cbegin()), std::out_of_range, "iterators out of range"); + CHECK_THROWS_WITH(j.erase(j.cend(), j.cend()), "iterators out of range"); + CHECK_THROWS_WITH(j.erase(j.cbegin(), j.cbegin()), "iterators out of range"); } } @@ -4261,15 +4214,15 @@ TEST_CASE("element access") json j = false; CHECK_THROWS_AS(j.erase(j.end(), j.end()), std::out_of_range); CHECK_THROWS_AS(j.erase(j.begin(), j.begin()), std::out_of_range); - CHECK_THROWS_NAME(j.erase(j.end(), j.end()), std::out_of_range, "iterators out of range"); - CHECK_THROWS_NAME(j.erase(j.begin(), j.begin()), std::out_of_range, "iterators out of range"); + CHECK_THROWS_WITH(j.erase(j.end(), j.end()), "iterators out of range"); + CHECK_THROWS_WITH(j.erase(j.begin(), j.begin()), "iterators out of range"); } { json j = true; CHECK_THROWS_AS(j.erase(j.cend(), j.cend()), std::out_of_range); CHECK_THROWS_AS(j.erase(j.cbegin(), j.cbegin()), std::out_of_range); - CHECK_THROWS_NAME(j.erase(j.cend(), j.cend()), std::out_of_range, "iterators out of range"); - CHECK_THROWS_NAME(j.erase(j.cbegin(), j.cbegin()), std::out_of_range, "iterators out of range"); + CHECK_THROWS_WITH(j.erase(j.cend(), j.cend()), "iterators out of range"); + CHECK_THROWS_WITH(j.erase(j.cbegin(), j.cbegin()), "iterators out of range"); } } @@ -4279,15 +4232,15 @@ TEST_CASE("element access") json j = 17; CHECK_THROWS_AS(j.erase(j.end(), j.end()), std::out_of_range); CHECK_THROWS_AS(j.erase(j.begin(), j.begin()), std::out_of_range); - CHECK_THROWS_NAME(j.erase(j.end(), j.end()), std::out_of_range, "iterators out of range"); - CHECK_THROWS_NAME(j.erase(j.begin(), j.begin()), std::out_of_range, "iterators out of range"); + CHECK_THROWS_WITH(j.erase(j.end(), j.end()), "iterators out of range"); + CHECK_THROWS_WITH(j.erase(j.begin(), j.begin()), "iterators out of range"); } { json j = 17; CHECK_THROWS_AS(j.erase(j.cend(), j.cend()), std::out_of_range); CHECK_THROWS_AS(j.erase(j.cbegin(), j.cbegin()), std::out_of_range); - CHECK_THROWS_NAME(j.erase(j.cend(), j.cend()), std::out_of_range, "iterators out of range"); - CHECK_THROWS_NAME(j.erase(j.cbegin(), j.cbegin()), std::out_of_range, "iterators out of range"); + CHECK_THROWS_WITH(j.erase(j.cend(), j.cend()), "iterators out of range"); + CHECK_THROWS_WITH(j.erase(j.cbegin(), j.cbegin()), "iterators out of range"); } } @@ -4297,15 +4250,15 @@ TEST_CASE("element access") json j = 23.42; CHECK_THROWS_AS(j.erase(j.end(), j.end()), std::out_of_range); CHECK_THROWS_AS(j.erase(j.begin(), j.begin()), std::out_of_range); - CHECK_THROWS_NAME(j.erase(j.end(), j.end()), std::out_of_range, "iterators out of range"); - CHECK_THROWS_NAME(j.erase(j.begin(), j.begin()), std::out_of_range, "iterators out of range"); + CHECK_THROWS_WITH(j.erase(j.end(), j.end()), "iterators out of range"); + CHECK_THROWS_WITH(j.erase(j.begin(), j.begin()), "iterators out of range"); } { json j = 23.42; CHECK_THROWS_AS(j.erase(j.cend(), j.cend()), std::out_of_range); CHECK_THROWS_AS(j.erase(j.cbegin(), j.cbegin()), std::out_of_range); - CHECK_THROWS_NAME(j.erase(j.cend(), j.cend()), std::out_of_range, "iterators out of range"); - CHECK_THROWS_NAME(j.erase(j.cbegin(), j.cbegin()), std::out_of_range, "iterators out of range"); + CHECK_THROWS_WITH(j.erase(j.cend(), j.cend()), "iterators out of range"); + CHECK_THROWS_WITH(j.erase(j.cbegin(), j.cbegin()), "iterators out of range"); } } } @@ -4510,10 +4463,10 @@ TEST_CASE("iterators") auto it = j.begin(); auto cit = j_const.cbegin(); CHECK_THROWS_AS(it.key(), std::domain_error); - CHECK_THROWS_NAME(it.key(), std::domain_error, "cannot use key() for non-object iterators"); + CHECK_THROWS_WITH(it.key(), "cannot use key() for non-object iterators"); CHECK(it.value() == json(true)); CHECK_THROWS_AS(cit.key(), std::domain_error); - CHECK_THROWS_NAME(cit.key(), std::domain_error, "cannot use key() for non-object iterators"); + CHECK_THROWS_WITH(cit.key(), "cannot use key() for non-object iterators"); CHECK(cit.value() == json(true)); auto rit = j.rend(); @@ -4522,10 +4475,10 @@ TEST_CASE("iterators") CHECK_THROWS_AS(rit.value(), std::out_of_range); CHECK_THROWS_AS(crit.key(), std::domain_error); CHECK_THROWS_AS(crit.value(), std::out_of_range); - CHECK_THROWS_NAME(rit.key(), std::domain_error, "cannot use key() for non-object iterators"); - CHECK_THROWS_NAME(rit.value(), std::out_of_range, "cannot get value"); - CHECK_THROWS_NAME(crit.key(), std::domain_error, "cannot use key() for non-object iterators"); - CHECK_THROWS_NAME(crit.value(), std::out_of_range, "cannot get value"); + CHECK_THROWS_WITH(rit.key(), "cannot use key() for non-object iterators"); + CHECK_THROWS_WITH(rit.value(), "cannot get value"); + CHECK_THROWS_WITH(crit.key(), "cannot use key() for non-object iterators"); + CHECK_THROWS_WITH(crit.value(), "cannot get value"); } } @@ -4714,10 +4667,10 @@ TEST_CASE("iterators") auto it = j.begin(); auto cit = j_const.cbegin(); CHECK_THROWS_AS(it.key(), std::domain_error); - CHECK_THROWS_NAME(it.key(), std::domain_error, "cannot use key() for non-object iterators"); + CHECK_THROWS_WITH(it.key(), "cannot use key() for non-object iterators"); CHECK(it.value() == json("hello world")); CHECK_THROWS_AS(cit.key(), std::domain_error); - CHECK_THROWS_NAME(cit.key(), std::domain_error, "cannot use key() for non-object iterators"); + CHECK_THROWS_WITH(cit.key(), "cannot use key() for non-object iterators"); CHECK(cit.value() == json("hello world")); auto rit = j.rend(); @@ -4726,10 +4679,10 @@ TEST_CASE("iterators") CHECK_THROWS_AS(rit.value(), std::out_of_range); CHECK_THROWS_AS(crit.key(), std::domain_error); CHECK_THROWS_AS(crit.value(), std::out_of_range); - CHECK_THROWS_NAME(rit.key(), std::domain_error, "cannot use key() for non-object iterators"); - CHECK_THROWS_NAME(rit.value(), std::out_of_range, "cannot get value"); - CHECK_THROWS_NAME(crit.key(), std::domain_error, "cannot use key() for non-object iterators"); - CHECK_THROWS_NAME(crit.value(), std::out_of_range, "cannot get value"); + CHECK_THROWS_WITH(rit.key(), "cannot use key() for non-object iterators"); + CHECK_THROWS_WITH(rit.value(), "cannot get value"); + CHECK_THROWS_WITH(crit.key(), "cannot use key() for non-object iterators"); + CHECK_THROWS_WITH(crit.value(), "cannot get value"); } } @@ -4911,10 +4864,10 @@ TEST_CASE("iterators") auto it = j.begin(); auto cit = j_const.cbegin(); CHECK_THROWS_AS(it.key(), std::domain_error); - CHECK_THROWS_NAME(it.key(), std::domain_error, "cannot use key() for non-object iterators"); + CHECK_THROWS_WITH(it.key(), "cannot use key() for non-object iterators"); CHECK(it.value() == json(1)); CHECK_THROWS_AS(cit.key(), std::domain_error); - CHECK_THROWS_NAME(cit.key(), std::domain_error, "cannot use key() for non-object iterators"); + CHECK_THROWS_WITH(cit.key(), "cannot use key() for non-object iterators"); CHECK(cit.value() == json(1)); } } @@ -5288,10 +5241,10 @@ TEST_CASE("iterators") auto it = j.begin(); auto cit = j_const.cbegin(); CHECK_THROWS_AS(it.key(), std::domain_error); - CHECK_THROWS_NAME(it.key(), std::domain_error, "cannot use key() for non-object iterators"); + CHECK_THROWS_WITH(it.key(), "cannot use key() for non-object iterators"); CHECK(it.value() == json(23)); CHECK_THROWS_AS(cit.key(), std::domain_error); - CHECK_THROWS_NAME(cit.key(), std::domain_error, "cannot use key() for non-object iterators"); + CHECK_THROWS_WITH(cit.key(), "cannot use key() for non-object iterators"); CHECK(cit.value() == json(23)); auto rit = j.rend(); @@ -5300,10 +5253,10 @@ TEST_CASE("iterators") CHECK_THROWS_AS(rit.value(), std::out_of_range); CHECK_THROWS_AS(crit.key(), std::domain_error); CHECK_THROWS_AS(crit.value(), std::out_of_range); - CHECK_THROWS_NAME(rit.key(), std::domain_error, "cannot use key() for non-object iterators"); - CHECK_THROWS_NAME(rit.value(), std::out_of_range, "cannot get value"); - CHECK_THROWS_NAME(crit.key(), std::domain_error, "cannot use key() for non-object iterators"); - CHECK_THROWS_NAME(crit.value(), std::out_of_range, "cannot get value"); + CHECK_THROWS_WITH(rit.key(), "cannot use key() for non-object iterators"); + CHECK_THROWS_WITH(rit.value(), "cannot get value"); + CHECK_THROWS_WITH(crit.key(), "cannot use key() for non-object iterators"); + CHECK_THROWS_WITH(crit.value(), "cannot get value"); } } @@ -5492,10 +5445,10 @@ TEST_CASE("iterators") auto it = j.begin(); auto cit = j_const.cbegin(); CHECK_THROWS_AS(it.key(), std::domain_error); - CHECK_THROWS_NAME(it.key(), std::domain_error, "cannot use key() for non-object iterators"); + CHECK_THROWS_WITH(it.key(), "cannot use key() for non-object iterators"); CHECK(it.value() == json(23.42)); CHECK_THROWS_AS(cit.key(), std::domain_error); - CHECK_THROWS_NAME(cit.key(), std::domain_error, "cannot use key() for non-object iterators"); + CHECK_THROWS_WITH(cit.key(), "cannot use key() for non-object iterators"); CHECK(cit.value() == json(23.42)); auto rit = j.rend(); @@ -5504,10 +5457,10 @@ TEST_CASE("iterators") CHECK_THROWS_AS(rit.value(), std::out_of_range); CHECK_THROWS_AS(crit.key(), std::domain_error); CHECK_THROWS_AS(crit.value(), std::out_of_range); - CHECK_THROWS_NAME(rit.key(), std::domain_error, "cannot use key() for non-object iterators"); - CHECK_THROWS_NAME(rit.value(), std::out_of_range, "cannot get value"); - CHECK_THROWS_NAME(crit.key(), std::domain_error, "cannot use key() for non-object iterators"); - CHECK_THROWS_NAME(crit.value(), std::out_of_range, "cannot get value"); + CHECK_THROWS_WITH(rit.key(), "cannot use key() for non-object iterators"); + CHECK_THROWS_WITH(rit.value(), "cannot get value"); + CHECK_THROWS_WITH(crit.key(), "cannot use key() for non-object iterators"); + CHECK_THROWS_WITH(crit.value(), "cannot get value"); } } @@ -5569,10 +5522,10 @@ TEST_CASE("iterators") CHECK_THROWS_AS(it.value(), std::out_of_range); CHECK_THROWS_AS(cit.key(), std::domain_error); CHECK_THROWS_AS(cit.value(), std::out_of_range); - CHECK_THROWS_NAME(it.key(), std::domain_error, "cannot use key() for non-object iterators"); - CHECK_THROWS_NAME(it.value(), std::out_of_range, "cannot get value"); - CHECK_THROWS_NAME(cit.key(), std::domain_error, "cannot use key() for non-object iterators"); - CHECK_THROWS_NAME(cit.value(), std::out_of_range, "cannot get value"); + CHECK_THROWS_WITH(it.key(), "cannot use key() for non-object iterators"); + CHECK_THROWS_WITH(it.value(), "cannot get value"); + CHECK_THROWS_WITH(cit.key(), "cannot use key() for non-object iterators"); + CHECK_THROWS_WITH(cit.value(), "cannot get value"); auto rit = j.rend(); auto crit = j.crend(); @@ -5580,10 +5533,10 @@ TEST_CASE("iterators") CHECK_THROWS_AS(rit.value(), std::out_of_range); CHECK_THROWS_AS(crit.key(), std::domain_error); CHECK_THROWS_AS(crit.value(), std::out_of_range); - CHECK_THROWS_NAME(rit.key(), std::domain_error, "cannot use key() for non-object iterators"); - CHECK_THROWS_NAME(rit.value(), std::out_of_range, "cannot get value"); - CHECK_THROWS_NAME(crit.key(), std::domain_error, "cannot use key() for non-object iterators"); - CHECK_THROWS_NAME(crit.value(), std::out_of_range, "cannot get value"); + CHECK_THROWS_WITH(rit.key(), "cannot use key() for non-object iterators"); + CHECK_THROWS_WITH(rit.value(), "cannot get value"); + CHECK_THROWS_WITH(crit.key(), "cannot use key() for non-object iterators"); + CHECK_THROWS_WITH(crit.value(), "cannot get value"); } } } @@ -5644,14 +5597,14 @@ TEST_CASE("iterators") CHECK_THROWS_AS(it1_c < it2_c, std::domain_error); CHECK_THROWS_AS(it2_c < it3_c, std::domain_error); CHECK_THROWS_AS(it1_c < it3_c, std::domain_error); - CHECK_THROWS_NAME(it1 < it1, std::domain_error, "cannot compare order of object iterators"); - CHECK_THROWS_NAME(it1 < it2, std::domain_error, "cannot compare order of object iterators"); - CHECK_THROWS_NAME(it2 < it3, std::domain_error, "cannot compare order of object iterators"); - CHECK_THROWS_NAME(it1 < it3, std::domain_error, "cannot compare order of object iterators"); - CHECK_THROWS_NAME(it1_c < it1_c, std::domain_error, "cannot compare order of object iterators"); - CHECK_THROWS_NAME(it1_c < it2_c, std::domain_error, "cannot compare order of object iterators"); - CHECK_THROWS_NAME(it2_c < it3_c, std::domain_error, "cannot compare order of object iterators"); - CHECK_THROWS_NAME(it1_c < it3_c, std::domain_error, "cannot compare order of object iterators"); + CHECK_THROWS_WITH(it1 < it1, "cannot compare order of object iterators"); + CHECK_THROWS_WITH(it1 < it2, "cannot compare order of object iterators"); + CHECK_THROWS_WITH(it2 < it3, "cannot compare order of object iterators"); + CHECK_THROWS_WITH(it1 < it3, "cannot compare order of object iterators"); + CHECK_THROWS_WITH(it1_c < it1_c, "cannot compare order of object iterators"); + CHECK_THROWS_WITH(it1_c < it2_c, "cannot compare order of object iterators"); + CHECK_THROWS_WITH(it2_c < it3_c, "cannot compare order of object iterators"); + CHECK_THROWS_WITH(it1_c < it3_c, "cannot compare order of object iterators"); } else { @@ -5678,14 +5631,14 @@ TEST_CASE("iterators") CHECK_THROWS_AS(it1_c <= it2_c, std::domain_error); CHECK_THROWS_AS(it2_c <= it3_c, std::domain_error); CHECK_THROWS_AS(it1_c <= it3_c, std::domain_error); - CHECK_THROWS_NAME(it1 <= it1, std::domain_error, "cannot compare order of object iterators"); - CHECK_THROWS_NAME(it1 <= it2, std::domain_error, "cannot compare order of object iterators"); - CHECK_THROWS_NAME(it2 <= it3, std::domain_error, "cannot compare order of object iterators"); - CHECK_THROWS_NAME(it1 <= it3, std::domain_error, "cannot compare order of object iterators"); - CHECK_THROWS_NAME(it1_c <= it1_c, std::domain_error, "cannot compare order of object iterators"); - CHECK_THROWS_NAME(it1_c <= it2_c, std::domain_error, "cannot compare order of object iterators"); - CHECK_THROWS_NAME(it2_c <= it3_c, std::domain_error, "cannot compare order of object iterators"); - CHECK_THROWS_NAME(it1_c <= it3_c, std::domain_error, "cannot compare order of object iterators"); + CHECK_THROWS_WITH(it1 <= it1, "cannot compare order of object iterators"); + CHECK_THROWS_WITH(it1 <= it2, "cannot compare order of object iterators"); + CHECK_THROWS_WITH(it2 <= it3, "cannot compare order of object iterators"); + CHECK_THROWS_WITH(it1 <= it3, "cannot compare order of object iterators"); + CHECK_THROWS_WITH(it1_c <= it1_c, "cannot compare order of object iterators"); + CHECK_THROWS_WITH(it1_c <= it2_c, "cannot compare order of object iterators"); + CHECK_THROWS_WITH(it2_c <= it3_c, "cannot compare order of object iterators"); + CHECK_THROWS_WITH(it1_c <= it3_c, "cannot compare order of object iterators"); } else { @@ -5713,14 +5666,14 @@ TEST_CASE("iterators") CHECK_THROWS_AS(it1_c > it2_c, std::domain_error); CHECK_THROWS_AS(it2_c > it3_c, std::domain_error); CHECK_THROWS_AS(it1_c > it3_c, std::domain_error); - CHECK_THROWS_NAME(it1 > it1, std::domain_error, "cannot compare order of object iterators"); - CHECK_THROWS_NAME(it1 > it2, std::domain_error, "cannot compare order of object iterators"); - CHECK_THROWS_NAME(it2 > it3, std::domain_error, "cannot compare order of object iterators"); - CHECK_THROWS_NAME(it1 > it3, std::domain_error, "cannot compare order of object iterators"); - CHECK_THROWS_NAME(it1_c > it1_c, std::domain_error, "cannot compare order of object iterators"); - CHECK_THROWS_NAME(it1_c > it2_c, std::domain_error, "cannot compare order of object iterators"); - CHECK_THROWS_NAME(it2_c > it3_c, std::domain_error, "cannot compare order of object iterators"); - CHECK_THROWS_NAME(it1_c > it3_c, std::domain_error, "cannot compare order of object iterators"); + CHECK_THROWS_WITH(it1 > it1, "cannot compare order of object iterators"); + CHECK_THROWS_WITH(it1 > it2, "cannot compare order of object iterators"); + CHECK_THROWS_WITH(it2 > it3, "cannot compare order of object iterators"); + CHECK_THROWS_WITH(it1 > it3, "cannot compare order of object iterators"); + CHECK_THROWS_WITH(it1_c > it1_c, "cannot compare order of object iterators"); + CHECK_THROWS_WITH(it1_c > it2_c, "cannot compare order of object iterators"); + CHECK_THROWS_WITH(it2_c > it3_c, "cannot compare order of object iterators"); + CHECK_THROWS_WITH(it1_c > it3_c, "cannot compare order of object iterators"); } else { @@ -5748,14 +5701,14 @@ TEST_CASE("iterators") CHECK_THROWS_AS(it1_c >= it2_c, std::domain_error); CHECK_THROWS_AS(it2_c >= it3_c, std::domain_error); CHECK_THROWS_AS(it1_c >= it3_c, std::domain_error); - CHECK_THROWS_NAME(it1 >= it1, std::domain_error, "cannot compare order of object iterators"); - CHECK_THROWS_NAME(it1 >= it2, std::domain_error, "cannot compare order of object iterators"); - CHECK_THROWS_NAME(it2 >= it3, std::domain_error, "cannot compare order of object iterators"); - CHECK_THROWS_NAME(it1 >= it3, std::domain_error, "cannot compare order of object iterators"); - CHECK_THROWS_NAME(it1_c >= it1_c, std::domain_error, "cannot compare order of object iterators"); - CHECK_THROWS_NAME(it1_c >= it2_c, std::domain_error, "cannot compare order of object iterators"); - CHECK_THROWS_NAME(it2_c >= it3_c, std::domain_error, "cannot compare order of object iterators"); - CHECK_THROWS_NAME(it1_c >= it3_c, std::domain_error, "cannot compare order of object iterators"); + CHECK_THROWS_WITH(it1 >= it1, "cannot compare order of object iterators"); + CHECK_THROWS_WITH(it1 >= it2, "cannot compare order of object iterators"); + CHECK_THROWS_WITH(it2 >= it3, "cannot compare order of object iterators"); + CHECK_THROWS_WITH(it1 >= it3, "cannot compare order of object iterators"); + CHECK_THROWS_WITH(it1_c >= it1_c, "cannot compare order of object iterators"); + CHECK_THROWS_WITH(it1_c >= it2_c, "cannot compare order of object iterators"); + CHECK_THROWS_WITH(it2_c >= it3_c, "cannot compare order of object iterators"); + CHECK_THROWS_WITH(it1_c >= it3_c, "cannot compare order of object iterators"); } else { @@ -5781,17 +5734,13 @@ TEST_CASE("iterators") { CHECK_THROWS_AS(j.begin() == k.begin(), std::domain_error); CHECK_THROWS_AS(j.cbegin() == k.cbegin(), std::domain_error); - CHECK_THROWS_NAME(j.begin() == k.begin(), std::domain_error, - "cannot compare iterators of different containers"); - CHECK_THROWS_NAME(j.cbegin() == k.cbegin(), std::domain_error, - "cannot compare iterators of different containers"); + CHECK_THROWS_WITH(j.begin() == k.begin(), "cannot compare iterators of different containers"); + CHECK_THROWS_WITH(j.cbegin() == k.cbegin(), "cannot compare iterators of different containers"); CHECK_THROWS_AS(j.begin() < k.begin(), std::domain_error); CHECK_THROWS_AS(j.cbegin() < k.cbegin(), std::domain_error); - CHECK_THROWS_NAME(j.begin() < k.begin(), std::domain_error, - "cannot compare iterators of different containers"); - CHECK_THROWS_NAME(j.cbegin() < k.cbegin(), std::domain_error, - "cannot compare iterators of different containers"); + CHECK_THROWS_WITH(j.begin() < k.begin(), "cannot compare iterators of different containers"); + CHECK_THROWS_WITH(j.cbegin() < k.cbegin(), "cannot compare iterators of different containers"); } } } @@ -5811,52 +5760,52 @@ TEST_CASE("iterators") { auto it = j_object.begin(); CHECK_THROWS_AS(it += 1, std::domain_error); - CHECK_THROWS_NAME(it += 1, std::domain_error, "cannot use offsets with object iterators"); + CHECK_THROWS_WITH(it += 1, "cannot use offsets with object iterators"); } { auto it = j_object.cbegin(); CHECK_THROWS_AS(it += 1, std::domain_error); - CHECK_THROWS_NAME(it += 1, std::domain_error, "cannot use offsets with object iterators"); + CHECK_THROWS_WITH(it += 1, "cannot use offsets with object iterators"); } { auto it = j_object.begin(); CHECK_THROWS_AS(it + 1, std::domain_error); - CHECK_THROWS_NAME(it + 1, std::domain_error, "cannot use offsets with object iterators"); + CHECK_THROWS_WITH(it + 1, "cannot use offsets with object iterators"); } { auto it = j_object.cbegin(); CHECK_THROWS_AS(it + 1, std::domain_error); - CHECK_THROWS_NAME(it + 1, std::domain_error, "cannot use offsets with object iterators"); + CHECK_THROWS_WITH(it + 1, "cannot use offsets with object iterators"); } { auto it = j_object.begin(); CHECK_THROWS_AS(it -= 1, std::domain_error); - CHECK_THROWS_NAME(it -= 1, std::domain_error, "cannot use offsets with object iterators"); + CHECK_THROWS_WITH(it -= 1, "cannot use offsets with object iterators"); } { auto it = j_object.cbegin(); CHECK_THROWS_AS(it -= 1, std::domain_error); - CHECK_THROWS_NAME(it -= 1, std::domain_error, "cannot use offsets with object iterators"); + CHECK_THROWS_WITH(it -= 1, "cannot use offsets with object iterators"); } { auto it = j_object.begin(); CHECK_THROWS_AS(it - 1, std::domain_error); - CHECK_THROWS_NAME(it - 1, std::domain_error, "cannot use offsets with object iterators"); + CHECK_THROWS_WITH(it - 1, "cannot use offsets with object iterators"); } { auto it = j_object.cbegin(); CHECK_THROWS_AS(it - 1, std::domain_error); - CHECK_THROWS_NAME(it - 1, std::domain_error, "cannot use offsets with object iterators"); + CHECK_THROWS_WITH(it - 1, "cannot use offsets with object iterators"); } { auto it = j_object.begin(); CHECK_THROWS_AS(it - it, std::domain_error); - CHECK_THROWS_NAME(it - it, std::domain_error, "cannot use offsets with object iterators"); + CHECK_THROWS_WITH(it - it, "cannot use offsets with object iterators"); } { auto it = j_object.cbegin(); CHECK_THROWS_AS(it - it, std::domain_error); - CHECK_THROWS_NAME(it - it, std::domain_error, "cannot use offsets with object iterators"); + CHECK_THROWS_WITH(it - it, "cannot use offsets with object iterators"); } } @@ -5941,15 +5890,15 @@ TEST_CASE("iterators") auto it = j_object.begin(); CHECK_THROWS_AS(it[0], std::domain_error); CHECK_THROWS_AS(it[1], std::domain_error); - CHECK_THROWS_NAME(it[0], std::domain_error, "cannot use operator[] for object iterators"); - CHECK_THROWS_NAME(it[1], std::domain_error, "cannot use operator[] for object iterators"); + CHECK_THROWS_WITH(it[0], "cannot use operator[] for object iterators"); + CHECK_THROWS_WITH(it[1], "cannot use operator[] for object iterators"); } { auto it = j_object.cbegin(); CHECK_THROWS_AS(it[0], std::domain_error); CHECK_THROWS_AS(it[1], std::domain_error); - CHECK_THROWS_NAME(it[0], std::domain_error, "cannot use operator[] for object iterators"); - CHECK_THROWS_NAME(it[1], std::domain_error, "cannot use operator[] for object iterators"); + CHECK_THROWS_WITH(it[0], "cannot use operator[] for object iterators"); + CHECK_THROWS_WITH(it[1], "cannot use operator[] for object iterators"); } } @@ -5981,15 +5930,15 @@ TEST_CASE("iterators") auto it = j_null.begin(); CHECK_THROWS_AS(it[0], std::out_of_range); CHECK_THROWS_AS(it[1], std::out_of_range); - CHECK_THROWS_NAME(it[0], std::out_of_range, "cannot get value"); - CHECK_THROWS_NAME(it[1], std::out_of_range, "cannot get value"); + CHECK_THROWS_WITH(it[0], "cannot get value"); + CHECK_THROWS_WITH(it[1], "cannot get value"); } { auto it = j_null.cbegin(); CHECK_THROWS_AS(it[0], std::out_of_range); CHECK_THROWS_AS(it[1], std::out_of_range); - CHECK_THROWS_NAME(it[0], std::out_of_range, "cannot get value"); - CHECK_THROWS_NAME(it[1], std::out_of_range, "cannot get value"); + CHECK_THROWS_WITH(it[0], "cannot get value"); + CHECK_THROWS_WITH(it[1], "cannot get value"); } } @@ -5999,13 +5948,13 @@ TEST_CASE("iterators") auto it = j_value.begin(); CHECK(it[0] == json(42)); CHECK_THROWS_AS(it[1], std::out_of_range); - CHECK_THROWS_NAME(it[1], std::out_of_range, "cannot get value"); + CHECK_THROWS_WITH(it[1], "cannot get value"); } { auto it = j_value.cbegin(); CHECK(it[0] == json(42)); CHECK_THROWS_AS(it[1], std::out_of_range); - CHECK_THROWS_NAME(it[1], std::out_of_range, "cannot get value"); + CHECK_THROWS_WITH(it[1], "cannot get value"); } } } @@ -6067,14 +6016,14 @@ TEST_CASE("iterators") CHECK_THROWS_AS(it1_c < it2_c, std::domain_error); CHECK_THROWS_AS(it2_c < it3_c, std::domain_error); CHECK_THROWS_AS(it1_c < it3_c, std::domain_error); - CHECK_THROWS_NAME(it1 < it1, std::domain_error, "cannot compare order of object iterators"); - CHECK_THROWS_NAME(it1 < it2, std::domain_error, "cannot compare order of object iterators"); - CHECK_THROWS_NAME(it2 < it3, std::domain_error, "cannot compare order of object iterators"); - CHECK_THROWS_NAME(it1 < it3, std::domain_error, "cannot compare order of object iterators"); - CHECK_THROWS_NAME(it1_c < it1_c, std::domain_error, "cannot compare order of object iterators"); - CHECK_THROWS_NAME(it1_c < it2_c, std::domain_error, "cannot compare order of object iterators"); - CHECK_THROWS_NAME(it2_c < it3_c, std::domain_error, "cannot compare order of object iterators"); - CHECK_THROWS_NAME(it1_c < it3_c, std::domain_error, "cannot compare order of object iterators"); + CHECK_THROWS_WITH(it1 < it1, "cannot compare order of object iterators"); + CHECK_THROWS_WITH(it1 < it2, "cannot compare order of object iterators"); + CHECK_THROWS_WITH(it2 < it3, "cannot compare order of object iterators"); + CHECK_THROWS_WITH(it1 < it3, "cannot compare order of object iterators"); + CHECK_THROWS_WITH(it1_c < it1_c, "cannot compare order of object iterators"); + CHECK_THROWS_WITH(it1_c < it2_c, "cannot compare order of object iterators"); + CHECK_THROWS_WITH(it2_c < it3_c, "cannot compare order of object iterators"); + CHECK_THROWS_WITH(it1_c < it3_c, "cannot compare order of object iterators"); } else { @@ -6101,14 +6050,14 @@ TEST_CASE("iterators") CHECK_THROWS_AS(it1_c <= it2_c, std::domain_error); CHECK_THROWS_AS(it2_c <= it3_c, std::domain_error); CHECK_THROWS_AS(it1_c <= it3_c, std::domain_error); - CHECK_THROWS_NAME(it1 <= it1, std::domain_error, "cannot compare order of object iterators"); - CHECK_THROWS_NAME(it1 <= it2, std::domain_error, "cannot compare order of object iterators"); - CHECK_THROWS_NAME(it2 <= it3, std::domain_error, "cannot compare order of object iterators"); - CHECK_THROWS_NAME(it1 <= it3, std::domain_error, "cannot compare order of object iterators"); - CHECK_THROWS_NAME(it1_c <= it1_c, std::domain_error, "cannot compare order of object iterators"); - CHECK_THROWS_NAME(it1_c <= it2_c, std::domain_error, "cannot compare order of object iterators"); - CHECK_THROWS_NAME(it2_c <= it3_c, std::domain_error, "cannot compare order of object iterators"); - CHECK_THROWS_NAME(it1_c <= it3_c, std::domain_error, "cannot compare order of object iterators"); + CHECK_THROWS_WITH(it1 <= it1, "cannot compare order of object iterators"); + CHECK_THROWS_WITH(it1 <= it2, "cannot compare order of object iterators"); + CHECK_THROWS_WITH(it2 <= it3, "cannot compare order of object iterators"); + CHECK_THROWS_WITH(it1 <= it3, "cannot compare order of object iterators"); + CHECK_THROWS_WITH(it1_c <= it1_c, "cannot compare order of object iterators"); + CHECK_THROWS_WITH(it1_c <= it2_c, "cannot compare order of object iterators"); + CHECK_THROWS_WITH(it2_c <= it3_c, "cannot compare order of object iterators"); + CHECK_THROWS_WITH(it1_c <= it3_c, "cannot compare order of object iterators"); } else { @@ -6136,14 +6085,14 @@ TEST_CASE("iterators") CHECK_THROWS_AS(it1_c > it2_c, std::domain_error); CHECK_THROWS_AS(it2_c > it3_c, std::domain_error); CHECK_THROWS_AS(it1_c > it3_c, std::domain_error); - CHECK_THROWS_NAME(it1 > it1, std::domain_error, "cannot compare order of object iterators"); - CHECK_THROWS_NAME(it1 > it2, std::domain_error, "cannot compare order of object iterators"); - CHECK_THROWS_NAME(it2 > it3, std::domain_error, "cannot compare order of object iterators"); - CHECK_THROWS_NAME(it1 > it3, std::domain_error, "cannot compare order of object iterators"); - CHECK_THROWS_NAME(it1_c > it1_c, std::domain_error, "cannot compare order of object iterators"); - CHECK_THROWS_NAME(it1_c > it2_c, std::domain_error, "cannot compare order of object iterators"); - CHECK_THROWS_NAME(it2_c > it3_c, std::domain_error, "cannot compare order of object iterators"); - CHECK_THROWS_NAME(it1_c > it3_c, std::domain_error, "cannot compare order of object iterators"); + CHECK_THROWS_WITH(it1 > it1, "cannot compare order of object iterators"); + CHECK_THROWS_WITH(it1 > it2, "cannot compare order of object iterators"); + CHECK_THROWS_WITH(it2 > it3, "cannot compare order of object iterators"); + CHECK_THROWS_WITH(it1 > it3, "cannot compare order of object iterators"); + CHECK_THROWS_WITH(it1_c > it1_c, "cannot compare order of object iterators"); + CHECK_THROWS_WITH(it1_c > it2_c, "cannot compare order of object iterators"); + CHECK_THROWS_WITH(it2_c > it3_c, "cannot compare order of object iterators"); + CHECK_THROWS_WITH(it1_c > it3_c, "cannot compare order of object iterators"); } else { @@ -6171,14 +6120,14 @@ TEST_CASE("iterators") CHECK_THROWS_AS(it1_c >= it2_c, std::domain_error); CHECK_THROWS_AS(it2_c >= it3_c, std::domain_error); CHECK_THROWS_AS(it1_c >= it3_c, std::domain_error); - CHECK_THROWS_NAME(it1 >= it1, std::domain_error, "cannot compare order of object iterators"); - CHECK_THROWS_NAME(it1 >= it2, std::domain_error, "cannot compare order of object iterators"); - CHECK_THROWS_NAME(it2 >= it3, std::domain_error, "cannot compare order of object iterators"); - CHECK_THROWS_NAME(it1 >= it3, std::domain_error, "cannot compare order of object iterators"); - CHECK_THROWS_NAME(it1_c >= it1_c, std::domain_error, "cannot compare order of object iterators"); - CHECK_THROWS_NAME(it1_c >= it2_c, std::domain_error, "cannot compare order of object iterators"); - CHECK_THROWS_NAME(it2_c >= it3_c, std::domain_error, "cannot compare order of object iterators"); - CHECK_THROWS_NAME(it1_c >= it3_c, std::domain_error, "cannot compare order of object iterators"); + CHECK_THROWS_WITH(it1 >= it1, "cannot compare order of object iterators"); + CHECK_THROWS_WITH(it1 >= it2, "cannot compare order of object iterators"); + CHECK_THROWS_WITH(it2 >= it3, "cannot compare order of object iterators"); + CHECK_THROWS_WITH(it1 >= it3, "cannot compare order of object iterators"); + CHECK_THROWS_WITH(it1_c >= it1_c, "cannot compare order of object iterators"); + CHECK_THROWS_WITH(it1_c >= it2_c, "cannot compare order of object iterators"); + CHECK_THROWS_WITH(it2_c >= it3_c, "cannot compare order of object iterators"); + CHECK_THROWS_WITH(it1_c >= it3_c, "cannot compare order of object iterators"); } else { @@ -6204,17 +6153,13 @@ TEST_CASE("iterators") { CHECK_THROWS_AS(j.rbegin() == k.rbegin(), std::domain_error); CHECK_THROWS_AS(j.crbegin() == k.crbegin(), std::domain_error); - CHECK_THROWS_NAME(j.rbegin() == k.rbegin(), std::domain_error, - "cannot compare iterators of different containers"); - CHECK_THROWS_NAME(j.crbegin() == k.crbegin(), std::domain_error, - "cannot compare iterators of different containers"); + CHECK_THROWS_WITH(j.rbegin() == k.rbegin(), "cannot compare iterators of different containers"); + CHECK_THROWS_WITH(j.crbegin() == k.crbegin(), "cannot compare iterators of different containers"); CHECK_THROWS_AS(j.rbegin() < k.rbegin(), std::domain_error); CHECK_THROWS_AS(j.crbegin() < k.crbegin(), std::domain_error); - CHECK_THROWS_NAME(j.rbegin() < k.rbegin(), std::domain_error, - "cannot compare iterators of different containers"); - CHECK_THROWS_NAME(j.crbegin() < k.crbegin(), std::domain_error, - "cannot compare iterators of different containers"); + CHECK_THROWS_WITH(j.rbegin() < k.rbegin(), "cannot compare iterators of different containers"); + CHECK_THROWS_WITH(j.crbegin() < k.crbegin(), "cannot compare iterators of different containers"); } } } @@ -6234,52 +6179,52 @@ TEST_CASE("iterators") { auto it = j_object.rbegin(); CHECK_THROWS_AS(it += 1, std::domain_error); - CHECK_THROWS_NAME(it += 1, std::domain_error, "cannot use offsets with object iterators"); + CHECK_THROWS_WITH(it += 1, "cannot use offsets with object iterators"); } { auto it = j_object.crbegin(); CHECK_THROWS_AS(it += 1, std::domain_error); - CHECK_THROWS_NAME(it += 1, std::domain_error, "cannot use offsets with object iterators"); + CHECK_THROWS_WITH(it += 1, "cannot use offsets with object iterators"); } { auto it = j_object.rbegin(); CHECK_THROWS_AS(it + 1, std::domain_error); - CHECK_THROWS_NAME(it + 1, std::domain_error, "cannot use offsets with object iterators"); + CHECK_THROWS_WITH(it + 1, "cannot use offsets with object iterators"); } { auto it = j_object.crbegin(); CHECK_THROWS_AS(it + 1, std::domain_error); - CHECK_THROWS_NAME(it + 1, std::domain_error, "cannot use offsets with object iterators"); + CHECK_THROWS_WITH(it + 1, "cannot use offsets with object iterators"); } { auto it = j_object.rbegin(); CHECK_THROWS_AS(it -= 1, std::domain_error); - CHECK_THROWS_NAME(it -= 1, std::domain_error, "cannot use offsets with object iterators"); + CHECK_THROWS_WITH(it -= 1, "cannot use offsets with object iterators"); } { auto it = j_object.crbegin(); CHECK_THROWS_AS(it -= 1, std::domain_error); - CHECK_THROWS_NAME(it -= 1, std::domain_error, "cannot use offsets with object iterators"); + CHECK_THROWS_WITH(it -= 1, "cannot use offsets with object iterators"); } { auto it = j_object.rbegin(); CHECK_THROWS_AS(it - 1, std::domain_error); - CHECK_THROWS_NAME(it - 1, std::domain_error, "cannot use offsets with object iterators"); + CHECK_THROWS_WITH(it - 1, "cannot use offsets with object iterators"); } { auto it = j_object.crbegin(); CHECK_THROWS_AS(it - 1, std::domain_error); - CHECK_THROWS_NAME(it - 1, std::domain_error, "cannot use offsets with object iterators"); + CHECK_THROWS_WITH(it - 1, "cannot use offsets with object iterators"); } { auto it = j_object.rbegin(); CHECK_THROWS_AS(it - it, std::domain_error); - CHECK_THROWS_NAME(it - it, std::domain_error, "cannot use offsets with object iterators"); + CHECK_THROWS_WITH(it - it, "cannot use offsets with object iterators"); } { auto it = j_object.crbegin(); CHECK_THROWS_AS(it - it, std::domain_error); - CHECK_THROWS_NAME(it - it, std::domain_error, "cannot use offsets with object iterators"); + CHECK_THROWS_WITH(it - it, "cannot use offsets with object iterators"); } } @@ -6364,15 +6309,15 @@ TEST_CASE("iterators") auto it = j_object.rbegin(); CHECK_THROWS_AS(it[0], std::domain_error); CHECK_THROWS_AS(it[1], std::domain_error); - CHECK_THROWS_NAME(it[0], std::domain_error, "cannot use offsets with object iterators"); - CHECK_THROWS_NAME(it[1], std::domain_error, "cannot use offsets with object iterators"); + CHECK_THROWS_WITH(it[0], "cannot use offsets with object iterators"); + CHECK_THROWS_WITH(it[1], "cannot use offsets with object iterators"); } { auto it = j_object.crbegin(); CHECK_THROWS_AS(it[0], std::domain_error); CHECK_THROWS_AS(it[1], std::domain_error); - CHECK_THROWS_NAME(it[0], std::domain_error, "cannot use offsets with object iterators"); - CHECK_THROWS_NAME(it[1], std::domain_error, "cannot use offsets with object iterators"); + CHECK_THROWS_WITH(it[0], "cannot use offsets with object iterators"); + CHECK_THROWS_WITH(it[1], "cannot use offsets with object iterators"); } } @@ -6404,15 +6349,15 @@ TEST_CASE("iterators") auto it = j_null.rbegin(); CHECK_THROWS_AS(it[0], std::out_of_range); CHECK_THROWS_AS(it[1], std::out_of_range); - CHECK_THROWS_NAME(it[0], std::out_of_range, "cannot get value"); - CHECK_THROWS_NAME(it[1], std::out_of_range, "cannot get value"); + CHECK_THROWS_WITH(it[0], "cannot get value"); + CHECK_THROWS_WITH(it[1], "cannot get value"); } { auto it = j_null.crbegin(); CHECK_THROWS_AS(it[0], std::out_of_range); CHECK_THROWS_AS(it[1], std::out_of_range); - CHECK_THROWS_NAME(it[0], std::out_of_range, "cannot get value"); - CHECK_THROWS_NAME(it[1], std::out_of_range, "cannot get value"); + CHECK_THROWS_WITH(it[0], "cannot get value"); + CHECK_THROWS_WITH(it[1], "cannot get value"); } } @@ -6422,13 +6367,13 @@ TEST_CASE("iterators") auto it = j_value.rbegin(); CHECK(it[0] == json(42)); CHECK_THROWS_AS(it[1], std::out_of_range); - CHECK_THROWS_NAME(it[1], std::out_of_range, "cannot get value"); + CHECK_THROWS_WITH(it[1], "cannot get value"); } { auto it = j_value.crbegin(); CHECK(it[0] == json(42)); CHECK_THROWS_AS(it[1], std::out_of_range); - CHECK_THROWS_NAME(it[1], std::out_of_range, "cannot get value"); + CHECK_THROWS_WITH(it[1], "cannot get value"); } } } @@ -7029,7 +6974,7 @@ TEST_CASE("modifiers") { json j = 1; CHECK_THROWS_AS(j.push_back("Hello"), std::domain_error); - CHECK_THROWS_NAME(j.push_back("Hello"), std::domain_error, "cannot use push_back() with number"); + CHECK_THROWS_WITH(j.push_back("Hello"), "cannot use push_back() with number"); } } @@ -7059,7 +7004,7 @@ TEST_CASE("modifiers") json j = 1; json k("Hello"); CHECK_THROWS_AS(j.push_back(k), std::domain_error); - CHECK_THROWS_NAME(j.push_back(k), std::domain_error, "cannot use push_back() with number"); + CHECK_THROWS_WITH(j.push_back(k), "cannot use push_back() with number"); } } } @@ -7092,7 +7037,7 @@ TEST_CASE("modifiers") json j = 1; json k("Hello"); CHECK_THROWS_AS(j.push_back(json::object_t::value_type({"one", 1})), std::domain_error); - CHECK_THROWS_NAME(j.push_back(json::object_t::value_type({"one", 1})), std::domain_error, + CHECK_THROWS_WITH(j.push_back(json::object_t::value_type({"one", 1})), "cannot use push_back() with number"); } } @@ -7125,7 +7070,7 @@ TEST_CASE("modifiers") { json j = 1; CHECK_THROWS_AS(j += "Hello", std::domain_error); - CHECK_THROWS_NAME(j += "Hello", std::domain_error, "cannot use push_back() with number"); + CHECK_THROWS_WITH(j += "Hello", "cannot use push_back() with number"); } } @@ -7155,7 +7100,7 @@ TEST_CASE("modifiers") json j = 1; json k("Hello"); CHECK_THROWS_AS(j += k, std::domain_error); - CHECK_THROWS_NAME(j += k, std::domain_error, "cannot use push_back() with number"); + CHECK_THROWS_WITH(j += k, "cannot use push_back() with number"); } } } @@ -7188,7 +7133,7 @@ TEST_CASE("modifiers") json j = 1; json k("Hello"); CHECK_THROWS_AS(j += json::object_t::value_type({"one", 1}), std::domain_error); - CHECK_THROWS_NAME(j += json::object_t::value_type({"one", 1}), std::domain_error, + CHECK_THROWS_WITH(j += json::object_t::value_type({"one", 1}), "cannot use push_back() with number"); } } @@ -7327,10 +7272,10 @@ TEST_CASE("modifiers") CHECK_THROWS_AS(j_array.insert(j_array.end(), j_other_array.begin(), j_other_array2.end()), std::domain_error); - CHECK_THROWS_NAME(j_array.insert(j_array.end(), j_array.begin(), j_array.end()), std::domain_error, + CHECK_THROWS_WITH(j_array.insert(j_array.end(), j_array.begin(), j_array.end()), "passed iterators may not belong to container"); - CHECK_THROWS_NAME(j_array.insert(j_array.end(), j_other_array.begin(), j_other_array2.end()), - std::domain_error, "iterators do not fit"); + CHECK_THROWS_WITH(j_array.insert(j_array.end(), j_other_array.begin(), j_other_array2.end()), + "iterators do not fit"); } } @@ -7376,15 +7321,14 @@ TEST_CASE("modifiers") j_yet_another_array.end()), std::domain_error); CHECK_THROWS_AS(j_array.insert(j_another_array.end(), {1, 2, 3, 4}), std::domain_error); - CHECK_THROWS_NAME(j_array.insert(j_another_array.end(), 10), std::domain_error, + CHECK_THROWS_WITH(j_array.insert(j_another_array.end(), 10), "iterator does not fit current value"); + CHECK_THROWS_WITH(j_array.insert(j_another_array.end(), j_value), "iterator does not fit current value"); - CHECK_THROWS_NAME(j_array.insert(j_another_array.end(), j_value), std::domain_error, + CHECK_THROWS_WITH(j_array.insert(j_another_array.end(), 10, 11), "iterator does not fit current value"); - CHECK_THROWS_NAME(j_array.insert(j_another_array.end(), 10, 11), std::domain_error, - "iterator does not fit current value"); - CHECK_THROWS_NAME(j_array.insert(j_another_array.end(), j_yet_another_array.begin(), - j_yet_another_array.end()), std::domain_error, "iterator does not fit current value"); - CHECK_THROWS_NAME(j_array.insert(j_another_array.end(), {1, 2, 3, 4}), std::domain_error, + CHECK_THROWS_WITH(j_array.insert(j_another_array.end(), j_yet_another_array.begin(), + j_yet_another_array.end()), "iterator does not fit current value"); + CHECK_THROWS_WITH(j_array.insert(j_another_array.end(), {1, 2, 3, 4}), "iterator does not fit current value"); } @@ -7400,15 +7344,12 @@ TEST_CASE("modifiers") j_yet_another_array.end()), std::domain_error); CHECK_THROWS_AS(j_nonarray.insert(j_nonarray.end(), {1, 2, 3, 4}), std::domain_error); - CHECK_THROWS_NAME(j_nonarray.insert(j_nonarray.end(), 10), std::domain_error, - "cannot use insert() with number"); - CHECK_THROWS_NAME(j_nonarray.insert(j_nonarray.end(), j_value), std::domain_error, - "cannot use insert() with number"); - CHECK_THROWS_NAME(j_nonarray.insert(j_nonarray.end(), 10, 11), std::domain_error, - "cannot use insert() with number"); - CHECK_THROWS_NAME(j_nonarray.insert(j_nonarray.end(), j_yet_another_array.begin(), - j_yet_another_array.end()), std::domain_error, "cannot use insert() with number"); - CHECK_THROWS_NAME(j_nonarray.insert(j_nonarray.end(), {1, 2, 3, 4}), std::domain_error, + CHECK_THROWS_WITH(j_nonarray.insert(j_nonarray.end(), 10), "cannot use insert() with number"); + CHECK_THROWS_WITH(j_nonarray.insert(j_nonarray.end(), j_value), "cannot use insert() with number"); + CHECK_THROWS_WITH(j_nonarray.insert(j_nonarray.end(), 10, 11), "cannot use insert() with number"); + CHECK_THROWS_WITH(j_nonarray.insert(j_nonarray.end(), j_yet_another_array.begin(), + j_yet_another_array.end()), "cannot use insert() with number"); + CHECK_THROWS_WITH(j_nonarray.insert(j_nonarray.end(), {1, 2, 3, 4}), "cannot use insert() with number"); } } @@ -7462,7 +7403,7 @@ TEST_CASE("modifiers") json::array_t a = {"foo", "bar", "baz"}; CHECK_THROWS_AS(j.swap(a), std::domain_error); - CHECK_THROWS_NAME(j.swap(a), std::domain_error, "cannot use swap() with number"); + CHECK_THROWS_WITH(j.swap(a), "cannot use swap() with number"); } } @@ -7488,7 +7429,7 @@ TEST_CASE("modifiers") json::object_t o = {{"cow", "Kuh"}, {"chicken", "Huhn"}}; CHECK_THROWS_AS(j.swap(o), std::domain_error); - CHECK_THROWS_NAME(j.swap(o), std::domain_error, "cannot use swap() with number"); + CHECK_THROWS_WITH(j.swap(o), "cannot use swap() with number"); } } @@ -7514,7 +7455,7 @@ TEST_CASE("modifiers") json::string_t s = "Hallo Welt"; CHECK_THROWS_AS(j.swap(s), std::domain_error); - CHECK_THROWS_NAME(j.swap(s), std::domain_error, "cannot use swap() with number"); + CHECK_THROWS_WITH(j.swap(s), "cannot use swap() with number"); } } } @@ -7899,7 +7840,7 @@ TEST_CASE("iterator class") json j(json::value_t::null); json::iterator it = j.begin(); CHECK_THROWS_AS(*it, std::out_of_range); - CHECK_THROWS_NAME(*it, std::out_of_range, "cannot get value"); + CHECK_THROWS_WITH(*it, "cannot get value"); } SECTION("number") @@ -7909,7 +7850,7 @@ TEST_CASE("iterator class") CHECK(*it == json(17)); it = j.end(); CHECK_THROWS_AS(*it, std::out_of_range); - CHECK_THROWS_NAME(*it, std::out_of_range, "cannot get value"); + CHECK_THROWS_WITH(*it, "cannot get value"); } SECTION("object") @@ -7934,7 +7875,7 @@ TEST_CASE("iterator class") json j(json::value_t::null); json::iterator it = j.begin(); CHECK_THROWS_AS(it->type_name(), std::out_of_range); - CHECK_THROWS_NAME(it->type_name(), std::out_of_range, "cannot get value"); + CHECK_THROWS_WITH(it->type_name(), "cannot get value"); } SECTION("number") @@ -7944,7 +7885,7 @@ TEST_CASE("iterator class") CHECK(it->type_name() == "number"); it = j.end(); CHECK_THROWS_AS(it->type_name(), std::out_of_range); - CHECK_THROWS_NAME(it->type_name(), std::out_of_range, "cannot get value"); + CHECK_THROWS_WITH(it->type_name(), "cannot get value"); } SECTION("object") @@ -8267,7 +8208,7 @@ TEST_CASE("const_iterator class") json j(json::value_t::null); json::const_iterator it = j.cbegin(); CHECK_THROWS_AS(*it, std::out_of_range); - CHECK_THROWS_NAME(*it, std::out_of_range, "cannot get value"); + CHECK_THROWS_WITH(*it, "cannot get value"); } SECTION("number") @@ -8277,7 +8218,7 @@ TEST_CASE("const_iterator class") CHECK(*it == json(17)); it = j.cend(); CHECK_THROWS_AS(*it, std::out_of_range); - CHECK_THROWS_NAME(*it, std::out_of_range, "cannot get value"); + CHECK_THROWS_WITH(*it, "cannot get value"); } SECTION("object") @@ -8302,7 +8243,7 @@ TEST_CASE("const_iterator class") json j(json::value_t::null); json::const_iterator it = j.cbegin(); CHECK_THROWS_AS(it->type_name(), std::out_of_range); - CHECK_THROWS_NAME(it->type_name(), std::out_of_range, "cannot get value"); + CHECK_THROWS_WITH(it->type_name(), "cannot get value"); } SECTION("number") @@ -8312,7 +8253,7 @@ TEST_CASE("const_iterator class") CHECK(it->type_name() == "number"); it = j.cend(); CHECK_THROWS_AS(it->type_name(), std::out_of_range); - CHECK_THROWS_NAME(it->type_name(), std::out_of_range, "cannot get value"); + CHECK_THROWS_WITH(it->type_name(), "cannot get value"); } SECTION("object") @@ -8711,8 +8652,7 @@ TEST_CASE("lexer class") { CHECK(json::lexer::to_unicode(0x1F4A9) == "💩"); CHECK_THROWS_AS(json::lexer::to_unicode(0x200000), std::out_of_range); - CHECK_THROWS_NAME(json::lexer::to_unicode(0x200000), std::out_of_range, - "code points above 0x10FFFF are invalid"); + CHECK_THROWS_WITH(json::lexer::to_unicode(0x200000), "code points above 0x10FFFF are invalid"); } } @@ -8772,19 +8712,15 @@ TEST_CASE("parser class") { // error: tab in string CHECK_THROWS_AS(json::parser("\"\t\"").parse(), std::invalid_argument); - CHECK_THROWS_NAME(json::parser("\"\t\"").parse(), std::invalid_argument, - "parse error - unexpected '\"'"); + CHECK_THROWS_WITH(json::parser("\"\t\"").parse(), "parse error - unexpected '\"'"); // error: newline in string CHECK_THROWS_AS(json::parser("\"\n\"").parse(), std::invalid_argument); CHECK_THROWS_AS(json::parser("\"\r\"").parse(), std::invalid_argument); - CHECK_THROWS_NAME(json::parser("\"\n\"").parse(), std::invalid_argument, - "parse error - unexpected '\"'"); - CHECK_THROWS_NAME(json::parser("\"\r\"").parse(), std::invalid_argument, - "parse error - unexpected '\"'"); + CHECK_THROWS_WITH(json::parser("\"\n\"").parse(), "parse error - unexpected '\"'"); + CHECK_THROWS_WITH(json::parser("\"\r\"").parse(), "parse error - unexpected '\"'"); // error: backspace in string CHECK_THROWS_AS(json::parser("\"\b\"").parse(), std::invalid_argument); - CHECK_THROWS_NAME(json::parser("\"\b\"").parse(), std::invalid_argument, - "parse error - unexpected '\"'"); + CHECK_THROWS_WITH(json::parser("\"\b\"").parse(), "parse error - unexpected '\"'"); } SECTION("escaped") @@ -8922,37 +8858,33 @@ TEST_CASE("parser class") CHECK_THROWS_AS(json::parser("-0e-:").parse(), std::invalid_argument); CHECK_THROWS_AS(json::parser("-0f").parse(), std::invalid_argument); - CHECK_THROWS_NAME(json::parser("01").parse(), std::invalid_argument, - "parse error - 0 is not a number"); - CHECK_THROWS_NAME(json::parser("--1").parse(), std::invalid_argument, - "parse error - unexpected '-'"); - CHECK_THROWS_NAME(json::parser("1.").parse(), std::invalid_argument, - "parse error - 1 is not a number"); - CHECK_THROWS_NAME(json::parser("1E").parse(), std::invalid_argument, + CHECK_THROWS_WITH(json::parser("01").parse(), "parse error - 0 is not a number"); + CHECK_THROWS_WITH(json::parser("--1").parse(), "parse error - unexpected '-'"); + CHECK_THROWS_WITH(json::parser("1.").parse(), "parse error - 1 is not a number"); + CHECK_THROWS_WITH(json::parser("1E").parse(), "parse error - unexpected 'E'; expected end of input"); - CHECK_THROWS_NAME(json::parser("1E-").parse(), std::invalid_argument, + CHECK_THROWS_WITH(json::parser("1E-").parse(), "parse error - unexpected 'E'; expected end of input"); - CHECK_THROWS_NAME(json::parser("1.E1").parse(), std::invalid_argument, - "parse error - 1 is not a number"); - CHECK_THROWS_NAME(json::parser("-1E").parse(), std::invalid_argument, + CHECK_THROWS_WITH(json::parser("1.E1").parse(), "parse error - 1 is not a number"); + CHECK_THROWS_WITH(json::parser("-1E").parse(), "parse error - unexpected 'E'; expected end of input"); - CHECK_THROWS_NAME(json::parser("-0E#").parse(), std::invalid_argument, + CHECK_THROWS_WITH(json::parser("-0E#").parse(), "parse error - unexpected 'E'; expected end of input"); - CHECK_THROWS_NAME(json::parser("-0E-#").parse(), std::invalid_argument, + CHECK_THROWS_WITH(json::parser("-0E-#").parse(), "parse error - unexpected 'E'; expected end of input"); - CHECK_THROWS_NAME(json::parser("-0#").parse(), std::invalid_argument, + CHECK_THROWS_WITH(json::parser("-0#").parse(), "parse error - unexpected '#'; expected end of input"); - CHECK_THROWS_NAME(json::parser("-0.0:").parse(), std::invalid_argument, + CHECK_THROWS_WITH(json::parser("-0.0:").parse(), "parse error - unexpected ':'; expected end of input"); - CHECK_THROWS_NAME(json::parser("-0.0Z").parse(), std::invalid_argument, + CHECK_THROWS_WITH(json::parser("-0.0Z").parse(), "parse error - unexpected 'Z'; expected end of input"); - CHECK_THROWS_NAME(json::parser("-0E123:").parse(), std::invalid_argument, + CHECK_THROWS_WITH(json::parser("-0E123:").parse(), "parse error - unexpected ':'; expected end of input"); - CHECK_THROWS_NAME(json::parser("-0e0-:").parse(), std::invalid_argument, + CHECK_THROWS_WITH(json::parser("-0e0-:").parse(), "parse error - unexpected '-'; expected end of input"); - CHECK_THROWS_NAME(json::parser("-0e-:").parse(), std::invalid_argument, + CHECK_THROWS_WITH(json::parser("-0e-:").parse(), "parse error - unexpected 'e'; expected end of input"); - CHECK_THROWS_NAME(json::parser("-0f").parse(), std::invalid_argument, + CHECK_THROWS_WITH(json::parser("-0f").parse(), "parse error - unexpected 'f'; expected end of input"); } } @@ -8975,52 +8907,51 @@ TEST_CASE("parser class") CHECK_THROWS_AS(json::parser("1E.").parse(), std::invalid_argument); CHECK_THROWS_AS(json::parser("1E/").parse(), std::invalid_argument); CHECK_THROWS_AS(json::parser("1E:").parse(), std::invalid_argument); - CHECK_THROWS_NAME(json::parser("0.").parse(), std::invalid_argument, - "parse error - 0 is not a number"); - CHECK_THROWS_NAME(json::parser("-").parse(), std::invalid_argument, "parse error - unexpected '-'"); - CHECK_THROWS_NAME(json::parser("--").parse(), std::invalid_argument, + CHECK_THROWS_WITH(json::parser("0.").parse(), "parse error - 0 is not a number"); + CHECK_THROWS_WITH(json::parser("-").parse(), "parse error - unexpected '-'"); + CHECK_THROWS_WITH(json::parser("--").parse(), "parse error - unexpected '-'"); - CHECK_THROWS_NAME(json::parser("-0.").parse(), std::invalid_argument, + CHECK_THROWS_WITH(json::parser("-0.").parse(), "parse error - -0 is not a number"); - CHECK_THROWS_NAME(json::parser("-.").parse(), std::invalid_argument, + CHECK_THROWS_WITH(json::parser("-.").parse(), "parse error - unexpected '-'"); - CHECK_THROWS_NAME(json::parser("-:").parse(), std::invalid_argument, + CHECK_THROWS_WITH(json::parser("-:").parse(), "parse error - unexpected '-'"); - CHECK_THROWS_NAME(json::parser("0.:").parse(), std::invalid_argument, + CHECK_THROWS_WITH(json::parser("0.:").parse(), "parse error - 0 is not a number"); - CHECK_THROWS_NAME(json::parser("e.").parse(), std::invalid_argument, + CHECK_THROWS_WITH(json::parser("e.").parse(), "parse error - unexpected 'e'"); - CHECK_THROWS_NAME(json::parser("1e.").parse(), std::invalid_argument, + CHECK_THROWS_WITH(json::parser("1e.").parse(), "parse error - unexpected 'e'; expected end of input"); - CHECK_THROWS_NAME(json::parser("1e/").parse(), std::invalid_argument, + CHECK_THROWS_WITH(json::parser("1e/").parse(), "parse error - unexpected 'e'; expected end of input"); - CHECK_THROWS_NAME(json::parser("1e:").parse(), std::invalid_argument, + CHECK_THROWS_WITH(json::parser("1e:").parse(), "parse error - unexpected 'e'; expected end of input"); - CHECK_THROWS_NAME(json::parser("1E.").parse(), std::invalid_argument, + CHECK_THROWS_WITH(json::parser("1E.").parse(), "parse error - unexpected 'E'; expected end of input"); - CHECK_THROWS_NAME(json::parser("1E/").parse(), std::invalid_argument, + CHECK_THROWS_WITH(json::parser("1E/").parse(), "parse error - unexpected 'E'; expected end of input"); - CHECK_THROWS_NAME(json::parser("1E:").parse(), std::invalid_argument, + CHECK_THROWS_WITH(json::parser("1E:").parse(), "parse error - unexpected 'E'; expected end of input"); // unexpected end of null CHECK_THROWS_AS(json::parser("n").parse(), std::invalid_argument); CHECK_THROWS_AS(json::parser("nu").parse(), std::invalid_argument); CHECK_THROWS_AS(json::parser("nul").parse(), std::invalid_argument); - CHECK_THROWS_NAME(json::parser("n").parse(), std::invalid_argument, "parse error - unexpected 'n'"); - CHECK_THROWS_NAME(json::parser("nu").parse(), std::invalid_argument, + CHECK_THROWS_WITH(json::parser("n").parse(), "parse error - unexpected 'n'"); + CHECK_THROWS_WITH(json::parser("nu").parse(), "parse error - unexpected 'n'"); - CHECK_THROWS_NAME(json::parser("nul").parse(), std::invalid_argument, + CHECK_THROWS_WITH(json::parser("nul").parse(), "parse error - unexpected 'n'"); // unexpected end of true CHECK_THROWS_AS(json::parser("t").parse(), std::invalid_argument); CHECK_THROWS_AS(json::parser("tr").parse(), std::invalid_argument); CHECK_THROWS_AS(json::parser("tru").parse(), std::invalid_argument); - CHECK_THROWS_NAME(json::parser("t").parse(), std::invalid_argument, "parse error - unexpected 't'"); - CHECK_THROWS_NAME(json::parser("tr").parse(), std::invalid_argument, + CHECK_THROWS_WITH(json::parser("t").parse(), "parse error - unexpected 't'"); + CHECK_THROWS_WITH(json::parser("tr").parse(), "parse error - unexpected 't'"); - CHECK_THROWS_NAME(json::parser("tru").parse(), std::invalid_argument, + CHECK_THROWS_WITH(json::parser("tru").parse(), "parse error - unexpected 't'"); // unexpected end of false @@ -9028,12 +8959,12 @@ TEST_CASE("parser class") CHECK_THROWS_AS(json::parser("fa").parse(), std::invalid_argument); CHECK_THROWS_AS(json::parser("fal").parse(), std::invalid_argument); CHECK_THROWS_AS(json::parser("fals").parse(), std::invalid_argument); - CHECK_THROWS_NAME(json::parser("f").parse(), std::invalid_argument, "parse error - unexpected 'f'"); - CHECK_THROWS_NAME(json::parser("fa").parse(), std::invalid_argument, + CHECK_THROWS_WITH(json::parser("f").parse(), "parse error - unexpected 'f'"); + CHECK_THROWS_WITH(json::parser("fa").parse(), "parse error - unexpected 'f'"); - CHECK_THROWS_NAME(json::parser("fal").parse(), std::invalid_argument, + CHECK_THROWS_WITH(json::parser("fal").parse(), "parse error - unexpected 'f'"); - CHECK_THROWS_NAME(json::parser("fals").parse(), std::invalid_argument, + CHECK_THROWS_WITH(json::parser("fals").parse(), "parse error - unexpected 'f'"); // missing/unexpected end of array @@ -9042,15 +8973,15 @@ TEST_CASE("parser class") CHECK_THROWS_AS(json::parser("[1,").parse(), std::invalid_argument); CHECK_THROWS_AS(json::parser("[1,]").parse(), std::invalid_argument); CHECK_THROWS_AS(json::parser("]").parse(), std::invalid_argument); - CHECK_THROWS_NAME(json::parser("[").parse(), std::invalid_argument, + CHECK_THROWS_WITH(json::parser("[").parse(), "parse error - unexpected end of input"); - CHECK_THROWS_NAME(json::parser("[1").parse(), std::invalid_argument, + CHECK_THROWS_WITH(json::parser("[1").parse(), "parse error - unexpected end of input; expected ']'"); - CHECK_THROWS_NAME(json::parser("[1,").parse(), std::invalid_argument, + CHECK_THROWS_WITH(json::parser("[1,").parse(), "parse error - unexpected end of input"); - CHECK_THROWS_NAME(json::parser("[1,]").parse(), std::invalid_argument, + CHECK_THROWS_WITH(json::parser("[1,]").parse(), "parse error - unexpected ']'"); - CHECK_THROWS_NAME(json::parser("]").parse(), std::invalid_argument, "parse error - unexpected ']'"); + CHECK_THROWS_WITH(json::parser("]").parse(), "parse error - unexpected ']'"); // missing/unexpected end of object CHECK_THROWS_AS(json::parser("{").parse(), std::invalid_argument); @@ -9059,17 +8990,17 @@ TEST_CASE("parser class") CHECK_THROWS_AS(json::parser("{\"foo\":}").parse(), std::invalid_argument); CHECK_THROWS_AS(json::parser("{\"foo\":1,}").parse(), std::invalid_argument); CHECK_THROWS_AS(json::parser("}").parse(), std::invalid_argument); - CHECK_THROWS_NAME(json::parser("{").parse(), std::invalid_argument, + CHECK_THROWS_WITH(json::parser("{").parse(), "parse error - unexpected end of input; expected string literal"); - CHECK_THROWS_NAME(json::parser("{\"foo\"").parse(), std::invalid_argument, + CHECK_THROWS_WITH(json::parser("{\"foo\"").parse(), "parse error - unexpected end of input; expected ':'"); - CHECK_THROWS_NAME(json::parser("{\"foo\":").parse(), std::invalid_argument, + CHECK_THROWS_WITH(json::parser("{\"foo\":").parse(), "parse error - unexpected end of input"); - CHECK_THROWS_NAME(json::parser("{\"foo\":}").parse(), std::invalid_argument, + CHECK_THROWS_WITH(json::parser("{\"foo\":}").parse(), "parse error - unexpected '}'"); - CHECK_THROWS_NAME(json::parser("{\"foo\":1,}").parse(), std::invalid_argument, + CHECK_THROWS_WITH(json::parser("{\"foo\":1,}").parse(), "parse error - unexpected '}'; expected string literal"); - CHECK_THROWS_NAME(json::parser("}").parse(), std::invalid_argument, "parse error - unexpected '}'"); + CHECK_THROWS_WITH(json::parser("}").parse(), "parse error - unexpected '}'"); // missing/unexpected end of string CHECK_THROWS_AS(json::parser("\"").parse(), std::invalid_argument); @@ -9078,17 +9009,17 @@ TEST_CASE("parser class") CHECK_THROWS_AS(json::parser("\"\\u0\"").parse(), std::invalid_argument); CHECK_THROWS_AS(json::parser("\"\\u01\"").parse(), std::invalid_argument); CHECK_THROWS_AS(json::parser("\"\\u012\"").parse(), std::invalid_argument); - CHECK_THROWS_NAME(json::parser("\"").parse(), std::invalid_argument, + CHECK_THROWS_WITH(json::parser("\"").parse(), "parse error - unexpected '\"'"); - CHECK_THROWS_NAME(json::parser("\"\\\"").parse(), std::invalid_argument, + CHECK_THROWS_WITH(json::parser("\"\\\"").parse(), "parse error - unexpected '\"'"); - CHECK_THROWS_NAME(json::parser("\"\\u\"").parse(), std::invalid_argument, + CHECK_THROWS_WITH(json::parser("\"\\u\"").parse(), "parse error - unexpected '\"'"); - CHECK_THROWS_NAME(json::parser("\"\\u0\"").parse(), std::invalid_argument, + CHECK_THROWS_WITH(json::parser("\"\\u0\"").parse(), "parse error - unexpected '\"'"); - CHECK_THROWS_NAME(json::parser("\"\\u01\"").parse(), std::invalid_argument, + CHECK_THROWS_WITH(json::parser("\"\\u01\"").parse(), "parse error - unexpected '\"'"); - CHECK_THROWS_NAME(json::parser("\"\\u012\"").parse(), std::invalid_argument, + CHECK_THROWS_WITH(json::parser("\"\\u012\"").parse(), "parse error - unexpected '\"'"); // invalid escapes @@ -9122,7 +9053,7 @@ TEST_CASE("parser class") default: { CHECK_THROWS_AS(json::parser(s).parse(), std::invalid_argument); - CHECK_THROWS_NAME(json::parser(s).parse(), std::invalid_argument, "parse error - unexpected '\"'"); + CHECK_THROWS_WITH(json::parser(s).parse(), "parse error - unexpected '\"'"); break; } } @@ -9192,26 +9123,26 @@ TEST_CASE("parser class") CHECK_THROWS_AS(json::parser(s3).parse(), std::invalid_argument); CHECK_THROWS_AS(json::parser(s4).parse(), std::invalid_argument); - CHECK_THROWS_NAME(json::parser(s1).parse(), std::invalid_argument, "parse error - unexpected '\"'"); - CHECK_THROWS_NAME(json::parser(s2).parse(), std::invalid_argument, "parse error - unexpected '\"'"); - CHECK_THROWS_NAME(json::parser(s3).parse(), std::invalid_argument, "parse error - unexpected '\"'"); - CHECK_THROWS_NAME(json::parser(s4).parse(), std::invalid_argument, "parse error - unexpected '\"'"); + CHECK_THROWS_WITH(json::parser(s1).parse(), "parse error - unexpected '\"'"); + CHECK_THROWS_WITH(json::parser(s2).parse(), "parse error - unexpected '\"'"); + CHECK_THROWS_WITH(json::parser(s3).parse(), "parse error - unexpected '\"'"); + CHECK_THROWS_WITH(json::parser(s4).parse(), "parse error - unexpected '\"'"); } } } // missing part of a surrogate pair CHECK_THROWS_AS(json::parse("\"\\uD80C\""), std::invalid_argument); - CHECK_THROWS_NAME(json::parse("\"\\uD80C\""), std::invalid_argument, "missing low surrogate"); + CHECK_THROWS_WITH(json::parse("\"\\uD80C\""), "missing low surrogate"); // invalid surrogate pair CHECK_THROWS_AS(json::parse("\"\\uD80C\\uD80C\""), std::invalid_argument); CHECK_THROWS_AS(json::parse("\"\\uD80C\\u0000\""), std::invalid_argument); CHECK_THROWS_AS(json::parse("\"\\uD80C\\uFFFF\""), std::invalid_argument); - CHECK_THROWS_NAME(json::parse("\"\\uD80C\\uD80C\""), std::invalid_argument, + CHECK_THROWS_WITH(json::parse("\"\\uD80C\\uD80C\""), "missing or wrong low surrogate"); - CHECK_THROWS_NAME(json::parse("\"\\uD80C\\u0000\""), std::invalid_argument, + CHECK_THROWS_WITH(json::parse("\"\\uD80C\\u0000\""), "missing or wrong low surrogate"); - CHECK_THROWS_NAME(json::parse("\"\\uD80C\\uFFFF\""), std::invalid_argument, + CHECK_THROWS_WITH(json::parse("\"\\uD80C\\uFFFF\""), "missing or wrong low surrogate"); } @@ -9805,8 +9736,7 @@ TEST_CASE("algorithms") { json j({{"one", 1}, {"two", 2}}); CHECK_THROWS_AS(std::sort(j.begin(), j.end()), std::domain_error); - CHECK_THROWS_NAME(std::sort(j.begin(), j.end()), std::domain_error, - "cannot use offsets with object iterators"); + CHECK_THROWS_WITH(std::sort(j.begin(), j.end()), "cannot use offsets with object iterators"); } } From d80bbffc783556dfee460ffb6fa9952b151b29d4 Mon Sep 17 00:00:00 2001 From: Niels Date: Sun, 27 Dec 2015 17:58:36 +0100 Subject: [PATCH 38/61] minor cleanup --- src/json.hpp | 46 +++++++++++++++++++++++++++++----------------- src/json.hpp.re2c | 46 +++++++++++++++++++++++++++++----------------- 2 files changed, 58 insertions(+), 34 deletions(-) diff --git a/src/json.hpp b/src/json.hpp index 7c8be3d4e..2c4fcc6ff 100644 --- a/src/json.hpp +++ b/src/json.hpp @@ -2457,8 +2457,8 @@ class basic_json object_t, @ref string_t, @ref boolean_t, @ref number_integer_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 + @return pointer to the internally stored JSON value if the requested + pointer type @a PointerType fits to the JSON value; `nullptr` otherwise @complexity Constant. @@ -2508,8 +2508,8 @@ class basic_json object_t, @ref string_t, @ref boolean_t, @ref number_integer_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 + @return pointer to the internally stored JSON value if the requested + pointer type @a PointerType fits to the JSON value; `nullptr` otherwise @complexity Constant. @@ -3897,8 +3897,7 @@ class basic_json array | result of function array_t::size() @complexity Constant, as long as @ref array_t and @ref object_t satisfy the - Container concept; that is, their size() functions have - constant complexity. + Container concept; that is, their size() functions have constant complexity. @requirement This function satisfies the Container requirements: - The complexity is constant. @@ -3956,8 +3955,8 @@ class basic_json array | result of function array_t::max_size() @complexity Constant, as long as @ref array_t and @ref object_t satisfy the - Container concept; that is, their max_size() functions have - constant complexity. + Container concept; that is, their max_size() functions have constant + complexity. @requirement This function satisfies the Container requirements: - The complexity is constant. @@ -4216,7 +4215,8 @@ class basic_json @param[in] val element to insert @return iterator pointing to the inserted @a val. - @throw std::domain_error if called on JSON values other than arrays + @throw std::domain_error if called on JSON values other than arrays; + example: `"cannot use insert() with string"` @throw std::domain_error if @a pos is not an iterator of *this; example: `"iterator does not fit current value"` @@ -4270,7 +4270,8 @@ class basic_json @return iterator pointing to the first element inserted, or @a pos if `cnt==0` - @throw std::domain_error if called on JSON values other than arrays + @throw std::domain_error if called on JSON values other than arrays; + example: `"cannot use insert() with string"` @throw std::domain_error if @a pos is not an iterator of *this; example: `"iterator does not fit current value"` @@ -4313,7 +4314,8 @@ class basic_json @param[in] first begin of the range of elements to insert @param[in] last end of the range of elements to insert - @throw std::domain_error if called on JSON values other than arrays + @throw std::domain_error if called on JSON values other than arrays; + example: `"cannot use insert() with string"` @throw std::domain_error if @a pos is not an iterator of *this; example: `"iterator does not fit current value"` @throw std::domain_error if @a first and @a last do not belong to the same @@ -4374,9 +4376,11 @@ class basic_json the end() iterator @param[in] ilist initializer list to insert the values from - @throw std::domain_error if called on JSON values other than arrays + @throw std::domain_error if called on JSON values other than arrays; + example: `"cannot use insert() with string"` @throw std::domain_error if @a pos is not an iterator of *this; example: `"iterator does not fit current value"` + @return iterator pointing to the first element inserted, or @a pos if `ilist` is empty @@ -4445,7 +4449,8 @@ class basic_json @param[in,out] other array to exchange the contents with - @throw std::domain_error when JSON value is not an array + @throw std::domain_error when JSON value is not an array; example: `"cannot + use swap() with string"` @complexity Constant. @@ -4477,7 +4482,8 @@ class basic_json @param[in,out] other object to exchange the contents with - @throw std::domain_error when JSON value is not an object + @throw std::domain_error when JSON value is not an object; example: + `"cannot use swap() with string"` @complexity Constant. @@ -4509,7 +4515,8 @@ class basic_json @param[in,out] other string to exchange the contents with - @throw std::domain_error when JSON value is not a string + @throw std::domain_error when JSON value is not a string; example: `"cannot + use swap() with boolean"` @complexity Constant. @@ -6349,6 +6356,8 @@ class basic_json m_start = m_cursor = m_content; m_limit = m_content + s.size(); } + + /// constructor with a given stream explicit lexer(std::istream* s) noexcept : m_stream(s), m_buffer() { @@ -6361,7 +6370,7 @@ class basic_json /// default constructor lexer() = default; - // switch of unwanted functions + // switch off unwanted functions lexer(const lexer&) = delete; lexer operator=(const lexer&) = delete; @@ -6370,10 +6379,13 @@ class basic_json @param[in] codepoint1 the code point (can be high surrogate) @param[in] codepoint2 the code point (can be low surrogate or 0) + @return string representation of the code point + @throw std::out_of_range if code point is >0x10ffff; example: `"code points above 0x10FFFF are invalid"` - @throw std::invalid_argument if the low surrogate is invalid + @throw std::invalid_argument if the low surrogate is invalid; example: + `""missing or wrong low surrogate""` @see */ diff --git a/src/json.hpp.re2c b/src/json.hpp.re2c index 9ef7f3300..a5cf1db40 100644 --- a/src/json.hpp.re2c +++ b/src/json.hpp.re2c @@ -2457,8 +2457,8 @@ class basic_json object_t, @ref string_t, @ref boolean_t, @ref number_integer_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 + @return pointer to the internally stored JSON value if the requested + pointer type @a PointerType fits to the JSON value; `nullptr` otherwise @complexity Constant. @@ -2508,8 +2508,8 @@ class basic_json object_t, @ref string_t, @ref boolean_t, @ref number_integer_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 + @return pointer to the internally stored JSON value if the requested + pointer type @a PointerType fits to the JSON value; `nullptr` otherwise @complexity Constant. @@ -3897,8 +3897,7 @@ class basic_json array | result of function array_t::size() @complexity Constant, as long as @ref array_t and @ref object_t satisfy the - Container concept; that is, their size() functions have - constant complexity. + Container concept; that is, their size() functions have constant complexity. @requirement This function satisfies the Container requirements: - The complexity is constant. @@ -3956,8 +3955,8 @@ class basic_json array | result of function array_t::max_size() @complexity Constant, as long as @ref array_t and @ref object_t satisfy the - Container concept; that is, their max_size() functions have - constant complexity. + Container concept; that is, their max_size() functions have constant + complexity. @requirement This function satisfies the Container requirements: - The complexity is constant. @@ -4216,7 +4215,8 @@ class basic_json @param[in] val element to insert @return iterator pointing to the inserted @a val. - @throw std::domain_error if called on JSON values other than arrays + @throw std::domain_error if called on JSON values other than arrays; + example: `"cannot use insert() with string"` @throw std::domain_error if @a pos is not an iterator of *this; example: `"iterator does not fit current value"` @@ -4270,7 +4270,8 @@ class basic_json @return iterator pointing to the first element inserted, or @a pos if `cnt==0` - @throw std::domain_error if called on JSON values other than arrays + @throw std::domain_error if called on JSON values other than arrays; + example: `"cannot use insert() with string"` @throw std::domain_error if @a pos is not an iterator of *this; example: `"iterator does not fit current value"` @@ -4313,7 +4314,8 @@ class basic_json @param[in] first begin of the range of elements to insert @param[in] last end of the range of elements to insert - @throw std::domain_error if called on JSON values other than arrays + @throw std::domain_error if called on JSON values other than arrays; + example: `"cannot use insert() with string"` @throw std::domain_error if @a pos is not an iterator of *this; example: `"iterator does not fit current value"` @throw std::domain_error if @a first and @a last do not belong to the same @@ -4374,9 +4376,11 @@ class basic_json the end() iterator @param[in] ilist initializer list to insert the values from - @throw std::domain_error if called on JSON values other than arrays + @throw std::domain_error if called on JSON values other than arrays; + example: `"cannot use insert() with string"` @throw std::domain_error if @a pos is not an iterator of *this; example: `"iterator does not fit current value"` + @return iterator pointing to the first element inserted, or @a pos if `ilist` is empty @@ -4445,7 +4449,8 @@ class basic_json @param[in,out] other array to exchange the contents with - @throw std::domain_error when JSON value is not an array + @throw std::domain_error when JSON value is not an array; example: `"cannot + use swap() with string"` @complexity Constant. @@ -4477,7 +4482,8 @@ class basic_json @param[in,out] other object to exchange the contents with - @throw std::domain_error when JSON value is not an object + @throw std::domain_error when JSON value is not an object; example: + `"cannot use swap() with string"` @complexity Constant. @@ -4509,7 +4515,8 @@ class basic_json @param[in,out] other string to exchange the contents with - @throw std::domain_error when JSON value is not a string + @throw std::domain_error when JSON value is not a string; example: `"cannot + use swap() with boolean"` @complexity Constant. @@ -6349,6 +6356,8 @@ class basic_json m_start = m_cursor = m_content; m_limit = m_content + s.size(); } + + /// constructor with a given stream explicit lexer(std::istream* s) noexcept : m_stream(s), m_buffer() { @@ -6361,7 +6370,7 @@ class basic_json /// default constructor lexer() = default; - // switch of unwanted functions + // switch off unwanted functions lexer(const lexer&) = delete; lexer operator=(const lexer&) = delete; @@ -6370,10 +6379,13 @@ class basic_json @param[in] codepoint1 the code point (can be high surrogate) @param[in] codepoint2 the code point (can be low surrogate or 0) + @return string representation of the code point + @throw std::out_of_range if code point is >0x10ffff; example: `"code points above 0x10FFFF are invalid"` - @throw std::invalid_argument if the low surrogate is invalid + @throw std::invalid_argument if the low surrogate is invalid; example: + `""missing or wrong low surrogate""` @see */ From 80cdecaaddae07593824370360931ebb7ede0c25 Mon Sep 17 00:00:00 2001 From: Niels Date: Sun, 27 Dec 2015 18:07:21 +0100 Subject: [PATCH 39/61] fixed a cppcheck warning --- src/json.hpp | 2 +- src/json.hpp.re2c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/json.hpp b/src/json.hpp index 2c4fcc6ff..6e5f515a7 100644 --- a/src/json.hpp +++ b/src/json.hpp @@ -5501,7 +5501,7 @@ class basic_json } /// inequality operator (needed for range-based for) - bool operator!= (const iteration_proxy_internal& o) + bool operator!= (const iteration_proxy_internal& o) const { return anchor != o.anchor; } diff --git a/src/json.hpp.re2c b/src/json.hpp.re2c index a5cf1db40..09bba9cdd 100644 --- a/src/json.hpp.re2c +++ b/src/json.hpp.re2c @@ -5501,7 +5501,7 @@ class basic_json } /// inequality operator (needed for range-based for) - bool operator!= (const iteration_proxy_internal& o) + bool operator!= (const iteration_proxy_internal& o) const { return anchor != o.anchor; } From cb5581392a8b1c71c0b8208126b6943c7c1ff856 Mon Sep 17 00:00:00 2001 From: Niels Date: Mon, 28 Dec 2015 14:51:57 +0100 Subject: [PATCH 40/61] preparing 1.0.0 release --- doc/ChangeLog.md | 22 +++++ src/json.hpp | 236 +++++++++++++++++++++++----------------------- src/json.hpp.re2c | 236 +++++++++++++++++++++++----------------------- 3 files changed, 258 insertions(+), 236 deletions(-) diff --git a/doc/ChangeLog.md b/doc/ChangeLog.md index d6afa4f16..a43b0e1ab 100644 --- a/doc/ChangeLog.md +++ b/doc/ChangeLog.md @@ -1,5 +1,27 @@ # JSON for Modern C++ +## Version 1.0.0 + +- Release date: 2015-12-28 +- MD5: 331c30e4407ecdcf591e9e3ed85100d0 + +### Summary + +This is the first official release. Compared to the [prerelease version 1.0.0-rc1](https://github.com/nlohmann/json/releases/tag/v1.0.0-rc1), only a few minor improvements have been made: + +### Changes + +- *Changed*: A **UTF-8 byte order mark** is silently ignored. +- *Changed*: `sprintf` is no longer used. +- *Changed*: `iterator_wrapper` also works for const objects; note: the name may change! +- *Changed*: **Error messages** during deserialization have been improved. +- *Added*: The `parse` function now also works with type `std::istream&&`. +- *Added*: Function `value(key, default_value)` returns either a copy of an object's element at the specified key or a given default value if no element with the key exists. +- *Added*: Public functions are tagged with the version they were introduced. This shall allow for better **versioning** in the future. +- *Added*: All public functions and types are **documented** (see http://nlohmann.github.io/json/) including executable examples. +- *Added*: Allocation of all types (in particular arrays, strings, and objects) is now exception-safe. +- *Added*: They descriptions of thrown exceptions have been overworked and are part of the tests suite and documentation. + ## Version 1.0.0-rc1 - Release date: 2015-07-26 diff --git a/src/json.hpp b/src/json.hpp index 6e5f515a7..4b6b87908 100644 --- a/src/json.hpp +++ b/src/json.hpp @@ -32,7 +32,7 @@ Class @ref nlohmann::basic_json is a good entry point for the documentation. @author [Niels Lohmann](http://nlohmann.me) @see https://github.com/nlohmann/json to download the source code -@version 1.0 +@version 1.0.0 */ #ifndef NLOHMANN_JSON_HPP @@ -73,7 +73,7 @@ Class @ref nlohmann::basic_json is a good entry point for the documentation. /*! @brief namespace for Niels Lohmann @see https://github.com/nlohmann -@since version 1.0 +@since version 1.0.0 */ namespace nlohmann { @@ -81,7 +81,7 @@ namespace nlohmann /*! @brief unnamed namespace with internal helper functions -@since version 1.0 +@since version 1.0.0 */ namespace { @@ -171,7 +171,7 @@ default) @see RFC 7159 -@since version 1.0 +@since version 1.0.0 @nosubgrouping */ @@ -331,7 +331,7 @@ class basic_json @sa @ref array_t -- type for an array value - @since version 1.0 + @since version 1.0.0 */ using object_t = ObjectType>; @@ -428,7 +428,7 @@ class basic_json for any access to string values, a pointer of type `string_t*` must be dereferenced. - @since version 1.0 + @since version 1.0.0 */ using string_t = StringType; @@ -454,7 +454,7 @@ class basic_json Boolean values are stored directly inside a @ref basic_json type. - @since version 1.0 + @since version 1.0.0 */ using boolean_t = BooleanType; @@ -522,7 +522,7 @@ class basic_json @sa @ref number_float_t -- type for number values (floating-point) - @since version 1.0 + @since version 1.0.0 */ using number_integer_t = NumberIntegerType; @@ -587,7 +587,7 @@ class basic_json @sa @ref number_integer_t -- type for number values (integer) - @since version 1.0 + @since version 1.0.0 */ using number_float_t = NumberFloatType; @@ -606,7 +606,7 @@ class basic_json is_object(), @ref is_array(), @ref is_string(), @ref is_boolean(), @ref is_number(), and @ref is_discarded() rely on it. - @since version 1.0 + @since version 1.0.0 */ enum class value_t : uint8_t { @@ -645,7 +645,7 @@ class basic_json The actual storage for a JSON value of the @ref basic_json class. - @since version 1.0 + @since version 1.0.0 */ union json_value { @@ -749,7 +749,7 @@ class basic_json This enumeration lists the parser events that can trigger calling a callback function of type @ref parser_callback_t during parsing. - @since version 1.0 + @since version 1.0.0 */ enum class parse_event_t : uint8_t { @@ -814,7 +814,7 @@ class basic_json @sa @ref parse(std::istream&, parser_callback_t) or @ref parse(const string_t&, parser_callback_t) for examples - @since version 1.0 + @since version 1.0.0 */ using parser_callback_t = std::function; @@ -861,7 +861,7 @@ class basic_json @sa @ref basic_json(const number_integer_t) -- create a number (integer) value - @since version 1.0 + @since version 1.0.0 */ basic_json(const value_t value_type) : m_type(value_type), m_value(value_type) @@ -884,7 +884,7 @@ class basic_json @sa @ref basic_json(std::nullptr_t) -- create a `null` value - @since version 1.0 + @since version 1.0.0 */ basic_json() noexcept = default; @@ -905,7 +905,7 @@ class basic_json @sa @ref basic_json() -- default constructor (implicitly creating a `null` value) - @since version 1.0 + @since version 1.0.0 */ basic_json(std::nullptr_t) noexcept : basic_json(value_t::null) @@ -928,7 +928,7 @@ class basic_json @sa @ref basic_json(const CompatibleObjectType&) -- create an object value from a compatible STL container - @since version 1.0 + @since version 1.0.0 */ basic_json(const object_t& val) : m_type(value_t::object), m_value(val) @@ -955,7 +955,7 @@ class basic_json @sa @ref basic_json(const object_t&) -- create an object value - @since version 1.0 + @since version 1.0.0 */ template ) -- create a JSON object value from an initializer list - @since version 1.0 + @since version 1.0.0 */ basic_json(std::initializer_list init, bool type_deduction = true, @@ -1462,7 +1462,7 @@ class basic_json @sa @ref object(std::initializer_list) -- create a JSON object value from an initializer list - @since version 1.0 + @since version 1.0.0 */ static basic_json array(std::initializer_list init = std::initializer_list()) @@ -1502,7 +1502,7 @@ class basic_json @sa @ref array(std::initializer_list) -- create a JSON array value from an initializer list - @since version 1.0 + @since version 1.0.0 */ static basic_json object(std::initializer_list init = std::initializer_list()) @@ -1526,7 +1526,7 @@ class basic_json basic_json(size_type\, const basic_json&) constructor.,basic_json__size_type_basic_json} - @since version 1.0 + @since version 1.0.0 */ basic_json(size_type cnt, const basic_json& val) : m_type(value_t::array) @@ -1566,7 +1566,7 @@ class basic_json @liveexample{The example below shows several ways to create JSON values by specifying a subrange with iterators.,basic_json__InputIt_InputIt} - @since version 1.0 + @since version 1.0.0 */ template ::value and @@ -1792,7 +1792,7 @@ class basic_json - The complexity is linear. - All stored elements are destroyed and all memory is freed. - @since version 1.0 + @since version 1.0.0 */ ~basic_json() { @@ -1861,7 +1861,7 @@ class basic_json @see https://docs.python.org/2/library/json.html#json.dump - @since version 1.0 + @since version 1.0.0 */ string_t dump(const int indent = -1) const { @@ -1892,7 +1892,7 @@ class basic_json @liveexample{The following code exemplifies @ref type() for all JSON types.,type} - @since version 1.0 + @since version 1.0.0 */ value_t type() const noexcept { @@ -1913,7 +1913,7 @@ class basic_json @liveexample{The following code exemplifies @ref is_primitive for all JSON types.,is_primitive} - @since version 1.0 + @since version 1.0.0 */ bool is_primitive() const noexcept { @@ -1933,7 +1933,7 @@ class basic_json @liveexample{The following code exemplifies @ref is_structured for all JSON types.,is_structured} - @since version 1.0 + @since version 1.0.0 */ bool is_structured() const noexcept { @@ -1952,7 +1952,7 @@ class basic_json @liveexample{The following code exemplifies @ref is_null for all JSON types.,is_null} - @since version 1.0 + @since version 1.0.0 */ bool is_null() const noexcept { @@ -1971,7 +1971,7 @@ class basic_json @liveexample{The following code exemplifies @ref is_boolean for all JSON types.,is_boolean} - @since version 1.0 + @since version 1.0.0 */ bool is_boolean() const noexcept { @@ -1995,7 +1995,7 @@ class basic_json @sa @ref is_number_integer() -- check if value is an integer number @sa @ref is_number_float() -- check if value is a floating-point number - @since version 1.0 + @since version 1.0.0 */ bool is_number() const noexcept { @@ -2018,7 +2018,7 @@ class basic_json @sa @ref is_number() -- check if value is a number @sa @ref is_number_float() -- check if value is a floating-point number - @since version 1.0 + @since version 1.0.0 */ bool is_number_integer() const noexcept { @@ -2041,7 +2041,7 @@ class basic_json @sa @ref is_number() -- check if value is number @sa @ref is_number_integer() -- check if value is an integer number - @since version 1.0 + @since version 1.0.0 */ bool is_number_float() const noexcept { @@ -2060,7 +2060,7 @@ class basic_json @liveexample{The following code exemplifies @ref is_object for all JSON types.,is_object} - @since version 1.0 + @since version 1.0.0 */ bool is_object() const noexcept { @@ -2079,7 +2079,7 @@ class basic_json @liveexample{The following code exemplifies @ref is_array for all JSON types.,is_array} - @since version 1.0 + @since version 1.0.0 */ bool is_array() const noexcept { @@ -2098,7 +2098,7 @@ class basic_json @liveexample{The following code exemplifies @ref is_string for all JSON types.,is_string} - @since version 1.0 + @since version 1.0.0 */ bool is_string() const noexcept { @@ -2122,7 +2122,7 @@ class basic_json @liveexample{The following code exemplifies @ref is_discarded for all JSON types.,is_discarded} - @since version 1.0 + @since version 1.0.0 */ bool is_discarded() const noexcept { @@ -2142,7 +2142,7 @@ class basic_json @liveexample{The following code exemplifies the value_t operator for all JSON types.,operator__value_t} - @since version 1.0 + @since version 1.0.0 */ operator value_t() const noexcept { @@ -2434,7 +2434,7 @@ class basic_json @sa @ref operator ValueType() const for implicit conversion @sa @ref get() for pointer-member access - @since version 1.0 + @since version 1.0.0 */ template`.,operator__ValueType} - @since version 1.0 + @since version 1.0.0 */ template reference operator[](const T (&key)[n]) @@ -3021,7 +3021,7 @@ class basic_json with range checking @sa @ref value() for access by value with a default value - @since version 1.0 + @since version 1.0.0 */ template const_reference operator[](const T (&key)[n]) const @@ -3083,7 +3083,7 @@ class basic_json @sa @ref operator[](const typename object_t::key_type&) for unchecked access by reference - @since version 1.0 + @since version 1.0.0 */ template ilist) { @@ -4426,7 +4426,7 @@ class basic_json @liveexample{The example below shows how JSON arrays can be swapped.,swap__reference} - @since version 1.0 + @since version 1.0.0 */ void swap(reference other) noexcept ( std::is_nothrow_move_constructible::value and @@ -4457,7 +4457,7 @@ class basic_json @liveexample{The example below shows how JSON values can be swapped.,swap__array_t} - @since version 1.0 + @since version 1.0.0 */ void swap(array_t& other) { @@ -4490,7 +4490,7 @@ class basic_json @liveexample{The example below shows how JSON values can be swapped.,swap__object_t} - @since version 1.0 + @since version 1.0.0 */ void swap(object_t& other) { @@ -4523,7 +4523,7 @@ class basic_json @liveexample{The example below shows how JSON values can be swapped.,swap__string_t} - @since version 1.0 + @since version 1.0.0 */ void swap(string_t& other) { @@ -4556,7 +4556,7 @@ class basic_json - order: null < boolean < number < object < array < string - furthermore, each type is not smaller than itself - @since version 1.0 + @since version 1.0.0 */ friend bool operator<(const value_t lhs, const value_t rhs) { @@ -4602,7 +4602,7 @@ class basic_json @liveexample{The example demonstrates comparing several JSON types.,operator__equal} - @since version 1.0 + @since version 1.0.0 */ friend bool operator==(const_reference lhs, const_reference rhs) noexcept { @@ -4660,7 +4660,7 @@ class basic_json @liveexample{The example compares several JSON types to the null pointer. ,operator__equal__nullptr_t} - @since version 1.0 + @since version 1.0.0 */ friend bool operator==(const_reference v, std::nullptr_t) noexcept { @@ -4690,7 +4690,7 @@ class basic_json @liveexample{The example demonstrates comparing several JSON types.,operator__notequal} - @since version 1.0 + @since version 1.0.0 */ friend bool operator!=(const_reference lhs, const_reference rhs) noexcept { @@ -4713,7 +4713,7 @@ class basic_json @liveexample{The example compares several JSON types to the null pointer. ,operator__notequal__nullptr_t} - @since version 1.0 + @since version 1.0.0 */ friend bool operator!=(const_reference v, std::nullptr_t) noexcept { @@ -4751,7 +4751,7 @@ class basic_json @liveexample{The example demonstrates comparing several JSON types.,operator__less} - @since version 1.0 + @since version 1.0.0 */ friend bool operator<(const_reference lhs, const_reference rhs) noexcept { @@ -4812,7 +4812,7 @@ class basic_json @liveexample{The example demonstrates comparing several JSON types.,operator__greater} - @since version 1.0 + @since version 1.0.0 */ friend bool operator<=(const_reference lhs, const_reference rhs) noexcept { @@ -4834,7 +4834,7 @@ class basic_json @liveexample{The example demonstrates comparing several JSON types.,operator__lessequal} - @since version 1.0 + @since version 1.0.0 */ friend bool operator>(const_reference lhs, const_reference rhs) noexcept { @@ -4856,7 +4856,7 @@ class basic_json @liveexample{The example demonstrates comparing several JSON types.,operator__greaterequal} - @since version 1.0 + @since version 1.0.0 */ friend bool operator>=(const_reference lhs, const_reference rhs) noexcept { @@ -4893,7 +4893,7 @@ class basic_json @liveexample{The example below shows the serialization with different parameters to `width` to adjust the indentation level.,operator_serialize} - @since version 1.0 + @since version 1.0.0 */ friend std::ostream& operator<<(std::ostream& o, const basic_json& j) { @@ -4950,7 +4950,7 @@ class basic_json @sa @ref parse(std::istream&, parser_callback_t) for a version that reads from an input stream - @since version 1.0 + @since version 1.0.0 */ static basic_json parse(const string_t& s, parser_callback_t cb = nullptr) { @@ -4979,7 +4979,7 @@ class basic_json @sa @ref parse(const string_t&, parser_callback_t) for a version that reads from a string - @since version 1.0 + @since version 1.0.0 */ static basic_json parse(std::istream& i, parser_callback_t cb = nullptr) { @@ -5015,7 +5015,7 @@ class basic_json @sa parse(std::istream&, parser_callback_t) for a variant with a parser callback function to filter values while parsing - @since version 1.0 + @since version 1.0.0 */ friend std::istream& operator<<(basic_json& j, std::istream& i) { @@ -5572,7 +5572,7 @@ class basic_json The iterator that can be moved to point (forward and backward) to any element in constant time. - @since version 1.0 + @since version 1.0.0 */ class const_iterator : public std::iterator { @@ -6074,7 +6074,7 @@ class basic_json - [OutputIterator](http://en.cppreference.com/w/cpp/concept/OutputIterator): It is possible to write to the pointed-to element. - @since version 1.0 + @since version 1.0.0 */ class iterator : public const_iterator { @@ -6213,7 +6213,7 @@ class basic_json It is possible to write to the pointed-to element (only if @a Base is @ref iterator). - @since version 1.0 + @since version 1.0.0 */ template class json_reverse_iterator : public std::reverse_iterator @@ -7806,7 +7806,7 @@ basic_json_parser_64: This type is the default specialization of the @ref basic_json class which uses the standard template types. -@since version 1.0 +@since version 1.0.0 */ using json = basic_json<>; } @@ -7822,7 +7822,7 @@ namespace std /*! @brief exchanges the values of two JSON objects -@since version 1.0 +@since version 1.0.0 */ template <> inline void swap(nlohmann::json& j1, @@ -7841,7 +7841,7 @@ struct hash /*! @brief return a hash value for a JSON object - @since version 1.0 + @since version 1.0.0 */ std::size_t operator()(const nlohmann::json& j) const { @@ -7862,7 +7862,7 @@ no parse error occurred. @param[in] s a string representation of a JSON object @return a JSON object -@since version 1.0 +@since version 1.0.0 */ inline nlohmann::json operator "" _json(const char* s, std::size_t) { diff --git a/src/json.hpp.re2c b/src/json.hpp.re2c index 09bba9cdd..0f6b0eaf4 100644 --- a/src/json.hpp.re2c +++ b/src/json.hpp.re2c @@ -32,7 +32,7 @@ Class @ref nlohmann::basic_json is a good entry point for the documentation. @author [Niels Lohmann](http://nlohmann.me) @see https://github.com/nlohmann/json to download the source code -@version 1.0 +@version 1.0.0 */ #ifndef NLOHMANN_JSON_HPP @@ -73,7 +73,7 @@ Class @ref nlohmann::basic_json is a good entry point for the documentation. /*! @brief namespace for Niels Lohmann @see https://github.com/nlohmann -@since version 1.0 +@since version 1.0.0 */ namespace nlohmann { @@ -81,7 +81,7 @@ namespace nlohmann /*! @brief unnamed namespace with internal helper functions -@since version 1.0 +@since version 1.0.0 */ namespace { @@ -171,7 +171,7 @@ default) @see RFC 7159 -@since version 1.0 +@since version 1.0.0 @nosubgrouping */ @@ -331,7 +331,7 @@ class basic_json @sa @ref array_t -- type for an array value - @since version 1.0 + @since version 1.0.0 */ using object_t = ObjectType>; @@ -428,7 +428,7 @@ class basic_json for any access to string values, a pointer of type `string_t*` must be dereferenced. - @since version 1.0 + @since version 1.0.0 */ using string_t = StringType; @@ -454,7 +454,7 @@ class basic_json Boolean values are stored directly inside a @ref basic_json type. - @since version 1.0 + @since version 1.0.0 */ using boolean_t = BooleanType; @@ -522,7 +522,7 @@ class basic_json @sa @ref number_float_t -- type for number values (floating-point) - @since version 1.0 + @since version 1.0.0 */ using number_integer_t = NumberIntegerType; @@ -587,7 +587,7 @@ class basic_json @sa @ref number_integer_t -- type for number values (integer) - @since version 1.0 + @since version 1.0.0 */ using number_float_t = NumberFloatType; @@ -606,7 +606,7 @@ class basic_json is_object(), @ref is_array(), @ref is_string(), @ref is_boolean(), @ref is_number(), and @ref is_discarded() rely on it. - @since version 1.0 + @since version 1.0.0 */ enum class value_t : uint8_t { @@ -645,7 +645,7 @@ class basic_json The actual storage for a JSON value of the @ref basic_json class. - @since version 1.0 + @since version 1.0.0 */ union json_value { @@ -749,7 +749,7 @@ class basic_json This enumeration lists the parser events that can trigger calling a callback function of type @ref parser_callback_t during parsing. - @since version 1.0 + @since version 1.0.0 */ enum class parse_event_t : uint8_t { @@ -814,7 +814,7 @@ class basic_json @sa @ref parse(std::istream&, parser_callback_t) or @ref parse(const string_t&, parser_callback_t) for examples - @since version 1.0 + @since version 1.0.0 */ using parser_callback_t = std::function; @@ -861,7 +861,7 @@ class basic_json @sa @ref basic_json(const number_integer_t) -- create a number (integer) value - @since version 1.0 + @since version 1.0.0 */ basic_json(const value_t value_type) : m_type(value_type), m_value(value_type) @@ -884,7 +884,7 @@ class basic_json @sa @ref basic_json(std::nullptr_t) -- create a `null` value - @since version 1.0 + @since version 1.0.0 */ basic_json() noexcept = default; @@ -905,7 +905,7 @@ class basic_json @sa @ref basic_json() -- default constructor (implicitly creating a `null` value) - @since version 1.0 + @since version 1.0.0 */ basic_json(std::nullptr_t) noexcept : basic_json(value_t::null) @@ -928,7 +928,7 @@ class basic_json @sa @ref basic_json(const CompatibleObjectType&) -- create an object value from a compatible STL container - @since version 1.0 + @since version 1.0.0 */ basic_json(const object_t& val) : m_type(value_t::object), m_value(val) @@ -955,7 +955,7 @@ class basic_json @sa @ref basic_json(const object_t&) -- create an object value - @since version 1.0 + @since version 1.0.0 */ template ) -- create a JSON object value from an initializer list - @since version 1.0 + @since version 1.0.0 */ basic_json(std::initializer_list init, bool type_deduction = true, @@ -1462,7 +1462,7 @@ class basic_json @sa @ref object(std::initializer_list) -- create a JSON object value from an initializer list - @since version 1.0 + @since version 1.0.0 */ static basic_json array(std::initializer_list init = std::initializer_list()) @@ -1502,7 +1502,7 @@ class basic_json @sa @ref array(std::initializer_list) -- create a JSON array value from an initializer list - @since version 1.0 + @since version 1.0.0 */ static basic_json object(std::initializer_list init = std::initializer_list()) @@ -1526,7 +1526,7 @@ class basic_json basic_json(size_type\, const basic_json&) constructor.,basic_json__size_type_basic_json} - @since version 1.0 + @since version 1.0.0 */ basic_json(size_type cnt, const basic_json& val) : m_type(value_t::array) @@ -1566,7 +1566,7 @@ class basic_json @liveexample{The example below shows several ways to create JSON values by specifying a subrange with iterators.,basic_json__InputIt_InputIt} - @since version 1.0 + @since version 1.0.0 */ template ::value and @@ -1792,7 +1792,7 @@ class basic_json - The complexity is linear. - All stored elements are destroyed and all memory is freed. - @since version 1.0 + @since version 1.0.0 */ ~basic_json() { @@ -1861,7 +1861,7 @@ class basic_json @see https://docs.python.org/2/library/json.html#json.dump - @since version 1.0 + @since version 1.0.0 */ string_t dump(const int indent = -1) const { @@ -1892,7 +1892,7 @@ class basic_json @liveexample{The following code exemplifies @ref type() for all JSON types.,type} - @since version 1.0 + @since version 1.0.0 */ value_t type() const noexcept { @@ -1913,7 +1913,7 @@ class basic_json @liveexample{The following code exemplifies @ref is_primitive for all JSON types.,is_primitive} - @since version 1.0 + @since version 1.0.0 */ bool is_primitive() const noexcept { @@ -1933,7 +1933,7 @@ class basic_json @liveexample{The following code exemplifies @ref is_structured for all JSON types.,is_structured} - @since version 1.0 + @since version 1.0.0 */ bool is_structured() const noexcept { @@ -1952,7 +1952,7 @@ class basic_json @liveexample{The following code exemplifies @ref is_null for all JSON types.,is_null} - @since version 1.0 + @since version 1.0.0 */ bool is_null() const noexcept { @@ -1971,7 +1971,7 @@ class basic_json @liveexample{The following code exemplifies @ref is_boolean for all JSON types.,is_boolean} - @since version 1.0 + @since version 1.0.0 */ bool is_boolean() const noexcept { @@ -1995,7 +1995,7 @@ class basic_json @sa @ref is_number_integer() -- check if value is an integer number @sa @ref is_number_float() -- check if value is a floating-point number - @since version 1.0 + @since version 1.0.0 */ bool is_number() const noexcept { @@ -2018,7 +2018,7 @@ class basic_json @sa @ref is_number() -- check if value is a number @sa @ref is_number_float() -- check if value is a floating-point number - @since version 1.0 + @since version 1.0.0 */ bool is_number_integer() const noexcept { @@ -2041,7 +2041,7 @@ class basic_json @sa @ref is_number() -- check if value is number @sa @ref is_number_integer() -- check if value is an integer number - @since version 1.0 + @since version 1.0.0 */ bool is_number_float() const noexcept { @@ -2060,7 +2060,7 @@ class basic_json @liveexample{The following code exemplifies @ref is_object for all JSON types.,is_object} - @since version 1.0 + @since version 1.0.0 */ bool is_object() const noexcept { @@ -2079,7 +2079,7 @@ class basic_json @liveexample{The following code exemplifies @ref is_array for all JSON types.,is_array} - @since version 1.0 + @since version 1.0.0 */ bool is_array() const noexcept { @@ -2098,7 +2098,7 @@ class basic_json @liveexample{The following code exemplifies @ref is_string for all JSON types.,is_string} - @since version 1.0 + @since version 1.0.0 */ bool is_string() const noexcept { @@ -2122,7 +2122,7 @@ class basic_json @liveexample{The following code exemplifies @ref is_discarded for all JSON types.,is_discarded} - @since version 1.0 + @since version 1.0.0 */ bool is_discarded() const noexcept { @@ -2142,7 +2142,7 @@ class basic_json @liveexample{The following code exemplifies the value_t operator for all JSON types.,operator__value_t} - @since version 1.0 + @since version 1.0.0 */ operator value_t() const noexcept { @@ -2434,7 +2434,7 @@ class basic_json @sa @ref operator ValueType() const for implicit conversion @sa @ref get() for pointer-member access - @since version 1.0 + @since version 1.0.0 */ template`.,operator__ValueType} - @since version 1.0 + @since version 1.0.0 */ template reference operator[](const T (&key)[n]) @@ -3021,7 +3021,7 @@ class basic_json with range checking @sa @ref value() for access by value with a default value - @since version 1.0 + @since version 1.0.0 */ template const_reference operator[](const T (&key)[n]) const @@ -3083,7 +3083,7 @@ class basic_json @sa @ref operator[](const typename object_t::key_type&) for unchecked access by reference - @since version 1.0 + @since version 1.0.0 */ template ilist) { @@ -4426,7 +4426,7 @@ class basic_json @liveexample{The example below shows how JSON arrays can be swapped.,swap__reference} - @since version 1.0 + @since version 1.0.0 */ void swap(reference other) noexcept ( std::is_nothrow_move_constructible::value and @@ -4457,7 +4457,7 @@ class basic_json @liveexample{The example below shows how JSON values can be swapped.,swap__array_t} - @since version 1.0 + @since version 1.0.0 */ void swap(array_t& other) { @@ -4490,7 +4490,7 @@ class basic_json @liveexample{The example below shows how JSON values can be swapped.,swap__object_t} - @since version 1.0 + @since version 1.0.0 */ void swap(object_t& other) { @@ -4523,7 +4523,7 @@ class basic_json @liveexample{The example below shows how JSON values can be swapped.,swap__string_t} - @since version 1.0 + @since version 1.0.0 */ void swap(string_t& other) { @@ -4556,7 +4556,7 @@ class basic_json - order: null < boolean < number < object < array < string - furthermore, each type is not smaller than itself - @since version 1.0 + @since version 1.0.0 */ friend bool operator<(const value_t lhs, const value_t rhs) { @@ -4602,7 +4602,7 @@ class basic_json @liveexample{The example demonstrates comparing several JSON types.,operator__equal} - @since version 1.0 + @since version 1.0.0 */ friend bool operator==(const_reference lhs, const_reference rhs) noexcept { @@ -4660,7 +4660,7 @@ class basic_json @liveexample{The example compares several JSON types to the null pointer. ,operator__equal__nullptr_t} - @since version 1.0 + @since version 1.0.0 */ friend bool operator==(const_reference v, std::nullptr_t) noexcept { @@ -4690,7 +4690,7 @@ class basic_json @liveexample{The example demonstrates comparing several JSON types.,operator__notequal} - @since version 1.0 + @since version 1.0.0 */ friend bool operator!=(const_reference lhs, const_reference rhs) noexcept { @@ -4713,7 +4713,7 @@ class basic_json @liveexample{The example compares several JSON types to the null pointer. ,operator__notequal__nullptr_t} - @since version 1.0 + @since version 1.0.0 */ friend bool operator!=(const_reference v, std::nullptr_t) noexcept { @@ -4751,7 +4751,7 @@ class basic_json @liveexample{The example demonstrates comparing several JSON types.,operator__less} - @since version 1.0 + @since version 1.0.0 */ friend bool operator<(const_reference lhs, const_reference rhs) noexcept { @@ -4812,7 +4812,7 @@ class basic_json @liveexample{The example demonstrates comparing several JSON types.,operator__greater} - @since version 1.0 + @since version 1.0.0 */ friend bool operator<=(const_reference lhs, const_reference rhs) noexcept { @@ -4834,7 +4834,7 @@ class basic_json @liveexample{The example demonstrates comparing several JSON types.,operator__lessequal} - @since version 1.0 + @since version 1.0.0 */ friend bool operator>(const_reference lhs, const_reference rhs) noexcept { @@ -4856,7 +4856,7 @@ class basic_json @liveexample{The example demonstrates comparing several JSON types.,operator__greaterequal} - @since version 1.0 + @since version 1.0.0 */ friend bool operator>=(const_reference lhs, const_reference rhs) noexcept { @@ -4893,7 +4893,7 @@ class basic_json @liveexample{The example below shows the serialization with different parameters to `width` to adjust the indentation level.,operator_serialize} - @since version 1.0 + @since version 1.0.0 */ friend std::ostream& operator<<(std::ostream& o, const basic_json& j) { @@ -4950,7 +4950,7 @@ class basic_json @sa @ref parse(std::istream&, parser_callback_t) for a version that reads from an input stream - @since version 1.0 + @since version 1.0.0 */ static basic_json parse(const string_t& s, parser_callback_t cb = nullptr) { @@ -4979,7 +4979,7 @@ class basic_json @sa @ref parse(const string_t&, parser_callback_t) for a version that reads from a string - @since version 1.0 + @since version 1.0.0 */ static basic_json parse(std::istream& i, parser_callback_t cb = nullptr) { @@ -5015,7 +5015,7 @@ class basic_json @sa parse(std::istream&, parser_callback_t) for a variant with a parser callback function to filter values while parsing - @since version 1.0 + @since version 1.0.0 */ friend std::istream& operator<<(basic_json& j, std::istream& i) { @@ -5572,7 +5572,7 @@ class basic_json The iterator that can be moved to point (forward and backward) to any element in constant time. - @since version 1.0 + @since version 1.0.0 */ class const_iterator : public std::iterator { @@ -6074,7 +6074,7 @@ class basic_json - [OutputIterator](http://en.cppreference.com/w/cpp/concept/OutputIterator): It is possible to write to the pointed-to element. - @since version 1.0 + @since version 1.0.0 */ class iterator : public const_iterator { @@ -6213,7 +6213,7 @@ class basic_json It is possible to write to the pointed-to element (only if @a Base is @ref iterator). - @since version 1.0 + @since version 1.0.0 */ template class json_reverse_iterator : public std::reverse_iterator @@ -7085,7 +7085,7 @@ class basic_json This type is the default specialization of the @ref basic_json class which uses the standard template types. -@since version 1.0 +@since version 1.0.0 */ using json = basic_json<>; } @@ -7101,7 +7101,7 @@ namespace std /*! @brief exchanges the values of two JSON objects -@since version 1.0 +@since version 1.0.0 */ template <> inline void swap(nlohmann::json& j1, @@ -7120,7 +7120,7 @@ struct hash /*! @brief return a hash value for a JSON object - @since version 1.0 + @since version 1.0.0 */ std::size_t operator()(const nlohmann::json& j) const { @@ -7141,7 +7141,7 @@ no parse error occurred. @param[in] s a string representation of a JSON object @return a JSON object -@since version 1.0 +@since version 1.0.0 */ inline nlohmann::json operator "" _json(const char* s, std::size_t) { From aca6a3b373b57e2b2b86f48d4195ca0e6a4b6f00 Mon Sep 17 00:00:00 2001 From: Niels Date: Mon, 28 Dec 2015 15:04:15 +0100 Subject: [PATCH 41/61] version number --- doc/Doxyfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/Doxyfile b/doc/Doxyfile index a7e5fbc67..9cca8a834 100644 --- a/doc/Doxyfile +++ b/doc/Doxyfile @@ -5,7 +5,7 @@ #--------------------------------------------------------------------------- DOXYFILE_ENCODING = UTF-8 PROJECT_NAME = "JSON for Modern C++" -PROJECT_NUMBER = 1.0.0-rc1 +PROJECT_NUMBER = 1.0.0 PROJECT_BRIEF = PROJECT_LOGO = OUTPUT_DIRECTORY = . From 3905406f9c232968b11fbb49520162517eea0d24 Mon Sep 17 00:00:00 2001 From: Niels Date: Tue, 29 Dec 2015 12:30:05 +0100 Subject: [PATCH 42/61] removed an unnecessary cast (fixed #162) --- README.md | 2 +- src/json.hpp | 3 +-- src/json.hpp.re2c | 3 +-- 3 files changed, 3 insertions(+), 5 deletions(-) diff --git a/README.md b/README.md index 8c1ea449d..91bb1e0dc 100644 --- a/README.md +++ b/README.md @@ -375,7 +375,7 @@ I deeply appreciate the help of the following people. - [Eric Cornelius](https://github.com/EricMCornelius) pointed out a bug in the handling with NaN and infinity values. He also improved the performance of the string escaping. - [易思龙](https://github.com/likebeta) implemented a conversion from anonymous enums. - [kepkin](https://github.com/kepkin) patiently pushed forward the support for Microsoft Visual studio. -- [gregmarr](https://github.com/gregmarr) simplified the implementation of reverse iterators. +- [gregmarr](https://github.com/gregmarr) simplified the implementation of reverse iterators and helped with numerous hints and improvements. - [Caio Luppi](https://github.com/caiovlp) fixed a bug in the Unicode handling. - [dariomt](https://github.com/dariomt) fixed some typos in the examples. - [Daniel Frey](https://github.com/d-frey) cleaned up some pointers and implemented exception-safe memory allocation. diff --git a/src/json.hpp b/src/json.hpp index 4b6b87908..82fa3b24f 100644 --- a/src/json.hpp +++ b/src/json.hpp @@ -7866,8 +7866,7 @@ no parse error occurred. */ inline nlohmann::json operator "" _json(const char* s, std::size_t) { - return nlohmann::json::parse(reinterpret_cast - (const_cast(s))); + return nlohmann::json::parse(reinterpret_cast(s)); } #endif diff --git a/src/json.hpp.re2c b/src/json.hpp.re2c index 0f6b0eaf4..0dfa6737b 100644 --- a/src/json.hpp.re2c +++ b/src/json.hpp.re2c @@ -7145,8 +7145,7 @@ no parse error occurred. */ inline nlohmann::json operator "" _json(const char* s, std::size_t) { - return nlohmann::json::parse(reinterpret_cast - (const_cast(s))); + return nlohmann::json::parse(reinterpret_cast(s)); } #endif From 9b07504e2305b81331712b8b4c5b0df9c7dede6a Mon Sep 17 00:00:00 2001 From: Niels Date: Fri, 1 Jan 2016 18:33:58 +0100 Subject: [PATCH 43/61] fix for #166 --- README.md | 1 + src/json.hpp | 4 ++-- src/json.hpp.re2c | 4 ++-- 3 files changed, 5 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index 91bb1e0dc..fff191bec 100644 --- a/README.md +++ b/README.md @@ -386,6 +386,7 @@ I deeply appreciate the help of the following people. - [ZahlGraf](https://github.com/ZahlGraf) added a workaround that allows compilation using Android NDK. - [whackashoe](https://github.com/whackashoe) replaced a function that was marked as unsafe by Visual Studio. - [406345](https://github.com/406345) fixed two small warnings. +- [Glen Fernandes](https://github.com/glenfe) noted a potential portability problem in the `has_mapped_type` function. Thanks a lot for helping out! diff --git a/src/json.hpp b/src/json.hpp index 82fa3b24f..c9fe4ebc5 100644 --- a/src/json.hpp +++ b/src/json.hpp @@ -94,9 +94,9 @@ struct has_mapped_type { private: template static char test(typename C::mapped_type*); - template static int test(...); + template static char (&test(...))[2]; public: - enum { value = sizeof(test(0)) == sizeof(char) }; + static constexpr bool value = sizeof(test(0)) == 1; }; /// "equality" comparison for floating point numbers diff --git a/src/json.hpp.re2c b/src/json.hpp.re2c index 0dfa6737b..d9d696aef 100644 --- a/src/json.hpp.re2c +++ b/src/json.hpp.re2c @@ -94,9 +94,9 @@ struct has_mapped_type { private: template static char test(typename C::mapped_type*); - template static int test(...); + template static char (&test(...))[2]; public: - enum { value = sizeof(test(0)) == sizeof(char) }; + static constexpr bool value = sizeof(test(0)) == 1; }; /// "equality" comparison for floating point numbers From 7614aa31c0f8807758655b492f09ec9586aa89db Mon Sep 17 00:00:00 2001 From: Niels Date: Sat, 2 Jan 2016 13:07:22 +0100 Subject: [PATCH 44/61] cleanup --- .travis.yml | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/.travis.yml b/.travis.yml index 62330af82..36fe5ba7e 100644 --- a/.travis.yml +++ b/.travis.yml @@ -13,6 +13,12 @@ matrix: packages: ['g++-4.9', 'valgrind', 'python-pip', 'python-yaml'] before_script: - pip install --user git+git://github.com/eddyxu/cpp-coveralls.git + after_success: + - make clean + - touch src/json.hpp + - make json_unit CXXFLAGS="-fprofile-arcs -ftest-coverage -std=c++11 -lstdc++" CXX=$COMPILER + - ./json_unit "*" + - coveralls --exclude test/catch.hpp --exclude test/unit.cpp --include src/json.hpp --gcov-options '\-lp' --gcov 'gcov-4.9' env: COMPILER=g++-4.9 - os: linux @@ -35,10 +41,3 @@ script: - make CXX=$COMPILER CXXFLAGS="-lstdc++" - ./json_unit "*" - valgrind --error-exitcode=1 --leak-check=full ./json_unit - -after_success: - - if [ "$COMPILER" = "g++-4.9" ]; then make clean ; fi - - if [ "$COMPILER" = "g++-4.9" ]; then touch src/json.hpp ; fi - - if [ "$COMPILER" = "g++-4.9" ]; then make json_unit CXXFLAGS="-fprofile-arcs -ftest-coverage -std=c++11 -lstdc++" CXX=$COMPILER ; fi - - if [ "$COMPILER" = "g++-4.9" ]; then ./json_unit "*" ; fi - - if [ "$COMPILER" = "g++-4.9" ]; then coveralls --exclude test/catch.hpp --exclude test/unit.cpp --include src/json.hpp --gcov-options '\-lp' --gcov 'gcov-4.9' ; fi From dbf58ae9c0e574c517516228601ff0dae23fbe96 Mon Sep 17 00:00:00 2001 From: Niels Date: Sat, 2 Jan 2016 15:24:13 +0100 Subject: [PATCH 45/61] trying to add Clang 3.7 toolchain --- .travis.yml | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/.travis.yml b/.travis.yml index 36fe5ba7e..605073fc5 100644 --- a/.travis.yml +++ b/.travis.yml @@ -37,6 +37,14 @@ matrix: packages: ['clang-3.6', 'valgrind'] env: COMPILER=clang++-3.6 + - os: linux + compiler: clang + addons: + apt: + sources: ['ubuntu-toolchain-r-test', 'llvm-toolchain-precise'] + packages: ['clang-3.7', 'valgrind'] + env: COMPILER=clang++-3.7 + script: - make CXX=$COMPILER CXXFLAGS="-lstdc++" - ./json_unit "*" From 33abe87407711dd1e367a823ba146cf5cd9a387a Mon Sep 17 00:00:00 2001 From: Niels Date: Sat, 2 Jan 2016 15:30:12 +0100 Subject: [PATCH 46/61] forgot version number --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 605073fc5..816e6e0c4 100644 --- a/.travis.yml +++ b/.travis.yml @@ -41,7 +41,7 @@ matrix: compiler: clang addons: apt: - sources: ['ubuntu-toolchain-r-test', 'llvm-toolchain-precise'] + sources: ['ubuntu-toolchain-r-test', 'llvm-toolchain-precise-3.7'] packages: ['clang-3.7', 'valgrind'] env: COMPILER=clang++-3.7 From 4a87ed4441ffe319b9f93889a3aa32d99fd625c6 Mon Sep 17 00:00:00 2001 From: Niels Date: Sat, 2 Jan 2016 15:34:34 +0100 Subject: [PATCH 47/61] trying Clang 3.8 --- .travis.yml | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/.travis.yml b/.travis.yml index 816e6e0c4..37c68c73c 100644 --- a/.travis.yml +++ b/.travis.yml @@ -45,6 +45,14 @@ matrix: packages: ['clang-3.7', 'valgrind'] env: COMPILER=clang++-3.7 + - os: linux + compiler: clang + addons: + apt: + sources: ['ubuntu-toolchain-r-test', 'llvm-toolchain-precise-3.8'] + packages: ['clang-3.8', 'valgrind'] + env: COMPILER=clang++-3.8 + script: - make CXX=$COMPILER CXXFLAGS="-lstdc++" - ./json_unit "*" From b4bb3afb6541899ddc9a965c0620768b01dd887c Mon Sep 17 00:00:00 2001 From: Niels Date: Sat, 2 Jan 2016 15:42:56 +0100 Subject: [PATCH 48/61] removed clang 3.8 --- .travis.yml | 8 -------- 1 file changed, 8 deletions(-) diff --git a/.travis.yml b/.travis.yml index 37c68c73c..816e6e0c4 100644 --- a/.travis.yml +++ b/.travis.yml @@ -45,14 +45,6 @@ matrix: packages: ['clang-3.7', 'valgrind'] env: COMPILER=clang++-3.7 - - os: linux - compiler: clang - addons: - apt: - sources: ['ubuntu-toolchain-r-test', 'llvm-toolchain-precise-3.8'] - packages: ['clang-3.8', 'valgrind'] - env: COMPILER=clang++-3.8 - script: - make CXX=$COMPILER CXXFLAGS="-lstdc++" - ./json_unit "*" From 2d48a36f5cda4b60a28ce2b039cb9d0d0c08d1d7 Mon Sep 17 00:00:00 2001 From: Niels Date: Sat, 2 Jan 2016 16:37:40 +0100 Subject: [PATCH 49/61] trying Travis and OSX --- .travis.yml | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/.travis.yml b/.travis.yml index 816e6e0c4..360e690b4 100644 --- a/.travis.yml +++ b/.travis.yml @@ -44,6 +44,13 @@ matrix: sources: ['ubuntu-toolchain-r-test', 'llvm-toolchain-precise-3.7'] packages: ['clang-3.7', 'valgrind'] env: COMPILER=clang++-3.7 + + - os: osx + compiler: clang + env: COMPILER=clang + before_install: + - brew update + - brew install valgrind script: - make CXX=$COMPILER CXXFLAGS="-lstdc++" From fb7ff414adb53971f51470537a7a3405d25ce5c4 Mon Sep 17 00:00:00 2001 From: Niels Date: Sat, 2 Jan 2016 16:42:45 +0100 Subject: [PATCH 50/61] more Valgrind information --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 360e690b4..21aade658 100644 --- a/.travis.yml +++ b/.travis.yml @@ -55,4 +55,4 @@ matrix: script: - make CXX=$COMPILER CXXFLAGS="-lstdc++" - ./json_unit "*" - - valgrind --error-exitcode=1 --leak-check=full ./json_unit + - valgrind --error-exitcode=1 --leak-check=full --show-leak-kinds=all ./json_unit From d27c8a8ea84dddad50a88caf8361b57528cf6af9 Mon Sep 17 00:00:00 2001 From: Niels Date: Sat, 2 Jan 2016 16:49:56 +0100 Subject: [PATCH 51/61] reverting OSX --- .travis.yml | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/.travis.yml b/.travis.yml index 21aade658..357c9e593 100644 --- a/.travis.yml +++ b/.travis.yml @@ -45,14 +45,14 @@ matrix: packages: ['clang-3.7', 'valgrind'] env: COMPILER=clang++-3.7 - - os: osx - compiler: clang - env: COMPILER=clang - before_install: - - brew update - - brew install valgrind + # - os: osx + # compiler: clang + # env: COMPILER=clang + # before_install: + # - brew update + # - brew install valgrind script: - make CXX=$COMPILER CXXFLAGS="-lstdc++" - ./json_unit "*" - - valgrind --error-exitcode=1 --leak-check=full --show-leak-kinds=all ./json_unit + - valgrind --error-exitcode=1 --leak-check=full ./json_unit From 4a452f11f9c309e8be262e7866d1a117f2283eeb Mon Sep 17 00:00:00 2001 From: Niels Date: Sun, 3 Jan 2016 17:05:27 +0100 Subject: [PATCH 52/61] added assertions (#168) --- src/json.hpp | 161 +++++++++++++++++++++++++++++++++++++++++++++- src/json.hpp.re2c | 161 +++++++++++++++++++++++++++++++++++++++++++++- 2 files changed, 318 insertions(+), 4 deletions(-) diff --git a/src/json.hpp b/src/json.hpp index c9fe4ebc5..edda8edcb 100644 --- a/src/json.hpp +++ b/src/json.hpp @@ -40,6 +40,7 @@ Class @ref nlohmann::basic_json is a good entry point for the documentation. #include #include +#include #include #include #include @@ -1417,6 +1418,8 @@ class basic_json m_type = value_t::object; m_value = value_t::object; + assert(m_value.object != nullptr); + for (auto& element : init) { m_value.object->emplace(std::move(*(element[0].m_value.string)), std::move(element[1])); @@ -1607,24 +1610,28 @@ class basic_json { case value_t::number_integer: { + assert(first.m_object != nullptr); m_value.number_integer = first.m_object->m_value.number_integer; break; } case value_t::number_float: { + assert(first.m_object != nullptr); m_value.number_float = first.m_object->m_value.number_float; break; } case value_t::boolean: { + assert(first.m_object != nullptr); m_value.boolean = first.m_object->m_value.boolean; break; } case value_t::string: { + assert(first.m_object != nullptr); m_value = *first.m_object->m_value.string; break; } @@ -1643,6 +1650,7 @@ class basic_json default: { + assert(first.m_object != nullptr); throw std::domain_error("cannot use construct with iterators from " + first.m_object->type_name()); } } @@ -1679,18 +1687,21 @@ class basic_json { case value_t::object: { + assert(other.m_value.object != nullptr); m_value = *other.m_value.object; break; } case value_t::array: { + assert(other.m_value.array != nullptr); m_value = *other.m_value.array; break; } case value_t::string: { + assert(other.m_value.string != nullptr); m_value = *other.m_value.string; break; } @@ -2166,6 +2177,7 @@ class basic_json { if (is_object()) { + assert(m_value.object != nullptr); return T(m_value.object->begin(), m_value.object->end()); } else @@ -2179,6 +2191,7 @@ class basic_json { if (is_object()) { + assert(m_value.object != nullptr); return *(m_value.object); } else @@ -2201,6 +2214,7 @@ class basic_json if (is_array()) { T to_vector; + assert(m_value.array != nullptr); std::transform(m_value.array->begin(), m_value.array->end(), std::inserter(to_vector, to_vector.end()), [](basic_json i) { @@ -2225,6 +2239,7 @@ class basic_json if (is_array()) { std::vector to_vector; + assert(m_value.array != nullptr); to_vector.reserve(m_value.array->size()); std::transform(m_value.array->begin(), m_value.array->end(), std::inserter(to_vector, to_vector.end()), [](basic_json i) @@ -2249,6 +2264,7 @@ class basic_json { if (is_array()) { + assert(m_value.array != nullptr); return T(m_value.array->begin(), m_value.array->end()); } else @@ -2262,6 +2278,7 @@ class basic_json { if (is_array()) { + assert(m_value.array != nullptr); return *(m_value.array); } else @@ -2279,6 +2296,7 @@ class basic_json { if (is_string()) { + assert(m_value.string != nullptr); return *m_value.string; } else @@ -2624,6 +2642,7 @@ class basic_json { try { + assert(m_value.array != nullptr); return m_value.array->at(idx); } catch (std::out_of_range& e) @@ -2667,6 +2686,7 @@ class basic_json { try { + assert(m_value.array != nullptr); return m_value.array->at(idx); } catch (std::out_of_range& e) @@ -2714,6 +2734,7 @@ class basic_json { try { + assert(m_value.object != nullptr); return m_value.object->at(key); } catch (std::out_of_range& e) @@ -2761,6 +2782,7 @@ class basic_json { try { + assert(m_value.object != nullptr); return m_value.object->at(key); } catch (std::out_of_range& e) @@ -2812,6 +2834,7 @@ class basic_json // [] only works for arrays if (is_array()) { + assert(m_value.array != nullptr); for (size_t i = m_value.array->size(); i <= idx; ++i) { m_value.array->push_back(basic_json()); @@ -2849,6 +2872,7 @@ class basic_json // at only works for arrays if (is_array()) { + assert(m_value.array != nullptr); return m_value.array->operator[](idx); } else @@ -2896,6 +2920,7 @@ class basic_json // [] only works for objects if (is_object()) { + assert(m_value.object != nullptr); return m_value.object->operator[](key); } else @@ -2936,6 +2961,8 @@ class basic_json // [] only works for objects if (is_object()) { + assert(m_value.object != nullptr); + assert(m_value.object->find(key) != m_value.object->end()); return m_value.object->find(key)->second; } else @@ -2986,6 +3013,7 @@ class basic_json // at only works for objects if (is_object()) { + assert(m_value.object != nullptr); return m_value.object->operator[](key); } else @@ -3029,6 +3057,8 @@ class basic_json // at only works for objects if (is_object()) { + assert(m_value.object != nullptr); + assert(m_value.object->find(key) != m_value.object->end()); return m_value.object->find(key)->second; } else @@ -3275,12 +3305,14 @@ class basic_json case value_t::object: { + assert(m_value.object != nullptr); result.m_it.object_iterator = m_value.object->erase(pos.m_it.object_iterator); break; } case value_t::array: { + assert(m_value.array != nullptr); result.m_it.array_iterator = m_value.array->erase(pos.m_it.array_iterator); break; } @@ -3378,6 +3410,7 @@ class basic_json case value_t::object: { + assert(m_value.object != nullptr); result.m_it.object_iterator = m_value.object->erase(first.m_it.object_iterator, last.m_it.object_iterator); break; @@ -3385,6 +3418,7 @@ class basic_json case value_t::array: { + assert(m_value.array != nullptr); result.m_it.array_iterator = m_value.array->erase(first.m_it.array_iterator, last.m_it.array_iterator); break; @@ -3430,6 +3464,7 @@ class basic_json // this erase only works for objects if (is_object()) { + assert(m_value.object != nullptr); return m_value.object->erase(key); } else @@ -3472,6 +3507,7 @@ class basic_json throw std::out_of_range("index out of range"); } + assert(m_value.array != nullptr); m_value.array->erase(m_value.array->begin() + static_cast(idx)); } else @@ -3503,6 +3539,7 @@ class basic_json if (is_object()) { + assert(m_value.object != nullptr); result.m_it.object_iterator = m_value.object->find(key); } @@ -3519,6 +3556,7 @@ class basic_json if (is_object()) { + assert(m_value.object != nullptr); result.m_it.object_iterator = m_value.object->find(key); } @@ -3546,6 +3584,7 @@ class basic_json size_type count(typename object_t::key_type key) const { // return 0 for all nonobject types + assert(not is_object() or m_value.object != nullptr); return is_object() ? m_value.object->count(key) : 0; } @@ -3864,11 +3903,13 @@ class basic_json case value_t::array: { + assert(m_value.array != nullptr); return m_value.array->empty(); } case value_t::object: { + assert(m_value.object != nullptr); return m_value.object->empty(); } @@ -3920,11 +3961,13 @@ class basic_json case value_t::array: { + assert(m_value.array != nullptr); return m_value.array->size(); } case value_t::object: { + assert(m_value.object != nullptr); return m_value.object->size(); } @@ -3974,11 +4017,13 @@ class basic_json { case value_t::array: { + assert(m_value.array != nullptr); return m_value.array->max_size(); } case value_t::object: { + assert(m_value.object != nullptr); return m_value.object->max_size(); } @@ -4049,18 +4094,21 @@ class basic_json case value_t::string: { + assert(m_value.string != nullptr); m_value.string->clear(); break; } case value_t::array: { + assert(m_value.array != nullptr); m_value.array->clear(); break; } case value_t::object: { + assert(m_value.object != nullptr); m_value.object->clear(); break; } @@ -4108,6 +4156,7 @@ class basic_json } // add element to array (move semantics) + assert(m_value.array != nullptr); m_value.array->push_back(std::move(val)); // invalidate object val.m_type = value_t::null; @@ -4143,6 +4192,7 @@ class basic_json } // add element to array + assert(m_value.array != nullptr); m_value.array->push_back(val); } @@ -4192,6 +4242,7 @@ class basic_json } // add element to array + assert(m_value.object != nullptr); m_value.object->insert(val); } @@ -4240,6 +4291,7 @@ class basic_json // insert to array and return iterator iterator result(this); + assert(m_value.array != nullptr); result.m_it.array_iterator = m_value.array->insert(pos.m_it.array_iterator, val); return result; } @@ -4295,6 +4347,7 @@ class basic_json // insert to array and return iterator iterator result(this); + assert(m_value.array != nullptr); result.m_it.array_iterator = m_value.array->insert(pos.m_it.array_iterator, cnt, val); return result; } @@ -4360,6 +4413,7 @@ class basic_json // insert to array and return iterator iterator result(this); + assert(m_value.array != nullptr); result.m_it.array_iterator = m_value.array->insert( pos.m_it.array_iterator, first.m_it.array_iterator, @@ -4407,6 +4461,7 @@ class basic_json // insert to array and return iterator iterator result(this); + assert(m_value.array != nullptr); result.m_it.array_iterator = m_value.array->insert(pos.m_it.array_iterator, ilist); return result; } @@ -4464,6 +4519,7 @@ class basic_json // swap only works for arrays if (is_array()) { + assert(m_value.array != nullptr); std::swap(*(m_value.array), other); } else @@ -4497,6 +4553,7 @@ class basic_json // swap only works for objects if (is_object()) { + assert(m_value.object != nullptr); std::swap(*(m_value.object), other); } else @@ -4530,6 +4587,7 @@ class basic_json // swap only works for strings if (is_string()) { + assert(m_value.string != nullptr); std::swap(*(m_value.string), other); } else @@ -4614,21 +4672,43 @@ class basic_json switch (lhs_type) { case value_t::array: + { + assert(lhs.m_value.array != nullptr); + assert(rhs.m_value.array != nullptr); return *lhs.m_value.array == *rhs.m_value.array; + } case value_t::object: + { + assert(lhs.m_value.object != nullptr); + assert(rhs.m_value.object != nullptr); return *lhs.m_value.object == *rhs.m_value.object; + } case value_t::null: + { return true; + } case value_t::string: + { + assert(lhs.m_value.string != nullptr); + assert(rhs.m_value.string != nullptr); return *lhs.m_value.string == *rhs.m_value.string; + } case value_t::boolean: + { return lhs.m_value.boolean == rhs.m_value.boolean; + } case value_t::number_integer: + { return lhs.m_value.number_integer == rhs.m_value.number_integer; + } case value_t::number_float: + { return approx(lhs.m_value.number_float, rhs.m_value.number_float); + } default: + { return false; + } } } else if (lhs_type == value_t::number_integer and rhs_type == value_t::number_float) @@ -4763,21 +4843,43 @@ class basic_json switch (lhs_type) { case value_t::array: + { + assert(lhs.m_value.array != nullptr); + assert(rhs.m_value.array != nullptr); return *lhs.m_value.array < *rhs.m_value.array; + } case value_t::object: + { + assert(lhs.m_value.object != nullptr); + assert(rhs.m_value.object != nullptr); return *lhs.m_value.object < *rhs.m_value.object; + } case value_t::null: + { return false; + } case value_t::string: + { + assert(lhs.m_value.string != nullptr); + assert(rhs.m_value.string != nullptr); return *lhs.m_value.string < *rhs.m_value.string; + } case value_t::boolean: + { return lhs.m_value.boolean < rhs.m_value.boolean; + } case value_t::number_integer: + { return lhs.m_value.number_integer < rhs.m_value.number_integer; + } case value_t::number_float: + { return lhs.m_value.number_float < rhs.m_value.number_float; + } default: + { return false; + } } } else if (lhs_type == value_t::number_integer and rhs_type == value_t::number_float) @@ -5254,6 +5356,8 @@ class basic_json { case value_t::object: { + assert(m_value.object != nullptr); + if (m_value.object->empty()) { o << "{}"; @@ -5294,6 +5398,8 @@ class basic_json case value_t::array: { + assert(m_value.array != nullptr); + if (m_value.array->empty()) { o << "[]"; @@ -5332,6 +5438,7 @@ class basic_json case value_t::string: { + assert(m_value.string != nullptr); o << string_t("\"") << escape_string(*m_value.string) << "\""; return; } @@ -5509,6 +5616,8 @@ class basic_json /// return key of the iterator typename basic_json::string_t key() const { + assert(anchor.m_object != nullptr); + switch (anchor.m_object->type()) { // use integer array index as key @@ -5597,6 +5706,8 @@ class basic_json /// constructor for a given JSON instance const_iterator(pointer object) : m_object(object) { + assert(m_object != nullptr); + switch (m_object->m_type) { case basic_json::value_t::object: @@ -5622,6 +5733,8 @@ class basic_json /// copy constructor given a nonconst iterator const_iterator(const iterator& other) : m_object(other.m_object) { + assert(m_object != nullptr); + switch (m_object->m_type) { case basic_json::value_t::object: @@ -5666,16 +5779,20 @@ class basic_json /// set the iterator to the first value void set_begin() { + assert(m_object != nullptr); + switch (m_object->m_type) { case basic_json::value_t::object: { + assert(m_object->m_value.object != nullptr); m_it.object_iterator = m_object->m_value.object->begin(); break; } case basic_json::value_t::array: { + assert(m_object->m_value.array != nullptr); m_it.array_iterator = m_object->m_value.array->begin(); break; } @@ -5698,16 +5815,20 @@ class basic_json /// set the iterator past the last value void set_end() { + assert(m_object != nullptr); + switch (m_object->m_type) { case basic_json::value_t::object: { + assert(m_object->m_value.object != nullptr); m_it.object_iterator = m_object->m_value.object->end(); break; } case basic_json::value_t::array: { + assert(m_object->m_value.array != nullptr); m_it.array_iterator = m_object->m_value.array->end(); break; } @@ -5724,15 +5845,21 @@ class basic_json /// return a reference to the value pointed to by the iterator reference operator*() const { + assert(m_object != nullptr); + switch (m_object->m_type) { case basic_json::value_t::object: { + assert(m_object->m_value.object); + assert(m_it.object_iterator != m_object->m_value.object->end()); return m_it.object_iterator->second; } case basic_json::value_t::array: { + assert(m_object->m_value.array); + assert(m_it.array_iterator != m_object->m_value.array->end()); return *m_it.array_iterator; } @@ -5758,15 +5885,21 @@ class basic_json /// dereference the iterator pointer operator->() const { + assert(m_object != nullptr); + switch (m_object->m_type) { case basic_json::value_t::object: { + assert(m_object->m_value.object); + assert(m_it.object_iterator != m_object->m_value.object->end()); return &(m_it.object_iterator->second); } case basic_json::value_t::array: { + assert(m_object->m_value.array); + assert(m_it.array_iterator != m_object->m_value.array->end()); return &*m_it.array_iterator; } @@ -5795,6 +5928,8 @@ class basic_json /// pre-increment (++it) const_iterator& operator++() { + assert(m_object != nullptr); + switch (m_object->m_type) { case basic_json::value_t::object: @@ -5830,6 +5965,8 @@ class basic_json /// pre-decrement (--it) const_iterator& operator--() { + assert(m_object != nullptr); + switch (m_object->m_type) { case basic_json::value_t::object: @@ -5863,6 +6000,8 @@ class basic_json throw std::domain_error("cannot compare iterators of different containers"); } + assert(m_object != nullptr); + switch (m_object->m_type) { case basic_json::value_t::object: @@ -5897,6 +6036,8 @@ class basic_json throw std::domain_error("cannot compare iterators of different containers"); } + assert(m_object != nullptr); + switch (m_object->m_type) { case basic_json::value_t::object: @@ -5937,6 +6078,8 @@ class basic_json /// add to iterator const_iterator& operator+=(difference_type i) { + assert(m_object != nullptr); + switch (m_object->m_type) { case basic_json::value_t::object: @@ -5985,6 +6128,8 @@ class basic_json /// return difference difference_type operator-(const const_iterator& other) const { + assert(m_object != nullptr); + switch (m_object->m_type) { case basic_json::value_t::object: @@ -6007,6 +6152,8 @@ class basic_json /// access to successor reference operator[](difference_type n) const { + assert(m_object != nullptr); + switch (m_object->m_type) { case basic_json::value_t::object: @@ -6041,6 +6188,8 @@ class basic_json /// return the key of an object iterator typename object_t::key_type key() const { + assert(m_object != nullptr); + if (m_object->is_object()) { return m_it.object_iterator->first; @@ -6353,6 +6502,7 @@ class basic_json : m_stream(nullptr), m_buffer(s) { m_content = reinterpret_cast(s.c_str()); + assert(m_content != nullptr); m_start = m_cursor = m_content; m_limit = m_content + s.size(); } @@ -6361,8 +6511,10 @@ class basic_json explicit lexer(std::istream* s) noexcept : m_stream(s), m_buffer() { + assert(m_stream != nullptr); getline(*m_stream, m_buffer); m_content = reinterpret_cast(m_buffer.c_str()); + assert(m_content != nullptr); m_start = m_cursor = m_content; m_limit = m_content + m_buffer.size(); } @@ -6511,6 +6663,7 @@ class basic_json // remember the begin of the token m_start = m_cursor; + assert(m_start != nullptr); { @@ -7302,7 +7455,7 @@ basic_json_parser_64: /// append data from the stream to the internal buffer void yyfill() noexcept { - if (not m_stream or not * m_stream) + if (m_stream == nullptr or not * m_stream) { return; } @@ -7313,10 +7466,12 @@ basic_json_parser_64: m_buffer.erase(0, static_cast(offset_start)); std::string line; + assert(m_stream != nullptr); std::getline(*m_stream, line); m_buffer += "\n" + line; // add line with newline symbol m_content = reinterpret_cast(m_buffer.c_str()); + assert(m_content != nullptr); m_start = m_content; m_marker = m_start + offset_marker; m_cursor = m_start + offset_cursor; @@ -7326,6 +7481,7 @@ basic_json_parser_64: /// return string representation of last read token string_t get_token() const noexcept { + assert(m_start != nullptr); return string_t(reinterpret_cast(m_start), static_cast(m_cursor - m_start)); } @@ -7475,6 +7631,7 @@ basic_json_parser_64: { // conversion typename string_t::value_type* endptr; + assert(m_start != nullptr); const auto float_val = std::strtold(reinterpret_cast(m_start), &endptr); @@ -7485,7 +7642,7 @@ basic_json_parser_64: private: /// optional input stream - std::istream* m_stream; + std::istream* m_stream = nullptr; /// the buffer string_t m_buffer; /// the buffer pointer diff --git a/src/json.hpp.re2c b/src/json.hpp.re2c index d9d696aef..93be8c050 100644 --- a/src/json.hpp.re2c +++ b/src/json.hpp.re2c @@ -40,6 +40,7 @@ Class @ref nlohmann::basic_json is a good entry point for the documentation. #include #include +#include #include #include #include @@ -1417,6 +1418,8 @@ class basic_json m_type = value_t::object; m_value = value_t::object; + assert(m_value.object != nullptr); + for (auto& element : init) { m_value.object->emplace(std::move(*(element[0].m_value.string)), std::move(element[1])); @@ -1607,24 +1610,28 @@ class basic_json { case value_t::number_integer: { + assert(first.m_object != nullptr); m_value.number_integer = first.m_object->m_value.number_integer; break; } case value_t::number_float: { + assert(first.m_object != nullptr); m_value.number_float = first.m_object->m_value.number_float; break; } case value_t::boolean: { + assert(first.m_object != nullptr); m_value.boolean = first.m_object->m_value.boolean; break; } case value_t::string: { + assert(first.m_object != nullptr); m_value = *first.m_object->m_value.string; break; } @@ -1643,6 +1650,7 @@ class basic_json default: { + assert(first.m_object != nullptr); throw std::domain_error("cannot use construct with iterators from " + first.m_object->type_name()); } } @@ -1679,18 +1687,21 @@ class basic_json { case value_t::object: { + assert(other.m_value.object != nullptr); m_value = *other.m_value.object; break; } case value_t::array: { + assert(other.m_value.array != nullptr); m_value = *other.m_value.array; break; } case value_t::string: { + assert(other.m_value.string != nullptr); m_value = *other.m_value.string; break; } @@ -2166,6 +2177,7 @@ class basic_json { if (is_object()) { + assert(m_value.object != nullptr); return T(m_value.object->begin(), m_value.object->end()); } else @@ -2179,6 +2191,7 @@ class basic_json { if (is_object()) { + assert(m_value.object != nullptr); return *(m_value.object); } else @@ -2201,6 +2214,7 @@ class basic_json if (is_array()) { T to_vector; + assert(m_value.array != nullptr); std::transform(m_value.array->begin(), m_value.array->end(), std::inserter(to_vector, to_vector.end()), [](basic_json i) { @@ -2225,6 +2239,7 @@ class basic_json if (is_array()) { std::vector to_vector; + assert(m_value.array != nullptr); to_vector.reserve(m_value.array->size()); std::transform(m_value.array->begin(), m_value.array->end(), std::inserter(to_vector, to_vector.end()), [](basic_json i) @@ -2249,6 +2264,7 @@ class basic_json { if (is_array()) { + assert(m_value.array != nullptr); return T(m_value.array->begin(), m_value.array->end()); } else @@ -2262,6 +2278,7 @@ class basic_json { if (is_array()) { + assert(m_value.array != nullptr); return *(m_value.array); } else @@ -2279,6 +2296,7 @@ class basic_json { if (is_string()) { + assert(m_value.string != nullptr); return *m_value.string; } else @@ -2624,6 +2642,7 @@ class basic_json { try { + assert(m_value.array != nullptr); return m_value.array->at(idx); } catch (std::out_of_range& e) @@ -2667,6 +2686,7 @@ class basic_json { try { + assert(m_value.array != nullptr); return m_value.array->at(idx); } catch (std::out_of_range& e) @@ -2714,6 +2734,7 @@ class basic_json { try { + assert(m_value.object != nullptr); return m_value.object->at(key); } catch (std::out_of_range& e) @@ -2761,6 +2782,7 @@ class basic_json { try { + assert(m_value.object != nullptr); return m_value.object->at(key); } catch (std::out_of_range& e) @@ -2812,6 +2834,7 @@ class basic_json // [] only works for arrays if (is_array()) { + assert(m_value.array != nullptr); for (size_t i = m_value.array->size(); i <= idx; ++i) { m_value.array->push_back(basic_json()); @@ -2849,6 +2872,7 @@ class basic_json // at only works for arrays if (is_array()) { + assert(m_value.array != nullptr); return m_value.array->operator[](idx); } else @@ -2896,6 +2920,7 @@ class basic_json // [] only works for objects if (is_object()) { + assert(m_value.object != nullptr); return m_value.object->operator[](key); } else @@ -2936,6 +2961,8 @@ class basic_json // [] only works for objects if (is_object()) { + assert(m_value.object != nullptr); + assert(m_value.object->find(key) != m_value.object->end()); return m_value.object->find(key)->second; } else @@ -2986,6 +3013,7 @@ class basic_json // at only works for objects if (is_object()) { + assert(m_value.object != nullptr); return m_value.object->operator[](key); } else @@ -3029,6 +3057,8 @@ class basic_json // at only works for objects if (is_object()) { + assert(m_value.object != nullptr); + assert(m_value.object->find(key) != m_value.object->end()); return m_value.object->find(key)->second; } else @@ -3275,12 +3305,14 @@ class basic_json case value_t::object: { + assert(m_value.object != nullptr); result.m_it.object_iterator = m_value.object->erase(pos.m_it.object_iterator); break; } case value_t::array: { + assert(m_value.array != nullptr); result.m_it.array_iterator = m_value.array->erase(pos.m_it.array_iterator); break; } @@ -3378,6 +3410,7 @@ class basic_json case value_t::object: { + assert(m_value.object != nullptr); result.m_it.object_iterator = m_value.object->erase(first.m_it.object_iterator, last.m_it.object_iterator); break; @@ -3385,6 +3418,7 @@ class basic_json case value_t::array: { + assert(m_value.array != nullptr); result.m_it.array_iterator = m_value.array->erase(first.m_it.array_iterator, last.m_it.array_iterator); break; @@ -3430,6 +3464,7 @@ class basic_json // this erase only works for objects if (is_object()) { + assert(m_value.object != nullptr); return m_value.object->erase(key); } else @@ -3472,6 +3507,7 @@ class basic_json throw std::out_of_range("index out of range"); } + assert(m_value.array != nullptr); m_value.array->erase(m_value.array->begin() + static_cast(idx)); } else @@ -3503,6 +3539,7 @@ class basic_json if (is_object()) { + assert(m_value.object != nullptr); result.m_it.object_iterator = m_value.object->find(key); } @@ -3519,6 +3556,7 @@ class basic_json if (is_object()) { + assert(m_value.object != nullptr); result.m_it.object_iterator = m_value.object->find(key); } @@ -3546,6 +3584,7 @@ class basic_json size_type count(typename object_t::key_type key) const { // return 0 for all nonobject types + assert(not is_object() or m_value.object != nullptr); return is_object() ? m_value.object->count(key) : 0; } @@ -3864,11 +3903,13 @@ class basic_json case value_t::array: { + assert(m_value.array != nullptr); return m_value.array->empty(); } case value_t::object: { + assert(m_value.object != nullptr); return m_value.object->empty(); } @@ -3920,11 +3961,13 @@ class basic_json case value_t::array: { + assert(m_value.array != nullptr); return m_value.array->size(); } case value_t::object: { + assert(m_value.object != nullptr); return m_value.object->size(); } @@ -3974,11 +4017,13 @@ class basic_json { case value_t::array: { + assert(m_value.array != nullptr); return m_value.array->max_size(); } case value_t::object: { + assert(m_value.object != nullptr); return m_value.object->max_size(); } @@ -4049,18 +4094,21 @@ class basic_json case value_t::string: { + assert(m_value.string != nullptr); m_value.string->clear(); break; } case value_t::array: { + assert(m_value.array != nullptr); m_value.array->clear(); break; } case value_t::object: { + assert(m_value.object != nullptr); m_value.object->clear(); break; } @@ -4108,6 +4156,7 @@ class basic_json } // add element to array (move semantics) + assert(m_value.array != nullptr); m_value.array->push_back(std::move(val)); // invalidate object val.m_type = value_t::null; @@ -4143,6 +4192,7 @@ class basic_json } // add element to array + assert(m_value.array != nullptr); m_value.array->push_back(val); } @@ -4192,6 +4242,7 @@ class basic_json } // add element to array + assert(m_value.object != nullptr); m_value.object->insert(val); } @@ -4240,6 +4291,7 @@ class basic_json // insert to array and return iterator iterator result(this); + assert(m_value.array != nullptr); result.m_it.array_iterator = m_value.array->insert(pos.m_it.array_iterator, val); return result; } @@ -4295,6 +4347,7 @@ class basic_json // insert to array and return iterator iterator result(this); + assert(m_value.array != nullptr); result.m_it.array_iterator = m_value.array->insert(pos.m_it.array_iterator, cnt, val); return result; } @@ -4360,6 +4413,7 @@ class basic_json // insert to array and return iterator iterator result(this); + assert(m_value.array != nullptr); result.m_it.array_iterator = m_value.array->insert( pos.m_it.array_iterator, first.m_it.array_iterator, @@ -4407,6 +4461,7 @@ class basic_json // insert to array and return iterator iterator result(this); + assert(m_value.array != nullptr); result.m_it.array_iterator = m_value.array->insert(pos.m_it.array_iterator, ilist); return result; } @@ -4464,6 +4519,7 @@ class basic_json // swap only works for arrays if (is_array()) { + assert(m_value.array != nullptr); std::swap(*(m_value.array), other); } else @@ -4497,6 +4553,7 @@ class basic_json // swap only works for objects if (is_object()) { + assert(m_value.object != nullptr); std::swap(*(m_value.object), other); } else @@ -4530,6 +4587,7 @@ class basic_json // swap only works for strings if (is_string()) { + assert(m_value.string != nullptr); std::swap(*(m_value.string), other); } else @@ -4614,21 +4672,43 @@ class basic_json switch (lhs_type) { case value_t::array: + { + assert(lhs.m_value.array != nullptr); + assert(rhs.m_value.array != nullptr); return *lhs.m_value.array == *rhs.m_value.array; + } case value_t::object: + { + assert(lhs.m_value.object != nullptr); + assert(rhs.m_value.object != nullptr); return *lhs.m_value.object == *rhs.m_value.object; + } case value_t::null: + { return true; + } case value_t::string: + { + assert(lhs.m_value.string != nullptr); + assert(rhs.m_value.string != nullptr); return *lhs.m_value.string == *rhs.m_value.string; + } case value_t::boolean: + { return lhs.m_value.boolean == rhs.m_value.boolean; + } case value_t::number_integer: + { return lhs.m_value.number_integer == rhs.m_value.number_integer; + } case value_t::number_float: + { return approx(lhs.m_value.number_float, rhs.m_value.number_float); + } default: + { return false; + } } } else if (lhs_type == value_t::number_integer and rhs_type == value_t::number_float) @@ -4763,21 +4843,43 @@ class basic_json switch (lhs_type) { case value_t::array: + { + assert(lhs.m_value.array != nullptr); + assert(rhs.m_value.array != nullptr); return *lhs.m_value.array < *rhs.m_value.array; + } case value_t::object: + { + assert(lhs.m_value.object != nullptr); + assert(rhs.m_value.object != nullptr); return *lhs.m_value.object < *rhs.m_value.object; + } case value_t::null: + { return false; + } case value_t::string: + { + assert(lhs.m_value.string != nullptr); + assert(rhs.m_value.string != nullptr); return *lhs.m_value.string < *rhs.m_value.string; + } case value_t::boolean: + { return lhs.m_value.boolean < rhs.m_value.boolean; + } case value_t::number_integer: + { return lhs.m_value.number_integer < rhs.m_value.number_integer; + } case value_t::number_float: + { return lhs.m_value.number_float < rhs.m_value.number_float; + } default: + { return false; + } } } else if (lhs_type == value_t::number_integer and rhs_type == value_t::number_float) @@ -5254,6 +5356,8 @@ class basic_json { case value_t::object: { + assert(m_value.object != nullptr); + if (m_value.object->empty()) { o << "{}"; @@ -5294,6 +5398,8 @@ class basic_json case value_t::array: { + assert(m_value.array != nullptr); + if (m_value.array->empty()) { o << "[]"; @@ -5332,6 +5438,7 @@ class basic_json case value_t::string: { + assert(m_value.string != nullptr); o << string_t("\"") << escape_string(*m_value.string) << "\""; return; } @@ -5509,6 +5616,8 @@ class basic_json /// return key of the iterator typename basic_json::string_t key() const { + assert(anchor.m_object != nullptr); + switch (anchor.m_object->type()) { // use integer array index as key @@ -5597,6 +5706,8 @@ class basic_json /// constructor for a given JSON instance const_iterator(pointer object) : m_object(object) { + assert(m_object != nullptr); + switch (m_object->m_type) { case basic_json::value_t::object: @@ -5622,6 +5733,8 @@ class basic_json /// copy constructor given a nonconst iterator const_iterator(const iterator& other) : m_object(other.m_object) { + assert(m_object != nullptr); + switch (m_object->m_type) { case basic_json::value_t::object: @@ -5666,16 +5779,20 @@ class basic_json /// set the iterator to the first value void set_begin() { + assert(m_object != nullptr); + switch (m_object->m_type) { case basic_json::value_t::object: { + assert(m_object->m_value.object != nullptr); m_it.object_iterator = m_object->m_value.object->begin(); break; } case basic_json::value_t::array: { + assert(m_object->m_value.array != nullptr); m_it.array_iterator = m_object->m_value.array->begin(); break; } @@ -5698,16 +5815,20 @@ class basic_json /// set the iterator past the last value void set_end() { + assert(m_object != nullptr); + switch (m_object->m_type) { case basic_json::value_t::object: { + assert(m_object->m_value.object != nullptr); m_it.object_iterator = m_object->m_value.object->end(); break; } case basic_json::value_t::array: { + assert(m_object->m_value.array != nullptr); m_it.array_iterator = m_object->m_value.array->end(); break; } @@ -5724,15 +5845,21 @@ class basic_json /// return a reference to the value pointed to by the iterator reference operator*() const { + assert(m_object != nullptr); + switch (m_object->m_type) { case basic_json::value_t::object: { + assert(m_object->m_value.object); + assert(m_it.object_iterator != m_object->m_value.object->end()); return m_it.object_iterator->second; } case basic_json::value_t::array: { + assert(m_object->m_value.array); + assert(m_it.array_iterator != m_object->m_value.array->end()); return *m_it.array_iterator; } @@ -5758,15 +5885,21 @@ class basic_json /// dereference the iterator pointer operator->() const { + assert(m_object != nullptr); + switch (m_object->m_type) { case basic_json::value_t::object: { + assert(m_object->m_value.object); + assert(m_it.object_iterator != m_object->m_value.object->end()); return &(m_it.object_iterator->second); } case basic_json::value_t::array: { + assert(m_object->m_value.array); + assert(m_it.array_iterator != m_object->m_value.array->end()); return &*m_it.array_iterator; } @@ -5795,6 +5928,8 @@ class basic_json /// pre-increment (++it) const_iterator& operator++() { + assert(m_object != nullptr); + switch (m_object->m_type) { case basic_json::value_t::object: @@ -5830,6 +5965,8 @@ class basic_json /// pre-decrement (--it) const_iterator& operator--() { + assert(m_object != nullptr); + switch (m_object->m_type) { case basic_json::value_t::object: @@ -5863,6 +6000,8 @@ class basic_json throw std::domain_error("cannot compare iterators of different containers"); } + assert(m_object != nullptr); + switch (m_object->m_type) { case basic_json::value_t::object: @@ -5897,6 +6036,8 @@ class basic_json throw std::domain_error("cannot compare iterators of different containers"); } + assert(m_object != nullptr); + switch (m_object->m_type) { case basic_json::value_t::object: @@ -5937,6 +6078,8 @@ class basic_json /// add to iterator const_iterator& operator+=(difference_type i) { + assert(m_object != nullptr); + switch (m_object->m_type) { case basic_json::value_t::object: @@ -5985,6 +6128,8 @@ class basic_json /// return difference difference_type operator-(const const_iterator& other) const { + assert(m_object != nullptr); + switch (m_object->m_type) { case basic_json::value_t::object: @@ -6007,6 +6152,8 @@ class basic_json /// access to successor reference operator[](difference_type n) const { + assert(m_object != nullptr); + switch (m_object->m_type) { case basic_json::value_t::object: @@ -6041,6 +6188,8 @@ class basic_json /// return the key of an object iterator typename object_t::key_type key() const { + assert(m_object != nullptr); + if (m_object->is_object()) { return m_it.object_iterator->first; @@ -6353,6 +6502,7 @@ class basic_json : m_stream(nullptr), m_buffer(s) { m_content = reinterpret_cast(s.c_str()); + assert(m_content != nullptr); m_start = m_cursor = m_content; m_limit = m_content + s.size(); } @@ -6361,8 +6511,10 @@ class basic_json explicit lexer(std::istream* s) noexcept : m_stream(s), m_buffer() { + assert(m_stream != nullptr); getline(*m_stream, m_buffer); m_content = reinterpret_cast(m_buffer.c_str()); + assert(m_content != nullptr); m_start = m_cursor = m_content; m_limit = m_content + m_buffer.size(); } @@ -6511,6 +6663,7 @@ class basic_json // remember the begin of the token m_start = m_cursor; + assert(m_start != nullptr); /*!re2c re2c:define:YYCTYPE = lexer_char_t; @@ -6581,7 +6734,7 @@ class basic_json /// append data from the stream to the internal buffer void yyfill() noexcept { - if (not m_stream or not * m_stream) + if (m_stream == nullptr or not * m_stream) { return; } @@ -6592,10 +6745,12 @@ class basic_json m_buffer.erase(0, static_cast(offset_start)); std::string line; + assert(m_stream != nullptr); std::getline(*m_stream, line); m_buffer += "\n" + line; // add line with newline symbol m_content = reinterpret_cast(m_buffer.c_str()); + assert(m_content != nullptr); m_start = m_content; m_marker = m_start + offset_marker; m_cursor = m_start + offset_cursor; @@ -6605,6 +6760,7 @@ class basic_json /// return string representation of last read token string_t get_token() const noexcept { + assert(m_start != nullptr); return string_t(reinterpret_cast(m_start), static_cast(m_cursor - m_start)); } @@ -6754,6 +6910,7 @@ class basic_json { // conversion typename string_t::value_type* endptr; + assert(m_start != nullptr); const auto float_val = std::strtold(reinterpret_cast(m_start), &endptr); @@ -6764,7 +6921,7 @@ class basic_json private: /// optional input stream - std::istream* m_stream; + std::istream* m_stream = nullptr; /// the buffer string_t m_buffer; /// the buffer pointer From 151d43f63e5c06aac83aa17f90ee1133231988f2 Mon Sep 17 00:00:00 2001 From: Niels Date: Wed, 13 Jan 2016 19:14:33 +0100 Subject: [PATCH 53/61] fixing numerous typos (fixes #179) --- src/json.hpp | 42 +++++++++++++++++++++--------------------- src/json.hpp.re2c | 42 +++++++++++++++++++++--------------------- 2 files changed, 42 insertions(+), 42 deletions(-) diff --git a/src/json.hpp b/src/json.hpp index edda8edcb..e57685f46 100644 --- a/src/json.hpp +++ b/src/json.hpp @@ -133,7 +133,7 @@ default) - [MoveConstructible](http://en.cppreference.com/w/cpp/concept/MoveConstructible): A JSON value can be constructed from an rvalue argument. - [CopyConstructible](http://en.cppreference.com/w/cpp/concept/CopyConstructible): - A JSON value can be copy-constrcuted from an lvalue expression. + A JSON value can be copy-constructed from an lvalue expression. - [MoveAssignable](http://en.cppreference.com/w/cpp/concept/MoveAssignable): A JSON value van be assigned from an rvalue argument. - [CopyAssignable](http://en.cppreference.com/w/cpp/concept/CopyAssignable): @@ -578,7 +578,7 @@ class basic_json This implementation does exactly follow this approach, as it uses double precision floating-point numbers. Note values smaller than - `-1.79769313486232e+308` and values greather than `1.79769313486232e+308` + `-1.79769313486232e+308` and values greater than `1.79769313486232e+308` will be stored as NaN internally and be serialized to `null`. #### Storage @@ -1136,7 +1136,7 @@ class basic_json /*! @brief create an integer number (explicit) - Create an interger number JSON value with a given content. + Create an integer number JSON value with a given content. @tparam T helper type to compare number_integer_t and int (not visible in) the interface. @@ -1321,7 +1321,7 @@ class basic_json 3. In all other cases, an array is created. The rules aim to create the best fit between a C++ initializer list and - JSON values. The ratioinale is as follows: + JSON values. The rationale is as follows: 1. The empty initializer list is written as `{}` which is exactly an empty JSON object. @@ -1477,7 +1477,7 @@ class basic_json @brief explicitly create an object from an initializer list Creates a JSON object value from a given initializer list. The initializer - lists elements must be pairs, and their first elments must be strings. If + lists elements must be pairs, and their first elements must be strings. If the initializer list is empty, the empty object `{}` is created. @note This function is only added for symmetry reasons. In contrast to the @@ -1854,7 +1854,7 @@ class basic_json /*! @brief serialization - Serialization function for JSON values. The function tries to mimick + Serialization function for JSON values. The function tries to mimic Python's @p json.dumps() function, and currently supports its @p indent parameter. @@ -1868,7 +1868,7 @@ class basic_json @complexity Linear. @liveexample{The following example shows the effect of different @a indent - parameters to the result of the serializaion.,dump} + parameters to the result of the serialization.,dump} @see https://docs.python.org/2/library/json.html#json.dump @@ -2437,11 +2437,11 @@ class basic_json @complexity Linear in the size of the JSON value. - @liveexample{The example below shows serveral conversions from JSON values + @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++ - assiciative containers such as `std::unordered_map`.,get__ValueType_const} @internal @@ -2516,7 +2516,7 @@ class basic_json /*! @brief get a pointer value (implicit) - Implict pointer access to the internally stored JSON value. No copies are + Implicit pointer access to the internally stored JSON value. No copies are made. @warning Writing data to the pointee of the result yields an undefined @@ -2566,7 +2566,7 @@ class basic_json /*! @brief get a value (implicit) - Implict type conversion between the JSON value and a compatible value. The + Implicit type conversion between the JSON value and a compatible value. The call is realized by calling @ref get() const. @tparam ValueType non-pointer type compatible to the JSON value, for @@ -2582,11 +2582,11 @@ class basic_json @complexity Linear in the size of the JSON value. - @liveexample{The example below shows serveral conversions from JSON values + @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++ - assiciative containers such as `std::unordered_map`.,operator__ValueType} @since version 1.0.0 @@ -3227,7 +3227,7 @@ class basic_json Removes the element specified by iterator @a pos. Invalidates iterators and references at or after the point of the erase, including the end() iterator. The iterator @a pos must be valid and dereferenceable. Thus the - end() iterator (which is valid, but is not dereferencable) cannot be used + end() iterator (which is valid, but is not dereferenceable) cannot be used as a value for @a pos. If called on a primitive type other than null, the resulting JSON value @@ -3258,7 +3258,7 @@ class basic_json @sa @ref erase(InteratorType, InteratorType) -- removes the elements in the given range - @sa @ref erase(const typename object_t::key_type&) -- remvoes the element + @sa @ref erase(const typename object_t::key_type&) -- removes the element from an object at the given key @sa @ref erase(const size_type) -- removes the element from an array at the given index @@ -3363,7 +3363,7 @@ class basic_json types.,erase__IteratorType_IteratorType} @sa @ref erase(InteratorType) -- removes the element at a given position - @sa @ref erase(const typename object_t::key_type&) -- remvoes the element + @sa @ref erase(const typename object_t::key_type&) -- removes the element from an object at the given key @sa @ref erase(const size_type) -- removes the element from an array at the given index @@ -3492,7 +3492,7 @@ class basic_json @sa @ref erase(InteratorType) -- removes the element at a given position @sa @ref erase(InteratorType, InteratorType) -- removes the elements in the given range - @sa @ref erase(const typename object_t::key_type&) -- remvoes the element + @sa @ref erase(const typename object_t::key_type&) -- removes the element from an object at the given key @since version 1.0.0 @@ -3831,7 +3831,7 @@ class basic_json /*! @brief wrapper to access iterator member functions in range-based for - This functuion allows to access @ref iterator::key() and @ref + This function allows to access @ref iterator::key() and @ref iterator::value() during range-based for loops. In these loops, a reference to the JSON values is returned, so there is no access to the underlying iterator. @@ -5331,12 +5331,12 @@ class basic_json @brief internal implementation of the serialization function This function is called by the public member function dump and organizes - the serializaion internally. The indentation level is propagated as + the serialization internally. The indentation level is propagated as additional parameter. In case of arrays and objects, the function is called recursively. Note that - strings and object keys are escaped using escape_string() - - integer numbers are converted implictly via operator<< + - integer numbers are converted implicitly via operator<< - floating-point numbers are converted to a string using "%g" format @param[out] o stream to write to @@ -6561,7 +6561,7 @@ class basic_json // low surrogate occupies the least significant 15 bits + codepoint2 // there is still the 0xD800, 0xDC00 and 0x10000 noise - // in the result so we have to substract with: + // in the result so we have to subtract with: // (0xD800 << 10) + DC00 - 0x10000 = 0x35FDC00 - 0x35FDC00; } diff --git a/src/json.hpp.re2c b/src/json.hpp.re2c index 93be8c050..431d72eeb 100644 --- a/src/json.hpp.re2c +++ b/src/json.hpp.re2c @@ -133,7 +133,7 @@ default) - [MoveConstructible](http://en.cppreference.com/w/cpp/concept/MoveConstructible): A JSON value can be constructed from an rvalue argument. - [CopyConstructible](http://en.cppreference.com/w/cpp/concept/CopyConstructible): - A JSON value can be copy-constrcuted from an lvalue expression. + A JSON value can be copy-constructed from an lvalue expression. - [MoveAssignable](http://en.cppreference.com/w/cpp/concept/MoveAssignable): A JSON value van be assigned from an rvalue argument. - [CopyAssignable](http://en.cppreference.com/w/cpp/concept/CopyAssignable): @@ -578,7 +578,7 @@ class basic_json This implementation does exactly follow this approach, as it uses double precision floating-point numbers. Note values smaller than - `-1.79769313486232e+308` and values greather than `1.79769313486232e+308` + `-1.79769313486232e+308` and values greater than `1.79769313486232e+308` will be stored as NaN internally and be serialized to `null`. #### Storage @@ -1136,7 +1136,7 @@ class basic_json /*! @brief create an integer number (explicit) - Create an interger number JSON value with a given content. + Create an integer number JSON value with a given content. @tparam T helper type to compare number_integer_t and int (not visible in) the interface. @@ -1321,7 +1321,7 @@ class basic_json 3. In all other cases, an array is created. The rules aim to create the best fit between a C++ initializer list and - JSON values. The ratioinale is as follows: + JSON values. The rationale is as follows: 1. The empty initializer list is written as `{}` which is exactly an empty JSON object. @@ -1477,7 +1477,7 @@ class basic_json @brief explicitly create an object from an initializer list Creates a JSON object value from a given initializer list. The initializer - lists elements must be pairs, and their first elments must be strings. If + lists elements must be pairs, and their first elements must be strings. If the initializer list is empty, the empty object `{}` is created. @note This function is only added for symmetry reasons. In contrast to the @@ -1854,7 +1854,7 @@ class basic_json /*! @brief serialization - Serialization function for JSON values. The function tries to mimick + Serialization function for JSON values. The function tries to mimic Python's @p json.dumps() function, and currently supports its @p indent parameter. @@ -1868,7 +1868,7 @@ class basic_json @complexity Linear. @liveexample{The following example shows the effect of different @a indent - parameters to the result of the serializaion.,dump} + parameters to the result of the serialization.,dump} @see https://docs.python.org/2/library/json.html#json.dump @@ -2437,11 +2437,11 @@ class basic_json @complexity Linear in the size of the JSON value. - @liveexample{The example below shows serveral conversions from JSON values + @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++ - assiciative containers such as `std::unordered_map`.,get__ValueType_const} @internal @@ -2516,7 +2516,7 @@ class basic_json /*! @brief get a pointer value (implicit) - Implict pointer access to the internally stored JSON value. No copies are + Implicit pointer access to the internally stored JSON value. No copies are made. @warning Writing data to the pointee of the result yields an undefined @@ -2566,7 +2566,7 @@ class basic_json /*! @brief get a value (implicit) - Implict type conversion between the JSON value and a compatible value. The + Implicit type conversion between the JSON value and a compatible value. The call is realized by calling @ref get() const. @tparam ValueType non-pointer type compatible to the JSON value, for @@ -2582,11 +2582,11 @@ class basic_json @complexity Linear in the size of the JSON value. - @liveexample{The example below shows serveral conversions from JSON values + @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++ - assiciative containers such as `std::unordered_map`.,operator__ValueType} @since version 1.0.0 @@ -3227,7 +3227,7 @@ class basic_json Removes the element specified by iterator @a pos. Invalidates iterators and references at or after the point of the erase, including the end() iterator. The iterator @a pos must be valid and dereferenceable. Thus the - end() iterator (which is valid, but is not dereferencable) cannot be used + end() iterator (which is valid, but is not dereferenceable) cannot be used as a value for @a pos. If called on a primitive type other than null, the resulting JSON value @@ -3258,7 +3258,7 @@ class basic_json @sa @ref erase(InteratorType, InteratorType) -- removes the elements in the given range - @sa @ref erase(const typename object_t::key_type&) -- remvoes the element + @sa @ref erase(const typename object_t::key_type&) -- removes the element from an object at the given key @sa @ref erase(const size_type) -- removes the element from an array at the given index @@ -3363,7 +3363,7 @@ class basic_json types.,erase__IteratorType_IteratorType} @sa @ref erase(InteratorType) -- removes the element at a given position - @sa @ref erase(const typename object_t::key_type&) -- remvoes the element + @sa @ref erase(const typename object_t::key_type&) -- removes the element from an object at the given key @sa @ref erase(const size_type) -- removes the element from an array at the given index @@ -3492,7 +3492,7 @@ class basic_json @sa @ref erase(InteratorType) -- removes the element at a given position @sa @ref erase(InteratorType, InteratorType) -- removes the elements in the given range - @sa @ref erase(const typename object_t::key_type&) -- remvoes the element + @sa @ref erase(const typename object_t::key_type&) -- removes the element from an object at the given key @since version 1.0.0 @@ -3831,7 +3831,7 @@ class basic_json /*! @brief wrapper to access iterator member functions in range-based for - This functuion allows to access @ref iterator::key() and @ref + This function allows to access @ref iterator::key() and @ref iterator::value() during range-based for loops. In these loops, a reference to the JSON values is returned, so there is no access to the underlying iterator. @@ -5331,12 +5331,12 @@ class basic_json @brief internal implementation of the serialization function This function is called by the public member function dump and organizes - the serializaion internally. The indentation level is propagated as + the serialization internally. The indentation level is propagated as additional parameter. In case of arrays and objects, the function is called recursively. Note that - strings and object keys are escaped using escape_string() - - integer numbers are converted implictly via operator<< + - integer numbers are converted implicitly via operator<< - floating-point numbers are converted to a string using "%g" format @param[out] o stream to write to @@ -6561,7 +6561,7 @@ class basic_json // low surrogate occupies the least significant 15 bits + codepoint2 // there is still the 0xD800, 0xDC00 and 0x10000 noise - // in the result so we have to substract with: + // in the result so we have to subtract with: // (0xD800 << 10) + DC00 - 0x10000 = 0x35FDC00 - 0x35FDC00; } From 4511145d3deb556d241298729c1d364dddaa92e4 Mon Sep 17 00:00:00 2001 From: Niels Date: Wed, 13 Jan 2016 19:19:35 +0100 Subject: [PATCH 54/61] removing unused catch variables (fixes #180) --- src/json.hpp | 8 ++++---- src/json.hpp.re2c | 8 ++++---- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/src/json.hpp b/src/json.hpp index e57685f46..b874a56a7 100644 --- a/src/json.hpp +++ b/src/json.hpp @@ -2645,7 +2645,7 @@ class basic_json assert(m_value.array != nullptr); return m_value.array->at(idx); } - catch (std::out_of_range& e) + catch (std::out_of_range&) { // create better exception explanation throw std::out_of_range("array index " + std::to_string(idx) + " is out of range"); @@ -2689,7 +2689,7 @@ class basic_json assert(m_value.array != nullptr); return m_value.array->at(idx); } - catch (std::out_of_range& e) + catch (std::out_of_range&) { // create better exception explanation throw std::out_of_range("array index " + std::to_string(idx) + " is out of range"); @@ -2737,7 +2737,7 @@ class basic_json assert(m_value.object != nullptr); return m_value.object->at(key); } - catch (std::out_of_range& e) + catch (std::out_of_range&) { // create better exception explanation throw std::out_of_range("key '" + key + "' not found"); @@ -2785,7 +2785,7 @@ class basic_json assert(m_value.object != nullptr); return m_value.object->at(key); } - catch (std::out_of_range& e) + catch (std::out_of_range&) { // create better exception explanation throw std::out_of_range("key '" + key + "' not found"); diff --git a/src/json.hpp.re2c b/src/json.hpp.re2c index 431d72eeb..00aa4d1fe 100644 --- a/src/json.hpp.re2c +++ b/src/json.hpp.re2c @@ -2645,7 +2645,7 @@ class basic_json assert(m_value.array != nullptr); return m_value.array->at(idx); } - catch (std::out_of_range& e) + catch (std::out_of_range&) { // create better exception explanation throw std::out_of_range("array index " + std::to_string(idx) + " is out of range"); @@ -2689,7 +2689,7 @@ class basic_json assert(m_value.array != nullptr); return m_value.array->at(idx); } - catch (std::out_of_range& e) + catch (std::out_of_range&) { // create better exception explanation throw std::out_of_range("array index " + std::to_string(idx) + " is out of range"); @@ -2737,7 +2737,7 @@ class basic_json assert(m_value.object != nullptr); return m_value.object->at(key); } - catch (std::out_of_range& e) + catch (std::out_of_range&) { // create better exception explanation throw std::out_of_range("key '" + key + "' not found"); @@ -2785,7 +2785,7 @@ class basic_json assert(m_value.object != nullptr); return m_value.object->at(key); } - catch (std::out_of_range& e) + catch (std::out_of_range&) { // create better exception explanation throw std::out_of_range("key '" + key + "' not found"); From 1741e58eb5bc61c9302cbfa63563120f4dd8d5a9 Mon Sep 17 00:00:00 2001 From: Niels Date: Wed, 13 Jan 2016 20:18:06 +0100 Subject: [PATCH 55/61] contribution guidelines (#175) --- CONTRIBUTING.md | 63 +++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 63 insertions(+) create mode 100644 CONTRIBUTING.md diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md new file mode 100644 index 000000000..2ef1df795 --- /dev/null +++ b/CONTRIBUTING.md @@ -0,0 +1,63 @@ +# How to contribute + +This project started as a little excuse to exercise some of the cool new C++11 features. Over the time, people actually started to use the JSON library (yey!) and started to help improving it by proposing features, finding bugs, or even fixing my mistakes. I am really [thankful](https://github.com/nlohmann/json/blob/master/README.md#thanks) for this and try to keep track of all the helpers. + +To make it as easy as possible for you to contribute and me to keep an overview, here are some few guidelines which should help us avoid all kind of unnecessary work or disappointment. And of course, this document is subject to discussion, so please [create an issue](https://github.com/nlohmann/json/issues/new) or a pull request if you find a way to improve it! + +## Prerequisites + +Please [create an issue](https://github.com/nlohmann/json/issues/new), assuming one does not already exist and described your concern. Note you need a [GitHub account](https://github.com/signup/free) for this. + +If you want propose changes to the code, you need to download the [`re2c`](http://re2c.org) tool. + +## Describe your issue + +Clearly describe the issue: + +- If it is a bug, please describe how to **reproduce** it. If possible, attach a complete example which demonstrates the error. Please also state what you **expected** to happen instead of the error. +- If you propose a change or addition, try to give an **example** how the improved code could look like or how to use it. +- If you found a compilation error, please tell us which **compiler** (version and operating system) you used and paste the (relevant part of) the error messages to the ticket. + +## Files to change + +There are currently two files which need to be edited: + +1. [`src/json.hpp.re2c`](https://github.com/nlohmann/json/blob/master/src/json.hpp.re2c) (note the `.re2c` suffix) - This file contains a comment section which describes the JSON lexic. This section is translated by [`re2c`](http://re2c.org) into file [`src/json.hpp`](https://github.com/nlohmann/json/blob/master/src/json.hpp) which is plain "vanilla" C++11 code. (In fact, the generated lexer consists of some hundred lines of `goto`s, which is a hint you never want to edit this file...). + +⋅⋅⋅If you only edit file `src.json.hpp` (without the `.re2c`) suffix, your changes will be overwritten as soon as the lexer is touched again. To generate the `src.json.hpp` file which is actually used during compilation of the tests and all other code, please execute + +... make re2c + +...To run [`re2c`](http://re2c.org) and generate/overwrite file `src/json.hpp` with your changes in file `src/json.hpp.re2c`. + + +2. [`test/unit.cpp`](https://github.com/nlohmann/json/blob/master/test/unit.cpp) - This contains the [Catch](https://github.com/philsquared/Catch) unit tests which currently cover [100 %](https://coveralls.io/github/nlohmann/json) of the library's code. + +...If you add or change a feature, please also add a unit test to this file. The unit tests can be compiled with + +... make + +...and can be executed with + +... ./json_unit + +...The test cases are also executed with several different compilers on [Travis](https://travis-ci.org/nlohmann/json) once you opened a pull request. + +Please understand that I cannot accept pull requests changing only file `src/json.hpp`. + + +## Please don't + +- Only make changes to file `src/json.hpp` -- please read the paragraph above and understand why `src/json.hpp.re2c` exists. +- 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 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 showed that there are ways to express the functionality 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. + +## Wanted + +The following areas really need contribution: + +- Getting the code to compile without errors with the lates **Microsoft Visual Studio** version. I am not using Windows myself, so I cannot debug code with MSVC myself. There is a job on [AppVeyor](https://ci.appveyor.com/project/nlohmann/json) though. +- Extending the **continuous integration** beyond Linux running some versions of GCC and Clang on [Travis](https://travis-ci.org/nlohmann/json) and Microsoft Visual Studio on [AppVeyor](https://ci.appveyor.com/project/nlohmann/json). We found a lot of bugs just because several compilers behave in a slightly different manner. +- Improving the efficiency of the **JSON parser**. The current parser is implemented as a naive recursive descent parser with hand coded string handling. More sophisticated approaches like LALR parsers would be really appreciated. That said, parser generators like Bison or ANTLR do not play nice with single-header files -- I really would like to keep the parser inside the `json.hpp` header, and I am not aware of approaches similar to [`re2c`](http://re2c.org) for parsing. +- Extending and updating existing **benchmarks** to include (the most recent version of) this library. Though efficiency is not everything, speed and memory consumption are very important characteristics for C++ developers, so having proper comparisons would be interesting. From 57e018483acb1c4975cbbd4447abe7eb176cab9d Mon Sep 17 00:00:00 2001 From: Niels Date: Wed, 13 Jan 2016 20:19:05 +0100 Subject: [PATCH 56/61] it's 2016 already... --- LICENSE.MIT | 2 +- README.md | 4 ++-- src/json.hpp | 2 +- src/json.hpp.re2c | 2 +- 4 files changed, 5 insertions(+), 5 deletions(-) diff --git a/LICENSE.MIT b/LICENSE.MIT index 18332db3c..e2ac4891d 100644 --- a/LICENSE.MIT +++ b/LICENSE.MIT @@ -1,7 +1,7 @@ The library is licensed under the MIT License : -Copyright (c) 2013-2015 Niels Lohmann +Copyright (c) 2013-2016 Niels Lohmann Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in diff --git a/README.md b/README.md index fff191bec..b27926fa5 100644 --- a/README.md +++ b/README.md @@ -40,7 +40,7 @@ to the files you want to use JSON objects. That's it. Do not forget to set the n ## Supported compilers -Though it's 2015 already, the support for C++11 is still a bit sparse. Currently, the following compilers are known to work: +Though it's 2016 already, the support for C++11 is still a bit sparse. Currently, the following compilers are known to work: - GCC 4.9 - 6.0 (and possibly later) - Clang 3.4 - 3.8 (and possibly later) @@ -351,7 +351,7 @@ int vi = jn.get(); The class is licensed under the [MIT License](http://opensource.org/licenses/MIT): -Copyright © 2013-2015 [Niels Lohmann](http://nlohmann.me) +Copyright © 2013-2016 [Niels Lohmann](http://nlohmann.me) Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: diff --git a/src/json.hpp b/src/json.hpp index b874a56a7..a91edba4f 100644 --- a/src/json.hpp +++ b/src/json.hpp @@ -9,7 +9,7 @@ Class @ref nlohmann::basic_json is a good entry point for the documentation. @copyright The code is licensed under the [MIT License](http://opensource.org/licenses/MIT):
- Copyright © 2013-2015 Niels Lohmann. + Copyright © 2013-2016 Niels Lohmann.
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/src/json.hpp.re2c b/src/json.hpp.re2c index 00aa4d1fe..a733f0979 100644 --- a/src/json.hpp.re2c +++ b/src/json.hpp.re2c @@ -9,7 +9,7 @@ Class @ref nlohmann::basic_json is a good entry point for the documentation. @copyright The code is licensed under the [MIT License](http://opensource.org/licenses/MIT):
- Copyright © 2013-2015 Niels Lohmann. + Copyright © 2013-2016 Niels Lohmann.
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal From 832fe49bc11c70aa9bfb595c7f9a3f8f34afa7a0 Mon Sep 17 00:00:00 2001 From: Niels Date: Wed, 13 Jan 2016 20:26:47 +0100 Subject: [PATCH 57/61] fixed lists --- CONTRIBUTING.md | 22 ++++++++++++++-------- 1 file changed, 14 insertions(+), 8 deletions(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 2ef1df795..247e8223b 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -24,24 +24,30 @@ There are currently two files which need to be edited: 1. [`src/json.hpp.re2c`](https://github.com/nlohmann/json/blob/master/src/json.hpp.re2c) (note the `.re2c` suffix) - This file contains a comment section which describes the JSON lexic. This section is translated by [`re2c`](http://re2c.org) into file [`src/json.hpp`](https://github.com/nlohmann/json/blob/master/src/json.hpp) which is plain "vanilla" C++11 code. (In fact, the generated lexer consists of some hundred lines of `goto`s, which is a hint you never want to edit this file...). -⋅⋅⋅If you only edit file `src.json.hpp` (without the `.re2c`) suffix, your changes will be overwritten as soon as the lexer is touched again. To generate the `src.json.hpp` file which is actually used during compilation of the tests and all other code, please execute + If you only edit file `src.json.hpp` (without the `.re2c`) suffix, your changes will be overwritten as soon as the lexer is touched again. To generate the `src.json.hpp` file which is actually used during compilation of the tests and all other code, please execute -... make re2c + ```sh + make re2c + ``` -...To run [`re2c`](http://re2c.org) and generate/overwrite file `src/json.hpp` with your changes in file `src/json.hpp.re2c`. + To run [`re2c`](http://re2c.org) and generate/overwrite file `src/json.hpp` with your changes in file `src/json.hpp.re2c`. 2. [`test/unit.cpp`](https://github.com/nlohmann/json/blob/master/test/unit.cpp) - This contains the [Catch](https://github.com/philsquared/Catch) unit tests which currently cover [100 %](https://coveralls.io/github/nlohmann/json) of the library's code. -...If you add or change a feature, please also add a unit test to this file. The unit tests can be compiled with + If you add or change a feature, please also add a unit test to this file. The unit tests can be compiled with -... make + ```sh + make + ``` -...and can be executed with + and can be executed with -... ./json_unit + ```sh + ./json_unit + ``` -...The test cases are also executed with several different compilers on [Travis](https://travis-ci.org/nlohmann/json) once you opened a pull request. + The test cases are also executed with several different compilers on [Travis](https://travis-ci.org/nlohmann/json) once you opened a pull request. Please understand that I cannot accept pull requests changing only file `src/json.hpp`. From a05f27867bb6f2255ef93af6b8b245548abf1d7a Mon Sep 17 00:00:00 2001 From: Niels Date: Wed, 13 Jan 2016 20:37:05 +0100 Subject: [PATCH 58/61] fixed wrong file name --- CONTRIBUTING.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 247e8223b..bff8df142 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -24,7 +24,7 @@ There are currently two files which need to be edited: 1. [`src/json.hpp.re2c`](https://github.com/nlohmann/json/blob/master/src/json.hpp.re2c) (note the `.re2c` suffix) - This file contains a comment section which describes the JSON lexic. This section is translated by [`re2c`](http://re2c.org) into file [`src/json.hpp`](https://github.com/nlohmann/json/blob/master/src/json.hpp) which is plain "vanilla" C++11 code. (In fact, the generated lexer consists of some hundred lines of `goto`s, which is a hint you never want to edit this file...). - If you only edit file `src.json.hpp` (without the `.re2c`) suffix, your changes will be overwritten as soon as the lexer is touched again. To generate the `src.json.hpp` file which is actually used during compilation of the tests and all other code, please execute + If you only edit file `src/json.hpp` (without the `.re2c`) suffix, your changes will be overwritten as soon as the lexer is touched again. To generate the `src/json.hpp` file which is actually used during compilation of the tests and all other code, please execute ```sh make re2c From c0bb5a56ebde9d0d44c472f6aa167144aee2943e Mon Sep 17 00:00:00 2001 From: Niels Date: Wed, 13 Jan 2016 21:08:42 +0100 Subject: [PATCH 59/61] added note on assertions (#168) --- README.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/README.md b/README.md index b27926fa5..97591f6a1 100644 --- a/README.md +++ b/README.md @@ -390,6 +390,10 @@ I deeply appreciate the help of the following people. Thanks a lot for helping out! +## Notes + +- The code contains numerous debug assertions which can be switched off by defining the preprocessor macro `NDEBUG`, see the [documentation of `assert`](http://en.cppreference.com/w/cpp/error/assert). + ## Execute unit tests To compile and run the tests, you need to execute From 8ecccf8628f434420ab0b2c10dcea3bc55dd9b1a Mon Sep 17 00:00:00 2001 From: Corbin Hughes Date: Thu, 14 Jan 2016 22:35:48 -0600 Subject: [PATCH 60/61] Fixed some typos in CONTRIBUTING.md --- CONTRIBUTING.md | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index bff8df142..81fac6d94 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -1,12 +1,12 @@ # How to contribute -This project started as a little excuse to exercise some of the cool new C++11 features. Over the time, people actually started to use the JSON library (yey!) and started to help improving it by proposing features, finding bugs, or even fixing my mistakes. I am really [thankful](https://github.com/nlohmann/json/blob/master/README.md#thanks) for this and try to keep track of all the helpers. +This project started as a little excuse to exercise some of the cool new C++11 features. Over time, people actually started to use the JSON library (yey!) and started to help improve it by proposing features, finding bugs, or even fixing my mistakes. I am really [thankful](https://github.com/nlohmann/json/blob/master/README.md#thanks) for this and try to keep track of all the helpers. -To make it as easy as possible for you to contribute and me to keep an overview, here are some few guidelines which should help us avoid all kind of unnecessary work or disappointment. And of course, this document is subject to discussion, so please [create an issue](https://github.com/nlohmann/json/issues/new) or a pull request if you find a way to improve it! +To make it as easy as possible for you to contribute and for me to keep an overview, here are a few guidelines which should help us avoid all kinds of unnecessary work or disappointment. And of course, this document is subject to discussion, so please [create an issue](https://github.com/nlohmann/json/issues/new) or a pull request if you find a way to improve it! ## Prerequisites -Please [create an issue](https://github.com/nlohmann/json/issues/new), assuming one does not already exist and described your concern. Note you need a [GitHub account](https://github.com/signup/free) for this. +Please [create an issue](https://github.com/nlohmann/json/issues/new), assuming one does not already exist, and describe your concern. Note you need a [GitHub account](https://github.com/signup/free) for this. If you want propose changes to the code, you need to download the [`re2c`](http://re2c.org) tool. @@ -24,7 +24,7 @@ There are currently two files which need to be edited: 1. [`src/json.hpp.re2c`](https://github.com/nlohmann/json/blob/master/src/json.hpp.re2c) (note the `.re2c` suffix) - This file contains a comment section which describes the JSON lexic. This section is translated by [`re2c`](http://re2c.org) into file [`src/json.hpp`](https://github.com/nlohmann/json/blob/master/src/json.hpp) which is plain "vanilla" C++11 code. (In fact, the generated lexer consists of some hundred lines of `goto`s, which is a hint you never want to edit this file...). - If you only edit file `src/json.hpp` (without the `.re2c`) suffix, your changes will be overwritten as soon as the lexer is touched again. To generate the `src/json.hpp` file which is actually used during compilation of the tests and all other code, please execute + If you only edit file `src/json.hpp` (without the `.re2c` suffix), your changes will be overwritten as soon as the lexer is touched again. To generate the `src/json.hpp` file which is actually used during compilation of the tests and all other code, please execute ```sh make re2c @@ -47,7 +47,7 @@ There are currently two files which need to be edited: ./json_unit ``` - The test cases are also executed with several different compilers on [Travis](https://travis-ci.org/nlohmann/json) once you opened a pull request. + The test cases are also executed with several different compilers on [Travis](https://travis-ci.org/nlohmann/json) once you open a pull request. Please understand that I cannot accept pull requests changing only file `src/json.hpp`. @@ -55,15 +55,15 @@ Please understand that I cannot accept pull requests changing only file `src/jso ## Please don't - Only make changes to file `src/json.hpp` -- please read the paragraph above and understand why `src/json.hpp.re2c` exists. -- 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 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 showed that there are ways to express the functionality that the code compiles with the most recent MSVC - unfortunately, this is not the main objective of the project. +- 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. +- 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. ## Wanted The following areas really need contribution: -- Getting the code to compile without errors with the lates **Microsoft Visual Studio** version. I am not using Windows myself, so I cannot debug code with MSVC myself. There is a job on [AppVeyor](https://ci.appveyor.com/project/nlohmann/json) though. -- Extending the **continuous integration** beyond Linux running some versions of GCC and Clang on [Travis](https://travis-ci.org/nlohmann/json) and Microsoft Visual Studio on [AppVeyor](https://ci.appveyor.com/project/nlohmann/json). We found a lot of bugs just because several compilers behave in a slightly different manner. +- Getting the code to compile without errors with the latest **Microsoft Visual Studio** version. I am not using Windows, so I cannot debug code with MSVC myself. There is a job on [AppVeyor](https://ci.appveyor.com/project/nlohmann/json) though. +- Extending the **continuous integration** beyond Linux running some versions of GCC and Clang on [Travis](https://travis-ci.org/nlohmann/json) and Microsoft Visual Studio on [AppVeyor](https://ci.appveyor.com/project/nlohmann/json). We have found a lot of bugs just because several compilers behave in a slightly different manner. - Improving the efficiency of the **JSON parser**. The current parser is implemented as a naive recursive descent parser with hand coded string handling. More sophisticated approaches like LALR parsers would be really appreciated. That said, parser generators like Bison or ANTLR do not play nice with single-header files -- I really would like to keep the parser inside the `json.hpp` header, and I am not aware of approaches similar to [`re2c`](http://re2c.org) for parsing. - Extending and updating existing **benchmarks** to include (the most recent version of) this library. Though efficiency is not everything, speed and memory consumption are very important characteristics for C++ developers, so having proper comparisons would be interesting. From 72e33eec1a7e901f50d14cea78ccdfe3428a2ac3 Mon Sep 17 00:00:00 2001 From: Niels Date: Fri, 15 Jan 2016 08:24:44 +0100 Subject: [PATCH 61/61] thanks --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index 97591f6a1..95e920f1b 100644 --- a/README.md +++ b/README.md @@ -387,6 +387,7 @@ I deeply appreciate the help of the following people. - [whackashoe](https://github.com/whackashoe) replaced a function that was marked as unsafe by Visual Studio. - [406345](https://github.com/406345) fixed two small warnings. - [Glen Fernandes](https://github.com/glenfe) noted a potential portability problem in the `has_mapped_type` function. +- [Corbin Hughes](https://github.com/nibroc) fixed some typos in the contribution guidelines. Thanks a lot for helping out!