diff --git a/neosensor/libraries/ArduinoJson/ArduinoJson.h b/neosensor/libraries/ArduinoJson/ArduinoJson.h index 7e3afa58abd03e378bdeb21f86b8220cd7b1e566..15c218f480f0be6a6e21f68eb3078d689babb515 100644 --- a/neosensor/libraries/ArduinoJson/ArduinoJson.h +++ b/neosensor/libraries/ArduinoJson/ArduinoJson.h @@ -1,5 +1,5 @@ // ArduinoJson - https://arduinojson.org -// Copyright © 2014-2022, Benoit BLANCHON +// Copyright © 2014-2023, Benoit BLANCHON // MIT License #include "src/ArduinoJson.h" diff --git a/neosensor/libraries/ArduinoJson/CHANGELOG.md b/neosensor/libraries/ArduinoJson/CHANGELOG.md index a0125a958e782238bdfa5cbd3dc9f790d16139ee..f5a9bb0adac8730db54b9990619a7fb7243215be 100644 --- a/neosensor/libraries/ArduinoJson/CHANGELOG.md +++ b/neosensor/libraries/ArduinoJson/CHANGELOG.md @@ -1,6 +1,33 @@ ArduinoJson: change log ======================= +v6.21.2 (2023-04-12) +------- + +* Fix compatibility with the Zephyr Project (issue #1905) +* Allow using PROGMEM outside of Arduino (issue #1903) +* Set default for `ARDUINOJSON_ENABLE_PROGMEM` to `1` on AVR + +v6.21.1 (2023-03-27) +------- + +* Double speed of `DynamicJsonDocument::garbageCollect()` +* Fix compatibility with GCC 5.2 (issue #1897) + +v6.21.0 (2023-03-14) +------- + +* Drop support for C++98/C++03. Minimum required is C++11. +* Remove `ARDUINOJSON_NAMESPACE`; use `ArduinoJson` instead. +* Make string support generic (issue #1807) + +v6.20.1 (2023-02-08) +------- + +* Remove explicit exclusion of `as<char*>()` and `as<char>()` (issue #1860) + If you try to call them, you'll now get the same error message as any unsupported type. + You could also add a custom converter for `char*` and `char`. + v6.20.0 (2022-12-26) ------- diff --git a/neosensor/libraries/ArduinoJson/CMakeLists.txt b/neosensor/libraries/ArduinoJson/CMakeLists.txt index 7841c0ecee9de39c4c32d268e53b70344b75c06a..ca0c6479797790806486b3f8fa77aa61847b3ead 100644 --- a/neosensor/libraries/ArduinoJson/CMakeLists.txt +++ b/neosensor/libraries/ArduinoJson/CMakeLists.txt @@ -1,19 +1,19 @@ # ArduinoJson - https://arduinojson.org -# Copyright © 2014-2022, Benoit BLANCHON +# Copyright © 2014-2023, Benoit BLANCHON # MIT License cmake_minimum_required(VERSION 3.15) if(ESP_PLATFORM) - # Build ArduinoJson as an ESP-IDF component - idf_component_register(INCLUDE_DIRS src) - return() + # Build ArduinoJson as an ESP-IDF component + idf_component_register(INCLUDE_DIRS src) + return() endif() -project(ArduinoJson VERSION 6.20.0) +project(ArduinoJson VERSION 6.21.2) if(CMAKE_PROJECT_NAME STREQUAL PROJECT_NAME) - include(CTest) + include(CTest) endif() add_subdirectory(src) diff --git a/neosensor/libraries/ArduinoJson/LICENSE.md b/neosensor/libraries/ArduinoJson/LICENSE.txt similarity index 95% rename from neosensor/libraries/ArduinoJson/LICENSE.md rename to neosensor/libraries/ArduinoJson/LICENSE.txt index dee0b5ba4d980985726e356b728359e5eed18e32..15f1b9fbb5a786a89289aa2f60bbdaf7be7d5326 100644 --- a/neosensor/libraries/ArduinoJson/LICENSE.md +++ b/neosensor/libraries/ArduinoJson/LICENSE.txt @@ -1,10 +1,10 @@ -The MIT License (MIT) ---------------------- - -Copyright © 2014-2022, Benoit BLANCHON - -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. +The MIT License (MIT) +--------------------- + +Copyright © 2014-2023, Benoit BLANCHON + +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. diff --git a/neosensor/libraries/ArduinoJson/README.md b/neosensor/libraries/ArduinoJson/README.md index 1e843d80b70415a88075930f16b1288863ffb1d9..dbd78a8a2581a0b23d7bbaedef342528d4763a49 100644 --- a/neosensor/libraries/ArduinoJson/README.md +++ b/neosensor/libraries/ArduinoJson/README.md @@ -1,17 +1,18 @@ <p align="center"> - <a href="https://arduinojson.org/"><img alt="ArduinoJson" src="logo.svg" /></a> + <a href="https://arduinojson.org/"><img alt="ArduinoJson" src="https://arduinojson.org/images/logo.svg" width="200" /></a> </p> --- -[](https://github.com/bblanchon/ArduinoJson/actions?query=workflow%3A%22Continuous+Integration%22+branch%3A6.x) +[](https://github.com/bblanchon/ArduinoJson/actions?query=workflow%3A%22Continuous+Integration%22+branch%3A6.x) [](https://ci.appveyor.com/project/bblanchon/arduinojson/branch/6.x) [](https://bugs.chromium.org/p/oss-fuzz/issues/list?sort=-opened&can=1&q=proj:arduinojson) [](https://coveralls.io/github/bblanchon/ArduinoJson?branch=6.x) -[](https://www.ardu-badge.com/ArduinoJson/6.20.0) -[](https://registry.platformio.org/packages/libraries/bblanchon/ArduinoJson?version=6.20.0) -[](https://github.com/bblanchon/ArduinoJson/stargazers) -[](https://github.com/sponsors/bblanchon) +[](https://www.ardu-badge.com/ArduinoJson/6.21.2) +[](https://registry.platformio.org/packages/libraries/bblanchon/ArduinoJson?version=6.21.2) +[](https://components.espressif.com/components/bblanchon/arduinojson) +[](https://github.com/bblanchon/ArduinoJson/stargazers) +[](https://github.com/sponsors/bblanchon) ArduinoJson is a C++ JSON library for Arduino and IoT (Internet Of Things). @@ -45,7 +46,8 @@ ArduinoJson is a C++ JSON library for Arduino and IoT (Internet Of Things). * Supports [custom converters](https://arduinojson.org/news/2021/05/04/version-6-18-0/) * Portable * Usable on any C++ project (not limited to Arduino) - * Compatible with C++98, C++11, C++14 and C++17 + * Compatible with C++11, C++14 and C++17 + * Support for C++98/C++03 available on [ArduinoJson 6.20.x](https://github.com/bblanchon/ArduinoJson/tree/6.20.x) * Zero warnings with `-Wall -Wextra -pedantic` and `/W4` * [Header-only library](https://en.wikipedia.org/wiki/Header-only) * Works with virtually any board @@ -82,9 +84,9 @@ ArduinoJson is a C++ JSON library for Arduino and IoT (Internet Of Things). * Well tested * [Unit test coverage close to 100%](https://coveralls.io/github/bblanchon/ArduinoJson?branch=6.x) * Continuously tested on - * [Visual Studio 2010, 2012, 2013, 2015, 2017, 2019, 2022](https://ci.appveyor.com/project/bblanchon/arduinojson/branch/6.x) - * [GCC 4.4, 4.6, 4.7, 4.8, 4.9, 5, 6, 7, 8, 9, 10, 11](https://github.com/bblanchon/ArduinoJson/actions?query=workflow%3A%22Continuous+Integration%22) - * [Clang 3.5, 3.6, 3.7, 3.8, 3.9, 4.0, 5.0, 6.0, 7, 8, 9, 10](https://github.com/bblanchon/ArduinoJson/actions?query=workflow%3A%22Continuous+Integration%22) + * [Visual Studio 2017, 2019, 2022](https://ci.appveyor.com/project/bblanchon/arduinojson/branch/6.x) + * [GCC 5, 6, 7, 8, 9, 10, 11](https://github.com/bblanchon/ArduinoJson/actions?query=workflow%3A%22Continuous+Integration%22) + * [Clang 3.8, 3.9, 4.0, 5.0, 6.0, 7, 8, 9, 10](https://github.com/bblanchon/ArduinoJson/actions?query=workflow%3A%22Continuous+Integration%22) * [Continuously fuzzed with Google OSS Fuzz](https://bugs.chromium.org/p/oss-fuzz/issues/list?sort=-opened&can=1&q=proj:arduinojson) * Passes all default checks of [clang-tidy](https://releases.llvm.org/10.0.0/tools/clang/tools/extra/docs/clang-tidy/) * Well documented @@ -99,7 +101,6 @@ ArduinoJson is a C++ JSON library for Arduino and IoT (Internet Of Things). * Most popular of all Arduino libraries on [GitHub](https://github.com/search?o=desc&q=arduino+library&s=stars&type=Repositories) * [Used in hundreds of projects](https://www.hackster.io/search?i=projects&q=arduinojson) * [Responsive support](https://github.com/bblanchon/ArduinoJson/issues?q=is%3Aissue+is%3Aclosed) - * [Discord server](https://discord.gg/DzN6hHHD4h) ## Quickstart diff --git a/neosensor/libraries/ArduinoJson/appveyor.yml b/neosensor/libraries/ArduinoJson/appveyor.yml index 0276d5d1572f410c5cd735b614ff078c9b53b33d..7948c646ba46f83024766908b5ddf998a1e6faf0 100644 --- a/neosensor/libraries/ArduinoJson/appveyor.yml +++ b/neosensor/libraries/ArduinoJson/appveyor.yml @@ -1,4 +1,4 @@ -version: 6.20.0.{build} +version: 6.21.2.{build} environment: matrix: - APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2022 @@ -7,15 +7,6 @@ environment: CMAKE_GENERATOR: Visual Studio 16 2019 - APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2017 CMAKE_GENERATOR: Visual Studio 15 2017 - - APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2015 - CMAKE_GENERATOR: Visual Studio 14 2015 - - CMAKE_GENERATOR: Visual Studio 12 2013 - - CMAKE_GENERATOR: Visual Studio 11 2012 - - CMAKE_GENERATOR: Visual Studio 10 2010 - - CMAKE_GENERATOR: Ninja - MINGW: MinGW # MinGW 32-bit 5.3.0 - - CMAKE_GENERATOR: Ninja - MINGW32: i686-5.3.0-posix-dwarf-rt_v4-rev0 # MinGW-w64 5.3.0 - CMAKE_GENERATOR: Ninja MINGW32: i686-6.3.0-posix-dwarf-rt_v5-rev1 # MinGW-w64 6.3.0 i686 - CMAKE_GENERATOR: Ninja diff --git a/neosensor/libraries/ArduinoJson/examples/JsonConfigFile/JsonConfigFile.ino b/neosensor/libraries/ArduinoJson/examples/JsonConfigFile/JsonConfigFile.ino index 3443ba729194b3aadbf41ac05c560a90f0cb1cff..b2819d553621d25a85d5573fe6257d6c1946d952 100644 --- a/neosensor/libraries/ArduinoJson/examples/JsonConfigFile/JsonConfigFile.ino +++ b/neosensor/libraries/ArduinoJson/examples/JsonConfigFile/JsonConfigFile.ino @@ -1,5 +1,5 @@ // ArduinoJson - https://arduinojson.org -// Copyright © 2014-2022, Benoit BLANCHON +// Copyright © 2014-2023, Benoit BLANCHON // MIT License // // This example shows how to store your project configuration in a file. diff --git a/neosensor/libraries/ArduinoJson/examples/JsonFilterExample/JsonFilterExample.ino b/neosensor/libraries/ArduinoJson/examples/JsonFilterExample/JsonFilterExample.ino index b546cd1d956b0934f11dc5fec66b1a7b9cca4388..fc980aab5c61da4eda2b37b817c6811b9cc0d0fc 100644 --- a/neosensor/libraries/ArduinoJson/examples/JsonFilterExample/JsonFilterExample.ino +++ b/neosensor/libraries/ArduinoJson/examples/JsonFilterExample/JsonFilterExample.ino @@ -1,5 +1,5 @@ // ArduinoJson - https://arduinojson.org -// Copyright © 2014-2022, Benoit BLANCHON +// Copyright © 2014-2023, Benoit BLANCHON // MIT License // // This example shows how to use DeserializationOption::Filter diff --git a/neosensor/libraries/ArduinoJson/examples/JsonGeneratorExample/JsonGeneratorExample.ino b/neosensor/libraries/ArduinoJson/examples/JsonGeneratorExample/JsonGeneratorExample.ino index ae1c0e25a43f5fc35d354d9e75224064d399c138..cf4ab0d948122606cfdb1c09e814551ebaa6905d 100644 --- a/neosensor/libraries/ArduinoJson/examples/JsonGeneratorExample/JsonGeneratorExample.ino +++ b/neosensor/libraries/ArduinoJson/examples/JsonGeneratorExample/JsonGeneratorExample.ino @@ -1,5 +1,5 @@ // ArduinoJson - https://arduinojson.org -// Copyright © 2014-2022, Benoit BLANCHON +// Copyright © 2014-2023, Benoit BLANCHON // MIT License // // This example shows how to generate a JSON document with ArduinoJson. diff --git a/neosensor/libraries/ArduinoJson/examples/JsonHttpClient/JsonHttpClient.ino b/neosensor/libraries/ArduinoJson/examples/JsonHttpClient/JsonHttpClient.ino index 8e2e6d7ba8a55e66bcb40d1205e7570c85049121..72f311fea543d2ffe1a5b6328221cccf1ae1bd28 100644 --- a/neosensor/libraries/ArduinoJson/examples/JsonHttpClient/JsonHttpClient.ino +++ b/neosensor/libraries/ArduinoJson/examples/JsonHttpClient/JsonHttpClient.ino @@ -1,5 +1,5 @@ // ArduinoJson - https://arduinojson.org -// Copyright © 2014-2022, Benoit BLANCHON +// Copyright © 2014-2023, Benoit BLANCHON // MIT License // // This example shows how to parse a JSON document in an HTTP response. diff --git a/neosensor/libraries/ArduinoJson/examples/JsonParserExample/JsonParserExample.ino b/neosensor/libraries/ArduinoJson/examples/JsonParserExample/JsonParserExample.ino index 10f14199400d88030fda3de922f2955fe22d52bf..a9d8b6d7b17c20f81fd9c66941b1fbc962223e7d 100644 --- a/neosensor/libraries/ArduinoJson/examples/JsonParserExample/JsonParserExample.ino +++ b/neosensor/libraries/ArduinoJson/examples/JsonParserExample/JsonParserExample.ino @@ -1,5 +1,5 @@ // ArduinoJson - https://arduinojson.org -// Copyright © 2014-2022, Benoit BLANCHON +// Copyright © 2014-2023, Benoit BLANCHON // MIT License // // This example shows how to deserialize a JSON document with ArduinoJson. diff --git a/neosensor/libraries/ArduinoJson/examples/JsonServer/JsonServer.ino b/neosensor/libraries/ArduinoJson/examples/JsonServer/JsonServer.ino index 52d55c5bd7c7edad11c52d080630f4c02355c66f..a897fce6da5f381175569592e5aee0af7f2e4dcb 100644 --- a/neosensor/libraries/ArduinoJson/examples/JsonServer/JsonServer.ino +++ b/neosensor/libraries/ArduinoJson/examples/JsonServer/JsonServer.ino @@ -1,5 +1,5 @@ // ArduinoJson - https://arduinojson.org -// Copyright © 2014-2022, Benoit BLANCHON +// Copyright © 2014-2023, Benoit BLANCHON // MIT License // // This example shows how to implement an HTTP server that sends a JSON document diff --git a/neosensor/libraries/ArduinoJson/examples/JsonUdpBeacon/JsonUdpBeacon.ino b/neosensor/libraries/ArduinoJson/examples/JsonUdpBeacon/JsonUdpBeacon.ino index 87965a3cc15d66ed87a97876615238a610a6cd00..6c369faa489e9f4f15d31a01972fc775ec3174d0 100644 --- a/neosensor/libraries/ArduinoJson/examples/JsonUdpBeacon/JsonUdpBeacon.ino +++ b/neosensor/libraries/ArduinoJson/examples/JsonUdpBeacon/JsonUdpBeacon.ino @@ -1,5 +1,5 @@ // ArduinoJson - https://arduinojson.org -// Copyright © 2014-2022, Benoit BLANCHON +// Copyright © 2014-2023, Benoit BLANCHON // MIT License // // This example shows how to send a JSON document to a UDP socket. diff --git a/neosensor/libraries/ArduinoJson/examples/MsgPackParser/MsgPackParser.ino b/neosensor/libraries/ArduinoJson/examples/MsgPackParser/MsgPackParser.ino index a14245b5d26366c9c40611f342d4efab8ee85955..1a54c3b3a1c4df19bc9592940a4b267202b1224a 100644 --- a/neosensor/libraries/ArduinoJson/examples/MsgPackParser/MsgPackParser.ino +++ b/neosensor/libraries/ArduinoJson/examples/MsgPackParser/MsgPackParser.ino @@ -1,5 +1,5 @@ // ArduinoJson - https://arduinojson.org -// Copyright © 2014-2022, Benoit BLANCHON +// Copyright © 2014-2023, Benoit BLANCHON // MIT License // // This example shows how to deserialize a MessagePack document with diff --git a/neosensor/libraries/ArduinoJson/examples/ProgmemExample/ProgmemExample.ino b/neosensor/libraries/ArduinoJson/examples/ProgmemExample/ProgmemExample.ino index 1a13ea00bf5ea2f40c958d7737ebb7f3bef3c20a..68b8ec562b72d645ea1da59c071537ae8bceab92 100644 --- a/neosensor/libraries/ArduinoJson/examples/ProgmemExample/ProgmemExample.ino +++ b/neosensor/libraries/ArduinoJson/examples/ProgmemExample/ProgmemExample.ino @@ -1,5 +1,5 @@ // ArduinoJson - https://arduinojson.org -// Copyright © 2014-2022, Benoit BLANCHON +// Copyright © 2014-2023, Benoit BLANCHON // MIT License // // This example shows the different ways you can use Flash strings with diff --git a/neosensor/libraries/ArduinoJson/examples/StringExample/StringExample.ino b/neosensor/libraries/ArduinoJson/examples/StringExample/StringExample.ino index 3d8f9e4ae8d8fd9b41463a9031c05f4dda31ec97..3e51b915b82d601058fcefb5aebfcf6c3e376dcd 100644 --- a/neosensor/libraries/ArduinoJson/examples/StringExample/StringExample.ino +++ b/neosensor/libraries/ArduinoJson/examples/StringExample/StringExample.ino @@ -1,5 +1,5 @@ // ArduinoJson - https://arduinojson.org -// Copyright © 2014-2022, Benoit BLANCHON +// Copyright © 2014-2023, Benoit BLANCHON // MIT License // // This example shows the different ways you can use String with ArduinoJson. diff --git a/neosensor/libraries/ArduinoJson/extras/CompileOptions.cmake b/neosensor/libraries/ArduinoJson/extras/CompileOptions.cmake index 82a750a12289698f0d857f2b3c9a68e64e469e1f..0cbd576c2a5cb9e0ecae35e422b99909b74b1926 100644 --- a/neosensor/libraries/ArduinoJson/extras/CompileOptions.cmake +++ b/neosensor/libraries/ArduinoJson/extras/CompileOptions.cmake @@ -27,11 +27,10 @@ if(CMAKE_CXX_COMPILER_ID MATCHES "(GNU|Clang)") if(${COVERAGE}) set(CMAKE_CXX_FLAGS "-fprofile-arcs -ftest-coverage") endif() - endif() -if(CMAKE_CXX_COMPILER_ID STREQUAL "GNU") - if((CMAKE_CXX_COMPILER_VERSION VERSION_GREATER 4.8) AND (NOT ${COVERAGE})) +if(CMAKE_CXX_COMPILER_ID STREQUAL "GNU") + if((CMAKE_CXX_COMPILER_VERSION VERSION_GREATER 4.8) AND(NOT ${COVERAGE})) add_compile_options(-g -Og) else() add_compile_options(-g -O0) @@ -65,7 +64,7 @@ if(CMAKE_CXX_COMPILER_ID MATCHES "Clang") endif() if(CMAKE_CXX_COMPILER_ID STREQUAL "Clang") - if((CMAKE_CXX_COMPILER_VERSION VERSION_GREATER 4.0) AND (NOT ${COVERAGE})) + if((CMAKE_CXX_COMPILER_VERSION VERSION_GREATER 4.0) AND(NOT ${COVERAGE})) add_compile_options(-g -Og) else() add_compile_options(-g -O0) @@ -73,7 +72,7 @@ if(CMAKE_CXX_COMPILER_ID STREQUAL "Clang") endif() if(CMAKE_CXX_COMPILER_ID STREQUAL "AppleClang") - if((CMAKE_CXX_COMPILER_VERSION VERSION_GREATER 9.0) AND (NOT ${COVERAGE})) + if((CMAKE_CXX_COMPILER_VERSION VERSION_GREATER 9.0) AND(NOT ${COVERAGE})) add_compile_options(-g -Og) else() add_compile_options(-g -O0) @@ -85,17 +84,12 @@ if(MSVC) add_compile_options( /W4 # Set warning level /WX # Treats all compiler warnings as errors. + /Zc:__cplusplus # Enable updated __cplusplus macro ) - - if (NOT MSVC_VERSION LESS 1910) # >= Visual Studio 2017 - add_compile_options( - /Zc:__cplusplus # Enable updated __cplusplus macro - ) - endif() endif() if(MINGW) - # Static link on MinGW to avoid linking with the wrong DLLs when multiple + # Static link on MinGW to avoid linking with the wrong DLLs when multiple # versions are installed. add_link_options(-static) endif() diff --git a/neosensor/libraries/ArduinoJson/extras/ci/espidf/CMakeLists.txt b/neosensor/libraries/ArduinoJson/extras/ci/espidf/CMakeLists.txt index e3c4475a494ac3a8ad7c554c45fd8f440b6e10d5..3b878969ac6c62c66a99146215dbfce7516e9b7c 100644 --- a/neosensor/libraries/ArduinoJson/extras/ci/espidf/CMakeLists.txt +++ b/neosensor/libraries/ArduinoJson/extras/ci/espidf/CMakeLists.txt @@ -1,5 +1,5 @@ # ArduinoJson - https://arduinojson.org -# Copyright © 2014-2022, Benoit BLANCHON +# Copyright © 2014-2023, Benoit BLANCHON # MIT License cmake_minimum_required(VERSION 3.5) diff --git a/neosensor/libraries/ArduinoJson/extras/ci/espidf/main/CMakeLists.txt b/neosensor/libraries/ArduinoJson/extras/ci/espidf/main/CMakeLists.txt index f06bfda6449e7d5cf576d2bf095a859d13442a0c..3e10ef8f8ff5866dd76d739b0e533dc7e669ce15 100644 --- a/neosensor/libraries/ArduinoJson/extras/ci/espidf/main/CMakeLists.txt +++ b/neosensor/libraries/ArduinoJson/extras/ci/espidf/main/CMakeLists.txt @@ -1,6 +1,8 @@ # ArduinoJson - https://arduinojson.org -# Copyright © 2014-2022, Benoit BLANCHON +# Copyright © 2014-2023, Benoit BLANCHON # MIT License -idf_component_register(SRCS "main.cpp" - INCLUDE_DIRS "") +idf_component_register( + SRCS "main.cpp" + INCLUDE_DIRS "" +) diff --git a/neosensor/libraries/ArduinoJson/extras/ci/espidf/main/main.cpp b/neosensor/libraries/ArduinoJson/extras/ci/espidf/main/main.cpp index 50d7ec072b5b92bef7565c5211a929c4ca4dde73..4818a6792c3e7ddaf15362c35c3c01cb6aed1dec 100644 --- a/neosensor/libraries/ArduinoJson/extras/ci/espidf/main/main.cpp +++ b/neosensor/libraries/ArduinoJson/extras/ci/espidf/main/main.cpp @@ -1,5 +1,5 @@ // ArduinoJson - https://arduinojson.org -// Copyright © 2014-2022, Benoit BLANCHON +// Copyright © 2014-2023, Benoit BLANCHON // MIT License #include <ArduinoJson.h> diff --git a/neosensor/libraries/ArduinoJson/extras/conf_test/avr.cpp b/neosensor/libraries/ArduinoJson/extras/conf_test/avr.cpp index cd0b4bdc481a1f15d87da51ea90261d2f38f300a..b2b105e394bf6049edd1fba9965a03402d6bcad1 100644 --- a/neosensor/libraries/ArduinoJson/extras/conf_test/avr.cpp +++ b/neosensor/libraries/ArduinoJson/extras/conf_test/avr.cpp @@ -1,5 +1,7 @@ #include <ArduinoJson.h> +static_assert(ARDUINOJSON_ENABLE_PROGMEM == 1, "ARDUINOJSON_ENABLE_PROGMEM"); + static_assert(ARDUINOJSON_USE_LONG_LONG == 0, "ARDUINOJSON_USE_LONG_LONG"); static_assert(ARDUINOJSON_SLOT_OFFSET_SIZE == 1, @@ -9,7 +11,7 @@ static_assert(ARDUINOJSON_LITTLE_ENDIAN == 1, "ARDUINOJSON_LITTLE_ENDIAN"); static_assert(ARDUINOJSON_USE_DOUBLE == 1, "ARDUINOJSON_USE_DOUBLE"); -static_assert(sizeof(ARDUINOJSON_NAMESPACE::VariantSlot) == 8, +static_assert(sizeof(ArduinoJson::detail::VariantSlot) == 8, "sizeof(VariantSlot)"); void setup() {} diff --git a/neosensor/libraries/ArduinoJson/extras/conf_test/esp8266.cpp b/neosensor/libraries/ArduinoJson/extras/conf_test/esp8266.cpp index bb9988bd7f0a9fc49965544c01e4d1e78e32ef64..caf70b2a3f2ebb79431df0dfa8f8e99509929da5 100644 --- a/neosensor/libraries/ArduinoJson/extras/conf_test/esp8266.cpp +++ b/neosensor/libraries/ArduinoJson/extras/conf_test/esp8266.cpp @@ -9,7 +9,7 @@ static_assert(ARDUINOJSON_LITTLE_ENDIAN == 1, "ARDUINOJSON_LITTLE_ENDIAN"); static_assert(ARDUINOJSON_USE_DOUBLE == 1, "ARDUINOJSON_USE_DOUBLE"); -static_assert(sizeof(ARDUINOJSON_NAMESPACE::VariantSlot) == 16, +static_assert(sizeof(ArduinoJson::detail::VariantSlot) == 16, "sizeof(VariantSlot)"); void setup() {} diff --git a/neosensor/libraries/ArduinoJson/extras/conf_test/x64.cpp b/neosensor/libraries/ArduinoJson/extras/conf_test/x64.cpp index 8cd6c06e0813dd35ea736de4a6372166b978cf4d..97838e34e92837e85e500e61838ecd093a1ee64a 100644 --- a/neosensor/libraries/ArduinoJson/extras/conf_test/x64.cpp +++ b/neosensor/libraries/ArduinoJson/extras/conf_test/x64.cpp @@ -9,7 +9,7 @@ static_assert(ARDUINOJSON_LITTLE_ENDIAN == 1, "ARDUINOJSON_LITTLE_ENDIAN"); static_assert(ARDUINOJSON_USE_DOUBLE == 1, "ARDUINOJSON_USE_DOUBLE"); -static_assert(sizeof(ARDUINOJSON_NAMESPACE::VariantSlot) == 32, +static_assert(sizeof(ArduinoJson::detail::VariantSlot) == 32, "sizeof(VariantSlot)"); int main() {} diff --git a/neosensor/libraries/ArduinoJson/extras/conf_test/x86.cpp b/neosensor/libraries/ArduinoJson/extras/conf_test/x86.cpp index dab9da61004b4ea0f8ac8ee676573f01ba844cf5..f3dab30ffaa0388fd4cb743803e164739e3a6f44 100644 --- a/neosensor/libraries/ArduinoJson/extras/conf_test/x86.cpp +++ b/neosensor/libraries/ArduinoJson/extras/conf_test/x86.cpp @@ -9,7 +9,7 @@ static_assert(ARDUINOJSON_LITTLE_ENDIAN == 1, "ARDUINOJSON_LITTLE_ENDIAN"); static_assert(ARDUINOJSON_USE_DOUBLE == 1, "ARDUINOJSON_USE_DOUBLE"); -static_assert(sizeof(ARDUINOJSON_NAMESPACE::VariantSlot) == 16, +static_assert(sizeof(ArduinoJson::detail::VariantSlot) == 16, "sizeof(VariantSlot)"); int main() {} diff --git a/neosensor/libraries/ArduinoJson/extras/fuzzing/CMakeLists.txt b/neosensor/libraries/ArduinoJson/extras/fuzzing/CMakeLists.txt index e5d6a36e6ca862890186e52979d2920632631072..1d439f46b24498b96e5352c2f25db01d2358770f 100644 --- a/neosensor/libraries/ArduinoJson/extras/fuzzing/CMakeLists.txt +++ b/neosensor/libraries/ArduinoJson/extras/fuzzing/CMakeLists.txt @@ -1,7 +1,10 @@ # ArduinoJson - https://arduinojson.org -# Copyright © 2014-2022, Benoit BLANCHON +# Copyright © 2014-2023, Benoit BLANCHON # MIT License +set(CMAKE_CXX_STANDARD 11) +set(CMAKE_CXX_STANDARD_REQUIRED ON) + if(MSVC) add_compile_options(-D_CRT_SECURE_NO_WARNINGS) endif() @@ -22,7 +25,7 @@ target_link_libraries(json_reproducer ArduinoJson ) -macro(add_fuzzer name) +macro(add_fuzzer name) set(FUZZER "${name}_fuzzer") set(CORPUS_DIR "${CMAKE_CURRENT_SOURCE_DIR}/${name}_corpus") set(SEED_CORPUS_DIR "${CMAKE_CURRENT_SOURCE_DIR}/${name}_seed_corpus") @@ -33,27 +36,23 @@ macro(add_fuzzer name) ArduinoJson ) set_target_properties("${FUZZER}" - PROPERTIES - COMPILE_FLAGS - "-fprofile-instr-generate -fcoverage-mapping -fsanitize=fuzzer -fno-sanitize-recover=all" - LINK_FLAGS - "-fprofile-instr-generate -fcoverage-mapping -fsanitize=fuzzer -fno-sanitize-recover=all" + PROPERTIES + COMPILE_FLAGS "-fprofile-instr-generate -fcoverage-mapping -fsanitize=fuzzer -fno-sanitize-recover=all" + LINK_FLAGS "-fprofile-instr-generate -fcoverage-mapping -fsanitize=fuzzer -fno-sanitize-recover=all" ) add_test( - NAME - "${FUZZER}" - COMMAND - "${FUZZER}" "${CORPUS_DIR}" "${SEED_CORPUS_DIR}" -max_total_time=5 -timeout=1 + NAME "${FUZZER}" + COMMAND "${FUZZER}" "${CORPUS_DIR}" "${SEED_CORPUS_DIR}" -max_total_time=5 -timeout=1 ) set_tests_properties("${FUZZER}" PROPERTIES - LABELS "Fuzzing" + LABELS "Fuzzing" ) endmacro() -if (CMAKE_CXX_COMPILER_ID STREQUAL "Clang" AND CMAKE_CXX_COMPILER_VERSION VERSION_GREATER 6) +if(CMAKE_CXX_COMPILER_ID STREQUAL "Clang" AND CMAKE_CXX_COMPILER_VERSION VERSION_GREATER 6) add_fuzzer(json) add_fuzzer(msgpack) endif() diff --git a/neosensor/libraries/ArduinoJson/extras/fuzzing/Makefile b/neosensor/libraries/ArduinoJson/extras/fuzzing/Makefile index d3c574e18d410db65342ad0e1f1776d41fd54ec0..81fc412570969f0349c6a95e4c05a17134f8eb17 100644 --- a/neosensor/libraries/ArduinoJson/extras/fuzzing/Makefile +++ b/neosensor/libraries/ArduinoJson/extras/fuzzing/Makefile @@ -1,6 +1,6 @@ # CAUTION: this file is invoked by https://github.com/google/oss-fuzz -CXXFLAGS += -I../../src -DARDUINOJSON_DEBUG=1 +CXXFLAGS += -I../../src -DARDUINOJSON_DEBUG=1 -std=c++11 all: \ $(OUT)/json_fuzzer \ diff --git a/neosensor/libraries/ArduinoJson/extras/fuzzing/reproducer.cpp b/neosensor/libraries/ArduinoJson/extras/fuzzing/reproducer.cpp index 86818012f355183198addca838c54166e9960b8f..a004d01eee112a9b499bcf85d8faaa2b705cb144 100644 --- a/neosensor/libraries/ArduinoJson/extras/fuzzing/reproducer.cpp +++ b/neosensor/libraries/ArduinoJson/extras/fuzzing/reproducer.cpp @@ -1,5 +1,5 @@ // ArduinoJson - https://arduinojson.org -// Copyright © 2014-2022, Benoit BLANCHON +// Copyright © 2014-2023, Benoit BLANCHON // MIT License // This file is NOT use by Google's OSS fuzz diff --git a/neosensor/libraries/ArduinoJson/extras/scripts/build-arduino-package.sh b/neosensor/libraries/ArduinoJson/extras/scripts/build-arduino-package.sh index 339db2f6240c9e54f6309f5b6a492f217788704e..09f6efb3077dc646522cb9e83b592e699db5c62c 100644 --- a/neosensor/libraries/ArduinoJson/extras/scripts/build-arduino-package.sh +++ b/neosensor/libraries/ArduinoJson/extras/scripts/build-arduino-package.sh @@ -18,6 +18,6 @@ rm -f "$OUTPUT" src \ keywords.txt \ library.properties \ - LICENSE.md \ + LICENSE.txt \ README.md \ ArduinoJson.h diff --git a/neosensor/libraries/ArduinoJson/extras/scripts/build-single-header.sh b/neosensor/libraries/ArduinoJson/extras/scripts/build-single-header.sh index 09d91d419bdf6509baf46008fc88b4dffe143a79..00292e307c5455086ace5a50454f4b5f78be9239 100644 --- a/neosensor/libraries/ArduinoJson/extras/scripts/build-single-header.sh +++ b/neosensor/libraries/ArduinoJson/extras/scripts/build-single-header.sh @@ -53,7 +53,8 @@ process() } simplify_namespaces() { - perl -p0i -e 's|\} // namespace ARDUINOJSON_NAMESPACE\r?\nnamespace ARDUINOJSON_NAMESPACE \{\r?\n||igs' "$1" + perl -p0i -e 's|ARDUINOJSON_END_PUBLIC_NAMESPACE\r?\nARDUINOJSON_BEGIN_PUBLIC_NAMESPACE\r?\n||igs' "$1" + perl -p0i -e 's|ARDUINOJSON_END_PRIVATE_NAMESPACE\r?\nARDUINOJSON_BEGIN_PRIVATE_NAMESPACE\r?\n||igs' "$1" rm -f "$1.bak" } diff --git a/neosensor/libraries/ArduinoJson/extras/scripts/publish-particle-library.sh b/neosensor/libraries/ArduinoJson/extras/scripts/publish-particle-library.sh index 62c3140f5c71ffe005677976b72f7d6c4ec31574..3ee7f91226bdbeb08d6f1380bdda1e87b180e611 100644 --- a/neosensor/libraries/ArduinoJson/extras/scripts/publish-particle-library.sh +++ b/neosensor/libraries/ArduinoJson/extras/scripts/publish-particle-library.sh @@ -9,10 +9,10 @@ trap 'rm -rf "$WORK_DIR"' EXIT cp "$SOURCE_DIR/README.md" "$WORK_DIR/README.md" cp "$SOURCE_DIR/CHANGELOG.md" "$WORK_DIR/CHANGELOG.md" cp "$SOURCE_DIR/library.properties" "$WORK_DIR/library.properties" -cp "$SOURCE_DIR/LICENSE.md" "$WORK_DIR/LICENSE.txt" +cp "$SOURCE_DIR/LICENSE.txt" "$WORK_DIR/LICENSE.txt" cp -r "$SOURCE_DIR/src" "$WORK_DIR/" cp -r "$SOURCE_DIR/examples" "$WORK_DIR/" cd "$WORK_DIR" -particle library upload -particle library publish +particle library upload -v +particle library publish -v diff --git a/neosensor/libraries/ArduinoJson/extras/scripts/publish.sh b/neosensor/libraries/ArduinoJson/extras/scripts/publish.sh index c5a4eefd35a4a01e19ebef987b9a1c842296fe14..a562a24cb576ffa39788ba9f9a4f59d19ba5dba8 100644 --- a/neosensor/libraries/ArduinoJson/extras/scripts/publish.sh +++ b/neosensor/libraries/ArduinoJson/extras/scripts/publish.sh @@ -38,6 +38,9 @@ update_version_in_source () { sed -i~ -bE "s/version: .*$/version: $VERSION.{build}/" appveyor.yml rm appveyor.yml~ + sed -i~ -bE "s/^version: .*$/version: \"$VERSION\"/" idf_component.yml + rm idf_component.yml~ + sed -i~ -bE \ -e "s/ARDUINOJSON_VERSION .*$/ARDUINOJSON_VERSION \"$VERSION\"/" \ -e "s/ARDUINOJSON_VERSION_MAJOR .*$/ARDUINOJSON_VERSION_MAJOR $MAJOR/" \ @@ -48,7 +51,7 @@ update_version_in_source () { } commit_new_version () { - git add src/ArduinoJson/version.hpp README.md CHANGELOG.md library.json library.properties appveyor.yml CMakeLists.txt + git add src/ArduinoJson/version.hpp README.md CHANGELOG.md library.json library.properties appveyor.yml CMakeLists.txt idf_component.yml git commit -m "Set version to $VERSION" } diff --git a/neosensor/libraries/ArduinoJson/extras/scripts/wandbox/JsonGeneratorExample.cpp b/neosensor/libraries/ArduinoJson/extras/scripts/wandbox/JsonGeneratorExample.cpp index 0090c849f1dfb38ba81050a86815085005dc447e..b35d1856ab13b2165af46be49c92c4c75b271cad 100644 --- a/neosensor/libraries/ArduinoJson/extras/scripts/wandbox/JsonGeneratorExample.cpp +++ b/neosensor/libraries/ArduinoJson/extras/scripts/wandbox/JsonGeneratorExample.cpp @@ -1,5 +1,5 @@ // ArduinoJson - https://arduinojson.org -// Copyright © 2014-2022, Benoit BLANCHON +// Copyright © 2014-2023, Benoit BLANCHON // MIT License // // This example shows how to generate a JSON document with ArduinoJson. diff --git a/neosensor/libraries/ArduinoJson/extras/scripts/wandbox/JsonParserExample.cpp b/neosensor/libraries/ArduinoJson/extras/scripts/wandbox/JsonParserExample.cpp index f513caff23ae66455d053c6834c6aca298358240..396f98cb0178c2473b76ad426574c9cdbb5b9740 100644 --- a/neosensor/libraries/ArduinoJson/extras/scripts/wandbox/JsonParserExample.cpp +++ b/neosensor/libraries/ArduinoJson/extras/scripts/wandbox/JsonParserExample.cpp @@ -1,5 +1,5 @@ // ArduinoJson - https://arduinojson.org -// Copyright © 2014-2022, Benoit BLANCHON +// Copyright © 2014-2023, Benoit BLANCHON // MIT License // // This example shows how to deserialize a JSON document with ArduinoJson. diff --git a/neosensor/libraries/ArduinoJson/extras/scripts/wandbox/MsgPackParserExample.cpp b/neosensor/libraries/ArduinoJson/extras/scripts/wandbox/MsgPackParserExample.cpp index 186816e610f005bf060bcbc8f90173e9c2dcede4..763de84e6a5a6ffd87a6c39c31dbfa74d861f7d7 100644 --- a/neosensor/libraries/ArduinoJson/extras/scripts/wandbox/MsgPackParserExample.cpp +++ b/neosensor/libraries/ArduinoJson/extras/scripts/wandbox/MsgPackParserExample.cpp @@ -1,5 +1,5 @@ // ArduinoJson - https://arduinojson.org -// Copyright © 2014-2022, Benoit BLANCHON +// Copyright © 2014-2023, Benoit BLANCHON // MIT License // // This example shows how to generate a JSON document with ArduinoJson. diff --git a/neosensor/libraries/ArduinoJson/extras/tests/CMakeLists.txt b/neosensor/libraries/ArduinoJson/extras/tests/CMakeLists.txt index faf4cd9a6015d03e946d50155541de877aebd95e..c62401f97094598393a6e72edc8a599c36c29b51 100644 --- a/neosensor/libraries/ArduinoJson/extras/tests/CMakeLists.txt +++ b/neosensor/libraries/ArduinoJson/extras/tests/CMakeLists.txt @@ -1,8 +1,8 @@ # ArduinoJson - https://arduinojson.org -# Copyright © 2014-2022, Benoit BLANCHON +# Copyright © 2014-2023, Benoit BLANCHON # MIT License -set(CMAKE_CXX_STANDARD 98) +set(CMAKE_CXX_STANDARD 11) set(CMAKE_CXX_STANDARD_REQUIRED ON) add_subdirectory(catch) @@ -10,7 +10,6 @@ add_subdirectory(catch) link_libraries(ArduinoJson catch) include_directories(Helpers) -add_subdirectory(Cpp11) add_subdirectory(Cpp17) add_subdirectory(Cpp20) add_subdirectory(FailingBuilds) diff --git a/neosensor/libraries/ArduinoJson/extras/tests/Cpp11/CMakeLists.txt b/neosensor/libraries/ArduinoJson/extras/tests/Cpp11/CMakeLists.txt deleted file mode 100644 index 0b84a14c75b1664e54aa935213e70c953c963914..0000000000000000000000000000000000000000 --- a/neosensor/libraries/ArduinoJson/extras/tests/Cpp11/CMakeLists.txt +++ /dev/null @@ -1,36 +0,0 @@ -# ArduinoJson - https://arduinojson.org -# Copyright © 2014-2022, Benoit BLANCHON -# MIT License - -if("cxx_nullptr" IN_LIST CMAKE_CXX_COMPILE_FEATURES) - list(APPEND SOURCES nullptr.cpp) - add_definitions(-DARDUINOJSON_HAS_NULLPTR=1) -endif() - -if("cxx_auto_type" IN_LIST CMAKE_CXX_COMPILE_FEATURES AND "cxx_constexpr" IN_LIST CMAKE_CXX_COMPILE_FEATURES) - list(APPEND SOURCES issue1120.cpp) -endif() - -if("cxx_long_long_type" IN_LIST CMAKE_CXX_COMPILE_FEATURES) - list(APPEND SOURCES use_long_long_0.cpp use_long_long_1.cpp) -endif() - -if("cxx_range_for" IN_LIST CMAKE_CXX_COMPILE_FEATURES AND "cxx_generalized_initializers" IN_LIST CMAKE_CXX_COMPILE_FEATURES) - list(APPEND SOURCES stl_containers.cpp) -endif() - -if(NOT SOURCES) - return() -endif() - -set(CMAKE_CXX_STANDARD 11) -set(CMAKE_CXX_STANDARD_REQUIRED ON) - -add_executable(Cpp11Tests ${SOURCES}) - -add_test(Cpp11 Cpp11Tests) - -set_tests_properties(Cpp11 - PROPERTIES - LABELS "Catch" -) diff --git a/neosensor/libraries/ArduinoJson/extras/tests/Cpp11/stl_containers.cpp b/neosensor/libraries/ArduinoJson/extras/tests/Cpp11/stl_containers.cpp deleted file mode 100644 index 9e590c14ac6d14ddc2bc0ea3f3ced15479eb4310..0000000000000000000000000000000000000000 --- a/neosensor/libraries/ArduinoJson/extras/tests/Cpp11/stl_containers.cpp +++ /dev/null @@ -1,72 +0,0 @@ -// ArduinoJson - https://arduinojson.org -// Copyright © 2014-2022, Benoit BLANCHON -// MIT License - -#include <ArduinoJson.h> -#include <stdint.h> -#include <catch.hpp> - -#include <string> -#include <vector> - -namespace ARDUINOJSON_NAMESPACE { -template <typename T> -struct Converter<std::vector<T> > { - static void toJson(const std::vector<T>& src, JsonVariant dst) { - JsonArray array = dst.to<JsonArray>(); - for (T item : src) - array.add(item); - } - - static std::vector<T> fromJson(JsonVariantConst src) { - std::vector<T> dst; - for (T item : src.as<JsonArrayConst>()) - dst.push_back(item); - return dst; - } - - static bool checkJson(JsonVariantConst src) { - JsonArrayConst array = src; - bool result = array; - for (JsonVariantConst item : array) { - if (!result) - break; - result = item.is<T>(); - } - return result; - } -}; -} // namespace ARDUINOJSON_NAMESPACE - -TEST_CASE("vector<int>") { - SECTION("toJson") { - std::vector<int> v = {1, 2}; - - StaticJsonDocument<128> doc; - doc.set(v); - REQUIRE(doc.as<std::string>() == "[1,2]"); - } - - SECTION("fromJson") { - StaticJsonDocument<128> doc; - doc.add(1); - doc.add(2); - - auto v = doc.as<std::vector<int> >(); - REQUIRE(v.size() == 2); - CHECK(v[0] == 1); - CHECK(v[1] == 2); - } - - SECTION("checkJson") { - StaticJsonDocument<128> doc; - CHECK(doc.is<std::vector<int> >() == false); - - doc.add(1); - doc.add(2); - CHECK(doc.is<std::vector<int> >() == true); - - doc.add("foo"); - CHECK(doc.is<std::vector<int> >() == false); - } -} diff --git a/neosensor/libraries/ArduinoJson/extras/tests/Cpp17/CMakeLists.txt b/neosensor/libraries/ArduinoJson/extras/tests/Cpp17/CMakeLists.txt index 05af20076981bc55ae08ef5552611a0cf6eabc33..62f2784ff96c994f36d11d36842051cc746f13cc 100644 --- a/neosensor/libraries/ArduinoJson/extras/tests/Cpp17/CMakeLists.txt +++ b/neosensor/libraries/ArduinoJson/extras/tests/Cpp17/CMakeLists.txt @@ -1,5 +1,5 @@ # ArduinoJson - https://arduinojson.org -# Copyright © 2014-2022, Benoit BLANCHON +# Copyright © 2014-2023, Benoit BLANCHON # MIT License if(MSVC_VERSION LESS 1910) @@ -25,5 +25,5 @@ add_test(Cpp17 Cpp17Tests) set_tests_properties(Cpp17 PROPERTIES - LABELS "Catch" + LABELS "Catch" ) diff --git a/neosensor/libraries/ArduinoJson/extras/tests/Cpp17/string_view.cpp b/neosensor/libraries/ArduinoJson/extras/tests/Cpp17/string_view.cpp index 729c59ae9fb3c852fc7f8f09023623aa4981106d..6a51ce2d9b2e5df82d2c810f73b1442df0b04169 100644 --- a/neosensor/libraries/ArduinoJson/extras/tests/Cpp17/string_view.cpp +++ b/neosensor/libraries/ArduinoJson/extras/tests/Cpp17/string_view.cpp @@ -1,6 +1,6 @@ #include <ArduinoJson.h> - #include <catch.hpp> + #include <string_view> #if !ARDUINOJSON_ENABLE_STRING_VIEW @@ -86,7 +86,7 @@ TEST_CASE("string_view") { } } -using ARDUINOJSON_NAMESPACE::adaptString; +using ArduinoJson::detail::adaptString; TEST_CASE("StringViewAdapter") { std::string_view str("bravoXXX", 5); diff --git a/neosensor/libraries/ArduinoJson/extras/tests/Cpp20/CMakeLists.txt b/neosensor/libraries/ArduinoJson/extras/tests/Cpp20/CMakeLists.txt index 2c9a72b0509c0e079798c9100a6455b9e6980733..e993e974b6008418d07dfb6ae5f0542724f36c60 100644 --- a/neosensor/libraries/ArduinoJson/extras/tests/Cpp20/CMakeLists.txt +++ b/neosensor/libraries/ArduinoJson/extras/tests/Cpp20/CMakeLists.txt @@ -1,5 +1,5 @@ # ArduinoJson - https://arduinojson.org -# Copyright © 2014-2022, Benoit BLANCHON +# Copyright © 2014-2023, Benoit BLANCHON # MIT License if(MSVC_VERSION LESS 1910) @@ -25,5 +25,5 @@ add_test(Cpp20 Cpp20Tests) set_tests_properties(Cpp20 PROPERTIES - LABELS "Catch" + LABELS "Catch" ) diff --git a/neosensor/libraries/ArduinoJson/extras/tests/FailingBuilds/CMakeLists.txt b/neosensor/libraries/ArduinoJson/extras/tests/FailingBuilds/CMakeLists.txt index dc76c9108a1d846b28793bd3790328a891c24d83..0464908c92e9c98e48757bd6bb455a4484967980 100644 --- a/neosensor/libraries/ArduinoJson/extras/tests/FailingBuilds/CMakeLists.txt +++ b/neosensor/libraries/ArduinoJson/extras/tests/FailingBuilds/CMakeLists.txt @@ -1,29 +1,25 @@ # ArduinoJson - https://arduinojson.org -# Copyright © 2014-2022, Benoit BLANCHON +# Copyright © 2014-2023, Benoit BLANCHON # MIT License macro(build_should_fail target) set_target_properties(${target} PROPERTIES - EXCLUDE_FROM_ALL TRUE - EXCLUDE_FROM_DEFAULT_BUILD TRUE + EXCLUDE_FROM_ALL TRUE + EXCLUDE_FROM_DEFAULT_BUILD TRUE ) add_test( - NAME - ${target} - COMMAND - ${CMAKE_COMMAND} --build . --target ${target} --config $<CONFIGURATION> - WORKING_DIRECTORY - ${CMAKE_BINARY_DIR} + NAME ${target} + COMMAND ${CMAKE_COMMAND} --build . --target ${target} --config $<CONFIGURATION> + WORKING_DIRECTORY ${CMAKE_BINARY_DIR} ) - set_tests_properties(${target} + set_tests_properties(${target} PROPERTIES - WILL_FAIL TRUE - LABELS "WillFail;Catch" + WILL_FAIL TRUE + LABELS "WillFail;Catch" ) endmacro() - add_executable(Issue978 Issue978.cpp) build_should_fail(Issue978) @@ -31,11 +27,9 @@ add_executable(Issue1189 Issue1189.cpp) build_should_fail(Issue1189) add_executable(read_long_long read_long_long.cpp) -set_property(TARGET read_long_long PROPERTY CXX_STANDARD 11) build_should_fail(read_long_long) add_executable(write_long_long write_long_long.cpp) -set_property(TARGET write_long_long PROPERTY CXX_STANDARD 11) build_should_fail(write_long_long) add_executable(delete_jsondocument delete_jsondocument.cpp) diff --git a/neosensor/libraries/ArduinoJson/extras/tests/FailingBuilds/Issue1189.cpp b/neosensor/libraries/ArduinoJson/extras/tests/FailingBuilds/Issue1189.cpp index e86bb992608c67956350157b66e1e5931a142ee8..40cb59f8f8875a16ec039d918698aef97f21d9f7 100644 --- a/neosensor/libraries/ArduinoJson/extras/tests/FailingBuilds/Issue1189.cpp +++ b/neosensor/libraries/ArduinoJson/extras/tests/FailingBuilds/Issue1189.cpp @@ -1,5 +1,5 @@ // ArduinoJson - https://arduinojson.org -// Copyright © 2014-2022, Benoit BLANCHON +// Copyright © 2014-2023, Benoit BLANCHON // MIT License #include <ArduinoJson.h> diff --git a/neosensor/libraries/ArduinoJson/extras/tests/FailingBuilds/Issue978.cpp b/neosensor/libraries/ArduinoJson/extras/tests/FailingBuilds/Issue978.cpp index 112d36d820bcca238a46312aff09b917c70f438c..d85aaa0c8848fb85d4c4e3ced9f8ccaf5735cff8 100644 --- a/neosensor/libraries/ArduinoJson/extras/tests/FailingBuilds/Issue978.cpp +++ b/neosensor/libraries/ArduinoJson/extras/tests/FailingBuilds/Issue978.cpp @@ -1,5 +1,5 @@ // ArduinoJson - https://arduinojson.org -// Copyright © 2014-2022, Benoit BLANCHON +// Copyright © 2014-2023, Benoit BLANCHON // MIT License #include <ArduinoJson.h> diff --git a/neosensor/libraries/ArduinoJson/extras/tests/FailingBuilds/assign_char.cpp b/neosensor/libraries/ArduinoJson/extras/tests/FailingBuilds/assign_char.cpp index 633b54de379eaaa9147474491ebdd17df85da169..b9d897f776c3f21592f87cd6a17a4dba3c66c5fd 100644 --- a/neosensor/libraries/ArduinoJson/extras/tests/FailingBuilds/assign_char.cpp +++ b/neosensor/libraries/ArduinoJson/extras/tests/FailingBuilds/assign_char.cpp @@ -1,5 +1,5 @@ // ArduinoJson - https://arduinojson.org -// Copyright © 2014-2022, Benoit BLANCHON +// Copyright © 2014-2023, Benoit BLANCHON // MIT License #include <ArduinoJson.h> diff --git a/neosensor/libraries/ArduinoJson/extras/tests/FailingBuilds/delete_jsondocument.cpp b/neosensor/libraries/ArduinoJson/extras/tests/FailingBuilds/delete_jsondocument.cpp index ef2b0e86bf5e66e610f8627346fcc731b4a68f9d..174b80a5d16f03310f6bed798f791c38e8941eff 100644 --- a/neosensor/libraries/ArduinoJson/extras/tests/FailingBuilds/delete_jsondocument.cpp +++ b/neosensor/libraries/ArduinoJson/extras/tests/FailingBuilds/delete_jsondocument.cpp @@ -1,5 +1,5 @@ // ArduinoJson - https://arduinojson.org -// Copyright © 2014-2022, Benoit BLANCHON +// Copyright © 2014-2023, Benoit BLANCHON // MIT License #include <ArduinoJson.h> diff --git a/neosensor/libraries/ArduinoJson/extras/tests/FailingBuilds/read_long_long.cpp b/neosensor/libraries/ArduinoJson/extras/tests/FailingBuilds/read_long_long.cpp index d900a7f3401b00788231356f811f542fd3511ee1..6fe5992a1db2ae4985068bc128ddd14319c2b351 100644 --- a/neosensor/libraries/ArduinoJson/extras/tests/FailingBuilds/read_long_long.cpp +++ b/neosensor/libraries/ArduinoJson/extras/tests/FailingBuilds/read_long_long.cpp @@ -1,5 +1,5 @@ // ArduinoJson - https://arduinojson.org -// Copyright © 2014-2022, Benoit BLANCHON +// Copyright © 2014-2023, Benoit BLANCHON // MIT License #define ARDUINOJSON_USE_LONG_LONG 0 @@ -9,10 +9,6 @@ # error This test requires sizeof(long) < 8 #endif -#if !ARDUINOJSON_HAS_LONG_LONG -# error This test requires C++11 -#endif - ARDUINOJSON_ASSERT_INTEGER_TYPE_IS_SUPPORTED(long long) int main() { DynamicJsonDocument doc(1024); diff --git a/neosensor/libraries/ArduinoJson/extras/tests/FailingBuilds/variant_as_char.cpp b/neosensor/libraries/ArduinoJson/extras/tests/FailingBuilds/variant_as_char.cpp index 41885cf6fbda343953dc2d2ddedbf129730b0a85..1a9e8342ffc02a1475e7e43186893bab34a7e3c5 100644 --- a/neosensor/libraries/ArduinoJson/extras/tests/FailingBuilds/variant_as_char.cpp +++ b/neosensor/libraries/ArduinoJson/extras/tests/FailingBuilds/variant_as_char.cpp @@ -1,5 +1,5 @@ // ArduinoJson - https://arduinojson.org -// Copyright © 2014-2022, Benoit BLANCHON +// Copyright © 2014-2023, Benoit BLANCHON // MIT License #include <ArduinoJson.h> diff --git a/neosensor/libraries/ArduinoJson/extras/tests/FailingBuilds/write_long_long.cpp b/neosensor/libraries/ArduinoJson/extras/tests/FailingBuilds/write_long_long.cpp index 2213a4dc0408605bd908cc5494c5ceff7289c9a3..6ff835651d6431167eb33220652e4c2584fd4f65 100644 --- a/neosensor/libraries/ArduinoJson/extras/tests/FailingBuilds/write_long_long.cpp +++ b/neosensor/libraries/ArduinoJson/extras/tests/FailingBuilds/write_long_long.cpp @@ -1,5 +1,5 @@ // ArduinoJson - https://arduinojson.org -// Copyright © 2014-2022, Benoit BLANCHON +// Copyright © 2014-2023, Benoit BLANCHON // MIT License #define ARDUINOJSON_USE_LONG_LONG 0 @@ -9,10 +9,6 @@ # error This test requires sizeof(long) < 8 #endif -#if !ARDUINOJSON_HAS_LONG_LONG -# error This test requires C++11 -#endif - int main() { DynamicJsonDocument doc(1024); doc["dummy"] = static_cast<long long>(42); diff --git a/neosensor/libraries/ArduinoJson/extras/tests/Helpers/Arduino.h b/neosensor/libraries/ArduinoJson/extras/tests/Helpers/Arduino.h index 4f24b263ef3dfd74f37c7e6a319044ee2916353c..ef3640d9c0de264c0d8d285dfbb84e8c4f5a9cf1 100644 --- a/neosensor/libraries/ArduinoJson/extras/tests/Helpers/Arduino.h +++ b/neosensor/libraries/ArduinoJson/extras/tests/Helpers/Arduino.h @@ -1,5 +1,5 @@ // ArduinoJson - https://arduinojson.org -// Copyright © 2014-2022, Benoit BLANCHON +// Copyright © 2014-2023, Benoit BLANCHON // MIT License #pragma once @@ -7,6 +7,7 @@ #include "api/Print.h" #include "api/Stream.h" #include "api/String.h" -#include "progmem_emulation.hpp" +#include "avr/pgmspace.h" +#define ARDUINO #define ARDUINO_H_INCLUDED 1 diff --git a/neosensor/libraries/ArduinoJson/extras/tests/Helpers/CustomReader.hpp b/neosensor/libraries/ArduinoJson/extras/tests/Helpers/CustomReader.hpp index 8a97b50343047d993425e3e5e1616608d4e1f292..66525a25bf9838d921e4528b64a395bf17f5c390 100644 --- a/neosensor/libraries/ArduinoJson/extras/tests/Helpers/CustomReader.hpp +++ b/neosensor/libraries/ArduinoJson/extras/tests/Helpers/CustomReader.hpp @@ -1,5 +1,5 @@ // ArduinoJson - https://arduinojson.org -// Copyright © 2014-2022, Benoit BLANCHON +// Copyright © 2014-2023, Benoit BLANCHON // MIT License #pragma once @@ -7,20 +7,18 @@ #include <sstream> class CustomReader { - std::stringstream _stream; + std::stringstream stream_; public: - CustomReader(const char* input) : _stream(input) {} + CustomReader(const char* input) : stream_(input) {} + CustomReader(const CustomReader&) = delete; int read() { - return _stream.get(); + return stream_.get(); } size_t readBytes(char* buffer, size_t length) { - _stream.read(buffer, static_cast<std::streamsize>(length)); - return static_cast<size_t>(_stream.gcount()); + stream_.read(buffer, static_cast<std::streamsize>(length)); + return static_cast<size_t>(stream_.gcount()); } - - private: - CustomReader(const CustomReader&); }; diff --git a/neosensor/libraries/ArduinoJson/extras/tests/Helpers/api/Print.h b/neosensor/libraries/ArduinoJson/extras/tests/Helpers/api/Print.h index 864fb41a00c07674d757a94f8e7ccd42bdf1b629..d3c27ccfe6e02596377804c500bcd3b15908da39 100644 --- a/neosensor/libraries/ArduinoJson/extras/tests/Helpers/api/Print.h +++ b/neosensor/libraries/ArduinoJson/extras/tests/Helpers/api/Print.h @@ -1,5 +1,5 @@ // ArduinoJson - https://arduinojson.org -// Copyright © 2014-2022, Benoit BLANCHON +// Copyright © 2014-2023, Benoit BLANCHON // MIT License #pragma once diff --git a/neosensor/libraries/ArduinoJson/extras/tests/Helpers/api/Stream.h b/neosensor/libraries/ArduinoJson/extras/tests/Helpers/api/Stream.h index 8cc18d2b4dc36c4d26ec0142ba3bfaf8e850b564..387940bb83f31f012de91eab93d6db0bb707b769 100644 --- a/neosensor/libraries/ArduinoJson/extras/tests/Helpers/api/Stream.h +++ b/neosensor/libraries/ArduinoJson/extras/tests/Helpers/api/Stream.h @@ -1,5 +1,5 @@ // ArduinoJson - https://arduinojson.org -// Copyright © 2014-2022, Benoit BLANCHON +// Copyright © 2014-2023, Benoit BLANCHON // MIT License #pragma once diff --git a/neosensor/libraries/ArduinoJson/extras/tests/Helpers/api/String.h b/neosensor/libraries/ArduinoJson/extras/tests/Helpers/api/String.h index e55ea44540e57a5f84f30a9a26e4f1e2fa0a3e18..64c763f943e3ae0f199eb378bb7dcd3e13451fd7 100644 --- a/neosensor/libraries/ArduinoJson/extras/tests/Helpers/api/String.h +++ b/neosensor/libraries/ArduinoJson/extras/tests/Helpers/api/String.h @@ -1,5 +1,5 @@ // ArduinoJson - https://arduinojson.org -// Copyright © 2014-2022, Benoit BLANCHON +// Copyright © 2014-2023, Benoit BLANCHON // MIT License #pragma once diff --git a/neosensor/libraries/ArduinoJson/extras/tests/Helpers/progmem_emulation.hpp b/neosensor/libraries/ArduinoJson/extras/tests/Helpers/avr/pgmspace.h similarity index 76% rename from neosensor/libraries/ArduinoJson/extras/tests/Helpers/progmem_emulation.hpp rename to neosensor/libraries/ArduinoJson/extras/tests/Helpers/avr/pgmspace.h index 41597dca8870a1e4c1704802e27f0c25353d459a..378065da3c8b71fc3e811d443d0858c7b85e019e 100644 --- a/neosensor/libraries/ArduinoJson/extras/tests/Helpers/progmem_emulation.hpp +++ b/neosensor/libraries/ArduinoJson/extras/tests/Helpers/avr/pgmspace.h @@ -1,7 +1,9 @@ // ArduinoJson - https://arduinojson.org -// Copyright © 2014-2022, Benoit BLANCHON +// Copyright © 2014-2023, Benoit BLANCHON // MIT License +#pragma once + #include <stdint.h> // uint8_t #define PROGMEM @@ -23,7 +25,7 @@ inline uint8_t pgm_read_byte(const void* p) { return *reinterpret_cast<const uint8_t*>(convertFlashToPtr(p)); } -#define ARDUINOJSON_DEFINE_PROGMEM_ARRAY(type, name, value) \ - static type const ARDUINOJSON_CONCAT2(name, _progmem)[] = value; \ - static type const* name = reinterpret_cast<type const*>( \ +#define ARDUINOJSON_DEFINE_PROGMEM_ARRAY(type, name, ...) \ + static type const ARDUINOJSON_CONCAT2(name, _progmem)[] = __VA_ARGS__; \ + static type const* name = reinterpret_cast<type const*>( \ convertPtrToFlash(ARDUINOJSON_CONCAT2(name, _progmem))); diff --git a/neosensor/libraries/ArduinoJson/extras/tests/IntegrationTests/CMakeLists.txt b/neosensor/libraries/ArduinoJson/extras/tests/IntegrationTests/CMakeLists.txt index 88b5ba689be6a7b43b265daa13b1f6c037a13e70..9ee858d88ab9ac16a8187484f73334048f50d55d 100644 --- a/neosensor/libraries/ArduinoJson/extras/tests/IntegrationTests/CMakeLists.txt +++ b/neosensor/libraries/ArduinoJson/extras/tests/IntegrationTests/CMakeLists.txt @@ -1,5 +1,5 @@ # ArduinoJson - https://arduinojson.org -# Copyright © 2014-2022, Benoit BLANCHON +# Copyright © 2014-2023, Benoit BLANCHON # MIT License add_executable(IntegrationTests @@ -9,10 +9,10 @@ add_executable(IntegrationTests openweathermap.cpp ) -if(CMAKE_CXX_COMPILER_ID MATCHES "GNU") +if(CMAKE_CXX_COMPILER_ID MATCHES "GNU" AND CMAKE_CXX_COMPILER_VERSION VERSION_GREATER_EQUAL 6) target_compile_options(IntegrationTests PUBLIC - -fsingle-precision-constant # issue 544 + -fsingle-precision-constant # issue 544 ) endif() @@ -20,5 +20,5 @@ add_test(IntegrationTests IntegrationTests) set_tests_properties(IntegrationTests PROPERTIES - LABELS "Catch" + LABELS "Catch" ) diff --git a/neosensor/libraries/ArduinoJson/extras/tests/IntegrationTests/gbathree.cpp b/neosensor/libraries/ArduinoJson/extras/tests/IntegrationTests/gbathree.cpp index 2190eb10d6ff107db33b70f734426cac09e55ddf..34c4d0d84cbf7d4db0f57ec0d0c0a69638f9422b 100644 --- a/neosensor/libraries/ArduinoJson/extras/tests/IntegrationTests/gbathree.cpp +++ b/neosensor/libraries/ArduinoJson/extras/tests/IntegrationTests/gbathree.cpp @@ -1,5 +1,5 @@ // ArduinoJson - https://arduinojson.org -// Copyright © 2014-2022, Benoit BLANCHON +// Copyright © 2014-2023, Benoit BLANCHON // MIT License #include <ArduinoJson.h> diff --git a/neosensor/libraries/ArduinoJson/extras/tests/IntegrationTests/issue772.cpp b/neosensor/libraries/ArduinoJson/extras/tests/IntegrationTests/issue772.cpp index 4984b43a6a699ac30c802de8ad6608030e157804..dd85a085acf38af51d16b8d00e2f8f33d80a75ce 100644 --- a/neosensor/libraries/ArduinoJson/extras/tests/IntegrationTests/issue772.cpp +++ b/neosensor/libraries/ArduinoJson/extras/tests/IntegrationTests/issue772.cpp @@ -1,5 +1,5 @@ // ArduinoJson - https://arduinojson.org -// Copyright © 2014-2022, Benoit BLANCHON +// Copyright © 2014-2023, Benoit BLANCHON // MIT License #include <ArduinoJson.h> diff --git a/neosensor/libraries/ArduinoJson/extras/tests/IntegrationTests/openweathermap.cpp b/neosensor/libraries/ArduinoJson/extras/tests/IntegrationTests/openweathermap.cpp index 44e2f7605433408a0c575fae136a307b17f9a23f..e91ac0a8a224ac7f994291944f5108b79b8426ea 100644 --- a/neosensor/libraries/ArduinoJson/extras/tests/IntegrationTests/openweathermap.cpp +++ b/neosensor/libraries/ArduinoJson/extras/tests/IntegrationTests/openweathermap.cpp @@ -1,5 +1,5 @@ // ArduinoJson - https://arduinojson.org -// Copyright © 2014-2022, Benoit BLANCHON +// Copyright © 2014-2023, Benoit BLANCHON // MIT License #include <ArduinoJson.h> diff --git a/neosensor/libraries/ArduinoJson/extras/tests/IntegrationTests/round_trip.cpp b/neosensor/libraries/ArduinoJson/extras/tests/IntegrationTests/round_trip.cpp index edc5538553d9de7c988fe62cb6c54299d442b9bd..ede311d00faa065fcb2bb387ffe63ec42e29ccdb 100644 --- a/neosensor/libraries/ArduinoJson/extras/tests/IntegrationTests/round_trip.cpp +++ b/neosensor/libraries/ArduinoJson/extras/tests/IntegrationTests/round_trip.cpp @@ -1,5 +1,5 @@ // ArduinoJson - https://arduinojson.org -// Copyright © 2014-2022, Benoit BLANCHON +// Copyright © 2014-2023, Benoit BLANCHON // MIT License #include <ArduinoJson.h> diff --git a/neosensor/libraries/ArduinoJson/extras/tests/JsonArray/CMakeLists.txt b/neosensor/libraries/ArduinoJson/extras/tests/JsonArray/CMakeLists.txt index 9f897992aa27a9c4e9d847a8d7ed8bf819276ef8..d97a2b16f5a8d4098ccf6f2c020f4a56263b0e0a 100644 --- a/neosensor/libraries/ArduinoJson/extras/tests/JsonArray/CMakeLists.txt +++ b/neosensor/libraries/ArduinoJson/extras/tests/JsonArray/CMakeLists.txt @@ -1,5 +1,5 @@ # ArduinoJson - https://arduinojson.org -# Copyright © 2014-2022, Benoit BLANCHON +# Copyright © 2014-2023, Benoit BLANCHON # MIT License add_executable(JsonArrayTests @@ -24,5 +24,5 @@ add_test(JsonArray JsonArrayTests) set_tests_properties(JsonArray PROPERTIES - LABELS "Catch" + LABELS "Catch" ) diff --git a/neosensor/libraries/ArduinoJson/extras/tests/JsonArray/add.cpp b/neosensor/libraries/ArduinoJson/extras/tests/JsonArray/add.cpp index 369bcf2da2069fe322368868ca024507d0e59a37..2708c7d4458e7b04972be70d1097d3bf79b1b113 100644 --- a/neosensor/libraries/ArduinoJson/extras/tests/JsonArray/add.cpp +++ b/neosensor/libraries/ArduinoJson/extras/tests/JsonArray/add.cpp @@ -1,5 +1,5 @@ // ArduinoJson - https://arduinojson.org -// Copyright © 2014-2022, Benoit BLANCHON +// Copyright © 2014-2023, Benoit BLANCHON // MIT License #include <ArduinoJson.h> diff --git a/neosensor/libraries/ArduinoJson/extras/tests/JsonArray/clear.cpp b/neosensor/libraries/ArduinoJson/extras/tests/JsonArray/clear.cpp index baeb022292a44c69922329543dc1013b79dba917..3a593c5ad108a7c79c3ce5d03d5030b1e159d531 100644 --- a/neosensor/libraries/ArduinoJson/extras/tests/JsonArray/clear.cpp +++ b/neosensor/libraries/ArduinoJson/extras/tests/JsonArray/clear.cpp @@ -1,5 +1,5 @@ // ArduinoJson - https://arduinojson.org -// Copyright © 2014-2022, Benoit BLANCHON +// Copyright © 2014-2023, Benoit BLANCHON // MIT License #include <ArduinoJson.h> diff --git a/neosensor/libraries/ArduinoJson/extras/tests/JsonArray/compare.cpp b/neosensor/libraries/ArduinoJson/extras/tests/JsonArray/compare.cpp index 4d1c9d079a336f0d9312fb5f4a968da3b966bb4b..1e64e166c4e210b55eb89752d77e81a29560998a 100644 --- a/neosensor/libraries/ArduinoJson/extras/tests/JsonArray/compare.cpp +++ b/neosensor/libraries/ArduinoJson/extras/tests/JsonArray/compare.cpp @@ -1,5 +1,5 @@ // ArduinoJson - https://arduinojson.org -// Copyright © 2014-2022, Benoit BLANCHON +// Copyright © 2014-2023, Benoit BLANCHON // MIT License #include <ArduinoJson.h> diff --git a/neosensor/libraries/ArduinoJson/extras/tests/JsonArray/copyArray.cpp b/neosensor/libraries/ArduinoJson/extras/tests/JsonArray/copyArray.cpp index 599821df82096412c537a0370739cd41823be547..7973c375c90354b2cf3185e6a65670937e1af90e 100644 --- a/neosensor/libraries/ArduinoJson/extras/tests/JsonArray/copyArray.cpp +++ b/neosensor/libraries/ArduinoJson/extras/tests/JsonArray/copyArray.cpp @@ -1,5 +1,5 @@ // ArduinoJson - https://arduinojson.org -// Copyright © 2014-2022, Benoit BLANCHON +// Copyright © 2014-2023, Benoit BLANCHON // MIT License #include <ArduinoJson.h> @@ -165,7 +165,7 @@ TEST_CASE("copyArray()") { char json[32] = ""; int source[][3] = {{1, 2, 3}, {4, 5, 6}}; - CAPTURE(SIZE) + CAPTURE(SIZE); bool ok = copyArray(source, array); CAPTURE(doc.memoryUsage()); diff --git a/neosensor/libraries/ArduinoJson/extras/tests/JsonArray/createNested.cpp b/neosensor/libraries/ArduinoJson/extras/tests/JsonArray/createNested.cpp index dbc4c304feb0d89ed07147ae1a289579da94d341..4801dbe0ea08f8060a0b48fe81d08a2176538d0a 100644 --- a/neosensor/libraries/ArduinoJson/extras/tests/JsonArray/createNested.cpp +++ b/neosensor/libraries/ArduinoJson/extras/tests/JsonArray/createNested.cpp @@ -1,5 +1,5 @@ // ArduinoJson - https://arduinojson.org -// Copyright © 2014-2022, Benoit BLANCHON +// Copyright © 2014-2023, Benoit BLANCHON // MIT License #include <ArduinoJson.h> diff --git a/neosensor/libraries/ArduinoJson/extras/tests/JsonArray/equals.cpp b/neosensor/libraries/ArduinoJson/extras/tests/JsonArray/equals.cpp index f4f9b521a7e1ca74eb700fe255db4cba7a7b0838..4998d388f26dd738a47df05b08f27145dca7e644 100644 --- a/neosensor/libraries/ArduinoJson/extras/tests/JsonArray/equals.cpp +++ b/neosensor/libraries/ArduinoJson/extras/tests/JsonArray/equals.cpp @@ -1,5 +1,5 @@ // ArduinoJson - https://arduinojson.org -// Copyright © 2014-2022, Benoit BLANCHON +// Copyright © 2014-2023, Benoit BLANCHON // MIT License #include <ArduinoJson.h> diff --git a/neosensor/libraries/ArduinoJson/extras/tests/JsonArray/isNull.cpp b/neosensor/libraries/ArduinoJson/extras/tests/JsonArray/isNull.cpp index ad953b91601771bad52d2a8f3156787f489de9aa..0da13be8d13dd554870872c30268b4fd32d680fa 100644 --- a/neosensor/libraries/ArduinoJson/extras/tests/JsonArray/isNull.cpp +++ b/neosensor/libraries/ArduinoJson/extras/tests/JsonArray/isNull.cpp @@ -1,5 +1,5 @@ // ArduinoJson - https://arduinojson.org -// Copyright © 2014-2022, Benoit BLANCHON +// Copyright © 2014-2023, Benoit BLANCHON // MIT License #include <ArduinoJson.h> diff --git a/neosensor/libraries/ArduinoJson/extras/tests/JsonArray/iterator.cpp b/neosensor/libraries/ArduinoJson/extras/tests/JsonArray/iterator.cpp index 435a5bb9d9dcd12b01ec1c78b73d15bba8036973..50eb27631b4325ffe7d5c20bb5c2d50ea267fc11 100644 --- a/neosensor/libraries/ArduinoJson/extras/tests/JsonArray/iterator.cpp +++ b/neosensor/libraries/ArduinoJson/extras/tests/JsonArray/iterator.cpp @@ -1,5 +1,5 @@ // ArduinoJson - https://arduinojson.org -// Copyright © 2014-2022, Benoit BLANCHON +// Copyright © 2014-2023, Benoit BLANCHON // MIT License #include <ArduinoJson.h> diff --git a/neosensor/libraries/ArduinoJson/extras/tests/JsonArray/memoryUsage.cpp b/neosensor/libraries/ArduinoJson/extras/tests/JsonArray/memoryUsage.cpp index 05b743f1cef6394c5d5de11153e01331dd0807af..9f4ea09b39f28a3b0ce94844a0d6bca3d2e49960 100644 --- a/neosensor/libraries/ArduinoJson/extras/tests/JsonArray/memoryUsage.cpp +++ b/neosensor/libraries/ArduinoJson/extras/tests/JsonArray/memoryUsage.cpp @@ -1,5 +1,5 @@ // ArduinoJson - https://arduinojson.org -// Copyright © 2014-2022, Benoit BLANCHON +// Copyright © 2014-2023, Benoit BLANCHON // MIT License #include <ArduinoJson.h> diff --git a/neosensor/libraries/ArduinoJson/extras/tests/JsonArray/nesting.cpp b/neosensor/libraries/ArduinoJson/extras/tests/JsonArray/nesting.cpp index 2118f5f75807511027dce8802bda6dcc1ae1f7e1..fc1be8c6a839eb5da7e91e1a2867ff2c473a523a 100644 --- a/neosensor/libraries/ArduinoJson/extras/tests/JsonArray/nesting.cpp +++ b/neosensor/libraries/ArduinoJson/extras/tests/JsonArray/nesting.cpp @@ -1,5 +1,5 @@ // ArduinoJson - https://arduinojson.org -// Copyright © 2014-2022, Benoit BLANCHON +// Copyright © 2014-2023, Benoit BLANCHON // MIT License #include <ArduinoJson.h> diff --git a/neosensor/libraries/ArduinoJson/extras/tests/JsonArray/remove.cpp b/neosensor/libraries/ArduinoJson/extras/tests/JsonArray/remove.cpp index b9e86fddafa3ddc8ecfebd6c1bc4b3a69df8aa9e..f75efda31eb8ee6932efb97d11d0373e27adf5a0 100644 --- a/neosensor/libraries/ArduinoJson/extras/tests/JsonArray/remove.cpp +++ b/neosensor/libraries/ArduinoJson/extras/tests/JsonArray/remove.cpp @@ -1,5 +1,5 @@ // ArduinoJson - https://arduinojson.org -// Copyright © 2014-2022, Benoit BLANCHON +// Copyright © 2014-2023, Benoit BLANCHON // MIT License #include <ArduinoJson.h> diff --git a/neosensor/libraries/ArduinoJson/extras/tests/JsonArray/size.cpp b/neosensor/libraries/ArduinoJson/extras/tests/JsonArray/size.cpp index 68b10de7a9ce15b800e22524443223efb33fd104..6edd4db86d5b547d5cff70c2c1d2748fda77d570 100644 --- a/neosensor/libraries/ArduinoJson/extras/tests/JsonArray/size.cpp +++ b/neosensor/libraries/ArduinoJson/extras/tests/JsonArray/size.cpp @@ -1,5 +1,5 @@ // ArduinoJson - https://arduinojson.org -// Copyright © 2014-2022, Benoit BLANCHON +// Copyright © 2014-2023, Benoit BLANCHON // MIT License #include <ArduinoJson.h> diff --git a/neosensor/libraries/ArduinoJson/extras/tests/JsonArray/std_string.cpp b/neosensor/libraries/ArduinoJson/extras/tests/JsonArray/std_string.cpp index 7af0ac2ed04811e04174869d6073356f68863bb4..7d3ec9f452241e3ded8108a3ded59bcf8c906e1a 100644 --- a/neosensor/libraries/ArduinoJson/extras/tests/JsonArray/std_string.cpp +++ b/neosensor/libraries/ArduinoJson/extras/tests/JsonArray/std_string.cpp @@ -1,5 +1,5 @@ // ArduinoJson - https://arduinojson.org -// Copyright © 2014-2022, Benoit BLANCHON +// Copyright © 2014-2023, Benoit BLANCHON // MIT License #include <ArduinoJson.h> diff --git a/neosensor/libraries/ArduinoJson/extras/tests/JsonArray/subscript.cpp b/neosensor/libraries/ArduinoJson/extras/tests/JsonArray/subscript.cpp index 57bbe140d51d4f19db723ce4a0da725bc5fcd42a..3079d2f98d7565867c6df572c2a1bb759d981b78 100644 --- a/neosensor/libraries/ArduinoJson/extras/tests/JsonArray/subscript.cpp +++ b/neosensor/libraries/ArduinoJson/extras/tests/JsonArray/subscript.cpp @@ -1,5 +1,5 @@ // ArduinoJson - https://arduinojson.org -// Copyright © 2014-2022, Benoit BLANCHON +// Copyright © 2014-2023, Benoit BLANCHON // MIT License #include <ArduinoJson.h> diff --git a/neosensor/libraries/ArduinoJson/extras/tests/JsonArray/unbound.cpp b/neosensor/libraries/ArduinoJson/extras/tests/JsonArray/unbound.cpp index 792feec3e726a88861dc38f2d833814429b9c168..0e21310b161c8fb202a5e63bee972a964a408379 100644 --- a/neosensor/libraries/ArduinoJson/extras/tests/JsonArray/unbound.cpp +++ b/neosensor/libraries/ArduinoJson/extras/tests/JsonArray/unbound.cpp @@ -1,5 +1,5 @@ // ArduinoJson - https://arduinojson.org -// Copyright © 2014-2022, Benoit BLANCHON +// Copyright © 2014-2023, Benoit BLANCHON // MIT License #include <ArduinoJson.h> diff --git a/neosensor/libraries/ArduinoJson/extras/tests/JsonDeserializer/CMakeLists.txt b/neosensor/libraries/ArduinoJson/extras/tests/JsonDeserializer/CMakeLists.txt index 429c37552def6f655de29dc64f84187631e5a7a7..f60ad4161a786f7aedd436c30c3396620a53518d 100644 --- a/neosensor/libraries/ArduinoJson/extras/tests/JsonDeserializer/CMakeLists.txt +++ b/neosensor/libraries/ArduinoJson/extras/tests/JsonDeserializer/CMakeLists.txt @@ -1,5 +1,5 @@ # ArduinoJson - https://arduinojson.org -# Copyright © 2014-2022, Benoit BLANCHON +# Copyright © 2014-2023, Benoit BLANCHON # MIT License add_executable(JsonDeserializerTests @@ -24,5 +24,5 @@ add_test(JsonDeserializer JsonDeserializerTests) set_tests_properties(JsonDeserializer PROPERTIES - LABELS "Catch" + LABELS "Catch" ) diff --git a/neosensor/libraries/ArduinoJson/extras/tests/JsonDeserializer/DeserializationError.cpp b/neosensor/libraries/ArduinoJson/extras/tests/JsonDeserializer/DeserializationError.cpp index 01ddaf69ead8a833e661ec37b9c65a8efe74eb91..fd1b1885411a97bfa4f8733cf63cd113f1379536 100644 --- a/neosensor/libraries/ArduinoJson/extras/tests/JsonDeserializer/DeserializationError.cpp +++ b/neosensor/libraries/ArduinoJson/extras/tests/JsonDeserializer/DeserializationError.cpp @@ -1,10 +1,12 @@ // ArduinoJson - https://arduinojson.org -// Copyright © 2014-2022, Benoit BLANCHON +// Copyright © 2014-2023, Benoit BLANCHON // MIT License #include <ArduinoJson.h> #include <catch.hpp> +#include <sstream> + void testStringification(DeserializationError error, std::string expected) { REQUIRE(error.c_str() == expected); } diff --git a/neosensor/libraries/ArduinoJson/extras/tests/JsonDeserializer/array.cpp b/neosensor/libraries/ArduinoJson/extras/tests/JsonDeserializer/array.cpp index 2e0038ee4f5fa600f2f78a4f59357b2194fd6d30..b30269c19b503c1e585734baadccdca03aec132d 100644 --- a/neosensor/libraries/ArduinoJson/extras/tests/JsonDeserializer/array.cpp +++ b/neosensor/libraries/ArduinoJson/extras/tests/JsonDeserializer/array.cpp @@ -1,5 +1,5 @@ // ArduinoJson - https://arduinojson.org -// Copyright © 2014-2022, Benoit BLANCHON +// Copyright © 2014-2023, Benoit BLANCHON // MIT License #include <ArduinoJson.h> diff --git a/neosensor/libraries/ArduinoJson/extras/tests/JsonDeserializer/array_static.cpp b/neosensor/libraries/ArduinoJson/extras/tests/JsonDeserializer/array_static.cpp index d828518fcd1348f5fec464e42cccb68deceeee42..2d1f538d7db4e9d04aead0c676ad9cca2d74729e 100644 --- a/neosensor/libraries/ArduinoJson/extras/tests/JsonDeserializer/array_static.cpp +++ b/neosensor/libraries/ArduinoJson/extras/tests/JsonDeserializer/array_static.cpp @@ -1,5 +1,5 @@ // ArduinoJson - https://arduinojson.org -// Copyright © 2014-2022, Benoit BLANCHON +// Copyright © 2014-2023, Benoit BLANCHON // MIT License #include <ArduinoJson.h> diff --git a/neosensor/libraries/ArduinoJson/extras/tests/JsonDeserializer/filter.cpp b/neosensor/libraries/ArduinoJson/extras/tests/JsonDeserializer/filter.cpp index e0c37341029ba078d9d81c69cda9ce06b9dff51e..f1c6e2e4c020206e616e824d93667286ca0a2e38 100644 --- a/neosensor/libraries/ArduinoJson/extras/tests/JsonDeserializer/filter.cpp +++ b/neosensor/libraries/ArduinoJson/extras/tests/JsonDeserializer/filter.cpp @@ -1,5 +1,5 @@ // ArduinoJson - https://arduinojson.org -// Copyright © 2014-2022, Benoit BLANCHON +// Copyright © 2014-2023, Benoit BLANCHON // MIT License #define ARDUINOJSON_ENABLE_COMMENTS 1 diff --git a/neosensor/libraries/ArduinoJson/extras/tests/JsonDeserializer/incomplete_input.cpp b/neosensor/libraries/ArduinoJson/extras/tests/JsonDeserializer/incomplete_input.cpp index 4e5bcdbd3c1feff7f61c99946d48c48d3f5c16c9..a34aede64d5a69fab09bb1ac33b2274eb5c5cf87 100644 --- a/neosensor/libraries/ArduinoJson/extras/tests/JsonDeserializer/incomplete_input.cpp +++ b/neosensor/libraries/ArduinoJson/extras/tests/JsonDeserializer/incomplete_input.cpp @@ -1,5 +1,5 @@ // ArduinoJson - https://arduinojson.org -// Copyright © 2014-2022, Benoit BLANCHON +// Copyright © 2014-2023, Benoit BLANCHON // MIT License #define ARDUINOJSON_DECODE_UNICODE 1 diff --git a/neosensor/libraries/ArduinoJson/extras/tests/JsonDeserializer/input_types.cpp b/neosensor/libraries/ArduinoJson/extras/tests/JsonDeserializer/input_types.cpp index 04054c6a7b08a5405242691f5f82c9d0f099efff..788319f4623dbbd3862090b8855881e166155f59 100644 --- a/neosensor/libraries/ArduinoJson/extras/tests/JsonDeserializer/input_types.cpp +++ b/neosensor/libraries/ArduinoJson/extras/tests/JsonDeserializer/input_types.cpp @@ -1,5 +1,5 @@ // ArduinoJson - https://arduinojson.org -// Copyright © 2014-2022, Benoit BLANCHON +// Copyright © 2014-2023, Benoit BLANCHON // MIT License #include <ArduinoJson.h> @@ -24,6 +24,30 @@ TEST_CASE("deserializeJson(char*)") { } } +TEST_CASE("deserializeJson(unsigned char*, unsigned int)") { // issue #1897 + StaticJsonDocument<1024> doc; + + unsigned char input[] = "{\"hello\":\"world\"}"; + unsigned char* input_ptr = input; + unsigned int size = sizeof(input); + + DeserializationError err = deserializeJson(doc, input_ptr, size); + + REQUIRE(err == DeserializationError::Ok); +} + +TEST_CASE("deserializeJson(uint8_t*, size_t)") { // issue #1898 + StaticJsonDocument<1024> doc; + + uint8_t input[] = "{\"hello\":\"world\"}"; + uint8_t* input_ptr = input; + size_t size = sizeof(input); + + DeserializationError err = deserializeJson(doc, input_ptr, size); + + REQUIRE(err == DeserializationError::Ok); +} + TEST_CASE("deserializeJson(const std::string&)") { DynamicJsonDocument doc(4096); diff --git a/neosensor/libraries/ArduinoJson/extras/tests/JsonDeserializer/invalid_input.cpp b/neosensor/libraries/ArduinoJson/extras/tests/JsonDeserializer/invalid_input.cpp index a2304a372f5f7b2baecf6588c975d9cab2600ef9..52b5038348157ddd64bf18c84a9ee419ae4afaa2 100644 --- a/neosensor/libraries/ArduinoJson/extras/tests/JsonDeserializer/invalid_input.cpp +++ b/neosensor/libraries/ArduinoJson/extras/tests/JsonDeserializer/invalid_input.cpp @@ -1,5 +1,5 @@ // ArduinoJson - https://arduinojson.org -// Copyright © 2014-2022, Benoit BLANCHON +// Copyright © 2014-2023, Benoit BLANCHON // MIT License #define ARDUINOJSON_DECODE_UNICODE 1 diff --git a/neosensor/libraries/ArduinoJson/extras/tests/JsonDeserializer/misc.cpp b/neosensor/libraries/ArduinoJson/extras/tests/JsonDeserializer/misc.cpp index dc8083c47395a2b88746c1598d60b5578caaa020..4f22de15fd1ee27bd8fcd63587e8f1f40a4b099d 100644 --- a/neosensor/libraries/ArduinoJson/extras/tests/JsonDeserializer/misc.cpp +++ b/neosensor/libraries/ArduinoJson/extras/tests/JsonDeserializer/misc.cpp @@ -1,5 +1,5 @@ // ArduinoJson - https://arduinojson.org -// Copyright © 2014-2022, Benoit BLANCHON +// Copyright © 2014-2023, Benoit BLANCHON // MIT License #include <ArduinoJson.h> diff --git a/neosensor/libraries/ArduinoJson/extras/tests/JsonDeserializer/nestingLimit.cpp b/neosensor/libraries/ArduinoJson/extras/tests/JsonDeserializer/nestingLimit.cpp index 0cdcb3e5492089e4c53b1c4ac4e2c1e0a230bfa8..cf55dc850f3767d981f1ca547eb5a263a418c2f3 100644 --- a/neosensor/libraries/ArduinoJson/extras/tests/JsonDeserializer/nestingLimit.cpp +++ b/neosensor/libraries/ArduinoJson/extras/tests/JsonDeserializer/nestingLimit.cpp @@ -1,10 +1,12 @@ // ArduinoJson - https://arduinojson.org -// Copyright © 2014-2022, Benoit BLANCHON +// Copyright © 2014-2023, Benoit BLANCHON // MIT License #include <ArduinoJson.h> #include <catch.hpp> +#include <sstream> + #define SHOULD_WORK(expression) REQUIRE(DeserializationError::Ok == expression); #define SHOULD_FAIL(expression) \ REQUIRE(DeserializationError::TooDeep == expression); diff --git a/neosensor/libraries/ArduinoJson/extras/tests/JsonDeserializer/number.cpp b/neosensor/libraries/ArduinoJson/extras/tests/JsonDeserializer/number.cpp index 44e24cbedf807cedffcd593d7ff3e0a27511034c..05cf89e8024b6374caa5b40a54808be461c8f1cc 100644 --- a/neosensor/libraries/ArduinoJson/extras/tests/JsonDeserializer/number.cpp +++ b/neosensor/libraries/ArduinoJson/extras/tests/JsonDeserializer/number.cpp @@ -1,5 +1,5 @@ // ArduinoJson - https://arduinojson.org -// Copyright © 2014-2022, Benoit BLANCHON +// Copyright © 2014-2023, Benoit BLANCHON // MIT License #define ARDUINOJSON_USE_LONG_LONG 0 @@ -11,8 +11,8 @@ #include <catch.hpp> namespace my { -using ARDUINOJSON_NAMESPACE::isinf; -using ARDUINOJSON_NAMESPACE::isnan; +using ArduinoJson::detail::isinf; +using ArduinoJson::detail::isnan; } // namespace my TEST_CASE("deserialize an integer") { diff --git a/neosensor/libraries/ArduinoJson/extras/tests/JsonDeserializer/object.cpp b/neosensor/libraries/ArduinoJson/extras/tests/JsonDeserializer/object.cpp index e5d5de7f4e6671e19af6b94a217575ee82b43d76..814258ecdda979ee3e94adc0dedc798b3e3991a5 100644 --- a/neosensor/libraries/ArduinoJson/extras/tests/JsonDeserializer/object.cpp +++ b/neosensor/libraries/ArduinoJson/extras/tests/JsonDeserializer/object.cpp @@ -1,5 +1,5 @@ // ArduinoJson - https://arduinojson.org -// Copyright © 2014-2022, Benoit BLANCHON +// Copyright © 2014-2023, Benoit BLANCHON // MIT License #include <ArduinoJson.h> @@ -100,7 +100,7 @@ TEST_CASE("deserialize JSON object") { REQUIRE(obj["key"] == "value"); } - SECTION("Before the colon") { + SECTION("Before the comma") { DeserializationError err = deserializeJson(doc, "{\"key1\":\"value1\" ,\"key2\":\"value2\"}"); JsonObject obj = doc.as<JsonObject>(); @@ -112,9 +112,9 @@ TEST_CASE("deserialize JSON object") { REQUIRE(obj["key2"] == "value2"); } - SECTION("After the colon") { + SECTION("After the comma") { DeserializationError err = - deserializeJson(doc, "{\"key1\":\"value1\" ,\"key2\":\"value2\"}"); + deserializeJson(doc, "{\"key1\":\"value1\", \"key2\":\"value2\"}"); JsonObject obj = doc.as<JsonObject>(); REQUIRE(err == DeserializationError::Ok); diff --git a/neosensor/libraries/ArduinoJson/extras/tests/JsonDeserializer/object_static.cpp b/neosensor/libraries/ArduinoJson/extras/tests/JsonDeserializer/object_static.cpp index a326afe6093855d02321bc30a75896144af8103a..b198ea74ff17f26b2b264ad25909c72e8c7b8fec 100644 --- a/neosensor/libraries/ArduinoJson/extras/tests/JsonDeserializer/object_static.cpp +++ b/neosensor/libraries/ArduinoJson/extras/tests/JsonDeserializer/object_static.cpp @@ -1,5 +1,5 @@ // ArduinoJson - https://arduinojson.org -// Copyright © 2014-2022, Benoit BLANCHON +// Copyright © 2014-2023, Benoit BLANCHON // MIT License #include <ArduinoJson.h> diff --git a/neosensor/libraries/ArduinoJson/extras/tests/JsonDeserializer/string.cpp b/neosensor/libraries/ArduinoJson/extras/tests/JsonDeserializer/string.cpp index 8f93ac63d90cb34bc895f65d957a611356d6f5e9..2379d45548ea5ad8ffdc7bbc80a7e7dba17c73e7 100644 --- a/neosensor/libraries/ArduinoJson/extras/tests/JsonDeserializer/string.cpp +++ b/neosensor/libraries/ArduinoJson/extras/tests/JsonDeserializer/string.cpp @@ -1,5 +1,5 @@ // ArduinoJson - https://arduinojson.org -// Copyright © 2014-2022, Benoit BLANCHON +// Copyright © 2014-2023, Benoit BLANCHON // MIT License #define ARDUINOJSON_DECODE_UNICODE 1 diff --git a/neosensor/libraries/ArduinoJson/extras/tests/JsonDocument/BasicJsonDocument.cpp b/neosensor/libraries/ArduinoJson/extras/tests/JsonDocument/BasicJsonDocument.cpp index d2074401a43e3ac7beeff1c2a01806f1f2d2838a..348fd94cfcd77fe557a053786b9156caf94ec6ad 100644 --- a/neosensor/libraries/ArduinoJson/extras/tests/JsonDocument/BasicJsonDocument.cpp +++ b/neosensor/libraries/ArduinoJson/extras/tests/JsonDocument/BasicJsonDocument.cpp @@ -1,5 +1,5 @@ // ArduinoJson - https://arduinojson.org -// Copyright © 2014-2022, Benoit BLANCHON +// Copyright © 2014-2023, Benoit BLANCHON // MIT License #include <ArduinoJson.h> @@ -8,34 +8,31 @@ #include <sstream> #include <utility> -using ARDUINOJSON_NAMESPACE::addPadding; - class SpyingAllocator { public: - SpyingAllocator(const SpyingAllocator& src) : _log(src._log) {} - SpyingAllocator(std::ostream& log) : _log(log) {} + SpyingAllocator(const SpyingAllocator& src) : log_(src.log_) {} + SpyingAllocator(std::ostream& log) : log_(log) {} + SpyingAllocator& operator=(const SpyingAllocator& src) = delete; void* allocate(size_t n) { - _log << "A" << n; + log_ << "A" << n; return malloc(n); } void deallocate(void* p) { - _log << "F"; + log_ << "F"; free(p); } private: - SpyingAllocator& operator=(const SpyingAllocator& src); - - std::ostream& _log; + std::ostream& log_; }; class ControllableAllocator { public: - ControllableAllocator() : _enabled(true) {} + ControllableAllocator() : enabled_(true) {} void* allocate(size_t n) { - return _enabled ? malloc(n) : 0; + return enabled_ ? malloc(n) : 0; } void deallocate(void* p) { @@ -43,11 +40,11 @@ class ControllableAllocator { } void disable() { - _enabled = false; + enabled_ = false; } private: - bool _enabled; + bool enabled_; }; TEST_CASE("BasicJsonDocument") { @@ -72,7 +69,6 @@ TEST_CASE("BasicJsonDocument") { REQUIRE(log.str() == "A4096A4096FF"); } -#if ARDUINOJSON_HAS_RVALUE_REFERENCES SECTION("Move construct") { { BasicJsonDocument<SpyingAllocator> doc1(4096, log); @@ -87,7 +83,6 @@ TEST_CASE("BasicJsonDocument") { } REQUIRE(log.str() == "A4096F"); } -#endif SECTION("Copy assign larger") { { @@ -134,7 +129,6 @@ TEST_CASE("BasicJsonDocument") { REQUIRE(log.str() == "A1024A1024FF"); } -#if ARDUINOJSON_HAS_RVALUE_REFERENCES SECTION("Move assign") { { BasicJsonDocument<SpyingAllocator> doc1(4096, log); @@ -150,7 +144,6 @@ TEST_CASE("BasicJsonDocument") { } REQUIRE(log.str() == "A4096A8FF"); } -#endif SECTION("garbageCollect()") { BasicJsonDocument<ControllableAllocator> doc(4096); diff --git a/neosensor/libraries/ArduinoJson/extras/tests/JsonDocument/CMakeLists.txt b/neosensor/libraries/ArduinoJson/extras/tests/JsonDocument/CMakeLists.txt index 535678033eb6c9bb64d7378b63f45a02b0915784..3e9b4683500c8490066b7d1f953931efe274b408 100644 --- a/neosensor/libraries/ArduinoJson/extras/tests/JsonDocument/CMakeLists.txt +++ b/neosensor/libraries/ArduinoJson/extras/tests/JsonDocument/CMakeLists.txt @@ -1,5 +1,5 @@ # ArduinoJson - https://arduinojson.org -# Copyright © 2014-2022, Benoit BLANCHON +# Copyright © 2014-2023, Benoit BLANCHON # MIT License add_executable(JsonDocumentTests @@ -12,6 +12,7 @@ add_executable(JsonDocumentTests DynamicJsonDocument.cpp ElementProxy.cpp isNull.cpp + issue1120.cpp MemberProxy.cpp nesting.cpp overflowed.cpp @@ -27,5 +28,5 @@ add_test(JsonDocument JsonDocumentTests) set_tests_properties(JsonDocument PROPERTIES - LABELS "Catch" + LABELS "Catch" ) diff --git a/neosensor/libraries/ArduinoJson/extras/tests/JsonDocument/DynamicJsonDocument.cpp b/neosensor/libraries/ArduinoJson/extras/tests/JsonDocument/DynamicJsonDocument.cpp index ce050f17ba14fc403d0ab7e03dbf7f1de67e9dbb..397f8c5dc19295ed705ed0a97b9f34952d971494 100644 --- a/neosensor/libraries/ArduinoJson/extras/tests/JsonDocument/DynamicJsonDocument.cpp +++ b/neosensor/libraries/ArduinoJson/extras/tests/JsonDocument/DynamicJsonDocument.cpp @@ -1,11 +1,11 @@ // ArduinoJson - https://arduinojson.org -// Copyright © 2014-2022, Benoit BLANCHON +// Copyright © 2014-2023, Benoit BLANCHON // MIT License #include <ArduinoJson.h> #include <catch.hpp> -using ARDUINOJSON_NAMESPACE::addPadding; +using ArduinoJson::detail::addPadding; static void REQUIRE_JSON(JsonDocument& doc, const std::string& expected) { std::string json; diff --git a/neosensor/libraries/ArduinoJson/extras/tests/JsonDocument/ElementProxy.cpp b/neosensor/libraries/ArduinoJson/extras/tests/JsonDocument/ElementProxy.cpp index eafc85f3089c8341846e6417db6aa4806a3fd54c..00fcdda26bb7a523ef4837fc95ceb39db2334237 100644 --- a/neosensor/libraries/ArduinoJson/extras/tests/JsonDocument/ElementProxy.cpp +++ b/neosensor/libraries/ArduinoJson/extras/tests/JsonDocument/ElementProxy.cpp @@ -1,11 +1,11 @@ // ArduinoJson - https://arduinojson.org -// Copyright © 2014-2022, Benoit BLANCHON +// Copyright © 2014-2023, Benoit BLANCHON // MIT License #include <ArduinoJson.h> #include <catch.hpp> -typedef ARDUINOJSON_NAMESPACE::ElementProxy<JsonDocument&> ElementProxy; +typedef ArduinoJson::detail::ElementProxy<JsonDocument&> ElementProxy; TEST_CASE("ElementProxy::add()") { DynamicJsonDocument doc(4096); diff --git a/neosensor/libraries/ArduinoJson/extras/tests/JsonDocument/MemberProxy.cpp b/neosensor/libraries/ArduinoJson/extras/tests/JsonDocument/MemberProxy.cpp index ed3e32bff02149c2c2cabdebc7c0cc4878f143e7..a3707b03e5d5ca3353eda5ced21da1ffac695836 100644 --- a/neosensor/libraries/ArduinoJson/extras/tests/JsonDocument/MemberProxy.cpp +++ b/neosensor/libraries/ArduinoJson/extras/tests/JsonDocument/MemberProxy.cpp @@ -1,11 +1,11 @@ // ArduinoJson - https://arduinojson.org -// Copyright © 2014-2022, Benoit BLANCHON +// Copyright © 2014-2023, Benoit BLANCHON // MIT License #include <ArduinoJson.h> #include <catch.hpp> -typedef ARDUINOJSON_NAMESPACE::MemberProxy<JsonDocument&, const char*> +typedef ArduinoJson::detail::MemberProxy<JsonDocument&, const char*> MemberProxy; TEST_CASE("MemberProxy::add()") { diff --git a/neosensor/libraries/ArduinoJson/extras/tests/JsonDocument/StaticJsonDocument.cpp b/neosensor/libraries/ArduinoJson/extras/tests/JsonDocument/StaticJsonDocument.cpp index fe193e4b1de3e3f7f8cf707c989d643c6e0665f5..0d4089bc2a765bf5d7ecadd2a9fa0f68b18d4ff5 100644 --- a/neosensor/libraries/ArduinoJson/extras/tests/JsonDocument/StaticJsonDocument.cpp +++ b/neosensor/libraries/ArduinoJson/extras/tests/JsonDocument/StaticJsonDocument.cpp @@ -1,5 +1,5 @@ // ArduinoJson - https://arduinojson.org -// Copyright © 2014-2022, Benoit BLANCHON +// Copyright © 2014-2023, Benoit BLANCHON // MIT License #include <ArduinoJson.h> diff --git a/neosensor/libraries/ArduinoJson/extras/tests/JsonDocument/add.cpp b/neosensor/libraries/ArduinoJson/extras/tests/JsonDocument/add.cpp index 109bd08bc3f65201c7bf84f1f4ed531cf9998ab8..5843ac96700ef2939ffa4d30366550ed4c583756 100644 --- a/neosensor/libraries/ArduinoJson/extras/tests/JsonDocument/add.cpp +++ b/neosensor/libraries/ArduinoJson/extras/tests/JsonDocument/add.cpp @@ -1,5 +1,5 @@ // ArduinoJson - https://arduinojson.org -// Copyright © 2014-2022, Benoit BLANCHON +// Copyright © 2014-2023, Benoit BLANCHON // MIT License #include <ArduinoJson.h> diff --git a/neosensor/libraries/ArduinoJson/extras/tests/JsonDocument/cast.cpp b/neosensor/libraries/ArduinoJson/extras/tests/JsonDocument/cast.cpp index e538f4bbf631e570a58b8a7a64da71478c06f7c3..253e1fc763ba3d139ec8ff37bb62b2bc086f4b6f 100644 --- a/neosensor/libraries/ArduinoJson/extras/tests/JsonDocument/cast.cpp +++ b/neosensor/libraries/ArduinoJson/extras/tests/JsonDocument/cast.cpp @@ -1,5 +1,5 @@ // ArduinoJson - https://arduinojson.org -// Copyright © 2014-2022, Benoit BLANCHON +// Copyright © 2014-2023, Benoit BLANCHON // MIT License #include <ArduinoJson.h> diff --git a/neosensor/libraries/ArduinoJson/extras/tests/JsonDocument/compare.cpp b/neosensor/libraries/ArduinoJson/extras/tests/JsonDocument/compare.cpp index 7e9b95008bcf57d76ddaaf746e4bd02fe8ba8e15..d834b226237bcd81f0304222e0462c6eb1ed9c4e 100644 --- a/neosensor/libraries/ArduinoJson/extras/tests/JsonDocument/compare.cpp +++ b/neosensor/libraries/ArduinoJson/extras/tests/JsonDocument/compare.cpp @@ -1,5 +1,5 @@ // ArduinoJson - https://arduinojson.org -// Copyright © 2014-2022, Benoit BLANCHON +// Copyright © 2014-2023, Benoit BLANCHON // MIT License #include <ArduinoJson.h> diff --git a/neosensor/libraries/ArduinoJson/extras/tests/JsonDocument/containsKey.cpp b/neosensor/libraries/ArduinoJson/extras/tests/JsonDocument/containsKey.cpp index 6936043751215ea981dc92900b73ed1575693cc0..8274fc76b27e3c65724b4ce06309f28c7f8dd3ce 100644 --- a/neosensor/libraries/ArduinoJson/extras/tests/JsonDocument/containsKey.cpp +++ b/neosensor/libraries/ArduinoJson/extras/tests/JsonDocument/containsKey.cpp @@ -1,5 +1,5 @@ // ArduinoJson - https://arduinojson.org -// Copyright © 2014-2022, Benoit BLANCHON +// Copyright © 2014-2023, Benoit BLANCHON // MIT License #include <ArduinoJson.h> diff --git a/neosensor/libraries/ArduinoJson/extras/tests/JsonDocument/createNested.cpp b/neosensor/libraries/ArduinoJson/extras/tests/JsonDocument/createNested.cpp index 258f05179f1cd59e9a90992e67178a9c4c60fb36..0c9435757091dc151795540cd8385638ae9412d1 100644 --- a/neosensor/libraries/ArduinoJson/extras/tests/JsonDocument/createNested.cpp +++ b/neosensor/libraries/ArduinoJson/extras/tests/JsonDocument/createNested.cpp @@ -1,5 +1,5 @@ // ArduinoJson - https://arduinojson.org -// Copyright © 2014-2022, Benoit BLANCHON +// Copyright © 2014-2023, Benoit BLANCHON // MIT License #include <ArduinoJson.h> diff --git a/neosensor/libraries/ArduinoJson/extras/tests/JsonDocument/isNull.cpp b/neosensor/libraries/ArduinoJson/extras/tests/JsonDocument/isNull.cpp index cfb70dd62aa4d46a8a5fa534612ab7ffa853617d..d5aaae022ea367700ee3a5f8673136945a2fafca 100644 --- a/neosensor/libraries/ArduinoJson/extras/tests/JsonDocument/isNull.cpp +++ b/neosensor/libraries/ArduinoJson/extras/tests/JsonDocument/isNull.cpp @@ -1,5 +1,5 @@ // ArduinoJson - https://arduinojson.org -// Copyright © 2014-2022, Benoit BLANCHON +// Copyright © 2014-2023, Benoit BLANCHON // MIT License #include <ArduinoJson.h> diff --git a/neosensor/libraries/ArduinoJson/extras/tests/Cpp11/issue1120.cpp b/neosensor/libraries/ArduinoJson/extras/tests/JsonDocument/issue1120.cpp similarity index 100% rename from neosensor/libraries/ArduinoJson/extras/tests/Cpp11/issue1120.cpp rename to neosensor/libraries/ArduinoJson/extras/tests/JsonDocument/issue1120.cpp diff --git a/neosensor/libraries/ArduinoJson/extras/tests/JsonDocument/nesting.cpp b/neosensor/libraries/ArduinoJson/extras/tests/JsonDocument/nesting.cpp index 3284dd1c2669a8d427613b1b618f641fad1381eb..7ac7e7685e51a4030b1c5cb11586e8d9713c459a 100644 --- a/neosensor/libraries/ArduinoJson/extras/tests/JsonDocument/nesting.cpp +++ b/neosensor/libraries/ArduinoJson/extras/tests/JsonDocument/nesting.cpp @@ -1,5 +1,5 @@ // ArduinoJson - https://arduinojson.org -// Copyright © 2014-2022, Benoit BLANCHON +// Copyright © 2014-2023, Benoit BLANCHON // MIT License #include <ArduinoJson.h> diff --git a/neosensor/libraries/ArduinoJson/extras/tests/JsonDocument/overflowed.cpp b/neosensor/libraries/ArduinoJson/extras/tests/JsonDocument/overflowed.cpp index cea0db9d5f1354cafe0e2242ef1106a2ed126734..e46d21b09b298f6e09f9f42c089293596c6a2a7a 100644 --- a/neosensor/libraries/ArduinoJson/extras/tests/JsonDocument/overflowed.cpp +++ b/neosensor/libraries/ArduinoJson/extras/tests/JsonDocument/overflowed.cpp @@ -1,5 +1,5 @@ // ArduinoJson - https://arduinojson.org -// Copyright © 2014-2022, Benoit BLANCHON +// Copyright © 2014-2023, Benoit BLANCHON // MIT License #include <ArduinoJson.h> diff --git a/neosensor/libraries/ArduinoJson/extras/tests/JsonDocument/remove.cpp b/neosensor/libraries/ArduinoJson/extras/tests/JsonDocument/remove.cpp index b777073396331aea4380f753724fd2dc2b0dbdba..724b324d5deb1e71ab52ade2563cecdbc8047f23 100644 --- a/neosensor/libraries/ArduinoJson/extras/tests/JsonDocument/remove.cpp +++ b/neosensor/libraries/ArduinoJson/extras/tests/JsonDocument/remove.cpp @@ -1,5 +1,5 @@ // ArduinoJson - https://arduinojson.org -// Copyright © 2014-2022, Benoit BLANCHON +// Copyright © 2014-2023, Benoit BLANCHON // MIT License #include <ArduinoJson.h> diff --git a/neosensor/libraries/ArduinoJson/extras/tests/JsonDocument/shrinkToFit.cpp b/neosensor/libraries/ArduinoJson/extras/tests/JsonDocument/shrinkToFit.cpp index 0eb34e8167cb277b1da7c1f869457a6e3e3da34c..a4423340486cae0504b655abb2220478fdbe4ccd 100644 --- a/neosensor/libraries/ArduinoJson/extras/tests/JsonDocument/shrinkToFit.cpp +++ b/neosensor/libraries/ArduinoJson/extras/tests/JsonDocument/shrinkToFit.cpp @@ -1,5 +1,5 @@ // ArduinoJson - https://arduinojson.org -// Copyright © 2014-2022, Benoit BLANCHON +// Copyright © 2014-2023, Benoit BLANCHON // MIT License #include <ArduinoJson.h> @@ -8,40 +8,38 @@ #include <stdlib.h> // malloc, free #include <string> -using ARDUINOJSON_NAMESPACE::addPadding; - class ArmoredAllocator { public: - ArmoredAllocator() : _ptr(0), _size(0) {} + ArmoredAllocator() : ptr_(0), size_(0) {} void* allocate(size_t size) { - _ptr = malloc(size); - _size = size; - return _ptr; + ptr_ = malloc(size); + size_ = size; + return ptr_; } void deallocate(void* ptr) { - REQUIRE(ptr == _ptr); + REQUIRE(ptr == ptr_); free(ptr); - _ptr = 0; - _size = 0; + ptr_ = 0; + size_ = 0; } void* reallocate(void* ptr, size_t new_size) { - REQUIRE(ptr == _ptr); + REQUIRE(ptr == ptr_); // don't call realloc, instead alloc a new buffer and erase the old one // this way we make sure we support relocation void* new_ptr = malloc(new_size); - memcpy(new_ptr, _ptr, std::min(new_size, _size)); - memset(_ptr, '#', _size); // erase - free(_ptr); - _ptr = new_ptr; + memcpy(new_ptr, ptr_, std::min(new_size, size_)); + memset(ptr_, '#', size_); // erase + free(ptr_); + ptr_ = new_ptr; return new_ptr; } private: - void* _ptr; - size_t _size; + void* ptr_; + size_t size_; }; typedef BasicJsonDocument<ArmoredAllocator> ShrinkToFitTestDocument; diff --git a/neosensor/libraries/ArduinoJson/extras/tests/JsonDocument/size.cpp b/neosensor/libraries/ArduinoJson/extras/tests/JsonDocument/size.cpp index 4fbb6e23ca139be08e6a6683144a7c2a793d0b2d..b3205a14693350ee6f541c93c5caee6effb2d467 100644 --- a/neosensor/libraries/ArduinoJson/extras/tests/JsonDocument/size.cpp +++ b/neosensor/libraries/ArduinoJson/extras/tests/JsonDocument/size.cpp @@ -1,5 +1,5 @@ // ArduinoJson - https://arduinojson.org -// Copyright © 2014-2022, Benoit BLANCHON +// Copyright © 2014-2023, Benoit BLANCHON // MIT License #include <ArduinoJson.h> diff --git a/neosensor/libraries/ArduinoJson/extras/tests/JsonDocument/subscript.cpp b/neosensor/libraries/ArduinoJson/extras/tests/JsonDocument/subscript.cpp index 4ba6ff846670a1006ea3a0b809ba7025b1620e1f..f4186f85d516ddca04e26c91356c728abf9e9d03 100644 --- a/neosensor/libraries/ArduinoJson/extras/tests/JsonDocument/subscript.cpp +++ b/neosensor/libraries/ArduinoJson/extras/tests/JsonDocument/subscript.cpp @@ -1,5 +1,5 @@ // ArduinoJson - https://arduinojson.org -// Copyright © 2014-2022, Benoit BLANCHON +// Copyright © 2014-2023, Benoit BLANCHON // MIT License #include <ArduinoJson.h> diff --git a/neosensor/libraries/ArduinoJson/extras/tests/JsonObject/CMakeLists.txt b/neosensor/libraries/ArduinoJson/extras/tests/JsonObject/CMakeLists.txt index 033e73ea7f0ee60899013061c99c6de731d7eb52..8676811ca0e0d6595190a10f58ae2a8e79609715 100644 --- a/neosensor/libraries/ArduinoJson/extras/tests/JsonObject/CMakeLists.txt +++ b/neosensor/libraries/ArduinoJson/extras/tests/JsonObject/CMakeLists.txt @@ -1,5 +1,5 @@ # ArduinoJson - https://arduinojson.org -# Copyright © 2014-2022, Benoit BLANCHON +# Copyright © 2014-2023, Benoit BLANCHON # MIT License add_executable(JsonObjectTests @@ -25,5 +25,5 @@ add_test(JsonObject JsonObjectTests) set_tests_properties(JsonObject PROPERTIES - LABELS "Catch" + LABELS "Catch" ) diff --git a/neosensor/libraries/ArduinoJson/extras/tests/JsonObject/clear.cpp b/neosensor/libraries/ArduinoJson/extras/tests/JsonObject/clear.cpp index da17b2cffacfa75b78ff812093174f61513006a7..e112a8dcd730f9a430cd54bb87ef0474a7e47bcc 100644 --- a/neosensor/libraries/ArduinoJson/extras/tests/JsonObject/clear.cpp +++ b/neosensor/libraries/ArduinoJson/extras/tests/JsonObject/clear.cpp @@ -1,5 +1,5 @@ // ArduinoJson - https://arduinojson.org -// Copyright © 2014-2022, Benoit BLANCHON +// Copyright © 2014-2023, Benoit BLANCHON // MIT License #include <ArduinoJson.h> diff --git a/neosensor/libraries/ArduinoJson/extras/tests/JsonObject/compare.cpp b/neosensor/libraries/ArduinoJson/extras/tests/JsonObject/compare.cpp index ffdb9aa2f4e3da4d97d3f205ba7f523a7a400875..9b747e3bf40936ae14f44083383ea3899c843c24 100644 --- a/neosensor/libraries/ArduinoJson/extras/tests/JsonObject/compare.cpp +++ b/neosensor/libraries/ArduinoJson/extras/tests/JsonObject/compare.cpp @@ -1,5 +1,5 @@ // ArduinoJson - https://arduinojson.org -// Copyright © 2014-2022, Benoit BLANCHON +// Copyright © 2014-2023, Benoit BLANCHON // MIT License #include <ArduinoJson.h> diff --git a/neosensor/libraries/ArduinoJson/extras/tests/JsonObject/containsKey.cpp b/neosensor/libraries/ArduinoJson/extras/tests/JsonObject/containsKey.cpp index 4f37f7e644b131ba70eebea7872feed89a256476..85335a8890176c9143d5d66671010b9d00912705 100644 --- a/neosensor/libraries/ArduinoJson/extras/tests/JsonObject/containsKey.cpp +++ b/neosensor/libraries/ArduinoJson/extras/tests/JsonObject/containsKey.cpp @@ -1,5 +1,5 @@ // ArduinoJson - https://arduinojson.org -// Copyright © 2014-2022, Benoit BLANCHON +// Copyright © 2014-2023, Benoit BLANCHON // MIT License #include <ArduinoJson.h> diff --git a/neosensor/libraries/ArduinoJson/extras/tests/JsonObject/copy.cpp b/neosensor/libraries/ArduinoJson/extras/tests/JsonObject/copy.cpp index c5514a21fbdab4232ba5e80ac9aa1123a3a7c5da..a4d5b5fa941e39e330dfb2273e4239f3c38ab416 100644 --- a/neosensor/libraries/ArduinoJson/extras/tests/JsonObject/copy.cpp +++ b/neosensor/libraries/ArduinoJson/extras/tests/JsonObject/copy.cpp @@ -1,5 +1,5 @@ // ArduinoJson - https://arduinojson.org -// Copyright © 2014-2022, Benoit BLANCHON +// Copyright © 2014-2023, Benoit BLANCHON // MIT License #include <ArduinoJson.h> diff --git a/neosensor/libraries/ArduinoJson/extras/tests/JsonObject/createNestedArray.cpp b/neosensor/libraries/ArduinoJson/extras/tests/JsonObject/createNestedArray.cpp index 4d43038faeae66c5d687119e8a3462ef3c0655b0..26c1a86055ade38c39705d2ba9fa20ee615c6a53 100644 --- a/neosensor/libraries/ArduinoJson/extras/tests/JsonObject/createNestedArray.cpp +++ b/neosensor/libraries/ArduinoJson/extras/tests/JsonObject/createNestedArray.cpp @@ -1,5 +1,5 @@ // ArduinoJson - https://arduinojson.org -// Copyright © 2014-2022, Benoit BLANCHON +// Copyright © 2014-2023, Benoit BLANCHON // MIT License #include <ArduinoJson.h> diff --git a/neosensor/libraries/ArduinoJson/extras/tests/JsonObject/createNestedObject.cpp b/neosensor/libraries/ArduinoJson/extras/tests/JsonObject/createNestedObject.cpp index 29f4d39dfb84dc21ac4466e6402ef9ca4020e1fd..9ea067a734a174b407c5dcdf76f7f8b456874ca9 100644 --- a/neosensor/libraries/ArduinoJson/extras/tests/JsonObject/createNestedObject.cpp +++ b/neosensor/libraries/ArduinoJson/extras/tests/JsonObject/createNestedObject.cpp @@ -1,5 +1,5 @@ // ArduinoJson - https://arduinojson.org -// Copyright © 2014-2022, Benoit BLANCHON +// Copyright © 2014-2023, Benoit BLANCHON // MIT License #include <ArduinoJson.h> diff --git a/neosensor/libraries/ArduinoJson/extras/tests/JsonObject/equals.cpp b/neosensor/libraries/ArduinoJson/extras/tests/JsonObject/equals.cpp index 101c61262d42350dad0d9163bfcbf8647af7e4bf..02d451f96627ed50f05e812fd1da48e2ab5671ec 100644 --- a/neosensor/libraries/ArduinoJson/extras/tests/JsonObject/equals.cpp +++ b/neosensor/libraries/ArduinoJson/extras/tests/JsonObject/equals.cpp @@ -1,5 +1,5 @@ // ArduinoJson - https://arduinojson.org -// Copyright © 2014-2022, Benoit BLANCHON +// Copyright © 2014-2023, Benoit BLANCHON // MIT License #include <ArduinoJson.h> diff --git a/neosensor/libraries/ArduinoJson/extras/tests/JsonObject/invalid.cpp b/neosensor/libraries/ArduinoJson/extras/tests/JsonObject/invalid.cpp index 199c8f03e8353de0c167d396d95167cbd7c1a511..0695b4814ab99829df6fb0f1d161ffb73e943b4b 100644 --- a/neosensor/libraries/ArduinoJson/extras/tests/JsonObject/invalid.cpp +++ b/neosensor/libraries/ArduinoJson/extras/tests/JsonObject/invalid.cpp @@ -1,5 +1,5 @@ // ArduinoJson - https://arduinojson.org -// Copyright © 2014-2022, Benoit BLANCHON +// Copyright © 2014-2023, Benoit BLANCHON // MIT License #include <ArduinoJson.h> diff --git a/neosensor/libraries/ArduinoJson/extras/tests/JsonObject/isNull.cpp b/neosensor/libraries/ArduinoJson/extras/tests/JsonObject/isNull.cpp index 44403481f0e608316b8d73a2ca176968b89df4d7..9fdff955fb35a31c60e84acba4f8f3fd3e4c4e1e 100644 --- a/neosensor/libraries/ArduinoJson/extras/tests/JsonObject/isNull.cpp +++ b/neosensor/libraries/ArduinoJson/extras/tests/JsonObject/isNull.cpp @@ -1,5 +1,5 @@ // ArduinoJson - https://arduinojson.org -// Copyright © 2014-2022, Benoit BLANCHON +// Copyright © 2014-2023, Benoit BLANCHON // MIT License #include <ArduinoJson.h> diff --git a/neosensor/libraries/ArduinoJson/extras/tests/JsonObject/iterator.cpp b/neosensor/libraries/ArduinoJson/extras/tests/JsonObject/iterator.cpp index e9f2cd2935eec2bf98ac43f8b1df1b8f2dc9fa7d..c48de5f6e3507c5106dcdb0ebdb3677298cc38a6 100644 --- a/neosensor/libraries/ArduinoJson/extras/tests/JsonObject/iterator.cpp +++ b/neosensor/libraries/ArduinoJson/extras/tests/JsonObject/iterator.cpp @@ -1,5 +1,5 @@ // ArduinoJson - https://arduinojson.org -// Copyright © 2014-2022, Benoit BLANCHON +// Copyright © 2014-2023, Benoit BLANCHON // MIT License #include <ArduinoJson.h> diff --git a/neosensor/libraries/ArduinoJson/extras/tests/JsonObject/memoryUsage.cpp b/neosensor/libraries/ArduinoJson/extras/tests/JsonObject/memoryUsage.cpp index 835ee4a7ed9f03b01992f38d301d1e6673d65f64..406bcda4fcf7a9680cb1dcc2646060cc0bd914a7 100644 --- a/neosensor/libraries/ArduinoJson/extras/tests/JsonObject/memoryUsage.cpp +++ b/neosensor/libraries/ArduinoJson/extras/tests/JsonObject/memoryUsage.cpp @@ -1,5 +1,5 @@ // ArduinoJson - https://arduinojson.org -// Copyright © 2014-2022, Benoit BLANCHON +// Copyright © 2014-2023, Benoit BLANCHON // MIT License #include <ArduinoJson.h> diff --git a/neosensor/libraries/ArduinoJson/extras/tests/JsonObject/nesting.cpp b/neosensor/libraries/ArduinoJson/extras/tests/JsonObject/nesting.cpp index 7937c289e9473c2b895455d576d53963a1ed5e97..2ba98adf6aad0e984b8f1520a9310c4de7e9ed41 100644 --- a/neosensor/libraries/ArduinoJson/extras/tests/JsonObject/nesting.cpp +++ b/neosensor/libraries/ArduinoJson/extras/tests/JsonObject/nesting.cpp @@ -1,5 +1,5 @@ // ArduinoJson - https://arduinojson.org -// Copyright © 2014-2022, Benoit BLANCHON +// Copyright © 2014-2023, Benoit BLANCHON // MIT License #include <ArduinoJson.h> diff --git a/neosensor/libraries/ArduinoJson/extras/tests/JsonObject/remove.cpp b/neosensor/libraries/ArduinoJson/extras/tests/JsonObject/remove.cpp index f1cb20cb7979bdf149b1a8c0e152b2b6769c8dbe..1dbd4bd53dd474fec81150d392b5e91c8722c65a 100644 --- a/neosensor/libraries/ArduinoJson/extras/tests/JsonObject/remove.cpp +++ b/neosensor/libraries/ArduinoJson/extras/tests/JsonObject/remove.cpp @@ -1,5 +1,5 @@ // ArduinoJson - https://arduinojson.org -// Copyright © 2014-2022, Benoit BLANCHON +// Copyright © 2014-2023, Benoit BLANCHON // MIT License #include <ArduinoJson.h> diff --git a/neosensor/libraries/ArduinoJson/extras/tests/JsonObject/size.cpp b/neosensor/libraries/ArduinoJson/extras/tests/JsonObject/size.cpp index 0d82cfb8cde201feeb07a084fd68238e71570dd7..d9c7bb78569d0167d209e32d9f3ae291dcf10e7f 100644 --- a/neosensor/libraries/ArduinoJson/extras/tests/JsonObject/size.cpp +++ b/neosensor/libraries/ArduinoJson/extras/tests/JsonObject/size.cpp @@ -1,5 +1,5 @@ // ArduinoJson - https://arduinojson.org -// Copyright © 2014-2022, Benoit BLANCHON +// Copyright © 2014-2023, Benoit BLANCHON // MIT License #include <ArduinoJson.h> diff --git a/neosensor/libraries/ArduinoJson/extras/tests/JsonObject/std_string.cpp b/neosensor/libraries/ArduinoJson/extras/tests/JsonObject/std_string.cpp index bc74d014ea7a0fd28eb1e2fa4984ca23a79e3c75..8a93d3f08b0ba76731f24c22abf0b052386a245b 100644 --- a/neosensor/libraries/ArduinoJson/extras/tests/JsonObject/std_string.cpp +++ b/neosensor/libraries/ArduinoJson/extras/tests/JsonObject/std_string.cpp @@ -1,5 +1,5 @@ // ArduinoJson - https://arduinojson.org -// Copyright © 2014-2022, Benoit BLANCHON +// Copyright © 2014-2023, Benoit BLANCHON // MIT License #include <ArduinoJson.h> diff --git a/neosensor/libraries/ArduinoJson/extras/tests/JsonObject/subscript.cpp b/neosensor/libraries/ArduinoJson/extras/tests/JsonObject/subscript.cpp index e8242f632dda8fb36737e031195afa6e32a909e8..afc567a6e2dc3e19fabf99ff116059ab1870a850 100644 --- a/neosensor/libraries/ArduinoJson/extras/tests/JsonObject/subscript.cpp +++ b/neosensor/libraries/ArduinoJson/extras/tests/JsonObject/subscript.cpp @@ -1,5 +1,5 @@ // ArduinoJson - https://arduinojson.org -// Copyright © 2014-2022, Benoit BLANCHON +// Copyright © 2014-2023, Benoit BLANCHON // MIT License #include <ArduinoJson.h> diff --git a/neosensor/libraries/ArduinoJson/extras/tests/JsonSerializer/CMakeLists.txt b/neosensor/libraries/ArduinoJson/extras/tests/JsonSerializer/CMakeLists.txt index ece6dbc25950ee7331f6265dbff08208dee9858b..0ec4937fb2ee70aec6977aba5d9d60e8585f7c4b 100644 --- a/neosensor/libraries/ArduinoJson/extras/tests/JsonSerializer/CMakeLists.txt +++ b/neosensor/libraries/ArduinoJson/extras/tests/JsonSerializer/CMakeLists.txt @@ -1,5 +1,5 @@ # ArduinoJson - https://arduinojson.org -# Copyright © 2014-2022, Benoit BLANCHON +# Copyright © 2014-2023, Benoit BLANCHON # MIT License add_executable(JsonSerializerTests @@ -18,5 +18,5 @@ add_test(JsonSerializer JsonSerializerTests) set_tests_properties(JsonSerializer PROPERTIES - LABELS "Catch" + LABELS "Catch" ) diff --git a/neosensor/libraries/ArduinoJson/extras/tests/JsonSerializer/CustomWriter.cpp b/neosensor/libraries/ArduinoJson/extras/tests/JsonSerializer/CustomWriter.cpp index d4ba459c9708ea7ae57de07930e6d767b2127be4..a84657a72f8391487d11a4c55f67bbb0439de127 100644 --- a/neosensor/libraries/ArduinoJson/extras/tests/JsonSerializer/CustomWriter.cpp +++ b/neosensor/libraries/ArduinoJson/extras/tests/JsonSerializer/CustomWriter.cpp @@ -1,5 +1,5 @@ // ArduinoJson - https://arduinojson.org -// Copyright © 2014-2022, Benoit BLANCHON +// Copyright © 2014-2023, Benoit BLANCHON // MIT License #include <ArduinoJson.h> @@ -8,26 +8,25 @@ class CustomWriter { public: CustomWriter() {} + CustomWriter(const CustomWriter&) = delete; + CustomWriter& operator=(const CustomWriter&) = delete; size_t write(uint8_t c) { - _str.append(1, static_cast<char>(c)); + str_.append(1, static_cast<char>(c)); return 1; } size_t write(const uint8_t* s, size_t n) { - _str.append(reinterpret_cast<const char*>(s), n); + str_.append(reinterpret_cast<const char*>(s), n); return n; } const std::string& str() const { - return _str; + return str_; } private: - CustomWriter(const CustomWriter&); // non-copiable - CustomWriter& operator=(const CustomWriter&); - - std::string _str; + std::string str_; }; TEST_CASE("CustomWriter") { diff --git a/neosensor/libraries/ArduinoJson/extras/tests/JsonSerializer/JsonArray.cpp b/neosensor/libraries/ArduinoJson/extras/tests/JsonSerializer/JsonArray.cpp index 7cecbf4eda1caab6572974a4496ccd1a684727ac..1fad69ddc715c503f145d40b5c371a57ae3a7db9 100644 --- a/neosensor/libraries/ArduinoJson/extras/tests/JsonSerializer/JsonArray.cpp +++ b/neosensor/libraries/ArduinoJson/extras/tests/JsonSerializer/JsonArray.cpp @@ -1,5 +1,5 @@ // ArduinoJson - https://arduinojson.org -// Copyright © 2014-2022, Benoit BLANCHON +// Copyright © 2014-2023, Benoit BLANCHON // MIT License #include <ArduinoJson.h> diff --git a/neosensor/libraries/ArduinoJson/extras/tests/JsonSerializer/JsonArrayPretty.cpp b/neosensor/libraries/ArduinoJson/extras/tests/JsonSerializer/JsonArrayPretty.cpp index 8c319fc0b12f155e86d005977653c1825d60e476..9abeb0151411ab8b7c8aebd124ce229719f3c610 100644 --- a/neosensor/libraries/ArduinoJson/extras/tests/JsonSerializer/JsonArrayPretty.cpp +++ b/neosensor/libraries/ArduinoJson/extras/tests/JsonSerializer/JsonArrayPretty.cpp @@ -1,5 +1,5 @@ // ArduinoJson - https://arduinojson.org -// Copyright © 2014-2022, Benoit BLANCHON +// Copyright © 2014-2023, Benoit BLANCHON // MIT License #include <ArduinoJson.h> diff --git a/neosensor/libraries/ArduinoJson/extras/tests/JsonSerializer/JsonObject.cpp b/neosensor/libraries/ArduinoJson/extras/tests/JsonSerializer/JsonObject.cpp index 20b90f5219e786e053c342f37e525a69231238ff..9ba21141d46595deb8413239e6f6eed50ae3859b 100644 --- a/neosensor/libraries/ArduinoJson/extras/tests/JsonSerializer/JsonObject.cpp +++ b/neosensor/libraries/ArduinoJson/extras/tests/JsonSerializer/JsonObject.cpp @@ -1,5 +1,5 @@ // ArduinoJson - https://arduinojson.org -// Copyright © 2014-2022, Benoit BLANCHON +// Copyright © 2014-2023, Benoit BLANCHON // MIT License #include <ArduinoJson.h> diff --git a/neosensor/libraries/ArduinoJson/extras/tests/JsonSerializer/JsonObjectPretty.cpp b/neosensor/libraries/ArduinoJson/extras/tests/JsonSerializer/JsonObjectPretty.cpp index ec4ae71b8bd5fa8272429c22751fcecbd0d820a9..4e8d113e22161c53d9972cb7388c153f4c2a984e 100644 --- a/neosensor/libraries/ArduinoJson/extras/tests/JsonSerializer/JsonObjectPretty.cpp +++ b/neosensor/libraries/ArduinoJson/extras/tests/JsonSerializer/JsonObjectPretty.cpp @@ -1,5 +1,5 @@ // ArduinoJson - https://arduinojson.org -// Copyright © 2014-2022, Benoit BLANCHON +// Copyright © 2014-2023, Benoit BLANCHON // MIT License #include <ArduinoJson.h> diff --git a/neosensor/libraries/ArduinoJson/extras/tests/JsonSerializer/JsonVariant.cpp b/neosensor/libraries/ArduinoJson/extras/tests/JsonSerializer/JsonVariant.cpp index 3525a1a478a047b23d9ecfb03c023058c16effbd..81553d315d9b55b0880f0880dccaecb1abdb2a71 100644 --- a/neosensor/libraries/ArduinoJson/extras/tests/JsonSerializer/JsonVariant.cpp +++ b/neosensor/libraries/ArduinoJson/extras/tests/JsonSerializer/JsonVariant.cpp @@ -1,5 +1,5 @@ // ArduinoJson - https://arduinojson.org -// Copyright © 2014-2022, Benoit BLANCHON +// Copyright © 2014-2023, Benoit BLANCHON // MIT License #include <ArduinoJson.h> diff --git a/neosensor/libraries/ArduinoJson/extras/tests/JsonSerializer/std_stream.cpp b/neosensor/libraries/ArduinoJson/extras/tests/JsonSerializer/std_stream.cpp index 74520286a97e181d21aed51ea698ad34f19aa035..411f4792428e290f9dd480b2aea00255caf74d33 100644 --- a/neosensor/libraries/ArduinoJson/extras/tests/JsonSerializer/std_stream.cpp +++ b/neosensor/libraries/ArduinoJson/extras/tests/JsonSerializer/std_stream.cpp @@ -1,5 +1,5 @@ // ArduinoJson - https://arduinojson.org -// Copyright © 2014-2022, Benoit BLANCHON +// Copyright © 2014-2023, Benoit BLANCHON // MIT License #include <ArduinoJson.h> diff --git a/neosensor/libraries/ArduinoJson/extras/tests/JsonSerializer/std_string.cpp b/neosensor/libraries/ArduinoJson/extras/tests/JsonSerializer/std_string.cpp index 7a145da8ecfbff6edc45bab3585c3fcf378d2829..af0d8096ed03bd4267362ec34d8c2f89129fe76a 100644 --- a/neosensor/libraries/ArduinoJson/extras/tests/JsonSerializer/std_string.cpp +++ b/neosensor/libraries/ArduinoJson/extras/tests/JsonSerializer/std_string.cpp @@ -1,5 +1,5 @@ // ArduinoJson - https://arduinojson.org -// Copyright © 2014-2022, Benoit BLANCHON +// Copyright © 2014-2023, Benoit BLANCHON // MIT License #include <ArduinoJson.h> diff --git a/neosensor/libraries/ArduinoJson/extras/tests/JsonVariant/CMakeLists.txt b/neosensor/libraries/ArduinoJson/extras/tests/JsonVariant/CMakeLists.txt index 1a0d14a93257251052be4c4e44c399dc6e016671..d43a971c19e312884541d9853a2ae9b8c8dd0bd9 100644 --- a/neosensor/libraries/ArduinoJson/extras/tests/JsonVariant/CMakeLists.txt +++ b/neosensor/libraries/ArduinoJson/extras/tests/JsonVariant/CMakeLists.txt @@ -1,5 +1,5 @@ # ArduinoJson - https://arduinojson.org -# Copyright © 2014-2022, Benoit BLANCHON +# Copyright © 2014-2023, Benoit BLANCHON # MIT License add_executable(JsonVariantTests @@ -16,12 +16,14 @@ add_executable(JsonVariantTests memoryUsage.cpp misc.cpp nesting.cpp + nullptr.cpp or.cpp overflow.cpp remove.cpp set.cpp shallowCopy.cpp size.cpp + stl_containers.cpp subscript.cpp types.cpp unbound.cpp @@ -31,5 +33,5 @@ add_test(JsonVariant JsonVariantTests) set_tests_properties(JsonVariant PROPERTIES - LABELS "Catch" + LABELS "Catch" ) diff --git a/neosensor/libraries/ArduinoJson/extras/tests/JsonVariant/add.cpp b/neosensor/libraries/ArduinoJson/extras/tests/JsonVariant/add.cpp index 526e914d83ff5294a39ba80dee91bbc8425ff894..6907ae3ed76dde74c524c68bd0fe42065272bcf9 100644 --- a/neosensor/libraries/ArduinoJson/extras/tests/JsonVariant/add.cpp +++ b/neosensor/libraries/ArduinoJson/extras/tests/JsonVariant/add.cpp @@ -1,5 +1,5 @@ // ArduinoJson - https://arduinojson.org -// Copyright © 2014-2022, Benoit BLANCHON +// Copyright © 2014-2023, Benoit BLANCHON // MIT License #include <ArduinoJson.h> diff --git a/neosensor/libraries/ArduinoJson/extras/tests/JsonVariant/as.cpp b/neosensor/libraries/ArduinoJson/extras/tests/JsonVariant/as.cpp index c9956778b62e362b89b0a8b8bb9aa14711aab3a5..01e263e9c7ab3ada09c68374e96f2d77ec84aa0a 100644 --- a/neosensor/libraries/ArduinoJson/extras/tests/JsonVariant/as.cpp +++ b/neosensor/libraries/ArduinoJson/extras/tests/JsonVariant/as.cpp @@ -1,5 +1,5 @@ // ArduinoJson - https://arduinojson.org -// Copyright © 2014-2022, Benoit BLANCHON +// Copyright © 2014-2023, Benoit BLANCHON // MIT License #include <ArduinoJson.h> @@ -7,7 +7,7 @@ #include <catch.hpp> namespace my { -using ARDUINOJSON_NAMESPACE::isinf; +using ArduinoJson::detail::isinf; } // namespace my enum MY_ENUM { ONE = 1, TWO = 2 }; diff --git a/neosensor/libraries/ArduinoJson/extras/tests/JsonVariant/clear.cpp b/neosensor/libraries/ArduinoJson/extras/tests/JsonVariant/clear.cpp index 2b40e324ddfa669d6bd6308c6fe0ec5c7f260937..d516ca6c17e135c7e749ed47c4bd22a6e9a50edc 100644 --- a/neosensor/libraries/ArduinoJson/extras/tests/JsonVariant/clear.cpp +++ b/neosensor/libraries/ArduinoJson/extras/tests/JsonVariant/clear.cpp @@ -1,5 +1,5 @@ // ArduinoJson - https://arduinojson.org -// Copyright © 2014-2022, Benoit BLANCHON +// Copyright © 2014-2023, Benoit BLANCHON // MIT License #include <ArduinoJson.h> diff --git a/neosensor/libraries/ArduinoJson/extras/tests/JsonVariant/compare.cpp b/neosensor/libraries/ArduinoJson/extras/tests/JsonVariant/compare.cpp index 2cbdaa3d5699dfa65c384e4faa54761c81e5dadb..1922df034ab241c9654b4178c42cf2c309b12148 100644 --- a/neosensor/libraries/ArduinoJson/extras/tests/JsonVariant/compare.cpp +++ b/neosensor/libraries/ArduinoJson/extras/tests/JsonVariant/compare.cpp @@ -1,5 +1,5 @@ // ArduinoJson - https://arduinojson.org -// Copyright © 2014-2022, Benoit BLANCHON +// Copyright © 2014-2023, Benoit BLANCHON // MIT License #include <ArduinoJson.h> diff --git a/neosensor/libraries/ArduinoJson/extras/tests/JsonVariant/containsKey.cpp b/neosensor/libraries/ArduinoJson/extras/tests/JsonVariant/containsKey.cpp index fca684ee1ffef032b812f62380bdf1cacf895bb4..d003d11df7e4a0b4c6a244202017046c2141a8f5 100644 --- a/neosensor/libraries/ArduinoJson/extras/tests/JsonVariant/containsKey.cpp +++ b/neosensor/libraries/ArduinoJson/extras/tests/JsonVariant/containsKey.cpp @@ -1,13 +1,11 @@ // ArduinoJson - https://arduinojson.org -// Copyright © 2014-2022, Benoit BLANCHON +// Copyright © 2014-2023, Benoit BLANCHON // MIT License #include <ArduinoJson.h> #include <stdint.h> #include <catch.hpp> -static const char* null = 0; - TEST_CASE("JsonVariant::containsKey()") { DynamicJsonDocument doc(4096); JsonVariant var = doc.to<JsonVariant>(); diff --git a/neosensor/libraries/ArduinoJson/extras/tests/JsonVariant/converters.cpp b/neosensor/libraries/ArduinoJson/extras/tests/JsonVariant/converters.cpp index 7281f2ba1ca968f87269c43b944c98e31f4ba039..89b34dedc90294b37f5be135c0a594a2a806d2ee 100644 --- a/neosensor/libraries/ArduinoJson/extras/tests/JsonVariant/converters.cpp +++ b/neosensor/libraries/ArduinoJson/extras/tests/JsonVariant/converters.cpp @@ -1,5 +1,5 @@ // ArduinoJson - https://arduinojson.org -// Copyright © 2014-2022, Benoit BLANCHON +// Copyright © 2014-2023, Benoit BLANCHON // MIT License #include <ArduinoJson.h> @@ -74,21 +74,21 @@ TEST_CASE("Custom converter with overloading") { class Complex { public: - explicit Complex(double r, double i) : _real(r), _imag(i) {} + explicit Complex(double r, double i) : real_(r), imag_(i) {} double real() const { - return _real; + return real_; } double imag() const { - return _imag; + return imag_; } private: - double _real, _imag; + double real_, imag_; }; -namespace ARDUINOJSON_NAMESPACE { +namespace ArduinoJson { template <> struct Converter<Complex> { static void toJson(const Complex& src, JsonVariant dst) { @@ -104,7 +104,7 @@ struct Converter<Complex> { return src["real"].is<double>() && src["imag"].is<double>(); } }; -} // namespace ARDUINOJSON_NAMESPACE +} // namespace ArduinoJson TEST_CASE("Custom converter with specialization") { DynamicJsonDocument doc(4096); @@ -142,7 +142,7 @@ TEST_CASE("Custom converter with specialization") { } TEST_CASE("ConverterNeedsWriteableRef") { - using namespace ARDUINOJSON_NAMESPACE; + using namespace ArduinoJson::detail; CHECK(ConverterNeedsWriteableRef<int>::value == false); CHECK(ConverterNeedsWriteableRef<float>::value == false); CHECK(ConverterNeedsWriteableRef<JsonVariant>::value == true); diff --git a/neosensor/libraries/ArduinoJson/extras/tests/JsonVariant/copy.cpp b/neosensor/libraries/ArduinoJson/extras/tests/JsonVariant/copy.cpp index 7784f0cadad8a85ad4d1d82d7715e67ddeeb3666..0d96bf9fa604573e0caf39af2beb8cf2bfe0ae9a 100644 --- a/neosensor/libraries/ArduinoJson/extras/tests/JsonVariant/copy.cpp +++ b/neosensor/libraries/ArduinoJson/extras/tests/JsonVariant/copy.cpp @@ -1,5 +1,5 @@ // ArduinoJson - https://arduinojson.org -// Copyright © 2014-2022, Benoit BLANCHON +// Copyright © 2014-2023, Benoit BLANCHON // MIT License #include <ArduinoJson.h> diff --git a/neosensor/libraries/ArduinoJson/extras/tests/JsonVariant/createNested.cpp b/neosensor/libraries/ArduinoJson/extras/tests/JsonVariant/createNested.cpp index efd75015850b3cc531a48b822ab7d84342831888..e3958231e622178bb9be870734ad07bc368d6d99 100644 --- a/neosensor/libraries/ArduinoJson/extras/tests/JsonVariant/createNested.cpp +++ b/neosensor/libraries/ArduinoJson/extras/tests/JsonVariant/createNested.cpp @@ -1,5 +1,5 @@ // ArduinoJson - https://arduinojson.org -// Copyright © 2014-2022, Benoit BLANCHON +// Copyright © 2014-2023, Benoit BLANCHON // MIT License #include <ArduinoJson.h> diff --git a/neosensor/libraries/ArduinoJson/extras/tests/JsonVariant/is.cpp b/neosensor/libraries/ArduinoJson/extras/tests/JsonVariant/is.cpp index 479e923a991caba13b2b338bc8b0921436258ab1..6a414a42fda5084a6f37a1301b0a859adacd8a78 100644 --- a/neosensor/libraries/ArduinoJson/extras/tests/JsonVariant/is.cpp +++ b/neosensor/libraries/ArduinoJson/extras/tests/JsonVariant/is.cpp @@ -1,5 +1,5 @@ // ArduinoJson - https://arduinojson.org -// Copyright © 2014-2022, Benoit BLANCHON +// Copyright © 2014-2023, Benoit BLANCHON // MIT License #include <ArduinoJson.h> diff --git a/neosensor/libraries/ArduinoJson/extras/tests/JsonVariant/isnull.cpp b/neosensor/libraries/ArduinoJson/extras/tests/JsonVariant/isnull.cpp index 1ec6f3539c06ea582b3d8363ee41016d7a6ba55f..bb9de714be5832f90a7aa3b55b61f63af687f8c5 100644 --- a/neosensor/libraries/ArduinoJson/extras/tests/JsonVariant/isnull.cpp +++ b/neosensor/libraries/ArduinoJson/extras/tests/JsonVariant/isnull.cpp @@ -1,5 +1,5 @@ // ArduinoJson - https://arduinojson.org -// Copyright © 2014-2022, Benoit BLANCHON +// Copyright © 2014-2023, Benoit BLANCHON // MIT License #include <ArduinoJson.h> diff --git a/neosensor/libraries/ArduinoJson/extras/tests/JsonVariant/memoryUsage.cpp b/neosensor/libraries/ArduinoJson/extras/tests/JsonVariant/memoryUsage.cpp index 59587dbbabe4d61703f0bd02ff8f49c243df85eb..808acb3a20c90098e56c7c2ed546fc98a775111a 100644 --- a/neosensor/libraries/ArduinoJson/extras/tests/JsonVariant/memoryUsage.cpp +++ b/neosensor/libraries/ArduinoJson/extras/tests/JsonVariant/memoryUsage.cpp @@ -1,5 +1,5 @@ // ArduinoJson - https://arduinojson.org -// Copyright © 2014-2022, Benoit BLANCHON +// Copyright © 2014-2023, Benoit BLANCHON // MIT License #include <ArduinoJson.h> diff --git a/neosensor/libraries/ArduinoJson/extras/tests/JsonVariant/misc.cpp b/neosensor/libraries/ArduinoJson/extras/tests/JsonVariant/misc.cpp index 05976c37770a0bf37ab385799abb0e6c4d014eba..7089f64050510761c87d33a97b90c9a08a519e12 100644 --- a/neosensor/libraries/ArduinoJson/extras/tests/JsonVariant/misc.cpp +++ b/neosensor/libraries/ArduinoJson/extras/tests/JsonVariant/misc.cpp @@ -1,10 +1,15 @@ // ArduinoJson - https://arduinojson.org -// Copyright © 2014-2022, Benoit BLANCHON +// Copyright © 2014-2023, Benoit BLANCHON // MIT License #include <ArduinoJson.h> #include <catch.hpp> +TEST_CASE("VariantData") { + REQUIRE(std::is_standard_layout<ArduinoJson::detail::VariantData>::value == + true); +} + TEST_CASE("JsonVariant from JsonArray") { SECTION("JsonArray is null") { JsonArray arr; diff --git a/neosensor/libraries/ArduinoJson/extras/tests/JsonVariant/nesting.cpp b/neosensor/libraries/ArduinoJson/extras/tests/JsonVariant/nesting.cpp index 3e936fbe49d5c765bb55f1ad1b6861a2a78a9f1b..1028a2838129a642b95bd5ee0ce282eb0efe7c60 100644 --- a/neosensor/libraries/ArduinoJson/extras/tests/JsonVariant/nesting.cpp +++ b/neosensor/libraries/ArduinoJson/extras/tests/JsonVariant/nesting.cpp @@ -1,5 +1,5 @@ // ArduinoJson - https://arduinojson.org -// Copyright © 2014-2022, Benoit BLANCHON +// Copyright © 2014-2023, Benoit BLANCHON // MIT License #include <ArduinoJson.h> diff --git a/neosensor/libraries/ArduinoJson/extras/tests/Cpp11/nullptr.cpp b/neosensor/libraries/ArduinoJson/extras/tests/JsonVariant/nullptr.cpp similarity index 75% rename from neosensor/libraries/ArduinoJson/extras/tests/Cpp11/nullptr.cpp rename to neosensor/libraries/ArduinoJson/extras/tests/JsonVariant/nullptr.cpp index 813b9cc2afbd38e93dc53ee008d83dca889bd549..e26d9306d84d444bce40de9ddb19e54e759f9a62 100644 --- a/neosensor/libraries/ArduinoJson/extras/tests/Cpp11/nullptr.cpp +++ b/neosensor/libraries/ArduinoJson/extras/tests/JsonVariant/nullptr.cpp @@ -2,24 +2,20 @@ #include <catch.hpp> -#if !ARDUINOJSON_HAS_NULLPTR -# error ARDUINOJSON_HAS_NULLPTR must be set to 1 -#endif - TEST_CASE("nullptr") { DynamicJsonDocument doc(4096); JsonVariant variant = doc.to<JsonVariant>(); SECTION("JsonVariant == nullptr") { - REQUIRE((variant == nullptr)); - REQUIRE_FALSE((variant != nullptr)); + REQUIRE(variant == nullptr); + REQUIRE_FALSE(variant != nullptr); } SECTION("JsonVariant != nullptr") { variant.set(42); - REQUIRE_FALSE((variant == nullptr)); - REQUIRE((variant != nullptr)); + REQUIRE_FALSE(variant == nullptr); + REQUIRE(variant != nullptr); } SECTION("JsonVariant.set(nullptr)") { diff --git a/neosensor/libraries/ArduinoJson/extras/tests/JsonVariant/or.cpp b/neosensor/libraries/ArduinoJson/extras/tests/JsonVariant/or.cpp index 7d1c190b8aa7403c46ceae0172fcd7bcc427e3f9..01ec4701c8ae3aec8e62590bdebacd93d444ab67 100644 --- a/neosensor/libraries/ArduinoJson/extras/tests/JsonVariant/or.cpp +++ b/neosensor/libraries/ArduinoJson/extras/tests/JsonVariant/or.cpp @@ -1,5 +1,5 @@ // ArduinoJson - https://arduinojson.org -// Copyright © 2014-2022, Benoit BLANCHON +// Copyright © 2014-2023, Benoit BLANCHON // MIT License #include <ArduinoJson.h> diff --git a/neosensor/libraries/ArduinoJson/extras/tests/JsonVariant/overflow.cpp b/neosensor/libraries/ArduinoJson/extras/tests/JsonVariant/overflow.cpp index ff0e3aa50ea4220b53a82c506041ddc0e5c8a40d..1123e98b80de946973b5177f681d838fc6fcbc83 100644 --- a/neosensor/libraries/ArduinoJson/extras/tests/JsonVariant/overflow.cpp +++ b/neosensor/libraries/ArduinoJson/extras/tests/JsonVariant/overflow.cpp @@ -1,5 +1,5 @@ // ArduinoJson - https://arduinojson.org -// Copyright © 2014-2022, Benoit BLANCHON +// Copyright © 2014-2023, Benoit BLANCHON // MIT License #include <ArduinoJson.h> diff --git a/neosensor/libraries/ArduinoJson/extras/tests/JsonVariant/remove.cpp b/neosensor/libraries/ArduinoJson/extras/tests/JsonVariant/remove.cpp index c744e19bbb1f4b2d2fa6fb0be7cfa100039b30d3..0835bf0ee593503834f4c8701dbf09a1ef6206f4 100644 --- a/neosensor/libraries/ArduinoJson/extras/tests/JsonVariant/remove.cpp +++ b/neosensor/libraries/ArduinoJson/extras/tests/JsonVariant/remove.cpp @@ -1,13 +1,11 @@ // ArduinoJson - https://arduinojson.org -// Copyright © 2014-2022, Benoit BLANCHON +// Copyright © 2014-2023, Benoit BLANCHON // MIT License #include <ArduinoJson.h> #include <stdint.h> #include <catch.hpp> -static const char* null = 0; - TEST_CASE("JsonVariant::remove()") { DynamicJsonDocument doc(4096); JsonVariant var = doc.to<JsonVariant>(); diff --git a/neosensor/libraries/ArduinoJson/extras/tests/JsonVariant/set.cpp b/neosensor/libraries/ArduinoJson/extras/tests/JsonVariant/set.cpp index 9188c98aa5f35ea2282c527d7e244de74e089971..4743afb970e3e02e1d9e4e51454a89dacbbf4e62 100644 --- a/neosensor/libraries/ArduinoJson/extras/tests/JsonVariant/set.cpp +++ b/neosensor/libraries/ArduinoJson/extras/tests/JsonVariant/set.cpp @@ -1,5 +1,5 @@ // ArduinoJson - https://arduinojson.org -// Copyright © 2014-2022, Benoit BLANCHON +// Copyright © 2014-2023, Benoit BLANCHON // MIT License #include <ArduinoJson.h> diff --git a/neosensor/libraries/ArduinoJson/extras/tests/JsonVariant/shallowCopy.cpp b/neosensor/libraries/ArduinoJson/extras/tests/JsonVariant/shallowCopy.cpp index c7c334b73a156d3e8e1df50dbabc24704281ed86..28aa38c60c9fe673432be20cf21266af82f25af1 100644 --- a/neosensor/libraries/ArduinoJson/extras/tests/JsonVariant/shallowCopy.cpp +++ b/neosensor/libraries/ArduinoJson/extras/tests/JsonVariant/shallowCopy.cpp @@ -1,5 +1,5 @@ // ArduinoJson - https://arduinojson.org -// Copyright © 2014-2022, Benoit BLANCHON +// Copyright © 2014-2023, Benoit BLANCHON // MIT License #include <ArduinoJson.h> diff --git a/neosensor/libraries/ArduinoJson/extras/tests/JsonVariant/size.cpp b/neosensor/libraries/ArduinoJson/extras/tests/JsonVariant/size.cpp index 73d9ced80c962914f8dd05ca1ef5c846eb0d11f9..3a4ec4676444fc7dc7768c96e688f084db36aba1 100644 --- a/neosensor/libraries/ArduinoJson/extras/tests/JsonVariant/size.cpp +++ b/neosensor/libraries/ArduinoJson/extras/tests/JsonVariant/size.cpp @@ -1,5 +1,5 @@ // ArduinoJson - https://arduinojson.org -// Copyright © 2014-2022, Benoit BLANCHON +// Copyright © 2014-2023, Benoit BLANCHON // MIT License #include <ArduinoJson.h> diff --git a/neosensor/libraries/ArduinoJson/extras/tests/JsonVariant/stl_containers.cpp b/neosensor/libraries/ArduinoJson/extras/tests/JsonVariant/stl_containers.cpp new file mode 100644 index 0000000000000000000000000000000000000000..d6b9b60bc1d373094df822955d01f08cc9ae34b0 --- /dev/null +++ b/neosensor/libraries/ArduinoJson/extras/tests/JsonVariant/stl_containers.cpp @@ -0,0 +1,138 @@ +// ArduinoJson - https://arduinojson.org +// Copyright © 2014-2023, Benoit BLANCHON +// MIT License + +#include <ArduinoJson.h> +#include <stdint.h> +#include <catch.hpp> + +#include <array> +#include <string> +#include <vector> + +namespace ArduinoJson { +template <typename T> +struct Converter<std::vector<T>> { + static void toJson(const std::vector<T>& src, JsonVariant dst) { + JsonArray array = dst.to<JsonArray>(); + for (T item : src) + array.add(item); + } + + static std::vector<T> fromJson(JsonVariantConst src) { + std::vector<T> dst; + for (T item : src.as<JsonArrayConst>()) + dst.push_back(item); + return dst; + } + + static bool checkJson(JsonVariantConst src) { + JsonArrayConst array = src; + bool result = array; + for (JsonVariantConst item : array) + result &= item.is<T>(); + return result; + } +}; + +template <typename T, size_t N> +struct Converter<std::array<T, N>> { + static void toJson(const std::array<T, N>& src, JsonVariant dst) { + JsonArray array = dst.to<JsonArray>(); + for (T item : src) + array.add(item); + } + + static std::array<T, N> fromJson(JsonVariantConst src) { + std::array<T, N> dst; + dst.fill(0); + size_t idx = 0; + for (T item : src.as<JsonArrayConst>()) + dst[idx++] = item; + return dst; + } + + static bool checkJson(JsonVariantConst src) { + JsonArrayConst array = src; + bool result = array; + size_t size = 0; + for (JsonVariantConst item : array) { + result &= item.is<T>(); + size++; + } + return result && size == N; + } +}; +} // namespace ArduinoJson + +TEST_CASE("vector<int>") { + SECTION("toJson") { + std::vector<int> v = {1, 2}; + + StaticJsonDocument<128> doc; + doc.set(v); + REQUIRE(doc.as<std::string>() == "[1,2]"); + } + + SECTION("fromJson") { + StaticJsonDocument<128> doc; + doc.add(1); + doc.add(2); + + auto v = doc.as<std::vector<int>>(); + REQUIRE(v.size() == 2); + CHECK(v[0] == 1); + CHECK(v[1] == 2); + } + + SECTION("checkJson") { + StaticJsonDocument<128> doc; + CHECK(doc.is<std::vector<int>>() == false); + + doc.add(1); + doc.add(2); + CHECK(doc.is<std::vector<int>>() == true); + + doc.add("foo"); + CHECK(doc.is<std::vector<int>>() == false); + } +} + +TEST_CASE("array<int, 2>") { + typedef std::array<int, 2> array_type; + + SECTION("toJson") { + array_type v; + v[0] = 1; + v[1] = 2; + + StaticJsonDocument<128> doc; + doc.set(v); + REQUIRE(doc.as<std::string>() == "[1,2]"); + } + + SECTION("fromJson") { + StaticJsonDocument<128> doc; + doc.add(1); + doc.add(2); + + auto v = doc.as<array_type>(); + REQUIRE(v.size() == 2); + CHECK(v[0] == 1); + CHECK(v[1] == 2); + } + + SECTION("checkJson") { + StaticJsonDocument<128> doc; + CHECK(doc.is<array_type>() == false); + + doc.add(1); + CHECK(doc.is<array_type>() == false); + + doc.add(2); + CHECK(doc.is<array_type>() == true); + + doc[0] = "foo"; + CHECK(doc.is<array_type>() == false); + } +} diff --git a/neosensor/libraries/ArduinoJson/extras/tests/JsonVariant/subscript.cpp b/neosensor/libraries/ArduinoJson/extras/tests/JsonVariant/subscript.cpp index f466cd275c0f31e818e54f02f2713567c2fe87a0..93f759b8b70e5ca34bc7dcb9f9b6e9f6e11b6d1c 100644 --- a/neosensor/libraries/ArduinoJson/extras/tests/JsonVariant/subscript.cpp +++ b/neosensor/libraries/ArduinoJson/extras/tests/JsonVariant/subscript.cpp @@ -1,5 +1,5 @@ // ArduinoJson - https://arduinojson.org -// Copyright © 2014-2022, Benoit BLANCHON +// Copyright © 2014-2023, Benoit BLANCHON // MIT License #include <ArduinoJson.h> diff --git a/neosensor/libraries/ArduinoJson/extras/tests/JsonVariant/types.cpp b/neosensor/libraries/ArduinoJson/extras/tests/JsonVariant/types.cpp index e37949902737d70a0bb7c3005949e0dbd2510ac2..4224299108edc2ad537cad1caedcb50f40ba91db 100644 --- a/neosensor/libraries/ArduinoJson/extras/tests/JsonVariant/types.cpp +++ b/neosensor/libraries/ArduinoJson/extras/tests/JsonVariant/types.cpp @@ -1,5 +1,5 @@ // ArduinoJson - https://arduinojson.org -// Copyright © 2014-2022, Benoit BLANCHON +// Copyright © 2014-2023, Benoit BLANCHON // MIT License #include <ArduinoJson.h> diff --git a/neosensor/libraries/ArduinoJson/extras/tests/JsonVariant/unbound.cpp b/neosensor/libraries/ArduinoJson/extras/tests/JsonVariant/unbound.cpp index 8089e1cca6f5d65c4caf7bcc514ef139131be455..902032363fc84582c1276e7614d98722a6211508 100644 --- a/neosensor/libraries/ArduinoJson/extras/tests/JsonVariant/unbound.cpp +++ b/neosensor/libraries/ArduinoJson/extras/tests/JsonVariant/unbound.cpp @@ -1,5 +1,5 @@ // ArduinoJson - https://arduinojson.org -// Copyright © 2014-2022, Benoit BLANCHON +// Copyright © 2014-2023, Benoit BLANCHON // MIT License #include <ArduinoJson.h> diff --git a/neosensor/libraries/ArduinoJson/extras/tests/MemoryPool/CMakeLists.txt b/neosensor/libraries/ArduinoJson/extras/tests/MemoryPool/CMakeLists.txt index 80ba3c6de49d86022f45c13afc0ac1bf75164bbd..2f809cc26d5fa5d7e2677ac5aff3c06f46f95960 100644 --- a/neosensor/libraries/ArduinoJson/extras/tests/MemoryPool/CMakeLists.txt +++ b/neosensor/libraries/ArduinoJson/extras/tests/MemoryPool/CMakeLists.txt @@ -1,8 +1,8 @@ # ArduinoJson - https://arduinojson.org -# Copyright © 2014-2022, Benoit BLANCHON +# Copyright © 2014-2023, Benoit BLANCHON # MIT License -add_executable(MemoryPoolTests +add_executable(MemoryPoolTests allocVariant.cpp clear.cpp saveString.cpp @@ -14,5 +14,5 @@ add_test(MemoryPool MemoryPoolTests) set_tests_properties(MemoryPool PROPERTIES - LABELS "Catch" + LABELS "Catch" ) diff --git a/neosensor/libraries/ArduinoJson/extras/tests/MemoryPool/StringCopier.cpp b/neosensor/libraries/ArduinoJson/extras/tests/MemoryPool/StringCopier.cpp index c6159053f40e6a6211ada404a366cf2404e679b6..0342bc4fc4af31c8f16068ea6ca4002bf35aff89 100644 --- a/neosensor/libraries/ArduinoJson/extras/tests/MemoryPool/StringCopier.cpp +++ b/neosensor/libraries/ArduinoJson/extras/tests/MemoryPool/StringCopier.cpp @@ -1,11 +1,11 @@ // ArduinoJson - https://arduinojson.org -// Copyright © 2014-2022, Benoit BLANCHON +// Copyright © 2014-2023, Benoit BLANCHON // MIT License #include <ArduinoJson/StringStorage/StringCopier.hpp> #include <catch.hpp> -using namespace ARDUINOJSON_NAMESPACE; +using namespace ArduinoJson::detail; TEST_CASE("StringCopier") { char buffer[4096]; diff --git a/neosensor/libraries/ArduinoJson/extras/tests/MemoryPool/allocVariant.cpp b/neosensor/libraries/ArduinoJson/extras/tests/MemoryPool/allocVariant.cpp index 606d6d7b992bedfa6031c360254fa234fe83cb94..5123a4e25eb53711e917efc3401d1769d6fec1b3 100644 --- a/neosensor/libraries/ArduinoJson/extras/tests/MemoryPool/allocVariant.cpp +++ b/neosensor/libraries/ArduinoJson/extras/tests/MemoryPool/allocVariant.cpp @@ -1,11 +1,11 @@ // ArduinoJson - https://arduinojson.org -// Copyright © 2014-2022, Benoit BLANCHON +// Copyright © 2014-2023, Benoit BLANCHON // MIT License #include <ArduinoJson/Memory/MemoryPool.hpp> #include <catch.hpp> -using namespace ARDUINOJSON_NAMESPACE; +using namespace ArduinoJson::detail; TEST_CASE("MemoryPool::allocVariant()") { char buffer[4096]; diff --git a/neosensor/libraries/ArduinoJson/extras/tests/MemoryPool/clear.cpp b/neosensor/libraries/ArduinoJson/extras/tests/MemoryPool/clear.cpp index 66e7775c235d4f9656ca9e782a4e566ebdd6b05c..9e33b4718c8fdce2589080bd8b95e151e0747a2d 100644 --- a/neosensor/libraries/ArduinoJson/extras/tests/MemoryPool/clear.cpp +++ b/neosensor/libraries/ArduinoJson/extras/tests/MemoryPool/clear.cpp @@ -1,12 +1,12 @@ // ArduinoJson - https://arduinojson.org -// Copyright © 2014-2022, Benoit BLANCHON +// Copyright © 2014-2023, Benoit BLANCHON // MIT License #include <ArduinoJson/Memory/MemoryPool.hpp> #include <ArduinoJson/Strings/StringAdapters.hpp> #include <catch.hpp> -using namespace ARDUINOJSON_NAMESPACE; +using namespace ArduinoJson::detail; static const size_t poolCapacity = 512; diff --git a/neosensor/libraries/ArduinoJson/extras/tests/MemoryPool/saveString.cpp b/neosensor/libraries/ArduinoJson/extras/tests/MemoryPool/saveString.cpp index 7e0548ccc0b3cca618c83d2bd44c56969fec0127..ba8d5b91ba53759750088079a76fa2bf3a3e9519 100644 --- a/neosensor/libraries/ArduinoJson/extras/tests/MemoryPool/saveString.cpp +++ b/neosensor/libraries/ArduinoJson/extras/tests/MemoryPool/saveString.cpp @@ -1,12 +1,12 @@ // ArduinoJson - https://arduinojson.org -// Copyright © 2014-2022, Benoit BLANCHON +// Copyright © 2014-2023, Benoit BLANCHON // MIT License #include <ArduinoJson/Memory/MemoryPool.hpp> #include <ArduinoJson/Strings/StringAdapters.hpp> #include <catch.hpp> -using namespace ARDUINOJSON_NAMESPACE; +using namespace ArduinoJson::detail; static const char* saveString(MemoryPool& pool, const char* s) { return pool.saveString(adaptString(const_cast<char*>(s))); diff --git a/neosensor/libraries/ArduinoJson/extras/tests/MemoryPool/size.cpp b/neosensor/libraries/ArduinoJson/extras/tests/MemoryPool/size.cpp index 5179b10557c542e73f9de02d1b107ff6a24b2c04..057f4ab30fa3a5b84791fbe561664b143788feea 100644 --- a/neosensor/libraries/ArduinoJson/extras/tests/MemoryPool/size.cpp +++ b/neosensor/libraries/ArduinoJson/extras/tests/MemoryPool/size.cpp @@ -1,11 +1,11 @@ // ArduinoJson - https://arduinojson.org -// Copyright © 2014-2022, Benoit BLANCHON +// Copyright © 2014-2023, Benoit BLANCHON // MIT License #include <ArduinoJson/Memory/MemoryPool.hpp> #include <catch.hpp> -using namespace ARDUINOJSON_NAMESPACE; +using namespace ArduinoJson::detail; TEST_CASE("MemoryPool::capacity()") { char buffer[4096]; diff --git a/neosensor/libraries/ArduinoJson/extras/tests/Misc/CMakeLists.txt b/neosensor/libraries/ArduinoJson/extras/tests/Misc/CMakeLists.txt index d567efbd40dce5eed6a023e1d39c46eb12a59b56..5655a08924b81dabb0f8d25226fec66bac10ff09 100644 --- a/neosensor/libraries/ArduinoJson/extras/tests/Misc/CMakeLists.txt +++ b/neosensor/libraries/ArduinoJson/extras/tests/Misc/CMakeLists.txt @@ -1,5 +1,5 @@ # ArduinoJson - https://arduinojson.org -# Copyright © 2014-2022, Benoit BLANCHON +# Copyright © 2014-2023, Benoit BLANCHON # MIT License add_executable(MiscTests @@ -25,5 +25,5 @@ add_test(Misc MiscTests) set_tests_properties(Misc PROPERTIES - LABELS "Catch" + LABELS "Catch" ) diff --git a/neosensor/libraries/ArduinoJson/extras/tests/Misc/FloatParts.cpp b/neosensor/libraries/ArduinoJson/extras/tests/Misc/FloatParts.cpp index 736b176cbec09a1aa8982f9066cd514fc5d57771..8e3d82e15413d683273dfe95431053adfe7c4593 100644 --- a/neosensor/libraries/ArduinoJson/extras/tests/Misc/FloatParts.cpp +++ b/neosensor/libraries/ArduinoJson/extras/tests/Misc/FloatParts.cpp @@ -1,11 +1,11 @@ // ArduinoJson - https://arduinojson.org -// Copyright © 2014-2022, Benoit BLANCHON +// Copyright © 2014-2023, Benoit BLANCHON // MIT License #include <ArduinoJson/Numbers/FloatParts.hpp> #include <catch.hpp> -using namespace ARDUINOJSON_NAMESPACE; +using namespace ArduinoJson::detail; TEST_CASE("FloatParts<double>") { SECTION("1.7976931348623157E+308") { diff --git a/neosensor/libraries/ArduinoJson/extras/tests/Misc/JsonString.cpp b/neosensor/libraries/ArduinoJson/extras/tests/Misc/JsonString.cpp index 557f99366250fa943ab9fac7f60958cfc04e18fe..c3dca1728dc2ec4c1bde1a71fe1a014f69d932a5 100644 --- a/neosensor/libraries/ArduinoJson/extras/tests/Misc/JsonString.cpp +++ b/neosensor/libraries/ArduinoJson/extras/tests/Misc/JsonString.cpp @@ -1,5 +1,5 @@ // ArduinoJson - https://arduinojson.org -// Copyright © 2014-2022, Benoit BLANCHON +// Copyright © 2014-2023, Benoit BLANCHON // MIT License #include <ArduinoJson.h> diff --git a/neosensor/libraries/ArduinoJson/extras/tests/Misc/NoArduinoHeader.cpp b/neosensor/libraries/ArduinoJson/extras/tests/Misc/NoArduinoHeader.cpp index 43a82b24916cdfc4eaf6c4026108f2e499109a5a..4b0218bff50c2dd203abf8d5403fad653f373291 100644 --- a/neosensor/libraries/ArduinoJson/extras/tests/Misc/NoArduinoHeader.cpp +++ b/neosensor/libraries/ArduinoJson/extras/tests/Misc/NoArduinoHeader.cpp @@ -1,5 +1,5 @@ // ArduinoJson - https://arduinojson.org -// Copyright © 2014-2022, Benoit BLANCHON +// Copyright © 2014-2023, Benoit BLANCHON // MIT License #define ARDUINO 1 diff --git a/neosensor/libraries/ArduinoJson/extras/tests/Misc/Readers.cpp b/neosensor/libraries/ArduinoJson/extras/tests/Misc/Readers.cpp index e46ad1e72c4732b4194a59775465baad84918ae0..0b8f4d5025ce5a49fc38297759dd76d4363a6050 100644 --- a/neosensor/libraries/ArduinoJson/extras/tests/Misc/Readers.cpp +++ b/neosensor/libraries/ArduinoJson/extras/tests/Misc/Readers.cpp @@ -1,12 +1,14 @@ // ArduinoJson - https://arduinojson.org -// Copyright © 2014-2022, Benoit BLANCHON +// Copyright © 2014-2023, Benoit BLANCHON // MIT License #include <Arduino.h> #include <ArduinoJson.hpp> #include <catch.hpp> -using namespace ARDUINOJSON_NAMESPACE; +#include <sstream> + +using namespace ArduinoJson::detail; TEST_CASE("Reader<std::istringstream>") { SECTION("read()") { @@ -168,19 +170,19 @@ TEST_CASE("IteratorReader") { class StreamStub : public Stream { public: - StreamStub(const char* s) : _stream(s) {} + StreamStub(const char* s) : stream_(s) {} int read() { - return _stream.get(); + return stream_.get(); } size_t readBytes(char* buffer, size_t length) { - _stream.read(buffer, static_cast<std::streamsize>(length)); - return static_cast<size_t>(_stream.gcount()); + stream_.read(buffer, static_cast<std::streamsize>(length)); + return static_cast<size_t>(stream_.gcount()); } private: - std::istringstream _stream; + std::istringstream stream_; }; TEST_CASE("Reader<Stream>") { diff --git a/neosensor/libraries/ArduinoJson/extras/tests/Misc/StringAdapters.cpp b/neosensor/libraries/ArduinoJson/extras/tests/Misc/StringAdapters.cpp index 0228233452e273fb6330ea6543a714454f81af67..1c77e08bf76f08fed9c84f4efb991c825eeb1cd4 100644 --- a/neosensor/libraries/ArduinoJson/extras/tests/Misc/StringAdapters.cpp +++ b/neosensor/libraries/ArduinoJson/extras/tests/Misc/StringAdapters.cpp @@ -1,19 +1,18 @@ // ArduinoJson - https://arduinojson.org -// Copyright © 2014-2022, Benoit BLANCHON +// Copyright © 2014-2023, Benoit BLANCHON // MIT License -#define ARDUINOJSON_ENABLE_PROGMEM 1 -#define ARDUINOJSON_ENABLE_ARDUINO_STRING 1 - -#include "custom_string.hpp" -#include "weird_strcmp.hpp" +#include <Arduino.h> #include <ArduinoJson/Strings/IsString.hpp> #include <ArduinoJson/Strings/StringAdapters.hpp> #include <catch.hpp> -using namespace ARDUINOJSON_NAMESPACE; +#include "custom_string.hpp" +#include "weird_strcmp.hpp" + +using namespace ArduinoJson::detail; TEST_CASE("ZeroTerminatedRamString") { SECTION("null") { @@ -90,13 +89,13 @@ struct EmptyStruct {}; TEST_CASE("IsString<T>") { CHECK(IsString<std::string>::value == true); - CHECK(IsString<std::basic_string<wchar_t> >::value == false); + CHECK(IsString<std::basic_string<wchar_t>>::value == false); CHECK(IsString<custom_string>::value == true); CHECK(IsString<const __FlashStringHelper*>::value == true); CHECK(IsString<const char*>::value == true); CHECK(IsString<const char[8]>::value == true); - CHECK(IsString< ::String>::value == true); - CHECK(IsString< ::StringSumHelper>::value == true); + CHECK(IsString<::String>::value == true); + CHECK(IsString<::StringSumHelper>::value == true); CHECK(IsString<const EmptyStruct*>::value == false); } diff --git a/neosensor/libraries/ArduinoJson/extras/tests/Misc/StringWriter.cpp b/neosensor/libraries/ArduinoJson/extras/tests/Misc/StringWriter.cpp index bdb5bdb1fb34d6ef3d16e2c193a24660c477e92f..81cb88e924b2fc4a3fb8cabf6edf3a7f0a76bf7f 100644 --- a/neosensor/libraries/ArduinoJson/extras/tests/Misc/StringWriter.cpp +++ b/neosensor/libraries/ArduinoJson/extras/tests/Misc/StringWriter.cpp @@ -1,14 +1,17 @@ // ArduinoJson - https://arduinojson.org -// Copyright © 2014-2022, Benoit BLANCHON +// Copyright © 2014-2023, Benoit BLANCHON // MIT License -#define ARDUINOJSON_ENABLE_ARDUINO_STRING 1 +#include <Arduino.h> + #define ARDUINOJSON_STRING_BUFFER_SIZE 5 #include <ArduinoJson.h> + #include <catch.hpp> + #include "custom_string.hpp" -using namespace ARDUINOJSON_NAMESPACE; +using namespace ArduinoJson::detail; template <typename StringWriter> static size_t print(StringWriter& writer, const char* s) { @@ -65,7 +68,7 @@ TEST_CASE("Writer<std::string>") { TEST_CASE("Writer<String>") { ::String output; - Writer< ::String> writer(output); + Writer<::String> writer(output); SECTION("write(char)") { SECTION("writes to temporary buffer") { diff --git a/neosensor/libraries/ArduinoJson/extras/tests/Misc/TypeTraits.cpp b/neosensor/libraries/ArduinoJson/extras/tests/Misc/TypeTraits.cpp index 76ec486171a2de7c6f56630785c9dd9ec1a55832..10b6168b598294fb7466fe1d21ee200bc9e4b047 100644 --- a/neosensor/libraries/ArduinoJson/extras/tests/Misc/TypeTraits.cpp +++ b/neosensor/libraries/ArduinoJson/extras/tests/Misc/TypeTraits.cpp @@ -1,11 +1,13 @@ // ArduinoJson - https://arduinojson.org -// Copyright © 2014-2022, Benoit BLANCHON +// Copyright © 2014-2023, Benoit BLANCHON // MIT License #include <ArduinoJson.h> #include <catch.hpp> -using namespace ARDUINOJSON_NAMESPACE; +#include <sstream> + +using namespace ArduinoJson::detail; class EmptyClass {}; enum EmptyEnum {}; @@ -19,9 +21,9 @@ TEST_CASE("Polyfills/type_traits") { } SECTION("is_array") { - REQUIRE_FALSE((is_array<const char*>::value)); - REQUIRE((is_array<const char[]>::value)); - REQUIRE((is_array<const char[10]>::value)); + REQUIRE_FALSE(is_array<const char*>::value); + REQUIRE(is_array<const char[]>::value); + REQUIRE(is_array<const char[10]>::value); } SECTION("is_const") { @@ -172,36 +174,35 @@ TEST_CASE("Polyfills/type_traits") { } SECTION("is_convertible") { - CHECK((is_convertible<short, int>::value == true)); - CHECK((is_convertible<int, int>::value == true)); - CHECK((is_convertible<EmptyEnum, int>::value == true)); - CHECK((is_convertible<int*, int>::value == false)); - CHECK((is_convertible<EmptyClass, int>::value == false)); - - CHECK((is_convertible<DeserializationError, JsonVariantConst>::value == - false)); - CHECK((is_convertible<JsonPair, JsonVariantConst>::value == false)); - CHECK((is_convertible<JsonVariant, JsonVariantConst>::value == true)); - CHECK((is_convertible<JsonVariantConst, JsonVariantConst>::value == true)); - CHECK((is_convertible<JsonArray, JsonVariantConst>::value == true)); - CHECK((is_convertible<ElementProxy<JsonArray>, JsonVariantConst>::value == - true)); - CHECK((is_convertible<JsonArrayConst, JsonVariantConst>::value == true)); - CHECK((is_convertible<JsonObject, JsonVariantConst>::value == true)); - CHECK((is_convertible<MemberProxy<JsonObject, const char*>, - JsonVariantConst>::value == true)); - CHECK((is_convertible<JsonObjectConst, JsonVariantConst>::value == true)); - CHECK( - (is_convertible<DynamicJsonDocument, JsonVariantConst>::value == true)); - CHECK((is_convertible<StaticJsonDocument<10>, JsonVariantConst>::value == - true)); + CHECK(is_convertible<short, int>::value == true); + CHECK(is_convertible<int, int>::value == true); + CHECK(is_convertible<EmptyEnum, int>::value == true); + CHECK(is_convertible<int*, int>::value == false); + CHECK(is_convertible<EmptyClass, int>::value == false); + + CHECK(is_convertible<DeserializationError, JsonVariantConst>::value == + false); + CHECK(is_convertible<JsonPair, JsonVariantConst>::value == false); + CHECK(is_convertible<JsonVariant, JsonVariantConst>::value == true); + CHECK(is_convertible<JsonVariantConst, JsonVariantConst>::value == true); + CHECK(is_convertible<JsonArray, JsonVariantConst>::value == true); + CHECK(is_convertible<ElementProxy<JsonArray>, JsonVariantConst>::value == + true); + CHECK(is_convertible<JsonArrayConst, JsonVariantConst>::value == true); + CHECK(is_convertible<JsonObject, JsonVariantConst>::value == true); + CHECK(is_convertible<MemberProxy<JsonObject, const char*>, + JsonVariantConst>::value == true); + CHECK(is_convertible<JsonObjectConst, JsonVariantConst>::value == true); + CHECK(is_convertible<DynamicJsonDocument, JsonVariantConst>::value == true); + CHECK(is_convertible<StaticJsonDocument<10>, JsonVariantConst>::value == + true); } SECTION("is_class") { - CHECK((is_class<int>::value == false)); - CHECK((is_class<EmptyEnum>::value == false)); - CHECK((is_class<int*>::value == false)); - CHECK((is_class<EmptyClass>::value == true)); + CHECK(is_class<int>::value == false); + CHECK(is_class<EmptyEnum>::value == false); + CHECK(is_class<int*>::value == false); + CHECK(is_class<EmptyClass>::value == true); } SECTION("is_enum") { diff --git a/neosensor/libraries/ArduinoJson/extras/tests/Misc/Utf16.cpp b/neosensor/libraries/ArduinoJson/extras/tests/Misc/Utf16.cpp index 31ab7ec5e6c9ad0c7f5c87cc2bef01d15faed0bd..3a595910522547207d8e0f6c63b50fcfea0171d4 100644 --- a/neosensor/libraries/ArduinoJson/extras/tests/Misc/Utf16.cpp +++ b/neosensor/libraries/ArduinoJson/extras/tests/Misc/Utf16.cpp @@ -1,11 +1,11 @@ // ArduinoJson - https://arduinojson.org -// Copyright © 2014-2022, Benoit BLANCHON +// Copyright © 2014-2023, Benoit BLANCHON // MIT License #include <ArduinoJson/Json/Utf16.hpp> #include <catch.hpp> -using namespace ARDUINOJSON_NAMESPACE; +using namespace ArduinoJson::detail; static void testUtf16Codepoint(uint16_t codeunit, uint32_t expectedCodepoint) { Utf16::Codepoint cp; diff --git a/neosensor/libraries/ArduinoJson/extras/tests/Misc/Utf8.cpp b/neosensor/libraries/ArduinoJson/extras/tests/Misc/Utf8.cpp index b44028ae30772c9cb77bae196f152912d2f03e30..0c62033d29744d1e0994dd5530b234d4d590cf66 100644 --- a/neosensor/libraries/ArduinoJson/extras/tests/Misc/Utf8.cpp +++ b/neosensor/libraries/ArduinoJson/extras/tests/Misc/Utf8.cpp @@ -1,5 +1,5 @@ // ArduinoJson - https://arduinojson.org -// Copyright © 2014-2022, Benoit BLANCHON +// Copyright © 2014-2023, Benoit BLANCHON // MIT License #include <ArduinoJson.h> @@ -7,7 +7,7 @@ #include <string> -using namespace ARDUINOJSON_NAMESPACE; +using namespace ArduinoJson::detail; static void testCodepoint(uint32_t codepoint, std::string expected) { char buffer[4096]; diff --git a/neosensor/libraries/ArduinoJson/extras/tests/Misc/arithmeticCompare.cpp b/neosensor/libraries/ArduinoJson/extras/tests/Misc/arithmeticCompare.cpp index a67943e8a78c0d527cc5a8abe6e8327f2196b21e..2d51754a151ceaee640b5ac8a586f18de1d485a4 100644 --- a/neosensor/libraries/ArduinoJson/extras/tests/Misc/arithmeticCompare.cpp +++ b/neosensor/libraries/ArduinoJson/extras/tests/Misc/arithmeticCompare.cpp @@ -1,103 +1,97 @@ // ArduinoJson - https://arduinojson.org -// Copyright © 2014-2022, Benoit BLANCHON +// Copyright © 2014-2023, Benoit BLANCHON // MIT License #include <ArduinoJson/Numbers/arithmeticCompare.hpp> #include <catch.hpp> -using namespace ARDUINOJSON_NAMESPACE; +using namespace ArduinoJson::detail; TEST_CASE("arithmeticCompare()") { SECTION("int vs uint8_t") { - CHECK((arithmeticCompare<int, uint8_t>(256, 1) == COMPARE_RESULT_GREATER)); - CHECK((arithmeticCompare<int, uint8_t>(41, 42) == COMPARE_RESULT_LESS)); - CHECK((arithmeticCompare<int, uint8_t>(42, 42) == COMPARE_RESULT_EQUAL)); - CHECK((arithmeticCompare<int, uint8_t>(43, 42) == COMPARE_RESULT_GREATER)); + CHECK(arithmeticCompare<int, uint8_t>(256, 1) == COMPARE_RESULT_GREATER); + CHECK(arithmeticCompare<int, uint8_t>(41, 42) == COMPARE_RESULT_LESS); + CHECK(arithmeticCompare<int, uint8_t>(42, 42) == COMPARE_RESULT_EQUAL); + CHECK(arithmeticCompare<int, uint8_t>(43, 42) == COMPARE_RESULT_GREATER); } SECTION("unsigned vs int") { - CHECK((arithmeticCompare<unsigned, int>(0, -1) == COMPARE_RESULT_GREATER)); - CHECK((arithmeticCompare<unsigned, int>(42, 41) == COMPARE_RESULT_GREATER)); - CHECK((arithmeticCompare<unsigned, int>(42, 42) == COMPARE_RESULT_EQUAL)); - CHECK((arithmeticCompare<unsigned, int>(42, 43) == COMPARE_RESULT_LESS)); + CHECK(arithmeticCompare<unsigned, int>(0, -1) == COMPARE_RESULT_GREATER); + CHECK(arithmeticCompare<unsigned, int>(42, 41) == COMPARE_RESULT_GREATER); + CHECK(arithmeticCompare<unsigned, int>(42, 42) == COMPARE_RESULT_EQUAL); + CHECK(arithmeticCompare<unsigned, int>(42, 43) == COMPARE_RESULT_LESS); } SECTION("float vs int") { - CHECK((arithmeticCompare<float, int>(42, 41) == COMPARE_RESULT_GREATER)); - CHECK((arithmeticCompare<float, int>(42, 42) == COMPARE_RESULT_EQUAL)); - CHECK((arithmeticCompare<float, int>(42, 43) == COMPARE_RESULT_LESS)); + CHECK(arithmeticCompare<float, int>(42, 41) == COMPARE_RESULT_GREATER); + CHECK(arithmeticCompare<float, int>(42, 42) == COMPARE_RESULT_EQUAL); + CHECK(arithmeticCompare<float, int>(42, 43) == COMPARE_RESULT_LESS); } SECTION("int vs unsigned") { - CHECK((arithmeticCompare<int, unsigned>(-1, 0) == COMPARE_RESULT_LESS)); - CHECK((arithmeticCompare<int, unsigned>(0, 0) == COMPARE_RESULT_EQUAL)); - CHECK((arithmeticCompare<int, unsigned>(1, 0) == COMPARE_RESULT_GREATER)); - CHECK((arithmeticCompare<int, unsigned>(42, 41) == COMPARE_RESULT_GREATER)); - CHECK((arithmeticCompare<int, unsigned>(42, 42) == COMPARE_RESULT_EQUAL)); - CHECK((arithmeticCompare<int, unsigned>(42, 43) == COMPARE_RESULT_LESS)); + CHECK(arithmeticCompare<int, unsigned>(-1, 0) == COMPARE_RESULT_LESS); + CHECK(arithmeticCompare<int, unsigned>(0, 0) == COMPARE_RESULT_EQUAL); + CHECK(arithmeticCompare<int, unsigned>(1, 0) == COMPARE_RESULT_GREATER); + CHECK(arithmeticCompare<int, unsigned>(42, 41) == COMPARE_RESULT_GREATER); + CHECK(arithmeticCompare<int, unsigned>(42, 42) == COMPARE_RESULT_EQUAL); + CHECK(arithmeticCompare<int, unsigned>(42, 43) == COMPARE_RESULT_LESS); } SECTION("unsigned vs unsigned") { - CHECK((arithmeticCompare<unsigned, unsigned>(42, 41) == - COMPARE_RESULT_GREATER)); - CHECK((arithmeticCompare<unsigned, unsigned>(42, 42) == - COMPARE_RESULT_EQUAL)); - CHECK( - (arithmeticCompare<unsigned, unsigned>(42, 43) == COMPARE_RESULT_LESS)); + CHECK(arithmeticCompare<unsigned, unsigned>(42, 41) == + COMPARE_RESULT_GREATER); + CHECK(arithmeticCompare<unsigned, unsigned>(42, 42) == + COMPARE_RESULT_EQUAL); + CHECK(arithmeticCompare<unsigned, unsigned>(42, 43) == COMPARE_RESULT_LESS); } SECTION("bool vs bool") { - CHECK( - (arithmeticCompare<bool, bool>(false, false) == COMPARE_RESULT_EQUAL)); - CHECK((arithmeticCompare<bool, bool>(true, true) == COMPARE_RESULT_EQUAL)); - CHECK((arithmeticCompare<bool, bool>(false, true) == COMPARE_RESULT_LESS)); - CHECK( - (arithmeticCompare<bool, bool>(true, false) == COMPARE_RESULT_GREATER)); + CHECK(arithmeticCompare<bool, bool>(false, false) == COMPARE_RESULT_EQUAL); + CHECK(arithmeticCompare<bool, bool>(true, true) == COMPARE_RESULT_EQUAL); + CHECK(arithmeticCompare<bool, bool>(false, true) == COMPARE_RESULT_LESS); + CHECK(arithmeticCompare<bool, bool>(true, false) == COMPARE_RESULT_GREATER); } SECTION("bool vs int") { - CHECK((arithmeticCompare<bool, int>(false, -1) == COMPARE_RESULT_GREATER)); - CHECK((arithmeticCompare<bool, int>(false, 0) == COMPARE_RESULT_EQUAL)); - CHECK((arithmeticCompare<bool, int>(false, 1) == COMPARE_RESULT_LESS)); - CHECK((arithmeticCompare<bool, int>(true, 0) == COMPARE_RESULT_GREATER)); - CHECK((arithmeticCompare<bool, int>(true, 1) == COMPARE_RESULT_EQUAL)); - CHECK((arithmeticCompare<bool, int>(true, 2) == COMPARE_RESULT_LESS)); + CHECK(arithmeticCompare<bool, int>(false, -1) == COMPARE_RESULT_GREATER); + CHECK(arithmeticCompare<bool, int>(false, 0) == COMPARE_RESULT_EQUAL); + CHECK(arithmeticCompare<bool, int>(false, 1) == COMPARE_RESULT_LESS); + CHECK(arithmeticCompare<bool, int>(true, 0) == COMPARE_RESULT_GREATER); + CHECK(arithmeticCompare<bool, int>(true, 1) == COMPARE_RESULT_EQUAL); + CHECK(arithmeticCompare<bool, int>(true, 2) == COMPARE_RESULT_LESS); } SECTION("bool vs int") { - CHECK((arithmeticCompare<int, bool>(0, false) == COMPARE_RESULT_EQUAL)); - CHECK((arithmeticCompare<int, bool>(1, true) == COMPARE_RESULT_EQUAL)); - CHECK((arithmeticCompare<int, bool>(1, false) == COMPARE_RESULT_GREATER)); - CHECK((arithmeticCompare<int, bool>(0, true) == COMPARE_RESULT_LESS)); + CHECK(arithmeticCompare<int, bool>(0, false) == COMPARE_RESULT_EQUAL); + CHECK(arithmeticCompare<int, bool>(1, true) == COMPARE_RESULT_EQUAL); + CHECK(arithmeticCompare<int, bool>(1, false) == COMPARE_RESULT_GREATER); + CHECK(arithmeticCompare<int, bool>(0, true) == COMPARE_RESULT_LESS); } } TEST_CASE("arithmeticCompareNegateLeft()") { SECTION("unsigned vs int") { - CHECK((arithmeticCompareNegateLeft<int>(0, 1) == COMPARE_RESULT_LESS)); - CHECK((arithmeticCompareNegateLeft<int>(42, -41) == COMPARE_RESULT_LESS)); - CHECK((arithmeticCompareNegateLeft<int>(42, -42) == COMPARE_RESULT_EQUAL)); - CHECK( - (arithmeticCompareNegateLeft<int>(42, -43) == COMPARE_RESULT_GREATER)); + CHECK(arithmeticCompareNegateLeft<int>(0, 1) == COMPARE_RESULT_LESS); + CHECK(arithmeticCompareNegateLeft<int>(42, -41) == COMPARE_RESULT_LESS); + CHECK(arithmeticCompareNegateLeft<int>(42, -42) == COMPARE_RESULT_EQUAL); + CHECK(arithmeticCompareNegateLeft<int>(42, -43) == COMPARE_RESULT_GREATER); } SECTION("unsigned vs unsigned") { - CHECK( - (arithmeticCompareNegateLeft<unsigned>(42, 42) == COMPARE_RESULT_LESS)); + CHECK(arithmeticCompareNegateLeft<unsigned>(42, 42) == COMPARE_RESULT_LESS); } } TEST_CASE("arithmeticCompareNegateRight()") { SECTION("int vs unsigned") { - CHECK((arithmeticCompareNegateRight<int>(1, 0) == COMPARE_RESULT_GREATER)); - CHECK( - (arithmeticCompareNegateRight<int>(-41, 42) == COMPARE_RESULT_GREATER)); - CHECK((arithmeticCompareNegateRight<int>(-42, 42) == COMPARE_RESULT_EQUAL)); - CHECK((arithmeticCompareNegateRight<int>(-43, 42) == COMPARE_RESULT_LESS)); + CHECK(arithmeticCompareNegateRight<int>(1, 0) == COMPARE_RESULT_GREATER); + CHECK(arithmeticCompareNegateRight<int>(-41, 42) == COMPARE_RESULT_GREATER); + CHECK(arithmeticCompareNegateRight<int>(-42, 42) == COMPARE_RESULT_EQUAL); + CHECK(arithmeticCompareNegateRight<int>(-43, 42) == COMPARE_RESULT_LESS); } SECTION("unsigned vs unsigned") { - CHECK((arithmeticCompareNegateRight<unsigned>(42, 42) == - COMPARE_RESULT_GREATER)); + CHECK(arithmeticCompareNegateRight<unsigned>(42, 42) == + COMPARE_RESULT_GREATER); } } diff --git a/neosensor/libraries/ArduinoJson/extras/tests/Misc/conflicts.cpp b/neosensor/libraries/ArduinoJson/extras/tests/Misc/conflicts.cpp index 991a94ef7b5086c5a48b6a076e79c4453495d40e..2e33ea1039ddf623dab44c75823377bf0f131f82 100644 --- a/neosensor/libraries/ArduinoJson/extras/tests/Misc/conflicts.cpp +++ b/neosensor/libraries/ArduinoJson/extras/tests/Misc/conflicts.cpp @@ -1,5 +1,5 @@ // ArduinoJson - https://arduinojson.org -// Copyright © 2014-2022, Benoit BLANCHON +// Copyright © 2014-2023, Benoit BLANCHON // MIT License // Include any header that might use the conflicting macros @@ -52,5 +52,8 @@ #define BLOCKSIZE #define CAPACITY +// issue #1905 +#define _current + // catch.hpp mutes several warnings, this file also allows to detect them #include "ArduinoJson.h" diff --git a/neosensor/libraries/ArduinoJson/extras/tests/Misc/custom_string.hpp b/neosensor/libraries/ArduinoJson/extras/tests/Misc/custom_string.hpp index 3c5b7c1457635c06b2a316521b0293b27e958325..4a6a5a73523988afeeeebab4163bb24b560431f0 100644 --- a/neosensor/libraries/ArduinoJson/extras/tests/Misc/custom_string.hpp +++ b/neosensor/libraries/ArduinoJson/extras/tests/Misc/custom_string.hpp @@ -1,5 +1,5 @@ // ArduinoJson - https://arduinojson.org -// Copyright © 2014-2022, Benoit BLANCHON +// Copyright © 2014-2023, Benoit BLANCHON // MIT License #pragma once diff --git a/neosensor/libraries/ArduinoJson/extras/tests/Misc/printable.cpp b/neosensor/libraries/ArduinoJson/extras/tests/Misc/printable.cpp index 7cec8f93498f1ba8d44780eb9503e8f6b851794c..09c23ad18a06a9edf0736829228e5280605045a0 100644 --- a/neosensor/libraries/ArduinoJson/extras/tests/Misc/printable.cpp +++ b/neosensor/libraries/ArduinoJson/extras/tests/Misc/printable.cpp @@ -1,5 +1,5 @@ // ArduinoJson - https://arduinojson.org -// Copyright © 2014-2022, Benoit BLANCHON +// Copyright © 2014-2023, Benoit BLANCHON // MIT License #include <Arduino.h> @@ -29,21 +29,21 @@ struct PrintAllAtOnce { template <typename PrintPolicy> struct PrintableString : public Printable { - PrintableString(const char* s) : _str(s), _total(0) {} + PrintableString(const char* s) : str_(s), total_(0) {} virtual size_t printTo(Print& p) const { - size_t result = PrintPolicy::printStringTo(_str, p); - _total += result; + size_t result = PrintPolicy::printStringTo(str_, p); + total_ += result; return result; } size_t totalBytesWritten() const { - return _total; + return total_; } private: - std::string _str; - mutable size_t _total; + std::string str_; + mutable size_t total_; }; TEST_CASE("Printable") { diff --git a/neosensor/libraries/ArduinoJson/extras/tests/Misc/unsigned_char.cpp b/neosensor/libraries/ArduinoJson/extras/tests/Misc/unsigned_char.cpp index 7a5e3eefaa40677f01c9324707a4ea672eb33732..d3ee492a3decf25589b307246b86904ba5ac2783 100644 --- a/neosensor/libraries/ArduinoJson/extras/tests/Misc/unsigned_char.cpp +++ b/neosensor/libraries/ArduinoJson/extras/tests/Misc/unsigned_char.cpp @@ -1,5 +1,5 @@ // ArduinoJson - https://arduinojson.org -// Copyright © 2014-2022, Benoit BLANCHON +// Copyright © 2014-2023, Benoit BLANCHON // MIT License #include <ArduinoJson.h> diff --git a/neosensor/libraries/ArduinoJson/extras/tests/Misc/version.cpp b/neosensor/libraries/ArduinoJson/extras/tests/Misc/version.cpp index 486a867025ed820c1fcbe7581a7dc3cd190b0497..a91f159a1a61e5a404ed783bf7359b4374c9ec7d 100644 --- a/neosensor/libraries/ArduinoJson/extras/tests/Misc/version.cpp +++ b/neosensor/libraries/ArduinoJson/extras/tests/Misc/version.cpp @@ -1,5 +1,5 @@ // ArduinoJson - https://arduinojson.org -// Copyright © 2014-2022, Benoit BLANCHON +// Copyright © 2014-2023, Benoit BLANCHON // MIT License #include <ArduinoJson/version.hpp> diff --git a/neosensor/libraries/ArduinoJson/extras/tests/Misc/weird_strcmp.hpp b/neosensor/libraries/ArduinoJson/extras/tests/Misc/weird_strcmp.hpp index ff755ef54887ae0c9484c9a3018cd00e6838bfbd..5463d7ec21b913a6fe7d86c4d7c340848457f717 100644 --- a/neosensor/libraries/ArduinoJson/extras/tests/Misc/weird_strcmp.hpp +++ b/neosensor/libraries/ArduinoJson/extras/tests/Misc/weird_strcmp.hpp @@ -1,5 +1,5 @@ // ArduinoJson - https://arduinojson.org -// Copyright © 2014-2022, Benoit BLANCHON +// Copyright © 2014-2023, Benoit BLANCHON // MIT License #include <ArduinoJson/Namespace.hpp> @@ -8,7 +8,8 @@ // Issue #1198: strcmp() implementation that returns a value larger than 8-bit -namespace ARDUINOJSON_NAMESPACE { +ARDUINOJSON_BEGIN_PRIVATE_NAMESPACE + int strcmp(const char* a, const char* b) { int result = ::strcmp(a, b); if (result > 0) @@ -26,4 +27,5 @@ int strncmp(const char* a, const char* b, size_t n) { return -214748364; return 0; } -} // namespace ARDUINOJSON_NAMESPACE + +ARDUINOJSON_END_PRIVATE_NAMESPACE diff --git a/neosensor/libraries/ArduinoJson/extras/tests/MixedConfiguration/CMakeLists.txt b/neosensor/libraries/ArduinoJson/extras/tests/MixedConfiguration/CMakeLists.txt index 01d1216e3ab7f1f0042832ba3c89521cf7b1151d..c2c9dc5caa506354238e5a463265e22ab305075f 100644 --- a/neosensor/libraries/ArduinoJson/extras/tests/MixedConfiguration/CMakeLists.txt +++ b/neosensor/libraries/ArduinoJson/extras/tests/MixedConfiguration/CMakeLists.txt @@ -1,5 +1,5 @@ # ArduinoJson - https://arduinojson.org -# Copyright © 2014-2022, Benoit BLANCHON +# Copyright © 2014-2023, Benoit BLANCHON # MIT License add_executable(MixedConfigurationTests @@ -19,6 +19,8 @@ add_executable(MixedConfigurationTests issue1707.cpp use_double_0.cpp use_double_1.cpp + use_long_long_0.cpp + use_long_long_1.cpp ) set_target_properties(MixedConfigurationTests PROPERTIES UNITY_BUILD OFF) @@ -27,5 +29,5 @@ add_test(MixedConfiguration MixedConfigurationTests) set_tests_properties(MixedConfiguration PROPERTIES - LABELS "Catch" + LABELS "Catch" ) diff --git a/neosensor/libraries/ArduinoJson/extras/tests/MixedConfiguration/enable_alignment_0.cpp b/neosensor/libraries/ArduinoJson/extras/tests/MixedConfiguration/enable_alignment_0.cpp index 426f516a1e94a6c91a8c0294c6ac41b26ca7f217..569f84aa54d1a0bd454b79073c3364d14764f2d5 100644 --- a/neosensor/libraries/ArduinoJson/extras/tests/MixedConfiguration/enable_alignment_0.cpp +++ b/neosensor/libraries/ArduinoJson/extras/tests/MixedConfiguration/enable_alignment_0.cpp @@ -1,11 +1,11 @@ -#define ARDUINOJSON_NAMESPACE ArduinoJson_NoAlignment +#define ARDUINOJSON_VERSION_NAMESPACE NoAlignment #define ARDUINOJSON_ENABLE_ALIGNMENT 0 #include <ArduinoJson.h> #include <catch.hpp> TEST_CASE("ARDUINOJSON_ENABLE_ALIGNMENT == 0") { - using namespace ARDUINOJSON_NAMESPACE; + using namespace ArduinoJson::detail; const size_t N = sizeof(void*); diff --git a/neosensor/libraries/ArduinoJson/extras/tests/MixedConfiguration/enable_alignment_1.cpp b/neosensor/libraries/ArduinoJson/extras/tests/MixedConfiguration/enable_alignment_1.cpp index 9abf50c84e189a587e293eb84b6943f408441021..56d48169a289a305cdc2b5bb8100a42d6ceef436 100644 --- a/neosensor/libraries/ArduinoJson/extras/tests/MixedConfiguration/enable_alignment_1.cpp +++ b/neosensor/libraries/ArduinoJson/extras/tests/MixedConfiguration/enable_alignment_1.cpp @@ -4,7 +4,7 @@ #include <catch.hpp> TEST_CASE("ARDUINOJSON_ENABLE_ALIGNMENT == 1") { - using namespace ARDUINOJSON_NAMESPACE; + using namespace ArduinoJson::detail; const size_t N = sizeof(void*); diff --git a/neosensor/libraries/ArduinoJson/extras/tests/MixedConfiguration/enable_comments_0.cpp b/neosensor/libraries/ArduinoJson/extras/tests/MixedConfiguration/enable_comments_0.cpp index 6329021ae02a7f18d6e6d73465bc2e9e10830f47..a3ada5ea162e460b4bc5769919547c589a69f550 100644 --- a/neosensor/libraries/ArduinoJson/extras/tests/MixedConfiguration/enable_comments_0.cpp +++ b/neosensor/libraries/ArduinoJson/extras/tests/MixedConfiguration/enable_comments_0.cpp @@ -1,5 +1,5 @@ // ArduinoJson - https://arduinojson.org -// Copyright © 2014-2022, Benoit BLANCHON +// Copyright © 2014-2023, Benoit BLANCHON // MIT License #define ARDUINOJSON_ENABLE_COMMENTS 0 diff --git a/neosensor/libraries/ArduinoJson/extras/tests/MixedConfiguration/enable_comments_1.cpp b/neosensor/libraries/ArduinoJson/extras/tests/MixedConfiguration/enable_comments_1.cpp index 18462922d435a319fad3ee9571161a2c67c70a96..5e0831c5b4c0a4271f2deaf91d6b89df79407226 100644 --- a/neosensor/libraries/ArduinoJson/extras/tests/MixedConfiguration/enable_comments_1.cpp +++ b/neosensor/libraries/ArduinoJson/extras/tests/MixedConfiguration/enable_comments_1.cpp @@ -1,5 +1,5 @@ // ArduinoJson - https://arduinojson.org -// Copyright © 2014-2022, Benoit BLANCHON +// Copyright © 2014-2023, Benoit BLANCHON // MIT License #define ARDUINOJSON_ENABLE_COMMENTS 1 diff --git a/neosensor/libraries/ArduinoJson/extras/tests/MixedConfiguration/enable_infinity_1.cpp b/neosensor/libraries/ArduinoJson/extras/tests/MixedConfiguration/enable_infinity_1.cpp index 19e0d5bfdf8be9490ab54384f20f429b1c76d7a0..28a3461fb275f5358009ab51cf2966ec1f621f66 100644 --- a/neosensor/libraries/ArduinoJson/extras/tests/MixedConfiguration/enable_infinity_1.cpp +++ b/neosensor/libraries/ArduinoJson/extras/tests/MixedConfiguration/enable_infinity_1.cpp @@ -5,7 +5,7 @@ #include <limits> namespace my { -using ARDUINOJSON_NAMESPACE::isinf; +using ArduinoJson::detail::isinf; } // namespace my TEST_CASE("ARDUINOJSON_ENABLE_INFINITY == 1") { diff --git a/neosensor/libraries/ArduinoJson/extras/tests/MixedConfiguration/enable_nan_1.cpp b/neosensor/libraries/ArduinoJson/extras/tests/MixedConfiguration/enable_nan_1.cpp index 34d94fcaefe2ddf4b3d1ead8d904cfda5dd013c2..f9ae04a6b950d88fae04a7ebc3065b23501485a4 100644 --- a/neosensor/libraries/ArduinoJson/extras/tests/MixedConfiguration/enable_nan_1.cpp +++ b/neosensor/libraries/ArduinoJson/extras/tests/MixedConfiguration/enable_nan_1.cpp @@ -5,7 +5,7 @@ #include <limits> namespace my { -using ARDUINOJSON_NAMESPACE::isnan; +using ArduinoJson::detail::isnan; } // namespace my TEST_CASE("ARDUINOJSON_ENABLE_NAN == 1") { diff --git a/neosensor/libraries/ArduinoJson/extras/tests/MixedConfiguration/enable_progmem_1.cpp b/neosensor/libraries/ArduinoJson/extras/tests/MixedConfiguration/enable_progmem_1.cpp index 9ddf7f263650b6cbd3b0701edabddc25fa12be38..2cc683d7c8cfd765d6464cfcf1e15f9b95cffedf 100644 --- a/neosensor/libraries/ArduinoJson/extras/tests/MixedConfiguration/enable_progmem_1.cpp +++ b/neosensor/libraries/ArduinoJson/extras/tests/MixedConfiguration/enable_progmem_1.cpp @@ -1,5 +1,5 @@ // ArduinoJson - https://arduinojson.org -// Copyright © 2014-2022, Benoit BLANCHON +// Copyright © 2014-2023, Benoit BLANCHON // MIT License #define ARDUINOJSON_ENABLE_PROGMEM 1 @@ -51,7 +51,7 @@ TEST_CASE("Flash strings") { } TEST_CASE("parseNumber()") { // tables are in Flash - using ARDUINOJSON_NAMESPACE::parseNumber; + using ArduinoJson::detail::parseNumber; CHECK(parseNumber<float>("1") == 1.f); CHECK(parseNumber<float>("1.23") == 1.23f); @@ -93,7 +93,7 @@ TEST_CASE("memcpy_P") { } TEST_CASE("BoundedReader<const __FlashStringHelper*>") { - using namespace ARDUINOJSON_NAMESPACE; + using namespace ArduinoJson::detail; SECTION("read") { BoundedReader<const __FlashStringHelper*> reader(F("\x01\xFF"), 2); @@ -133,7 +133,7 @@ TEST_CASE("BoundedReader<const __FlashStringHelper*>") { } TEST_CASE("Reader<const __FlashStringHelper*>") { - using namespace ARDUINOJSON_NAMESPACE; + using namespace ArduinoJson::detail; SECTION("read()") { Reader<const __FlashStringHelper*> reader(F("\x01\xFF\x00\x12")); diff --git a/neosensor/libraries/ArduinoJson/extras/tests/MixedConfiguration/enable_string_deduplication_0.cpp b/neosensor/libraries/ArduinoJson/extras/tests/MixedConfiguration/enable_string_deduplication_0.cpp index d9ca166e2f398bedac24e835354bab0b4bb07615..7277af945d2ca557e5c8655e1988abdfe09507ef 100644 --- a/neosensor/libraries/ArduinoJson/extras/tests/MixedConfiguration/enable_string_deduplication_0.cpp +++ b/neosensor/libraries/ArduinoJson/extras/tests/MixedConfiguration/enable_string_deduplication_0.cpp @@ -1,5 +1,5 @@ // ArduinoJson - https://arduinojson.org -// Copyright © 2014-2022, Benoit BLANCHON +// Copyright © 2014-2023, Benoit BLANCHON // MIT License #define ARDUINOJSON_ENABLE_ARDUINO_STRING 1 diff --git a/neosensor/libraries/ArduinoJson/extras/tests/MixedConfiguration/enable_string_deduplication_1.cpp b/neosensor/libraries/ArduinoJson/extras/tests/MixedConfiguration/enable_string_deduplication_1.cpp index 27fc18d68482b1ba00f1323dc625d9833ef7bfa7..d3b2285e3866ba00ea290cc42ebfe5d6a220b825 100644 --- a/neosensor/libraries/ArduinoJson/extras/tests/MixedConfiguration/enable_string_deduplication_1.cpp +++ b/neosensor/libraries/ArduinoJson/extras/tests/MixedConfiguration/enable_string_deduplication_1.cpp @@ -1,5 +1,5 @@ // ArduinoJson - https://arduinojson.org -// Copyright © 2014-2022, Benoit BLANCHON +// Copyright © 2014-2023, Benoit BLANCHON // MIT License #define ARDUINOJSON_ENABLE_ARDUINO_STRING 1 diff --git a/neosensor/libraries/ArduinoJson/extras/tests/MixedConfiguration/issue1707.cpp b/neosensor/libraries/ArduinoJson/extras/tests/MixedConfiguration/issue1707.cpp index befdee53605f239e1ddfcefbf848ae5cfb53b37b..f8ca566b57227dc8493ae748a5f9c47cc719d308 100644 --- a/neosensor/libraries/ArduinoJson/extras/tests/MixedConfiguration/issue1707.cpp +++ b/neosensor/libraries/ArduinoJson/extras/tests/MixedConfiguration/issue1707.cpp @@ -1,5 +1,5 @@ // ArduinoJson - https://arduinojson.org -// Copyright © 2014-2022, Benoit BLANCHON +// Copyright © 2014-2023, Benoit BLANCHON // MIT License #define ARDUINO diff --git a/neosensor/libraries/ArduinoJson/extras/tests/Cpp11/use_long_long_0.cpp b/neosensor/libraries/ArduinoJson/extras/tests/MixedConfiguration/use_long_long_0.cpp similarity index 100% rename from neosensor/libraries/ArduinoJson/extras/tests/Cpp11/use_long_long_0.cpp rename to neosensor/libraries/ArduinoJson/extras/tests/MixedConfiguration/use_long_long_0.cpp diff --git a/neosensor/libraries/ArduinoJson/extras/tests/Cpp11/use_long_long_1.cpp b/neosensor/libraries/ArduinoJson/extras/tests/MixedConfiguration/use_long_long_1.cpp similarity index 100% rename from neosensor/libraries/ArduinoJson/extras/tests/Cpp11/use_long_long_1.cpp rename to neosensor/libraries/ArduinoJson/extras/tests/MixedConfiguration/use_long_long_1.cpp diff --git a/neosensor/libraries/ArduinoJson/extras/tests/MsgPackDeserializer/CMakeLists.txt b/neosensor/libraries/ArduinoJson/extras/tests/MsgPackDeserializer/CMakeLists.txt index f2435279cb25eb2680bed35aef469981d763d4b2..a5442076a17aeedfbc8291d24a0036e7a00b15d6 100644 --- a/neosensor/libraries/ArduinoJson/extras/tests/MsgPackDeserializer/CMakeLists.txt +++ b/neosensor/libraries/ArduinoJson/extras/tests/MsgPackDeserializer/CMakeLists.txt @@ -1,5 +1,5 @@ # ArduinoJson - https://arduinojson.org -# Copyright © 2014-2022, Benoit BLANCHON +# Copyright © 2014-2023, Benoit BLANCHON # MIT License add_executable(MsgPackDeserializerTests @@ -20,5 +20,5 @@ add_test(MsgPackDeserializer MsgPackDeserializerTests) set_tests_properties(MsgPackDeserializer PROPERTIES - LABELS "Catch" + LABELS "Catch" ) diff --git a/neosensor/libraries/ArduinoJson/extras/tests/MsgPackDeserializer/deserializeArray.cpp b/neosensor/libraries/ArduinoJson/extras/tests/MsgPackDeserializer/deserializeArray.cpp index 4540bd0527f13ff00afc5e40c9377adfbd650028..356a9fe47d5747588c373dbe93628e18dd595206 100644 --- a/neosensor/libraries/ArduinoJson/extras/tests/MsgPackDeserializer/deserializeArray.cpp +++ b/neosensor/libraries/ArduinoJson/extras/tests/MsgPackDeserializer/deserializeArray.cpp @@ -1,5 +1,5 @@ // ArduinoJson - https://arduinojson.org -// Copyright © 2014-2022, Benoit BLANCHON +// Copyright © 2014-2023, Benoit BLANCHON // MIT License #include <ArduinoJson.h> diff --git a/neosensor/libraries/ArduinoJson/extras/tests/MsgPackDeserializer/deserializeObject.cpp b/neosensor/libraries/ArduinoJson/extras/tests/MsgPackDeserializer/deserializeObject.cpp index 7a0e7b8425e30a8c3b8dadfaee15b639648e746f..4aeb5532a253d468bab5b81232e9aaca39df407f 100644 --- a/neosensor/libraries/ArduinoJson/extras/tests/MsgPackDeserializer/deserializeObject.cpp +++ b/neosensor/libraries/ArduinoJson/extras/tests/MsgPackDeserializer/deserializeObject.cpp @@ -1,5 +1,5 @@ // ArduinoJson - https://arduinojson.org -// Copyright © 2014-2022, Benoit BLANCHON +// Copyright © 2014-2023, Benoit BLANCHON // MIT License #include <ArduinoJson.h> diff --git a/neosensor/libraries/ArduinoJson/extras/tests/MsgPackDeserializer/deserializeStaticVariant.cpp b/neosensor/libraries/ArduinoJson/extras/tests/MsgPackDeserializer/deserializeStaticVariant.cpp index 2d4093ca49dedda0cc59ff9ea22a043d61ac24ba..0e126ff29a8500c98cbc75ccbb6572f6070fbbf2 100644 --- a/neosensor/libraries/ArduinoJson/extras/tests/MsgPackDeserializer/deserializeStaticVariant.cpp +++ b/neosensor/libraries/ArduinoJson/extras/tests/MsgPackDeserializer/deserializeStaticVariant.cpp @@ -1,5 +1,5 @@ // ArduinoJson - https://arduinojson.org -// Copyright © 2014-2022, Benoit BLANCHON +// Copyright © 2014-2023, Benoit BLANCHON // MIT License #include <ArduinoJson.h> diff --git a/neosensor/libraries/ArduinoJson/extras/tests/MsgPackDeserializer/deserializeVariant.cpp b/neosensor/libraries/ArduinoJson/extras/tests/MsgPackDeserializer/deserializeVariant.cpp index be20b9cae59c58fa48bef3293d5061779288051a..87f38d6e2573d2b8e68505767353e00d92e28646 100644 --- a/neosensor/libraries/ArduinoJson/extras/tests/MsgPackDeserializer/deserializeVariant.cpp +++ b/neosensor/libraries/ArduinoJson/extras/tests/MsgPackDeserializer/deserializeVariant.cpp @@ -1,5 +1,5 @@ // ArduinoJson - https://arduinojson.org -// Copyright © 2014-2022, Benoit BLANCHON +// Copyright © 2014-2023, Benoit BLANCHON // MIT License #include <ArduinoJson.h> diff --git a/neosensor/libraries/ArduinoJson/extras/tests/MsgPackDeserializer/doubleToFloat.cpp b/neosensor/libraries/ArduinoJson/extras/tests/MsgPackDeserializer/doubleToFloat.cpp index b0470de5b327f78b60313edc5035ae7f22e60862..fb2c25d090ab58c87cc4b6c3ff674f9e59114e7e 100644 --- a/neosensor/libraries/ArduinoJson/extras/tests/MsgPackDeserializer/doubleToFloat.cpp +++ b/neosensor/libraries/ArduinoJson/extras/tests/MsgPackDeserializer/doubleToFloat.cpp @@ -1,11 +1,11 @@ // ArduinoJson - https://arduinojson.org -// Copyright © 2014-2022, Benoit BLANCHON +// Copyright © 2014-2023, Benoit BLANCHON // MIT License #include <ArduinoJson.h> #include <catch.hpp> -using namespace ARDUINOJSON_NAMESPACE; +using namespace ArduinoJson::detail; template <typename T> static void check(const char* input, T expected) { diff --git a/neosensor/libraries/ArduinoJson/extras/tests/MsgPackDeserializer/filter.cpp b/neosensor/libraries/ArduinoJson/extras/tests/MsgPackDeserializer/filter.cpp index 57dd7bea98cf618c23143703d278314b168b28b2..78700db64c73e8dca5dce22b767defefb8c9941a 100644 --- a/neosensor/libraries/ArduinoJson/extras/tests/MsgPackDeserializer/filter.cpp +++ b/neosensor/libraries/ArduinoJson/extras/tests/MsgPackDeserializer/filter.cpp @@ -1,11 +1,13 @@ // ArduinoJson - https://arduinojson.org -// Copyright © 2014-2022, Benoit BLANCHON +// Copyright © 2014-2023, Benoit BLANCHON // MIT License #include <ArduinoJson.h> #include <catch.hpp> -using namespace ARDUINOJSON_NAMESPACE; +#include <sstream> + +using namespace ArduinoJson::detail; TEST_CASE("deserializeMsgPack() filter") { StaticJsonDocument<4096> doc; diff --git a/neosensor/libraries/ArduinoJson/extras/tests/MsgPackDeserializer/incompleteInput.cpp b/neosensor/libraries/ArduinoJson/extras/tests/MsgPackDeserializer/incompleteInput.cpp index 029facfc049ef68f7f26a9ceba5448c27d2020f5..6a563882533fe52253a70dbe1ee8eff902ef3bd7 100644 --- a/neosensor/libraries/ArduinoJson/extras/tests/MsgPackDeserializer/incompleteInput.cpp +++ b/neosensor/libraries/ArduinoJson/extras/tests/MsgPackDeserializer/incompleteInput.cpp @@ -1,5 +1,5 @@ // ArduinoJson - https://arduinojson.org -// Copyright © 2014-2022, Benoit BLANCHON +// Copyright © 2014-2023, Benoit BLANCHON // MIT License #include <ArduinoJson.h> diff --git a/neosensor/libraries/ArduinoJson/extras/tests/MsgPackDeserializer/input_types.cpp b/neosensor/libraries/ArduinoJson/extras/tests/MsgPackDeserializer/input_types.cpp index f46d4691e6683e69c41b74dba97c267a0104b042..783aaa2c1e5751b8b7ea7ce7927a3c7c9ae90b5b 100644 --- a/neosensor/libraries/ArduinoJson/extras/tests/MsgPackDeserializer/input_types.cpp +++ b/neosensor/libraries/ArduinoJson/extras/tests/MsgPackDeserializer/input_types.cpp @@ -1,5 +1,5 @@ // ArduinoJson - https://arduinojson.org -// Copyright © 2014-2022, Benoit BLANCHON +// Copyright © 2014-2023, Benoit BLANCHON // MIT License #include <ArduinoJson.h> diff --git a/neosensor/libraries/ArduinoJson/extras/tests/MsgPackDeserializer/misc.cpp b/neosensor/libraries/ArduinoJson/extras/tests/MsgPackDeserializer/misc.cpp index 071717164be6a212a0564b07f75f36b09c0820d5..25137b35898dccdd3e648bafecec26be2f70b192 100644 --- a/neosensor/libraries/ArduinoJson/extras/tests/MsgPackDeserializer/misc.cpp +++ b/neosensor/libraries/ArduinoJson/extras/tests/MsgPackDeserializer/misc.cpp @@ -1,10 +1,12 @@ // ArduinoJson - https://arduinojson.org -// Copyright © 2014-2022, Benoit BLANCHON +// Copyright © 2014-2023, Benoit BLANCHON // MIT License #include <ArduinoJson.h> #include <catch.hpp> +#include <sstream> + TEST_CASE("deserializeMsgPack() returns EmptyInput") { StaticJsonDocument<100> doc; diff --git a/neosensor/libraries/ArduinoJson/extras/tests/MsgPackDeserializer/nestingLimit.cpp b/neosensor/libraries/ArduinoJson/extras/tests/MsgPackDeserializer/nestingLimit.cpp index 6005f55bb46d152198dc72c0f39c0fcf11491b97..2936415a55e416659f76c051a1cb2ddcd938bd64 100644 --- a/neosensor/libraries/ArduinoJson/extras/tests/MsgPackDeserializer/nestingLimit.cpp +++ b/neosensor/libraries/ArduinoJson/extras/tests/MsgPackDeserializer/nestingLimit.cpp @@ -1,10 +1,12 @@ // ArduinoJson - https://arduinojson.org -// Copyright © 2014-2022, Benoit BLANCHON +// Copyright © 2014-2023, Benoit BLANCHON // MIT License #include <ArduinoJson.h> #include <catch.hpp> +#include <sstream> + #define SHOULD_WORK(expression) REQUIRE(DeserializationError::Ok == expression); #define SHOULD_FAIL(expression) \ REQUIRE(DeserializationError::TooDeep == expression); diff --git a/neosensor/libraries/ArduinoJson/extras/tests/MsgPackDeserializer/notSupported.cpp b/neosensor/libraries/ArduinoJson/extras/tests/MsgPackDeserializer/notSupported.cpp index 5e204cdf0e70ccd60dabbf565db503d58330e76e..2be0f1ec5f85f75ce8553a953c3175594ee0f6ec 100644 --- a/neosensor/libraries/ArduinoJson/extras/tests/MsgPackDeserializer/notSupported.cpp +++ b/neosensor/libraries/ArduinoJson/extras/tests/MsgPackDeserializer/notSupported.cpp @@ -1,5 +1,5 @@ // ArduinoJson - https://arduinojson.org -// Copyright © 2014-2022, Benoit BLANCHON +// Copyright © 2014-2023, Benoit BLANCHON // MIT License #include <ArduinoJson.h> diff --git a/neosensor/libraries/ArduinoJson/extras/tests/MsgPackSerializer/CMakeLists.txt b/neosensor/libraries/ArduinoJson/extras/tests/MsgPackSerializer/CMakeLists.txt index 9a7721e9d619a01664067d74c8fc29984d0575ca..2f3d8cc76daf494eecc89ebcd6c2ba330695737b 100644 --- a/neosensor/libraries/ArduinoJson/extras/tests/MsgPackSerializer/CMakeLists.txt +++ b/neosensor/libraries/ArduinoJson/extras/tests/MsgPackSerializer/CMakeLists.txt @@ -1,5 +1,5 @@ # ArduinoJson - https://arduinojson.org -# Copyright © 2014-2022, Benoit BLANCHON +# Copyright © 2014-2023, Benoit BLANCHON # MIT License add_executable(MsgPackSerializerTests @@ -15,5 +15,5 @@ add_test(MsgPackSerializer MsgPackSerializerTests) set_tests_properties(MsgPackSerializer PROPERTIES - LABELS "Catch" + LABELS "Catch" ) diff --git a/neosensor/libraries/ArduinoJson/extras/tests/MsgPackSerializer/destination_types.cpp b/neosensor/libraries/ArduinoJson/extras/tests/MsgPackSerializer/destination_types.cpp index 6a5bc849086b1602a657f3fd95a20b9be82e5688..8b0dffa00cdcb11cc420af5c8a2e7e12848ef994 100644 --- a/neosensor/libraries/ArduinoJson/extras/tests/MsgPackSerializer/destination_types.cpp +++ b/neosensor/libraries/ArduinoJson/extras/tests/MsgPackSerializer/destination_types.cpp @@ -1,5 +1,5 @@ // ArduinoJson - https://arduinojson.org -// Copyright © 2014-2022, Benoit BLANCHON +// Copyright © 2014-2023, Benoit BLANCHON // MIT License #include <ArduinoJson.h> diff --git a/neosensor/libraries/ArduinoJson/extras/tests/MsgPackSerializer/measure.cpp b/neosensor/libraries/ArduinoJson/extras/tests/MsgPackSerializer/measure.cpp index d49bcd9bac671f7f1bf9fa67899498315afc46e5..a6a4fc9dcec8767011d2790ecaa08b3eafa4bcce 100644 --- a/neosensor/libraries/ArduinoJson/extras/tests/MsgPackSerializer/measure.cpp +++ b/neosensor/libraries/ArduinoJson/extras/tests/MsgPackSerializer/measure.cpp @@ -1,5 +1,5 @@ // ArduinoJson - https://arduinojson.org -// Copyright © 2014-2022, Benoit BLANCHON +// Copyright © 2014-2023, Benoit BLANCHON // MIT License #include <ArduinoJson.h> diff --git a/neosensor/libraries/ArduinoJson/extras/tests/MsgPackSerializer/serializeArray.cpp b/neosensor/libraries/ArduinoJson/extras/tests/MsgPackSerializer/serializeArray.cpp index 58eae9ccabe9a0dd95b01646061fbd396ef127de..a8ec639c9e3d3b37e3e76faf320a177ce10d36ba 100644 --- a/neosensor/libraries/ArduinoJson/extras/tests/MsgPackSerializer/serializeArray.cpp +++ b/neosensor/libraries/ArduinoJson/extras/tests/MsgPackSerializer/serializeArray.cpp @@ -1,5 +1,5 @@ // ArduinoJson - https://arduinojson.org -// Copyright © 2014-2022, Benoit BLANCHON +// Copyright © 2014-2023, Benoit BLANCHON // MIT License #include <ArduinoJson.h> diff --git a/neosensor/libraries/ArduinoJson/extras/tests/MsgPackSerializer/serializeObject.cpp b/neosensor/libraries/ArduinoJson/extras/tests/MsgPackSerializer/serializeObject.cpp index e5c167a619379a987bf15746980aa78e5131d3ae..88173074350232101c9a8184c7b40145b2b55a39 100644 --- a/neosensor/libraries/ArduinoJson/extras/tests/MsgPackSerializer/serializeObject.cpp +++ b/neosensor/libraries/ArduinoJson/extras/tests/MsgPackSerializer/serializeObject.cpp @@ -1,5 +1,5 @@ // ArduinoJson - https://arduinojson.org -// Copyright © 2014-2022, Benoit BLANCHON +// Copyright © 2014-2023, Benoit BLANCHON // MIT License #include <ArduinoJson.h> diff --git a/neosensor/libraries/ArduinoJson/extras/tests/MsgPackSerializer/serializeVariant.cpp b/neosensor/libraries/ArduinoJson/extras/tests/MsgPackSerializer/serializeVariant.cpp index c0919590135add97e4340dcb6560505a43c2936f..b8a021f926749910168ef4c98f11de26481a064c 100644 --- a/neosensor/libraries/ArduinoJson/extras/tests/MsgPackSerializer/serializeVariant.cpp +++ b/neosensor/libraries/ArduinoJson/extras/tests/MsgPackSerializer/serializeVariant.cpp @@ -1,5 +1,5 @@ // ArduinoJson - https://arduinojson.org -// Copyright © 2014-2022, Benoit BLANCHON +// Copyright © 2014-2023, Benoit BLANCHON // MIT License #include <ArduinoJson.h> diff --git a/neosensor/libraries/ArduinoJson/extras/tests/Numbers/CMakeLists.txt b/neosensor/libraries/ArduinoJson/extras/tests/Numbers/CMakeLists.txt index 05e1e89492d8ab2b4e2b101778d007fca9557d92..48cf8c0f1f6e9359d0ac711e39dd720cc9050e65 100644 --- a/neosensor/libraries/ArduinoJson/extras/tests/Numbers/CMakeLists.txt +++ b/neosensor/libraries/ArduinoJson/extras/tests/Numbers/CMakeLists.txt @@ -1,10 +1,7 @@ # ArduinoJson - https://arduinojson.org -# Copyright © 2014-2022, Benoit BLANCHON +# Copyright © 2014-2023, Benoit BLANCHON # MIT License -set(CMAKE_CXX_STANDARD 11) -set(CMAKE_CXX_STANDARD_REQUIRED OFF) - add_executable(NumbersTests convertNumber.cpp parseFloat.cpp @@ -13,10 +10,9 @@ add_executable(NumbersTests parseNumber.cpp ) - add_test(Numbers NumbersTests) set_tests_properties(Numbers PROPERTIES - LABELS "Catch" + LABELS "Catch" ) diff --git a/neosensor/libraries/ArduinoJson/extras/tests/Numbers/convertNumber.cpp b/neosensor/libraries/ArduinoJson/extras/tests/Numbers/convertNumber.cpp index 8c193dc30a4a381309483ceaa744bf552613b221..ca0cc5e03e0a35538e547040c1892002292bd486 100644 --- a/neosensor/libraries/ArduinoJson/extras/tests/Numbers/convertNumber.cpp +++ b/neosensor/libraries/ArduinoJson/extras/tests/Numbers/convertNumber.cpp @@ -1,136 +1,131 @@ // ArduinoJson - https://arduinojson.org -// Copyright © 2014-2022, Benoit BLANCHON +// Copyright © 2014-2023, Benoit BLANCHON // MIT License #include <stdint.h> #include <ArduinoJson.hpp> #include <catch.hpp> -using namespace ARDUINOJSON_NAMESPACE; +using namespace ArduinoJson::detail; TEST_CASE("canConvertNumber<TOut, TIn>()") { SECTION("int8_t -> int8_t") { - CHECK((canConvertNumber<int8_t, int8_t>(0)) == true); - CHECK((canConvertNumber<int8_t, int8_t>(127)) == true); - CHECK((canConvertNumber<int8_t, int8_t>(-128)) == true); + CHECK(canConvertNumber<int8_t, int8_t>(0) == true); + CHECK(canConvertNumber<int8_t, int8_t>(127) == true); + CHECK(canConvertNumber<int8_t, int8_t>(-128) == true); } SECTION("int8_t -> int16_t") { - CHECK((canConvertNumber<int16_t, int8_t>(0)) == true); - CHECK((canConvertNumber<int16_t, int8_t>(127)) == true); - CHECK((canConvertNumber<int16_t, int8_t>(-128)) == true); + CHECK(canConvertNumber<int16_t, int8_t>(0) == true); + CHECK(canConvertNumber<int16_t, int8_t>(127) == true); + CHECK(canConvertNumber<int16_t, int8_t>(-128) == true); } SECTION("int8_t -> uint8_t") { - CHECK((canConvertNumber<uint8_t, int8_t>(0)) == true); - CHECK((canConvertNumber<uint8_t, int8_t>(127)) == true); - CHECK((canConvertNumber<uint8_t, int8_t>(-128)) == false); + CHECK(canConvertNumber<uint8_t, int8_t>(0) == true); + CHECK(canConvertNumber<uint8_t, int8_t>(127) == true); + CHECK(canConvertNumber<uint8_t, int8_t>(-128) == false); } SECTION("int8_t -> uint16_t") { - CHECK((canConvertNumber<uint16_t, int8_t>(0)) == true); - CHECK((canConvertNumber<uint16_t, int8_t>(127)) == true); - CHECK((canConvertNumber<uint16_t, int8_t>(-128)) == false); + CHECK(canConvertNumber<uint16_t, int8_t>(0) == true); + CHECK(canConvertNumber<uint16_t, int8_t>(127) == true); + CHECK(canConvertNumber<uint16_t, int8_t>(-128) == false); } SECTION("int16_t -> int8_t") { - CHECK((canConvertNumber<int8_t, int16_t>(0)) == true); - CHECK((canConvertNumber<int8_t, int16_t>(127)) == true); - CHECK((canConvertNumber<int8_t, int16_t>(128)) == false); - CHECK((canConvertNumber<int8_t, int16_t>(-128)) == true); - CHECK((canConvertNumber<int8_t, int16_t>(-129)) == false); + CHECK(canConvertNumber<int8_t, int16_t>(0) == true); + CHECK(canConvertNumber<int8_t, int16_t>(127) == true); + CHECK(canConvertNumber<int8_t, int16_t>(128) == false); + CHECK(canConvertNumber<int8_t, int16_t>(-128) == true); + CHECK(canConvertNumber<int8_t, int16_t>(-129) == false); } SECTION("int16_t -> uint8_t") { - CHECK((canConvertNumber<uint8_t, int16_t>(0)) == true); - CHECK((canConvertNumber<uint8_t, int16_t>(255)) == true); - CHECK((canConvertNumber<uint8_t, int16_t>(256)) == false); - CHECK((canConvertNumber<uint8_t, int16_t>(-1)) == false); + CHECK(canConvertNumber<uint8_t, int16_t>(0) == true); + CHECK(canConvertNumber<uint8_t, int16_t>(255) == true); + CHECK(canConvertNumber<uint8_t, int16_t>(256) == false); + CHECK(canConvertNumber<uint8_t, int16_t>(-1) == false); } SECTION("uint8_t -> int8_t") { - CHECK((canConvertNumber<int8_t, uint8_t>(0)) == true); - CHECK((canConvertNumber<int8_t, uint8_t>(127)) == true); - CHECK((canConvertNumber<int8_t, uint8_t>(128)) == false); - CHECK((canConvertNumber<int8_t, uint8_t>(255)) == false); + CHECK(canConvertNumber<int8_t, uint8_t>(0) == true); + CHECK(canConvertNumber<int8_t, uint8_t>(127) == true); + CHECK(canConvertNumber<int8_t, uint8_t>(128) == false); + CHECK(canConvertNumber<int8_t, uint8_t>(255) == false); } SECTION("uint8_t -> int16_t") { - CHECK((canConvertNumber<int16_t, uint8_t>(0)) == true); - CHECK((canConvertNumber<int16_t, uint8_t>(127)) == true); - CHECK((canConvertNumber<int16_t, uint8_t>(128)) == true); - CHECK((canConvertNumber<int16_t, uint8_t>(255)) == true); + CHECK(canConvertNumber<int16_t, uint8_t>(0) == true); + CHECK(canConvertNumber<int16_t, uint8_t>(127) == true); + CHECK(canConvertNumber<int16_t, uint8_t>(128) == true); + CHECK(canConvertNumber<int16_t, uint8_t>(255) == true); } SECTION("uint8_t -> uint8_t") { - CHECK((canConvertNumber<uint8_t, uint8_t>(0)) == true); - CHECK((canConvertNumber<uint8_t, uint8_t>(127)) == true); - CHECK((canConvertNumber<uint8_t, uint8_t>(128)) == true); - CHECK((canConvertNumber<uint8_t, uint8_t>(255)) == true); + CHECK(canConvertNumber<uint8_t, uint8_t>(0) == true); + CHECK(canConvertNumber<uint8_t, uint8_t>(127) == true); + CHECK(canConvertNumber<uint8_t, uint8_t>(128) == true); + CHECK(canConvertNumber<uint8_t, uint8_t>(255) == true); } SECTION("uint8_t -> uint16_t") { - CHECK((canConvertNumber<uint16_t, uint8_t>(0)) == true); - CHECK((canConvertNumber<uint16_t, uint8_t>(127)) == true); - CHECK((canConvertNumber<uint16_t, uint8_t>(128)) == true); - CHECK((canConvertNumber<uint16_t, uint8_t>(255)) == true); + CHECK(canConvertNumber<uint16_t, uint8_t>(0) == true); + CHECK(canConvertNumber<uint16_t, uint8_t>(127) == true); + CHECK(canConvertNumber<uint16_t, uint8_t>(128) == true); + CHECK(canConvertNumber<uint16_t, uint8_t>(255) == true); } SECTION("float -> int32_t") { - CHECK((canConvertNumber<int32_t, float>(0)) == true); - CHECK((canConvertNumber<int32_t, float>(-2.147483904e9f)) == false); - CHECK((canConvertNumber<int32_t, float>(-2.147483648e+9f)) == true); - CHECK((canConvertNumber<int32_t, float>(2.14748352e+9f)) == true); - CHECK((canConvertNumber<int32_t, float>(2.14748365e+9f)) == false); + CHECK(canConvertNumber<int32_t, float>(0) == true); + CHECK(canConvertNumber<int32_t, float>(-2.147483904e9f) == false); + CHECK(canConvertNumber<int32_t, float>(-2.147483648e+9f) == true); + CHECK(canConvertNumber<int32_t, float>(2.14748352e+9f) == true); + CHECK(canConvertNumber<int32_t, float>(2.14748365e+9f) == false); } SECTION("double -> int32_t") { - CHECK((canConvertNumber<int32_t, double>(0)) == true); - CHECK((canConvertNumber<int32_t, double>(-2.147483649e+9)) == false); - CHECK((canConvertNumber<int32_t, double>(-2.147483648e+9)) == true); - CHECK((canConvertNumber<int32_t, double>(2.147483647e+9)) == true); - CHECK((canConvertNumber<int32_t, double>(2.147483648e+9)) == false); + CHECK(canConvertNumber<int32_t, double>(0) == true); + CHECK(canConvertNumber<int32_t, double>(-2.147483649e+9) == false); + CHECK(canConvertNumber<int32_t, double>(-2.147483648e+9) == true); + CHECK(canConvertNumber<int32_t, double>(2.147483647e+9) == true); + CHECK(canConvertNumber<int32_t, double>(2.147483648e+9) == false); } SECTION("float -> uint32_t") { - CHECK((canConvertNumber<uint32_t, float>(0)) == true); - CHECK((canConvertNumber<uint32_t, float>(-1.401298e-45f)) == false); - CHECK((canConvertNumber<uint32_t, float>(4.29496704e+9f)) == true); - CHECK((canConvertNumber<uint32_t, float>(4.294967296e+9f)) == false); + CHECK(canConvertNumber<uint32_t, float>(0) == true); + CHECK(canConvertNumber<uint32_t, float>(-1.401298e-45f) == false); + CHECK(canConvertNumber<uint32_t, float>(4.29496704e+9f) == true); + CHECK(canConvertNumber<uint32_t, float>(4.294967296e+9f) == false); } -#if ARDUINOJSON_HAS_LONG_LONG SECTION("float -> int64_t") { - CHECK((canConvertNumber<int64_t, float>(0)) == true); - CHECK((canConvertNumber<int64_t, float>(-9.22337204e+18f)) == true); - CHECK((canConvertNumber<int64_t, float>(9.22337149e+18f)) == true); - CHECK((canConvertNumber<int64_t, float>(9.22337204e+18f)) == false); + CHECK(canConvertNumber<int64_t, float>(0) == true); + CHECK(canConvertNumber<int64_t, float>(-9.22337204e+18f) == true); + CHECK(canConvertNumber<int64_t, float>(9.22337149e+18f) == true); + CHECK(canConvertNumber<int64_t, float>(9.22337204e+18f) == false); } SECTION("double -> int64_t") { - CHECK((canConvertNumber<int64_t, double>(0)) == true); - CHECK((canConvertNumber<int64_t, double>(-9.2233720368547758e+18)) == true); - CHECK((canConvertNumber<int64_t, double>(9.2233720368547748e+18)) == true); - CHECK((canConvertNumber<int64_t, double>(9.2233720368547758e+18)) == false); + CHECK(canConvertNumber<int64_t, double>(0) == true); + CHECK(canConvertNumber<int64_t, double>(-9.2233720368547758e+18) == true); + CHECK(canConvertNumber<int64_t, double>(9.2233720368547748e+18) == true); + CHECK(canConvertNumber<int64_t, double>(9.2233720368547758e+18) == false); } SECTION("float -> uint64_t") { - CHECK((canConvertNumber<uint64_t, float>(0)) == true); - CHECK((canConvertNumber<uint64_t, float>(-1.401298e-45f)) == false); - CHECK((canConvertNumber<uint64_t, float>(1.844674297419792384e+19f)) == - true); - CHECK((canConvertNumber<uint64_t, float>(1.8446744073709551616e+19f)) == + CHECK(canConvertNumber<uint64_t, float>(0) == true); + CHECK(canConvertNumber<uint64_t, float>(-1.401298e-45f) == false); + CHECK(canConvertNumber<uint64_t, float>(1.84467429741979238e+19f) == true); + CHECK(canConvertNumber<uint64_t, float>(1.844674407370955161e+19f) == false); } SECTION("double -> uint64_t") { - CHECK((canConvertNumber<uint64_t, double>(0)) == true); - CHECK((canConvertNumber<uint64_t, double>(-4.94065645841247e-324)) == - false); - CHECK((canConvertNumber<uint64_t, double>(1.8446744073709549568e+19)) == - true); - CHECK((canConvertNumber<uint64_t, double>(1.8446744073709551616e+19)) == + CHECK(canConvertNumber<uint64_t, double>(0) == true); + CHECK(canConvertNumber<uint64_t, double>(-4.9406564584124e-324) == false); + CHECK(canConvertNumber<uint64_t, double>(1.844674407370954958e+19) == true); + CHECK(canConvertNumber<uint64_t, double>(1.844674407370955166e+19) == false); } -#endif } diff --git a/neosensor/libraries/ArduinoJson/extras/tests/Numbers/parseDouble.cpp b/neosensor/libraries/ArduinoJson/extras/tests/Numbers/parseDouble.cpp index 1ce9a02e7c9efb6a2cf66a984cacb49f0b6974d0..301aa0ce00bc642ec870f51db65bd8460e8de269 100644 --- a/neosensor/libraries/ArduinoJson/extras/tests/Numbers/parseDouble.cpp +++ b/neosensor/libraries/ArduinoJson/extras/tests/Numbers/parseDouble.cpp @@ -1,5 +1,5 @@ // ArduinoJson - https://arduinojson.org -// Copyright © 2014-2022, Benoit BLANCHON +// Copyright © 2014-2023, Benoit BLANCHON // MIT License #define ARDUINOJSON_USE_DOUBLE 1 @@ -9,7 +9,7 @@ #include <ArduinoJson.hpp> #include <catch.hpp> -using namespace ARDUINOJSON_NAMESPACE; +using namespace ArduinoJson::detail; void checkDouble(const char* input, double expected) { CAPTURE(input); diff --git a/neosensor/libraries/ArduinoJson/extras/tests/Numbers/parseFloat.cpp b/neosensor/libraries/ArduinoJson/extras/tests/Numbers/parseFloat.cpp index ec69cab9fdb43c29b97374b6543c5245f121e931..4e9c1d47787c0bf2bcdbb4f31761e37b96e701d0 100644 --- a/neosensor/libraries/ArduinoJson/extras/tests/Numbers/parseFloat.cpp +++ b/neosensor/libraries/ArduinoJson/extras/tests/Numbers/parseFloat.cpp @@ -1,5 +1,5 @@ // ArduinoJson - https://arduinojson.org -// Copyright © 2014-2022, Benoit BLANCHON +// Copyright © 2014-2023, Benoit BLANCHON // MIT License #define ARDUINOJSON_USE_DOUBLE 0 @@ -9,7 +9,7 @@ #include <ArduinoJson.hpp> #include <catch.hpp> -using namespace ARDUINOJSON_NAMESPACE; +using namespace ArduinoJson::detail; void checkFloat(const char* input, float expected) { CAPTURE(input); diff --git a/neosensor/libraries/ArduinoJson/extras/tests/Numbers/parseInteger.cpp b/neosensor/libraries/ArduinoJson/extras/tests/Numbers/parseInteger.cpp index aae66e808a3003aa9a3d54f21fe173e98d2fdf8e..880da7640600ac770b8364082ac5fea7d66cddc4 100644 --- a/neosensor/libraries/ArduinoJson/extras/tests/Numbers/parseInteger.cpp +++ b/neosensor/libraries/ArduinoJson/extras/tests/Numbers/parseInteger.cpp @@ -1,12 +1,12 @@ // ArduinoJson - https://arduinojson.org -// Copyright © 2014-2022, Benoit BLANCHON +// Copyright © 2014-2023, Benoit BLANCHON // MIT License #include <stdint.h> #include <ArduinoJson.hpp> #include <catch.hpp> -using namespace ARDUINOJSON_NAMESPACE; +using namespace ArduinoJson::detail; template <typename T> void checkInteger(const char* input, T expected) { diff --git a/neosensor/libraries/ArduinoJson/extras/tests/Numbers/parseNumber.cpp b/neosensor/libraries/ArduinoJson/extras/tests/Numbers/parseNumber.cpp index 7dd5aa06a657fe60354abbc1fa1201d05bc75774..48163c15060f2776e7175562a0bbb926111c7054 100644 --- a/neosensor/libraries/ArduinoJson/extras/tests/Numbers/parseNumber.cpp +++ b/neosensor/libraries/ArduinoJson/extras/tests/Numbers/parseNumber.cpp @@ -1,16 +1,15 @@ // ArduinoJson - https://arduinojson.org -// Copyright © 2014-2022, Benoit BLANCHON +// Copyright © 2014-2023, Benoit BLANCHON // MIT License #include <ArduinoJson.hpp> #include <catch.hpp> -using namespace ARDUINOJSON_NAMESPACE; +using namespace ArduinoJson; +using namespace ArduinoJson::detail; TEST_CASE("Test unsigned integer overflow") { VariantData first, second; - first.init(); - second.init(); // Avoids MSVC warning C4127 (conditional expression is constant) size_t integerSize = sizeof(JsonInteger); @@ -29,8 +28,6 @@ TEST_CASE("Test unsigned integer overflow") { TEST_CASE("Test signed integer overflow") { VariantData first, second; - first.init(); - second.init(); // Avoids MSVC warning C4127 (conditional expression is constant) size_t integerSize = sizeof(JsonInteger); @@ -49,7 +46,6 @@ TEST_CASE("Test signed integer overflow") { TEST_CASE("Invalid value") { VariantData result; - result.init(); parseNumber("6a3", result); diff --git a/neosensor/libraries/ArduinoJson/extras/tests/TextFormatter/CMakeLists.txt b/neosensor/libraries/ArduinoJson/extras/tests/TextFormatter/CMakeLists.txt index 57a3f85b23e245cbb1866359d4a36c9076bc47c6..2bc4a899d92775fc259939af8d152ab9921ba5fd 100644 --- a/neosensor/libraries/ArduinoJson/extras/tests/TextFormatter/CMakeLists.txt +++ b/neosensor/libraries/ArduinoJson/extras/tests/TextFormatter/CMakeLists.txt @@ -1,8 +1,8 @@ # ArduinoJson - https://arduinojson.org -# Copyright © 2014-2022, Benoit BLANCHON +# Copyright © 2014-2023, Benoit BLANCHON # MIT License -add_executable(TextFormatterTests +add_executable(TextFormatterTests writeFloat.cpp writeInteger.cpp writeString.cpp @@ -14,5 +14,5 @@ add_test(TextFormatter TextFormatterTests) set_tests_properties(TextFormatter PROPERTIES - LABELS "Catch" + LABELS "Catch" ) diff --git a/neosensor/libraries/ArduinoJson/extras/tests/TextFormatter/writeFloat.cpp b/neosensor/libraries/ArduinoJson/extras/tests/TextFormatter/writeFloat.cpp index 87eef3d94006459ca98c3cfa596588c6090a45fb..8e4bd7e78367e71bda61fc726c9fed9ea51258f8 100644 --- a/neosensor/libraries/ArduinoJson/extras/tests/TextFormatter/writeFloat.cpp +++ b/neosensor/libraries/ArduinoJson/extras/tests/TextFormatter/writeFloat.cpp @@ -1,5 +1,5 @@ // ArduinoJson - https://arduinojson.org -// Copyright © 2014-2022, Benoit BLANCHON +// Copyright © 2014-2023, Benoit BLANCHON // MIT License #include <catch.hpp> @@ -11,13 +11,13 @@ #include <ArduinoJson/Json/TextFormatter.hpp> #include <ArduinoJson/Serialization/Writer.hpp> -using namespace ARDUINOJSON_NAMESPACE; +using namespace ArduinoJson::detail; template <typename TFloat> void check(TFloat input, const std::string& expected) { std::string output; Writer<std::string> sb(output); - TextFormatter<Writer<std::string> > writer(sb); + TextFormatter<Writer<std::string>> writer(sb); writer.writeFloat(input); REQUIRE(writer.bytesWritten() == output.size()); CHECK(expected == output); diff --git a/neosensor/libraries/ArduinoJson/extras/tests/TextFormatter/writeInteger.cpp b/neosensor/libraries/ArduinoJson/extras/tests/TextFormatter/writeInteger.cpp index cc29fc0ffeb5de4be318e79c207abc5e40bb6e6a..20cbd29faad3ffeac4779403c21859647c418a36 100644 --- a/neosensor/libraries/ArduinoJson/extras/tests/TextFormatter/writeInteger.cpp +++ b/neosensor/libraries/ArduinoJson/extras/tests/TextFormatter/writeInteger.cpp @@ -1,5 +1,5 @@ // ArduinoJson - https://arduinojson.org -// Copyright © 2014-2022, Benoit BLANCHON +// Copyright © 2014-2023, Benoit BLANCHON // MIT License #include <catch.hpp> @@ -9,7 +9,7 @@ #include <ArduinoJson/Json/TextFormatter.hpp> #include <ArduinoJson/Serialization/Writer.hpp> -using namespace ARDUINOJSON_NAMESPACE; +using namespace ArduinoJson::detail; template <typename T> void checkWriteInteger(T value, std::string expected) { diff --git a/neosensor/libraries/ArduinoJson/extras/tests/TextFormatter/writeString.cpp b/neosensor/libraries/ArduinoJson/extras/tests/TextFormatter/writeString.cpp index 67b12b5029ec0160eecaf427ea54798815330f7a..2be9191cf9b1e016b0a0728253fd2ddd3d6e7e58 100644 --- a/neosensor/libraries/ArduinoJson/extras/tests/TextFormatter/writeString.cpp +++ b/neosensor/libraries/ArduinoJson/extras/tests/TextFormatter/writeString.cpp @@ -1,5 +1,5 @@ // ArduinoJson - https://arduinojson.org -// Copyright © 2014-2022, Benoit BLANCHON +// Copyright © 2014-2023, Benoit BLANCHON // MIT License #include <catch.hpp> @@ -7,7 +7,7 @@ #include <ArduinoJson/Json/TextFormatter.hpp> #include <ArduinoJson/Serialization/Writers/StaticStringWriter.hpp> -using namespace ARDUINOJSON_NAMESPACE; +using namespace ArduinoJson::detail; void check(const char* input, std::string expected) { char output[64] = {0}; diff --git a/neosensor/libraries/ArduinoJson/extras/tests/catch/CMakeLists.txt b/neosensor/libraries/ArduinoJson/extras/tests/catch/CMakeLists.txt index 776a07a007f48a61cd14ab77c5ed0bde44f2b013..c5fb5fb8340b043e00fd42b43e8e407351fbb0bb 100644 --- a/neosensor/libraries/ArduinoJson/extras/tests/catch/CMakeLists.txt +++ b/neosensor/libraries/ArduinoJson/extras/tests/catch/CMakeLists.txt @@ -2,7 +2,7 @@ # Copyright Benoit Blanchon 2014-2021 # MIT License -set(CMAKE_CXX_STANDARD 11) +set(CMAKE_CXX_STANDARD 17) set(CMAKE_CXX_STANDARD_REQUIRED OFF) add_library(catch @@ -12,10 +12,10 @@ add_library(catch target_include_directories(catch PUBLIC - ${CMAKE_CURRENT_SOURCE_DIR} + ${CMAKE_CURRENT_SOURCE_DIR} ) -if(CMAKE_CXX_COMPILER_ID MATCHES "GNU") - # prevent "xxx will change in GCC x.x" with arm-linux-gnueabihf-gcc - target_compile_options(catch PRIVATE -Wno-psabi) +if(MINGW) + # prevent "too many sections (32837)" with MinGW + target_compile_options(catch PRIVATE -Wa,-mbig-obj) endif() diff --git a/neosensor/libraries/ArduinoJson/extras/tests/catch/catch.hpp b/neosensor/libraries/ArduinoJson/extras/tests/catch/catch.hpp index fdb046fe442822af5f7b8de14db3ee242cee18a8..9b309bddc6bcc736af7c1264c2a6f760fa52d4bb 100644 --- a/neosensor/libraries/ArduinoJson/extras/tests/catch/catch.hpp +++ b/neosensor/libraries/ArduinoJson/extras/tests/catch/catch.hpp @@ -1,17 +1,21 @@ /* - * Catch v1.12.2 - * Generated: 2018-05-14 15:10:01.112442 + * Catch v2.13.10 + * Generated: 2022-10-16 11:01:23.452308 * ---------------------------------------------------------- * This file has been merged from multiple headers. Please don't edit it directly - * Copyright (c) 2012 Two Blue Cubes Ltd. All rights reserved. + * Copyright (c) 2022 Two Blue Cubes Ltd. All rights reserved. * * Distributed under the Boost Software License, Version 1.0. (See accompanying * file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) */ #ifndef TWOBLUECUBES_SINGLE_INCLUDE_CATCH_HPP_INCLUDED #define TWOBLUECUBES_SINGLE_INCLUDE_CATCH_HPP_INCLUDED +// start catch.hpp -#define TWOBLUECUBES_CATCH_HPP_INCLUDED + +#define CATCH_VERSION_MAJOR 2 +#define CATCH_VERSION_MINOR 13 +#define CATCH_VERSION_PATCH 10 #ifdef __clang__ # pragma clang system_header @@ -19,36 +23,69 @@ # pragma GCC system_header #endif -// #included from: internal/catch_suppress_warnings.h +// start catch_suppress_warnings.h #ifdef __clang__ # ifdef __ICC // icpc defines the __clang__ macro # pragma warning(push) # pragma warning(disable: 161 1682) # else // __ICC -# pragma clang diagnostic ignored "-Wglobal-constructors" -# pragma clang diagnostic ignored "-Wvariadic-macros" -# pragma clang diagnostic ignored "-Wc99-extensions" -# pragma clang diagnostic ignored "-Wunused-variable" # pragma clang diagnostic push # pragma clang diagnostic ignored "-Wpadded" -# 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" -# pragma GCC diagnostic ignored "-Wunused-variable" -# pragma GCC diagnostic ignored "-Wparentheses" + // Because REQUIREs trigger GCC's -Wparentheses, and because still + // supported version of g++ have only buggy support for _Pragmas, + // Wparentheses have to be suppressed globally. +# pragma GCC diagnostic ignored "-Wparentheses" // See #674 for details # pragma GCC diagnostic push +# pragma GCC diagnostic ignored "-Wunused-variable" # pragma GCC diagnostic ignored "-Wpadded" #endif +// end catch_suppress_warnings.h #if defined(CATCH_CONFIG_MAIN) || defined(CATCH_CONFIG_RUNNER) # define CATCH_IMPL +# define CATCH_CONFIG_ALL_PARTS +#endif + +// In the impl file, we want to have access to all parts of the headers +// Can also be used to sanely support PCHs +#if defined(CATCH_CONFIG_ALL_PARTS) +# define CATCH_CONFIG_EXTERNAL_INTERFACES +# if defined(CATCH_CONFIG_DISABLE_MATCHERS) +# undef CATCH_CONFIG_DISABLE_MATCHERS +# endif +# if !defined(CATCH_CONFIG_ENABLE_CHRONO_STRINGMAKER) +# define CATCH_CONFIG_ENABLE_CHRONO_STRINGMAKER +# endif +#endif + +#if !defined(CATCH_CONFIG_IMPL_ONLY) +// start catch_platform.h + +// See e.g.: +// https://opensource.apple.com/source/CarbonHeaders/CarbonHeaders-18.1/TargetConditionals.h.auto.html +#ifdef __APPLE__ +# include <TargetConditionals.h> +# if (defined(TARGET_OS_OSX) && TARGET_OS_OSX == 1) || \ + (defined(TARGET_OS_MAC) && TARGET_OS_MAC == 1) +# define CATCH_PLATFORM_MAC +# elif (defined(TARGET_OS_IPHONE) && TARGET_OS_IPHONE == 1) +# define CATCH_PLATFORM_IPHONE +# endif + +#elif defined(linux) || defined(__linux) || defined(__linux__) +# define CATCH_PLATFORM_LINUX + +#elif defined(WIN32) || defined(__WIN32__) || defined(_WIN32) || defined(_MSC_VER) || defined(__MINGW32__) +# define CATCH_PLATFORM_WINDOWS #endif +// end catch_platform.h + #ifdef CATCH_IMPL # ifndef CLARA_CONFIG_MAIN # define CLARA_CONFIG_MAIN_NOT_DEFINED @@ -56,93 +93,106 @@ # endif #endif -// #included from: internal/catch_notimplemented_exception.h -#define TWOBLUECUBES_CATCH_NOTIMPLEMENTED_EXCEPTION_H_INCLUDED +// start catch_user_interfaces.h -// #included from: catch_common.h -#define TWOBLUECUBES_CATCH_COMMON_H_INCLUDED +namespace Catch { + unsigned int rngSeed(); +} + +// end catch_user_interfaces.h +// start catch_tag_alias_autoregistrar.h -// #included from: catch_compiler_capabilities.h -#define TWOBLUECUBES_CATCH_COMPILER_CAPABILITIES_HPP_INCLUDED +// start catch_common.h -// Detect a number of compiler features - mostly C++11/14 conformance - by compiler +// start catch_compiler_capabilities.h + +// Detect a number of compiler features - by compiler // The following features are defined: // -// CATCH_CONFIG_CPP11_NULLPTR : is nullptr supported? -// CATCH_CONFIG_CPP11_NOEXCEPT : is noexcept supported? -// 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_SHUFFLE : is std::shuffle supported? -// CATCH_CONFIG_CPP11_TYPE_TRAITS : are type_traits and enable_if supported? - -// CATCH_CONFIG_CPP11_OR_GREATER : Is C++11 supported? - -// CATCH_CONFIG_VARIADIC_MACROS : are variadic macros supported? // CATCH_CONFIG_COUNTER : is the __COUNTER__ macro supported? // CATCH_CONFIG_WINDOWS_SEH : is Windows SEH supported? // CATCH_CONFIG_POSIX_SIGNALS : are POSIX signals supported? +// CATCH_CONFIG_DISABLE_EXCEPTIONS : Are exceptions enabled? // **************** // Note to maintainers: if new toggles are added please document them // in configuration.md, too // **************** // In general each macro has a _NO_<feature name> form -// (e.g. CATCH_CONFIG_CPP11_NO_NULLPTR) which disables the feature. +// (e.g. CATCH_CONFIG_NO_POSIX_SIGNALS) which disables the feature. // Many features, at point of detection, define an _INTERNAL_ macro, so they // can be combined, en-mass, with the _NO_ forms later. -// All the C++11 features can be disabled with CATCH_CONFIG_NO_CPP11 - #ifdef __cplusplus -# if __cplusplus >= 201103L -# define CATCH_CPP11_OR_GREATER +# if (__cplusplus >= 201402L) || (defined(_MSVC_LANG) && _MSVC_LANG >= 201402L) +# define CATCH_CPP14_OR_GREATER # endif -# if __cplusplus >= 201402L -# define CATCH_CPP14_OR_GREATER +# if (__cplusplus >= 201703L) || (defined(_MSVC_LANG) && _MSVC_LANG >= 201703L) +# define CATCH_CPP17_OR_GREATER # endif #endif -#ifdef __clang__ +// Only GCC compiler should be used in this block, so other compilers trying to +// mask themselves as GCC should be ignored. +#if defined(__GNUC__) && !defined(__clang__) && !defined(__ICC) && !defined(__CUDACC__) && !defined(__LCC__) +# define CATCH_INTERNAL_START_WARNINGS_SUPPRESSION _Pragma( "GCC diagnostic push" ) +# define CATCH_INTERNAL_STOP_WARNINGS_SUPPRESSION _Pragma( "GCC diagnostic pop" ) -# if __has_feature(cxx_nullptr) -# define CATCH_INTERNAL_CONFIG_CPP11_NULLPTR -# endif +# define CATCH_INTERNAL_IGNORE_BUT_WARN(...) (void)__builtin_constant_p(__VA_ARGS__) + +#endif -# if __has_feature(cxx_noexcept) -# define CATCH_INTERNAL_CONFIG_CPP11_NOEXCEPT +#if defined(__clang__) + +# define CATCH_INTERNAL_START_WARNINGS_SUPPRESSION _Pragma( "clang diagnostic push" ) +# define CATCH_INTERNAL_STOP_WARNINGS_SUPPRESSION _Pragma( "clang diagnostic pop" ) + +// As of this writing, IBM XL's implementation of __builtin_constant_p has a bug +// which results in calls to destructors being emitted for each temporary, +// without a matching initialization. In practice, this can result in something +// like `std::string::~string` being called on an uninitialized value. +// +// For example, this code will likely segfault under IBM XL: +// ``` +// REQUIRE(std::string("12") + "34" == "1234") +// ``` +// +// Therefore, `CATCH_INTERNAL_IGNORE_BUT_WARN` is not implemented. +# if !defined(__ibmxl__) && !defined(__CUDACC__) +# define CATCH_INTERNAL_IGNORE_BUT_WARN(...) (void)__builtin_constant_p(__VA_ARGS__) /* NOLINT(cppcoreguidelines-pro-type-vararg, hicpp-vararg) */ # endif -# if defined(CATCH_CPP11_OR_GREATER) -# define CATCH_INTERNAL_SUPPRESS_ETD_WARNINGS \ - _Pragma( "clang diagnostic push" ) \ - _Pragma( "clang diagnostic ignored \"-Wexit-time-destructors\"" ) -# define CATCH_INTERNAL_UNSUPPRESS_ETD_WARNINGS \ - _Pragma( "clang diagnostic pop" ) - -# define CATCH_INTERNAL_SUPPRESS_PARENTHESES_WARNINGS \ - _Pragma( "clang diagnostic push" ) \ - _Pragma( "clang diagnostic ignored \"-Wparentheses\"" ) -# define CATCH_INTERNAL_UNSUPPRESS_PARENTHESES_WARNINGS \ - _Pragma( "clang diagnostic pop" ) -# endif +# define CATCH_INTERNAL_SUPPRESS_GLOBALS_WARNINGS \ + _Pragma( "clang diagnostic ignored \"-Wexit-time-destructors\"" ) \ + _Pragma( "clang diagnostic ignored \"-Wglobal-constructors\"") + +# define CATCH_INTERNAL_SUPPRESS_PARENTHESES_WARNINGS \ + _Pragma( "clang diagnostic ignored \"-Wparentheses\"" ) + +# define CATCH_INTERNAL_SUPPRESS_UNUSED_WARNINGS \ + _Pragma( "clang diagnostic ignored \"-Wunused-variable\"" ) + +# define CATCH_INTERNAL_SUPPRESS_ZERO_VARIADIC_WARNINGS \ + _Pragma( "clang diagnostic ignored \"-Wgnu-zero-variadic-macro-arguments\"" ) + +# define CATCH_INTERNAL_SUPPRESS_UNUSED_TEMPLATE_WARNINGS \ + _Pragma( "clang diagnostic ignored \"-Wunused-template\"" ) #endif // __clang__ //////////////////////////////////////////////////////////////////////////////// -// We know some environments not to support full POSIX signals -#if defined(__CYGWIN__) || defined(__QNX__) - -# if !defined(CATCH_CONFIG_POSIX_SIGNALS) -# define CATCH_INTERNAL_CONFIG_NO_POSIX_SIGNALS -# endif +// Assume that non-Windows platforms support posix signals by default +#if !defined(CATCH_PLATFORM_WINDOWS) + #define CATCH_INTERNAL_CONFIG_POSIX_SIGNALS +#endif +//////////////////////////////////////////////////////////////////////////////// +// We know some environments not to support full POSIX signals +#if defined(__CYGWIN__) || defined(__QNX__) || defined(__EMSCRIPTEN__) || defined(__DJGPP__) + #define CATCH_INTERNAL_CONFIG_NO_POSIX_SIGNALS #endif #ifdef __OS400__ @@ -150,6 +200,25 @@ # define CATCH_CONFIG_COLOUR_NONE #endif +//////////////////////////////////////////////////////////////////////////////// +// Android somehow still does not support std::to_string +#if defined(__ANDROID__) +# define CATCH_INTERNAL_CONFIG_NO_CPP11_TO_STRING +# define CATCH_INTERNAL_CONFIG_ANDROID_LOGWRITE +#endif + +//////////////////////////////////////////////////////////////////////////////// +// Not all Windows environments support SEH properly +#if defined(__MINGW32__) +# define CATCH_INTERNAL_CONFIG_NO_WINDOWS_SEH +#endif + +//////////////////////////////////////////////////////////////////////////////// +// PS4 +#if defined(__ORBIS__) +# define CATCH_INTERNAL_CONFIG_NO_NEW_CAPTURE +#endif + //////////////////////////////////////////////////////////////////////////////// // Cygwin #ifdef __CYGWIN__ @@ -157,219 +226,245 @@ // Required for some versions of Cygwin to declare gettimeofday // see: http://stackoverflow.com/questions/36901803/gettimeofday-not-declared-in-this-scope-cygwin # define _BSD_SOURCE +// some versions of cygwin (most) do not support std::to_string. Use the libstd check. +// https://gcc.gnu.org/onlinedocs/gcc-4.8.2/libstdc++/api/a01053_source.html line 2812-2813 +# if !((__cplusplus >= 201103L) && defined(_GLIBCXX_USE_C99) \ + && !defined(_GLIBCXX_HAVE_BROKEN_VSWPRINTF)) -#endif // __CYGWIN__ - -//////////////////////////////////////////////////////////////////////////////// -// Borland -#ifdef __BORLANDC__ +# define CATCH_INTERNAL_CONFIG_NO_CPP11_TO_STRING -#endif // __BORLANDC__ +# endif +#endif // __CYGWIN__ //////////////////////////////////////////////////////////////////////////////// -// EDG -#ifdef __EDG_VERSION__ - -#endif // __EDG_VERSION__ +// Visual C++ +#if defined(_MSC_VER) -//////////////////////////////////////////////////////////////////////////////// -// Digital Mars -#ifdef __DMC__ +// Universal Windows platform does not support SEH +// Or console colours (or console at all...) +# if defined(WINAPI_FAMILY) && (WINAPI_FAMILY == WINAPI_FAMILY_APP) +# define CATCH_CONFIG_COLOUR_NONE +# else +# define CATCH_INTERNAL_CONFIG_WINDOWS_SEH +# endif -#endif // __DMC__ +# if !defined(__clang__) // Handle Clang masquerading for msvc -//////////////////////////////////////////////////////////////////////////////// -// GCC -#ifdef __GNUC__ +// MSVC traditional preprocessor needs some workaround for __VA_ARGS__ +// _MSVC_TRADITIONAL == 0 means new conformant preprocessor +// _MSVC_TRADITIONAL == 1 means old traditional non-conformant preprocessor +# if !defined(_MSVC_TRADITIONAL) || (defined(_MSVC_TRADITIONAL) && _MSVC_TRADITIONAL) +# define CATCH_INTERNAL_CONFIG_TRADITIONAL_MSVC_PREPROCESSOR +# endif // MSVC_TRADITIONAL -# if __GNUC__ == 4 && __GNUC_MINOR__ >= 6 && defined(__GXX_EXPERIMENTAL_CXX0X__) -# define CATCH_INTERNAL_CONFIG_CPP11_NULLPTR -# endif +// Only do this if we're not using clang on Windows, which uses `diagnostic push` & `diagnostic pop` +# define CATCH_INTERNAL_START_WARNINGS_SUPPRESSION __pragma( warning(push) ) +# define CATCH_INTERNAL_STOP_WARNINGS_SUPPRESSION __pragma( warning(pop) ) +# endif // __clang__ -// - otherwise more recent versions define __cplusplus >= 201103L -// and will get picked up below +#endif // _MSC_VER -#endif // __GNUC__ +#if defined(_REENTRANT) || defined(_MSC_VER) +// Enable async processing, as -pthread is specified or no additional linking is required +# define CATCH_INTERNAL_CONFIG_USE_ASYNC +#endif // _MSC_VER //////////////////////////////////////////////////////////////////////////////// -// Visual C++ -#ifdef _MSC_VER - -#define CATCH_INTERNAL_CONFIG_WINDOWS_SEH - -#if (_MSC_VER >= 1600) -# define CATCH_INTERNAL_CONFIG_CPP11_NULLPTR -# define CATCH_INTERNAL_CONFIG_CPP11_UNIQUE_PTR +// Check if we are compiled with -fno-exceptions or equivalent +#if defined(__EXCEPTIONS) || defined(__cpp_exceptions) || defined(_CPPUNWIND) +# define CATCH_INTERNAL_CONFIG_EXCEPTIONS_ENABLED #endif -#if (_MSC_VER >= 1900 ) // (VC++ 13 (VS2015)) -#define CATCH_INTERNAL_CONFIG_CPP11_NOEXCEPT -#define CATCH_INTERNAL_CONFIG_CPP11_GENERATED_METHODS -#define CATCH_INTERNAL_CONFIG_CPP11_SHUFFLE -#define CATCH_INTERNAL_CONFIG_CPP11_TYPE_TRAITS -#endif - -#endif // _MSC_VER - //////////////////////////////////////////////////////////////////////////////// +// DJGPP +#ifdef __DJGPP__ +# define CATCH_INTERNAL_CONFIG_NO_WCHAR +#endif // __DJGPP__ -// Use variadic macros if the compiler supports them -#if ( defined _MSC_VER && _MSC_VER > 1400 && !defined __EDGE__) || \ - ( defined __WAVE__ && __WAVE_HAS_VARIADICS ) || \ - ( defined __GNUC__ && __GNUC__ >= 3 ) || \ - ( !defined __cplusplus && __STDC_VERSION__ >= 199901L || __cplusplus >= 201103L ) - -#define CATCH_INTERNAL_CONFIG_VARIADIC_MACROS - +//////////////////////////////////////////////////////////////////////////////// +// Embarcadero C++Build +#if defined(__BORLANDC__) + #define CATCH_INTERNAL_CONFIG_POLYFILL_ISNAN #endif -// Use __COUNTER__ if the compiler supports it -#if ( defined _MSC_VER && _MSC_VER >= 1300 ) || \ - ( defined __GNUC__ && ( __GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 3 )) ) || \ - ( defined __clang__ && __clang_major__ >= 3 ) +//////////////////////////////////////////////////////////////////////////////// -// Use of __COUNTER__ is suppressed during code analysis in CLion/AppCode 2017.2.x and former, -// because __COUNTER__ is not properly handled by it. -// This does not affect compilation -#if ( !defined __JETBRAINS_IDE__ || __JETBRAINS_IDE__ >= 20170300L ) +// Use of __COUNTER__ is suppressed during code analysis in +// CLion/AppCode 2017.2.x and former, because __COUNTER__ is not properly +// handled by it. +// Otherwise all supported compilers support COUNTER macro, +// but user still might want to turn it off +#if ( !defined(__JETBRAINS_IDE__) || __JETBRAINS_IDE__ >= 20170300L ) #define CATCH_INTERNAL_CONFIG_COUNTER #endif -#endif - //////////////////////////////////////////////////////////////////////////////// -// C++ language feature support -// catch all support for C++11 -#if defined(CATCH_CPP11_OR_GREATER) - -# if !defined(CATCH_INTERNAL_CONFIG_CPP11_NULLPTR) -# define CATCH_INTERNAL_CONFIG_CPP11_NULLPTR -# endif +// RTX is a special version of Windows that is real time. +// This means that it is detected as Windows, but does not provide +// the same set of capabilities as real Windows does. +#if defined(UNDER_RTSS) || defined(RTX64_BUILD) + #define CATCH_INTERNAL_CONFIG_NO_WINDOWS_SEH + #define CATCH_INTERNAL_CONFIG_NO_ASYNC + #define CATCH_CONFIG_COLOUR_NONE +#endif -# ifndef CATCH_INTERNAL_CONFIG_CPP11_NOEXCEPT -# define CATCH_INTERNAL_CONFIG_CPP11_NOEXCEPT -# endif +#if !defined(_GLIBCXX_USE_C99_MATH_TR1) +#define CATCH_INTERNAL_CONFIG_GLOBAL_NEXTAFTER +#endif -# ifndef CATCH_INTERNAL_CONFIG_CPP11_GENERATED_METHODS -# define CATCH_INTERNAL_CONFIG_CPP11_GENERATED_METHODS -# endif +// Various stdlib support checks that require __has_include +#if defined(__has_include) + // Check if string_view is available and usable + #if __has_include(<string_view>) && defined(CATCH_CPP17_OR_GREATER) + # define CATCH_INTERNAL_CONFIG_CPP17_STRING_VIEW + #endif + + // Check if optional is available and usable + # if __has_include(<optional>) && defined(CATCH_CPP17_OR_GREATER) + # define CATCH_INTERNAL_CONFIG_CPP17_OPTIONAL + # endif // __has_include(<optional>) && defined(CATCH_CPP17_OR_GREATER) + + // Check if byte is available and usable + # if __has_include(<cstddef>) && defined(CATCH_CPP17_OR_GREATER) + # include <cstddef> + # if defined(__cpp_lib_byte) && (__cpp_lib_byte > 0) + # define CATCH_INTERNAL_CONFIG_CPP17_BYTE + # endif + # endif // __has_include(<cstddef>) && defined(CATCH_CPP17_OR_GREATER) + + // Check if variant is available and usable + # if __has_include(<variant>) && defined(CATCH_CPP17_OR_GREATER) + # if defined(__clang__) && (__clang_major__ < 8) + // work around clang bug with libstdc++ https://bugs.llvm.org/show_bug.cgi?id=31852 + // fix should be in clang 8, workaround in libstdc++ 8.2 + # include <ciso646> + # if defined(__GLIBCXX__) && defined(_GLIBCXX_RELEASE) && (_GLIBCXX_RELEASE < 9) + # define CATCH_CONFIG_NO_CPP17_VARIANT + # else + # define CATCH_INTERNAL_CONFIG_CPP17_VARIANT + # endif // defined(__GLIBCXX__) && defined(_GLIBCXX_RELEASE) && (_GLIBCXX_RELEASE < 9) + # else + # define CATCH_INTERNAL_CONFIG_CPP17_VARIANT + # endif // defined(__clang__) && (__clang_major__ < 8) + # endif // __has_include(<variant>) && defined(CATCH_CPP17_OR_GREATER) +#endif // defined(__has_include) -# ifndef CATCH_INTERNAL_CONFIG_CPP11_IS_ENUM -# define CATCH_INTERNAL_CONFIG_CPP11_IS_ENUM -# endif +#if defined(CATCH_INTERNAL_CONFIG_COUNTER) && !defined(CATCH_CONFIG_NO_COUNTER) && !defined(CATCH_CONFIG_COUNTER) +# define CATCH_CONFIG_COUNTER +#endif +#if defined(CATCH_INTERNAL_CONFIG_WINDOWS_SEH) && !defined(CATCH_CONFIG_NO_WINDOWS_SEH) && !defined(CATCH_CONFIG_WINDOWS_SEH) && !defined(CATCH_INTERNAL_CONFIG_NO_WINDOWS_SEH) +# define CATCH_CONFIG_WINDOWS_SEH +#endif +// This is set by default, because we assume that unix compilers are posix-signal-compatible by default. +#if defined(CATCH_INTERNAL_CONFIG_POSIX_SIGNALS) && !defined(CATCH_INTERNAL_CONFIG_NO_POSIX_SIGNALS) && !defined(CATCH_CONFIG_NO_POSIX_SIGNALS) && !defined(CATCH_CONFIG_POSIX_SIGNALS) +# define CATCH_CONFIG_POSIX_SIGNALS +#endif +// This is set by default, because we assume that compilers with no wchar_t support are just rare exceptions. +#if !defined(CATCH_INTERNAL_CONFIG_NO_WCHAR) && !defined(CATCH_CONFIG_NO_WCHAR) && !defined(CATCH_CONFIG_WCHAR) +# define CATCH_CONFIG_WCHAR +#endif -# ifndef CATCH_INTERNAL_CONFIG_CPP11_TUPLE -# define CATCH_INTERNAL_CONFIG_CPP11_TUPLE -# endif +#if !defined(CATCH_INTERNAL_CONFIG_NO_CPP11_TO_STRING) && !defined(CATCH_CONFIG_NO_CPP11_TO_STRING) && !defined(CATCH_CONFIG_CPP11_TO_STRING) +# define CATCH_CONFIG_CPP11_TO_STRING +#endif -# ifndef CATCH_INTERNAL_CONFIG_VARIADIC_MACROS -# define CATCH_INTERNAL_CONFIG_VARIADIC_MACROS -# endif +#if defined(CATCH_INTERNAL_CONFIG_CPP17_OPTIONAL) && !defined(CATCH_CONFIG_NO_CPP17_OPTIONAL) && !defined(CATCH_CONFIG_CPP17_OPTIONAL) +# define CATCH_CONFIG_CPP17_OPTIONAL +#endif -# if !defined(CATCH_INTERNAL_CONFIG_CPP11_LONG_LONG) -# define CATCH_INTERNAL_CONFIG_CPP11_LONG_LONG -# endif +#if defined(CATCH_INTERNAL_CONFIG_CPP17_STRING_VIEW) && !defined(CATCH_CONFIG_NO_CPP17_STRING_VIEW) && !defined(CATCH_CONFIG_CPP17_STRING_VIEW) +# define CATCH_CONFIG_CPP17_STRING_VIEW +#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 -# if !defined(CATCH_INTERNAL_CONFIG_CPP11_SHUFFLE) -# define CATCH_INTERNAL_CONFIG_CPP11_SHUFFLE -# endif -# if !defined(CATCH_INTERNAL_CONFIG_CPP11_TYPE_TRAITS) -# define CATCH_INTERNAL_CONFIG_CPP11_TYPE_TRAITS -# endif +#if defined(CATCH_INTERNAL_CONFIG_CPP17_VARIANT) && !defined(CATCH_CONFIG_NO_CPP17_VARIANT) && !defined(CATCH_CONFIG_CPP17_VARIANT) +# define CATCH_CONFIG_CPP17_VARIANT +#endif -#endif // __cplusplus >= 201103L +#if defined(CATCH_INTERNAL_CONFIG_CPP17_BYTE) && !defined(CATCH_CONFIG_NO_CPP17_BYTE) && !defined(CATCH_CONFIG_CPP17_BYTE) +# define CATCH_CONFIG_CPP17_BYTE +#endif -// Now set the actual defines based on the above + anything the user has configured -#if defined(CATCH_INTERNAL_CONFIG_CPP11_NULLPTR) && !defined(CATCH_CONFIG_CPP11_NO_NULLPTR) && !defined(CATCH_CONFIG_CPP11_NULLPTR) && !defined(CATCH_CONFIG_NO_CPP11) -# define CATCH_CONFIG_CPP11_NULLPTR +#if defined(CATCH_CONFIG_EXPERIMENTAL_REDIRECT) +# define CATCH_INTERNAL_CONFIG_NEW_CAPTURE #endif -#if defined(CATCH_INTERNAL_CONFIG_CPP11_NOEXCEPT) && !defined(CATCH_CONFIG_CPP11_NO_NOEXCEPT) && !defined(CATCH_CONFIG_CPP11_NOEXCEPT) && !defined(CATCH_CONFIG_NO_CPP11) -# define CATCH_CONFIG_CPP11_NOEXCEPT + +#if defined(CATCH_INTERNAL_CONFIG_NEW_CAPTURE) && !defined(CATCH_INTERNAL_CONFIG_NO_NEW_CAPTURE) && !defined(CATCH_CONFIG_NO_NEW_CAPTURE) && !defined(CATCH_CONFIG_NEW_CAPTURE) +# define CATCH_CONFIG_NEW_CAPTURE #endif -#if defined(CATCH_INTERNAL_CONFIG_CPP11_GENERATED_METHODS) && !defined(CATCH_CONFIG_CPP11_NO_GENERATED_METHODS) && !defined(CATCH_CONFIG_CPP11_GENERATED_METHODS) && !defined(CATCH_CONFIG_NO_CPP11) -# define CATCH_CONFIG_CPP11_GENERATED_METHODS + +#if !defined(CATCH_INTERNAL_CONFIG_EXCEPTIONS_ENABLED) && !defined(CATCH_CONFIG_DISABLE_EXCEPTIONS) +# define CATCH_CONFIG_DISABLE_EXCEPTIONS #endif -#if defined(CATCH_INTERNAL_CONFIG_CPP11_IS_ENUM) && !defined(CATCH_CONFIG_CPP11_NO_IS_ENUM) && !defined(CATCH_CONFIG_CPP11_IS_ENUM) && !defined(CATCH_CONFIG_NO_CPP11) -# define CATCH_CONFIG_CPP11_IS_ENUM + +#if defined(CATCH_INTERNAL_CONFIG_POLYFILL_ISNAN) && !defined(CATCH_CONFIG_NO_POLYFILL_ISNAN) && !defined(CATCH_CONFIG_POLYFILL_ISNAN) +# define CATCH_CONFIG_POLYFILL_ISNAN #endif -#if defined(CATCH_INTERNAL_CONFIG_CPP11_TUPLE) && !defined(CATCH_CONFIG_CPP11_NO_TUPLE) && !defined(CATCH_CONFIG_CPP11_TUPLE) && !defined(CATCH_CONFIG_NO_CPP11) -# define CATCH_CONFIG_CPP11_TUPLE + +#if defined(CATCH_INTERNAL_CONFIG_USE_ASYNC) && !defined(CATCH_INTERNAL_CONFIG_NO_ASYNC) && !defined(CATCH_CONFIG_NO_USE_ASYNC) && !defined(CATCH_CONFIG_USE_ASYNC) +# define CATCH_CONFIG_USE_ASYNC #endif -#if defined(CATCH_INTERNAL_CONFIG_VARIADIC_MACROS) && !defined(CATCH_CONFIG_NO_VARIADIC_MACROS) && !defined(CATCH_CONFIG_VARIADIC_MACROS) -# define CATCH_CONFIG_VARIADIC_MACROS + +#if defined(CATCH_INTERNAL_CONFIG_ANDROID_LOGWRITE) && !defined(CATCH_CONFIG_NO_ANDROID_LOGWRITE) && !defined(CATCH_CONFIG_ANDROID_LOGWRITE) +# define CATCH_CONFIG_ANDROID_LOGWRITE #endif -#if defined(CATCH_INTERNAL_CONFIG_CPP11_LONG_LONG) && !defined(CATCH_CONFIG_CPP11_NO_LONG_LONG) && !defined(CATCH_CONFIG_CPP11_LONG_LONG) && !defined(CATCH_CONFIG_NO_CPP11) -# define CATCH_CONFIG_CPP11_LONG_LONG + +#if defined(CATCH_INTERNAL_CONFIG_GLOBAL_NEXTAFTER) && !defined(CATCH_CONFIG_NO_GLOBAL_NEXTAFTER) && !defined(CATCH_CONFIG_GLOBAL_NEXTAFTER) +# define CATCH_CONFIG_GLOBAL_NEXTAFTER #endif -#if defined(CATCH_INTERNAL_CONFIG_CPP11_OVERRIDE) && !defined(CATCH_CONFIG_CPP11_NO_OVERRIDE) && !defined(CATCH_CONFIG_CPP11_OVERRIDE) && !defined(CATCH_CONFIG_NO_CPP11) -# define CATCH_CONFIG_CPP11_OVERRIDE + +// Even if we do not think the compiler has that warning, we still have +// to provide a macro that can be used by the code. +#if !defined(CATCH_INTERNAL_START_WARNINGS_SUPPRESSION) +# define CATCH_INTERNAL_START_WARNINGS_SUPPRESSION #endif -#if defined(CATCH_INTERNAL_CONFIG_CPP11_UNIQUE_PTR) && !defined(CATCH_CONFIG_CPP11_NO_UNIQUE_PTR) && !defined(CATCH_CONFIG_CPP11_UNIQUE_PTR) && !defined(CATCH_CONFIG_NO_CPP11) -# define CATCH_CONFIG_CPP11_UNIQUE_PTR +#if !defined(CATCH_INTERNAL_STOP_WARNINGS_SUPPRESSION) +# define CATCH_INTERNAL_STOP_WARNINGS_SUPPRESSION #endif -#if defined(CATCH_INTERNAL_CONFIG_COUNTER) && !defined(CATCH_CONFIG_NO_COUNTER) && !defined(CATCH_CONFIG_COUNTER) -# define CATCH_CONFIG_COUNTER +#if !defined(CATCH_INTERNAL_SUPPRESS_PARENTHESES_WARNINGS) +# define CATCH_INTERNAL_SUPPRESS_PARENTHESES_WARNINGS #endif -#if defined(CATCH_INTERNAL_CONFIG_CPP11_SHUFFLE) && !defined(CATCH_CONFIG_CPP11_NO_SHUFFLE) && !defined(CATCH_CONFIG_CPP11_SHUFFLE) && !defined(CATCH_CONFIG_NO_CPP11) -# define CATCH_CONFIG_CPP11_SHUFFLE +#if !defined(CATCH_INTERNAL_SUPPRESS_GLOBALS_WARNINGS) +# define CATCH_INTERNAL_SUPPRESS_GLOBALS_WARNINGS #endif -# if defined(CATCH_INTERNAL_CONFIG_CPP11_TYPE_TRAITS) && !defined(CATCH_CONFIG_CPP11_NO_TYPE_TRAITS) && !defined(CATCH_CONFIG_CPP11_TYPE_TRAITS) && !defined(CATCH_CONFIG_NO_CPP11) -# define CATCH_CONFIG_CPP11_TYPE_TRAITS -# endif -#if defined(CATCH_INTERNAL_CONFIG_WINDOWS_SEH) && !defined(CATCH_CONFIG_NO_WINDOWS_SEH) && !defined(CATCH_CONFIG_WINDOWS_SEH) -# define CATCH_CONFIG_WINDOWS_SEH +#if !defined(CATCH_INTERNAL_SUPPRESS_UNUSED_WARNINGS) +# define CATCH_INTERNAL_SUPPRESS_UNUSED_WARNINGS #endif -// This is set by default, because we assume that unix compilers are posix-signal-compatible by default. -#if !defined(CATCH_INTERNAL_CONFIG_NO_POSIX_SIGNALS) && !defined(CATCH_CONFIG_NO_POSIX_SIGNALS) && !defined(CATCH_CONFIG_POSIX_SIGNALS) -# define CATCH_CONFIG_POSIX_SIGNALS +#if !defined(CATCH_INTERNAL_SUPPRESS_ZERO_VARIADIC_WARNINGS) +# define CATCH_INTERNAL_SUPPRESS_ZERO_VARIADIC_WARNINGS #endif -#if !defined(CATCH_INTERNAL_SUPPRESS_PARENTHESES_WARNINGS) -# define CATCH_INTERNAL_SUPPRESS_PARENTHESES_WARNINGS -# define CATCH_INTERNAL_UNSUPPRESS_PARENTHESES_WARNINGS -#endif -#if !defined(CATCH_INTERNAL_SUPPRESS_ETD_WARNINGS) -# define CATCH_INTERNAL_SUPPRESS_ETD_WARNINGS -# define CATCH_INTERNAL_UNSUPPRESS_ETD_WARNINGS +// The goal of this macro is to avoid evaluation of the arguments, but +// still have the compiler warn on problems inside... +#if !defined(CATCH_INTERNAL_IGNORE_BUT_WARN) +# define CATCH_INTERNAL_IGNORE_BUT_WARN(...) #endif -// noexcept support: -#if defined(CATCH_CONFIG_CPP11_NOEXCEPT) && !defined(CATCH_NOEXCEPT) -# define CATCH_NOEXCEPT noexcept -# define CATCH_NOEXCEPT_IS(x) noexcept(x) -#else -# define CATCH_NOEXCEPT throw() -# define CATCH_NOEXCEPT_IS(x) +#if defined(__APPLE__) && defined(__apple_build_version__) && (__clang_major__ < 10) +# undef CATCH_INTERNAL_SUPPRESS_UNUSED_TEMPLATE_WARNINGS +#elif defined(__clang__) && (__clang_major__ < 5) +# undef CATCH_INTERNAL_SUPPRESS_UNUSED_TEMPLATE_WARNINGS #endif -// nullptr support -#ifdef CATCH_CONFIG_CPP11_NULLPTR -# define CATCH_NULL nullptr -#else -# define CATCH_NULL NULL +#if !defined(CATCH_INTERNAL_SUPPRESS_UNUSED_TEMPLATE_WARNINGS) +# define CATCH_INTERNAL_SUPPRESS_UNUSED_TEMPLATE_WARNINGS #endif -// override support -#ifdef CATCH_CONFIG_CPP11_OVERRIDE -# define CATCH_OVERRIDE override +#if defined(CATCH_CONFIG_DISABLE_EXCEPTIONS) +#define CATCH_TRY if ((true)) +#define CATCH_CATCH_ALL if ((false)) +#define CATCH_CATCH_ANON(type) if ((false)) #else -# define CATCH_OVERRIDE +#define CATCH_TRY try +#define CATCH_CATCH_ALL catch (...) +#define CATCH_CATCH_ANON(type) catch (type) #endif -// unique_ptr support -#ifdef CATCH_CONFIG_CPP11_UNIQUE_PTR -# define CATCH_AUTO_PTR( T ) std::unique_ptr<T> -#else -# define CATCH_AUTO_PTR( T ) std::auto_ptr<T> +#if defined(CATCH_INTERNAL_CONFIG_TRADITIONAL_MSVC_PREPROCESSOR) && !defined(CATCH_CONFIG_NO_TRADITIONAL_MSVC_PREPROCESSOR) && !defined(CATCH_CONFIG_TRADITIONAL_MSVC_PREPROCESSOR) +#define CATCH_CONFIG_TRADITIONAL_MSVC_PREPROCESSOR #endif +// end catch_compiler_capabilities.h #define INTERNAL_CATCH_UNIQUE_NAME_LINE2( name, line ) name##line #define INTERNAL_CATCH_UNIQUE_NAME_LINE( name, line ) INTERNAL_CATCH_UNIQUE_NAME_LINE2( name, line ) #ifdef CATCH_CONFIG_COUNTER @@ -378,95 +473,48 @@ # define INTERNAL_CATCH_UNIQUE_NAME( name ) INTERNAL_CATCH_UNIQUE_NAME_LINE( name, __LINE__ ) #endif -#define INTERNAL_CATCH_STRINGIFY2( expr ) #expr -#define INTERNAL_CATCH_STRINGIFY( expr ) INTERNAL_CATCH_STRINGIFY2( expr ) +#include <iosfwd> +#include <string> +#include <cstdint> -#include <sstream> -#include <algorithm> +// We need a dummy global operator<< so we can bring it into Catch namespace later +struct Catch_global_namespace_dummy {}; +std::ostream& operator<<(std::ostream&, Catch_global_namespace_dummy); namespace Catch { - struct IConfig; - struct CaseSensitive { enum Choice { Yes, No }; }; class NonCopyable { -#ifdef CATCH_CONFIG_CPP11_GENERATED_METHODS NonCopyable( NonCopyable const& ) = delete; NonCopyable( NonCopyable && ) = delete; NonCopyable& operator = ( NonCopyable const& ) = delete; NonCopyable& operator = ( NonCopyable && ) = delete; -#else - NonCopyable( NonCopyable const& info ); - NonCopyable& operator = ( NonCopyable const& ); -#endif protected: - NonCopyable() {} + NonCopyable(); virtual ~NonCopyable(); }; - class SafeBool { - public: - typedef void (SafeBool::*type)() const; - - static type makeSafe( bool value ) { - return value ? &SafeBool::trueValue : 0; - } - private: - void trueValue() const {} - }; - - template<typename ContainerT> - void deleteAll( ContainerT& container ) { - typename ContainerT::const_iterator it = container.begin(); - typename ContainerT::const_iterator itEnd = container.end(); - for(; it != itEnd; ++it ) - delete *it; - } - template<typename AssociativeContainerT> - void deleteAllValues( AssociativeContainerT& container ) { - typename AssociativeContainerT::const_iterator it = container.begin(); - typename AssociativeContainerT::const_iterator itEnd = container.end(); - for(; it != itEnd; ++it ) - delete it->second; - } - - bool startsWith( std::string const& s, std::string const& prefix ); - bool startsWith( std::string const& s, char prefix ); - bool endsWith( std::string const& s, std::string const& suffix ); - bool endsWith( std::string const& s, char suffix ); - bool contains( std::string const& s, std::string const& infix ); - void toLowerInPlace( std::string& s ); - std::string toLower( std::string const& s ); - std::string trim( std::string const& str ); - bool replaceInPlace( std::string& str, std::string const& replaceThis, std::string const& withThis ); - - struct pluralise { - pluralise( std::size_t count, std::string const& label ); - - friend std::ostream& operator << ( std::ostream& os, pluralise const& pluraliser ); + struct SourceLineInfo { - std::size_t m_count; - std::string m_label; - }; + SourceLineInfo() = delete; + SourceLineInfo( char const* _file, std::size_t _line ) noexcept + : file( _file ), + line( _line ) + {} - struct SourceLineInfo { + SourceLineInfo( SourceLineInfo const& other ) = default; + SourceLineInfo& operator = ( SourceLineInfo const& ) = default; + SourceLineInfo( SourceLineInfo&& ) noexcept = default; + SourceLineInfo& operator = ( SourceLineInfo&& ) noexcept = default; - SourceLineInfo(); - SourceLineInfo( char const* _file, std::size_t _line ); -# ifdef CATCH_CONFIG_CPP11_GENERATED_METHODS - SourceLineInfo(SourceLineInfo const& other) = default; - SourceLineInfo( SourceLineInfo && ) = default; - SourceLineInfo& operator = ( SourceLineInfo const& ) = default; - SourceLineInfo& operator = ( SourceLineInfo && ) = default; -# endif - bool empty() const; - bool operator == ( SourceLineInfo const& other ) const; - bool operator < ( SourceLineInfo const& other ) const; + bool empty() const noexcept { return file[0] == '\0'; } + bool operator == ( SourceLineInfo const& other ) const noexcept; + bool operator < ( SourceLineInfo const& other ) const noexcept; char const* file; std::size_t line; @@ -474,24 +522,17 @@ namespace Catch { std::ostream& operator << ( std::ostream& os, SourceLineInfo const& info ); - // This is just here to avoid compiler warnings with macro constants and boolean literals - inline bool isTrue( bool value ){ return value; } - inline bool alwaysTrue() { return true; } - inline bool alwaysFalse() { return false; } - - void throwLogicError( std::string const& message, SourceLineInfo const& locationInfo ); - - void seedRng( IConfig const& config ); - unsigned int rngSeed(); + // Bring in operator<< from global namespace into Catch namespace + // This is necessary because the overload of operator<< above makes + // lookup stop at namespace Catch + using ::operator<<; // Use this in variadic streaming macros to allow // >> +StreamEndStop // as well as // >> stuff +StreamEndStop struct StreamEndStop { - std::string operator+() { - return std::string(); - } + std::string operator+() const; }; template<typename T> T const& operator + ( T const& value, StreamEndStop ) { @@ -499,363 +540,812 @@ namespace Catch { } } -#define CATCH_INTERNAL_LINEINFO ::Catch::SourceLineInfo( __FILE__, static_cast<std::size_t>( __LINE__ ) ) -#define CATCH_INTERNAL_ERROR( msg ) ::Catch::throwLogicError( msg, CATCH_INTERNAL_LINEINFO ); +#define CATCH_INTERNAL_LINEINFO \ + ::Catch::SourceLineInfo( __FILE__, static_cast<std::size_t>( __LINE__ ) ) +// end catch_common.h namespace Catch { - class NotImplementedException : public std::exception - { - public: - NotImplementedException( SourceLineInfo const& lineInfo ); - - virtual ~NotImplementedException() CATCH_NOEXCEPT {} - - virtual const char* what() const CATCH_NOEXCEPT; - - private: - std::string m_what; - SourceLineInfo m_lineInfo; + struct RegistrarForTagAliases { + RegistrarForTagAliases( char const* alias, char const* tag, SourceLineInfo const& lineInfo ); }; } // end namespace Catch -/////////////////////////////////////////////////////////////////////////////// -#define CATCH_NOT_IMPLEMENTED throw Catch::NotImplementedException( CATCH_INTERNAL_LINEINFO ) +#define CATCH_REGISTER_TAG_ALIAS( alias, spec ) \ + CATCH_INTERNAL_START_WARNINGS_SUPPRESSION \ + CATCH_INTERNAL_SUPPRESS_GLOBALS_WARNINGS \ + namespace{ Catch::RegistrarForTagAliases INTERNAL_CATCH_UNIQUE_NAME( AutoRegisterTagAlias )( alias, spec, CATCH_INTERNAL_LINEINFO ); } \ + CATCH_INTERNAL_STOP_WARNINGS_SUPPRESSION -// #included from: internal/catch_context.h -#define TWOBLUECUBES_CATCH_CONTEXT_H_INCLUDED +// end catch_tag_alias_autoregistrar.h +// start catch_test_registry.h -// #included from: catch_interfaces_generators.h -#define TWOBLUECUBES_CATCH_INTERFACES_GENERATORS_H_INCLUDED +// start catch_interfaces_testcase.h -#include <string> +#include <vector> namespace Catch { - struct IGeneratorInfo { - virtual ~IGeneratorInfo(); - virtual bool moveNext() = 0; - virtual std::size_t getCurrentIndex() const = 0; + class TestSpec; + + struct ITestInvoker { + virtual void invoke () const = 0; + virtual ~ITestInvoker(); }; - struct IGeneratorsForTest { - virtual ~IGeneratorsForTest(); + class TestCase; + struct IConfig; - virtual IGeneratorInfo& getGeneratorInfo( std::string const& fileInfo, std::size_t size ) = 0; - virtual bool moveNext() = 0; + struct ITestCaseRegistry { + virtual ~ITestCaseRegistry(); + virtual std::vector<TestCase> const& getAllTests() const = 0; + virtual std::vector<TestCase> const& getAllTestsSorted( IConfig const& config ) const = 0; }; - IGeneratorsForTest* createGeneratorsForTest(); + bool isThrowSafe( TestCase const& testCase, IConfig const& config ); + bool matchTest( TestCase const& testCase, TestSpec const& testSpec, IConfig const& config ); + std::vector<TestCase> filterTests( std::vector<TestCase> const& testCases, TestSpec const& testSpec, IConfig const& config ); + std::vector<TestCase> const& getAllTestCasesSorted( IConfig const& config ); -} // end namespace Catch +} -// #included from: catch_ptr.hpp -#define TWOBLUECUBES_CATCH_PTR_HPP_INCLUDED +// end catch_interfaces_testcase.h +// start catch_stringref.h -#ifdef __clang__ -#pragma clang diagnostic push -#pragma clang diagnostic ignored "-Wpadded" -#endif +#include <cstddef> +#include <string> +#include <iosfwd> +#include <cassert> namespace Catch { - // An intrusive reference counting smart pointer. - // T must implement addRef() and release() methods - // typically implementing the IShared interface - template<typename T> - class Ptr { + /// A non-owning string class (similar to the forthcoming std::string_view) + /// Note that, because a StringRef may be a substring of another string, + /// it may not be null terminated. + class StringRef { public: - Ptr() : m_p( CATCH_NULL ){} - Ptr( T* p ) : m_p( p ){ - if( m_p ) - m_p->addRef(); - } - Ptr( Ptr const& other ) : m_p( other.m_p ){ - if( m_p ) - m_p->addRef(); - } - ~Ptr(){ - if( m_p ) - m_p->release(); - } - void reset() { - if( m_p ) - m_p->release(); - m_p = CATCH_NULL; - } - Ptr& operator = ( T* p ){ - Ptr temp( p ); - swap( temp ); - return *this; - } - Ptr& operator = ( Ptr const& other ){ - Ptr temp( other ); - swap( temp ); - return *this; - } - void swap( Ptr& other ) { std::swap( m_p, other.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 == CATCH_NULL; } - operator SafeBool::type() const { return SafeBool::makeSafe( m_p != CATCH_NULL ); } + using size_type = std::size_t; + using const_iterator = const char*; private: - T* m_p; - }; + static constexpr char const* const s_empty = ""; - struct IShared : NonCopyable { - virtual ~IShared(); - virtual void addRef() const = 0; - virtual void release() const = 0; - }; + char const* m_start = s_empty; + size_type m_size = 0; + + public: // construction + constexpr StringRef() noexcept = default; - template<typename T = IShared> - struct SharedImpl : T { + StringRef( char const* rawChars ) noexcept; - SharedImpl() : m_rc( 0 ){} + constexpr StringRef( char const* rawChars, size_type size ) noexcept + : m_start( rawChars ), + m_size( size ) + {} + + StringRef( std::string const& stdString ) noexcept + : m_start( stdString.c_str() ), + m_size( stdString.size() ) + {} - virtual void addRef() const { - ++m_rc; + explicit operator std::string() const { + return std::string(m_start, m_size); } - virtual void release() const { - if( --m_rc == 0 ) - delete this; + + public: // operators + auto operator == ( StringRef const& other ) const noexcept -> bool; + auto operator != (StringRef const& other) const noexcept -> bool { + return !(*this == other); } - mutable unsigned int m_rc; - }; + auto operator[] ( size_type index ) const noexcept -> char { + assert(index < m_size); + return m_start[index]; + } -} // end namespace Catch + public: // named queries + constexpr auto empty() const noexcept -> bool { + return m_size == 0; + } + constexpr auto size() const noexcept -> size_type { + return m_size; + } -#ifdef __clang__ -#pragma clang diagnostic pop -#endif + // Returns the current start pointer. If the StringRef is not + // null-terminated, throws std::domain_exception + auto c_str() const -> char const*; -namespace Catch { + public: // substrings and searches + // Returns a substring of [start, start + length). + // If start + length > size(), then the substring is [start, size()). + // If start > size(), then the substring is empty. + auto substr( size_type start, size_type length ) const noexcept -> StringRef; - class TestCase; - class Stream; - struct IResultCapture; - struct IRunner; - struct IGeneratorsForTest; - struct IConfig; + // Returns the current start pointer. May not be null-terminated. + auto data() const noexcept -> char const*; - struct IContext - { - virtual ~IContext(); + constexpr auto isNullTerminated() const noexcept -> bool { + return m_start[m_size] == '\0'; + } - virtual IResultCapture* getResultCapture() = 0; - virtual IRunner* getRunner() = 0; - virtual size_t getGeneratorIndex( std::string const& fileInfo, size_t totalSize ) = 0; - virtual bool advanceGeneratorsForCurrentTest() = 0; - virtual Ptr<IConfig const> getConfig() const = 0; + public: // iterators + constexpr const_iterator begin() const { return m_start; } + constexpr const_iterator end() const { return m_start + m_size; } }; - struct IMutableContext : IContext - { - virtual ~IMutableContext(); - virtual void setResultCapture( IResultCapture* resultCapture ) = 0; - virtual void setRunner( IRunner* runner ) = 0; - virtual void setConfig( Ptr<IConfig const> const& config ) = 0; - }; + auto operator += ( std::string& lhs, StringRef const& sr ) -> std::string&; + auto operator << ( std::ostream& os, StringRef const& sr ) -> std::ostream&; - IContext& getCurrentContext(); - IMutableContext& getCurrentMutableContext(); - void cleanUpContext(); - Stream createStream( std::string const& streamName ); + constexpr auto operator "" _sr( char const* rawChars, std::size_t size ) noexcept -> StringRef { + return StringRef( rawChars, size ); + } +} // namespace Catch +constexpr auto operator "" _catch_sr( char const* rawChars, std::size_t size ) noexcept -> Catch::StringRef { + return Catch::StringRef( rawChars, size ); } -// #included from: internal/catch_test_registry.hpp -#define TWOBLUECUBES_CATCH_TEST_REGISTRY_HPP_INCLUDED +// end catch_stringref.h +// start catch_preprocessor.hpp -// #included from: catch_interfaces_testcase.h -#define TWOBLUECUBES_CATCH_INTERFACES_TESTCASE_H_INCLUDED -#include <vector> +#define CATCH_RECURSION_LEVEL0(...) __VA_ARGS__ +#define CATCH_RECURSION_LEVEL1(...) CATCH_RECURSION_LEVEL0(CATCH_RECURSION_LEVEL0(CATCH_RECURSION_LEVEL0(__VA_ARGS__))) +#define CATCH_RECURSION_LEVEL2(...) CATCH_RECURSION_LEVEL1(CATCH_RECURSION_LEVEL1(CATCH_RECURSION_LEVEL1(__VA_ARGS__))) +#define CATCH_RECURSION_LEVEL3(...) CATCH_RECURSION_LEVEL2(CATCH_RECURSION_LEVEL2(CATCH_RECURSION_LEVEL2(__VA_ARGS__))) +#define CATCH_RECURSION_LEVEL4(...) CATCH_RECURSION_LEVEL3(CATCH_RECURSION_LEVEL3(CATCH_RECURSION_LEVEL3(__VA_ARGS__))) +#define CATCH_RECURSION_LEVEL5(...) CATCH_RECURSION_LEVEL4(CATCH_RECURSION_LEVEL4(CATCH_RECURSION_LEVEL4(__VA_ARGS__))) -namespace Catch { +#ifdef CATCH_CONFIG_TRADITIONAL_MSVC_PREPROCESSOR +#define INTERNAL_CATCH_EXPAND_VARGS(...) __VA_ARGS__ +// MSVC needs more evaluations +#define CATCH_RECURSION_LEVEL6(...) CATCH_RECURSION_LEVEL5(CATCH_RECURSION_LEVEL5(CATCH_RECURSION_LEVEL5(__VA_ARGS__))) +#define CATCH_RECURSE(...) CATCH_RECURSION_LEVEL6(CATCH_RECURSION_LEVEL6(__VA_ARGS__)) +#else +#define CATCH_RECURSE(...) CATCH_RECURSION_LEVEL5(__VA_ARGS__) +#endif - class TestSpec; +#define CATCH_REC_END(...) +#define CATCH_REC_OUT + +#define CATCH_EMPTY() +#define CATCH_DEFER(id) id CATCH_EMPTY() + +#define CATCH_REC_GET_END2() 0, CATCH_REC_END +#define CATCH_REC_GET_END1(...) CATCH_REC_GET_END2 +#define CATCH_REC_GET_END(...) CATCH_REC_GET_END1 +#define CATCH_REC_NEXT0(test, next, ...) next CATCH_REC_OUT +#define CATCH_REC_NEXT1(test, next) CATCH_DEFER ( CATCH_REC_NEXT0 ) ( test, next, 0) +#define CATCH_REC_NEXT(test, next) CATCH_REC_NEXT1(CATCH_REC_GET_END test, next) + +#define CATCH_REC_LIST0(f, x, peek, ...) , f(x) CATCH_DEFER ( CATCH_REC_NEXT(peek, CATCH_REC_LIST1) ) ( f, peek, __VA_ARGS__ ) +#define CATCH_REC_LIST1(f, x, peek, ...) , f(x) CATCH_DEFER ( CATCH_REC_NEXT(peek, CATCH_REC_LIST0) ) ( f, peek, __VA_ARGS__ ) +#define CATCH_REC_LIST2(f, x, peek, ...) f(x) CATCH_DEFER ( CATCH_REC_NEXT(peek, CATCH_REC_LIST1) ) ( f, peek, __VA_ARGS__ ) + +#define CATCH_REC_LIST0_UD(f, userdata, x, peek, ...) , f(userdata, x) CATCH_DEFER ( CATCH_REC_NEXT(peek, CATCH_REC_LIST1_UD) ) ( f, userdata, peek, __VA_ARGS__ ) +#define CATCH_REC_LIST1_UD(f, userdata, x, peek, ...) , f(userdata, x) CATCH_DEFER ( CATCH_REC_NEXT(peek, CATCH_REC_LIST0_UD) ) ( f, userdata, peek, __VA_ARGS__ ) +#define CATCH_REC_LIST2_UD(f, userdata, x, peek, ...) f(userdata, x) CATCH_DEFER ( CATCH_REC_NEXT(peek, CATCH_REC_LIST1_UD) ) ( f, userdata, peek, __VA_ARGS__ ) + +// Applies the function macro `f` to each of the remaining parameters, inserts commas between the results, +// and passes userdata as the first parameter to each invocation, +// e.g. CATCH_REC_LIST_UD(f, x, a, b, c) evaluates to f(x, a), f(x, b), f(x, c) +#define CATCH_REC_LIST_UD(f, userdata, ...) CATCH_RECURSE(CATCH_REC_LIST2_UD(f, userdata, __VA_ARGS__, ()()(), ()()(), ()()(), 0)) + +#define CATCH_REC_LIST(f, ...) CATCH_RECURSE(CATCH_REC_LIST2(f, __VA_ARGS__, ()()(), ()()(), ()()(), 0)) + +#define INTERNAL_CATCH_EXPAND1(param) INTERNAL_CATCH_EXPAND2(param) +#define INTERNAL_CATCH_EXPAND2(...) INTERNAL_CATCH_NO## __VA_ARGS__ +#define INTERNAL_CATCH_DEF(...) INTERNAL_CATCH_DEF __VA_ARGS__ +#define INTERNAL_CATCH_NOINTERNAL_CATCH_DEF +#define INTERNAL_CATCH_STRINGIZE(...) INTERNAL_CATCH_STRINGIZE2(__VA_ARGS__) +#ifndef CATCH_CONFIG_TRADITIONAL_MSVC_PREPROCESSOR +#define INTERNAL_CATCH_STRINGIZE2(...) #__VA_ARGS__ +#define INTERNAL_CATCH_STRINGIZE_WITHOUT_PARENS(param) INTERNAL_CATCH_STRINGIZE(INTERNAL_CATCH_REMOVE_PARENS(param)) +#else +// MSVC is adding extra space and needs another indirection to expand INTERNAL_CATCH_NOINTERNAL_CATCH_DEF +#define INTERNAL_CATCH_STRINGIZE2(...) INTERNAL_CATCH_STRINGIZE3(__VA_ARGS__) +#define INTERNAL_CATCH_STRINGIZE3(...) #__VA_ARGS__ +#define INTERNAL_CATCH_STRINGIZE_WITHOUT_PARENS(param) (INTERNAL_CATCH_STRINGIZE(INTERNAL_CATCH_REMOVE_PARENS(param)) + 1) +#endif - struct ITestCase : IShared { - virtual void invoke () const = 0; - protected: - virtual ~ITestCase(); - }; +#define INTERNAL_CATCH_MAKE_NAMESPACE2(...) ns_##__VA_ARGS__ +#define INTERNAL_CATCH_MAKE_NAMESPACE(name) INTERNAL_CATCH_MAKE_NAMESPACE2(name) - class TestCase; - struct IConfig; +#define INTERNAL_CATCH_REMOVE_PARENS(...) INTERNAL_CATCH_EXPAND1(INTERNAL_CATCH_DEF __VA_ARGS__) - struct ITestCaseRegistry { - virtual ~ITestCaseRegistry(); - virtual std::vector<TestCase> const& getAllTests() const = 0; - virtual std::vector<TestCase> const& getAllTestsSorted( IConfig const& config ) const = 0; +#ifndef CATCH_CONFIG_TRADITIONAL_MSVC_PREPROCESSOR +#define INTERNAL_CATCH_MAKE_TYPE_LIST2(...) decltype(get_wrapper<INTERNAL_CATCH_REMOVE_PARENS_GEN(__VA_ARGS__)>()) +#define INTERNAL_CATCH_MAKE_TYPE_LIST(...) INTERNAL_CATCH_MAKE_TYPE_LIST2(INTERNAL_CATCH_REMOVE_PARENS(__VA_ARGS__)) +#else +#define INTERNAL_CATCH_MAKE_TYPE_LIST2(...) INTERNAL_CATCH_EXPAND_VARGS(decltype(get_wrapper<INTERNAL_CATCH_REMOVE_PARENS_GEN(__VA_ARGS__)>())) +#define INTERNAL_CATCH_MAKE_TYPE_LIST(...) INTERNAL_CATCH_EXPAND_VARGS(INTERNAL_CATCH_MAKE_TYPE_LIST2(INTERNAL_CATCH_REMOVE_PARENS(__VA_ARGS__))) +#endif + +#define INTERNAL_CATCH_MAKE_TYPE_LISTS_FROM_TYPES(...)\ + CATCH_REC_LIST(INTERNAL_CATCH_MAKE_TYPE_LIST,__VA_ARGS__) + +#define INTERNAL_CATCH_REMOVE_PARENS_1_ARG(_0) INTERNAL_CATCH_REMOVE_PARENS(_0) +#define INTERNAL_CATCH_REMOVE_PARENS_2_ARG(_0, _1) INTERNAL_CATCH_REMOVE_PARENS(_0), INTERNAL_CATCH_REMOVE_PARENS_1_ARG(_1) +#define INTERNAL_CATCH_REMOVE_PARENS_3_ARG(_0, _1, _2) INTERNAL_CATCH_REMOVE_PARENS(_0), INTERNAL_CATCH_REMOVE_PARENS_2_ARG(_1, _2) +#define INTERNAL_CATCH_REMOVE_PARENS_4_ARG(_0, _1, _2, _3) INTERNAL_CATCH_REMOVE_PARENS(_0), INTERNAL_CATCH_REMOVE_PARENS_3_ARG(_1, _2, _3) +#define INTERNAL_CATCH_REMOVE_PARENS_5_ARG(_0, _1, _2, _3, _4) INTERNAL_CATCH_REMOVE_PARENS(_0), INTERNAL_CATCH_REMOVE_PARENS_4_ARG(_1, _2, _3, _4) +#define INTERNAL_CATCH_REMOVE_PARENS_6_ARG(_0, _1, _2, _3, _4, _5) INTERNAL_CATCH_REMOVE_PARENS(_0), INTERNAL_CATCH_REMOVE_PARENS_5_ARG(_1, _2, _3, _4, _5) +#define INTERNAL_CATCH_REMOVE_PARENS_7_ARG(_0, _1, _2, _3, _4, _5, _6) INTERNAL_CATCH_REMOVE_PARENS(_0), INTERNAL_CATCH_REMOVE_PARENS_6_ARG(_1, _2, _3, _4, _5, _6) +#define INTERNAL_CATCH_REMOVE_PARENS_8_ARG(_0, _1, _2, _3, _4, _5, _6, _7) INTERNAL_CATCH_REMOVE_PARENS(_0), INTERNAL_CATCH_REMOVE_PARENS_7_ARG(_1, _2, _3, _4, _5, _6, _7) +#define INTERNAL_CATCH_REMOVE_PARENS_9_ARG(_0, _1, _2, _3, _4, _5, _6, _7, _8) INTERNAL_CATCH_REMOVE_PARENS(_0), INTERNAL_CATCH_REMOVE_PARENS_8_ARG(_1, _2, _3, _4, _5, _6, _7, _8) +#define INTERNAL_CATCH_REMOVE_PARENS_10_ARG(_0, _1, _2, _3, _4, _5, _6, _7, _8, _9) INTERNAL_CATCH_REMOVE_PARENS(_0), INTERNAL_CATCH_REMOVE_PARENS_9_ARG(_1, _2, _3, _4, _5, _6, _7, _8, _9) +#define INTERNAL_CATCH_REMOVE_PARENS_11_ARG(_0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10) INTERNAL_CATCH_REMOVE_PARENS(_0), INTERNAL_CATCH_REMOVE_PARENS_10_ARG(_1, _2, _3, _4, _5, _6, _7, _8, _9, _10) + +#define INTERNAL_CATCH_VA_NARGS_IMPL(_0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, N, ...) N + +#define INTERNAL_CATCH_TYPE_GEN\ + template<typename...> struct TypeList {};\ + template<typename...Ts>\ + constexpr auto get_wrapper() noexcept -> TypeList<Ts...> { return {}; }\ + template<template<typename...> class...> struct TemplateTypeList{};\ + template<template<typename...> class...Cs>\ + constexpr auto get_wrapper() noexcept -> TemplateTypeList<Cs...> { return {}; }\ + template<typename...>\ + struct append;\ + template<typename...>\ + struct rewrap;\ + template<template<typename...> class, typename...>\ + struct create;\ + template<template<typename...> class, typename>\ + struct convert;\ + \ + template<typename T> \ + struct append<T> { using type = T; };\ + template< template<typename...> class L1, typename...E1, template<typename...> class L2, typename...E2, typename...Rest>\ + struct append<L1<E1...>, L2<E2...>, Rest...> { using type = typename append<L1<E1...,E2...>, Rest...>::type; };\ + template< template<typename...> class L1, typename...E1, typename...Rest>\ + struct append<L1<E1...>, TypeList<mpl_::na>, Rest...> { using type = L1<E1...>; };\ + \ + template< template<typename...> class Container, template<typename...> class List, typename...elems>\ + struct rewrap<TemplateTypeList<Container>, List<elems...>> { using type = TypeList<Container<elems...>>; };\ + template< template<typename...> class Container, template<typename...> class List, class...Elems, typename...Elements>\ + struct rewrap<TemplateTypeList<Container>, List<Elems...>, Elements...> { using type = typename append<TypeList<Container<Elems...>>, typename rewrap<TemplateTypeList<Container>, Elements...>::type>::type; };\ + \ + template<template <typename...> class Final, template< typename...> class...Containers, typename...Types>\ + struct create<Final, TemplateTypeList<Containers...>, TypeList<Types...>> { using type = typename append<Final<>, typename rewrap<TemplateTypeList<Containers>, Types...>::type...>::type; };\ + template<template <typename...> class Final, template <typename...> class List, typename...Ts>\ + struct convert<Final, List<Ts...>> { using type = typename append<Final<>,TypeList<Ts>...>::type; }; + +#define INTERNAL_CATCH_NTTP_1(signature, ...)\ + template<INTERNAL_CATCH_REMOVE_PARENS(signature)> struct Nttp{};\ + template<INTERNAL_CATCH_REMOVE_PARENS(signature)>\ + constexpr auto get_wrapper() noexcept -> Nttp<__VA_ARGS__> { return {}; } \ + template<template<INTERNAL_CATCH_REMOVE_PARENS(signature)> class...> struct NttpTemplateTypeList{};\ + template<template<INTERNAL_CATCH_REMOVE_PARENS(signature)> class...Cs>\ + constexpr auto get_wrapper() noexcept -> NttpTemplateTypeList<Cs...> { return {}; } \ + \ + template< template<INTERNAL_CATCH_REMOVE_PARENS(signature)> class Container, template<INTERNAL_CATCH_REMOVE_PARENS(signature)> class List, INTERNAL_CATCH_REMOVE_PARENS(signature)>\ + struct rewrap<NttpTemplateTypeList<Container>, List<__VA_ARGS__>> { using type = TypeList<Container<__VA_ARGS__>>; };\ + template< template<INTERNAL_CATCH_REMOVE_PARENS(signature)> class Container, template<INTERNAL_CATCH_REMOVE_PARENS(signature)> class List, INTERNAL_CATCH_REMOVE_PARENS(signature), typename...Elements>\ + struct rewrap<NttpTemplateTypeList<Container>, List<__VA_ARGS__>, Elements...> { using type = typename append<TypeList<Container<__VA_ARGS__>>, typename rewrap<NttpTemplateTypeList<Container>, Elements...>::type>::type; };\ + template<template <typename...> class Final, template<INTERNAL_CATCH_REMOVE_PARENS(signature)> class...Containers, typename...Types>\ + struct create<Final, NttpTemplateTypeList<Containers...>, TypeList<Types...>> { using type = typename append<Final<>, typename rewrap<NttpTemplateTypeList<Containers>, Types...>::type...>::type; }; + +#define INTERNAL_CATCH_DECLARE_SIG_TEST0(TestName) +#define INTERNAL_CATCH_DECLARE_SIG_TEST1(TestName, signature)\ + template<INTERNAL_CATCH_REMOVE_PARENS(signature)>\ + static void TestName() +#define INTERNAL_CATCH_DECLARE_SIG_TEST_X(TestName, signature, ...)\ + template<INTERNAL_CATCH_REMOVE_PARENS(signature)>\ + static void TestName() + +#define INTERNAL_CATCH_DEFINE_SIG_TEST0(TestName) +#define INTERNAL_CATCH_DEFINE_SIG_TEST1(TestName, signature)\ + template<INTERNAL_CATCH_REMOVE_PARENS(signature)>\ + static void TestName() +#define INTERNAL_CATCH_DEFINE_SIG_TEST_X(TestName, signature,...)\ + template<INTERNAL_CATCH_REMOVE_PARENS(signature)>\ + static void TestName() + +#define INTERNAL_CATCH_NTTP_REGISTER0(TestFunc, signature)\ + template<typename Type>\ + void reg_test(TypeList<Type>, Catch::NameAndTags nameAndTags)\ + {\ + Catch::AutoReg( Catch::makeTestInvoker(&TestFunc<Type>), CATCH_INTERNAL_LINEINFO, Catch::StringRef(), nameAndTags);\ + } + +#define INTERNAL_CATCH_NTTP_REGISTER(TestFunc, signature, ...)\ + template<INTERNAL_CATCH_REMOVE_PARENS(signature)>\ + void reg_test(Nttp<__VA_ARGS__>, Catch::NameAndTags nameAndTags)\ + {\ + Catch::AutoReg( Catch::makeTestInvoker(&TestFunc<__VA_ARGS__>), CATCH_INTERNAL_LINEINFO, Catch::StringRef(), nameAndTags);\ + } + +#define INTERNAL_CATCH_NTTP_REGISTER_METHOD0(TestName, signature, ...)\ + template<typename Type>\ + void reg_test(TypeList<Type>, Catch::StringRef className, Catch::NameAndTags nameAndTags)\ + {\ + Catch::AutoReg( Catch::makeTestInvoker(&TestName<Type>::test), CATCH_INTERNAL_LINEINFO, className, nameAndTags);\ + } + +#define INTERNAL_CATCH_NTTP_REGISTER_METHOD(TestName, signature, ...)\ + template<INTERNAL_CATCH_REMOVE_PARENS(signature)>\ + void reg_test(Nttp<__VA_ARGS__>, Catch::StringRef className, Catch::NameAndTags nameAndTags)\ + {\ + Catch::AutoReg( Catch::makeTestInvoker(&TestName<__VA_ARGS__>::test), CATCH_INTERNAL_LINEINFO, className, nameAndTags);\ + } + +#define INTERNAL_CATCH_DECLARE_SIG_TEST_METHOD0(TestName, ClassName) +#define INTERNAL_CATCH_DECLARE_SIG_TEST_METHOD1(TestName, ClassName, signature)\ + template<typename TestType> \ + struct TestName : INTERNAL_CATCH_REMOVE_PARENS(ClassName)<TestType> { \ + void test();\ + } + +#define INTERNAL_CATCH_DECLARE_SIG_TEST_METHOD_X(TestName, ClassName, signature, ...)\ + template<INTERNAL_CATCH_REMOVE_PARENS(signature)> \ + struct TestName : INTERNAL_CATCH_REMOVE_PARENS(ClassName)<__VA_ARGS__> { \ + void test();\ + } + +#define INTERNAL_CATCH_DEFINE_SIG_TEST_METHOD0(TestName) +#define INTERNAL_CATCH_DEFINE_SIG_TEST_METHOD1(TestName, signature)\ + template<typename TestType> \ + void INTERNAL_CATCH_MAKE_NAMESPACE(TestName)::TestName<TestType>::test() +#define INTERNAL_CATCH_DEFINE_SIG_TEST_METHOD_X(TestName, signature, ...)\ + template<INTERNAL_CATCH_REMOVE_PARENS(signature)> \ + void INTERNAL_CATCH_MAKE_NAMESPACE(TestName)::TestName<__VA_ARGS__>::test() + +#ifndef CATCH_CONFIG_TRADITIONAL_MSVC_PREPROCESSOR +#define INTERNAL_CATCH_NTTP_0 +#define INTERNAL_CATCH_NTTP_GEN(...) INTERNAL_CATCH_VA_NARGS_IMPL(__VA_ARGS__, INTERNAL_CATCH_NTTP_1(__VA_ARGS__), INTERNAL_CATCH_NTTP_1(__VA_ARGS__), INTERNAL_CATCH_NTTP_1(__VA_ARGS__), INTERNAL_CATCH_NTTP_1(__VA_ARGS__), INTERNAL_CATCH_NTTP_1(__VA_ARGS__), INTERNAL_CATCH_NTTP_1( __VA_ARGS__), INTERNAL_CATCH_NTTP_1( __VA_ARGS__), INTERNAL_CATCH_NTTP_1( __VA_ARGS__), INTERNAL_CATCH_NTTP_1( __VA_ARGS__),INTERNAL_CATCH_NTTP_1( __VA_ARGS__), INTERNAL_CATCH_NTTP_0) +#define INTERNAL_CATCH_DEFINE_SIG_TEST_METHOD(TestName, ...) INTERNAL_CATCH_VA_NARGS_IMPL( "dummy", __VA_ARGS__, INTERNAL_CATCH_DEFINE_SIG_TEST_METHOD_X,INTERNAL_CATCH_DEFINE_SIG_TEST_METHOD_X, INTERNAL_CATCH_DEFINE_SIG_TEST_METHOD_X, INTERNAL_CATCH_DEFINE_SIG_TEST_METHOD_X, INTERNAL_CATCH_DEFINE_SIG_TEST_METHOD_X, INTERNAL_CATCH_DEFINE_SIG_TEST_METHOD_X, INTERNAL_CATCH_DEFINE_SIG_TEST_METHOD_X,INTERNAL_CATCH_DEFINE_SIG_TEST_METHOD_X,INTERNAL_CATCH_DEFINE_SIG_TEST_METHOD_X, INTERNAL_CATCH_DEFINE_SIG_TEST_METHOD1, INTERNAL_CATCH_DEFINE_SIG_TEST_METHOD0)(TestName, __VA_ARGS__) +#define INTERNAL_CATCH_DECLARE_SIG_TEST_METHOD(TestName, ClassName, ...) INTERNAL_CATCH_VA_NARGS_IMPL( "dummy", __VA_ARGS__, INTERNAL_CATCH_DECLARE_SIG_TEST_METHOD_X,INTERNAL_CATCH_DECLARE_SIG_TEST_METHOD_X, INTERNAL_CATCH_DECLARE_SIG_TEST_METHOD_X, INTERNAL_CATCH_DECLARE_SIG_TEST_METHOD_X, INTERNAL_CATCH_DECLARE_SIG_TEST_METHOD_X, INTERNAL_CATCH_DECLARE_SIG_TEST_METHOD_X, INTERNAL_CATCH_DECLARE_SIG_TEST_METHOD_X,INTERNAL_CATCH_DECLARE_SIG_TEST_METHOD_X,INTERNAL_CATCH_DECLARE_SIG_TEST_METHOD_X, INTERNAL_CATCH_DECLARE_SIG_TEST_METHOD1, INTERNAL_CATCH_DECLARE_SIG_TEST_METHOD0)(TestName, ClassName, __VA_ARGS__) +#define INTERNAL_CATCH_NTTP_REG_METHOD_GEN(TestName, ...) INTERNAL_CATCH_VA_NARGS_IMPL( "dummy", __VA_ARGS__, INTERNAL_CATCH_NTTP_REGISTER_METHOD, INTERNAL_CATCH_NTTP_REGISTER_METHOD, INTERNAL_CATCH_NTTP_REGISTER_METHOD, INTERNAL_CATCH_NTTP_REGISTER_METHOD, INTERNAL_CATCH_NTTP_REGISTER_METHOD, INTERNAL_CATCH_NTTP_REGISTER_METHOD, INTERNAL_CATCH_NTTP_REGISTER_METHOD, INTERNAL_CATCH_NTTP_REGISTER_METHOD, INTERNAL_CATCH_NTTP_REGISTER_METHOD, INTERNAL_CATCH_NTTP_REGISTER_METHOD0, INTERNAL_CATCH_NTTP_REGISTER_METHOD0)(TestName, __VA_ARGS__) +#define INTERNAL_CATCH_NTTP_REG_GEN(TestFunc, ...) INTERNAL_CATCH_VA_NARGS_IMPL( "dummy", __VA_ARGS__, INTERNAL_CATCH_NTTP_REGISTER, INTERNAL_CATCH_NTTP_REGISTER, INTERNAL_CATCH_NTTP_REGISTER, INTERNAL_CATCH_NTTP_REGISTER, INTERNAL_CATCH_NTTP_REGISTER, INTERNAL_CATCH_NTTP_REGISTER, INTERNAL_CATCH_NTTP_REGISTER, INTERNAL_CATCH_NTTP_REGISTER, INTERNAL_CATCH_NTTP_REGISTER, INTERNAL_CATCH_NTTP_REGISTER0, INTERNAL_CATCH_NTTP_REGISTER0)(TestFunc, __VA_ARGS__) +#define INTERNAL_CATCH_DEFINE_SIG_TEST(TestName, ...) INTERNAL_CATCH_VA_NARGS_IMPL( "dummy", __VA_ARGS__, INTERNAL_CATCH_DEFINE_SIG_TEST_X, INTERNAL_CATCH_DEFINE_SIG_TEST_X, INTERNAL_CATCH_DEFINE_SIG_TEST_X, INTERNAL_CATCH_DEFINE_SIG_TEST_X, INTERNAL_CATCH_DEFINE_SIG_TEST_X, INTERNAL_CATCH_DEFINE_SIG_TEST_X, INTERNAL_CATCH_DEFINE_SIG_TEST_X, INTERNAL_CATCH_DEFINE_SIG_TEST_X,INTERNAL_CATCH_DEFINE_SIG_TEST_X,INTERNAL_CATCH_DEFINE_SIG_TEST1, INTERNAL_CATCH_DEFINE_SIG_TEST0)(TestName, __VA_ARGS__) +#define INTERNAL_CATCH_DECLARE_SIG_TEST(TestName, ...) INTERNAL_CATCH_VA_NARGS_IMPL( "dummy", __VA_ARGS__, INTERNAL_CATCH_DECLARE_SIG_TEST_X,INTERNAL_CATCH_DECLARE_SIG_TEST_X, INTERNAL_CATCH_DECLARE_SIG_TEST_X, INTERNAL_CATCH_DECLARE_SIG_TEST_X, INTERNAL_CATCH_DECLARE_SIG_TEST_X, INTERNAL_CATCH_DECLARE_SIG_TEST_X, INTERNAL_CATCH_DEFINE_SIG_TEST_X,INTERNAL_CATCH_DECLARE_SIG_TEST_X,INTERNAL_CATCH_DECLARE_SIG_TEST_X, INTERNAL_CATCH_DECLARE_SIG_TEST1, INTERNAL_CATCH_DECLARE_SIG_TEST0)(TestName, __VA_ARGS__) +#define INTERNAL_CATCH_REMOVE_PARENS_GEN(...) INTERNAL_CATCH_VA_NARGS_IMPL(__VA_ARGS__, INTERNAL_CATCH_REMOVE_PARENS_11_ARG,INTERNAL_CATCH_REMOVE_PARENS_10_ARG,INTERNAL_CATCH_REMOVE_PARENS_9_ARG,INTERNAL_CATCH_REMOVE_PARENS_8_ARG,INTERNAL_CATCH_REMOVE_PARENS_7_ARG,INTERNAL_CATCH_REMOVE_PARENS_6_ARG,INTERNAL_CATCH_REMOVE_PARENS_5_ARG,INTERNAL_CATCH_REMOVE_PARENS_4_ARG,INTERNAL_CATCH_REMOVE_PARENS_3_ARG,INTERNAL_CATCH_REMOVE_PARENS_2_ARG,INTERNAL_CATCH_REMOVE_PARENS_1_ARG)(__VA_ARGS__) +#else +#define INTERNAL_CATCH_NTTP_0(signature) +#define INTERNAL_CATCH_NTTP_GEN(...) INTERNAL_CATCH_EXPAND_VARGS(INTERNAL_CATCH_VA_NARGS_IMPL(__VA_ARGS__, INTERNAL_CATCH_NTTP_1, INTERNAL_CATCH_NTTP_1, INTERNAL_CATCH_NTTP_1, INTERNAL_CATCH_NTTP_1, INTERNAL_CATCH_NTTP_1, INTERNAL_CATCH_NTTP_1, INTERNAL_CATCH_NTTP_1, INTERNAL_CATCH_NTTP_1, INTERNAL_CATCH_NTTP_1,INTERNAL_CATCH_NTTP_1, INTERNAL_CATCH_NTTP_0)( __VA_ARGS__)) +#define INTERNAL_CATCH_DEFINE_SIG_TEST_METHOD(TestName, ...) INTERNAL_CATCH_EXPAND_VARGS(INTERNAL_CATCH_VA_NARGS_IMPL( "dummy", __VA_ARGS__, INTERNAL_CATCH_DEFINE_SIG_TEST_METHOD_X,INTERNAL_CATCH_DEFINE_SIG_TEST_METHOD_X, INTERNAL_CATCH_DEFINE_SIG_TEST_METHOD_X, INTERNAL_CATCH_DEFINE_SIG_TEST_METHOD_X, INTERNAL_CATCH_DEFINE_SIG_TEST_METHOD_X, INTERNAL_CATCH_DEFINE_SIG_TEST_METHOD_X, INTERNAL_CATCH_DEFINE_SIG_TEST_METHOD_X,INTERNAL_CATCH_DEFINE_SIG_TEST_METHOD_X,INTERNAL_CATCH_DEFINE_SIG_TEST_METHOD_X, INTERNAL_CATCH_DEFINE_SIG_TEST_METHOD1, INTERNAL_CATCH_DEFINE_SIG_TEST_METHOD0)(TestName, __VA_ARGS__)) +#define INTERNAL_CATCH_DECLARE_SIG_TEST_METHOD(TestName, ClassName, ...) INTERNAL_CATCH_EXPAND_VARGS(INTERNAL_CATCH_VA_NARGS_IMPL( "dummy", __VA_ARGS__, INTERNAL_CATCH_DECLARE_SIG_TEST_METHOD_X,INTERNAL_CATCH_DECLARE_SIG_TEST_METHOD_X, INTERNAL_CATCH_DECLARE_SIG_TEST_METHOD_X, INTERNAL_CATCH_DECLARE_SIG_TEST_METHOD_X, INTERNAL_CATCH_DECLARE_SIG_TEST_METHOD_X, INTERNAL_CATCH_DECLARE_SIG_TEST_METHOD_X, INTERNAL_CATCH_DECLARE_SIG_TEST_METHOD_X,INTERNAL_CATCH_DECLARE_SIG_TEST_METHOD_X,INTERNAL_CATCH_DECLARE_SIG_TEST_METHOD_X, INTERNAL_CATCH_DECLARE_SIG_TEST_METHOD1, INTERNAL_CATCH_DECLARE_SIG_TEST_METHOD0)(TestName, ClassName, __VA_ARGS__)) +#define INTERNAL_CATCH_NTTP_REG_METHOD_GEN(TestName, ...) INTERNAL_CATCH_EXPAND_VARGS(INTERNAL_CATCH_VA_NARGS_IMPL( "dummy", __VA_ARGS__, INTERNAL_CATCH_NTTP_REGISTER_METHOD, INTERNAL_CATCH_NTTP_REGISTER_METHOD, INTERNAL_CATCH_NTTP_REGISTER_METHOD, INTERNAL_CATCH_NTTP_REGISTER_METHOD, INTERNAL_CATCH_NTTP_REGISTER_METHOD, INTERNAL_CATCH_NTTP_REGISTER_METHOD, INTERNAL_CATCH_NTTP_REGISTER_METHOD, INTERNAL_CATCH_NTTP_REGISTER_METHOD, INTERNAL_CATCH_NTTP_REGISTER_METHOD, INTERNAL_CATCH_NTTP_REGISTER_METHOD0, INTERNAL_CATCH_NTTP_REGISTER_METHOD0)(TestName, __VA_ARGS__)) +#define INTERNAL_CATCH_NTTP_REG_GEN(TestFunc, ...) INTERNAL_CATCH_EXPAND_VARGS(INTERNAL_CATCH_VA_NARGS_IMPL( "dummy", __VA_ARGS__, INTERNAL_CATCH_NTTP_REGISTER, INTERNAL_CATCH_NTTP_REGISTER, INTERNAL_CATCH_NTTP_REGISTER, INTERNAL_CATCH_NTTP_REGISTER, INTERNAL_CATCH_NTTP_REGISTER, INTERNAL_CATCH_NTTP_REGISTER, INTERNAL_CATCH_NTTP_REGISTER, INTERNAL_CATCH_NTTP_REGISTER, INTERNAL_CATCH_NTTP_REGISTER, INTERNAL_CATCH_NTTP_REGISTER0, INTERNAL_CATCH_NTTP_REGISTER0)(TestFunc, __VA_ARGS__)) +#define INTERNAL_CATCH_DEFINE_SIG_TEST(TestName, ...) INTERNAL_CATCH_EXPAND_VARGS(INTERNAL_CATCH_VA_NARGS_IMPL( "dummy", __VA_ARGS__, INTERNAL_CATCH_DEFINE_SIG_TEST_X, INTERNAL_CATCH_DEFINE_SIG_TEST_X, INTERNAL_CATCH_DEFINE_SIG_TEST_X, INTERNAL_CATCH_DEFINE_SIG_TEST_X, INTERNAL_CATCH_DEFINE_SIG_TEST_X, INTERNAL_CATCH_DEFINE_SIG_TEST_X, INTERNAL_CATCH_DEFINE_SIG_TEST_X, INTERNAL_CATCH_DEFINE_SIG_TEST_X,INTERNAL_CATCH_DEFINE_SIG_TEST_X,INTERNAL_CATCH_DEFINE_SIG_TEST1, INTERNAL_CATCH_DEFINE_SIG_TEST0)(TestName, __VA_ARGS__)) +#define INTERNAL_CATCH_DECLARE_SIG_TEST(TestName, ...) INTERNAL_CATCH_EXPAND_VARGS(INTERNAL_CATCH_VA_NARGS_IMPL( "dummy", __VA_ARGS__, INTERNAL_CATCH_DECLARE_SIG_TEST_X,INTERNAL_CATCH_DECLARE_SIG_TEST_X, INTERNAL_CATCH_DECLARE_SIG_TEST_X, INTERNAL_CATCH_DECLARE_SIG_TEST_X, INTERNAL_CATCH_DECLARE_SIG_TEST_X, INTERNAL_CATCH_DECLARE_SIG_TEST_X, INTERNAL_CATCH_DEFINE_SIG_TEST_X,INTERNAL_CATCH_DECLARE_SIG_TEST_X,INTERNAL_CATCH_DECLARE_SIG_TEST_X, INTERNAL_CATCH_DECLARE_SIG_TEST1, INTERNAL_CATCH_DECLARE_SIG_TEST0)(TestName, __VA_ARGS__)) +#define INTERNAL_CATCH_REMOVE_PARENS_GEN(...) INTERNAL_CATCH_EXPAND_VARGS(INTERNAL_CATCH_VA_NARGS_IMPL(__VA_ARGS__, INTERNAL_CATCH_REMOVE_PARENS_11_ARG,INTERNAL_CATCH_REMOVE_PARENS_10_ARG,INTERNAL_CATCH_REMOVE_PARENS_9_ARG,INTERNAL_CATCH_REMOVE_PARENS_8_ARG,INTERNAL_CATCH_REMOVE_PARENS_7_ARG,INTERNAL_CATCH_REMOVE_PARENS_6_ARG,INTERNAL_CATCH_REMOVE_PARENS_5_ARG,INTERNAL_CATCH_REMOVE_PARENS_4_ARG,INTERNAL_CATCH_REMOVE_PARENS_3_ARG,INTERNAL_CATCH_REMOVE_PARENS_2_ARG,INTERNAL_CATCH_REMOVE_PARENS_1_ARG)(__VA_ARGS__)) +#endif + +// end catch_preprocessor.hpp +// start catch_meta.hpp + + +#include <type_traits> + +namespace Catch { + template<typename T> + struct always_false : std::false_type {}; + + template <typename> struct true_given : std::true_type {}; + struct is_callable_tester { + template <typename Fun, typename... Args> + true_given<decltype(std::declval<Fun>()(std::declval<Args>()...))> static test(int); + template <typename...> + std::false_type static test(...); }; - bool matchTest( TestCase const& testCase, TestSpec const& testSpec, IConfig const& config ); - std::vector<TestCase> filterTests( std::vector<TestCase> const& testCases, TestSpec const& testSpec, IConfig const& config ); - std::vector<TestCase> const& getAllTestCasesSorted( IConfig const& config ); + template <typename T> + struct is_callable; + + template <typename Fun, typename... Args> + struct is_callable<Fun(Args...)> : decltype(is_callable_tester::test<Fun, Args...>(0)) {}; + +#if defined(__cpp_lib_is_invocable) && __cpp_lib_is_invocable >= 201703 + // std::result_of is deprecated in C++17 and removed in C++20. Hence, it is + // replaced with std::invoke_result here. + template <typename Func, typename... U> + using FunctionReturnType = std::remove_reference_t<std::remove_cv_t<std::invoke_result_t<Func, U...>>>; +#else + // Keep ::type here because we still support C++11 + template <typename Func, typename... U> + using FunctionReturnType = typename std::remove_reference<typename std::remove_cv<typename std::result_of<Func(U...)>::type>::type>::type; +#endif + +} // namespace Catch +namespace mpl_{ + struct na; } +// end catch_meta.hpp namespace Catch { template<typename C> -class MethodTestCase : public SharedImpl<ITestCase> { - +class TestInvokerAsMethod : public ITestInvoker { + void (C::*m_testAsMethod)(); public: - MethodTestCase( void (C::*method)() ) : m_method( method ) {} + TestInvokerAsMethod( void (C::*testAsMethod)() ) noexcept : m_testAsMethod( testAsMethod ) {} - virtual void invoke() const { + void invoke() const override { C obj; - (obj.*m_method)(); + (obj.*m_testAsMethod)(); } - -private: - virtual ~MethodTestCase() {} - - void (C::*m_method)(); }; -typedef void(*TestFunction)(); +auto makeTestInvoker( void(*testAsFunction)() ) noexcept -> ITestInvoker*; -struct NameAndDesc { - NameAndDesc( const char* _name = "", const char* _description= "" ) - : name( _name ), description( _description ) - {} +template<typename C> +auto makeTestInvoker( void (C::*testAsMethod)() ) noexcept -> ITestInvoker* { + return new(std::nothrow) TestInvokerAsMethod<C>( testAsMethod ); +} - const char* name; - const char* description; +struct NameAndTags { + NameAndTags( StringRef const& name_ = StringRef(), StringRef const& tags_ = StringRef() ) noexcept; + StringRef name; + StringRef tags; }; -void registerTestCase - ( ITestCase* testCase, - char const* className, - NameAndDesc const& nameAndDesc, - SourceLineInfo const& lineInfo ); - -struct AutoReg { - - AutoReg - ( TestFunction function, - SourceLineInfo const& lineInfo, - NameAndDesc const& nameAndDesc ); - - template<typename C> - AutoReg - ( void (C::*method)(), - char const* className, - NameAndDesc const& nameAndDesc, - SourceLineInfo const& lineInfo ) { +struct AutoReg : NonCopyable { + AutoReg( ITestInvoker* invoker, SourceLineInfo const& lineInfo, StringRef const& classOrMethod, NameAndTags const& nameAndTags ) noexcept; + ~AutoReg(); +}; - registerTestCase - ( new MethodTestCase<C>( method ), - className, - nameAndDesc, - lineInfo ); - } +} // end namespace Catch - ~AutoReg(); +#if defined(CATCH_CONFIG_DISABLE) + #define INTERNAL_CATCH_TESTCASE_NO_REGISTRATION( TestName, ... ) \ + static void TestName() + #define INTERNAL_CATCH_TESTCASE_METHOD_NO_REGISTRATION( TestName, ClassName, ... ) \ + namespace{ \ + struct TestName : INTERNAL_CATCH_REMOVE_PARENS(ClassName) { \ + void test(); \ + }; \ + } \ + void TestName::test() + #define INTERNAL_CATCH_TEMPLATE_TEST_CASE_NO_REGISTRATION_2( TestName, TestFunc, Name, Tags, Signature, ... ) \ + INTERNAL_CATCH_DEFINE_SIG_TEST(TestFunc, INTERNAL_CATCH_REMOVE_PARENS(Signature)) + #define INTERNAL_CATCH_TEMPLATE_TEST_CASE_METHOD_NO_REGISTRATION_2( TestNameClass, TestName, ClassName, Name, Tags, Signature, ... ) \ + namespace{ \ + namespace INTERNAL_CATCH_MAKE_NAMESPACE(TestName) { \ + INTERNAL_CATCH_DECLARE_SIG_TEST_METHOD(TestName, ClassName, INTERNAL_CATCH_REMOVE_PARENS(Signature));\ + } \ + } \ + INTERNAL_CATCH_DEFINE_SIG_TEST_METHOD(TestName, INTERNAL_CATCH_REMOVE_PARENS(Signature)) + + #ifndef CATCH_CONFIG_TRADITIONAL_MSVC_PREPROCESSOR + #define INTERNAL_CATCH_TEMPLATE_TEST_CASE_NO_REGISTRATION(Name, Tags, ...) \ + INTERNAL_CATCH_TEMPLATE_TEST_CASE_NO_REGISTRATION_2( INTERNAL_CATCH_UNIQUE_NAME( C_A_T_C_H_T_E_M_P_L_A_T_E_T_E_S_T_ ), INTERNAL_CATCH_UNIQUE_NAME( C_A_T_C_H_T_E_M_P_L_A_T_E_T_E_S_T_F_U_N_C_ ), Name, Tags, typename TestType, __VA_ARGS__ ) + #else + #define INTERNAL_CATCH_TEMPLATE_TEST_CASE_NO_REGISTRATION(Name, Tags, ...) \ + INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_TEST_CASE_NO_REGISTRATION_2( INTERNAL_CATCH_UNIQUE_NAME( C_A_T_C_H_T_E_M_P_L_A_T_E_T_E_S_T_ ), INTERNAL_CATCH_UNIQUE_NAME( C_A_T_C_H_T_E_M_P_L_A_T_E_T_E_S_T_F_U_N_C_ ), Name, Tags, typename TestType, __VA_ARGS__ ) ) + #endif -private: - AutoReg( AutoReg const& ); - void operator= ( AutoReg const& ); -}; + #ifndef CATCH_CONFIG_TRADITIONAL_MSVC_PREPROCESSOR + #define INTERNAL_CATCH_TEMPLATE_TEST_CASE_SIG_NO_REGISTRATION(Name, Tags, Signature, ...) \ + INTERNAL_CATCH_TEMPLATE_TEST_CASE_NO_REGISTRATION_2( INTERNAL_CATCH_UNIQUE_NAME( C_A_T_C_H_T_E_M_P_L_A_T_E_T_E_S_T_ ), INTERNAL_CATCH_UNIQUE_NAME( C_A_T_C_H_T_E_M_P_L_A_T_E_T_E_S_T_F_U_N_C_ ), Name, Tags, Signature, __VA_ARGS__ ) + #else + #define INTERNAL_CATCH_TEMPLATE_TEST_CASE_SIG_NO_REGISTRATION(Name, Tags, Signature, ...) \ + INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_TEST_CASE_NO_REGISTRATION_2( INTERNAL_CATCH_UNIQUE_NAME( C_A_T_C_H_T_E_M_P_L_A_T_E_T_E_S_T_ ), INTERNAL_CATCH_UNIQUE_NAME( C_A_T_C_H_T_E_M_P_L_A_T_E_T_E_S_T_F_U_N_C_ ), Name, Tags, Signature, __VA_ARGS__ ) ) + #endif -void registerTestCaseFunction - ( TestFunction function, - SourceLineInfo const& lineInfo, - NameAndDesc const& nameAndDesc ); + #ifndef CATCH_CONFIG_TRADITIONAL_MSVC_PREPROCESSOR + #define INTERNAL_CATCH_TEMPLATE_TEST_CASE_METHOD_NO_REGISTRATION( ClassName, Name, Tags,... ) \ + INTERNAL_CATCH_TEMPLATE_TEST_CASE_METHOD_NO_REGISTRATION_2( INTERNAL_CATCH_UNIQUE_NAME( C_A_T_C_H_T_E_M_P_L_A_T_E_T_E_S_T_C_L_A_S_S_ ), INTERNAL_CATCH_UNIQUE_NAME( C_A_T_C_H_T_E_M_P_L_A_T_E_T_E_S_T_ ) , ClassName, Name, Tags, typename T, __VA_ARGS__ ) + #else + #define INTERNAL_CATCH_TEMPLATE_TEST_CASE_METHOD_NO_REGISTRATION( ClassName, Name, Tags,... ) \ + INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_TEST_CASE_METHOD_NO_REGISTRATION_2( INTERNAL_CATCH_UNIQUE_NAME( C_A_T_C_H_T_E_M_P_L_A_T_E_T_E_S_T_C_L_A_S_S_ ), INTERNAL_CATCH_UNIQUE_NAME( C_A_T_C_H_T_E_M_P_L_A_T_E_T_E_S_T_ ) , ClassName, Name, Tags, typename T, __VA_ARGS__ ) ) + #endif -} // end namespace Catch + #ifndef CATCH_CONFIG_TRADITIONAL_MSVC_PREPROCESSOR + #define INTERNAL_CATCH_TEMPLATE_TEST_CASE_METHOD_SIG_NO_REGISTRATION( ClassName, Name, Tags, Signature, ... ) \ + INTERNAL_CATCH_TEMPLATE_TEST_CASE_METHOD_NO_REGISTRATION_2( INTERNAL_CATCH_UNIQUE_NAME( C_A_T_C_H_T_E_M_P_L_A_T_E_T_E_S_T_C_L_A_S_S_ ), INTERNAL_CATCH_UNIQUE_NAME( C_A_T_C_H_T_E_M_P_L_A_T_E_T_E_S_T_ ) , ClassName, Name, Tags, Signature, __VA_ARGS__ ) + #else + #define INTERNAL_CATCH_TEMPLATE_TEST_CASE_METHOD_SIG_NO_REGISTRATION( ClassName, Name, Tags, Signature, ... ) \ + INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_TEST_CASE_METHOD_NO_REGISTRATION_2( INTERNAL_CATCH_UNIQUE_NAME( C_A_T_C_H_T_E_M_P_L_A_T_E_T_E_S_T_C_L_A_S_S_ ), INTERNAL_CATCH_UNIQUE_NAME( C_A_T_C_H_T_E_M_P_L_A_T_E_T_E_S_T_ ) , ClassName, Name, Tags, Signature, __VA_ARGS__ ) ) + #endif +#endif -#ifdef CATCH_CONFIG_VARIADIC_MACROS /////////////////////////////////////////////////////////////////////////////// #define INTERNAL_CATCH_TESTCASE2( TestName, ... ) \ static void TestName(); \ - CATCH_INTERNAL_SUPPRESS_ETD_WARNINGS \ - namespace{ Catch::AutoReg INTERNAL_CATCH_UNIQUE_NAME( autoRegistrar )( &TestName, CATCH_INTERNAL_LINEINFO, Catch::NameAndDesc( __VA_ARGS__ ) ); } /* NOLINT */ \ - CATCH_INTERNAL_UNSUPPRESS_ETD_WARNINGS \ + CATCH_INTERNAL_START_WARNINGS_SUPPRESSION \ + CATCH_INTERNAL_SUPPRESS_GLOBALS_WARNINGS \ + namespace{ Catch::AutoReg INTERNAL_CATCH_UNIQUE_NAME( autoRegistrar )( Catch::makeTestInvoker( &TestName ), CATCH_INTERNAL_LINEINFO, Catch::StringRef(), Catch::NameAndTags{ __VA_ARGS__ } ); } /* NOLINT */ \ + CATCH_INTERNAL_STOP_WARNINGS_SUPPRESSION \ static void TestName() #define INTERNAL_CATCH_TESTCASE( ... ) \ - INTERNAL_CATCH_TESTCASE2( INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_S_T____ ), __VA_ARGS__ ) + INTERNAL_CATCH_TESTCASE2( INTERNAL_CATCH_UNIQUE_NAME( C_A_T_C_H_T_E_S_T_ ), __VA_ARGS__ ) /////////////////////////////////////////////////////////////////////////////// #define INTERNAL_CATCH_METHOD_AS_TEST_CASE( QualifiedMethod, ... ) \ - CATCH_INTERNAL_SUPPRESS_ETD_WARNINGS \ - namespace{ Catch::AutoReg INTERNAL_CATCH_UNIQUE_NAME( autoRegistrar )( &QualifiedMethod, "&" #QualifiedMethod, Catch::NameAndDesc( __VA_ARGS__ ), CATCH_INTERNAL_LINEINFO ); } /* NOLINT */ \ - CATCH_INTERNAL_UNSUPPRESS_ETD_WARNINGS + CATCH_INTERNAL_START_WARNINGS_SUPPRESSION \ + CATCH_INTERNAL_SUPPRESS_GLOBALS_WARNINGS \ + namespace{ Catch::AutoReg INTERNAL_CATCH_UNIQUE_NAME( autoRegistrar )( Catch::makeTestInvoker( &QualifiedMethod ), CATCH_INTERNAL_LINEINFO, "&" #QualifiedMethod, Catch::NameAndTags{ __VA_ARGS__ } ); } /* NOLINT */ \ + CATCH_INTERNAL_STOP_WARNINGS_SUPPRESSION /////////////////////////////////////////////////////////////////////////////// #define INTERNAL_CATCH_TEST_CASE_METHOD2( TestName, ClassName, ... )\ - CATCH_INTERNAL_SUPPRESS_ETD_WARNINGS \ + CATCH_INTERNAL_START_WARNINGS_SUPPRESSION \ + CATCH_INTERNAL_SUPPRESS_GLOBALS_WARNINGS \ namespace{ \ - struct TestName : ClassName{ \ + struct TestName : INTERNAL_CATCH_REMOVE_PARENS(ClassName) { \ void test(); \ }; \ - Catch::AutoReg INTERNAL_CATCH_UNIQUE_NAME( autoRegistrar ) ( &TestName::test, #ClassName, Catch::NameAndDesc( __VA_ARGS__ ), CATCH_INTERNAL_LINEINFO ); /* NOLINT */ \ + Catch::AutoReg INTERNAL_CATCH_UNIQUE_NAME( autoRegistrar ) ( Catch::makeTestInvoker( &TestName::test ), CATCH_INTERNAL_LINEINFO, #ClassName, Catch::NameAndTags{ __VA_ARGS__ } ); /* NOLINT */ \ } \ - CATCH_INTERNAL_UNSUPPRESS_ETD_WARNINGS \ + CATCH_INTERNAL_STOP_WARNINGS_SUPPRESSION \ void TestName::test() #define INTERNAL_CATCH_TEST_CASE_METHOD( ClassName, ... ) \ - INTERNAL_CATCH_TEST_CASE_METHOD2( INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_S_T____ ), ClassName, __VA_ARGS__ ) + INTERNAL_CATCH_TEST_CASE_METHOD2( INTERNAL_CATCH_UNIQUE_NAME( C_A_T_C_H_T_E_S_T_ ), ClassName, __VA_ARGS__ ) /////////////////////////////////////////////////////////////////////////////// #define INTERNAL_CATCH_REGISTER_TESTCASE( Function, ... ) \ - CATCH_INTERNAL_SUPPRESS_ETD_WARNINGS \ - Catch::AutoReg( Function, CATCH_INTERNAL_LINEINFO, Catch::NameAndDesc( __VA_ARGS__ ) ); /* NOLINT */ \ - CATCH_INTERNAL_UNSUPPRESS_ETD_WARNINGS + CATCH_INTERNAL_START_WARNINGS_SUPPRESSION \ + CATCH_INTERNAL_SUPPRESS_GLOBALS_WARNINGS \ + Catch::AutoReg INTERNAL_CATCH_UNIQUE_NAME( autoRegistrar )( Catch::makeTestInvoker( Function ), CATCH_INTERNAL_LINEINFO, Catch::StringRef(), Catch::NameAndTags{ __VA_ARGS__ } ); /* NOLINT */ \ + CATCH_INTERNAL_STOP_WARNINGS_SUPPRESSION -#else /////////////////////////////////////////////////////////////////////////////// - #define INTERNAL_CATCH_TESTCASE2( TestName, Name, Desc ) \ - static void TestName(); \ - CATCH_INTERNAL_SUPPRESS_ETD_WARNINGS \ - namespace{ Catch::AutoReg INTERNAL_CATCH_UNIQUE_NAME( autoRegistrar )( &TestName, CATCH_INTERNAL_LINEINFO, Catch::NameAndDesc( Name, Desc ) ); } /* NOLINT */ \ - CATCH_INTERNAL_UNSUPPRESS_ETD_WARNINGS \ - static void TestName() - #define INTERNAL_CATCH_TESTCASE( Name, Desc ) \ - INTERNAL_CATCH_TESTCASE2( INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_S_T____ ), Name, Desc ) + #define INTERNAL_CATCH_TEMPLATE_TEST_CASE_2(TestName, TestFunc, Name, Tags, Signature, ... )\ + CATCH_INTERNAL_START_WARNINGS_SUPPRESSION \ + CATCH_INTERNAL_SUPPRESS_GLOBALS_WARNINGS \ + CATCH_INTERNAL_SUPPRESS_ZERO_VARIADIC_WARNINGS \ + CATCH_INTERNAL_SUPPRESS_UNUSED_TEMPLATE_WARNINGS \ + INTERNAL_CATCH_DECLARE_SIG_TEST(TestFunc, INTERNAL_CATCH_REMOVE_PARENS(Signature));\ + namespace {\ + namespace INTERNAL_CATCH_MAKE_NAMESPACE(TestName){\ + INTERNAL_CATCH_TYPE_GEN\ + INTERNAL_CATCH_NTTP_GEN(INTERNAL_CATCH_REMOVE_PARENS(Signature))\ + INTERNAL_CATCH_NTTP_REG_GEN(TestFunc,INTERNAL_CATCH_REMOVE_PARENS(Signature))\ + template<typename...Types> \ + struct TestName{\ + TestName(){\ + int index = 0; \ + constexpr char const* tmpl_types[] = {CATCH_REC_LIST(INTERNAL_CATCH_STRINGIZE_WITHOUT_PARENS, __VA_ARGS__)};\ + using expander = int[];\ + (void)expander{(reg_test(Types{}, Catch::NameAndTags{ Name " - " + std::string(tmpl_types[index]), Tags } ), index++)... };/* NOLINT */ \ + }\ + };\ + static int INTERNAL_CATCH_UNIQUE_NAME( globalRegistrar ) = [](){\ + TestName<INTERNAL_CATCH_MAKE_TYPE_LISTS_FROM_TYPES(__VA_ARGS__)>();\ + return 0;\ + }();\ + }\ + }\ + CATCH_INTERNAL_STOP_WARNINGS_SUPPRESSION \ + INTERNAL_CATCH_DEFINE_SIG_TEST(TestFunc,INTERNAL_CATCH_REMOVE_PARENS(Signature)) + +#ifndef CATCH_CONFIG_TRADITIONAL_MSVC_PREPROCESSOR + #define INTERNAL_CATCH_TEMPLATE_TEST_CASE(Name, Tags, ...) \ + INTERNAL_CATCH_TEMPLATE_TEST_CASE_2( INTERNAL_CATCH_UNIQUE_NAME( C_A_T_C_H_T_E_M_P_L_A_T_E_T_E_S_T_ ), INTERNAL_CATCH_UNIQUE_NAME( C_A_T_C_H_T_E_M_P_L_A_T_E_T_E_S_T_F_U_N_C_ ), Name, Tags, typename TestType, __VA_ARGS__ ) +#else + #define INTERNAL_CATCH_TEMPLATE_TEST_CASE(Name, Tags, ...) \ + INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_TEST_CASE_2( INTERNAL_CATCH_UNIQUE_NAME( C_A_T_C_H_T_E_M_P_L_A_T_E_T_E_S_T_ ), INTERNAL_CATCH_UNIQUE_NAME( C_A_T_C_H_T_E_M_P_L_A_T_E_T_E_S_T_F_U_N_C_ ), Name, Tags, typename TestType, __VA_ARGS__ ) ) +#endif - /////////////////////////////////////////////////////////////////////////////// - #define INTERNAL_CATCH_METHOD_AS_TEST_CASE( QualifiedMethod, Name, Desc ) \ - CATCH_INTERNAL_SUPPRESS_ETD_WARNINGS \ - namespace{ Catch::AutoReg INTERNAL_CATCH_UNIQUE_NAME( autoRegistrar )( &QualifiedMethod, "&" #QualifiedMethod, Catch::NameAndDesc( Name, Desc ), CATCH_INTERNAL_LINEINFO ); } /* NOLINT */ \ - CATCH_INTERNAL_UNSUPPRESS_ETD_WARNINGS +#ifndef CATCH_CONFIG_TRADITIONAL_MSVC_PREPROCESSOR + #define INTERNAL_CATCH_TEMPLATE_TEST_CASE_SIG(Name, Tags, Signature, ...) \ + INTERNAL_CATCH_TEMPLATE_TEST_CASE_2( INTERNAL_CATCH_UNIQUE_NAME( C_A_T_C_H_T_E_M_P_L_A_T_E_T_E_S_T_ ), INTERNAL_CATCH_UNIQUE_NAME( C_A_T_C_H_T_E_M_P_L_A_T_E_T_E_S_T_F_U_N_C_ ), Name, Tags, Signature, __VA_ARGS__ ) +#else + #define INTERNAL_CATCH_TEMPLATE_TEST_CASE_SIG(Name, Tags, Signature, ...) \ + INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_TEST_CASE_2( INTERNAL_CATCH_UNIQUE_NAME( C_A_T_C_H_T_E_M_P_L_A_T_E_T_E_S_T_ ), INTERNAL_CATCH_UNIQUE_NAME( C_A_T_C_H_T_E_M_P_L_A_T_E_T_E_S_T_F_U_N_C_ ), Name, Tags, Signature, __VA_ARGS__ ) ) +#endif - /////////////////////////////////////////////////////////////////////////////// - #define INTERNAL_CATCH_TEST_CASE_METHOD2( TestCaseName, ClassName, TestName, Desc )\ - CATCH_INTERNAL_SUPPRESS_ETD_WARNINGS \ - namespace{ \ - struct TestCaseName : ClassName{ \ - void test(); \ - }; \ - Catch::AutoReg INTERNAL_CATCH_UNIQUE_NAME( autoRegistrar ) ( &TestCaseName::test, #ClassName, Catch::NameAndDesc( TestName, Desc ), CATCH_INTERNAL_LINEINFO ); /* NOLINT */ \ - } \ - CATCH_INTERNAL_UNSUPPRESS_ETD_WARNINGS \ - void TestCaseName::test() - #define INTERNAL_CATCH_TEST_CASE_METHOD( ClassName, TestName, Desc )\ - INTERNAL_CATCH_TEST_CASE_METHOD2( INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_S_T____ ), ClassName, TestName, Desc ) + #define INTERNAL_CATCH_TEMPLATE_PRODUCT_TEST_CASE2(TestName, TestFuncName, Name, Tags, Signature, TmplTypes, TypesList) \ + CATCH_INTERNAL_START_WARNINGS_SUPPRESSION \ + CATCH_INTERNAL_SUPPRESS_GLOBALS_WARNINGS \ + CATCH_INTERNAL_SUPPRESS_ZERO_VARIADIC_WARNINGS \ + CATCH_INTERNAL_SUPPRESS_UNUSED_TEMPLATE_WARNINGS \ + template<typename TestType> static void TestFuncName(); \ + namespace {\ + namespace INTERNAL_CATCH_MAKE_NAMESPACE(TestName) { \ + INTERNAL_CATCH_TYPE_GEN \ + INTERNAL_CATCH_NTTP_GEN(INTERNAL_CATCH_REMOVE_PARENS(Signature)) \ + template<typename... Types> \ + struct TestName { \ + void reg_tests() { \ + int index = 0; \ + using expander = int[]; \ + constexpr char const* tmpl_types[] = {CATCH_REC_LIST(INTERNAL_CATCH_STRINGIZE_WITHOUT_PARENS, INTERNAL_CATCH_REMOVE_PARENS(TmplTypes))};\ + constexpr char const* types_list[] = {CATCH_REC_LIST(INTERNAL_CATCH_STRINGIZE_WITHOUT_PARENS, INTERNAL_CATCH_REMOVE_PARENS(TypesList))};\ + constexpr auto num_types = sizeof(types_list) / sizeof(types_list[0]);\ + (void)expander{(Catch::AutoReg( Catch::makeTestInvoker( &TestFuncName<Types> ), CATCH_INTERNAL_LINEINFO, Catch::StringRef(), Catch::NameAndTags{ Name " - " + std::string(tmpl_types[index / num_types]) + "<" + std::string(types_list[index % num_types]) + ">", Tags } ), index++)... };/* NOLINT */\ + } \ + }; \ + static int INTERNAL_CATCH_UNIQUE_NAME( globalRegistrar ) = [](){ \ + using TestInit = typename create<TestName, decltype(get_wrapper<INTERNAL_CATCH_REMOVE_PARENS(TmplTypes)>()), TypeList<INTERNAL_CATCH_MAKE_TYPE_LISTS_FROM_TYPES(INTERNAL_CATCH_REMOVE_PARENS(TypesList))>>::type; \ + TestInit t; \ + t.reg_tests(); \ + return 0; \ + }(); \ + } \ + } \ + CATCH_INTERNAL_STOP_WARNINGS_SUPPRESSION \ + template<typename TestType> \ + static void TestFuncName() + +#ifndef CATCH_CONFIG_TRADITIONAL_MSVC_PREPROCESSOR + #define INTERNAL_CATCH_TEMPLATE_PRODUCT_TEST_CASE(Name, Tags, ...)\ + INTERNAL_CATCH_TEMPLATE_PRODUCT_TEST_CASE2(INTERNAL_CATCH_UNIQUE_NAME( C_A_T_C_H_T_E_M_P_L_A_T_E_T_E_S_T_ ), INTERNAL_CATCH_UNIQUE_NAME( C_A_T_C_H_T_E_M_P_L_A_T_E_T_E_S_T_F_U_N_C_ ), Name, Tags, typename T,__VA_ARGS__) +#else + #define INTERNAL_CATCH_TEMPLATE_PRODUCT_TEST_CASE(Name, Tags, ...)\ + INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_PRODUCT_TEST_CASE2( INTERNAL_CATCH_UNIQUE_NAME( C_A_T_C_H_T_E_M_P_L_A_T_E_T_E_S_T_ ), INTERNAL_CATCH_UNIQUE_NAME( C_A_T_C_H_T_E_M_P_L_A_T_E_T_E_S_T_F_U_N_C_ ), Name, Tags, typename T, __VA_ARGS__ ) ) +#endif - /////////////////////////////////////////////////////////////////////////////// - #define INTERNAL_CATCH_REGISTER_TESTCASE( Function, Name, Desc ) \ - CATCH_INTERNAL_SUPPRESS_ETD_WARNINGS \ - Catch::AutoReg( Function, CATCH_INTERNAL_LINEINFO, Catch::NameAndDesc( Name, Desc ) ); /* NOLINT */ \ - CATCH_INTERNAL_UNSUPPRESS_ETD_WARNINGS +#ifndef CATCH_CONFIG_TRADITIONAL_MSVC_PREPROCESSOR + #define INTERNAL_CATCH_TEMPLATE_PRODUCT_TEST_CASE_SIG(Name, Tags, Signature, ...)\ + INTERNAL_CATCH_TEMPLATE_PRODUCT_TEST_CASE2(INTERNAL_CATCH_UNIQUE_NAME( C_A_T_C_H_T_E_M_P_L_A_T_E_T_E_S_T_ ), INTERNAL_CATCH_UNIQUE_NAME( C_A_T_C_H_T_E_M_P_L_A_T_E_T_E_S_T_F_U_N_C_ ), Name, Tags, Signature, __VA_ARGS__) +#else + #define INTERNAL_CATCH_TEMPLATE_PRODUCT_TEST_CASE_SIG(Name, Tags, Signature, ...)\ + INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_PRODUCT_TEST_CASE2( INTERNAL_CATCH_UNIQUE_NAME( C_A_T_C_H_T_E_M_P_L_A_T_E_T_E_S_T_ ), INTERNAL_CATCH_UNIQUE_NAME( C_A_T_C_H_T_E_M_P_L_A_T_E_T_E_S_T_F_U_N_C_ ), Name, Tags, Signature, __VA_ARGS__ ) ) +#endif + + #define INTERNAL_CATCH_TEMPLATE_LIST_TEST_CASE_2(TestName, TestFunc, Name, Tags, TmplList)\ + CATCH_INTERNAL_START_WARNINGS_SUPPRESSION \ + CATCH_INTERNAL_SUPPRESS_GLOBALS_WARNINGS \ + CATCH_INTERNAL_SUPPRESS_UNUSED_TEMPLATE_WARNINGS \ + template<typename TestType> static void TestFunc(); \ + namespace {\ + namespace INTERNAL_CATCH_MAKE_NAMESPACE(TestName){\ + INTERNAL_CATCH_TYPE_GEN\ + template<typename... Types> \ + struct TestName { \ + void reg_tests() { \ + int index = 0; \ + using expander = int[]; \ + (void)expander{(Catch::AutoReg( Catch::makeTestInvoker( &TestFunc<Types> ), CATCH_INTERNAL_LINEINFO, Catch::StringRef(), Catch::NameAndTags{ Name " - " + std::string(INTERNAL_CATCH_STRINGIZE(TmplList)) + " - " + std::to_string(index), Tags } ), index++)... };/* NOLINT */\ + } \ + };\ + static int INTERNAL_CATCH_UNIQUE_NAME( globalRegistrar ) = [](){ \ + using TestInit = typename convert<TestName, TmplList>::type; \ + TestInit t; \ + t.reg_tests(); \ + return 0; \ + }(); \ + }}\ + CATCH_INTERNAL_STOP_WARNINGS_SUPPRESSION \ + template<typename TestType> \ + static void TestFunc() + + #define INTERNAL_CATCH_TEMPLATE_LIST_TEST_CASE(Name, Tags, TmplList) \ + INTERNAL_CATCH_TEMPLATE_LIST_TEST_CASE_2( INTERNAL_CATCH_UNIQUE_NAME( C_A_T_C_H_T_E_M_P_L_A_T_E_T_E_S_T_ ), INTERNAL_CATCH_UNIQUE_NAME( C_A_T_C_H_T_E_M_P_L_A_T_E_T_E_S_T_F_U_N_C_ ), Name, Tags, TmplList ) + + #define INTERNAL_CATCH_TEMPLATE_TEST_CASE_METHOD_2( TestNameClass, TestName, ClassName, Name, Tags, Signature, ... ) \ + CATCH_INTERNAL_START_WARNINGS_SUPPRESSION \ + CATCH_INTERNAL_SUPPRESS_GLOBALS_WARNINGS \ + CATCH_INTERNAL_SUPPRESS_ZERO_VARIADIC_WARNINGS \ + CATCH_INTERNAL_SUPPRESS_UNUSED_TEMPLATE_WARNINGS \ + namespace {\ + namespace INTERNAL_CATCH_MAKE_NAMESPACE(TestName){ \ + INTERNAL_CATCH_TYPE_GEN\ + INTERNAL_CATCH_NTTP_GEN(INTERNAL_CATCH_REMOVE_PARENS(Signature))\ + INTERNAL_CATCH_DECLARE_SIG_TEST_METHOD(TestName, ClassName, INTERNAL_CATCH_REMOVE_PARENS(Signature));\ + INTERNAL_CATCH_NTTP_REG_METHOD_GEN(TestName, INTERNAL_CATCH_REMOVE_PARENS(Signature))\ + template<typename...Types> \ + struct TestNameClass{\ + TestNameClass(){\ + int index = 0; \ + constexpr char const* tmpl_types[] = {CATCH_REC_LIST(INTERNAL_CATCH_STRINGIZE_WITHOUT_PARENS, __VA_ARGS__)};\ + using expander = int[];\ + (void)expander{(reg_test(Types{}, #ClassName, Catch::NameAndTags{ Name " - " + std::string(tmpl_types[index]), Tags } ), index++)... };/* NOLINT */ \ + }\ + };\ + static int INTERNAL_CATCH_UNIQUE_NAME( globalRegistrar ) = [](){\ + TestNameClass<INTERNAL_CATCH_MAKE_TYPE_LISTS_FROM_TYPES(__VA_ARGS__)>();\ + return 0;\ + }();\ + }\ + }\ + CATCH_INTERNAL_STOP_WARNINGS_SUPPRESSION \ + INTERNAL_CATCH_DEFINE_SIG_TEST_METHOD(TestName, INTERNAL_CATCH_REMOVE_PARENS(Signature)) + +#ifndef CATCH_CONFIG_TRADITIONAL_MSVC_PREPROCESSOR + #define INTERNAL_CATCH_TEMPLATE_TEST_CASE_METHOD( ClassName, Name, Tags,... ) \ + INTERNAL_CATCH_TEMPLATE_TEST_CASE_METHOD_2( INTERNAL_CATCH_UNIQUE_NAME( C_A_T_C_H_T_E_M_P_L_A_T_E_T_E_S_T_C_L_A_S_S_ ), INTERNAL_CATCH_UNIQUE_NAME( C_A_T_C_H_T_E_M_P_L_A_T_E_T_E_S_T_ ) , ClassName, Name, Tags, typename T, __VA_ARGS__ ) +#else + #define INTERNAL_CATCH_TEMPLATE_TEST_CASE_METHOD( ClassName, Name, Tags,... ) \ + INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_TEST_CASE_METHOD_2( INTERNAL_CATCH_UNIQUE_NAME( C_A_T_C_H_T_E_M_P_L_A_T_E_T_E_S_T_C_L_A_S_S_ ), INTERNAL_CATCH_UNIQUE_NAME( C_A_T_C_H_T_E_M_P_L_A_T_E_T_E_S_T_ ) , ClassName, Name, Tags, typename T, __VA_ARGS__ ) ) +#endif +#ifndef CATCH_CONFIG_TRADITIONAL_MSVC_PREPROCESSOR + #define INTERNAL_CATCH_TEMPLATE_TEST_CASE_METHOD_SIG( ClassName, Name, Tags, Signature, ... ) \ + INTERNAL_CATCH_TEMPLATE_TEST_CASE_METHOD_2( INTERNAL_CATCH_UNIQUE_NAME( C_A_T_C_H_T_E_M_P_L_A_T_E_T_E_S_T_C_L_A_S_S_ ), INTERNAL_CATCH_UNIQUE_NAME( C_A_T_C_H_T_E_M_P_L_A_T_E_T_E_S_T_ ) , ClassName, Name, Tags, Signature, __VA_ARGS__ ) +#else + #define INTERNAL_CATCH_TEMPLATE_TEST_CASE_METHOD_SIG( ClassName, Name, Tags, Signature, ... ) \ + INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_TEST_CASE_METHOD_2( INTERNAL_CATCH_UNIQUE_NAME( C_A_T_C_H_T_E_M_P_L_A_T_E_T_E_S_T_C_L_A_S_S_ ), INTERNAL_CATCH_UNIQUE_NAME( C_A_T_C_H_T_E_M_P_L_A_T_E_T_E_S_T_ ) , ClassName, Name, Tags, Signature, __VA_ARGS__ ) ) #endif -// #included from: internal/catch_capture.hpp -#define TWOBLUECUBES_CATCH_CAPTURE_HPP_INCLUDED + #define INTERNAL_CATCH_TEMPLATE_PRODUCT_TEST_CASE_METHOD_2(TestNameClass, TestName, ClassName, Name, Tags, Signature, TmplTypes, TypesList)\ + CATCH_INTERNAL_START_WARNINGS_SUPPRESSION \ + CATCH_INTERNAL_SUPPRESS_GLOBALS_WARNINGS \ + CATCH_INTERNAL_SUPPRESS_ZERO_VARIADIC_WARNINGS \ + CATCH_INTERNAL_SUPPRESS_UNUSED_TEMPLATE_WARNINGS \ + template<typename TestType> \ + struct TestName : INTERNAL_CATCH_REMOVE_PARENS(ClassName <TestType>) { \ + void test();\ + };\ + namespace {\ + namespace INTERNAL_CATCH_MAKE_NAMESPACE(TestNameClass) {\ + INTERNAL_CATCH_TYPE_GEN \ + INTERNAL_CATCH_NTTP_GEN(INTERNAL_CATCH_REMOVE_PARENS(Signature))\ + template<typename...Types>\ + struct TestNameClass{\ + void reg_tests(){\ + int index = 0;\ + using expander = int[];\ + constexpr char const* tmpl_types[] = {CATCH_REC_LIST(INTERNAL_CATCH_STRINGIZE_WITHOUT_PARENS, INTERNAL_CATCH_REMOVE_PARENS(TmplTypes))};\ + constexpr char const* types_list[] = {CATCH_REC_LIST(INTERNAL_CATCH_STRINGIZE_WITHOUT_PARENS, INTERNAL_CATCH_REMOVE_PARENS(TypesList))};\ + constexpr auto num_types = sizeof(types_list) / sizeof(types_list[0]);\ + (void)expander{(Catch::AutoReg( Catch::makeTestInvoker( &TestName<Types>::test ), CATCH_INTERNAL_LINEINFO, #ClassName, Catch::NameAndTags{ Name " - " + std::string(tmpl_types[index / num_types]) + "<" + std::string(types_list[index % num_types]) + ">", Tags } ), index++)... };/* NOLINT */ \ + }\ + };\ + static int INTERNAL_CATCH_UNIQUE_NAME( globalRegistrar ) = [](){\ + using TestInit = typename create<TestNameClass, decltype(get_wrapper<INTERNAL_CATCH_REMOVE_PARENS(TmplTypes)>()), TypeList<INTERNAL_CATCH_MAKE_TYPE_LISTS_FROM_TYPES(INTERNAL_CATCH_REMOVE_PARENS(TypesList))>>::type;\ + TestInit t;\ + t.reg_tests();\ + return 0;\ + }(); \ + }\ + }\ + CATCH_INTERNAL_STOP_WARNINGS_SUPPRESSION \ + template<typename TestType> \ + void TestName<TestType>::test() + +#ifndef CATCH_CONFIG_TRADITIONAL_MSVC_PREPROCESSOR + #define INTERNAL_CATCH_TEMPLATE_PRODUCT_TEST_CASE_METHOD( ClassName, Name, Tags, ... )\ + INTERNAL_CATCH_TEMPLATE_PRODUCT_TEST_CASE_METHOD_2( INTERNAL_CATCH_UNIQUE_NAME( C_A_T_C_H_T_E_M_P_L_A_T_E_T_E_S_T_ ), INTERNAL_CATCH_UNIQUE_NAME( C_A_T_C_H_T_E_M_P_L_A_T_E_T_E_S_T_F_U_N_C_ ), ClassName, Name, Tags, typename T, __VA_ARGS__ ) +#else + #define INTERNAL_CATCH_TEMPLATE_PRODUCT_TEST_CASE_METHOD( ClassName, Name, Tags, ... )\ + INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_PRODUCT_TEST_CASE_METHOD_2( INTERNAL_CATCH_UNIQUE_NAME( C_A_T_C_H_T_E_M_P_L_A_T_E_T_E_S_T_ ), INTERNAL_CATCH_UNIQUE_NAME( C_A_T_C_H_T_E_M_P_L_A_T_E_T_E_S_T_F_U_N_C_ ), ClassName, Name, Tags, typename T,__VA_ARGS__ ) ) +#endif -// #included from: catch_result_builder.h -#define TWOBLUECUBES_CATCH_RESULT_BUILDER_H_INCLUDED +#ifndef CATCH_CONFIG_TRADITIONAL_MSVC_PREPROCESSOR + #define INTERNAL_CATCH_TEMPLATE_PRODUCT_TEST_CASE_METHOD_SIG( ClassName, Name, Tags, Signature, ... )\ + INTERNAL_CATCH_TEMPLATE_PRODUCT_TEST_CASE_METHOD_2( INTERNAL_CATCH_UNIQUE_NAME( C_A_T_C_H_T_E_M_P_L_A_T_E_T_E_S_T_ ), INTERNAL_CATCH_UNIQUE_NAME( C_A_T_C_H_T_E_M_P_L_A_T_E_T_E_S_T_F_U_N_C_ ), ClassName, Name, Tags, Signature, __VA_ARGS__ ) +#else + #define INTERNAL_CATCH_TEMPLATE_PRODUCT_TEST_CASE_METHOD_SIG( ClassName, Name, Tags, Signature, ... )\ + INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_PRODUCT_TEST_CASE_METHOD_2( INTERNAL_CATCH_UNIQUE_NAME( C_A_T_C_H_T_E_M_P_L_A_T_E_T_E_S_T_ ), INTERNAL_CATCH_UNIQUE_NAME( C_A_T_C_H_T_E_M_P_L_A_T_E_T_E_S_T_F_U_N_C_ ), ClassName, Name, Tags, Signature,__VA_ARGS__ ) ) +#endif -// #included from: catch_result_type.h -#define TWOBLUECUBES_CATCH_RESULT_TYPE_H_INCLUDED + #define INTERNAL_CATCH_TEMPLATE_LIST_TEST_CASE_METHOD_2( TestNameClass, TestName, ClassName, Name, Tags, TmplList) \ + CATCH_INTERNAL_START_WARNINGS_SUPPRESSION \ + CATCH_INTERNAL_SUPPRESS_GLOBALS_WARNINGS \ + CATCH_INTERNAL_SUPPRESS_UNUSED_TEMPLATE_WARNINGS \ + template<typename TestType> \ + struct TestName : INTERNAL_CATCH_REMOVE_PARENS(ClassName <TestType>) { \ + void test();\ + };\ + namespace {\ + namespace INTERNAL_CATCH_MAKE_NAMESPACE(TestName){ \ + INTERNAL_CATCH_TYPE_GEN\ + template<typename...Types>\ + struct TestNameClass{\ + void reg_tests(){\ + int index = 0;\ + using expander = int[];\ + (void)expander{(Catch::AutoReg( Catch::makeTestInvoker( &TestName<Types>::test ), CATCH_INTERNAL_LINEINFO, #ClassName, Catch::NameAndTags{ Name " - " + std::string(INTERNAL_CATCH_STRINGIZE(TmplList)) + " - " + std::to_string(index), Tags } ), index++)... };/* NOLINT */ \ + }\ + };\ + static int INTERNAL_CATCH_UNIQUE_NAME( globalRegistrar ) = [](){\ + using TestInit = typename convert<TestNameClass, TmplList>::type;\ + TestInit t;\ + t.reg_tests();\ + return 0;\ + }(); \ + }}\ + CATCH_INTERNAL_STOP_WARNINGS_SUPPRESSION \ + template<typename TestType> \ + void TestName<TestType>::test() + +#define INTERNAL_CATCH_TEMPLATE_LIST_TEST_CASE_METHOD(ClassName, Name, Tags, TmplList) \ + INTERNAL_CATCH_TEMPLATE_LIST_TEST_CASE_METHOD_2( INTERNAL_CATCH_UNIQUE_NAME( C_A_T_C_H_T_E_M_P_L_A_T_E_T_E_S_T_ ), INTERNAL_CATCH_UNIQUE_NAME( C_A_T_C_H_T_E_M_P_L_A_T_E_T_E_S_T_F_U_N_C_ ), ClassName, Name, Tags, TmplList ) + +// end catch_test_registry.h +// start catch_capture.hpp + +// start catch_assertionhandler.h + +// start catch_assertioninfo.h + +// start catch_result_type.h namespace Catch { @@ -880,12 +1370,8 @@ namespace Catch { }; }; - inline bool isOk( ResultWas::OfType resultType ) { - return ( resultType & ResultWas::FailureBit ) == 0; - } - inline bool isJustInfo( int flags ) { - return flags == ResultWas::Info; - } + bool isOk( ResultWas::OfType resultType ); + bool isJustInfo( int flags ); // ResultDisposition::Flags enum struct ResultDisposition { enum Flags { @@ -896,622 +1382,125 @@ namespace Catch { SuppressFail = 0x08 // Failures are reported but do not fail the test }; }; - inline ResultDisposition::Flags operator | ( ResultDisposition::Flags lhs, ResultDisposition::Flags rhs ) { - return static_cast<ResultDisposition::Flags>( static_cast<int>( lhs ) | static_cast<int>( rhs ) ); - } + ResultDisposition::Flags operator | ( ResultDisposition::Flags lhs, ResultDisposition::Flags rhs ); - inline bool shouldContinueOnFailure( int flags ) { return ( flags & ResultDisposition::ContinueOnFailure ) != 0; } - inline bool isFalseTest( int flags ) { return ( flags & ResultDisposition::FalseTest ) != 0; } - inline bool shouldSuppressFailure( int flags ) { return ( flags & ResultDisposition::SuppressFail ) != 0; } + bool shouldContinueOnFailure( int flags ); + inline bool isFalseTest( int flags ) { return ( flags & ResultDisposition::FalseTest ) != 0; } + bool shouldSuppressFailure( int flags ); } // end namespace Catch -// #included from: catch_assertionresult.h -#define TWOBLUECUBES_CATCH_ASSERTIONRESULT_H_INCLUDED - -#include <string> - +// end catch_result_type.h namespace Catch { - struct STATIC_ASSERT_Expression_Too_Complex_Please_Rewrite_As_Binary_Comparison; - - struct DecomposedExpression - { - virtual ~DecomposedExpression() {} - virtual bool isBinaryExpression() const { - return false; - } - virtual void reconstructExpression( std::string& dest ) const = 0; - - // Only simple binary comparisons can be decomposed. - // If more complex check is required then wrap sub-expressions in parentheses. - template<typename T> STATIC_ASSERT_Expression_Too_Complex_Please_Rewrite_As_Binary_Comparison& operator + ( T const& ); - template<typename T> STATIC_ASSERT_Expression_Too_Complex_Please_Rewrite_As_Binary_Comparison& operator - ( T const& ); - template<typename T> STATIC_ASSERT_Expression_Too_Complex_Please_Rewrite_As_Binary_Comparison& operator * ( T const& ); - template<typename T> STATIC_ASSERT_Expression_Too_Complex_Please_Rewrite_As_Binary_Comparison& operator / ( T const& ); - template<typename T> STATIC_ASSERT_Expression_Too_Complex_Please_Rewrite_As_Binary_Comparison& operator % ( T const& ); - template<typename T> STATIC_ASSERT_Expression_Too_Complex_Please_Rewrite_As_Binary_Comparison& operator && ( T const& ); - template<typename T> STATIC_ASSERT_Expression_Too_Complex_Please_Rewrite_As_Binary_Comparison& operator || ( T const& ); - - private: - DecomposedExpression& operator = (DecomposedExpression const&); - }; - struct AssertionInfo { - AssertionInfo(); - AssertionInfo( char const * _macroName, - SourceLineInfo const& _lineInfo, - char const * _capturedExpression, - ResultDisposition::Flags _resultDisposition, - char const * _secondArg = ""); - - char const * macroName; + StringRef macroName; SourceLineInfo lineInfo; - char const * capturedExpression; + StringRef capturedExpression; ResultDisposition::Flags resultDisposition; - char const * secondArg; - }; - - struct AssertionResultData - { - AssertionResultData() : decomposedExpression( CATCH_NULL ) - , resultType( ResultWas::Unknown ) - , negated( false ) - , parenthesized( false ) {} - - void negate( bool parenthesize ) { - negated = !negated; - parenthesized = parenthesize; - if( resultType == ResultWas::Ok ) - resultType = ResultWas::ExpressionFailed; - else if( resultType == ResultWas::ExpressionFailed ) - resultType = ResultWas::Ok; - } - - std::string const& reconstructExpression() const { - if( decomposedExpression != CATCH_NULL ) { - decomposedExpression->reconstructExpression( reconstructedExpression ); - if( parenthesized ) { - reconstructedExpression.insert( 0, 1, '(' ); - reconstructedExpression.append( 1, ')' ); - } - if( negated ) { - reconstructedExpression.insert( 0, 1, '!' ); - } - decomposedExpression = CATCH_NULL; - } - return reconstructedExpression; - } - mutable DecomposedExpression const* decomposedExpression; - mutable std::string reconstructedExpression; - std::string message; - ResultWas::OfType resultType; - bool negated; - bool parenthesized; + // We want to delete this constructor but a compiler bug in 4.8 means + // the struct is then treated as non-aggregate + //AssertionInfo() = delete; }; - class AssertionResult { - public: - AssertionResult(); - AssertionResult( AssertionInfo const& info, AssertionResultData const& data ); - ~AssertionResult(); -# ifdef CATCH_CONFIG_CPP11_GENERATED_METHODS - AssertionResult( AssertionResult const& ) = default; - AssertionResult( AssertionResult && ) = default; - AssertionResult& operator = ( AssertionResult const& ) = default; - AssertionResult& operator = ( AssertionResult && ) = default; -# endif +} // end namespace Catch - bool isOk() const; - bool succeeded() const; - ResultWas::OfType getResultType() const; - bool hasExpression() const; - bool hasMessage() const; - std::string getExpression() const; - std::string getExpressionInMacro() const; - bool hasExpandedExpression() const; - std::string getExpandedExpression() const; - std::string getMessage() const; - SourceLineInfo getSourceInfo() const; - std::string getTestMacroName() const; - void discardDecomposedExpression() const; - void expandDecomposedExpression() const; +// end catch_assertioninfo.h +// start catch_decomposer.h - protected: - AssertionInfo m_info; - AssertionResultData m_resultData; - }; +// start catch_tostring.h -} // end namespace Catch +#include <vector> +#include <cstddef> +#include <type_traits> +#include <string> +// start catch_stream.h -// #included from: catch_matchers.hpp -#define TWOBLUECUBES_CATCH_MATCHERS_HPP_INCLUDED +#include <iosfwd> +#include <cstddef> +#include <ostream> namespace Catch { -namespace Matchers { - namespace Impl { - - template<typename ArgT> struct MatchAllOf; - template<typename ArgT> struct MatchAnyOf; - template<typename ArgT> struct MatchNotOf; - class MatcherUntypedBase { - public: - std::string toString() const { - if( m_cachedToString.empty() ) - m_cachedToString = describe(); - return m_cachedToString; - } + std::ostream& cout(); + std::ostream& cerr(); + std::ostream& clog(); - protected: - virtual ~MatcherUntypedBase(); - virtual std::string describe() const = 0; - mutable std::string m_cachedToString; - private: - MatcherUntypedBase& operator = ( MatcherUntypedBase const& ); - }; + class StringRef; - template<typename ObjectT> - struct MatcherMethod { - virtual bool match( ObjectT const& arg ) const = 0; - }; - template<typename PtrT> - struct MatcherMethod<PtrT*> { - virtual bool match( PtrT* arg ) const = 0; - }; + struct IStream { + virtual ~IStream(); + virtual std::ostream& stream() const = 0; + }; - template<typename ObjectT, typename ComparatorT = ObjectT> - struct MatcherBase : MatcherUntypedBase, MatcherMethod<ObjectT> { + auto makeStream( StringRef const &filename ) -> IStream const*; - MatchAllOf<ComparatorT> operator && ( MatcherBase const& other ) const; - MatchAnyOf<ComparatorT> operator || ( MatcherBase const& other ) const; - MatchNotOf<ComparatorT> operator ! () const; - }; + class ReusableStringStream : NonCopyable { + std::size_t m_index; + std::ostream* m_oss; + public: + ReusableStringStream(); + ~ReusableStringStream(); - template<typename ArgT> - struct MatchAllOf : MatcherBase<ArgT> { - virtual bool match( ArgT const& arg ) const CATCH_OVERRIDE { - for( std::size_t i = 0; i < m_matchers.size(); ++i ) { - if (!m_matchers[i]->match(arg)) - return false; - } - return true; - } - virtual std::string describe() const CATCH_OVERRIDE { - std::string description; - description.reserve( 4 + m_matchers.size()*32 ); - description += "( "; - for( std::size_t i = 0; i < m_matchers.size(); ++i ) { - if( i != 0 ) - description += " and "; - description += m_matchers[i]->toString(); - } - description += " )"; - return description; - } + auto str() const -> std::string; - MatchAllOf<ArgT>& operator && ( MatcherBase<ArgT> const& other ) { - m_matchers.push_back( &other ); - return *this; - } + template<typename T> + auto operator << ( T const& value ) -> ReusableStringStream& { + *m_oss << value; + return *this; + } + auto get() -> std::ostream& { return *m_oss; } + }; +} - std::vector<MatcherBase<ArgT> const*> m_matchers; - }; - template<typename ArgT> - struct MatchAnyOf : MatcherBase<ArgT> { +// end catch_stream.h +// start catch_interfaces_enum_values_registry.h - virtual bool match( ArgT const& arg ) const CATCH_OVERRIDE { - for( std::size_t i = 0; i < m_matchers.size(); ++i ) { - if (m_matchers[i]->match(arg)) - return true; - } - return false; - } - virtual std::string describe() const CATCH_OVERRIDE { - std::string description; - description.reserve( 4 + m_matchers.size()*32 ); - description += "( "; - for( std::size_t i = 0; i < m_matchers.size(); ++i ) { - if( i != 0 ) - description += " or "; - description += m_matchers[i]->toString(); - } - description += " )"; - return description; - } +#include <vector> - MatchAnyOf<ArgT>& operator || ( MatcherBase<ArgT> const& other ) { - m_matchers.push_back( &other ); - return *this; - } +namespace Catch { - std::vector<MatcherBase<ArgT> const*> m_matchers; - }; + namespace Detail { + struct EnumInfo { + StringRef m_name; + std::vector<std::pair<int, StringRef>> m_values; - template<typename ArgT> - struct MatchNotOf : MatcherBase<ArgT> { + ~EnumInfo(); - MatchNotOf( MatcherBase<ArgT> const& underlyingMatcher ) : m_underlyingMatcher( underlyingMatcher ) {} + StringRef lookup( int value ) const; + }; + } // namespace Detail - virtual bool match( ArgT const& arg ) const CATCH_OVERRIDE { - return !m_underlyingMatcher.match( arg ); - } + struct IMutableEnumValuesRegistry { + virtual ~IMutableEnumValuesRegistry(); - virtual std::string describe() const CATCH_OVERRIDE { - return "not " + m_underlyingMatcher.toString(); - } - MatcherBase<ArgT> const& m_underlyingMatcher; - }; + virtual Detail::EnumInfo const& registerEnum( StringRef enumName, StringRef allEnums, std::vector<int> const& values ) = 0; - template<typename ObjectT, typename ComparatorT> - MatchAllOf<ComparatorT> MatcherBase<ObjectT, ComparatorT>::operator && ( MatcherBase const& other ) const { - return MatchAllOf<ComparatorT>() && *this && other; - } - template<typename ObjectT, typename ComparatorT> - MatchAnyOf<ComparatorT> MatcherBase<ObjectT, ComparatorT>::operator || ( MatcherBase const& other ) const { - return MatchAnyOf<ComparatorT>() || *this || other; + template<typename E> + Detail::EnumInfo const& registerEnum( StringRef enumName, StringRef allEnums, std::initializer_list<E> values ) { + static_assert(sizeof(int) >= sizeof(E), "Cannot serialize enum to int"); + std::vector<int> intValues; + intValues.reserve( values.size() ); + for( auto enumValue : values ) + intValues.push_back( static_cast<int>( enumValue ) ); + return registerEnum( enumName, allEnums, intValues ); } - template<typename ObjectT, typename ComparatorT> - MatchNotOf<ComparatorT> MatcherBase<ObjectT, ComparatorT>::operator ! () const { - return MatchNotOf<ComparatorT>( *this ); - } - - } // namespace Impl + }; - // The following functions create the actual matcher objects. - // This allows the types to be inferred - // - deprecated: prefer ||, && and ! - template<typename T> - Impl::MatchNotOf<T> Not( Impl::MatcherBase<T> const& underlyingMatcher ) { - return Impl::MatchNotOf<T>( underlyingMatcher ); - } - template<typename T> - Impl::MatchAllOf<T> AllOf( Impl::MatcherBase<T> const& m1, Impl::MatcherBase<T> const& m2 ) { - return Impl::MatchAllOf<T>() && m1 && m2; - } - template<typename T> - Impl::MatchAllOf<T> AllOf( Impl::MatcherBase<T> const& m1, Impl::MatcherBase<T> const& m2, Impl::MatcherBase<T> const& m3 ) { - return Impl::MatchAllOf<T>() && m1 && m2 && m3; - } - template<typename T> - Impl::MatchAnyOf<T> AnyOf( Impl::MatcherBase<T> const& m1, Impl::MatcherBase<T> const& m2 ) { - return Impl::MatchAnyOf<T>() || m1 || m2; - } - template<typename T> - Impl::MatchAnyOf<T> AnyOf( Impl::MatcherBase<T> const& m1, Impl::MatcherBase<T> const& m2, Impl::MatcherBase<T> const& m3 ) { - return Impl::MatchAnyOf<T>() || m1 || m2 || m3; - } +} // Catch -} // namespace Matchers +// end catch_interfaces_enum_values_registry.h -using namespace Matchers; -using Matchers::Impl::MatcherBase; +#ifdef CATCH_CONFIG_CPP17_STRING_VIEW +#include <string_view> +#endif -} // namespace Catch +#ifdef __OBJC__ +// start catch_objc_arc.hpp -namespace Catch { - - struct TestFailureException{}; - - template<typename T> class ExpressionLhs; - - struct CopyableStream { - CopyableStream() {} - CopyableStream( CopyableStream const& other ) { - oss << other.oss.str(); - } - CopyableStream& operator=( CopyableStream const& other ) { - oss.str(std::string()); - oss << other.oss.str(); - return *this; - } - std::ostringstream oss; - }; - - class ResultBuilder : public DecomposedExpression { - public: - ResultBuilder( char const* macroName, - SourceLineInfo const& lineInfo, - char const* capturedExpression, - ResultDisposition::Flags resultDisposition, - char const* secondArg = "" ); - ~ResultBuilder(); - - template<typename T> - ExpressionLhs<T const&> operator <= ( T const& operand ); - ExpressionLhs<bool> operator <= ( bool value ); - - template<typename T> - ResultBuilder& operator << ( T const& value ) { - stream().oss << value; - return *this; - } - - ResultBuilder& setResultType( ResultWas::OfType result ); - ResultBuilder& setResultType( bool result ); - - void endExpression( DecomposedExpression const& expr ); - - virtual void reconstructExpression( std::string& dest ) const CATCH_OVERRIDE; - - AssertionResult build() const; - AssertionResult build( DecomposedExpression const& expr ) const; - - void useActiveException( ResultDisposition::Flags resultDisposition = ResultDisposition::Normal ); - void captureResult( ResultWas::OfType resultType ); - void captureExpression(); - void captureExpectedException( std::string const& expectedMessage ); - void captureExpectedException( Matchers::Impl::MatcherBase<std::string> const& matcher ); - void handleResult( AssertionResult const& result ); - void react(); - bool shouldDebugBreak() const; - bool allowThrows() const; - - template<typename ArgT, typename MatcherT> - void captureMatch( ArgT const& arg, MatcherT const& matcher, char const* matcherString ); - - void setExceptionGuard(); - void unsetExceptionGuard(); - - private: - AssertionInfo m_assertionInfo; - AssertionResultData m_data; - - CopyableStream &stream() - { - if(!m_usedStream) - { - m_usedStream = true; - m_stream().oss.str(""); - } - return m_stream(); - } - - static CopyableStream &m_stream() - { - static CopyableStream s; - return s; - } - - bool m_shouldDebugBreak; - bool m_shouldThrow; - bool m_guardException; - bool m_usedStream; - }; - -} // namespace Catch - -// Include after due to circular dependency: -// #included from: catch_expression_lhs.hpp -#define TWOBLUECUBES_CATCH_EXPRESSION_LHS_HPP_INCLUDED - -// #included from: catch_evaluate.hpp -#define TWOBLUECUBES_CATCH_EVALUATE_HPP_INCLUDED - -#ifdef _MSC_VER -#pragma warning(push) -#pragma warning(disable:4389) // '==' : signed/unsigned mismatch -#pragma warning(disable:4018) // more "signed/unsigned mismatch" -#pragma warning(disable:4312) // Converting int to T* using reinterpret_cast (issue on x64 platform) -#endif - -#include <cstddef> - -namespace Catch { -namespace Internal { - - enum Operator { - IsEqualTo, - IsNotEqualTo, - IsLessThan, - IsGreaterThan, - IsLessThanOrEqualTo, - IsGreaterThanOrEqualTo - }; - - template<Operator Op> struct OperatorTraits { static const char* getName(){ return "*error*"; } }; - template<> struct OperatorTraits<IsEqualTo> { static const char* getName(){ return "=="; } }; - template<> struct OperatorTraits<IsNotEqualTo> { static const char* getName(){ return "!="; } }; - template<> struct OperatorTraits<IsLessThan> { static const char* getName(){ return "<"; } }; - template<> struct OperatorTraits<IsGreaterThan> { static const char* getName(){ return ">"; } }; - template<> struct OperatorTraits<IsLessThanOrEqualTo> { static const char* getName(){ return "<="; } }; - template<> struct OperatorTraits<IsGreaterThanOrEqualTo>{ static const char* getName(){ return ">="; } }; - - template<typename T> - T& opCast(T const& t) { return const_cast<T&>(t); } - -// nullptr_t support based on pull request #154 from Konstantin Baumann -#ifdef CATCH_CONFIG_CPP11_NULLPTR - inline std::nullptr_t opCast(std::nullptr_t) { return nullptr; } -#endif // CATCH_CONFIG_CPP11_NULLPTR - - // So the compare overloads can be operator agnostic we convey the operator as a template - // enum, which is used to specialise an Evaluator for doing the comparison. - template<typename T1, typename T2, Operator Op> - struct Evaluator{}; - - template<typename T1, typename T2> - struct Evaluator<T1, T2, IsEqualTo> { - static bool evaluate( T1 const& lhs, T2 const& rhs) { - return bool( opCast( lhs ) == opCast( rhs ) ); - } - }; - template<typename T1, typename T2> - struct Evaluator<T1, T2, IsNotEqualTo> { - static bool evaluate( T1 const& lhs, T2 const& rhs ) { - return bool( opCast( lhs ) != opCast( rhs ) ); - } - }; - template<typename T1, typename T2> - struct Evaluator<T1, T2, IsLessThan> { - static bool evaluate( T1 const& lhs, T2 const& rhs ) { - return bool( opCast( lhs ) < opCast( rhs ) ); - } - }; - template<typename T1, typename T2> - struct Evaluator<T1, T2, IsGreaterThan> { - static bool evaluate( T1 const& lhs, T2 const& rhs ) { - return bool( opCast( lhs ) > opCast( rhs ) ); - } - }; - template<typename T1, typename T2> - struct Evaluator<T1, T2, IsGreaterThanOrEqualTo> { - static bool evaluate( T1 const& lhs, T2 const& rhs ) { - return bool( opCast( lhs ) >= opCast( rhs ) ); - } - }; - template<typename T1, typename T2> - struct Evaluator<T1, T2, IsLessThanOrEqualTo> { - static bool evaluate( T1 const& lhs, T2 const& rhs ) { - return bool( opCast( lhs ) <= opCast( rhs ) ); - } - }; - - template<Operator Op, typename T1, typename T2> - bool applyEvaluator( T1 const& lhs, T2 const& rhs ) { - return Evaluator<T1, T2, Op>::evaluate( lhs, rhs ); - } - - // This level of indirection allows us to specialise for integer types - // to avoid signed/ unsigned warnings - - // "base" overload - template<Operator Op, typename T1, typename T2> - bool compare( T1 const& lhs, T2 const& rhs ) { - return Evaluator<T1, T2, Op>::evaluate( lhs, rhs ); - } - - // unsigned X to int - template<Operator Op> bool compare( unsigned int lhs, int rhs ) { - return applyEvaluator<Op>( lhs, static_cast<unsigned int>( rhs ) ); - } - template<Operator Op> bool compare( unsigned long lhs, int rhs ) { - return applyEvaluator<Op>( lhs, static_cast<unsigned int>( rhs ) ); - } - template<Operator Op> bool compare( unsigned char lhs, int rhs ) { - return applyEvaluator<Op>( lhs, static_cast<unsigned int>( rhs ) ); - } - - // unsigned X to long - template<Operator Op> bool compare( unsigned int lhs, long rhs ) { - return applyEvaluator<Op>( lhs, static_cast<unsigned long>( rhs ) ); - } - template<Operator Op> bool compare( unsigned long lhs, long rhs ) { - return applyEvaluator<Op>( lhs, static_cast<unsigned long>( rhs ) ); - } - template<Operator Op> bool compare( unsigned char lhs, long rhs ) { - return applyEvaluator<Op>( lhs, static_cast<unsigned long>( rhs ) ); - } - - // int to unsigned X - template<Operator Op> bool compare( int lhs, unsigned int rhs ) { - return applyEvaluator<Op>( static_cast<unsigned int>( lhs ), rhs ); - } - template<Operator Op> bool compare( int lhs, unsigned long rhs ) { - return applyEvaluator<Op>( static_cast<unsigned int>( lhs ), rhs ); - } - template<Operator Op> bool compare( int lhs, unsigned char rhs ) { - return applyEvaluator<Op>( static_cast<unsigned int>( lhs ), rhs ); - } - - // long to unsigned X - template<Operator Op> bool compare( long lhs, unsigned int rhs ) { - return applyEvaluator<Op>( static_cast<unsigned long>( lhs ), rhs ); - } - template<Operator Op> bool compare( long lhs, unsigned long rhs ) { - return applyEvaluator<Op>( static_cast<unsigned long>( lhs ), rhs ); - } - template<Operator Op> bool compare( long lhs, unsigned char rhs ) { - return applyEvaluator<Op>( static_cast<unsigned long>( lhs ), rhs ); - } - - // pointer to long (when comparing against NULL) - template<Operator Op, typename T> bool compare( long lhs, T* rhs ) { - return Evaluator<T*, T*, Op>::evaluate( reinterpret_cast<T*>( lhs ), rhs ); - } - template<Operator Op, typename T> bool compare( T* lhs, long rhs ) { - return Evaluator<T*, T*, Op>::evaluate( lhs, reinterpret_cast<T*>( rhs ) ); - } - - // pointer to int (when comparing against NULL) - template<Operator Op, typename T> bool compare( int lhs, T* rhs ) { - return Evaluator<T*, T*, Op>::evaluate( reinterpret_cast<T*>( lhs ), rhs ); - } - template<Operator Op, typename T> bool compare( T* lhs, int rhs ) { - return Evaluator<T*, T*, Op>::evaluate( lhs, reinterpret_cast<T*>( rhs ) ); - } - -#ifdef CATCH_CONFIG_CPP11_LONG_LONG - // long long to unsigned X - template<Operator Op> bool compare( long long lhs, unsigned int rhs ) { - return applyEvaluator<Op>( static_cast<unsigned long>( lhs ), rhs ); - } - template<Operator Op> bool compare( long long lhs, unsigned long rhs ) { - return applyEvaluator<Op>( static_cast<unsigned long>( lhs ), rhs ); - } - template<Operator Op> bool compare( long long lhs, unsigned long long rhs ) { - return applyEvaluator<Op>( static_cast<unsigned long>( lhs ), rhs ); - } - template<Operator Op> bool compare( long long lhs, unsigned char rhs ) { - return applyEvaluator<Op>( static_cast<unsigned long>( lhs ), rhs ); - } - - // unsigned long long to X - template<Operator Op> bool compare( unsigned long long lhs, int rhs ) { - return applyEvaluator<Op>( static_cast<long>( lhs ), rhs ); - } - template<Operator Op> bool compare( unsigned long long lhs, long rhs ) { - return applyEvaluator<Op>( static_cast<long>( lhs ), rhs ); - } - template<Operator Op> bool compare( unsigned long long lhs, long long rhs ) { - return applyEvaluator<Op>( static_cast<long>( lhs ), rhs ); - } - template<Operator Op> bool compare( unsigned long long lhs, char rhs ) { - return applyEvaluator<Op>( static_cast<long>( lhs ), rhs ); - } - - // pointer to long long (when comparing against NULL) - template<Operator Op, typename T> bool compare( long long lhs, T* rhs ) { - return Evaluator<T*, T*, Op>::evaluate( reinterpret_cast<T*>( lhs ), rhs ); - } - template<Operator Op, typename T> bool compare( T* lhs, long long rhs ) { - return Evaluator<T*, T*, Op>::evaluate( lhs, reinterpret_cast<T*>( rhs ) ); - } -#endif // CATCH_CONFIG_CPP11_LONG_LONG - -#ifdef CATCH_CONFIG_CPP11_NULLPTR - // pointer to nullptr_t (when comparing against nullptr) - template<Operator Op, typename T> bool compare( std::nullptr_t, T* rhs ) { - return Evaluator<T*, T*, Op>::evaluate( nullptr, rhs ); - } - template<Operator Op, typename T> bool compare( T* lhs, std::nullptr_t ) { - return Evaluator<T*, T*, Op>::evaluate( lhs, nullptr ); - } -#endif // CATCH_CONFIG_CPP11_NULLPTR - -} // end of namespace Internal -} // end of namespace Catch - -#ifdef _MSC_VER -#pragma warning(pop) -#endif - -// #included from: catch_tostring.h -#define TWOBLUECUBES_CATCH_TOSTRING_H_INCLUDED - -#include <sstream> -#include <iomanip> -#include <limits> -#include <vector> -#include <cstddef> - -#ifdef __OBJC__ -// #included from: catch_objc_arc.hpp -#define TWOBLUECUBES_CATCH_OBJC_ARC_HPP_INCLUDED - -#import <Foundation/Foundation.h> +#import <Foundation/Foundation.h> #ifdef __has_feature #define CATCH_ARC_ENABLED __has_feature(objc_arc) @@ -1551,883 +1540,1340 @@ inline id performOptionalSelector( id obj, SEL sel ) { #define CATCH_ARC_STRONG __strong #endif +// end catch_objc_arc.hpp #endif -#ifdef CATCH_CONFIG_CPP11_TUPLE -#include <tuple> -#endif - -#ifdef CATCH_CONFIG_CPP11_IS_ENUM -#include <type_traits> +#ifdef _MSC_VER +#pragma warning(push) +#pragma warning(disable:4180) // We attempt to stream a function (address) by const&, which MSVC complains about but is harmless #endif namespace Catch { + namespace Detail { -// Why we're here. -template<typename T> -std::string toString( T const& value ); + extern const std::string unprintableString; + + std::string rawMemoryToString( const void *object, std::size_t size ); + + template<typename T> + std::string rawMemoryToString( const T& object ) { + return rawMemoryToString( &object, sizeof(object) ); + } + + template<typename T> + class IsStreamInsertable { + template<typename Stream, typename U> + static auto test(int) + -> decltype(std::declval<Stream&>() << std::declval<U>(), std::true_type()); + + template<typename, typename> + static auto test(...)->std::false_type; -// Built in overloads + public: + static const bool value = decltype(test<std::ostream, const T&>(0))::value; + }; + + template<typename E> + std::string convertUnknownEnumToString( E e ); + + template<typename T> + typename std::enable_if< + !std::is_enum<T>::value && !std::is_base_of<std::exception, T>::value, + std::string>::type convertUnstreamable( T const& ) { + return Detail::unprintableString; + } + template<typename T> + typename std::enable_if< + !std::is_enum<T>::value && std::is_base_of<std::exception, T>::value, + std::string>::type convertUnstreamable(T const& ex) { + return ex.what(); + } -std::string toString( std::string const& value ); -std::string toString( std::wstring const& value ); -std::string toString( const char* const value ); -std::string toString( char* const value ); -std::string toString( const wchar_t* const value ); -std::string toString( wchar_t* const value ); -std::string toString( int value ); -std::string toString( unsigned long value ); -std::string toString( unsigned int value ); -std::string toString( const double value ); -std::string toString( const float value ); -std::string toString( bool value ); -std::string toString( char value ); -std::string toString( signed char value ); -std::string toString( unsigned char value ); + template<typename T> + typename std::enable_if< + std::is_enum<T>::value + , std::string>::type convertUnstreamable( T const& value ) { + return convertUnknownEnumToString( value ); + } -#ifdef CATCH_CONFIG_CPP11_LONG_LONG -std::string toString( long long value ); -std::string toString( unsigned long long value ); +#if defined(_MANAGED) + //! Convert a CLR string to a utf8 std::string + template<typename T> + std::string clrReferenceToString( T^ ref ) { + if (ref == nullptr) + return std::string("null"); + auto bytes = System::Text::Encoding::UTF8->GetBytes(ref->ToString()); + cli::pin_ptr<System::Byte> p = &bytes[0]; + return std::string(reinterpret_cast<char const *>(p), bytes->Length); + } #endif -#ifdef CATCH_CONFIG_CPP11_NULLPTR -std::string toString( std::nullptr_t ); + } // namespace Detail + + // If we decide for C++14, change these to enable_if_ts + template <typename T, typename = void> + struct StringMaker { + template <typename Fake = T> + static + typename std::enable_if<::Catch::Detail::IsStreamInsertable<Fake>::value, std::string>::type + convert(const Fake& value) { + ReusableStringStream rss; + // NB: call using the function-like syntax to avoid ambiguity with + // user-defined templated operator<< under clang. + rss.operator<<(value); + return rss.str(); + } + + template <typename Fake = T> + static + typename std::enable_if<!::Catch::Detail::IsStreamInsertable<Fake>::value, std::string>::type + convert( const Fake& value ) { +#if !defined(CATCH_CONFIG_FALLBACK_STRINGIFIER) + return Detail::convertUnstreamable(value); +#else + return CATCH_CONFIG_FALLBACK_STRINGIFIER(value); #endif + } + }; -#ifdef __OBJC__ - std::string toString( NSString const * const& nsstring ); - std::string toString( NSString * CATCH_ARC_STRONG & nsstring ); - std::string toString( NSObject* const& nsObject ); + namespace Detail { + + // This function dispatches all stringification requests inside of Catch. + // Should be preferably called fully qualified, like ::Catch::Detail::stringify + template <typename T> + std::string stringify(const T& e) { + return ::Catch::StringMaker<typename std::remove_cv<typename std::remove_reference<T>::type>::type>::convert(e); + } + + template<typename E> + std::string convertUnknownEnumToString( E e ) { + return ::Catch::Detail::stringify(static_cast<typename std::underlying_type<E>::type>(e)); + } + +#if defined(_MANAGED) + template <typename T> + std::string stringify( T^ e ) { + return ::Catch::StringMaker<T^>::convert(e); + } #endif -namespace Detail { + } // namespace Detail - extern const std::string unprintableString; + // Some predefined specializations - #if !defined(CATCH_CONFIG_CPP11_STREAM_INSERTABLE_CHECK) - struct BorgType { - template<typename T> BorgType( T const& ); + template<> + struct StringMaker<std::string> { + static std::string convert(const std::string& str); }; - struct TrueType { char sizer[1]; }; - struct FalseType { char sizer[2]; }; - - TrueType& testStreamable( std::ostream& ); - FalseType testStreamable( FalseType ); +#ifdef CATCH_CONFIG_CPP17_STRING_VIEW + template<> + struct StringMaker<std::string_view> { + static std::string convert(std::string_view str); + }; +#endif - FalseType operator<<( std::ostream const&, BorgType const& ); + template<> + struct StringMaker<char const *> { + static std::string convert(char const * str); + }; + template<> + struct StringMaker<char *> { + static std::string convert(char * str); + }; - template<typename T> - struct IsStreamInsertable { - static std::ostream &s; - static T const&t; - enum { value = sizeof( testStreamable(s << t) ) == sizeof( TrueType ) }; +#ifdef CATCH_CONFIG_WCHAR + template<> + struct StringMaker<std::wstring> { + static std::string convert(const std::wstring& wstr); }; -#else - template<typename T> - class IsStreamInsertable { - template<typename SS, typename TT> - static auto test(int) - -> decltype( std::declval<SS&>() << std::declval<TT>(), std::true_type() ); - template<typename, typename> - static auto test(...) -> std::false_type; +# ifdef CATCH_CONFIG_CPP17_STRING_VIEW + template<> + struct StringMaker<std::wstring_view> { + static std::string convert(std::wstring_view str); + }; +# endif - public: - static const bool value = decltype(test<std::ostream,const T&>(0))::value; + template<> + struct StringMaker<wchar_t const *> { + static std::string convert(wchar_t const * str); + }; + template<> + struct StringMaker<wchar_t *> { + static std::string convert(wchar_t * str); }; #endif -#if defined(CATCH_CONFIG_CPP11_IS_ENUM) - template<typename T, - bool IsEnum = std::is_enum<T>::value - > - struct EnumStringMaker - { - static std::string convert( T const& ) { return unprintableString; } + // TBD: Should we use `strnlen` to ensure that we don't go out of the buffer, + // while keeping string semantics? + template<int SZ> + struct StringMaker<char[SZ]> { + static std::string convert(char const* str) { + return ::Catch::Detail::stringify(std::string{ str }); + } }; - - template<typename T> - struct EnumStringMaker<T,true> - { - static std::string convert( T const& v ) - { - return ::Catch::toString( - static_cast<typename std::underlying_type<T>::type>(v) - ); + template<int SZ> + struct StringMaker<signed char[SZ]> { + static std::string convert(signed char const* str) { + return ::Catch::Detail::stringify(std::string{ reinterpret_cast<char const *>(str) }); } }; -#endif - template<bool C> - struct StringMakerBase { -#if defined(CATCH_CONFIG_CPP11_IS_ENUM) - template<typename T> - static std::string convert( T const& v ) - { - return EnumStringMaker<T>::convert( v ); + template<int SZ> + struct StringMaker<unsigned char[SZ]> { + static std::string convert(unsigned char const* str) { + return ::Catch::Detail::stringify(std::string{ reinterpret_cast<char const *>(str) }); } -#else - template<typename T> - static std::string convert( T const& ) { return unprintableString; } -#endif }; +#if defined(CATCH_CONFIG_CPP17_BYTE) template<> - struct StringMakerBase<true> { - template<typename T> - static std::string convert( T const& _value ) { - std::ostringstream oss; - oss << _value; - return oss.str(); - } + struct StringMaker<std::byte> { + static std::string convert(std::byte value); + }; +#endif // defined(CATCH_CONFIG_CPP17_BYTE) + template<> + struct StringMaker<int> { + static std::string convert(int value); + }; + template<> + struct StringMaker<long> { + static std::string convert(long value); + }; + template<> + struct StringMaker<long long> { + static std::string convert(long long value); + }; + template<> + struct StringMaker<unsigned int> { + static std::string convert(unsigned int value); + }; + template<> + struct StringMaker<unsigned long> { + static std::string convert(unsigned long value); + }; + template<> + struct StringMaker<unsigned long long> { + static std::string convert(unsigned long long value); }; - std::string rawMemoryToString( const void *object, std::size_t size ); + template<> + struct StringMaker<bool> { + static std::string convert(bool b); + }; - template<typename T> - std::string rawMemoryToString( const T& object ) { - return rawMemoryToString( &object, sizeof(object) ); - } + template<> + struct StringMaker<char> { + static std::string convert(char c); + }; + template<> + struct StringMaker<signed char> { + static std::string convert(signed char c); + }; + template<> + struct StringMaker<unsigned char> { + static std::string convert(unsigned char c); + }; -} // end namespace Detail + template<> + struct StringMaker<std::nullptr_t> { + static std::string convert(std::nullptr_t); + }; -template<typename T> -struct StringMaker : - Detail::StringMakerBase<Detail::IsStreamInsertable<T>::value> {}; + template<> + struct StringMaker<float> { + static std::string convert(float value); + static int precision; + }; -template<typename T> -struct StringMaker<T*> { - template<typename U> - static std::string convert( U* p ) { - if( !p ) - return "NULL"; - else - return Detail::rawMemoryToString( p ); - } -}; + template<> + struct StringMaker<double> { + static std::string convert(double value); + static int precision; + }; -template<typename R, typename C> -struct StringMaker<R C::*> { - static std::string convert( R C::* p ) { - if( !p ) - return "NULL"; - else - return Detail::rawMemoryToString( p ); - } -}; + template <typename T> + struct StringMaker<T*> { + template <typename U> + static std::string convert(U* p) { + if (p) { + return ::Catch::Detail::rawMemoryToString(p); + } else { + return "nullptr"; + } + } + }; -namespace Detail { - template<typename InputIterator> - std::string rangeToString( InputIterator first, InputIterator last ); -} - -//template<typename T, typename Allocator> -//struct StringMaker<std::vector<T, Allocator> > { -// static std::string convert( std::vector<T,Allocator> const& v ) { -// return Detail::rangeToString( v.begin(), v.end() ); -// } -//}; - -template<typename T, typename Allocator> -std::string toString( std::vector<T,Allocator> const& v ) { - return Detail::rangeToString( v.begin(), v.end() ); -} - -#ifdef CATCH_CONFIG_CPP11_TUPLE - -// toString for tuples -namespace TupleDetail { - template< - typename Tuple, - std::size_t N = 0, - bool = (N < std::tuple_size<Tuple>::value) - > - struct ElementPrinter { - static void print( const Tuple& tuple, std::ostream& os ) - { - os << ( N ? ", " : " " ) - << Catch::toString(std::get<N>(tuple)); - ElementPrinter<Tuple,N+1>::print(tuple,os); - } - }; + template <typename R, typename C> + struct StringMaker<R C::*> { + static std::string convert(R C::* p) { + if (p) { + return ::Catch::Detail::rawMemoryToString(p); + } else { + return "nullptr"; + } + } + }; - template< - typename Tuple, - std::size_t N - > - struct ElementPrinter<Tuple,N,false> { - static void print( const Tuple&, std::ostream& ) {} - }; +#if defined(_MANAGED) + template <typename T> + struct StringMaker<T^> { + static std::string convert( T^ ref ) { + return ::Catch::Detail::clrReferenceToString(ref); + } + }; +#endif -} + namespace Detail { + template<typename InputIterator, typename Sentinel = InputIterator> + std::string rangeToString(InputIterator first, Sentinel last) { + ReusableStringStream rss; + rss << "{ "; + if (first != last) { + rss << ::Catch::Detail::stringify(*first); + for (++first; first != last; ++first) + rss << ", " << ::Catch::Detail::stringify(*first); + } + rss << " }"; + return rss.str(); + } + } -template<typename ...Types> -struct StringMaker<std::tuple<Types...>> { +#ifdef __OBJC__ + template<> + struct StringMaker<NSString*> { + static std::string convert(NSString * nsstring) { + if (!nsstring) + return "nil"; + return std::string("@") + [nsstring UTF8String]; + } + }; + template<> + struct StringMaker<NSObject*> { + static std::string convert(NSObject* nsObject) { + return ::Catch::Detail::stringify([nsObject description]); + } - static std::string convert( const std::tuple<Types...>& tuple ) - { - std::ostringstream os; - os << '{'; - TupleDetail::ElementPrinter<std::tuple<Types...>>::print( tuple, os ); - os << " }"; - return os.str(); - } -}; -#endif // CATCH_CONFIG_CPP11_TUPLE + }; + namespace Detail { + inline std::string stringify( NSString* nsstring ) { + return StringMaker<NSString*>::convert( nsstring ); + } -namespace Detail { - template<typename T> - std::string makeString( T const& value ) { - return StringMaker<T>::convert( value ); - } -} // end namespace Detail + } // namespace Detail +#endif // __OBJC__ -/// \brief converts any type to a string -/// -/// The default template forwards on to ostringstream - except when an -/// ostringstream overload does not exist - in which case it attempts to detect -/// that and writes {?}. -/// Overload (not specialise) this template for custom typs that you don't want -/// to provide an ostream overload for. -template<typename T> -std::string toString( T const& value ) { - return StringMaker<T>::convert( value ); +} // namespace Catch + +////////////////////////////////////////////////////// +// Separate std-lib types stringification, so it can be selectively enabled +// This means that we do not bring in + +#if defined(CATCH_CONFIG_ENABLE_ALL_STRINGMAKERS) +# define CATCH_CONFIG_ENABLE_PAIR_STRINGMAKER +# define CATCH_CONFIG_ENABLE_TUPLE_STRINGMAKER +# define CATCH_CONFIG_ENABLE_VARIANT_STRINGMAKER +# define CATCH_CONFIG_ENABLE_CHRONO_STRINGMAKER +# define CATCH_CONFIG_ENABLE_OPTIONAL_STRINGMAKER +#endif + +// Separate std::pair specialization +#if defined(CATCH_CONFIG_ENABLE_PAIR_STRINGMAKER) +#include <utility> +namespace Catch { + template<typename T1, typename T2> + struct StringMaker<std::pair<T1, T2> > { + static std::string convert(const std::pair<T1, T2>& pair) { + ReusableStringStream rss; + rss << "{ " + << ::Catch::Detail::stringify(pair.first) + << ", " + << ::Catch::Detail::stringify(pair.second) + << " }"; + return rss.str(); + } + }; } +#endif // CATCH_CONFIG_ENABLE_PAIR_STRINGMAKER +#if defined(CATCH_CONFIG_ENABLE_OPTIONAL_STRINGMAKER) && defined(CATCH_CONFIG_CPP17_OPTIONAL) +#include <optional> +namespace Catch { + template<typename T> + struct StringMaker<std::optional<T> > { + static std::string convert(const std::optional<T>& optional) { + ReusableStringStream rss; + if (optional.has_value()) { + rss << ::Catch::Detail::stringify(*optional); + } else { + rss << "{ }"; + } + return rss.str(); + } + }; +} +#endif // CATCH_CONFIG_ENABLE_OPTIONAL_STRINGMAKER + +// Separate std::tuple specialization +#if defined(CATCH_CONFIG_ENABLE_TUPLE_STRINGMAKER) +#include <tuple> +namespace Catch { namespace Detail { - template<typename InputIterator> - std::string rangeToString( InputIterator first, InputIterator last ) { - std::ostringstream oss; - oss << "{ "; - if( first != last ) { - oss << Catch::toString( *first ); - for( ++first ; first != last ; ++first ) - oss << ", " << Catch::toString( *first ); - } - oss << " }"; - return oss.str(); + template< + typename Tuple, + std::size_t N = 0, + bool = (N < std::tuple_size<Tuple>::value) + > + struct TupleElementPrinter { + static void print(const Tuple& tuple, std::ostream& os) { + os << (N ? ", " : " ") + << ::Catch::Detail::stringify(std::get<N>(tuple)); + TupleElementPrinter<Tuple, N + 1>::print(tuple, os); + } + }; + + template< + typename Tuple, + std::size_t N + > + struct TupleElementPrinter<Tuple, N, false> { + static void print(const Tuple&, std::ostream&) {} + }; + } -} -} // end namespace Catch + template<typename ...Types> + struct StringMaker<std::tuple<Types...>> { + static std::string convert(const std::tuple<Types...>& tuple) { + ReusableStringStream rss; + rss << '{'; + Detail::TupleElementPrinter<std::tuple<Types...>>::print(tuple, rss.get()); + rss << " }"; + return rss.str(); + } + }; +} +#endif // CATCH_CONFIG_ENABLE_TUPLE_STRINGMAKER +#if defined(CATCH_CONFIG_ENABLE_VARIANT_STRINGMAKER) && defined(CATCH_CONFIG_CPP17_VARIANT) +#include <variant> namespace Catch { + template<> + struct StringMaker<std::monostate> { + static std::string convert(const std::monostate&) { + return "{ }"; + } + }; -template<typename LhsT, Internal::Operator Op, typename RhsT> -class BinaryExpression; + template<typename... Elements> + struct StringMaker<std::variant<Elements...>> { + static std::string convert(const std::variant<Elements...>& variant) { + if (variant.valueless_by_exception()) { + return "{valueless variant}"; + } else { + return std::visit( + [](const auto& value) { + return ::Catch::Detail::stringify(value); + }, + variant + ); + } + } + }; +} +#endif // CATCH_CONFIG_ENABLE_VARIANT_STRINGMAKER -template<typename ArgT, typename MatcherT> -class MatchExpression; +namespace Catch { + // Import begin/ end from std here + using std::begin; + using std::end; + + namespace detail { + template <typename...> + struct void_type { + using type = void; + }; -// Wraps the LHS of an expression and overloads comparison operators -// for also capturing those and RHS (if any) -template<typename T> -class ExpressionLhs : public DecomposedExpression { -public: - ExpressionLhs( ResultBuilder& rb, T lhs ) : m_rb( rb ), m_lhs( lhs ), m_truthy(false) {} + template <typename T, typename = void> + struct is_range_impl : std::false_type { + }; - ExpressionLhs& operator = ( const ExpressionLhs& ); + template <typename T> + struct is_range_impl<T, typename void_type<decltype(begin(std::declval<T>()))>::type> : std::true_type { + }; + } // namespace detail - template<typename RhsT> - BinaryExpression<T, Internal::IsEqualTo, RhsT const&> - operator == ( RhsT const& rhs ) { - return captureExpression<Internal::IsEqualTo>( rhs ); - } + template <typename T> + struct is_range : detail::is_range_impl<T> { + }; - template<typename RhsT> - BinaryExpression<T, Internal::IsNotEqualTo, RhsT const&> - operator != ( RhsT const& rhs ) { - return captureExpression<Internal::IsNotEqualTo>( rhs ); - } +#if defined(_MANAGED) // Managed types are never ranges + template <typename T> + struct is_range<T^> { + static const bool value = false; + }; +#endif - template<typename RhsT> - BinaryExpression<T, Internal::IsLessThan, RhsT const&> - operator < ( RhsT const& rhs ) { - return captureExpression<Internal::IsLessThan>( rhs ); + template<typename Range> + std::string rangeToString( Range const& range ) { + return ::Catch::Detail::rangeToString( begin( range ), end( range ) ); } - template<typename RhsT> - BinaryExpression<T, Internal::IsGreaterThan, RhsT const&> - operator > ( RhsT const& rhs ) { - return captureExpression<Internal::IsGreaterThan>( rhs ); + // Handle vector<bool> specially + template<typename Allocator> + std::string rangeToString( std::vector<bool, Allocator> const& v ) { + ReusableStringStream rss; + rss << "{ "; + bool first = true; + for( bool b : v ) { + if( first ) + first = false; + else + rss << ", "; + rss << ::Catch::Detail::stringify( b ); + } + rss << " }"; + return rss.str(); } - template<typename RhsT> - BinaryExpression<T, Internal::IsLessThanOrEqualTo, RhsT const&> - operator <= ( RhsT const& rhs ) { - return captureExpression<Internal::IsLessThanOrEqualTo>( rhs ); - } + template<typename R> + struct StringMaker<R, typename std::enable_if<is_range<R>::value && !::Catch::Detail::IsStreamInsertable<R>::value>::type> { + static std::string convert( R const& range ) { + return rangeToString( range ); + } + }; - template<typename RhsT> - BinaryExpression<T, Internal::IsGreaterThanOrEqualTo, RhsT const&> - operator >= ( RhsT const& rhs ) { - return captureExpression<Internal::IsGreaterThanOrEqualTo>( rhs ); - } + template <typename T, int SZ> + struct StringMaker<T[SZ]> { + static std::string convert(T const(&arr)[SZ]) { + return rangeToString(arr); + } + }; - BinaryExpression<T, Internal::IsEqualTo, bool> operator == ( bool rhs ) { - return captureExpression<Internal::IsEqualTo>( rhs ); - } +} // namespace Catch - BinaryExpression<T, Internal::IsNotEqualTo, bool> operator != ( bool rhs ) { - return captureExpression<Internal::IsNotEqualTo>( rhs ); - } +// Separate std::chrono::duration specialization +#if defined(CATCH_CONFIG_ENABLE_CHRONO_STRINGMAKER) +#include <ctime> +#include <ratio> +#include <chrono> - void endExpression() { - m_truthy = m_lhs ? true : false; - m_rb - .setResultType( m_truthy ) - .endExpression( *this ); - } +namespace Catch { - virtual void reconstructExpression( std::string& dest ) const CATCH_OVERRIDE { - dest = Catch::toString( m_lhs ); - } +template <class Ratio> +struct ratio_string { + static std::string symbol(); +}; -private: - template<Internal::Operator Op, typename RhsT> - BinaryExpression<T, Op, RhsT&> captureExpression( RhsT& rhs ) const { - return BinaryExpression<T, Op, RhsT&>( m_rb, m_lhs, rhs ); - } +template <class Ratio> +std::string ratio_string<Ratio>::symbol() { + Catch::ReusableStringStream rss; + rss << '[' << Ratio::num << '/' + << Ratio::den << ']'; + return rss.str(); +} +template <> +struct ratio_string<std::atto> { + static std::string symbol(); +}; +template <> +struct ratio_string<std::femto> { + static std::string symbol(); +}; +template <> +struct ratio_string<std::pico> { + static std::string symbol(); +}; +template <> +struct ratio_string<std::nano> { + static std::string symbol(); +}; +template <> +struct ratio_string<std::micro> { + static std::string symbol(); +}; +template <> +struct ratio_string<std::milli> { + static std::string symbol(); +}; - template<Internal::Operator Op> - BinaryExpression<T, Op, bool> captureExpression( bool rhs ) const { - return BinaryExpression<T, Op, bool>( m_rb, m_lhs, rhs ); - } + //////////// + // std::chrono::duration specializations + template<typename Value, typename Ratio> + struct StringMaker<std::chrono::duration<Value, Ratio>> { + static std::string convert(std::chrono::duration<Value, Ratio> const& duration) { + ReusableStringStream rss; + rss << duration.count() << ' ' << ratio_string<Ratio>::symbol() << 's'; + return rss.str(); + } + }; + template<typename Value> + struct StringMaker<std::chrono::duration<Value, std::ratio<1>>> { + static std::string convert(std::chrono::duration<Value, std::ratio<1>> const& duration) { + ReusableStringStream rss; + rss << duration.count() << " s"; + return rss.str(); + } + }; + template<typename Value> + struct StringMaker<std::chrono::duration<Value, std::ratio<60>>> { + static std::string convert(std::chrono::duration<Value, std::ratio<60>> const& duration) { + ReusableStringStream rss; + rss << duration.count() << " m"; + return rss.str(); + } + }; + template<typename Value> + struct StringMaker<std::chrono::duration<Value, std::ratio<3600>>> { + static std::string convert(std::chrono::duration<Value, std::ratio<3600>> const& duration) { + ReusableStringStream rss; + rss << duration.count() << " h"; + return rss.str(); + } + }; -private: - ResultBuilder& m_rb; - T m_lhs; - bool m_truthy; -}; + //////////// + // std::chrono::time_point specialization + // Generic time_point cannot be specialized, only std::chrono::time_point<system_clock> + template<typename Clock, typename Duration> + struct StringMaker<std::chrono::time_point<Clock, Duration>> { + static std::string convert(std::chrono::time_point<Clock, Duration> const& time_point) { + return ::Catch::Detail::stringify(time_point.time_since_epoch()) + " since epoch"; + } + }; + // std::chrono::time_point<system_clock> specialization + template<typename Duration> + struct StringMaker<std::chrono::time_point<std::chrono::system_clock, Duration>> { + static std::string convert(std::chrono::time_point<std::chrono::system_clock, Duration> const& time_point) { + auto converted = std::chrono::system_clock::to_time_t(time_point); -template<typename LhsT, Internal::Operator Op, typename RhsT> -class BinaryExpression : public DecomposedExpression { -public: - BinaryExpression( ResultBuilder& rb, LhsT lhs, RhsT rhs ) - : m_rb( rb ), m_lhs( lhs ), m_rhs( rhs ) {} +#ifdef _MSC_VER + std::tm timeInfo = {}; + gmtime_s(&timeInfo, &converted); +#else + std::tm* timeInfo = std::gmtime(&converted); +#endif - BinaryExpression& operator = ( BinaryExpression& ); + auto const timeStampSize = sizeof("2017-01-16T17:06:45Z"); + char timeStamp[timeStampSize]; + const char * const fmt = "%Y-%m-%dT%H:%M:%SZ"; - void endExpression() const { - m_rb - .setResultType( Internal::compare<Op>( m_lhs, m_rhs ) ) - .endExpression( *this ); - } +#ifdef _MSC_VER + std::strftime(timeStamp, timeStampSize, fmt, &timeInfo); +#else + std::strftime(timeStamp, timeStampSize, fmt, timeInfo); +#endif + return std::string(timeStamp); + } + }; +} +#endif // CATCH_CONFIG_ENABLE_CHRONO_STRINGMAKER + +#define INTERNAL_CATCH_REGISTER_ENUM( enumName, ... ) \ +namespace Catch { \ + template<> struct StringMaker<enumName> { \ + static std::string convert( enumName value ) { \ + static const auto& enumInfo = ::Catch::getMutableRegistryHub().getMutableEnumValuesRegistry().registerEnum( #enumName, #__VA_ARGS__, { __VA_ARGS__ } ); \ + return static_cast<std::string>(enumInfo.lookup( static_cast<int>( value ) )); \ + } \ + }; \ +} - virtual bool isBinaryExpression() const CATCH_OVERRIDE { - return true; - } +#define CATCH_REGISTER_ENUM( enumName, ... ) INTERNAL_CATCH_REGISTER_ENUM( enumName, __VA_ARGS__ ) - virtual void reconstructExpression( std::string& dest ) const CATCH_OVERRIDE { - std::string lhs = Catch::toString( m_lhs ); - std::string rhs = Catch::toString( m_rhs ); - char delim = lhs.size() + rhs.size() < 40 && - lhs.find('\n') == std::string::npos && - rhs.find('\n') == std::string::npos ? ' ' : '\n'; - dest.reserve( 7 + lhs.size() + rhs.size() ); - // 2 for spaces around operator - // 2 for operator - // 2 for parentheses (conditionally added later) - // 1 for negation (conditionally added later) - dest = lhs; - dest += delim; - dest += Internal::OperatorTraits<Op>::getName(); - dest += delim; - dest += rhs; - } +#ifdef _MSC_VER +#pragma warning(pop) +#endif -private: - ResultBuilder& m_rb; - LhsT m_lhs; - RhsT m_rhs; -}; +// end catch_tostring.h +#include <iosfwd> -template<typename ArgT, typename MatcherT> -class MatchExpression : public DecomposedExpression { -public: - MatchExpression( ArgT arg, MatcherT matcher, char const* matcherString ) - : m_arg( arg ), m_matcher( matcher ), m_matcherString( matcherString ) {} +#ifdef _MSC_VER +#pragma warning(push) +#pragma warning(disable:4389) // '==' : signed/unsigned mismatch +#pragma warning(disable:4018) // more "signed/unsigned mismatch" +#pragma warning(disable:4312) // Converting int to T* using reinterpret_cast (issue on x64 platform) +#pragma warning(disable:4180) // qualifier applied to function type has no meaning +#pragma warning(disable:4800) // Forcing result to true or false +#endif - virtual bool isBinaryExpression() const CATCH_OVERRIDE { - return true; - } +namespace Catch { - virtual void reconstructExpression( std::string& dest ) const CATCH_OVERRIDE { - std::string matcherAsString = m_matcher.toString(); - dest = Catch::toString( m_arg ); - dest += ' '; - if( matcherAsString == Detail::unprintableString ) - dest += m_matcherString; - else - dest += matcherAsString; - } + struct ITransientExpression { + auto isBinaryExpression() const -> bool { return m_isBinaryExpression; } + auto getResult() const -> bool { return m_result; } + virtual void streamReconstructedExpression( std::ostream &os ) const = 0; -private: - ArgT m_arg; - MatcherT m_matcher; - char const* m_matcherString; -}; + ITransientExpression( bool isBinaryExpression, bool result ) + : m_isBinaryExpression( isBinaryExpression ), + m_result( result ) + {} -} // end namespace Catch + // We don't actually need a virtual destructor, but many static analysers + // complain if it's not here :-( + virtual ~ITransientExpression(); + bool m_isBinaryExpression; + bool m_result; -namespace Catch { + }; - template<typename T> - ExpressionLhs<T const&> ResultBuilder::operator <= ( T const& operand ) { - return ExpressionLhs<T const&>( *this, operand ); - } + void formatReconstructedExpression( std::ostream &os, std::string const& lhs, StringRef op, std::string const& rhs ); - inline ExpressionLhs<bool> ResultBuilder::operator <= ( bool value ) { - return ExpressionLhs<bool>( *this, value ); - } + template<typename LhsT, typename RhsT> + class BinaryExpr : public ITransientExpression { + LhsT m_lhs; + StringRef m_op; + RhsT m_rhs; - template<typename ArgT, typename MatcherT> - void ResultBuilder::captureMatch( ArgT const& arg, MatcherT const& matcher, - char const* matcherString ) { - MatchExpression<ArgT const&, MatcherT const&> expr( arg, matcher, matcherString ); - setResultType( matcher.match( arg ) ); - endExpression( expr ); - } + void streamReconstructedExpression( std::ostream &os ) const override { + formatReconstructedExpression + ( os, Catch::Detail::stringify( m_lhs ), m_op, Catch::Detail::stringify( m_rhs ) ); + } -} // namespace Catch + public: + BinaryExpr( bool comparisonResult, LhsT lhs, StringRef op, RhsT rhs ) + : ITransientExpression{ true, comparisonResult }, + m_lhs( lhs ), + m_op( op ), + m_rhs( rhs ) + {} -// #included from: catch_message.h -#define TWOBLUECUBES_CATCH_MESSAGE_H_INCLUDED + template<typename T> + auto operator && ( T ) const -> BinaryExpr<LhsT, RhsT const&> const { + static_assert(always_false<T>::value, + "chained comparisons are not supported inside assertions, " + "wrap the expression inside parentheses, or decompose it"); + } -#include <string> + template<typename T> + auto operator || ( T ) const -> BinaryExpr<LhsT, RhsT const&> const { + static_assert(always_false<T>::value, + "chained comparisons are not supported inside assertions, " + "wrap the expression inside parentheses, or decompose it"); + } -namespace Catch { + template<typename T> + auto operator == ( T ) const -> BinaryExpr<LhsT, RhsT const&> const { + static_assert(always_false<T>::value, + "chained comparisons are not supported inside assertions, " + "wrap the expression inside parentheses, or decompose it"); + } - struct MessageInfo { - MessageInfo( std::string const& _macroName, - SourceLineInfo const& _lineInfo, - ResultWas::OfType _type ); + template<typename T> + auto operator != ( T ) const -> BinaryExpr<LhsT, RhsT const&> const { + static_assert(always_false<T>::value, + "chained comparisons are not supported inside assertions, " + "wrap the expression inside parentheses, or decompose it"); + } - std::string macroName; - SourceLineInfo lineInfo; - ResultWas::OfType type; - std::string message; - unsigned int sequence; + template<typename T> + auto operator > ( T ) const -> BinaryExpr<LhsT, RhsT const&> const { + static_assert(always_false<T>::value, + "chained comparisons are not supported inside assertions, " + "wrap the expression inside parentheses, or decompose it"); + } + + template<typename T> + auto operator < ( T ) const -> BinaryExpr<LhsT, RhsT const&> const { + static_assert(always_false<T>::value, + "chained comparisons are not supported inside assertions, " + "wrap the expression inside parentheses, or decompose it"); + } - bool operator == ( MessageInfo const& other ) const { - return sequence == other.sequence; + template<typename T> + auto operator >= ( T ) const -> BinaryExpr<LhsT, RhsT const&> const { + static_assert(always_false<T>::value, + "chained comparisons are not supported inside assertions, " + "wrap the expression inside parentheses, or decompose it"); } - bool operator < ( MessageInfo const& other ) const { - return sequence < other.sequence; + + template<typename T> + auto operator <= ( T ) const -> BinaryExpr<LhsT, RhsT const&> const { + static_assert(always_false<T>::value, + "chained comparisons are not supported inside assertions, " + "wrap the expression inside parentheses, or decompose it"); } - private: - static unsigned int globalCount; }; - struct MessageBuilder { - MessageBuilder( std::string const& macroName, - SourceLineInfo const& lineInfo, - ResultWas::OfType type ) - : m_info( macroName, lineInfo, type ) - {} + template<typename LhsT> + class UnaryExpr : public ITransientExpression { + LhsT m_lhs; - template<typename T> - MessageBuilder& operator << ( T const& value ) { - m_stream << value; - return *this; + void streamReconstructedExpression( std::ostream &os ) const override { + os << Catch::Detail::stringify( m_lhs ); } - MessageInfo m_info; - std::ostringstream m_stream; + public: + explicit UnaryExpr( LhsT lhs ) + : ITransientExpression{ false, static_cast<bool>(lhs) }, + m_lhs( lhs ) + {} }; - class ScopedMessage { + // Specialised comparison functions to handle equality comparisons between ints and pointers (NULL deduces as an int) + template<typename LhsT, typename RhsT> + auto compareEqual( LhsT const& lhs, RhsT const& rhs ) -> bool { return static_cast<bool>(lhs == rhs); } + template<typename T> + auto compareEqual( T* const& lhs, int rhs ) -> bool { return lhs == reinterpret_cast<void const*>( rhs ); } + template<typename T> + auto compareEqual( T* const& lhs, long rhs ) -> bool { return lhs == reinterpret_cast<void const*>( rhs ); } + template<typename T> + auto compareEqual( int lhs, T* const& rhs ) -> bool { return reinterpret_cast<void const*>( lhs ) == rhs; } + template<typename T> + auto compareEqual( long lhs, T* const& rhs ) -> bool { return reinterpret_cast<void const*>( lhs ) == rhs; } + + template<typename LhsT, typename RhsT> + auto compareNotEqual( LhsT const& lhs, RhsT&& rhs ) -> bool { return static_cast<bool>(lhs != rhs); } + template<typename T> + auto compareNotEqual( T* const& lhs, int rhs ) -> bool { return lhs != reinterpret_cast<void const*>( rhs ); } + template<typename T> + auto compareNotEqual( T* const& lhs, long rhs ) -> bool { return lhs != reinterpret_cast<void const*>( rhs ); } + template<typename T> + auto compareNotEqual( int lhs, T* const& rhs ) -> bool { return reinterpret_cast<void const*>( lhs ) != rhs; } + template<typename T> + auto compareNotEqual( long lhs, T* const& rhs ) -> bool { return reinterpret_cast<void const*>( lhs ) != rhs; } + + template<typename LhsT> + class ExprLhs { + LhsT m_lhs; public: - ScopedMessage( MessageBuilder const& builder ); - ScopedMessage( ScopedMessage const& other ); - ~ScopedMessage(); + explicit ExprLhs( LhsT lhs ) : m_lhs( lhs ) {} - MessageInfo m_info; + template<typename RhsT> + auto operator == ( RhsT const& rhs ) -> BinaryExpr<LhsT, RhsT const&> const { + return { compareEqual( m_lhs, rhs ), m_lhs, "==", rhs }; + } + auto operator == ( bool rhs ) -> BinaryExpr<LhsT, bool> const { + return { m_lhs == rhs, m_lhs, "==", rhs }; + } + + template<typename RhsT> + auto operator != ( RhsT const& rhs ) -> BinaryExpr<LhsT, RhsT const&> const { + return { compareNotEqual( m_lhs, rhs ), m_lhs, "!=", rhs }; + } + auto operator != ( bool rhs ) -> BinaryExpr<LhsT, bool> const { + return { m_lhs != rhs, m_lhs, "!=", rhs }; + } + + template<typename RhsT> + auto operator > ( RhsT const& rhs ) -> BinaryExpr<LhsT, RhsT const&> const { + return { static_cast<bool>(m_lhs > rhs), m_lhs, ">", rhs }; + } + template<typename RhsT> + auto operator < ( RhsT const& rhs ) -> BinaryExpr<LhsT, RhsT const&> const { + return { static_cast<bool>(m_lhs < rhs), m_lhs, "<", rhs }; + } + template<typename RhsT> + auto operator >= ( RhsT const& rhs ) -> BinaryExpr<LhsT, RhsT const&> const { + return { static_cast<bool>(m_lhs >= rhs), m_lhs, ">=", rhs }; + } + template<typename RhsT> + auto operator <= ( RhsT const& rhs ) -> BinaryExpr<LhsT, RhsT const&> const { + return { static_cast<bool>(m_lhs <= rhs), m_lhs, "<=", rhs }; + } + template <typename RhsT> + auto operator | (RhsT const& rhs) -> BinaryExpr<LhsT, RhsT const&> const { + return { static_cast<bool>(m_lhs | rhs), m_lhs, "|", rhs }; + } + template <typename RhsT> + auto operator & (RhsT const& rhs) -> BinaryExpr<LhsT, RhsT const&> const { + return { static_cast<bool>(m_lhs & rhs), m_lhs, "&", rhs }; + } + template <typename RhsT> + auto operator ^ (RhsT const& rhs) -> BinaryExpr<LhsT, RhsT const&> const { + return { static_cast<bool>(m_lhs ^ rhs), m_lhs, "^", rhs }; + } + + template<typename RhsT> + auto operator && ( RhsT const& ) -> BinaryExpr<LhsT, RhsT const&> const { + static_assert(always_false<RhsT>::value, + "operator&& is not supported inside assertions, " + "wrap the expression inside parentheses, or decompose it"); + } + + template<typename RhsT> + auto operator || ( RhsT const& ) -> BinaryExpr<LhsT, RhsT const&> const { + static_assert(always_false<RhsT>::value, + "operator|| is not supported inside assertions, " + "wrap the expression inside parentheses, or decompose it"); + } + + auto makeUnaryExpr() const -> UnaryExpr<LhsT> { + return UnaryExpr<LhsT>{ m_lhs }; + } + }; + + void handleExpression( ITransientExpression const& expr ); + + template<typename T> + void handleExpression( ExprLhs<T> const& expr ) { + handleExpression( expr.makeUnaryExpr() ); + } + + struct Decomposer { + template<typename T> + auto operator <= ( T const& lhs ) -> ExprLhs<T const&> { + return ExprLhs<T const&>{ lhs }; + } + + auto operator <=( bool value ) -> ExprLhs<bool> { + return ExprLhs<bool>{ value }; + } }; } // end namespace Catch -// #included from: catch_interfaces_capture.h -#define TWOBLUECUBES_CATCH_INTERFACES_CAPTURE_H_INCLUDED +#ifdef _MSC_VER +#pragma warning(pop) +#endif + +// end catch_decomposer.h +// start catch_interfaces_capture.h #include <string> +#include <chrono> namespace Catch { - class TestCase; class AssertionResult; struct AssertionInfo; struct SectionInfo; struct SectionEndInfo; struct MessageInfo; - class ScopedMessageBuilder; + struct MessageBuilder; struct Counts; + struct AssertionReaction; + struct SourceLineInfo; - struct IResultCapture { + struct ITransientExpression; + struct IGeneratorTracker; + +#if defined(CATCH_CONFIG_ENABLE_BENCHMARKING) + struct BenchmarkInfo; + template <typename Duration = std::chrono::duration<double, std::nano>> + struct BenchmarkStats; +#endif // CATCH_CONFIG_ENABLE_BENCHMARKING + + struct IResultCapture { virtual ~IResultCapture(); - virtual void assertionEnded( AssertionResult const& result ) = 0; virtual bool sectionStarted( SectionInfo const& sectionInfo, Counts& assertions ) = 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; - virtual std::string getCurrentTestName() const = 0; - virtual const AssertionResult* getLastResult() const = 0; + virtual auto acquireGeneratorTracker( StringRef generatorName, SourceLineInfo const& lineInfo ) -> IGeneratorTracker& = 0; - virtual void exceptionEarlyReported() = 0; +#if defined(CATCH_CONFIG_ENABLE_BENCHMARKING) + virtual void benchmarkPreparing( std::string const& name ) = 0; + virtual void benchmarkStarting( BenchmarkInfo const& info ) = 0; + virtual void benchmarkEnded( BenchmarkStats<> const& stats ) = 0; + virtual void benchmarkFailed( std::string const& error ) = 0; +#endif // CATCH_CONFIG_ENABLE_BENCHMARKING - virtual void handleFatalErrorCondition( std::string const& message ) = 0; + virtual void pushScopedMessage( MessageInfo const& message ) = 0; + virtual void popScopedMessage( MessageInfo const& message ) = 0; + + virtual void emplaceUnscopedMessage( MessageBuilder const& builder ) = 0; + + virtual void handleFatalErrorCondition( StringRef message ) = 0; + + virtual void handleExpr + ( AssertionInfo const& info, + ITransientExpression const& expr, + AssertionReaction& reaction ) = 0; + virtual void handleMessage + ( AssertionInfo const& info, + ResultWas::OfType resultType, + StringRef const& message, + AssertionReaction& reaction ) = 0; + virtual void handleUnexpectedExceptionNotThrown + ( AssertionInfo const& info, + AssertionReaction& reaction ) = 0; + virtual void handleUnexpectedInflightException + ( AssertionInfo const& info, + std::string const& message, + AssertionReaction& reaction ) = 0; + virtual void handleIncomplete + ( AssertionInfo const& info ) = 0; + virtual void handleNonExpr + ( AssertionInfo const &info, + ResultWas::OfType resultType, + AssertionReaction &reaction ) = 0; virtual bool lastAssertionPassed() = 0; virtual void assertionPassed() = 0; - virtual void assertionRun() = 0; + + // Deprecated, do not use: + virtual std::string getCurrentTestName() const = 0; + virtual const AssertionResult* getLastResult() const = 0; + virtual void exceptionEarlyReported() = 0; }; IResultCapture& getResultCapture(); } -// #included from: catch_debugger.h -#define TWOBLUECUBES_CATCH_DEBUGGER_H_INCLUDED +// end catch_interfaces_capture.h +namespace Catch { -// #included from: catch_platform.h -#define TWOBLUECUBES_CATCH_PLATFORM_H_INCLUDED + struct TestFailureException{}; + struct AssertionResultData; + struct IResultCapture; + class RunContext; -#if defined(__MAC_OS_X_VERSION_MIN_REQUIRED) -# define CATCH_PLATFORM_MAC -#elif defined(__IPHONE_OS_VERSION_MIN_REQUIRED) -# define CATCH_PLATFORM_IPHONE -#elif defined(linux) || defined(__linux) || defined(__linux__) -# define CATCH_PLATFORM_LINUX -#elif defined(WIN32) || defined(__WIN32__) || defined(_WIN32) || defined(_MSC_VER) -# define CATCH_PLATFORM_WINDOWS -# if !defined(NOMINMAX) && !defined(CATCH_CONFIG_NO_NOMINMAX) -# define CATCH_DEFINES_NOMINMAX -# endif -# if !defined(WIN32_LEAN_AND_MEAN) && !defined(CATCH_CONFIG_NO_WIN32_LEAN_AND_MEAN) -# define CATCH_DEFINES_WIN32_LEAN_AND_MEAN -# endif -#endif + class LazyExpression { + friend class AssertionHandler; + friend struct AssertionStats; + friend class RunContext; -#include <string> + ITransientExpression const* m_transientExpression = nullptr; + bool m_isNegated; + public: + LazyExpression( bool isNegated ); + LazyExpression( LazyExpression const& other ); + LazyExpression& operator = ( LazyExpression const& ) = delete; -namespace Catch{ + explicit operator bool() const; - bool isDebuggerActive(); - void writeToDebugConsole( std::string const& text ); -} + friend auto operator << ( std::ostream& os, LazyExpression const& lazyExpr ) -> std::ostream&; + }; -#ifdef CATCH_PLATFORM_MAC + struct AssertionReaction { + bool shouldDebugBreak = false; + bool shouldThrow = false; + }; - // The following code snippet based on: - // http://cocoawithlove.com/2008/03/break-into-debugger.html - #if defined(__ppc64__) || defined(__ppc__) - #define CATCH_TRAP() \ - __asm__("li r0, 20\nsc\nnop\nli r0, 37\nli r4, 2\nsc\nnop\n" \ - : : : "memory","r0","r3","r4" ) /* NOLINT */ - #else - #define CATCH_TRAP() __asm__("int $3\n" : : /* NOLINT */ ) - #endif + class AssertionHandler { + AssertionInfo m_assertionInfo; + AssertionReaction m_reaction; + bool m_completed = false; + IResultCapture& m_resultCapture; -#elif defined(CATCH_PLATFORM_LINUX) - // If we can use inline assembler, do it because this allows us to break - // directly at the location of the failing check instead of breaking inside - // raise() called from it, i.e. one stack frame below. - #if defined(__GNUC__) && (defined(__i386) || defined(__x86_64)) - #define CATCH_TRAP() asm volatile ("int $3") /* NOLINT */ - #else // Fall back to the generic way. - #include <signal.h> + public: + AssertionHandler + ( StringRef const& macroName, + SourceLineInfo const& lineInfo, + StringRef capturedExpression, + ResultDisposition::Flags resultDisposition ); + ~AssertionHandler() { + if ( !m_completed ) { + m_resultCapture.handleIncomplete( m_assertionInfo ); + } + } - #define CATCH_TRAP() raise(SIGTRAP) - #endif -#elif defined(_MSC_VER) - #define CATCH_TRAP() __debugbreak() -#elif defined(__MINGW32__) - extern "C" __declspec(dllimport) void __stdcall DebugBreak(); - #define CATCH_TRAP() DebugBreak() -#endif + template<typename T> + void handleExpr( ExprLhs<T> const& expr ) { + handleExpr( expr.makeUnaryExpr() ); + } + void handleExpr( ITransientExpression const& expr ); -#ifdef CATCH_TRAP - #define CATCH_BREAK_INTO_DEBUGGER() if( Catch::isDebuggerActive() ) { CATCH_TRAP(); } -#else - #define CATCH_BREAK_INTO_DEBUGGER() Catch::alwaysTrue(); -#endif + void handleMessage(ResultWas::OfType resultType, StringRef const& message); + + void handleExceptionThrownAsExpected(); + void handleUnexpectedExceptionNotThrown(); + void handleExceptionNotThrownAsExpected(); + void handleThrowingCallSkipped(); + void handleUnexpectedInflightException(); + + void complete(); + void setCompleted(); + + // query + auto allowThrows() const -> bool; + }; + + void handleExceptionMatchExpr( AssertionHandler& handler, std::string const& str, StringRef const& matcherString ); + +} // namespace Catch + +// end catch_assertionhandler.h +// start catch_message.h -// #included from: catch_interfaces_runner.h -#define TWOBLUECUBES_CATCH_INTERFACES_RUNNER_H_INCLUDED +#include <string> +#include <vector> namespace Catch { - class TestCase; - struct IRunner { - virtual ~IRunner(); - virtual bool aborting() const = 0; + struct MessageInfo { + MessageInfo( StringRef const& _macroName, + SourceLineInfo const& _lineInfo, + ResultWas::OfType _type ); + + StringRef macroName; + std::string message; + SourceLineInfo lineInfo; + ResultWas::OfType type; + unsigned int sequence; + + bool operator == ( MessageInfo const& other ) const; + bool operator < ( MessageInfo const& other ) const; + private: + static unsigned int globalCount; }; -} + + struct MessageStream { + + template<typename T> + MessageStream& operator << ( T const& value ) { + m_stream << value; + return *this; + } + + ReusableStringStream m_stream; + }; + + struct MessageBuilder : MessageStream { + MessageBuilder( StringRef const& macroName, + SourceLineInfo const& lineInfo, + ResultWas::OfType type ); + + template<typename T> + MessageBuilder& operator << ( T const& value ) { + m_stream << value; + return *this; + } + + MessageInfo m_info; + }; + + class ScopedMessage { + public: + explicit ScopedMessage( MessageBuilder const& builder ); + ScopedMessage( ScopedMessage& duplicate ) = delete; + ScopedMessage( ScopedMessage&& old ); + ~ScopedMessage(); + + MessageInfo m_info; + bool m_moved; + }; + + class Capturer { + std::vector<MessageInfo> m_messages; + IResultCapture& m_resultCapture = getResultCapture(); + size_t m_captured = 0; + public: + Capturer( StringRef macroName, SourceLineInfo const& lineInfo, ResultWas::OfType resultType, StringRef names ); + ~Capturer(); + + void captureValue( size_t index, std::string const& value ); + + template<typename T> + void captureValues( size_t index, T const& value ) { + captureValue( index, Catch::Detail::stringify( value ) ); + } + + template<typename T, typename... Ts> + void captureValues( size_t index, T const& value, Ts const&... values ) { + captureValue( index, Catch::Detail::stringify(value) ); + captureValues( index+1, values... ); + } + }; + +} // end namespace Catch + +// end catch_message.h +#if !defined(CATCH_CONFIG_DISABLE) #if !defined(CATCH_CONFIG_DISABLE_STRINGIFICATION) -# define CATCH_INTERNAL_STRINGIFY(expr) #expr + #define CATCH_INTERNAL_STRINGIFY(...) #__VA_ARGS__ #else -# define CATCH_INTERNAL_STRINGIFY(expr) "Disabled by CATCH_CONFIG_DISABLE_STRINGIFICATION" + #define CATCH_INTERNAL_STRINGIFY(...) "Disabled by CATCH_CONFIG_DISABLE_STRINGIFICATION" #endif -#if defined(CATCH_CONFIG_FAST_COMPILE) -/////////////////////////////////////////////////////////////////////////////// -// We can speedup compilation significantly by breaking into debugger lower in -// the callstack, because then we don't have to expand CATCH_BREAK_INTO_DEBUGGER -// macro in each assertion -#define INTERNAL_CATCH_REACT( resultBuilder ) \ - resultBuilder.react(); +#if defined(CATCH_CONFIG_FAST_COMPILE) || defined(CATCH_CONFIG_DISABLE_EXCEPTIONS) /////////////////////////////////////////////////////////////////////////////// // Another way to speed-up compilation is to omit local try-catch for REQUIRE* // macros. -// This can potentially cause false negative, if the test code catches -// the exception before it propagates back up to the runner. -#define INTERNAL_CATCH_TEST_NO_TRY( macroName, resultDisposition, expr ) \ - do { \ - Catch::ResultBuilder __catchResult( macroName, CATCH_INTERNAL_LINEINFO, CATCH_INTERNAL_STRINGIFY(expr), resultDisposition ); \ - __catchResult.setExceptionGuard(); \ - CATCH_INTERNAL_SUPPRESS_PARENTHESES_WARNINGS \ - ( __catchResult <= expr ).endExpression(); \ - CATCH_INTERNAL_UNSUPPRESS_PARENTHESES_WARNINGS \ - __catchResult.unsetExceptionGuard(); \ - INTERNAL_CATCH_REACT( __catchResult ) \ - } while( Catch::isTrue( false && static_cast<bool>( !!(expr) ) ) ) // expr here is never evaluated at runtime but it forces the compiler to give it a look -// The double negation silences MSVC's C4800 warning, the static_cast forces short-circuit evaluation if the type has overloaded &&. - -#define INTERNAL_CHECK_THAT_NO_TRY( macroName, matcher, resultDisposition, arg ) \ - do { \ - Catch::ResultBuilder __catchResult( macroName, CATCH_INTERNAL_LINEINFO, CATCH_INTERNAL_STRINGIFY(arg) ", " CATCH_INTERNAL_STRINGIFY(matcher), resultDisposition ); \ - __catchResult.setExceptionGuard(); \ - __catchResult.captureMatch( arg, matcher, CATCH_INTERNAL_STRINGIFY(matcher) ); \ - __catchResult.unsetExceptionGuard(); \ - INTERNAL_CATCH_REACT( __catchResult ) \ - } while( Catch::alwaysFalse() ) +#define INTERNAL_CATCH_TRY +#define INTERNAL_CATCH_CATCH( capturer ) + +#else // CATCH_CONFIG_FAST_COMPILE + +#define INTERNAL_CATCH_TRY try +#define INTERNAL_CATCH_CATCH( handler ) catch(...) { handler.handleUnexpectedInflightException(); } -#else -/////////////////////////////////////////////////////////////////////////////// -// In the event of a failure works out if the debugger needs to be invoked -// and/or an exception thrown and takes appropriate action. -// This needs to be done as a macro so the debugger will stop in the user -// source code rather than in Catch library code -#define INTERNAL_CATCH_REACT( resultBuilder ) \ - if( resultBuilder.shouldDebugBreak() ) CATCH_BREAK_INTO_DEBUGGER(); \ - resultBuilder.react(); #endif +#define INTERNAL_CATCH_REACT( handler ) handler.complete(); + /////////////////////////////////////////////////////////////////////////////// -#define INTERNAL_CATCH_TEST( macroName, resultDisposition, expr ) \ +#define INTERNAL_CATCH_TEST( macroName, resultDisposition, ... ) \ do { \ - Catch::ResultBuilder __catchResult( macroName, CATCH_INTERNAL_LINEINFO, CATCH_INTERNAL_STRINGIFY(expr), resultDisposition ); \ - try { \ + CATCH_INTERNAL_IGNORE_BUT_WARN(__VA_ARGS__); \ + Catch::AssertionHandler catchAssertionHandler( macroName##_catch_sr, CATCH_INTERNAL_LINEINFO, CATCH_INTERNAL_STRINGIFY(__VA_ARGS__), resultDisposition ); \ + INTERNAL_CATCH_TRY { \ + CATCH_INTERNAL_START_WARNINGS_SUPPRESSION \ CATCH_INTERNAL_SUPPRESS_PARENTHESES_WARNINGS \ - ( __catchResult <= expr ).endExpression(); \ - CATCH_INTERNAL_UNSUPPRESS_PARENTHESES_WARNINGS \ - } \ - catch( ... ) { \ - __catchResult.useActiveException( resultDisposition ); \ - } \ - INTERNAL_CATCH_REACT( __catchResult ) \ - } while( Catch::isTrue( false && static_cast<bool>( !!(expr) ) ) ) // expr here is never evaluated at runtime but it forces the compiler to give it a look - // The double negation silences MSVC's C4800 warning, the static_cast forces short-circuit evaluation if the type has overloaded &&. + catchAssertionHandler.handleExpr( Catch::Decomposer() <= __VA_ARGS__ ); \ + CATCH_INTERNAL_STOP_WARNINGS_SUPPRESSION \ + } INTERNAL_CATCH_CATCH( catchAssertionHandler ) \ + INTERNAL_CATCH_REACT( catchAssertionHandler ) \ + } while( (void)0, (false) && static_cast<bool>( !!(__VA_ARGS__) ) ) /////////////////////////////////////////////////////////////////////////////// -#define INTERNAL_CATCH_IF( macroName, resultDisposition, expr ) \ - INTERNAL_CATCH_TEST( macroName, resultDisposition, expr ); \ +#define INTERNAL_CATCH_IF( macroName, resultDisposition, ... ) \ + INTERNAL_CATCH_TEST( macroName, resultDisposition, __VA_ARGS__ ); \ if( Catch::getResultCapture().lastAssertionPassed() ) /////////////////////////////////////////////////////////////////////////////// -#define INTERNAL_CATCH_ELSE( macroName, resultDisposition, expr ) \ - INTERNAL_CATCH_TEST( macroName, resultDisposition, expr ); \ +#define INTERNAL_CATCH_ELSE( macroName, resultDisposition, ... ) \ + INTERNAL_CATCH_TEST( macroName, resultDisposition, __VA_ARGS__ ); \ if( !Catch::getResultCapture().lastAssertionPassed() ) /////////////////////////////////////////////////////////////////////////////// -#define INTERNAL_CATCH_NO_THROW( macroName, resultDisposition, expr ) \ +#define INTERNAL_CATCH_NO_THROW( macroName, resultDisposition, ... ) \ do { \ - Catch::ResultBuilder __catchResult( macroName, CATCH_INTERNAL_LINEINFO, CATCH_INTERNAL_STRINGIFY(expr), resultDisposition ); \ + Catch::AssertionHandler catchAssertionHandler( macroName##_catch_sr, CATCH_INTERNAL_LINEINFO, CATCH_INTERNAL_STRINGIFY(__VA_ARGS__), resultDisposition ); \ try { \ - static_cast<void>(expr); \ - __catchResult.captureResult( Catch::ResultWas::Ok ); \ + static_cast<void>(__VA_ARGS__); \ + catchAssertionHandler.handleExceptionNotThrownAsExpected(); \ } \ catch( ... ) { \ - __catchResult.useActiveException( resultDisposition ); \ + catchAssertionHandler.handleUnexpectedInflightException(); \ } \ - INTERNAL_CATCH_REACT( __catchResult ) \ - } while( Catch::alwaysFalse() ) + INTERNAL_CATCH_REACT( catchAssertionHandler ) \ + } while( false ) /////////////////////////////////////////////////////////////////////////////// -#define INTERNAL_CATCH_THROWS( macroName, resultDisposition, matcher, expr ) \ +#define INTERNAL_CATCH_THROWS( macroName, resultDisposition, ... ) \ do { \ - Catch::ResultBuilder __catchResult( macroName, CATCH_INTERNAL_LINEINFO, CATCH_INTERNAL_STRINGIFY(expr), resultDisposition, CATCH_INTERNAL_STRINGIFY(matcher) ); \ - if( __catchResult.allowThrows() ) \ + Catch::AssertionHandler catchAssertionHandler( macroName##_catch_sr, CATCH_INTERNAL_LINEINFO, CATCH_INTERNAL_STRINGIFY(__VA_ARGS__), resultDisposition); \ + if( catchAssertionHandler.allowThrows() ) \ try { \ - static_cast<void>(expr); \ - __catchResult.captureResult( Catch::ResultWas::DidntThrowException ); \ + static_cast<void>(__VA_ARGS__); \ + catchAssertionHandler.handleUnexpectedExceptionNotThrown(); \ } \ catch( ... ) { \ - __catchResult.captureExpectedException( matcher ); \ + catchAssertionHandler.handleExceptionThrownAsExpected(); \ } \ else \ - __catchResult.captureResult( Catch::ResultWas::Ok ); \ - INTERNAL_CATCH_REACT( __catchResult ) \ - } while( Catch::alwaysFalse() ) + catchAssertionHandler.handleThrowingCallSkipped(); \ + INTERNAL_CATCH_REACT( catchAssertionHandler ) \ + } while( false ) /////////////////////////////////////////////////////////////////////////////// #define INTERNAL_CATCH_THROWS_AS( macroName, exceptionType, resultDisposition, expr ) \ do { \ - Catch::ResultBuilder __catchResult( macroName, CATCH_INTERNAL_LINEINFO, CATCH_INTERNAL_STRINGIFY(expr) ", " CATCH_INTERNAL_STRINGIFY(exceptionType), resultDisposition ); \ - if( __catchResult.allowThrows() ) \ + Catch::AssertionHandler catchAssertionHandler( macroName##_catch_sr, CATCH_INTERNAL_LINEINFO, CATCH_INTERNAL_STRINGIFY(expr) ", " CATCH_INTERNAL_STRINGIFY(exceptionType), resultDisposition ); \ + if( catchAssertionHandler.allowThrows() ) \ try { \ static_cast<void>(expr); \ - __catchResult.captureResult( Catch::ResultWas::DidntThrowException ); \ + catchAssertionHandler.handleUnexpectedExceptionNotThrown(); \ } \ - catch( exceptionType ) { \ - __catchResult.captureResult( Catch::ResultWas::Ok ); \ + catch( exceptionType const& ) { \ + catchAssertionHandler.handleExceptionThrownAsExpected(); \ } \ catch( ... ) { \ - __catchResult.useActiveException( resultDisposition ); \ + catchAssertionHandler.handleUnexpectedInflightException(); \ } \ else \ - __catchResult.captureResult( Catch::ResultWas::Ok ); \ - INTERNAL_CATCH_REACT( __catchResult ) \ - } while( Catch::alwaysFalse() ) + catchAssertionHandler.handleThrowingCallSkipped(); \ + INTERNAL_CATCH_REACT( catchAssertionHandler ) \ + } while( false ) /////////////////////////////////////////////////////////////////////////////// -#ifdef CATCH_CONFIG_VARIADIC_MACROS - #define INTERNAL_CATCH_MSG( macroName, messageType, resultDisposition, ... ) \ - do { \ - Catch::ResultBuilder __catchResult( macroName, CATCH_INTERNAL_LINEINFO, "", resultDisposition ); \ - __catchResult << __VA_ARGS__ + ::Catch::StreamEndStop(); \ - __catchResult.captureResult( messageType ); \ - INTERNAL_CATCH_REACT( __catchResult ) \ - } while( Catch::alwaysFalse() ) -#else - #define INTERNAL_CATCH_MSG( macroName, messageType, resultDisposition, log ) \ - do { \ - Catch::ResultBuilder __catchResult( macroName, CATCH_INTERNAL_LINEINFO, "", resultDisposition ); \ - __catchResult << log + ::Catch::StreamEndStop(); \ - __catchResult.captureResult( messageType ); \ - INTERNAL_CATCH_REACT( __catchResult ) \ - } while( Catch::alwaysFalse() ) -#endif +#define INTERNAL_CATCH_MSG( macroName, messageType, resultDisposition, ... ) \ + do { \ + Catch::AssertionHandler catchAssertionHandler( macroName##_catch_sr, CATCH_INTERNAL_LINEINFO, Catch::StringRef(), resultDisposition ); \ + catchAssertionHandler.handleMessage( messageType, ( Catch::MessageStream() << __VA_ARGS__ + ::Catch::StreamEndStop() ).m_stream.str() ); \ + INTERNAL_CATCH_REACT( catchAssertionHandler ) \ + } while( false ) + +/////////////////////////////////////////////////////////////////////////////// +#define INTERNAL_CATCH_CAPTURE( varName, macroName, ... ) \ + auto varName = Catch::Capturer( macroName, CATCH_INTERNAL_LINEINFO, Catch::ResultWas::Info, #__VA_ARGS__ ); \ + varName.captureValues( 0, __VA_ARGS__ ) /////////////////////////////////////////////////////////////////////////////// #define INTERNAL_CATCH_INFO( macroName, log ) \ - Catch::ScopedMessage INTERNAL_CATCH_UNIQUE_NAME( scopedMessage ) = Catch::MessageBuilder( macroName, CATCH_INTERNAL_LINEINFO, Catch::ResultWas::Info ) << log; + Catch::ScopedMessage INTERNAL_CATCH_UNIQUE_NAME( scopedMessage )( Catch::MessageBuilder( macroName##_catch_sr, CATCH_INTERNAL_LINEINFO, Catch::ResultWas::Info ) << log ); /////////////////////////////////////////////////////////////////////////////// -#define INTERNAL_CHECK_THAT( macroName, matcher, resultDisposition, arg ) \ +#define INTERNAL_CATCH_UNSCOPED_INFO( macroName, log ) \ + Catch::getResultCapture().emplaceUnscopedMessage( Catch::MessageBuilder( macroName##_catch_sr, CATCH_INTERNAL_LINEINFO, Catch::ResultWas::Info ) << log ) + +/////////////////////////////////////////////////////////////////////////////// +// Although this is matcher-based, it can be used with just a string +#define INTERNAL_CATCH_THROWS_STR_MATCHES( macroName, resultDisposition, matcher, ... ) \ do { \ - Catch::ResultBuilder __catchResult( macroName, CATCH_INTERNAL_LINEINFO, CATCH_INTERNAL_STRINGIFY(arg) ", " CATCH_INTERNAL_STRINGIFY(matcher), resultDisposition ); \ - try { \ - __catchResult.captureMatch( arg, matcher, CATCH_INTERNAL_STRINGIFY(matcher) ); \ - } catch( ... ) { \ - __catchResult.useActiveException( resultDisposition | Catch::ResultDisposition::ContinueOnFailure ); \ - } \ - INTERNAL_CATCH_REACT( __catchResult ) \ - } while( Catch::alwaysFalse() ) + Catch::AssertionHandler catchAssertionHandler( macroName##_catch_sr, CATCH_INTERNAL_LINEINFO, CATCH_INTERNAL_STRINGIFY(__VA_ARGS__) ", " CATCH_INTERNAL_STRINGIFY(matcher), resultDisposition ); \ + if( catchAssertionHandler.allowThrows() ) \ + try { \ + static_cast<void>(__VA_ARGS__); \ + catchAssertionHandler.handleUnexpectedExceptionNotThrown(); \ + } \ + catch( ... ) { \ + Catch::handleExceptionMatchExpr( catchAssertionHandler, matcher, #matcher##_catch_sr ); \ + } \ + else \ + catchAssertionHandler.handleThrowingCallSkipped(); \ + INTERNAL_CATCH_REACT( catchAssertionHandler ) \ + } while( false ) -// #included from: internal/catch_section.h -#define TWOBLUECUBES_CATCH_SECTION_H_INCLUDED +#endif // CATCH_CONFIG_DISABLE -// #included from: catch_section_info.h -#define TWOBLUECUBES_CATCH_SECTION_INFO_H_INCLUDED +// end catch_capture.hpp +// start catch_section.h -// #included from: catch_totals.hpp -#define TWOBLUECUBES_CATCH_TOTALS_HPP_INCLUDED +// start catch_section_info.h + +// start catch_totals.h #include <cstddef> namespace Catch { struct Counts { - Counts() : passed( 0 ), failed( 0 ), failedButOk( 0 ) {} - - Counts operator - ( Counts const& other ) const { - Counts diff; - diff.passed = passed - other.passed; - diff.failed = failed - other.failed; - diff.failedButOk = failedButOk - other.failedButOk; - return diff; - } - Counts& operator += ( Counts const& other ) { - passed += other.passed; - failed += other.failed; - failedButOk += other.failedButOk; - return *this; - } + Counts operator - ( Counts const& other ) const; + Counts& operator += ( Counts const& other ); - std::size_t total() const { - return passed + failed + failedButOk; - } - bool allPassed() const { - return failed == 0 && failedButOk == 0; - } - bool allOk() const { - return failed == 0; - } + std::size_t total() const; + bool allPassed() const; + bool allOk() const; - std::size_t passed; - std::size_t failed; - std::size_t failedButOk; + std::size_t passed = 0; + std::size_t failed = 0; + std::size_t failedButOk = 0; }; struct Totals { - Totals operator - ( Totals const& other ) const { - Totals diff; - diff.assertions = assertions - other.assertions; - diff.testCases = testCases - other.testCases; - return diff; - } - - Totals delta( Totals const& prevTotals ) const { - Totals diff = *this - prevTotals; - if( diff.assertions.failed > 0 ) - ++diff.testCases.failed; - else if( diff.assertions.failedButOk > 0 ) - ++diff.testCases.failedButOk; - else - ++diff.testCases.passed; - return diff; - } + Totals operator - ( Totals const& other ) const; + Totals& operator += ( Totals const& other ); - Totals& operator += ( Totals const& other ) { - assertions += other.assertions; - testCases += other.testCases; - return *this; - } + Totals delta( Totals const& prevTotals ) const; + int error = 0; Counts assertions; Counts testCases; }; } +// end catch_totals.h #include <string> namespace Catch { struct SectionInfo { + SectionInfo + ( SourceLineInfo const& _lineInfo, + std::string const& _name ); + + // Deprecated SectionInfo ( SourceLineInfo const& _lineInfo, std::string const& _name, - std::string const& _description = std::string() ); + std::string const& ) : SectionInfo( _lineInfo, _name ) {} std::string name; - std::string description; + std::string description; // !Deprecated: this will always be empty 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; @@ -2435,36 +2881,29 @@ namespace Catch { } // end namespace Catch -// #included from: catch_timer.h -#define TWOBLUECUBES_CATCH_TIMER_H_INCLUDED +// end catch_section_info.h +// start catch_timer.h -#ifdef _MSC_VER +#include <cstdint> namespace Catch { - typedef unsigned long long UInt64; -} -#else -#include <stdint.h> -namespace Catch { - typedef uint64_t UInt64; -} -#endif -namespace Catch { + auto getCurrentNanosecondsSinceEpoch() -> uint64_t; + auto getEstimatedClockResolution() -> uint64_t; + class Timer { + uint64_t m_nanoseconds = 0; public: - Timer() : m_ticks( 0 ) {} void start(); - unsigned int getElapsedMicroseconds() const; - unsigned int getElapsedMilliseconds() const; - double getElapsedSeconds() const; - - private: - UInt64 m_ticks; + auto getElapsedNanoseconds() const -> uint64_t; + auto getElapsedMicroseconds() const -> uint64_t; + auto getElapsedMilliseconds() const -> unsigned int; + auto getElapsedSeconds() const -> double; }; } // namespace Catch +// end catch_timer.h #include <string> namespace Catch { @@ -2475,7 +2914,7 @@ namespace Catch { ~Section(); // This indicates whether the section should be executed or not - operator bool() const; + explicit operator bool() const; private: SectionInfo m_info; @@ -2488,277 +2927,120 @@ namespace Catch { } // end namespace Catch -#ifdef CATCH_CONFIG_VARIADIC_MACROS - #define INTERNAL_CATCH_SECTION( ... ) \ - if( Catch::Section const& INTERNAL_CATCH_UNIQUE_NAME( catch_internal_Section ) = Catch::SectionInfo( CATCH_INTERNAL_LINEINFO, __VA_ARGS__ ) ) -#else - #define INTERNAL_CATCH_SECTION( name, desc ) \ - if( Catch::Section const& INTERNAL_CATCH_UNIQUE_NAME( catch_internal_Section ) = Catch::SectionInfo( CATCH_INTERNAL_LINEINFO, name, desc ) ) -#endif +#define INTERNAL_CATCH_SECTION( ... ) \ + CATCH_INTERNAL_START_WARNINGS_SUPPRESSION \ + CATCH_INTERNAL_SUPPRESS_UNUSED_WARNINGS \ + if( Catch::Section const& INTERNAL_CATCH_UNIQUE_NAME( catch_internal_Section ) = Catch::SectionInfo( CATCH_INTERNAL_LINEINFO, __VA_ARGS__ ) ) \ + CATCH_INTERNAL_STOP_WARNINGS_SUPPRESSION -// #included from: internal/catch_generators.hpp -#define TWOBLUECUBES_CATCH_GENERATORS_HPP_INCLUDED +#define INTERNAL_CATCH_DYNAMIC_SECTION( ... ) \ + CATCH_INTERNAL_START_WARNINGS_SUPPRESSION \ + CATCH_INTERNAL_SUPPRESS_UNUSED_WARNINGS \ + if( Catch::Section const& INTERNAL_CATCH_UNIQUE_NAME( catch_internal_Section ) = Catch::SectionInfo( CATCH_INTERNAL_LINEINFO, (Catch::ReusableStringStream() << __VA_ARGS__).str() ) ) \ + CATCH_INTERNAL_STOP_WARNINGS_SUPPRESSION + +// end catch_section.h +// start catch_interfaces_exception.h + +// start catch_interfaces_registry_hub.h -#include <vector> #include <string> -#include <stdlib.h> +#include <memory> namespace Catch { -template<typename T> -struct IGenerator { - virtual ~IGenerator() {} - virtual T getValue( std::size_t index ) const = 0; - virtual std::size_t size () const = 0; -}; - -template<typename T> -class BetweenGenerator : public IGenerator<T> { -public: - BetweenGenerator( T from, T to ) : m_from( from ), m_to( to ){} + class TestCase; + struct ITestCaseRegistry; + struct IExceptionTranslatorRegistry; + struct IExceptionTranslator; + struct IReporterRegistry; + struct IReporterFactory; + struct ITagAliasRegistry; + struct IMutableEnumValuesRegistry; - virtual T getValue( std::size_t index ) const { - return m_from+static_cast<int>( index ); - } + class StartupExceptionRegistry; - virtual std::size_t size() const { - return static_cast<std::size_t>( 1+m_to-m_from ); - } + using IReporterFactoryPtr = std::shared_ptr<IReporterFactory>; -private: + struct IRegistryHub { + virtual ~IRegistryHub(); - T m_from; - T m_to; -}; + virtual IReporterRegistry const& getReporterRegistry() const = 0; + virtual ITestCaseRegistry const& getTestCaseRegistry() const = 0; + virtual ITagAliasRegistry const& getTagAliasRegistry() const = 0; + virtual IExceptionTranslatorRegistry const& getExceptionTranslatorRegistry() const = 0; -template<typename T> -class ValuesGenerator : public IGenerator<T> { -public: - ValuesGenerator(){} + virtual StartupExceptionRegistry const& getStartupExceptionRegistry() const = 0; + }; - void add( T value ) { - m_values.push_back( value ); - } + struct IMutableRegistryHub { + virtual ~IMutableRegistryHub(); + virtual void registerReporter( std::string const& name, IReporterFactoryPtr const& factory ) = 0; + virtual void registerListener( IReporterFactoryPtr const& factory ) = 0; + virtual void registerTest( TestCase const& testInfo ) = 0; + virtual void registerTranslator( const IExceptionTranslator* translator ) = 0; + virtual void registerTagAlias( std::string const& alias, std::string const& tag, SourceLineInfo const& lineInfo ) = 0; + virtual void registerStartupException() noexcept = 0; + virtual IMutableEnumValuesRegistry& getMutableEnumValuesRegistry() = 0; + }; - virtual T getValue( std::size_t index ) const { - return m_values[index]; - } + IRegistryHub const& getRegistryHub(); + IMutableRegistryHub& getMutableRegistryHub(); + void cleanUp(); + std::string translateActiveException(); - virtual std::size_t size() const { - return m_values.size(); - } +} -private: - std::vector<T> m_values; -}; +// end catch_interfaces_registry_hub.h +#if defined(CATCH_CONFIG_DISABLE) + #define INTERNAL_CATCH_TRANSLATE_EXCEPTION_NO_REG( translatorName, signature) \ + static std::string translatorName( signature ) +#endif -template<typename T> -class CompositeGenerator { -public: - CompositeGenerator() : m_totalSize( 0 ) {} +#include <exception> +#include <string> +#include <vector> - // *** Move semantics, similar to auto_ptr *** - CompositeGenerator( CompositeGenerator& other ) - : m_fileInfo( other.m_fileInfo ), - m_totalSize( 0 ) - { - move( other ); - } +namespace Catch { + using exceptionTranslateFunction = std::string(*)(); - CompositeGenerator& setFileInfo( const char* fileInfo ) { - m_fileInfo = fileInfo; - return *this; - } + struct IExceptionTranslator; + using ExceptionTranslators = std::vector<std::unique_ptr<IExceptionTranslator const>>; - ~CompositeGenerator() { - deleteAll( m_composed ); - } + struct IExceptionTranslator { + virtual ~IExceptionTranslator(); + virtual std::string translate( ExceptionTranslators::const_iterator it, ExceptionTranslators::const_iterator itEnd ) const = 0; + }; - operator T () const { - size_t overallIndex = getCurrentContext().getGeneratorIndex( m_fileInfo, m_totalSize ); + struct IExceptionTranslatorRegistry { + virtual ~IExceptionTranslatorRegistry(); - typename std::vector<const IGenerator<T>*>::const_iterator it = m_composed.begin(); - typename std::vector<const IGenerator<T>*>::const_iterator itEnd = m_composed.end(); - for( size_t index = 0; it != itEnd; ++it ) - { - const IGenerator<T>* generator = *it; - if( overallIndex >= index && overallIndex < index + generator->size() ) - { - return generator->getValue( overallIndex-index ); - } - index += generator->size(); - } - CATCH_INTERNAL_ERROR( "Indexed past end of generated range" ); - return T(); // Suppress spurious "not all control paths return a value" warning in Visual Studio - if you know how to fix this please do so - } + virtual std::string translateActiveException() const = 0; + }; - void add( const IGenerator<T>* generator ) { - m_totalSize += generator->size(); - m_composed.push_back( generator ); - } - - CompositeGenerator& then( CompositeGenerator& other ) { - move( other ); - return *this; - } - - CompositeGenerator& then( T value ) { - ValuesGenerator<T>* valuesGen = new ValuesGenerator<T>(); - valuesGen->add( value ); - add( valuesGen ); - return *this; - } - -private: - - void move( CompositeGenerator& other ) { - m_composed.insert( m_composed.end(), other.m_composed.begin(), other.m_composed.end() ); - m_totalSize += other.m_totalSize; - other.m_composed.clear(); - } - - std::vector<const IGenerator<T>*> m_composed; - std::string m_fileInfo; - size_t m_totalSize; -}; - -namespace Generators -{ - template<typename T> - CompositeGenerator<T> between( T from, T to ) { - CompositeGenerator<T> generators; - generators.add( new BetweenGenerator<T>( from, to ) ); - return generators; - } - - template<typename T> - CompositeGenerator<T> values( T val1, T val2 ) { - CompositeGenerator<T> generators; - ValuesGenerator<T>* valuesGen = new ValuesGenerator<T>(); - valuesGen->add( val1 ); - valuesGen->add( val2 ); - generators.add( valuesGen ); - return generators; - } - - template<typename T> - CompositeGenerator<T> values( T val1, T val2, T val3 ){ - CompositeGenerator<T> generators; - ValuesGenerator<T>* valuesGen = new ValuesGenerator<T>(); - valuesGen->add( val1 ); - valuesGen->add( val2 ); - valuesGen->add( val3 ); - generators.add( valuesGen ); - return generators; - } - - template<typename T> - CompositeGenerator<T> values( T val1, T val2, T val3, T val4 ) { - CompositeGenerator<T> generators; - ValuesGenerator<T>* valuesGen = new ValuesGenerator<T>(); - valuesGen->add( val1 ); - valuesGen->add( val2 ); - valuesGen->add( val3 ); - valuesGen->add( val4 ); - generators.add( valuesGen ); - return generators; - } - -} // end namespace Generators - -using namespace Generators; - -} // end namespace Catch - -#define INTERNAL_CATCH_LINESTR2( line ) #line -#define INTERNAL_CATCH_LINESTR( line ) INTERNAL_CATCH_LINESTR2( line ) - -#define INTERNAL_CATCH_GENERATE( expr ) expr.setFileInfo( __FILE__ "(" INTERNAL_CATCH_LINESTR( __LINE__ ) ")" ) - -// #included from: internal/catch_interfaces_exception.h -#define TWOBLUECUBES_CATCH_INTERFACES_EXCEPTION_H_INCLUDED - -#include <string> -#include <vector> - -// #included from: catch_interfaces_registry_hub.h -#define TWOBLUECUBES_CATCH_INTERFACES_REGISTRY_HUB_H_INCLUDED - -#include <string> - -namespace Catch { - - class TestCase; - struct ITestCaseRegistry; - struct IExceptionTranslatorRegistry; - struct IExceptionTranslator; - struct IReporterRegistry; - struct IReporterFactory; - struct ITagAliasRegistry; - - struct IRegistryHub { - virtual ~IRegistryHub(); - - virtual IReporterRegistry const& getReporterRegistry() const = 0; - virtual ITestCaseRegistry const& getTestCaseRegistry() const = 0; - virtual ITagAliasRegistry const& getTagAliasRegistry() const = 0; - - virtual IExceptionTranslatorRegistry& getExceptionTranslatorRegistry() = 0; - }; - - struct IMutableRegistryHub { - virtual ~IMutableRegistryHub(); - virtual void registerReporter( std::string const& name, Ptr<IReporterFactory> const& factory ) = 0; - virtual void registerListener( Ptr<IReporterFactory> const& factory ) = 0; - virtual void registerTest( TestCase const& testInfo ) = 0; - virtual void registerTranslator( const IExceptionTranslator* translator ) = 0; - virtual void registerTagAlias( std::string const& alias, std::string const& tag, SourceLineInfo const& lineInfo ) = 0; - }; - - IRegistryHub& getRegistryHub(); - IMutableRegistryHub& getMutableRegistryHub(); - void cleanUp(); - std::string translateActiveException(); - -} - -namespace Catch { - - typedef std::string(*exceptionTranslateFunction)(); - - struct IExceptionTranslator; - typedef std::vector<const IExceptionTranslator*> ExceptionTranslators; - - struct IExceptionTranslator { - virtual ~IExceptionTranslator(); - virtual std::string translate( ExceptionTranslators::const_iterator it, ExceptionTranslators::const_iterator itEnd ) const = 0; - }; - - struct IExceptionTranslatorRegistry { - virtual ~IExceptionTranslatorRegistry(); - - virtual std::string translateActiveException() const = 0; - }; - - class ExceptionTranslatorRegistrar { - template<typename T> - class ExceptionTranslator : public IExceptionTranslator { - public: + class ExceptionTranslatorRegistrar { + template<typename T> + class ExceptionTranslator : public IExceptionTranslator { + public: ExceptionTranslator( std::string(*translateFunction)( T& ) ) : m_translateFunction( translateFunction ) {} - virtual std::string translate( ExceptionTranslators::const_iterator it, ExceptionTranslators::const_iterator itEnd ) const CATCH_OVERRIDE { + std::string translate( ExceptionTranslators::const_iterator it, ExceptionTranslators::const_iterator itEnd ) const override { +#if defined(CATCH_CONFIG_DISABLE_EXCEPTIONS) + return ""; +#else try { if( it == itEnd ) - throw; + std::rethrow_exception(std::current_exception()); else return (*it)->translate( it+1, itEnd ); } catch( T& ex ) { return m_translateFunction( ex ); } +#endif } protected: @@ -2777,62 +3059,56 @@ namespace Catch { /////////////////////////////////////////////////////////////////////////////// #define INTERNAL_CATCH_TRANSLATE_EXCEPTION2( translatorName, signature ) \ static std::string translatorName( signature ); \ - namespace{ Catch::ExceptionTranslatorRegistrar INTERNAL_CATCH_UNIQUE_NAME( catch_internal_ExceptionRegistrar )( &translatorName ); }\ + CATCH_INTERNAL_START_WARNINGS_SUPPRESSION \ + CATCH_INTERNAL_SUPPRESS_GLOBALS_WARNINGS \ + namespace{ Catch::ExceptionTranslatorRegistrar INTERNAL_CATCH_UNIQUE_NAME( catch_internal_ExceptionRegistrar )( &translatorName ); } \ + CATCH_INTERNAL_STOP_WARNINGS_SUPPRESSION \ static std::string translatorName( signature ) #define INTERNAL_CATCH_TRANSLATE_EXCEPTION( signature ) INTERNAL_CATCH_TRANSLATE_EXCEPTION2( INTERNAL_CATCH_UNIQUE_NAME( catch_internal_ExceptionTranslator ), signature ) -// #included from: internal/catch_approx.hpp -#define TWOBLUECUBES_CATCH_APPROX_HPP_INCLUDED +// end catch_interfaces_exception.h +// start catch_approx.h -#include <cmath> -#include <limits> - -#if defined(CATCH_CONFIG_CPP11_TYPE_TRAITS) #include <type_traits> -#endif namespace Catch { namespace Detail { class Approx { + private: + bool equalityComparisonImpl(double other) const; + // Validates the new margin (margin >= 0) + // out-of-line to avoid including stdexcept in the header + void setMargin(double margin); + // Validates the new epsilon (0 < epsilon < 1) + // out-of-line to avoid including stdexcept in the header + void setEpsilon(double epsilon); + public: - explicit Approx ( double value ) - : m_epsilon( std::numeric_limits<float>::epsilon()*100 ), - m_margin( 0.0 ), - m_scale( 1.0 ), - m_value( value ) - {} + explicit Approx ( double value ); - static Approx custom() { - return Approx( 0 ); - } + static Approx custom(); -#if defined(CATCH_CONFIG_CPP11_TYPE_TRAITS) + Approx operator-() const; template <typename T, typename = typename std::enable_if<std::is_constructible<double, T>::value>::type> - Approx operator()( T value ) { + Approx operator()( T const& value ) const { Approx approx( static_cast<double>(value) ); - approx.epsilon( m_epsilon ); - approx.margin( m_margin ); - approx.scale( m_scale ); + approx.m_epsilon = m_epsilon; + approx.m_margin = m_margin; + approx.m_scale = m_scale; return approx; } template <typename T, typename = typename std::enable_if<std::is_constructible<double, T>::value>::type> - explicit Approx( T value ): Approx(static_cast<double>(value)) + explicit Approx( T const& value ): Approx(static_cast<double>(value)) {} template <typename T, typename = typename std::enable_if<std::is_constructible<double, T>::value>::type> friend bool operator == ( const T& lhs, Approx const& rhs ) { - // Thanks to Richard Harris for his help refining this formula - auto lhs_v = double(lhs); - bool relativeOK = std::fabs(lhs_v - rhs.m_value) < rhs.m_epsilon * (rhs.m_scale + (std::max)(std::fabs(lhs_v), std::fabs(rhs.m_value))); - if (relativeOK) { - return true; - } - - return std::fabs(lhs_v - rhs.m_value) <= rhs.m_margin; + auto lhs_v = static_cast<double>(lhs); + return rhs.equalityComparisonImpl(lhs_v); } template <typename T, typename = typename std::enable_if<std::is_constructible<double, T>::value>::type> @@ -2841,121 +3117,56 @@ namespace Detail { } template <typename T, typename = typename std::enable_if<std::is_constructible<double, T>::value>::type> - friend bool operator != ( T lhs, Approx const& rhs ) { + friend bool operator != ( T const& lhs, Approx const& rhs ) { return !operator==( lhs, rhs ); } template <typename T, typename = typename std::enable_if<std::is_constructible<double, T>::value>::type> - friend bool operator != ( Approx const& lhs, T rhs ) { + friend bool operator != ( Approx const& lhs, T const& rhs ) { return !operator==( rhs, lhs ); } template <typename T, typename = typename std::enable_if<std::is_constructible<double, T>::value>::type> - friend bool operator <= ( T lhs, Approx const& rhs ) { - return double(lhs) < rhs.m_value || lhs == rhs; + friend bool operator <= ( T const& lhs, Approx const& rhs ) { + return static_cast<double>(lhs) < rhs.m_value || lhs == rhs; } template <typename T, typename = typename std::enable_if<std::is_constructible<double, T>::value>::type> - friend bool operator <= ( Approx const& lhs, T rhs ) { - return lhs.m_value < double(rhs) || lhs == rhs; + friend bool operator <= ( Approx const& lhs, T const& rhs ) { + return lhs.m_value < static_cast<double>(rhs) || lhs == rhs; } template <typename T, typename = typename std::enable_if<std::is_constructible<double, T>::value>::type> - friend bool operator >= ( T lhs, Approx const& rhs ) { - return double(lhs) > rhs.m_value || lhs == rhs; + friend bool operator >= ( T const& lhs, Approx const& rhs ) { + return static_cast<double>(lhs) > rhs.m_value || lhs == rhs; } template <typename T, typename = typename std::enable_if<std::is_constructible<double, T>::value>::type> - friend bool operator >= ( Approx const& lhs, T rhs ) { - return lhs.m_value > double(rhs) || lhs == rhs; + friend bool operator >= ( Approx const& lhs, T const& rhs ) { + return lhs.m_value > static_cast<double>(rhs) || lhs == rhs; } template <typename T, typename = typename std::enable_if<std::is_constructible<double, T>::value>::type> - Approx& epsilon( T newEpsilon ) { - m_epsilon = double(newEpsilon); + Approx& epsilon( T const& newEpsilon ) { + double epsilonAsDouble = static_cast<double>(newEpsilon); + setEpsilon(epsilonAsDouble); return *this; } template <typename T, typename = typename std::enable_if<std::is_constructible<double, T>::value>::type> - Approx& margin( T newMargin ) { - m_margin = double(newMargin); + Approx& margin( T const& newMargin ) { + double marginAsDouble = static_cast<double>(newMargin); + setMargin(marginAsDouble); return *this; } template <typename T, typename = typename std::enable_if<std::is_constructible<double, T>::value>::type> - Approx& scale( T newScale ) { - m_scale = double(newScale); - return *this; - } - -#else - - Approx operator()( double value ) { - Approx approx( value ); - approx.epsilon( m_epsilon ); - approx.margin( m_margin ); - approx.scale( m_scale ); - return approx; - } - - friend bool operator == ( double lhs, Approx const& rhs ) { - // Thanks to Richard Harris for his help refining this formula - bool relativeOK = std::fabs( lhs - rhs.m_value ) < rhs.m_epsilon * (rhs.m_scale + (std::max)( std::fabs(lhs), std::fabs(rhs.m_value) ) ); - if (relativeOK) { - return true; - } - return std::fabs(lhs - rhs.m_value) <= rhs.m_margin; - } - - friend bool operator == ( Approx const& lhs, double rhs ) { - return operator==( rhs, lhs ); - } - - friend bool operator != ( double lhs, Approx const& rhs ) { - return !operator==( lhs, rhs ); - } - - friend bool operator != ( Approx const& lhs, double rhs ) { - return !operator==( rhs, lhs ); - } - - friend bool operator <= ( double lhs, Approx const& rhs ) { - return lhs < rhs.m_value || lhs == rhs; - } - - friend bool operator <= ( Approx const& lhs, double rhs ) { - return lhs.m_value < rhs || lhs == rhs; - } - - friend bool operator >= ( double lhs, Approx const& rhs ) { - return lhs > rhs.m_value || lhs == rhs; - } - - friend bool operator >= ( Approx const& lhs, double rhs ) { - return lhs.m_value > rhs || lhs == rhs; - } - - Approx& epsilon( double newEpsilon ) { - m_epsilon = newEpsilon; - return *this; - } - - Approx& margin( double newMargin ) { - m_margin = newMargin; - return *this; - } - - Approx& scale( double newScale ) { - m_scale = newScale; + Approx& scale( T const& newScale ) { + m_scale = static_cast<double>(newScale); return *this; } -#endif - std::string toString() const { - std::ostringstream oss; - oss << "Approx( " << Catch::toString( m_value ) << " )"; - return oss.str(); - } + std::string toString() const; private: double m_epsilon; @@ -2963,2677 +3174,2330 @@ namespace Detail { double m_scale; double m_value; }; -} +} // end namespace Detail + +namespace literals { + Detail::Approx operator "" _a(long double val); + Detail::Approx operator "" _a(unsigned long long val); +} // end namespace literals template<> -inline std::string toString<Detail::Approx>( Detail::Approx const& value ) { - return value.toString(); -} +struct StringMaker<Catch::Detail::Approx> { + static std::string convert(Catch::Detail::Approx const& value); +}; } // end namespace Catch -// #included from: internal/catch_matchers_string.h -#define TWOBLUECUBES_CATCH_MATCHERS_STRING_H_INCLUDED - -namespace Catch { -namespace Matchers { - - namespace StdString { +// end catch_approx.h +// start catch_string_manip.h - struct CasedString - { - CasedString( std::string const& str, CaseSensitive::Choice caseSensitivity ); - std::string adjustString( std::string const& str ) const; - std::string caseSensitivitySuffix() const; +#include <string> +#include <iosfwd> +#include <vector> - CaseSensitive::Choice m_caseSensitivity; - std::string m_str; - }; +namespace Catch { - struct StringMatcherBase : MatcherBase<std::string> { - StringMatcherBase( std::string const& operation, CasedString const& comparator ); - virtual std::string describe() const CATCH_OVERRIDE; + bool startsWith( std::string const& s, std::string const& prefix ); + bool startsWith( std::string const& s, char prefix ); + bool endsWith( std::string const& s, std::string const& suffix ); + bool endsWith( std::string const& s, char suffix ); + bool contains( std::string const& s, std::string const& infix ); + void toLowerInPlace( std::string& s ); + std::string toLower( std::string const& s ); + //! Returns a new string without whitespace at the start/end + std::string trim( std::string const& str ); + //! Returns a substring of the original ref without whitespace. Beware lifetimes! + StringRef trim(StringRef ref); - CasedString m_comparator; - std::string m_operation; - }; + // !!! Be aware, returns refs into original string - make sure original string outlives them + std::vector<StringRef> splitStringRef( StringRef str, char delimiter ); + bool replaceInPlace( std::string& str, std::string const& replaceThis, std::string const& withThis ); - struct EqualsMatcher : StringMatcherBase { - EqualsMatcher( CasedString const& comparator ); - virtual bool match( std::string const& source ) const CATCH_OVERRIDE; - }; - struct ContainsMatcher : StringMatcherBase { - ContainsMatcher( CasedString const& comparator ); - virtual bool match( std::string const& source ) const CATCH_OVERRIDE; - }; - struct StartsWithMatcher : StringMatcherBase { - StartsWithMatcher( CasedString const& comparator ); - virtual bool match( std::string const& source ) const CATCH_OVERRIDE; - }; - struct EndsWithMatcher : StringMatcherBase { - EndsWithMatcher( CasedString const& comparator ); - virtual bool match( std::string const& source ) const CATCH_OVERRIDE; - }; + struct pluralise { + pluralise( std::size_t count, std::string const& label ); - } // namespace StdString + friend std::ostream& operator << ( std::ostream& os, pluralise const& pluraliser ); - // The following functions create the actual matcher objects. - // This allows the types to be inferred + std::size_t m_count; + std::string m_label; + }; +} - StdString::EqualsMatcher Equals( std::string const& str, CaseSensitive::Choice caseSensitivity = CaseSensitive::Yes ); - StdString::ContainsMatcher Contains( std::string const& str, CaseSensitive::Choice caseSensitivity = CaseSensitive::Yes ); - StdString::EndsWithMatcher EndsWith( std::string const& str, CaseSensitive::Choice caseSensitivity = CaseSensitive::Yes ); - StdString::StartsWithMatcher StartsWith( std::string const& str, CaseSensitive::Choice caseSensitivity = CaseSensitive::Yes ); +// end catch_string_manip.h +#ifndef CATCH_CONFIG_DISABLE_MATCHERS +// start catch_capture_matchers.h -} // namespace Matchers -} // namespace Catch +// start catch_matchers.h -// #included from: internal/catch_matchers_vector.h -#define TWOBLUECUBES_CATCH_MATCHERS_VECTOR_H_INCLUDED +#include <string> +#include <vector> namespace Catch { namespace Matchers { + namespace Impl { - namespace Vector { + template<typename ArgT> struct MatchAllOf; + template<typename ArgT> struct MatchAnyOf; + template<typename ArgT> struct MatchNotOf; - template<typename T> - struct ContainsElementMatcher : MatcherBase<std::vector<T>, T> { + class MatcherUntypedBase { + public: + MatcherUntypedBase() = default; + MatcherUntypedBase ( MatcherUntypedBase const& ) = default; + MatcherUntypedBase& operator = ( MatcherUntypedBase const& ) = delete; + std::string toString() const; - ContainsElementMatcher(T const &comparator) : m_comparator( comparator) {} + protected: + virtual ~MatcherUntypedBase(); + virtual std::string describe() const = 0; + mutable std::string m_cachedToString; + }; - bool match(std::vector<T> const &v) const CATCH_OVERRIDE { - return std::find(v.begin(), v.end(), m_comparator) != v.end(); - } +#ifdef __clang__ +# pragma clang diagnostic push +# pragma clang diagnostic ignored "-Wnon-virtual-dtor" +#endif - virtual std::string describe() const CATCH_OVERRIDE { - return "Contains: " + Catch::toString( m_comparator ); - } + template<typename ObjectT> + struct MatcherMethod { + virtual bool match( ObjectT const& arg ) const = 0; + }; - T const& m_comparator; +#if defined(__OBJC__) + // Hack to fix Catch GH issue #1661. Could use id for generic Object support. + // use of const for Object pointers is very uncommon and under ARC it causes some kind of signature mismatch that breaks compilation + template<> + struct MatcherMethod<NSString*> { + virtual bool match( NSString* arg ) const = 0; }; +#endif + +#ifdef __clang__ +# pragma clang diagnostic pop +#endif template<typename T> - struct ContainsMatcher : MatcherBase<std::vector<T>, std::vector<T> > { + struct MatcherBase : MatcherUntypedBase, MatcherMethod<T> { - ContainsMatcher(std::vector<T> const &comparator) : m_comparator( comparator ) {} + MatchAllOf<T> operator && ( MatcherBase const& other ) const; + MatchAnyOf<T> operator || ( MatcherBase const& other ) const; + MatchNotOf<T> operator ! () const; + }; - bool match(std::vector<T> const &v) const CATCH_OVERRIDE { - // !TBD: see note in EqualsMatcher - if (m_comparator.size() > v.size()) - return false; - for (size_t i = 0; i < m_comparator.size(); ++i) - if (std::find(v.begin(), v.end(), m_comparator[i]) == v.end()) + template<typename ArgT> + struct MatchAllOf : MatcherBase<ArgT> { + bool match( ArgT const& arg ) const override { + for( auto matcher : m_matchers ) { + if (!matcher->match(arg)) return false; + } return true; } - virtual std::string describe() const CATCH_OVERRIDE { - return "Contains: " + Catch::toString( m_comparator ); + std::string describe() const override { + std::string description; + description.reserve( 4 + m_matchers.size()*32 ); + description += "( "; + bool first = true; + for( auto matcher : m_matchers ) { + if( first ) + first = false; + else + description += " and "; + description += matcher->toString(); + } + description += " )"; + return description; } - std::vector<T> const& m_comparator; - }; + MatchAllOf<ArgT> operator && ( MatcherBase<ArgT> const& other ) { + auto copy(*this); + copy.m_matchers.push_back( &other ); + return copy; + } - template<typename T> - struct EqualsMatcher : MatcherBase<std::vector<T>, std::vector<T> > { - - EqualsMatcher(std::vector<T> const &comparator) : m_comparator( comparator ) {} + std::vector<MatcherBase<ArgT> const*> m_matchers; + }; + template<typename ArgT> + struct MatchAnyOf : MatcherBase<ArgT> { - bool match(std::vector<T> const &v) const CATCH_OVERRIDE { - // !TBD: This currently works if all elements can be compared using != - // - a more general approach would be via a compare template that defaults - // to using !=. but could be specialised for, e.g. std::vector<T> etc - // - then just call that directly - if (m_comparator.size() != v.size()) - return false; - for (size_t i = 0; i < v.size(); ++i) - if (m_comparator[i] != v[i]) - return false; - return true; + bool match( ArgT const& arg ) const override { + for( auto matcher : m_matchers ) { + if (matcher->match(arg)) + return true; + } + return false; } - virtual std::string describe() const CATCH_OVERRIDE { - return "Equals: " + Catch::toString( m_comparator ); + std::string describe() const override { + std::string description; + description.reserve( 4 + m_matchers.size()*32 ); + description += "( "; + bool first = true; + for( auto matcher : m_matchers ) { + if( first ) + first = false; + else + description += " or "; + description += matcher->toString(); + } + description += " )"; + return description; } - std::vector<T> const& m_comparator; - }; - } // namespace Vector - - // The following functions create the actual matcher objects. - // This allows the types to be inferred + MatchAnyOf<ArgT> operator || ( MatcherBase<ArgT> const& other ) { + auto copy(*this); + copy.m_matchers.push_back( &other ); + return copy; + } - template<typename T> - Vector::ContainsMatcher<T> Contains( std::vector<T> const& comparator ) { - return Vector::ContainsMatcher<T>( comparator ); - } + std::vector<MatcherBase<ArgT> const*> m_matchers; + }; - template<typename T> - Vector::ContainsElementMatcher<T> VectorContains( T const& comparator ) { - return Vector::ContainsElementMatcher<T>( comparator ); - } + template<typename ArgT> + struct MatchNotOf : MatcherBase<ArgT> { - template<typename T> - Vector::EqualsMatcher<T> Equals( std::vector<T> const& comparator ) { - return Vector::EqualsMatcher<T>( comparator ); - } + MatchNotOf( MatcherBase<ArgT> const& underlyingMatcher ) : m_underlyingMatcher( underlyingMatcher ) {} -} // namespace Matchers -} // namespace Catch + bool match( ArgT const& arg ) const override { + return !m_underlyingMatcher.match( arg ); + } -// #included from: internal/catch_interfaces_tag_alias_registry.h -#define TWOBLUECUBES_CATCH_INTERFACES_TAG_ALIAS_REGISTRY_H_INCLUDED + std::string describe() const override { + return "not " + m_underlyingMatcher.toString(); + } + MatcherBase<ArgT> const& m_underlyingMatcher; + }; -// #included from: catch_tag_alias.h -#define TWOBLUECUBES_CATCH_TAG_ALIAS_H_INCLUDED + template<typename T> + MatchAllOf<T> MatcherBase<T>::operator && ( MatcherBase const& other ) const { + return MatchAllOf<T>() && *this && other; + } + template<typename T> + MatchAnyOf<T> MatcherBase<T>::operator || ( MatcherBase const& other ) const { + return MatchAnyOf<T>() || *this || other; + } + template<typename T> + MatchNotOf<T> MatcherBase<T>::operator ! () const { + return MatchNotOf<T>( *this ); + } -#include <string> + } // namespace Impl -namespace Catch { +} // namespace Matchers - struct TagAlias { - TagAlias( std::string const& _tag, SourceLineInfo _lineInfo ) : tag( _tag ), lineInfo( _lineInfo ) {} +using namespace Matchers; +using Matchers::Impl::MatcherBase; - std::string tag; - SourceLineInfo lineInfo; - }; +} // namespace Catch - struct RegistrarForTagAliases { - RegistrarForTagAliases( char const* alias, char const* tag, SourceLineInfo const& lineInfo ); - }; +// end catch_matchers.h +// start catch_matchers_exception.hpp -} // end namespace Catch +namespace Catch { +namespace Matchers { +namespace Exception { -#define CATCH_REGISTER_TAG_ALIAS( alias, spec ) namespace{ Catch::RegistrarForTagAliases INTERNAL_CATCH_UNIQUE_NAME( AutoRegisterTagAlias )( alias, spec, CATCH_INTERNAL_LINEINFO ); } -// #included from: catch_option.hpp -#define TWOBLUECUBES_CATCH_OPTION_HPP_INCLUDED +class ExceptionMessageMatcher : public MatcherBase<std::exception> { + std::string m_message; +public: -namespace Catch { + ExceptionMessageMatcher(std::string const& message): + m_message(message) + {} - // An optional type - template<typename T> - class Option { - public: - Option() : nullableValue( CATCH_NULL ) {} - Option( T const& _value ) - : nullableValue( new( storage ) T( _value ) ) - {} - Option( Option const& _other ) - : nullableValue( _other ? new( storage ) T( *_other ) : CATCH_NULL ) - {} + bool match(std::exception const& ex) const override; - ~Option() { - reset(); - } + std::string describe() const override; +}; - Option& operator= ( Option const& _other ) { - if( &_other != this ) { - reset(); - if( _other ) - nullableValue = new( storage ) T( *_other ); - } - return *this; - } - Option& operator = ( T const& _value ) { - reset(); - nullableValue = new( storage ) T( _value ); - return *this; - } +} // namespace Exception - void reset() { - if( nullableValue ) - nullableValue->~T(); - nullableValue = CATCH_NULL; - } +Exception::ExceptionMessageMatcher Message(std::string const& message); - T& operator*() { return *nullableValue; } - T const& operator*() const { return *nullableValue; } - T* operator->() { return nullableValue; } - const T* operator->() const { return nullableValue; } +} // namespace Matchers +} // namespace Catch - T valueOr( T const& defaultValue ) const { - return nullableValue ? *nullableValue : defaultValue; - } +// end catch_matchers_exception.hpp +// start catch_matchers_floating.h - bool some() const { return nullableValue != CATCH_NULL; } - bool none() const { return nullableValue == CATCH_NULL; } +namespace Catch { +namespace Matchers { - bool operator !() const { return nullableValue == CATCH_NULL; } - operator SafeBool::type() const { - return SafeBool::makeSafe( some() ); - } + namespace Floating { - private: - T *nullableValue; - union { - char storage[sizeof(T)]; + enum class FloatingPointKind : uint8_t; - // These are here to force alignment for the storage - long double dummy1; - void (*dummy2)(); - long double dummy3; -#ifdef CATCH_CONFIG_CPP11_LONG_LONG - long long dummy4; -#endif + struct WithinAbsMatcher : MatcherBase<double> { + WithinAbsMatcher(double target, double margin); + bool match(double const& matchee) const override; + std::string describe() const override; + private: + double m_target; + double m_margin; }; - }; -} // end namespace Catch + struct WithinUlpsMatcher : MatcherBase<double> { + WithinUlpsMatcher(double target, uint64_t ulps, FloatingPointKind baseType); + bool match(double const& matchee) const override; + std::string describe() const override; + private: + double m_target; + uint64_t m_ulps; + FloatingPointKind m_type; + }; -namespace Catch { + // Given IEEE-754 format for floats and doubles, we can assume + // that float -> double promotion is lossless. Given this, we can + // assume that if we do the standard relative comparison of + // |lhs - rhs| <= epsilon * max(fabs(lhs), fabs(rhs)), then we get + // the same result if we do this for floats, as if we do this for + // doubles that were promoted from floats. + struct WithinRelMatcher : MatcherBase<double> { + WithinRelMatcher(double target, double epsilon); + bool match(double const& matchee) const override; + std::string describe() const override; + private: + double m_target; + double m_epsilon; + }; - struct ITagAliasRegistry { - virtual ~ITagAliasRegistry(); - virtual Option<TagAlias> find( std::string const& alias ) const = 0; - virtual std::string expandAliases( std::string const& unexpandedTestSpec ) const = 0; + } // namespace Floating - static ITagAliasRegistry const& get(); - }; + // The following functions create the actual matcher objects. + // This allows the types to be inferred + Floating::WithinUlpsMatcher WithinULP(double target, uint64_t maxUlpDiff); + Floating::WithinUlpsMatcher WithinULP(float target, uint64_t maxUlpDiff); + Floating::WithinAbsMatcher WithinAbs(double target, double margin); + Floating::WithinRelMatcher WithinRel(double target, double eps); + // defaults epsilon to 100*numeric_limits<double>::epsilon() + Floating::WithinRelMatcher WithinRel(double target); + Floating::WithinRelMatcher WithinRel(float target, float eps); + // defaults epsilon to 100*numeric_limits<float>::epsilon() + Floating::WithinRelMatcher WithinRel(float target); -} // end namespace Catch +} // namespace Matchers +} // namespace Catch -// These files are included here so the single_include script doesn't put them -// in the conditionally compiled sections -// #included from: internal/catch_test_case_info.h -#define TWOBLUECUBES_CATCH_TEST_CASE_INFO_H_INCLUDED +// end catch_matchers_floating.h +// start catch_matchers_generic.hpp +#include <functional> #include <string> -#include <set> - -#ifdef __clang__ -#pragma clang diagnostic push -#pragma clang diagnostic ignored "-Wpadded" -#endif namespace Catch { +namespace Matchers { +namespace Generic { - struct ITestCase; +namespace Detail { + std::string finalizeDescription(const std::string& desc); +} - struct TestCaseInfo { - enum SpecialProperties{ - None = 0, - IsHidden = 1 << 1, - ShouldFail = 1 << 2, - MayFail = 1 << 3, - Throws = 1 << 4, - NonPortable = 1 << 5 - }; +template <typename T> +class PredicateMatcher : public MatcherBase<T> { + std::function<bool(T const&)> m_predicate; + std::string m_description; +public: - TestCaseInfo( std::string const& _name, - std::string const& _className, - std::string const& _description, - std::set<std::string> const& _tags, - SourceLineInfo const& _lineInfo ); + PredicateMatcher(std::function<bool(T const&)> const& elem, std::string const& descr) + :m_predicate(std::move(elem)), + m_description(Detail::finalizeDescription(descr)) + {} - TestCaseInfo( TestCaseInfo const& other ); + bool match( T const& item ) const override { + return m_predicate(item); + } - friend void setTags( TestCaseInfo& testCaseInfo, std::set<std::string> const& tags ); + std::string describe() const override { + return m_description; + } +}; - bool isHidden() const; - bool throws() const; - bool okToFail() const; - bool expectedToFail() const; +} // namespace Generic - std::string name; - std::string className; - std::string description; - std::set<std::string> tags; - std::set<std::string> lcaseTags; - std::string tagsAsString; - SourceLineInfo lineInfo; - SpecialProperties properties; - }; + // The following functions create the actual matcher objects. + // The user has to explicitly specify type to the function, because + // inferring std::function<bool(T const&)> is hard (but possible) and + // requires a lot of TMP. + template<typename T> + Generic::PredicateMatcher<T> Predicate(std::function<bool(T const&)> const& predicate, std::string const& description = "") { + return Generic::PredicateMatcher<T>(predicate, description); + } - class TestCase : public TestCaseInfo { - public: +} // namespace Matchers +} // namespace Catch - TestCase( ITestCase* testCase, TestCaseInfo const& info ); - TestCase( TestCase const& other ); +// end catch_matchers_generic.hpp +// start catch_matchers_string.h - TestCase withName( std::string const& _newName ) const; +#include <string> - void invoke() const; +namespace Catch { +namespace Matchers { - TestCaseInfo const& getTestCaseInfo() const; + namespace StdString { - void swap( TestCase& other ); - bool operator == ( TestCase const& other ) const; - bool operator < ( TestCase const& other ) const; - TestCase& operator = ( TestCase const& other ); + struct CasedString + { + CasedString( std::string const& str, CaseSensitive::Choice caseSensitivity ); + std::string adjustString( std::string const& str ) const; + std::string caseSensitivitySuffix() const; - private: - Ptr<ITestCase> test; - }; + CaseSensitive::Choice m_caseSensitivity; + std::string m_str; + }; - TestCase makeTestCase( ITestCase* testCase, - std::string const& className, - std::string const& name, - std::string const& description, - SourceLineInfo const& lineInfo ); -} + struct StringMatcherBase : MatcherBase<std::string> { + StringMatcherBase( std::string const& operation, CasedString const& comparator ); + std::string describe() const override; -#ifdef __clang__ -#pragma clang diagnostic pop -#endif + CasedString m_comparator; + std::string m_operation; + }; + struct EqualsMatcher : StringMatcherBase { + EqualsMatcher( CasedString const& comparator ); + bool match( std::string const& source ) const override; + }; + struct ContainsMatcher : StringMatcherBase { + ContainsMatcher( CasedString const& comparator ); + bool match( std::string const& source ) const override; + }; + struct StartsWithMatcher : StringMatcherBase { + StartsWithMatcher( CasedString const& comparator ); + bool match( std::string const& source ) const override; + }; + struct EndsWithMatcher : StringMatcherBase { + EndsWithMatcher( CasedString const& comparator ); + bool match( std::string const& source ) const override; + }; -#ifdef __OBJC__ -// #included from: internal/catch_objc.hpp -#define TWOBLUECUBES_CATCH_OBJC_HPP_INCLUDED + struct RegexMatcher : MatcherBase<std::string> { + RegexMatcher( std::string regex, CaseSensitive::Choice caseSensitivity ); + bool match( std::string const& matchee ) const override; + std::string describe() const override; -#import <objc/runtime.h> + private: + std::string m_regex; + CaseSensitive::Choice m_caseSensitivity; + }; -#include <string> + } // namespace StdString -// NB. Any general catch headers included here must be included -// in catch.hpp first to make sure they are included by the single -// header for non obj-usage + // The following functions create the actual matcher objects. + // This allows the types to be inferred -/////////////////////////////////////////////////////////////////////////////// -// This protocol is really only here for (self) documenting purposes, since -// all its methods are optional. -@protocol OcFixture + StdString::EqualsMatcher Equals( std::string const& str, CaseSensitive::Choice caseSensitivity = CaseSensitive::Yes ); + StdString::ContainsMatcher Contains( std::string const& str, CaseSensitive::Choice caseSensitivity = CaseSensitive::Yes ); + StdString::EndsWithMatcher EndsWith( std::string const& str, CaseSensitive::Choice caseSensitivity = CaseSensitive::Yes ); + StdString::StartsWithMatcher StartsWith( std::string const& str, CaseSensitive::Choice caseSensitivity = CaseSensitive::Yes ); + StdString::RegexMatcher Matches( std::string const& regex, CaseSensitive::Choice caseSensitivity = CaseSensitive::Yes ); -@optional +} // namespace Matchers +} // namespace Catch --(void) setUp; --(void) tearDown; +// end catch_matchers_string.h +// start catch_matchers_vector.h -@end +#include <algorithm> namespace Catch { +namespace Matchers { - class OcMethod : public SharedImpl<ITestCase> { - - public: - OcMethod( Class cls, SEL sel ) : m_cls( cls ), m_sel( sel ) {} - - virtual void invoke() const { - id obj = [[m_cls alloc] init]; - - performOptionalSelector( obj, @selector(setUp) ); - performOptionalSelector( obj, m_sel ); - performOptionalSelector( obj, @selector(tearDown) ); - - arcSafeRelease( obj ); - } - private: - virtual ~OcMethod() {} + namespace Vector { + template<typename T, typename Alloc> + struct ContainsElementMatcher : MatcherBase<std::vector<T, Alloc>> { - Class m_cls; - SEL m_sel; - }; + ContainsElementMatcher(T const &comparator) : m_comparator( comparator) {} - namespace Detail{ + bool match(std::vector<T, Alloc> const &v) const override { + for (auto const& el : v) { + if (el == m_comparator) { + return true; + } + } + return false; + } - inline std::string getAnnotation( Class cls, - std::string const& annotationName, - std::string const& testCaseName ) { - NSString* selStr = [[NSString alloc] initWithFormat:@"Catch_%s_%s", annotationName.c_str(), testCaseName.c_str()]; - SEL sel = NSSelectorFromString( selStr ); - arcSafeRelease( selStr ); - id value = performOptionalSelector( cls, sel ); - if( value ) - return [(NSString*)value UTF8String]; - return ""; - } - } + std::string describe() const override { + return "Contains: " + ::Catch::Detail::stringify( m_comparator ); + } - inline size_t registerTestMethods() { - size_t noTestMethods = 0; - int noClasses = objc_getClassList( CATCH_NULL, 0 ); + T const& m_comparator; + }; - Class* classes = (CATCH_UNSAFE_UNRETAINED Class *)malloc( sizeof(Class) * noClasses); - objc_getClassList( classes, noClasses ); + template<typename T, typename AllocComp, typename AllocMatch> + struct ContainsMatcher : MatcherBase<std::vector<T, AllocMatch>> { - for( int c = 0; c < noClasses; c++ ) { - Class cls = classes[c]; - { - u_int count; - Method* methods = class_copyMethodList( cls, &count ); - for( u_int m = 0; m < count ; m++ ) { - SEL selector = method_getName(methods[m]); - std::string methodName = sel_getName(selector); - if( startsWith( methodName, "Catch_TestCase_" ) ) { - std::string testCaseName = methodName.substr( 15 ); - std::string name = Detail::getAnnotation( cls, "Name", testCaseName ); - std::string desc = Detail::getAnnotation( cls, "Description", testCaseName ); - const char* className = class_getName( cls ); + ContainsMatcher(std::vector<T, AllocComp> const &comparator) : m_comparator( comparator ) {} - getMutableRegistryHub().registerTest( makeTestCase( new OcMethod( cls, selector ), className, name.c_str(), desc.c_str(), SourceLineInfo() ) ); - noTestMethods++; + bool match(std::vector<T, AllocMatch> const &v) const override { + // !TBD: see note in EqualsMatcher + if (m_comparator.size() > v.size()) + return false; + for (auto const& comparator : m_comparator) { + auto present = false; + for (const auto& el : v) { + if (el == comparator) { + present = true; + break; + } + } + if (!present) { + return false; } } - free(methods); + return true; + } + std::string describe() const override { + return "Contains: " + ::Catch::Detail::stringify( m_comparator ); } - } - return noTestMethods; - } - namespace Matchers { - namespace Impl { - namespace NSStringMatchers { + std::vector<T, AllocComp> const& m_comparator; + }; - struct StringHolder : MatcherBase<NSString*>{ - StringHolder( NSString* substr ) : m_substr( [substr copy] ){} - StringHolder( StringHolder const& other ) : m_substr( [other.m_substr copy] ){} - StringHolder() { - arcSafeRelease( m_substr ); - } + template<typename T, typename AllocComp, typename AllocMatch> + struct EqualsMatcher : MatcherBase<std::vector<T, AllocMatch>> { + + EqualsMatcher(std::vector<T, AllocComp> const &comparator) : m_comparator( comparator ) {} - virtual bool match( NSString* arg ) const CATCH_OVERRIDE { + bool match(std::vector<T, AllocMatch> const &v) const override { + // !TBD: This currently works if all elements can be compared using != + // - a more general approach would be via a compare template that defaults + // to using !=. but could be specialised for, e.g. std::vector<T, Alloc> etc + // - then just call that directly + if (m_comparator.size() != v.size()) return false; - } + for (std::size_t i = 0; i < v.size(); ++i) + if (m_comparator[i] != v[i]) + return false; + return true; + } + std::string describe() const override { + return "Equals: " + ::Catch::Detail::stringify( m_comparator ); + } + std::vector<T, AllocComp> const& m_comparator; + }; - NSString* m_substr; - }; + template<typename T, typename AllocComp, typename AllocMatch> + struct ApproxMatcher : MatcherBase<std::vector<T, AllocMatch>> { - struct Equals : StringHolder { - Equals( NSString* substr ) : StringHolder( substr ){} + ApproxMatcher(std::vector<T, AllocComp> const& comparator) : m_comparator( comparator ) {} - virtual bool match( NSString* str ) const CATCH_OVERRIDE { - return (str != nil || m_substr == nil ) && - [str isEqualToString:m_substr]; - } + bool match(std::vector<T, AllocMatch> const &v) const override { + if (m_comparator.size() != v.size()) + return false; + for (std::size_t i = 0; i < v.size(); ++i) + if (m_comparator[i] != approx(v[i])) + return false; + return true; + } + std::string describe() const override { + return "is approx: " + ::Catch::Detail::stringify( m_comparator ); + } + template <typename = typename std::enable_if<std::is_constructible<double, T>::value>::type> + ApproxMatcher& epsilon( T const& newEpsilon ) { + approx.epsilon(newEpsilon); + return *this; + } + template <typename = typename std::enable_if<std::is_constructible<double, T>::value>::type> + ApproxMatcher& margin( T const& newMargin ) { + approx.margin(newMargin); + return *this; + } + template <typename = typename std::enable_if<std::is_constructible<double, T>::value>::type> + ApproxMatcher& scale( T const& newScale ) { + approx.scale(newScale); + return *this; + } + + std::vector<T, AllocComp> const& m_comparator; + mutable Catch::Detail::Approx approx = Catch::Detail::Approx::custom(); + }; - virtual std::string describe() const CATCH_OVERRIDE { - return "equals string: " + Catch::toString( m_substr ); + template<typename T, typename AllocComp, typename AllocMatch> + struct UnorderedEqualsMatcher : MatcherBase<std::vector<T, AllocMatch>> { + UnorderedEqualsMatcher(std::vector<T, AllocComp> const& target) : m_target(target) {} + bool match(std::vector<T, AllocMatch> const& vec) const override { + if (m_target.size() != vec.size()) { + return false; } - }; + return std::is_permutation(m_target.begin(), m_target.end(), vec.begin()); + } - struct Contains : StringHolder { - Contains( NSString* substr ) : StringHolder( substr ){} + std::string describe() const override { + return "UnorderedEquals: " + ::Catch::Detail::stringify(m_target); + } + private: + std::vector<T, AllocComp> const& m_target; + }; - virtual bool match( NSString* str ) const { - return (str != nil || m_substr == nil ) && - [str rangeOfString:m_substr].location != NSNotFound; - } + } // namespace Vector - virtual std::string describe() const CATCH_OVERRIDE { - return "contains string: " + Catch::toString( m_substr ); - } - }; + // The following functions create the actual matcher objects. + // This allows the types to be inferred - struct StartsWith : StringHolder { - StartsWith( NSString* substr ) : StringHolder( substr ){} + template<typename T, typename AllocComp = std::allocator<T>, typename AllocMatch = AllocComp> + Vector::ContainsMatcher<T, AllocComp, AllocMatch> Contains( std::vector<T, AllocComp> const& comparator ) { + return Vector::ContainsMatcher<T, AllocComp, AllocMatch>( comparator ); + } - virtual bool match( NSString* str ) const { - return (str != nil || m_substr == nil ) && - [str rangeOfString:m_substr].location == 0; - } + template<typename T, typename Alloc = std::allocator<T>> + Vector::ContainsElementMatcher<T, Alloc> VectorContains( T const& comparator ) { + return Vector::ContainsElementMatcher<T, Alloc>( comparator ); + } - virtual std::string describe() const CATCH_OVERRIDE { - return "starts with: " + Catch::toString( m_substr ); - } - }; - struct EndsWith : StringHolder { - EndsWith( NSString* substr ) : StringHolder( substr ){} + template<typename T, typename AllocComp = std::allocator<T>, typename AllocMatch = AllocComp> + Vector::EqualsMatcher<T, AllocComp, AllocMatch> Equals( std::vector<T, AllocComp> const& comparator ) { + return Vector::EqualsMatcher<T, AllocComp, AllocMatch>( comparator ); + } - virtual bool match( NSString* str ) const { - return (str != nil || m_substr == nil ) && - [str rangeOfString:m_substr].location == [str length] - [m_substr length]; - } + template<typename T, typename AllocComp = std::allocator<T>, typename AllocMatch = AllocComp> + Vector::ApproxMatcher<T, AllocComp, AllocMatch> Approx( std::vector<T, AllocComp> const& comparator ) { + return Vector::ApproxMatcher<T, AllocComp, AllocMatch>( comparator ); + } - virtual std::string describe() const CATCH_OVERRIDE { - return "ends with: " + Catch::toString( m_substr ); - } - }; + template<typename T, typename AllocComp = std::allocator<T>, typename AllocMatch = AllocComp> + Vector::UnorderedEqualsMatcher<T, AllocComp, AllocMatch> UnorderedEquals(std::vector<T, AllocComp> const& target) { + return Vector::UnorderedEqualsMatcher<T, AllocComp, AllocMatch>( target ); + } - } // namespace NSStringMatchers - } // namespace Impl +} // namespace Matchers +} // namespace Catch - inline Impl::NSStringMatchers::Equals - Equals( NSString* substr ){ return Impl::NSStringMatchers::Equals( substr ); } +// end catch_matchers_vector.h +namespace Catch { - inline Impl::NSStringMatchers::Contains - Contains( NSString* substr ){ return Impl::NSStringMatchers::Contains( substr ); } + template<typename ArgT, typename MatcherT> + class MatchExpr : public ITransientExpression { + ArgT const& m_arg; + MatcherT m_matcher; + StringRef m_matcherString; + public: + MatchExpr( ArgT const& arg, MatcherT const& matcher, StringRef const& matcherString ) + : ITransientExpression{ true, matcher.match( arg ) }, + m_arg( arg ), + m_matcher( matcher ), + m_matcherString( matcherString ) + {} - inline Impl::NSStringMatchers::StartsWith - StartsWith( NSString* substr ){ return Impl::NSStringMatchers::StartsWith( substr ); } + void streamReconstructedExpression( std::ostream &os ) const override { + auto matcherAsString = m_matcher.toString(); + os << Catch::Detail::stringify( m_arg ) << ' '; + if( matcherAsString == Detail::unprintableString ) + os << m_matcherString; + else + os << matcherAsString; + } + }; - inline Impl::NSStringMatchers::EndsWith - EndsWith( NSString* substr ){ return Impl::NSStringMatchers::EndsWith( substr ); } + using StringMatcher = Matchers::Impl::MatcherBase<std::string>; - } // namespace Matchers + void handleExceptionMatchExpr( AssertionHandler& handler, StringMatcher const& matcher, StringRef const& matcherString ); - using namespace Matchers; + template<typename ArgT, typename MatcherT> + auto makeMatchExpr( ArgT const& arg, MatcherT const& matcher, StringRef const& matcherString ) -> MatchExpr<ArgT, MatcherT> { + return MatchExpr<ArgT, MatcherT>( arg, matcher, matcherString ); + } } // namespace Catch /////////////////////////////////////////////////////////////////////////////// -#define OC_TEST_CASE( name, desc )\ -+(NSString*) INTERNAL_CATCH_UNIQUE_NAME( Catch_Name_test ) \ -{\ -return @ name; \ -}\ -+(NSString*) INTERNAL_CATCH_UNIQUE_NAME( Catch_Description_test ) \ -{ \ -return @ desc; \ -} \ --(void) INTERNAL_CATCH_UNIQUE_NAME( Catch_TestCase_test ) - -#endif +#define INTERNAL_CHECK_THAT( macroName, matcher, resultDisposition, arg ) \ + do { \ + Catch::AssertionHandler catchAssertionHandler( macroName##_catch_sr, CATCH_INTERNAL_LINEINFO, CATCH_INTERNAL_STRINGIFY(arg) ", " CATCH_INTERNAL_STRINGIFY(matcher), resultDisposition ); \ + INTERNAL_CATCH_TRY { \ + catchAssertionHandler.handleExpr( Catch::makeMatchExpr( arg, matcher, #matcher##_catch_sr ) ); \ + } INTERNAL_CATCH_CATCH( catchAssertionHandler ) \ + INTERNAL_CATCH_REACT( catchAssertionHandler ) \ + } while( false ) -#ifdef CATCH_IMPL +/////////////////////////////////////////////////////////////////////////////// +#define INTERNAL_CATCH_THROWS_MATCHES( macroName, exceptionType, resultDisposition, matcher, ... ) \ + do { \ + Catch::AssertionHandler catchAssertionHandler( macroName##_catch_sr, CATCH_INTERNAL_LINEINFO, CATCH_INTERNAL_STRINGIFY(__VA_ARGS__) ", " CATCH_INTERNAL_STRINGIFY(exceptionType) ", " CATCH_INTERNAL_STRINGIFY(matcher), resultDisposition ); \ + if( catchAssertionHandler.allowThrows() ) \ + try { \ + static_cast<void>(__VA_ARGS__ ); \ + catchAssertionHandler.handleUnexpectedExceptionNotThrown(); \ + } \ + catch( exceptionType const& ex ) { \ + catchAssertionHandler.handleExpr( Catch::makeMatchExpr( ex, matcher, #matcher##_catch_sr ) ); \ + } \ + catch( ... ) { \ + catchAssertionHandler.handleUnexpectedInflightException(); \ + } \ + else \ + catchAssertionHandler.handleThrowingCallSkipped(); \ + INTERNAL_CATCH_REACT( catchAssertionHandler ) \ + } while( false ) -// !TBD: Move the leak detector code into a separate header -#ifdef CATCH_CONFIG_WINDOWS_CRTDBG -#include <crtdbg.h> -class LeakDetector { -public: - LeakDetector() { - int flag = _CrtSetDbgFlag(_CRTDBG_REPORT_FLAG); - flag |= _CRTDBG_LEAK_CHECK_DF; - flag |= _CRTDBG_ALLOC_MEM_DF; - _CrtSetDbgFlag(flag); - _CrtSetReportMode(_CRT_WARN, _CRTDBG_MODE_FILE | _CRTDBG_MODE_DEBUG); - _CrtSetReportFile(_CRT_WARN, _CRTDBG_FILE_STDERR); - // Change this to leaking allocation's number to break there - _CrtSetBreakAlloc(-1); - } -}; -#else -class LeakDetector {}; +// end catch_capture_matchers.h #endif +// start catch_generators.hpp -LeakDetector leakDetector; +// start catch_interfaces_generatortracker.h -// #included from: internal/catch_impl.hpp -#define TWOBLUECUBES_CATCH_IMPL_HPP_INCLUDED -// Collect all the implementation files together here -// These are the equivalent of what would usually be cpp files +#include <memory> -#ifdef __clang__ -#pragma clang diagnostic push -#pragma clang diagnostic ignored "-Wweak-vtables" -#endif +namespace Catch { -// #included from: ../catch_session.hpp -#define TWOBLUECUBES_CATCH_RUNNER_HPP_INCLUDED + namespace Generators { + class GeneratorUntypedBase { + public: + GeneratorUntypedBase() = default; + virtual ~GeneratorUntypedBase(); + // Attempts to move the generator to the next element + // + // Returns true iff the move succeeded (and a valid element + // can be retrieved). + virtual bool next() = 0; + }; + using GeneratorBasePtr = std::unique_ptr<GeneratorUntypedBase>; -// #included from: internal/catch_commandline.hpp -#define TWOBLUECUBES_CATCH_COMMANDLINE_HPP_INCLUDED + } // namespace Generators -// #included from: catch_config.hpp -#define TWOBLUECUBES_CATCH_CONFIG_HPP_INCLUDED + struct IGeneratorTracker { + virtual ~IGeneratorTracker(); + virtual auto hasGenerator() const -> bool = 0; + virtual auto getGenerator() const -> Generators::GeneratorBasePtr const& = 0; + virtual void setGenerator( Generators::GeneratorBasePtr&& generator ) = 0; + }; -// #included from: catch_test_spec_parser.hpp -#define TWOBLUECUBES_CATCH_TEST_SPEC_PARSER_HPP_INCLUDED +} // namespace Catch -#ifdef __clang__ -#pragma clang diagnostic push -#pragma clang diagnostic ignored "-Wpadded" -#endif +// end catch_interfaces_generatortracker.h +// start catch_enforce.h -// #included from: catch_test_spec.hpp -#define TWOBLUECUBES_CATCH_TEST_SPEC_HPP_INCLUDED +#include <exception> -#ifdef __clang__ -#pragma clang diagnostic push -#pragma clang diagnostic ignored "-Wpadded" +namespace Catch { +#if !defined(CATCH_CONFIG_DISABLE_EXCEPTIONS) + template <typename Ex> + [[noreturn]] + void throw_exception(Ex const& e) { + throw e; + } +#else // ^^ Exceptions are enabled // Exceptions are disabled vv + [[noreturn]] + void throw_exception(std::exception const& e); #endif -// #included from: catch_wildcard_pattern.hpp -#define TWOBLUECUBES_CATCH_WILDCARD_PATTERN_HPP_INCLUDED + [[noreturn]] + void throw_logic_error(std::string const& msg); + [[noreturn]] + void throw_domain_error(std::string const& msg); + [[noreturn]] + void throw_runtime_error(std::string const& msg); -#include <stdexcept> +} // namespace Catch; -namespace Catch -{ - class WildcardPattern { - enum WildcardPosition { - NoWildcard = 0, - WildcardAtStart = 1, - WildcardAtEnd = 2, - WildcardAtBothEnds = WildcardAtStart | WildcardAtEnd - }; +#define CATCH_MAKE_MSG(...) \ + (Catch::ReusableStringStream() << __VA_ARGS__).str() - public: +#define CATCH_INTERNAL_ERROR(...) \ + Catch::throw_logic_error(CATCH_MAKE_MSG( CATCH_INTERNAL_LINEINFO << ": Internal Catch2 error: " << __VA_ARGS__)) - 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<WildcardPosition>( 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 ); - } +#define CATCH_ERROR(...) \ + Catch::throw_domain_error(CATCH_MAKE_MSG( __VA_ARGS__ )) -#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; - }; -} +#define CATCH_RUNTIME_ERROR(...) \ + Catch::throw_runtime_error(CATCH_MAKE_MSG( __VA_ARGS__ )) -#include <string> +#define CATCH_ENFORCE( condition, ... ) \ + do{ if( !(condition) ) CATCH_ERROR( __VA_ARGS__ ); } while(false) + +// end catch_enforce.h +#include <memory> #include <vector> +#include <cassert> + +#include <utility> +#include <exception> namespace Catch { - class TestSpec { - struct Pattern : SharedImpl<> { - virtual ~Pattern(); - virtual bool matches( TestCaseInfo const& testCase ) const = 0; - }; - class NamePattern : public Pattern { - public: - NamePattern( std::string const& name ) - : m_wildcardPattern( toLower( name ), CaseSensitive::No ) - {} - virtual ~NamePattern(); - virtual bool matches( TestCaseInfo const& testCase ) const { - return m_wildcardPattern.matches( toLower( testCase.name ) ); - } - private: - WildcardPattern m_wildcardPattern; - }; +class GeneratorException : public std::exception { + const char* const m_msg = ""; - class TagPattern : public Pattern { - public: - TagPattern( std::string const& tag ) : m_tag( toLower( tag ) ) {} - virtual ~TagPattern(); - virtual bool matches( TestCaseInfo const& testCase ) const { - return testCase.lcaseTags.find( m_tag ) != testCase.lcaseTags.end(); - } - private: - std::string m_tag; - }; +public: + GeneratorException(const char* msg): + m_msg(msg) + {} - class ExcludedPattern : public Pattern { - public: - ExcludedPattern( Ptr<Pattern> const& underlyingPattern ) : m_underlyingPattern( underlyingPattern ) {} - virtual ~ExcludedPattern(); - virtual bool matches( TestCaseInfo const& testCase ) const { return !m_underlyingPattern->matches( testCase ); } - private: - Ptr<Pattern> m_underlyingPattern; - }; + const char* what() const noexcept override final; +}; - struct Filter { - std::vector<Ptr<Pattern> > m_patterns; +namespace Generators { - bool matches( TestCaseInfo const& testCase ) const { - // All patterns in a filter must match for the filter to be a match - for( std::vector<Ptr<Pattern> >::const_iterator it = m_patterns.begin(), itEnd = m_patterns.end(); it != itEnd; ++it ) { - if( !(*it)->matches( testCase ) ) - return false; - } - return true; - } - }; + // !TBD move this into its own location? + namespace pf{ + template<typename T, typename... Args> + std::unique_ptr<T> make_unique( Args&&... args ) { + return std::unique_ptr<T>(new T(std::forward<Args>(args)...)); + } + } + template<typename T> + struct IGenerator : GeneratorUntypedBase { + virtual ~IGenerator() = default; + + // Returns the current element of the generator + // + // \Precondition The generator is either freshly constructed, + // or the last call to `next()` returned true + virtual T const& get() const = 0; + using type = T; + }; + + template<typename T> + class SingleValueGenerator final : public IGenerator<T> { + T m_value; public: - bool hasFilters() const { - return !m_filters.empty(); + SingleValueGenerator(T&& value) : m_value(std::move(value)) {} + + T const& get() const override { + return m_value; } - bool matches( TestCaseInfo const& testCase ) const { - // A TestSpec matches if any filter matches - for( std::vector<Filter>::const_iterator it = m_filters.begin(), itEnd = m_filters.end(); it != itEnd; ++it ) - if( it->matches( testCase ) ) - return true; + bool next() override { return false; } + }; - private: - std::vector<Filter> m_filters; + template<typename T> + class FixedValuesGenerator final : public IGenerator<T> { + static_assert(!std::is_same<T, bool>::value, + "FixedValuesGenerator does not support bools because of std::vector<bool>" + "specialization, use SingleValue Generator instead."); + std::vector<T> m_values; + size_t m_idx = 0; + public: + FixedValuesGenerator( std::initializer_list<T> values ) : m_values( values ) {} - friend class TestSpecParser; + T const& get() const override { + return m_values[m_idx]; + } + bool next() override { + ++m_idx; + return m_idx < m_values.size(); + } }; -} -#ifdef __clang__ -#pragma clang diagnostic pop -#endif + template <typename T> + class GeneratorWrapper final { + std::unique_ptr<IGenerator<T>> m_generator; + public: + GeneratorWrapper(std::unique_ptr<IGenerator<T>> generator): + m_generator(std::move(generator)) + {} + T const& get() const { + return m_generator->get(); + } + bool next() { + return m_generator->next(); + } + }; -namespace Catch { + template <typename T> + GeneratorWrapper<T> value(T&& value) { + return GeneratorWrapper<T>(pf::make_unique<SingleValueGenerator<T>>(std::forward<T>(value))); + } + template <typename T> + GeneratorWrapper<T> values(std::initializer_list<T> values) { + return GeneratorWrapper<T>(pf::make_unique<FixedValuesGenerator<T>>(values)); + } - class TestSpecParser { - enum Mode{ None, Name, QuotedName, Tag, EscapedName }; - Mode m_mode; - bool m_exclusion; - std::size_t m_start, m_pos; - std::string m_arg; - std::vector<std::size_t> m_escapeChars; - TestSpec::Filter m_currentFilter; - TestSpec m_testSpec; - ITagAliasRegistry const* m_tagAliases; + template<typename T> + class Generators : public IGenerator<T> { + std::vector<GeneratorWrapper<T>> m_generators; + size_t m_current = 0; + + void populate(GeneratorWrapper<T>&& generator) { + m_generators.emplace_back(std::move(generator)); + } + void populate(T&& val) { + m_generators.emplace_back(value(std::forward<T>(val))); + } + template<typename U> + void populate(U&& val) { + populate(T(std::forward<U>(val))); + } + template<typename U, typename... Gs> + void populate(U&& valueOrGenerator, Gs &&... moreGenerators) { + populate(std::forward<U>(valueOrGenerator)); + populate(std::forward<Gs>(moreGenerators)...); + } public: - TestSpecParser( ITagAliasRegistry const& tagAliases ) :m_mode(None), m_exclusion(false), m_start(0), m_pos(0), m_tagAliases( &tagAliases ) {} - - TestSpecParser& parse( std::string const& arg ) { - m_mode = None; - m_exclusion = false; - m_start = std::string::npos; - m_arg = m_tagAliases->expandAliases( arg ); - m_escapeChars.clear(); - for( m_pos = 0; m_pos < m_arg.size(); ++m_pos ) - visitChar( m_arg[m_pos] ); - if( m_mode == Name ) - addPattern<TestSpec::NamePattern>(); - return *this; + template <typename... Gs> + Generators(Gs &&... moreGenerators) { + m_generators.reserve(sizeof...(Gs)); + populate(std::forward<Gs>(moreGenerators)...); } - TestSpec testSpec() { - addFilter(); - return m_testSpec; + + T const& get() const override { + return m_generators[m_current].get(); } - private: - void visitChar( char c ) { - if( m_mode == None ) { - switch( c ) { - case ' ': return; - case '~': m_exclusion = true; return; - case '[': return startNewMode( Tag, ++m_pos ); - case '"': return startNewMode( QuotedName, ++m_pos ); - case '\\': return escape(); - default: startNewMode( Name, m_pos ); break; - } - } - if( m_mode == Name ) { - if( c == ',' ) { - addPattern<TestSpec::NamePattern>(); - addFilter(); - } - else if( c == '[' ) { - if( subString() == "exclude:" ) - m_exclusion = true; - else - addPattern<TestSpec::NamePattern>(); - startNewMode( Tag, ++m_pos ); - } - else if( c == '\\' ) - escape(); - } - else if( m_mode == EscapedName ) - m_mode = Name; - else if( m_mode == QuotedName && c == '"' ) - addPattern<TestSpec::NamePattern>(); - else if( m_mode == Tag && c == ']' ) - addPattern<TestSpec::TagPattern>(); - } - void startNewMode( Mode mode, std::size_t start ) { - m_mode = mode; - m_start = start; - } - void escape() { - if( m_mode == None ) - m_start = m_pos; - m_mode = EscapedName; - m_escapeChars.push_back( m_pos ); - } - std::string subString() const { return m_arg.substr( m_start, m_pos - m_start ); } - template<typename T> - void addPattern() { - std::string token = subString(); - for( size_t i = 0; i < m_escapeChars.size(); ++i ) - token = token.substr( 0, m_escapeChars[i]-m_start-i ) + token.substr( m_escapeChars[i]-m_start-i+1 ); - m_escapeChars.clear(); - if( startsWith( token, "exclude:" ) ) { - m_exclusion = true; - token = token.substr( 8 ); - } - if( !token.empty() ) { - Ptr<TestSpec::Pattern> pattern = new T( token ); - if( m_exclusion ) - pattern = new TestSpec::ExcludedPattern( pattern ); - m_currentFilter.m_patterns.push_back( pattern ); + + bool next() override { + if (m_current >= m_generators.size()) { + return false; } - m_exclusion = false; - m_mode = None; - } - void addFilter() { - if( !m_currentFilter.m_patterns.empty() ) { - m_testSpec.m_filters.push_back( m_currentFilter ); - m_currentFilter = TestSpec::Filter(); + const bool current_status = m_generators[m_current].next(); + if (!current_status) { + ++m_current; } + return m_current < m_generators.size(); } }; - inline TestSpec parseTestSpec( std::string const& arg ) { - return TestSpecParser( ITagAliasRegistry::get() ).parse( arg ).testSpec(); - } - -} // namespace Catch -#ifdef __clang__ -#pragma clang diagnostic pop -#endif + template<typename... Ts> + GeneratorWrapper<std::tuple<Ts...>> table( std::initializer_list<std::tuple<typename std::decay<Ts>::type...>> tuples ) { + return values<std::tuple<Ts...>>( tuples ); + } -// #included from: catch_interfaces_config.h -#define TWOBLUECUBES_CATCH_INTERFACES_CONFIG_H_INCLUDED + // Tag type to signal that a generator sequence should convert arguments to a specific type + template <typename T> + struct as {}; -#include <iosfwd> -#include <string> -#include <vector> + template<typename T, typename... Gs> + auto makeGenerators( GeneratorWrapper<T>&& generator, Gs &&... moreGenerators ) -> Generators<T> { + return Generators<T>(std::move(generator), std::forward<Gs>(moreGenerators)...); + } + template<typename T> + auto makeGenerators( GeneratorWrapper<T>&& generator ) -> Generators<T> { + return Generators<T>(std::move(generator)); + } + template<typename T, typename... Gs> + auto makeGenerators( T&& val, Gs &&... moreGenerators ) -> Generators<T> { + return makeGenerators( value( std::forward<T>( val ) ), std::forward<Gs>( moreGenerators )... ); + } + template<typename T, typename U, typename... Gs> + auto makeGenerators( as<T>, U&& val, Gs &&... moreGenerators ) -> Generators<T> { + return makeGenerators( value( T( std::forward<U>( val ) ) ), std::forward<Gs>( moreGenerators )... ); + } -namespace Catch { + auto acquireGeneratorTracker( StringRef generatorName, SourceLineInfo const& lineInfo ) -> IGeneratorTracker&; - struct Verbosity { enum Level { - NoOutput = 0, - Quiet, - Normal - }; }; + template<typename L> + // Note: The type after -> is weird, because VS2015 cannot parse + // the expression used in the typedef inside, when it is in + // return type. Yeah. + auto generate( StringRef generatorName, SourceLineInfo const& lineInfo, L const& generatorExpression ) -> decltype(std::declval<decltype(generatorExpression())>().get()) { + using UnderlyingType = typename decltype(generatorExpression())::type; - struct WarnAbout { enum What { - Nothing = 0x00, - NoAssertions = 0x01 - }; }; + IGeneratorTracker& tracker = acquireGeneratorTracker( generatorName, lineInfo ); + if (!tracker.hasGenerator()) { + tracker.setGenerator(pf::make_unique<Generators<UnderlyingType>>(generatorExpression())); + } - struct ShowDurations { enum OrNot { - DefaultForReporter, - Always, - Never - }; }; - struct RunTests { enum InWhatOrder { - InDeclarationOrder, - InLexicographicalOrder, - InRandomOrder - }; }; - struct UseColour { enum YesOrNo { - Auto, - Yes, - No - }; }; - struct WaitForKeypress { enum When { - Never, - BeforeStart = 1, - BeforeExit = 2, - BeforeStartAndExit = BeforeStart | BeforeExit - }; }; + auto const& generator = static_cast<IGenerator<UnderlyingType> const&>( *tracker.getGenerator() ); + return generator.get(); + } - class TestSpec; +} // namespace Generators +} // namespace Catch - struct IConfig : IShared { +#define GENERATE( ... ) \ + Catch::Generators::generate( INTERNAL_CATCH_STRINGIZE(INTERNAL_CATCH_UNIQUE_NAME(generator)), \ + CATCH_INTERNAL_LINEINFO, \ + [ ]{ using namespace Catch::Generators; return makeGenerators( __VA_ARGS__ ); } ) //NOLINT(google-build-using-namespace) +#define GENERATE_COPY( ... ) \ + Catch::Generators::generate( INTERNAL_CATCH_STRINGIZE(INTERNAL_CATCH_UNIQUE_NAME(generator)), \ + CATCH_INTERNAL_LINEINFO, \ + [=]{ using namespace Catch::Generators; return makeGenerators( __VA_ARGS__ ); } ) //NOLINT(google-build-using-namespace) +#define GENERATE_REF( ... ) \ + Catch::Generators::generate( INTERNAL_CATCH_STRINGIZE(INTERNAL_CATCH_UNIQUE_NAME(generator)), \ + CATCH_INTERNAL_LINEINFO, \ + [&]{ using namespace Catch::Generators; return makeGenerators( __VA_ARGS__ ); } ) //NOLINT(google-build-using-namespace) + +// end catch_generators.hpp +// start catch_generators_generic.hpp - virtual ~IConfig(); +namespace Catch { +namespace Generators { - virtual bool allowThrows() const = 0; - virtual std::ostream& stream() const = 0; - virtual std::string name() const = 0; - virtual bool includeSuccessfulResults() const = 0; - virtual bool shouldDebugBreak() const = 0; - virtual bool warnAboutMissingAssertions() const = 0; - virtual int abortAfter() const = 0; - virtual bool showInvisibles() const = 0; - virtual ShowDurations::OrNot showDurations() const = 0; - virtual TestSpec const& testSpec() const = 0; - virtual RunTests::InWhatOrder runOrder() const = 0; - virtual unsigned int rngSeed() const = 0; - virtual UseColour::YesOrNo useColour() const = 0; - virtual std::vector<std::string> const& getSectionsToRun() const = 0; + template <typename T> + class TakeGenerator : public IGenerator<T> { + GeneratorWrapper<T> m_generator; + size_t m_returned = 0; + size_t m_target; + public: + TakeGenerator(size_t target, GeneratorWrapper<T>&& generator): + m_generator(std::move(generator)), + m_target(target) + { + assert(target != 0 && "Empty generators are not allowed"); + } + T const& get() const override { + return m_generator.get(); + } + bool next() override { + ++m_returned; + if (m_returned >= m_target) { + return false; + } + const auto success = m_generator.next(); + // If the underlying generator does not contain enough values + // then we cut short as well + if (!success) { + m_returned = m_target; + } + return success; + } }; -} - -// #included from: catch_stream.h -#define TWOBLUECUBES_CATCH_STREAM_H_INCLUDED -// #included from: catch_streambuf.h -#define TWOBLUECUBES_CATCH_STREAMBUF_H_INCLUDED - -#include <streambuf> - -namespace Catch { + template <typename T> + GeneratorWrapper<T> take(size_t target, GeneratorWrapper<T>&& generator) { + return GeneratorWrapper<T>(pf::make_unique<TakeGenerator<T>>(target, std::move(generator))); + } - class StreamBufBase : public std::streambuf { + template <typename T, typename Predicate> + class FilterGenerator : public IGenerator<T> { + GeneratorWrapper<T> m_generator; + Predicate m_predicate; public: - virtual ~StreamBufBase() CATCH_NOEXCEPT; - }; -} - -#include <streambuf> -#include <ostream> -#include <fstream> -#include <memory> + template <typename P = Predicate> + FilterGenerator(P&& pred, GeneratorWrapper<T>&& generator): + m_generator(std::move(generator)), + m_predicate(std::forward<P>(pred)) + { + if (!m_predicate(m_generator.get())) { + // It might happen that there are no values that pass the + // filter. In that case we throw an exception. + auto has_initial_value = nextImpl(); + if (!has_initial_value) { + Catch::throw_exception(GeneratorException("No valid value found in filtered generator")); + } + } + } -namespace Catch { + T const& get() const override { + return m_generator.get(); + } - std::ostream& cout(); - std::ostream& cerr(); - std::ostream& clog(); + bool next() override { + return nextImpl(); + } - struct IStream { - virtual ~IStream() CATCH_NOEXCEPT; - virtual std::ostream& stream() const = 0; + private: + bool nextImpl() { + bool success = m_generator.next(); + if (!success) { + return false; + } + while (!m_predicate(m_generator.get()) && (success = m_generator.next()) == true); + return success; + } }; - class FileStream : public IStream { - mutable std::ofstream m_ofs; + template <typename T, typename Predicate> + GeneratorWrapper<T> filter(Predicate&& pred, GeneratorWrapper<T>&& generator) { + return GeneratorWrapper<T>(std::unique_ptr<IGenerator<T>>(pf::make_unique<FilterGenerator<T, Predicate>>(std::forward<Predicate>(pred), std::move(generator)))); + } + + template <typename T> + class RepeatGenerator : public IGenerator<T> { + static_assert(!std::is_same<T, bool>::value, + "RepeatGenerator currently does not support bools" + "because of std::vector<bool> specialization"); + GeneratorWrapper<T> m_generator; + mutable std::vector<T> m_returned; + size_t m_target_repeats; + size_t m_current_repeat = 0; + size_t m_repeat_index = 0; public: - FileStream( std::string const& filename ); - virtual ~FileStream() CATCH_NOEXCEPT; - public: // IStream - virtual std::ostream& stream() const CATCH_OVERRIDE; - }; + RepeatGenerator(size_t repeats, GeneratorWrapper<T>&& generator): + m_generator(std::move(generator)), + m_target_repeats(repeats) + { + assert(m_target_repeats > 0 && "Repeat generator must repeat at least once"); + } - class CoutStream : public IStream { - mutable std::ostream m_os; - public: - CoutStream(); - virtual ~CoutStream() CATCH_NOEXCEPT; + T const& get() const override { + if (m_current_repeat == 0) { + m_returned.push_back(m_generator.get()); + return m_returned.back(); + } + return m_returned[m_repeat_index]; + } - public: // IStream - virtual std::ostream& stream() const CATCH_OVERRIDE; - }; + bool next() override { + // There are 2 basic cases: + // 1) We are still reading the generator + // 2) We are reading our own cache - class DebugOutStream : public IStream { - CATCH_AUTO_PTR( StreamBufBase ) m_streamBuf; - mutable std::ostream m_os; - public: - DebugOutStream(); - virtual ~DebugOutStream() CATCH_NOEXCEPT; + // In the first case, we need to poke the underlying generator. + // If it happily moves, we are left in that state, otherwise it is time to start reading from our cache + if (m_current_repeat == 0) { + const auto success = m_generator.next(); + if (!success) { + ++m_current_repeat; + } + return m_current_repeat < m_target_repeats; + } - public: // IStream - virtual std::ostream& stream() const CATCH_OVERRIDE; + // In the second case, we need to move indices forward and check that we haven't run up against the end + ++m_repeat_index; + if (m_repeat_index == m_returned.size()) { + m_repeat_index = 0; + ++m_current_repeat; + } + return m_current_repeat < m_target_repeats; + } }; -} - -#include <memory> -#include <vector> -#include <string> -#include <stdexcept> -#ifndef CATCH_CONFIG_CONSOLE_WIDTH -#define CATCH_CONFIG_CONSOLE_WIDTH 80 -#endif - -namespace Catch { - - struct ConfigData { + template <typename T> + GeneratorWrapper<T> repeat(size_t repeats, GeneratorWrapper<T>&& generator) { + return GeneratorWrapper<T>(pf::make_unique<RepeatGenerator<T>>(repeats, std::move(generator))); + } - ConfigData() - : listTests( false ), - listTags( false ), - listReporters( false ), - listTestNamesOnly( false ), - listExtraInfo( false ), - showSuccessfulTests( false ), - shouldDebugBreak( false ), - noThrow( false ), - showHelp( false ), - showInvisibles( false ), - filenamesAsTags( false ), - libIdentify( false ), - abortAfter( -1 ), - rngSeed( 0 ), - verbosity( Verbosity::Normal ), - warnings( WarnAbout::Nothing ), - showDurations( ShowDurations::DefaultForReporter ), - runOrder( RunTests::InDeclarationOrder ), - useColour( UseColour::Auto ), - waitForKeypress( WaitForKeypress::Never ) + template <typename T, typename U, typename Func> + class MapGenerator : public IGenerator<T> { + // TBD: provide static assert for mapping function, for friendly error message + GeneratorWrapper<U> m_generator; + Func m_function; + // To avoid returning dangling reference, we have to save the values + T m_cache; + public: + template <typename F2 = Func> + MapGenerator(F2&& function, GeneratorWrapper<U>&& generator) : + m_generator(std::move(generator)), + m_function(std::forward<F2>(function)), + m_cache(m_function(m_generator.get())) {} - bool listTests; - bool listTags; - bool listReporters; - bool listTestNamesOnly; - bool listExtraInfo; - - bool showSuccessfulTests; - bool shouldDebugBreak; - bool noThrow; - bool showHelp; - bool showInvisibles; - bool filenamesAsTags; - bool libIdentify; - - int abortAfter; - unsigned int rngSeed; - - Verbosity::Level verbosity; - WarnAbout::What warnings; - ShowDurations::OrNot showDurations; - RunTests::InWhatOrder runOrder; - UseColour::YesOrNo useColour; - WaitForKeypress::When waitForKeypress; - - std::string outputFilename; - std::string name; - std::string processName; - - std::vector<std::string> reporterNames; - std::vector<std::string> testsOrTags; - std::vector<std::string> sectionsToRun; + T const& get() const override { + return m_cache; + } + bool next() override { + const auto success = m_generator.next(); + if (success) { + m_cache = m_function(m_generator.get()); + } + return success; + } }; - class Config : public SharedImpl<IConfig> { - private: - Config( Config const& other ); - Config& operator = ( Config const& other ); - virtual void dummy(); - public: + template <typename Func, typename U, typename T = FunctionReturnType<Func, U>> + GeneratorWrapper<T> map(Func&& function, GeneratorWrapper<U>&& generator) { + return GeneratorWrapper<T>( + pf::make_unique<MapGenerator<T, U, Func>>(std::forward<Func>(function), std::move(generator)) + ); + } - Config() - {} + template <typename T, typename U, typename Func> + GeneratorWrapper<T> map(Func&& function, GeneratorWrapper<U>&& generator) { + return GeneratorWrapper<T>( + pf::make_unique<MapGenerator<T, U, Func>>(std::forward<Func>(function), std::move(generator)) + ); + } - Config( ConfigData const& data ) - : m_data( data ), - m_stream( openStream() ) + template <typename T> + class ChunkGenerator final : public IGenerator<std::vector<T>> { + std::vector<T> m_chunk; + size_t m_chunk_size; + GeneratorWrapper<T> m_generator; + bool m_used_up = false; + public: + ChunkGenerator(size_t size, GeneratorWrapper<T> generator) : + m_chunk_size(size), m_generator(std::move(generator)) { - if( !data.testsOrTags.empty() ) { - TestSpecParser parser( ITagAliasRegistry::get() ); - for( std::size_t i = 0; i < data.testsOrTags.size(); ++i ) - parser.parse( data.testsOrTags[i] ); - m_testSpec = parser.testSpec(); + m_chunk.reserve(m_chunk_size); + if (m_chunk_size != 0) { + m_chunk.push_back(m_generator.get()); + for (size_t i = 1; i < m_chunk_size; ++i) { + if (!m_generator.next()) { + Catch::throw_exception(GeneratorException("Not enough values to initialize the first chunk")); + } + m_chunk.push_back(m_generator.get()); + } } } - - virtual ~Config() {} - - std::string const& getFilename() const { - return m_data.outputFilename ; + std::vector<T> const& get() const override { + return m_chunk; + } + bool next() override { + m_chunk.clear(); + for (size_t idx = 0; idx < m_chunk_size; ++idx) { + if (!m_generator.next()) { + return false; + } + m_chunk.push_back(m_generator.get()); + } + return true; } + }; - bool listTests() const { return m_data.listTests; } - bool listTestNamesOnly() const { return m_data.listTestNamesOnly; } - bool listTags() const { return m_data.listTags; } - bool listReporters() const { return m_data.listReporters; } - bool listExtraInfo() const { return m_data.listExtraInfo; } + template <typename T> + GeneratorWrapper<std::vector<T>> chunk(size_t size, GeneratorWrapper<T>&& generator) { + return GeneratorWrapper<std::vector<T>>( + pf::make_unique<ChunkGenerator<T>>(size, std::move(generator)) + ); + } - std::string getProcessName() const { return m_data.processName; } +} // namespace Generators +} // namespace Catch - std::vector<std::string> const& getReporterNames() const { return m_data.reporterNames; } - std::vector<std::string> const& getSectionsToRun() const CATCH_OVERRIDE { return m_data.sectionsToRun; } +// end catch_generators_generic.hpp +// start catch_generators_specific.hpp - virtual TestSpec const& testSpec() const CATCH_OVERRIDE { return m_testSpec; } +// start catch_context.h - bool showHelp() const { return m_data.showHelp; } +#include <memory> - // IConfig interface - virtual bool allowThrows() const CATCH_OVERRIDE { return !m_data.noThrow; } - virtual std::ostream& stream() const CATCH_OVERRIDE { return m_stream->stream(); } - virtual std::string name() const CATCH_OVERRIDE { return m_data.name.empty() ? m_data.processName : m_data.name; } - virtual bool includeSuccessfulResults() const CATCH_OVERRIDE { return m_data.showSuccessfulTests; } - virtual bool warnAboutMissingAssertions() const CATCH_OVERRIDE { return m_data.warnings & WarnAbout::NoAssertions; } - virtual ShowDurations::OrNot showDurations() const CATCH_OVERRIDE { return m_data.showDurations; } - virtual RunTests::InWhatOrder runOrder() const CATCH_OVERRIDE { return m_data.runOrder; } - virtual unsigned int rngSeed() const CATCH_OVERRIDE { return m_data.rngSeed; } - virtual UseColour::YesOrNo useColour() const CATCH_OVERRIDE { return m_data.useColour; } - virtual bool shouldDebugBreak() const CATCH_OVERRIDE { return m_data.shouldDebugBreak; } - virtual int abortAfter() const CATCH_OVERRIDE { return m_data.abortAfter; } - virtual bool showInvisibles() const CATCH_OVERRIDE { return m_data.showInvisibles; } +namespace Catch { - private: + struct IResultCapture; + struct IRunner; + struct IConfig; + struct IMutableContext; - 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; + using IConfigPtr = std::shared_ptr<IConfig const>; - CATCH_AUTO_PTR( IStream const ) m_stream; - TestSpec m_testSpec; + struct IContext + { + virtual ~IContext(); + + virtual IResultCapture* getResultCapture() = 0; + virtual IRunner* getRunner() = 0; + virtual IConfigPtr const& getConfig() const = 0; }; -} // end namespace Catch - -// #included from: catch_clara.h -#define TWOBLUECUBES_CATCH_CLARA_H_INCLUDED - -// Use Catch's value for console width (store Clara's off to the side, if present) -#ifdef CLARA_CONFIG_CONSOLE_WIDTH -#define CATCH_TEMP_CLARA_CONFIG_CONSOLE_WIDTH CLARA_CONFIG_CONSOLE_WIDTH -#undef CLARA_CONFIG_CONSOLE_WIDTH -#endif -#define CLARA_CONFIG_CONSOLE_WIDTH CATCH_CONFIG_CONSOLE_WIDTH - -// Declare Clara inside the Catch namespace -#define STITCH_CLARA_OPEN_NAMESPACE namespace Catch { -// #included from: ../external/clara.h - -// Version 0.0.2.4 - -// Only use header guard if we are not using an outer namespace -#if !defined(TWOBLUECUBES_CLARA_H_INCLUDED) || defined(STITCH_CLARA_OPEN_NAMESPACE) + struct IMutableContext : IContext + { + virtual ~IMutableContext(); + virtual void setResultCapture( IResultCapture* resultCapture ) = 0; + virtual void setRunner( IRunner* runner ) = 0; + virtual void setConfig( IConfigPtr const& config ) = 0; -#ifndef STITCH_CLARA_OPEN_NAMESPACE -#define TWOBLUECUBES_CLARA_H_INCLUDED -#define STITCH_CLARA_OPEN_NAMESPACE -#define STITCH_CLARA_CLOSE_NAMESPACE -#else -#define STITCH_CLARA_CLOSE_NAMESPACE } -#endif + private: + static IMutableContext *currentContext; + friend IMutableContext& getCurrentMutableContext(); + friend void cleanUpContext(); + static void createContext(); + }; -#define STITCH_TBC_TEXT_FORMAT_OPEN_NAMESPACE STITCH_CLARA_OPEN_NAMESPACE + inline IMutableContext& getCurrentMutableContext() + { + if( !IMutableContext::currentContext ) + IMutableContext::createContext(); + // NOLINTNEXTLINE(clang-analyzer-core.uninitialized.UndefReturn) + return *IMutableContext::currentContext; + } -// ----------- #included from tbc_text_format.h ----------- + inline IContext& getCurrentContext() + { + return getCurrentMutableContext(); + } -// Only use header guard if we are not using an outer namespace -#if !defined(TBC_TEXT_FORMAT_H_INCLUDED) || defined(STITCH_TBC_TEXT_FORMAT_OUTER_NAMESPACE) -#ifndef STITCH_TBC_TEXT_FORMAT_OUTER_NAMESPACE -#define TBC_TEXT_FORMAT_H_INCLUDED -#endif + void cleanUpContext(); -#include <string> -#include <vector> -#include <sstream> -#include <algorithm> -#include <cctype> + class SimplePcg32; + SimplePcg32& rng(); +} -// Use optional outer namespace -#ifdef STITCH_TBC_TEXT_FORMAT_OUTER_NAMESPACE -namespace STITCH_TBC_TEXT_FORMAT_OUTER_NAMESPACE { -#endif +// end catch_context.h +// start catch_interfaces_config.h -namespace Tbc { +// start catch_option.hpp -#ifdef TBC_TEXT_FORMAT_CONSOLE_WIDTH - const unsigned int consoleWidth = TBC_TEXT_FORMAT_CONSOLE_WIDTH; -#else - const unsigned int consoleWidth = 80; -#endif +namespace Catch { - struct TextAttributes { - TextAttributes() - : initialIndent( std::string::npos ), - indent( 0 ), - width( consoleWidth-1 ), - tabChar( '\t' ) + // An optional type + template<typename T> + class Option { + public: + Option() : nullableValue( nullptr ) {} + Option( T const& _value ) + : nullableValue( new( storage ) T( _value ) ) + {} + Option( Option const& _other ) + : nullableValue( _other ? new( storage ) T( *_other ) : nullptr ) {} - TextAttributes& setInitialIndent( std::size_t _value ) { initialIndent = _value; return *this; } - TextAttributes& setIndent( std::size_t _value ) { indent = _value; return *this; } - TextAttributes& setWidth( std::size_t _value ) { width = _value; return *this; } - TextAttributes& setTabChar( char _value ) { tabChar = _value; return *this; } - - std::size_t initialIndent; // indent of first line, or npos - std::size_t indent; // indent of subsequent lines, or all if initialIndent is npos - std::size_t width; // maximum width of text, including indent. Longer text will wrap - char tabChar; // If this char is seen the indent is changed to current pos - }; - - class Text { - public: - Text( std::string const& _str, TextAttributes const& _attr = TextAttributes() ) - : attr( _attr ) - { - std::string wrappableChars = " [({.,/|\\-"; - std::size_t indent = _attr.initialIndent != std::string::npos - ? _attr.initialIndent - : _attr.indent; - std::string remainder = _str; - - while( !remainder.empty() ) { - if( lines.size() >= 1000 ) { - lines.push_back( "... message truncated due to excessive size" ); - return; - } - std::size_t tabPos = std::string::npos; - std::size_t width = (std::min)( remainder.size(), _attr.width - indent ); - std::size_t pos = remainder.find_first_of( '\n' ); - if( pos <= width ) { - width = pos; - } - pos = remainder.find_last_of( _attr.tabChar, width ); - if( pos != std::string::npos ) { - tabPos = pos; - if( remainder[width] == '\n' ) - width--; - remainder = remainder.substr( 0, tabPos ) + remainder.substr( tabPos+1 ); - } + ~Option() { + reset(); + } - if( width == remainder.size() ) { - spliceLine( indent, remainder, width ); - } - else if( remainder[width] == '\n' ) { - spliceLine( indent, remainder, width ); - if( width <= 1 || remainder.size() != 1 ) - remainder = remainder.substr( 1 ); - indent = _attr.indent; - } - else { - pos = remainder.find_last_of( wrappableChars, width ); - if( pos != std::string::npos && pos > 0 ) { - spliceLine( indent, remainder, pos ); - if( remainder[0] == ' ' ) - remainder = remainder.substr( 1 ); - } - else { - spliceLine( indent, remainder, width-1 ); - lines.back() += "-"; - } - if( lines.size() == 1 ) - indent = _attr.indent; - if( tabPos != std::string::npos ) - indent += tabPos; - } + Option& operator= ( Option const& _other ) { + if( &_other != this ) { + reset(); + if( _other ) + nullableValue = new( storage ) T( *_other ); } + return *this; + } + Option& operator = ( T const& _value ) { + reset(); + nullableValue = new( storage ) T( _value ); + return *this; } - void spliceLine( std::size_t _indent, std::string& _remainder, std::size_t _pos ) { - lines.push_back( std::string( _indent, ' ' ) + _remainder.substr( 0, _pos ) ); - _remainder = _remainder.substr( _pos ); + void reset() { + if( nullableValue ) + nullableValue->~T(); + nullableValue = nullptr; } - typedef std::vector<std::string>::const_iterator const_iterator; + T& operator*() { return *nullableValue; } + T const& operator*() const { return *nullableValue; } + T* operator->() { return nullableValue; } + const T* operator->() const { return nullableValue; } - const_iterator begin() const { return lines.begin(); } - const_iterator end() const { return lines.end(); } - std::string const& last() const { return lines.back(); } - std::size_t size() const { return lines.size(); } - std::string const& operator[]( std::size_t _index ) const { return lines[_index]; } - std::string toString() const { - std::ostringstream oss; - oss << *this; - return oss.str(); + T valueOr( T const& defaultValue ) const { + return nullableValue ? *nullableValue : defaultValue; } - friend std::ostream& operator << ( std::ostream& _stream, Text const& _text ) { - for( Text::const_iterator it = _text.begin(), itEnd = _text.end(); - it != itEnd; ++it ) { - if( it != _text.begin() ) - _stream << "\n"; - _stream << *it; - } - return _stream; + bool some() const { return nullableValue != nullptr; } + bool none() const { return nullableValue == nullptr; } + + bool operator !() const { return nullableValue == nullptr; } + explicit operator bool() const { + return some(); } private: - std::string str; - TextAttributes attr; - std::vector<std::string> lines; + T *nullableValue; + alignas(alignof(T)) char storage[sizeof(T)]; }; -} // end namespace Tbc - -#ifdef STITCH_TBC_TEXT_FORMAT_OUTER_NAMESPACE -} // end outer namespace -#endif +} // end namespace Catch -#endif // TBC_TEXT_FORMAT_H_INCLUDED +// end catch_option.hpp +#include <chrono> +#include <iosfwd> +#include <string> +#include <vector> +#include <memory> -// ----------- end of #include from tbc_text_format.h ----------- -// ........... back in clara.h +namespace Catch { -#undef STITCH_TBC_TEXT_FORMAT_OPEN_NAMESPACE + enum class Verbosity { + Quiet = 0, + Normal, + High + }; -// ----------- #included from clara_compilers.h ----------- + struct WarnAbout { enum What { + Nothing = 0x00, + NoAssertions = 0x01, + NoTests = 0x02 + }; }; -#ifndef TWOBLUECUBES_CLARA_COMPILERS_H_INCLUDED -#define TWOBLUECUBES_CLARA_COMPILERS_H_INCLUDED + struct ShowDurations { enum OrNot { + DefaultForReporter, + Always, + Never + }; }; + struct RunTests { enum InWhatOrder { + InDeclarationOrder, + InLexicographicalOrder, + InRandomOrder + }; }; + struct UseColour { enum YesOrNo { + Auto, + Yes, + No + }; }; + struct WaitForKeypress { enum When { + Never, + BeforeStart = 1, + BeforeExit = 2, + BeforeStartAndExit = BeforeStart | BeforeExit + }; }; -// Detect a number of compiler features - mostly C++11/14 conformance - by compiler -// The following features are defined: -// -// CLARA_CONFIG_CPP11_NULLPTR : is nullptr supported? -// CLARA_CONFIG_CPP11_NOEXCEPT : is noexcept supported? -// CLARA_CONFIG_CPP11_GENERATED_METHODS : The delete and default keywords for compiler generated methods -// CLARA_CONFIG_CPP11_OVERRIDE : is override supported? -// CLARA_CONFIG_CPP11_UNIQUE_PTR : is unique_ptr supported (otherwise use auto_ptr) + class TestSpec; -// CLARA_CONFIG_CPP11_OR_GREATER : Is C++11 supported? + struct IConfig : NonCopyable { -// CLARA_CONFIG_VARIADIC_MACROS : are variadic macros supported? + virtual ~IConfig(); -// In general each macro has a _NO_<feature name> form -// (e.g. CLARA_CONFIG_CPP11_NO_NULLPTR) which disables the feature. -// Many features, at point of detection, define an _INTERNAL_ macro, so they -// can be combined, en-mass, with the _NO_ forms later. + virtual bool allowThrows() const = 0; + virtual std::ostream& stream() const = 0; + virtual std::string name() const = 0; + virtual bool includeSuccessfulResults() const = 0; + virtual bool shouldDebugBreak() const = 0; + virtual bool warnAboutMissingAssertions() const = 0; + virtual bool warnAboutNoTests() const = 0; + virtual int abortAfter() const = 0; + virtual bool showInvisibles() const = 0; + virtual ShowDurations::OrNot showDurations() const = 0; + virtual double minDuration() const = 0; + virtual TestSpec const& testSpec() const = 0; + virtual bool hasTestFilters() const = 0; + virtual std::vector<std::string> const& getTestsOrTags() const = 0; + virtual RunTests::InWhatOrder runOrder() const = 0; + virtual unsigned int rngSeed() const = 0; + virtual UseColour::YesOrNo useColour() const = 0; + virtual std::vector<std::string> const& getSectionsToRun() const = 0; + virtual Verbosity verbosity() const = 0; -// All the C++11 features can be disabled with CLARA_CONFIG_NO_CPP11 + virtual bool benchmarkNoAnalysis() const = 0; + virtual int benchmarkSamples() const = 0; + virtual double benchmarkConfidenceInterval() const = 0; + virtual unsigned int benchmarkResamples() const = 0; + virtual std::chrono::milliseconds benchmarkWarmupTime() const = 0; + }; -#ifdef __clang__ + using IConfigPtr = std::shared_ptr<IConfig const>; +} -#if __has_feature(cxx_nullptr) -#define CLARA_INTERNAL_CONFIG_CPP11_NULLPTR -#endif +// end catch_interfaces_config.h +// start catch_random_number_generator.h -#if __has_feature(cxx_noexcept) -#define CLARA_INTERNAL_CONFIG_CPP11_NOEXCEPT -#endif +#include <cstdint> -#endif // __clang__ +namespace Catch { -//////////////////////////////////////////////////////////////////////////////// -// GCC -#ifdef __GNUC__ + // This is a simple implementation of C++11 Uniform Random Number + // Generator. It does not provide all operators, because Catch2 + // does not use it, but it should behave as expected inside stdlib's + // distributions. + // The implementation is based on the PCG family (http://pcg-random.org) + class SimplePcg32 { + using state_type = std::uint64_t; + public: + using result_type = std::uint32_t; + static constexpr result_type (min)() { + return 0; + } + static constexpr result_type (max)() { + return static_cast<result_type>(-1); + } -#if __GNUC__ == 4 && __GNUC_MINOR__ >= 6 && defined(__GXX_EXPERIMENTAL_CXX0X__) -#define CLARA_INTERNAL_CONFIG_CPP11_NULLPTR -#endif + // Provide some default initial state for the default constructor + SimplePcg32():SimplePcg32(0xed743cc4U) {} -// - otherwise more recent versions define __cplusplus >= 201103L -// and will get picked up below + explicit SimplePcg32(result_type seed_); -#endif // __GNUC__ + void seed(result_type seed_); + void discard(uint64_t skip); -//////////////////////////////////////////////////////////////////////////////// -// Visual C++ -#ifdef _MSC_VER + result_type operator()(); -#if (_MSC_VER >= 1600) -#define CLARA_INTERNAL_CONFIG_CPP11_NULLPTR -#define CLARA_INTERNAL_CONFIG_CPP11_UNIQUE_PTR -#endif + private: + friend bool operator==(SimplePcg32 const& lhs, SimplePcg32 const& rhs); + friend bool operator!=(SimplePcg32 const& lhs, SimplePcg32 const& rhs); + + // In theory we also need operator<< and operator>> + // In practice we do not use them, so we will skip them for now + + std::uint64_t m_state; + // This part of the state determines which "stream" of the numbers + // is chosen -- we take it as a constant for Catch2, so we only + // need to deal with seeding the main state. + // Picked by reading 8 bytes from `/dev/random` :-) + static const std::uint64_t s_inc = (0x13ed0cc53f939476ULL << 1ULL) | 1ULL; + }; -#if (_MSC_VER >= 1900 ) // (VC++ 13 (VS2015)) -#define CLARA_INTERNAL_CONFIG_CPP11_NOEXCEPT -#define CLARA_INTERNAL_CONFIG_CPP11_GENERATED_METHODS -#endif +} // end namespace Catch -#endif // _MSC_VER +// end catch_random_number_generator.h +#include <random> -//////////////////////////////////////////////////////////////////////////////// -// C++ language feature support +namespace Catch { +namespace Generators { -// catch all support for C++11 -#if defined(__cplusplus) && __cplusplus >= 201103L +template <typename Float> +class RandomFloatingGenerator final : public IGenerator<Float> { + Catch::SimplePcg32& m_rng; + std::uniform_real_distribution<Float> m_dist; + Float m_current_number; +public: -#define CLARA_CPP11_OR_GREATER + RandomFloatingGenerator(Float a, Float b): + m_rng(rng()), + m_dist(a, b) { + static_cast<void>(next()); + } -#if !defined(CLARA_INTERNAL_CONFIG_CPP11_NULLPTR) -#define CLARA_INTERNAL_CONFIG_CPP11_NULLPTR -#endif + Float const& get() const override { + return m_current_number; + } + bool next() override { + m_current_number = m_dist(m_rng); + return true; + } +}; -#ifndef CLARA_INTERNAL_CONFIG_CPP11_NOEXCEPT -#define CLARA_INTERNAL_CONFIG_CPP11_NOEXCEPT -#endif +template <typename Integer> +class RandomIntegerGenerator final : public IGenerator<Integer> { + Catch::SimplePcg32& m_rng; + std::uniform_int_distribution<Integer> m_dist; + Integer m_current_number; +public: -#ifndef CLARA_INTERNAL_CONFIG_CPP11_GENERATED_METHODS -#define CLARA_INTERNAL_CONFIG_CPP11_GENERATED_METHODS -#endif + RandomIntegerGenerator(Integer a, Integer b): + m_rng(rng()), + m_dist(a, b) { + static_cast<void>(next()); + } -#if !defined(CLARA_INTERNAL_CONFIG_CPP11_OVERRIDE) -#define CLARA_INTERNAL_CONFIG_CPP11_OVERRIDE -#endif -#if !defined(CLARA_INTERNAL_CONFIG_CPP11_UNIQUE_PTR) -#define CLARA_INTERNAL_CONFIG_CPP11_UNIQUE_PTR -#endif + Integer const& get() const override { + return m_current_number; + } + bool next() override { + m_current_number = m_dist(m_rng); + return true; + } +}; -#endif // __cplusplus >= 201103L +// TODO: Ideally this would be also constrained against the various char types, +// but I don't expect users to run into that in practice. +template <typename T> +typename std::enable_if<std::is_integral<T>::value && !std::is_same<T, bool>::value, +GeneratorWrapper<T>>::type +random(T a, T b) { + return GeneratorWrapper<T>( + pf::make_unique<RandomIntegerGenerator<T>>(a, b) + ); +} -// Now set the actual defines based on the above + anything the user has configured -#if defined(CLARA_INTERNAL_CONFIG_CPP11_NULLPTR) && !defined(CLARA_CONFIG_CPP11_NO_NULLPTR) && !defined(CLARA_CONFIG_CPP11_NULLPTR) && !defined(CLARA_CONFIG_NO_CPP11) -#define CLARA_CONFIG_CPP11_NULLPTR -#endif -#if defined(CLARA_INTERNAL_CONFIG_CPP11_NOEXCEPT) && !defined(CLARA_CONFIG_CPP11_NO_NOEXCEPT) && !defined(CLARA_CONFIG_CPP11_NOEXCEPT) && !defined(CLARA_CONFIG_NO_CPP11) -#define CLARA_CONFIG_CPP11_NOEXCEPT -#endif -#if defined(CLARA_INTERNAL_CONFIG_CPP11_GENERATED_METHODS) && !defined(CLARA_CONFIG_CPP11_NO_GENERATED_METHODS) && !defined(CLARA_CONFIG_CPP11_GENERATED_METHODS) && !defined(CLARA_CONFIG_NO_CPP11) -#define CLARA_CONFIG_CPP11_GENERATED_METHODS -#endif -#if defined(CLARA_INTERNAL_CONFIG_CPP11_OVERRIDE) && !defined(CLARA_CONFIG_NO_OVERRIDE) && !defined(CLARA_CONFIG_CPP11_OVERRIDE) && !defined(CLARA_CONFIG_NO_CPP11) -#define CLARA_CONFIG_CPP11_OVERRIDE -#endif -#if defined(CLARA_INTERNAL_CONFIG_CPP11_UNIQUE_PTR) && !defined(CLARA_CONFIG_NO_UNIQUE_PTR) && !defined(CLARA_CONFIG_CPP11_UNIQUE_PTR) && !defined(CLARA_CONFIG_NO_CPP11) -#define CLARA_CONFIG_CPP11_UNIQUE_PTR -#endif +template <typename T> +typename std::enable_if<std::is_floating_point<T>::value, +GeneratorWrapper<T>>::type +random(T a, T b) { + return GeneratorWrapper<T>( + pf::make_unique<RandomFloatingGenerator<T>>(a, b) + ); +} -// noexcept support: -#if defined(CLARA_CONFIG_CPP11_NOEXCEPT) && !defined(CLARA_NOEXCEPT) -#define CLARA_NOEXCEPT noexcept -# define CLARA_NOEXCEPT_IS(x) noexcept(x) -#else -#define CLARA_NOEXCEPT throw() -# define CLARA_NOEXCEPT_IS(x) -#endif +template <typename T> +class RangeGenerator final : public IGenerator<T> { + T m_current; + T m_end; + T m_step; + bool m_positive; -// nullptr support -#ifdef CLARA_CONFIG_CPP11_NULLPTR -#define CLARA_NULL nullptr -#else -#define CLARA_NULL NULL -#endif +public: + RangeGenerator(T const& start, T const& end, T const& step): + m_current(start), + m_end(end), + m_step(step), + m_positive(m_step > T(0)) + { + assert(m_current != m_end && "Range start and end cannot be equal"); + assert(m_step != T(0) && "Step size cannot be zero"); + assert(((m_positive && m_current <= m_end) || (!m_positive && m_current >= m_end)) && "Step moves away from end"); + } -// override support -#ifdef CLARA_CONFIG_CPP11_OVERRIDE -#define CLARA_OVERRIDE override -#else -#define CLARA_OVERRIDE -#endif + RangeGenerator(T const& start, T const& end): + RangeGenerator(start, end, (start < end) ? T(1) : T(-1)) + {} -// unique_ptr support -#ifdef CLARA_CONFIG_CPP11_UNIQUE_PTR -# define CLARA_AUTO_PTR( T ) std::unique_ptr<T> -#else -# define CLARA_AUTO_PTR( T ) std::auto_ptr<T> -#endif + T const& get() const override { + return m_current; + } -#endif // TWOBLUECUBES_CLARA_COMPILERS_H_INCLUDED + bool next() override { + m_current += m_step; + return (m_positive) ? (m_current < m_end) : (m_current > m_end); + } +}; -// ----------- end of #include from clara_compilers.h ----------- -// ........... back in clara.h +template <typename T> +GeneratorWrapper<T> range(T const& start, T const& end, T const& step) { + static_assert(std::is_arithmetic<T>::value && !std::is_same<T, bool>::value, "Type must be numeric"); + return GeneratorWrapper<T>(pf::make_unique<RangeGenerator<T>>(start, end, step)); +} -#include <map> -#include <stdexcept> -#include <memory> +template <typename T> +GeneratorWrapper<T> range(T const& start, T const& end) { + static_assert(std::is_integral<T>::value && !std::is_same<T, bool>::value, "Type must be an integer"); + return GeneratorWrapper<T>(pf::make_unique<RangeGenerator<T>>(start, end)); +} -#if defined(WIN32) || defined(__WIN32__) || defined(_WIN32) || defined(_MSC_VER) -#define CLARA_PLATFORM_WINDOWS -#endif +template <typename T> +class IteratorGenerator final : public IGenerator<T> { + static_assert(!std::is_same<T, bool>::value, + "IteratorGenerator currently does not support bools" + "because of std::vector<bool> specialization"); -// Use optional outer namespace -#ifdef STITCH_CLARA_OPEN_NAMESPACE -STITCH_CLARA_OPEN_NAMESPACE -#endif + std::vector<T> m_elems; + size_t m_current = 0; +public: + template <typename InputIterator, typename InputSentinel> + IteratorGenerator(InputIterator first, InputSentinel last):m_elems(first, last) { + if (m_elems.empty()) { + Catch::throw_exception(GeneratorException("IteratorGenerator received no valid values")); + } + } -namespace Clara { + T const& get() const override { + return m_elems[m_current]; + } - struct UnpositionalTag {}; + bool next() override { + ++m_current; + return m_current != m_elems.size(); + } +}; - extern UnpositionalTag _; +template <typename InputIterator, + typename InputSentinel, + typename ResultType = typename std::iterator_traits<InputIterator>::value_type> +GeneratorWrapper<ResultType> from_range(InputIterator from, InputSentinel to) { + return GeneratorWrapper<ResultType>(pf::make_unique<IteratorGenerator<ResultType>>(from, to)); +} -#ifdef CLARA_CONFIG_MAIN - UnpositionalTag _; -#endif +template <typename Container, + typename ResultType = typename Container::value_type> +GeneratorWrapper<ResultType> from_range(Container const& cnt) { + return GeneratorWrapper<ResultType>(pf::make_unique<IteratorGenerator<ResultType>>(cnt.begin(), cnt.end())); +} - namespace Detail { +} // namespace Generators +} // namespace Catch -#ifdef CLARA_CONSOLE_WIDTH - const unsigned int consoleWidth = CLARA_CONFIG_CONSOLE_WIDTH; -#else - const unsigned int consoleWidth = 80; -#endif +// end catch_generators_specific.hpp - using namespace Tbc; +// These files are included here so the single_include script doesn't put them +// in the conditionally compiled sections +// start catch_test_case_info.h - inline bool startsWith( std::string const& str, std::string const& prefix ) { - return str.size() >= prefix.size() && str.substr( 0, prefix.size() ) == prefix; - } +#include <string> +#include <vector> +#include <memory> - template<typename T> struct RemoveConstRef{ typedef T type; }; - template<typename T> struct RemoveConstRef<T&>{ typedef T type; }; - template<typename T> struct RemoveConstRef<T const&>{ typedef T type; }; - template<typename T> struct RemoveConstRef<T const>{ typedef T type; }; +#ifdef __clang__ +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wpadded" +#endif - template<typename T> struct IsBool { static const bool value = false; }; - template<> struct IsBool<bool> { static const bool value = true; }; +namespace Catch { - template<typename T> - void convertInto( std::string const& _source, T& _dest ) { - std::stringstream ss; - ss << _source; - ss >> _dest; - if( ss.fail() ) - throw std::runtime_error( "Unable to convert " + _source + " to destination type" ); - } - inline void convertInto( std::string const& _source, std::string& _dest ) { - _dest = _source; - } - char toLowerCh(char c) { - return static_cast<char>( std::tolower( c ) ); - } - inline void convertInto( std::string const& _source, bool& _dest ) { - std::string sourceLC = _source; - std::transform( sourceLC.begin(), sourceLC.end(), sourceLC.begin(), toLowerCh ); - if( sourceLC == "y" || sourceLC == "1" || sourceLC == "true" || sourceLC == "yes" || sourceLC == "on" ) - _dest = true; - else if( sourceLC == "n" || sourceLC == "0" || sourceLC == "false" || sourceLC == "no" || sourceLC == "off" ) - _dest = false; - else - throw std::runtime_error( "Expected a boolean value but did not recognise:\n '" + _source + "'" ); - } + struct ITestInvoker; - template<typename ConfigT> - struct IArgFunction { - virtual ~IArgFunction() {} -#ifdef CLARA_CONFIG_CPP11_GENERATED_METHODS - IArgFunction() = default; - IArgFunction( IArgFunction const& ) = default; -#endif - virtual void set( ConfigT& config, std::string const& value ) const = 0; - virtual bool takesArg() const = 0; - virtual IArgFunction* clone() const = 0; + struct TestCaseInfo { + enum SpecialProperties{ + None = 0, + IsHidden = 1 << 1, + ShouldFail = 1 << 2, + MayFail = 1 << 3, + Throws = 1 << 4, + NonPortable = 1 << 5, + Benchmark = 1 << 6 }; - template<typename ConfigT> - class BoundArgFunction { - public: - BoundArgFunction() : functionObj( CLARA_NULL ) {} - BoundArgFunction( IArgFunction<ConfigT>* _functionObj ) : functionObj( _functionObj ) {} - BoundArgFunction( BoundArgFunction const& other ) : functionObj( other.functionObj ? other.functionObj->clone() : CLARA_NULL ) {} - BoundArgFunction& operator = ( BoundArgFunction const& other ) { - IArgFunction<ConfigT>* newFunctionObj = other.functionObj ? other.functionObj->clone() : CLARA_NULL; - delete functionObj; - functionObj = newFunctionObj; - return *this; - } - ~BoundArgFunction() { delete functionObj; } + TestCaseInfo( std::string const& _name, + std::string const& _className, + std::string const& _description, + std::vector<std::string> const& _tags, + SourceLineInfo const& _lineInfo ); - void set( ConfigT& config, std::string const& value ) const { - functionObj->set( config, value ); - } - bool takesArg() const { return functionObj->takesArg(); } + friend void setTags( TestCaseInfo& testCaseInfo, std::vector<std::string> tags ); - bool isSet() const { - return functionObj != CLARA_NULL; - } - private: - IArgFunction<ConfigT>* functionObj; - }; - - template<typename C> - struct NullBinder : IArgFunction<C>{ - virtual void set( C&, std::string const& ) const {} - virtual bool takesArg() const { return true; } - virtual IArgFunction<C>* clone() const { return new NullBinder( *this ); } - }; - - template<typename C, typename M> - struct BoundDataMember : IArgFunction<C>{ - BoundDataMember( M C::* _member ) : member( _member ) {} - virtual void set( C& p, std::string const& stringValue ) const { - convertInto( stringValue, p.*member ); - } - virtual bool takesArg() const { return !IsBool<M>::value; } - virtual IArgFunction<C>* clone() const { return new BoundDataMember( *this ); } - M C::* member; - }; - template<typename C, typename M> - struct BoundUnaryMethod : IArgFunction<C>{ - BoundUnaryMethod( void (C::*_member)( M ) ) : member( _member ) {} - virtual void set( C& p, std::string const& stringValue ) const { - typename RemoveConstRef<M>::type value; - convertInto( stringValue, value ); - (p.*member)( value ); - } - virtual bool takesArg() const { return !IsBool<M>::value; } - virtual IArgFunction<C>* clone() const { return new BoundUnaryMethod( *this ); } - void (C::*member)( M ); - }; - template<typename C> - struct BoundNullaryMethod : IArgFunction<C>{ - BoundNullaryMethod( void (C::*_member)() ) : member( _member ) {} - virtual void set( C& p, std::string const& stringValue ) const { - bool value; - convertInto( stringValue, value ); - if( value ) - (p.*member)(); - } - virtual bool takesArg() const { return false; } - virtual IArgFunction<C>* clone() const { return new BoundNullaryMethod( *this ); } - void (C::*member)(); - }; + bool isHidden() const; + bool throws() const; + bool okToFail() const; + bool expectedToFail() const; - template<typename C> - struct BoundUnaryFunction : IArgFunction<C>{ - BoundUnaryFunction( void (*_function)( C& ) ) : function( _function ) {} - virtual void set( C& obj, std::string const& stringValue ) const { - bool value; - convertInto( stringValue, value ); - if( value ) - function( obj ); - } - virtual bool takesArg() const { return false; } - virtual IArgFunction<C>* clone() const { return new BoundUnaryFunction( *this ); } - void (*function)( C& ); - }; + std::string tagsAsString() const; - template<typename C, typename T> - struct BoundBinaryFunction : IArgFunction<C>{ - BoundBinaryFunction( void (*_function)( C&, T ) ) : function( _function ) {} - virtual void set( C& obj, std::string const& stringValue ) const { - typename RemoveConstRef<T>::type value; - convertInto( stringValue, value ); - function( obj, value ); - } - virtual bool takesArg() const { return !IsBool<T>::value; } - virtual IArgFunction<C>* clone() const { return new BoundBinaryFunction( *this ); } - void (*function)( C&, T ); - }; + std::string name; + std::string className; + std::string description; + std::vector<std::string> tags; + std::vector<std::string> lcaseTags; + SourceLineInfo lineInfo; + SpecialProperties properties; + }; - } // namespace Detail + class TestCase : public TestCaseInfo { + public: - inline std::vector<std::string> argsToVector( int argc, char const* const* const argv ) { - std::vector<std::string> args( static_cast<std::size_t>( argc ) ); - for( std::size_t i = 0; i < static_cast<std::size_t>( argc ); ++i ) - args[i] = argv[i]; + TestCase( ITestInvoker* testCase, TestCaseInfo&& info ); - return args; - } + TestCase withName( std::string const& _newName ) const; - class Parser { - enum Mode { None, MaybeShortOpt, SlashOpt, ShortOpt, LongOpt, Positional }; - Mode mode; - std::size_t from; - bool inQuotes; - public: + void invoke() const; - struct Token { - enum Type { Positional, ShortOpt, LongOpt }; - Token( Type _type, std::string const& _data ) : type( _type ), data( _data ) {} - Type type; - std::string data; - }; + TestCaseInfo const& getTestCaseInfo() const; - Parser() : mode( None ), from( 0 ), inQuotes( false ){} + bool operator == ( TestCase const& other ) const; + bool operator < ( TestCase const& other ) const; - void parseIntoTokens( std::vector<std::string> const& args, std::vector<Token>& tokens ) { - const std::string doubleDash = "--"; - for( std::size_t i = 1; i < args.size() && args[i] != doubleDash; ++i ) - parseIntoTokens( args[i], tokens); - } + private: + std::shared_ptr<ITestInvoker> test; + }; - void parseIntoTokens( std::string const& arg, std::vector<Token>& tokens ) { - for( std::size_t i = 0; i < arg.size(); ++i ) { - char c = arg[i]; - if( c == '"' ) - inQuotes = !inQuotes; - mode = handleMode( i, c, arg, tokens ); - } - mode = handleMode( arg.size(), '\0', arg, tokens ); - } - Mode handleMode( std::size_t i, char c, std::string const& arg, std::vector<Token>& tokens ) { - switch( mode ) { - case None: return handleNone( i, c ); - case MaybeShortOpt: return handleMaybeShortOpt( i, c ); - case ShortOpt: - case LongOpt: - case SlashOpt: return handleOpt( i, c, arg, tokens ); - case Positional: return handlePositional( i, c, arg, tokens ); - default: throw std::logic_error( "Unknown mode" ); - } - } + TestCase makeTestCase( ITestInvoker* testCase, + std::string const& className, + NameAndTags const& nameAndTags, + SourceLineInfo const& lineInfo ); +} - Mode handleNone( std::size_t i, char c ) { - if( inQuotes ) { - from = i; - return Positional; - } - switch( c ) { - case '-': return MaybeShortOpt; -#ifdef CLARA_PLATFORM_WINDOWS - case '/': from = i+1; return SlashOpt; +#ifdef __clang__ +#pragma clang diagnostic pop #endif - default: from = i; return Positional; - } - } - Mode handleMaybeShortOpt( std::size_t i, char c ) { - switch( c ) { - case '-': from = i+1; return LongOpt; - default: from = i; return ShortOpt; - } - } - Mode handleOpt( std::size_t i, char c, std::string const& arg, std::vector<Token>& tokens ) { - if( std::string( ":=\0", 3 ).find( c ) == std::string::npos ) - return mode; +// end catch_test_case_info.h +// start catch_interfaces_runner.h - std::string optName = arg.substr( from, i-from ); - if( mode == ShortOpt ) - for( std::size_t j = 0; j < optName.size(); ++j ) - tokens.push_back( Token( Token::ShortOpt, optName.substr( j, 1 ) ) ); - else if( mode == SlashOpt && optName.size() == 1 ) - tokens.push_back( Token( Token::ShortOpt, optName ) ); - else - tokens.push_back( Token( Token::LongOpt, optName ) ); - return None; - } - Mode handlePositional( std::size_t i, char c, std::string const& arg, std::vector<Token>& tokens ) { - if( inQuotes || std::string( "\0", 1 ).find( c ) == std::string::npos ) - return mode; +namespace Catch { - std::string data = arg.substr( from, i-from ); - tokens.push_back( Token( Token::Positional, data ) ); - return None; - } + struct IRunner { + virtual ~IRunner(); + virtual bool aborting() const = 0; }; +} - template<typename ConfigT> - struct CommonArgProperties { - CommonArgProperties() {} - CommonArgProperties( Detail::BoundArgFunction<ConfigT> const& _boundField ) : boundField( _boundField ) {} +// end catch_interfaces_runner.h - Detail::BoundArgFunction<ConfigT> boundField; - std::string description; - std::string detail; - std::string placeholder; // Only value if boundField takes an arg +#ifdef __OBJC__ +// start catch_objc.hpp - bool takesArg() const { - return !placeholder.empty(); - } - void validate() const { - if( !boundField.isSet() ) - throw std::logic_error( "option not bound" ); - } - }; - struct OptionArgProperties { - std::vector<std::string> shortNames; - std::string longName; +#import <objc/runtime.h> - bool hasShortName( std::string const& shortName ) const { - return std::find( shortNames.begin(), shortNames.end(), shortName ) != shortNames.end(); - } - bool hasLongName( std::string const& _longName ) const { - return _longName == longName; - } - }; - struct PositionalArgProperties { - PositionalArgProperties() : position( -1 ) {} - int position; // -1 means non-positional (floating) +#include <string> - bool isFixedPositional() const { - return position != -1; - } - }; +// NB. Any general catch headers included here must be included +// in catch.hpp first to make sure they are included by the single +// header for non obj-usage - template<typename ConfigT> - class CommandLine { +/////////////////////////////////////////////////////////////////////////////// +// This protocol is really only here for (self) documenting purposes, since +// all its methods are optional. +@protocol OcFixture - struct Arg : CommonArgProperties<ConfigT>, OptionArgProperties, PositionalArgProperties { - Arg() {} - Arg( Detail::BoundArgFunction<ConfigT> const& _boundField ) : CommonArgProperties<ConfigT>( _boundField ) {} +@optional - using CommonArgProperties<ConfigT>::placeholder; // !TBD +-(void) setUp; +-(void) tearDown; - std::string dbgName() const { - if( !longName.empty() ) - return "--" + longName; - if( !shortNames.empty() ) - return "-" + shortNames[0]; - return "positional args"; - } - std::string commands() const { - std::ostringstream oss; - bool first = true; - std::vector<std::string>::const_iterator it = shortNames.begin(), itEnd = shortNames.end(); - for(; it != itEnd; ++it ) { - if( first ) - first = false; - else - oss << ", "; - oss << "-" << *it; - } - if( !longName.empty() ) { - if( !first ) - oss << ", "; - oss << "--" << longName; - } - if( !placeholder.empty() ) - oss << " <" << placeholder << ">"; - return oss.str(); - } - }; +@end - typedef CLARA_AUTO_PTR( Arg ) ArgAutoPtr; +namespace Catch { - friend void addOptName( Arg& arg, std::string const& optName ) - { - if( optName.empty() ) - return; - if( Detail::startsWith( optName, "--" ) ) { - if( !arg.longName.empty() ) - throw std::logic_error( "Only one long opt may be specified. '" - + arg.longName - + "' already specified, now attempting to add '" - + optName + "'" ); - arg.longName = optName.substr( 2 ); - } - else if( Detail::startsWith( optName, "-" ) ) - arg.shortNames.push_back( optName.substr( 1 ) ); - else - throw std::logic_error( "option must begin with - or --. Option was: '" + optName + "'" ); - } - friend void setPositionalArg( Arg& arg, int position ) - { - arg.position = position; - } + class OcMethod : public ITestInvoker { - class ArgBuilder { - public: - ArgBuilder( Arg* arg ) : m_arg( arg ) {} + public: + OcMethod( Class cls, SEL sel ) : m_cls( cls ), m_sel( sel ) {} - // Bind a non-boolean data member (requires placeholder string) - template<typename C, typename M> - void bind( M C::* field, std::string const& placeholder ) { - m_arg->boundField = new Detail::BoundDataMember<C,M>( field ); - m_arg->placeholder = placeholder; - } - // Bind a boolean data member (no placeholder required) - template<typename C> - void bind( bool C::* field ) { - m_arg->boundField = new Detail::BoundDataMember<C,bool>( field ); - } + virtual void invoke() const { + id obj = [[m_cls alloc] init]; - // Bind a method taking a single, non-boolean argument (requires a placeholder string) - template<typename C, typename M> - void bind( void (C::* unaryMethod)( M ), std::string const& placeholder ) { - m_arg->boundField = new Detail::BoundUnaryMethod<C,M>( unaryMethod ); - m_arg->placeholder = placeholder; - } + performOptionalSelector( obj, @selector(setUp) ); + performOptionalSelector( obj, m_sel ); + performOptionalSelector( obj, @selector(tearDown) ); - // Bind a method taking a single, boolean argument (no placeholder string required) - template<typename C> - void bind( void (C::* unaryMethod)( bool ) ) { - m_arg->boundField = new Detail::BoundUnaryMethod<C,bool>( unaryMethod ); - } + arcSafeRelease( obj ); + } + private: + virtual ~OcMethod() {} - // Bind a method that takes no arguments (will be called if opt is present) - template<typename C> - void bind( void (C::* nullaryMethod)() ) { - m_arg->boundField = new Detail::BoundNullaryMethod<C>( nullaryMethod ); - } + Class m_cls; + SEL m_sel; + }; - // Bind a free function taking a single argument - the object to operate on (no placeholder string required) - template<typename C> - void bind( void (* unaryFunction)( C& ) ) { - m_arg->boundField = new Detail::BoundUnaryFunction<C>( unaryFunction ); - } + namespace Detail{ - // Bind a free function taking a single argument - the object to operate on (requires a placeholder string) - template<typename C, typename T> - void bind( void (* binaryFunction)( C&, T ), std::string const& placeholder ) { - m_arg->boundField = new Detail::BoundBinaryFunction<C, T>( binaryFunction ); - m_arg->placeholder = placeholder; - } + inline std::string getAnnotation( Class cls, + std::string const& annotationName, + std::string const& testCaseName ) { + NSString* selStr = [[NSString alloc] initWithFormat:@"Catch_%s_%s", annotationName.c_str(), testCaseName.c_str()]; + SEL sel = NSSelectorFromString( selStr ); + arcSafeRelease( selStr ); + id value = performOptionalSelector( cls, sel ); + if( value ) + return [(NSString*)value UTF8String]; + return ""; + } + } - ArgBuilder& describe( std::string const& description ) { - m_arg->description = description; - return *this; - } - ArgBuilder& detail( std::string const& detail ) { - m_arg->detail = detail; - return *this; - } + inline std::size_t registerTestMethods() { + std::size_t noTestMethods = 0; + int noClasses = objc_getClassList( nullptr, 0 ); - protected: - Arg* m_arg; - }; + Class* classes = (CATCH_UNSAFE_UNRETAINED Class *)malloc( sizeof(Class) * noClasses); + objc_getClassList( classes, noClasses ); - class OptBuilder : public ArgBuilder { - public: - OptBuilder( Arg* arg ) : ArgBuilder( arg ) {} - OptBuilder( OptBuilder& other ) : ArgBuilder( other ) {} + for( int c = 0; c < noClasses; c++ ) { + Class cls = classes[c]; + { + u_int count; + Method* methods = class_copyMethodList( cls, &count ); + for( u_int m = 0; m < count ; m++ ) { + SEL selector = method_getName(methods[m]); + std::string methodName = sel_getName(selector); + if( startsWith( methodName, "Catch_TestCase_" ) ) { + std::string testCaseName = methodName.substr( 15 ); + std::string name = Detail::getAnnotation( cls, "Name", testCaseName ); + std::string desc = Detail::getAnnotation( cls, "Description", testCaseName ); + const char* className = class_getName( cls ); - OptBuilder& operator[]( std::string const& optName ) { - addOptName( *ArgBuilder::m_arg, optName ); - return *this; + getMutableRegistryHub().registerTest( makeTestCase( new OcMethod( cls, selector ), className, NameAndTags( name.c_str(), desc.c_str() ), SourceLineInfo("",0) ) ); + noTestMethods++; + } + } + free(methods); } - }; + } + return noTestMethods; + } - public: +#if !defined(CATCH_CONFIG_DISABLE_MATCHERS) - CommandLine() - : m_boundProcessName( new Detail::NullBinder<ConfigT>() ), - m_highestSpecifiedArgPosition( 0 ), - m_throwOnUnrecognisedTokens( false ) - {} - CommandLine( CommandLine const& other ) - : m_boundProcessName( other.m_boundProcessName ), - m_options ( other.m_options ), - m_positionalArgs( other.m_positionalArgs ), - m_highestSpecifiedArgPosition( other.m_highestSpecifiedArgPosition ), - m_throwOnUnrecognisedTokens( other.m_throwOnUnrecognisedTokens ) - { - if( other.m_floatingArg.get() ) - m_floatingArg.reset( new Arg( *other.m_floatingArg ) ); - } + namespace Matchers { + namespace Impl { + namespace NSStringMatchers { - CommandLine& setThrowOnUnrecognisedTokens( bool shouldThrow = true ) { - m_throwOnUnrecognisedTokens = shouldThrow; - return *this; - } + struct StringHolder : MatcherBase<NSString*>{ + StringHolder( NSString* substr ) : m_substr( [substr copy] ){} + StringHolder( StringHolder const& other ) : m_substr( [other.m_substr copy] ){} + StringHolder() { + arcSafeRelease( m_substr ); + } - OptBuilder operator[]( std::string const& optName ) { - m_options.push_back( Arg() ); - addOptName( m_options.back(), optName ); - OptBuilder builder( &m_options.back() ); - return builder; - } + bool match( NSString* str ) const override { + return false; + } - ArgBuilder operator[]( int position ) { - m_positionalArgs.insert( std::make_pair( position, Arg() ) ); - if( position > m_highestSpecifiedArgPosition ) - m_highestSpecifiedArgPosition = position; - setPositionalArg( m_positionalArgs[position], position ); - ArgBuilder builder( &m_positionalArgs[position] ); - return builder; - } + NSString* CATCH_ARC_STRONG m_substr; + }; - // Invoke this with the _ instance - ArgBuilder operator[]( UnpositionalTag ) { - if( m_floatingArg.get() ) - throw std::logic_error( "Only one unpositional argument can be added" ); - m_floatingArg.reset( new Arg() ); - ArgBuilder builder( m_floatingArg.get() ); - return builder; - } + struct Equals : StringHolder { + Equals( NSString* substr ) : StringHolder( substr ){} - template<typename C, typename M> - void bindProcessName( M C::* field ) { - m_boundProcessName = new Detail::BoundDataMember<C,M>( field ); - } - template<typename C, typename M> - void bindProcessName( void (C::*_unaryMethod)( M ) ) { - m_boundProcessName = new Detail::BoundUnaryMethod<C,M>( _unaryMethod ); - } + bool match( NSString* str ) const override { + return (str != nil || m_substr == nil ) && + [str isEqualToString:m_substr]; + } - void optUsage( std::ostream& os, std::size_t indent = 0, std::size_t width = Detail::consoleWidth ) const { - typename std::vector<Arg>::const_iterator itBegin = m_options.begin(), itEnd = m_options.end(), it; - std::size_t maxWidth = 0; - for( it = itBegin; it != itEnd; ++it ) - maxWidth = (std::max)( maxWidth, it->commands().size() ); + std::string describe() const override { + return "equals string: " + Catch::Detail::stringify( m_substr ); + } + }; - for( it = itBegin; it != itEnd; ++it ) { - Detail::Text usage( it->commands(), Detail::TextAttributes() - .setWidth( maxWidth+indent ) - .setIndent( indent ) ); - Detail::Text desc( it->description, Detail::TextAttributes() - .setWidth( width - maxWidth - 3 ) ); + struct Contains : StringHolder { + Contains( NSString* substr ) : StringHolder( substr ){} - for( std::size_t i = 0; i < (std::max)( usage.size(), desc.size() ); ++i ) { - std::string usageCol = i < usage.size() ? usage[i] : ""; - os << usageCol; + bool match( NSString* str ) const override { + return (str != nil || m_substr == nil ) && + [str rangeOfString:m_substr].location != NSNotFound; + } - if( i < desc.size() && !desc[i].empty() ) - os << std::string( indent + 2 + maxWidth - usageCol.size(), ' ' ) - << desc[i]; - os << "\n"; + std::string describe() const override { + return "contains string: " + Catch::Detail::stringify( m_substr ); } - } - } - std::string optUsage() const { - std::ostringstream oss; - optUsage( oss ); - return oss.str(); - } - - void argSynopsis( std::ostream& os ) const { - for( int i = 1; i <= m_highestSpecifiedArgPosition; ++i ) { - if( i > 1 ) - os << " "; - typename std::map<int, Arg>::const_iterator it = m_positionalArgs.find( i ); - if( it != m_positionalArgs.end() ) - os << "<" << it->second.placeholder << ">"; - else if( m_floatingArg.get() ) - os << "<" << m_floatingArg->placeholder << ">"; - else - throw std::logic_error( "non consecutive positional arguments with no floating args" ); - } - // !TBD No indication of mandatory args - if( m_floatingArg.get() ) { - if( m_highestSpecifiedArgPosition > 1 ) - os << " "; - os << "[<" << m_floatingArg->placeholder << "> ...]"; - } - } - std::string argSynopsis() const { - std::ostringstream oss; - argSynopsis( oss ); - return oss.str(); - } + }; - void usage( std::ostream& os, std::string const& procName ) const { - validate(); - os << "usage:\n " << procName << " "; - argSynopsis( os ); - if( !m_options.empty() ) { - os << " [options]\n\nwhere options are: \n"; - optUsage( os, 2 ); - } - os << "\n"; - } - std::string usage( std::string const& procName ) const { - std::ostringstream oss; - usage( oss, procName ); - return oss.str(); - } - - ConfigT parse( std::vector<std::string> const& args ) const { - ConfigT config; - parseInto( args, config ); - return config; - } - - std::vector<Parser::Token> parseInto( std::vector<std::string> const& args, ConfigT& config ) const { - std::string processName = args.empty() ? std::string() : args[0]; - std::size_t lastSlash = processName.find_last_of( "/\\" ); - if( lastSlash != std::string::npos ) - processName = processName.substr( lastSlash+1 ); - m_boundProcessName.set( config, processName ); - std::vector<Parser::Token> tokens; - Parser parser; - parser.parseIntoTokens( args, tokens ); - return populate( tokens, config ); - } - - std::vector<Parser::Token> populate( std::vector<Parser::Token> const& tokens, ConfigT& config ) const { - validate(); - std::vector<Parser::Token> unusedTokens = populateOptions( tokens, config ); - unusedTokens = populateFixedArgs( unusedTokens, config ); - unusedTokens = populateFloatingArgs( unusedTokens, config ); - return unusedTokens; - } - - std::vector<Parser::Token> populateOptions( std::vector<Parser::Token> const& tokens, ConfigT& config ) const { - std::vector<Parser::Token> unusedTokens; - std::vector<std::string> errors; - for( std::size_t i = 0; i < tokens.size(); ++i ) { - Parser::Token const& token = tokens[i]; - typename std::vector<Arg>::const_iterator it = m_options.begin(), itEnd = m_options.end(); - for(; it != itEnd; ++it ) { - Arg const& arg = *it; - - try { - if( ( token.type == Parser::Token::ShortOpt && arg.hasShortName( token.data ) ) || - ( token.type == Parser::Token::LongOpt && arg.hasLongName( token.data ) ) ) { - if( arg.takesArg() ) { - if( i == tokens.size()-1 || tokens[i+1].type != Parser::Token::Positional ) - errors.push_back( "Expected argument to option: " + token.data ); - else - arg.boundField.set( config, tokens[++i].data ); - } - else { - arg.boundField.set( config, "true" ); - } - break; - } - } - catch( std::exception& ex ) { - errors.push_back( std::string( ex.what() ) + "\n- while parsing: (" + arg.commands() + ")" ); - } + struct StartsWith : StringHolder { + StartsWith( NSString* substr ) : StringHolder( substr ){} + + bool match( NSString* str ) const override { + return (str != nil || m_substr == nil ) && + [str rangeOfString:m_substr].location == 0; } - if( it == itEnd ) { - if( token.type == Parser::Token::Positional || !m_throwOnUnrecognisedTokens ) - unusedTokens.push_back( token ); - else if( errors.empty() && m_throwOnUnrecognisedTokens ) - errors.push_back( "unrecognised option: " + token.data ); + + std::string describe() const override { + return "starts with: " + Catch::Detail::stringify( m_substr ); } - } - if( !errors.empty() ) { - std::ostringstream oss; - for( std::vector<std::string>::const_iterator it = errors.begin(), itEnd = errors.end(); - it != itEnd; - ++it ) { - if( it != errors.begin() ) - oss << "\n"; - oss << *it; + }; + struct EndsWith : StringHolder { + EndsWith( NSString* substr ) : StringHolder( substr ){} + + bool match( NSString* str ) const override { + return (str != nil || m_substr == nil ) && + [str rangeOfString:m_substr].location == [str length] - [m_substr length]; } - throw std::runtime_error( oss.str() ); - } - return unusedTokens; - } - std::vector<Parser::Token> populateFixedArgs( std::vector<Parser::Token> const& tokens, ConfigT& config ) const { - std::vector<Parser::Token> unusedTokens; - int position = 1; - for( std::size_t i = 0; i < tokens.size(); ++i ) { - Parser::Token const& token = tokens[i]; - typename std::map<int, Arg>::const_iterator it = m_positionalArgs.find( position ); - if( it != m_positionalArgs.end() ) - it->second.boundField.set( config, token.data ); - else - unusedTokens.push_back( token ); - if( token.type == Parser::Token::Positional ) - position++; - } - return unusedTokens; - } - std::vector<Parser::Token> populateFloatingArgs( std::vector<Parser::Token> const& tokens, ConfigT& config ) const { - if( !m_floatingArg.get() ) - return tokens; - std::vector<Parser::Token> unusedTokens; - for( std::size_t i = 0; i < tokens.size(); ++i ) { - Parser::Token const& token = tokens[i]; - if( token.type == Parser::Token::Positional ) - m_floatingArg->boundField.set( config, token.data ); - else - unusedTokens.push_back( token ); - } - return unusedTokens; - } - void validate() const - { - if( m_options.empty() && m_positionalArgs.empty() && !m_floatingArg.get() ) - throw std::logic_error( "No options or arguments specified" ); + std::string describe() const override { + return "ends with: " + Catch::Detail::stringify( m_substr ); + } + }; - for( typename std::vector<Arg>::const_iterator it = m_options.begin(), - itEnd = m_options.end(); - it != itEnd; ++it ) - it->validate(); - } + } // namespace NSStringMatchers + } // namespace Impl - private: - Detail::BoundArgFunction<ConfigT> m_boundProcessName; - std::vector<Arg> m_options; - std::map<int, Arg> m_positionalArgs; - ArgAutoPtr m_floatingArg; - int m_highestSpecifiedArgPosition; - bool m_throwOnUnrecognisedTokens; - }; + inline Impl::NSStringMatchers::Equals + Equals( NSString* substr ){ return Impl::NSStringMatchers::Equals( substr ); } -} // end namespace Clara + inline Impl::NSStringMatchers::Contains + Contains( NSString* substr ){ return Impl::NSStringMatchers::Contains( substr ); } -STITCH_CLARA_CLOSE_NAMESPACE -#undef STITCH_CLARA_OPEN_NAMESPACE -#undef STITCH_CLARA_CLOSE_NAMESPACE + inline Impl::NSStringMatchers::StartsWith + StartsWith( NSString* substr ){ return Impl::NSStringMatchers::StartsWith( substr ); } -#endif // TWOBLUECUBES_CLARA_H_INCLUDED -#undef STITCH_CLARA_OPEN_NAMESPACE + inline Impl::NSStringMatchers::EndsWith + EndsWith( NSString* substr ){ return Impl::NSStringMatchers::EndsWith( substr ); } -// Restore Clara's value for console width, if present -#ifdef CATCH_TEMP_CLARA_CONFIG_CONSOLE_WIDTH -#define CLARA_CONFIG_CONSOLE_WIDTH CATCH_TEMP_CLARA_CONFIG_CONSOLE_WIDTH -#undef CATCH_TEMP_CLARA_CONFIG_CONSOLE_WIDTH -#endif + } // namespace Matchers -#include <fstream> -#include <ctime> + using namespace Matchers; -namespace Catch { +#endif // CATCH_CONFIG_DISABLE_MATCHERS - inline void abortAfterFirst( ConfigData& config ) { config.abortAfter = 1; } - inline void abortAfterX( ConfigData& config, int x ) { - if( x < 1 ) - throw std::runtime_error( "Value after -x or --abortAfter must be greater than zero" ); - config.abortAfter = x; - } - inline void addTestOrTags( ConfigData& config, std::string const& _testSpec ) { config.testsOrTags.push_back( _testSpec ); } - inline void addSectionToRun( ConfigData& config, std::string const& sectionName ) { config.sectionsToRun.push_back( sectionName ); } - inline void addReporterName( ConfigData& config, std::string const& _reporterName ) { config.reporterNames.push_back( _reporterName ); } +} // namespace Catch - inline void addWarning( ConfigData& config, std::string const& _warning ) { - if( _warning == "NoAssertions" ) - config.warnings = static_cast<WarnAbout::What>( config.warnings | WarnAbout::NoAssertions ); - else - throw std::runtime_error( "Unrecognised warning: '" + _warning + '\'' ); - } - inline void setOrder( ConfigData& config, std::string const& order ) { - if( startsWith( "declared", order ) ) - config.runOrder = RunTests::InDeclarationOrder; - else if( startsWith( "lexical", order ) ) - config.runOrder = RunTests::InLexicographicalOrder; - else if( startsWith( "random", order ) ) - config.runOrder = RunTests::InRandomOrder; - else - throw std::runtime_error( "Unrecognised ordering: '" + order + '\'' ); - } - inline void setRngSeed( ConfigData& config, std::string const& seed ) { - if( seed == "time" ) { - config.rngSeed = static_cast<unsigned int>( std::time(0) ); - } - else { - std::stringstream ss; - ss << seed; - ss >> config.rngSeed; - if( ss.fail() ) - throw std::runtime_error( "Argument to --rng-seed should be the word 'time' or a number" ); - } - } - inline void setVerbosity( ConfigData& config, int level ) { - // !TBD: accept strings? - config.verbosity = static_cast<Verbosity::Level>( level ); - } - inline void setShowDurations( ConfigData& config, bool _showDurations ) { - config.showDurations = _showDurations - ? ShowDurations::Always - : ShowDurations::Never; - } - inline void setUseColour( ConfigData& config, std::string const& value ) { - std::string mode = toLower( value ); - - if( mode == "yes" ) - config.useColour = UseColour::Yes; - else if( mode == "no" ) - config.useColour = UseColour::No; - else if( mode == "auto" ) - config.useColour = UseColour::Auto; - else - throw std::runtime_error( "colour mode must be one of: auto, yes or no" ); - } - inline void setWaitForKeypress( ConfigData& config, std::string const& keypress ) { - std::string keypressLc = toLower( keypress ); - if( keypressLc == "start" ) - config.waitForKeypress = WaitForKeypress::BeforeStart; - else if( keypressLc == "exit" ) - config.waitForKeypress = WaitForKeypress::BeforeExit; - else if( keypressLc == "both" ) - config.waitForKeypress = WaitForKeypress::BeforeStartAndExit; - else - throw std::runtime_error( "keypress argument must be one of: start, exit or both. '" + keypress + "' not recognised" ); - }; +/////////////////////////////////////////////////////////////////////////////// +#define OC_MAKE_UNIQUE_NAME( root, uniqueSuffix ) root##uniqueSuffix +#define OC_TEST_CASE2( name, desc, uniqueSuffix ) \ ++(NSString*) OC_MAKE_UNIQUE_NAME( Catch_Name_test_, uniqueSuffix ) \ +{ \ +return @ name; \ +} \ ++(NSString*) OC_MAKE_UNIQUE_NAME( Catch_Description_test_, uniqueSuffix ) \ +{ \ +return @ desc; \ +} \ +-(void) OC_MAKE_UNIQUE_NAME( Catch_TestCase_test_, uniqueSuffix ) - inline void forceColour( ConfigData& config ) { - config.useColour = UseColour::Yes; - } - inline void loadTestNamesFromFile( ConfigData& config, std::string const& _filename ) { - std::ifstream f( _filename.c_str() ); - if( !f.is_open() ) - throw std::domain_error( "Unable to load input file: " + _filename ); +#define OC_TEST_CASE( name, desc ) OC_TEST_CASE2( name, desc, __LINE__ ) - std::string line; - while( std::getline( f, line ) ) { - line = trim(line); - if( !line.empty() && !startsWith( line, '#' ) ) { - if( !startsWith( line, '"' ) ) - line = '"' + line + '"'; - addTestOrTags( config, line + ',' ); - } - } - } +// end catch_objc.hpp +#endif + +// Benchmarking needs the externally-facing parts of reporters to work +#if defined(CATCH_CONFIG_EXTERNAL_INTERFACES) || defined(CATCH_CONFIG_ENABLE_BENCHMARKING) +// start catch_external_interfaces.h + +// start catch_reporter_bases.hpp - inline Clara::CommandLine<ConfigData> makeCommandLineParser() { +// start catch_interfaces_reporter.h - using namespace Clara; - CommandLine<ConfigData> cli; +// start catch_config.hpp - cli.bindProcessName( &ConfigData::processName ); +// start catch_test_spec_parser.h - cli["-?"]["-h"]["--help"] - .describe( "display usage information" ) - .bind( &ConfigData::showHelp ); +#ifdef __clang__ +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wpadded" +#endif + +// start catch_test_spec.h + +#ifdef __clang__ +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wpadded" +#endif - cli["-l"]["--list-tests"] - .describe( "list all/matching test cases" ) - .bind( &ConfigData::listTests ); +// start catch_wildcard_pattern.h - cli["-t"]["--list-tags"] - .describe( "list all/matching tags" ) - .bind( &ConfigData::listTags ); +namespace Catch +{ + class WildcardPattern { + enum WildcardPosition { + NoWildcard = 0, + WildcardAtStart = 1, + WildcardAtEnd = 2, + WildcardAtBothEnds = WildcardAtStart | WildcardAtEnd + }; - cli["-s"]["--success"] - .describe( "include successful tests in output" ) - .bind( &ConfigData::showSuccessfulTests ); + public: - cli["-b"]["--break"] - .describe( "break into debugger on failure" ) - .bind( &ConfigData::shouldDebugBreak ); + WildcardPattern( std::string const& pattern, CaseSensitive::Choice caseSensitivity ); + virtual ~WildcardPattern() = default; + virtual bool matches( std::string const& str ) const; - cli["-e"]["--nothrow"] - .describe( "skip exception tests" ) - .bind( &ConfigData::noThrow ); + private: + std::string normaliseString( std::string const& str ) const; + CaseSensitive::Choice m_caseSensitivity; + WildcardPosition m_wildcard = NoWildcard; + std::string m_pattern; + }; +} - cli["-i"]["--invisibles"] - .describe( "show invisibles (tabs, newlines)" ) - .bind( &ConfigData::showInvisibles ); +// end catch_wildcard_pattern.h +#include <string> +#include <vector> +#include <memory> - cli["-o"]["--out"] - .describe( "output filename" ) - .bind( &ConfigData::outputFilename, "filename" ); +namespace Catch { - cli["-r"]["--reporter"] -// .placeholder( "name[:filename]" ) - .describe( "reporter to use (defaults to console)" ) - .bind( &addReporterName, "name" ); + struct IConfig; - cli["-n"]["--name"] - .describe( "suite name" ) - .bind( &ConfigData::name, "name" ); + class TestSpec { + class Pattern { + public: + explicit Pattern( std::string const& name ); + virtual ~Pattern(); + virtual bool matches( TestCaseInfo const& testCase ) const = 0; + std::string const& name() const; + private: + std::string const m_name; + }; + using PatternPtr = std::shared_ptr<Pattern>; - cli["-a"]["--abort"] - .describe( "abort at first failure" ) - .bind( &abortAfterFirst ); + class NamePattern : public Pattern { + public: + explicit NamePattern( std::string const& name, std::string const& filterString ); + bool matches( TestCaseInfo const& testCase ) const override; + private: + WildcardPattern m_wildcardPattern; + }; - cli["-x"]["--abortx"] - .describe( "abort after x failures" ) - .bind( &abortAfterX, "no. failures" ); + class TagPattern : public Pattern { + public: + explicit TagPattern( std::string const& tag, std::string const& filterString ); + bool matches( TestCaseInfo const& testCase ) const override; + private: + std::string m_tag; + }; - cli["-w"]["--warn"] - .describe( "enable warnings" ) - .bind( &addWarning, "warning name" ); + class ExcludedPattern : public Pattern { + public: + explicit ExcludedPattern( PatternPtr const& underlyingPattern ); + bool matches( TestCaseInfo const& testCase ) const override; + private: + PatternPtr m_underlyingPattern; + }; -// - needs updating if reinstated -// cli.into( &setVerbosity ) -// .describe( "level of verbosity (0=no output)" ) -// .shortOpt( "v") -// .longOpt( "verbosity" ) -// .placeholder( "level" ); + struct Filter { + std::vector<PatternPtr> m_patterns; - cli[_] - .describe( "which test or tests to use" ) - .bind( &addTestOrTags, "test name, pattern or tags" ); + bool matches( TestCaseInfo const& testCase ) const; + std::string name() const; + }; - cli["-d"]["--durations"] - .describe( "show test durations" ) - .bind( &setShowDurations, "yes|no" ); + public: + struct FilterMatch { + std::string name; + std::vector<TestCase const*> tests; + }; + using Matches = std::vector<FilterMatch>; + using vectorStrings = std::vector<std::string>; - cli["-f"]["--input-file"] - .describe( "load test names to run from a file" ) - .bind( &loadTestNamesFromFile, "filename" ); + bool hasFilters() const; + bool matches( TestCaseInfo const& testCase ) const; + Matches matchesByFilter( std::vector<TestCase> const& testCases, IConfig const& config ) const; + const vectorStrings & getInvalidArgs() const; - cli["-#"]["--filenames-as-tags"] - .describe( "adds a tag for the filename" ) - .bind( &ConfigData::filenamesAsTags ); + private: + std::vector<Filter> m_filters; + std::vector<std::string> m_invalidArgs; + friend class TestSpecParser; + }; +} - cli["-c"]["--section"] - .describe( "specify section to run" ) - .bind( &addSectionToRun, "section name" ); +#ifdef __clang__ +#pragma clang diagnostic pop +#endif - // Less common commands which don't have a short form - cli["--list-test-names-only"] - .describe( "list all/matching test cases names only" ) - .bind( &ConfigData::listTestNamesOnly ); +// end catch_test_spec.h +// start catch_interfaces_tag_alias_registry.h - cli["--list-extra-info"] - .describe( "list all/matching test cases with more info" ) - .bind( &ConfigData::listExtraInfo ); +#include <string> - cli["--list-reporters"] - .describe( "list all reporters" ) - .bind( &ConfigData::listReporters ); +namespace Catch { - cli["--order"] - .describe( "test case order (defaults to decl)" ) - .bind( &setOrder, "decl|lex|rand" ); + struct TagAlias; - cli["--rng-seed"] - .describe( "set a specific seed for random numbers" ) - .bind( &setRngSeed, "'time'|number" ); - - cli["--force-colour"] - .describe( "force colourised output (deprecated)" ) - .bind( &forceColour ); - - cli["--use-colour"] - .describe( "should output be colourised" ) - .bind( &setUseColour, "yes|no" ); - - cli["--libidentify"] - .describe( "report name and version according to libidentify standard" ) - .bind( &ConfigData::libIdentify ); - - cli["--wait-for-keypress"] - .describe( "waits for a keypress before exiting" ) - .bind( &setWaitForKeypress, "start|exit|both" ); + struct ITagAliasRegistry { + virtual ~ITagAliasRegistry(); + // Nullptr if not present + virtual TagAlias const* find( std::string const& alias ) const = 0; + virtual std::string expandAliases( std::string const& unexpandedTestSpec ) const = 0; - return cli; - } + static ITagAliasRegistry const& get(); + }; } // end namespace Catch -// #included from: internal/catch_list.hpp -#define TWOBLUECUBES_CATCH_LIST_HPP_INCLUDED +// end catch_interfaces_tag_alias_registry.h +namespace Catch { + + class TestSpecParser { + enum Mode{ None, Name, QuotedName, Tag, EscapedName }; + Mode m_mode = None; + Mode lastMode = None; + bool m_exclusion = false; + std::size_t m_pos = 0; + std::size_t m_realPatternPos = 0; + std::string m_arg; + std::string m_substring; + std::string m_patternName; + std::vector<std::size_t> m_escapeChars; + TestSpec::Filter m_currentFilter; + TestSpec m_testSpec; + ITagAliasRegistry const* m_tagAliases = nullptr; + + public: + TestSpecParser( ITagAliasRegistry const& tagAliases ); -// #included from: catch_text.h -#define TWOBLUECUBES_CATCH_TEXT_H_INCLUDED + TestSpecParser& parse( std::string const& arg ); + TestSpec testSpec(); -#define TBC_TEXT_FORMAT_CONSOLE_WIDTH CATCH_CONFIG_CONSOLE_WIDTH + private: + bool visitChar( char c ); + void startNewMode( Mode mode ); + bool processNoneChar( char c ); + void processNameChar( char c ); + bool processOtherChar( char c ); + void endMode(); + void escape(); + bool isControlChar( char c ) const; + void saveLastMode(); + void revertBackToLastMode(); + void addFilter(); + bool separate(); + + // Handles common preprocessing of the pattern for name/tag patterns + std::string preprocessPattern(); + // Adds the current pattern as a test name + void addNamePattern(); + // Adds the current pattern as a tag + void addTagPattern(); + + inline void addCharToPattern(char c) { + m_substring += c; + m_patternName += c; + m_realPatternPos++; + } -#define CLICHE_TBC_TEXT_FORMAT_OUTER_NAMESPACE Catch -// #included from: ../external/tbc_text_format.h -// Only use header guard if we are not using an outer namespace -#ifndef CLICHE_TBC_TEXT_FORMAT_OUTER_NAMESPACE -# ifdef TWOBLUECUBES_TEXT_FORMAT_H_INCLUDED -# ifndef TWOBLUECUBES_TEXT_FORMAT_H_ALREADY_INCLUDED -# define TWOBLUECUBES_TEXT_FORMAT_H_ALREADY_INCLUDED -# endif -# else -# define TWOBLUECUBES_TEXT_FORMAT_H_INCLUDED -# endif + }; + TestSpec parseTestSpec( std::string const& arg ); + +} // namespace Catch + +#ifdef __clang__ +#pragma clang diagnostic pop #endif -#ifndef TWOBLUECUBES_TEXT_FORMAT_H_ALREADY_INCLUDED -#include <string> + +// end catch_test_spec_parser.h +// Libstdc++ doesn't like incomplete classes for unique_ptr + +#include <memory> #include <vector> -#include <sstream> +#include <string> -// Use optional outer namespace -#ifdef CLICHE_TBC_TEXT_FORMAT_OUTER_NAMESPACE -namespace CLICHE_TBC_TEXT_FORMAT_OUTER_NAMESPACE { +#ifndef CATCH_CONFIG_CONSOLE_WIDTH +#define CATCH_CONFIG_CONSOLE_WIDTH 80 #endif -namespace Tbc { +namespace Catch { -#ifdef TBC_TEXT_FORMAT_CONSOLE_WIDTH - const unsigned int consoleWidth = TBC_TEXT_FORMAT_CONSOLE_WIDTH; -#else - const unsigned int consoleWidth = 80; -#endif + struct IStream; - struct TextAttributes { - TextAttributes() - : initialIndent( std::string::npos ), - indent( 0 ), - width( consoleWidth-1 ) - {} + struct ConfigData { + bool listTests = false; + bool listTags = false; + bool listReporters = false; + bool listTestNamesOnly = false; + + bool showSuccessfulTests = false; + bool shouldDebugBreak = false; + bool noThrow = false; + bool showHelp = false; + bool showInvisibles = false; + bool filenamesAsTags = false; + bool libIdentify = false; + + int abortAfter = -1; + unsigned int rngSeed = 0; + + bool benchmarkNoAnalysis = false; + unsigned int benchmarkSamples = 100; + double benchmarkConfidenceInterval = 0.95; + unsigned int benchmarkResamples = 100000; + std::chrono::milliseconds::rep benchmarkWarmupTime = 100; + + Verbosity verbosity = Verbosity::Normal; + WarnAbout::What warnings = WarnAbout::Nothing; + ShowDurations::OrNot showDurations = ShowDurations::DefaultForReporter; + double minDuration = -1; + RunTests::InWhatOrder runOrder = RunTests::InDeclarationOrder; + UseColour::YesOrNo useColour = UseColour::Auto; + WaitForKeypress::When waitForKeypress = WaitForKeypress::Never; - TextAttributes& setInitialIndent( std::size_t _value ) { initialIndent = _value; return *this; } - TextAttributes& setIndent( std::size_t _value ) { indent = _value; return *this; } - TextAttributes& setWidth( std::size_t _value ) { width = _value; return *this; } + std::string outputFilename; + std::string name; + std::string processName; +#ifndef CATCH_CONFIG_DEFAULT_REPORTER +#define CATCH_CONFIG_DEFAULT_REPORTER "console" +#endif + std::string reporterName = CATCH_CONFIG_DEFAULT_REPORTER; +#undef CATCH_CONFIG_DEFAULT_REPORTER - std::size_t initialIndent; // indent of first line, or npos - std::size_t indent; // indent of subsequent lines, or all if initialIndent is npos - std::size_t width; // maximum width of text, including indent. Longer text will wrap + std::vector<std::string> testsOrTags; + std::vector<std::string> sectionsToRun; }; - class Text { + class Config : public IConfig { public: - Text( std::string const& _str, TextAttributes const& _attr = TextAttributes() ) - : attr( _attr ) - { - const std::string wrappableBeforeChars = "[({<\t"; - const std::string wrappableAfterChars = "])}>-,./|\\"; - const std::string wrappableInsteadOfChars = " \n\r"; - std::string indent = _attr.initialIndent != std::string::npos - ? std::string( _attr.initialIndent, ' ' ) - : std::string( _attr.indent, ' ' ); - - typedef std::string::const_iterator iterator; - iterator it = _str.begin(); - const iterator strEnd = _str.end(); - - while( it != strEnd ) { - - if( lines.size() >= 1000 ) { - lines.push_back( "... message truncated due to excessive size" ); - return; - } - std::string suffix; - std::size_t width = (std::min)( static_cast<size_t>( strEnd-it ), _attr.width-static_cast<size_t>( indent.size() ) ); - iterator itEnd = it+width; - iterator itNext = _str.end(); - - iterator itNewLine = std::find( it, itEnd, '\n' ); - if( itNewLine != itEnd ) - itEnd = itNewLine; - - if( itEnd != strEnd ) { - bool foundWrapPoint = false; - iterator findIt = itEnd; - do { - if( wrappableAfterChars.find( *findIt ) != std::string::npos && findIt != itEnd ) { - itEnd = findIt+1; - itNext = findIt+1; - foundWrapPoint = true; - } - else if( findIt > it && wrappableBeforeChars.find( *findIt ) != std::string::npos ) { - itEnd = findIt; - itNext = findIt; - foundWrapPoint = true; - } - else if( wrappableInsteadOfChars.find( *findIt ) != std::string::npos ) { - itNext = findIt+1; - itEnd = findIt; - foundWrapPoint = true; - } - if( findIt == it ) - break; - else - --findIt; - } - while( !foundWrapPoint ); + Config() = default; + Config( ConfigData const& data ); + virtual ~Config() = default; - if( !foundWrapPoint ) { - // No good wrap char, so we'll break mid word and add a hyphen - --itEnd; - itNext = itEnd; - suffix = "-"; - } - else { - while( itEnd > it && wrappableInsteadOfChars.find( *(itEnd-1) ) != std::string::npos ) - --itEnd; - } - } - lines.push_back( indent + std::string( it, itEnd ) + suffix ); + std::string const& getFilename() const; - if( indent.size() != _attr.indent ) - indent = std::string( _attr.indent, ' ' ); - it = itNext; - } - } + bool listTests() const; + bool listTestNamesOnly() const; + bool listTags() const; + bool listReporters() const; - typedef std::vector<std::string>::const_iterator const_iterator; + std::string getProcessName() const; + std::string const& getReporterName() const; - const_iterator begin() const { return lines.begin(); } - const_iterator end() const { return lines.end(); } - std::string const& last() const { return lines.back(); } - std::size_t size() const { return lines.size(); } - std::string const& operator[]( std::size_t _index ) const { return lines[_index]; } - std::string toString() const { - std::ostringstream oss; - oss << *this; - return oss.str(); - } + std::vector<std::string> const& getTestsOrTags() const override; + std::vector<std::string> const& getSectionsToRun() const override; - inline friend std::ostream& operator << ( std::ostream& _stream, Text const& _text ) { - for( Text::const_iterator it = _text.begin(), itEnd = _text.end(); - it != itEnd; ++it ) { - if( it != _text.begin() ) - _stream << "\n"; - _stream << *it; - } - return _stream; - } + TestSpec const& testSpec() const override; + bool hasTestFilters() const override; + + bool showHelp() const; + + // IConfig interface + bool allowThrows() const override; + std::ostream& stream() const override; + std::string name() const override; + bool includeSuccessfulResults() const override; + bool warnAboutMissingAssertions() const override; + bool warnAboutNoTests() const override; + ShowDurations::OrNot showDurations() const override; + double minDuration() const override; + RunTests::InWhatOrder runOrder() const override; + unsigned int rngSeed() const override; + UseColour::YesOrNo useColour() const override; + bool shouldDebugBreak() const override; + int abortAfter() const override; + bool showInvisibles() const override; + Verbosity verbosity() const override; + bool benchmarkNoAnalysis() const override; + int benchmarkSamples() const override; + double benchmarkConfidenceInterval() const override; + unsigned int benchmarkResamples() const override; + std::chrono::milliseconds benchmarkWarmupTime() const override; private: - std::string str; - TextAttributes attr; - std::vector<std::string> lines; + + IStream const* openStream(); + ConfigData m_data; + + std::unique_ptr<IStream const> m_stream; + TestSpec m_testSpec; + bool m_hasTestFilters = false; }; -} // end namespace Tbc +} // end namespace Catch -#ifdef CLICHE_TBC_TEXT_FORMAT_OUTER_NAMESPACE -} // end outer namespace -#endif +// end catch_config.hpp +// start catch_assertionresult.h -#endif // TWOBLUECUBES_TEXT_FORMAT_H_ALREADY_INCLUDED -#undef CLICHE_TBC_TEXT_FORMAT_OUTER_NAMESPACE +#include <string> namespace Catch { - using Tbc::Text; - using Tbc::TextAttributes; -} -// #included from: catch_console_colour.hpp -#define TWOBLUECUBES_CATCH_CONSOLE_COLOUR_HPP_INCLUDED + struct AssertionResultData + { + AssertionResultData() = delete; -namespace Catch { + AssertionResultData( ResultWas::OfType _resultType, LazyExpression const& _lazyExpression ); - struct Colour { - enum Code { - None = 0, + std::string message; + mutable std::string reconstructedExpression; + LazyExpression lazyExpression; + ResultWas::OfType resultType; - White, - Red, - Green, - Blue, - Cyan, - Yellow, - Grey, + std::string reconstructExpression() const; + }; - Bright = 0x10, + class AssertionResult { + public: + AssertionResult() = delete; + AssertionResult( AssertionInfo const& info, AssertionResultData const& data ); - BrightRed = Bright | Red, - BrightGreen = Bright | Green, - LightGrey = Bright | Grey, - BrightWhite = Bright | White, + bool isOk() const; + bool succeeded() const; + ResultWas::OfType getResultType() const; + bool hasExpression() const; + bool hasMessage() const; + std::string getExpression() const; + std::string getExpressionInMacro() const; + bool hasExpandedExpression() const; + std::string getExpandedExpression() const; + std::string getMessage() const; + SourceLineInfo getSourceInfo() const; + StringRef getTestMacroName() const; - // By intention - FileName = LightGrey, - Warning = Yellow, - ResultError = BrightRed, - ResultSuccess = BrightGreen, - ResultExpectedFailure = Warning, + //protected: + AssertionInfo m_info; + AssertionResultData m_resultData; + }; - Error = BrightRed, - Success = Green, +} // end namespace Catch - OriginalExpression = Cyan, - ReconstructedExpression = Yellow, +// end catch_assertionresult.h +#if defined(CATCH_CONFIG_ENABLE_BENCHMARKING) +// start catch_estimate.hpp - SecondaryText = LightGrey, - Headers = White - }; + // Statistics estimates - // Use constructed object for RAII guard - Colour( Code _colourCode ); - Colour( Colour const& other ); - ~Colour(); - // Use static method for one-shot changes - static void use( Code _colourCode ); +namespace Catch { + namespace Benchmark { + template <typename Duration> + struct Estimate { + Duration point; + Duration lower_bound; + Duration upper_bound; + double confidence_interval; + + template <typename Duration2> + operator Estimate<Duration2>() const { + return { point, lower_bound, upper_bound, confidence_interval }; + } + }; + } // namespace Benchmark +} // namespace Catch - private: - bool m_moved; - }; +// end catch_estimate.hpp +// start catch_outlier_classification.hpp - inline std::ostream& operator << ( std::ostream& os, Colour const& ) { return os; } +// Outlier information -} // end namespace Catch +namespace Catch { + namespace Benchmark { + struct OutlierClassification { + int samples_seen = 0; + int low_severe = 0; // more than 3 times IQR below Q1 + int low_mild = 0; // 1.5 to 3 times IQR below Q1 + int high_mild = 0; // 1.5 to 3 times IQR above Q3 + int high_severe = 0; // more than 3 times IQR above Q3 + + int total() const { + return low_severe + low_mild + high_mild + high_severe; + } + }; + } // namespace Benchmark +} // namespace Catch -// #included from: catch_interfaces_reporter.h -#define TWOBLUECUBES_CATCH_INTERFACES_REPORTER_H_INCLUDED +// end catch_outlier_classification.hpp + +#include <iterator> +#endif // CATCH_CONFIG_ENABLE_BENCHMARKING #include <string> -#include <ostream> +#include <iosfwd> #include <map> +#include <set> +#include <memory> +#include <algorithm> + +namespace Catch { -namespace Catch -{ struct ReporterConfig { - explicit ReporterConfig( Ptr<IConfig const> const& _fullConfig ) - : m_stream( &_fullConfig->stream() ), m_fullConfig( _fullConfig ) {} + explicit ReporterConfig( IConfigPtr const& _fullConfig ); - ReporterConfig( Ptr<IConfig const> const& _fullConfig, std::ostream& _stream ) - : m_stream( &_stream ), m_fullConfig( _fullConfig ) {} + ReporterConfig( IConfigPtr const& _fullConfig, std::ostream& _stream ); - std::ostream& stream() const { return *m_stream; } - Ptr<IConfig const> fullConfig() const { return m_fullConfig; } + std::ostream& stream() const; + IConfigPtr fullConfig() const; private: std::ostream* m_stream; - Ptr<IConfig const> m_fullConfig; + IConfigPtr m_fullConfig; }; struct ReporterPreferences { - ReporterPreferences() - : shouldRedirectStdOut( false ) - {} - - bool shouldRedirectStdOut; + bool shouldRedirectStdOut = false; + bool shouldReportAllAssertions = false; }; template<typename T> struct LazyStat : Option<T> { - LazyStat() : used( false ) {} LazyStat& operator=( T const& _value ) { Option<T>::operator=( _value ); used = false; @@ -5643,21 +5507,17 @@ namespace Catch Option<T>::reset(); used = false; } - bool used; + bool used = false; }; struct TestRunInfo { - TestRunInfo( std::string const& _name ) : name( _name ) {} + TestRunInfo( std::string const& _name ); std::string name; }; struct GroupInfo { GroupInfo( std::string const& _name, std::size_t _groupIndex, - std::size_t _groupsCount ) - : name( _name ), - groupIndex( _groupIndex ), - groupsCounts( _groupsCount ) - {} + std::size_t _groupsCount ); std::string name; std::size_t groupIndex; @@ -5667,29 +5527,13 @@ namespace Catch struct AssertionStats { AssertionStats( AssertionResult const& _assertionResult, std::vector<MessageInfo> const& _infoMessages, - Totals const& _totals ) - : assertionResult( _assertionResult ), - infoMessages( _infoMessages ), - totals( _totals ) - { - if( assertionResult.hasMessage() ) { - // Copy message into messages list. - // !TBD This should have been done earlier, somewhere - MessageBuilder builder( assertionResult.getTestMacroName(), assertionResult.getSourceInfo(), assertionResult.getResultType() ); - builder << assertionResult.getMessage(); - builder.m_info.message = builder.m_stream.str(); - - infoMessages.push_back( builder.m_info ); - } - } - virtual ~AssertionStats(); + Totals const& _totals ); -# ifdef CATCH_CONFIG_CPP11_GENERATED_METHODS AssertionStats( AssertionStats const& ) = default; AssertionStats( AssertionStats && ) = default; - AssertionStats& operator = ( AssertionStats const& ) = default; - AssertionStats& operator = ( AssertionStats && ) = default; -# endif + AssertionStats& operator = ( AssertionStats const& ) = delete; + AssertionStats& operator = ( AssertionStats && ) = delete; + virtual ~AssertionStats(); AssertionResult assertionResult; std::vector<MessageInfo> infoMessages; @@ -5700,19 +5544,12 @@ namespace Catch SectionStats( SectionInfo const& _sectionInfo, Counts const& _assertions, double _durationInSeconds, - bool _missingAssertions ) - : sectionInfo( _sectionInfo ), - assertions( _assertions ), - durationInSeconds( _durationInSeconds ), - missingAssertions( _missingAssertions ) - {} - virtual ~SectionStats(); -# ifdef CATCH_CONFIG_CPP11_GENERATED_METHODS + bool _missingAssertions ); SectionStats( SectionStats const& ) = default; SectionStats( SectionStats && ) = default; SectionStats& operator = ( SectionStats const& ) = default; SectionStats& operator = ( SectionStats && ) = default; -# endif + virtual ~SectionStats(); SectionInfo sectionInfo; Counts assertions; @@ -5725,21 +5562,13 @@ namespace Catch Totals const& _totals, std::string const& _stdOut, std::string const& _stdErr, - bool _aborting ) - : testInfo( _testInfo ), - totals( _totals ), - stdOut( _stdOut ), - stdErr( _stdErr ), - aborting( _aborting ) - {} - virtual ~TestCaseStats(); + bool _aborting ); -# ifdef CATCH_CONFIG_CPP11_GENERATED_METHODS TestCaseStats( TestCaseStats const& ) = default; TestCaseStats( TestCaseStats && ) = default; TestCaseStats& operator = ( TestCaseStats const& ) = default; TestCaseStats& operator = ( TestCaseStats && ) = default; -# endif + virtual ~TestCaseStats(); TestCaseInfo testInfo; Totals totals; @@ -5751,23 +5580,14 @@ namespace Catch struct TestGroupStats { TestGroupStats( GroupInfo const& _groupInfo, Totals const& _totals, - bool _aborting ) - : groupInfo( _groupInfo ), - totals( _totals ), - aborting( _aborting ) - {} - TestGroupStats( GroupInfo const& _groupInfo ) - : groupInfo( _groupInfo ), - aborting( false ) - {} - virtual ~TestGroupStats(); + bool _aborting ); + TestGroupStats( GroupInfo const& _groupInfo ); -# ifdef CATCH_CONFIG_CPP11_GENERATED_METHODS TestGroupStats( TestGroupStats const& ) = default; TestGroupStats( TestGroupStats && ) = default; TestGroupStats& operator = ( TestGroupStats const& ) = default; TestGroupStats& operator = ( TestGroupStats && ) = default; -# endif + virtual ~TestGroupStats(); GroupInfo groupInfo; Totals totals; @@ -5777,49 +5597,83 @@ namespace Catch struct TestRunStats { TestRunStats( TestRunInfo const& _runInfo, Totals const& _totals, - bool _aborting ) - : runInfo( _runInfo ), - totals( _totals ), - aborting( _aborting ) - {} - virtual ~TestRunStats(); + bool _aborting ); -# ifndef CATCH_CONFIG_CPP11_GENERATED_METHODS - TestRunStats( TestRunStats const& _other ) - : runInfo( _other.runInfo ), - totals( _other.totals ), - aborting( _other.aborting ) - {} -# else TestRunStats( TestRunStats const& ) = default; TestRunStats( TestRunStats && ) = default; TestRunStats& operator = ( TestRunStats const& ) = default; TestRunStats& operator = ( TestRunStats && ) = default; -# endif + virtual ~TestRunStats(); TestRunInfo runInfo; Totals totals; bool aborting; }; - class MultipleReporters; +#if defined(CATCH_CONFIG_ENABLE_BENCHMARKING) + struct BenchmarkInfo { + std::string name; + double estimatedDuration; + int iterations; + int samples; + unsigned int resamples; + double clockResolution; + double clockCost; + }; + + template <class Duration> + struct BenchmarkStats { + BenchmarkInfo info; + + std::vector<Duration> samples; + Benchmark::Estimate<Duration> mean; + Benchmark::Estimate<Duration> standardDeviation; + Benchmark::OutlierClassification outliers; + double outlierVariance; + + template <typename Duration2> + operator BenchmarkStats<Duration2>() const { + std::vector<Duration2> samples2; + samples2.reserve(samples.size()); + std::transform(samples.begin(), samples.end(), std::back_inserter(samples2), [](Duration d) { return Duration2(d); }); + return { + info, + std::move(samples2), + mean, + standardDeviation, + outliers, + outlierVariance, + }; + } + }; +#endif // CATCH_CONFIG_ENABLE_BENCHMARKING - struct IStreamingReporter : IShared { - virtual ~IStreamingReporter(); + struct IStreamingReporter { + virtual ~IStreamingReporter() = default; - // Implementing class must also provide the following static method: + // Implementing class must also provide the following static methods: // static std::string getDescription(); + // static std::set<Verbosity> getSupportedVerbosities() virtual ReporterPreferences getPreferences() const = 0; virtual void noMatchingTestCases( std::string const& spec ) = 0; + virtual void reportInvalidArguments(std::string const&) {} + virtual void testRunStarting( TestRunInfo const& testRunInfo ) = 0; virtual void testGroupStarting( GroupInfo const& groupInfo ) = 0; virtual void testCaseStarting( TestCaseInfo const& testInfo ) = 0; virtual void sectionStarting( SectionInfo const& sectionInfo ) = 0; +#if defined(CATCH_CONFIG_ENABLE_BENCHMARKING) + virtual void benchmarkPreparing( std::string const& ) {} + virtual void benchmarkStarting( BenchmarkInfo const& ) {} + virtual void benchmarkEnded( BenchmarkStats<> const& ) {} + virtual void benchmarkFailed( std::string const& ) {} +#endif // CATCH_CONFIG_ENABLE_BENCHMARKING + virtual void assertionStarting( AssertionInfo const& assertionInfo ) = 0; // The return value indicates if the messages buffer should be cleared: @@ -5832,2475 +5686,8383 @@ namespace Catch virtual void skipTest( TestCaseInfo const& testInfo ) = 0; - virtual MultipleReporters* tryAsMulti() { return CATCH_NULL; } + // Default empty implementation provided + virtual void fatalErrorEncountered( StringRef name ); + + virtual bool isMulti() const; }; + using IStreamingReporterPtr = std::unique_ptr<IStreamingReporter>; - struct IReporterFactory : IShared { + struct IReporterFactory { virtual ~IReporterFactory(); - virtual IStreamingReporter* create( ReporterConfig const& config ) const = 0; + virtual IStreamingReporterPtr create( ReporterConfig const& config ) const = 0; virtual std::string getDescription() const = 0; }; + using IReporterFactoryPtr = std::shared_ptr<IReporterFactory>; struct IReporterRegistry { - typedef std::map<std::string, Ptr<IReporterFactory> > FactoryMap; - typedef std::vector<Ptr<IReporterFactory> > Listeners; + using FactoryMap = std::map<std::string, IReporterFactoryPtr>; + using Listeners = std::vector<IReporterFactoryPtr>; virtual ~IReporterRegistry(); - virtual IStreamingReporter* create( std::string const& name, Ptr<IConfig const> const& config ) const = 0; + virtual IStreamingReporterPtr create( std::string const& name, IConfigPtr const& config ) const = 0; virtual FactoryMap const& getFactories() const = 0; virtual Listeners const& getListeners() const = 0; }; - Ptr<IStreamingReporter> addReporter( Ptr<IStreamingReporter> const& existingReporter, Ptr<IStreamingReporter> const& additionalReporter ); - -} +} // end namespace Catch -#include <limits> +// end catch_interfaces_reporter.h #include <algorithm> +#include <cstring> +#include <cfloat> +#include <cstdio> +#include <cassert> +#include <memory> +#include <ostream> namespace Catch { + void prepareExpandedExpression(AssertionResult& result); - inline std::size_t listTests( Config const& config ) { + // Returns double formatted as %.3f (format expected on output) + std::string getFormattedDuration( double duration ); - TestSpec testSpec = config.testSpec(); - if( config.testSpec().hasFilters() ) - Catch::cout() << "Matching test cases:\n"; - else { - Catch::cout() << "All available test cases:\n"; - testSpec = TestSpecParser( ITagAliasRegistry::get() ).parse( "*" ).testSpec(); - } + //! Should the reporter show + bool shouldShowDuration( IConfig const& config, double duration ); - std::size_t matchedTests = 0; - TextAttributes nameAttr, descAttr, tagsAttr; - nameAttr.setInitialIndent( 2 ).setIndent( 4 ); - descAttr.setIndent( 4 ); - tagsAttr.setIndent( 6 ); + std::string serializeFilters( std::vector<std::string> const& container ); - std::vector<TestCase> matchedTestCases = filterTests( getAllTestCasesSorted( config ), testSpec, config ); - for( std::vector<TestCase>::const_iterator it = matchedTestCases.begin(), itEnd = matchedTestCases.end(); - it != itEnd; - ++it ) { - matchedTests++; - TestCaseInfo const& testCaseInfo = it->getTestCaseInfo(); - Colour::Code colour = testCaseInfo.isHidden() - ? Colour::SecondaryText - : Colour::None; - Colour colourGuard( colour ); + template<typename DerivedT> + struct StreamingReporterBase : IStreamingReporter { - Catch::cout() << Text( testCaseInfo.name, nameAttr ) << std::endl; - if( config.listExtraInfo() ) { - Catch::cout() << " " << testCaseInfo.lineInfo << std::endl; - std::string description = testCaseInfo.description; - if( description.empty() ) - description = "(NO DESCRIPTION)"; - Catch::cout() << Text( description, descAttr ) << std::endl; - } - if( !testCaseInfo.tags.empty() ) - Catch::cout() << Text( testCaseInfo.tagsAsString, tagsAttr ) << std::endl; + StreamingReporterBase( ReporterConfig const& _config ) + : m_config( _config.fullConfig() ), + stream( _config.stream() ) + { + m_reporterPrefs.shouldRedirectStdOut = false; + if( !DerivedT::getSupportedVerbosities().count( m_config->verbosity() ) ) + CATCH_ERROR( "Verbosity level not supported by this reporter" ); } - if( !config.testSpec().hasFilters() ) - Catch::cout() << pluralise( matchedTests, "test case" ) << '\n' << std::endl; - else - Catch::cout() << pluralise( matchedTests, "matching test case" ) << '\n' << std::endl; - return matchedTests; - } - - inline std::size_t listTestsNamesOnly( Config const& config ) { - TestSpec testSpec = config.testSpec(); - if( !config.testSpec().hasFilters() ) - testSpec = TestSpecParser( ITagAliasRegistry::get() ).parse( "*" ).testSpec(); - std::size_t matchedTests = 0; - std::vector<TestCase> matchedTestCases = filterTests( getAllTestCasesSorted( config ), testSpec, config ); - for( std::vector<TestCase>::const_iterator it = matchedTestCases.begin(), itEnd = matchedTestCases.end(); - it != itEnd; - ++it ) { - matchedTests++; - TestCaseInfo const& testCaseInfo = it->getTestCaseInfo(); - if( startsWith( testCaseInfo.name, '#' ) ) - Catch::cout() << '"' << testCaseInfo.name << '"'; - else - Catch::cout() << testCaseInfo.name; - if ( config.listExtraInfo() ) - Catch::cout() << "\t@" << testCaseInfo.lineInfo; - Catch::cout() << std::endl; + ReporterPreferences getPreferences() const override { + return m_reporterPrefs; } - return matchedTests; - } - struct TagInfo { - TagInfo() : count ( 0 ) {} - void add( std::string const& spelling ) { - ++count; - spellings.insert( spelling ); - } - std::string all() const { - std::string out; - for( std::set<std::string>::const_iterator it = spellings.begin(), itEnd = spellings.end(); - it != itEnd; - ++it ) - out += "[" + *it + "]"; - return out; + static std::set<Verbosity> getSupportedVerbosities() { + return { Verbosity::Normal }; } - std::set<std::string> spellings; - std::size_t count; - }; - inline std::size_t listTags( Config const& config ) { - TestSpec testSpec = config.testSpec(); - if( config.testSpec().hasFilters() ) - Catch::cout() << "Tags for matching test cases:\n"; - else { - Catch::cout() << "All available tags:\n"; - testSpec = TestSpecParser( ITagAliasRegistry::get() ).parse( "*" ).testSpec(); - } + ~StreamingReporterBase() override = default; - std::map<std::string, TagInfo> tagCounts; + void noMatchingTestCases(std::string const&) override {} - std::vector<TestCase> matchedTestCases = filterTests( getAllTestCasesSorted( config ), testSpec, config ); - for( std::vector<TestCase>::const_iterator it = matchedTestCases.begin(), itEnd = matchedTestCases.end(); - it != itEnd; - ++it ) { - for( std::set<std::string>::const_iterator tagIt = it->getTestCaseInfo().tags.begin(), - tagItEnd = it->getTestCaseInfo().tags.end(); - tagIt != tagItEnd; - ++tagIt ) { - std::string tagName = *tagIt; - std::string lcaseTagName = toLower( tagName ); - std::map<std::string, TagInfo>::iterator countIt = tagCounts.find( lcaseTagName ); - if( countIt == tagCounts.end() ) - countIt = tagCounts.insert( std::make_pair( lcaseTagName, TagInfo() ) ).first; - countIt->second.add( tagName ); - } - } + void reportInvalidArguments(std::string const&) override {} - for( std::map<std::string, TagInfo>::const_iterator countIt = tagCounts.begin(), - countItEnd = tagCounts.end(); - countIt != countItEnd; - ++countIt ) { - std::ostringstream oss; - oss << " " << std::setw(2) << countIt->second.count << " "; - Text wrapper( countIt->second.all(), TextAttributes() - .setInitialIndent( 0 ) - .setIndent( oss.str().size() ) - .setWidth( CATCH_CONFIG_CONSOLE_WIDTH-10 ) ); - Catch::cout() << oss.str() << wrapper << '\n'; + void testRunStarting(TestRunInfo const& _testRunInfo) override { + currentTestRunInfo = _testRunInfo; } - Catch::cout() << pluralise( tagCounts.size(), "tag" ) << '\n' << std::endl; - return tagCounts.size(); - } - inline std::size_t listReporters( Config const& /*config*/ ) { - Catch::cout() << "Available reporters:\n"; - IReporterRegistry::FactoryMap const& factories = getRegistryHub().getReporterRegistry().getFactories(); - IReporterRegistry::FactoryMap::const_iterator itBegin = factories.begin(), itEnd = factories.end(), it; - std::size_t maxNameLen = 0; - for(it = itBegin; it != itEnd; ++it ) - maxNameLen = (std::max)( maxNameLen, it->first.size() ); - - for(it = itBegin; it != itEnd; ++it ) { - Text wrapper( it->second->getDescription(), TextAttributes() - .setInitialIndent( 0 ) - .setIndent( 7+maxNameLen ) - .setWidth( CATCH_CONFIG_CONSOLE_WIDTH - maxNameLen-8 ) ); - Catch::cout() << " " - << it->first - << ':' - << std::string( maxNameLen - it->first.size() + 2, ' ' ) - << wrapper << '\n'; + void testGroupStarting(GroupInfo const& _groupInfo) override { + currentGroupInfo = _groupInfo; } - Catch::cout() << std::endl; - return factories.size(); - } - inline Option<std::size_t> list( Config const& config ) { - Option<std::size_t> listedCount; - if( config.listTests() || ( config.listExtraInfo() && !config.listTestNamesOnly() ) ) - listedCount = listedCount.valueOr(0) + listTests( config ); - if( config.listTestNamesOnly() ) - listedCount = listedCount.valueOr(0) + listTestsNamesOnly( config ); - if( config.listTags() ) - listedCount = listedCount.valueOr(0) + listTags( config ); - if( config.listReporters() ) - listedCount = listedCount.valueOr(0) + listReporters( config ); - return listedCount; - } - -} // end namespace Catch - -// #included from: internal/catch_run_context.hpp -#define TWOBLUECUBES_CATCH_RUNNER_IMPL_HPP_INCLUDED - -// #included from: catch_test_case_tracker.hpp -#define TWOBLUECUBES_CATCH_TEST_CASE_TRACKER_HPP_INCLUDED + void testCaseStarting(TestCaseInfo const& _testInfo) override { + currentTestCaseInfo = _testInfo; + } + void sectionStarting(SectionInfo const& _sectionInfo) override { + m_sectionStack.push_back(_sectionInfo); + } -#include <algorithm> -#include <string> -#include <assert.h> -#include <vector> -#include <stdexcept> + void sectionEnded(SectionStats const& /* _sectionStats */) override { + m_sectionStack.pop_back(); + } + void testCaseEnded(TestCaseStats const& /* _testCaseStats */) override { + currentTestCaseInfo.reset(); + } + void testGroupEnded(TestGroupStats const& /* _testGroupStats */) override { + currentGroupInfo.reset(); + } + void testRunEnded(TestRunStats const& /* _testRunStats */) override { + currentTestCaseInfo.reset(); + currentGroupInfo.reset(); + currentTestRunInfo.reset(); + } -CATCH_INTERNAL_SUPPRESS_ETD_WARNINGS + void skipTest(TestCaseInfo const&) override { + // Don't do anything with this by default. + // It can optionally be overridden in the derived class. + } -namespace Catch { -namespace TestCaseTracking { + IConfigPtr m_config; + std::ostream& stream; - struct NameAndLocation { - std::string name; - SourceLineInfo location; + LazyStat<TestRunInfo> currentTestRunInfo; + LazyStat<GroupInfo> currentGroupInfo; + LazyStat<TestCaseInfo> currentTestCaseInfo; - NameAndLocation( std::string const& _name, SourceLineInfo const& _location ) - : name( _name ), - location( _location ) - {} + std::vector<SectionInfo> m_sectionStack; + ReporterPreferences m_reporterPrefs; }; - struct ITracker : SharedImpl<> { - virtual ~ITracker(); - - // static queries - virtual NameAndLocation const& nameAndLocation() 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; + template<typename DerivedT> + struct CumulativeReporterBase : IStreamingReporter { + template<typename T, typename ChildNodeT> + struct Node { + explicit Node( T const& _value ) : value( _value ) {} + virtual ~Node() {} - // actions - virtual void close() = 0; // Successfully complete - virtual void fail() = 0; - virtual void markAsNeedingAnotherRun() = 0; + using ChildNodes = std::vector<std::shared_ptr<ChildNodeT>>; + T value; + ChildNodes children; + }; + struct SectionNode { + explicit SectionNode(SectionStats const& _stats) : stats(_stats) {} + virtual ~SectionNode() = default; - virtual void addChild( Ptr<ITracker> const& child ) = 0; - virtual ITracker* findChild( NameAndLocation const& nameAndLocation ) = 0; - virtual void openChild() = 0; + bool operator == (SectionNode const& other) const { + return stats.sectionInfo.lineInfo == other.stats.sectionInfo.lineInfo; + } + bool operator == (std::shared_ptr<SectionNode> const& other) const { + return operator==(*other); + } - // Debug/ checking - virtual bool isSectionTracker() const = 0; - virtual bool isIndexTracker() const = 0; - }; + SectionStats stats; + using ChildSections = std::vector<std::shared_ptr<SectionNode>>; + using Assertions = std::vector<AssertionStats>; + ChildSections childSections; + Assertions assertions; + std::string stdOut; + std::string stdErr; + }; - class TrackerContext { + struct BySectionInfo { + BySectionInfo( SectionInfo const& other ) : m_other( other ) {} + BySectionInfo( BySectionInfo const& other ) : m_other( other.m_other ) {} + bool operator() (std::shared_ptr<SectionNode> const& node) const { + return ((node->stats.sectionInfo.name == m_other.name) && + (node->stats.sectionInfo.lineInfo == m_other.lineInfo)); + } + void operator=(BySectionInfo const&) = delete; - enum RunState { - NotStarted, - Executing, - CompletedCycle + private: + SectionInfo const& m_other; }; - Ptr<ITracker> m_rootTracker; - ITracker* m_currentTracker; - RunState m_runState; - - public: + using TestCaseNode = Node<TestCaseStats, SectionNode>; + using TestGroupNode = Node<TestGroupStats, TestCaseNode>; + using TestRunNode = Node<TestRunStats, TestGroupNode>; - static TrackerContext& instance() { - static TrackerContext s_instance; - return s_instance; + CumulativeReporterBase( ReporterConfig const& _config ) + : m_config( _config.fullConfig() ), + stream( _config.stream() ) + { + m_reporterPrefs.shouldRedirectStdOut = false; + if( !DerivedT::getSupportedVerbosities().count( m_config->verbosity() ) ) + CATCH_ERROR( "Verbosity level not supported by this reporter" ); } + ~CumulativeReporterBase() override = default; - TrackerContext() - : m_currentTracker( CATCH_NULL ), - m_runState( NotStarted ) - {} - - ITracker& startRun(); - - void endRun() { - m_rootTracker.reset(); - m_currentTracker = CATCH_NULL; - m_runState = NotStarted; + ReporterPreferences getPreferences() const override { + return m_reporterPrefs; } - void startCycle() { - m_currentTracker = m_rootTracker.get(); - m_runState = Executing; - } - void completeCycle() { - m_runState = CompletedCycle; + static std::set<Verbosity> getSupportedVerbosities() { + return { Verbosity::Normal }; } - bool completedCycle() const { - return m_runState == CompletedCycle; - } - ITracker& currentTracker() { - return *m_currentTracker; - } - void setCurrentTracker( ITracker* tracker ) { - m_currentTracker = tracker; - } - }; + void testRunStarting( TestRunInfo const& ) override {} + void testGroupStarting( GroupInfo const& ) override {} - class TrackerBase : public ITracker { - protected: - enum CycleState { - NotStarted, - Executing, - ExecutingChildren, - NeedsAnotherRun, - CompletedSuccessfully, - Failed - }; - class TrackerHasName { - NameAndLocation m_nameAndLocation; - public: - TrackerHasName( NameAndLocation const& nameAndLocation ) : m_nameAndLocation( nameAndLocation ) {} - bool operator ()( Ptr<ITracker> const& tracker ) { - return - tracker->nameAndLocation().name == m_nameAndLocation.name && - tracker->nameAndLocation().location == m_nameAndLocation.location; + void testCaseStarting( TestCaseInfo const& ) override {} + + void sectionStarting( SectionInfo const& sectionInfo ) override { + SectionStats incompleteStats( sectionInfo, Counts(), 0, false ); + std::shared_ptr<SectionNode> node; + if( m_sectionStack.empty() ) { + if( !m_rootSection ) + m_rootSection = std::make_shared<SectionNode>( incompleteStats ); + node = m_rootSection; } - }; - typedef std::vector<Ptr<ITracker> > Children; - NameAndLocation m_nameAndLocation; - TrackerContext& m_ctx; - ITracker* m_parent; - Children m_children; - CycleState m_runState; - public: - TrackerBase( NameAndLocation const& nameAndLocation, TrackerContext& ctx, ITracker* parent ) - : m_nameAndLocation( nameAndLocation ), - m_ctx( ctx ), - m_parent( parent ), - m_runState( NotStarted ) - {} - virtual ~TrackerBase(); + else { + SectionNode& parentNode = *m_sectionStack.back(); + auto it = + std::find_if( parentNode.childSections.begin(), + parentNode.childSections.end(), + BySectionInfo( sectionInfo ) ); + if( it == parentNode.childSections.end() ) { + node = std::make_shared<SectionNode>( incompleteStats ); + parentNode.childSections.push_back( node ); + } + else + node = *it; + } + m_sectionStack.push_back( node ); + m_deepestSection = std::move(node); + } - virtual NameAndLocation const& nameAndLocation() const CATCH_OVERRIDE { - return m_nameAndLocation; + void assertionStarting(AssertionInfo const&) override {} + + bool assertionEnded(AssertionStats const& assertionStats) override { + assert(!m_sectionStack.empty()); + // AssertionResult holds a pointer to a temporary DecomposedExpression, + // which getExpandedExpression() calls to build the expression string. + // Our section stack copy of the assertionResult will likely outlive the + // temporary, so it must be expanded or discarded now to avoid calling + // a destroyed object later. + prepareExpandedExpression(const_cast<AssertionResult&>( assertionStats.assertionResult ) ); + SectionNode& sectionNode = *m_sectionStack.back(); + sectionNode.assertions.push_back(assertionStats); + return true; } - virtual bool isComplete() const CATCH_OVERRIDE { - return m_runState == CompletedSuccessfully || m_runState == Failed; + void sectionEnded(SectionStats const& sectionStats) override { + assert(!m_sectionStack.empty()); + SectionNode& node = *m_sectionStack.back(); + node.stats = sectionStats; + m_sectionStack.pop_back(); } - virtual bool isSuccessfullyCompleted() const CATCH_OVERRIDE { - return m_runState == CompletedSuccessfully; + void testCaseEnded(TestCaseStats const& testCaseStats) override { + auto node = std::make_shared<TestCaseNode>(testCaseStats); + assert(m_sectionStack.size() == 0); + node->children.push_back(m_rootSection); + m_testCases.push_back(node); + m_rootSection.reset(); + + assert(m_deepestSection); + m_deepestSection->stdOut = testCaseStats.stdOut; + m_deepestSection->stdErr = testCaseStats.stdErr; } - virtual bool isOpen() const CATCH_OVERRIDE { - return m_runState != NotStarted && !isComplete(); + void testGroupEnded(TestGroupStats const& testGroupStats) override { + auto node = std::make_shared<TestGroupNode>(testGroupStats); + node->children.swap(m_testCases); + m_testGroups.push_back(node); } - virtual bool hasChildren() const CATCH_OVERRIDE { - return !m_children.empty(); + void testRunEnded(TestRunStats const& testRunStats) override { + auto node = std::make_shared<TestRunNode>(testRunStats); + node->children.swap(m_testGroups); + m_testRuns.push_back(node); + testRunEndedCumulative(); } + virtual void testRunEndedCumulative() = 0; - virtual void addChild( Ptr<ITracker> const& child ) CATCH_OVERRIDE { - m_children.push_back( child ); - } + void skipTest(TestCaseInfo const&) override {} - virtual ITracker* findChild( NameAndLocation const& nameAndLocation ) CATCH_OVERRIDE { - Children::const_iterator it = std::find_if( m_children.begin(), m_children.end(), TrackerHasName( nameAndLocation ) ); - 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; - } + IConfigPtr m_config; + std::ostream& stream; + std::vector<AssertionStats> m_assertions; + std::vector<std::vector<std::shared_ptr<SectionNode>>> m_sections; + std::vector<std::shared_ptr<TestCaseNode>> m_testCases; + std::vector<std::shared_ptr<TestGroupNode>> m_testGroups; - virtual void openChild() CATCH_OVERRIDE { - if( m_runState != ExecutingChildren ) { - m_runState = ExecutingChildren; - if( m_parent ) - m_parent->openChild(); - } - } + std::vector<std::shared_ptr<TestRunNode>> m_testRuns; - virtual bool isSectionTracker() const CATCH_OVERRIDE { return false; } - virtual bool isIndexTracker() const CATCH_OVERRIDE { return false; } + std::shared_ptr<SectionNode> m_rootSection; + std::shared_ptr<SectionNode> m_deepestSection; + std::vector<std::shared_ptr<SectionNode>> m_sectionStack; + ReporterPreferences m_reporterPrefs; + }; - void open() { - m_runState = Executing; - moveToThis(); - if( m_parent ) - m_parent->openChild(); + template<char C> + char const* getLineOfChars() { + static char line[CATCH_CONFIG_CONSOLE_WIDTH] = {0}; + if( !*line ) { + std::memset( line, C, CATCH_CONFIG_CONSOLE_WIDTH-1 ); + line[CATCH_CONFIG_CONSOLE_WIDTH-1] = 0; } + return line; + } - virtual void close() CATCH_OVERRIDE { + struct TestEventListenerBase : StreamingReporterBase<TestEventListenerBase> { + TestEventListenerBase( ReporterConfig const& _config ); - // Close any still open children (e.g. generators) - while( &m_ctx.currentTracker() != this ) - m_ctx.currentTracker().close(); + static std::set<Verbosity> getSupportedVerbosities(); - switch( m_runState ) { - case NotStarted: - case CompletedSuccessfully: - case Failed: - throw std::logic_error( "Illogical state" ); + void assertionStarting(AssertionInfo const&) override; + bool assertionEnded(AssertionStats const&) override; + }; - case NeedsAnotherRun: - break;; +} // end namespace Catch - case Executing: - m_runState = CompletedSuccessfully; - break; - case ExecutingChildren: - if( m_children.empty() || m_children.back()->isComplete() ) - m_runState = CompletedSuccessfully; - break; +// end catch_reporter_bases.hpp +// start catch_console_colour.h - default: - throw std::logic_error( "Unexpected state" ); - } - 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 moveToParent() { - assert( m_parent ); - m_ctx.setCurrentTracker( m_parent ); - } - void moveToThis() { - m_ctx.setCurrentTracker( this ); - } - }; +namespace Catch { - class SectionTracker : public TrackerBase { - std::vector<std::string> m_filters; - public: - SectionTracker( NameAndLocation const& nameAndLocation, TrackerContext& ctx, ITracker* parent ) - : TrackerBase( nameAndLocation, ctx, parent ) - { - if( parent ) { - while( !parent->isSectionTracker() ) - parent = &parent->parent(); + struct Colour { + enum Code { + None = 0, - SectionTracker& parentSection = static_cast<SectionTracker&>( *parent ); - addNextFilters( parentSection.m_filters ); - } - } - virtual ~SectionTracker(); + White, + Red, + Green, + Blue, + Cyan, + Yellow, + Grey, - virtual bool isSectionTracker() const CATCH_OVERRIDE { return true; } + Bright = 0x10, - static SectionTracker& acquire( TrackerContext& ctx, NameAndLocation const& nameAndLocation ) { - SectionTracker* section = CATCH_NULL; + BrightRed = Bright | Red, + BrightGreen = Bright | Green, + LightGrey = Bright | Grey, + BrightWhite = Bright | White, + BrightYellow = Bright | Yellow, - ITracker& currentTracker = ctx.currentTracker(); - if( ITracker* childTracker = currentTracker.findChild( nameAndLocation ) ) { - assert( childTracker ); - assert( childTracker->isSectionTracker() ); - section = static_cast<SectionTracker*>( childTracker ); - } - else { - section = new SectionTracker( nameAndLocation, ctx, ¤tTracker ); - currentTracker.addChild( section ); - } - if( !ctx.completedCycle() ) - section->tryOpen(); - return *section; - } + // By intention + FileName = LightGrey, + Warning = BrightYellow, + ResultError = BrightRed, + ResultSuccess = BrightGreen, + ResultExpectedFailure = Warning, - void tryOpen() { - if( !isComplete() && (m_filters.empty() || m_filters[0].empty() || m_filters[0] == m_nameAndLocation.name ) ) - open(); - } + Error = BrightRed, + Success = Green, - void addInitialFilters( std::vector<std::string> const& filters ) { - if( !filters.empty() ) { - m_filters.push_back(""); // Root - should never be consulted - m_filters.push_back(""); // Test Case - not a section filter - m_filters.insert( m_filters.end(), filters.begin(), filters.end() ); - } - } - void addNextFilters( std::vector<std::string> const& filters ) { - if( filters.size() > 1 ) - m_filters.insert( m_filters.end(), ++filters.begin(), filters.end() ); - } + OriginalExpression = Cyan, + ReconstructedExpression = BrightYellow, + + SecondaryText = LightGrey, + Headers = White + }; + + // Use constructed object for RAII guard + Colour( Code _colourCode ); + Colour( Colour&& other ) noexcept; + Colour& operator=( Colour&& other ) noexcept; + ~Colour(); + + // Use static method for one-shot changes + static void use( Code _colourCode ); + + private: + bool m_moved = false; }; - class IndexTracker : public TrackerBase { - int m_size; - int m_index; - public: - IndexTracker( NameAndLocation const& nameAndLocation, TrackerContext& ctx, ITracker* parent, int size ) - : TrackerBase( nameAndLocation, ctx, parent ), - m_size( size ), - m_index( -1 ) - {} - virtual ~IndexTracker(); + std::ostream& operator << ( std::ostream& os, Colour const& ); - virtual bool isIndexTracker() const CATCH_OVERRIDE { return true; } +} // end namespace Catch - static IndexTracker& acquire( TrackerContext& ctx, NameAndLocation const& nameAndLocation, int size ) { - IndexTracker* tracker = CATCH_NULL; +// end catch_console_colour.h +// start catch_reporter_registrars.hpp - ITracker& currentTracker = ctx.currentTracker(); - if( ITracker* childTracker = currentTracker.findChild( nameAndLocation ) ) { - assert( childTracker ); - assert( childTracker->isIndexTracker() ); - tracker = static_cast<IndexTracker*>( childTracker ); - } - else { - tracker = new IndexTracker( nameAndLocation, ctx, ¤tTracker, size ); - currentTracker.addChild( tracker ); + +namespace Catch { + + template<typename T> + class ReporterRegistrar { + + class ReporterFactory : public IReporterFactory { + + IStreamingReporterPtr create( ReporterConfig const& config ) const override { + return std::unique_ptr<T>( new T( config ) ); } - if( !ctx.completedCycle() && !tracker->isComplete() ) { - if( tracker->m_runState != ExecutingChildren && tracker->m_runState != NeedsAnotherRun ) - tracker->moveNext(); - tracker->open(); + std::string getDescription() const override { + return T::getDescription(); } + }; + + public: - return *tracker; + explicit ReporterRegistrar( std::string const& name ) { + getMutableRegistryHub().registerReporter( name, std::make_shared<ReporterFactory>() ); } + }; - int index() const { return m_index; } + template<typename T> + class ListenerRegistrar { - void moveNext() { - m_index++; - m_children.clear(); - } + class ListenerFactory : public IReporterFactory { - virtual void close() CATCH_OVERRIDE { - TrackerBase::close(); - if( m_runState == CompletedSuccessfully && m_index < m_size-1 ) - m_runState = Executing; + IStreamingReporterPtr create( ReporterConfig const& config ) const override { + return std::unique_ptr<T>( new T( config ) ); + } + std::string getDescription() const override { + return std::string(); + } + }; + + public: + + ListenerRegistrar() { + getMutableRegistryHub().registerListener( std::make_shared<ListenerFactory>() ); } }; +} - inline ITracker& TrackerContext::startRun() { - m_rootTracker = new SectionTracker( NameAndLocation( "{root}", CATCH_INTERNAL_LINEINFO ), *this, CATCH_NULL ); - m_currentTracker = CATCH_NULL; - m_runState = Executing; - return *m_rootTracker; - } +#if !defined(CATCH_CONFIG_DISABLE) -} // namespace TestCaseTracking +#define CATCH_REGISTER_REPORTER( name, reporterType ) \ + CATCH_INTERNAL_START_WARNINGS_SUPPRESSION \ + CATCH_INTERNAL_SUPPRESS_GLOBALS_WARNINGS \ + namespace{ Catch::ReporterRegistrar<reporterType> catch_internal_RegistrarFor##reporterType( name ); } \ + CATCH_INTERNAL_STOP_WARNINGS_SUPPRESSION -using TestCaseTracking::ITracker; -using TestCaseTracking::TrackerContext; -using TestCaseTracking::SectionTracker; -using TestCaseTracking::IndexTracker; +#define CATCH_REGISTER_LISTENER( listenerType ) \ + CATCH_INTERNAL_START_WARNINGS_SUPPRESSION \ + CATCH_INTERNAL_SUPPRESS_GLOBALS_WARNINGS \ + namespace{ Catch::ListenerRegistrar<listenerType> catch_internal_RegistrarFor##listenerType; } \ + CATCH_INTERNAL_STOP_WARNINGS_SUPPRESSION +#else // CATCH_CONFIG_DISABLE -} // namespace Catch +#define CATCH_REGISTER_REPORTER(name, reporterType) +#define CATCH_REGISTER_LISTENER(listenerType) -CATCH_INTERNAL_UNSUPPRESS_ETD_WARNINGS +#endif // CATCH_CONFIG_DISABLE -// #included from: catch_fatal_condition.hpp -#define TWOBLUECUBES_CATCH_FATAL_CONDITION_H_INCLUDED +// end catch_reporter_registrars.hpp +// Allow users to base their work off existing reporters +// start catch_reporter_compact.h namespace Catch { - // Report the error condition - inline void reportFatal( std::string const& message ) { - IContext& context = Catch::getCurrentContext(); - IResultCapture* resultCapture = context.getResultCapture(); - resultCapture->handleFatalErrorCondition( message ); - } + struct CompactReporter : StreamingReporterBase<CompactReporter> { -} // namespace Catch + using StreamingReporterBase::StreamingReporterBase; -#if defined ( CATCH_PLATFORM_WINDOWS ) ///////////////////////////////////////// -// #included from: catch_windows_h_proxy.h + ~CompactReporter() override; -#define TWOBLUECUBES_CATCH_WINDOWS_H_PROXY_H_INCLUDED + static std::string getDescription(); -#ifdef CATCH_DEFINES_NOMINMAX -# define NOMINMAX -#endif -#ifdef CATCH_DEFINES_WIN32_LEAN_AND_MEAN -# define WIN32_LEAN_AND_MEAN -#endif + void noMatchingTestCases(std::string const& spec) override; -#ifdef __AFXDLL -#include <AfxWin.h> -#else -#include <windows.h> -#endif + void assertionStarting(AssertionInfo const&) override; -#ifdef CATCH_DEFINES_NOMINMAX -# undef NOMINMAX -#endif -#ifdef CATCH_DEFINES_WIN32_LEAN_AND_MEAN -# undef WIN32_LEAN_AND_MEAN -#endif + bool assertionEnded(AssertionStats const& _assertionStats) override; + void sectionEnded(SectionStats const& _sectionStats) override; -# if !defined ( CATCH_CONFIG_WINDOWS_SEH ) + void testRunEnded(TestRunStats const& _testRunStats) override; -namespace Catch { - struct FatalConditionHandler { - void reset() {} }; -} - -# else // CATCH_CONFIG_WINDOWS_SEH is defined -namespace Catch { +} // end namespace Catch - struct SignalDefs { DWORD id; const char* name; }; - extern SignalDefs signalDefs[]; - // There is no 1-1 mapping between signals and windows exceptions. - // Windows can easily distinguish between SO and SigSegV, - // but SigInt, SigTerm, etc are handled differently. - SignalDefs signalDefs[] = { - { EXCEPTION_ILLEGAL_INSTRUCTION, "SIGILL - Illegal instruction signal" }, - { EXCEPTION_STACK_OVERFLOW, "SIGSEGV - Stack overflow" }, - { EXCEPTION_ACCESS_VIOLATION, "SIGSEGV - Segmentation violation signal" }, - { EXCEPTION_INT_DIVIDE_BY_ZERO, "Divide by zero error" }, - }; +// end catch_reporter_compact.h +// start catch_reporter_console.h - struct FatalConditionHandler { +#if defined(_MSC_VER) +#pragma warning(push) +#pragma warning(disable:4061) // Not all labels are EXPLICITLY handled in switch + // Note that 4062 (not all labels are handled + // and default is missing) is enabled +#endif - static LONG CALLBACK handleVectoredException(PEXCEPTION_POINTERS ExceptionInfo) { - for (int i = 0; i < sizeof(signalDefs) / sizeof(SignalDefs); ++i) { - if (ExceptionInfo->ExceptionRecord->ExceptionCode == signalDefs[i].id) { - reportFatal(signalDefs[i].name); - } - } - // If its not an exception we care about, pass it along. - // This stops us from eating debugger breaks etc. - return EXCEPTION_CONTINUE_SEARCH; - } +namespace Catch { + // Fwd decls + struct SummaryColumn; + class TablePrinter; - FatalConditionHandler() { - isSet = true; - // 32k seems enough for Catch to handle stack overflow, - // but the value was found experimentally, so there is no strong guarantee - guaranteeSize = 32 * 1024; - exceptionHandlerHandle = CATCH_NULL; - // Register as first handler in current chain - exceptionHandlerHandle = AddVectoredExceptionHandler(1, handleVectoredException); - // Pass in guarantee size to be filled - SetThreadStackGuarantee(&guaranteeSize); - } + struct ConsoleReporter : StreamingReporterBase<ConsoleReporter> { + std::unique_ptr<TablePrinter> m_tablePrinter; - static void reset() { - if (isSet) { - // Unregister handler and restore the old guarantee - RemoveVectoredExceptionHandler(exceptionHandlerHandle); - SetThreadStackGuarantee(&guaranteeSize); - exceptionHandlerHandle = CATCH_NULL; - isSet = false; - } - } + ConsoleReporter(ReporterConfig const& config); + ~ConsoleReporter() override; + static std::string getDescription(); - ~FatalConditionHandler() { - reset(); - } - private: - static bool isSet; - static ULONG guaranteeSize; - static PVOID exceptionHandlerHandle; - }; + void noMatchingTestCases(std::string const& spec) override; - bool FatalConditionHandler::isSet = false; - ULONG FatalConditionHandler::guaranteeSize = 0; - PVOID FatalConditionHandler::exceptionHandlerHandle = CATCH_NULL; + void reportInvalidArguments(std::string const&arg) override; -} // namespace Catch + void assertionStarting(AssertionInfo const&) override; -# endif // CATCH_CONFIG_WINDOWS_SEH + bool assertionEnded(AssertionStats const& _assertionStats) override; -#else // Not Windows - assumed to be POSIX compatible ////////////////////////// + void sectionStarting(SectionInfo const& _sectionInfo) override; + void sectionEnded(SectionStats const& _sectionStats) override; -# if !defined(CATCH_CONFIG_POSIX_SIGNALS) +#if defined(CATCH_CONFIG_ENABLE_BENCHMARKING) + void benchmarkPreparing(std::string const& name) override; + void benchmarkStarting(BenchmarkInfo const& info) override; + void benchmarkEnded(BenchmarkStats<> const& stats) override; + void benchmarkFailed(std::string const& error) override; +#endif // CATCH_CONFIG_ENABLE_BENCHMARKING -namespace Catch { - struct FatalConditionHandler { - void reset() {} - }; -} + void testCaseEnded(TestCaseStats const& _testCaseStats) override; + void testGroupEnded(TestGroupStats const& _testGroupStats) override; + void testRunEnded(TestRunStats const& _testRunStats) override; + void testRunStarting(TestRunInfo const& _testRunInfo) override; + private: -# else // CATCH_CONFIG_POSIX_SIGNALS is defined + void lazyPrint(); -#include <signal.h> + void lazyPrintWithoutClosingBenchmarkTable(); + void lazyPrintRunInfo(); + void lazyPrintGroupInfo(); + void printTestCaseAndSectionHeader(); -namespace Catch { + void printClosedHeader(std::string const& _name); + void printOpenHeader(std::string const& _name); - struct SignalDefs { - int id; - const char* name; - }; - extern SignalDefs signalDefs[]; - SignalDefs signalDefs[] = { - { SIGINT, "SIGINT - Terminal interrupt signal" }, - { SIGILL, "SIGILL - Illegal instruction signal" }, - { SIGFPE, "SIGFPE - Floating point error signal" }, - { SIGSEGV, "SIGSEGV - Segmentation violation signal" }, - { SIGTERM, "SIGTERM - Termination request signal" }, - { SIGABRT, "SIGABRT - Abort (abnormal termination) signal" } - }; - - struct FatalConditionHandler { - - static bool isSet; - static struct sigaction oldSigActions [sizeof(signalDefs)/sizeof(SignalDefs)]; - static stack_t oldSigStack; - static char altStackMem[SIGSTKSZ]; - - static void handleSignal( int sig ) { - std::string name = "<unknown signal>"; - for (std::size_t i = 0; i < sizeof(signalDefs) / sizeof(SignalDefs); ++i) { - SignalDefs &def = signalDefs[i]; - if (sig == def.id) { - name = def.name; - break; - } - } - reset(); - reportFatal(name); - raise( sig ); - } + // if string has a : in first line will set indent to follow it on + // subsequent lines + void printHeaderString(std::string const& _string, std::size_t indent = 0); - FatalConditionHandler() { - isSet = true; - stack_t sigStack; - sigStack.ss_sp = altStackMem; - sigStack.ss_size = SIGSTKSZ; - sigStack.ss_flags = 0; - sigaltstack(&sigStack, &oldSigStack); - struct sigaction sa = { 0 }; + void printTotals(Totals const& totals); + void printSummaryRow(std::string const& label, std::vector<SummaryColumn> const& cols, std::size_t row); - sa.sa_handler = handleSignal; - sa.sa_flags = SA_ONSTACK; - for (std::size_t i = 0; i < sizeof(signalDefs)/sizeof(SignalDefs); ++i) { - sigaction(signalDefs[i].id, &sa, &oldSigActions[i]); - } - } + void printTotalsDivider(Totals const& totals); + void printSummaryDivider(); + void printTestFilters(); - ~FatalConditionHandler() { - reset(); - } - static void reset() { - if( isSet ) { - // Set signals back to previous values -- hopefully nobody overwrote them in the meantime - for( std::size_t i = 0; i < sizeof(signalDefs)/sizeof(SignalDefs); ++i ) { - sigaction(signalDefs[i].id, &oldSigActions[i], CATCH_NULL); - } - // Return the old stack - sigaltstack(&oldSigStack, CATCH_NULL); - isSet = false; - } - } + private: + bool m_headerPrinted = false; }; - bool FatalConditionHandler::isSet = false; - struct sigaction FatalConditionHandler::oldSigActions[sizeof(signalDefs)/sizeof(SignalDefs)] = {}; - stack_t FatalConditionHandler::oldSigStack = {}; - char FatalConditionHandler::altStackMem[SIGSTKSZ] = {}; +} // end namespace Catch -} // namespace Catch +#if defined(_MSC_VER) +#pragma warning(pop) +#endif -# endif // CATCH_CONFIG_POSIX_SIGNALS +// end catch_reporter_console.h +// start catch_reporter_junit.h -#endif // not Windows +// start catch_xmlwriter.h -#include <cassert> -#include <set> -#include <string> +#include <vector> namespace Catch { + enum class XmlFormatting { + None = 0x00, + Indent = 0x01, + Newline = 0x02, + }; - class StreamRedirect { + XmlFormatting operator | (XmlFormatting lhs, XmlFormatting rhs); + XmlFormatting operator & (XmlFormatting lhs, XmlFormatting rhs); + class XmlEncode { public: - StreamRedirect( std::ostream& stream, std::string& targetString ) - : m_stream( stream ), - m_prevBuf( stream.rdbuf() ), - m_targetString( targetString ) - { - stream.rdbuf( m_oss.rdbuf() ); - } + enum ForWhat { ForTextNodes, ForAttributes }; - ~StreamRedirect() { - m_targetString += m_oss.str(); - m_stream.rdbuf( m_prevBuf ); - } + XmlEncode( std::string const& str, ForWhat forWhat = ForTextNodes ); - private: - std::ostream& m_stream; - std::streambuf* m_prevBuf; - std::ostringstream m_oss; - std::string& m_targetString; - }; + void encodeTo( std::ostream& os ) const; + + friend std::ostream& operator << ( std::ostream& os, XmlEncode const& xmlEncode ); - // StdErr has two constituent streams in C++, std::cerr and std::clog - // This means that we need to redirect 2 streams into 1 to keep proper - // order of writes and cannot use StreamRedirect on its own - class StdErrRedirect { - public: - StdErrRedirect(std::string& targetString) - :m_cerrBuf( cerr().rdbuf() ), m_clogBuf(clog().rdbuf()), - m_targetString(targetString){ - cerr().rdbuf(m_oss.rdbuf()); - clog().rdbuf(m_oss.rdbuf()); - } - ~StdErrRedirect() { - m_targetString += m_oss.str(); - cerr().rdbuf(m_cerrBuf); - clog().rdbuf(m_clogBuf); - } private: - std::streambuf* m_cerrBuf; - std::streambuf* m_clogBuf; - std::ostringstream m_oss; - std::string& m_targetString; + std::string m_str; + ForWhat m_forWhat; }; - /////////////////////////////////////////////////////////////////////////// - - class RunContext : public IResultCapture, public IRunner { - - RunContext( RunContext const& ); - void operator =( RunContext const& ); - + class XmlWriter { public: - explicit RunContext( Ptr<IConfig const> const& _config, Ptr<IStreamingReporter> const& reporter ) - : m_runInfo( _config->name() ), - m_context( getCurrentMutableContext() ), - m_activeTestCase( CATCH_NULL ), - m_config( _config ), - m_reporter( reporter ), - m_shouldReportUnexpected ( true ) - { - m_context.setRunner( this ); - m_context.setConfig( m_config ); - m_context.setResultCapture( this ); - m_reporter->testRunStarting( m_runInfo ); - } + class ScopedElement { + public: + ScopedElement( XmlWriter* writer, XmlFormatting fmt ); - virtual ~RunContext() { - m_reporter->testRunEnded( TestRunStats( m_runInfo, m_totals, aborting() ) ); - } + ScopedElement( ScopedElement&& other ) noexcept; + ScopedElement& operator=( ScopedElement&& other ) noexcept; - void testGroupStarting( std::string const& testSpec, std::size_t groupIndex, std::size_t groupsCount ) { - m_reporter->testGroupStarting( GroupInfo( testSpec, groupIndex, groupsCount ) ); - } - void testGroupEnded( std::string const& testSpec, Totals const& totals, std::size_t groupIndex, std::size_t groupsCount ) { - m_reporter->testGroupEnded( TestGroupStats( GroupInfo( testSpec, groupIndex, groupsCount ), totals, aborting() ) ); - } + ~ScopedElement(); - Totals runTest( TestCase const& testCase ) { - Totals prevTotals = m_totals; + ScopedElement& writeText( std::string const& text, XmlFormatting fmt = XmlFormatting::Newline | XmlFormatting::Indent ); + + template<typename T> + ScopedElement& writeAttribute( std::string const& name, T const& attribute ) { + m_writer->writeAttribute( name, attribute ); + return *this; + } - std::string redirectedCout; - std::string redirectedCerr; + private: + mutable XmlWriter* m_writer = nullptr; + XmlFormatting m_fmt; + }; - TestCaseInfo testInfo = testCase.getTestCaseInfo(); + XmlWriter( std::ostream& os = Catch::cout() ); + ~XmlWriter(); - m_reporter->testCaseStarting( testInfo ); + XmlWriter( XmlWriter const& ) = delete; + XmlWriter& operator=( XmlWriter const& ) = delete; - m_activeTestCase = &testCase; + XmlWriter& startElement( std::string const& name, XmlFormatting fmt = XmlFormatting::Newline | XmlFormatting::Indent); - do { - ITracker& rootTracker = m_trackerContext.startRun(); - assert( rootTracker.isSectionTracker() ); - static_cast<SectionTracker&>( rootTracker ).addInitialFilters( m_config->getSectionsToRun() ); - do { - m_trackerContext.startCycle(); - m_testCaseTracker = &SectionTracker::acquire( m_trackerContext, TestCaseTracking::NameAndLocation( testInfo.name, testInfo.lineInfo ) ); - runCurrentTest( redirectedCout, redirectedCerr ); - } - while( !m_testCaseTracker->isSuccessfullyCompleted() && !aborting() ); - } - // !TBD: deprecated - this will be replaced by indexed trackers - while( getCurrentContext().advanceGeneratorsForCurrentTest() && !aborting() ); + ScopedElement scopedElement( std::string const& name, XmlFormatting fmt = XmlFormatting::Newline | XmlFormatting::Indent); - Totals deltaTotals = m_totals.delta( prevTotals ); - if( testInfo.expectedToFail() && deltaTotals.testCases.passed > 0 ) { - deltaTotals.assertions.failed++; - deltaTotals.testCases.passed--; - deltaTotals.testCases.failed++; - } - m_totals.testCases += deltaTotals.testCases; - m_reporter->testCaseEnded( TestCaseStats( testInfo, - deltaTotals, - redirectedCout, - redirectedCerr, - aborting() ) ); + XmlWriter& endElement(XmlFormatting fmt = XmlFormatting::Newline | XmlFormatting::Indent); - m_activeTestCase = CATCH_NULL; - m_testCaseTracker = CATCH_NULL; + XmlWriter& writeAttribute( std::string const& name, std::string const& attribute ); - return deltaTotals; - } + XmlWriter& writeAttribute( std::string const& name, bool attribute ); - Ptr<IConfig const> config() const { - return m_config; + template<typename T> + XmlWriter& writeAttribute( std::string const& name, T const& attribute ) { + ReusableStringStream rss; + rss << attribute; + return writeAttribute( name, rss.str() ); } - private: // IResultCapture + XmlWriter& writeText( std::string const& text, XmlFormatting fmt = XmlFormatting::Newline | XmlFormatting::Indent); - virtual void assertionEnded( AssertionResult const& result ) { - if( result.getResultType() == ResultWas::Ok ) { - m_totals.assertions.passed++; - } - else if( !result.isOk() ) { - if( m_activeTestCase->getTestCaseInfo().okToFail() ) - m_totals.assertions.failedButOk++; - else - m_totals.assertions.failed++; - } + XmlWriter& writeComment(std::string const& text, XmlFormatting fmt = XmlFormatting::Newline | XmlFormatting::Indent); - // We have no use for the return value (whether messages should be cleared), because messages were made scoped - // and should be let to clear themselves out. - static_cast<void>(m_reporter->assertionEnded(AssertionStats(result, m_messages, m_totals))); + void writeStylesheetRef( std::string const& url ); - // Reset working state - m_lastAssertionInfo = AssertionInfo( "", m_lastAssertionInfo.lineInfo, "{Unknown expression after the reported line}" , m_lastAssertionInfo.resultDisposition ); - m_lastResult = result; - } + XmlWriter& writeBlankLine(); - virtual bool lastAssertionPassed() - { - return m_totals.assertions.passed == (m_prevPassed + 1); - } + void ensureTagClosed(); - virtual void assertionPassed() - { - m_totals.assertions.passed++; - m_lastAssertionInfo.capturedExpression = "{Unknown expression after the reported line}"; - m_lastAssertionInfo.macroName = ""; - } + private: - virtual void assertionRun() - { - m_prevPassed = m_totals.assertions.passed; - } + void applyFormatting(XmlFormatting fmt); - virtual bool sectionStarted ( - SectionInfo const& sectionInfo, - Counts& assertions - ) - { - ITracker& sectionTracker = SectionTracker::acquire( m_trackerContext, TestCaseTracking::NameAndLocation( sectionInfo.name, sectionInfo.lineInfo ) ); - if( !sectionTracker.isOpen() ) - return false; - m_activeSections.push_back( §ionTracker ); + void writeDeclaration(); - m_lastAssertionInfo.lineInfo = sectionInfo.lineInfo; + void newlineIfNecessary(); - m_reporter->sectionStarting( sectionInfo ); + bool m_tagIsOpen = false; + bool m_needsNewline = false; + std::vector<std::string> m_tags; + std::string m_indent; + std::ostream& m_os; + }; - assertions = m_totals.assertions; +} - return true; - } - bool testForMissingAssertions( Counts& assertions ) { - 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; - } +// end catch_xmlwriter.h +namespace Catch { - virtual void sectionEnded( SectionEndInfo const& endInfo ) { - Counts assertions = m_totals.assertions - endInfo.prevAssertions; - bool missingAssertions = testForMissingAssertions( assertions ); + class JunitReporter : public CumulativeReporterBase<JunitReporter> { + public: + JunitReporter(ReporterConfig const& _config); - if( !m_activeSections.empty() ) { - m_activeSections.back()->close(); - m_activeSections.pop_back(); - } + ~JunitReporter() override; - m_reporter->sectionEnded( SectionStats( endInfo.sectionInfo, assertions, endInfo.durationInSeconds, missingAssertions ) ); - m_messages.clear(); - } + static std::string getDescription(); - virtual void sectionEndedEarly( SectionEndInfo const& endInfo ) { - if( m_unfinishedSections.empty() ) - m_activeSections.back()->fail(); - else - m_activeSections.back()->close(); - m_activeSections.pop_back(); + void noMatchingTestCases(std::string const& /*spec*/) override; - m_unfinishedSections.push_back( endInfo ); - } + void testRunStarting(TestRunInfo const& runInfo) override; - virtual void pushScopedMessage( MessageInfo const& message ) { - m_messages.push_back( message ); - } + void testGroupStarting(GroupInfo const& groupInfo) override; - virtual void popScopedMessage( MessageInfo const& message ) { - m_messages.erase( std::remove( m_messages.begin(), m_messages.end(), message ), m_messages.end() ); - } + void testCaseStarting(TestCaseInfo const& testCaseInfo) override; + bool assertionEnded(AssertionStats const& assertionStats) override; - virtual std::string getCurrentTestName() const { - return m_activeTestCase - ? m_activeTestCase->getTestCaseInfo().name - : std::string(); - } + void testCaseEnded(TestCaseStats const& testCaseStats) override; - virtual const AssertionResult* getLastResult() const { - return &m_lastResult; - } + void testGroupEnded(TestGroupStats const& testGroupStats) override; - virtual void exceptionEarlyReported() { - m_shouldReportUnexpected = false; - } + void testRunEndedCumulative() override; - virtual void handleFatalErrorCondition( std::string const& message ) { - // Don't rebuild the result -- the stringification itself can cause more fatal errors - // Instead, fake a result data. - AssertionResultData tempResult; - tempResult.resultType = ResultWas::FatalErrorCondition; - tempResult.message = message; - AssertionResult result(m_lastAssertionInfo, tempResult); + void writeGroup(TestGroupNode const& groupNode, double suiteTime); - getResultCapture().assertionEnded(result); + void writeTestCase(TestCaseNode const& testCaseNode); - handleUnfinishedSections(); + void writeSection( std::string const& className, + std::string const& rootName, + SectionNode const& sectionNode, + bool testOkToFail ); - // Recreate section for test case (as we will lose the one that was in scope) - TestCaseInfo const& testCaseInfo = m_activeTestCase->getTestCaseInfo(); - SectionInfo testCaseSection( testCaseInfo.lineInfo, testCaseInfo.name, testCaseInfo.description ); + void writeAssertions(SectionNode const& sectionNode); + void writeAssertion(AssertionStats const& stats); - Counts assertions; - assertions.failed = 1; - SectionStats testCaseSectionStats( testCaseSection, assertions, 0, false ); - m_reporter->sectionEnded( testCaseSectionStats ); + XmlWriter xml; + Timer suiteTimer; + std::string stdOutForSuite; + std::string stdErrForSuite; + unsigned int unexpectedExceptions = 0; + bool m_okToFail = false; + }; - TestCaseInfo testInfo = m_activeTestCase->getTestCaseInfo(); +} // end namespace Catch - Totals deltaTotals; - deltaTotals.testCases.failed = 1; - deltaTotals.assertions.failed = 1; - m_reporter->testCaseEnded( TestCaseStats( testInfo, - deltaTotals, - std::string(), - std::string(), - false ) ); - m_totals.testCases.failed++; - testGroupEnded( std::string(), m_totals, 1, 1 ); - m_reporter->testRunEnded( TestRunStats( m_runInfo, m_totals, false ) ); - } +// end catch_reporter_junit.h +// start catch_reporter_xml.h +namespace Catch { + class XmlReporter : public StreamingReporterBase<XmlReporter> { public: - // !TBD We need to do this another way! - bool aborting() const { - return m_totals.assertions.failed == static_cast<std::size_t>( m_config->abortAfter() ); - } + XmlReporter(ReporterConfig const& _config); - private: - - void runCurrentTest( std::string& redirectedCout, std::string& redirectedCerr ) { - TestCaseInfo const& testCaseInfo = m_activeTestCase->getTestCaseInfo(); - SectionInfo testCaseSection( testCaseInfo.lineInfo, testCaseInfo.name, testCaseInfo.description ); - m_reporter->sectionStarting( testCaseSection ); - Counts prevAssertions = m_totals.assertions; - double duration = 0; - m_shouldReportUnexpected = true; - try { - m_lastAssertionInfo = AssertionInfo( "TEST_CASE", testCaseInfo.lineInfo, "", ResultDisposition::Normal ); - - seedRng( *m_config ); - - Timer timer; - timer.start(); - if( m_reporter->getPreferences().shouldRedirectStdOut ) { - StreamRedirect coutRedir( Catch::cout(), redirectedCout ); - StdErrRedirect errRedir( redirectedCerr ); - invokeActiveTestCase(); - } - else { - invokeActiveTestCase(); - } - duration = timer.getElapsedSeconds(); - } - catch( TestFailureException& ) { - // This just means the test was aborted due to failure - } - catch(...) { - // Under CATCH_CONFIG_FAST_COMPILE, unexpected exceptions under REQUIRE assertions - // are reported without translation at the point of origin. - if (m_shouldReportUnexpected) { - makeUnexpectedResultBuilder().useActiveException(); - } - } - m_testCaseTracker->close(); - handleUnfinishedSections(); - m_messages.clear(); + ~XmlReporter() override; - Counts assertions = m_totals.assertions - prevAssertions; - bool missingAssertions = testForMissingAssertions( assertions ); + static std::string getDescription(); - SectionStats testCaseSectionStats( testCaseSection, assertions, duration, missingAssertions ); - m_reporter->sectionEnded( testCaseSectionStats ); - } + virtual std::string getStylesheetRef() const; - void invokeActiveTestCase() { - FatalConditionHandler fatalConditionHandler; // Handle signals - m_activeTestCase->invoke(); - fatalConditionHandler.reset(); - } + void writeSourceInfo(SourceLineInfo const& sourceInfo); - private: + public: // StreamingReporterBase - ResultBuilder makeUnexpectedResultBuilder() const { - return ResultBuilder( m_lastAssertionInfo.macroName, - m_lastAssertionInfo.lineInfo, - m_lastAssertionInfo.capturedExpression, - m_lastAssertionInfo.resultDisposition ); - } + void noMatchingTestCases(std::string const& s) override; - 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<SectionEndInfo>::const_reverse_iterator it = m_unfinishedSections.rbegin(), - itEnd = m_unfinishedSections.rend(); - it != itEnd; - ++it ) - sectionEnded( *it ); - m_unfinishedSections.clear(); - } + void testRunStarting(TestRunInfo const& testInfo) override; - TestRunInfo m_runInfo; - IMutableContext& m_context; - TestCase const* m_activeTestCase; - ITracker* m_testCaseTracker; - ITracker* m_currentSectionTracker; - AssertionResult m_lastResult; + void testGroupStarting(GroupInfo const& groupInfo) override; - Ptr<IConfig const> m_config; - Totals m_totals; - Ptr<IStreamingReporter> m_reporter; - std::vector<MessageInfo> m_messages; - AssertionInfo m_lastAssertionInfo; - std::vector<SectionEndInfo> m_unfinishedSections; - std::vector<ITracker*> m_activeSections; - TrackerContext m_trackerContext; - size_t m_prevPassed; - bool m_shouldReportUnexpected; - }; + void testCaseStarting(TestCaseInfo const& testInfo) override; - IResultCapture& getResultCapture() { - if( IResultCapture* capture = getCurrentContext().getResultCapture() ) - return *capture; - else - throw std::logic_error( "No result capture instance" ); - } + void sectionStarting(SectionInfo const& sectionInfo) override; -} // end namespace Catch + void assertionStarting(AssertionInfo const&) override; -// #included from: internal/catch_version.h -#define TWOBLUECUBES_CATCH_VERSION_H_INCLUDED + bool assertionEnded(AssertionStats const& assertionStats) override; -namespace Catch { + void sectionEnded(SectionStats const& sectionStats) override; - // Versioning information - struct Version { - Version( unsigned int _majorVersion, - unsigned int _minorVersion, - unsigned int _patchNumber, - char const * const _branchName, - unsigned int _buildNumber ); + void testCaseEnded(TestCaseStats const& testCaseStats) override; - unsigned int const majorVersion; - unsigned int const minorVersion; - unsigned int const patchNumber; + void testGroupEnded(TestGroupStats const& testGroupStats) override; - // buildNumber is only used if branchName is not null - char const * const branchName; - unsigned int const buildNumber; + void testRunEnded(TestRunStats const& testRunStats) override; - friend std::ostream& operator << ( std::ostream& os, Version const& version ); +#if defined(CATCH_CONFIG_ENABLE_BENCHMARKING) + void benchmarkPreparing(std::string const& name) override; + void benchmarkStarting(BenchmarkInfo const&) override; + void benchmarkEnded(BenchmarkStats<> const&) override; + void benchmarkFailed(std::string const&) override; +#endif // CATCH_CONFIG_ENABLE_BENCHMARKING private: - void operator=( Version const& ); + Timer m_testCaseTimer; + XmlWriter m_xml; + int m_sectionDepth = 0; }; - inline Version libraryVersion(); -} +} // end namespace Catch -#include <fstream> -#include <stdlib.h> -#include <limits> +// end catch_reporter_xml.h -namespace Catch { +// end catch_external_interfaces.h +#endif - Ptr<IStreamingReporter> createReporter( std::string const& reporterName, Ptr<Config> const& config ) { - Ptr<IStreamingReporter> 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; - } +#if defined(CATCH_CONFIG_ENABLE_BENCHMARKING) +// start catch_benchmarking_all.hpp -#if !defined(CATCH_CONFIG_DEFAULT_REPORTER) -#define CATCH_CONFIG_DEFAULT_REPORTER "console" -#endif +// A proxy header that includes all of the benchmarking headers to allow +// concise include of the benchmarking features. You should prefer the +// individual includes in standard use. - Ptr<IStreamingReporter> makeReporter( Ptr<Config> const& config ) { - std::vector<std::string> reporters = config->getReporterNames(); - if( reporters.empty() ) - reporters.push_back( CATCH_CONFIG_DEFAULT_REPORTER ); +// start catch_benchmark.hpp - Ptr<IStreamingReporter> reporter; - for( std::vector<std::string>::const_iterator it = reporters.begin(), itEnd = reporters.end(); - it != itEnd; - ++it ) - reporter = addReporter( reporter, createReporter( *it, config ) ); - return reporter; - } - Ptr<IStreamingReporter> addListeners( Ptr<IConfig const> const& config, Ptr<IStreamingReporter> 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; - } + // Benchmark - Totals runTests( Ptr<Config> const& config ) { +// start catch_chronometer.hpp - Ptr<IConfig const> iconfig = config.get(); +// User-facing chronometer - Ptr<IStreamingReporter> reporter = makeReporter( config ); - reporter = addListeners( iconfig, reporter ); - RunContext context( iconfig, reporter ); +// start catch_clock.hpp - Totals totals; +// Clocks - context.testGroupStarting( config->name(), 1, 1 ); - TestSpec testSpec = config->testSpec(); - if( !testSpec.hasFilters() ) - testSpec = TestSpecParser( ITagAliasRegistry::get() ).parse( "~[.]" ).testSpec(); // All not hidden tests +#include <chrono> +#include <ratio> - std::vector<TestCase> const& allTestCases = getAllTestCasesSorted( *iconfig ); - for( std::vector<TestCase>::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 ); - } +namespace Catch { + namespace Benchmark { + template <typename Clock> + using ClockDuration = typename Clock::duration; + template <typename Clock> + using FloatDuration = std::chrono::duration<double, typename Clock::period>; - context.testGroupEnded( iconfig->name(), totals, 1, 1 ); - return totals; - } + template <typename Clock> + using TimePoint = typename Clock::time_point; - void applyFilenamesAsTags( IConfig const& config ) { - std::vector<TestCase> const& tests = getAllTestCasesSorted( config ); - for(std::size_t i = 0; i < tests.size(); ++i ) { - TestCase& test = const_cast<TestCase&>( tests[i] ); - std::set<std::string> tags = test.tags; + using default_clock = std::chrono::steady_clock; - 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 ); + template <typename Clock> + struct now { + TimePoint<Clock> operator()() const { + return Clock::now(); + } + }; - std::string::size_type lastDot = filename.find_last_of( '.' ); - if( lastDot != std::string::npos ) - filename = filename.substr( 0, lastDot ); + using fp_seconds = std::chrono::duration<double, std::ratio<1>>; + } // namespace Benchmark +} // namespace Catch - tags.insert( '#' + filename ); - setTags( test, tags ); - } - } +// end catch_clock.hpp +// start catch_optimizer.hpp - class Session : NonCopyable { - static bool alreadyInstantiated; + // Hinting the optimizer - public: - struct OnUnusedOptions { enum DoWhat { Ignore, Fail }; }; +#if defined(_MSC_VER) +# include <atomic> // atomic_thread_fence +#endif - Session() - : m_cli( makeCommandLineParser() ) { - if( alreadyInstantiated ) { - std::string msg = "Only one instance of Catch::Session can ever be used"; - Catch::cerr() << msg << std::endl; - throw std::logic_error( msg ); - } - alreadyInstantiated = true; +namespace Catch { + namespace Benchmark { +#if defined(__GNUC__) || defined(__clang__) + template <typename T> + inline void keep_memory(T* p) { + asm volatile("" : : "g"(p) : "memory"); } - ~Session() { - Catch::cleanUp(); + inline void keep_memory() { + asm volatile("" : : : "memory"); } - void showHelp( std::string const& processName ) { - Catch::cout() << "\nCatch v" << libraryVersion() << "\n"; + namespace Detail { + inline void optimizer_barrier() { keep_memory(); } + } // namespace Detail +#elif defined(_MSC_VER) - m_cli.usage( Catch::cout(), processName ); - Catch::cout() << "For more detail usage please see the project docs\n" << std::endl; - } - void libIdentify() { - Catch::cout() - << std::left << std::setw(16) << "description: " << "A Catch test executable\n" - << std::left << std::setw(16) << "category: " << "testframework\n" - << std::left << std::setw(16) << "framework: " << "Catch Test\n" - << std::left << std::setw(16) << "version: " << libraryVersion() << std::endl; - } - - int applyCommandLine( int argc, char const* const* const argv, OnUnusedOptions::DoWhat unusedOptionBehaviour = OnUnusedOptions::Fail ) { - try { - m_cli.setThrowOnUnrecognisedTokens( unusedOptionBehaviour == OnUnusedOptions::Fail ); - m_unusedTokens = m_cli.parseInto( Clara::argsToVector( argc, argv ), m_configData ); - if( m_configData.showHelp ) - showHelp( m_configData.processName ); - if( m_configData.libIdentify ) - libIdentify(); - m_config.reset(); - } - catch( std::exception& ex ) { - { - Colour colourGuard( Colour::Red ); - Catch::cerr() - << "\nError(s) in input:\n" - << Text( ex.what(), TextAttributes().setIndent(2) ) - << "\n\n"; - } - m_cli.usage( Catch::cout(), m_configData.processName ); - return (std::numeric_limits<int>::max)(); - } - return 0; +#pragma optimize("", off) + template <typename T> + inline void keep_memory(T* p) { + // thanks @milleniumbug + *reinterpret_cast<char volatile*>(p) = *reinterpret_cast<char const volatile*>(p); } + // TODO equivalent keep_memory() +#pragma optimize("", on) - void useConfigData( ConfigData const& _configData ) { - m_configData = _configData; - m_config.reset(); - } + namespace Detail { + inline void optimizer_barrier() { + std::atomic_thread_fence(std::memory_order_seq_cst); + } + } // namespace Detail - int run( int argc, char const* const* const argv ) { +#endif - int returnCode = applyCommandLine( argc, argv ); - if( returnCode == 0 ) - returnCode = run(); - return returnCode; + template <typename T> + inline void deoptimize_value(T&& x) { + keep_memory(&x); } - #if defined(WIN32) && defined(UNICODE) - int run( int argc, wchar_t const* const* const argv ) { + template <typename Fn, typename... Args> + inline auto invoke_deoptimized(Fn&& fn, Args&&... args) -> typename std::enable_if<!std::is_same<void, decltype(fn(args...))>::value>::type { + deoptimize_value(std::forward<Fn>(fn) (std::forward<Args...>(args...))); + } - char **utf8Argv = new char *[ argc ]; + template <typename Fn, typename... Args> + inline auto invoke_deoptimized(Fn&& fn, Args&&... args) -> typename std::enable_if<std::is_same<void, decltype(fn(args...))>::value>::type { + std::forward<Fn>(fn) (std::forward<Args...>(args...)); + } + } // namespace Benchmark +} // namespace Catch - for ( int i = 0; i < argc; ++i ) { - int bufSize = WideCharToMultiByte( CP_UTF8, 0, argv[i], -1, NULL, 0, NULL, NULL ); +// end catch_optimizer.hpp +// start catch_complete_invoke.hpp - utf8Argv[ i ] = new char[ bufSize ]; +// Invoke with a special case for void - WideCharToMultiByte( CP_UTF8, 0, argv[i], -1, utf8Argv[i], bufSize, NULL, NULL ); - } - int returnCode = applyCommandLine( argc, utf8Argv ); - if( returnCode == 0 ) - returnCode = run(); +#include <type_traits> +#include <utility> - for ( int i = 0; i < argc; ++i ) - delete [] utf8Argv[ i ]; +namespace Catch { + namespace Benchmark { + namespace Detail { + template <typename T> + struct CompleteType { using type = T; }; + template <> + struct CompleteType<void> { struct type {}; }; + + template <typename T> + using CompleteType_t = typename CompleteType<T>::type; + + template <typename Result> + struct CompleteInvoker { + template <typename Fun, typename... Args> + static Result invoke(Fun&& fun, Args&&... args) { + return std::forward<Fun>(fun)(std::forward<Args>(args)...); + } + }; + template <> + struct CompleteInvoker<void> { + template <typename Fun, typename... Args> + static CompleteType_t<void> invoke(Fun&& fun, Args&&... args) { + std::forward<Fun>(fun)(std::forward<Args>(args)...); + return {}; + } + }; - delete [] utf8Argv; + // invoke and not return void :( + template <typename Fun, typename... Args> + CompleteType_t<FunctionReturnType<Fun, Args...>> complete_invoke(Fun&& fun, Args&&... args) { + return CompleteInvoker<FunctionReturnType<Fun, Args...>>::invoke(std::forward<Fun>(fun), std::forward<Args>(args)...); + } - return returnCode; - } - #endif + const std::string benchmarkErrorMsg = "a benchmark failed to run successfully"; + } // namespace Detail - int run() { - if( ( m_configData.waitForKeypress & WaitForKeypress::BeforeStart ) != 0 ) { - Catch::cout() << "...waiting for enter/ return before starting" << std::endl; - static_cast<void>(std::getchar()); + template <typename Fun> + Detail::CompleteType_t<FunctionReturnType<Fun>> user_code(Fun&& fun) { + CATCH_TRY{ + return Detail::complete_invoke(std::forward<Fun>(fun)); + } CATCH_CATCH_ALL{ + getResultCapture().benchmarkFailed(translateActiveException()); + CATCH_RUNTIME_ERROR(Detail::benchmarkErrorMsg); } - int exitCode = runInternal(); - if( ( m_configData.waitForKeypress & WaitForKeypress::BeforeExit ) != 0 ) { - Catch::cout() << "...waiting for enter/ return before exiting, with code: " << exitCode << std::endl; - static_cast<void>(std::getchar()); - } - return exitCode; } + } // namespace Benchmark +} // namespace Catch - Clara::CommandLine<ConfigData> const& cli() const { - return m_cli; - } - std::vector<Clara::Parser::Token> const& unusedTokens() const { - return m_unusedTokens; - } - ConfigData& configData() { - return m_configData; - } - Config& config() { - if( !m_config ) - m_config = new Config( m_configData ); - return *m_config; - } - private: +// end catch_complete_invoke.hpp +namespace Catch { + namespace Benchmark { + namespace Detail { + struct ChronometerConcept { + virtual void start() = 0; + virtual void finish() = 0; + virtual ~ChronometerConcept() = default; + }; + template <typename Clock> + struct ChronometerModel final : public ChronometerConcept { + void start() override { started = Clock::now(); } + void finish() override { finished = Clock::now(); } - int runInternal() { - if( m_configData.showHelp || m_configData.libIdentify ) - return 0; + ClockDuration<Clock> elapsed() const { return finished - started; } - try - { - config(); // Force config to be constructed + TimePoint<Clock> started; + TimePoint<Clock> finished; + }; + } // namespace Detail - seedRng( *m_config ); + struct Chronometer { + public: + template <typename Fun> + void measure(Fun&& fun) { measure(std::forward<Fun>(fun), is_callable<Fun(int)>()); } - if( m_configData.filenamesAsTags ) - applyFilenamesAsTags( *m_config ); + int runs() const { return k; } - // Handle list request - if( Option<std::size_t> listed = list( config() ) ) - return static_cast<int>( *listed ); + Chronometer(Detail::ChronometerConcept& meter, int k) + : impl(&meter) + , k(k) {} - return static_cast<int>( runTests( m_config ).assertions.failed ); - } - catch( std::exception& ex ) { - Catch::cerr() << ex.what() << std::endl; - return (std::numeric_limits<int>::max)(); + private: + template <typename Fun> + void measure(Fun&& fun, std::false_type) { + measure([&fun](int) { return fun(); }, std::true_type()); } - } - Clara::CommandLine<ConfigData> m_cli; - std::vector<Clara::Parser::Token> m_unusedTokens; - ConfigData m_configData; - Ptr<Config> m_config; - }; - - bool Session::alreadyInstantiated = false; + template <typename Fun> + void measure(Fun&& fun, std::true_type) { + Detail::optimizer_barrier(); + impl->start(); + for (int i = 0; i < k; ++i) invoke_deoptimized(fun, i); + impl->finish(); + Detail::optimizer_barrier(); + } -} // end namespace Catch + Detail::ChronometerConcept* impl; + int k; + }; + } // namespace Benchmark +} // namespace Catch -// #included from: catch_registry_hub.hpp -#define TWOBLUECUBES_CATCH_REGISTRY_HUB_HPP_INCLUDED +// end catch_chronometer.hpp +// start catch_environment.hpp -// #included from: catch_test_case_registry_impl.hpp -#define TWOBLUECUBES_CATCH_TEST_CASE_REGISTRY_IMPL_HPP_INCLUDED +// Environment information -#include <vector> -#include <set> -#include <sstream> -#include <algorithm> namespace Catch { + namespace Benchmark { + template <typename Duration> + struct EnvironmentEstimate { + Duration mean; + OutlierClassification outliers; + + template <typename Duration2> + operator EnvironmentEstimate<Duration2>() const { + return { mean, outliers }; + } + }; + template <typename Clock> + struct Environment { + using clock_type = Clock; + EnvironmentEstimate<FloatDuration<Clock>> clock_resolution; + EnvironmentEstimate<FloatDuration<Clock>> clock_cost; + }; + } // namespace Benchmark +} // namespace Catch - struct RandomNumberGenerator { - typedef unsigned int result_type; +// end catch_environment.hpp +// start catch_execution_plan.hpp - result_type operator()( result_type n ) const { return std::rand() % n; } + // Execution plan -#ifdef CATCH_CONFIG_CPP11_SHUFFLE - static constexpr result_type (min)() { return 0; } - static constexpr result_type (max)() { return 1000000; } - result_type operator()() const { return std::rand() % (max)(); } -#endif - template<typename V> - static void shuffle( V& vector ) { - RandomNumberGenerator rng; -#ifdef CATCH_CONFIG_CPP11_SHUFFLE - std::shuffle( vector.begin(), vector.end(), rng ); -#else - std::random_shuffle( vector.begin(), vector.end(), rng ); -#endif - } - }; - inline std::vector<TestCase> sortTests( IConfig const& config, std::vector<TestCase> const& unsortedTestCases ) { +// start catch_benchmark_function.hpp - std::vector<TestCase> sorted = unsortedTestCases; + // Dumb std::function implementation for consistent call overhead - switch( config.runOrder() ) { - case RunTests::InLexicographicalOrder: - std::sort( sorted.begin(), sorted.end() ); - break; - case RunTests::InRandomOrder: - { - seedRng( config ); - RandomNumberGenerator::shuffle( sorted ); - } - 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<TestCase> const& functions ) { - std::set<TestCase> seenFunctions; - for( std::vector<TestCase>::const_iterator it = functions.begin(), itEnd = functions.end(); - it != itEnd; - ++it ) { - std::pair<std::set<TestCase>::const_iterator, bool> prev = seenFunctions.insert( *it ); - if( !prev.second ) { - std::ostringstream ss; +#include <cassert> +#include <type_traits> +#include <utility> +#include <memory> - ss << 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; +namespace Catch { + namespace Benchmark { + namespace Detail { + template <typename T> + using Decay = typename std::decay<T>::type; + template <typename T, typename U> + struct is_related + : std::is_same<Decay<T>, Decay<U>> {}; + + /// We need to reinvent std::function because every piece of code that might add overhead + /// in a measurement context needs to have consistent performance characteristics so that we + /// can account for it in the measurement. + /// Implementations of std::function with optimizations that aren't always applicable, like + /// small buffer optimizations, are not uncommon. + /// This is effectively an implementation of std::function without any such optimizations; + /// it may be slow, but it is consistently slow. + struct BenchmarkFunction { + private: + struct callable { + virtual void call(Chronometer meter) const = 0; + virtual callable* clone() const = 0; + virtual ~callable() = default; + }; + template <typename Fun> + struct model : public callable { + model(Fun&& fun) : fun(std::move(fun)) {} + model(Fun const& fun) : fun(fun) {} + + model<Fun>* clone() const override { return new model<Fun>(*this); } + + void call(Chronometer meter) const override { + call(meter, is_callable<Fun(Chronometer)>()); + } + void call(Chronometer meter, std::true_type) const { + fun(meter); + } + void call(Chronometer meter, std::false_type) const { + meter.measure(fun); + } - throw std::runtime_error(ss.str()); - } - } - } + Fun fun; + }; - std::vector<TestCase> filterTests( std::vector<TestCase> const& testCases, TestSpec const& testSpec, IConfig const& config ) { - std::vector<TestCase> filtered; - filtered.reserve( testCases.size() ); - for( std::vector<TestCase>::const_iterator it = testCases.begin(), itEnd = testCases.end(); - it != itEnd; - ++it ) - if( matchTest( *it, testSpec, config ) ) - filtered.push_back( *it ); - return filtered; - } - std::vector<TestCase> const& getAllTestCasesSorted( IConfig const& config ) { - return getRegistryHub().getTestCaseRegistry().getAllTestsSorted( config ); - } + struct do_nothing { void operator()() const {} }; - class TestRegistry : public ITestCaseRegistry { - public: - TestRegistry() - : m_currentSortOrder( RunTests::InDeclarationOrder ), - m_unnamedCount( 0 ) - {} - virtual ~TestRegistry(); + template <typename T> + BenchmarkFunction(model<T>* c) : f(c) {} - virtual void registerTest( TestCase const& testCase ) { - std::string name = testCase.getTestCaseInfo().name; - if( name.empty() ) { - std::ostringstream oss; - oss << "Anonymous test case " << ++m_unnamedCount; - return registerTest( testCase.withName( oss.str() ) ); - } - m_functions.push_back( testCase ); - } + public: + BenchmarkFunction() + : f(new model<do_nothing>{ {} }) {} - virtual std::vector<TestCase> const& getAllTests() const { - return m_functions; - } - virtual std::vector<TestCase> const& getAllTestsSorted( IConfig const& config ) const { - if( m_sortedFunctions.empty() ) - enforceNoDuplicateTestCases( m_functions ); + template <typename Fun, + typename std::enable_if<!is_related<Fun, BenchmarkFunction>::value, int>::type = 0> + BenchmarkFunction(Fun&& fun) + : f(new model<typename std::decay<Fun>::type>(std::forward<Fun>(fun))) {} - if( m_currentSortOrder != config.runOrder() || m_sortedFunctions.empty() ) { - m_sortedFunctions = sortTests( config, m_functions ); - m_currentSortOrder = config.runOrder(); - } - return m_sortedFunctions; - } + BenchmarkFunction(BenchmarkFunction&& that) + : f(std::move(that.f)) {} - private: - std::vector<TestCase> m_functions; - mutable RunTests::InWhatOrder m_currentSortOrder; - mutable std::vector<TestCase> m_sortedFunctions; - size_t m_unnamedCount; - std::ios_base::Init m_ostreamInit; // Forces cout/ cerr to be initialised - }; + BenchmarkFunction(BenchmarkFunction const& that) + : f(that.f->clone()) {} - /////////////////////////////////////////////////////////////////////////// + BenchmarkFunction& operator=(BenchmarkFunction&& that) { + f = std::move(that.f); + return *this; + } - class FreeFunctionTestCase : public SharedImpl<ITestCase> { - public: + BenchmarkFunction& operator=(BenchmarkFunction const& that) { + f.reset(that.f->clone()); + return *this; + } - FreeFunctionTestCase( TestFunction fun ) : m_fun( fun ) {} + void operator()(Chronometer meter) const { f->call(meter); } - virtual void invoke() const { - m_fun(); - } + private: + std::unique_ptr<callable> f; + }; + } // namespace Detail + } // namespace Benchmark +} // namespace Catch - private: - virtual ~FreeFunctionTestCase(); +// end catch_benchmark_function.hpp +// start catch_repeat.hpp - TestFunction m_fun; - }; +// repeat algorithm - inline std::string extractClassName( std::string const& classOrQualifiedMethodName ) { - std::string className = classOrQualifiedMethodName; - if( startsWith( className, '&' ) ) - { - std::size_t lastColons = className.rfind( "::" ); - std::size_t penultimateColons = className.rfind( "::", lastColons-1 ); - if( penultimateColons == std::string::npos ) - penultimateColons = 1; - className = className.substr( penultimateColons, lastColons-penultimateColons ); - } - return className; - } - void registerTestCase - ( ITestCase* testCase, - char const* classOrQualifiedMethodName, - NameAndDesc const& nameAndDesc, - SourceLineInfo const& lineInfo ) { +#include <type_traits> +#include <utility> - 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 ); - } +namespace Catch { + namespace Benchmark { + namespace Detail { + template <typename Fun> + struct repeater { + void operator()(int k) const { + for (int i = 0; i < k; ++i) { + fun(); + } + } + Fun fun; + }; + template <typename Fun> + repeater<typename std::decay<Fun>::type> repeat(Fun&& fun) { + return { std::forward<Fun>(fun) }; + } + } // namespace Detail + } // namespace Benchmark +} // namespace Catch - /////////////////////////////////////////////////////////////////////////// +// end catch_repeat.hpp +// start catch_run_for_at_least.hpp - AutoReg::AutoReg - ( TestFunction function, - SourceLineInfo const& lineInfo, - NameAndDesc const& nameAndDesc ) { - registerTestCaseFunction( function, lineInfo, nameAndDesc ); - } +// Run a function for a minimum amount of time - AutoReg::~AutoReg() {} -} // end namespace Catch +// start catch_measure.hpp -// #included from: catch_reporter_registry.hpp -#define TWOBLUECUBES_CATCH_REPORTER_REGISTRY_HPP_INCLUDED +// Measure -#include <map> -namespace Catch { +// start catch_timing.hpp - class ReporterRegistry : public IReporterRegistry { +// Timing - public: - virtual ~ReporterRegistry() CATCH_OVERRIDE {} - - virtual IStreamingReporter* create( std::string const& name, Ptr<IConfig const> const& config ) const CATCH_OVERRIDE { - FactoryMap::const_iterator it = m_factories.find( name ); - if( it == m_factories.end() ) - return CATCH_NULL; - return it->second->create( ReporterConfig( config ) ); - } - - void registerReporter( std::string const& name, Ptr<IReporterFactory> const& factory ) { - m_factories.insert( std::make_pair( name, factory ) ); - } - void registerListener( Ptr<IReporterFactory> const& factory ) { - m_listeners.push_back( factory ); - } +#include <tuple> +#include <type_traits> - virtual FactoryMap const& getFactories() const CATCH_OVERRIDE { - return m_factories; - } - virtual Listeners const& getListeners() const CATCH_OVERRIDE { - return m_listeners; - } +namespace Catch { + namespace Benchmark { + template <typename Duration, typename Result> + struct Timing { + Duration elapsed; + Result result; + int iterations; + }; + template <typename Clock, typename Func, typename... Args> + using TimingOf = Timing<ClockDuration<Clock>, Detail::CompleteType_t<FunctionReturnType<Func, Args...>>>; + } // namespace Benchmark +} // namespace Catch - private: - FactoryMap m_factories; - Listeners m_listeners; - }; -} +// end catch_timing.hpp +#include <utility> -// #included from: catch_exception_translator_registry.hpp -#define TWOBLUECUBES_CATCH_EXCEPTION_TRANSLATOR_REGISTRY_HPP_INCLUDED +namespace Catch { + namespace Benchmark { + namespace Detail { + template <typename Clock, typename Fun, typename... Args> + TimingOf<Clock, Fun, Args...> measure(Fun&& fun, Args&&... args) { + auto start = Clock::now(); + auto&& r = Detail::complete_invoke(fun, std::forward<Args>(args)...); + auto end = Clock::now(); + auto delta = end - start; + return { delta, std::forward<decltype(r)>(r), 1 }; + } + } // namespace Detail + } // namespace Benchmark +} // namespace Catch -#ifdef __OBJC__ -#import "Foundation/Foundation.h" -#endif +// end catch_measure.hpp +#include <utility> +#include <type_traits> namespace Catch { + namespace Benchmark { + namespace Detail { + template <typename Clock, typename Fun> + TimingOf<Clock, Fun, int> measure_one(Fun&& fun, int iters, std::false_type) { + return Detail::measure<Clock>(fun, iters); + } + template <typename Clock, typename Fun> + TimingOf<Clock, Fun, Chronometer> measure_one(Fun&& fun, int iters, std::true_type) { + Detail::ChronometerModel<Clock> meter; + auto&& result = Detail::complete_invoke(fun, Chronometer(meter, iters)); - class ExceptionTranslatorRegistry : public IExceptionTranslatorRegistry { - public: - ~ExceptionTranslatorRegistry() { - deleteAll( m_translators ); - } + return { meter.elapsed(), std::move(result), iters }; + } - virtual void registerTranslator( const IExceptionTranslator* translator ) { - m_translators.push_back( translator ); - } + template <typename Clock, typename Fun> + using run_for_at_least_argument_t = typename std::conditional<is_callable<Fun(Chronometer)>::value, Chronometer, int>::type; - virtual std::string translateActiveException() const { - try { -#ifdef __OBJC__ - // In Objective-C try objective-c exceptions first - @try { - return tryTranslators(); + struct optimized_away_error : std::exception { + const char* what() const noexcept override { + return "could not measure benchmark, maybe it was optimized away"; } - @catch (NSException *exception) { - return Catch::toString( [exception description] ); + }; + + template <typename Clock, typename Fun> + TimingOf<Clock, Fun, run_for_at_least_argument_t<Clock, Fun>> run_for_at_least(ClockDuration<Clock> how_long, int seed, Fun&& fun) { + auto iters = seed; + while (iters < (1 << 30)) { + auto&& Timing = measure_one<Clock>(fun, iters, is_callable<Fun(Chronometer)>()); + + if (Timing.elapsed >= how_long) { + return { Timing.elapsed, std::move(Timing.result), iters }; + } + iters *= 2; } -#else - return tryTranslators(); -#endif - } - catch( TestFailureException& ) { - throw; - } - catch( std::exception& ex ) { - return ex.what(); + Catch::throw_exception(optimized_away_error{}); } - catch( std::string& msg ) { - return msg; - } - catch( const char* msg ) { - return msg; - } - catch(...) { - return "Unknown exception"; + } // namespace Detail + } // namespace Benchmark +} // namespace Catch + +// end catch_run_for_at_least.hpp +#include <algorithm> +#include <iterator> + +namespace Catch { + namespace Benchmark { + template <typename Duration> + struct ExecutionPlan { + int iterations_per_sample; + Duration estimated_duration; + Detail::BenchmarkFunction benchmark; + Duration warmup_time; + int warmup_iterations; + + template <typename Duration2> + operator ExecutionPlan<Duration2>() const { + return { iterations_per_sample, estimated_duration, benchmark, warmup_time, warmup_iterations }; } - } - std::string tryTranslators() const { - if( m_translators.empty() ) - throw; - else - return m_translators[0]->translate( m_translators.begin()+1, m_translators.end() ); - } + template <typename Clock> + std::vector<FloatDuration<Clock>> run(const IConfig &cfg, Environment<FloatDuration<Clock>> env) const { + // warmup a bit + Detail::run_for_at_least<Clock>(std::chrono::duration_cast<ClockDuration<Clock>>(warmup_time), warmup_iterations, Detail::repeat(now<Clock>{})); + + std::vector<FloatDuration<Clock>> times; + times.reserve(cfg.benchmarkSamples()); + std::generate_n(std::back_inserter(times), cfg.benchmarkSamples(), [this, env] { + Detail::ChronometerModel<Clock> model; + this->benchmark(Chronometer(model, iterations_per_sample)); + auto sample_time = model.elapsed() - env.clock_cost.mean; + if (sample_time < FloatDuration<Clock>::zero()) sample_time = FloatDuration<Clock>::zero(); + return sample_time / iterations_per_sample; + }); + return times; + } + }; + } // namespace Benchmark +} // namespace Catch - private: - std::vector<const IExceptionTranslator*> m_translators; - }; -} +// end catch_execution_plan.hpp +// start catch_estimate_clock.hpp -// #included from: catch_tag_alias_registry.h -#define TWOBLUECUBES_CATCH_TAG_ALIAS_REGISTRY_H_INCLUDED + // Environment measurement -#include <map> -namespace Catch { +// start catch_stats.hpp - class TagAliasRegistry : public ITagAliasRegistry { - public: - virtual ~TagAliasRegistry(); - virtual Option<TagAlias> find( std::string const& alias ) const; - virtual std::string expandAliases( std::string const& unexpandedTestSpec ) const; - void add( std::string const& alias, std::string const& tag, SourceLineInfo const& lineInfo ); +// Statistical analysis tools - private: - std::map<std::string, TagAlias> m_registry; - }; -} // end namespace Catch +#include <algorithm> +#include <functional> +#include <vector> +#include <iterator> +#include <numeric> +#include <tuple> +#include <cmath> +#include <utility> +#include <cstddef> +#include <random> namespace Catch { + namespace Benchmark { + namespace Detail { + using sample = std::vector<double>; + + double weighted_average_quantile(int k, int q, std::vector<double>::iterator first, std::vector<double>::iterator last); + + template <typename Iterator> + OutlierClassification classify_outliers(Iterator first, Iterator last) { + std::vector<double> copy(first, last); + + auto q1 = weighted_average_quantile(1, 4, copy.begin(), copy.end()); + auto q3 = weighted_average_quantile(3, 4, copy.begin(), copy.end()); + auto iqr = q3 - q1; + auto los = q1 - (iqr * 3.); + auto lom = q1 - (iqr * 1.5); + auto him = q3 + (iqr * 1.5); + auto his = q3 + (iqr * 3.); + + OutlierClassification o; + for (; first != last; ++first) { + auto&& t = *first; + if (t < los) ++o.low_severe; + else if (t < lom) ++o.low_mild; + else if (t > his) ++o.high_severe; + else if (t > him) ++o.high_mild; + ++o.samples_seen; + } + return o; + } - namespace { + template <typename Iterator> + double mean(Iterator first, Iterator last) { + auto count = last - first; + double sum = std::accumulate(first, last, 0.); + return sum / count; + } - class RegistryHub : public IRegistryHub, public IMutableRegistryHub { + template <typename URng, typename Iterator, typename Estimator> + sample resample(URng& rng, int resamples, Iterator first, Iterator last, Estimator& estimator) { + auto n = last - first; + std::uniform_int_distribution<decltype(n)> dist(0, n - 1); + + sample out; + out.reserve(resamples); + std::generate_n(std::back_inserter(out), resamples, [n, first, &estimator, &dist, &rng] { + std::vector<double> resampled; + resampled.reserve(n); + std::generate_n(std::back_inserter(resampled), n, [first, &dist, &rng] { return first[dist(rng)]; }); + return estimator(resampled.begin(), resampled.end()); + }); + std::sort(out.begin(), out.end()); + return out; + } - RegistryHub( RegistryHub const& ); - void operator=( RegistryHub const& ); + template <typename Estimator, typename Iterator> + sample jackknife(Estimator&& estimator, Iterator first, Iterator last) { + auto n = last - first; + auto second = std::next(first); + sample results; + results.reserve(n); - public: // IRegistryHub - RegistryHub() { - } - virtual IReporterRegistry const& getReporterRegistry() const CATCH_OVERRIDE { - return m_reporterRegistry; - } - virtual ITestCaseRegistry const& getTestCaseRegistry() const CATCH_OVERRIDE { - return m_testCaseRegistry; - } - virtual IExceptionTranslatorRegistry& getExceptionTranslatorRegistry() CATCH_OVERRIDE { - return m_exceptionTranslatorRegistry; + for (auto it = first; it != last; ++it) { + std::iter_swap(it, first); + results.push_back(estimator(second, last)); + } + + return results; } - virtual ITagAliasRegistry const& getTagAliasRegistry() const CATCH_OVERRIDE { - return m_tagAliasRegistry; + + inline double normal_cdf(double x) { + return std::erfc(-x / std::sqrt(2.0)) / 2.0; } - public: // IMutableRegistryHub - virtual void registerReporter( std::string const& name, Ptr<IReporterFactory> const& factory ) CATCH_OVERRIDE { - m_reporterRegistry.registerReporter( name, factory ); + double erfc_inv(double x); + + double normal_quantile(double p); + + template <typename Iterator, typename Estimator> + Estimate<double> bootstrap(double confidence_level, Iterator first, Iterator last, sample const& resample, Estimator&& estimator) { + auto n_samples = last - first; + + double point = estimator(first, last); + // Degenerate case with a single sample + if (n_samples == 1) return { point, point, point, confidence_level }; + + sample jack = jackknife(estimator, first, last); + double jack_mean = mean(jack.begin(), jack.end()); + double sum_squares, sum_cubes; + std::tie(sum_squares, sum_cubes) = std::accumulate(jack.begin(), jack.end(), std::make_pair(0., 0.), [jack_mean](std::pair<double, double> sqcb, double x) -> std::pair<double, double> { + auto d = jack_mean - x; + auto d2 = d * d; + auto d3 = d2 * d; + return { sqcb.first + d2, sqcb.second + d3 }; + }); + + double accel = sum_cubes / (6 * std::pow(sum_squares, 1.5)); + int n = static_cast<int>(resample.size()); + double prob_n = std::count_if(resample.begin(), resample.end(), [point](double x) { return x < point; }) / (double)n; + // degenerate case with uniform samples + if (prob_n == 0) return { point, point, point, confidence_level }; + + double bias = normal_quantile(prob_n); + double z1 = normal_quantile((1. - confidence_level) / 2.); + + auto cumn = [n](double x) -> int { + return std::lround(normal_cdf(x) * n); }; + auto a = [bias, accel](double b) { return bias + b / (1. - accel * b); }; + double b1 = bias + z1; + double b2 = bias - z1; + double a1 = a(b1); + double a2 = a(b2); + auto lo = (std::max)(cumn(a1), 0); + auto hi = (std::min)(cumn(a2), n - 1); + + return { point, resample[lo], resample[hi], confidence_level }; } - virtual void registerListener( Ptr<IReporterFactory> const& factory ) CATCH_OVERRIDE { - m_reporterRegistry.registerListener( factory ); + + double outlier_variance(Estimate<double> mean, Estimate<double> stddev, int n); + + struct bootstrap_analysis { + Estimate<double> mean; + Estimate<double> standard_deviation; + double outlier_variance; + }; + + bootstrap_analysis analyse_samples(double confidence_level, int n_resamples, std::vector<double>::iterator first, std::vector<double>::iterator last); + } // namespace Detail + } // namespace Benchmark +} // namespace Catch + +// end catch_stats.hpp +#include <algorithm> +#include <iterator> +#include <tuple> +#include <vector> +#include <cmath> + +namespace Catch { + namespace Benchmark { + namespace Detail { + template <typename Clock> + std::vector<double> resolution(int k) { + std::vector<TimePoint<Clock>> times; + times.reserve(k + 1); + std::generate_n(std::back_inserter(times), k + 1, now<Clock>{}); + + std::vector<double> deltas; + deltas.reserve(k); + std::transform(std::next(times.begin()), times.end(), times.begin(), + std::back_inserter(deltas), + [](TimePoint<Clock> a, TimePoint<Clock> b) { return static_cast<double>((a - b).count()); }); + + return deltas; } - virtual void registerTest( TestCase const& testInfo ) CATCH_OVERRIDE { - m_testCaseRegistry.registerTest( testInfo ); + + const auto warmup_iterations = 10000; + const auto warmup_time = std::chrono::milliseconds(100); + const auto minimum_ticks = 1000; + const auto warmup_seed = 10000; + const auto clock_resolution_estimation_time = std::chrono::milliseconds(500); + const auto clock_cost_estimation_time_limit = std::chrono::seconds(1); + const auto clock_cost_estimation_tick_limit = 100000; + const auto clock_cost_estimation_time = std::chrono::milliseconds(10); + const auto clock_cost_estimation_iterations = 10000; + + template <typename Clock> + int warmup() { + return run_for_at_least<Clock>(std::chrono::duration_cast<ClockDuration<Clock>>(warmup_time), warmup_seed, &resolution<Clock>) + .iterations; } - virtual void registerTranslator( const IExceptionTranslator* translator ) CATCH_OVERRIDE { - m_exceptionTranslatorRegistry.registerTranslator( translator ); + template <typename Clock> + EnvironmentEstimate<FloatDuration<Clock>> estimate_clock_resolution(int iterations) { + auto r = run_for_at_least<Clock>(std::chrono::duration_cast<ClockDuration<Clock>>(clock_resolution_estimation_time), iterations, &resolution<Clock>) + .result; + return { + FloatDuration<Clock>(mean(r.begin(), r.end())), + classify_outliers(r.begin(), r.end()), + }; } - virtual void registerTagAlias( std::string const& alias, std::string const& tag, SourceLineInfo const& lineInfo ) CATCH_OVERRIDE { - m_tagAliasRegistry.add( alias, tag, lineInfo ); + template <typename Clock> + EnvironmentEstimate<FloatDuration<Clock>> estimate_clock_cost(FloatDuration<Clock> resolution) { + auto time_limit = (std::min)( + resolution * clock_cost_estimation_tick_limit, + FloatDuration<Clock>(clock_cost_estimation_time_limit)); + auto time_clock = [](int k) { + return Detail::measure<Clock>([k] { + for (int i = 0; i < k; ++i) { + volatile auto ignored = Clock::now(); + (void)ignored; + } + }).elapsed; + }; + time_clock(1); + int iters = clock_cost_estimation_iterations; + auto&& r = run_for_at_least<Clock>(std::chrono::duration_cast<ClockDuration<Clock>>(clock_cost_estimation_time), iters, time_clock); + std::vector<double> times; + int nsamples = static_cast<int>(std::ceil(time_limit / r.elapsed)); + times.reserve(nsamples); + std::generate_n(std::back_inserter(times), nsamples, [time_clock, &r] { + return static_cast<double>((time_clock(r.iterations) / r.iterations).count()); + }); + return { + FloatDuration<Clock>(mean(times.begin(), times.end())), + classify_outliers(times.begin(), times.end()), + }; } - private: - TestRegistry m_testCaseRegistry; - ReporterRegistry m_reporterRegistry; - ExceptionTranslatorRegistry m_exceptionTranslatorRegistry; - TagAliasRegistry m_tagAliasRegistry; - }; - - // Single, global, instance - inline RegistryHub*& getTheRegistryHub() { - static RegistryHub* theRegistryHub = CATCH_NULL; - if( !theRegistryHub ) - theRegistryHub = new RegistryHub(); - return theRegistryHub; - } - } - - IRegistryHub& getRegistryHub() { - return *getTheRegistryHub(); - } - IMutableRegistryHub& getMutableRegistryHub() { - return *getTheRegistryHub(); - } - void cleanUp() { - delete getTheRegistryHub(); - getTheRegistryHub() = CATCH_NULL; - cleanUpContext(); - } - std::string translateActiveException() { - return getRegistryHub().getExceptionTranslatorRegistry().translateActiveException(); - } - -} // end namespace Catch + template <typename Clock> + Environment<FloatDuration<Clock>> measure_environment() { + static Environment<FloatDuration<Clock>>* env = nullptr; + if (env) { + return *env; + } -// #included from: catch_notimplemented_exception.hpp -#define TWOBLUECUBES_CATCH_NOTIMPLEMENTED_EXCEPTION_HPP_INCLUDED + auto iters = Detail::warmup<Clock>(); + auto resolution = Detail::estimate_clock_resolution<Clock>(iters); + auto cost = Detail::estimate_clock_cost<Clock>(resolution.mean); -#include <sstream> + env = new Environment<FloatDuration<Clock>>{ resolution, cost }; + return *env; + } + } // namespace Detail + } // namespace Benchmark +} // namespace Catch -namespace Catch { +// end catch_estimate_clock.hpp +// start catch_analyse.hpp - NotImplementedException::NotImplementedException( SourceLineInfo const& lineInfo ) - : m_lineInfo( lineInfo ) { - std::ostringstream oss; - oss << lineInfo << ": function "; - oss << "not implemented"; - m_what = oss.str(); - } + // Run and analyse one benchmark - const char* NotImplementedException::what() const CATCH_NOEXCEPT { - return m_what.c_str(); - } -} // end namespace Catch +// start catch_sample_analysis.hpp -// #included from: catch_context_impl.hpp -#define TWOBLUECUBES_CATCH_CONTEXT_IMPL_HPP_INCLUDED +// Benchmark results -// #included from: catch_stream.hpp -#define TWOBLUECUBES_CATCH_STREAM_HPP_INCLUDED -#include <stdexcept> -#include <cstdio> -#include <iostream> +#include <algorithm> +#include <vector> +#include <string> +#include <iterator> namespace Catch { + namespace Benchmark { + template <typename Duration> + struct SampleAnalysis { + std::vector<Duration> samples; + Estimate<Duration> mean; + Estimate<Duration> standard_deviation; + OutlierClassification outliers; + double outlier_variance; + + template <typename Duration2> + operator SampleAnalysis<Duration2>() const { + std::vector<Duration2> samples2; + samples2.reserve(samples.size()); + std::transform(samples.begin(), samples.end(), std::back_inserter(samples2), [](Duration d) { return Duration2(d); }); + return { + std::move(samples2), + mean, + standard_deviation, + outliers, + outlier_variance, + }; + } + }; + } // namespace Benchmark +} // namespace Catch - template<typename WriterF, size_t bufferSize=256> - class StreamBufImpl : public StreamBufBase { - char data[bufferSize]; - WriterF m_writer; - - public: - StreamBufImpl() { - setp( data, data + sizeof(data) ); - } +// end catch_sample_analysis.hpp +#include <algorithm> +#include <iterator> +#include <vector> - ~StreamBufImpl() CATCH_NOEXCEPT { - sync(); - } +namespace Catch { + namespace Benchmark { + namespace Detail { + template <typename Duration, typename Iterator> + SampleAnalysis<Duration> analyse(const IConfig &cfg, Environment<Duration>, Iterator first, Iterator last) { + if (!cfg.benchmarkNoAnalysis()) { + std::vector<double> samples; + samples.reserve(last - first); + std::transform(first, last, std::back_inserter(samples), [](Duration d) { return d.count(); }); + + auto analysis = Catch::Benchmark::Detail::analyse_samples(cfg.benchmarkConfidenceInterval(), cfg.benchmarkResamples(), samples.begin(), samples.end()); + auto outliers = Catch::Benchmark::Detail::classify_outliers(samples.begin(), samples.end()); + + auto wrap_estimate = [](Estimate<double> e) { + return Estimate<Duration> { + Duration(e.point), + Duration(e.lower_bound), + Duration(e.upper_bound), + e.confidence_interval, + }; + }; + std::vector<Duration> samples2; + samples2.reserve(samples.size()); + std::transform(samples.begin(), samples.end(), std::back_inserter(samples2), [](double d) { return Duration(d); }); + return { + std::move(samples2), + wrap_estimate(analysis.mean), + wrap_estimate(analysis.standard_deviation), + outliers, + analysis.outlier_variance, + }; + } else { + std::vector<Duration> samples; + samples.reserve(last - first); + + Duration mean = Duration(0); + int i = 0; + for (auto it = first; it < last; ++it, ++i) { + samples.push_back(Duration(*it)); + mean += Duration(*it); + } + mean /= i; + + return { + std::move(samples), + Estimate<Duration>{mean, mean, mean, 0.0}, + Estimate<Duration>{Duration(0), Duration(0), Duration(0), 0.0}, + OutlierClassification{}, + 0.0 + }; + } + } + } // namespace Detail + } // namespace Benchmark +} // namespace Catch - private: - int overflow( int c ) { - sync(); +// end catch_analyse.hpp +#include <algorithm> +#include <functional> +#include <string> +#include <vector> +#include <cmath> - if( c != EOF ) { - if( pbase() == epptr() ) - m_writer( std::string( 1, static_cast<char>( c ) ) ); - else - sputc( static_cast<char>( c ) ); +namespace Catch { + namespace Benchmark { + struct Benchmark { + Benchmark(std::string &&name) + : name(std::move(name)) {} + + template <class FUN> + Benchmark(std::string &&name, FUN &&func) + : fun(std::move(func)), name(std::move(name)) {} + + template <typename Clock> + ExecutionPlan<FloatDuration<Clock>> prepare(const IConfig &cfg, Environment<FloatDuration<Clock>> env) const { + auto min_time = env.clock_resolution.mean * Detail::minimum_ticks; + auto run_time = std::max(min_time, std::chrono::duration_cast<decltype(min_time)>(cfg.benchmarkWarmupTime())); + auto&& test = Detail::run_for_at_least<Clock>(std::chrono::duration_cast<ClockDuration<Clock>>(run_time), 1, fun); + int new_iters = static_cast<int>(std::ceil(min_time * test.iterations / test.elapsed)); + return { new_iters, test.elapsed / test.iterations * new_iters * cfg.benchmarkSamples(), fun, std::chrono::duration_cast<FloatDuration<Clock>>(cfg.benchmarkWarmupTime()), Detail::warmup_iterations }; } - return 0; - } - int sync() { - if( pbase() != pptr() ) { - m_writer( std::string( pbase(), static_cast<std::string::size_type>( pptr() - pbase() ) ) ); - setp( pbase(), epptr() ); + template <typename Clock = default_clock> + void run() { + IConfigPtr cfg = getCurrentContext().getConfig(); + + auto env = Detail::measure_environment<Clock>(); + + getResultCapture().benchmarkPreparing(name); + CATCH_TRY{ + auto plan = user_code([&] { + return prepare<Clock>(*cfg, env); + }); + + BenchmarkInfo info { + name, + plan.estimated_duration.count(), + plan.iterations_per_sample, + cfg->benchmarkSamples(), + cfg->benchmarkResamples(), + env.clock_resolution.mean.count(), + env.clock_cost.mean.count() + }; + + getResultCapture().benchmarkStarting(info); + + auto samples = user_code([&] { + return plan.template run<Clock>(*cfg, env); + }); + + auto analysis = Detail::analyse(*cfg, env, samples.begin(), samples.end()); + BenchmarkStats<FloatDuration<Clock>> stats{ info, analysis.samples, analysis.mean, analysis.standard_deviation, analysis.outliers, analysis.outlier_variance }; + getResultCapture().benchmarkEnded(stats); + + } CATCH_CATCH_ALL{ + if (translateActiveException() != Detail::benchmarkErrorMsg) // benchmark errors have been reported, otherwise rethrow. + std::rethrow_exception(std::current_exception()); + } } - return 0; - } - }; - /////////////////////////////////////////////////////////////////////////// + // sets lambda to be used in fun *and* executes benchmark! + template <typename Fun, + typename std::enable_if<!Detail::is_related<Fun, Benchmark>::value, int>::type = 0> + Benchmark & operator=(Fun func) { + fun = Detail::BenchmarkFunction(func); + run(); + return *this; + } - 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() ); - } - } + explicit operator bool() { + return true; + } - std::ostream& FileStream::stream() const { - return m_ofs; + private: + Detail::BenchmarkFunction fun; + std::string name; + }; } +} // namespace Catch - struct OutputDebugWriter { +#define INTERNAL_CATCH_GET_1_ARG(arg1, arg2, ...) arg1 +#define INTERNAL_CATCH_GET_2_ARG(arg1, arg2, ...) arg2 - void operator()( std::string const&str ) { - writeToDebugConsole( str ); - } - }; +#define INTERNAL_CATCH_BENCHMARK(BenchmarkName, name, benchmarkIndex)\ + if( Catch::Benchmark::Benchmark BenchmarkName{name} ) \ + BenchmarkName = [&](int benchmarkIndex) - DebugOutStream::DebugOutStream() - : m_streamBuf( new StreamBufImpl<OutputDebugWriter>() ), - m_os( m_streamBuf.get() ) - {} +#define INTERNAL_CATCH_BENCHMARK_ADVANCED(BenchmarkName, name)\ + if( Catch::Benchmark::Benchmark BenchmarkName{name} ) \ + BenchmarkName = [&] - std::ostream& DebugOutStream::stream() const { - return m_os; - } +// end catch_benchmark.hpp +// start catch_constructor.hpp - // Store the streambuf from cout up-front because - // cout may get redirected when running tests - CoutStream::CoutStream() - : m_os( Catch::cout().rdbuf() ) - {} +// Constructor and destructor helpers - 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; - } - std::ostream& cerr() { - return std::cerr; - } - std::ostream& clog() { - return std::clog; - } -#endif -} +#include <type_traits> namespace Catch { + namespace Benchmark { + namespace Detail { + template <typename T, bool Destruct> + struct ObjectStorage + { + ObjectStorage() : data() {} - class Context : public IMutableContext { - - Context() : m_config( CATCH_NULL ), m_runner( CATCH_NULL ), m_resultCapture( CATCH_NULL ) {} - Context( Context const& ); - void operator=( Context const& ); + ObjectStorage(const ObjectStorage& other) + { + new(&data) T(other.stored_object()); + } - public: - virtual ~Context() { - deleteAllValues( m_generatorsByTestName ); - } + ObjectStorage(ObjectStorage&& other) + { + new(&data) T(std::move(other.stored_object())); + } - public: // IContext - virtual IResultCapture* getResultCapture() { - return m_resultCapture; - } - virtual IRunner* getRunner() { - return m_runner; - } - virtual size_t getGeneratorIndex( std::string const& fileInfo, size_t totalSize ) { - return getGeneratorsForCurrentTest() - .getGeneratorInfo( fileInfo, totalSize ) - .getCurrentIndex(); - } - virtual bool advanceGeneratorsForCurrentTest() { - IGeneratorsForTest* generators = findGeneratorsForCurrentTest(); - return generators && generators->moveNext(); - } + ~ObjectStorage() { destruct_on_exit<T>(); } - virtual Ptr<IConfig const> getConfig() const { - return m_config; - } + template <typename... Args> + void construct(Args&&... args) + { + new (&data) T(std::forward<Args>(args)...); + } - public: // IMutableContext - virtual void setResultCapture( IResultCapture* resultCapture ) { - m_resultCapture = resultCapture; - } - virtual void setRunner( IRunner* runner ) { - m_runner = runner; - } - virtual void setConfig( Ptr<IConfig const> const& config ) { - m_config = config; - } + template <bool AllowManualDestruction = !Destruct> + typename std::enable_if<AllowManualDestruction>::type destruct() + { + stored_object().~T(); + } - friend IMutableContext& getCurrentMutableContext(); + private: + // If this is a constructor benchmark, destruct the underlying object + template <typename U> + void destruct_on_exit(typename std::enable_if<Destruct, U>::type* = 0) { destruct<true>(); } + // Otherwise, don't + template <typename U> + void destruct_on_exit(typename std::enable_if<!Destruct, U>::type* = 0) { } - private: - IGeneratorsForTest* findGeneratorsForCurrentTest() { - std::string testName = getResultCapture()->getCurrentTestName(); + T& stored_object() { + return *static_cast<T*>(static_cast<void*>(&data)); + } - std::map<std::string, IGeneratorsForTest*>::const_iterator it = - m_generatorsByTestName.find( testName ); - return it != m_generatorsByTestName.end() - ? it->second - : CATCH_NULL; - } + T const& stored_object() const { + return *static_cast<T*>(static_cast<void*>(&data)); + } - IGeneratorsForTest& getGeneratorsForCurrentTest() { - IGeneratorsForTest* generators = findGeneratorsForCurrentTest(); - if( !generators ) { - std::string testName = getResultCapture()->getCurrentTestName(); - generators = createGeneratorsForTest(); - m_generatorsByTestName.insert( std::make_pair( testName, generators ) ); - } - return *generators; + struct { alignas(T) unsigned char data[sizeof(T)]; } data; + }; } - private: - Ptr<IConfig const> m_config; - IRunner* m_runner; - IResultCapture* m_resultCapture; - std::map<std::string, IGeneratorsForTest*> m_generatorsByTestName; - }; - - namespace { - Context* currentContext = CATCH_NULL; - } - IMutableContext& getCurrentMutableContext() { - if( !currentContext ) - currentContext = new Context(); - return *currentContext; - } - IContext& getCurrentContext() { - return getCurrentMutableContext(); - } + template <typename T> + using storage_for = Detail::ObjectStorage<T, true>; - void cleanUpContext() { - delete currentContext; - currentContext = CATCH_NULL; + template <typename T> + using destructable_object = Detail::ObjectStorage<T, false>; } } -// #included from: catch_console_colour_impl.hpp -#define TWOBLUECUBES_CATCH_CONSOLE_COLOUR_IMPL_HPP_INCLUDED +// end catch_constructor.hpp +// end catch_benchmarking_all.hpp +#endif -// #included from: catch_errno_guard.hpp -#define TWOBLUECUBES_CATCH_ERRNO_GUARD_HPP_INCLUDED +#endif // ! CATCH_CONFIG_IMPL_ONLY -#include <cerrno> +#ifdef CATCH_IMPL +// start catch_impl.hpp -namespace Catch { +#ifdef __clang__ +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wweak-vtables" +#endif - class ErrnoGuard { - public: - ErrnoGuard():m_oldErrno(errno){} - ~ErrnoGuard() { errno = m_oldErrno; } - private: - int m_oldErrno; - }; +// Keep these here for external reporters +// start catch_test_case_tracker.h -} +#include <string> +#include <vector> +#include <memory> namespace Catch { - namespace { +namespace TestCaseTracking { - struct IColourImpl { - virtual ~IColourImpl() {} - virtual void use( Colour::Code _colourCode ) = 0; - }; - - struct NoColourImpl : IColourImpl { - void use( Colour::Code ) {} - - static IColourImpl* instance() { - static NoColourImpl s_instance; - return &s_instance; - } - }; + struct NameAndLocation { + std::string name; + SourceLineInfo location; - } // anon namespace -} // namespace Catch + NameAndLocation( std::string const& _name, SourceLineInfo const& _location ); + friend bool operator==(NameAndLocation const& lhs, NameAndLocation const& rhs) { + return lhs.name == rhs.name + && lhs.location == rhs.location; + } + }; -#if !defined( CATCH_CONFIG_COLOUR_NONE ) && !defined( CATCH_CONFIG_COLOUR_WINDOWS ) && !defined( CATCH_CONFIG_COLOUR_ANSI ) -# ifdef CATCH_PLATFORM_WINDOWS -# define CATCH_CONFIG_COLOUR_WINDOWS -# else -# define CATCH_CONFIG_COLOUR_ANSI -# endif -#endif + class ITracker; -#if defined ( CATCH_CONFIG_COLOUR_WINDOWS ) ///////////////////////////////////////// + using ITrackerPtr = std::shared_ptr<ITracker>; -namespace Catch { -namespace { + class ITracker { + NameAndLocation m_nameAndLocation; - class Win32ColourImpl : public IColourImpl { public: - Win32ColourImpl() : stdoutHandle( GetStdHandle(STD_OUTPUT_HANDLE) ) - { - CONSOLE_SCREEN_BUFFER_INFO csbiInfo; - GetConsoleScreenBufferInfo( stdoutHandle, &csbiInfo ); - originalForegroundAttributes = csbiInfo.wAttributes & ~( BACKGROUND_GREEN | BACKGROUND_RED | BACKGROUND_BLUE | BACKGROUND_INTENSITY ); - originalBackgroundAttributes = csbiInfo.wAttributes & ~( FOREGROUND_GREEN | FOREGROUND_RED | FOREGROUND_BLUE | FOREGROUND_INTENSITY ); + ITracker(NameAndLocation const& nameAndLoc) : + m_nameAndLocation(nameAndLoc) + {} + + // static queries + NameAndLocation const& nameAndLocation() const { + return m_nameAndLocation; } - virtual void use( Colour::Code _colourCode ) { - switch( _colourCode ) { - 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 ); - case Colour::Blue: return setTextAttribute( FOREGROUND_BLUE ); - case Colour::Cyan: return setTextAttribute( FOREGROUND_BLUE | FOREGROUND_GREEN ); - case Colour::Yellow: return setTextAttribute( FOREGROUND_RED | FOREGROUND_GREEN ); - case Colour::Grey: return setTextAttribute( 0 ); + virtual ~ITracker(); - case Colour::LightGrey: return setTextAttribute( FOREGROUND_INTENSITY ); - case Colour::BrightRed: return setTextAttribute( FOREGROUND_INTENSITY | FOREGROUND_RED ); - case Colour::BrightGreen: return setTextAttribute( FOREGROUND_INTENSITY | FOREGROUND_GREEN ); - case Colour::BrightWhite: return setTextAttribute( FOREGROUND_INTENSITY | FOREGROUND_GREEN | FOREGROUND_RED | FOREGROUND_BLUE ); + // 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 bool hasStarted() const = 0; - case Colour::Bright: throw std::logic_error( "not a colour" ); - } - } + virtual ITracker& parent() = 0; - private: - void setTextAttribute( WORD _textAttribute ) { - SetConsoleTextAttribute( stdoutHandle, _textAttribute | originalBackgroundAttributes ); - } - HANDLE stdoutHandle; - WORD originalForegroundAttributes; - WORD originalBackgroundAttributes; + // actions + virtual void close() = 0; // Successfully complete + virtual void fail() = 0; + virtual void markAsNeedingAnotherRun() = 0; + + virtual void addChild( ITrackerPtr const& child ) = 0; + virtual ITrackerPtr findChild( NameAndLocation const& nameAndLocation ) = 0; + virtual void openChild() = 0; + + // Debug/ checking + virtual bool isSectionTracker() const = 0; + virtual bool isGeneratorTracker() const = 0; }; - IColourImpl* platformColourInstance() { - static Win32ColourImpl s_instance; + class TrackerContext { - Ptr<IConfig const> config = getCurrentContext().getConfig(); - UseColour::YesOrNo colourMode = config - ? config->useColour() - : UseColour::Auto; - if( colourMode == UseColour::Auto ) - colourMode = !isDebuggerActive() - ? UseColour::Yes - : UseColour::No; - return colourMode == UseColour::Yes - ? &s_instance - : NoColourImpl::instance(); - } + enum RunState { + NotStarted, + Executing, + CompletedCycle + }; -} // end anon namespace -} // end namespace Catch + ITrackerPtr m_rootTracker; + ITracker* m_currentTracker = nullptr; + RunState m_runState = NotStarted; -#elif defined( CATCH_CONFIG_COLOUR_ANSI ) ////////////////////////////////////// + public: -#include <unistd.h> + ITracker& startRun(); + void endRun(); -namespace Catch { -namespace { + void startCycle(); + void completeCycle(); - // use POSIX/ ANSI console terminal codes - // Thanks to Adam Strzelecki for original contribution - // (http://github.com/nanoant) - // https://github.com/philsquared/Catch/pull/131 - class PosixColourImpl : public IColourImpl { - public: - virtual void use( Colour::Code _colourCode ) { - switch( _colourCode ) { - case Colour::None: - case Colour::White: return setColour( "[0m" ); - case Colour::Red: return setColour( "[0;31m" ); - case Colour::Green: return setColour( "[0;32m" ); - case Colour::Blue: return setColour( "[0;34m" ); - case Colour::Cyan: return setColour( "[0;36m" ); - case Colour::Yellow: return setColour( "[0;33m" ); - case Colour::Grey: return setColour( "[1;30m" ); + bool completedCycle() const; + ITracker& currentTracker(); + void setCurrentTracker( ITracker* tracker ); + }; - case Colour::LightGrey: return setColour( "[0;37m" ); - case Colour::BrightRed: return setColour( "[1;31m" ); - case Colour::BrightGreen: return setColour( "[1;32m" ); - case Colour::BrightWhite: return setColour( "[1;37m" ); + class TrackerBase : public ITracker { + protected: + enum CycleState { + NotStarted, + Executing, + ExecutingChildren, + NeedsAnotherRun, + CompletedSuccessfully, + Failed + }; - case Colour::Bright: throw std::logic_error( "not a colour" ); - } - } - static IColourImpl* instance() { - static PosixColourImpl s_instance; - return &s_instance; + using Children = std::vector<ITrackerPtr>; + TrackerContext& m_ctx; + ITracker* m_parent; + Children m_children; + CycleState m_runState = NotStarted; + + public: + TrackerBase( NameAndLocation const& nameAndLocation, TrackerContext& ctx, ITracker* parent ); + + bool isComplete() const override; + bool isSuccessfullyCompleted() const override; + bool isOpen() const override; + bool hasChildren() const override; + bool hasStarted() const override { + return m_runState != NotStarted; } + void addChild( ITrackerPtr const& child ) override; + + ITrackerPtr findChild( NameAndLocation const& nameAndLocation ) override; + ITracker& parent() override; + + void openChild() override; + + bool isSectionTracker() const override; + bool isGeneratorTracker() const override; + + void open(); + + void close() override; + void fail() override; + void markAsNeedingAnotherRun() override; + private: - void setColour( const char* _escapeCode ) { - Catch::cout() << '\033' << _escapeCode; - } + void moveToParent(); + void moveToThis(); }; - IColourImpl* platformColourInstance() { - ErrnoGuard guard; - Ptr<IConfig const> config = getCurrentContext().getConfig(); - UseColour::YesOrNo colourMode = config - ? config->useColour() - : UseColour::Auto; - if( colourMode == UseColour::Auto ) - colourMode = (!isDebuggerActive() && isatty(STDOUT_FILENO) ) - ? UseColour::Yes - : UseColour::No; - return colourMode == UseColour::Yes - ? PosixColourImpl::instance() - : NoColourImpl::instance(); - } + class SectionTracker : public TrackerBase { + std::vector<std::string> m_filters; + std::string m_trimmed_name; + public: + SectionTracker( NameAndLocation const& nameAndLocation, TrackerContext& ctx, ITracker* parent ); -} // end anon namespace -} // end namespace Catch + bool isSectionTracker() const override; -#else // not Windows or ANSI /////////////////////////////////////////////// + bool isComplete() const override; -namespace Catch { + static SectionTracker& acquire( TrackerContext& ctx, NameAndLocation const& nameAndLocation ); - static IColourImpl* platformColourInstance() { return NoColourImpl::instance(); } + void tryOpen(); -} // end namespace Catch + void addInitialFilters( std::vector<std::string> const& filters ); + void addNextFilters( std::vector<std::string> const& filters ); + //! Returns filters active in this tracker + std::vector<std::string> const& getFilters() const; + //! Returns whitespace-trimmed name of the tracked section + std::string const& trimmedName() const; + }; -#endif // Windows/ ANSI/ None +} // namespace TestCaseTracking + +using TestCaseTracking::ITracker; +using TestCaseTracking::TrackerContext; +using TestCaseTracking::SectionTracker; + +} // namespace Catch + +// end catch_test_case_tracker.h + +// start catch_leak_detector.h namespace Catch { - Colour::Colour( Code _colourCode ) : m_moved( false ) { use( _colourCode ); } - Colour::Colour( Colour const& _other ) : m_moved( false ) { const_cast<Colour&>( _other ).m_moved = true; } - Colour::~Colour(){ if( !m_moved ) use( None ); } + struct LeakDetector { + LeakDetector(); + ~LeakDetector(); + }; - void Colour::use( Code _colourCode ) { - static IColourImpl* impl = platformColourInstance(); - impl->use( _colourCode ); - } +} +// end catch_leak_detector.h +// Cpp files will be included in the single-header file here +// start catch_stats.cpp -} // end namespace Catch +// Statistical analysis tools -// #included from: catch_generators_impl.hpp -#define TWOBLUECUBES_CATCH_GENERATORS_IMPL_HPP_INCLUDED +#if defined(CATCH_CONFIG_ENABLE_BENCHMARKING) -#include <vector> -#include <string> -#include <map> +#include <cassert> +#include <random> + +#if defined(CATCH_CONFIG_USE_ASYNC) +#include <future> +#endif + +namespace { + double erf_inv(double x) { + // Code accompanying the article "Approximating the erfinv function" in GPU Computing Gems, Volume 2 + double w, p; + + w = -log((1.0 - x) * (1.0 + x)); + + if (w < 6.250000) { + w = w - 3.125000; + p = -3.6444120640178196996e-21; + p = -1.685059138182016589e-19 + p * w; + p = 1.2858480715256400167e-18 + p * w; + p = 1.115787767802518096e-17 + p * w; + p = -1.333171662854620906e-16 + p * w; + p = 2.0972767875968561637e-17 + p * w; + p = 6.6376381343583238325e-15 + p * w; + p = -4.0545662729752068639e-14 + p * w; + p = -8.1519341976054721522e-14 + p * w; + p = 2.6335093153082322977e-12 + p * w; + p = -1.2975133253453532498e-11 + p * w; + p = -5.4154120542946279317e-11 + p * w; + p = 1.051212273321532285e-09 + p * w; + p = -4.1126339803469836976e-09 + p * w; + p = -2.9070369957882005086e-08 + p * w; + p = 4.2347877827932403518e-07 + p * w; + p = -1.3654692000834678645e-06 + p * w; + p = -1.3882523362786468719e-05 + p * w; + p = 0.0001867342080340571352 + p * w; + p = -0.00074070253416626697512 + p * w; + p = -0.0060336708714301490533 + p * w; + p = 0.24015818242558961693 + p * w; + p = 1.6536545626831027356 + p * w; + } else if (w < 16.000000) { + w = sqrt(w) - 3.250000; + p = 2.2137376921775787049e-09; + p = 9.0756561938885390979e-08 + p * w; + p = -2.7517406297064545428e-07 + p * w; + p = 1.8239629214389227755e-08 + p * w; + p = 1.5027403968909827627e-06 + p * w; + p = -4.013867526981545969e-06 + p * w; + p = 2.9234449089955446044e-06 + p * w; + p = 1.2475304481671778723e-05 + p * w; + p = -4.7318229009055733981e-05 + p * w; + p = 6.8284851459573175448e-05 + p * w; + p = 2.4031110387097893999e-05 + p * w; + p = -0.0003550375203628474796 + p * w; + p = 0.00095328937973738049703 + p * w; + p = -0.0016882755560235047313 + p * w; + p = 0.0024914420961078508066 + p * w; + p = -0.0037512085075692412107 + p * w; + p = 0.005370914553590063617 + p * w; + p = 1.0052589676941592334 + p * w; + p = 3.0838856104922207635 + p * w; + } else { + w = sqrt(w) - 5.000000; + p = -2.7109920616438573243e-11; + p = -2.5556418169965252055e-10 + p * w; + p = 1.5076572693500548083e-09 + p * w; + p = -3.7894654401267369937e-09 + p * w; + p = 7.6157012080783393804e-09 + p * w; + p = -1.4960026627149240478e-08 + p * w; + p = 2.9147953450901080826e-08 + p * w; + p = -6.7711997758452339498e-08 + p * w; + p = 2.2900482228026654717e-07 + p * w; + p = -9.9298272942317002539e-07 + p * w; + p = 4.5260625972231537039e-06 + p * w; + p = -1.9681778105531670567e-05 + p * w; + p = 7.5995277030017761139e-05 + p * w; + p = -0.00021503011930044477347 + p * w; + p = -0.00013871931833623122026 + p * w; + p = 1.0103004648645343977 + p * w; + p = 4.8499064014085844221 + p * w; + } + return p * x; + } + + double standard_deviation(std::vector<double>::iterator first, std::vector<double>::iterator last) { + auto m = Catch::Benchmark::Detail::mean(first, last); + double variance = std::accumulate(first, last, 0., [m](double a, double b) { + double diff = b - m; + return a + diff * diff; + }) / (last - first); + return std::sqrt(variance); + } + +} namespace Catch { + namespace Benchmark { + namespace Detail { + + double weighted_average_quantile(int k, int q, std::vector<double>::iterator first, std::vector<double>::iterator last) { + auto count = last - first; + double idx = (count - 1) * k / static_cast<double>(q); + int j = static_cast<int>(idx); + double g = idx - j; + std::nth_element(first, first + j, last); + auto xj = first[j]; + if (g == 0) return xj; + + auto xj1 = *std::min_element(first + (j + 1), last); + return xj + g * (xj1 - xj); + } - struct GeneratorInfo : IGeneratorInfo { + double erfc_inv(double x) { + return erf_inv(1.0 - x); + } - GeneratorInfo( std::size_t size ) - : m_size( size ), - m_currentIndex( 0 ) - {} + double normal_quantile(double p) { + static const double ROOT_TWO = std::sqrt(2.0); - bool moveNext() { - if( ++m_currentIndex == m_size ) { - m_currentIndex = 0; - return false; + double result = 0.0; + assert(p >= 0 && p <= 1); + if (p < 0 || p > 1) { + return result; + } + + result = -erfc_inv(2.0 * p); + // result *= normal distribution standard deviation (1.0) * sqrt(2) + result *= /*sd * */ ROOT_TWO; + // result += normal disttribution mean (0) + return result; } - return true; - } - std::size_t getCurrentIndex() const { - return m_currentIndex; - } + double outlier_variance(Estimate<double> mean, Estimate<double> stddev, int n) { + double sb = stddev.point; + double mn = mean.point / n; + double mg_min = mn / 2.; + double sg = (std::min)(mg_min / 4., sb / std::sqrt(n)); + double sg2 = sg * sg; + double sb2 = sb * sb; + + auto c_max = [n, mn, sb2, sg2](double x) -> double { + double k = mn - x; + double d = k * k; + double nd = n * d; + double k0 = -n * nd; + double k1 = sb2 - n * sg2 + nd; + double det = k1 * k1 - 4 * sg2 * k0; + return (int)(-2. * k0 / (k1 + std::sqrt(det))); + }; + + auto var_out = [n, sb2, sg2](double c) { + double nc = n - c; + return (nc / n) * (sb2 - nc * sg2); + }; + + return (std::min)(var_out(1), var_out((std::min)(c_max(0.), c_max(mg_min)))) / sb2; + } - std::size_t m_size; - std::size_t m_currentIndex; - }; + bootstrap_analysis analyse_samples(double confidence_level, int n_resamples, std::vector<double>::iterator first, std::vector<double>::iterator last) { + CATCH_INTERNAL_START_WARNINGS_SUPPRESSION + CATCH_INTERNAL_SUPPRESS_GLOBALS_WARNINGS + static std::random_device entropy; + CATCH_INTERNAL_STOP_WARNINGS_SUPPRESSION - /////////////////////////////////////////////////////////////////////////// + auto n = static_cast<int>(last - first); // seriously, one can't use integral types without hell in C++ - class GeneratorsForTest : public IGeneratorsForTest { + auto mean = &Detail::mean<std::vector<double>::iterator>; + auto stddev = &standard_deviation; - public: - ~GeneratorsForTest() { - deleteAll( m_generatorsInOrder ); - } +#if defined(CATCH_CONFIG_USE_ASYNC) + auto Estimate = [=](double(*f)(std::vector<double>::iterator, std::vector<double>::iterator)) { + auto seed = entropy(); + return std::async(std::launch::async, [=] { + std::mt19937 rng(seed); + auto resampled = resample(rng, n_resamples, first, last, f); + return bootstrap(confidence_level, first, last, resampled, f); + }); + }; - IGeneratorInfo& getGeneratorInfo( std::string const& fileInfo, std::size_t size ) { - std::map<std::string, IGeneratorInfo*>::const_iterator it = m_generatorsByName.find( fileInfo ); - if( it == m_generatorsByName.end() ) { - IGeneratorInfo* info = new GeneratorInfo( size ); - m_generatorsByName.insert( std::make_pair( fileInfo, info ) ); - m_generatorsInOrder.push_back( info ); - return *info; - } - return *it->second; - } + auto mean_future = Estimate(mean); + auto stddev_future = Estimate(stddev); - bool moveNext() { - std::vector<IGeneratorInfo*>::const_iterator it = m_generatorsInOrder.begin(); - std::vector<IGeneratorInfo*>::const_iterator itEnd = m_generatorsInOrder.end(); - for(; it != itEnd; ++it ) { - if( (*it)->moveNext() ) - return true; + auto mean_estimate = mean_future.get(); + auto stddev_estimate = stddev_future.get(); +#else + auto Estimate = [=](double(*f)(std::vector<double>::iterator, std::vector<double>::iterator)) { + auto seed = entropy(); + std::mt19937 rng(seed); + auto resampled = resample(rng, n_resamples, first, last, f); + return bootstrap(confidence_level, first, last, resampled, f); + }; + + auto mean_estimate = Estimate(mean); + auto stddev_estimate = Estimate(stddev); +#endif // CATCH_USE_ASYNC + + double outlier_variance = Detail::outlier_variance(mean_estimate, stddev_estimate, n); + + return { mean_estimate, stddev_estimate, outlier_variance }; } - return false; - } + } // namespace Detail + } // namespace Benchmark +} // namespace Catch - private: - std::map<std::string, IGeneratorInfo*> m_generatorsByName; - std::vector<IGeneratorInfo*> m_generatorsInOrder; - }; +#endif // CATCH_CONFIG_ENABLE_BENCHMARKING +// end catch_stats.cpp +// start catch_approx.cpp - IGeneratorsForTest* createGeneratorsForTest() - { - return new GeneratorsForTest(); - } +#include <cmath> +#include <limits> -} // end namespace Catch +namespace { -// #included from: catch_assertionresult.hpp -#define TWOBLUECUBES_CATCH_ASSERTIONRESULT_HPP_INCLUDED +// Performs equivalent check of std::fabs(lhs - rhs) <= margin +// But without the subtraction to allow for INFINITY in comparison +bool marginComparison(double lhs, double rhs, double margin) { + return (lhs + margin >= rhs) && (rhs + margin >= lhs); +} -namespace Catch { +} - AssertionInfo::AssertionInfo():macroName(""), capturedExpression(""), resultDisposition(ResultDisposition::Normal), secondArg(""){} +namespace Catch { +namespace Detail { - AssertionInfo::AssertionInfo( char const * _macroName, - SourceLineInfo const& _lineInfo, - char const * _capturedExpression, - ResultDisposition::Flags _resultDisposition, - char const * _secondArg) - : macroName( _macroName ), - lineInfo( _lineInfo ), - capturedExpression( _capturedExpression ), - resultDisposition( _resultDisposition ), - secondArg( _secondArg ) + Approx::Approx ( double value ) + : m_epsilon( std::numeric_limits<float>::epsilon()*100 ), + m_margin( 0.0 ), + m_scale( 0.0 ), + m_value( value ) {} - AssertionResult::AssertionResult() {} + Approx Approx::custom() { + return Approx( 0 ); + } - AssertionResult::AssertionResult( AssertionInfo const& info, AssertionResultData const& data ) - : m_info( info ), - m_resultData( data ) - {} + Approx Approx::operator-() const { + auto temp(*this); + temp.m_value = -temp.m_value; + return temp; + } - AssertionResult::~AssertionResult() {} + std::string Approx::toString() const { + ReusableStringStream rss; + rss << "Approx( " << ::Catch::Detail::stringify( m_value ) << " )"; + return rss.str(); + } - // Result was a success - bool AssertionResult::succeeded() const { - return Catch::isOk( m_resultData.resultType ); + bool Approx::equalityComparisonImpl(const double other) const { + // First try with fixed margin, then compute margin based on epsilon, scale and Approx's value + // Thanks to Richard Harris for his help refining the scaled margin value + return marginComparison(m_value, other, m_margin) + || marginComparison(m_value, other, m_epsilon * (m_scale + std::fabs(std::isinf(m_value)? 0 : m_value))); } - // Result was a success, or failure is suppressed - bool AssertionResult::isOk() const { - return Catch::isOk( m_resultData.resultType ) || shouldSuppressFailure( m_info.resultDisposition ); + void Approx::setMargin(double newMargin) { + CATCH_ENFORCE(newMargin >= 0, + "Invalid Approx::margin: " << newMargin << '.' + << " Approx::Margin has to be non-negative."); + m_margin = newMargin; + } + + void Approx::setEpsilon(double newEpsilon) { + CATCH_ENFORCE(newEpsilon >= 0 && newEpsilon <= 1.0, + "Invalid Approx::epsilon: " << newEpsilon << '.' + << " Approx::epsilon has to be in [0, 1]"); + m_epsilon = newEpsilon; } - ResultWas::OfType AssertionResult::getResultType() const { - return m_resultData.resultType; +} // end namespace Detail + +namespace literals { + Detail::Approx operator "" _a(long double val) { + return Detail::Approx(val); + } + Detail::Approx operator "" _a(unsigned long long val) { + return Detail::Approx(val); + } +} // end namespace literals + +std::string StringMaker<Catch::Detail::Approx>::convert(Catch::Detail::Approx const& value) { + return value.toString(); +} + +} // end namespace Catch +// end catch_approx.cpp +// start catch_assertionhandler.cpp + +// start catch_debugger.h + +namespace Catch { + bool isDebuggerActive(); +} + +#ifdef CATCH_PLATFORM_MAC + + #if defined(__i386__) || defined(__x86_64__) + #define CATCH_TRAP() __asm__("int $3\n" : : ) /* NOLINT */ + #elif defined(__aarch64__) + #define CATCH_TRAP() __asm__(".inst 0xd43e0000") + #endif + +#elif defined(CATCH_PLATFORM_IPHONE) + + // use inline assembler + #if defined(__i386__) || defined(__x86_64__) + #define CATCH_TRAP() __asm__("int $3") + #elif defined(__aarch64__) + #define CATCH_TRAP() __asm__(".inst 0xd4200000") + #elif defined(__arm__) && !defined(__thumb__) + #define CATCH_TRAP() __asm__(".inst 0xe7f001f0") + #elif defined(__arm__) && defined(__thumb__) + #define CATCH_TRAP() __asm__(".inst 0xde01") + #endif + +#elif defined(CATCH_PLATFORM_LINUX) + // If we can use inline assembler, do it because this allows us to break + // directly at the location of the failing check instead of breaking inside + // raise() called from it, i.e. one stack frame below. + #if defined(__GNUC__) && (defined(__i386) || defined(__x86_64)) + #define CATCH_TRAP() asm volatile ("int $3") /* NOLINT */ + #else // Fall back to the generic way. + #include <signal.h> + + #define CATCH_TRAP() raise(SIGTRAP) + #endif +#elif defined(_MSC_VER) + #define CATCH_TRAP() __debugbreak() +#elif defined(__MINGW32__) + extern "C" __declspec(dllimport) void __stdcall DebugBreak(); + #define CATCH_TRAP() DebugBreak() +#endif + +#ifndef CATCH_BREAK_INTO_DEBUGGER + #ifdef CATCH_TRAP + #define CATCH_BREAK_INTO_DEBUGGER() []{ if( Catch::isDebuggerActive() ) { CATCH_TRAP(); } }() + #else + #define CATCH_BREAK_INTO_DEBUGGER() []{}() + #endif +#endif + +// end catch_debugger.h +// start catch_run_context.h + +// start catch_fatal_condition.h + +#include <cassert> + +namespace Catch { + + // Wrapper for platform-specific fatal error (signals/SEH) handlers + // + // Tries to be cooperative with other handlers, and not step over + // other handlers. This means that unknown structured exceptions + // are passed on, previous signal handlers are called, and so on. + // + // Can only be instantiated once, and assumes that once a signal + // is caught, the binary will end up terminating. Thus, there + class FatalConditionHandler { + bool m_started = false; + + // Install/disengage implementation for specific platform. + // Should be if-defed to work on current platform, can assume + // engage-disengage 1:1 pairing. + void engage_platform(); + void disengage_platform(); + public: + // Should also have platform-specific implementations as needed + FatalConditionHandler(); + ~FatalConditionHandler(); + + void engage() { + assert(!m_started && "Handler cannot be installed twice."); + m_started = true; + engage_platform(); + } + + void disengage() { + assert(m_started && "Handler cannot be uninstalled without being installed first"); + m_started = false; + disengage_platform(); + } + }; + + //! Simple RAII guard for (dis)engaging the FatalConditionHandler + class FatalConditionHandlerGuard { + FatalConditionHandler* m_handler; + public: + FatalConditionHandlerGuard(FatalConditionHandler* handler): + m_handler(handler) { + m_handler->engage(); + } + ~FatalConditionHandlerGuard() { + m_handler->disengage(); + } + }; + +} // end namespace Catch + +// end catch_fatal_condition.h +#include <string> + +namespace Catch { + + struct IMutableContext; + + /////////////////////////////////////////////////////////////////////////// + + class RunContext : public IResultCapture, public IRunner { + + public: + RunContext( RunContext const& ) = delete; + RunContext& operator =( RunContext const& ) = delete; + + explicit RunContext( IConfigPtr const& _config, IStreamingReporterPtr&& reporter ); + + ~RunContext() override; + + void testGroupStarting( std::string const& testSpec, std::size_t groupIndex, std::size_t groupsCount ); + void testGroupEnded( std::string const& testSpec, Totals const& totals, std::size_t groupIndex, std::size_t groupsCount ); + + Totals runTest(TestCase const& testCase); + + IConfigPtr config() const; + IStreamingReporter& reporter() const; + + public: // IResultCapture + + // Assertion handlers + void handleExpr + ( AssertionInfo const& info, + ITransientExpression const& expr, + AssertionReaction& reaction ) override; + void handleMessage + ( AssertionInfo const& info, + ResultWas::OfType resultType, + StringRef const& message, + AssertionReaction& reaction ) override; + void handleUnexpectedExceptionNotThrown + ( AssertionInfo const& info, + AssertionReaction& reaction ) override; + void handleUnexpectedInflightException + ( AssertionInfo const& info, + std::string const& message, + AssertionReaction& reaction ) override; + void handleIncomplete + ( AssertionInfo const& info ) override; + void handleNonExpr + ( AssertionInfo const &info, + ResultWas::OfType resultType, + AssertionReaction &reaction ) override; + + bool sectionStarted( SectionInfo const& sectionInfo, Counts& assertions ) override; + + void sectionEnded( SectionEndInfo const& endInfo ) override; + void sectionEndedEarly( SectionEndInfo const& endInfo ) override; + + auto acquireGeneratorTracker( StringRef generatorName, SourceLineInfo const& lineInfo ) -> IGeneratorTracker& override; + +#if defined(CATCH_CONFIG_ENABLE_BENCHMARKING) + void benchmarkPreparing( std::string const& name ) override; + void benchmarkStarting( BenchmarkInfo const& info ) override; + void benchmarkEnded( BenchmarkStats<> const& stats ) override; + void benchmarkFailed( std::string const& error ) override; +#endif // CATCH_CONFIG_ENABLE_BENCHMARKING + + void pushScopedMessage( MessageInfo const& message ) override; + void popScopedMessage( MessageInfo const& message ) override; + + void emplaceUnscopedMessage( MessageBuilder const& builder ) override; + + std::string getCurrentTestName() const override; + + const AssertionResult* getLastResult() const override; + + void exceptionEarlyReported() override; + + void handleFatalErrorCondition( StringRef message ) override; + + bool lastAssertionPassed() override; + + void assertionPassed() override; + + public: + // !TBD We need to do this another way! + bool aborting() const final; + + private: + + void runCurrentTest( std::string& redirectedCout, std::string& redirectedCerr ); + void invokeActiveTestCase(); + + void resetAssertionInfo(); + bool testForMissingAssertions( Counts& assertions ); + + void assertionEnded( AssertionResult const& result ); + void reportExpr + ( AssertionInfo const &info, + ResultWas::OfType resultType, + ITransientExpression const *expr, + bool negated ); + + void populateReaction( AssertionReaction& reaction ); + + private: + + void handleUnfinishedSections(); + + TestRunInfo m_runInfo; + IMutableContext& m_context; + TestCase const* m_activeTestCase = nullptr; + ITracker* m_testCaseTracker = nullptr; + Option<AssertionResult> m_lastResult; + + IConfigPtr m_config; + Totals m_totals; + IStreamingReporterPtr m_reporter; + std::vector<MessageInfo> m_messages; + std::vector<ScopedMessage> m_messageScopes; /* Keeps owners of so-called unscoped messages. */ + AssertionInfo m_lastAssertionInfo; + std::vector<SectionEndInfo> m_unfinishedSections; + std::vector<ITracker*> m_activeSections; + TrackerContext m_trackerContext; + FatalConditionHandler m_fatalConditionhandler; + bool m_lastAssertionPassed = false; + bool m_shouldReportUnexpected = true; + bool m_includeSuccessfulResults; + }; + + void seedRng(IConfig const& config); + unsigned int rngSeed(); +} // end namespace Catch + +// end catch_run_context.h +namespace Catch { + + namespace { + auto operator <<( std::ostream& os, ITransientExpression const& expr ) -> std::ostream& { + expr.streamReconstructedExpression( os ); + return os; + } + } + + LazyExpression::LazyExpression( bool isNegated ) + : m_isNegated( isNegated ) + {} + + LazyExpression::LazyExpression( LazyExpression const& other ) : m_isNegated( other.m_isNegated ) {} + + LazyExpression::operator bool() const { + return m_transientExpression != nullptr; + } + + auto operator << ( std::ostream& os, LazyExpression const& lazyExpr ) -> std::ostream& { + if( lazyExpr.m_isNegated ) + os << "!"; + + if( lazyExpr ) { + if( lazyExpr.m_isNegated && lazyExpr.m_transientExpression->isBinaryExpression() ) + os << "(" << *lazyExpr.m_transientExpression << ")"; + else + os << *lazyExpr.m_transientExpression; + } + else { + os << "{** error - unchecked empty expression requested **}"; + } + return os; + } + + AssertionHandler::AssertionHandler + ( StringRef const& macroName, + SourceLineInfo const& lineInfo, + StringRef capturedExpression, + ResultDisposition::Flags resultDisposition ) + : m_assertionInfo{ macroName, lineInfo, capturedExpression, resultDisposition }, + m_resultCapture( getResultCapture() ) + {} + + void AssertionHandler::handleExpr( ITransientExpression const& expr ) { + m_resultCapture.handleExpr( m_assertionInfo, expr, m_reaction ); + } + void AssertionHandler::handleMessage(ResultWas::OfType resultType, StringRef const& message) { + m_resultCapture.handleMessage( m_assertionInfo, resultType, message, m_reaction ); + } + + auto AssertionHandler::allowThrows() const -> bool { + return getCurrentContext().getConfig()->allowThrows(); + } + + void AssertionHandler::complete() { + setCompleted(); + if( m_reaction.shouldDebugBreak ) { + + // If you find your debugger stopping you here then go one level up on the + // call-stack for the code that caused it (typically a failed assertion) + + // (To go back to the test and change execution, jump over the throw, next) + CATCH_BREAK_INTO_DEBUGGER(); + } + if (m_reaction.shouldThrow) { +#if !defined(CATCH_CONFIG_DISABLE_EXCEPTIONS) + throw Catch::TestFailureException(); +#else + CATCH_ERROR( "Test failure requires aborting test!" ); +#endif + } + } + void AssertionHandler::setCompleted() { + m_completed = true; + } + + void AssertionHandler::handleUnexpectedInflightException() { + m_resultCapture.handleUnexpectedInflightException( m_assertionInfo, Catch::translateActiveException(), m_reaction ); + } + + void AssertionHandler::handleExceptionThrownAsExpected() { + m_resultCapture.handleNonExpr(m_assertionInfo, ResultWas::Ok, m_reaction); + } + void AssertionHandler::handleExceptionNotThrownAsExpected() { + m_resultCapture.handleNonExpr(m_assertionInfo, ResultWas::Ok, m_reaction); + } + + void AssertionHandler::handleUnexpectedExceptionNotThrown() { + m_resultCapture.handleUnexpectedExceptionNotThrown( m_assertionInfo, m_reaction ); + } + + void AssertionHandler::handleThrowingCallSkipped() { + m_resultCapture.handleNonExpr(m_assertionInfo, ResultWas::Ok, m_reaction); + } + + // This is the overload that takes a string and infers the Equals matcher from it + // The more general overload, that takes any string matcher, is in catch_capture_matchers.cpp + void handleExceptionMatchExpr( AssertionHandler& handler, std::string const& str, StringRef const& matcherString ) { + handleExceptionMatchExpr( handler, Matchers::Equals( str ), matcherString ); + } + +} // namespace Catch +// end catch_assertionhandler.cpp +// start catch_assertionresult.cpp + +namespace Catch { + AssertionResultData::AssertionResultData(ResultWas::OfType _resultType, LazyExpression const & _lazyExpression): + lazyExpression(_lazyExpression), + resultType(_resultType) {} + + std::string AssertionResultData::reconstructExpression() const { + + if( reconstructedExpression.empty() ) { + if( lazyExpression ) { + ReusableStringStream rss; + rss << lazyExpression; + reconstructedExpression = rss.str(); + } + } + return reconstructedExpression; + } + + AssertionResult::AssertionResult( AssertionInfo const& info, AssertionResultData const& data ) + : m_info( info ), + m_resultData( data ) + {} + + // Result was a success + bool AssertionResult::succeeded() const { + return Catch::isOk( m_resultData.resultType ); + } + + // Result was a success, or failure is suppressed + bool AssertionResult::isOk() const { + return Catch::isOk( m_resultData.resultType ) || shouldSuppressFailure( m_info.resultDisposition ); + } + + ResultWas::OfType AssertionResult::getResultType() const { + return m_resultData.resultType; + } + + bool AssertionResult::hasExpression() const { + return !m_info.capturedExpression.empty(); + } + + bool AssertionResult::hasMessage() const { + return !m_resultData.message.empty(); + } + + std::string AssertionResult::getExpression() const { + // Possibly overallocating by 3 characters should be basically free + std::string expr; expr.reserve(m_info.capturedExpression.size() + 3); + if (isFalseTest(m_info.resultDisposition)) { + expr += "!("; + } + expr += m_info.capturedExpression; + if (isFalseTest(m_info.resultDisposition)) { + expr += ')'; + } + return expr; + } + + std::string AssertionResult::getExpressionInMacro() const { + std::string expr; + if( m_info.macroName.empty() ) + expr = static_cast<std::string>(m_info.capturedExpression); + else { + expr.reserve( m_info.macroName.size() + m_info.capturedExpression.size() + 4 ); + expr += m_info.macroName; + expr += "( "; + expr += m_info.capturedExpression; + expr += " )"; + } + return expr; + } + + bool AssertionResult::hasExpandedExpression() const { + return hasExpression() && getExpandedExpression() != getExpression(); + } + + std::string AssertionResult::getExpandedExpression() const { + std::string expr = m_resultData.reconstructExpression(); + return expr.empty() + ? getExpression() + : expr; + } + + std::string AssertionResult::getMessage() const { + return m_resultData.message; + } + SourceLineInfo AssertionResult::getSourceInfo() const { + return m_info.lineInfo; + } + + StringRef AssertionResult::getTestMacroName() const { + return m_info.macroName; + } + +} // end namespace Catch +// end catch_assertionresult.cpp +// start catch_capture_matchers.cpp + +namespace Catch { + + using StringMatcher = Matchers::Impl::MatcherBase<std::string>; + + // This is the general overload that takes a any string matcher + // There is another overload, in catch_assertionhandler.h/.cpp, that only takes a string and infers + // the Equals matcher (so the header does not mention matchers) + void handleExceptionMatchExpr( AssertionHandler& handler, StringMatcher const& matcher, StringRef const& matcherString ) { + std::string exceptionMessage = Catch::translateActiveException(); + MatchExpr<std::string, StringMatcher const&> expr( exceptionMessage, matcher, matcherString ); + handler.handleExpr( expr ); + } + +} // namespace Catch +// end catch_capture_matchers.cpp +// start catch_commandline.cpp + +// start catch_commandline.h + +// start catch_clara.h + +// Use Catch's value for console width (store Clara's off to the side, if present) +#ifdef CLARA_CONFIG_CONSOLE_WIDTH +#define CATCH_TEMP_CLARA_CONFIG_CONSOLE_WIDTH CATCH_CLARA_TEXTFLOW_CONFIG_CONSOLE_WIDTH +#undef CATCH_CLARA_TEXTFLOW_CONFIG_CONSOLE_WIDTH +#endif +#define CATCH_CLARA_TEXTFLOW_CONFIG_CONSOLE_WIDTH CATCH_CONFIG_CONSOLE_WIDTH-1 + +#ifdef __clang__ +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wweak-vtables" +#pragma clang diagnostic ignored "-Wexit-time-destructors" +#pragma clang diagnostic ignored "-Wshadow" +#endif + +// start clara.hpp +// Copyright 2017 Two Blue Cubes Ltd. All rights reserved. +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// See https://github.com/philsquared/Clara for more details + +// Clara v1.1.5 + + +#ifndef CATCH_CLARA_CONFIG_CONSOLE_WIDTH +#define CATCH_CLARA_CONFIG_CONSOLE_WIDTH 80 +#endif + +#ifndef CATCH_CLARA_TEXTFLOW_CONFIG_CONSOLE_WIDTH +#define CATCH_CLARA_TEXTFLOW_CONFIG_CONSOLE_WIDTH CATCH_CLARA_CONFIG_CONSOLE_WIDTH +#endif + +#ifndef CLARA_CONFIG_OPTIONAL_TYPE +#ifdef __has_include +#if __has_include(<optional>) && __cplusplus >= 201703L +#include <optional> +#define CLARA_CONFIG_OPTIONAL_TYPE std::optional +#endif +#endif +#endif + +// ----------- #included from clara_textflow.hpp ----------- + +// TextFlowCpp +// +// A single-header library for wrapping and laying out basic text, by Phil Nash +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// This project is hosted at https://github.com/philsquared/textflowcpp + + +#include <cassert> +#include <ostream> +#include <sstream> +#include <vector> + +#ifndef CATCH_CLARA_TEXTFLOW_CONFIG_CONSOLE_WIDTH +#define CATCH_CLARA_TEXTFLOW_CONFIG_CONSOLE_WIDTH 80 +#endif + +namespace Catch { +namespace clara { +namespace TextFlow { + +inline auto isWhitespace(char c) -> bool { + static std::string chars = " \t\n\r"; + return chars.find(c) != std::string::npos; +} +inline auto isBreakableBefore(char c) -> bool { + static std::string chars = "[({<|"; + return chars.find(c) != std::string::npos; +} +inline auto isBreakableAfter(char c) -> bool { + static std::string chars = "])}>.,:;*+-=&/\\"; + return chars.find(c) != std::string::npos; +} + +class Columns; + +class Column { + std::vector<std::string> m_strings; + size_t m_width = CATCH_CLARA_TEXTFLOW_CONFIG_CONSOLE_WIDTH; + size_t m_indent = 0; + size_t m_initialIndent = std::string::npos; + +public: + class iterator { + friend Column; + + Column const& m_column; + size_t m_stringIndex = 0; + size_t m_pos = 0; + + size_t m_len = 0; + size_t m_end = 0; + bool m_suffix = false; + + iterator(Column const& column, size_t stringIndex) + : m_column(column), + m_stringIndex(stringIndex) {} + + auto line() const -> std::string const& { return m_column.m_strings[m_stringIndex]; } + + auto isBoundary(size_t at) const -> bool { + assert(at > 0); + assert(at <= line().size()); + + return at == line().size() || + (isWhitespace(line()[at]) && !isWhitespace(line()[at - 1])) || + isBreakableBefore(line()[at]) || + isBreakableAfter(line()[at - 1]); + } + + void calcLength() { + assert(m_stringIndex < m_column.m_strings.size()); + + m_suffix = false; + auto width = m_column.m_width - indent(); + m_end = m_pos; + if (line()[m_pos] == '\n') { + ++m_end; + } + while (m_end < line().size() && line()[m_end] != '\n') + ++m_end; + + if (m_end < m_pos + width) { + m_len = m_end - m_pos; + } else { + size_t len = width; + while (len > 0 && !isBoundary(m_pos + len)) + --len; + while (len > 0 && isWhitespace(line()[m_pos + len - 1])) + --len; + + if (len > 0) { + m_len = len; + } else { + m_suffix = true; + m_len = width - 1; + } + } + } + + auto indent() const -> size_t { + auto initial = m_pos == 0 && m_stringIndex == 0 ? m_column.m_initialIndent : std::string::npos; + return initial == std::string::npos ? m_column.m_indent : initial; + } + + auto addIndentAndSuffix(std::string const &plain) const -> std::string { + return std::string(indent(), ' ') + (m_suffix ? plain + "-" : plain); + } + + public: + using difference_type = std::ptrdiff_t; + using value_type = std::string; + using pointer = value_type * ; + using reference = value_type & ; + using iterator_category = std::forward_iterator_tag; + + explicit iterator(Column const& column) : m_column(column) { + assert(m_column.m_width > m_column.m_indent); + assert(m_column.m_initialIndent == std::string::npos || m_column.m_width > m_column.m_initialIndent); + calcLength(); + if (m_len == 0) + m_stringIndex++; // Empty string + } + + auto operator *() const -> std::string { + assert(m_stringIndex < m_column.m_strings.size()); + assert(m_pos <= m_end); + return addIndentAndSuffix(line().substr(m_pos, m_len)); + } + + auto operator ++() -> iterator& { + m_pos += m_len; + if (m_pos < line().size() && line()[m_pos] == '\n') + m_pos += 1; + else + while (m_pos < line().size() && isWhitespace(line()[m_pos])) + ++m_pos; + + if (m_pos == line().size()) { + m_pos = 0; + ++m_stringIndex; + } + if (m_stringIndex < m_column.m_strings.size()) + calcLength(); + return *this; + } + auto operator ++(int) -> iterator { + iterator prev(*this); + operator++(); + return prev; + } + + auto operator ==(iterator const& other) const -> bool { + return + m_pos == other.m_pos && + m_stringIndex == other.m_stringIndex && + &m_column == &other.m_column; + } + auto operator !=(iterator const& other) const -> bool { + return !operator==(other); + } + }; + using const_iterator = iterator; + + explicit Column(std::string const& text) { m_strings.push_back(text); } + + auto width(size_t newWidth) -> Column& { + assert(newWidth > 0); + m_width = newWidth; + return *this; + } + auto indent(size_t newIndent) -> Column& { + m_indent = newIndent; + return *this; + } + auto initialIndent(size_t newIndent) -> Column& { + m_initialIndent = newIndent; + return *this; + } + + auto width() const -> size_t { return m_width; } + auto begin() const -> iterator { return iterator(*this); } + auto end() const -> iterator { return { *this, m_strings.size() }; } + + inline friend std::ostream& operator << (std::ostream& os, Column const& col) { + bool first = true; + for (auto line : col) { + if (first) + first = false; + else + os << "\n"; + os << line; + } + return os; + } + + auto operator + (Column const& other)->Columns; + + auto toString() const -> std::string { + std::ostringstream oss; + oss << *this; + return oss.str(); + } +}; + +class Spacer : public Column { + +public: + explicit Spacer(size_t spaceWidth) : Column("") { + width(spaceWidth); + } +}; + +class Columns { + std::vector<Column> m_columns; + +public: + + class iterator { + friend Columns; + struct EndTag {}; + + std::vector<Column> const& m_columns; + std::vector<Column::iterator> m_iterators; + size_t m_activeIterators; + + iterator(Columns const& columns, EndTag) + : m_columns(columns.m_columns), + m_activeIterators(0) { + m_iterators.reserve(m_columns.size()); + + for (auto const& col : m_columns) + m_iterators.push_back(col.end()); + } + + public: + using difference_type = std::ptrdiff_t; + using value_type = std::string; + using pointer = value_type * ; + using reference = value_type & ; + using iterator_category = std::forward_iterator_tag; + + explicit iterator(Columns const& columns) + : m_columns(columns.m_columns), + m_activeIterators(m_columns.size()) { + m_iterators.reserve(m_columns.size()); + + for (auto const& col : m_columns) + m_iterators.push_back(col.begin()); + } + + auto operator ==(iterator const& other) const -> bool { + return m_iterators == other.m_iterators; + } + auto operator !=(iterator const& other) const -> bool { + return m_iterators != other.m_iterators; + } + auto operator *() const -> std::string { + std::string row, padding; + + for (size_t i = 0; i < m_columns.size(); ++i) { + auto width = m_columns[i].width(); + if (m_iterators[i] != m_columns[i].end()) { + std::string col = *m_iterators[i]; + row += padding + col; + if (col.size() < width) + padding = std::string(width - col.size(), ' '); + else + padding = ""; + } else { + padding += std::string(width, ' '); + } + } + return row; + } + auto operator ++() -> iterator& { + for (size_t i = 0; i < m_columns.size(); ++i) { + if (m_iterators[i] != m_columns[i].end()) + ++m_iterators[i]; + } + return *this; + } + auto operator ++(int) -> iterator { + iterator prev(*this); + operator++(); + return prev; + } + }; + using const_iterator = iterator; + + auto begin() const -> iterator { return iterator(*this); } + auto end() const -> iterator { return { *this, iterator::EndTag() }; } + + auto operator += (Column const& col) -> Columns& { + m_columns.push_back(col); + return *this; + } + auto operator + (Column const& col) -> Columns { + Columns combined = *this; + combined += col; + return combined; + } + + inline friend std::ostream& operator << (std::ostream& os, Columns const& cols) { + + bool first = true; + for (auto line : cols) { + if (first) + first = false; + else + os << "\n"; + os << line; + } + return os; + } + + auto toString() const -> std::string { + std::ostringstream oss; + oss << *this; + return oss.str(); + } +}; + +inline auto Column::operator + (Column const& other) -> Columns { + Columns cols; + cols += *this; + cols += other; + return cols; +} +} + +} +} + +// ----------- end of #include from clara_textflow.hpp ----------- +// ........... back in clara.hpp + +#include <cctype> +#include <string> +#include <memory> +#include <set> +#include <algorithm> + +#if !defined(CATCH_PLATFORM_WINDOWS) && ( defined(WIN32) || defined(__WIN32__) || defined(_WIN32) || defined(_MSC_VER) ) +#define CATCH_PLATFORM_WINDOWS +#endif + +namespace Catch { namespace clara { +namespace detail { + + // Traits for extracting arg and return type of lambdas (for single argument lambdas) + template<typename L> + struct UnaryLambdaTraits : UnaryLambdaTraits<decltype( &L::operator() )> {}; + + template<typename ClassT, typename ReturnT, typename... Args> + struct UnaryLambdaTraits<ReturnT( ClassT::* )( Args... ) const> { + static const bool isValid = false; + }; + + template<typename ClassT, typename ReturnT, typename ArgT> + struct UnaryLambdaTraits<ReturnT( ClassT::* )( ArgT ) const> { + static const bool isValid = true; + using ArgType = typename std::remove_const<typename std::remove_reference<ArgT>::type>::type; + using ReturnType = ReturnT; + }; + + class TokenStream; + + // Transport for raw args (copied from main args, or supplied via init list for testing) + class Args { + friend TokenStream; + std::string m_exeName; + std::vector<std::string> m_args; + + public: + Args( int argc, char const* const* argv ) + : m_exeName(argv[0]), + m_args(argv + 1, argv + argc) {} + + Args( std::initializer_list<std::string> args ) + : m_exeName( *args.begin() ), + m_args( args.begin()+1, args.end() ) + {} + + auto exeName() const -> std::string { + return m_exeName; + } + }; + + // Wraps a token coming from a token stream. These may not directly correspond to strings as a single string + // may encode an option + its argument if the : or = form is used + enum class TokenType { + Option, Argument + }; + struct Token { + TokenType type; + std::string token; + }; + + inline auto isOptPrefix( char c ) -> bool { + return c == '-' +#ifdef CATCH_PLATFORM_WINDOWS + || c == '/' +#endif + ; + } + + // Abstracts iterators into args as a stream of tokens, with option arguments uniformly handled + class TokenStream { + using Iterator = std::vector<std::string>::const_iterator; + Iterator it; + Iterator itEnd; + std::vector<Token> m_tokenBuffer; + + void loadBuffer() { + m_tokenBuffer.resize( 0 ); + + // Skip any empty strings + while( it != itEnd && it->empty() ) + ++it; + + if( it != itEnd ) { + auto const &next = *it; + if( isOptPrefix( next[0] ) ) { + auto delimiterPos = next.find_first_of( " :=" ); + if( delimiterPos != std::string::npos ) { + m_tokenBuffer.push_back( { TokenType::Option, next.substr( 0, delimiterPos ) } ); + m_tokenBuffer.push_back( { TokenType::Argument, next.substr( delimiterPos + 1 ) } ); + } else { + if( next[1] != '-' && next.size() > 2 ) { + std::string opt = "- "; + for( size_t i = 1; i < next.size(); ++i ) { + opt[1] = next[i]; + m_tokenBuffer.push_back( { TokenType::Option, opt } ); + } + } else { + m_tokenBuffer.push_back( { TokenType::Option, next } ); + } + } + } else { + m_tokenBuffer.push_back( { TokenType::Argument, next } ); + } + } + } + + public: + explicit TokenStream( Args const &args ) : TokenStream( args.m_args.begin(), args.m_args.end() ) {} + + TokenStream( Iterator it, Iterator itEnd ) : it( it ), itEnd( itEnd ) { + loadBuffer(); + } + + explicit operator bool() const { + return !m_tokenBuffer.empty() || it != itEnd; + } + + auto count() const -> size_t { return m_tokenBuffer.size() + (itEnd - it); } + + auto operator*() const -> Token { + assert( !m_tokenBuffer.empty() ); + return m_tokenBuffer.front(); + } + + auto operator->() const -> Token const * { + assert( !m_tokenBuffer.empty() ); + return &m_tokenBuffer.front(); + } + + auto operator++() -> TokenStream & { + if( m_tokenBuffer.size() >= 2 ) { + m_tokenBuffer.erase( m_tokenBuffer.begin() ); + } else { + if( it != itEnd ) + ++it; + loadBuffer(); + } + return *this; + } + }; + + class ResultBase { + public: + enum Type { + Ok, LogicError, RuntimeError + }; + + protected: + ResultBase( Type type ) : m_type( type ) {} + virtual ~ResultBase() = default; + + virtual void enforceOk() const = 0; + + Type m_type; + }; + + template<typename T> + class ResultValueBase : public ResultBase { + public: + auto value() const -> T const & { + enforceOk(); + return m_value; + } + + protected: + ResultValueBase( Type type ) : ResultBase( type ) {} + + ResultValueBase( ResultValueBase const &other ) : ResultBase( other ) { + if( m_type == ResultBase::Ok ) + new( &m_value ) T( other.m_value ); + } + + ResultValueBase( Type, T const &value ) : ResultBase( Ok ) { + new( &m_value ) T( value ); + } + + auto operator=( ResultValueBase const &other ) -> ResultValueBase & { + if( m_type == ResultBase::Ok ) + m_value.~T(); + ResultBase::operator=(other); + if( m_type == ResultBase::Ok ) + new( &m_value ) T( other.m_value ); + return *this; + } + + ~ResultValueBase() override { + if( m_type == Ok ) + m_value.~T(); + } + + union { + T m_value; + }; + }; + + template<> + class ResultValueBase<void> : public ResultBase { + protected: + using ResultBase::ResultBase; + }; + + template<typename T = void> + class BasicResult : public ResultValueBase<T> { + public: + template<typename U> + explicit BasicResult( BasicResult<U> const &other ) + : ResultValueBase<T>( other.type() ), + m_errorMessage( other.errorMessage() ) + { + assert( type() != ResultBase::Ok ); + } + + template<typename U> + static auto ok( U const &value ) -> BasicResult { return { ResultBase::Ok, value }; } + static auto ok() -> BasicResult { return { ResultBase::Ok }; } + static auto logicError( std::string const &message ) -> BasicResult { return { ResultBase::LogicError, message }; } + static auto runtimeError( std::string const &message ) -> BasicResult { return { ResultBase::RuntimeError, message }; } + + explicit operator bool() const { return m_type == ResultBase::Ok; } + auto type() const -> ResultBase::Type { return m_type; } + auto errorMessage() const -> std::string { return m_errorMessage; } + + protected: + void enforceOk() const override { + + // Errors shouldn't reach this point, but if they do + // the actual error message will be in m_errorMessage + assert( m_type != ResultBase::LogicError ); + assert( m_type != ResultBase::RuntimeError ); + if( m_type != ResultBase::Ok ) + std::abort(); + } + + std::string m_errorMessage; // Only populated if resultType is an error + + BasicResult( ResultBase::Type type, std::string const &message ) + : ResultValueBase<T>(type), + m_errorMessage(message) + { + assert( m_type != ResultBase::Ok ); + } + + using ResultValueBase<T>::ResultValueBase; + using ResultBase::m_type; + }; + + enum class ParseResultType { + Matched, NoMatch, ShortCircuitAll, ShortCircuitSame + }; + + class ParseState { + public: + + ParseState( ParseResultType type, TokenStream const &remainingTokens ) + : m_type(type), + m_remainingTokens( remainingTokens ) + {} + + auto type() const -> ParseResultType { return m_type; } + auto remainingTokens() const -> TokenStream { return m_remainingTokens; } + + private: + ParseResultType m_type; + TokenStream m_remainingTokens; + }; + + using Result = BasicResult<void>; + using ParserResult = BasicResult<ParseResultType>; + using InternalParseResult = BasicResult<ParseState>; + + struct HelpColumns { + std::string left; + std::string right; + }; + + template<typename T> + inline auto convertInto( std::string const &source, T& target ) -> ParserResult { + std::stringstream ss; + ss << source; + ss >> target; + if( ss.fail() ) + return ParserResult::runtimeError( "Unable to convert '" + source + "' to destination type" ); + else + return ParserResult::ok( ParseResultType::Matched ); + } + inline auto convertInto( std::string const &source, std::string& target ) -> ParserResult { + target = source; + return ParserResult::ok( ParseResultType::Matched ); + } + inline auto convertInto( std::string const &source, bool &target ) -> ParserResult { + std::string srcLC = source; + std::transform( srcLC.begin(), srcLC.end(), srcLC.begin(), []( unsigned char c ) { return static_cast<char>( std::tolower(c) ); } ); + if (srcLC == "y" || srcLC == "1" || srcLC == "true" || srcLC == "yes" || srcLC == "on") + target = true; + else if (srcLC == "n" || srcLC == "0" || srcLC == "false" || srcLC == "no" || srcLC == "off") + target = false; + else + return ParserResult::runtimeError( "Expected a boolean value but did not recognise: '" + source + "'" ); + return ParserResult::ok( ParseResultType::Matched ); + } +#ifdef CLARA_CONFIG_OPTIONAL_TYPE + template<typename T> + inline auto convertInto( std::string const &source, CLARA_CONFIG_OPTIONAL_TYPE<T>& target ) -> ParserResult { + T temp; + auto result = convertInto( source, temp ); + if( result ) + target = std::move(temp); + return result; + } +#endif // CLARA_CONFIG_OPTIONAL_TYPE + + struct NonCopyable { + NonCopyable() = default; + NonCopyable( NonCopyable const & ) = delete; + NonCopyable( NonCopyable && ) = delete; + NonCopyable &operator=( NonCopyable const & ) = delete; + NonCopyable &operator=( NonCopyable && ) = delete; + }; + + struct BoundRef : NonCopyable { + virtual ~BoundRef() = default; + virtual auto isContainer() const -> bool { return false; } + virtual auto isFlag() const -> bool { return false; } + }; + struct BoundValueRefBase : BoundRef { + virtual auto setValue( std::string const &arg ) -> ParserResult = 0; + }; + struct BoundFlagRefBase : BoundRef { + virtual auto setFlag( bool flag ) -> ParserResult = 0; + virtual auto isFlag() const -> bool { return true; } + }; + + template<typename T> + struct BoundValueRef : BoundValueRefBase { + T &m_ref; + + explicit BoundValueRef( T &ref ) : m_ref( ref ) {} + + auto setValue( std::string const &arg ) -> ParserResult override { + return convertInto( arg, m_ref ); + } + }; + + template<typename T> + struct BoundValueRef<std::vector<T>> : BoundValueRefBase { + std::vector<T> &m_ref; + + explicit BoundValueRef( std::vector<T> &ref ) : m_ref( ref ) {} + + auto isContainer() const -> bool override { return true; } + + auto setValue( std::string const &arg ) -> ParserResult override { + T temp; + auto result = convertInto( arg, temp ); + if( result ) + m_ref.push_back( temp ); + return result; + } + }; + + struct BoundFlagRef : BoundFlagRefBase { + bool &m_ref; + + explicit BoundFlagRef( bool &ref ) : m_ref( ref ) {} + + auto setFlag( bool flag ) -> ParserResult override { + m_ref = flag; + return ParserResult::ok( ParseResultType::Matched ); + } + }; + + template<typename ReturnType> + struct LambdaInvoker { + static_assert( std::is_same<ReturnType, ParserResult>::value, "Lambda must return void or clara::ParserResult" ); + + template<typename L, typename ArgType> + static auto invoke( L const &lambda, ArgType const &arg ) -> ParserResult { + return lambda( arg ); + } + }; + + template<> + struct LambdaInvoker<void> { + template<typename L, typename ArgType> + static auto invoke( L const &lambda, ArgType const &arg ) -> ParserResult { + lambda( arg ); + return ParserResult::ok( ParseResultType::Matched ); + } + }; + + template<typename ArgType, typename L> + inline auto invokeLambda( L const &lambda, std::string const &arg ) -> ParserResult { + ArgType temp{}; + auto result = convertInto( arg, temp ); + return !result + ? result + : LambdaInvoker<typename UnaryLambdaTraits<L>::ReturnType>::invoke( lambda, temp ); + } + + template<typename L> + struct BoundLambda : BoundValueRefBase { + L m_lambda; + + static_assert( UnaryLambdaTraits<L>::isValid, "Supplied lambda must take exactly one argument" ); + explicit BoundLambda( L const &lambda ) : m_lambda( lambda ) {} + + auto setValue( std::string const &arg ) -> ParserResult override { + return invokeLambda<typename UnaryLambdaTraits<L>::ArgType>( m_lambda, arg ); + } + }; + + template<typename L> + struct BoundFlagLambda : BoundFlagRefBase { + L m_lambda; + + static_assert( UnaryLambdaTraits<L>::isValid, "Supplied lambda must take exactly one argument" ); + static_assert( std::is_same<typename UnaryLambdaTraits<L>::ArgType, bool>::value, "flags must be boolean" ); + + explicit BoundFlagLambda( L const &lambda ) : m_lambda( lambda ) {} + + auto setFlag( bool flag ) -> ParserResult override { + return LambdaInvoker<typename UnaryLambdaTraits<L>::ReturnType>::invoke( m_lambda, flag ); + } + }; + + enum class Optionality { Optional, Required }; + + struct Parser; + + class ParserBase { + public: + virtual ~ParserBase() = default; + virtual auto validate() const -> Result { return Result::ok(); } + virtual auto parse( std::string const& exeName, TokenStream const &tokens) const -> InternalParseResult = 0; + virtual auto cardinality() const -> size_t { return 1; } + + auto parse( Args const &args ) const -> InternalParseResult { + return parse( args.exeName(), TokenStream( args ) ); + } + }; + + template<typename DerivedT> + class ComposableParserImpl : public ParserBase { + public: + template<typename T> + auto operator|( T const &other ) const -> Parser; + + template<typename T> + auto operator+( T const &other ) const -> Parser; + }; + + // Common code and state for Args and Opts + template<typename DerivedT> + class ParserRefImpl : public ComposableParserImpl<DerivedT> { + protected: + Optionality m_optionality = Optionality::Optional; + std::shared_ptr<BoundRef> m_ref; + std::string m_hint; + std::string m_description; + + explicit ParserRefImpl( std::shared_ptr<BoundRef> const &ref ) : m_ref( ref ) {} + + public: + template<typename T> + ParserRefImpl( T &ref, std::string const &hint ) + : m_ref( std::make_shared<BoundValueRef<T>>( ref ) ), + m_hint( hint ) + {} + + template<typename LambdaT> + ParserRefImpl( LambdaT const &ref, std::string const &hint ) + : m_ref( std::make_shared<BoundLambda<LambdaT>>( ref ) ), + m_hint(hint) + {} + + auto operator()( std::string const &description ) -> DerivedT & { + m_description = description; + return static_cast<DerivedT &>( *this ); + } + + auto optional() -> DerivedT & { + m_optionality = Optionality::Optional; + return static_cast<DerivedT &>( *this ); + }; + + auto required() -> DerivedT & { + m_optionality = Optionality::Required; + return static_cast<DerivedT &>( *this ); + }; + + auto isOptional() const -> bool { + return m_optionality == Optionality::Optional; + } + + auto cardinality() const -> size_t override { + if( m_ref->isContainer() ) + return 0; + else + return 1; + } + + auto hint() const -> std::string { return m_hint; } + }; + + class ExeName : public ComposableParserImpl<ExeName> { + std::shared_ptr<std::string> m_name; + std::shared_ptr<BoundValueRefBase> m_ref; + + template<typename LambdaT> + static auto makeRef(LambdaT const &lambda) -> std::shared_ptr<BoundValueRefBase> { + return std::make_shared<BoundLambda<LambdaT>>( lambda) ; + } + + public: + ExeName() : m_name( std::make_shared<std::string>( "<executable>" ) ) {} + + explicit ExeName( std::string &ref ) : ExeName() { + m_ref = std::make_shared<BoundValueRef<std::string>>( ref ); + } + + template<typename LambdaT> + explicit ExeName( LambdaT const& lambda ) : ExeName() { + m_ref = std::make_shared<BoundLambda<LambdaT>>( lambda ); + } + + // The exe name is not parsed out of the normal tokens, but is handled specially + auto parse( std::string const&, TokenStream const &tokens ) const -> InternalParseResult override { + return InternalParseResult::ok( ParseState( ParseResultType::NoMatch, tokens ) ); + } + + auto name() const -> std::string { return *m_name; } + auto set( std::string const& newName ) -> ParserResult { + + auto lastSlash = newName.find_last_of( "\\/" ); + auto filename = ( lastSlash == std::string::npos ) + ? newName + : newName.substr( lastSlash+1 ); + + *m_name = filename; + if( m_ref ) + return m_ref->setValue( filename ); + else + return ParserResult::ok( ParseResultType::Matched ); + } + }; + + class Arg : public ParserRefImpl<Arg> { + public: + using ParserRefImpl::ParserRefImpl; + + auto parse( std::string const &, TokenStream const &tokens ) const -> InternalParseResult override { + auto validationResult = validate(); + if( !validationResult ) + return InternalParseResult( validationResult ); + + auto remainingTokens = tokens; + auto const &token = *remainingTokens; + if( token.type != TokenType::Argument ) + return InternalParseResult::ok( ParseState( ParseResultType::NoMatch, remainingTokens ) ); + + assert( !m_ref->isFlag() ); + auto valueRef = static_cast<detail::BoundValueRefBase*>( m_ref.get() ); + + auto result = valueRef->setValue( remainingTokens->token ); + if( !result ) + return InternalParseResult( result ); + else + return InternalParseResult::ok( ParseState( ParseResultType::Matched, ++remainingTokens ) ); + } + }; + + inline auto normaliseOpt( std::string const &optName ) -> std::string { +#ifdef CATCH_PLATFORM_WINDOWS + if( optName[0] == '/' ) + return "-" + optName.substr( 1 ); + else +#endif + return optName; + } + + class Opt : public ParserRefImpl<Opt> { + protected: + std::vector<std::string> m_optNames; + + public: + template<typename LambdaT> + explicit Opt( LambdaT const &ref ) : ParserRefImpl( std::make_shared<BoundFlagLambda<LambdaT>>( ref ) ) {} + + explicit Opt( bool &ref ) : ParserRefImpl( std::make_shared<BoundFlagRef>( ref ) ) {} + + template<typename LambdaT> + Opt( LambdaT const &ref, std::string const &hint ) : ParserRefImpl( ref, hint ) {} + + template<typename T> + Opt( T &ref, std::string const &hint ) : ParserRefImpl( ref, hint ) {} + + auto operator[]( std::string const &optName ) -> Opt & { + m_optNames.push_back( optName ); + return *this; + } + + auto getHelpColumns() const -> std::vector<HelpColumns> { + std::ostringstream oss; + bool first = true; + for( auto const &opt : m_optNames ) { + if (first) + first = false; + else + oss << ", "; + oss << opt; + } + if( !m_hint.empty() ) + oss << " <" << m_hint << ">"; + return { { oss.str(), m_description } }; + } + + auto isMatch( std::string const &optToken ) const -> bool { + auto normalisedToken = normaliseOpt( optToken ); + for( auto const &name : m_optNames ) { + if( normaliseOpt( name ) == normalisedToken ) + return true; + } + return false; + } + + using ParserBase::parse; + + auto parse( std::string const&, TokenStream const &tokens ) const -> InternalParseResult override { + auto validationResult = validate(); + if( !validationResult ) + return InternalParseResult( validationResult ); + + auto remainingTokens = tokens; + if( remainingTokens && remainingTokens->type == TokenType::Option ) { + auto const &token = *remainingTokens; + if( isMatch(token.token ) ) { + if( m_ref->isFlag() ) { + auto flagRef = static_cast<detail::BoundFlagRefBase*>( m_ref.get() ); + auto result = flagRef->setFlag( true ); + if( !result ) + return InternalParseResult( result ); + if( result.value() == ParseResultType::ShortCircuitAll ) + return InternalParseResult::ok( ParseState( result.value(), remainingTokens ) ); + } else { + auto valueRef = static_cast<detail::BoundValueRefBase*>( m_ref.get() ); + ++remainingTokens; + if( !remainingTokens ) + return InternalParseResult::runtimeError( "Expected argument following " + token.token ); + auto const &argToken = *remainingTokens; + if( argToken.type != TokenType::Argument ) + return InternalParseResult::runtimeError( "Expected argument following " + token.token ); + auto result = valueRef->setValue( argToken.token ); + if( !result ) + return InternalParseResult( result ); + if( result.value() == ParseResultType::ShortCircuitAll ) + return InternalParseResult::ok( ParseState( result.value(), remainingTokens ) ); + } + return InternalParseResult::ok( ParseState( ParseResultType::Matched, ++remainingTokens ) ); + } + } + return InternalParseResult::ok( ParseState( ParseResultType::NoMatch, remainingTokens ) ); + } + + auto validate() const -> Result override { + if( m_optNames.empty() ) + return Result::logicError( "No options supplied to Opt" ); + for( auto const &name : m_optNames ) { + if( name.empty() ) + return Result::logicError( "Option name cannot be empty" ); +#ifdef CATCH_PLATFORM_WINDOWS + if( name[0] != '-' && name[0] != '/' ) + return Result::logicError( "Option name must begin with '-' or '/'" ); +#else + if( name[0] != '-' ) + return Result::logicError( "Option name must begin with '-'" ); +#endif + } + return ParserRefImpl::validate(); + } + }; + + struct Help : Opt { + Help( bool &showHelpFlag ) + : Opt([&]( bool flag ) { + showHelpFlag = flag; + return ParserResult::ok( ParseResultType::ShortCircuitAll ); + }) + { + static_cast<Opt &>( *this ) + ("display usage information") + ["-?"]["-h"]["--help"] + .optional(); + } + }; + + struct Parser : ParserBase { + + mutable ExeName m_exeName; + std::vector<Opt> m_options; + std::vector<Arg> m_args; + + auto operator|=( ExeName const &exeName ) -> Parser & { + m_exeName = exeName; + return *this; + } + + auto operator|=( Arg const &arg ) -> Parser & { + m_args.push_back(arg); + return *this; + } + + auto operator|=( Opt const &opt ) -> Parser & { + m_options.push_back(opt); + return *this; + } + + auto operator|=( Parser const &other ) -> Parser & { + m_options.insert(m_options.end(), other.m_options.begin(), other.m_options.end()); + m_args.insert(m_args.end(), other.m_args.begin(), other.m_args.end()); + return *this; + } + + template<typename T> + auto operator|( T const &other ) const -> Parser { + return Parser( *this ) |= other; + } + + // Forward deprecated interface with '+' instead of '|' + template<typename T> + auto operator+=( T const &other ) -> Parser & { return operator|=( other ); } + template<typename T> + auto operator+( T const &other ) const -> Parser { return operator|( other ); } + + auto getHelpColumns() const -> std::vector<HelpColumns> { + std::vector<HelpColumns> cols; + for (auto const &o : m_options) { + auto childCols = o.getHelpColumns(); + cols.insert( cols.end(), childCols.begin(), childCols.end() ); + } + return cols; + } + + void writeToStream( std::ostream &os ) const { + if (!m_exeName.name().empty()) { + os << "usage:\n" << " " << m_exeName.name() << " "; + bool required = true, first = true; + for( auto const &arg : m_args ) { + if (first) + first = false; + else + os << " "; + if( arg.isOptional() && required ) { + os << "["; + required = false; + } + os << "<" << arg.hint() << ">"; + if( arg.cardinality() == 0 ) + os << " ... "; + } + if( !required ) + os << "]"; + if( !m_options.empty() ) + os << " options"; + os << "\n\nwhere options are:" << std::endl; + } + + auto rows = getHelpColumns(); + size_t consoleWidth = CATCH_CLARA_CONFIG_CONSOLE_WIDTH; + size_t optWidth = 0; + for( auto const &cols : rows ) + optWidth = (std::max)(optWidth, cols.left.size() + 2); + + optWidth = (std::min)(optWidth, consoleWidth/2); + + for( auto const &cols : rows ) { + auto row = + TextFlow::Column( cols.left ).width( optWidth ).indent( 2 ) + + TextFlow::Spacer(4) + + TextFlow::Column( cols.right ).width( consoleWidth - 7 - optWidth ); + os << row << std::endl; + } + } + + friend auto operator<<( std::ostream &os, Parser const &parser ) -> std::ostream& { + parser.writeToStream( os ); + return os; + } + + auto validate() const -> Result override { + for( auto const &opt : m_options ) { + auto result = opt.validate(); + if( !result ) + return result; + } + for( auto const &arg : m_args ) { + auto result = arg.validate(); + if( !result ) + return result; + } + return Result::ok(); + } + + using ParserBase::parse; + + auto parse( std::string const& exeName, TokenStream const &tokens ) const -> InternalParseResult override { + + struct ParserInfo { + ParserBase const* parser = nullptr; + size_t count = 0; + }; + const size_t totalParsers = m_options.size() + m_args.size(); + assert( totalParsers < 512 ); + // ParserInfo parseInfos[totalParsers]; // <-- this is what we really want to do + ParserInfo parseInfos[512]; + + { + size_t i = 0; + for (auto const &opt : m_options) parseInfos[i++].parser = &opt; + for (auto const &arg : m_args) parseInfos[i++].parser = &arg; + } + + m_exeName.set( exeName ); + + auto result = InternalParseResult::ok( ParseState( ParseResultType::NoMatch, tokens ) ); + while( result.value().remainingTokens() ) { + bool tokenParsed = false; + + for( size_t i = 0; i < totalParsers; ++i ) { + auto& parseInfo = parseInfos[i]; + if( parseInfo.parser->cardinality() == 0 || parseInfo.count < parseInfo.parser->cardinality() ) { + result = parseInfo.parser->parse(exeName, result.value().remainingTokens()); + if (!result) + return result; + if (result.value().type() != ParseResultType::NoMatch) { + tokenParsed = true; + ++parseInfo.count; + break; + } + } + } + + if( result.value().type() == ParseResultType::ShortCircuitAll ) + return result; + if( !tokenParsed ) + return InternalParseResult::runtimeError( "Unrecognised token: " + result.value().remainingTokens()->token ); + } + // !TBD Check missing required options + return result; + } + }; + + template<typename DerivedT> + template<typename T> + auto ComposableParserImpl<DerivedT>::operator|( T const &other ) const -> Parser { + return Parser() | static_cast<DerivedT const &>( *this ) | other; + } +} // namespace detail + +// A Combined parser +using detail::Parser; + +// A parser for options +using detail::Opt; + +// A parser for arguments +using detail::Arg; + +// Wrapper for argc, argv from main() +using detail::Args; + +// Specifies the name of the executable +using detail::ExeName; + +// Convenience wrapper for option parser that specifies the help option +using detail::Help; + +// enum of result types from a parse +using detail::ParseResultType; + +// Result type for parser operation +using detail::ParserResult; + +}} // namespace Catch::clara + +// end clara.hpp +#ifdef __clang__ +#pragma clang diagnostic pop +#endif + +// Restore Clara's value for console width, if present +#ifdef CATCH_TEMP_CLARA_CONFIG_CONSOLE_WIDTH +#define CATCH_CLARA_TEXTFLOW_CONFIG_CONSOLE_WIDTH CATCH_TEMP_CLARA_CONFIG_CONSOLE_WIDTH +#undef CATCH_TEMP_CLARA_CONFIG_CONSOLE_WIDTH +#endif + +// end catch_clara.h +namespace Catch { + + clara::Parser makeCommandLineParser( ConfigData& config ); + +} // end namespace Catch + +// end catch_commandline.h +#include <fstream> +#include <ctime> + +namespace Catch { + + clara::Parser makeCommandLineParser( ConfigData& config ) { + + using namespace clara; + + auto const setWarning = [&]( std::string const& warning ) { + auto warningSet = [&]() { + if( warning == "NoAssertions" ) + return WarnAbout::NoAssertions; + + if ( warning == "NoTests" ) + return WarnAbout::NoTests; + + return WarnAbout::Nothing; + }(); + + if (warningSet == WarnAbout::Nothing) + return ParserResult::runtimeError( "Unrecognised warning: '" + warning + "'" ); + config.warnings = static_cast<WarnAbout::What>( config.warnings | warningSet ); + return ParserResult::ok( ParseResultType::Matched ); + }; + auto const loadTestNamesFromFile = [&]( std::string const& filename ) { + std::ifstream f( filename.c_str() ); + if( !f.is_open() ) + return ParserResult::runtimeError( "Unable to load input file: '" + filename + "'" ); + + std::string line; + while( std::getline( f, line ) ) { + line = trim(line); + if( !line.empty() && !startsWith( line, '#' ) ) { + if( !startsWith( line, '"' ) ) + line = '"' + line + '"'; + config.testsOrTags.push_back( line ); + config.testsOrTags.emplace_back( "," ); + } + } + //Remove comma in the end + if(!config.testsOrTags.empty()) + config.testsOrTags.erase( config.testsOrTags.end()-1 ); + + return ParserResult::ok( ParseResultType::Matched ); + }; + auto const setTestOrder = [&]( std::string const& order ) { + if( startsWith( "declared", order ) ) + config.runOrder = RunTests::InDeclarationOrder; + else if( startsWith( "lexical", order ) ) + config.runOrder = RunTests::InLexicographicalOrder; + else if( startsWith( "random", order ) ) + config.runOrder = RunTests::InRandomOrder; + else + return clara::ParserResult::runtimeError( "Unrecognised ordering: '" + order + "'" ); + return ParserResult::ok( ParseResultType::Matched ); + }; + auto const setRngSeed = [&]( std::string const& seed ) { + if( seed != "time" ) + return clara::detail::convertInto( seed, config.rngSeed ); + config.rngSeed = static_cast<unsigned int>( std::time(nullptr) ); + return ParserResult::ok( ParseResultType::Matched ); + }; + auto const setColourUsage = [&]( std::string const& useColour ) { + auto mode = toLower( useColour ); + + if( mode == "yes" ) + config.useColour = UseColour::Yes; + else if( mode == "no" ) + config.useColour = UseColour::No; + else if( mode == "auto" ) + config.useColour = UseColour::Auto; + else + return ParserResult::runtimeError( "colour mode must be one of: auto, yes or no. '" + useColour + "' not recognised" ); + return ParserResult::ok( ParseResultType::Matched ); + }; + auto const setWaitForKeypress = [&]( std::string const& keypress ) { + auto keypressLc = toLower( keypress ); + if (keypressLc == "never") + config.waitForKeypress = WaitForKeypress::Never; + else if( keypressLc == "start" ) + config.waitForKeypress = WaitForKeypress::BeforeStart; + else if( keypressLc == "exit" ) + config.waitForKeypress = WaitForKeypress::BeforeExit; + else if( keypressLc == "both" ) + config.waitForKeypress = WaitForKeypress::BeforeStartAndExit; + else + return ParserResult::runtimeError( "keypress argument must be one of: never, start, exit or both. '" + keypress + "' not recognised" ); + return ParserResult::ok( ParseResultType::Matched ); + }; + auto const setVerbosity = [&]( std::string const& verbosity ) { + auto lcVerbosity = toLower( verbosity ); + if( lcVerbosity == "quiet" ) + config.verbosity = Verbosity::Quiet; + else if( lcVerbosity == "normal" ) + config.verbosity = Verbosity::Normal; + else if( lcVerbosity == "high" ) + config.verbosity = Verbosity::High; + else + return ParserResult::runtimeError( "Unrecognised verbosity, '" + verbosity + "'" ); + return ParserResult::ok( ParseResultType::Matched ); + }; + auto const setReporter = [&]( std::string const& reporter ) { + IReporterRegistry::FactoryMap const& factories = getRegistryHub().getReporterRegistry().getFactories(); + + auto lcReporter = toLower( reporter ); + auto result = factories.find( lcReporter ); + + if( factories.end() != result ) + config.reporterName = lcReporter; + else + return ParserResult::runtimeError( "Unrecognized reporter, '" + reporter + "'. Check available with --list-reporters" ); + return ParserResult::ok( ParseResultType::Matched ); + }; + + auto cli + = ExeName( config.processName ) + | Help( config.showHelp ) + | Opt( config.listTests ) + ["-l"]["--list-tests"] + ( "list all/matching test cases" ) + | Opt( config.listTags ) + ["-t"]["--list-tags"] + ( "list all/matching tags" ) + | Opt( config.showSuccessfulTests ) + ["-s"]["--success"] + ( "include successful tests in output" ) + | Opt( config.shouldDebugBreak ) + ["-b"]["--break"] + ( "break into debugger on failure" ) + | Opt( config.noThrow ) + ["-e"]["--nothrow"] + ( "skip exception tests" ) + | Opt( config.showInvisibles ) + ["-i"]["--invisibles"] + ( "show invisibles (tabs, newlines)" ) + | Opt( config.outputFilename, "filename" ) + ["-o"]["--out"] + ( "output filename" ) + | Opt( setReporter, "name" ) + ["-r"]["--reporter"] + ( "reporter to use (defaults to console)" ) + | Opt( config.name, "name" ) + ["-n"]["--name"] + ( "suite name" ) + | Opt( [&]( bool ){ config.abortAfter = 1; } ) + ["-a"]["--abort"] + ( "abort at first failure" ) + | Opt( [&]( int x ){ config.abortAfter = x; }, "no. failures" ) + ["-x"]["--abortx"] + ( "abort after x failures" ) + | Opt( setWarning, "warning name" ) + ["-w"]["--warn"] + ( "enable warnings" ) + | Opt( [&]( bool flag ) { config.showDurations = flag ? ShowDurations::Always : ShowDurations::Never; }, "yes|no" ) + ["-d"]["--durations"] + ( "show test durations" ) + | Opt( config.minDuration, "seconds" ) + ["-D"]["--min-duration"] + ( "show test durations for tests taking at least the given number of seconds" ) + | Opt( loadTestNamesFromFile, "filename" ) + ["-f"]["--input-file"] + ( "load test names to run from a file" ) + | Opt( config.filenamesAsTags ) + ["-#"]["--filenames-as-tags"] + ( "adds a tag for the filename" ) + | Opt( config.sectionsToRun, "section name" ) + ["-c"]["--section"] + ( "specify section to run" ) + | Opt( setVerbosity, "quiet|normal|high" ) + ["-v"]["--verbosity"] + ( "set output verbosity" ) + | Opt( config.listTestNamesOnly ) + ["--list-test-names-only"] + ( "list all/matching test cases names only" ) + | Opt( config.listReporters ) + ["--list-reporters"] + ( "list all reporters" ) + | Opt( setTestOrder, "decl|lex|rand" ) + ["--order"] + ( "test case order (defaults to decl)" ) + | Opt( setRngSeed, "'time'|number" ) + ["--rng-seed"] + ( "set a specific seed for random numbers" ) + | Opt( setColourUsage, "yes|no" ) + ["--use-colour"] + ( "should output be colourised" ) + | Opt( config.libIdentify ) + ["--libidentify"] + ( "report name and version according to libidentify standard" ) + | Opt( setWaitForKeypress, "never|start|exit|both" ) + ["--wait-for-keypress"] + ( "waits for a keypress before exiting" ) + | Opt( config.benchmarkSamples, "samples" ) + ["--benchmark-samples"] + ( "number of samples to collect (default: 100)" ) + | Opt( config.benchmarkResamples, "resamples" ) + ["--benchmark-resamples"] + ( "number of resamples for the bootstrap (default: 100000)" ) + | Opt( config.benchmarkConfidenceInterval, "confidence interval" ) + ["--benchmark-confidence-interval"] + ( "confidence interval for the bootstrap (between 0 and 1, default: 0.95)" ) + | Opt( config.benchmarkNoAnalysis ) + ["--benchmark-no-analysis"] + ( "perform only measurements; do not perform any analysis" ) + | Opt( config.benchmarkWarmupTime, "benchmarkWarmupTime" ) + ["--benchmark-warmup-time"] + ( "amount of time in milliseconds spent on warming up each test (default: 100)" ) + | Arg( config.testsOrTags, "test name|pattern|tags" ) + ( "which test or tests to use" ); + + return cli; + } + +} // end namespace Catch +// end catch_commandline.cpp +// start catch_common.cpp + +#include <cstring> +#include <ostream> + +namespace Catch { + + bool SourceLineInfo::operator == ( SourceLineInfo const& other ) const noexcept { + return line == other.line && (file == other.file || std::strcmp(file, other.file) == 0); + } + bool SourceLineInfo::operator < ( SourceLineInfo const& other ) const noexcept { + // We can assume that the same file will usually have the same pointer. + // Thus, if the pointers are the same, there is no point in calling the strcmp + return line < other.line || ( line == other.line && file != other.file && (std::strcmp(file, other.file) < 0)); + } + + std::ostream& operator << ( std::ostream& os, SourceLineInfo const& info ) { +#ifndef __GNUG__ + os << info.file << '(' << info.line << ')'; +#else + os << info.file << ':' << info.line; +#endif + return os; + } + + std::string StreamEndStop::operator+() const { + return std::string(); + } + + NonCopyable::NonCopyable() = default; + NonCopyable::~NonCopyable() = default; + +} +// end catch_common.cpp +// start catch_config.cpp + +namespace Catch { + + Config::Config( ConfigData const& data ) + : m_data( data ), + m_stream( openStream() ) + { + // We need to trim filter specs to avoid trouble with superfluous + // whitespace (esp. important for bdd macros, as those are manually + // aligned with whitespace). + + for (auto& elem : m_data.testsOrTags) { + elem = trim(elem); + } + for (auto& elem : m_data.sectionsToRun) { + elem = trim(elem); + } + + TestSpecParser parser(ITagAliasRegistry::get()); + if (!m_data.testsOrTags.empty()) { + m_hasTestFilters = true; + for (auto const& testOrTags : m_data.testsOrTags) { + parser.parse(testOrTags); + } + } + m_testSpec = parser.testSpec(); + } + + std::string const& Config::getFilename() const { + return m_data.outputFilename ; + } + + bool Config::listTests() const { return m_data.listTests; } + bool Config::listTestNamesOnly() const { return m_data.listTestNamesOnly; } + bool Config::listTags() const { return m_data.listTags; } + bool Config::listReporters() const { return m_data.listReporters; } + + std::string Config::getProcessName() const { return m_data.processName; } + std::string const& Config::getReporterName() const { return m_data.reporterName; } + + std::vector<std::string> const& Config::getTestsOrTags() const { return m_data.testsOrTags; } + std::vector<std::string> const& Config::getSectionsToRun() const { return m_data.sectionsToRun; } + + TestSpec const& Config::testSpec() const { return m_testSpec; } + bool Config::hasTestFilters() const { return m_hasTestFilters; } + + bool Config::showHelp() const { return m_data.showHelp; } + + // IConfig interface + bool Config::allowThrows() const { return !m_data.noThrow; } + std::ostream& Config::stream() const { return m_stream->stream(); } + std::string Config::name() const { return m_data.name.empty() ? m_data.processName : m_data.name; } + bool Config::includeSuccessfulResults() const { return m_data.showSuccessfulTests; } + bool Config::warnAboutMissingAssertions() const { return !!(m_data.warnings & WarnAbout::NoAssertions); } + bool Config::warnAboutNoTests() const { return !!(m_data.warnings & WarnAbout::NoTests); } + ShowDurations::OrNot Config::showDurations() const { return m_data.showDurations; } + double Config::minDuration() const { return m_data.minDuration; } + RunTests::InWhatOrder Config::runOrder() const { return m_data.runOrder; } + unsigned int Config::rngSeed() const { return m_data.rngSeed; } + UseColour::YesOrNo Config::useColour() const { return m_data.useColour; } + bool Config::shouldDebugBreak() const { return m_data.shouldDebugBreak; } + int Config::abortAfter() const { return m_data.abortAfter; } + bool Config::showInvisibles() const { return m_data.showInvisibles; } + Verbosity Config::verbosity() const { return m_data.verbosity; } + + bool Config::benchmarkNoAnalysis() const { return m_data.benchmarkNoAnalysis; } + int Config::benchmarkSamples() const { return m_data.benchmarkSamples; } + double Config::benchmarkConfidenceInterval() const { return m_data.benchmarkConfidenceInterval; } + unsigned int Config::benchmarkResamples() const { return m_data.benchmarkResamples; } + std::chrono::milliseconds Config::benchmarkWarmupTime() const { return std::chrono::milliseconds(m_data.benchmarkWarmupTime); } + + IStream const* Config::openStream() { + return Catch::makeStream(m_data.outputFilename); + } + +} // end namespace Catch +// end catch_config.cpp +// start catch_console_colour.cpp + +#if defined(__clang__) +# pragma clang diagnostic push +# pragma clang diagnostic ignored "-Wexit-time-destructors" +#endif + +// start catch_errno_guard.h + +namespace Catch { + + class ErrnoGuard { + public: + ErrnoGuard(); + ~ErrnoGuard(); + private: + int m_oldErrno; + }; + +} + +// end catch_errno_guard.h +// start catch_windows_h_proxy.h + + +#if defined(CATCH_PLATFORM_WINDOWS) + +#if !defined(NOMINMAX) && !defined(CATCH_CONFIG_NO_NOMINMAX) +# define CATCH_DEFINED_NOMINMAX +# define NOMINMAX +#endif +#if !defined(WIN32_LEAN_AND_MEAN) && !defined(CATCH_CONFIG_NO_WIN32_LEAN_AND_MEAN) +# define CATCH_DEFINED_WIN32_LEAN_AND_MEAN +# define WIN32_LEAN_AND_MEAN +#endif + +#ifdef __AFXDLL +#include <AfxWin.h> +#else +#include <windows.h> +#endif + +#ifdef CATCH_DEFINED_NOMINMAX +# undef NOMINMAX +#endif +#ifdef CATCH_DEFINED_WIN32_LEAN_AND_MEAN +# undef WIN32_LEAN_AND_MEAN +#endif + +#endif // defined(CATCH_PLATFORM_WINDOWS) + +// end catch_windows_h_proxy.h +#include <sstream> + +namespace Catch { + namespace { + + struct IColourImpl { + virtual ~IColourImpl() = default; + virtual void use( Colour::Code _colourCode ) = 0; + }; + + struct NoColourImpl : IColourImpl { + void use( Colour::Code ) override {} + + static IColourImpl* instance() { + static NoColourImpl s_instance; + return &s_instance; + } + }; + + } // anon namespace +} // namespace Catch + +#if !defined( CATCH_CONFIG_COLOUR_NONE ) && !defined( CATCH_CONFIG_COLOUR_WINDOWS ) && !defined( CATCH_CONFIG_COLOUR_ANSI ) +# ifdef CATCH_PLATFORM_WINDOWS +# define CATCH_CONFIG_COLOUR_WINDOWS +# else +# define CATCH_CONFIG_COLOUR_ANSI +# endif +#endif + +#if defined ( CATCH_CONFIG_COLOUR_WINDOWS ) ///////////////////////////////////////// + +namespace Catch { +namespace { + + class Win32ColourImpl : public IColourImpl { + public: + Win32ColourImpl() : stdoutHandle( GetStdHandle(STD_OUTPUT_HANDLE) ) + { + CONSOLE_SCREEN_BUFFER_INFO csbiInfo; + GetConsoleScreenBufferInfo( stdoutHandle, &csbiInfo ); + originalForegroundAttributes = csbiInfo.wAttributes & ~( BACKGROUND_GREEN | BACKGROUND_RED | BACKGROUND_BLUE | BACKGROUND_INTENSITY ); + originalBackgroundAttributes = csbiInfo.wAttributes & ~( FOREGROUND_GREEN | FOREGROUND_RED | FOREGROUND_BLUE | FOREGROUND_INTENSITY ); + } + + void use( Colour::Code _colourCode ) override { + switch( _colourCode ) { + 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 ); + case Colour::Blue: return setTextAttribute( FOREGROUND_BLUE ); + case Colour::Cyan: return setTextAttribute( FOREGROUND_BLUE | FOREGROUND_GREEN ); + case Colour::Yellow: return setTextAttribute( FOREGROUND_RED | FOREGROUND_GREEN ); + case Colour::Grey: return setTextAttribute( 0 ); + + case Colour::LightGrey: return setTextAttribute( FOREGROUND_INTENSITY ); + case Colour::BrightRed: return setTextAttribute( FOREGROUND_INTENSITY | FOREGROUND_RED ); + case Colour::BrightGreen: return setTextAttribute( FOREGROUND_INTENSITY | FOREGROUND_GREEN ); + case Colour::BrightWhite: return setTextAttribute( FOREGROUND_INTENSITY | FOREGROUND_GREEN | FOREGROUND_RED | FOREGROUND_BLUE ); + case Colour::BrightYellow: return setTextAttribute( FOREGROUND_INTENSITY | FOREGROUND_RED | FOREGROUND_GREEN ); + + case Colour::Bright: CATCH_INTERNAL_ERROR( "not a colour" ); + + default: + CATCH_ERROR( "Unknown colour requested" ); + } + } + + private: + void setTextAttribute( WORD _textAttribute ) { + SetConsoleTextAttribute( stdoutHandle, _textAttribute | originalBackgroundAttributes ); + } + HANDLE stdoutHandle; + WORD originalForegroundAttributes; + WORD originalBackgroundAttributes; + }; + + IColourImpl* platformColourInstance() { + static Win32ColourImpl s_instance; + + IConfigPtr config = getCurrentContext().getConfig(); + UseColour::YesOrNo colourMode = config + ? config->useColour() + : UseColour::Auto; + if( colourMode == UseColour::Auto ) + colourMode = UseColour::Yes; + return colourMode == UseColour::Yes + ? &s_instance + : NoColourImpl::instance(); + } + +} // end anon namespace +} // end namespace Catch + +#elif defined( CATCH_CONFIG_COLOUR_ANSI ) ////////////////////////////////////// + +#include <unistd.h> + +namespace Catch { +namespace { + + // use POSIX/ ANSI console terminal codes + // Thanks to Adam Strzelecki for original contribution + // (http://github.com/nanoant) + // https://github.com/philsquared/Catch/pull/131 + class PosixColourImpl : public IColourImpl { + public: + void use( Colour::Code _colourCode ) override { + switch( _colourCode ) { + case Colour::None: + case Colour::White: return setColour( "[0m" ); + case Colour::Red: return setColour( "[0;31m" ); + case Colour::Green: return setColour( "[0;32m" ); + case Colour::Blue: return setColour( "[0;34m" ); + case Colour::Cyan: return setColour( "[0;36m" ); + case Colour::Yellow: return setColour( "[0;33m" ); + case Colour::Grey: return setColour( "[1;30m" ); + + case Colour::LightGrey: return setColour( "[0;37m" ); + case Colour::BrightRed: return setColour( "[1;31m" ); + case Colour::BrightGreen: return setColour( "[1;32m" ); + case Colour::BrightWhite: return setColour( "[1;37m" ); + case Colour::BrightYellow: return setColour( "[1;33m" ); + + case Colour::Bright: CATCH_INTERNAL_ERROR( "not a colour" ); + default: CATCH_INTERNAL_ERROR( "Unknown colour requested" ); + } + } + static IColourImpl* instance() { + static PosixColourImpl s_instance; + return &s_instance; + } + + private: + void setColour( const char* _escapeCode ) { + getCurrentContext().getConfig()->stream() + << '\033' << _escapeCode; + } + }; + + bool useColourOnPlatform() { + return +#if defined(CATCH_PLATFORM_MAC) || defined(CATCH_PLATFORM_IPHONE) + !isDebuggerActive() && +#endif +#if !(defined(__DJGPP__) && defined(__STRICT_ANSI__)) + isatty(STDOUT_FILENO) +#else + false +#endif + ; + } + IColourImpl* platformColourInstance() { + ErrnoGuard guard; + IConfigPtr config = getCurrentContext().getConfig(); + UseColour::YesOrNo colourMode = config + ? config->useColour() + : UseColour::Auto; + if( colourMode == UseColour::Auto ) + colourMode = useColourOnPlatform() + ? UseColour::Yes + : UseColour::No; + return colourMode == UseColour::Yes + ? PosixColourImpl::instance() + : NoColourImpl::instance(); + } + +} // end anon namespace +} // end namespace Catch + +#else // not Windows or ANSI /////////////////////////////////////////////// + +namespace Catch { + + static IColourImpl* platformColourInstance() { return NoColourImpl::instance(); } + +} // end namespace Catch + +#endif // Windows/ ANSI/ None + +namespace Catch { + + Colour::Colour( Code _colourCode ) { use( _colourCode ); } + Colour::Colour( Colour&& other ) noexcept { + m_moved = other.m_moved; + other.m_moved = true; + } + Colour& Colour::operator=( Colour&& other ) noexcept { + m_moved = other.m_moved; + other.m_moved = true; + return *this; + } + + Colour::~Colour(){ if( !m_moved ) use( None ); } + + void Colour::use( Code _colourCode ) { + static IColourImpl* impl = platformColourInstance(); + // Strictly speaking, this cannot possibly happen. + // However, under some conditions it does happen (see #1626), + // and this change is small enough that we can let practicality + // triumph over purity in this case. + if (impl != nullptr) { + impl->use( _colourCode ); + } + } + + std::ostream& operator << ( std::ostream& os, Colour const& ) { + return os; + } + +} // end namespace Catch + +#if defined(__clang__) +# pragma clang diagnostic pop +#endif + +// end catch_console_colour.cpp +// start catch_context.cpp + +namespace Catch { + + class Context : public IMutableContext, NonCopyable { + + public: // IContext + IResultCapture* getResultCapture() override { + return m_resultCapture; + } + IRunner* getRunner() override { + return m_runner; + } + + IConfigPtr const& getConfig() const override { + return m_config; + } + + ~Context() override; + + public: // IMutableContext + void setResultCapture( IResultCapture* resultCapture ) override { + m_resultCapture = resultCapture; + } + void setRunner( IRunner* runner ) override { + m_runner = runner; + } + void setConfig( IConfigPtr const& config ) override { + m_config = config; + } + + friend IMutableContext& getCurrentMutableContext(); + + private: + IConfigPtr m_config; + IRunner* m_runner = nullptr; + IResultCapture* m_resultCapture = nullptr; + }; + + IMutableContext *IMutableContext::currentContext = nullptr; + + void IMutableContext::createContext() + { + currentContext = new Context(); + } + + void cleanUpContext() { + delete IMutableContext::currentContext; + IMutableContext::currentContext = nullptr; + } + IContext::~IContext() = default; + IMutableContext::~IMutableContext() = default; + Context::~Context() = default; + + SimplePcg32& rng() { + static SimplePcg32 s_rng; + return s_rng; + } + +} +// end catch_context.cpp +// start catch_debug_console.cpp + +// start catch_debug_console.h + +#include <string> + +namespace Catch { + void writeToDebugConsole( std::string const& text ); +} + +// end catch_debug_console.h +#if defined(CATCH_CONFIG_ANDROID_LOGWRITE) +#include <android/log.h> + + namespace Catch { + void writeToDebugConsole( std::string const& text ) { + __android_log_write( ANDROID_LOG_DEBUG, "Catch", text.c_str() ); + } + } + +#elif defined(CATCH_PLATFORM_WINDOWS) + + namespace Catch { + void writeToDebugConsole( std::string const& text ) { + ::OutputDebugStringA( text.c_str() ); + } + } + +#else + + namespace Catch { + void writeToDebugConsole( std::string const& text ) { + // !TBD: Need a version for Mac/ XCode and other IDEs + Catch::cout() << text; + } + } + +#endif // Platform +// end catch_debug_console.cpp +// start catch_debugger.cpp + +#if defined(CATCH_PLATFORM_MAC) || defined(CATCH_PLATFORM_IPHONE) + +# include <cassert> +# include <sys/types.h> +# include <unistd.h> +# include <cstddef> +# include <ostream> + +#ifdef __apple_build_version__ + // These headers will only compile with AppleClang (XCode) + // For other compilers (Clang, GCC, ... ) we need to exclude them +# include <sys/sysctl.h> +#endif + + namespace Catch { + #ifdef __apple_build_version__ + // The following function is taken directly from the following technical note: + // https://developer.apple.com/library/archive/qa/qa1361/_index.html + + // Returns true if the current process is being debugged (either + // running under the debugger or has a debugger attached post facto). + bool isDebuggerActive(){ + int mib[4]; + struct kinfo_proc info; + std::size_t size; + + // Initialize the flags so that, if sysctl fails for some bizarre + // reason, we get a predictable result. + + info.kp_proc.p_flag = 0; + + // Initialize mib, which tells sysctl the info we want, in this case + // we're looking for information about a specific process ID. + + mib[0] = CTL_KERN; + mib[1] = KERN_PROC; + mib[2] = KERN_PROC_PID; + mib[3] = getpid(); + + // Call sysctl. + + size = sizeof(info); + if( sysctl(mib, sizeof(mib) / sizeof(*mib), &info, &size, nullptr, 0) != 0 ) { + Catch::cerr() << "\n** Call to sysctl failed - unable to determine if debugger is active **\n" << std::endl; + return false; + } + + // We're being debugged if the P_TRACED flag is set. + + return ( (info.kp_proc.p_flag & P_TRACED) != 0 ); + } + #else + bool isDebuggerActive() { + // We need to find another way to determine this for non-appleclang compilers on macOS + return false; + } + #endif + } // namespace Catch + +#elif defined(CATCH_PLATFORM_LINUX) + #include <fstream> + #include <string> + + namespace Catch{ + // The standard POSIX way of detecting a debugger is to attempt to + // ptrace() the process, but this needs to be done from a child and not + // this process itself to still allow attaching to this process later + // if wanted, so is rather heavy. Under Linux we have the PID of the + // "debugger" (which doesn't need to be gdb, of course, it could also + // be strace, for example) in /proc/$PID/status, so just get it from + // there instead. + bool isDebuggerActive(){ + // Libstdc++ has a bug, where std::ifstream sets errno to 0 + // This way our users can properly assert over errno values + ErrnoGuard guard; + std::ifstream in("/proc/self/status"); + for( std::string line; std::getline(in, line); ) { + static const int PREFIX_LEN = 11; + if( line.compare(0, PREFIX_LEN, "TracerPid:\t") == 0 ) { + // We're traced if the PID is not 0 and no other PID starts + // with 0 digit, so it's enough to check for just a single + // character. + return line.length() > PREFIX_LEN && line[PREFIX_LEN] != '0'; + } + } + + return false; + } + } // namespace Catch +#elif defined(_MSC_VER) + extern "C" __declspec(dllimport) int __stdcall IsDebuggerPresent(); + namespace Catch { + bool isDebuggerActive() { + return IsDebuggerPresent() != 0; + } + } +#elif defined(__MINGW32__) + extern "C" __declspec(dllimport) int __stdcall IsDebuggerPresent(); + namespace Catch { + bool isDebuggerActive() { + return IsDebuggerPresent() != 0; + } + } +#else + namespace Catch { + bool isDebuggerActive() { return false; } + } +#endif // Platform +// end catch_debugger.cpp +// start catch_decomposer.cpp + +namespace Catch { + + ITransientExpression::~ITransientExpression() = default; + + void formatReconstructedExpression( std::ostream &os, std::string const& lhs, StringRef op, std::string const& rhs ) { + if( lhs.size() + rhs.size() < 40 && + lhs.find('\n') == std::string::npos && + rhs.find('\n') == std::string::npos ) + os << lhs << " " << op << " " << rhs; + else + os << lhs << "\n" << op << "\n" << rhs; + } +} +// end catch_decomposer.cpp +// start catch_enforce.cpp + +#include <stdexcept> + +namespace Catch { +#if defined(CATCH_CONFIG_DISABLE_EXCEPTIONS) && !defined(CATCH_CONFIG_DISABLE_EXCEPTIONS_CUSTOM_HANDLER) + [[noreturn]] + void throw_exception(std::exception const& e) { + Catch::cerr() << "Catch will terminate because it needed to throw an exception.\n" + << "The message was: " << e.what() << '\n'; + std::terminate(); + } +#endif + + [[noreturn]] + void throw_logic_error(std::string const& msg) { + throw_exception(std::logic_error(msg)); + } + + [[noreturn]] + void throw_domain_error(std::string const& msg) { + throw_exception(std::domain_error(msg)); + } + + [[noreturn]] + void throw_runtime_error(std::string const& msg) { + throw_exception(std::runtime_error(msg)); + } + +} // namespace Catch; +// end catch_enforce.cpp +// start catch_enum_values_registry.cpp +// start catch_enum_values_registry.h + +#include <vector> +#include <memory> + +namespace Catch { + + namespace Detail { + + std::unique_ptr<EnumInfo> makeEnumInfo( StringRef enumName, StringRef allValueNames, std::vector<int> const& values ); + + class EnumValuesRegistry : public IMutableEnumValuesRegistry { + + std::vector<std::unique_ptr<EnumInfo>> m_enumInfos; + + EnumInfo const& registerEnum( StringRef enumName, StringRef allEnums, std::vector<int> const& values) override; + }; + + std::vector<StringRef> parseEnums( StringRef enums ); + + } // Detail + +} // Catch + +// end catch_enum_values_registry.h + +#include <map> +#include <cassert> + +namespace Catch { + + IMutableEnumValuesRegistry::~IMutableEnumValuesRegistry() {} + + namespace Detail { + + namespace { + // Extracts the actual name part of an enum instance + // In other words, it returns the Blue part of Bikeshed::Colour::Blue + StringRef extractInstanceName(StringRef enumInstance) { + // Find last occurrence of ":" + size_t name_start = enumInstance.size(); + while (name_start > 0 && enumInstance[name_start - 1] != ':') { + --name_start; + } + return enumInstance.substr(name_start, enumInstance.size() - name_start); + } + } + + std::vector<StringRef> parseEnums( StringRef enums ) { + auto enumValues = splitStringRef( enums, ',' ); + std::vector<StringRef> parsed; + parsed.reserve( enumValues.size() ); + for( auto const& enumValue : enumValues ) { + parsed.push_back(trim(extractInstanceName(enumValue))); + } + return parsed; + } + + EnumInfo::~EnumInfo() {} + + StringRef EnumInfo::lookup( int value ) const { + for( auto const& valueToName : m_values ) { + if( valueToName.first == value ) + return valueToName.second; + } + return "{** unexpected enum value **}"_sr; + } + + std::unique_ptr<EnumInfo> makeEnumInfo( StringRef enumName, StringRef allValueNames, std::vector<int> const& values ) { + std::unique_ptr<EnumInfo> enumInfo( new EnumInfo ); + enumInfo->m_name = enumName; + enumInfo->m_values.reserve( values.size() ); + + const auto valueNames = Catch::Detail::parseEnums( allValueNames ); + assert( valueNames.size() == values.size() ); + std::size_t i = 0; + for( auto value : values ) + enumInfo->m_values.emplace_back(value, valueNames[i++]); + + return enumInfo; + } + + EnumInfo const& EnumValuesRegistry::registerEnum( StringRef enumName, StringRef allValueNames, std::vector<int> const& values ) { + m_enumInfos.push_back(makeEnumInfo(enumName, allValueNames, values)); + return *m_enumInfos.back(); + } + + } // Detail +} // Catch + +// end catch_enum_values_registry.cpp +// start catch_errno_guard.cpp + +#include <cerrno> + +namespace Catch { + ErrnoGuard::ErrnoGuard():m_oldErrno(errno){} + ErrnoGuard::~ErrnoGuard() { errno = m_oldErrno; } +} +// end catch_errno_guard.cpp +// start catch_exception_translator_registry.cpp + +// start catch_exception_translator_registry.h + +#include <vector> +#include <string> +#include <memory> + +namespace Catch { + + class ExceptionTranslatorRegistry : public IExceptionTranslatorRegistry { + public: + ~ExceptionTranslatorRegistry(); + virtual void registerTranslator( const IExceptionTranslator* translator ); + std::string translateActiveException() const override; + std::string tryTranslators() const; + + private: + std::vector<std::unique_ptr<IExceptionTranslator const>> m_translators; + }; +} + +// end catch_exception_translator_registry.h +#ifdef __OBJC__ +#import "Foundation/Foundation.h" +#endif + +namespace Catch { + + ExceptionTranslatorRegistry::~ExceptionTranslatorRegistry() { + } + + void ExceptionTranslatorRegistry::registerTranslator( const IExceptionTranslator* translator ) { + m_translators.push_back( std::unique_ptr<const IExceptionTranslator>( translator ) ); + } + +#if !defined(CATCH_CONFIG_DISABLE_EXCEPTIONS) + std::string ExceptionTranslatorRegistry::translateActiveException() const { + try { +#ifdef __OBJC__ + // In Objective-C try objective-c exceptions first + @try { + return tryTranslators(); + } + @catch (NSException *exception) { + return Catch::Detail::stringify( [exception description] ); + } +#else + // Compiling a mixed mode project with MSVC means that CLR + // exceptions will be caught in (...) as well. However, these + // do not fill-in std::current_exception and thus lead to crash + // when attempting rethrow. + // /EHa switch also causes structured exceptions to be caught + // here, but they fill-in current_exception properly, so + // at worst the output should be a little weird, instead of + // causing a crash. + if (std::current_exception() == nullptr) { + return "Non C++ exception. Possibly a CLR exception."; + } + return tryTranslators(); +#endif + } + catch( TestFailureException& ) { + std::rethrow_exception(std::current_exception()); + } + catch( std::exception& ex ) { + return ex.what(); + } + catch( std::string& msg ) { + return msg; + } + catch( const char* msg ) { + return msg; + } + catch(...) { + return "Unknown exception"; + } + } + + std::string ExceptionTranslatorRegistry::tryTranslators() const { + if (m_translators.empty()) { + std::rethrow_exception(std::current_exception()); + } else { + return m_translators[0]->translate(m_translators.begin() + 1, m_translators.end()); + } + } + +#else // ^^ Exceptions are enabled // Exceptions are disabled vv + std::string ExceptionTranslatorRegistry::translateActiveException() const { + CATCH_INTERNAL_ERROR("Attempted to translate active exception under CATCH_CONFIG_DISABLE_EXCEPTIONS!"); + } + + std::string ExceptionTranslatorRegistry::tryTranslators() const { + CATCH_INTERNAL_ERROR("Attempted to use exception translators under CATCH_CONFIG_DISABLE_EXCEPTIONS!"); + } +#endif + +} +// end catch_exception_translator_registry.cpp +// start catch_fatal_condition.cpp + +#include <algorithm> + +#if !defined( CATCH_CONFIG_WINDOWS_SEH ) && !defined( CATCH_CONFIG_POSIX_SIGNALS ) + +namespace Catch { + + // If neither SEH nor signal handling is required, the handler impls + // do not have to do anything, and can be empty. + void FatalConditionHandler::engage_platform() {} + void FatalConditionHandler::disengage_platform() {} + FatalConditionHandler::FatalConditionHandler() = default; + FatalConditionHandler::~FatalConditionHandler() = default; + +} // end namespace Catch + +#endif // !CATCH_CONFIG_WINDOWS_SEH && !CATCH_CONFIG_POSIX_SIGNALS + +#if defined( CATCH_CONFIG_WINDOWS_SEH ) && defined( CATCH_CONFIG_POSIX_SIGNALS ) +#error "Inconsistent configuration: Windows' SEH handling and POSIX signals cannot be enabled at the same time" +#endif // CATCH_CONFIG_WINDOWS_SEH && CATCH_CONFIG_POSIX_SIGNALS + +#if defined( CATCH_CONFIG_WINDOWS_SEH ) || defined( CATCH_CONFIG_POSIX_SIGNALS ) + +namespace { + //! Signals fatal error message to the run context + void reportFatal( char const * const message ) { + Catch::getCurrentContext().getResultCapture()->handleFatalErrorCondition( message ); + } + + //! Minimal size Catch2 needs for its own fatal error handling. + //! Picked anecdotally, so it might not be sufficient on all + //! platforms, and for all configurations. + constexpr std::size_t minStackSizeForErrors = 32 * 1024; +} // end unnamed namespace + +#endif // CATCH_CONFIG_WINDOWS_SEH || CATCH_CONFIG_POSIX_SIGNALS + +#if defined( CATCH_CONFIG_WINDOWS_SEH ) + +namespace Catch { + + struct SignalDefs { DWORD id; const char* name; }; + + // There is no 1-1 mapping between signals and windows exceptions. + // Windows can easily distinguish between SO and SigSegV, + // but SigInt, SigTerm, etc are handled differently. + static SignalDefs signalDefs[] = { + { static_cast<DWORD>(EXCEPTION_ILLEGAL_INSTRUCTION), "SIGILL - Illegal instruction signal" }, + { static_cast<DWORD>(EXCEPTION_STACK_OVERFLOW), "SIGSEGV - Stack overflow" }, + { static_cast<DWORD>(EXCEPTION_ACCESS_VIOLATION), "SIGSEGV - Segmentation violation signal" }, + { static_cast<DWORD>(EXCEPTION_INT_DIVIDE_BY_ZERO), "Divide by zero error" }, + }; + + static LONG CALLBACK handleVectoredException(PEXCEPTION_POINTERS ExceptionInfo) { + for (auto const& def : signalDefs) { + if (ExceptionInfo->ExceptionRecord->ExceptionCode == def.id) { + reportFatal(def.name); + } + } + // If its not an exception we care about, pass it along. + // This stops us from eating debugger breaks etc. + return EXCEPTION_CONTINUE_SEARCH; + } + + // Since we do not support multiple instantiations, we put these + // into global variables and rely on cleaning them up in outlined + // constructors/destructors + static PVOID exceptionHandlerHandle = nullptr; + + // For MSVC, we reserve part of the stack memory for handling + // memory overflow structured exception. + FatalConditionHandler::FatalConditionHandler() { + ULONG guaranteeSize = static_cast<ULONG>(minStackSizeForErrors); + if (!SetThreadStackGuarantee(&guaranteeSize)) { + // We do not want to fully error out, because needing + // the stack reserve should be rare enough anyway. + Catch::cerr() + << "Failed to reserve piece of stack." + << " Stack overflows will not be reported successfully."; + } + } + + // We do not attempt to unset the stack guarantee, because + // Windows does not support lowering the stack size guarantee. + FatalConditionHandler::~FatalConditionHandler() = default; + + void FatalConditionHandler::engage_platform() { + // Register as first handler in current chain + exceptionHandlerHandle = AddVectoredExceptionHandler(1, handleVectoredException); + if (!exceptionHandlerHandle) { + CATCH_RUNTIME_ERROR("Could not register vectored exception handler"); + } + } + + void FatalConditionHandler::disengage_platform() { + if (!RemoveVectoredExceptionHandler(exceptionHandlerHandle)) { + CATCH_RUNTIME_ERROR("Could not unregister vectored exception handler"); + } + exceptionHandlerHandle = nullptr; + } + +} // end namespace Catch + +#endif // CATCH_CONFIG_WINDOWS_SEH + +#if defined( CATCH_CONFIG_POSIX_SIGNALS ) + +#include <signal.h> + +namespace Catch { + + struct SignalDefs { + int id; + const char* name; + }; + + static SignalDefs signalDefs[] = { + { SIGINT, "SIGINT - Terminal interrupt signal" }, + { SIGILL, "SIGILL - Illegal instruction signal" }, + { SIGFPE, "SIGFPE - Floating point error signal" }, + { SIGSEGV, "SIGSEGV - Segmentation violation signal" }, + { SIGTERM, "SIGTERM - Termination request signal" }, + { SIGABRT, "SIGABRT - Abort (abnormal termination) signal" } + }; + +// Older GCCs trigger -Wmissing-field-initializers for T foo = {} +// which is zero initialization, but not explicit. We want to avoid +// that. +#if defined(__GNUC__) +# pragma GCC diagnostic push +# pragma GCC diagnostic ignored "-Wmissing-field-initializers" +#endif + + static char* altStackMem = nullptr; + static std::size_t altStackSize = 0; + static stack_t oldSigStack{}; + static struct sigaction oldSigActions[sizeof(signalDefs) / sizeof(SignalDefs)]{}; + + static void restorePreviousSignalHandlers() { + // We set signal handlers back to the previous ones. Hopefully + // nobody overwrote them in the meantime, and doesn't expect + // their signal handlers to live past ours given that they + // installed them after ours.. + for (std::size_t i = 0; i < sizeof(signalDefs) / sizeof(SignalDefs); ++i) { + sigaction(signalDefs[i].id, &oldSigActions[i], nullptr); + } + // Return the old stack + sigaltstack(&oldSigStack, nullptr); + } + + static void handleSignal( int sig ) { + char const * name = "<unknown signal>"; + for (auto const& def : signalDefs) { + if (sig == def.id) { + name = def.name; + break; + } + } + // We need to restore previous signal handlers and let them do + // their thing, so that the users can have the debugger break + // when a signal is raised, and so on. + restorePreviousSignalHandlers(); + reportFatal( name ); + raise( sig ); + } + + FatalConditionHandler::FatalConditionHandler() { + assert(!altStackMem && "Cannot initialize POSIX signal handler when one already exists"); + if (altStackSize == 0) { + altStackSize = std::max(static_cast<size_t>(SIGSTKSZ), minStackSizeForErrors); + } + altStackMem = new char[altStackSize](); + } + + FatalConditionHandler::~FatalConditionHandler() { + delete[] altStackMem; + // We signal that another instance can be constructed by zeroing + // out the pointer. + altStackMem = nullptr; + } + + void FatalConditionHandler::engage_platform() { + stack_t sigStack; + sigStack.ss_sp = altStackMem; + sigStack.ss_size = altStackSize; + sigStack.ss_flags = 0; + sigaltstack(&sigStack, &oldSigStack); + struct sigaction sa = { }; + + sa.sa_handler = handleSignal; + sa.sa_flags = SA_ONSTACK; + for (std::size_t i = 0; i < sizeof(signalDefs)/sizeof(SignalDefs); ++i) { + sigaction(signalDefs[i].id, &sa, &oldSigActions[i]); + } + } + +#if defined(__GNUC__) +# pragma GCC diagnostic pop +#endif + + void FatalConditionHandler::disengage_platform() { + restorePreviousSignalHandlers(); + } + +} // end namespace Catch + +#endif // CATCH_CONFIG_POSIX_SIGNALS +// end catch_fatal_condition.cpp +// start catch_generators.cpp + +#include <limits> +#include <set> + +namespace Catch { + +IGeneratorTracker::~IGeneratorTracker() {} + +const char* GeneratorException::what() const noexcept { + return m_msg; +} + +namespace Generators { + + GeneratorUntypedBase::~GeneratorUntypedBase() {} + + auto acquireGeneratorTracker( StringRef generatorName, SourceLineInfo const& lineInfo ) -> IGeneratorTracker& { + return getResultCapture().acquireGeneratorTracker( generatorName, lineInfo ); + } + +} // namespace Generators +} // namespace Catch +// end catch_generators.cpp +// start catch_interfaces_capture.cpp + +namespace Catch { + IResultCapture::~IResultCapture() = default; +} +// end catch_interfaces_capture.cpp +// start catch_interfaces_config.cpp + +namespace Catch { + IConfig::~IConfig() = default; +} +// end catch_interfaces_config.cpp +// start catch_interfaces_exception.cpp + +namespace Catch { + IExceptionTranslator::~IExceptionTranslator() = default; + IExceptionTranslatorRegistry::~IExceptionTranslatorRegistry() = default; +} +// end catch_interfaces_exception.cpp +// start catch_interfaces_registry_hub.cpp + +namespace Catch { + IRegistryHub::~IRegistryHub() = default; + IMutableRegistryHub::~IMutableRegistryHub() = default; +} +// end catch_interfaces_registry_hub.cpp +// start catch_interfaces_reporter.cpp + +// start catch_reporter_listening.h + +namespace Catch { + + class ListeningReporter : public IStreamingReporter { + using Reporters = std::vector<IStreamingReporterPtr>; + Reporters m_listeners; + IStreamingReporterPtr m_reporter = nullptr; + ReporterPreferences m_preferences; + + public: + ListeningReporter(); + + void addListener( IStreamingReporterPtr&& listener ); + void addReporter( IStreamingReporterPtr&& reporter ); + + public: // IStreamingReporter + + ReporterPreferences getPreferences() const override; + + void noMatchingTestCases( std::string const& spec ) override; + + void reportInvalidArguments(std::string const&arg) override; + + static std::set<Verbosity> getSupportedVerbosities(); + +#if defined(CATCH_CONFIG_ENABLE_BENCHMARKING) + void benchmarkPreparing(std::string const& name) override; + void benchmarkStarting( BenchmarkInfo const& benchmarkInfo ) override; + void benchmarkEnded( BenchmarkStats<> const& benchmarkStats ) override; + void benchmarkFailed(std::string const&) override; +#endif // CATCH_CONFIG_ENABLE_BENCHMARKING + + void testRunStarting( TestRunInfo const& testRunInfo ) override; + void testGroupStarting( GroupInfo const& groupInfo ) override; + void testCaseStarting( TestCaseInfo const& testInfo ) override; + void sectionStarting( SectionInfo const& sectionInfo ) override; + void assertionStarting( AssertionInfo const& assertionInfo ) override; + + // The return value indicates if the messages buffer should be cleared: + bool assertionEnded( AssertionStats const& assertionStats ) override; + void sectionEnded( SectionStats const& sectionStats ) override; + void testCaseEnded( TestCaseStats const& testCaseStats ) override; + void testGroupEnded( TestGroupStats const& testGroupStats ) override; + void testRunEnded( TestRunStats const& testRunStats ) override; + + void skipTest( TestCaseInfo const& testInfo ) override; + bool isMulti() const override; + + }; + +} // end namespace Catch + +// end catch_reporter_listening.h +namespace Catch { + + ReporterConfig::ReporterConfig( IConfigPtr const& _fullConfig ) + : m_stream( &_fullConfig->stream() ), m_fullConfig( _fullConfig ) {} + + ReporterConfig::ReporterConfig( IConfigPtr const& _fullConfig, std::ostream& _stream ) + : m_stream( &_stream ), m_fullConfig( _fullConfig ) {} + + std::ostream& ReporterConfig::stream() const { return *m_stream; } + IConfigPtr ReporterConfig::fullConfig() const { return m_fullConfig; } + + TestRunInfo::TestRunInfo( std::string const& _name ) : name( _name ) {} + + GroupInfo::GroupInfo( std::string const& _name, + std::size_t _groupIndex, + std::size_t _groupsCount ) + : name( _name ), + groupIndex( _groupIndex ), + groupsCounts( _groupsCount ) + {} + + AssertionStats::AssertionStats( AssertionResult const& _assertionResult, + std::vector<MessageInfo> const& _infoMessages, + Totals const& _totals ) + : assertionResult( _assertionResult ), + infoMessages( _infoMessages ), + totals( _totals ) + { + assertionResult.m_resultData.lazyExpression.m_transientExpression = _assertionResult.m_resultData.lazyExpression.m_transientExpression; + + if( assertionResult.hasMessage() ) { + // Copy message into messages list. + // !TBD This should have been done earlier, somewhere + MessageBuilder builder( assertionResult.getTestMacroName(), assertionResult.getSourceInfo(), assertionResult.getResultType() ); + builder << assertionResult.getMessage(); + builder.m_info.message = builder.m_stream.str(); + + infoMessages.push_back( builder.m_info ); + } + } + + AssertionStats::~AssertionStats() = default; + + SectionStats::SectionStats( SectionInfo const& _sectionInfo, + Counts const& _assertions, + double _durationInSeconds, + bool _missingAssertions ) + : sectionInfo( _sectionInfo ), + assertions( _assertions ), + durationInSeconds( _durationInSeconds ), + missingAssertions( _missingAssertions ) + {} + + SectionStats::~SectionStats() = default; + + TestCaseStats::TestCaseStats( TestCaseInfo const& _testInfo, + Totals const& _totals, + std::string const& _stdOut, + std::string const& _stdErr, + bool _aborting ) + : testInfo( _testInfo ), + totals( _totals ), + stdOut( _stdOut ), + stdErr( _stdErr ), + aborting( _aborting ) + {} + + TestCaseStats::~TestCaseStats() = default; + + TestGroupStats::TestGroupStats( GroupInfo const& _groupInfo, + Totals const& _totals, + bool _aborting ) + : groupInfo( _groupInfo ), + totals( _totals ), + aborting( _aborting ) + {} + + TestGroupStats::TestGroupStats( GroupInfo const& _groupInfo ) + : groupInfo( _groupInfo ), + aborting( false ) + {} + + TestGroupStats::~TestGroupStats() = default; + + TestRunStats::TestRunStats( TestRunInfo const& _runInfo, + Totals const& _totals, + bool _aborting ) + : runInfo( _runInfo ), + totals( _totals ), + aborting( _aborting ) + {} + + TestRunStats::~TestRunStats() = default; + + void IStreamingReporter::fatalErrorEncountered( StringRef ) {} + bool IStreamingReporter::isMulti() const { return false; } + + IReporterFactory::~IReporterFactory() = default; + IReporterRegistry::~IReporterRegistry() = default; + +} // end namespace Catch +// end catch_interfaces_reporter.cpp +// start catch_interfaces_runner.cpp + +namespace Catch { + IRunner::~IRunner() = default; +} +// end catch_interfaces_runner.cpp +// start catch_interfaces_testcase.cpp + +namespace Catch { + ITestInvoker::~ITestInvoker() = default; + ITestCaseRegistry::~ITestCaseRegistry() = default; +} +// end catch_interfaces_testcase.cpp +// start catch_leak_detector.cpp + +#ifdef CATCH_CONFIG_WINDOWS_CRTDBG +#include <crtdbg.h> + +namespace Catch { + + LeakDetector::LeakDetector() { + int flag = _CrtSetDbgFlag(_CRTDBG_REPORT_FLAG); + flag |= _CRTDBG_LEAK_CHECK_DF; + flag |= _CRTDBG_ALLOC_MEM_DF; + _CrtSetDbgFlag(flag); + _CrtSetReportMode(_CRT_WARN, _CRTDBG_MODE_FILE | _CRTDBG_MODE_DEBUG); + _CrtSetReportFile(_CRT_WARN, _CRTDBG_FILE_STDERR); + // Change this to leaking allocation's number to break there + _CrtSetBreakAlloc(-1); + } +} + +#else + + Catch::LeakDetector::LeakDetector() {} + +#endif + +Catch::LeakDetector::~LeakDetector() { + Catch::cleanUp(); +} +// end catch_leak_detector.cpp +// start catch_list.cpp + +// start catch_list.h + +#include <set> + +namespace Catch { + + std::size_t listTests( Config const& config ); + + std::size_t listTestsNamesOnly( Config const& config ); + + struct TagInfo { + void add( std::string const& spelling ); + std::string all() const; + + std::set<std::string> spellings; + std::size_t count = 0; + }; + + std::size_t listTags( Config const& config ); + + std::size_t listReporters(); + + Option<std::size_t> list( std::shared_ptr<Config> const& config ); + +} // end namespace Catch + +// end catch_list.h +// start catch_text.h + +namespace Catch { + using namespace clara::TextFlow; +} + +// end catch_text.h +#include <limits> +#include <algorithm> +#include <iomanip> + +namespace Catch { + + std::size_t listTests( Config const& config ) { + TestSpec const& testSpec = config.testSpec(); + if( config.hasTestFilters() ) + Catch::cout() << "Matching test cases:\n"; + else { + Catch::cout() << "All available test cases:\n"; + } + + auto matchedTestCases = filterTests( getAllTestCasesSorted( config ), testSpec, config ); + for( auto const& testCaseInfo : matchedTestCases ) { + Colour::Code colour = testCaseInfo.isHidden() + ? Colour::SecondaryText + : Colour::None; + Colour colourGuard( colour ); + + Catch::cout() << Column( testCaseInfo.name ).initialIndent( 2 ).indent( 4 ) << "\n"; + if( config.verbosity() >= Verbosity::High ) { + Catch::cout() << Column( Catch::Detail::stringify( testCaseInfo.lineInfo ) ).indent(4) << std::endl; + std::string description = testCaseInfo.description; + if( description.empty() ) + description = "(NO DESCRIPTION)"; + Catch::cout() << Column( description ).indent(4) << std::endl; + } + if( !testCaseInfo.tags.empty() ) + Catch::cout() << Column( testCaseInfo.tagsAsString() ).indent( 6 ) << "\n"; + } + + if( !config.hasTestFilters() ) + Catch::cout() << pluralise( matchedTestCases.size(), "test case" ) << '\n' << std::endl; + else + Catch::cout() << pluralise( matchedTestCases.size(), "matching test case" ) << '\n' << std::endl; + return matchedTestCases.size(); + } + + std::size_t listTestsNamesOnly( Config const& config ) { + TestSpec const& testSpec = config.testSpec(); + std::size_t matchedTests = 0; + std::vector<TestCase> matchedTestCases = filterTests( getAllTestCasesSorted( config ), testSpec, config ); + for( auto const& testCaseInfo : matchedTestCases ) { + matchedTests++; + if( startsWith( testCaseInfo.name, '#' ) ) + Catch::cout() << '"' << testCaseInfo.name << '"'; + else + Catch::cout() << testCaseInfo.name; + if ( config.verbosity() >= Verbosity::High ) + Catch::cout() << "\t@" << testCaseInfo.lineInfo; + Catch::cout() << std::endl; + } + return matchedTests; + } + + void TagInfo::add( std::string const& spelling ) { + ++count; + spellings.insert( spelling ); + } + + std::string TagInfo::all() const { + size_t size = 0; + for (auto const& spelling : spellings) { + // Add 2 for the brackes + size += spelling.size() + 2; + } + + std::string out; out.reserve(size); + for (auto const& spelling : spellings) { + out += '['; + out += spelling; + out += ']'; + } + return out; + } + + std::size_t listTags( Config const& config ) { + TestSpec const& testSpec = config.testSpec(); + if( config.hasTestFilters() ) + Catch::cout() << "Tags for matching test cases:\n"; + else { + Catch::cout() << "All available tags:\n"; + } + + std::map<std::string, TagInfo> tagCounts; + + std::vector<TestCase> matchedTestCases = filterTests( getAllTestCasesSorted( config ), testSpec, config ); + for( auto const& testCase : matchedTestCases ) { + for( auto const& tagName : testCase.getTestCaseInfo().tags ) { + std::string lcaseTagName = toLower( tagName ); + auto countIt = tagCounts.find( lcaseTagName ); + if( countIt == tagCounts.end() ) + countIt = tagCounts.insert( std::make_pair( lcaseTagName, TagInfo() ) ).first; + countIt->second.add( tagName ); + } + } + + for( auto const& tagCount : tagCounts ) { + ReusableStringStream rss; + rss << " " << std::setw(2) << tagCount.second.count << " "; + auto str = rss.str(); + auto wrapper = Column( tagCount.second.all() ) + .initialIndent( 0 ) + .indent( str.size() ) + .width( CATCH_CONFIG_CONSOLE_WIDTH-10 ); + Catch::cout() << str << wrapper << '\n'; + } + Catch::cout() << pluralise( tagCounts.size(), "tag" ) << '\n' << std::endl; + return tagCounts.size(); + } + + std::size_t listReporters() { + Catch::cout() << "Available reporters:\n"; + IReporterRegistry::FactoryMap const& factories = getRegistryHub().getReporterRegistry().getFactories(); + std::size_t maxNameLen = 0; + for( auto const& factoryKvp : factories ) + maxNameLen = (std::max)( maxNameLen, factoryKvp.first.size() ); + + for( auto const& factoryKvp : factories ) { + Catch::cout() + << Column( factoryKvp.first + ":" ) + .indent(2) + .width( 5+maxNameLen ) + + Column( factoryKvp.second->getDescription() ) + .initialIndent(0) + .indent(2) + .width( CATCH_CONFIG_CONSOLE_WIDTH - maxNameLen-8 ) + << "\n"; + } + Catch::cout() << std::endl; + return factories.size(); + } + + Option<std::size_t> list( std::shared_ptr<Config> const& config ) { + Option<std::size_t> listedCount; + getCurrentMutableContext().setConfig( config ); + if( config->listTests() ) + listedCount = listedCount.valueOr(0) + listTests( *config ); + if( config->listTestNamesOnly() ) + listedCount = listedCount.valueOr(0) + listTestsNamesOnly( *config ); + if( config->listTags() ) + listedCount = listedCount.valueOr(0) + listTags( *config ); + if( config->listReporters() ) + listedCount = listedCount.valueOr(0) + listReporters(); + return listedCount; + } + +} // end namespace Catch +// end catch_list.cpp +// start catch_matchers.cpp + +namespace Catch { +namespace Matchers { + namespace Impl { + + std::string MatcherUntypedBase::toString() const { + if( m_cachedToString.empty() ) + m_cachedToString = describe(); + return m_cachedToString; + } + + MatcherUntypedBase::~MatcherUntypedBase() = default; + + } // namespace Impl +} // namespace Matchers + +using namespace Matchers; +using Matchers::Impl::MatcherBase; + +} // namespace Catch +// end catch_matchers.cpp +// start catch_matchers_exception.cpp + +namespace Catch { +namespace Matchers { +namespace Exception { + +bool ExceptionMessageMatcher::match(std::exception const& ex) const { + return ex.what() == m_message; +} + +std::string ExceptionMessageMatcher::describe() const { + return "exception message matches \"" + m_message + "\""; +} + +} +Exception::ExceptionMessageMatcher Message(std::string const& message) { + return Exception::ExceptionMessageMatcher(message); +} + +// namespace Exception +} // namespace Matchers +} // namespace Catch +// end catch_matchers_exception.cpp +// start catch_matchers_floating.cpp + +// start catch_polyfills.hpp + +namespace Catch { + bool isnan(float f); + bool isnan(double d); +} + +// end catch_polyfills.hpp +// start catch_to_string.hpp + +#include <string> + +namespace Catch { + template <typename T> + std::string to_string(T const& t) { +#if defined(CATCH_CONFIG_CPP11_TO_STRING) + return std::to_string(t); +#else + ReusableStringStream rss; + rss << t; + return rss.str(); +#endif + } +} // end namespace Catch + +// end catch_to_string.hpp +#include <algorithm> +#include <cmath> +#include <cstdlib> +#include <cstdint> +#include <cstring> +#include <sstream> +#include <type_traits> +#include <iomanip> +#include <limits> + +namespace Catch { +namespace { + + int32_t convert(float f) { + static_assert(sizeof(float) == sizeof(int32_t), "Important ULP matcher assumption violated"); + int32_t i; + std::memcpy(&i, &f, sizeof(f)); + return i; + } + + int64_t convert(double d) { + static_assert(sizeof(double) == sizeof(int64_t), "Important ULP matcher assumption violated"); + int64_t i; + std::memcpy(&i, &d, sizeof(d)); + return i; + } + + template <typename FP> + bool almostEqualUlps(FP lhs, FP rhs, uint64_t maxUlpDiff) { + // Comparison with NaN should always be false. + // This way we can rule it out before getting into the ugly details + if (Catch::isnan(lhs) || Catch::isnan(rhs)) { + return false; + } + + auto lc = convert(lhs); + auto rc = convert(rhs); + + if ((lc < 0) != (rc < 0)) { + // Potentially we can have +0 and -0 + return lhs == rhs; + } + + // static cast as a workaround for IBM XLC + auto ulpDiff = std::abs(static_cast<FP>(lc - rc)); + return static_cast<uint64_t>(ulpDiff) <= maxUlpDiff; + } + +#if defined(CATCH_CONFIG_GLOBAL_NEXTAFTER) + + float nextafter(float x, float y) { + return ::nextafterf(x, y); + } + + double nextafter(double x, double y) { + return ::nextafter(x, y); + } + +#endif // ^^^ CATCH_CONFIG_GLOBAL_NEXTAFTER ^^^ + +template <typename FP> +FP step(FP start, FP direction, uint64_t steps) { + for (uint64_t i = 0; i < steps; ++i) { +#if defined(CATCH_CONFIG_GLOBAL_NEXTAFTER) + start = Catch::nextafter(start, direction); +#else + start = std::nextafter(start, direction); +#endif + } + return start; +} + +// Performs equivalent check of std::fabs(lhs - rhs) <= margin +// But without the subtraction to allow for INFINITY in comparison +bool marginComparison(double lhs, double rhs, double margin) { + return (lhs + margin >= rhs) && (rhs + margin >= lhs); +} + +template <typename FloatingPoint> +void write(std::ostream& out, FloatingPoint num) { + out << std::scientific + << std::setprecision(std::numeric_limits<FloatingPoint>::max_digits10 - 1) + << num; +} + +} // end anonymous namespace + +namespace Matchers { +namespace Floating { + + enum class FloatingPointKind : uint8_t { + Float, + Double + }; + + WithinAbsMatcher::WithinAbsMatcher(double target, double margin) + :m_target{ target }, m_margin{ margin } { + CATCH_ENFORCE(margin >= 0, "Invalid margin: " << margin << '.' + << " Margin has to be non-negative."); + } + + // Performs equivalent check of std::fabs(lhs - rhs) <= margin + // But without the subtraction to allow for INFINITY in comparison + bool WithinAbsMatcher::match(double const& matchee) const { + return (matchee + m_margin >= m_target) && (m_target + m_margin >= matchee); + } + + std::string WithinAbsMatcher::describe() const { + return "is within " + ::Catch::Detail::stringify(m_margin) + " of " + ::Catch::Detail::stringify(m_target); + } + + WithinUlpsMatcher::WithinUlpsMatcher(double target, uint64_t ulps, FloatingPointKind baseType) + :m_target{ target }, m_ulps{ ulps }, m_type{ baseType } { + CATCH_ENFORCE(m_type == FloatingPointKind::Double + || m_ulps < (std::numeric_limits<uint32_t>::max)(), + "Provided ULP is impossibly large for a float comparison."); + } + +#if defined(__clang__) +#pragma clang diagnostic push +// Clang <3.5 reports on the default branch in the switch below +#pragma clang diagnostic ignored "-Wunreachable-code" +#endif + + bool WithinUlpsMatcher::match(double const& matchee) const { + switch (m_type) { + case FloatingPointKind::Float: + return almostEqualUlps<float>(static_cast<float>(matchee), static_cast<float>(m_target), m_ulps); + case FloatingPointKind::Double: + return almostEqualUlps<double>(matchee, m_target, m_ulps); + default: + CATCH_INTERNAL_ERROR( "Unknown FloatingPointKind value" ); + } + } + +#if defined(__clang__) +#pragma clang diagnostic pop +#endif + + std::string WithinUlpsMatcher::describe() const { + std::stringstream ret; + + ret << "is within " << m_ulps << " ULPs of "; + + if (m_type == FloatingPointKind::Float) { + write(ret, static_cast<float>(m_target)); + ret << 'f'; + } else { + write(ret, m_target); + } + + ret << " (["; + if (m_type == FloatingPointKind::Double) { + write(ret, step(m_target, static_cast<double>(-INFINITY), m_ulps)); + ret << ", "; + write(ret, step(m_target, static_cast<double>( INFINITY), m_ulps)); + } else { + // We have to cast INFINITY to float because of MinGW, see #1782 + write(ret, step(static_cast<float>(m_target), static_cast<float>(-INFINITY), m_ulps)); + ret << ", "; + write(ret, step(static_cast<float>(m_target), static_cast<float>( INFINITY), m_ulps)); + } + ret << "])"; + + return ret.str(); + } + + WithinRelMatcher::WithinRelMatcher(double target, double epsilon): + m_target(target), + m_epsilon(epsilon){ + CATCH_ENFORCE(m_epsilon >= 0., "Relative comparison with epsilon < 0 does not make sense."); + CATCH_ENFORCE(m_epsilon < 1., "Relative comparison with epsilon >= 1 does not make sense."); + } + + bool WithinRelMatcher::match(double const& matchee) const { + const auto relMargin = m_epsilon * (std::max)(std::fabs(matchee), std::fabs(m_target)); + return marginComparison(matchee, m_target, + std::isinf(relMargin)? 0 : relMargin); + } + + std::string WithinRelMatcher::describe() const { + Catch::ReusableStringStream sstr; + sstr << "and " << m_target << " are within " << m_epsilon * 100. << "% of each other"; + return sstr.str(); + } + +}// namespace Floating + +Floating::WithinUlpsMatcher WithinULP(double target, uint64_t maxUlpDiff) { + return Floating::WithinUlpsMatcher(target, maxUlpDiff, Floating::FloatingPointKind::Double); +} + +Floating::WithinUlpsMatcher WithinULP(float target, uint64_t maxUlpDiff) { + return Floating::WithinUlpsMatcher(target, maxUlpDiff, Floating::FloatingPointKind::Float); +} + +Floating::WithinAbsMatcher WithinAbs(double target, double margin) { + return Floating::WithinAbsMatcher(target, margin); +} + +Floating::WithinRelMatcher WithinRel(double target, double eps) { + return Floating::WithinRelMatcher(target, eps); +} + +Floating::WithinRelMatcher WithinRel(double target) { + return Floating::WithinRelMatcher(target, std::numeric_limits<double>::epsilon() * 100); +} + +Floating::WithinRelMatcher WithinRel(float target, float eps) { + return Floating::WithinRelMatcher(target, eps); +} + +Floating::WithinRelMatcher WithinRel(float target) { + return Floating::WithinRelMatcher(target, std::numeric_limits<float>::epsilon() * 100); +} + +} // namespace Matchers +} // namespace Catch +// end catch_matchers_floating.cpp +// start catch_matchers_generic.cpp + +std::string Catch::Matchers::Generic::Detail::finalizeDescription(const std::string& desc) { + if (desc.empty()) { + return "matches undescribed predicate"; + } else { + return "matches predicate: \"" + desc + '"'; + } +} +// end catch_matchers_generic.cpp +// start catch_matchers_string.cpp + +#include <regex> + +namespace Catch { +namespace Matchers { + + namespace StdString { + + CasedString::CasedString( std::string const& str, CaseSensitive::Choice caseSensitivity ) + : m_caseSensitivity( caseSensitivity ), + m_str( adjustString( str ) ) + {} + std::string CasedString::adjustString( std::string const& str ) const { + return m_caseSensitivity == CaseSensitive::No + ? toLower( str ) + : str; + } + std::string CasedString::caseSensitivitySuffix() const { + return m_caseSensitivity == CaseSensitive::No + ? " (case insensitive)" + : std::string(); + } + + StringMatcherBase::StringMatcherBase( std::string const& operation, CasedString const& comparator ) + : m_comparator( comparator ), + m_operation( operation ) { + } + + std::string StringMatcherBase::describe() const { + std::string description; + description.reserve(5 + m_operation.size() + m_comparator.m_str.size() + + m_comparator.caseSensitivitySuffix().size()); + description += m_operation; + description += ": \""; + description += m_comparator.m_str; + description += "\""; + description += m_comparator.caseSensitivitySuffix(); + return description; + } + + EqualsMatcher::EqualsMatcher( CasedString const& comparator ) : StringMatcherBase( "equals", comparator ) {} + + bool EqualsMatcher::match( std::string const& source ) const { + return m_comparator.adjustString( source ) == m_comparator.m_str; + } + + ContainsMatcher::ContainsMatcher( CasedString const& comparator ) : StringMatcherBase( "contains", comparator ) {} + + bool ContainsMatcher::match( std::string const& source ) const { + return contains( m_comparator.adjustString( source ), m_comparator.m_str ); + } + + StartsWithMatcher::StartsWithMatcher( CasedString const& comparator ) : StringMatcherBase( "starts with", comparator ) {} + + bool StartsWithMatcher::match( std::string const& source ) const { + return startsWith( m_comparator.adjustString( source ), m_comparator.m_str ); + } + + EndsWithMatcher::EndsWithMatcher( CasedString const& comparator ) : StringMatcherBase( "ends with", comparator ) {} + + bool EndsWithMatcher::match( std::string const& source ) const { + return endsWith( m_comparator.adjustString( source ), m_comparator.m_str ); + } + + RegexMatcher::RegexMatcher(std::string regex, CaseSensitive::Choice caseSensitivity): m_regex(std::move(regex)), m_caseSensitivity(caseSensitivity) {} + + bool RegexMatcher::match(std::string const& matchee) const { + auto flags = std::regex::ECMAScript; // ECMAScript is the default syntax option anyway + if (m_caseSensitivity == CaseSensitive::Choice::No) { + flags |= std::regex::icase; + } + auto reg = std::regex(m_regex, flags); + return std::regex_match(matchee, reg); + } + + std::string RegexMatcher::describe() const { + return "matches " + ::Catch::Detail::stringify(m_regex) + ((m_caseSensitivity == CaseSensitive::Choice::Yes)? " case sensitively" : " case insensitively"); + } + + } // namespace StdString + + StdString::EqualsMatcher Equals( std::string const& str, CaseSensitive::Choice caseSensitivity ) { + return StdString::EqualsMatcher( StdString::CasedString( str, caseSensitivity) ); + } + StdString::ContainsMatcher Contains( std::string const& str, CaseSensitive::Choice caseSensitivity ) { + return StdString::ContainsMatcher( StdString::CasedString( str, caseSensitivity) ); + } + StdString::EndsWithMatcher EndsWith( std::string const& str, CaseSensitive::Choice caseSensitivity ) { + return StdString::EndsWithMatcher( StdString::CasedString( str, caseSensitivity) ); + } + StdString::StartsWithMatcher StartsWith( std::string const& str, CaseSensitive::Choice caseSensitivity ) { + return StdString::StartsWithMatcher( StdString::CasedString( str, caseSensitivity) ); + } + + StdString::RegexMatcher Matches(std::string const& regex, CaseSensitive::Choice caseSensitivity) { + return StdString::RegexMatcher(regex, caseSensitivity); + } + +} // namespace Matchers +} // namespace Catch +// end catch_matchers_string.cpp +// start catch_message.cpp + +// start catch_uncaught_exceptions.h + +namespace Catch { + bool uncaught_exceptions(); +} // end namespace Catch + +// end catch_uncaught_exceptions.h +#include <cassert> +#include <stack> + +namespace Catch { + + MessageInfo::MessageInfo( StringRef const& _macroName, + SourceLineInfo const& _lineInfo, + ResultWas::OfType _type ) + : macroName( _macroName ), + lineInfo( _lineInfo ), + type( _type ), + sequence( ++globalCount ) + {} + + bool MessageInfo::operator==( MessageInfo const& other ) const { + return sequence == other.sequence; + } + + bool MessageInfo::operator<( MessageInfo const& other ) const { + return sequence < other.sequence; + } + + // This may need protecting if threading support is added + unsigned int MessageInfo::globalCount = 0; + + //////////////////////////////////////////////////////////////////////////// + + Catch::MessageBuilder::MessageBuilder( StringRef const& macroName, + SourceLineInfo const& lineInfo, + ResultWas::OfType type ) + :m_info(macroName, lineInfo, type) {} + + //////////////////////////////////////////////////////////////////////////// + + ScopedMessage::ScopedMessage( MessageBuilder const& builder ) + : m_info( builder.m_info ), m_moved() + { + m_info.message = builder.m_stream.str(); + getResultCapture().pushScopedMessage( m_info ); + } + + ScopedMessage::ScopedMessage( ScopedMessage&& old ) + : m_info( old.m_info ), m_moved() + { + old.m_moved = true; + } + + ScopedMessage::~ScopedMessage() { + if ( !uncaught_exceptions() && !m_moved ){ + getResultCapture().popScopedMessage(m_info); + } + } + + Capturer::Capturer( StringRef macroName, SourceLineInfo const& lineInfo, ResultWas::OfType resultType, StringRef names ) { + auto trimmed = [&] (size_t start, size_t end) { + while (names[start] == ',' || isspace(static_cast<unsigned char>(names[start]))) { + ++start; + } + while (names[end] == ',' || isspace(static_cast<unsigned char>(names[end]))) { + --end; + } + return names.substr(start, end - start + 1); + }; + auto skipq = [&] (size_t start, char quote) { + for (auto i = start + 1; i < names.size() ; ++i) { + if (names[i] == quote) + return i; + if (names[i] == '\\') + ++i; + } + CATCH_INTERNAL_ERROR("CAPTURE parsing encountered unmatched quote"); + }; + + size_t start = 0; + std::stack<char> openings; + for (size_t pos = 0; pos < names.size(); ++pos) { + char c = names[pos]; + switch (c) { + case '[': + case '{': + case '(': + // It is basically impossible to disambiguate between + // comparison and start of template args in this context +// case '<': + openings.push(c); + break; + case ']': + case '}': + case ')': +// case '>': + openings.pop(); + break; + case '"': + case '\'': + pos = skipq(pos, c); + break; + case ',': + if (start != pos && openings.empty()) { + m_messages.emplace_back(macroName, lineInfo, resultType); + m_messages.back().message = static_cast<std::string>(trimmed(start, pos)); + m_messages.back().message += " := "; + start = pos; + } + } + } + assert(openings.empty() && "Mismatched openings"); + m_messages.emplace_back(macroName, lineInfo, resultType); + m_messages.back().message = static_cast<std::string>(trimmed(start, names.size() - 1)); + m_messages.back().message += " := "; + } + Capturer::~Capturer() { + if ( !uncaught_exceptions() ){ + assert( m_captured == m_messages.size() ); + for( size_t i = 0; i < m_captured; ++i ) + m_resultCapture.popScopedMessage( m_messages[i] ); + } + } + + void Capturer::captureValue( size_t index, std::string const& value ) { + assert( index < m_messages.size() ); + m_messages[index].message += value; + m_resultCapture.pushScopedMessage( m_messages[index] ); + m_captured++; + } + +} // end namespace Catch +// end catch_message.cpp +// start catch_output_redirect.cpp + +// start catch_output_redirect.h +#ifndef TWOBLUECUBES_CATCH_OUTPUT_REDIRECT_H +#define TWOBLUECUBES_CATCH_OUTPUT_REDIRECT_H + +#include <cstdio> +#include <iosfwd> +#include <string> + +namespace Catch { + + class RedirectedStream { + std::ostream& m_originalStream; + std::ostream& m_redirectionStream; + std::streambuf* m_prevBuf; + + public: + RedirectedStream( std::ostream& originalStream, std::ostream& redirectionStream ); + ~RedirectedStream(); + }; + + class RedirectedStdOut { + ReusableStringStream m_rss; + RedirectedStream m_cout; + public: + RedirectedStdOut(); + auto str() const -> std::string; + }; + + // StdErr has two constituent streams in C++, std::cerr and std::clog + // This means that we need to redirect 2 streams into 1 to keep proper + // order of writes + class RedirectedStdErr { + ReusableStringStream m_rss; + RedirectedStream m_cerr; + RedirectedStream m_clog; + public: + RedirectedStdErr(); + auto str() const -> std::string; + }; + + class RedirectedStreams { + public: + RedirectedStreams(RedirectedStreams const&) = delete; + RedirectedStreams& operator=(RedirectedStreams const&) = delete; + RedirectedStreams(RedirectedStreams&&) = delete; + RedirectedStreams& operator=(RedirectedStreams&&) = delete; + + RedirectedStreams(std::string& redirectedCout, std::string& redirectedCerr); + ~RedirectedStreams(); + private: + std::string& m_redirectedCout; + std::string& m_redirectedCerr; + RedirectedStdOut m_redirectedStdOut; + RedirectedStdErr m_redirectedStdErr; + }; + +#if defined(CATCH_CONFIG_NEW_CAPTURE) + + // Windows's implementation of std::tmpfile is terrible (it tries + // to create a file inside system folder, thus requiring elevated + // privileges for the binary), so we have to use tmpnam(_s) and + // create the file ourselves there. + class TempFile { + public: + TempFile(TempFile const&) = delete; + TempFile& operator=(TempFile const&) = delete; + TempFile(TempFile&&) = delete; + TempFile& operator=(TempFile&&) = delete; + + TempFile(); + ~TempFile(); + + std::FILE* getFile(); + std::string getContents(); + + private: + std::FILE* m_file = nullptr; + #if defined(_MSC_VER) + char m_buffer[L_tmpnam] = { 0 }; + #endif + }; + + class OutputRedirect { + public: + OutputRedirect(OutputRedirect const&) = delete; + OutputRedirect& operator=(OutputRedirect const&) = delete; + OutputRedirect(OutputRedirect&&) = delete; + OutputRedirect& operator=(OutputRedirect&&) = delete; + + OutputRedirect(std::string& stdout_dest, std::string& stderr_dest); + ~OutputRedirect(); + + private: + int m_originalStdout = -1; + int m_originalStderr = -1; + TempFile m_stdoutFile; + TempFile m_stderrFile; + std::string& m_stdoutDest; + std::string& m_stderrDest; + }; + +#endif + +} // end namespace Catch + +#endif // TWOBLUECUBES_CATCH_OUTPUT_REDIRECT_H +// end catch_output_redirect.h +#include <cstdio> +#include <cstring> +#include <fstream> +#include <sstream> +#include <stdexcept> + +#if defined(CATCH_CONFIG_NEW_CAPTURE) + #if defined(_MSC_VER) + #include <io.h> //_dup and _dup2 + #define dup _dup + #define dup2 _dup2 + #define fileno _fileno + #else + #include <unistd.h> // dup and dup2 + #endif +#endif + +namespace Catch { + + RedirectedStream::RedirectedStream( std::ostream& originalStream, std::ostream& redirectionStream ) + : m_originalStream( originalStream ), + m_redirectionStream( redirectionStream ), + m_prevBuf( m_originalStream.rdbuf() ) + { + m_originalStream.rdbuf( m_redirectionStream.rdbuf() ); + } + + RedirectedStream::~RedirectedStream() { + m_originalStream.rdbuf( m_prevBuf ); + } + + RedirectedStdOut::RedirectedStdOut() : m_cout( Catch::cout(), m_rss.get() ) {} + auto RedirectedStdOut::str() const -> std::string { return m_rss.str(); } + + RedirectedStdErr::RedirectedStdErr() + : m_cerr( Catch::cerr(), m_rss.get() ), + m_clog( Catch::clog(), m_rss.get() ) + {} + auto RedirectedStdErr::str() const -> std::string { return m_rss.str(); } + + RedirectedStreams::RedirectedStreams(std::string& redirectedCout, std::string& redirectedCerr) + : m_redirectedCout(redirectedCout), + m_redirectedCerr(redirectedCerr) + {} + + RedirectedStreams::~RedirectedStreams() { + m_redirectedCout += m_redirectedStdOut.str(); + m_redirectedCerr += m_redirectedStdErr.str(); + } + +#if defined(CATCH_CONFIG_NEW_CAPTURE) + +#if defined(_MSC_VER) + TempFile::TempFile() { + if (tmpnam_s(m_buffer)) { + CATCH_RUNTIME_ERROR("Could not get a temp filename"); + } + if (fopen_s(&m_file, m_buffer, "w+")) { + char buffer[100]; + if (strerror_s(buffer, errno)) { + CATCH_RUNTIME_ERROR("Could not translate errno to a string"); + } + CATCH_RUNTIME_ERROR("Could not open the temp file: '" << m_buffer << "' because: " << buffer); + } + } +#else + TempFile::TempFile() { + m_file = std::tmpfile(); + if (!m_file) { + CATCH_RUNTIME_ERROR("Could not create a temp file."); + } + } + +#endif + + TempFile::~TempFile() { + // TBD: What to do about errors here? + std::fclose(m_file); + // We manually create the file on Windows only, on Linux + // it will be autodeleted +#if defined(_MSC_VER) + std::remove(m_buffer); +#endif + } + + FILE* TempFile::getFile() { + return m_file; + } + + std::string TempFile::getContents() { + std::stringstream sstr; + char buffer[100] = {}; + std::rewind(m_file); + while (std::fgets(buffer, sizeof(buffer), m_file)) { + sstr << buffer; + } + return sstr.str(); + } + + OutputRedirect::OutputRedirect(std::string& stdout_dest, std::string& stderr_dest) : + m_originalStdout(dup(1)), + m_originalStderr(dup(2)), + m_stdoutDest(stdout_dest), + m_stderrDest(stderr_dest) { + dup2(fileno(m_stdoutFile.getFile()), 1); + dup2(fileno(m_stderrFile.getFile()), 2); + } + + OutputRedirect::~OutputRedirect() { + Catch::cout() << std::flush; + fflush(stdout); + // Since we support overriding these streams, we flush cerr + // even though std::cerr is unbuffered + Catch::cerr() << std::flush; + Catch::clog() << std::flush; + fflush(stderr); + + dup2(m_originalStdout, 1); + dup2(m_originalStderr, 2); + + m_stdoutDest += m_stdoutFile.getContents(); + m_stderrDest += m_stderrFile.getContents(); + } + +#endif // CATCH_CONFIG_NEW_CAPTURE + +} // namespace Catch + +#if defined(CATCH_CONFIG_NEW_CAPTURE) + #if defined(_MSC_VER) + #undef dup + #undef dup2 + #undef fileno + #endif +#endif +// end catch_output_redirect.cpp +// start catch_polyfills.cpp + +#include <cmath> + +namespace Catch { + +#if !defined(CATCH_CONFIG_POLYFILL_ISNAN) + bool isnan(float f) { + return std::isnan(f); + } + bool isnan(double d) { + return std::isnan(d); + } +#else + // For now we only use this for embarcadero + bool isnan(float f) { + return std::_isnan(f); + } + bool isnan(double d) { + return std::_isnan(d); + } +#endif + +} // end namespace Catch +// end catch_polyfills.cpp +// start catch_random_number_generator.cpp + +namespace Catch { + +namespace { + +#if defined(_MSC_VER) +#pragma warning(push) +#pragma warning(disable:4146) // we negate uint32 during the rotate +#endif + // Safe rotr implementation thanks to John Regehr + uint32_t rotate_right(uint32_t val, uint32_t count) { + const uint32_t mask = 31; + count &= mask; + return (val >> count) | (val << (-count & mask)); + } + +#if defined(_MSC_VER) +#pragma warning(pop) +#endif + +} + + SimplePcg32::SimplePcg32(result_type seed_) { + seed(seed_); + } + + void SimplePcg32::seed(result_type seed_) { + m_state = 0; + (*this)(); + m_state += seed_; + (*this)(); + } + + void SimplePcg32::discard(uint64_t skip) { + // We could implement this to run in O(log n) steps, but this + // should suffice for our use case. + for (uint64_t s = 0; s < skip; ++s) { + static_cast<void>((*this)()); + } + } + + SimplePcg32::result_type SimplePcg32::operator()() { + // prepare the output value + const uint32_t xorshifted = static_cast<uint32_t>(((m_state >> 18u) ^ m_state) >> 27u); + const auto output = rotate_right(xorshifted, m_state >> 59u); + + // advance state + m_state = m_state * 6364136223846793005ULL + s_inc; + + return output; + } + + bool operator==(SimplePcg32 const& lhs, SimplePcg32 const& rhs) { + return lhs.m_state == rhs.m_state; + } + + bool operator!=(SimplePcg32 const& lhs, SimplePcg32 const& rhs) { + return lhs.m_state != rhs.m_state; + } +} +// end catch_random_number_generator.cpp +// start catch_registry_hub.cpp + +// start catch_test_case_registry_impl.h + +#include <vector> +#include <set> +#include <algorithm> +#include <ios> + +namespace Catch { + + class TestCase; + struct IConfig; + + std::vector<TestCase> sortTests( IConfig const& config, std::vector<TestCase> const& unsortedTestCases ); + + bool isThrowSafe( TestCase const& testCase, IConfig const& config ); + bool matchTest( TestCase const& testCase, TestSpec const& testSpec, IConfig const& config ); + + void enforceNoDuplicateTestCases( std::vector<TestCase> const& functions ); + + std::vector<TestCase> filterTests( std::vector<TestCase> const& testCases, TestSpec const& testSpec, IConfig const& config ); + std::vector<TestCase> const& getAllTestCasesSorted( IConfig const& config ); + + class TestRegistry : public ITestCaseRegistry { + public: + virtual ~TestRegistry() = default; + + virtual void registerTest( TestCase const& testCase ); + + std::vector<TestCase> const& getAllTests() const override; + std::vector<TestCase> const& getAllTestsSorted( IConfig const& config ) const override; + + private: + std::vector<TestCase> m_functions; + mutable RunTests::InWhatOrder m_currentSortOrder = RunTests::InDeclarationOrder; + mutable std::vector<TestCase> m_sortedFunctions; + std::size_t m_unnamedCount = 0; + std::ios_base::Init m_ostreamInit; // Forces cout/ cerr to be initialised + }; + + /////////////////////////////////////////////////////////////////////////// + + class TestInvokerAsFunction : public ITestInvoker { + void(*m_testAsFunction)(); + public: + TestInvokerAsFunction( void(*testAsFunction)() ) noexcept; + + void invoke() const override; + }; + + std::string extractClassName( StringRef const& classOrQualifiedMethodName ); + + /////////////////////////////////////////////////////////////////////////// + +} // end namespace Catch + +// end catch_test_case_registry_impl.h +// start catch_reporter_registry.h + +#include <map> + +namespace Catch { + + class ReporterRegistry : public IReporterRegistry { + + public: + + ~ReporterRegistry() override; + + IStreamingReporterPtr create( std::string const& name, IConfigPtr const& config ) const override; + + void registerReporter( std::string const& name, IReporterFactoryPtr const& factory ); + void registerListener( IReporterFactoryPtr const& factory ); + + FactoryMap const& getFactories() const override; + Listeners const& getListeners() const override; + + private: + FactoryMap m_factories; + Listeners m_listeners; + }; +} + +// end catch_reporter_registry.h +// start catch_tag_alias_registry.h + +// start catch_tag_alias.h + +#include <string> + +namespace Catch { + + struct TagAlias { + TagAlias(std::string const& _tag, SourceLineInfo _lineInfo); + + std::string tag; + SourceLineInfo lineInfo; + }; + +} // end namespace Catch + +// end catch_tag_alias.h +#include <map> + +namespace Catch { + + class TagAliasRegistry : public ITagAliasRegistry { + public: + ~TagAliasRegistry() override; + TagAlias const* find( std::string const& alias ) const override; + std::string expandAliases( std::string const& unexpandedTestSpec ) const override; + void add( std::string const& alias, std::string const& tag, SourceLineInfo const& lineInfo ); + + private: + std::map<std::string, TagAlias> m_registry; + }; + +} // end namespace Catch + +// end catch_tag_alias_registry.h +// start catch_startup_exception_registry.h + +#include <vector> +#include <exception> + +namespace Catch { + + class StartupExceptionRegistry { +#if !defined(CATCH_CONFIG_DISABLE_EXCEPTIONS) + public: + void add(std::exception_ptr const& exception) noexcept; + std::vector<std::exception_ptr> const& getExceptions() const noexcept; + private: + std::vector<std::exception_ptr> m_exceptions; +#endif + }; + +} // end namespace Catch + +// end catch_startup_exception_registry.h +// start catch_singletons.hpp + +namespace Catch { + + struct ISingleton { + virtual ~ISingleton(); + }; + + void addSingleton( ISingleton* singleton ); + void cleanupSingletons(); + + template<typename SingletonImplT, typename InterfaceT = SingletonImplT, typename MutableInterfaceT = InterfaceT> + class Singleton : SingletonImplT, public ISingleton { + + static auto getInternal() -> Singleton* { + static Singleton* s_instance = nullptr; + if( !s_instance ) { + s_instance = new Singleton; + addSingleton( s_instance ); + } + return s_instance; + } + + public: + static auto get() -> InterfaceT const& { + return *getInternal(); + } + static auto getMutable() -> MutableInterfaceT& { + return *getInternal(); + } + }; + +} // namespace Catch + +// end catch_singletons.hpp +namespace Catch { + + namespace { + + class RegistryHub : public IRegistryHub, public IMutableRegistryHub, + private NonCopyable { + + public: // IRegistryHub + RegistryHub() = default; + IReporterRegistry const& getReporterRegistry() const override { + return m_reporterRegistry; + } + ITestCaseRegistry const& getTestCaseRegistry() const override { + return m_testCaseRegistry; + } + IExceptionTranslatorRegistry const& getExceptionTranslatorRegistry() const override { + return m_exceptionTranslatorRegistry; + } + ITagAliasRegistry const& getTagAliasRegistry() const override { + return m_tagAliasRegistry; + } + StartupExceptionRegistry const& getStartupExceptionRegistry() const override { + return m_exceptionRegistry; + } + + public: // IMutableRegistryHub + void registerReporter( std::string const& name, IReporterFactoryPtr const& factory ) override { + m_reporterRegistry.registerReporter( name, factory ); + } + void registerListener( IReporterFactoryPtr const& factory ) override { + m_reporterRegistry.registerListener( factory ); + } + void registerTest( TestCase const& testInfo ) override { + m_testCaseRegistry.registerTest( testInfo ); + } + void registerTranslator( const IExceptionTranslator* translator ) override { + m_exceptionTranslatorRegistry.registerTranslator( translator ); + } + void registerTagAlias( std::string const& alias, std::string const& tag, SourceLineInfo const& lineInfo ) override { + m_tagAliasRegistry.add( alias, tag, lineInfo ); + } + void registerStartupException() noexcept override { +#if !defined(CATCH_CONFIG_DISABLE_EXCEPTIONS) + m_exceptionRegistry.add(std::current_exception()); +#else + CATCH_INTERNAL_ERROR("Attempted to register active exception under CATCH_CONFIG_DISABLE_EXCEPTIONS!"); +#endif + } + IMutableEnumValuesRegistry& getMutableEnumValuesRegistry() override { + return m_enumValuesRegistry; + } + + private: + TestRegistry m_testCaseRegistry; + ReporterRegistry m_reporterRegistry; + ExceptionTranslatorRegistry m_exceptionTranslatorRegistry; + TagAliasRegistry m_tagAliasRegistry; + StartupExceptionRegistry m_exceptionRegistry; + Detail::EnumValuesRegistry m_enumValuesRegistry; + }; + } + + using RegistryHubSingleton = Singleton<RegistryHub, IRegistryHub, IMutableRegistryHub>; + + IRegistryHub const& getRegistryHub() { + return RegistryHubSingleton::get(); + } + IMutableRegistryHub& getMutableRegistryHub() { + return RegistryHubSingleton::getMutable(); + } + void cleanUp() { + cleanupSingletons(); + cleanUpContext(); + } + std::string translateActiveException() { + return getRegistryHub().getExceptionTranslatorRegistry().translateActiveException(); + } + +} // end namespace Catch +// end catch_registry_hub.cpp +// start catch_reporter_registry.cpp + +namespace Catch { + + ReporterRegistry::~ReporterRegistry() = default; + + IStreamingReporterPtr ReporterRegistry::create( std::string const& name, IConfigPtr const& config ) const { + auto it = m_factories.find( name ); + if( it == m_factories.end() ) + return nullptr; + return it->second->create( ReporterConfig( config ) ); + } + + void ReporterRegistry::registerReporter( std::string const& name, IReporterFactoryPtr const& factory ) { + m_factories.emplace(name, factory); + } + void ReporterRegistry::registerListener( IReporterFactoryPtr const& factory ) { + m_listeners.push_back( factory ); + } + + IReporterRegistry::FactoryMap const& ReporterRegistry::getFactories() const { + return m_factories; + } + IReporterRegistry::Listeners const& ReporterRegistry::getListeners() const { + return m_listeners; + } + +} +// end catch_reporter_registry.cpp +// start catch_result_type.cpp + +namespace Catch { + + bool isOk( ResultWas::OfType resultType ) { + return ( resultType & ResultWas::FailureBit ) == 0; + } + bool isJustInfo( int flags ) { + return flags == ResultWas::Info; + } + + ResultDisposition::Flags operator | ( ResultDisposition::Flags lhs, ResultDisposition::Flags rhs ) { + return static_cast<ResultDisposition::Flags>( static_cast<int>( lhs ) | static_cast<int>( rhs ) ); + } + + bool shouldContinueOnFailure( int flags ) { return ( flags & ResultDisposition::ContinueOnFailure ) != 0; } + bool shouldSuppressFailure( int flags ) { return ( flags & ResultDisposition::SuppressFail ) != 0; } + +} // end namespace Catch +// end catch_result_type.cpp +// start catch_run_context.cpp + +#include <cassert> +#include <algorithm> +#include <sstream> + +namespace Catch { + + namespace Generators { + struct GeneratorTracker : TestCaseTracking::TrackerBase, IGeneratorTracker { + GeneratorBasePtr m_generator; + + GeneratorTracker( TestCaseTracking::NameAndLocation const& nameAndLocation, TrackerContext& ctx, ITracker* parent ) + : TrackerBase( nameAndLocation, ctx, parent ) + {} + ~GeneratorTracker(); + + static GeneratorTracker& acquire( TrackerContext& ctx, TestCaseTracking::NameAndLocation const& nameAndLocation ) { + std::shared_ptr<GeneratorTracker> tracker; + + ITracker& currentTracker = ctx.currentTracker(); + // Under specific circumstances, the generator we want + // to acquire is also the current tracker. If this is + // the case, we have to avoid looking through current + // tracker's children, and instead return the current + // tracker. + // A case where this check is important is e.g. + // for (int i = 0; i < 5; ++i) { + // int n = GENERATE(1, 2); + // } + // + // without it, the code above creates 5 nested generators. + if (currentTracker.nameAndLocation() == nameAndLocation) { + auto thisTracker = currentTracker.parent().findChild(nameAndLocation); + assert(thisTracker); + assert(thisTracker->isGeneratorTracker()); + tracker = std::static_pointer_cast<GeneratorTracker>(thisTracker); + } else if ( TestCaseTracking::ITrackerPtr childTracker = currentTracker.findChild( nameAndLocation ) ) { + assert( childTracker ); + assert( childTracker->isGeneratorTracker() ); + tracker = std::static_pointer_cast<GeneratorTracker>( childTracker ); + } else { + tracker = std::make_shared<GeneratorTracker>( nameAndLocation, ctx, ¤tTracker ); + currentTracker.addChild( tracker ); + } + + if( !tracker->isComplete() ) { + tracker->open(); + } + + return *tracker; + } + + // TrackerBase interface + bool isGeneratorTracker() const override { return true; } + auto hasGenerator() const -> bool override { + return !!m_generator; + } + void close() override { + TrackerBase::close(); + // If a generator has a child (it is followed by a section) + // and none of its children have started, then we must wait + // until later to start consuming its values. + // This catches cases where `GENERATE` is placed between two + // `SECTION`s. + // **The check for m_children.empty cannot be removed**. + // doing so would break `GENERATE` _not_ followed by `SECTION`s. + const bool should_wait_for_child = [&]() { + // No children -> nobody to wait for + if ( m_children.empty() ) { + return false; + } + // If at least one child started executing, don't wait + if ( std::find_if( + m_children.begin(), + m_children.end(), + []( TestCaseTracking::ITrackerPtr tracker ) { + return tracker->hasStarted(); + } ) != m_children.end() ) { + return false; + } + + // No children have started. We need to check if they _can_ + // start, and thus we should wait for them, or they cannot + // start (due to filters), and we shouldn't wait for them + auto* parent = m_parent; + // This is safe: there is always at least one section + // tracker in a test case tracking tree + while ( !parent->isSectionTracker() ) { + parent = &( parent->parent() ); + } + assert( parent && + "Missing root (test case) level section" ); + + auto const& parentSection = + static_cast<SectionTracker&>( *parent ); + auto const& filters = parentSection.getFilters(); + // No filters -> no restrictions on running sections + if ( filters.empty() ) { + return true; + } + + for ( auto const& child : m_children ) { + if ( child->isSectionTracker() && + std::find( filters.begin(), + filters.end(), + static_cast<SectionTracker&>( *child ) + .trimmedName() ) != + filters.end() ) { + return true; + } + } + return false; + }(); + + // This check is a bit tricky, because m_generator->next() + // has a side-effect, where it consumes generator's current + // value, but we do not want to invoke the side-effect if + // this generator is still waiting for any child to start. + if ( should_wait_for_child || + ( m_runState == CompletedSuccessfully && + m_generator->next() ) ) { + m_children.clear(); + m_runState = Executing; + } + } + + // IGeneratorTracker interface + auto getGenerator() const -> GeneratorBasePtr const& override { + return m_generator; + } + void setGenerator( GeneratorBasePtr&& generator ) override { + m_generator = std::move( generator ); + } + }; + GeneratorTracker::~GeneratorTracker() {} + } + + RunContext::RunContext(IConfigPtr const& _config, IStreamingReporterPtr&& reporter) + : m_runInfo(_config->name()), + m_context(getCurrentMutableContext()), + m_config(_config), + m_reporter(std::move(reporter)), + m_lastAssertionInfo{ StringRef(), SourceLineInfo("",0), StringRef(), ResultDisposition::Normal }, + m_includeSuccessfulResults( m_config->includeSuccessfulResults() || m_reporter->getPreferences().shouldReportAllAssertions ) + { + m_context.setRunner(this); + m_context.setConfig(m_config); + m_context.setResultCapture(this); + m_reporter->testRunStarting(m_runInfo); + } + + RunContext::~RunContext() { + m_reporter->testRunEnded(TestRunStats(m_runInfo, m_totals, aborting())); + } + + void RunContext::testGroupStarting(std::string const& testSpec, std::size_t groupIndex, std::size_t groupsCount) { + m_reporter->testGroupStarting(GroupInfo(testSpec, groupIndex, groupsCount)); + } + + void RunContext::testGroupEnded(std::string const& testSpec, Totals const& totals, std::size_t groupIndex, std::size_t groupsCount) { + m_reporter->testGroupEnded(TestGroupStats(GroupInfo(testSpec, groupIndex, groupsCount), totals, aborting())); + } + + Totals RunContext::runTest(TestCase const& testCase) { + Totals prevTotals = m_totals; + + std::string redirectedCout; + std::string redirectedCerr; + + auto const& testInfo = testCase.getTestCaseInfo(); + + m_reporter->testCaseStarting(testInfo); + + m_activeTestCase = &testCase; + + ITracker& rootTracker = m_trackerContext.startRun(); + assert(rootTracker.isSectionTracker()); + static_cast<SectionTracker&>(rootTracker).addInitialFilters(m_config->getSectionsToRun()); + do { + m_trackerContext.startCycle(); + m_testCaseTracker = &SectionTracker::acquire(m_trackerContext, TestCaseTracking::NameAndLocation(testInfo.name, testInfo.lineInfo)); + runCurrentTest(redirectedCout, redirectedCerr); + } while (!m_testCaseTracker->isSuccessfullyCompleted() && !aborting()); + + Totals deltaTotals = m_totals.delta(prevTotals); + if (testInfo.expectedToFail() && deltaTotals.testCases.passed > 0) { + deltaTotals.assertions.failed++; + deltaTotals.testCases.passed--; + deltaTotals.testCases.failed++; + } + m_totals.testCases += deltaTotals.testCases; + m_reporter->testCaseEnded(TestCaseStats(testInfo, + deltaTotals, + redirectedCout, + redirectedCerr, + aborting())); + + m_activeTestCase = nullptr; + m_testCaseTracker = nullptr; + + return deltaTotals; + } + + IConfigPtr RunContext::config() const { + return m_config; + } + + IStreamingReporter& RunContext::reporter() const { + return *m_reporter; + } + + void RunContext::assertionEnded(AssertionResult const & result) { + if (result.getResultType() == ResultWas::Ok) { + m_totals.assertions.passed++; + m_lastAssertionPassed = true; + } else if (!result.isOk()) { + m_lastAssertionPassed = false; + if( m_activeTestCase->getTestCaseInfo().okToFail() ) + m_totals.assertions.failedButOk++; + else + m_totals.assertions.failed++; + } + else { + m_lastAssertionPassed = true; + } + + // We have no use for the return value (whether messages should be cleared), because messages were made scoped + // and should be let to clear themselves out. + static_cast<void>(m_reporter->assertionEnded(AssertionStats(result, m_messages, m_totals))); + + if (result.getResultType() != ResultWas::Warning) + m_messageScopes.clear(); + + // Reset working state + resetAssertionInfo(); + m_lastResult = result; + } + void RunContext::resetAssertionInfo() { + m_lastAssertionInfo.macroName = StringRef(); + m_lastAssertionInfo.capturedExpression = "{Unknown expression after the reported line}"_sr; + } + + bool RunContext::sectionStarted(SectionInfo const & sectionInfo, Counts & assertions) { + ITracker& sectionTracker = SectionTracker::acquire(m_trackerContext, TestCaseTracking::NameAndLocation(sectionInfo.name, sectionInfo.lineInfo)); + if (!sectionTracker.isOpen()) + return false; + m_activeSections.push_back(§ionTracker); + + m_lastAssertionInfo.lineInfo = sectionInfo.lineInfo; + + m_reporter->sectionStarting(sectionInfo); + + assertions = m_totals.assertions; + + return true; + } + auto RunContext::acquireGeneratorTracker( StringRef generatorName, SourceLineInfo const& lineInfo ) -> IGeneratorTracker& { + using namespace Generators; + GeneratorTracker& tracker = GeneratorTracker::acquire(m_trackerContext, + TestCaseTracking::NameAndLocation( static_cast<std::string>(generatorName), lineInfo ) ); + m_lastAssertionInfo.lineInfo = lineInfo; + return tracker; + } + + bool RunContext::testForMissingAssertions(Counts& assertions) { + 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; + } + + void RunContext::sectionEnded(SectionEndInfo const & endInfo) { + Counts assertions = m_totals.assertions - endInfo.prevAssertions; + bool missingAssertions = testForMissingAssertions(assertions); + + if (!m_activeSections.empty()) { + m_activeSections.back()->close(); + m_activeSections.pop_back(); + } + + m_reporter->sectionEnded(SectionStats(endInfo.sectionInfo, assertions, endInfo.durationInSeconds, missingAssertions)); + m_messages.clear(); + m_messageScopes.clear(); + } + + void RunContext::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); + } + +#if defined(CATCH_CONFIG_ENABLE_BENCHMARKING) + void RunContext::benchmarkPreparing(std::string const& name) { + m_reporter->benchmarkPreparing(name); + } + void RunContext::benchmarkStarting( BenchmarkInfo const& info ) { + m_reporter->benchmarkStarting( info ); + } + void RunContext::benchmarkEnded( BenchmarkStats<> const& stats ) { + m_reporter->benchmarkEnded( stats ); + } + void RunContext::benchmarkFailed(std::string const & error) { + m_reporter->benchmarkFailed(error); + } +#endif // CATCH_CONFIG_ENABLE_BENCHMARKING + + void RunContext::pushScopedMessage(MessageInfo const & message) { + m_messages.push_back(message); + } + + void RunContext::popScopedMessage(MessageInfo const & message) { + m_messages.erase(std::remove(m_messages.begin(), m_messages.end(), message), m_messages.end()); + } + + void RunContext::emplaceUnscopedMessage( MessageBuilder const& builder ) { + m_messageScopes.emplace_back( builder ); + } + + std::string RunContext::getCurrentTestName() const { + return m_activeTestCase + ? m_activeTestCase->getTestCaseInfo().name + : std::string(); + } + + const AssertionResult * RunContext::getLastResult() const { + return &(*m_lastResult); + } + + void RunContext::exceptionEarlyReported() { + m_shouldReportUnexpected = false; + } + + void RunContext::handleFatalErrorCondition( StringRef message ) { + // First notify reporter that bad things happened + m_reporter->fatalErrorEncountered(message); + + // Don't rebuild the result -- the stringification itself can cause more fatal errors + // Instead, fake a result data. + AssertionResultData tempResult( ResultWas::FatalErrorCondition, { false } ); + tempResult.message = static_cast<std::string>(message); + AssertionResult result(m_lastAssertionInfo, tempResult); + + assertionEnded(result); + + handleUnfinishedSections(); + + // Recreate section for test case (as we will lose the one that was in scope) + auto const& testCaseInfo = m_activeTestCase->getTestCaseInfo(); + SectionInfo testCaseSection(testCaseInfo.lineInfo, testCaseInfo.name); + + Counts assertions; + assertions.failed = 1; + SectionStats testCaseSectionStats(testCaseSection, assertions, 0, false); + m_reporter->sectionEnded(testCaseSectionStats); + + auto const& testInfo = m_activeTestCase->getTestCaseInfo(); + + Totals deltaTotals; + deltaTotals.testCases.failed = 1; + deltaTotals.assertions.failed = 1; + m_reporter->testCaseEnded(TestCaseStats(testInfo, + deltaTotals, + std::string(), + std::string(), + false)); + m_totals.testCases.failed++; + testGroupEnded(std::string(), m_totals, 1, 1); + m_reporter->testRunEnded(TestRunStats(m_runInfo, m_totals, false)); + } + + bool RunContext::lastAssertionPassed() { + return m_lastAssertionPassed; + } + + void RunContext::assertionPassed() { + m_lastAssertionPassed = true; + ++m_totals.assertions.passed; + resetAssertionInfo(); + m_messageScopes.clear(); + } + + bool RunContext::aborting() const { + return m_totals.assertions.failed >= static_cast<std::size_t>(m_config->abortAfter()); + } + + void RunContext::runCurrentTest(std::string & redirectedCout, std::string & redirectedCerr) { + auto const& testCaseInfo = m_activeTestCase->getTestCaseInfo(); + SectionInfo testCaseSection(testCaseInfo.lineInfo, testCaseInfo.name); + m_reporter->sectionStarting(testCaseSection); + Counts prevAssertions = m_totals.assertions; + double duration = 0; + m_shouldReportUnexpected = true; + m_lastAssertionInfo = { "TEST_CASE"_sr, testCaseInfo.lineInfo, StringRef(), ResultDisposition::Normal }; + + seedRng(*m_config); + + Timer timer; + CATCH_TRY { + if (m_reporter->getPreferences().shouldRedirectStdOut) { +#if !defined(CATCH_CONFIG_EXPERIMENTAL_REDIRECT) + RedirectedStreams redirectedStreams(redirectedCout, redirectedCerr); + + timer.start(); + invokeActiveTestCase(); +#else + OutputRedirect r(redirectedCout, redirectedCerr); + timer.start(); + invokeActiveTestCase(); +#endif + } else { + timer.start(); + invokeActiveTestCase(); + } + duration = timer.getElapsedSeconds(); + } CATCH_CATCH_ANON (TestFailureException&) { + // This just means the test was aborted due to failure + } CATCH_CATCH_ALL { + // Under CATCH_CONFIG_FAST_COMPILE, unexpected exceptions under REQUIRE assertions + // are reported without translation at the point of origin. + if( m_shouldReportUnexpected ) { + AssertionReaction dummyReaction; + handleUnexpectedInflightException( m_lastAssertionInfo, translateActiveException(), dummyReaction ); + } + } + Counts assertions = m_totals.assertions - prevAssertions; + bool missingAssertions = testForMissingAssertions(assertions); + + m_testCaseTracker->close(); + handleUnfinishedSections(); + m_messages.clear(); + m_messageScopes.clear(); + + SectionStats testCaseSectionStats(testCaseSection, assertions, duration, missingAssertions); + m_reporter->sectionEnded(testCaseSectionStats); + } + + void RunContext::invokeActiveTestCase() { + FatalConditionHandlerGuard _(&m_fatalConditionhandler); + m_activeTestCase->invoke(); + } + + void RunContext::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 (auto it = m_unfinishedSections.rbegin(), + itEnd = m_unfinishedSections.rend(); + it != itEnd; + ++it) + sectionEnded(*it); + m_unfinishedSections.clear(); + } + + void RunContext::handleExpr( + AssertionInfo const& info, + ITransientExpression const& expr, + AssertionReaction& reaction + ) { + m_reporter->assertionStarting( info ); + + bool negated = isFalseTest( info.resultDisposition ); + bool result = expr.getResult() != negated; + + if( result ) { + if (!m_includeSuccessfulResults) { + assertionPassed(); + } + else { + reportExpr(info, ResultWas::Ok, &expr, negated); + } + } + else { + reportExpr(info, ResultWas::ExpressionFailed, &expr, negated ); + populateReaction( reaction ); + } + } + void RunContext::reportExpr( + AssertionInfo const &info, + ResultWas::OfType resultType, + ITransientExpression const *expr, + bool negated ) { + + m_lastAssertionInfo = info; + AssertionResultData data( resultType, LazyExpression( negated ) ); + + AssertionResult assertionResult{ info, data }; + assertionResult.m_resultData.lazyExpression.m_transientExpression = expr; + + assertionEnded( assertionResult ); + } + + void RunContext::handleMessage( + AssertionInfo const& info, + ResultWas::OfType resultType, + StringRef const& message, + AssertionReaction& reaction + ) { + m_reporter->assertionStarting( info ); + + m_lastAssertionInfo = info; + + AssertionResultData data( resultType, LazyExpression( false ) ); + data.message = static_cast<std::string>(message); + AssertionResult assertionResult{ m_lastAssertionInfo, data }; + assertionEnded( assertionResult ); + if( !assertionResult.isOk() ) + populateReaction( reaction ); + } + void RunContext::handleUnexpectedExceptionNotThrown( + AssertionInfo const& info, + AssertionReaction& reaction + ) { + handleNonExpr(info, Catch::ResultWas::DidntThrowException, reaction); + } + + void RunContext::handleUnexpectedInflightException( + AssertionInfo const& info, + std::string const& message, + AssertionReaction& reaction + ) { + m_lastAssertionInfo = info; + + AssertionResultData data( ResultWas::ThrewException, LazyExpression( false ) ); + data.message = message; + AssertionResult assertionResult{ info, data }; + assertionEnded( assertionResult ); + populateReaction( reaction ); + } + + void RunContext::populateReaction( AssertionReaction& reaction ) { + reaction.shouldDebugBreak = m_config->shouldDebugBreak(); + reaction.shouldThrow = aborting() || (m_lastAssertionInfo.resultDisposition & ResultDisposition::Normal); + } + + void RunContext::handleIncomplete( + AssertionInfo const& info + ) { + m_lastAssertionInfo = info; + + AssertionResultData data( ResultWas::ThrewException, LazyExpression( false ) ); + data.message = "Exception translation was disabled by CATCH_CONFIG_FAST_COMPILE"; + AssertionResult assertionResult{ info, data }; + assertionEnded( assertionResult ); + } + void RunContext::handleNonExpr( + AssertionInfo const &info, + ResultWas::OfType resultType, + AssertionReaction &reaction + ) { + m_lastAssertionInfo = info; + + AssertionResultData data( resultType, LazyExpression( false ) ); + AssertionResult assertionResult{ info, data }; + assertionEnded( assertionResult ); + + if( !assertionResult.isOk() ) + populateReaction( reaction ); + } + + IResultCapture& getResultCapture() { + if (auto* capture = getCurrentContext().getResultCapture()) + return *capture; + else + CATCH_INTERNAL_ERROR("No result capture instance"); + } + + void seedRng(IConfig const& config) { + if (config.rngSeed() != 0) { + std::srand(config.rngSeed()); + rng().seed(config.rngSeed()); + } + } + + unsigned int rngSeed() { + return getCurrentContext().getConfig()->rngSeed(); + } + +} +// end catch_run_context.cpp +// start catch_section.cpp + +namespace Catch { + + Section::Section( SectionInfo const& info ) + : m_info( info ), + m_sectionIncluded( getResultCapture().sectionStarted( m_info, m_assertions ) ) + { + m_timer.start(); + } + + Section::~Section() { + if( m_sectionIncluded ) { + SectionEndInfo endInfo{ m_info, m_assertions, m_timer.getElapsedSeconds() }; + if( uncaught_exceptions() ) + getResultCapture().sectionEndedEarly( endInfo ); + else + getResultCapture().sectionEnded( endInfo ); + } + } + + // This indicates whether the section should be executed or not + Section::operator bool() const { + return m_sectionIncluded; + } + +} // end namespace Catch +// end catch_section.cpp +// start catch_section_info.cpp + +namespace Catch { + + SectionInfo::SectionInfo + ( SourceLineInfo const& _lineInfo, + std::string const& _name ) + : name( _name ), + lineInfo( _lineInfo ) + {} + +} // end namespace Catch +// end catch_section_info.cpp +// start catch_session.cpp + +// start catch_session.h + +#include <memory> + +namespace Catch { + + class Session : NonCopyable { + public: + + Session(); + ~Session() override; + + void showHelp() const; + void libIdentify(); + + int applyCommandLine( int argc, char const * const * argv ); + #if defined(CATCH_CONFIG_WCHAR) && defined(_WIN32) && defined(UNICODE) + int applyCommandLine( int argc, wchar_t const * const * argv ); + #endif + + void useConfigData( ConfigData const& configData ); + + template<typename CharT> + int run(int argc, CharT const * const argv[]) { + if (m_startupExceptions) + return 1; + int returnCode = applyCommandLine(argc, argv); + if (returnCode == 0) + returnCode = run(); + return returnCode; + } + + int run(); + + clara::Parser const& cli() const; + void cli( clara::Parser const& newParser ); + ConfigData& configData(); + Config& config(); + private: + int runInternal(); + + clara::Parser m_cli; + ConfigData m_configData; + std::shared_ptr<Config> m_config; + bool m_startupExceptions = false; + }; + +} // end namespace Catch + +// end catch_session.h +// start catch_version.h + +#include <iosfwd> + +namespace Catch { + + // Versioning information + struct Version { + Version( Version const& ) = delete; + Version& operator=( Version const& ) = delete; + Version( unsigned int _majorVersion, + unsigned int _minorVersion, + unsigned int _patchNumber, + char const * const _branchName, + unsigned int _buildNumber ); + + unsigned int const majorVersion; + unsigned int const minorVersion; + unsigned int const patchNumber; + + // buildNumber is only used if branchName is not null + char const * const branchName; + unsigned int const buildNumber; + + friend std::ostream& operator << ( std::ostream& os, Version const& version ); + }; + + Version const& libraryVersion(); +} + +// end catch_version.h +#include <cstdlib> +#include <iomanip> +#include <set> +#include <iterator> + +namespace Catch { + + namespace { + const int MaxExitCode = 255; + + IStreamingReporterPtr createReporter(std::string const& reporterName, IConfigPtr const& config) { + auto reporter = Catch::getRegistryHub().getReporterRegistry().create(reporterName, config); + CATCH_ENFORCE(reporter, "No reporter registered with name: '" << reporterName << "'"); + + return reporter; + } + + IStreamingReporterPtr makeReporter(std::shared_ptr<Config> const& config) { + if (Catch::getRegistryHub().getReporterRegistry().getListeners().empty()) { + return createReporter(config->getReporterName(), config); + } + + // On older platforms, returning std::unique_ptr<ListeningReporter> + // when the return type is std::unique_ptr<IStreamingReporter> + // doesn't compile without a std::move call. However, this causes + // a warning on newer platforms. Thus, we have to work around + // it a bit and downcast the pointer manually. + auto ret = std::unique_ptr<IStreamingReporter>(new ListeningReporter); + auto& multi = static_cast<ListeningReporter&>(*ret); + auto const& listeners = Catch::getRegistryHub().getReporterRegistry().getListeners(); + for (auto const& listener : listeners) { + multi.addListener(listener->create(Catch::ReporterConfig(config))); + } + multi.addReporter(createReporter(config->getReporterName(), config)); + return ret; + } + + class TestGroup { + public: + explicit TestGroup(std::shared_ptr<Config> const& config) + : m_config{config} + , m_context{config, makeReporter(config)} + { + auto const& allTestCases = getAllTestCasesSorted(*m_config); + m_matches = m_config->testSpec().matchesByFilter(allTestCases, *m_config); + auto const& invalidArgs = m_config->testSpec().getInvalidArgs(); + + if (m_matches.empty() && invalidArgs.empty()) { + for (auto const& test : allTestCases) + if (!test.isHidden()) + m_tests.emplace(&test); + } else { + for (auto const& match : m_matches) + m_tests.insert(match.tests.begin(), match.tests.end()); + } + } + + Totals execute() { + auto const& invalidArgs = m_config->testSpec().getInvalidArgs(); + Totals totals; + m_context.testGroupStarting(m_config->name(), 1, 1); + for (auto const& testCase : m_tests) { + if (!m_context.aborting()) + totals += m_context.runTest(*testCase); + else + m_context.reporter().skipTest(*testCase); + } + + for (auto const& match : m_matches) { + if (match.tests.empty()) { + m_context.reporter().noMatchingTestCases(match.name); + totals.error = -1; + } + } + + if (!invalidArgs.empty()) { + for (auto const& invalidArg: invalidArgs) + m_context.reporter().reportInvalidArguments(invalidArg); + } + + m_context.testGroupEnded(m_config->name(), totals, 1, 1); + return totals; + } + + private: + using Tests = std::set<TestCase const*>; + + std::shared_ptr<Config> m_config; + RunContext m_context; + Tests m_tests; + TestSpec::Matches m_matches; + }; + + void applyFilenamesAsTags(Catch::IConfig const& config) { + auto& tests = const_cast<std::vector<TestCase>&>(getAllTestCasesSorted(config)); + for (auto& testCase : tests) { + auto tags = testCase.tags; + + std::string filename = testCase.lineInfo.file; + auto lastSlash = filename.find_last_of("\\/"); + if (lastSlash != std::string::npos) { + filename.erase(0, lastSlash); + filename[0] = '#'; + } + else + { + filename.insert(0, "#"); + } + + auto lastDot = filename.find_last_of('.'); + if (lastDot != std::string::npos) { + filename.erase(lastDot); + } + + tags.push_back(std::move(filename)); + setTags(testCase, tags); + } + } + + } // anon namespace + + Session::Session() { + static bool alreadyInstantiated = false; + if( alreadyInstantiated ) { + CATCH_TRY { CATCH_INTERNAL_ERROR( "Only one instance of Catch::Session can ever be used" ); } + CATCH_CATCH_ALL { getMutableRegistryHub().registerStartupException(); } + } + + // There cannot be exceptions at startup in no-exception mode. +#if !defined(CATCH_CONFIG_DISABLE_EXCEPTIONS) + const auto& exceptions = getRegistryHub().getStartupExceptionRegistry().getExceptions(); + if ( !exceptions.empty() ) { + config(); + getCurrentMutableContext().setConfig(m_config); + + m_startupExceptions = true; + Colour colourGuard( Colour::Red ); + Catch::cerr() << "Errors occurred during startup!" << '\n'; + // iterate over all exceptions and notify user + for ( const auto& ex_ptr : exceptions ) { + try { + std::rethrow_exception(ex_ptr); + } catch ( std::exception const& ex ) { + Catch::cerr() << Column( ex.what() ).indent(2) << '\n'; + } + } + } +#endif + + alreadyInstantiated = true; + m_cli = makeCommandLineParser( m_configData ); + } + Session::~Session() { + Catch::cleanUp(); + } + + void Session::showHelp() const { + Catch::cout() + << "\nCatch v" << libraryVersion() << "\n" + << m_cli << std::endl + << "For more detailed usage please see the project docs\n" << std::endl; + } + void Session::libIdentify() { + Catch::cout() + << std::left << std::setw(16) << "description: " << "A Catch2 test executable\n" + << std::left << std::setw(16) << "category: " << "testframework\n" + << std::left << std::setw(16) << "framework: " << "Catch Test\n" + << std::left << std::setw(16) << "version: " << libraryVersion() << std::endl; + } + + int Session::applyCommandLine( int argc, char const * const * argv ) { + if( m_startupExceptions ) + return 1; + + auto result = m_cli.parse( clara::Args( argc, argv ) ); + if( !result ) { + config(); + getCurrentMutableContext().setConfig(m_config); + Catch::cerr() + << Colour( Colour::Red ) + << "\nError(s) in input:\n" + << Column( result.errorMessage() ).indent( 2 ) + << "\n\n"; + Catch::cerr() << "Run with -? for usage\n" << std::endl; + return MaxExitCode; + } + + if( m_configData.showHelp ) + showHelp(); + if( m_configData.libIdentify ) + libIdentify(); + m_config.reset(); + return 0; + } + +#if defined(CATCH_CONFIG_WCHAR) && defined(_WIN32) && defined(UNICODE) + int Session::applyCommandLine( int argc, wchar_t const * const * argv ) { + + char **utf8Argv = new char *[ argc ]; + + for ( int i = 0; i < argc; ++i ) { + int bufSize = WideCharToMultiByte( CP_UTF8, 0, argv[i], -1, nullptr, 0, nullptr, nullptr ); + + utf8Argv[ i ] = new char[ bufSize ]; + + WideCharToMultiByte( CP_UTF8, 0, argv[i], -1, utf8Argv[i], bufSize, nullptr, nullptr ); + } + + int returnCode = applyCommandLine( argc, utf8Argv ); + + for ( int i = 0; i < argc; ++i ) + delete [] utf8Argv[ i ]; + + delete [] utf8Argv; + + return returnCode; + } +#endif + + void Session::useConfigData( ConfigData const& configData ) { + m_configData = configData; + m_config.reset(); + } + + int Session::run() { + if( ( m_configData.waitForKeypress & WaitForKeypress::BeforeStart ) != 0 ) { + Catch::cout() << "...waiting for enter/ return before starting" << std::endl; + static_cast<void>(std::getchar()); + } + int exitCode = runInternal(); + if( ( m_configData.waitForKeypress & WaitForKeypress::BeforeExit ) != 0 ) { + Catch::cout() << "...waiting for enter/ return before exiting, with code: " << exitCode << std::endl; + static_cast<void>(std::getchar()); + } + return exitCode; + } + + clara::Parser const& Session::cli() const { + return m_cli; + } + void Session::cli( clara::Parser const& newParser ) { + m_cli = newParser; + } + ConfigData& Session::configData() { + return m_configData; + } + Config& Session::config() { + if( !m_config ) + m_config = std::make_shared<Config>( m_configData ); + return *m_config; + } + + int Session::runInternal() { + if( m_startupExceptions ) + return 1; + + if (m_configData.showHelp || m_configData.libIdentify) { + return 0; + } + + CATCH_TRY { + config(); // Force config to be constructed + + seedRng( *m_config ); + + if( m_configData.filenamesAsTags ) + applyFilenamesAsTags( *m_config ); + + // Handle list request + if( Option<std::size_t> listed = list( m_config ) ) + return (std::min) (MaxExitCode, static_cast<int>(*listed)); + + TestGroup tests { m_config }; + auto const totals = tests.execute(); + + if( m_config->warnAboutNoTests() && totals.error == -1 ) + return 2; + + // Note that on unices only the lower 8 bits are usually used, clamping + // the return value to 255 prevents false negative when some multiple + // of 256 tests has failed + return (std::min) (MaxExitCode, (std::max) (totals.error, static_cast<int>(totals.assertions.failed))); + } +#if !defined(CATCH_CONFIG_DISABLE_EXCEPTIONS) + catch( std::exception& ex ) { + Catch::cerr() << ex.what() << std::endl; + return MaxExitCode; + } +#endif + } + +} // end namespace Catch +// end catch_session.cpp +// start catch_singletons.cpp + +#include <vector> + +namespace Catch { + + namespace { + static auto getSingletons() -> std::vector<ISingleton*>*& { + static std::vector<ISingleton*>* g_singletons = nullptr; + if( !g_singletons ) + g_singletons = new std::vector<ISingleton*>(); + return g_singletons; + } + } + + ISingleton::~ISingleton() {} + + void addSingleton(ISingleton* singleton ) { + getSingletons()->push_back( singleton ); + } + void cleanupSingletons() { + auto& singletons = getSingletons(); + for( auto singleton : *singletons ) + delete singleton; + delete singletons; + singletons = nullptr; + } + +} // namespace Catch +// end catch_singletons.cpp +// start catch_startup_exception_registry.cpp + +#if !defined(CATCH_CONFIG_DISABLE_EXCEPTIONS) +namespace Catch { +void StartupExceptionRegistry::add( std::exception_ptr const& exception ) noexcept { + CATCH_TRY { + m_exceptions.push_back(exception); + } CATCH_CATCH_ALL { + // If we run out of memory during start-up there's really not a lot more we can do about it + std::terminate(); + } + } + + std::vector<std::exception_ptr> const& StartupExceptionRegistry::getExceptions() const noexcept { + return m_exceptions; + } + +} // end namespace Catch +#endif +// end catch_startup_exception_registry.cpp +// start catch_stream.cpp + +#include <cstdio> +#include <iostream> +#include <fstream> +#include <sstream> +#include <vector> +#include <memory> + +namespace Catch { + + Catch::IStream::~IStream() = default; + + namespace Detail { namespace { + template<typename WriterF, std::size_t bufferSize=256> + class StreamBufImpl : public std::streambuf { + char data[bufferSize]; + WriterF m_writer; + + public: + StreamBufImpl() { + setp( data, data + sizeof(data) ); + } + + ~StreamBufImpl() noexcept { + StreamBufImpl::sync(); + } + + private: + int overflow( int c ) override { + sync(); + + if( c != EOF ) { + if( pbase() == epptr() ) + m_writer( std::string( 1, static_cast<char>( c ) ) ); + else + sputc( static_cast<char>( c ) ); + } + return 0; + } + + int sync() override { + if( pbase() != pptr() ) { + m_writer( std::string( pbase(), static_cast<std::string::size_type>( pptr() - pbase() ) ) ); + setp( pbase(), epptr() ); + } + return 0; + } + }; + + /////////////////////////////////////////////////////////////////////////// + + struct OutputDebugWriter { + + void operator()( std::string const&str ) { + writeToDebugConsole( str ); + } + }; + + /////////////////////////////////////////////////////////////////////////// + + class FileStream : public IStream { + mutable std::ofstream m_ofs; + public: + FileStream( StringRef filename ) { + m_ofs.open( filename.c_str() ); + CATCH_ENFORCE( !m_ofs.fail(), "Unable to open file: '" << filename << "'" ); + } + ~FileStream() override = default; + public: // IStream + std::ostream& stream() const override { + return m_ofs; + } + }; + + /////////////////////////////////////////////////////////////////////////// + + class CoutStream : public IStream { + mutable std::ostream m_os; + public: + // Store the streambuf from cout up-front because + // cout may get redirected when running tests + CoutStream() : m_os( Catch::cout().rdbuf() ) {} + ~CoutStream() override = default; + + public: // IStream + std::ostream& stream() const override { return m_os; } + }; + + /////////////////////////////////////////////////////////////////////////// + + class DebugOutStream : public IStream { + std::unique_ptr<StreamBufImpl<OutputDebugWriter>> m_streamBuf; + mutable std::ostream m_os; + public: + DebugOutStream() + : m_streamBuf( new StreamBufImpl<OutputDebugWriter>() ), + m_os( m_streamBuf.get() ) + {} + + ~DebugOutStream() override = default; + + public: // IStream + std::ostream& stream() const override { return m_os; } + }; + + }} // namespace anon::detail + + /////////////////////////////////////////////////////////////////////////// + + auto makeStream( StringRef const &filename ) -> IStream const* { + if( filename.empty() ) + return new Detail::CoutStream(); + else if( filename[0] == '%' ) { + if( filename == "%debug" ) + return new Detail::DebugOutStream(); + else + CATCH_ERROR( "Unrecognised stream: '" << filename << "'" ); + } + else + return new Detail::FileStream( filename ); + } + + // This class encapsulates the idea of a pool of ostringstreams that can be reused. + struct StringStreams { + std::vector<std::unique_ptr<std::ostringstream>> m_streams; + std::vector<std::size_t> m_unused; + std::ostringstream m_referenceStream; // Used for copy state/ flags from + + auto add() -> std::size_t { + if( m_unused.empty() ) { + m_streams.push_back( std::unique_ptr<std::ostringstream>( new std::ostringstream ) ); + return m_streams.size()-1; + } + else { + auto index = m_unused.back(); + m_unused.pop_back(); + return index; + } + } + + void release( std::size_t index ) { + m_streams[index]->copyfmt( m_referenceStream ); // Restore initial flags and other state + m_unused.push_back(index); + } + }; + + ReusableStringStream::ReusableStringStream() + : m_index( Singleton<StringStreams>::getMutable().add() ), + m_oss( Singleton<StringStreams>::getMutable().m_streams[m_index].get() ) + {} + + ReusableStringStream::~ReusableStringStream() { + static_cast<std::ostringstream*>( m_oss )->str(""); + m_oss->clear(); + Singleton<StringStreams>::getMutable().release( m_index ); + } + + auto ReusableStringStream::str() const -> std::string { + return static_cast<std::ostringstream*>( m_oss )->str(); + } + + /////////////////////////////////////////////////////////////////////////// + +#ifndef CATCH_CONFIG_NOSTDOUT // If you #define this you must implement these functions + std::ostream& cout() { return std::cout; } + std::ostream& cerr() { return std::cerr; } + std::ostream& clog() { return std::clog; } +#endif +} +// end catch_stream.cpp +// start catch_string_manip.cpp + +#include <algorithm> +#include <ostream> +#include <cstring> +#include <cctype> +#include <vector> + +namespace Catch { + + namespace { + char toLowerCh(char c) { + return static_cast<char>( std::tolower( static_cast<unsigned char>(c) ) ); + } + } + + bool startsWith( std::string const& s, std::string const& prefix ) { + return s.size() >= prefix.size() && std::equal(prefix.begin(), prefix.end(), s.begin()); + } + bool startsWith( std::string const& s, char prefix ) { + return !s.empty() && s[0] == prefix; + } + bool endsWith( std::string const& s, std::string const& suffix ) { + return s.size() >= suffix.size() && std::equal(suffix.rbegin(), suffix.rend(), s.rbegin()); + } + bool endsWith( std::string const& s, char suffix ) { + return !s.empty() && s[s.size()-1] == suffix; + } + bool contains( std::string const& s, std::string const& infix ) { + return s.find( infix ) != std::string::npos; + } + void toLowerInPlace( std::string& s ) { + std::transform( s.begin(), s.end(), s.begin(), toLowerCh ); + } + std::string toLower( std::string const& s ) { + std::string lc = s; + toLowerInPlace( lc ); + return lc; + } + std::string trim( std::string const& str ) { + static char const* whitespaceChars = "\n\r\t "; + std::string::size_type start = str.find_first_not_of( whitespaceChars ); + std::string::size_type end = str.find_last_not_of( whitespaceChars ); + + return start != std::string::npos ? str.substr( start, 1+end-start ) : std::string(); + } + + StringRef trim(StringRef ref) { + const auto is_ws = [](char c) { + return c == ' ' || c == '\t' || c == '\n' || c == '\r'; + }; + size_t real_begin = 0; + while (real_begin < ref.size() && is_ws(ref[real_begin])) { ++real_begin; } + size_t real_end = ref.size(); + while (real_end > real_begin && is_ws(ref[real_end - 1])) { --real_end; } + + return ref.substr(real_begin, real_end - real_begin); + } + + bool replaceInPlace( std::string& str, std::string const& replaceThis, std::string const& withThis ) { + bool replaced = false; + std::size_t i = str.find( replaceThis ); + while( i != std::string::npos ) { + replaced = true; + str = str.substr( 0, i ) + withThis + str.substr( i+replaceThis.size() ); + if( i < str.size()-withThis.size() ) + i = str.find( replaceThis, i+withThis.size() ); + else + i = std::string::npos; + } + return replaced; + } + + std::vector<StringRef> splitStringRef( StringRef str, char delimiter ) { + std::vector<StringRef> subStrings; + std::size_t start = 0; + for(std::size_t pos = 0; pos < str.size(); ++pos ) { + if( str[pos] == delimiter ) { + if( pos - start > 1 ) + subStrings.push_back( str.substr( start, pos-start ) ); + start = pos+1; + } + } + if( start < str.size() ) + subStrings.push_back( str.substr( start, str.size()-start ) ); + return subStrings; + } + + pluralise::pluralise( std::size_t count, std::string const& label ) + : m_count( count ), + m_label( label ) + {} + + std::ostream& operator << ( std::ostream& os, pluralise const& pluraliser ) { + os << pluraliser.m_count << ' ' << pluraliser.m_label; + if( pluraliser.m_count != 1 ) + os << 's'; + return os; + } + +} +// end catch_string_manip.cpp +// start catch_stringref.cpp + +#include <algorithm> +#include <ostream> +#include <cstring> +#include <cstdint> + +namespace Catch { + StringRef::StringRef( char const* rawChars ) noexcept + : StringRef( rawChars, static_cast<StringRef::size_type>(std::strlen(rawChars) ) ) + {} + + auto StringRef::c_str() const -> char const* { + CATCH_ENFORCE(isNullTerminated(), "Called StringRef::c_str() on a non-null-terminated instance"); + return m_start; + } + auto StringRef::data() const noexcept -> char const* { + return m_start; + } + + auto StringRef::substr( size_type start, size_type size ) const noexcept -> StringRef { + if (start < m_size) { + return StringRef(m_start + start, (std::min)(m_size - start, size)); + } else { + return StringRef(); + } + } + auto StringRef::operator == ( StringRef const& other ) const noexcept -> bool { + return m_size == other.m_size + && (std::memcmp( m_start, other.m_start, m_size ) == 0); + } + + auto operator << ( std::ostream& os, StringRef const& str ) -> std::ostream& { + return os.write(str.data(), str.size()); + } + + auto operator+=( std::string& lhs, StringRef const& rhs ) -> std::string& { + lhs.append(rhs.data(), rhs.size()); + return lhs; + } + +} // namespace Catch +// end catch_stringref.cpp +// start catch_tag_alias.cpp + +namespace Catch { + TagAlias::TagAlias(std::string const & _tag, SourceLineInfo _lineInfo): tag(_tag), lineInfo(_lineInfo) {} +} +// end catch_tag_alias.cpp +// start catch_tag_alias_autoregistrar.cpp + +namespace Catch { + + RegistrarForTagAliases::RegistrarForTagAliases(char const* alias, char const* tag, SourceLineInfo const& lineInfo) { + CATCH_TRY { + getMutableRegistryHub().registerTagAlias(alias, tag, lineInfo); + } CATCH_CATCH_ALL { + // Do not throw when constructing global objects, instead register the exception to be processed later + getMutableRegistryHub().registerStartupException(); + } } - bool AssertionResult::hasExpression() const { - return m_info.capturedExpression[0] != 0; - } +} +// end catch_tag_alias_autoregistrar.cpp +// start catch_tag_alias_registry.cpp - bool AssertionResult::hasMessage() const { - return !m_resultData.message.empty(); - } +#include <sstream> - std::string capturedExpressionWithSecondArgument( char const * capturedExpression, char const * secondArg ) { - return (secondArg[0] == 0 || secondArg[0] == '"' && secondArg[1] == '"') - ? capturedExpression - : std::string(capturedExpression) + ", " + secondArg; - } +namespace Catch { - std::string AssertionResult::getExpression() const { - if( isFalseTest( m_info.resultDisposition ) ) - return "!(" + capturedExpressionWithSecondArgument(m_info.capturedExpression, m_info.secondArg) + ")"; - else - return capturedExpressionWithSecondArgument(m_info.capturedExpression, m_info.secondArg); - } - std::string AssertionResult::getExpressionInMacro() const { - if( m_info.macroName[0] == 0 ) - return capturedExpressionWithSecondArgument(m_info.capturedExpression, m_info.secondArg); - else - return std::string(m_info.macroName) + "( " + capturedExpressionWithSecondArgument(m_info.capturedExpression, m_info.secondArg) + " )"; - } + TagAliasRegistry::~TagAliasRegistry() {} - bool AssertionResult::hasExpandedExpression() const { - return hasExpression() && getExpandedExpression() != getExpression(); + TagAlias const* TagAliasRegistry::find( std::string const& alias ) const { + auto it = m_registry.find( alias ); + if( it != m_registry.end() ) + return &(it->second); + else + return nullptr; } - std::string AssertionResult::getExpandedExpression() const { - return m_resultData.reconstructExpression(); + std::string TagAliasRegistry::expandAliases( std::string const& unexpandedTestSpec ) const { + std::string expandedTestSpec = unexpandedTestSpec; + for( auto const& registryKvp : m_registry ) { + std::size_t pos = expandedTestSpec.find( registryKvp.first ); + if( pos != std::string::npos ) { + expandedTestSpec = expandedTestSpec.substr( 0, pos ) + + registryKvp.second.tag + + expandedTestSpec.substr( pos + registryKvp.first.size() ); + } + } + return expandedTestSpec; } - std::string AssertionResult::getMessage() const { - return m_resultData.message; - } - SourceLineInfo AssertionResult::getSourceInfo() const { - return m_info.lineInfo; - } + void TagAliasRegistry::add( std::string const& alias, std::string const& tag, SourceLineInfo const& lineInfo ) { + CATCH_ENFORCE( startsWith(alias, "[@") && endsWith(alias, ']'), + "error: tag alias, '" << alias << "' is not of the form [@alias name].\n" << lineInfo ); - std::string AssertionResult::getTestMacroName() const { - return m_info.macroName; + CATCH_ENFORCE( m_registry.insert(std::make_pair(alias, TagAlias(tag, lineInfo))).second, + "error: tag alias, '" << alias << "' already registered.\n" + << "\tFirst seen at: " << find(alias)->lineInfo << "\n" + << "\tRedefined at: " << lineInfo ); } - void AssertionResult::discardDecomposedExpression() const { - m_resultData.decomposedExpression = CATCH_NULL; - } + ITagAliasRegistry::~ITagAliasRegistry() {} - void AssertionResult::expandDecomposedExpression() const { - m_resultData.reconstructExpression(); + ITagAliasRegistry const& ITagAliasRegistry::get() { + return getRegistryHub().getTagAliasRegistry(); } } // end namespace Catch - -// #included from: catch_test_case_info.hpp -#define TWOBLUECUBES_CATCH_TEST_CASE_INFO_HPP_INCLUDED +// end catch_tag_alias_registry.cpp +// start catch_test_case_info.cpp #include <cctype> +#include <exception> +#include <algorithm> +#include <sstream> namespace Catch { - inline TestCaseInfo::SpecialProperties parseSpecialTag( std::string const& tag ) { - if( startsWith( tag, '.' ) || - tag == "hide" || - tag == "!hide" ) - return TestCaseInfo::IsHidden; - else if( tag == "!throws" ) - return TestCaseInfo::Throws; - else if( tag == "!shouldfail" ) - return TestCaseInfo::ShouldFail; - else if( tag == "!mayfail" ) - return TestCaseInfo::MayFail; - else if( tag == "!nonportable" ) - return TestCaseInfo::NonPortable; - else - return TestCaseInfo::None; - } - inline bool isReservedTag( std::string const& tag ) { - return parseSpecialTag( tag ) == TestCaseInfo::None && tag.size() > 0 && !std::isalnum( tag[0] ); - } - inline void enforceNotReservedTag( std::string const& tag, SourceLineInfo const& _lineInfo ) { - if( isReservedTag( tag ) ) { - std::ostringstream ss; - ss << Colour(Colour::Red) - << "Tag name [" << tag << "] not allowed.\n" - << "Tag names starting with non alpha-numeric characters are reserved\n" - << Colour(Colour::FileName) - << _lineInfo << '\n'; - throw std::runtime_error(ss.str()); + namespace { + TestCaseInfo::SpecialProperties parseSpecialTag( std::string const& tag ) { + if( startsWith( tag, '.' ) || + tag == "!hide" ) + return TestCaseInfo::IsHidden; + else if( tag == "!throws" ) + return TestCaseInfo::Throws; + else if( tag == "!shouldfail" ) + return TestCaseInfo::ShouldFail; + else if( tag == "!mayfail" ) + return TestCaseInfo::MayFail; + else if( tag == "!nonportable" ) + return TestCaseInfo::NonPortable; + else if( tag == "!benchmark" ) + return static_cast<TestCaseInfo::SpecialProperties>( TestCaseInfo::Benchmark | TestCaseInfo::IsHidden ); + else + return TestCaseInfo::None; + } + bool isReservedTag( std::string const& tag ) { + return parseSpecialTag( tag ) == TestCaseInfo::None && tag.size() > 0 && !std::isalnum( static_cast<unsigned char>(tag[0]) ); + } + void enforceNotReservedTag( std::string const& tag, SourceLineInfo const& _lineInfo ) { + CATCH_ENFORCE( !isReservedTag(tag), + "Tag name: [" << tag << "] is not allowed.\n" + << "Tag names starting with non alphanumeric characters are reserved\n" + << _lineInfo ); } } - TestCase makeTestCase( ITestCase* _testCase, + TestCase makeTestCase( ITestInvoker* _testCase, std::string const& _className, - std::string const& _name, - std::string const& _descOrTags, + NameAndTags const& nameAndTags, SourceLineInfo const& _lineInfo ) { - bool isHidden( startsWith( _name, "./" ) ); // Legacy support + bool isHidden = false; // Parse out tags - std::set<std::string> tags; + std::vector<std::string> tags; std::string desc, tag; bool inTag = false; - for( std::size_t i = 0; i < _descOrTags.size(); ++i ) { - char c = _descOrTags[i]; + for (char c : nameAndTags.tags) { if( !inTag ) { if( c == '[' ) inTag = true; @@ -8310,12 +14072,18 @@ namespace Catch { else { if( c == ']' ) { TestCaseInfo::SpecialProperties prop = parseSpecialTag( tag ); - if( prop == TestCaseInfo::IsHidden ) + if( ( prop & TestCaseInfo::IsHidden ) != 0 ) isHidden = true; else if( prop == TestCaseInfo::None ) enforceNotReservedTag( tag, _lineInfo ); - tags.insert( tag ); + // Merged hide tags like `[.approvals]` should be added as + // `[.][approvals]`. The `[.]` is added at later point, so + // we only strip the prefix + if (startsWith(tag, '.') && tag.size() > 1) { + tag.erase(0, 1); + } + tags.push_back( tag ); tag.clear(); inTag = false; } @@ -8324,33 +14092,31 @@ namespace Catch { } } if( isHidden ) { - tags.insert( "hide" ); - tags.insert( "." ); + // Add all "hidden" tags to make them behave identically + tags.insert( tags.end(), { ".", "!hide" } ); } - TestCaseInfo info( _name, _className, desc, tags, _lineInfo ); - return TestCase( _testCase, info ); + TestCaseInfo info( static_cast<std::string>(nameAndTags.name), _className, desc, tags, _lineInfo ); + return TestCase( _testCase, std::move(info) ); } - void setTags( TestCaseInfo& testCaseInfo, std::set<std::string> const& tags ) - { - testCaseInfo.tags = tags; + void setTags( TestCaseInfo& testCaseInfo, std::vector<std::string> tags ) { + std::sort(begin(tags), end(tags)); + tags.erase(std::unique(begin(tags), end(tags)), end(tags)); testCaseInfo.lcaseTags.clear(); - std::ostringstream oss; - for( std::set<std::string>::const_iterator it = tags.begin(), itEnd = tags.end(); it != itEnd; ++it ) { - oss << '[' << *it << ']'; - std::string lcaseTag = toLower( *it ); + for( auto const& tag : tags ) { + std::string lcaseTag = toLower( tag ); testCaseInfo.properties = static_cast<TestCaseInfo::SpecialProperties>( testCaseInfo.properties | parseSpecialTag( lcaseTag ) ); - testCaseInfo.lcaseTags.insert( lcaseTag ); + testCaseInfo.lcaseTags.push_back( lcaseTag ); } - testCaseInfo.tagsAsString = oss.str(); + testCaseInfo.tags = std::move(tags); } TestCaseInfo::TestCaseInfo( std::string const& _name, std::string const& _className, std::string const& _description, - std::set<std::string> const& _tags, + std::vector<std::string> const& _tags, SourceLineInfo const& _lineInfo ) : name( _name ), className( _className ), @@ -8361,17 +14127,6 @@ namespace Catch { setTags( *this, _tags ); } - TestCaseInfo::TestCaseInfo( TestCaseInfo const& other ) - : name( other.name ), - className( other.className ), - description( other.description ), - tags( other.tags ), - lcaseTags( other.lcaseTags ), - tagsAsString( other.tagsAsString ), - lineInfo( other.lineInfo ), - properties( other.properties ) - {} - bool TestCaseInfo::isHidden() const { return ( properties & IsHidden ) != 0; } @@ -8385,12 +14140,24 @@ namespace Catch { return ( properties & (ShouldFail ) ) != 0; } - TestCase::TestCase( ITestCase* testCase, TestCaseInfo const& info ) : TestCaseInfo( info ), test( testCase ) {} + std::string TestCaseInfo::tagsAsString() const { + std::string ret; + // '[' and ']' per tag + std::size_t full_size = 2 * tags.size(); + for (const auto& tag : tags) { + full_size += tag.size(); + } + ret.reserve(full_size); + for (const auto& tag : tags) { + ret.push_back('['); + ret.append(tag); + ret.push_back(']'); + } - TestCase::TestCase( TestCase const& other ) - : TestCaseInfo( other ), - test( other.test ) - {} + return ret; + } + + TestCase::TestCase( ITestInvoker* testCase, TestCaseInfo&& info ) : TestCaseInfo( std::move(info) ), test( testCase ) {} TestCase TestCase::withName( std::string const& _newName ) const { TestCase other( *this ); @@ -8398,18 +14165,6 @@ namespace Catch { return other; } - void TestCase::swap( TestCase& other ) { - test.swap( other.test ); - name.swap( other.name ); - className.swap( other.className ); - description.swap( other.description ); - tags.swap( other.tags ); - lcaseTags.swap( other.lcaseTags ); - tagsAsString.swap( other.tagsAsString ); - std::swap( TestCaseInfo::properties, static_cast<TestCaseInfo&>( other ).properties ); - std::swap( lineInfo, other.lineInfo ); - } - void TestCase::invoke() const { test->invoke(); } @@ -8423,11 +14178,6 @@ namespace Catch { bool TestCase::operator < ( TestCase const& other ) const { return name < other.name; } - TestCase& TestCase::operator = ( TestCase const& other ) { - TestCase temp( other ); - swap( temp ); - return *this; - } TestCaseInfo const& TestCase::getTestCaseInfo() const { @@ -8435,1995 +14185,2624 @@ namespace Catch { } } // end namespace Catch +// end catch_test_case_info.cpp +// start catch_test_case_registry_impl.cpp -// #included from: catch_version.hpp -#define TWOBLUECUBES_CATCH_VERSION_HPP_INCLUDED - -namespace Catch { - - Version::Version - ( unsigned int _majorVersion, - unsigned int _minorVersion, - unsigned int _patchNumber, - char const * const _branchName, - unsigned int _buildNumber ) - : majorVersion( _majorVersion ), - minorVersion( _minorVersion ), - patchNumber( _patchNumber ), - branchName( _branchName ), - buildNumber( _buildNumber ) - {} - - std::ostream& operator << ( std::ostream& os, Version const& version ) { - os << version.majorVersion << '.' - << version.minorVersion << '.' - << version.patchNumber; - // branchName is never null -> 0th char is \0 if it is empty - if (version.branchName[0]) { - os << '-' << version.branchName - << '.' << version.buildNumber; - } - return os; - } - - inline Version libraryVersion() { - static Version version( 1, 12, 2, "", 0 ); - return version; - } - -} - -// #included from: catch_message.hpp -#define TWOBLUECUBES_CATCH_MESSAGE_HPP_INCLUDED +#include <algorithm> +#include <sstream> namespace Catch { - MessageInfo::MessageInfo( std::string const& _macroName, - SourceLineInfo const& _lineInfo, - ResultWas::OfType _type ) - : macroName( _macroName ), - lineInfo( _lineInfo ), - type( _type ), - sequence( ++globalCount ) - {} - - // This may need protecting if threading support is added - unsigned int MessageInfo::globalCount = 0; - - //////////////////////////////////////////////////////////////////////////// - - ScopedMessage::ScopedMessage( MessageBuilder const& builder ) - : m_info( builder.m_info ) - { - m_info.message = builder.m_stream.str(); - getResultCapture().pushScopedMessage( m_info ); - } - ScopedMessage::ScopedMessage( ScopedMessage const& other ) - : m_info( other.m_info ) - {} - -#if defined(_MSC_VER) -#pragma warning(push) -#pragma warning(disable:4996) // std::uncaught_exception is deprecated in C++17 -#endif - ScopedMessage::~ScopedMessage() { - if ( !std::uncaught_exception() ){ - getResultCapture().popScopedMessage(m_info); - } - } -#if defined(_MSC_VER) -#pragma warning(pop) -#endif - -} // end namespace Catch - -// #included from: catch_legacy_reporter_adapter.hpp -#define TWOBLUECUBES_CATCH_LEGACY_REPORTER_ADAPTER_HPP_INCLUDED - -// #included from: catch_legacy_reporter_adapter.h -#define TWOBLUECUBES_CATCH_LEGACY_REPORTER_ADAPTER_H_INCLUDED - -namespace Catch -{ - // Deprecated - struct IReporter : IShared { - virtual ~IReporter(); - - virtual bool shouldRedirectStdout() const = 0; - - virtual void StartTesting() = 0; - virtual void EndTesting( Totals const& totals ) = 0; - virtual void StartGroup( std::string const& groupName ) = 0; - virtual void EndGroup( std::string const& groupName, Totals const& totals ) = 0; - virtual void StartTestCase( TestCaseInfo const& testInfo ) = 0; - virtual void EndTestCase( TestCaseInfo const& testInfo, Totals const& totals, std::string const& stdOut, std::string const& stdErr ) = 0; - virtual void StartSection( std::string const& sectionName, std::string const& description ) = 0; - virtual void EndSection( std::string const& sectionName, Counts const& assertions ) = 0; - virtual void NoAssertionsInSection( std::string const& sectionName ) = 0; - virtual void NoAssertionsInTestCase( std::string const& testName ) = 0; - virtual void Aborted() = 0; - virtual void Result( AssertionResult const& result ) = 0; - }; - - class LegacyReporterAdapter : public SharedImpl<IStreamingReporter> - { - public: - LegacyReporterAdapter( Ptr<IReporter> const& legacyReporter ); - virtual ~LegacyReporterAdapter(); - - virtual ReporterPreferences getPreferences() const; - virtual void noMatchingTestCases( std::string const& ); - virtual void testRunStarting( TestRunInfo const& ); - virtual void testGroupStarting( GroupInfo const& groupInfo ); - virtual void testCaseStarting( TestCaseInfo const& testInfo ); - virtual void sectionStarting( SectionInfo const& sectionInfo ); - virtual void assertionStarting( AssertionInfo const& ); - virtual bool assertionEnded( AssertionStats const& assertionStats ); - virtual void sectionEnded( SectionStats const& sectionStats ); - virtual void testCaseEnded( TestCaseStats const& testCaseStats ); - virtual void testGroupEnded( TestGroupStats const& testGroupStats ); - virtual void testRunEnded( TestRunStats const& testRunStats ); - virtual void skipTest( TestCaseInfo const& ); - - private: - Ptr<IReporter> m_legacyReporter; - }; -} - -namespace Catch -{ - LegacyReporterAdapter::LegacyReporterAdapter( Ptr<IReporter> const& legacyReporter ) - : m_legacyReporter( legacyReporter ) - {} - LegacyReporterAdapter::~LegacyReporterAdapter() {} - - ReporterPreferences LegacyReporterAdapter::getPreferences() const { - ReporterPreferences prefs; - prefs.shouldRedirectStdOut = m_legacyReporter->shouldRedirectStdout(); - return prefs; - } - - void LegacyReporterAdapter::noMatchingTestCases( std::string const& ) {} - void LegacyReporterAdapter::testRunStarting( TestRunInfo const& ) { - m_legacyReporter->StartTesting(); - } - void LegacyReporterAdapter::testGroupStarting( GroupInfo const& groupInfo ) { - m_legacyReporter->StartGroup( groupInfo.name ); - } - void LegacyReporterAdapter::testCaseStarting( TestCaseInfo const& testInfo ) { - m_legacyReporter->StartTestCase( testInfo ); - } - void LegacyReporterAdapter::sectionStarting( SectionInfo const& sectionInfo ) { - m_legacyReporter->StartSection( sectionInfo.name, sectionInfo.description ); - } - void LegacyReporterAdapter::assertionStarting( AssertionInfo const& ) { - // Not on legacy interface - } - - bool LegacyReporterAdapter::assertionEnded( AssertionStats const& assertionStats ) { - if( assertionStats.assertionResult.getResultType() != ResultWas::Ok ) { - for( std::vector<MessageInfo>::const_iterator it = assertionStats.infoMessages.begin(), itEnd = assertionStats.infoMessages.end(); - it != itEnd; - ++it ) { - if( it->type == ResultWas::Info ) { - ResultBuilder rb( it->macroName.c_str(), it->lineInfo, "", ResultDisposition::Normal ); - rb << it->message; - rb.setResultType( ResultWas::Info ); - AssertionResult result = rb.build(); - m_legacyReporter->Result( result ); + namespace { + struct TestHasher { + using hash_t = uint64_t; + + explicit TestHasher( hash_t hashSuffix ): + m_hashSuffix{ hashSuffix } {} + + uint32_t operator()( TestCase const& t ) const { + // FNV-1a hash with multiplication fold. + const hash_t prime = 1099511628211u; + hash_t hash = 14695981039346656037u; + for ( const char c : t.name ) { + hash ^= c; + hash *= prime; } + hash ^= m_hashSuffix; + hash *= prime; + const uint32_t low{ static_cast<uint32_t>( hash ) }; + const uint32_t high{ static_cast<uint32_t>( hash >> 32 ) }; + return low * high; } - } - m_legacyReporter->Result( assertionStats.assertionResult ); - return true; - } - void LegacyReporterAdapter::sectionEnded( SectionStats const& sectionStats ) { - if( sectionStats.missingAssertions ) - m_legacyReporter->NoAssertionsInSection( sectionStats.sectionInfo.name ); - m_legacyReporter->EndSection( sectionStats.sectionInfo.name, sectionStats.assertions ); - } - void LegacyReporterAdapter::testCaseEnded( TestCaseStats const& testCaseStats ) { - m_legacyReporter->EndTestCase - ( testCaseStats.testInfo, - testCaseStats.totals, - testCaseStats.stdOut, - testCaseStats.stdErr ); - } - void LegacyReporterAdapter::testGroupEnded( TestGroupStats const& testGroupStats ) { - if( testGroupStats.aborting ) - m_legacyReporter->Aborted(); - m_legacyReporter->EndGroup( testGroupStats.groupInfo.name, testGroupStats.totals ); - } - void LegacyReporterAdapter::testRunEnded( TestRunStats const& testRunStats ) { - m_legacyReporter->EndTesting( testRunStats.totals ); - } - void LegacyReporterAdapter::skipTest( TestCaseInfo const& ) { - } -} - -// #included from: catch_timer.hpp - -#ifdef __clang__ -#pragma clang diagnostic push -#pragma clang diagnostic ignored "-Wc++11-long-long" -#endif - -#ifdef CATCH_PLATFORM_WINDOWS - -#else -#include <sys/time.h> - -#endif + private: + hash_t m_hashSuffix; + }; + } // end unnamed namespace -namespace Catch { + std::vector<TestCase> sortTests( IConfig const& config, std::vector<TestCase> const& unsortedTestCases ) { + switch( config.runOrder() ) { + case RunTests::InDeclarationOrder: + // already in declaration order + break; - namespace { -#ifdef CATCH_PLATFORM_WINDOWS - UInt64 getCurrentTicks() { - static UInt64 hz=0, hzo=0; - if (!hz) { - QueryPerformanceFrequency( reinterpret_cast<LARGE_INTEGER*>( &hz ) ); - QueryPerformanceCounter( reinterpret_cast<LARGE_INTEGER*>( &hzo ) ); + case RunTests::InLexicographicalOrder: { + std::vector<TestCase> sorted = unsortedTestCases; + std::sort( sorted.begin(), sorted.end() ); + return sorted; } - UInt64 t; - QueryPerformanceCounter( reinterpret_cast<LARGE_INTEGER*>( &t ) ); - return ((t-hzo)*1000000)/hz; - } -#else - UInt64 getCurrentTicks() { - timeval t; - gettimeofday(&t,CATCH_NULL); - return static_cast<UInt64>( t.tv_sec ) * 1000000ull + static_cast<UInt64>( t.tv_usec ); - } -#endif - } - - void Timer::start() { - m_ticks = getCurrentTicks(); - } - unsigned int Timer::getElapsedMicroseconds() const { - return static_cast<unsigned int>(getCurrentTicks() - m_ticks); - } - unsigned int Timer::getElapsedMilliseconds() const { - return static_cast<unsigned int>(getElapsedMicroseconds()/1000); - } - double Timer::getElapsedSeconds() const { - return getElapsedMicroseconds()/1000000.0; - } - -} // namespace Catch - -#ifdef __clang__ -#pragma clang diagnostic pop -#endif -// #included from: catch_common.hpp -#define TWOBLUECUBES_CATCH_COMMON_HPP_INCLUDED - -#include <cstring> -#include <cctype> - -namespace Catch { - bool startsWith( std::string const& s, std::string const& prefix ) { - return s.size() >= prefix.size() && std::equal(prefix.begin(), prefix.end(), s.begin()); - } - bool startsWith( std::string const& s, char prefix ) { - return !s.empty() && s[0] == prefix; - } - bool endsWith( std::string const& s, std::string const& suffix ) { - return s.size() >= suffix.size() && std::equal(suffix.rbegin(), suffix.rend(), s.rbegin()); - } - bool endsWith( std::string const& s, char suffix ) { - return !s.empty() && s[s.size()-1] == suffix; - } - bool contains( std::string const& s, std::string const& infix ) { - return s.find( infix ) != std::string::npos; - } - char toLowerCh(char c) { - return static_cast<char>( std::tolower( c ) ); - } - void toLowerInPlace( std::string& s ) { - std::transform( s.begin(), s.end(), s.begin(), toLowerCh ); - } - std::string toLower( std::string const& s ) { - std::string lc = s; - toLowerInPlace( lc ); - return lc; - } - std::string trim( std::string const& str ) { - static char const* whitespaceChars = "\n\r\t "; - std::string::size_type start = str.find_first_not_of( whitespaceChars ); - std::string::size_type end = str.find_last_not_of( whitespaceChars ); + case RunTests::InRandomOrder: { + seedRng( config ); + TestHasher h{ config.rngSeed() }; - return start != std::string::npos ? str.substr( start, 1+end-start ) : std::string(); - } + using hashedTest = std::pair<TestHasher::hash_t, TestCase const*>; + std::vector<hashedTest> indexed_tests; + indexed_tests.reserve( unsortedTestCases.size() ); - bool replaceInPlace( std::string& str, std::string const& replaceThis, std::string const& withThis ) { - bool replaced = false; - std::size_t i = str.find( replaceThis ); - while( i != std::string::npos ) { - replaced = true; - str = str.substr( 0, i ) + withThis + str.substr( i+replaceThis.size() ); - if( i < str.size()-withThis.size() ) - i = str.find( replaceThis, i+withThis.size() ); - else - i = std::string::npos; - } - return replaced; - } + for (auto const& testCase : unsortedTestCases) { + indexed_tests.emplace_back(h(testCase), &testCase); + } - pluralise::pluralise( std::size_t count, std::string const& label ) - : m_count( count ), - m_label( label ) - {} + std::sort(indexed_tests.begin(), indexed_tests.end(), + [](hashedTest const& lhs, hashedTest const& rhs) { + if (lhs.first == rhs.first) { + return lhs.second->name < rhs.second->name; + } + return lhs.first < rhs.first; + }); - std::ostream& operator << ( std::ostream& os, pluralise const& pluraliser ) { - os << pluraliser.m_count << ' ' << pluraliser.m_label; - if( pluraliser.m_count != 1 ) - os << 's'; - return os; + std::vector<TestCase> sorted; + sorted.reserve( indexed_tests.size() ); + + for (auto const& hashed : indexed_tests) { + sorted.emplace_back(*hashed.second); + } + + return sorted; + } + } + return unsortedTestCases; } - SourceLineInfo::SourceLineInfo() : file(""), line( 0 ){} - SourceLineInfo::SourceLineInfo( char const* _file, std::size_t _line ) - : file( _file ), - line( _line ) - {} - bool SourceLineInfo::empty() const { - return file[0] == '\0'; + bool isThrowSafe( TestCase const& testCase, IConfig const& config ) { + return !testCase.throws() || config.allowThrows(); } - bool SourceLineInfo::operator == ( SourceLineInfo const& other ) const { - return line == other.line && (file == other.file || std::strcmp(file, other.file) == 0); + + bool matchTest( TestCase const& testCase, TestSpec const& testSpec, IConfig const& config ) { + return testSpec.matches( testCase ) && isThrowSafe( testCase, config ); } - bool SourceLineInfo::operator < ( SourceLineInfo const& other ) const { - return line < other.line || ( line == other.line && (std::strcmp(file, other.file) < 0)); + + void enforceNoDuplicateTestCases( std::vector<TestCase> const& functions ) { + std::set<TestCase> seenFunctions; + for( auto const& function : functions ) { + auto prev = seenFunctions.insert( function ); + CATCH_ENFORCE( prev.second, + "error: TEST_CASE( \"" << function.name << "\" ) already defined.\n" + << "\tFirst seen at " << prev.first->getTestCaseInfo().lineInfo << "\n" + << "\tRedefined at " << function.getTestCaseInfo().lineInfo ); + } } - void seedRng( IConfig const& config ) { - if( config.rngSeed() != 0 ) - std::srand( config.rngSeed() ); + std::vector<TestCase> filterTests( std::vector<TestCase> const& testCases, TestSpec const& testSpec, IConfig const& config ) { + std::vector<TestCase> filtered; + filtered.reserve( testCases.size() ); + for (auto const& testCase : testCases) { + if ((!testSpec.hasFilters() && !testCase.isHidden()) || + (testSpec.hasFilters() && matchTest(testCase, testSpec, config))) { + filtered.push_back(testCase); + } + } + return filtered; } - unsigned int rngSeed() { - return getCurrentContext().getConfig()->rngSeed(); + std::vector<TestCase> const& getAllTestCasesSorted( IConfig const& config ) { + return getRegistryHub().getTestCaseRegistry().getAllTestsSorted( config ); } - std::ostream& operator << ( std::ostream& os, SourceLineInfo const& info ) { -#ifndef __GNUG__ - os << info.file << '(' << info.line << ')'; -#else - os << info.file << ':' << info.line; -#endif - return os; + void TestRegistry::registerTest( TestCase const& testCase ) { + std::string name = testCase.getTestCaseInfo().name; + if( name.empty() ) { + ReusableStringStream rss; + rss << "Anonymous test case " << ++m_unnamedCount; + return registerTest( testCase.withName( rss.str() ) ); + } + m_functions.push_back( testCase ); } - void throwLogicError( std::string const& message, SourceLineInfo const& locationInfo ) { - std::ostringstream oss; - oss << locationInfo << ": Internal Catch error: '" << message << '\''; - if( alwaysTrue() ) - throw std::logic_error( oss.str() ); + std::vector<TestCase> const& TestRegistry::getAllTests() const { + return m_functions; } -} - -// #included from: catch_section.hpp -#define TWOBLUECUBES_CATCH_SECTION_HPP_INCLUDED + std::vector<TestCase> const& TestRegistry::getAllTestsSorted( IConfig const& config ) const { + if( m_sortedFunctions.empty() ) + enforceNoDuplicateTestCases( m_functions ); -namespace Catch { + if( m_currentSortOrder != config.runOrder() || m_sortedFunctions.empty() ) { + m_sortedFunctions = sortTests( config, m_functions ); + m_currentSortOrder = config.runOrder(); + } + return m_sortedFunctions; + } - SectionInfo::SectionInfo - ( SourceLineInfo const& _lineInfo, - std::string const& _name, - std::string const& _description ) - : name( _name ), - description( _description ), - lineInfo( _lineInfo ) - {} + /////////////////////////////////////////////////////////////////////////// + TestInvokerAsFunction::TestInvokerAsFunction( void(*testAsFunction)() ) noexcept : m_testAsFunction( testAsFunction ) {} - Section::Section( SectionInfo const& info ) - : m_info( info ), - m_sectionIncluded( getResultCapture().sectionStarted( m_info, m_assertions ) ) - { - m_timer.start(); + void TestInvokerAsFunction::invoke() const { + m_testAsFunction(); } -#if defined(_MSC_VER) -#pragma warning(push) -#pragma warning(disable:4996) // std::uncaught_exception is deprecated in C++17 -#endif - Section::~Section() { - if( m_sectionIncluded ) { - SectionEndInfo endInfo( m_info, m_assertions, m_timer.getElapsedSeconds() ); - if( std::uncaught_exception() ) - getResultCapture().sectionEndedEarly( endInfo ); - else - getResultCapture().sectionEnded( endInfo ); + std::string extractClassName( StringRef const& classOrQualifiedMethodName ) { + std::string className(classOrQualifiedMethodName); + if( startsWith( className, '&' ) ) + { + std::size_t lastColons = className.rfind( "::" ); + std::size_t penultimateColons = className.rfind( "::", lastColons-1 ); + if( penultimateColons == std::string::npos ) + penultimateColons = 1; + className = className.substr( penultimateColons, lastColons-penultimateColons ); } + return className; } -#if defined(_MSC_VER) -#pragma warning(pop) + +} // end namespace Catch +// end catch_test_case_registry_impl.cpp +// start catch_test_case_tracker.cpp + +#include <algorithm> +#include <cassert> +#include <stdexcept> +#include <memory> +#include <sstream> + +#if defined(__clang__) +# pragma clang diagnostic push +# pragma clang diagnostic ignored "-Wexit-time-destructors" #endif - // This indicates whether the section should be executed or not - Section::operator bool() const { - return m_sectionIncluded; - } +namespace Catch { +namespace TestCaseTracking { -} // end namespace Catch + NameAndLocation::NameAndLocation( std::string const& _name, SourceLineInfo const& _location ) + : name( _name ), + location( _location ) + {} -// #included from: catch_debugger.hpp -#define TWOBLUECUBES_CATCH_DEBUGGER_HPP_INCLUDED + ITracker::~ITracker() = default; -#ifdef CATCH_PLATFORM_MAC + ITracker& TrackerContext::startRun() { + m_rootTracker = std::make_shared<SectionTracker>( NameAndLocation( "{root}", CATCH_INTERNAL_LINEINFO ), *this, nullptr ); + m_currentTracker = nullptr; + m_runState = Executing; + return *m_rootTracker; + } - #include <assert.h> - #include <stdbool.h> - #include <sys/types.h> - #include <unistd.h> - #include <sys/sysctl.h> + void TrackerContext::endRun() { + m_rootTracker.reset(); + m_currentTracker = nullptr; + m_runState = NotStarted; + } - namespace Catch{ + void TrackerContext::startCycle() { + m_currentTracker = m_rootTracker.get(); + m_runState = Executing; + } + void TrackerContext::completeCycle() { + m_runState = CompletedCycle; + } - // The following function is taken directly from the following technical note: - // http://developer.apple.com/library/mac/#qa/qa2004/qa1361.html + bool TrackerContext::completedCycle() const { + return m_runState == CompletedCycle; + } + ITracker& TrackerContext::currentTracker() { + return *m_currentTracker; + } + void TrackerContext::setCurrentTracker( ITracker* tracker ) { + m_currentTracker = tracker; + } - // Returns true if the current process is being debugged (either - // running under the debugger or has a debugger attached post facto). - bool isDebuggerActive(){ + TrackerBase::TrackerBase( NameAndLocation const& nameAndLocation, TrackerContext& ctx, ITracker* parent ): + ITracker(nameAndLocation), + m_ctx( ctx ), + m_parent( parent ) + {} - int mib[4]; - struct kinfo_proc info; - size_t size; + bool TrackerBase::isComplete() const { + return m_runState == CompletedSuccessfully || m_runState == Failed; + } + bool TrackerBase::isSuccessfullyCompleted() const { + return m_runState == CompletedSuccessfully; + } + bool TrackerBase::isOpen() const { + return m_runState != NotStarted && !isComplete(); + } + bool TrackerBase::hasChildren() const { + return !m_children.empty(); + } - // Initialize the flags so that, if sysctl fails for some bizarre - // reason, we get a predictable result. + void TrackerBase::addChild( ITrackerPtr const& child ) { + m_children.push_back( child ); + } - info.kp_proc.p_flag = 0; + ITrackerPtr TrackerBase::findChild( NameAndLocation const& nameAndLocation ) { + auto it = std::find_if( m_children.begin(), m_children.end(), + [&nameAndLocation]( ITrackerPtr const& tracker ){ + return + tracker->nameAndLocation().location == nameAndLocation.location && + tracker->nameAndLocation().name == nameAndLocation.name; + } ); + return( it != m_children.end() ) + ? *it + : nullptr; + } + ITracker& TrackerBase::parent() { + assert( m_parent ); // Should always be non-null except for root + return *m_parent; + } - // Initialize mib, which tells sysctl the info we want, in this case - // we're looking for information about a specific process ID. + void TrackerBase::openChild() { + if( m_runState != ExecutingChildren ) { + m_runState = ExecutingChildren; + if( m_parent ) + m_parent->openChild(); + } + } - mib[0] = CTL_KERN; - mib[1] = KERN_PROC; - mib[2] = KERN_PROC_PID; - mib[3] = getpid(); + bool TrackerBase::isSectionTracker() const { return false; } + bool TrackerBase::isGeneratorTracker() const { return false; } - // Call sysctl. + void TrackerBase::open() { + m_runState = Executing; + moveToThis(); + if( m_parent ) + m_parent->openChild(); + } - size = sizeof(info); - 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; - } + void TrackerBase::close() { - // We're being debugged if the P_TRACED flag is set. + // Close any still open children (e.g. generators) + while( &m_ctx.currentTracker() != this ) + m_ctx.currentTracker().close(); - return ( (info.kp_proc.p_flag & P_TRACED) != 0 ); - } - } // namespace Catch + switch( m_runState ) { + case NeedsAnotherRun: + break; -#elif defined(CATCH_PLATFORM_LINUX) - #include <fstream> - #include <string> + case Executing: + m_runState = CompletedSuccessfully; + break; + case ExecutingChildren: + if( std::all_of(m_children.begin(), m_children.end(), [](ITrackerPtr const& t){ return t->isComplete(); }) ) + m_runState = CompletedSuccessfully; + break; - namespace Catch{ - // The standard POSIX way of detecting a debugger is to attempt to - // ptrace() the process, but this needs to be done from a child and not - // this process itself to still allow attaching to this process later - // if wanted, so is rather heavy. Under Linux we have the PID of the - // "debugger" (which doesn't need to be gdb, of course, it could also - // be strace, for example) in /proc/$PID/status, so just get it from - // there instead. - bool isDebuggerActive(){ - // Libstdc++ has a bug, where std::ifstream sets errno to 0 - // This way our users can properly assert over errno values - ErrnoGuard guard; - std::ifstream in("/proc/self/status"); - for( std::string line; std::getline(in, line); ) { - static const int PREFIX_LEN = 11; - if( line.compare(0, PREFIX_LEN, "TracerPid:\t") == 0 ) { - // We're traced if the PID is not 0 and no other PID starts - // with 0 digit, so it's enough to check for just a single - // character. - return line.length() > PREFIX_LEN && line[PREFIX_LEN] != '0'; - } - } + case NotStarted: + case CompletedSuccessfully: + case Failed: + CATCH_INTERNAL_ERROR( "Illogical state: " << m_runState ); - return false; - } - } // namespace Catch -#elif defined(_MSC_VER) - extern "C" __declspec(dllimport) int __stdcall IsDebuggerPresent(); - namespace Catch { - bool isDebuggerActive() { - return IsDebuggerPresent() != 0; + default: + CATCH_INTERNAL_ERROR( "Unknown state: " << m_runState ); } + moveToParent(); + m_ctx.completeCycle(); } -#elif defined(__MINGW32__) - extern "C" __declspec(dllimport) int __stdcall IsDebuggerPresent(); - namespace Catch { - bool isDebuggerActive() { - return IsDebuggerPresent() != 0; - } + void TrackerBase::fail() { + m_runState = Failed; + if( m_parent ) + m_parent->markAsNeedingAnotherRun(); + moveToParent(); + m_ctx.completeCycle(); } -#else - namespace Catch { - inline bool isDebuggerActive() { return false; } + void TrackerBase::markAsNeedingAnotherRun() { + m_runState = NeedsAnotherRun; } -#endif // Platform - -#ifdef CATCH_PLATFORM_WINDOWS - namespace Catch { - void writeToDebugConsole( std::string const& text ) { - ::OutputDebugStringA( text.c_str() ); - } + void TrackerBase::moveToParent() { + assert( m_parent ); + m_ctx.setCurrentTracker( m_parent ); } -#else - namespace Catch { - void writeToDebugConsole( std::string const& text ) { - // !TBD: Need a version for Mac/ XCode and other IDEs - Catch::cout() << text; - } + void TrackerBase::moveToThis() { + m_ctx.setCurrentTracker( this ); } -#endif // Platform -// #included from: catch_tostring.hpp -#define TWOBLUECUBES_CATCH_TOSTRING_HPP_INCLUDED + SectionTracker::SectionTracker( NameAndLocation const& nameAndLocation, TrackerContext& ctx, ITracker* parent ) + : TrackerBase( nameAndLocation, ctx, parent ), + m_trimmed_name(trim(nameAndLocation.name)) + { + if( parent ) { + while( !parent->isSectionTracker() ) + parent = &parent->parent(); -namespace Catch { + SectionTracker& parentSection = static_cast<SectionTracker&>( *parent ); + addNextFilters( parentSection.m_filters ); + } + } -namespace Detail { + bool SectionTracker::isComplete() const { + bool complete = true; - const std::string unprintableString = "{?}"; + if (m_filters.empty() + || m_filters[0] == "" + || std::find(m_filters.begin(), m_filters.end(), m_trimmed_name) != m_filters.end()) { + complete = TrackerBase::isComplete(); + } + return complete; + } - namespace { - const int hexThreshold = 255; + bool SectionTracker::isSectionTracker() const { return true; } - struct Endianness { - enum Arch { Big, Little }; + SectionTracker& SectionTracker::acquire( TrackerContext& ctx, NameAndLocation const& nameAndLocation ) { + std::shared_ptr<SectionTracker> section; - static Arch which() { - union _{ - int asInt; - char asChar[sizeof (int)]; - } u; + ITracker& currentTracker = ctx.currentTracker(); + if( ITrackerPtr childTracker = currentTracker.findChild( nameAndLocation ) ) { + assert( childTracker ); + assert( childTracker->isSectionTracker() ); + section = std::static_pointer_cast<SectionTracker>( childTracker ); + } + else { + section = std::make_shared<SectionTracker>( nameAndLocation, ctx, ¤tTracker ); + currentTracker.addChild( section ); + } + if( !ctx.completedCycle() ) + section->tryOpen(); + return *section; + } - u.asInt = 1; - return ( u.asChar[sizeof(int)-1] == 1 ) ? Big : Little; - } - }; + void SectionTracker::tryOpen() { + if( !isComplete() ) + open(); } - std::string rawMemoryToString( const void *object, std::size_t size ) - { - // Reverse order for little endian architectures - int i = 0, end = static_cast<int>( size ), inc = 1; - if( Endianness::which() == Endianness::Little ) { - i = end-1; - end = inc = -1; + void SectionTracker::addInitialFilters( std::vector<std::string> const& filters ) { + if( !filters.empty() ) { + m_filters.reserve( m_filters.size() + filters.size() + 2 ); + m_filters.emplace_back(""); // Root - should never be consulted + m_filters.emplace_back(""); // Test Case - not a section filter + m_filters.insert( m_filters.end(), filters.begin(), filters.end() ); } - - unsigned char const *bytes = static_cast<unsigned char const *>(object); - std::ostringstream os; - os << "0x" << std::setfill('0') << std::hex; - for( ; i != end; i += inc ) - os << std::setw(2) << static_cast<unsigned>(bytes[i]); - return os.str(); } -} + void SectionTracker::addNextFilters( std::vector<std::string> const& filters ) { + if( filters.size() > 1 ) + m_filters.insert( m_filters.end(), filters.begin()+1, filters.end() ); + } -std::string toString( std::string const& value ) { - std::string s = value; - if( getCurrentContext().getConfig()->showInvisibles() ) { - for(size_t i = 0; i < s.size(); ++i ) { - std::string subs; - switch( s[i] ) { - case '\n': subs = "\\n"; break; - case '\t': subs = "\\t"; break; - default: break; - } - if( !subs.empty() ) { - s = s.substr( 0, i ) + subs + s.substr( i+1 ); - ++i; - } - } + std::vector<std::string> const& SectionTracker::getFilters() const { + return m_filters; } - return '"' + s + '"'; -} -std::string toString( std::wstring const& value ) { - std::string s; - s.reserve( value.size() ); - for(size_t i = 0; i < value.size(); ++i ) - s += value[i] <= 0xff ? static_cast<char>( value[i] ) : '?'; - return Catch::toString( s ); -} + std::string const& SectionTracker::trimmedName() const { + return m_trimmed_name; + } -std::string toString( const char* const value ) { - return value ? Catch::toString( std::string( value ) ) : std::string( "{null string}" ); -} +} // namespace TestCaseTracking -std::string toString( char* const value ) { - return Catch::toString( static_cast<const char*>( value ) ); -} +using TestCaseTracking::ITracker; +using TestCaseTracking::TrackerContext; +using TestCaseTracking::SectionTracker; -std::string toString( const wchar_t* const value ) -{ - return value ? Catch::toString( std::wstring(value) ) : std::string( "{null string}" ); -} +} // namespace Catch -std::string toString( wchar_t* const value ) -{ - return Catch::toString( static_cast<const wchar_t*>( value ) ); -} +#if defined(__clang__) +# pragma clang diagnostic pop +#endif +// end catch_test_case_tracker.cpp +// start catch_test_registry.cpp -std::string toString( int value ) { - std::ostringstream oss; - oss << value; - if( value > Detail::hexThreshold ) - oss << " (0x" << std::hex << value << ')'; - return oss.str(); -} +namespace Catch { -std::string toString( unsigned long value ) { - std::ostringstream oss; - oss << value; - if( value > Detail::hexThreshold ) - oss << " (0x" << std::hex << value << ')'; - return oss.str(); -} + auto makeTestInvoker( void(*testAsFunction)() ) noexcept -> ITestInvoker* { + return new(std::nothrow) TestInvokerAsFunction( testAsFunction ); + } -std::string toString( unsigned int value ) { - return Catch::toString( static_cast<unsigned long>( value ) ); -} + NameAndTags::NameAndTags( StringRef const& name_ , StringRef const& tags_ ) noexcept : name( name_ ), tags( tags_ ) {} -template<typename T> -std::string fpToString( T value, int precision ) { - std::ostringstream oss; - oss << std::setprecision( precision ) - << std::fixed - << value; - std::string d = oss.str(); - std::size_t i = d.find_last_not_of( '0' ); - if( i != std::string::npos && i != d.size()-1 ) { - if( d[i] == '.' ) - i++; - d = d.substr( 0, i+1 ); + AutoReg::AutoReg( ITestInvoker* invoker, SourceLineInfo const& lineInfo, StringRef const& classOrMethod, NameAndTags const& nameAndTags ) noexcept { + CATCH_TRY { + getMutableRegistryHub() + .registerTest( + makeTestCase( + invoker, + extractClassName( classOrMethod ), + nameAndTags, + lineInfo)); + } CATCH_CATCH_ALL { + // Do not throw when constructing global objects, instead register the exception to be processed later + getMutableRegistryHub().registerStartupException(); + } } - return d; -} -std::string toString( const double value ) { - return fpToString( value, 10 ); -} -std::string toString( const float value ) { - return fpToString( value, 5 ) + 'f'; + AutoReg::~AutoReg() = default; } +// end catch_test_registry.cpp +// start catch_test_spec.cpp -std::string toString( bool value ) { - return value ? "true" : "false"; -} +#include <algorithm> +#include <string> +#include <vector> +#include <memory> -std::string toString( char value ) { - if ( value == '\r' ) - return "'\\r'"; - if ( value == '\f' ) - return "'\\f'"; - if ( value == '\n' ) - return "'\\n'"; - if ( value == '\t' ) - return "'\\t'"; - if ( '\0' <= value && value < ' ' ) - return toString( static_cast<unsigned int>( value ) ); - char chstr[] = "' '"; - chstr[1] = value; - return chstr; -} +namespace Catch { -std::string toString( signed char value ) { - return toString( static_cast<char>( value ) ); -} + TestSpec::Pattern::Pattern( std::string const& name ) + : m_name( name ) + {} -std::string toString( unsigned char value ) { - return toString( static_cast<char>( value ) ); -} + TestSpec::Pattern::~Pattern() = default; -#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 + std::string const& TestSpec::Pattern::name() const { + return m_name; + } -#ifdef CATCH_CONFIG_CPP11_NULLPTR -std::string toString( std::nullptr_t ) { - return "nullptr"; -} -#endif + TestSpec::NamePattern::NamePattern( std::string const& name, std::string const& filterString ) + : Pattern( filterString ) + , m_wildcardPattern( toLower( name ), CaseSensitive::No ) + {} -#ifdef __OBJC__ - std::string toString( NSString const * const& nsstring ) { - if( !nsstring ) - return "nil"; - return "@" + toString([nsstring UTF8String]); + bool TestSpec::NamePattern::matches( TestCaseInfo const& testCase ) const { + return m_wildcardPattern.matches( testCase.name ); } - std::string toString( NSString * CATCH_ARC_STRONG & nsstring ) { - if( !nsstring ) - return "nil"; - return "@" + toString([nsstring UTF8String]); + + TestSpec::TagPattern::TagPattern( std::string const& tag, std::string const& filterString ) + : Pattern( filterString ) + , m_tag( toLower( tag ) ) + {} + + bool TestSpec::TagPattern::matches( TestCaseInfo const& testCase ) const { + return std::find(begin(testCase.lcaseTags), + end(testCase.lcaseTags), + m_tag) != end(testCase.lcaseTags); } - std::string toString( NSObject* const& nsObject ) { - return toString( [nsObject description] ); + + TestSpec::ExcludedPattern::ExcludedPattern( PatternPtr const& underlyingPattern ) + : Pattern( underlyingPattern->name() ) + , m_underlyingPattern( underlyingPattern ) + {} + + bool TestSpec::ExcludedPattern::matches( TestCaseInfo const& testCase ) const { + return !m_underlyingPattern->matches( testCase ); } -#endif -} // end namespace Catch + bool TestSpec::Filter::matches( TestCaseInfo const& testCase ) const { + return std::all_of( m_patterns.begin(), m_patterns.end(), [&]( PatternPtr const& p ){ return p->matches( testCase ); } ); + } -// #included from: catch_result_builder.hpp -#define TWOBLUECUBES_CATCH_RESULT_BUILDER_HPP_INCLUDED + std::string TestSpec::Filter::name() const { + std::string name; + for( auto const& p : m_patterns ) + name += p->name(); + return name; + } -#include <cassert> + bool TestSpec::hasFilters() const { + return !m_filters.empty(); + } -namespace Catch { + bool TestSpec::matches( TestCaseInfo const& testCase ) const { + return std::any_of( m_filters.begin(), m_filters.end(), [&]( Filter const& f ){ return f.matches( testCase ); } ); + } - ResultBuilder::ResultBuilder( char const* macroName, - SourceLineInfo const& lineInfo, - char const* capturedExpression, - ResultDisposition::Flags resultDisposition, - char const* secondArg ) - : m_assertionInfo( macroName, lineInfo, capturedExpression, resultDisposition, secondArg ), - m_shouldDebugBreak( false ), - m_shouldThrow( false ), - m_guardException( false ), - m_usedStream( false ) - {} + TestSpec::Matches TestSpec::matchesByFilter( std::vector<TestCase> const& testCases, IConfig const& config ) const + { + Matches matches( m_filters.size() ); + std::transform( m_filters.begin(), m_filters.end(), matches.begin(), [&]( Filter const& filter ){ + std::vector<TestCase const*> currentMatches; + for( auto const& test : testCases ) + if( isThrowSafe( test, config ) && filter.matches( test ) ) + currentMatches.emplace_back( &test ); + return FilterMatch{ filter.name(), currentMatches }; + } ); + return matches; + } - ResultBuilder::~ResultBuilder() { -#if defined(CATCH_CONFIG_FAST_COMPILE) - if ( m_guardException ) { - stream().oss << "Exception translation was disabled by CATCH_CONFIG_FAST_COMPILE"; - captureResult( ResultWas::ThrewException ); - getCurrentContext().getResultCapture()->exceptionEarlyReported(); - } -#endif + const TestSpec::vectorStrings& TestSpec::getInvalidArgs() const{ + return (m_invalidArgs); } - ResultBuilder& ResultBuilder::setResultType( ResultWas::OfType result ) { - m_data.resultType = result; +} +// end catch_test_spec.cpp +// start catch_test_spec_parser.cpp + +namespace Catch { + + TestSpecParser::TestSpecParser( ITagAliasRegistry const& tagAliases ) : m_tagAliases( &tagAliases ) {} + + TestSpecParser& TestSpecParser::parse( std::string const& arg ) { + m_mode = None; + m_exclusion = false; + m_arg = m_tagAliases->expandAliases( arg ); + m_escapeChars.clear(); + m_substring.reserve(m_arg.size()); + m_patternName.reserve(m_arg.size()); + m_realPatternPos = 0; + + for( m_pos = 0; m_pos < m_arg.size(); ++m_pos ) + //if visitChar fails + if( !visitChar( m_arg[m_pos] ) ){ + m_testSpec.m_invalidArgs.push_back(arg); + break; + } + endMode(); return *this; } - ResultBuilder& ResultBuilder::setResultType( bool result ) { - m_data.resultType = result ? ResultWas::Ok : ResultWas::ExpressionFailed; - return *this; + TestSpec TestSpecParser::testSpec() { + addFilter(); + return m_testSpec; } + bool TestSpecParser::visitChar( char c ) { + if( (m_mode != EscapedName) && (c == '\\') ) { + escape(); + addCharToPattern(c); + return true; + }else if((m_mode != EscapedName) && (c == ',') ) { + return separate(); + } - void ResultBuilder::endExpression( DecomposedExpression const& expr ) { - // Flip bool results if FalseTest flag is set - if( isFalseTest( m_assertionInfo.resultDisposition ) ) { - m_data.negate( expr.isBinaryExpression() ); + switch( m_mode ) { + case None: + if( processNoneChar( c ) ) + return true; + break; + case Name: + processNameChar( c ); + break; + case EscapedName: + endMode(); + addCharToPattern(c); + return true; + default: + case Tag: + case QuotedName: + if( processOtherChar( c ) ) + return true; + break; } - getResultCapture().assertionRun(); + m_substring += c; + if( !isControlChar( c ) ) { + m_patternName += c; + m_realPatternPos++; + } + return true; + } + // Two of the processing methods return true to signal the caller to return + // without adding the given character to the current pattern strings + bool TestSpecParser::processNoneChar( char c ) { + switch( c ) { + case ' ': + return true; + case '~': + m_exclusion = true; + return false; + case '[': + startNewMode( Tag ); + return false; + case '"': + startNewMode( QuotedName ); + return false; + default: + startNewMode( Name ); + return false; + } + } + void TestSpecParser::processNameChar( char c ) { + if( c == '[' ) { + if( m_substring == "exclude:" ) + m_exclusion = true; + else + endMode(); + startNewMode( Tag ); + } + } + bool TestSpecParser::processOtherChar( char c ) { + if( !isControlChar( c ) ) + return false; + m_substring += c; + endMode(); + return true; + } + void TestSpecParser::startNewMode( Mode mode ) { + m_mode = mode; + } + void TestSpecParser::endMode() { + switch( m_mode ) { + case Name: + case QuotedName: + return addNamePattern(); + case Tag: + return addTagPattern(); + case EscapedName: + revertBackToLastMode(); + return; + case None: + default: + return startNewMode( None ); + } + } + void TestSpecParser::escape() { + saveLastMode(); + m_mode = EscapedName; + m_escapeChars.push_back(m_realPatternPos); + } + bool TestSpecParser::isControlChar( char c ) const { + switch( m_mode ) { + default: + return false; + case None: + return c == '~'; + case Name: + return c == '['; + case EscapedName: + return true; + case QuotedName: + return c == '"'; + case Tag: + return c == '[' || c == ']'; + } + } - if(getCurrentContext().getConfig()->includeSuccessfulResults() || m_data.resultType != ResultWas::Ok) - { - AssertionResult result = build( expr ); - handleResult( result ); + void TestSpecParser::addFilter() { + if( !m_currentFilter.m_patterns.empty() ) { + m_testSpec.m_filters.push_back( m_currentFilter ); + m_currentFilter = TestSpec::Filter(); } - else - getResultCapture().assertionPassed(); } - void ResultBuilder::useActiveException( ResultDisposition::Flags resultDisposition ) { - m_assertionInfo.resultDisposition = resultDisposition; - stream().oss << Catch::translateActiveException(); - captureResult( ResultWas::ThrewException ); + void TestSpecParser::saveLastMode() { + lastMode = m_mode; } - void ResultBuilder::captureResult( ResultWas::OfType resultType ) { - setResultType( resultType ); - captureExpression(); + void TestSpecParser::revertBackToLastMode() { + m_mode = lastMode; } - void ResultBuilder::captureExpectedException( std::string const& expectedMessage ) { - if( expectedMessage.empty() ) - captureExpectedException( Matchers::Impl::MatchAllOf<std::string>() ); - else - captureExpectedException( Matchers::Equals( expectedMessage ) ); + bool TestSpecParser::separate() { + if( (m_mode==QuotedName) || (m_mode==Tag) ){ + //invalid argument, signal failure to previous scope. + m_mode = None; + m_pos = m_arg.size(); + m_substring.clear(); + m_patternName.clear(); + m_realPatternPos = 0; + return false; + } + endMode(); + addFilter(); + return true; //success } - void ResultBuilder::captureExpectedException( Matchers::Impl::MatcherBase<std::string> const& matcher ) { + std::string TestSpecParser::preprocessPattern() { + std::string token = m_patternName; + for (std::size_t i = 0; i < m_escapeChars.size(); ++i) + token = token.substr(0, m_escapeChars[i] - i) + token.substr(m_escapeChars[i] - i + 1); + m_escapeChars.clear(); + if (startsWith(token, "exclude:")) { + m_exclusion = true; + token = token.substr(8); + } - assert( !isFalseTest( m_assertionInfo.resultDisposition ) ); - AssertionResultData data = m_data; - data.resultType = ResultWas::Ok; - data.reconstructedExpression = capturedExpressionWithSecondArgument(m_assertionInfo.capturedExpression, m_assertionInfo.secondArg); + m_patternName.clear(); + m_realPatternPos = 0; - std::string actualMessage = Catch::translateActiveException(); - if( !matcher.match( actualMessage ) ) { - data.resultType = ResultWas::ExpressionFailed; - data.reconstructedExpression = actualMessage; - } - AssertionResult result( m_assertionInfo, data ); - handleResult( result ); + return token; } - void ResultBuilder::captureExpression() { - AssertionResult result = build(); - handleResult( result ); + void TestSpecParser::addNamePattern() { + auto token = preprocessPattern(); + + if (!token.empty()) { + TestSpec::PatternPtr pattern = std::make_shared<TestSpec::NamePattern>(token, m_substring); + if (m_exclusion) + pattern = std::make_shared<TestSpec::ExcludedPattern>(pattern); + m_currentFilter.m_patterns.push_back(pattern); + } + m_substring.clear(); + m_exclusion = false; + m_mode = None; } - void ResultBuilder::handleResult( AssertionResult const& result ) - { - getResultCapture().assertionEnded( result ); + void TestSpecParser::addTagPattern() { + auto token = preprocessPattern(); - if( !result.isOk() ) { - if( getCurrentContext().getConfig()->shouldDebugBreak() ) - m_shouldDebugBreak = true; - if( getCurrentContext().getRunner()->aborting() || (m_assertionInfo.resultDisposition & ResultDisposition::Normal) ) - m_shouldThrow = true; + if (!token.empty()) { + // If the tag pattern is the "hide and tag" shorthand (e.g. [.foo]) + // we have to create a separate hide tag and shorten the real one + if (token.size() > 1 && token[0] == '.') { + token.erase(token.begin()); + TestSpec::PatternPtr pattern = std::make_shared<TestSpec::TagPattern>(".", m_substring); + if (m_exclusion) { + pattern = std::make_shared<TestSpec::ExcludedPattern>(pattern); + } + m_currentFilter.m_patterns.push_back(pattern); + } + + TestSpec::PatternPtr pattern = std::make_shared<TestSpec::TagPattern>(token, m_substring); + + if (m_exclusion) { + pattern = std::make_shared<TestSpec::ExcludedPattern>(pattern); + } + m_currentFilter.m_patterns.push_back(pattern); } + m_substring.clear(); + m_exclusion = false; + m_mode = None; } - void ResultBuilder::react() { -#if defined(CATCH_CONFIG_FAST_COMPILE) - if (m_shouldDebugBreak) { - /////////////////////////////////////////////////////////////////// - // To inspect the state during test, you need to go one level up the callstack - // To go back to the test and change execution, jump over the throw statement - /////////////////////////////////////////////////////////////////// - CATCH_BREAK_INTO_DEBUGGER(); - } -#endif - if( m_shouldThrow ) - throw Catch::TestFailureException(); + TestSpec parseTestSpec( std::string const& arg ) { + return TestSpecParser( ITagAliasRegistry::get() ).parse( arg ).testSpec(); } - bool ResultBuilder::shouldDebugBreak() const { return m_shouldDebugBreak; } - bool ResultBuilder::allowThrows() const { return getCurrentContext().getConfig()->allowThrows(); } +} // namespace Catch +// end catch_test_spec_parser.cpp +// start catch_timer.cpp - AssertionResult ResultBuilder::build() const - { - return build( *this ); - } +#include <chrono> - // CAVEAT: The returned AssertionResult stores a pointer to the argument expr, - // a temporary DecomposedExpression, which in turn holds references to - // operands, possibly temporary as well. - // It should immediately be passed to handleResult; if the expression - // needs to be reported, its string expansion must be composed before - // the temporaries are destroyed. - AssertionResult ResultBuilder::build( DecomposedExpression const& expr ) const - { - assert( m_data.resultType != ResultWas::Unknown ); - AssertionResultData data = m_data; +static const uint64_t nanosecondsInSecond = 1000000000; - if(m_usedStream) - data.message = m_stream().oss.str(); - data.decomposedExpression = &expr; // for lazy reconstruction - return AssertionResult( m_assertionInfo, data ); +namespace Catch { + + auto getCurrentNanosecondsSinceEpoch() -> uint64_t { + return std::chrono::duration_cast<std::chrono::nanoseconds>( std::chrono::high_resolution_clock::now().time_since_epoch() ).count(); } - void ResultBuilder::reconstructExpression( std::string& dest ) const { - dest = capturedExpressionWithSecondArgument(m_assertionInfo.capturedExpression, m_assertionInfo.secondArg); + namespace { + auto estimateClockResolution() -> uint64_t { + uint64_t sum = 0; + static const uint64_t iterations = 1000000; + + auto startTime = getCurrentNanosecondsSinceEpoch(); + + for( std::size_t i = 0; i < iterations; ++i ) { + + uint64_t ticks; + uint64_t baseTicks = getCurrentNanosecondsSinceEpoch(); + do { + ticks = getCurrentNanosecondsSinceEpoch(); + } while( ticks == baseTicks ); + + auto delta = ticks - baseTicks; + sum += delta; + + // If we have been calibrating for over 3 seconds -- the clock + // is terrible and we should move on. + // TBD: How to signal that the measured resolution is probably wrong? + if (ticks > startTime + 3 * nanosecondsInSecond) { + return sum / ( i + 1u ); + } + } + + // We're just taking the mean, here. To do better we could take the std. dev and exclude outliers + // - and potentially do more iterations if there's a high variance. + return sum/iterations; + } + } + auto getEstimatedClockResolution() -> uint64_t { + static auto s_resolution = estimateClockResolution(); + return s_resolution; } - void ResultBuilder::setExceptionGuard() { - m_guardException = true; + void Timer::start() { + m_nanoseconds = getCurrentNanosecondsSinceEpoch(); + } + auto Timer::getElapsedNanoseconds() const -> uint64_t { + return getCurrentNanosecondsSinceEpoch() - m_nanoseconds; } - void ResultBuilder::unsetExceptionGuard() { - m_guardException = false; + auto Timer::getElapsedMicroseconds() const -> uint64_t { + return getElapsedNanoseconds()/1000; + } + auto Timer::getElapsedMilliseconds() const -> unsigned int { + return static_cast<unsigned int>(getElapsedMicroseconds()/1000); + } + auto Timer::getElapsedSeconds() const -> double { + return getElapsedMicroseconds()/1000000.0; } -} // end namespace Catch +} // namespace Catch +// end catch_timer.cpp +// start catch_tostring.cpp + +#if defined(__clang__) +# pragma clang diagnostic push +# pragma clang diagnostic ignored "-Wexit-time-destructors" +# pragma clang diagnostic ignored "-Wglobal-constructors" +#endif -// #included from: catch_tag_alias_registry.hpp -#define TWOBLUECUBES_CATCH_TAG_ALIAS_REGISTRY_HPP_INCLUDED +// Enable specific decls locally +#if !defined(CATCH_CONFIG_ENABLE_CHRONO_STRINGMAKER) +#define CATCH_CONFIG_ENABLE_CHRONO_STRINGMAKER +#endif + +#include <cmath> +#include <iomanip> namespace Catch { - TagAliasRegistry::~TagAliasRegistry() {} +namespace Detail { - Option<TagAlias> TagAliasRegistry::find( std::string const& alias ) const { - std::map<std::string, TagAlias>::const_iterator it = m_registry.find( alias ); - if( it != m_registry.end() ) - return it->second; - else - return Option<TagAlias>(); - } + const std::string unprintableString = "{?}"; - std::string TagAliasRegistry::expandAliases( std::string const& unexpandedTestSpec ) const { - std::string expandedTestSpec = unexpandedTestSpec; - for( std::map<std::string, TagAlias>::const_iterator it = m_registry.begin(), itEnd = m_registry.end(); - it != itEnd; - ++it ) { - std::size_t pos = expandedTestSpec.find( it->first ); - if( pos != std::string::npos ) { - expandedTestSpec = expandedTestSpec.substr( 0, pos ) + - it->second.tag + - expandedTestSpec.substr( pos + it->first.size() ); - } - } - return expandedTestSpec; - } + namespace { + const int hexThreshold = 255; - void TagAliasRegistry::add( std::string const& alias, std::string const& tag, SourceLineInfo const& lineInfo ) { + struct Endianness { + enum Arch { Big, Little }; - if( !startsWith( alias, "[@" ) || !endsWith( alias, ']' ) ) { - std::ostringstream oss; - oss << Colour( Colour::Red ) - << "error: tag alias, \"" << alias << "\" is not of the form [@alias name].\n" - << Colour( Colour::FileName ) - << lineInfo << '\n'; - throw std::domain_error( oss.str().c_str() ); - } - if( !m_registry.insert( std::make_pair( alias, TagAlias( tag, lineInfo ) ) ).second ) { - std::ostringstream oss; - oss << Colour( Colour::Red ) - << "error: tag alias, \"" << alias << "\" already registered.\n" - << "\tFirst seen at " - << Colour( Colour::Red ) << find(alias)->lineInfo << '\n' - << Colour( Colour::Red ) << "\tRedefined at " - << Colour( Colour::FileName) << lineInfo << '\n'; - throw std::domain_error( oss.str().c_str() ); - } + static Arch which() { + int one = 1; + // If the lowest byte we read is non-zero, we can assume + // that little endian format is used. + auto value = *reinterpret_cast<char*>(&one); + return value ? Little : Big; + } + }; } - ITagAliasRegistry::~ITagAliasRegistry() {} + std::string rawMemoryToString( const void *object, std::size_t size ) { + // Reverse order for little endian architectures + int i = 0, end = static_cast<int>( size ), inc = 1; + if( Endianness::which() == Endianness::Little ) { + i = end-1; + end = inc = -1; + } - ITagAliasRegistry const& ITagAliasRegistry::get() { - return getRegistryHub().getTagAliasRegistry(); + unsigned char const *bytes = static_cast<unsigned char const *>(object); + ReusableStringStream rss; + rss << "0x" << std::setfill('0') << std::hex; + for( ; i != end; i += inc ) + rss << std::setw(2) << static_cast<unsigned>(bytes[i]); + return rss.str(); } +} - RegistrarForTagAliases::RegistrarForTagAliases( char const* alias, char const* tag, SourceLineInfo const& lineInfo ) { - getMutableRegistryHub().registerTagAlias( alias, tag, lineInfo ); +template<typename T> +std::string fpToString( T value, int precision ) { + if (Catch::isnan(value)) { + return "nan"; } -} // end namespace Catch - -// #included from: catch_matchers_string.hpp + ReusableStringStream rss; + rss << std::setprecision( precision ) + << std::fixed + << value; + std::string d = rss.str(); + std::size_t i = d.find_last_not_of( '0' ); + if( i != std::string::npos && i != d.size()-1 ) { + if( d[i] == '.' ) + i++; + d = d.substr( 0, i+1 ); + } + return d; +} -namespace Catch { -namespace Matchers { +//// ======================================================= //// +// +// Out-of-line defs for full specialization of StringMaker +// +//// ======================================================= //// - namespace StdString { +std::string StringMaker<std::string>::convert(const std::string& str) { + if (!getCurrentContext().getConfig()->showInvisibles()) { + return '"' + str + '"'; + } - CasedString::CasedString( std::string const& str, CaseSensitive::Choice caseSensitivity ) - : m_caseSensitivity( caseSensitivity ), - m_str( adjustString( str ) ) - {} - std::string CasedString::adjustString( std::string const& str ) const { - return m_caseSensitivity == CaseSensitive::No - ? toLower( str ) - : str; - } - std::string CasedString::caseSensitivitySuffix() const { - return m_caseSensitivity == CaseSensitive::No - ? " (case insensitive)" - : std::string(); + std::string s("\""); + for (char c : str) { + switch (c) { + case '\n': + s.append("\\n"); + break; + case '\t': + s.append("\\t"); + break; + default: + s.push_back(c); + break; } + } + s.append("\""); + return s; +} - StringMatcherBase::StringMatcherBase( std::string const& operation, CasedString const& comparator ) - : m_comparator( comparator ), - m_operation( operation ) { - } +#ifdef CATCH_CONFIG_CPP17_STRING_VIEW +std::string StringMaker<std::string_view>::convert(std::string_view str) { + return ::Catch::Detail::stringify(std::string{ str }); +} +#endif - std::string StringMatcherBase::describe() const { - std::string description; - description.reserve(5 + m_operation.size() + m_comparator.m_str.size() + - m_comparator.caseSensitivitySuffix().size()); - description += m_operation; - description += ": \""; - description += m_comparator.m_str; - description += "\""; - description += m_comparator.caseSensitivitySuffix(); - return description; - } +std::string StringMaker<char const*>::convert(char const* str) { + if (str) { + return ::Catch::Detail::stringify(std::string{ str }); + } else { + return{ "{null string}" }; + } +} +std::string StringMaker<char*>::convert(char* str) { + if (str) { + return ::Catch::Detail::stringify(std::string{ str }); + } else { + return{ "{null string}" }; + } +} - EqualsMatcher::EqualsMatcher( CasedString const& comparator ) : StringMatcherBase( "equals", comparator ) {} +#ifdef CATCH_CONFIG_WCHAR +std::string StringMaker<std::wstring>::convert(const std::wstring& wstr) { + std::string s; + s.reserve(wstr.size()); + for (auto c : wstr) { + s += (c <= 0xff) ? static_cast<char>(c) : '?'; + } + return ::Catch::Detail::stringify(s); +} - bool EqualsMatcher::match( std::string const& source ) const { - return m_comparator.adjustString( source ) == m_comparator.m_str; - } +# ifdef CATCH_CONFIG_CPP17_STRING_VIEW +std::string StringMaker<std::wstring_view>::convert(std::wstring_view str) { + return StringMaker<std::wstring>::convert(std::wstring(str)); +} +# endif - ContainsMatcher::ContainsMatcher( CasedString const& comparator ) : StringMatcherBase( "contains", comparator ) {} +std::string StringMaker<wchar_t const*>::convert(wchar_t const * str) { + if (str) { + return ::Catch::Detail::stringify(std::wstring{ str }); + } else { + return{ "{null string}" }; + } +} +std::string StringMaker<wchar_t *>::convert(wchar_t * str) { + if (str) { + return ::Catch::Detail::stringify(std::wstring{ str }); + } else { + return{ "{null string}" }; + } +} +#endif - bool ContainsMatcher::match( std::string const& source ) const { - return contains( m_comparator.adjustString( source ), m_comparator.m_str ); - } +#if defined(CATCH_CONFIG_CPP17_BYTE) +#include <cstddef> +std::string StringMaker<std::byte>::convert(std::byte value) { + return ::Catch::Detail::stringify(std::to_integer<unsigned long long>(value)); +} +#endif // defined(CATCH_CONFIG_CPP17_BYTE) + +std::string StringMaker<int>::convert(int value) { + return ::Catch::Detail::stringify(static_cast<long long>(value)); +} +std::string StringMaker<long>::convert(long value) { + return ::Catch::Detail::stringify(static_cast<long long>(value)); +} +std::string StringMaker<long long>::convert(long long value) { + ReusableStringStream rss; + rss << value; + if (value > Detail::hexThreshold) { + rss << " (0x" << std::hex << value << ')'; + } + return rss.str(); +} - StartsWithMatcher::StartsWithMatcher( CasedString const& comparator ) : StringMatcherBase( "starts with", comparator ) {} +std::string StringMaker<unsigned int>::convert(unsigned int value) { + return ::Catch::Detail::stringify(static_cast<unsigned long long>(value)); +} +std::string StringMaker<unsigned long>::convert(unsigned long value) { + return ::Catch::Detail::stringify(static_cast<unsigned long long>(value)); +} +std::string StringMaker<unsigned long long>::convert(unsigned long long value) { + ReusableStringStream rss; + rss << value; + if (value > Detail::hexThreshold) { + rss << " (0x" << std::hex << value << ')'; + } + return rss.str(); +} - bool StartsWithMatcher::match( std::string const& source ) const { - return startsWith( m_comparator.adjustString( source ), m_comparator.m_str ); - } +std::string StringMaker<bool>::convert(bool b) { + return b ? "true" : "false"; +} - EndsWithMatcher::EndsWithMatcher( CasedString const& comparator ) : StringMatcherBase( "ends with", comparator ) {} +std::string StringMaker<signed char>::convert(signed char value) { + if (value == '\r') { + return "'\\r'"; + } else if (value == '\f') { + return "'\\f'"; + } else if (value == '\n') { + return "'\\n'"; + } else if (value == '\t') { + return "'\\t'"; + } else if ('\0' <= value && value < ' ') { + return ::Catch::Detail::stringify(static_cast<unsigned int>(value)); + } else { + char chstr[] = "' '"; + chstr[1] = value; + return chstr; + } +} +std::string StringMaker<char>::convert(char c) { + return ::Catch::Detail::stringify(static_cast<signed char>(c)); +} +std::string StringMaker<unsigned char>::convert(unsigned char c) { + return ::Catch::Detail::stringify(static_cast<char>(c)); +} - bool EndsWithMatcher::match( std::string const& source ) const { - return endsWith( m_comparator.adjustString( source ), m_comparator.m_str ); - } +std::string StringMaker<std::nullptr_t>::convert(std::nullptr_t) { + return "nullptr"; +} - } // namespace StdString +int StringMaker<float>::precision = 5; - StdString::EqualsMatcher Equals( std::string const& str, CaseSensitive::Choice caseSensitivity ) { - return StdString::EqualsMatcher( StdString::CasedString( str, caseSensitivity) ); - } - StdString::ContainsMatcher Contains( std::string const& str, CaseSensitive::Choice caseSensitivity ) { - return StdString::ContainsMatcher( StdString::CasedString( str, caseSensitivity) ); - } - StdString::EndsWithMatcher EndsWith( std::string const& str, CaseSensitive::Choice caseSensitivity ) { - return StdString::EndsWithMatcher( StdString::CasedString( str, caseSensitivity) ); - } - StdString::StartsWithMatcher StartsWith( std::string const& str, CaseSensitive::Choice caseSensitivity ) { - return StdString::StartsWithMatcher( StdString::CasedString( str, caseSensitivity) ); - } +std::string StringMaker<float>::convert(float value) { + return fpToString(value, precision) + 'f'; +} -} // namespace Matchers -} // namespace Catch -// #included from: ../reporters/catch_reporter_multi.hpp -#define TWOBLUECUBES_CATCH_REPORTER_MULTI_HPP_INCLUDED +int StringMaker<double>::precision = 10; -namespace Catch { +std::string StringMaker<double>::convert(double value) { + return fpToString(value, precision); +} -class MultipleReporters : public SharedImpl<IStreamingReporter> { - typedef std::vector<Ptr<IStreamingReporter> > Reporters; - Reporters m_reporters; +std::string ratio_string<std::atto>::symbol() { return "a"; } +std::string ratio_string<std::femto>::symbol() { return "f"; } +std::string ratio_string<std::pico>::symbol() { return "p"; } +std::string ratio_string<std::nano>::symbol() { return "n"; } +std::string ratio_string<std::micro>::symbol() { return "u"; } +std::string ratio_string<std::milli>::symbol() { return "m"; } -public: - void add( Ptr<IStreamingReporter> const& reporter ) { - m_reporters.push_back( reporter ); - } +} // end namespace Catch -public: // IStreamingReporter +#if defined(__clang__) +# pragma clang diagnostic pop +#endif - virtual ReporterPreferences getPreferences() const CATCH_OVERRIDE { - return m_reporters[0]->getPreferences(); - } +// end catch_tostring.cpp +// start catch_totals.cpp - 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 ); - } +namespace Catch { - 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 ); + Counts Counts::operator - ( Counts const& other ) const { + Counts diff; + diff.passed = passed - other.passed; + diff.failed = failed - other.failed; + diff.failedButOk = failedButOk - other.failedButOk; + return diff; } - 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 ); + Counts& Counts::operator += ( Counts const& other ) { + passed += other.passed; + failed += other.failed; + failedButOk += other.failedButOk; + return *this; } - 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 ); + std::size_t Counts::total() const { + return passed + failed + failedButOk; } - - 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 ); + bool Counts::allPassed() const { + return failed == 0 && failedButOk == 0; } - - 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 ); + bool Counts::allOk() const { + return failed == 0; } - // 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; + Totals Totals::operator - ( Totals const& other ) const { + Totals diff; + diff.assertions = assertions - other.assertions; + diff.testCases = testCases - other.testCases; + return diff; } - 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 ); + Totals& Totals::operator += ( Totals const& other ) { + assertions += other.assertions; + testCases += other.testCases; + return *this; } - 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 ); + Totals Totals::delta( Totals const& prevTotals ) const { + Totals diff = *this - prevTotals; + if( diff.assertions.failed > 0 ) + ++diff.testCases.failed; + else if( diff.assertions.failedButOk > 0 ) + ++diff.testCases.failedButOk; + else + ++diff.testCases.passed; + return diff; } - 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 ); - } +} +// end catch_totals.cpp +// start catch_uncaught_exceptions.cpp - 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 ); - } +// start catch_config_uncaught_exceptions.hpp - 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 ); - } +// Copyright Catch2 Authors +// Distributed under the Boost Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt or copy at +// https://www.boost.org/LICENSE_1_0.txt) - virtual MultipleReporters* tryAsMulti() CATCH_OVERRIDE { - return this; - } +// SPDX-License-Identifier: BSL-1.0 -}; +#ifndef CATCH_CONFIG_UNCAUGHT_EXCEPTIONS_HPP +#define CATCH_CONFIG_UNCAUGHT_EXCEPTIONS_HPP -Ptr<IStreamingReporter> addReporter( Ptr<IStreamingReporter> const& existingReporter, Ptr<IStreamingReporter> const& additionalReporter ) { - Ptr<IStreamingReporter> resultingReporter; +#if defined(_MSC_VER) +# if _MSC_VER >= 1900 // Visual Studio 2015 or newer +# define CATCH_INTERNAL_CONFIG_CPP17_UNCAUGHT_EXCEPTIONS +# endif +#endif - if( existingReporter ) { - MultipleReporters* multi = existingReporter->tryAsMulti(); - if( !multi ) { - multi = new MultipleReporters; - resultingReporter = Ptr<IStreamingReporter>( multi ); - if( existingReporter ) - multi->add( existingReporter ); - } - else - resultingReporter = existingReporter; - multi->add( additionalReporter ); - } - else - resultingReporter = additionalReporter; +#include <exception> - return resultingReporter; -} +#if defined(__cpp_lib_uncaught_exceptions) \ + && !defined(CATCH_INTERNAL_CONFIG_CPP17_UNCAUGHT_EXCEPTIONS) -} // end namespace Catch +# define CATCH_INTERNAL_CONFIG_CPP17_UNCAUGHT_EXCEPTIONS +#endif // __cpp_lib_uncaught_exceptions -// #included from: ../reporters/catch_reporter_xml.hpp -#define TWOBLUECUBES_CATCH_REPORTER_XML_HPP_INCLUDED +#if defined(CATCH_INTERNAL_CONFIG_CPP17_UNCAUGHT_EXCEPTIONS) \ + && !defined(CATCH_CONFIG_NO_CPP17_UNCAUGHT_EXCEPTIONS) \ + && !defined(CATCH_CONFIG_CPP17_UNCAUGHT_EXCEPTIONS) -// #included from: catch_reporter_bases.hpp -#define TWOBLUECUBES_CATCH_REPORTER_BASES_HPP_INCLUDED +# define CATCH_CONFIG_CPP17_UNCAUGHT_EXCEPTIONS +#endif -#include <cstring> -#include <cfloat> -#include <cstdio> -#include <assert.h> +#endif // CATCH_CONFIG_UNCAUGHT_EXCEPTIONS_HPP +// end catch_config_uncaught_exceptions.hpp +#include <exception> namespace Catch { - - namespace { - // Because formatting using c++ streams is stateful, drop down to C is required - // Alternatively we could use stringstream, but its performance is... not good. - std::string getFormattedDuration( double duration ) { - // Max exponent + 1 is required to represent the whole part - // + 1 for decimal point - // + 3 for the 3 decimal places - // + 1 for null terminator - const size_t maxDoubleSize = DBL_MAX_10_EXP + 1 + 1 + 3 + 1; - char buffer[maxDoubleSize]; - - // Save previous errno, to prevent sprintf from overwriting it - ErrnoGuard guard; -#ifdef _MSC_VER - sprintf_s(buffer, "%.3f", duration); + bool uncaught_exceptions() { +#if defined(CATCH_CONFIG_DISABLE_EXCEPTIONS) + return false; +#elif defined(CATCH_CONFIG_CPP17_UNCAUGHT_EXCEPTIONS) + return std::uncaught_exceptions() > 0; #else - sprintf(buffer, "%.3f", duration); + return std::uncaught_exception(); #endif - return std::string(buffer); + } +} // end namespace Catch +// end catch_uncaught_exceptions.cpp +// start catch_version.cpp + +#include <ostream> + +namespace Catch { + + Version::Version + ( unsigned int _majorVersion, + unsigned int _minorVersion, + unsigned int _patchNumber, + char const * const _branchName, + unsigned int _buildNumber ) + : majorVersion( _majorVersion ), + minorVersion( _minorVersion ), + patchNumber( _patchNumber ), + branchName( _branchName ), + buildNumber( _buildNumber ) + {} + + std::ostream& operator << ( std::ostream& os, Version const& version ) { + os << version.majorVersion << '.' + << version.minorVersion << '.' + << version.patchNumber; + // branchName is never null -> 0th char is \0 if it is empty + if (version.branchName[0]) { + os << '-' << version.branchName + << '.' << version.buildNumber; } + return os; } - struct StreamingReporterBase : SharedImpl<IStreamingReporter> { + Version const& libraryVersion() { + static Version version( 2, 13, 10, "", 0 ); + return version; + } - StreamingReporterBase( ReporterConfig const& _config ) - : m_config( _config.fullConfig() ), - stream( _config.stream() ) - { - m_reporterPrefs.shouldRedirectStdOut = false; +} +// end catch_version.cpp +// start catch_wildcard_pattern.cpp + +namespace Catch { + + WildcardPattern::WildcardPattern( std::string const& pattern, + CaseSensitive::Choice caseSensitivity ) + : m_caseSensitivity( caseSensitivity ), + m_pattern( normaliseString( 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<WildcardPosition>( m_wildcard | WildcardAtEnd ); + } + } - virtual ReporterPreferences getPreferences() const CATCH_OVERRIDE { - return m_reporterPrefs; + bool WildcardPattern::matches( std::string const& str ) const { + switch( m_wildcard ) { + case NoWildcard: + return m_pattern == normaliseString( str ); + case WildcardAtStart: + return endsWith( normaliseString( str ), m_pattern ); + case WildcardAtEnd: + return startsWith( normaliseString( str ), m_pattern ); + case WildcardAtBothEnds: + return contains( normaliseString( str ), m_pattern ); + default: + CATCH_INTERNAL_ERROR( "Unknown enum" ); } + } + + std::string WildcardPattern::normaliseString( std::string const& str ) const { + return trim( m_caseSensitivity == CaseSensitive::No ? toLower( str ) : str ); + } +} +// end catch_wildcard_pattern.cpp +// start catch_xmlwriter.cpp + +#include <iomanip> +#include <type_traits> - virtual ~StreamingReporterBase() CATCH_OVERRIDE; +namespace Catch { - virtual void noMatchingTestCases( std::string const& ) CATCH_OVERRIDE {} +namespace { - virtual void testRunStarting( TestRunInfo const& _testRunInfo ) CATCH_OVERRIDE { - currentTestRunInfo = _testRunInfo; - } - virtual void testGroupStarting( GroupInfo const& _groupInfo ) CATCH_OVERRIDE { - currentGroupInfo = _groupInfo; + size_t trailingBytes(unsigned char c) { + if ((c & 0xE0) == 0xC0) { + return 2; } - - virtual void testCaseStarting( TestCaseInfo const& _testInfo ) CATCH_OVERRIDE { - currentTestCaseInfo = _testInfo; + if ((c & 0xF0) == 0xE0) { + return 3; } - virtual void sectionStarting( SectionInfo const& _sectionInfo ) CATCH_OVERRIDE { - m_sectionStack.push_back( _sectionInfo ); + if ((c & 0xF8) == 0xF0) { + return 4; } + CATCH_INTERNAL_ERROR("Invalid multibyte utf-8 start byte encountered"); + } - virtual void sectionEnded( SectionStats const& /* _sectionStats */ ) CATCH_OVERRIDE { - m_sectionStack.pop_back(); - } - virtual void testCaseEnded( TestCaseStats const& /* _testCaseStats */ ) CATCH_OVERRIDE { - currentTestCaseInfo.reset(); + uint32_t headerValue(unsigned char c) { + if ((c & 0xE0) == 0xC0) { + return c & 0x1F; } - virtual void testGroupEnded( TestGroupStats const& /* _testGroupStats */ ) CATCH_OVERRIDE { - currentGroupInfo.reset(); + if ((c & 0xF0) == 0xE0) { + return c & 0x0F; } - virtual void testRunEnded( TestRunStats const& /* _testRunStats */ ) CATCH_OVERRIDE { - currentTestCaseInfo.reset(); - currentGroupInfo.reset(); - currentTestRunInfo.reset(); + if ((c & 0xF8) == 0xF0) { + return c & 0x07; } + CATCH_INTERNAL_ERROR("Invalid multibyte utf-8 start byte encountered"); + } - virtual void skipTest( TestCaseInfo const& ) CATCH_OVERRIDE { - // Don't do anything with this by default. - // It can optionally be overridden in the derived class. - } + void hexEscapeChar(std::ostream& os, unsigned char c) { + std::ios_base::fmtflags f(os.flags()); + os << "\\x" + << std::uppercase << std::hex << std::setfill('0') << std::setw(2) + << static_cast<int>(c); + os.flags(f); + } - Ptr<IConfig const> m_config; - std::ostream& stream; + bool shouldNewline(XmlFormatting fmt) { + return !!(static_cast<std::underlying_type<XmlFormatting>::type>(fmt & XmlFormatting::Newline)); + } - LazyStat<TestRunInfo> currentTestRunInfo; - LazyStat<GroupInfo> currentGroupInfo; - LazyStat<TestCaseInfo> currentTestCaseInfo; + bool shouldIndent(XmlFormatting fmt) { + return !!(static_cast<std::underlying_type<XmlFormatting>::type>(fmt & XmlFormatting::Indent)); + } - std::vector<SectionInfo> m_sectionStack; - ReporterPreferences m_reporterPrefs; - }; +} // anonymous namespace - struct CumulativeReporterBase : SharedImpl<IStreamingReporter> { - template<typename T, typename ChildNodeT> - struct Node : SharedImpl<> { - explicit Node( T const& _value ) : value( _value ) {} - virtual ~Node() {} + XmlFormatting operator | (XmlFormatting lhs, XmlFormatting rhs) { + return static_cast<XmlFormatting>( + static_cast<std::underlying_type<XmlFormatting>::type>(lhs) | + static_cast<std::underlying_type<XmlFormatting>::type>(rhs) + ); + } - typedef std::vector<Ptr<ChildNodeT> > ChildNodes; - T value; - ChildNodes children; - }; - struct SectionNode : SharedImpl<> { - explicit SectionNode( SectionStats const& _stats ) : stats( _stats ) {} - virtual ~SectionNode(); + XmlFormatting operator & (XmlFormatting lhs, XmlFormatting rhs) { + return static_cast<XmlFormatting>( + static_cast<std::underlying_type<XmlFormatting>::type>(lhs) & + static_cast<std::underlying_type<XmlFormatting>::type>(rhs) + ); + } - bool operator == ( SectionNode const& other ) const { - return stats.sectionInfo.lineInfo == other.stats.sectionInfo.lineInfo; - } - bool operator == ( Ptr<SectionNode> const& other ) const { - return operator==( *other ); - } + XmlEncode::XmlEncode( std::string const& str, ForWhat forWhat ) + : m_str( str ), + m_forWhat( forWhat ) + {} - SectionStats stats; - typedef std::vector<Ptr<SectionNode> > ChildSections; - typedef std::vector<AssertionStats> Assertions; - ChildSections childSections; - Assertions assertions; - std::string stdOut; - std::string stdErr; - }; + void XmlEncode::encodeTo( std::ostream& os ) const { + // Apostrophe escaping not necessary if we always use " to write attributes + // (see: http://www.w3.org/TR/xml/#syntax) - struct BySectionInfo { - BySectionInfo( SectionInfo const& other ) : m_other( other ) {} - BySectionInfo( BySectionInfo const& other ) : m_other( other.m_other ) {} - bool operator() ( Ptr<SectionNode> const& node ) const { - return ((node->stats.sectionInfo.name == m_other.name) && - (node->stats.sectionInfo.lineInfo == m_other.lineInfo)); + for( std::size_t idx = 0; idx < m_str.size(); ++ idx ) { + unsigned char c = m_str[idx]; + switch (c) { + case '<': os << "<"; break; + case '&': os << "&"; break; + + case '>': + // See: http://www.w3.org/TR/xml/#syntax + if (idx > 2 && m_str[idx - 1] == ']' && m_str[idx - 2] == ']') + os << ">"; + else + os << c; + break; + + case '\"': + if (m_forWhat == ForAttributes) + os << """; + else + os << c; + break; + + default: + // Check for control characters and invalid utf-8 + + // Escape control characters in standard ascii + // see http://stackoverflow.com/questions/404107/why-are-control-characters-illegal-in-xml-1-0 + if (c < 0x09 || (c > 0x0D && c < 0x20) || c == 0x7F) { + hexEscapeChar(os, c); + break; + } + + // Plain ASCII: Write it to stream + if (c < 0x7F) { + os << c; + break; + } + + // UTF-8 territory + // Check if the encoding is valid and if it is not, hex escape bytes. + // Important: We do not check the exact decoded values for validity, only the encoding format + // First check that this bytes is a valid lead byte: + // This means that it is not encoded as 1111 1XXX + // Or as 10XX XXXX + if (c < 0xC0 || + c >= 0xF8) { + hexEscapeChar(os, c); + break; + } + + auto encBytes = trailingBytes(c); + // Are there enough bytes left to avoid accessing out-of-bounds memory? + if (idx + encBytes - 1 >= m_str.size()) { + hexEscapeChar(os, c); + break; + } + // The header is valid, check data + // The next encBytes bytes must together be a valid utf-8 + // This means: bitpattern 10XX XXXX and the extracted value is sane (ish) + bool valid = true; + uint32_t value = headerValue(c); + for (std::size_t n = 1; n < encBytes; ++n) { + unsigned char nc = m_str[idx + n]; + valid &= ((nc & 0xC0) == 0x80); + value = (value << 6) | (nc & 0x3F); + } + + if ( + // Wrong bit pattern of following bytes + (!valid) || + // Overlong encodings + (value < 0x80) || + (0x80 <= value && value < 0x800 && encBytes > 2) || + (0x800 < value && value < 0x10000 && encBytes > 3) || + // Encoded value out of range + (value >= 0x110000) + ) { + hexEscapeChar(os, c); + break; + } + + // If we got here, this is in fact a valid(ish) utf-8 sequence + for (std::size_t n = 0; n < encBytes; ++n) { + os << m_str[idx + n]; + } + idx += encBytes - 1; + break; } - private: - void operator=( BySectionInfo const& ); - SectionInfo const& m_other; - }; + } + } - typedef Node<TestCaseStats, SectionNode> TestCaseNode; - typedef Node<TestGroupStats, TestCaseNode> TestGroupNode; - typedef Node<TestRunStats, TestGroupNode> TestRunNode; + std::ostream& operator << ( std::ostream& os, XmlEncode const& xmlEncode ) { + xmlEncode.encodeTo( os ); + return os; + } - CumulativeReporterBase( ReporterConfig const& _config ) - : m_config( _config.fullConfig() ), - stream( _config.stream() ) - { - m_reporterPrefs.shouldRedirectStdOut = false; + XmlWriter::ScopedElement::ScopedElement( XmlWriter* writer, XmlFormatting fmt ) + : m_writer( writer ), + m_fmt(fmt) + {} + + XmlWriter::ScopedElement::ScopedElement( ScopedElement&& other ) noexcept + : m_writer( other.m_writer ), + m_fmt(other.m_fmt) + { + other.m_writer = nullptr; + other.m_fmt = XmlFormatting::None; + } + XmlWriter::ScopedElement& XmlWriter::ScopedElement::operator=( ScopedElement&& other ) noexcept { + if ( m_writer ) { + m_writer->endElement(); } - ~CumulativeReporterBase(); + m_writer = other.m_writer; + other.m_writer = nullptr; + m_fmt = other.m_fmt; + other.m_fmt = XmlFormatting::None; + return *this; + } - virtual ReporterPreferences getPreferences() const CATCH_OVERRIDE { - return m_reporterPrefs; + XmlWriter::ScopedElement::~ScopedElement() { + if (m_writer) { + m_writer->endElement(m_fmt); } + } - virtual void testRunStarting( TestRunInfo const& ) CATCH_OVERRIDE {} - virtual void testGroupStarting( GroupInfo const& ) CATCH_OVERRIDE {} + XmlWriter::ScopedElement& XmlWriter::ScopedElement::writeText( std::string const& text, XmlFormatting fmt ) { + m_writer->writeText( text, fmt ); + return *this; + } - virtual void testCaseStarting( TestCaseInfo const& ) CATCH_OVERRIDE {} + XmlWriter::XmlWriter( std::ostream& os ) : m_os( os ) + { + writeDeclaration(); + } - virtual void sectionStarting( SectionInfo const& sectionInfo ) CATCH_OVERRIDE { - SectionStats incompleteStats( sectionInfo, Counts(), 0, false ); - Ptr<SectionNode> node; - if( m_sectionStack.empty() ) { - if( !m_rootSection ) - m_rootSection = new SectionNode( incompleteStats ); - node = m_rootSection; - } - else { - SectionNode& parentNode = *m_sectionStack.back(); - SectionNode::ChildSections::const_iterator it = - std::find_if( parentNode.childSections.begin(), - parentNode.childSections.end(), - BySectionInfo( sectionInfo ) ); - if( it == parentNode.childSections.end() ) { - node = new SectionNode( incompleteStats ); - parentNode.childSections.push_back( node ); - } - else - node = *it; + XmlWriter::~XmlWriter() { + while (!m_tags.empty()) { + endElement(); + } + newlineIfNecessary(); + } + + XmlWriter& XmlWriter::startElement( std::string const& name, XmlFormatting fmt ) { + ensureTagClosed(); + newlineIfNecessary(); + if (shouldIndent(fmt)) { + m_os << m_indent; + m_indent += " "; + } + m_os << '<' << name; + m_tags.push_back( name ); + m_tagIsOpen = true; + applyFormatting(fmt); + return *this; + } + + XmlWriter::ScopedElement XmlWriter::scopedElement( std::string const& name, XmlFormatting fmt ) { + ScopedElement scoped( this, fmt ); + startElement( name, fmt ); + return scoped; + } + + XmlWriter& XmlWriter::endElement(XmlFormatting fmt) { + m_indent = m_indent.substr(0, m_indent.size() - 2); + + if( m_tagIsOpen ) { + m_os << "/>"; + m_tagIsOpen = false; + } else { + newlineIfNecessary(); + if (shouldIndent(fmt)) { + m_os << m_indent; } - m_sectionStack.push_back( node ); - m_deepestSection = node; + m_os << "</" << m_tags.back() << ">"; } + m_os << std::flush; + applyFormatting(fmt); + m_tags.pop_back(); + return *this; + } - virtual void assertionStarting( AssertionInfo const& ) CATCH_OVERRIDE {} + XmlWriter& XmlWriter::writeAttribute( std::string const& name, std::string const& attribute ) { + if( !name.empty() && !attribute.empty() ) + m_os << ' ' << name << "=\"" << XmlEncode( attribute, XmlEncode::ForAttributes ) << '"'; + return *this; + } - virtual bool assertionEnded( AssertionStats const& assertionStats ) CATCH_OVERRIDE { - assert( !m_sectionStack.empty() ); - SectionNode& sectionNode = *m_sectionStack.back(); - sectionNode.assertions.push_back( assertionStats ); - // AssertionResult holds a pointer to a temporary DecomposedExpression, - // which getExpandedExpression() calls to build the expression string. - // Our section stack copy of the assertionResult will likely outlive the - // temporary, so it must be expanded or discarded now to avoid calling - // a destroyed object later. - prepareExpandedExpression( sectionNode.assertions.back().assertionResult ); - return true; - } - 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 ) CATCH_OVERRIDE { - Ptr<TestCaseNode> node = new TestCaseNode( testCaseStats ); - assert( m_sectionStack.size() == 0 ); - node->children.push_back( m_rootSection ); - m_testCases.push_back( node ); - m_rootSection.reset(); + XmlWriter& XmlWriter::writeAttribute( std::string const& name, bool attribute ) { + m_os << ' ' << name << "=\"" << ( attribute ? "true" : "false" ) << '"'; + return *this; + } - assert( m_deepestSection ); - m_deepestSection->stdOut = testCaseStats.stdOut; - m_deepestSection->stdErr = testCaseStats.stdErr; + XmlWriter& XmlWriter::writeText( std::string const& text, XmlFormatting fmt) { + if( !text.empty() ){ + bool tagWasOpen = m_tagIsOpen; + ensureTagClosed(); + if (tagWasOpen && shouldIndent(fmt)) { + m_os << m_indent; + } + m_os << XmlEncode( text ); + applyFormatting(fmt); } - virtual void testGroupEnded( TestGroupStats const& testGroupStats ) CATCH_OVERRIDE { - Ptr<TestGroupNode> node = new TestGroupNode( testGroupStats ); - node->children.swap( m_testCases ); - m_testGroups.push_back( node ); + return *this; + } + + XmlWriter& XmlWriter::writeComment( std::string const& text, XmlFormatting fmt) { + ensureTagClosed(); + if (shouldIndent(fmt)) { + m_os << m_indent; } - virtual void testRunEnded( TestRunStats const& testRunStats ) CATCH_OVERRIDE { - Ptr<TestRunNode> node = new TestRunNode( testRunStats ); - node->children.swap( m_testGroups ); - m_testRuns.push_back( node ); - testRunEndedCumulative(); + m_os << "<!--" << text << "-->"; + applyFormatting(fmt); + return *this; + } + + void XmlWriter::writeStylesheetRef( std::string const& url ) { + m_os << "<?xml-stylesheet type=\"text/xsl\" href=\"" << url << "\"?>\n"; + } + + XmlWriter& XmlWriter::writeBlankLine() { + ensureTagClosed(); + m_os << '\n'; + return *this; + } + + void XmlWriter::ensureTagClosed() { + if( m_tagIsOpen ) { + m_os << '>' << std::flush; + newlineIfNecessary(); + m_tagIsOpen = false; } - virtual void testRunEndedCumulative() = 0; + } - virtual void skipTest( TestCaseInfo const& ) CATCH_OVERRIDE {} + void XmlWriter::applyFormatting(XmlFormatting fmt) { + m_needsNewline = shouldNewline(fmt); + } - virtual void prepareExpandedExpression( AssertionResult& result ) const { - if( result.isOk() ) - result.discardDecomposedExpression(); - else - result.expandDecomposedExpression(); + void XmlWriter::writeDeclaration() { + m_os << "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"; + } + + void XmlWriter::newlineIfNecessary() { + if( m_needsNewline ) { + m_os << std::endl; + m_needsNewline = false; } + } +} +// end catch_xmlwriter.cpp +// start catch_reporter_bases.cpp - Ptr<IConfig const> m_config; - std::ostream& stream; - std::vector<AssertionStats> m_assertions; - std::vector<std::vector<Ptr<SectionNode> > > m_sections; - std::vector<Ptr<TestCaseNode> > m_testCases; - std::vector<Ptr<TestGroupNode> > m_testGroups; +#include <cstring> +#include <cfloat> +#include <cstdio> +#include <cassert> +#include <memory> - std::vector<Ptr<TestRunNode> > m_testRuns; +namespace Catch { + void prepareExpandedExpression(AssertionResult& result) { + result.getExpandedExpression(); + } - Ptr<SectionNode> m_rootSection; - Ptr<SectionNode> m_deepestSection; - std::vector<Ptr<SectionNode> > m_sectionStack; - ReporterPreferences m_reporterPrefs; + // Because formatting using c++ streams is stateful, drop down to C is required + // Alternatively we could use stringstream, but its performance is... not good. + std::string getFormattedDuration( double duration ) { + // Max exponent + 1 is required to represent the whole part + // + 1 for decimal point + // + 3 for the 3 decimal places + // + 1 for null terminator + const std::size_t maxDoubleSize = DBL_MAX_10_EXP + 1 + 1 + 3 + 1; + char buffer[maxDoubleSize]; - }; + // Save previous errno, to prevent sprintf from overwriting it + ErrnoGuard guard; +#ifdef _MSC_VER + sprintf_s(buffer, "%.3f", duration); +#else + std::sprintf(buffer, "%.3f", duration); +#endif + return std::string(buffer); + } - template<char C> - char const* getLineOfChars() { - static char line[CATCH_CONFIG_CONSOLE_WIDTH] = {0}; - if( !*line ) { - std::memset( line, C, CATCH_CONFIG_CONSOLE_WIDTH-1 ); - line[CATCH_CONFIG_CONSOLE_WIDTH-1] = 0; + bool shouldShowDuration( IConfig const& config, double duration ) { + if ( config.showDurations() == ShowDurations::Always ) { + return true; } - return line; + if ( config.showDurations() == ShowDurations::Never ) { + return false; + } + const double min = config.minDuration(); + return min >= 0 && duration >= min; } - struct TestEventListenerBase : StreamingReporterBase { - TestEventListenerBase( ReporterConfig const& _config ) - : StreamingReporterBase( _config ) - {} + std::string serializeFilters( std::vector<std::string> const& container ) { + ReusableStringStream oss; + bool first = true; + for (auto&& filter : container) + { + if (!first) + oss << ' '; + else + first = false; - virtual void assertionStarting( AssertionInfo const& ) CATCH_OVERRIDE {} - virtual bool assertionEnded( AssertionStats const& ) CATCH_OVERRIDE { - return false; + oss << filter; } - }; + return oss.str(); + } + + TestEventListenerBase::TestEventListenerBase(ReporterConfig const & _config) + :StreamingReporterBase(_config) {} + + std::set<Verbosity> TestEventListenerBase::getSupportedVerbosities() { + return { Verbosity::Quiet, Verbosity::Normal, Verbosity::High }; + } + + void TestEventListenerBase::assertionStarting(AssertionInfo const &) {} + + bool TestEventListenerBase::assertionEnded(AssertionStats const &) { + return false; + } } // end namespace Catch +// end catch_reporter_bases.cpp +// start catch_reporter_compact.cpp -// #included from: ../internal/catch_reporter_registrars.hpp -#define TWOBLUECUBES_CATCH_REPORTER_REGISTRARS_HPP_INCLUDED +namespace { -namespace Catch { +#ifdef CATCH_PLATFORM_MAC + const char* failedString() { return "FAILED"; } + const char* passedString() { return "PASSED"; } +#else + const char* failedString() { return "failed"; } + const char* passedString() { return "passed"; } +#endif - template<typename T> - class LegacyReporterRegistrar { + // Colour::LightGrey + Catch::Colour::Code dimColour() { return Catch::Colour::FileName; } - class ReporterFactory : public IReporterFactory { - virtual IStreamingReporter* create( ReporterConfig const& config ) const { - return new LegacyReporterAdapter( new T( config ) ); - } + std::string bothOrAll( std::size_t count ) { + return count == 1 ? std::string() : + count == 2 ? "both " : "all " ; + } - virtual std::string getDescription() const { - return T::getDescription(); - } - }; +} // anon namespace - public: +namespace Catch { +namespace { +// Colour, message variants: +// - white: No tests ran. +// - red: Failed [both/all] N test cases, failed [both/all] M assertions. +// - white: Passed [both/all] N test cases (no assertions). +// - red: Failed N tests cases, failed M assertions. +// - green: Passed [both/all] N tests cases with M assertions. +void printTotals(std::ostream& out, const Totals& totals) { + if (totals.testCases.total() == 0) { + out << "No tests ran."; + } else if (totals.testCases.failed == totals.testCases.total()) { + Colour colour(Colour::ResultError); + const std::string qualify_assertions_failed = + totals.assertions.failed == totals.assertions.total() ? + bothOrAll(totals.assertions.failed) : std::string(); + out << + "Failed " << bothOrAll(totals.testCases.failed) + << pluralise(totals.testCases.failed, "test case") << ", " + "failed " << qualify_assertions_failed << + pluralise(totals.assertions.failed, "assertion") << '.'; + } else if (totals.assertions.total() == 0) { + out << + "Passed " << bothOrAll(totals.testCases.total()) + << pluralise(totals.testCases.total(), "test case") + << " (no assertions)."; + } else if (totals.assertions.failed) { + Colour colour(Colour::ResultError); + out << + "Failed " << pluralise(totals.testCases.failed, "test case") << ", " + "failed " << pluralise(totals.assertions.failed, "assertion") << '.'; + } else { + Colour colour(Colour::ResultSuccess); + out << + "Passed " << bothOrAll(totals.testCases.passed) + << pluralise(totals.testCases.passed, "test case") << + " with " << pluralise(totals.assertions.passed, "assertion") << '.'; + } +} - LegacyReporterRegistrar( std::string const& name ) { - getMutableRegistryHub().registerReporter( name, new ReporterFactory() ); +// Implementation of CompactReporter formatting +class AssertionPrinter { +public: + AssertionPrinter& operator= (AssertionPrinter const&) = delete; + AssertionPrinter(AssertionPrinter const&) = delete; + AssertionPrinter(std::ostream& _stream, AssertionStats const& _stats, bool _printInfoMessages) + : stream(_stream) + , result(_stats.assertionResult) + , messages(_stats.infoMessages) + , itMessage(_stats.infoMessages.begin()) + , printInfoMessages(_printInfoMessages) {} + + void print() { + printSourceInfo(); + + itMessage = messages.begin(); + + switch (result.getResultType()) { + case ResultWas::Ok: + printResultType(Colour::ResultSuccess, passedString()); + printOriginalExpression(); + printReconstructedExpression(); + if (!result.hasExpression()) + printRemainingMessages(Colour::None); + else + printRemainingMessages(); + break; + case ResultWas::ExpressionFailed: + if (result.isOk()) + printResultType(Colour::ResultSuccess, failedString() + std::string(" - but was ok")); + else + printResultType(Colour::Error, failedString()); + printOriginalExpression(); + printReconstructedExpression(); + printRemainingMessages(); + break; + case ResultWas::ThrewException: + printResultType(Colour::Error, failedString()); + printIssue("unexpected exception with message:"); + printMessage(); + printExpressionWas(); + printRemainingMessages(); + break; + case ResultWas::FatalErrorCondition: + printResultType(Colour::Error, failedString()); + printIssue("fatal error condition with message:"); + printMessage(); + printExpressionWas(); + printRemainingMessages(); + break; + case ResultWas::DidntThrowException: + printResultType(Colour::Error, failedString()); + printIssue("expected exception, got none"); + printExpressionWas(); + printRemainingMessages(); + break; + case ResultWas::Info: + printResultType(Colour::None, "info"); + printMessage(); + printRemainingMessages(); + break; + case ResultWas::Warning: + printResultType(Colour::None, "warning"); + printMessage(); + printRemainingMessages(); + break; + case ResultWas::ExplicitFailure: + printResultType(Colour::Error, failedString()); + printIssue("explicitly"); + printRemainingMessages(Colour::None); + break; + // These cases are here to prevent compiler warnings + case ResultWas::Unknown: + case ResultWas::FailureBit: + case ResultWas::Exception: + printResultType(Colour::Error, "** internal error **"); + break; } - }; - - template<typename T> - class ReporterRegistrar { + } - class ReporterFactory : public SharedImpl<IReporterFactory> { +private: + void printSourceInfo() const { + Colour colourGuard(Colour::FileName); + stream << result.getSourceInfo() << ':'; + } - // *** Please Note ***: - // - If you end up here looking at a compiler error because it's trying to register - // your custom reporter class be aware that the native reporter interface has changed - // to IStreamingReporter. The "legacy" interface, IReporter, is still supported via - // an adapter. Just use REGISTER_LEGACY_REPORTER to take advantage of the adapter. - // However please consider updating to the new interface as the old one is now - // deprecated and will probably be removed quite soon! - // Please contact me via github if you have any questions at all about this. - // In fact, ideally, please contact me anyway to let me know you've hit this - as I have - // no idea who is actually using custom reporters at all (possibly no-one!). - // The new interface is designed to minimise exposure to interface changes in the future. - virtual IStreamingReporter* create( ReporterConfig const& config ) const { - return new T( config ); + void printResultType(Colour::Code colour, std::string const& passOrFail) const { + if (!passOrFail.empty()) { + { + Colour colourGuard(colour); + stream << ' ' << passOrFail; } + stream << ':'; + } + } - virtual std::string getDescription() const { - return T::getDescription(); + void printIssue(std::string const& issue) const { + stream << ' ' << issue; + } + + void printExpressionWas() { + if (result.hasExpression()) { + stream << ';'; + { + Colour colour(dimColour()); + stream << " expression was:"; } - }; + printOriginalExpression(); + } + } - public: + void printOriginalExpression() const { + if (result.hasExpression()) { + stream << ' ' << result.getExpression(); + } + } - ReporterRegistrar( std::string const& name ) { - getMutableRegistryHub().registerReporter( name, new ReporterFactory() ); + void printReconstructedExpression() const { + if (result.hasExpandedExpression()) { + { + Colour colour(dimColour()); + stream << " for: "; + } + stream << result.getExpandedExpression(); } - }; + } - template<typename T> - class ListenerRegistrar { + void printMessage() { + if (itMessage != messages.end()) { + stream << " '" << itMessage->message << '\''; + ++itMessage; + } + } - class ListenerFactory : public SharedImpl<IReporterFactory> { + void printRemainingMessages(Colour::Code colour = dimColour()) { + if (itMessage == messages.end()) + return; - virtual IStreamingReporter* create( ReporterConfig const& config ) const { - return new T( config ); - } - virtual std::string getDescription() const { - return std::string(); - } - }; + const auto itEnd = messages.cend(); + const auto N = static_cast<std::size_t>(std::distance(itMessage, itEnd)); - public: + { + Colour colourGuard(colour); + stream << " with " << pluralise(N, "message") << ':'; + } - ListenerRegistrar() { - getMutableRegistryHub().registerListener( new ListenerFactory() ); + while (itMessage != itEnd) { + // If this assertion is a warning ignore any INFO messages + if (printInfoMessages || itMessage->type != ResultWas::Info) { + printMessage(); + if (itMessage != itEnd) { + Colour colourGuard(dimColour()); + stream << " and"; + } + continue; + } + ++itMessage; } - }; -} + } -#define INTERNAL_CATCH_REGISTER_LEGACY_REPORTER( name, reporterType ) \ - namespace{ Catch::LegacyReporterRegistrar<reporterType> catch_internal_RegistrarFor##reporterType( name ); } +private: + std::ostream& stream; + AssertionResult const& result; + std::vector<MessageInfo> messages; + std::vector<MessageInfo>::const_iterator itMessage; + bool printInfoMessages; +}; -#define INTERNAL_CATCH_REGISTER_REPORTER( name, reporterType ) \ - namespace{ Catch::ReporterRegistrar<reporterType> catch_internal_RegistrarFor##reporterType( name ); } +} // anon namespace -// Deprecated - use the form without INTERNAL_ -#define INTERNAL_CATCH_REGISTER_LISTENER( listenerType ) \ - namespace{ Catch::ListenerRegistrar<listenerType> catch_internal_RegistrarFor##listenerType; } + std::string CompactReporter::getDescription() { + return "Reports test results on a single line, suitable for IDEs"; + } -#define CATCH_REGISTER_LISTENER( listenerType ) \ - namespace{ Catch::ListenerRegistrar<listenerType> catch_internal_RegistrarFor##listenerType; } + void CompactReporter::noMatchingTestCases( std::string const& spec ) { + stream << "No test cases matched '" << spec << '\'' << std::endl; + } -// #included from: ../internal/catch_xmlwriter.hpp -#define TWOBLUECUBES_CATCH_XMLWRITER_HPP_INCLUDED + void CompactReporter::assertionStarting( AssertionInfo const& ) {} -#include <sstream> -#include <string> -#include <vector> -#include <iomanip> + bool CompactReporter::assertionEnded( AssertionStats const& _assertionStats ) { + AssertionResult const& result = _assertionStats.assertionResult; -namespace Catch { + bool printInfoMessages = true; - class XmlEncode { - public: - enum ForWhat { ForTextNodes, ForAttributes }; + // Drop out if result was successful and we're not printing those + if( !m_config->includeSuccessfulResults() && result.isOk() ) { + if( result.getResultType() != ResultWas::Warning ) + return false; + printInfoMessages = false; + } - XmlEncode( std::string const& str, ForWhat forWhat = ForTextNodes ) - : m_str( str ), - m_forWhat( forWhat ) - {} + AssertionPrinter printer( stream, _assertionStats, printInfoMessages ); + printer.print(); - 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 and - // by @mrpi PR #588 - if ( ( c >= 0 && c < '\x09' ) || ( c > '\x0D' && c < '\x20') || c=='\x7F' ) { - // see http://stackoverflow.com/questions/404107/why-are-control-characters-illegal-in-xml-1-0 - os << "\\x" << std::uppercase << std::hex << std::setfill('0') << std::setw(2) - << static_cast<int>( c ); - } - else - os << c; - } + stream << std::endl; + return true; + } + + void CompactReporter::sectionEnded(SectionStats const& _sectionStats) { + double dur = _sectionStats.durationInSeconds; + if ( shouldShowDuration( *m_config, dur ) ) { + stream << getFormattedDuration( dur ) << " s: " << _sectionStats.sectionInfo.name << std::endl; } } - friend std::ostream& operator << ( std::ostream& os, XmlEncode const& xmlEncode ) { - xmlEncode.encodeTo( os ); - return os; + void CompactReporter::testRunEnded( TestRunStats const& _testRunStats ) { + printTotals( stream, _testRunStats.totals ); + stream << '\n' << std::endl; + StreamingReporterBase::testRunEnded( _testRunStats ); } - private: - std::string m_str; - ForWhat m_forWhat; - }; + CompactReporter::~CompactReporter() {} - class XmlWriter { - public: + CATCH_REGISTER_REPORTER( "compact", CompactReporter ) - class ScopedElement { - public: - ScopedElement( XmlWriter* writer ) - : m_writer( writer ) - {} +} // end namespace Catch +// end catch_reporter_compact.cpp +// start catch_reporter_console.cpp - ScopedElement( ScopedElement const& other ) - : m_writer( other.m_writer ){ - other.m_writer = CATCH_NULL; - } +#include <cfloat> +#include <cstdio> - ~ScopedElement() { - if( m_writer ) - m_writer->endElement(); - } +#if defined(_MSC_VER) +#pragma warning(push) +#pragma warning(disable:4061) // Not all labels are EXPLICITLY handled in switch + // Note that 4062 (not all labels are handled and default is missing) is enabled +#endif - ScopedElement& writeText( std::string const& text, bool indent = true ) { - m_writer->writeText( text, indent ); - return *this; - } +#if defined(__clang__) +# pragma clang diagnostic push +// For simplicity, benchmarking-only helpers are always enabled +# pragma clang diagnostic ignored "-Wunused-function" +#endif - template<typename T> - ScopedElement& writeAttribute( std::string const& name, T const& attribute ) { - m_writer->writeAttribute( name, attribute ); - return *this; - } +namespace Catch { - private: - mutable XmlWriter* m_writer; - }; +namespace { - XmlWriter() - : m_tagIsOpen( false ), - m_needsNewline( false ), - m_os( Catch::cout() ) - { - writeDeclaration(); +// Formatter impl for ConsoleReporter +class ConsoleAssertionPrinter { +public: + ConsoleAssertionPrinter& operator= (ConsoleAssertionPrinter const&) = delete; + ConsoleAssertionPrinter(ConsoleAssertionPrinter const&) = delete; + ConsoleAssertionPrinter(std::ostream& _stream, AssertionStats const& _stats, bool _printInfoMessages) + : stream(_stream), + stats(_stats), + result(_stats.assertionResult), + colour(Colour::None), + message(result.getMessage()), + messages(_stats.infoMessages), + printInfoMessages(_printInfoMessages) { + switch (result.getResultType()) { + case ResultWas::Ok: + colour = Colour::Success; + passOrFail = "PASSED"; + //if( result.hasMessage() ) + if (_stats.infoMessages.size() == 1) + messageLabel = "with message"; + if (_stats.infoMessages.size() > 1) + messageLabel = "with messages"; + break; + case ResultWas::ExpressionFailed: + if (result.isOk()) { + colour = Colour::Success; + passOrFail = "FAILED - but was ok"; + } else { + colour = Colour::Error; + passOrFail = "FAILED"; + } + if (_stats.infoMessages.size() == 1) + messageLabel = "with message"; + if (_stats.infoMessages.size() > 1) + messageLabel = "with messages"; + break; + case ResultWas::ThrewException: + colour = Colour::Error; + passOrFail = "FAILED"; + messageLabel = "due to unexpected exception with "; + if (_stats.infoMessages.size() == 1) + messageLabel += "message"; + if (_stats.infoMessages.size() > 1) + messageLabel += "messages"; + break; + case ResultWas::FatalErrorCondition: + colour = Colour::Error; + passOrFail = "FAILED"; + messageLabel = "due to a fatal error condition"; + break; + case ResultWas::DidntThrowException: + colour = Colour::Error; + passOrFail = "FAILED"; + messageLabel = "because no exception was thrown where one was expected"; + break; + case ResultWas::Info: + messageLabel = "info"; + break; + case ResultWas::Warning: + messageLabel = "warning"; + break; + case ResultWas::ExplicitFailure: + passOrFail = "FAILED"; + colour = Colour::Error; + if (_stats.infoMessages.size() == 1) + messageLabel = "explicitly with message"; + if (_stats.infoMessages.size() > 1) + messageLabel = "explicitly with messages"; + break; + // These cases are here to prevent compiler warnings + case ResultWas::Unknown: + case ResultWas::FailureBit: + case ResultWas::Exception: + passOrFail = "** internal error **"; + colour = Colour::Error; + break; + } + } + + void print() const { + printSourceInfo(); + if (stats.totals.assertions.total() > 0) { + printResultType(); + printOriginalExpression(); + printReconstructedExpression(); + } else { + stream << '\n'; } + printMessage(); + } - XmlWriter( std::ostream& os ) - : m_tagIsOpen( false ), - m_needsNewline( false ), - m_os( os ) - { - writeDeclaration(); +private: + void printResultType() const { + if (!passOrFail.empty()) { + Colour colourGuard(colour); + stream << passOrFail << ":\n"; } - - ~XmlWriter() { - while( !m_tags.empty() ) - endElement(); + } + void printOriginalExpression() const { + if (result.hasExpression()) { + Colour colourGuard(Colour::OriginalExpression); + stream << " "; + stream << result.getExpressionInMacro(); + stream << '\n'; } - - XmlWriter& startElement( std::string const& name ) { - ensureTagClosed(); - newlineIfNecessary(); - m_os << m_indent << '<' << name; - m_tags.push_back( name ); - m_indent += " "; - m_tagIsOpen = true; - return *this; + } + void printReconstructedExpression() const { + if (result.hasExpandedExpression()) { + stream << "with expansion:\n"; + Colour colourGuard(Colour::ReconstructedExpression); + stream << Column(result.getExpandedExpression()).indent(2) << '\n'; } - - ScopedElement scopedElement( std::string const& name ) { - ScopedElement scoped( this ); - startElement( name ); - return scoped; + } + void printMessage() const { + if (!messageLabel.empty()) + stream << messageLabel << ':' << '\n'; + for (auto const& msg : messages) { + // If this assertion is a warning ignore any INFO messages + if (printInfoMessages || msg.type != ResultWas::Info) + stream << Column(msg.message).indent(2) << '\n'; } + } + void printSourceInfo() const { + Colour colourGuard(Colour::FileName); + stream << result.getSourceInfo() << ": "; + } - XmlWriter& endElement() { - newlineIfNecessary(); - m_indent = m_indent.substr( 0, m_indent.size()-2 ); - if( m_tagIsOpen ) { - m_os << "/>"; - m_tagIsOpen = false; - } - else { - m_os << m_indent << "</" << m_tags.back() << ">"; - } - m_os << std::endl; - m_tags.pop_back(); - return *this; - } + std::ostream& stream; + AssertionStats const& stats; + AssertionResult const& result; + Colour::Code colour; + std::string passOrFail; + std::string messageLabel; + std::string message; + std::vector<MessageInfo> messages; + bool printInfoMessages; +}; - XmlWriter& writeAttribute( std::string const& name, std::string const& attribute ) { - if( !name.empty() && !attribute.empty() ) - m_os << ' ' << name << "=\"" << XmlEncode( attribute, XmlEncode::ForAttributes ) << '"'; - return *this; +std::size_t makeRatio(std::size_t number, std::size_t total) { + std::size_t ratio = total > 0 ? CATCH_CONFIG_CONSOLE_WIDTH * number / total : 0; + return (ratio == 0 && number > 0) ? 1 : ratio; +} + +std::size_t& findMax(std::size_t& i, std::size_t& j, std::size_t& k) { + if (i > j && i > k) + return i; + else if (j > k) + return j; + else + return k; +} + +struct ColumnInfo { + enum Justification { Left, Right }; + std::string name; + int width; + Justification justification; +}; +struct ColumnBreak {}; +struct RowBreak {}; + +class Duration { + enum class Unit { + Auto, + Nanoseconds, + Microseconds, + Milliseconds, + Seconds, + Minutes + }; + static const uint64_t s_nanosecondsInAMicrosecond = 1000; + static const uint64_t s_nanosecondsInAMillisecond = 1000 * s_nanosecondsInAMicrosecond; + static const uint64_t s_nanosecondsInASecond = 1000 * s_nanosecondsInAMillisecond; + static const uint64_t s_nanosecondsInAMinute = 60 * s_nanosecondsInASecond; + + double m_inNanoseconds; + Unit m_units; + +public: + explicit Duration(double inNanoseconds, Unit units = Unit::Auto) + : m_inNanoseconds(inNanoseconds), + m_units(units) { + if (m_units == Unit::Auto) { + if (m_inNanoseconds < s_nanosecondsInAMicrosecond) + m_units = Unit::Nanoseconds; + else if (m_inNanoseconds < s_nanosecondsInAMillisecond) + m_units = Unit::Microseconds; + else if (m_inNanoseconds < s_nanosecondsInASecond) + m_units = Unit::Milliseconds; + else if (m_inNanoseconds < s_nanosecondsInAMinute) + m_units = Unit::Seconds; + else + m_units = Unit::Minutes; } - XmlWriter& writeAttribute( std::string const& name, bool attribute ) { - m_os << ' ' << name << "=\"" << ( attribute ? "true" : "false" ) << '"'; - return *this; - } + } - template<typename T> - XmlWriter& writeAttribute( std::string const& name, T const& attribute ) { - std::ostringstream oss; - oss << attribute; - return writeAttribute( name, oss.str() ); + auto value() const -> double { + switch (m_units) { + case Unit::Microseconds: + return m_inNanoseconds / static_cast<double>(s_nanosecondsInAMicrosecond); + case Unit::Milliseconds: + return m_inNanoseconds / static_cast<double>(s_nanosecondsInAMillisecond); + case Unit::Seconds: + return m_inNanoseconds / static_cast<double>(s_nanosecondsInASecond); + case Unit::Minutes: + return m_inNanoseconds / static_cast<double>(s_nanosecondsInAMinute); + default: + return m_inNanoseconds; } - - XmlWriter& writeText( std::string const& text, bool indent = true ) { - if( !text.empty() ){ - bool tagWasOpen = m_tagIsOpen; - ensureTagClosed(); - if( tagWasOpen && indent ) - m_os << m_indent; - m_os << XmlEncode( text ); - m_needsNewline = true; - } - return *this; + } + auto unitsAsString() const -> std::string { + switch (m_units) { + case Unit::Nanoseconds: + return "ns"; + case Unit::Microseconds: + return "us"; + case Unit::Milliseconds: + return "ms"; + case Unit::Seconds: + return "s"; + case Unit::Minutes: + return "m"; + default: + return "** internal error **"; } - XmlWriter& writeComment( std::string const& text ) { - ensureTagClosed(); - m_os << m_indent << "<!--" << text << "-->"; - m_needsNewline = true; - return *this; - } + } + friend auto operator << (std::ostream& os, Duration const& duration) -> std::ostream& { + return os << duration.value() << ' ' << duration.unitsAsString(); + } +}; +} // end anon namespace - void writeStylesheetRef( std::string const& url ) { - m_os << "<?xml-stylesheet type=\"text/xsl\" href=\"" << url << "\"?>\n"; - } +class TablePrinter { + std::ostream& m_os; + std::vector<ColumnInfo> m_columnInfos; + std::ostringstream m_oss; + int m_currentColumn = -1; + bool m_isOpen = false; - XmlWriter& writeBlankLine() { - ensureTagClosed(); - m_os << '\n'; - return *this; - } +public: + TablePrinter( std::ostream& os, std::vector<ColumnInfo> columnInfos ) + : m_os( os ), + m_columnInfos( std::move( columnInfos ) ) {} - void ensureTagClosed() { - if( m_tagIsOpen ) { - m_os << ">" << std::endl; - m_tagIsOpen = false; - } - } + auto columnInfos() const -> std::vector<ColumnInfo> const& { + return m_columnInfos; + } - private: - XmlWriter( XmlWriter const& ); - void operator=( XmlWriter const& ); + void open() { + if (!m_isOpen) { + m_isOpen = true; + *this << RowBreak(); - void writeDeclaration() { - m_os << "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"; - } + Columns headerCols; + Spacer spacer(2); + for (auto const& info : m_columnInfos) { + headerCols += Column(info.name).width(static_cast<std::size_t>(info.width - 2)); + headerCols += spacer; + } + m_os << headerCols << '\n'; - void newlineIfNecessary() { - if( m_needsNewline ) { - m_os << std::endl; - m_needsNewline = false; - } + m_os << Catch::getLineOfChars<'-'>() << '\n'; } + } + void close() { + if (m_isOpen) { + *this << RowBreak(); + m_os << std::endl; + m_isOpen = false; + } + } - bool m_tagIsOpen; - bool m_needsNewline; - std::vector<std::string> m_tags; - std::string m_indent; - std::ostream& m_os; - }; + template<typename T> + friend TablePrinter& operator << (TablePrinter& tp, T const& value) { + tp.m_oss << value; + return tp; + } + + friend TablePrinter& operator << (TablePrinter& tp, ColumnBreak) { + auto colStr = tp.m_oss.str(); + const auto strSize = colStr.size(); + tp.m_oss.str(""); + tp.open(); + if (tp.m_currentColumn == static_cast<int>(tp.m_columnInfos.size() - 1)) { + tp.m_currentColumn = -1; + tp.m_os << '\n'; + } + tp.m_currentColumn++; + + auto colInfo = tp.m_columnInfos[tp.m_currentColumn]; + auto padding = (strSize + 1 < static_cast<std::size_t>(colInfo.width)) + ? std::string(colInfo.width - (strSize + 1), ' ') + : std::string(); + if (colInfo.justification == ColumnInfo::Left) + tp.m_os << colStr << padding << ' '; + else + tp.m_os << padding << colStr << ' '; + return tp; + } -} + friend TablePrinter& operator << (TablePrinter& tp, RowBreak) { + if (tp.m_currentColumn > 0) { + tp.m_os << '\n'; + tp.m_currentColumn = -1; + } + return tp; + } +}; -namespace Catch { - class XmlReporter : public StreamingReporterBase { - public: - XmlReporter( ReporterConfig const& _config ) - : StreamingReporterBase( _config ), - m_xml(_config.stream()), - m_sectionDepth( 0 ) +ConsoleReporter::ConsoleReporter(ReporterConfig const& config) + : StreamingReporterBase(config), + m_tablePrinter(new TablePrinter(config.stream(), + [&config]() -> std::vector<ColumnInfo> { + if (config.fullConfig()->benchmarkNoAnalysis()) { - m_reporterPrefs.shouldRedirectStdOut = true; + return{ + { "benchmark name", CATCH_CONFIG_CONSOLE_WIDTH - 43, ColumnInfo::Left }, + { " samples", 14, ColumnInfo::Right }, + { " iterations", 14, ColumnInfo::Right }, + { " mean", 14, ColumnInfo::Right } + }; + } + else + { + return{ + { "benchmark name", CATCH_CONFIG_CONSOLE_WIDTH - 43, ColumnInfo::Left }, + { "samples mean std dev", 14, ColumnInfo::Right }, + { "iterations low mean low std dev", 14, ColumnInfo::Right }, + { "estimated high mean high std dev", 14, ColumnInfo::Right } + }; } + }())) {} +ConsoleReporter::~ConsoleReporter() = default; - virtual ~XmlReporter() CATCH_OVERRIDE; +std::string ConsoleReporter::getDescription() { + return "Reports test results as plain lines of text"; +} - static std::string getDescription() { - return "Reports test results as an XML document"; - } +void ConsoleReporter::noMatchingTestCases(std::string const& spec) { + stream << "No test cases matched '" << spec << '\'' << std::endl; +} - virtual std::string getStylesheetRef() const { - return std::string(); - } +void ConsoleReporter::reportInvalidArguments(std::string const&arg){ + stream << "Invalid Filter: " << arg << std::endl; +} - void writeSourceInfo( SourceLineInfo const& sourceInfo ) { - m_xml - .writeAttribute( "filename", sourceInfo.file ) - .writeAttribute( "line", sourceInfo.line ); - } +void ConsoleReporter::assertionStarting(AssertionInfo const&) {} - public: // StreamingReporterBase +bool ConsoleReporter::assertionEnded(AssertionStats const& _assertionStats) { + AssertionResult const& result = _assertionStats.assertionResult; - virtual void noMatchingTestCases( std::string const& s ) CATCH_OVERRIDE { - StreamingReporterBase::noMatchingTestCases( s ); - } + bool includeResults = m_config->includeSuccessfulResults() || !result.isOk(); - virtual void testRunStarting( TestRunInfo const& testInfo ) CATCH_OVERRIDE { - StreamingReporterBase::testRunStarting( testInfo ); - std::string stylesheetRef = getStylesheetRef(); - if( !stylesheetRef.empty() ) - m_xml.writeStylesheetRef( stylesheetRef ); - m_xml.startElement( "Catch" ); - if( !m_config->name().empty() ) - m_xml.writeAttribute( "name", m_config->name() ); - } + // Drop out if result was successful but we're not printing them. + if (!includeResults && result.getResultType() != ResultWas::Warning) + return false; - virtual void testGroupStarting( GroupInfo const& groupInfo ) CATCH_OVERRIDE { - StreamingReporterBase::testGroupStarting( groupInfo ); - m_xml.startElement( "Group" ) - .writeAttribute( "name", groupInfo.name ); - } + lazyPrint(); + + ConsoleAssertionPrinter printer(stream, _assertionStats, includeResults); + printer.print(); + stream << std::endl; + return true; +} - virtual void testCaseStarting( TestCaseInfo const& testInfo ) CATCH_OVERRIDE { - StreamingReporterBase::testCaseStarting(testInfo); - m_xml.startElement( "TestCase" ) - .writeAttribute( "name", trim( testInfo.name ) ) - .writeAttribute( "description", testInfo.description ) - .writeAttribute( "tags", testInfo.tagsAsString ); +void ConsoleReporter::sectionStarting(SectionInfo const& _sectionInfo) { + m_tablePrinter->close(); + m_headerPrinted = false; + StreamingReporterBase::sectionStarting(_sectionInfo); +} +void ConsoleReporter::sectionEnded(SectionStats const& _sectionStats) { + m_tablePrinter->close(); + if (_sectionStats.missingAssertions) { + lazyPrint(); + Colour colour(Colour::ResultError); + if (m_sectionStack.size() > 1) + stream << "\nNo assertions in section"; + else + stream << "\nNo assertions in test case"; + stream << " '" << _sectionStats.sectionInfo.name << "'\n" << std::endl; + } + double dur = _sectionStats.durationInSeconds; + if (shouldShowDuration(*m_config, dur)) { + stream << getFormattedDuration(dur) << " s: " << _sectionStats.sectionInfo.name << std::endl; + } + if (m_headerPrinted) { + m_headerPrinted = false; + } + StreamingReporterBase::sectionEnded(_sectionStats); +} - writeSourceInfo( testInfo.lineInfo ); +#if defined(CATCH_CONFIG_ENABLE_BENCHMARKING) +void ConsoleReporter::benchmarkPreparing(std::string const& name) { + lazyPrintWithoutClosingBenchmarkTable(); - if ( m_config->showDurations() == ShowDurations::Always ) - m_testCaseTimer.start(); - m_xml.ensureTagClosed(); - } + auto nameCol = Column(name).width(static_cast<std::size_t>(m_tablePrinter->columnInfos()[0].width - 2)); - virtual void sectionStarting( SectionInfo const& sectionInfo ) CATCH_OVERRIDE { - StreamingReporterBase::sectionStarting( sectionInfo ); - if( m_sectionDepth++ > 0 ) { - m_xml.startElement( "Section" ) - .writeAttribute( "name", trim( sectionInfo.name ) ) - .writeAttribute( "description", sectionInfo.description ); - writeSourceInfo( sectionInfo.lineInfo ); - m_xml.ensureTagClosed(); - } - } + bool firstLine = true; + for (auto line : nameCol) { + if (!firstLine) + (*m_tablePrinter) << ColumnBreak() << ColumnBreak() << ColumnBreak(); + else + firstLine = false; - virtual void assertionStarting( AssertionInfo const& ) CATCH_OVERRIDE { } + (*m_tablePrinter) << line << ColumnBreak(); + } +} - virtual bool assertionEnded( AssertionStats const& assertionStats ) CATCH_OVERRIDE { +void ConsoleReporter::benchmarkStarting(BenchmarkInfo const& info) { + (*m_tablePrinter) << info.samples << ColumnBreak() + << info.iterations << ColumnBreak(); + if (!m_config->benchmarkNoAnalysis()) + (*m_tablePrinter) << Duration(info.estimatedDuration) << ColumnBreak(); +} +void ConsoleReporter::benchmarkEnded(BenchmarkStats<> const& stats) { + if (m_config->benchmarkNoAnalysis()) + { + (*m_tablePrinter) << Duration(stats.mean.point.count()) << ColumnBreak(); + } + else + { + (*m_tablePrinter) << ColumnBreak() + << Duration(stats.mean.point.count()) << ColumnBreak() + << Duration(stats.mean.lower_bound.count()) << ColumnBreak() + << Duration(stats.mean.upper_bound.count()) << ColumnBreak() << ColumnBreak() + << Duration(stats.standardDeviation.point.count()) << ColumnBreak() + << Duration(stats.standardDeviation.lower_bound.count()) << ColumnBreak() + << Duration(stats.standardDeviation.upper_bound.count()) << ColumnBreak() << ColumnBreak() << ColumnBreak() << ColumnBreak() << ColumnBreak(); + } +} - AssertionResult const& result = assertionStats.assertionResult; +void ConsoleReporter::benchmarkFailed(std::string const& error) { + Colour colour(Colour::Red); + (*m_tablePrinter) + << "Benchmark failed (" << error << ')' + << ColumnBreak() << RowBreak(); +} +#endif // CATCH_CONFIG_ENABLE_BENCHMARKING - bool includeResults = m_config->includeSuccessfulResults() || !result.isOk(); +void ConsoleReporter::testCaseEnded(TestCaseStats const& _testCaseStats) { + m_tablePrinter->close(); + StreamingReporterBase::testCaseEnded(_testCaseStats); + m_headerPrinted = false; +} +void ConsoleReporter::testGroupEnded(TestGroupStats const& _testGroupStats) { + if (currentGroupInfo.used) { + printSummaryDivider(); + stream << "Summary for group '" << _testGroupStats.groupInfo.name << "':\n"; + printTotals(_testGroupStats.totals); + stream << '\n' << std::endl; + } + StreamingReporterBase::testGroupEnded(_testGroupStats); +} +void ConsoleReporter::testRunEnded(TestRunStats const& _testRunStats) { + printTotalsDivider(_testRunStats.totals); + printTotals(_testRunStats.totals); + stream << std::endl; + StreamingReporterBase::testRunEnded(_testRunStats); +} +void ConsoleReporter::testRunStarting(TestRunInfo const& _testInfo) { + StreamingReporterBase::testRunStarting(_testInfo); + printTestFilters(); +} - if( includeResults || result.getResultType() == ResultWas::Warning ) { - // Print any info messages in <Info> tags. - for( std::vector<MessageInfo>::const_iterator it = assertionStats.infoMessages.begin(), itEnd = assertionStats.infoMessages.end(); - it != itEnd; - ++it ) { - if( it->type == ResultWas::Info && includeResults ) { - m_xml.scopedElement( "Info" ) - .writeText( it->message ); - } else if ( it->type == ResultWas::Warning ) { - m_xml.scopedElement( "Warning" ) - .writeText( it->message ); - } - } - } +void ConsoleReporter::lazyPrint() { - // Drop out if result was successful but we're not printing them. - if( !includeResults && result.getResultType() != ResultWas::Warning ) - return true; + m_tablePrinter->close(); + lazyPrintWithoutClosingBenchmarkTable(); +} - // Print the expression if there is one. - if( result.hasExpression() ) { - m_xml.startElement( "Expression" ) - .writeAttribute( "success", result.succeeded() ) - .writeAttribute( "type", result.getTestMacroName() ); +void ConsoleReporter::lazyPrintWithoutClosingBenchmarkTable() { - writeSourceInfo( result.getSourceInfo() ); + if (!currentTestRunInfo.used) + lazyPrintRunInfo(); + if (!currentGroupInfo.used) + lazyPrintGroupInfo(); - m_xml.scopedElement( "Original" ) - .writeText( result.getExpression() ); - m_xml.scopedElement( "Expanded" ) - .writeText( result.getExpandedExpression() ); - } + if (!m_headerPrinted) { + printTestCaseAndSectionHeader(); + m_headerPrinted = true; + } +} +void ConsoleReporter::lazyPrintRunInfo() { + stream << '\n' << getLineOfChars<'~'>() << '\n'; + Colour colour(Colour::SecondaryText); + stream << currentTestRunInfo->name + << " is a Catch v" << libraryVersion() << " host application.\n" + << "Run with -? for options\n\n"; - // And... Print a result applicable to each result type. - switch( result.getResultType() ) { - case ResultWas::ThrewException: - m_xml.startElement( "Exception" ); - writeSourceInfo( result.getSourceInfo() ); - m_xml.writeText( result.getMessage() ); - m_xml.endElement(); - break; - case ResultWas::FatalErrorCondition: - m_xml.startElement( "FatalErrorCondition" ); - writeSourceInfo( result.getSourceInfo() ); - m_xml.writeText( result.getMessage() ); - m_xml.endElement(); - break; - case ResultWas::Info: - m_xml.scopedElement( "Info" ) - .writeText( result.getMessage() ); - break; - case ResultWas::Warning: - // Warning will already have been written - break; - case ResultWas::ExplicitFailure: - m_xml.startElement( "Failure" ); - writeSourceInfo( result.getSourceInfo() ); - m_xml.writeText( result.getMessage() ); - m_xml.endElement(); - break; - default: - break; - } + if (m_config->rngSeed() != 0) + stream << "Randomness seeded to: " << m_config->rngSeed() << "\n\n"; - if( result.hasExpression() ) - m_xml.endElement(); + currentTestRunInfo.used = true; +} +void ConsoleReporter::lazyPrintGroupInfo() { + if (!currentGroupInfo->name.empty() && currentGroupInfo->groupsCounts > 1) { + printClosedHeader("Group: " + currentGroupInfo->name); + currentGroupInfo.used = true; + } +} +void ConsoleReporter::printTestCaseAndSectionHeader() { + assert(!m_sectionStack.empty()); + printOpenHeader(currentTestCaseInfo->name); - return true; - } + if (m_sectionStack.size() > 1) { + Colour colourGuard(Colour::Headers); - virtual void sectionEnded( SectionStats const& sectionStats ) CATCH_OVERRIDE { - StreamingReporterBase::sectionEnded( sectionStats ); - if( --m_sectionDepth > 0 ) { - XmlWriter::ScopedElement e = m_xml.scopedElement( "OverallResults" ); - e.writeAttribute( "successes", sectionStats.assertions.passed ); - e.writeAttribute( "failures", sectionStats.assertions.failed ); - e.writeAttribute( "expectedFailures", sectionStats.assertions.failedButOk ); + auto + it = m_sectionStack.begin() + 1, // Skip first section (test case) + itEnd = m_sectionStack.end(); + for (; it != itEnd; ++it) + printHeaderString(it->name, 2); + } - if ( m_config->showDurations() == ShowDurations::Always ) - e.writeAttribute( "durationInSeconds", sectionStats.durationInSeconds ); + SourceLineInfo lineInfo = m_sectionStack.back().lineInfo; - m_xml.endElement(); - } - } + stream << getLineOfChars<'-'>() << '\n'; + Colour colourGuard(Colour::FileName); + stream << lineInfo << '\n'; + stream << getLineOfChars<'.'>() << '\n' << std::endl; +} - 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() ); +void ConsoleReporter::printClosedHeader(std::string const& _name) { + printOpenHeader(_name); + stream << getLineOfChars<'.'>() << '\n'; +} +void ConsoleReporter::printOpenHeader(std::string const& _name) { + stream << getLineOfChars<'-'>() << '\n'; + { + Colour colourGuard(Colour::Headers); + printHeaderString(_name); + } +} - if ( m_config->showDurations() == ShowDurations::Always ) - e.writeAttribute( "durationInSeconds", m_testCaseTimer.getElapsedSeconds() ); +// if string has a : in first line will set indent to follow it on +// subsequent lines +void ConsoleReporter::printHeaderString(std::string const& _string, std::size_t indent) { + std::size_t i = _string.find(": "); + if (i != std::string::npos) + i += 2; + else + i = 0; + stream << Column(_string).indent(indent + i).initialIndent(indent) << '\n'; +} - if( !testCaseStats.stdOut.empty() ) - m_xml.scopedElement( "StdOut" ).writeText( trim( testCaseStats.stdOut ), false ); - if( !testCaseStats.stdErr.empty() ) - m_xml.scopedElement( "StdErr" ).writeText( trim( testCaseStats.stdErr ), false ); +struct SummaryColumn { + + SummaryColumn( std::string _label, Colour::Code _colour ) + : label( std::move( _label ) ), + colour( _colour ) {} + SummaryColumn addRow( std::size_t count ) { + ReusableStringStream rss; + rss << count; + std::string row = rss.str(); + for (auto& oldRow : rows) { + while (oldRow.size() < row.size()) + oldRow = ' ' + oldRow; + while (oldRow.size() > row.size()) + row = ' ' + row; + } + rows.push_back(row); + return *this; + } - m_xml.endElement(); - } + std::string label; + Colour::Code colour; + std::vector<std::string> rows; - virtual void testGroupEnded( TestGroupStats const& testGroupStats ) CATCH_OVERRIDE { - StreamingReporterBase::testGroupEnded( testGroupStats ); - // TODO: Check testGroupStats.aborting and act accordingly. - m_xml.scopedElement( "OverallResults" ) - .writeAttribute( "successes", testGroupStats.totals.assertions.passed ) - .writeAttribute( "failures", testGroupStats.totals.assertions.failed ) - .writeAttribute( "expectedFailures", testGroupStats.totals.assertions.failedButOk ); - m_xml.endElement(); - } +}; - virtual void testRunEnded( TestRunStats const& testRunStats ) CATCH_OVERRIDE { - StreamingReporterBase::testRunEnded( testRunStats ); - m_xml.scopedElement( "OverallResults" ) - .writeAttribute( "successes", testRunStats.totals.assertions.passed ) - .writeAttribute( "failures", testRunStats.totals.assertions.failed ) - .writeAttribute( "expectedFailures", testRunStats.totals.assertions.failedButOk ); - m_xml.endElement(); +void ConsoleReporter::printTotals( Totals const& totals ) { + if (totals.testCases.total() == 0) { + stream << Colour(Colour::Warning) << "No tests ran\n"; + } else if (totals.assertions.total() > 0 && totals.testCases.allPassed()) { + stream << Colour(Colour::ResultSuccess) << "All tests passed"; + stream << " (" + << pluralise(totals.assertions.passed, "assertion") << " in " + << pluralise(totals.testCases.passed, "test case") << ')' + << '\n'; + } else { + + std::vector<SummaryColumn> columns; + columns.push_back(SummaryColumn("", Colour::None) + .addRow(totals.testCases.total()) + .addRow(totals.assertions.total())); + columns.push_back(SummaryColumn("passed", Colour::Success) + .addRow(totals.testCases.passed) + .addRow(totals.assertions.passed)); + columns.push_back(SummaryColumn("failed", Colour::ResultError) + .addRow(totals.testCases.failed) + .addRow(totals.assertions.failed)); + columns.push_back(SummaryColumn("failed as expected", Colour::ResultExpectedFailure) + .addRow(totals.testCases.failedButOk) + .addRow(totals.assertions.failedButOk)); + + printSummaryRow("test cases", columns, 0); + printSummaryRow("assertions", columns, 1); + } +} +void ConsoleReporter::printSummaryRow(std::string const& label, std::vector<SummaryColumn> const& cols, std::size_t row) { + for (auto col : cols) { + std::string value = col.rows[row]; + if (col.label.empty()) { + stream << label << ": "; + if (value != "0") + stream << value; + else + stream << Colour(Colour::Warning) << "- none -"; + } else if (value != "0") { + stream << Colour(Colour::LightGrey) << " | "; + stream << Colour(col.colour) + << value << ' ' << col.label; } + } + stream << '\n'; +} - private: - Timer m_testCaseTimer; - XmlWriter m_xml; - int m_sectionDepth; - }; +void ConsoleReporter::printTotalsDivider(Totals const& totals) { + if (totals.testCases.total() > 0) { + std::size_t failedRatio = makeRatio(totals.testCases.failed, totals.testCases.total()); + std::size_t failedButOkRatio = makeRatio(totals.testCases.failedButOk, totals.testCases.total()); + std::size_t passedRatio = makeRatio(totals.testCases.passed, totals.testCases.total()); + while (failedRatio + failedButOkRatio + passedRatio < CATCH_CONFIG_CONSOLE_WIDTH - 1) + findMax(failedRatio, failedButOkRatio, passedRatio)++; + while (failedRatio + failedButOkRatio + passedRatio > CATCH_CONFIG_CONSOLE_WIDTH - 1) + findMax(failedRatio, failedButOkRatio, passedRatio)--; + + stream << Colour(Colour::Error) << std::string(failedRatio, '='); + stream << Colour(Colour::ResultExpectedFailure) << std::string(failedButOkRatio, '='); + if (totals.testCases.allPassed()) + stream << Colour(Colour::ResultSuccess) << std::string(passedRatio, '='); + else + stream << Colour(Colour::Success) << std::string(passedRatio, '='); + } else { + stream << Colour(Colour::Warning) << std::string(CATCH_CONFIG_CONSOLE_WIDTH - 1, '='); + } + stream << '\n'; +} +void ConsoleReporter::printSummaryDivider() { + stream << getLineOfChars<'-'>() << '\n'; +} + +void ConsoleReporter::printTestFilters() { + if (m_config->testSpec().hasFilters()) { + Colour guard(Colour::BrightYellow); + stream << "Filters: " << serializeFilters(m_config->getTestsOrTags()) << '\n'; + } +} - INTERNAL_CATCH_REGISTER_REPORTER( "xml", XmlReporter ) +CATCH_REGISTER_REPORTER("console", ConsoleReporter) } // end namespace Catch -// #included from: ../reporters/catch_reporter_junit.hpp -#define TWOBLUECUBES_CATCH_REPORTER_JUNIT_HPP_INCLUDED +#if defined(_MSC_VER) +#pragma warning(pop) +#endif + +#if defined(__clang__) +# pragma clang diagnostic pop +#endif +// end catch_reporter_console.cpp +// start catch_reporter_junit.cpp -#include <assert.h> +#include <cassert> +#include <sstream> +#include <ctime> +#include <algorithm> +#include <iomanip> namespace Catch { @@ -10433,7 +16812,7 @@ namespace Catch { // Also, UTC only, again because of backward compatibility (%z is C++11) time_t rawtime; std::time(&rawtime); - const size_t timeStampSize = sizeof("2017-01-16T17:06:45Z"); + auto const timeStampSize = sizeof("2017-01-16T17:06:45Z"); #ifdef _MSC_VER std::tm timeInfo = {}; @@ -10451,1027 +16830,717 @@ namespace Catch { #else std::strftime(timeStamp, timeStampSize, fmt, timeInfo); #endif - return std::string(timeStamp); - } - - } - - class JunitReporter : public CumulativeReporterBase { - public: - JunitReporter( ReporterConfig const& _config ) - : CumulativeReporterBase( _config ), - xml( _config.stream() ), - unexpectedExceptions( 0 ), - m_okToFail( false ) - { - m_reporterPrefs.shouldRedirectStdOut = true; - } - - virtual ~JunitReporter() CATCH_OVERRIDE; - - static std::string getDescription() { - return "Reports test results in an XML format that looks like Ant's junitreport target"; + return std::string(timeStamp, timeStampSize-1); } - virtual void noMatchingTestCases( std::string const& /*spec*/ ) CATCH_OVERRIDE {} - - virtual void testRunStarting( TestRunInfo const& runInfo ) CATCH_OVERRIDE { - CumulativeReporterBase::testRunStarting( runInfo ); - xml.startElement( "testsuites" ); - } - - virtual void testGroupStarting( GroupInfo const& groupInfo ) CATCH_OVERRIDE { - suiteTimer.start(); - stdOutForSuite.str(""); - stdErrForSuite.str(""); - unexpectedExceptions = 0; - CumulativeReporterBase::testGroupStarting( groupInfo ); + std::string fileNameTag(const std::vector<std::string> &tags) { + auto it = std::find_if(begin(tags), + end(tags), + [] (std::string const& tag) {return tag.front() == '#'; }); + if (it != tags.end()) + return it->substr(1); + return std::string(); } - virtual void testCaseStarting( TestCaseInfo const& testCaseInfo ) CATCH_OVERRIDE { - m_okToFail = testCaseInfo.okToFail(); - } - virtual bool assertionEnded( AssertionStats const& assertionStats ) CATCH_OVERRIDE { - if( assertionStats.assertionResult.getResultType() == ResultWas::ThrewException && !m_okToFail ) - unexpectedExceptions++; - return CumulativeReporterBase::assertionEnded( assertionStats ); + // Formats the duration in seconds to 3 decimal places. + // This is done because some genius defined Maven Surefire schema + // in a way that only accepts 3 decimal places, and tools like + // Jenkins use that schema for validation JUnit reporter output. + std::string formatDuration( double seconds ) { + ReusableStringStream rss; + rss << std::fixed << std::setprecision( 3 ) << seconds; + return rss.str(); } - virtual void testCaseEnded( TestCaseStats const& testCaseStats ) CATCH_OVERRIDE { - stdOutForSuite << testCaseStats.stdOut; - stdErrForSuite << testCaseStats.stdErr; - CumulativeReporterBase::testCaseEnded( testCaseStats ); - } + } // anonymous namespace - virtual void testGroupEnded( TestGroupStats const& testGroupStats ) CATCH_OVERRIDE { - double suiteTime = suiteTimer.getElapsedSeconds(); - CumulativeReporterBase::testGroupEnded( testGroupStats ); - writeGroup( *m_testGroups.back(), suiteTime ); + JunitReporter::JunitReporter( ReporterConfig const& _config ) + : CumulativeReporterBase( _config ), + xml( _config.stream() ) + { + m_reporterPrefs.shouldRedirectStdOut = true; + m_reporterPrefs.shouldReportAllAssertions = true; } - virtual void testRunEndedCumulative() CATCH_OVERRIDE { - xml.endElement(); - } + JunitReporter::~JunitReporter() {} - void writeGroup( TestGroupNode const& groupNode, double suiteTime ) { - XmlWriter::ScopedElement e = xml.scopedElement( "testsuite" ); - TestGroupStats const& stats = groupNode.value; - xml.writeAttribute( "name", stats.groupInfo.name ); - xml.writeAttribute( "errors", unexpectedExceptions ); - xml.writeAttribute( "failures", stats.totals.assertions.failed-unexpectedExceptions ); - xml.writeAttribute( "tests", stats.totals.assertions.total() ); - xml.writeAttribute( "hostname", "tbd" ); // !TBD - if( m_config->showDurations() == ShowDurations::Never ) - xml.writeAttribute( "time", "" ); - else - xml.writeAttribute( "time", suiteTime ); - xml.writeAttribute( "timestamp", getCurrentTimestamp() ); + std::string JunitReporter::getDescription() { + return "Reports test results in an XML format that looks like Ant's junitreport target"; + } - // Write test cases - for( TestGroupNode::ChildNodes::const_iterator - it = groupNode.children.begin(), itEnd = groupNode.children.end(); - it != itEnd; - ++it ) - writeTestCase( **it ); + void JunitReporter::noMatchingTestCases( std::string const& /*spec*/ ) {} - xml.scopedElement( "system-out" ).writeText( trim( stdOutForSuite.str() ), false ); - xml.scopedElement( "system-err" ).writeText( trim( stdErrForSuite.str() ), false ); - } + void JunitReporter::testRunStarting( TestRunInfo const& runInfo ) { + CumulativeReporterBase::testRunStarting( runInfo ); + xml.startElement( "testsuites" ); + } - void writeTestCase( TestCaseNode const& testCaseNode ) { - TestCaseStats const& stats = testCaseNode.value; + void JunitReporter::testGroupStarting( GroupInfo const& groupInfo ) { + suiteTimer.start(); + stdOutForSuite.clear(); + stdErrForSuite.clear(); + unexpectedExceptions = 0; + CumulativeReporterBase::testGroupStarting( groupInfo ); + } - // All test cases have exactly one section - which represents the - // test case itself. That section may have 0-n nested sections - assert( testCaseNode.children.size() == 1 ); - SectionNode const& rootSection = *testCaseNode.children.front(); + void JunitReporter::testCaseStarting( TestCaseInfo const& testCaseInfo ) { + m_okToFail = testCaseInfo.okToFail(); + } - std::string className = stats.testInfo.className; + bool JunitReporter::assertionEnded( AssertionStats const& assertionStats ) { + if( assertionStats.assertionResult.getResultType() == ResultWas::ThrewException && !m_okToFail ) + unexpectedExceptions++; + return CumulativeReporterBase::assertionEnded( assertionStats ); + } - if( className.empty() ) { - if( rootSection.childSections.empty() ) - className = "global"; - } - writeSection( className, "", rootSection ); - } - - void writeSection( std::string const& className, - std::string const& rootName, - SectionNode const& sectionNode ) { - std::string name = trim( sectionNode.stats.sectionInfo.name ); - if( !rootName.empty() ) - name = rootName + '/' + name; - - if( !sectionNode.assertions.empty() || - !sectionNode.stdOut.empty() || - !sectionNode.stdErr.empty() ) { - XmlWriter::ScopedElement e = xml.scopedElement( "testcase" ); - if( className.empty() ) { - xml.writeAttribute( "classname", name ); - xml.writeAttribute( "name", "root" ); - } - else { - xml.writeAttribute( "classname", className ); - xml.writeAttribute( "name", name ); - } - xml.writeAttribute( "time", Catch::toString( sectionNode.stats.durationInSeconds ) ); - - writeAssertions( sectionNode ); - - if( !sectionNode.stdOut.empty() ) - xml.scopedElement( "system-out" ).writeText( trim( sectionNode.stdOut ), false ); - if( !sectionNode.stdErr.empty() ) - xml.scopedElement( "system-err" ).writeText( trim( sectionNode.stdErr ), false ); - } - for( SectionNode::ChildSections::const_iterator - it = sectionNode.childSections.begin(), - itEnd = sectionNode.childSections.end(); - it != itEnd; - ++it ) - if( className.empty() ) - writeSection( name, "", **it ); - else - writeSection( className, name, **it ); - } - - void writeAssertions( SectionNode const& sectionNode ) { - for( SectionNode::Assertions::const_iterator - it = sectionNode.assertions.begin(), itEnd = sectionNode.assertions.end(); - it != itEnd; - ++it ) - writeAssertion( *it ); - } - void writeAssertion( AssertionStats const& stats ) { - AssertionResult const& result = stats.assertionResult; - if( !result.isOk() ) { - std::string elementName; - switch( result.getResultType() ) { - case ResultWas::ThrewException: - case ResultWas::FatalErrorCondition: - elementName = "error"; - break; - case ResultWas::ExplicitFailure: - elementName = "failure"; - break; - case ResultWas::ExpressionFailed: - elementName = "failure"; - break; - case ResultWas::DidntThrowException: - elementName = "failure"; - break; - - // We should never see these here: - case ResultWas::Info: - case ResultWas::Warning: - case ResultWas::Ok: - case ResultWas::Unknown: - case ResultWas::FailureBit: - case ResultWas::Exception: - elementName = "internalError"; - break; - } + void JunitReporter::testCaseEnded( TestCaseStats const& testCaseStats ) { + stdOutForSuite += testCaseStats.stdOut; + stdErrForSuite += testCaseStats.stdErr; + CumulativeReporterBase::testCaseEnded( testCaseStats ); + } - XmlWriter::ScopedElement e = xml.scopedElement( elementName ); + void JunitReporter::testGroupEnded( TestGroupStats const& testGroupStats ) { + double suiteTime = suiteTimer.getElapsedSeconds(); + CumulativeReporterBase::testGroupEnded( testGroupStats ); + writeGroup( *m_testGroups.back(), suiteTime ); + } - xml.writeAttribute( "message", result.getExpandedExpression() ); - xml.writeAttribute( "type", result.getTestMacroName() ); + void JunitReporter::testRunEndedCumulative() { + xml.endElement(); + } - std::ostringstream oss; - if( !result.getMessage().empty() ) - oss << result.getMessage() << '\n'; - for( std::vector<MessageInfo>::const_iterator - it = stats.infoMessages.begin(), - itEnd = stats.infoMessages.end(); - it != itEnd; - ++it ) - if( it->type == ResultWas::Info ) - oss << it->message << '\n'; + void JunitReporter::writeGroup( TestGroupNode const& groupNode, double suiteTime ) { + XmlWriter::ScopedElement e = xml.scopedElement( "testsuite" ); - oss << "at " << result.getSourceInfo(); - xml.writeText( oss.str(), false ); + TestGroupStats const& stats = groupNode.value; + xml.writeAttribute( "name", stats.groupInfo.name ); + xml.writeAttribute( "errors", unexpectedExceptions ); + xml.writeAttribute( "failures", stats.totals.assertions.failed-unexpectedExceptions ); + xml.writeAttribute( "tests", stats.totals.assertions.total() ); + xml.writeAttribute( "hostname", "tbd" ); // !TBD + if( m_config->showDurations() == ShowDurations::Never ) + xml.writeAttribute( "time", "" ); + else + xml.writeAttribute( "time", formatDuration( suiteTime ) ); + xml.writeAttribute( "timestamp", getCurrentTimestamp() ); + + // Write properties if there are any + if (m_config->hasTestFilters() || m_config->rngSeed() != 0) { + auto properties = xml.scopedElement("properties"); + if (m_config->hasTestFilters()) { + xml.scopedElement("property") + .writeAttribute("name", "filters") + .writeAttribute("value", serializeFilters(m_config->getTestsOrTags())); + } + if (m_config->rngSeed() != 0) { + xml.scopedElement("property") + .writeAttribute("name", "random-seed") + .writeAttribute("value", m_config->rngSeed()); } } - XmlWriter xml; - Timer suiteTimer; - std::ostringstream stdOutForSuite; - std::ostringstream stdErrForSuite; - unsigned int unexpectedExceptions; - bool m_okToFail; - }; - - INTERNAL_CATCH_REGISTER_REPORTER( "junit", JunitReporter ) + // Write test cases + for( auto const& child : groupNode.children ) + writeTestCase( *child ); -} // end namespace Catch - -// #included from: ../reporters/catch_reporter_console.hpp -#define TWOBLUECUBES_CATCH_REPORTER_CONSOLE_HPP_INCLUDED - -#include <cassert> -#include <cfloat> -#include <cstdio> - -namespace Catch { + xml.scopedElement( "system-out" ).writeText( trim( stdOutForSuite ), XmlFormatting::Newline ); + xml.scopedElement( "system-err" ).writeText( trim( stdErrForSuite ), XmlFormatting::Newline ); + } - struct ConsoleReporter : StreamingReporterBase { - ConsoleReporter( ReporterConfig const& _config ) - : StreamingReporterBase( _config ), - m_headerPrinted( false ) - {} + void JunitReporter::writeTestCase( TestCaseNode const& testCaseNode ) { + TestCaseStats const& stats = testCaseNode.value; - virtual ~ConsoleReporter() CATCH_OVERRIDE; - static std::string getDescription() { - return "Reports test results as plain lines of text"; - } + // All test cases have exactly one section - which represents the + // test case itself. That section may have 0-n nested sections + assert( testCaseNode.children.size() == 1 ); + SectionNode const& rootSection = *testCaseNode.children.front(); - virtual void noMatchingTestCases( std::string const& spec ) CATCH_OVERRIDE { - stream << "No test cases matched '" << spec << '\'' << std::endl; - } + std::string className = stats.testInfo.className; - virtual void assertionStarting( AssertionInfo const& ) CATCH_OVERRIDE { + if( className.empty() ) { + className = fileNameTag(stats.testInfo.tags); + if ( className.empty() ) + className = "global"; } - virtual bool assertionEnded( AssertionStats const& _assertionStats ) CATCH_OVERRIDE { - AssertionResult const& result = _assertionStats.assertionResult; - - bool includeResults = m_config->includeSuccessfulResults() || !result.isOk(); - - // Drop out if result was successful but we're not printing them. - if( !includeResults && result.getResultType() != ResultWas::Warning ) - return false; + if ( !m_config->name().empty() ) + className = m_config->name() + "." + className; - lazyPrint(); + writeSection( className, "", rootSection, stats.testInfo.okToFail() ); + } - AssertionPrinter printer( stream, _assertionStats, includeResults ); - printer.print(); - stream << std::endl; - return true; - } + void JunitReporter::writeSection( std::string const& className, + std::string const& rootName, + SectionNode const& sectionNode, + bool testOkToFail) { + std::string name = trim( sectionNode.stats.sectionInfo.name ); + if( !rootName.empty() ) + name = rootName + '/' + name; - virtual void sectionStarting( SectionInfo const& _sectionInfo ) CATCH_OVERRIDE { - m_headerPrinted = false; - StreamingReporterBase::sectionStarting( _sectionInfo ); - } - virtual void sectionEnded( SectionStats const& _sectionStats ) CATCH_OVERRIDE { - if( _sectionStats.missingAssertions ) { - lazyPrint(); - Colour colour( Colour::ResultError ); - if( m_sectionStack.size() > 1 ) - stream << "\nNo assertions in section"; - else - stream << "\nNo assertions in test case"; - stream << " '" << _sectionStats.sectionInfo.name << "'\n" << std::endl; + if( !sectionNode.assertions.empty() || + !sectionNode.stdOut.empty() || + !sectionNode.stdErr.empty() ) { + XmlWriter::ScopedElement e = xml.scopedElement( "testcase" ); + if( className.empty() ) { + xml.writeAttribute( "classname", name ); + xml.writeAttribute( "name", "root" ); } - if( m_config->showDurations() == ShowDurations::Always ) { - stream << getFormattedDuration(_sectionStats.durationInSeconds) << " s: " << _sectionStats.sectionInfo.name << std::endl; + else { + xml.writeAttribute( "classname", className ); + xml.writeAttribute( "name", name ); } - if( m_headerPrinted ) { - m_headerPrinted = false; + xml.writeAttribute( "time", formatDuration( sectionNode.stats.durationInSeconds ) ); + // This is not ideal, but it should be enough to mimic gtest's + // junit output. + // Ideally the JUnit reporter would also handle `skipTest` + // events and write those out appropriately. + xml.writeAttribute( "status", "run" ); + + if (sectionNode.stats.assertions.failedButOk) { + xml.scopedElement("skipped") + .writeAttribute("message", "TEST_CASE tagged with !mayfail"); } - StreamingReporterBase::sectionEnded( _sectionStats ); - } - virtual void testCaseEnded( TestCaseStats const& _testCaseStats ) CATCH_OVERRIDE { - StreamingReporterBase::testCaseEnded( _testCaseStats ); - m_headerPrinted = false; + writeAssertions( sectionNode ); + + if( !sectionNode.stdOut.empty() ) + xml.scopedElement( "system-out" ).writeText( trim( sectionNode.stdOut ), XmlFormatting::Newline ); + if( !sectionNode.stdErr.empty() ) + xml.scopedElement( "system-err" ).writeText( trim( sectionNode.stdErr ), XmlFormatting::Newline ); } - virtual void testGroupEnded( TestGroupStats const& _testGroupStats ) CATCH_OVERRIDE { - if( currentGroupInfo.used ) { - printSummaryDivider(); - stream << "Summary for group '" << _testGroupStats.groupInfo.name << "':\n"; - printTotals( _testGroupStats.totals ); - stream << '\n' << std::endl; + for( auto const& childNode : sectionNode.childSections ) + if( className.empty() ) + writeSection( name, "", *childNode, testOkToFail ); + else + writeSection( className, name, *childNode, testOkToFail ); + } + + void JunitReporter::writeAssertions( SectionNode const& sectionNode ) { + for( auto const& assertion : sectionNode.assertions ) + writeAssertion( assertion ); + } + + void JunitReporter::writeAssertion( AssertionStats const& stats ) { + AssertionResult const& result = stats.assertionResult; + if( !result.isOk() ) { + std::string elementName; + switch( result.getResultType() ) { + case ResultWas::ThrewException: + case ResultWas::FatalErrorCondition: + elementName = "error"; + break; + case ResultWas::ExplicitFailure: + case ResultWas::ExpressionFailed: + case ResultWas::DidntThrowException: + elementName = "failure"; + break; + + // We should never see these here: + case ResultWas::Info: + case ResultWas::Warning: + case ResultWas::Ok: + case ResultWas::Unknown: + case ResultWas::FailureBit: + case ResultWas::Exception: + elementName = "internalError"; + break; } - StreamingReporterBase::testGroupEnded( _testGroupStats ); - } - virtual void testRunEnded( TestRunStats const& _testRunStats ) CATCH_OVERRIDE { - printTotalsDivider( _testRunStats.totals ); - printTotals( _testRunStats.totals ); - stream << std::endl; - StreamingReporterBase::testRunEnded( _testRunStats ); - } - private: + XmlWriter::ScopedElement e = xml.scopedElement( elementName ); - class AssertionPrinter { - void operator= ( AssertionPrinter const& ); - public: - AssertionPrinter( std::ostream& _stream, AssertionStats const& _stats, bool _printInfoMessages ) - : stream( _stream ), - stats( _stats ), - result( _stats.assertionResult ), - colour( Colour::None ), - message( result.getMessage() ), - messages( _stats.infoMessages ), - printInfoMessages( _printInfoMessages ) - { - switch( result.getResultType() ) { - case ResultWas::Ok: - colour = Colour::Success; - passOrFail = "PASSED"; - //if( result.hasMessage() ) - if( _stats.infoMessages.size() == 1 ) - messageLabel = "with message"; - if( _stats.infoMessages.size() > 1 ) - messageLabel = "with messages"; - break; - case ResultWas::ExpressionFailed: - if( result.isOk() ) { - colour = Colour::Success; - passOrFail = "FAILED - but was ok"; - } - else { - colour = Colour::Error; - passOrFail = "FAILED"; - } - if( _stats.infoMessages.size() == 1 ) - messageLabel = "with message"; - if( _stats.infoMessages.size() > 1 ) - messageLabel = "with messages"; - break; - case ResultWas::ThrewException: - colour = Colour::Error; - passOrFail = "FAILED"; - messageLabel = "due to unexpected exception with "; - if (_stats.infoMessages.size() == 1) - messageLabel += "message"; - if (_stats.infoMessages.size() > 1) - messageLabel += "messages"; - break; - case ResultWas::FatalErrorCondition: - colour = Colour::Error; - passOrFail = "FAILED"; - messageLabel = "due to a fatal error condition"; - break; - case ResultWas::DidntThrowException: - colour = Colour::Error; - passOrFail = "FAILED"; - messageLabel = "because no exception was thrown where one was expected"; - break; - case ResultWas::Info: - messageLabel = "info"; - break; - case ResultWas::Warning: - messageLabel = "warning"; - break; - case ResultWas::ExplicitFailure: - passOrFail = "FAILED"; - colour = Colour::Error; - if( _stats.infoMessages.size() == 1 ) - messageLabel = "explicitly with message"; - if( _stats.infoMessages.size() > 1 ) - messageLabel = "explicitly with messages"; - break; - // These cases are here to prevent compiler warnings - case ResultWas::Unknown: - case ResultWas::FailureBit: - case ResultWas::Exception: - passOrFail = "** internal error **"; - colour = Colour::Error; - break; - } - } + xml.writeAttribute( "message", result.getExpression() ); + xml.writeAttribute( "type", result.getTestMacroName() ); - void print() const { - printSourceInfo(); - if( stats.totals.assertions.total() > 0 ) { - if( result.isOk() ) - stream << '\n'; - printResultType(); - printOriginalExpression(); - printReconstructedExpression(); + ReusableStringStream rss; + if (stats.totals.assertions.total() > 0) { + rss << "FAILED" << ":\n"; + if (result.hasExpression()) { + rss << " "; + rss << result.getExpressionInMacro(); + rss << '\n'; } - else { - stream << '\n'; + if (result.hasExpandedExpression()) { + rss << "with expansion:\n"; + rss << Column(result.getExpandedExpression()).indent(2) << '\n'; } - printMessage(); + } else { + rss << '\n'; } - private: - void printResultType() const { - if( !passOrFail.empty() ) { - Colour colourGuard( colour ); - stream << passOrFail << ":\n"; - } - } - void printOriginalExpression() const { - if( result.hasExpression() ) { - Colour colourGuard( Colour::OriginalExpression ); - stream << " "; - stream << result.getExpressionInMacro(); - stream << '\n'; - } - } - void printReconstructedExpression() const { - if( result.hasExpandedExpression() ) { - stream << "with expansion:\n"; - Colour colourGuard( Colour::ReconstructedExpression ); - stream << Text( result.getExpandedExpression(), TextAttributes().setIndent(2) ) << '\n'; - } - } - void printMessage() const { - if( !messageLabel.empty() ) - stream << messageLabel << ':' << '\n'; - for( std::vector<MessageInfo>::const_iterator it = messages.begin(), itEnd = messages.end(); - it != itEnd; - ++it ) { - // If this assertion is a warning ignore any INFO messages - if( printInfoMessages || it->type != ResultWas::Info ) - stream << Text( it->message, TextAttributes().setIndent(2) ) << '\n'; - } - } - void printSourceInfo() const { - Colour colourGuard( Colour::FileName ); - stream << result.getSourceInfo() << ": "; - } + if( !result.getMessage().empty() ) + rss << result.getMessage() << '\n'; + for( auto const& msg : stats.infoMessages ) + if( msg.type == ResultWas::Info ) + rss << msg.message << '\n'; - std::ostream& stream; - AssertionStats const& stats; - AssertionResult const& result; - Colour::Code colour; - std::string passOrFail; - std::string messageLabel; - std::string message; - std::vector<MessageInfo> messages; - bool printInfoMessages; - }; + rss << "at " << result.getSourceInfo(); + xml.writeText( rss.str(), XmlFormatting::Newline ); + } + } - void lazyPrint() { + CATCH_REGISTER_REPORTER( "junit", JunitReporter ) - if( !currentTestRunInfo.used ) - lazyPrintRunInfo(); - if( !currentGroupInfo.used ) - lazyPrintGroupInfo(); +} // end namespace Catch +// end catch_reporter_junit.cpp +// start catch_reporter_listening.cpp - if( !m_headerPrinted ) { - printTestCaseAndSectionHeader(); - m_headerPrinted = true; - } - } - void lazyPrintRunInfo() { - stream << '\n' << getLineOfChars<'~'>() << '\n'; - Colour colour( Colour::SecondaryText ); - stream << currentTestRunInfo->name - << " is a Catch v" << libraryVersion() << " host application.\n" - << "Run with -? for options\n\n"; +#include <cassert> - if( m_config->rngSeed() != 0 ) - stream << "Randomness seeded to: " << m_config->rngSeed() << "\n\n"; +namespace Catch { - currentTestRunInfo.used = true; - } - void lazyPrintGroupInfo() { - if( !currentGroupInfo->name.empty() && currentGroupInfo->groupsCounts > 1 ) { - printClosedHeader( "Group: " + currentGroupInfo->name ); - currentGroupInfo.used = true; - } - } - void printTestCaseAndSectionHeader() { - assert( !m_sectionStack.empty() ); - printOpenHeader( currentTestCaseInfo->name ); + ListeningReporter::ListeningReporter() { + // We will assume that listeners will always want all assertions + m_preferences.shouldReportAllAssertions = true; + } - if( m_sectionStack.size() > 1 ) { - Colour colourGuard( Colour::Headers ); + void ListeningReporter::addListener( IStreamingReporterPtr&& listener ) { + m_listeners.push_back( std::move( listener ) ); + } - std::vector<SectionInfo>::const_iterator - it = m_sectionStack.begin()+1, // Skip first section (test case) - itEnd = m_sectionStack.end(); - for( ; it != itEnd; ++it ) - printHeaderString( it->name, 2 ); - } + void ListeningReporter::addReporter(IStreamingReporterPtr&& reporter) { + assert(!m_reporter && "Listening reporter can wrap only 1 real reporter"); + m_reporter = std::move( reporter ); + m_preferences.shouldRedirectStdOut = m_reporter->getPreferences().shouldRedirectStdOut; + } - SourceLineInfo lineInfo = m_sectionStack.back().lineInfo; + ReporterPreferences ListeningReporter::getPreferences() const { + return m_preferences; + } - if( !lineInfo.empty() ){ - stream << getLineOfChars<'-'>() << '\n'; - Colour colourGuard( Colour::FileName ); - stream << lineInfo << '\n'; - } - stream << getLineOfChars<'.'>() << '\n' << std::endl; + std::set<Verbosity> ListeningReporter::getSupportedVerbosities() { + return std::set<Verbosity>{ }; + } + + void ListeningReporter::noMatchingTestCases( std::string const& spec ) { + for ( auto const& listener : m_listeners ) { + listener->noMatchingTestCases( spec ); } + m_reporter->noMatchingTestCases( spec ); + } - void printClosedHeader( std::string const& _name ) { - printOpenHeader( _name ); - stream << getLineOfChars<'.'>() << '\n'; + void ListeningReporter::reportInvalidArguments(std::string const&arg){ + for ( auto const& listener : m_listeners ) { + listener->reportInvalidArguments( arg ); } - void printOpenHeader( std::string const& _name ) { - stream << getLineOfChars<'-'>() << '\n'; - { - Colour colourGuard( Colour::Headers ); - printHeaderString( _name ); - } + m_reporter->reportInvalidArguments( arg ); + } + +#if defined(CATCH_CONFIG_ENABLE_BENCHMARKING) + void ListeningReporter::benchmarkPreparing( std::string const& name ) { + for (auto const& listener : m_listeners) { + listener->benchmarkPreparing(name); + } + m_reporter->benchmarkPreparing(name); + } + void ListeningReporter::benchmarkStarting( BenchmarkInfo const& benchmarkInfo ) { + for ( auto const& listener : m_listeners ) { + listener->benchmarkStarting( benchmarkInfo ); + } + m_reporter->benchmarkStarting( benchmarkInfo ); + } + void ListeningReporter::benchmarkEnded( BenchmarkStats<> const& benchmarkStats ) { + for ( auto const& listener : m_listeners ) { + listener->benchmarkEnded( benchmarkStats ); } + m_reporter->benchmarkEnded( benchmarkStats ); + } - // if string has a : in first line will set indent to follow it on - // subsequent lines - void printHeaderString( std::string const& _string, std::size_t indent = 0 ) { - std::size_t i = _string.find( ": " ); - if( i != std::string::npos ) - i+=2; - else - i = 0; - stream << Text( _string, TextAttributes() - .setIndent( indent+i) - .setInitialIndent( indent ) ) << '\n'; + void ListeningReporter::benchmarkFailed( std::string const& error ) { + for (auto const& listener : m_listeners) { + listener->benchmarkFailed(error); + } + m_reporter->benchmarkFailed(error); + } +#endif // CATCH_CONFIG_ENABLE_BENCHMARKING + + void ListeningReporter::testRunStarting( TestRunInfo const& testRunInfo ) { + for ( auto const& listener : m_listeners ) { + listener->testRunStarting( testRunInfo ); } + m_reporter->testRunStarting( testRunInfo ); + } - struct SummaryColumn { + void ListeningReporter::testGroupStarting( GroupInfo const& groupInfo ) { + for ( auto const& listener : m_listeners ) { + listener->testGroupStarting( groupInfo ); + } + m_reporter->testGroupStarting( groupInfo ); + } - SummaryColumn( std::string const& _label, Colour::Code _colour ) - : label( _label ), - colour( _colour ) - {} - SummaryColumn addRow( std::size_t count ) { - std::ostringstream oss; - oss << count; - std::string row = oss.str(); - for( std::vector<std::string>::iterator it = rows.begin(); it != rows.end(); ++it ) { - while( it->size() < row.size() ) - *it = ' ' + *it; - while( it->size() > row.size() ) - row = ' ' + row; - } - rows.push_back( row ); - return *this; - } + void ListeningReporter::testCaseStarting( TestCaseInfo const& testInfo ) { + for ( auto const& listener : m_listeners ) { + listener->testCaseStarting( testInfo ); + } + m_reporter->testCaseStarting( testInfo ); + } - std::string label; - Colour::Code colour; - std::vector<std::string> rows; + void ListeningReporter::sectionStarting( SectionInfo const& sectionInfo ) { + for ( auto const& listener : m_listeners ) { + listener->sectionStarting( sectionInfo ); + } + m_reporter->sectionStarting( sectionInfo ); + } - }; + void ListeningReporter::assertionStarting( AssertionInfo const& assertionInfo ) { + for ( auto const& listener : m_listeners ) { + listener->assertionStarting( assertionInfo ); + } + m_reporter->assertionStarting( assertionInfo ); + } - void printTotals( Totals const& totals ) { - if( totals.testCases.total() == 0 ) { - stream << Colour( Colour::Warning ) << "No tests ran\n"; - } - else if( totals.assertions.total() > 0 && totals.testCases.allPassed() ) { - stream << Colour( Colour::ResultSuccess ) << "All tests passed"; - stream << " (" - << pluralise( totals.assertions.passed, "assertion" ) << " in " - << pluralise( totals.testCases.passed, "test case" ) << ')' - << '\n'; - } - else { + // The return value indicates if the messages buffer should be cleared: + bool ListeningReporter::assertionEnded( AssertionStats const& assertionStats ) { + for( auto const& listener : m_listeners ) { + static_cast<void>( listener->assertionEnded( assertionStats ) ); + } + return m_reporter->assertionEnded( assertionStats ); + } - std::vector<SummaryColumn> columns; - columns.push_back( SummaryColumn( "", Colour::None ) - .addRow( totals.testCases.total() ) - .addRow( totals.assertions.total() ) ); - columns.push_back( SummaryColumn( "passed", Colour::Success ) - .addRow( totals.testCases.passed ) - .addRow( totals.assertions.passed ) ); - columns.push_back( SummaryColumn( "failed", Colour::ResultError ) - .addRow( totals.testCases.failed ) - .addRow( totals.assertions.failed ) ); - columns.push_back( SummaryColumn( "failed as expected", Colour::ResultExpectedFailure ) - .addRow( totals.testCases.failedButOk ) - .addRow( totals.assertions.failedButOk ) ); - - printSummaryRow( "test cases", columns, 0 ); - printSummaryRow( "assertions", columns, 1 ); - } - } - void printSummaryRow( std::string const& label, std::vector<SummaryColumn> const& cols, std::size_t row ) { - for( std::vector<SummaryColumn>::const_iterator it = cols.begin(); it != cols.end(); ++it ) { - std::string value = it->rows[row]; - if( it->label.empty() ) { - stream << label << ": "; - if( value != "0" ) - stream << value; - else - stream << Colour( Colour::Warning ) << "- none -"; - } - else if( value != "0" ) { - stream << Colour( Colour::LightGrey ) << " | "; - stream << Colour( it->colour ) - << value << ' ' << it->label; - } - } - stream << '\n'; + void ListeningReporter::sectionEnded( SectionStats const& sectionStats ) { + for ( auto const& listener : m_listeners ) { + listener->sectionEnded( sectionStats ); } + m_reporter->sectionEnded( sectionStats ); + } - static std::size_t makeRatio( std::size_t number, std::size_t total ) { - std::size_t ratio = total > 0 ? CATCH_CONFIG_CONSOLE_WIDTH * number/ total : 0; - return ( ratio == 0 && number > 0 ) ? 1 : ratio; + void ListeningReporter::testCaseEnded( TestCaseStats const& testCaseStats ) { + for ( auto const& listener : m_listeners ) { + listener->testCaseEnded( testCaseStats ); } - static std::size_t& findMax( std::size_t& i, std::size_t& j, std::size_t& k ) { - if( i > j && i > k ) - return i; - else if( j > k ) - return j; - else - return k; - } - - void printTotalsDivider( Totals const& totals ) { - if( totals.testCases.total() > 0 ) { - std::size_t failedRatio = makeRatio( totals.testCases.failed, totals.testCases.total() ); - std::size_t failedButOkRatio = makeRatio( totals.testCases.failedButOk, totals.testCases.total() ); - std::size_t passedRatio = makeRatio( totals.testCases.passed, totals.testCases.total() ); - while( failedRatio + failedButOkRatio + passedRatio < CATCH_CONFIG_CONSOLE_WIDTH-1 ) - findMax( failedRatio, failedButOkRatio, passedRatio )++; - while( failedRatio + failedButOkRatio + passedRatio > CATCH_CONFIG_CONSOLE_WIDTH-1 ) - findMax( failedRatio, failedButOkRatio, passedRatio )--; - - stream << Colour( Colour::Error ) << std::string( failedRatio, '=' ); - stream << Colour( Colour::ResultExpectedFailure ) << std::string( failedButOkRatio, '=' ); - if( totals.testCases.allPassed() ) - stream << Colour( Colour::ResultSuccess ) << std::string( passedRatio, '=' ); - else - stream << Colour( Colour::Success ) << std::string( passedRatio, '=' ); - } - else { - stream << Colour( Colour::Warning ) << std::string( CATCH_CONFIG_CONSOLE_WIDTH-1, '=' ); - } - stream << '\n'; + m_reporter->testCaseEnded( testCaseStats ); + } + + void ListeningReporter::testGroupEnded( TestGroupStats const& testGroupStats ) { + for ( auto const& listener : m_listeners ) { + listener->testGroupEnded( testGroupStats ); } - void printSummaryDivider() { - stream << getLineOfChars<'-'>() << '\n'; + m_reporter->testGroupEnded( testGroupStats ); + } + + void ListeningReporter::testRunEnded( TestRunStats const& testRunStats ) { + for ( auto const& listener : m_listeners ) { + listener->testRunEnded( testRunStats ); } + m_reporter->testRunEnded( testRunStats ); + } - private: - bool m_headerPrinted; - }; + void ListeningReporter::skipTest( TestCaseInfo const& testInfo ) { + for ( auto const& listener : m_listeners ) { + listener->skipTest( testInfo ); + } + m_reporter->skipTest( testInfo ); + } - INTERNAL_CATCH_REGISTER_REPORTER( "console", ConsoleReporter ) + bool ListeningReporter::isMulti() const { + return true; + } } // end namespace Catch +// end catch_reporter_listening.cpp +// start catch_reporter_xml.cpp -// #included from: ../reporters/catch_reporter_compact.hpp -#define TWOBLUECUBES_CATCH_REPORTER_COMPACT_HPP_INCLUDED +#if defined(_MSC_VER) +#pragma warning(push) +#pragma warning(disable:4061) // Not all labels are EXPLICITLY handled in switch + // Note that 4062 (not all labels are handled + // and default is missing) is enabled +#endif namespace Catch { + XmlReporter::XmlReporter( ReporterConfig const& _config ) + : StreamingReporterBase( _config ), + m_xml(_config.stream()) + { + m_reporterPrefs.shouldRedirectStdOut = true; + m_reporterPrefs.shouldReportAllAssertions = true; + } - struct CompactReporter : StreamingReporterBase { - - CompactReporter( ReporterConfig const& _config ) - : StreamingReporterBase( _config ) - {} - - virtual ~CompactReporter(); - - static std::string getDescription() { - return "Reports test results on a single line, suitable for IDEs"; - } + XmlReporter::~XmlReporter() = default; - virtual ReporterPreferences getPreferences() const { - ReporterPreferences prefs; - prefs.shouldRedirectStdOut = false; - return prefs; - } + std::string XmlReporter::getDescription() { + return "Reports test results as an XML document"; + } - virtual void noMatchingTestCases( std::string const& spec ) { - stream << "No test cases matched '" << spec << '\'' << std::endl; - } + std::string XmlReporter::getStylesheetRef() const { + return std::string(); + } - virtual void assertionStarting( AssertionInfo const& ) {} + void XmlReporter::writeSourceInfo( SourceLineInfo const& sourceInfo ) { + m_xml + .writeAttribute( "filename", sourceInfo.file ) + .writeAttribute( "line", sourceInfo.line ); + } - virtual bool assertionEnded( AssertionStats const& _assertionStats ) { - AssertionResult const& result = _assertionStats.assertionResult; + void XmlReporter::noMatchingTestCases( std::string const& s ) { + StreamingReporterBase::noMatchingTestCases( s ); + } - bool printInfoMessages = true; + void XmlReporter::testRunStarting( TestRunInfo const& testInfo ) { + StreamingReporterBase::testRunStarting( testInfo ); + std::string stylesheetRef = getStylesheetRef(); + if( !stylesheetRef.empty() ) + m_xml.writeStylesheetRef( stylesheetRef ); + m_xml.startElement( "Catch" ); + if( !m_config->name().empty() ) + m_xml.writeAttribute( "name", m_config->name() ); + if (m_config->testSpec().hasFilters()) + m_xml.writeAttribute( "filters", serializeFilters( m_config->getTestsOrTags() ) ); + if( m_config->rngSeed() != 0 ) + m_xml.scopedElement( "Randomness" ) + .writeAttribute( "seed", m_config->rngSeed() ); + } - // Drop out if result was successful and we're not printing those - if( !m_config->includeSuccessfulResults() && result.isOk() ) { - if( result.getResultType() != ResultWas::Warning ) - return false; - printInfoMessages = false; - } + void XmlReporter::testGroupStarting( GroupInfo const& groupInfo ) { + StreamingReporterBase::testGroupStarting( groupInfo ); + m_xml.startElement( "Group" ) + .writeAttribute( "name", groupInfo.name ); + } - AssertionPrinter printer( stream, _assertionStats, printInfoMessages ); - printer.print(); + void XmlReporter::testCaseStarting( TestCaseInfo const& testInfo ) { + StreamingReporterBase::testCaseStarting(testInfo); + m_xml.startElement( "TestCase" ) + .writeAttribute( "name", trim( testInfo.name ) ) + .writeAttribute( "description", testInfo.description ) + .writeAttribute( "tags", testInfo.tagsAsString() ); - stream << std::endl; - return true; - } + writeSourceInfo( testInfo.lineInfo ); - virtual void sectionEnded(SectionStats const& _sectionStats) CATCH_OVERRIDE { - if (m_config->showDurations() == ShowDurations::Always) { - stream << getFormattedDuration(_sectionStats.durationInSeconds) << " s: " << _sectionStats.sectionInfo.name << std::endl; - } - } + if ( m_config->showDurations() == ShowDurations::Always ) + m_testCaseTimer.start(); + m_xml.ensureTagClosed(); + } - virtual void testRunEnded( TestRunStats const& _testRunStats ) { - printTotals( _testRunStats.totals ); - stream << '\n' << std::endl; - StreamingReporterBase::testRunEnded( _testRunStats ); + void XmlReporter::sectionStarting( SectionInfo const& sectionInfo ) { + StreamingReporterBase::sectionStarting( sectionInfo ); + if( m_sectionDepth++ > 0 ) { + m_xml.startElement( "Section" ) + .writeAttribute( "name", trim( sectionInfo.name ) ); + writeSourceInfo( sectionInfo.lineInfo ); + m_xml.ensureTagClosed(); } + } - private: - class AssertionPrinter { - void operator= ( AssertionPrinter const& ); - public: - AssertionPrinter( std::ostream& _stream, AssertionStats const& _stats, bool _printInfoMessages ) - : stream( _stream ) - , stats( _stats ) - , result( _stats.assertionResult ) - , messages( _stats.infoMessages ) - , itMessage( _stats.infoMessages.begin() ) - , printInfoMessages( _printInfoMessages ) - {} - - void print() { - printSourceInfo(); - - itMessage = messages.begin(); - - switch( result.getResultType() ) { - case ResultWas::Ok: - printResultType( Colour::ResultSuccess, passedString() ); - printOriginalExpression(); - printReconstructedExpression(); - if ( ! result.hasExpression() ) - printRemainingMessages( Colour::None ); - else - printRemainingMessages(); - break; - case ResultWas::ExpressionFailed: - if( result.isOk() ) - printResultType( Colour::ResultSuccess, failedString() + std::string( " - but was ok" ) ); - else - printResultType( Colour::Error, failedString() ); - printOriginalExpression(); - printReconstructedExpression(); - printRemainingMessages(); - break; - case ResultWas::ThrewException: - printResultType( Colour::Error, failedString() ); - printIssue( "unexpected exception with message:" ); - printMessage(); - printExpressionWas(); - printRemainingMessages(); - break; - case ResultWas::FatalErrorCondition: - printResultType( Colour::Error, failedString() ); - printIssue( "fatal error condition with message:" ); - printMessage(); - printExpressionWas(); - printRemainingMessages(); - break; - case ResultWas::DidntThrowException: - printResultType( Colour::Error, failedString() ); - printIssue( "expected exception, got none" ); - printExpressionWas(); - printRemainingMessages(); - break; - case ResultWas::Info: - printResultType( Colour::None, "info" ); - printMessage(); - printRemainingMessages(); - break; - case ResultWas::Warning: - printResultType( Colour::None, "warning" ); - printMessage(); - printRemainingMessages(); - break; - case ResultWas::ExplicitFailure: - printResultType( Colour::Error, failedString() ); - printIssue( "explicitly" ); - printRemainingMessages( Colour::None ); - break; - // These cases are here to prevent compiler warnings - case ResultWas::Unknown: - case ResultWas::FailureBit: - case ResultWas::Exception: - printResultType( Colour::Error, "** internal error **" ); - break; - } - } - - private: - // Colour::LightGrey + void XmlReporter::assertionStarting( AssertionInfo const& ) { } - static Colour::Code dimColour() { return Colour::FileName; } + bool XmlReporter::assertionEnded( AssertionStats const& assertionStats ) { -#ifdef CATCH_PLATFORM_MAC - static const char* failedString() { return "FAILED"; } - static const char* passedString() { return "PASSED"; } -#else - static const char* failedString() { return "failed"; } - static const char* passedString() { return "passed"; } -#endif + AssertionResult const& result = assertionStats.assertionResult; - void printSourceInfo() const { - Colour colourGuard( Colour::FileName ); - stream << result.getSourceInfo() << ':'; - } + bool includeResults = m_config->includeSuccessfulResults() || !result.isOk(); - void printResultType( Colour::Code colour, std::string const& passOrFail ) const { - if( !passOrFail.empty() ) { - { - Colour colourGuard( colour ); - stream << ' ' << passOrFail; - } - stream << ':'; + if( includeResults || result.getResultType() == ResultWas::Warning ) { + // Print any info messages in <Info> tags. + for( auto const& msg : assertionStats.infoMessages ) { + if( msg.type == ResultWas::Info && includeResults ) { + m_xml.scopedElement( "Info" ) + .writeText( msg.message ); + } else if ( msg.type == ResultWas::Warning ) { + m_xml.scopedElement( "Warning" ) + .writeText( msg.message ); } } + } - void printIssue( std::string const& issue ) const { - stream << ' ' << issue; - } - - void printExpressionWas() { - if( result.hasExpression() ) { - stream << ';'; - { - Colour colour( dimColour() ); - stream << " expression was:"; - } - printOriginalExpression(); - } - } + // Drop out if result was successful but we're not printing them. + if( !includeResults && result.getResultType() != ResultWas::Warning ) + return true; - void printOriginalExpression() const { - if( result.hasExpression() ) { - stream << ' ' << result.getExpression(); - } - } + // Print the expression if there is one. + if( result.hasExpression() ) { + m_xml.startElement( "Expression" ) + .writeAttribute( "success", result.succeeded() ) + .writeAttribute( "type", result.getTestMacroName() ); - void printReconstructedExpression() const { - if( result.hasExpandedExpression() ) { - { - Colour colour( dimColour() ); - stream << " for: "; - } - stream << result.getExpandedExpression(); - } - } + writeSourceInfo( result.getSourceInfo() ); - void printMessage() { - if ( itMessage != messages.end() ) { - stream << " '" << itMessage->message << '\''; - ++itMessage; - } - } + m_xml.scopedElement( "Original" ) + .writeText( result.getExpression() ); + m_xml.scopedElement( "Expanded" ) + .writeText( result.getExpandedExpression() ); + } - void printRemainingMessages( Colour::Code colour = dimColour() ) { - if ( itMessage == messages.end() ) - return; + // And... Print a result applicable to each result type. + switch( result.getResultType() ) { + case ResultWas::ThrewException: + m_xml.startElement( "Exception" ); + writeSourceInfo( result.getSourceInfo() ); + m_xml.writeText( result.getMessage() ); + m_xml.endElement(); + break; + case ResultWas::FatalErrorCondition: + m_xml.startElement( "FatalErrorCondition" ); + writeSourceInfo( result.getSourceInfo() ); + m_xml.writeText( result.getMessage() ); + m_xml.endElement(); + break; + case ResultWas::Info: + m_xml.scopedElement( "Info" ) + .writeText( result.getMessage() ); + break; + case ResultWas::Warning: + // Warning will already have been written + break; + case ResultWas::ExplicitFailure: + m_xml.startElement( "Failure" ); + writeSourceInfo( result.getSourceInfo() ); + m_xml.writeText( result.getMessage() ); + m_xml.endElement(); + break; + default: + break; + } - // using messages.end() directly yields compilation error: - std::vector<MessageInfo>::const_iterator itEnd = messages.end(); - const std::size_t N = static_cast<std::size_t>( std::distance( itMessage, itEnd ) ); + if( result.hasExpression() ) + m_xml.endElement(); - { - Colour colourGuard( colour ); - stream << " with " << pluralise( N, "message" ) << ':'; - } + return true; + } - for(; itMessage != itEnd; ) { - // If this assertion is a warning ignore any INFO messages - if( printInfoMessages || itMessage->type != ResultWas::Info ) { - stream << " '" << itMessage->message << '\''; - if ( ++itMessage != itEnd ) { - Colour colourGuard( dimColour() ); - stream << " and"; - } - } - } - } + void XmlReporter::sectionEnded( SectionStats const& sectionStats ) { + StreamingReporterBase::sectionEnded( sectionStats ); + if( --m_sectionDepth > 0 ) { + XmlWriter::ScopedElement e = m_xml.scopedElement( "OverallResults" ); + e.writeAttribute( "successes", sectionStats.assertions.passed ); + e.writeAttribute( "failures", sectionStats.assertions.failed ); + e.writeAttribute( "expectedFailures", sectionStats.assertions.failedButOk ); - private: - std::ostream& stream; - AssertionStats const& stats; - AssertionResult const& result; - std::vector<MessageInfo> messages; - std::vector<MessageInfo>::const_iterator itMessage; - bool printInfoMessages; - }; + if ( m_config->showDurations() == ShowDurations::Always ) + e.writeAttribute( "durationInSeconds", sectionStats.durationInSeconds ); - // Colour, message variants: - // - white: No tests ran. - // - red: Failed [both/all] N test cases, failed [both/all] M assertions. - // - white: Passed [both/all] N test cases (no assertions). - // - red: Failed N tests cases, failed M assertions. - // - green: Passed [both/all] N tests cases with M assertions. - - std::string bothOrAll( std::size_t count ) const { - return count == 1 ? std::string() : count == 2 ? "both " : "all " ; - } - - void printTotals( const Totals& totals ) const { - if( totals.testCases.total() == 0 ) { - stream << "No tests ran."; - } - else if( totals.testCases.failed == totals.testCases.total() ) { - Colour colour( Colour::ResultError ); - const std::string qualify_assertions_failed = - totals.assertions.failed == totals.assertions.total() ? - bothOrAll( totals.assertions.failed ) : std::string(); - stream << - "Failed " << bothOrAll( totals.testCases.failed ) - << pluralise( totals.testCases.failed, "test case" ) << ", " - "failed " << qualify_assertions_failed << - pluralise( totals.assertions.failed, "assertion" ) << '.'; - } - else if( totals.assertions.total() == 0 ) { - stream << - "Passed " << bothOrAll( totals.testCases.total() ) - << pluralise( totals.testCases.total(), "test case" ) - << " (no assertions)."; - } - else if( totals.assertions.failed ) { - Colour colour( Colour::ResultError ); - stream << - "Failed " << pluralise( totals.testCases.failed, "test case" ) << ", " - "failed " << pluralise( totals.assertions.failed, "assertion" ) << '.'; - } - else { - Colour colour( Colour::ResultSuccess ); - stream << - "Passed " << bothOrAll( totals.testCases.passed ) - << pluralise( totals.testCases.passed, "test case" ) << - " with " << pluralise( totals.assertions.passed, "assertion" ) << '.'; - } + m_xml.endElement(); } - }; + } - INTERNAL_CATCH_REGISTER_REPORTER( "compact", CompactReporter ) + void XmlReporter::testCaseEnded( TestCaseStats const& testCaseStats ) { + StreamingReporterBase::testCaseEnded( testCaseStats ); + XmlWriter::ScopedElement e = m_xml.scopedElement( "OverallResult" ); + e.writeAttribute( "success", testCaseStats.totals.assertions.allOk() ); + + if ( m_config->showDurations() == ShowDurations::Always ) + e.writeAttribute( "durationInSeconds", m_testCaseTimer.getElapsedSeconds() ); + + if( !testCaseStats.stdOut.empty() ) + m_xml.scopedElement( "StdOut" ).writeText( trim( testCaseStats.stdOut ), XmlFormatting::Newline ); + if( !testCaseStats.stdErr.empty() ) + m_xml.scopedElement( "StdErr" ).writeText( trim( testCaseStats.stdErr ), XmlFormatting::Newline ); + + m_xml.endElement(); + } + + void XmlReporter::testGroupEnded( TestGroupStats const& testGroupStats ) { + StreamingReporterBase::testGroupEnded( testGroupStats ); + // TODO: Check testGroupStats.aborting and act accordingly. + m_xml.scopedElement( "OverallResults" ) + .writeAttribute( "successes", testGroupStats.totals.assertions.passed ) + .writeAttribute( "failures", testGroupStats.totals.assertions.failed ) + .writeAttribute( "expectedFailures", testGroupStats.totals.assertions.failedButOk ); + m_xml.scopedElement( "OverallResultsCases") + .writeAttribute( "successes", testGroupStats.totals.testCases.passed ) + .writeAttribute( "failures", testGroupStats.totals.testCases.failed ) + .writeAttribute( "expectedFailures", testGroupStats.totals.testCases.failedButOk ); + m_xml.endElement(); + } + + void XmlReporter::testRunEnded( TestRunStats const& testRunStats ) { + StreamingReporterBase::testRunEnded( testRunStats ); + m_xml.scopedElement( "OverallResults" ) + .writeAttribute( "successes", testRunStats.totals.assertions.passed ) + .writeAttribute( "failures", testRunStats.totals.assertions.failed ) + .writeAttribute( "expectedFailures", testRunStats.totals.assertions.failedButOk ); + m_xml.scopedElement( "OverallResultsCases") + .writeAttribute( "successes", testRunStats.totals.testCases.passed ) + .writeAttribute( "failures", testRunStats.totals.testCases.failed ) + .writeAttribute( "expectedFailures", testRunStats.totals.testCases.failedButOk ); + m_xml.endElement(); + } + +#if defined(CATCH_CONFIG_ENABLE_BENCHMARKING) + void XmlReporter::benchmarkPreparing(std::string const& name) { + m_xml.startElement("BenchmarkResults") + .writeAttribute("name", name); + } + + void XmlReporter::benchmarkStarting(BenchmarkInfo const &info) { + m_xml.writeAttribute("samples", info.samples) + .writeAttribute("resamples", info.resamples) + .writeAttribute("iterations", info.iterations) + .writeAttribute("clockResolution", info.clockResolution) + .writeAttribute("estimatedDuration", info.estimatedDuration) + .writeComment("All values in nano seconds"); + } + + void XmlReporter::benchmarkEnded(BenchmarkStats<> const& benchmarkStats) { + m_xml.startElement("mean") + .writeAttribute("value", benchmarkStats.mean.point.count()) + .writeAttribute("lowerBound", benchmarkStats.mean.lower_bound.count()) + .writeAttribute("upperBound", benchmarkStats.mean.upper_bound.count()) + .writeAttribute("ci", benchmarkStats.mean.confidence_interval); + m_xml.endElement(); + m_xml.startElement("standardDeviation") + .writeAttribute("value", benchmarkStats.standardDeviation.point.count()) + .writeAttribute("lowerBound", benchmarkStats.standardDeviation.lower_bound.count()) + .writeAttribute("upperBound", benchmarkStats.standardDeviation.upper_bound.count()) + .writeAttribute("ci", benchmarkStats.standardDeviation.confidence_interval); + m_xml.endElement(); + m_xml.startElement("outliers") + .writeAttribute("variance", benchmarkStats.outlierVariance) + .writeAttribute("lowMild", benchmarkStats.outliers.low_mild) + .writeAttribute("lowSevere", benchmarkStats.outliers.low_severe) + .writeAttribute("highMild", benchmarkStats.outliers.high_mild) + .writeAttribute("highSevere", benchmarkStats.outliers.high_severe); + m_xml.endElement(); + m_xml.endElement(); + } + + void XmlReporter::benchmarkFailed(std::string const &error) { + m_xml.scopedElement("failed"). + writeAttribute("message", error); + m_xml.endElement(); + } +#endif // CATCH_CONFIG_ENABLE_BENCHMARKING + + CATCH_REGISTER_REPORTER( "xml", XmlReporter ) } // 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() {} - ITestCase::~ITestCase() {} - ITestCaseRegistry::~ITestCaseRegistry() {} - IRegistryHub::~IRegistryHub() {} - IMutableRegistryHub::~IMutableRegistryHub() {} - IExceptionTranslator::~IExceptionTranslator() {} - IExceptionTranslatorRegistry::~IExceptionTranslatorRegistry() {} - IReporter::~IReporter() {} - IReporterFactory::~IReporterFactory() {} - IReporterRegistry::~IReporterRegistry() {} - IStreamingReporter::~IStreamingReporter() {} - AssertionStats::~AssertionStats() {} - SectionStats::~SectionStats() {} - TestCaseStats::~TestCaseStats() {} - TestGroupStats::~TestGroupStats() {} - TestRunStats::~TestRunStats() {} - CumulativeReporterBase::SectionNode::~SectionNode() {} - CumulativeReporterBase::~CumulativeReporterBase() {} - - StreamingReporterBase::~StreamingReporterBase() {} - ConsoleReporter::~ConsoleReporter() {} - CompactReporter::~CompactReporter() {} - IRunner::~IRunner() {} - IMutableContext::~IMutableContext() {} - IConfig::~IConfig() {} - XmlReporter::~XmlReporter() {} - JunitReporter::~JunitReporter() {} - TestRegistry::~TestRegistry() {} - FreeFunctionTestCase::~FreeFunctionTestCase() {} - IGeneratorInfo::~IGeneratorInfo() {} - IGeneratorsForTest::~IGeneratorsForTest() {} - WildcardPattern::~WildcardPattern() {} - TestSpec::Pattern::~Pattern() {} - TestSpec::NamePattern::~NamePattern() {} - TestSpec::TagPattern::~TagPattern() {} - TestSpec::ExcludedPattern::~ExcludedPattern() {} - Matchers::Impl::MatcherUntypedBase::~MatcherUntypedBase() {} - - void Config::dummy() {} +#if defined(_MSC_VER) +#pragma warning(pop) +#endif +// end catch_reporter_xml.cpp - namespace TestCaseTracking { - ITracker::~ITracker() {} - TrackerBase::~TrackerBase() {} - SectionTracker::~SectionTracker() {} - IndexTracker::~IndexTracker() {} - } +namespace Catch { + LeakDetector leakDetector; } #ifdef __clang__ #pragma clang diagnostic pop #endif +// end catch_impl.hpp #endif #ifdef CATCH_CONFIG_MAIN -// #included from: internal/catch_default_main.hpp -#define TWOBLUECUBES_CATCH_DEFAULT_MAIN_HPP_INCLUDED +// start catch_default_main.hpp #ifndef __OBJC__ -#if defined(WIN32) && defined(_UNICODE) && !defined(DO_NOT_USE_WMAIN) +#ifndef CATCH_INTERNAL_CDECL +#ifdef _MSC_VER +#define CATCH_INTERNAL_CDECL __cdecl +#else +#define CATCH_INTERNAL_CDECL +#endif +#endif + +#if defined(CATCH_CONFIG_WCHAR) && defined(CATCH_PLATFORM_WINDOWS) && defined(_UNICODE) && !defined(DO_NOT_USE_WMAIN) // Standard C/C++ Win32 Unicode wmain entry point -extern "C" int wmain (int argc, wchar_t * argv[], wchar_t * []) { +extern "C" int CATCH_INTERNAL_CDECL wmain (int argc, wchar_t * argv[], wchar_t * []) { #else // Standard C/C++ main entry point -int main (int argc, char * argv[]) { +int CATCH_INTERNAL_CDECL main (int argc, char * argv[]) { #endif - int result = Catch::Session().run( argc, argv ); - return ( result < 0xff ? result : 0xff ); + return Catch::Session().run( argc, argv ); } #else // __OBJC__ @@ -11483,197 +17552,413 @@ int main (int argc, char * const argv[]) { #endif Catch::registerTestMethods(); - int result = Catch::Session().run( argc, (char* const*)argv ); + int result = Catch::Session().run( argc, (char**)argv ); #if !CATCH_ARC_ENABLED [pool drain]; #endif - return ( result < 0xff ? result : 0xff ); + return result; } #endif // __OBJC__ +// end catch_default_main.hpp #endif +#if !defined(CATCH_CONFIG_IMPL_ONLY) + #ifdef CLARA_CONFIG_MAIN_NOT_DEFINED # undef CLARA_CONFIG_MAIN #endif +#if !defined(CATCH_CONFIG_DISABLE) ////// - // If this config identifier is defined then all CATCH macros are prefixed with CATCH_ #ifdef CATCH_CONFIG_PREFIX_ALL -#if defined(CATCH_CONFIG_FAST_COMPILE) -#define CATCH_REQUIRE( expr ) INTERNAL_CATCH_TEST_NO_TRY( "CATCH_REQUIRE", Catch::ResultDisposition::Normal, expr ) -#define CATCH_REQUIRE_FALSE( expr ) INTERNAL_CATCH_TEST_NO_TRY( "CATCH_REQUIRE_FALSE", Catch::ResultDisposition::Normal | Catch::ResultDisposition::FalseTest, expr ) -#else -#define CATCH_REQUIRE( expr ) INTERNAL_CATCH_TEST( "CATCH_REQUIRE", Catch::ResultDisposition::Normal, expr ) -#define CATCH_REQUIRE_FALSE( expr ) INTERNAL_CATCH_TEST( "CATCH_REQUIRE_FALSE", Catch::ResultDisposition::Normal | Catch::ResultDisposition::FalseTest, expr ) -#endif +#define CATCH_REQUIRE( ... ) INTERNAL_CATCH_TEST( "CATCH_REQUIRE", Catch::ResultDisposition::Normal, __VA_ARGS__ ) +#define CATCH_REQUIRE_FALSE( ... ) INTERNAL_CATCH_TEST( "CATCH_REQUIRE_FALSE", Catch::ResultDisposition::Normal | Catch::ResultDisposition::FalseTest, __VA_ARGS__ ) -#define CATCH_REQUIRE_THROWS( expr ) INTERNAL_CATCH_THROWS( "CATCH_REQUIRE_THROWS", Catch::ResultDisposition::Normal, "", expr ) +#define CATCH_REQUIRE_THROWS( ... ) INTERNAL_CATCH_THROWS( "CATCH_REQUIRE_THROWS", Catch::ResultDisposition::Normal, __VA_ARGS__ ) #define CATCH_REQUIRE_THROWS_AS( expr, exceptionType ) INTERNAL_CATCH_THROWS_AS( "CATCH_REQUIRE_THROWS_AS", exceptionType, Catch::ResultDisposition::Normal, expr ) -#define CATCH_REQUIRE_THROWS_WITH( expr, matcher ) INTERNAL_CATCH_THROWS( "CATCH_REQUIRE_THROWS_WITH", Catch::ResultDisposition::Normal, matcher, expr ) -#define CATCH_REQUIRE_NOTHROW( expr ) INTERNAL_CATCH_NO_THROW( "CATCH_REQUIRE_NOTHROW", Catch::ResultDisposition::Normal, expr ) - -#define CATCH_CHECK( expr ) INTERNAL_CATCH_TEST( "CATCH_CHECK", Catch::ResultDisposition::ContinueOnFailure, expr ) -#define CATCH_CHECK_FALSE( expr ) INTERNAL_CATCH_TEST( "CATCH_CHECK_FALSE", Catch::ResultDisposition::ContinueOnFailure | Catch::ResultDisposition::FalseTest, expr ) -#define CATCH_CHECKED_IF( expr ) INTERNAL_CATCH_IF( "CATCH_CHECKED_IF", Catch::ResultDisposition::ContinueOnFailure, expr ) -#define CATCH_CHECKED_ELSE( expr ) INTERNAL_CATCH_ELSE( "CATCH_CHECKED_ELSE", Catch::ResultDisposition::ContinueOnFailure, expr ) -#define CATCH_CHECK_NOFAIL( expr ) INTERNAL_CATCH_TEST( "CATCH_CHECK_NOFAIL", Catch::ResultDisposition::ContinueOnFailure | Catch::ResultDisposition::SuppressFail, expr ) - -#define CATCH_CHECK_THROWS( expr ) INTERNAL_CATCH_THROWS( "CATCH_CHECK_THROWS", Catch::ResultDisposition::ContinueOnFailure, "", expr ) +#define CATCH_REQUIRE_THROWS_WITH( expr, matcher ) INTERNAL_CATCH_THROWS_STR_MATCHES( "CATCH_REQUIRE_THROWS_WITH", Catch::ResultDisposition::Normal, matcher, expr ) +#if !defined(CATCH_CONFIG_DISABLE_MATCHERS) +#define CATCH_REQUIRE_THROWS_MATCHES( expr, exceptionType, matcher ) INTERNAL_CATCH_THROWS_MATCHES( "CATCH_REQUIRE_THROWS_MATCHES", exceptionType, Catch::ResultDisposition::Normal, matcher, expr ) +#endif// CATCH_CONFIG_DISABLE_MATCHERS +#define CATCH_REQUIRE_NOTHROW( ... ) INTERNAL_CATCH_NO_THROW( "CATCH_REQUIRE_NOTHROW", Catch::ResultDisposition::Normal, __VA_ARGS__ ) + +#define CATCH_CHECK( ... ) INTERNAL_CATCH_TEST( "CATCH_CHECK", Catch::ResultDisposition::ContinueOnFailure, __VA_ARGS__ ) +#define CATCH_CHECK_FALSE( ... ) INTERNAL_CATCH_TEST( "CATCH_CHECK_FALSE", Catch::ResultDisposition::ContinueOnFailure | Catch::ResultDisposition::FalseTest, __VA_ARGS__ ) +#define CATCH_CHECKED_IF( ... ) INTERNAL_CATCH_IF( "CATCH_CHECKED_IF", Catch::ResultDisposition::ContinueOnFailure, __VA_ARGS__ ) +#define CATCH_CHECKED_ELSE( ... ) INTERNAL_CATCH_ELSE( "CATCH_CHECKED_ELSE", Catch::ResultDisposition::ContinueOnFailure, __VA_ARGS__ ) +#define CATCH_CHECK_NOFAIL( ... ) INTERNAL_CATCH_TEST( "CATCH_CHECK_NOFAIL", Catch::ResultDisposition::ContinueOnFailure | Catch::ResultDisposition::SuppressFail, __VA_ARGS__ ) + +#define CATCH_CHECK_THROWS( ... ) INTERNAL_CATCH_THROWS( "CATCH_CHECK_THROWS", Catch::ResultDisposition::ContinueOnFailure, __VA_ARGS__ ) #define CATCH_CHECK_THROWS_AS( expr, exceptionType ) INTERNAL_CATCH_THROWS_AS( "CATCH_CHECK_THROWS_AS", exceptionType, Catch::ResultDisposition::ContinueOnFailure, expr ) -#define CATCH_CHECK_THROWS_WITH( expr, matcher ) INTERNAL_CATCH_THROWS( "CATCH_CHECK_THROWS_WITH", Catch::ResultDisposition::ContinueOnFailure, matcher, expr ) -#define CATCH_CHECK_NOTHROW( expr ) INTERNAL_CATCH_NO_THROW( "CATCH_CHECK_NOTHROW", Catch::ResultDisposition::ContinueOnFailure, expr ) +#define CATCH_CHECK_THROWS_WITH( expr, matcher ) INTERNAL_CATCH_THROWS_STR_MATCHES( "CATCH_CHECK_THROWS_WITH", Catch::ResultDisposition::ContinueOnFailure, matcher, expr ) +#if !defined(CATCH_CONFIG_DISABLE_MATCHERS) +#define CATCH_CHECK_THROWS_MATCHES( expr, exceptionType, matcher ) INTERNAL_CATCH_THROWS_MATCHES( "CATCH_CHECK_THROWS_MATCHES", exceptionType, Catch::ResultDisposition::ContinueOnFailure, matcher, expr ) +#endif // CATCH_CONFIG_DISABLE_MATCHERS +#define CATCH_CHECK_NOTHROW( ... ) INTERNAL_CATCH_NO_THROW( "CATCH_CHECK_NOTHROW", Catch::ResultDisposition::ContinueOnFailure, __VA_ARGS__ ) +#if !defined(CATCH_CONFIG_DISABLE_MATCHERS) #define CATCH_CHECK_THAT( arg, matcher ) INTERNAL_CHECK_THAT( "CATCH_CHECK_THAT", matcher, Catch::ResultDisposition::ContinueOnFailure, arg ) -#if defined(CATCH_CONFIG_FAST_COMPILE) -#define CATCH_REQUIRE_THAT( arg, matcher ) INTERNAL_CHECK_THAT_NO_TRY( "CATCH_REQUIRE_THAT", matcher, Catch::ResultDisposition::Normal, arg ) -#else #define CATCH_REQUIRE_THAT( arg, matcher ) INTERNAL_CHECK_THAT( "CATCH_REQUIRE_THAT", matcher, Catch::ResultDisposition::Normal, arg ) -#endif +#endif // CATCH_CONFIG_DISABLE_MATCHERS #define CATCH_INFO( msg ) INTERNAL_CATCH_INFO( "CATCH_INFO", msg ) +#define CATCH_UNSCOPED_INFO( msg ) INTERNAL_CATCH_UNSCOPED_INFO( "CATCH_UNSCOPED_INFO", msg ) #define CATCH_WARN( msg ) INTERNAL_CATCH_MSG( "CATCH_WARN", Catch::ResultWas::Warning, Catch::ResultDisposition::ContinueOnFailure, msg ) -#define CATCH_SCOPED_INFO( msg ) INTERNAL_CATCH_INFO( "CATCH_INFO", msg ) -#define CATCH_CAPTURE( msg ) INTERNAL_CATCH_INFO( "CATCH_CAPTURE", #msg " := " << Catch::toString(msg) ) -#define CATCH_SCOPED_CAPTURE( msg ) INTERNAL_CATCH_INFO( "CATCH_CAPTURE", #msg " := " << Catch::toString(msg) ) - -#ifdef CATCH_CONFIG_VARIADIC_MACROS - #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( Function, ... ) INTERNAL_CATCH_REGISTER_TESTCASE( Function, __VA_ARGS__ ) - #define CATCH_SECTION( ... ) INTERNAL_CATCH_SECTION( __VA_ARGS__ ) - #define CATCH_FAIL( ... ) INTERNAL_CATCH_MSG( "CATCH_FAIL", Catch::ResultWas::ExplicitFailure, Catch::ResultDisposition::Normal, __VA_ARGS__ ) - #define CATCH_FAIL_CHECK( ... ) INTERNAL_CATCH_MSG( "CATCH_FAIL_CHECK", Catch::ResultWas::ExplicitFailure, Catch::ResultDisposition::ContinueOnFailure, __VA_ARGS__ ) - #define CATCH_SUCCEED( ... ) INTERNAL_CATCH_MSG( "CATCH_SUCCEED", Catch::ResultWas::Ok, Catch::ResultDisposition::ContinueOnFailure, __VA_ARGS__ ) +#define CATCH_CAPTURE( ... ) INTERNAL_CATCH_CAPTURE( INTERNAL_CATCH_UNIQUE_NAME(capturer), "CATCH_CAPTURE",__VA_ARGS__ ) + +#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( Function, ... ) INTERNAL_CATCH_REGISTER_TESTCASE( Function, __VA_ARGS__ ) +#define CATCH_SECTION( ... ) INTERNAL_CATCH_SECTION( __VA_ARGS__ ) +#define CATCH_DYNAMIC_SECTION( ... ) INTERNAL_CATCH_DYNAMIC_SECTION( __VA_ARGS__ ) +#define CATCH_FAIL( ... ) INTERNAL_CATCH_MSG( "CATCH_FAIL", Catch::ResultWas::ExplicitFailure, Catch::ResultDisposition::Normal, __VA_ARGS__ ) +#define CATCH_FAIL_CHECK( ... ) INTERNAL_CATCH_MSG( "CATCH_FAIL_CHECK", Catch::ResultWas::ExplicitFailure, Catch::ResultDisposition::ContinueOnFailure, __VA_ARGS__ ) +#define CATCH_SUCCEED( ... ) INTERNAL_CATCH_MSG( "CATCH_SUCCEED", Catch::ResultWas::Ok, Catch::ResultDisposition::ContinueOnFailure, __VA_ARGS__ ) + +#define CATCH_ANON_TEST_CASE() INTERNAL_CATCH_TESTCASE() + +#ifndef CATCH_CONFIG_TRADITIONAL_MSVC_PREPROCESSOR +#define CATCH_TEMPLATE_TEST_CASE( ... ) INTERNAL_CATCH_TEMPLATE_TEST_CASE( __VA_ARGS__ ) +#define CATCH_TEMPLATE_TEST_CASE_SIG( ... ) INTERNAL_CATCH_TEMPLATE_TEST_CASE_SIG( __VA_ARGS__ ) +#define CATCH_TEMPLATE_TEST_CASE_METHOD( className, ... ) INTERNAL_CATCH_TEMPLATE_TEST_CASE_METHOD( className, __VA_ARGS__ ) +#define CATCH_TEMPLATE_TEST_CASE_METHOD_SIG( className, ... ) INTERNAL_CATCH_TEMPLATE_TEST_CASE_METHOD_SIG( className, __VA_ARGS__ ) +#define CATCH_TEMPLATE_PRODUCT_TEST_CASE( ... ) INTERNAL_CATCH_TEMPLATE_PRODUCT_TEST_CASE( __VA_ARGS__ ) +#define CATCH_TEMPLATE_PRODUCT_TEST_CASE_SIG( ... ) INTERNAL_CATCH_TEMPLATE_PRODUCT_TEST_CASE_SIG( __VA_ARGS__ ) +#define CATCH_TEMPLATE_PRODUCT_TEST_CASE_METHOD( className, ... ) INTERNAL_CATCH_TEMPLATE_PRODUCT_TEST_CASE_METHOD( className, __VA_ARGS__ ) +#define CATCH_TEMPLATE_PRODUCT_TEST_CASE_METHOD_SIG( className, ... ) INTERNAL_CATCH_TEMPLATE_PRODUCT_TEST_CASE_METHOD_SIG( className, __VA_ARGS__ ) #else - #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_FAIL", Catch::ResultWas::ExplicitFailure, Catch::ResultDisposition::Normal, msg ) - #define CATCH_FAIL_CHECK( msg ) INTERNAL_CATCH_MSG( "CATCH_FAIL_CHECK", Catch::ResultWas::ExplicitFailure, Catch::ResultDisposition::ContinueOnFailure, msg ) - #define CATCH_SUCCEED( msg ) INTERNAL_CATCH_MSG( "CATCH_SUCCEED", Catch::ResultWas::Ok, Catch::ResultDisposition::ContinueOnFailure, msg ) +#define CATCH_TEMPLATE_TEST_CASE( ... ) INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_TEST_CASE( __VA_ARGS__ ) ) +#define CATCH_TEMPLATE_TEST_CASE_SIG( ... ) INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_TEST_CASE_SIG( __VA_ARGS__ ) ) +#define CATCH_TEMPLATE_TEST_CASE_METHOD( className, ... ) INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_TEST_CASE_METHOD( className, __VA_ARGS__ ) ) +#define CATCH_TEMPLATE_TEST_CASE_METHOD_SIG( className, ... ) INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_TEST_CASE_METHOD_SIG( className, __VA_ARGS__ ) ) +#define CATCH_TEMPLATE_PRODUCT_TEST_CASE( ... ) INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_PRODUCT_TEST_CASE( __VA_ARGS__ ) ) +#define CATCH_TEMPLATE_PRODUCT_TEST_CASE_SIG( ... ) INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_PRODUCT_TEST_CASE_SIG( __VA_ARGS__ ) ) +#define CATCH_TEMPLATE_PRODUCT_TEST_CASE_METHOD( className, ... ) INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_PRODUCT_TEST_CASE_METHOD( className, __VA_ARGS__ ) ) +#define CATCH_TEMPLATE_PRODUCT_TEST_CASE_METHOD_SIG( className, ... ) INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_PRODUCT_TEST_CASE_METHOD_SIG( className, __VA_ARGS__ ) ) #endif -#define CATCH_ANON_TEST_CASE() INTERNAL_CATCH_TESTCASE( "", "" ) - -#define CATCH_REGISTER_REPORTER( name, reporterType ) INTERNAL_CATCH_REGISTER_REPORTER( name, reporterType ) -#define CATCH_REGISTER_LEGACY_REPORTER( name, reporterType ) INTERNAL_CATCH_REGISTER_LEGACY_REPORTER( name, reporterType ) -#define CATCH_GENERATE( expr) INTERNAL_CATCH_GENERATE( expr ) +#if !defined(CATCH_CONFIG_RUNTIME_STATIC_REQUIRE) +#define CATCH_STATIC_REQUIRE( ... ) static_assert( __VA_ARGS__ , #__VA_ARGS__ ); CATCH_SUCCEED( #__VA_ARGS__ ) +#define CATCH_STATIC_REQUIRE_FALSE( ... ) static_assert( !(__VA_ARGS__), "!(" #__VA_ARGS__ ")" ); CATCH_SUCCEED( #__VA_ARGS__ ) +#else +#define CATCH_STATIC_REQUIRE( ... ) CATCH_REQUIRE( __VA_ARGS__ ) +#define CATCH_STATIC_REQUIRE_FALSE( ... ) CATCH_REQUIRE_FALSE( __VA_ARGS__ ) +#endif // "BDD-style" convenience wrappers -#ifdef CATCH_CONFIG_VARIADIC_MACROS #define CATCH_SCENARIO( ... ) CATCH_TEST_CASE( "Scenario: " __VA_ARGS__ ) #define CATCH_SCENARIO_METHOD( className, ... ) INTERNAL_CATCH_TEST_CASE_METHOD( className, "Scenario: " __VA_ARGS__ ) -#else -#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( 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, "" ) +#define CATCH_GIVEN( desc ) INTERNAL_CATCH_DYNAMIC_SECTION( " Given: " << desc ) +#define CATCH_AND_GIVEN( desc ) INTERNAL_CATCH_DYNAMIC_SECTION( "And given: " << desc ) +#define CATCH_WHEN( desc ) INTERNAL_CATCH_DYNAMIC_SECTION( " When: " << desc ) +#define CATCH_AND_WHEN( desc ) INTERNAL_CATCH_DYNAMIC_SECTION( " And when: " << desc ) +#define CATCH_THEN( desc ) INTERNAL_CATCH_DYNAMIC_SECTION( " Then: " << desc ) +#define CATCH_AND_THEN( desc ) INTERNAL_CATCH_DYNAMIC_SECTION( " And: " << desc ) + +#if defined(CATCH_CONFIG_ENABLE_BENCHMARKING) +#define CATCH_BENCHMARK(...) \ + INTERNAL_CATCH_BENCHMARK(INTERNAL_CATCH_UNIQUE_NAME(C_A_T_C_H_B_E_N_C_H_), INTERNAL_CATCH_GET_1_ARG(__VA_ARGS__,,), INTERNAL_CATCH_GET_2_ARG(__VA_ARGS__,,)) +#define CATCH_BENCHMARK_ADVANCED(name) \ + INTERNAL_CATCH_BENCHMARK_ADVANCED(INTERNAL_CATCH_UNIQUE_NAME(C_A_T_C_H_B_E_N_C_H_), name) +#endif // CATCH_CONFIG_ENABLE_BENCHMARKING // If CATCH_CONFIG_PREFIX_ALL is not defined then the CATCH_ prefix is not required #else -#if defined(CATCH_CONFIG_FAST_COMPILE) -#define REQUIRE( expr ) INTERNAL_CATCH_TEST_NO_TRY( "REQUIRE", Catch::ResultDisposition::Normal, expr ) -#define REQUIRE_FALSE( expr ) INTERNAL_CATCH_TEST_NO_TRY( "REQUIRE_FALSE", Catch::ResultDisposition::Normal | Catch::ResultDisposition::FalseTest, expr ) - -#else -#define REQUIRE( expr ) INTERNAL_CATCH_TEST( "REQUIRE", Catch::ResultDisposition::Normal, expr ) -#define REQUIRE_FALSE( expr ) INTERNAL_CATCH_TEST( "REQUIRE_FALSE", Catch::ResultDisposition::Normal | Catch::ResultDisposition::FalseTest, expr ) -#endif +#define REQUIRE( ... ) INTERNAL_CATCH_TEST( "REQUIRE", Catch::ResultDisposition::Normal, __VA_ARGS__ ) +#define REQUIRE_FALSE( ... ) INTERNAL_CATCH_TEST( "REQUIRE_FALSE", Catch::ResultDisposition::Normal | Catch::ResultDisposition::FalseTest, __VA_ARGS__ ) -#define REQUIRE_THROWS( expr ) INTERNAL_CATCH_THROWS( "REQUIRE_THROWS", Catch::ResultDisposition::Normal, "", expr ) +#define REQUIRE_THROWS( ... ) INTERNAL_CATCH_THROWS( "REQUIRE_THROWS", Catch::ResultDisposition::Normal, __VA_ARGS__ ) #define REQUIRE_THROWS_AS( expr, exceptionType ) INTERNAL_CATCH_THROWS_AS( "REQUIRE_THROWS_AS", exceptionType, Catch::ResultDisposition::Normal, expr ) -#define REQUIRE_THROWS_WITH( expr, matcher ) INTERNAL_CATCH_THROWS( "REQUIRE_THROWS_WITH", Catch::ResultDisposition::Normal, matcher, expr ) -#define REQUIRE_NOTHROW( expr ) INTERNAL_CATCH_NO_THROW( "REQUIRE_NOTHROW", Catch::ResultDisposition::Normal, expr ) - -#define CHECK( expr ) INTERNAL_CATCH_TEST( "CHECK", Catch::ResultDisposition::ContinueOnFailure, expr ) -#define CHECK_FALSE( expr ) INTERNAL_CATCH_TEST( "CHECK_FALSE", Catch::ResultDisposition::ContinueOnFailure | Catch::ResultDisposition::FalseTest, expr ) -#define CHECKED_IF( expr ) INTERNAL_CATCH_IF( "CHECKED_IF", Catch::ResultDisposition::ContinueOnFailure, expr ) -#define CHECKED_ELSE( expr ) INTERNAL_CATCH_ELSE( "CHECKED_ELSE", Catch::ResultDisposition::ContinueOnFailure, expr ) -#define CHECK_NOFAIL( expr ) INTERNAL_CATCH_TEST( "CHECK_NOFAIL", Catch::ResultDisposition::ContinueOnFailure | Catch::ResultDisposition::SuppressFail, expr ) - -#define CHECK_THROWS( expr ) INTERNAL_CATCH_THROWS( "CHECK_THROWS", Catch::ResultDisposition::ContinueOnFailure, "", expr ) +#define REQUIRE_THROWS_WITH( expr, matcher ) INTERNAL_CATCH_THROWS_STR_MATCHES( "REQUIRE_THROWS_WITH", Catch::ResultDisposition::Normal, matcher, expr ) +#if !defined(CATCH_CONFIG_DISABLE_MATCHERS) +#define REQUIRE_THROWS_MATCHES( expr, exceptionType, matcher ) INTERNAL_CATCH_THROWS_MATCHES( "REQUIRE_THROWS_MATCHES", exceptionType, Catch::ResultDisposition::Normal, matcher, expr ) +#endif // CATCH_CONFIG_DISABLE_MATCHERS +#define REQUIRE_NOTHROW( ... ) INTERNAL_CATCH_NO_THROW( "REQUIRE_NOTHROW", Catch::ResultDisposition::Normal, __VA_ARGS__ ) + +#define CHECK( ... ) INTERNAL_CATCH_TEST( "CHECK", Catch::ResultDisposition::ContinueOnFailure, __VA_ARGS__ ) +#define CHECK_FALSE( ... ) INTERNAL_CATCH_TEST( "CHECK_FALSE", Catch::ResultDisposition::ContinueOnFailure | Catch::ResultDisposition::FalseTest, __VA_ARGS__ ) +#define CHECKED_IF( ... ) INTERNAL_CATCH_IF( "CHECKED_IF", Catch::ResultDisposition::ContinueOnFailure, __VA_ARGS__ ) +#define CHECKED_ELSE( ... ) INTERNAL_CATCH_ELSE( "CHECKED_ELSE", Catch::ResultDisposition::ContinueOnFailure, __VA_ARGS__ ) +#define CHECK_NOFAIL( ... ) INTERNAL_CATCH_TEST( "CHECK_NOFAIL", Catch::ResultDisposition::ContinueOnFailure | Catch::ResultDisposition::SuppressFail, __VA_ARGS__ ) + +#define CHECK_THROWS( ... ) INTERNAL_CATCH_THROWS( "CHECK_THROWS", Catch::ResultDisposition::ContinueOnFailure, __VA_ARGS__ ) #define CHECK_THROWS_AS( expr, exceptionType ) INTERNAL_CATCH_THROWS_AS( "CHECK_THROWS_AS", exceptionType, Catch::ResultDisposition::ContinueOnFailure, expr ) -#define CHECK_THROWS_WITH( expr, matcher ) INTERNAL_CATCH_THROWS( "CHECK_THROWS_WITH", Catch::ResultDisposition::ContinueOnFailure, matcher, expr ) -#define CHECK_NOTHROW( expr ) INTERNAL_CATCH_NO_THROW( "CHECK_NOTHROW", Catch::ResultDisposition::ContinueOnFailure, expr ) +#define CHECK_THROWS_WITH( expr, matcher ) INTERNAL_CATCH_THROWS_STR_MATCHES( "CHECK_THROWS_WITH", Catch::ResultDisposition::ContinueOnFailure, matcher, expr ) +#if !defined(CATCH_CONFIG_DISABLE_MATCHERS) +#define CHECK_THROWS_MATCHES( expr, exceptionType, matcher ) INTERNAL_CATCH_THROWS_MATCHES( "CHECK_THROWS_MATCHES", exceptionType, Catch::ResultDisposition::ContinueOnFailure, matcher, expr ) +#endif // CATCH_CONFIG_DISABLE_MATCHERS +#define CHECK_NOTHROW( ... ) INTERNAL_CATCH_NO_THROW( "CHECK_NOTHROW", Catch::ResultDisposition::ContinueOnFailure, __VA_ARGS__ ) +#if !defined(CATCH_CONFIG_DISABLE_MATCHERS) #define CHECK_THAT( arg, matcher ) INTERNAL_CHECK_THAT( "CHECK_THAT", matcher, Catch::ResultDisposition::ContinueOnFailure, arg ) -#if defined(CATCH_CONFIG_FAST_COMPILE) -#define REQUIRE_THAT( arg, matcher ) INTERNAL_CHECK_THAT_NO_TRY( "REQUIRE_THAT", matcher, Catch::ResultDisposition::Normal, arg ) -#else #define REQUIRE_THAT( arg, matcher ) INTERNAL_CHECK_THAT( "REQUIRE_THAT", matcher, Catch::ResultDisposition::Normal, arg ) -#endif +#endif // CATCH_CONFIG_DISABLE_MATCHERS #define INFO( msg ) INTERNAL_CATCH_INFO( "INFO", msg ) +#define UNSCOPED_INFO( msg ) INTERNAL_CATCH_UNSCOPED_INFO( "UNSCOPED_INFO", msg ) #define WARN( msg ) INTERNAL_CATCH_MSG( "WARN", Catch::ResultWas::Warning, Catch::ResultDisposition::ContinueOnFailure, msg ) -#define SCOPED_INFO( msg ) INTERNAL_CATCH_INFO( "INFO", msg ) -#define CAPTURE( msg ) INTERNAL_CATCH_INFO( "CAPTURE", #msg " := " << Catch::toString(msg) ) -#define SCOPED_CAPTURE( msg ) INTERNAL_CATCH_INFO( "CAPTURE", #msg " := " << Catch::toString(msg) ) +#define CAPTURE( ... ) INTERNAL_CATCH_CAPTURE( INTERNAL_CATCH_UNIQUE_NAME(capturer), "CAPTURE",__VA_ARGS__ ) -#ifdef CATCH_CONFIG_VARIADIC_MACROS #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( Function, ... ) INTERNAL_CATCH_REGISTER_TESTCASE( Function, __VA_ARGS__ ) #define SECTION( ... ) INTERNAL_CATCH_SECTION( __VA_ARGS__ ) +#define DYNAMIC_SECTION( ... ) INTERNAL_CATCH_DYNAMIC_SECTION( __VA_ARGS__ ) #define FAIL( ... ) INTERNAL_CATCH_MSG( "FAIL", Catch::ResultWas::ExplicitFailure, Catch::ResultDisposition::Normal, __VA_ARGS__ ) #define FAIL_CHECK( ... ) INTERNAL_CATCH_MSG( "FAIL_CHECK", Catch::ResultWas::ExplicitFailure, Catch::ResultDisposition::ContinueOnFailure, __VA_ARGS__ ) #define SUCCEED( ... ) INTERNAL_CATCH_MSG( "SUCCEED", Catch::ResultWas::Ok, Catch::ResultDisposition::ContinueOnFailure, __VA_ARGS__ ) +#define ANON_TEST_CASE() INTERNAL_CATCH_TESTCASE() + +#ifndef CATCH_CONFIG_TRADITIONAL_MSVC_PREPROCESSOR +#define TEMPLATE_TEST_CASE( ... ) INTERNAL_CATCH_TEMPLATE_TEST_CASE( __VA_ARGS__ ) +#define TEMPLATE_TEST_CASE_SIG( ... ) INTERNAL_CATCH_TEMPLATE_TEST_CASE_SIG( __VA_ARGS__ ) +#define TEMPLATE_TEST_CASE_METHOD( className, ... ) INTERNAL_CATCH_TEMPLATE_TEST_CASE_METHOD( className, __VA_ARGS__ ) +#define TEMPLATE_TEST_CASE_METHOD_SIG( className, ... ) INTERNAL_CATCH_TEMPLATE_TEST_CASE_METHOD_SIG( className, __VA_ARGS__ ) +#define TEMPLATE_PRODUCT_TEST_CASE( ... ) INTERNAL_CATCH_TEMPLATE_PRODUCT_TEST_CASE( __VA_ARGS__ ) +#define TEMPLATE_PRODUCT_TEST_CASE_SIG( ... ) INTERNAL_CATCH_TEMPLATE_PRODUCT_TEST_CASE_SIG( __VA_ARGS__ ) +#define TEMPLATE_PRODUCT_TEST_CASE_METHOD( className, ... ) INTERNAL_CATCH_TEMPLATE_PRODUCT_TEST_CASE_METHOD( className, __VA_ARGS__ ) +#define TEMPLATE_PRODUCT_TEST_CASE_METHOD_SIG( className, ... ) INTERNAL_CATCH_TEMPLATE_PRODUCT_TEST_CASE_METHOD_SIG( className, __VA_ARGS__ ) +#define TEMPLATE_LIST_TEST_CASE( ... ) INTERNAL_CATCH_TEMPLATE_LIST_TEST_CASE(__VA_ARGS__) +#define TEMPLATE_LIST_TEST_CASE_METHOD( className, ... ) INTERNAL_CATCH_TEMPLATE_LIST_TEST_CASE_METHOD( className, __VA_ARGS__ ) #else -#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( method, name, description ) INTERNAL_CATCH_REGISTER_TESTCASE( method, name, description ) - #define SECTION( name, description ) INTERNAL_CATCH_SECTION( name, description ) - #define FAIL( msg ) INTERNAL_CATCH_MSG( "FAIL", Catch::ResultWas::ExplicitFailure, Catch::ResultDisposition::Normal, msg ) - #define FAIL_CHECK( msg ) INTERNAL_CATCH_MSG( "FAIL_CHECK", Catch::ResultWas::ExplicitFailure, Catch::ResultDisposition::ContinueOnFailure, msg ) - #define SUCCEED( msg ) INTERNAL_CATCH_MSG( "SUCCEED", Catch::ResultWas::Ok, Catch::ResultDisposition::ContinueOnFailure, msg ) +#define TEMPLATE_TEST_CASE( ... ) INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_TEST_CASE( __VA_ARGS__ ) ) +#define TEMPLATE_TEST_CASE_SIG( ... ) INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_TEST_CASE_SIG( __VA_ARGS__ ) ) +#define TEMPLATE_TEST_CASE_METHOD( className, ... ) INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_TEST_CASE_METHOD( className, __VA_ARGS__ ) ) +#define TEMPLATE_TEST_CASE_METHOD_SIG( className, ... ) INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_TEST_CASE_METHOD_SIG( className, __VA_ARGS__ ) ) +#define TEMPLATE_PRODUCT_TEST_CASE( ... ) INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_PRODUCT_TEST_CASE( __VA_ARGS__ ) ) +#define TEMPLATE_PRODUCT_TEST_CASE_SIG( ... ) INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_PRODUCT_TEST_CASE_SIG( __VA_ARGS__ ) ) +#define TEMPLATE_PRODUCT_TEST_CASE_METHOD( className, ... ) INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_PRODUCT_TEST_CASE_METHOD( className, __VA_ARGS__ ) ) +#define TEMPLATE_PRODUCT_TEST_CASE_METHOD_SIG( className, ... ) INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_PRODUCT_TEST_CASE_METHOD_SIG( className, __VA_ARGS__ ) ) +#define TEMPLATE_LIST_TEST_CASE( ... ) INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_LIST_TEST_CASE( __VA_ARGS__ ) ) +#define TEMPLATE_LIST_TEST_CASE_METHOD( className, ... ) INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_LIST_TEST_CASE_METHOD( className, __VA_ARGS__ ) ) #endif -#define ANON_TEST_CASE() INTERNAL_CATCH_TESTCASE( "", "" ) - -#define REGISTER_REPORTER( name, reporterType ) INTERNAL_CATCH_REGISTER_REPORTER( name, reporterType ) -#define REGISTER_LEGACY_REPORTER( name, reporterType ) INTERNAL_CATCH_REGISTER_LEGACY_REPORTER( name, reporterType ) -#define GENERATE( expr) INTERNAL_CATCH_GENERATE( expr ) +#if !defined(CATCH_CONFIG_RUNTIME_STATIC_REQUIRE) +#define STATIC_REQUIRE( ... ) static_assert( __VA_ARGS__, #__VA_ARGS__ ); SUCCEED( #__VA_ARGS__ ) +#define STATIC_REQUIRE_FALSE( ... ) static_assert( !(__VA_ARGS__), "!(" #__VA_ARGS__ ")" ); SUCCEED( "!(" #__VA_ARGS__ ")" ) +#else +#define STATIC_REQUIRE( ... ) REQUIRE( __VA_ARGS__ ) +#define STATIC_REQUIRE_FALSE( ... ) REQUIRE_FALSE( __VA_ARGS__ ) +#endif #endif #define CATCH_TRANSLATE_EXCEPTION( signature ) INTERNAL_CATCH_TRANSLATE_EXCEPTION( signature ) // "BDD-style" convenience wrappers -#ifdef CATCH_CONFIG_VARIADIC_MACROS #define SCENARIO( ... ) TEST_CASE( "Scenario: " __VA_ARGS__ ) #define SCENARIO_METHOD( className, ... ) INTERNAL_CATCH_TEST_CASE_METHOD( className, "Scenario: " __VA_ARGS__ ) + +#define GIVEN( desc ) INTERNAL_CATCH_DYNAMIC_SECTION( " Given: " << desc ) +#define AND_GIVEN( desc ) INTERNAL_CATCH_DYNAMIC_SECTION( "And given: " << desc ) +#define WHEN( desc ) INTERNAL_CATCH_DYNAMIC_SECTION( " When: " << desc ) +#define AND_WHEN( desc ) INTERNAL_CATCH_DYNAMIC_SECTION( " And when: " << desc ) +#define THEN( desc ) INTERNAL_CATCH_DYNAMIC_SECTION( " Then: " << desc ) +#define AND_THEN( desc ) INTERNAL_CATCH_DYNAMIC_SECTION( " And: " << desc ) + +#if defined(CATCH_CONFIG_ENABLE_BENCHMARKING) +#define BENCHMARK(...) \ + INTERNAL_CATCH_BENCHMARK(INTERNAL_CATCH_UNIQUE_NAME(C_A_T_C_H_B_E_N_C_H_), INTERNAL_CATCH_GET_1_ARG(__VA_ARGS__,,), INTERNAL_CATCH_GET_2_ARG(__VA_ARGS__,,)) +#define BENCHMARK_ADVANCED(name) \ + INTERNAL_CATCH_BENCHMARK_ADVANCED(INTERNAL_CATCH_UNIQUE_NAME(C_A_T_C_H_B_E_N_C_H_), name) +#endif // CATCH_CONFIG_ENABLE_BENCHMARKING + +using Catch::Detail::Approx; + +#else // CATCH_CONFIG_DISABLE + +////// +// If this config identifier is defined then all CATCH macros are prefixed with CATCH_ +#ifdef CATCH_CONFIG_PREFIX_ALL + +#define CATCH_REQUIRE( ... ) (void)(0) +#define CATCH_REQUIRE_FALSE( ... ) (void)(0) + +#define CATCH_REQUIRE_THROWS( ... ) (void)(0) +#define CATCH_REQUIRE_THROWS_AS( expr, exceptionType ) (void)(0) +#define CATCH_REQUIRE_THROWS_WITH( expr, matcher ) (void)(0) +#if !defined(CATCH_CONFIG_DISABLE_MATCHERS) +#define CATCH_REQUIRE_THROWS_MATCHES( expr, exceptionType, matcher ) (void)(0) +#endif// CATCH_CONFIG_DISABLE_MATCHERS +#define CATCH_REQUIRE_NOTHROW( ... ) (void)(0) + +#define CATCH_CHECK( ... ) (void)(0) +#define CATCH_CHECK_FALSE( ... ) (void)(0) +#define CATCH_CHECKED_IF( ... ) if (__VA_ARGS__) +#define CATCH_CHECKED_ELSE( ... ) if (!(__VA_ARGS__)) +#define CATCH_CHECK_NOFAIL( ... ) (void)(0) + +#define CATCH_CHECK_THROWS( ... ) (void)(0) +#define CATCH_CHECK_THROWS_AS( expr, exceptionType ) (void)(0) +#define CATCH_CHECK_THROWS_WITH( expr, matcher ) (void)(0) +#if !defined(CATCH_CONFIG_DISABLE_MATCHERS) +#define CATCH_CHECK_THROWS_MATCHES( expr, exceptionType, matcher ) (void)(0) +#endif // CATCH_CONFIG_DISABLE_MATCHERS +#define CATCH_CHECK_NOTHROW( ... ) (void)(0) + +#if !defined(CATCH_CONFIG_DISABLE_MATCHERS) +#define CATCH_CHECK_THAT( arg, matcher ) (void)(0) + +#define CATCH_REQUIRE_THAT( arg, matcher ) (void)(0) +#endif // CATCH_CONFIG_DISABLE_MATCHERS + +#define CATCH_INFO( msg ) (void)(0) +#define CATCH_UNSCOPED_INFO( msg ) (void)(0) +#define CATCH_WARN( msg ) (void)(0) +#define CATCH_CAPTURE( msg ) (void)(0) + +#define CATCH_TEST_CASE( ... ) INTERNAL_CATCH_TESTCASE_NO_REGISTRATION(INTERNAL_CATCH_UNIQUE_NAME( C_A_T_C_H_T_E_S_T_ )) +#define CATCH_TEST_CASE_METHOD( className, ... ) INTERNAL_CATCH_TESTCASE_NO_REGISTRATION(INTERNAL_CATCH_UNIQUE_NAME( C_A_T_C_H_T_E_S_T_ )) +#define CATCH_METHOD_AS_TEST_CASE( method, ... ) +#define CATCH_REGISTER_TEST_CASE( Function, ... ) (void)(0) +#define CATCH_SECTION( ... ) +#define CATCH_DYNAMIC_SECTION( ... ) +#define CATCH_FAIL( ... ) (void)(0) +#define CATCH_FAIL_CHECK( ... ) (void)(0) +#define CATCH_SUCCEED( ... ) (void)(0) + +#define CATCH_ANON_TEST_CASE() INTERNAL_CATCH_TESTCASE_NO_REGISTRATION(INTERNAL_CATCH_UNIQUE_NAME( C_A_T_C_H_T_E_S_T_ )) + +#ifndef CATCH_CONFIG_TRADITIONAL_MSVC_PREPROCESSOR +#define CATCH_TEMPLATE_TEST_CASE( ... ) INTERNAL_CATCH_TEMPLATE_TEST_CASE_NO_REGISTRATION(__VA_ARGS__) +#define CATCH_TEMPLATE_TEST_CASE_SIG( ... ) INTERNAL_CATCH_TEMPLATE_TEST_CASE_SIG_NO_REGISTRATION(__VA_ARGS__) +#define CATCH_TEMPLATE_TEST_CASE_METHOD( className, ... ) INTERNAL_CATCH_TEMPLATE_TEST_CASE_METHOD_NO_REGISTRATION(className, __VA_ARGS__) +#define CATCH_TEMPLATE_TEST_CASE_METHOD_SIG( className, ... ) INTERNAL_CATCH_TEMPLATE_TEST_CASE_METHOD_SIG_NO_REGISTRATION(className, __VA_ARGS__ ) +#define CATCH_TEMPLATE_PRODUCT_TEST_CASE( ... ) CATCH_TEMPLATE_TEST_CASE( __VA_ARGS__ ) +#define CATCH_TEMPLATE_PRODUCT_TEST_CASE_SIG( ... ) CATCH_TEMPLATE_TEST_CASE( __VA_ARGS__ ) +#define CATCH_TEMPLATE_PRODUCT_TEST_CASE_METHOD( className, ... ) CATCH_TEMPLATE_TEST_CASE_METHOD( className, __VA_ARGS__ ) +#define CATCH_TEMPLATE_PRODUCT_TEST_CASE_METHOD_SIG( className, ... ) CATCH_TEMPLATE_TEST_CASE_METHOD( className, __VA_ARGS__ ) +#else +#define CATCH_TEMPLATE_TEST_CASE( ... ) INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_TEST_CASE_NO_REGISTRATION(__VA_ARGS__) ) +#define CATCH_TEMPLATE_TEST_CASE_SIG( ... ) INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_TEST_CASE_SIG_NO_REGISTRATION(__VA_ARGS__) ) +#define CATCH_TEMPLATE_TEST_CASE_METHOD( className, ... ) INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_TEST_CASE_METHOD_NO_REGISTRATION(className, __VA_ARGS__ ) ) +#define CATCH_TEMPLATE_TEST_CASE_METHOD_SIG( className, ... ) INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_TEST_CASE_METHOD_SIG_NO_REGISTRATION(className, __VA_ARGS__ ) ) +#define CATCH_TEMPLATE_PRODUCT_TEST_CASE( ... ) CATCH_TEMPLATE_TEST_CASE( __VA_ARGS__ ) +#define CATCH_TEMPLATE_PRODUCT_TEST_CASE_SIG( ... ) CATCH_TEMPLATE_TEST_CASE( __VA_ARGS__ ) +#define CATCH_TEMPLATE_PRODUCT_TEST_CASE_METHOD( className, ... ) CATCH_TEMPLATE_TEST_CASE_METHOD( className, __VA_ARGS__ ) +#define CATCH_TEMPLATE_PRODUCT_TEST_CASE_METHOD_SIG( className, ... ) CATCH_TEMPLATE_TEST_CASE_METHOD( className, __VA_ARGS__ ) +#endif + +// "BDD-style" convenience wrappers +#define CATCH_SCENARIO( ... ) INTERNAL_CATCH_TESTCASE_NO_REGISTRATION(INTERNAL_CATCH_UNIQUE_NAME( C_A_T_C_H_T_E_S_T_ )) +#define CATCH_SCENARIO_METHOD( className, ... ) INTERNAL_CATCH_TESTCASE_METHOD_NO_REGISTRATION(INTERNAL_CATCH_UNIQUE_NAME( C_A_T_C_H_T_E_S_T_ ), className ) +#define CATCH_GIVEN( desc ) +#define CATCH_AND_GIVEN( desc ) +#define CATCH_WHEN( desc ) +#define CATCH_AND_WHEN( desc ) +#define CATCH_THEN( desc ) +#define CATCH_AND_THEN( desc ) + +#define CATCH_STATIC_REQUIRE( ... ) (void)(0) +#define CATCH_STATIC_REQUIRE_FALSE( ... ) (void)(0) + +// If CATCH_CONFIG_PREFIX_ALL is not defined then the CATCH_ prefix is not required #else -#define SCENARIO( name, tags ) TEST_CASE( "Scenario: " name, tags ) -#define SCENARIO_METHOD( className, name, tags ) INTERNAL_CATCH_TEST_CASE_METHOD( className, "Scenario: " name, tags ) + +#define REQUIRE( ... ) (void)(0) +#define REQUIRE_FALSE( ... ) (void)(0) + +#define REQUIRE_THROWS( ... ) (void)(0) +#define REQUIRE_THROWS_AS( expr, exceptionType ) (void)(0) +#define REQUIRE_THROWS_WITH( expr, matcher ) (void)(0) +#if !defined(CATCH_CONFIG_DISABLE_MATCHERS) +#define REQUIRE_THROWS_MATCHES( expr, exceptionType, matcher ) (void)(0) +#endif // CATCH_CONFIG_DISABLE_MATCHERS +#define REQUIRE_NOTHROW( ... ) (void)(0) + +#define CHECK( ... ) (void)(0) +#define CHECK_FALSE( ... ) (void)(0) +#define CHECKED_IF( ... ) if (__VA_ARGS__) +#define CHECKED_ELSE( ... ) if (!(__VA_ARGS__)) +#define CHECK_NOFAIL( ... ) (void)(0) + +#define CHECK_THROWS( ... ) (void)(0) +#define CHECK_THROWS_AS( expr, exceptionType ) (void)(0) +#define CHECK_THROWS_WITH( expr, matcher ) (void)(0) +#if !defined(CATCH_CONFIG_DISABLE_MATCHERS) +#define CHECK_THROWS_MATCHES( expr, exceptionType, matcher ) (void)(0) +#endif // CATCH_CONFIG_DISABLE_MATCHERS +#define CHECK_NOTHROW( ... ) (void)(0) + +#if !defined(CATCH_CONFIG_DISABLE_MATCHERS) +#define CHECK_THAT( arg, matcher ) (void)(0) + +#define REQUIRE_THAT( arg, matcher ) (void)(0) +#endif // CATCH_CONFIG_DISABLE_MATCHERS + +#define INFO( msg ) (void)(0) +#define UNSCOPED_INFO( msg ) (void)(0) +#define WARN( msg ) (void)(0) +#define CAPTURE( ... ) (void)(0) + +#define TEST_CASE( ... ) INTERNAL_CATCH_TESTCASE_NO_REGISTRATION(INTERNAL_CATCH_UNIQUE_NAME( C_A_T_C_H_T_E_S_T_ )) +#define TEST_CASE_METHOD( className, ... ) INTERNAL_CATCH_TESTCASE_NO_REGISTRATION(INTERNAL_CATCH_UNIQUE_NAME( C_A_T_C_H_T_E_S_T_ )) +#define METHOD_AS_TEST_CASE( method, ... ) +#define REGISTER_TEST_CASE( Function, ... ) (void)(0) +#define SECTION( ... ) +#define DYNAMIC_SECTION( ... ) +#define FAIL( ... ) (void)(0) +#define FAIL_CHECK( ... ) (void)(0) +#define SUCCEED( ... ) (void)(0) +#define ANON_TEST_CASE() INTERNAL_CATCH_TESTCASE_NO_REGISTRATION(INTERNAL_CATCH_UNIQUE_NAME( C_A_T_C_H_T_E_S_T_ )) + +#ifndef CATCH_CONFIG_TRADITIONAL_MSVC_PREPROCESSOR +#define TEMPLATE_TEST_CASE( ... ) INTERNAL_CATCH_TEMPLATE_TEST_CASE_NO_REGISTRATION(__VA_ARGS__) +#define TEMPLATE_TEST_CASE_SIG( ... ) INTERNAL_CATCH_TEMPLATE_TEST_CASE_SIG_NO_REGISTRATION(__VA_ARGS__) +#define TEMPLATE_TEST_CASE_METHOD( className, ... ) INTERNAL_CATCH_TEMPLATE_TEST_CASE_METHOD_NO_REGISTRATION(className, __VA_ARGS__) +#define TEMPLATE_TEST_CASE_METHOD_SIG( className, ... ) INTERNAL_CATCH_TEMPLATE_TEST_CASE_METHOD_SIG_NO_REGISTRATION(className, __VA_ARGS__ ) +#define TEMPLATE_PRODUCT_TEST_CASE( ... ) TEMPLATE_TEST_CASE( __VA_ARGS__ ) +#define TEMPLATE_PRODUCT_TEST_CASE_SIG( ... ) TEMPLATE_TEST_CASE( __VA_ARGS__ ) +#define TEMPLATE_PRODUCT_TEST_CASE_METHOD( className, ... ) TEMPLATE_TEST_CASE_METHOD( className, __VA_ARGS__ ) +#define TEMPLATE_PRODUCT_TEST_CASE_METHOD_SIG( className, ... ) TEMPLATE_TEST_CASE_METHOD( className, __VA_ARGS__ ) +#else +#define TEMPLATE_TEST_CASE( ... ) INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_TEST_CASE_NO_REGISTRATION(__VA_ARGS__) ) +#define TEMPLATE_TEST_CASE_SIG( ... ) INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_TEST_CASE_SIG_NO_REGISTRATION(__VA_ARGS__) ) +#define TEMPLATE_TEST_CASE_METHOD( className, ... ) INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_TEST_CASE_METHOD_NO_REGISTRATION(className, __VA_ARGS__ ) ) +#define TEMPLATE_TEST_CASE_METHOD_SIG( className, ... ) INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_TEST_CASE_METHOD_SIG_NO_REGISTRATION(className, __VA_ARGS__ ) ) +#define TEMPLATE_PRODUCT_TEST_CASE( ... ) TEMPLATE_TEST_CASE( __VA_ARGS__ ) +#define TEMPLATE_PRODUCT_TEST_CASE_SIG( ... ) TEMPLATE_TEST_CASE( __VA_ARGS__ ) +#define TEMPLATE_PRODUCT_TEST_CASE_METHOD( className, ... ) TEMPLATE_TEST_CASE_METHOD( className, __VA_ARGS__ ) +#define TEMPLATE_PRODUCT_TEST_CASE_METHOD_SIG( className, ... ) TEMPLATE_TEST_CASE_METHOD( className, __VA_ARGS__ ) +#endif + +#define STATIC_REQUIRE( ... ) (void)(0) +#define STATIC_REQUIRE_FALSE( ... ) (void)(0) + #endif -#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, "" ) + +#define CATCH_TRANSLATE_EXCEPTION( signature ) INTERNAL_CATCH_TRANSLATE_EXCEPTION_NO_REG( INTERNAL_CATCH_UNIQUE_NAME( catch_internal_ExceptionTranslator ), signature ) + +// "BDD-style" convenience wrappers +#define SCENARIO( ... ) INTERNAL_CATCH_TESTCASE_NO_REGISTRATION(INTERNAL_CATCH_UNIQUE_NAME( C_A_T_C_H_T_E_S_T_ ) ) +#define SCENARIO_METHOD( className, ... ) INTERNAL_CATCH_TESTCASE_METHOD_NO_REGISTRATION(INTERNAL_CATCH_UNIQUE_NAME( C_A_T_C_H_T_E_S_T_ ), className ) + +#define GIVEN( desc ) +#define AND_GIVEN( desc ) +#define WHEN( desc ) +#define AND_WHEN( desc ) +#define THEN( desc ) +#define AND_THEN( desc ) using Catch::Detail::Approx; -// #included from: internal/catch_reenable_warnings.h +#endif + +#endif // ! CATCH_CONFIG_IMPL_ONLY + +// start catch_reenable_warnings.h -#define TWOBLUECUBES_CATCH_REENABLE_WARNINGS_H_INCLUDED #ifdef __clang__ # ifdef __ICC // icpc defines the __clang__ macro @@ -11685,5 +17970,7 @@ using Catch::Detail::Approx; # pragma GCC diagnostic pop #endif +// end catch_reenable_warnings.h +// end catch.hpp #endif // TWOBLUECUBES_SINGLE_INCLUDE_CATCH_HPP_INCLUDED diff --git a/neosensor/libraries/ArduinoJson/idf_component.yml b/neosensor/libraries/ArduinoJson/idf_component.yml new file mode 100644 index 0000000000000000000000000000000000000000..bbf7b39f09cf51079b6ac0212c3d635287c34ddd --- /dev/null +++ b/neosensor/libraries/ArduinoJson/idf_component.yml @@ -0,0 +1,13 @@ +version: "6.21.2" +description: >- + A simple and efficient JSON library for embedded C++. + ArduinoJson supports ✔ serialization, ✔ deserialization, ✔ MessagePack, ✔ fixed allocation, ✔ zero-copy, ✔ streams, ✔ filtering, and more. + It is the most popular Arduino library on GitHub ❤❤❤❤❤. + Check out arduinojson.org for a comprehensive documentation. +url: https://arduinojson.org/ +files: + exclude: + - "**/.vs/**/*" + - ".devcontainer/**/*" + - "examples/**/*" + - "extras/**/*" diff --git a/neosensor/libraries/ArduinoJson/library.json b/neosensor/libraries/ArduinoJson/library.json index 01596a965aacd35c0ed9c44c5ea6e86e8743063e..507d5702b3ae3af4b3b60adcc0742af7b8c94736 100644 --- a/neosensor/libraries/ArduinoJson/library.json +++ b/neosensor/libraries/ArduinoJson/library.json @@ -7,12 +7,13 @@ "type": "git", "url": "https://github.com/bblanchon/ArduinoJson.git" }, - "version": "6.20.0", + "version": "6.21.2", "authors": { "name": "Benoit Blanchon", "url": "https://blog.benoitblanchon.fr" }, "exclude": [ + ".devcontainer", ".github", "extras" ], diff --git a/neosensor/libraries/ArduinoJson/library.properties b/neosensor/libraries/ArduinoJson/library.properties index 72a5334ea4863ee5ee4c012bdfcf4a752ef1e4af..414daa469237aa1d5356ea3c08e97297722a73d5 100644 --- a/neosensor/libraries/ArduinoJson/library.properties +++ b/neosensor/libraries/ArduinoJson/library.properties @@ -1,5 +1,5 @@ name=ArduinoJson -version=6.20.0 +version=6.21.2 author=Benoit Blanchon <blog.benoitblanchon.fr> maintainer=Benoit Blanchon <blog.benoitblanchon.fr> sentence=A simple and efficient JSON library for embedded C++. diff --git a/neosensor/libraries/ArduinoJson/logo.svg b/neosensor/libraries/ArduinoJson/logo.svg deleted file mode 100644 index 5afb6ac7449a89dc65ed32116441f33cac238795..0000000000000000000000000000000000000000 --- a/neosensor/libraries/ArduinoJson/logo.svg +++ /dev/null @@ -1 +0,0 @@ -<svg width="301.19" height="238.96" viewBox="0 0 79.691 63.225" xmlns="http://www.w3.org/2000/svg"><defs><clipPath id="a"><path d="M0 638h1000V0H0z"/></clipPath></defs><g clip-path="url(#a)" transform="matrix(.1564 0 0 -.1564 -38.351 81.5)"><path d="m246.91 120.14 20.015 58.057h19.881l20.013-58.057h-15.771l-2.918 10.34h-22.4l-3.048-10.34zm22.135 21.605h15.771l-5.83 19.219c-.265.53-.53 1.457-.797 2.787-.398 1.323-.795 3.043-1.192 5.034-.398-1.461-.662-2.784-1.062-4.11-.397-1.322-.662-2.519-1.059-3.711zM311.46 120.14v40.029h13.387v-9.41c1.326 3.447 3.182 5.965 5.566 7.69 2.387 1.72 5.304 2.648 8.616 2.648.661 0 1.192-.133 1.723-.133.53 0 1.192-.135 1.722-.135l-1.325-12.853c-.928.266-1.723.533-2.517.664-.795.133-1.592.133-2.386.133-3.446 0-6.098-1.065-7.953-3.182-1.855-2.119-2.783-5.037-2.783-8.883V120.14zM390.72 181.64v-61.498h-12.989v6.494c-1.724-2.648-3.844-4.769-5.966-6.096-2.253-1.322-4.771-1.984-7.554-1.984-5.567 0-10.073 1.984-13.387 5.83-3.314 3.977-5.036 9.147-5.036 15.772 0 6.359 1.722 11.531 5.036 15.375 3.314 3.976 7.556 5.962 12.856 5.962 3.446 0 6.229-.664 8.35-1.853 2.121-1.191 3.977-3.314 5.701-6.098-.265.928-.265 1.989-.397 3.182-.135 1.193-.135 2.519-.135 3.975v20.939zm-12.459-41.482c0 3.05-.795 5.566-2.519 7.287-1.591 1.859-3.845 2.787-6.76 2.787-2.783 0-5.036-.928-6.761-2.787-1.588-1.721-2.385-4.237-2.385-7.287 0-3.182.797-5.698 2.385-7.426 1.725-1.852 3.978-2.647 6.761-2.647 2.915 0 5.169.795 6.76 2.647 1.724 1.859 2.519 4.244 2.519 7.426M442.28 160.17v-20.412c0-4.506-.265-7.953-1.061-10.072-.663-2.254-1.989-4.11-3.71-5.83-1.724-1.727-3.978-3.051-6.496-3.979-2.65-.793-5.831-1.322-9.41-1.322-3.578 0-6.626.529-9.277 1.322-2.651.928-4.771 2.252-6.628 3.979-1.724 1.587-3.048 3.576-3.712 5.83-.663 2.119-1.06 5.566-1.06 10.072v20.412h13.519v-21.336c0-3.316.532-5.836 1.591-7.293 1.195-1.457 2.916-2.252 5.434-2.252s4.375.795 5.435 2.252 1.59 3.842 1.59 7.293v21.336zM452.88 160.17h14.05v-40.029h-14.05zm-.795 12.461c0 2.119.795 3.974 2.386 5.435 1.457 1.588 3.313 2.25 5.434 2.25 2.254 0 4.108-.662 5.567-2.119 1.458-1.592 2.254-3.316 2.254-5.566 0-2.123-.796-3.977-2.254-5.57-1.592-1.457-3.447-2.25-5.567-2.25-2.121 0-3.977.793-5.434 2.25-1.591 1.593-2.386 3.447-2.386 5.57M477.8 120.14v40.029h12.856v-8.088c1.988 3.186 4.109 5.567 6.496 7.163 2.517 1.455 5.434 2.25 8.881 2.25 2.648 0 4.904-.53 6.891-1.325 1.99-.795 3.712-1.984 4.903-3.58 1.059-1.322 1.854-2.912 2.256-4.902.529-1.986.662-4.774.662-8.613V120.14h-14.05v21.473c0 3.181-.53 5.433-1.59 6.896-1.062 1.455-2.651 2.25-5.035 2.25-2.918 0-5.04-1.058-6.365-3.316-1.325-2.119-1.987-5.698-1.987-10.469V120.14zM573.23 140.03c0-2.918-.529-5.566-1.721-8.221-1.059-2.515-2.653-4.904-4.905-6.89-2.118-2.125-4.507-3.711-7.287-4.774-2.653-1.056-5.439-1.586-8.484-1.586-3.05 0-5.963.53-8.617 1.586-2.653 1.063-5.037 2.649-7.155 4.774-2.124 1.986-3.845 4.242-4.904 6.89-1.064 2.522-1.594 5.303-1.594 8.221s.53 5.697 1.594 8.35c1.059 2.515 2.648 4.904 4.904 6.892 1.986 2.117 4.37 3.578 7.155 4.639 2.654 1.058 5.567 1.588 8.617 1.588 3.045 0 5.962-.53 8.612-1.588 2.652-1.061 5.041-2.522 7.159-4.639 2.252-2.119 3.846-4.377 4.905-7.025 1.192-2.52 1.721-5.299 1.721-8.217m-14.05 0c0 3.049-.795 5.299-2.252 7.021-1.457 1.727-3.579 2.655-6.095 2.655-2.654 0-4.639-.928-6.096-2.655-1.461-1.722-2.256-3.972-2.256-7.021 0-2.918.795-5.303 2.256-7.027 1.457-1.725 3.442-2.518 6.096-2.518 2.516 0 4.638.793 6.095 2.518 1.457 1.724 2.252 4.109 2.252 7.027" fill="#00868e"/><path d="M593.77 178.2h15.776v-37.643c0-4.109-.264-7.287-.799-9.545a18.004 18.004 0 0 0-2.649-5.832c-1.589-2.115-3.58-3.843-5.964-4.902-2.387-1.191-4.903-1.721-7.821-1.721-3.712 0-7.022.793-9.808 2.383-2.914 1.588-5.301 3.846-7.289 6.889l9.676 8.75c.133-1.723.796-3.045 1.589-3.977.928-.927 1.987-1.326 3.316-1.326 1.456 0 2.516.797 3.178 2.524.529 1.586.795 5.83.795 12.455zM616.44 123.46l3.051 10.734c1.985-1.724 4.237-3.181 6.758-4.107 2.519-.928 4.903-1.459 7.424-1.459 1.854 0 3.178.268 4.105.928.933.531 1.329 1.326 1.329 2.384 0 1.86-1.858 3.182-5.571 3.979-1.192.264-2.251.529-2.913.793-4.242 1.191-7.292 2.652-9.279 4.639-1.853 1.859-2.786 4.244-2.786 7.293 0 3.839 1.462 7.021 4.375 9.277 2.917 2.385 6.895 3.576 11.8 3.576 2.648 0 5.168-.396 7.816-.928a53.904 53.904 0 0 0 8.22-2.785l-2.918-9.67c-1.853 1.192-3.841 2.25-5.698 2.912-1.986.664-3.846.928-5.831.928-1.589 0-2.786-.264-3.713-.793-.794-.533-1.192-1.193-1.192-2.119 0-1.463 1.855-2.654 5.566-3.582.928-.264 1.457-.396 1.859-.529 4.904-1.455 8.348-3.051 10.205-4.903 1.987-1.988 2.914-4.507 2.914-7.691 0-4.104-1.589-7.42-4.771-9.939-3.047-2.518-7.289-3.84-12.457-3.84-3.448 0-6.763.396-9.809 1.191-2.918.793-5.831 2.119-8.484 3.711M701.93 140.03c0-2.918-.53-5.566-1.723-8.221a20.15 20.15 0 0 0-4.77-6.89c-2.252-2.125-4.64-3.711-7.288-4.774a23.769 23.769 0 0 0-8.616-1.586c-3.051 0-5.964.53-8.618 1.586-2.647 1.063-5.036 2.649-7.155 4.774-2.123 1.986-3.712 4.242-4.903 6.89-1.065 2.522-1.594 5.303-1.594 8.221s.529 5.697 1.594 8.35c1.191 2.515 2.78 4.904 4.903 6.892 2.119 2.117 4.508 3.578 7.155 4.639 2.654 1.058 5.567 1.588 8.618 1.588 3.177 0 5.962-.53 8.616-1.588 2.781-1.061 5.169-2.522 7.288-4.639 2.119-2.119 3.713-4.377 4.904-7.025 1.059-2.52 1.589-5.299 1.589-8.217m-14.05 0c0 3.049-.663 5.299-2.252 7.021-1.457 1.727-3.447 2.655-6.095 2.655-2.521 0-4.64-.928-6.097-2.655-1.461-1.722-2.255-3.972-2.255-7.021 0-2.918.794-5.303 2.255-7.027 1.457-1.725 3.576-2.518 6.097-2.518 2.648 0 4.638.793 6.095 2.518 1.589 1.724 2.252 4.109 2.252 7.027M710.01 120.14v40.029h12.992v-8.088c1.854 3.186 3.973 5.567 6.492 7.163 2.516 1.455 5.434 2.25 8.882 2.25 2.516 0 4.904-.53 6.89-1.325s3.58-1.984 4.904-3.58c1.06-1.322 1.854-2.912 2.257-4.902.396-1.986.661-4.774.661-8.613V120.14h-14.05v21.473c0 3.181-.529 5.433-1.589 6.896-1.064 1.455-2.786 2.25-5.042 2.25-2.913 0-5.036-1.058-6.492-3.316-1.324-2.119-1.987-5.698-1.987-10.469V120.14zM703.39 417.11l-8.81-3.271c5.363-15.116 8.291-31.384 8.291-48.338 0-4.616-.226-9.177-.648-13.683l9.375-.627c.434 4.712.667 9.484.667 14.31 0 18.104-3.136 35.475-8.875 51.609M558.32 220.95c-15.705 0-30.819 2.516-44.978 7.146a153.294 153.294 0 0 0-11.51-5.49c-.144-.06-.29-.117-.434-.177 17.609-7.012 36.814-10.874 56.922-10.874 48.132 0 91.098 22.094 119.33 56.688l-8.571 4.381c-26.517-31.586-66.288-51.674-110.76-51.674" fill="#e5ad23"/><path d="M441.68 219.54c-21.463 0-41.833 4.674-60.154 13.053l-4.695-7.885c19.71-9.17 41.679-14.299 64.849-14.299 21.177 0 41.352 4.283 59.716 12.022a153.11 153.11 0 0 0-11.733 5.257c-15.018-5.273-31.164-8.148-47.983-8.148" fill="#e47128"/><path d="M552.47 271.13c.009 0 .017-.004.023-.004-.006 0-.014.004-.023.004M554.52 271.03a83.931 83.931 0 0 1 3.8-.098c1.279 0 2.549.041 3.814.098a94.767 94.767 0 0 0-3.818-.096c-1.273 0-2.534.045-3.796.096M554.31 459.97c1.311.054 2.624.099 3.947.1a84.766 84.766 0 0 1-3.947-.1M550.65 459.73h.006-.006M564.11 271.12c.021.002.04.002.061.006h.001c-.021 0-.041-.004-.062-.006M562.34 459.97c-1.334.056-2.67.101-4.018.101h-.002c1.349 0 2.686-.046 4.021-.102l-.001.001M595.63 364.35c0 33.746-10.866 64.951-29.28 90.321a90.409 90.409 0 0 1-8.033.377c-1.23 0-2.45-.044-3.667-.093 19.923-24.808 31.849-56.312 31.849-90.605 0-33.273-11.235-63.909-30.102-88.358.64-.014 1.276-.049 1.92-.049 3.298 0 6.55.191 9.755.539 17.361 24.918 27.558 55.196 27.558 87.868" fill="#e5ad23"/><path d="M672.62 365.5c0 63.125-51.175 114.3-114.3 114.3-4.692 0-9.316-.289-13.861-.839-3.962-.48-7.86-1.156-11.687-2.03a145.022 145.022 0 0 0 8.947-7.866c3.831.61 7.731 1.013 11.688 1.195 1.629.076 3.266.119 4.913.119 57.922 0 104.88-46.956 104.88-104.88 0-3.787-.206-7.525-.597-11.208l9.292-1.675c.474 4.23.727 8.526.727 12.883" fill="#e5ad23"/><path d="m383.38 235.7 2.881 4.838c-47.274 21.193-80.206 68.66-80.206 123.82 0 8.489.321 14.111 1.814 22.167l-18.228 2.079a155.144 155.144 0 0 1-1.907-24.246c0-61.852 36.484-115.18 89.1-139.65l4.695 7.885zM475.99 495.6a134.617 134.617 0 0 0 12.062-3.756 142.93 142.93 0 0 0 6.585 3.453c1.45.713 2.909 1.406 4.384 2.071a143.17 143.17 0 0 0 11.648 4.638c14.921 5.208 30.952 8.047 47.649 8.047 50.216 0 94.445-25.61 120.36-64.478l7.703 5.385c-27.61 41.291-74.657 68.488-128.06 68.488-21.178 0-41.356-4.278-59.72-12.015a153.202 153.202 0 0 1-11.628-5.493 152.38 152.38 0 0 1-4.39-2.391 141.193 141.193 0 0 1-50.108 5.718l-.323-5.623a135.848 135.848 0 0 0 43.841-4.044" fill="#62aeb2"/><path d="m342.81 347.38 4.169 2.559a96.39 96.39 0 0 0-1.083 14.418c0 51.248 40.26 93.047 90.872 95.611a154.602 154.602 0 0 0 3.806 4.693 155.257 155.257 0 0 0 6.155 6.887c-1.673.08-3.352.136-5.045.136-59.276 0-107.33-48.053-107.33-107.33 0-57.863 45.79-105.02 103.11-107.24l-5.896 7.424c-45.017 4.51-81.248 38.772-88.761 82.837" fill="#62aeb2"/><path d="M454.56 264.87a148.932 148.932 0 0 0-3.857 4.131 145.173 145.173 0 0 0-14.674 19.422l-10.18-1.379a154.653 154.653 0 0 1 12.825-18.408 155.187 155.187 0 0 1 10.177-11.368 156.325 156.325 0 0 1 7.121-6.742l10.99 2.959a143.075 143.075 0 0 0-6.091 5.254 144.273 144.273 0 0 0-6.311 6.131M420.05 407.76l-9.694.332a153.96 153.96 0 0 1-5.979-42.596c0-20.788 4.126-40.609 11.596-58.699h10.22c-7.983 17.938-12.422 37.799-12.422 58.699 0 14.704 2.197 28.895 6.279 42.264M458.43 365.5c0-17.657 4.593-34.231 12.636-48.619l4.824 2.261c-.085.15-.164.305-.247.456-.309.553-.611 1.11-.909 1.671a100.017 100.017 0 0 0-3.833 8.142 94.53 94.53 0 0 0-1.251 3.173c-.178.479-.342.965-.512 1.449a95.322 95.322 0 0 0-.813 2.401c-.16.498-.323.994-.476 1.496a92.022 92.022 0 0 0-.986 3.474c-.119.448-.225.9-.337 1.351-.232.939-.45 1.884-.654 2.834-.087.408-.181.812-.263 1.222a93.627 93.627 0 0 0-.674 3.776c-.067.418-.126.838-.186 1.258a94.464 94.464 0 0 0-.425 3.343c-.031.282-.069.562-.097.844a95.78 95.78 0 0 0-.366 5.239 94.86 94.86 0 0 0-.1 3.965c0 .088-.007.175-.007.264 0 .173.012.344.013.517.007 1.306.039 2.606.099 3.898.025.564.069 1.123.105 1.685.058.914.124 1.826.208 2.733a96.424 96.424 0 0 0 .513 4.374c.089.638.178 1.276.28 1.91.132.823.284 1.64.438 2.456.116.616.222 1.236.349 1.848.271 1.292.566 2.576.888 3.849.192.756.41 1.501.62 2.251.166.593.328 1.188.505 1.777.243.808.505 1.608.77 2.407.164.498.33.995.503 1.489.297.848.604 1.692.924 2.531.146.38.298.759.449 1.138.369.93.743 1.856 1.14 2.771l.022.048a94.131 94.131 0 0 0 7.034 13.177c.004.009.01.017.015.025a95.434 95.434 0 0 0 4.24 6.115l-5.094 2.048C465.621 408.009 458.43 387.6 458.43 365.5" fill="#62aeb2"/><path d="m581.16 243.57-2.615 9.418-2.535 9.131c45.885 7.797 81.619 45.39 86.59 92.177.391 3.682.597 7.42.597 11.207 0 57.922-46.956 104.88-104.88 104.88-1.647 0-3.284-.043-4.913-.119a105.226 105.226 0 0 1-11.688-1.194 104.98 104.98 0 0 1-4.422-.797 103.31 103.31 0 0 1-6.613-1.578 104.297 104.297 0 0 1-17.449-6.475 104.871 104.871 0 0 1-18.076-10.988 100.108 100.108 0 0 1-8.89 4.998 114.256 114.256 0 0 0 18.06 12.038 113.806 113.806 0 0 0 10.644 5.02c2.225.913 4.484 1.764 6.778 2.54 2.179.735 4.39 1.399 6.626 2.004 1.455.394 2.919.766 4.395 1.103a115.525 115.525 0 0 0 25.548 2.869c63.125 0 114.3-51.173 114.3-114.3 0-4.357-.253-8.653-.727-12.883l9.607-1.732c-6.345-54.048-47.438-97.468-100.34-107.32m-22.841 27.365c-1.275 0-2.54.041-3.8.098-.676.025-1.35.058-2.024.098-.007 0-.015.003-.023.003a94.109 94.109 0 0 0-53.919 21.088c-.391.323-.775.651-1.161.975a100.902 100.902 0 0 0-3.216 2.834 99.216 99.216 0 0 0-1.786 1.705c-.4.389-.807.772-1.2 1.168a90.995 90.995 0 0 0-2.536 2.66c-.474.516-.932 1.047-1.394 1.574-.414.471-.827.942-1.231 1.418a99.82 99.82 0 0 0-2.487 3.084c-.48.621-.96 1.241-1.424 1.869-.029.041-.06.079-.089.118l-4.694-2.575-4.419-2.419c-12.258 17.162-19.475 38.172-19.475 60.87 0 25.55 9.142 48.961 24.325 67.153l4.675-2.22 4.99-2.369a94.878 94.878 0 0 0 28.026 21.725c.266.137.532.277.803.411.77.384 1.547.755 2.33 1.118.419.194.841.382 1.263.571a93.97 93.97 0 0 0 30.794 7.843h.006c1.216.097 2.434.183 3.66.234 1.31.062 2.624.099 3.948.101H558.316c1.348 0 2.684-.044 4.018-.1l.024-.002a94.398 94.398 0 0 0 4.382-.292c.116-.009.234-.015.352-.026a93.293 93.293 0 0 0 4.156-.483c.171-.023.344-.041.514-.065a95.083 95.083 0 0 0 3.956-.657c.213-.041.431-.075.646-.116a93.744 93.744 0 0 0 3.769-.817c.252-.06.505-.113.756-.175a91.676 91.676 0 0 0 3.593-.963c.283-.082.571-.158.853-.243a92.313 92.313 0 0 0 3.426-1.099c.31-.106.623-.207.933-.316 1.1-.387 2.186-.798 3.267-1.225.332-.13.666-.257.997-.392a96.367 96.367 0 0 0 3.11-1.339c.354-.159.708-.315 1.059-.479a92.603 92.603 0 0 0 2.954-1.441c.371-.189.742-.376 1.109-.569a92.422 92.422 0 0 0 2.801-1.535c.387-.219.771-.439 1.154-.664a93.505 93.505 0 0 0 2.648-1.617c.399-.253.796-.506 1.192-.764a92.352 92.352 0 0 0 2.493-1.69 89.785 89.785 0 0 0 4.812-3.6 95.347 95.347 0 0 0 5.505-4.752c.426-.397.846-.802 1.267-1.207a96.934 96.934 0 0 0 1.904-1.89c.426-.437.845-.881 1.263-1.326a96.568 96.568 0 0 0 1.761-1.918c.425-.478.84-.964 1.255-1.449a96.685 96.685 0 0 0 1.621-1.939c.419-.518.826-1.045 1.235-1.572.501-.647 1-1.295 1.485-1.954.41-.559.806-1.128 1.205-1.696.455-.649.91-1.3 1.35-1.962.4-.601.783-1.212 1.168-1.822.412-.652.825-1.301 1.22-1.963.384-.643.752-1.297 1.121-1.95.368-.65.738-1.297 1.092-1.956.367-.687.715-1.386 1.065-2.083.326-.644.655-1.286.965-1.939.348-.731.673-1.474 1.002-2.216.283-.637.573-1.272.842-1.917.324-.778.624-1.567.929-2.354.242-.627.493-1.25.722-1.883.299-.828.571-1.668.848-2.506.201-.61.413-1.215.602-1.83.272-.884.513-1.781.759-2.676.162-.585.335-1.164.486-1.753.242-.952.451-1.916.665-2.879.12-.546.256-1.087.367-1.638.211-1.038.384-2.089.56-3.138.082-.488.18-.97.255-1.461.178-1.174.316-2.361.451-3.549.042-.376.1-.747.139-1.124.148-1.468.256-2.947.337-4.434.005-.103.018-.205.023-.307.082-1.609.125-3.227.125-4.855 0-1.619-.044-3.227-.124-4.826-.013-.244-.04-.484-.054-.728a93.422 93.422 0 0 0-.304-3.987c-.045-.459-.114-.911-.167-1.368a93.13 93.13 0 0 0-.416-3.278c-.083-.549-.189-1.089-.28-1.634-.167-.983-.329-1.966-.526-2.937-.119-.594-.261-1.179-.391-1.769-.203-.911-.402-1.823-.629-2.724-.157-.62-.335-1.231-.505-1.847-.234-.855-.467-1.711-.726-2.557-.195-.639-.41-1.267-.617-1.901-.265-.806-.53-1.613-.816-2.411-.234-.65-.484-1.291-.732-1.933-.294-.764-.586-1.527-.899-2.28-.272-.658-.561-1.307-.849-1.957a90.549 90.549 0 0 0-.971-2.152c-.314-.663-.641-1.317-.968-1.972a94.17 94.17 0 0 0-1.038-2.026 94.763 94.763 0 0 0-1.089-1.98 93.772 93.772 0 0 0-1.095-1.902 93.042 93.042 0 0 0-1.213-1.985c-.375-.595-.753-1.189-1.14-1.779a109.172 109.172 0 0 0-2.519-3.635 91.938 91.938 0 0 0-2.676-3.498 92.36 92.36 0 0 0-1.617-1.969 109.552 109.552 0 0 0-2.974-3.353 94.078 94.078 0 0 0-1.194-1.25 91.336 91.336 0 0 0-1.932-1.955c-.383-.375-.775-.74-1.164-1.111a96.75 96.75 0 0 0-2.105-1.942c-.366-.324-.739-.641-1.11-.961a99.453 99.453 0 0 0-2.303-1.937c-.334-.27-.676-.53-1.014-.797a95.448 95.448 0 0 0-2.53-1.934c-.289-.213-.586-.416-.879-.625a94.486 94.486 0 0 0-2.792-1.941c-.221-.145-.447-.283-.669-.428a95.711 95.711 0 0 0-3.124-1.961c-.113-.068-.229-.131-.342-.197a93.997 93.997 0 0 0-42.053-12.928 2.428 2.428 0 0 0-.168-.014c-.021-.003-.04-.003-.061-.005a91.893 91.893 0 0 0-1.978-.096 84.71 84.71 0 0 0-3.815-.098m-85.397-22.062a120.25 120.25 0 0 0-31.241-4.131c-66.062 0-119.62 53.557-119.62 119.62 0 66.06 53.553 119.61 119.62 119.61a120.528 120.528 0 0 0 28.968-3.539 119.713 119.713 0 0 0 8.984-2.611 137.84 137.84 0 0 1-11.885-9.36 137.608 137.608 0 0 1-6.202-5.799 136.297 136.297 0 0 1-3.749-3.893c-22.715-24.472-36.612-57.243-36.612-93.266 0-36.992 14.653-70.558 38.464-95.226a139.838 139.838 0 0 1 3.856-3.846 137.803 137.803 0 0 1 6.308-5.668 137.887 137.887 0 0 1 12.028-9.103 119.98 119.98 0 0 0-8.919-2.787m221.27 98.007a139.13 139.13 0 0 1 1.263 18.623c0 16.046-2.766 31.444-7.829 45.756a133.266 133.266 0 0 1-1.724 4.626l6.893 2.746 8.729 3.476a153.345 153.345 0 0 1-10.98 22.267l-7.722-5.398-6.098-4.262a137.377 137.377 0 0 1-4.129 6.611c-24.569 36.953-66.575 61.311-114.28 61.311a137.187 137.187 0 0 1-50.301-9.519 137.253 137.253 0 0 1-4.386-1.829c-2.231-.972-4.43-2-6.597-3.084a136.804 136.804 0 0 1-6.785-3.63 128.316 128.316 0 0 1-21.044 6.476 130.064 130.064 0 0 1-27.525 2.939c-5.952 0-11.807-.41-17.545-1.186v11.687c-47.353-5.868-87.438-35.177-108.28-75.958-1.506-2.943.317 1.31-.982-1.749l-12.972 2.059c-4.076-8.46-7.828-18.427-10.767-32.195l24.257-2.727c-.699-2.652-.383-1.799-.915-4.514a130.18 130.18 0 0 1-2.428-25.048c0-71.595 58.038-129.63 129.63-129.63 10.329 0 20.368 1.233 30 3.516 4.071.965 8.063 2.127 11.975 3.465.891.304 1.789.594 2.672.916 2.115.775 4.194 1.625 6.256 2.506a136.833 136.833 0 0 1 17.947-8.194 136.293 136.293 0 0 1 11.726-3.763 137.333 137.333 0 0 1 36.062-4.801c64.248 0 118.17 44.185 133.05 103.83l7.379-1.056c-4.883-20.026-13.934-38.415-26.188-54.198l8.534-4.31c15.737 20.773 26.325 45.657 29.862 72.763l-9.37.83z" fill="#00868e"/><path d="M554.65 454.96a89.134 89.134 0 0 1-28.527-5.896c21.724-21.656 35.173-51.611 35.173-84.709 0-13.873-2.363-27.191-6.707-39.58l-12.005 2.938c4.153 11.435 6.425 23.771 6.425 36.642 0 31.303-13.42 59.455-34.8 79.071a89.816 89.816 0 0 1-9.978-6.562c20.346-17.563 33.238-43.523 33.238-72.509 0-28.309-12.292-53.734-31.815-71.269 14.298-10.416 31.794-16.689 50.743-17.09 18.867 24.449 30.103 55.086 30.103 88.359 0 34.293-11.926 65.797-31.85 90.605" fill="#00868e"/><path d="m393.19 500.78-2.466 8.942c-37.188-13.021-67.852-39.919-85.788-74.484l9.666-1.535c16.934 30.994 44.882 55.11 78.588 67.077" fill="#e5ad23"/></g></svg> \ No newline at end of file diff --git a/neosensor/libraries/ArduinoJson/src/ArduinoJson.h b/neosensor/libraries/ArduinoJson/src/ArduinoJson.h index f79212dbc2a5d4067a709cd0c5b7842d59ceb122..c9ac0ca64285f408533114bdb3c7e1bdb3e2312f 100644 --- a/neosensor/libraries/ArduinoJson/src/ArduinoJson.h +++ b/neosensor/libraries/ArduinoJson/src/ArduinoJson.h @@ -1,5 +1,5 @@ // ArduinoJson - https://arduinojson.org -// Copyright © 2014-2022, Benoit BLANCHON +// Copyright © 2014-2023, Benoit BLANCHON // MIT License #pragma once diff --git a/neosensor/libraries/ArduinoJson/src/ArduinoJson.hpp b/neosensor/libraries/ArduinoJson/src/ArduinoJson.hpp index 3a490f33e0a3aa712766c21d5550d9714b847370..2d1b0be13374bf6468c3a8015587045b528bd741 100644 --- a/neosensor/libraries/ArduinoJson/src/ArduinoJson.hpp +++ b/neosensor/libraries/ArduinoJson/src/ArduinoJson.hpp @@ -1,15 +1,20 @@ // ArduinoJson - https://arduinojson.org -// Copyright © 2014-2022, Benoit BLANCHON +// Copyright © 2014-2023, Benoit BLANCHON // MIT License #pragma once +#if __cplusplus < 201103L && (!defined(_MSC_VER) || _MSC_VER < 1910) +# error ArduinoJson requires C++11 or newer. Configure your compiler for C++11 or downgrade ArduinoJson to 6.20. +#endif + #include "ArduinoJson/Configuration.hpp" // Include Arduino.h before stdlib.h to avoid conflict with atexit() // https://github.com/bblanchon/ArduinoJson/pull/1693#issuecomment-1001060240 #if ARDUINOJSON_ENABLE_ARDUINO_STRING || ARDUINOJSON_ENABLE_ARDUINO_STREAM || \ - ARDUINOJSON_ENABLE_ARDUINO_PRINT || ARDUINOJSON_ENABLE_PROGMEM + ARDUINOJSON_ENABLE_ARDUINO_PRINT || \ + (ARDUINOJSON_ENABLE_PROGMEM && defined(ARDUINO)) # include <Arduino.h> #endif @@ -45,36 +50,3 @@ #include "ArduinoJson/MsgPack/MsgPackSerializer.hpp" #include "ArduinoJson/compatibility.hpp" - -namespace ArduinoJson { -using ARDUINOJSON_NAMESPACE::BasicJsonDocument; -using ARDUINOJSON_NAMESPACE::copyArray; -using ARDUINOJSON_NAMESPACE::DeserializationError; -using ARDUINOJSON_NAMESPACE::deserializeJson; -using ARDUINOJSON_NAMESPACE::deserializeMsgPack; -using ARDUINOJSON_NAMESPACE::DynamicJsonDocument; -using ARDUINOJSON_NAMESPACE::JsonArray; -using ARDUINOJSON_NAMESPACE::JsonArrayConst; -using ARDUINOJSON_NAMESPACE::JsonDocument; -using ARDUINOJSON_NAMESPACE::JsonFloat; -using ARDUINOJSON_NAMESPACE::JsonInteger; -using ARDUINOJSON_NAMESPACE::JsonObject; -using ARDUINOJSON_NAMESPACE::JsonObjectConst; -using ARDUINOJSON_NAMESPACE::JsonPair; -using ARDUINOJSON_NAMESPACE::JsonPairConst; -using ARDUINOJSON_NAMESPACE::JsonString; -using ARDUINOJSON_NAMESPACE::JsonUInt; -using ARDUINOJSON_NAMESPACE::JsonVariant; -using ARDUINOJSON_NAMESPACE::JsonVariantConst; -using ARDUINOJSON_NAMESPACE::measureJson; -using ARDUINOJSON_NAMESPACE::serialized; -using ARDUINOJSON_NAMESPACE::serializeJson; -using ARDUINOJSON_NAMESPACE::serializeJsonPretty; -using ARDUINOJSON_NAMESPACE::serializeMsgPack; -using ARDUINOJSON_NAMESPACE::StaticJsonDocument; - -namespace DeserializationOption { -using ARDUINOJSON_NAMESPACE::Filter; -using ARDUINOJSON_NAMESPACE::NestingLimit; -} // namespace DeserializationOption -} // namespace ArduinoJson diff --git a/neosensor/libraries/ArduinoJson/src/ArduinoJson/Array/ElementProxy.hpp b/neosensor/libraries/ArduinoJson/src/ArduinoJson/Array/ElementProxy.hpp index b3e00a2c01c248480c9c580bc2270ae961cdcdf9..d6e9aa5d10a58ad1f908a4672810bde3e6aab400 100644 --- a/neosensor/libraries/ArduinoJson/src/ArduinoJson/Array/ElementProxy.hpp +++ b/neosensor/libraries/ArduinoJson/src/ArduinoJson/Array/ElementProxy.hpp @@ -1,26 +1,26 @@ // ArduinoJson - https://arduinojson.org -// Copyright © 2014-2022, Benoit BLANCHON +// Copyright © 2014-2023, Benoit BLANCHON // MIT License #pragma once #include <ArduinoJson/Variant/VariantRefBase.hpp> -namespace ARDUINOJSON_NAMESPACE { +ARDUINOJSON_BEGIN_PRIVATE_NAMESPACE // A proxy class to get or set an element of an array. // https://arduinojson.org/v6/api/jsonarray/subscript/ template <typename TUpstream> -class ElementProxy : public VariantRefBase<ElementProxy<TUpstream> >, - public VariantOperators<ElementProxy<TUpstream> > { +class ElementProxy : public VariantRefBase<ElementProxy<TUpstream>>, + public VariantOperators<ElementProxy<TUpstream>> { friend class VariantAttorney; public: ElementProxy(TUpstream upstream, size_t index) - : _upstream(upstream), _index(index) {} + : upstream_(upstream), index_(index) {} ElementProxy(const ElementProxy& src) - : _upstream(src._upstream), _index(src._index) {} + : upstream_(src.upstream_), index_(src.index_) {} FORCE_INLINE ElementProxy& operator=(const ElementProxy& src) { this->set(src); @@ -41,20 +41,20 @@ class ElementProxy : public VariantRefBase<ElementProxy<TUpstream> >, private: FORCE_INLINE MemoryPool* getPool() const { - return VariantAttorney::getPool(_upstream); + return VariantAttorney::getPool(upstream_); } FORCE_INLINE VariantData* getData() const { - return variantGetElement(VariantAttorney::getData(_upstream), _index); + return variantGetElement(VariantAttorney::getData(upstream_), index_); } FORCE_INLINE VariantData* getOrCreateData() const { - return variantGetOrAddElement(VariantAttorney::getOrCreateData(_upstream), - _index, VariantAttorney::getPool(_upstream)); + return variantGetOrAddElement(VariantAttorney::getOrCreateData(upstream_), + index_, VariantAttorney::getPool(upstream_)); } - TUpstream _upstream; - size_t _index; + TUpstream upstream_; + size_t index_; }; -} // namespace ARDUINOJSON_NAMESPACE +ARDUINOJSON_END_PRIVATE_NAMESPACE diff --git a/neosensor/libraries/ArduinoJson/src/ArduinoJson/Array/JsonArray.hpp b/neosensor/libraries/ArduinoJson/src/ArduinoJson/Array/JsonArray.hpp index a26b1f1f1c7bf8ee894d17fe84e71d685eb79559..d208e417542115779fcaf40a04fdf72a7ec5d17e 100644 --- a/neosensor/libraries/ArduinoJson/src/ArduinoJson/Array/JsonArray.hpp +++ b/neosensor/libraries/ArduinoJson/src/ArduinoJson/Array/JsonArray.hpp @@ -1,5 +1,5 @@ // ArduinoJson - https://arduinojson.org -// Copyright © 2014-2022, Benoit BLANCHON +// Copyright © 2014-2023, Benoit BLANCHON // MIT License #pragma once @@ -7,45 +7,45 @@ #include <ArduinoJson/Array/ElementProxy.hpp> #include <ArduinoJson/Array/JsonArrayConst.hpp> -namespace ARDUINOJSON_NAMESPACE { +ARDUINOJSON_BEGIN_PUBLIC_NAMESPACE class JsonObject; // A reference to an array in a JsonDocument // https://arduinojson.org/v6/api/jsonarray/ -class JsonArray : public VariantOperators<JsonArray> { - friend class VariantAttorney; +class JsonArray : public detail::VariantOperators<JsonArray> { + friend class detail::VariantAttorney; public: typedef JsonArrayIterator iterator; // Constructs an unbound reference. - FORCE_INLINE JsonArray() : _data(0), _pool(0) {} + FORCE_INLINE JsonArray() : data_(0), pool_(0) {} // INTERNAL USE ONLY - FORCE_INLINE JsonArray(MemoryPool* pool, CollectionData* data) - : _data(data), _pool(pool) {} + FORCE_INLINE JsonArray(detail::MemoryPool* pool, detail::CollectionData* data) + : data_(data), pool_(pool) {} // Returns a JsonVariant pointing to the array. // https://arduinojson.org/v6/api/jsonvariant/ operator JsonVariant() { - void* data = _data; // prevent warning cast-align - return JsonVariant(_pool, reinterpret_cast<VariantData*>(data)); + void* data = data_; // prevent warning cast-align + return JsonVariant(pool_, reinterpret_cast<detail::VariantData*>(data)); } // Returns a read-only reference to the array. // https://arduinojson.org/v6/api/jsonarrayconst/ operator JsonArrayConst() const { - return JsonArrayConst(_data); + return JsonArrayConst(data_); } // Appends a new (null) element to the array. // Returns a reference to the new element. // https://arduinojson.org/v6/api/jsonarray/add/ JsonVariant add() const { - if (!_data) + if (!data_) return JsonVariant(); - return JsonVariant(_pool, _data->addElement(_pool)); + return JsonVariant(pool_, data_->addElement(pool_)); } // Appends a value to the array. @@ -65,9 +65,9 @@ class JsonArray : public VariantOperators<JsonArray> { // Returns an iterator to the first element of the array. // https://arduinojson.org/v6/api/jsonarray/begin/ FORCE_INLINE iterator begin() const { - if (!_data) + if (!data_) return iterator(); - return iterator(_pool, _data->head()); + return iterator(pool_, data_->head()); } // Returns an iterator following the last element of the array. @@ -79,47 +79,47 @@ class JsonArray : public VariantOperators<JsonArray> { // Copies an array. // https://arduinojson.org/v6/api/jsonarray/set/ FORCE_INLINE bool set(JsonArrayConst src) const { - if (!_data || !src._data) + if (!data_ || !src.data_) return false; - return _data->copyFrom(*src._data, _pool); + return data_->copyFrom(*src.data_, pool_); } // Compares the content of two arrays. FORCE_INLINE bool operator==(JsonArray rhs) const { - return JsonArrayConst(_data) == JsonArrayConst(rhs._data); + return JsonArrayConst(data_) == JsonArrayConst(rhs.data_); } // Removes the element at the specified iterator. // ⚠️ Doesn't release the memory associated with the removed element. // https://arduinojson.org/v6/api/jsonarray/remove/ FORCE_INLINE void remove(iterator it) const { - if (!_data) + if (!data_) return; - _data->removeSlot(it._slot); + data_->removeSlot(it.slot_); } // Removes the element at the specified index. // ⚠️ Doesn't release the memory associated with the removed element. // https://arduinojson.org/v6/api/jsonarray/remove/ FORCE_INLINE void remove(size_t index) const { - if (!_data) + if (!data_) return; - _data->removeElement(index); + data_->removeElement(index); } // Removes all the elements of the array. // ⚠️ Doesn't release the memory associated with the removed elements. // https://arduinojson.org/v6/api/jsonarray/clear/ void clear() const { - if (!_data) + if (!data_) return; - _data->clear(); + data_->clear(); } // Gets or sets the element at the specified index. // https://arduinojson.org/v6/api/jsonarray/subscript/ - FORCE_INLINE ElementProxy<JsonArray> operator[](size_t index) const { - return ElementProxy<JsonArray>(*this, index); + FORCE_INLINE detail::ElementProxy<JsonArray> operator[](size_t index) const { + return {*this, index}; } // Creates an object and appends it to the array. @@ -133,69 +133,69 @@ class JsonArray : public VariantOperators<JsonArray> { } operator JsonVariantConst() const { - return JsonVariantConst(collectionToVariant(_data)); + return JsonVariantConst(collectionToVariant(data_)); } // Returns true if the reference is unbound. // https://arduinojson.org/v6/api/jsonarray/isnull/ FORCE_INLINE bool isNull() const { - return _data == 0; + return data_ == 0; } // Returns true if the reference is bound. // https://arduinojson.org/v6/api/jsonarray/isnull/ FORCE_INLINE operator bool() const { - return _data != 0; + return data_ != 0; } // Returns the number of bytes occupied by the array. // https://arduinojson.org/v6/api/jsonarray/memoryusage/ FORCE_INLINE size_t memoryUsage() const { - return _data ? _data->memoryUsage() : 0; + return data_ ? data_->memoryUsage() : 0; } // Returns the depth (nesting level) of the array. // https://arduinojson.org/v6/api/jsonarray/nesting/ FORCE_INLINE size_t nesting() const { - return variantNesting(collectionToVariant(_data)); + return variantNesting(collectionToVariant(data_)); } // Returns the number of elements in the array. // https://arduinojson.org/v6/api/jsonarray/size/ FORCE_INLINE size_t size() const { - return _data ? _data->size() : 0; + return data_ ? data_->size() : 0; } private: - MemoryPool* getPool() const { - return _pool; + detail::MemoryPool* getPool() const { + return pool_; } - VariantData* getData() const { - return collectionToVariant(_data); + detail::VariantData* getData() const { + return collectionToVariant(data_); } - VariantData* getOrCreateData() const { - return collectionToVariant(_data); + detail::VariantData* getOrCreateData() const { + return collectionToVariant(data_); } - CollectionData* _data; - MemoryPool* _pool; + detail::CollectionData* data_; + detail::MemoryPool* pool_; }; template <> -struct Converter<JsonArray> : private VariantAttorney { +struct Converter<JsonArray> : private detail::VariantAttorney { static void toJson(JsonVariantConst src, JsonVariant dst) { variantCopyFrom(getData(dst), getData(src), getPool(dst)); } static JsonArray fromJson(JsonVariant src) { - VariantData* data = getData(src); - MemoryPool* pool = getPool(src); + auto data = getData(src); + auto pool = getPool(src); return JsonArray(pool, data != 0 ? data->asArray() : 0); } - static InvalidConversion<JsonVariantConst, JsonArray> fromJson( + static detail::InvalidConversion<JsonVariantConst, JsonArray> fromJson( JsonVariantConst); static bool checkJson(JsonVariantConst) { @@ -203,8 +203,9 @@ struct Converter<JsonArray> : private VariantAttorney { } static bool checkJson(JsonVariant src) { - VariantData* data = getData(src); + auto data = getData(src); return data && data->isArray(); } }; -} // namespace ARDUINOJSON_NAMESPACE + +ARDUINOJSON_END_PUBLIC_NAMESPACE diff --git a/neosensor/libraries/ArduinoJson/src/ArduinoJson/Array/JsonArrayConst.hpp b/neosensor/libraries/ArduinoJson/src/ArduinoJson/Array/JsonArrayConst.hpp index 17e65a4bbcd9699c071c625db36d41db79fc05ce..6a6463c8cd8db99ee7ad5412c0eac0be86a7615d 100644 --- a/neosensor/libraries/ArduinoJson/src/ArduinoJson/Array/JsonArrayConst.hpp +++ b/neosensor/libraries/ArduinoJson/src/ArduinoJson/Array/JsonArrayConst.hpp @@ -1,5 +1,5 @@ // ArduinoJson - https://arduinojson.org -// Copyright © 2014-2022, Benoit BLANCHON +// Copyright © 2014-2023, Benoit BLANCHON // MIT License #pragma once @@ -8,15 +8,15 @@ #include <ArduinoJson/Variant/VariantAttorney.hpp> #include <ArduinoJson/Variant/VariantData.hpp> -namespace ARDUINOJSON_NAMESPACE { +ARDUINOJSON_BEGIN_PUBLIC_NAMESPACE class JsonObject; // A read-only reference to an array in a JsonDocument // https://arduinojson.org/v6/api/jsonarrayconst/ -class JsonArrayConst : public VariantOperators<JsonArrayConst> { +class JsonArrayConst : public detail::VariantOperators<JsonArrayConst> { friend class JsonArray; - friend class VariantAttorney; + friend class detail::VariantAttorney; public: typedef JsonArrayConstIterator iterator; @@ -24,9 +24,9 @@ class JsonArrayConst : public VariantOperators<JsonArrayConst> { // Returns an iterator to the first element of the array. // https://arduinojson.org/v6/api/jsonarrayconst/begin/ FORCE_INLINE iterator begin() const { - if (!_data) + if (!data_) return iterator(); - return iterator(_data->head()); + return iterator(data_->head()); } // Returns an iterator to the element following the last element of the array. @@ -36,17 +36,18 @@ class JsonArrayConst : public VariantOperators<JsonArrayConst> { } // Creates an unbound reference. - FORCE_INLINE JsonArrayConst() : _data(0) {} + FORCE_INLINE JsonArrayConst() : data_(0) {} // INTERNAL USE ONLY - FORCE_INLINE JsonArrayConst(const CollectionData* data) : _data(data) {} + FORCE_INLINE JsonArrayConst(const detail::CollectionData* data) + : data_(data) {} // Compares the content of two arrays. // Returns true if the two arrays are equal. FORCE_INLINE bool operator==(JsonArrayConst rhs) const { - if (_data == rhs._data) + if (data_ == rhs.data_) return true; - if (!_data || !rhs._data) + if (!data_ || !rhs.data_) return false; iterator it1 = begin(); @@ -69,66 +70,66 @@ class JsonArrayConst : public VariantOperators<JsonArrayConst> { // Returns the element at the specified index. // https://arduinojson.org/v6/api/jsonarrayconst/subscript/ FORCE_INLINE JsonVariantConst operator[](size_t index) const { - return JsonVariantConst(_data ? _data->getElement(index) : 0); + return JsonVariantConst(data_ ? data_->getElement(index) : 0); } operator JsonVariantConst() const { - return JsonVariantConst(collectionToVariant(_data)); + return JsonVariantConst(collectionToVariant(data_)); } // Returns true if the reference is unbound. // https://arduinojson.org/v6/api/jsonarrayconst/isnull/ FORCE_INLINE bool isNull() const { - return _data == 0; + return data_ == 0; } // Returns true if the reference is bound. // https://arduinojson.org/v6/api/jsonarrayconst/isnull/ FORCE_INLINE operator bool() const { - return _data != 0; + return data_ != 0; } // Returns the number of bytes occupied by the array. // https://arduinojson.org/v6/api/jsonarrayconst/memoryusage/ FORCE_INLINE size_t memoryUsage() const { - return _data ? _data->memoryUsage() : 0; + return data_ ? data_->memoryUsage() : 0; } // Returns the depth (nesting level) of the array. // https://arduinojson.org/v6/api/jsonarrayconst/nesting/ FORCE_INLINE size_t nesting() const { - return variantNesting(collectionToVariant(_data)); + return variantNesting(collectionToVariant(data_)); } // Returns the number of elements in the array. // https://arduinojson.org/v6/api/jsonarrayconst/size/ FORCE_INLINE size_t size() const { - return _data ? _data->size() : 0; + return data_ ? data_->size() : 0; } private: - const VariantData* getData() const { - return collectionToVariant(_data); + const detail::VariantData* getData() const { + return collectionToVariant(data_); } - const CollectionData* _data; + const detail::CollectionData* data_; }; template <> -struct Converter<JsonArrayConst> : private VariantAttorney { +struct Converter<JsonArrayConst> : private detail::VariantAttorney { static void toJson(JsonVariantConst src, JsonVariant dst) { variantCopyFrom(getData(dst), getData(src), getPool(dst)); } static JsonArrayConst fromJson(JsonVariantConst src) { - const VariantData* data = getData(src); + auto data = getData(src); return data ? data->asArray() : 0; } static bool checkJson(JsonVariantConst src) { - const VariantData* data = getData(src); + auto data = getData(src); return data && data->isArray(); } }; -} // namespace ARDUINOJSON_NAMESPACE +ARDUINOJSON_END_PUBLIC_NAMESPACE diff --git a/neosensor/libraries/ArduinoJson/src/ArduinoJson/Array/JsonArrayImpl.hpp b/neosensor/libraries/ArduinoJson/src/ArduinoJson/Array/JsonArrayImpl.hpp index 45a520f49319c5abf1e864ca54ad75374ce3a9c8..dc0487af8c95c7365e952352bdcfc658f6a3481b 100644 --- a/neosensor/libraries/ArduinoJson/src/ArduinoJson/Array/JsonArrayImpl.hpp +++ b/neosensor/libraries/ArduinoJson/src/ArduinoJson/Array/JsonArrayImpl.hpp @@ -1,5 +1,5 @@ // ArduinoJson - https://arduinojson.org -// Copyright © 2014-2022, Benoit BLANCHON +// Copyright © 2014-2023, Benoit BLANCHON // MIT License #pragma once @@ -7,12 +7,16 @@ #include <ArduinoJson/Array/JsonArray.hpp> #include <ArduinoJson/Object/JsonObject.hpp> -namespace ARDUINOJSON_NAMESPACE { +ARDUINOJSON_BEGIN_PUBLIC_NAMESPACE inline JsonObject JsonArray::createNestedObject() const { return add().to<JsonObject>(); } +ARDUINOJSON_END_PUBLIC_NAMESPACE + +ARDUINOJSON_BEGIN_PRIVATE_NAMESPACE + template <typename TDerived> inline JsonArray VariantRefBase<TDerived>::createNestedArray() const { return add().template to<JsonArray>(); @@ -29,4 +33,4 @@ inline ElementProxy<TDerived> VariantRefBase<TDerived>::operator[]( return ElementProxy<TDerived>(derived(), index); } -} // namespace ARDUINOJSON_NAMESPACE +ARDUINOJSON_END_PRIVATE_NAMESPACE diff --git a/neosensor/libraries/ArduinoJson/src/ArduinoJson/Array/JsonArrayIterator.hpp b/neosensor/libraries/ArduinoJson/src/ArduinoJson/Array/JsonArrayIterator.hpp index 382d117756a8451be6bf954f7cee5890f2fd34e3..d9048b28c7e976795795b47875e085d09825f357 100644 --- a/neosensor/libraries/ArduinoJson/src/ArduinoJson/Array/JsonArrayIterator.hpp +++ b/neosensor/libraries/ArduinoJson/src/ArduinoJson/Array/JsonArrayIterator.hpp @@ -1,5 +1,5 @@ // ArduinoJson - https://arduinojson.org -// Copyright © 2014-2022, Benoit BLANCHON +// Copyright © 2014-2023, Benoit BLANCHON // MIT License #pragma once @@ -7,111 +7,115 @@ #include <ArduinoJson/Variant/JsonVariant.hpp> #include <ArduinoJson/Variant/SlotFunctions.hpp> -namespace ARDUINOJSON_NAMESPACE { +ARDUINOJSON_BEGIN_PUBLIC_NAMESPACE class VariantPtr { public: - VariantPtr(MemoryPool* pool, VariantData* data) : _variant(pool, data) {} + VariantPtr(detail::MemoryPool* pool, detail::VariantData* data) + : variant_(pool, data) {} JsonVariant* operator->() { - return &_variant; + return &variant_; } JsonVariant& operator*() { - return _variant; + return variant_; } private: - JsonVariant _variant; + JsonVariant variant_; }; class JsonArrayIterator { friend class JsonArray; public: - JsonArrayIterator() : _slot(0) {} - explicit JsonArrayIterator(MemoryPool* pool, VariantSlot* slot) - : _pool(pool), _slot(slot) {} + JsonArrayIterator() : slot_(0) {} + explicit JsonArrayIterator(detail::MemoryPool* pool, + detail::VariantSlot* slot) + : pool_(pool), slot_(slot) {} JsonVariant operator*() const { - return JsonVariant(_pool, _slot->data()); + return JsonVariant(pool_, slot_->data()); } VariantPtr operator->() { - return VariantPtr(_pool, _slot->data()); + return VariantPtr(pool_, slot_->data()); } bool operator==(const JsonArrayIterator& other) const { - return _slot == other._slot; + return slot_ == other.slot_; } bool operator!=(const JsonArrayIterator& other) const { - return _slot != other._slot; + return slot_ != other.slot_; } JsonArrayIterator& operator++() { - _slot = _slot->next(); + slot_ = slot_->next(); return *this; } JsonArrayIterator& operator+=(size_t distance) { - _slot = _slot->next(distance); + slot_ = slot_->next(distance); return *this; } private: - MemoryPool* _pool; - VariantSlot* _slot; + detail::MemoryPool* pool_; + detail::VariantSlot* slot_; }; class VariantConstPtr { public: - VariantConstPtr(const VariantData* data) : _variant(data) {} + VariantConstPtr(const detail::VariantData* data) : variant_(data) {} JsonVariantConst* operator->() { - return &_variant; + return &variant_; } JsonVariantConst& operator*() { - return _variant; + return variant_; } private: - JsonVariantConst _variant; + JsonVariantConst variant_; }; class JsonArrayConstIterator { friend class JsonArray; public: - JsonArrayConstIterator() : _slot(0) {} - explicit JsonArrayConstIterator(const VariantSlot* slot) : _slot(slot) {} + JsonArrayConstIterator() : slot_(0) {} + explicit JsonArrayConstIterator(const detail::VariantSlot* slot) + : slot_(slot) {} JsonVariantConst operator*() const { - return JsonVariantConst(_slot->data()); + return JsonVariantConst(slot_->data()); } VariantConstPtr operator->() { - return VariantConstPtr(_slot->data()); + return VariantConstPtr(slot_->data()); } bool operator==(const JsonArrayConstIterator& other) const { - return _slot == other._slot; + return slot_ == other.slot_; } bool operator!=(const JsonArrayConstIterator& other) const { - return _slot != other._slot; + return slot_ != other.slot_; } JsonArrayConstIterator& operator++() { - _slot = _slot->next(); + slot_ = slot_->next(); return *this; } JsonArrayConstIterator& operator+=(size_t distance) { - _slot = _slot->next(distance); + slot_ = slot_->next(distance); return *this; } private: - const VariantSlot* _slot; + const detail::VariantSlot* slot_; }; -} // namespace ARDUINOJSON_NAMESPACE + +ARDUINOJSON_END_PUBLIC_NAMESPACE diff --git a/neosensor/libraries/ArduinoJson/src/ArduinoJson/Array/Utilities.hpp b/neosensor/libraries/ArduinoJson/src/ArduinoJson/Array/Utilities.hpp index 1bff6830ca8e37af5a77c5d61bb4e0fe48cc4523..398e11d456975904afc7a3ca94a036488cf4dc20 100644 --- a/neosensor/libraries/ArduinoJson/src/ArduinoJson/Array/Utilities.hpp +++ b/neosensor/libraries/ArduinoJson/src/ArduinoJson/Array/Utilities.hpp @@ -1,5 +1,5 @@ // ArduinoJson - https://arduinojson.org -// Copyright © 2014-2022, Benoit BLANCHON +// Copyright © 2014-2023, Benoit BLANCHON // MIT License #pragma once @@ -7,21 +7,21 @@ #include <ArduinoJson/Array/JsonArray.hpp> #include <ArduinoJson/Document/JsonDocument.hpp> -namespace ARDUINOJSON_NAMESPACE { +ARDUINOJSON_BEGIN_PUBLIC_NAMESPACE // Copies a value to a JsonVariant. // This is a degenerated form of copyArray() to stop the recursion. template <typename T> -inline typename enable_if<!is_array<T>::value, bool>::type copyArray( - const T& src, JsonVariant dst) { +inline typename detail::enable_if<!detail::is_array<T>::value, bool>::type +copyArray(const T& src, JsonVariant dst) { return dst.set(src); } // Copies values from an array to a JsonArray or a JsonVariant. // https://arduinojson.org/v6/api/misc/copyarray/ template <typename T, size_t N, typename TDestination> -inline typename enable_if<!is_base_of<JsonDocument, TDestination>::value, - bool>::type +inline typename detail::enable_if< + !detail::is_base_of<JsonDocument, TDestination>::value, bool>::type copyArray(T (&src)[N], const TDestination& dst) { return copyArray(src, N, dst); } @@ -29,8 +29,8 @@ copyArray(T (&src)[N], const TDestination& dst) { // Copies values from an array to a JsonArray or a JsonVariant. // https://arduinojson.org/v6/api/misc/copyarray/ template <typename T, typename TDestination> -inline typename enable_if<!is_base_of<JsonDocument, TDestination>::value, - bool>::type +inline typename detail::enable_if< + !detail::is_base_of<JsonDocument, TDestination>::value, bool>::type copyArray(const T* src, size_t len, const TDestination& dst) { bool ok = true; for (size_t i = 0; i < len; i++) { @@ -63,8 +63,8 @@ inline bool copyArray(const T* src, size_t len, JsonDocument& dst) { // Copies a value from a JsonVariant. // This is a degenerated form of copyArray() to stop the recursion. template <typename T> -inline typename enable_if<!is_array<T>::value, size_t>::type copyArray( - JsonVariantConst src, T& dst) { +inline typename detail::enable_if<!detail::is_array<T>::value, size_t>::type +copyArray(JsonVariantConst src, T& dst) { dst = src.as<T>(); return 1; } @@ -103,11 +103,12 @@ inline size_t copyArray(JsonVariantConst src, char (&dst)[N]) { // Copies values from a JsonDocument to an array. // https://arduinojson.org/v6/api/misc/copyarray/ template <typename TSource, typename T> -inline typename enable_if<is_array<T>::value && - is_base_of<JsonDocument, TSource>::value, - size_t>::type +inline typename detail::enable_if< + detail::is_array<T>::value && + detail::is_base_of<JsonDocument, TSource>::value, + size_t>::type copyArray(const TSource& src, T& dst) { return copyArray(src.template as<JsonArrayConst>(), dst); } -} // namespace ARDUINOJSON_NAMESPACE +ARDUINOJSON_END_PUBLIC_NAMESPACE diff --git a/neosensor/libraries/ArduinoJson/src/ArduinoJson/Collection/CollectionData.hpp b/neosensor/libraries/ArduinoJson/src/ArduinoJson/Collection/CollectionData.hpp index 560e7e33672de85edfce6f80d52c96a12887f595..090c98b9e278103bb623199b3ca9e6614798fa68 100644 --- a/neosensor/libraries/ArduinoJson/src/ArduinoJson/Collection/CollectionData.hpp +++ b/neosensor/libraries/ArduinoJson/src/ArduinoJson/Collection/CollectionData.hpp @@ -1,5 +1,5 @@ // ArduinoJson - https://arduinojson.org -// Copyright © 2014-2022, Benoit BLANCHON +// Copyright © 2014-2023, Benoit BLANCHON // MIT License #pragma once @@ -9,15 +9,15 @@ #include <stddef.h> // size_t -namespace ARDUINOJSON_NAMESPACE { +ARDUINOJSON_BEGIN_PRIVATE_NAMESPACE class MemoryPool; class VariantData; class VariantSlot; class CollectionData { - VariantSlot* _head; - VariantSlot* _tail; + VariantSlot* head_; + VariantSlot* tail_; public: // Must be a POD! @@ -67,7 +67,7 @@ class CollectionData { bool copyFrom(const CollectionData& src, MemoryPool* pool); VariantSlot* head() const { - return _head; + return head_; } void movePointers(ptrdiff_t stringDistance, ptrdiff_t variantDistance); @@ -91,4 +91,5 @@ inline VariantData* collectionToVariant(CollectionData* collection) { void* data = collection; // prevent warning cast-align return reinterpret_cast<VariantData*>(data); } -} // namespace ARDUINOJSON_NAMESPACE + +ARDUINOJSON_END_PRIVATE_NAMESPACE diff --git a/neosensor/libraries/ArduinoJson/src/ArduinoJson/Collection/CollectionImpl.hpp b/neosensor/libraries/ArduinoJson/src/ArduinoJson/Collection/CollectionImpl.hpp index f933f527ec76c29ddac38791738416a000d6be1e..134d5bd646dfc4cbee086b24ea62d81b1bfd33b1 100644 --- a/neosensor/libraries/ArduinoJson/src/ArduinoJson/Collection/CollectionImpl.hpp +++ b/neosensor/libraries/ArduinoJson/src/ArduinoJson/Collection/CollectionImpl.hpp @@ -1,5 +1,5 @@ // ArduinoJson - https://arduinojson.org -// Copyright © 2014-2022, Benoit BLANCHON +// Copyright © 2014-2023, Benoit BLANCHON // MIT License #pragma once @@ -9,20 +9,20 @@ #include <ArduinoJson/Strings/StringAdapters.hpp> #include <ArduinoJson/Variant/VariantData.hpp> -namespace ARDUINOJSON_NAMESPACE { +ARDUINOJSON_BEGIN_PRIVATE_NAMESPACE inline VariantSlot* CollectionData::addSlot(MemoryPool* pool) { VariantSlot* slot = pool->allocVariant(); if (!slot) return 0; - if (_tail) { - ARDUINOJSON_ASSERT(pool->owns(_tail)); // Can't alter a linked array/object - _tail->setNextNotNull(slot); - _tail = slot; + if (tail_) { + ARDUINOJSON_ASSERT(pool->owns(tail_)); // Can't alter a linked array/object + tail_->setNextNotNull(slot); + tail_ = slot; } else { - _head = slot; - _tail = slot; + head_ = slot; + tail_ = slot; } slot->clear(); @@ -45,8 +45,8 @@ inline VariantData* CollectionData::addMember(TAdaptedString key, } inline void CollectionData::clear() { - _head = 0; - _tail = 0; + head_ = 0; + tail_ = 0; } template <typename TAdaptedString> @@ -57,7 +57,7 @@ inline bool CollectionData::containsKey(const TAdaptedString& key) const { inline bool CollectionData::copyFrom(const CollectionData& src, MemoryPool* pool) { clear(); - for (VariantSlot* s = src._head; s; s = s->next()) { + for (VariantSlot* s = src.head_; s; s = s->next()) { VariantData* var; if (s->key() != 0) { JsonString key(s->key(), @@ -78,7 +78,7 @@ template <typename TAdaptedString> inline VariantSlot* CollectionData::getSlot(TAdaptedString key) const { if (key.isNull()) return 0; - VariantSlot* slot = _head; + VariantSlot* slot = head_; while (slot) { if (stringEquals(key, adaptString(slot->key()))) break; @@ -88,13 +88,13 @@ inline VariantSlot* CollectionData::getSlot(TAdaptedString key) const { } inline VariantSlot* CollectionData::getSlot(size_t index) const { - if (!_head) + if (!head_) return 0; - return _head->next(index); + return head_->next(index); } inline VariantSlot* CollectionData::getPreviousSlot(VariantSlot* target) const { - VariantSlot* current = _head; + VariantSlot* current = head_; while (current) { VariantSlot* next = current->next(); if (next == target) @@ -132,7 +132,7 @@ inline VariantData* CollectionData::getElement(size_t index) const { inline VariantData* CollectionData::getOrAddElement(size_t index, MemoryPool* pool) { - VariantSlot* slot = _head; + VariantSlot* slot = head_; while (slot && index > 0) { slot = slot->next(); index--; @@ -154,9 +154,9 @@ inline void CollectionData::removeSlot(VariantSlot* slot) { if (prev) prev->setNext(next); else - _head = next; + head_ = next; if (!next) - _tail = prev; + tail_ = prev; } inline void CollectionData::removeElement(size_t index) { @@ -165,7 +165,7 @@ inline void CollectionData::removeElement(size_t index) { inline size_t CollectionData::memoryUsage() const { size_t total = 0; - for (VariantSlot* s = _head; s; s = s->next()) { + for (VariantSlot* s = head_; s; s = s->next()) { total += sizeof(VariantSlot) + s->data()->memoryUsage(); if (s->ownsKey()) total += strlen(s->key()) + 1; @@ -174,7 +174,7 @@ inline size_t CollectionData::memoryUsage() const { } inline size_t CollectionData::size() const { - return slotSize(_head); + return slotSize(head_); } template <typename T> @@ -188,10 +188,10 @@ inline void movePointer(T*& p, ptrdiff_t offset) { inline void CollectionData::movePointers(ptrdiff_t stringDistance, ptrdiff_t variantDistance) { - movePointer(_head, variantDistance); - movePointer(_tail, variantDistance); - for (VariantSlot* slot = _head; slot; slot = slot->next()) + movePointer(head_, variantDistance); + movePointer(tail_, variantDistance); + for (VariantSlot* slot = head_; slot; slot = slot->next()) slot->movePointers(stringDistance, variantDistance); } -} // namespace ARDUINOJSON_NAMESPACE +ARDUINOJSON_END_PRIVATE_NAMESPACE diff --git a/neosensor/libraries/ArduinoJson/src/ArduinoJson/Configuration.hpp b/neosensor/libraries/ArduinoJson/src/ArduinoJson/Configuration.hpp index ed5687a39bb3c8d1c2c7b83339f1b5fac74e1f83..ac0ea660a28ac3c23fdfc86e5cd0dc2be5d6ee5b 100644 --- a/neosensor/libraries/ArduinoJson/src/ArduinoJson/Configuration.hpp +++ b/neosensor/libraries/ArduinoJson/src/ArduinoJson/Configuration.hpp @@ -1,31 +1,9 @@ // ArduinoJson - https://arduinojson.org -// Copyright © 2014-2022, Benoit BLANCHON +// Copyright © 2014-2023, Benoit BLANCHON // MIT License #pragma once -#if __cplusplus >= 201103L -# define ARDUINOJSON_HAS_LONG_LONG 1 -# define ARDUINOJSON_HAS_RVALUE_REFERENCES 1 -#else -# define ARDUINOJSON_HAS_LONG_LONG 0 -# define ARDUINOJSON_HAS_RVALUE_REFERENCES 0 -#endif - -#ifndef ARDUINOJSON_HAS_NULLPTR -# if __cplusplus >= 201103L -# define ARDUINOJSON_HAS_NULLPTR 1 -# else -# define ARDUINOJSON_HAS_NULLPTR 0 -# endif -#endif - -#if defined(_MSC_VER) && !ARDUINOJSON_HAS_LONG_LONG -# define ARDUINOJSON_HAS_INT64 1 -#else -# define ARDUINOJSON_HAS_INT64 0 -#endif - // Support std::istream and std::ostream #ifndef ARDUINOJSON_ENABLE_STD_STREAM # ifdef __has_include @@ -83,8 +61,7 @@ // Store integral values with long (0) or long long (1) #ifndef ARDUINOJSON_USE_LONG_LONG -# if ARDUINOJSON_HAS_LONG_LONG && defined(__SIZEOF_POINTER__) && \ - __SIZEOF_POINTER__ >= 4 || \ +# if defined(__SIZEOF_POINTER__) && __SIZEOF_POINTER__ >= 4 || \ defined(_MSC_VER) # define ARDUINOJSON_USE_LONG_LONG 1 # endif @@ -153,9 +130,13 @@ # define ARDUINOJSON_ENABLE_ARDUINO_PRINT 0 # endif -// Disable support for PROGMEM +// Enable PROGMEM support on AVR only # ifndef ARDUINOJSON_ENABLE_PROGMEM -# define ARDUINOJSON_ENABLE_PROGMEM 0 +# ifdef __AVR__ +# define ARDUINOJSON_ENABLE_PROGMEM 1 +# else +# define ARDUINOJSON_ENABLE_PROGMEM 0 +# endif # endif #endif // ARDUINO @@ -230,7 +211,7 @@ # endif #endif -#if ARDUINOJSON_HAS_NULLPTR && defined(nullptr) +#if defined(nullptr) # error nullptr is defined as a macro. Remove the faulty #define or #undef nullptr // See https://github.com/bblanchon/ArduinoJson/issues/1355 #endif diff --git a/neosensor/libraries/ArduinoJson/src/ArduinoJson/Deserialization/DeserializationError.hpp b/neosensor/libraries/ArduinoJson/src/ArduinoJson/Deserialization/DeserializationError.hpp index 96b3a178b1a1dea69403bc97c4289eec5864212d..1bfc393925755e3850de4869194fba4ab2093b3f 100644 --- a/neosensor/libraries/ArduinoJson/src/ArduinoJson/Deserialization/DeserializationError.hpp +++ b/neosensor/libraries/ArduinoJson/src/ArduinoJson/Deserialization/DeserializationError.hpp @@ -1,21 +1,20 @@ // ArduinoJson - https://arduinojson.org -// Copyright © 2014-2022, Benoit BLANCHON +// Copyright © 2014-2023, Benoit BLANCHON // MIT License #pragma once -#include <ArduinoJson/Misc/SafeBoolIdiom.hpp> #include <ArduinoJson/Namespace.hpp> +#include <ArduinoJson/Polyfills/pgmspace_generic.hpp> #include <ArduinoJson/Polyfills/preprocessor.hpp> -#include <ArduinoJson/Polyfills/static_array.hpp> #if ARDUINOJSON_ENABLE_STD_STREAM # include <ostream> #endif -namespace ARDUINOJSON_NAMESPACE { +ARDUINOJSON_BEGIN_PUBLIC_NAMESPACE -class DeserializationError : public SafeBoolIdom<DeserializationError> { +class DeserializationError { public: enum Code { Ok, @@ -27,68 +26,68 @@ class DeserializationError : public SafeBoolIdom<DeserializationError> { }; DeserializationError() {} - DeserializationError(Code c) : _code(c) {} + DeserializationError(Code c) : code_(c) {} // Compare with DeserializationError friend bool operator==(const DeserializationError& lhs, const DeserializationError& rhs) { - return lhs._code == rhs._code; + return lhs.code_ == rhs.code_; } friend bool operator!=(const DeserializationError& lhs, const DeserializationError& rhs) { - return lhs._code != rhs._code; + return lhs.code_ != rhs.code_; } // Compare with Code friend bool operator==(const DeserializationError& lhs, Code rhs) { - return lhs._code == rhs; + return lhs.code_ == rhs; } friend bool operator==(Code lhs, const DeserializationError& rhs) { - return lhs == rhs._code; + return lhs == rhs.code_; } friend bool operator!=(const DeserializationError& lhs, Code rhs) { - return lhs._code != rhs; + return lhs.code_ != rhs; } friend bool operator!=(Code lhs, const DeserializationError& rhs) { - return lhs != rhs._code; + return lhs != rhs.code_; } - // Behaves like a bool - operator bool_type() const { - return _code != Ok ? safe_true() : safe_false(); + // Returns true if there is an error + explicit operator bool() const { + return code_ != Ok; } // Returns internal enum, useful for switch statement Code code() const { - return _code; + return code_; } const char* c_str() const { static const char* messages[] = { "Ok", "EmptyInput", "IncompleteInput", "InvalidInput", "NoMemory", "TooDeep"}; - ARDUINOJSON_ASSERT(static_cast<size_t>(_code) < + ARDUINOJSON_ASSERT(static_cast<size_t>(code_) < sizeof(messages) / sizeof(messages[0])); - return messages[_code]; + return messages[code_]; } #if ARDUINOJSON_ENABLE_PROGMEM const __FlashStringHelper* f_str() const { - ARDUINOJSON_DEFINE_STATIC_ARRAY(char, s0, "Ok"); - ARDUINOJSON_DEFINE_STATIC_ARRAY(char, s1, "EmptyInput"); - ARDUINOJSON_DEFINE_STATIC_ARRAY(char, s2, "IncompleteInput"); - ARDUINOJSON_DEFINE_STATIC_ARRAY(char, s3, "InvalidInput"); - ARDUINOJSON_DEFINE_STATIC_ARRAY(char, s4, "NoMemory"); - ARDUINOJSON_DEFINE_STATIC_ARRAY(char, s5, "TooDeep"); - ARDUINOJSON_DEFINE_STATIC_ARRAY( - const char*, messages, ARDUINOJSON_EXPAND6({s0, s1, s2, s3, s4, s5})); - return ARDUINOJSON_READ_STATIC_ARRAY(const __FlashStringHelper*, messages, - _code); + ARDUINOJSON_DEFINE_PROGMEM_ARRAY(char, s0, "Ok"); + ARDUINOJSON_DEFINE_PROGMEM_ARRAY(char, s1, "EmptyInput"); + ARDUINOJSON_DEFINE_PROGMEM_ARRAY(char, s2, "IncompleteInput"); + ARDUINOJSON_DEFINE_PROGMEM_ARRAY(char, s3, "InvalidInput"); + ARDUINOJSON_DEFINE_PROGMEM_ARRAY(char, s4, "NoMemory"); + ARDUINOJSON_DEFINE_PROGMEM_ARRAY(char, s5, "TooDeep"); + ARDUINOJSON_DEFINE_PROGMEM_ARRAY(const char*, messages, + {s0, s1, s2, s3, s4, s5}); + return reinterpret_cast<const __FlashStringHelper*>( + detail::pgm_read(messages + code_)); } #endif private: - Code _code; + Code code_; }; #if ARDUINOJSON_ENABLE_STD_STREAM @@ -104,4 +103,4 @@ inline std::ostream& operator<<(std::ostream& s, DeserializationError::Code c) { } #endif -} // namespace ARDUINOJSON_NAMESPACE +ARDUINOJSON_END_PUBLIC_NAMESPACE diff --git a/neosensor/libraries/ArduinoJson/src/ArduinoJson/Deserialization/DeserializationOptions.hpp b/neosensor/libraries/ArduinoJson/src/ArduinoJson/Deserialization/DeserializationOptions.hpp new file mode 100644 index 0000000000000000000000000000000000000000..8400cc0b23113e5a58dece81bbdcd0a89eff9fb9 --- /dev/null +++ b/neosensor/libraries/ArduinoJson/src/ArduinoJson/Deserialization/DeserializationOptions.hpp @@ -0,0 +1,35 @@ +// ArduinoJson - https://arduinojson.org +// Copyright © 2014-2023, Benoit BLANCHON +// MIT License + +#pragma once + +#include <ArduinoJson/Deserialization/Filter.hpp> +#include <ArduinoJson/Deserialization/NestingLimit.hpp> + +ARDUINOJSON_BEGIN_PRIVATE_NAMESPACE + +template <typename TFilter> +struct DeserializationOptions { + TFilter filter; + DeserializationOption::NestingLimit nestingLimit; +}; + +template <typename TFilter> +inline DeserializationOptions<TFilter> makeDeserializationOptions( + TFilter filter, DeserializationOption::NestingLimit nestingLimit = {}) { + return {filter, nestingLimit}; +} + +template <typename TFilter> +inline DeserializationOptions<TFilter> makeDeserializationOptions( + DeserializationOption::NestingLimit nestingLimit, TFilter filter) { + return {filter, nestingLimit}; +} + +inline DeserializationOptions<AllowAllFilter> makeDeserializationOptions( + DeserializationOption::NestingLimit nestingLimit = {}) { + return {{}, nestingLimit}; +} + +ARDUINOJSON_END_PRIVATE_NAMESPACE diff --git a/neosensor/libraries/ArduinoJson/src/ArduinoJson/Deserialization/Filter.hpp b/neosensor/libraries/ArduinoJson/src/ArduinoJson/Deserialization/Filter.hpp index 501acf3e431ed30498f5bf7d29af0e775007156f..39883027da6507cbb6d31a9649c898a26a7bbec3 100644 --- a/neosensor/libraries/ArduinoJson/src/ArduinoJson/Deserialization/Filter.hpp +++ b/neosensor/libraries/ArduinoJson/src/ArduinoJson/Deserialization/Filter.hpp @@ -1,45 +1,48 @@ // ArduinoJson - https://arduinojson.org -// Copyright © 2014-2022, Benoit BLANCHON +// Copyright © 2014-2023, Benoit BLANCHON // MIT License #pragma once #include <ArduinoJson/Namespace.hpp> -namespace ARDUINOJSON_NAMESPACE { +ARDUINOJSON_BEGIN_PUBLIC_NAMESPACE +namespace DeserializationOption { class Filter { public: - explicit Filter(JsonVariantConst v) : _variant(v) {} + explicit Filter(JsonVariantConst v) : variant_(v) {} bool allow() const { - return _variant; + return variant_; } bool allowArray() const { - return _variant == true || _variant.is<JsonArrayConst>(); + return variant_ == true || variant_.is<JsonArrayConst>(); } bool allowObject() const { - return _variant == true || _variant.is<JsonObjectConst>(); + return variant_ == true || variant_.is<JsonObjectConst>(); } bool allowValue() const { - return _variant == true; + return variant_ == true; } template <typename TKey> Filter operator[](const TKey& key) const { - if (_variant == true) // "true" means "allow recursively" + if (variant_ == true) // "true" means "allow recursively" return *this; - JsonVariantConst member = _variant[key]; - return Filter(member.isNull() ? _variant["*"] : member); + JsonVariantConst member = variant_[key]; + return Filter(member.isNull() ? variant_["*"] : member); } private: - JsonVariantConst _variant; + JsonVariantConst variant_; }; +} // namespace DeserializationOption +namespace detail { struct AllowAllFilter { bool allow() const { return true; @@ -62,5 +65,6 @@ struct AllowAllFilter { return AllowAllFilter(); } }; +} // namespace detail -} // namespace ARDUINOJSON_NAMESPACE +ARDUINOJSON_END_PUBLIC_NAMESPACE diff --git a/neosensor/libraries/ArduinoJson/src/ArduinoJson/Deserialization/NestingLimit.hpp b/neosensor/libraries/ArduinoJson/src/ArduinoJson/Deserialization/NestingLimit.hpp index af5724d0af010020dd4c2f5a02c7e23487f72033..6434275bec9b8a42d4f7a70182811d65a7a28d19 100644 --- a/neosensor/libraries/ArduinoJson/src/ArduinoJson/Deserialization/NestingLimit.hpp +++ b/neosensor/libraries/ArduinoJson/src/ArduinoJson/Deserialization/NestingLimit.hpp @@ -1,5 +1,5 @@ // ArduinoJson - https://arduinojson.org -// Copyright © 2014-2022, Benoit BLANCHON +// Copyright © 2014-2023, Benoit BLANCHON // MIT License #pragma once @@ -7,23 +7,26 @@ #include <ArduinoJson/Namespace.hpp> #include <ArduinoJson/Polyfills/assert.hpp> -namespace ARDUINOJSON_NAMESPACE { +ARDUINOJSON_BEGIN_PUBLIC_NAMESPACE +namespace DeserializationOption { class NestingLimit { public: - NestingLimit() : _value(ARDUINOJSON_DEFAULT_NESTING_LIMIT) {} - explicit NestingLimit(uint8_t n) : _value(n) {} + NestingLimit() : value_(ARDUINOJSON_DEFAULT_NESTING_LIMIT) {} + explicit NestingLimit(uint8_t n) : value_(n) {} NestingLimit decrement() const { - ARDUINOJSON_ASSERT(_value > 0); - return NestingLimit(static_cast<uint8_t>(_value - 1)); + ARDUINOJSON_ASSERT(value_ > 0); + return NestingLimit(static_cast<uint8_t>(value_ - 1)); } bool reached() const { - return _value == 0; + return value_ == 0; } private: - uint8_t _value; + uint8_t value_; }; -} // namespace ARDUINOJSON_NAMESPACE +} // namespace DeserializationOption + +ARDUINOJSON_END_PUBLIC_NAMESPACE diff --git a/neosensor/libraries/ArduinoJson/src/ArduinoJson/Deserialization/Reader.hpp b/neosensor/libraries/ArduinoJson/src/ArduinoJson/Deserialization/Reader.hpp index 4e1958c7505bc67c05400a1bfd39a8732d482123..5f18c7b3022b2981e84da4e6869f34f7eb3811b9 100644 --- a/neosensor/libraries/ArduinoJson/src/ArduinoJson/Deserialization/Reader.hpp +++ b/neosensor/libraries/ArduinoJson/src/ArduinoJson/Deserialization/Reader.hpp @@ -1,31 +1,32 @@ // ArduinoJson - https://arduinojson.org -// Copyright © 2014-2022, Benoit BLANCHON +// Copyright © 2014-2023, Benoit BLANCHON // MIT License #pragma once #include <ArduinoJson/Namespace.hpp> +#include <ArduinoJson/Polyfills/utility.hpp> #include <stdlib.h> // for size_t -namespace ARDUINOJSON_NAMESPACE { +ARDUINOJSON_BEGIN_PRIVATE_NAMESPACE // The default reader is a simple wrapper for Readers that are not copiable template <typename TSource, typename Enable = void> struct Reader { public: - Reader(TSource& source) : _source(&source) {} + Reader(TSource& source) : source_(&source) {} int read() { - return _source->read(); // Error here? You passed an unsupported input type + return source_->read(); // Error here? You passed an unsupported input type } size_t readBytes(char* buffer, size_t length) { - return _source->readBytes(buffer, length); + return source_->readBytes(buffer, length); } private: - TSource* _source; + TSource* source_; }; template <typename TSource, typename Enable = void> @@ -33,7 +34,8 @@ struct BoundedReader { // no default implementation because we need to pass the size to the // constructor }; -} // namespace ARDUINOJSON_NAMESPACE + +ARDUINOJSON_END_PRIVATE_NAMESPACE #include <ArduinoJson/Deserialization/Readers/IteratorReader.hpp> #include <ArduinoJson/Deserialization/Readers/RamReader.hpp> @@ -54,3 +56,18 @@ struct BoundedReader { #if ARDUINOJSON_ENABLE_STD_STREAM # include <ArduinoJson/Deserialization/Readers/StdStreamReader.hpp> #endif + +ARDUINOJSON_BEGIN_PRIVATE_NAMESPACE + +template <typename TInput> +Reader<typename remove_reference<TInput>::type> makeReader(TInput&& input) { + return Reader<typename remove_reference<TInput>::type>{ + detail::forward<TInput>(input)}; +} + +template <typename TChar> +BoundedReader<TChar*> makeReader(TChar* input, size_t inputSize) { + return BoundedReader<TChar*>{input, inputSize}; +} + +ARDUINOJSON_END_PRIVATE_NAMESPACE diff --git a/neosensor/libraries/ArduinoJson/src/ArduinoJson/Deserialization/Readers/ArduinoStreamReader.hpp b/neosensor/libraries/ArduinoJson/src/ArduinoJson/Deserialization/Readers/ArduinoStreamReader.hpp index 179e376817cc0b6f71165adb56c955edda16d51d..8a8738858113feea23513cd039f6ffc43489d989 100644 --- a/neosensor/libraries/ArduinoJson/src/ArduinoJson/Deserialization/Readers/ArduinoStreamReader.hpp +++ b/neosensor/libraries/ArduinoJson/src/ArduinoJson/Deserialization/Readers/ArduinoStreamReader.hpp @@ -1,31 +1,31 @@ // ArduinoJson - https://arduinojson.org -// Copyright © 2014-2022, Benoit BLANCHON +// Copyright © 2014-2023, Benoit BLANCHON // MIT License #pragma once #include <Arduino.h> -namespace ARDUINOJSON_NAMESPACE { +ARDUINOJSON_BEGIN_PRIVATE_NAMESPACE template <typename TSource> struct Reader<TSource, typename enable_if<is_base_of<Stream, TSource>::value>::type> { public: - explicit Reader(Stream& stream) : _stream(&stream) {} + explicit Reader(Stream& stream) : stream_(&stream) {} int read() { - // don't use _stream.read() as it ignores the timeout + // don't use stream_.read() as it ignores the timeout char c; - return _stream->readBytes(&c, 1) ? static_cast<unsigned char>(c) : -1; + return stream_->readBytes(&c, 1) ? static_cast<unsigned char>(c) : -1; } size_t readBytes(char* buffer, size_t length) { - return _stream->readBytes(buffer, length); + return stream_->readBytes(buffer, length); } private: - Stream* _stream; + Stream* stream_; }; -} // namespace ARDUINOJSON_NAMESPACE +ARDUINOJSON_END_PRIVATE_NAMESPACE diff --git a/neosensor/libraries/ArduinoJson/src/ArduinoJson/Deserialization/Readers/ArduinoStringReader.hpp b/neosensor/libraries/ArduinoJson/src/ArduinoJson/Deserialization/Readers/ArduinoStringReader.hpp index 652409a0f642e178aa5e5edfad3cbdd3ffe7b600..14491f44a85e65972d13733786d1e6bea68763aa 100644 --- a/neosensor/libraries/ArduinoJson/src/ArduinoJson/Deserialization/Readers/ArduinoStringReader.hpp +++ b/neosensor/libraries/ArduinoJson/src/ArduinoJson/Deserialization/Readers/ArduinoStringReader.hpp @@ -1,19 +1,19 @@ // ArduinoJson - https://arduinojson.org -// Copyright © 2014-2022, Benoit BLANCHON +// Copyright © 2014-2023, Benoit BLANCHON // MIT License #pragma once #include <Arduino.h> -namespace ARDUINOJSON_NAMESPACE { +ARDUINOJSON_BEGIN_PRIVATE_NAMESPACE template <typename TSource> struct Reader<TSource, - typename enable_if<is_base_of< ::String, TSource>::value>::type> + typename enable_if<is_base_of<::String, TSource>::value>::type> : BoundedReader<const char*> { explicit Reader(const ::String& s) : BoundedReader<const char*>(s.c_str(), s.length()) {} }; -} // namespace ARDUINOJSON_NAMESPACE +ARDUINOJSON_END_PRIVATE_NAMESPACE diff --git a/neosensor/libraries/ArduinoJson/src/ArduinoJson/Deserialization/Readers/FlashReader.hpp b/neosensor/libraries/ArduinoJson/src/ArduinoJson/Deserialization/Readers/FlashReader.hpp index c48248c1d64bf3baa35166ce958eaaccbd52f4bb..97714afb14040ac14a004dcd4a43374a8e1c26cd 100644 --- a/neosensor/libraries/ArduinoJson/src/ArduinoJson/Deserialization/Readers/FlashReader.hpp +++ b/neosensor/libraries/ArduinoJson/src/ArduinoJson/Deserialization/Readers/FlashReader.hpp @@ -1,55 +1,56 @@ // ArduinoJson - https://arduinojson.org -// Copyright © 2014-2022, Benoit BLANCHON +// Copyright © 2014-2023, Benoit BLANCHON // MIT License #pragma once -#include <Arduino.h> +#include <ArduinoJson/Polyfills/pgmspace.hpp> -namespace ARDUINOJSON_NAMESPACE { +ARDUINOJSON_BEGIN_PRIVATE_NAMESPACE template <> struct Reader<const __FlashStringHelper*, void> { - const char* _ptr; + const char* ptr_; public: explicit Reader(const __FlashStringHelper* ptr) - : _ptr(reinterpret_cast<const char*>(ptr)) {} + : ptr_(reinterpret_cast<const char*>(ptr)) {} int read() { - return pgm_read_byte(_ptr++); + return pgm_read_byte(ptr_++); } size_t readBytes(char* buffer, size_t length) { - memcpy_P(buffer, _ptr, length); - _ptr += length; + memcpy_P(buffer, ptr_, length); + ptr_ += length; return length; } }; template <> struct BoundedReader<const __FlashStringHelper*, void> { - const char* _ptr; - const char* _end; + const char* ptr_; + const char* end_; public: explicit BoundedReader(const __FlashStringHelper* ptr, size_t size) - : _ptr(reinterpret_cast<const char*>(ptr)), _end(_ptr + size) {} + : ptr_(reinterpret_cast<const char*>(ptr)), end_(ptr_ + size) {} int read() { - if (_ptr < _end) - return pgm_read_byte(_ptr++); + if (ptr_ < end_) + return pgm_read_byte(ptr_++); else return -1; } size_t readBytes(char* buffer, size_t length) { - size_t available = static_cast<size_t>(_end - _ptr); + size_t available = static_cast<size_t>(end_ - ptr_); if (available < length) length = available; - memcpy_P(buffer, _ptr, length); - _ptr += length; + memcpy_P(buffer, ptr_, length); + ptr_ += length; return length; } }; -} // namespace ARDUINOJSON_NAMESPACE + +ARDUINOJSON_END_PRIVATE_NAMESPACE diff --git a/neosensor/libraries/ArduinoJson/src/ArduinoJson/Deserialization/Readers/IteratorReader.hpp b/neosensor/libraries/ArduinoJson/src/ArduinoJson/Deserialization/Readers/IteratorReader.hpp index 96494df01857994cb65b0a043f56ec75d9dea948..c0ca4a7713bb62d7a7e11e2a61468171d0a31695 100644 --- a/neosensor/libraries/ArduinoJson/src/ArduinoJson/Deserialization/Readers/IteratorReader.hpp +++ b/neosensor/libraries/ArduinoJson/src/ArduinoJson/Deserialization/Readers/IteratorReader.hpp @@ -1,30 +1,30 @@ // ArduinoJson - https://arduinojson.org -// Copyright © 2014-2022, Benoit BLANCHON +// Copyright © 2014-2023, Benoit BLANCHON // MIT License #pragma once -namespace ARDUINOJSON_NAMESPACE { +ARDUINOJSON_BEGIN_PRIVATE_NAMESPACE template <typename TIterator> class IteratorReader { - TIterator _ptr, _end; + TIterator ptr_, end_; public: explicit IteratorReader(TIterator begin, TIterator end) - : _ptr(begin), _end(end) {} + : ptr_(begin), end_(end) {} int read() { - if (_ptr < _end) - return static_cast<unsigned char>(*_ptr++); + if (ptr_ < end_) + return static_cast<unsigned char>(*ptr_++); else return -1; } size_t readBytes(char* buffer, size_t length) { size_t i = 0; - while (i < length && _ptr < _end) - buffer[i++] = *_ptr++; + while (i < length && ptr_ < end_) + buffer[i++] = *ptr_++; return i; } }; @@ -41,4 +41,5 @@ struct Reader<TSource, typename void_<typename TSource::const_iterator>::type> : IteratorReader<typename TSource::const_iterator>(source.begin(), source.end()) {} }; -} // namespace ARDUINOJSON_NAMESPACE + +ARDUINOJSON_END_PRIVATE_NAMESPACE diff --git a/neosensor/libraries/ArduinoJson/src/ArduinoJson/Deserialization/Readers/RamReader.hpp b/neosensor/libraries/ArduinoJson/src/ArduinoJson/Deserialization/Readers/RamReader.hpp index 120ce8a80520854253e6ce02504f2c8a8a38ec99..eff67bac35615a155291de3c12e3326935e186d2 100644 --- a/neosensor/libraries/ArduinoJson/src/ArduinoJson/Deserialization/Readers/RamReader.hpp +++ b/neosensor/libraries/ArduinoJson/src/ArduinoJson/Deserialization/Readers/RamReader.hpp @@ -1,12 +1,12 @@ // ArduinoJson - https://arduinojson.org -// Copyright © 2014-2022, Benoit BLANCHON +// Copyright © 2014-2023, Benoit BLANCHON // MIT License #pragma once #include <ArduinoJson/Polyfills/type_traits.hpp> -namespace ARDUINOJSON_NAMESPACE { +ARDUINOJSON_BEGIN_PRIVATE_NAMESPACE template <typename T> struct IsCharOrVoid { @@ -21,19 +21,19 @@ struct IsCharOrVoid<const T> : IsCharOrVoid<T> {}; template <typename TSource> struct Reader<TSource*, typename enable_if<IsCharOrVoid<TSource>::value>::type> { - const char* _ptr; + const char* ptr_; public: explicit Reader(const void* ptr) - : _ptr(ptr ? reinterpret_cast<const char*>(ptr) : "") {} + : ptr_(ptr ? reinterpret_cast<const char*>(ptr) : "") {} int read() { - return static_cast<unsigned char>(*_ptr++); + return static_cast<unsigned char>(*ptr_++); } size_t readBytes(char* buffer, size_t length) { for (size_t i = 0; i < length; i++) - buffer[i] = *_ptr++; + buffer[i] = *ptr_++; return length; } }; @@ -48,4 +48,4 @@ struct BoundedReader<TSource*, reinterpret_cast<const char*>(ptr) + len) {} }; -} // namespace ARDUINOJSON_NAMESPACE +ARDUINOJSON_END_PRIVATE_NAMESPACE diff --git a/neosensor/libraries/ArduinoJson/src/ArduinoJson/Deserialization/Readers/StdStreamReader.hpp b/neosensor/libraries/ArduinoJson/src/ArduinoJson/Deserialization/Readers/StdStreamReader.hpp index c92f7931b7cc5c8e3bcc5652a1e7855d865dfb8b..41e0c00aac1807c10330a87d6e59a27e6e15633c 100644 --- a/neosensor/libraries/ArduinoJson/src/ArduinoJson/Deserialization/Readers/StdStreamReader.hpp +++ b/neosensor/libraries/ArduinoJson/src/ArduinoJson/Deserialization/Readers/StdStreamReader.hpp @@ -1,29 +1,30 @@ // ArduinoJson - https://arduinojson.org -// Copyright © 2014-2022, Benoit BLANCHON +// Copyright © 2014-2023, Benoit BLANCHON // MIT License #pragma once #include <istream> -namespace ARDUINOJSON_NAMESPACE { +ARDUINOJSON_BEGIN_PRIVATE_NAMESPACE template <typename TSource> struct Reader<TSource, typename enable_if< is_base_of<std::istream, TSource>::value>::type> { public: - explicit Reader(std::istream& stream) : _stream(&stream) {} + explicit Reader(std::istream& stream) : stream_(&stream) {} int read() { - return _stream->get(); + return stream_->get(); } size_t readBytes(char* buffer, size_t length) { - _stream->read(buffer, static_cast<std::streamsize>(length)); - return static_cast<size_t>(_stream->gcount()); + stream_->read(buffer, static_cast<std::streamsize>(length)); + return static_cast<size_t>(stream_->gcount()); } private: - std::istream* _stream; + std::istream* stream_; }; -} // namespace ARDUINOJSON_NAMESPACE + +ARDUINOJSON_END_PRIVATE_NAMESPACE diff --git a/neosensor/libraries/ArduinoJson/src/ArduinoJson/Deserialization/Readers/VariantReader.hpp b/neosensor/libraries/ArduinoJson/src/ArduinoJson/Deserialization/Readers/VariantReader.hpp index 17918cd046494ea12e0a6badbf0d412a1dfa8088..b60f1cec87787972050c56e0033690e2ddb0d6f6 100644 --- a/neosensor/libraries/ArduinoJson/src/ArduinoJson/Deserialization/Readers/VariantReader.hpp +++ b/neosensor/libraries/ArduinoJson/src/ArduinoJson/Deserialization/Readers/VariantReader.hpp @@ -1,5 +1,5 @@ // ArduinoJson - https://arduinojson.org -// Copyright © 2014-2022, Benoit BLANCHON +// Copyright © 2014-2023, Benoit BLANCHON // MIT License #pragma once @@ -7,7 +7,7 @@ #include <ArduinoJson/Object/MemberProxy.hpp> #include <ArduinoJson/Variant/JsonVariantConst.hpp> -namespace ARDUINOJSON_NAMESPACE { +ARDUINOJSON_BEGIN_PRIVATE_NAMESPACE template <typename TVariant> struct Reader<TVariant, typename enable_if<IsVariant<TVariant>::value>::type> @@ -16,4 +16,4 @@ struct Reader<TVariant, typename enable_if<IsVariant<TVariant>::value>::type> : Reader<char*, void>(x.template as<const char*>()) {} }; -} // namespace ARDUINOJSON_NAMESPACE +ARDUINOJSON_END_PRIVATE_NAMESPACE diff --git a/neosensor/libraries/ArduinoJson/src/ArduinoJson/Deserialization/deserialize.hpp b/neosensor/libraries/ArduinoJson/src/ArduinoJson/Deserialization/deserialize.hpp index 062b10921f543b144ceae5daa3798ec278f8e52d..9f4d78e85e66c76e0254b974a32d77230f8d2464 100644 --- a/neosensor/libraries/ArduinoJson/src/ArduinoJson/Deserialization/deserialize.hpp +++ b/neosensor/libraries/ArduinoJson/src/ArduinoJson/Deserialization/deserialize.hpp @@ -1,16 +1,27 @@ // ArduinoJson - https://arduinojson.org -// Copyright © 2014-2022, Benoit BLANCHON +// Copyright © 2014-2023, Benoit BLANCHON // MIT License #pragma once #include <ArduinoJson/Deserialization/DeserializationError.hpp> -#include <ArduinoJson/Deserialization/Filter.hpp> -#include <ArduinoJson/Deserialization/NestingLimit.hpp> +#include <ArduinoJson/Deserialization/DeserializationOptions.hpp> #include <ArduinoJson/Deserialization/Reader.hpp> +#include <ArduinoJson/Polyfills/utility.hpp> #include <ArduinoJson/StringStorage/StringStorage.hpp> -namespace ARDUINOJSON_NAMESPACE { +ARDUINOJSON_BEGIN_PRIVATE_NAMESPACE + +// A meta-function that returns the first type of the parameter pack +// or void if empty +template <typename...> +struct first_or_void { + using type = void; +}; +template <typename T, typename... Rest> +struct first_or_void<T, Rest...> { + using type = T; +}; template <template <typename, typename> class TDeserializer, typename TReader, typename TWriter> @@ -21,55 +32,35 @@ TDeserializer<TReader, TWriter> makeDeserializer(MemoryPool* pool, return TDeserializer<TReader, TWriter>(pool, reader, writer); } -// deserialize(JsonDocument&, const std::string&, NestingLimit, Filter); -// deserialize(JsonDocument&, const String&, NestingLimit, Filter); -// deserialize(JsonDocument&, char*, NestingLimit, Filter); -// deserialize(JsonDocument&, const char*, NestingLimit, Filter); -// deserialize(JsonDocument&, const __FlashStringHelper*, NestingLimit, Filter); -template <template <typename, typename> class TDeserializer, typename TString, - typename TFilter> -typename enable_if<!is_array<TString>::value, DeserializationError>::type -deserialize(JsonDocument& doc, const TString& input, NestingLimit nestingLimit, - TFilter filter) { - Reader<TString> reader(input); - VariantData* data = VariantAttorney::getData(doc); - MemoryPool* pool = VariantAttorney::getPool(doc); +template <template <typename, typename> class TDeserializer, typename TStream, + typename... Args, + typename = typename enable_if< // issue #1897 + !is_integral<typename first_or_void<Args...>::type>::value>::type> +DeserializationError deserialize(JsonDocument& doc, TStream&& input, + Args... args) { + auto reader = makeReader(detail::forward<TStream>(input)); + auto data = VariantAttorney::getData(doc); + auto pool = VariantAttorney::getPool(doc); + auto options = makeDeserializationOptions(args...); doc.clear(); return makeDeserializer<TDeserializer>(pool, reader, makeStringStorage(input, pool)) - .parse(*data, filter, nestingLimit); + .parse(*data, options.filter, options.nestingLimit); } -// -// deserialize(JsonDocument&, char*, size_t, NestingLimit, Filter); -// deserialize(JsonDocument&, const char*, size_t, NestingLimit, Filter); -// deserialize(JsonDocument&, const __FlashStringHelper*, size_t, NL, Filter); + template <template <typename, typename> class TDeserializer, typename TChar, - typename TFilter> + typename Size, typename... Args, + typename = typename enable_if<is_integral<Size>::value>::type> DeserializationError deserialize(JsonDocument& doc, TChar* input, - size_t inputSize, NestingLimit nestingLimit, - TFilter filter) { - BoundedReader<TChar*> reader(input, inputSize); - VariantData* data = VariantAttorney::getData(doc); - MemoryPool* pool = VariantAttorney::getPool(doc); - doc.clear(); - return makeDeserializer<TDeserializer>(pool, reader, - makeStringStorage(input, pool)) - .parse(*data, filter, nestingLimit); -} -// -// deserialize(JsonDocument&, std::istream&, NestingLimit, Filter); -// deserialize(JsonDocument&, Stream&, NestingLimit, Filter); -template <template <typename, typename> class TDeserializer, typename TStream, - typename TFilter> -DeserializationError deserialize(JsonDocument& doc, TStream& input, - NestingLimit nestingLimit, TFilter filter) { - Reader<TStream> reader(input); - VariantData* data = VariantAttorney::getData(doc); - MemoryPool* pool = VariantAttorney::getPool(doc); + Size inputSize, Args... args) { + auto reader = makeReader(input, size_t(inputSize)); + auto data = VariantAttorney::getData(doc); + auto pool = VariantAttorney::getPool(doc); + auto options = makeDeserializationOptions(args...); doc.clear(); return makeDeserializer<TDeserializer>(pool, reader, makeStringStorage(input, pool)) - .parse(*data, filter, nestingLimit); + .parse(*data, options.filter, options.nestingLimit); } -} // namespace ARDUINOJSON_NAMESPACE +ARDUINOJSON_END_PRIVATE_NAMESPACE diff --git a/neosensor/libraries/ArduinoJson/src/ArduinoJson/Document/BasicJsonDocument.hpp b/neosensor/libraries/ArduinoJson/src/ArduinoJson/Document/BasicJsonDocument.hpp index 7a32f6f2f5a98966b34fbe5209623161a1585bc1..bc206f02f3d90cd566aea7fe657652c1343dbaad 100644 --- a/neosensor/libraries/ArduinoJson/src/ArduinoJson/Document/BasicJsonDocument.hpp +++ b/neosensor/libraries/ArduinoJson/src/ArduinoJson/Document/BasicJsonDocument.hpp @@ -1,12 +1,12 @@ // ArduinoJson - https://arduinojson.org -// Copyright © 2014-2022, Benoit BLANCHON +// Copyright © 2014-2023, Benoit BLANCHON // MIT License #pragma once #include <ArduinoJson/Document/JsonDocument.hpp> -namespace ARDUINOJSON_NAMESPACE { +ARDUINOJSON_BEGIN_PUBLIC_NAMESPACE // Helper to implement the "base-from-member" idiom // (we need to store the allocator before constructing JsonDocument) @@ -14,27 +14,27 @@ template <typename TAllocator> class AllocatorOwner { public: AllocatorOwner() {} - AllocatorOwner(TAllocator a) : _allocator(a) {} + AllocatorOwner(TAllocator a) : allocator_(a) {} void* allocate(size_t size) { - return _allocator.allocate(size); + return allocator_.allocate(size); } void deallocate(void* ptr) { if (ptr) - _allocator.deallocate(ptr); + allocator_.deallocate(ptr); } void* reallocate(void* ptr, size_t new_size) { - return _allocator.reallocate(ptr, new_size); + return allocator_.reallocate(ptr, new_size); } TAllocator& allocator() { - return _allocator; + return allocator_; } private: - TAllocator _allocator; + TAllocator allocator_; }; // A JsonDocument that uses the provided allocator to allocate its memory pool. @@ -52,11 +52,9 @@ class BasicJsonDocument : AllocatorOwner<TAllocator>, public JsonDocument { } // Move-constructor -#if ARDUINOJSON_HAS_RVALUE_REFERENCES BasicJsonDocument(BasicJsonDocument&& src) : AllocatorOwner<TAllocator>(src) { moveAssignFrom(src); } -#endif BasicJsonDocument(const JsonDocument& src) { copyAssignFrom(src); @@ -64,13 +62,14 @@ class BasicJsonDocument : AllocatorOwner<TAllocator>, public JsonDocument { // Construct from variant, array, or object template <typename T> - BasicJsonDocument( - const T& src, - typename enable_if< - is_same<T, JsonVariant>::value || - is_same<T, JsonVariantConst>::value || is_same<T, JsonArray>::value || - is_same<T, JsonArrayConst>::value || is_same<T, JsonObject>::value || - is_same<T, JsonObjectConst>::value>::type* = 0) + BasicJsonDocument(const T& src, + typename detail::enable_if< + detail::is_same<T, JsonVariant>::value || + detail::is_same<T, JsonVariantConst>::value || + detail::is_same<T, JsonArray>::value || + detail::is_same<T, JsonArrayConst>::value || + detail::is_same<T, JsonObject>::value || + detail::is_same<T, JsonObjectConst>::value>::type* = 0) : JsonDocument(allocPool(src.memoryUsage())) { set(src); } @@ -90,12 +89,10 @@ class BasicJsonDocument : AllocatorOwner<TAllocator>, public JsonDocument { return *this; } -#if ARDUINOJSON_HAS_RVALUE_REFERENCES BasicJsonDocument& operator=(BasicJsonDocument&& src) { moveAssignFrom(src); return *this; } -#endif template <typename T> BasicJsonDocument& operator=(const T& src) { @@ -109,18 +106,18 @@ class BasicJsonDocument : AllocatorOwner<TAllocator>, public JsonDocument { // Reduces the capacity of the memory pool to match the current usage. // https://arduinojson.org/v6/api/basicjsondocument/shrinktofit/ void shrinkToFit() { - ptrdiff_t bytes_reclaimed = _pool.squash(); + ptrdiff_t bytes_reclaimed = pool_.squash(); if (bytes_reclaimed == 0) return; - void* old_ptr = _pool.buffer(); - void* new_ptr = this->reallocate(old_ptr, _pool.capacity()); + void* old_ptr = pool_.buffer(); + void* new_ptr = this->reallocate(old_ptr, pool_.capacity()); ptrdiff_t ptr_offset = static_cast<char*>(new_ptr) - static_cast<char*>(old_ptr); - _pool.movePointers(ptr_offset); - _data.movePointers(ptr_offset, ptr_offset - bytes_reclaimed); + pool_.movePointers(ptr_offset); + data_.movePointers(ptr_offset, ptr_offset - bytes_reclaimed); } // Reclaims the memory leaked when removing and replacing values. @@ -130,7 +127,6 @@ class BasicJsonDocument : AllocatorOwner<TAllocator>, public JsonDocument { BasicJsonDocument tmp(*this); if (!tmp.capacity()) return false; - tmp.set(*this); moveAssignFrom(tmp); return true; } @@ -138,17 +134,17 @@ class BasicJsonDocument : AllocatorOwner<TAllocator>, public JsonDocument { using AllocatorOwner<TAllocator>::allocator; private: - MemoryPool allocPool(size_t requiredSize) { - size_t capa = addPadding(requiredSize); - return MemoryPool(reinterpret_cast<char*>(this->allocate(capa)), capa); + detail::MemoryPool allocPool(size_t requiredSize) { + size_t capa = detail::addPadding(requiredSize); + return {reinterpret_cast<char*>(this->allocate(capa)), capa}; } void reallocPool(size_t requiredSize) { - size_t capa = addPadding(requiredSize); - if (capa == _pool.capacity()) + size_t capa = detail::addPadding(requiredSize); + if (capa == pool_.capacity()) return; freePool(); - replacePool(allocPool(addPadding(requiredSize))); + replacePool(allocPool(detail::addPadding(requiredSize))); } void freePool() { @@ -162,11 +158,11 @@ class BasicJsonDocument : AllocatorOwner<TAllocator>, public JsonDocument { void moveAssignFrom(BasicJsonDocument& src) { freePool(); - _data = src._data; - _pool = src._pool; - src._data.setNull(); - src._pool = MemoryPool(0, 0); + data_ = src.data_; + pool_ = src.pool_; + src.data_.setNull(); + src.pool_ = {0, 0}; } }; -} // namespace ARDUINOJSON_NAMESPACE +ARDUINOJSON_END_PUBLIC_NAMESPACE diff --git a/neosensor/libraries/ArduinoJson/src/ArduinoJson/Document/DynamicJsonDocument.hpp b/neosensor/libraries/ArduinoJson/src/ArduinoJson/Document/DynamicJsonDocument.hpp index dd889a818bd7d25cd64c05c3fb2d2b21f8a0ef5e..3c2dc3a61cf9f85f5ef72eff400be71192dd2d82 100644 --- a/neosensor/libraries/ArduinoJson/src/ArduinoJson/Document/DynamicJsonDocument.hpp +++ b/neosensor/libraries/ArduinoJson/src/ArduinoJson/Document/DynamicJsonDocument.hpp @@ -1,5 +1,5 @@ // ArduinoJson - https://arduinojson.org -// Copyright © 2014-2022, Benoit BLANCHON +// Copyright © 2014-2023, Benoit BLANCHON // MIT License #pragma once @@ -8,7 +8,7 @@ #include <stdlib.h> // malloc, free -namespace ARDUINOJSON_NAMESPACE { +ARDUINOJSON_BEGIN_PUBLIC_NAMESPACE // The allocator of DynamicJsonDocument. struct DefaultAllocator { @@ -29,4 +29,4 @@ struct DefaultAllocator { // https://arduinojson.org/v6/api/dynamicjsondocument/ typedef BasicJsonDocument<DefaultAllocator> DynamicJsonDocument; -} // namespace ARDUINOJSON_NAMESPACE +ARDUINOJSON_END_PUBLIC_NAMESPACE diff --git a/neosensor/libraries/ArduinoJson/src/ArduinoJson/Document/JsonDocument.hpp b/neosensor/libraries/ArduinoJson/src/ArduinoJson/Document/JsonDocument.hpp index 286283f84bc2e99bdab879c159041509c655c98f..39c1536f12b232b6af397a619fcdf4f82349271f 100644 --- a/neosensor/libraries/ArduinoJson/src/ArduinoJson/Document/JsonDocument.hpp +++ b/neosensor/libraries/ArduinoJson/src/ArduinoJson/Document/JsonDocument.hpp @@ -1,5 +1,5 @@ // ArduinoJson - https://arduinojson.org -// Copyright © 2014-2022, Benoit BLANCHON +// Copyright © 2014-2023, Benoit BLANCHON // MIT License #pragma once @@ -12,14 +12,17 @@ #include <ArduinoJson/Variant/JsonVariantConst.hpp> #include <ArduinoJson/Variant/VariantTo.hpp> -namespace ARDUINOJSON_NAMESPACE { +ARDUINOJSON_BEGIN_PUBLIC_NAMESPACE // A JSON document. // https://arduinojson.org/v6/api/jsondocument/ -class JsonDocument : public VariantOperators<const JsonDocument&> { - friend class VariantAttorney; +class JsonDocument : public detail::VariantOperators<const JsonDocument&> { + friend class detail::VariantAttorney; public: + JsonDocument(const JsonDocument&) = delete; + JsonDocument& operator=(const JsonDocument&) = delete; + // Casts the root to the specified type. // https://arduinojson.org/v6/api/jsondocument/as/ template <typename T> @@ -37,8 +40,8 @@ class JsonDocument : public VariantOperators<const JsonDocument&> { // Empties the document and resets the memory pool // https://arduinojson.org/v6/api/jsondocument/clear/ void clear() { - _pool.clear(); - _data.init(); + pool_.clear(); + data_.setNull(); } // Returns true if the root is of the specified type. @@ -64,31 +67,31 @@ class JsonDocument : public VariantOperators<const JsonDocument&> { // Returns the number of used bytes in the memory pool. // https://arduinojson.org/v6/api/jsondocument/memoryusage/ size_t memoryUsage() const { - return _pool.size(); + return pool_.size(); } // Returns trues if the memory pool was too small. // https://arduinojson.org/v6/api/jsondocument/overflowed/ bool overflowed() const { - return _pool.overflowed(); + return pool_.overflowed(); } // Returns the depth (nesting level) of the array. // https://arduinojson.org/v6/api/jsondocument/nesting/ size_t nesting() const { - return variantNesting(&_data); + return variantNesting(&data_); } // Returns the capacity of the memory pool. // https://arduinojson.org/v6/api/jsondocument/capacity/ size_t capacity() const { - return _pool.capacity(); + return pool_.capacity(); } // Returns the number of elements in the root array or object. // https://arduinojson.org/v6/api/jsondocument/size/ size_t size() const { - return _data.size(); + return data_.size(); } // Copies the specified document. @@ -100,15 +103,16 @@ class JsonDocument : public VariantOperators<const JsonDocument&> { // Replaces the root with the specified value. // https://arduinojson.org/v6/api/jsondocument/set/ template <typename T> - typename enable_if<!is_base_of<JsonDocument, T>::value, bool>::type set( - const T& src) { + typename detail::enable_if<!detail::is_base_of<JsonDocument, T>::value, + bool>::type + set(const T& src) { return to<JsonVariant>().set(src); } // Clears the document and converts it to the specified type. // https://arduinojson.org/v6/api/jsondocument/to/ template <typename T> - typename VariantTo<T>::type to() { + typename detail::VariantTo<T>::type to() { clear(); return getVariant().template to<T>(); } @@ -157,69 +161,71 @@ class JsonDocument : public VariantOperators<const JsonDocument&> { // https://arduinojson.org/v6/api/jsondocument/containskey/ template <typename TChar> bool containsKey(TChar* key) const { - return _data.getMember(adaptString(key)) != 0; + return data_.getMember(detail::adaptString(key)) != 0; } // Returns true if the root object contains the specified key. // https://arduinojson.org/v6/api/jsondocument/containskey/ template <typename TString> bool containsKey(const TString& key) const { - return _data.getMember(adaptString(key)) != 0; + return data_.getMember(detail::adaptString(key)) != 0; } // Gets or sets a root object's member. // https://arduinojson.org/v6/api/jsondocument/subscript/ template <typename TString> - FORCE_INLINE typename enable_if<IsString<TString>::value, - MemberProxy<JsonDocument&, TString> >::type + FORCE_INLINE typename detail::enable_if< + detail::IsString<TString>::value, + detail::MemberProxy<JsonDocument&, TString>>::type operator[](const TString& key) { - return MemberProxy<JsonDocument&, TString>(*this, key); + return {*this, key}; } // Gets or sets a root object's member. // https://arduinojson.org/v6/api/jsondocument/subscript/ template <typename TChar> - FORCE_INLINE typename enable_if<IsString<TChar*>::value, - MemberProxy<JsonDocument&, TChar*> >::type + FORCE_INLINE typename detail::enable_if< + detail::IsString<TChar*>::value, + detail::MemberProxy<JsonDocument&, TChar*>>::type operator[](TChar* key) { - return MemberProxy<JsonDocument&, TChar*>(*this, key); + return {*this, key}; } // Gets a root object's member. // https://arduinojson.org/v6/api/jsondocument/subscript/ template <typename TString> - FORCE_INLINE - typename enable_if<IsString<TString>::value, JsonVariantConst>::type - operator[](const TString& key) const { - return JsonVariantConst(_data.getMember(adaptString(key))); + FORCE_INLINE typename detail::enable_if<detail::IsString<TString>::value, + JsonVariantConst>::type + operator[](const TString& key) const { + return JsonVariantConst(data_.getMember(detail::adaptString(key))); } // Gets a root object's member. // https://arduinojson.org/v6/api/jsondocument/subscript/ template <typename TChar> - FORCE_INLINE - typename enable_if<IsString<TChar*>::value, JsonVariantConst>::type - operator[](TChar* key) const { - return JsonVariantConst(_data.getMember(adaptString(key))); + FORCE_INLINE typename detail::enable_if<detail::IsString<TChar*>::value, + JsonVariantConst>::type + operator[](TChar* key) const { + return JsonVariantConst(data_.getMember(detail::adaptString(key))); } // Gets or sets a root array's element. // https://arduinojson.org/v6/api/jsondocument/subscript/ - FORCE_INLINE ElementProxy<JsonDocument&> operator[](size_t index) { - return ElementProxy<JsonDocument&>(*this, index); + FORCE_INLINE detail::ElementProxy<JsonDocument&> operator[](size_t index) { + return {*this, index}; } // Gets a root array's member. // https://arduinojson.org/v6/api/jsondocument/subscript/ FORCE_INLINE JsonVariantConst operator[](size_t index) const { - return JsonVariantConst(_data.getElement(index)); + return JsonVariantConst(data_.getElement(index)); } // Appends a new (null) element to the root array. // Returns a reference to the new element. // https://arduinojson.org/v6/api/jsondocument/add/ FORCE_INLINE JsonVariant add() { - return JsonVariant(&_pool, _data.addElement(&_pool)); + return JsonVariant(&pool_, data_.addElement(&pool_)); } // Appends a value to the root array. @@ -240,25 +246,26 @@ class JsonDocument : public VariantOperators<const JsonDocument&> { // ⚠️ Doesn't release the memory associated with the removed element. // https://arduinojson.org/v6/api/jsondocument/remove/ FORCE_INLINE void remove(size_t index) { - _data.remove(index); + data_.remove(index); } // Removes a member of the root object. // ⚠️ Doesn't release the memory associated with the removed element. // https://arduinojson.org/v6/api/jsondocument/remove/ template <typename TChar> - FORCE_INLINE typename enable_if<IsString<TChar*>::value>::type remove( - TChar* key) { - _data.remove(adaptString(key)); + FORCE_INLINE typename detail::enable_if<detail::IsString<TChar*>::value>::type + remove(TChar* key) { + data_.remove(detail::adaptString(key)); } // Removes a member of the root object. // ⚠️ Doesn't release the memory associated with the removed element. // https://arduinojson.org/v6/api/jsondocument/remove/ template <typename TString> - FORCE_INLINE typename enable_if<IsString<TString>::value>::type remove( - const TString& key) { - _data.remove(adaptString(key)); + FORCE_INLINE + typename detail::enable_if<detail::IsString<TString>::value>::type + remove(const TString& key) { + data_.remove(detail::adaptString(key)); } FORCE_INLINE operator JsonVariant() { @@ -270,54 +277,44 @@ class JsonDocument : public VariantOperators<const JsonDocument&> { } protected: - JsonDocument() : _pool(0, 0) { - _data.init(); - } + JsonDocument() : pool_(0, 0) {} - JsonDocument(MemoryPool pool) : _pool(pool) { - _data.init(); - } + JsonDocument(detail::MemoryPool pool) : pool_(pool) {} - JsonDocument(char* buf, size_t capa) : _pool(buf, capa) { - _data.init(); - } + JsonDocument(char* buf, size_t capa) : pool_(buf, capa) {} ~JsonDocument() {} - void replacePool(MemoryPool pool) { - _pool = pool; + void replacePool(detail::MemoryPool pool) { + pool_ = pool; } JsonVariant getVariant() { - return JsonVariant(&_pool, &_data); + return JsonVariant(&pool_, &data_); } JsonVariantConst getVariant() const { - return JsonVariantConst(&_data); + return JsonVariantConst(&data_); } - MemoryPool _pool; - VariantData _data; - - private: - JsonDocument(const JsonDocument&); - JsonDocument& operator=(const JsonDocument&); + detail::MemoryPool pool_; + detail::VariantData data_; protected: - MemoryPool* getPool() { - return &_pool; + detail::MemoryPool* getPool() { + return &pool_; } - VariantData* getData() { - return &_data; + detail::VariantData* getData() { + return &data_; } - const VariantData* getData() const { - return &_data; + const detail::VariantData* getData() const { + return &data_; } - VariantData* getOrCreateData() { - return &_data; + detail::VariantData* getOrCreateData() { + return &data_; } }; @@ -325,4 +322,4 @@ inline void convertToJson(const JsonDocument& src, JsonVariant dst) { dst.set(src.as<JsonVariantConst>()); } -} // namespace ARDUINOJSON_NAMESPACE +ARDUINOJSON_END_PUBLIC_NAMESPACE diff --git a/neosensor/libraries/ArduinoJson/src/ArduinoJson/Document/StaticJsonDocument.hpp b/neosensor/libraries/ArduinoJson/src/ArduinoJson/Document/StaticJsonDocument.hpp index d88dc5747d0cdd67ed4b6bade9205c74c797d882..0716666436c235efa8868372990acade9b4bf416 100644 --- a/neosensor/libraries/ArduinoJson/src/ArduinoJson/Document/StaticJsonDocument.hpp +++ b/neosensor/libraries/ArduinoJson/src/ArduinoJson/Document/StaticJsonDocument.hpp @@ -1,37 +1,38 @@ // ArduinoJson - https://arduinojson.org -// Copyright © 2014-2022, Benoit BLANCHON +// Copyright © 2014-2023, Benoit BLANCHON // MIT License #pragma once #include <ArduinoJson/Document/JsonDocument.hpp> -namespace ARDUINOJSON_NAMESPACE { +ARDUINOJSON_BEGIN_PUBLIC_NAMESPACE // A JsonDocument with a memory pool on the stack. template <size_t desiredCapacity> class StaticJsonDocument : public JsonDocument { - static const size_t _capacity = - AddPadding<Max<1, desiredCapacity>::value>::value; + static const size_t capacity_ = + detail::AddPadding<detail::Max<1, desiredCapacity>::value>::value; public: - StaticJsonDocument() : JsonDocument(_buffer, _capacity) {} + StaticJsonDocument() : JsonDocument(buffer_, capacity_) {} StaticJsonDocument(const StaticJsonDocument& src) - : JsonDocument(_buffer, _capacity) { + : JsonDocument(buffer_, capacity_) { set(src); } template <typename T> StaticJsonDocument( const T& src, - typename enable_if<is_convertible<T, JsonVariantConst>::value>::type* = 0) - : JsonDocument(_buffer, _capacity) { + typename detail::enable_if< + detail::is_convertible<T, JsonVariantConst>::value>::type* = 0) + : JsonDocument(buffer_, capacity_) { set(src); } // disambiguate - StaticJsonDocument(JsonVariant src) : JsonDocument(_buffer, _capacity) { + StaticJsonDocument(JsonVariant src) : JsonDocument(buffer_, capacity_) { set(src); } @@ -54,7 +55,7 @@ class StaticJsonDocument : public JsonDocument { } private: - char _buffer[_capacity]; + char buffer_[capacity_]; }; -} // namespace ARDUINOJSON_NAMESPACE +ARDUINOJSON_END_PUBLIC_NAMESPACE diff --git a/neosensor/libraries/ArduinoJson/src/ArduinoJson/Json/EscapeSequence.hpp b/neosensor/libraries/ArduinoJson/src/ArduinoJson/Json/EscapeSequence.hpp index 7d28a8281c2e17dd3b7f9c70e8b31178186f13da..d2740cc4235c1e2e3d6b6266b28ea4c04e728dd7 100644 --- a/neosensor/libraries/ArduinoJson/src/ArduinoJson/Json/EscapeSequence.hpp +++ b/neosensor/libraries/ArduinoJson/src/ArduinoJson/Json/EscapeSequence.hpp @@ -1,12 +1,12 @@ // ArduinoJson - https://arduinojson.org -// Copyright © 2014-2022, Benoit BLANCHON +// Copyright © 2014-2023, Benoit BLANCHON // MIT License #pragma once #include <ArduinoJson/Namespace.hpp> -namespace ARDUINOJSON_NAMESPACE { +ARDUINOJSON_BEGIN_PRIVATE_NAMESPACE class EscapeSequence { public: @@ -36,4 +36,5 @@ class EscapeSequence { return &"//\"\"\\\\b\bf\fn\nr\rt\t"[excludeSolidus ? 2 : 0]; } }; -} // namespace ARDUINOJSON_NAMESPACE + +ARDUINOJSON_END_PRIVATE_NAMESPACE diff --git a/neosensor/libraries/ArduinoJson/src/ArduinoJson/Json/JsonDeserializer.hpp b/neosensor/libraries/ArduinoJson/src/ArduinoJson/Json/JsonDeserializer.hpp index 894e6d344fb0f960419d4dc55a62f74ea91638e2..a566aea9ea6ffaafc257d62670dbb0d5ad566d58 100644 --- a/neosensor/libraries/ArduinoJson/src/ArduinoJson/Json/JsonDeserializer.hpp +++ b/neosensor/libraries/ArduinoJson/src/ArduinoJson/Json/JsonDeserializer.hpp @@ -1,5 +1,5 @@ // ArduinoJson - https://arduinojson.org -// Copyright © 2014-2022, Benoit BLANCHON +// Copyright © 2014-2023, Benoit BLANCHON // MIT License #pragma once @@ -13,28 +13,29 @@ #include <ArduinoJson/Numbers/parseNumber.hpp> #include <ArduinoJson/Polyfills/assert.hpp> #include <ArduinoJson/Polyfills/type_traits.hpp> +#include <ArduinoJson/Polyfills/utility.hpp> #include <ArduinoJson/Variant/VariantData.hpp> -namespace ARDUINOJSON_NAMESPACE { +ARDUINOJSON_BEGIN_PRIVATE_NAMESPACE template <typename TReader, typename TStringStorage> class JsonDeserializer { public: JsonDeserializer(MemoryPool* pool, TReader reader, TStringStorage stringStorage) - : _stringStorage(stringStorage), - _foundSomething(false), - _latch(reader), - _pool(pool) {} + : stringStorage_(stringStorage), + foundSomething_(false), + latch_(reader), + pool_(pool) {} template <typename TFilter> DeserializationError parse(VariantData& variant, TFilter filter, - NestingLimit nestingLimit) { + DeserializationOption::NestingLimit nestingLimit) { DeserializationError::Code err; err = parseVariant(variant, filter, nestingLimit); - if (!err && _latch.last() != 0 && !variant.isEnclosed()) { + if (!err && latch_.last() != 0 && !variant.isEnclosed()) { // We don't detect trailing characters earlier, so we need to check now return DeserializationError::InvalidInput; } @@ -44,11 +45,11 @@ class JsonDeserializer { private: char current() { - return _latch.current(); + return latch_.current(); } void move() { - _latch.clear(); + latch_.clear(); } bool eat(char charToSkip) { @@ -59,8 +60,9 @@ class JsonDeserializer { } template <typename TFilter> - DeserializationError::Code parseVariant(VariantData& variant, TFilter filter, - NestingLimit nestingLimit) { + DeserializationError::Code parseVariant( + VariantData& variant, TFilter filter, + DeserializationOption::NestingLimit nestingLimit) { DeserializationError::Code err; err = skipSpacesAndComments(); @@ -110,7 +112,8 @@ class JsonDeserializer { } } - DeserializationError::Code skipVariant(NestingLimit nestingLimit) { + DeserializationError::Code skipVariant( + DeserializationOption::NestingLimit nestingLimit) { DeserializationError::Code err; err = skipSpacesAndComments(); @@ -143,8 +146,9 @@ class JsonDeserializer { } template <typename TFilter> - DeserializationError::Code parseArray(CollectionData& array, TFilter filter, - NestingLimit nestingLimit) { + DeserializationError::Code parseArray( + CollectionData& array, TFilter filter, + DeserializationOption::NestingLimit nestingLimit) { DeserializationError::Code err; if (nestingLimit.reached()) @@ -169,7 +173,7 @@ class JsonDeserializer { for (;;) { if (memberFilter.allow()) { // Allocate slot in array - VariantData* value = array.addElement(_pool); + VariantData* value = array.addElement(pool_); if (!value) return DeserializationError::NoMemory; @@ -196,7 +200,8 @@ class JsonDeserializer { } } - DeserializationError::Code skipArray(NestingLimit nestingLimit) { + DeserializationError::Code skipArray( + DeserializationOption::NestingLimit nestingLimit) { DeserializationError::Code err; if (nestingLimit.reached()) @@ -227,8 +232,9 @@ class JsonDeserializer { } template <typename TFilter> - DeserializationError::Code parseObject(CollectionData& object, TFilter filter, - NestingLimit nestingLimit) { + DeserializationError::Code parseObject( + CollectionData& object, TFilter filter, + DeserializationOption::NestingLimit nestingLimit) { DeserializationError::Code err; if (nestingLimit.reached()) @@ -263,7 +269,7 @@ class JsonDeserializer { if (!eat(':')) return DeserializationError::InvalidInput; - JsonString key = _stringStorage.str(); + JsonString key = stringStorage_.str(); TFilter memberFilter = filter[key.c_str()]; @@ -272,10 +278,10 @@ class JsonDeserializer { if (!variant) { // Save key in memory pool. // This MUST be done before adding the slot. - key = _stringStorage.save(); + key = stringStorage_.save(); // Allocate slot in object - VariantSlot* slot = object.addSlot(_pool); + VariantSlot* slot = object.addSlot(pool_); if (!slot) return DeserializationError::NoMemory; @@ -312,7 +318,8 @@ class JsonDeserializer { } } - DeserializationError::Code skipObject(NestingLimit nestingLimit) { + DeserializationError::Code skipObject( + DeserializationOption::NestingLimit nestingLimit) { DeserializationError::Code err; if (nestingLimit.reached()) @@ -370,7 +377,7 @@ class JsonDeserializer { } DeserializationError::Code parseKey() { - _stringStorage.startString(); + stringStorage_.startString(); if (isQuote(current())) { return parseQuotedString(); } else { @@ -381,13 +388,13 @@ class JsonDeserializer { DeserializationError::Code parseStringValue(VariantData& variant) { DeserializationError::Code err; - _stringStorage.startString(); + stringStorage_.startString(); err = parseQuotedString(); if (err) return err; - variant.setString(_stringStorage.save()); + variant.setString(stringStorage_.save()); return DeserializationError::Ok; } @@ -423,9 +430,9 @@ class JsonDeserializer { if (err) return err; if (codepoint.append(codeunit)) - Utf8::encodeCodepoint(codepoint.value(), _stringStorage); + Utf8::encodeCodepoint(codepoint.value(), stringStorage_); #else - _stringStorage.append('\\'); + stringStorage_.append('\\'); #endif continue; } @@ -437,10 +444,10 @@ class JsonDeserializer { move(); } - _stringStorage.append(c); + stringStorage_.append(c); } - if (!_stringStorage.isValid()) + if (!stringStorage_.isValid()) return DeserializationError::NoMemory; return DeserializationError::Ok; @@ -453,14 +460,14 @@ class JsonDeserializer { if (canBeInNonQuotedString(c)) { // no quotes do { move(); - _stringStorage.append(c); + stringStorage_.append(c); c = current(); } while (canBeInNonQuotedString(c)); } else { return DeserializationError::InvalidInput; } - if (!_stringStorage.isValid()) + if (!stringStorage_.isValid()) return DeserializationError::NoMemory; return DeserializationError::Ok; @@ -509,12 +516,12 @@ class JsonDeserializer { char c = current(); while (canBeInNumber(c) && n < 63) { move(); - _buffer[n++] = c; + buffer_[n++] = c; c = current(); } - _buffer[n] = 0; + buffer_[n] = 0; - if (!parseNumber(_buffer, result)) + if (!parseNumber(buffer_, result)) return DeserializationError::InvalidInput; return DeserializationError::Ok; @@ -578,7 +585,7 @@ class JsonDeserializer { switch (current()) { // end of string case '\0': - return _foundSomething ? DeserializationError::IncompleteInput + return foundSomething_ ? DeserializationError::IncompleteInput : DeserializationError::EmptyInput; // spaces @@ -633,7 +640,7 @@ class JsonDeserializer { #endif default: - _foundSomething = true; + foundSomething_ = true; return DeserializationError::Ok; } } @@ -652,124 +659,35 @@ class JsonDeserializer { return DeserializationError::Ok; } - TStringStorage _stringStorage; - bool _foundSomething; - Latch<TReader> _latch; - MemoryPool* _pool; - char _buffer[64]; // using a member instead of a local variable because it + TStringStorage stringStorage_; + bool foundSomething_; + Latch<TReader> latch_; + MemoryPool* pool_; + char buffer_[64]; // using a member instead of a local variable because it // ended in the recursive path after compiler inlined the // code }; -// Parses a JSON input and puts the result in a JsonDocument. -// https://arduinojson.org/v6/api/json/deserializejson/ -template <typename TString> -DeserializationError deserializeJson( - JsonDocument& doc, const TString& input, - NestingLimit nestingLimit = NestingLimit()) { - return deserialize<JsonDeserializer>(doc, input, nestingLimit, - AllowAllFilter()); -} - -// Parses a JSON input, filters, and puts the result in a JsonDocument. -// https://arduinojson.org/v6/api/json/deserializejson/ -template <typename TString> -DeserializationError deserializeJson( - JsonDocument& doc, const TString& input, Filter filter, - NestingLimit nestingLimit = NestingLimit()) { - return deserialize<JsonDeserializer>(doc, input, nestingLimit, filter); -} - -// Parses a JSON input, filters, and puts the result in a JsonDocument. -// https://arduinojson.org/v6/api/json/deserializejson/ -template <typename TString> -DeserializationError deserializeJson(JsonDocument& doc, const TString& input, - NestingLimit nestingLimit, Filter filter) { - return deserialize<JsonDeserializer>(doc, input, nestingLimit, filter); -} +ARDUINOJSON_END_PRIVATE_NAMESPACE -// Parses a JSON input and puts the result in a JsonDocument. -// https://arduinojson.org/v6/api/json/deserializejson/ -template <typename TStream> -DeserializationError deserializeJson( - JsonDocument& doc, TStream& input, - NestingLimit nestingLimit = NestingLimit()) { - return deserialize<JsonDeserializer>(doc, input, nestingLimit, - AllowAllFilter()); -} - -// Parses a JSON input, filters, and puts the result in a JsonDocument. -// https://arduinojson.org/v6/api/json/deserializejson/ -template <typename TStream> -DeserializationError deserializeJson( - JsonDocument& doc, TStream& input, Filter filter, - NestingLimit nestingLimit = NestingLimit()) { - return deserialize<JsonDeserializer>(doc, input, nestingLimit, filter); -} - -// Parses a JSON input, filters, and puts the result in a JsonDocument. -// https://arduinojson.org/v6/api/json/deserializejson/ -template <typename TStream> -DeserializationError deserializeJson(JsonDocument& doc, TStream& input, - NestingLimit nestingLimit, Filter filter) { - return deserialize<JsonDeserializer>(doc, input, nestingLimit, filter); -} - -// Parses a JSON input and puts the result in a JsonDocument. -// https://arduinojson.org/v6/api/json/deserializejson/ -template <typename TChar> -DeserializationError deserializeJson( - JsonDocument& doc, TChar* input, - NestingLimit nestingLimit = NestingLimit()) { - return deserialize<JsonDeserializer>(doc, input, nestingLimit, - AllowAllFilter()); -} - -// Parses a JSON input, filters, and puts the result in a JsonDocument. -// https://arduinojson.org/v6/api/json/deserializejson/ -template <typename TChar> -DeserializationError deserializeJson( - JsonDocument& doc, TChar* input, Filter filter, - NestingLimit nestingLimit = NestingLimit()) { - return deserialize<JsonDeserializer>(doc, input, nestingLimit, filter); -} - -// Parses a JSON input, filters, and puts the result in a JsonDocument. -// https://arduinojson.org/v6/api/json/deserializejson/ -template <typename TChar> -DeserializationError deserializeJson(JsonDocument& doc, TChar* input, - NestingLimit nestingLimit, Filter filter) { - return deserialize<JsonDeserializer>(doc, input, nestingLimit, filter); -} - -// Parses a JSON input and puts the result in a JsonDocument. -// https://arduinojson.org/v6/api/json/deserializejson/ -template <typename TChar> -DeserializationError deserializeJson( - JsonDocument& doc, TChar* input, size_t inputSize, - NestingLimit nestingLimit = NestingLimit()) { - return deserialize<JsonDeserializer>(doc, input, inputSize, nestingLimit, - AllowAllFilter()); -} +ARDUINOJSON_BEGIN_PUBLIC_NAMESPACE // Parses a JSON input, filters, and puts the result in a JsonDocument. // https://arduinojson.org/v6/api/json/deserializejson/ -template <typename TChar> -DeserializationError deserializeJson( - JsonDocument& doc, TChar* input, size_t inputSize, Filter filter, - NestingLimit nestingLimit = NestingLimit()) { - return deserialize<JsonDeserializer>(doc, input, inputSize, nestingLimit, - filter); +template <typename... Args> +DeserializationError deserializeJson(JsonDocument& doc, Args&&... args) { + using namespace detail; + return deserialize<JsonDeserializer>(doc, detail::forward<Args>(args)...); } // Parses a JSON input, filters, and puts the result in a JsonDocument. // https://arduinojson.org/v6/api/json/deserializejson/ -template <typename TChar> +template <typename TChar, typename... Args> DeserializationError deserializeJson(JsonDocument& doc, TChar* input, - size_t inputSize, - NestingLimit nestingLimit, Filter filter) { - return deserialize<JsonDeserializer>(doc, input, inputSize, nestingLimit, - filter); + Args&&... args) { + using namespace detail; + return deserialize<JsonDeserializer>(doc, input, + detail::forward<Args>(args)...); } -} // namespace ARDUINOJSON_NAMESPACE +ARDUINOJSON_END_PUBLIC_NAMESPACE diff --git a/neosensor/libraries/ArduinoJson/src/ArduinoJson/Json/JsonSerializer.hpp b/neosensor/libraries/ArduinoJson/src/ArduinoJson/Json/JsonSerializer.hpp index 563f12e8073e01d96b551c9404e10e4d52e68c04..781c9c93553b47d1386914235fe479fce811895e 100644 --- a/neosensor/libraries/ArduinoJson/src/ArduinoJson/Json/JsonSerializer.hpp +++ b/neosensor/libraries/ArduinoJson/src/ArduinoJson/Json/JsonSerializer.hpp @@ -1,5 +1,5 @@ // ArduinoJson - https://arduinojson.org -// Copyright © 2014-2022, Benoit BLANCHON +// Copyright © 2014-2023, Benoit BLANCHON // MIT License #pragma once @@ -9,14 +9,14 @@ #include <ArduinoJson/Serialization/serialize.hpp> #include <ArduinoJson/Variant/Visitor.hpp> -namespace ARDUINOJSON_NAMESPACE { +ARDUINOJSON_BEGIN_PRIVATE_NAMESPACE template <typename TWriter> class JsonSerializer : public Visitor<size_t> { public: static const bool producesText = true; - JsonSerializer(TWriter writer) : _formatter(writer) {} + JsonSerializer(TWriter writer) : formatter_(writer) {} FORCE_INLINE size_t visitArray(const CollectionData& array) { write('['); @@ -43,7 +43,7 @@ class JsonSerializer : public Visitor<size_t> { const VariantSlot* slot = object.head(); while (slot != 0) { - _formatter.writeString(slot->key()); + formatter_.writeString(slot->key()); write(':'); slot->data()->accept(*this); @@ -59,66 +59,71 @@ class JsonSerializer : public Visitor<size_t> { } size_t visitFloat(JsonFloat value) { - _formatter.writeFloat(value); + formatter_.writeFloat(value); return bytesWritten(); } size_t visitString(const char* value) { - _formatter.writeString(value); + formatter_.writeString(value); return bytesWritten(); } size_t visitString(const char* value, size_t n) { - _formatter.writeString(value, n); + formatter_.writeString(value, n); return bytesWritten(); } size_t visitRawJson(const char* data, size_t n) { - _formatter.writeRaw(data, n); + formatter_.writeRaw(data, n); return bytesWritten(); } size_t visitSignedInteger(JsonInteger value) { - _formatter.writeInteger(value); + formatter_.writeInteger(value); return bytesWritten(); } size_t visitUnsignedInteger(JsonUInt value) { - _formatter.writeInteger(value); + formatter_.writeInteger(value); return bytesWritten(); } size_t visitBoolean(bool value) { - _formatter.writeBoolean(value); + formatter_.writeBoolean(value); return bytesWritten(); } size_t visitNull() { - _formatter.writeRaw("null"); + formatter_.writeRaw("null"); return bytesWritten(); } protected: size_t bytesWritten() const { - return _formatter.bytesWritten(); + return formatter_.bytesWritten(); } void write(char c) { - _formatter.writeRaw(c); + formatter_.writeRaw(c); } void write(const char* s) { - _formatter.writeRaw(s); + formatter_.writeRaw(s); } private: - TextFormatter<TWriter> _formatter; + TextFormatter<TWriter> formatter_; }; +ARDUINOJSON_END_PRIVATE_NAMESPACE + +ARDUINOJSON_BEGIN_PUBLIC_NAMESPACE + // Produces a minified JSON document. // https://arduinojson.org/v6/api/json/serializejson/ template <typename TDestination> size_t serializeJson(JsonVariantConst source, TDestination& destination) { + using namespace detail; return serialize<JsonSerializer>(source, destination); } @@ -126,23 +131,25 @@ size_t serializeJson(JsonVariantConst source, TDestination& destination) { // https://arduinojson.org/v6/api/json/serializejson/ inline size_t serializeJson(JsonVariantConst source, void* buffer, size_t bufferSize) { + using namespace detail; return serialize<JsonSerializer>(source, buffer, bufferSize); } // Computes the length of the document that serializeJson() produces. // https://arduinojson.org/v6/api/json/measurejson/ inline size_t measureJson(JsonVariantConst source) { + using namespace detail; return measure<JsonSerializer>(source); } #if ARDUINOJSON_ENABLE_STD_STREAM template <typename T> -inline typename enable_if<is_convertible<T, JsonVariantConst>::value, - std::ostream&>::type +inline typename detail::enable_if< + detail::is_convertible<T, JsonVariantConst>::value, std::ostream&>::type operator<<(std::ostream& os, const T& source) { serializeJson(source, os); return os; } #endif -} // namespace ARDUINOJSON_NAMESPACE +ARDUINOJSON_END_PUBLIC_NAMESPACE diff --git a/neosensor/libraries/ArduinoJson/src/ArduinoJson/Json/Latch.hpp b/neosensor/libraries/ArduinoJson/src/ArduinoJson/Json/Latch.hpp index c422fef16c25c329eff884f6b1399546a6032d8c..08070eb3f78768fe0ce3df7b8cada2079c5623bd 100644 --- a/neosensor/libraries/ArduinoJson/src/ArduinoJson/Json/Latch.hpp +++ b/neosensor/libraries/ArduinoJson/src/ArduinoJson/Json/Latch.hpp @@ -1,56 +1,56 @@ // ArduinoJson - https://arduinojson.org -// Copyright © 2014-2022, Benoit BLANCHON +// Copyright © 2014-2023, Benoit BLANCHON // MIT License #pragma once #include <ArduinoJson/Polyfills/assert.hpp> -namespace ARDUINOJSON_NAMESPACE { +ARDUINOJSON_BEGIN_PRIVATE_NAMESPACE template <typename TReader> class Latch { public: - Latch(TReader reader) : _reader(reader), _loaded(false) { + Latch(TReader reader) : reader_(reader), loaded_(false) { #if ARDUINOJSON_DEBUG - _ended = false; + ended_ = false; #endif } void clear() { - _loaded = false; + loaded_ = false; } int last() const { - return _current; + return current_; } FORCE_INLINE char current() { - if (!_loaded) { + if (!loaded_) { load(); } - return _current; + return current_; } private: void load() { - ARDUINOJSON_ASSERT(!_ended); - int c = _reader.read(); + ARDUINOJSON_ASSERT(!ended_); + int c = reader_.read(); #if ARDUINOJSON_DEBUG if (c <= 0) - _ended = true; + ended_ = true; #endif - _current = static_cast<char>(c > 0 ? c : 0); - _loaded = true; + current_ = static_cast<char>(c > 0 ? c : 0); + loaded_ = true; } - TReader _reader; - char _current; // NOLINT(clang-analyzer-optin.cplusplus.UninitializedObject) + TReader reader_; + char current_; // NOLINT(clang-analyzer-optin.cplusplus.UninitializedObject) // Not initialized in constructor (+10 bytes on AVR) - bool _loaded; + bool loaded_; #if ARDUINOJSON_DEBUG - bool _ended; + bool ended_; #endif }; -} // namespace ARDUINOJSON_NAMESPACE +ARDUINOJSON_END_PRIVATE_NAMESPACE diff --git a/neosensor/libraries/ArduinoJson/src/ArduinoJson/Json/PrettyJsonSerializer.hpp b/neosensor/libraries/ArduinoJson/src/ArduinoJson/Json/PrettyJsonSerializer.hpp index e14ab0dbc645b011b6c57e8bf75935d3f83816e6..e8a92064239190170a739b9880e8eb3a99486cf0 100644 --- a/neosensor/libraries/ArduinoJson/src/ArduinoJson/Json/PrettyJsonSerializer.hpp +++ b/neosensor/libraries/ArduinoJson/src/ArduinoJson/Json/PrettyJsonSerializer.hpp @@ -1,5 +1,5 @@ // ArduinoJson - https://arduinojson.org -// Copyright © 2014-2022, Benoit BLANCHON +// Copyright © 2014-2023, Benoit BLANCHON // MIT License #pragma once @@ -9,20 +9,20 @@ #include <ArduinoJson/Serialization/measure.hpp> #include <ArduinoJson/Serialization/serialize.hpp> -namespace ARDUINOJSON_NAMESPACE { +ARDUINOJSON_BEGIN_PRIVATE_NAMESPACE template <typename TWriter> class PrettyJsonSerializer : public JsonSerializer<TWriter> { typedef JsonSerializer<TWriter> base; public: - PrettyJsonSerializer(TWriter writer) : base(writer), _nesting(0) {} + PrettyJsonSerializer(TWriter writer) : base(writer), nesting_(0) {} size_t visitArray(const CollectionData& array) { const VariantSlot* slot = array.head(); if (slot) { base::write("[\r\n"); - _nesting++; + nesting_++; while (slot != 0) { indent(); slot->data()->accept(*this); @@ -30,7 +30,7 @@ class PrettyJsonSerializer : public JsonSerializer<TWriter> { slot = slot->next(); base::write(slot ? ",\r\n" : "\r\n"); } - _nesting--; + nesting_--; indent(); base::write("]"); } else { @@ -43,7 +43,7 @@ class PrettyJsonSerializer : public JsonSerializer<TWriter> { const VariantSlot* slot = object.head(); if (slot) { base::write("{\r\n"); - _nesting++; + nesting_++; while (slot != 0) { indent(); base::visitString(slot->key()); @@ -53,7 +53,7 @@ class PrettyJsonSerializer : public JsonSerializer<TWriter> { slot = slot->next(); base::write(slot ? ",\r\n" : "\r\n"); } - _nesting--; + nesting_--; indent(); base::write("}"); } else { @@ -64,17 +64,22 @@ class PrettyJsonSerializer : public JsonSerializer<TWriter> { private: void indent() { - for (uint8_t i = 0; i < _nesting; i++) + for (uint8_t i = 0; i < nesting_; i++) base::write(ARDUINOJSON_TAB); } - uint8_t _nesting; + uint8_t nesting_; }; +ARDUINOJSON_END_PRIVATE_NAMESPACE + +ARDUINOJSON_BEGIN_PUBLIC_NAMESPACE + // Produces JsonDocument to create a prettified JSON document. // https://arduinojson.org/v6/api/json/serializejsonpretty/ template <typename TDestination> size_t serializeJsonPretty(JsonVariantConst source, TDestination& destination) { + using namespace ArduinoJson::detail; return serialize<PrettyJsonSerializer>(source, destination); } @@ -82,13 +87,15 @@ size_t serializeJsonPretty(JsonVariantConst source, TDestination& destination) { // https://arduinojson.org/v6/api/json/serializejsonpretty/ inline size_t serializeJsonPretty(JsonVariantConst source, void* buffer, size_t bufferSize) { + using namespace ArduinoJson::detail; return serialize<PrettyJsonSerializer>(source, buffer, bufferSize); } // Computes the length of the document that serializeJsonPretty() produces. // https://arduinojson.org/v6/api/json/measurejsonpretty/ inline size_t measureJsonPretty(JsonVariantConst source) { + using namespace ArduinoJson::detail; return measure<PrettyJsonSerializer>(source); } -} // namespace ARDUINOJSON_NAMESPACE +ARDUINOJSON_END_PUBLIC_NAMESPACE diff --git a/neosensor/libraries/ArduinoJson/src/ArduinoJson/Json/TextFormatter.hpp b/neosensor/libraries/ArduinoJson/src/ArduinoJson/Json/TextFormatter.hpp index 2080b14ccbe9d6d8c5a9e5cfa26fd55c83275354..f8eb2822c6c002a2dab9233b9a88965f8549a1b5 100644 --- a/neosensor/libraries/ArduinoJson/src/ArduinoJson/Json/TextFormatter.hpp +++ b/neosensor/libraries/ArduinoJson/src/ArduinoJson/Json/TextFormatter.hpp @@ -1,5 +1,5 @@ // ArduinoJson - https://arduinojson.org -// Copyright © 2014-2022, Benoit BLANCHON +// Copyright © 2014-2023, Benoit BLANCHON // MIT License #pragma once @@ -15,16 +15,18 @@ #include <ArduinoJson/Polyfills/type_traits.hpp> #include <ArduinoJson/Serialization/CountingDecorator.hpp> -namespace ARDUINOJSON_NAMESPACE { +ARDUINOJSON_BEGIN_PRIVATE_NAMESPACE template <typename TWriter> class TextFormatter { public: - explicit TextFormatter(TWriter writer) : _writer(writer) {} + explicit TextFormatter(TWriter writer) : writer_(writer) {} + + TextFormatter& operator=(const TextFormatter&) = delete; // Returns the number of bytes sent to the TWriter implementation. size_t bytesWritten() const { - return _writer.count(); + return writer_.count(); } void writeBoolean(bool value) { @@ -144,30 +146,28 @@ class TextFormatter { } void writeRaw(const char* s) { - _writer.write(reinterpret_cast<const uint8_t*>(s), strlen(s)); + writer_.write(reinterpret_cast<const uint8_t*>(s), strlen(s)); } void writeRaw(const char* s, size_t n) { - _writer.write(reinterpret_cast<const uint8_t*>(s), n); + writer_.write(reinterpret_cast<const uint8_t*>(s), n); } void writeRaw(const char* begin, const char* end) { - _writer.write(reinterpret_cast<const uint8_t*>(begin), + writer_.write(reinterpret_cast<const uint8_t*>(begin), static_cast<size_t>(end - begin)); } template <size_t N> void writeRaw(const char (&s)[N]) { - _writer.write(reinterpret_cast<const uint8_t*>(s), N - 1); + writer_.write(reinterpret_cast<const uint8_t*>(s), N - 1); } void writeRaw(char c) { - _writer.write(static_cast<uint8_t>(c)); + writer_.write(static_cast<uint8_t>(c)); } protected: - CountingDecorator<TWriter> _writer; - - private: - TextFormatter& operator=(const TextFormatter&); // cannot be assigned + CountingDecorator<TWriter> writer_; }; -} // namespace ARDUINOJSON_NAMESPACE + +ARDUINOJSON_END_PRIVATE_NAMESPACE diff --git a/neosensor/libraries/ArduinoJson/src/ArduinoJson/Json/Utf16.hpp b/neosensor/libraries/ArduinoJson/src/ArduinoJson/Json/Utf16.hpp index 3a22bf3a66d99aba2128cf882b72587c1e89d662..6e314db2827a94e0660f1836030443d2aae7b70f 100644 --- a/neosensor/libraries/ArduinoJson/src/ArduinoJson/Json/Utf16.hpp +++ b/neosensor/libraries/ArduinoJson/src/ArduinoJson/Json/Utf16.hpp @@ -1,5 +1,5 @@ // ArduinoJson - https://arduinojson.org -// Copyright © 2014-2022, Benoit BLANCHON +// Copyright © 2014-2023, Benoit BLANCHON // MIT License #pragma once @@ -18,7 +18,7 @@ # endif #endif -namespace ARDUINOJSON_NAMESPACE { +ARDUINOJSON_BEGIN_PRIVATE_NAMESPACE namespace Utf16 { inline bool isHighSurrogate(uint16_t codeunit) { @@ -31,34 +31,34 @@ inline bool isLowSurrogate(uint16_t codeunit) { class Codepoint { public: - Codepoint() : _highSurrogate(0), _codepoint(0) {} + Codepoint() : highSurrogate_(0), codepoint_(0) {} bool append(uint16_t codeunit) { if (isHighSurrogate(codeunit)) { - _highSurrogate = codeunit & 0x3FF; + highSurrogate_ = codeunit & 0x3FF; return false; } if (isLowSurrogate(codeunit)) { - _codepoint = - uint32_t(0x10000 + ((_highSurrogate << 10) | (codeunit & 0x3FF))); + codepoint_ = + uint32_t(0x10000 + ((highSurrogate_ << 10) | (codeunit & 0x3FF))); return true; } - _codepoint = codeunit; + codepoint_ = codeunit; return true; } uint32_t value() const { - return _codepoint; + return codepoint_; } private: - uint16_t _highSurrogate; - uint32_t _codepoint; + uint16_t highSurrogate_; + uint32_t codepoint_; }; } // namespace Utf16 -} // namespace ARDUINOJSON_NAMESPACE +ARDUINOJSON_END_PRIVATE_NAMESPACE #if defined(__GNUC__) # if __GNUC__ >= 8 diff --git a/neosensor/libraries/ArduinoJson/src/ArduinoJson/Json/Utf8.hpp b/neosensor/libraries/ArduinoJson/src/ArduinoJson/Json/Utf8.hpp index 0ec23ac76ffcb15255b3e6f870742147ad18f790..1e33c186cd6906c9824e80ea97c069c99da23485 100644 --- a/neosensor/libraries/ArduinoJson/src/ArduinoJson/Json/Utf8.hpp +++ b/neosensor/libraries/ArduinoJson/src/ArduinoJson/Json/Utf8.hpp @@ -1,12 +1,12 @@ // ArduinoJson - https://arduinojson.org -// Copyright © 2014-2022, Benoit BLANCHON +// Copyright © 2014-2023, Benoit BLANCHON // MIT License #pragma once #include <ArduinoJson/Namespace.hpp> -namespace ARDUINOJSON_NAMESPACE { +ARDUINOJSON_BEGIN_PRIVATE_NAMESPACE namespace Utf8 { template <typename TStringBuilder> @@ -43,4 +43,4 @@ inline void encodeCodepoint(uint32_t codepoint32, TStringBuilder& str) { } } } // namespace Utf8 -} // namespace ARDUINOJSON_NAMESPACE +ARDUINOJSON_END_PRIVATE_NAMESPACE diff --git a/neosensor/libraries/ArduinoJson/src/ArduinoJson/Memory/Alignment.hpp b/neosensor/libraries/ArduinoJson/src/ArduinoJson/Memory/Alignment.hpp index e9a6baff03205b96c2e534ba48e3299c6d4ee5bf..61b8654e7f40000c76ce04a81af9447d243f9541 100644 --- a/neosensor/libraries/ArduinoJson/src/ArduinoJson/Memory/Alignment.hpp +++ b/neosensor/libraries/ArduinoJson/src/ArduinoJson/Memory/Alignment.hpp @@ -1,5 +1,5 @@ // ArduinoJson - https://arduinojson.org -// Copyright © 2014-2022, Benoit BLANCHON +// Copyright © 2014-2023, Benoit BLANCHON // MIT License #pragma once @@ -8,7 +8,7 @@ #include <stddef.h> // size_t -namespace ARDUINOJSON_NAMESPACE { +ARDUINOJSON_BEGIN_PRIVATE_NAMESPACE #if ARDUINOJSON_ENABLE_ALIGNMENT @@ -57,4 +57,4 @@ inline T* addPadding(T* p) { return reinterpret_cast<T*>(address); } -} // namespace ARDUINOJSON_NAMESPACE +ARDUINOJSON_END_PRIVATE_NAMESPACE diff --git a/neosensor/libraries/ArduinoJson/src/ArduinoJson/Memory/MemoryPool.hpp b/neosensor/libraries/ArduinoJson/src/ArduinoJson/Memory/MemoryPool.hpp index a0329debd45779f66926ed44ca0417391ba435cf..754d58513acfa8a41044d33fce660afcd864a539 100644 --- a/neosensor/libraries/ArduinoJson/src/ArduinoJson/Memory/MemoryPool.hpp +++ b/neosensor/libraries/ArduinoJson/src/ArduinoJson/Memory/MemoryPool.hpp @@ -1,5 +1,5 @@ // ArduinoJson - https://arduinojson.org -// Copyright © 2014-2022, Benoit BLANCHON +// Copyright © 2014-2023, Benoit BLANCHON // MIT License #pragma once @@ -17,52 +17,52 @@ // Computes the size required to store an array in a JsonDocument. // https://arduinojson.org/v6/how-to/determine-the-capacity-of-the-jsondocument/ #define JSON_ARRAY_SIZE(NUMBER_OF_ELEMENTS) \ - ((NUMBER_OF_ELEMENTS) * sizeof(ARDUINOJSON_NAMESPACE::VariantSlot)) + ((NUMBER_OF_ELEMENTS) * sizeof(ArduinoJson::detail::VariantSlot)) // Returns the size (in bytes) of an object with n elements. // Can be very handy to determine the size of a StaticMemoryPool. #define JSON_OBJECT_SIZE(NUMBER_OF_ELEMENTS) \ - ((NUMBER_OF_ELEMENTS) * sizeof(ARDUINOJSON_NAMESPACE::VariantSlot)) + ((NUMBER_OF_ELEMENTS) * sizeof(ArduinoJson::detail::VariantSlot)) -namespace ARDUINOJSON_NAMESPACE { +ARDUINOJSON_BEGIN_PRIVATE_NAMESPACE -// _begin _end +// begin_ end_ // v v // +-------------+--------------+--------------+ // | strings... | (free) | ...variants | // +-------------+--------------+--------------+ // ^ ^ -// _left _right +// left_ right_ class MemoryPool { public: MemoryPool(char* buf, size_t capa) - : _begin(buf), - _left(buf), - _right(buf ? buf + capa : 0), - _end(buf ? buf + capa : 0), - _overflowed(false) { - ARDUINOJSON_ASSERT(isAligned(_begin)); - ARDUINOJSON_ASSERT(isAligned(_right)); - ARDUINOJSON_ASSERT(isAligned(_end)); + : begin_(buf), + left_(buf), + right_(buf ? buf + capa : 0), + end_(buf ? buf + capa : 0), + overflowed_(false) { + ARDUINOJSON_ASSERT(isAligned(begin_)); + ARDUINOJSON_ASSERT(isAligned(right_)); + ARDUINOJSON_ASSERT(isAligned(end_)); } void* buffer() { - return _begin; // NOLINT(clang-analyzer-unix.Malloc) + return begin_; // NOLINT(clang-analyzer-unix.Malloc) // movePointers() alters this pointer } // Gets the capacity of the memoryPool in bytes size_t capacity() const { - return size_t(_end - _begin); + return size_t(end_ - begin_); } size_t size() const { - return size_t(_left - _begin + _end - _right); + return size_t(left_ - begin_ + end_ - right_); } bool overflowed() const { - return _overflowed; + return overflowed_; } VariantSlot* allocVariant() { @@ -91,40 +91,40 @@ class MemoryPool { } void getFreeZone(char** zoneStart, size_t* zoneSize) const { - *zoneStart = _left; - *zoneSize = size_t(_right - _left); + *zoneStart = left_; + *zoneSize = size_t(right_ - left_); } const char* saveStringFromFreeZone(size_t len) { #if ARDUINOJSON_ENABLE_STRING_DEDUPLICATION - const char* dup = findString(adaptString(_left, len)); + const char* dup = findString(adaptString(left_, len)); if (dup) return dup; #endif - const char* str = _left; - _left += len; - *_left++ = 0; + const char* str = left_; + left_ += len; + *left_++ = 0; checkInvariants(); return str; } void markAsOverflowed() { - _overflowed = true; + overflowed_ = true; } void clear() { - _left = _begin; - _right = _end; - _overflowed = false; + left_ = begin_; + right_ = end_; + overflowed_ = false; } bool canAlloc(size_t bytes) const { - return _left + bytes <= _right; + return left_ + bytes <= right_; } bool owns(void* p) const { - return _begin <= p && p < _end; + return begin_ <= p && p < end_; } // Workaround for missing placement new @@ -134,51 +134,51 @@ class MemoryPool { // Squash the free space between strings and variants // - // _begin _end + // begin_ end_ // v v // +-------------+--------------+ // | strings... | ...variants | // +-------------+--------------+ // ^ - // _left _right + // left_ right_ // // This funcion is called before a realloc. ptrdiff_t squash() { - char* new_right = addPadding(_left); - if (new_right >= _right) + char* new_right = addPadding(left_); + if (new_right >= right_) return 0; - size_t right_size = static_cast<size_t>(_end - _right); - memmove(new_right, _right, right_size); + size_t right_size = static_cast<size_t>(end_ - right_); + memmove(new_right, right_, right_size); - ptrdiff_t bytes_reclaimed = _right - new_right; - _right = new_right; - _end = new_right + right_size; + ptrdiff_t bytes_reclaimed = right_ - new_right; + right_ = new_right; + end_ = new_right + right_size; return bytes_reclaimed; } // Move all pointers together // This funcion is called after a realloc. void movePointers(ptrdiff_t offset) { - _begin += offset; - _left += offset; - _right += offset; - _end += offset; + begin_ += offset; + left_ += offset; + right_ += offset; + end_ += offset; } private: void checkInvariants() { - ARDUINOJSON_ASSERT(_begin <= _left); - ARDUINOJSON_ASSERT(_left <= _right); - ARDUINOJSON_ASSERT(_right <= _end); - ARDUINOJSON_ASSERT(isAligned(_right)); + ARDUINOJSON_ASSERT(begin_ <= left_); + ARDUINOJSON_ASSERT(left_ <= right_); + ARDUINOJSON_ASSERT(right_ <= end_); + ARDUINOJSON_ASSERT(isAligned(right_)); } #if ARDUINOJSON_ENABLE_STRING_DEDUPLICATION template <typename TAdaptedString> const char* findString(const TAdaptedString& str) const { size_t n = str.size(); - for (char* next = _begin; next + n < _left; ++next) { + for (char* next = begin_; next + n < left_; ++next) { if (next[n] == '\0' && stringEquals(str, adaptString(next, n))) return next; @@ -192,11 +192,11 @@ class MemoryPool { char* allocString(size_t n) { if (!canAlloc(n)) { - _overflowed = true; + overflowed_ = true; return 0; } - char* s = _left; - _left += n; + char* s = left_; + left_ += n; checkInvariants(); return s; } @@ -208,15 +208,15 @@ class MemoryPool { void* allocRight(size_t bytes) { if (!canAlloc(bytes)) { - _overflowed = true; + overflowed_ = true; return 0; } - _right -= bytes; - return _right; + right_ -= bytes; + return right_; } - char *_begin, *_left, *_right, *_end; - bool _overflowed; + char *begin_, *left_, *right_, *end_; + bool overflowed_; }; template <typename TAdaptedString, typename TCallback> @@ -250,4 +250,4 @@ bool storeString(MemoryPool* pool, TAdaptedString str, TCallback callback) { return storeString(pool, str, str.storagePolicy(), callback); } -} // namespace ARDUINOJSON_NAMESPACE +ARDUINOJSON_END_PRIVATE_NAMESPACE diff --git a/neosensor/libraries/ArduinoJson/src/ArduinoJson/Misc/SafeBoolIdiom.hpp b/neosensor/libraries/ArduinoJson/src/ArduinoJson/Misc/SafeBoolIdiom.hpp deleted file mode 100644 index ff4bf53a38b7204203a0706690a00d5838fc18a6..0000000000000000000000000000000000000000 --- a/neosensor/libraries/ArduinoJson/src/ArduinoJson/Misc/SafeBoolIdiom.hpp +++ /dev/null @@ -1,26 +0,0 @@ -// ArduinoJson - https://arduinojson.org -// Copyright © 2014-2022, Benoit BLANCHON -// MIT License - -#pragma once - -#include <ArduinoJson/Polyfills/type_traits.hpp> - -namespace ARDUINOJSON_NAMESPACE { - -template <typename T> -class SafeBoolIdom { - protected: - typedef void (T::*bool_type)() const; - void safeBoolHelper() const {} - - static bool_type safe_true() { - return &SafeBoolIdom::safeBoolHelper; - } - - static bool_type safe_false() { - return 0; - } -}; - -} // namespace ARDUINOJSON_NAMESPACE diff --git a/neosensor/libraries/ArduinoJson/src/ArduinoJson/Misc/SerializedValue.hpp b/neosensor/libraries/ArduinoJson/src/ArduinoJson/Misc/SerializedValue.hpp index 217c6f3c505940f57e0bc433dd144ad06cfd79aa..ae9abd3c3773fd1386e7ff0d51c009d0d09de70d 100644 --- a/neosensor/libraries/ArduinoJson/src/ArduinoJson/Misc/SerializedValue.hpp +++ b/neosensor/libraries/ArduinoJson/src/ArduinoJson/Misc/SerializedValue.hpp @@ -1,54 +1,54 @@ // ArduinoJson - https://arduinojson.org -// Copyright © 2014-2022, Benoit BLANCHON +// Copyright © 2014-2023, Benoit BLANCHON // MIT License #pragma once #include <ArduinoJson/Strings/StringAdapters.hpp> -namespace ARDUINOJSON_NAMESPACE { +ARDUINOJSON_BEGIN_PUBLIC_NAMESPACE // A special type of data that can be used to insert pregenerated JSON portions. template <typename T> class SerializedValue { public: - explicit SerializedValue(T str) : _str(str) {} + explicit SerializedValue(T str) : str_(str) {} operator T() const { - return _str; + return str_; } const char* data() const { - return _str.c_str(); + return str_.c_str(); } size_t size() const { // CAUTION: the old Arduino String doesn't have size() - return _str.length(); + return str_.length(); } private: - T _str; + T str_; }; template <typename TChar> class SerializedValue<TChar*> { public: - explicit SerializedValue(TChar* p, size_t n) : _data(p), _size(n) {} + explicit SerializedValue(TChar* p, size_t n) : data_(p), size_(n) {} operator TChar*() const { - return _data; + return data_; } TChar* data() const { - return _data; + return data_; } size_t size() const { - return _size; + return size_; } private: - TChar* _data; - size_t _size; + TChar* data_; + size_t size_; }; template <typename T> @@ -58,11 +58,12 @@ inline SerializedValue<T> serialized(T str) { template <typename TChar> inline SerializedValue<TChar*> serialized(TChar* p) { - return SerializedValue<TChar*>(p, adaptString(p).size()); + return SerializedValue<TChar*>(p, detail::adaptString(p).size()); } template <typename TChar> inline SerializedValue<TChar*> serialized(TChar* p, size_t n) { return SerializedValue<TChar*>(p, n); } -} // namespace ARDUINOJSON_NAMESPACE + +ARDUINOJSON_END_PUBLIC_NAMESPACE diff --git a/neosensor/libraries/ArduinoJson/src/ArduinoJson/MsgPack/MsgPackDeserializer.hpp b/neosensor/libraries/ArduinoJson/src/ArduinoJson/MsgPack/MsgPackDeserializer.hpp index 5013d2e29e40cc386c377faa59f8f9a537e0372d..41934295bc921f2eda04b79a1d1ff01a514b4855 100644 --- a/neosensor/libraries/ArduinoJson/src/ArduinoJson/MsgPack/MsgPackDeserializer.hpp +++ b/neosensor/libraries/ArduinoJson/src/ArduinoJson/MsgPack/MsgPackDeserializer.hpp @@ -1,5 +1,5 @@ // ArduinoJson - https://arduinojson.org -// Copyright © 2014-2022, Benoit BLANCHON +// Copyright © 2014-2023, Benoit BLANCHON // MIT License #pragma once @@ -11,30 +11,31 @@ #include <ArduinoJson/Polyfills/type_traits.hpp> #include <ArduinoJson/Variant/VariantData.hpp> -namespace ARDUINOJSON_NAMESPACE { +ARDUINOJSON_BEGIN_PRIVATE_NAMESPACE template <typename TReader, typename TStringStorage> class MsgPackDeserializer { public: MsgPackDeserializer(MemoryPool* pool, TReader reader, TStringStorage stringStorage) - : _pool(pool), - _reader(reader), - _stringStorage(stringStorage), - _foundSomething(false) {} + : pool_(pool), + reader_(reader), + stringStorage_(stringStorage), + foundSomething_(false) {} template <typename TFilter> DeserializationError parse(VariantData& variant, TFilter filter, - NestingLimit nestingLimit) { + DeserializationOption::NestingLimit nestingLimit) { DeserializationError::Code err; err = parseVariant(&variant, filter, nestingLimit); - return _foundSomething ? err : DeserializationError::EmptyInput; + return foundSomething_ ? err : DeserializationError::EmptyInput; } private: template <typename TFilter> - DeserializationError::Code parseVariant(VariantData* variant, TFilter filter, - NestingLimit nestingLimit) { + DeserializationError::Code parseVariant( + VariantData* variant, TFilter filter, + DeserializationOption::NestingLimit nestingLimit) { DeserializationError::Code err; uint8_t code = 0; // TODO: why do we need to initialize this variable? @@ -42,7 +43,7 @@ class MsgPackDeserializer { if (err) return err; - _foundSomething = true; + foundSomething_ = true; bool allowValue = filter.allowValue(); @@ -223,7 +224,7 @@ class MsgPackDeserializer { } DeserializationError::Code readByte(uint8_t& value) { - int c = _reader.read(); + int c = reader_.read(); if (c < 0) return DeserializationError::IncompleteInput; value = static_cast<uint8_t>(c); @@ -231,7 +232,7 @@ class MsgPackDeserializer { } DeserializationError::Code readBytes(uint8_t* p, size_t n) { - if (_reader.readBytes(reinterpret_cast<char*>(p), n) == n) + if (reader_.readBytes(reinterpret_cast<char*>(p), n) == n) return DeserializationError::Ok; return DeserializationError::IncompleteInput; } @@ -243,7 +244,7 @@ class MsgPackDeserializer { DeserializationError::Code skipBytes(size_t n) { for (; n; --n) { - if (_reader.read() < 0) + if (reader_.read() < 0) return DeserializationError::IncompleteInput; } return DeserializationError::Ok; @@ -370,14 +371,14 @@ class MsgPackDeserializer { if (err) return err; - variant->setString(_stringStorage.save()); + variant->setString(stringStorage_.save()); return DeserializationError::Ok; } DeserializationError::Code readString(size_t n) { DeserializationError::Code err; - _stringStorage.startString(); + stringStorage_.startString(); for (; n; --n) { uint8_t c; @@ -385,18 +386,19 @@ class MsgPackDeserializer { if (err) return err; - _stringStorage.append(static_cast<char>(c)); + stringStorage_.append(static_cast<char>(c)); } - if (!_stringStorage.isValid()) + if (!stringStorage_.isValid()) return DeserializationError::NoMemory; return DeserializationError::Ok; } template <typename TSize, typename TFilter> - DeserializationError::Code readArray(VariantData* variant, TFilter filter, - NestingLimit nestingLimit) { + DeserializationError::Code readArray( + VariantData* variant, TFilter filter, + DeserializationOption::NestingLimit nestingLimit) { DeserializationError::Code err; TSize size; @@ -408,9 +410,9 @@ class MsgPackDeserializer { } template <typename TFilter> - DeserializationError::Code readArray(VariantData* variant, size_t n, - TFilter filter, - NestingLimit nestingLimit) { + DeserializationError::Code readArray( + VariantData* variant, size_t n, TFilter filter, + DeserializationOption::NestingLimit nestingLimit) { DeserializationError::Code err; if (nestingLimit.reached()) @@ -418,7 +420,13 @@ class MsgPackDeserializer { bool allowArray = filter.allowArray(); - CollectionData* array = allowArray ? &variant->toArray() : 0; + CollectionData* array; + if (allowArray) { + ARDUINOJSON_ASSERT(variant != 0); + array = &variant->toArray(); + } else { + array = 0; + } TFilter memberFilter = filter[0U]; @@ -426,7 +434,8 @@ class MsgPackDeserializer { VariantData* value; if (memberFilter.allow()) { - value = array->addElement(_pool); + ARDUINOJSON_ASSERT(array != 0); + value = array->addElement(pool_); if (!value) return DeserializationError::NoMemory; } else { @@ -442,8 +451,9 @@ class MsgPackDeserializer { } template <typename TSize, typename TFilter> - DeserializationError::Code readObject(VariantData* variant, TFilter filter, - NestingLimit nestingLimit) { + DeserializationError::Code readObject( + VariantData* variant, TFilter filter, + DeserializationOption::NestingLimit nestingLimit) { DeserializationError::Code err; TSize size; @@ -455,33 +465,39 @@ class MsgPackDeserializer { } template <typename TFilter> - DeserializationError::Code readObject(VariantData* variant, size_t n, - TFilter filter, - NestingLimit nestingLimit) { + DeserializationError::Code readObject( + VariantData* variant, size_t n, TFilter filter, + DeserializationOption::NestingLimit nestingLimit) { DeserializationError::Code err; if (nestingLimit.reached()) return DeserializationError::TooDeep; - CollectionData* object = filter.allowObject() ? &variant->toObject() : 0; + CollectionData* object; + if (filter.allowObject()) { + ARDUINOJSON_ASSERT(variant != 0); + object = &variant->toObject(); + } else { + object = 0; + } for (; n; --n) { err = readKey(); if (err) return err; - JsonString key = _stringStorage.str(); + JsonString key = stringStorage_.str(); TFilter memberFilter = filter[key.c_str()]; VariantData* member; if (memberFilter.allow()) { - ARDUINOJSON_ASSERT(object); + ARDUINOJSON_ASSERT(object != 0); // Save key in memory pool. // This MUST be done before adding the slot. - key = _stringStorage.save(); + key = stringStorage_.save(); - VariantSlot* slot = object->addSlot(_pool); + VariantSlot* slot = object->addSlot(pool_); if (!slot) return DeserializationError::NoMemory; @@ -538,125 +554,32 @@ class MsgPackDeserializer { return skipBytes(size + 1U); } - MemoryPool* _pool; - TReader _reader; - TStringStorage _stringStorage; - bool _foundSomething; + MemoryPool* pool_; + TReader reader_; + TStringStorage stringStorage_; + bool foundSomething_; }; -// Parses a MessagePack input and puts the result in a JsonDocument. -// https://arduinojson.org/v6/api/msgpack/deserializemsgpack/ -template <typename TString> -DeserializationError deserializeMsgPack( - JsonDocument& doc, const TString& input, - NestingLimit nestingLimit = NestingLimit()) { - return deserialize<MsgPackDeserializer>(doc, input, nestingLimit, - AllowAllFilter()); -} - -// Parses a MessagePack input, filters, and puts the result in a JsonDocument. -// https://arduinojson.org/v6/api/msgpack/deserializemsgpack/ -template <typename TString> -DeserializationError deserializeMsgPack( - JsonDocument& doc, const TString& input, Filter filter, - NestingLimit nestingLimit = NestingLimit()) { - return deserialize<MsgPackDeserializer>(doc, input, nestingLimit, filter); -} +ARDUINOJSON_END_PRIVATE_NAMESPACE -// Parses a MessagePack input, filters, and puts the result in a JsonDocument. -// https://arduinojson.org/v6/api/msgpack/deserializemsgpack/ -template <typename TString> -DeserializationError deserializeMsgPack(JsonDocument& doc, const TString& input, - NestingLimit nestingLimit, - Filter filter) { - return deserialize<MsgPackDeserializer>(doc, input, nestingLimit, filter); -} +ARDUINOJSON_BEGIN_PUBLIC_NAMESPACE // Parses a MessagePack input and puts the result in a JsonDocument. // https://arduinojson.org/v6/api/msgpack/deserializemsgpack/ -template <typename TStream> -DeserializationError deserializeMsgPack( - JsonDocument& doc, TStream& input, - NestingLimit nestingLimit = NestingLimit()) { - return deserialize<MsgPackDeserializer>(doc, input, nestingLimit, - AllowAllFilter()); -} - -// Parses a MessagePack input, filters, and puts the result in a JsonDocument. -// https://arduinojson.org/v6/api/msgpack/deserializemsgpack/ -template <typename TStream> -DeserializationError deserializeMsgPack( - JsonDocument& doc, TStream& input, Filter filter, - NestingLimit nestingLimit = NestingLimit()) { - return deserialize<MsgPackDeserializer>(doc, input, nestingLimit, filter); -} - -// Parses a MessagePack input, filters, and puts the result in a JsonDocument. -// https://arduinojson.org/v6/api/msgpack/deserializemsgpack/ -template <typename TStream> -DeserializationError deserializeMsgPack(JsonDocument& doc, TStream& input, - NestingLimit nestingLimit, - Filter filter) { - return deserialize<MsgPackDeserializer>(doc, input, nestingLimit, filter); +template <typename... Args> +DeserializationError deserializeMsgPack(JsonDocument& doc, Args&&... args) { + using namespace detail; + return deserialize<MsgPackDeserializer>(doc, detail::forward<Args>(args)...); } // Parses a MessagePack input and puts the result in a JsonDocument. // https://arduinojson.org/v6/api/msgpack/deserializemsgpack/ -template <typename TChar> -DeserializationError deserializeMsgPack( - JsonDocument& doc, TChar* input, - NestingLimit nestingLimit = NestingLimit()) { - return deserialize<MsgPackDeserializer>(doc, input, nestingLimit, - AllowAllFilter()); -} - -// Parses a MessagePack input, filters, and puts the result in a JsonDocument. -// https://arduinojson.org/v6/api/msgpack/deserializemsgpack/ -template <typename TChar> -DeserializationError deserializeMsgPack( - JsonDocument& doc, TChar* input, Filter filter, - NestingLimit nestingLimit = NestingLimit()) { - return deserialize<MsgPackDeserializer>(doc, input, nestingLimit, filter); -} - -// Parses a MessagePack input, filters, and puts the result in a JsonDocument. -// https://arduinojson.org/v6/api/msgpack/deserializemsgpack/ -template <typename TChar> -DeserializationError deserializeMsgPack(JsonDocument& doc, TChar* input, - NestingLimit nestingLimit, - Filter filter) { - return deserialize<MsgPackDeserializer>(doc, input, nestingLimit, filter); -} - -// Parses a MessagePack input and puts the result in a JsonDocument. -// https://arduinojson.org/v6/api/msgpack/deserializemsgpack/ -template <typename TChar> -DeserializationError deserializeMsgPack( - JsonDocument& doc, TChar* input, size_t inputSize, - NestingLimit nestingLimit = NestingLimit()) { - return deserialize<MsgPackDeserializer>(doc, input, inputSize, nestingLimit, - AllowAllFilter()); -} - -// Parses a MessagePack input, filters, and puts the result in a JsonDocument. -// https://arduinojson.org/v6/api/msgpack/deserializemsgpack/ -template <typename TChar> -DeserializationError deserializeMsgPack( - JsonDocument& doc, TChar* input, size_t inputSize, Filter filter, - NestingLimit nestingLimit = NestingLimit()) { - return deserialize<MsgPackDeserializer>(doc, input, inputSize, nestingLimit, - filter); -} - -// Parses a MessagePack input, filters, and puts the result in a JsonDocument. -// https://arduinojson.org/v6/api/msgpack/deserializemsgpack/ -template <typename TChar> +template <typename TChar, typename... Args> DeserializationError deserializeMsgPack(JsonDocument& doc, TChar* input, - size_t inputSize, - NestingLimit nestingLimit, - Filter filter) { - return deserialize<MsgPackDeserializer>(doc, input, inputSize, nestingLimit, - filter); + Args&&... args) { + using namespace detail; + return deserialize<MsgPackDeserializer>(doc, input, + detail::forward<Args>(args)...); } -} // namespace ARDUINOJSON_NAMESPACE +ARDUINOJSON_END_PUBLIC_NAMESPACE diff --git a/neosensor/libraries/ArduinoJson/src/ArduinoJson/MsgPack/MsgPackSerializer.hpp b/neosensor/libraries/ArduinoJson/src/ArduinoJson/MsgPack/MsgPackSerializer.hpp index d2c44238ac6468ec94ea96dde39560e58a6b474e..65769a16c6963a23547cb6846b15ef9fc355f401 100644 --- a/neosensor/libraries/ArduinoJson/src/ArduinoJson/MsgPack/MsgPackSerializer.hpp +++ b/neosensor/libraries/ArduinoJson/src/ArduinoJson/MsgPack/MsgPackSerializer.hpp @@ -1,5 +1,5 @@ // ArduinoJson - https://arduinojson.org -// Copyright © 2014-2022, Benoit BLANCHON +// Copyright © 2014-2023, Benoit BLANCHON // MIT License #pragma once @@ -12,14 +12,14 @@ #include <ArduinoJson/Serialization/serialize.hpp> #include <ArduinoJson/Variant/VariantData.hpp> -namespace ARDUINOJSON_NAMESPACE { +ARDUINOJSON_BEGIN_PRIVATE_NAMESPACE template <typename TWriter> class MsgPackSerializer : public Visitor<size_t> { public: static const bool producesText = false; - MsgPackSerializer(TWriter writer) : _writer(writer) {} + MsgPackSerializer(TWriter writer) : writer_(writer) {} template <typename T> typename enable_if<sizeof(T) == 4, size_t>::type visitFloat(T value32) { @@ -177,15 +177,15 @@ class MsgPackSerializer : public Visitor<size_t> { private: size_t bytesWritten() const { - return _writer.count(); + return writer_.count(); } void writeByte(uint8_t c) { - _writer.write(c); + writer_.write(c); } void writeBytes(const uint8_t* p, size_t n) { - _writer.write(p, n); + writer_.write(p, n); } template <typename T> @@ -194,13 +194,18 @@ class MsgPackSerializer : public Visitor<size_t> { writeBytes(reinterpret_cast<uint8_t*>(&value), sizeof(value)); } - CountingDecorator<TWriter> _writer; + CountingDecorator<TWriter> writer_; }; +ARDUINOJSON_END_PRIVATE_NAMESPACE + +ARDUINOJSON_BEGIN_PUBLIC_NAMESPACE + // Produces a MessagePack document. // https://arduinojson.org/v6/api/msgpack/serializemsgpack/ template <typename TDestination> inline size_t serializeMsgPack(JsonVariantConst source, TDestination& output) { + using namespace ArduinoJson::detail; return serialize<MsgPackSerializer>(source, output); } @@ -208,13 +213,15 @@ inline size_t serializeMsgPack(JsonVariantConst source, TDestination& output) { // https://arduinojson.org/v6/api/msgpack/serializemsgpack/ inline size_t serializeMsgPack(JsonVariantConst source, void* output, size_t size) { + using namespace ArduinoJson::detail; return serialize<MsgPackSerializer>(source, output, size); } // Computes the length of the document that serializeMsgPack() produces. // https://arduinojson.org/v6/api/msgpack/measuremsgpack/ inline size_t measureMsgPack(JsonVariantConst source) { + using namespace ArduinoJson::detail; return measure<MsgPackSerializer>(source); } -} // namespace ARDUINOJSON_NAMESPACE +ARDUINOJSON_END_PUBLIC_NAMESPACE diff --git a/neosensor/libraries/ArduinoJson/src/ArduinoJson/MsgPack/endianess.hpp b/neosensor/libraries/ArduinoJson/src/ArduinoJson/MsgPack/endianess.hpp index 98e3156bd92b8f754577c6026d4db098bdd37198..bb2dadd318b475362c746bab78a8718a65194a15 100644 --- a/neosensor/libraries/ArduinoJson/src/ArduinoJson/MsgPack/endianess.hpp +++ b/neosensor/libraries/ArduinoJson/src/ArduinoJson/MsgPack/endianess.hpp @@ -1,12 +1,12 @@ // ArduinoJson - https://arduinojson.org -// Copyright © 2014-2022, Benoit BLANCHON +// Copyright © 2014-2023, Benoit BLANCHON // MIT License #pragma once #include <ArduinoJson/Polyfills/type_traits.hpp> -namespace ARDUINOJSON_NAMESPACE { +ARDUINOJSON_BEGIN_PRIVATE_NAMESPACE #if ARDUINOJSON_LITTLE_ENDIAN inline void swapBytes(uint8_t& a, uint8_t& b) { @@ -43,4 +43,4 @@ template <typename T> inline void fixEndianess(T&) {} #endif -} // namespace ARDUINOJSON_NAMESPACE +ARDUINOJSON_END_PRIVATE_NAMESPACE diff --git a/neosensor/libraries/ArduinoJson/src/ArduinoJson/MsgPack/ieee754.hpp b/neosensor/libraries/ArduinoJson/src/ArduinoJson/MsgPack/ieee754.hpp index 16f380ae9c47d787ce7faf34b762de02de73daa2..8513d493c670754977190abe1f9f54d84bfdd800 100644 --- a/neosensor/libraries/ArduinoJson/src/ArduinoJson/MsgPack/ieee754.hpp +++ b/neosensor/libraries/ArduinoJson/src/ArduinoJson/MsgPack/ieee754.hpp @@ -1,12 +1,12 @@ // ArduinoJson - https://arduinojson.org -// Copyright © 2014-2022, Benoit BLANCHON +// Copyright © 2014-2023, Benoit BLANCHON // MIT License #pragma once #include <ArduinoJson/Namespace.hpp> -namespace ARDUINOJSON_NAMESPACE { +ARDUINOJSON_BEGIN_PRIVATE_NAMESPACE inline void doubleToFloat(const uint8_t d[8], uint8_t f[4]) { f[0] = uint8_t((d[0] & 0xC0) | (d[0] << 3 & 0x3f) | (d[1] >> 5)); @@ -15,4 +15,4 @@ inline void doubleToFloat(const uint8_t d[8], uint8_t f[4]) { f[3] = uint8_t((d[3] << 3) | (d[4] >> 5)); } -} // namespace ARDUINOJSON_NAMESPACE +ARDUINOJSON_END_PRIVATE_NAMESPACE diff --git a/neosensor/libraries/ArduinoJson/src/ArduinoJson/Namespace.hpp b/neosensor/libraries/ArduinoJson/src/ArduinoJson/Namespace.hpp index ac4004eb63adc8899d4c98e41e586152c7ff0a8d..7f3b8b49ba7a7b82c04ebd86daeb23cc9c725a58 100644 --- a/neosensor/libraries/ArduinoJson/src/ArduinoJson/Namespace.hpp +++ b/neosensor/libraries/ArduinoJson/src/ArduinoJson/Namespace.hpp @@ -1,5 +1,5 @@ // ArduinoJson - https://arduinojson.org -// Copyright © 2014-2022, Benoit BLANCHON +// Copyright © 2014-2023, Benoit BLANCHON // MIT License #pragma once @@ -8,19 +8,36 @@ #include <ArduinoJson/Polyfills/preprocessor.hpp> #include <ArduinoJson/version.hpp> -#ifndef ARDUINOJSON_NAMESPACE +#ifndef ARDUINOJSON_VERSION_NAMESPACE -# define ARDUINOJSON_NAMESPACE \ - ARDUINOJSON_CONCAT4( \ - ARDUINOJSON_CONCAT4(ArduinoJson, ARDUINOJSON_VERSION_MAJOR, \ +# define ARDUINOJSON_VERSION_NAMESPACE \ + ARDUINOJSON_CONCAT3( \ + ARDUINOJSON_CONCAT4(V, ARDUINOJSON_VERSION_MAJOR, \ ARDUINOJSON_VERSION_MINOR, \ ARDUINOJSON_VERSION_REVISION), \ - _, \ - ARDUINOJSON_HEX_DIGIT( \ + ARDUINOJSON_BIN2ALPHA( \ ARDUINOJSON_ENABLE_PROGMEM, ARDUINOJSON_USE_LONG_LONG, \ ARDUINOJSON_USE_DOUBLE, ARDUINOJSON_ENABLE_STRING_DEDUPLICATION), \ - ARDUINOJSON_HEX_DIGIT( \ + ARDUINOJSON_BIN2ALPHA( \ ARDUINOJSON_ENABLE_NAN, ARDUINOJSON_ENABLE_INFINITY, \ ARDUINOJSON_ENABLE_COMMENTS, ARDUINOJSON_DECODE_UNICODE)) #endif + +#define ARDUINOJSON_BEGIN_PUBLIC_NAMESPACE \ + namespace ArduinoJson { \ + inline namespace ARDUINOJSON_VERSION_NAMESPACE { + +#define ARDUINOJSON_END_PUBLIC_NAMESPACE \ + } \ + } + +#define ARDUINOJSON_BEGIN_PRIVATE_NAMESPACE \ + namespace ArduinoJson { \ + inline namespace ARDUINOJSON_VERSION_NAMESPACE { \ + namespace detail { + +#define ARDUINOJSON_END_PRIVATE_NAMESPACE \ + } \ + } \ + } diff --git a/neosensor/libraries/ArduinoJson/src/ArduinoJson/Numbers/FloatParts.hpp b/neosensor/libraries/ArduinoJson/src/ArduinoJson/Numbers/FloatParts.hpp index 2f28ff75e1456515bc95f4264199bf1a35bf9fa6..214bc7a8dd1cc30300f0e484e80749b498c2203d 100644 --- a/neosensor/libraries/ArduinoJson/src/ArduinoJson/Numbers/FloatParts.hpp +++ b/neosensor/libraries/ArduinoJson/src/ArduinoJson/Numbers/FloatParts.hpp @@ -1,5 +1,5 @@ // ArduinoJson - https://arduinojson.org -// Copyright © 2014-2022, Benoit BLANCHON +// Copyright © 2014-2023, Benoit BLANCHON // MIT License #pragma once @@ -8,7 +8,7 @@ #include <ArduinoJson/Numbers/FloatTraits.hpp> #include <ArduinoJson/Polyfills/math.hpp> -namespace ARDUINOJSON_NAMESPACE { +ARDUINOJSON_BEGIN_PRIVATE_NAMESPACE template <typename TFloat> struct FloatParts { @@ -63,8 +63,8 @@ struct FloatParts { if (value >= ARDUINOJSON_POSITIVE_EXPONENTIATION_THRESHOLD) { for (; index >= 0; index--) { - if (value >= traits::positiveBinaryPowerOfTen(index)) { - value *= traits::negativeBinaryPowerOfTen(index); + if (value >= traits::positiveBinaryPowersOfTen()[index]) { + value *= traits::negativeBinaryPowersOfTen()[index]; powersOf10 = int16_t(powersOf10 + bit); } bit >>= 1; @@ -73,8 +73,8 @@ struct FloatParts { if (value > 0 && value <= ARDUINOJSON_NEGATIVE_EXPONENTIATION_THRESHOLD) { for (; index >= 0; index--) { - if (value < traits::negativeBinaryPowerOfTenPlusOne(index)) { - value *= traits::positiveBinaryPowerOfTen(index); + if (value < traits::negativeBinaryPowersOfTen()[index] * 10) { + value *= traits::positiveBinaryPowersOfTen()[index]; powersOf10 = int16_t(powersOf10 - bit); } bit >>= 1; @@ -84,4 +84,5 @@ struct FloatParts { return powersOf10; } }; -} // namespace ARDUINOJSON_NAMESPACE + +ARDUINOJSON_END_PRIVATE_NAMESPACE diff --git a/neosensor/libraries/ArduinoJson/src/ArduinoJson/Numbers/FloatTraits.hpp b/neosensor/libraries/ArduinoJson/src/ArduinoJson/Numbers/FloatTraits.hpp index 4d5782b7a6aa7a7bab99f38aff00e9adea3384cd..23abd7fff5451eaa5b5b6c76f22ea6894fe82ef0 100644 --- a/neosensor/libraries/ArduinoJson/src/ArduinoJson/Numbers/FloatTraits.hpp +++ b/neosensor/libraries/ArduinoJson/src/ArduinoJson/Numbers/FloatTraits.hpp @@ -1,5 +1,5 @@ // ArduinoJson - https://arduinojson.org -// Copyright © 2014-2022, Benoit BLANCHON +// Copyright © 2014-2023, Benoit BLANCHON // MIT License #pragma once @@ -10,11 +10,11 @@ #include <ArduinoJson/Configuration.hpp> #include <ArduinoJson/Polyfills/alias_cast.hpp> #include <ArduinoJson/Polyfills/math.hpp> +#include <ArduinoJson/Polyfills/pgmspace_generic.hpp> #include <ArduinoJson/Polyfills/preprocessor.hpp> -#include <ArduinoJson/Polyfills/static_array.hpp> #include <ArduinoJson/Polyfills/type_traits.hpp> -namespace ARDUINOJSON_NAMESPACE { +ARDUINOJSON_BEGIN_PRIVATE_NAMESPACE template <typename T, size_t = sizeof(T)> struct FloatTraits {}; @@ -29,92 +29,50 @@ struct FloatTraits<T, 8 /*64bits*/> { typedef int16_t exponent_type; static const exponent_type exponent_max = 308; - template <typename TExponent> - static T make_float(T m, TExponent e) { - if (e > 0) { - for (uint8_t index = 0; e != 0; index++) { - if (e & 1) - m *= positiveBinaryPowerOfTen(index); - e >>= 1; - } - } else { - e = TExponent(-e); - for (uint8_t index = 0; e != 0; index++) { - if (e & 1) - m *= negativeBinaryPowerOfTen(index); - e >>= 1; - } - } - return m; - } - - static T positiveBinaryPowerOfTen(int index) { - ARDUINOJSON_DEFINE_STATIC_ARRAY( // - uint32_t, factors, - ARDUINOJSON_EXPAND18({ - 0x40240000, 0x00000000, // 1e1 - 0x40590000, 0x00000000, // 1e2 - 0x40C38800, 0x00000000, // 1e4 - 0x4197D784, 0x00000000, // 1e8 - 0x4341C379, 0x37E08000, // 1e16 - 0x4693B8B5, 0xB5056E17, // 1e32 - 0x4D384F03, 0xE93FF9F5, // 1e64 - 0x5A827748, 0xF9301D32, // 1e128 - 0x75154FDD, 0x7F73BF3C // 1e256 - })); - return forge( - ARDUINOJSON_READ_STATIC_ARRAY(uint32_t, factors, 2 * index), - ARDUINOJSON_READ_STATIC_ARRAY(uint32_t, factors, 2 * index + 1)); - } - - static T negativeBinaryPowerOfTen(int index) { - ARDUINOJSON_DEFINE_STATIC_ARRAY( // - uint32_t, factors, - ARDUINOJSON_EXPAND18({ - 0x3FB99999, 0x9999999A, // 1e-1 - 0x3F847AE1, 0x47AE147B, // 1e-2 - 0x3F1A36E2, 0xEB1C432D, // 1e-4 - 0x3E45798E, 0xE2308C3A, // 1e-8 - 0x3C9CD2B2, 0x97D889BC, // 1e-16 - 0x3949F623, 0xD5A8A733, // 1e-32 - 0x32A50FFD, 0x44F4A73D, // 1e-64 - 0x255BBA08, 0xCF8C979D, // 1e-128 - 0x0AC80628, 0x64AC6F43 // 1e-256 - })); - return forge( - ARDUINOJSON_READ_STATIC_ARRAY(uint32_t, factors, 2 * index), - ARDUINOJSON_READ_STATIC_ARRAY(uint32_t, factors, 2 * index + 1)); - } - - static T negativeBinaryPowerOfTenPlusOne(int index) { - ARDUINOJSON_DEFINE_STATIC_ARRAY( // - uint32_t, factors, - ARDUINOJSON_EXPAND18({ - 0x3FF00000, 0x00000000, // 1e0 - 0x3FB99999, 0x9999999A, // 1e-1 - 0x3F50624D, 0xD2F1A9FC, // 1e-3 - 0x3E7AD7F2, 0x9ABCAF48, // 1e-7 - 0x3CD203AF, 0x9EE75616, // 1e-15 - 0x398039D6, 0x65896880, // 1e-31 - 0x32DA53FC, 0x9631D10D, // 1e-63 - 0x25915445, 0x81B7DEC2, // 1e-127 - 0x0AFE07B2, 0x7DD78B14 // 1e-255 - })); - return forge( - ARDUINOJSON_READ_STATIC_ARRAY(uint32_t, factors, 2 * index), - ARDUINOJSON_READ_STATIC_ARRAY(uint32_t, factors, 2 * index + 1)); + static pgm_ptr<T> positiveBinaryPowersOfTen() { + ARDUINOJSON_DEFINE_PROGMEM_ARRAY( // + uint64_t, factors, + { + 0x4024000000000000, // 1e1 + 0x4059000000000000, // 1e2 + 0x40C3880000000000, // 1e4 + 0x4197D78400000000, // 1e8 + 0x4341C37937E08000, // 1e16 + 0x4693B8B5B5056E17, // 1e32 + 0x4D384F03E93FF9F5, // 1e64 + 0x5A827748F9301D32, // 1e128 + 0x75154FDD7F73BF3C, // 1e256 + }); + return pgm_ptr<T>(reinterpret_cast<const T*>(factors)); + } + + static pgm_ptr<T> negativeBinaryPowersOfTen() { + ARDUINOJSON_DEFINE_PROGMEM_ARRAY( // + uint64_t, factors, + { + 0x3FB999999999999A, // 1e-1 + 0x3F847AE147AE147B, // 1e-2 + 0x3F1A36E2EB1C432D, // 1e-4 + 0x3E45798EE2308C3A, // 1e-8 + 0x3C9CD2B297D889BC, // 1e-16 + 0x3949F623D5A8A733, // 1e-32 + 0x32A50FFD44F4A73D, // 1e-64 + 0x255BBA08CF8C979D, // 1e-128 + 0x0AC8062864AC6F43 // 1e-256 + }); + return pgm_ptr<T>(reinterpret_cast<const T*>(factors)); } static T nan() { - return forge(0x7ff80000, 0x00000000); + return forge(0x7ff8000000000000); } static T inf() { - return forge(0x7ff00000, 0x00000000); + return forge(0x7ff0000000000000); } static T highest() { - return forge(0x7FEFFFFF, 0xFFFFFFFF); + return forge(0x7FEFFFFFFFFFFFFF); } template <typename TOut> // int64_t @@ -122,7 +80,7 @@ struct FloatTraits<T, 8 /*64bits*/> { typename enable_if<is_integral<TOut>::value && is_signed<TOut>::value && sizeof(TOut) == 8, signed>::type* = 0) { - return forge(0x43DFFFFF, 0xFFFFFFFF); // 9.2233720368547748e+18 + return forge(0x43DFFFFFFFFFFFFF); // 9.2233720368547748e+18 } template <typename TOut> // uint64_t @@ -130,18 +88,18 @@ struct FloatTraits<T, 8 /*64bits*/> { typename enable_if<is_integral<TOut>::value && is_unsigned<TOut>::value && sizeof(TOut) == 8, unsigned>::type* = 0) { - return forge(0x43EFFFFF, 0xFFFFFFFF); // 1.8446744073709549568e+19 + return forge(0x43EFFFFFFFFFFFFF); // 1.8446744073709549568e+19 } static T lowest() { - return forge(0xFFEFFFFF, 0xFFFFFFFF); + return forge(0xFFEFFFFFFFFFFFFF); } // constructs a double floating point values from its binary representation // we use this function to workaround platforms with single precision literals // (for example, when -fsingle-precision-constant is passed to GCC) - static T forge(uint32_t msb, uint32_t lsb) { - return alias_cast<T>((uint64_t(msb) << 32) | lsb); + static T forge(uint64_t bits) { + return alias_cast<T>(bits); } }; @@ -155,62 +113,30 @@ struct FloatTraits<T, 4 /*32bits*/> { typedef int8_t exponent_type; static const exponent_type exponent_max = 38; - template <typename TExponent> - static T make_float(T m, TExponent e) { - if (e > 0) { - for (uint8_t index = 0; e != 0; index++) { - if (e & 1) - m *= positiveBinaryPowerOfTen(index); - e >>= 1; - } - } else { - e = -e; - for (uint8_t index = 0; e != 0; index++) { - if (e & 1) - m *= negativeBinaryPowerOfTen(index); - e >>= 1; - } - } - return m; - } - - static T positiveBinaryPowerOfTen(int index) { - ARDUINOJSON_DEFINE_STATIC_ARRAY(uint32_t, factors, - ARDUINOJSON_EXPAND6({ - 0x41200000, // 1e1f - 0x42c80000, // 1e2f - 0x461c4000, // 1e4f - 0x4cbebc20, // 1e8f - 0x5a0e1bca, // 1e16f - 0x749dc5ae // 1e32f - })); - return forge(ARDUINOJSON_READ_STATIC_ARRAY(uint32_t, factors, index)); - } - - static T negativeBinaryPowerOfTen(int index) { - ARDUINOJSON_DEFINE_STATIC_ARRAY(uint32_t, factors, - ARDUINOJSON_EXPAND6({ - 0x3dcccccd, // 1e-1f - 0x3c23d70a, // 1e-2f - 0x38d1b717, // 1e-4f - 0x322bcc77, // 1e-8f - 0x24e69595, // 1e-16f - 0x0a4fb11f // 1e-32f - })); - return forge(ARDUINOJSON_READ_STATIC_ARRAY(uint32_t, factors, index)); - } - - static T negativeBinaryPowerOfTenPlusOne(int index) { - ARDUINOJSON_DEFINE_STATIC_ARRAY(uint32_t, factors, - ARDUINOJSON_EXPAND6({ - 0x3f800000, // 1e0f - 0x3dcccccd, // 1e-1f - 0x3a83126f, // 1e-3f - 0x33d6bf95, // 1e-7f - 0x26901d7d, // 1e-15f - 0x0c01ceb3 // 1e-31f - })); - return forge(ARDUINOJSON_READ_STATIC_ARRAY(uint32_t, factors, index)); + static pgm_ptr<T> positiveBinaryPowersOfTen() { + ARDUINOJSON_DEFINE_PROGMEM_ARRAY(uint32_t, factors, + { + 0x41200000, // 1e1f + 0x42c80000, // 1e2f + 0x461c4000, // 1e4f + 0x4cbebc20, // 1e8f + 0x5a0e1bca, // 1e16f + 0x749dc5ae // 1e32f + }); + return pgm_ptr<T>(reinterpret_cast<const T*>(factors)); + } + + static pgm_ptr<T> negativeBinaryPowersOfTen() { + ARDUINOJSON_DEFINE_PROGMEM_ARRAY(uint32_t, factors, + { + 0x3dcccccd, // 1e-1f + 0x3c23d70a, // 1e-2f + 0x38d1b717, // 1e-4f + 0x322bcc77, // 1e-8f + 0x24e69595, // 1e-16f + 0x0a4fb11f // 1e-32f + }); + return pgm_ptr<T>(reinterpret_cast<const T*>(factors)); } static T forge(uint32_t bits) { @@ -265,4 +191,22 @@ struct FloatTraits<T, 4 /*32bits*/> { return forge(0xFf7fffff); } }; -} // namespace ARDUINOJSON_NAMESPACE + +template <typename TFloat, typename TExponent> +inline TFloat make_float(TFloat m, TExponent e) { + using traits = FloatTraits<TFloat>; + + auto powersOfTen = e > 0 ? traits::positiveBinaryPowersOfTen() + : traits::negativeBinaryPowersOfTen(); + if (e <= 0) + e = TExponent(-e); + + for (uint8_t index = 0; e != 0; index++) { + if (e & 1) + m *= powersOfTen[index]; + e >>= 1; + } + return m; +} + +ARDUINOJSON_END_PRIVATE_NAMESPACE diff --git a/neosensor/libraries/ArduinoJson/src/ArduinoJson/Numbers/JsonFloat.hpp b/neosensor/libraries/ArduinoJson/src/ArduinoJson/Numbers/JsonFloat.hpp index a88439fe73303329ef2e329cca01fed83864e517..a1259d07a47aa125d3b0e2836c9bc869c3ddf819 100644 --- a/neosensor/libraries/ArduinoJson/src/ArduinoJson/Numbers/JsonFloat.hpp +++ b/neosensor/libraries/ArduinoJson/src/ArduinoJson/Numbers/JsonFloat.hpp @@ -1,5 +1,5 @@ // ArduinoJson - https://arduinojson.org -// Copyright © 2014-2022, Benoit BLANCHON +// Copyright © 2014-2023, Benoit BLANCHON // MIT License #pragma once @@ -7,11 +7,12 @@ #include <ArduinoJson/Configuration.hpp> #include <ArduinoJson/Namespace.hpp> -namespace ARDUINOJSON_NAMESPACE { +ARDUINOJSON_BEGIN_PUBLIC_NAMESPACE #if ARDUINOJSON_USE_DOUBLE typedef double JsonFloat; #else typedef float JsonFloat; #endif -} // namespace ARDUINOJSON_NAMESPACE + +ARDUINOJSON_END_PUBLIC_NAMESPACE diff --git a/neosensor/libraries/ArduinoJson/src/ArduinoJson/Numbers/JsonInteger.hpp b/neosensor/libraries/ArduinoJson/src/ArduinoJson/Numbers/JsonInteger.hpp index ccf852bd9a6ae2152449d1e1751924fa660b5850..9100565367bbae03256b5832f57e71242d04331d 100644 --- a/neosensor/libraries/ArduinoJson/src/ArduinoJson/Numbers/JsonInteger.hpp +++ b/neosensor/libraries/ArduinoJson/src/ArduinoJson/Numbers/JsonInteger.hpp @@ -1,5 +1,5 @@ // ArduinoJson - https://arduinojson.org -// Copyright © 2014-2022, Benoit BLANCHON +// Copyright © 2014-2023, Benoit BLANCHON // MIT License #pragma once @@ -9,7 +9,7 @@ #include <stdint.h> // int64_t -namespace ARDUINOJSON_NAMESPACE { +ARDUINOJSON_BEGIN_PUBLIC_NAMESPACE #if ARDUINOJSON_USE_LONG_LONG typedef int64_t JsonInteger; @@ -19,14 +19,10 @@ typedef long JsonInteger; typedef unsigned long JsonUInt; #endif -} // namespace ARDUINOJSON_NAMESPACE +ARDUINOJSON_END_PUBLIC_NAMESPACE -#if ARDUINOJSON_HAS_LONG_LONG && !ARDUINOJSON_USE_LONG_LONG -# define ARDUINOJSON_ASSERT_INTEGER_TYPE_IS_SUPPORTED(T) \ - static_assert(sizeof(T) <= sizeof(ARDUINOJSON_NAMESPACE::JsonInteger), \ - "To use 64-bit integers with ArduinoJson, you must set " \ - "ARDUINOJSON_USE_LONG_LONG to 1. See " \ - "https://arduinojson.org/v6/api/config/use_long_long/"); -#else -# define ARDUINOJSON_ASSERT_INTEGER_TYPE_IS_SUPPORTED(T) -#endif +#define ARDUINOJSON_ASSERT_INTEGER_TYPE_IS_SUPPORTED(T) \ + static_assert(sizeof(T) <= sizeof(ArduinoJson::JsonInteger), \ + "To use 64-bit integers with ArduinoJson, you must set " \ + "ARDUINOJSON_USE_LONG_LONG to 1. See " \ + "https://arduinojson.org/v6/api/config/use_long_long/"); diff --git a/neosensor/libraries/ArduinoJson/src/ArduinoJson/Numbers/arithmeticCompare.hpp b/neosensor/libraries/ArduinoJson/src/ArduinoJson/Numbers/arithmeticCompare.hpp index 515bc4e62a9153a8a8cb5bf94ea4b002ccec1ab2..e706fd94d64397d0094635113abc6fe5e19dcd0c 100644 --- a/neosensor/libraries/ArduinoJson/src/ArduinoJson/Numbers/arithmeticCompare.hpp +++ b/neosensor/libraries/ArduinoJson/src/ArduinoJson/Numbers/arithmeticCompare.hpp @@ -1,5 +1,5 @@ // ArduinoJson - https://arduinojson.org -// Copyright © 2014-2022, Benoit BLANCHON +// Copyright © 2014-2023, Benoit BLANCHON // MIT License #pragma once @@ -7,7 +7,7 @@ #include <ArduinoJson/Numbers/JsonInteger.hpp> #include <ArduinoJson/Polyfills/type_traits.hpp> -namespace ARDUINOJSON_NAMESPACE { +ARDUINOJSON_BEGIN_PRIVATE_NAMESPACE enum CompareResult { COMPARE_RESULT_DIFFER = 0, @@ -33,10 +33,7 @@ template <typename T1, typename T2> CompareResult arithmeticCompare( const T1& lhs, const T2& rhs, typename enable_if<is_integral<T1>::value && is_integral<T2>::value && - sizeof(T1) < sizeof(T2), - int // Using int instead of void to avoid C2572 on - // Visual Studio 2012, 2013, and 2015 - >::type* = 0) { + sizeof(T1) < sizeof(T2)>::type* = 0) { return arithmeticCompare<T2>(static_cast<T2>(lhs), rhs); } @@ -120,4 +117,4 @@ CompareResult arithmeticCompareNegateRight( return arithmeticCompare(static_cast<T1>(rhs), -lhs); } -} // namespace ARDUINOJSON_NAMESPACE +ARDUINOJSON_END_PRIVATE_NAMESPACE diff --git a/neosensor/libraries/ArduinoJson/src/ArduinoJson/Numbers/convertNumber.hpp b/neosensor/libraries/ArduinoJson/src/ArduinoJson/Numbers/convertNumber.hpp index 9a78bdd574af0f8360d5c423468eaff365b0b1e6..4fbf8655da5f69b0a39c214f51812e149ae6db8d 100644 --- a/neosensor/libraries/ArduinoJson/src/ArduinoJson/Numbers/convertNumber.hpp +++ b/neosensor/libraries/ArduinoJson/src/ArduinoJson/Numbers/convertNumber.hpp @@ -1,5 +1,5 @@ // ArduinoJson - https://arduinojson.org -// Copyright © 2014-2022, Benoit BLANCHON +// Copyright © 2014-2023, Benoit BLANCHON // MIT License #pragma once @@ -8,9 +8,7 @@ # pragma clang diagnostic push # pragma clang diagnostic ignored "-Wconversion" #elif defined(__GNUC__) -# if __GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6) -# pragma GCC diagnostic push -# endif +# pragma GCC diagnostic push # pragma GCC diagnostic ignored "-Wconversion" #endif @@ -19,7 +17,7 @@ #include <ArduinoJson/Polyfills/limits.hpp> #include <ArduinoJson/Polyfills/type_traits.hpp> -namespace ARDUINOJSON_NAMESPACE { +ARDUINOJSON_BEGIN_PRIVATE_NAMESPACE // uint32 -> int32 // uint64 -> int32 @@ -128,12 +126,10 @@ template <typename TOut, typename TIn> TOut convertNumber(TIn value) { return canConvertNumber<TOut>(value) ? TOut(value) : 0; } -} // namespace ARDUINOJSON_NAMESPACE +ARDUINOJSON_END_PRIVATE_NAMESPACE #if defined(__clang__) # pragma clang diagnostic pop #elif defined(__GNUC__) -# if __GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6) -# pragma GCC diagnostic pop -# endif +# pragma GCC diagnostic pop #endif diff --git a/neosensor/libraries/ArduinoJson/src/ArduinoJson/Numbers/parseNumber.hpp b/neosensor/libraries/ArduinoJson/src/ArduinoJson/Numbers/parseNumber.hpp index 05fca73341cc3596e58df8a2cc940361be640cfe..4cec1a69e4c4a49ba0d46e3f207317d348566607 100644 --- a/neosensor/libraries/ArduinoJson/src/ArduinoJson/Numbers/parseNumber.hpp +++ b/neosensor/libraries/ArduinoJson/src/ArduinoJson/Numbers/parseNumber.hpp @@ -1,5 +1,5 @@ // ArduinoJson - https://arduinojson.org -// Copyright © 2014-2022, Benoit BLANCHON +// Copyright © 2014-2023, Benoit BLANCHON // MIT License #pragma once @@ -13,7 +13,7 @@ #include <ArduinoJson/Variant/Converter.hpp> #include <ArduinoJson/Variant/VariantData.hpp> -namespace ARDUINOJSON_NAMESPACE { +ARDUINOJSON_BEGIN_PRIVATE_NAMESPACE template <typename A, typename B> struct choose_largest : conditional<(sizeof(A) > sizeof(B)), A, B> {}; @@ -137,7 +137,7 @@ inline bool parseNumber(const char* s, VariantData& result) { return false; JsonFloat final_result = - traits::make_float(static_cast<JsonFloat>(mantissa), exponent); + make_float(static_cast<JsonFloat>(mantissa), exponent); result.setFloat(is_negative ? -final_result : final_result); return true; @@ -146,8 +146,7 @@ inline bool parseNumber(const char* s, VariantData& result) { template <typename T> inline T parseNumber(const char* s) { VariantData value; - value.init(); // VariantData is a POD, so it has no constructor parseNumber(s, value); return Converter<T>::fromJson(JsonVariantConst(&value)); } -} // namespace ARDUINOJSON_NAMESPACE +ARDUINOJSON_END_PRIVATE_NAMESPACE diff --git a/neosensor/libraries/ArduinoJson/src/ArduinoJson/Object/JsonObject.hpp b/neosensor/libraries/ArduinoJson/src/ArduinoJson/Object/JsonObject.hpp index 0df210d837c0c3a45ed8253fd1c50a3ec9e71829..7cdc1c76eb19028536966fc19c14d86e8ea3c16b 100644 --- a/neosensor/libraries/ArduinoJson/src/ArduinoJson/Object/JsonObject.hpp +++ b/neosensor/libraries/ArduinoJson/src/ArduinoJson/Object/JsonObject.hpp @@ -1,5 +1,5 @@ // ArduinoJson - https://arduinojson.org -// Copyright © 2014-2022, Benoit BLANCHON +// Copyright © 2014-2023, Benoit BLANCHON // MIT License #pragma once @@ -7,74 +7,74 @@ #include <ArduinoJson/Object/JsonObjectConst.hpp> #include <ArduinoJson/Object/MemberProxy.hpp> -namespace ARDUINOJSON_NAMESPACE { +ARDUINOJSON_BEGIN_PUBLIC_NAMESPACE class JsonArray; // A reference to an object in a JsonDocument. // https://arduinojson.org/v6/api/jsonobject/ -class JsonObject : public VariantOperators<JsonObject> { - friend class VariantAttorney; +class JsonObject : public detail::VariantOperators<JsonObject> { + friend class detail::VariantAttorney; public: typedef JsonObjectIterator iterator; // Creates an unbound reference. - FORCE_INLINE JsonObject() : _data(0), _pool(0) {} + FORCE_INLINE JsonObject() : data_(0), pool_(0) {} // INTERNAL USE ONLY - FORCE_INLINE JsonObject(MemoryPool* buf, CollectionData* data) - : _data(data), _pool(buf) {} + FORCE_INLINE JsonObject(detail::MemoryPool* buf, detail::CollectionData* data) + : data_(data), pool_(buf) {} operator JsonVariant() const { - void* data = _data; // prevent warning cast-align - return JsonVariant(_pool, reinterpret_cast<VariantData*>(data)); + void* data = data_; // prevent warning cast-align + return JsonVariant(pool_, reinterpret_cast<detail::VariantData*>(data)); } operator JsonObjectConst() const { - return JsonObjectConst(_data); + return JsonObjectConst(data_); } operator JsonVariantConst() const { - return JsonVariantConst(collectionToVariant(_data)); + return JsonVariantConst(collectionToVariant(data_)); } // Returns true if the reference is unbound. // https://arduinojson.org/v6/api/jsonobject/isnull/ FORCE_INLINE bool isNull() const { - return _data == 0; + return data_ == 0; } // Returns true if the reference is bound. // https://arduinojson.org/v6/api/jsonobject/isnull/ FORCE_INLINE operator bool() const { - return _data != 0; + return data_ != 0; } // Returns the number of bytes occupied by the object. // https://arduinojson.org/v6/api/jsonobject/memoryusage/ FORCE_INLINE size_t memoryUsage() const { - return _data ? _data->memoryUsage() : 0; + return data_ ? data_->memoryUsage() : 0; } // Returns the depth (nesting level) of the object. // https://arduinojson.org/v6/api/jsonobject/nesting/ FORCE_INLINE size_t nesting() const { - return variantNesting(collectionToVariant(_data)); + return variantNesting(collectionToVariant(data_)); } // Returns the number of members in the object. // https://arduinojson.org/v6/api/jsonobject/size/ FORCE_INLINE size_t size() const { - return _data ? _data->size() : 0; + return data_ ? data_->size() : 0; } // Returns an iterator to the first key-value pair of the object. // https://arduinojson.org/v6/api/jsonobject/begin/ FORCE_INLINE iterator begin() const { - if (!_data) + if (!data_) return iterator(); - return iterator(_pool, _data->head()); + return iterator(pool_, data_->head()); } // Returns an iterator following the last key-value pair of the object. @@ -87,49 +87,51 @@ class JsonObject : public VariantOperators<JsonObject> { // ⚠️ Doesn't release the memory associated with the removed members. // https://arduinojson.org/v6/api/jsonobject/clear/ void clear() const { - if (!_data) + if (!data_) return; - _data->clear(); + data_->clear(); } // Copies an object. // https://arduinojson.org/v6/api/jsonobject/set/ FORCE_INLINE bool set(JsonObjectConst src) { - if (!_data || !src._data) + if (!data_ || !src.data_) return false; - return _data->copyFrom(*src._data, _pool); + return data_->copyFrom(*src.data_, pool_); } // Compares the content of two objects. FORCE_INLINE bool operator==(JsonObject rhs) const { - return JsonObjectConst(_data) == JsonObjectConst(rhs._data); + return JsonObjectConst(data_) == JsonObjectConst(rhs.data_); } // Gets or sets the member with specified key. // https://arduinojson.org/v6/api/jsonobject/subscript/ template <typename TString> - FORCE_INLINE typename enable_if<IsString<TString>::value, - MemberProxy<JsonObject, TString> >::type - operator[](const TString& key) const { - return MemberProxy<JsonObject, TString>(*this, key); + FORCE_INLINE + typename detail::enable_if<detail::IsString<TString>::value, + detail::MemberProxy<JsonObject, TString>>::type + operator[](const TString& key) const { + return {*this, key}; } // Gets or sets the member with specified key. // https://arduinojson.org/v6/api/jsonobject/subscript/ template <typename TChar> - FORCE_INLINE typename enable_if<IsString<TChar*>::value, - MemberProxy<JsonObject, TChar*> >::type - operator[](TChar* key) const { - return MemberProxy<JsonObject, TChar*>(*this, key); + FORCE_INLINE + typename detail::enable_if<detail::IsString<TChar*>::value, + detail::MemberProxy<JsonObject, TChar*>>::type + operator[](TChar* key) const { + return {*this, key}; } // Removes the member at the specified iterator. // ⚠️ Doesn't release the memory associated with the removed member. // https://arduinojson.org/v6/api/jsonobject/remove/ FORCE_INLINE void remove(iterator it) const { - if (!_data) + if (!data_) return; - _data->removeSlot(it._slot); + data_->removeSlot(it.slot_); } // Removes the member with the specified key. @@ -137,7 +139,7 @@ class JsonObject : public VariantOperators<JsonObject> { // https://arduinojson.org/v6/api/jsonobject/remove/ template <typename TString> FORCE_INLINE void remove(const TString& key) const { - removeMember(adaptString(key)); + removeMember(detail::adaptString(key)); } // Removes the member with the specified key. @@ -145,23 +147,25 @@ class JsonObject : public VariantOperators<JsonObject> { // https://arduinojson.org/v6/api/jsonobject/remove/ template <typename TChar> FORCE_INLINE void remove(TChar* key) const { - removeMember(adaptString(key)); + removeMember(detail::adaptString(key)); } // Returns true if the object contains the specified key. // https://arduinojson.org/v6/api/jsonobject/containskey/ template <typename TString> - FORCE_INLINE typename enable_if<IsString<TString>::value, bool>::type - containsKey(const TString& key) const { - return getMember(adaptString(key)) != 0; + FORCE_INLINE + typename detail::enable_if<detail::IsString<TString>::value, bool>::type + containsKey(const TString& key) const { + return getMember(detail::adaptString(key)) != 0; } // Returns true if the object contains the specified key. // https://arduinojson.org/v6/api/jsonobject/containskey/ template <typename TChar> - FORCE_INLINE typename enable_if<IsString<TChar*>::value, bool>::type - containsKey(TChar* key) const { - return getMember(adaptString(key)) != 0; + FORCE_INLINE + typename detail::enable_if<detail::IsString<TChar*>::value, bool>::type + containsKey(TChar* key) const { + return getMember(detail::adaptString(key)) != 0; } // Creates an array and adds it to the object. @@ -189,49 +193,49 @@ class JsonObject : public VariantOperators<JsonObject> { } private: - MemoryPool* getPool() const { - return _pool; + detail::MemoryPool* getPool() const { + return pool_; } - VariantData* getData() const { - return collectionToVariant(_data); + detail::VariantData* getData() const { + return detail::collectionToVariant(data_); } - VariantData* getOrCreateData() const { - return collectionToVariant(_data); + detail::VariantData* getOrCreateData() const { + return detail::collectionToVariant(data_); } template <typename TAdaptedString> - inline VariantData* getMember(TAdaptedString key) const { - if (!_data) + inline detail::VariantData* getMember(TAdaptedString key) const { + if (!data_) return 0; - return _data->getMember(key); + return data_->getMember(key); } template <typename TAdaptedString> void removeMember(TAdaptedString key) const { - if (!_data) + if (!data_) return; - _data->removeMember(key); + data_->removeMember(key); } - CollectionData* _data; - MemoryPool* _pool; + detail::CollectionData* data_; + detail::MemoryPool* pool_; }; template <> -struct Converter<JsonObject> : private VariantAttorney { +struct Converter<JsonObject> : private detail::VariantAttorney { static void toJson(JsonVariantConst src, JsonVariant dst) { variantCopyFrom(getData(dst), getData(src), getPool(dst)); } static JsonObject fromJson(JsonVariant src) { - VariantData* data = getData(src); - MemoryPool* pool = getPool(src); + auto data = getData(src); + auto pool = getPool(src); return JsonObject(pool, data != 0 ? data->asObject() : 0); } - static InvalidConversion<JsonVariantConst, JsonObject> fromJson( + static detail::InvalidConversion<JsonVariantConst, JsonObject> fromJson( JsonVariantConst); static bool checkJson(JsonVariantConst) { @@ -239,8 +243,9 @@ struct Converter<JsonObject> : private VariantAttorney { } static bool checkJson(JsonVariant src) { - VariantData* data = getData(src); + auto data = getData(src); return data && data->isObject(); } }; -} // namespace ARDUINOJSON_NAMESPACE + +ARDUINOJSON_END_PUBLIC_NAMESPACE diff --git a/neosensor/libraries/ArduinoJson/src/ArduinoJson/Object/JsonObjectConst.hpp b/neosensor/libraries/ArduinoJson/src/ArduinoJson/Object/JsonObjectConst.hpp index 93ad9d8604207488f4edcf72d386654bcb5e6121..e9b5e48355d794eb21542d229aa7f3affe5eb11c 100644 --- a/neosensor/libraries/ArduinoJson/src/ArduinoJson/Object/JsonObjectConst.hpp +++ b/neosensor/libraries/ArduinoJson/src/ArduinoJson/Object/JsonObjectConst.hpp @@ -1,5 +1,5 @@ // ArduinoJson - https://arduinojson.org -// Copyright © 2014-2022, Benoit BLANCHON +// Copyright © 2014-2023, Benoit BLANCHON // MIT License #pragma once @@ -7,63 +7,63 @@ #include <ArduinoJson/Object/JsonObjectIterator.hpp> #include <ArduinoJson/Variant/VariantOperators.hpp> -namespace ARDUINOJSON_NAMESPACE { +ARDUINOJSON_BEGIN_PUBLIC_NAMESPACE // A read-only reference to an object in a JsonDocument. // https://arduinojson.org/v6/api/jsonobjectconst/ -class JsonObjectConst : public VariantOperators<JsonObjectConst> { +class JsonObjectConst : public detail::VariantOperators<JsonObjectConst> { friend class JsonObject; - friend class VariantAttorney; + friend class detail::VariantAttorney; public: typedef JsonObjectConstIterator iterator; // Creates an unbound reference. - JsonObjectConst() : _data(0) {} + JsonObjectConst() : data_(0) {} // INTERNAL USE ONLY - JsonObjectConst(const CollectionData* data) : _data(data) {} + JsonObjectConst(const detail::CollectionData* data) : data_(data) {} operator JsonVariantConst() const { - return JsonVariantConst(collectionToVariant(_data)); + return JsonVariantConst(collectionToVariant(data_)); } // Returns true if the reference is unbound. // https://arduinojson.org/v6/api/jsonobjectconst/isnull/ FORCE_INLINE bool isNull() const { - return _data == 0; + return data_ == 0; } // Returns true if the reference is bound. // https://arduinojson.org/v6/api/jsonobjectconst/isnull/ FORCE_INLINE operator bool() const { - return _data != 0; + return data_ != 0; } // Returns the number of bytes occupied by the object. // https://arduinojson.org/v6/api/jsonobjectconst/memoryusage/ FORCE_INLINE size_t memoryUsage() const { - return _data ? _data->memoryUsage() : 0; + return data_ ? data_->memoryUsage() : 0; } // Returns the depth (nesting level) of the object. // https://arduinojson.org/v6/api/jsonobjectconst/nesting/ FORCE_INLINE size_t nesting() const { - return variantNesting(collectionToVariant(_data)); + return variantNesting(collectionToVariant(data_)); } // Returns the number of members in the object. // https://arduinojson.org/v6/api/jsonobjectconst/size/ FORCE_INLINE size_t size() const { - return _data ? _data->size() : 0; + return data_ ? data_->size() : 0; } // Returns an iterator to the first key-value pair of the object. // https://arduinojson.org/v6/api/jsonobjectconst/begin/ FORCE_INLINE iterator begin() const { - if (!_data) + if (!data_) return iterator(); - return iterator(_data->head()); + return iterator(data_->head()); } // Returns an iterator following the last key-value pair of the object. @@ -76,40 +76,40 @@ class JsonObjectConst : public VariantOperators<JsonObjectConst> { // https://arduinojson.org/v6/api/jsonobjectconst/containskey/ template <typename TString> FORCE_INLINE bool containsKey(const TString& key) const { - return getMember(adaptString(key)) != 0; + return getMember(detail::adaptString(key)) != 0; } // Returns true if the object contains the specified key. // https://arduinojson.org/v6/api/jsonobjectconst/containskey/ template <typename TChar> FORCE_INLINE bool containsKey(TChar* key) const { - return getMember(adaptString(key)) != 0; + return getMember(detail::adaptString(key)) != 0; } // Gets the member with specified key. // https://arduinojson.org/v6/api/jsonobjectconst/subscript/ template <typename TString> - FORCE_INLINE - typename enable_if<IsString<TString>::value, JsonVariantConst>::type - operator[](const TString& key) const { - return JsonVariantConst(getMember(adaptString(key))); + FORCE_INLINE typename detail::enable_if<detail::IsString<TString>::value, + JsonVariantConst>::type + operator[](const TString& key) const { + return JsonVariantConst(getMember(detail::adaptString(key))); } // Gets the member with specified key. // https://arduinojson.org/v6/api/jsonobjectconst/subscript/ template <typename TChar> - FORCE_INLINE - typename enable_if<IsString<TChar*>::value, JsonVariantConst>::type - operator[](TChar* key) const { - return JsonVariantConst(getMember(adaptString(key))); + FORCE_INLINE typename detail::enable_if<detail::IsString<TChar*>::value, + JsonVariantConst>::type + operator[](TChar* key) const { + return JsonVariantConst(getMember(detail::adaptString(key))); } // Compares objects. FORCE_INLINE bool operator==(JsonObjectConst rhs) const { - if (_data == rhs._data) + if (data_ == rhs.data_) return true; - if (!_data || !rhs._data) + if (!data_ || !rhs.data_) return false; size_t count = 0; @@ -122,35 +122,35 @@ class JsonObjectConst : public VariantOperators<JsonObjectConst> { } private: - const VariantData* getData() const { - return collectionToVariant(_data); + const detail::VariantData* getData() const { + return collectionToVariant(data_); } template <typename TAdaptedString> - const VariantData* getMember(TAdaptedString key) const { - if (!_data) + const detail::VariantData* getMember(TAdaptedString key) const { + if (!data_) return 0; - return _data->getMember(key); + return data_->getMember(key); } - const CollectionData* _data; + const detail::CollectionData* data_; }; template <> -struct Converter<JsonObjectConst> : private VariantAttorney { +struct Converter<JsonObjectConst> : private detail::VariantAttorney { static void toJson(JsonVariantConst src, JsonVariant dst) { variantCopyFrom(getData(dst), getData(src), getPool(dst)); } static JsonObjectConst fromJson(JsonVariantConst src) { - const VariantData* data = getData(src); + auto data = getData(src); return data != 0 ? data->asObject() : 0; } static bool checkJson(JsonVariantConst src) { - const VariantData* data = getData(src); + auto data = getData(src); return data && data->isObject(); } }; -} // namespace ARDUINOJSON_NAMESPACE +ARDUINOJSON_END_PUBLIC_NAMESPACE diff --git a/neosensor/libraries/ArduinoJson/src/ArduinoJson/Object/JsonObjectImpl.hpp b/neosensor/libraries/ArduinoJson/src/ArduinoJson/Object/JsonObjectImpl.hpp index fc6c96e2ab83ccb648fdf7a97c4943645f180f4f..3b24081a285d5d202eb6314bbdaf3111b3276f80 100644 --- a/neosensor/libraries/ArduinoJson/src/ArduinoJson/Object/JsonObjectImpl.hpp +++ b/neosensor/libraries/ArduinoJson/src/ArduinoJson/Object/JsonObjectImpl.hpp @@ -1,5 +1,5 @@ // ArduinoJson - https://arduinojson.org -// Copyright © 2014-2022, Benoit BLANCHON +// Copyright © 2014-2023, Benoit BLANCHON // MIT License #pragma once @@ -7,7 +7,7 @@ #include <ArduinoJson/Array/JsonArray.hpp> #include <ArduinoJson/Object/JsonObject.hpp> -namespace ARDUINOJSON_NAMESPACE { +ARDUINOJSON_BEGIN_PUBLIC_NAMESPACE template <typename TString> inline JsonArray JsonObject::createNestedArray(const TString& key) const { @@ -19,6 +19,10 @@ inline JsonArray JsonObject::createNestedArray(TChar* key) const { return operator[](key).template to<JsonArray>(); } +ARDUINOJSON_END_PUBLIC_NAMESPACE + +ARDUINOJSON_BEGIN_PRIVATE_NAMESPACE + template <typename TDerived> template <typename TString> inline JsonArray VariantRefBase<TDerived>::createNestedArray( @@ -65,7 +69,7 @@ VariantRefBase<TDerived>::containsKey(TChar* key) const { template <typename TDerived> template <typename TString> inline typename enable_if<IsString<TString*>::value, - MemberProxy<TDerived, TString*> >::type + MemberProxy<TDerived, TString*>>::type VariantRefBase<TDerived>::operator[](TString* key) const { return MemberProxy<TDerived, TString*>(derived(), key); } @@ -73,9 +77,9 @@ VariantRefBase<TDerived>::operator[](TString* key) const { template <typename TDerived> template <typename TString> inline typename enable_if<IsString<TString>::value, - MemberProxy<TDerived, TString> >::type + MemberProxy<TDerived, TString>>::type VariantRefBase<TDerived>::operator[](const TString& key) const { return MemberProxy<TDerived, TString>(derived(), key); } -} // namespace ARDUINOJSON_NAMESPACE +ARDUINOJSON_END_PRIVATE_NAMESPACE diff --git a/neosensor/libraries/ArduinoJson/src/ArduinoJson/Object/JsonObjectIterator.hpp b/neosensor/libraries/ArduinoJson/src/ArduinoJson/Object/JsonObjectIterator.hpp index b01babb07ecd4383dee9132814f5a64cd59b4fba..55c09ed78a1334498da77ed43ee5a3c8c992b9ef 100644 --- a/neosensor/libraries/ArduinoJson/src/ArduinoJson/Object/JsonObjectIterator.hpp +++ b/neosensor/libraries/ArduinoJson/src/ArduinoJson/Object/JsonObjectIterator.hpp @@ -1,5 +1,5 @@ // ArduinoJson - https://arduinojson.org -// Copyright © 2014-2022, Benoit BLANCHON +// Copyright © 2014-2023, Benoit BLANCHON // MIT License #pragma once @@ -7,113 +7,117 @@ #include <ArduinoJson/Object/JsonPair.hpp> #include <ArduinoJson/Variant/SlotFunctions.hpp> -namespace ARDUINOJSON_NAMESPACE { +ARDUINOJSON_BEGIN_PUBLIC_NAMESPACE class JsonPairPtr { public: - JsonPairPtr(MemoryPool* pool, VariantSlot* slot) : _pair(pool, slot) {} + JsonPairPtr(detail::MemoryPool* pool, detail::VariantSlot* slot) + : pair_(pool, slot) {} const JsonPair* operator->() const { - return &_pair; + return &pair_; } const JsonPair& operator*() const { - return _pair; + return pair_; } private: - JsonPair _pair; + JsonPair pair_; }; class JsonObjectIterator { friend class JsonObject; public: - JsonObjectIterator() : _slot(0) {} + JsonObjectIterator() : slot_(0) {} - explicit JsonObjectIterator(MemoryPool* pool, VariantSlot* slot) - : _pool(pool), _slot(slot) {} + explicit JsonObjectIterator(detail::MemoryPool* pool, + detail::VariantSlot* slot) + : pool_(pool), slot_(slot) {} JsonPair operator*() const { - return JsonPair(_pool, _slot); + return JsonPair(pool_, slot_); } JsonPairPtr operator->() { - return JsonPairPtr(_pool, _slot); + return JsonPairPtr(pool_, slot_); } bool operator==(const JsonObjectIterator& other) const { - return _slot == other._slot; + return slot_ == other.slot_; } bool operator!=(const JsonObjectIterator& other) const { - return _slot != other._slot; + return slot_ != other.slot_; } JsonObjectIterator& operator++() { - _slot = _slot->next(); + slot_ = slot_->next(); return *this; } JsonObjectIterator& operator+=(size_t distance) { - _slot = _slot->next(distance); + slot_ = slot_->next(distance); return *this; } private: - MemoryPool* _pool; - VariantSlot* _slot; + detail::MemoryPool* pool_; + detail::VariantSlot* slot_; }; class JsonPairConstPtr { public: - JsonPairConstPtr(const VariantSlot* slot) : _pair(slot) {} + JsonPairConstPtr(const detail::VariantSlot* slot) : pair_(slot) {} const JsonPairConst* operator->() const { - return &_pair; + return &pair_; } const JsonPairConst& operator*() const { - return _pair; + return pair_; } private: - JsonPairConst _pair; + JsonPairConst pair_; }; class JsonObjectConstIterator { friend class JsonObject; public: - JsonObjectConstIterator() : _slot(0) {} + JsonObjectConstIterator() : slot_(0) {} - explicit JsonObjectConstIterator(const VariantSlot* slot) : _slot(slot) {} + explicit JsonObjectConstIterator(const detail::VariantSlot* slot) + : slot_(slot) {} JsonPairConst operator*() const { - return JsonPairConst(_slot); + return JsonPairConst(slot_); } JsonPairConstPtr operator->() { - return JsonPairConstPtr(_slot); + return JsonPairConstPtr(slot_); } bool operator==(const JsonObjectConstIterator& other) const { - return _slot == other._slot; + return slot_ == other.slot_; } bool operator!=(const JsonObjectConstIterator& other) const { - return _slot != other._slot; + return slot_ != other.slot_; } JsonObjectConstIterator& operator++() { - _slot = _slot->next(); + slot_ = slot_->next(); return *this; } JsonObjectConstIterator& operator+=(size_t distance) { - _slot = _slot->next(distance); + slot_ = slot_->next(distance); return *this; } private: - const VariantSlot* _slot; + const detail::VariantSlot* slot_; }; -} // namespace ARDUINOJSON_NAMESPACE + +ARDUINOJSON_END_PUBLIC_NAMESPACE diff --git a/neosensor/libraries/ArduinoJson/src/ArduinoJson/Object/JsonPair.hpp b/neosensor/libraries/ArduinoJson/src/ArduinoJson/Object/JsonPair.hpp index fa86a7c6999cdc790e74bce73799be9d7be2fbb8..862a6579347067b63bbd1746d1e18a5962b49abd 100644 --- a/neosensor/libraries/ArduinoJson/src/ArduinoJson/Object/JsonPair.hpp +++ b/neosensor/libraries/ArduinoJson/src/ArduinoJson/Object/JsonPair.hpp @@ -1,5 +1,5 @@ // ArduinoJson - https://arduinojson.org -// Copyright © 2014-2022, Benoit BLANCHON +// Copyright © 2014-2023, Benoit BLANCHON // MIT License #pragma once @@ -8,60 +8,61 @@ #include <ArduinoJson/Variant/JsonVariant.hpp> #include <ArduinoJson/Variant/JsonVariantConst.hpp> -namespace ARDUINOJSON_NAMESPACE { +ARDUINOJSON_BEGIN_PUBLIC_NAMESPACE // A key-value pair. // https://arduinojson.org/v6/api/jsonobject/begin_end/ class JsonPair { public: // INTERNAL USE ONLY - JsonPair(MemoryPool* pool, VariantSlot* slot) { + JsonPair(detail::MemoryPool* pool, detail::VariantSlot* slot) { if (slot) { - _key = JsonString(slot->key(), slot->ownsKey() ? JsonString::Copied + key_ = JsonString(slot->key(), slot->ownsKey() ? JsonString::Copied : JsonString::Linked); - _value = JsonVariant(pool, slot->data()); + value_ = JsonVariant(pool, slot->data()); } } // Returns the key. JsonString key() const { - return _key; + return key_; } // Returns the value. JsonVariant value() const { - return _value; + return value_; } private: - JsonString _key; - JsonVariant _value; + JsonString key_; + JsonVariant value_; }; // A read-only key-value pair. // https://arduinojson.org/v6/api/jsonobjectconst/begin_end/ class JsonPairConst { public: - JsonPairConst(const VariantSlot* slot) { + JsonPairConst(const detail::VariantSlot* slot) { if (slot) { - _key = JsonString(slot->key(), slot->ownsKey() ? JsonString::Copied + key_ = JsonString(slot->key(), slot->ownsKey() ? JsonString::Copied : JsonString::Linked); - _value = JsonVariantConst(slot->data()); + value_ = JsonVariantConst(slot->data()); } } // Returns the key. JsonString key() const { - return _key; + return key_; } // Returns the value. JsonVariantConst value() const { - return _value; + return value_; } private: - JsonString _key; - JsonVariantConst _value; + JsonString key_; + JsonVariantConst value_; }; -} // namespace ARDUINOJSON_NAMESPACE + +ARDUINOJSON_END_PUBLIC_NAMESPACE diff --git a/neosensor/libraries/ArduinoJson/src/ArduinoJson/Object/MemberProxy.hpp b/neosensor/libraries/ArduinoJson/src/ArduinoJson/Object/MemberProxy.hpp index 4720600ecff0649f7af1b8647e4c0efa7fc9cd5f..78e5a5211ea87a189943ef66d660338eedb6549a 100644 --- a/neosensor/libraries/ArduinoJson/src/ArduinoJson/Object/MemberProxy.hpp +++ b/neosensor/libraries/ArduinoJson/src/ArduinoJson/Object/MemberProxy.hpp @@ -1,27 +1,27 @@ // ArduinoJson - https://arduinojson.org -// Copyright © 2014-2022, Benoit BLANCHON +// Copyright © 2014-2023, Benoit BLANCHON // MIT License #pragma once #include <ArduinoJson/Variant/VariantRefBase.hpp> -namespace ARDUINOJSON_NAMESPACE { +ARDUINOJSON_BEGIN_PRIVATE_NAMESPACE // A proxy class to get or set a member of an object. // https://arduinojson.org/v6/api/jsonobject/subscript/ template <typename TUpstream, typename TStringRef> class MemberProxy - : public VariantRefBase<MemberProxy<TUpstream, TStringRef> >, - public VariantOperators<MemberProxy<TUpstream, TStringRef> > { + : public VariantRefBase<MemberProxy<TUpstream, TStringRef>>, + public VariantOperators<MemberProxy<TUpstream, TStringRef>> { friend class VariantAttorney; public: FORCE_INLINE MemberProxy(TUpstream upstream, TStringRef key) - : _upstream(upstream), _key(key) {} + : upstream_(upstream), key_(key) {} MemberProxy(const MemberProxy& src) - : _upstream(src._upstream), _key(src._key) {} + : upstream_(src.upstream_), key_(src.key_) {} FORCE_INLINE MemberProxy& operator=(const MemberProxy& src) { this->set(src); @@ -42,23 +42,23 @@ class MemberProxy private: FORCE_INLINE MemoryPool* getPool() const { - return VariantAttorney::getPool(_upstream); + return VariantAttorney::getPool(upstream_); } FORCE_INLINE VariantData* getData() const { - return variantGetMember(VariantAttorney::getData(_upstream), - adaptString(_key)); + return variantGetMember(VariantAttorney::getData(upstream_), + adaptString(key_)); } FORCE_INLINE VariantData* getOrCreateData() const { - return variantGetOrAddMember(VariantAttorney::getOrCreateData(_upstream), - adaptString(_key), - VariantAttorney::getPool(_upstream)); + return variantGetOrAddMember(VariantAttorney::getOrCreateData(upstream_), + adaptString(key_), + VariantAttorney::getPool(upstream_)); } private: - TUpstream _upstream; - TStringRef _key; + TUpstream upstream_; + TStringRef key_; }; -} // namespace ARDUINOJSON_NAMESPACE +ARDUINOJSON_END_PRIVATE_NAMESPACE diff --git a/neosensor/libraries/ArduinoJson/src/ArduinoJson/Polyfills/alias_cast.hpp b/neosensor/libraries/ArduinoJson/src/ArduinoJson/Polyfills/alias_cast.hpp index 7030b7d9028c2c34033069d8967332c0f40a3177..4dac6c4676a1af0d84f07ec40ce95e2e71ee971a 100644 --- a/neosensor/libraries/ArduinoJson/src/ArduinoJson/Polyfills/alias_cast.hpp +++ b/neosensor/libraries/ArduinoJson/src/ArduinoJson/Polyfills/alias_cast.hpp @@ -1,5 +1,5 @@ // ArduinoJson - https://arduinojson.org -// Copyright © 2014-2022, Benoit BLANCHON +// Copyright © 2014-2023, Benoit BLANCHON // MIT License #pragma once @@ -10,7 +10,7 @@ #include <ArduinoJson/Configuration.hpp> #include "math.hpp" -namespace ARDUINOJSON_NAMESPACE { +ARDUINOJSON_BEGIN_PRIVATE_NAMESPACE template <typename T, typename F> struct alias_cast_t { @@ -26,4 +26,5 @@ T alias_cast(F raw_data) { ac.raw = raw_data; return ac.data; } -} // namespace ARDUINOJSON_NAMESPACE + +ARDUINOJSON_END_PRIVATE_NAMESPACE diff --git a/neosensor/libraries/ArduinoJson/src/ArduinoJson/Polyfills/assert.hpp b/neosensor/libraries/ArduinoJson/src/ArduinoJson/Polyfills/assert.hpp index 9b17ab455a3828bd5d297c94dc8bdb8455ea9045..819bcf5056edf3190160d0beb426c2280739197f 100644 --- a/neosensor/libraries/ArduinoJson/src/ArduinoJson/Polyfills/assert.hpp +++ b/neosensor/libraries/ArduinoJson/src/ArduinoJson/Polyfills/assert.hpp @@ -1,5 +1,5 @@ // ArduinoJson - https://arduinojson.org -// Copyright © 2014-2022, Benoit BLANCHON +// Copyright © 2014-2023, Benoit BLANCHON // MIT License #pragma once diff --git a/neosensor/libraries/ArduinoJson/src/ArduinoJson/Polyfills/attributes.hpp b/neosensor/libraries/ArduinoJson/src/ArduinoJson/Polyfills/attributes.hpp index 9e37c82aef7bd870eac4b800ce608ccb3adf52c0..c4196fbb044488aa45a7e641244068654b51644f 100644 --- a/neosensor/libraries/ArduinoJson/src/ArduinoJson/Polyfills/attributes.hpp +++ b/neosensor/libraries/ArduinoJson/src/ArduinoJson/Polyfills/attributes.hpp @@ -1,5 +1,5 @@ // ArduinoJson - https://arduinojson.org -// Copyright © 2014-2022, Benoit BLANCHON +// Copyright © 2014-2023, Benoit BLANCHON // MIT License #pragma once @@ -21,12 +21,6 @@ #endif -#if __cplusplus >= 201103L -# define NOEXCEPT noexcept -#else -# define NOEXCEPT throw() -#endif - #if defined(__has_attribute) # if __has_attribute(no_sanitize) # define ARDUINOJSON_NO_SANITIZE(check) __attribute__((no_sanitize(check))) diff --git a/neosensor/libraries/ArduinoJson/src/ArduinoJson/Polyfills/ctype.hpp b/neosensor/libraries/ArduinoJson/src/ArduinoJson/Polyfills/ctype.hpp index 7a957b95fdbe34d4036dfec82d50b0115f8f59ef..b3a6231ccd94a693a3b32a48681d2866c8be126c 100644 --- a/neosensor/libraries/ArduinoJson/src/ArduinoJson/Polyfills/ctype.hpp +++ b/neosensor/libraries/ArduinoJson/src/ArduinoJson/Polyfills/ctype.hpp @@ -1,12 +1,12 @@ // ArduinoJson - https://arduinojson.org -// Copyright © 2014-2022, Benoit BLANCHON +// Copyright © 2014-2023, Benoit BLANCHON // MIT License #pragma once #include <ArduinoJson/Namespace.hpp> -namespace ARDUINOJSON_NAMESPACE { +ARDUINOJSON_BEGIN_PRIVATE_NAMESPACE #ifndef isdigit inline bool isdigit(char c) { @@ -17,4 +17,5 @@ inline bool isdigit(char c) { inline bool issign(char c) { return '-' == c || c == '+'; } -} // namespace ARDUINOJSON_NAMESPACE + +ARDUINOJSON_END_PRIVATE_NAMESPACE diff --git a/neosensor/libraries/ArduinoJson/src/ArduinoJson/Polyfills/integer.hpp b/neosensor/libraries/ArduinoJson/src/ArduinoJson/Polyfills/integer.hpp index 08708d57dea28048b7fb8b64dd1331c359e4d199..2bfce365da27e8276dcf04e0ac3f9d21ef52f272 100644 --- a/neosensor/libraries/ArduinoJson/src/ArduinoJson/Polyfills/integer.hpp +++ b/neosensor/libraries/ArduinoJson/src/ArduinoJson/Polyfills/integer.hpp @@ -1,5 +1,5 @@ // ArduinoJson - https://arduinojson.org -// Copyright © 2014-2022, Benoit BLANCHON +// Copyright © 2014-2023, Benoit BLANCHON // MIT License #pragma once @@ -8,7 +8,7 @@ #include <ArduinoJson/Namespace.hpp> -namespace ARDUINOJSON_NAMESPACE { +ARDUINOJSON_BEGIN_PRIVATE_NAMESPACE template <int Bits> struct int_t; @@ -27,4 +27,5 @@ template <> struct int_t<32> { typedef int32_t type; }; -} // namespace ARDUINOJSON_NAMESPACE + +ARDUINOJSON_END_PRIVATE_NAMESPACE diff --git a/neosensor/libraries/ArduinoJson/src/ArduinoJson/Polyfills/limits.hpp b/neosensor/libraries/ArduinoJson/src/ArduinoJson/Polyfills/limits.hpp index 9c26b67a6c9284fe04219f1b1db18f72d3d9cd5d..cf799da6dc028a7b3e98bf89c012d4c12e06083b 100644 --- a/neosensor/libraries/ArduinoJson/src/ArduinoJson/Polyfills/limits.hpp +++ b/neosensor/libraries/ArduinoJson/src/ArduinoJson/Polyfills/limits.hpp @@ -1,5 +1,5 @@ // ArduinoJson - https://arduinojson.org -// Copyright © 2014-2022, Benoit BLANCHON +// Copyright © 2014-2023, Benoit BLANCHON // MIT License #pragma once @@ -11,7 +11,7 @@ # pragma warning(disable : 4310) #endif -namespace ARDUINOJSON_NAMESPACE { +ARDUINOJSON_BEGIN_PRIVATE_NAMESPACE // Differs from standard because we can't use the symbols "min" and "max" template <typename T, typename Enable = void> @@ -38,7 +38,7 @@ struct numeric_limits< } }; -} // namespace ARDUINOJSON_NAMESPACE +ARDUINOJSON_END_PRIVATE_NAMESPACE #ifdef _MSC_VER # pragma warning(pop) diff --git a/neosensor/libraries/ArduinoJson/src/ArduinoJson/Polyfills/math.hpp b/neosensor/libraries/ArduinoJson/src/ArduinoJson/Polyfills/math.hpp index 2b77c5c5f8aee57383573331a23529a3ce63e034..45fc8d2f0b8a1d1dae7334dbd0ed6485f7477ed7 100644 --- a/neosensor/libraries/ArduinoJson/src/ArduinoJson/Polyfills/math.hpp +++ b/neosensor/libraries/ArduinoJson/src/ArduinoJson/Polyfills/math.hpp @@ -1,12 +1,12 @@ // ArduinoJson - https://arduinojson.org -// Copyright © 2014-2022, Benoit BLANCHON +// Copyright © 2014-2023, Benoit BLANCHON // MIT License #pragma once #include <ArduinoJson/Namespace.hpp> -namespace ARDUINOJSON_NAMESPACE { +ARDUINOJSON_BEGIN_PRIVATE_NAMESPACE // Some libraries #define isnan() and isinf() so we need to check before // using this name @@ -24,4 +24,4 @@ bool isinf(T x) { return x != 0.0 && x * 2 == x; } #endif -} // namespace ARDUINOJSON_NAMESPACE +ARDUINOJSON_END_PRIVATE_NAMESPACE diff --git a/neosensor/libraries/ArduinoJson/src/ArduinoJson/Polyfills/mpl/max.hpp b/neosensor/libraries/ArduinoJson/src/ArduinoJson/Polyfills/mpl/max.hpp index e3b09119ce302e66599d70b63e7f87ab00399c42..3970b83875f8603a100342b16ec05050bc721d46 100644 --- a/neosensor/libraries/ArduinoJson/src/ArduinoJson/Polyfills/mpl/max.hpp +++ b/neosensor/libraries/ArduinoJson/src/ArduinoJson/Polyfills/mpl/max.hpp @@ -1,5 +1,5 @@ // ArduinoJson - https://arduinojson.org -// Copyright © 2014-2022, Benoit BLANCHON +// Copyright © 2014-2023, Benoit BLANCHON // MIT License #pragma once @@ -8,7 +8,7 @@ #include <stddef.h> // for size_t -namespace ARDUINOJSON_NAMESPACE { +ARDUINOJSON_BEGIN_PRIVATE_NAMESPACE // A meta-function that returns the highest value template <size_t X, size_t Y, bool MaxIsX = (X > Y)> @@ -23,4 +23,5 @@ template <size_t X, size_t Y> struct Max<X, Y, false> { static const size_t value = Y; }; -} // namespace ARDUINOJSON_NAMESPACE + +ARDUINOJSON_END_PRIVATE_NAMESPACE diff --git a/neosensor/libraries/ArduinoJson/src/ArduinoJson/Polyfills/pgmspace.hpp b/neosensor/libraries/ArduinoJson/src/ArduinoJson/Polyfills/pgmspace.hpp index 3e39a37e6635d5d90db545ed641259c1e4f90912..9e66f96a1cc6b492b4b1cb2808b5f77bdf486be9 100644 --- a/neosensor/libraries/ArduinoJson/src/ArduinoJson/Polyfills/pgmspace.hpp +++ b/neosensor/libraries/ArduinoJson/src/ArduinoJson/Polyfills/pgmspace.hpp @@ -1,26 +1,33 @@ // ArduinoJson - https://arduinojson.org -// Copyright © 2014-2022, Benoit BLANCHON +// Copyright © 2014-2023, Benoit BLANCHON // MIT License #pragma once -#include <Arduino.h> +#ifdef ARDUINO +# include <Arduino.h> +#else +// Allow using PROGMEM outside of Arduino (issue #1903) +class __FlashStringHelper; +# include <avr/pgmspace.h> +#endif #include <ArduinoJson/Configuration.hpp> #include <ArduinoJson/Namespace.hpp> #include <ArduinoJson/Polyfills/assert.hpp> -namespace ARDUINOJSON_NAMESPACE { +ARDUINOJSON_BEGIN_PRIVATE_NAMESPACE // Wraps a const char* so that the our functions are picked only if the // originals are missing struct pgm_p { pgm_p(const void* p) : address(reinterpret_cast<const char*>(p)) {} const char* address; }; -} // namespace ARDUINOJSON_NAMESPACE + +ARDUINOJSON_END_PRIVATE_NAMESPACE #ifndef strlen_P -inline size_t strlen_P(ARDUINOJSON_NAMESPACE::pgm_p s) { +inline size_t strlen_P(ArduinoJson::detail::pgm_p s) { const char* p = s.address; ARDUINOJSON_ASSERT(p != NULL); while (pgm_read_byte(p)) @@ -30,7 +37,7 @@ inline size_t strlen_P(ARDUINOJSON_NAMESPACE::pgm_p s) { #endif #ifndef strncmp_P -inline int strncmp_P(const char* a, ARDUINOJSON_NAMESPACE::pgm_p b, size_t n) { +inline int strncmp_P(const char* a, ArduinoJson::detail::pgm_p b, size_t n) { const char* s1 = a; const char* s2 = b.address; ARDUINOJSON_ASSERT(s1 != NULL); @@ -50,7 +57,7 @@ inline int strncmp_P(const char* a, ARDUINOJSON_NAMESPACE::pgm_p b, size_t n) { #endif #ifndef strcmp_P -inline int strcmp_P(const char* a, ARDUINOJSON_NAMESPACE::pgm_p b) { +inline int strcmp_P(const char* a, ArduinoJson::detail::pgm_p b) { const char* s1 = a; const char* s2 = b.address; ARDUINOJSON_ASSERT(s1 != NULL); @@ -69,7 +76,7 @@ inline int strcmp_P(const char* a, ARDUINOJSON_NAMESPACE::pgm_p b) { #endif #ifndef memcmp_P -inline int memcmp_P(const void* a, ARDUINOJSON_NAMESPACE::pgm_p b, size_t n) { +inline int memcmp_P(const void* a, ArduinoJson::detail::pgm_p b, size_t n) { const uint8_t* p1 = reinterpret_cast<const uint8_t*>(a); const char* p2 = b.address; ARDUINOJSON_ASSERT(p1 != NULL); @@ -85,7 +92,7 @@ inline int memcmp_P(const void* a, ARDUINOJSON_NAMESPACE::pgm_p b, size_t n) { #endif #ifndef memcpy_P -inline void* memcpy_P(void* dst, ARDUINOJSON_NAMESPACE::pgm_p src, size_t n) { +inline void* memcpy_P(void* dst, ArduinoJson::detail::pgm_p src, size_t n) { uint8_t* d = reinterpret_cast<uint8_t*>(dst); const char* s = src.address; ARDUINOJSON_ASSERT(d != NULL); @@ -98,15 +105,38 @@ inline void* memcpy_P(void* dst, ARDUINOJSON_NAMESPACE::pgm_p src, size_t n) { #endif #ifndef pgm_read_dword -inline uint32_t pgm_read_dword(ARDUINOJSON_NAMESPACE::pgm_p p) { +inline uint32_t pgm_read_dword(ArduinoJson::detail::pgm_p p) { uint32_t result; memcpy_P(&result, p.address, 4); return result; } #endif +#ifndef pgm_read_float +inline float pgm_read_float(ArduinoJson::detail::pgm_p p) { + float result; + memcpy_P(&result, p.address, sizeof(float)); + return result; +} +#endif + +#ifndef pgm_read_double +# if defined(__SIZEOF_DOUBLE__) && defined(__SIZEOF_FLOAT__) && \ + __SIZEOF_DOUBLE__ == __SIZEOF_FLOAT__ +inline double pgm_read_double(ArduinoJson::detail::pgm_p p) { + return pgm_read_float(p.address); +} +# else +inline double pgm_read_double(ArduinoJson::detail::pgm_p p) { + double result; + memcpy_P(&result, p.address, sizeof(double)); + return result; +} +# endif +#endif + #ifndef pgm_read_ptr -inline void* pgm_read_ptr(ARDUINOJSON_NAMESPACE::pgm_p p) { +inline void* pgm_read_ptr(ArduinoJson::detail::pgm_p p) { void* result; memcpy_P(&result, p.address, sizeof(result)); return result; diff --git a/neosensor/libraries/ArduinoJson/src/ArduinoJson/Polyfills/pgmspace_generic.hpp b/neosensor/libraries/ArduinoJson/src/ArduinoJson/Polyfills/pgmspace_generic.hpp index d9e964b85fd8b459cd16ff1ec200e63c6c09699f..dc47581f54f6025332536e3833afe322a743f42b 100644 --- a/neosensor/libraries/ArduinoJson/src/ArduinoJson/Polyfills/pgmspace_generic.hpp +++ b/neosensor/libraries/ArduinoJson/src/ArduinoJson/Polyfills/pgmspace_generic.hpp @@ -1,24 +1,67 @@ // ArduinoJson - https://arduinojson.org -// Copyright © 2014-2022, Benoit BLANCHON +// Copyright © 2014-2023, Benoit BLANCHON // MIT License #pragma once #include <ArduinoJson/Namespace.hpp> -#include <ArduinoJson/Polyfills/pgmspace.hpp> -#include <ArduinoJson/Polyfills/type_traits.hpp> -namespace ARDUINOJSON_NAMESPACE { +#if ARDUINOJSON_ENABLE_PROGMEM +# include <ArduinoJson/Polyfills/pgmspace.hpp> +# include <ArduinoJson/Polyfills/type_traits.hpp> +#endif + +ARDUINOJSON_BEGIN_PRIVATE_NAMESPACE + +#if ARDUINOJSON_ENABLE_PROGMEM + +# ifndef ARDUINOJSON_DEFINE_PROGMEM_ARRAY +# define ARDUINOJSON_DEFINE_PROGMEM_ARRAY(type, name, ...) \ + static type const name[] PROGMEM = __VA_ARGS__; +# endif template <typename T> -typename enable_if<is_pointer<T>::value, T>::type pgm_read(const void* p) { - return reinterpret_cast<T>(pgm_read_ptr(p)); +inline const T* pgm_read(const T* const* p) { + return reinterpret_cast<const T*>(pgm_read_ptr(p)); } -template <typename T> -typename enable_if<is_same<T, uint32_t>::value, T>::type pgm_read( - const void* p) { +inline uint32_t pgm_read(const uint32_t* p) { return pgm_read_dword(p); } -} // namespace ARDUINOJSON_NAMESPACE +inline double pgm_read(const double* p) { + return pgm_read_double(p); +} + +inline float pgm_read(const float* p) { + return pgm_read_float(p); +} + +#else + +# ifndef ARDUINOJSON_DEFINE_PROGMEM_ARRAY +# define ARDUINOJSON_DEFINE_PROGMEM_ARRAY(type, name, ...) \ + static type const name[] = __VA_ARGS__; +# endif + +template <typename T> +inline T pgm_read(const T* p) { + return *p; +} + +#endif + +template <typename T> +class pgm_ptr { + public: + explicit pgm_ptr(const T* ptr) : ptr_(ptr) {} + + T operator[](intptr_t index) const { + return pgm_read(ptr_ + index); + } + + private: + const T* ptr_; +}; + +ARDUINOJSON_END_PRIVATE_NAMESPACE diff --git a/neosensor/libraries/ArduinoJson/src/ArduinoJson/Polyfills/preprocessor.hpp b/neosensor/libraries/ArduinoJson/src/ArduinoJson/Polyfills/preprocessor.hpp index c9b97c94306262f6194535a9048e42cea2b0b9f2..b91baf74ac7d4ba5641b9c6f865ed6872a538893 100644 --- a/neosensor/libraries/ArduinoJson/src/ArduinoJson/Polyfills/preprocessor.hpp +++ b/neosensor/libraries/ArduinoJson/src/ArduinoJson/Polyfills/preprocessor.hpp @@ -1,35 +1,31 @@ // ArduinoJson - https://arduinojson.org -// Copyright © 2014-2022, Benoit BLANCHON +// Copyright © 2014-2023, Benoit BLANCHON // MIT License #pragma once -#define ARDUINOJSON_EXPAND6(a, b, c, d, e, f) a, b, c, d, e, f -#define ARDUINOJSON_EXPAND9(a, b, c, d, e, f, g, h, i) a, b, c, d, e, f, g, h, i -#define ARDUINOJSON_EXPAND18(a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p, \ - q, r) \ - a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p, q, r - #define ARDUINOJSON_CONCAT_(A, B) A##B #define ARDUINOJSON_CONCAT2(A, B) ARDUINOJSON_CONCAT_(A, B) +#define ARDUINOJSON_CONCAT3(A, B, C) \ + ARDUINOJSON_CONCAT2(ARDUINOJSON_CONCAT2(A, B), C) #define ARDUINOJSON_CONCAT4(A, B, C, D) \ ARDUINOJSON_CONCAT2(ARDUINOJSON_CONCAT2(A, B), ARDUINOJSON_CONCAT2(C, D)) -#define ARDUINOJSON_HEX_DIGIT_0000() 0 -#define ARDUINOJSON_HEX_DIGIT_0001() 1 -#define ARDUINOJSON_HEX_DIGIT_0010() 2 -#define ARDUINOJSON_HEX_DIGIT_0011() 3 -#define ARDUINOJSON_HEX_DIGIT_0100() 4 -#define ARDUINOJSON_HEX_DIGIT_0101() 5 -#define ARDUINOJSON_HEX_DIGIT_0110() 6 -#define ARDUINOJSON_HEX_DIGIT_0111() 7 -#define ARDUINOJSON_HEX_DIGIT_1000() 8 -#define ARDUINOJSON_HEX_DIGIT_1001() 9 -#define ARDUINOJSON_HEX_DIGIT_1010() A -#define ARDUINOJSON_HEX_DIGIT_1011() B -#define ARDUINOJSON_HEX_DIGIT_1100() C -#define ARDUINOJSON_HEX_DIGIT_1101() D -#define ARDUINOJSON_HEX_DIGIT_1110() E -#define ARDUINOJSON_HEX_DIGIT_1111() F -#define ARDUINOJSON_HEX_DIGIT_(A, B, C, D) ARDUINOJSON_HEX_DIGIT_##A##B##C##D() -#define ARDUINOJSON_HEX_DIGIT(A, B, C, D) ARDUINOJSON_HEX_DIGIT_(A, B, C, D) +#define ARDUINOJSON_BIN2ALPHA_0000() A +#define ARDUINOJSON_BIN2ALPHA_0001() B +#define ARDUINOJSON_BIN2ALPHA_0010() C +#define ARDUINOJSON_BIN2ALPHA_0011() D +#define ARDUINOJSON_BIN2ALPHA_0100() E +#define ARDUINOJSON_BIN2ALPHA_0101() F +#define ARDUINOJSON_BIN2ALPHA_0110() F +#define ARDUINOJSON_BIN2ALPHA_0111() H +#define ARDUINOJSON_BIN2ALPHA_1000() I +#define ARDUINOJSON_BIN2ALPHA_1001() J +#define ARDUINOJSON_BIN2ALPHA_1010() K +#define ARDUINOJSON_BIN2ALPHA_1011() L +#define ARDUINOJSON_BIN2ALPHA_1100() M +#define ARDUINOJSON_BIN2ALPHA_1101() N +#define ARDUINOJSON_BIN2ALPHA_1110() O +#define ARDUINOJSON_BIN2ALPHA_1111() P +#define ARDUINOJSON_BIN2ALPHA_(A, B, C, D) ARDUINOJSON_BIN2ALPHA_##A##B##C##D() +#define ARDUINOJSON_BIN2ALPHA(A, B, C, D) ARDUINOJSON_BIN2ALPHA_(A, B, C, D) diff --git a/neosensor/libraries/ArduinoJson/src/ArduinoJson/Polyfills/static_array.hpp b/neosensor/libraries/ArduinoJson/src/ArduinoJson/Polyfills/static_array.hpp deleted file mode 100644 index b2ebbf6b2dc0bb9191dee267a6b1abe6a0f0b229..0000000000000000000000000000000000000000 --- a/neosensor/libraries/ArduinoJson/src/ArduinoJson/Polyfills/static_array.hpp +++ /dev/null @@ -1,30 +0,0 @@ -// ArduinoJson - https://arduinojson.org -// Copyright © 2014-2022, Benoit BLANCHON -// MIT License - -#pragma once - -#include <ArduinoJson/Configuration.hpp> - -#if ARDUINOJSON_ENABLE_PROGMEM - -# include <ArduinoJson/Polyfills/pgmspace_generic.hpp> - -# ifndef ARDUINOJSON_DEFINE_PROGMEM_ARRAY -# define ARDUINOJSON_DEFINE_PROGMEM_ARRAY(type, name, value) \ - static type const name[] PROGMEM = value; -# endif - -# define ARDUINOJSON_DEFINE_STATIC_ARRAY ARDUINOJSON_DEFINE_PROGMEM_ARRAY - -# define ARDUINOJSON_READ_STATIC_ARRAY(type, name, index) \ - pgm_read<type>(name + index) - -#else // i.e. ARDUINOJSON_ENABLE_PROGMEM == 0 - -# define ARDUINOJSON_DEFINE_STATIC_ARRAY(type, name, value) \ - static type const name[] = value; - -# define ARDUINOJSON_READ_STATIC_ARRAY(type, name, index) name[index] - -#endif diff --git a/neosensor/libraries/ArduinoJson/src/ArduinoJson/Polyfills/type_traits.hpp b/neosensor/libraries/ArduinoJson/src/ArduinoJson/Polyfills/type_traits.hpp index f7afcb78560012d1098d7b03376acfddab314761..8b61e7c91b22d0c314a2976437de871a0b616815 100644 --- a/neosensor/libraries/ArduinoJson/src/ArduinoJson/Polyfills/type_traits.hpp +++ b/neosensor/libraries/ArduinoJson/src/ArduinoJson/Polyfills/type_traits.hpp @@ -1,5 +1,5 @@ // ArduinoJson - https://arduinojson.org -// Copyright © 2014-2022, Benoit BLANCHON +// Copyright © 2014-2023, Benoit BLANCHON // MIT License #pragma once diff --git a/neosensor/libraries/ArduinoJson/src/ArduinoJson/Polyfills/type_traits/conditional.hpp b/neosensor/libraries/ArduinoJson/src/ArduinoJson/Polyfills/type_traits/conditional.hpp index 0f2dc580404f81a2fc7708f8774df8ff8a842864..c481bcb83a395ddcb34501f49b696d1fd80d6453 100644 --- a/neosensor/libraries/ArduinoJson/src/ArduinoJson/Polyfills/type_traits/conditional.hpp +++ b/neosensor/libraries/ArduinoJson/src/ArduinoJson/Polyfills/type_traits/conditional.hpp @@ -1,12 +1,12 @@ // ArduinoJson - https://arduinojson.org -// Copyright © 2014-2022, Benoit BLANCHON +// Copyright © 2014-2023, Benoit BLANCHON // MIT License #pragma once #include <ArduinoJson/Namespace.hpp> -namespace ARDUINOJSON_NAMESPACE { +ARDUINOJSON_BEGIN_PRIVATE_NAMESPACE template <bool Condition, class TrueType, class FalseType> struct conditional { @@ -17,4 +17,5 @@ template <class TrueType, class FalseType> struct conditional<false, TrueType, FalseType> { typedef FalseType type; }; -} // namespace ARDUINOJSON_NAMESPACE + +ARDUINOJSON_END_PRIVATE_NAMESPACE diff --git a/neosensor/libraries/ArduinoJson/src/ArduinoJson/Polyfills/type_traits/declval.hpp b/neosensor/libraries/ArduinoJson/src/ArduinoJson/Polyfills/type_traits/declval.hpp index 4dd5ed929246728649de1aa1dba617a9f7eef38c..41f63e60b2fce4d63363daeb16b0c2df871efee9 100644 --- a/neosensor/libraries/ArduinoJson/src/ArduinoJson/Polyfills/type_traits/declval.hpp +++ b/neosensor/libraries/ArduinoJson/src/ArduinoJson/Polyfills/type_traits/declval.hpp @@ -1,14 +1,14 @@ // ArduinoJson - https://arduinojson.org -// Copyright © 2014-2022, Benoit BLANCHON +// Copyright © 2014-2023, Benoit BLANCHON // MIT License #pragma once #include <ArduinoJson/Namespace.hpp> -namespace ARDUINOJSON_NAMESPACE { +ARDUINOJSON_BEGIN_PRIVATE_NAMESPACE template <typename T> -T declval(); +T&& declval(); -} // namespace ARDUINOJSON_NAMESPACE +ARDUINOJSON_END_PRIVATE_NAMESPACE diff --git a/neosensor/libraries/ArduinoJson/src/ArduinoJson/Polyfills/type_traits/enable_if.hpp b/neosensor/libraries/ArduinoJson/src/ArduinoJson/Polyfills/type_traits/enable_if.hpp index 3eec34cf5f2e7d4028956c7edd94a318548607a9..9d0c530cbc989b6163f9f0f2205fe5b1dce733b2 100644 --- a/neosensor/libraries/ArduinoJson/src/ArduinoJson/Polyfills/type_traits/enable_if.hpp +++ b/neosensor/libraries/ArduinoJson/src/ArduinoJson/Polyfills/type_traits/enable_if.hpp @@ -1,12 +1,12 @@ // ArduinoJson - https://arduinojson.org -// Copyright © 2014-2022, Benoit BLANCHON +// Copyright © 2014-2023, Benoit BLANCHON // MIT License #pragma once #include <ArduinoJson/Namespace.hpp> -namespace ARDUINOJSON_NAMESPACE { +ARDUINOJSON_BEGIN_PRIVATE_NAMESPACE // A meta-function that return the type T if Condition is true. template <bool Condition, typename T = void> @@ -16,4 +16,5 @@ template <typename T> struct enable_if<true, T> { typedef T type; }; -} // namespace ARDUINOJSON_NAMESPACE + +ARDUINOJSON_END_PRIVATE_NAMESPACE diff --git a/neosensor/libraries/ArduinoJson/src/ArduinoJson/Polyfills/type_traits/integral_constant.hpp b/neosensor/libraries/ArduinoJson/src/ArduinoJson/Polyfills/type_traits/integral_constant.hpp index f2585392ec49254ea0bd14e1e67dcce11209338f..e4e224ef5167d3bf63a6c174ad155ffeeb8af075 100644 --- a/neosensor/libraries/ArduinoJson/src/ArduinoJson/Polyfills/type_traits/integral_constant.hpp +++ b/neosensor/libraries/ArduinoJson/src/ArduinoJson/Polyfills/type_traits/integral_constant.hpp @@ -1,12 +1,12 @@ // ArduinoJson - https://arduinojson.org -// Copyright © 2014-2022, Benoit BLANCHON +// Copyright © 2014-2023, Benoit BLANCHON // MIT License #pragma once #include <ArduinoJson/Namespace.hpp> -namespace ARDUINOJSON_NAMESPACE { +ARDUINOJSON_BEGIN_PRIVATE_NAMESPACE template <typename T, T v> struct integral_constant { @@ -16,4 +16,4 @@ struct integral_constant { typedef integral_constant<bool, true> true_type; typedef integral_constant<bool, false> false_type; -} // namespace ARDUINOJSON_NAMESPACE +ARDUINOJSON_END_PRIVATE_NAMESPACE diff --git a/neosensor/libraries/ArduinoJson/src/ArduinoJson/Polyfills/type_traits/is_array.hpp b/neosensor/libraries/ArduinoJson/src/ArduinoJson/Polyfills/type_traits/is_array.hpp index 935671d89e3c6d787c7e3bb63561ece603518d4a..470031be9080b04b41db0534354ef42a94aedf45 100644 --- a/neosensor/libraries/ArduinoJson/src/ArduinoJson/Polyfills/type_traits/is_array.hpp +++ b/neosensor/libraries/ArduinoJson/src/ArduinoJson/Polyfills/type_traits/is_array.hpp @@ -1,5 +1,5 @@ // ArduinoJson - https://arduinojson.org -// Copyright © 2014-2022, Benoit BLANCHON +// Copyright © 2014-2023, Benoit BLANCHON // MIT License #pragma once @@ -8,7 +8,7 @@ #include <stddef.h> // size_t -namespace ARDUINOJSON_NAMESPACE { +ARDUINOJSON_BEGIN_PRIVATE_NAMESPACE template <typename T> struct is_array : false_type {}; @@ -18,4 +18,5 @@ struct is_array<T[]> : true_type {}; template <typename T, size_t N> struct is_array<T[N]> : true_type {}; -} // namespace ARDUINOJSON_NAMESPACE + +ARDUINOJSON_END_PRIVATE_NAMESPACE diff --git a/neosensor/libraries/ArduinoJson/src/ArduinoJson/Polyfills/type_traits/is_base_of.hpp b/neosensor/libraries/ArduinoJson/src/ArduinoJson/Polyfills/type_traits/is_base_of.hpp index 8936bd9bb7f3b4e4fc35498fa631b9b3729399d3..61820a004b0a866d99641bf6a28a4ded5494ec3f 100644 --- a/neosensor/libraries/ArduinoJson/src/ArduinoJson/Polyfills/type_traits/is_base_of.hpp +++ b/neosensor/libraries/ArduinoJson/src/ArduinoJson/Polyfills/type_traits/is_base_of.hpp @@ -1,12 +1,14 @@ // ArduinoJson - https://arduinojson.org -// Copyright © 2014-2022, Benoit BLANCHON +// Copyright © 2014-2023, Benoit BLANCHON // MIT License #pragma once #include <ArduinoJson/Namespace.hpp> -namespace ARDUINOJSON_NAMESPACE { +#include "remove_reference.hpp" + +ARDUINOJSON_BEGIN_PRIVATE_NAMESPACE // A meta-function that returns true if Derived inherits from TBase is an // integral type. @@ -18,6 +20,8 @@ class is_base_of { public: static const bool value = - sizeof(probe(reinterpret_cast<TDerived*>(0))) == sizeof(int); + sizeof(probe(reinterpret_cast<typename remove_reference<TDerived>::type*>( + 0))) == sizeof(int); }; -} // namespace ARDUINOJSON_NAMESPACE + +ARDUINOJSON_END_PRIVATE_NAMESPACE diff --git a/neosensor/libraries/ArduinoJson/src/ArduinoJson/Polyfills/type_traits/is_class.hpp b/neosensor/libraries/ArduinoJson/src/ArduinoJson/Polyfills/type_traits/is_class.hpp index a586c3c5b03cf1c2c75e159e2ecf25adfb20301d..f2b3e27a96fa93a2a74e3ec556b0cf8911dbf168 100644 --- a/neosensor/libraries/ArduinoJson/src/ArduinoJson/Polyfills/type_traits/is_class.hpp +++ b/neosensor/libraries/ArduinoJson/src/ArduinoJson/Polyfills/type_traits/is_class.hpp @@ -1,12 +1,12 @@ // ArduinoJson - https://arduinojson.org -// Copyright © 2014-2022, Benoit BLANCHON +// Copyright © 2014-2023, Benoit BLANCHON // MIT License #pragma once #include "declval.hpp" -namespace ARDUINOJSON_NAMESPACE { +ARDUINOJSON_BEGIN_PRIVATE_NAMESPACE template <typename T> struct is_class { @@ -20,4 +20,4 @@ struct is_class { static const bool value = sizeof(probe<T>(0)) == sizeof(int); }; -} // namespace ARDUINOJSON_NAMESPACE +ARDUINOJSON_END_PRIVATE_NAMESPACE diff --git a/neosensor/libraries/ArduinoJson/src/ArduinoJson/Polyfills/type_traits/is_const.hpp b/neosensor/libraries/ArduinoJson/src/ArduinoJson/Polyfills/type_traits/is_const.hpp index f66d14208456f5d88ce8264525ed6c782394ce5a..330134fd82044c8d92e72b357d435b163a2df9f8 100644 --- a/neosensor/libraries/ArduinoJson/src/ArduinoJson/Polyfills/type_traits/is_const.hpp +++ b/neosensor/libraries/ArduinoJson/src/ArduinoJson/Polyfills/type_traits/is_const.hpp @@ -1,12 +1,12 @@ // ArduinoJson - https://arduinojson.org -// Copyright © 2014-2022, Benoit BLANCHON +// Copyright © 2014-2023, Benoit BLANCHON // MIT License #pragma once #include "integral_constant.hpp" -namespace ARDUINOJSON_NAMESPACE { +ARDUINOJSON_BEGIN_PRIVATE_NAMESPACE // A meta-function that return the type T without the const modifier template <typename T> @@ -14,4 +14,5 @@ struct is_const : false_type {}; template <typename T> struct is_const<const T> : true_type {}; -} // namespace ARDUINOJSON_NAMESPACE + +ARDUINOJSON_END_PRIVATE_NAMESPACE diff --git a/neosensor/libraries/ArduinoJson/src/ArduinoJson/Polyfills/type_traits/is_convertible.hpp b/neosensor/libraries/ArduinoJson/src/ArduinoJson/Polyfills/type_traits/is_convertible.hpp index ef18cf24ba899c4d4f6f121624cb761432d6ac04..7c4810f3fc5760a2b6298f38b016e5495c82c37a 100644 --- a/neosensor/libraries/ArduinoJson/src/ArduinoJson/Polyfills/type_traits/is_convertible.hpp +++ b/neosensor/libraries/ArduinoJson/src/ArduinoJson/Polyfills/type_traits/is_convertible.hpp @@ -1,5 +1,5 @@ // ArduinoJson - https://arduinojson.org -// Copyright © 2014-2022, Benoit BLANCHON +// Copyright © 2014-2023, Benoit BLANCHON // MIT License #pragma once @@ -19,7 +19,7 @@ #endif // clang-format on -namespace ARDUINOJSON_NAMESPACE { +ARDUINOJSON_BEGIN_PRIVATE_NAMESPACE template <typename From, typename To> struct is_convertible { @@ -27,13 +27,13 @@ struct is_convertible { static int probe(To); static char probe(...); - static From& _from; + static From& from_; public: - static const bool value = sizeof(probe(_from)) == sizeof(int); + static const bool value = sizeof(probe(from_)) == sizeof(int); }; -} // namespace ARDUINOJSON_NAMESPACE +ARDUINOJSON_END_PRIVATE_NAMESPACE #ifdef _MSC_VER # pragma warning(pop) diff --git a/neosensor/libraries/ArduinoJson/src/ArduinoJson/Polyfills/type_traits/is_enum.hpp b/neosensor/libraries/ArduinoJson/src/ArduinoJson/Polyfills/type_traits/is_enum.hpp index de6663a9d6114b5696cb76ab3974281d5decbf08..a66687961b6005af75f1a297613cca56007bd0a7 100644 --- a/neosensor/libraries/ArduinoJson/src/ArduinoJson/Polyfills/type_traits/is_enum.hpp +++ b/neosensor/libraries/ArduinoJson/src/ArduinoJson/Polyfills/type_traits/is_enum.hpp @@ -1,5 +1,5 @@ // ArduinoJson - https://arduinojson.org -// Copyright © 2014-2022, Benoit BLANCHON +// Copyright © 2014-2023, Benoit BLANCHON // MIT License #pragma once @@ -10,7 +10,7 @@ #include "is_integral.hpp" #include "is_same.hpp" -namespace ARDUINOJSON_NAMESPACE { +ARDUINOJSON_BEGIN_PRIVATE_NAMESPACE template <typename T> struct is_enum { @@ -19,4 +19,4 @@ struct is_enum { !is_floating_point<T>::value; }; -} // namespace ARDUINOJSON_NAMESPACE +ARDUINOJSON_END_PRIVATE_NAMESPACE diff --git a/neosensor/libraries/ArduinoJson/src/ArduinoJson/Polyfills/type_traits/is_floating_point.hpp b/neosensor/libraries/ArduinoJson/src/ArduinoJson/Polyfills/type_traits/is_floating_point.hpp index c725eb845096384fb1e76ff6bf9e0f876cb2b325..4a58dfa01ca6eb5b81c9a16846d6551331f8a374 100644 --- a/neosensor/libraries/ArduinoJson/src/ArduinoJson/Polyfills/type_traits/is_floating_point.hpp +++ b/neosensor/libraries/ArduinoJson/src/ArduinoJson/Polyfills/type_traits/is_floating_point.hpp @@ -1,5 +1,5 @@ // ArduinoJson - https://arduinojson.org -// Copyright © 2014-2022, Benoit BLANCHON +// Copyright © 2014-2023, Benoit BLANCHON // MIT License #pragma once @@ -8,7 +8,7 @@ #include "is_same.hpp" #include "remove_cv.hpp" -namespace ARDUINOJSON_NAMESPACE { +ARDUINOJSON_BEGIN_PRIVATE_NAMESPACE template <class T> struct is_floating_point @@ -17,4 +17,4 @@ struct is_floating_point is_same<float, typename remove_cv<T>::type>::value || is_same<double, typename remove_cv<T>::type>::value> {}; -} // namespace ARDUINOJSON_NAMESPACE +ARDUINOJSON_END_PRIVATE_NAMESPACE diff --git a/neosensor/libraries/ArduinoJson/src/ArduinoJson/Polyfills/type_traits/is_integral.hpp b/neosensor/libraries/ArduinoJson/src/ArduinoJson/Polyfills/type_traits/is_integral.hpp index fc0da04ac2da25381f11198fad3dcf71305ec93a..85d183262188c6c9e0a64105943a6b60ed3fba81 100644 --- a/neosensor/libraries/ArduinoJson/src/ArduinoJson/Polyfills/type_traits/is_integral.hpp +++ b/neosensor/libraries/ArduinoJson/src/ArduinoJson/Polyfills/type_traits/is_integral.hpp @@ -1,5 +1,5 @@ // ArduinoJson - https://arduinojson.org -// Copyright © 2014-2022, Benoit BLANCHON +// Copyright © 2014-2023, Benoit BLANCHON // MIT License #pragma once @@ -10,7 +10,7 @@ #include "is_same.hpp" #include "remove_cv.hpp" -namespace ARDUINOJSON_NAMESPACE { +ARDUINOJSON_BEGIN_PRIVATE_NAMESPACE // clang-format off template <typename T> @@ -23,15 +23,10 @@ struct is_integral : integral_constant<bool, is_same<typename remove_cv<T>::type, unsigned int>::value || is_same<typename remove_cv<T>::type, signed long>::value || is_same<typename remove_cv<T>::type, unsigned long>::value || -#if ARDUINOJSON_HAS_LONG_LONG is_same<typename remove_cv<T>::type, signed long long>::value || is_same<typename remove_cv<T>::type, unsigned long long>::value || -#endif -#if ARDUINOJSON_HAS_INT64 - is_same<typename remove_cv<T>::type, signed __int64>::value || - is_same<typename remove_cv<T>::type, unsigned __int64>::value || -#endif is_same<typename remove_cv<T>::type, char>::value || is_same<typename remove_cv<T>::type, bool>::value> {}; // clang-format on -} // namespace ARDUINOJSON_NAMESPACE + +ARDUINOJSON_END_PRIVATE_NAMESPACE diff --git a/neosensor/libraries/ArduinoJson/src/ArduinoJson/Polyfills/type_traits/is_pointer.hpp b/neosensor/libraries/ArduinoJson/src/ArduinoJson/Polyfills/type_traits/is_pointer.hpp index 8a99cdb60bbba9d92b91bd195729d2ba4aea7808..2c200da2a4378dc02f9f9a5f7cefe5f0b1886171 100644 --- a/neosensor/libraries/ArduinoJson/src/ArduinoJson/Polyfills/type_traits/is_pointer.hpp +++ b/neosensor/libraries/ArduinoJson/src/ArduinoJson/Polyfills/type_traits/is_pointer.hpp @@ -1,16 +1,17 @@ // ArduinoJson - https://arduinojson.org -// Copyright © 2014-2022, Benoit BLANCHON +// Copyright © 2014-2023, Benoit BLANCHON // MIT License #pragma once #include "integral_constant.hpp" -namespace ARDUINOJSON_NAMESPACE { +ARDUINOJSON_BEGIN_PRIVATE_NAMESPACE template <typename T> struct is_pointer : false_type {}; template <typename T> struct is_pointer<T*> : true_type {}; -} // namespace ARDUINOJSON_NAMESPACE + +ARDUINOJSON_END_PRIVATE_NAMESPACE diff --git a/neosensor/libraries/ArduinoJson/src/ArduinoJson/Polyfills/type_traits/is_same.hpp b/neosensor/libraries/ArduinoJson/src/ArduinoJson/Polyfills/type_traits/is_same.hpp index 956db6b423c11ba687e45731c5a2148122115fd1..71e668920313acf69b8d189b5d7fdb11ea841ad3 100644 --- a/neosensor/libraries/ArduinoJson/src/ArduinoJson/Polyfills/type_traits/is_same.hpp +++ b/neosensor/libraries/ArduinoJson/src/ArduinoJson/Polyfills/type_traits/is_same.hpp @@ -1,12 +1,12 @@ // ArduinoJson - https://arduinojson.org -// Copyright © 2014-2022, Benoit BLANCHON +// Copyright © 2014-2023, Benoit BLANCHON // MIT License #pragma once #include "integral_constant.hpp" -namespace ARDUINOJSON_NAMESPACE { +ARDUINOJSON_BEGIN_PRIVATE_NAMESPACE // A meta-function that returns true if types T and U are the same. template <typename T, typename U> @@ -14,4 +14,5 @@ struct is_same : false_type {}; template <typename T> struct is_same<T, T> : true_type {}; -} // namespace ARDUINOJSON_NAMESPACE + +ARDUINOJSON_END_PRIVATE_NAMESPACE diff --git a/neosensor/libraries/ArduinoJson/src/ArduinoJson/Polyfills/type_traits/is_signed.hpp b/neosensor/libraries/ArduinoJson/src/ArduinoJson/Polyfills/type_traits/is_signed.hpp index d6c7016a4602fd1458453f82780f3a16d9cf2960..eb3cc62498bb1d821035e4ffbe2f0386719aa27f 100644 --- a/neosensor/libraries/ArduinoJson/src/ArduinoJson/Polyfills/type_traits/is_signed.hpp +++ b/neosensor/libraries/ArduinoJson/src/ArduinoJson/Polyfills/type_traits/is_signed.hpp @@ -1,5 +1,5 @@ // ArduinoJson - https://arduinojson.org -// Copyright © 2014-2022, Benoit BLANCHON +// Copyright © 2014-2023, Benoit BLANCHON // MIT License #pragma once @@ -8,23 +8,19 @@ #include "is_same.hpp" #include "remove_cv.hpp" -namespace ARDUINOJSON_NAMESPACE { +ARDUINOJSON_BEGIN_PRIVATE_NAMESPACE // clang-format off template <typename T> -struct is_signed : integral_constant<bool, +struct is_signed : integral_constant<bool, is_same<typename remove_cv<T>::type, char>::value || is_same<typename remove_cv<T>::type, signed char>::value || is_same<typename remove_cv<T>::type, signed short>::value || is_same<typename remove_cv<T>::type, signed int>::value || is_same<typename remove_cv<T>::type, signed long>::value || -#if ARDUINOJSON_HAS_LONG_LONG is_same<typename remove_cv<T>::type, signed long long>::value || -#endif -#if ARDUINOJSON_HAS_INT64 - is_same<typename remove_cv<T>::type, signed __int64>::value || -#endif is_same<typename remove_cv<T>::type, float>::value || is_same<typename remove_cv<T>::type, double>::value> {}; // clang-format on -} // namespace ARDUINOJSON_NAMESPACE + +ARDUINOJSON_END_PRIVATE_NAMESPACE diff --git a/neosensor/libraries/ArduinoJson/src/ArduinoJson/Polyfills/type_traits/is_unsigned.hpp b/neosensor/libraries/ArduinoJson/src/ArduinoJson/Polyfills/type_traits/is_unsigned.hpp index 84b7d05115ca3435f00a3cf4692558cc972a17cc..803eaea03ff3e5b2744a73705cf71a549f5d4510 100644 --- a/neosensor/libraries/ArduinoJson/src/ArduinoJson/Polyfills/type_traits/is_unsigned.hpp +++ b/neosensor/libraries/ArduinoJson/src/ArduinoJson/Polyfills/type_traits/is_unsigned.hpp @@ -1,5 +1,5 @@ // ArduinoJson - https://arduinojson.org -// Copyright © 2014-2022, Benoit BLANCHON +// Copyright © 2014-2023, Benoit BLANCHON // MIT License #pragma once @@ -8,7 +8,7 @@ #include "is_same.hpp" #include "remove_cv.hpp" -namespace ARDUINOJSON_NAMESPACE { +ARDUINOJSON_BEGIN_PRIVATE_NAMESPACE // clang-format off template <typename T> @@ -17,12 +17,8 @@ struct is_unsigned : integral_constant<bool, is_same<typename remove_cv<T>::type, unsigned short>::value || is_same<typename remove_cv<T>::type, unsigned int>::value || is_same<typename remove_cv<T>::type, unsigned long>::value || -#if ARDUINOJSON_HAS_INT64 - is_same<typename remove_cv<T>::type, unsigned __int64>::value || -#endif -#if ARDUINOJSON_HAS_LONG_LONG is_same<typename remove_cv<T>::type, unsigned long long>::value || -#endif is_same<typename remove_cv<T>::type, bool>::value> {}; // clang-format on -} // namespace ARDUINOJSON_NAMESPACE + +ARDUINOJSON_END_PRIVATE_NAMESPACE diff --git a/neosensor/libraries/ArduinoJson/src/ArduinoJson/Polyfills/type_traits/make_unsigned.hpp b/neosensor/libraries/ArduinoJson/src/ArduinoJson/Polyfills/type_traits/make_unsigned.hpp index f7fc371211cc08791afcc8a48c0fcb487fed54bc..8479848753a21d4de6aeb94e541d04a90aa1b253 100644 --- a/neosensor/libraries/ArduinoJson/src/ArduinoJson/Polyfills/type_traits/make_unsigned.hpp +++ b/neosensor/libraries/ArduinoJson/src/ArduinoJson/Polyfills/type_traits/make_unsigned.hpp @@ -1,11 +1,11 @@ // ArduinoJson - https://arduinojson.org -// Copyright © 2014-2022, Benoit BLANCHON +// Copyright © 2014-2023, Benoit BLANCHON // MIT License #pragma once #include "type_identity.hpp" -namespace ARDUINOJSON_NAMESPACE { +ARDUINOJSON_BEGIN_PRIVATE_NAMESPACE template <typename T> struct make_unsigned; @@ -33,17 +33,9 @@ struct make_unsigned<signed long> : type_identity<unsigned long> {}; template <> struct make_unsigned<unsigned long> : type_identity<unsigned long> {}; -#if ARDUINOJSON_HAS_LONG_LONG template <> struct make_unsigned<signed long long> : type_identity<unsigned long long> {}; template <> struct make_unsigned<unsigned long long> : type_identity<unsigned long long> {}; -#endif -#if ARDUINOJSON_HAS_INT64 -template <> -struct make_unsigned<signed __int64> : type_identity<unsigned __int64> {}; -template <> -struct make_unsigned<unsigned __int64> : type_identity<unsigned __int64> {}; -#endif -} // namespace ARDUINOJSON_NAMESPACE +ARDUINOJSON_END_PRIVATE_NAMESPACE diff --git a/neosensor/libraries/ArduinoJson/src/ArduinoJson/Polyfills/type_traits/make_void.hpp b/neosensor/libraries/ArduinoJson/src/ArduinoJson/Polyfills/type_traits/make_void.hpp index bd2d7448b794b19b5ea85df9551c765e54c746c2..b20d424d5051571e8930ebb8f56f5dae47e836c7 100644 --- a/neosensor/libraries/ArduinoJson/src/ArduinoJson/Polyfills/type_traits/make_void.hpp +++ b/neosensor/libraries/ArduinoJson/src/ArduinoJson/Polyfills/type_traits/make_void.hpp @@ -1,14 +1,14 @@ // ArduinoJson - https://arduinojson.org -// Copyright © 2014-2022, Benoit BLANCHON +// Copyright © 2014-2023, Benoit BLANCHON // MIT License #pragma once -namespace ARDUINOJSON_NAMESPACE { +ARDUINOJSON_BEGIN_PRIVATE_NAMESPACE template <class = void> struct make_void { typedef void type; }; -} // namespace ARDUINOJSON_NAMESPACE +ARDUINOJSON_END_PRIVATE_NAMESPACE diff --git a/neosensor/libraries/ArduinoJson/src/ArduinoJson/Polyfills/type_traits/remove_const.hpp b/neosensor/libraries/ArduinoJson/src/ArduinoJson/Polyfills/type_traits/remove_const.hpp index 77fb438df021b2bbb9fb06741704978462ce004b..2592566c1c397b95876ed320250a1afb2f7abef1 100644 --- a/neosensor/libraries/ArduinoJson/src/ArduinoJson/Polyfills/type_traits/remove_const.hpp +++ b/neosensor/libraries/ArduinoJson/src/ArduinoJson/Polyfills/type_traits/remove_const.hpp @@ -1,12 +1,12 @@ // ArduinoJson - https://arduinojson.org -// Copyright © 2014-2022, Benoit BLANCHON +// Copyright © 2014-2023, Benoit BLANCHON // MIT License #pragma once #include <ArduinoJson/Namespace.hpp> -namespace ARDUINOJSON_NAMESPACE { +ARDUINOJSON_BEGIN_PRIVATE_NAMESPACE // A meta-function that return the type T without the const modifier template <typename T> @@ -17,4 +17,5 @@ template <typename T> struct remove_const<const T> { typedef T type; }; -} // namespace ARDUINOJSON_NAMESPACE + +ARDUINOJSON_END_PRIVATE_NAMESPACE diff --git a/neosensor/libraries/ArduinoJson/src/ArduinoJson/Polyfills/type_traits/remove_cv.hpp b/neosensor/libraries/ArduinoJson/src/ArduinoJson/Polyfills/type_traits/remove_cv.hpp index 64f6e109bcf83551ad6f8e796644208d1a635115..70ceed3466723660cf16ea53a9548b89ff4063c4 100644 --- a/neosensor/libraries/ArduinoJson/src/ArduinoJson/Polyfills/type_traits/remove_cv.hpp +++ b/neosensor/libraries/ArduinoJson/src/ArduinoJson/Polyfills/type_traits/remove_cv.hpp @@ -1,12 +1,12 @@ // ArduinoJson - https://arduinojson.org -// Copyright © 2014-2022, Benoit BLANCHON +// Copyright © 2014-2023, Benoit BLANCHON // MIT License #pragma once #include <ArduinoJson/Namespace.hpp> -namespace ARDUINOJSON_NAMESPACE { +ARDUINOJSON_BEGIN_PRIVATE_NAMESPACE template <typename T> struct remove_cv { @@ -24,4 +24,5 @@ template <typename T> struct remove_cv<const volatile T> { typedef T type; }; -} // namespace ARDUINOJSON_NAMESPACE + +ARDUINOJSON_END_PRIVATE_NAMESPACE diff --git a/neosensor/libraries/ArduinoJson/src/ArduinoJson/Polyfills/type_traits/remove_reference.hpp b/neosensor/libraries/ArduinoJson/src/ArduinoJson/Polyfills/type_traits/remove_reference.hpp index b63d1ae9129c0ec829ad41de361e3f574632598e..263c730048d9e120c44bd0de66571525a720ba74 100644 --- a/neosensor/libraries/ArduinoJson/src/ArduinoJson/Polyfills/type_traits/remove_reference.hpp +++ b/neosensor/libraries/ArduinoJson/src/ArduinoJson/Polyfills/type_traits/remove_reference.hpp @@ -1,12 +1,12 @@ // ArduinoJson - https://arduinojson.org -// Copyright © 2014-2022, Benoit BLANCHON +// Copyright © 2014-2023, Benoit BLANCHON // MIT License #pragma once #include <ArduinoJson/Namespace.hpp> -namespace ARDUINOJSON_NAMESPACE { +ARDUINOJSON_BEGIN_PRIVATE_NAMESPACE // A meta-function that return the type T without the reference modifier. template <typename T> @@ -17,4 +17,5 @@ template <typename T> struct remove_reference<T&> { typedef T type; }; -} // namespace ARDUINOJSON_NAMESPACE + +ARDUINOJSON_END_PRIVATE_NAMESPACE diff --git a/neosensor/libraries/ArduinoJson/src/ArduinoJson/Polyfills/type_traits/type_identity.hpp b/neosensor/libraries/ArduinoJson/src/ArduinoJson/Polyfills/type_traits/type_identity.hpp index b797b517dbbdfe0d9068446dd69645b50c693e47..4481bc7e4faa8e0150d911679731548247191331 100644 --- a/neosensor/libraries/ArduinoJson/src/ArduinoJson/Polyfills/type_traits/type_identity.hpp +++ b/neosensor/libraries/ArduinoJson/src/ArduinoJson/Polyfills/type_traits/type_identity.hpp @@ -1,15 +1,16 @@ // ArduinoJson - https://arduinojson.org -// Copyright © 2014-2022, Benoit BLANCHON +// Copyright © 2014-2023, Benoit BLANCHON // MIT License #pragma once #include "integral_constant.hpp" -namespace ARDUINOJSON_NAMESPACE { +ARDUINOJSON_BEGIN_PRIVATE_NAMESPACE template <typename T> struct type_identity { typedef T type; }; -} // namespace ARDUINOJSON_NAMESPACE + +ARDUINOJSON_END_PRIVATE_NAMESPACE diff --git a/neosensor/libraries/ArduinoJson/src/ArduinoJson/Polyfills/utility.hpp b/neosensor/libraries/ArduinoJson/src/ArduinoJson/Polyfills/utility.hpp new file mode 100644 index 0000000000000000000000000000000000000000..13fb3e706386d84f96c6ef187e98db49e6e20cb6 --- /dev/null +++ b/neosensor/libraries/ArduinoJson/src/ArduinoJson/Polyfills/utility.hpp @@ -0,0 +1,16 @@ +// ArduinoJson - https://arduinojson.org +// Copyright © 2014-2023, Benoit BLANCHON +// MIT License + +#pragma once + +#include "type_traits.hpp" + +ARDUINOJSON_BEGIN_PRIVATE_NAMESPACE + +template <class T> +T&& forward(typename remove_reference<T>::type& t) noexcept { + return static_cast<T&&>(t); +} + +ARDUINOJSON_END_PRIVATE_NAMESPACE diff --git a/neosensor/libraries/ArduinoJson/src/ArduinoJson/Serialization/CountingDecorator.hpp b/neosensor/libraries/ArduinoJson/src/ArduinoJson/Serialization/CountingDecorator.hpp index 6fc4689dff6225dc63ad28e7ca62938755339d47..b38a22dfcb274647df5d0e038548b00e1e821d8c 100644 --- a/neosensor/libraries/ArduinoJson/src/ArduinoJson/Serialization/CountingDecorator.hpp +++ b/neosensor/libraries/ArduinoJson/src/ArduinoJson/Serialization/CountingDecorator.hpp @@ -1,33 +1,33 @@ // ArduinoJson - https://arduinojson.org -// Copyright © 2014-2022, Benoit BLANCHON +// Copyright © 2014-2023, Benoit BLANCHON // MIT License #pragma once #include <ArduinoJson/Namespace.hpp> -namespace ARDUINOJSON_NAMESPACE { +ARDUINOJSON_BEGIN_PRIVATE_NAMESPACE template <typename TWriter> class CountingDecorator { public: - explicit CountingDecorator(TWriter& writer) : _writer(writer), _count(0) {} + explicit CountingDecorator(TWriter& writer) : writer_(writer), count_(0) {} void write(uint8_t c) { - _count += _writer.write(c); + count_ += writer_.write(c); } void write(const uint8_t* s, size_t n) { - _count += _writer.write(s, n); + count_ += writer_.write(s, n); } size_t count() const { - return _count; + return count_; } private: - TWriter _writer; - size_t _count; + TWriter writer_; + size_t count_; }; -} // namespace ARDUINOJSON_NAMESPACE +ARDUINOJSON_END_PRIVATE_NAMESPACE diff --git a/neosensor/libraries/ArduinoJson/src/ArduinoJson/Serialization/Writer.hpp b/neosensor/libraries/ArduinoJson/src/ArduinoJson/Serialization/Writer.hpp index e69247c7fa68514ddcbce8f79277a0b2e69a5d4d..f6ba225dfbf831f31c776b0bf6d8fefb4f37b548 100644 --- a/neosensor/libraries/ArduinoJson/src/ArduinoJson/Serialization/Writer.hpp +++ b/neosensor/libraries/ArduinoJson/src/ArduinoJson/Serialization/Writer.hpp @@ -1,32 +1,32 @@ // ArduinoJson - https://arduinojson.org -// Copyright © 2014-2022, Benoit BLANCHON +// Copyright © 2014-2023, Benoit BLANCHON // MIT License #pragma once #include <ArduinoJson/Namespace.hpp> -namespace ARDUINOJSON_NAMESPACE { +ARDUINOJSON_BEGIN_PRIVATE_NAMESPACE // The default writer is a simple wrapper for Writers that are not copiable template <typename TDestination, typename Enable = void> class Writer { public: - explicit Writer(TDestination& dest) : _dest(&dest) {} + explicit Writer(TDestination& dest) : dest_(&dest) {} size_t write(uint8_t c) { - return _dest->write(c); + return dest_->write(c); } size_t write(const uint8_t* s, size_t n) { - return _dest->write(s, n); + return dest_->write(s, n); } private: - TDestination* _dest; + TDestination* dest_; }; -} // namespace ARDUINOJSON_NAMESPACE +ARDUINOJSON_END_PRIVATE_NAMESPACE #include <ArduinoJson/Serialization/Writers/StaticStringWriter.hpp> diff --git a/neosensor/libraries/ArduinoJson/src/ArduinoJson/Serialization/Writers/ArduinoStringWriter.hpp b/neosensor/libraries/ArduinoJson/src/ArduinoJson/Serialization/Writers/ArduinoStringWriter.hpp index 3ab1be3dd381c778906b2a64a8b03ee6a9c979d6..c643248798da271e38e99bbbc948e2b7c14b56fb 100644 --- a/neosensor/libraries/ArduinoJson/src/ArduinoJson/Serialization/Writers/ArduinoStringWriter.hpp +++ b/neosensor/libraries/ArduinoJson/src/ArduinoJson/Serialization/Writers/ArduinoStringWriter.hpp @@ -1,20 +1,20 @@ // ArduinoJson - https://arduinojson.org -// Copyright © 2014-2022, Benoit BLANCHON +// Copyright © 2014-2023, Benoit BLANCHON // MIT License #pragma once #include <Arduino.h> -namespace ARDUINOJSON_NAMESPACE { +ARDUINOJSON_BEGIN_PRIVATE_NAMESPACE template <> -class Writer< ::String, void> { +class Writer<::String, void> { static const size_t bufferCapacity = ARDUINOJSON_STRING_BUFFER_SIZE; public: - explicit Writer(::String& str) : _destination(&str) { - _size = 0; + explicit Writer(::String& str) : destination_(&str) { + size_ = 0; } ~Writer() { @@ -22,10 +22,10 @@ class Writer< ::String, void> { } size_t write(uint8_t c) { - if (_size + 1 >= bufferCapacity) + if (size_ + 1 >= bufferCapacity) if (flush() != 0) return 0; - _buffer[_size++] = static_cast<char>(c); + buffer_[size_++] = static_cast<char>(c); return 1; } @@ -37,17 +37,17 @@ class Writer< ::String, void> { } size_t flush() { - ARDUINOJSON_ASSERT(_size < bufferCapacity); - _buffer[_size] = 0; - if (_destination->concat(_buffer)) - _size = 0; - return _size; + ARDUINOJSON_ASSERT(size_ < bufferCapacity); + buffer_[size_] = 0; + if (destination_->concat(buffer_)) + size_ = 0; + return size_; } private: - ::String* _destination; - char _buffer[bufferCapacity]; - size_t _size; + ::String* destination_; + char buffer_[bufferCapacity]; + size_t size_; }; -} // namespace ARDUINOJSON_NAMESPACE +ARDUINOJSON_END_PRIVATE_NAMESPACE diff --git a/neosensor/libraries/ArduinoJson/src/ArduinoJson/Serialization/Writers/DummyWriter.hpp b/neosensor/libraries/ArduinoJson/src/ArduinoJson/Serialization/Writers/DummyWriter.hpp index 430865e9dfa944cc4c4c0047f2221fd22c723aa7..ff35def7abec7e4e1f0c542ca6052b994f92ccf4 100644 --- a/neosensor/libraries/ArduinoJson/src/ArduinoJson/Serialization/Writers/DummyWriter.hpp +++ b/neosensor/libraries/ArduinoJson/src/ArduinoJson/Serialization/Writers/DummyWriter.hpp @@ -1,12 +1,12 @@ // ArduinoJson - https://arduinojson.org -// Copyright © 2014-2022, Benoit BLANCHON +// Copyright © 2014-2023, Benoit BLANCHON // MIT License #pragma once #include <ArduinoJson/Namespace.hpp> -namespace ARDUINOJSON_NAMESPACE { +ARDUINOJSON_BEGIN_PRIVATE_NAMESPACE class DummyWriter { public: @@ -18,4 +18,5 @@ class DummyWriter { return n; } }; -} // namespace ARDUINOJSON_NAMESPACE + +ARDUINOJSON_END_PRIVATE_NAMESPACE diff --git a/neosensor/libraries/ArduinoJson/src/ArduinoJson/Serialization/Writers/PrintWriter.hpp b/neosensor/libraries/ArduinoJson/src/ArduinoJson/Serialization/Writers/PrintWriter.hpp index cfac79fb0955d2242e008000b908e55d4a8dae54..49f6a6e96a6c11c4c4c171c81c9d42eb8e429b2d 100644 --- a/neosensor/libraries/ArduinoJson/src/ArduinoJson/Serialization/Writers/PrintWriter.hpp +++ b/neosensor/libraries/ArduinoJson/src/ArduinoJson/Serialization/Writers/PrintWriter.hpp @@ -1,30 +1,30 @@ // ArduinoJson - https://arduinojson.org -// Copyright © 2014-2022, Benoit BLANCHON +// Copyright © 2014-2023, Benoit BLANCHON // MIT License #pragma once #include <Arduino.h> -namespace ARDUINOJSON_NAMESPACE { +ARDUINOJSON_BEGIN_PRIVATE_NAMESPACE template <typename TDestination> class Writer< TDestination, - typename enable_if<is_base_of< ::Print, TDestination>::value>::type> { + typename enable_if<is_base_of<::Print, TDestination>::value>::type> { public: - explicit Writer(::Print& print) : _print(&print) {} + explicit Writer(::Print& print) : print_(&print) {} size_t write(uint8_t c) { - return _print->write(c); + return print_->write(c); } size_t write(const uint8_t* s, size_t n) { - return _print->write(s, n); + return print_->write(s, n); } private: - ::Print* _print; + ::Print* print_; }; -} // namespace ARDUINOJSON_NAMESPACE +ARDUINOJSON_END_PRIVATE_NAMESPACE diff --git a/neosensor/libraries/ArduinoJson/src/ArduinoJson/Serialization/Writers/StaticStringWriter.hpp b/neosensor/libraries/ArduinoJson/src/ArduinoJson/Serialization/Writers/StaticStringWriter.hpp index f55ddaff55f874e6d91180fc7e6d299508e51d25..169ebe1941e9b5c04db5629eee7029a395d4305f 100644 --- a/neosensor/libraries/ArduinoJson/src/ArduinoJson/Serialization/Writers/StaticStringWriter.hpp +++ b/neosensor/libraries/ArduinoJson/src/ArduinoJson/Serialization/Writers/StaticStringWriter.hpp @@ -1,12 +1,12 @@ // ArduinoJson - https://arduinojson.org -// Copyright © 2014-2022, Benoit BLANCHON +// Copyright © 2014-2023, Benoit BLANCHON // MIT License #pragma once #include <ArduinoJson/Namespace.hpp> -namespace ARDUINOJSON_NAMESPACE { +ARDUINOJSON_BEGIN_PRIVATE_NAMESPACE class StaticStringWriter { public: @@ -32,4 +32,5 @@ class StaticStringWriter { char* end; char* p; }; -} // namespace ARDUINOJSON_NAMESPACE + +ARDUINOJSON_END_PRIVATE_NAMESPACE diff --git a/neosensor/libraries/ArduinoJson/src/ArduinoJson/Serialization/Writers/StdStreamWriter.hpp b/neosensor/libraries/ArduinoJson/src/ArduinoJson/Serialization/Writers/StdStreamWriter.hpp index e77b445bcaf9633d216239bc1072a4e053c9ecd1..fdfead73896dfc72b7b0c5cd9f2fe1345ec875c0 100644 --- a/neosensor/libraries/ArduinoJson/src/ArduinoJson/Serialization/Writers/StdStreamWriter.hpp +++ b/neosensor/libraries/ArduinoJson/src/ArduinoJson/Serialization/Writers/StdStreamWriter.hpp @@ -1,32 +1,33 @@ // ArduinoJson - https://arduinojson.org -// Copyright © 2014-2022, Benoit BLANCHON +// Copyright © 2014-2023, Benoit BLANCHON // MIT License #pragma once #include <ostream> -namespace ARDUINOJSON_NAMESPACE { +ARDUINOJSON_BEGIN_PRIVATE_NAMESPACE template <typename TDestination> class Writer< TDestination, typename enable_if<is_base_of<std::ostream, TDestination>::value>::type> { public: - explicit Writer(std::ostream& os) : _os(&os) {} + explicit Writer(std::ostream& os) : os_(&os) {} size_t write(uint8_t c) { - _os->put(static_cast<char>(c)); + os_->put(static_cast<char>(c)); return 1; } size_t write(const uint8_t* s, size_t n) { - _os->write(reinterpret_cast<const char*>(s), + os_->write(reinterpret_cast<const char*>(s), static_cast<std::streamsize>(n)); return n; } private: - std::ostream* _os; + std::ostream* os_; }; -} // namespace ARDUINOJSON_NAMESPACE + +ARDUINOJSON_END_PRIVATE_NAMESPACE diff --git a/neosensor/libraries/ArduinoJson/src/ArduinoJson/Serialization/Writers/StdStringWriter.hpp b/neosensor/libraries/ArduinoJson/src/ArduinoJson/Serialization/Writers/StdStringWriter.hpp index 2ca14505c50678708b35928557eb85ee123bd215..1f8afaa8863a64a6f4b12063a73b8eaeab1e871d 100644 --- a/neosensor/libraries/ArduinoJson/src/ArduinoJson/Serialization/Writers/StdStringWriter.hpp +++ b/neosensor/libraries/ArduinoJson/src/ArduinoJson/Serialization/Writers/StdStringWriter.hpp @@ -1,5 +1,5 @@ // ArduinoJson - https://arduinojson.org -// Copyright © 2014-2022, Benoit BLANCHON +// Copyright © 2014-2023, Benoit BLANCHON // MIT License #pragma once @@ -7,34 +7,37 @@ #include <ArduinoJson/Namespace.hpp> #include <ArduinoJson/Polyfills/type_traits.hpp> -#include <string> +ARDUINOJSON_BEGIN_PRIVATE_NAMESPACE -namespace ARDUINOJSON_NAMESPACE { +template <class...> +using void_t = void; -template <class T> +template <class T, typename = void> struct is_std_string : false_type {}; -template <class TCharTraits, class TAllocator> -struct is_std_string<std::basic_string<char, TCharTraits, TAllocator> > +template <class T> +struct is_std_string< + T, void_t<decltype(T().push_back('a')), decltype(T().append(""))>> : true_type {}; template <typename TDestination> class Writer<TDestination, typename enable_if<is_std_string<TDestination>::value>::type> { public: - Writer(TDestination& str) : _str(&str) {} + Writer(TDestination& str) : str_(&str) {} size_t write(uint8_t c) { - _str->operator+=(static_cast<char>(c)); + str_->push_back(static_cast<char>(c)); return 1; } size_t write(const uint8_t* s, size_t n) { - _str->append(reinterpret_cast<const char*>(s), n); + str_->append(reinterpret_cast<const char*>(s), n); return n; } private: - TDestination* _str; + TDestination* str_; }; -} // namespace ARDUINOJSON_NAMESPACE + +ARDUINOJSON_END_PRIVATE_NAMESPACE diff --git a/neosensor/libraries/ArduinoJson/src/ArduinoJson/Serialization/measure.hpp b/neosensor/libraries/ArduinoJson/src/ArduinoJson/Serialization/measure.hpp index b8172c577a40f2f474038e7739352f99d38101a3..5a71e104bd2a90c522478e7447fba75a00f8c0af 100644 --- a/neosensor/libraries/ArduinoJson/src/ArduinoJson/Serialization/measure.hpp +++ b/neosensor/libraries/ArduinoJson/src/ArduinoJson/Serialization/measure.hpp @@ -1,5 +1,5 @@ // ArduinoJson - https://arduinojson.org -// Copyright © 2014-2022, Benoit BLANCHON +// Copyright © 2014-2023, Benoit BLANCHON // MIT License #pragma once @@ -7,13 +7,13 @@ #include <ArduinoJson/Serialization/Writers/DummyWriter.hpp> #include <ArduinoJson/Variant/VariantFunctions.hpp> -namespace ARDUINOJSON_NAMESPACE { +ARDUINOJSON_BEGIN_PRIVATE_NAMESPACE template <template <typename> class TSerializer> -size_t measure(JsonVariantConst source) { +size_t measure(ArduinoJson::JsonVariantConst source) { DummyWriter dp; TSerializer<DummyWriter> serializer(dp); return variantAccept(VariantAttorney::getData(source), serializer); } -} // namespace ARDUINOJSON_NAMESPACE +ARDUINOJSON_END_PRIVATE_NAMESPACE diff --git a/neosensor/libraries/ArduinoJson/src/ArduinoJson/Serialization/serialize.hpp b/neosensor/libraries/ArduinoJson/src/ArduinoJson/Serialization/serialize.hpp index cc57b4c69d052735a15d8a76d30d844aa2e07186..1014a7d6290251a77654269571465cb6eb4e6f5a 100644 --- a/neosensor/libraries/ArduinoJson/src/ArduinoJson/Serialization/serialize.hpp +++ b/neosensor/libraries/ArduinoJson/src/ArduinoJson/Serialization/serialize.hpp @@ -1,5 +1,5 @@ // ArduinoJson - https://arduinojson.org -// Copyright © 2014-2022, Benoit BLANCHON +// Copyright © 2014-2023, Benoit BLANCHON // MIT License #pragma once @@ -7,30 +7,33 @@ #include <ArduinoJson/Serialization/Writer.hpp> #include <ArduinoJson/Variant/VariantFunctions.hpp> -namespace ARDUINOJSON_NAMESPACE { +ARDUINOJSON_BEGIN_PRIVATE_NAMESPACE template <template <typename> class TSerializer, typename TWriter> -size_t doSerialize(JsonVariantConst source, TWriter writer) { +size_t doSerialize(ArduinoJson::JsonVariantConst source, TWriter writer) { TSerializer<TWriter> serializer(writer); return variantAccept(VariantAttorney::getData(source), serializer); } template <template <typename> class TSerializer, typename TDestination> -size_t serialize(JsonVariantConst source, TDestination& destination) { +size_t serialize(ArduinoJson::JsonVariantConst source, + TDestination& destination) { Writer<TDestination> writer(destination); return doSerialize<TSerializer>(source, writer); } template <template <typename> class TSerializer> typename enable_if<!TSerializer<StaticStringWriter>::producesText, size_t>::type -serialize(JsonVariantConst source, void* buffer, size_t bufferSize) { +serialize(ArduinoJson::JsonVariantConst source, void* buffer, + size_t bufferSize) { StaticStringWriter writer(reinterpret_cast<char*>(buffer), bufferSize); return doSerialize<TSerializer>(source, writer); } template <template <typename> class TSerializer> typename enable_if<TSerializer<StaticStringWriter>::producesText, size_t>::type -serialize(JsonVariantConst source, void* buffer, size_t bufferSize) { +serialize(ArduinoJson::JsonVariantConst source, void* buffer, + size_t bufferSize) { StaticStringWriter writer(reinterpret_cast<char*>(buffer), bufferSize); size_t n = doSerialize<TSerializer>(source, writer); // add null-terminator for text output (not counted in the size) @@ -41,8 +44,8 @@ serialize(JsonVariantConst source, void* buffer, size_t bufferSize) { template <template <typename> class TSerializer, typename TChar, size_t N> typename enable_if<IsChar<TChar>::value, size_t>::type serialize( - JsonVariantConst source, TChar (&buffer)[N]) { + ArduinoJson::JsonVariantConst source, TChar (&buffer)[N]) { return serialize<TSerializer>(source, buffer, N); } -} // namespace ARDUINOJSON_NAMESPACE +ARDUINOJSON_END_PRIVATE_NAMESPACE diff --git a/neosensor/libraries/ArduinoJson/src/ArduinoJson/StringStorage/StringCopier.hpp b/neosensor/libraries/ArduinoJson/src/ArduinoJson/StringStorage/StringCopier.hpp index e9624e5940810b8af43923a4f34c9ec57bf26aeb..bcd34898beef085c948160a9249968a6680ab93d 100644 --- a/neosensor/libraries/ArduinoJson/src/ArduinoJson/StringStorage/StringCopier.hpp +++ b/neosensor/libraries/ArduinoJson/src/ArduinoJson/StringStorage/StringCopier.hpp @@ -1,28 +1,28 @@ // ArduinoJson - https://arduinojson.org -// Copyright © 2014-2022, Benoit BLANCHON +// Copyright © 2014-2023, Benoit BLANCHON // MIT License #pragma once #include <ArduinoJson/Memory/MemoryPool.hpp> -namespace ARDUINOJSON_NAMESPACE { +ARDUINOJSON_BEGIN_PRIVATE_NAMESPACE class StringCopier { public: - StringCopier(MemoryPool* pool) : _pool(pool) {} + StringCopier(MemoryPool* pool) : pool_(pool) {} void startString() { - _pool->getFreeZone(&_ptr, &_capacity); - _size = 0; - if (_capacity == 0) - _pool->markAsOverflowed(); + pool_->getFreeZone(&ptr_, &capacity_); + size_ = 0; + if (capacity_ == 0) + pool_->markAsOverflowed(); } JsonString save() { - ARDUINOJSON_ASSERT(_ptr); - ARDUINOJSON_ASSERT(_size < _capacity); // needs room for the terminator - return JsonString(_pool->saveStringFromFreeZone(_size), _size, + ARDUINOJSON_ASSERT(ptr_); + ARDUINOJSON_ASSERT(size_ < capacity_); // needs room for the terminator + return JsonString(pool_->saveStringFromFreeZone(size_), size_, JsonString::Copied); } @@ -37,35 +37,36 @@ class StringCopier { } void append(char c) { - if (_size + 1 < _capacity) - _ptr[_size++] = c; + if (size_ + 1 < capacity_) + ptr_[size_++] = c; else - _pool->markAsOverflowed(); + pool_->markAsOverflowed(); } bool isValid() const { - return !_pool->overflowed(); + return !pool_->overflowed(); } size_t size() const { - return _size; + return size_; } JsonString str() const { - ARDUINOJSON_ASSERT(_ptr); - ARDUINOJSON_ASSERT(_size < _capacity); - _ptr[_size] = 0; - return JsonString(_ptr, _size, JsonString::Copied); + ARDUINOJSON_ASSERT(ptr_); + ARDUINOJSON_ASSERT(size_ < capacity_); + ptr_[size_] = 0; + return JsonString(ptr_, size_, JsonString::Copied); } private: - MemoryPool* _pool; + MemoryPool* pool_; // These fields aren't initialized by the constructor but startString() // // NOLINTNEXTLINE(clang-analyzer-optin.cplusplus.UninitializedObject) - char* _ptr; + char* ptr_; // NOLINTNEXTLINE(clang-analyzer-optin.cplusplus.UninitializedObject) - size_t _size, _capacity; + size_t size_, capacity_; }; -} // namespace ARDUINOJSON_NAMESPACE + +ARDUINOJSON_END_PRIVATE_NAMESPACE diff --git a/neosensor/libraries/ArduinoJson/src/ArduinoJson/StringStorage/StringMover.hpp b/neosensor/libraries/ArduinoJson/src/ArduinoJson/StringStorage/StringMover.hpp index 688e9e27a3055c408fc109ec8fbd126a7cd87b51..584b25314535a932bb387df437381b580c0c672d 100644 --- a/neosensor/libraries/ArduinoJson/src/ArduinoJson/StringStorage/StringMover.hpp +++ b/neosensor/libraries/ArduinoJson/src/ArduinoJson/StringStorage/StringMover.hpp @@ -1,5 +1,5 @@ // ArduinoJson - https://arduinojson.org -// Copyright © 2014-2022, Benoit BLANCHON +// Copyright © 2014-2023, Benoit BLANCHON // MIT License #pragma once @@ -7,24 +7,24 @@ #include <ArduinoJson/Namespace.hpp> #include <ArduinoJson/Strings/JsonString.hpp> -namespace ARDUINOJSON_NAMESPACE { +ARDUINOJSON_BEGIN_PRIVATE_NAMESPACE class StringMover { public: - StringMover(char* ptr) : _writePtr(ptr) {} + StringMover(char* ptr) : writePtr_(ptr) {} void startString() { - _startPtr = _writePtr; + startPtr_ = writePtr_; } FORCE_INLINE JsonString save() { JsonString s = str(); - _writePtr++; + writePtr_++; return s; } void append(char c) { - *_writePtr++ = c; + *writePtr_++ = c; } bool isValid() const { @@ -32,16 +32,17 @@ class StringMover { } JsonString str() const { - _writePtr[0] = 0; // terminator - return JsonString(_startPtr, size(), JsonString::Linked); + writePtr_[0] = 0; // terminator + return JsonString(startPtr_, size(), JsonString::Linked); } size_t size() const { - return size_t(_writePtr - _startPtr); + return size_t(writePtr_ - startPtr_); } private: - char* _writePtr; - char* _startPtr; + char* writePtr_; + char* startPtr_; }; -} // namespace ARDUINOJSON_NAMESPACE + +ARDUINOJSON_END_PRIVATE_NAMESPACE diff --git a/neosensor/libraries/ArduinoJson/src/ArduinoJson/StringStorage/StringStorage.hpp b/neosensor/libraries/ArduinoJson/src/ArduinoJson/StringStorage/StringStorage.hpp index 8ef034beeb32b920eb771b563c8c18f24034a90d..0b1f77cc8905de284519406473890c2fc821a450 100644 --- a/neosensor/libraries/ArduinoJson/src/ArduinoJson/StringStorage/StringStorage.hpp +++ b/neosensor/libraries/ArduinoJson/src/ArduinoJson/StringStorage/StringStorage.hpp @@ -1,5 +1,5 @@ // ArduinoJson - https://arduinojson.org -// Copyright © 2014-2022, Benoit BLANCHON +// Copyright © 2014-2023, Benoit BLANCHON // MIT License #pragma once @@ -7,7 +7,7 @@ #include <ArduinoJson/StringStorage/StringCopier.hpp> #include <ArduinoJson/StringStorage/StringMover.hpp> -namespace ARDUINOJSON_NAMESPACE { +ARDUINOJSON_BEGIN_PRIVATE_NAMESPACE template <typename TInput> StringCopier makeStringStorage(TInput&, MemoryPool* pool) { @@ -21,4 +21,4 @@ StringMover makeStringStorage( typename enable_if<!is_const<TChar>::value>::type* = 0) { return StringMover(reinterpret_cast<char*>(input)); } -} // namespace ARDUINOJSON_NAMESPACE +ARDUINOJSON_END_PRIVATE_NAMESPACE diff --git a/neosensor/libraries/ArduinoJson/src/ArduinoJson/Strings/Adapters/ArduinoString.hpp b/neosensor/libraries/ArduinoJson/src/ArduinoJson/Strings/Adapters/ArduinoString.hpp deleted file mode 100644 index 13d39181f6842b11b9c1c82678a46d292b9695f6..0000000000000000000000000000000000000000 --- a/neosensor/libraries/ArduinoJson/src/ArduinoJson/Strings/Adapters/ArduinoString.hpp +++ /dev/null @@ -1,25 +0,0 @@ -// ArduinoJson - https://arduinojson.org -// Copyright © 2014-2022, Benoit BLANCHON -// MIT License - -#pragma once - -#include <Arduino.h> - -#include <ArduinoJson/Strings/Adapters/RamString.hpp> -#include <ArduinoJson/Strings/StringAdapter.hpp> - -namespace ARDUINOJSON_NAMESPACE { - -template <typename T> -struct StringAdapter< - T, typename enable_if<is_same<T, ::String>::value || - is_same<T, ::StringSumHelper>::value>::type> { - typedef SizedRamString AdaptedString; - - static AdaptedString adapt(const ::String& s) { - return AdaptedString(s.c_str(), s.length()); - } -}; - -} // namespace ARDUINOJSON_NAMESPACE diff --git a/neosensor/libraries/ArduinoJson/src/ArduinoJson/Strings/Adapters/FlashString.hpp b/neosensor/libraries/ArduinoJson/src/ArduinoJson/Strings/Adapters/FlashString.hpp index ccd07bfa81c4ee0f32eeeb127fcb87952bf21f7c..4989315a2b7f76fc512f99bb8ef9728dfd4449c1 100644 --- a/neosensor/libraries/ArduinoJson/src/ArduinoJson/Strings/Adapters/FlashString.hpp +++ b/neosensor/libraries/ArduinoJson/src/ArduinoJson/Strings/Adapters/FlashString.hpp @@ -1,35 +1,33 @@ // ArduinoJson - https://arduinojson.org -// Copyright © 2014-2022, Benoit BLANCHON +// Copyright © 2014-2023, Benoit BLANCHON // MIT License #pragma once -#include <Arduino.h> - #include <ArduinoJson/Polyfills/pgmspace.hpp> #include <ArduinoJson/Strings/StringAdapter.hpp> -namespace ARDUINOJSON_NAMESPACE { +ARDUINOJSON_BEGIN_PRIVATE_NAMESPACE class FlashString { public: static const size_t typeSortKey = 1; FlashString(const __FlashStringHelper* str, size_t sz) - : _str(reinterpret_cast<const char*>(str)), _size(sz) {} + : str_(reinterpret_cast<const char*>(str)), size_(sz) {} bool isNull() const { - return !_str; + return !str_; } char operator[](size_t i) const { - ARDUINOJSON_ASSERT(_str != 0); - ARDUINOJSON_ASSERT(i <= _size); - return static_cast<char>(pgm_read_byte(_str + i)); + ARDUINOJSON_ASSERT(str_ != 0); + ARDUINOJSON_ASSERT(i <= size_); + return static_cast<char>(pgm_read_byte(str_ + i)); } size_t size() const { - return _size; + return size_; } friend bool stringEquals(FlashString a, SizedRamString b) { @@ -38,7 +36,7 @@ class FlashString { ARDUINOJSON_ASSERT(!b.isNull()); if (a.size() != b.size()) return false; - return ::memcmp_P(b.data(), a._str, a._size) == 0; + return ::memcmp_P(b.data(), a.str_, a.size_) == 0; } friend int stringCompare(FlashString a, SizedRamString b) { @@ -46,7 +44,7 @@ class FlashString { ARDUINOJSON_ASSERT(!a.isNull()); ARDUINOJSON_ASSERT(!b.isNull()); size_t minsize = a.size() < b.size() ? a.size() : b.size(); - int res = ::memcmp_P(b.data(), a._str, minsize); + int res = ::memcmp_P(b.data(), a.str_, minsize); if (res) return -res; if (a.size() < b.size()) @@ -58,7 +56,7 @@ class FlashString { friend void stringGetChars(FlashString s, char* p, size_t n) { ARDUINOJSON_ASSERT(s.size() <= n); - ::memcpy_P(p, s._str, n); + ::memcpy_P(p, s.str_, n); } StringStoragePolicy::Copy storagePolicy() const { @@ -66,8 +64,8 @@ class FlashString { } private: - const char* _str; - size_t _size; + const char* str_; + size_t size_; }; template <> @@ -88,4 +86,4 @@ struct SizedStringAdapter<const __FlashStringHelper*, void> { } }; -} // namespace ARDUINOJSON_NAMESPACE +ARDUINOJSON_END_PRIVATE_NAMESPACE diff --git a/neosensor/libraries/ArduinoJson/src/ArduinoJson/Strings/Adapters/JsonString.hpp b/neosensor/libraries/ArduinoJson/src/ArduinoJson/Strings/Adapters/JsonString.hpp index eb203ba28eba8b52112f5bd8c92a43a58fc7302e..5db7c208d8274513ba59235cf58eadc880b40f44 100644 --- a/neosensor/libraries/ArduinoJson/src/ArduinoJson/Strings/Adapters/JsonString.hpp +++ b/neosensor/libraries/ArduinoJson/src/ArduinoJson/Strings/Adapters/JsonString.hpp @@ -1,5 +1,5 @@ // ArduinoJson - https://arduinojson.org -// Copyright © 2014-2022, Benoit BLANCHON +// Copyright © 2014-2023, Benoit BLANCHON // MIT License #pragma once @@ -8,20 +8,20 @@ #include <ArduinoJson/Strings/JsonString.hpp> #include <ArduinoJson/Strings/StringAdapter.hpp> -namespace ARDUINOJSON_NAMESPACE { +ARDUINOJSON_BEGIN_PRIVATE_NAMESPACE class JsonStringAdapter : public SizedRamString { public: JsonStringAdapter(const JsonString& s) - : SizedRamString(s.c_str(), s.size()), _linked(s.isLinked()) {} + : SizedRamString(s.c_str(), s.size()), linked_(s.isLinked()) {} StringStoragePolicy::LinkOrCopy storagePolicy() const { - StringStoragePolicy::LinkOrCopy policy = {_linked}; + StringStoragePolicy::LinkOrCopy policy = {linked_}; return policy; } private: - bool _linked; + bool linked_; }; template <> @@ -33,4 +33,4 @@ struct StringAdapter<JsonString> { } }; -} // namespace ARDUINOJSON_NAMESPACE +ARDUINOJSON_END_PRIVATE_NAMESPACE diff --git a/neosensor/libraries/ArduinoJson/src/ArduinoJson/Strings/Adapters/RamString.hpp b/neosensor/libraries/ArduinoJson/src/ArduinoJson/Strings/Adapters/RamString.hpp index 164478ef14489179e6ae2c16ad25be7c48aa403c..12c67c94fd86ae733e7a75ca783475c3e31c520f 100644 --- a/neosensor/libraries/ArduinoJson/src/ArduinoJson/Strings/Adapters/RamString.hpp +++ b/neosensor/libraries/ArduinoJson/src/ArduinoJson/Strings/Adapters/RamString.hpp @@ -1,5 +1,5 @@ // ArduinoJson - https://arduinojson.org -// Copyright © 2014-2022, Benoit BLANCHON +// Copyright © 2014-2023, Benoit BLANCHON // MIT License #pragma once @@ -11,7 +11,7 @@ #include <ArduinoJson/Strings/StoragePolicy.hpp> #include <ArduinoJson/Strings/StringAdapter.hpp> -namespace ARDUINOJSON_NAMESPACE { +ARDUINOJSON_BEGIN_PRIVATE_NAMESPACE template <typename T> struct IsChar @@ -21,31 +21,31 @@ class ZeroTerminatedRamString { public: static const size_t typeSortKey = 3; - ZeroTerminatedRamString(const char* str) : _str(str) {} + ZeroTerminatedRamString(const char* str) : str_(str) {} bool isNull() const { - return !_str; + return !str_; } size_t size() const { - return _str ? ::strlen(_str) : 0; + return str_ ? ::strlen(str_) : 0; } char operator[](size_t i) const { - ARDUINOJSON_ASSERT(_str != 0); + ARDUINOJSON_ASSERT(str_ != 0); ARDUINOJSON_ASSERT(i <= size()); - return _str[i]; + return str_[i]; } const char* data() const { - return _str; + return str_; } friend int stringCompare(ZeroTerminatedRamString a, ZeroTerminatedRamString b) { ARDUINOJSON_ASSERT(!a.isNull()); ARDUINOJSON_ASSERT(!b.isNull()); - return ::strcmp(a._str, b._str); + return ::strcmp(a.str_, b.str_); } friend bool stringEquals(ZeroTerminatedRamString a, @@ -58,7 +58,7 @@ class ZeroTerminatedRamString { } protected: - const char* _str; + const char* str_; }; template <typename TChar> @@ -101,24 +101,24 @@ class SizedRamString { public: static const size_t typeSortKey = 2; - SizedRamString(const char* str, size_t sz) : _str(str), _size(sz) {} + SizedRamString(const char* str, size_t sz) : str_(str), size_(sz) {} bool isNull() const { - return !_str; + return !str_; } size_t size() const { - return _size; + return size_; } char operator[](size_t i) const { - ARDUINOJSON_ASSERT(_str != 0); + ARDUINOJSON_ASSERT(str_ != 0); ARDUINOJSON_ASSERT(i <= size()); - return _str[i]; + return str_[i]; } const char* data() const { - return _str; + return str_; } StringStoragePolicy::Copy storagePolicy() const { @@ -126,8 +126,8 @@ class SizedRamString { } protected: - const char* _str; - size_t _size; + const char* str_; + size_t size_; }; template <typename TChar> @@ -140,4 +140,4 @@ struct SizedStringAdapter<TChar*, } }; -} // namespace ARDUINOJSON_NAMESPACE +ARDUINOJSON_END_PRIVATE_NAMESPACE diff --git a/neosensor/libraries/ArduinoJson/src/ArduinoJson/Strings/Adapters/StdString.hpp b/neosensor/libraries/ArduinoJson/src/ArduinoJson/Strings/Adapters/StdString.hpp deleted file mode 100644 index 76f39fa8e187e46f1ce2e846d0135d3f17f730e3..0000000000000000000000000000000000000000 --- a/neosensor/libraries/ArduinoJson/src/ArduinoJson/Strings/Adapters/StdString.hpp +++ /dev/null @@ -1,23 +0,0 @@ -// ArduinoJson - https://arduinojson.org -// Copyright © 2014-2022, Benoit BLANCHON -// MIT License - -#pragma once - -#include <ArduinoJson/Strings/Adapters/RamString.hpp> - -#include <string> - -namespace ARDUINOJSON_NAMESPACE { - -template <typename TCharTraits, typename TAllocator> -struct StringAdapter<std::basic_string<char, TCharTraits, TAllocator>, void> { - typedef SizedRamString AdaptedString; - - static AdaptedString adapt( - const std::basic_string<char, TCharTraits, TAllocator>& s) { - return AdaptedString(s.c_str(), s.size()); - } -}; - -} // namespace ARDUINOJSON_NAMESPACE diff --git a/neosensor/libraries/ArduinoJson/src/ArduinoJson/Strings/Adapters/StringObject.hpp b/neosensor/libraries/ArduinoJson/src/ArduinoJson/Strings/Adapters/StringObject.hpp new file mode 100644 index 0000000000000000000000000000000000000000..d52b0c7fb2084026bcf792b60ad5f8ea8507aff2 --- /dev/null +++ b/neosensor/libraries/ArduinoJson/src/ArduinoJson/Strings/Adapters/StringObject.hpp @@ -0,0 +1,51 @@ +// ArduinoJson - https://arduinojson.org +// Copyright © 2014-2023, Benoit BLANCHON +// MIT License + +#pragma once + +#include <ArduinoJson/Strings/Adapters/RamString.hpp> +#include <ArduinoJson/Strings/StringAdapter.hpp> +#include <ArduinoJson/Strings/StringTraits.hpp> + +ARDUINOJSON_BEGIN_PRIVATE_NAMESPACE + +template <typename T> +struct StringAdapter< + T, + typename enable_if< + (string_traits<T>::has_cstr || string_traits<T>::has_data) && + (string_traits<T>::has_length || string_traits<T>::has_size)>::type> { + typedef SizedRamString AdaptedString; + + static AdaptedString adapt(const T& s) { + return AdaptedString(get_data(s), get_size(s)); + } + + private: + template <typename U> + static typename enable_if<string_traits<U>::has_size, size_t>::type get_size( + const U& s) { + return s.size(); + } + + template <typename U> + static typename enable_if<!string_traits<U>::has_size, size_t>::type get_size( + const U& s) { + return s.length(); + } + + template <typename U> + static typename enable_if<string_traits<U>::has_data, const char*>::type + get_data(const U& s) { + return s.data(); + } + + template <typename U> + static typename enable_if<!string_traits<U>::has_data, const char*>::type + get_data(const U& s) { + return s.c_str(); + } +}; + +ARDUINOJSON_END_PRIVATE_NAMESPACE diff --git a/neosensor/libraries/ArduinoJson/src/ArduinoJson/Strings/Adapters/StringView.hpp b/neosensor/libraries/ArduinoJson/src/ArduinoJson/Strings/Adapters/StringView.hpp deleted file mode 100644 index 543f7658c3bfd46b44a7b8e250db50d6c292787b..0000000000000000000000000000000000000000 --- a/neosensor/libraries/ArduinoJson/src/ArduinoJson/Strings/Adapters/StringView.hpp +++ /dev/null @@ -1,22 +0,0 @@ -// ArduinoJson - https://arduinojson.org -// Copyright © 2014-2022, Benoit BLANCHON -// MIT License - -#pragma once - -#include <ArduinoJson/Strings/Adapters/RamString.hpp> - -#include <string_view> - -namespace ARDUINOJSON_NAMESPACE { - -template <> -struct StringAdapter<std::string_view, void> { - typedef SizedRamString AdaptedString; - - static AdaptedString adapt(const std::string_view& s) { - return AdaptedString(s.data(), s.size()); - } -}; - -} // namespace ARDUINOJSON_NAMESPACE diff --git a/neosensor/libraries/ArduinoJson/src/ArduinoJson/Strings/IsString.hpp b/neosensor/libraries/ArduinoJson/src/ArduinoJson/Strings/IsString.hpp index e674a64e4dee40b6edc2d0f38b1b3e70ca691f96..31e4601dace9551283926e0baf3142aeca195261 100644 --- a/neosensor/libraries/ArduinoJson/src/ArduinoJson/Strings/IsString.hpp +++ b/neosensor/libraries/ArduinoJson/src/ArduinoJson/Strings/IsString.hpp @@ -1,5 +1,5 @@ // ArduinoJson - https://arduinojson.org -// Copyright © 2014-2022, Benoit BLANCHON +// Copyright © 2014-2023, Benoit BLANCHON // MIT License #pragma once @@ -7,7 +7,7 @@ #include <ArduinoJson/Polyfills/type_traits.hpp> #include <ArduinoJson/Strings/StringAdapter.hpp> -namespace ARDUINOJSON_NAMESPACE { +ARDUINOJSON_BEGIN_PRIVATE_NAMESPACE template <typename T, typename Enable = void> struct IsString : false_type {}; @@ -17,4 +17,4 @@ struct IsString< T, typename make_void<typename StringAdapter<T>::AdaptedString>::type> : true_type {}; -} // namespace ARDUINOJSON_NAMESPACE +ARDUINOJSON_END_PRIVATE_NAMESPACE diff --git a/neosensor/libraries/ArduinoJson/src/ArduinoJson/Strings/JsonString.hpp b/neosensor/libraries/ArduinoJson/src/ArduinoJson/Strings/JsonString.hpp index 3c4cc0b4092f1ca8bf642708ce7b84048c2b0e28..538dbc8ad5e04de8577e97858c2ba49bfeba1b58 100644 --- a/neosensor/libraries/ArduinoJson/src/ArduinoJson/Strings/JsonString.hpp +++ b/neosensor/libraries/ArduinoJson/src/ArduinoJson/Strings/JsonString.hpp @@ -1,68 +1,66 @@ // ArduinoJson - https://arduinojson.org -// Copyright © 2014-2022, Benoit BLANCHON +// Copyright © 2014-2023, Benoit BLANCHON // MIT License #pragma once -#include <ArduinoJson/Misc/SafeBoolIdiom.hpp> - #if ARDUINOJSON_ENABLE_STD_STREAM # include <ostream> #endif -namespace ARDUINOJSON_NAMESPACE { +ARDUINOJSON_BEGIN_PUBLIC_NAMESPACE // A string. // https://arduinojson.org/v6/api/jsonstring/ -class JsonString : public SafeBoolIdom<JsonString> { +class JsonString { public: enum Ownership { Copied, Linked }; - JsonString() : _data(0), _size(0), _ownership(Linked) {} + JsonString() : data_(0), size_(0), ownership_(Linked) {} JsonString(const char* data, Ownership ownership = Linked) - : _data(data), _size(data ? ::strlen(data) : 0), _ownership(ownership) {} + : data_(data), size_(data ? ::strlen(data) : 0), ownership_(ownership) {} JsonString(const char* data, size_t sz, Ownership ownership = Linked) - : _data(data), _size(sz), _ownership(ownership) {} + : data_(data), size_(sz), ownership_(ownership) {} // Returns a pointer to the characters. const char* c_str() const { - return _data; + return data_; } // Returns true if the string is null. bool isNull() const { - return !_data; + return !data_; } // Returns true if the string is stored by address. // Returns false if the string is stored by copy. bool isLinked() const { - return _ownership == Linked; + return ownership_ == Linked; } // Returns length of the string. size_t size() const { - return _size; + return size_; } - // safe bool idiom - operator bool_type() const { - return _data ? safe_true() : safe_false(); + // Returns true if the string is non-null + explicit operator bool() const { + return data_ != 0; } // Returns true if strings are equal. friend bool operator==(JsonString lhs, JsonString rhs) { - if (lhs._size != rhs._size) + if (lhs.size_ != rhs.size_) return false; - if (lhs._data == rhs._data) + if (lhs.data_ == rhs.data_) return true; - if (!lhs._data) + if (!lhs.data_) return false; - if (!rhs._data) + if (!rhs.data_) return false; - return memcmp(lhs._data, rhs._data, lhs._size) == 0; + return memcmp(lhs.data_, rhs.data_, lhs.size_) == 0; } // Returns true if strings differs. @@ -78,9 +76,9 @@ class JsonString : public SafeBoolIdom<JsonString> { #endif private: - const char* _data; - size_t _size; - Ownership _ownership; + const char* data_; + size_t size_; + Ownership ownership_; }; -} // namespace ARDUINOJSON_NAMESPACE +ARDUINOJSON_END_PUBLIC_NAMESPACE diff --git a/neosensor/libraries/ArduinoJson/src/ArduinoJson/Strings/StoragePolicy.hpp b/neosensor/libraries/ArduinoJson/src/ArduinoJson/Strings/StoragePolicy.hpp index 8f3d273069cc976021f17f1c4d21a5523c766441..b8b3b6a6cdc30fcc90bedd83e3041a5280ab49fc 100644 --- a/neosensor/libraries/ArduinoJson/src/ArduinoJson/Strings/StoragePolicy.hpp +++ b/neosensor/libraries/ArduinoJson/src/ArduinoJson/Strings/StoragePolicy.hpp @@ -1,10 +1,10 @@ // ArduinoJson - https://arduinojson.org -// Copyright © 2014-2022, Benoit BLANCHON +// Copyright © 2014-2023, Benoit BLANCHON // MIT License #pragma once -namespace ARDUINOJSON_NAMESPACE { +ARDUINOJSON_BEGIN_PRIVATE_NAMESPACE namespace StringStoragePolicy { @@ -15,4 +15,4 @@ struct LinkOrCopy { }; } // namespace StringStoragePolicy -} // namespace ARDUINOJSON_NAMESPACE +ARDUINOJSON_END_PRIVATE_NAMESPACE diff --git a/neosensor/libraries/ArduinoJson/src/ArduinoJson/Strings/StringAdapter.hpp b/neosensor/libraries/ArduinoJson/src/ArduinoJson/Strings/StringAdapter.hpp index 0f19d26013ff7a043675251169595d71b9507004..7ebad0b5295389d9f36cbd9572ef3784319de6ce 100644 --- a/neosensor/libraries/ArduinoJson/src/ArduinoJson/Strings/StringAdapter.hpp +++ b/neosensor/libraries/ArduinoJson/src/ArduinoJson/Strings/StringAdapter.hpp @@ -1,10 +1,10 @@ // ArduinoJson - https://arduinojson.org -// Copyright © 2014-2022, Benoit BLANCHON +// Copyright © 2014-2023, Benoit BLANCHON // MIT License #pragma once -namespace ARDUINOJSON_NAMESPACE { +ARDUINOJSON_BEGIN_PRIVATE_NAMESPACE template <typename TString, typename Enable = void> struct StringAdapter; @@ -28,4 +28,4 @@ typename SizedStringAdapter<TChar*>::AdaptedString adaptString(TChar* p, return SizedStringAdapter<TChar*>::adapt(p, n); } -} // namespace ARDUINOJSON_NAMESPACE +ARDUINOJSON_END_PRIVATE_NAMESPACE diff --git a/neosensor/libraries/ArduinoJson/src/ArduinoJson/Strings/StringAdapters.hpp b/neosensor/libraries/ArduinoJson/src/ArduinoJson/Strings/StringAdapters.hpp index 0be5cd901b21fee26552630d7f8d5ec216ee4e3a..edf881cef65369ffbbe8684164d7d6ec1e723da0 100644 --- a/neosensor/libraries/ArduinoJson/src/ArduinoJson/Strings/StringAdapters.hpp +++ b/neosensor/libraries/ArduinoJson/src/ArduinoJson/Strings/StringAdapters.hpp @@ -1,5 +1,5 @@ // ArduinoJson - https://arduinojson.org -// Copyright © 2014-2022, Benoit BLANCHON +// Copyright © 2014-2023, Benoit BLANCHON // MIT License #pragma once @@ -7,24 +7,13 @@ #include <ArduinoJson/Polyfills/type_traits.hpp> #include <ArduinoJson/Strings/Adapters/JsonString.hpp> #include <ArduinoJson/Strings/Adapters/RamString.hpp> - -#if ARDUINOJSON_ENABLE_STD_STRING -# include <ArduinoJson/Strings/Adapters/StdString.hpp> -#endif - -#if ARDUINOJSON_ENABLE_STRING_VIEW -# include <ArduinoJson/Strings/Adapters/StringView.hpp> -#endif - -#if ARDUINOJSON_ENABLE_ARDUINO_STRING -# include <ArduinoJson/Strings/Adapters/ArduinoString.hpp> -#endif +#include <ArduinoJson/Strings/Adapters/StringObject.hpp> #if ARDUINOJSON_ENABLE_PROGMEM # include <ArduinoJson/Strings/Adapters/FlashString.hpp> #endif -namespace ARDUINOJSON_NAMESPACE { +ARDUINOJSON_BEGIN_PRIVATE_NAMESPACE template <typename TAdaptedString1, typename TAdaptedString2> typename enable_if<TAdaptedString1::typeSortKey <= TAdaptedString2::typeSortKey, @@ -85,4 +74,4 @@ static void stringGetChars(TAdaptedString s, char* p, size_t n) { } } -} // namespace ARDUINOJSON_NAMESPACE +ARDUINOJSON_END_PRIVATE_NAMESPACE diff --git a/neosensor/libraries/ArduinoJson/src/ArduinoJson/Strings/StringTraits.hpp b/neosensor/libraries/ArduinoJson/src/ArduinoJson/Strings/StringTraits.hpp new file mode 100644 index 0000000000000000000000000000000000000000..45804cd15a14649fd931ec4902922564dd03c4d4 --- /dev/null +++ b/neosensor/libraries/ArduinoJson/src/ArduinoJson/Strings/StringTraits.hpp @@ -0,0 +1,79 @@ +// ArduinoJson - https://arduinojson.org +// Copyright © 2014-2023, Benoit BLANCHON +// MIT License + +#pragma once + +#include <ArduinoJson/Strings/Adapters/RamString.hpp> +#include <ArduinoJson/Strings/StringAdapter.hpp> + +ARDUINOJSON_BEGIN_PRIVATE_NAMESPACE + +namespace string_traits_impl { + +// const char* c_str() const +// - String +// - std::string + +template <class T, class = void> +struct has_cstr : false_type {}; + +template <class T> +struct has_cstr<T, + typename enable_if<is_same<decltype(declval<const T>().c_str()), + const char*>::value>::type> + : true_type {}; + +// const char* data() const +// - std::string +// - std::string_view +// - etl::string + +template <class T, class = void> +struct has_data : false_type {}; + +template <class T> +struct has_data<T, + typename enable_if<is_same<decltype(declval<const T>().data()), + const char*>::value>::type> + : true_type {}; + +// size_t length() const +// - String + +template <class T, class = void> +struct has_length : false_type {}; + +template <class T> +struct has_length< + T, typename enable_if< + is_same<decltype(declval<const T>().length()), size_t>::value>::type> + : true_type {}; + +// size_t size() const +// - std::string +// - std::string_view +// - etl::string + +template <class T, class = void> +struct has_size : false_type {}; + +template <class T> +struct has_size< + T, typename enable_if< + is_same<decltype(declval<const T>().size()), size_t>::value>::type> + : true_type {}; + +} // namespace string_traits_impl + +template <typename T> +struct string_traits { + enum { + has_cstr = string_traits_impl::has_cstr<T>::value, + has_length = string_traits_impl::has_length<T>::value, + has_data = string_traits_impl::has_data<T>::value, + has_size = string_traits_impl::has_size<T>::value + }; +}; + +ARDUINOJSON_END_PRIVATE_NAMESPACE diff --git a/neosensor/libraries/ArduinoJson/src/ArduinoJson/Variant/Converter.hpp b/neosensor/libraries/ArduinoJson/src/ArduinoJson/Variant/Converter.hpp index 63604dc98c9d386bde6378028b1272cc8ec05b33..8a63d9969ba4c6972cc0051398d51194cf8f63fd 100644 --- a/neosensor/libraries/ArduinoJson/src/ArduinoJson/Variant/Converter.hpp +++ b/neosensor/libraries/ArduinoJson/src/ArduinoJson/Variant/Converter.hpp @@ -1,16 +1,20 @@ // ArduinoJson - https://arduinojson.org -// Copyright © 2014-2022, Benoit BLANCHON +// Copyright © 2014-2023, Benoit BLANCHON // MIT License #pragma once #include <ArduinoJson/Namespace.hpp> -namespace ARDUINOJSON_NAMESPACE { +ARDUINOJSON_BEGIN_PUBLIC_NAMESPACE template <typename T, typename Enable = void> struct Converter; +ARDUINOJSON_END_PUBLIC_NAMESPACE + +ARDUINOJSON_BEGIN_PRIVATE_NAMESPACE + // clang-format off template <typename T1, typename T2> class InvalidConversion; // Error here? See https://arduinojson.org/v6/invalid-conversion/ @@ -19,4 +23,4 @@ class InvalidConversion; // Error here? See https://arduinojson.org/v6/invalid- template <typename T> struct ConverterNeedsWriteableRef; -} // namespace ARDUINOJSON_NAMESPACE +ARDUINOJSON_END_PRIVATE_NAMESPACE diff --git a/neosensor/libraries/ArduinoJson/src/ArduinoJson/Variant/ConverterImpl.hpp b/neosensor/libraries/ArduinoJson/src/ArduinoJson/Variant/ConverterImpl.hpp index f74bcfee3dc98b4c3dc5938503a76d55ad63f932..e95b33e5d1d3c513860f2f1bdd6adabf875eeae6 100644 --- a/neosensor/libraries/ArduinoJson/src/ArduinoJson/Variant/ConverterImpl.hpp +++ b/neosensor/libraries/ArduinoJson/src/ArduinoJson/Variant/ConverterImpl.hpp @@ -1,5 +1,5 @@ // ArduinoJson - https://arduinojson.org -// Copyright © 2014-2022, Benoit BLANCHON +// Copyright © 2014-2023, Benoit BLANCHON // MIT License #pragma once @@ -8,7 +8,7 @@ #include <ArduinoJson/Variant/JsonVariantConst.hpp> #include <ArduinoJson/Variant/VariantFunctions.hpp> -namespace ARDUINOJSON_NAMESPACE { +ARDUINOJSON_BEGIN_PUBLIC_NAMESPACE template <typename T, typename Enable> struct Converter { @@ -36,11 +36,12 @@ struct Converter { template <typename T> struct Converter< - T, typename enable_if<is_integral<T>::value && !is_same<bool, T>::value && - !is_same<char, T>::value>::type> - : private VariantAttorney { + T, typename detail::enable_if<detail::is_integral<T>::value && + !detail::is_same<bool, T>::value && + !detail::is_same<char, T>::value>::type> + : private detail::VariantAttorney { static void toJson(T src, JsonVariant dst) { - VariantData* data = getData(dst); + auto data = getData(dst); ARDUINOJSON_ASSERT_INTEGER_TYPE_IS_SUPPORTED(T); if (data) data->setInteger(src); @@ -48,119 +49,122 @@ struct Converter< static T fromJson(JsonVariantConst src) { ARDUINOJSON_ASSERT_INTEGER_TYPE_IS_SUPPORTED(T); - const VariantData* data = getData(src); - return data ? data->asIntegral<T>() : T(); + auto data = getData(src); + return data ? data->template asIntegral<T>() : T(); } static bool checkJson(JsonVariantConst src) { - const VariantData* data = getData(src); - return data && data->isInteger<T>(); + auto data = getData(src); + return data && data->template isInteger<T>(); } }; template <typename T> -struct Converter<T, typename enable_if<is_enum<T>::value>::type> - : private VariantAttorney { +struct Converter<T, typename detail::enable_if<detail::is_enum<T>::value>::type> + : private detail::VariantAttorney { static void toJson(T src, JsonVariant dst) { dst.set(static_cast<JsonInteger>(src)); } static T fromJson(JsonVariantConst src) { - const VariantData* data = getData(src); - return data ? static_cast<T>(data->asIntegral<int>()) : T(); + auto data = getData(src); + return data ? static_cast<T>(data->template asIntegral<int>()) : T(); } static bool checkJson(JsonVariantConst src) { - const VariantData* data = getData(src); - return data && data->isInteger<int>(); + auto data = getData(src); + return data && data->template isInteger<int>(); } }; template <> -struct Converter<bool> : private VariantAttorney { +struct Converter<bool> : private detail::VariantAttorney { static void toJson(bool src, JsonVariant dst) { - VariantData* data = getData(dst); + auto data = getData(dst); if (data) data->setBoolean(src); } static bool fromJson(JsonVariantConst src) { - const VariantData* data = getData(src); + auto data = getData(src); return data ? data->asBoolean() : false; } static bool checkJson(JsonVariantConst src) { - const VariantData* data = getData(src); + auto data = getData(src); return data && data->isBoolean(); } }; template <typename T> -struct Converter<T, typename enable_if<is_floating_point<T>::value>::type> - : private VariantAttorney { +struct Converter< + T, typename detail::enable_if<detail::is_floating_point<T>::value>::type> + : private detail::VariantAttorney { static void toJson(T src, JsonVariant dst) { - VariantData* data = getData(dst); + auto data = getData(dst); if (data) data->setFloat(static_cast<JsonFloat>(src)); } static T fromJson(JsonVariantConst src) { - const VariantData* data = getData(src); - return data ? data->asFloat<T>() : 0; + auto data = getData(src); + return data ? data->template asFloat<T>() : 0; } static bool checkJson(JsonVariantConst src) { - const VariantData* data = getData(src); + auto data = getData(src); return data && data->isFloat(); } }; template <> -struct Converter<const char*> : private VariantAttorney { +struct Converter<const char*> : private detail::VariantAttorney { static void toJson(const char* src, JsonVariant dst) { - variantSetString(getData(dst), adaptString(src), getPool(dst)); + variantSetString(getData(dst), detail::adaptString(src), getPool(dst)); } static const char* fromJson(JsonVariantConst src) { - const VariantData* data = getData(src); + auto data = getData(src); return data ? data->asString().c_str() : 0; } static bool checkJson(JsonVariantConst src) { - const VariantData* data = getData(src); + auto data = getData(src); return data && data->isString(); } }; template <> -struct Converter<JsonString> : private VariantAttorney { +struct Converter<JsonString> : private detail::VariantAttorney { static void toJson(JsonString src, JsonVariant dst) { - variantSetString(getData(dst), adaptString(src), getPool(dst)); + variantSetString(getData(dst), detail::adaptString(src), getPool(dst)); } static JsonString fromJson(JsonVariantConst src) { - const VariantData* data = getData(src); + auto data = getData(src); return data ? data->asString() : 0; } static bool checkJson(JsonVariantConst src) { - const VariantData* data = getData(src); + auto data = getData(src); return data && data->isString(); } }; template <typename T> -inline typename enable_if<IsString<T>::value, bool>::type convertToJson( - const T& src, JsonVariant dst) { - VariantData* data = VariantAttorney::getData(dst); - MemoryPool* pool = VariantAttorney::getPool(dst); +inline typename detail::enable_if<detail::IsString<T>::value, bool>::type +convertToJson(const T& src, JsonVariant dst) { + using namespace detail; + auto data = VariantAttorney::getData(dst); + auto pool = VariantAttorney::getPool(dst); return variantSetString(data, adaptString(src), pool); } template <> -struct Converter<SerializedValue<const char*> > { +struct Converter<SerializedValue<const char*>> + : private detail::VariantAttorney { static void toJson(SerializedValue<const char*> src, JsonVariant dst) { - VariantData* data = VariantAttorney::getData(dst); + auto data = getData(dst); if (data) data->setLinkedRaw(src); } @@ -170,21 +174,20 @@ struct Converter<SerializedValue<const char*> > { // SerializedValue<String> // SerializedValue<const __FlashStringHelper*> template <typename T> -struct Converter<SerializedValue<T>, - typename enable_if<!is_same<const char*, T>::value>::type> - : private VariantAttorney { +struct Converter< + SerializedValue<T>, + typename detail::enable_if<!detail::is_same<const char*, T>::value>::type> + : private detail::VariantAttorney { static void toJson(SerializedValue<T> src, JsonVariant dst) { - VariantData* data = getData(dst); - MemoryPool* pool = getPool(dst); + auto data = getData(dst); + auto pool = getPool(dst); if (data) data->storeOwnedRaw(src, pool); } }; -#if ARDUINOJSON_HAS_NULLPTR - template <> -struct Converter<decltype(nullptr)> : private VariantAttorney { +struct Converter<decltype(nullptr)> : private detail::VariantAttorney { static void toJson(decltype(nullptr), JsonVariant dst) { variantSetNull(getData(dst)); } @@ -192,62 +195,62 @@ struct Converter<decltype(nullptr)> : private VariantAttorney { return nullptr; } static bool checkJson(JsonVariantConst src) { - const VariantData* data = getData(src); + auto data = getData(src); return data == 0 || data->isNull(); } }; -#endif - #if ARDUINOJSON_ENABLE_ARDUINO_STREAM +namespace detail { class MemoryPoolPrint : public Print { public: - MemoryPoolPrint(MemoryPool* pool) : _pool(pool), _size(0) { - pool->getFreeZone(&_string, &_capacity); + MemoryPoolPrint(MemoryPool* pool) : pool_(pool), size_(0) { + pool->getFreeZone(&string_, &capacity_); } JsonString str() { - ARDUINOJSON_ASSERT(_size < _capacity); - return JsonString(_pool->saveStringFromFreeZone(_size), _size, + ARDUINOJSON_ASSERT(size_ < capacity_); + return JsonString(pool_->saveStringFromFreeZone(size_), size_, JsonString::Copied); } size_t write(uint8_t c) { - if (_size >= _capacity) + if (size_ >= capacity_) return 0; - _string[_size++] = char(c); + string_[size_++] = char(c); return 1; } size_t write(const uint8_t* buffer, size_t size) { - if (_size + size >= _capacity) { - _size = _capacity; // mark as overflowed + if (size_ + size >= capacity_) { + size_ = capacity_; // mark as overflowed return 0; } - memcpy(&_string[_size], buffer, size); - _size += size; + memcpy(&string_[size_], buffer, size); + size_ += size; return size; } bool overflowed() const { - return _size >= _capacity; + return size_ >= capacity_; } private: - MemoryPool* _pool; - size_t _size; - char* _string; - size_t _capacity; + MemoryPool* pool_; + size_t size_; + char* string_; + size_t capacity_; }; +} // namespace detail inline void convertToJson(const ::Printable& src, JsonVariant dst) { - MemoryPool* pool = VariantAttorney::getPool(dst); - VariantData* data = VariantAttorney::getData(dst); + auto pool = detail::VariantAttorney::getPool(dst); + auto data = detail::VariantAttorney::getData(dst); if (!pool || !data) return; - MemoryPoolPrint print(pool); + detail::MemoryPoolPrint print(pool); src.printTo(print); if (print.overflowed()) { pool->markAsOverflowed(); @@ -305,15 +308,17 @@ inline bool canConvertFromJson(JsonVariantConst src, const std::string_view&) { #endif +namespace detail { template <typename T> struct ConverterNeedsWriteableRef { protected: // <- to avoid GCC's "all member functions in class are private" - static int probe(T (*f)(JsonVariant)); - static char probe(T (*f)(JsonVariantConst)); + static int probe(T (*f)(ArduinoJson::JsonVariant)); + static char probe(T (*f)(ArduinoJson::JsonVariantConst)); public: static const bool value = sizeof(probe(Converter<T>::fromJson)) == sizeof(int); }; +} // namespace detail -} // namespace ARDUINOJSON_NAMESPACE +ARDUINOJSON_END_PUBLIC_NAMESPACE diff --git a/neosensor/libraries/ArduinoJson/src/ArduinoJson/Variant/JsonVariant.hpp b/neosensor/libraries/ArduinoJson/src/ArduinoJson/Variant/JsonVariant.hpp index 95ac56e32c647b909e728da49c89108e122abc4d..d1f122e9c9bb8ee3c1c5e238ec45971dded0fe74 100644 --- a/neosensor/libraries/ArduinoJson/src/ArduinoJson/Variant/JsonVariant.hpp +++ b/neosensor/libraries/ArduinoJson/src/ArduinoJson/Variant/JsonVariant.hpp @@ -1,58 +1,59 @@ // ArduinoJson - https://arduinojson.org -// Copyright © 2014-2022, Benoit BLANCHON +// Copyright © 2014-2023, Benoit BLANCHON // MIT License #pragma once #include <ArduinoJson/Variant/VariantRefBase.hpp> -namespace ARDUINOJSON_NAMESPACE { +ARDUINOJSON_BEGIN_PUBLIC_NAMESPACE // A reference to a value in a JsonDocument. // https://arduinojson.org/v6/api/jsonvariant/ -class JsonVariant : public VariantRefBase<JsonVariant>, - public VariantOperators<JsonVariant> { - friend class VariantAttorney; +class JsonVariant : public detail::VariantRefBase<JsonVariant>, + public detail::VariantOperators<JsonVariant> { + friend class detail::VariantAttorney; public: // Creates an unbound reference. - JsonVariant() : _data(0), _pool(0) {} + JsonVariant() : data_(0), pool_(0) {} // INTERNAL USE ONLY - JsonVariant(MemoryPool* pool, VariantData* data) : _data(data), _pool(pool) {} + JsonVariant(detail::MemoryPool* pool, detail::VariantData* data) + : data_(data), pool_(pool) {} private: - FORCE_INLINE MemoryPool* getPool() const { - return _pool; + FORCE_INLINE detail::MemoryPool* getPool() const { + return pool_; } - FORCE_INLINE VariantData* getData() const { - return _data; + FORCE_INLINE detail::VariantData* getData() const { + return data_; } - FORCE_INLINE VariantData* getOrCreateData() const { - return _data; + FORCE_INLINE detail::VariantData* getOrCreateData() const { + return data_; } - VariantData* _data; - MemoryPool* _pool; + detail::VariantData* data_; + detail::MemoryPool* pool_; }; template <> -struct Converter<JsonVariant> : private VariantAttorney { +struct Converter<JsonVariant> : private detail::VariantAttorney { static void toJson(JsonVariant src, JsonVariant dst) { - variantCopyFrom(getData(dst), getData(src), getPool(dst)); + detail::variantCopyFrom(getData(dst), getData(src), getPool(dst)); } static JsonVariant fromJson(JsonVariant src) { return src; } - static InvalidConversion<JsonVariantConst, JsonVariant> fromJson( + static detail::InvalidConversion<JsonVariantConst, JsonVariant> fromJson( JsonVariantConst); static bool checkJson(JsonVariant src) { - VariantData* data = getData(src); + auto data = getData(src); return !!data; } @@ -62,7 +63,7 @@ struct Converter<JsonVariant> : private VariantAttorney { }; template <> -struct Converter<JsonVariantConst> : private VariantAttorney { +struct Converter<JsonVariantConst> : private detail::VariantAttorney { static void toJson(JsonVariantConst src, JsonVariant dst) { variantCopyFrom(getData(dst), getData(src), getPool(dst)); } @@ -72,9 +73,9 @@ struct Converter<JsonVariantConst> : private VariantAttorney { } static bool checkJson(JsonVariantConst src) { - const VariantData* data = getData(src); + auto data = getData(src); return !!data; } }; -} // namespace ARDUINOJSON_NAMESPACE +ARDUINOJSON_END_PUBLIC_NAMESPACE diff --git a/neosensor/libraries/ArduinoJson/src/ArduinoJson/Variant/JsonVariantConst.hpp b/neosensor/libraries/ArduinoJson/src/ArduinoJson/Variant/JsonVariantConst.hpp index c15202e0a13286ca2e57c24e0f885ff85dde5791..606df0833302d5ffd38c8dbe3c00c02c50713936 100644 --- a/neosensor/libraries/ArduinoJson/src/ArduinoJson/Variant/JsonVariantConst.hpp +++ b/neosensor/libraries/ArduinoJson/src/ArduinoJson/Variant/JsonVariantConst.hpp @@ -1,5 +1,5 @@ // ArduinoJson - https://arduinojson.org -// Copyright © 2014-2022, Benoit BLANCHON +// Copyright © 2014-2023, Benoit BLANCHON // MIT License #pragma once @@ -16,7 +16,7 @@ #include <ArduinoJson/Variant/VariantOperators.hpp> #include <ArduinoJson/Variant/VariantTag.hpp> -namespace ARDUINOJSON_NAMESPACE { +ARDUINOJSON_BEGIN_PUBLIC_NAMESPACE // Forward declarations. class JsonArray; @@ -24,63 +24,64 @@ class JsonObject; // A read-only reference to a value in a JsonDocument // https://arduinojson.org/v6/api/jsonarrayconst/ -class JsonVariantConst : public VariantTag, - public VariantOperators<JsonVariantConst> { - friend class VariantAttorney; +class JsonVariantConst : public detail::VariantTag, + public detail::VariantOperators<JsonVariantConst> { + friend class detail::VariantAttorney; public: // Creates an unbound reference. - JsonVariantConst() : _data(0) {} + JsonVariantConst() : data_(0) {} // INTERNAL USE ONLY - explicit JsonVariantConst(const VariantData* data) : _data(data) {} + explicit JsonVariantConst(const detail::VariantData* data) : data_(data) {} // Returns true if the value is null or the reference is unbound. // https://arduinojson.org/v6/api/jsonvariantconst/isnull/ FORCE_INLINE bool isNull() const { - return variantIsNull(_data); + using namespace detail; + return variantIsNull(data_); } // Returns true if the reference is unbound. FORCE_INLINE bool isUnbound() const { - return !_data; + return !data_; } // Returns the number of bytes occupied by the value. // https://arduinojson.org/v6/api/jsonvariantconst/memoryusage/ FORCE_INLINE size_t memoryUsage() const { - return _data ? _data->memoryUsage() : 0; + return data_ ? data_->memoryUsage() : 0; } // Returns the depth (nesting level) of the value. // https://arduinojson.org/v6/api/jsonvariantconst/nesting/ FORCE_INLINE size_t nesting() const { - return variantNesting(_data); + return variantNesting(data_); } // Returns the size of the array or object. // https://arduinojson.org/v6/api/jsonvariantconst/size/ size_t size() const { - return variantSize(_data); + return variantSize(data_); } // Casts the value to the specified type. // https://arduinojson.org/v6/api/jsonvariantconst/as/ template <typename T> - FORCE_INLINE - typename enable_if<!is_same<T, char*>::value && !is_same<T, char>::value, - T>::type - as() const { + FORCE_INLINE typename detail::enable_if<!detail::is_same<T, char*>::value && + !detail::is_same<T, char>::value, + T>::type + as() const { return Converter<T>::fromJson(*this); } // Returns true if the value is of the specified type. // https://arduinojson.org/v6/api/jsonvariantconst/is/ template <typename T> - FORCE_INLINE - typename enable_if<!is_same<T, char*>::value && !is_same<T, char>::value, - bool>::type - is() const { + FORCE_INLINE typename detail::enable_if<!detail::is_same<T, char*>::value && + !detail::is_same<T, char>::value, + bool>::type + is() const { return Converter<T>::checkJson(*this); } @@ -92,50 +93,52 @@ class JsonVariantConst : public VariantTag, // Gets array's element at specified index. // https://arduinojson.org/v6/api/jsonvariantconst/subscript/ FORCE_INLINE JsonVariantConst operator[](size_t index) const { - return JsonVariantConst(variantGetElement(_data, index)); + return JsonVariantConst(variantGetElement(data_, index)); } // Gets object's member with specified key. // https://arduinojson.org/v6/api/jsonvariantconst/subscript/ template <typename TString> - FORCE_INLINE - typename enable_if<IsString<TString>::value, JsonVariantConst>::type - operator[](const TString& key) const { - return JsonVariantConst(variantGetMember(_data, adaptString(key))); + FORCE_INLINE typename detail::enable_if<detail::IsString<TString>::value, + JsonVariantConst>::type + operator[](const TString& key) const { + return JsonVariantConst(variantGetMember(data_, detail::adaptString(key))); } // Gets object's member with specified key. // https://arduinojson.org/v6/api/jsonvariantconst/subscript/ template <typename TChar> - FORCE_INLINE - typename enable_if<IsString<TChar*>::value, JsonVariantConst>::type - operator[](TChar* key) const { - return JsonVariantConst(variantGetMember(_data, adaptString(key))); + FORCE_INLINE typename detail::enable_if<detail::IsString<TChar*>::value, + JsonVariantConst>::type + operator[](TChar* key) const { + return JsonVariantConst(variantGetMember(data_, detail::adaptString(key))); } // Returns true if tge object contains the specified key. // https://arduinojson.org/v6/api/jsonvariantconst/containskey/ template <typename TString> - FORCE_INLINE typename enable_if<IsString<TString>::value, bool>::type - containsKey(const TString& key) const { - return variantGetMember(getData(), adaptString(key)) != 0; + FORCE_INLINE + typename detail::enable_if<detail::IsString<TString>::value, bool>::type + containsKey(const TString& key) const { + return variantGetMember(getData(), detail::adaptString(key)) != 0; } // Returns true if tge object contains the specified key. // https://arduinojson.org/v6/api/jsonvariantconst/containskey/ template <typename TChar> - FORCE_INLINE typename enable_if<IsString<TChar*>::value, bool>::type - containsKey(TChar* key) const { - return variantGetMember(getData(), adaptString(key)) != 0; + FORCE_INLINE + typename detail::enable_if<detail::IsString<TChar*>::value, bool>::type + containsKey(TChar* key) const { + return variantGetMember(getData(), detail::adaptString(key)) != 0; } protected: - const VariantData* getData() const { - return _data; + const detail::VariantData* getData() const { + return data_; } private: - const VariantData* _data; + const detail::VariantData* data_; }; -} // namespace ARDUINOJSON_NAMESPACE +ARDUINOJSON_END_PUBLIC_NAMESPACE diff --git a/neosensor/libraries/ArduinoJson/src/ArduinoJson/Variant/SlotFunctions.hpp b/neosensor/libraries/ArduinoJson/src/ArduinoJson/Variant/SlotFunctions.hpp index 1b5b5228ef4a53a59c104825e00a95a1803a92d5..8fee77f2db81b58e3939ccb7aca995f467f9209d 100644 --- a/neosensor/libraries/ArduinoJson/src/ArduinoJson/Variant/SlotFunctions.hpp +++ b/neosensor/libraries/ArduinoJson/src/ArduinoJson/Variant/SlotFunctions.hpp @@ -1,5 +1,5 @@ // ArduinoJson - https://arduinojson.org -// Copyright © 2014-2022, Benoit BLANCHON +// Copyright © 2014-2023, Benoit BLANCHON // MIT License #pragma once @@ -7,20 +7,20 @@ #include <ArduinoJson/Polyfills/assert.hpp> #include <ArduinoJson/Variant/VariantData.hpp> -namespace ARDUINOJSON_NAMESPACE { +ARDUINOJSON_BEGIN_PRIVATE_NAMESPACE struct SlotKeySetter { - SlotKeySetter(VariantSlot* instance) : _instance(instance) {} + SlotKeySetter(VariantSlot* instance) : instance_(instance) {} template <typename TStoredString> void operator()(TStoredString s) { if (!s) return; - ARDUINOJSON_ASSERT(_instance != 0); - _instance->setKey(s); + ARDUINOJSON_ASSERT(instance_ != 0); + instance_->setKey(s); } - VariantSlot* _instance; + VariantSlot* instance_; }; template <typename TAdaptedString> @@ -42,4 +42,4 @@ inline size_t slotSize(const VariantSlot* var) { inline VariantData* slotData(VariantSlot* slot) { return reinterpret_cast<VariantData*>(slot); } -} // namespace ARDUINOJSON_NAMESPACE +ARDUINOJSON_END_PRIVATE_NAMESPACE diff --git a/neosensor/libraries/ArduinoJson/src/ArduinoJson/Variant/VariantAttorney.hpp b/neosensor/libraries/ArduinoJson/src/ArduinoJson/Variant/VariantAttorney.hpp index ee4f171310e96af841c952bd6360ec0cee5d0b5d..a2f6815f6abfc862d45c580db653f15a958e7766 100644 --- a/neosensor/libraries/ArduinoJson/src/ArduinoJson/Variant/VariantAttorney.hpp +++ b/neosensor/libraries/ArduinoJson/src/ArduinoJson/Variant/VariantAttorney.hpp @@ -1,5 +1,5 @@ // ArduinoJson - https://arduinojson.org -// Copyright © 2014-2022, Benoit BLANCHON +// Copyright © 2014-2023, Benoit BLANCHON // MIT License #pragma once @@ -9,7 +9,7 @@ #include <ArduinoJson/Variant/VariantTo.hpp> #include "JsonVariantConst.hpp" -namespace ARDUINOJSON_NAMESPACE { +ARDUINOJSON_BEGIN_PRIVATE_NAMESPACE // Grants access to the internal variant API class VariantAttorney { @@ -45,4 +45,4 @@ class VariantAttorney { } }; -} // namespace ARDUINOJSON_NAMESPACE +ARDUINOJSON_END_PRIVATE_NAMESPACE diff --git a/neosensor/libraries/ArduinoJson/src/ArduinoJson/Variant/VariantCompare.hpp b/neosensor/libraries/ArduinoJson/src/ArduinoJson/Variant/VariantCompare.hpp index b6e7ea8c99104194ff48855cf8b0c46613bdc045..42445c6b99a8a1a8222b2e394760de184fd5d327 100644 --- a/neosensor/libraries/ArduinoJson/src/ArduinoJson/Variant/VariantCompare.hpp +++ b/neosensor/libraries/ArduinoJson/src/ArduinoJson/Variant/VariantCompare.hpp @@ -1,5 +1,5 @@ // ArduinoJson - https://arduinojson.org -// Copyright © 2014-2022, Benoit BLANCHON +// Copyright © 2014-2023, Benoit BLANCHON // MIT License #pragma once @@ -10,7 +10,7 @@ #include <ArduinoJson/Strings/StringAdapters.hpp> #include <ArduinoJson/Variant/Visitor.hpp> -namespace ARDUINOJSON_NAMESPACE { +ARDUINOJSON_BEGIN_PRIVATE_NAMESPACE class CollectionData; @@ -75,20 +75,18 @@ struct NullComparer : ComparerBase { } }; -#if ARDUINOJSON_HAS_NULLPTR template <> struct Comparer<decltype(nullptr), void> : NullComparer { explicit Comparer(decltype(nullptr)) : NullComparer() {} }; -#endif struct ArrayComparer : ComparerBase { - const CollectionData* _rhs; + const CollectionData* rhs_; - explicit ArrayComparer(const CollectionData& rhs) : _rhs(&rhs) {} + explicit ArrayComparer(const CollectionData& rhs) : rhs_(&rhs) {} CompareResult visitArray(const CollectionData& lhs) { - if (JsonArrayConst(&lhs) == JsonArrayConst(_rhs)) + if (JsonArrayConst(&lhs) == JsonArrayConst(rhs_)) return COMPARE_RESULT_EQUAL; else return COMPARE_RESULT_DIFFER; @@ -96,12 +94,12 @@ struct ArrayComparer : ComparerBase { }; struct ObjectComparer : ComparerBase { - const CollectionData* _rhs; + const CollectionData* rhs_; - explicit ObjectComparer(const CollectionData& rhs) : _rhs(&rhs) {} + explicit ObjectComparer(const CollectionData& rhs) : rhs_(&rhs) {} CompareResult visitObject(const CollectionData& lhs) { - if (JsonObjectConst(&lhs) == JsonObjectConst(_rhs)) + if (JsonObjectConst(&lhs) == JsonObjectConst(rhs_)) return COMPARE_RESULT_EQUAL; else return COMPARE_RESULT_DIFFER; @@ -109,15 +107,15 @@ struct ObjectComparer : ComparerBase { }; struct RawComparer : ComparerBase { - const char* _rhsData; - size_t _rhsSize; + const char* rhsData_; + size_t rhsSize_; explicit RawComparer(const char* rhsData, size_t rhsSize) - : _rhsData(rhsData), _rhsSize(rhsSize) {} + : rhsData_(rhsData), rhsSize_(rhsSize) {} CompareResult visitRawJson(const char* lhsData, size_t lhsSize) { - size_t size = _rhsSize < lhsSize ? _rhsSize : lhsSize; - int n = memcmp(lhsData, _rhsData, size); + size_t size = rhsSize_ < lhsSize ? rhsSize_ : lhsSize; + int n = memcmp(lhsData, rhsData_, size); if (n < 0) return COMPARE_RESULT_LESS; else if (n > 0) @@ -193,17 +191,17 @@ struct VariantComparer : ComparerBase { }; template <typename T> -struct Comparer< - T, typename enable_if<is_convertible<T, JsonVariantConst>::value>::type> +struct Comparer<T, typename enable_if<is_convertible< + T, ArduinoJson::JsonVariantConst>::value>::type> : VariantComparer { explicit Comparer(const T& value) : VariantComparer(VariantAttorney::getData(value)) {} }; template <typename T> -CompareResult compare(JsonVariantConst lhs, const T& rhs) { +CompareResult compare(ArduinoJson::JsonVariantConst lhs, const T& rhs) { Comparer<T> comparer(rhs); return variantAccept(VariantAttorney::getData(lhs), comparer); } -} // namespace ARDUINOJSON_NAMESPACE +ARDUINOJSON_END_PRIVATE_NAMESPACE diff --git a/neosensor/libraries/ArduinoJson/src/ArduinoJson/Variant/VariantContent.hpp b/neosensor/libraries/ArduinoJson/src/ArduinoJson/Variant/VariantContent.hpp index e904b33719accdacdff929fc0cc04ad02c3cbcb3..22239019b1406d7762faddd7cd65ee120b253279 100644 --- a/neosensor/libraries/ArduinoJson/src/ArduinoJson/Variant/VariantContent.hpp +++ b/neosensor/libraries/ArduinoJson/src/ArduinoJson/Variant/VariantContent.hpp @@ -1,5 +1,5 @@ // ArduinoJson - https://arduinojson.org -// Copyright © 2014-2022, Benoit BLANCHON +// Copyright © 2014-2023, Benoit BLANCHON // MIT License #pragma once @@ -10,7 +10,7 @@ #include <ArduinoJson/Numbers/JsonFloat.hpp> #include <ArduinoJson/Numbers/JsonInteger.hpp> -namespace ARDUINOJSON_NAMESPACE { +ARDUINOJSON_BEGIN_PRIVATE_NAMESPACE enum { VALUE_MASK = 0x7F, @@ -54,4 +54,5 @@ union VariantContent { size_t size; } asString; }; -} // namespace ARDUINOJSON_NAMESPACE + +ARDUINOJSON_END_PRIVATE_NAMESPACE diff --git a/neosensor/libraries/ArduinoJson/src/ArduinoJson/Variant/VariantData.hpp b/neosensor/libraries/ArduinoJson/src/ArduinoJson/Variant/VariantData.hpp index d086accc11a975c122a0bc43775c8979b83aa8ef..7ef218c00c5baac5c33f042fd3f77486d2d037d5 100644 --- a/neosensor/libraries/ArduinoJson/src/ArduinoJson/Variant/VariantData.hpp +++ b/neosensor/libraries/ArduinoJson/src/ArduinoJson/Variant/VariantData.hpp @@ -1,5 +1,5 @@ // ArduinoJson - https://arduinojson.org -// Copyright © 2014-2022, Benoit BLANCHON +// Copyright © 2014-2023, Benoit BLANCHON // MIT License #pragma once @@ -11,67 +11,50 @@ #include <ArduinoJson/Strings/StringAdapters.hpp> #include <ArduinoJson/Variant/VariantContent.hpp> -// VariantData can't have a constructor (to be a POD), so we have no way to fix -// this warning -#if defined(__GNUC__) -# if __GNUC__ >= 7 -# pragma GCC diagnostic push -# pragma GCC diagnostic ignored "-Wmaybe-uninitialized" -# pragma GCC diagnostic ignored "-Wuninitialized" -# endif -#endif - -namespace ARDUINOJSON_NAMESPACE { +ARDUINOJSON_BEGIN_PRIVATE_NAMESPACE class VariantData { - VariantContent _content; // must be first to allow cast from array to variant - uint8_t _flags; + VariantContent content_; // must be first to allow cast from array to variant + uint8_t flags_; public: - // Must be a POD! - // - no constructor - // - no destructor - // - no virtual - // - no inheritance - void init() { - _flags = VALUE_IS_NULL; - } + VariantData() : flags_(VALUE_IS_NULL) {} void operator=(const VariantData& src) { - _content = src._content; - _flags = uint8_t((_flags & OWNED_KEY_BIT) | (src._flags & ~OWNED_KEY_BIT)); + content_ = src.content_; + flags_ = uint8_t((flags_ & OWNED_KEY_BIT) | (src.flags_ & ~OWNED_KEY_BIT)); } template <typename TVisitor> typename TVisitor::result_type accept(TVisitor& visitor) const { switch (type()) { case VALUE_IS_FLOAT: - return visitor.visitFloat(_content.asFloat); + return visitor.visitFloat(content_.asFloat); case VALUE_IS_ARRAY: - return visitor.visitArray(_content.asCollection); + return visitor.visitArray(content_.asCollection); case VALUE_IS_OBJECT: - return visitor.visitObject(_content.asCollection); + return visitor.visitObject(content_.asCollection); case VALUE_IS_LINKED_STRING: case VALUE_IS_OWNED_STRING: - return visitor.visitString(_content.asString.data, - _content.asString.size); + return visitor.visitString(content_.asString.data, + content_.asString.size); case VALUE_IS_OWNED_RAW: case VALUE_IS_LINKED_RAW: - return visitor.visitRawJson(_content.asString.data, - _content.asString.size); + return visitor.visitRawJson(content_.asString.data, + content_.asString.size); case VALUE_IS_SIGNED_INTEGER: - return visitor.visitSignedInteger(_content.asSignedInteger); + return visitor.visitSignedInteger(content_.asSignedInteger); case VALUE_IS_UNSIGNED_INTEGER: - return visitor.visitUnsignedInteger(_content.asUnsignedInteger); + return visitor.visitUnsignedInteger(content_.asUnsignedInteger); case VALUE_IS_BOOLEAN: - return visitor.visitBoolean(_content.asBoolean != 0); + return visitor.visitBoolean(content_.asBoolean != 0); default: return visitor.visitNull(); @@ -89,7 +72,7 @@ class VariantData { bool asBoolean() const; CollectionData* asArray() { - return isArray() ? &_content.asCollection : 0; + return isArray() ? &content_.asCollection : 0; } const CollectionData* asArray() const { @@ -97,11 +80,11 @@ class VariantData { } const CollectionData* asCollection() const { - return isCollection() ? &_content.asCollection : 0; + return isCollection() ? &content_.asCollection : 0; } CollectionData* asObject() { - return isObject() ? &_content.asCollection : 0; + return isObject() ? &content_.asCollection : 0; } const CollectionData* asObject() const { @@ -111,7 +94,7 @@ class VariantData { bool copyFrom(const VariantData& src, MemoryPool* pool); bool isArray() const { - return (_flags & VALUE_IS_ARRAY) != 0; + return (flags_ & VALUE_IS_ARRAY) != 0; } bool isBoolean() const { @@ -119,17 +102,17 @@ class VariantData { } bool isCollection() const { - return (_flags & COLLECTION_MASK) != 0; + return (flags_ & COLLECTION_MASK) != 0; } template <typename T> bool isInteger() const { switch (type()) { case VALUE_IS_UNSIGNED_INTEGER: - return canConvertNumber<T>(_content.asUnsignedInteger); + return canConvertNumber<T>(content_.asUnsignedInteger); case VALUE_IS_SIGNED_INTEGER: - return canConvertNumber<T>(_content.asSignedInteger); + return canConvertNumber<T>(content_.asSignedInteger); default: return false; @@ -137,7 +120,7 @@ class VariantData { } bool isFloat() const { - return (_flags & NUMBER_BIT) != 0; + return (flags_ & NUMBER_BIT) != 0; } bool isString() const { @@ -145,7 +128,7 @@ class VariantData { } bool isObject() const { - return (_flags & VALUE_IS_OBJECT) != 0; + return (flags_ & VALUE_IS_OBJECT) != 0; } bool isNull() const { @@ -158,30 +141,30 @@ class VariantData { void remove(size_t index) { if (isArray()) - _content.asCollection.removeElement(index); + content_.asCollection.removeElement(index); } template <typename TAdaptedString> void remove(TAdaptedString key) { if (isObject()) - _content.asCollection.removeMember(key); + content_.asCollection.removeMember(key); } void setBoolean(bool value) { setType(VALUE_IS_BOOLEAN); - _content.asBoolean = value; + content_.asBoolean = value; } void setFloat(JsonFloat value) { setType(VALUE_IS_FLOAT); - _content.asFloat = value; + content_.asFloat = value; } void setLinkedRaw(SerializedValue<const char*> value) { if (value.data()) { setType(VALUE_IS_LINKED_RAW); - _content.asString.data = value.data(); - _content.asString.size = value.size(); + content_.asString.data = value.data(); + content_.asString.size = value.size(); } else { setType(VALUE_IS_NULL); } @@ -192,8 +175,8 @@ class VariantData { const char* dup = pool->saveString(adaptString(value.data(), value.size())); if (dup) { setType(VALUE_IS_OWNED_RAW); - _content.asString.data = dup; - _content.asString.size = value.size(); + content_.asString.data = dup; + content_.asString.size = value.size(); return true; } else { setType(VALUE_IS_NULL); @@ -204,13 +187,13 @@ class VariantData { template <typename T> typename enable_if<is_unsigned<T>::value>::type setInteger(T value) { setType(VALUE_IS_UNSIGNED_INTEGER); - _content.asUnsignedInteger = static_cast<JsonUInt>(value); + content_.asUnsignedInteger = static_cast<JsonUInt>(value); } template <typename T> typename enable_if<is_signed<T>::value>::type setInteger(T value) { setType(VALUE_IS_SIGNED_INTEGER); - _content.asSignedInteger = value; + content_.asSignedInteger = value; } void setNull() { @@ -223,20 +206,20 @@ class VariantData { setType(VALUE_IS_LINKED_STRING); else setType(VALUE_IS_OWNED_STRING); - _content.asString.data = s.c_str(); - _content.asString.size = s.size(); + content_.asString.data = s.c_str(); + content_.asString.size = s.size(); } CollectionData& toArray() { setType(VALUE_IS_ARRAY); - _content.asCollection.clear(); - return _content.asCollection; + content_.asCollection.clear(); + return content_.asCollection; } CollectionData& toObject() { setType(VALUE_IS_OBJECT); - _content.asCollection.clear(); - return _content.asCollection; + content_.asCollection.clear(); + return content_.asCollection; } size_t memoryUsage() const { @@ -245,17 +228,17 @@ class VariantData { case VALUE_IS_OWNED_RAW: // We always add a zero at the end: the deduplication function uses it // to detect the beginning of the next string. - return _content.asString.size + 1; + return content_.asString.size + 1; case VALUE_IS_OBJECT: case VALUE_IS_ARRAY: - return _content.asCollection.memoryUsage(); + return content_.asCollection.memoryUsage(); default: return 0; } } size_t size() const { - return isCollection() ? _content.asCollection.size() : 0; + return isCollection() ? content_.asCollection.size() : 0; } VariantData* addElement(MemoryPool* pool) { @@ -263,7 +246,7 @@ class VariantData { toArray(); if (!isArray()) return 0; - return _content.asCollection.addElement(pool); + return content_.asCollection.addElement(pool); } VariantData* getElement(size_t index) const { @@ -276,7 +259,7 @@ class VariantData { toArray(); if (!isArray()) return 0; - return _content.asCollection.getOrAddElement(index, pool); + return content_.asCollection.getOrAddElement(index, pool); } template <typename TAdaptedString> @@ -291,18 +274,18 @@ class VariantData { toObject(); if (!isObject()) return 0; - return _content.asCollection.getOrAddMember(key, pool); + return content_.asCollection.getOrAddMember(key, pool); } void movePointers(ptrdiff_t stringDistance, ptrdiff_t variantDistance) { - if (_flags & OWNED_VALUE_BIT) - _content.asString.data += stringDistance; - if (_flags & COLLECTION_MASK) - _content.asCollection.movePointers(stringDistance, variantDistance); + if (flags_ & OWNED_VALUE_BIT) + content_.asString.data += stringDistance; + if (flags_ & COLLECTION_MASK) + content_.asCollection.movePointers(stringDistance, variantDistance); } uint8_t type() const { - return _flags & VALUE_MASK; + return flags_ & VALUE_MASK; } template <typename TAdaptedString> @@ -317,29 +300,23 @@ class VariantData { private: void setType(uint8_t t) { - _flags &= OWNED_KEY_BIT; - _flags |= t; + flags_ &= OWNED_KEY_BIT; + flags_ |= t; } struct VariantStringSetter { - VariantStringSetter(VariantData* instance) : _instance(instance) {} + VariantStringSetter(VariantData* instance) : instance_(instance) {} template <typename TStoredString> void operator()(TStoredString s) { if (s) - _instance->setString(s); + instance_->setString(s); else - _instance->setNull(); + instance_->setNull(); } - VariantData* _instance; + VariantData* instance_; }; }; -} // namespace ARDUINOJSON_NAMESPACE - -#if defined(__GNUC__) -# if __GNUC__ >= 8 -# pragma GCC diagnostic pop -# endif -#endif +ARDUINOJSON_END_PRIVATE_NAMESPACE diff --git a/neosensor/libraries/ArduinoJson/src/ArduinoJson/Variant/VariantFunctions.hpp b/neosensor/libraries/ArduinoJson/src/ArduinoJson/Variant/VariantFunctions.hpp index 99cc7cb1268b79e096c5625bd46c52e89cb841a2..c0c91957709c27c4ce0ac23d1d24ee4e0c75c1a1 100644 --- a/neosensor/libraries/ArduinoJson/src/ArduinoJson/Variant/VariantFunctions.hpp +++ b/neosensor/libraries/ArduinoJson/src/ArduinoJson/Variant/VariantFunctions.hpp @@ -1,5 +1,5 @@ // ArduinoJson - https://arduinojson.org -// Copyright © 2014-2022, Benoit BLANCHON +// Copyright © 2014-2023, Benoit BLANCHON // MIT License #pragma once @@ -9,7 +9,7 @@ #include <ArduinoJson/Variant/VariantData.hpp> #include <ArduinoJson/Variant/Visitor.hpp> -namespace ARDUINOJSON_NAMESPACE { +ARDUINOJSON_BEGIN_PRIVATE_NAMESPACE template <typename TVisitor> inline typename TVisitor::result_type variantAccept(const VariantData* var, @@ -110,4 +110,4 @@ inline size_t variantNesting(const VariantData* var) { return maxChildNesting + 1; } -} // namespace ARDUINOJSON_NAMESPACE +ARDUINOJSON_END_PRIVATE_NAMESPACE diff --git a/neosensor/libraries/ArduinoJson/src/ArduinoJson/Variant/VariantImpl.hpp b/neosensor/libraries/ArduinoJson/src/ArduinoJson/Variant/VariantImpl.hpp index ced1b8a5cb177b5e0b55709f4324c99c32348d08..66a473bbd0dd9876c1ab3e945990d1d445028162 100644 --- a/neosensor/libraries/ArduinoJson/src/ArduinoJson/Variant/VariantImpl.hpp +++ b/neosensor/libraries/ArduinoJson/src/ArduinoJson/Variant/VariantImpl.hpp @@ -1,5 +1,5 @@ // ArduinoJson - https://arduinojson.org -// Copyright © 2014-2022, Benoit BLANCHON +// Copyright © 2014-2023, Benoit BLANCHON // MIT License #pragma once @@ -13,22 +13,22 @@ #include <string.h> // for strcmp -namespace ARDUINOJSON_NAMESPACE { +ARDUINOJSON_BEGIN_PRIVATE_NAMESPACE template <typename T> inline T VariantData::asIntegral() const { switch (type()) { case VALUE_IS_BOOLEAN: - return _content.asBoolean; + return content_.asBoolean; case VALUE_IS_UNSIGNED_INTEGER: - return convertNumber<T>(_content.asUnsignedInteger); + return convertNumber<T>(content_.asUnsignedInteger); case VALUE_IS_SIGNED_INTEGER: - return convertNumber<T>(_content.asSignedInteger); + return convertNumber<T>(content_.asSignedInteger); case VALUE_IS_LINKED_STRING: case VALUE_IS_OWNED_STRING: - return parseNumber<T>(_content.asString.data); + return parseNumber<T>(content_.asString.data); case VALUE_IS_FLOAT: - return convertNumber<T>(_content.asFloat); + return convertNumber<T>(content_.asFloat); default: return 0; } @@ -37,12 +37,12 @@ inline T VariantData::asIntegral() const { inline bool VariantData::asBoolean() const { switch (type()) { case VALUE_IS_BOOLEAN: - return _content.asBoolean; + return content_.asBoolean; case VALUE_IS_SIGNED_INTEGER: case VALUE_IS_UNSIGNED_INTEGER: - return _content.asUnsignedInteger != 0; + return content_.asUnsignedInteger != 0; case VALUE_IS_FLOAT: - return _content.asFloat != 0; + return content_.asFloat != 0; case VALUE_IS_NULL: return false; default: @@ -55,16 +55,16 @@ template <typename T> inline T VariantData::asFloat() const { switch (type()) { case VALUE_IS_BOOLEAN: - return static_cast<T>(_content.asBoolean); + return static_cast<T>(content_.asBoolean); case VALUE_IS_UNSIGNED_INTEGER: - return static_cast<T>(_content.asUnsignedInteger); + return static_cast<T>(content_.asUnsignedInteger); case VALUE_IS_SIGNED_INTEGER: - return static_cast<T>(_content.asSignedInteger); + return static_cast<T>(content_.asSignedInteger); case VALUE_IS_LINKED_STRING: case VALUE_IS_OWNED_STRING: - return parseNumber<T>(_content.asString.data); + return parseNumber<T>(content_.asString.data); case VALUE_IS_FLOAT: - return static_cast<T>(_content.asFloat); + return static_cast<T>(content_.asFloat); default: return 0; } @@ -73,10 +73,10 @@ inline T VariantData::asFloat() const { inline JsonString VariantData::asString() const { switch (type()) { case VALUE_IS_LINKED_STRING: - return JsonString(_content.asString.data, _content.asString.size, + return JsonString(content_.asString.data, content_.asString.size, JsonString::Linked); case VALUE_IS_OWNED_STRING: - return JsonString(_content.asString.data, _content.asString.size, + return JsonString(content_.asString.data, content_.asString.size, JsonString::Copied); default: return JsonString(); @@ -86,20 +86,20 @@ inline JsonString VariantData::asString() const { inline bool VariantData::copyFrom(const VariantData& src, MemoryPool* pool) { switch (src.type()) { case VALUE_IS_ARRAY: - return toArray().copyFrom(src._content.asCollection, pool); + return toArray().copyFrom(src.content_.asCollection, pool); case VALUE_IS_OBJECT: - return toObject().copyFrom(src._content.asCollection, pool); + return toObject().copyFrom(src.content_.asCollection, pool); case VALUE_IS_OWNED_STRING: { JsonString value = src.asString(); return setString(adaptString(value), pool); } case VALUE_IS_OWNED_RAW: return storeOwnedRaw( - serialized(src._content.asString.data, src._content.asString.size), + serialized(src.content_.asString.data, src.content_.asString.size), pool); default: setType(src.type()); - _content = src._content; + content_ = src.content_; return true; } } @@ -148,4 +148,4 @@ inline void convertToJson(const VariantRefBase<TDerived>& src, dst.set(src.template as<JsonVariantConst>()); } -} // namespace ARDUINOJSON_NAMESPACE +ARDUINOJSON_END_PRIVATE_NAMESPACE diff --git a/neosensor/libraries/ArduinoJson/src/ArduinoJson/Variant/VariantOperators.hpp b/neosensor/libraries/ArduinoJson/src/ArduinoJson/Variant/VariantOperators.hpp index b73ff937b40fe597bae7af5f96c77a3ed09f7106..a352f0c41a59e2f05cbbd2dc75e7608ad0627962 100644 --- a/neosensor/libraries/ArduinoJson/src/ArduinoJson/Variant/VariantOperators.hpp +++ b/neosensor/libraries/ArduinoJson/src/ArduinoJson/Variant/VariantOperators.hpp @@ -1,5 +1,5 @@ // ArduinoJson - https://arduinojson.org -// Copyright © 2014-2022, Benoit BLANCHON +// Copyright © 2014-2023, Benoit BLANCHON // MIT License #pragma once @@ -9,10 +9,14 @@ #include <ArduinoJson/Polyfills/type_traits.hpp> #include <ArduinoJson/Variant/VariantTag.hpp> -namespace ARDUINOJSON_NAMESPACE { +ARDUINOJSON_BEGIN_PUBLIC_NAMESPACE class JsonVariantConst; +ARDUINOJSON_END_PUBLIC_NAMESPACE + +ARDUINOJSON_BEGIN_PRIVATE_NAMESPACE + template <typename T> CompareResult compare(JsonVariantConst lhs, const T& rhs); // VariantCompare.cpp @@ -187,4 +191,5 @@ struct VariantOperators : VariantOperatorTag { return (compare(lhs, rhs) & COMPARE_RESULT_GREATER_OR_EQUAL) != 0; } }; -} // namespace ARDUINOJSON_NAMESPACE + +ARDUINOJSON_END_PRIVATE_NAMESPACE diff --git a/neosensor/libraries/ArduinoJson/src/ArduinoJson/Variant/VariantRefBase.hpp b/neosensor/libraries/ArduinoJson/src/ArduinoJson/Variant/VariantRefBase.hpp index ddfcf0d60ea2a44f914e4cf70fce66dab9851276..2afdda6a49561fd499e97d2391c1e8637f87bf0c 100644 --- a/neosensor/libraries/ArduinoJson/src/ArduinoJson/Variant/VariantRefBase.hpp +++ b/neosensor/libraries/ArduinoJson/src/ArduinoJson/Variant/VariantRefBase.hpp @@ -1,5 +1,5 @@ // ArduinoJson - https://arduinojson.org -// Copyright © 2014-2022, Benoit BLANCHON +// Copyright © 2014-2023, Benoit BLANCHON // MIT License #pragma once @@ -10,10 +10,11 @@ #include <ArduinoJson/Variant/VariantOperators.hpp> #include <ArduinoJson/Variant/VariantTo.hpp> -namespace ARDUINOJSON_NAMESPACE { - +ARDUINOJSON_BEGIN_PUBLIC_NAMESPACE class JsonVariant; +ARDUINOJSON_END_PUBLIC_NAMESPACE +ARDUINOJSON_BEGIN_PRIVATE_NAMESPACE template <typename> class ElementProxy; @@ -46,11 +47,9 @@ class VariantRefBase : public VariantTag { // Casts the value to the specified type. // https://arduinojson.org/v6/api/jsonvariant/as/ template <typename T> - FORCE_INLINE typename enable_if<!is_same<T, char*>::value && - !is_same<T, char>::value && - !ConverterNeedsWriteableRef<T>::value, - T>::type - as() const { + FORCE_INLINE + typename enable_if<!ConverterNeedsWriteableRef<T>::value, T>::type + as() const { return Converter<T>::fromJson(getVariantConst()); } @@ -109,7 +108,7 @@ class VariantRefBase : public VariantTag { // Shallow copies the specified value. // https://arduinojson.org/v6/api/jsonvariant/shallowcopy/ - FORCE_INLINE void shallowCopy(JsonVariantConst target) { + FORCE_INLINE void shallowCopy(ArduinoJson::JsonVariantConst target) { VariantData* data = getOrCreateData(); if (!data) return; @@ -235,14 +234,14 @@ class VariantRefBase : public VariantTag { // https://arduinojson.org/v6/api/jsonvariant/subscript/ template <typename TString> FORCE_INLINE typename enable_if<IsString<TString>::value, - MemberProxy<TDerived, TString> >::type + MemberProxy<TDerived, TString>>::type operator[](const TString& key) const; // Gets or sets an object member. // https://arduinojson.org/v6/api/jsonvariant/subscript/ template <typename TChar> FORCE_INLINE typename enable_if<IsString<TChar*>::value, - MemberProxy<TDerived, TChar*> >::type + MemberProxy<TDerived, TChar*>>::type operator[](TChar* key) const; // Creates an array and adds it to the object. @@ -287,13 +286,13 @@ class VariantRefBase : public VariantTag { } private: - FORCE_INLINE JsonVariant getVariant() const; + FORCE_INLINE ArduinoJson::JsonVariant getVariant() const; - FORCE_INLINE JsonVariantConst getVariantConst() const { - return JsonVariantConst(getData()); + FORCE_INLINE ArduinoJson::JsonVariantConst getVariantConst() const { + return ArduinoJson::JsonVariantConst(getData()); } - FORCE_INLINE JsonVariant getOrCreateVariant() const; + FORCE_INLINE ArduinoJson::JsonVariant getOrCreateVariant() const; }; -} // namespace ARDUINOJSON_NAMESPACE +ARDUINOJSON_END_PRIVATE_NAMESPACE diff --git a/neosensor/libraries/ArduinoJson/src/ArduinoJson/Variant/VariantSlot.hpp b/neosensor/libraries/ArduinoJson/src/ArduinoJson/Variant/VariantSlot.hpp index 5cd53bd30e2d5efc7252253b887e955753324bd5..f88e35badc37f566c020c0c82b4b754fd683cfb6 100644 --- a/neosensor/libraries/ArduinoJson/src/ArduinoJson/Variant/VariantSlot.hpp +++ b/neosensor/libraries/ArduinoJson/src/ArduinoJson/Variant/VariantSlot.hpp @@ -1,5 +1,5 @@ // ArduinoJson - https://arduinojson.org -// Copyright © 2014-2022, Benoit BLANCHON +// Copyright © 2014-2023, Benoit BLANCHON // MIT License #pragma once @@ -9,7 +9,7 @@ #include <ArduinoJson/Polyfills/type_traits.hpp> #include <ArduinoJson/Variant/VariantContent.hpp> -namespace ARDUINOJSON_NAMESPACE { +ARDUINOJSON_BEGIN_PRIVATE_NAMESPACE typedef int_t<ARDUINOJSON_SLOT_OFFSET_SIZE * 8>::type VariantSlotDiff; @@ -17,10 +17,10 @@ class VariantSlot { // CAUTION: same layout as VariantData // we cannot use composition because it adds padding // (+20% on ESP8266 for example) - VariantContent _content; - uint8_t _flags; - VariantSlotDiff _next; - const char* _key; + VariantContent content_; + uint8_t flags_; + VariantSlotDiff next_; + const char* key_; public: // Must be a POD! @@ -30,15 +30,15 @@ class VariantSlot { // - no inheritance VariantData* data() { - return reinterpret_cast<VariantData*>(&_content); + return reinterpret_cast<VariantData*>(&content_); } const VariantData* data() const { - return reinterpret_cast<const VariantData*>(&_content); + return reinterpret_cast<const VariantData*>(&content_); } VariantSlot* next() { - return _next ? this + _next : 0; + return next_ ? this + next_ : 0; } const VariantSlot* next() const { @@ -48,9 +48,9 @@ class VariantSlot { VariantSlot* next(size_t distance) { VariantSlot* slot = this; while (distance--) { - if (!slot->_next) + if (!slot->next_) return 0; - slot += slot->_next; + slot += slot->next_; } return slot; } @@ -64,7 +64,7 @@ class VariantSlot { numeric_limits<VariantSlotDiff>::lowest()); ARDUINOJSON_ASSERT(!slot || slot - this <= numeric_limits<VariantSlotDiff>::highest()); - _next = VariantSlotDiff(slot ? slot - this : 0); + next_ = VariantSlotDiff(slot ? slot - this : 0); } void setNextNotNull(VariantSlot* slot) { @@ -73,40 +73,40 @@ class VariantSlot { numeric_limits<VariantSlotDiff>::lowest()); ARDUINOJSON_ASSERT(slot - this <= numeric_limits<VariantSlotDiff>::highest()); - _next = VariantSlotDiff(slot - this); + next_ = VariantSlotDiff(slot - this); } void setKey(JsonString k) { ARDUINOJSON_ASSERT(k); if (k.isLinked()) - _flags &= VALUE_MASK; + flags_ &= VALUE_MASK; else - _flags |= OWNED_KEY_BIT; - _key = k.c_str(); + flags_ |= OWNED_KEY_BIT; + key_ = k.c_str(); } const char* key() const { - return _key; + return key_; } bool ownsKey() const { - return (_flags & OWNED_KEY_BIT) != 0; + return (flags_ & OWNED_KEY_BIT) != 0; } void clear() { - _next = 0; - _flags = 0; - _key = 0; + next_ = 0; + flags_ = 0; + key_ = 0; } void movePointers(ptrdiff_t stringDistance, ptrdiff_t variantDistance) { - if (_flags & OWNED_KEY_BIT) - _key += stringDistance; - if (_flags & OWNED_VALUE_BIT) - _content.asString.data += stringDistance; - if (_flags & COLLECTION_MASK) - _content.asCollection.movePointers(stringDistance, variantDistance); + if (flags_ & OWNED_KEY_BIT) + key_ += stringDistance; + if (flags_ & OWNED_VALUE_BIT) + content_.asString.data += stringDistance; + if (flags_ & COLLECTION_MASK) + content_.asCollection.movePointers(stringDistance, variantDistance); } }; -} // namespace ARDUINOJSON_NAMESPACE +ARDUINOJSON_END_PRIVATE_NAMESPACE diff --git a/neosensor/libraries/ArduinoJson/src/ArduinoJson/Variant/VariantTag.hpp b/neosensor/libraries/ArduinoJson/src/ArduinoJson/Variant/VariantTag.hpp index 94ec38b9f8e6f30ff379dc8f32edd99498450ce9..0c5ee40db76e4889bdf944d78ca1bc86f770e306 100644 --- a/neosensor/libraries/ArduinoJson/src/ArduinoJson/Variant/VariantTag.hpp +++ b/neosensor/libraries/ArduinoJson/src/ArduinoJson/Variant/VariantTag.hpp @@ -1,16 +1,16 @@ // ArduinoJson - https://arduinojson.org -// Copyright © 2014-2022, Benoit BLANCHON +// Copyright © 2014-2023, Benoit BLANCHON // MIT License #pragma once #include <ArduinoJson/Namespace.hpp> -namespace ARDUINOJSON_NAMESPACE { +ARDUINOJSON_BEGIN_PRIVATE_NAMESPACE struct VariantTag {}; template <typename T> struct IsVariant : is_base_of<VariantTag, T> {}; -} // namespace ARDUINOJSON_NAMESPACE +ARDUINOJSON_END_PRIVATE_NAMESPACE diff --git a/neosensor/libraries/ArduinoJson/src/ArduinoJson/Variant/VariantTo.hpp b/neosensor/libraries/ArduinoJson/src/ArduinoJson/Variant/VariantTo.hpp index 1521d7777e4c219e9a3dd8c19e67db2f60840f29..0ca56df60300cf7622eb64e4041bee1b2f66c76b 100644 --- a/neosensor/libraries/ArduinoJson/src/ArduinoJson/Variant/VariantTo.hpp +++ b/neosensor/libraries/ArduinoJson/src/ArduinoJson/Variant/VariantTo.hpp @@ -1,16 +1,18 @@ // ArduinoJson - https://arduinojson.org -// Copyright © 2014-2022, Benoit BLANCHON +// Copyright © 2014-2023, Benoit BLANCHON // MIT License #pragma once #include <ArduinoJson/Namespace.hpp> -namespace ARDUINOJSON_NAMESPACE { +ARDUINOJSON_BEGIN_PUBLIC_NAMESPACE class JsonArray; class JsonObject; class JsonVariant; +ARDUINOJSON_END_PUBLIC_NAMESPACE +ARDUINOJSON_BEGIN_PRIVATE_NAMESPACE // A metafunction that returns the type of the value returned by // JsonVariant::to<T>() template <typename T> @@ -29,4 +31,4 @@ struct VariantTo<JsonVariant> { typedef JsonVariant type; }; -} // namespace ARDUINOJSON_NAMESPACE +ARDUINOJSON_END_PRIVATE_NAMESPACE diff --git a/neosensor/libraries/ArduinoJson/src/ArduinoJson/Variant/Visitor.hpp b/neosensor/libraries/ArduinoJson/src/ArduinoJson/Variant/Visitor.hpp index 6c79316a30d4fa06a9705dd1d83781cc94440244..f1c784165d468333ba1634a276aebd90a34b680c 100644 --- a/neosensor/libraries/ArduinoJson/src/ArduinoJson/Variant/Visitor.hpp +++ b/neosensor/libraries/ArduinoJson/src/ArduinoJson/Variant/Visitor.hpp @@ -1,5 +1,5 @@ // ArduinoJson - https://arduinojson.org -// Copyright © 2014-2022, Benoit BLANCHON +// Copyright © 2014-2023, Benoit BLANCHON // MIT License #pragma once @@ -8,7 +8,7 @@ #include <ArduinoJson/Numbers/JsonFloat.hpp> #include <ArduinoJson/Numbers/JsonInteger.hpp> -namespace ARDUINOJSON_NAMESPACE { +ARDUINOJSON_BEGIN_PRIVATE_NAMESPACE template <typename TResult> struct Visitor { @@ -51,4 +51,4 @@ struct Visitor { } }; -} // namespace ARDUINOJSON_NAMESPACE +ARDUINOJSON_END_PRIVATE_NAMESPACE diff --git a/neosensor/libraries/ArduinoJson/src/ArduinoJson/compatibility.hpp b/neosensor/libraries/ArduinoJson/src/ArduinoJson/compatibility.hpp index ca178a2713672d56010e9d8094db5f039e20709d..85769487d84470e625609855d859c8099e9da061 100644 --- a/neosensor/libraries/ArduinoJson/src/ArduinoJson/compatibility.hpp +++ b/neosensor/libraries/ArduinoJson/src/ArduinoJson/compatibility.hpp @@ -1,5 +1,5 @@ // ArduinoJson - https://arduinojson.org -// Copyright © 2014-2022, Benoit BLANCHON +// Copyright © 2014-2023, Benoit BLANCHON // MIT License // // clang-format off @@ -20,4 +20,6 @@ #define JsonBuffer ARDUINOJSON_DEPRECATION_ERROR(JsonBuffer, class) #define RawJson ARDUINOJSON_DEPRECATION_ERROR(RawJson, function) +#define ARDUINOJSON_NAMESPACE _Pragma ("GCC warning \"ARDUINOJSON_NAMESPACE is deprecated, use ArduinoJson instead\"") ArduinoJson + #endif diff --git a/neosensor/libraries/ArduinoJson/src/ArduinoJson/version.hpp b/neosensor/libraries/ArduinoJson/src/ArduinoJson/version.hpp index 7f4aff88f3c259205cf9ef590467011fce5842fa..f0ee0afa7f98fed4997dcbe9a3032d173bb21139 100644 --- a/neosensor/libraries/ArduinoJson/src/ArduinoJson/version.hpp +++ b/neosensor/libraries/ArduinoJson/src/ArduinoJson/version.hpp @@ -1,10 +1,10 @@ // ArduinoJson - https://arduinojson.org -// Copyright © 2014-2022, Benoit BLANCHON +// Copyright © 2014-2023, Benoit BLANCHON // MIT License #pragma once -#define ARDUINOJSON_VERSION "6.20.0" +#define ARDUINOJSON_VERSION "6.21.2" #define ARDUINOJSON_VERSION_MAJOR 6 -#define ARDUINOJSON_VERSION_MINOR 20 -#define ARDUINOJSON_VERSION_REVISION 0 +#define ARDUINOJSON_VERSION_MINOR 21 +#define ARDUINOJSON_VERSION_REVISION 2 diff --git a/neosensor/libraries/ArduinoJson/src/CMakeLists.txt b/neosensor/libraries/ArduinoJson/src/CMakeLists.txt index ebc83a952fb02b111b5e797b5ed935817e3e6eb9..10aef8089eaf40b65207e7752dc50b69e1bfa8d8 100644 --- a/neosensor/libraries/ArduinoJson/src/CMakeLists.txt +++ b/neosensor/libraries/ArduinoJson/src/CMakeLists.txt @@ -1,5 +1,5 @@ # ArduinoJson - https://arduinojson.org -# Copyright © 2014-2022, Benoit BLANCHON +# Copyright © 2014-2023, Benoit BLANCHON # MIT License # I have no idea what this is about, I simply followed the instructions from: @@ -12,79 +12,80 @@ include(GNUInstallDirs) # Adding the install interface generator expression makes sure that the include # files are installed to the proper location (provided by GNUInstallDirs) target_include_directories(ArduinoJson - INTERFACE - $<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}> - $<INSTALL_INTERFACE:${CMAKE_INSTALL_INCLUDEDIR}> + INTERFACE + $<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}> + $<INSTALL_INTERFACE:${CMAKE_INSTALL_INCLUDEDIR}> ) target_compile_definitions(ArduinoJson - INTERFACE - ARDUINOJSON_DEBUG=$<CONFIG:Debug> + INTERFACE + ARDUINOJSON_DEBUG=$<CONFIG:Debug> ) # locations are provided by GNUInstallDirs install( - TARGETS - ArduinoJson - EXPORT - ArduinoJson_Targets - ARCHIVE DESTINATION - ${CMAKE_INSTALL_LIBDIR} - LIBRARY DESTINATION - ${CMAKE_INSTALL_LIBDIR} - RUNTIME DESTINATION - ${CMAKE_INSTALL_BINDIR} + TARGETS + ArduinoJson + EXPORT + ArduinoJson_Targets + ARCHIVE DESTINATION + ${CMAKE_INSTALL_LIBDIR} + LIBRARY DESTINATION + ${CMAKE_INSTALL_LIBDIR} + RUNTIME DESTINATION + ${CMAKE_INSTALL_BINDIR} ) include(CMakePackageConfigHelpers) -if(${CMAKE_VERSION} VERSION_GREATER "3.14.0") - set(ARCH_INDEPENDENT "ARCH_INDEPENDENT") +if(${CMAKE_VERSION} VERSION_GREATER "3.14.0") + set(ARCH_INDEPENDENT "ARCH_INDEPENDENT") endif() write_basic_package_version_file( - "${PROJECT_BINARY_DIR}/ArduinoJsonConfigVersion.cmake" - VERSION - ${PROJECT_VERSION} - COMPATIBILITY - SameMajorVersion - ${ARCH_INDEPENDENT} + "${PROJECT_BINARY_DIR}/ArduinoJsonConfigVersion.cmake" + VERSION + ${PROJECT_VERSION} + COMPATIBILITY + SameMajorVersion + ${ARCH_INDEPENDENT} ) configure_package_config_file( - "${PROJECT_SOURCE_DIR}/extras/ArduinoJsonConfig.cmake.in" - "${PROJECT_BINARY_DIR}/ArduinoJsonConfig.cmake" - INSTALL_DESTINATION - ${CMAKE_INSTALL_DATAROOTDIR}/ArduinoJson/cmake) + "${PROJECT_SOURCE_DIR}/extras/ArduinoJsonConfig.cmake.in" + "${PROJECT_BINARY_DIR}/ArduinoJsonConfig.cmake" + INSTALL_DESTINATION + ${CMAKE_INSTALL_DATAROOTDIR}/ArduinoJson/cmake +) install( - EXPORT - ArduinoJson_Targets - FILE - ArduinoJsonTargets.cmake - DESTINATION - ${CMAKE_INSTALL_DATAROOTDIR}/ArduinoJson/cmake + EXPORT + ArduinoJson_Targets + FILE + ArduinoJsonTargets.cmake + DESTINATION + ${CMAKE_INSTALL_DATAROOTDIR}/ArduinoJson/cmake ) install( - FILES - "${PROJECT_BINARY_DIR}/ArduinoJsonConfig.cmake" - "${PROJECT_BINARY_DIR}/ArduinoJsonConfigVersion.cmake" - DESTINATION - "${CMAKE_INSTALL_DATAROOTDIR}/ArduinoJson/cmake" + FILES + "${PROJECT_BINARY_DIR}/ArduinoJsonConfig.cmake" + "${PROJECT_BINARY_DIR}/ArduinoJsonConfigVersion.cmake" + DESTINATION + "${CMAKE_INSTALL_DATAROOTDIR}/ArduinoJson/cmake" ) install( - FILES - ArduinoJson.h - ArduinoJson.hpp - DESTINATION - include + FILES + ArduinoJson.h + ArduinoJson.hpp + DESTINATION + include ) install( - DIRECTORY - "${CMAKE_CURRENT_SOURCE_DIR}/ArduinoJson" - DESTINATION - include + DIRECTORY + "${CMAKE_CURRENT_SOURCE_DIR}/ArduinoJson" + DESTINATION + include ) diff --git a/neosensor/neosensor.ino b/neosensor/neosensor.ino index 27eba1acfb0b1919916ba0ba6a178643b12baac1..1a2b64c9b98521f5dcfbdb557cdbb2f778c41e36 100644 --- a/neosensor/neosensor.ino +++ b/neosensor/neosensor.ino @@ -558,16 +558,12 @@ bool setupNTP( void ) { #ifdef ESP8266 // register ntp sync callback settimeofday_cb( syncNTP_cb ); - // [may.20] as default, NTP server is provided by the DHCP server - configTime( MYTZ, NTP_DEFAULT_SERVER1, NTP_DEFAULT_SERVER2, NTP_DEFAULT_SERVER3 ); #elif ESP32 // register ntp sync callback sntp_set_time_sync_notification_cb( _syncNTP_cb ); - // [nov.21] now using timezone definition :) - configTzTime( MYTZ, NTP_DEFAULT_SERVER1, NTP_DEFAULT_SERVER2, NTP_DEFAULT_SERVER3 ); - // [may.20] as default, NTP server is provided by the DHCP server - // configTime(gmtOffset_sec, daylightOffset_sec, NTP_DEFAULT_SERVER1, NTP_DEFAULT_SERVER2, NTP_DEFAULT_SERVER3 ); #endif + // [may.23] esp32/8266 unified API + configTzTime( MYTZ, NTP_DEFAULT_SERVER1, NTP_DEFAULT_SERVER2, NTP_DEFAULT_SERVER3 ); log_flush(); // the end ... @@ -632,18 +628,22 @@ void processWIFIparameters( wifiParametersMgt *wp=nullptr ) { // --- // show WiFi protocols in use -void display_wifi_protocol( wifi_interface_t ifx=WIFI_IF_STA ) { +void display_wifi_protocol( void ) { uint8_t cur_protocols; - esp_err_t _err; - _err = esp_wifi_get_protocol(ifx, &cur_protocols); + int _err; +#ifdef ESP32 + _err = esp_wifi_get_protocol(WIFI_IF_STA, &cur_protocols); if( _err != ESP_OK ) { log_error(F("\n[WiFiProtocol] Could not get protocol!")); return; } - - log_debug(F("\n# WIFI protocols = 0x"));log_debug(cur_protocols,HEX);log_flush(); +#elif defined (ESP8266) + cur_protocols = (uint8_t)WiFi.getPhyMode(); +#endif + log_debug(F("\n# WIFI protocols = 0x"));log_debug(cur_protocols,HEX);log_flush(); +#ifdef ESP32 if( cur_protocols & WIFI_PROTOCOL_11N ) { log_debug(F("\n\tWiFi_Protocol_11n")); } @@ -653,6 +653,17 @@ void display_wifi_protocol( wifi_interface_t ifx=WIFI_IF_STA ) { if( cur_protocols & WIFI_PROTOCOL_11B ) { log_debug(F("\n\tWiFi_Protocol_11b")); } +#elif defined (ESP8266) + if( cur_protocols==WIFI_PHY_MODE_11N ) { + log_debug(F("\n\tWiFi_Protocol_11n")); + } + else if( cur_protocols==WIFI_PHY_MODE_11G ) { + log_debug(F("\n\tWiFi_Protocol_11g")); + } + else if( cur_protocols==WIFI_PHY_MODE_11B ) { + log_debug(F("\n\tWiFi_Protocol_11b")); + } +#endif }