From c02a20a5c136ee74247dfec5dd67370f56bbab2b Mon Sep 17 00:00:00 2001 From: crackedmind Date: Sun, 11 Mar 2018 03:44:20 +0300 Subject: [PATCH] git subrepo pull Telegram/ThirdParty/Catch subrepo: subdir: "Telegram/ThirdParty/Catch" merged: "11c89a5f7" upstream: origin: "https://github.com/catchorg/Catch2" branch: "master" commit: "11c89a5f7" git-subrepo: version: "0.3.1" origin: "https://github.com/ingydotnet/git-subrepo" commit: "a7ee886" --- Telegram/ThirdParty/Catch/.gitattributes | 13 +- Telegram/ThirdParty/Catch/.gitignore | 1 + Telegram/ThirdParty/Catch/.gitrepo | 4 +- Telegram/ThirdParty/Catch/.travis.yml | 149 +- .../ThirdParty/Catch/CMake/FindGcov.cmake | 157 + .../ThirdParty/Catch/CMake/FindLcov.cmake | 354 + .../ThirdParty/Catch/CMake/Findcodecov.cmake | 258 + .../ThirdParty/Catch/CMake/llvm-cov-wrapper | 56 + Telegram/ThirdParty/Catch/CMakeLists.txt | 143 +- Telegram/ThirdParty/Catch/README.md | 11 +- Telegram/ThirdParty/Catch/appveyor.yml | 57 +- Telegram/ThirdParty/Catch/catch.pc.in | 9 +- Telegram/ThirdParty/Catch/codecov.yml | 26 + Telegram/ThirdParty/Catch/conanfile.py | 2 +- Telegram/ThirdParty/Catch/contrib/Catch.cmake | 175 + .../Catch/contrib/CatchAddTests.cmake | 77 + Telegram/ThirdParty/Catch/docs/assertions.md | 4 +- .../ThirdParty/Catch/docs/build-systems.md | 28 +- .../ThirdParty/Catch/docs/command-line.md | 17 +- .../ThirdParty/Catch/docs/configuration.md | 44 +- .../ThirdParty/Catch/docs/event-listeners.md | 2 +- Telegram/ThirdParty/Catch/docs/limitations.md | 8 + .../ThirdParty/Catch/docs/opensource-users.md | 24 +- Telegram/ThirdParty/Catch/docs/own-main.md | 17 +- .../ThirdParty/Catch/docs/release-notes.md | 141 +- .../ThirdParty/Catch/docs/release-process.md | 31 +- Telegram/ThirdParty/Catch/docs/tostring.md | 17 + .../ThirdParty/Catch/examples/CMakeLists.txt | 2 +- Telegram/ThirdParty/Catch/include/catch.hpp | 3 + .../Catch/include/external/clara.hpp | 150 +- .../internal/catch_assertionhandler.cpp | 112 +- .../include/internal/catch_assertionhandler.h | 51 +- .../internal/catch_assertionresult.cpp | 4 +- .../Catch/include/internal/catch_capture.hpp | 72 +- .../internal/catch_capture_matchers.cpp | 4 +- .../include/internal/catch_capture_matchers.h | 26 +- .../include/internal/catch_commandline.cpp | 14 +- .../Catch/include/internal/catch_common.cpp | 7 - .../Catch/include/internal/catch_common.h | 10 +- .../internal/catch_compiler_capabilities.h | 45 +- .../Catch/include/internal/catch_config.cpp | 15 +- .../Catch/include/internal/catch_config.hpp | 4 + .../include/internal/catch_console_colour.cpp | 21 +- .../include/internal/catch_console_colour.h | 5 +- .../Catch/include/internal/catch_context.cpp | 2 +- .../Catch/include/internal/catch_context.h | 2 +- .../include/internal/catch_debug_console.cpp | 6 +- .../Catch/include/internal/catch_debugger.h | 5 +- .../Catch/include/internal/catch_decomposer.h | 58 +- .../include/internal/catch_default_main.hpp | 2 +- .../Catch/include/internal/catch_enforce.h | 3 +- .../catch_exception_translator_registry.cpp | 11 + .../internal/catch_fatal_condition.cpp | 36 +- .../include/internal/catch_fatal_condition.h | 41 +- .../internal/catch_interfaces_capture.h | 42 +- .../internal/catch_interfaces_config.h | 5 +- .../internal/catch_interfaces_exception.h | 4 +- .../include/internal/catch_leak_detector.cpp | 9 +- .../Catch/include/internal/catch_list.cpp | 10 +- .../internal/catch_matchers_floating.cpp | 8 +- .../include/internal/catch_matchers_vector.h | 68 + .../Catch/include/internal/catch_message.cpp | 5 +- .../Catch/include/internal/catch_message.h | 2 +- .../include/internal/catch_registry_hub.cpp | 1 + .../internal/catch_reporter_registrars.hpp | 2 +- .../include/internal/catch_result_type.cpp | 1 - .../include/internal/catch_result_type.h | 2 +- .../include/internal/catch_run_context.cpp | 211 +- .../include/internal/catch_run_context.h | 91 +- .../Catch/include/internal/catch_section.cpp | 10 +- .../Catch/include/internal/catch_session.cpp | 156 +- .../Catch/include/internal/catch_session.h | 4 +- .../Catch/include/internal/catch_stream.cpp | 15 +- .../Catch/include/internal/catch_stream.h | 2 + .../include/internal/catch_stringref.cpp | 27 +- .../Catch/include/internal/catch_stringref.h | 23 +- .../internal/catch_suppress_warnings.h | 5 - .../internal/catch_tag_alias_autoregistrar.h | 5 +- .../include/internal/catch_test_case_info.cpp | 10 +- .../include/internal/catch_test_case_info.h | 6 +- .../catch_test_case_registry_impl.cpp | 2 +- .../internal/catch_test_case_registry_impl.h | 4 +- .../include/internal/catch_test_registry.cpp | 9 +- .../include/internal/catch_test_registry.h | 4 +- .../Catch/include/internal/catch_timer.cpp | 8 +- .../Catch/include/internal/catch_timer.h | 4 +- .../Catch/include/internal/catch_tostring.cpp | 4 + .../Catch/include/internal/catch_tostring.h | 108 +- .../Catch/include/internal/catch_totals.h | 2 +- .../internal/catch_uncaught_exceptions.cpp | 21 + .../internal/catch_uncaught_exceptions.h | 15 + .../Catch/include/internal/catch_version.cpp | 2 +- .../reporters/catch_reporter_console.cpp | 23 +- .../reporters/catch_reporter_junit.cpp | 2 +- .../include/reporters/catch_reporter_tap.hpp | 2 +- .../reporters/catch_reporter_teamcity.hpp | 6 +- .../include/reporters/catch_reporter_xml.cpp | 6 +- Telegram/ThirdParty/Catch/misc/CMakeLists.txt | 11 + .../misc/appveyorBuildConfigurationScript.bat | 27 + .../Catch/misc/appveyorMergeCoverageScript.py | 9 + .../Catch/misc/appveyorTestRunScript.bat | 13 + .../ThirdParty/Catch/misc/coverage-helper.cpp | 105 + .../Catch/misc/installOpenCppCoverage.ps1 | 19 + .../Baselines/automake.std.approved.txt | 2 +- .../Baselines/compact.sw.approved.txt | 1084 +++ .../Baselines/console.std.approved.txt | 58 +- .../Baselines/console.sw.approved.txt | 667 +- .../Baselines/console.swa4.approved.txt | 55 +- .../SelfTest/Baselines/junit.sw.approved.txt | 72 +- .../SelfTest/Baselines/xml.sw.approved.txt | 670 +- .../IntrospectiveTests/CmdLine.tests.cpp | 8 +- .../IntrospectiveTests/String.tests.cpp | 69 +- .../Catch/projects/SelfTest/TestMain.cpp | 2 +- .../SelfTest/UsageTests/Approx.tests.cpp | 4 +- .../SelfTest/UsageTests/Compilation.tests.cpp | 25 + .../UsageTests/EnumToString.tests.cpp | 4 +- .../SelfTest/UsageTests/Exception.tests.cpp | 50 +- .../SelfTest/UsageTests/Matchers.tests.cpp | 68 +- .../SelfTest/UsageTests/Message.tests.cpp | 2 +- .../SelfTest/UsageTests/Misc.tests.cpp | 15 +- .../UsageTests/ToStringChrono.tests.cpp | 3 + .../UsageTests/ToStringGeneral.tests.cpp | 64 + .../UsageTests/ToStringVector.tests.cpp | 22 +- .../UsageTests/ToStringWhich.tests.cpp | 111 +- .../SelfTest/UsageTests/Tricky.tests.cpp | 8 +- .../projects/XCode/OCTest/OCTest/OCTest.1 | 4 +- .../ThirdParty/Catch/scripts/approvalTests.py | 6 + .../ThirdParty/Catch/scripts/embedClara.py | 2 + .../Catch/scripts/generateSingleHeader.py | 31 +- .../ThirdParty/Catch/scripts/releaseCommon.py | 40 +- .../Catch/scripts/updateDocumentToC.py | 6 +- .../Catch/scripts/updateVcpkgPackage.py | 4 +- .../ThirdParty/Catch/single_include/catch.hpp | 5825 ++++++++++------- .../catch_reporter_automake.hpp | 62 + .../single_include/catch_reporter_tap.hpp | 255 + .../catch_reporter_teamcity.hpp | 220 + .../Catch/test_package/conanfile.py | 2 +- .../ThirdParty/Catch/third_party/clara.hpp | 150 +- 138 files changed, 9732 insertions(+), 3604 deletions(-) create mode 100644 Telegram/ThirdParty/Catch/CMake/FindGcov.cmake create mode 100644 Telegram/ThirdParty/Catch/CMake/FindLcov.cmake create mode 100644 Telegram/ThirdParty/Catch/CMake/Findcodecov.cmake create mode 100755 Telegram/ThirdParty/Catch/CMake/llvm-cov-wrapper create mode 100644 Telegram/ThirdParty/Catch/codecov.yml create mode 100644 Telegram/ThirdParty/Catch/contrib/Catch.cmake create mode 100644 Telegram/ThirdParty/Catch/contrib/CatchAddTests.cmake create mode 100644 Telegram/ThirdParty/Catch/include/internal/catch_uncaught_exceptions.cpp create mode 100644 Telegram/ThirdParty/Catch/include/internal/catch_uncaught_exceptions.h create mode 100644 Telegram/ThirdParty/Catch/misc/CMakeLists.txt create mode 100644 Telegram/ThirdParty/Catch/misc/appveyorBuildConfigurationScript.bat create mode 100644 Telegram/ThirdParty/Catch/misc/appveyorMergeCoverageScript.py create mode 100644 Telegram/ThirdParty/Catch/misc/appveyorTestRunScript.bat create mode 100644 Telegram/ThirdParty/Catch/misc/coverage-helper.cpp create mode 100644 Telegram/ThirdParty/Catch/misc/installOpenCppCoverage.ps1 create mode 100644 Telegram/ThirdParty/Catch/projects/SelfTest/Baselines/compact.sw.approved.txt mode change 100644 => 100755 Telegram/ThirdParty/Catch/scripts/embedClara.py create mode 100644 Telegram/ThirdParty/Catch/single_include/catch_reporter_automake.hpp create mode 100644 Telegram/ThirdParty/Catch/single_include/catch_reporter_tap.hpp create mode 100644 Telegram/ThirdParty/Catch/single_include/catch_reporter_teamcity.hpp diff --git a/Telegram/ThirdParty/Catch/.gitattributes b/Telegram/ThirdParty/Catch/.gitattributes index a2d66d32b..b5a2cdccd 100644 --- a/Telegram/ThirdParty/Catch/.gitattributes +++ b/Telegram/ThirdParty/Catch/.gitattributes @@ -8,4 +8,15 @@ *.hpp text # Windows specific files should retain windows line-endings -*.sln text eol=crlf \ No newline at end of file +*.sln text eol=crlf + +# Keep executable scripts with LFs so they can be run after being +# checked out on Windows +*.py text eol=lf + + +# Keep the single include header with LFs to make sure it is uploaded, +# hashed etc with LF +single_include/*.hpp eol=lf +# Also keep the LICENCE file with LFs for the same reason +LICENCE.txt eol=lf diff --git a/Telegram/ThirdParty/Catch/.gitignore b/Telegram/ThirdParty/Catch/.gitignore index bf296d96f..ffce8e91c 100644 --- a/Telegram/ThirdParty/Catch/.gitignore +++ b/Telegram/ThirdParty/Catch/.gitignore @@ -26,3 +26,4 @@ Build .idea .vs cmake-build-* +benchmark-dir diff --git a/Telegram/ThirdParty/Catch/.gitrepo b/Telegram/ThirdParty/Catch/.gitrepo index f7981afd6..211e3e6f8 100644 --- a/Telegram/ThirdParty/Catch/.gitrepo +++ b/Telegram/ThirdParty/Catch/.gitrepo @@ -6,6 +6,6 @@ [subrepo] remote = https://github.com/catchorg/Catch2 branch = master - commit = 63c097a07775f939b5b77c88dd61fe933f4d7050 - parent = f27cd81fd0d3ecd9dc02be18c70e767a4a3fee6e + commit = 11c89a5f7de008c2a21c9cd2a6b96d94f9a55cef + parent = 0c4e81f37a8489a0b26508d55e6d6d1fa7f78c07 cmdver = 0.3.1 diff --git a/Telegram/ThirdParty/Catch/.travis.yml b/Telegram/ThirdParty/Catch/.travis.yml index bbcaf54a7..fbf1c09d8 100644 --- a/Telegram/ThirdParty/Catch/.travis.yml +++ b/Telegram/ThirdParty/Catch/.travis.yml @@ -1,6 +1,10 @@ language: cpp sudo: false +branches: + except: + - /dev-appveyor.*/ + common_sources: &all_sources - ubuntu-toolchain-r-test - llvm-toolchain-trusty @@ -17,145 +21,140 @@ matrix: addons: apt: sources: *all_sources - packages: ['valgrind', 'clang-3.5'] - env: COMPILER='clang++-3.5' VALGRIND=1 + packages: ['clang-3.5'] + env: COMPILER='clang++-3.5' - os: linux compiler: clang addons: apt: sources: *all_sources - packages: ['valgrind', 'clang-3.6'] - env: COMPILER='clang++-3.6' VALGRIND=1 + packages: ['clang-3.6'] + env: COMPILER='clang++-3.6' -# Travis's containers do not seem to have Clang 3.7 in apt, no matter what sources I add. -# - os: linux -# compiler: clang -# addons: -# apt: -# sources: *all_sources -# packages: ['valgrind', 'clang-3.7'] -# env: COMPILER='clang++-3.7' VALGRIND=1 + # Clang 3.7 is intentionally skipped as we cannot get it easily on + # TravisCI container - os: linux compiler: clang addons: apt: sources: *all_sources - packages: ['valgrind', 'clang-3.8'] - env: COMPILER='clang++-3.8' VALGRIND=1 + packages: ['lcov', 'clang-3.8'] + env: COMPILER='clang++-3.8' - os: linux compiler: clang addons: apt: sources: *all_sources - packages: ['clang-3.9', 'valgrind'] - env: COMPILER='clang++-3.9' VALGRIND=1 + packages: ['clang-3.9'] + env: COMPILER='clang++-3.9' - os: linux compiler: clang addons: apt: sources: *all_sources - packages: ['clang-4.0', 'valgrind'] - env: COMPILER='clang++-4.0' VALGRIND=1 + packages: ['clang-4.0'] + env: COMPILER='clang++-4.0' - os: linux compiler: clang addons: apt: sources: *all_sources - packages: ['clang-5.0', 'valgrind'] - env: COMPILER='clang++-5.0' VALGRIND=1 + packages: ['clang-5.0'] + env: COMPILER='clang++-5.0' # 2/ Linux GCC Builds - os: linux compiler: gcc addons: apt: - sources: ['ubuntu-toolchain-r-test'] - packages: ['valgrind', 'g++-4.8'] - env: COMPILER='g++-4.8' VALGRIND=1 + sources: *all_sources + packages: ['g++-4.8'] + env: COMPILER='g++-4.8' - os: linux compiler: gcc addons: apt: sources: *all_sources - packages: ['valgrind', 'g++-4.9'] - env: COMPILER='g++-4.9' VALGRIND=1 + packages: ['g++-4.9'] + env: COMPILER='g++-4.9' - os: linux compiler: gcc addons: apt: sources: *all_sources - packages: ['valgrind', 'g++-5'] - env: COMPILER='g++-5' VALGRIND=1 + packages: ['g++-5'] + env: COMPILER='g++-5' - os: linux compiler: gcc addons: &gcc6 apt: sources: *all_sources - packages: ['valgrind', 'g++-6'] - env: COMPILER='g++-6' VALGRIND=1 + packages: ['g++-6'] + env: COMPILER='g++-6' - os: linux compiler: gcc addons: &gcc7 apt: sources: *all_sources - packages: ['valgrind', 'g++-7'] - env: COMPILER='g++-7' VALGRIND=1 + packages: ['g++-7'] + env: COMPILER='g++-7' # 3b/ Linux C++14 Clang builds + # Note that we need newer libstdc++ for C++14 support - os: linux compiler: clang addons: apt: - packages: ['clang-3.8', 'valgrind', 'libstdc++-6-dev'] + packages: ['clang-3.8', 'libstdc++-6-dev'] sources: - ubuntu-toolchain-r-test - llvm-toolchain-trusty - env: COMPILER='clang++-3.8' CPP14=1 VALGRIND=1 + env: COMPILER='clang++-3.8' CPP14=1 - os: linux compiler: clang addons: apt: sources: *all_sources - packages: ['clang-3.9', 'valgrind', 'libstdc++-6-dev'] - env: COMPILER='clang++-3.9' CPP14=1 VALGRIND=1 + packages: ['clang-3.9', 'libstdc++-6-dev'] + env: COMPILER='clang++-3.9' CPP14=1 - os: linux compiler: clang addons: apt: sources: *all_sources - packages: ['clang-4.0', 'valgrind', 'libstdc++-6-dev'] - env: COMPILER='clang++-4.0' CPP14=1 VALGRIND=1 + packages: ['clang-4.0', 'libstdc++-6-dev'] + env: COMPILER='clang++-4.0' CPP14=1 - os: linux compiler: clang addons: apt: sources: *all_sources - packages: ['clang-5.0', 'valgrind', 'libstdc++-6-dev'] - env: COMPILER='clang++-5.0' CPP14=1 VALGRIND=1 + packages: ['clang-5.0', 'libstdc++-6-dev'] + env: COMPILER='clang++-5.0' CPP14=1 # 4a/ Linux C++14 GCC builds - os: linux compiler: gcc addons: *gcc6 - env: COMPILER='g++-6' CPP14=1 VALGRIND=1 + env: COMPILER='g++-6' CPP14=1 - os: linux compiler: gcc addons: *gcc7 - env: COMPILER='g++-7' CPP14=1 VALGRIND=1 + env: COMPILER='g++-7' CPP14=1 # 5/ OSX Clang Builds - os: osx @@ -181,7 +180,39 @@ matrix: - os: osx osx_image: xcode9.1 compiler: clang - env: COMPILER='clang++' USE_CPP14=1 + env: COMPILER='clang++' CPP14=1 + + # 6/ Special builds -- examples, coverage, valgrind, etc. + - os: linux + compiler: gcc + addons: + apt: + sources: *all_sources + packages: ['lcov', 'g++-7'] + env: COMPILER='g++-7' CPP14=1 EXAMPLES=1 COVERAGE=1 + + - os: linux + compiler: clang + addons: + apt: + packages: ['clang-3.8', 'lcov'] + sources: + - ubuntu-toolchain-r-test + - llvm-toolchain-trusty + env: COMPILER='clang++-3.8' EXAMPLES=1 COVERAGE=1 + + - os: linux + compiler: gcc + addons: + apt: + sources: *all_sources + packages: ['valgrind', 'lcov', 'g++-7'] + env: COMPILER='g++-7' CPP14=1 VALGRIND=1 + + - os: osx + osx_image: xcode9.1 + compiler: clang + env: COMPILER='clang++' CPP14=1 EXAMPLES=1 COVERAGE=1 install: - DEPS_DIR="${TRAVIS_BUILD_DIR}/deps" @@ -192,7 +223,7 @@ install: mkdir cmake && travis_retry wget --no-check-certificate --quiet -O - ${CMAKE_URL} | tar --strip-components=1 -xz -C cmake export PATH=${DEPS_DIR}/cmake/bin:${PATH} elif [[ "${TRAVIS_OS_NAME}" == "osx" ]]; then - which cmake || brew install cmake + which cmake || brew install cmake; fi before_script: @@ -201,15 +232,27 @@ before_script: # Regenerate single header file, so it is tested in the examples... - python scripts/generateSingleHeader.py - # Use Debug builds for running Valgrind and building examples - - cmake -H. -BBuild-Debug -DCMAKE_BUILD_TYPE=Debug -Wdev -DUSE_CPP14=${CPP14} -DUSE_VALGRIND=${VALGRIND} -DBUILD_EXAMPLES=ON - # Check that we don't miscompile with optimalizations... - - cmake -H. -BBuild-Release -DCMAKE_BUILD_TYPE=Release -Wdev -DUSE_CPP14=${CPP14} + - | + # Use Debug builds for running Valgrind and building examples + cmake -H. -BBuild-Debug -DCMAKE_BUILD_TYPE=Debug -Wdev -DUSE_CPP14=${CPP14} -DCATCH_USE_VALGRIND=${VALGRIND} -DCATCH_BUILD_EXAMPLES=${EXAMPLES} -DCATCH_ENABLE_COVERAGE=${COVERAGE} + # Don't bother with release build for coverage build + cmake -H. -BBuild-Release -DCMAKE_BUILD_TYPE=Release -Wdev -DUSE_CPP14=${CPP14} + script: - - cd Build-Debug - - make -j 2 - - ctest -V -j 2 - - cd ../Build-Release - - make -j 2 - - ctest -V -j 2 + - | + cd Build-Debug + make -j 2 + CTEST_OUTPUT_ON_FAILURE=1 ctest -j 2 + # Coverage collection does not work for OS X atm + echo "${TRAVIS_OS_NAME}"; + echo "${COVERAGE}"; + if [[ "${TRAVIS_OS_NAME}" == "linux" ]] && [[ "${COVERAGE}" == "1" ]]; then + make gcov + make lcov + bash <(curl -s https://codecov.io/bash) -X gcov || echo "Codecov did not collect coverage reports" + fi + # Go to release build + cd ../Build-Release + make -j 2 + CTEST_OUTPUT_ON_FAILURE=1 ctest -j 2 diff --git a/Telegram/ThirdParty/Catch/CMake/FindGcov.cmake b/Telegram/ThirdParty/Catch/CMake/FindGcov.cmake new file mode 100644 index 000000000..6ffd6eacb --- /dev/null +++ b/Telegram/ThirdParty/Catch/CMake/FindGcov.cmake @@ -0,0 +1,157 @@ +# This file is part of CMake-codecov. +# +# Copyright (c) +# 2015-2017 RWTH Aachen University, Federal Republic of Germany +# +# See the LICENSE file in the package base directory for details +# +# Written by Alexander Haase, alexander.haase@rwth-aachen.de +# + + +# include required Modules +include(FindPackageHandleStandardArgs) + + +# Search for gcov binary. +set(CMAKE_REQUIRED_QUIET_SAVE ${CMAKE_REQUIRED_QUIET}) +set(CMAKE_REQUIRED_QUIET ${codecov_FIND_QUIETLY}) + +get_property(ENABLED_LANGUAGES GLOBAL PROPERTY ENABLED_LANGUAGES) +foreach (LANG ${ENABLED_LANGUAGES}) + # Gcov evaluation is dependend on the used compiler. Check gcov support for + # each compiler that is used. If gcov binary was already found for this + # compiler, do not try to find it again. + if (NOT GCOV_${CMAKE_${LANG}_COMPILER_ID}_BIN) + get_filename_component(COMPILER_PATH "${CMAKE_${LANG}_COMPILER}" PATH) + + if ("${CMAKE_${LANG}_COMPILER_ID}" STREQUAL "GNU") + # Some distributions like OSX (homebrew) ship gcov with the compiler + # version appended as gcov-x. To find this binary we'll build the + # suggested binary name with the compiler version. + string(REGEX MATCH "^[0-9]+" GCC_VERSION + "${CMAKE_${LANG}_COMPILER_VERSION}") + + find_program(GCOV_BIN NAMES gcov-${GCC_VERSION} gcov + HINTS ${COMPILER_PATH}) + + elseif ("${CMAKE_${LANG}_COMPILER_ID}" STREQUAL "Clang") + # Some distributions like Debian ship llvm-cov with the compiler + # version appended as llvm-cov-x.y. To find this binary we'll build + # the suggested binary name with the compiler version. + string(REGEX MATCH "^[0-9]+.[0-9]+" LLVM_VERSION + "${CMAKE_${LANG}_COMPILER_VERSION}") + + # llvm-cov prior version 3.5 seems to be not working with coverage + # evaluation tools, but these versions are compatible with the gcc + # gcov tool. + if(LLVM_VERSION VERSION_GREATER 3.4) + find_program(LLVM_COV_BIN NAMES "llvm-cov-${LLVM_VERSION}" + "llvm-cov" HINTS ${COMPILER_PATH}) + mark_as_advanced(LLVM_COV_BIN) + + if (LLVM_COV_BIN) + find_program(LLVM_COV_WRAPPER "llvm-cov-wrapper" PATHS + ${CMAKE_MODULE_PATH}) + if (LLVM_COV_WRAPPER) + set(GCOV_BIN "${LLVM_COV_WRAPPER}" CACHE FILEPATH "") + + # set additional parameters + set(GCOV_${CMAKE_${LANG}_COMPILER_ID}_ENV + "LLVM_COV_BIN=${LLVM_COV_BIN}" CACHE STRING + "Environment variables for llvm-cov-wrapper.") + mark_as_advanced(GCOV_${CMAKE_${LANG}_COMPILER_ID}_ENV) + endif () + endif () + endif () + + if (NOT GCOV_BIN) + # Fall back to gcov binary if llvm-cov was not found or is + # incompatible. This is the default on OSX, but may crash on + # recent Linux versions. + find_program(GCOV_BIN gcov HINTS ${COMPILER_PATH}) + endif () + endif () + + + if (GCOV_BIN) + set(GCOV_${CMAKE_${LANG}_COMPILER_ID}_BIN "${GCOV_BIN}" CACHE STRING + "${LANG} gcov binary.") + + if (NOT CMAKE_REQUIRED_QUIET) + message("-- Found gcov evaluation for " + "${CMAKE_${LANG}_COMPILER_ID}: ${GCOV_BIN}") + endif() + + unset(GCOV_BIN CACHE) + endif () + endif () +endforeach () + + + + +# Add a new global target for all gcov targets. This target could be used to +# generate the gcov files for the whole project instead of calling -gcov +# for each target. +if (NOT TARGET gcov) + add_custom_target(gcov) +endif (NOT TARGET gcov) + + + +# This function will add gcov evaluation for target . Only sources of +# this target will be evaluated and no dependencies will be added. It will call +# Gcov on any source file of once and store the gcov file in the same +# directory. +function (add_gcov_target TNAME) + set(TDIR ${CMAKE_CURRENT_BINARY_DIR}/CMakeFiles/${TNAME}.dir) + + # We don't have to check, if the target has support for coverage, thus this + # will be checked by add_coverage_target in Findcoverage.cmake. Instead we + # have to determine which gcov binary to use. + get_target_property(TSOURCES ${TNAME} SOURCES) + set(SOURCES "") + set(TCOMPILER "") + foreach (FILE ${TSOURCES}) + codecov_path_of_source(${FILE} FILE) + if (NOT "${FILE}" STREQUAL "") + codecov_lang_of_source(${FILE} LANG) + if (NOT "${LANG}" STREQUAL "") + list(APPEND SOURCES "${FILE}") + set(TCOMPILER ${CMAKE_${LANG}_COMPILER_ID}) + endif () + endif () + endforeach () + + # If no gcov binary was found, coverage data can't be evaluated. + if (NOT GCOV_${TCOMPILER}_BIN) + message(WARNING "No coverage evaluation binary found for ${TCOMPILER}.") + return() + endif () + + set(GCOV_BIN "${GCOV_${TCOMPILER}_BIN}") + set(GCOV_ENV "${GCOV_${TCOMPILER}_ENV}") + + + set(BUFFER "") + foreach(FILE ${SOURCES}) + get_filename_component(FILE_PATH "${TDIR}/${FILE}" PATH) + + # call gcov + add_custom_command(OUTPUT ${TDIR}/${FILE}.gcov + COMMAND ${GCOV_ENV} ${GCOV_BIN} ${TDIR}/${FILE}.gcno > /dev/null + DEPENDS ${TNAME} ${TDIR}/${FILE}.gcno + WORKING_DIRECTORY ${FILE_PATH} + ) + + list(APPEND BUFFER ${TDIR}/${FILE}.gcov) + endforeach() + + + # add target for gcov evaluation of + add_custom_target(${TNAME}-gcov DEPENDS ${BUFFER}) + + # add evaluation target to the global gcov target. + add_dependencies(gcov ${TNAME}-gcov) +endfunction (add_gcov_target) diff --git a/Telegram/ThirdParty/Catch/CMake/FindLcov.cmake b/Telegram/ThirdParty/Catch/CMake/FindLcov.cmake new file mode 100644 index 000000000..beb925ae0 --- /dev/null +++ b/Telegram/ThirdParty/Catch/CMake/FindLcov.cmake @@ -0,0 +1,354 @@ +# This file is part of CMake-codecov. +# +# Copyright (c) +# 2015-2017 RWTH Aachen University, Federal Republic of Germany +# +# See the LICENSE file in the package base directory for details +# +# Written by Alexander Haase, alexander.haase@rwth-aachen.de +# + + +# configuration +set(LCOV_DATA_PATH "${CMAKE_BINARY_DIR}/lcov/data") +set(LCOV_DATA_PATH_INIT "${LCOV_DATA_PATH}/init") +set(LCOV_DATA_PATH_CAPTURE "${LCOV_DATA_PATH}/capture") +set(LCOV_HTML_PATH "${CMAKE_BINARY_DIR}/lcov/html") + + + + +# Search for Gcov which is used by Lcov. +find_package(Gcov) + + + + +# This function will add lcov evaluation for target . Only sources of +# this target will be evaluated and no dependencies will be added. It will call +# geninfo on any source file of once and store the info file in the same +# directory. +# +# Note: This function is only a wrapper to define this function always, even if +# coverage is not supported by the compiler or disabled. This function must +# be defined here, because the module will be exited, if there is no coverage +# support by the compiler or it is disabled by the user. +function (add_lcov_target TNAME) + if (LCOV_FOUND) + # capture initial coverage data + lcov_capture_initial_tgt(${TNAME}) + + # capture coverage data after execution + lcov_capture_tgt(${TNAME}) + endif () +endfunction (add_lcov_target) + + + + +# include required Modules +include(FindPackageHandleStandardArgs) + +# Search for required lcov binaries. +find_program(LCOV_BIN lcov) +find_program(GENINFO_BIN geninfo) +find_program(GENHTML_BIN genhtml) +find_package_handle_standard_args(lcov + REQUIRED_VARS LCOV_BIN GENINFO_BIN GENHTML_BIN +) + +# enable genhtml C++ demangeling, if c++filt is found. +set(GENHTML_CPPFILT_FLAG "") +find_program(CPPFILT_BIN c++filt) +if (NOT CPPFILT_BIN STREQUAL "") + set(GENHTML_CPPFILT_FLAG "--demangle-cpp") +endif (NOT CPPFILT_BIN STREQUAL "") + +# enable no-external flag for lcov, if available. +if (GENINFO_BIN AND NOT DEFINED GENINFO_EXTERN_FLAG) + set(FLAG "") + execute_process(COMMAND ${GENINFO_BIN} --help OUTPUT_VARIABLE GENINFO_HELP) + string(REGEX MATCH "external" GENINFO_RES "${GENINFO_HELP}") + if (GENINFO_RES) + set(FLAG "--no-external") + endif () + + set(GENINFO_EXTERN_FLAG "${FLAG}" + CACHE STRING "Geninfo flag to exclude system sources.") +endif () + +# If Lcov was not found, exit module now. +if (NOT LCOV_FOUND) + return() +endif (NOT LCOV_FOUND) + + + + +# Create directories to be used. +file(MAKE_DIRECTORY ${LCOV_DATA_PATH_INIT}) +file(MAKE_DIRECTORY ${LCOV_DATA_PATH_CAPTURE}) + +set(LCOV_REMOVE_PATTERNS "") + +# This function will merge lcov files to a single target file. Additional lcov +# flags may be set with setting LCOV_EXTRA_FLAGS before calling this function. +function (lcov_merge_files OUTFILE ...) + # Remove ${OUTFILE} from ${ARGV} and generate lcov parameters with files. + list(REMOVE_AT ARGV 0) + + # Generate merged file. + string(REPLACE "${CMAKE_BINARY_DIR}/" "" FILE_REL "${OUTFILE}") + add_custom_command(OUTPUT "${OUTFILE}.raw" + COMMAND cat ${ARGV} > ${OUTFILE}.raw + DEPENDS ${ARGV} + COMMENT "Generating ${FILE_REL}" + ) + + add_custom_command(OUTPUT "${OUTFILE}" + COMMAND ${LCOV_BIN} --quiet -a ${OUTFILE}.raw --output-file ${OUTFILE} + --base-directory ${PROJECT_SOURCE_DIR} ${LCOV_EXTRA_FLAGS} + COMMAND ${LCOV_BIN} --quiet -r ${OUTFILE} ${LCOV_REMOVE_PATTERNS} + --output-file ${OUTFILE} ${LCOV_EXTRA_FLAGS} + DEPENDS ${OUTFILE}.raw + COMMENT "Post-processing ${FILE_REL}" + ) +endfunction () + + + + +# Add a new global target to generate initial coverage reports for all targets. +# This target will be used to generate the global initial info file, which is +# used to gather even empty report data. +if (NOT TARGET lcov-capture-init) + add_custom_target(lcov-capture-init) + set(LCOV_CAPTURE_INIT_FILES "" CACHE INTERNAL "") +endif (NOT TARGET lcov-capture-init) + + +# This function will add initial capture of coverage data for target , +# which is needed to get also data for objects, which were not loaded at +# execution time. It will call geninfo for every source file of once and +# store the info file in the same directory. +function (lcov_capture_initial_tgt TNAME) + # We don't have to check, if the target has support for coverage, thus this + # will be checked by add_coverage_target in Findcoverage.cmake. Instead we + # have to determine which gcov binary to use. + get_target_property(TSOURCES ${TNAME} SOURCES) + set(SOURCES "") + set(TCOMPILER "") + foreach (FILE ${TSOURCES}) + codecov_path_of_source(${FILE} FILE) + if (NOT "${FILE}" STREQUAL "") + codecov_lang_of_source(${FILE} LANG) + if (NOT "${LANG}" STREQUAL "") + list(APPEND SOURCES "${FILE}") + set(TCOMPILER ${CMAKE_${LANG}_COMPILER_ID}) + endif () + endif () + endforeach () + + # If no gcov binary was found, coverage data can't be evaluated. + if (NOT GCOV_${TCOMPILER}_BIN) + message(WARNING "No coverage evaluation binary found for ${TCOMPILER}.") + return() + endif () + + set(GCOV_BIN "${GCOV_${TCOMPILER}_BIN}") + set(GCOV_ENV "${GCOV_${TCOMPILER}_ENV}") + + + set(TDIR ${CMAKE_CURRENT_BINARY_DIR}/CMakeFiles/${TNAME}.dir) + set(GENINFO_FILES "") + foreach(FILE ${SOURCES}) + # generate empty coverage files + set(OUTFILE "${TDIR}/${FILE}.info.init") + list(APPEND GENINFO_FILES ${OUTFILE}) + + add_custom_command(OUTPUT ${OUTFILE} COMMAND ${GCOV_ENV} ${GENINFO_BIN} + --quiet --base-directory ${PROJECT_SOURCE_DIR} --initial + --gcov-tool ${GCOV_BIN} --output-filename ${OUTFILE} + ${GENINFO_EXTERN_FLAG} ${TDIR}/${FILE}.gcno + DEPENDS ${TNAME} + COMMENT "Capturing initial coverage data for ${FILE}" + ) + endforeach() + + # Concatenate all files generated by geninfo to a single file per target. + set(OUTFILE "${LCOV_DATA_PATH_INIT}/${TNAME}.info") + set(LCOV_EXTRA_FLAGS "--initial") + lcov_merge_files("${OUTFILE}" ${GENINFO_FILES}) + add_custom_target(${TNAME}-capture-init ALL DEPENDS ${OUTFILE}) + + # add geninfo file generation to global lcov-geninfo target + add_dependencies(lcov-capture-init ${TNAME}-capture-init) + set(LCOV_CAPTURE_INIT_FILES "${LCOV_CAPTURE_INIT_FILES}" + "${OUTFILE}" CACHE INTERNAL "" + ) +endfunction (lcov_capture_initial_tgt) + + +# This function will generate the global info file for all targets. It has to be +# called after all other CMake functions in the root CMakeLists.txt file, to get +# a full list of all targets that generate coverage data. +function (lcov_capture_initial) + # Skip this function (and do not create the following targets), if there are + # no input files. + if ("${LCOV_CAPTURE_INIT_FILES}" STREQUAL "") + return() + endif () + + # Add a new target to merge the files of all targets. + set(OUTFILE "${LCOV_DATA_PATH_INIT}/all_targets.info") + lcov_merge_files("${OUTFILE}" ${LCOV_CAPTURE_INIT_FILES}) + add_custom_target(lcov-geninfo-init ALL DEPENDS ${OUTFILE} + lcov-capture-init + ) +endfunction (lcov_capture_initial) + + + + +# Add a new global target to generate coverage reports for all targets. This +# target will be used to generate the global info file. +if (NOT TARGET lcov-capture) + add_custom_target(lcov-capture) + set(LCOV_CAPTURE_FILES "" CACHE INTERNAL "") +endif (NOT TARGET lcov-capture) + + +# This function will add capture of coverage data for target , which is +# needed to get also data for objects, which were not loaded at execution time. +# It will call geninfo for every source file of once and store the info +# file in the same directory. +function (lcov_capture_tgt TNAME) + # We don't have to check, if the target has support for coverage, thus this + # will be checked by add_coverage_target in Findcoverage.cmake. Instead we + # have to determine which gcov binary to use. + get_target_property(TSOURCES ${TNAME} SOURCES) + set(SOURCES "") + set(TCOMPILER "") + foreach (FILE ${TSOURCES}) + codecov_path_of_source(${FILE} FILE) + if (NOT "${FILE}" STREQUAL "") + codecov_lang_of_source(${FILE} LANG) + if (NOT "${LANG}" STREQUAL "") + list(APPEND SOURCES "${FILE}") + set(TCOMPILER ${CMAKE_${LANG}_COMPILER_ID}) + endif () + endif () + endforeach () + + # If no gcov binary was found, coverage data can't be evaluated. + if (NOT GCOV_${TCOMPILER}_BIN) + message(WARNING "No coverage evaluation binary found for ${TCOMPILER}.") + return() + endif () + + set(GCOV_BIN "${GCOV_${TCOMPILER}_BIN}") + set(GCOV_ENV "${GCOV_${TCOMPILER}_ENV}") + + + set(TDIR ${CMAKE_CURRENT_BINARY_DIR}/CMakeFiles/${TNAME}.dir) + set(GENINFO_FILES "") + foreach(FILE ${SOURCES}) + # Generate coverage files. If no .gcda file was generated during + # execution, the empty coverage file will be used instead. + set(OUTFILE "${TDIR}/${FILE}.info") + list(APPEND GENINFO_FILES ${OUTFILE}) + + add_custom_command(OUTPUT ${OUTFILE} + COMMAND test -f "${TDIR}/${FILE}.gcda" + && ${GCOV_ENV} ${GENINFO_BIN} --quiet --base-directory + ${PROJECT_SOURCE_DIR} --gcov-tool ${GCOV_BIN} + --output-filename ${OUTFILE} ${GENINFO_EXTERN_FLAG} + ${TDIR}/${FILE}.gcda + || cp ${OUTFILE}.init ${OUTFILE} + DEPENDS ${TNAME} ${TNAME}-capture-init + COMMENT "Capturing coverage data for ${FILE}" + ) + endforeach() + + # Concatenate all files generated by geninfo to a single file per target. + set(OUTFILE "${LCOV_DATA_PATH_CAPTURE}/${TNAME}.info") + lcov_merge_files("${OUTFILE}" ${GENINFO_FILES}) + add_custom_target(${TNAME}-geninfo DEPENDS ${OUTFILE}) + + # add geninfo file generation to global lcov-capture target + add_dependencies(lcov-capture ${TNAME}-geninfo) + set(LCOV_CAPTURE_FILES "${LCOV_CAPTURE_FILES}" "${OUTFILE}" CACHE INTERNAL + "" + ) + + # Add target for generating html output for this target only. + file(MAKE_DIRECTORY ${LCOV_HTML_PATH}/${TNAME}) + add_custom_target(${TNAME}-genhtml + COMMAND ${GENHTML_BIN} --quiet --sort --prefix ${PROJECT_SOURCE_DIR} + --baseline-file ${LCOV_DATA_PATH_INIT}/${TNAME}.info + --output-directory ${LCOV_HTML_PATH}/${TNAME} + --title "${CMAKE_PROJECT_NAME} - target ${TNAME}" + ${GENHTML_CPPFILT_FLAG} ${OUTFILE} + DEPENDS ${TNAME}-geninfo ${TNAME}-capture-init + ) +endfunction (lcov_capture_tgt) + + +# This function will generate the global info file for all targets. It has to be +# called after all other CMake functions in the root CMakeLists.txt file, to get +# a full list of all targets that generate coverage data. +function (lcov_capture) + # Skip this function (and do not create the following targets), if there are + # no input files. + if ("${LCOV_CAPTURE_FILES}" STREQUAL "") + return() + endif () + + # Add a new target to merge the files of all targets. + set(OUTFILE "${LCOV_DATA_PATH_CAPTURE}/all_targets.info") + lcov_merge_files("${OUTFILE}" ${LCOV_CAPTURE_FILES}) + add_custom_target(lcov-geninfo DEPENDS ${OUTFILE} lcov-capture) + + # Add a new global target for all lcov targets. This target could be used to + # generate the lcov html output for the whole project instead of calling + # -geninfo and -genhtml for each target. It will also be + # used to generate a html site for all project data together instead of one + # for each target. + if (NOT TARGET lcov) + file(MAKE_DIRECTORY ${LCOV_HTML_PATH}/all_targets) + add_custom_target(lcov + COMMAND ${GENHTML_BIN} --quiet --sort + --baseline-file ${LCOV_DATA_PATH_INIT}/all_targets.info + --output-directory ${LCOV_HTML_PATH}/all_targets + --title "${CMAKE_PROJECT_NAME}" --prefix "${PROJECT_SOURCE_DIR}" + ${GENHTML_CPPFILT_FLAG} ${OUTFILE} + DEPENDS lcov-geninfo-init lcov-geninfo + ) + endif () +endfunction (lcov_capture) + + + + +# Add a new global target to generate the lcov html report for the whole project +# instead of calling -genhtml for each target (to create an own report +# for each target). Instead of the lcov target it does not require geninfo for +# all targets, so you have to call -geninfo to generate the info files +# the targets you'd like to have in your report or lcov-geninfo for generating +# info files for all targets before calling lcov-genhtml. +file(MAKE_DIRECTORY ${LCOV_HTML_PATH}/selected_targets) +if (NOT TARGET lcov-genhtml) + add_custom_target(lcov-genhtml + COMMAND ${GENHTML_BIN} + --quiet + --output-directory ${LCOV_HTML_PATH}/selected_targets + --title \"${CMAKE_PROJECT_NAME} - targets `find + ${LCOV_DATA_PATH_CAPTURE} -name \"*.info\" ! -name + \"all_targets.info\" -exec basename {} .info \\\;`\" + --prefix ${PROJECT_SOURCE_DIR} + --sort + ${GENHTML_CPPFILT_FLAG} + `find ${LCOV_DATA_PATH_CAPTURE} -name \"*.info\" ! -name + \"all_targets.info\"` + ) +endif (NOT TARGET lcov-genhtml) diff --git a/Telegram/ThirdParty/Catch/CMake/Findcodecov.cmake b/Telegram/ThirdParty/Catch/CMake/Findcodecov.cmake new file mode 100644 index 000000000..fa135fa8f --- /dev/null +++ b/Telegram/ThirdParty/Catch/CMake/Findcodecov.cmake @@ -0,0 +1,258 @@ +# This file is part of CMake-codecov. +# +# Copyright (c) +# 2015-2017 RWTH Aachen University, Federal Republic of Germany +# +# See the LICENSE file in the package base directory for details +# +# Written by Alexander Haase, alexander.haase@rwth-aachen.de +# + + +# Add an option to choose, if coverage should be enabled or not. If enabled +# marked targets will be build with coverage support and appropriate targets +# will be added. If disabled coverage will be ignored for *ALL* targets. +option(ENABLE_COVERAGE "Enable coverage build." OFF) + +set(COVERAGE_FLAG_CANDIDATES + # gcc and clang + "-O0 -g -fprofile-arcs -ftest-coverage" + + # gcc and clang fallback + "-O0 -g --coverage" +) + + +# Add coverage support for target ${TNAME} and register target for coverage +# evaluation. If coverage is disabled or not supported, this function will +# simply do nothing. +# +# Note: This function is only a wrapper to define this function always, even if +# coverage is not supported by the compiler or disabled. This function must +# be defined here, because the module will be exited, if there is no coverage +# support by the compiler or it is disabled by the user. +function (add_coverage TNAME) + # only add coverage for target, if coverage is support and enabled. + if (ENABLE_COVERAGE) + foreach (TNAME ${ARGV}) + add_coverage_target(${TNAME}) + endforeach () + endif () +endfunction (add_coverage) + + +# Add global target to gather coverage information after all targets have been +# added. Other evaluation functions could be added here, after checks for the +# specific module have been passed. +# +# Note: This function is only a wrapper to define this function always, even if +# coverage is not supported by the compiler or disabled. This function must +# be defined here, because the module will be exited, if there is no coverage +# support by the compiler or it is disabled by the user. +function (coverage_evaluate) + # add lcov evaluation + if (LCOV_FOUND) + lcov_capture_initial() + lcov_capture() + endif (LCOV_FOUND) +endfunction () + + +# Exit this module, if coverage is disabled. add_coverage is defined before this +# return, so this module can be exited now safely without breaking any build- +# scripts. +if (NOT ENABLE_COVERAGE) + return() +endif () + + + + +# Find the reuired flags foreach language. +set(CMAKE_REQUIRED_QUIET_SAVE ${CMAKE_REQUIRED_QUIET}) +set(CMAKE_REQUIRED_QUIET ${codecov_FIND_QUIETLY}) + +get_property(ENABLED_LANGUAGES GLOBAL PROPERTY ENABLED_LANGUAGES) +foreach (LANG ${ENABLED_LANGUAGES}) + # Coverage flags are not dependend on language, but the used compiler. So + # instead of searching flags foreach language, search flags foreach compiler + # used. + set(COMPILER ${CMAKE_${LANG}_COMPILER_ID}) + if (NOT COVERAGE_${COMPILER}_FLAGS) + foreach (FLAG ${COVERAGE_FLAG_CANDIDATES}) + if(NOT CMAKE_REQUIRED_QUIET) + message(STATUS "Try ${COMPILER} code coverage flag = [${FLAG}]") + endif() + + set(CMAKE_REQUIRED_FLAGS "${FLAG}") + unset(COVERAGE_FLAG_DETECTED CACHE) + + if (${LANG} STREQUAL "C") + include(CheckCCompilerFlag) + check_c_compiler_flag("${FLAG}" COVERAGE_FLAG_DETECTED) + + elseif (${LANG} STREQUAL "CXX") + include(CheckCXXCompilerFlag) + check_cxx_compiler_flag("${FLAG}" COVERAGE_FLAG_DETECTED) + + elseif (${LANG} STREQUAL "Fortran") + # CheckFortranCompilerFlag was introduced in CMake 3.x. To be + # compatible with older Cmake versions, we will check if this + # module is present before we use it. Otherwise we will define + # Fortran coverage support as not available. + include(CheckFortranCompilerFlag OPTIONAL + RESULT_VARIABLE INCLUDED) + if (INCLUDED) + check_fortran_compiler_flag("${FLAG}" + COVERAGE_FLAG_DETECTED) + elseif (NOT CMAKE_REQUIRED_QUIET) + message("-- Performing Test COVERAGE_FLAG_DETECTED") + message("-- Performing Test COVERAGE_FLAG_DETECTED - Failed" + " (Check not supported)") + endif () + endif() + + if (COVERAGE_FLAG_DETECTED) + set(COVERAGE_${COMPILER}_FLAGS "${FLAG}" + CACHE STRING "${COMPILER} flags for code coverage.") + mark_as_advanced(COVERAGE_${COMPILER}_FLAGS) + break() + else () + message(WARNING "Code coverage is not available for ${COMPILER}" + " compiler. Targets using this compiler will be " + "compiled without it.") + endif () + endforeach () + endif () +endforeach () + +set(CMAKE_REQUIRED_QUIET ${CMAKE_REQUIRED_QUIET_SAVE}) + + + + +# Helper function to get the language of a source file. +function (codecov_lang_of_source FILE RETURN_VAR) + get_filename_component(FILE_EXT "${FILE}" EXT) + string(TOLOWER "${FILE_EXT}" FILE_EXT) + string(SUBSTRING "${FILE_EXT}" 1 -1 FILE_EXT) + + get_property(ENABLED_LANGUAGES GLOBAL PROPERTY ENABLED_LANGUAGES) + foreach (LANG ${ENABLED_LANGUAGES}) + list(FIND CMAKE_${LANG}_SOURCE_FILE_EXTENSIONS "${FILE_EXT}" TEMP) + if (NOT ${TEMP} EQUAL -1) + set(${RETURN_VAR} "${LANG}" PARENT_SCOPE) + return() + endif () + endforeach() + + set(${RETURN_VAR} "" PARENT_SCOPE) +endfunction () + + +# Helper function to get the relative path of the source file destination path. +# This path is needed by FindGcov and FindLcov cmake files to locate the +# captured data. +function (codecov_path_of_source FILE RETURN_VAR) + string(REGEX MATCH "TARGET_OBJECTS:([^ >]+)" _source ${FILE}) + + # If expression was found, SOURCEFILE is a generator-expression for an + # object library. Currently we found no way to call this function automatic + # for the referenced target, so it must be called in the directoryso of the + # object library definition. + if (NOT "${_source}" STREQUAL "") + set(${RETURN_VAR} "" PARENT_SCOPE) + return() + endif () + + + string(REPLACE "${CMAKE_CURRENT_BINARY_DIR}/" "" FILE "${FILE}") + if(IS_ABSOLUTE ${FILE}) + file(RELATIVE_PATH FILE ${CMAKE_CURRENT_SOURCE_DIR} ${FILE}) + endif() + + # get the right path for file + string(REPLACE ".." "__" PATH "${FILE}") + + set(${RETURN_VAR} "${PATH}" PARENT_SCOPE) +endfunction() + + + + +# Add coverage support for target ${TNAME} and register target for coverage +# evaluation. +function(add_coverage_target TNAME) + # Check if all sources for target use the same compiler. If a target uses + # e.g. C and Fortran mixed and uses different compilers (e.g. clang and + # gfortran) this can trigger huge problems, because different compilers may + # use different implementations for code coverage. + get_target_property(TSOURCES ${TNAME} SOURCES) + set(TARGET_COMPILER "") + set(ADDITIONAL_FILES "") + foreach (FILE ${TSOURCES}) + # If expression was found, FILE is a generator-expression for an object + # library. Object libraries will be ignored. + string(REGEX MATCH "TARGET_OBJECTS:([^ >]+)" _file ${FILE}) + if ("${_file}" STREQUAL "") + codecov_lang_of_source(${FILE} LANG) + if (LANG) + list(APPEND TARGET_COMPILER ${CMAKE_${LANG}_COMPILER_ID}) + + list(APPEND ADDITIONAL_FILES "${FILE}.gcno") + list(APPEND ADDITIONAL_FILES "${FILE}.gcda") + endif () + endif () + endforeach () + + list(REMOVE_DUPLICATES TARGET_COMPILER) + list(LENGTH TARGET_COMPILER NUM_COMPILERS) + + if (NUM_COMPILERS GREATER 1) + message(WARNING "Can't use code coverage for target ${TNAME}, because " + "it will be compiled by incompatible compilers. Target will be " + "compiled without code coverage.") + return() + + elseif (NUM_COMPILERS EQUAL 0) + message(WARNING "Can't use code coverage for target ${TNAME}, because " + "it uses an unknown compiler. Target will be compiled without " + "code coverage.") + return() + + elseif (NOT DEFINED "COVERAGE_${TARGET_COMPILER}_FLAGS") + # A warning has been printed before, so just return if flags for this + # compiler aren't available. + return() + endif() + + + # enable coverage for target + set_property(TARGET ${TNAME} APPEND_STRING + PROPERTY COMPILE_FLAGS " ${COVERAGE_${TARGET_COMPILER}_FLAGS}") + set_property(TARGET ${TNAME} APPEND_STRING + PROPERTY LINK_FLAGS " ${COVERAGE_${TARGET_COMPILER}_FLAGS}") + + + # Add gcov files generated by compiler to clean target. + set(CLEAN_FILES "") + foreach (FILE ${ADDITIONAL_FILES}) + codecov_path_of_source(${FILE} FILE) + list(APPEND CLEAN_FILES "CMakeFiles/${TNAME}.dir/${FILE}") + endforeach() + + set_directory_properties(PROPERTIES ADDITIONAL_MAKE_CLEAN_FILES + "${CLEAN_FILES}") + + + add_gcov_target(${TNAME}) + add_lcov_target(${TNAME}) +endfunction(add_coverage_target) + + + + +# Include modules for parsing the collected data and output it in a readable +# format (like gcov and lcov). +find_package(Gcov) +find_package(Lcov) diff --git a/Telegram/ThirdParty/Catch/CMake/llvm-cov-wrapper b/Telegram/ThirdParty/Catch/CMake/llvm-cov-wrapper new file mode 100755 index 000000000..2ac331024 --- /dev/null +++ b/Telegram/ThirdParty/Catch/CMake/llvm-cov-wrapper @@ -0,0 +1,56 @@ +#!/bin/sh + +# This file is part of CMake-codecov. +# +# Copyright (c) +# 2015-2017 RWTH Aachen University, Federal Republic of Germany +# +# See the LICENSE file in the package base directory for details +# +# Written by Alexander Haase, alexander.haase@rwth-aachen.de +# + +if [ -z "$LLVM_COV_BIN" ] +then + echo "LLVM_COV_BIN not set!" >& 2 + exit 1 +fi + + +# Get LLVM version to find out. +LLVM_VERSION=$($LLVM_COV_BIN -version | grep -i "LLVM version" \ + | sed "s/^\([A-Za-z ]*\)\([0-9]\).\([0-9]\).*$/\2.\3/g") + +if [ "$1" = "-v" ] +then + echo "llvm-cov-wrapper $LLVM_VERSION" + exit 0 +fi + + +if [ -n "$LLVM_VERSION" ] +then + MAJOR=$(echo $LLVM_VERSION | cut -d'.' -f1) + MINOR=$(echo $LLVM_VERSION | cut -d'.' -f2) + + if [ $MAJOR -eq 3 ] && [ $MINOR -le 4 ] + then + if [ -f "$1" ] + then + filename=$(basename "$1") + extension="${filename##*.}" + + case "$extension" in + "gcno") exec $LLVM_COV_BIN --gcno="$1" ;; + "gcda") exec $LLVM_COV_BIN --gcda="$1" ;; + esac + fi + fi + + if [ $MAJOR -eq 3 ] && [ $MINOR -le 5 ] + then + exec $LLVM_COV_BIN $@ + fi +fi + +exec $LLVM_COV_BIN gcov $@ diff --git a/Telegram/ThirdParty/Catch/CMakeLists.txt b/Telegram/ThirdParty/Catch/CMakeLists.txt index 3792bad62..f42f57e00 100644 --- a/Telegram/ThirdParty/Catch/CMakeLists.txt +++ b/Telegram/ThirdParty/Catch/CMakeLists.txt @@ -1,9 +1,19 @@ -cmake_minimum_required(VERSION 3.0) +cmake_minimum_required(VERSION 3.1) -project(CatchSelfTest) +# detect if Catch is being bundled, +# disable testsuite in that case +if(NOT DEFINED PROJECT_NAME) + set(NOT_SUBPROJECT ON) +endif() -option(USE_VALGRIND "Perform SelfTests with Valgrind" OFF) -option(BUILD_EXAMPLES "Build documentation examples" OFF) +project(Catch2 LANGUAGES CXX VERSION 2.2.0) + +include(GNUInstallDirs) + +option(CATCH_USE_VALGRIND "Perform SelfTests with Valgrind" OFF) +option(CATCH_BUILD_EXAMPLES "Build documentation examples" OFF) +option(CATCH_ENABLE_COVERAGE "Generate coverage for codecov.io" OFF) +option(CATCH_ENABLE_WERROR "Enable all warnings as errors" ON) set_property(GLOBAL PROPERTY USE_FOLDERS ON) @@ -12,7 +22,6 @@ set(CATCH_DIR ${CMAKE_CURRENT_SOURCE_DIR}) set(SELF_TEST_DIR ${CATCH_DIR}/projects/SelfTest) set(BENCHMARK_DIR ${CATCH_DIR}/projects/Benchmark) set(HEADER_DIR ${CATCH_DIR}/include) -set(CATCH_VERSION_NUMBER 2.0.1) if(USE_WMAIN) set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} /ENTRY:wmainCRTStartup") @@ -178,6 +187,7 @@ set(INTERNAL_HEADERS ${HEADER_DIR}/internal/catch_timer.h ${HEADER_DIR}/internal/catch_tostring.h ${HEADER_DIR}/internal/catch_totals.h + ${HEADER_DIR}/internal/catch_uncaught_exceptions.h ${HEADER_DIR}/internal/catch_user_interfaces.h ${HEADER_DIR}/internal/catch_version.h ${HEADER_DIR}/internal/catch_wildcard_pattern.h @@ -238,6 +248,7 @@ set(IMPL_SOURCES ${HEADER_DIR}/internal/catch_timer.cpp ${HEADER_DIR}/internal/catch_tostring.cpp ${HEADER_DIR}/internal/catch_totals.cpp + ${HEADER_DIR}/internal/catch_uncaught_exceptions.cpp ${HEADER_DIR}/internal/catch_version.cpp ${HEADER_DIR}/internal/catch_wildcard_pattern.cpp ${HEADER_DIR}/internal/catch_xmlwriter.cpp @@ -280,11 +291,22 @@ set(HEADERS SOURCE_GROUP("Tests" FILES ${TEST_SOURCES}) SOURCE_GROUP("Surrogates" FILES ${SURROGATE_SOURCES}) -# configure the executable # Projects consuming Catch via ExternalProject_Add might want to use install step # without building all of our selftests. -if (NOT NO_SELFTEST) + +if(DEFINED NO_SELFTEST) + message(DEPRECATION "*** CMake option NO_SELFTEST is deprecated; use BUILD_TESTING instead") + if (NO_SELFTEST) + set(BUILD_TESTING OFF CACHE BOOL "Disable Catch2 internal testsuite" FORCE) + else() + set(BUILD_TESTING ON CACHE BOOL "Disable Catch2 internal testsuite" FORCE) + endif() +endif() + +include(CTest) + +if (BUILD_TESTING AND NOT_SUBPROJECT) add_executable(SelfTest ${TEST_SOURCES} ${IMPL_SOURCES} ${REPORTER_SOURCES} ${SURROGATE_SOURCES} ${HEADERS}) target_include_directories(SelfTest PRIVATE ${HEADER_DIR}) @@ -299,59 +321,95 @@ if (NOT NO_SELFTEST) set_property(TARGET SelfTest PROPERTY CXX_STANDARD_REQUIRED ON) set_property(TARGET SelfTest PROPERTY CXX_EXTENSIONS OFF) - - # Add desired warnings - if ( CMAKE_CXX_COMPILER_ID MATCHES "Clang|AppleClang|GNU" ) - target_compile_options( SelfTest PRIVATE -Wall -Wextra -Wunreachable-code -Werror ) + if (CATCH_ENABLE_COVERAGE) + set(ENABLE_COVERAGE ON CACHE BOOL "Enable coverage build." FORCE) + list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_LIST_DIR}/CMake") + find_package(codecov) + add_coverage(SelfTest) + list(APPEND LCOV_REMOVE_PATTERNS "'/usr/*'") + coverage_evaluate() endif() - # Clang specific warning go here + + # Add per compiler options + if ( CMAKE_CXX_COMPILER_ID MATCHES "Clang|AppleClang|GNU" ) + target_compile_options( SelfTest PRIVATE -Wall -Wextra -Wunreachable-code -Wpedantic) + if (CATCH_ENABLE_WERROR) + target_compile_options( SelfTest PRIVATE -Werror) + endif() + endif() + # Clang specific options go here if ( CMAKE_CXX_COMPILER_ID MATCHES "Clang" ) - # Actually keep these target_compile_options( SelfTest PRIVATE -Wweak-vtables -Wexit-time-destructors -Wglobal-constructors -Wmissing-noreturn ) endif() if ( CMAKE_CXX_COMPILER_ID MATCHES "MSVC" ) - target_compile_options( SelfTest PRIVATE /W4 /w44265 /WX /w44061 /w44062 ) + STRING(REGEX REPLACE "/W[0-9]" "/W4" CMAKE_CXX_FLAGS ${CMAKE_CXX_FLAGS}) # override default warning level + target_compile_options( SelfTest PRIVATE /w44265 /w44061 /w44062 ) + if (CATCH_ENABLE_WERROR) + target_compile_options( SelfTest PRIVATE /WX) + endif() + # Force MSVC to consider everything as encoded in utf-8 + target_compile_options( SelfTest PRIVATE /utf-8 ) endif() # configure unit tests via CTest - enable_testing() + include(CTest) add_test(NAME RunTests COMMAND $) - add_test(NAME ListTests COMMAND $ --list-tests) - set_tests_properties(ListTests PROPERTIES PASS_REGULAR_EXPRESSION "[0-9]+ test cases") + add_test(NAME ListTests COMMAND $ --list-tests --verbosity high) + set_tests_properties(ListTests PROPERTIES + PASS_REGULAR_EXPRESSION "[0-9]+ test cases" + FAIL_REGULAR_EXPRESSION "Hidden Test" + ) add_test(NAME ListTags COMMAND $ --list-tags) - set_tests_properties(ListTags PROPERTIES PASS_REGULAR_EXPRESSION "[0-9]+ tags") + set_tests_properties(ListTags PROPERTIES + PASS_REGULAR_EXPRESSION "[0-9]+ tags" + FAIL_REGULAR_EXPRESSION "[.]") + + add_test(NAME ListReporters COMMAND $ --list-reporters) + set_tests_properties(ListReporters PROPERTIES PASS_REGULAR_EXPRESSION "Available reporters:") + + add_test(NAME ListTestNamesOnly COMMAND $ --list-test-names-only) + set_tests_properties(ListTestNamesOnly PROPERTIES + PASS_REGULAR_EXPRESSION "Regex string matcher" + FAIL_REGULAR_EXPRESSION "Hidden Test") + + add_test(NAME NoAssertions COMMAND $ -w NoAssertions) + set_tests_properties(NoAssertions PROPERTIES PASS_REGULAR_EXPRESSION "No assertions in test case") + + add_test(NAME NoTest COMMAND $ -w NoTests "___nonexistent_test___") + set_tests_properties(NoTest PROPERTIES PASS_REGULAR_EXPRESSION "No test cases matched") # AppVeyor has a Python 2.7 in path, but doesn't have .py files as autorunnable add_test(NAME ApprovalTests COMMAND python ${CMAKE_CURRENT_SOURCE_DIR}/scripts/approvalTests.py $) set_tests_properties(ApprovalTests PROPERTIES FAIL_REGULAR_EXPRESSION "Results differed") - - if (USE_VALGRIND) + + if (CATCH_USE_VALGRIND) add_test(NAME ValgrindRunTests COMMAND valgrind --leak-check=full --error-exitcode=1 $) - add_test(NAME ValgrindListTests COMMAND valgrind --leak-check=full --error-exitcode=1 $ --list-tests) + add_test(NAME ValgrindListTests COMMAND valgrind --leak-check=full --error-exitcode=1 $ --list-tests --verbosity high) set_tests_properties(ValgrindListTests PROPERTIES PASS_REGULAR_EXPRESSION "definitely lost: 0 bytes in 0 blocks") add_test(NAME ValgrindListTags COMMAND valgrind --leak-check=full --error-exitcode=1 $ --list-tags) set_tests_properties(ValgrindListTags PROPERTIES PASS_REGULAR_EXPRESSION "definitely lost: 0 bytes in 0 blocks") endif() - + endif() # !NO_SELFTEST -if(BUILD_EXAMPLES) +if(CATCH_BUILD_EXAMPLES) add_subdirectory(examples) endif() +install(DIRECTORY "single_include/" DESTINATION "${CMAKE_INSTALL_INCLUDEDIR}/catch") -install(DIRECTORY "single_include/" DESTINATION "include/catch") +install(DIRECTORY docs/ DESTINATION "${CMAKE_INSTALL_DOCDIR}") ## Provide some pkg-config integration # Don't bother on Windows if(NOT WIN32 OR NOT CMAKE_HOST_SYSTEM_NAME MATCHES Windows) set(PKGCONFIG_INSTALL_DIR - "${CMAKE_INSTALL_PREFIX}/share/pkgconfig" + "${CMAKE_INSTALL_DATAROOTDIR}/pkgconfig" CACHE PATH "Path where catch.pc is installed" ) @@ -359,3 +417,38 @@ if(NOT WIN32 OR NOT CMAKE_HOST_SYSTEM_NAME MATCHES Windows) install(FILES ${CMAKE_CURRENT_BINARY_DIR}/catch.pc DESTINATION ${PKGCONFIG_INSTALL_DIR}) endif() + +# add catch as a 'linkable' target +add_library(Catch INTERFACE) + +# depend on some obvious c++11 features so the dependency is transitively added dependants +target_compile_features(Catch INTERFACE cxx_auto_type cxx_constexpr cxx_noexcept) + +target_include_directories(Catch + INTERFACE + $ + $ + $) + +# provide a namespaced alias for clients to 'link' against if catch is included as a sub-project +add_library(Catch2::Catch ALIAS Catch) + +set(CATCH_CMAKE_CONFIG_DESTINATION "${CMAKE_INSTALL_LIBDIR}/cmake/Catch2") + +# create and install an export set for catch target as Catch2::Catch +install(TARGETS Catch EXPORT Catch2Config DESTINATION ${CMAKE_INSTALL_LIBDIR}) + +install(EXPORT Catch2Config + NAMESPACE Catch2:: + DESTINATION ${CATCH_CMAKE_CONFIG_DESTINATION}) + +# install Catch2ConfigVersion.cmake file to handle versions in find_package +include(CMakePackageConfigHelpers) + +write_basic_package_version_file( + "${CMAKE_CURRENT_BINARY_DIR}/Catch2ConfigVersion.cmake" + COMPATIBILITY SameMajorVersion) + +install(FILES + "${CMAKE_CURRENT_BINARY_DIR}/Catch2ConfigVersion.cmake" + DESTINATION ${CATCH_CMAKE_CONFIG_DESTINATION}) diff --git a/Telegram/ThirdParty/Catch/README.md b/Telegram/ThirdParty/Catch/README.md index fc85b85e2..e07f26e77 100644 --- a/Telegram/ThirdParty/Catch/README.md +++ b/Telegram/ThirdParty/Catch/README.md @@ -2,15 +2,16 @@ ![catch logo](artwork/catch2-logo-small.png) [![Github Releases](https://img.shields.io/github/release/catchorg/catch2.svg)](https://github.com/catchorg/catch2/releases) -[![Build Status](https://travis-ci.org/catchorg/Catch2.svg)](https://travis-ci.org/catchorg/Catch2) -[![Build status](https://ci.appveyor.com/api/projects/status/hrtk60hv6tw6fght?svg=true)](https://ci.appveyor.com/project/catchorg/catch2) -[![Try online](https://img.shields.io/badge/try-online-blue.svg)](https://wandbox.org/permlink/tB8z0G3kMAIZkIca) +[![Build Status](https://travis-ci.org/catchorg/Catch2.svg?branch=master)](https://travis-ci.org/catchorg/Catch2) +[![Build status](https://ci.appveyor.com/api/projects/status/github/catchorg/Catch2?svg=true)](https://ci.appveyor.com/project/catchorg/catch2) +[![codecov](https://codecov.io/gh/catchorg/Catch2/branch/master/graph/badge.svg)](https://codecov.io/gh/catchorg/Catch2) +[![Try online](https://img.shields.io/badge/try-online-blue.svg)](https://wandbox.org/permlink/vOtfjd7LKmcj4JqD) -The latest version of the single header can be downloaded directly using this link +The latest version of the single header can be downloaded directly using this link ## Catch2 is released! -If you've been using an earlier version of Catch, please see the +If you've been using an earlier version of Catch, please see the Breaking Changes section of [the release notes](https://github.com/catchorg/Catch2/releases/tag/v2.0.1) before moving to Catch2. You might also like to read [this blog post](http://www.levelofindirection.com/journal/2017/11/3/catch2-released.html) for more details. diff --git a/Telegram/ThirdParty/Catch/appveyor.yml b/Telegram/ThirdParty/Catch/appveyor.yml index f3a2c5bde..847d3f62d 100644 --- a/Telegram/ThirdParty/Catch/appveyor.yml +++ b/Telegram/ThirdParty/Catch/appveyor.yml @@ -19,19 +19,51 @@ environment: - additional_flags: "/D_UNICODE /DUNICODE" wmain: 1 + coverage: 0 + + # Have a coverage dimension + - additional_flags: "" + wmain: 0 + coverage: 1 + + # Have an examples dimension + - additional_flags: "" + wmain: 0 + examples: 1 + matrix: exclude: - os: Visual Studio 2015 additional_flags: "/permissive- /std:c++latest" -init: - - git config --global core.autocrlf input - # Set build version to git commit-hash - - ps: Update-AppveyorBuild -Version "$($env:APPVEYOR_REPO_BRANCH) - $($env:APPVEYOR_REPO_COMMIT)" + - os: Visual Studio 2015 + additional_flags: "/D_UNICODE /DUNICODE" -# fetch repository as zip archive -shallow_clone: true + # Exclude unwanted coverage configurations + - coverage: 1 + platform: Win32 + + - coverage: 1 + os: Visual Studio 2015 + + - coverage: 1 + configuration: Release + + # Exclude unwanted examples configurations + - examples: 1 + platform: Win32 + + - examples: 1 + os: Visual Studio 2015 + + - examples: 1 + configuration: Release + + +install: + - ps: if (($env:CONFIGURATION) -eq "Debug" -And ($env:coverage) -eq "1" ) { python -m pip install codecov } + - ps: if (($env:CONFIGURATION) -eq "Debug" -And ($env:coverage) -eq "1" ) { .\misc\installOpenCppCoverage.ps1 } # Win32 and x64 are CMake-compatible solution platform names. # This allows us to pass %PLATFORM% to CMake -A. @@ -46,16 +78,19 @@ configuration: #Cmake will autodetect the compiler, but we set the arch before_build: - - python scripts/generateSingleHeader.py - set CXXFLAGS=%additional_flags% - - cmake -H. -BBuild -A%PLATFORM% -DUSE_WMAIN=%wmain% -DBUILD_EXAMPLES=ON + # Indirection because appveyor doesn't handle multiline batch scripts properly + # https://stackoverflow.com/questions/37627248/how-to-split-a-command-over-multiple-lines-in-appveyor-yml/37647169#37647169 + # https://help.appveyor.com/discussions/questions/3888-multi-line-cmd-or-powershell-warning-ignore + - cmd: .\misc\appveyorBuildConfigurationScript.bat + # build with MSBuild build: - project: Build\CatchSelfTest.sln # path to Visual Studio solution or project + project: Build\Catch2.sln # path to Visual Studio solution or project parallel: true # enable MSBuild parallel builds verbosity: normal # MSBuild verbosity level {quiet|minimal|normal|detailed} test_script: - - cd Build - - ctest -V -j 2 -C %CONFIGURATION% + - set CTEST_OUTPUT_ON_FAILURE=1 + - cmd: .\misc\appveyorTestRunScript.bat diff --git a/Telegram/ThirdParty/Catch/catch.pc.in b/Telegram/ThirdParty/Catch/catch.pc.in index 4a7b25454..abd0b66b1 100644 --- a/Telegram/ThirdParty/Catch/catch.pc.in +++ b/Telegram/ThirdParty/Catch/catch.pc.in @@ -1,9 +1,6 @@ -prefix=@CMAKE_INSTALL_PREFIX@ -exec_prefix=${prefix} +includedir=@CMAKE_INSTALL_FULL_INCLUDEDIR@ Name: Catch Description: Testing library for C++ -Requires: -Version: @CATCH_VERSION_NUMBER@ -Libs: -Cflags: -I${prefix}/@INCLUDE_INSTALL_DIR@/include +Version: @Catch2_VERSION@ +Cflags: -I${includedir} diff --git a/Telegram/ThirdParty/Catch/codecov.yml b/Telegram/ThirdParty/Catch/codecov.yml new file mode 100644 index 000000000..d81582d7e --- /dev/null +++ b/Telegram/ThirdParty/Catch/codecov.yml @@ -0,0 +1,26 @@ +coverage: + precision: 2 + round: nearest + range: "60...90" + status: + project: + default: + threshold: 2% + patch: + default: + target: 80% + + +codecov: + branch: master + +comment: + layout: "diff" + +coverage: + ignore: + - "projects/SelfTest" + - "**/catch_reporter_tap.hpp" + - "**/catch_reporter_automake.hpp" + - "**/catch_reporter_teamcity.hpp" + - "**/external/clara.hpp" diff --git a/Telegram/ThirdParty/Catch/conanfile.py b/Telegram/ThirdParty/Catch/conanfile.py index b4993b717..6d24a73c6 100644 --- a/Telegram/ThirdParty/Catch/conanfile.py +++ b/Telegram/ThirdParty/Catch/conanfile.py @@ -4,7 +4,7 @@ from conans import ConanFile class CatchConan(ConanFile): name = "Catch" - version = "2.0.1" + version = "2.2.0" description = "A modern, C++-native, header-only, framework for unit-tests, TDD and BDD" author = "philsquared" generators = "cmake" diff --git a/Telegram/ThirdParty/Catch/contrib/Catch.cmake b/Telegram/ThirdParty/Catch/contrib/Catch.cmake new file mode 100644 index 000000000..486e32331 --- /dev/null +++ b/Telegram/ThirdParty/Catch/contrib/Catch.cmake @@ -0,0 +1,175 @@ +# Distributed under the OSI-approved BSD 3-Clause License. See accompanying +# file Copyright.txt or https://cmake.org/licensing for details. + +#[=======================================================================[.rst: +Catch +----- + +This module defines a function to help use the Catch test framework. + +The :command:`catch_discover_tests` discovers tests by asking the compiled test +executable to enumerate its tests. This does not require CMake to be re-run +when tests change. However, it may not work in a cross-compiling environment, +and setting test properties is less convenient. + +This command is intended to replace use of :command:`add_test` to register +tests, and will create a separate CTest test for each Catch test case. Note +that this is in some cases less efficient, as common set-up and tear-down logic +cannot be shared by multiple test cases executing in the same instance. +However, it provides more fine-grained pass/fail information to CTest, which is +usually considered as more beneficial. By default, the CTest test name is the +same as the Catch name; see also ``TEST_PREFIX`` and ``TEST_SUFFIX``. + +.. command:: catch_discover_tests + + Automatically add tests with CTest by querying the compiled test executable + for available tests:: + + catch_discover_tests(target + [TEST_SPEC arg1...] + [EXTRA_ARGS arg1...] + [WORKING_DIRECTORY dir] + [TEST_PREFIX prefix] + [TEST_SUFFIX suffix] + [PROPERTIES name1 value1...] + [TEST_LIST var] + ) + + ``catch_discover_tests`` sets up a post-build command on the test executable + that generates the list of tests by parsing the output from running the test + with the ``--list-test-names-only`` argument. This ensures that the full + list of tests is obtained. Since test discovery occurs at build time, it is + not necessary to re-run CMake when the list of tests changes. + However, it requires that :prop_tgt:`CROSSCOMPILING_EMULATOR` is properly set + in order to function in a cross-compiling environment. + + Additionally, setting properties on tests is somewhat less convenient, since + the tests are not available at CMake time. Additional test properties may be + assigned to the set of tests as a whole using the ``PROPERTIES`` option. If + more fine-grained test control is needed, custom content may be provided + through an external CTest script using the :prop_dir:`TEST_INCLUDE_FILES` + directory property. The set of discovered tests is made accessible to such a + script via the ``_TESTS`` variable. + + The options are: + + ``target`` + Specifies the Catch executable, which must be a known CMake executable + target. CMake will substitute the location of the built executable when + running the test. + + ``TEST_SPEC arg1...`` + Specifies test cases, wildcarded test cases, tags and tag expressions to + pass to the Catch executable with the ``--list-test-names-only`` argument. + + ``EXTRA_ARGS arg1...`` + Any extra arguments to pass on the command line to each test case. + + ``WORKING_DIRECTORY dir`` + Specifies the directory in which to run the discovered test cases. If this + option is not provided, the current binary directory is used. + + ``TEST_PREFIX prefix`` + Specifies a ``prefix`` to be prepended to the name of each discovered test + case. This can be useful when the same test executable is being used in + multiple calls to ``catch_discover_tests()`` but with different + ``TEST_SPEC`` or ``EXTRA_ARGS``. + + ``TEST_SUFFIX suffix`` + Similar to ``TEST_PREFIX`` except the ``suffix`` is appended to the name of + every discovered test case. Both ``TEST_PREFIX`` and ``TEST_SUFFIX`` may + be specified. + + ``PROPERTIES name1 value1...`` + Specifies additional properties to be set on all tests discovered by this + invocation of ``catch_discover_tests``. + + ``TEST_LIST var`` + Make the list of tests available in the variable ``var``, rather than the + default ``_TESTS``. This can be useful when the same test + executable is being used in multiple calls to ``catch_discover_tests()``. + Note that this variable is only available in CTest. + +#]=======================================================================] + +#------------------------------------------------------------------------------ +function(catch_discover_tests TARGET) + cmake_parse_arguments( + "" + "" + "TEST_PREFIX;TEST_SUFFIX;WORKING_DIRECTORY;TEST_LIST" + "TEST_SPEC;EXTRA_ARGS;PROPERTIES" + ${ARGN} + ) + + if(NOT _WORKING_DIRECTORY) + set(_WORKING_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}") + endif() + if(NOT _TEST_LIST) + set(_TEST_LIST ${TARGET}_TESTS) + endif() + + ## Generate a unique name based on the extra arguments + string(SHA1 args_hash "${_TEST_SPEC} ${_EXTRA_ARGS}") + string(SUBSTRING ${args_hash} 0 7 args_hash) + + # Define rule to generate test list for aforementioned test executable + set(ctest_include_file "${CMAKE_CURRENT_BINARY_DIR}/${TARGET}_include-${args_hash}.cmake") + set(ctest_tests_file "${CMAKE_CURRENT_BINARY_DIR}/${TARGET}_tests-${args_hash}.cmake") + get_property(crosscompiling_emulator + TARGET ${TARGET} + PROPERTY CROSSCOMPILING_EMULATOR + ) + add_custom_command( + TARGET ${TARGET} POST_BUILD + BYPRODUCTS "${ctest_tests_file}" + COMMAND "${CMAKE_COMMAND}" + -D "TEST_TARGET=${TARGET}" + -D "TEST_EXECUTABLE=$" + -D "TEST_EXECUTOR=${crosscompiling_emulator}" + -D "TEST_WORKING_DIR=${_WORKING_DIRECTORY}" + -D "TEST_SPEC=${_TEST_SPEC}" + -D "TEST_EXTRA_ARGS=${_EXTRA_ARGS}" + -D "TEST_PROPERTIES=${_PROPERTIES}" + -D "TEST_PREFIX=${_TEST_PREFIX}" + -D "TEST_SUFFIX=${_TEST_SUFFIX}" + -D "TEST_LIST=${_TEST_LIST}" + -D "CTEST_FILE=${ctest_tests_file}" + -P "${_CATCH_DISCOVER_TESTS_SCRIPT}" + VERBATIM + ) + + file(WRITE "${ctest_include_file}" + "if(EXISTS \"${ctest_tests_file}\")\n" + " include(\"${ctest_tests_file}\")\n" + "else()\n" + " add_test(${TARGET}_NOT_BUILT-${args_hash} ${TARGET}_NOT_BUILT-${args_hash})\n" + "endif()\n" + ) + + if(NOT ${CMAKE_VERSION} VERSION_LESS "3.10.0") + # Add discovered tests to directory TEST_INCLUDE_FILES + set_property(DIRECTORY + APPEND PROPERTY TEST_INCLUDE_FILES "${ctest_include_file}" + ) + else() + # Add discovered tests as directory TEST_INCLUDE_FILE if possible + get_property(test_include_file_set DIRECTORY PROPERTY TEST_INCLUDE_FILE SET) + if (NOT ${test_include_file_set}) + set_property(DIRECTORY + PROPERTY TEST_INCLUDE_FILE "${ctest_include_file}" + ) + else() + message(FATAL_ERROR + "Cannot set more than one TEST_INCLUDE_FILE" + ) + endif() + endif() + +endfunction() + +############################################################################### + +set(_CATCH_DISCOVER_TESTS_SCRIPT + ${CMAKE_CURRENT_LIST_DIR}/CatchAddTests.cmake +) diff --git a/Telegram/ThirdParty/Catch/contrib/CatchAddTests.cmake b/Telegram/ThirdParty/Catch/contrib/CatchAddTests.cmake new file mode 100644 index 000000000..c68921e4f --- /dev/null +++ b/Telegram/ThirdParty/Catch/contrib/CatchAddTests.cmake @@ -0,0 +1,77 @@ +# Distributed under the OSI-approved BSD 3-Clause License. See accompanying +# file Copyright.txt or https://cmake.org/licensing for details. + +set(prefix "${TEST_PREFIX}") +set(suffix "${TEST_SUFFIX}") +set(spec ${TEST_SPEC}) +set(extra_args ${TEST_EXTRA_ARGS}) +set(properties ${TEST_PROPERTIES}) +set(script) +set(suite) +set(tests) + +function(add_command NAME) + set(_args "") + foreach(_arg ${ARGN}) + if(_arg MATCHES "[^-./:a-zA-Z0-9_]") + set(_args "${_args} [==[${_arg}]==]") # form a bracket_argument + else() + set(_args "${_args} ${_arg}") + endif() + endforeach() + set(script "${script}${NAME}(${_args})\n" PARENT_SCOPE) +endfunction() + +# Run test executable to get list of available tests +if(NOT EXISTS "${TEST_EXECUTABLE}") + message(FATAL_ERROR + "Specified test executable '${TEST_EXECUTABLE}' does not exist" + ) +endif() +execute_process( + COMMAND ${TEST_EXECUTOR} "${TEST_EXECUTABLE}" ${spec} --list-test-names-only + OUTPUT_VARIABLE output + RESULT_VARIABLE result +) +# Catch --list-test-names-only reports the number of tests, so 0 is... surprising +if(${result} EQUAL 0) + message(WARNING + "Test executable '${TEST_EXECUTABLE}' contains no tests!\n" + ) +elseif(${result} LESS 0) + message(FATAL_ERROR + "Error running test executable '${TEST_EXECUTABLE}':\n" + " Result: ${result}\n" + " Output: ${output}\n" + ) +endif() + +string(REPLACE "\n" ";" output "${output}") + +# Parse output +foreach(line ${output}) + # Test name; strip spaces to get just the name... + string(REGEX REPLACE " +" "" test "${line}") + # ...and add to script + add_command(add_test + "${prefix}${test}${suffix}" + ${TEST_EXECUTOR} + "${TEST_EXECUTABLE}" + "${test}" + ${extra_args} + ) + add_command(set_tests_properties + "${prefix}${test}${suffix}" + PROPERTIES + WORKING_DIRECTORY "${TEST_WORKING_DIR}" + ${properties} + ) + list(APPEND tests "${prefix}${test}${suffix}") +endforeach() + +# Create a list of all discovered tests, which users may use to e.g. set +# properties on the tests +add_command(set ${TEST_LIST} ${tests}) + +# Write CTest script +file(WRITE "${CTEST_FILE}" "${script}") diff --git a/Telegram/ThirdParty/Catch/docs/assertions.md b/Telegram/ThirdParty/Catch/docs/assertions.md index 93f88c412..509abf8a5 100644 --- a/Telegram/ThirdParty/Catch/docs/assertions.md +++ b/Telegram/ThirdParty/Catch/docs/assertions.md @@ -9,7 +9,7 @@ Most test frameworks have a large collection of assertion macros to capture all possible conditional forms (```_EQUALS```, ```_NOTEQUALS```, ```_GREATER_THAN``` etc). -Catch is different. Because it decomposes natural C-style conditional expressions most of these forms are reduced to one or two that you will use all the time. That said there are a rich set of auxilliary macros as well. We'll describe all of these here. +Catch is different. Because it decomposes natural C-style conditional expressions most of these forms are reduced to one or two that you will use all the time. That said there are a rich set of auxiliary macros as well. We'll describe all of these here. Most of these macros come in two forms: @@ -21,7 +21,7 @@ The ```CHECK``` family are equivalent but execution continues in the same test c * **REQUIRE(** _expression_ **)** and * **CHECK(** _expression_ **)** -Evaluates the expression and records the result. If an exception is thrown it is caught, reported, and counted as a failure. These are the macros you will use most of the time +Evaluates the expression and records the result. If an exception is thrown, it is caught, reported, and counted as a failure. These are the macros you will use most of the time. Examples: ``` diff --git a/Telegram/ThirdParty/Catch/docs/build-systems.md b/Telegram/ThirdParty/Catch/docs/build-systems.md index 5f65480d8..2873bc62a 100644 --- a/Telegram/ThirdParty/Catch/docs/build-systems.md +++ b/Telegram/ThirdParty/Catch/docs/build-systems.md @@ -28,9 +28,14 @@ The advantage of this format is that the JUnit Ant schema is widely understood b The disadvantage is that this schema was designed to correspond to how JUnit works - and there is a significant mismatch with how Catch works. Additionally the format is not streamable (because opening elements hold counts of failed and passing tests as attributes) - so the whole test run must complete before it can be written. ## Other reporters -Other reporters are not part of the single-header distribution and need to be downloaded and included separately. All reporters are stored in `include/reporters` directory in the git repository, and are named `catch_reporter_*.hpp`. For example, to use the TeamCity reporter you need to download `include/reporters/catch_reporter_teamcity.hpp` and include it after Catch itself. +Other reporters are not part of the single-header distribution and need +to be downloaded and included separately. All reporters are stored in +`single_include` directory in the git repository, and are named +`catch_reporter_*.hpp`. For example, to use the TeamCity reporter you +need to download `single_include/catch_reporter_teamcity.hpp` and include +it after Catch itself. -``` +```cpp #define CATCH_CONFIG_MAIN #include "catch.hpp" #include "catch_reporter_teamcity.hpp" @@ -124,7 +129,15 @@ The advantage of this approach is that you can always automatically update Catch ### Automatic test registration -If you are also using ctest, `contrib/ParseAndAddCatchTests.cmake` is a CMake script that attempts to parse your test files and automatically register all test cases, using tags as labels. This means that these +We provide 2 CMake scripts that can automatically register Catch-based +tests with CTest, + * `contrib/ParseAndAddCatchTests.cmake` + * `contrib/CatchAddTests.cmake` + +The first is based on parsing the test implementation files, and attempts +to register all `TEST_CASE`s using their tags as labels. This means that +these: + ```cpp TEST_CASE("Test1", "[unit]") { int a = 1; @@ -144,7 +157,14 @@ TEST_CASE("Test3", "[a][b][c]") { REQUIRE(a == b); } ``` -would be registered as 3 tests, `Test1`, `Test2` and `Test3`, and 4 ctest labels would be created, `a`, `b`, `c` and `unit`. +would be registered as 3 tests, `Test1`, `Test2` and `Test3`, +and 4 CTest labels would be created, `a`, `b`, `c` and `unit`. + + +The second is based on parsing the output of a Catch binary given +`--list-test-names-only`. This means that it deals with inactive +(e.g. commented-out) tests better, but requires CMake 3.10 for full +functionality. ### CodeCoverage module (GCOV, LCOV...) diff --git a/Telegram/ThirdParty/Catch/docs/command-line.md b/Telegram/ThirdParty/Catch/docs/command-line.md index 8afcb7d4d..78d83625f 100644 --- a/Telegram/ThirdParty/Catch/docs/command-line.md +++ b/Telegram/ThirdParty/Catch/docs/command-line.md @@ -78,7 +78,7 @@ Wildcards consist of the `*` character at the beginning and/or end of test case Test specs are case insensitive. -If a spec is prefixed with `exclude:` or the `~` character then the pattern matches an exclusion. This means that tests matching the pattern are excluded from the set - even if a prior inclusion spec included them. Subsequent inclusion specs will take precendence, however. +If a spec is prefixed with `exclude:` or the `~` character then the pattern matches an exclusion. This means that tests matching the pattern are excluded from the set - even if a prior inclusion spec included them. Subsequent inclusion specs will take precedence, however. Inclusions and exclusions are evaluated in left-to-right order. Test case examples: @@ -94,7 +94,7 @@ a* ~ab* abc Matches all tests that start with 'a', except those that Names within square brackets are interpreted as tags. -A series of tags form an AND expression wheras a comma-separated sequence forms an OR expression. e.g.: +A series of tags form an AND expression whereas a comma-separated sequence forms an OR expression. e.g.:
[one][two],[three]
This matches all tests tagged `[one]` and `[two]`, as well as all tests tagged `[three]` @@ -192,9 +192,16 @@ This option transforms tabs and newline characters into ```\t``` and ```\n``` re ## Warnings
-w, --warn <warning name>
-Enables reporting of warnings (only one, at time of this writing). If a warning is issued it fails the test. +Enables reporting of suspicious test states. There are currently two +available warnings + +``` + NoAssertions // Fail test case / leaf section if no assertions + // (e.g. `REQUIRE`) is encountered. + NoTests // Return non-zero exit code when no test cases were run + // Also calls reporter's noMatchingTestCases method +``` -The ony available warning, presently, is ```NoAssertions```. This warning fails a test case, or (leaf) section if no assertions (```REQUIRE```/ ```CHECK``` etc) are encountered. ## Reporting timings @@ -262,7 +269,7 @@ either before running any tests, after running all tests - or both, depending on When running benchmarks the clock resolution is estimated. Benchmarks are then run for exponentially increasing numbers of iterations until some multiple of the estimated resolution is exceed. By default that multiple is 100, but -it can be overriden here. +it can be overridden here. ## Usage diff --git a/Telegram/ThirdParty/Catch/docs/configuration.md b/Telegram/ThirdParty/Catch/docs/configuration.md index 3e59e7639..dd81dde4b 100644 --- a/Telegram/ThirdParty/Catch/docs/configuration.md +++ b/Telegram/ThirdParty/Catch/docs/configuration.md @@ -7,6 +7,8 @@ [Terminal colour](#terminal-colour)
[Console width](#console-width)
[stdout](#stdout)
+[Fallback stringifier](#fallback-stringifier)
+[Default reporter](#default-reporter)
[Other toggles](#other-toggles)
[Windows header clutter](#windows-header-clutter)
[Enabling stringification](#enabling-stringification)
@@ -24,7 +26,7 @@ Although Catch is header only it still, internally, maintains a distinction betw # Reporter / Listener interfaces - CATCH_CONFIG_EXTERNAL_INTERFACES // Brings in neccessary headers for Reporter/Listener implementation + CATCH_CONFIG_EXTERNAL_INTERFACES // Brings in necessary headers for Reporter/Listener implementation Brings in various parts of Catch that are required for user defined Reporters and Listeners. This means that new Reporters and Listeners can be defined in this file as well as in the main file. @@ -73,6 +75,40 @@ Catch does not use ```std::cout```, ```std::cerr``` and ```std::clog``` directly This can be useful on certain platforms that do not provide the standard iostreams, such as certain embedded systems. +## Fallback stringifier + +By default Catch's stringification machinery falls back to a "{?}". To +let projects reuse their own existing stringification machinery, this +fallback can be overridden by defining `CATCH_CONFIG_FALLBACK_STRINGIFIER` +to a name of a function that should perform the stringification instead. + +The provided function must return std::string and must accept any type +(e.g. via overloading). + +_Note that if the provided function does not handle a type and this type +requires to be stringified, the compilation will fail._ + + +## Default reporter + +Catch's default reporter can be changed by defining macro +`CATCH_CONFIG_DEFAULT_REPORTER` to string literal naming the desired +default reporter. + +This means that defining `CATCH_CONFIG_DEFAULT_REPORTER` to `"console"` +is equivalent with the out-of-the-box experience. + + +## C++17 toggles + + CATCH_CONFIG_CPP17_UNCAUGHT_EXCEPTIONS // Use std::uncaught_exceptions instead of std::uncaught_exception + +Catch contains basic compiler/standard detection and attempts to use +some C++17 features whenever appropriate. This automatic detection +can be manually overridden in both directions, that is, a feature +can be enabled by defining the macro in the table above, and disabled +by using `_NO_` in the macro, e.g. `CATCH_CONFIG_NO_CPP17_UNCAUGHT_EXCEPTIONS`. + ## Other toggles @@ -84,6 +120,7 @@ This can be useful on certain platforms that do not provide the standard iostrea CATCH_CONFIG_WINDOWS_CRTDBG // Enable leak checking using Windows's CRT Debug Heap CATCH_CONFIG_DISABLE_STRINGIFICATION // Disable stringifying the original expression CATCH_CONFIG_DISABLE // Disables assertions and test case registration + CATCH_CONFIG_WCHAR // Enables use of wchart_t Currently Catch enables `CATCH_CONFIG_WINDOWS_SEH` only when compiled with MSVC, because some versions of MinGW do not have the necessary Win32 API support. @@ -91,12 +128,15 @@ Currently Catch enables `CATCH_CONFIG_WINDOWS_SEH` only when compiled with MSVC, `CATCH_CONFIG_WINDOWS_CRTDBG` is off by default. If enabled, Windows's CRT is used to check for memory leaks, and displays them after the tests finish running. +`CATCH_CONFIG_WCHAR` is on by default, but can be disabled. Currently +it is only used in support for DJGPP cross-compiler. + These toggles can be disabled by using `_NO_` form of the toggle, e.g. `CATCH_CONFIG_NO_WINDOWS_SEH`. ### `CATCH_CONFIG_FAST_COMPILE` Defining this flag speeds up compilation of test files by ~20%, by making 2 changes: * The `-b` (`--break`) flag no longer makes Catch break into debugger in the same stack frame as the failed test, but rather in a stack frame *below*. -* Non-exception family of macros ({`REQUIRE`,`CHECK`}{`_`,`_FALSE`, `_FALSE`}, no longer use local try-cache block. This disables exception translation, but should not lead to false negatives. +* Non-exception family of macros ({`REQUIRE`,`CHECK`}{`_`,`_FALSE`, `_THAT`}, no longer use local try-catch block. This disables exception translation, but should not lead to false negatives. `CATCH_CONFIG_FAST_COMPILE` has to be either defined, or not defined, in all translation units that are linked into single test binary, or the behaviour of setting `-b` flag and throwing unexpected exceptions will be unpredictable. diff --git a/Telegram/ThirdParty/Catch/docs/event-listeners.md b/Telegram/ThirdParty/Catch/docs/event-listeners.md index 1ddef0f8c..c6625a2e0 100644 --- a/Telegram/ThirdParty/Catch/docs/event-listeners.md +++ b/Telegram/ThirdParty/Catch/docs/event-listeners.md @@ -44,7 +44,7 @@ _Note that you should not use any assertion macros within a Listener!_ ## Events that can be hooked -The following are the methods that can be overriden in the Listener: +The following are the methods that can be overridden in the Listener: ```c++ // The whole test run, starting and ending diff --git a/Telegram/ThirdParty/Catch/docs/limitations.md b/Telegram/ThirdParty/Catch/docs/limitations.md index bcdbab066..9acade0e1 100644 --- a/Telegram/ThirdParty/Catch/docs/limitations.md +++ b/Telegram/ThirdParty/Catch/docs/limitations.md @@ -96,6 +96,14 @@ with expansion: ""\" == ""\" ``` +### Visual Studio 2015 -- Alignment compilation error (C2718) + +VS 2015 has a known bug, where `declval` can cause compilation error +if `T` has alignment requirements that it cannot meet. + + +A workaround is to explicitly specialize `Catch::is_range` for given +type (this avoids code path that uses `declval` in a SFINAE context). ### Visual Studio 2015 -- Wrong line number reported in debug mode diff --git a/Telegram/ThirdParty/Catch/docs/opensource-users.md b/Telegram/ThirdParty/Catch/docs/opensource-users.md index 561eaae12..374cb1d2d 100644 --- a/Telegram/ThirdParty/Catch/docs/opensource-users.md +++ b/Telegram/ThirdParty/Catch/docs/opensource-users.md @@ -1,18 +1,18 @@ # Open Source projects using Catch -Catch is great for open source. With its [liberal license](../LICENSE.txt) and single-header, dependency-free, distribution +Catch is great for open source. With its [liberal license](../LICENSE.txt) and single-header, dependency-free, distribution it's easy to just drop the header into your project and start writing tests - what's not to like? As a result Catch is now being used in many Open Source projects, including some quite well known ones. This page is an attempt to track those projects. Obviously it can never be complete. This effort largely relies on the maintainers of the projects themselves updating this page and submitting a PR -(or, if you prefer contact one of the maintainers of Catch directly, use the +(or, if you prefer contact one of the maintainers of Catch directly, use the [forums](https://groups.google.com/forum/?fromgroups#!forum/catch-forum)), or raise an [issue](https://github.com/philsquared/Catch/issues) to let us know). Of course users of those projects might want to update this page too. That's fine - as long you're confident the project maintainers won't mind. -If you're an Open Source project maintainer and see your project listed here but would rather it wasn't - +If you're an Open Source project maintainer and see your project listed here but would rather it wasn't - just let us know via any of the previously mentioned means - although I'm sure there won't be many who feel that way. - + Listing a project here does not imply endorsement and the plan is to keep these ordered alphabetically to avoid an implication of relative importance. ## Libraries & Frameworks @@ -21,7 +21,7 @@ Listing a project here does not imply endorsement and the plan is to keep these Boost Asio style bindings for ZeroMQ ### [ChakraCore](https://github.com/Microsoft/ChakraCore) -The core part of the Chakra Javascript engine that powers Microsoft Edge +The core part of the Chakra JavaScript engine that powers Microsoft Edge ### [ChaiScript](https://github.com/ChaiScript/ChaiScript) A, header-only, embedded scripting language designed from the ground up to directly target C++ and take advantage of modern C++ development techniques @@ -30,7 +30,16 @@ A, header-only, embedded scripting language designed from the ground up to direc A, single-header-only, type-safe, command line parser - which also prints formatted usage strings. ### [Couchbase-lite-core](https://github.com/couchbase/couchbase-lite-core) -The next-generation core storage and query engine for Couchbase Lite/ +The next-generation core storage and query engine for Couchbase Lite + +### [DtCraft](https://github.com/twhuang-uiuc/DtCraft) +A High-performance Cluster Computing Engine + +### [forest](https://github.com/xorz57/forest) +Forest is an open-source, template library of tree data structures written in C++11. + +### [Fuxedo](https://github.com/fuxedo/fuxedo) +Open source Oracle Tuxedo-like XATMI middleware for C and C++. ### [Inja](https://github.com/pantor/inja) A header-only template engine for modern C++. @@ -82,6 +91,9 @@ MAME originally stood for Multiple Arcade Machine Emulator ### [Newsbeuter](https://github.com/akrennmair/newsbeuter) Newsbeuter is an open-source RSS/Atom feed reader for text terminals. +### [SpECTRE](https://github.com/sxs-collaboration/spectre) +SpECTRE is a code for multi-scale, multi-physics problems in astrophysics and gravitational physics. + ### [Standardese](https://github.com/foonathan/standardese) Standardese aims to be a nextgen Doxygen diff --git a/Telegram/ThirdParty/Catch/docs/own-main.md b/Telegram/ThirdParty/Catch/docs/own-main.md index fbaff5911..c74f9f14e 100644 --- a/Telegram/ThirdParty/Catch/docs/own-main.md +++ b/Telegram/ThirdParty/Catch/docs/own-main.md @@ -30,7 +30,7 @@ int main( int argc, char* argv[] ) { ## Amending the config -If you still want Catch to process the command line, but you want to programatically tweak the config, you can do so in one of two ways: +If you still want Catch to process the command line, but you want to programmatically tweak the config, you can do so in one of two ways: ```c++ #define CATCH_CONFIG_RUNNER @@ -81,6 +81,7 @@ int main( int argc, char* argv[] ) int height = 0; // Some user variable you want to be able to set // Build a new parser on top of Catch's + using namespace Catch::clara; auto cli = session.cli() // Get Catch's composite command line parser | Opt( height, "height" ) // bind variable to a new option, with a hint string @@ -105,6 +106,20 @@ int main( int argc, char* argv[] ) See the [Clara documentation](https://github.com/philsquared/Clara/blob/master/README.md) for more details. + +## Version detection + +Catch provides a triplet of macros providing the header's version, + +* `CATCH_VERSION_MAJOR` +* `CATCH_VERSION_MINOR` +* `CATCH_VERSION_PATCH` + +these macros expand into a single number, that corresponds to the appropriate +part of the version. As an example, given single header version v2.3.4, +the macros would expand into `2`, `3`, and `4` respectively. + + --- [Home](Readme.md#top) diff --git a/Telegram/ThirdParty/Catch/docs/release-notes.md b/Telegram/ThirdParty/Catch/docs/release-notes.md index 4d053578e..ca9330db6 100644 --- a/Telegram/ThirdParty/Catch/docs/release-notes.md +++ b/Telegram/ThirdParty/Catch/docs/release-notes.md @@ -1,4 +1,104 @@ + +# 2.2.0 + +## Fixes +* Hidden tests are not listed by default when listing tests (#1175) + * This makes `catch_discover_tests` CMake script work better +* Fixed regression that meant `` could potentially not be included properly (#1197) +* Fixed installing `Catch2ConfigVersion.cmake` when Catch2 is a subproject. + +## Improvements +* Added an option to warn (+ exit with error) when no tests were ran (#1158) + * Use as `-w NoTests` +* Added provisional support for Emscripten (#1114) +* [Added a way to override the fallback stringifier](https://github.com/catchorg/Catch2/blob/master/docs/configuration.md#fallback-stringifier) (#1024) + * This allows project's own stringification machinery to be easily reused for Catch +* `Catch::Session::run()` now accepts `char const * const *`, allowing it to accept array of string literals (#1031, #1178) + * The embedded version of Clara was bumped to v1.1.3 +* Various minor performance improvements +* Added support for DJGPP DOS crosscompiler (#1206) + + +# 2.1.2 + +## Fixes +* Fixed compilation error with `-fno-rtti` (#1165) +* Fixed NoAssertion warnings +* `operator<<` is used before range-based stringification (#1172) +* Fixed `-Wpedantic` warnings (extra semicolons and binary literals) (#1173) + + +## Improvements +* Added `CATCH_VERSION_{MAJOR,MINOR,PATCH}` macros (#1131) +* Added `BrightYellow` colour for use in reporters (#979) + * It is also used by ConsoleReporter for reconstructed expressions + +## Other changes +* Catch is now exported as a CMake package and linkable target (#1170) + +# 2.1.1 + +## Improvements +* Static arrays are now properly stringified like ranges across MSVC/GCC/Clang +* Embedded newer version of Clara -- v1.1.1 + * This should fix some warnings dragged in from Clara +* MSVC's CLR exceptions are supported + + +## Fixes +* Fixed compilation when comparison operators do not return bool (#1147) +* Fixed CLR exceptions blowing up the executable during translation (#1138) + + +## Other changes +* Many CMake changes + * `NO_SELFTEST` option is deprecated, use `BUILD_TESTING` instead. + * Catch specific CMake options were prefixed with `CATCH_` for namespacing purposes + * Other changes to simplify Catch2's packaging + + + +# 2.1.0 + +## Improvements +* Various performance improvements + * On top of the performance regression fixes +* Experimental support for PCH was added (#1061) +* `CATCH_CONFIG_EXTERNAL_INTERFACES` now brings in declarations of Console, Compact, XML and JUnit reporters +* `MatcherBase` no longer has a pointless second template argument +* Reduced the number of warning suppressions that leak into user's code + * Bugs in g++ 4.x and 5.x mean that some of them have to be left in + + +## Fixes +* Fixed performance regression from Catch classic + * One of the performance improvement patches for Catch classic was not applied to Catch2 +* Fixed platform detection for iOS (#1084) +* Fixed compilation when `g++` is used together with `libc++` (#1110) +* Fixed TeamCity reporter compilation with the single header version + * To fix the underlying issue we will be versioning reporters in single_include folder per release +* The XML reporter will now report `WARN` messages even when not used with `-s` +* Fixed compilation when `VectorContains` matcher was combined using `&&` (#1092) +* Fixed test duration overflowing after 10 seconds (#1125, #1129) +* Fixed `std::uncaught_exception` deprecation warning (#1124) + + +## New features +* New Matchers + * Regex matcher for strings, `Matches`. + * Set-equal matcher for vectors, `UnorderedEquals` + * Floating point matchers, `WithinAbs` and `WithinULP`. +* Stringification now attempts to decompose all containers (#606) + * Containers are objects that respond to ADL `begin(T)` and `end(T)`. + + +## Other changes +* Reporters will now be versioned in the `single_include` folder to ensure their compatibility with the last released version + + + + # 2.0.1 ## Breaking changes @@ -87,6 +187,41 @@ # Older versions +## 1.11.x + +### 1.11.0 + +#### Fixes +* The original expression in `REQUIRE_FALSE( expr )` is now reporter properly as `!( expr )` (#1051) + * Previously the parentheses were missing and `x != y` would be expanded as `!x != x` +* `Approx::Margin` is now inclusive (#952) + * Previously it was meant and documented as inclusive, but the check itself wasn't + * This means that `REQUIRE( 0.25f == Approx( 0.0f ).margin( 0.25f ) )` passes, instead of fails +* `RandomNumberGenerator::result_type` is now unsigned (#1050) + +#### Improvements +* `__JETBRAINS_IDE__` macro handling is now CLion version specific (#1017) + * When CLion 2017.3 or newer is detected, `__COUNTER__` is used instead of +* TeamCity reporter now explicitly flushes output stream after each report (#1057) + * On some platforms, output from redirected streams would show up only after the tests finished running +* `ParseAndAddCatchTests` now can add test files as dependency to CMake configuration + * This means you do not have to manually rerun CMake configuration step to detect new tests + +## 1.10.x + +### 1.10.0 + +#### Fixes +* Evaluation layer has been rewritten (backported from Catch 2) + * The new layer is much simpler and fixes some issues (#981) +* Implemented workaround for VS 2017 raw string literal stringification bug (#995) +* Fixed interaction between `[!shouldfail]` and `[!mayfail]` tags and sections + * Previously sections with failing assertions would be marked as failed, not failed-but-ok + +#### Improvements +* Added [libidentify](https://github.com/janwilmans/LibIdentify) support +* Added "wait-for-keypress" option + ## 1.9.x ### 1.9.6 @@ -264,8 +399,8 @@ Cygwin issue with `gettimeofday` - `#define` was not early enough * Cygwin compatibility fixes * Signal handling is no longer compiled by default. * Usage of `gettimeofday` inside Catch should no longer cause compilation errors. -* Improved `-Wparentheses` supression for gcc (#674) - * When compiled with gcc 4.8 or newer, the supression is localized to assertions only +* Improved `-Wparentheses` suppression for gcc (#674) + * When compiled with gcc 4.8 or newer, the suppression is localized to assertions only * Otherwise it is supressed for the whole TU * Fixed test spec parser issue (with escapes in multiple names) @@ -284,7 +419,7 @@ Xml: * C-escape control characters instead of XML encoding them (which requires XML 1.1) * Revert XML output to XML 1.0 * Can provide stylesheet references by extending the XML reporter -* Added description and tags attribites to XML Reporter +* Added description and tags attributes to XML Reporter * Tags are closed and the stream flushed more eagerly to avoid stdout interpolation diff --git a/Telegram/ThirdParty/Catch/docs/release-process.md b/Telegram/ThirdParty/Catch/docs/release-process.md index 34002ae63..9990bab2b 100644 --- a/Telegram/ThirdParty/Catch/docs/release-process.md +++ b/Telegram/ThirdParty/Catch/docs/release-process.md @@ -1,11 +1,11 @@ # How to release -When enough changes have accumulated, it is time to release new version of Catch. This document describes the proces in doing so, that no steps are forgotten. Note that all referenced scripts can be found in the `scripts/` directory. +When enough changes have accumulated, it is time to release new version of Catch. This document describes the process in doing so, that no steps are forgotten. Note that all referenced scripts can be found in the `scripts/` directory. -## Neccessary steps +## Necessary steps -These steps are neccessary and have to be performed before each new release. They serve to make sure that the new release is correct and linked-to from the standard places. +These steps are necessary and have to be performed before each new release. They serve to make sure that the new release is correct and linked-to from the standard places. ### Approval testing @@ -21,10 +21,8 @@ Catch uses a variant of [semantic versioning](http://semver.org/), with breaking After deciding which part of version number should be incremented, you can use one of the `*Release.py` scripts to perform the required changes to Catch. - -### Generate updated single-include header - -After updating version number, regenerate single-include header using `generateSingleHeader.py`. +This will take care of generating the single include header, updating +version numbers everywhere and pushing the new version to Wandbox. ### Release notes @@ -39,16 +37,24 @@ After version number is incremented, single-include header is regenerated and re ### Release on GitHub -After pushing changes to GitHub, GitHub release *needs* to be created. Tag version and release title should be same as the new version, description should contain the release notes for the current release. Single header version of `catch.hpp` *needs* to be attached as a binary, as that is where the official download link links to. Preferably it should use linux line endings. +After pushing changes to GitHub, GitHub release *needs* to be created. +Tag version and release title should be same as the new version, +description should contain the release notes for the current release. +Single header version of `catch.hpp` *needs* to be attached as a binary, +as that is where the official download link links to. Preferably +it should use linux line endings. All non-bundled reporters (Automake, +TAP, TeamCity) should also be attached as binaries, as they are dependent +on a specific version of the single-include header. + ## Optional steps -The following steps are optional, and do not have to be performed when releasing new version of Catch. However, they are *should* happen, but they can happen the next day without losing anything significant. +The following steps are optional, and do not have to be performed when releasing new version of Catch. However, they *should* happen, but they can happen the next day without losing anything significant. ### vcpkg update -Catch is maintaining its own port in Microsoft's package manager [vcpkg](https://github.com/Microsoft/vcpkg). This means that when new version of Catch is released, it should be posted there as well. `updateVcpkgPackage.py` can do a lot of neccessary work for you, it creates a branch and commits neccessary changes. You should review these changes, push and open a PR against vcpkg's upstream. +Catch is maintaining its own port in Microsoft's package manager [vcpkg](https://github.com/Microsoft/vcpkg). This means that when new version of Catch is released, it should be posted there as well. `updateVcpkgPackage.py` can do a lot of necessary work for you, it creates a branch and commits necessary changes. You should review these changes, push and open a PR against vcpkg's upstream. Note that the script assumes you have your fork of vcpkg checked out in a directory next to the directory where you have checked out Catch, like so: ``` @@ -57,8 +63,3 @@ GitHub vcpkg ``` - -### Wandbox update - -Recently we also included a link to wandbox with preloaded Catch on the main page. Strictly speaking it is unneccessary to update this after every release, Catch usually does not change that much between versions, but it should be kept up to date anyway. - diff --git a/Telegram/ThirdParty/Catch/docs/tostring.md b/Telegram/ThirdParty/Catch/docs/tostring.md index cfca05331..568c1c275 100644 --- a/Telegram/ThirdParty/Catch/docs/tostring.md +++ b/Telegram/ThirdParty/Catch/docs/tostring.md @@ -33,6 +33,23 @@ namespace Catch { } ``` +## Catch::is_range specialisation +As a fallback, Catch attempts to detect if the type can be iterated +(`begin(T)` and `end(T)` are valid) and if it can be, it is stringified +as a range. For certain types this can lead to infinite recursion, so +it can be disabled by specializing `Catch::is_range` like so: + +```cpp +namespace Catch { + template<> + struct is_range { + static const bool value = false; + }; +} + +``` + + ## Exceptions By default all exceptions deriving from `std::exception` will be translated to strings by calling the `what()` method. For exception types that do not derive from `std::exception` - or if `what()` does not return a suitable string - use `CATCH_TRANSLATE_EXCEPTION`. This defines a function that takes your exception type, by reference, and returns a string. It can appear anywhere in the code - it doesn't have to be in the same translation unit. For example: diff --git a/Telegram/ThirdParty/Catch/examples/CMakeLists.txt b/Telegram/ThirdParty/Catch/examples/CMakeLists.txt index 9f7c7fae3..7270e933e 100644 --- a/Telegram/ThirdParty/Catch/examples/CMakeLists.txt +++ b/Telegram/ThirdParty/Catch/examples/CMakeLists.txt @@ -1,7 +1,7 @@ # # Build examples. # -# Requires BUILD_EXAMPLES to be defined 'true', see ../CMakeLists.txt. +# Requires CATCH_BUILD_EXAMPLES to be defined 'true', see ../CMakeLists.txt. # cmake_minimum_required( VERSION 3.0 ) diff --git a/Telegram/ThirdParty/Catch/include/catch.hpp b/Telegram/ThirdParty/Catch/include/catch.hpp index 34c551bef..ebad166e5 100644 --- a/Telegram/ThirdParty/Catch/include/catch.hpp +++ b/Telegram/ThirdParty/Catch/include/catch.hpp @@ -9,6 +9,9 @@ #ifndef TWOBLUECUBES_CATCH_HPP_INCLUDED #define TWOBLUECUBES_CATCH_HPP_INCLUDED +#define CATCH_VERSION_MAJOR 2 +#define CATCH_VERSION_MINOR 2 +#define CATCH_VERSION_PATCH 0 #ifdef __clang__ # pragma clang system_header diff --git a/Telegram/ThirdParty/Catch/include/external/clara.hpp b/Telegram/ThirdParty/Catch/include/external/clara.hpp index 88a5e9fe7..3a7f88363 100644 --- a/Telegram/ThirdParty/Catch/include/external/clara.hpp +++ b/Telegram/ThirdParty/Catch/include/external/clara.hpp @@ -1,5 +1,11 @@ -// v1.0-develop.2 -// See https://github.com/philsquared/Clara +// 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.4 #ifndef CATCH_CLARA_HPP_INCLUDED #define CATCH_CLARA_HPP_INCLUDED @@ -12,6 +18,16 @@ #define CATCH_CLARA_TEXTFLOW_CONFIG_CONSOLE_WIDTH CATCH_CLARA_CONFIG_CONSOLE_WIDTH #endif +#ifndef CLARA_CONFIG_OPTIONAL_TYPE +#ifdef __has_include +#if __has_include() && __cplusplus >= 201703L +#include +#define CLARA_CONFIG_OPTIONAL_TYPE std::optional +#endif +#endif +#endif + + // ----------- #included from clara_textflow.hpp ----------- // TextFlowCpp @@ -370,7 +386,7 @@ namespace detail { template struct UnaryLambdaTraits { static const bool isValid = true; - using ArgType = typename std::remove_const::type>::type;; + using ArgType = typename std::remove_const::type>::type; using ReturnType = ReturnT; }; @@ -383,11 +399,9 @@ namespace detail { std::vector m_args; public: - Args( int argc, char *argv[] ) { - m_exeName = argv[0]; - for( int i = 1; i < argc; ++i ) - m_args.push_back( argv[i] ); - } + Args( int argc, char const* const* argv ) + : m_exeName(argv[0]), + m_args(argv + 1, argv + argc) {} Args( std::initializer_list args ) : m_exeName( *args.begin() ), @@ -535,7 +549,7 @@ namespace detail { return *this; } - ~ResultValueBase() { + ~ResultValueBase() override { if( m_type == Ok ) m_value.~T(); } @@ -573,16 +587,14 @@ namespace detail { auto errorMessage() const -> std::string { return m_errorMessage; } protected: - virtual void enforceOk() const { - // !TBD: If no exceptions, std::terminate here or something - switch( m_type ) { - case ResultBase::LogicError: - throw std::logic_error( m_errorMessage ); - case ResultBase::RuntimeError: - throw std::runtime_error( m_errorMessage ); - case ResultBase::Ok: - break; - } + 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 @@ -652,47 +664,43 @@ namespace detail { return ParserResult::runtimeError( "Expected a boolean value but did not recognise: '" + source + "'" ); return ParserResult::ok( ParseResultType::Matched ); } +#ifdef CLARA_CONFIG_OPTIONAL_TYPE + template + inline auto convertInto( std::string const &source, CLARA_CONFIG_OPTIONAL_TYPE& target ) -> ParserResult { + T temp; + auto result = convertInto( source, temp ); + if( result ) + target = std::move(temp); + return result; + } +#endif // CLARA_CONFIG_OPTIONAL_TYPE - struct BoundRefBase { - BoundRefBase() = default; - BoundRefBase( BoundRefBase const & ) = delete; - BoundRefBase( BoundRefBase && ) = delete; - BoundRefBase &operator=( BoundRefBase const & ) = delete; - BoundRefBase &operator=( BoundRefBase && ) = delete; + struct NonCopyable { + NonCopyable() = default; + NonCopyable( NonCopyable const & ) = delete; + NonCopyable( NonCopyable && ) = delete; + NonCopyable &operator=( NonCopyable const & ) = delete; + NonCopyable &operator=( NonCopyable && ) = delete; + }; - virtual ~BoundRefBase() = default; - - virtual auto isFlag() const -> bool = 0; + 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; - }; - - struct BoundValueRefBase : BoundRefBase { - auto isFlag() const -> bool override { return false; } - - auto setFlag( bool ) -> ParserResult override { - return ParserResult::logicError( "Flags can only be set on boolean fields" ); - } - }; - - struct BoundFlagRefBase : BoundRefBase { - auto isFlag() const -> bool override { return true; } - - auto setValue( std::string const &arg ) -> ParserResult override { - bool flag; - auto result = convertInto( arg, flag ); - if( result ) - setFlag( flag ); - return result; - } + virtual auto isFlag() const -> bool { return true; } }; template - struct BoundRef : BoundValueRefBase { + struct BoundValueRef : BoundValueRefBase { T &m_ref; - explicit BoundRef( T &ref ) : m_ref( ref ) {} + explicit BoundValueRef( T &ref ) : m_ref( ref ) {} auto setValue( std::string const &arg ) -> ParserResult override { return convertInto( arg, m_ref ); @@ -700,10 +708,10 @@ namespace detail { }; template - struct BoundRef> : BoundValueRefBase { + struct BoundValueRef> : BoundValueRefBase { std::vector &m_ref; - explicit BoundRef( std::vector &ref ) : m_ref( ref ) {} + explicit BoundValueRef( std::vector &ref ) : m_ref( ref ) {} auto isContainer() const -> bool override { return true; } @@ -748,12 +756,12 @@ namespace detail { template inline auto invokeLambda( L const &lambda, std::string const &arg ) -> ParserResult { - ArgType temp; + ArgType temp{}; auto result = convertInto( arg, temp ); return !result ? result : LambdaInvoker::ReturnType>::invoke( lambda, temp ); - }; + } template @@ -803,6 +811,9 @@ namespace detail { public: template auto operator|( T const &other ) const -> Parser; + + template + auto operator+( T const &other ) const -> Parser; }; // Common code and state for Args and Opts @@ -810,16 +821,16 @@ namespace detail { class ParserRefImpl : public ComposableParserImpl { protected: Optionality m_optionality = Optionality::Optional; - std::shared_ptr m_ref; + std::shared_ptr m_ref; std::string m_hint; std::string m_description; - explicit ParserRefImpl( std::shared_ptr const &ref ) : m_ref( ref ) {} + explicit ParserRefImpl( std::shared_ptr const &ref ) : m_ref( ref ) {} public: template ParserRefImpl( T &ref, std::string const &hint ) - : m_ref( std::make_shared>( ref ) ), + : m_ref( std::make_shared>( ref ) ), m_hint( hint ) {} @@ -860,10 +871,10 @@ namespace detail { class ExeName : public ComposableParserImpl { std::shared_ptr m_name; - std::shared_ptr m_ref; + std::shared_ptr m_ref; template - static auto makeRef(LambdaT const &lambda) -> std::shared_ptr { + static auto makeRef(LambdaT const &lambda) -> std::shared_ptr { return std::make_shared>( lambda) ; } @@ -871,7 +882,7 @@ namespace detail { ExeName() : m_name( std::make_shared( "" ) ) {} explicit ExeName( std::string &ref ) : ExeName() { - m_ref = std::make_shared>( ref ); + m_ref = std::make_shared>( ref ); } template @@ -914,7 +925,10 @@ namespace detail { if( token.type != TokenType::Argument ) return InternalParseResult::ok( ParseState( ParseResultType::NoMatch, remainingTokens ) ); - auto result = m_ref->setValue( remainingTokens->token ); + assert( !m_ref->isFlag() ); + auto valueRef = static_cast( m_ref.get() ); + + auto result = valueRef->setValue( remainingTokens->token ); if( !result ) return InternalParseResult( result ); else @@ -988,19 +1002,21 @@ namespace detail { auto const &token = *remainingTokens; if( isMatch(token.token ) ) { if( m_ref->isFlag() ) { - auto result = m_ref->setFlag( true ); + auto flagRef = static_cast( 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( 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 = m_ref->setValue( argToken.token ); + auto result = valueRef->setValue( argToken.token ); if( !result ) return InternalParseResult( result ); if( result.value() == ParseResultType::ShortCircuitAll ) @@ -1077,6 +1093,12 @@ namespace detail { return Parser( *this ) |= other; } + // Forward deprecated interface with '+' instead of '|' + template + auto operator+=( T const &other ) -> Parser & { return operator|=( other ); } + template + auto operator+( T const &other ) const -> Parser { return operator|( other ); } + auto getHelpColumns() const -> std::vector { std::vector cols; for (auto const &o : m_options) { @@ -1116,6 +1138,8 @@ namespace detail { 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 ) + diff --git a/Telegram/ThirdParty/Catch/include/internal/catch_assertionhandler.cpp b/Telegram/ThirdParty/Catch/include/internal/catch_assertionhandler.cpp index 3465269fb..c6818c14d 100644 --- a/Telegram/ThirdParty/Catch/include/internal/catch_assertionhandler.cpp +++ b/Telegram/ThirdParty/Catch/include/internal/catch_assertionhandler.cpp @@ -8,15 +8,13 @@ #include "catch_assertionhandler.h" #include "catch_assertionresult.h" -#include "catch_interfaces_capture.h" #include "catch_interfaces_runner.h" #include "catch_interfaces_config.h" #include "catch_context.h" #include "catch_debugger.h" #include "catch_interfaces_registry_hub.h" #include "catch_capture_matchers.h" - -#include +#include "catch_run_context.h" namespace Catch { @@ -56,93 +54,55 @@ namespace Catch { SourceLineInfo const& lineInfo, StringRef capturedExpression, ResultDisposition::Flags resultDisposition ) - : m_assertionInfo{ macroName, lineInfo, capturedExpression, resultDisposition } - { - getCurrentContext().getResultCapture()->assertionStarting( m_assertionInfo ); + : m_assertionInfo{ macroName, lineInfo, capturedExpression, resultDisposition }, + m_resultCapture( getResultCapture() ) + {} + + void AssertionHandler::handleExpr( ITransientExpression const& expr ) { + m_resultCapture.handleExpr( m_assertionInfo, expr, m_reaction ); } - AssertionHandler::~AssertionHandler() { - if ( m_inExceptionGuard ) { - handle( ResultWas::ThrewException, "Exception translation was disabled by CATCH_CONFIG_FAST_COMPILE" ); - getCurrentContext().getResultCapture()->exceptionEarlyReported(); - } - } - - void AssertionHandler::handle( ITransientExpression const& expr ) { - - bool negated = isFalseTest( m_assertionInfo.resultDisposition ); - bool result = expr.getResult() != negated; - - if(result && !getCurrentContext().getConfig()->includeSuccessfulResults()) - { - getCurrentContext().getResultCapture()->assertionRun(); - getCurrentContext().getResultCapture()->assertionPassed(); - return; - } - - handle( result ? ResultWas::Ok : ResultWas::ExpressionFailed, &expr, negated ); - } - void AssertionHandler::handle( ResultWas::OfType resultType ) { - handle( resultType, nullptr, false ); - } - void AssertionHandler::handle( ResultWas::OfType resultType, StringRef const& message ) { - AssertionResultData data( resultType, LazyExpression( false ) ); - data.message = message; - handle( data, nullptr ); - } - void AssertionHandler::handle( ResultWas::OfType resultType, ITransientExpression const* expr, bool negated ) { - AssertionResultData data( resultType, LazyExpression( negated ) ); - handle( data, expr ); - } - void AssertionHandler::handle( AssertionResultData const& resultData, ITransientExpression const* expr ) { - - getResultCapture().assertionRun(); - - AssertionResult assertionResult{ m_assertionInfo, resultData }; - assertionResult.m_resultData.lazyExpression.m_transientExpression = expr; - - getResultCapture().assertionEnded( assertionResult ); - - if( !assertionResult.isOk() ) { - m_shouldDebugBreak = getCurrentContext().getConfig()->shouldDebugBreak(); - m_shouldThrow = - getCurrentContext().getRunner()->aborting() || - (m_assertionInfo.resultDisposition & ResultDisposition::Normal); - } + 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(); } - auto AssertionHandler::shouldDebugBreak() const -> bool { - return m_shouldDebugBreak; - } - void AssertionHandler::reactWithDebugBreak() const { - 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 reactWithoutDebugBreak() call - /////////////////////////////////////////////////////////////////// + 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(); } - reactWithoutDebugBreak(); - } - void AssertionHandler::reactWithoutDebugBreak() const { - if( m_shouldThrow ) + if( m_reaction.shouldThrow ) throw Catch::TestFailureException(); } - - void AssertionHandler::useActiveException() { - handle( ResultWas::ThrewException, Catch::translateActiveException() ); + void AssertionHandler::setCompleted() { + m_completed = true; } - void AssertionHandler::setExceptionGuard() { - assert( m_inExceptionGuard == false ); - m_inExceptionGuard = true; + void AssertionHandler::handleUnexpectedInflightException() { + m_resultCapture.handleUnexpectedInflightException( m_assertionInfo, Catch::translateActiveException(), m_reaction ); } - void AssertionHandler::unsetExceptionGuard() { - assert( m_inExceptionGuard == true ); - m_inExceptionGuard = false; + + 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 diff --git a/Telegram/ThirdParty/Catch/include/internal/catch_assertionhandler.h b/Telegram/ThirdParty/Catch/include/internal/catch_assertionhandler.h index 9fdbee4f5..cadc78f34 100644 --- a/Telegram/ThirdParty/Catch/include/internal/catch_assertionhandler.h +++ b/Telegram/ThirdParty/Catch/include/internal/catch_assertionhandler.h @@ -8,17 +8,21 @@ #ifndef TWOBLUECUBES_CATCH_ASSERTIONHANDLER_H_INCLUDED #define TWOBLUECUBES_CATCH_ASSERTIONHANDLER_H_INCLUDED -#include "catch_decomposer.h" #include "catch_assertioninfo.h" +#include "catch_decomposer.h" +#include "catch_interfaces_capture.h" namespace Catch { struct TestFailureException{}; struct AssertionResultData; + struct IResultCapture; + class RunContext; class LazyExpression { friend class AssertionHandler; friend struct AssertionStats; + friend class RunContext; ITransientExpression const* m_transientExpression = nullptr; bool m_isNegated; @@ -32,11 +36,16 @@ namespace Catch { friend auto operator << ( std::ostream& os, LazyExpression const& lazyExpr ) -> std::ostream&; }; + struct AssertionReaction { + bool shouldDebugBreak = false; + bool shouldThrow = false; + }; + class AssertionHandler { AssertionInfo m_assertionInfo; - bool m_shouldDebugBreak = false; - bool m_shouldThrow = false; - bool m_inExceptionGuard = false; + AssertionReaction m_reaction; + bool m_completed = false; + IResultCapture& m_resultCapture; public: AssertionHandler @@ -44,26 +53,32 @@ namespace Catch { SourceLineInfo const& lineInfo, StringRef capturedExpression, ResultDisposition::Flags resultDisposition ); - ~AssertionHandler(); + ~AssertionHandler() { + if ( !m_completed ) { + m_resultCapture.handleIncomplete( m_assertionInfo ); + } + } - void handle( ITransientExpression const& expr ); template - void handle( ExprLhs const& expr ) { - handle( expr.makeUnaryExpr() ); + void handleExpr( ExprLhs const& expr ) { + handleExpr( expr.makeUnaryExpr() ); } - void handle( ResultWas::OfType resultType ); - void handle( ResultWas::OfType resultType, StringRef const& message ); - void handle( ResultWas::OfType resultType, ITransientExpression const* expr, bool negated ); - void handle( AssertionResultData const& resultData, ITransientExpression const* expr ); + void handleExpr( ITransientExpression const& expr ); - auto shouldDebugBreak() const -> bool; + 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 reactWithDebugBreak() const; - void reactWithoutDebugBreak() const; - void useActiveException(); - void setExceptionGuard(); - void unsetExceptionGuard(); }; void handleExceptionMatchExpr( AssertionHandler& handler, std::string const& str, StringRef matcherString ); diff --git a/Telegram/ThirdParty/Catch/include/internal/catch_assertionresult.cpp b/Telegram/ThirdParty/Catch/include/internal/catch_assertionresult.cpp index ec32c664e..4ce071876 100644 --- a/Telegram/ThirdParty/Catch/include/internal/catch_assertionresult.cpp +++ b/Telegram/ThirdParty/Catch/include/internal/catch_assertionresult.cpp @@ -65,9 +65,9 @@ namespace Catch { expr = m_info.capturedExpression; else { expr.reserve( m_info.macroName.size() + m_info.capturedExpression.size() + 4 ); - expr += m_info.macroName.c_str(); + expr += m_info.macroName; expr += "( "; - expr += m_info.capturedExpression.c_str(); + expr += m_info.capturedExpression; expr += " )"; } return expr; diff --git a/Telegram/ThirdParty/Catch/include/internal/catch_capture.hpp b/Telegram/ThirdParty/Catch/include/internal/catch_capture.hpp index 595336d42..e4600f7c6 100644 --- a/Telegram/ThirdParty/Catch/include/internal/catch_capture.hpp +++ b/Telegram/ThirdParty/Catch/include/internal/catch_capture.hpp @@ -11,7 +11,6 @@ #include "catch_assertionhandler.h" #include "catch_message.h" #include "catch_interfaces_capture.h" -#include "catch_debugger.h" #if !defined(CATCH_CONFIG_DISABLE) @@ -22,48 +21,33 @@ #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( handler ) \ - handler.reactWithDebugBreak(); /////////////////////////////////////////////////////////////////////////////// // 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_TRY( capturer ) capturer.setExceptionGuard(); -#define INTERNAL_CATCH_CATCH( capturer ) capturer.unsetExceptionGuard(); +#define INTERNAL_CATCH_TRY +#define INTERNAL_CATCH_CATCH( capturer ) #else // CATCH_CONFIG_FAST_COMPILE -/////////////////////////////////////////////////////////////////////////////// -// 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( handler ) \ - if( handler.shouldDebugBreak() ) CATCH_BREAK_INTO_DEBUGGER(); \ - handler.reactWithoutDebugBreak(); - -#define INTERNAL_CATCH_TRY( capturer ) try -#define INTERNAL_CATCH_CATCH( capturer ) catch(...) { capturer.useActiveException(); } +#define INTERNAL_CATCH_TRY try +#define INTERNAL_CATCH_CATCH( handler ) catch(...) { handler.handleUnexpectedInflightException(); } #endif +#define INTERNAL_CATCH_REACT( handler ) handler.complete(); + /////////////////////////////////////////////////////////////////////////////// #define INTERNAL_CATCH_TEST( macroName, resultDisposition, ... ) \ do { \ Catch::AssertionHandler catchAssertionHandler( macroName, CATCH_INTERNAL_LINEINFO, CATCH_INTERNAL_STRINGIFY(__VA_ARGS__), resultDisposition ); \ - INTERNAL_CATCH_TRY( catchAssertionHandler ) { \ + INTERNAL_CATCH_TRY { \ CATCH_INTERNAL_SUPPRESS_PARENTHESES_WARNINGS \ - catchAssertionHandler.handle( Catch::Decomposer() <= __VA_ARGS__ ); \ + catchAssertionHandler.handleExpr( Catch::Decomposer() <= __VA_ARGS__ ); \ CATCH_INTERNAL_UNSUPPRESS_PARENTHESES_WARNINGS \ } INTERNAL_CATCH_CATCH( catchAssertionHandler ) \ INTERNAL_CATCH_REACT( catchAssertionHandler ) \ - } while( Catch::isTrue(false) && static_cast( !!(__VA_ARGS__) ) ) // the expression here is never evaluated at runtime but it forces the compiler to give it a look + } while( (void)0, false && static_cast( !!(__VA_ARGS__) ) ) // the expression 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 &&. /////////////////////////////////////////////////////////////////////////////// @@ -82,13 +66,13 @@ Catch::AssertionHandler catchAssertionHandler( macroName, CATCH_INTERNAL_LINEINFO, CATCH_INTERNAL_STRINGIFY(__VA_ARGS__), resultDisposition ); \ try { \ static_cast(__VA_ARGS__); \ - catchAssertionHandler.handle( Catch::ResultWas::Ok ); \ + catchAssertionHandler.handleExceptionNotThrownAsExpected(); \ } \ catch( ... ) { \ - catchAssertionHandler.useActiveException(); \ + catchAssertionHandler.handleUnexpectedInflightException(); \ } \ INTERNAL_CATCH_REACT( catchAssertionHandler ) \ - } while( Catch::alwaysFalse() ) + } while( false ) /////////////////////////////////////////////////////////////////////////////// #define INTERNAL_CATCH_THROWS( macroName, resultDisposition, ... ) \ @@ -97,15 +81,15 @@ if( catchAssertionHandler.allowThrows() ) \ try { \ static_cast(__VA_ARGS__); \ - catchAssertionHandler.handle( Catch::ResultWas::DidntThrowException ); \ + catchAssertionHandler.handleUnexpectedExceptionNotThrown(); \ } \ catch( ... ) { \ - catchAssertionHandler.handle( Catch::ResultWas::Ok ); \ + catchAssertionHandler.handleExceptionThrownAsExpected(); \ } \ else \ - catchAssertionHandler.handle( Catch::ResultWas::Ok ); \ + catchAssertionHandler.handleThrowingCallSkipped(); \ INTERNAL_CATCH_REACT( catchAssertionHandler ) \ - } while( Catch::alwaysFalse() ) + } while( false ) /////////////////////////////////////////////////////////////////////////////// #define INTERNAL_CATCH_THROWS_AS( macroName, exceptionType, resultDisposition, expr ) \ @@ -114,31 +98,31 @@ if( catchAssertionHandler.allowThrows() ) \ try { \ static_cast(expr); \ - catchAssertionHandler.handle( Catch::ResultWas::DidntThrowException ); \ + catchAssertionHandler.handleUnexpectedExceptionNotThrown(); \ } \ catch( exceptionType const& ) { \ - catchAssertionHandler.handle( Catch::ResultWas::Ok ); \ + catchAssertionHandler.handleExceptionThrownAsExpected(); \ } \ catch( ... ) { \ - catchAssertionHandler.useActiveException(); \ + catchAssertionHandler.handleUnexpectedInflightException(); \ } \ else \ - catchAssertionHandler.handle( Catch::ResultWas::Ok ); \ + catchAssertionHandler.handleThrowingCallSkipped(); \ INTERNAL_CATCH_REACT( catchAssertionHandler ) \ - } while( Catch::alwaysFalse() ) + } while( false ) /////////////////////////////////////////////////////////////////////////////// #define INTERNAL_CATCH_MSG( macroName, messageType, resultDisposition, ... ) \ do { \ Catch::AssertionHandler catchAssertionHandler( macroName, CATCH_INTERNAL_LINEINFO, "", resultDisposition ); \ - catchAssertionHandler.handle( messageType, ( Catch::MessageStream() << __VA_ARGS__ + ::Catch::StreamEndStop() ).m_stream.str() ); \ + catchAssertionHandler.handleMessage( messageType, ( Catch::MessageStream() << __VA_ARGS__ + ::Catch::StreamEndStop() ).m_stream.str() ); \ INTERNAL_CATCH_REACT( catchAssertionHandler ) \ - } while( Catch::alwaysFalse() ) + } while( false ) /////////////////////////////////////////////////////////////////////////////// #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_INTERNAL_LINEINFO, Catch::ResultWas::Info ) << log ); /////////////////////////////////////////////////////////////////////////////// // Although this is matcher-based, it can be used with just a string @@ -148,15 +132,15 @@ if( catchAssertionHandler.allowThrows() ) \ try { \ static_cast(__VA_ARGS__); \ - catchAssertionHandler.handle( Catch::ResultWas::DidntThrowException ); \ + catchAssertionHandler.handleUnexpectedExceptionNotThrown(); \ } \ catch( ... ) { \ - handleExceptionMatchExpr( catchAssertionHandler, matcher, #matcher ); \ + Catch::handleExceptionMatchExpr( catchAssertionHandler, matcher, #matcher ); \ } \ else \ - catchAssertionHandler.handle( Catch::ResultWas::Ok ); \ + catchAssertionHandler.handleThrowingCallSkipped(); \ INTERNAL_CATCH_REACT( catchAssertionHandler ) \ - } while( Catch::alwaysFalse() ) + } while( false ) #endif // CATCH_CONFIG_DISABLE diff --git a/Telegram/ThirdParty/Catch/include/internal/catch_capture_matchers.cpp b/Telegram/ThirdParty/Catch/include/internal/catch_capture_matchers.cpp index 758177e9b..a67cc797a 100644 --- a/Telegram/ThirdParty/Catch/include/internal/catch_capture_matchers.cpp +++ b/Telegram/ThirdParty/Catch/include/internal/catch_capture_matchers.cpp @@ -13,12 +13,12 @@ namespace Catch { using StringMatcher = Matchers::Impl::MatcherBase; // This is the general overload that takes a any string matcher - // There is another overload, in catch_assertinhandler.h/.cpp, that only takes a string and infers + // 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 matcherString ) { std::string exceptionMessage = Catch::translateActiveException(); MatchExpr expr( exceptionMessage, matcher, matcherString ); - handler.handle( expr ); + handler.handleExpr( expr ); } } // namespace Catch diff --git a/Telegram/ThirdParty/Catch/include/internal/catch_capture_matchers.h b/Telegram/ThirdParty/Catch/include/internal/catch_capture_matchers.h index 77366f334..358bbc3b8 100644 --- a/Telegram/ThirdParty/Catch/include/internal/catch_capture_matchers.h +++ b/Telegram/ThirdParty/Catch/include/internal/catch_capture_matchers.h @@ -21,18 +21,14 @@ namespace Catch { ArgT const& m_arg; MatcherT m_matcher; StringRef m_matcherString; - bool m_result; public: MatchExpr( ArgT const& arg, MatcherT const& matcher, StringRef matcherString ) - : m_arg( arg ), + : ITransientExpression{ true, matcher.match( arg ) }, + m_arg( arg ), m_matcher( matcher ), - m_matcherString( matcherString ), - m_result( matcher.match( arg ) ) + m_matcherString( matcherString ) {} - auto isBinaryExpression() const -> bool override { return true; } - auto getResult() const -> bool override { return m_result; } - void streamReconstructedExpression( std::ostream &os ) const override { auto matcherAsString = m_matcher.toString(); os << Catch::Detail::stringify( m_arg ) << ' '; @@ -59,11 +55,11 @@ namespace Catch { #define INTERNAL_CHECK_THAT( macroName, matcher, resultDisposition, arg ) \ do { \ Catch::AssertionHandler catchAssertionHandler( macroName, CATCH_INTERNAL_LINEINFO, CATCH_INTERNAL_STRINGIFY(arg) ", " CATCH_INTERNAL_STRINGIFY(matcher), resultDisposition ); \ - INTERNAL_CATCH_TRY( catchAssertionHandler ) { \ - catchAssertionHandler.handle( Catch::makeMatchExpr( arg, matcher, #matcher ) ); \ + INTERNAL_CATCH_TRY { \ + catchAssertionHandler.handleExpr( Catch::makeMatchExpr( arg, matcher, #matcher ) ); \ } INTERNAL_CATCH_CATCH( catchAssertionHandler ) \ INTERNAL_CATCH_REACT( catchAssertionHandler ) \ - } while( Catch::alwaysFalse() ) + } while( false ) /////////////////////////////////////////////////////////////////////////////// @@ -73,17 +69,17 @@ namespace Catch { if( catchAssertionHandler.allowThrows() ) \ try { \ static_cast(__VA_ARGS__ ); \ - catchAssertionHandler.handle( Catch::ResultWas::DidntThrowException ); \ + catchAssertionHandler.handleUnexpectedExceptionNotThrown(); \ } \ catch( exceptionType const& ex ) { \ - catchAssertionHandler.handle( Catch::makeMatchExpr( ex, matcher, #matcher ) ); \ + catchAssertionHandler.handleExpr( Catch::makeMatchExpr( ex, matcher, #matcher ) ); \ } \ catch( ... ) { \ - catchAssertionHandler.useActiveException(); \ + catchAssertionHandler.handleUnexpectedInflightException(); \ } \ else \ - catchAssertionHandler.handle( Catch::ResultWas::Ok ); \ + catchAssertionHandler.handleThrowingCallSkipped(); \ INTERNAL_CATCH_REACT( catchAssertionHandler ) \ - } while( Catch::alwaysFalse() ) + } while( false ) #endif // TWOBLUECUBES_CATCH_CAPTURE_MATCHERS_HPP_INCLUDED diff --git a/Telegram/ThirdParty/Catch/include/internal/catch_commandline.cpp b/Telegram/ThirdParty/Catch/include/internal/catch_commandline.cpp index c0231d1a6..85af10855 100644 --- a/Telegram/ThirdParty/Catch/include/internal/catch_commandline.cpp +++ b/Telegram/ThirdParty/Catch/include/internal/catch_commandline.cpp @@ -20,9 +20,19 @@ namespace Catch { using namespace clara; auto const setWarning = [&]( std::string const& warning ) { - if( warning != "NoAssertions" ) + 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( config.warnings | WarnAbout::NoAssertions ); + config.warnings = static_cast( config.warnings | warningSet ); return ParserResult::ok( ParseResultType::Matched ); }; auto const loadTestNamesFromFile = [&]( std::string const& filename ) { diff --git a/Telegram/ThirdParty/Catch/include/internal/catch_common.cpp b/Telegram/ThirdParty/Catch/include/internal/catch_common.cpp index 470b7ea99..c271146d7 100644 --- a/Telegram/ThirdParty/Catch/include/internal/catch_common.cpp +++ b/Telegram/ThirdParty/Catch/include/internal/catch_common.cpp @@ -15,10 +15,6 @@ namespace Catch { - SourceLineInfo::SourceLineInfo( char const* _file, std::size_t _line ) noexcept - : file( _file ), - line( _line ) - {} bool SourceLineInfo::empty() const noexcept { return file[0] == '\0'; } @@ -38,9 +34,6 @@ namespace Catch { return os; } - bool alwaysTrue() { return true; } - bool alwaysFalse() { return false; } - std::string StreamEndStop::operator+() const { return std::string(); } diff --git a/Telegram/ThirdParty/Catch/include/internal/catch_common.h b/Telegram/ThirdParty/Catch/include/internal/catch_common.h index 026ac2bb5..4aaf80c59 100644 --- a/Telegram/ThirdParty/Catch/include/internal/catch_common.h +++ b/Telegram/ThirdParty/Catch/include/internal/catch_common.h @@ -43,7 +43,10 @@ namespace Catch { struct SourceLineInfo { SourceLineInfo() = delete; - SourceLineInfo( char const* _file, std::size_t _line ) noexcept; + SourceLineInfo( char const* _file, std::size_t _line ) noexcept + : file( _file ), + line( _line ) + {} SourceLineInfo( SourceLineInfo const& other ) = default; SourceLineInfo( SourceLineInfo && ) = default; @@ -60,11 +63,6 @@ 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; } - bool alwaysTrue(); - bool alwaysFalse(); - // Use this in variadic streaming macros to allow // >> +StreamEndStop // as well as diff --git a/Telegram/ThirdParty/Catch/include/internal/catch_compiler_capabilities.h b/Telegram/ThirdParty/Catch/include/internal/catch_compiler_capabilities.h index 88180af2c..0eb266c46 100644 --- a/Telegram/ThirdParty/Catch/include/internal/catch_compiler_capabilities.h +++ b/Telegram/ThirdParty/Catch/include/internal/catch_compiler_capabilities.h @@ -31,6 +31,14 @@ # define CATCH_CPP14_OR_GREATER # endif +# if __cplusplus >= 201703L +# define CATCH_CPP17_OR_GREATER +# endif + +#endif + +#if defined(CATCH_CPP17_OR_GREATER) +# define CATCH_INTERNAL_CONFIG_CPP17_UNCAUGHT_EXCEPTIONS #endif #ifdef __clang__ @@ -51,14 +59,16 @@ #endif // __clang__ +//////////////////////////////////////////////////////////////////////////////// +// 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__) - -# if !defined(CATCH_CONFIG_POSIX_SIGNALS) -# define CATCH_INTERNAL_CONFIG_NO_POSIX_SIGNALS -# endif - +#if defined(__CYGWIN__) || defined(__QNX__) || defined(__EMSCRIPTEN__) || defined(__DJGPP__) + #define CATCH_INTERNAL_CONFIG_NO_POSIX_SIGNALS #endif #ifdef __OS400__ @@ -80,6 +90,11 @@ // Visual C++ #ifdef _MSC_VER + +# if _MSC_VER >= 1900 // Visual Studio 2015 or newer +# define CATCH_INTERNAL_CONFIG_CPP17_UNCAUGHT_EXCEPTIONS +# endif + // Universal Windows platform does not support SEH // Or console colours (or console at all...) # if defined(WINAPI_FAMILY) && (WINAPI_FAMILY == WINAPI_FAMILY_APP) @@ -92,6 +107,13 @@ //////////////////////////////////////////////////////////////////////////////// +// DJGPP +#ifdef __DJGPP__ +# define CATCH_INTERNAL_CONFIG_NO_WCHAR +#endif // __DJGPP__ + +//////////////////////////////////////////////////////////////////////////////// + // Use of __COUNTER__ is suppressed during code analysis in // CLion/AppCode 2017.2.x and former, because __COUNTER__ is not properly // handled by it. @@ -108,9 +130,18 @@ # 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_NO_POSIX_SIGNALS) && !defined(CATCH_CONFIG_NO_POSIX_SIGNALS) && !defined(CATCH_CONFIG_POSIX_SIGNALS) +#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 + +#if defined(CATCH_INTERNAL_CONFIG_CPP17_UNCAUGHT_EXCEPTIONS) && !defined(CATCH_CONFIG_NO_CPP17_UNCAUGHT_EXCEPTIONS) && !defined(CATCH_CONFIG_CPP17_UNCAUGHT_EXCEPTIONS) +# define CATCH_CONFIG_CPP17_UNCAUGHT_EXCEPTIONS +#endif + #if !defined(CATCH_INTERNAL_SUPPRESS_PARENTHESES_WARNINGS) # define CATCH_INTERNAL_SUPPRESS_PARENTHESES_WARNINGS diff --git a/Telegram/ThirdParty/Catch/include/internal/catch_config.cpp b/Telegram/ThirdParty/Catch/include/internal/catch_config.cpp index 67d2b2709..1db941196 100644 --- a/Telegram/ThirdParty/Catch/include/internal/catch_config.cpp +++ b/Telegram/ThirdParty/Catch/include/internal/catch_config.cpp @@ -15,12 +15,16 @@ namespace Catch { : m_data( data ), m_stream( openStream() ) { - if( !data.testsOrTags.empty() ) { - TestSpecParser parser( ITagAliasRegistry::get() ); + TestSpecParser parser(ITagAliasRegistry::get()); + if (data.testsOrTags.empty()) { + parser.parse("~[.]"); // All not hidden tests + } + else { + m_hasTestFilters = true; for( auto const& testOrTags : data.testsOrTags ) parser.parse( testOrTags ); - m_testSpec = parser.testSpec(); } + m_testSpec = parser.testSpec(); } std::string const& Config::getFilename() const { @@ -35,9 +39,11 @@ namespace Catch { std::string Config::getProcessName() const { return m_data.processName; } std::vector const& Config::getReporterNames() const { return m_data.reporterNames; } + std::vector const& Config::getTestsOrTags() const { return m_data.testsOrTags; } std::vector 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; } @@ -46,7 +52,8 @@ namespace Catch { 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::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; } RunTests::InWhatOrder Config::runOrder() const { return m_data.runOrder; } unsigned int Config::rngSeed() const { return m_data.rngSeed; } diff --git a/Telegram/ThirdParty/Catch/include/internal/catch_config.hpp b/Telegram/ThirdParty/Catch/include/internal/catch_config.hpp index fcaa0500a..3afdff5ec 100644 --- a/Telegram/ThirdParty/Catch/include/internal/catch_config.hpp +++ b/Telegram/ThirdParty/Catch/include/internal/catch_config.hpp @@ -78,9 +78,11 @@ namespace Catch { std::string getProcessName() const; std::vector const& getReporterNames() const; + std::vector const& getTestsOrTags() const; std::vector const& getSectionsToRun() const override; virtual TestSpec const& testSpec() const override; + bool hasTestFilters() const override; bool showHelp() const; @@ -90,6 +92,7 @@ namespace Catch { std::string name() const override; bool includeSuccessfulResults() const override; bool warnAboutMissingAssertions() const override; + bool warnAboutNoTests() const override; ShowDurations::OrNot showDurations() const override; RunTests::InWhatOrder runOrder() const override; unsigned int rngSeed() const override; @@ -107,6 +110,7 @@ namespace Catch { std::unique_ptr m_stream; TestSpec m_testSpec; + bool m_hasTestFilters = false; }; } // end namespace Catch diff --git a/Telegram/ThirdParty/Catch/include/internal/catch_console_colour.cpp b/Telegram/ThirdParty/Catch/include/internal/catch_console_colour.cpp index 25949f7f7..5fb1d07f1 100644 --- a/Telegram/ThirdParty/Catch/include/internal/catch_console_colour.cpp +++ b/Telegram/ThirdParty/Catch/include/internal/catch_console_colour.cpp @@ -11,8 +11,8 @@ # pragma clang diagnostic push # pragma clang diagnostic ignored "-Wexit-time-destructors" #endif - - + + #include "catch_console_colour.h" #include "catch_enforce.h" #include "catch_errno_guard.h" @@ -84,8 +84,12 @@ namespace { 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" ); } } @@ -143,8 +147,10 @@ namespace { 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() { @@ -163,7 +169,12 @@ namespace { #ifdef CATCH_PLATFORM_MAC !isDebuggerActive() && #endif - isatty(STDOUT_FILENO); +#if !(defined(__DJGPP__) && defined(__STRICT_ANSI__)) + isatty(STDOUT_FILENO) +#else + false +#endif + ; } IColourImpl* platformColourInstance() { ErrnoGuard guard; @@ -196,7 +207,7 @@ namespace Catch { namespace Catch { Colour::Colour( Code _colourCode ) { use( _colourCode ); } - Colour::Colour( Colour&& rhs ) noexcept { + Colour::Colour( Colour&& rhs ) noexcept { m_moved = rhs.m_moved; rhs.m_moved = true; } @@ -205,7 +216,7 @@ namespace Catch { rhs.m_moved = true; return *this; } - + Colour::~Colour(){ if( !m_moved ) use( None ); } void Colour::use( Code _colourCode ) { diff --git a/Telegram/ThirdParty/Catch/include/internal/catch_console_colour.h b/Telegram/ThirdParty/Catch/include/internal/catch_console_colour.h index d1e68f879..ec653424e 100644 --- a/Telegram/ThirdParty/Catch/include/internal/catch_console_colour.h +++ b/Telegram/ThirdParty/Catch/include/internal/catch_console_colour.h @@ -30,10 +30,11 @@ namespace Catch { BrightGreen = Bright | Green, LightGrey = Bright | Grey, BrightWhite = Bright | White, + BrightYellow = Bright | Yellow, // By intention FileName = LightGrey, - Warning = Yellow, + Warning = BrightYellow, ResultError = BrightRed, ResultSuccess = BrightGreen, ResultExpectedFailure = Warning, @@ -42,7 +43,7 @@ namespace Catch { Success = Green, OriginalExpression = Cyan, - ReconstructedExpression = Yellow, + ReconstructedExpression = BrightYellow, SecondaryText = LightGrey, Headers = White diff --git a/Telegram/ThirdParty/Catch/include/internal/catch_context.cpp b/Telegram/ThirdParty/Catch/include/internal/catch_context.cpp index 0341a6f1c..e116f28f5 100644 --- a/Telegram/ThirdParty/Catch/include/internal/catch_context.cpp +++ b/Telegram/ThirdParty/Catch/include/internal/catch_context.cpp @@ -20,7 +20,7 @@ namespace Catch { return m_runner; } - virtual IConfigPtr getConfig() const override { + virtual IConfigPtr const& getConfig() const override { return m_config; } diff --git a/Telegram/ThirdParty/Catch/include/internal/catch_context.h b/Telegram/ThirdParty/Catch/include/internal/catch_context.h index eb8611ccb..3d3c6bad4 100644 --- a/Telegram/ThirdParty/Catch/include/internal/catch_context.h +++ b/Telegram/ThirdParty/Catch/include/internal/catch_context.h @@ -25,7 +25,7 @@ namespace Catch { virtual IResultCapture* getResultCapture() = 0; virtual IRunner* getRunner() = 0; - virtual IConfigPtr getConfig() const = 0; + virtual IConfigPtr const& getConfig() const = 0; }; struct IMutableContext : IContext diff --git a/Telegram/ThirdParty/Catch/include/internal/catch_debug_console.cpp b/Telegram/ThirdParty/Catch/include/internal/catch_debug_console.cpp index d817c561f..5d25f651c 100644 --- a/Telegram/ThirdParty/Catch/include/internal/catch_debug_console.cpp +++ b/Telegram/ThirdParty/Catch/include/internal/catch_debug_console.cpp @@ -9,21 +9,23 @@ #include "catch_debug_console.h" #include "catch_stream.h" #include "catch_platform.h" +#include "catch_windows_h_proxy.h" #ifdef CATCH_PLATFORM_WINDOWS -#include "catch_windows_h_proxy.h" - 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 diff --git a/Telegram/ThirdParty/Catch/include/internal/catch_debugger.h b/Telegram/ThirdParty/Catch/include/internal/catch_debugger.h index f842ff5b1..75419842b 100644 --- a/Telegram/ThirdParty/Catch/include/internal/catch_debugger.h +++ b/Telegram/ThirdParty/Catch/include/internal/catch_debugger.h @@ -40,7 +40,10 @@ namespace Catch { #ifdef CATCH_TRAP #define CATCH_BREAK_INTO_DEBUGGER() if( Catch::isDebuggerActive() ) { CATCH_TRAP(); } #else - #define CATCH_BREAK_INTO_DEBUGGER() Catch::alwaysTrue(); + namespace Catch { + inline void doNothing() {} + } + #define CATCH_BREAK_INTO_DEBUGGER() Catch::doNothing() #endif #endif // TWOBLUECUBES_CATCH_DEBUGGER_H_INCLUDED diff --git a/Telegram/ThirdParty/Catch/include/internal/catch_decomposer.h b/Telegram/ThirdParty/Catch/include/internal/catch_decomposer.h index 25824c78f..618a25090 100644 --- a/Telegram/ThirdParty/Catch/include/internal/catch_decomposer.h +++ b/Telegram/ThirdParty/Catch/include/internal/catch_decomposer.h @@ -24,27 +24,32 @@ namespace Catch { struct ITransientExpression { - virtual auto isBinaryExpression() const -> bool = 0; - virtual auto getResult() const -> bool = 0; + auto isBinaryExpression() const -> bool { return m_isBinaryExpression; } + auto getResult() const -> bool { return m_result; } virtual void streamReconstructedExpression( std::ostream &os ) const = 0; - // We don't actually need a virtual destructore, but many static analysers + ITransientExpression( bool isBinaryExpression, bool result ) + : m_isBinaryExpression( isBinaryExpression ), + m_result( result ) + {} + + // 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; + }; void formatReconstructedExpression( std::ostream &os, std::string const& lhs, StringRef op, std::string const& rhs ); template class BinaryExpr : public ITransientExpression { - bool m_result; LhsT m_lhs; StringRef m_op; RhsT m_rhs; - auto isBinaryExpression() const -> bool override { return true; } - auto getResult() const -> bool override { return m_result; } - void streamReconstructedExpression( std::ostream &os ) const override { formatReconstructedExpression ( os, Catch::Detail::stringify( m_lhs ), m_op, Catch::Detail::stringify( m_rhs ) ); @@ -52,7 +57,7 @@ namespace Catch { public: BinaryExpr( bool comparisonResult, LhsT lhs, StringRef op, RhsT rhs ) - : m_result( comparisonResult ), + : ITransientExpression{ true, comparisonResult }, m_lhs( lhs ), m_op( op ), m_rhs( rhs ) @@ -63,21 +68,21 @@ namespace Catch { class UnaryExpr : public ITransientExpression { LhsT m_lhs; - auto isBinaryExpression() const -> bool override { return false; } - auto getResult() const -> bool override { return m_lhs ? true : false; } - void streamReconstructedExpression( std::ostream &os ) const override { os << Catch::Detail::stringify( m_lhs ); } public: - UnaryExpr( LhsT lhs ) : m_lhs( lhs ) {} + explicit UnaryExpr( LhsT lhs ) + : ITransientExpression{ false, lhs ? true : false }, + m_lhs( lhs ) + {} }; // Specialised comparison functions to handle equality comparisons between ints and pointers (NULL deduces as an int) template - auto compareEqual( LhsT const& lhs, RhsT const& rhs ) -> bool { return lhs == rhs; }; + auto compareEqual( LhsT const& lhs, RhsT const& rhs ) -> bool { return static_cast(lhs == rhs); } template auto compareEqual( T* const& lhs, int rhs ) -> bool { return lhs == reinterpret_cast( rhs ); } template @@ -88,7 +93,7 @@ namespace Catch { auto compareEqual( long lhs, T* const& rhs ) -> bool { return reinterpret_cast( lhs ) == rhs; } template - auto compareNotEqual( LhsT const& lhs, RhsT&& rhs ) -> bool { return lhs != rhs; }; + auto compareNotEqual( LhsT const& lhs, RhsT&& rhs ) -> bool { return static_cast(lhs != rhs); } template auto compareNotEqual( T* const& lhs, int rhs ) -> bool { return lhs != reinterpret_cast( rhs ); } template @@ -103,43 +108,43 @@ namespace Catch { class ExprLhs { LhsT m_lhs; public: - ExprLhs( LhsT lhs ) : m_lhs( lhs ) {} + explicit ExprLhs( LhsT lhs ) : m_lhs( lhs ) {} template auto operator == ( RhsT const& rhs ) -> BinaryExpr const { - return BinaryExpr( compareEqual( m_lhs, rhs ), m_lhs, "==", rhs ); + return { compareEqual( m_lhs, rhs ), m_lhs, "==", rhs }; } auto operator == ( bool rhs ) -> BinaryExpr const { - return BinaryExpr( m_lhs == rhs, m_lhs, "==", rhs ); + return { m_lhs == rhs, m_lhs, "==", rhs }; } template auto operator != ( RhsT const& rhs ) -> BinaryExpr const { - return BinaryExpr( compareNotEqual( m_lhs, rhs ), m_lhs, "!=", rhs ); + return { compareNotEqual( m_lhs, rhs ), m_lhs, "!=", rhs }; } auto operator != ( bool rhs ) -> BinaryExpr const { - return BinaryExpr( m_lhs != rhs, m_lhs, "!=", rhs ); + return { m_lhs != rhs, m_lhs, "!=", rhs }; } template auto operator > ( RhsT const& rhs ) -> BinaryExpr const { - return BinaryExpr( m_lhs > rhs, m_lhs, ">", rhs ); + return { static_cast(m_lhs > rhs), m_lhs, ">", rhs }; } template auto operator < ( RhsT const& rhs ) -> BinaryExpr const { - return BinaryExpr( m_lhs < rhs, m_lhs, "<", rhs ); + return { static_cast(m_lhs < rhs), m_lhs, "<", rhs }; } template auto operator >= ( RhsT const& rhs ) -> BinaryExpr const { - return BinaryExpr( m_lhs >= rhs, m_lhs, ">=", rhs ); + return { static_cast(m_lhs >= rhs), m_lhs, ">=", rhs }; } template auto operator <= ( RhsT const& rhs ) -> BinaryExpr const { - return BinaryExpr( m_lhs <= rhs, m_lhs, "<=", rhs ); + return { static_cast(m_lhs <= rhs), m_lhs, "<=", rhs }; } auto makeUnaryExpr() const -> UnaryExpr { - return UnaryExpr( m_lhs ); + return UnaryExpr{ m_lhs }; } }; @@ -153,10 +158,11 @@ namespace Catch { struct Decomposer { template auto operator <= ( T const& lhs ) -> ExprLhs { - return ExprLhs( lhs ); + return ExprLhs{ lhs }; } + auto operator <=( bool value ) -> ExprLhs { - return ExprLhs( value ); + return ExprLhs{ value }; } }; diff --git a/Telegram/ThirdParty/Catch/include/internal/catch_default_main.hpp b/Telegram/ThirdParty/Catch/include/internal/catch_default_main.hpp index 4372e9cc7..17ad090a8 100644 --- a/Telegram/ThirdParty/Catch/include/internal/catch_default_main.hpp +++ b/Telegram/ThirdParty/Catch/include/internal/catch_default_main.hpp @@ -12,7 +12,7 @@ #ifndef __OBJC__ -#if defined(WIN32) && defined(_UNICODE) && !defined(DO_NOT_USE_WMAIN) +#if defined(CATCH_CONFIG_WCHAR) && defined(WIN32) && 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 * []) { #else diff --git a/Telegram/ThirdParty/Catch/include/internal/catch_enforce.h b/Telegram/ThirdParty/Catch/include/internal/catch_enforce.h index 7dc3e3d03..513dcf1c6 100644 --- a/Telegram/ThirdParty/Catch/include/internal/catch_enforce.h +++ b/Telegram/ThirdParty/Catch/include/internal/catch_enforce.h @@ -11,10 +11,9 @@ #include "catch_stream.h" #include -#include #define CATCH_PREPARE_EXCEPTION( type, msg ) \ - type( static_cast( Catch::ReusableStringStream().get() << msg ).str() ) + type( ( Catch::ReusableStringStream() << msg ).str() ) #define CATCH_INTERNAL_ERROR( msg ) \ throw CATCH_PREPARE_EXCEPTION( std::logic_error, CATCH_INTERNAL_LINEINFO << ": Internal Catch error: " << msg); #define CATCH_ERROR( msg ) \ diff --git a/Telegram/ThirdParty/Catch/include/internal/catch_exception_translator_registry.cpp b/Telegram/ThirdParty/Catch/include/internal/catch_exception_translator_registry.cpp index 77f74a884..78b9c5733 100644 --- a/Telegram/ThirdParty/Catch/include/internal/catch_exception_translator_registry.cpp +++ b/Telegram/ThirdParty/Catch/include/internal/catch_exception_translator_registry.cpp @@ -33,6 +33,17 @@ namespace Catch { 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 } diff --git a/Telegram/ThirdParty/Catch/include/internal/catch_fatal_condition.cpp b/Telegram/ThirdParty/Catch/include/internal/catch_fatal_condition.cpp index 0fa09f264..ca72d980d 100644 --- a/Telegram/ThirdParty/Catch/include/internal/catch_fatal_condition.cpp +++ b/Telegram/ThirdParty/Catch/include/internal/catch_fatal_condition.cpp @@ -17,6 +17,8 @@ # pragma GCC diagnostic ignored "-Wmissing-field-initializers" #endif +#if defined( CATCH_CONFIG_WINDOWS_SEH ) || defined( CATCH_CONFIG_POSIX_SIGNALS ) + namespace { // Report the error condition void reportFatal( char const * const message ) { @@ -24,15 +26,9 @@ namespace { } } -#if defined ( CATCH_PLATFORM_WINDOWS ) ///////////////////////////////////////// +#endif // signals/SEH handling -# if !defined ( CATCH_CONFIG_WINDOWS_SEH ) - -namespace Catch { - void FatalConditionHandler::reset() {} -} - -# else // CATCH_CONFIG_WINDOWS_SEH is defined +#if defined( CATCH_CONFIG_WINDOWS_SEH ) namespace Catch { struct SignalDefs { DWORD id; const char* name; }; @@ -72,7 +68,6 @@ namespace Catch { void FatalConditionHandler::reset() { if (isSet) { - // Unregister handler and restore the old guarantee RemoveVectoredExceptionHandler(exceptionHandlerHandle); SetThreadStackGuarantee(&guaranteeSize); exceptionHandlerHandle = nullptr; @@ -91,20 +86,7 @@ PVOID FatalConditionHandler::exceptionHandlerHandle = nullptr; } // namespace Catch -# endif // CATCH_CONFIG_WINDOWS_SEH - -#else // Not Windows - assumed to be POSIX compatible ////////////////////////// - -# if !defined(CATCH_CONFIG_POSIX_SIGNALS) - -namespace Catch { - void FatalConditionHandler::reset() {} -} - - -# else // CATCH_CONFIG_POSIX_SIGNALS is defined - -#include +#elif defined( CATCH_CONFIG_POSIX_SIGNALS ) namespace Catch { @@ -176,9 +158,13 @@ namespace Catch { } // namespace Catch -# endif // CATCH_CONFIG_POSIX_SIGNALS +#else -#endif // not Windows +namespace Catch { + void FatalConditionHandler::reset() {} +} + +#endif // signals/SEH handling #if defined(__GNUC__) # pragma GCC diagnostic pop diff --git a/Telegram/ThirdParty/Catch/include/internal/catch_fatal_condition.h b/Telegram/ThirdParty/Catch/include/internal/catch_fatal_condition.h index 9977702a0..a64fa628f 100644 --- a/Telegram/ThirdParty/Catch/include/internal/catch_fatal_condition.h +++ b/Telegram/ThirdParty/Catch/include/internal/catch_fatal_condition.h @@ -9,23 +9,12 @@ #ifndef TWOBLUECUBES_CATCH_FATAL_CONDITION_H_INCLUDED #define TWOBLUECUBES_CATCH_FATAL_CONDITION_H_INCLUDED -#include #include "catch_platform.h" #include "catch_compiler_capabilities.h" - - -#if defined ( CATCH_PLATFORM_WINDOWS ) ///////////////////////////////////////// #include "catch_windows_h_proxy.h" -# if !defined ( CATCH_CONFIG_WINDOWS_SEH ) -namespace Catch { - struct FatalConditionHandler { - void reset(); - }; -} - -# else // CATCH_CONFIG_WINDOWS_SEH is defined +#if defined( CATCH_CONFIG_WINDOWS_SEH ) namespace Catch { @@ -44,20 +33,7 @@ namespace Catch { } // namespace Catch -# endif // CATCH_CONFIG_WINDOWS_SEH - -#else // Not Windows - assumed to be POSIX compatible ////////////////////////// - -# if !defined(CATCH_CONFIG_POSIX_SIGNALS) - -namespace Catch { - struct FatalConditionHandler { - void reset(); - }; -} - - -# else // CATCH_CONFIG_POSIX_SIGNALS is defined +#elif defined ( CATCH_CONFIG_POSIX_SIGNALS ) #include @@ -66,7 +42,7 @@ namespace Catch { struct FatalConditionHandler { static bool isSet; - static struct sigaction oldSigActions[];// [sizeof(signalDefs) / sizeof(SignalDefs)]; + static struct sigaction oldSigActions[]; static stack_t oldSigStack; static char altStackMem[]; @@ -79,8 +55,15 @@ namespace Catch { } // namespace Catch -# endif // CATCH_CONFIG_POSIX_SIGNALS -#endif // not Windows +#else + +namespace Catch { + struct FatalConditionHandler { + void reset(); + }; +} + +#endif #endif // TWOBLUECUBES_CATCH_FATAL_CONDITION_H_INCLUDED diff --git a/Telegram/ThirdParty/Catch/include/internal/catch_interfaces_capture.h b/Telegram/ThirdParty/Catch/include/internal/catch_interfaces_capture.h index 5b3701148..4d091f892 100644 --- a/Telegram/ThirdParty/Catch/include/internal/catch_interfaces_capture.h +++ b/Telegram/ThirdParty/Catch/include/internal/catch_interfaces_capture.h @@ -11,6 +11,7 @@ #include #include "catch_stringref.h" +#include "catch_result_type.h" namespace Catch { @@ -22,13 +23,14 @@ namespace Catch { struct Counts; struct BenchmarkInfo; struct BenchmarkStats; + struct AssertionReaction; + + struct ITransientExpression; struct IResultCapture { virtual ~IResultCapture(); - virtual void assertionStarting( AssertionInfo const& info ) = 0; - virtual void assertionEnded( AssertionResult const& result ) = 0; virtual bool sectionStarted( SectionInfo const& sectionInfo, Counts& assertions ) = 0; virtual void sectionEnded( SectionEndInfo const& endInfo ) = 0; @@ -40,16 +42,40 @@ namespace Catch { 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 void exceptionEarlyReported() = 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(); diff --git a/Telegram/ThirdParty/Catch/include/internal/catch_interfaces_config.h b/Telegram/ThirdParty/Catch/include/internal/catch_interfaces_config.h index 2584ccc0c..f509c7ed8 100644 --- a/Telegram/ThirdParty/Catch/include/internal/catch_interfaces_config.h +++ b/Telegram/ThirdParty/Catch/include/internal/catch_interfaces_config.h @@ -25,7 +25,8 @@ namespace Catch { struct WarnAbout { enum What { Nothing = 0x00, - NoAssertions = 0x01 + NoAssertions = 0x01, + NoTests = 0x02 }; }; struct ShowDurations { enum OrNot { @@ -62,10 +63,12 @@ namespace Catch { 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 TestSpec const& testSpec() const = 0; + virtual bool hasTestFilters() const = 0; virtual RunTests::InWhatOrder runOrder() const = 0; virtual unsigned int rngSeed() const = 0; virtual int benchmarkResolutionMultiple() const = 0; diff --git a/Telegram/ThirdParty/Catch/include/internal/catch_interfaces_exception.h b/Telegram/ThirdParty/Catch/include/internal/catch_interfaces_exception.h index 3473ff52e..430701cb8 100644 --- a/Telegram/ThirdParty/Catch/include/internal/catch_interfaces_exception.h +++ b/Telegram/ThirdParty/Catch/include/internal/catch_interfaces_exception.h @@ -73,7 +73,9 @@ 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_SUPPRESS_GLOBALS_WARNINGS \ + namespace{ Catch::ExceptionTranslatorRegistrar INTERNAL_CATCH_UNIQUE_NAME( catch_internal_ExceptionRegistrar )( &translatorName ); } \ + CATCH_INTERNAL_UNSUPPRESS_GLOBALS_WARNINGS \ static std::string translatorName( signature ) #define INTERNAL_CATCH_TRANSLATE_EXCEPTION( signature ) INTERNAL_CATCH_TRANSLATE_EXCEPTION2( INTERNAL_CATCH_UNIQUE_NAME( catch_internal_ExceptionTranslator ), signature ) diff --git a/Telegram/ThirdParty/Catch/include/internal/catch_leak_detector.cpp b/Telegram/ThirdParty/Catch/include/internal/catch_leak_detector.cpp index 321093100..36aba6abc 100644 --- a/Telegram/ThirdParty/Catch/include/internal/catch_leak_detector.cpp +++ b/Telegram/ThirdParty/Catch/include/internal/catch_leak_detector.cpp @@ -8,11 +8,11 @@ #include "catch_leak_detector.h" -namespace Catch { - #ifdef CATCH_CONFIG_WINDOWS_CRTDBG #include +namespace Catch { + LeakDetector::LeakDetector() { int flag = _CrtSetDbgFlag(_CRTDBG_REPORT_FLAG); flag |= _CRTDBG_LEAK_CHECK_DF; @@ -23,11 +23,10 @@ namespace Catch { // Change this to leaking allocation's number to break there _CrtSetBreakAlloc(-1); } +} #else - LeakDetector::LeakDetector(){} + Catch::LeakDetector::LeakDetector() {} #endif - -} diff --git a/Telegram/ThirdParty/Catch/include/internal/catch_list.cpp b/Telegram/ThirdParty/Catch/include/internal/catch_list.cpp index 3efad0b77..3b0e33f11 100644 --- a/Telegram/ThirdParty/Catch/include/internal/catch_list.cpp +++ b/Telegram/ThirdParty/Catch/include/internal/catch_list.cpp @@ -28,11 +28,10 @@ namespace Catch { std::size_t listTests( Config const& config ) { TestSpec testSpec = config.testSpec(); - if( config.testSpec().hasFilters() ) + if( config.hasTestFilters() ) Catch::cout() << "Matching test cases:\n"; else { Catch::cout() << "All available test cases:\n"; - testSpec = TestSpecParser( ITagAliasRegistry::get() ).parse( "*" ).testSpec(); } auto matchedTestCases = filterTests( getAllTestCasesSorted( config ), testSpec, config ); @@ -54,7 +53,7 @@ namespace Catch { Catch::cout() << Column( testCaseInfo.tagsAsString() ).indent( 6 ) << "\n"; } - if( !config.testSpec().hasFilters() ) + 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; @@ -63,8 +62,6 @@ namespace Catch { 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 matchedTestCases = filterTests( getAllTestCasesSorted( config ), testSpec, config ); for( auto const& testCaseInfo : matchedTestCases ) { @@ -94,11 +91,10 @@ namespace Catch { std::size_t listTags( Config const& config ) { TestSpec testSpec = config.testSpec(); - if( config.testSpec().hasFilters() ) + if( config.hasTestFilters() ) Catch::cout() << "Tags for matching test cases:\n"; else { Catch::cout() << "All available tags:\n"; - testSpec = TestSpecParser( ITagAliasRegistry::get() ).parse( "*" ).testSpec(); } std::map tagCounts; diff --git a/Telegram/ThirdParty/Catch/include/internal/catch_matchers_floating.cpp b/Telegram/ThirdParty/Catch/include/internal/catch_matchers_floating.cpp index 3d2e342a1..c6d2b1dd1 100644 --- a/Telegram/ThirdParty/Catch/include/internal/catch_matchers_floating.cpp +++ b/Telegram/ThirdParty/Catch/include/internal/catch_matchers_floating.cpp @@ -79,7 +79,11 @@ namespace Catch { namespace Matchers { namespace Floating { WithinAbsMatcher::WithinAbsMatcher(double target, double margin) - :m_target{ target }, m_margin{ margin } {} + :m_target{ target }, m_margin{ margin } { + if (m_margin < 0) { + throw std::domain_error("Allowed margin difference has to be >= 0"); + } + } // Performs equivalent check of std::fabs(lhs - rhs) <= margin // But without the subtraction to allow for INFINITY in comparison @@ -95,7 +99,7 @@ namespace Floating { WithinUlpsMatcher::WithinUlpsMatcher(double target, int ulps, FloatingPointKind baseType) :m_target{ target }, m_ulps{ ulps }, m_type{ baseType } { if (m_ulps < 0) { - throw std::domain_error("Expected ulp difference has to be >0"); + throw std::domain_error("Allowed ulp difference has to be >= 0"); } } diff --git a/Telegram/ThirdParty/Catch/include/internal/catch_matchers_vector.h b/Telegram/ThirdParty/Catch/include/internal/catch_matchers_vector.h index 84ffab87b..833d7dc2c 100644 --- a/Telegram/ThirdParty/Catch/include/internal/catch_matchers_vector.h +++ b/Telegram/ThirdParty/Catch/include/internal/catch_matchers_vector.h @@ -10,10 +10,33 @@ #include "catch_matchers.h" +#include + namespace Catch { namespace Matchers { namespace Vector { + namespace Detail { + template + size_t count(InputIterator first, InputIterator last, T const& item) { + size_t cnt = 0; + for (; first != last; ++first) { + if (*first == item) { + ++cnt; + } + } + return cnt; + } + template + bool contains(InputIterator first, InputIterator last, T const& item) { + for (; first != last; ++first) { + if (*first == item) { + return true; + } + } + return false; + } + } template struct ContainsElementMatcher : MatcherBase> { @@ -89,6 +112,46 @@ namespace Matchers { std::vector const& m_comparator; }; + template + struct UnorderedEqualsMatcher : MatcherBase> { + UnorderedEqualsMatcher(std::vector const& target) : m_target(target) {} + bool match(std::vector const& vec) const override { + // Note: This is a reimplementation of std::is_permutation, + // because I don't want to include inside the common path + if (m_target.size() != vec.size()) { + return false; + } + auto lfirst = m_target.begin(), llast = m_target.end(); + auto rfirst = vec.begin(), rlast = vec.end(); + // Cut common prefix to optimize checking of permuted parts + while (lfirst != llast && *lfirst != *rfirst) { + ++lfirst; ++rfirst; + } + if (lfirst == llast) { + return true; + } + + for (auto mid = lfirst; mid != llast; ++mid) { + // Skip already counted items + if (Detail::contains(lfirst, mid, *mid)) { + continue; + } + size_t num_vec = Detail::count(rfirst, rlast, *mid); + if (num_vec == 0 || Detail::count(lfirst, llast, *mid) != num_vec) { + return false; + } + } + + return true; + } + + std::string describe() const override { + return "UnorderedEquals: " + ::Catch::Detail::stringify(m_target); + } + private: + std::vector const& m_target; + }; + } // namespace Vector // The following functions create the actual matcher objects. @@ -109,6 +172,11 @@ namespace Matchers { return Vector::EqualsMatcher( comparator ); } + template + Vector::UnorderedEqualsMatcher UnorderedEquals(std::vector const& target) { + return Vector::UnorderedEqualsMatcher(target); + } + } // namespace Matchers } // namespace Catch diff --git a/Telegram/ThirdParty/Catch/include/internal/catch_message.cpp b/Telegram/ThirdParty/Catch/include/internal/catch_message.cpp index a66c52712..8684970a9 100644 --- a/Telegram/ThirdParty/Catch/include/internal/catch_message.cpp +++ b/Telegram/ThirdParty/Catch/include/internal/catch_message.cpp @@ -8,6 +8,7 @@ #include "catch_message.h" #include "catch_interfaces_capture.h" +#include "catch_uncaught_exceptions.h" namespace Catch { @@ -50,10 +51,8 @@ namespace Catch { } ScopedMessage::~ScopedMessage() { - if ( !std::uncaught_exception() ){ + if ( !uncaught_exceptions() ){ getResultCapture().popScopedMessage(m_info); } } - - } // end namespace Catch diff --git a/Telegram/ThirdParty/Catch/include/internal/catch_message.h b/Telegram/ThirdParty/Catch/include/internal/catch_message.h index 9000fbd9f..0a512ed57 100644 --- a/Telegram/ThirdParty/Catch/include/internal/catch_message.h +++ b/Telegram/ThirdParty/Catch/include/internal/catch_message.h @@ -59,7 +59,7 @@ namespace Catch { class ScopedMessage { public: - ScopedMessage( MessageBuilder const& builder ); + explicit ScopedMessage( MessageBuilder const& builder ); ~ScopedMessage(); MessageInfo m_info; diff --git a/Telegram/ThirdParty/Catch/include/internal/catch_registry_hub.cpp b/Telegram/ThirdParty/Catch/include/internal/catch_registry_hub.cpp index ab5ad361c..d98708c58 100644 --- a/Telegram/ThirdParty/Catch/include/internal/catch_registry_hub.cpp +++ b/Telegram/ThirdParty/Catch/include/internal/catch_registry_hub.cpp @@ -87,6 +87,7 @@ namespace Catch { delete getTheRegistryHub(); getTheRegistryHub() = nullptr; cleanUpContext(); + ReusableStringStream::cleanup(); } std::string translateActiveException() { return getRegistryHub().getExceptionTranslatorRegistry().translateActiveException(); diff --git a/Telegram/ThirdParty/Catch/include/internal/catch_reporter_registrars.hpp b/Telegram/ThirdParty/Catch/include/internal/catch_reporter_registrars.hpp index ce88fa347..943fba651 100644 --- a/Telegram/ThirdParty/Catch/include/internal/catch_reporter_registrars.hpp +++ b/Telegram/ThirdParty/Catch/include/internal/catch_reporter_registrars.hpp @@ -29,7 +29,7 @@ namespace Catch { public: - ReporterRegistrar( std::string const& name ) { + explicit ReporterRegistrar( std::string const& name ) { getMutableRegistryHub().registerReporter( name, std::make_shared() ); } }; diff --git a/Telegram/ThirdParty/Catch/include/internal/catch_result_type.cpp b/Telegram/ThirdParty/Catch/include/internal/catch_result_type.cpp index 6e0488656..0f62f1b88 100644 --- a/Telegram/ThirdParty/Catch/include/internal/catch_result_type.cpp +++ b/Telegram/ThirdParty/Catch/include/internal/catch_result_type.cpp @@ -22,7 +22,6 @@ namespace Catch { } bool shouldContinueOnFailure( int flags ) { return ( flags & ResultDisposition::ContinueOnFailure ) != 0; } - bool isFalseTest( int flags ) { return ( flags & ResultDisposition::FalseTest ) != 0; } bool shouldSuppressFailure( int flags ) { return ( flags & ResultDisposition::SuppressFail ) != 0; } } // end namespace Catch diff --git a/Telegram/ThirdParty/Catch/include/internal/catch_result_type.h b/Telegram/ThirdParty/Catch/include/internal/catch_result_type.h index 6934fc110..000b4f3d8 100644 --- a/Telegram/ThirdParty/Catch/include/internal/catch_result_type.h +++ b/Telegram/ThirdParty/Catch/include/internal/catch_result_type.h @@ -47,7 +47,7 @@ namespace Catch { ResultDisposition::Flags operator | ( ResultDisposition::Flags lhs, ResultDisposition::Flags rhs ); bool shouldContinueOnFailure( int flags ); - bool isFalseTest( int flags ); + inline bool isFalseTest( int flags ) { return ( flags & ResultDisposition::FalseTest ) != 0; } bool shouldSuppressFailure( int flags ); } // end namespace Catch diff --git a/Telegram/ThirdParty/Catch/include/internal/catch_run_context.cpp b/Telegram/ThirdParty/Catch/include/internal/catch_run_context.cpp index d6ab15762..99c770583 100644 --- a/Telegram/ThirdParty/Catch/include/internal/catch_run_context.cpp +++ b/Telegram/ThirdParty/Catch/include/internal/catch_run_context.cpp @@ -10,37 +10,55 @@ namespace Catch { - StreamRedirect::StreamRedirect(std::ostream& stream, std::string& targetString) - : m_stream(stream), - m_prevBuf(stream.rdbuf()), - m_targetString(targetString) { - stream.rdbuf(m_oss.get().rdbuf()); - } + class RedirectedStream { + std::ostream& m_originalStream; + std::ostream& m_redirectionStream; + std::streambuf* m_prevBuf; - StreamRedirect::~StreamRedirect() { - m_targetString += m_oss.str(); - m_stream.rdbuf(m_prevBuf); - } + public: + 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() { + m_originalStream.rdbuf( m_prevBuf ); + } + }; - StdErrRedirect::StdErrRedirect(std::string & targetString) - :m_cerrBuf(cerr().rdbuf()), m_clogBuf(clog().rdbuf()), - m_targetString(targetString) { - cerr().rdbuf(m_oss.get().rdbuf()); - clog().rdbuf(m_oss.get().rdbuf()); - } + class RedirectedStdOut { + ReusableStringStream m_rss; + RedirectedStream m_cout; + public: + RedirectedStdOut() : m_cout( Catch::cout(), m_rss.get() ) {} + auto str() const -> std::string { return m_rss.str(); } + }; + + // 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() + : m_cerr( Catch::cerr(), m_rss.get() ), + m_clog( Catch::clog(), m_rss.get() ) + {} + auto str() const -> std::string { return m_rss.str(); } + }; - StdErrRedirect::~StdErrRedirect() { - m_targetString += m_oss.str(); - cerr().rdbuf(m_cerrBuf); - clog().rdbuf(m_clogBuf); - } RunContext::RunContext(IConfigPtr const& _config, IStreamingReporterPtr&& reporter) : m_runInfo(_config->name()), m_context(getCurrentMutableContext()), m_config(_config), m_reporter(std::move(reporter)), - m_lastAssertionInfo{ "", SourceLineInfo("",0), "", ResultDisposition::Normal } + m_lastAssertionInfo{ StringRef(), SourceLineInfo("",0), StringRef(), ResultDisposition::Normal }, + m_includeSuccessfulResults( m_config->includeSuccessfulResults() ) { m_context.setRunner(this); m_context.setConfig(m_config); @@ -66,7 +84,7 @@ namespace Catch { std::string redirectedCout; std::string redirectedCerr; - TestCaseInfo testInfo = testCase.getTestCaseInfo(); + auto const& testInfo = testCase.getTestCaseInfo(); m_reporter->testCaseStarting(testInfo); @@ -109,18 +127,20 @@ namespace Catch { return *m_reporter; } - void RunContext::assertionStarting(AssertionInfo const& info) { - m_reporter->assertionStarting( info ); - } 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. @@ -223,7 +243,7 @@ namespace Catch { tempResult.message = message; AssertionResult result(m_lastAssertionInfo, tempResult); - getResultCapture().assertionEnded(result); + assertionEnded(result); handleUnfinishedSections(); @@ -252,18 +272,15 @@ namespace Catch { } bool RunContext::lastAssertionPassed() { - return m_totals.assertions.passed == (m_prevPassed + 1); + return m_lastAssertionPassed; } void RunContext::assertionPassed() { + m_lastAssertionPassed = true; ++m_totals.assertions.passed; resetAssertionInfo(); } - void RunContext::assertionRun() { - m_prevPassed = m_totals.assertions.passed; - } - bool RunContext::aborting() const { return m_totals.assertions.failed == static_cast(m_config->abortAfter()); } @@ -275,17 +292,20 @@ namespace Catch { Counts prevAssertions = m_totals.assertions; double duration = 0; m_shouldReportUnexpected = true; - m_lastAssertionInfo = { "TEST_CASE", testCaseInfo.lineInfo, "", ResultDisposition::Normal }; + m_lastAssertionInfo = { "TEST_CASE"_sr, testCaseInfo.lineInfo, StringRef(), ResultDisposition::Normal }; seedRng(*m_config); Timer timer; try { if (m_reporter->getPreferences().shouldRedirectStdOut) { - StreamRedirect coutRedir(cout(), redirectedCout); - StdErrRedirect errRedir(redirectedCerr); + RedirectedStdOut redirectedStdOut; + RedirectedStdErr redirectedStdErr; timer.start(); invokeActiveTestCase(); + redirectedCout += redirectedStdOut.str(); + redirectedCerr += redirectedStdErr.str(); + } else { timer.start(); invokeActiveTestCase(); @@ -296,20 +316,18 @@ namespace Catch { } catch (...) { // Under CATCH_CONFIG_FAST_COMPILE, unexpected exceptions under REQUIRE assertions // are reported without translation at the point of origin. - if (m_shouldReportUnexpected) { - AssertionHandler - ( m_lastAssertionInfo.macroName, - m_lastAssertionInfo.lineInfo, - m_lastAssertionInfo.capturedExpression, - m_lastAssertionInfo.resultDisposition ).useActiveException(); + 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(); - Counts assertions = m_totals.assertions - prevAssertions; - bool missingAssertions = testForMissingAssertions(assertions); SectionStats testCaseSectionStats(testCaseSection, assertions, duration, missingAssertions); m_reporter->sectionEnded(testCaseSectionStats); } @@ -331,6 +349,113 @@ namespace Catch { 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 = 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; diff --git a/Telegram/ThirdParty/Catch/include/internal/catch_run_context.h b/Telegram/ThirdParty/Catch/include/internal/catch_run_context.h index 22c4d76a7..d0007a36e 100644 --- a/Telegram/ThirdParty/Catch/include/internal/catch_run_context.h +++ b/Telegram/ThirdParty/Catch/include/internal/catch_run_context.h @@ -28,33 +28,6 @@ namespace Catch { struct IMutableContext; - class StreamRedirect { - - public: - StreamRedirect(std::ostream& stream, std::string& targetString); - ~StreamRedirect(); - - private: - std::ostream& m_stream; - std::streambuf* m_prevBuf; - ReusableStringStream m_oss; - std::string& m_targetString; - }; - - // 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); - ~StdErrRedirect(); - private: - std::streambuf* m_cerrBuf; - std::streambuf* m_clogBuf; - ReusableStringStream m_oss; - std::string& m_targetString; - }; - /////////////////////////////////////////////////////////////////////////// class RunContext : public IResultCapture, public IRunner { @@ -63,35 +36,54 @@ namespace Catch { RunContext( RunContext const& ) = delete; RunContext& operator =( RunContext const& ) = delete; - explicit RunContext(IConfigPtr const& _config, IStreamingReporterPtr&& reporter); + explicit RunContext( IConfigPtr const& _config, IStreamingReporterPtr&& reporter ); - virtual ~RunContext(); + ~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); + 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; - private: // IResultCapture + public: // IResultCapture - - void assertionStarting(AssertionInfo const& info) override; - void assertionEnded(AssertionResult const& result) override; + // 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; - bool testForMissingAssertions(Counts& assertions); - void sectionEnded(SectionEndInfo const& endInfo) override; - void sectionEndedEarly(SectionEndInfo const& endInfo) override; + void sectionEnded( SectionEndInfo const& endInfo ) override; + void sectionEndedEarly( SectionEndInfo const& endInfo ) override; void benchmarkStarting( BenchmarkInfo const& info ) override; void benchmarkEnded( BenchmarkStats const& stats ) override; - void pushScopedMessage(MessageInfo const& message) override; - void popScopedMessage(MessageInfo const& message) override; + void pushScopedMessage( MessageInfo const& message ) override; + void popScopedMessage( MessageInfo const& message ) override; std::string getCurrentTestName() const override; @@ -105,18 +97,26 @@ namespace Catch { void assertionPassed() override; - void assertionRun() override; - public: // !TBD We need to do this another way! bool aborting() const override; private: - void runCurrentTest(std::string& redirectedCout, std::string& redirectedCerr); + 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: @@ -136,12 +136,11 @@ namespace Catch { std::vector m_unfinishedSections; std::vector m_activeSections; TrackerContext m_trackerContext; - std::size_t m_prevPassed = 0; + bool m_lastAssertionPassed = false; bool m_shouldReportUnexpected = true; + bool m_includeSuccessfulResults; }; - IResultCapture& getResultCapture(); - } // end namespace Catch #endif // TWOBLUECUBES_CATCH_RUNNER_IMPL_HPP_INCLUDED diff --git a/Telegram/ThirdParty/Catch/include/internal/catch_section.cpp b/Telegram/ThirdParty/Catch/include/internal/catch_section.cpp index c2572d5e4..72a57d517 100644 --- a/Telegram/ThirdParty/Catch/include/internal/catch_section.cpp +++ b/Telegram/ThirdParty/Catch/include/internal/catch_section.cpp @@ -8,6 +8,7 @@ #include "catch_section.h" #include "catch_capture.hpp" +#include "catch_uncaught_exceptions.h" namespace Catch { @@ -18,22 +19,15 @@ namespace Catch { m_timer.start(); } -#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() ) + if( uncaught_exceptions() ) getResultCapture().sectionEndedEarly( endInfo ); else getResultCapture().sectionEnded( endInfo ); } } -#if defined(_MSC_VER) -#pragma warning(pop) -#endif // This indicates whether the section should be executed or not Section::operator bool() const { diff --git a/Telegram/ThirdParty/Catch/include/internal/catch_session.cpp b/Telegram/ThirdParty/Catch/include/internal/catch_session.cpp index 5a6a8434a..a5f8946ef 100644 --- a/Telegram/ThirdParty/Catch/include/internal/catch_session.cpp +++ b/Telegram/ThirdParty/Catch/include/internal/catch_session.cpp @@ -18,101 +18,109 @@ #include "catch_random_number_generator.h" #include "catch_startup_exception_registry.h" #include "catch_text.h" +#include "catch_stream.h" +#include "catch_windows_h_proxy.h" #include #include +namespace Catch { -namespace { - const int MaxExitCode = 255; - using Catch::IStreamingReporterPtr; - using Catch::IConfigPtr; - using Catch::Config; + 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 << "'"); + 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; - } + return reporter; + } #ifndef CATCH_CONFIG_DEFAULT_REPORTER #define CATCH_CONFIG_DEFAULT_REPORTER "console" #endif - IStreamingReporterPtr makeReporter(std::shared_ptr const& config) { - auto const& reporterNames = config->getReporterNames(); - if (reporterNames.empty()) - return createReporter(CATCH_CONFIG_DEFAULT_REPORTER, config); + IStreamingReporterPtr makeReporter(std::shared_ptr const& config) { + auto const& reporterNames = config->getReporterNames(); + if (reporterNames.empty()) + return createReporter(CATCH_CONFIG_DEFAULT_REPORTER, config); - IStreamingReporterPtr reporter; - for (auto const& name : reporterNames) - addReporter(reporter, createReporter(name, config)); - return reporter; - } + IStreamingReporterPtr reporter; + for (auto const& name : reporterNames) + addReporter(reporter, createReporter(name, config)); + return reporter; + } #undef CATCH_CONFIG_DEFAULT_REPORTER - void addListeners(IStreamingReporterPtr& reporters, IConfigPtr const& config) { - auto const& listeners = Catch::getRegistryHub().getReporterRegistry().getListeners(); - for (auto const& listener : listeners) - addReporter(reporters, listener->create(Catch::ReporterConfig(config))); - } - - - Catch::Totals runTests(std::shared_ptr const& config) { - using namespace Catch; - IStreamingReporterPtr reporter = makeReporter(config); - addListeners(reporter, config); - - RunContext context(config, std::move(reporter)); - - Totals totals; - - context.testGroupStarting(config->name(), 1, 1); - - TestSpec testSpec = config->testSpec(); - if (!testSpec.hasFilters()) - testSpec = TestSpecParser(ITagAliasRegistry::get()).parse("~[.]").testSpec(); // All not hidden tests - - auto const& allTestCases = getAllTestCasesSorted(*config); - for (auto const& testCase : allTestCases) { - if (!context.aborting() && matchTest(testCase, testSpec, *config)) - totals += context.runTest(testCase); - else - context.reporter().skipTest(testCase); + void addListeners(IStreamingReporterPtr& reporters, IConfigPtr const& config) { + auto const& listeners = Catch::getRegistryHub().getReporterRegistry().getListeners(); + for (auto const& listener : listeners) + addReporter(reporters, listener->create(Catch::ReporterConfig(config))); } - context.testGroupEnded(config->name(), totals, 1, 1); - return totals; - } - void applyFilenamesAsTags(Catch::IConfig const& config) { - using namespace Catch; - auto& tests = const_cast&>(getAllTestCasesSorted(config)); - for (auto& testCase : tests) { - auto tags = testCase.tags; + Catch::Totals runTests(std::shared_ptr const& config) { + IStreamingReporterPtr reporter = makeReporter(config); + addListeners(reporter, config); - std::string filename = testCase.lineInfo.file; - auto lastSlash = filename.find_last_of("\\/"); - if (lastSlash != std::string::npos) { - filename.erase(0, lastSlash); - filename[0] = '#'; + RunContext context(config, std::move(reporter)); + + Totals totals; + + context.testGroupStarting(config->name(), 1, 1); + + TestSpec testSpec = config->testSpec(); + + auto const& allTestCases = getAllTestCasesSorted(*config); + for (auto const& testCase : allTestCases) { + if (!context.aborting() && matchTest(testCase, testSpec, *config)) + totals += context.runTest(testCase); + else + context.reporter().skipTest(testCase); } - auto lastDot = filename.find_last_of('.'); - if (lastDot != std::string::npos) { - filename.erase(lastDot); + if (config->warnAboutNoTests() && totals.testCases.total() == 0) { + ReusableStringStream testConfig; + + bool first = true; + for (const auto& input : config->getTestsOrTags()) { + if (!first) { testConfig << ' '; } + first = false; + testConfig << input; + } + + context.reporter().noMatchingTestCases(testConfig.str()); + totals.error = -1; } - tags.push_back(std::move(filename)); - setTags(testCase, tags); + context.testGroupEnded(config->name(), totals, 1, 1); + return totals; } - } -} + void applyFilenamesAsTags(Catch::IConfig const& config) { + auto& tests = const_cast&>(getAllTestCasesSorted(config)); + for (auto& testCase : tests) { + auto tags = testCase.tags; -namespace Catch { + std::string filename = testCase.lineInfo.file; + auto lastSlash = filename.find_last_of("\\/"); + if (lastSlash != std::string::npos) { + filename.erase(0, lastSlash); + filename[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; @@ -125,7 +133,7 @@ namespace Catch { if ( !exceptions.empty() ) { m_startupExceptions = true; Colour colourGuard( Colour::Red ); - Catch::cerr() << "Errors occured during startup!" << '\n'; + Catch::cerr() << "Errors occurred during startup!" << '\n'; // iterate over all exceptions and notify user for ( const auto& ex_ptr : exceptions ) { try { @@ -157,7 +165,7 @@ namespace Catch { << std::left << std::setw(16) << "version: " << libraryVersion() << std::endl; } - int Session::applyCommandLine( int argc, char* argv[] ) { + int Session::applyCommandLine( int argc, char const * const * argv ) { if( m_startupExceptions ) return 1; @@ -194,7 +202,7 @@ namespace Catch { return returnCode; } -#if defined(WIN32) && defined(UNICODE) +#if defined(CATCH_CONFIG_WCHAR) && defined(WIN32) && defined(UNICODE) int Session::run( int argc, wchar_t* const argv[] ) { char **utf8Argv = new char *[ argc ]; @@ -265,7 +273,11 @@ namespace Catch { if( Option listed = list( config() ) ) return static_cast( *listed ); - return (std::min)( MaxExitCode, static_cast( runTests( m_config ).assertions.failed ) ); + auto totals = runTests( m_config ); + // 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(totals.assertions.failed))); } catch( std::exception& ex ) { Catch::cerr() << ex.what() << std::endl; diff --git a/Telegram/ThirdParty/Catch/include/internal/catch_session.h b/Telegram/ThirdParty/Catch/include/internal/catch_session.h index b814aa6a9..eb8013cd2 100644 --- a/Telegram/ThirdParty/Catch/include/internal/catch_session.h +++ b/Telegram/ThirdParty/Catch/include/internal/catch_session.h @@ -25,12 +25,12 @@ namespace Catch { void showHelp() const; void libIdentify(); - int applyCommandLine( int argc, char* argv[] ); + int applyCommandLine( int argc, char const * const * argv ); void useConfigData( ConfigData const& configData ); int run( int argc, char* argv[] ); - #if defined(WIN32) && defined(UNICODE) + #if defined(CATCH_CONFIG_WCHAR) && defined(WIN32) && defined(UNICODE) int run( int argc, wchar_t* const argv[] ); #endif int run(); diff --git a/Telegram/ThirdParty/Catch/include/internal/catch_stream.cpp b/Telegram/ThirdParty/Catch/include/internal/catch_stream.cpp index 76bbc8f32..125fd471e 100644 --- a/Telegram/ThirdParty/Catch/include/internal/catch_stream.cpp +++ b/Telegram/ThirdParty/Catch/include/internal/catch_stream.cpp @@ -145,6 +145,7 @@ namespace Catch { std::vector> m_streams; std::vector m_unused; std::ostringstream m_referenceStream; // Used for copy state/ flags from + static StringStreams* s_instance; auto add() -> std::size_t { if( m_unused.empty() ) { @@ -165,11 +166,21 @@ namespace Catch { // !TBD: put in TLS static auto instance() -> StringStreams& { - static StringStreams s_stringStreams; - return s_stringStreams; + if( !s_instance ) + s_instance = new StringStreams(); + return *s_instance; + } + static void cleanup() { + delete s_instance; + s_instance = nullptr; } }; + StringStreams* StringStreams::s_instance = nullptr; + + void ReusableStringStream::cleanup() { + StringStreams::cleanup(); + } ReusableStringStream::ReusableStringStream() : m_index( StringStreams::instance().add() ), diff --git a/Telegram/ThirdParty/Catch/include/internal/catch_stream.h b/Telegram/ThirdParty/Catch/include/internal/catch_stream.h index 2b41adbd9..c5e78b226 100644 --- a/Telegram/ThirdParty/Catch/include/internal/catch_stream.h +++ b/Telegram/ThirdParty/Catch/include/internal/catch_stream.h @@ -43,6 +43,8 @@ namespace Catch { return *this; } auto get() -> std::ostream& { return *m_oss; } + + static void cleanup(); }; } diff --git a/Telegram/ThirdParty/Catch/include/internal/catch_stringref.cpp b/Telegram/ThirdParty/Catch/include/internal/catch_stringref.cpp index bac8b1d8e..9e9095e4b 100644 --- a/Telegram/ThirdParty/Catch/include/internal/catch_stringref.cpp +++ b/Telegram/ThirdParty/Catch/include/internal/catch_stringref.cpp @@ -15,6 +15,13 @@ #include #include +#include + +namespace { + const uint32_t byte_2_lead = 0xC0; + const uint32_t byte_3_lead = 0xE0; + const uint32_t byte_4_lead = 0xF0; +} namespace Catch { StringRef::StringRef( char const* rawChars ) noexcept @@ -36,7 +43,7 @@ namespace Catch { const_cast( this )->takeOwnership(); return m_start; } - auto StringRef::data() const noexcept -> char const* { + auto StringRef::currentData() const noexcept -> char const* { return m_start; } @@ -79,13 +86,12 @@ namespace Catch { // Make adjustments for uft encodings for( size_type i=0; i < m_size; ++i ) { char c = m_start[i]; - if( ( c & 0b11000000 ) == 0b11000000 ) { - if( ( c & 0b11100000 ) == 0b11000000 ) + if( ( c & byte_2_lead ) == byte_2_lead ) { + noChars--; + if (( c & byte_3_lead ) == byte_3_lead ) + noChars--; + if( ( c & byte_4_lead ) == byte_4_lead ) noChars--; - else if( ( c & 0b11110000 ) == 0b11100000 ) - noChars-=2; - else if( ( c & 0b11111000 ) == 0b11110000 ) - noChars-=3; } } return noChars; @@ -106,7 +112,12 @@ namespace Catch { } auto operator << ( std::ostream& os, StringRef const& str ) -> std::ostream& { - return os << str.c_str(); + return os.write(str.currentData(), str.size()); + } + + auto operator+=( std::string& lhs, StringRef const& rhs ) -> std::string& { + lhs.append(rhs.currentData(), rhs.size()); + return lhs; } } // namespace Catch diff --git a/Telegram/ThirdParty/Catch/include/internal/catch_stringref.h b/Telegram/ThirdParty/Catch/include/internal/catch_stringref.h index 0f9e78011..757d70cc1 100644 --- a/Telegram/ThirdParty/Catch/include/internal/catch_stringref.h +++ b/Telegram/ThirdParty/Catch/include/internal/catch_stringref.h @@ -12,7 +12,7 @@ #include namespace Catch { - + class StringData; /// A non-owning string class (similar to the forthcoming std::string_view) @@ -31,13 +31,13 @@ namespace Catch { char const* m_start; size_type m_size; - + char* m_data = nullptr; - + void takeOwnership(); static constexpr char const* const s_empty = ""; - + public: // construction/ assignment StringRef() noexcept : StringRef( s_empty, 0 ) @@ -83,13 +83,13 @@ namespace Catch { operator std::string() const; void swap( StringRef& other ) noexcept; - + public: // operators auto operator == ( StringRef const& other ) const noexcept -> bool; auto operator != ( StringRef const& other ) const noexcept -> bool; - + auto operator[] ( size_type index ) const noexcept -> char; - + public: // named queries auto empty() const noexcept -> bool { return m_size == 0; @@ -100,22 +100,27 @@ namespace Catch { auto numberOfCharacters() const noexcept -> size_type; auto c_str() const -> char const*; - + public: // substrings and searches auto substr( size_type start, size_type size ) const noexcept -> StringRef; + // Returns the current start pointer. + // Note that the pointer can change when if the StringRef is a substring + auto currentData() const noexcept -> char const*; + private: // ownership queries - may not be consistent between calls auto isOwned() const noexcept -> bool; auto isSubstring() const noexcept -> bool; - auto data() const noexcept -> char const*; }; auto operator + ( StringRef const& lhs, StringRef const& rhs ) -> std::string; auto operator + ( StringRef const& lhs, char const* rhs ) -> std::string; auto operator + ( char const* lhs, StringRef const& rhs ) -> std::string; + auto operator += ( std::string& lhs, StringRef const& sr ) -> std::string&; auto operator << ( std::ostream& os, StringRef const& sr ) -> std::ostream&; + inline auto operator "" _sr( char const* rawChars, std::size_t size ) noexcept -> StringRef { return StringRef( rawChars, size ); } diff --git a/Telegram/ThirdParty/Catch/include/internal/catch_suppress_warnings.h b/Telegram/ThirdParty/Catch/include/internal/catch_suppress_warnings.h index 65ed6a621..928011424 100644 --- a/Telegram/ThirdParty/Catch/include/internal/catch_suppress_warnings.h +++ b/Telegram/ThirdParty/Catch/include/internal/catch_suppress_warnings.h @@ -10,9 +10,6 @@ # 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" @@ -20,10 +17,8 @@ # 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" - # pragma GCC diagnostic push # pragma GCC diagnostic ignored "-Wpadded" #endif diff --git a/Telegram/ThirdParty/Catch/include/internal/catch_tag_alias_autoregistrar.h b/Telegram/ThirdParty/Catch/include/internal/catch_tag_alias_autoregistrar.h index e9b961e4f..32a5734ef 100644 --- a/Telegram/ThirdParty/Catch/include/internal/catch_tag_alias_autoregistrar.h +++ b/Telegram/ThirdParty/Catch/include/internal/catch_tag_alias_autoregistrar.h @@ -17,6 +17,9 @@ namespace Catch { } // end namespace Catch -#define CATCH_REGISTER_TAG_ALIAS( alias, spec ) namespace{ Catch::RegistrarForTagAliases INTERNAL_CATCH_UNIQUE_NAME( AutoRegisterTagAlias )( alias, spec, CATCH_INTERNAL_LINEINFO ); } +#define CATCH_REGISTER_TAG_ALIAS( alias, spec ) \ + CATCH_INTERNAL_SUPPRESS_GLOBALS_WARNINGS \ + namespace{ Catch::RegistrarForTagAliases INTERNAL_CATCH_UNIQUE_NAME( AutoRegisterTagAlias )( alias, spec, CATCH_INTERNAL_LINEINFO ); } \ + CATCH_INTERNAL_UNSUPPRESS_GLOBALS_WARNINGS #endif // TWOBLUECUBES_CATCH_TAG_ALIAS_AUTOREGISTRAR_H_INCLUDED diff --git a/Telegram/ThirdParty/Catch/include/internal/catch_test_case_info.cpp b/Telegram/ThirdParty/Catch/include/internal/catch_test_case_info.cpp index 4ab977558..9bf68912c 100644 --- a/Telegram/ThirdParty/Catch/include/internal/catch_test_case_info.cpp +++ b/Telegram/ThirdParty/Catch/include/internal/catch_test_case_info.cpp @@ -48,8 +48,7 @@ namespace Catch { TestCase makeTestCase( ITestInvoker* _testCase, std::string const& _className, - std::string const& _name, - std::string const& _descOrTags, + NameAndTags const& nameAndTags, SourceLineInfo const& _lineInfo ) { bool isHidden = false; @@ -58,6 +57,7 @@ namespace Catch { std::vector tags; std::string desc, tag; bool inTag = false; + std::string _descOrTags = nameAndTags.tags; for (char c : _descOrTags) { if( !inTag ) { if( c == '[' ) @@ -85,8 +85,8 @@ namespace Catch { tags.push_back( "." ); } - TestCaseInfo info( _name, _className, desc, tags, _lineInfo ); - return TestCase( _testCase, info ); + TestCaseInfo info( nameAndTags.name, _className, desc, tags, _lineInfo ); + return TestCase( _testCase, std::move(info) ); } void setTags( TestCaseInfo& testCaseInfo, std::vector tags ) { @@ -147,7 +147,7 @@ namespace Catch { } - TestCase::TestCase( ITestInvoker* testCase, TestCaseInfo const& info ) : TestCaseInfo( info ), test( testCase ) {} + TestCase::TestCase( ITestInvoker* testCase, TestCaseInfo&& info ) : TestCaseInfo( std::move(info) ), test( testCase ) {} TestCase TestCase::withName( std::string const& _newName ) const { diff --git a/Telegram/ThirdParty/Catch/include/internal/catch_test_case_info.h b/Telegram/ThirdParty/Catch/include/internal/catch_test_case_info.h index 2a911b061..809c974f9 100644 --- a/Telegram/ThirdParty/Catch/include/internal/catch_test_case_info.h +++ b/Telegram/ThirdParty/Catch/include/internal/catch_test_case_info.h @@ -9,6 +9,7 @@ #define TWOBLUECUBES_CATCH_TEST_CASE_INFO_H_INCLUDED #include "catch_common.h" +#include "catch_test_registry.h" #include #include @@ -61,7 +62,7 @@ namespace Catch { class TestCase : public TestCaseInfo { public: - TestCase( ITestInvoker* testCase, TestCaseInfo const& info ); + TestCase( ITestInvoker* testCase, TestCaseInfo&& info ); TestCase withName( std::string const& _newName ) const; @@ -78,8 +79,7 @@ namespace Catch { TestCase makeTestCase( ITestInvoker* testCase, std::string const& className, - std::string const& name, - std::string const& description, + NameAndTags const& nameAndTags, SourceLineInfo const& lineInfo ); } diff --git a/Telegram/ThirdParty/Catch/include/internal/catch_test_case_registry_impl.cpp b/Telegram/ThirdParty/Catch/include/internal/catch_test_case_registry_impl.cpp index 89c72392f..b30b112ae 100644 --- a/Telegram/ThirdParty/Catch/include/internal/catch_test_case_registry_impl.cpp +++ b/Telegram/ThirdParty/Catch/include/internal/catch_test_case_registry_impl.cpp @@ -96,7 +96,7 @@ namespace Catch { m_testAsFunction(); } - std::string extractClassName( std::string const& classOrQualifiedMethodName ) { + std::string extractClassName( StringRef const& classOrQualifiedMethodName ) { std::string className = classOrQualifiedMethodName; if( startsWith( className, '&' ) ) { diff --git a/Telegram/ThirdParty/Catch/include/internal/catch_test_case_registry_impl.h b/Telegram/ThirdParty/Catch/include/internal/catch_test_case_registry_impl.h index ad45e5a09..8dc5b0fe3 100644 --- a/Telegram/ThirdParty/Catch/include/internal/catch_test_case_registry_impl.h +++ b/Telegram/ThirdParty/Catch/include/internal/catch_test_case_registry_impl.h @@ -22,7 +22,7 @@ namespace Catch { class TestCase; struct IConfig; - std::vector sortTests( IConfig const& config, std::vector const& unsortedTestCases ); + std::vector sortTests( IConfig const& config, std::vector const& unsortedTestCases ); bool matchTest( TestCase const& testCase, TestSpec const& testSpec, IConfig const& config ); void enforceNoDuplicateTestCases( std::vector const& functions ); @@ -58,7 +58,7 @@ namespace Catch { }; - std::string extractClassName( std::string const& classOrQualifiedMethodName ); + std::string extractClassName( StringRef const& classOrQualifiedMethodName ); /////////////////////////////////////////////////////////////////////////// diff --git a/Telegram/ThirdParty/Catch/include/internal/catch_test_registry.cpp b/Telegram/ThirdParty/Catch/include/internal/catch_test_registry.cpp index ec50e92c7..ac83f3332 100644 --- a/Telegram/ThirdParty/Catch/include/internal/catch_test_registry.cpp +++ b/Telegram/ThirdParty/Catch/include/internal/catch_test_registry.cpp @@ -15,23 +15,22 @@ namespace Catch { return new(std::nothrow) TestInvokerAsFunction( testAsFunction ); } - NameAndTags::NameAndTags( StringRef name_ , StringRef tags_ ) noexcept : name( name_ ), tags( tags_ ) {} + NameAndTags::NameAndTags( StringRef const& name_ , StringRef const& tags_ ) noexcept : name( name_ ), tags( tags_ ) {} - AutoReg::AutoReg( ITestInvoker* invoker, SourceLineInfo const& lineInfo, StringRef classOrMethod, NameAndTags const& nameAndTags ) noexcept { + AutoReg::AutoReg( ITestInvoker* invoker, SourceLineInfo const& lineInfo, StringRef const& classOrMethod, NameAndTags const& nameAndTags ) noexcept { try { getMutableRegistryHub() .registerTest( makeTestCase( invoker, extractClassName( classOrMethod ), - nameAndTags.name, - nameAndTags.tags, + nameAndTags, lineInfo)); } catch (...) { // Do not throw when constructing global objects, instead register the exception to be processed later getMutableRegistryHub().registerStartupException(); } } - + AutoReg::~AutoReg() = default; } diff --git a/Telegram/ThirdParty/Catch/include/internal/catch_test_registry.h b/Telegram/ThirdParty/Catch/include/internal/catch_test_registry.h index 84001018b..a192a5312 100644 --- a/Telegram/ThirdParty/Catch/include/internal/catch_test_registry.h +++ b/Telegram/ThirdParty/Catch/include/internal/catch_test_registry.h @@ -35,13 +35,13 @@ auto makeTestInvoker( void (C::*testAsMethod)() ) noexcept -> ITestInvoker* { } struct NameAndTags { - NameAndTags( StringRef name_ = StringRef(), StringRef tags_ = StringRef() ) noexcept; + NameAndTags( StringRef const& name_ = StringRef(), StringRef const& tags_ = StringRef() ) noexcept; StringRef name; StringRef tags; }; struct AutoReg : NonCopyable { - AutoReg( ITestInvoker* invoker, SourceLineInfo const& lineInfo, StringRef classOrMethod, NameAndTags const& nameAndTags ) noexcept; + AutoReg( ITestInvoker* invoker, SourceLineInfo const& lineInfo, StringRef const& classOrMethod, NameAndTags const& nameAndTags ) noexcept; ~AutoReg(); }; diff --git a/Telegram/ThirdParty/Catch/include/internal/catch_timer.cpp b/Telegram/ThirdParty/Catch/include/internal/catch_timer.cpp index a6f37e8ef..b9ae68879 100644 --- a/Telegram/ThirdParty/Catch/include/internal/catch_timer.cpp +++ b/Telegram/ThirdParty/Catch/include/internal/catch_timer.cpp @@ -45,11 +45,11 @@ namespace Catch { void Timer::start() { m_nanoseconds = getCurrentNanosecondsSinceEpoch(); } - auto Timer::getElapsedNanoseconds() const -> unsigned int { - return static_cast(getCurrentNanosecondsSinceEpoch() - m_nanoseconds); + auto Timer::getElapsedNanoseconds() const -> uint64_t { + return getCurrentNanosecondsSinceEpoch() - m_nanoseconds; } - auto Timer::getElapsedMicroseconds() const -> unsigned int { - return static_cast(getElapsedNanoseconds()/1000); + auto Timer::getElapsedMicroseconds() const -> uint64_t { + return getElapsedNanoseconds()/1000; } auto Timer::getElapsedMilliseconds() const -> unsigned int { return static_cast(getElapsedMicroseconds()/1000); diff --git a/Telegram/ThirdParty/Catch/include/internal/catch_timer.h b/Telegram/ThirdParty/Catch/include/internal/catch_timer.h index 28e1f9dbd..74ab428e4 100644 --- a/Telegram/ThirdParty/Catch/include/internal/catch_timer.h +++ b/Telegram/ThirdParty/Catch/include/internal/catch_timer.h @@ -19,8 +19,8 @@ namespace Catch { uint64_t m_nanoseconds = 0; public: void start(); - auto getElapsedNanoseconds() const -> unsigned int; - auto getElapsedMicroseconds() const -> unsigned int; + auto getElapsedNanoseconds() const -> uint64_t; + auto getElapsedMicroseconds() const -> uint64_t; auto getElapsedMilliseconds() const -> unsigned int; auto getElapsedSeconds() const -> double; }; diff --git a/Telegram/ThirdParty/Catch/include/internal/catch_tostring.cpp b/Telegram/ThirdParty/Catch/include/internal/catch_tostring.cpp index a9f7735e0..0d0158fa6 100644 --- a/Telegram/ThirdParty/Catch/include/internal/catch_tostring.cpp +++ b/Telegram/ThirdParty/Catch/include/internal/catch_tostring.cpp @@ -116,6 +116,7 @@ std::string StringMaker::convert(const std::string& str) { return s; } +#ifdef CATCH_CONFIG_WCHAR std::string StringMaker::convert(const std::wstring& wstr) { std::string s; s.reserve(wstr.size()); @@ -124,6 +125,7 @@ std::string StringMaker::convert(const std::wstring& wstr) { } return ::Catch::Detail::stringify(s); } +#endif std::string StringMaker::convert(char const* str) { if (str) { @@ -139,6 +141,7 @@ std::string StringMaker::convert(char* str) { return{ "{null string}" }; } } +#ifdef CATCH_CONFIG_WCHAR std::string StringMaker::convert(wchar_t const * str) { if (str) { return ::Catch::Detail::stringify(std::wstring{ str }); @@ -153,6 +156,7 @@ std::string StringMaker::convert(wchar_t * str) { return{ "{null string}" }; } } +#endif std::string StringMaker::convert(int value) { diff --git a/Telegram/ThirdParty/Catch/include/internal/catch_tostring.h b/Telegram/ThirdParty/Catch/include/internal/catch_tostring.h index 79e02448f..26756fa99 100644 --- a/Telegram/ThirdParty/Catch/include/internal/catch_tostring.h +++ b/Telegram/ThirdParty/Catch/include/internal/catch_tostring.h @@ -13,6 +13,7 @@ #include #include #include +#include "catch_compiler_capabilities.h" #include "catch_stream.h" #ifdef __OBJC__ @@ -57,25 +58,43 @@ namespace Catch { static const bool value = decltype(test(0))::value; }; + template + std::string convertUnknownEnumToString( E e ); + + template + typename std::enable_if::value, std::string>::type convertUnstreamable( T const& value ) { +#if !defined(CATCH_CONFIG_FALLBACK_STRINGIFIER) + (void)value; + return Detail::unprintableString; +#else + return CATCH_CONFIG_FALLBACK_STRINGIFIER(value); +#endif + } + template + typename std::enable_if::value, std::string>::type convertUnstreamable( T const& value ) { + return convertUnknownEnumToString( value ); + } + } // namespace Detail + // If we decide for C++14, change these to enable_if_ts - template + template struct StringMaker { template static typename std::enable_if<::Catch::Detail::IsStreamInsertable::value, std::string>::type - convert(const Fake& t) { + convert(const Fake& value) { ReusableStringStream rss; - rss << t; + rss << value; return rss.str(); } template static typename std::enable_if::value, std::string>::type - convert(const Fake&) { - return Detail::unprintableString; + convert( const Fake& value ) { + return Detail::convertUnstreamable( value ); } }; @@ -88,8 +107,12 @@ namespace Catch { return ::Catch::StringMaker::type>::type>::convert(e); } - } // namespace Detail + template + std::string convertUnknownEnumToString( E e ) { + return ::Catch::Detail::stringify(static_cast::type>(e)); + } + } // namespace Detail // Some predefined specializations @@ -97,10 +120,12 @@ namespace Catch { struct StringMaker { static std::string convert(const std::string& str); }; +#ifdef CATCH_CONFIG_WCHAR template<> struct StringMaker { static std::string convert(const std::wstring& wstr); }; +#endif template<> struct StringMaker { @@ -110,6 +135,7 @@ namespace Catch { struct StringMaker { static std::string convert(char * str); }; +#ifdef CATCH_CONFIG_WCHAR template<> struct StringMaker { static std::string convert(wchar_t const * str); @@ -118,6 +144,7 @@ namespace Catch { struct StringMaker { static std::string convert(wchar_t * str); }; +#endif template struct StringMaker { @@ -233,20 +260,6 @@ namespace Catch { } } - template - struct StringMaker > { - static std::string convert( std::vector const& v ) { - return ::Catch::Detail::rangeToString( v.begin(), v.end() ); - } - }; - - template - struct EnumStringMaker { - static std::string convert(const T& t) { - return ::Catch::Detail::stringify(static_cast::type>(t)); - } - }; - #ifdef __OBJC__ template<> struct StringMaker { @@ -344,6 +357,61 @@ namespace Catch { } #endif // CATCH_CONFIG_ENABLE_TUPLE_STRINGMAKER +namespace Catch { + struct not_this_one {}; // Tag type for detecting which begin/ end are being selected + + // Import begin/ end from std here so they are considered alongside the fallback (...) overloads in this namespace + using std::begin; + using std::end; + + not_this_one begin( ... ); + not_this_one end( ... ); + + template + struct is_range { + static const bool value = + !std::is_same())), not_this_one>::value && + !std::is_same())), not_this_one>::value; + }; + + template + std::string rangeToString( Range const& range ) { + return ::Catch::Detail::rangeToString( begin( range ), end( range ) ); + } + + // Handle vector specially + template + std::string rangeToString( std::vector 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 + struct StringMaker::value && !::Catch::Detail::IsStreamInsertable::value>::type> { + static std::string convert( R const& range ) { + return rangeToString( range ); + } + }; + + template + struct StringMaker { + static std::string convert(T const(&arr)[SZ]) { + return rangeToString(arr); + } + }; + + +} // namespace Catch // Separate std::chrono::duration specialization #if defined(CATCH_CONFIG_ENABLE_CHRONO_STRINGMAKER) diff --git a/Telegram/ThirdParty/Catch/include/internal/catch_totals.h b/Telegram/ThirdParty/Catch/include/internal/catch_totals.h index 9507582d5..569272832 100644 --- a/Telegram/ThirdParty/Catch/include/internal/catch_totals.h +++ b/Telegram/ThirdParty/Catch/include/internal/catch_totals.h @@ -32,7 +32,7 @@ namespace Catch { Totals delta( Totals const& prevTotals ) const; - + int error = 0; Counts assertions; Counts testCases; }; diff --git a/Telegram/ThirdParty/Catch/include/internal/catch_uncaught_exceptions.cpp b/Telegram/ThirdParty/Catch/include/internal/catch_uncaught_exceptions.cpp new file mode 100644 index 000000000..b990ccd8f --- /dev/null +++ b/Telegram/ThirdParty/Catch/include/internal/catch_uncaught_exceptions.cpp @@ -0,0 +1,21 @@ +/* + * Created by Josh on 1/2/2018. + * Copyright 2018 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) + */ + +#include "catch_compiler_capabilities.h" +#include "catch_uncaught_exceptions.h" +#include + +namespace Catch { + bool uncaught_exceptions() { +#if defined(CATCH_CONFIG_CPP17_UNCAUGHT_EXCEPTIONS) + return std::uncaught_exceptions() > 0; +#else + return std::uncaught_exception(); +#endif + } +} // end namespace Catch diff --git a/Telegram/ThirdParty/Catch/include/internal/catch_uncaught_exceptions.h b/Telegram/ThirdParty/Catch/include/internal/catch_uncaught_exceptions.h new file mode 100644 index 000000000..c68d680cc --- /dev/null +++ b/Telegram/ThirdParty/Catch/include/internal/catch_uncaught_exceptions.h @@ -0,0 +1,15 @@ +/* + * Created by Josh on 1/2/2018. + * Copyright 2018 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_CATCH_UNCAUGHT_EXCEPTIONS_H_INCLUDED +#define TWOBLUECUBES_CATCH_UNCAUGHT_EXCEPTIONS_H_INCLUDED + +namespace Catch { + bool uncaught_exceptions(); +} // end namespace Catch + +#endif // TWOBLUECUBES_CATCH_UNCAUGHT_EXCEPTIONS_H_INCLUDED diff --git a/Telegram/ThirdParty/Catch/include/internal/catch_version.cpp b/Telegram/ThirdParty/Catch/include/internal/catch_version.cpp index a9dc64e6e..aab90cf0e 100644 --- a/Telegram/ThirdParty/Catch/include/internal/catch_version.cpp +++ b/Telegram/ThirdParty/Catch/include/internal/catch_version.cpp @@ -37,7 +37,7 @@ namespace Catch { } Version const& libraryVersion() { - static Version version( 2, 0, 1, "", 0 ); + static Version version( 2, 2, 0, "", 0 ); return version; } diff --git a/Telegram/ThirdParty/Catch/include/reporters/catch_reporter_console.cpp b/Telegram/ThirdParty/Catch/include/reporters/catch_reporter_console.cpp index 74d2f19d9..54b62cd80 100644 --- a/Telegram/ThirdParty/Catch/include/reporters/catch_reporter_console.cpp +++ b/Telegram/ThirdParty/Catch/include/reporters/catch_reporter_console.cpp @@ -210,7 +210,7 @@ class Duration { Unit m_units; public: - Duration(uint64_t inNanoseconds, Unit units = Unit::Auto) + explicit Duration(uint64_t inNanoseconds, Unit units = Unit::Auto) : m_inNanoseconds(inNanoseconds), m_units(units) { if (m_units == Unit::Auto) { @@ -273,9 +273,9 @@ class TablePrinter { bool m_isOpen = false; public: - TablePrinter(std::ostream& os, std::vector const& columnInfos) - : m_os(os), - m_columnInfos(columnInfos) {} + TablePrinter( std::ostream& os, std::vector columnInfos ) + : m_os( os ), + m_columnInfos( std::move( columnInfos ) ) {} auto columnInfos() const -> std::vector const& { return m_columnInfos; @@ -346,7 +346,8 @@ ConsoleReporter::ConsoleReporter(ReporterConfig const& config) { "elapsed ns", 14, ColumnInfo::Right }, { "average", 14, ColumnInfo::Right } })) {} -ConsoleReporter::~ConsoleReporter() {} +ConsoleReporter::~ConsoleReporter() = default; + std::string ConsoleReporter::getDescription() { return "Reports test results as plain lines of text"; } @@ -402,7 +403,7 @@ void ConsoleReporter::sectionEnded(SectionStats const& _sectionStats) { void ConsoleReporter::benchmarkStarting(BenchmarkInfo const& info) { lazyPrintWithoutClosingBenchmarkTable(); - auto nameCol = Column(info.name).width(m_tablePrinter->columnInfos()[0].width - 2); + auto nameCol = Column( info.name ).width( static_cast( m_tablePrinter->columnInfos()[0].width - 2 ) ); bool firstLine = true; for (auto line : nameCol) { @@ -528,10 +529,10 @@ void ConsoleReporter::printHeaderString(std::string const& _string, std::size_t struct SummaryColumn { - SummaryColumn(std::string const& _label, Colour::Code _colour) - : label(_label), - colour(_colour) {} - SummaryColumn addRow(std::size_t count) { + 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(); @@ -551,7 +552,7 @@ struct SummaryColumn { }; -void ConsoleReporter::printTotals(Totals const& totals) { +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()) { diff --git a/Telegram/ThirdParty/Catch/include/reporters/catch_reporter_junit.cpp b/Telegram/ThirdParty/Catch/include/reporters/catch_reporter_junit.cpp index 541a18b5a..d133b7006 100644 --- a/Telegram/ThirdParty/Catch/include/reporters/catch_reporter_junit.cpp +++ b/Telegram/ThirdParty/Catch/include/reporters/catch_reporter_junit.cpp @@ -64,7 +64,7 @@ namespace Catch { m_reporterPrefs.shouldRedirectStdOut = true; } - JunitReporter::~JunitReporter() {}; + JunitReporter::~JunitReporter() {} std::string JunitReporter::getDescription() { return "Reports test results in an XML format that looks like Ant's junitreport target"; diff --git a/Telegram/ThirdParty/Catch/include/reporters/catch_reporter_tap.hpp b/Telegram/ThirdParty/Catch/include/reporters/catch_reporter_tap.hpp index edb75b5ae..19e54ed19 100644 --- a/Telegram/ThirdParty/Catch/include/reporters/catch_reporter_tap.hpp +++ b/Telegram/ThirdParty/Catch/include/reporters/catch_reporter_tap.hpp @@ -26,7 +26,7 @@ namespace Catch { ~TAPReporter() override; static std::string getDescription() { - return "Reports test results in TAP format, suitable for test harneses"; + return "Reports test results in TAP format, suitable for test harnesses"; } ReporterPreferences getPreferences() const override { diff --git a/Telegram/ThirdParty/Catch/include/reporters/catch_reporter_teamcity.hpp b/Telegram/ThirdParty/Catch/include/reporters/catch_reporter_teamcity.hpp index 96e35a849..dbd0db532 100644 --- a/Telegram/ThirdParty/Catch/include/reporters/catch_reporter_teamcity.hpp +++ b/Telegram/ThirdParty/Catch/include/reporters/catch_reporter_teamcity.hpp @@ -14,8 +14,6 @@ // file can be distributed as a single header that works with the main // Catch single header. -#include "../internal/catch_enforce.h" - #include #ifdef __clang__ @@ -99,12 +97,12 @@ namespace Catch { case ResultWas::Ok: case ResultWas::Info: case ResultWas::Warning: - CATCH_ERROR( "Internal error in TeamCity reporter" ); + throw std::domain_error( "Internal error in TeamCity reporter" ); // These cases are here to prevent compiler warnings case ResultWas::Unknown: case ResultWas::FailureBit: case ResultWas::Exception: - CATCH_ERROR( "Not implemented" ); + throw std::domain_error( "Not implemented" ); } if( assertionStats.infoMessages.size() == 1 ) msg << " with message:"; diff --git a/Telegram/ThirdParty/Catch/include/reporters/catch_reporter_xml.cpp b/Telegram/ThirdParty/Catch/include/reporters/catch_reporter_xml.cpp index 1ea61c0b5..b721d449e 100644 --- a/Telegram/ThirdParty/Catch/include/reporters/catch_reporter_xml.cpp +++ b/Telegram/ThirdParty/Catch/include/reporters/catch_reporter_xml.cpp @@ -26,7 +26,7 @@ namespace Catch { m_reporterPrefs.shouldRedirectStdOut = true; } - XmlReporter::~XmlReporter() {}; + XmlReporter::~XmlReporter() = default; std::string XmlReporter::getDescription() { return "Reports test results as an XML document"; @@ -95,10 +95,10 @@ namespace Catch { bool includeResults = m_config->includeSuccessfulResults() || !result.isOk(); - if( includeResults ) { + if( includeResults || result.getResultType() == ResultWas::Warning ) { // Print any info messages in tags. for( auto const& msg : assertionStats.infoMessages ) { - if( msg.type == ResultWas::Info ) { + if( msg.type == ResultWas::Info && includeResults ) { m_xml.scopedElement( "Info" ) .writeText( msg.message ); } else if ( msg.type == ResultWas::Warning ) { diff --git a/Telegram/ThirdParty/Catch/misc/CMakeLists.txt b/Telegram/ThirdParty/Catch/misc/CMakeLists.txt new file mode 100644 index 000000000..bf80846cd --- /dev/null +++ b/Telegram/ThirdParty/Catch/misc/CMakeLists.txt @@ -0,0 +1,11 @@ +cmake_minimum_required(VERSION 3.0) + +project(CatchCoverageHelper) + +add_executable(CoverageHelper coverage-helper.cpp) +set_property(TARGET CoverageHelper PROPERTY CXX_STANDARD 11) +set_property(TARGET CoverageHelper PROPERTY CXX_STANDARD_REQUIRED ON) +set_property(TARGET CoverageHelper PROPERTY CXX_EXTENSIONS OFF) +if (MSVC) + target_compile_options( CoverageHelper PRIVATE /W4 /w44265 /WX /w44061 /w44062 ) +endif() diff --git a/Telegram/ThirdParty/Catch/misc/appveyorBuildConfigurationScript.bat b/Telegram/ThirdParty/Catch/misc/appveyorBuildConfigurationScript.bat new file mode 100644 index 000000000..1e91a588f --- /dev/null +++ b/Telegram/ThirdParty/Catch/misc/appveyorBuildConfigurationScript.bat @@ -0,0 +1,27 @@ + +@REM # Possibilities: +@REM # Debug build + coverage +@REM # Debug build + examples +@REM # Debug build + --- +@REM # Release build +if "%CONFIGURATION%"=="Debug" ( + if "%coverage%"=="1" ( + @REM # coverage needs to build the special helper as well as the main + cmake -Hmisc -Bbuild-misc -A%PLATFORM% + cmake --build build-misc + cmake -H. -BBuild -A%PLATFORM% -DUSE_WMAIN=%wmain% -DMEMORYCHECK_COMMAND=build-misc\Debug\CoverageHelper.exe -DMEMORYCHECK_COMMAND_OPTIONS=--sep-- -DMEMORYCHECK_TYPE=Valgrind + ) else ( + @REM # We know that coverage is 0 + if "%examples%"=="1" ( + @REM # Examples live off the single header, so it needs to be regenerated + python scripts\generateSingleHeader.py + cmake -H. -BBuild -A%PLATFORM% -DUSE_WMAIN=%wmain% -DCATCH_BUILD_EXAMPLES=ON + ) else ( + @REM # This is just a plain debug build + cmake -H. -BBuild -A%PLATFORM% -DUSE_WMAIN=%wmain% + ) + ) +) +if "%CONFIGURATION%"=="Release" ( + cmake -H. -BBuild -A%PLATFORM% -DUSE_WMAIN=%wmain% +) diff --git a/Telegram/ThirdParty/Catch/misc/appveyorMergeCoverageScript.py b/Telegram/ThirdParty/Catch/misc/appveyorMergeCoverageScript.py new file mode 100644 index 000000000..a74e6e0e8 --- /dev/null +++ b/Telegram/ThirdParty/Catch/misc/appveyorMergeCoverageScript.py @@ -0,0 +1,9 @@ +#!/usr/bin/env python2 + +import glob +import subprocess + +if __name__ == '__main__': + cov_files = list(glob.glob('cov-report*.bin')) + base_cmd = ['OpenCppCoverage', '--quiet', '--export_type=cobertura:cobertura.xml'] + ['--input_coverage={}'.format(f) for f in cov_files] + subprocess.call(base_cmd) diff --git a/Telegram/ThirdParty/Catch/misc/appveyorTestRunScript.bat b/Telegram/ThirdParty/Catch/misc/appveyorTestRunScript.bat new file mode 100644 index 000000000..19a364be1 --- /dev/null +++ b/Telegram/ThirdParty/Catch/misc/appveyorTestRunScript.bat @@ -0,0 +1,13 @@ +cd Build +if "%CONFIGURATION%"=="Debug" ( + if "%coverage%"=="1" ( + ctest -j 2 -C %CONFIGURATION% -D ExperimentalMemCheck + python ..\misc\appveyorMergeCoverageScript.py + codecov --root .. --no-color --disable gcov -f cobertura.xml -t %CODECOV_TOKEN% + ) else ( + ctest -j 2 -C %CONFIGURATION% + ) +) +if "%CONFIGURATION%"=="Release" ( + ctest -j 2 -C %CONFIGURATION% +) diff --git a/Telegram/ThirdParty/Catch/misc/coverage-helper.cpp b/Telegram/ThirdParty/Catch/misc/coverage-helper.cpp new file mode 100644 index 000000000..172189055 --- /dev/null +++ b/Telegram/ThirdParty/Catch/misc/coverage-helper.cpp @@ -0,0 +1,105 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +void create_empty_file(std::string const& path) { + std::ofstream ofs(path); + ofs << '\n'; +} + +const std::string separator = "--sep--"; +const std::string logfile_prefix = "--log-file="; + +bool starts_with(std::string const& str, std::string const& pref) { + return str.find(pref) == 0; +} + +int parse_log_file_arg(std::string const& arg) { + assert(starts_with(arg, logfile_prefix) && "Attempting to parse incorrect arg!"); + auto fname = arg.substr(logfile_prefix.size()); + create_empty_file(fname); + std::regex regex("MemoryChecker\\.(\\d+)\\.log", std::regex::icase); + std::smatch match; + if (std::regex_search(fname, match, regex)) { + return std::stoi(match[1]); + } else { + throw std::domain_error("Couldn't find desired expression in string: " + fname); + } +} + +std::string catch_path(std::string path) { + auto start = path.find("catch"); + // try capitalized instead + if (start == std::string::npos) { + start = path.find("Catch"); + } + if (start == std::string::npos) { + throw std::domain_error("Couldn't find Catch's base path"); + } + auto end = path.find_first_of("\\/", start); + return path.substr(0, end); +} + +std::string windowsify_path(std::string path) { + for (auto& c : path) { + if (c == '/') { + c = '\\'; + } + } + return path; +} + +void exec_cmd(std::string const& cmd, int log_num, std::string const& path) { + std::array buffer; +#if defined(_WIN32) + auto real_cmd = "OpenCppCoverage --export_type binary:cov-report" + std::to_string(log_num) + + ".bin --quiet " + "--sources " + path + " --cover_children -- " + cmd; + std::cout << "=== Marker ===: Cmd: " << real_cmd << '\n'; + std::shared_ptr pipe(_popen(real_cmd.c_str(), "r"), _pclose); +#else // Just for testing, in the real world we will always work under WIN32 + (void)log_num; (void)path; + std::shared_ptr pipe(popen(cmd.c_str(), "r"), pclose); +#endif + + if (!pipe) { + throw std::runtime_error("popen() failed!"); + } + while (!feof(pipe.get())) { + if (fgets(buffer.data(), 128, pipe.get()) != nullptr) { + std::cout << buffer.data(); + } + } +} + +// argv should be: +// [0]: our path +// [1]: "--log-file=" +// [2]: "--sep--" +// [3]+: the actual command + +int main(int argc, char** argv) { + std::vector args(argv, argv + argc); + auto sep = std::find(begin(args), end(args), separator); + assert(sep - begin(args) == 2 && "Structure differs from expected!"); + + auto num = parse_log_file_arg(args[1]); + + auto cmdline = std::accumulate(++sep, end(args), std::string{}, [] (const std::string& lhs, const std::string& rhs) { + return lhs + ' ' + rhs; + }); + + try { + return exec_cmd(cmdline, num, windowsify_path(catch_path(args[0]))); + } catch (std::exception const& ex) { + std::cerr << "Helper failed with: '" << ex.what() << "'\n"; + return 12; + } +} diff --git a/Telegram/ThirdParty/Catch/misc/installOpenCppCoverage.ps1 b/Telegram/ThirdParty/Catch/misc/installOpenCppCoverage.ps1 new file mode 100644 index 000000000..d277a55de --- /dev/null +++ b/Telegram/ThirdParty/Catch/misc/installOpenCppCoverage.ps1 @@ -0,0 +1,19 @@ +# Downloads are done from the official github release page links +$downloadUrl = "https://github.com/OpenCppCoverage/OpenCppCoverage/releases/download/release-0.9.7.0/OpenCppCoverageSetup-x64-0.9.7.0.exe" +$installerPath = [System.IO.Path]::Combine($Env:USERPROFILE, "Downloads", "OpenCppCoverageSetup.exe") + +if(-Not (Test-Path $installerPath)) { + Write-Host -ForegroundColor White ("Downloading OpenCppCoverage from: " + $downloadUrl) + Start-FileDownload $downloadUrl -FileName $installerPath +} + +Write-Host -ForegroundColor White "About to install OpenCppCoverage..." + +$installProcess = (Start-Process $installerPath -ArgumentList '/VERYSILENT' -PassThru -Wait) +if($installProcess.ExitCode -ne 0) { + throw [System.String]::Format("Failed to install OpenCppCoverage, ExitCode: {0}.", $installProcess.ExitCode) +} + +# Assume standard, boring, installation path of ".../Program Files/OpenCppCoverage" +$installPath = [System.IO.Path]::Combine(${Env:ProgramFiles}, "OpenCppCoverage") +$env:Path="$env:Path;$installPath" diff --git a/Telegram/ThirdParty/Catch/projects/SelfTest/Baselines/automake.std.approved.txt b/Telegram/ThirdParty/Catch/projects/SelfTest/Baselines/automake.std.approved.txt index 85299f703..057be069f 100644 --- a/Telegram/ThirdParty/Catch/projects/SelfTest/Baselines/automake.std.approved.txt +++ b/Telegram/ThirdParty/Catch/projects/SelfTest/Baselines/automake.std.approved.txt @@ -53,7 +53,7 @@ :test-result: PASS Inequality checks that should succeed :test-result: PASS Less-than inequalities with different epsilons :test-result: PASS Long strings can be wrapped -:test-result: PASS Long text is truncted +:test-result: PASS Long text is truncated :test-result: PASS ManuallyRegistered :test-result: PASS Matchers can be (AllOf) composed with the && operator :test-result: PASS Matchers can be (AnyOf) composed with the || operator diff --git a/Telegram/ThirdParty/Catch/projects/SelfTest/Baselines/compact.sw.approved.txt b/Telegram/ThirdParty/Catch/projects/SelfTest/Baselines/compact.sw.approved.txt new file mode 100644 index 000000000..4a1aeb78c --- /dev/null +++ b/Telegram/ThirdParty/Catch/projects/SelfTest/Baselines/compact.sw.approved.txt @@ -0,0 +1,1084 @@ +Misc.tests.cpp:: passed: with 1 message: 'yay' +Decomposition.tests.cpp:: passed: fptr == 0 for: 0 == 0 +Decomposition.tests.cpp:: passed: fptr == 0l for: 0 == 0 +Compilation.tests.cpp:: passed: y.v == 0 for: 0 == 0 +Compilation.tests.cpp:: passed: 0 == y.v for: 0 == 0 +Compilation.tests.cpp:: passed: t1 == t2 for: {?} == {?} +Compilation.tests.cpp:: passed: t1 != t2 for: {?} != {?} +Compilation.tests.cpp:: passed: t1 < t2 for: {?} < {?} +Compilation.tests.cpp:: passed: t1 > t2 for: {?} > {?} +Compilation.tests.cpp:: passed: t1 <= t2 for: {?} <= {?} +Compilation.tests.cpp:: passed: t1 >= t2 for: {?} >= {?} +Misc.tests.cpp:: passed: +Exception.tests.cpp:: failed: unexpected exception with message: 'answer := 42' with 1 message: 'expected exception' +Exception.tests.cpp:: failed: unexpected exception with message: 'answer := 42'; expression was: thisThrows() with 1 message: 'expected exception' +Exception.tests.cpp:: passed: thisThrows() with 1 message: 'answer := 42' +Compilation.tests.cpp:: passed: 42 == f for: 42 == {?} +Compilation.tests.cpp:: passed: a == t for: 3 == 3 +Compilation.tests.cpp:: passed: a == t for: 3 == 3 +Compilation.tests.cpp:: passed: throws_int(true) +Compilation.tests.cpp:: passed: throws_int(true), int +Compilation.tests.cpp:: passed: throws_int(false) +Compilation.tests.cpp:: passed: "aaa", Catch::EndsWith("aaa") for: "aaa" ends with: "aaa" +Compilation.tests.cpp:: passed: templated_tests(3) for: true +Misc.tests.cpp:: failed: f() == 0 for: 1 == 0 +Misc.tests.cpp:: passed: errno == 1 for: 1 == 1 +Compilation.tests.cpp:: passed: x == 4 for: {?} == 4 with 1 message: 'dummy := 0' +Misc.tests.cpp:: passed: with 1 message: 'Everything is OK' +Misc.tests.cpp:: passed: with 1 message: 'Everything is OK' +Misc.tests.cpp:: passed: with 1 message: 'Everything is OK' +Misc.tests.cpp:: passed: with 1 message: 'Everything is OK' +Misc.tests.cpp:: passed: with 1 message: 'Everything is OK' +Condition.tests.cpp:: failed: false != false +Condition.tests.cpp:: failed: true != true +Condition.tests.cpp:: failed: !true for: false +Condition.tests.cpp:: failed: !(true) for: !true +Condition.tests.cpp:: failed: !trueValue for: false +Condition.tests.cpp:: failed: !(trueValue) for: !true +Condition.tests.cpp:: failed: !(1 == 1) for: false +Condition.tests.cpp:: failed: !(1 == 1) +Condition.tests.cpp:: passed: false == false +Condition.tests.cpp:: passed: true == true +Condition.tests.cpp:: passed: !false for: true +Condition.tests.cpp:: passed: !(false) for: !false +Condition.tests.cpp:: passed: !falseValue for: true +Condition.tests.cpp:: passed: !(falseValue) for: !false +Condition.tests.cpp:: passed: !(1 == 2) for: true +Condition.tests.cpp:: passed: !(1 == 2) +Tricky.tests.cpp:: passed: is_true::value == true for: true == true +Tricky.tests.cpp:: passed: true == is_true::value for: true == true +Tricky.tests.cpp:: passed: is_true::value == false for: false == false +Tricky.tests.cpp:: passed: false == is_true::value for: false == false +Tricky.tests.cpp:: passed: !is_true::value for: true +Tricky.tests.cpp:: passed: !!is_true::value for: true +Tricky.tests.cpp:: passed: is_true::value for: true +Tricky.tests.cpp:: passed: !(is_true::value) for: !false +Class.tests.cpp:: failed: s == "world" for: "hello" == "world" +Class.tests.cpp:: passed: s == "hello" for: "hello" == "hello" +Class.tests.cpp:: failed: m_a == 2 for: 1 == 2 +Class.tests.cpp:: passed: m_a == 1 for: 1 == 1 +Misc.tests.cpp:: passed: with 1 message: 'that's not flying - that's failing in style' +Misc.tests.cpp:: failed: explicitly with 1 message: 'to infinity and beyond' +Tricky.tests.cpp:: failed: &o1 == &o2 for: 0x == 0x +Tricky.tests.cpp:: failed: o1 == o2 for: {?} == {?} +Approx.tests.cpp:: passed: 104.0 != Approx(100.0) for: 104.0 != Approx( 100.0 ) +Approx.tests.cpp:: passed: 104.0 == Approx(100.0).margin(5) for: 104.0 == Approx( 100.0 ) +Approx.tests.cpp:: passed: 104.0 == Approx(100.0).margin(4) for: 104.0 == Approx( 100.0 ) +Approx.tests.cpp:: passed: 104.0 != Approx(100.0).margin(3) for: 104.0 != Approx( 100.0 ) +Approx.tests.cpp:: passed: 100.3 != Approx(100.0) for: 100.3 != Approx( 100.0 ) +Approx.tests.cpp:: passed: 100.3 == Approx(100.0).margin(0.5) for: 100.3 == Approx( 100.0 ) +Tricky.tests.cpp:: passed: i++ == 7 for: 7 == 7 +Tricky.tests.cpp:: passed: i++ == 8 for: 8 == 8 +Exception.tests.cpp:: passed: 1 == 1 +Exception.tests.cpp:: failed: unexpected exception with message: 'unexpected exception'; expression was: {Unknown expression after the reported line} +VariadicMacros.tests.cpp:: passed: with 1 message: 'anonymous test case' +Approx.tests.cpp:: passed: Approx(0).margin(0) +Approx.tests.cpp:: passed: Approx(0).margin(1234656) +Approx.tests.cpp:: passed: Approx(0).margin(-2), std::domain_error +Approx.tests.cpp:: passed: Approx(0).epsilon(0) +Approx.tests.cpp:: passed: Approx(0).epsilon(1) +Approx.tests.cpp:: passed: Approx(0).epsilon(-0.001), std::domain_error +Approx.tests.cpp:: passed: Approx(0).epsilon(1.0001), std::domain_error +Approx.tests.cpp:: passed: 0.25f == Approx(0.0f).margin(0.25f) for: 0.25f == Approx( 0.0 ) +Approx.tests.cpp:: passed: 0.0f == Approx(0.25f).margin(0.25f) for: 0.0f == Approx( 0.25 ) +Approx.tests.cpp:: passed: 0.5f == Approx(0.25f).margin(0.25f) for: 0.5f == Approx( 0.25 ) +Approx.tests.cpp:: passed: 245.0f == Approx(245.25f).margin(0.25f) for: 245.0f == Approx( 245.25 ) +Approx.tests.cpp:: passed: 245.5f == Approx(245.25f).margin(0.25f) for: 245.5f == Approx( 245.25 ) +Approx.tests.cpp:: passed: divide( 22, 7 ) == Approx( 3.141 ).epsilon( 0.001 ) for: 3.1428571429 == Approx( 3.141 ) +Approx.tests.cpp:: passed: divide( 22, 7 ) != Approx( 3.141 ).epsilon( 0.0001 ) for: 3.1428571429 != Approx( 3.141 ) +Approx.tests.cpp:: passed: d != Approx( 1.231 ) for: 1.23 != Approx( 1.231 ) +Approx.tests.cpp:: passed: d == Approx( 1.231 ).epsilon( 0.1 ) for: 1.23 == Approx( 1.231 ) +Approx.tests.cpp:: passed: 1.23f == Approx( 1.23f ) for: 1.23f == Approx( 1.2300000191 ) +Approx.tests.cpp:: passed: 0.0f == Approx( 0.0f ) for: 0.0f == Approx( 0.0 ) +Approx.tests.cpp:: passed: 1 == Approx( 1 ) for: 1 == Approx( 1.0 ) +Approx.tests.cpp:: passed: 0 == Approx( 0 ) for: 0 == Approx( 0.0 ) +Approx.tests.cpp:: passed: 1.0f == Approx( 1 ) for: 1.0f == Approx( 1.0 ) +Approx.tests.cpp:: passed: 0 == Approx( dZero) for: 0 == Approx( 0.0 ) +Approx.tests.cpp:: passed: 0 == Approx( dSmall ).margin( 0.001 ) for: 0 == Approx( 0.00001 ) +Approx.tests.cpp:: passed: 1.234f == Approx( dMedium ) for: 1.234f == Approx( 1.234 ) +Approx.tests.cpp:: passed: dMedium == Approx( 1.234f ) for: 1.234 == Approx( 1.2339999676 ) +Tricky.tests.cpp:: passed: true +Tricky.tests.cpp:: passed: true +Tricky.tests.cpp:: passed: true +Tricky.tests.cpp:: passed: true +Tricky.tests.cpp:: passed: true +Tricky.tests.cpp:: passed: true +Approx.tests.cpp:: passed: INFINITY == Approx(INFINITY) for: inff == Approx( inf ) +Approx.tests.cpp:: passed: NAN != Approx(NAN) for: nanf != Approx( nan ) +Approx.tests.cpp:: passed: !(NAN == Approx(NAN)) for: !(nanf == Approx( nan )) +Tricky.tests.cpp:: passed: y.v == 0 for: 0 == 0 +Tricky.tests.cpp:: passed: 0 == y.v for: 0 == 0 +ToStringGeneral.tests.cpp:: passed: true with 1 message: 'i := 2' +ToStringGeneral.tests.cpp:: passed: true with 1 message: '3' +ToStringGeneral.tests.cpp:: passed: tab == '/t' for: '/t' == '/t' +ToStringGeneral.tests.cpp:: passed: newline == '/n' for: '/n' == '/n' +ToStringGeneral.tests.cpp:: passed: carr_return == '/r' for: '/r' == '/r' +ToStringGeneral.tests.cpp:: passed: form_feed == '/f' for: '/f' == '/f' +ToStringGeneral.tests.cpp:: passed: space == ' ' for: ' ' == ' ' +ToStringGeneral.tests.cpp:: passed: c == chars[i] for: 'a' == 'a' +ToStringGeneral.tests.cpp:: passed: c == chars[i] for: 'z' == 'z' +ToStringGeneral.tests.cpp:: passed: c == chars[i] for: 'A' == 'A' +ToStringGeneral.tests.cpp:: passed: c == chars[i] for: 'Z' == 'Z' +ToStringGeneral.tests.cpp:: passed: null_terminator == '/0' for: 0 == 0 +ToStringGeneral.tests.cpp:: passed: c == i for: 2 == 2 +ToStringGeneral.tests.cpp:: passed: c == i for: 3 == 3 +ToStringGeneral.tests.cpp:: passed: c == i for: 4 == 4 +ToStringGeneral.tests.cpp:: passed: c == i for: 5 == 5 +Tricky.tests.cpp:: passed: std::vector{constructor_throws{}, constructor_throws{}} +Tricky.tests.cpp:: passed: std::vector{constructor_throws{}, constructor_throws{}} +Tricky.tests.cpp:: passed: std::vector{1, 2, 3} == std::vector{1, 2, 3} +Tricky.tests.cpp:: passed: std::vector{1, 2, 3} == std::vector{1, 2, 3} +Tricky.tests.cpp:: passed: std::vector{1, 2} == std::vector{1, 2} for: { 1, 2 } == { 1, 2 } +Tricky.tests.cpp:: passed: std::vector{1, 2} == std::vector{1, 2} for: { 1, 2 } == { 1, 2 } +Tricky.tests.cpp:: passed: !(std::vector{1, 2} == std::vector{1, 2, 3}) for: !({ 1, 2 } == { 1, 2, 3 }) +Tricky.tests.cpp:: passed: !(std::vector{1, 2} == std::vector{1, 2, 3}) for: !({ 1, 2 } == { 1, 2, 3 }) +Tricky.tests.cpp:: passed: std::vector{1, 2} == std::vector{1, 2} for: { 1, 2 } == { 1, 2 } +Tricky.tests.cpp:: passed: std::vector{1, 2} == std::vector{1, 2} for: { 1, 2 } == { 1, 2 } +Tricky.tests.cpp:: passed: true +Tricky.tests.cpp:: passed: std::vector{1, 2} == std::vector{1, 2} for: { 1, 2 } == { 1, 2 } +Tricky.tests.cpp:: passed: a for: 0x +Tricky.tests.cpp:: passed: a == &foo for: 0x == 0x +Approx.tests.cpp:: passed: td == Approx(10.0) for: StrongDoubleTypedef(10) == Approx( 10.0 ) +Approx.tests.cpp:: passed: Approx(10.0) == td for: Approx( 10.0 ) == StrongDoubleTypedef(10) +Approx.tests.cpp:: passed: td != Approx(11.0) for: StrongDoubleTypedef(10) != Approx( 11.0 ) +Approx.tests.cpp:: passed: Approx(11.0) != td for: Approx( 11.0 ) != StrongDoubleTypedef(10) +Approx.tests.cpp:: passed: td <= Approx(10.0) for: StrongDoubleTypedef(10) <= Approx( 10.0 ) +Approx.tests.cpp:: passed: td <= Approx(11.0) for: StrongDoubleTypedef(10) <= Approx( 11.0 ) +Approx.tests.cpp:: passed: Approx(10.0) <= td for: Approx( 10.0 ) <= StrongDoubleTypedef(10) +Approx.tests.cpp:: passed: Approx(9.0) <= td for: Approx( 9.0 ) <= StrongDoubleTypedef(10) +Approx.tests.cpp:: passed: td >= Approx(9.0) for: StrongDoubleTypedef(10) >= Approx( 9.0 ) +Approx.tests.cpp:: passed: td >= Approx(td) for: StrongDoubleTypedef(10) >= Approx( 10.0 ) +Approx.tests.cpp:: passed: Approx(td) >= td for: Approx( 10.0 ) >= StrongDoubleTypedef(10) +Approx.tests.cpp:: passed: Approx(11.0) >= td for: Approx( 11.0 ) >= StrongDoubleTypedef(10) +Condition.tests.cpp:: passed: 54 == 6*9 for: 54 == 54 +Condition.tests.cpp:: passed: ( -1 > 2u ) for: true +Condition.tests.cpp:: passed: -1 > 2u for: -1 > 2 +Condition.tests.cpp:: passed: ( 2u < -1 ) for: true +Condition.tests.cpp:: passed: 2u < -1 for: 2 < -1 +Condition.tests.cpp:: passed: ( minInt > 2u ) for: true +Condition.tests.cpp:: passed: minInt > 2u for: -2147483648 > 2 +Condition.tests.cpp:: passed: i == 1 for: 1 == 1 +Condition.tests.cpp:: passed: ui == 2 for: 2 == 2 +Condition.tests.cpp:: passed: l == 3 for: 3 == 3 +Condition.tests.cpp:: passed: ul == 4 for: 4 == 4 +Condition.tests.cpp:: passed: c == 5 for: 5 == 5 +Condition.tests.cpp:: passed: uc == 6 for: 6 == 6 +Condition.tests.cpp:: passed: 1 == i for: 1 == 1 +Condition.tests.cpp:: passed: 2 == ui for: 2 == 2 +Condition.tests.cpp:: passed: 3 == l for: 3 == 3 +Condition.tests.cpp:: passed: 4 == ul for: 4 == 4 +Condition.tests.cpp:: passed: 5 == c for: 5 == 5 +Condition.tests.cpp:: passed: 6 == uc for: 6 == 6 +Condition.tests.cpp:: passed: (std::numeric_limits::max)() > ul for: 4294967295 (0x) > 4 +Matchers.tests.cpp:: failed: testStringForMatching(), Contains("not there", Catch::CaseSensitive::No) for: "this string contains 'abc' as a substring" contains: "not there" (case insensitive) +Matchers.tests.cpp:: failed: testStringForMatching(), Contains("STRING") for: "this string contains 'abc' as a substring" contains: "STRING" +Exception.tests.cpp:: failed: unexpected exception with message: 'custom exception - not std'; expression was: throwCustom() +Exception.tests.cpp:: failed: unexpected exception with message: 'custom exception - not std'; expression was: throwCustom(), std::exception +Exception.tests.cpp:: failed: unexpected exception with message: 'custom std exception' +Approx.tests.cpp:: passed: 101.000001 != Approx(100).epsilon(0.01) for: 101.000001 != Approx( 100.0 ) +Approx.tests.cpp:: passed: std::pow(10, -5) != Approx(std::pow(10, -7)) for: 0.00001 != Approx( 0.0000001 ) +Matchers.tests.cpp:: failed: testStringForMatching(), EndsWith("Substring") for: "this string contains 'abc' as a substring" ends with: "Substring" +Matchers.tests.cpp:: failed: testStringForMatching(), EndsWith("this", Catch::CaseSensitive::No) for: "this string contains 'abc' as a substring" ends with: "this" (case insensitive) +Approx.tests.cpp:: passed: 101.01 != Approx(100).epsilon(0.01) for: 101.01 != Approx( 100.0 ) +Condition.tests.cpp:: failed: data.int_seven == 6 for: 7 == 6 +Condition.tests.cpp:: failed: data.int_seven == 8 for: 7 == 8 +Condition.tests.cpp:: failed: data.int_seven == 0 for: 7 == 0 +Condition.tests.cpp:: failed: data.float_nine_point_one == Approx( 9.11f ) for: 9.1f == Approx( 9.1099996567 ) +Condition.tests.cpp:: failed: data.float_nine_point_one == Approx( 9.0f ) for: 9.1f == Approx( 9.0 ) +Condition.tests.cpp:: failed: data.float_nine_point_one == Approx( 1 ) for: 9.1f == Approx( 1.0 ) +Condition.tests.cpp:: failed: data.float_nine_point_one == Approx( 0 ) for: 9.1f == Approx( 0.0 ) +Condition.tests.cpp:: failed: data.double_pi == Approx( 3.1415 ) for: 3.1415926535 == Approx( 3.1415 ) +Condition.tests.cpp:: failed: data.str_hello == "goodbye" for: "hello" == "goodbye" +Condition.tests.cpp:: failed: data.str_hello == "hell" for: "hello" == "hell" +Condition.tests.cpp:: failed: data.str_hello == "hello1" for: "hello" == "hello1" +Condition.tests.cpp:: failed: data.str_hello.size() == 6 for: 5 == 6 +Condition.tests.cpp:: failed: x == Approx( 1.301 ) for: 1.3 == Approx( 1.301 ) +Condition.tests.cpp:: passed: data.int_seven == 7 for: 7 == 7 +Condition.tests.cpp:: passed: data.float_nine_point_one == Approx( 9.1f ) for: 9.1f == Approx( 9.1000003815 ) +Condition.tests.cpp:: passed: data.double_pi == Approx( 3.1415926535 ) for: 3.1415926535 == Approx( 3.1415926535 ) +Condition.tests.cpp:: passed: data.str_hello == "hello" for: "hello" == "hello" +Condition.tests.cpp:: passed: "hello" == data.str_hello for: "hello" == "hello" +Condition.tests.cpp:: passed: data.str_hello.size() == 5 for: 5 == 5 +Condition.tests.cpp:: passed: x == Approx( 1.3 ) for: 1.3 == Approx( 1.3 ) +Matchers.tests.cpp:: passed: testStringForMatching(), Equals("this string contains 'abc' as a substring") for: "this string contains 'abc' as a substring" equals: "this string contains 'abc' as a substring" +Matchers.tests.cpp:: passed: testStringForMatching(), Equals("this string contains 'ABC' as a substring", Catch::CaseSensitive::No) for: "this string contains 'abc' as a substring" equals: "this string contains 'abc' as a substring" (case insensitive) +Matchers.tests.cpp:: failed: testStringForMatching(), Equals("this string contains 'ABC' as a substring") for: "this string contains 'abc' as a substring" equals: "this string contains 'ABC' as a substring" +Matchers.tests.cpp:: failed: testStringForMatching(), Equals("something else", Catch::CaseSensitive::No) for: "this string contains 'abc' as a substring" equals: "something else" (case insensitive) +Matchers.tests.cpp:: failed: expected exception, got none; expression was: doesNotThrow(), SpecialException, ExceptionMatcher{1} +Matchers.tests.cpp:: failed: expected exception, got none; expression was: doesNotThrow(), SpecialException, ExceptionMatcher{1} +Matchers.tests.cpp:: failed: unexpected exception with message: 'Unknown exception'; expression was: throwsAsInt(1), SpecialException, ExceptionMatcher{1} +Matchers.tests.cpp:: failed: unexpected exception with message: 'Unknown exception'; expression was: throwsAsInt(1), SpecialException, ExceptionMatcher{1} +Matchers.tests.cpp:: failed: throws(3), SpecialException, ExceptionMatcher{1} for: {?} special exception has value of 1 +Matchers.tests.cpp:: failed: throws(4), SpecialException, ExceptionMatcher{1} for: {?} special exception has value of 1 +Matchers.tests.cpp:: passed: throws(1), SpecialException, ExceptionMatcher{1} for: {?} special exception has value of 1 +Matchers.tests.cpp:: passed: throws(2), SpecialException, ExceptionMatcher{2} for: {?} special exception has value of 2 +Exception.tests.cpp:: passed: thisThrows(), "expected exception" for: "expected exception" equals: "expected exception" +Exception.tests.cpp:: passed: thisThrows(), Equals( "expecteD Exception", Catch::CaseSensitive::No ) for: "expected exception" equals: "expected exception" (case insensitive) +Exception.tests.cpp:: passed: thisThrows(), StartsWith( "expected" ) for: "expected exception" starts with: "expected" +Exception.tests.cpp:: passed: thisThrows(), EndsWith( "exception" ) for: "expected exception" ends with: "exception" +Exception.tests.cpp:: passed: thisThrows(), Contains( "except" ) for: "expected exception" contains: "except" +Exception.tests.cpp:: passed: thisThrows(), Contains( "exCept", Catch::CaseSensitive::No ) for: "expected exception" contains: "except" (case insensitive) +Exception.tests.cpp:: failed: unexpected exception with message: 'expected exception'; expression was: thisThrows(), std::string +Exception.tests.cpp:: failed: expected exception, got none; expression was: thisDoesntThrow(), std::domain_error +Exception.tests.cpp:: failed: unexpected exception with message: 'expected exception'; expression was: thisThrows() +Message.tests.cpp:: failed: explicitly with 1 message: 'This is a failure' +Message.tests.cpp:: failed: explicitly +Message.tests.cpp:: failed: explicitly with 1 message: 'This is a failure' +Message.tests.cpp:: warning: 'This message appears in the output' +Misc.tests.cpp:: passed: Factorial(0) == 1 for: 1 == 1 +Misc.tests.cpp:: passed: Factorial(1) == 1 for: 1 == 1 +Misc.tests.cpp:: passed: Factorial(2) == 2 for: 2 == 2 +Misc.tests.cpp:: passed: Factorial(3) == 6 for: 6 == 6 +Misc.tests.cpp:: passed: Factorial(10) == 3628800 for: 3628800 (0x) == 3628800 (0x) +Matchers.tests.cpp:: passed: 1., WithinAbs(1., 0) for: 1.0 is within 0.0 of 1.0 +Matchers.tests.cpp:: passed: 0., WithinAbs(1., 1) for: 0.0 is within 1.0 of 1.0 +Matchers.tests.cpp:: passed: 0., !WithinAbs(1., 0.99) for: 0.0 not is within 0.99 of 1.0 +Matchers.tests.cpp:: passed: 0., !WithinAbs(1., 0.99) for: 0.0 not is within 0.99 of 1.0 +Matchers.tests.cpp:: passed: NAN, !WithinAbs(NAN, 0) for: nanf not is within 0.0 of nan +Matchers.tests.cpp:: passed: 1., WithinULP(1., 0) for: 1.0 is within 0 ULPs of 1.0 +Matchers.tests.cpp:: passed: nextafter(1., 2.), WithinULP(1., 1) for: 1.0 is within 1 ULPs of 1.0 +Matchers.tests.cpp:: passed: nextafter(1., 0.), WithinULP(1., 1) for: 1.0 is within 1 ULPs of 1.0 +Matchers.tests.cpp:: passed: nextafter(1., 2.), !WithinULP(1., 0) for: 1.0 not is within 0 ULPs of 1.0 +Matchers.tests.cpp:: passed: 1., WithinULP(1., 0) for: 1.0 is within 0 ULPs of 1.0 +Matchers.tests.cpp:: passed: -0., WithinULP(0., 0) for: -0.0 is within 0 ULPs of 0.0 +Matchers.tests.cpp:: passed: NAN, !WithinULP(NAN, 123) for: nanf not is within 123 ULPs of nanf +Matchers.tests.cpp:: passed: 1., WithinAbs(1., 0.5) || WithinULP(2., 1) for: 1.0 ( is within 0.5 of 1.0 or is within 1 ULPs of 2.0 ) +Matchers.tests.cpp:: passed: 1., WithinAbs(2., 0.5) || WithinULP(1., 0) for: 1.0 ( is within 0.5 of 2.0 or is within 0 ULPs of 1.0 ) +Matchers.tests.cpp:: passed: NAN, !(WithinAbs(NAN, 100) || WithinULP(NAN, 123)) for: nanf not ( is within 100.0 of nan or is within 123 ULPs of nanf ) +Matchers.tests.cpp:: passed: WithinAbs(1., 0.) +Matchers.tests.cpp:: passed: WithinAbs(1., -1.), std::domain_error +Matchers.tests.cpp:: passed: WithinULP(1., 0) +Matchers.tests.cpp:: passed: WithinULP(1., -1), std::domain_error +Matchers.tests.cpp:: passed: 1.f, WithinAbs(1.f, 0) for: 1.0f is within 0.0 of 1.0 +Matchers.tests.cpp:: passed: 0.f, WithinAbs(1.f, 1) for: 0.0f is within 1.0 of 1.0 +Matchers.tests.cpp:: passed: 0.f, !WithinAbs(1.f, 0.99f) for: 0.0f not is within 0.9900000095 of 1.0 +Matchers.tests.cpp:: passed: 0.f, !WithinAbs(1.f, 0.99f) for: 0.0f not is within 0.9900000095 of 1.0 +Matchers.tests.cpp:: passed: 0.f, WithinAbs(-0.f, 0) for: 0.0f is within 0.0 of -0.0 +Matchers.tests.cpp:: passed: NAN, !WithinAbs(NAN, 0) for: nanf not is within 0.0 of nan +Matchers.tests.cpp:: passed: 1.f, WithinULP(1.f, 0) for: 1.0f is within 0 ULPs of 1.0f +Matchers.tests.cpp:: passed: nextafter(1.f, 2.f), WithinULP(1.f, 1) for: 1.0f is within 1 ULPs of 1.0f +Matchers.tests.cpp:: passed: nextafter(1.f, 0.f), WithinULP(1.f, 1) for: 1.0f is within 1 ULPs of 1.0f +Matchers.tests.cpp:: passed: nextafter(1.f, 2.f), !WithinULP(1.f, 0) for: 1.0f not is within 0 ULPs of 1.0f +Matchers.tests.cpp:: passed: 1.f, WithinULP(1.f, 0) for: 1.0f is within 0 ULPs of 1.0f +Matchers.tests.cpp:: passed: -0.f, WithinULP(0.f, 0) for: -0.0f is within 0 ULPs of 0.0f +Matchers.tests.cpp:: passed: NAN, !WithinULP(NAN, 123) for: nanf not is within 123 ULPs of nanf +Matchers.tests.cpp:: passed: 1.f, WithinAbs(1.f, 0.5) || WithinULP(1.f, 1) for: 1.0f ( is within 0.5 of 1.0 or is within 1 ULPs of 1.0f ) +Matchers.tests.cpp:: passed: 1.f, WithinAbs(2.f, 0.5) || WithinULP(1.f, 0) for: 1.0f ( is within 0.5 of 2.0 or is within 0 ULPs of 1.0f ) +Matchers.tests.cpp:: passed: NAN, !(WithinAbs(NAN, 100) || WithinULP(NAN, 123)) for: nanf not ( is within 100.0 of nan or is within 123 ULPs of nanf ) +Matchers.tests.cpp:: passed: WithinAbs(1.f, 0.f) +Matchers.tests.cpp:: passed: WithinAbs(1.f, -1.f), std::domain_error +Matchers.tests.cpp:: passed: WithinULP(1.f, 0) +Matchers.tests.cpp:: passed: WithinULP(1.f, -1), std::domain_error +Approx.tests.cpp:: passed: d >= Approx( 1.22 ) for: 1.23 >= Approx( 1.22 ) +Approx.tests.cpp:: passed: d >= Approx( 1.23 ) for: 1.23 >= Approx( 1.23 ) +Approx.tests.cpp:: passed: !(d >= Approx( 1.24 )) for: !(1.23 >= Approx( 1.24 )) +Approx.tests.cpp:: passed: d >= Approx( 1.24 ).epsilon(0.1) for: 1.23 >= Approx( 1.24 ) +Message.tests.cpp:: warning: 'this is a message' with 1 message: 'this is a warning' +Message.tests.cpp:: failed: a == 1 for: 2 == 1 with 2 messages: 'this message should be logged' and 'so should this' +Message.tests.cpp:: passed: a == 2 for: 2 == 2 with 1 message: 'this message may be logged later' +Message.tests.cpp:: failed: a == 1 for: 2 == 1 with 2 messages: 'this message may be logged later' and 'this message should be logged' +Message.tests.cpp:: failed: a == 0 for: 2 == 0 with 3 messages: 'this message may be logged later' and 'this message should be logged' and 'and this, but later' +Message.tests.cpp:: passed: a == 2 for: 2 == 2 with 4 messages: 'this message may be logged later' and 'this message should be logged' and 'and this, but later' and 'but not this' +Message.tests.cpp:: passed: i < 10 for: 0 < 10 with 2 messages: 'current counter 0' and 'i := 0' +Message.tests.cpp:: passed: i < 10 for: 1 < 10 with 2 messages: 'current counter 1' and 'i := 1' +Message.tests.cpp:: passed: i < 10 for: 2 < 10 with 2 messages: 'current counter 2' and 'i := 2' +Message.tests.cpp:: passed: i < 10 for: 3 < 10 with 2 messages: 'current counter 3' and 'i := 3' +Message.tests.cpp:: passed: i < 10 for: 4 < 10 with 2 messages: 'current counter 4' and 'i := 4' +Message.tests.cpp:: passed: i < 10 for: 5 < 10 with 2 messages: 'current counter 5' and 'i := 5' +Message.tests.cpp:: passed: i < 10 for: 6 < 10 with 2 messages: 'current counter 6' and 'i := 6' +Message.tests.cpp:: passed: i < 10 for: 7 < 10 with 2 messages: 'current counter 7' and 'i := 7' +Message.tests.cpp:: passed: i < 10 for: 8 < 10 with 2 messages: 'current counter 8' and 'i := 8' +Message.tests.cpp:: passed: i < 10 for: 9 < 10 with 2 messages: 'current counter 9' and 'i := 9' +Message.tests.cpp:: failed: i < 10 for: 10 < 10 with 2 messages: 'current counter 10' and 'i := 10' +Condition.tests.cpp:: failed: data.int_seven != 7 for: 7 != 7 +Condition.tests.cpp:: failed: data.float_nine_point_one != Approx( 9.1f ) for: 9.1f != Approx( 9.1000003815 ) +Condition.tests.cpp:: failed: data.double_pi != Approx( 3.1415926535 ) for: 3.1415926535 != Approx( 3.1415926535 ) +Condition.tests.cpp:: failed: data.str_hello != "hello" for: "hello" != "hello" +Condition.tests.cpp:: failed: data.str_hello.size() != 5 for: 5 != 5 +Condition.tests.cpp:: passed: data.int_seven != 6 for: 7 != 6 +Condition.tests.cpp:: passed: data.int_seven != 8 for: 7 != 8 +Condition.tests.cpp:: passed: data.float_nine_point_one != Approx( 9.11f ) for: 9.1f != Approx( 9.1099996567 ) +Condition.tests.cpp:: passed: data.float_nine_point_one != Approx( 9.0f ) for: 9.1f != Approx( 9.0 ) +Condition.tests.cpp:: passed: data.float_nine_point_one != Approx( 1 ) for: 9.1f != Approx( 1.0 ) +Condition.tests.cpp:: passed: data.float_nine_point_one != Approx( 0 ) for: 9.1f != Approx( 0.0 ) +Condition.tests.cpp:: passed: data.double_pi != Approx( 3.1415 ) for: 3.1415926535 != Approx( 3.1415 ) +Condition.tests.cpp:: passed: data.str_hello != "goodbye" for: "hello" != "goodbye" +Condition.tests.cpp:: passed: data.str_hello != "hell" for: "hello" != "hell" +Condition.tests.cpp:: passed: data.str_hello != "hello1" for: "hello" != "hello1" +Condition.tests.cpp:: passed: data.str_hello.size() != 6 for: 5 != 6 +Approx.tests.cpp:: passed: d <= Approx( 1.24 ) for: 1.23 <= Approx( 1.24 ) +Approx.tests.cpp:: passed: d <= Approx( 1.23 ) for: 1.23 <= Approx( 1.23 ) +Approx.tests.cpp:: passed: !(d <= Approx( 1.22 )) for: !(1.23 <= Approx( 1.22 )) +Approx.tests.cpp:: passed: d <= Approx( 1.22 ).epsilon(0.1) for: 1.23 <= Approx( 1.22 ) +Misc.tests.cpp:: passed: with 1 message: 'was called' +Matchers.tests.cpp:: passed: testStringForMatching(), Contains("string") && Contains("abc") && Contains("substring") && Contains("contains") for: "this string contains 'abc' as a substring" ( contains: "string" and contains: "abc" and contains: "substring" and contains: "contains" ) +Matchers.tests.cpp:: passed: testStringForMatching(), Contains("string") || Contains("different") || Contains("random") for: "this string contains 'abc' as a substring" ( contains: "string" or contains: "different" or contains: "random" ) +Matchers.tests.cpp:: passed: testStringForMatching2(), Contains("string") || Contains("different") || Contains("random") for: "some completely different text that contains one common word" ( contains: "string" or contains: "different" or contains: "random" ) +Matchers.tests.cpp:: passed: testStringForMatching(), (Contains("string") || Contains("different")) && Contains("substring") for: "this string contains 'abc' as a substring" ( ( contains: "string" or contains: "different" ) and contains: "substring" ) +Matchers.tests.cpp:: failed: testStringForMatching(), (Contains("string") || Contains("different")) && Contains("random") for: "this string contains 'abc' as a substring" ( ( contains: "string" or contains: "different" ) and contains: "random" ) +Matchers.tests.cpp:: passed: testStringForMatching(), !Contains("different") for: "this string contains 'abc' as a substring" not contains: "different" +Matchers.tests.cpp:: failed: testStringForMatching(), !Contains("substring") for: "this string contains 'abc' as a substring" not contains: "substring" +Exception.tests.cpp:: passed: thisThrows(), "expected exception" for: "expected exception" equals: "expected exception" +Exception.tests.cpp:: failed: thisThrows(), "should fail" for: "expected exception" equals: "should fail" +Misc.tests.cpp:: warning: 'This one ran' +Exception.tests.cpp:: failed: unexpected exception with message: 'custom exception' +Tricky.tests.cpp:: passed: True for: {?} +Tricky.tests.cpp:: passed: !False for: true +Tricky.tests.cpp:: passed: !(False) for: !{?} +Condition.tests.cpp:: failed: data.int_seven > 7 for: 7 > 7 +Condition.tests.cpp:: failed: data.int_seven < 7 for: 7 < 7 +Condition.tests.cpp:: failed: data.int_seven > 8 for: 7 > 8 +Condition.tests.cpp:: failed: data.int_seven < 6 for: 7 < 6 +Condition.tests.cpp:: failed: data.int_seven < 0 for: 7 < 0 +Condition.tests.cpp:: failed: data.int_seven < -1 for: 7 < -1 +Condition.tests.cpp:: failed: data.int_seven >= 8 for: 7 >= 8 +Condition.tests.cpp:: failed: data.int_seven <= 6 for: 7 <= 6 +Condition.tests.cpp:: failed: data.float_nine_point_one < 9 for: 9.1f < 9 +Condition.tests.cpp:: failed: data.float_nine_point_one > 10 for: 9.1f > 10 +Condition.tests.cpp:: failed: data.float_nine_point_one > 9.2 for: 9.1f > 9.2 +Condition.tests.cpp:: failed: data.str_hello > "hello" for: "hello" > "hello" +Condition.tests.cpp:: failed: data.str_hello < "hello" for: "hello" < "hello" +Condition.tests.cpp:: failed: data.str_hello > "hellp" for: "hello" > "hellp" +Condition.tests.cpp:: failed: data.str_hello > "z" for: "hello" > "z" +Condition.tests.cpp:: failed: data.str_hello < "hellm" for: "hello" < "hellm" +Condition.tests.cpp:: failed: data.str_hello < "a" for: "hello" < "a" +Condition.tests.cpp:: failed: data.str_hello >= "z" for: "hello" >= "z" +Condition.tests.cpp:: failed: data.str_hello <= "a" for: "hello" <= "a" +Condition.tests.cpp:: passed: data.int_seven < 8 for: 7 < 8 +Condition.tests.cpp:: passed: data.int_seven > 6 for: 7 > 6 +Condition.tests.cpp:: passed: data.int_seven > 0 for: 7 > 0 +Condition.tests.cpp:: passed: data.int_seven > -1 for: 7 > -1 +Condition.tests.cpp:: passed: data.int_seven >= 7 for: 7 >= 7 +Condition.tests.cpp:: passed: data.int_seven >= 6 for: 7 >= 6 +Condition.tests.cpp:: passed: data.int_seven <= 7 for: 7 <= 7 +Condition.tests.cpp:: passed: data.int_seven <= 8 for: 7 <= 8 +Condition.tests.cpp:: passed: data.float_nine_point_one > 9 for: 9.1f > 9 +Condition.tests.cpp:: passed: data.float_nine_point_one < 10 for: 9.1f < 10 +Condition.tests.cpp:: passed: data.float_nine_point_one < 9.2 for: 9.1f < 9.2 +Condition.tests.cpp:: passed: data.str_hello <= "hello" for: "hello" <= "hello" +Condition.tests.cpp:: passed: data.str_hello >= "hello" for: "hello" >= "hello" +Condition.tests.cpp:: passed: data.str_hello < "hellp" for: "hello" < "hellp" +Condition.tests.cpp:: passed: data.str_hello < "zebra" for: "hello" < "zebra" +Condition.tests.cpp:: passed: data.str_hello > "hellm" for: "hello" > "hellm" +Condition.tests.cpp:: passed: data.str_hello > "a" for: "hello" > "a" +Message.tests.cpp:: failed: explicitly with 1 message: 'Message from section one' +Message.tests.cpp:: failed: explicitly with 1 message: 'Message from section two' +CmdLine.tests.cpp:: passed: spec.hasFilters() == false for: false == false +CmdLine.tests.cpp:: passed: spec.matches( tcA ) == false for: false == false +CmdLine.tests.cpp:: passed: spec.matches( tcB ) == false for: false == false +CmdLine.tests.cpp:: passed: spec.hasFilters() == false for: false == false +CmdLine.tests.cpp:: passed: spec.matches(tcA ) == false for: false == false +CmdLine.tests.cpp:: passed: spec.matches( tcB ) == false for: false == false +CmdLine.tests.cpp:: passed: spec.hasFilters() == false for: false == false +CmdLine.tests.cpp:: passed: spec.matches( tcA ) == false for: false == false +CmdLine.tests.cpp:: passed: spec.matches( tcB ) == false for: false == false +CmdLine.tests.cpp:: passed: spec.hasFilters() == true for: true == true +CmdLine.tests.cpp:: passed: spec.matches( tcA ) == false for: false == false +CmdLine.tests.cpp:: passed: spec.matches( tcB ) == true for: true == true +CmdLine.tests.cpp:: passed: spec.hasFilters() == true for: true == true +CmdLine.tests.cpp:: passed: spec.matches( tcA ) == false for: false == false +CmdLine.tests.cpp:: passed: spec.matches( tcB ) == true for: true == true +CmdLine.tests.cpp:: passed: spec.hasFilters() == true for: true == true +CmdLine.tests.cpp:: passed: spec.matches( tcA ) == false for: false == false +CmdLine.tests.cpp:: passed: spec.matches( tcB ) == true for: true == true +CmdLine.tests.cpp:: passed: spec.matches( tcC ) == false for: false == false +CmdLine.tests.cpp:: passed: spec.hasFilters() == true for: true == true +CmdLine.tests.cpp:: passed: spec.matches( tcA ) == false for: false == false +CmdLine.tests.cpp:: passed: spec.matches( tcB ) == false for: false == false +CmdLine.tests.cpp:: passed: spec.matches( tcC ) == true for: true == true +CmdLine.tests.cpp:: passed: spec.matches( tcD ) == false for: false == false +CmdLine.tests.cpp:: passed: parseTestSpec( "*a" ).matches( tcA ) == true for: true == true +CmdLine.tests.cpp:: passed: spec.hasFilters() == true for: true == true +CmdLine.tests.cpp:: passed: spec.matches( tcA ) == false for: false == false +CmdLine.tests.cpp:: passed: spec.matches( tcB ) == false for: false == false +CmdLine.tests.cpp:: passed: spec.matches( tcC ) == true for: true == true +CmdLine.tests.cpp:: passed: spec.matches( tcD ) == false for: false == false +CmdLine.tests.cpp:: passed: parseTestSpec( "a*" ).matches( tcA ) == true for: true == true +CmdLine.tests.cpp:: passed: spec.hasFilters() == true for: true == true +CmdLine.tests.cpp:: passed: spec.matches( tcA ) == false for: false == false +CmdLine.tests.cpp:: passed: spec.matches( tcB ) == false for: false == false +CmdLine.tests.cpp:: passed: spec.matches( tcC ) == true for: true == true +CmdLine.tests.cpp:: passed: spec.matches( tcD ) == true for: true == true +CmdLine.tests.cpp:: passed: parseTestSpec( "*a*" ).matches( tcA ) == true for: true == true +CmdLine.tests.cpp:: passed: spec.hasFilters() == true for: true == true +CmdLine.tests.cpp:: passed: spec.matches( tcA ) == true for: true == true +CmdLine.tests.cpp:: passed: spec.matches( tcB ) == false for: false == false +CmdLine.tests.cpp:: passed: spec.hasFilters() == true for: true == true +CmdLine.tests.cpp:: passed: spec.matches( tcA ) == true for: true == true +CmdLine.tests.cpp:: passed: spec.matches( tcB ) == false for: false == false +CmdLine.tests.cpp:: passed: spec.hasFilters() == true for: true == true +CmdLine.tests.cpp:: passed: spec.matches( tcA ) == true for: true == true +CmdLine.tests.cpp:: passed: spec.matches( tcB ) == false for: false == false +CmdLine.tests.cpp:: passed: spec.hasFilters() == true for: true == true +CmdLine.tests.cpp:: passed: spec.matches( tcA ) == false for: false == false +CmdLine.tests.cpp:: passed: spec.matches( tcB ) == false for: false == false +CmdLine.tests.cpp:: passed: spec.matches( tcC ) == true for: true == true +CmdLine.tests.cpp:: passed: spec.matches( tcD ) == true for: true == true +CmdLine.tests.cpp:: passed: spec.hasFilters() == true for: true == true +CmdLine.tests.cpp:: passed: spec.matches( tcA ) == true for: true == true +CmdLine.tests.cpp:: passed: spec.matches( tcB ) == true for: true == true +CmdLine.tests.cpp:: passed: spec.matches( tcC ) == true for: true == true +CmdLine.tests.cpp:: passed: spec.matches( tcD ) == true for: true == true +CmdLine.tests.cpp:: passed: spec.hasFilters() == true for: true == true +CmdLine.tests.cpp:: passed: spec.matches( tcA ) == false for: false == false +CmdLine.tests.cpp:: passed: spec.matches( tcB ) == true for: true == true +CmdLine.tests.cpp:: passed: spec.matches( tcC ) == false for: false == false +CmdLine.tests.cpp:: passed: spec.hasFilters() == true for: true == true +CmdLine.tests.cpp:: passed: spec.matches( tcA ) == false for: false == false +CmdLine.tests.cpp:: passed: spec.matches( tcB ) == true for: true == true +CmdLine.tests.cpp:: passed: spec.matches( tcC ) == true for: true == true +CmdLine.tests.cpp:: passed: spec.hasFilters() == true for: true == true +CmdLine.tests.cpp:: passed: spec.matches( tcA ) == false for: false == false +CmdLine.tests.cpp:: passed: spec.matches( tcB ) == false for: false == false +CmdLine.tests.cpp:: passed: spec.matches( tcC ) == true for: true == true +CmdLine.tests.cpp:: passed: spec.hasFilters() == true for: true == true +CmdLine.tests.cpp:: passed: spec.matches( tcA ) == false for: false == false +CmdLine.tests.cpp:: passed: spec.matches( tcB ) == false for: false == false +CmdLine.tests.cpp:: passed: spec.matches( tcC ) == true for: true == true +CmdLine.tests.cpp:: passed: spec.hasFilters() == true for: true == true +CmdLine.tests.cpp:: passed: spec.matches( tcA ) == false for: false == false +CmdLine.tests.cpp:: passed: spec.matches( tcB ) == false for: false == false +CmdLine.tests.cpp:: passed: spec.matches( tcC ) == true for: true == true +CmdLine.tests.cpp:: passed: spec.matches( tcD ) == false for: false == false +CmdLine.tests.cpp:: passed: spec.hasFilters() == true for: true == true +CmdLine.tests.cpp:: passed: spec.matches( tcA ) == true for: true == true +CmdLine.tests.cpp:: passed: spec.matches( tcB ) == false for: false == false +CmdLine.tests.cpp:: passed: spec.matches( tcC ) == true for: true == true +CmdLine.tests.cpp:: passed: spec.hasFilters() == true for: true == true +CmdLine.tests.cpp:: passed: spec.matches( tcA ) == false for: false == false +CmdLine.tests.cpp:: passed: spec.matches( tcB ) == true for: true == true +CmdLine.tests.cpp:: passed: spec.matches( tcC ) == false for: false == false +CmdLine.tests.cpp:: passed: spec.hasFilters() == true for: true == true +CmdLine.tests.cpp:: passed: spec.matches( tcA ) == false for: false == false +CmdLine.tests.cpp:: passed: spec.matches( tcB ) == false for: false == false +CmdLine.tests.cpp:: passed: spec.matches( tcC ) == false for: false == false +CmdLine.tests.cpp:: passed: spec.matches( tcD ) == true for: true == true +CmdLine.tests.cpp:: passed: spec.hasFilters() == true for: true == true +CmdLine.tests.cpp:: passed: spec.matches( tcA ) == false for: false == false +CmdLine.tests.cpp:: passed: spec.matches( tcB ) == false for: false == false +CmdLine.tests.cpp:: passed: spec.matches( tcC ) == false for: false == false +CmdLine.tests.cpp:: passed: spec.matches( tcD ) == true for: true == true +CmdLine.tests.cpp:: passed: spec.hasFilters() == true for: true == true +CmdLine.tests.cpp:: passed: spec.matches( tcA ) == true for: true == true +CmdLine.tests.cpp:: passed: spec.matches( tcB ) == false for: false == false +CmdLine.tests.cpp:: passed: spec.matches( tcC ) == true for: true == true +CmdLine.tests.cpp:: passed: spec.matches( tcD ) == true for: true == true +CmdLine.tests.cpp:: passed: spec.hasFilters() == true for: true == true +CmdLine.tests.cpp:: passed: spec.matches( tcA ) == true for: true == true +CmdLine.tests.cpp:: passed: spec.matches( tcB ) == true for: true == true +CmdLine.tests.cpp:: passed: spec.matches( tcC ) == false for: false == false +CmdLine.tests.cpp:: passed: spec.matches( tcD ) == false for: false == false +CmdLine.tests.cpp:: passed: spec.hasFilters() == true for: true == true +CmdLine.tests.cpp:: passed: spec.matches( tcA ) == true for: true == true +CmdLine.tests.cpp:: passed: spec.matches( tcB ) == true for: true == true +CmdLine.tests.cpp:: passed: spec.matches( tcC ) == true for: true == true +CmdLine.tests.cpp:: passed: spec.matches( tcD ) == false for: false == false +CmdLine.tests.cpp:: passed: spec.hasFilters() == true for: true == true +CmdLine.tests.cpp:: passed: spec.matches( tcA ) == true for: true == true +CmdLine.tests.cpp:: passed: spec.matches( tcB ) == true for: true == true +CmdLine.tests.cpp:: passed: spec.matches( tcC ) == true for: true == true +CmdLine.tests.cpp:: passed: spec.matches( tcD ) == false for: false == false +CmdLine.tests.cpp:: passed: spec.hasFilters() == true for: true == true +CmdLine.tests.cpp:: passed: spec.matches( tcA ) == false for: false == false +CmdLine.tests.cpp:: passed: spec.matches( tcB ) == false for: false == false +CmdLine.tests.cpp:: passed: spec.matches( tcC ) == true for: true == true +CmdLine.tests.cpp:: passed: spec.matches( tcD ) == false for: false == false +CmdLine.tests.cpp:: passed: spec.hasFilters() == false for: false == false +CmdLine.tests.cpp:: passed: spec.matches( tcA ) == false for: false == false +CmdLine.tests.cpp:: passed: spec.matches( tcB ) == false for: false == false +CmdLine.tests.cpp:: passed: spec.matches( tcC ) == false for: false == false +CmdLine.tests.cpp:: passed: spec.matches( tcD ) == false for: false == false +CmdLine.tests.cpp:: passed: spec.hasFilters() == false for: false == false +CmdLine.tests.cpp:: passed: spec.matches( tcA ) == false for: false == false +CmdLine.tests.cpp:: passed: spec.matches( tcB ) == false for: false == false +CmdLine.tests.cpp:: passed: spec.matches( tcC ) == false for: false == false +CmdLine.tests.cpp:: passed: spec.matches( tcD ) == false for: false == false +CmdLine.tests.cpp:: passed: spec.hasFilters() == true for: true == true +CmdLine.tests.cpp:: passed: spec.matches( tcA ) == false for: false == false +CmdLine.tests.cpp:: passed: spec.matches( tcB ) == false for: false == false +CmdLine.tests.cpp:: passed: spec.matches( tcC ) == false for: false == false +CmdLine.tests.cpp:: passed: spec.matches( tcD ) == true for: true == true +Tricky.tests.cpp:: passed: (std::pair( 1, 2 )) == aNicePair for: {?} == {?} +Condition.tests.cpp:: passed: p == 0 for: 0 == 0 +Condition.tests.cpp:: passed: p == pNULL for: 0 == 0 +Condition.tests.cpp:: passed: p != 0 for: 0x != 0 +Condition.tests.cpp:: passed: cp != 0 for: 0x != 0 +Condition.tests.cpp:: passed: cpc != 0 for: 0x != 0 +Condition.tests.cpp:: passed: returnsNull() == 0 for: {null string} == 0 +Condition.tests.cpp:: passed: returnsConstNull() == 0 for: {null string} == 0 +Condition.tests.cpp:: passed: 0 != p for: 0 != 0x +CmdLine.tests.cpp:: passed: result for: {?} +CmdLine.tests.cpp:: passed: config.processName == "" for: "" == "" +CmdLine.tests.cpp:: passed: result for: {?} +CmdLine.tests.cpp:: passed: config.processName == "test" for: "test" == "test" +CmdLine.tests.cpp:: passed: config.shouldDebugBreak == false for: false == false +CmdLine.tests.cpp:: passed: config.abortAfter == -1 for: -1 == -1 +CmdLine.tests.cpp:: passed: config.noThrow == false for: false == false +CmdLine.tests.cpp:: passed: config.reporterNames.empty() for: true +CmdLine.tests.cpp:: passed: !(cfg.hasTestFilters()) for: !false +CmdLine.tests.cpp:: passed: result for: {?} +CmdLine.tests.cpp:: passed: cfg.hasTestFilters() for: true +CmdLine.tests.cpp:: passed: cfg.testSpec().matches(fakeTestCase("notIncluded")) == false for: false == false +CmdLine.tests.cpp:: passed: cfg.testSpec().matches(fakeTestCase("test1")) for: true +CmdLine.tests.cpp:: passed: result for: {?} +CmdLine.tests.cpp:: passed: cfg.hasTestFilters() for: true +CmdLine.tests.cpp:: passed: cfg.testSpec().matches(fakeTestCase("test1")) == false for: false == false +CmdLine.tests.cpp:: passed: cfg.testSpec().matches(fakeTestCase("alwaysIncluded")) for: true +CmdLine.tests.cpp:: passed: result for: {?} +CmdLine.tests.cpp:: passed: cfg.hasTestFilters() for: true +CmdLine.tests.cpp:: passed: cfg.testSpec().matches(fakeTestCase("test1")) == false for: false == false +CmdLine.tests.cpp:: passed: cfg.testSpec().matches(fakeTestCase("alwaysIncluded")) for: true +CmdLine.tests.cpp:: passed: cli.parse({"test", "-r", "console"}) for: {?} +CmdLine.tests.cpp:: passed: config.reporterNames[0] == "console" for: "console" == "console" +CmdLine.tests.cpp:: passed: cli.parse({"test", "-r", "xml"}) for: {?} +CmdLine.tests.cpp:: passed: config.reporterNames[0] == "xml" for: "xml" == "xml" +CmdLine.tests.cpp:: passed: cli.parse({"test", "-r", "xml", "-r", "junit"}) for: {?} +CmdLine.tests.cpp:: passed: config.reporterNames.size() == 2 for: 2 == 2 +CmdLine.tests.cpp:: passed: config.reporterNames[0] == "xml" for: "xml" == "xml" +CmdLine.tests.cpp:: passed: config.reporterNames[1] == "junit" for: "junit" == "junit" +CmdLine.tests.cpp:: passed: cli.parse({"test", "--reporter", "junit"}) for: {?} +CmdLine.tests.cpp:: passed: config.reporterNames[0] == "junit" for: "junit" == "junit" +CmdLine.tests.cpp:: passed: cli.parse({"test", "-b"}) for: {?} +CmdLine.tests.cpp:: passed: config.shouldDebugBreak == true for: true == true +CmdLine.tests.cpp:: passed: cli.parse({"test", "--break"}) for: {?} +CmdLine.tests.cpp:: passed: config.shouldDebugBreak for: true +CmdLine.tests.cpp:: passed: cli.parse({"test", "-a"}) for: {?} +CmdLine.tests.cpp:: passed: config.abortAfter == 1 for: 1 == 1 +CmdLine.tests.cpp:: passed: cli.parse({"test", "-x", "2"}) for: {?} +CmdLine.tests.cpp:: passed: config.abortAfter == 2 for: 2 == 2 +CmdLine.tests.cpp:: passed: !result for: true +CmdLine.tests.cpp:: passed: result.errorMessage(), Contains("convert") && Contains("oops") for: "Unable to convert 'oops' to destination type" ( contains: "convert" and contains: "oops" ) +CmdLine.tests.cpp:: passed: cli.parse({"test", "-e"}) for: {?} +CmdLine.tests.cpp:: passed: config.noThrow for: true +CmdLine.tests.cpp:: passed: cli.parse({"test", "--nothrow"}) for: {?} +CmdLine.tests.cpp:: passed: config.noThrow for: true +CmdLine.tests.cpp:: passed: cli.parse({"test", "-o", "filename.ext"}) for: {?} +CmdLine.tests.cpp:: passed: config.outputFilename == "filename.ext" for: "filename.ext" == "filename.ext" +CmdLine.tests.cpp:: passed: cli.parse({"test", "--out", "filename.ext"}) for: {?} +CmdLine.tests.cpp:: passed: config.outputFilename == "filename.ext" for: "filename.ext" == "filename.ext" +CmdLine.tests.cpp:: passed: cli.parse({"test", "-abe"}) for: {?} +CmdLine.tests.cpp:: passed: config.abortAfter == 1 for: 1 == 1 +CmdLine.tests.cpp:: passed: config.shouldDebugBreak for: true +CmdLine.tests.cpp:: passed: config.noThrow == true for: true == true +CmdLine.tests.cpp:: passed: cli.parse({"test"}) for: {?} +CmdLine.tests.cpp:: passed: config.useColour == UseColour::Auto for: 0 == 0 +CmdLine.tests.cpp:: passed: cli.parse({"test", "--use-colour", "auto"}) for: {?} +CmdLine.tests.cpp:: passed: config.useColour == UseColour::Auto for: 0 == 0 +CmdLine.tests.cpp:: passed: cli.parse({"test", "--use-colour", "yes"}) for: {?} +CmdLine.tests.cpp:: passed: config.useColour == UseColour::Yes for: 1 == 1 +CmdLine.tests.cpp:: passed: cli.parse({"test", "--use-colour", "no"}) for: {?} +CmdLine.tests.cpp:: passed: config.useColour == UseColour::No for: 2 == 2 +CmdLine.tests.cpp:: passed: !result for: true +CmdLine.tests.cpp:: passed: result.errorMessage(), Contains( "colour mode must be one of" ) for: "colour mode must be one of: auto, yes or no. 'wrong' not recognised" contains: "colour mode must be one of" +Decomposition.tests.cpp:: failed: truthy(false) for: Hey, its truthy! +Matchers.tests.cpp:: failed: testStringForMatching(), Matches("this STRING contains 'abc' as a substring") for: "this string contains 'abc' as a substring" matches "this STRING contains 'abc' as a substring" case sensitively +Matchers.tests.cpp:: failed: testStringForMatching(), Matches("contains 'abc' as a substring") for: "this string contains 'abc' as a substring" matches "contains 'abc' as a substring" case sensitively +Matchers.tests.cpp:: failed: testStringForMatching(), Matches("this string contains 'abc' as a") for: "this string contains 'abc' as a substring" matches "this string contains 'abc' as a" case sensitively +Message.tests.cpp:: passed: with 1 message: 'this is a success' +Message.tests.cpp:: passed: +BDD.tests.cpp:: passed: before == 0 for: 0 == 0 +BDD.tests.cpp:: passed: after > before for: 1 > 0 +BDD.tests.cpp:: passed: itDoesThis() for: true +BDD.tests.cpp:: passed: itDoesThat() for: true +BDD.tests.cpp:: passed: with 1 message: 'boo!' +BDD.tests.cpp:: passed: v.size() == 0 for: 0 == 0 +BDD.tests.cpp:: passed: v.size() == 10 for: 10 == 10 +BDD.tests.cpp:: passed: v.capacity() >= 10 for: 10 >= 10 +BDD.tests.cpp:: passed: v.size() == 5 for: 5 == 5 +BDD.tests.cpp:: passed: v.capacity() >= 10 for: 10 >= 10 +BDD.tests.cpp:: passed: v.size() == 0 for: 0 == 0 +BDD.tests.cpp:: passed: v.capacity() >= 10 for: 10 >= 10 +BDD.tests.cpp:: passed: v.size() == 0 for: 0 == 0 +A string sent directly to stdout +A string sent directly to stderr +A string sent to stderr via clog +Approx.tests.cpp:: passed: d == Approx( 1.23 ) for: 1.23 == Approx( 1.23 ) +Approx.tests.cpp:: passed: d != Approx( 1.22 ) for: 1.23 != Approx( 1.22 ) +Approx.tests.cpp:: passed: d != Approx( 1.24 ) for: 1.23 != Approx( 1.24 ) +Approx.tests.cpp:: passed: Approx( d ) == 1.23 for: Approx( 1.23 ) == 1.23 +Approx.tests.cpp:: passed: Approx( d ) != 1.22 for: Approx( 1.23 ) != 1.22 +Approx.tests.cpp:: passed: Approx( d ) != 1.24 for: Approx( 1.23 ) != 1.24 +Approx.tests.cpp:: passed: INFINITY == Approx(INFINITY) for: inff == Approx( inf ) +Message from section one +Message from section two +Matchers.tests.cpp:: failed: testStringForMatching(), StartsWith("This String") for: "this string contains 'abc' as a substring" starts with: "This String" +Matchers.tests.cpp:: failed: testStringForMatching(), StartsWith("string", Catch::CaseSensitive::No) for: "this string contains 'abc' as a substring" starts with: "string" (case insensitive) +ToStringGeneral.tests.cpp:: passed: Catch::Detail::stringify(singular) == "{ 1 }" for: "{ 1 }" == "{ 1 }" +ToStringGeneral.tests.cpp:: passed: Catch::Detail::stringify(arr) == "{ 3, 2, 1 }" for: "{ 3, 2, 1 }" == "{ 3, 2, 1 }" +ToStringGeneral.tests.cpp:: passed: Catch::Detail::stringify(arr) == R"({ { "1:1", "1:2", "1:3" }, { "2:1", "2:2" } })" for: "{ { "1:1", "1:2", "1:3" }, { "2:1", "2:2" } }" +== +"{ { "1:1", "1:2", "1:3" }, { "2:1", "2:2" } }" +Matchers.tests.cpp:: passed: testStringForMatching(), Contains("string") for: "this string contains 'abc' as a substring" contains: "string" +Matchers.tests.cpp:: passed: testStringForMatching(), Contains("string", Catch::CaseSensitive::No) for: "this string contains 'abc' as a substring" contains: "string" (case insensitive) +Matchers.tests.cpp:: passed: testStringForMatching(), Contains("abc") for: "this string contains 'abc' as a substring" contains: "abc" +Matchers.tests.cpp:: passed: testStringForMatching(), Contains("aBC", Catch::CaseSensitive::No) for: "this string contains 'abc' as a substring" contains: "abc" (case insensitive) +Matchers.tests.cpp:: passed: testStringForMatching(), StartsWith("this") for: "this string contains 'abc' as a substring" starts with: "this" +Matchers.tests.cpp:: passed: testStringForMatching(), StartsWith("THIS", Catch::CaseSensitive::No) for: "this string contains 'abc' as a substring" starts with: "this" (case insensitive) +Matchers.tests.cpp:: passed: testStringForMatching(), EndsWith("substring") for: "this string contains 'abc' as a substring" ends with: "substring" +Matchers.tests.cpp:: passed: testStringForMatching(), EndsWith(" SuBsTrInG", Catch::CaseSensitive::No) for: "this string contains 'abc' as a substring" ends with: " substring" (case insensitive) +String.tests.cpp:: passed: empty.empty() for: true +String.tests.cpp:: passed: empty.size() == 0 for: 0 == 0 +String.tests.cpp:: passed: std::strcmp( empty.c_str(), "" ) == 0 for: 0 == 0 +String.tests.cpp:: passed: s.empty() == false for: false == false +String.tests.cpp:: passed: s.size() == 5 for: 5 == 5 +String.tests.cpp:: passed: isSubstring( s ) == false for: false == false +String.tests.cpp:: passed: std::strcmp( rawChars, "hello" ) == 0 for: 0 == 0 +String.tests.cpp:: passed: isOwned( s ) == false for: false == false +String.tests.cpp:: passed: s.c_str() == rawChars for: "hello" == "hello" +String.tests.cpp:: passed: isOwned( s ) == false for: false == false +String.tests.cpp:: passed: original == "original" +String.tests.cpp:: passed: isSubstring( original ) for: true +String.tests.cpp:: passed: isOwned( original ) == false for: false == false +String.tests.cpp:: passed: isSubstring( original ) == false for: false == false +String.tests.cpp:: passed: isOwned( original ) for: true +String.tests.cpp:: passed: ss.empty() == false for: false == false +String.tests.cpp:: passed: ss.size() == 5 for: 5 == 5 +String.tests.cpp:: passed: std::strcmp( ss.c_str(), "hello" ) == 0 for: 0 == 0 +String.tests.cpp:: passed: ss == "hello" for: hello == "hello" +String.tests.cpp:: passed: isSubstring( ss ) for: true +String.tests.cpp:: passed: isOwned( ss ) == false for: false == false +String.tests.cpp:: passed: rawChars == s.currentData() for: "hello world!" == "hello world!" +String.tests.cpp:: passed: ss.c_str() != rawChars for: "hello" != "hello world!" +String.tests.cpp:: passed: isSubstring( ss ) == false for: false == false +String.tests.cpp:: passed: isOwned( ss ) for: true +String.tests.cpp:: passed: ss.currentData() != s.currentData() for: "hello" != "hello world!" +String.tests.cpp:: passed: ss.size() == 6 for: 6 == 6 +String.tests.cpp:: passed: std::strcmp( ss.c_str(), "world!" ) == 0 for: 0 == 0 +String.tests.cpp:: passed: s.c_str() == s2.c_str() for: "hello world!" == "hello world!" +String.tests.cpp:: passed: s.c_str() != ss.c_str() for: "hello world!" != "hello" +String.tests.cpp:: passed: StringRef("hello") == StringRef("hello") for: hello == hello +String.tests.cpp:: passed: StringRef("hello") != StringRef("cello") for: hello != cello +String.tests.cpp:: passed: sr == "a standard string" for: a standard string == "a standard string" +String.tests.cpp:: passed: sr.size() == stdStr.size() for: 17 == 17 +String.tests.cpp:: passed: sr == "a standard string" for: a standard string == "a standard string" +String.tests.cpp:: passed: sr.size() == stdStr.size() for: 17 == 17 +String.tests.cpp:: passed: sr == "a standard string" for: a standard string == "a standard string" +String.tests.cpp:: passed: sr.size() == stdStr.size() for: 17 == 17 +String.tests.cpp:: passed: stdStr == "a stringref" for: "a stringref" == "a stringref" +String.tests.cpp:: passed: stdStr.size() == sr.size() for: 11 == 11 +String.tests.cpp:: passed: stdStr == "a stringref" for: "a stringref" == "a stringref" +String.tests.cpp:: passed: stdStr.size() == sr.size() for: 11 == 11 +String.tests.cpp:: passed: stdStr == "a stringref" for: "a stringref" == "a stringref" +String.tests.cpp:: passed: stdStr.size() == sr.size() for: 11 == 11 +String.tests.cpp:: passed: ascii.numberOfCharacters() == ascii.size() for: 39 == 39 +String.tests.cpp:: passed: simpleu8.numberOfCharacters() == 30 for: 30 == 30 +String.tests.cpp:: passed: emojis.numberOfCharacters() == 9 for: 9 == 9 +ToStringChrono.tests.cpp:: passed: minute == seconds for: 1 m == 60 s +ToStringChrono.tests.cpp:: passed: hour != seconds for: 1 h != 60 s +ToStringChrono.tests.cpp:: passed: micro != milli for: 1 us != 1 ms +ToStringChrono.tests.cpp:: passed: nano != micro for: 1 ns != 1 us +ToStringChrono.tests.cpp:: passed: half_minute != femto_second for: 1 [30/1]s != 1 fs +ToStringChrono.tests.cpp:: passed: pico_second != atto_second for: 1 ps != 1 as +ToStringChrono.tests.cpp:: passed: now != later for: {iso8601-timestamp} +!= +{iso8601-timestamp} +Misc.tests.cpp:: failed: s1 == s2 for: "if ($b == 10) { + $a = 20; +}" +== +"if ($b == 10) { + $a = 20; +} +" +TagAlias.tests.cpp:: passed: what, Contains( "[@zzz]" ) for: "error: tag alias, '[@zzz]' already registered. + First seen at: file:2 + Redefined at: file:10" contains: "[@zzz]" +TagAlias.tests.cpp:: passed: what, Contains( "file" ) for: "error: tag alias, '[@zzz]' already registered. + First seen at: file:2 + Redefined at: file:10" contains: "file" +TagAlias.tests.cpp:: passed: what, Contains( "2" ) for: "error: tag alias, '[@zzz]' already registered. + First seen at: file:2 + Redefined at: file:10" contains: "2" +TagAlias.tests.cpp:: passed: what, Contains( "10" ) for: "error: tag alias, '[@zzz]' already registered. + First seen at: file:2 + Redefined at: file:10" contains: "10" +TagAlias.tests.cpp:: passed: registry.add( "[no ampersat]", "", Catch::SourceLineInfo( "file", 3 ) ) +TagAlias.tests.cpp:: passed: registry.add( "[the @ is not at the start]", "", Catch::SourceLineInfo( "file", 3 ) ) +TagAlias.tests.cpp:: passed: registry.add( "@no square bracket at start]", "", Catch::SourceLineInfo( "file", 3 ) ) +TagAlias.tests.cpp:: passed: registry.add( "[@no square bracket at end", "", Catch::SourceLineInfo( "file", 3 ) ) +VariadicMacros.tests.cpp:: passed: with 1 message: 'no assertions' +Tricky.tests.cpp:: passed: 0x == bit30and31 for: 3221225472 (0x) == 3221225472 +Message.tests.cpp:: failed - but was ok: 1 == 2 +Misc.tests.cpp:: passed: with 1 message: 'oops!' +Exception.tests.cpp:: failed: unexpected exception with message: 'For some reason someone is throwing a string literal!' +PartTracker.tests.cpp:: passed: testCase.isOpen() for: true +PartTracker.tests.cpp:: passed: s1.isOpen() for: true +PartTracker.tests.cpp:: passed: s1.isSuccessfullyCompleted() for: true +PartTracker.tests.cpp:: passed: testCase.isComplete() == false for: false == false +PartTracker.tests.cpp:: passed: ctx.completedCycle() for: true +PartTracker.tests.cpp:: passed: testCase.isSuccessfullyCompleted() for: true +PartTracker.tests.cpp:: passed: testCase.isOpen() for: true +PartTracker.tests.cpp:: passed: s1.isOpen() for: true +PartTracker.tests.cpp:: passed: s1.isComplete() for: true +PartTracker.tests.cpp:: passed: s1.isSuccessfullyCompleted() == false for: false == false +PartTracker.tests.cpp:: passed: testCase.isComplete() == false for: false == false +PartTracker.tests.cpp:: passed: ctx.completedCycle() for: true +PartTracker.tests.cpp:: passed: testCase.isSuccessfullyCompleted() == false for: false == false +PartTracker.tests.cpp:: passed: testCase2.isOpen() for: true +PartTracker.tests.cpp:: passed: s1b.isOpen() == false for: false == false +PartTracker.tests.cpp:: passed: ctx.completedCycle() for: true +PartTracker.tests.cpp:: passed: testCase.isComplete() for: true +PartTracker.tests.cpp:: passed: testCase.isSuccessfullyCompleted() for: true +PartTracker.tests.cpp:: passed: testCase.isOpen() for: true +PartTracker.tests.cpp:: passed: s1.isOpen() for: true +PartTracker.tests.cpp:: passed: s1.isComplete() for: true +PartTracker.tests.cpp:: passed: s1.isSuccessfullyCompleted() == false for: false == false +PartTracker.tests.cpp:: passed: testCase.isComplete() == false for: false == false +PartTracker.tests.cpp:: passed: ctx.completedCycle() for: true +PartTracker.tests.cpp:: passed: testCase.isSuccessfullyCompleted() == false for: false == false +PartTracker.tests.cpp:: passed: testCase2.isOpen() for: true +PartTracker.tests.cpp:: passed: s1b.isOpen() == false for: false == false +PartTracker.tests.cpp:: passed: s2.isOpen() for: true +PartTracker.tests.cpp:: passed: ctx.completedCycle() for: true +PartTracker.tests.cpp:: passed: testCase.isComplete() for: true +PartTracker.tests.cpp:: passed: testCase.isSuccessfullyCompleted() for: true +PartTracker.tests.cpp:: passed: testCase.isOpen() for: true +PartTracker.tests.cpp:: passed: s1.isOpen() for: true +PartTracker.tests.cpp:: passed: s2.isOpen() == false for: false == false +PartTracker.tests.cpp:: passed: testCase.isComplete() == false for: false == false +PartTracker.tests.cpp:: passed: testCase2.isOpen() for: true +PartTracker.tests.cpp:: passed: s1b.isOpen() == false for: false == false +PartTracker.tests.cpp:: passed: s2b.isOpen() for: true +PartTracker.tests.cpp:: passed: ctx.completedCycle() == false for: false == false +PartTracker.tests.cpp:: passed: ctx.completedCycle() for: true +PartTracker.tests.cpp:: passed: s2b.isSuccessfullyCompleted() for: true +PartTracker.tests.cpp:: passed: testCase2.isComplete() == false for: false == false +PartTracker.tests.cpp:: passed: testCase2.isSuccessfullyCompleted() for: true +PartTracker.tests.cpp:: passed: testCase.isOpen() for: true +PartTracker.tests.cpp:: passed: s1.isOpen() for: true +PartTracker.tests.cpp:: passed: s2.isOpen() == false for: false == false +PartTracker.tests.cpp:: passed: testCase.isComplete() == false for: false == false +PartTracker.tests.cpp:: passed: testCase2.isOpen() for: true +PartTracker.tests.cpp:: passed: s1b.isOpen() == false for: false == false +PartTracker.tests.cpp:: passed: s2b.isOpen() for: true +PartTracker.tests.cpp:: passed: ctx.completedCycle() == false for: false == false +PartTracker.tests.cpp:: passed: ctx.completedCycle() for: true +PartTracker.tests.cpp:: passed: s2b.isComplete() for: true +PartTracker.tests.cpp:: passed: s2b.isSuccessfullyCompleted() == false for: false == false +PartTracker.tests.cpp:: passed: testCase2.isSuccessfullyCompleted() == false for: false == false +PartTracker.tests.cpp:: passed: testCase3.isOpen() for: true +PartTracker.tests.cpp:: passed: s1c.isOpen() == false for: false == false +PartTracker.tests.cpp:: passed: s2c.isOpen() == false for: false == false +PartTracker.tests.cpp:: passed: testCase3.isSuccessfullyCompleted() for: true +PartTracker.tests.cpp:: passed: testCase.isOpen() for: true +PartTracker.tests.cpp:: passed: s1.isOpen() for: true +PartTracker.tests.cpp:: passed: s2.isOpen() for: true +PartTracker.tests.cpp:: passed: s2.isComplete() for: true +PartTracker.tests.cpp:: passed: s1.isComplete() == false for: false == false +PartTracker.tests.cpp:: passed: s1.isComplete() for: true +PartTracker.tests.cpp:: passed: testCase.isComplete() == false for: false == false +PartTracker.tests.cpp:: passed: testCase.isComplete() for: true +PartTracker.tests.cpp:: passed: testCase.isOpen() for: true +PartTracker.tests.cpp:: passed: s1.isOpen() for: true +PartTracker.tests.cpp:: passed: g1.isOpen() for: true +PartTracker.tests.cpp:: passed: g1.index() == 0 for: 0 == 0 +PartTracker.tests.cpp:: passed: g1.isComplete() == false for: false == false +PartTracker.tests.cpp:: passed: s1.isComplete() == false for: false == false +PartTracker.tests.cpp:: passed: s1.isComplete() == false for: false == false +PartTracker.tests.cpp:: passed: testCase.isSuccessfullyCompleted() == false for: false == false +PartTracker.tests.cpp:: passed: testCase2.isOpen() for: true +PartTracker.tests.cpp:: passed: s1b.isOpen() for: true +PartTracker.tests.cpp:: passed: g1b.isOpen() for: true +PartTracker.tests.cpp:: passed: g1b.index() == 1 for: 1 == 1 +PartTracker.tests.cpp:: passed: s1.isComplete() == false for: false == false +PartTracker.tests.cpp:: passed: s1b.isComplete() for: true +PartTracker.tests.cpp:: passed: g1b.isComplete() for: true +PartTracker.tests.cpp:: passed: testCase2.isComplete() for: true +PartTracker.tests.cpp:: passed: testCase.isOpen() for: true +PartTracker.tests.cpp:: passed: s1.isOpen() for: true +PartTracker.tests.cpp:: passed: g1.isOpen() for: true +PartTracker.tests.cpp:: passed: g1.index() == 0 for: 0 == 0 +PartTracker.tests.cpp:: passed: g1.isComplete() == false for: false == false +PartTracker.tests.cpp:: passed: s1.isComplete() == false for: false == false +PartTracker.tests.cpp:: passed: s2.isOpen() for: true +PartTracker.tests.cpp:: passed: s2.isComplete() for: true +PartTracker.tests.cpp:: passed: s1.isComplete() == false for: false == false +PartTracker.tests.cpp:: passed: testCase.isComplete() == false for: false == false +PartTracker.tests.cpp:: passed: testCase2.isOpen() for: true +PartTracker.tests.cpp:: passed: s1b.isOpen() for: true +PartTracker.tests.cpp:: passed: g1b.isOpen() for: true +PartTracker.tests.cpp:: passed: g1b.index() == 1 for: 1 == 1 +PartTracker.tests.cpp:: passed: s2b.isOpen() for: true +PartTracker.tests.cpp:: passed: s2b.isComplete() for: true +PartTracker.tests.cpp:: passed: g1b.isComplete() for: true +PartTracker.tests.cpp:: passed: s1b.isComplete() for: true +PartTracker.tests.cpp:: passed: testCase2.isComplete() for: true +PartTracker.tests.cpp:: passed: testCase.isOpen() for: true +PartTracker.tests.cpp:: passed: s1.isOpen() for: true +PartTracker.tests.cpp:: passed: g1.isOpen() for: true +PartTracker.tests.cpp:: passed: g1.index() == 0 for: 0 == 0 +PartTracker.tests.cpp:: passed: g1.isComplete() == false for: false == false +PartTracker.tests.cpp:: passed: s1.isComplete() == false for: false == false +PartTracker.tests.cpp:: passed: s2.isOpen() for: true +PartTracker.tests.cpp:: passed: s2.isComplete() for: true +PartTracker.tests.cpp:: passed: s2.isSuccessfullyCompleted() == false for: false == false +PartTracker.tests.cpp:: passed: s1.isComplete() == false for: false == false +PartTracker.tests.cpp:: passed: testCase.isComplete() == false for: false == false +PartTracker.tests.cpp:: passed: testCase2.isOpen() for: true +PartTracker.tests.cpp:: passed: s1b.isOpen() for: true +PartTracker.tests.cpp:: passed: g1b.isOpen() for: true +PartTracker.tests.cpp:: passed: g1b.index() == 0 for: 0 == 0 +PartTracker.tests.cpp:: passed: s2b.isOpen() == false for: false == false +PartTracker.tests.cpp:: passed: g1b.isComplete() == false for: false == false +PartTracker.tests.cpp:: passed: s1b.isComplete() == false for: false == false +PartTracker.tests.cpp:: passed: testCase2.isComplete() == false for: false == false +PartTracker.tests.cpp:: passed: testCase3.isOpen() for: true +PartTracker.tests.cpp:: passed: s1c.isOpen() for: true +PartTracker.tests.cpp:: passed: g1c.isOpen() for: true +PartTracker.tests.cpp:: passed: g1c.index() == 1 for: 1 == 1 +PartTracker.tests.cpp:: passed: s2c.isOpen() for: true +PartTracker.tests.cpp:: passed: s2c.isComplete() for: true +PartTracker.tests.cpp:: passed: g1c.isComplete() for: true +PartTracker.tests.cpp:: passed: s1c.isComplete() for: true +PartTracker.tests.cpp:: passed: testCase3.isComplete() for: true +Exception.tests.cpp:: failed: unexpected exception with message: '3.14' +Approx.tests.cpp:: passed: d == approx( 1.23 ) for: 1.23 == Approx( 1.23 ) +Approx.tests.cpp:: passed: d == approx( 1.22 ) for: 1.23 == Approx( 1.22 ) +Approx.tests.cpp:: passed: d == approx( 1.24 ) for: 1.23 == Approx( 1.24 ) +Approx.tests.cpp:: passed: d != approx( 1.25 ) for: 1.23 != Approx( 1.25 ) +Approx.tests.cpp:: passed: approx( d ) == 1.23 for: Approx( 1.23 ) == 1.23 +Approx.tests.cpp:: passed: approx( d ) == 1.22 for: Approx( 1.23 ) == 1.22 +Approx.tests.cpp:: passed: approx( d ) == 1.24 for: Approx( 1.23 ) == 1.24 +Approx.tests.cpp:: passed: approx( d ) != 1.25 for: Approx( 1.23 ) != 1.25 +VariadicMacros.tests.cpp:: passed: with 1 message: 'no assertions' +Matchers.tests.cpp:: passed: v, VectorContains(1) for: { 1, 2, 3 } Contains: 1 +Matchers.tests.cpp:: passed: v, VectorContains(2) for: { 1, 2, 3 } Contains: 2 +Matchers.tests.cpp:: passed: v, Contains(v2) for: { 1, 2, 3 } Contains: { 1, 2 } +Matchers.tests.cpp:: passed: v, Contains(v2) for: { 1, 2, 3 } Contains: { 1, 2, 3 } +Matchers.tests.cpp:: passed: v, Contains(empty) for: { 1, 2, 3 } Contains: { } +Matchers.tests.cpp:: passed: empty, Contains(empty) for: { } Contains: { } +Matchers.tests.cpp:: passed: v, VectorContains(1) && VectorContains(2) for: { 1, 2, 3 } ( Contains: 1 and Contains: 2 ) +Matchers.tests.cpp:: passed: v, Equals(v) for: { 1, 2, 3 } Equals: { 1, 2, 3 } +Matchers.tests.cpp:: passed: empty, Equals(empty) for: { } Equals: { } +Matchers.tests.cpp:: passed: v, Equals(v2) for: { 1, 2, 3 } Equals: { 1, 2, 3 } +Matchers.tests.cpp:: passed: v, UnorderedEquals(v) for: { 1, 2, 3 } UnorderedEquals: { 1, 2, 3 } +Matchers.tests.cpp:: passed: empty, UnorderedEquals(empty) for: { } UnorderedEquals: { } +Matchers.tests.cpp:: passed: permuted, UnorderedEquals(v) for: { 1, 3, 2 } UnorderedEquals: { 1, 2, 3 } +Matchers.tests.cpp:: passed: permuted, UnorderedEquals(v) for: { 2, 3, 1 } UnorderedEquals: { 1, 2, 3 } +Matchers.tests.cpp:: failed: v, VectorContains(-1) for: { 1, 2, 3 } Contains: -1 +Matchers.tests.cpp:: failed: empty, VectorContains(1) for: { } Contains: 1 +Matchers.tests.cpp:: failed: empty, Contains(v) for: { } Contains: { 1, 2, 3 } +Matchers.tests.cpp:: failed: v, Contains(v2) for: { 1, 2, 3 } Contains: { 1, 2, 4 } +Matchers.tests.cpp:: failed: v, Equals(v2) for: { 1, 2, 3 } Equals: { 1, 2 } +Matchers.tests.cpp:: failed: v2, Equals(v) for: { 1, 2 } Equals: { 1, 2, 3 } +Matchers.tests.cpp:: failed: empty, Equals(v) for: { } Equals: { 1, 2, 3 } +Matchers.tests.cpp:: failed: v, Equals(empty) for: { 1, 2, 3 } Equals: { } +Matchers.tests.cpp:: failed: v, UnorderedEquals(empty) for: { 1, 2, 3 } UnorderedEquals: { } +Matchers.tests.cpp:: failed: empty, UnorderedEquals(v) for: { } UnorderedEquals: { 1, 2, 3 } +Matchers.tests.cpp:: failed: permuted, UnorderedEquals(v) for: { 1, 3 } UnorderedEquals: { 1, 2, 3 } +Matchers.tests.cpp:: failed: permuted, UnorderedEquals(v) for: { 3, 1 } UnorderedEquals: { 1, 2, 3 } +Exception.tests.cpp:: passed: thisThrows(), std::domain_error +Exception.tests.cpp:: passed: thisDoesntThrow() +Exception.tests.cpp:: passed: thisThrows() +Exception.tests.cpp:: failed: unexpected exception with message: 'unexpected exception' +Exception.tests.cpp:: failed: unexpected exception with message: 'expected exception'; expression was: thisThrows() == 0 +Exception.tests.cpp:: failed: unexpected exception with message: 'expected exception'; expression was: thisThrows() == 0 +Exception.tests.cpp:: failed: unexpected exception with message: 'expected exception'; expression was: thisThrows() == 0 +Exception.tests.cpp:: failed: unexpected exception with message: 'unexpected exception' +Tricky.tests.cpp:: warning: 'Uncomment the code in this test to check that it gives a sensible compiler error' +Tricky.tests.cpp:: warning: 'Uncomment the code in this test to check that it gives a sensible compiler error' +Tricky.tests.cpp:: passed: +Tricky.tests.cpp:: passed: +Tricky.tests.cpp:: passed: +Tricky.tests.cpp:: passed: +Xml.tests.cpp:: passed: encode( "normal string" ) == "normal string" for: "normal string" == "normal string" +Xml.tests.cpp:: passed: encode( "" ) == "" for: "" == "" +Xml.tests.cpp:: passed: encode( "smith & jones" ) == "smith & jones" for: "smith & jones" == "smith & jones" +Xml.tests.cpp:: passed: encode( "smith < jones" ) == "smith < jones" for: "smith < jones" == "smith < jones" +Xml.tests.cpp:: passed: encode( "smith > jones" ) == "smith > jones" for: "smith > jones" == "smith > jones" +Xml.tests.cpp:: passed: encode( "smith ]]> jones" ) == "smith ]]> jones" for: "smith ]]> jones" +== +"smith ]]> jones" +Xml.tests.cpp:: passed: encode( stringWithQuotes ) == stringWithQuotes for: "don't "quote" me on that" +== +"don't "quote" me on that" +Xml.tests.cpp:: passed: encode( stringWithQuotes, Catch::XmlEncode::ForAttributes ) == "don't "quote" me on that" for: "don't "quote" me on that" +== +"don't "quote" me on that" +Xml.tests.cpp:: passed: encode( "[/x01]" ) == "[//x01]" for: "[/x01]" == "[/x01]" +Xml.tests.cpp:: passed: encode( "[/x7F]" ) == "[//x7F]" for: "[/x7F]" == "[/x7F]" +ToStringVector.tests.cpp:: passed: Catch::Detail::stringify( empty ) == "{ }" for: "{ }" == "{ }" +ToStringVector.tests.cpp:: passed: Catch::Detail::stringify( oneValue ) == "{ 42 }" for: "{ 42 }" == "{ 42 }" +ToStringVector.tests.cpp:: passed: Catch::Detail::stringify( twoValues ) == "{ 42, 250 }" for: "{ 42, 250 }" == "{ 42, 250 }" +Misc.tests.cpp:: passed: x == 0 for: 0 == 0 +Tricky.tests.cpp:: passed: obj.prop != 0 for: 0x != 0 +Misc.tests.cpp:: passed: flag for: true +Misc.tests.cpp:: passed: testCheckedElse( true ) for: true +Misc.tests.cpp:: failed: flag for: false +Misc.tests.cpp:: failed: testCheckedElse( false ) for: false +Misc.tests.cpp:: passed: flag for: true +Misc.tests.cpp:: passed: testCheckedIf( true ) for: true +Misc.tests.cpp:: failed: flag for: false +Misc.tests.cpp:: failed: testCheckedIf( false ) for: false +Condition.tests.cpp:: passed: unsigned_char_var == 1 for: 1 == 1 +Condition.tests.cpp:: passed: unsigned_short_var == 1 for: 1 == 1 +Condition.tests.cpp:: passed: unsigned_int_var == 1 for: 1 == 1 +Condition.tests.cpp:: passed: unsigned_long_var == 1 for: 1 == 1 +Condition.tests.cpp:: passed: long_var == unsigned_char_var for: 1 == 1 +Condition.tests.cpp:: passed: long_var == unsigned_short_var for: 1 == 1 +Condition.tests.cpp:: passed: long_var == unsigned_int_var for: 1 == 1 +Condition.tests.cpp:: passed: long_var == unsigned_long_var for: 1 == 1 +Misc.tests.cpp:: passed: +Misc.tests.cpp:: passed: +Misc.tests.cpp:: passed: +loose text artifact +Message.tests.cpp:: failed: explicitly with 1 message: 'Previous info should not be seen' +Misc.tests.cpp:: passed: l == std::numeric_limits::max() for: 9223372036854775807 (0x) +== +9223372036854775807 (0x) +Misc.tests.cpp:: failed: b > a for: 0 > 1 +Misc.tests.cpp:: failed: ( fib[i] % 2 ) == 0 for: 1 == 0 with 1 message: 'Testing if fib[0] (1) is even' +Misc.tests.cpp:: failed: ( fib[i] % 2 ) == 0 for: 1 == 0 with 1 message: 'Testing if fib[1] (1) is even' +Misc.tests.cpp:: passed: ( fib[i] % 2 ) == 0 for: 0 == 0 with 1 message: 'Testing if fib[2] (2) is even' +Misc.tests.cpp:: failed: ( fib[i] % 2 ) == 0 for: 1 == 0 with 1 message: 'Testing if fib[3] (3) is even' +Misc.tests.cpp:: failed: ( fib[i] % 2 ) == 0 for: 1 == 0 with 1 message: 'Testing if fib[4] (5) is even' +Misc.tests.cpp:: passed: ( fib[i] % 2 ) == 0 for: 0 == 0 with 1 message: 'Testing if fib[5] (8) is even' +Misc.tests.cpp:: failed: ( fib[i] % 2 ) == 0 for: 1 == 0 with 1 message: 'Testing if fib[6] (13) is even' +Misc.tests.cpp:: failed: ( fib[i] % 2 ) == 0 for: 1 == 0 with 1 message: 'Testing if fib[7] (21) is even' +Misc.tests.cpp:: failed: a == b for: 1 == 2 +Misc.tests.cpp:: passed: a != b for: 1 != 2 +Misc.tests.cpp:: passed: a < b for: 1 < 2 +Misc.tests.cpp:: passed: a != b for: 1 != 2 +Misc.tests.cpp:: passed: b != a for: 2 != 1 +Misc.tests.cpp:: passed: a != b for: 1 != 2 +Tricky.tests.cpp:: passed: s == "7" for: "7" == "7" +Tricky.tests.cpp:: passed: ti == typeid(int) for: {?} == {?} +Misc.tests.cpp:: passed: +Misc.tests.cpp:: passed: makeString( false ) != static_cast(0) for: "valid string" != {null string} +Misc.tests.cpp:: passed: makeString( true ) == static_cast(0) for: {null string} == {null string} +Tricky.tests.cpp:: passed: ptr.get() == 0 for: 0 == 0 +ToStringPair.tests.cpp:: passed: ::Catch::Detail::stringify( pair ) == "{ { 42, /"Arthur/" }, { /"Ford/", 24 } }" for: "{ { 42, "Arthur" }, { "Ford", 24 } }" +== +"{ { 42, "Arthur" }, { "Ford", 24 } }" +Tricky.tests.cpp:: passed: p == 0 for: 0 == 0 +Misc.tests.cpp:: passed: a != b for: 1 != 2 +Misc.tests.cpp:: passed: b != a for: 2 != 1 +Misc.tests.cpp:: passed: a != b for: 1 != 2 +String.tests.cpp:: passed: Catch::replaceInPlace( letters, "b", "z" ) for: true +String.tests.cpp:: passed: letters == "azcdefcg" for: "azcdefcg" == "azcdefcg" +String.tests.cpp:: passed: Catch::replaceInPlace( letters, "c", "z" ) for: true +String.tests.cpp:: passed: letters == "abzdefzg" for: "abzdefzg" == "abzdefzg" +String.tests.cpp:: passed: Catch::replaceInPlace( letters, "a", "z" ) for: true +String.tests.cpp:: passed: letters == "zbcdefcg" for: "zbcdefcg" == "zbcdefcg" +String.tests.cpp:: passed: Catch::replaceInPlace( letters, "g", "z" ) for: true +String.tests.cpp:: passed: letters == "abcdefcz" for: "abcdefcz" == "abcdefcz" +String.tests.cpp:: passed: Catch::replaceInPlace( letters, letters, "replaced" ) for: true +String.tests.cpp:: passed: letters == "replaced" for: "replaced" == "replaced" +String.tests.cpp:: passed: !(Catch::replaceInPlace( letters, "x", "z" )) for: !false +String.tests.cpp:: passed: letters == letters for: "abcdefcg" == "abcdefcg" +String.tests.cpp:: passed: Catch::replaceInPlace( s, "'", "|'" ) for: true +String.tests.cpp:: passed: s == "didn|'t" for: "didn|'t" == "didn|'t" +Misc.tests.cpp:: failed: false with 1 message: '3' +Message.tests.cpp:: failed: false with 2 messages: 'hi' and 'i := 7' +ToStringGeneral.tests.cpp:: passed: Catch::Detail::stringify( emptyMap ) == "{ }" for: "{ }" == "{ }" +ToStringGeneral.tests.cpp:: passed: Catch::Detail::stringify( map ) == "{ { /"one/", 1 } }" for: "{ { "one", 1 } }" == "{ { "one", 1 } }" +ToStringGeneral.tests.cpp:: passed: Catch::Detail::stringify( map ) == "{ { /"abc/", 1 }, { /"def/", 2 }, { /"ghi/", 3 } }" for: "{ { "abc", 1 }, { "def", 2 }, { "ghi", 3 } }" +== +"{ { "abc", 1 }, { "def", 2 }, { "ghi", 3 } }" +ToStringPair.tests.cpp:: passed: ::Catch::Detail::stringify(value) == "{ 34, /"xyzzy/" }" for: "{ 34, "xyzzy" }" == "{ 34, "xyzzy" }" +ToStringPair.tests.cpp:: passed: ::Catch::Detail::stringify( value ) == "{ 34, /"xyzzy/" }" for: "{ 34, "xyzzy" }" == "{ 34, "xyzzy" }" +ToStringGeneral.tests.cpp:: passed: Catch::Detail::stringify( emptySet ) == "{ }" for: "{ }" == "{ }" +ToStringGeneral.tests.cpp:: passed: Catch::Detail::stringify( set ) == "{ /"one/" }" for: "{ "one" }" == "{ "one" }" +ToStringGeneral.tests.cpp:: passed: Catch::Detail::stringify( set ) == "{ /"abc/", /"def/", /"ghi/" }" for: "{ "abc", "def", "ghi" }" +== +"{ "abc", "def", "ghi" }" +ToStringPair.tests.cpp:: passed: ::Catch::Detail::stringify( pr ) == "{ { /"green/", 55 } }" for: "{ { "green", 55 } }" +== +"{ { "green", 55 } }" +Tricky.tests.cpp:: failed: std::string( "first" ) == "second" for: "first" == "second" +ToStringWhich.tests.cpp:: passed: ::Catch::Detail::stringify(streamable_range{}) == "op<<(streamable_range)" for: "op<<(streamable_range)" +== +"op<<(streamable_range)" +ToStringWhich.tests.cpp:: passed: ::Catch::Detail::stringify(stringmaker_range{}) == "stringmaker(streamable_range)" for: "stringmaker(streamable_range)" +== +"stringmaker(streamable_range)" +ToStringWhich.tests.cpp:: passed: ::Catch::Detail::stringify(just_range{}) == "{ 1, 2, 3, 4 }" for: "{ 1, 2, 3, 4 }" == "{ 1, 2, 3, 4 }" +ToStringWhich.tests.cpp:: passed: ::Catch::Detail::stringify(disabled_range{}) == "{ !!! }" for: "{ !!! }" == "{ !!! }" +ToStringWhich.tests.cpp:: passed: ::Catch::Detail::stringify( item ) == "StringMaker" for: "StringMaker" +== +"StringMaker" +ToStringWhich.tests.cpp:: passed: ::Catch::Detail::stringify( item ) == "StringMaker" for: "StringMaker" +== +"StringMaker" +ToStringWhich.tests.cpp:: passed: ::Catch::Detail::stringify(item) == "{ !!! }" for: "{ !!! }" == "{ !!! }" +ToStringWhich.tests.cpp:: passed: ::Catch::Detail::stringify( item ) == "operator<<( has_operator )" for: "operator<<( has_operator )" +== +"operator<<( has_operator )" +ToStringWhich.tests.cpp:: passed: ::Catch::Detail::stringify( v ) == "{ StringMaker }" for: "{ StringMaker }" +== +"{ StringMaker }" +ToStringWhich.tests.cpp:: passed: ::Catch::Detail::stringify( v ) == "{ StringMaker }" for: "{ StringMaker }" +== +"{ StringMaker }" +ToStringWhich.tests.cpp:: passed: ::Catch::Detail::stringify( v ) == "{ operator<<( has_operator ) }" for: "{ operator<<( has_operator ) }" +== +"{ operator<<( has_operator ) }" +Exception.tests.cpp:: failed: unexpected exception with message: 'Why would you throw a std::string?' +Misc.tests.cpp:: passed: result == "/"wide load/"" for: ""wide load"" == ""wide load"" +Misc.tests.cpp:: passed: result == "/"wide load/"" for: ""wide load"" == ""wide load"" +Misc.tests.cpp:: passed: result == "/"wide load/"" for: ""wide load"" == ""wide load"" +Misc.tests.cpp:: passed: result == "/"wide load/"" for: ""wide load"" == ""wide load"" +EnumToString.tests.cpp:: passed: ::Catch::Detail::stringify(e0) == "E2/V0" for: "E2/V0" == "E2/V0" +EnumToString.tests.cpp:: passed: ::Catch::Detail::stringify(e1) == "E2/V1" for: "E2/V1" == "E2/V1" +EnumToString.tests.cpp:: passed: ::Catch::Detail::stringify(e3) == "Unknown enum value 10" for: "Unknown enum value 10" +== +"Unknown enum value 10" +EnumToString.tests.cpp:: passed: ::Catch::Detail::stringify(e0) == "0" for: "0" == "0" +EnumToString.tests.cpp:: passed: ::Catch::Detail::stringify(e1) == "1" for: "1" == "1" +EnumToString.tests.cpp:: passed: ::Catch::Detail::stringify(e0) == "E2{0}" for: "E2{0}" == "E2{0}" +EnumToString.tests.cpp:: passed: ::Catch::Detail::stringify(e1) == "E2{1}" for: "E2{1}" == "E2{1}" +EnumToString.tests.cpp:: passed: ::Catch::Detail::stringify(e0) == "0" for: "0" == "0" +EnumToString.tests.cpp:: passed: ::Catch::Detail::stringify(e1) == "1" for: "1" == "1" +ToStringTuple.tests.cpp:: passed: "{ }" == ::Catch::Detail::stringify(type{}) for: "{ }" == "{ }" +ToStringTuple.tests.cpp:: passed: "{ }" == ::Catch::Detail::stringify(value) for: "{ }" == "{ }" +ToStringTuple.tests.cpp:: passed: "1.2f" == ::Catch::Detail::stringify(float(1.2)) for: "1.2f" == "1.2f" +ToStringTuple.tests.cpp:: passed: "{ 1.2f, 0 }" == ::Catch::Detail::stringify(type{1.2f,0}) for: "{ 1.2f, 0 }" == "{ 1.2f, 0 }" +ToStringTuple.tests.cpp:: passed: "{ 0 }" == ::Catch::Detail::stringify(type{0}) for: "{ 0 }" == "{ 0 }" +ToStringTuple.tests.cpp:: passed: "{ 0, 42, /"Catch me/" }" == ::Catch::Detail::stringify(value) for: "{ 0, 42, "Catch me" }" +== +"{ 0, 42, "Catch me" }" +ToStringTuple.tests.cpp:: passed: "{ /"hello/", /"world/" }" == ::Catch::Detail::stringify(type{"hello","world"}) for: "{ "hello", "world" }" +== +"{ "hello", "world" }" +ToStringTuple.tests.cpp:: passed: "{ { 42 }, { }, 1.2f }" == ::Catch::Detail::stringify(value) for: "{ { 42 }, { }, 1.2f }" +== +"{ { 42 }, { }, 1.2f }" +ToStringVector.tests.cpp:: passed: ::Catch::Detail::stringify(v) == "{ }" for: "{ }" == "{ }" +ToStringVector.tests.cpp:: passed: ::Catch::Detail::stringify(v) == "{ { /"hello/" }, { /"world/" } }" for: "{ { "hello" }, { "world" } }" +== +"{ { "hello" }, { "world" } }" +ToStringVector.tests.cpp:: passed: ::Catch::Detail::stringify(bools) == "{ }" for: "{ }" == "{ }" +ToStringVector.tests.cpp:: passed: ::Catch::Detail::stringify(bools) == "{ true }" for: "{ true }" == "{ true }" +ToStringVector.tests.cpp:: passed: ::Catch::Detail::stringify(bools) == "{ true, false }" for: "{ true, false }" == "{ true, false }" +ToStringVector.tests.cpp:: passed: ::Catch::Detail::stringify(vv) == "{ }" for: "{ }" == "{ }" +ToStringVector.tests.cpp:: passed: ::Catch::Detail::stringify(vv) == "{ 42 }" for: "{ 42 }" == "{ 42 }" +ToStringVector.tests.cpp:: passed: ::Catch::Detail::stringify(vv) == "{ 42, 250 }" for: "{ 42, 250 }" == "{ 42, 250 }" +ToStringVector.tests.cpp:: passed: ::Catch::Detail::stringify(vv) == "{ }" for: "{ }" == "{ }" +ToStringVector.tests.cpp:: passed: ::Catch::Detail::stringify(vv) == "{ 42 }" for: "{ 42 }" == "{ 42 }" +ToStringVector.tests.cpp:: passed: ::Catch::Detail::stringify(vv) == "{ 42, 250 }" for: "{ 42, 250 }" == "{ 42, 250 }" +ToStringVector.tests.cpp:: passed: ::Catch::Detail::stringify(vv) == "{ }" for: "{ }" == "{ }" +ToStringVector.tests.cpp:: passed: ::Catch::Detail::stringify(vv) == "{ /"hello/" }" for: "{ "hello" }" == "{ "hello" }" +ToStringVector.tests.cpp:: passed: ::Catch::Detail::stringify(vv) == "{ /"hello/", /"world/" }" for: "{ "hello", "world" }" +== +"{ "hello", "world" }" +Misc.tests.cpp:: passed: v.size() == 5 for: 5 == 5 +Misc.tests.cpp:: passed: v.capacity() >= 5 for: 5 >= 5 +Misc.tests.cpp:: passed: v.size() == 10 for: 10 == 10 +Misc.tests.cpp:: passed: v.capacity() >= 10 for: 10 >= 10 +Misc.tests.cpp:: passed: v.size() == 5 for: 5 == 5 +Misc.tests.cpp:: passed: v.capacity() >= 5 for: 5 >= 5 +Misc.tests.cpp:: passed: v.size() == 0 for: 0 == 0 +Misc.tests.cpp:: passed: v.capacity() >= 5 for: 5 >= 5 +Misc.tests.cpp:: passed: v.capacity() == 0 for: 0 == 0 +Misc.tests.cpp:: passed: v.size() == 5 for: 5 == 5 +Misc.tests.cpp:: passed: v.capacity() >= 5 for: 5 >= 5 +Misc.tests.cpp:: passed: v.size() == 5 for: 5 == 5 +Misc.tests.cpp:: passed: v.capacity() >= 10 for: 10 >= 10 +Misc.tests.cpp:: passed: v.size() == 5 for: 5 == 5 +Misc.tests.cpp:: passed: v.capacity() >= 5 for: 5 >= 5 +Misc.tests.cpp:: passed: v.size() == 5 for: 5 == 5 +Misc.tests.cpp:: passed: v.capacity() >= 5 for: 5 >= 5 +Misc.tests.cpp:: passed: +Misc.tests.cpp:: passed: +Failed 62 test cases, failed 121 assertions. + diff --git a/Telegram/ThirdParty/Catch/projects/SelfTest/Baselines/console.std.approved.txt b/Telegram/ThirdParty/Catch/projects/SelfTest/Baselines/console.std.approved.txt index 13846d4c3..5091ff1d7 100644 --- a/Telegram/ThirdParty/Catch/projects/SelfTest/Baselines/console.std.approved.txt +++ b/Telegram/ThirdParty/Catch/projects/SelfTest/Baselines/console.std.approved.txt @@ -700,6 +700,7 @@ with expansion: A string sent directly to stdout A string sent directly to stderr +A string sent to stderr via clog Message from section one Message from section two ------------------------------------------------------------------------------- @@ -737,6 +738,16 @@ with expansion: } " +------------------------------------------------------------------------------- +Thrown string literals are translated +------------------------------------------------------------------------------- +Exception.tests.cpp: +............................................................................... + +Exception.tests.cpp:: FAILED: +due to unexpected exception with message: + For some reason someone is throwing a string literal! + ------------------------------------------------------------------------------- Unexpected exceptions can be translated ------------------------------------------------------------------------------- @@ -808,6 +819,33 @@ Matchers.tests.cpp:: FAILED: with expansion: { 1, 2, 3 } Equals: { } +------------------------------------------------------------------------------- +Vector matchers that fail + UnorderedEquals +------------------------------------------------------------------------------- +Matchers.tests.cpp: +............................................................................... + +Matchers.tests.cpp:: FAILED: + CHECK_THAT( v, UnorderedEquals(empty) ) +with expansion: + { 1, 2, 3 } UnorderedEquals: { } + +Matchers.tests.cpp:: FAILED: + CHECK_THAT( empty, UnorderedEquals(v) ) +with expansion: + { } UnorderedEquals: { 1, 2, 3 } + +Matchers.tests.cpp:: FAILED: + CHECK_THAT( permuted, UnorderedEquals(v) ) +with expansion: + { 1, 3 } UnorderedEquals: { 1, 2, 3 } + +Matchers.tests.cpp:: FAILED: + CHECK_THAT( permuted, UnorderedEquals(v) ) +with expansion: + { 3, 1 } UnorderedEquals: { 1, 2, 3 } + ------------------------------------------------------------------------------- When unchecked exceptions are thrown directly they are always failures ------------------------------------------------------------------------------- @@ -1036,22 +1074,16 @@ with expansion: "first" == "second" ------------------------------------------------------------------------------- -toString(enum class) +thrown std::strings are translated ------------------------------------------------------------------------------- -EnumToString.tests.cpp: +Exception.tests.cpp: ............................................................................... -EnumToString.tests.cpp:: FAILED: - CHECK( ::Catch::Detail::stringify(e0) == "0" ) -with expansion: - "{?}" == "0" - -EnumToString.tests.cpp:: FAILED: - CHECK( ::Catch::Detail::stringify(e1) == "1" ) -with expansion: - "{?}" == "1" +Exception.tests.cpp:: FAILED: +due to unexpected exception with message: + Why would you throw a std::string? =============================================================================== -test cases: 189 | 137 passed | 48 failed | 4 failed as expected -assertions: 952 | 828 passed | 103 failed | 21 failed as expected +test cases: 202 | 149 passed | 49 failed | 4 failed as expected +assertions: 1007 | 879 passed | 107 failed | 21 failed as expected diff --git a/Telegram/ThirdParty/Catch/projects/SelfTest/Baselines/console.sw.approved.txt b/Telegram/ThirdParty/Catch/projects/SelfTest/Baselines/console.sw.approved.txt index 6eac35ed3..70bff4a8e 100644 --- a/Telegram/ThirdParty/Catch/projects/SelfTest/Baselines/console.sw.approved.txt +++ b/Telegram/ThirdParty/Catch/projects/SelfTest/Baselines/console.sw.approved.txt @@ -51,6 +51,57 @@ PASSED: with expansion: 0 == 0 +------------------------------------------------------------------------------- +#1147 +------------------------------------------------------------------------------- +Compilation.tests.cpp: +............................................................................... + +Compilation.tests.cpp:: +PASSED: + REQUIRE( t1 == t2 ) +with expansion: + {?} == {?} + +Compilation.tests.cpp:: +PASSED: + REQUIRE( t1 != t2 ) +with expansion: + {?} != {?} + +Compilation.tests.cpp:: +PASSED: + REQUIRE( t1 < t2 ) +with expansion: + {?} < {?} + +Compilation.tests.cpp:: +PASSED: + REQUIRE( t1 > t2 ) +with expansion: + {?} > {?} + +Compilation.tests.cpp:: +PASSED: + REQUIRE( t1 <= t2 ) +with expansion: + {?} <= {?} + +Compilation.tests.cpp:: +PASSED: + REQUIRE( t1 >= t2 ) +with expansion: + {?} >= {?} + +------------------------------------------------------------------------------- +#1175 - Hidden Test +------------------------------------------------------------------------------- +Misc.tests.cpp: +............................................................................... + +Misc.tests.cpp:: +PASSED: + ------------------------------------------------------------------------------- #748 - captures with unexpected exceptions outside assertions @@ -532,6 +583,15 @@ PASSED: with expansion: 100.3 == Approx( 100.0 ) +------------------------------------------------------------------------------- +An empty test with no assertions +------------------------------------------------------------------------------- +Misc.tests.cpp: +............................................................................... + + +No assertions in test case 'An empty test with no assertions' + ------------------------------------------------------------------------------- An expression with side-effects should only be evaluated once ------------------------------------------------------------------------------- @@ -762,9 +822,7 @@ Tricky.tests.cpp: Tricky.tests.cpp:: PASSED: - REQUIRE( Catch::alwaysTrue() ) -with expansion: - true + REQUIRE( true ) ------------------------------------------------------------------------------- Assertions then sections @@ -775,9 +833,7 @@ Tricky.tests.cpp: Tricky.tests.cpp:: PASSED: - REQUIRE( Catch::alwaysTrue() ) -with expansion: - true + REQUIRE( true ) ------------------------------------------------------------------------------- Assertions then sections @@ -789,9 +845,7 @@ Tricky.tests.cpp: Tricky.tests.cpp:: PASSED: - REQUIRE( Catch::alwaysTrue() ) -with expansion: - true + REQUIRE( true ) ------------------------------------------------------------------------------- Assertions then sections @@ -801,9 +855,7 @@ Tricky.tests.cpp: Tricky.tests.cpp:: PASSED: - REQUIRE( Catch::alwaysTrue() ) -with expansion: - true + REQUIRE( true ) ------------------------------------------------------------------------------- Assertions then sections @@ -814,9 +866,7 @@ Tricky.tests.cpp: Tricky.tests.cpp:: PASSED: - REQUIRE( Catch::alwaysTrue() ) -with expansion: - true + REQUIRE( true ) ------------------------------------------------------------------------------- Assertions then sections @@ -828,9 +878,7 @@ Tricky.tests.cpp: Tricky.tests.cpp:: PASSED: - REQUIRE( Catch::alwaysTrue() ) -with expansion: - true + REQUIRE( true ) ------------------------------------------------------------------------------- Assorted miscellaneous tests @@ -1153,13 +1201,13 @@ with expansion: Approx.tests.cpp:: PASSED: - REQUIRE( td >= Approx(10.0) ) + REQUIRE( td >= Approx(td) ) with expansion: StrongDoubleTypedef(10) >= Approx( 10.0 ) Approx.tests.cpp:: PASSED: - REQUIRE( Approx(10.0) >= td ) + REQUIRE( Approx(td) >= td ) with expansion: Approx( 10.0 ) >= StrongDoubleTypedef(10) @@ -1825,19 +1873,19 @@ with expansion: Matchers.tests.cpp:: PASSED: - REQUIRE_THAT( std::nextafter(1., 2.), WithinULP(1., 1) ) + REQUIRE_THAT( nextafter(1., 2.), WithinULP(1., 1) ) with expansion: 1.0 is within 1 ULPs of 1.0 Matchers.tests.cpp:: PASSED: - REQUIRE_THAT( std::nextafter(1., 0.), WithinULP(1., 1) ) + REQUIRE_THAT( nextafter(1., 0.), WithinULP(1., 1) ) with expansion: 1.0 is within 1 ULPs of 1.0 Matchers.tests.cpp:: PASSED: - REQUIRE_THAT( std::nextafter(1., 2.), !WithinULP(1., 0) ) + REQUIRE_THAT( nextafter(1., 2.), !WithinULP(1., 0) ) with expansion: 1.0 not is within 0 ULPs of 1.0 @@ -1884,6 +1932,29 @@ PASSED: with expansion: nanf not ( is within 100.0 of nan or is within 123 ULPs of nanf ) +------------------------------------------------------------------------------- +Floating point matchers: double + Constructor validation +------------------------------------------------------------------------------- +Matchers.tests.cpp: +............................................................................... + +Matchers.tests.cpp:: +PASSED: + REQUIRE_NOTHROW( WithinAbs(1., 0.) ) + +Matchers.tests.cpp:: +PASSED: + REQUIRE_THROWS_AS( WithinAbs(1., -1.), std::domain_error ) + +Matchers.tests.cpp:: +PASSED: + REQUIRE_NOTHROW( WithinULP(1., 0) ) + +Matchers.tests.cpp:: +PASSED: + REQUIRE_THROWS_AS( WithinULP(1., -1), std::domain_error ) + ------------------------------------------------------------------------------- Floating point matchers: float Margin @@ -1942,19 +2013,19 @@ with expansion: Matchers.tests.cpp:: PASSED: - REQUIRE_THAT( std::nextafter(1.f, 2.f), WithinULP(1.f, 1) ) + REQUIRE_THAT( nextafter(1.f, 2.f), WithinULP(1.f, 1) ) with expansion: 1.0f is within 1 ULPs of 1.0f Matchers.tests.cpp:: PASSED: - REQUIRE_THAT( std::nextafter(1.f, 0.f), WithinULP(1.f, 1) ) + REQUIRE_THAT( nextafter(1.f, 0.f), WithinULP(1.f, 1) ) with expansion: 1.0f is within 1 ULPs of 1.0f Matchers.tests.cpp:: PASSED: - REQUIRE_THAT( std::nextafter(1.f, 2.f), !WithinULP(1.f, 0) ) + REQUIRE_THAT( nextafter(1.f, 2.f), !WithinULP(1.f, 0) ) with expansion: 1.0f not is within 0 ULPs of 1.0f @@ -2001,6 +2072,29 @@ PASSED: with expansion: nanf not ( is within 100.0 of nan or is within 123 ULPs of nanf ) +------------------------------------------------------------------------------- +Floating point matchers: float + Constructor validation +------------------------------------------------------------------------------- +Matchers.tests.cpp: +............................................................................... + +Matchers.tests.cpp:: +PASSED: + REQUIRE_NOTHROW( WithinAbs(1.f, 0.f) ) + +Matchers.tests.cpp:: +PASSED: + REQUIRE_THROWS_AS( WithinAbs(1.f, -1.f), std::domain_error ) + +Matchers.tests.cpp:: +PASSED: + REQUIRE_NOTHROW( WithinULP(1.f, 0) ) + +Matchers.tests.cpp:: +PASSED: + REQUIRE_THROWS_AS( WithinULP(1.f, -1), std::domain_error ) + ------------------------------------------------------------------------------- Greater-than inequalities with different epsilons ------------------------------------------------------------------------------- @@ -2042,6 +2136,9 @@ warning: this is a message this is a warning + +No assertions in test case 'INFO and WARN do not abort tests' + ------------------------------------------------------------------------------- INFO gets logged on failure ------------------------------------------------------------------------------- @@ -2454,6 +2551,9 @@ Misc.tests.cpp:: warning: This one ran + +No assertions in test case 'Nice descriptive name' + ------------------------------------------------------------------------------- Non-std exceptions can be translated ------------------------------------------------------------------------------- @@ -3874,6 +3974,12 @@ PASSED: with expansion: true +CmdLine.tests.cpp:: +PASSED: + CHECK_FALSE( cfg.hasTestFilters() ) +with expansion: + !false + ------------------------------------------------------------------------------- Process can be configured on command line test lists @@ -3888,6 +3994,12 @@ PASSED: with expansion: {?} +CmdLine.tests.cpp:: +PASSED: + REQUIRE( cfg.hasTestFilters() ) +with expansion: + true + CmdLine.tests.cpp:: PASSED: REQUIRE( cfg.testSpec().matches(fakeTestCase("notIncluded")) == false ) @@ -3914,6 +4026,12 @@ PASSED: with expansion: {?} +CmdLine.tests.cpp:: +PASSED: + REQUIRE( cfg.hasTestFilters() ) +with expansion: + true + CmdLine.tests.cpp:: PASSED: REQUIRE( cfg.testSpec().matches(fakeTestCase("test1")) == false ) @@ -3940,6 +4058,12 @@ PASSED: with expansion: {?} +CmdLine.tests.cpp:: +PASSED: + REQUIRE( cfg.hasTestFilters() ) +with expansion: + true + CmdLine.tests.cpp:: PASSED: REQUIRE( cfg.testSpec().matches(fakeTestCase("test1")) == false ) @@ -4405,7 +4529,7 @@ with message: this is a success ------------------------------------------------------------------------------- -SUCCESS does not require an argument +SUCCEED does not require an argument ------------------------------------------------------------------------------- Message.tests.cpp: ............................................................................... @@ -4585,6 +4709,16 @@ with expansion: A string sent directly to stdout A string sent directly to stderr +A string sent to stderr via clog +------------------------------------------------------------------------------- +Sends stuff to stdout and stderr +------------------------------------------------------------------------------- +Misc.tests.cpp: +............................................................................... + + +No assertions in test case 'Sends stuff to stdout and stderr' + ------------------------------------------------------------------------------- Some simple comparisons between doubles ------------------------------------------------------------------------------- @@ -4672,6 +4806,47 @@ with expansion: "this string contains 'abc' as a substring" starts with: "string" (case insensitive) +------------------------------------------------------------------------------- +Static arrays are convertible to string + Single item +------------------------------------------------------------------------------- +ToStringGeneral.tests.cpp: +............................................................................... + +ToStringGeneral.tests.cpp:: +PASSED: + REQUIRE( Catch::Detail::stringify(singular) == "{ 1 }" ) +with expansion: + "{ 1 }" == "{ 1 }" + +------------------------------------------------------------------------------- +Static arrays are convertible to string + Multiple +------------------------------------------------------------------------------- +ToStringGeneral.tests.cpp: +............................................................................... + +ToStringGeneral.tests.cpp:: +PASSED: + REQUIRE( Catch::Detail::stringify(arr) == "{ 3, 2, 1 }" ) +with expansion: + "{ 3, 2, 1 }" == "{ 3, 2, 1 }" + +------------------------------------------------------------------------------- +Static arrays are convertible to string + Non-trivial inner items +------------------------------------------------------------------------------- +ToStringGeneral.tests.cpp: +............................................................................... + +ToStringGeneral.tests.cpp:: +PASSED: + REQUIRE( Catch::Detail::stringify(arr) == R"({ { "1:1", "1:2", "1:3" }, { "2:1", "2:2" } })" ) +with expansion: + "{ { "1:1", "1:2", "1:3" }, { "2:1", "2:2" } }" + == + "{ { "1:1", "1:2", "1:3" }, { "2:1", "2:2" } }" + ------------------------------------------------------------------------------- String matchers ------------------------------------------------------------------------------- @@ -4823,10 +4998,29 @@ String.tests.cpp:: PASSED: REQUIRE( original == "original" ) -String.tests.cpp:: FAILED: +String.tests.cpp:: +PASSED: REQUIRE( isSubstring( original ) ) with expansion: - false + true + +String.tests.cpp:: +PASSED: + REQUIRE( isOwned( original ) == false ) +with expansion: + false == false + +String.tests.cpp:: +PASSED: + REQUIRE( isSubstring( original ) == false ) +with expansion: + false == false + +String.tests.cpp:: +PASSED: + REQUIRE( isOwned( original ) ) +with expansion: + true ------------------------------------------------------------------------------- StringRef @@ -4882,7 +5076,7 @@ with expansion: String.tests.cpp:: PASSED: - REQUIRE( rawChars == data( s ) ) + REQUIRE( rawChars == s.currentData() ) with expansion: "hello world!" == "hello world!" @@ -4906,7 +5100,7 @@ with expansion: String.tests.cpp:: PASSED: - REQUIRE( data( ss ) != data( s ) ) + REQUIRE( ss.currentData() != s.currentData() ) with expansion: "hello" != "hello world!" @@ -5097,6 +5291,31 @@ PASSED: with expansion: 11 == 11 +------------------------------------------------------------------------------- +StringRef + Counting utf-8 codepoints +------------------------------------------------------------------------------- +String.tests.cpp: +............................................................................... + +String.tests.cpp:: +PASSED: + REQUIRE( ascii.numberOfCharacters() == ascii.size() ) +with expansion: + 39 == 39 + +String.tests.cpp:: +PASSED: + REQUIRE( simpleu8.numberOfCharacters() == 30 ) +with expansion: + 30 == 30 + +String.tests.cpp:: +PASSED: + REQUIRE( emojis.numberOfCharacters() == 9 ) +with expansion: + 9 == 9 + ------------------------------------------------------------------------------- Stringifying std::chrono::duration helpers ------------------------------------------------------------------------------- @@ -5139,6 +5358,12 @@ PASSED: with expansion: 1 [30/1]s != 1 fs +ToStringChrono.tests.cpp:: +PASSED: + REQUIRE( pico_second != atto_second ) +with expansion: + 1 ps != 1 as + ------------------------------------------------------------------------------- Stringifying std::chrono::time_point ------------------------------------------------------------------------------- @@ -5266,6 +5491,9 @@ Message.tests.cpp:: FAILED - but was ok: CHECK_NOFAIL( 1 == 2 ) + +No assertions in test case 'The NO_FAIL macro reports a failure but does not fail the test' + ------------------------------------------------------------------------------- This test 'should' fail but doesn't ------------------------------------------------------------------------------- @@ -5277,6 +5505,16 @@ PASSED: with message: oops! +------------------------------------------------------------------------------- +Thrown string literals are translated +------------------------------------------------------------------------------- +Exception.tests.cpp: +............................................................................... + +Exception.tests.cpp:: FAILED: +due to unexpected exception with message: + For some reason someone is throwing a string literal! + ------------------------------------------------------------------------------- Tracker ------------------------------------------------------------------------------- @@ -6439,6 +6677,37 @@ PASSED: with expansion: { 1, 2, 3 } Equals: { 1, 2, 3 } +------------------------------------------------------------------------------- +Vector matchers + UnorderedEquals +------------------------------------------------------------------------------- +Matchers.tests.cpp: +............................................................................... + +Matchers.tests.cpp:: +PASSED: + CHECK_THAT( v, UnorderedEquals(v) ) +with expansion: + { 1, 2, 3 } UnorderedEquals: { 1, 2, 3 } + +Matchers.tests.cpp:: +PASSED: + CHECK_THAT( empty, UnorderedEquals(empty) ) +with expansion: + { } UnorderedEquals: { } + +Matchers.tests.cpp:: +PASSED: + REQUIRE_THAT( permuted, UnorderedEquals(v) ) +with expansion: + { 1, 3, 2 } UnorderedEquals: { 1, 2, 3 } + +Matchers.tests.cpp:: +PASSED: + REQUIRE_THAT( permuted, UnorderedEquals(v) ) +with expansion: + { 2, 3, 1 } UnorderedEquals: { 1, 2, 3 } + ------------------------------------------------------------------------------- Vector matchers that fail Contains (element) @@ -6500,6 +6769,33 @@ Matchers.tests.cpp:: FAILED: with expansion: { 1, 2, 3 } Equals: { } +------------------------------------------------------------------------------- +Vector matchers that fail + UnorderedEquals +------------------------------------------------------------------------------- +Matchers.tests.cpp: +............................................................................... + +Matchers.tests.cpp:: FAILED: + CHECK_THAT( v, UnorderedEquals(empty) ) +with expansion: + { 1, 2, 3 } UnorderedEquals: { } + +Matchers.tests.cpp:: FAILED: + CHECK_THAT( empty, UnorderedEquals(v) ) +with expansion: + { } UnorderedEquals: { 1, 2, 3 } + +Matchers.tests.cpp:: FAILED: + CHECK_THAT( permuted, UnorderedEquals(v) ) +with expansion: + { 1, 3 } UnorderedEquals: { 1, 2, 3 } + +Matchers.tests.cpp:: FAILED: + CHECK_THAT( permuted, UnorderedEquals(v) ) +with expansion: + { 3, 1 } UnorderedEquals: { 1, 2, 3 } + ------------------------------------------------------------------------------- When checked exceptions are thrown they can be expected or unexpected ------------------------------------------------------------------------------- @@ -6573,6 +6869,15 @@ Exception.tests.cpp:: FAILED: due to unexpected exception with message: unexpected exception +------------------------------------------------------------------------------- +When unchecked exceptions are thrown, but caught, they do not affect the test +------------------------------------------------------------------------------- +Exception.tests.cpp: +............................................................................... + + +No assertions in test case 'When unchecked exceptions are thrown, but caught, they do not affect the test' + ------------------------------------------------------------------------------- Where the LHS is not a simple value ------------------------------------------------------------------------------- @@ -6584,6 +6889,9 @@ warning: Uncomment the code in this test to check that it gives a sensible compiler error + +No assertions in test case 'Where the LHS is not a simple value' + ------------------------------------------------------------------------------- Where there is more to the expression after the RHS ------------------------------------------------------------------------------- @@ -6595,6 +6903,9 @@ warning: Uncomment the code in this test to check that it gives a sensible compiler error + +No assertions in test case 'Where there is more to the expression after the RHS' + ------------------------------------------------------------------------------- X/level/0/a ------------------------------------------------------------------------------- @@ -6753,6 +7064,30 @@ PASSED: with expansion: "[\x7F]" == "[\x7F]" +------------------------------------------------------------------------------- +array -> toString +------------------------------------------------------------------------------- +ToStringVector.tests.cpp: +............................................................................... + +ToStringVector.tests.cpp:: +PASSED: + REQUIRE( Catch::Detail::stringify( empty ) == "{ }" ) +with expansion: + "{ }" == "{ }" + +ToStringVector.tests.cpp:: +PASSED: + REQUIRE( Catch::Detail::stringify( oneValue ) == "{ 42 }" ) +with expansion: + "{ 42 }" == "{ 42 }" + +ToStringVector.tests.cpp:: +PASSED: + REQUIRE( Catch::Detail::stringify( twoValues ) == "{ 42, 250 }" ) +with expansion: + "{ 42, 250 }" == "{ 42, 250 }" + ------------------------------------------------------------------------------- atomic if ------------------------------------------------------------------------------- @@ -6937,7 +7272,25 @@ Misc.tests.cpp: Misc.tests.cpp:: PASSED: +------------------------------------------------------------------------------- +first tag +------------------------------------------------------------------------------- +Misc.tests.cpp: +............................................................................... + + +No assertions in test case 'first tag' + loose text artifact +------------------------------------------------------------------------------- +has printf +------------------------------------------------------------------------------- +Tricky.tests.cpp: +............................................................................... + + +No assertions in test case 'has printf' + ------------------------------------------------------------------------------- just failure ------------------------------------------------------------------------------- @@ -6948,6 +7301,15 @@ Message.tests.cpp:: FAILED: explicitly with message: Previous info should not be seen +------------------------------------------------------------------------------- +just info +------------------------------------------------------------------------------- +Message.tests.cpp: +............................................................................... + + +No assertions in test case 'just info' + ------------------------------------------------------------------------------- long long ------------------------------------------------------------------------------- @@ -7366,6 +7728,15 @@ PASSED: with expansion: "didn|'t" == "didn|'t" +------------------------------------------------------------------------------- +second tag +------------------------------------------------------------------------------- +Misc.tests.cpp: +............................................................................... + + +No assertions in test case 'second tag' + ------------------------------------------------------------------------------- send a single char to INFO ------------------------------------------------------------------------------- @@ -7389,6 +7760,47 @@ with messages: hi i := 7 +------------------------------------------------------------------------------- +std::map is convertible string + empty +------------------------------------------------------------------------------- +ToStringGeneral.tests.cpp: +............................................................................... + +ToStringGeneral.tests.cpp:: +PASSED: + REQUIRE( Catch::Detail::stringify( emptyMap ) == "{ }" ) +with expansion: + "{ }" == "{ }" + +------------------------------------------------------------------------------- +std::map is convertible string + single item +------------------------------------------------------------------------------- +ToStringGeneral.tests.cpp: +............................................................................... + +ToStringGeneral.tests.cpp:: +PASSED: + REQUIRE( Catch::Detail::stringify( map ) == "{ { \"one\", 1 } }" ) +with expansion: + "{ { "one", 1 } }" == "{ { "one", 1 } }" + +------------------------------------------------------------------------------- +std::map is convertible string + several items +------------------------------------------------------------------------------- +ToStringGeneral.tests.cpp: +............................................................................... + +ToStringGeneral.tests.cpp:: +PASSED: + REQUIRE( Catch::Detail::stringify( map ) == "{ { \"abc\", 1 }, { \"def\", 2 }, { \"ghi\", 3 } }" ) +with expansion: + "{ { "abc", 1 }, { "def", 2 }, { "ghi", 3 } }" + == + "{ { "abc", 1 }, { "def", 2 }, { "ghi", 3 } }" + ------------------------------------------------------------------------------- std::pair -> toString ------------------------------------------------------------------------------- @@ -7413,6 +7825,47 @@ PASSED: with expansion: "{ 34, "xyzzy" }" == "{ 34, "xyzzy" }" +------------------------------------------------------------------------------- +std::set is convertible string + empty +------------------------------------------------------------------------------- +ToStringGeneral.tests.cpp: +............................................................................... + +ToStringGeneral.tests.cpp:: +PASSED: + REQUIRE( Catch::Detail::stringify( emptySet ) == "{ }" ) +with expansion: + "{ }" == "{ }" + +------------------------------------------------------------------------------- +std::set is convertible string + single item +------------------------------------------------------------------------------- +ToStringGeneral.tests.cpp: +............................................................................... + +ToStringGeneral.tests.cpp:: +PASSED: + REQUIRE( Catch::Detail::stringify( set ) == "{ \"one\" }" ) +with expansion: + "{ "one" }" == "{ "one" }" + +------------------------------------------------------------------------------- +std::set is convertible string + several items +------------------------------------------------------------------------------- +ToStringGeneral.tests.cpp: +............................................................................... + +ToStringGeneral.tests.cpp:: +PASSED: + REQUIRE( Catch::Detail::stringify( set ) == "{ \"abc\", \"def\", \"ghi\" }" ) +with expansion: + "{ "abc", "def", "ghi" }" + == + "{ "abc", "def", "ghi" }" + ------------------------------------------------------------------------------- std::vector > -> toString ------------------------------------------------------------------------------- @@ -7438,6 +7891,40 @@ Tricky.tests.cpp:: FAILED: with expansion: "first" == "second" +------------------------------------------------------------------------------- +stringify ranges +------------------------------------------------------------------------------- +ToStringWhich.tests.cpp: +............................................................................... + +ToStringWhich.tests.cpp:: +PASSED: + REQUIRE( ::Catch::Detail::stringify(streamable_range{}) == "op<<(streamable_range)" ) +with expansion: + "op<<(streamable_range)" + == + "op<<(streamable_range)" + +ToStringWhich.tests.cpp:: +PASSED: + REQUIRE( ::Catch::Detail::stringify(stringmaker_range{}) == "stringmaker(streamable_range)" ) +with expansion: + "stringmaker(streamable_range)" + == + "stringmaker(streamable_range)" + +ToStringWhich.tests.cpp:: +PASSED: + REQUIRE( ::Catch::Detail::stringify(just_range{}) == "{ 1, 2, 3, 4 }" ) +with expansion: + "{ 1, 2, 3, 4 }" == "{ 1, 2, 3, 4 }" + +ToStringWhich.tests.cpp:: +PASSED: + REQUIRE( ::Catch::Detail::stringify(disabled_range{}) == "{ !!! }" ) +with expansion: + "{ !!! }" == "{ !!! }" + ------------------------------------------------------------------------------- stringify( has_maker ) ------------------------------------------------------------------------------- @@ -7453,7 +7940,7 @@ with expansion: "StringMaker" ------------------------------------------------------------------------------- -stringify( has_maker_and_toString ) +stringify( has_maker_and_operator ) ------------------------------------------------------------------------------- ToStringWhich.tests.cpp: ............................................................................... @@ -7466,6 +7953,18 @@ with expansion: == "StringMaker" +------------------------------------------------------------------------------- +stringify( has_neither ) +------------------------------------------------------------------------------- +ToStringWhich.tests.cpp: +............................................................................... + +ToStringWhich.tests.cpp:: +PASSED: + REQUIRE( ::Catch::Detail::stringify(item) == "{ !!! }" ) +with expansion: + "{ !!! }" == "{ !!! }" + ------------------------------------------------------------------------------- stringify( has_operator ) ------------------------------------------------------------------------------- @@ -7480,6 +7979,58 @@ with expansion: == "operator<<( has_operator )" +------------------------------------------------------------------------------- +stringify( vectors ) +------------------------------------------------------------------------------- +ToStringWhich.tests.cpp: +............................................................................... + +ToStringWhich.tests.cpp:: +PASSED: + REQUIRE( ::Catch::Detail::stringify( v ) == "{ StringMaker }" ) +with expansion: + "{ StringMaker }" + == + "{ StringMaker }" + +------------------------------------------------------------------------------- +stringify( vectors ) +------------------------------------------------------------------------------- +ToStringWhich.tests.cpp: +............................................................................... + +ToStringWhich.tests.cpp:: +PASSED: + REQUIRE( ::Catch::Detail::stringify( v ) == "{ StringMaker }" ) +with expansion: + "{ StringMaker }" + == + "{ StringMaker }" + +------------------------------------------------------------------------------- +stringify( vectors ) +------------------------------------------------------------------------------- +ToStringWhich.tests.cpp: +............................................................................... + +ToStringWhich.tests.cpp:: +PASSED: + REQUIRE( ::Catch::Detail::stringify( v ) == "{ operator<<( has_operator ) }" ) +with expansion: + "{ operator<<( has_operator ) }" + == + "{ operator<<( has_operator ) }" + +------------------------------------------------------------------------------- +thrown std::strings are translated +------------------------------------------------------------------------------- +Exception.tests.cpp: +............................................................................... + +Exception.tests.cpp:: FAILED: +due to unexpected exception with message: + Why would you throw a std::string? + ------------------------------------------------------------------------------- toString on const wchar_t const pointer returns the string contents ------------------------------------------------------------------------------- @@ -7528,20 +8079,6 @@ PASSED: with expansion: ""wide load"" == ""wide load"" -------------------------------------------------------------------------------- -toString( vectors -............................................................................... - -ToStringWhich.tests.cpp:: -PASSED: - REQUIRE( ::Catch::Detail::stringify( v ) == "{ StringMaker }" ) -with expansion: - "{ StringMaker }" - == - "{ StringMaker }" - ------------------------------------------------------------------------------- toString(enum class w/operator<<) ------------------------------------------------------------------------------- @@ -7574,15 +8111,17 @@ toString(enum class) EnumToString.tests.cpp: ............................................................................... -EnumToString.tests.cpp:: FAILED: +EnumToString.tests.cpp:: +PASSED: CHECK( ::Catch::Detail::stringify(e0) == "0" ) with expansion: - "{?}" == "0" + "0" == "0" -EnumToString.tests.cpp:: FAILED: +EnumToString.tests.cpp:: +PASSED: CHECK( ::Catch::Detail::stringify(e1) == "1" ) with expansion: - "{?}" == "1" + "1" == "1" ------------------------------------------------------------------------------- toString(enum w/operator<<) @@ -7730,6 +8269,30 @@ with expansion: == "{ { "hello" }, { "world" } }" +------------------------------------------------------------------------------- +vector -> toString +------------------------------------------------------------------------------- +ToStringVector.tests.cpp: +............................................................................... + +ToStringVector.tests.cpp:: +PASSED: + REQUIRE( ::Catch::Detail::stringify(bools) == "{ }" ) +with expansion: + "{ }" == "{ }" + +ToStringVector.tests.cpp:: +PASSED: + REQUIRE( ::Catch::Detail::stringify(bools) == "{ true }" ) +with expansion: + "{ true }" == "{ true }" + +ToStringVector.tests.cpp:: +PASSED: + REQUIRE( ::Catch::Detail::stringify(bools) == "{ true, false }" ) +with expansion: + "{ true, false }" == "{ true, false }" + ------------------------------------------------------------------------------- vector -> toString ------------------------------------------------------------------------------- @@ -7987,6 +8550,6 @@ Misc.tests.cpp:: PASSED: =============================================================================== -test cases: 189 | 135 passed | 50 failed | 4 failed as expected -assertions: 951 | 824 passed | 106 failed | 21 failed as expected +test cases: 202 | 136 passed | 62 failed | 4 failed as expected +assertions: 1021 | 879 passed | 121 failed | 21 failed as expected diff --git a/Telegram/ThirdParty/Catch/projects/SelfTest/Baselines/console.swa4.approved.txt b/Telegram/ThirdParty/Catch/projects/SelfTest/Baselines/console.swa4.approved.txt index 19c6e5c12..9b41d3980 100644 --- a/Telegram/ThirdParty/Catch/projects/SelfTest/Baselines/console.swa4.approved.txt +++ b/Telegram/ThirdParty/Catch/projects/SelfTest/Baselines/console.swa4.approved.txt @@ -51,6 +51,57 @@ PASSED: with expansion: 0 == 0 +------------------------------------------------------------------------------- +#1147 +------------------------------------------------------------------------------- +Compilation.tests.cpp: +............................................................................... + +Compilation.tests.cpp:: +PASSED: + REQUIRE( t1 == t2 ) +with expansion: + {?} == {?} + +Compilation.tests.cpp:: +PASSED: + REQUIRE( t1 != t2 ) +with expansion: + {?} != {?} + +Compilation.tests.cpp:: +PASSED: + REQUIRE( t1 < t2 ) +with expansion: + {?} < {?} + +Compilation.tests.cpp:: +PASSED: + REQUIRE( t1 > t2 ) +with expansion: + {?} > {?} + +Compilation.tests.cpp:: +PASSED: + REQUIRE( t1 <= t2 ) +with expansion: + {?} <= {?} + +Compilation.tests.cpp:: +PASSED: + REQUIRE( t1 >= t2 ) +with expansion: + {?} >= {?} + +------------------------------------------------------------------------------- +#1175 - Hidden Test +------------------------------------------------------------------------------- +Misc.tests.cpp: +............................................................................... + +Misc.tests.cpp:: +PASSED: + ------------------------------------------------------------------------------- #748 - captures with unexpected exceptions outside assertions @@ -257,6 +308,6 @@ with expansion: !true =============================================================================== -test cases: 10 | 7 passed | 1 failed | 2 failed as expected -assertions: 28 | 21 passed | 4 failed | 3 failed as expected +test cases: 12 | 9 passed | 1 failed | 2 failed as expected +assertions: 35 | 28 passed | 4 failed | 3 failed as expected diff --git a/Telegram/ThirdParty/Catch/projects/SelfTest/Baselines/junit.sw.approved.txt b/Telegram/ThirdParty/Catch/projects/SelfTest/Baselines/junit.sw.approved.txt index 610e3f8e9..895e41f99 100644 --- a/Telegram/ThirdParty/Catch/projects/SelfTest/Baselines/junit.sw.approved.txt +++ b/Telegram/ThirdParty/Catch/projects/SelfTest/Baselines/junit.sw.approved.txt @@ -1,10 +1,12 @@ - + + + expected exception @@ -276,9 +278,11 @@ Message.tests.cpp: + + @@ -501,7 +505,7 @@ Matchers.tests.cpp: - + @@ -517,6 +521,7 @@ A string sent directly to stdout A string sent directly to stderr +A string sent to stderr via clog @@ -534,15 +539,14 @@ Matchers.tests.cpp: Matchers.tests.cpp: + + + - - -String.tests.cpp: - - + @@ -555,6 +559,7 @@ String.tests.cpp: + @@ -576,6 +581,12 @@ Misc.tests.cpp: + + +For some reason someone is throwing a string literal! +Exception.tests.cpp: + + @@ -605,6 +616,7 @@ Exception.tests.cpp: + Matchers.tests.cpp: @@ -632,6 +644,20 @@ Matchers.tests.cpp: Matchers.tests.cpp: +Matchers.tests.cpp: + + + + +Matchers.tests.cpp: + + +Matchers.tests.cpp: + + +Matchers.tests.cpp: + + Matchers.tests.cpp: @@ -680,6 +706,7 @@ Exception.tests.cpp: + @@ -781,31 +808,40 @@ i := 7 Message.tests.cpp: + + + + + + Tricky.tests.cpp: + - + + + + + + + +Why would you throw a std::string? +Exception.tests.cpp: + + - - - -EnumToString.tests.cpp: - - -EnumToString.tests.cpp: - - + @@ -815,6 +851,7 @@ EnumToString.tests.cpp: + @@ -833,6 +870,7 @@ Message from section two A string sent directly to stderr +A string sent to stderr via clog diff --git a/Telegram/ThirdParty/Catch/projects/SelfTest/Baselines/xml.sw.approved.txt b/Telegram/ThirdParty/Catch/projects/SelfTest/Baselines/xml.sw.approved.txt index d194c96e5..227dee937 100644 --- a/Telegram/ThirdParty/Catch/projects/SelfTest/Baselines/xml.sw.approved.txt +++ b/Telegram/ThirdParty/Catch/projects/SelfTest/Baselines/xml.sw.approved.txt @@ -42,6 +42,60 @@ + + + + t1 == t2 + + + {?} == {?} + + + + + t1 != t2 + + + {?} != {?} + + + + + t1 < t2 + + + {?} < {?} + + + + + t1 > t2 + + + {?} > {?} + + + + + t1 <= t2 + + + {?} <= {?} + + + + + t1 >= t2 + + + {?} >= {?} + + + + + + +
@@ -549,7 +603,7 @@ - + @@ -819,7 +873,7 @@ - Catch::alwaysTrue() + true true @@ -828,7 +882,7 @@
- Catch::alwaysTrue() + true true @@ -837,7 +891,7 @@
- Catch::alwaysTrue() + true true @@ -849,7 +903,7 @@
- Catch::alwaysTrue() + true true @@ -858,7 +912,7 @@
- Catch::alwaysTrue() + true true @@ -867,7 +921,7 @@
- Catch::alwaysTrue() + true true @@ -1273,7 +1327,7 @@ - td >= Approx(10.0) + td >= Approx(td) StrongDoubleTypedef(10) >= Approx( 10.0 ) @@ -1281,7 +1335,7 @@ - Approx(10.0) >= td + Approx(td) >= td Approx( 10.0 ) >= StrongDoubleTypedef(10) @@ -2067,7 +2121,7 @@ - std::nextafter(1., 2.), WithinULP(1., 1) + nextafter(1., 2.), WithinULP(1., 1) 1.0 is within 1 ULPs of 1.0 @@ -2075,7 +2129,7 @@ - std::nextafter(1., 0.), WithinULP(1., 1) + nextafter(1., 0.), WithinULP(1., 1) 1.0 is within 1 ULPs of 1.0 @@ -2083,7 +2137,7 @@ - std::nextafter(1., 2.), !WithinULP(1., 0) + nextafter(1., 2.), !WithinULP(1., 0) 1.0 not is within 0 ULPs of 1.0 @@ -2142,6 +2196,41 @@
+
+ + + WithinAbs(1., 0.) + + + WithinAbs(1., 0.) + + + + + WithinAbs(1., -1.), std::domain_error + + + WithinAbs(1., -1.), std::domain_error + + + + + WithinULP(1., 0) + + + WithinULP(1., 0) + + + + + WithinULP(1., -1), std::domain_error + + + WithinULP(1., -1), std::domain_error + + + +
@@ -2207,7 +2296,7 @@
- std::nextafter(1.f, 2.f), WithinULP(1.f, 1) + nextafter(1.f, 2.f), WithinULP(1.f, 1) 1.0f is within 1 ULPs of 1.0f @@ -2215,7 +2304,7 @@ - std::nextafter(1.f, 0.f), WithinULP(1.f, 1) + nextafter(1.f, 0.f), WithinULP(1.f, 1) 1.0f is within 1 ULPs of 1.0f @@ -2223,7 +2312,7 @@ - std::nextafter(1.f, 2.f), !WithinULP(1.f, 0) + nextafter(1.f, 2.f), !WithinULP(1.f, 0) 1.0f not is within 0 ULPs of 1.0f @@ -2282,6 +2371,41 @@
+
+ + + WithinAbs(1.f, 0.f) + + + WithinAbs(1.f, 0.f) + + + + + WithinAbs(1.f, -1.f), std::domain_error + + + WithinAbs(1.f, -1.f), std::domain_error + + + + + WithinULP(1.f, 0) + + + WithinULP(1.f, 0) + + + + + WithinULP(1.f, -1), std::domain_error + + + WithinULP(1.f, -1), std::domain_error + + + +
@@ -2326,7 +2450,7 @@ this is a warning - + @@ -2836,7 +2960,7 @@ This one ran - + @@ -4503,7 +4627,15 @@ true
- + + + !(cfg.hasTestFilters()) + + + !false + + +
@@ -4515,6 +4647,14 @@ {?} + + + cfg.hasTestFilters() + + + true + + cfg.testSpec().matches(fakeTestCase("notIncluded")) == false @@ -4531,9 +4671,9 @@ true - +
- +
@@ -4545,6 +4685,14 @@ {?} + + + cfg.hasTestFilters() + + + true + + cfg.testSpec().matches(fakeTestCase("test1")) == false @@ -4561,9 +4709,9 @@ true - +
- +
@@ -4575,6 +4723,14 @@ {?} + + + cfg.hasTestFilters() + + + true + + cfg.testSpec().matches(fakeTestCase("test1")) == false @@ -4591,9 +4747,9 @@ true - +
- +
@@ -5088,7 +5244,7 @@ - + @@ -5254,12 +5410,13 @@ - + A string sent directly to stdout A string sent directly to stderr +A string sent to stderr via clog @@ -5355,6 +5512,44 @@ Message from section two + +
+ + + Catch::Detail::stringify(singular) == "{ 1 }" + + + "{ 1 }" == "{ 1 }" + + + +
+
+ + + Catch::Detail::stringify(arr) == "{ 3, 2, 1 }" + + + "{ 3, 2, 1 }" == "{ 3, 2, 1 }" + + + +
+
+ + + Catch::Detail::stringify(arr) == R"({ { "1:1", "1:2", "1:3" }, { "2:1", "2:2" } })" + + + "{ { "1:1", "1:2", "1:3" }, { "2:1", "2:2" } }" +== +"{ { "1:1", "1:2", "1:3" }, { "2:1", "2:2" } }" + + + +
+ +
@@ -5422,7 +5617,7 @@ Message from section two - +
@@ -5521,15 +5716,39 @@ Message from section two original == "original" - + isSubstring( original ) - false + true - + + + isOwned( original ) == false + + + false == false + + + + + isSubstring( original ) == false + + + false == false + + + + + isOwned( original ) + + + true + + +
@@ -5589,7 +5808,7 @@ Message from section two - rawChars == data( s ) + rawChars == s.currentData() "hello world!" == "hello world!" @@ -5621,7 +5840,7 @@ Message from section two - data( ss ) != data( s ) + ss.currentData() != s.currentData() "hello" != "hello world!" @@ -5832,7 +6051,34 @@ Message from section two
- +
+ + + ascii.numberOfCharacters() == ascii.size() + + + 39 == 39 + + + + + simpleu8.numberOfCharacters() == 30 + + + 30 == 30 + + + + + emojis.numberOfCharacters() == 9 + + + 9 == 9 + + + +
+
@@ -5878,6 +6124,14 @@ Message from section two 1 [30/1]s != 1 fs + + + pico_second != atto_second + + + 1 ps != 1 as + + @@ -6015,11 +6269,17 @@ Message from section two 1 == 2 - + + + + For some reason someone is throwing a string literal! + + + @@ -7298,6 +7558,41 @@ Message from section two
+
+ + + v, UnorderedEquals(v) + + + { 1, 2, 3 } UnorderedEquals: { 1, 2, 3 } + + + + + empty, UnorderedEquals(empty) + + + { } UnorderedEquals: { } + + + + + permuted, UnorderedEquals(v) + + + { 1, 3, 2 } UnorderedEquals: { 1, 2, 3 } + + + + + permuted, UnorderedEquals(v) + + + { 2, 3, 1 } UnorderedEquals: { 1, 2, 3 } + + + +
@@ -7374,6 +7669,41 @@ Message from section two
+
+ + + v, UnorderedEquals(empty) + + + { 1, 2, 3 } UnorderedEquals: { } + + + + + empty, UnorderedEquals(v) + + + { } UnorderedEquals: { 1, 2, 3 } + + + + + permuted, UnorderedEquals(v) + + + { 1, 3 } UnorderedEquals: { 1, 2, 3 } + + + + + permuted, UnorderedEquals(v) + + + { 3, 1 } UnorderedEquals: { 1, 2, 3 } + + + +
@@ -7461,19 +7791,19 @@ Message from section two - + Uncomment the code in this test to check that it gives a sensible compiler error - + Uncomment the code in this test to check that it gives a sensible compiler error - + @@ -7600,6 +7930,33 @@ Message from section two
+ + + + Catch::Detail::stringify( empty ) == "{ }" + + + "{ }" == "{ }" + + + + + Catch::Detail::stringify( oneValue ) == "{ 42 }" + + + "{ 42 }" == "{ 42 }" + + + + + Catch::Detail::stringify( twoValues ) == "{ 42, 250 }" + + + "{ 42, 250 }" == "{ 42, 250 }" + + + + @@ -7787,11 +8144,11 @@ Message from section two - + loose text artifact - + @@ -7800,7 +8157,7 @@ loose text artifact - + @@ -8110,7 +8467,7 @@ loose text artifact - +
@@ -8247,7 +8604,7 @@ loose text artifact - + @@ -8280,6 +8637,44 @@ loose text artifact + +
+ + + Catch::Detail::stringify( emptyMap ) == "{ }" + + + "{ }" == "{ }" + + + +
+
+ + + Catch::Detail::stringify( map ) == "{ { \"one\", 1 } }" + + + "{ { "one", 1 } }" == "{ { "one", 1 } }" + + + +
+
+ + + Catch::Detail::stringify( map ) == "{ { \"abc\", 1 }, { \"def\", 2 }, { \"ghi\", 3 } }" + + + "{ { "abc", 1 }, { "def", 2 }, { "ghi", 3 } }" +== +"{ { "abc", 1 }, { "def", 2 }, { "ghi", 3 } }" + + + +
+ +
@@ -8302,6 +8697,44 @@ loose text artifact + +
+ + + Catch::Detail::stringify( emptySet ) == "{ }" + + + "{ }" == "{ }" + + + +
+
+ + + Catch::Detail::stringify( set ) == "{ \"one\" }" + + + "{ "one" }" == "{ "one" }" + + + +
+
+ + + Catch::Detail::stringify( set ) == "{ \"abc\", \"def\", \"ghi\" }" + + + "{ "abc", "def", "ghi" }" +== +"{ "abc", "def", "ghi" }" + + + +
+ +
@@ -8326,6 +8759,45 @@ loose text artifact + + + + ::Catch::Detail::stringify(streamable_range{}) == "op<<(streamable_range)" + + + "op<<(streamable_range)" +== +"op<<(streamable_range)" + + + + + ::Catch::Detail::stringify(stringmaker_range{}) == "stringmaker(streamable_range)" + + + "stringmaker(streamable_range)" +== +"stringmaker(streamable_range)" + + + + + ::Catch::Detail::stringify(just_range{}) == "{ 1, 2, 3, 4 }" + + + "{ 1, 2, 3, 4 }" == "{ 1, 2, 3, 4 }" + + + + + ::Catch::Detail::stringify(disabled_range{}) == "{ !!! }" + + + "{ !!! }" == "{ !!! }" + + + + @@ -8339,7 +8811,7 @@ loose text artifact - + ::Catch::Detail::stringify( item ) == "StringMaker<has_maker_and_operator>" @@ -8352,6 +8824,17 @@ loose text artifact + + + + ::Catch::Detail::stringify(item) == "{ !!! }" + + + "{ !!! }" == "{ !!! }" + + + + @@ -8365,6 +8848,51 @@ loose text artifact + + + + ::Catch::Detail::stringify( v ) == "{ StringMaker<has_maker> }" + + + "{ StringMaker<has_maker> }" +== +"{ StringMaker<has_maker> }" + + + + + + + + ::Catch::Detail::stringify( v ) == "{ StringMaker<has_maker_and_operator> }" + + + "{ StringMaker<has_maker_and_operator> }" +== +"{ StringMaker<has_maker_and_operator> }" + + + + + + + + ::Catch::Detail::stringify( v ) == "{ operator<<( has_operator ) }" + + + "{ operator<<( has_operator ) }" +== +"{ operator<<( has_operator ) }" + + + + + + + Why would you throw a std::string? + + + @@ -8409,19 +8937,6 @@ loose text artifact - - - - ::Catch::Detail::stringify( v ) == "{ StringMaker<has_maker> }" - - - "{ StringMaker<has_maker> }" -== -"{ StringMaker<has_maker> }" - - - - @@ -8451,24 +8966,24 @@ loose text artifact - - + + ::Catch::Detail::stringify(e0) == "0" - "{?}" == "0" + "0" == "0" - + ::Catch::Detail::stringify(e1) == "1" - "{?}" == "1" + "1" == "1" - + @@ -8617,6 +9132,33 @@ loose text artifact + + + + ::Catch::Detail::stringify(bools) == "{ }" + + + "{ }" == "{ }" + + + + + ::Catch::Detail::stringify(bools) == "{ true }" + + + "{ true }" == "{ true }" + + + + + ::Catch::Detail::stringify(bools) == "{ true, false }" + + + "{ true, false }" == "{ true, false }" + + + + @@ -8863,7 +9405,7 @@ loose text artifact
- + - + diff --git a/Telegram/ThirdParty/Catch/projects/SelfTest/IntrospectiveTests/CmdLine.tests.cpp b/Telegram/ThirdParty/Catch/projects/SelfTest/IntrospectiveTests/CmdLine.tests.cpp index a07358522..7bc4a367d 100644 --- a/Telegram/ThirdParty/Catch/projects/SelfTest/IntrospectiveTests/CmdLine.tests.cpp +++ b/Telegram/ThirdParty/Catch/projects/SelfTest/IntrospectiveTests/CmdLine.tests.cpp @@ -15,7 +15,7 @@ # pragma clang diagnostic ignored "-Wc++98-compat" #endif -inline Catch::TestCase fakeTestCase( const char* name, const char* desc = "" ){ return Catch::makeTestCase( nullptr, "", name, desc, CATCH_INTERNAL_LINEINFO ); } +inline Catch::TestCase fakeTestCase(const char* name, const char* desc = "") { return Catch::makeTestCase(nullptr, "", { name, desc }, CATCH_INTERNAL_LINEINFO); } TEST_CASE( "Parse test names and tags" ) { @@ -289,6 +289,9 @@ TEST_CASE( "Process can be configured on command line", "[config][command-line]" CHECK(config.abortAfter == -1); CHECK(config.noThrow == false); CHECK(config.reporterNames.empty()); + + Catch::Config cfg(config); + CHECK_FALSE(cfg.hasTestFilters()); } SECTION("test lists") { @@ -297,6 +300,7 @@ TEST_CASE( "Process can be configured on command line", "[config][command-line]" CHECK(result); Catch::Config cfg(config); + REQUIRE(cfg.hasTestFilters()); REQUIRE(cfg.testSpec().matches(fakeTestCase("notIncluded")) == false); REQUIRE(cfg.testSpec().matches(fakeTestCase("test1"))); } @@ -305,6 +309,7 @@ TEST_CASE( "Process can be configured on command line", "[config][command-line]" CHECK(result); Catch::Config cfg(config); + REQUIRE(cfg.hasTestFilters()); REQUIRE(cfg.testSpec().matches(fakeTestCase("test1")) == false); REQUIRE(cfg.testSpec().matches(fakeTestCase("alwaysIncluded"))); } @@ -314,6 +319,7 @@ TEST_CASE( "Process can be configured on command line", "[config][command-line]" CHECK(result); Catch::Config cfg(config); + REQUIRE(cfg.hasTestFilters()); REQUIRE(cfg.testSpec().matches(fakeTestCase("test1")) == false); REQUIRE(cfg.testSpec().matches(fakeTestCase("alwaysIncluded"))); } diff --git a/Telegram/ThirdParty/Catch/projects/SelfTest/IntrospectiveTests/String.tests.cpp b/Telegram/ThirdParty/Catch/projects/SelfTest/IntrospectiveTests/String.tests.cpp index 9c9c55995..ee6e4c58e 100644 --- a/Telegram/ThirdParty/Catch/projects/SelfTest/IntrospectiveTests/String.tests.cpp +++ b/Telegram/ThirdParty/Catch/projects/SelfTest/IntrospectiveTests/String.tests.cpp @@ -14,9 +14,6 @@ namespace Catch { static auto isSubstring( StringRef const& stringRef ) -> bool { return stringRef.isSubstring(); } - static auto data( StringRef const& stringRef ) -> char const* { - return stringRef.data(); - } }; auto isOwned( StringRef const& stringRef ) -> bool { @@ -25,19 +22,16 @@ namespace Catch { auto isSubstring( StringRef const& stringRef ) -> bool { return StringRefTestAccess::isSubstring( stringRef ); } - auto data( StringRef const& stringRef ) -> char const* { - return StringRefTestAccess::data( stringRef ); - } } // namespace Catch2 namespace Catch { inline auto toString( Catch::StringRef const& stringRef ) -> std::string { - return std::string( data( stringRef ), stringRef.size() ); + return std::string( stringRef.currentData(), stringRef.size() ); } } // namespace Catch -TEST_CASE( "StringRef", "[Strings]" ) { - +TEST_CASE( "StringRef", "[Strings][StringRef]" ) { + using Catch::StringRef; SECTION( "Empty string" ) { @@ -46,21 +40,21 @@ TEST_CASE( "StringRef", "[Strings]" ) { REQUIRE( empty.size() == 0 ); REQUIRE( std::strcmp( empty.c_str(), "" ) == 0 ); } - + SECTION( "From string literal" ) { StringRef s = "hello"; REQUIRE( s.empty() == false ); REQUIRE( s.size() == 5 ); REQUIRE( isSubstring( s ) == false ); - - auto rawChars = data( s ); + + auto rawChars = s.currentData(); REQUIRE( std::strcmp( rawChars, "hello" ) == 0 ); - + SECTION( "c_str() does not cause copy" ) { REQUIRE( isOwned( s ) == false ); - + REQUIRE( s.c_str() == rawChars ); - + REQUIRE( isOwned( s ) == false ); } } @@ -69,19 +63,18 @@ TEST_CASE( "StringRef", "[Strings]" ) { REQUIRE( original == "original" ); REQUIRE( isSubstring( original ) ); REQUIRE( isOwned( original ) == false ); - + original.c_str(); // Forces it to take ownership - + REQUIRE( isSubstring( original ) == false ); REQUIRE( isOwned( original ) ); - } - - + + SECTION( "Substrings" ) { StringRef s = "hello world!"; StringRef ss = s.substr(0, 5); - + SECTION( "zero-based substring" ) { REQUIRE( ss.empty() == false ); REQUIRE( ss.size() == 5 ); @@ -91,33 +84,33 @@ TEST_CASE( "StringRef", "[Strings]" ) { SECTION( "c_str() causes copy" ) { REQUIRE( isSubstring( ss ) ); REQUIRE( isOwned( ss ) == false ); - - auto rawChars = data( ss ); - REQUIRE( rawChars == data( s ) ); // same pointer value + + auto rawChars = ss.currentData(); + REQUIRE( rawChars == s.currentData() ); // same pointer value REQUIRE( ss.c_str() != rawChars ); - + REQUIRE( isSubstring( ss ) == false ); REQUIRE( isOwned( ss ) ); - - REQUIRE( data( ss ) != data( s ) ); // different pointer value + + REQUIRE( ss.currentData() != s.currentData() ); // different pointer value } - + SECTION( "non-zero-based substring") { ss = s.substr( 6, 6 ); REQUIRE( ss.size() == 6 ); REQUIRE( std::strcmp( ss.c_str(), "world!" ) == 0 ); } - + SECTION( "Pointer values of full refs should match" ) { StringRef s2 = s; REQUIRE( s.c_str() == s2.c_str() ); } - + SECTION( "Pointer values of substring refs should not match" ) { REQUIRE( s.c_str() != ss.c_str() ); } } - + SECTION( "Comparisons" ) { REQUIRE( StringRef("hello") == StringRef("hello") ); REQUIRE( StringRef("hello") != StringRef("cello") ); @@ -164,9 +157,21 @@ TEST_CASE( "StringRef", "[Strings]" ) { REQUIRE( stdStr.size() == sr.size() ); } } + + SECTION( "Counting utf-8 codepoints" ) { + StringRef ascii = "just a plain old boring ascii string..."; + REQUIRE(ascii.numberOfCharacters() == ascii.size()); + + StringRef simpleu8 = u8"Trocha češtiny nikoho nezabila"; + REQUIRE(simpleu8.numberOfCharacters() == 30); + + StringRef emojis = u8"Here be 👾"; + REQUIRE(emojis.numberOfCharacters() == 9); + } + } -TEST_CASE( "replaceInPlace" ) { +TEST_CASE( "replaceInPlace", "[Strings][StringManip]" ) { std::string letters = "abcdefcg"; SECTION( "replace single char" ) { CHECK( Catch::replaceInPlace( letters, "b", "z" ) ); diff --git a/Telegram/ThirdParty/Catch/projects/SelfTest/TestMain.cpp b/Telegram/ThirdParty/Catch/projects/SelfTest/TestMain.cpp index 9b7c1c217..1c023ce91 100644 --- a/Telegram/ThirdParty/Catch/projects/SelfTest/TestMain.cpp +++ b/Telegram/ThirdParty/Catch/projects/SelfTest/TestMain.cpp @@ -29,5 +29,5 @@ CATCH_REGISTER_TAG_ALIAS( "[@tricky]", "[tricky]~[.]" ) struct TestListener : Catch::TestEventListenerBase { using TestEventListenerBase::TestEventListenerBase; // inherit constructor }; -CATCH_REGISTER_LISTENER( TestListener ); +CATCH_REGISTER_LISTENER( TestListener ) diff --git a/Telegram/ThirdParty/Catch/projects/SelfTest/UsageTests/Approx.tests.cpp b/Telegram/ThirdParty/Catch/projects/SelfTest/UsageTests/Approx.tests.cpp index b39749713..5930075d1 100644 --- a/Telegram/ThirdParty/Catch/projects/SelfTest/UsageTests/Approx.tests.cpp +++ b/Telegram/ThirdParty/Catch/projects/SelfTest/UsageTests/Approx.tests.cpp @@ -189,8 +189,8 @@ TEST_CASE( "Comparison with explicitly convertible types", "[Approx]" ) REQUIRE(Approx(9.0) <= td); REQUIRE(td >= Approx(9.0)); - REQUIRE(td >= Approx(10.0)); - REQUIRE(Approx(10.0) >= td); + REQUIRE(td >= Approx(td)); + REQUIRE(Approx(td) >= td); REQUIRE(Approx(11.0) >= td); } diff --git a/Telegram/ThirdParty/Catch/projects/SelfTest/UsageTests/Compilation.tests.cpp b/Telegram/ThirdParty/Catch/projects/SelfTest/UsageTests/Compilation.tests.cpp index f140e3e8e..9075743aa 100644 --- a/Telegram/ThirdParty/Catch/projects/SelfTest/UsageTests/Compilation.tests.cpp +++ b/Telegram/ThirdParty/Catch/projects/SelfTest/UsageTests/Compilation.tests.cpp @@ -12,6 +12,19 @@ namespace { namespace CompilationTests { #ifndef COMPILATION_TEST_HELPERS_INCLUDED // Don't compile this more than once per TU #define COMPILATION_TEST_HELPERS_INCLUDED + // Comparison operators can return non-booleans. + // This is unusual, but should be supported. + struct logic_t { + logic_t operator< (logic_t) const { return {}; } + logic_t operator<=(logic_t) const { return {}; } + logic_t operator> (logic_t) const { return {}; } + logic_t operator>=(logic_t) const { return {}; } + logic_t operator==(logic_t) const { return {}; } + logic_t operator!=(logic_t) const { return {}; } + explicit operator bool() const { return true; } + }; + + // This is a minimal example for an issue we have found in 1.7.0 struct foo { int i; @@ -109,4 +122,16 @@ namespace { namespace CompilationTests { REQUIRE(0 == y.v); } + // Comparison operators can return non-booleans. + // This is unusual, but should be supported. + TEST_CASE("#1147") { + logic_t t1, t2; + REQUIRE(t1 == t2); + REQUIRE(t1 != t2); + REQUIRE(t1 < t2); + REQUIRE(t1 > t2); + REQUIRE(t1 <= t2); + REQUIRE(t1 >= t2); + } + }} // namespace CompilationTests diff --git a/Telegram/ThirdParty/Catch/projects/SelfTest/UsageTests/EnumToString.tests.cpp b/Telegram/ThirdParty/Catch/projects/SelfTest/UsageTests/EnumToString.tests.cpp index be0da03a6..7d18a292c 100644 --- a/Telegram/ThirdParty/Catch/projects/SelfTest/UsageTests/EnumToString.tests.cpp +++ b/Telegram/ThirdParty/Catch/projects/SelfTest/UsageTests/EnumToString.tests.cpp @@ -28,9 +28,7 @@ TEST_CASE( "toString(enum w/operator<<)", "[toString][enum]" ) { // Enum class without user-provided stream operator enum class EnumClass1 { EnumClass1Value0, EnumClass1Value1 }; -// This fails, but has been hidden for a while - not sure if it's a regression or if it never worked -// - need to investigate -TEST_CASE( "toString(enum class)", "[toString][enum][enumClass][.]" ) { +TEST_CASE( "toString(enum class)", "[toString][enum][enumClass]" ) { EnumClass1 e0 = EnumClass1::EnumClass1Value0; CHECK( ::Catch::Detail::stringify(e0) == "0" ); EnumClass1 e1 = EnumClass1::EnumClass1Value1; diff --git a/Telegram/ThirdParty/Catch/projects/SelfTest/UsageTests/Exception.tests.cpp b/Telegram/ThirdParty/Catch/projects/SelfTest/UsageTests/Exception.tests.cpp index 1100114a7..f9c73ed53 100644 --- a/Telegram/ThirdParty/Catch/projects/SelfTest/UsageTests/Exception.tests.cpp +++ b/Telegram/ThirdParty/Catch/projects/SelfTest/UsageTests/Exception.tests.cpp @@ -12,11 +12,12 @@ #include #ifdef _MSC_VER -#pragma warning(disable:4702) // Unreachable code -- MSVC 19 (VS 2015) sees right through the indirection +#pragma warning(disable:4702) // Unreachable code -- unconditional throws and so on #endif #ifdef __clang__ #pragma clang diagnostic push #pragma clang diagnostic ignored "-Wweak-vtables" +#pragma clang diagnostic ignored "-Wmissing-noreturn" #endif namespace { namespace ExceptionTests { @@ -24,9 +25,8 @@ namespace { namespace ExceptionTests { #ifndef EXCEPTION_TEST_HELPERS_INCLUDED // Don't compile this more than once per TU #define EXCEPTION_TEST_HELPERS_INCLUDED -inline int thisThrows() { - if( Catch::alwaysTrue() ) - throw std::domain_error( "expected exception" ); +int thisThrows() { + throw std::domain_error( "expected exception" ); return 1; } @@ -36,8 +36,8 @@ int thisDoesntThrow() { class CustomException { public: - CustomException( const std::string& msg ) - : m_msg( msg ) + explicit CustomException( const std::string& msg ) + : m_msg( msg ) {} std::string getMessage() const { @@ -50,10 +50,10 @@ private: class CustomStdException : public std::exception { public: - CustomStdException( const std::string& msg ) - : m_msg( msg ) + explicit CustomStdException( const std::string& msg ) + : m_msg( msg ) {} - ~CustomStdException() noexcept {} + ~CustomStdException() noexcept override {} std::string getMessage() const { return m_msg; @@ -63,9 +63,8 @@ private: std::string m_msg; }; -inline void throwCustom() { - if( Catch::alwaysTrue() ) - throw CustomException( "custom exception - not std" ); +[[noreturn]] void throwCustom() { + throw CustomException( "custom exception - not std" ); } #endif @@ -83,20 +82,17 @@ TEST_CASE( "Expected exceptions that don't throw or unexpected exceptions fail t } TEST_CASE( "When unchecked exceptions are thrown directly they are always failures", "[.][failing][!throws]" ) { - if( Catch::alwaysTrue() ) - throw std::domain_error( "unexpected exception" ); + throw std::domain_error( "unexpected exception" ); } TEST_CASE( "An unchecked exception reports the line of the last assertion", "[.][failing][!throws]" ) { CHECK( 1 == 1 ); - if( Catch::alwaysTrue() ) - throw std::domain_error( "unexpected exception" ); + throw std::domain_error( "unexpected exception" ); } TEST_CASE( "When unchecked exceptions are thrown from sections they are always failures", "[.][failing][!throws]" ) { SECTION( "section name" ) { - if( Catch::alwaysTrue() ) - throw std::domain_error( "unexpected exception" ); + throw std::domain_error("unexpected exception"); } } @@ -139,13 +135,11 @@ CATCH_TRANSLATE_EXCEPTION( double& ex ) { } TEST_CASE("Non-std exceptions can be translated", "[.][failing][!throws]" ) { - if( Catch::alwaysTrue() ) - throw CustomException( "custom exception" ); + throw CustomException( "custom exception" ); } TEST_CASE("Custom std-exceptions can be custom translated", "[.][failing][!throws]" ) { - if( Catch::alwaysTrue() ) - throw CustomException( "custom std exception" ); + throw CustomException( "custom std exception" ); } TEST_CASE( "Custom exceptions can be translated when testing for nothrow", "[.][failing][!throws]" ) { @@ -157,10 +151,18 @@ TEST_CASE( "Custom exceptions can be translated when testing for throwing as som } TEST_CASE( "Unexpected exceptions can be translated", "[.][failing][!throws]" ) { - if( Catch::alwaysTrue() ) - throw double( 3.14 ); + throw double( 3.14 ); } +TEST_CASE("Thrown string literals are translated", "[.][failing][!throws]") { + throw "For some reason someone is throwing a string literal!"; +} + +TEST_CASE("thrown std::strings are translated", "[.][failing][!throws]") { + throw std::string{ "Why would you throw a std::string?" }; +} + + #ifndef CATCH_CONFIG_DISABLE_MATCHERS TEST_CASE( "Exception messages can be tested for", "[!throws]" ) { diff --git a/Telegram/ThirdParty/Catch/projects/SelfTest/UsageTests/Matchers.tests.cpp b/Telegram/ThirdParty/Catch/projects/SelfTest/UsageTests/Matchers.tests.cpp index 34f167ab6..05056b437 100644 --- a/Telegram/ThirdParty/Catch/projects/SelfTest/UsageTests/Matchers.tests.cpp +++ b/Telegram/ThirdParty/Catch/projects/SelfTest/UsageTests/Matchers.tests.cpp @@ -9,6 +9,7 @@ #include "catch.hpp" #include +#include #ifdef __clang__ #pragma clang diagnostic push @@ -76,6 +77,20 @@ namespace { namespace MatchersTests { using namespace Catch::Matchers; +#ifdef __DJGPP__ + float nextafter(float from, float to) + { + return ::nextafterf(from, to); + } + + double nextafter(double from, double to) + { + return ::nextafter(from, to); + } +#else + using std::nextafter; +#endif + TEST_CASE("String matchers", "[matchers]") { REQUIRE_THAT(testStringForMatching(), Contains("string")); REQUIRE_THAT(testStringForMatching(), Contains("string", Catch::CaseSensitive::No)); @@ -129,12 +144,16 @@ namespace { namespace MatchersTests { (defined(_GLIBCXX_RELEASE) && \ _GLIBCXX_RELEASE > 4)))) +// DJGPP meets the above condition but does not work properly anyway +#ifndef __DJGPP__ REQUIRE_THAT(testStringForMatching(), Matches("this string contains 'abc' as a substring")); REQUIRE_THAT(testStringForMatching(), Matches("this string CONTAINS 'abc' as a substring", Catch::CaseSensitive::No)); REQUIRE_THAT(testStringForMatching(), Matches("^this string contains 'abc' as a substring$")); REQUIRE_THAT(testStringForMatching(), Matches("^.* 'abc' .*$")); REQUIRE_THAT(testStringForMatching(), Matches("^.* 'ABC' .*$", Catch::CaseSensitive::No)); +#endif + #endif REQUIRE_THAT(testStringForMatching2(), !Matches("this string contains 'abc' as a substring")); @@ -216,6 +235,17 @@ namespace { namespace MatchersTests { v2.push_back(3); CHECK_THAT(v, Equals(v2)); } + SECTION("UnorderedEquals") { + CHECK_THAT(v, UnorderedEquals(v)); + CHECK_THAT(empty, UnorderedEquals(empty)); + + auto permuted = v; + std::next_permutation(begin(permuted), end(permuted)); + REQUIRE_THAT(permuted, UnorderedEquals(v)); + + std::reverse(begin(permuted), end(permuted)); + REQUIRE_THAT(permuted, UnorderedEquals(v)); + } } TEST_CASE("Vector matchers that fail", "[matchers][vector][.][failing]") { @@ -247,6 +277,18 @@ namespace { namespace MatchersTests { CHECK_THAT(empty, Equals(v)); CHECK_THAT(v, Equals(empty)); } + SECTION("UnorderedEquals") { + CHECK_THAT(v, UnorderedEquals(empty)); + CHECK_THAT(empty, UnorderedEquals(v)); + + auto permuted = v; + std::next_permutation(begin(permuted), end(permuted)); + permuted.pop_back(); + CHECK_THAT(permuted, UnorderedEquals(v)); + + std::reverse(begin(permuted), end(permuted)); + CHECK_THAT(permuted, UnorderedEquals(v)); + } } TEST_CASE("Exception matchers that succeed", "[matchers][exceptions][!throws]") { @@ -283,9 +325,9 @@ namespace { namespace MatchersTests { SECTION("ULPs") { REQUIRE_THAT(1.f, WithinULP(1.f, 0)); - REQUIRE_THAT(std::nextafter(1.f, 2.f), WithinULP(1.f, 1)); - REQUIRE_THAT(std::nextafter(1.f, 0.f), WithinULP(1.f, 1)); - REQUIRE_THAT(std::nextafter(1.f, 2.f), !WithinULP(1.f, 0)); + REQUIRE_THAT(nextafter(1.f, 2.f), WithinULP(1.f, 1)); + REQUIRE_THAT(nextafter(1.f, 0.f), WithinULP(1.f, 1)); + REQUIRE_THAT(nextafter(1.f, 2.f), !WithinULP(1.f, 0)); REQUIRE_THAT(1.f, WithinULP(1.f, 0)); REQUIRE_THAT(-0.f, WithinULP(0.f, 0)); @@ -298,6 +340,13 @@ namespace { namespace MatchersTests { REQUIRE_THAT(NAN, !(WithinAbs(NAN, 100) || WithinULP(NAN, 123))); } + SECTION("Constructor validation") { + REQUIRE_NOTHROW(WithinAbs(1.f, 0.f)); + REQUIRE_THROWS_AS(WithinAbs(1.f, -1.f), std::domain_error); + + REQUIRE_NOTHROW(WithinULP(1.f, 0)); + REQUIRE_THROWS_AS(WithinULP(1.f, -1), std::domain_error); + } } TEST_CASE("Floating point matchers: double", "[matchers][floating-point]") { @@ -313,9 +362,9 @@ namespace { namespace MatchersTests { SECTION("ULPs") { REQUIRE_THAT(1., WithinULP(1., 0)); - REQUIRE_THAT(std::nextafter(1., 2.), WithinULP(1., 1)); - REQUIRE_THAT(std::nextafter(1., 0.), WithinULP(1., 1)); - REQUIRE_THAT(std::nextafter(1., 2.), !WithinULP(1., 0)); + REQUIRE_THAT(nextafter(1., 2.), WithinULP(1., 1)); + REQUIRE_THAT(nextafter(1., 0.), WithinULP(1., 1)); + REQUIRE_THAT(nextafter(1., 2.), !WithinULP(1., 0)); REQUIRE_THAT(1., WithinULP(1., 0)); REQUIRE_THAT(-0., WithinULP(0., 0)); @@ -328,6 +377,13 @@ namespace { namespace MatchersTests { REQUIRE_THAT(NAN, !(WithinAbs(NAN, 100) || WithinULP(NAN, 123))); } + SECTION("Constructor validation") { + REQUIRE_NOTHROW(WithinAbs(1., 0.)); + REQUIRE_THROWS_AS(WithinAbs(1., -1.), std::domain_error); + + REQUIRE_NOTHROW(WithinULP(1., 0)); + REQUIRE_THROWS_AS(WithinULP(1., -1), std::domain_error); + } } } } // namespace MatchersTests diff --git a/Telegram/ThirdParty/Catch/projects/SelfTest/UsageTests/Message.tests.cpp b/Telegram/ThirdParty/Catch/projects/SelfTest/UsageTests/Message.tests.cpp index 6082a4e68..f3ac02a1f 100644 --- a/Telegram/ThirdParty/Catch/projects/SelfTest/UsageTests/Message.tests.cpp +++ b/Telegram/ThirdParty/Catch/projects/SelfTest/UsageTests/Message.tests.cpp @@ -61,7 +61,7 @@ TEST_CASE( "FAIL does not require an argument", "[failing][messages][.]" ) { FAIL(); } -TEST_CASE( "SUCCESS does not require an argument", "[messages][.]" ) { +TEST_CASE( "SUCCEED does not require an argument", "[messages][.]" ) { SUCCEED(); } diff --git a/Telegram/ThirdParty/Catch/projects/SelfTest/UsageTests/Misc.tests.cpp b/Telegram/ThirdParty/Catch/projects/SelfTest/UsageTests/Misc.tests.cpp index 6a6f1da05..fa158705c 100644 --- a/Telegram/ThirdParty/Catch/projects/SelfTest/UsageTests/Misc.tests.cpp +++ b/Telegram/ThirdParty/Catch/projects/SelfTest/UsageTests/Misc.tests.cpp @@ -57,7 +57,9 @@ struct AutoTestReg { REGISTER_TEST_CASE( manuallyRegisteredTestFunction, "ManuallyRegistered" ); } }; +CATCH_INTERNAL_SUPPRESS_GLOBALS_WARNINGS static AutoTestReg autoTestReg; +CATCH_INTERNAL_UNSUPPRESS_GLOBALS_WARNINGS #endif @@ -146,8 +148,8 @@ TEST_CASE( "looped tests", "[.][failing]" ) { TEST_CASE( "Sends stuff to stdout and stderr", "[.]" ) { std::cout << "A string sent directly to stdout" << std::endl; - std::cerr << "A string sent directly to stderr" << std::endl; + std::clog << "A string sent to stderr via clog" << std::endl; } TEST_CASE( "null strings" ) { @@ -288,6 +290,7 @@ TEST_CASE( "Tabs and newlines show in output", "[.][whitespace][failing]" ) { } +#ifdef CATCH_CONFIG_WCHAR TEST_CASE( "toString on const wchar_t const pointer returns the string contents", "[toString]" ) { const wchar_t * const s = L"wide load"; std::string result = ::Catch::Detail::stringify( s ); @@ -301,16 +304,17 @@ TEST_CASE( "toString on const wchar_t pointer returns the string contents", "[to } TEST_CASE( "toString on wchar_t const pointer returns the string contents", "[toString]" ) { - wchar_t * const s = const_cast( L"wide load" ); + auto const s = const_cast( L"wide load" ); std::string result = ::Catch::Detail::stringify( s ); CHECK( result == "\"wide load\"" ); } TEST_CASE( "toString on wchar_t returns the string contents", "[toString]" ) { - wchar_t * s = const_cast( L"wide load" ); + auto s = const_cast( L"wide load" ); std::string result = ::Catch::Detail::stringify( s ); CHECK( result == "\"wide load\"" ); } +#endif TEST_CASE( "long long" ) { long long l = std::numeric_limits::max(); @@ -346,4 +350,9 @@ TEST_CASE( "#961 -- Dynamically created sections should all be reported", "[.]" } } +TEST_CASE( "#1175 - Hidden Test", "[.]" ) { + // Just for checking that hidden test is not listed by default + SUCCEED(); +} + }} // namespace MiscTests diff --git a/Telegram/ThirdParty/Catch/projects/SelfTest/UsageTests/ToStringChrono.tests.cpp b/Telegram/ThirdParty/Catch/projects/SelfTest/UsageTests/ToStringChrono.tests.cpp index 97d0c1cbd..c2c0829f0 100644 --- a/Telegram/ThirdParty/Catch/projects/SelfTest/UsageTests/ToStringChrono.tests.cpp +++ b/Telegram/ThirdParty/Catch/projects/SelfTest/UsageTests/ToStringChrono.tests.cpp @@ -20,8 +20,11 @@ TEST_CASE("Stringifying std::chrono::duration helpers", "[toString][chrono]") { TEST_CASE("Stringifying std::chrono::duration with weird ratios", "[toString][chrono]") { std::chrono::duration> half_minute(1); + std::chrono::duration> pico_second(1); std::chrono::duration> femto_second(1); + std::chrono::duration> atto_second(1); REQUIRE(half_minute != femto_second); + REQUIRE(pico_second != atto_second); } TEST_CASE("Stringifying std::chrono::time_point", "[toString][chrono]") { diff --git a/Telegram/ThirdParty/Catch/projects/SelfTest/UsageTests/ToStringGeneral.tests.cpp b/Telegram/ThirdParty/Catch/projects/SelfTest/UsageTests/ToStringGeneral.tests.cpp index 743882b16..8ab33249e 100644 --- a/Telegram/ThirdParty/Catch/projects/SelfTest/UsageTests/ToStringGeneral.tests.cpp +++ b/Telegram/ThirdParty/Catch/projects/SelfTest/UsageTests/ToStringGeneral.tests.cpp @@ -5,8 +5,11 @@ * file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) */ +#define CATCH_CONFIG_ENABLE_PAIR_STRINGMAKER #include "catch.hpp" +#include +#include TEST_CASE( "Character pretty printing" ){ SECTION("Specifically escaped"){ @@ -51,3 +54,64 @@ TEST_CASE( "Capture and info messages" ) { REQUIRE(true); } } + +TEST_CASE( "std::map is convertible string", "[toString]" ) { + + SECTION( "empty" ) { + std::map emptyMap; + + REQUIRE( Catch::Detail::stringify( emptyMap ) == "{ }" ); + } + + SECTION( "single item" ) { + std::map map = { { "one", 1 } }; + + REQUIRE( Catch::Detail::stringify( map ) == "{ { \"one\", 1 } }" ); + } + + SECTION( "several items" ) { + std::map map = { + { "abc", 1 }, + { "def", 2 }, + { "ghi", 3 } + }; + + REQUIRE( Catch::Detail::stringify( map ) == "{ { \"abc\", 1 }, { \"def\", 2 }, { \"ghi\", 3 } }" ); + } +} + +TEST_CASE( "std::set is convertible string", "[toString]" ) { + + SECTION( "empty" ) { + std::set emptySet; + + REQUIRE( Catch::Detail::stringify( emptySet ) == "{ }" ); + } + + SECTION( "single item" ) { + std::set set = { "one" }; + + REQUIRE( Catch::Detail::stringify( set ) == "{ \"one\" }" ); + } + + SECTION( "several items" ) { + std::set set = { "abc", "def", "ghi" }; + + REQUIRE( Catch::Detail::stringify( set ) == "{ \"abc\", \"def\", \"ghi\" }" ); + } +} + +TEST_CASE("Static arrays are convertible to string", "[toString]") { + SECTION("Single item") { + int singular[1] = { 1 }; + REQUIRE(Catch::Detail::stringify(singular) == "{ 1 }"); + } + SECTION("Multiple") { + int arr[3] = { 3, 2, 1 }; + REQUIRE(Catch::Detail::stringify(arr) == "{ 3, 2, 1 }"); + } + SECTION("Non-trivial inner items") { + std::vector arr[2] = { {"1:1", "1:2", "1:3"}, {"2:1", "2:2"} }; + REQUIRE(Catch::Detail::stringify(arr) == R"({ { "1:1", "1:2", "1:3" }, { "2:1", "2:2" } })"); + } +} diff --git a/Telegram/ThirdParty/Catch/projects/SelfTest/UsageTests/ToStringVector.tests.cpp b/Telegram/ThirdParty/Catch/projects/SelfTest/UsageTests/ToStringVector.tests.cpp index df9c55abd..63b49e502 100644 --- a/Telegram/ThirdParty/Catch/projects/SelfTest/UsageTests/ToStringVector.tests.cpp +++ b/Telegram/ThirdParty/Catch/projects/SelfTest/UsageTests/ToStringVector.tests.cpp @@ -1,8 +1,8 @@ #include "catch.hpp" #include +#include - -// vedctor +// vector TEST_CASE( "vector -> toString", "[toString][vector]" ) { std::vector vv; @@ -66,3 +66,21 @@ TEST_CASE( "vec> -> toString", "[toString][vector,allocator]" v.push_back( inner { "world" } ); REQUIRE( ::Catch::Detail::stringify(v) == "{ { \"hello\" }, { \"world\" } }" ); } + +// Based on PR by mat-so: https://github.com/catchorg/Catch2/pull/606/files#diff-43562f40f8c6dcfe2c54557316e0f852 +TEST_CASE( "vector -> toString", "[toString][containers][vector]" ) { + std::vector bools; + REQUIRE( ::Catch::Detail::stringify(bools) == "{ }"); + bools.push_back(true); + REQUIRE( ::Catch::Detail::stringify(bools) == "{ true }"); + bools.push_back(false); + REQUIRE( ::Catch::Detail::stringify(bools) == "{ true, false }"); +} +TEST_CASE( "array -> toString", "[toString][containers][array]" ) { + std::array empty; + REQUIRE( Catch::Detail::stringify( empty ) == "{ }" ); + std::array oneValue = {{ 42 }}; + REQUIRE( Catch::Detail::stringify( oneValue ) == "{ 42 }" ); + std::array twoValues = {{ 42, 250 }}; + REQUIRE( Catch::Detail::stringify( twoValues ) == "{ 42, 250 }" ); +} \ No newline at end of file diff --git a/Telegram/ThirdParty/Catch/projects/SelfTest/UsageTests/ToStringWhich.tests.cpp b/Telegram/ThirdParty/Catch/projects/SelfTest/UsageTests/ToStringWhich.tests.cpp index fc658a7a5..7be99dcd4 100644 --- a/Telegram/ThirdParty/Catch/projects/SelfTest/UsageTests/ToStringWhich.tests.cpp +++ b/Telegram/ThirdParty/Catch/projects/SelfTest/UsageTests/ToStringWhich.tests.cpp @@ -1,13 +1,25 @@ -#include "catch.hpp" /* - Demonstrate which version of toString/StringMaker is being used - for various types -*/ + * Demonstrate which version of toString/StringMaker is being used + * for various types + */ + +// Replace fallback stringifier for this TU +// We should avoid ODR violations because these specific types aren't +// present in different TUs +#include +template +std::string fallbackStringifier(T const&) { + return "{ !!! }"; +} + +#define CATCH_CONFIG_FALLBACK_STRINGIFIER fallbackStringifier +#include "catch.hpp" struct has_operator { }; struct has_maker {}; struct has_maker_and_operator {}; +struct has_neither {}; std::ostream& operator<<(std::ostream& os, const has_operator&) { os << "operator<<( has_operator )"; @@ -47,27 +59,102 @@ TEST_CASE( "stringify( has_maker )", "[toString]" ) { } // Call the stringmaker -TEST_CASE( "stringify( has_maker_and_toString )", "[.][toString]" ) { +TEST_CASE( "stringify( has_maker_and_operator )", "[toString]" ) { has_maker_and_operator item; REQUIRE( ::Catch::Detail::stringify( item ) == "StringMaker" ); } +TEST_CASE("stringify( has_neither )", "[toString]") { + has_neither item; + REQUIRE( ::Catch::Detail::stringify(item) == "{ !!! }" ); +} + + // Vectors... -// Don't run this in approval tests as it is sensitive to two phase lookup differences -TEST_CASE( "toString( vectors )", "[toString]" ) { std::vector v(1); REQUIRE( ::Catch::Detail::stringify( v ) == "{ operator<<( has_operator ) }" ); } -TEST_CASE( "toString( vectors )", "[toString]" ) { std::vector v(1); REQUIRE( ::Catch::Detail::stringify( v ) == "{ StringMaker }" ); } - -// Don't run this in approval tests as it is sensitive to two phase lookup differences -TEST_CASE( "toString( vectors )", "[toString]" ) { std::vector v(1); - REQUIRE( ::Catch::Detail::stringify( v ) == "{ StringMaker }" ); + REQUIRE( ::Catch::Detail::stringify( v ) == "{ StringMaker }" ); +} + +// Range-based conversion should only be used if other possibilities fail +struct int_iterator { + using iterator_category = std::input_iterator_tag; + using difference_type = std::ptrdiff_t; + using value_type = int; + using reference = int&; + using pointer = int*; + + int_iterator() = default; + int_iterator(int i) :val(i) {} + + value_type operator*() const { return val; } + bool operator==(int_iterator rhs) const { return val == rhs.val; } + bool operator!=(int_iterator rhs) const { return val != rhs.val; } + int_iterator operator++() { ++val; return *this; } + int_iterator operator++(int) { + auto temp(*this); + ++val; + return temp; + } +private: + int val = 5; +}; + +struct streamable_range { + int_iterator begin() const { return int_iterator{ 1 }; } + int_iterator end() const { return {}; } +}; + +std::ostream& operator<<(std::ostream& os, const streamable_range&) { + os << "op<<(streamable_range)"; + return os; +} + +struct stringmaker_range { + int_iterator begin() const { return int_iterator{ 1 }; } + int_iterator end() const { return {}; } +}; + +namespace Catch { +template <> +struct StringMaker { + static std::string convert(stringmaker_range const&) { + return "stringmaker(streamable_range)"; + } +}; +} + +struct just_range { + int_iterator begin() const { return int_iterator{ 1 }; } + int_iterator end() const { return {}; } +}; + +struct disabled_range { + int_iterator begin() const { return int_iterator{ 1 }; } + int_iterator end() const { return {}; } +}; + +namespace Catch { +template <> +struct is_range { + static const bool value = false; +}; +} + +TEST_CASE("stringify ranges", "[toString]") { + REQUIRE(::Catch::Detail::stringify(streamable_range{}) == "op<<(streamable_range)"); + REQUIRE(::Catch::Detail::stringify(stringmaker_range{}) == "stringmaker(streamable_range)"); + REQUIRE(::Catch::Detail::stringify(just_range{}) == "{ 1, 2, 3, 4 }"); + REQUIRE(::Catch::Detail::stringify(disabled_range{}) == "{ !!! }"); } diff --git a/Telegram/ThirdParty/Catch/projects/SelfTest/UsageTests/Tricky.tests.cpp b/Telegram/ThirdParty/Catch/projects/SelfTest/UsageTests/Tricky.tests.cpp index 79d2c63cf..1c352ce98 100644 --- a/Telegram/ThirdParty/Catch/projects/SelfTest/UsageTests/Tricky.tests.cpp +++ b/Telegram/ThirdParty/Catch/projects/SelfTest/UsageTests/Tricky.tests.cpp @@ -298,19 +298,19 @@ TEST_CASE( "Assertions then sections", "[Tricky]" ) // This was causing a failure due to the way the console reporter was handling // the current section - REQUIRE( Catch::alwaysTrue() ); + REQUIRE( true ); SECTION( "A section" ) { - REQUIRE( Catch::alwaysTrue() ); + REQUIRE( true ); SECTION( "Another section" ) { - REQUIRE( Catch::alwaysTrue() ); + REQUIRE( true ); } SECTION( "Another other section" ) { - REQUIRE( Catch::alwaysTrue() ); + REQUIRE( true ); } } } diff --git a/Telegram/ThirdParty/Catch/projects/XCode/OCTest/OCTest/OCTest.1 b/Telegram/ThirdParty/Catch/projects/XCode/OCTest/OCTest/OCTest.1 index 38afeb5f8..1cd333e29 100644 --- a/Telegram/ThirdParty/Catch/projects/XCode/OCTest/OCTest/OCTest.1 +++ b/Telegram/ThirdParty/Catch/projects/XCode/OCTest/OCTest/OCTest.1 @@ -61,9 +61,9 @@ FILE_2 description .\" .Sh DIAGNOSTICS \" May not be needed .\" .Bl -diag .\" .It Diagnostic Tag -.\" Diagnostic informtion here. +.\" Diagnostic information here. .\" .It Diagnostic Tag -.\" Diagnostic informtion here. +.\" Diagnostic information here. .\" .El .Sh SEE ALSO .\" List links in ascending order by section, alphabetically within a section. diff --git a/Telegram/ThirdParty/Catch/scripts/approvalTests.py b/Telegram/ThirdParty/Catch/scripts/approvalTests.py index 92a40a0e5..a2ab5d5a2 100755 --- a/Telegram/ThirdParty/Catch/scripts/approvalTests.py +++ b/Telegram/ThirdParty/Catch/scripts/approvalTests.py @@ -50,6 +50,8 @@ infParser = re.compile(r''' | \(__builtin_inff\(\)\) # Linux (ubuntu) INFINITY macro | + \(__builtin_inff\ \(\)\) # Fedora INFINITY macro + | __builtin_huge_valf\(\) # OSX macro ''', re.VERBOSE) nanParser = re.compile(r''' @@ -167,6 +169,8 @@ def approve(baseName, args): print("Running approvals against executable:") print(" " + cmdPath) + +### Keep default reporters here # Standard console reporter approve("console.std", ["~[!nonportable]~[!benchmark]~[approvals]", "--order", "lex"]) # console reporter, include passes, warn about No Assertions @@ -177,6 +181,8 @@ approve("console.swa4", ["~[!nonportable]~[!benchmark]~[approvals]", "-s", "-w", approve("junit.sw", ["~[!nonportable]~[!benchmark]~[approvals]", "-s", "-w", "NoAssertions", "-r", "junit", "--order", "lex"]) # xml reporter, include passes, warn about No Assertions approve("xml.sw", ["~[!nonportable]~[!benchmark]~[approvals]", "-s", "-w", "NoAssertions", "-r", "xml", "--order", "lex"]) +# compact reporter, include passes, warn about No Assertions +approve('compact.sw', ['~[!nonportable]~[!benchmark]~[approvals]', '-s', '-w', 'NoAssertions', '-r', 'compact', '--order', 'lex']) if overallResult != 0: print("If these differences are expected, run approve.py to approve new baselines.") diff --git a/Telegram/ThirdParty/Catch/scripts/embedClara.py b/Telegram/ThirdParty/Catch/scripts/embedClara.py old mode 100644 new mode 100755 index e7bb9335c..7ceb3e32e --- a/Telegram/ThirdParty/Catch/scripts/embedClara.py +++ b/Telegram/ThirdParty/Catch/scripts/embedClara.py @@ -1,3 +1,5 @@ +#!/usr/bin/env python + # Execute this script any time you import a new copy of Clara into the third_party area import os import sys diff --git a/Telegram/ThirdParty/Catch/scripts/generateSingleHeader.py b/Telegram/ThirdParty/Catch/scripts/generateSingleHeader.py index b1d186731..633e8c120 100755 --- a/Telegram/ThirdParty/Catch/scripts/generateSingleHeader.py +++ b/Telegram/ThirdParty/Catch/scripts/generateSingleHeader.py @@ -3,6 +3,7 @@ from __future__ import print_function import os +import io import sys import re import datetime @@ -46,11 +47,11 @@ def generate(v): outDir = os.path.dirname(outputPath) if not os.path.exists(outDir): os.makedirs(outDir) - out = open( outputPath, 'w' ) + out = io.open( outputPath, 'w', newline='\n') def write( line ): if globals['includeImpl'] or globals['implIfDefs'] == -1: - out.write( line ) + out.write( line.decode('utf-8') ) def insertCpps(): dirs = [os.path.join( rootPath, s) for s in ['', 'internal', 'reporters']] @@ -104,22 +105,22 @@ def generate(v): write( '// end {}\n'.format(filename) ) - out.write( "/*\n" ) - out.write( " * Catch v{0}\n".format( v.getVersionString() ) ) - out.write( " * Generated: {0}\n".format( datetime.datetime.now() ) ) - out.write( " * ----------------------------------------------------------\n" ) - out.write( " * This file has been merged from multiple headers. Please don't edit it directly\n" ) - out.write( " * Copyright (c) {} Two Blue Cubes Ltd. All rights reserved.\n".format( datetime.date.today().year ) ) - out.write( " *\n" ) - out.write( " * Distributed under the Boost Software License, Version 1.0. (See accompanying\n" ) - out.write( " * file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)\n" ) - out.write( " */\n" ) - out.write( "#ifndef TWOBLUECUBES_SINGLE_INCLUDE_CATCH_HPP_INCLUDED\n" ) - out.write( "#define TWOBLUECUBES_SINGLE_INCLUDE_CATCH_HPP_INCLUDED\n" ) + write( "/*\n" ) + write( " * Catch v{0}\n".format( v.getVersionString() ) ) + write( " * Generated: {0}\n".format( datetime.datetime.now() ) ) + write( " * ----------------------------------------------------------\n" ) + write( " * This file has been merged from multiple headers. Please don't edit it directly\n" ) + write( " * Copyright (c) {} Two Blue Cubes Ltd. All rights reserved.\n".format( datetime.date.today().year ) ) + write( " *\n" ) + write( " * Distributed under the Boost Software License, Version 1.0. (See accompanying\n" ) + write( " * file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)\n" ) + write( " */\n" ) + write( "#ifndef TWOBLUECUBES_SINGLE_INCLUDE_CATCH_HPP_INCLUDED\n" ) + write( "#define TWOBLUECUBES_SINGLE_INCLUDE_CATCH_HPP_INCLUDED\n" ) parseFile( rootPath, 'catch.hpp' ) - out.write( "#endif // TWOBLUECUBES_SINGLE_INCLUDE_CATCH_HPP_INCLUDED\n\n" ) + write( "#endif // TWOBLUECUBES_SINGLE_INCLUDE_CATCH_HPP_INCLUDED\n\n" ) out.close() print ("Generated single include for Catch v{0}\n".format( v.getVersionString() ) ) diff --git a/Telegram/ThirdParty/Catch/scripts/releaseCommon.py b/Telegram/ThirdParty/Catch/scripts/releaseCommon.py index 688b13ce7..6e44da240 100644 --- a/Telegram/ThirdParty/Catch/scripts/releaseCommon.py +++ b/Telegram/ThirdParty/Catch/scripts/releaseCommon.py @@ -10,6 +10,7 @@ from scriptCommon import catchPath versionParser = re.compile( r'(\s*static\sVersion\sversion)\s*\(\s*(.*)\s*,\s*(.*)\s*,\s*(.*)\s*,\s*\"(.*)\"\s*,\s*(.*)\s*\).*' ) rootPath = os.path.join( catchPath, 'include/' ) versionPath = os.path.join( rootPath, "internal/catch_version.cpp" ) +definePath = os.path.join(rootPath, 'catch.hpp') readmePath = os.path.join( catchPath, "README.md" ) conanPath = os.path.join(catchPath, 'conanfile.py') conanTestPath = os.path.join(catchPath, 'test_package', 'conanfile.py') @@ -80,7 +81,7 @@ class Version: def updateReadmeFile(version): import updateWandbox - downloadParser = re.compile( r'' ) + downloadParser = re.compile( r'' ) success, wandboxLink = updateWandbox.uploadFiles() if not success: print('Error when uploading to wandbox: {}'.format(wandboxLink)) @@ -92,7 +93,7 @@ def updateReadmeFile(version): f.close() f = open( readmePath, 'w' ) for line in lines: - line = downloadParser.sub( r''.format(version.getVersionString()) , line) + line = downloadParser.sub( r''.format(version.getVersionString()) , line) if '[![Try online](https://img.shields.io/badge/try-online-blue.svg)]' in line: line = '[![Try online](https://img.shields.io/badge/try-online-blue.svg)]({0})'.format(wandboxLink) f.write( line + "\n" ) @@ -128,24 +129,49 @@ def updateConanTestFile(version): f.write( line + "\n" ) def updateCmakeFile(version): - cmakeParser = re.compile(r'set(CATCH_VERSION_NUMBER \d+\.\d+\.\d+)') with open(cmakePath, 'r') as file: lines = file.readlines() with open(cmakePath, 'w') as file: for line in lines: - if 'set(CATCH_VERSION_NUMBER ' in line: - file.write('set(CATCH_VERSION_NUMBER {0})\n'.format(version.getVersionString())) + if 'project(Catch2 LANGUAGES CXX VERSION ' in line: + file.write('project(Catch2 LANGUAGES CXX VERSION {0})\n'.format(version.getVersionString())) else: file.write(line) + +def updateVersionDefine(version): + with open(definePath, 'r') as file: + lines = file.readlines() + with open(definePath, 'w') as file: + for line in lines: + if '#define CATCH_VERSION_MAJOR' in line: + file.write('#define CATCH_VERSION_MAJOR {}\n'.format(version.majorVersion)) + elif '#define CATCH_VERSION_MINOR' in line: + file.write('#define CATCH_VERSION_MINOR {}\n'.format(version.minorVersion)) + elif '#define CATCH_VERSION_PATCH' in line: + file.write('#define CATCH_VERSION_PATCH {}\n'.format(version.patchNumber)) + else: + file.write(line) + + def performUpdates(version): # First update version file, so we can regenerate single header and # have it ready for upload to wandbox, when updating readme version.updateVersionFile() - + updateVersionDefine(version) + import generateSingleHeader generateSingleHeader.generate(version) - + + # Then copy the reporters to single include folder to keep them in sync + # We probably should have some kind of convention to select which reporters need to be copied automagically, + # but this works for now + import shutil + for rep in ('automake', 'tap', 'teamcity'): + sourceFile = os.path.join(catchPath, 'include/reporters/catch_reporter_{}.hpp'.format(rep)) + destFile = os.path.join(catchPath, 'single_include/catch_reporter_{}.hpp'.format(rep)) + shutil.copyfile(sourceFile, destFile) + updateReadmeFile(version) updateConanFile(version) updateConanTestFile(version) diff --git a/Telegram/ThirdParty/Catch/scripts/updateDocumentToC.py b/Telegram/ThirdParty/Catch/scripts/updateDocumentToC.py index 948e5e1dd..e706c5c36 100644 --- a/Telegram/ThirdParty/Catch/scripts/updateDocumentToC.py +++ b/Telegram/ThirdParty/Catch/scripts/updateDocumentToC.py @@ -127,7 +127,7 @@ def tagAndCollect(lines, id_tag=True, back_links=False, exclude_h=None): A list of 3-value sublists, where the first value represents the heading, the second value the string that was inserted assigned to the IDs in the anchor tags, - and the third value is an integer that reprents the headline level. + and the third value is an integer that represents the headline level. E.g., [['some header lvl3', 'some-header-lvl3', 3], ...] @@ -282,7 +282,7 @@ def markdownToclify( input_file: str Path to the markdown input file. - output_file: str (defaul: None) + output_file: str (default: None) Path to the markdown output file. min_toc_len: int (default: 2) @@ -420,7 +420,7 @@ def updateDocumentToCMain(): default=minTocEntries, type=int, metavar='N', - help='the minimum number of entries to create a table of contents for [{deflt}]'.format(deflt=minTocEntries)) + help='the minimum number of entries to create a table of contents for [{default}]'.format(default=minTocEntries)) parser.add_argument( '--remove-toc', diff --git a/Telegram/ThirdParty/Catch/scripts/updateVcpkgPackage.py b/Telegram/ThirdParty/Catch/scripts/updateVcpkgPackage.py index 43f5bb4f6..fd7b759a0 100644 --- a/Telegram/ThirdParty/Catch/scripts/updateVcpkgPackage.py +++ b/Telegram/ThirdParty/Catch/scripts/updateVcpkgPackage.py @@ -8,7 +8,7 @@ from releaseCommon import Version print(catchPath) -default_path = '../vcpkg/ports/catch/' +default_path = '../vcpkg/ports/catch2/' def adjusted_path(path): return os.path.join(catchPath, path) @@ -89,7 +89,7 @@ def git_push(path_to_repo): # Make sure we branch off master subprocess.call('git checkout master', shell=True) - # Update repo to current master, so we don't work off old version of the portsfile + # Update repo to current master, so we don't work off old version of the portfile subprocess.call('git pull Microsoft master', shell=True) subprocess.call('git push', shell=True) diff --git a/Telegram/ThirdParty/Catch/single_include/catch.hpp b/Telegram/ThirdParty/Catch/single_include/catch.hpp index 362f8693f..c36a98784 100644 --- a/Telegram/ThirdParty/Catch/single_include/catch.hpp +++ b/Telegram/ThirdParty/Catch/single_include/catch.hpp @@ -1,9 +1,9 @@ /* - * Catch v2.0.1 - * Generated: 2017-11-03 11:53:39.642003 + * Catch v2.2.0 + * Generated: 2018-03-07 10:56:32.217228 * ---------------------------------------------------------- * This file has been merged from multiple headers. Please don't edit it directly - * Copyright (c) 2017 Two Blue Cubes Ltd. All rights reserved. + * Copyright (c) 2018 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) @@ -13,6 +13,10 @@ // start catch.hpp +#define CATCH_VERSION_MAJOR 2 +#define CATCH_VERSION_MINOR 2 +#define CATCH_VERSION_PATCH 0 + #ifdef __clang__ # pragma clang system_header #elif defined __GNUC__ @@ -26,9 +30,6 @@ # 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" @@ -36,27 +37,33 @@ # 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" - # pragma GCC diagnostic push # 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 +# define CATCH_CONFIG_ENABLE_CHRONO_STRINGMAKER #endif +#if !defined(CATCH_CONFIG_IMPL_ONLY) // start catch_platform.h #ifdef __APPLE__ # include -# if TARGET_OS_MAC == 1 +# if TARGET_OS_OSX == 1 # define CATCH_PLATFORM_MAC # elif TARGET_OS_IPHONE == 1 # define CATCH_PLATFORM_IPHONE @@ -70,6 +77,7 @@ #endif // end catch_platform.h + #ifdef CATCH_IMPL # ifndef CLARA_CONFIG_MAIN # define CLARA_CONFIG_MAIN_NOT_DEFINED @@ -77,6 +85,13 @@ # endif #endif +// start catch_user_interfaces.h + +namespace Catch { + unsigned int rngSeed(); +} + +// end catch_user_interfaces.h // start catch_tag_alias_autoregistrar.h // start catch_common.h @@ -105,6 +120,14 @@ # define CATCH_CPP14_OR_GREATER # endif +# if __cplusplus >= 201703L +# define CATCH_CPP17_OR_GREATER +# endif + +#endif + +#if defined(CATCH_CPP17_OR_GREATER) +# define CATCH_INTERNAL_CONFIG_CPP17_UNCAUGHT_EXCEPTIONS #endif #ifdef __clang__ @@ -124,14 +147,16 @@ #endif // __clang__ +//////////////////////////////////////////////////////////////////////////////// +// 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__) - -# if !defined(CATCH_CONFIG_POSIX_SIGNALS) -# define CATCH_INTERNAL_CONFIG_NO_POSIX_SIGNALS -# endif - +#if defined(__CYGWIN__) || defined(__QNX__) || defined(__EMSCRIPTEN__) || defined(__DJGPP__) + #define CATCH_INTERNAL_CONFIG_NO_POSIX_SIGNALS #endif #ifdef __OS400__ @@ -153,6 +178,10 @@ // Visual C++ #ifdef _MSC_VER +# if _MSC_VER >= 1900 // Visual Studio 2015 or newer +# define CATCH_INTERNAL_CONFIG_CPP17_UNCAUGHT_EXCEPTIONS +# endif + // Universal Windows platform does not support SEH // Or console colours (or console at all...) # if defined(WINAPI_FAMILY) && (WINAPI_FAMILY == WINAPI_FAMILY_APP) @@ -165,6 +194,13 @@ //////////////////////////////////////////////////////////////////////////////// +// DJGPP +#ifdef __DJGPP__ +# define CATCH_INTERNAL_CONFIG_NO_WCHAR +#endif // __DJGPP__ + +//////////////////////////////////////////////////////////////////////////////// + // Use of __COUNTER__ is suppressed during code analysis in // CLion/AppCode 2017.2.x and former, because __COUNTER__ is not properly // handled by it. @@ -181,9 +217,17 @@ # 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_NO_POSIX_SIGNALS) && !defined(CATCH_CONFIG_NO_POSIX_SIGNALS) && !defined(CATCH_CONFIG_POSIX_SIGNALS) +#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 + +#if defined(CATCH_INTERNAL_CONFIG_CPP17_UNCAUGHT_EXCEPTIONS) && !defined(CATCH_CONFIG_NO_CPP17_UNCAUGHT_EXCEPTIONS) && !defined(CATCH_CONFIG_CPP17_UNCAUGHT_EXCEPTIONS) +# define CATCH_CONFIG_CPP17_UNCAUGHT_EXCEPTIONS +#endif #if !defined(CATCH_INTERNAL_SUPPRESS_PARENTHESES_WARNINGS) # define CATCH_INTERNAL_SUPPRESS_PARENTHESES_WARNINGS @@ -228,7 +272,10 @@ namespace Catch { struct SourceLineInfo { SourceLineInfo() = delete; - SourceLineInfo( char const* _file, std::size_t _line ) noexcept; + SourceLineInfo( char const* _file, std::size_t _line ) noexcept + : file( _file ), + line( _line ) + {} SourceLineInfo( SourceLineInfo const& other ) = default; SourceLineInfo( SourceLineInfo && ) = default; @@ -245,11 +292,6 @@ 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 - bool isTrue( bool value ); - bool alwaysTrue(); - bool alwaysFalse(); - // Use this in variadic streaming macros to allow // >> +StreamEndStop // as well as @@ -275,7 +317,10 @@ namespace Catch { } // end namespace Catch -#define CATCH_REGISTER_TAG_ALIAS( alias, spec ) namespace{ Catch::RegistrarForTagAliases INTERNAL_CATCH_UNIQUE_NAME( AutoRegisterTagAlias )( alias, spec, CATCH_INTERNAL_LINEINFO ); } +#define CATCH_REGISTER_TAG_ALIAS( alias, spec ) \ + CATCH_INTERNAL_SUPPRESS_GLOBALS_WARNINGS \ + namespace{ Catch::RegistrarForTagAliases INTERNAL_CATCH_UNIQUE_NAME( AutoRegisterTagAlias )( alias, spec, CATCH_INTERNAL_LINEINFO ); } \ + CATCH_INTERNAL_UNSUPPRESS_GLOBALS_WARNINGS // end catch_tag_alias_autoregistrar.h // start catch_test_registry.h @@ -330,10 +375,12 @@ namespace Catch { /// visible - but it does mean (substring) StringRefs should not be shared between /// threads. class StringRef { - friend struct StringRefTestAccess; - + public: using size_type = std::size_t; + private: + friend struct StringRefTestAccess; + char const* m_start; size_type m_size; @@ -341,16 +388,50 @@ namespace Catch { void takeOwnership(); - public: // construction/ assignment - StringRef() noexcept; - StringRef( StringRef const& other ) noexcept; - StringRef( StringRef&& other ) noexcept; - StringRef( char const* rawChars ) noexcept; - StringRef( char const* rawChars, size_type size ) noexcept; - StringRef( std::string const& stdString ) noexcept; - ~StringRef() noexcept; + static constexpr char const* const s_empty = ""; + + public: // construction/ assignment + StringRef() noexcept + : StringRef( s_empty, 0 ) + {} + + StringRef( StringRef const& other ) noexcept + : m_start( other.m_start ), + m_size( other.m_size ) + {} + + StringRef( StringRef&& other ) noexcept + : m_start( other.m_start ), + m_size( other.m_size ), + m_data( other.m_data ) + { + other.m_data = nullptr; + } + + StringRef( char const* rawChars ) noexcept; + + 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() ) + {} + + ~StringRef() noexcept { + delete[] m_data; + } + + auto operator = ( StringRef const &other ) noexcept -> StringRef& { + delete[] m_data; + m_data = nullptr; + m_start = other.m_start; + m_size = other.m_size; + return *this; + } - auto operator = ( StringRef other ) noexcept -> StringRef&; operator std::string() const; void swap( StringRef& other ) noexcept; @@ -362,26 +443,39 @@ namespace Catch { auto operator[] ( size_type index ) const noexcept -> char; public: // named queries - auto empty() const noexcept -> bool; - auto size() const noexcept -> size_type; + auto empty() const noexcept -> bool { + return m_size == 0; + } + auto size() const noexcept -> size_type { + return m_size; + } + auto numberOfCharacters() const noexcept -> size_type; auto c_str() const -> char const*; public: // substrings and searches auto substr( size_type start, size_type size ) const noexcept -> StringRef; + // Returns the current start pointer. + // Note that the pointer can change when if the StringRef is a substring + auto currentData() const noexcept -> char const*; + private: // ownership queries - may not be consistent between calls auto isOwned() const noexcept -> bool; auto isSubstring() const noexcept -> bool; - auto data() const noexcept -> char const*; }; auto operator + ( StringRef const& lhs, StringRef const& rhs ) -> std::string; auto operator + ( StringRef const& lhs, char const* rhs ) -> std::string; auto operator + ( char const* lhs, StringRef const& rhs ) -> std::string; + auto operator += ( std::string& lhs, StringRef const& sr ) -> std::string&; auto operator << ( std::ostream& os, StringRef const& sr ) -> std::ostream&; + inline auto operator "" _sr( char const* rawChars, std::size_t size ) noexcept -> StringRef { + return StringRef( rawChars, size ); + } + } // namespace Catch // end catch_stringref.h @@ -407,13 +501,13 @@ auto makeTestInvoker( void (C::*testAsMethod)() ) noexcept -> ITestInvoker* { } struct NameAndTags { - NameAndTags( StringRef name_ = "", StringRef tags_ = "" ) noexcept; + NameAndTags( StringRef const& name_ = StringRef(), StringRef const& tags_ = StringRef() ) noexcept; StringRef name; StringRef tags; }; struct AutoReg : NonCopyable { - AutoReg( ITestInvoker* invoker, SourceLineInfo const& lineInfo, StringRef classOrMethod, NameAndTags const& nameAndTags ) noexcept; + AutoReg( ITestInvoker* invoker, SourceLineInfo const& lineInfo, StringRef const& classOrMethod, NameAndTags const& nameAndTags ) noexcept; ~AutoReg(); }; @@ -473,15 +567,121 @@ struct AutoReg : NonCopyable { // start catch_assertionhandler.h +// start catch_assertioninfo.h + +// start catch_result_type.h + +namespace Catch { + + // ResultWas::OfType enum + struct ResultWas { enum OfType { + Unknown = -1, + Ok = 0, + Info = 1, + Warning = 2, + + FailureBit = 0x10, + + ExpressionFailed = FailureBit | 1, + ExplicitFailure = FailureBit | 2, + + Exception = 0x100 | FailureBit, + + ThrewException = Exception | 1, + DidntThrowException = Exception | 2, + + FatalErrorCondition = 0x200 | FailureBit + + }; }; + + bool isOk( ResultWas::OfType resultType ); + bool isJustInfo( int flags ); + + // ResultDisposition::Flags enum + struct ResultDisposition { enum Flags { + Normal = 0x01, + + ContinueOnFailure = 0x02, // Failures fail test, but execution continues + FalseTest = 0x04, // Prefix expression with ! + SuppressFail = 0x08 // Failures are reported but do not fail the test + }; }; + + ResultDisposition::Flags operator | ( ResultDisposition::Flags lhs, ResultDisposition::Flags rhs ); + + bool shouldContinueOnFailure( int flags ); + inline bool isFalseTest( int flags ) { return ( flags & ResultDisposition::FalseTest ) != 0; } + bool shouldSuppressFailure( int flags ); + +} // end namespace Catch + +// end catch_result_type.h +namespace Catch { + + struct AssertionInfo + { + StringRef macroName; + SourceLineInfo lineInfo; + StringRef capturedExpression; + ResultDisposition::Flags resultDisposition; + + // We want to delete this constructor but a compiler bug in 4.8 means + // the struct is then treated as non-aggregate + //AssertionInfo() = delete; + }; + +} // end namespace Catch + +// end catch_assertioninfo.h // start catch_decomposer.h // start catch_tostring.h -#include #include #include #include #include +// start catch_stream.h + +#include +#include +#include + +namespace Catch { + + std::ostream& cout(); + std::ostream& cerr(); + std::ostream& clog(); + + class StringRef; + + struct IStream { + virtual ~IStream(); + virtual std::ostream& stream() const = 0; + }; + + auto makeStream( StringRef const &filename ) -> IStream const*; + + class ReusableStringStream { + std::size_t m_index; + std::ostream* m_oss; + public: + ReusableStringStream(); + ~ReusableStringStream(); + + auto str() const -> std::string; + + template + auto operator << ( T const& value ) -> ReusableStringStream& { + *m_oss << value; + return *this; + } + auto get() -> std::ostream& { return *m_oss; } + + static void cleanup(); + }; +} + +// end catch_stream.h #ifdef __OBJC__ // start catch_objc_arc.hpp @@ -535,7 +735,7 @@ inline id performOptionalSelector( id obj, SEL sel ) { #endif // We need a dummy global operator<< so we can bring it into Catch namespace later -struct Catch_global_namespace_dummy; +struct Catch_global_namespace_dummy {}; std::ostream& operator<<(std::ostream&, Catch_global_namespace_dummy); namespace Catch { @@ -566,25 +766,42 @@ namespace Catch { static const bool value = decltype(test(0))::value; }; + template + std::string convertUnknownEnumToString( E e ); + + template + typename std::enable_if::value, std::string>::type convertUnstreamable( T const& value ) { +#if !defined(CATCH_CONFIG_FALLBACK_STRINGIFIER) + (void)value; + return Detail::unprintableString; +#else + return CATCH_CONFIG_FALLBACK_STRINGIFIER(value); +#endif + } + template + typename std::enable_if::value, std::string>::type convertUnstreamable( T const& value ) { + return convertUnknownEnumToString( value ); + } + } // namespace Detail // If we decide for C++14, change these to enable_if_ts - template + template struct StringMaker { template static typename std::enable_if<::Catch::Detail::IsStreamInsertable::value, std::string>::type - convert(const Fake& t) { - std::ostringstream sstr; - sstr << t; - return sstr.str(); + convert(const Fake& value) { + ReusableStringStream rss; + rss << value; + return rss.str(); } template static typename std::enable_if::value, std::string>::type - convert(const Fake&) { - return Detail::unprintableString; + convert( const Fake& value ) { + return Detail::convertUnstreamable( value ); } }; @@ -597,6 +814,11 @@ namespace Catch { return ::Catch::StringMaker::type>::type>::convert(e); } + template + std::string convertUnknownEnumToString( E e ) { + return ::Catch::Detail::stringify(static_cast::type>(e)); + } + } // namespace Detail // Some predefined specializations @@ -605,10 +827,12 @@ namespace Catch { struct StringMaker { static std::string convert(const std::string& str); }; +#ifdef CATCH_CONFIG_WCHAR template<> struct StringMaker { static std::string convert(const std::wstring& wstr); }; +#endif template<> struct StringMaker { @@ -618,6 +842,7 @@ namespace Catch { struct StringMaker { static std::string convert(char * str); }; +#ifdef CATCH_CONFIG_WCHAR template<> struct StringMaker { static std::string convert(wchar_t const * str); @@ -626,6 +851,7 @@ namespace Catch { struct StringMaker { static std::string convert(wchar_t * str); }; +#endif template struct StringMaker { @@ -729,32 +955,18 @@ namespace Catch { namespace Detail { template std::string rangeToString(InputIterator first, InputIterator last) { - std::ostringstream oss; - oss << "{ "; + ReusableStringStream rss; + rss << "{ "; if (first != last) { - oss << ::Catch::Detail::stringify(*first); + rss << ::Catch::Detail::stringify(*first); for (++first; first != last; ++first) - oss << ", " << ::Catch::Detail::stringify(*first); + rss << ", " << ::Catch::Detail::stringify(*first); } - oss << " }"; - return oss.str(); + rss << " }"; + return rss.str(); } } - template - struct StringMaker > { - static std::string convert( std::vector const& v ) { - return ::Catch::Detail::rangeToString( v.begin(), v.end() ); - } - }; - - template - struct EnumStringMaker { - static std::string convert(const T& t) { - return ::Catch::Detail::stringify(static_cast::type>(t)); - } - }; - #ifdef __OBJC__ template<> struct StringMaker { @@ -798,13 +1010,13 @@ namespace Catch { template struct StringMaker > { static std::string convert(const std::pair& pair) { - std::ostringstream oss; - oss << "{ " + ReusableStringStream rss; + rss << "{ " << ::Catch::Detail::stringify(pair.first) << ", " << ::Catch::Detail::stringify(pair.second) << " }"; - return oss.str(); + return rss.str(); } }; } @@ -841,22 +1053,79 @@ namespace Catch { template struct StringMaker> { static std::string convert(const std::tuple& tuple) { - std::ostringstream os; - os << '{'; - Detail::TupleElementPrinter>::print(tuple, os); - os << " }"; - return os.str(); + ReusableStringStream rss; + rss << '{'; + Detail::TupleElementPrinter>::print(tuple, rss.get()); + rss << " }"; + return rss.str(); } }; } #endif // CATCH_CONFIG_ENABLE_TUPLE_STRINGMAKER +namespace Catch { + struct not_this_one {}; // Tag type for detecting which begin/ end are being selected + + // Import begin/ end from std here so they are considered alongside the fallback (...) overloads in this namespace + using std::begin; + using std::end; + + not_this_one begin( ... ); + not_this_one end( ... ); + + template + struct is_range { + static const bool value = + !std::is_same())), not_this_one>::value && + !std::is_same())), not_this_one>::value; + }; + + template + std::string rangeToString( Range const& range ) { + return ::Catch::Detail::rangeToString( begin( range ), end( range ) ); + } + + // Handle vector specially + template + std::string rangeToString( std::vector 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 + struct StringMaker::value && !::Catch::Detail::IsStreamInsertable::value>::type> { + static std::string convert( R const& range ) { + return rangeToString( range ); + } + }; + + template + struct StringMaker { + static std::string convert(T const(&arr)[SZ]) { + return rangeToString(arr); + } + }; + +} // namespace Catch + // Separate std::chrono::duration specialization #if defined(CATCH_CONFIG_ENABLE_CHRONO_STRINGMAKER) #include #include #include +namespace Catch { + template struct ratio_string { static std::string symbol(); @@ -864,69 +1133,68 @@ struct ratio_string { template std::string ratio_string::symbol() { - std::ostringstream oss; - oss << '[' << Ratio::num << '/' + Catch::ReusableStringStream rss; + rss << '[' << Ratio::num << '/' << Ratio::den << ']'; - return oss.str(); + return rss.str(); } template <> struct ratio_string { - static std::string symbol() { return "a"; } + static std::string symbol(); }; template <> struct ratio_string { - static std::string symbol() { return "f"; } + static std::string symbol(); }; template <> struct ratio_string { - static std::string symbol() { return "p"; } + static std::string symbol(); }; template <> struct ratio_string { - static std::string symbol() { return "n"; } + static std::string symbol(); }; template <> struct ratio_string { - static std::string symbol() { return "u"; } + static std::string symbol(); }; template <> struct ratio_string { - static std::string symbol() { return "m"; } + static std::string symbol(); }; -namespace Catch { //////////// // std::chrono::duration specializations template struct StringMaker> { static std::string convert(std::chrono::duration const& duration) { - std::ostringstream oss; - oss << duration.count() << ' ' << ratio_string::symbol() << 's'; - return oss.str(); + ReusableStringStream rss; + rss << duration.count() << ' ' << ratio_string::symbol() << 's'; + return rss.str(); } }; template struct StringMaker>> { static std::string convert(std::chrono::duration> const& duration) { - std::ostringstream oss; - oss << duration.count() << " s"; - return oss.str(); + ReusableStringStream rss; + rss << duration.count() << " s"; + return rss.str(); } }; template struct StringMaker>> { static std::string convert(std::chrono::duration> const& duration) { - std::ostringstream oss; - oss << duration.count() << " m"; - return oss.str(); + ReusableStringStream rss; + rss << duration.count() << " m"; + return rss.str(); } }; template struct StringMaker>> { static std::string convert(std::chrono::duration> const& duration) { - std::ostringstream oss; - oss << duration.count() << " h"; - return oss.str(); + ReusableStringStream rss; + rss << duration.count() << " h"; + return rss.str(); } }; @@ -972,7 +1240,7 @@ namespace Catch { #endif // end catch_tostring.h -#include +#include #ifdef _MSC_VER #pragma warning(push) @@ -985,27 +1253,32 @@ namespace Catch { namespace Catch { struct ITransientExpression { - virtual auto isBinaryExpression() const -> bool = 0; - virtual auto getResult() const -> bool = 0; + auto isBinaryExpression() const -> bool { return m_isBinaryExpression; } + auto getResult() const -> bool { return m_result; } virtual void streamReconstructedExpression( std::ostream &os ) const = 0; - // We don't actually need a virtual destructore, but many static analysers + ITransientExpression( bool isBinaryExpression, bool result ) + : m_isBinaryExpression( isBinaryExpression ), + m_result( result ) + {} + + // 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; + }; void formatReconstructedExpression( std::ostream &os, std::string const& lhs, StringRef op, std::string const& rhs ); template class BinaryExpr : public ITransientExpression { - bool m_result; LhsT m_lhs; StringRef m_op; RhsT m_rhs; - auto isBinaryExpression() const -> bool override { return true; } - auto getResult() const -> bool override { return m_result; } - void streamReconstructedExpression( std::ostream &os ) const override { formatReconstructedExpression ( os, Catch::Detail::stringify( m_lhs ), m_op, Catch::Detail::stringify( m_rhs ) ); @@ -1013,7 +1286,7 @@ namespace Catch { public: BinaryExpr( bool comparisonResult, LhsT lhs, StringRef op, RhsT rhs ) - : m_result( comparisonResult ), + : ITransientExpression{ true, comparisonResult }, m_lhs( lhs ), m_op( op ), m_rhs( rhs ) @@ -1024,20 +1297,20 @@ namespace Catch { class UnaryExpr : public ITransientExpression { LhsT m_lhs; - auto isBinaryExpression() const -> bool override { return false; } - auto getResult() const -> bool override { return m_lhs ? true : false; } - void streamReconstructedExpression( std::ostream &os ) const override { os << Catch::Detail::stringify( m_lhs ); } public: - UnaryExpr( LhsT lhs ) : m_lhs( lhs ) {} + explicit UnaryExpr( LhsT lhs ) + : ITransientExpression{ false, lhs ? true : false }, + m_lhs( lhs ) + {} }; // Specialised comparison functions to handle equality comparisons between ints and pointers (NULL deduces as an int) template - auto compareEqual( LhsT const& lhs, RhsT const& rhs ) -> bool { return lhs == rhs; }; + auto compareEqual( LhsT const& lhs, RhsT const& rhs ) -> bool { return static_cast(lhs == rhs); } template auto compareEqual( T* const& lhs, int rhs ) -> bool { return lhs == reinterpret_cast( rhs ); } template @@ -1048,7 +1321,7 @@ namespace Catch { auto compareEqual( long lhs, T* const& rhs ) -> bool { return reinterpret_cast( lhs ) == rhs; } template - auto compareNotEqual( LhsT const& lhs, RhsT&& rhs ) -> bool { return lhs != rhs; }; + auto compareNotEqual( LhsT const& lhs, RhsT&& rhs ) -> bool { return static_cast(lhs != rhs); } template auto compareNotEqual( T* const& lhs, int rhs ) -> bool { return lhs != reinterpret_cast( rhs ); } template @@ -1062,43 +1335,43 @@ namespace Catch { class ExprLhs { LhsT m_lhs; public: - ExprLhs( LhsT lhs ) : m_lhs( lhs ) {} + explicit ExprLhs( LhsT lhs ) : m_lhs( lhs ) {} template auto operator == ( RhsT const& rhs ) -> BinaryExpr const { - return BinaryExpr( compareEqual( m_lhs, rhs ), m_lhs, "==", rhs ); + return { compareEqual( m_lhs, rhs ), m_lhs, "==", rhs }; } auto operator == ( bool rhs ) -> BinaryExpr const { - return BinaryExpr( m_lhs == rhs, m_lhs, "==", rhs ); + return { m_lhs == rhs, m_lhs, "==", rhs }; } template auto operator != ( RhsT const& rhs ) -> BinaryExpr const { - return BinaryExpr( compareNotEqual( m_lhs, rhs ), m_lhs, "!=", rhs ); + return { compareNotEqual( m_lhs, rhs ), m_lhs, "!=", rhs }; } auto operator != ( bool rhs ) -> BinaryExpr const { - return BinaryExpr( m_lhs != rhs, m_lhs, "!=", rhs ); + return { m_lhs != rhs, m_lhs, "!=", rhs }; } template auto operator > ( RhsT const& rhs ) -> BinaryExpr const { - return BinaryExpr( m_lhs > rhs, m_lhs, ">", rhs ); + return { static_cast(m_lhs > rhs), m_lhs, ">", rhs }; } template auto operator < ( RhsT const& rhs ) -> BinaryExpr const { - return BinaryExpr( m_lhs < rhs, m_lhs, "<", rhs ); + return { static_cast(m_lhs < rhs), m_lhs, "<", rhs }; } template auto operator >= ( RhsT const& rhs ) -> BinaryExpr const { - return BinaryExpr( m_lhs >= rhs, m_lhs, ">=", rhs ); + return { static_cast(m_lhs >= rhs), m_lhs, ">=", rhs }; } template auto operator <= ( RhsT const& rhs ) -> BinaryExpr const { - return BinaryExpr( m_lhs <= rhs, m_lhs, "<=", rhs ); + return { static_cast(m_lhs <= rhs), m_lhs, "<=", rhs }; } auto makeUnaryExpr() const -> UnaryExpr { - return UnaryExpr( m_lhs ); + return UnaryExpr{ m_lhs }; } }; @@ -1112,10 +1385,11 @@ namespace Catch { struct Decomposer { template auto operator <= ( T const& lhs ) -> ExprLhs { - return ExprLhs( lhs ); + return ExprLhs{ lhs }; } + auto operator <=( bool value ) -> ExprLhs { - return ExprLhs( value ); + return ExprLhs{ value }; } }; @@ -1126,79 +1400,88 @@ namespace Catch { #endif // end catch_decomposer.h -// start catch_assertioninfo.h +// start catch_interfaces_capture.h -// start catch_result_type.h +#include namespace Catch { - // ResultWas::OfType enum - struct ResultWas { enum OfType { - Unknown = -1, - Ok = 0, - Info = 1, - Warning = 2, + class AssertionResult; + struct AssertionInfo; + struct SectionInfo; + struct SectionEndInfo; + struct MessageInfo; + struct Counts; + struct BenchmarkInfo; + struct BenchmarkStats; + struct AssertionReaction; - FailureBit = 0x10, + struct ITransientExpression; - ExpressionFailed = FailureBit | 1, - ExplicitFailure = FailureBit | 2, + struct IResultCapture { - Exception = 0x100 | FailureBit, + virtual ~IResultCapture(); - ThrewException = Exception | 1, - DidntThrowException = Exception | 2, + virtual bool sectionStarted( SectionInfo const& sectionInfo, + Counts& assertions ) = 0; + virtual void sectionEnded( SectionEndInfo const& endInfo ) = 0; + virtual void sectionEndedEarly( SectionEndInfo const& endInfo ) = 0; - FatalErrorCondition = 0x200 | FailureBit + virtual void benchmarkStarting( BenchmarkInfo const& info ) = 0; + virtual void benchmarkEnded( BenchmarkStats const& stats ) = 0; - }; }; + virtual void pushScopedMessage( MessageInfo const& message ) = 0; + virtual void popScopedMessage( MessageInfo const& message ) = 0; - bool isOk( ResultWas::OfType resultType ); - bool isJustInfo( int flags ); + virtual void handleFatalErrorCondition( StringRef message ) = 0; - // ResultDisposition::Flags enum - struct ResultDisposition { enum Flags { - Normal = 0x01, + 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; - ContinueOnFailure = 0x02, // Failures fail test, but execution continues - FalseTest = 0x04, // Prefix expression with ! - SuppressFail = 0x08 // Failures are reported but do not fail the test - }; }; + virtual bool lastAssertionPassed() = 0; + virtual void assertionPassed() = 0; - ResultDisposition::Flags operator | ( ResultDisposition::Flags lhs, ResultDisposition::Flags rhs ); - - bool shouldContinueOnFailure( int flags ); - bool isFalseTest( int flags ); - bool shouldSuppressFailure( int flags ); - -} // end namespace Catch - -// end catch_result_type.h -namespace Catch { - - struct AssertionInfo - { - StringRef macroName; - SourceLineInfo lineInfo; - StringRef capturedExpression; - ResultDisposition::Flags resultDisposition; - - // We want to delete this constructor but a compiler bug in 4.8 means - // the struct is then treated as non-aggregate - //AssertionInfo() = delete; + // Deprecated, do not use: + virtual std::string getCurrentTestName() const = 0; + virtual const AssertionResult* getLastResult() const = 0; + virtual void exceptionEarlyReported() = 0; }; -} // end namespace Catch + IResultCapture& getResultCapture(); +} -// end catch_assertioninfo.h +// end catch_interfaces_capture.h namespace Catch { struct TestFailureException{}; struct AssertionResultData; + struct IResultCapture; + class RunContext; class LazyExpression { friend class AssertionHandler; friend struct AssertionStats; + friend class RunContext; ITransientExpression const* m_transientExpression = nullptr; bool m_isNegated; @@ -1212,11 +1495,16 @@ namespace Catch { friend auto operator << ( std::ostream& os, LazyExpression const& lazyExpr ) -> std::ostream&; }; + struct AssertionReaction { + bool shouldDebugBreak = false; + bool shouldThrow = false; + }; + class AssertionHandler { AssertionInfo m_assertionInfo; - bool m_shouldDebugBreak = false; - bool m_shouldThrow = false; - bool m_inExceptionGuard = false; + AssertionReaction m_reaction; + bool m_completed = false; + IResultCapture& m_resultCapture; public: AssertionHandler @@ -1224,26 +1512,31 @@ namespace Catch { SourceLineInfo const& lineInfo, StringRef capturedExpression, ResultDisposition::Flags resultDisposition ); - ~AssertionHandler(); - - void handle( ITransientExpression const& expr ); + ~AssertionHandler() { + if ( !m_completed ) { + m_resultCapture.handleIncomplete( m_assertionInfo ); + } + } template - void handle( ExprLhs const& expr ) { - handle( expr.makeUnaryExpr() ); + void handleExpr( ExprLhs const& expr ) { + handleExpr( expr.makeUnaryExpr() ); } - void handle( ResultWas::OfType resultType ); - void handle( ResultWas::OfType resultType, StringRef const& message ); - void handle( ResultWas::OfType resultType, ITransientExpression const* expr, bool negated ); - void handle( AssertionResultData const& resultData, ITransientExpression const* expr ); + void handleExpr( ITransientExpression const& expr ); - auto shouldDebugBreak() const -> bool; + 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 reactWithDebugBreak() const; - void reactWithoutDebugBreak() const; - void useActiveException(); - void setExceptionGuard(); - void unsetExceptionGuard(); }; void handleExceptionMatchExpr( AssertionHandler& handler, std::string const& str, StringRef matcherString ); @@ -1254,7 +1547,6 @@ namespace Catch { // start catch_message.h #include -#include namespace Catch { @@ -1283,8 +1575,7 @@ namespace Catch { return *this; } - // !TBD reuse a global/ thread-local stream - std::ostringstream m_stream; + ReusableStringStream m_stream; }; struct MessageBuilder : MessageStream { @@ -1303,7 +1594,7 @@ namespace Catch { class ScopedMessage { public: - ScopedMessage( MessageBuilder const& builder ); + explicit ScopedMessage( MessageBuilder const& builder ); ~ScopedMessage(); MessageInfo m_info; @@ -1312,89 +1603,6 @@ namespace Catch { } // end namespace Catch // end catch_message.h -// start catch_interfaces_capture.h - -#include - -namespace Catch { - - class AssertionResult; - struct AssertionInfo; - struct SectionInfo; - struct SectionEndInfo; - struct MessageInfo; - struct Counts; - struct BenchmarkInfo; - struct BenchmarkStats; - - struct IResultCapture { - - virtual ~IResultCapture(); - - virtual void assertionStarting( AssertionInfo const& info ) = 0; - 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 benchmarkStarting( BenchmarkInfo const& info ) = 0; - virtual void benchmarkEnded( BenchmarkStats const& stats ) = 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 void exceptionEarlyReported() = 0; - - virtual void handleFatalErrorCondition( StringRef message ) = 0; - - virtual bool lastAssertionPassed() = 0; - virtual void assertionPassed() = 0; - virtual void assertionRun() = 0; - }; - - IResultCapture& getResultCapture(); -} - -// end catch_interfaces_capture.h -// start catch_debugger.h - -namespace Catch { - bool isDebuggerActive(); -} - -#ifdef CATCH_PLATFORM_MAC - - #define CATCH_TRAP() __asm__("int $3\n" : : ) /* NOLINT */ - -#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 - - #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 - -#ifdef CATCH_TRAP - #define CATCH_BREAK_INTO_DEBUGGER() if( Catch::isDebuggerActive() ) { CATCH_TRAP(); } -#else - #define CATCH_BREAK_INTO_DEBUGGER() Catch::alwaysTrue(); -#endif - -// end catch_debugger.h #if !defined(CATCH_CONFIG_DISABLE) #if !defined(CATCH_CONFIG_DISABLE_STRINGIFICATION) @@ -1404,48 +1612,33 @@ namespace Catch { #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( handler ) \ - handler.reactWithDebugBreak(); /////////////////////////////////////////////////////////////////////////////// // 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_TRY( capturer ) capturer.setExceptionGuard(); -#define INTERNAL_CATCH_CATCH( capturer ) capturer.unsetExceptionGuard(); +#define INTERNAL_CATCH_TRY +#define INTERNAL_CATCH_CATCH( capturer ) #else // CATCH_CONFIG_FAST_COMPILE -/////////////////////////////////////////////////////////////////////////////// -// 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( handler ) \ - if( handler.shouldDebugBreak() ) CATCH_BREAK_INTO_DEBUGGER(); \ - handler.reactWithoutDebugBreak(); - -#define INTERNAL_CATCH_TRY( capturer ) try -#define INTERNAL_CATCH_CATCH( capturer ) catch(...) { capturer.useActiveException(); } +#define INTERNAL_CATCH_TRY try +#define INTERNAL_CATCH_CATCH( handler ) catch(...) { handler.handleUnexpectedInflightException(); } #endif +#define INTERNAL_CATCH_REACT( handler ) handler.complete(); + /////////////////////////////////////////////////////////////////////////////// #define INTERNAL_CATCH_TEST( macroName, resultDisposition, ... ) \ do { \ Catch::AssertionHandler catchAssertionHandler( macroName, CATCH_INTERNAL_LINEINFO, CATCH_INTERNAL_STRINGIFY(__VA_ARGS__), resultDisposition ); \ - INTERNAL_CATCH_TRY( catchAssertionHandler ) { \ + INTERNAL_CATCH_TRY { \ CATCH_INTERNAL_SUPPRESS_PARENTHESES_WARNINGS \ - catchAssertionHandler.handle( Catch::Decomposer() <= __VA_ARGS__ ); \ + catchAssertionHandler.handleExpr( Catch::Decomposer() <= __VA_ARGS__ ); \ CATCH_INTERNAL_UNSUPPRESS_PARENTHESES_WARNINGS \ } INTERNAL_CATCH_CATCH( catchAssertionHandler ) \ INTERNAL_CATCH_REACT( catchAssertionHandler ) \ - } while( Catch::isTrue( false && static_cast( !!(__VA_ARGS__) ) ) ) // the expression here is never evaluated at runtime but it forces the compiler to give it a look + } while( (void)0, false && static_cast( !!(__VA_ARGS__) ) ) // the expression 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 &&. /////////////////////////////////////////////////////////////////////////////// @@ -1464,13 +1657,13 @@ namespace Catch { Catch::AssertionHandler catchAssertionHandler( macroName, CATCH_INTERNAL_LINEINFO, CATCH_INTERNAL_STRINGIFY(__VA_ARGS__), resultDisposition ); \ try { \ static_cast(__VA_ARGS__); \ - catchAssertionHandler.handle( Catch::ResultWas::Ok ); \ + catchAssertionHandler.handleExceptionNotThrownAsExpected(); \ } \ catch( ... ) { \ - catchAssertionHandler.useActiveException(); \ + catchAssertionHandler.handleUnexpectedInflightException(); \ } \ INTERNAL_CATCH_REACT( catchAssertionHandler ) \ - } while( Catch::alwaysFalse() ) + } while( false ) /////////////////////////////////////////////////////////////////////////////// #define INTERNAL_CATCH_THROWS( macroName, resultDisposition, ... ) \ @@ -1479,15 +1672,15 @@ namespace Catch { if( catchAssertionHandler.allowThrows() ) \ try { \ static_cast(__VA_ARGS__); \ - catchAssertionHandler.handle( Catch::ResultWas::DidntThrowException ); \ + catchAssertionHandler.handleUnexpectedExceptionNotThrown(); \ } \ catch( ... ) { \ - catchAssertionHandler.handle( Catch::ResultWas::Ok ); \ + catchAssertionHandler.handleExceptionThrownAsExpected(); \ } \ else \ - catchAssertionHandler.handle( Catch::ResultWas::Ok ); \ + catchAssertionHandler.handleThrowingCallSkipped(); \ INTERNAL_CATCH_REACT( catchAssertionHandler ) \ - } while( Catch::alwaysFalse() ) + } while( false ) /////////////////////////////////////////////////////////////////////////////// #define INTERNAL_CATCH_THROWS_AS( macroName, exceptionType, resultDisposition, expr ) \ @@ -1496,30 +1689,30 @@ namespace Catch { if( catchAssertionHandler.allowThrows() ) \ try { \ static_cast(expr); \ - catchAssertionHandler.handle( Catch::ResultWas::DidntThrowException ); \ + catchAssertionHandler.handleUnexpectedExceptionNotThrown(); \ } \ catch( exceptionType const& ) { \ - catchAssertionHandler.handle( Catch::ResultWas::Ok ); \ + catchAssertionHandler.handleExceptionThrownAsExpected(); \ } \ catch( ... ) { \ - catchAssertionHandler.useActiveException(); \ + catchAssertionHandler.handleUnexpectedInflightException(); \ } \ else \ - catchAssertionHandler.handle( Catch::ResultWas::Ok ); \ + catchAssertionHandler.handleThrowingCallSkipped(); \ INTERNAL_CATCH_REACT( catchAssertionHandler ) \ - } while( Catch::alwaysFalse() ) + } while( false ) /////////////////////////////////////////////////////////////////////////////// #define INTERNAL_CATCH_MSG( macroName, messageType, resultDisposition, ... ) \ do { \ Catch::AssertionHandler catchAssertionHandler( macroName, CATCH_INTERNAL_LINEINFO, "", resultDisposition ); \ - catchAssertionHandler.handle( messageType, ( Catch::MessageStream() << __VA_ARGS__ + ::Catch::StreamEndStop() ).m_stream.str() ); \ + catchAssertionHandler.handleMessage( messageType, ( Catch::MessageStream() << __VA_ARGS__ + ::Catch::StreamEndStop() ).m_stream.str() ); \ INTERNAL_CATCH_REACT( catchAssertionHandler ) \ - } while( Catch::alwaysFalse() ) + } while( false ) /////////////////////////////////////////////////////////////////////////////// #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_INTERNAL_LINEINFO, Catch::ResultWas::Info ) << log ); /////////////////////////////////////////////////////////////////////////////// // Although this is matcher-based, it can be used with just a string @@ -1529,15 +1722,15 @@ namespace Catch { if( catchAssertionHandler.allowThrows() ) \ try { \ static_cast(__VA_ARGS__); \ - catchAssertionHandler.handle( Catch::ResultWas::DidntThrowException ); \ + catchAssertionHandler.handleUnexpectedExceptionNotThrown(); \ } \ catch( ... ) { \ - handleExceptionMatchExpr( catchAssertionHandler, matcher, #matcher ); \ + Catch::handleExceptionMatchExpr( catchAssertionHandler, matcher, #matcher ); \ } \ else \ - catchAssertionHandler.handle( Catch::ResultWas::Ok ); \ + catchAssertionHandler.handleThrowingCallSkipped(); \ INTERNAL_CATCH_REACT( catchAssertionHandler ) \ - } while( Catch::alwaysFalse() ) + } while( false ) #endif // CATCH_CONFIG_DISABLE @@ -1572,6 +1765,7 @@ namespace Catch { Totals delta( Totals const& prevTotals ) const; + int error = 0; Counts assertions; Counts testCases; }; @@ -1617,8 +1811,8 @@ namespace Catch { uint64_t m_nanoseconds = 0; public: void start(); - auto getElapsedNanoseconds() const -> unsigned int; - auto getElapsedMicroseconds() const -> unsigned int; + auto getElapsedNanoseconds() const -> uint64_t; + auto getElapsedMicroseconds() const -> uint64_t; auto getElapsedMilliseconds() const -> unsigned int; auto getElapsedSeconds() const -> double; }; @@ -1812,7 +2006,9 @@ 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_SUPPRESS_GLOBALS_WARNINGS \ + namespace{ Catch::ExceptionTranslatorRegistrar INTERNAL_CATCH_UNIQUE_NAME( catch_internal_ExceptionRegistrar )( &translatorName ); } \ + CATCH_INTERNAL_UNSUPPRESS_GLOBALS_WARNINGS \ static std::string translatorName( signature ) #define INTERNAL_CATCH_TRANSLATE_EXCEPTION( signature ) INTERNAL_CATCH_TRANSLATE_EXCEPTION2( INTERNAL_CATCH_UNIQUE_NAME( catch_internal_ExceptionTranslator ), signature ) @@ -1820,22 +2016,8 @@ namespace Catch { // end catch_interfaces_exception.h // start catch_approx.h -// start catch_enforce.h - -#include -#include - -#define CATCH_PREPARE_EXCEPTION( type, msg ) \ - type( static_cast( std::ostringstream() << msg ).str() ) -#define CATCH_INTERNAL_ERROR( msg ) \ - throw CATCH_PREPARE_EXCEPTION( std::logic_error, CATCH_INTERNAL_LINEINFO << ": Internal Catch error: " << msg); -#define CATCH_ERROR( msg ) \ - throw CATCH_PREPARE_EXCEPTION( std::domain_error, msg ) -#define CATCH_ENFORCE( condition, msg ) \ - do{ if( !(condition) ) CATCH_ERROR( msg ); } while(false) - -// end catch_enforce.h #include +#include namespace Catch { namespace Detail { @@ -1906,9 +2088,12 @@ namespace Detail { template ::value>::type> Approx& epsilon( T const& newEpsilon ) { double epsilonAsDouble = static_cast(newEpsilon); - CATCH_ENFORCE(epsilonAsDouble >= 0 && epsilonAsDouble <= 1.0, - "Invalid Approx::epsilon: " << epsilonAsDouble - << ", Approx::epsilon has to be between 0 and 1"); + if( epsilonAsDouble < 0 || epsilonAsDouble > 1.0 ) { + throw std::domain_error + ( "Invalid Approx::epsilon: " + + Catch::Detail::stringify( epsilonAsDouble ) + + ", Approx::epsilon has to be between 0 and 1" ); + } m_epsilon = epsilonAsDouble; return *this; } @@ -1916,9 +2101,13 @@ namespace Detail { template ::value>::type> Approx& margin( T const& newMargin ) { double marginAsDouble = static_cast(newMargin); - CATCH_ENFORCE(marginAsDouble >= 0, - "Invalid Approx::margin: " << marginAsDouble - << ", Approx::Margin has to be non-negative."); + if( marginAsDouble < 0 ) { + throw std::domain_error + ( "Invalid Approx::margin: " + + Catch::Detail::stringify( marginAsDouble ) + + ", Approx::Margin has to be non-negative." ); + + } m_margin = marginAsDouble; return *this; } @@ -2013,12 +2202,12 @@ namespace Matchers { virtual bool match( PtrT* arg ) const = 0; }; - template - struct MatcherBase : MatcherUntypedBase, MatcherMethod { + template + struct MatcherBase : MatcherUntypedBase, MatcherMethod { - MatchAllOf operator && ( MatcherBase const& other ) const; - MatchAnyOf operator || ( MatcherBase const& other ) const; - MatchNotOf operator ! () const; + MatchAllOf operator && ( MatcherBase const& other ) const; + MatchAnyOf operator || ( MatcherBase const& other ) const; + MatchNotOf operator ! () const; }; template @@ -2102,17 +2291,17 @@ namespace Matchers { MatcherBase const& m_underlyingMatcher; }; - template - MatchAllOf MatcherBase::operator && ( MatcherBase const& other ) const { - return MatchAllOf() && *this && other; + template + MatchAllOf MatcherBase::operator && ( MatcherBase const& other ) const { + return MatchAllOf() && *this && other; } - template - MatchAnyOf MatcherBase::operator || ( MatcherBase const& other ) const { - return MatchAnyOf() || *this || other; + template + MatchAnyOf MatcherBase::operator || ( MatcherBase const& other ) const { + return MatchAnyOf() || *this || other; } - template - MatchNotOf MatcherBase::operator ! () const { - return MatchNotOf( *this ); + template + MatchNotOf MatcherBase::operator ! () const { + return MatchNotOf( *this ); } } // namespace Impl @@ -2125,6 +2314,49 @@ using Matchers::Impl::MatcherBase; } // namespace Catch // end catch_matchers.h +// start catch_matchers_floating.h + +#include +#include + +namespace Catch { +namespace Matchers { + + namespace Floating { + + enum class FloatingPointKind : uint8_t; + + struct WithinAbsMatcher : MatcherBase { + WithinAbsMatcher(double target, double margin); + bool match(double const& matchee) const override; + std::string describe() const override; + private: + double m_target; + double m_margin; + }; + + struct WithinUlpsMatcher : MatcherBase { + WithinUlpsMatcher(double target, int ulps, FloatingPointKind baseType); + bool match(double const& matchee) const override; + std::string describe() const override; + private: + double m_target; + int m_ulps; + FloatingPointKind m_type; + }; + + } // namespace Floating + + // The following functions create the actual matcher objects. + // This allows the types to be inferred + Floating::WithinUlpsMatcher WithinULP(double target, int maxUlpDiff); + Floating::WithinUlpsMatcher WithinULP(float target, int maxUlpDiff); + Floating::WithinAbsMatcher WithinAbs(double target, double margin); + +} // namespace Matchers +} // namespace Catch + +// end catch_matchers_floating.h // start catch_matchers_string.h #include @@ -2169,6 +2401,16 @@ namespace Matchers { bool match( std::string const& source ) const override; }; + struct RegexMatcher : MatcherBase { + RegexMatcher( std::string regex, CaseSensitive::Choice caseSensitivity ); + bool match( std::string const& matchee ) const override; + std::string describe() const override; + + private: + std::string m_regex; + CaseSensitive::Choice m_caseSensitivity; + }; + } // namespace StdString // The following functions create the actual matcher objects. @@ -2178,6 +2420,7 @@ namespace Matchers { 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 ); } // namespace Matchers } // namespace Catch @@ -2185,13 +2428,36 @@ namespace Matchers { // end catch_matchers_string.h // start catch_matchers_vector.h +#include + namespace Catch { namespace Matchers { namespace Vector { + namespace Detail { + template + size_t count(InputIterator first, InputIterator last, T const& item) { + size_t cnt = 0; + for (; first != last; ++first) { + if (*first == item) { + ++cnt; + } + } + return cnt; + } + template + bool contains(InputIterator first, InputIterator last, T const& item) { + for (; first != last; ++first) { + if (*first == item) { + return true; + } + } + return false; + } + } template - struct ContainsElementMatcher : MatcherBase, T> { + struct ContainsElementMatcher : MatcherBase> { ContainsElementMatcher(T const &comparator) : m_comparator( comparator) {} @@ -2212,7 +2478,7 @@ namespace Matchers { }; template - struct ContainsMatcher : MatcherBase, std::vector > { + struct ContainsMatcher : MatcherBase> { ContainsMatcher(std::vector const &comparator) : m_comparator( comparator ) {} @@ -2242,7 +2508,7 @@ namespace Matchers { }; template - struct EqualsMatcher : MatcherBase, std::vector > { + struct EqualsMatcher : MatcherBase> { EqualsMatcher(std::vector const &comparator) : m_comparator( comparator ) {} @@ -2264,6 +2530,46 @@ namespace Matchers { std::vector const& m_comparator; }; + template + struct UnorderedEqualsMatcher : MatcherBase> { + UnorderedEqualsMatcher(std::vector const& target) : m_target(target) {} + bool match(std::vector const& vec) const override { + // Note: This is a reimplementation of std::is_permutation, + // because I don't want to include inside the common path + if (m_target.size() != vec.size()) { + return false; + } + auto lfirst = m_target.begin(), llast = m_target.end(); + auto rfirst = vec.begin(), rlast = vec.end(); + // Cut common prefix to optimize checking of permuted parts + while (lfirst != llast && *lfirst != *rfirst) { + ++lfirst; ++rfirst; + } + if (lfirst == llast) { + return true; + } + + for (auto mid = lfirst; mid != llast; ++mid) { + // Skip already counted items + if (Detail::contains(lfirst, mid, *mid)) { + continue; + } + size_t num_vec = Detail::count(rfirst, rlast, *mid); + if (num_vec == 0 || Detail::count(lfirst, llast, *mid) != num_vec) { + return false; + } + } + + return true; + } + + std::string describe() const override { + return "UnorderedEquals: " + ::Catch::Detail::stringify(m_target); + } + private: + std::vector const& m_target; + }; + } // namespace Vector // The following functions create the actual matcher objects. @@ -2284,6 +2590,11 @@ namespace Matchers { return Vector::EqualsMatcher( comparator ); } + template + Vector::UnorderedEqualsMatcher UnorderedEquals(std::vector const& target) { + return Vector::UnorderedEqualsMatcher(target); + } + } // namespace Matchers } // namespace Catch @@ -2295,18 +2606,14 @@ namespace Catch { ArgT const& m_arg; MatcherT m_matcher; StringRef m_matcherString; - bool m_result; public: MatchExpr( ArgT const& arg, MatcherT const& matcher, StringRef matcherString ) - : m_arg( arg ), + : ITransientExpression{ true, matcher.match( arg ) }, + m_arg( arg ), m_matcher( matcher ), - m_matcherString( matcherString ), - m_result( matcher.match( arg ) ) + m_matcherString( matcherString ) {} - auto isBinaryExpression() const -> bool override { return true; } - auto getResult() const -> bool override { return m_result; } - void streamReconstructedExpression( std::ostream &os ) const override { auto matcherAsString = m_matcher.toString(); os << Catch::Detail::stringify( m_arg ) << ' '; @@ -2332,11 +2639,11 @@ namespace Catch { #define INTERNAL_CHECK_THAT( macroName, matcher, resultDisposition, arg ) \ do { \ Catch::AssertionHandler catchAssertionHandler( macroName, CATCH_INTERNAL_LINEINFO, CATCH_INTERNAL_STRINGIFY(arg) ", " CATCH_INTERNAL_STRINGIFY(matcher), resultDisposition ); \ - INTERNAL_CATCH_TRY( catchAssertionHandler ) { \ - catchAssertionHandler.handle( Catch::makeMatchExpr( arg, matcher, #matcher ) ); \ + INTERNAL_CATCH_TRY { \ + catchAssertionHandler.handleExpr( Catch::makeMatchExpr( arg, matcher, #matcher ) ); \ } INTERNAL_CATCH_CATCH( catchAssertionHandler ) \ INTERNAL_CATCH_REACT( catchAssertionHandler ) \ - } while( Catch::alwaysFalse() ) + } while( false ) /////////////////////////////////////////////////////////////////////////////// #define INTERNAL_CATCH_THROWS_MATCHES( macroName, exceptionType, resultDisposition, matcher, ... ) \ @@ -2345,18 +2652,18 @@ namespace Catch { if( catchAssertionHandler.allowThrows() ) \ try { \ static_cast(__VA_ARGS__ ); \ - catchAssertionHandler.handle( Catch::ResultWas::DidntThrowException ); \ + catchAssertionHandler.handleUnexpectedExceptionNotThrown(); \ } \ catch( exceptionType const& ex ) { \ - catchAssertionHandler.handle( Catch::makeMatchExpr( ex, matcher, #matcher ) ); \ + catchAssertionHandler.handleExpr( Catch::makeMatchExpr( ex, matcher, #matcher ) ); \ } \ catch( ... ) { \ - catchAssertionHandler.useActiveException(); \ + catchAssertionHandler.handleUnexpectedInflightException(); \ } \ else \ - catchAssertionHandler.handle( Catch::ResultWas::Ok ); \ + catchAssertionHandler.handleThrowingCallSkipped(); \ INTERNAL_CATCH_REACT( catchAssertionHandler ) \ - } while( Catch::alwaysFalse() ) + } while( false ) // end catch_capture_matchers.h #endif @@ -2416,7 +2723,7 @@ namespace Catch { class TestCase : public TestCaseInfo { public: - TestCase( ITestInvoker* testCase, TestCaseInfo const& info ); + TestCase( ITestInvoker* testCase, TestCaseInfo&& info ); TestCase withName( std::string const& _newName ) const; @@ -2433,8 +2740,7 @@ namespace Catch { TestCase makeTestCase( ITestInvoker* testCase, std::string const& className, - std::string const& name, - std::string const& description, + NameAndTags const& nameAndTags, SourceLineInfo const& lineInfo ); } @@ -2864,7 +3170,8 @@ namespace Catch { struct WarnAbout { enum What { Nothing = 0x00, - NoAssertions = 0x01 + NoAssertions = 0x01, + NoTests = 0x02 }; }; struct ShowDurations { enum OrNot { @@ -2901,10 +3208,12 @@ namespace Catch { 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 TestSpec const& testSpec() const = 0; + virtual bool hasTestFilters() const = 0; virtual RunTests::InWhatOrder runOrder() const = 0; virtual unsigned int rngSeed() const = 0; virtual int benchmarkResolutionMultiple() const = 0; @@ -2918,69 +3227,6 @@ namespace Catch { // end catch_interfaces_config.h // Libstdc++ doesn't like incomplete classes for unique_ptr -// start catch_stream.h - -// start catch_streambuf.h - -#include - -namespace Catch { - - class StreamBufBase : public std::streambuf { - public: - virtual ~StreamBufBase(); - }; -} - -// end catch_streambuf.h -#include -#include -#include -#include - -namespace Catch { - - std::ostream& cout(); - std::ostream& cerr(); - std::ostream& clog(); - - struct IStream { - virtual ~IStream(); - virtual std::ostream& stream() const = 0; - }; - - class FileStream : public IStream { - mutable std::ofstream m_ofs; - public: - FileStream( std::string const& filename ); - ~FileStream() override = default; - public: // IStream - std::ostream& stream() const override; - }; - - class CoutStream : public IStream { - mutable std::ostream m_os; - public: - CoutStream(); - ~CoutStream() override = default; - - public: // IStream - std::ostream& stream() const override; - }; - - class DebugOutStream : public IStream { - std::unique_ptr m_streamBuf; - mutable std::ostream m_os; - public: - DebugOutStream(); - ~DebugOutStream() override = default; - - public: // IStream - std::ostream& stream() const override; - }; -} - -// end catch_stream.h #include #include @@ -3045,9 +3291,11 @@ namespace Catch { std::string getProcessName() const; std::vector const& getReporterNames() const; + std::vector const& getTestsOrTags() const; std::vector const& getSectionsToRun() const override; virtual TestSpec const& testSpec() const override; + bool hasTestFilters() const override; bool showHelp() const; @@ -3057,6 +3305,7 @@ namespace Catch { std::string name() const override; bool includeSuccessfulResults() const override; bool warnAboutMissingAssertions() const override; + bool warnAboutNoTests() const override; ShowDurations::OrNot showDurations() const override; RunTests::InWhatOrder runOrder() const override; unsigned int rngSeed() const override; @@ -3074,6 +3323,7 @@ namespace Catch { std::unique_ptr m_stream; TestSpec m_testSpec; + bool m_hasTestFilters = false; }; } // end namespace Catch @@ -3115,7 +3365,7 @@ namespace Catch { std::string getExpandedExpression() const; std::string getMessage() const; SourceLineInfo getSourceInfo() const; - std::string getTestMacroName() const; + StringRef getTestMacroName() const; //protected: AssertionInfo m_info; @@ -3408,6 +3658,7 @@ namespace Catch { #include #include #include +#include namespace Catch { void prepareExpandedExpression(AssertionResult& result); @@ -3423,7 +3674,8 @@ namespace Catch { stream( _config.stream() ) { m_reporterPrefs.shouldRedirectStdOut = false; - CATCH_ENFORCE( DerivedT::getSupportedVerbosities().count( m_config->verbosity() ), "Verbosity level not supported by this reporter" ); + if( !DerivedT::getSupportedVerbosities().count( m_config->verbosity() ) ) + throw std::domain_error( "Verbosity level not supported by this reporter" ); } ReporterPreferences getPreferences() const override { @@ -3536,7 +3788,8 @@ namespace Catch { stream( _config.stream() ) { m_reporterPrefs.shouldRedirectStdOut = false; - CATCH_ENFORCE( DerivedT::getSupportedVerbosities().count( m_config->verbosity() ), "Verbosity level not supported by this reporter" ); + if( !DerivedT::getSupportedVerbosities().count( m_config->verbosity() ) ) + throw std::domain_error( "Verbosity level not supported by this reporter" ); } ~CumulativeReporterBase() override = default; @@ -3681,10 +3934,11 @@ namespace Catch { BrightGreen = Bright | Green, LightGrey = Bright | Grey, BrightWhite = Bright | White, + BrightYellow = Bright | Yellow, // By intention FileName = LightGrey, - Warning = Yellow, + Warning = BrightYellow, ResultError = BrightRed, ResultSuccess = BrightGreen, ResultExpectedFailure = Warning, @@ -3693,7 +3947,7 @@ namespace Catch { Success = Green, OriginalExpression = Cyan, - ReconstructedExpression = Yellow, + ReconstructedExpression = BrightYellow, SecondaryText = LightGrey, Headers = White @@ -3738,7 +3992,7 @@ namespace Catch { public: - ReporterRegistrar( std::string const& name ) { + explicit ReporterRegistrar( std::string const& name ) { getMutableRegistryHub().registerReporter( name, std::make_shared() ); } }; @@ -3783,9 +4037,303 @@ namespace Catch { #endif // CATCH_CONFIG_DISABLE // end catch_reporter_registrars.hpp +// Allow users to base their work off existing reporters +// start catch_reporter_compact.h + +namespace Catch { + + struct CompactReporter : StreamingReporterBase { + + using StreamingReporterBase::StreamingReporterBase; + + ~CompactReporter() override; + + static std::string getDescription(); + + ReporterPreferences getPreferences() const override; + + void noMatchingTestCases(std::string const& spec) override; + + void assertionStarting(AssertionInfo const&) override; + + bool assertionEnded(AssertionStats const& _assertionStats) override; + + void sectionEnded(SectionStats const& _sectionStats) override; + + void testRunEnded(TestRunStats const& _testRunStats) override; + + }; + +} // end namespace Catch + +// end catch_reporter_compact.h +// start catch_reporter_console.h + +#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 { + // Fwd decls + struct SummaryColumn; + class TablePrinter; + + struct ConsoleReporter : StreamingReporterBase { + std::unique_ptr m_tablePrinter; + + ConsoleReporter(ReporterConfig const& config); + ~ConsoleReporter() override; + static std::string getDescription(); + + void noMatchingTestCases(std::string const& spec) override; + + void assertionStarting(AssertionInfo const&) override; + + bool assertionEnded(AssertionStats const& _assertionStats) override; + + void sectionStarting(SectionInfo const& _sectionInfo) override; + void sectionEnded(SectionStats const& _sectionStats) override; + + void benchmarkStarting(BenchmarkInfo const& info) override; + void benchmarkEnded(BenchmarkStats const& stats) override; + + void testCaseEnded(TestCaseStats const& _testCaseStats) override; + void testGroupEnded(TestGroupStats const& _testGroupStats) override; + void testRunEnded(TestRunStats const& _testRunStats) override; + + private: + + void lazyPrint(); + + void lazyPrintWithoutClosingBenchmarkTable(); + void lazyPrintRunInfo(); + void lazyPrintGroupInfo(); + void printTestCaseAndSectionHeader(); + + void printClosedHeader(std::string const& _name); + void printOpenHeader(std::string const& _name); + + // 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); + + void printTotals(Totals const& totals); + void printSummaryRow(std::string const& label, std::vector const& cols, std::size_t row); + + void printTotalsDivider(Totals const& totals); + void printSummaryDivider(); + + private: + bool m_headerPrinted = false; + }; + +} // end namespace Catch + +#if defined(_MSC_VER) +#pragma warning(pop) +#endif + +// end catch_reporter_console.h +// start catch_reporter_junit.h + +// start catch_xmlwriter.h + +#include + +namespace Catch { + + class XmlEncode { + public: + enum ForWhat { ForTextNodes, ForAttributes }; + + XmlEncode( std::string const& str, ForWhat forWhat = ForTextNodes ); + + void encodeTo( std::ostream& os ) const; + + friend std::ostream& operator << ( std::ostream& os, XmlEncode const& xmlEncode ); + + private: + std::string m_str; + ForWhat m_forWhat; + }; + + class XmlWriter { + public: + + class ScopedElement { + public: + ScopedElement( XmlWriter* writer ); + + ScopedElement( ScopedElement&& other ) noexcept; + ScopedElement& operator=( ScopedElement&& other ) noexcept; + + ~ScopedElement(); + + ScopedElement& writeText( std::string const& text, bool indent = true ); + + template + ScopedElement& writeAttribute( std::string const& name, T const& attribute ) { + m_writer->writeAttribute( name, attribute ); + return *this; + } + + private: + mutable XmlWriter* m_writer = nullptr; + }; + + XmlWriter( std::ostream& os = Catch::cout() ); + ~XmlWriter(); + + XmlWriter( XmlWriter const& ) = delete; + XmlWriter& operator=( XmlWriter const& ) = delete; + + XmlWriter& startElement( std::string const& name ); + + ScopedElement scopedElement( std::string const& name ); + + XmlWriter& endElement(); + + XmlWriter& writeAttribute( std::string const& name, std::string const& attribute ); + + XmlWriter& writeAttribute( std::string const& name, bool attribute ); + + template + XmlWriter& writeAttribute( std::string const& name, T const& attribute ) { + ReusableStringStream rss; + rss << attribute; + return writeAttribute( name, rss.str() ); + } + + XmlWriter& writeText( std::string const& text, bool indent = true ); + + XmlWriter& writeComment( std::string const& text ); + + void writeStylesheetRef( std::string const& url ); + + XmlWriter& writeBlankLine(); + + void ensureTagClosed(); + + private: + + void writeDeclaration(); + + void newlineIfNecessary(); + + bool m_tagIsOpen = false; + bool m_needsNewline = false; + std::vector m_tags; + std::string m_indent; + std::ostream& m_os; + }; + +} + +// end catch_xmlwriter.h +namespace Catch { + + class JunitReporter : public CumulativeReporterBase { + public: + JunitReporter(ReporterConfig const& _config); + + ~JunitReporter() override; + + static std::string getDescription(); + + void noMatchingTestCases(std::string const& /*spec*/) override; + + void testRunStarting(TestRunInfo const& runInfo) override; + + void testGroupStarting(GroupInfo const& groupInfo) override; + + void testCaseStarting(TestCaseInfo const& testCaseInfo) override; + bool assertionEnded(AssertionStats const& assertionStats) override; + + void testCaseEnded(TestCaseStats const& testCaseStats) override; + + void testGroupEnded(TestGroupStats const& testGroupStats) override; + + void testRunEndedCumulative() override; + + void writeGroup(TestGroupNode const& groupNode, double suiteTime); + + void writeTestCase(TestCaseNode const& testCaseNode); + + void writeSection(std::string const& className, + std::string const& rootName, + SectionNode const& sectionNode); + + void writeAssertions(SectionNode const& sectionNode); + void writeAssertion(AssertionStats const& stats); + + XmlWriter xml; + Timer suiteTimer; + std::string stdOutForSuite; + std::string stdErrForSuite; + unsigned int unexpectedExceptions = 0; + bool m_okToFail = false; + }; + +} // end namespace Catch + +// end catch_reporter_junit.h +// start catch_reporter_xml.h + +namespace Catch { + class XmlReporter : public StreamingReporterBase { + public: + XmlReporter(ReporterConfig const& _config); + + ~XmlReporter() override; + + static std::string getDescription(); + + virtual std::string getStylesheetRef() const; + + void writeSourceInfo(SourceLineInfo const& sourceInfo); + + public: // StreamingReporterBase + + void noMatchingTestCases(std::string const& s) override; + + void testRunStarting(TestRunInfo const& testInfo) override; + + void testGroupStarting(GroupInfo const& groupInfo) override; + + void testCaseStarting(TestCaseInfo const& testInfo) override; + + void sectionStarting(SectionInfo const& sectionInfo) override; + + void assertionStarting(AssertionInfo const&) override; + + 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; + + private: + Timer m_testCaseTimer; + XmlWriter m_xml; + int m_sectionDepth = 0; + }; + +} // end namespace Catch + +// end catch_reporter_xml.h + // end catch_external_interfaces.h #endif +#endif // ! CATCH_CONFIG_IMPL_ONLY + #ifdef CATCH_IMPL // start catch_impl.hpp @@ -4008,9 +4556,9 @@ namespace Detail { } std::string Approx::toString() const { - std::ostringstream oss; - oss << "Approx( " << ::Catch::Detail::stringify( m_value ) << " )"; - return oss.str(); + ReusableStringStream rss; + rss << "Approx( " << ::Catch::Detail::stringify( m_value ) << " )"; + return rss.str(); } bool Approx::equalityComparisonImpl(const double other) const { @@ -4038,6 +4586,7 @@ namespace Catch { struct IResultCapture; struct IRunner; struct IConfig; + struct IMutableContext; using IConfigPtr = std::shared_ptr; @@ -4047,7 +4596,7 @@ namespace Catch { virtual IResultCapture* getResultCapture() = 0; virtual IRunner* getRunner() = 0; - virtual IConfigPtr getConfig() const = 0; + virtual IConfigPtr const& getConfig() const = 0; }; struct IMutableContext : IContext @@ -4056,16 +4605,276 @@ namespace Catch { virtual void setResultCapture( IResultCapture* resultCapture ) = 0; virtual void setRunner( IRunner* runner ) = 0; virtual void setConfig( IConfigPtr const& config ) = 0; + + private: + static IMutableContext *currentContext; + friend IMutableContext& getCurrentMutableContext(); + friend void cleanUpContext(); + static void createContext(); }; - IContext& getCurrentContext(); - IMutableContext& getCurrentMutableContext(); + inline IMutableContext& getCurrentMutableContext() + { + if( !IMutableContext::currentContext ) + IMutableContext::createContext(); + return *IMutableContext::currentContext; + } + + inline IContext& getCurrentContext() + { + return getCurrentMutableContext(); + } + void cleanUpContext(); } // end catch_context.h -#include +// start catch_debugger.h +namespace Catch { + bool isDebuggerActive(); +} + +#ifdef CATCH_PLATFORM_MAC + + #define CATCH_TRAP() __asm__("int $3\n" : : ) /* NOLINT */ + +#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 + + #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 + +#ifdef CATCH_TRAP + #define CATCH_BREAK_INTO_DEBUGGER() if( Catch::isDebuggerActive() ) { CATCH_TRAP(); } +#else + namespace Catch { + inline void doNothing() {} + } + #define CATCH_BREAK_INTO_DEBUGGER() Catch::doNothing() +#endif + +// end catch_debugger.h +// start catch_run_context.h + +// start catch_fatal_condition.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 +#else +#include +#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 +#if defined( CATCH_CONFIG_WINDOWS_SEH ) + +namespace Catch { + + struct FatalConditionHandler { + + static LONG CALLBACK handleVectoredException(PEXCEPTION_POINTERS ExceptionInfo); + FatalConditionHandler(); + static void reset(); + ~FatalConditionHandler(); + + private: + static bool isSet; + static ULONG guaranteeSize; + static PVOID exceptionHandlerHandle; + }; + +} // namespace Catch + +#elif defined ( CATCH_CONFIG_POSIX_SIGNALS ) + +#include + +namespace Catch { + + struct FatalConditionHandler { + + static bool isSet; + static struct sigaction oldSigActions[]; + static stack_t oldSigStack; + static char altStackMem[]; + + static void handleSignal( int sig ); + + FatalConditionHandler(); + ~FatalConditionHandler(); + static void reset(); + }; + +} // namespace Catch + +#else + +namespace Catch { + struct FatalConditionHandler { + void reset(); + }; +} + +#endif + +// end catch_fatal_condition.h +#include + +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; + + void benchmarkStarting( BenchmarkInfo const& info ) override; + void benchmarkEnded( BenchmarkStats const& stats ) override; + + void pushScopedMessage( MessageInfo const& message ) override; + void popScopedMessage( MessageInfo const& message ) 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 override; + + 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; + Option m_lastResult; + + IConfigPtr m_config; + Totals m_totals; + IStreamingReporterPtr m_reporter; + std::vector m_messages; + AssertionInfo m_lastAssertionInfo; + std::vector m_unfinishedSections; + std::vector m_activeSections; + TrackerContext m_trackerContext; + bool m_lastAssertionPassed = false; + bool m_shouldReportUnexpected = true; + bool m_includeSuccessfulResults; + }; + +} // end namespace Catch + +// end catch_run_context.h namespace Catch { auto operator <<( std::ostream& os, ITransientExpression const& expr ) -> std::ostream& { @@ -4104,86 +4913,55 @@ namespace Catch { SourceLineInfo const& lineInfo, StringRef capturedExpression, ResultDisposition::Flags resultDisposition ) - : m_assertionInfo{ macroName, lineInfo, capturedExpression, resultDisposition } - { - getCurrentContext().getResultCapture()->assertionStarting( m_assertionInfo ); + : m_assertionInfo{ macroName, lineInfo, capturedExpression, resultDisposition }, + m_resultCapture( getResultCapture() ) + {} + + void AssertionHandler::handleExpr( ITransientExpression const& expr ) { + m_resultCapture.handleExpr( m_assertionInfo, expr, m_reaction ); } - AssertionHandler::~AssertionHandler() { - if ( m_inExceptionGuard ) { - handle( ResultWas::ThrewException, "Exception translation was disabled by CATCH_CONFIG_FAST_COMPILE" ); - getCurrentContext().getResultCapture()->exceptionEarlyReported(); - } - } - - void AssertionHandler::handle( ITransientExpression const& expr ) { - - bool negated = isFalseTest( m_assertionInfo.resultDisposition ); - bool result = expr.getResult() != negated; - - handle( result ? ResultWas::Ok : ResultWas::ExpressionFailed, &expr, negated ); - } - void AssertionHandler::handle( ResultWas::OfType resultType ) { - handle( resultType, nullptr, false ); - } - void AssertionHandler::handle( ResultWas::OfType resultType, StringRef const& message ) { - AssertionResultData data( resultType, LazyExpression( false ) ); - data.message = message; - handle( data, nullptr ); - } - void AssertionHandler::handle( ResultWas::OfType resultType, ITransientExpression const* expr, bool negated ) { - AssertionResultData data( resultType, LazyExpression( negated ) ); - handle( data, expr ); - } - void AssertionHandler::handle( AssertionResultData const& resultData, ITransientExpression const* expr ) { - - getResultCapture().assertionRun(); - - AssertionResult assertionResult{ m_assertionInfo, resultData }; - assertionResult.m_resultData.lazyExpression.m_transientExpression = expr; - - getResultCapture().assertionEnded( assertionResult ); - - if( !assertionResult.isOk() ) { - m_shouldDebugBreak = getCurrentContext().getConfig()->shouldDebugBreak(); - m_shouldThrow = - getCurrentContext().getRunner()->aborting() || - (m_assertionInfo.resultDisposition & ResultDisposition::Normal); - } + 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(); } - auto AssertionHandler::shouldDebugBreak() const -> bool { - return m_shouldDebugBreak; - } - void AssertionHandler::reactWithDebugBreak() const { - 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 reactWithoutDebugBreak() call - /////////////////////////////////////////////////////////////////// + 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(); } - reactWithoutDebugBreak(); - } - void AssertionHandler::reactWithoutDebugBreak() const { - if( m_shouldThrow ) + if( m_reaction.shouldThrow ) throw Catch::TestFailureException(); } - - void AssertionHandler::useActiveException() { - handle( ResultWas::ThrewException, Catch::translateActiveException() ); + void AssertionHandler::setCompleted() { + m_completed = true; } - void AssertionHandler::setExceptionGuard() { - assert( m_inExceptionGuard == false ); - m_inExceptionGuard = true; + void AssertionHandler::handleUnexpectedInflightException() { + m_resultCapture.handleUnexpectedInflightException( m_assertionInfo, Catch::translateActiveException(), m_reaction ); } - void AssertionHandler::unsetExceptionGuard() { - assert( m_inExceptionGuard == true ); - m_inExceptionGuard = false; + + 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 @@ -4205,10 +4983,9 @@ namespace Catch { if( reconstructedExpression.empty() ) { if( lazyExpression ) { - // !TBD Use stringstream for now, but rework above to pass stream in - std::ostringstream oss; - oss << lazyExpression; - reconstructedExpression = oss.str(); + ReusableStringStream rss; + rss << lazyExpression; + reconstructedExpression = rss.str(); } } return reconstructedExpression; @@ -4243,7 +5020,7 @@ namespace Catch { std::string AssertionResult::getExpression() const { if( isFalseTest( m_info.resultDisposition ) ) - return "!(" + std::string(m_info.capturedExpression) + ")"; + return "!(" + m_info.capturedExpression + ")"; else return m_info.capturedExpression; } @@ -4280,7 +5057,7 @@ namespace Catch { return m_info.lineInfo; } - std::string AssertionResult::getTestMacroName() const { + StringRef AssertionResult::getTestMacroName() const { return m_info.macroName; } @@ -4319,12 +5096,12 @@ namespace Catch { using StringMatcher = Matchers::Impl::MatcherBase; // This is the general overload that takes a any string matcher - // There is another overload, in catch_assertinhandler.h/.cpp, that only takes a string and infers + // 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 matcherString ) { std::string exceptionMessage = Catch::translateActiveException(); MatchExpr expr( exceptionMessage, matcher, matcherString ); - handler.handle( expr ); + handler.handleExpr( expr ); } } // namespace Catch @@ -4350,8 +5127,14 @@ namespace Catch { #endif // start clara.hpp -// v1.0-develop.2 -// See https://github.com/philsquared/Clara +// 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.3 #ifndef CATCH_CLARA_CONFIG_CONSOLE_WIDTH @@ -4362,6 +5145,14 @@ namespace Catch { #define CATCH_CLARA_TEXTFLOW_CONFIG_CONSOLE_WIDTH CATCH_CLARA_CONFIG_CONSOLE_WIDTH #endif +#ifndef CLARA_CONFIG_OPTIONAL_TYPE +#ifdef __has_include +#if __has_include() && __cplusplus >= 201703L +#define CLARA_CONFIG_OPTIONAL_TYPE std::optional +#endif +#endif +#endif + // ----------- #included from clara_textflow.hpp ----------- // TextFlowCpp @@ -4714,7 +5505,7 @@ namespace detail { template struct UnaryLambdaTraits { static const bool isValid = true; - using ArgType = typename std::remove_const::type>::type;; + using ArgType = typename std::remove_const::type>::type; using ReturnType = ReturnT; }; @@ -4727,11 +5518,9 @@ namespace detail { std::vector m_args; public: - Args( int argc, char *argv[] ) { - m_exeName = argv[0]; - for( int i = 1; i < argc; ++i ) - m_args.push_back( argv[i] ); - } + Args( int argc, char const* const* argv ) + : m_exeName(argv[0]), + m_args(argv + 1, argv + argc) {} Args( std::initializer_list args ) : m_exeName( *args.begin() ), @@ -4878,7 +5667,7 @@ namespace detail { return *this; } - ~ResultValueBase() { + ~ResultValueBase() override { if( m_type == Ok ) m_value.~T(); } @@ -4916,16 +5705,14 @@ namespace detail { auto errorMessage() const -> std::string { return m_errorMessage; } protected: - virtual void enforceOk() const { - // !TBD: If no exceptions, std::terminate here or something - switch( m_type ) { - case ResultBase::LogicError: - throw std::logic_error( m_errorMessage ); - case ResultBase::RuntimeError: - throw std::runtime_error( m_errorMessage ); - case ResultBase::Ok: - break; - } + 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 @@ -4995,47 +5782,43 @@ namespace detail { return ParserResult::runtimeError( "Expected a boolean value but did not recognise: '" + source + "'" ); return ParserResult::ok( ParseResultType::Matched ); } +#ifdef CLARA_CONFIG_OPTIONAL_TYPE + template + inline auto convertInto( std::string const &source, std::optional& target ) -> ParserResult { + T temp; + auto result = convertInto( source, temp ); + if( result ) + target = temp; + return result; + } +#endif // CLARA_CONFIG_OPTIONAL_TYPE - struct BoundRefBase { - BoundRefBase() = default; - BoundRefBase( BoundRefBase const & ) = delete; - BoundRefBase( BoundRefBase && ) = delete; - BoundRefBase &operator=( BoundRefBase const & ) = delete; - BoundRefBase &operator=( BoundRefBase && ) = delete; + struct NonCopyable { + NonCopyable() = default; + NonCopyable( NonCopyable const & ) = delete; + NonCopyable( NonCopyable && ) = delete; + NonCopyable &operator=( NonCopyable const & ) = delete; + NonCopyable &operator=( NonCopyable && ) = delete; + }; - virtual ~BoundRefBase() = default; - - virtual auto isFlag() const -> bool = 0; + 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; - }; - - struct BoundValueRefBase : BoundRefBase { - auto isFlag() const -> bool override { return false; } - - auto setFlag( bool ) -> ParserResult override { - return ParserResult::logicError( "Flags can only be set on boolean fields" ); - } - }; - - struct BoundFlagRefBase : BoundRefBase { - auto isFlag() const -> bool override { return true; } - - auto setValue( std::string const &arg ) -> ParserResult override { - bool flag; - auto result = convertInto( arg, flag ); - if( result ) - setFlag( flag ); - return result; - } + virtual auto isFlag() const -> bool { return true; } }; template - struct BoundRef : BoundValueRefBase { + struct BoundValueRef : BoundValueRefBase { T &m_ref; - explicit BoundRef( T &ref ) : m_ref( ref ) {} + explicit BoundValueRef( T &ref ) : m_ref( ref ) {} auto setValue( std::string const &arg ) -> ParserResult override { return convertInto( arg, m_ref ); @@ -5043,10 +5826,10 @@ namespace detail { }; template - struct BoundRef> : BoundValueRefBase { + struct BoundValueRef> : BoundValueRefBase { std::vector &m_ref; - explicit BoundRef( std::vector &ref ) : m_ref( ref ) {} + explicit BoundValueRef( std::vector &ref ) : m_ref( ref ) {} auto isContainer() const -> bool override { return true; } @@ -5091,12 +5874,12 @@ namespace detail { template inline auto invokeLambda( L const &lambda, std::string const &arg ) -> ParserResult { - ArgType temp; + ArgType temp{}; auto result = convertInto( arg, temp ); return !result ? result : LambdaInvoker::ReturnType>::invoke( lambda, temp ); - }; + } template struct BoundLambda : BoundValueRefBase { @@ -5145,6 +5928,9 @@ namespace detail { public: template auto operator|( T const &other ) const -> Parser; + + template + auto operator+( T const &other ) const -> Parser; }; // Common code and state for Args and Opts @@ -5152,16 +5938,16 @@ namespace detail { class ParserRefImpl : public ComposableParserImpl { protected: Optionality m_optionality = Optionality::Optional; - std::shared_ptr m_ref; + std::shared_ptr m_ref; std::string m_hint; std::string m_description; - explicit ParserRefImpl( std::shared_ptr const &ref ) : m_ref( ref ) {} + explicit ParserRefImpl( std::shared_ptr const &ref ) : m_ref( ref ) {} public: template ParserRefImpl( T &ref, std::string const &hint ) - : m_ref( std::make_shared>( ref ) ), + : m_ref( std::make_shared>( ref ) ), m_hint( hint ) {} @@ -5202,10 +5988,10 @@ namespace detail { class ExeName : public ComposableParserImpl { std::shared_ptr m_name; - std::shared_ptr m_ref; + std::shared_ptr m_ref; template - static auto makeRef(LambdaT const &lambda) -> std::shared_ptr { + static auto makeRef(LambdaT const &lambda) -> std::shared_ptr { return std::make_shared>( lambda) ; } @@ -5213,7 +5999,7 @@ namespace detail { ExeName() : m_name( std::make_shared( "" ) ) {} explicit ExeName( std::string &ref ) : ExeName() { - m_ref = std::make_shared>( ref ); + m_ref = std::make_shared>( ref ); } template @@ -5256,7 +6042,10 @@ namespace detail { if( token.type != TokenType::Argument ) return InternalParseResult::ok( ParseState( ParseResultType::NoMatch, remainingTokens ) ); - auto result = m_ref->setValue( remainingTokens->token ); + assert( !m_ref->isFlag() ); + auto valueRef = static_cast( m_ref.get() ); + + auto result = valueRef->setValue( remainingTokens->token ); if( !result ) return InternalParseResult( result ); else @@ -5330,19 +6119,21 @@ namespace detail { auto const &token = *remainingTokens; if( isMatch(token.token ) ) { if( m_ref->isFlag() ) { - auto result = m_ref->setFlag( true ); + auto flagRef = static_cast( 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( 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 = m_ref->setValue( argToken.token ); + auto result = valueRef->setValue( argToken.token ); if( !result ) return InternalParseResult( result ); if( result.value() == ParseResultType::ShortCircuitAll ) @@ -5418,6 +6209,12 @@ namespace detail { return Parser( *this ) |= other; } + // Forward deprecated interface with '+' instead of '|' + template + auto operator+=( T const &other ) -> Parser & { return operator|=( other ); } + template + auto operator+( T const &other ) const -> Parser { return operator|( other ); } + auto getHelpColumns() const -> std::vector { std::vector cols; for (auto const &o : m_options) { @@ -5457,6 +6254,8 @@ namespace detail { 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 ) + @@ -5596,9 +6395,19 @@ namespace Catch { using namespace clara; auto const setWarning = [&]( std::string const& warning ) { - if( warning != "NoAssertions" ) + 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( config.warnings | WarnAbout::NoAssertions ); + config.warnings = static_cast( config.warnings | warningSet ); return ParserResult::ok( ParseResultType::Matched ); }; auto const loadTestNamesFromFile = [&]( std::string const& filename ) { @@ -5766,10 +6575,6 @@ namespace Catch { namespace Catch { - SourceLineInfo::SourceLineInfo( char const* _file, std::size_t _line ) noexcept - : file( _file ), - line( _line ) - {} bool SourceLineInfo::empty() const noexcept { return file[0] == '\0'; } @@ -5789,10 +6594,6 @@ namespace Catch { return os; } - bool isTrue( bool value ){ return value; } - bool alwaysTrue() { return true; } - bool alwaysFalse() { return false; } - std::string StreamEndStop::operator+() const { return std::string(); } @@ -5804,18 +6605,36 @@ namespace Catch { // end catch_common.cpp // start catch_config.cpp +// start catch_enforce.h + +#include + +#define CATCH_PREPARE_EXCEPTION( type, msg ) \ + type( ( Catch::ReusableStringStream() << msg ).str() ) +#define CATCH_INTERNAL_ERROR( msg ) \ + throw CATCH_PREPARE_EXCEPTION( std::logic_error, CATCH_INTERNAL_LINEINFO << ": Internal Catch error: " << msg); +#define CATCH_ERROR( msg ) \ + throw CATCH_PREPARE_EXCEPTION( std::domain_error, msg ) +#define CATCH_ENFORCE( condition, msg ) \ + do{ if( !(condition) ) CATCH_ERROR( msg ); } while(false) + +// end catch_enforce.h namespace Catch { Config::Config( ConfigData const& data ) : m_data( data ), m_stream( openStream() ) { - if( !data.testsOrTags.empty() ) { - TestSpecParser parser( ITagAliasRegistry::get() ); + TestSpecParser parser(ITagAliasRegistry::get()); + if (data.testsOrTags.empty()) { + parser.parse("~[.]"); // All not hidden tests + } + else { + m_hasTestFilters = true; for( auto const& testOrTags : data.testsOrTags ) parser.parse( testOrTags ); - m_testSpec = parser.testSpec(); } + m_testSpec = parser.testSpec(); } std::string const& Config::getFilename() const { @@ -5830,9 +6649,11 @@ namespace Catch { std::string Config::getProcessName() const { return m_data.processName; } std::vector const& Config::getReporterNames() const { return m_data.reporterNames; } + std::vector const& Config::getTestsOrTags() const { return m_data.testsOrTags; } std::vector 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; } @@ -5841,7 +6662,8 @@ namespace Catch { 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::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; } RunTests::InWhatOrder Config::runOrder() const { return m_data.runOrder; } unsigned int Config::rngSeed() const { return m_data.rngSeed; } @@ -5853,16 +6675,7 @@ namespace Catch { Verbosity Config::verbosity() const { return m_data.verbosity; } IStream const* Config::openStream() { - if( m_data.outputFilename.empty() ) - return new CoutStream(); - else if( m_data.outputFilename[0] == '%' ) { - if( m_data.outputFilename == "%debug" ) - return new DebugOutStream(); - else - CATCH_ERROR( "Unrecognised stream: '" << m_data.outputFilename << "'" ); - } - else - return new FileStream( m_data.outputFilename ); + return Catch::makeStream(m_data.outputFilename); } } // end namespace Catch @@ -5889,36 +6702,8 @@ namespace Catch { } // end catch_errno_guard.h -// start catch_windows_h_proxy.h +#include - -#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 -#else -#include -#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 namespace Catch { namespace { @@ -5977,8 +6762,12 @@ namespace { 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" ); } } @@ -6036,8 +6825,10 @@ namespace { 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() { @@ -6056,7 +6847,12 @@ namespace { #ifdef CATCH_PLATFORM_MAC !isDebuggerActive() && #endif - isatty(STDOUT_FILENO); +#if !(defined(__DJGPP__) && defined(__STRICT_ANSI__)) + isatty(STDOUT_FILENO) +#else + false +#endif + ; } IColourImpl* platformColourInstance() { ErrnoGuard guard; @@ -6131,7 +6927,7 @@ namespace Catch { return m_runner; } - virtual IConfigPtr getConfig() const override { + virtual IConfigPtr const& getConfig() const override { return m_config; } @@ -6156,21 +6952,16 @@ namespace Catch { IResultCapture* m_resultCapture = nullptr; }; - namespace { - Context* currentContext = nullptr; - } - IMutableContext& getCurrentMutableContext() { - if( !currentContext ) - currentContext = new Context(); - return *currentContext; - } - IContext& getCurrentContext() { - return getCurrentMutableContext(); + IMutableContext *IMutableContext::currentContext = nullptr; + + void IMutableContext::createContext() + { + currentContext = new Context(); } void cleanUpContext() { - delete currentContext; - currentContext = nullptr; + delete IMutableContext::currentContext; + IMutableContext::currentContext = nullptr; } IContext::~IContext() = default; IMutableContext::~IMutableContext() = default; @@ -6195,26 +6986,31 @@ namespace Catch { ::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 #ifdef CATCH_PLATFORM_MAC - #include - #include - #include - #include - #include +# include +# include +# include +# include +# include +# include +# include - namespace Catch { +namespace Catch { // The following function is taken directly from the following technical note: // http://developer.apple.com/library/mac/#qa/qa2004/qa1361.html @@ -6376,6 +7172,17 @@ namespace Catch { 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 } @@ -6406,78 +7213,13 @@ namespace Catch { // end catch_exception_translator_registry.cpp // start catch_fatal_condition.cpp -// start catch_fatal_condition.h +#if defined(__GNUC__) +# pragma GCC diagnostic push +# pragma GCC diagnostic ignored "-Wmissing-field-initializers" +#endif -#include +#if defined( CATCH_CONFIG_WINDOWS_SEH ) || defined( CATCH_CONFIG_POSIX_SIGNALS ) -#if defined ( CATCH_PLATFORM_WINDOWS ) ///////////////////////////////////////// - -# if !defined ( CATCH_CONFIG_WINDOWS_SEH ) - -namespace Catch { - struct FatalConditionHandler { - void reset(); - }; -} - -# else // CATCH_CONFIG_WINDOWS_SEH is defined - -namespace Catch { - - struct FatalConditionHandler { - - static LONG CALLBACK handleVectoredException(PEXCEPTION_POINTERS ExceptionInfo); - FatalConditionHandler(); - static void reset(); - ~FatalConditionHandler(); - - private: - static bool isSet; - static ULONG guaranteeSize; - static PVOID exceptionHandlerHandle; - }; - -} // namespace Catch - -# endif // CATCH_CONFIG_WINDOWS_SEH - -#else // Not Windows - assumed to be POSIX compatible ////////////////////////// - -# if !defined(CATCH_CONFIG_POSIX_SIGNALS) - -namespace Catch { - struct FatalConditionHandler { - void reset(); - }; -} - -# else // CATCH_CONFIG_POSIX_SIGNALS is defined - -#include - -namespace Catch { - - struct FatalConditionHandler { - - static bool isSet; - static struct sigaction oldSigActions[];// [sizeof(signalDefs) / sizeof(SignalDefs)]; - static stack_t oldSigStack; - static char altStackMem[]; - - static void handleSignal( int sig ); - - FatalConditionHandler(); - ~FatalConditionHandler(); - static void reset(); - }; - -} // namespace Catch - -# endif // CATCH_CONFIG_POSIX_SIGNALS - -#endif // not Windows - -// end catch_fatal_condition.h namespace { // Report the error condition void reportFatal( char const * const message ) { @@ -6485,15 +7227,9 @@ namespace { } } -#if defined ( CATCH_PLATFORM_WINDOWS ) ///////////////////////////////////////// +#endif // signals/SEH handling -# if !defined ( CATCH_CONFIG_WINDOWS_SEH ) - -namespace Catch { - void FatalConditionHandler::reset() {} -} - -# else // CATCH_CONFIG_WINDOWS_SEH is defined +#if defined( CATCH_CONFIG_WINDOWS_SEH ) namespace Catch { struct SignalDefs { DWORD id; const char* name; }; @@ -6533,7 +7269,6 @@ namespace Catch { void FatalConditionHandler::reset() { if (isSet) { - // Unregister handler and restore the old guarantee RemoveVectoredExceptionHandler(exceptionHandlerHandle); SetThreadStackGuarantee(&guaranteeSize); exceptionHandlerHandle = nullptr; @@ -6551,19 +7286,7 @@ PVOID FatalConditionHandler::exceptionHandlerHandle = nullptr; } // namespace Catch -# endif // CATCH_CONFIG_WINDOWS_SEH - -#else // Not Windows - assumed to be POSIX compatible ////////////////////////// - -# if !defined(CATCH_CONFIG_POSIX_SIGNALS) - -namespace Catch { - void FatalConditionHandler::reset() {} -} - -# else // CATCH_CONFIG_POSIX_SIGNALS is defined - -#include +#elif defined( CATCH_CONFIG_POSIX_SIGNALS ) namespace Catch { @@ -6632,9 +7355,17 @@ namespace Catch { } // namespace Catch -# endif // CATCH_CONFIG_POSIX_SIGNALS +#else -#endif // not Windows +namespace Catch { + void FatalConditionHandler::reset() {} +} + +#endif // signals/SEH handling + +#if defined(__GNUC__) +# pragma GCC diagnostic pop +#endif // end catch_fatal_condition.cpp // start catch_interfaces_capture.cpp @@ -6845,11 +7576,11 @@ namespace Catch { // end catch_interfaces_testcase.cpp // start catch_leak_detector.cpp -namespace Catch { - #ifdef CATCH_CONFIG_WINDOWS_CRTDBG #include +namespace Catch { + LeakDetector::LeakDetector() { int flag = _CrtSetDbgFlag(_CRTDBG_REPORT_FLAG); flag |= _CRTDBG_LEAK_CHECK_DF; @@ -6860,14 +7591,13 @@ namespace Catch { // Change this to leaking allocation's number to break there _CrtSetBreakAlloc(-1); } +} #else - LeakDetector::LeakDetector(){} + Catch::LeakDetector::LeakDetector() {} #endif - -} // end catch_leak_detector.cpp // start catch_list.cpp @@ -6913,11 +7643,10 @@ namespace Catch { std::size_t listTests( Config const& config ) { TestSpec testSpec = config.testSpec(); - if( config.testSpec().hasFilters() ) + if( config.hasTestFilters() ) Catch::cout() << "Matching test cases:\n"; else { Catch::cout() << "All available test cases:\n"; - testSpec = TestSpecParser( ITagAliasRegistry::get() ).parse( "*" ).testSpec(); } auto matchedTestCases = filterTests( getAllTestCasesSorted( config ), testSpec, config ); @@ -6939,7 +7668,7 @@ namespace Catch { Catch::cout() << Column( testCaseInfo.tagsAsString() ).indent( 6 ) << "\n"; } - if( !config.testSpec().hasFilters() ) + 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; @@ -6948,8 +7677,6 @@ namespace Catch { 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 matchedTestCases = filterTests( getAllTestCasesSorted( config ), testSpec, config ); for( auto const& testCaseInfo : matchedTestCases ) { @@ -6979,11 +7706,10 @@ namespace Catch { std::size_t listTags( Config const& config ) { TestSpec testSpec = config.testSpec(); - if( config.testSpec().hasFilters() ) + if( config.hasTestFilters() ) Catch::cout() << "Tags for matching test cases:\n"; else { Catch::cout() << "All available tags:\n"; - testSpec = TestSpecParser( ITagAliasRegistry::get() ).parse( "*" ).testSpec(); } std::map tagCounts; @@ -7000,13 +7726,14 @@ namespace Catch { } for( auto const& tagCount : tagCounts ) { - std::ostringstream oss; - oss << " " << std::setw(2) << tagCount.second.count << " "; + ReusableStringStream rss; + rss << " " << std::setw(2) << tagCount.second.count << " "; + auto str = rss.str(); auto wrapper = Column( tagCount.second.all() ) .initialIndent( 0 ) - .indent( oss.str().size() ) + .indent( str.size() ) .width( CATCH_CONFIG_CONSOLE_WIDTH-10 ); - Catch::cout() << oss.str() << wrapper << '\n'; + Catch::cout() << str << wrapper << '\n'; } Catch::cout() << pluralise( tagCounts.size(), "tag" ) << '\n' << std::endl; return tagCounts.size(); @@ -7071,8 +7798,138 @@ using Matchers::Impl::MatcherBase; } // namespace Catch // end catch_matchers.cpp +// start catch_matchers_floating.cpp + +#include +#include +#include +#include + +namespace Catch { +namespace Matchers { +namespace Floating { +enum class FloatingPointKind : uint8_t { + Float, + Double +}; +} +} +} + +namespace { + +template +struct Converter; + +template <> +struct Converter { + static_assert(sizeof(float) == sizeof(int32_t), "Important ULP matcher assumption violated"); + Converter(float f) { + std::memcpy(&i, &f, sizeof(f)); + } + int32_t i; +}; + +template <> +struct Converter { + static_assert(sizeof(double) == sizeof(int64_t), "Important ULP matcher assumption violated"); + Converter(double d) { + std::memcpy(&i, &d, sizeof(d)); + } + int64_t i; +}; + +template +auto convert(T t) -> Converter { + return Converter(t); +} + +template +bool almostEqualUlps(FP lhs, FP rhs, int maxUlpDiff) { + // Comparison with NaN should always be false. + // This way we can rule it out before getting into the ugly details + if (std::isnan(lhs) || std::isnan(rhs)) { + return false; + } + + auto lc = convert(lhs); + auto rc = convert(rhs); + + if ((lc.i < 0) != (rc.i < 0)) { + // Potentially we can have +0 and -0 + return lhs == rhs; + } + + auto ulpDiff = std::abs(lc.i - rc.i); + return ulpDiff <= maxUlpDiff; +} + +} + +namespace Catch { +namespace Matchers { +namespace Floating { + WithinAbsMatcher::WithinAbsMatcher(double target, double margin) + :m_target{ target }, m_margin{ margin } { + if (m_margin < 0) { + throw std::domain_error("Allowed margin difference has to be >= 0"); + } + } + + // 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 >= m_margin); + } + + std::string WithinAbsMatcher::describe() const { + return "is within " + ::Catch::Detail::stringify(m_margin) + " of " + ::Catch::Detail::stringify(m_target); + } + + WithinUlpsMatcher::WithinUlpsMatcher(double target, int ulps, FloatingPointKind baseType) + :m_target{ target }, m_ulps{ ulps }, m_type{ baseType } { + if (m_ulps < 0) { + throw std::domain_error("Allowed ulp difference has to be >= 0"); + } + } + + bool WithinUlpsMatcher::match(double const& matchee) const { + switch (m_type) { + case FloatingPointKind::Float: + return almostEqualUlps(static_cast(matchee), static_cast(m_target), m_ulps); + case FloatingPointKind::Double: + return almostEqualUlps(matchee, m_target, m_ulps); + default: + throw std::domain_error("Unknown FloatingPointKind value"); + } + } + + std::string WithinUlpsMatcher::describe() const { + return "is within " + std::to_string(m_ulps) + " ULPs of " + ::Catch::Detail::stringify(m_target) + ((m_type == FloatingPointKind::Float)? "f" : ""); + } + +}// namespace Floating + +Floating::WithinUlpsMatcher WithinULP(double target, int maxUlpDiff) { + return Floating::WithinUlpsMatcher(target, maxUlpDiff, Floating::FloatingPointKind::Double); +} + +Floating::WithinUlpsMatcher WithinULP(float target, int maxUlpDiff) { + return Floating::WithinUlpsMatcher(target, maxUlpDiff, Floating::FloatingPointKind::Float); +} + +Floating::WithinAbsMatcher WithinAbs(double target, double margin) { + return Floating::WithinAbsMatcher(target, margin); +} + +} // namespace Matchers +} // namespace Catch + +// end catch_matchers_floating.cpp // start catch_matchers_string.cpp +#include + namespace Catch { namespace Matchers { @@ -7134,6 +7991,21 @@ namespace Matchers { 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 ) { @@ -7149,11 +8021,22 @@ namespace Matchers { 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 namespace Catch { MessageInfo::MessageInfo( std::string const& _macroName, @@ -7193,11 +8076,10 @@ namespace Catch { } ScopedMessage::~ScopedMessage() { - if ( !std::uncaught_exception() ){ + if ( !uncaught_exceptions() ){ getResultCapture().popScopedMessage(m_info); } } - } // end namespace Catch // end catch_message.cpp // start catch_random_number_generator.cpp @@ -7303,7 +8185,7 @@ namespace Catch { void invoke() const override; }; - std::string extractClassName( std::string const& classOrQualifiedMethodName ); + std::string extractClassName( StringRef const& classOrQualifiedMethodName ); /////////////////////////////////////////////////////////////////////////// @@ -7463,6 +8345,7 @@ namespace Catch { delete getTheRegistryHub(); getTheRegistryHub() = nullptr; cleanUpContext(); + ReusableStringStream::cleanup(); } std::string translateActiveException() { return getRegistryHub().getExceptionTranslatorRegistry().translateActiveException(); @@ -7515,172 +8398,66 @@ namespace Catch { } bool shouldContinueOnFailure( int flags ) { return ( flags & ResultDisposition::ContinueOnFailure ) != 0; } - bool isFalseTest( int flags ) { return ( flags & ResultDisposition::FalseTest ) != 0; } bool shouldSuppressFailure( int flags ) { return ( flags & ResultDisposition::SuppressFail ) != 0; } } // end namespace Catch // end catch_result_type.cpp // start catch_run_context.cpp -// start catch_run_context.h -#include +#include +#include +#include namespace Catch { - struct IMutableContext; - - class StreamRedirect { + class RedirectedStream { + std::ostream& m_originalStream; + std::ostream& m_redirectionStream; + std::streambuf* m_prevBuf; public: - StreamRedirect(std::ostream& stream, std::string& targetString); + 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() { + m_originalStream.rdbuf( m_prevBuf ); + } + }; - ~StreamRedirect(); - - private: - std::ostream& m_stream; - std::streambuf* m_prevBuf; - std::ostringstream m_oss; - std::string& m_targetString; + class RedirectedStdOut { + ReusableStringStream m_rss; + RedirectedStream m_cout; + public: + RedirectedStdOut() : m_cout( Catch::cout(), m_rss.get() ) {} + auto str() const -> std::string { return m_rss.str(); } }; // 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 { + // order of writes + class RedirectedStdErr { + ReusableStringStream m_rss; + RedirectedStream m_cerr; + RedirectedStream m_clog; public: - StdErrRedirect(std::string& targetString); - ~StdErrRedirect(); - private: - std::streambuf* m_cerrBuf; - std::streambuf* m_clogBuf; - std::ostringstream m_oss; - std::string& m_targetString; + RedirectedStdErr() + : m_cerr( Catch::cerr(), m_rss.get() ), + m_clog( Catch::clog(), m_rss.get() ) + {} + auto str() const -> std::string { return m_rss.str(); } }; - /////////////////////////////////////////////////////////////////////////// - - class RunContext : public IResultCapture, public IRunner { - - public: - RunContext( RunContext const& ) = delete; - RunContext& operator =( RunContext const& ) = delete; - - explicit RunContext(IConfigPtr const& _config, IStreamingReporterPtr&& reporter); - - virtual ~RunContext(); - - 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; - - private: // IResultCapture - - void assertionStarting(AssertionInfo const& info) override; - void assertionEnded(AssertionResult const& result) override; - - bool sectionStarted( SectionInfo const& sectionInfo, Counts& assertions ) override; - bool testForMissingAssertions(Counts& assertions); - - void sectionEnded(SectionEndInfo const& endInfo) override; - void sectionEndedEarly(SectionEndInfo const& endInfo) override; - - void benchmarkStarting( BenchmarkInfo const& info ) override; - void benchmarkEnded( BenchmarkStats const& stats ) override; - - void pushScopedMessage(MessageInfo const& message) override; - void popScopedMessage(MessageInfo const& message) 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; - - void assertionRun() override; - - public: - // !TBD We need to do this another way! - bool aborting() const override; - - private: - - void runCurrentTest(std::string& redirectedCout, std::string& redirectedCerr); - void invokeActiveTestCase(); - - private: - - void handleUnfinishedSections(); - - TestRunInfo m_runInfo; - IMutableContext& m_context; - TestCase const* m_activeTestCase = nullptr; - ITracker* m_testCaseTracker; - Option m_lastResult; - - IConfigPtr m_config; - Totals m_totals; - IStreamingReporterPtr m_reporter; - std::vector m_messages; - AssertionInfo m_lastAssertionInfo; - std::vector m_unfinishedSections; - std::vector m_activeSections; - TrackerContext m_trackerContext; - std::size_t m_prevPassed = 0; - bool m_shouldReportUnexpected = true; - }; - - IResultCapture& getResultCapture(); - -} // end namespace Catch - -// end catch_run_context.h - -#include -#include - -namespace Catch { - - StreamRedirect::StreamRedirect(std::ostream& stream, std::string& targetString) - : m_stream(stream), - m_prevBuf(stream.rdbuf()), - m_targetString(targetString) { - stream.rdbuf(m_oss.rdbuf()); - } - - StreamRedirect::~StreamRedirect() { - m_targetString += m_oss.str(); - m_stream.rdbuf(m_prevBuf); - } - - StdErrRedirect::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::~StdErrRedirect() { - m_targetString += m_oss.str(); - cerr().rdbuf(m_cerrBuf); - clog().rdbuf(m_clogBuf); - } - RunContext::RunContext(IConfigPtr const& _config, IStreamingReporterPtr&& reporter) : m_runInfo(_config->name()), m_context(getCurrentMutableContext()), m_config(_config), m_reporter(std::move(reporter)), - m_lastAssertionInfo{ "", SourceLineInfo("",0), "", ResultDisposition::Normal } + m_lastAssertionInfo{ StringRef(), SourceLineInfo("",0), StringRef(), ResultDisposition::Normal }, + m_includeSuccessfulResults( m_config->includeSuccessfulResults() ) { m_context.setRunner(this); m_context.setConfig(m_config); @@ -7706,7 +8483,7 @@ namespace Catch { std::string redirectedCout; std::string redirectedCerr; - TestCaseInfo testInfo = testCase.getTestCaseInfo(); + auto const& testInfo = testCase.getTestCaseInfo(); m_reporter->testCaseStarting(testInfo); @@ -7748,27 +8525,33 @@ namespace Catch { return *m_reporter; } - void RunContext::assertionStarting(AssertionInfo const& info) { - m_reporter->assertionStarting( info ); - } 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(m_reporter->assertionEnded(AssertionStats(result, m_messages, m_totals))); // Reset working state - m_lastAssertionInfo = { "", m_lastAssertionInfo.lineInfo, "{Unknown expression after the reported line}", m_lastAssertionInfo.resultDisposition }; + 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)); @@ -7858,7 +8641,7 @@ namespace Catch { tempResult.message = message; AssertionResult result(m_lastAssertionInfo, tempResult); - getResultCapture().assertionEnded(result); + assertionEnded(result); handleUnfinishedSections(); @@ -7887,17 +8670,13 @@ namespace Catch { } bool RunContext::lastAssertionPassed() { - return m_totals.assertions.passed == (m_prevPassed + 1); + return m_lastAssertionPassed; } void RunContext::assertionPassed() { + m_lastAssertionPassed = true; ++m_totals.assertions.passed; - m_lastAssertionInfo.capturedExpression = "{Unknown expression after the reported line}"; - m_lastAssertionInfo.macroName = ""; - } - - void RunContext::assertionRun() { - m_prevPassed = m_totals.assertions.passed; + resetAssertionInfo(); } bool RunContext::aborting() const { @@ -7911,18 +8690,22 @@ namespace Catch { 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; try { - m_lastAssertionInfo = { "TEST_CASE", testCaseInfo.lineInfo, "", ResultDisposition::Normal }; - - seedRng(*m_config); - - Timer timer; - timer.start(); if (m_reporter->getPreferences().shouldRedirectStdOut) { - StreamRedirect coutRedir(cout(), redirectedCout); - StdErrRedirect errRedir(redirectedCerr); + RedirectedStdOut redirectedStdOut; + RedirectedStdErr redirectedStdErr; + timer.start(); invokeActiveTestCase(); + redirectedCout += redirectedStdOut.str(); + redirectedCerr += redirectedStdErr.str(); + } else { + timer.start(); invokeActiveTestCase(); } duration = timer.getElapsedSeconds(); @@ -7931,20 +8714,18 @@ namespace Catch { } catch (...) { // Under CATCH_CONFIG_FAST_COMPILE, unexpected exceptions under REQUIRE assertions // are reported without translation at the point of origin. - if (m_shouldReportUnexpected) { - AssertionHandler - ( m_lastAssertionInfo.macroName, - m_lastAssertionInfo.lineInfo, - m_lastAssertionInfo.capturedExpression, - m_lastAssertionInfo.resultDisposition ).useActiveException(); + 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(); - Counts assertions = m_totals.assertions - prevAssertions; - bool missingAssertions = testForMissingAssertions(assertions); SectionStats testCaseSectionStats(testCaseSection, assertions, duration, missingAssertions); m_reporter->sectionEnded(testCaseSectionStats); } @@ -7966,6 +8747,112 @@ namespace Catch { 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 = 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; @@ -7985,22 +8872,15 @@ namespace Catch { m_timer.start(); } -#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() ) + if( uncaught_exceptions() ) getResultCapture().sectionEndedEarly( endInfo ); else getResultCapture().sectionEnded( endInfo ); } } -#if defined(_MSC_VER) -#pragma warning(pop) -#endif // This indicates whether the section should be executed or not Section::operator bool() const { @@ -8045,12 +8925,12 @@ namespace Catch { void showHelp() const; void libIdentify(); - int applyCommandLine( int argc, char* argv[] ); + int applyCommandLine( int argc, char const * const * argv ); void useConfigData( ConfigData const& configData ); int run( int argc, char* argv[] ); - #if defined(WIN32) && defined(UNICODE) + #if defined(CATCH_CONFIG_WCHAR) && defined(WIN32) && defined(UNICODE) int run( int argc, wchar_t* const argv[] ); #endif int run(); @@ -8105,95 +8985,102 @@ namespace Catch { #include #include -namespace { - const int MaxExitCode = 255; - using Catch::IStreamingReporterPtr; - using Catch::IConfigPtr; - using Catch::Config; +namespace Catch { - 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 << "'"); + namespace { + const int MaxExitCode = 255; - return reporter; - } + 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; + } #ifndef CATCH_CONFIG_DEFAULT_REPORTER #define CATCH_CONFIG_DEFAULT_REPORTER "console" #endif - IStreamingReporterPtr makeReporter(std::shared_ptr const& config) { - auto const& reporterNames = config->getReporterNames(); - if (reporterNames.empty()) - return createReporter(CATCH_CONFIG_DEFAULT_REPORTER, config); + IStreamingReporterPtr makeReporter(std::shared_ptr const& config) { + auto const& reporterNames = config->getReporterNames(); + if (reporterNames.empty()) + return createReporter(CATCH_CONFIG_DEFAULT_REPORTER, config); - IStreamingReporterPtr reporter; - for (auto const& name : reporterNames) - addReporter(reporter, createReporter(name, config)); - return reporter; - } + IStreamingReporterPtr reporter; + for (auto const& name : reporterNames) + addReporter(reporter, createReporter(name, config)); + return reporter; + } #undef CATCH_CONFIG_DEFAULT_REPORTER - void addListeners(IStreamingReporterPtr& reporters, IConfigPtr const& config) { - auto const& listeners = Catch::getRegistryHub().getReporterRegistry().getListeners(); - for (auto const& listener : listeners) - addReporter(reporters, listener->create(Catch::ReporterConfig(config))); - } - - Catch::Totals runTests(std::shared_ptr const& config) { - using namespace Catch; - IStreamingReporterPtr reporter = makeReporter(config); - addListeners(reporter, config); - - RunContext context(config, std::move(reporter)); - - Totals totals; - - context.testGroupStarting(config->name(), 1, 1); - - TestSpec testSpec = config->testSpec(); - if (!testSpec.hasFilters()) - testSpec = TestSpecParser(ITagAliasRegistry::get()).parse("~[.]").testSpec(); // All not hidden tests - - auto const& allTestCases = getAllTestCasesSorted(*config); - for (auto const& testCase : allTestCases) { - if (!context.aborting() && matchTest(testCase, testSpec, *config)) - totals += context.runTest(testCase); - else - context.reporter().skipTest(testCase); + void addListeners(IStreamingReporterPtr& reporters, IConfigPtr const& config) { + auto const& listeners = Catch::getRegistryHub().getReporterRegistry().getListeners(); + for (auto const& listener : listeners) + addReporter(reporters, listener->create(Catch::ReporterConfig(config))); } - context.testGroupEnded(config->name(), totals, 1, 1); - return totals; - } + Catch::Totals runTests(std::shared_ptr const& config) { + IStreamingReporterPtr reporter = makeReporter(config); + addListeners(reporter, config); - void applyFilenamesAsTags(Catch::IConfig const& config) { - using namespace Catch; - auto& tests = const_cast&>(getAllTestCasesSorted(config)); - for (auto& testCase : tests) { - auto tags = testCase.tags; + RunContext context(config, std::move(reporter)); - std::string filename = testCase.lineInfo.file; - auto lastSlash = filename.find_last_of("\\/"); - if (lastSlash != std::string::npos) { - filename.erase(0, lastSlash); - filename[0] = '#'; + Totals totals; + + context.testGroupStarting(config->name(), 1, 1); + + TestSpec testSpec = config->testSpec(); + + auto const& allTestCases = getAllTestCasesSorted(*config); + for (auto const& testCase : allTestCases) { + if (!context.aborting() && matchTest(testCase, testSpec, *config)) + totals += context.runTest(testCase); + else + context.reporter().skipTest(testCase); } - auto lastDot = filename.find_last_of('.'); - if (lastDot != std::string::npos) { - filename.erase(lastDot); + if (config->warnAboutNoTests() && totals.testCases.total() == 0) { + ReusableStringStream testConfig; + + bool first = true; + for (const auto& input : config->getTestsOrTags()) { + if (!first) { testConfig << ' '; } + first = false; + testConfig << input; + } + + context.reporter().noMatchingTestCases(testConfig.str()); + totals.error = -1; } - tags.push_back(std::move(filename)); - setTags(testCase, tags); + context.testGroupEnded(config->name(), totals, 1, 1); + return totals; } - } -} + void applyFilenamesAsTags(Catch::IConfig const& config) { + auto& tests = const_cast&>(getAllTestCasesSorted(config)); + for (auto& testCase : tests) { + auto tags = testCase.tags; -namespace Catch { + std::string filename = testCase.lineInfo.file; + auto lastSlash = filename.find_last_of("\\/"); + if (lastSlash != std::string::npos) { + filename.erase(0, lastSlash); + filename[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; @@ -8206,7 +9093,7 @@ namespace Catch { if ( !exceptions.empty() ) { m_startupExceptions = true; Colour colourGuard( Colour::Red ); - Catch::cerr() << "Errors occured during startup!" << '\n'; + Catch::cerr() << "Errors occurred during startup!" << '\n'; // iterate over all exceptions and notify user for ( const auto& ex_ptr : exceptions ) { try { @@ -8238,7 +9125,7 @@ namespace Catch { << std::left << std::setw(16) << "version: " << libraryVersion() << std::endl; } - int Session::applyCommandLine( int argc, char* argv[] ) { + int Session::applyCommandLine( int argc, char const * const * argv ) { if( m_startupExceptions ) return 1; @@ -8275,7 +9162,7 @@ namespace Catch { return returnCode; } -#if defined(WIN32) && defined(UNICODE) +#if defined(CATCH_CONFIG_WCHAR) && defined(WIN32) && defined(UNICODE) int Session::run( int argc, wchar_t* const argv[] ) { char **utf8Argv = new char *[ argc ]; @@ -8346,7 +9233,11 @@ namespace Catch { if( Option listed = list( config() ) ) return static_cast( *listed ); - return (std::min)( MaxExitCode, static_cast( runTests( m_config ).assertions.failed ) ); + auto totals = runTests( m_config ); + // 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, totals.error, static_cast( totals.assertions.failed ) } ); } catch( std::exception& ex ) { Catch::cerr() << ex.what() << std::endl; @@ -8377,106 +9268,202 @@ namespace Catch { // end catch_startup_exception_registry.cpp // start catch_stream.cpp -#include #include #include +#include +#include +#include +#include + +#if defined(__clang__) +# pragma clang diagnostic push +# pragma clang diagnostic ignored "-Wexit-time-destructors" +#endif namespace Catch { - template - class StreamBufImpl : public StreamBufBase { - 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( c ) ) ); - else - sputc( static_cast( c ) ); - } - return 0; - } - - int sync() override { - if( pbase() != pptr() ) { - m_writer( std::string( pbase(), static_cast( pptr() - pbase() ) ) ); - setp( pbase(), epptr() ); - } - return 0; - } - }; - - /////////////////////////////////////////////////////////////////////////// - Catch::IStream::~IStream() = default; - FileStream::FileStream( std::string const& filename ) { - m_ofs.open( filename.c_str() ); - CATCH_ENFORCE( !m_ofs.fail(), "Unable to open file: '" << filename << "'" ); + namespace detail { namespace { + template + 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( c ) ) ); + else + sputc( static_cast( c ) ); + } + return 0; + } + + int sync() override { + if( pbase() != pptr() ) { + m_writer( std::string( pbase(), static_cast( 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> m_streamBuf; + mutable std::ostream m_os; + public: + DebugOutStream() + : m_streamBuf( new StreamBufImpl() ), + 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 ); } - std::ostream& FileStream::stream() const { - return m_ofs; - } + // This class encapsulates the idea of a pool of ostringstreams that can be reused. + struct StringStreams { + std::vector> m_streams; + std::vector m_unused; + std::ostringstream m_referenceStream; // Used for copy state/ flags from + static StringStreams* s_instance; - struct OutputDebugWriter { + auto add() -> std::size_t { + if( m_unused.empty() ) { + m_streams.push_back( std::unique_ptr( new std::ostringstream ) ); + return m_streams.size()-1; + } + else { + auto index = m_unused.back(); + m_unused.pop_back(); + return index; + } + } - void operator()( std::string const&str ) { - writeToDebugConsole( str ); + void release( std::size_t index ) { + m_streams[index]->copyfmt( m_referenceStream ); // Restore initial flags and other state + m_unused.push_back(index); + } + + // !TBD: put in TLS + static auto instance() -> StringStreams& { + if( !s_instance ) + s_instance = new StringStreams(); + return *s_instance; + } + static void cleanup() { + delete s_instance; + s_instance = nullptr; } }; - DebugOutStream::DebugOutStream() - : m_streamBuf( new StreamBufImpl() ), - m_os( m_streamBuf.get() ) - {} + StringStreams* StringStreams::s_instance = nullptr; - std::ostream& DebugOutStream::stream() const { - return m_os; + void ReusableStringStream::cleanup() { + StringStreams::cleanup(); } - // Store the streambuf from cout up-front because - // cout may get redirected when running tests - CoutStream::CoutStream() - : m_os( Catch::cout().rdbuf() ) + ReusableStringStream::ReusableStringStream() + : m_index( StringStreams::instance().add() ), + m_oss( StringStreams::instance().m_streams[m_index].get() ) {} - std::ostream& CoutStream::stream() const { - return m_os; + ReusableStringStream::~ReusableStringStream() { + static_cast( m_oss )->str(""); + m_oss->clear(); + StringStreams::instance().release( m_index ); } + auto ReusableStringStream::str() const -> std::string { + return static_cast( 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; - } + 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_streambuf.cpp -namespace Catch { - StreamBufBase::~StreamBufBase() = default; -} -// end catch_streambuf.cpp +#if defined(__clang__) +# pragma clang diagnostic pop +#endif +// end catch_stream.cpp // start catch_string_manip.cpp #include @@ -8556,62 +9543,20 @@ namespace Catch { #endif #include -#include #include +#include + +namespace { + const uint32_t byte_2_lead = 0xC0; + const uint32_t byte_3_lead = 0xE0; + const uint32_t byte_4_lead = 0xF0; +} namespace Catch { - - auto getEmptyStringRef() -> StringRef { - static StringRef s_emptyStringRef(""); - return s_emptyStringRef; - } - - StringRef::StringRef() noexcept - : StringRef( getEmptyStringRef() ) - {} - - StringRef::StringRef( StringRef const& other ) noexcept - : m_start( other.m_start ), - m_size( other.m_size ) - {} - - StringRef::StringRef( StringRef&& other ) noexcept - : m_start( other.m_start ), - m_size( other.m_size ), - m_data( other.m_data ) - { - other.m_data = nullptr; - } - StringRef::StringRef( char const* rawChars ) noexcept - : m_start( rawChars ), - m_size( static_cast( std::strlen( rawChars ) ) ) - { - assert( rawChars != nullptr ); - } - - StringRef::StringRef( char const* rawChars, size_type size ) noexcept - : m_start( rawChars ), - m_size( size ) - { - size_type rawSize = rawChars == nullptr ? 0 : static_cast( std::strlen( rawChars ) ); - if( rawSize < size ) - m_size = rawSize; - } - - StringRef::StringRef( std::string const& stdString ) noexcept - : m_start( stdString.c_str() ), - m_size( stdString.size() ) + : StringRef( rawChars, static_cast(std::strlen(rawChars) ) ) {} - StringRef::~StringRef() noexcept { - delete[] m_data; - } - - auto StringRef::operator = ( StringRef other ) noexcept -> StringRef& { - swap( other ); - return *this; - } StringRef::operator std::string() const { return std::string( m_start, m_size ); } @@ -8627,7 +9572,7 @@ namespace Catch { const_cast( this )->takeOwnership(); return m_start; } - auto StringRef::data() const noexcept -> char const* { + auto StringRef::currentData() const noexcept -> char const* { return m_start; } @@ -8665,25 +9610,17 @@ namespace Catch { return m_start[index]; } - auto StringRef::empty() const noexcept -> bool { - return m_size == 0; - } - - auto StringRef::size() const noexcept -> size_type { - return m_size; - } auto StringRef::numberOfCharacters() const noexcept -> size_type { size_type noChars = m_size; // Make adjustments for uft encodings for( size_type i=0; i < m_size; ++i ) { char c = m_start[i]; - if( ( c & 0b11000000 ) == 0b11000000 ) { - if( ( c & 0b11100000 ) == 0b11000000 ) + if( ( c & byte_2_lead ) == byte_2_lead ) { + noChars--; + if (( c & byte_3_lead ) == byte_3_lead ) + noChars--; + if( ( c & byte_4_lead ) == byte_4_lead ) noChars--; - else if( ( c & 0b11110000 ) == 0b11100000 ) - noChars-=2; - else if( ( c & 0b11111000 ) == 0b11110000 ) - noChars-=3; } } return noChars; @@ -8704,7 +9641,12 @@ namespace Catch { } auto operator << ( std::ostream& os, StringRef const& str ) -> std::ostream& { - return os << str.c_str(); + return os.write(str.currentData(), str.size()); + } + + auto operator+=( std::string& lhs, StringRef const& rhs ) -> std::string& { + lhs.append(rhs.currentData(), rhs.size()); + return lhs; } } // namespace Catch @@ -8736,6 +9678,8 @@ namespace Catch { // end catch_tag_alias_autoregistrar.cpp // start catch_tag_alias_registry.cpp +#include + namespace Catch { TagAliasRegistry::~TagAliasRegistry() {} @@ -8784,6 +9728,7 @@ namespace Catch { #include #include #include +#include namespace Catch { @@ -8816,8 +9761,7 @@ namespace Catch { TestCase makeTestCase( ITestInvoker* _testCase, std::string const& _className, - std::string const& _name, - std::string const& _descOrTags, + NameAndTags const& nameAndTags, SourceLineInfo const& _lineInfo ) { bool isHidden = false; @@ -8826,6 +9770,7 @@ namespace Catch { std::vector tags; std::string desc, tag; bool inTag = false; + std::string _descOrTags = nameAndTags.tags; for (char c : _descOrTags) { if( !inTag ) { if( c == '[' ) @@ -8853,8 +9798,8 @@ namespace Catch { tags.push_back( "." ); } - TestCaseInfo info( _name, _className, desc, tags, _lineInfo ); - return TestCase( _testCase, info ); + TestCaseInfo info( nameAndTags.name, _className, desc, tags, _lineInfo ); + return TestCase( _testCase, std::move(info) ); } void setTags( TestCaseInfo& testCaseInfo, std::vector tags ) { @@ -8914,7 +9859,7 @@ namespace Catch { return ret; } - TestCase::TestCase( ITestInvoker* testCase, TestCaseInfo const& info ) : TestCaseInfo( info ), test( testCase ) {} + TestCase::TestCase( ITestInvoker* testCase, TestCaseInfo&& info ) : TestCaseInfo( std::move(info) ), test( testCase ) {} TestCase TestCase::withName( std::string const& _newName ) const { TestCase other( *this ); @@ -8997,9 +9942,9 @@ namespace Catch { void TestRegistry::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() ) ); + ReusableStringStream rss; + rss << "Anonymous test case " << ++m_unnamedCount; + return registerTest( testCase.withName( rss.str() ) ); } m_functions.push_back( testCase ); } @@ -9025,7 +9970,7 @@ namespace Catch { m_testAsFunction(); } - std::string extractClassName( std::string const& classOrQualifiedMethodName ) { + std::string extractClassName( StringRef const& classOrQualifiedMethodName ) { std::string className = classOrQualifiedMethodName; if( startsWith( className, '&' ) ) { @@ -9046,6 +9991,7 @@ namespace Catch { #include #include #include +#include #if defined(__clang__) # pragma clang diagnostic push @@ -9321,17 +10267,16 @@ namespace Catch { return new(std::nothrow) TestInvokerAsFunction( testAsFunction ); } - NameAndTags::NameAndTags( StringRef name_ , StringRef tags_ ) noexcept : name( name_ ), tags( tags_ ) {} + NameAndTags::NameAndTags( StringRef const& name_ , StringRef const& tags_ ) noexcept : name( name_ ), tags( tags_ ) {} - AutoReg::AutoReg( ITestInvoker* invoker, SourceLineInfo const& lineInfo, StringRef classOrMethod, NameAndTags const& nameAndTags ) noexcept { + AutoReg::AutoReg( ITestInvoker* invoker, SourceLineInfo const& lineInfo, StringRef const& classOrMethod, NameAndTags const& nameAndTags ) noexcept { try { getMutableRegistryHub() .registerTest( makeTestCase( invoker, extractClassName( classOrMethod ), - nameAndTags.name, - nameAndTags.tags, + nameAndTags, lineInfo)); } catch (...) { // Do not throw when constructing global objects, instead register the exception to be processed later @@ -9514,11 +10459,11 @@ namespace Catch { void Timer::start() { m_nanoseconds = getCurrentNanosecondsSinceEpoch(); } - auto Timer::getElapsedNanoseconds() const -> unsigned int { - return static_cast(getCurrentNanosecondsSinceEpoch() - m_nanoseconds); + auto Timer::getElapsedNanoseconds() const -> uint64_t { + return getCurrentNanosecondsSinceEpoch() - m_nanoseconds; } - auto Timer::getElapsedMicroseconds() const -> unsigned int { - return static_cast(getElapsedNanoseconds()/1000); + auto Timer::getElapsedMicroseconds() const -> uint64_t { + return getElapsedNanoseconds()/1000; } auto Timer::getElapsedMilliseconds() const -> unsigned int { return static_cast(getElapsedMicroseconds()/1000); @@ -9537,6 +10482,12 @@ namespace Catch { # pragma clang diagnostic ignored "-Wglobal-constructors" #endif +// Enable specific decls locally +#if !defined(CATCH_CONFIG_ENABLE_CHRONO_STRINGMAKER) +#define CATCH_CONFIG_ENABLE_CHRONO_STRINGMAKER +#endif + +#include #include namespace Catch { @@ -9572,21 +10523,25 @@ namespace Detail { } unsigned char const *bytes = static_cast(object); - std::ostringstream os; - os << "0x" << std::setfill('0') << std::hex; + ReusableStringStream rss; + rss << "0x" << std::setfill('0') << std::hex; for( ; i != end; i += inc ) - os << std::setw(2) << static_cast(bytes[i]); - return os.str(); + rss << std::setw(2) << static_cast(bytes[i]); + return rss.str(); } } template std::string fpToString( T value, int precision ) { - std::ostringstream oss; - oss << std::setprecision( precision ) + if (std::isnan(value)) { + return "nan"; + } + + ReusableStringStream rss; + rss << std::setprecision( precision ) << std::fixed << value; - std::string d = oss.str(); + 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] == '.' ) @@ -9625,6 +10580,7 @@ std::string StringMaker::convert(const std::string& str) { return s; } +#ifdef CATCH_CONFIG_WCHAR std::string StringMaker::convert(const std::wstring& wstr) { std::string s; s.reserve(wstr.size()); @@ -9633,6 +10589,7 @@ std::string StringMaker::convert(const std::wstring& wstr) { } return ::Catch::Detail::stringify(s); } +#endif std::string StringMaker::convert(char const* str) { if (str) { @@ -9648,6 +10605,7 @@ std::string StringMaker::convert(char* str) { return{ "{null string}" }; } } +#ifdef CATCH_CONFIG_WCHAR std::string StringMaker::convert(wchar_t const * str) { if (str) { return ::Catch::Detail::stringify(std::wstring{ str }); @@ -9662,6 +10620,7 @@ std::string StringMaker::convert(wchar_t * str) { return{ "{null string}" }; } } +#endif std::string StringMaker::convert(int value) { return ::Catch::Detail::stringify(static_cast(value)); @@ -9670,12 +10629,12 @@ std::string StringMaker::convert(long value) { return ::Catch::Detail::stringify(static_cast(value)); } std::string StringMaker::convert(long long value) { - std::ostringstream oss; - oss << value; + ReusableStringStream rss; + rss << value; if (value > Detail::hexThreshold) { - oss << " (0x" << std::hex << value << ')'; + rss << " (0x" << std::hex << value << ')'; } - return oss.str(); + return rss.str(); } std::string StringMaker::convert(unsigned int value) { @@ -9685,12 +10644,12 @@ std::string StringMaker::convert(unsigned long value) { return ::Catch::Detail::stringify(static_cast(value)); } std::string StringMaker::convert(unsigned long long value) { - std::ostringstream oss; - oss << value; + ReusableStringStream rss; + rss << value; if (value > Detail::hexThreshold) { - oss << " (0x" << std::hex << value << ')'; + rss << " (0x" << std::hex << value << ')'; } - return oss.str(); + return rss.str(); } std::string StringMaker::convert(bool b) { @@ -9732,6 +10691,13 @@ std::string StringMaker::convert(double value) { return fpToString(value, 10); } +std::string ratio_string::symbol() { return "a"; } +std::string ratio_string::symbol() { return "f"; } +std::string ratio_string::symbol() { return "p"; } +std::string ratio_string::symbol() { return "n"; } +std::string ratio_string::symbol() { return "u"; } +std::string ratio_string::symbol() { return "m"; } + } // end namespace Catch #if defined(__clang__) @@ -9794,6 +10760,20 @@ namespace Catch { } // end catch_totals.cpp +// start catch_uncaught_exceptions.cpp + +#include + +namespace Catch { + bool uncaught_exceptions() { +#if defined(CATCH_CONFIG_CPP17_UNCAUGHT_EXCEPTIONS) + return std::uncaught_exceptions() > 0; +#else + return std::uncaught_exception(); +#endif + } +} // end namespace Catch +// end catch_uncaught_exceptions.cpp // start catch_version.cpp #include @@ -9826,7 +10806,7 @@ namespace Catch { } Version const& libraryVersion() { - static Version version( 2, 0, 1, "", 0 ); + static Version version( 2, 2, 0, "", 0 ); return version; } @@ -9834,6 +10814,8 @@ namespace Catch { // end catch_version.cpp // start catch_wildcard_pattern.cpp +#include + namespace Catch { WildcardPattern::WildcardPattern( std::string const& pattern, @@ -9873,103 +10855,6 @@ namespace Catch { // end catch_wildcard_pattern.cpp // start catch_xmlwriter.cpp -// start catch_xmlwriter.h - -#include -#include - -namespace Catch { - - class XmlEncode { - public: - enum ForWhat { ForTextNodes, ForAttributes }; - - XmlEncode( std::string const& str, ForWhat forWhat = ForTextNodes ); - - void encodeTo( std::ostream& os ) const; - - friend std::ostream& operator << ( std::ostream& os, XmlEncode const& xmlEncode ); - - private: - std::string m_str; - ForWhat m_forWhat; - }; - - class XmlWriter { - public: - - class ScopedElement { - public: - ScopedElement( XmlWriter* writer ); - - ScopedElement( ScopedElement&& other ) noexcept; - ScopedElement& operator=( ScopedElement&& other ) noexcept; - - ~ScopedElement(); - - ScopedElement& writeText( std::string const& text, bool indent = true ); - - template - ScopedElement& writeAttribute( std::string const& name, T const& attribute ) { - m_writer->writeAttribute( name, attribute ); - return *this; - } - - private: - mutable XmlWriter* m_writer = nullptr; - }; - - XmlWriter( std::ostream& os = Catch::cout() ); - ~XmlWriter(); - - XmlWriter( XmlWriter const& ) = delete; - XmlWriter& operator=( XmlWriter const& ) = delete; - - XmlWriter& startElement( std::string const& name ); - - ScopedElement scopedElement( std::string const& name ); - - XmlWriter& endElement(); - - XmlWriter& writeAttribute( std::string const& name, std::string const& attribute ); - - XmlWriter& writeAttribute( std::string const& name, bool attribute ); - - template - XmlWriter& writeAttribute( std::string const& name, T const& attribute ) { - m_oss.clear(); - m_oss.str(std::string()); - m_oss << attribute; - return writeAttribute( name, m_oss.str() ); - } - - XmlWriter& writeText( std::string const& text, bool indent = true ); - - XmlWriter& writeComment( std::string const& text ); - - void writeStylesheetRef( std::string const& url ); - - XmlWriter& writeBlankLine(); - - void ensureTagClosed(); - - private: - - void writeDeclaration(); - - void newlineIfNecessary(); - - bool m_tagIsOpen = false; - bool m_needsNewline = false; - std::vector m_tags; - std::string m_indent; - std::ostream& m_os; - std::ostringstream m_oss; - }; - -} - -// end catch_xmlwriter.h #include namespace Catch { @@ -10214,33 +11099,235 @@ namespace { return count == 1 ? std::string() : count == 2 ? "both " : "all " ; } -} + +} // anon namespace 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") << '.'; + } +} - struct CompactReporter : StreamingReporterBase { +// 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) {} - using StreamingReporterBase::StreamingReporterBase; + void print() { + printSourceInfo(); - ~CompactReporter() override; + itMessage = messages.begin(); - static std::string getDescription() { + 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: + void printSourceInfo() const { + Colour colourGuard(Colour::FileName); + stream << result.getSourceInfo() << ':'; + } + + void printResultType(Colour::Code colour, std::string const& passOrFail) const { + if (!passOrFail.empty()) { + { + Colour colourGuard(colour); + stream << ' ' << passOrFail; + } + stream << ':'; + } + } + + void printIssue(std::string const& issue) const { + stream << ' ' << issue; + } + + void printExpressionWas() { + if (result.hasExpression()) { + stream << ';'; + { + Colour colour(dimColour()); + stream << " expression was:"; + } + printOriginalExpression(); + } + } + + void printOriginalExpression() const { + if (result.hasExpression()) { + stream << ' ' << result.getExpression(); + } + } + + void printReconstructedExpression() const { + if (result.hasExpandedExpression()) { + { + Colour colour(dimColour()); + stream << " for: "; + } + stream << result.getExpandedExpression(); + } + } + + void printMessage() { + if (itMessage != messages.end()) { + stream << " '" << itMessage->message << '\''; + ++itMessage; + } + } + + void printRemainingMessages(Colour::Code colour = dimColour()) { + if (itMessage == messages.end()) + return; + + // using messages.end() directly yields (or auto) compilation error: + std::vector::const_iterator itEnd = messages.end(); + const std::size_t N = static_cast(std::distance(itMessage, itEnd)); + + { + Colour colourGuard(colour); + stream << " with " << pluralise(N, "message") << ':'; + } + + 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"; + } + } + } + } + +private: + std::ostream& stream; + AssertionResult const& result; + std::vector messages; + std::vector::const_iterator itMessage; + bool printInfoMessages; +}; + +} // anon namespace + + std::string CompactReporter::getDescription() { return "Reports test results on a single line, suitable for IDEs"; } - ReporterPreferences getPreferences() const override { + ReporterPreferences CompactReporter::getPreferences() const { ReporterPreferences prefs; prefs.shouldRedirectStdOut = false; return prefs; } - void noMatchingTestCases( std::string const& spec ) override { + void CompactReporter::noMatchingTestCases( std::string const& spec ) { stream << "No test cases matched '" << spec << '\'' << std::endl; } - void assertionStarting( AssertionInfo const& ) override {} + void CompactReporter::assertionStarting( AssertionInfo const& ) {} - bool assertionEnded( AssertionStats const& _assertionStats ) override { + bool CompactReporter::assertionEnded( AssertionStats const& _assertionStats ) { AssertionResult const& result = _assertionStats.assertionResult; bool printInfoMessages = true; @@ -10259,231 +11346,19 @@ namespace Catch { return true; } - void sectionEnded(SectionStats const& _sectionStats) override { + void CompactReporter::sectionEnded(SectionStats const& _sectionStats) { if (m_config->showDurations() == ShowDurations::Always) { stream << getFormattedDuration(_sectionStats.durationInSeconds) << " s: " << _sectionStats.sectionInfo.name << std::endl; } } - void testRunEnded( TestRunStats const& _testRunStats ) override { - printTotals( _testRunStats.totals ); + void CompactReporter::testRunEnded( TestRunStats const& _testRunStats ) { + printTotals( stream, _testRunStats.totals ); stream << '\n' << std::endl; StreamingReporterBase::testRunEnded( _testRunStats ); } - private: - 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; - } - } - - private: - void printSourceInfo() const { - Colour colourGuard( Colour::FileName ); - stream << result.getSourceInfo() << ':'; - } - - void printResultType( Colour::Code colour, std::string const& passOrFail ) const { - if( !passOrFail.empty() ) { - { - Colour colourGuard( colour ); - stream << ' ' << passOrFail; - } - stream << ':'; - } - } - - void printIssue( std::string const& issue ) const { - stream << ' ' << issue; - } - - void printExpressionWas() { - if( result.hasExpression() ) { - stream << ';'; - { - Colour colour( dimColour() ); - stream << " expression was:"; - } - printOriginalExpression(); - } - } - - void printOriginalExpression() const { - if( result.hasExpression() ) { - stream << ' ' << result.getExpression(); - } - } - - void printReconstructedExpression() const { - if( result.hasExpandedExpression() ) { - { - Colour colour( dimColour() ); - stream << " for: "; - } - stream << result.getExpandedExpression(); - } - } - - void printMessage() { - if ( itMessage != messages.end() ) { - stream << " '" << itMessage->message << '\''; - ++itMessage; - } - } - - void printRemainingMessages( Colour::Code colour = dimColour() ) { - if ( itMessage == messages.end() ) - return; - - // using messages.end() directly yields (or auto) compilation error: - std::vector::const_iterator itEnd = messages.end(); - const std::size_t N = static_cast( std::distance( itMessage, itEnd ) ); - - { - Colour colourGuard( colour ); - stream << " with " << pluralise( N, "message" ) << ':'; - } - - 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"; - } - } - } - } - - private: - std::ostream& stream; - AssertionResult const& result; - std::vector messages; - std::vector::const_iterator itMessage; - bool printInfoMessages; - }; - - // 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( 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" ) << '.'; - } - } - }; - - CompactReporter::~CompactReporter() {} + CompactReporter::~CompactReporter() {} CATCH_REGISTER_REPORTER( "compact", CompactReporter ) @@ -10497,629 +11372,609 @@ namespace Catch { #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 + // Note that 4062 (not all labels are handled + // and default is missing) is enabled #endif namespace Catch { - namespace { - 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; +namespace { + +// 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; } + } - 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 TablePrinter { - std::ostream& m_os; - std::vector m_columnInfos; - std::ostringstream m_oss; - int m_currentColumn = -1; - bool m_isOpen = false; - - public: - TablePrinter( std::ostream& os, std::vector const& columnInfos ) - : m_os( os ), - m_columnInfos( columnInfos ) - {} - - auto columnInfos() const -> std::vector const& { - return m_columnInfos; - } - - void open() { - if( !m_isOpen ) { - m_isOpen = true; - *this << RowBreak(); - for( auto const& info : m_columnInfos ) - *this << info.name << ColumnBreak(); - *this << RowBreak(); - m_os << Catch::getLineOfChars<'-'>() << "\n"; - } - } - void close() { - if( m_isOpen ) { - *this << RowBreak(); - m_os << std::endl; - m_isOpen = false; - } - } - - template - 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(); - // This takes account of utf8 encodings - auto strSize = Catch::StringRef( colStr ).numberOfCharacters(); - tp.m_oss.str(""); - tp.open(); - if( tp.m_currentColumn == static_cast(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+2 < static_cast( colInfo.width ) ) - ? std::string( colInfo.width-(strSize+2), ' ' ) - : 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; - } - }; - - 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; - - uint64_t m_inNanoseconds; - Unit m_units; - - public: - Duration( uint64_t 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; - } - - } - - auto value() const -> double { - switch( m_units ) { - case Unit::Microseconds: - return m_inNanoseconds / static_cast( s_nanosecondsInAMicrosecond ); - case Unit::Milliseconds: - return m_inNanoseconds / static_cast( s_nanosecondsInAMillisecond ); - case Unit::Seconds: - return m_inNanoseconds / static_cast( s_nanosecondsInASecond ); - case Unit::Minutes: - return m_inNanoseconds / static_cast( s_nanosecondsInAMinute ); - default: - return static_cast( m_inNanoseconds ); - } - } - auto unitsAsString() const -> std::string { - switch( m_units ) { - case Unit::Nanoseconds: - return "ns"; - case Unit::Microseconds: - return "µs"; - case Unit::Milliseconds: - return "ms"; - case Unit::Seconds: - return "s"; - case Unit::Minutes: - return "m"; - default: - return "** internal error **"; - } - - } - friend auto operator << ( std::ostream& os, Duration const& duration ) -> std::ostream& { - return os << duration.value() << " " << duration.unitsAsString(); - } - }; - } // end anon namespace - - struct ConsoleReporter : StreamingReporterBase { - TablePrinter m_tablePrinter; - - ConsoleReporter( ReporterConfig const& config ) - : StreamingReporterBase( config ), - m_tablePrinter( config.stream(), - { - { "benchmark name", CATCH_CONFIG_CONSOLE_WIDTH-32, ColumnInfo::Left }, - { "iters", 8, ColumnInfo::Right }, - { "elapsed ns", 14, ColumnInfo::Right }, - { "average", 14, ColumnInfo::Right } - } ) - {} - ~ConsoleReporter() override; - static std::string getDescription() { - return "Reports test results as plain lines of text"; - } - - void noMatchingTestCases( std::string const& spec ) override { - stream << "No test cases matched '" << spec << '\'' << std::endl; - } - - void assertionStarting( AssertionInfo const& ) override { - } - - bool assertionEnded( AssertionStats const& _assertionStats ) 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; - - lazyPrint(); - - AssertionPrinter printer( stream, _assertionStats, includeResults ); - printer.print(); - stream << std::endl; - return true; - } - - void sectionStarting( SectionInfo const& _sectionInfo ) override { - m_headerPrinted = false; - StreamingReporterBase::sectionStarting( _sectionInfo ); - } - void sectionEnded( SectionStats const& _sectionStats ) override { - 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; - } - if( m_config->showDurations() == ShowDurations::Always ) { - stream << getFormattedDuration(_sectionStats.durationInSeconds) << " s: " << _sectionStats.sectionInfo.name << std::endl; - } - if( m_headerPrinted ) { - m_headerPrinted = false; - } - StreamingReporterBase::sectionEnded( _sectionStats ); - } - - void benchmarkStarting( BenchmarkInfo const& info ) override { - lazyPrintWithoutClosingBenchmarkTable(); - - auto nameCol = Column( info.name ).width( m_tablePrinter.columnInfos()[0].width-2 ); - - bool firstLine = true; - for( auto line : nameCol ) { - if( !firstLine ) - m_tablePrinter << ColumnBreak() << ColumnBreak() << ColumnBreak(); - else - firstLine = false; - - m_tablePrinter << line << ColumnBreak(); - } - } - void benchmarkEnded( BenchmarkStats const& stats ) override { - Duration average( stats.elapsedTimeInNanoseconds/stats.iterations ); - m_tablePrinter - << stats.iterations << ColumnBreak() - << stats.elapsedTimeInNanoseconds << ColumnBreak() - << average << ColumnBreak(); - } - - void testCaseEnded( TestCaseStats const& _testCaseStats ) override { - m_tablePrinter.close(); - StreamingReporterBase::testCaseEnded( _testCaseStats ); - m_headerPrinted = false; - } - void testGroupEnded( TestGroupStats const& _testGroupStats ) override { - if( currentGroupInfo.used ) { - printSummaryDivider(); - stream << "Summary for group '" << _testGroupStats.groupInfo.name << "':\n"; - printTotals( _testGroupStats.totals ); - stream << '\n' << std::endl; - } - StreamingReporterBase::testGroupEnded( _testGroupStats ); - } - void testRunEnded( TestRunStats const& _testRunStats ) override { - printTotalsDivider( _testRunStats.totals ); - printTotals( _testRunStats.totals ); - stream << std::endl; - StreamingReporterBase::testRunEnded( _testRunStats ); - } - - private: - - class AssertionPrinter { - public: - AssertionPrinter& operator= ( AssertionPrinter const& ) = delete; - AssertionPrinter( AssertionPrinter const& ) = delete; - 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; - } - } - - void print() const { - printSourceInfo(); - if( stats.totals.assertions.total() > 0 ) { - if( result.isOk() ) - stream << '\n'; - printResultType(); - printOriginalExpression(); - printReconstructedExpression(); - } - else { - stream << '\n'; - } - printMessage(); - } - - 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 << Column( result.getExpandedExpression() ).indent(2) << '\n'; - } - } - 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() << ": "; - } - - std::ostream& stream; - AssertionStats const& stats; - AssertionResult const& result; - Colour::Code colour; - std::string passOrFail; - std::string messageLabel; - std::string message; - std::vector messages; - bool printInfoMessages; - }; - - void lazyPrint() { - - m_tablePrinter.close(); - lazyPrintWithoutClosingBenchmarkTable(); - } - - void lazyPrintWithoutClosingBenchmarkTable() { - - if( !currentTestRunInfo.used ) - lazyPrintRunInfo(); - if( !currentGroupInfo.used ) - lazyPrintGroupInfo(); - - 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"; - - if( m_config->rngSeed() != 0 ) - stream << "Randomness seeded to: " << m_config->rngSeed() << "\n\n"; - - 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 ); - - if( m_sectionStack.size() > 1 ) { - Colour colourGuard( Colour::Headers ); - - auto - it = m_sectionStack.begin()+1, // Skip first section (test case) - itEnd = m_sectionStack.end(); - for( ; it != itEnd; ++it ) - printHeaderString( it->name, 2 ); - } - - SourceLineInfo lineInfo = m_sectionStack.back().lineInfo; - - if( !lineInfo.empty() ){ - stream << getLineOfChars<'-'>() << '\n'; - Colour colourGuard( Colour::FileName ); - stream << lineInfo << '\n'; - } - stream << getLineOfChars<'.'>() << '\n' << std::endl; - } - - void printClosedHeader( std::string const& _name ) { - printOpenHeader( _name ); - stream << getLineOfChars<'.'>() << '\n'; - } - void printOpenHeader( std::string const& _name ) { - stream << getLineOfChars<'-'>() << '\n'; - { - Colour colourGuard( Colour::Headers ); - printHeaderString( _name ); - } - } - - // 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 << Column( _string ).indent( indent+i ).initialIndent( indent ) << '\n'; - } - - struct SummaryColumn { - - 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( auto& oldRow : rows ) { - while( oldRow.size() < row.size() ) - oldRow = ' ' + oldRow; - while( oldRow.size() > row.size() ) - row = ' ' + row; - } - rows.push_back( row ); - return *this; - } - - std::string label; - Colour::Code colour; - std::vector rows; - - }; - - 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 { - - std::vector 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 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; - } - } + void print() const { + printSourceInfo(); + if (stats.totals.assertions.total() > 0) { + if (result.isOk()) + stream << '\n'; + printResultType(); + printOriginalExpression(); + printReconstructedExpression(); + } else { stream << '\n'; } + printMessage(); + } - 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, '=' ); - } +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 printSummaryDivider() { - stream << getLineOfChars<'-'>() << '\n'; + } + void printReconstructedExpression() const { + if (result.hasExpandedExpression()) { + stream << "with expansion:\n"; + Colour colourGuard(Colour::ReconstructedExpression); + stream << Column(result.getExpandedExpression()).indent(2) << '\n'; } + } + 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() << ": "; + } - private: - bool m_headerPrinted = false; + std::ostream& stream; + AssertionStats const& stats; + AssertionResult const& result; + Colour::Code colour; + std::string passOrFail; + std::string messageLabel; + std::string message; + std::vector messages; + bool printInfoMessages; +}; + +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; - CATCH_REGISTER_REPORTER( "console", ConsoleReporter ) + uint64_t m_inNanoseconds; + Unit m_units; - ConsoleReporter::~ConsoleReporter() {} +public: + explicit Duration(uint64_t 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; + } + + } + + auto value() const -> double { + switch (m_units) { + case Unit::Microseconds: + return m_inNanoseconds / static_cast(s_nanosecondsInAMicrosecond); + case Unit::Milliseconds: + return m_inNanoseconds / static_cast(s_nanosecondsInAMillisecond); + case Unit::Seconds: + return m_inNanoseconds / static_cast(s_nanosecondsInASecond); + case Unit::Minutes: + return m_inNanoseconds / static_cast(s_nanosecondsInAMinute); + default: + return static_cast(m_inNanoseconds); + } + } + auto unitsAsString() const -> std::string { + switch (m_units) { + case Unit::Nanoseconds: + return "ns"; + case Unit::Microseconds: + return "µs"; + case Unit::Milliseconds: + return "ms"; + case Unit::Seconds: + return "s"; + case Unit::Minutes: + return "m"; + default: + return "** internal error **"; + } + + } + friend auto operator << (std::ostream& os, Duration const& duration) -> std::ostream& { + return os << duration.value() << " " << duration.unitsAsString(); + } +}; +} // end anon namespace + +class TablePrinter { + std::ostream& m_os; + std::vector m_columnInfos; + std::ostringstream m_oss; + int m_currentColumn = -1; + bool m_isOpen = false; + +public: + TablePrinter( std::ostream& os, std::vector columnInfos ) + : m_os( os ), + m_columnInfos( std::move( columnInfos ) ) {} + + auto columnInfos() const -> std::vector const& { + return m_columnInfos; + } + + void open() { + if (!m_isOpen) { + m_isOpen = true; + *this << RowBreak(); + for (auto const& info : m_columnInfos) + *this << info.name << ColumnBreak(); + *this << RowBreak(); + m_os << Catch::getLineOfChars<'-'>() << "\n"; + } + } + void close() { + if (m_isOpen) { + *this << RowBreak(); + m_os << std::endl; + m_isOpen = false; + } + } + + template + 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(); + // This takes account of utf8 encodings + auto strSize = Catch::StringRef(colStr).numberOfCharacters(); + tp.m_oss.str(""); + tp.open(); + if (tp.m_currentColumn == static_cast(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 + 2 < static_cast(colInfo.width)) + ? std::string(colInfo.width - (strSize + 2), ' ') + : 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; + } +}; + +ConsoleReporter::ConsoleReporter(ReporterConfig const& config) + : StreamingReporterBase(config), + m_tablePrinter(new TablePrinter(config.stream(), + { + { "benchmark name", CATCH_CONFIG_CONSOLE_WIDTH - 32, ColumnInfo::Left }, + { "iters", 8, ColumnInfo::Right }, + { "elapsed ns", 14, ColumnInfo::Right }, + { "average", 14, ColumnInfo::Right } + })) {} +ConsoleReporter::~ConsoleReporter() = default; + +std::string ConsoleReporter::getDescription() { + return "Reports test results as plain lines of text"; +} + +void ConsoleReporter::noMatchingTestCases(std::string const& spec) { + stream << "No test cases matched '" << spec << '\'' << std::endl; +} + +void ConsoleReporter::assertionStarting(AssertionInfo const&) {} + +bool ConsoleReporter::assertionEnded(AssertionStats const& _assertionStats) { + 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; + + lazyPrint(); + + ConsoleAssertionPrinter printer(stream, _assertionStats, includeResults); + printer.print(); + stream << std::endl; + return true; +} + +void ConsoleReporter::sectionStarting(SectionInfo const& _sectionInfo) { + 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; + } + if (m_config->showDurations() == ShowDurations::Always) { + stream << getFormattedDuration(_sectionStats.durationInSeconds) << " s: " << _sectionStats.sectionInfo.name << std::endl; + } + if (m_headerPrinted) { + m_headerPrinted = false; + } + StreamingReporterBase::sectionEnded(_sectionStats); +} + +void ConsoleReporter::benchmarkStarting(BenchmarkInfo const& info) { + lazyPrintWithoutClosingBenchmarkTable(); + + auto nameCol = Column( info.name ).width( static_cast( m_tablePrinter->columnInfos()[0].width - 2 ) ); + + bool firstLine = true; + for (auto line : nameCol) { + if (!firstLine) + (*m_tablePrinter) << ColumnBreak() << ColumnBreak() << ColumnBreak(); + else + firstLine = false; + + (*m_tablePrinter) << line << ColumnBreak(); + } +} +void ConsoleReporter::benchmarkEnded(BenchmarkStats const& stats) { + Duration average(stats.elapsedTimeInNanoseconds / stats.iterations); + (*m_tablePrinter) + << stats.iterations << ColumnBreak() + << stats.elapsedTimeInNanoseconds << ColumnBreak() + << average << ColumnBreak(); +} + +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::lazyPrint() { + + m_tablePrinter->close(); + lazyPrintWithoutClosingBenchmarkTable(); +} + +void ConsoleReporter::lazyPrintWithoutClosingBenchmarkTable() { + + if (!currentTestRunInfo.used) + lazyPrintRunInfo(); + if (!currentGroupInfo.used) + lazyPrintGroupInfo(); + + 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"; + + if (m_config->rngSeed() != 0) + stream << "Randomness seeded to: " << m_config->rngSeed() << "\n\n"; + + 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); + + if (m_sectionStack.size() > 1) { + Colour colourGuard(Colour::Headers); + + auto + it = m_sectionStack.begin() + 1, // Skip first section (test case) + itEnd = m_sectionStack.end(); + for (; it != itEnd; ++it) + printHeaderString(it->name, 2); + } + + SourceLineInfo lineInfo = m_sectionStack.back().lineInfo; + + if (!lineInfo.empty()) { + stream << getLineOfChars<'-'>() << '\n'; + Colour colourGuard(Colour::FileName); + stream << lineInfo << '\n'; + } + stream << getLineOfChars<'.'>() << '\n' << std::endl; +} + +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 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'; +} + +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; + } + + std::string label; + Colour::Code colour; + std::vector rows; + +}; + +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 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 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'; +} + +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'; +} + +CATCH_REGISTER_REPORTER("console", ConsoleReporter) } // end namespace Catch @@ -11130,7 +11985,7 @@ namespace Catch { // start catch_reporter_junit.cpp #include - +#include #include #include @@ -11171,202 +12026,193 @@ namespace Catch { return it->substr(1); return std::string(); } - } + } // anonymous namespace - class JunitReporter : public CumulativeReporterBase { - public: - JunitReporter( ReporterConfig const& _config ) + JunitReporter::JunitReporter( ReporterConfig const& _config ) : CumulativeReporterBase( _config ), xml( _config.stream() ) { m_reporterPrefs.shouldRedirectStdOut = true; } - ~JunitReporter() override; - - static std::string getDescription() { - return "Reports test results in an XML format that looks like Ant's junitreport target"; - } - - void noMatchingTestCases( std::string const& /*spec*/ ) override {} - - void testRunStarting( TestRunInfo const& runInfo ) override { - CumulativeReporterBase::testRunStarting( runInfo ); - xml.startElement( "testsuites" ); - } - - void testGroupStarting( GroupInfo const& groupInfo ) override { - suiteTimer.start(); - stdOutForSuite.str(""); - stdErrForSuite.str(""); - unexpectedExceptions = 0; - CumulativeReporterBase::testGroupStarting( groupInfo ); - } - - void testCaseStarting( TestCaseInfo const& testCaseInfo ) override { - m_okToFail = testCaseInfo.okToFail(); - } - bool assertionEnded( AssertionStats const& assertionStats ) override { - if( assertionStats.assertionResult.getResultType() == ResultWas::ThrewException && !m_okToFail ) - unexpectedExceptions++; - return CumulativeReporterBase::assertionEnded( assertionStats ); - } - - void testCaseEnded( TestCaseStats const& testCaseStats ) override { - stdOutForSuite << testCaseStats.stdOut; - stdErrForSuite << testCaseStats.stdErr; - CumulativeReporterBase::testCaseEnded( testCaseStats ); - } - - void testGroupEnded( TestGroupStats const& testGroupStats ) override { - double suiteTime = suiteTimer.getElapsedSeconds(); - CumulativeReporterBase::testGroupEnded( testGroupStats ); - writeGroup( *m_testGroups.back(), suiteTime ); - } - - void testRunEndedCumulative() override { - xml.endElement(); - } - - 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() ); - - // Write test cases - for( auto const& child : groupNode.children ) - writeTestCase( *child ); - - xml.scopedElement( "system-out" ).writeText( trim( stdOutForSuite.str() ), false ); - xml.scopedElement( "system-err" ).writeText( trim( stdErrForSuite.str() ), false ); - } - - void writeTestCase( TestCaseNode const& testCaseNode ) { - TestCaseStats const& stats = testCaseNode.value; - - // 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(); - - std::string className = stats.testInfo.className; - - if( className.empty() ) { - className = fileNameTag(stats.testInfo.tags); - if ( className.empty() ) - className = "global"; - } - - if ( !m_config->name().empty() ) - className = m_config->name() + "." + className; - - 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::Detail::stringify( 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( auto const& childNode : sectionNode.childSections ) - if( className.empty() ) - writeSection( name, "", *childNode ); - else - writeSection( className, name, *childNode ); - } - - void writeAssertions( SectionNode const& sectionNode ) { - for( auto const& assertion : sectionNode.assertions ) - writeAssertion( assertion ); - } - 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; - } - - XmlWriter::ScopedElement e = xml.scopedElement( elementName ); - - xml.writeAttribute( "message", result.getExpandedExpression() ); - xml.writeAttribute( "type", result.getTestMacroName() ); - - std::ostringstream oss; - if( !result.getMessage().empty() ) - oss << result.getMessage() << '\n'; - for( auto const& msg : stats.infoMessages ) - if( msg.type == ResultWas::Info ) - oss << msg.message << '\n'; - - oss << "at " << result.getSourceInfo(); - xml.writeText( oss.str(), false ); - } - } - - XmlWriter xml; - Timer suiteTimer; - std::ostringstream stdOutForSuite; - std::ostringstream stdErrForSuite; - unsigned int unexpectedExceptions = 0; - bool m_okToFail = false; - }; - JunitReporter::~JunitReporter() {} + + std::string JunitReporter::getDescription() { + return "Reports test results in an XML format that looks like Ant's junitreport target"; + } + + void JunitReporter::noMatchingTestCases( std::string const& /*spec*/ ) {} + + void JunitReporter::testRunStarting( TestRunInfo const& runInfo ) { + CumulativeReporterBase::testRunStarting( runInfo ); + xml.startElement( "testsuites" ); + } + + void JunitReporter::testGroupStarting( GroupInfo const& groupInfo ) { + suiteTimer.start(); + stdOutForSuite.clear(); + stdErrForSuite.clear(); + unexpectedExceptions = 0; + CumulativeReporterBase::testGroupStarting( groupInfo ); + } + + void JunitReporter::testCaseStarting( TestCaseInfo const& testCaseInfo ) { + m_okToFail = testCaseInfo.okToFail(); + } + + bool JunitReporter::assertionEnded( AssertionStats const& assertionStats ) { + if( assertionStats.assertionResult.getResultType() == ResultWas::ThrewException && !m_okToFail ) + unexpectedExceptions++; + return CumulativeReporterBase::assertionEnded( assertionStats ); + } + + void JunitReporter::testCaseEnded( TestCaseStats const& testCaseStats ) { + stdOutForSuite += testCaseStats.stdOut; + stdErrForSuite += testCaseStats.stdErr; + CumulativeReporterBase::testCaseEnded( testCaseStats ); + } + + void JunitReporter::testGroupEnded( TestGroupStats const& testGroupStats ) { + double suiteTime = suiteTimer.getElapsedSeconds(); + CumulativeReporterBase::testGroupEnded( testGroupStats ); + writeGroup( *m_testGroups.back(), suiteTime ); + } + + void JunitReporter::testRunEndedCumulative() { + xml.endElement(); + } + + void JunitReporter::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() ); + + // Write test cases + for( auto const& child : groupNode.children ) + writeTestCase( *child ); + + xml.scopedElement( "system-out" ).writeText( trim( stdOutForSuite ), false ); + xml.scopedElement( "system-err" ).writeText( trim( stdErrForSuite ), false ); + } + + void JunitReporter::writeTestCase( TestCaseNode const& testCaseNode ) { + TestCaseStats const& stats = testCaseNode.value; + + // 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(); + + std::string className = stats.testInfo.className; + + if( className.empty() ) { + className = fileNameTag(stats.testInfo.tags); + if ( className.empty() ) + className = "global"; + } + + if ( !m_config->name().empty() ) + className = m_config->name() + "." + className; + + writeSection( className, "", rootSection ); + } + + void JunitReporter::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::Detail::stringify( 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( auto const& childNode : sectionNode.childSections ) + if( className.empty() ) + writeSection( name, "", *childNode ); + else + writeSection( className, name, *childNode ); + } + + 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: + 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; + } + + XmlWriter::ScopedElement e = xml.scopedElement( elementName ); + + xml.writeAttribute( "message", result.getExpandedExpression() ); + xml.writeAttribute( "type", result.getTestMacroName() ); + + ReusableStringStream rss; + if( !result.getMessage().empty() ) + rss << result.getMessage() << '\n'; + for( auto const& msg : stats.infoMessages ) + if( msg.type == ResultWas::Info ) + rss << msg.message << '\n'; + + rss << "at " << result.getSourceInfo(); + xml.writeText( rss.str(), false ); + } + } + CATCH_REGISTER_REPORTER( "junit", JunitReporter ) } // end namespace Catch @@ -11475,211 +12321,200 @@ namespace Catch { #endif namespace Catch { - class XmlReporter : public StreamingReporterBase { - public: - XmlReporter( ReporterConfig const& _config ) - : StreamingReporterBase( _config ), - m_xml(_config.stream()) - { - m_reporterPrefs.shouldRedirectStdOut = true; - } + XmlReporter::XmlReporter( ReporterConfig const& _config ) + : StreamingReporterBase( _config ), + m_xml(_config.stream()) + { + m_reporterPrefs.shouldRedirectStdOut = true; + } - ~XmlReporter() override; + XmlReporter::~XmlReporter() = default; - static std::string getDescription() { - return "Reports test results as an XML document"; - } + std::string XmlReporter::getDescription() { + return "Reports test results as an XML document"; + } - virtual std::string getStylesheetRef() const { - return std::string(); - } + std::string XmlReporter::getStylesheetRef() const { + return std::string(); + } - void writeSourceInfo( SourceLineInfo const& sourceInfo ) { - m_xml - .writeAttribute( "filename", sourceInfo.file ) - .writeAttribute( "line", sourceInfo.line ); - } + void XmlReporter::writeSourceInfo( SourceLineInfo const& sourceInfo ) { + m_xml + .writeAttribute( "filename", sourceInfo.file ) + .writeAttribute( "line", sourceInfo.line ); + } - public: // StreamingReporterBase + void XmlReporter::noMatchingTestCases( std::string const& s ) { + StreamingReporterBase::noMatchingTestCases( s ); + } - void noMatchingTestCases( std::string const& s ) override { - StreamingReporterBase::noMatchingTestCases( s ); - } + 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() ); + } - void testRunStarting( TestRunInfo const& testInfo ) 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() ); - } + void XmlReporter::testGroupStarting( GroupInfo const& groupInfo ) { + StreamingReporterBase::testGroupStarting( groupInfo ); + m_xml.startElement( "Group" ) + .writeAttribute( "name", groupInfo.name ); + } - void testGroupStarting( GroupInfo const& groupInfo ) override { - StreamingReporterBase::testGroupStarting( groupInfo ); - m_xml.startElement( "Group" ) - .writeAttribute( "name", groupInfo.name ); - } + 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() ); - void testCaseStarting( TestCaseInfo const& testInfo ) override { - StreamingReporterBase::testCaseStarting(testInfo); - m_xml.startElement( "TestCase" ) - .writeAttribute( "name", trim( testInfo.name ) ) - .writeAttribute( "description", testInfo.description ) - .writeAttribute( "tags", testInfo.tagsAsString() ); + writeSourceInfo( testInfo.lineInfo ); - writeSourceInfo( testInfo.lineInfo ); + if ( m_config->showDurations() == ShowDurations::Always ) + m_testCaseTimer.start(); + m_xml.ensureTagClosed(); + } - if ( m_config->showDurations() == ShowDurations::Always ) - m_testCaseTimer.start(); + void XmlReporter::sectionStarting( SectionInfo const& sectionInfo ) { + 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(); } + } - void sectionStarting( SectionInfo const& sectionInfo ) 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(); - } - } + void XmlReporter::assertionStarting( AssertionInfo const& ) { } - void assertionStarting( AssertionInfo const& ) override { } + bool XmlReporter::assertionEnded( AssertionStats const& assertionStats ) { - bool assertionEnded( AssertionStats const& assertionStats ) override { + AssertionResult const& result = assertionStats.assertionResult; - AssertionResult const& result = assertionStats.assertionResult; + bool includeResults = m_config->includeSuccessfulResults() || !result.isOk(); - bool includeResults = m_config->includeSuccessfulResults() || !result.isOk(); - - if( includeResults ) { - // Print any info messages in tags. - for( auto const& msg : assertionStats.infoMessages ) { - if( msg.type == ResultWas::Info ) { - m_xml.scopedElement( "Info" ) - .writeText( msg.message ); - } else if ( msg.type == ResultWas::Warning ) { - m_xml.scopedElement( "Warning" ) - .writeText( msg.message ); - } + if( includeResults || result.getResultType() == ResultWas::Warning ) { + // Print any info messages in 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 ); } } + } - // Drop out if result was successful but we're not printing them. - if( !includeResults && result.getResultType() != ResultWas::Warning ) - return true; - - // Print the expression if there is one. - if( result.hasExpression() ) { - m_xml.startElement( "Expression" ) - .writeAttribute( "success", result.succeeded() ) - .writeAttribute( "type", result.getTestMacroName() ); - - writeSourceInfo( result.getSourceInfo() ); - - m_xml.scopedElement( "Original" ) - .writeText( result.getExpression() ); - m_xml.scopedElement( "Expanded" ) - .writeText( result.getExpandedExpression() ); - } - - // 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( result.hasExpression() ) - m_xml.endElement(); - + // Drop out if result was successful but we're not printing them. + if( !includeResults && result.getResultType() != ResultWas::Warning ) return true; + + // Print the expression if there is one. + if( result.hasExpression() ) { + m_xml.startElement( "Expression" ) + .writeAttribute( "success", result.succeeded() ) + .writeAttribute( "type", result.getTestMacroName() ); + + writeSourceInfo( result.getSourceInfo() ); + + m_xml.scopedElement( "Original" ) + .writeText( result.getExpression() ); + m_xml.scopedElement( "Expanded" ) + .writeText( result.getExpandedExpression() ); } - void sectionEnded( SectionStats const& sectionStats ) 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 ); - - if ( m_config->showDurations() == ShowDurations::Always ) - e.writeAttribute( "durationInSeconds", sectionStats.durationInSeconds ); - + // 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; } - void testCaseEnded( TestCaseStats const& testCaseStats ) override { - StreamingReporterBase::testCaseEnded( testCaseStats ); - XmlWriter::ScopedElement e = m_xml.scopedElement( "OverallResult" ); - e.writeAttribute( "success", testCaseStats.totals.assertions.allOk() ); + if( result.hasExpression() ) + m_xml.endElement(); + + return true; + } + + 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 ); if ( m_config->showDurations() == ShowDurations::Always ) - e.writeAttribute( "durationInSeconds", m_testCaseTimer.getElapsedSeconds() ); - - 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 ); + e.writeAttribute( "durationInSeconds", sectionStats.durationInSeconds ); m_xml.endElement(); } + } - void testGroupEnded( TestGroupStats const& testGroupStats ) 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(); - } + void XmlReporter::testCaseEnded( TestCaseStats const& testCaseStats ) { + StreamingReporterBase::testCaseEnded( testCaseStats ); + XmlWriter::ScopedElement e = m_xml.scopedElement( "OverallResult" ); + e.writeAttribute( "success", testCaseStats.totals.assertions.allOk() ); - void testRunEnded( TestRunStats const& testRunStats ) 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(); - } + if ( m_config->showDurations() == ShowDurations::Always ) + e.writeAttribute( "durationInSeconds", m_testCaseTimer.getElapsedSeconds() ); - private: - Timer m_testCaseTimer; - XmlWriter m_xml; - int m_sectionDepth = 0; - }; + 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 ); + + 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.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.endElement(); + } - XmlReporter::~XmlReporter() {} CATCH_REGISTER_REPORTER( "xml", XmlReporter ) } // end namespace Catch @@ -11705,7 +12540,7 @@ namespace Catch { #ifndef __OBJC__ -#if defined(WIN32) && defined(_UNICODE) && !defined(DO_NOT_USE_WMAIN) +#if defined(CATCH_CONFIG_WCHAR) && defined(WIN32) && 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 * []) { #else @@ -11739,6 +12574,8 @@ int main (int argc, char * const argv[]) { // end catch_default_main.hpp #endif +#if !defined(CATCH_CONFIG_IMPL_ONLY) + #ifdef CLARA_CONFIG_MAIN_NOT_DEFINED # undef CLARA_CONFIG_MAIN #endif @@ -11993,6 +12830,8 @@ using Catch::Detail::Approx; #endif +#endif // ! CATCH_CONFIG_IMPL_ONLY + // start catch_reenable_warnings.h diff --git a/Telegram/ThirdParty/Catch/single_include/catch_reporter_automake.hpp b/Telegram/ThirdParty/Catch/single_include/catch_reporter_automake.hpp new file mode 100644 index 000000000..dbebe9751 --- /dev/null +++ b/Telegram/ThirdParty/Catch/single_include/catch_reporter_automake.hpp @@ -0,0 +1,62 @@ +/* + * Created by Justin R. Wilson on 2/19/2017. + * Copyright 2017 Justin R. Wilson. 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_CATCH_REPORTER_AUTOMAKE_HPP_INCLUDED +#define TWOBLUECUBES_CATCH_REPORTER_AUTOMAKE_HPP_INCLUDED + +// Don't #include any Catch headers here - we can assume they are already +// included before this header. +// This is not good practice in general but is necessary in this case so this +// file can be distributed as a single header that works with the main +// Catch single header. + +namespace Catch { + + struct AutomakeReporter : StreamingReporterBase { + AutomakeReporter( ReporterConfig const& _config ) + : StreamingReporterBase( _config ) + {} + + ~AutomakeReporter() override; + + static std::string getDescription() { + return "Reports test results in the format of Automake .trs files"; + } + + void assertionStarting( AssertionInfo const& ) override {} + + bool assertionEnded( AssertionStats const& /*_assertionStats*/ ) override { return true; } + + void testCaseEnded( TestCaseStats const& _testCaseStats ) override { + // Possible values to emit are PASS, XFAIL, SKIP, FAIL, XPASS and ERROR. + stream << ":test-result: "; + if (_testCaseStats.totals.assertions.allPassed()) { + stream << "PASS"; + } else if (_testCaseStats.totals.assertions.allOk()) { + stream << "XFAIL"; + } else { + stream << "FAIL"; + } + stream << ' ' << _testCaseStats.testInfo.name << '\n'; + StreamingReporterBase::testCaseEnded( _testCaseStats ); + } + + void skipTest( TestCaseInfo const& testInfo ) override { + stream << ":test-result: SKIP " << testInfo.name << '\n'; + } + + }; + +#ifdef CATCH_IMPL + AutomakeReporter::~AutomakeReporter() {} +#endif + + CATCH_REGISTER_REPORTER( "automake", AutomakeReporter) + +} // end namespace Catch + +#endif // TWOBLUECUBES_CATCH_REPORTER_AUTOMAKE_HPP_INCLUDED diff --git a/Telegram/ThirdParty/Catch/single_include/catch_reporter_tap.hpp b/Telegram/ThirdParty/Catch/single_include/catch_reporter_tap.hpp new file mode 100644 index 000000000..19e54ed19 --- /dev/null +++ b/Telegram/ThirdParty/Catch/single_include/catch_reporter_tap.hpp @@ -0,0 +1,255 @@ +/* + * Created by Colton Wolkins on 2015-08-15. + * Copyright 2015 Martin Moene. 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_CATCH_REPORTER_TAP_HPP_INCLUDED +#define TWOBLUECUBES_CATCH_REPORTER_TAP_HPP_INCLUDED + + +// Don't #include any Catch headers here - we can assume they are already +// included before this header. +// This is not good practice in general but is necessary in this case so this +// file can be distributed as a single header that works with the main +// Catch single header. + +#include + +namespace Catch { + + struct TAPReporter : StreamingReporterBase { + + using StreamingReporterBase::StreamingReporterBase; + + ~TAPReporter() override; + + static std::string getDescription() { + return "Reports test results in TAP format, suitable for test harnesses"; + } + + ReporterPreferences getPreferences() const override { + ReporterPreferences prefs; + prefs.shouldRedirectStdOut = false; + return prefs; + } + + void noMatchingTestCases( std::string const& spec ) override { + stream << "# No test cases matched '" << spec << "'" << std::endl; + } + + void assertionStarting( AssertionInfo const& ) override {} + + bool assertionEnded( AssertionStats const& _assertionStats ) override { + ++counter; + + AssertionPrinter printer( stream, _assertionStats, counter ); + printer.print(); + stream << " # " << currentTestCaseInfo->name ; + + stream << std::endl; + return true; + } + + void testRunEnded( TestRunStats const& _testRunStats ) override { + printTotals( _testRunStats.totals ); + stream << "\n" << std::endl; + StreamingReporterBase::testRunEnded( _testRunStats ); + } + + private: + std::size_t counter = 0; + class AssertionPrinter { + public: + AssertionPrinter& operator= ( AssertionPrinter const& ) = delete; + AssertionPrinter( AssertionPrinter const& ) = delete; + AssertionPrinter( std::ostream& _stream, AssertionStats const& _stats, std::size_t _counter ) + : stream( _stream ) + , result( _stats.assertionResult ) + , messages( _stats.infoMessages ) + , itMessage( _stats.infoMessages.begin() ) + , printInfoMessages( true ) + , counter(_counter) + {} + + void print() { + itMessage = messages.begin(); + + switch( result.getResultType() ) { + case ResultWas::Ok: + printResultType( passedString() ); + printOriginalExpression(); + printReconstructedExpression(); + if ( ! result.hasExpression() ) + printRemainingMessages( Colour::None ); + else + printRemainingMessages(); + break; + case ResultWas::ExpressionFailed: + if (result.isOk()) { + printResultType(passedString()); + } else { + printResultType(failedString()); + } + printOriginalExpression(); + printReconstructedExpression(); + if (result.isOk()) { + printIssue(" # TODO"); + } + printRemainingMessages(); + break; + case ResultWas::ThrewException: + printResultType( failedString() ); + printIssue( "unexpected exception with message:" ); + printMessage(); + printExpressionWas(); + printRemainingMessages(); + break; + case ResultWas::FatalErrorCondition: + printResultType( failedString() ); + printIssue( "fatal error condition with message:" ); + printMessage(); + printExpressionWas(); + printRemainingMessages(); + break; + case ResultWas::DidntThrowException: + printResultType( failedString() ); + printIssue( "expected exception, got none" ); + printExpressionWas(); + printRemainingMessages(); + break; + case ResultWas::Info: + printResultType( "info" ); + printMessage(); + printRemainingMessages(); + break; + case ResultWas::Warning: + printResultType( "warning" ); + printMessage(); + printRemainingMessages(); + break; + case ResultWas::ExplicitFailure: + printResultType( 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( "** internal error **" ); + break; + } + } + + private: + static Colour::Code dimColour() { return Colour::FileName; } + + static const char* failedString() { return "not ok"; } + static const char* passedString() { return "ok"; } + + void printSourceInfo() const { + Colour colourGuard( dimColour() ); + stream << result.getSourceInfo() << ":"; + } + + void printResultType( std::string const& passOrFail ) const { + if( !passOrFail.empty() ) { + stream << passOrFail << ' ' << counter << " -"; + } + } + + void printIssue( std::string const& issue ) const { + stream << " " << issue; + } + + void printExpressionWas() { + if( result.hasExpression() ) { + stream << ";"; + { + Colour colour( dimColour() ); + stream << " expression was:"; + } + printOriginalExpression(); + } + } + + void printOriginalExpression() const { + if( result.hasExpression() ) { + stream << " " << result.getExpression(); + } + } + + void printReconstructedExpression() const { + if( result.hasExpandedExpression() ) { + { + Colour colour( dimColour() ); + stream << " for: "; + } + std::string expr = result.getExpandedExpression(); + std::replace( expr.begin(), expr.end(), '\n', ' '); + stream << expr; + } + } + + void printMessage() { + if ( itMessage != messages.end() ) { + stream << " '" << itMessage->message << "'"; + ++itMessage; + } + } + + void printRemainingMessages( Colour::Code colour = dimColour() ) { + if (itMessage == messages.end()) { + return; + } + + // using messages.end() directly (or auto) yields compilation error: + std::vector::const_iterator itEnd = messages.end(); + const std::size_t N = static_cast( std::distance( itMessage, itEnd ) ); + + { + Colour colourGuard( colour ); + stream << " with " << pluralise( N, "message" ) << ":"; + } + + 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"; + } + } + } + } + + private: + std::ostream& stream; + AssertionResult const& result; + std::vector messages; + std::vector::const_iterator itMessage; + bool printInfoMessages; + std::size_t counter; + }; + + void printTotals( const Totals& totals ) const { + if( totals.testCases.total() == 0 ) { + stream << "1..0 # Skipped: No tests ran."; + } else { + stream << "1.." << counter; + } + } + }; + +#ifdef CATCH_IMPL + TAPReporter::~TAPReporter() {} +#endif + + CATCH_REGISTER_REPORTER( "tap", TAPReporter ) + +} // end namespace Catch + +#endif // TWOBLUECUBES_CATCH_REPORTER_TAP_HPP_INCLUDED diff --git a/Telegram/ThirdParty/Catch/single_include/catch_reporter_teamcity.hpp b/Telegram/ThirdParty/Catch/single_include/catch_reporter_teamcity.hpp new file mode 100644 index 000000000..dbd0db532 --- /dev/null +++ b/Telegram/ThirdParty/Catch/single_include/catch_reporter_teamcity.hpp @@ -0,0 +1,220 @@ +/* + * Created by Phil Nash on 19th December 2014 + * Copyright 2014 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_CATCH_REPORTER_TEAMCITY_HPP_INCLUDED +#define TWOBLUECUBES_CATCH_REPORTER_TEAMCITY_HPP_INCLUDED + +// Don't #include any Catch headers here - we can assume they are already +// included before this header. +// This is not good practice in general but is necessary in this case so this +// file can be distributed as a single header that works with the main +// Catch single header. + +#include + +#ifdef __clang__ +# pragma clang diagnostic push +# pragma clang diagnostic ignored "-Wpadded" +#endif + +namespace Catch { + + struct TeamCityReporter : StreamingReporterBase { + TeamCityReporter( ReporterConfig const& _config ) + : StreamingReporterBase( _config ) + { + m_reporterPrefs.shouldRedirectStdOut = true; + } + + static std::string escape( std::string const& str ) { + std::string escaped = str; + replaceInPlace( escaped, "|", "||" ); + replaceInPlace( escaped, "'", "|'" ); + replaceInPlace( escaped, "\n", "|n" ); + replaceInPlace( escaped, "\r", "|r" ); + replaceInPlace( escaped, "[", "|[" ); + replaceInPlace( escaped, "]", "|]" ); + return escaped; + } + ~TeamCityReporter() override; + + static std::string getDescription() { + return "Reports test results as TeamCity service messages"; + } + + void skipTest( TestCaseInfo const& /* testInfo */ ) override { + } + + void noMatchingTestCases( std::string const& /* spec */ ) override {} + + void testGroupStarting( GroupInfo const& groupInfo ) override { + StreamingReporterBase::testGroupStarting( groupInfo ); + stream << "##teamcity[testSuiteStarted name='" + << escape( groupInfo.name ) << "']\n"; + } + void testGroupEnded( TestGroupStats const& testGroupStats ) override { + StreamingReporterBase::testGroupEnded( testGroupStats ); + stream << "##teamcity[testSuiteFinished name='" + << escape( testGroupStats.groupInfo.name ) << "']\n"; + } + + + void assertionStarting( AssertionInfo const& ) override {} + + bool assertionEnded( AssertionStats const& assertionStats ) override { + AssertionResult const& result = assertionStats.assertionResult; + if( !result.isOk() ) { + + ReusableStringStream msg; + if( !m_headerPrintedForThisSection ) + printSectionHeader( msg.get() ); + m_headerPrintedForThisSection = true; + + msg << result.getSourceInfo() << "\n"; + + switch( result.getResultType() ) { + case ResultWas::ExpressionFailed: + msg << "expression failed"; + break; + case ResultWas::ThrewException: + msg << "unexpected exception"; + break; + case ResultWas::FatalErrorCondition: + msg << "fatal error condition"; + break; + case ResultWas::DidntThrowException: + msg << "no exception was thrown where one was expected"; + break; + case ResultWas::ExplicitFailure: + msg << "explicit failure"; + break; + + // We shouldn't get here because of the isOk() test + case ResultWas::Ok: + case ResultWas::Info: + case ResultWas::Warning: + throw std::domain_error( "Internal error in TeamCity reporter" ); + // These cases are here to prevent compiler warnings + case ResultWas::Unknown: + case ResultWas::FailureBit: + case ResultWas::Exception: + throw std::domain_error( "Not implemented" ); + } + if( assertionStats.infoMessages.size() == 1 ) + msg << " with message:"; + if( assertionStats.infoMessages.size() > 1 ) + msg << " with messages:"; + for( auto const& messageInfo : assertionStats.infoMessages ) + msg << "\n \"" << messageInfo.message << "\""; + + + if( result.hasExpression() ) { + msg << + "\n " << result.getExpressionInMacro() << "\n" + "with expansion:\n" << + " " << result.getExpandedExpression() << "\n"; + } + + if( currentTestCaseInfo->okToFail() ) { + msg << "- failure ignore as test marked as 'ok to fail'\n"; + stream << "##teamcity[testIgnored" + << " name='" << escape( currentTestCaseInfo->name )<< "'" + << " message='" << escape( msg.str() ) << "'" + << "]\n"; + } + else { + stream << "##teamcity[testFailed" + << " name='" << escape( currentTestCaseInfo->name )<< "'" + << " message='" << escape( msg.str() ) << "'" + << "]\n"; + } + } + stream.flush(); + return true; + } + + void sectionStarting( SectionInfo const& sectionInfo ) override { + m_headerPrintedForThisSection = false; + StreamingReporterBase::sectionStarting( sectionInfo ); + } + + void testCaseStarting( TestCaseInfo const& testInfo ) override { + m_testTimer.start(); + StreamingReporterBase::testCaseStarting( testInfo ); + stream << "##teamcity[testStarted name='" + << escape( testInfo.name ) << "']\n"; + stream.flush(); + } + + void testCaseEnded( TestCaseStats const& testCaseStats ) override { + StreamingReporterBase::testCaseEnded( testCaseStats ); + if( !testCaseStats.stdOut.empty() ) + stream << "##teamcity[testStdOut name='" + << escape( testCaseStats.testInfo.name ) + << "' out='" << escape( testCaseStats.stdOut ) << "']\n"; + if( !testCaseStats.stdErr.empty() ) + stream << "##teamcity[testStdErr name='" + << escape( testCaseStats.testInfo.name ) + << "' out='" << escape( testCaseStats.stdErr ) << "']\n"; + stream << "##teamcity[testFinished name='" + << escape( testCaseStats.testInfo.name ) << "' duration='" + << m_testTimer.getElapsedMilliseconds() << "']\n"; + stream.flush(); + } + + private: + void printSectionHeader( std::ostream& os ) { + assert( !m_sectionStack.empty() ); + + if( m_sectionStack.size() > 1 ) { + os << getLineOfChars<'-'>() << "\n"; + + std::vector::const_iterator + it = m_sectionStack.begin()+1, // Skip first section (test case) + itEnd = m_sectionStack.end(); + for( ; it != itEnd; ++it ) + printHeaderString( os, it->name ); + os << getLineOfChars<'-'>() << "\n"; + } + + SourceLineInfo lineInfo = m_sectionStack.front().lineInfo; + + if( !lineInfo.empty() ) + os << lineInfo << "\n"; + os << getLineOfChars<'.'>() << "\n\n"; + } + + // if string has a : in first line will set indent to follow it on + // subsequent lines + static void printHeaderString( std::ostream& os, 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; + os << Column( _string ) + .indent( indent+i) + .initialIndent( indent ) << "\n"; + } + private: + bool m_headerPrintedForThisSection = false; + Timer m_testTimer; + }; + +#ifdef CATCH_IMPL + TeamCityReporter::~TeamCityReporter() {} +#endif + + CATCH_REGISTER_REPORTER( "teamcity", TeamCityReporter ) + +} // end namespace Catch + +#ifdef __clang__ +# pragma clang diagnostic pop +#endif + +#endif // TWOBLUECUBES_CATCH_REPORTER_TEAMCITY_HPP_INCLUDED diff --git a/Telegram/ThirdParty/Catch/test_package/conanfile.py b/Telegram/ThirdParty/Catch/test_package/conanfile.py index 207c480e4..f47fd11d9 100644 --- a/Telegram/ThirdParty/Catch/test_package/conanfile.py +++ b/Telegram/ThirdParty/Catch/test_package/conanfile.py @@ -10,7 +10,7 @@ class CatchConanTest(ConanFile): settings = "os", "compiler", "arch", "build_type" username = getenv("CONAN_USERNAME", "philsquared") channel = getenv("CONAN_CHANNEL", "testing") - requires = "Catch/2.0.1@%s/%s" % (username, channel) + requires = "Catch/2.2.0@%s/%s" % (username, channel) def build(self): cmake = CMake(self) diff --git a/Telegram/ThirdParty/Catch/third_party/clara.hpp b/Telegram/ThirdParty/Catch/third_party/clara.hpp index aa429e7a1..43568cee2 100644 --- a/Telegram/ThirdParty/Catch/third_party/clara.hpp +++ b/Telegram/ThirdParty/Catch/third_party/clara.hpp @@ -1,5 +1,11 @@ -// v1.0-develop.2 -// See https://github.com/philsquared/Clara +// 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.4 #ifndef CLARA_HPP_INCLUDED #define CLARA_HPP_INCLUDED @@ -12,6 +18,16 @@ #define CLARA_TEXTFLOW_CONFIG_CONSOLE_WIDTH CLARA_CONFIG_CONSOLE_WIDTH #endif +#ifndef CLARA_CONFIG_OPTIONAL_TYPE +#ifdef __has_include +#if __has_include() && __cplusplus >= 201703L +#include +#define CLARA_CONFIG_OPTIONAL_TYPE std::optional +#endif +#endif +#endif + + // ----------- #included from clara_textflow.hpp ----------- // TextFlowCpp @@ -370,7 +386,7 @@ namespace detail { template struct UnaryLambdaTraits { static const bool isValid = true; - using ArgType = typename std::remove_const::type>::type;; + using ArgType = typename std::remove_const::type>::type; using ReturnType = ReturnT; }; @@ -383,11 +399,9 @@ namespace detail { std::vector m_args; public: - Args( int argc, char *argv[] ) { - m_exeName = argv[0]; - for( int i = 1; i < argc; ++i ) - m_args.push_back( argv[i] ); - } + Args( int argc, char const* const* argv ) + : m_exeName(argv[0]), + m_args(argv + 1, argv + argc) {} Args( std::initializer_list args ) : m_exeName( *args.begin() ), @@ -535,7 +549,7 @@ namespace detail { return *this; } - ~ResultValueBase() { + ~ResultValueBase() override { if( m_type == Ok ) m_value.~T(); } @@ -573,16 +587,14 @@ namespace detail { auto errorMessage() const -> std::string { return m_errorMessage; } protected: - virtual void enforceOk() const { - // !TBD: If no exceptions, std::terminate here or something - switch( m_type ) { - case ResultBase::LogicError: - throw std::logic_error( m_errorMessage ); - case ResultBase::RuntimeError: - throw std::runtime_error( m_errorMessage ); - case ResultBase::Ok: - break; - } + 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 @@ -652,47 +664,43 @@ namespace detail { return ParserResult::runtimeError( "Expected a boolean value but did not recognise: '" + source + "'" ); return ParserResult::ok( ParseResultType::Matched ); } +#ifdef CLARA_CONFIG_OPTIONAL_TYPE + template + inline auto convertInto( std::string const &source, CLARA_CONFIG_OPTIONAL_TYPE& target ) -> ParserResult { + T temp; + auto result = convertInto( source, temp ); + if( result ) + target = std::move(temp); + return result; + } +#endif // CLARA_CONFIG_OPTIONAL_TYPE - struct BoundRefBase { - BoundRefBase() = default; - BoundRefBase( BoundRefBase const & ) = delete; - BoundRefBase( BoundRefBase && ) = delete; - BoundRefBase &operator=( BoundRefBase const & ) = delete; - BoundRefBase &operator=( BoundRefBase && ) = delete; + struct NonCopyable { + NonCopyable() = default; + NonCopyable( NonCopyable const & ) = delete; + NonCopyable( NonCopyable && ) = delete; + NonCopyable &operator=( NonCopyable const & ) = delete; + NonCopyable &operator=( NonCopyable && ) = delete; + }; - virtual ~BoundRefBase() = default; - - virtual auto isFlag() const -> bool = 0; + 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; - }; - - struct BoundValueRefBase : BoundRefBase { - auto isFlag() const -> bool override { return false; } - - auto setFlag( bool ) -> ParserResult override { - return ParserResult::logicError( "Flags can only be set on boolean fields" ); - } - }; - - struct BoundFlagRefBase : BoundRefBase { - auto isFlag() const -> bool override { return true; } - - auto setValue( std::string const &arg ) -> ParserResult override { - bool flag; - auto result = convertInto( arg, flag ); - if( result ) - setFlag( flag ); - return result; - } + virtual auto isFlag() const -> bool { return true; } }; template - struct BoundRef : BoundValueRefBase { + struct BoundValueRef : BoundValueRefBase { T &m_ref; - explicit BoundRef( T &ref ) : m_ref( ref ) {} + explicit BoundValueRef( T &ref ) : m_ref( ref ) {} auto setValue( std::string const &arg ) -> ParserResult override { return convertInto( arg, m_ref ); @@ -700,10 +708,10 @@ namespace detail { }; template - struct BoundRef> : BoundValueRefBase { + struct BoundValueRef> : BoundValueRefBase { std::vector &m_ref; - explicit BoundRef( std::vector &ref ) : m_ref( ref ) {} + explicit BoundValueRef( std::vector &ref ) : m_ref( ref ) {} auto isContainer() const -> bool override { return true; } @@ -748,12 +756,12 @@ namespace detail { template inline auto invokeLambda( L const &lambda, std::string const &arg ) -> ParserResult { - ArgType temp; + ArgType temp{}; auto result = convertInto( arg, temp ); return !result ? result : LambdaInvoker::ReturnType>::invoke( lambda, temp ); - }; + } template @@ -803,6 +811,9 @@ namespace detail { public: template auto operator|( T const &other ) const -> Parser; + + template + auto operator+( T const &other ) const -> Parser; }; // Common code and state for Args and Opts @@ -810,16 +821,16 @@ namespace detail { class ParserRefImpl : public ComposableParserImpl { protected: Optionality m_optionality = Optionality::Optional; - std::shared_ptr m_ref; + std::shared_ptr m_ref; std::string m_hint; std::string m_description; - explicit ParserRefImpl( std::shared_ptr const &ref ) : m_ref( ref ) {} + explicit ParserRefImpl( std::shared_ptr const &ref ) : m_ref( ref ) {} public: template ParserRefImpl( T &ref, std::string const &hint ) - : m_ref( std::make_shared>( ref ) ), + : m_ref( std::make_shared>( ref ) ), m_hint( hint ) {} @@ -860,10 +871,10 @@ namespace detail { class ExeName : public ComposableParserImpl { std::shared_ptr m_name; - std::shared_ptr m_ref; + std::shared_ptr m_ref; template - static auto makeRef(LambdaT const &lambda) -> std::shared_ptr { + static auto makeRef(LambdaT const &lambda) -> std::shared_ptr { return std::make_shared>( lambda) ; } @@ -871,7 +882,7 @@ namespace detail { ExeName() : m_name( std::make_shared( "" ) ) {} explicit ExeName( std::string &ref ) : ExeName() { - m_ref = std::make_shared>( ref ); + m_ref = std::make_shared>( ref ); } template @@ -914,7 +925,10 @@ namespace detail { if( token.type != TokenType::Argument ) return InternalParseResult::ok( ParseState( ParseResultType::NoMatch, remainingTokens ) ); - auto result = m_ref->setValue( remainingTokens->token ); + assert( !m_ref->isFlag() ); + auto valueRef = static_cast( m_ref.get() ); + + auto result = valueRef->setValue( remainingTokens->token ); if( !result ) return InternalParseResult( result ); else @@ -988,19 +1002,21 @@ namespace detail { auto const &token = *remainingTokens; if( isMatch(token.token ) ) { if( m_ref->isFlag() ) { - auto result = m_ref->setFlag( true ); + auto flagRef = static_cast( 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( 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 = m_ref->setValue( argToken.token ); + auto result = valueRef->setValue( argToken.token ); if( !result ) return InternalParseResult( result ); if( result.value() == ParseResultType::ShortCircuitAll ) @@ -1077,6 +1093,12 @@ namespace detail { return Parser( *this ) |= other; } + // Forward deprecated interface with '+' instead of '|' + template + auto operator+=( T const &other ) -> Parser & { return operator|=( other ); } + template + auto operator+( T const &other ) const -> Parser { return operator|( other ); } + auto getHelpColumns() const -> std::vector { std::vector cols; for (auto const &o : m_options) { @@ -1116,6 +1138,8 @@ namespace detail { 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 ) +