summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorHaibo Huang <hhb@google.com>2020-03-23 19:58:50 +0000
committerAutomerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com>2020-03-23 19:58:50 +0000
commit58a877e56714839d31639ca35624728f9f8fad3c (patch)
tree0835de12c1ead9541cc311c005445af19bba0f24
parentdba03cace0e298b6a690c00ccd99848193c2e0f9 (diff)
parent23c558a446676c76149e3a15fc3f1aa414537b99 (diff)
downloadcatch2-58a877e56714839d31639ca35624728f9f8fad3c.tar.gz
Upgrade catch2 to 'v2.11.2' am: 7ddcf9576c am: 23c558a446
Change-Id: Ifc6f57bce5249b372ecf8c4e4c19d7120e8ce707
-rw-r--r--.github/FUNDING.yml1
-rw-r--r--.travis.yml25
-rw-r--r--Android.bp1
-rw-r--r--CMakeLists.txt20
-rw-r--r--METADATA8
-rw-r--r--README.md9
-rw-r--r--appveyor.yml7
-rw-r--r--artwork/catch2-c-logo.pngbin18222 -> 10636 bytes
-rw-r--r--artwork/catch2-hand-logo.pngbin57969 -> 33761 bytes
-rw-r--r--artwork/catch2-logo-small.pngbin29025 -> 20939 bytes
-rw-r--r--codecov.yml1
-rw-r--r--conanfile.py2
-rw-r--r--contrib/CatchAddTests.cmake69
-rw-r--r--docs/Readme.md2
-rw-r--r--docs/assertions.md2
-rw-r--r--docs/benchmarks.md254
-rw-r--r--docs/ci-and-misc.md6
-rw-r--r--docs/command-line.md74
-rw-r--r--docs/commercial-users.md3
-rw-r--r--docs/configuration.md32
-rw-r--r--docs/contributing.md64
-rw-r--r--docs/deprecations.md44
-rw-r--r--docs/generators.md35
-rw-r--r--docs/limitations.md9
-rw-r--r--docs/logging.md4
-rw-r--r--docs/matchers.md101
-rw-r--r--docs/opensource-users.md9
-rw-r--r--docs/other-macros.md4
-rw-r--r--docs/release-notes.md215
-rw-r--r--docs/release-process.md5
-rw-r--r--docs/reporters.md1
-rw-r--r--docs/slow-compiles.md7
-rw-r--r--docs/test-cases-and-sections.md85
-rw-r--r--docs/test-fixtures.md54
-rw-r--r--docs/tostring.md67
-rw-r--r--docs/tutorial.md2
-rw-r--r--examples/210-Evt-EventListeners.cpp6
-rw-r--r--examples/231-Cfg-OutputStreams.cpp13
-rw-r--r--examples/301-Gen-MapTypeConversion.cpp8
-rw-r--r--include/catch.hpp86
-rw-r--r--include/internal/benchmark/catch_benchmark.hpp122
-rw-r--r--include/internal/benchmark/catch_benchmarking_all.hpp29
-rw-r--r--include/internal/benchmark/catch_chronometer.hpp71
-rw-r--r--include/internal/benchmark/catch_clock.hpp40
-rw-r--r--include/internal/benchmark/catch_constructor.hpp79
-rw-r--r--include/internal/benchmark/catch_environment.hpp38
-rw-r--r--include/internal/benchmark/catch_estimate.hpp31
-rw-r--r--include/internal/benchmark/catch_execution_plan.hpp58
-rw-r--r--include/internal/benchmark/catch_optimizer.hpp68
-rw-r--r--include/internal/benchmark/catch_outlier_classification.hpp29
-rw-r--r--include/internal/benchmark/catch_sample_analysis.hpp50
-rw-r--r--include/internal/benchmark/detail/catch_analyse.hpp78
-rw-r--r--include/internal/benchmark/detail/catch_benchmark_function.hpp105
-rw-r--r--include/internal/benchmark/detail/catch_complete_invoke.hpp69
-rw-r--r--include/internal/benchmark/detail/catch_estimate_clock.hpp113
-rw-r--r--include/internal/benchmark/detail/catch_measure.hpp35
-rw-r--r--include/internal/benchmark/detail/catch_repeat.hpp37
-rw-r--r--include/internal/benchmark/detail/catch_run_for_at_least.hpp65
-rw-r--r--include/internal/benchmark/detail/catch_stats.cpp224
-rw-r--r--include/internal/benchmark/detail/catch_stats.hpp160
-rw-r--r--include/internal/benchmark/detail/catch_timing.hpp33
-rw-r--r--include/internal/catch_approx.cpp3
-rw-r--r--include/internal/catch_assertionresult.cpp20
-rw-r--r--include/internal/catch_benchmark.cpp36
-rw-r--r--include/internal/catch_benchmark.h57
-rw-r--r--include/internal/catch_capture.hpp8
-rw-r--r--include/internal/catch_capture_matchers.h1
-rw-r--r--include/internal/catch_commandline.cpp34
-rw-r--r--include/internal/catch_common.cpp3
-rw-r--r--include/internal/catch_common.h2
-rw-r--r--include/internal/catch_compiler_capabilities.h201
-rw-r--r--include/internal/catch_config.cpp25
-rw-r--r--include/internal/catch_config.hpp13
-rw-r--r--include/internal/catch_console_colour.cpp24
-rw-r--r--include/internal/catch_context.cpp8
-rw-r--r--include/internal/catch_context.h4
-rw-r--r--include/internal/catch_debug_console.cpp12
-rw-r--r--include/internal/catch_debugger.cpp2
-rw-r--r--include/internal/catch_debugger.h23
-rw-r--r--include/internal/catch_default_main.hpp3
-rw-r--r--include/internal/catch_enforce.cpp21
-rw-r--r--include/internal/catch_enforce.h35
-rw-r--r--include/internal/catch_enum_values_registry.cpp75
-rw-r--r--include/internal/catch_enum_values_registry.h35
-rw-r--r--include/internal/catch_fatal_condition.cpp2
-rw-r--r--include/internal/catch_generators.hpp24
-rw-r--r--include/internal/catch_generators_generic.hpp29
-rw-r--r--include/internal/catch_generators_specific.hpp56
-rw-r--r--include/internal/catch_interfaces_capture.h15
-rw-r--r--include/internal/catch_interfaces_config.cpp2
-rw-r--r--include/internal/catch_interfaces_config.h11
-rw-r--r--include/internal/catch_interfaces_enum_values_registry.h46
-rw-r--r--include/internal/catch_interfaces_exception.cpp2
-rw-r--r--include/internal/catch_interfaces_exception.h3
-rw-r--r--include/internal/catch_interfaces_registry_hub.cpp2
-rw-r--r--include/internal/catch_interfaces_registry_hub.h4
-rw-r--r--include/internal/catch_interfaces_reporter.h50
-rw-r--r--include/internal/catch_interfaces_runner.cpp2
-rw-r--r--include/internal/catch_interfaces_testcase.cpp2
-rw-r--r--include/internal/catch_interfaces_testcase.h1
-rw-r--r--include/internal/catch_list.cpp21
-rw-r--r--include/internal/catch_matchers.h23
-rw-r--r--include/internal/catch_matchers_exception.cpp30
-rw-r--r--include/internal/catch_matchers_exception.hpp36
-rw-r--r--include/internal/catch_matchers_floating.cpp186
-rw-r--r--include/internal/catch_matchers_floating.h31
-rw-r--r--include/internal/catch_message.cpp22
-rw-r--r--include/internal/catch_meta.hpp83
-rw-r--r--include/internal/catch_objc.hpp10
-rw-r--r--include/internal/catch_preprocessor.hpp167
-rw-r--r--include/internal/catch_random_number_generator.cpp62
-rw-r--r--include/internal/catch_random_number_generator.h49
-rw-r--r--include/internal/catch_registry_hub.cpp5
-rw-r--r--include/internal/catch_reporter_registrars.hpp10
-rw-r--r--include/internal/catch_run_context.cpp27
-rw-r--r--include/internal/catch_run_context.h8
-rw-r--r--include/internal/catch_section.h6
-rw-r--r--include/internal/catch_session.cpp101
-rw-r--r--include/internal/catch_session.h2
-rw-r--r--include/internal/catch_stream.cpp8
-rw-r--r--include/internal/catch_stream.h4
-rw-r--r--include/internal/catch_string_manip.cpp29
-rw-r--r--include/internal/catch_string_manip.h9
-rw-r--r--include/internal/catch_stringref.cpp101
-rw-r--r--include/internal/catch_stringref.h100
-rw-r--r--include/internal/catch_tag_alias_autoregistrar.h3
-rw-r--r--include/internal/catch_test_case_info.cpp8
-rw-r--r--include/internal/catch_test_case_registry_impl.cpp10
-rw-r--r--include/internal/catch_test_case_registry_impl.h2
-rw-r--r--include/internal/catch_test_case_tracker.cpp22
-rw-r--r--include/internal/catch_test_case_tracker.h1
-rw-r--r--include/internal/catch_test_registry.h293
-rw-r--r--include/internal/catch_test_spec.cpp80
-rw-r--r--include/internal/catch_test_spec.h30
-rw-r--r--include/internal/catch_test_spec_parser.cpp233
-rw-r--r--include/internal/catch_test_spec_parser.h52
-rw-r--r--include/internal/catch_tostring.cpp27
-rw-r--r--include/internal/catch_tostring.h25
-rw-r--r--include/internal/catch_type_traits.hpp40
-rw-r--r--include/internal/catch_version.cpp2
-rw-r--r--include/internal/catch_wildcard_pattern.cpp16
-rw-r--r--include/internal/catch_wildcard_pattern.h2
-rw-r--r--include/internal/catch_xmlwriter.cpp112
-rw-r--r--include/internal/catch_xmlwriter.h25
-rw-r--r--include/reporters/catch_reporter_bases.hpp4
-rw-r--r--include/reporters/catch_reporter_compact.cpp15
-rw-r--r--include/reporters/catch_reporter_console.cpp153
-rw-r--r--include/reporters/catch_reporter_console.h11
-rw-r--r--include/reporters/catch_reporter_junit.cpp32
-rw-r--r--include/reporters/catch_reporter_listening.cpp28
-rw-r--r--include/reporters/catch_reporter_listening.h12
-rw-r--r--include/reporters/catch_reporter_sonarqube.hpp181
-rw-r--r--include/reporters/catch_reporter_teamcity.hpp3
-rw-r--r--include/reporters/catch_reporter_xml.cpp49
-rw-r--r--include/reporters/catch_reporter_xml.h7
-rw-r--r--misc/appveyorMergeCoverageScript.py4
-rw-r--r--misc/coverage-helper.cpp26
-rw-r--r--projects/CMakeLists.txt129
-rw-r--r--projects/ExtraTests/CMakeLists.txt32
-rw-r--r--projects/ExtraTests/X01-PrefixedMacros.cpp1
-rw-r--r--projects/ExtraTests/X12-CustomDebugBreakMacro.cpp17
-rw-r--r--projects/ExtraTests/X20-BenchmarkingMacros.cpp125
-rw-r--r--projects/ExtraTests/X90-WindowsHeaderInclusion.cpp12
-rw-r--r--projects/SelfTest/Baselines/compact.sw.approved.txt530
-rw-r--r--projects/SelfTest/Baselines/console.std.approved.txt89
-rw-r--r--projects/SelfTest/Baselines/console.sw.approved.txt3110
-rw-r--r--projects/SelfTest/Baselines/console.swa4.approved.txt20
-rw-r--r--projects/SelfTest/Baselines/junit.sw.approved.txt883
-rw-r--r--projects/SelfTest/Baselines/sonarqube.sw.approved.txt1731
-rw-r--r--projects/SelfTest/Baselines/xml.sw.approved.txt4047
-rw-r--r--projects/SelfTest/IntrospectiveTests/CmdLine.tests.cpp92
-rw-r--r--projects/SelfTest/IntrospectiveTests/Details.tests.cpp23
-rw-r--r--projects/SelfTest/IntrospectiveTests/GeneratorsImpl.tests.cpp94
-rw-r--r--projects/SelfTest/IntrospectiveTests/InternalBenchmark.tests.cpp405
-rw-r--r--projects/SelfTest/IntrospectiveTests/PartTracker.tests.cpp15
-rw-r--r--projects/SelfTest/IntrospectiveTests/RandomNumberGeneration.tests.cpp45
-rw-r--r--projects/SelfTest/IntrospectiveTests/String.tests.cpp162
-rw-r--r--projects/SelfTest/IntrospectiveTests/StringManip.tests.cpp67
-rw-r--r--projects/SelfTest/IntrospectiveTests/Tag.tests.cpp7
-rw-r--r--projects/SelfTest/IntrospectiveTests/ToString.tests.cpp42
-rw-r--r--projects/SelfTest/IntrospectiveTests/Xml.tests.cpp64
-rw-r--r--projects/SelfTest/Misc/invalid-test-names.input1
-rw-r--r--projects/SelfTest/Misc/plain-old-tests.input2
-rw-r--r--projects/SelfTest/Misc/special-characters-in-file.input1
-rw-r--r--projects/SelfTest/TestMain.cpp1
-rw-r--r--projects/SelfTest/UsageTests/Approx.tests.cpp7
-rw-r--r--projects/SelfTest/UsageTests/Benchmark.tests.cpp153
-rw-r--r--projects/SelfTest/UsageTests/Class.tests.cpp34
-rw-r--r--projects/SelfTest/UsageTests/Compilation.tests.cpp36
-rw-r--r--projects/SelfTest/UsageTests/EnumToString.tests.cpp35
-rw-r--r--projects/SelfTest/UsageTests/Generators.tests.cpp54
-rw-r--r--projects/SelfTest/UsageTests/Matchers.tests.cpp117
-rw-r--r--projects/SelfTest/UsageTests/Message.tests.cpp7
-rw-r--r--projects/SelfTest/UsageTests/Misc.tests.cpp91
-rw-r--r--projects/SelfTest/UsageTests/ToStringByte.tests.cpp15
-rw-r--r--projects/SelfTest/UsageTests/ToStringGeneral.tests.cpp34
-rw-r--r--projects/SelfTest/UsageTests/ToStringVariant.tests.cpp4
-rw-r--r--projects/SelfTest/UsageTests/ToStringVector.tests.cpp6
-rw-r--r--projects/SelfTest/UsageTests/Tricky.tests.cpp34
-rw-r--r--projects/SelfTest/WarnAboutNoTests.cmake19
-rw-r--r--projects/Where did the projects go.txt13
-rwxr-xr-xscripts/approvalTests.py6
-rwxr-xr-xscripts/approve.py2
-rwxr-xr-xscripts/benchmarkCompile.py2
-rwxr-xr-xscripts/developBuild.py2
-rwxr-xr-xscripts/embedClara.py2
-rw-r--r--scripts/extractFeaturesFromReleaseNotes.py94
-rwxr-xr-xscripts/fixWhitespace.py2
-rwxr-xr-xscripts/generateSingleHeader.py28
-rwxr-xr-xscripts/majorRelease.py2
-rwxr-xr-xscripts/minorRelease.py2
-rwxr-xr-xscripts/patchRelease.py2
-rw-r--r--scripts/releaseCommon.py55
-rwxr-xr-xscripts/releaseNotes.py2
-rw-r--r--scripts/updateDocumentToC.py2
-rw-r--r--scripts/updateWandbox.py20
-rw-r--r--single_include/catch2/catch.hpp4659
-rw-r--r--single_include/catch2/catch_reporter_sonarqube.hpp181
-rw-r--r--single_include/catch2/catch_reporter_teamcity.hpp3
219 files changed, 19927 insertions, 3948 deletions
diff --git a/.github/FUNDING.yml b/.github/FUNDING.yml
new file mode 100644
index 00000000..01d384e8
--- /dev/null
+++ b/.github/FUNDING.yml
@@ -0,0 +1 @@
+patreon: horenmar
diff --git a/.travis.yml b/.travis.yml
index 345edfbb..0fe2abb1 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -9,8 +9,8 @@ common_sources: &all_sources
- llvm-toolchain-trusty
- llvm-toolchain-trusty-3.9
- llvm-toolchain-trusty-4.0
- - llvm-toolchain-trusty-5.0
- - llvm-toolchain-trusty-6.0
+ - llvm-toolchain-xenial-5.0
+ - llvm-toolchain-xenial-6.0
matrix:
include:
@@ -60,6 +60,7 @@ matrix:
env: COMPILER='clang++-4.0'
- os: linux
+ dist: xenial
compiler: clang
addons:
apt:
@@ -68,6 +69,7 @@ matrix:
env: COMPILER='clang++-5.0'
- os: linux
+ dist: xenial
compiler: clang
addons:
apt:
@@ -153,6 +155,7 @@ matrix:
env: COMPILER='clang++-4.0' CPP14=1
- os: linux
+ dist: xenial
compiler: clang
addons:
apt:
@@ -161,6 +164,7 @@ matrix:
env: COMPILER='clang++-5.0' CPP14=1
- os: linux
+ dist: xenial
compiler: clang
addons:
apt:
@@ -255,6 +259,7 @@ matrix:
env: COMPILER='g++-7' EXAMPLES=1 COVERAGE=1 EXTRAS=1 CPP17=1
- os: linux
+ dist: xenial
compiler: clang
addons:
apt:
@@ -263,6 +268,7 @@ matrix:
env: COMPILER='clang++-6.0' CPP17=1
- os: linux
+ dist: xenial
compiler: clang
addons:
apt:
@@ -276,7 +282,7 @@ matrix:
- "3.7"
dist: xenial
install:
- - pip install conan==1.10.2 conan-package-tools
+ - pip install conan-package-tools
env:
- CONAN_GCC_VERSIONS=8
- CONAN_DOCKER_IMAGE=conanio/gcc8
@@ -301,10 +307,19 @@ before_script:
# Regenerate single header file, so it is tested in the examples...
- python scripts/generateSingleHeader.py
+ - |
+ if [[ ${CPP17} -eq 1 ]]; then
+ export CPP_STANDARD=17
+ elif [[ ${CPP14} -eq 1 ]]; then
+ export CPP_STANDARD=14
+ else
+ export CPP_STANDARD=11
+ fi
+
# Use Debug builds for running Valgrind and building examples
- - cmake -H. -BBuild-Debug -DCMAKE_BUILD_TYPE=Debug -Wdev -DUSE_CPP14=${CPP14} -DUSE_CPP17=${CPP17} -DCATCH_USE_VALGRIND=${VALGRIND} -DCATCH_BUILD_EXAMPLES=${EXAMPLES} -DCATCH_ENABLE_COVERAGE=${COVERAGE} -DCATCH_BUILD_EXTRA_TESTS=${EXTRAS}
+ - cmake -H. -BBuild-Debug -DCMAKE_BUILD_TYPE=Debug -Wdev -DCATCH_USE_VALGRIND=${VALGRIND} -DCATCH_BUILD_EXAMPLES=${EXAMPLES} -DCATCH_ENABLE_COVERAGE=${COVERAGE} -DCATCH_BUILD_EXTRA_TESTS=${EXTRAS} -DCMAKE_CXX_STANDARD=${CPP_STANDARD} -DCMAKE_CXX_STANDARD_REQUIRED=On -DCMAKE_CXX_EXTENSIONS=OFF
# Don't bother with release build for coverage build
- - cmake -H. -BBuild-Release -DCMAKE_BUILD_TYPE=Release -Wdev -DUSE_CPP14=${CPP14} -DUSE_CPP17=${CPP17}
+ - cmake -H. -BBuild-Release -DCMAKE_BUILD_TYPE=Release -Wdev -DCMAKE_CXX_STANDARD=${CPP_STANDARD} -DCMAKE_CXX_STANDARD_REQUIRED=On -DCMAKE_CXX_EXTENSIONS=OFF
script:
diff --git a/Android.bp b/Android.bp
index 4852cf03..6f81964d 100644
--- a/Android.bp
+++ b/Android.bp
@@ -71,6 +71,7 @@ cc_defaults {
exclude_srcs: [
"projects/SelfTest/CompileTimePerfTests/**/*.cpp",
],
+ shared_libs: ["liblog"],
}
// Upstream config: Exceptions are enabled.
diff --git a/CMakeLists.txt b/CMakeLists.txt
index e2329c69..ad04dec1 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -6,7 +6,15 @@ if(NOT DEFINED PROJECT_NAME)
set(NOT_SUBPROJECT ON)
endif()
-project(Catch2 LANGUAGES CXX VERSION 2.7.2)
+# Catch2's build breaks if done in-tree. You probably should not build
+# things in tree anyway, but we can allow projects that include Catch2
+# as a subproject to build in-tree as long as it is not in our tree.
+if (CMAKE_BINARY_DIR STREQUAL CMAKE_CURRENT_SOURCE_DIR)
+ message(FATAL_ERROR "Building in-source is not supported! Create a build dir and remove ${CMAKE_SOURCE_DIR}/CMakeCache.txt")
+endif()
+
+
+project(Catch2 LANGUAGES CXX VERSION 2.11.2)
# Provide path for scripts
list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_LIST_DIR}/CMake")
@@ -88,6 +96,10 @@ target_include_directories(Catch2
$<INSTALL_INTERFACE:${CMAKE_INSTALL_INCLUDEDIR}>
)
+if (ANDROID)
+ target_link_libraries(Catch2 INTERFACE log)
+endif()
+
# provide a namespaced alias for clients to 'link' against if catch is included as a sub-project
add_library(Catch2::Catch2 ALIAS Catch2)
@@ -132,9 +144,11 @@ if (NOT_SUBPROJECT)
#
# CMake does not provide a direct customization point for this in
# `write_basic_package_version_file`, but it can be accomplished
- # indirectly by temporarily undefining `CMAKE_SIZEOF_VOID_P`.
+ # indirectly by temporarily redefining `CMAKE_SIZEOF_VOID_P` to an
+ # empty string. Note that just undefining the variable could be
+ # insufficient in cases where the variable was already in CMake cache
set(CATCH2_CMAKE_SIZEOF_VOID_P ${CMAKE_SIZEOF_VOID_P})
- unset(CMAKE_SIZEOF_VOID_P)
+ set(CMAKE_SIZEOF_VOID_P "")
write_basic_package_version_file(
"${CMAKE_CURRENT_BINARY_DIR}/Catch2ConfigVersion.cmake"
COMPATIBILITY
diff --git a/METADATA b/METADATA
index 50e9afad..25e339a7 100644
--- a/METADATA
+++ b/METADATA
@@ -9,11 +9,11 @@ third_party {
type: GIT
value: "https://github.com/catchorg/Catch2.git"
}
- version: "v2.7.2"
+ version: "v2.11.2"
license_type: NOTICE
last_upgrade_date {
- year: 2019
- month: 5
- day: 2
+ year: 2020
+ month: 3
+ day: 19
}
}
diff --git a/README.md b/README.md
index 535ac6ec..3167d24d 100644
--- a/README.md
+++ b/README.md
@@ -5,11 +5,11 @@
[![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/rsEsNO9M0flb5NlQ)
+[![Try online](https://img.shields.io/badge/try-online-blue.svg)](https://wandbox.org/permlink/ZI5SYb7JE1UJhAKP)
[![Join the chat in Discord: https://discord.gg/4CWS9zD](https://img.shields.io/badge/Discord-Chat!-brightgreen.svg)](https://discord.gg/4CWS9zD)
-<a href="https://github.com/catchorg/Catch2/releases/download/v2.7.2/catch.hpp">The latest version of the single header can be downloaded directly using this link</a>
+<a href="https://github.com/catchorg/Catch2/releases/download/v2.11.2/catch.hpp">The latest version of the single header can be downloaded directly using this link</a>
## Catch2 is released!
@@ -19,9 +19,8 @@ before moving to Catch2. You might also like to read [this blog post](https://le
## What's the Catch?
-Catch2 stands for C++ Automated Test Cases in a Header and is a
-multi-paradigm test framework for C++. which also supports Objective-C
-(and maybe C).
+Catch2 is a multi-paradigm test framework for C++. which also supports
+Objective-C (and maybe C).
It is primarily distributed as a single header file, although certain
extensions may require additional headers.
diff --git a/appveyor.yml b/appveyor.yml
index 53f5b395..dfd44316 100644
--- a/appveyor.yml
+++ b/appveyor.yml
@@ -1,6 +1,11 @@
# version string format -- This will be overwritten later anyway
version: "{build}"
+# We need a more up to date pip because Python 2.7 is EOL soon
+init:
+ - set PATH=C:\Python35\Scripts;%PATH%
+
+
branches:
except:
- /dev-travis.+/
@@ -62,7 +67,7 @@ matrix:
install:
- - ps: if (($env:CONFIGURATION) -eq "Debug" -And ($env:coverage) -eq "1" ) { python -m pip --disable-pip-version-check install codecov }
+ - ps: if (($env:CONFIGURATION) -eq "Debug" -And ($env:coverage) -eq "1" ) { pip --disable-pip-version-check 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.
diff --git a/artwork/catch2-c-logo.png b/artwork/catch2-c-logo.png
index bab400f9..b1066b8e 100644
--- a/artwork/catch2-c-logo.png
+++ b/artwork/catch2-c-logo.png
Binary files differ
diff --git a/artwork/catch2-hand-logo.png b/artwork/catch2-hand-logo.png
index 5a5e142d..ab857eaa 100644
--- a/artwork/catch2-hand-logo.png
+++ b/artwork/catch2-hand-logo.png
Binary files differ
diff --git a/artwork/catch2-logo-small.png b/artwork/catch2-logo-small.png
index f2118bee..742e81e1 100644
--- a/artwork/catch2-logo-small.png
+++ b/artwork/catch2-logo-small.png
Binary files differ
diff --git a/codecov.yml b/codecov.yml
index 94d88d83..75809ee2 100644
--- a/codecov.yml
+++ b/codecov.yml
@@ -14,6 +14,7 @@ coverage:
- "**/catch_reporter_tap.hpp"
- "**/catch_reporter_automake.hpp"
- "**/catch_reporter_teamcity.hpp"
+ - "**/catch_reporter_sonarqube.hpp"
- "**/external/clara.hpp"
diff --git a/conanfile.py b/conanfile.py
index a7cebb92..8d407baf 100644
--- a/conanfile.py
+++ b/conanfile.py
@@ -18,7 +18,7 @@ class CatchConan(ConanFile):
cmake.definitions["BUILD_TESTING"] = "OFF"
cmake.definitions["CATCH_INSTALL_DOCS"] = "OFF"
cmake.definitions["CATCH_INSTALL_HELPERS"] = "ON"
- cmake.configure()
+ cmake.configure(build_folder='build')
cmake.install()
self.copy(pattern="LICENSE.txt", dst="licenses")
diff --git a/contrib/CatchAddTests.cmake b/contrib/CatchAddTests.cmake
index ca5ebc17..156d55ff 100644
--- a/contrib/CatchAddTests.cmake
+++ b/contrib/CatchAddTests.cmake
@@ -22,39 +22,6 @@ function(add_command NAME)
set(script "${script}${NAME}(${_args})\n" PARENT_SCOPE)
endfunction()
-macro(_add_catch_test_labels LINE)
- # convert to list of tags
- string(REPLACE "][" "]\\;[" tags ${line})
-
- add_command(
- set_tests_properties "${prefix}${test}${suffix}"
- PROPERTIES
- LABELS "${tags}"
- )
-endmacro()
-
-macro(_add_catch_test LINE)
- set(test ${line})
- # use escape commas to handle properly test cases with commans inside the name
- string(REPLACE "," "\\," test_name ${test})
- # ...and add to script
- add_command(
- add_test "${prefix}${test}${suffix}"
- ${TEST_EXECUTOR}
- "${TEST_EXECUTABLE}"
- "${test_name}"
- ${extra_args}
- )
-
- add_command(
- set_tests_properties "${prefix}${test}${suffix}"
- PROPERTIES
- WORKING_DIRECTORY "${TEST_WORKING_DIR}"
- ${properties}
- )
- list(APPEND tests "${prefix}${test}${suffix}")
-endmacro()
-
# Run test executable to get list of available tests
if(NOT EXISTS "${TEST_EXECUTABLE}")
message(FATAL_ERROR
@@ -62,7 +29,7 @@ if(NOT EXISTS "${TEST_EXECUTABLE}")
)
endif()
execute_process(
- COMMAND ${TEST_EXECUTOR} "${TEST_EXECUTABLE}" ${spec} --list-tests
+ COMMAND ${TEST_EXECUTOR} "${TEST_EXECUTABLE}" ${spec} --list-test-names-only
OUTPUT_VARIABLE output
RESULT_VARIABLE result
)
@@ -80,22 +47,30 @@ elseif(${result} LESS 0)
endif()
string(REPLACE "\n" ";" output "${output}")
-set(test)
-set(tags_regex "(\\[([^\\[]*)\\])+$")
# Parse output
foreach(line ${output})
- # lines without leading whitespaces are catch output not tests
- if(${line} MATCHES "^[ \t]+")
- # strip leading spaces and tabs
- string(REGEX REPLACE "^[ \t]+" "" line ${line})
-
- if(${line} MATCHES "${tags_regex}")
- _add_catch_test_labels(${line})
- else()
- _add_catch_test(${line})
- endif()
- endif()
+ set(test ${line})
+ # Escape characters in test case names that would be parsed by Catch2
+ set(test_name ${test})
+ foreach(char , [ ])
+ string(REPLACE ${char} "\\${char}" test_name ${test_name})
+ endforeach(char)
+ # ...and add to script
+ add_command(add_test
+ "${prefix}${test}${suffix}"
+ ${TEST_EXECUTOR}
+ "${TEST_EXECUTABLE}"
+ "${test_name}"
+ ${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
diff --git a/docs/Readme.md b/docs/Readme.md
index 721880ab..0bbb104e 100644
--- a/docs/Readme.md
+++ b/docs/Readme.md
@@ -14,6 +14,7 @@ Writing tests:
* [Event Listeners](event-listeners.md#top)
* [Data Generators](generators.md#top)
* [Other macros](other-macros.md#top)
+* [Micro benchmarking](benchmarks.md#top)
Fine tuning:
* [Supplying your own main()](own-main.md#top)
@@ -34,6 +35,7 @@ FAQ:
Other:
* [Why Catch?](why-catch.md#top)
* [Open Source Projects using Catch](opensource-users.md#top)
+* [Commercial Projects using Catch](commercial-users.md#top)
* [Contributing](contributing.md#top)
* [Release Notes](release-notes.md#top)
* [Deprecations and incoming changes](deprecations.md#top)
diff --git a/docs/assertions.md b/docs/assertions.md
index 07d2484e..682eb6e7 100644
--- a/docs/assertions.md
+++ b/docs/assertions.md
@@ -136,7 +136,7 @@ REQUIRE_THROWS_WITH( dismantleHal(), "My mind is going" );
* **REQUIRE_THROWS_MATCHES(** _expression_, _exception type_, _matcher for given exception type_ **)** and
* **CHECK_THROWS_MATCHES(** _expression_, _exception type_, _matcher for given exception type_ **)**
-Expects that exception of _exception type_ is thrown and it matches provided matcher (see next section for Matchers).
+Expects that exception of _exception type_ is thrown and it matches provided matcher (see the [documentation for Matchers](matchers.md#top)).
_Please note that the `THROW` family of assertions expects to be passed a single expression, not a statement or series of statements. If you want to check a more complicated sequence of operations, you can use a C++11 lambda function._
diff --git a/docs/benchmarks.md b/docs/benchmarks.md
new file mode 100644
index 00000000..a41839fd
--- /dev/null
+++ b/docs/benchmarks.md
@@ -0,0 +1,254 @@
+<a id="top"></a>
+# Authoring benchmarks
+
+> [Introduced](https://github.com/catchorg/Catch2/issues/1616) in Catch 2.9.0.
+
+_Note that benchmarking support is disabled by default and to enable it,
+you need to define `CATCH_CONFIG_ENABLE_BENCHMARKING`. For more details,
+see the [compile-time configuration documentation](configuration.md#top)._
+
+Writing benchmarks is not easy. Catch simplifies certain aspects but you'll
+always need to take care about various aspects. Understanding a few things about
+the way Catch runs your code will be very helpful when writing your benchmarks.
+
+First off, let's go over some terminology that will be used throughout this
+guide.
+
+- *User code*: user code is the code that the user provides to be measured.
+- *Run*: one run is one execution of the user code.
+- *Sample*: one sample is one data point obtained by measuring the time it takes
+ to perform a certain number of runs. One sample can consist of more than one
+ run if the clock available does not have enough resolution to accurately
+ measure a single run. All samples for a given benchmark execution are obtained
+ with the same number of runs.
+
+## Execution procedure
+
+Now I can explain how a benchmark is executed in Catch. There are three main
+steps, though the first does not need to be repeated for every benchmark.
+
+1. *Environmental probe*: before any benchmarks can be executed, the clock's
+resolution is estimated. A few other environmental artifacts are also estimated
+at this point, like the cost of calling the clock function, but they almost
+never have any impact in the results.
+
+2. *Estimation*: the user code is executed a few times to obtain an estimate of
+the amount of runs that should be in each sample. This also has the potential
+effect of bringing relevant code and data into the caches before the actual
+measurement starts.
+
+3. *Measurement*: all the samples are collected sequentially by performing the
+number of runs estimated in the previous step for each sample.
+
+This already gives us one important rule for writing benchmarks for Catch: the
+benchmarks must be repeatable. The user code will be executed several times, and
+the number of times it will be executed during the estimation step cannot be
+known beforehand since it depends on the time it takes to execute the code.
+User code that cannot be executed repeatedly will lead to bogus results or
+crashes.
+
+## Benchmark specification
+
+Benchmarks can be specified anywhere inside a Catch test case.
+There is a simple and a slightly more advanced version of the `BENCHMARK` macro.
+
+Let's have a look how a naive Fibonacci implementation could be benchmarked:
+```c++
+std::uint64_t Fibonacci(std::uint64_t number) {
+ return number < 2 ? 1 : Fibonacci(number - 1) + Fibonacci(number - 2);
+}
+```
+Now the most straight forward way to benchmark this function, is just adding a `BENCHMARK` macro to our test case:
+```c++
+TEST_CASE("Fibonacci") {
+ CHECK(Fibonacci(0) == 1);
+ // some more asserts..
+ CHECK(Fibonacci(5) == 8);
+ // some more asserts..
+
+ // now let's benchmark:
+ BENCHMARK("Fibonacci 20") {
+ return Fibonacci(20);
+ };
+
+ BENCHMARK("Fibonacci 25") {
+ return Fibonacci(25);
+ };
+
+ BENCHMARK("Fibonacci 30") {
+ return Fibonacci(30);
+ };
+
+ BENCHMARK("Fibonacci 35") {
+ return Fibonacci(35);
+ };
+}
+```
+There's a few things to note:
+- As `BENCHMARK` expands to a lambda expression it is necessary to add a semicolon after
+ the closing brace (as opposed to the first experimental version).
+- The `return` is a handy way to avoid the compiler optimizing away the benchmark code.
+
+Running this already runs the benchmarks and outputs something similar to:
+```
+-------------------------------------------------------------------------------
+Fibonacci
+-------------------------------------------------------------------------------
+C:\path\to\Catch2\Benchmark.tests.cpp(10)
+...............................................................................
+benchmark name samples iterations estimated
+ mean low mean high mean
+ std dev low std dev high std dev
+-------------------------------------------------------------------------------
+Fibonacci 20 100 416439 83.2878 ms
+ 2 ns 2 ns 2 ns
+ 0 ns 0 ns 0 ns
+
+Fibonacci 25 100 400776 80.1552 ms
+ 3 ns 3 ns 3 ns
+ 0 ns 0 ns 0 ns
+
+Fibonacci 30 100 396873 79.3746 ms
+ 17 ns 17 ns 17 ns
+ 0 ns 0 ns 0 ns
+
+Fibonacci 35 100 145169 87.1014 ms
+ 468 ns 464 ns 473 ns
+ 21 ns 15 ns 34 ns
+```
+
+### Advanced benchmarking
+The simplest use case shown above, takes no arguments and just runs the user code that needs to be measured.
+However, if using the `BENCHMARK_ADVANCED` macro and adding a `Catch::Benchmark::Chronometer` argument after
+the macro, some advanced features are available. The contents of the simple benchmarks are invoked once per run,
+while the blocks of the advanced benchmarks are invoked exactly twice:
+once during the estimation phase, and another time during the execution phase.
+
+```c++
+BENCHMARK("simple"){ return long_computation(); };
+
+BENCHMARK_ADVANCED("advanced")(Catch::Benchmark::Chronometer meter) {
+ set_up();
+ meter.measure([] { return long_computation(); });
+};
+```
+
+These advanced benchmarks no longer consist entirely of user code to be measured.
+In these cases, the code to be measured is provided via the
+`Catch::Benchmark::Chronometer::measure` member function. This allows you to set up any
+kind of state that might be required for the benchmark but is not to be included
+in the measurements, like making a vector of random integers to feed to a
+sorting algorithm.
+
+A single call to `Catch::Benchmark::Chronometer::measure` performs the actual measurements
+by invoking the callable object passed in as many times as necessary. Anything
+that needs to be done outside the measurement can be done outside the call to
+`measure`.
+
+The callable object passed in to `measure` can optionally accept an `int`
+parameter.
+
+```c++
+meter.measure([](int i) { return long_computation(i); });
+```
+
+If it accepts an `int` parameter, the sequence number of each run will be passed
+in, starting with 0. This is useful if you want to measure some mutating code,
+for example. The number of runs can be known beforehand by calling
+`Catch::Benchmark::Chronometer::runs`; with this one can set up a different instance to be
+mutated by each run.
+
+```c++
+std::vector<std::string> v(meter.runs());
+std::fill(v.begin(), v.end(), test_string());
+meter.measure([&v](int i) { in_place_escape(v[i]); });
+```
+
+Note that it is not possible to simply use the same instance for different runs
+and resetting it between each run since that would pollute the measurements with
+the resetting code.
+
+It is also possible to just provide an argument name to the simple `BENCHMARK` macro to get
+the same semantics as providing a callable to `meter.measure` with `int` argument:
+
+```c++
+BENCHMARK("indexed", i){ return long_computation(i); };
+```
+
+### Constructors and destructors
+
+All of these tools give you a lot mileage, but there are two things that still
+need special handling: constructors and destructors. The problem is that if you
+use automatic objects they get destroyed by the end of the scope, so you end up
+measuring the time for construction and destruction together. And if you use
+dynamic allocation instead, you end up including the time to allocate memory in
+the measurements.
+
+To solve this conundrum, Catch provides class templates that let you manually
+construct and destroy objects without dynamic allocation and in a way that lets
+you measure construction and destruction separately.
+
+```c++
+BENCHMARK_ADVANCED("construct")(Catch::Benchmark::Chronometer meter) {
+ std::vector<Catch::Benchmark::storage_for<std::string>> storage(meter.runs());
+ meter.measure([&](int i) { storage[i].construct("thing"); });
+};
+
+BENCHMARK_ADVANCED("destroy")(Catch::Benchmark::Chronometer meter) {
+ std::vector<Catch::Benchmark::destructable_object<std::string>> storage(meter.runs());
+ for(auto&& o : storage)
+ o.construct("thing");
+ meter.measure([&](int i) { storage[i].destruct(); });
+};
+```
+
+`Catch::Benchmark::storage_for<T>` objects are just pieces of raw storage suitable for `T`
+objects. You can use the `Catch::Benchmark::storage_for::construct` member function to call a constructor and
+create an object in that storage. So if you want to measure the time it takes
+for a certain constructor to run, you can just measure the time it takes to run
+this function.
+
+When the lifetime of a `Catch::Benchmark::storage_for<T>` object ends, if an actual object was
+constructed there it will be automatically destroyed, so nothing leaks.
+
+If you want to measure a destructor, though, we need to use
+`Catch::Benchmark::destructable_object<T>`. These objects are similar to
+`Catch::Benchmark::storage_for<T>` in that construction of the `T` object is manual, but
+it does not destroy anything automatically. Instead, you are required to call
+the `Catch::Benchmark::destructable_object::destruct` member function, which is what you
+can use to measure the destruction time.
+
+### The optimizer
+
+Sometimes the optimizer will optimize away the very code that you want to
+measure. There are several ways to use results that will prevent the optimiser
+from removing them. You can use the `volatile` keyword, or you can output the
+value to standard output or to a file, both of which force the program to
+actually generate the value somehow.
+
+Catch adds a third option. The values returned by any function provided as user
+code are guaranteed to be evaluated and not optimised out. This means that if
+your user code consists of computing a certain value, you don't need to bother
+with using `volatile` or forcing output. Just `return` it from the function.
+That helps with keeping the code in a natural fashion.
+
+Here's an example:
+
+```c++
+// may measure nothing at all by skipping the long calculation since its
+// result is not used
+BENCHMARK("no return"){ long_calculation(); };
+
+// the result of long_calculation() is guaranteed to be computed somehow
+BENCHMARK("with return"){ return long_calculation(); };
+```
+
+However, there's no other form of control over the optimizer whatsoever. It is
+up to you to write a benchmark that actually measures what you want and doesn't
+just measure the time to do a whole bunch of nothing.
+
+To sum up, there are two simple rules: whatever you would do in handwritten code
+to control optimization still works in Catch; and Catch makes return values
+from user code into observable effects that can't be optimized away.
+
+<i>Adapted from nonius' documentation.</i>
diff --git a/docs/ci-and-misc.md b/docs/ci-and-misc.md
index 8c330872..40b7cec9 100644
--- a/docs/ci-and-misc.md
+++ b/docs/ci-and-misc.md
@@ -12,7 +12,7 @@ Build Systems may refer to low-level tools, like CMake, or larger systems that r
## Continuous Integration systems
-Probably the most important aspect to using Catch with a build server is the use of different reporters. Catch comes bundled with three reporters that should cover the majority of build servers out there - although adding more for better integration with some is always a possibility (currently we also offer TeamCity, TAP and Automake reporters).
+Probably the most important aspect to using Catch with a build server is the use of different reporters. Catch comes bundled with three reporters that should cover the majority of build servers out there - although adding more for better integration with some is always a possibility (currently we also offer TeamCity, TAP, Automake and SonarQube reporters).
Two of these reporters are built in (XML and JUnit) and the third (TeamCity) is included as a separate header. It's possible that the other two may be split out in the future too - as that would make the core of Catch smaller for those that don't need them.
@@ -65,6 +65,10 @@ The Automake Reporter writes out the [meta tags](https://www.gnu.org/software/au
Because of the incremental nature of Catch's test suites and ability to run specific tests, our implementation of TAP reporter writes out the number of tests in a suite last.
+### SonarQube Reporter
+```-r sonarqube```
+[SonarQube Generic Test Data](https://docs.sonarqube.org/latest/analysis/generic-test/) XML format for tests metrics.
+
## Low-level tools
### Precompiled headers (PCHs)
diff --git a/docs/command-line.md b/docs/command-line.md
index f68c84ca..51eeb2f6 100644
--- a/docs/command-line.md
+++ b/docs/command-line.md
@@ -20,7 +20,11 @@
[Specify a seed for the Random Number Generator](#specify-a-seed-for-the-random-number-generator)<br>
[Identify framework and version according to the libIdentify standard](#identify-framework-and-version-according-to-the-libidentify-standard)<br>
[Wait for key before continuing](#wait-for-key-before-continuing)<br>
-[Specify multiples of clock resolution to run benchmarks for](#specify-multiples-of-clock-resolution-to-run-benchmarks-for)<br>
+[Specify the number of benchmark samples to collect](#specify-the-number-of-benchmark-samples-to-collect)<br>
+[Specify the number of resamples for bootstrapping](#specify-the-number-of-resamples-for-bootstrapping)<br>
+[Specify the confidence-interval for bootstrapping](#specify-the-confidence-interval-for-bootstrapping)<br>
+[Disable statistical analysis of collected benchmark samples](#disable-statistical-analysis-of-collected-benchmark-samples)<br>
+[Specify the amount of time in milliseconds spent on warming up each test](#specify-the-amount-of-time-in-milliseconds-spent-on-warming-up-each-test)<br>
[Usage](#usage)<br>
[Specify the section to run](#specify-the-section-to-run)<br>
[Filenames as tags](#filenames-as-tags)<br>
@@ -57,7 +61,11 @@ Click one of the following links to take you straight to that option - or scroll
<a href="#rng-seed"> ` --rng-seed`</a><br />
<a href="#libidentify"> ` --libidentify`</a><br />
<a href="#wait-for-keypress"> ` --wait-for-keypress`</a><br />
-<a href="#benchmark-resolution-multiple"> ` --benchmark-resolution-multiple`</a><br />
+<a href="#benchmark-samples"> ` --benchmark-samples`</a><br />
+<a href="#benchmark-resamples"> ` --benchmark-resamples`</a><br />
+<a href="#benchmark-confidence-interval"> ` --benchmark-confidence-interval`</a><br />
+<a href="#benchmark-no-analysis"> ` --benchmark-no-analysis`</a><br />
+<a href="#benchmark-warmup-time"> ` --benchmark-warmup-time`</a><br />
<a href="#use-colour"> ` --use-colour`</a><br />
</br>
@@ -93,6 +101,7 @@ exclude:notThis Matches all tests except, 'notThis'
~*private* Matches all tests except those that contain 'private'
a* ~ab* abc Matches all tests that start with 'a', except those that
start with 'ab', except 'abc', which is included
+-# [#somefile] Matches all tests from the file 'somefile.cpp'
</pre>
Names within square brackets are interpreted as tags.
@@ -236,7 +245,7 @@ Test cases are ordered one of three ways:
### decl
-Declaration order. The order the tests were originally declared in. Note that ordering between files is not guaranteed and is implementation dependent.
+Declaration order (this is the default order if no --order argument is provided). The order the tests were originally declared in. Note that ordering between files is not guaranteed and is implementation dependent.
### lex
Lexicographically sorted. Tests are sorted, alpha-numerically, by name.
@@ -250,7 +259,7 @@ Randomly sorted. Test names are sorted using ```std::random_shuffle()```. By def
Sets a seed for the random number generator using ```std::srand()```.
If a number is provided this is used directly as the seed so the random pattern is repeatable.
-Alternatively if the keyword ```time``` is provided then the result of calling ```std::time(0)``` is used and so the pattern becomes unpredictable.
+Alternatively if the keyword ```time``` is provided then the result of calling ```std::time(0)``` is used and so the pattern becomes unpredictable. In some cases, you might need to pass the keyword ```time``` in double quotes instead of single quotes.
In either case the actual value for the seed is printed as part of Catch's output so if an issue is discovered that is sensitive to test ordering the ordering can be reproduced - even if it was originally seeded from ```std::time(0)```.
@@ -262,18 +271,61 @@ See [The LibIdentify repo for more information and examples](https://github.com/
<a id="wait-for-keypress"></a>
## Wait for key before continuing
-<pre>--wait-for-keypress &lt;start|exit|both&gt;</pre>
+<pre>--wait-for-keypress &lt;never|start|exit|both&gt;</pre>
Will cause the executable to print a message and wait until the return/ enter key is pressed before continuing -
either before running any tests, after running all tests - or both, depending on the argument.
-<a id="benchmark-resolution-multiple"></a>
-## Specify multiples of clock resolution to run benchmarks for
-<pre>--benchmark-resolution-multiple &lt;multiplier&gt;</pre>
+<a id="benchmark-samples"></a>
+## Specify the number of benchmark samples to collect
+<pre>--benchmark-samples &lt;# of samples&gt;</pre>
-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 overridden here.
+> [Introduced](https://github.com/catchorg/Catch2/issues/1616) in Catch 2.9.0.
+
+When running benchmarks a number of "samples" is collected. This is the base data for later statistical analysis.
+Per sample a clock resolution dependent number of iterations of the user code is run, which is independent of the number of samples. Defaults to 100.
+
+<a id="benchmark-resamples"></a>
+## Specify the number of resamples for bootstrapping
+<pre>--benchmark-resamples &lt;# of resamples&gt;</pre>
+
+> [Introduced](https://github.com/catchorg/Catch2/issues/1616) in Catch 2.9.0.
+
+After the measurements are performed, statistical [bootstrapping] is performed
+on the samples. The number of resamples for that bootstrapping is configurable
+but defaults to 100000. Due to the bootstrapping it is possible to give
+estimates for the mean and standard deviation. The estimates come with a lower
+bound and an upper bound, and the confidence interval (which is configurable but
+defaults to 95%).
+
+ [bootstrapping]: http://en.wikipedia.org/wiki/Bootstrapping_%28statistics%29
+
+<a id="benchmark-confidence-interval"></a>
+## Specify the confidence-interval for bootstrapping
+<pre>--benchmark-confidence-interval &lt;confidence-interval&gt;</pre>
+
+> [Introduced](https://github.com/catchorg/Catch2/issues/1616) in Catch 2.9.0.
+
+The confidence-interval is used for statistical bootstrapping on the samples to
+calculate the upper and lower bounds of mean and standard deviation.
+Must be between 0 and 1 and defaults to 0.95.
+
+<a id="benchmark-no-analysis"></a>
+## Disable statistical analysis of collected benchmark samples
+<pre>--benchmark-no-analysis</pre>
+
+> [Introduced](https://github.com/catchorg/Catch2/issues/1616) in Catch 2.9.0.
+
+When this flag is specified no bootstrapping or any other statistical analysis is performed.
+Instead the user code is only measured and the plain mean from the samples is reported.
+
+<a id="benchmark-warmup-time"></a>
+## Specify the amount of time in milliseconds spent on warming up each test
+<pre>--benchmark-warmup-time</pre>
+
+> [Introduced](https://github.com/catchorg/Catch2/pull/1844) in Catch 2.11.2.
+
+Configure the amount of time spent warming up each test.
<a id="usage"></a>
## Usage
diff --git a/docs/commercial-users.md b/docs/commercial-users.md
index 4f98f759..7d2e87d3 100644
--- a/docs/commercial-users.md
+++ b/docs/commercial-users.md
@@ -17,3 +17,6 @@ fact then please let us know - either directly, via a PR or
- NASA
- [Inscopix Inc.](https://www.inscopix.com/)
- [Makimo](https://makimo.pl/)
+ - [UX3D](https://ux3d.io)
+ - [King](https://king.com)
+
diff --git a/docs/configuration.md b/docs/configuration.md
index c01d7f5e..940356ad 100644
--- a/docs/configuration.md
+++ b/docs/configuration.md
@@ -16,6 +16,7 @@
[Windows header clutter](#windows-header-clutter)<br>
[Enabling stringification](#enabling-stringification)<br>
[Disabling exceptions](#disabling-exceptions)<br>
+[Overriding Catch's debug break (`-b`)](#overriding-catchs-debug-break--b)<br>
Catch is designed to "just work" as much as possible. For most people the only configuration needed is telling Catch which source file should host all the implementation code (```CATCH_CONFIG_MAIN```).
@@ -127,8 +128,12 @@ Catch's selection, by defining either `CATCH_CONFIG_CPP11_TO_STRING` or
## C++17 toggles
CATCH_CONFIG_CPP17_UNCAUGHT_EXCEPTIONS // Use std::uncaught_exceptions instead of std::uncaught_exception
- CATCH_CONFIG_CPP17_STRING_VIEW // Provide StringMaker specialization for std::string_view
- CATCH_CONFIG_CPP17_VARIANT // Override C++17 detection for CATCH_CONFIG_ENABLE_VARIANT_STRINGMAKER
+ CATCH_CONFIG_CPP17_STRING_VIEW // Override std::string_view support detection(Catch provides a StringMaker specialization by default)
+ CATCH_CONFIG_CPP17_VARIANT // Override std::variant support detection (checked by CATCH_CONFIG_ENABLE_VARIANT_STRINGMAKER)
+ CATCH_CONFIG_CPP17_OPTIONAL // Override std::optional support detection (checked by CATCH_CONFIG_ENABLE_OPTIONAL_STRINGMAKER)
+ CATCH_CONFIG_CPP17_BYTE // Override std::byte support detection (Catch provides a StringMaker specialization by default)
+
+> `CATCH_CONFIG_CPP17_STRING_VIEW` was [introduced](https://github.com/catchorg/Catch2/issues/1376) in Catch 2.4.1.
Catch contains basic compiler/standard detection and attempts to use
some C++17 features whenever appropriate. This automatic detection
@@ -149,6 +154,12 @@ by using `_NO_` in the macro, e.g. `CATCH_CONFIG_NO_CPP17_UNCAUGHT_EXCEPTIONS`.
CATCH_CONFIG_DISABLE // Disables assertions and test case registration
CATCH_CONFIG_WCHAR // Enables use of wchart_t
CATCH_CONFIG_EXPERIMENTAL_REDIRECT // Enables the new (experimental) way of capturing stdout/stderr
+ CATCH_CONFIG_ENABLE_BENCHMARKING // Enables the integrated benchmarking features (has a significant effect on compilation speed)
+ CATCH_CONFIG_USE_ASYNC // Force parallel statistical processing of samples during benchmarking
+ CATCH_CONFIG_ANDROID_LOGWRITE // Use android's logging system for debug output
+ CATCH_CONFIG_GLOBAL_NEXTAFTER // Use nextafter{,f,l} instead of std::nextafter
+
+> [`CATCH_CONFIG_ANDROID_LOGWRITE`](https://github.com/catchorg/Catch2/issues/1743) and [`CATCH_CONFIG_GLOBAL_NEXTAFTER`](https://github.com/catchorg/Catch2/pull/1739) were introduced in Catch 2.10.0
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.
@@ -207,9 +218,14 @@ By default, Catch does not stringify some types from the standard library. This
CATCH_CONFIG_ENABLE_OPTIONAL_STRINGMAKER // Provide StringMaker specialization for std::optional (on C++17)
CATCH_CONFIG_ENABLE_ALL_STRINGMAKERS // Defines all of the above
+> `CATCH_CONFIG_ENABLE_VARIANT_STRINGMAKER` was [introduced](https://github.com/catchorg/Catch2/issues/1380) in Catch 2.4.1.
+
+> `CATCH_CONFIG_ENABLE_OPTIONAL_STRINGMAKER` was [introduced](https://github.com/catchorg/Catch2/issues/1510) in Catch 2.6.0.
## Disabling exceptions
+> Introduced in Catch 2.4.0.
+
By default, Catch2 uses exceptions to signal errors and to abort tests
when an assertion from the `REQUIRE` family of assertions fails. We also
provide an experimental support for disabling exceptions. Catch2 should
@@ -242,6 +258,18 @@ namespace Catch {
}
```
+## Overriding Catch's debug break (`-b`)
+
+> [Introduced](https://github.com/catchorg/Catch2/pull/1846) in Catch 2.11.2.
+
+You can override Catch2's break-into-debugger code by defining the
+`CATCH_BREAK_INTO_DEBUGGER()` macro. This can be used if e.g. Catch2 does
+not know your platform, or your platform is misdetected.
+
+The macro will be used as is, that is, `CATCH_BREAK_INTO_DEBUGGER();`
+must compile and must break into debugger.
+
+
---
[Home](Readme.md#top)
diff --git a/docs/contributing.md b/docs/contributing.md
index b95edf86..5429bf9d 100644
--- a/docs/contributing.md
+++ b/docs/contributing.md
@@ -1,6 +1,13 @@
<a id="top"></a>
# Contributing to Catch
+**Contents**<br>
+[Branches](#branches)<br>
+[Directory structure](#directory-structure)<br>
+[Testing your changes](#testing-your-changes)<br>
+[Documenting your code](#documenting-your-code)<br>
+[Code constructs to watch out for](#code-constructs-to-watch-out-for)<br>
+
So you want to contribute something to Catch? That's great! Whether it's a bug fix, a new feature, support for
additional compilers - or just a fix to the documentation - all contributions are very welcome and very much appreciated.
Of course so are bug reports and other comments and questions.
@@ -63,6 +70,10 @@ locally takes just a few minutes.
$ cd debug-build
$ ctest -j 2 --output-on-failure
```
+__Note:__ When running your tests with multi-configuration generators like
+Visual Studio, you might get errors "Test not available without configuration."
+You then have to pick one configuration (e.g. ` -C Debug`) in the `ctest` call.
+
If you added new tests, approval tests are very likely to fail. If they
do not, it means that your changes weren't run as part of them. This
_might_ be intentional, but usually is not.
@@ -75,6 +86,59 @@ before you do so, you need to check that the introduced changes are indeed
intentional.
+## Documenting your code
+
+If you have added new feature to Catch2, it needs documentation, so that
+other people can use it as well. This section collects some technical
+information that you will need for updating Catch2's documentation, and
+possibly some generic advise as well.
+
+First, the technicalities:
+
+* We introduced version tags to the documentation, which show users in
+which version a specific feature was introduced. This means that newly
+written documentation should be tagged with a placeholder, that will
+be replaced with the actual version upon release. There are 2 styles
+of placeholders used through the documentation, you should pick one that
+fits your text better (if in doubt, take a look at the existing version
+tags for other features).
+ * `> [Introduced](link-to-issue-or-PR) in Catch X.Y.Z` - this
+ placeholder is usually used after a section heading
+ * `> X (Y and Z) was [introduced](link-to-issue-or-PR) in Catch X.Y.Z`
+ - this placeholder is used when you need to tag a subpart of something,
+ e.g. list
+* Crosslinks to different pages should target the `top` anchor, like this
+`[link to contributing](contributing.md#top)`.
+* If you have introduced a new document, there is a simple template you
+should use. It provides you with the top anchor mentioned above, and also
+with a backlink to the top of the documentation:
+```markdown
+<a id="top"></a>
+# Cool feature
+
+Text that explains how to use the cool feature.
+
+
+---
+
+[Home](Readme.md#top)
+```
+* For pages with more than 4 subheadings, we provide a table of contents
+(ToC) at the top of the page. Because GitHub markdown does not support
+automatic generation of ToC, it has to be handled semi-manually. Thus,
+if you've added a new subheading to some page, you should add it to the
+ToC. This can be done either manually, or by running the
+`updateDocumentToC.py` script in the `scripts/` folder.
+
+
+Now, for the generic tips:
+ * Usage examples are good
+ * Don't be afraid to introduce new pages
+ * Try to be reasonably consistent with the surrounding documentation
+
+
+
+
## Code constructs to watch out for
This section is a (sadly incomplete) listing of various constructs that
diff --git a/docs/deprecations.md b/docs/deprecations.md
index 0489e1ff..39194ed7 100644
--- a/docs/deprecations.md
+++ b/docs/deprecations.md
@@ -39,6 +39,39 @@ apart from writing it out for `--list-tests -v high`.
Because it isn't actually used nor documented, and brings complications
to Catch2's internals, description support will be removed.
+### SourceLineInfo::empty()
+
+There should be no reason to ever have an empty `SourceLineInfo`, so the
+method will be removed.
+
+
+### Composing lvalues of already composed matchers
+
+Because a significant bug in this use case has persisted for 2+ years
+without a bug report, and to simplify the implementation, code that
+composes lvalues of composed matchers will not compile. That is,
+this code will no longer work:
+
+```cpp
+ auto m1 = Contains("string");
+ auto m2 = Contains("random");
+ auto composed1 = m1 || m2;
+ auto m3 = Contains("different");
+ auto composed2 = composed1 || m3;
+ REQUIRE_THAT(foo(), !composed1);
+ REQUIRE_THAT(foo(), composed2);
+```
+
+Instead you will have to write this:
+
+```cpp
+ auto m1 = Contains("string");
+ auto m2 = Contains("random");
+ auto m3 = Contains("different");
+ REQUIRE_THAT(foo(), !(m1 || m2));
+ REQUIRE_THAT(foo(), m1 || m2 || m3);
+```
+
## Planned changes
@@ -88,6 +121,17 @@ positively match a testspec.
The API for Catch2's console colour will be changed to take an extra
argument, the stream to which the colour code should be applied.
+
+### Type erasure in the `PredicateMatcher`
+
+Currently, the `PredicateMatcher` uses `std::function` for type erasure,
+so that type of the matcher is always `PredicateMatcher<T>`, regardless
+of the type of the predicate. Because of the high compilation overhead
+of `std::function`, and the fact that the type erasure is used only rarely,
+`PredicateMatcher` will no longer be type erased in the future. Instead,
+the predicate type will be made part of the PredicateMatcher's type.
+
+
---
[Home](Readme.md#top)
diff --git a/docs/generators.md b/docs/generators.md
index 57fdf44b..55ff0ba5 100644
--- a/docs/generators.md
+++ b/docs/generators.md
@@ -1,6 +1,8 @@
<a id="top"></a>
# Data Generators
+> Introduced in Catch 2.6.0.
+
Data generators (also known as _data driven/parametrized test cases_)
let you reuse the same set of assertions across different input values.
In Catch2, this means that they respect the ordering and nesting
@@ -34,8 +36,8 @@ Catch2's provided generator functionality consists of three parts,
* `GENERATE` macro, that serves to integrate generator expression with
a test case,
* 2 fundamental generators
- * `ValueGenerator<T>` -- contains only single element
- * `ValuesGenerator<T>` -- contains multiple elements
+ * `SingleValueGenerator<T>` -- contains only single element
+ * `FixedValuesGenerator<T>` -- contains multiple elements
* 5 generic generators that modify other generators
* `FilterGenerator<T, Predicate>` -- filters out elements from a generator
for which the predicate returns "false"
@@ -44,16 +46,22 @@ a test case,
* `MapGenerator<T, U, Func>` -- returns the result of applying `Func`
on elements from a different generator
* `ChunkGenerator<T>` -- returns chunks (inside `std::vector`) of n elements from a generator
-* 3 specific purpose generators
+* 4 specific purpose generators
* `RandomIntegerGenerator<Integral>` -- generates random Integrals from range
* `RandomFloatGenerator<Float>` -- generates random Floats from range
- * `RangeGenerator<T>` -- generates all values inside a specific range
+ * `RangeGenerator<T>` -- generates all values inside an arithmetic range
+ * `IteratorGenerator<T>` -- copies and returns values from an iterator range
+
+> `ChunkGenerator<T>`, `RandomIntegerGenerator<Integral>`, `RandomFloatGenerator<Float>` and `RangeGenerator<T>` were introduced in Catch 2.7.0.
+
+> `IteratorGenerator<T>` was introduced in Catch 2.10.0.
The generators also have associated helper functions that infer their
type, making their usage much nicer. These are
-* `value(T&&)` for `ValueGenerator<T>`
-* `values(std::initializer_list<T>)` for `ValuesGenerator<T>`
+* `value(T&&)` for `SingleValueGenerator<T>`
+* `values(std::initializer_list<T>)` for `FixedValuesGenerator<T>`
+* `table<Ts...>(std::initializer_list<std::tuple<Ts...>>)` for `FixedValuesGenerator<std::tuple<Ts...>>`
* `filter(predicate, GeneratorWrapper<T>&&)` for `FilterGenerator<T, Predicate>`
* `take(count, GeneratorWrapper<T>&&)` for `TakeGenerator<T>`
* `repeat(repeats, GeneratorWrapper<T>&&)` for `RepeatGenerator<T>`
@@ -61,9 +69,16 @@ type, making their usage much nicer. These are
* `map<T>(func, GeneratorWrapper<U>&&)` for `MapGenerator<T, U, Func>` (map `U` to `T`)
* `chunk(chunk-size, GeneratorWrapper<T>&&)` for `ChunkGenerator<T>`
* `random(IntegerOrFloat a, IntegerOrFloat b)` for `RandomIntegerGenerator` or `RandomFloatGenerator`
-* `range(start, end)` for `RangeGenerator<T>` with a step size of `1`
-* `range(start, end, step)` for `RangeGenerator<T>` with a custom step size
+* `range(Arithemtic start, Arithmetic end)` for `RangeGenerator<Arithmetic>` with a step size of `1`
+* `range(Arithmetic start, Arithmetic end, Arithmetic step)` for `RangeGenerator<Arithmetic>` with a custom step size
+* `from_range(InputIterator from, InputIterator to)` for `IteratorGenerator<T>`
+* `from_range(Container const&)` for `IteratorGenerator<T>`
+> `chunk()`, `random()` and both `range()` functions were introduced in Catch 2.7.0.
+
+> `from_range` has been introduced in Catch 2.10.0
+
+> `range()` for floating point numbers has been introduced in Catch 2.11.0
And can be used as shown in the example below to create a generator
that returns 100 odd random number:
@@ -84,7 +99,7 @@ Apart from registering generators with Catch2, the `GENERATE` macro has
one more purpose, and that is to provide simple way of generating trivial
generators, as seen in the first example on this page, where we used it
as `auto i = GENERATE(1, 2, 3);`. This usage converted each of the three
-literals into a single `ValueGenerator<int>` and then placed them all in
+literals into a single `SingleValueGenerator<int>` and then placed them all in
a special generator that concatenates other generators. It can also be
used with other generators as arguments, such as `auto i = GENERATE(0, 2,
take(100, random(300, 3000)));`. This is useful e.g. if you know that
@@ -96,6 +111,8 @@ scope and thus capturing references is dangerous. If you need to use
variables inside the generator expression, make sure you thought through
the lifetime implications and use `GENERATE_COPY` or `GENERATE_REF`.**
+> `GENERATE_COPY` and `GENERATE_REF` were introduced in Catch 2.7.1.
+
You can also override the inferred type by using `as<type>` as the first
argument to the macro. This can be useful when dealing with string literals,
if you want them to come out as `std::string`:
diff --git a/docs/limitations.md b/docs/limitations.md
index b95cd87f..65483b87 100644
--- a/docs/limitations.md
+++ b/docs/limitations.md
@@ -45,6 +45,15 @@ the `REQUIRE` family of macros), Catch2 does not know that there are no
more sections in that test case and must run the test case again.
+### MinGW/CygWin compilation (linking) is extremely slow
+
+Compiling Catch2 with MinGW can be exceedingly slow, especially during
+the linking step. As far as we can tell, this is caused by deficiencies
+in its default linker. If you can tell MinGW to instead use lld, via
+`-fuse-ld=lld`, the link time should drop down to reasonable length
+again.
+
+
## Features
This section outlines some missing features, what is their status and their possible workarounds.
diff --git a/docs/logging.md b/docs/logging.md
index 7b5c6c4b..476b1e08 100644
--- a/docs/logging.md
+++ b/docs/logging.md
@@ -30,6 +30,8 @@ When the last `CHECK` fails in the "Bar" test case, then only one message will b
## Logging without local scope
+> [Introduced](https://github.com/catchorg/Catch2/issues/1522) in Catch 2.7.0.
+
`UNSCOPED_INFO` is similar to `INFO` with two key differences:
- Lifetime of an unscoped message is not tied to its own scope.
@@ -104,6 +106,8 @@ This semicolon will be removed with next major version. It is highly advised to
**UNSCOPED_INFO(** _message expression_ **)**
+> [Introduced](https://github.com/catchorg/Catch2/issues/1522) in Catch 2.7.0.
+
Similar to `INFO`, but messages are not limited to their own scope: They are removed from the buffer after each assertion, section or test case, whichever comes first.
**WARN(** _message expression_ **)**
diff --git a/docs/matchers.md b/docs/matchers.md
index 13c7d0c8..bdb7dac4 100644
--- a/docs/matchers.md
+++ b/docs/matchers.md
@@ -12,31 +12,57 @@ The first argument is the thing (object or value) under test. The second part is
which consists of either a single matcher or one or more matchers combined using `&&`, `||` or `!` operators.
For example, to assert that a string ends with a certain substring:
-
+
```c++
using Catch::Matchers::EndsWith; // or Catch::EndsWith
std::string str = getStringFromSomewhere();
-REQUIRE_THAT( str, EndsWith( "as a service" ) );
- ```
+REQUIRE_THAT( str, EndsWith( "as a service" ) );
+```
The matcher objects can take multiple arguments, allowing more fine tuning.
The built-in string matchers, for example, take a second argument specifying whether the comparison is
case sensitive or not:
```c++
-REQUIRE_THAT( str, EndsWith( "as a service", Catch::CaseSensitive::No ) );
+REQUIRE_THAT( str, EndsWith( "as a service", Catch::CaseSensitive::No ) );
```
And matchers can be combined:
```c++
-REQUIRE_THAT( str,
- EndsWith( "as a service" ) ||
- (StartsWith( "Big data" ) && !Contains( "web scale" ) ) );
+REQUIRE_THAT( str,
+ EndsWith( "as a service" ) ||
+ (StartsWith( "Big data" ) && !Contains( "web scale" ) ) );
```
+_The combining operators do not take ownership of the matcher objects.
+This means that if you store the combined object, you have to ensure that
+the matcher objects outlive its last use. What this means is that code
+like this leads to a use-after-free and (hopefully) a crash:_
+
+```cpp
+TEST_CASE("Bugs, bugs, bugs", "[Bug]"){
+ std::string str = "Bugs as a service";
+
+ auto match_expression = Catch::EndsWith( "as a service" ) ||
+ (Catch::StartsWith( "Big data" ) && !Catch::Contains( "web scale" ) );
+ REQUIRE_THAT(str, match_expression);
+}
+```
+
+
## Built in matchers
-Catch currently provides some matchers, they are in the `Catch::Matchers` and `Catch` namespaces.
+Catch2 provides some matchers by default. They can be found in the
+`Catch::Matchers::foo` namespace and are imported into the `Catch`
+namespace as well.
+
+There are two parts to each of the built-in matchers, the matcher
+type itself and a helper function that provides template argument
+deduction when creating templated matchers. As an example, the matcher
+for checking that two instances of `std::vector` are identical is
+`EqualsMatcher<T>`, but the user is expected to use the `Equals`
+helper function instead.
+
### String matchers
The string matchers are `StartsWith`, `EndsWith`, `Contains`, `Equals` and `Matches`. The first four match a literal (sub)string against a result, while `Matches` takes and matches an ECMAScript regex. Do note that `Matches` matches the string as a whole, meaning that "abc" will not match against "abcd", but "abc.*" will.
@@ -45,13 +71,42 @@ Each of the provided `std::string` matchers also takes an optional second argume
### Vector matchers
-The vector matchers are `Contains`, `VectorContains` and `Equals`. `VectorContains` looks for a single element in the matched vector, `Contains` looks for a set (vector) of elements inside the matched vector.
+Catch2 currently provides 5 built-in matchers that work on `std::vector`.
+These are
-### Floating point matchers
-The floating point matchers are `WithinULP` and `WithinAbs`. `WithinAbs` accepts floating point numbers that are within a certain margin of target. `WithinULP` performs an [ULP](https://en.wikipedia.org/wiki/Unit_in_the_last_place)-based comparison of two floating point numbers and accepts them if they are less than certain number of ULPs apart.
+ * `Contains` which checks whether a specified vector is present in the result
+ * `VectorContains` which checks whether a specified element is present in the result
+ * `Equals` which checks whether the result is exactly equal (order matters) to a specific vector
+ * `UnorderedEquals` which checks whether the result is equal to a specific vector under a permutation
+ * `Approx` which checks whether the result is "approx-equal" (order matters, but comparison is done via `Approx`) to a specific vector
+> Approx matcher was [introduced](https://github.com/catchorg/Catch2/issues/1499) in Catch 2.7.2.
-Do note that ULP-based checks only make sense when both compared numbers are of the same type and `WithinULP` will use type of its argument as the target type. This means that `WithinULP(1.f, 1)` will expect to compare `float`s, but `WithinULP(1., 1)` will expect to compare `double`s.
+### Floating point matchers
+Catch2 provides 3 matchers for working with floating point numbers. These
+are `WithinAbsMatcher`, `WithinUlpsMatcher` and `WithinRelMatcher`.
+
+The `WithinAbsMatcher` matcher accepts floating point numbers that are
+within a certain distance of target. It should be constructed with the
+`WithinAbs(double target, double margin)` helper.
+
+The `WithinUlpsMatcher` matcher accepts floating point numbers that are
+within a certain number of [ULPs](https://en.wikipedia.org/wiki/Unit_in_the_last_place)
+of the target. Because ULP comparisons need to be done differently for
+`float`s and for `double`s, there are two overloads of the helpers for
+this matcher, `WithinULP(float target, int64_t ULPs)`, and
+`WithinULP(double target, int64_t ULPs)`.
+
+The `WithinRelMatcher` matcher accepts floating point numbers that are
+_approximately equal_ with the target number with some specific tolerance.
+In other words, it checks that `|lhs - rhs| <= epsilon * max(|lhs|, |rhs|)`,
+with special casing for `INFINITY` and `NaN`. There are _4_ overloads of
+the helpers for this matcher, `WithinRel(double target, double margin)`,
+`WithinRel(float target, float margin)`, `WithinRel(double target)`, and
+`WithinRel(float target)`. The latter two provide a default epsilon of
+machine epsilon * 100.
+
+> `WithinRel` matcher was introduced in Catch 2.10.0
### Generic matchers
Catch also aims to provide a set of generic matchers. Currently this set
@@ -72,13 +127,29 @@ The second argument is an optional description of the predicate, and is
used only during reporting of the result.
+### Exception matchers
+Catch2 also provides an exception matcher that can be used to verify
+that an exception's message exactly matches desired string. The matcher
+is `ExceptionMessageMatcher`, and we also provide a helper function
+`Message`.
+
+The matched exception must publicly derive from `std::exception` and
+the message matching is done _exactly_, including case.
+
+> `ExceptionMessageMatcher` was introduced in Catch 2.10.0
+
+Example use:
+```cpp
+REQUIRE_THROWS_MATCHES(throwsDerivedException(), DerivedException, Message("DerivedException::what"));
+```
+
## Custom matchers
It's easy to provide your own matchers to extend Catch or just to work with your own types.
-You need to provide two things:
+You need to provide two things:
1. A matcher class, derived from `Catch::MatcherBase<T>` - where `T` is the type being tested.
The constructor takes and stores any arguments needed (e.g. something to compare against) and you must
-override two methods: `match()` and `describe()`.
+override two methods: `match()` and `describe()`.
2. A simple builder function. This is what is actually called from the test code and allows overloading.
Here's an example for asserting that an integer falls within a given range
@@ -123,7 +194,7 @@ TEST_CASE("Integers are within a range")
```
Running this test gives the following in the console:
-
+
```
/**/TestFile.cpp:123: FAILED:
CHECK_THAT( 100, IsBetween( 1, 10 ) )
diff --git a/docs/opensource-users.md b/docs/opensource-users.md
index 489bbdcc..36c0db64 100644
--- a/docs/opensource-users.md
+++ b/docs/opensource-users.md
@@ -23,6 +23,9 @@ C++11 implementation of Approval Tests, for quick, convenient testing of legacy
### [Azmq](https://github.com/zeromq/azmq)
Boost Asio style bindings for ZeroMQ.
+### [Cataclysm: Dark Days Ahead](https://github.com/CleverRaven/Cataclysm-DDA)
+Post-apocalyptic survival RPG.
+
### [ChakraCore](https://github.com/Microsoft/ChakraCore)
The core part of the Chakra JavaScript engine that powers Microsoft Edge.
@@ -50,9 +53,6 @@ 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++.
-### [JSON for Modern C++](https://github.com/nlohmann/json)
-A, single-header, JSON parsing library that takes advantage of what C++ has to offer.
-
### [libcluon](https://github.com/chrberger/libcluon)
A single-header-only library written in C++14 to glue distributed software components (UDP, TCP, shared memory) supporting natively Protobuf, LCM/ZCM, MsgPack, and JSON for dynamic message transformations in-between.
@@ -112,6 +112,9 @@ SpECTRE is a code for multi-scale, multi-physics problems in astrophysics and gr
### [Standardese](https://github.com/foonathan/standardese)
Standardese aims to be a nextgen Doxygen.
+### [PopHead](https://github.com/SPC-Some-Polish-Coders/PopHead)
+A 2D, Zombie, RPG game which is being made on our own engine.
+
---
[Home](Readme.md#top)
diff --git a/docs/other-macros.md b/docs/other-macros.md
index 345234d5..994115f1 100644
--- a/docs/other-macros.md
+++ b/docs/other-macros.md
@@ -59,6 +59,8 @@ TEST_CASE( "SUCCEED showcase" ) {
* `STATIC_REQUIRE`
+> [Introduced](https://github.com/catchorg/Catch2/issues/1362) in Catch 2.4.2.
+
`STATIC_REQUIRE( expr )` is a macro that can be used the same way as a
`static_assert`, but also registers the success with Catch2, so it is
reported as a success at runtime. The whole check can also be deferred
@@ -132,6 +134,8 @@ ANON_TEST_CASE() {
* `DYNAMIC_SECTION`
+> Introduced in Catch 2.3.0.
+
`DYNAMIC_SECTION` is a `SECTION` where the user can use `operator<<` to
create the final name for that section. This can be useful with e.g.
generators, or when creating a `SECTION` dynamically, within a loop.
diff --git a/docs/release-notes.md b/docs/release-notes.md
index c5f92d2b..0c023085 100644
--- a/docs/release-notes.md
+++ b/docs/release-notes.md
@@ -2,6 +2,16 @@
# Release notes
**Contents**<br>
+[2.11.2](#2112)<br>
+[2.11.1](#2111)<br>
+[2.11.0](#2110)<br>
+[2.10.2](#2102)<br>
+[2.10.1](#2101)<br>
+[2.10.0](#2100)<br>
+[2.9.2](#292)<br>
+[2.9.1](#291)<br>
+[2.9.0](#290)<br>
+[2.8.0](#280)<br>
[2.7.2](#272)<br>
[2.7.1](#271)<br>
[2.7.0](#270)<br>
@@ -24,6 +34,209 @@
[Even Older versions](#even-older-versions)<br>
+## 2.11.2
+
+### Improvements
+* GCC and Clang now issue warnings for suspicious code in assertions (#1880)
+ * E.g. `REQUIRE( int != unsigned int )` will now issue mixed signedness comparison warning
+ * This has always worked on MSVC, but it now also works for GCC and current Clang versions
+* Colorization of "Test filters" output should be more robust now
+* `--wait-for-keypress` now also accepts `never` as an option (#1866)
+* Reporters no longer round-off nanoseconds when reporting benchmarking results (#1876)
+* Catch2's debug break now supports iOS while using Thumb instruction set (#1862)
+* It is now possible to customize benchmark's warm-up time when running the test binary (#1844)
+ * `--benchmark-warmup-time {ms}`
+* User can now specify how Catch2 should break into debugger (#1846)
+
+### Fixes
+* Fixes missing `<random>` include in benchmarking (#1831)
+* Fixed missing `<iterator>` include in benchmarking (#1874)
+* Hidden test cases are now also tagged with `[!hide]` as per documentation (#1847)
+* Detection of whether libc provides `std::nextafter` has been improved (#1854)
+* Detection of `wmain` no longer incorrectly looks for `WIN32` macro (#1849)
+ * Now it just detects Windows platform
+* Composing already-composed matchers no longer modifies the partially-composed matcher expression
+ * This bug has been present for the last ~2 years and nobody reported it
+
+
+## 2.11.1
+
+### Improvements
+* Breaking into debugger is supported on iOS (#1817)
+* `google-build-using-namespace` clang-tidy warning is suppressed (#1799)
+
+### Fixes
+* Clang on Windows is no longer assumed to implement MSVC's traditional preprocessor (#1806)
+* `ObjectStorage` now behaves properly in `const` contexts (#1820)
+* `GENERATE_COPY(a, b)` now compiles properly (#1809, #1815)
+* Some more cleanups in the benchmarking support
+
+
+## 2.11.0
+
+### Improvements
+* JUnit reporter output now contains more details in case of failure (#1347, #1719)
+* Added SonarQube Test Data reporter (#1738)
+ * It is in a separate header, just like the TAP, Automake, and TeamCity reporters
+* `range` generator now allows floating point numbers (#1776)
+* Reworked part of internals to increase throughput
+
+
+### Fixes
+* The single header version should contain full benchmarking support (#1800)
+* `[.foo]` is now properly parsed as `[.][foo]` when used on the command line (#1798)
+* Fixed compilation of benchmarking on platforms where `steady_clock::period` is not `std::nano` (#1794)
+
+
+
+## 2.10.2
+
+### Improvements
+* Catch2 will now compile on platform where `INFINITY` is double (#1782)
+
+
+### Fixes
+* Warning suppressed during listener registration will no longer leak
+
+
+
+## 2.10.1
+
+### Improvements
+* Catch2 now guards itself against `min` and `max` macros from `windows.h` (#1772)
+* Templated tests will now compile with ICC (#1748)
+* `WithinULP` matcher now uses scientific notation for stringification (#1760)
+
+
+### Fixes
+* Templated tests no longer trigger `-Wunused-templates` (#1762)
+* Suppressed clang-analyzer false positive in context getter (#1230, #1735)
+
+
+### Miscellaneous
+* CMake no longer prohibits in-tree build when Catch2 is used as a subproject (#1773, #1774)
+
+
+
+## 2.10.0
+
+### Fixes
+* `TEMPLATE_LIST_TEST_CASE` now properly handles non-copyable and non-movable types (#1729)
+* Fixed compilation error on Solaris caused by a system header defining macro `TT` (#1722, #1723)
+* `REGISTER_ENUM` will now fail at compilation time if the registered enum is too large
+* Removed use of `std::is_same_v` in C++17 mode (#1757)
+* Fixed parsing of escaped special characters when reading test specs from a file (#1767, #1769)
+
+
+### Improvements
+* Trailing and leading whitespace in test/section specs are now ignored.
+* Writing to Android debug log now uses `__android_log_write` instead of `__android_log_print`
+* Android logging support can now be turned on/off at compile time (#1743)
+ * The toggle is `CATCH_CONFIG_ANDROID_LOGWRITE`
+* Added a generator that returns elements of a range
+ * Use via `from_range(from, to)` or `from_range(container)`
+* Added support for CRTs that do not provide `std::nextafter` (#1739)
+ * They must still provide global `nextafter{f,l,}`
+ * Enabled via `CATCH_CONFIG_GLOBAL_NEXTAFTER`
+* Special cased `Approx(inf)` not to match non-infinite values
+ * Very strictly speaking this might be a breaking change, but it should match user expectations better
+* The output of benchmarking through the Console reporter when `--benchmark-no-analysis` is set is now much simpler (#1768)
+* Added a matcher that can be used for checking an exceptions message (#1649, #1728)
+ * The matcher helper function is called `Message`
+ * The exception must publicly derive from `std::exception`
+ * The matching is done exactly, including case and whitespace
+* Added a matcher that can be used for checking relative equality of floating point numbers (#1746)
+ * Unlike `Approx`, it considers both sides when determining the allowed margin
+ * Special cases `NaN` and `INFINITY` to match user expectations
+ * The matcher helper function is called `WithinRel`
+* The ULP matcher now allows for any possible distance between the two numbers
+* The random number generators now use Catch-global instance of RNG (#1734, #1736)
+ * This means that nested random number generators actually generate different numbers
+
+
+### Miscellaneous
+* In-repo PNGs have been optimized to lower overhead of using Catch2 via git clone
+* Catch2 now uses its own implementation of the URBG concept
+ * In the future we also plan to use our own implementation of the distributions from `<random>` to provide cross-platform repeatability of random results
+
+
+
+## 2.9.2
+
+### Fixes
+* `ChunkGenerator` can now be used with chunks of size 0 (#1671)
+* Nested subsections are now run properly when specific section is run via the `-c` argument (#1670, #1673)
+* Catch2 now consistently uses `_WIN32` to detect Windows platform (#1676)
+* `TEMPLATE_LIST_TEST_CASE` now support non-default constructible type lists (#1697)
+* Fixed a crash in the XMLReporter when a benchmark throws exception during warmup (#1706)
+* Fixed a possible infinite loop in CompactReporter (#1715)
+* Fixed `-w NoTests` returning 0 even when no tests were matched (#1449, #1683, #1684)
+* Fixed matcher compilation under Obj-C++ (#1661)
+
+### Improvements
+* `RepeatGenerator` and `FixedValuesGenerator` now fail to compile when used with `bool` (#1692)
+ * Previously they would fail at runtime.
+* Catch2 now supports Android's debug logging for its debug output (#1710)
+* Catch2 now detects and configures itself for the RTX platform (#1693)
+ * You still need to pass `--benchmark-no-analysis` if you are using benchmarking under RTX
+* Removed a "storage class is not first" warning when compiling Catch2 with PGI compiler (#1717)
+
+### Miscellaneous
+* Documentation now contains indication when a specific feature was introduced (#1695)
+ * These start with Catch2 v2.3.0, (a bit over a year ago).
+ * `docs/contributing.md` has been updated to provide contributors guidance on how to add these to newly written documentation
+* Various other documentation improvements
+ * ToC fixes
+ * Documented `--order` and `--rng-seed` command line options
+ * Benchmarking documentation now clearly states that it requires opt-in
+ * Documented `CATCH_CONFIG_CPP17_OPTIONAL` and `CATCH_CONFIG_CPP17_BYTE` macros
+ * Properly documented built-in vector matchers
+ * Improved `*_THROWS_MATCHES` documentation a bit
+* CMake config file is now arch-independent even if `CMAKE_SIZEOF_VOID_P` is in CMake cache (#1660)
+* `CatchAddTests` now properly escapes `[` and `]` in test names (#1634, #1698)
+* Reverted `CatchAddTests` adding tags as CTest labels (#1658)
+ * The script broke when test names were too long
+ * Overwriting `LABELS` caused trouble for users who set them manually
+ * CMake does not let users append to `LABELS` if the test name has spaces
+
+
+## 2.9.1
+
+### Fixes
+* Fix benchmarking compilation failure in files without `CATCH_CONFIG_EXTERNAL_INTERFACES` (or implementation)
+
+## 2.9.0
+
+### Improvements
+* The experimental benchmarking support has been replaced by integrating Nonius code (#1616)
+ * This provides a much more featurefull micro-benchmarking support.
+ * Due to the compilation cost, it is disabled by default. See the documentation for details.
+ * As far as backwards compatibility is concerned, this feature is still considered experimental in that we might change the interface based on user feedback.
+* `WithinULP` matcher now shows the acceptable range (#1581)
+* Template test cases now support type lists (#1627)
+
+
+## 2.8.0
+
+### Improvements
+* Templated test cases no longer check whether the provided types are unique (#1628)
+ * This allows you to e.g. test over `uint32_t`, `uint64_t`, and `size_t` without compilation failing
+* The precision of floating point stringification can be modified by user (#1612, #1614)
+* We now provide `REGISTER_ENUM` convenience macro for generating `StringMaker` specializations for enums
+ * See the "String conversion" documentation for details
+* Added new set of macros for template test cases that enables the use of NTTPs (#1531, #1609)
+ * See "Test cases and sections" documentation for details
+
+### Fixes
+* `UNSCOPED_INFO` macro now has a prefixed/disabled/prefixed+disabled versions (#1611)
+* Reporting errors at startup should no longer cause a segfault under certain circumstances (#1626)
+
+
+### Miscellaneous
+* CMake will now prevent you from attempting in-tree build (#1636, #1638)
+ * Previously it would break with an obscure error message during the build step
+
+
## 2.7.2
### Improvements
@@ -49,7 +262,7 @@
### Improvements
* Reporters now print out the filters applied to test cases (#1550, #1585)
-* Added `GENERATE_COPY` and `GENERATE_VAR` macros that can use variables inside the generator expression
+* Added `GENERATE_COPY` and `GENERATE_REF` macros that can use variables inside the generator expression
* Because of the significant danger of lifetime issues, the default `GENERATE` macro still does not allow variables
* The `map` generator helper now deduces the mapped return type (#1576)
diff --git a/docs/release-process.md b/docs/release-process.md
index 7fa5f7e1..130a8922 100644
--- a/docs/release-process.md
+++ b/docs/release-process.md
@@ -42,8 +42,8 @@ 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 might be
+it should use linux line endings. All non-bundled reporters (Automake, TAP,
+TeamCity, SonarQube) should also be attached as binaries, as they might be
dependent on a specific version of the single-include header.
Since 2.5.0, the release tag and the "binaries" (headers) should be PGP
@@ -67,6 +67,7 @@ $ gpg2 --armor --output catch.hpp.asc --detach-sig catch.hpp
$ gpg2 --armor --output catch_reporter_automake.hpp.asc --detach-sig catch_reporter_automake.hpp
$ gpg2 --armor --output catch_reporter_teamcity.hpp.asc --detach-sig catch_reporter_teamcity.hpp
$ gpg2 --armor --output catch_reporter_tap.hpp.asc --detach-sig catch_reporter_tap.hpp
+$ gpg2 --armor --output catch_reporter_sonarqube.hpp.asc --detach-sig catch_reporter_sonarqube.hpp
```
_GPG does not support signing multiple files in single invocation._
diff --git a/docs/reporters.md b/docs/reporters.md
index 32b3419b..a33e55bf 100644
--- a/docs/reporters.md
+++ b/docs/reporters.md
@@ -29,6 +29,7 @@ Do this in one source file - the same one you have `CATCH_CONFIG_MAIN` or `CATCH
Use this when building as part of a TeamCity build to see results as they happen ([code example](../examples/207-Rpt-TeamCityReporter.cpp)).
* `tap` writes in the TAP ([Test Anything Protocol](https://en.wikipedia.org/wiki/Test_Anything_Protocol)) format.
* `automake` writes in a format that correspond to [automake .trs](https://www.gnu.org/software/automake/manual/html_node/Log-files-generation-and-test-results-recording.html) files
+* `sonarqube` writes the [SonarQube Generic Test Data](https://docs.sonarqube.org/latest/analysis/generic-test/) XML format.
You see what reporters are available from the command line by running with `--list-reporters`.
diff --git a/docs/slow-compiles.md b/docs/slow-compiles.md
index 0853b661..230f5330 100644
--- a/docs/slow-compiles.md
+++ b/docs/slow-compiles.md
@@ -22,7 +22,7 @@ But functions and methods can also be written inline in header files. The downsi
Because Catch is implemented *entirely* in headers you might think that the whole of Catch must be compiled into every translation unit that uses it! Actually it's not quite as bad as that. Catch mitigates this situation by effectively maintaining the traditional separation between the implementation code and declarations. Internally the implementation code is protected by ```#ifdef```s and is conditionally compiled into only one translation unit. This translation unit is that one that ```#define```s ```CATCH_CONFIG_MAIN``` or ```CATCH_CONFIG_RUNNER```. Let's call this the main source file.
-As a result the main source file *does* compile the whole of Catch every time! So it makes sense to dedicate this file to *only* ```#define```-ing the identifier and ```#include```-ing Catch (and implementing the runner code, if you're doing that). Keep all your test cases in other files. This way you won't pay the recompilation cost for the whole of Catch
+As a result the main source file *does* compile the whole of Catch every time! So it makes sense to dedicate this file to *only* ```#define```-ing the identifier and ```#include```-ing Catch (and implementing the runner code, if you're doing that). Keep all your test cases in other files. This way you won't pay the recompilation cost for the whole of Catch.
## Practical example
Assume you have the `Factorial` function from the [tutorial](tutorial.md#top) in `factorial.cpp` (with forward declaration in `factorial.h`) and want to test it and keep the compile times down when adding new tests. Then you should have 2 files, `tests-main.cpp` and `tests-factorial.cpp`:
@@ -51,14 +51,15 @@ After compiling `tests-main.cpp` once, it is enough to link it with separately c
```
$ g++ tests-main.cpp -c
-$ g++ tests-main.o tests-factorial.cpp -o tests && ./tests -r compact
+$ g++ factorial.cpp -c
+$ g++ tests-main.o factorial.o tests-factorial.cpp -o tests && ./tests -r compact
Passed 1 test case with 4 assertions.
```
Now, the next time we change the file `tests-factorial.cpp` (say we add `REQUIRE( Factorial(0) == 1)`), it is enough to recompile the tests instead of recompiling main as well:
```
-$ g++ tests-main.o tests-factorial.cpp -o tests && ./tests -r compact
+$ g++ tests-main.o factorial.o tests-factorial.cpp -o tests && ./tests -r compact
tests-factorial.cpp:11: failed: Factorial(0) == 1 for: 0 == 1
Failed 1 test case, failed 1 assertion.
```
diff --git a/docs/test-cases-and-sections.md b/docs/test-cases-and-sections.md
index 62a805f4..53f9e150 100644
--- a/docs/test-cases-and-sections.md
+++ b/docs/test-cases-and-sections.md
@@ -6,6 +6,7 @@
[Tag aliases](#tag-aliases)<br>
[BDD-style test cases](#bdd-style-test-cases)<br>
[Type parametrised test cases](#type-parametrised-test-cases)<br>
+[Signature based parametrised test cases](#signature-based-parametrised-test-cases)<br>
While Catch fully supports the traditional, xUnit, style of class-based fixtures containing test case methods this is not the preferred style.
@@ -83,10 +84,13 @@ This macro maps onto ```TEST_CASE``` and works in the same way, except that the
These macros map onto ```SECTION```s except that the section names are the _something_s prefixed by "given: ", "when: " or "then: " respectively.
+* **AND_GIVEN(** _something_ **)**
* **AND_WHEN(** _something_ **)**
* **AND_THEN(** _something_ **)**
-Similar to ```WHEN``` and ```THEN``` except that the prefixes start with "and ". These are used to chain ```WHEN```s and ```THEN```s together.
+Similar to ```GIVEN```, ```WHEN``` and ```THEN``` except that the prefixes start with "and ". These are used to chain ```GIVEN```s, ```WHEN```s and ```THEN```s together.
+
+> `AND_GIVEN` was [introduced](https://github.com/catchorg/Catch2/issues/1360) in Catch 2.4.0.
When any of these macros are used the console reporter recognises them and formats the test case header such that the Givens, Whens and Thens are aligned to aid readability.
@@ -95,11 +99,13 @@ Other than the additional prefixes and the formatting in the console reporter th
## Type parametrised test cases
In addition to `TEST_CASE`s, Catch2 also supports test cases parametrised
-by types, in the form of `TEMPLATE_TEST_CASE` and
-`TEMPLATE_PRODUCT_TEST_CASE`.
+by types, in the form of `TEMPLATE_TEST_CASE`,
+`TEMPLATE_PRODUCT_TEST_CASE` and `TEMPLATE_LIST_TEST_CASE`.
* **TEMPLATE_TEST_CASE(** _test name_ , _tags_, _type1_, _type2_, ..., _typen_ **)**
+> [Introduced](https://github.com/catchorg/Catch2/issues/1437) in Catch 2.5.0.
+
_test name_ and _tag_ are exactly the same as they are in `TEST_CASE`,
with the difference that the tag string must be provided (however, it
can be empty). _type1_ through _typen_ is the list of types for which
@@ -150,6 +156,8 @@ TEMPLATE_TEST_CASE( "vectors can be sized and resized", "[vector][template]", in
* **TEMPLATE_PRODUCT_TEST_CASE(** _test name_ , _tags_, (_template-type1_, _template-type2_, ..., _template-typen_), (_template-arg1_, _template-arg2_, ..., _template-argm_) **)**
+> [Introduced](https://github.com/catchorg/Catch2/issues/1468) in Catch 2.6.0.
+
_template-type1_ through _template-typen_ is list of template template
types which should be combined with each of _template-arg1_ through
_template-argm_, resulting in _n * m_ test cases. Inside the test case,
@@ -191,6 +199,77 @@ _While there is an upper limit on the number of types you can specify
in single `TEMPLATE_TEST_CASE` or `TEMPLATE_PRODUCT_TEST_CASE`, the limit
is very high and should not be encountered in practice._
+* **TEMPLATE_LIST_TEST_CASE(** _test name_, _tags_, _type list_ **)**
+
+> [Introduced](https://github.com/catchorg/Catch2/issues/1627) in Catch 2.9.0.
+
+_type list_ is a generic list of types on which test case should be instantiated.
+List can be `std::tuple`, `boost::mpl::list`, `boost::mp11::mp_list` or anything with
+`template <typename...>` signature.
+
+This allows you to reuse the _type list_ in multiple test cases.
+
+Example:
+```cpp
+using MyTypes = std::tuple<int, char, float>;
+TEMPLATE_LIST_TEST_CASE("Template test case with test types specified inside std::tuple", "[template][list]", MyTypes)
+{
+ REQUIRE(sizeof(TestType) > 0);
+}
+```
+
+
+## Signature based parametrised test cases
+
+> [Introduced](https://github.com/catchorg/Catch2/issues/1609) in Catch 2.8.0.
+
+In addition to [type parametrised test cases](#type-parametrised-test-cases) Catch2 also supports
+signature base parametrised test cases, in form of `TEMPLATE_TEST_CASE_SIG` and `TEMPLATE_PRODUCT_TEST_CASE_SIG`.
+These test cases have similar syntax like [type parametrised test cases](#type-parametrised-test-cases), with one
+additional positional argument which specifies the signature.
+
+### Signature
+Signature has some strict rules for these tests cases to work properly:
+* signature with multiple template parameters e.g. `typename T, size_t S` must have this format in test case declaration
+ `((typename T, size_t S), T, S)`
+* signature with variadic template arguments e.g. `typename T, size_t S, typename...Ts` must have this format in test case declaration
+ `((typename T, size_t S, typename...Ts), T, S, Ts...)`
+* signature with single non type template parameter e.g. `int V` must have this format in test case declaration `((int V), V)`
+* signature with single type template parameter e.g. `typename T` should not be used as it is in fact `TEMPLATE_TEST_CASE`
+
+Currently Catch2 support up to 11 template parameters in signature
+
+### Examples
+
+* **TEMPLATE_TEST_CASE_SIG(** _test name_ , _tags_, _signature_, _type1_, _type2_, ..., _typen_ **)**
+
+Inside `TEMPLATE_TEST_CASE_SIG` test case you can use the names of template parameters as defined in _signature_.
+
+```cpp
+TEMPLATE_TEST_CASE_SIG("TemplateTestSig: arrays can be created from NTTP arguments", "[vector][template][nttp]",
+ ((typename T, int V), T, V), (int,5), (float,4), (std::string,15), ((std::tuple<int, float>), 6)) {
+
+ std::array<T, V> v;
+ REQUIRE(v.size() > 1);
+}
+```
+
+* **TEMPLATE_PRODUCT_TEST_CASE_SIG(** _test name_ , _tags_, _signature_, (_template-type1_, _template-type2_, ..., _template-typen_), (_template-arg1_, _template-arg2_, ..., _template-argm_) **)**
+
+```cpp
+
+template<typename T, size_t S>
+struct Bar {
+ size_t size() { return S; }
+};
+
+TEMPLATE_PRODUCT_TEST_CASE_SIG("A Template product test case with array signature", "[template][product][nttp]", ((typename T, size_t S), T, S), (std::array, Bar), ((int, 9), (float, 42))) {
+ TestType x;
+ REQUIRE(x.size() > 0);
+}
+```
+
+
---
[Home](Readme.md#top)
diff --git a/docs/test-fixtures.md b/docs/test-fixtures.md
index 6b29ce68..832bba12 100644
--- a/docs/test-fixtures.md
+++ b/docs/test-fixtures.md
@@ -1,6 +1,8 @@
<a id="top"></a>
# Test fixtures
+## Defining test fixtures
+
Although Catch allows you to group tests together as sections within a test case, it can still be convenient, sometimes, to group them using a more traditional test fixture. Catch fully supports this too. You define the test fixture as a simple structure:
```c++
@@ -84,6 +86,58 @@ _While there is an upper limit on the number of types you can specify
in single `TEMPLATE_TEST_CASE_METHOD` or `TEMPLATE_PRODUCT_TEST_CASE_METHOD`,
the limit is very high and should not be encountered in practice._
+## Signature-based parametrised test fixtures
+
+> [Introduced](https://github.com/catchorg/Catch2/issues/1609) in Catch 2.8.0.
+
+Catch2 also provides `TEMPLATE_TEST_CASE_METHOD_SIG` and `TEMPLATE_PRODUCT_TEST_CASE_METHOD_SIG` to support
+fixtures using non-type template parameters. These test cases work similar to `TEMPLATE_TEST_CASE_METHOD` and `TEMPLATE_PRODUCT_TEST_CASE_METHOD`,
+with additional positional argument for [signature](test-cases-and-sections.md#signature-based-parametrised-test-cases).
+
+Example:
+```cpp
+template <int V>
+struct Nttp_Fixture{
+ int value = V;
+};
+
+TEMPLATE_TEST_CASE_METHOD_SIG(Nttp_Fixture, "A TEMPLATE_TEST_CASE_METHOD_SIG based test run that succeeds", "[class][template][nttp]",((int V), V), 1, 3, 6) {
+ REQUIRE(Nttp_Fixture<V>::value > 0);
+}
+
+template<typename T>
+struct Template_Fixture_2 {
+ Template_Fixture_2() {}
+
+ T m_a;
+};
+
+template< typename T, size_t V>
+struct Template_Foo_2 {
+ size_t size() { return V; }
+};
+
+TEMPLATE_PRODUCT_TEST_CASE_METHOD_SIG(Template_Fixture_2, "A TEMPLATE_PRODUCT_TEST_CASE_METHOD_SIG based test run that succeeds", "[class][template][product][nttp]", ((typename T, size_t S), T, S),(std::array, Template_Foo_2), ((int,2), (float,6)))
+{
+ REQUIRE(Template_Fixture_2<TestType>{}.m_a.size() >= 2);
+}
+```
+
+## Template fixtures with types specified in template type lists
+
+Catch2 also provides `TEMPLATE_LIST_TEST_CASE_METHOD` to support template fixtures with types specified in
+template type lists like `std::tuple`, `boost::mpl::list` or `boost::mp11::mp_list`. This test case works the same as `TEMPLATE_TEST_CASE_METHOD`,
+only difference is the source of types. This allows you to reuse the template type list in multiple test cases.
+
+Example:
+```cpp
+using MyTypes = std::tuple<int, char, double>;
+TEMPLATE_LIST_TEST_CASE_METHOD(Template_Fixture, "Template test case method with test types specified inside std::tuple", "[class][template][list]", MyTypes)
+{
+ REQUIRE( Template_Fixture<TestType>::m_a == 1 );
+}
+```
+
---
[Home](Readme.md#top)
diff --git a/docs/tostring.md b/docs/tostring.md
index 933f2e61..156c895a 100644
--- a/docs/tostring.md
+++ b/docs/tostring.md
@@ -6,6 +6,9 @@
[Catch::StringMaker specialisation](#catchstringmaker-specialisation)<br>
[Catch::is_range specialisation](#catchis_range-specialisation)<br>
[Exceptions](#exceptions)<br>
+[Enums](#enums)<br>
+[Floating point precision](#floating-point-precision)<br>
+
Catch needs to be able to convert types you use in assertions and logging expressions into strings (for logging and reporting purposes).
Most built-in or std types are supported out of the box but there are two ways that you can tell Catch how to convert your own types (or other, third-party types) into strings.
@@ -14,7 +17,7 @@ Most built-in or std types are supported out of the box but there are two ways t
This is the standard way of providing string conversions in C++ - and the chances are you may already provide this for your own purposes. If you're not familiar with this idiom it involves writing a free function of the form:
-```
+```cpp
std::ostream& operator << ( std::ostream& os, T const& value ) {
os << convertMyTypeToString( value );
return os;
@@ -28,7 +31,7 @@ You should put this function in the same namespace as your type, or the global n
## Catch::StringMaker specialisation
If you don't want to provide an ```operator <<``` overload, or you want to convert your type differently for testing purposes, you can provide a specialization for `Catch::StringMaker<T>`:
-```
+```cpp
namespace Catch {
template<>
struct StringMaker<T> {
@@ -60,12 +63,70 @@ namespace Catch {
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:
-```
+```cpp
CATCH_TRANSLATE_EXCEPTION( MyType& ex ) {
return ex.message();
}
```
+## Enums
+
+> Introduced in Catch 2.8.0.
+
+Enums that already have a `<<` overload for `std::ostream` will convert to strings as expected.
+If you only need to convert enums to strings for test reporting purposes you can provide a `StringMaker` specialisations as any other type.
+However, as a convenience, Catch provides the `REGISTER_ENUM` helper macro that will generate the `StringMaker` specialiation for you with minimal code.
+Simply provide it the (qualified) enum name, followed by all the enum values, and you're done!
+
+E.g.
+
+```cpp
+enum class Fruits { Banana, Apple, Mango };
+
+CATCH_REGISTER_ENUM( Fruits, Fruits::Banana, Fruits::Apple, Fruits::Mango )
+
+TEST_CASE() {
+ REQUIRE( Fruits::Mango == Fruits::Apple );
+}
+```
+
+... or if the enum is in a namespace:
+```cpp
+namespace Bikeshed {
+ enum class Colours { Red, Green, Blue };
+}
+
+// Important!: This macro must appear at top level scope - not inside a namespace
+// You can fully qualify the names, or use a using if you prefer
+CATCH_REGISTER_ENUM( Bikeshed::Colours,
+ Bikeshed::Colours::Red,
+ Bikeshed::Colours::Green,
+ Bikeshed::Colours::Blue )
+
+TEST_CASE() {
+ REQUIRE( Bikeshed::Colours::Red == Bikeshed::Colours::Blue );
+}
+```
+
+## Floating point precision
+
+> [Introduced](https://github.com/catchorg/Catch2/issues/1614) in Catch 2.8.0.
+
+Catch provides a built-in `StringMaker` specialization for both `float`
+and `double`. By default, it uses what we think is a reasonable precision,
+but you can customize it by modifying the `precision` static variable
+inside the `StringMaker` specialization, like so:
+
+```cpp
+ Catch::StringMaker<float>::precision = 15;
+ const float testFloat1 = 1.12345678901234567899f;
+ const float testFloat2 = 1.12345678991234567899f;
+ REQUIRE(testFloat1 == testFloat2);
+```
+
+This assertion will fail and print out the `testFloat1` and `testFloat2`
+to 15 decimal places.
+
---
[Home](Readme.md#top)
diff --git a/docs/tutorial.md b/docs/tutorial.md
index e45f967e..1f0b8ff2 100644
--- a/docs/tutorial.md
+++ b/docs/tutorial.md
@@ -106,7 +106,7 @@ Of course there are still more issues to deal with. For example we'll hit proble
Although this was a simple test it's been enough to demonstrate a few things about how Catch is used. Let's take a moment to consider those before we move on.
1. All we did was ```#define``` one identifier and ```#include``` one header and we got everything - even an implementation of ```main()``` that will [respond to command line arguments](command-line.md#top). You can only use that ```#define``` in one implementation file, for (hopefully) obvious reasons. Once you have more than one file with unit tests in you'll just ```#include "catch.hpp"``` and go. Usually it's a good idea to have a dedicated implementation file that just has ```#define CATCH_CONFIG_MAIN``` and ```#include "catch.hpp"```. You can also provide your own implementation of main and drive Catch yourself (see [Supplying-your-own-main()](own-main.md#top)).
-2. We introduce test cases with the ```TEST_CASE``` macro. This macro takes one or two arguments - a free form test name and, optionally, one or more tags (for more see <a href="#test-cases-and-sections">Test cases and Sections</a>, ). The test name must be unique. You can run sets of tests by specifying a wildcarded test name or a tag expression. See the [command line docs](command-line.md#top) for more information on running tests.
+2. We introduce test cases with the ```TEST_CASE``` macro. This macro takes one or two arguments - a free form test name and, optionally, one or more tags (for more see <a href="#test-cases-and-sections">Test cases and Sections</a>). The test name must be unique. You can run sets of tests by specifying a wildcarded test name or a tag expression. See the [command line docs](command-line.md#top) for more information on running tests.
3. The name and tags arguments are just strings. We haven't had to declare a function or method - or explicitly register the test case anywhere. Behind the scenes a function with a generated name is defined for you, and automatically registered using static registry classes. By abstracting the function name away we can name our tests without the constraints of identifier names.
4. We write our individual test assertions using the ```REQUIRE``` macro. Rather than a separate macro for each type of condition we express the condition naturally using C/C++ syntax. Behind the scenes a simple set of expression templates captures the left-hand-side and right-hand-side of the expression so we can display the values in our test report. As we'll see later there _are_ other assertion macros - but because of this technique the number of them is drastically reduced.
diff --git a/examples/210-Evt-EventListeners.cpp b/examples/210-Evt-EventListeners.cpp
index 2d5fdb28..044a29e3 100644
--- a/examples/210-Evt-EventListeners.cpp
+++ b/examples/210-Evt-EventListeners.cpp
@@ -24,7 +24,7 @@ std::string ws(int const level) {
template< typename T >
std::ostream& operator<<( std::ostream& os, std::vector<T> const& v ) {
os << "{ ";
- for ( auto x : v )
+ for ( const auto& x : v )
os << x << ", ";
return os << "}";
}
@@ -57,7 +57,7 @@ void print( std::ostream& os, int const level, Catch::MessageInfo const& info )
void print( std::ostream& os, int const level, std::string const& title, std::vector<Catch::MessageInfo> const& v ) {
os << ws(level ) << title << ":\n";
- for ( auto x : v )
+ for ( const auto& x : v )
{
os << ws(level+1) << "{\n";
print( os, level+2, x );
@@ -300,7 +300,7 @@ char const * dashed_line =
struct MyListener : Catch::TestEventListenerBase {
using TestEventListenerBase::TestEventListenerBase; // inherit constructor
-
+
// Get rid of Wweak-tables
~MyListener();
diff --git a/examples/231-Cfg-OutputStreams.cpp b/examples/231-Cfg-OutputStreams.cpp
index efa99971..8c65cc44 100644
--- a/examples/231-Cfg-OutputStreams.cpp
+++ b/examples/231-Cfg-OutputStreams.cpp
@@ -10,12 +10,13 @@
#define CATCH_CONFIG_MAIN
#include <catch2/catch.hpp>
+
class out_buff : public std::stringbuf {
std::FILE* m_stream;
public:
- out_buff(std::FILE* stream) :m_stream(stream) {}
- ~out_buff() { pubsync(); }
- int sync() {
+ out_buff(std::FILE* stream):m_stream(stream) {}
+ ~out_buff();
+ int sync() override {
int ret = 0;
for (unsigned char c : str()) {
if (putc(c, m_stream) == EOF) {
@@ -29,6 +30,12 @@ public:
}
};
+out_buff::~out_buff() { pubsync(); }
+
+#if defined(__clang__)
+#pragma clang diagnostic ignored "-Wexit-time-destructors" // static variables in cout/cerr/clog
+#endif
+
namespace Catch {
std::ostream& cout() {
static std::ostream ret(new out_buff(stdout));
diff --git a/examples/301-Gen-MapTypeConversion.cpp b/examples/301-Gen-MapTypeConversion.cpp
index b6377e99..88772971 100644
--- a/examples/301-Gen-MapTypeConversion.cpp
+++ b/examples/301-Gen-MapTypeConversion.cpp
@@ -22,15 +22,17 @@ public:
}
}
- std::string const& get() const override {
- return m_line;
- }
+ std::string const& get() const override;
bool next() override {
return !!std::getline(m_stream, m_line);
}
};
+std::string const& LineGenerator::get() const {
+ return m_line;
+}
+
// This helper function provides a nicer UX when instantiating the generator
// Notice that it returns an instance of GeneratorWrapper<std::string>, which
// is a value-wrapper around std::unique_ptr<IGenerator<std::string>>.
diff --git a/include/catch.hpp b/include/catch.hpp
index 5667def9..633d91aa 100644
--- a/include/catch.hpp
+++ b/include/catch.hpp
@@ -10,7 +10,7 @@
#define TWOBLUECUBES_CATCH_HPP_INCLUDED
#define CATCH_VERSION_MAJOR 2
-#define CATCH_VERSION_MINOR 7
+#define CATCH_VERSION_MINOR 11
#define CATCH_VERSION_PATCH 2
#ifdef __clang__
@@ -53,7 +53,6 @@
#include "internal/catch_test_registry.h"
#include "internal/catch_capture.hpp"
#include "internal/catch_section.h"
-#include "internal/catch_benchmark.h"
#include "internal/catch_interfaces_exception.h"
#include "internal/catch_approx.h"
#include "internal/catch_compiler_capabilities.h"
@@ -75,10 +74,15 @@
#include "internal/catch_objc.hpp"
#endif
-#ifdef CATCH_CONFIG_EXTERNAL_INTERFACES
+// Benchmarking needs the externally-facing parts of reporters to work
+#if defined(CATCH_CONFIG_EXTERNAL_INTERFACES) || defined(CATCH_CONFIG_ENABLE_BENCHMARKING)
#include "internal/catch_external_interfaces.h"
#endif
+#if defined(CATCH_CONFIG_ENABLE_BENCHMARKING)
+#include "internal/benchmark/catch_benchmarking_all.hpp"
+#endif
+
#endif // ! CATCH_CONFIG_IMPL_ONLY
#ifdef CATCH_IMPL
@@ -89,6 +93,7 @@
#include "internal/catch_default_main.hpp"
#endif
+
#if !defined(CATCH_CONFIG_IMPL_ONLY)
#ifdef CLARA_CONFIG_MAIN_NOT_DEFINED
@@ -132,6 +137,7 @@
#endif // CATCH_CONFIG_DISABLE_MATCHERS
#define CATCH_INFO( msg ) INTERNAL_CATCH_INFO( "CATCH_INFO", msg )
+#define CATCH_UNSCOPED_INFO( msg ) INTERNAL_CATCH_UNSCOPED_INFO( "CATCH_UNSCOPED_INFO", msg )
#define CATCH_WARN( msg ) INTERNAL_CATCH_MSG( "CATCH_WARN", Catch::ResultWas::Warning, Catch::ResultDisposition::ContinueOnFailure, msg )
#define CATCH_CAPTURE( ... ) INTERNAL_CATCH_CAPTURE( INTERNAL_CATCH_UNIQUE_NAME(capturer), "CATCH_CAPTURE",__VA_ARGS__ )
@@ -149,14 +155,22 @@
#ifndef CATCH_CONFIG_TRADITIONAL_MSVC_PREPROCESSOR
#define CATCH_TEMPLATE_TEST_CASE( ... ) INTERNAL_CATCH_TEMPLATE_TEST_CASE( __VA_ARGS__ )
+#define CATCH_TEMPLATE_TEST_CASE_SIG( ... ) INTERNAL_CATCH_TEMPLATE_TEST_CASE_SIG( __VA_ARGS__ )
#define CATCH_TEMPLATE_TEST_CASE_METHOD( className, ... ) INTERNAL_CATCH_TEMPLATE_TEST_CASE_METHOD( className, __VA_ARGS__ )
+#define CATCH_TEMPLATE_TEST_CASE_METHOD_SIG( className, ... ) INTERNAL_CATCH_TEMPLATE_TEST_CASE_METHOD_SIG( className, __VA_ARGS__ )
#define CATCH_TEMPLATE_PRODUCT_TEST_CASE( ... ) INTERNAL_CATCH_TEMPLATE_PRODUCT_TEST_CASE( __VA_ARGS__ )
+#define CATCH_TEMPLATE_PRODUCT_TEST_CASE_SIG( ... ) INTERNAL_CATCH_TEMPLATE_PRODUCT_TEST_CASE_SIG( __VA_ARGS__ )
#define CATCH_TEMPLATE_PRODUCT_TEST_CASE_METHOD( className, ... ) INTERNAL_CATCH_TEMPLATE_PRODUCT_TEST_CASE_METHOD( className, __VA_ARGS__ )
+#define CATCH_TEMPLATE_PRODUCT_TEST_CASE_METHOD_SIG( className, ... ) INTERNAL_CATCH_TEMPLATE_PRODUCT_TEST_CASE_METHOD_SIG( className, __VA_ARGS__ )
#else
#define CATCH_TEMPLATE_TEST_CASE( ... ) INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_TEST_CASE( __VA_ARGS__ ) )
+#define CATCH_TEMPLATE_TEST_CASE_SIG( ... ) INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_TEST_CASE_SIG( __VA_ARGS__ ) )
#define CATCH_TEMPLATE_TEST_CASE_METHOD( className, ... ) INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_TEST_CASE_METHOD( className, __VA_ARGS__ ) )
+#define CATCH_TEMPLATE_TEST_CASE_METHOD_SIG( className, ... ) INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_TEST_CASE_METHOD_SIG( className, __VA_ARGS__ ) )
#define CATCH_TEMPLATE_PRODUCT_TEST_CASE( ... ) INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_PRODUCT_TEST_CASE( __VA_ARGS__ ) )
+#define CATCH_TEMPLATE_PRODUCT_TEST_CASE_SIG( ... ) INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_PRODUCT_TEST_CASE_SIG( __VA_ARGS__ ) )
#define CATCH_TEMPLATE_PRODUCT_TEST_CASE_METHOD( className, ... ) INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_PRODUCT_TEST_CASE_METHOD( className, __VA_ARGS__ ) )
+#define CATCH_TEMPLATE_PRODUCT_TEST_CASE_METHOD_SIG( className, ... ) INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_PRODUCT_TEST_CASE_METHOD_SIG( className, __VA_ARGS__ ) )
#endif
@@ -179,6 +193,13 @@
#define CATCH_THEN( desc ) INTERNAL_CATCH_DYNAMIC_SECTION( " Then: " << desc )
#define CATCH_AND_THEN( desc ) INTERNAL_CATCH_DYNAMIC_SECTION( " And: " << desc )
+#if defined(CATCH_CONFIG_ENABLE_BENCHMARKING)
+#define CATCH_BENCHMARK(...) \
+ INTERNAL_CATCH_BENCHMARK(INTERNAL_CATCH_UNIQUE_NAME(____C_A_T_C_H____B_E_N_C_H____), INTERNAL_CATCH_GET_1_ARG(__VA_ARGS__,,), INTERNAL_CATCH_GET_2_ARG(__VA_ARGS__,,))
+#define CATCH_BENCHMARK_ADVANCED(name) \
+ INTERNAL_CATCH_BENCHMARK_ADVANCED(INTERNAL_CATCH_UNIQUE_NAME(____C_A_T_C_H____B_E_N_C_H____), name)
+#endif // CATCH_CONFIG_ENABLE_BENCHMARKING
+
// If CATCH_CONFIG_PREFIX_ALL is not defined then the CATCH_ prefix is not required
#else
@@ -232,14 +253,26 @@
#ifndef CATCH_CONFIG_TRADITIONAL_MSVC_PREPROCESSOR
#define TEMPLATE_TEST_CASE( ... ) INTERNAL_CATCH_TEMPLATE_TEST_CASE( __VA_ARGS__ )
+#define TEMPLATE_TEST_CASE_SIG( ... ) INTERNAL_CATCH_TEMPLATE_TEST_CASE_SIG( __VA_ARGS__ )
#define TEMPLATE_TEST_CASE_METHOD( className, ... ) INTERNAL_CATCH_TEMPLATE_TEST_CASE_METHOD( className, __VA_ARGS__ )
+#define TEMPLATE_TEST_CASE_METHOD_SIG( className, ... ) INTERNAL_CATCH_TEMPLATE_TEST_CASE_METHOD_SIG( className, __VA_ARGS__ )
#define TEMPLATE_PRODUCT_TEST_CASE( ... ) INTERNAL_CATCH_TEMPLATE_PRODUCT_TEST_CASE( __VA_ARGS__ )
+#define TEMPLATE_PRODUCT_TEST_CASE_SIG( ... ) INTERNAL_CATCH_TEMPLATE_PRODUCT_TEST_CASE_SIG( __VA_ARGS__ )
#define TEMPLATE_PRODUCT_TEST_CASE_METHOD( className, ... ) INTERNAL_CATCH_TEMPLATE_PRODUCT_TEST_CASE_METHOD( className, __VA_ARGS__ )
+#define TEMPLATE_PRODUCT_TEST_CASE_METHOD_SIG( className, ... ) INTERNAL_CATCH_TEMPLATE_PRODUCT_TEST_CASE_METHOD_SIG( className, __VA_ARGS__ )
+#define TEMPLATE_LIST_TEST_CASE( ... ) INTERNAL_CATCH_TEMPLATE_LIST_TEST_CASE(__VA_ARGS__)
+#define TEMPLATE_LIST_TEST_CASE_METHOD( className, ... ) INTERNAL_CATCH_TEMPLATE_LIST_TEST_CASE_METHOD( className, __VA_ARGS__ )
#else
#define TEMPLATE_TEST_CASE( ... ) INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_TEST_CASE( __VA_ARGS__ ) )
+#define TEMPLATE_TEST_CASE_SIG( ... ) INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_TEST_CASE_SIG( __VA_ARGS__ ) )
#define TEMPLATE_TEST_CASE_METHOD( className, ... ) INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_TEST_CASE_METHOD( className, __VA_ARGS__ ) )
+#define TEMPLATE_TEST_CASE_METHOD_SIG( className, ... ) INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_TEST_CASE_METHOD_SIG( className, __VA_ARGS__ ) )
#define TEMPLATE_PRODUCT_TEST_CASE( ... ) INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_PRODUCT_TEST_CASE( __VA_ARGS__ ) )
+#define TEMPLATE_PRODUCT_TEST_CASE_SIG( ... ) INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_PRODUCT_TEST_CASE_SIG( __VA_ARGS__ ) )
#define TEMPLATE_PRODUCT_TEST_CASE_METHOD( className, ... ) INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_PRODUCT_TEST_CASE_METHOD( className, __VA_ARGS__ ) )
+#define TEMPLATE_PRODUCT_TEST_CASE_METHOD_SIG( className, ... ) INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_PRODUCT_TEST_CASE_METHOD_SIG( className, __VA_ARGS__ ) )
+#define TEMPLATE_LIST_TEST_CASE( ... ) INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_LIST_TEST_CASE( __VA_ARGS__ ) )
+#define TEMPLATE_LIST_TEST_CASE_METHOD( className, ... ) INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_LIST_TEST_CASE_METHOD( className, __VA_ARGS__ ) )
#endif
@@ -266,6 +299,13 @@
#define THEN( desc ) INTERNAL_CATCH_DYNAMIC_SECTION( " Then: " << desc )
#define AND_THEN( desc ) INTERNAL_CATCH_DYNAMIC_SECTION( " And: " << desc )
+#if defined(CATCH_CONFIG_ENABLE_BENCHMARKING)
+#define BENCHMARK(...) \
+ INTERNAL_CATCH_BENCHMARK(INTERNAL_CATCH_UNIQUE_NAME(____C_A_T_C_H____B_E_N_C_H____), INTERNAL_CATCH_GET_1_ARG(__VA_ARGS__,,), INTERNAL_CATCH_GET_2_ARG(__VA_ARGS__,,))
+#define BENCHMARK_ADVANCED(name) \
+ INTERNAL_CATCH_BENCHMARK_ADVANCED(INTERNAL_CATCH_UNIQUE_NAME(____C_A_T_C_H____B_E_N_C_H____), name)
+#endif // CATCH_CONFIG_ENABLE_BENCHMARKING
+
using Catch::Detail::Approx;
#else // CATCH_CONFIG_DISABLE
@@ -305,9 +345,10 @@ using Catch::Detail::Approx;
#define CATCH_REQUIRE_THAT( arg, matcher ) (void)(0)
#endif // CATCH_CONFIG_DISABLE_MATCHERS
-#define CATCH_INFO( msg ) (void)(0)
-#define CATCH_WARN( msg ) (void)(0)
-#define CATCH_CAPTURE( msg ) (void)(0)
+#define CATCH_INFO( msg ) (void)(0)
+#define CATCH_UNSCOPED_INFO( msg ) (void)(0)
+#define CATCH_WARN( msg ) (void)(0)
+#define CATCH_CAPTURE( msg ) (void)(0)
#define CATCH_TEST_CASE( ... ) INTERNAL_CATCH_TESTCASE_NO_REGISTRATION(INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_S_T____ ))
#define CATCH_TEST_CASE_METHOD( className, ... ) INTERNAL_CATCH_TESTCASE_NO_REGISTRATION(INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_S_T____ ))
@@ -322,15 +363,23 @@ using Catch::Detail::Approx;
#define CATCH_ANON_TEST_CASE() INTERNAL_CATCH_TESTCASE_NO_REGISTRATION(INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_S_T____ ))
#ifndef CATCH_CONFIG_TRADITIONAL_MSVC_PREPROCESSOR
-#define CATCH_TEMPLATE_TEST_CASE( ... ) INTERNAL_CATCH_TEMPLATE_TEST_CASE_NO_REGISTRATION(INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_M_P_L_A_T_E____T_E_S_T____ ) )
-#define CATCH_TEMPLATE_TEST_CASE_METHOD( className, ... ) INTERNAL_CATCH_TEMPLATE_TEST_CASE_METHOD_NO_REGISTRATION(INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_M_P_L_A_T_E____T_E_S_T____ ), className )
+#define CATCH_TEMPLATE_TEST_CASE( ... ) INTERNAL_CATCH_TEMPLATE_TEST_CASE_NO_REGISTRATION(__VA_ARGS__)
+#define CATCH_TEMPLATE_TEST_CASE_SIG( ... ) INTERNAL_CATCH_TEMPLATE_TEST_CASE_SIG_NO_REGISTRATION(__VA_ARGS__)
+#define CATCH_TEMPLATE_TEST_CASE_METHOD( className, ... ) INTERNAL_CATCH_TEMPLATE_TEST_CASE_METHOD_NO_REGISTRATION(className, __VA_ARGS__)
+#define CATCH_TEMPLATE_TEST_CASE_METHOD_SIG( className, ... ) INTERNAL_CATCH_TEMPLATE_TEST_CASE_METHOD_SIG_NO_REGISTRATION(className, __VA_ARGS__ )
#define CATCH_TEMPLATE_PRODUCT_TEST_CASE( ... ) CATCH_TEMPLATE_TEST_CASE( __VA_ARGS__ )
+#define CATCH_TEMPLATE_PRODUCT_TEST_CASE_SIG( ... ) CATCH_TEMPLATE_TEST_CASE( __VA_ARGS__ )
#define CATCH_TEMPLATE_PRODUCT_TEST_CASE_METHOD( className, ... ) CATCH_TEMPLATE_TEST_CASE_METHOD( className, __VA_ARGS__ )
+#define CATCH_TEMPLATE_PRODUCT_TEST_CASE_METHOD_SIG( className, ... ) CATCH_TEMPLATE_TEST_CASE_METHOD( className, __VA_ARGS__ )
#else
-#define CATCH_TEMPLATE_TEST_CASE( ... ) INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_TEST_CASE_NO_REGISTRATION(INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_M_P_L_A_T_E____T_E_S_T____ ) ) )
-#define CATCH_TEMPLATE_TEST_CASE_METHOD( className, ... ) INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_TEST_CASE_METHOD_NO_REGISTRATION(INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_M_P_L_A_T_E____T_E_S_T____ ), className ) )
+#define CATCH_TEMPLATE_TEST_CASE( ... ) INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_TEST_CASE_NO_REGISTRATION(__VA_ARGS__) )
+#define CATCH_TEMPLATE_TEST_CASE_SIG( ... ) INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_TEST_CASE_SIG_NO_REGISTRATION(__VA_ARGS__) )
+#define CATCH_TEMPLATE_TEST_CASE_METHOD( className, ... ) INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_TEST_CASE_METHOD_NO_REGISTRATION(className, __VA_ARGS__ ) )
+#define CATCH_TEMPLATE_TEST_CASE_METHOD_SIG( className, ... ) INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_TEST_CASE_METHOD_SIG_NO_REGISTRATION(className, __VA_ARGS__ ) )
#define CATCH_TEMPLATE_PRODUCT_TEST_CASE( ... ) CATCH_TEMPLATE_TEST_CASE( __VA_ARGS__ )
+#define CATCH_TEMPLATE_PRODUCT_TEST_CASE_SIG( ... ) CATCH_TEMPLATE_TEST_CASE( __VA_ARGS__ )
#define CATCH_TEMPLATE_PRODUCT_TEST_CASE_METHOD( className, ... ) CATCH_TEMPLATE_TEST_CASE_METHOD( className, __VA_ARGS__ )
+#define CATCH_TEMPLATE_PRODUCT_TEST_CASE_METHOD_SIG( className, ... ) CATCH_TEMPLATE_TEST_CASE_METHOD( className, __VA_ARGS__ )
#endif
// "BDD-style" convenience wrappers
@@ -382,6 +431,7 @@ using Catch::Detail::Approx;
#endif // CATCH_CONFIG_DISABLE_MATCHERS
#define INFO( msg ) (void)(0)
+#define UNSCOPED_INFO( msg ) (void)(0)
#define WARN( msg ) (void)(0)
#define CAPTURE( msg ) (void)(0)
@@ -397,15 +447,23 @@ using Catch::Detail::Approx;
#define ANON_TEST_CASE() INTERNAL_CATCH_TESTCASE_NO_REGISTRATION(INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_S_T____ ))
#ifndef CATCH_CONFIG_TRADITIONAL_MSVC_PREPROCESSOR
-#define TEMPLATE_TEST_CASE( ... ) INTERNAL_CATCH_TEMPLATE_TEST_CASE_NO_REGISTRATION(INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_M_P_L_A_T_E____T_E_S_T____ ) )
-#define TEMPLATE_TEST_CASE_METHOD( className, ... ) INTERNAL_CATCH_TEMPLATE_TEST_CASE_METHOD_NO_REGISTRATION(INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_M_P_L_A_T_E____T_E_S_T____ ), className )
+#define TEMPLATE_TEST_CASE( ... ) INTERNAL_CATCH_TEMPLATE_TEST_CASE_NO_REGISTRATION(__VA_ARGS__)
+#define TEMPLATE_TEST_CASE_SIG( ... ) INTERNAL_CATCH_TEMPLATE_TEST_CASE_SIG_NO_REGISTRATION(__VA_ARGS__)
+#define TEMPLATE_TEST_CASE_METHOD( className, ... ) INTERNAL_CATCH_TEMPLATE_TEST_CASE_METHOD_NO_REGISTRATION(className, __VA_ARGS__)
+#define TEMPLATE_TEST_CASE_METHOD_SIG( className, ... ) INTERNAL_CATCH_TEMPLATE_TEST_CASE_METHOD_SIG_NO_REGISTRATION(className, __VA_ARGS__ )
#define TEMPLATE_PRODUCT_TEST_CASE( ... ) TEMPLATE_TEST_CASE( __VA_ARGS__ )
+#define TEMPLATE_PRODUCT_TEST_CASE_SIG( ... ) TEMPLATE_TEST_CASE( __VA_ARGS__ )
#define TEMPLATE_PRODUCT_TEST_CASE_METHOD( className, ... ) TEMPLATE_TEST_CASE_METHOD( className, __VA_ARGS__ )
+#define TEMPLATE_PRODUCT_TEST_CASE_METHOD_SIG( className, ... ) TEMPLATE_TEST_CASE_METHOD( className, __VA_ARGS__ )
#else
-#define TEMPLATE_TEST_CASE( ... ) INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_TEST_CASE_NO_REGISTRATION(INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_M_P_L_A_T_E____T_E_S_T____ ) ) )
-#define TEMPLATE_TEST_CASE_METHOD( className, ... ) INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_TEST_CASE_METHOD_NO_REGISTRATION(INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_M_P_L_A_T_E____T_E_S_T____ ), className ) )
+#define TEMPLATE_TEST_CASE( ... ) INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_TEST_CASE_NO_REGISTRATION(__VA_ARGS__) )
+#define TEMPLATE_TEST_CASE_SIG( ... ) INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_TEST_CASE_SIG_NO_REGISTRATION(__VA_ARGS__) )
+#define TEMPLATE_TEST_CASE_METHOD( className, ... ) INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_TEST_CASE_METHOD_NO_REGISTRATION(className, __VA_ARGS__ ) )
+#define TEMPLATE_TEST_CASE_METHOD_SIG( className, ... ) INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_TEST_CASE_METHOD_SIG_NO_REGISTRATION(className, __VA_ARGS__ ) )
#define TEMPLATE_PRODUCT_TEST_CASE( ... ) TEMPLATE_TEST_CASE( __VA_ARGS__ )
+#define TEMPLATE_PRODUCT_TEST_CASE_SIG( ... ) TEMPLATE_TEST_CASE( __VA_ARGS__ )
#define TEMPLATE_PRODUCT_TEST_CASE_METHOD( className, ... ) TEMPLATE_TEST_CASE_METHOD( className, __VA_ARGS__ )
+#define TEMPLATE_PRODUCT_TEST_CASE_METHOD_SIG( className, ... ) TEMPLATE_TEST_CASE_METHOD( className, __VA_ARGS__ )
#endif
#define STATIC_REQUIRE( ... ) (void)(0)
diff --git a/include/internal/benchmark/catch_benchmark.hpp b/include/internal/benchmark/catch_benchmark.hpp
new file mode 100644
index 00000000..ec8dde08
--- /dev/null
+++ b/include/internal/benchmark/catch_benchmark.hpp
@@ -0,0 +1,122 @@
+/*
+ * Created by Joachim on 16/04/2019.
+ * Adapted from donated nonius code.
+ *
+ * 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)
+ */
+
+ // Benchmark
+#ifndef TWOBLUECUBES_CATCH_BENCHMARK_HPP_INCLUDED
+#define TWOBLUECUBES_CATCH_BENCHMARK_HPP_INCLUDED
+
+#include "../catch_config.hpp"
+#include "../catch_context.h"
+#include "../catch_interfaces_reporter.h"
+#include "../catch_test_registry.h"
+
+#include "catch_chronometer.hpp"
+#include "catch_clock.hpp"
+#include "catch_environment.hpp"
+#include "catch_execution_plan.hpp"
+#include "detail/catch_estimate_clock.hpp"
+#include "detail/catch_complete_invoke.hpp"
+#include "detail/catch_analyse.hpp"
+#include "detail/catch_benchmark_function.hpp"
+#include "detail/catch_run_for_at_least.hpp"
+
+#include <algorithm>
+#include <functional>
+#include <string>
+#include <vector>
+#include <cmath>
+
+namespace Catch {
+ namespace Benchmark {
+ struct Benchmark {
+ Benchmark(std::string &&name)
+ : name(std::move(name)) {}
+
+ template <class FUN>
+ Benchmark(std::string &&name, FUN &&func)
+ : fun(std::move(func)), name(std::move(name)) {}
+
+ template <typename Clock>
+ ExecutionPlan<FloatDuration<Clock>> prepare(const IConfig &cfg, Environment<FloatDuration<Clock>> env) const {
+ auto min_time = env.clock_resolution.mean * Detail::minimum_ticks;
+ auto run_time = std::max(min_time, std::chrono::duration_cast<decltype(min_time)>(cfg.benchmarkWarmupTime()));
+ auto&& test = Detail::run_for_at_least<Clock>(std::chrono::duration_cast<ClockDuration<Clock>>(run_time), 1, fun);
+ int new_iters = static_cast<int>(std::ceil(min_time * test.iterations / test.elapsed));
+ return { new_iters, test.elapsed / test.iterations * new_iters * cfg.benchmarkSamples(), fun, std::chrono::duration_cast<FloatDuration<Clock>>(cfg.benchmarkWarmupTime()), Detail::warmup_iterations };
+ }
+
+ template <typename Clock = default_clock>
+ void run() {
+ IConfigPtr cfg = getCurrentContext().getConfig();
+
+ auto env = Detail::measure_environment<Clock>();
+
+ getResultCapture().benchmarkPreparing(name);
+ CATCH_TRY{
+ auto plan = user_code([&] {
+ return prepare<Clock>(*cfg, env);
+ });
+
+ BenchmarkInfo info {
+ name,
+ plan.estimated_duration.count(),
+ plan.iterations_per_sample,
+ cfg->benchmarkSamples(),
+ cfg->benchmarkResamples(),
+ env.clock_resolution.mean.count(),
+ env.clock_cost.mean.count()
+ };
+
+ getResultCapture().benchmarkStarting(info);
+
+ auto samples = user_code([&] {
+ return plan.template run<Clock>(*cfg, env);
+ });
+
+ auto analysis = Detail::analyse(*cfg, env, samples.begin(), samples.end());
+ BenchmarkStats<FloatDuration<Clock>> stats{ info, analysis.samples, analysis.mean, analysis.standard_deviation, analysis.outliers, analysis.outlier_variance };
+ getResultCapture().benchmarkEnded(stats);
+
+ } CATCH_CATCH_ALL{
+ if (translateActiveException() != Detail::benchmarkErrorMsg) // benchmark errors have been reported, otherwise rethrow.
+ std::rethrow_exception(std::current_exception());
+ }
+ }
+
+ // sets lambda to be used in fun *and* executes benchmark!
+ template <typename Fun,
+ typename std::enable_if<!Detail::is_related<Fun, Benchmark>::value, int>::type = 0>
+ Benchmark & operator=(Fun func) {
+ fun = Detail::BenchmarkFunction(func);
+ run();
+ return *this;
+ }
+
+ explicit operator bool() {
+ return true;
+ }
+
+ private:
+ Detail::BenchmarkFunction fun;
+ std::string name;
+ };
+ }
+} // namespace Catch
+
+#define INTERNAL_CATCH_GET_1_ARG(arg1, arg2, ...) arg1
+#define INTERNAL_CATCH_GET_2_ARG(arg1, arg2, ...) arg2
+
+#define INTERNAL_CATCH_BENCHMARK(BenchmarkName, name, benchmarkIndex)\
+ if( Catch::Benchmark::Benchmark BenchmarkName{name} ) \
+ BenchmarkName = [&](int benchmarkIndex)
+
+#define INTERNAL_CATCH_BENCHMARK_ADVANCED(BenchmarkName, name)\
+ if( Catch::Benchmark::Benchmark BenchmarkName{name} ) \
+ BenchmarkName = [&]
+
+#endif // TWOBLUECUBES_CATCH_BENCHMARK_HPP_INCLUDED
diff --git a/include/internal/benchmark/catch_benchmarking_all.hpp b/include/internal/benchmark/catch_benchmarking_all.hpp
new file mode 100644
index 00000000..7717f899
--- /dev/null
+++ b/include/internal/benchmark/catch_benchmarking_all.hpp
@@ -0,0 +1,29 @@
+/*
+ * 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)
+ */
+
+
+// A proxy header that includes all of the benchmarking headers to allow
+// concise include of the benchmarking features. You should prefer the
+// individual includes in standard use.
+
+#include "catch_benchmark.hpp"
+#include "catch_chronometer.hpp"
+#include "catch_clock.hpp"
+#include "catch_constructor.hpp"
+#include "catch_environment.hpp"
+#include "catch_estimate.hpp"
+#include "catch_execution_plan.hpp"
+#include "catch_optimizer.hpp"
+#include "catch_outlier_classification.hpp"
+#include "catch_sample_analysis.hpp"
+#include "detail/catch_analyse.hpp"
+#include "detail/catch_benchmark_function.hpp"
+#include "detail/catch_complete_invoke.hpp"
+#include "detail/catch_estimate_clock.hpp"
+#include "detail/catch_measure.hpp"
+#include "detail/catch_repeat.hpp"
+#include "detail/catch_run_for_at_least.hpp"
+#include "detail/catch_stats.hpp"
+#include "detail/catch_timing.hpp"
diff --git a/include/internal/benchmark/catch_chronometer.hpp b/include/internal/benchmark/catch_chronometer.hpp
new file mode 100644
index 00000000..1022017d
--- /dev/null
+++ b/include/internal/benchmark/catch_chronometer.hpp
@@ -0,0 +1,71 @@
+/*
+ * Created by Joachim on 16/04/2019.
+ * Adapted from donated nonius code.
+ *
+ * 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)
+ */
+
+// User-facing chronometer
+
+#ifndef TWOBLUECUBES_CATCH_CHRONOMETER_HPP_INCLUDED
+#define TWOBLUECUBES_CATCH_CHRONOMETER_HPP_INCLUDED
+
+#include "catch_clock.hpp"
+#include "catch_optimizer.hpp"
+#include "detail/catch_complete_invoke.hpp"
+#include "../catch_meta.hpp"
+
+namespace Catch {
+ namespace Benchmark {
+ namespace Detail {
+ struct ChronometerConcept {
+ virtual void start() = 0;
+ virtual void finish() = 0;
+ virtual ~ChronometerConcept() = default;
+ };
+ template <typename Clock>
+ struct ChronometerModel final : public ChronometerConcept {
+ void start() override { started = Clock::now(); }
+ void finish() override { finished = Clock::now(); }
+
+ ClockDuration<Clock> elapsed() const { return finished - started; }
+
+ TimePoint<Clock> started;
+ TimePoint<Clock> finished;
+ };
+ } // namespace Detail
+
+ struct Chronometer {
+ public:
+ template <typename Fun>
+ void measure(Fun&& fun) { measure(std::forward<Fun>(fun), is_callable<Fun(int)>()); }
+
+ int runs() const { return k; }
+
+ Chronometer(Detail::ChronometerConcept& meter, int k)
+ : impl(&meter)
+ , k(k) {}
+
+ private:
+ template <typename Fun>
+ void measure(Fun&& fun, std::false_type) {
+ measure([&fun](int) { return fun(); }, std::true_type());
+ }
+
+ template <typename Fun>
+ void measure(Fun&& fun, std::true_type) {
+ Detail::optimizer_barrier();
+ impl->start();
+ for (int i = 0; i < k; ++i) invoke_deoptimized(fun, i);
+ impl->finish();
+ Detail::optimizer_barrier();
+ }
+
+ Detail::ChronometerConcept* impl;
+ int k;
+ };
+ } // namespace Benchmark
+} // namespace Catch
+
+#endif // TWOBLUECUBES_CATCH_CHRONOMETER_HPP_INCLUDED
diff --git a/include/internal/benchmark/catch_clock.hpp b/include/internal/benchmark/catch_clock.hpp
new file mode 100644
index 00000000..32a3e868
--- /dev/null
+++ b/include/internal/benchmark/catch_clock.hpp
@@ -0,0 +1,40 @@
+/*
+ * Created by Joachim on 16/04/2019.
+ * Adapted from donated nonius code.
+ *
+ * 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)
+ */
+
+// Clocks
+
+#ifndef TWOBLUECUBES_CATCH_CLOCK_HPP_INCLUDED
+#define TWOBLUECUBES_CATCH_CLOCK_HPP_INCLUDED
+
+#include <chrono>
+#include <ratio>
+
+namespace Catch {
+ namespace Benchmark {
+ template <typename Clock>
+ using ClockDuration = typename Clock::duration;
+ template <typename Clock>
+ using FloatDuration = std::chrono::duration<double, typename Clock::period>;
+
+ template <typename Clock>
+ using TimePoint = typename Clock::time_point;
+
+ using default_clock = std::chrono::steady_clock;
+
+ template <typename Clock>
+ struct now {
+ TimePoint<Clock> operator()() const {
+ return Clock::now();
+ }
+ };
+
+ using fp_seconds = std::chrono::duration<double, std::ratio<1>>;
+ } // namespace Benchmark
+} // namespace Catch
+
+#endif // TWOBLUECUBES_CATCH_CLOCK_HPP_INCLUDED
diff --git a/include/internal/benchmark/catch_constructor.hpp b/include/internal/benchmark/catch_constructor.hpp
new file mode 100644
index 00000000..4fc04042
--- /dev/null
+++ b/include/internal/benchmark/catch_constructor.hpp
@@ -0,0 +1,79 @@
+/*
+ * Created by Joachim on 16/04/2019.
+ * Adapted from donated nonius code.
+ *
+ * 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)
+ */
+
+// Constructor and destructor helpers
+
+#ifndef TWOBLUECUBES_CATCH_CONSTRUCTOR_HPP_INCLUDED
+#define TWOBLUECUBES_CATCH_CONSTRUCTOR_HPP_INCLUDED
+
+#include <type_traits>
+
+namespace Catch {
+ namespace Benchmark {
+ namespace Detail {
+ template <typename T, bool Destruct>
+ struct ObjectStorage
+ {
+ using TStorage = typename std::aligned_storage<sizeof(T), std::alignment_of<T>::value>::type;
+
+ ObjectStorage() : data() {}
+
+ ObjectStorage(const ObjectStorage& other)
+ {
+ new(&data) T(other.stored_object());
+ }
+
+ ObjectStorage(ObjectStorage&& other)
+ {
+ new(&data) T(std::move(other.stored_object()));
+ }
+
+ ~ObjectStorage() { destruct_on_exit<T>(); }
+
+ template <typename... Args>
+ void construct(Args&&... args)
+ {
+ new (&data) T(std::forward<Args>(args)...);
+ }
+
+ template <bool AllowManualDestruction = !Destruct>
+ typename std::enable_if<AllowManualDestruction>::type destruct()
+ {
+ stored_object().~T();
+ }
+
+ private:
+ // If this is a constructor benchmark, destruct the underlying object
+ template <typename U>
+ void destruct_on_exit(typename std::enable_if<Destruct, U>::type* = 0) { destruct<true>(); }
+ // Otherwise, don't
+ template <typename U>
+ void destruct_on_exit(typename std::enable_if<!Destruct, U>::type* = 0) { }
+
+ T& stored_object() {
+ return *static_cast<T*>(static_cast<void*>(&data));
+ }
+
+ T const& stored_object() const {
+ return *static_cast<T*>(static_cast<void*>(&data));
+ }
+
+
+ TStorage data;
+ };
+ }
+
+ template <typename T>
+ using storage_for = Detail::ObjectStorage<T, true>;
+
+ template <typename T>
+ using destructable_object = Detail::ObjectStorage<T, false>;
+ }
+}
+
+#endif // TWOBLUECUBES_CATCH_CONSTRUCTOR_HPP_INCLUDED
diff --git a/include/internal/benchmark/catch_environment.hpp b/include/internal/benchmark/catch_environment.hpp
new file mode 100644
index 00000000..55951249
--- /dev/null
+++ b/include/internal/benchmark/catch_environment.hpp
@@ -0,0 +1,38 @@
+/*
+ * Created by Joachim on 16/04/2019.
+ * Adapted from donated nonius code.
+ *
+ * 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)
+ */
+
+// Environment information
+
+#ifndef TWOBLUECUBES_CATCH_ENVIRONMENT_HPP_INCLUDED
+#define TWOBLUECUBES_CATCH_ENVIRONMENT_HPP_INCLUDED
+
+#include "catch_clock.hpp"
+#include "catch_outlier_classification.hpp"
+
+namespace Catch {
+ namespace Benchmark {
+ template <typename Duration>
+ struct EnvironmentEstimate {
+ Duration mean;
+ OutlierClassification outliers;
+
+ template <typename Duration2>
+ operator EnvironmentEstimate<Duration2>() const {
+ return { mean, outliers };
+ }
+ };
+ template <typename Clock>
+ struct Environment {
+ using clock_type = Clock;
+ EnvironmentEstimate<FloatDuration<Clock>> clock_resolution;
+ EnvironmentEstimate<FloatDuration<Clock>> clock_cost;
+ };
+ } // namespace Benchmark
+} // namespace Catch
+
+#endif // TWOBLUECUBES_CATCH_ENVIRONMENT_HPP_INCLUDED
diff --git a/include/internal/benchmark/catch_estimate.hpp b/include/internal/benchmark/catch_estimate.hpp
new file mode 100644
index 00000000..a3c913ce
--- /dev/null
+++ b/include/internal/benchmark/catch_estimate.hpp
@@ -0,0 +1,31 @@
+/*
+ * Created by Joachim on 16/04/2019.
+ * Adapted from donated nonius code.
+ *
+ * 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)
+ */
+
+ // Statistics estimates
+
+#ifndef TWOBLUECUBES_CATCH_ESTIMATE_HPP_INCLUDED
+#define TWOBLUECUBES_CATCH_ESTIMATE_HPP_INCLUDED
+
+namespace Catch {
+ namespace Benchmark {
+ template <typename Duration>
+ struct Estimate {
+ Duration point;
+ Duration lower_bound;
+ Duration upper_bound;
+ double confidence_interval;
+
+ template <typename Duration2>
+ operator Estimate<Duration2>() const {
+ return { point, lower_bound, upper_bound, confidence_interval };
+ }
+ };
+ } // namespace Benchmark
+} // namespace Catch
+
+#endif // TWOBLUECUBES_CATCH_ESTIMATE_HPP_INCLUDED
diff --git a/include/internal/benchmark/catch_execution_plan.hpp b/include/internal/benchmark/catch_execution_plan.hpp
new file mode 100644
index 00000000..e56c83aa
--- /dev/null
+++ b/include/internal/benchmark/catch_execution_plan.hpp
@@ -0,0 +1,58 @@
+/*
+ * Created by Joachim on 16/04/2019.
+ * Adapted from donated nonius code.
+ *
+ * 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)
+ */
+
+ // Execution plan
+
+#ifndef TWOBLUECUBES_CATCH_EXECUTION_PLAN_HPP_INCLUDED
+#define TWOBLUECUBES_CATCH_EXECUTION_PLAN_HPP_INCLUDED
+
+#include "../catch_config.hpp"
+#include "catch_clock.hpp"
+#include "catch_environment.hpp"
+#include "detail/catch_benchmark_function.hpp"
+#include "detail/catch_repeat.hpp"
+#include "detail/catch_run_for_at_least.hpp"
+
+#include <algorithm>
+
+namespace Catch {
+ namespace Benchmark {
+ template <typename Duration>
+ struct ExecutionPlan {
+ int iterations_per_sample;
+ Duration estimated_duration;
+ Detail::BenchmarkFunction benchmark;
+ Duration warmup_time;
+ int warmup_iterations;
+
+ template <typename Duration2>
+ operator ExecutionPlan<Duration2>() const {
+ return { iterations_per_sample, estimated_duration, benchmark, warmup_time, warmup_iterations };
+ }
+
+ template <typename Clock>
+ std::vector<FloatDuration<Clock>> run(const IConfig &cfg, Environment<FloatDuration<Clock>> env) const {
+ // warmup a bit
+ Detail::run_for_at_least<Clock>(std::chrono::duration_cast<ClockDuration<Clock>>(warmup_time), warmup_iterations, Detail::repeat(now<Clock>{}));
+
+ std::vector<FloatDuration<Clock>> times;
+ times.reserve(cfg.benchmarkSamples());
+ std::generate_n(std::back_inserter(times), cfg.benchmarkSamples(), [this, env] {
+ Detail::ChronometerModel<Clock> model;
+ this->benchmark(Chronometer(model, iterations_per_sample));
+ auto sample_time = model.elapsed() - env.clock_cost.mean;
+ if (sample_time < FloatDuration<Clock>::zero()) sample_time = FloatDuration<Clock>::zero();
+ return sample_time / iterations_per_sample;
+ });
+ return times;
+ }
+ };
+ } // namespace Benchmark
+} // namespace Catch
+
+#endif // TWOBLUECUBES_CATCH_EXECUTION_PLAN_HPP_INCLUDED
diff --git a/include/internal/benchmark/catch_optimizer.hpp b/include/internal/benchmark/catch_optimizer.hpp
new file mode 100644
index 00000000..bda7c6d7
--- /dev/null
+++ b/include/internal/benchmark/catch_optimizer.hpp
@@ -0,0 +1,68 @@
+/*
+ * Created by Joachim on 16/04/2019.
+ * Adapted from donated nonius code.
+ *
+ * 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)
+ */
+
+ // Hinting the optimizer
+
+#ifndef TWOBLUECUBES_CATCH_OPTIMIZER_HPP_INCLUDED
+#define TWOBLUECUBES_CATCH_OPTIMIZER_HPP_INCLUDED
+
+#if defined(_MSC_VER)
+# include <atomic> // atomic_thread_fence
+#endif
+
+namespace Catch {
+ namespace Benchmark {
+#if defined(__GNUC__) || defined(__clang__)
+ template <typename T>
+ inline void keep_memory(T* p) {
+ asm volatile("" : : "g"(p) : "memory");
+ }
+ inline void keep_memory() {
+ asm volatile("" : : : "memory");
+ }
+
+ namespace Detail {
+ inline void optimizer_barrier() { keep_memory(); }
+ } // namespace Detail
+#elif defined(_MSC_VER)
+
+#pragma optimize("", off)
+ template <typename T>
+ inline void keep_memory(T* p) {
+ // thanks @milleniumbug
+ *reinterpret_cast<char volatile*>(p) = *reinterpret_cast<char const volatile*>(p);
+ }
+ // TODO equivalent keep_memory()
+#pragma optimize("", on)
+
+ namespace Detail {
+ inline void optimizer_barrier() {
+ std::atomic_thread_fence(std::memory_order_seq_cst);
+ }
+ } // namespace Detail
+
+#endif
+
+ template <typename T>
+ inline void deoptimize_value(T&& x) {
+ keep_memory(&x);
+ }
+
+ template <typename Fn, typename... Args>
+ inline auto invoke_deoptimized(Fn&& fn, Args&&... args) -> typename std::enable_if<!std::is_same<void, decltype(fn(args...))>::value>::type {
+ deoptimize_value(std::forward<Fn>(fn) (std::forward<Args...>(args...)));
+ }
+
+ template <typename Fn, typename... Args>
+ inline auto invoke_deoptimized(Fn&& fn, Args&&... args) -> typename std::enable_if<std::is_same<void, decltype(fn(args...))>::value>::type {
+ std::forward<Fn>(fn) (std::forward<Args...>(args...));
+ }
+ } // namespace Benchmark
+} // namespace Catch
+
+#endif // TWOBLUECUBES_CATCH_OPTIMIZER_HPP_INCLUDED
diff --git a/include/internal/benchmark/catch_outlier_classification.hpp b/include/internal/benchmark/catch_outlier_classification.hpp
new file mode 100644
index 00000000..66a0adf5
--- /dev/null
+++ b/include/internal/benchmark/catch_outlier_classification.hpp
@@ -0,0 +1,29 @@
+/*
+ * Created by Joachim on 16/04/2019.
+ * Adapted from donated nonius code.
+ *
+ * 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)
+ */
+
+// Outlier information
+#ifndef TWOBLUECUBES_CATCH_OUTLIERS_HPP_INCLUDED
+#define TWOBLUECUBES_CATCH_OUTLIERS_HPP_INCLUDED
+
+namespace Catch {
+ namespace Benchmark {
+ struct OutlierClassification {
+ int samples_seen = 0;
+ int low_severe = 0; // more than 3 times IQR below Q1
+ int low_mild = 0; // 1.5 to 3 times IQR below Q1
+ int high_mild = 0; // 1.5 to 3 times IQR above Q3
+ int high_severe = 0; // more than 3 times IQR above Q3
+
+ int total() const {
+ return low_severe + low_mild + high_mild + high_severe;
+ }
+ };
+ } // namespace Benchmark
+} // namespace Catch
+
+#endif // TWOBLUECUBES_CATCH_OUTLIERS_HPP_INCLUDED
diff --git a/include/internal/benchmark/catch_sample_analysis.hpp b/include/internal/benchmark/catch_sample_analysis.hpp
new file mode 100644
index 00000000..4550d0bc
--- /dev/null
+++ b/include/internal/benchmark/catch_sample_analysis.hpp
@@ -0,0 +1,50 @@
+/*
+ * Created by Joachim on 16/04/2019.
+ * Adapted from donated nonius code.
+ *
+ * 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)
+ */
+
+// Benchmark results
+
+#ifndef TWOBLUECUBES_CATCH_BENCHMARK_RESULTS_HPP_INCLUDED
+#define TWOBLUECUBES_CATCH_BENCHMARK_RESULTS_HPP_INCLUDED
+
+#include "catch_clock.hpp"
+#include "catch_estimate.hpp"
+#include "catch_outlier_classification.hpp"
+
+#include <algorithm>
+#include <vector>
+#include <string>
+#include <iterator>
+
+namespace Catch {
+ namespace Benchmark {
+ template <typename Duration>
+ struct SampleAnalysis {
+ std::vector<Duration> samples;
+ Estimate<Duration> mean;
+ Estimate<Duration> standard_deviation;
+ OutlierClassification outliers;
+ double outlier_variance;
+
+ template <typename Duration2>
+ operator SampleAnalysis<Duration2>() const {
+ std::vector<Duration2> samples2;
+ samples2.reserve(samples.size());
+ std::transform(samples.begin(), samples.end(), std::back_inserter(samples2), [](Duration d) { return Duration2(d); });
+ return {
+ std::move(samples2),
+ mean,
+ standard_deviation,
+ outliers,
+ outlier_variance,
+ };
+ }
+ };
+ } // namespace Benchmark
+} // namespace Catch
+
+#endif // TWOBLUECUBES_CATCH_BENCHMARK_RESULTS_HPP_INCLUDED
diff --git a/include/internal/benchmark/detail/catch_analyse.hpp b/include/internal/benchmark/detail/catch_analyse.hpp
new file mode 100644
index 00000000..a3becbe4
--- /dev/null
+++ b/include/internal/benchmark/detail/catch_analyse.hpp
@@ -0,0 +1,78 @@
+/*
+ * Created by Joachim on 16/04/2019.
+ * Adapted from donated nonius code.
+ *
+ * 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)
+ */
+
+ // Run and analyse one benchmark
+
+#ifndef TWOBLUECUBES_CATCH_DETAIL_ANALYSE_HPP_INCLUDED
+#define TWOBLUECUBES_CATCH_DETAIL_ANALYSE_HPP_INCLUDED
+
+#include "../catch_clock.hpp"
+#include "../catch_sample_analysis.hpp"
+#include "catch_stats.hpp"
+
+#include <algorithm>
+#include <iterator>
+#include <vector>
+
+namespace Catch {
+ namespace Benchmark {
+ namespace Detail {
+ template <typename Duration, typename Iterator>
+ SampleAnalysis<Duration> analyse(const IConfig &cfg, Environment<Duration>, Iterator first, Iterator last) {
+ if (!cfg.benchmarkNoAnalysis()) {
+ std::vector<double> samples;
+ samples.reserve(last - first);
+ std::transform(first, last, std::back_inserter(samples), [](Duration d) { return d.count(); });
+
+ auto analysis = Catch::Benchmark::Detail::analyse_samples(cfg.benchmarkConfidenceInterval(), cfg.benchmarkResamples(), samples.begin(), samples.end());
+ auto outliers = Catch::Benchmark::Detail::classify_outliers(samples.begin(), samples.end());
+
+ auto wrap_estimate = [](Estimate<double> e) {
+ return Estimate<Duration> {
+ Duration(e.point),
+ Duration(e.lower_bound),
+ Duration(e.upper_bound),
+ e.confidence_interval,
+ };
+ };
+ std::vector<Duration> samples2;
+ samples2.reserve(samples.size());
+ std::transform(samples.begin(), samples.end(), std::back_inserter(samples2), [](double d) { return Duration(d); });
+ return {
+ std::move(samples2),
+ wrap_estimate(analysis.mean),
+ wrap_estimate(analysis.standard_deviation),
+ outliers,
+ analysis.outlier_variance,
+ };
+ } else {
+ std::vector<Duration> samples;
+ samples.reserve(last - first);
+
+ Duration mean = Duration(0);
+ int i = 0;
+ for (auto it = first; it < last; ++it, ++i) {
+ samples.push_back(Duration(*it));
+ mean += Duration(*it);
+ }
+ mean /= i;
+
+ return {
+ std::move(samples),
+ Estimate<Duration>{mean, mean, mean, 0.0},
+ Estimate<Duration>{Duration(0), Duration(0), Duration(0), 0.0},
+ OutlierClassification{},
+ 0.0
+ };
+ }
+ }
+ } // namespace Detail
+ } // namespace Benchmark
+} // namespace Catch
+
+#endif // TWOBLUECUBES_CATCH_DETAIL_ANALYSE_HPP_INCLUDED
diff --git a/include/internal/benchmark/detail/catch_benchmark_function.hpp b/include/internal/benchmark/detail/catch_benchmark_function.hpp
new file mode 100644
index 00000000..60c7f1d6
--- /dev/null
+++ b/include/internal/benchmark/detail/catch_benchmark_function.hpp
@@ -0,0 +1,105 @@
+ /*
+ * Created by Joachim on 16/04/2019.
+ * Adapted from donated nonius code.
+ *
+ * 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)
+ */
+
+ // Dumb std::function implementation for consistent call overhead
+
+#ifndef TWOBLUECUBES_CATCH_DETAIL_BENCHMARK_FUNCTION_HPP_INCLUDED
+#define TWOBLUECUBES_CATCH_DETAIL_BENCHMARK_FUNCTION_HPP_INCLUDED
+
+#include "../catch_chronometer.hpp"
+#include "catch_complete_invoke.hpp"
+#include "../../catch_meta.hpp"
+
+#include <cassert>
+#include <type_traits>
+#include <utility>
+#include <memory>
+
+namespace Catch {
+ namespace Benchmark {
+ namespace Detail {
+ template <typename T>
+ using Decay = typename std::decay<T>::type;
+ template <typename T, typename U>
+ struct is_related
+ : std::is_same<Decay<T>, Decay<U>> {};
+
+ /// We need to reinvent std::function because every piece of code that might add overhead
+ /// in a measurement context needs to have consistent performance characteristics so that we
+ /// can account for it in the measurement.
+ /// Implementations of std::function with optimizations that aren't always applicable, like
+ /// small buffer optimizations, are not uncommon.
+ /// This is effectively an implementation of std::function without any such optimizations;
+ /// it may be slow, but it is consistently slow.
+ struct BenchmarkFunction {
+ private:
+ struct callable {
+ virtual void call(Chronometer meter) const = 0;
+ virtual callable* clone() const = 0;
+ virtual ~callable() = default;
+ };
+ template <typename Fun>
+ struct model : public callable {
+ model(Fun&& fun) : fun(std::move(fun)) {}
+ model(Fun const& fun) : fun(fun) {}
+
+ model<Fun>* clone() const override { return new model<Fun>(*this); }
+
+ void call(Chronometer meter) const override {
+ call(meter, is_callable<Fun(Chronometer)>());
+ }
+ void call(Chronometer meter, std::true_type) const {
+ fun(meter);
+ }
+ void call(Chronometer meter, std::false_type) const {
+ meter.measure(fun);
+ }
+
+ Fun fun;
+ };
+
+ struct do_nothing { void operator()() const {} };
+
+ template <typename T>
+ BenchmarkFunction(model<T>* c) : f(c) {}
+
+ public:
+ BenchmarkFunction()
+ : f(new model<do_nothing>{ {} }) {}
+
+ template <typename Fun,
+ typename std::enable_if<!is_related<Fun, BenchmarkFunction>::value, int>::type = 0>
+ BenchmarkFunction(Fun&& fun)
+ : f(new model<typename std::decay<Fun>::type>(std::forward<Fun>(fun))) {}
+
+ BenchmarkFunction(BenchmarkFunction&& that)
+ : f(std::move(that.f)) {}
+
+ BenchmarkFunction(BenchmarkFunction const& that)
+ : f(that.f->clone()) {}
+
+ BenchmarkFunction& operator=(BenchmarkFunction&& that) {
+ f = std::move(that.f);
+ return *this;
+ }
+
+ BenchmarkFunction& operator=(BenchmarkFunction const& that) {
+ f.reset(that.f->clone());
+ return *this;
+ }
+
+ void operator()(Chronometer meter) const { f->call(meter); }
+
+ private:
+ std::unique_ptr<callable> f;
+ };
+ } // namespace Detail
+ } // namespace Benchmark
+} // namespace Catch
+
+#endif // TWOBLUECUBES_CATCH_DETAIL_BENCHMARK_FUNCTION_HPP_INCLUDED
diff --git a/include/internal/benchmark/detail/catch_complete_invoke.hpp b/include/internal/benchmark/detail/catch_complete_invoke.hpp
new file mode 100644
index 00000000..abeb2ac7
--- /dev/null
+++ b/include/internal/benchmark/detail/catch_complete_invoke.hpp
@@ -0,0 +1,69 @@
+/*
+ * Created by Joachim on 16/04/2019.
+ * Adapted from donated nonius code.
+ *
+ * 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)
+ */
+
+// Invoke with a special case for void
+
+#ifndef TWOBLUECUBES_CATCH_DETAIL_COMPLETE_INVOKE_HPP_INCLUDED
+#define TWOBLUECUBES_CATCH_DETAIL_COMPLETE_INVOKE_HPP_INCLUDED
+
+#include "../../catch_enforce.h"
+
+#include <type_traits>
+#include <utility>
+
+namespace Catch {
+ namespace Benchmark {
+ namespace Detail {
+ template <typename T>
+ struct CompleteType { using type = T; };
+ template <>
+ struct CompleteType<void> { struct type {}; };
+
+ template <typename T>
+ using CompleteType_t = typename CompleteType<T>::type;
+
+ template <typename Result>
+ struct CompleteInvoker {
+ template <typename Fun, typename... Args>
+ static Result invoke(Fun&& fun, Args&&... args) {
+ return std::forward<Fun>(fun)(std::forward<Args>(args)...);
+ }
+ };
+ template <>
+ struct CompleteInvoker<void> {
+ template <typename Fun, typename... Args>
+ static CompleteType_t<void> invoke(Fun&& fun, Args&&... args) {
+ std::forward<Fun>(fun)(std::forward<Args>(args)...);
+ return {};
+ }
+ };
+ template <typename Sig>
+ using ResultOf_t = typename std::result_of<Sig>::type;
+
+ // invoke and not return void :(
+ template <typename Fun, typename... Args>
+ CompleteType_t<ResultOf_t<Fun(Args...)>> complete_invoke(Fun&& fun, Args&&... args) {
+ return CompleteInvoker<ResultOf_t<Fun(Args...)>>::invoke(std::forward<Fun>(fun), std::forward<Args>(args)...);
+ }
+
+ const std::string benchmarkErrorMsg = "a benchmark failed to run successfully";
+ } // namespace Detail
+
+ template <typename Fun>
+ Detail::CompleteType_t<Detail::ResultOf_t<Fun()>> user_code(Fun&& fun) {
+ CATCH_TRY{
+ return Detail::complete_invoke(std::forward<Fun>(fun));
+ } CATCH_CATCH_ALL{
+ getResultCapture().benchmarkFailed(translateActiveException());
+ CATCH_RUNTIME_ERROR(Detail::benchmarkErrorMsg);
+ }
+ }
+ } // namespace Benchmark
+} // namespace Catch
+
+#endif // TWOBLUECUBES_CATCH_DETAIL_COMPLETE_INVOKE_HPP_INCLUDED
diff --git a/include/internal/benchmark/detail/catch_estimate_clock.hpp b/include/internal/benchmark/detail/catch_estimate_clock.hpp
new file mode 100644
index 00000000..055c5825
--- /dev/null
+++ b/include/internal/benchmark/detail/catch_estimate_clock.hpp
@@ -0,0 +1,113 @@
+/*
+ * Created by Joachim on 16/04/2019.
+ * Adapted from donated nonius code.
+ *
+ * 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)
+ */
+
+ // Environment measurement
+
+#ifndef TWOBLUECUBES_CATCH_DETAIL_ESTIMATE_CLOCK_HPP_INCLUDED
+#define TWOBLUECUBES_CATCH_DETAIL_ESTIMATE_CLOCK_HPP_INCLUDED
+
+#include "../catch_clock.hpp"
+#include "../catch_environment.hpp"
+#include "catch_stats.hpp"
+#include "catch_measure.hpp"
+#include "catch_run_for_at_least.hpp"
+#include "../catch_clock.hpp"
+
+#include <algorithm>
+#include <iterator>
+#include <tuple>
+#include <vector>
+#include <cmath>
+
+namespace Catch {
+ namespace Benchmark {
+ namespace Detail {
+ template <typename Clock>
+ std::vector<double> resolution(int k) {
+ std::vector<TimePoint<Clock>> times;
+ times.reserve(k + 1);
+ std::generate_n(std::back_inserter(times), k + 1, now<Clock>{});
+
+ std::vector<double> deltas;
+ deltas.reserve(k);
+ std::transform(std::next(times.begin()), times.end(), times.begin(),
+ std::back_inserter(deltas),
+ [](TimePoint<Clock> a, TimePoint<Clock> b) { return static_cast<double>((a - b).count()); });
+
+ return deltas;
+ }
+
+ const auto warmup_iterations = 10000;
+ const auto warmup_time = std::chrono::milliseconds(100);
+ const auto minimum_ticks = 1000;
+ const auto warmup_seed = 10000;
+ const auto clock_resolution_estimation_time = std::chrono::milliseconds(500);
+ const auto clock_cost_estimation_time_limit = std::chrono::seconds(1);
+ const auto clock_cost_estimation_tick_limit = 100000;
+ const auto clock_cost_estimation_time = std::chrono::milliseconds(10);
+ const auto clock_cost_estimation_iterations = 10000;
+
+ template <typename Clock>
+ int warmup() {
+ return run_for_at_least<Clock>(std::chrono::duration_cast<ClockDuration<Clock>>(warmup_time), warmup_seed, &resolution<Clock>)
+ .iterations;
+ }
+ template <typename Clock>
+ EnvironmentEstimate<FloatDuration<Clock>> estimate_clock_resolution(int iterations) {
+ auto r = run_for_at_least<Clock>(std::chrono::duration_cast<ClockDuration<Clock>>(clock_resolution_estimation_time), iterations, &resolution<Clock>)
+ .result;
+ return {
+ FloatDuration<Clock>(mean(r.begin(), r.end())),
+ classify_outliers(r.begin(), r.end()),
+ };
+ }
+ template <typename Clock>
+ EnvironmentEstimate<FloatDuration<Clock>> estimate_clock_cost(FloatDuration<Clock> resolution) {
+ auto time_limit = std::min(resolution * clock_cost_estimation_tick_limit, FloatDuration<Clock>(clock_cost_estimation_time_limit));
+ auto time_clock = [](int k) {
+ return Detail::measure<Clock>([k] {
+ for (int i = 0; i < k; ++i) {
+ volatile auto ignored = Clock::now();
+ (void)ignored;
+ }
+ }).elapsed;
+ };
+ time_clock(1);
+ int iters = clock_cost_estimation_iterations;
+ auto&& r = run_for_at_least<Clock>(std::chrono::duration_cast<ClockDuration<Clock>>(clock_cost_estimation_time), iters, time_clock);
+ std::vector<double> times;
+ int nsamples = static_cast<int>(std::ceil(time_limit / r.elapsed));
+ times.reserve(nsamples);
+ std::generate_n(std::back_inserter(times), nsamples, [time_clock, &r] {
+ return static_cast<double>((time_clock(r.iterations) / r.iterations).count());
+ });
+ return {
+ FloatDuration<Clock>(mean(times.begin(), times.end())),
+ classify_outliers(times.begin(), times.end()),
+ };
+ }
+
+ template <typename Clock>
+ Environment<FloatDuration<Clock>> measure_environment() {
+ static Environment<FloatDuration<Clock>>* env = nullptr;
+ if (env) {
+ return *env;
+ }
+
+ auto iters = Detail::warmup<Clock>();
+ auto resolution = Detail::estimate_clock_resolution<Clock>(iters);
+ auto cost = Detail::estimate_clock_cost<Clock>(resolution.mean);
+
+ env = new Environment<FloatDuration<Clock>>{ resolution, cost };
+ return *env;
+ }
+ } // namespace Detail
+ } // namespace Benchmark
+} // namespace Catch
+
+#endif // TWOBLUECUBES_CATCH_DETAIL_ESTIMATE_CLOCK_HPP_INCLUDED
diff --git a/include/internal/benchmark/detail/catch_measure.hpp b/include/internal/benchmark/detail/catch_measure.hpp
new file mode 100644
index 00000000..62ed2809
--- /dev/null
+++ b/include/internal/benchmark/detail/catch_measure.hpp
@@ -0,0 +1,35 @@
+/*
+ * Created by Joachim on 16/04/2019.
+ * Adapted from donated nonius code.
+ *
+ * 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)
+ */
+
+// Measure
+
+#ifndef TWOBLUECUBES_CATCH_DETAIL_MEASURE_HPP_INCLUDED
+#define TWOBLUECUBES_CATCH_DETAIL_MEASURE_HPP_INCLUDED
+
+#include "../catch_clock.hpp"
+#include "catch_complete_invoke.hpp"
+#include "catch_timing.hpp"
+
+#include <utility>
+
+namespace Catch {
+ namespace Benchmark {
+ namespace Detail {
+ template <typename Clock, typename Fun, typename... Args>
+ TimingOf<Clock, Fun(Args...)> measure(Fun&& fun, Args&&... args) {
+ auto start = Clock::now();
+ auto&& r = Detail::complete_invoke(fun, std::forward<Args>(args)...);
+ auto end = Clock::now();
+ auto delta = end - start;
+ return { delta, std::forward<decltype(r)>(r), 1 };
+ }
+ } // namespace Detail
+ } // namespace Benchmark
+} // namespace Catch
+
+#endif // TWOBLUECUBES_CATCH_DETAIL_MEASURE_HPP_INCLUDED
diff --git a/include/internal/benchmark/detail/catch_repeat.hpp b/include/internal/benchmark/detail/catch_repeat.hpp
new file mode 100644
index 00000000..ab240792
--- /dev/null
+++ b/include/internal/benchmark/detail/catch_repeat.hpp
@@ -0,0 +1,37 @@
+/*
+ * Created by Joachim on 16/04/2019.
+ * Adapted from donated nonius code.
+ *
+ * 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)
+ */
+
+// repeat algorithm
+
+#ifndef TWOBLUECUBES_CATCH_DETAIL_REPEAT_HPP_INCLUDED
+#define TWOBLUECUBES_CATCH_DETAIL_REPEAT_HPP_INCLUDED
+
+#include <type_traits>
+#include <utility>
+
+namespace Catch {
+ namespace Benchmark {
+ namespace Detail {
+ template <typename Fun>
+ struct repeater {
+ void operator()(int k) const {
+ for (int i = 0; i < k; ++i) {
+ fun();
+ }
+ }
+ Fun fun;
+ };
+ template <typename Fun>
+ repeater<typename std::decay<Fun>::type> repeat(Fun&& fun) {
+ return { std::forward<Fun>(fun) };
+ }
+ } // namespace Detail
+ } // namespace Benchmark
+} // namespace Catch
+
+#endif // TWOBLUECUBES_CATCH_DETAIL_REPEAT_HPP_INCLUDED
diff --git a/include/internal/benchmark/detail/catch_run_for_at_least.hpp b/include/internal/benchmark/detail/catch_run_for_at_least.hpp
new file mode 100644
index 00000000..a41c6b46
--- /dev/null
+++ b/include/internal/benchmark/detail/catch_run_for_at_least.hpp
@@ -0,0 +1,65 @@
+/*
+ * Created by Joachim on 16/04/2019.
+ * Adapted from donated nonius code.
+ *
+ * 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)
+ */
+
+// Run a function for a minimum amount of time
+
+#ifndef TWOBLUECUBES_CATCH_RUN_FOR_AT_LEAST_HPP_INCLUDED
+#define TWOBLUECUBES_CATCH_RUN_FOR_AT_LEAST_HPP_INCLUDED
+
+#include "../catch_clock.hpp"
+#include "../catch_chronometer.hpp"
+#include "catch_measure.hpp"
+#include "catch_complete_invoke.hpp"
+#include "catch_timing.hpp"
+#include "../../catch_meta.hpp"
+
+#include <utility>
+#include <type_traits>
+
+namespace Catch {
+ namespace Benchmark {
+ namespace Detail {
+ template <typename Clock, typename Fun>
+ TimingOf<Clock, Fun(int)> measure_one(Fun&& fun, int iters, std::false_type) {
+ return Detail::measure<Clock>(fun, iters);
+ }
+ template <typename Clock, typename Fun>
+ TimingOf<Clock, Fun(Chronometer)> measure_one(Fun&& fun, int iters, std::true_type) {
+ Detail::ChronometerModel<Clock> meter;
+ auto&& result = Detail::complete_invoke(fun, Chronometer(meter, iters));
+
+ return { meter.elapsed(), std::move(result), iters };
+ }
+
+ template <typename Clock, typename Fun>
+ using run_for_at_least_argument_t = typename std::conditional<is_callable<Fun(Chronometer)>::value, Chronometer, int>::type;
+
+ struct optimized_away_error : std::exception {
+ const char* what() const noexcept override {
+ return "could not measure benchmark, maybe it was optimized away";
+ }
+ };
+
+ template <typename Clock, typename Fun>
+ TimingOf<Clock, Fun(run_for_at_least_argument_t<Clock, Fun>)> run_for_at_least(ClockDuration<Clock> how_long, int seed, Fun&& fun) {
+ auto iters = seed;
+ while (iters < (1 << 30)) {
+ auto&& Timing = measure_one<Clock>(fun, iters, is_callable<Fun(Chronometer)>());
+
+ if (Timing.elapsed >= how_long) {
+ return { Timing.elapsed, std::move(Timing.result), iters };
+ }
+ iters *= 2;
+ }
+ throw optimized_away_error{};
+ }
+ } // namespace Detail
+ } // namespace Benchmark
+} // namespace Catch
+
+#endif // TWOBLUECUBES_CATCH_RUN_FOR_AT_LEAST_HPP_INCLUDED
diff --git a/include/internal/benchmark/detail/catch_stats.cpp b/include/internal/benchmark/detail/catch_stats.cpp
new file mode 100644
index 00000000..b85b740e
--- /dev/null
+++ b/include/internal/benchmark/detail/catch_stats.cpp
@@ -0,0 +1,224 @@
+/*
+ * Created by Martin on 15/06/2019.
+ * Adapted from donated nonius code.
+ *
+ * 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)
+ */
+
+// Statistical analysis tools
+
+#if defined(CATCH_CONFIG_ENABLE_BENCHMARKING)
+
+#include "catch_stats.hpp"
+
+#include "../../catch_compiler_capabilities.h"
+
+#include <cassert>
+#include <random>
+
+
+#if defined(CATCH_CONFIG_USE_ASYNC)
+#include <future>
+#endif
+
+namespace {
+ double erf_inv(double x) {
+ // Code accompanying the article "Approximating the erfinv function" in GPU Computing Gems, Volume 2
+ double w, p;
+
+ w = -log((1.0 - x) * (1.0 + x));
+
+ if (w < 6.250000) {
+ w = w - 3.125000;
+ p = -3.6444120640178196996e-21;
+ p = -1.685059138182016589e-19 + p * w;
+ p = 1.2858480715256400167e-18 + p * w;
+ p = 1.115787767802518096e-17 + p * w;
+ p = -1.333171662854620906e-16 + p * w;
+ p = 2.0972767875968561637e-17 + p * w;
+ p = 6.6376381343583238325e-15 + p * w;
+ p = -4.0545662729752068639e-14 + p * w;
+ p = -8.1519341976054721522e-14 + p * w;
+ p = 2.6335093153082322977e-12 + p * w;
+ p = -1.2975133253453532498e-11 + p * w;
+ p = -5.4154120542946279317e-11 + p * w;
+ p = 1.051212273321532285e-09 + p * w;
+ p = -4.1126339803469836976e-09 + p * w;
+ p = -2.9070369957882005086e-08 + p * w;
+ p = 4.2347877827932403518e-07 + p * w;
+ p = -1.3654692000834678645e-06 + p * w;
+ p = -1.3882523362786468719e-05 + p * w;
+ p = 0.0001867342080340571352 + p * w;
+ p = -0.00074070253416626697512 + p * w;
+ p = -0.0060336708714301490533 + p * w;
+ p = 0.24015818242558961693 + p * w;
+ p = 1.6536545626831027356 + p * w;
+ } else if (w < 16.000000) {
+ w = sqrt(w) - 3.250000;
+ p = 2.2137376921775787049e-09;
+ p = 9.0756561938885390979e-08 + p * w;
+ p = -2.7517406297064545428e-07 + p * w;
+ p = 1.8239629214389227755e-08 + p * w;
+ p = 1.5027403968909827627e-06 + p * w;
+ p = -4.013867526981545969e-06 + p * w;
+ p = 2.9234449089955446044e-06 + p * w;
+ p = 1.2475304481671778723e-05 + p * w;
+ p = -4.7318229009055733981e-05 + p * w;
+ p = 6.8284851459573175448e-05 + p * w;
+ p = 2.4031110387097893999e-05 + p * w;
+ p = -0.0003550375203628474796 + p * w;
+ p = 0.00095328937973738049703 + p * w;
+ p = -0.0016882755560235047313 + p * w;
+ p = 0.0024914420961078508066 + p * w;
+ p = -0.0037512085075692412107 + p * w;
+ p = 0.005370914553590063617 + p * w;
+ p = 1.0052589676941592334 + p * w;
+ p = 3.0838856104922207635 + p * w;
+ } else {
+ w = sqrt(w) - 5.000000;
+ p = -2.7109920616438573243e-11;
+ p = -2.5556418169965252055e-10 + p * w;
+ p = 1.5076572693500548083e-09 + p * w;
+ p = -3.7894654401267369937e-09 + p * w;
+ p = 7.6157012080783393804e-09 + p * w;
+ p = -1.4960026627149240478e-08 + p * w;
+ p = 2.9147953450901080826e-08 + p * w;
+ p = -6.7711997758452339498e-08 + p * w;
+ p = 2.2900482228026654717e-07 + p * w;
+ p = -9.9298272942317002539e-07 + p * w;
+ p = 4.5260625972231537039e-06 + p * w;
+ p = -1.9681778105531670567e-05 + p * w;
+ p = 7.5995277030017761139e-05 + p * w;
+ p = -0.00021503011930044477347 + p * w;
+ p = -0.00013871931833623122026 + p * w;
+ p = 1.0103004648645343977 + p * w;
+ p = 4.8499064014085844221 + p * w;
+ }
+ return p * x;
+ }
+
+ double standard_deviation(std::vector<double>::iterator first, std::vector<double>::iterator last) {
+ auto m = Catch::Benchmark::Detail::mean(first, last);
+ double variance = std::accumulate(first, last, 0., [m](double a, double b) {
+ double diff = b - m;
+ return a + diff * diff;
+ }) / (last - first);
+ return std::sqrt(variance);
+ }
+
+}
+
+namespace Catch {
+ namespace Benchmark {
+ namespace Detail {
+
+ double weighted_average_quantile(int k, int q, std::vector<double>::iterator first, std::vector<double>::iterator last) {
+ auto count = last - first;
+ double idx = (count - 1) * k / static_cast<double>(q);
+ int j = static_cast<int>(idx);
+ double g = idx - j;
+ std::nth_element(first, first + j, last);
+ auto xj = first[j];
+ if (g == 0) return xj;
+
+ auto xj1 = *std::min_element(first + (j + 1), last);
+ return xj + g * (xj1 - xj);
+ }
+
+
+ double erfc_inv(double x) {
+ return erf_inv(1.0 - x);
+ }
+
+ double normal_quantile(double p) {
+ static const double ROOT_TWO = std::sqrt(2.0);
+
+ double result = 0.0;
+ assert(p >= 0 && p <= 1);
+ if (p < 0 || p > 1) {
+ return result;
+ }
+
+ result = -erfc_inv(2.0 * p);
+ // result *= normal distribution standard deviation (1.0) * sqrt(2)
+ result *= /*sd * */ ROOT_TWO;
+ // result += normal disttribution mean (0)
+ return result;
+ }
+
+
+ double outlier_variance(Estimate<double> mean, Estimate<double> stddev, int n) {
+ double sb = stddev.point;
+ double mn = mean.point / n;
+ double mg_min = mn / 2.;
+ double sg = std::min(mg_min / 4., sb / std::sqrt(n));
+ double sg2 = sg * sg;
+ double sb2 = sb * sb;
+
+ auto c_max = [n, mn, sb2, sg2](double x) -> double {
+ double k = mn - x;
+ double d = k * k;
+ double nd = n * d;
+ double k0 = -n * nd;
+ double k1 = sb2 - n * sg2 + nd;
+ double det = k1 * k1 - 4 * sg2 * k0;
+ return (int)(-2. * k0 / (k1 + std::sqrt(det)));
+ };
+
+ auto var_out = [n, sb2, sg2](double c) {
+ double nc = n - c;
+ return (nc / n) * (sb2 - nc * sg2);
+ };
+
+ return std::min(var_out(1), var_out(std::min(c_max(0.), c_max(mg_min)))) / sb2;
+ }
+
+
+ bootstrap_analysis analyse_samples(double confidence_level, int n_resamples, std::vector<double>::iterator first, std::vector<double>::iterator last) {
+ CATCH_INTERNAL_START_WARNINGS_SUPPRESSION
+ CATCH_INTERNAL_SUPPRESS_GLOBALS_WARNINGS
+ static std::random_device entropy;
+ CATCH_INTERNAL_STOP_WARNINGS_SUPPRESSION
+
+ auto n = static_cast<int>(last - first); // seriously, one can't use integral types without hell in C++
+
+ auto mean = &Detail::mean<std::vector<double>::iterator>;
+ auto stddev = &standard_deviation;
+
+#if defined(CATCH_CONFIG_USE_ASYNC)
+ auto Estimate = [=](double(*f)(std::vector<double>::iterator, std::vector<double>::iterator)) {
+ auto seed = entropy();
+ return std::async(std::launch::async, [=] {
+ std::mt19937 rng(seed);
+ auto resampled = resample(rng, n_resamples, first, last, f);
+ return bootstrap(confidence_level, first, last, resampled, f);
+ });
+ };
+
+ auto mean_future = Estimate(mean);
+ auto stddev_future = Estimate(stddev);
+
+ auto mean_estimate = mean_future.get();
+ auto stddev_estimate = stddev_future.get();
+#else
+ auto Estimate = [=](double(*f)(std::vector<double>::iterator, std::vector<double>::iterator)) {
+ auto seed = entropy();
+ std::mt19937 rng(seed);
+ auto resampled = resample(rng, n_resamples, first, last, f);
+ return bootstrap(confidence_level, first, last, resampled, f);
+ };
+
+ auto mean_estimate = Estimate(mean);
+ auto stddev_estimate = Estimate(stddev);
+#endif // CATCH_USE_ASYNC
+
+ double outlier_variance = Detail::outlier_variance(mean_estimate, stddev_estimate, n);
+
+ return { mean_estimate, stddev_estimate, outlier_variance };
+ }
+ } // namespace Detail
+ } // namespace Benchmark
+} // namespace Catch
+
+#endif // CATCH_CONFIG_ENABLE_BENCHMARKING
diff --git a/include/internal/benchmark/detail/catch_stats.hpp b/include/internal/benchmark/detail/catch_stats.hpp
new file mode 100644
index 00000000..71a460d9
--- /dev/null
+++ b/include/internal/benchmark/detail/catch_stats.hpp
@@ -0,0 +1,160 @@
+/*
+ * Created by Joachim on 16/04/2019.
+ * Adapted from donated nonius code.
+ *
+ * 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)
+ */
+
+// Statistical analysis tools
+
+#ifndef TWOBLUECUBES_CATCH_DETAIL_ANALYSIS_HPP_INCLUDED
+#define TWOBLUECUBES_CATCH_DETAIL_ANALYSIS_HPP_INCLUDED
+
+#include "../catch_clock.hpp"
+#include "../catch_estimate.hpp"
+#include "../catch_outlier_classification.hpp"
+
+#include <algorithm>
+#include <functional>
+#include <vector>
+#include <iterator>
+#include <numeric>
+#include <tuple>
+#include <cmath>
+#include <utility>
+#include <cstddef>
+#include <random>
+
+namespace Catch {
+ namespace Benchmark {
+ namespace Detail {
+ using sample = std::vector<double>;
+
+ double weighted_average_quantile(int k, int q, std::vector<double>::iterator first, std::vector<double>::iterator last);
+
+ template <typename Iterator>
+ OutlierClassification classify_outliers(Iterator first, Iterator last) {
+ std::vector<double> copy(first, last);
+
+ auto q1 = weighted_average_quantile(1, 4, copy.begin(), copy.end());
+ auto q3 = weighted_average_quantile(3, 4, copy.begin(), copy.end());
+ auto iqr = q3 - q1;
+ auto los = q1 - (iqr * 3.);
+ auto lom = q1 - (iqr * 1.5);
+ auto him = q3 + (iqr * 1.5);
+ auto his = q3 + (iqr * 3.);
+
+ OutlierClassification o;
+ for (; first != last; ++first) {
+ auto&& t = *first;
+ if (t < los) ++o.low_severe;
+ else if (t < lom) ++o.low_mild;
+ else if (t > his) ++o.high_severe;
+ else if (t > him) ++o.high_mild;
+ ++o.samples_seen;
+ }
+ return o;
+ }
+
+ template <typename Iterator>
+ double mean(Iterator first, Iterator last) {
+ auto count = last - first;
+ double sum = std::accumulate(first, last, 0.);
+ return sum / count;
+ }
+
+ template <typename URng, typename Iterator, typename Estimator>
+ sample resample(URng& rng, int resamples, Iterator first, Iterator last, Estimator& estimator) {
+ auto n = last - first;
+ std::uniform_int_distribution<decltype(n)> dist(0, n - 1);
+
+ sample out;
+ out.reserve(resamples);
+ std::generate_n(std::back_inserter(out), resamples, [n, first, &estimator, &dist, &rng] {
+ std::vector<double> resampled;
+ resampled.reserve(n);
+ std::generate_n(std::back_inserter(resampled), n, [first, &dist, &rng] { return first[dist(rng)]; });
+ return estimator(resampled.begin(), resampled.end());
+ });
+ std::sort(out.begin(), out.end());
+ return out;
+ }
+
+ template <typename Estimator, typename Iterator>
+ sample jackknife(Estimator&& estimator, Iterator first, Iterator last) {
+ auto n = last - first;
+ auto second = std::next(first);
+ sample results;
+ results.reserve(n);
+
+ for (auto it = first; it != last; ++it) {
+ std::iter_swap(it, first);
+ results.push_back(estimator(second, last));
+ }
+
+ return results;
+ }
+
+ inline double normal_cdf(double x) {
+ return std::erfc(-x / std::sqrt(2.0)) / 2.0;
+ }
+
+ double erfc_inv(double x);
+
+ double normal_quantile(double p);
+
+ template <typename Iterator, typename Estimator>
+ Estimate<double> bootstrap(double confidence_level, Iterator first, Iterator last, sample const& resample, Estimator&& estimator) {
+ auto n_samples = last - first;
+
+ double point = estimator(first, last);
+ // Degenerate case with a single sample
+ if (n_samples == 1) return { point, point, point, confidence_level };
+
+ sample jack = jackknife(estimator, first, last);
+ double jack_mean = mean(jack.begin(), jack.end());
+ double sum_squares, sum_cubes;
+ std::tie(sum_squares, sum_cubes) = std::accumulate(jack.begin(), jack.end(), std::make_pair(0., 0.), [jack_mean](std::pair<double, double> sqcb, double x) -> std::pair<double, double> {
+ auto d = jack_mean - x;
+ auto d2 = d * d;
+ auto d3 = d2 * d;
+ return { sqcb.first + d2, sqcb.second + d3 };
+ });
+
+ double accel = sum_cubes / (6 * std::pow(sum_squares, 1.5));
+ int n = static_cast<int>(resample.size());
+ double prob_n = std::count_if(resample.begin(), resample.end(), [point](double x) { return x < point; }) / (double)n;
+ // degenerate case with uniform samples
+ if (prob_n == 0) return { point, point, point, confidence_level };
+
+ double bias = normal_quantile(prob_n);
+ double z1 = normal_quantile((1. - confidence_level) / 2.);
+
+ auto cumn = [n](double x) -> int {
+ return std::lround(normal_cdf(x) * n); };
+ auto a = [bias, accel](double b) { return bias + b / (1. - accel * b); };
+ double b1 = bias + z1;
+ double b2 = bias - z1;
+ double a1 = a(b1);
+ double a2 = a(b2);
+ auto lo = std::max(cumn(a1), 0);
+ auto hi = std::min(cumn(a2), n - 1);
+
+ return { point, resample[lo], resample[hi], confidence_level };
+ }
+
+ double outlier_variance(Estimate<double> mean, Estimate<double> stddev, int n);
+
+ struct bootstrap_analysis {
+ Estimate<double> mean;
+ Estimate<double> standard_deviation;
+ double outlier_variance;
+ };
+
+ bootstrap_analysis analyse_samples(double confidence_level, int n_resamples, std::vector<double>::iterator first, std::vector<double>::iterator last);
+ } // namespace Detail
+ } // namespace Benchmark
+} // namespace Catch
+
+#endif // TWOBLUECUBES_CATCH_DETAIL_ANALYSIS_HPP_INCLUDED
diff --git a/include/internal/benchmark/detail/catch_timing.hpp b/include/internal/benchmark/detail/catch_timing.hpp
new file mode 100644
index 00000000..073cb742
--- /dev/null
+++ b/include/internal/benchmark/detail/catch_timing.hpp
@@ -0,0 +1,33 @@
+/*
+ * Created by Joachim on 16/04/2019.
+ * Adapted from donated nonius code.
+ *
+ * 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)
+ */
+
+// Timing
+
+#ifndef TWOBLUECUBES_CATCH_DETAIL_TIMING_HPP_INCLUDED
+#define TWOBLUECUBES_CATCH_DETAIL_TIMING_HPP_INCLUDED
+
+#include "../catch_clock.hpp"
+#include "catch_complete_invoke.hpp"
+
+#include <tuple>
+#include <type_traits>
+
+namespace Catch {
+ namespace Benchmark {
+ template <typename Duration, typename Result>
+ struct Timing {
+ Duration elapsed;
+ Result result;
+ int iterations;
+ };
+ template <typename Clock, typename Sig>
+ using TimingOf = Timing<ClockDuration<Clock>, Detail::CompleteType_t<Detail::ResultOf_t<Sig>>>;
+ } // namespace Benchmark
+} // namespace Catch
+
+#endif // TWOBLUECUBES_CATCH_DETAIL_TIMING_HPP_INCLUDED
diff --git a/include/internal/catch_approx.cpp b/include/internal/catch_approx.cpp
index da7e4020..32b5e043 100644
--- a/include/internal/catch_approx.cpp
+++ b/include/internal/catch_approx.cpp
@@ -52,7 +52,8 @@ namespace Detail {
bool Approx::equalityComparisonImpl(const double other) const {
// First try with fixed margin, then compute margin based on epsilon, scale and Approx's value
// Thanks to Richard Harris for his help refining the scaled margin value
- return marginComparison(m_value, other, m_margin) || marginComparison(m_value, other, m_epsilon * (m_scale + std::fabs(m_value)));
+ return marginComparison(m_value, other, m_margin)
+ || marginComparison(m_value, other, m_epsilon * (m_scale + std::fabs(std::isinf(m_value)? 0 : m_value)));
}
void Approx::setMargin(double newMargin) {
diff --git a/include/internal/catch_assertionresult.cpp b/include/internal/catch_assertionresult.cpp
index 4ce07187..608a9add 100644
--- a/include/internal/catch_assertionresult.cpp
+++ b/include/internal/catch_assertionresult.cpp
@@ -45,7 +45,7 @@ namespace Catch {
}
bool AssertionResult::hasExpression() const {
- return m_info.capturedExpression[0] != 0;
+ return !m_info.capturedExpression.empty();
}
bool AssertionResult::hasMessage() const {
@@ -53,16 +53,22 @@ namespace Catch {
}
std::string AssertionResult::getExpression() const {
- if( isFalseTest( m_info.resultDisposition ) )
- return "!(" + m_info.capturedExpression + ")";
- else
- return m_info.capturedExpression;
+ // Possibly overallocating by 3 characters should be basically free
+ std::string expr; expr.reserve(m_info.capturedExpression.size() + 3);
+ if (isFalseTest(m_info.resultDisposition)) {
+ expr += "!(";
+ }
+ expr += m_info.capturedExpression;
+ if (isFalseTest(m_info.resultDisposition)) {
+ expr += ')';
+ }
+ return expr;
}
std::string AssertionResult::getExpressionInMacro() const {
std::string expr;
- if( m_info.macroName[0] == 0 )
- expr = m_info.capturedExpression;
+ if( m_info.macroName.empty() )
+ expr = static_cast<std::string>(m_info.capturedExpression);
else {
expr.reserve( m_info.macroName.size() + m_info.capturedExpression.size() + 4 );
expr += m_info.macroName;
diff --git a/include/internal/catch_benchmark.cpp b/include/internal/catch_benchmark.cpp
deleted file mode 100644
index 742418f7..00000000
--- a/include/internal/catch_benchmark.cpp
+++ /dev/null
@@ -1,36 +0,0 @@
-/*
- * Created by Phil on 04/07/2017.
- * 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)
- */
-
-#include "catch_benchmark.h"
-#include "catch_capture.hpp"
-#include "catch_interfaces_reporter.h"
-#include "catch_context.h"
-
-namespace Catch {
-
- auto BenchmarkLooper::getResolution() -> uint64_t {
- return getEstimatedClockResolution() * getCurrentContext().getConfig()->benchmarkResolutionMultiple();
- }
-
- void BenchmarkLooper::reportStart() {
- getResultCapture().benchmarkStarting( { m_name } );
- }
- auto BenchmarkLooper::needsMoreIterations() -> bool {
- auto elapsed = m_timer.getElapsedNanoseconds();
-
- // Exponentially increasing iterations until we're confident in our timer resolution
- if( elapsed < m_resolution ) {
- m_iterationsToRun *= 10;
- return true;
- }
-
- getResultCapture().benchmarkEnded( { { m_name }, m_count, elapsed } );
- return false;
- }
-
-} // end namespace Catch
diff --git a/include/internal/catch_benchmark.h b/include/internal/catch_benchmark.h
deleted file mode 100644
index e546713c..00000000
--- a/include/internal/catch_benchmark.h
+++ /dev/null
@@ -1,57 +0,0 @@
-/*
- * Created by Phil on 04/07/2017.
- * 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)
- */
-#ifndef TWOBLUECUBES_CATCH_BENCHMARK_H_INCLUDED
-#define TWOBLUECUBES_CATCH_BENCHMARK_H_INCLUDED
-
-#include "catch_stringref.h"
-#include "catch_timer.h"
-
-#include <cstdint>
-#include <string>
-
-namespace Catch {
-
- class BenchmarkLooper {
-
- std::string m_name;
- std::size_t m_count = 0;
- std::size_t m_iterationsToRun = 1;
- uint64_t m_resolution;
- Timer m_timer;
-
- static auto getResolution() -> uint64_t;
- public:
- // Keep most of this inline as it's on the code path that is being timed
- BenchmarkLooper( StringRef name )
- : m_name( name ),
- m_resolution( getResolution() )
- {
- reportStart();
- m_timer.start();
- }
-
- explicit operator bool() {
- if( m_count < m_iterationsToRun )
- return true;
- return needsMoreIterations();
- }
-
- void increment() {
- ++m_count;
- }
-
- void reportStart();
- auto needsMoreIterations() -> bool;
- };
-
-} // end namespace Catch
-
-#define BENCHMARK( name ) \
- for( Catch::BenchmarkLooper looper( name ); looper; looper.increment() )
-
-#endif // TWOBLUECUBES_CATCH_BENCHMARK_H_INCLUDED
diff --git a/include/internal/catch_capture.hpp b/include/internal/catch_capture.hpp
index 51fa0352..6b2f7727 100644
--- a/include/internal/catch_capture.hpp
+++ b/include/internal/catch_capture.hpp
@@ -41,15 +41,17 @@
///////////////////////////////////////////////////////////////////////////////
#define INTERNAL_CATCH_TEST( macroName, resultDisposition, ... ) \
do { \
+ /* The expression should not be evaluated, but warnings should hopefully be checked */ \
+ CATCH_INTERNAL_IGNORE_BUT_WARN(__VA_ARGS__); \
Catch::AssertionHandler catchAssertionHandler( macroName##_catch_sr, CATCH_INTERNAL_LINEINFO, CATCH_INTERNAL_STRINGIFY(__VA_ARGS__), resultDisposition ); \
INTERNAL_CATCH_TRY { \
+ CATCH_INTERNAL_START_WARNINGS_SUPPRESSION \
CATCH_INTERNAL_SUPPRESS_PARENTHESES_WARNINGS \
catchAssertionHandler.handleExpr( Catch::Decomposer() <= __VA_ARGS__ ); \
- CATCH_INTERNAL_UNSUPPRESS_PARENTHESES_WARNINGS \
+ CATCH_INTERNAL_STOP_WARNINGS_SUPPRESSION \
} INTERNAL_CATCH_CATCH( catchAssertionHandler ) \
INTERNAL_CATCH_REACT( catchAssertionHandler ) \
- } while( (void)0, (false) && static_cast<bool>( !!(__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 &&.
+ } while( false )
///////////////////////////////////////////////////////////////////////////////
#define INTERNAL_CATCH_IF( macroName, resultDisposition, ... ) \
diff --git a/include/internal/catch_capture_matchers.h b/include/internal/catch_capture_matchers.h
index 0ced01d5..5386e5e1 100644
--- a/include/internal/catch_capture_matchers.h
+++ b/include/internal/catch_capture_matchers.h
@@ -10,6 +10,7 @@
#include "catch_capture.hpp"
#include "catch_matchers.h"
+#include "catch_matchers_exception.hpp"
#include "catch_matchers_floating.h"
#include "catch_matchers_generic.hpp"
#include "catch_matchers_string.h"
diff --git a/include/internal/catch_commandline.cpp b/include/internal/catch_commandline.cpp
index 66759ebb..a4010850 100644
--- a/include/internal/catch_commandline.cpp
+++ b/include/internal/catch_commandline.cpp
@@ -49,9 +49,14 @@ namespace Catch {
if( !line.empty() && !startsWith( line, '#' ) ) {
if( !startsWith( line, '"' ) )
line = '"' + line + '"';
- config.testsOrTags.push_back( line + ',' );
+ config.testsOrTags.push_back( line );
+ config.testsOrTags.emplace_back( "," );
}
}
+ //Remove comma in the end
+ if(!config.testsOrTags.empty())
+ config.testsOrTags.erase( config.testsOrTags.end()-1 );
+
return ParserResult::ok( ParseResultType::Matched );
};
auto const setTestOrder = [&]( std::string const& order ) {
@@ -86,14 +91,16 @@ namespace Catch {
};
auto const setWaitForKeypress = [&]( std::string const& keypress ) {
auto keypressLc = toLower( keypress );
- if( keypressLc == "start" )
+ if (keypressLc == "never")
+ config.waitForKeypress = WaitForKeypress::Never;
+ else if( keypressLc == "start" )
config.waitForKeypress = WaitForKeypress::BeforeStart;
else if( keypressLc == "exit" )
config.waitForKeypress = WaitForKeypress::BeforeExit;
else if( keypressLc == "both" )
config.waitForKeypress = WaitForKeypress::BeforeStartAndExit;
else
- return ParserResult::runtimeError( "keypress argument must be one of: start, exit or both. '" + keypress + "' not recognised" );
+ return ParserResult::runtimeError( "keypress argument must be one of: never, start, exit or both. '" + keypress + "' not recognised" );
return ParserResult::ok( ParseResultType::Matched );
};
auto const setVerbosity = [&]( std::string const& verbosity ) {
@@ -193,13 +200,24 @@ namespace Catch {
| Opt( config.libIdentify )
["--libidentify"]
( "report name and version according to libidentify standard" )
- | Opt( setWaitForKeypress, "start|exit|both" )
+ | Opt( setWaitForKeypress, "never|start|exit|both" )
["--wait-for-keypress"]
( "waits for a keypress before exiting" )
- | Opt( config.benchmarkResolutionMultiple, "multiplier" )
- ["--benchmark-resolution-multiple"]
- ( "multiple of clock resolution to run benchmarks" )
-
+ | Opt( config.benchmarkSamples, "samples" )
+ ["--benchmark-samples"]
+ ( "number of samples to collect (default: 100)" )
+ | Opt( config.benchmarkResamples, "resamples" )
+ ["--benchmark-resamples"]
+ ( "number of resamples for the bootstrap (default: 100000)" )
+ | Opt( config.benchmarkConfidenceInterval, "confidence interval" )
+ ["--benchmark-confidence-interval"]
+ ( "confidence interval for the bootstrap (between 0 and 1, default: 0.95)" )
+ | Opt( config.benchmarkNoAnalysis )
+ ["--benchmark-no-analysis"]
+ ( "perform only measurements; do not perform any analysis" )
+ | Opt( config.benchmarkWarmupTime, "benchmarkWarmupTime" )
+ ["--benchmark-warmup-time"]
+ ( "amount of time in milliseconds spent on warming up each test (default: 100)" )
| Arg( config.testsOrTags, "test name|pattern|tags" )
( "which test or tests to use" );
diff --git a/include/internal/catch_common.cpp b/include/internal/catch_common.cpp
index b2fca4c4..790acbe5 100644
--- a/include/internal/catch_common.cpp
+++ b/include/internal/catch_common.cpp
@@ -15,9 +15,6 @@
namespace Catch {
- bool SourceLineInfo::empty() const noexcept {
- return file[0] == '\0';
- }
bool SourceLineInfo::operator == ( SourceLineInfo const& other ) const noexcept {
return line == other.line && (file == other.file || std::strcmp(file, other.file) == 0);
}
diff --git a/include/internal/catch_common.h b/include/internal/catch_common.h
index e4745622..5e097fbf 100644
--- a/include/internal/catch_common.h
+++ b/include/internal/catch_common.h
@@ -57,7 +57,7 @@ namespace Catch {
SourceLineInfo( SourceLineInfo&& ) noexcept = default;
SourceLineInfo& operator = ( SourceLineInfo&& ) noexcept = default;
- bool empty() const noexcept;
+ bool empty() const noexcept { return file[0] == '\0'; }
bool operator == ( SourceLineInfo const& other ) const noexcept;
bool operator < ( SourceLineInfo const& other ) const noexcept;
diff --git a/include/internal/catch_compiler_capabilities.h b/include/internal/catch_compiler_capabilities.h
index 012bf462..0ea76137 100644
--- a/include/internal/catch_compiler_capabilities.h
+++ b/include/internal/catch_compiler_capabilities.h
@@ -43,26 +43,39 @@
# define CATCH_INTERNAL_CONFIG_CPP17_UNCAUGHT_EXCEPTIONS
#endif
-#ifdef __clang__
-
-# define CATCH_INTERNAL_SUPPRESS_GLOBALS_WARNINGS \
- _Pragma( "clang diagnostic push" ) \
- _Pragma( "clang diagnostic ignored \"-Wexit-time-destructors\"" ) \
- _Pragma( "clang diagnostic ignored \"-Wglobal-constructors\"")
-# define CATCH_INTERNAL_UNSUPPRESS_GLOBALS_WARNINGS \
- _Pragma( "clang diagnostic pop" )
-
-# define CATCH_INTERNAL_SUPPRESS_PARENTHESES_WARNINGS \
- _Pragma( "clang diagnostic push" ) \
- _Pragma( "clang diagnostic ignored \"-Wparentheses\"" )
-# define CATCH_INTERNAL_UNSUPPRESS_PARENTHESES_WARNINGS \
- _Pragma( "clang diagnostic pop" )
-
-# define CATCH_INTERNAL_SUPPRESS_UNUSED_WARNINGS \
- _Pragma( "clang diagnostic push" ) \
- _Pragma( "clang diagnostic ignored \"-Wunused-variable\"" )
-# define CATCH_INTERNAL_UNSUPPRESS_UNUSED_WARNINGS \
- _Pragma( "clang diagnostic pop" )
+// We have to avoid both ICC and Clang, because they try to mask themselves
+// as gcc, and we want only GCC in this block
+#if defined(__GNUC__) && !defined(__clang__) && !defined(__ICC)
+# define CATCH_INTERNAL_START_WARNINGS_SUPPRESSION _Pragma( "GCC diagnostic push" )
+# define CATCH_INTERNAL_STOP_WARNINGS_SUPPRESSION _Pragma( "GCC diagnostic pop" )
+
+# define CATCH_INTERNAL_IGNORE_BUT_WARN(...) (void)__builtin_constant_p(__VA_ARGS__)
+
+#endif
+
+#if defined(__clang__)
+
+# define CATCH_INTERNAL_START_WARNINGS_SUPPRESSION _Pragma( "clang diagnostic push" )
+# define CATCH_INTERNAL_STOP_WARNINGS_SUPPRESSION _Pragma( "clang diagnostic pop" )
+
+# define CATCH_INTERNAL_IGNORE_BUT_WARN(...) (void)__builtin_constant_p(__VA_ARGS__)
+
+
+# define CATCH_INTERNAL_SUPPRESS_GLOBALS_WARNINGS \
+ _Pragma( "clang diagnostic ignored \"-Wexit-time-destructors\"" ) \
+ _Pragma( "clang diagnostic ignored \"-Wglobal-constructors\"")
+
+# define CATCH_INTERNAL_SUPPRESS_PARENTHESES_WARNINGS \
+ _Pragma( "clang diagnostic ignored \"-Wparentheses\"" )
+
+# define CATCH_INTERNAL_SUPPRESS_UNUSED_WARNINGS \
+ _Pragma( "clang diagnostic ignored \"-Wunused-variable\"" )
+
+# define CATCH_INTERNAL_SUPPRESS_ZERO_VARIADIC_WARNINGS \
+ _Pragma( "clang diagnostic ignored \"-Wgnu-zero-variadic-macro-arguments\"" )
+
+# define CATCH_INTERNAL_SUPPRESS_UNUSED_TEMPLATE_WARNINGS \
+ _Pragma( "clang diagnostic ignored \"-Wunused-template\"" )
#endif // __clang__
@@ -88,6 +101,7 @@
// Android somehow still does not support std::to_string
#if defined(__ANDROID__)
# define CATCH_INTERNAL_CONFIG_NO_CPP11_TO_STRING
+# define CATCH_INTERNAL_CONFIG_ANDROID_LOGWRITE
#endif
////////////////////////////////////////////////////////////////////////////////
@@ -109,20 +123,24 @@
// Required for some versions of Cygwin to declare gettimeofday
// see: http://stackoverflow.com/questions/36901803/gettimeofday-not-declared-in-this-scope-cygwin
# define _BSD_SOURCE
-// some versions of cygwin (most) do not support std::to_string. Use the libstd check.
+// some versions of cygwin (most) do not support std::to_string. Use the libstd check.
// https://gcc.gnu.org/onlinedocs/gcc-4.8.2/libstdc++/api/a01053_source.html line 2812-2813
# if !((__cplusplus >= 201103L) && defined(_GLIBCXX_USE_C99) \
- && !defined(_GLIBCXX_HAVE_BROKEN_VSWPRINTF))
+ && !defined(_GLIBCXX_HAVE_BROKEN_VSWPRINTF))
-# define CATCH_INTERNAL_CONFIG_NO_CPP11_TO_STRING
+# define CATCH_INTERNAL_CONFIG_NO_CPP11_TO_STRING
# endif
#endif // __CYGWIN__
////////////////////////////////////////////////////////////////////////////////
// Visual C++
-#ifdef _MSC_VER
+#if defined(_MSC_VER)
+
+# define CATCH_INTERNAL_START_WARNINGS_SUPPRESSION __pragma( warning(push) )
+# define CATCH_INTERNAL_STOP_WARNINGS_SUPPRESSION __pragma( warning(pop) )
+# define CATCH_INTERNAL_IGNORE_BUT_WARN(...) (void)sizeof(__VA_ARGS__)
# if _MSC_VER >= 1900 // Visual Studio 2015 or newer
# define CATCH_INTERNAL_CONFIG_CPP17_UNCAUGHT_EXCEPTIONS
@@ -139,10 +157,17 @@
// MSVC traditional preprocessor needs some workaround for __VA_ARGS__
// _MSVC_TRADITIONAL == 0 means new conformant preprocessor
// _MSVC_TRADITIONAL == 1 means old traditional non-conformant preprocessor
-# if !defined(_MSVC_TRADITIONAL) || (defined(_MSVC_TRADITIONAL) && _MSVC_TRADITIONAL)
-# define CATCH_INTERNAL_CONFIG_TRADITIONAL_MSVC_PREPROCESSOR
-# endif
+# if !defined(__clang__) // Handle Clang masquerading for msvc
+# if !defined(_MSVC_TRADITIONAL) || (defined(_MSVC_TRADITIONAL) && _MSVC_TRADITIONAL)
+# define CATCH_INTERNAL_CONFIG_TRADITIONAL_MSVC_PREPROCESSOR
+# endif // MSVC_TRADITIONAL
+# endif // __clang__
+
+#endif // _MSC_VER
+#if defined(_REENTRANT) || defined(_MSC_VER)
+// Enable async processing, as -pthread is specified or no additional linking is required
+# define CATCH_INTERNAL_CONFIG_USE_ASYNC
#endif // _MSC_VER
////////////////////////////////////////////////////////////////////////////////
@@ -174,41 +199,55 @@
#define CATCH_INTERNAL_CONFIG_COUNTER
#endif
+
////////////////////////////////////////////////////////////////////////////////
-// Check if string_view is available and usable
-// The check is split apart to work around v140 (VS2015) preprocessor issue...
-#if defined(__has_include)
-#if __has_include(<string_view>) && defined(CATCH_CPP17_OR_GREATER)
-# define CATCH_INTERNAL_CONFIG_CPP17_STRING_VIEW
-#endif
+
+// RTX is a special version of Windows that is real time.
+// This means that it is detected as Windows, but does not provide
+// the same set of capabilities as real Windows does.
+#if defined(UNDER_RTSS) || defined(RTX64_BUILD)
+ #define CATCH_INTERNAL_CONFIG_NO_WINDOWS_SEH
+ #define CATCH_INTERNAL_CONFIG_NO_ASYNC
+ #define CATCH_CONFIG_COLOUR_NONE
#endif
-////////////////////////////////////////////////////////////////////////////////
-// Check if optional is available and usable
-#if defined(__has_include)
-# if __has_include(<optional>) && defined(CATCH_CPP17_OR_GREATER)
-# define CATCH_INTERNAL_CONFIG_CPP17_OPTIONAL
-# endif // __has_include(<optional>) && defined(CATCH_CPP17_OR_GREATER)
-#endif // __has_include
+#if !defined(_GLIBCXX_USE_C99_MATH_TR1)
+#define CATCH_INTERNAL_CONFIG_GLOBAL_NEXTAFTER
+#endif
-////////////////////////////////////////////////////////////////////////////////
-// Check if variant is available and usable
+// Various stdlib support checks that require __has_include
#if defined(__has_include)
-# if __has_include(<variant>) && defined(CATCH_CPP17_OR_GREATER)
-# if defined(__clang__) && (__clang_major__ < 8)
- // work around clang bug with libstdc++ https://bugs.llvm.org/show_bug.cgi?id=31852
- // fix should be in clang 8, workaround in libstdc++ 8.2
-# include <ciso646>
-# if defined(__GLIBCXX__) && defined(_GLIBCXX_RELEASE) && (_GLIBCXX_RELEASE < 9)
-# define CATCH_CONFIG_NO_CPP17_VARIANT
-# else
-# define CATCH_INTERNAL_CONFIG_CPP17_VARIANT
-# endif // defined(__GLIBCXX__) && defined(_GLIBCXX_RELEASE) && (_GLIBCXX_RELEASE < 9)
-# else
-# define CATCH_INTERNAL_CONFIG_CPP17_VARIANT
-# endif // defined(__clang__) && (__clang_major__ < 8)
-# endif // __has_include(<variant>) && defined(CATCH_CPP17_OR_GREATER)
-#endif // __has_include
+ // Check if string_view is available and usable
+ #if __has_include(<string_view>) && defined(CATCH_CPP17_OR_GREATER)
+ # define CATCH_INTERNAL_CONFIG_CPP17_STRING_VIEW
+ #endif
+
+ // Check if optional is available and usable
+ # if __has_include(<optional>) && defined(CATCH_CPP17_OR_GREATER)
+ # define CATCH_INTERNAL_CONFIG_CPP17_OPTIONAL
+ # endif // __has_include(<optional>) && defined(CATCH_CPP17_OR_GREATER)
+
+ // Check if byte is available and usable
+ # if __has_include(<cstddef>) && defined(CATCH_CPP17_OR_GREATER)
+ # define CATCH_INTERNAL_CONFIG_CPP17_BYTE
+ # endif // __has_include(<cstddef>) && defined(CATCH_CPP17_OR_GREATER)
+
+ // Check if variant is available and usable
+ # if __has_include(<variant>) && defined(CATCH_CPP17_OR_GREATER)
+ # if defined(__clang__) && (__clang_major__ < 8)
+ // work around clang bug with libstdc++ https://bugs.llvm.org/show_bug.cgi?id=31852
+ // fix should be in clang 8, workaround in libstdc++ 8.2
+ # include <ciso646>
+ # if defined(__GLIBCXX__) && defined(_GLIBCXX_RELEASE) && (_GLIBCXX_RELEASE < 9)
+ # define CATCH_CONFIG_NO_CPP17_VARIANT
+ # else
+ # define CATCH_INTERNAL_CONFIG_CPP17_VARIANT
+ # endif // defined(__GLIBCXX__) && defined(_GLIBCXX_RELEASE) && (_GLIBCXX_RELEASE < 9)
+ # else
+ # define CATCH_INTERNAL_CONFIG_CPP17_VARIANT
+ # endif // defined(__clang__) && (__clang_major__ < 8)
+ # endif // __has_include(<variant>) && defined(CATCH_CPP17_OR_GREATER)
+#endif // defined(__has_include)
#if defined(CATCH_INTERNAL_CONFIG_COUNTER) && !defined(CATCH_CONFIG_NO_COUNTER) && !defined(CATCH_CONFIG_COUNTER)
@@ -246,6 +285,11 @@
# define CATCH_CONFIG_CPP17_VARIANT
#endif
+#if defined(CATCH_INTERNAL_CONFIG_CPP17_BYTE) && !defined(CATCH_CONFIG_NO_CPP17_BYTE) && !defined(CATCH_CONFIG_CPP17_BYTE)
+# define CATCH_CONFIG_CPP17_BYTE
+#endif
+
+
#if defined(CATCH_CONFIG_EXPERIMENTAL_REDIRECT)
# define CATCH_INTERNAL_CONFIG_NEW_CAPTURE
#endif
@@ -262,17 +306,54 @@
# define CATCH_CONFIG_POLYFILL_ISNAN
#endif
+#if defined(CATCH_INTERNAL_CONFIG_USE_ASYNC) && !defined(CATCH_INTERNAL_CONFIG_NO_ASYNC) && !defined(CATCH_CONFIG_NO_USE_ASYNC) && !defined(CATCH_CONFIG_USE_ASYNC)
+# define CATCH_CONFIG_USE_ASYNC
+#endif
+
+#if defined(CATCH_INTERNAL_CONFIG_ANDROID_LOGWRITE) && !defined(CATCH_CONFIG_NO_ANDROID_LOGWRITE) && !defined(CATCH_CONFIG_ANDROID_LOGWRITE)
+# define CATCH_CONFIG_ANDROID_LOGWRITE
+#endif
+
+#if defined(CATCH_INTERNAL_CONFIG_GLOBAL_NEXTAFTER) && !defined(CATCH_CONFIG_NO_GLOBAL_NEXTAFTER) && !defined(CATCH_CONFIG_GLOBAL_NEXTAFTER)
+# define CATCH_CONFIG_GLOBAL_NEXTAFTER
+#endif
+
+
+// Even if we do not think the compiler has that warning, we still have
+// to provide a macro that can be used by the code.
+#if !defined(CATCH_INTERNAL_START_WARNINGS_SUPPRESSION)
+# define CATCH_INTERNAL_START_WARNINGS_SUPPRESSION
+#endif
+#if !defined(CATCH_INTERNAL_STOP_WARNINGS_SUPPRESSION)
+# define CATCH_INTERNAL_STOP_WARNINGS_SUPPRESSION
+#endif
#if !defined(CATCH_INTERNAL_SUPPRESS_PARENTHESES_WARNINGS)
# define CATCH_INTERNAL_SUPPRESS_PARENTHESES_WARNINGS
-# define CATCH_INTERNAL_UNSUPPRESS_PARENTHESES_WARNINGS
#endif
#if !defined(CATCH_INTERNAL_SUPPRESS_GLOBALS_WARNINGS)
# define CATCH_INTERNAL_SUPPRESS_GLOBALS_WARNINGS
-# define CATCH_INTERNAL_UNSUPPRESS_GLOBALS_WARNINGS
#endif
#if !defined(CATCH_INTERNAL_SUPPRESS_UNUSED_WARNINGS)
# define CATCH_INTERNAL_SUPPRESS_UNUSED_WARNINGS
-# define CATCH_INTERNAL_UNSUPPRESS_UNUSED_WARNINGS
+#endif
+#if !defined(CATCH_INTERNAL_SUPPRESS_ZERO_VARIADIC_WARNINGS)
+# define CATCH_INTERNAL_SUPPRESS_ZERO_VARIADIC_WARNINGS
+#endif
+
+// The goal of this macro is to avoid evaluation of the arguments, but
+// still have the compiler warn on problems inside...
+#if !defined(CATCH_INTERNAL_IGNORE_BUT_WARN)
+# define CATCH_INTERNAL_IGNORE_BUT_WARN(...)
+#endif
+
+#if defined(__APPLE__) && defined(__apple_build_version__) && (__clang_major__ < 10)
+# undef CATCH_INTERNAL_SUPPRESS_UNUSED_TEMPLATE_WARNINGS
+#elif defined(__clang__) && (__clang_major__ < 5)
+# undef CATCH_INTERNAL_SUPPRESS_UNUSED_TEMPLATE_WARNINGS
+#endif
+
+#if !defined(CATCH_INTERNAL_SUPPRESS_UNUSED_TEMPLATE_WARNINGS)
+# define CATCH_INTERNAL_SUPPRESS_UNUSED_TEMPLATE_WARNINGS
#endif
#if defined(CATCH_CONFIG_DISABLE_EXCEPTIONS)
diff --git a/include/internal/catch_config.cpp b/include/internal/catch_config.cpp
index d9ee9182..21cd6296 100644
--- a/include/internal/catch_config.cpp
+++ b/include/internal/catch_config.cpp
@@ -15,11 +15,23 @@ namespace Catch {
: m_data( data ),
m_stream( openStream() )
{
+ // We need to trim filter specs to avoid trouble with superfluous
+ // whitespace (esp. important for bdd macros, as those are manually
+ // aligned with whitespace).
+
+ for (auto& elem : m_data.testsOrTags) {
+ elem = trim(elem);
+ }
+ for (auto& elem : m_data.sectionsToRun) {
+ elem = trim(elem);
+ }
+
TestSpecParser parser(ITagAliasRegistry::get());
- if (!data.testsOrTags.empty()) {
+ if (!m_data.testsOrTags.empty()) {
m_hasTestFilters = true;
- for( auto const& testOrTags : data.testsOrTags )
- parser.parse( testOrTags );
+ for (auto const& testOrTags : m_data.testsOrTags) {
+ parser.parse(testOrTags);
+ }
}
m_testSpec = parser.testSpec();
}
@@ -54,13 +66,18 @@ namespace Catch {
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; }
- int Config::benchmarkResolutionMultiple() const { return m_data.benchmarkResolutionMultiple; }
UseColour::YesOrNo Config::useColour() const { return m_data.useColour; }
bool Config::shouldDebugBreak() const { return m_data.shouldDebugBreak; }
int Config::abortAfter() const { return m_data.abortAfter; }
bool Config::showInvisibles() const { return m_data.showInvisibles; }
Verbosity Config::verbosity() const { return m_data.verbosity; }
+ bool Config::benchmarkNoAnalysis() const { return m_data.benchmarkNoAnalysis; }
+ int Config::benchmarkSamples() const { return m_data.benchmarkSamples; }
+ double Config::benchmarkConfidenceInterval() const { return m_data.benchmarkConfidenceInterval; }
+ unsigned int Config::benchmarkResamples() const { return m_data.benchmarkResamples; }
+ std::chrono::milliseconds Config::benchmarkWarmupTime() const { return std::chrono::milliseconds(m_data.benchmarkWarmupTime); }
+
IStream const* Config::openStream() {
return Catch::makeStream(m_data.outputFilename);
}
diff --git a/include/internal/catch_config.hpp b/include/internal/catch_config.hpp
index a9850233..64d2c035 100644
--- a/include/internal/catch_config.hpp
+++ b/include/internal/catch_config.hpp
@@ -42,7 +42,12 @@ namespace Catch {
int abortAfter = -1;
unsigned int rngSeed = 0;
- int benchmarkResolutionMultiple = 100;
+
+ bool benchmarkNoAnalysis = false;
+ unsigned int benchmarkSamples = 100;
+ double benchmarkConfidenceInterval = 0.95;
+ unsigned int benchmarkResamples = 100000;
+ std::chrono::milliseconds::rep benchmarkWarmupTime = 100;
Verbosity verbosity = Verbosity::Normal;
WarnAbout::What warnings = WarnAbout::Nothing;
@@ -100,12 +105,16 @@ namespace Catch {
ShowDurations::OrNot showDurations() const override;
RunTests::InWhatOrder runOrder() const override;
unsigned int rngSeed() const override;
- int benchmarkResolutionMultiple() const override;
UseColour::YesOrNo useColour() const override;
bool shouldDebugBreak() const override;
int abortAfter() const override;
bool showInvisibles() const override;
Verbosity verbosity() const override;
+ bool benchmarkNoAnalysis() const override;
+ int benchmarkSamples() const override;
+ double benchmarkConfidenceInterval() const override;
+ unsigned int benchmarkResamples() const override;
+ std::chrono::milliseconds benchmarkWarmupTime() const override;
private:
diff --git a/include/internal/catch_console_colour.cpp b/include/internal/catch_console_colour.cpp
index 0a13a1bb..de0fff43 100644
--- a/include/internal/catch_console_colour.cpp
+++ b/include/internal/catch_console_colour.cpp
@@ -34,7 +34,7 @@ namespace Catch {
};
struct NoColourImpl : IColourImpl {
- void use( Colour::Code ) {}
+ void use( Colour::Code ) override {}
static IColourImpl* instance() {
static NoColourImpl s_instance;
@@ -167,7 +167,7 @@ namespace {
bool useColourOnPlatform() {
return
-#ifdef CATCH_PLATFORM_MAC
+#if defined(CATCH_PLATFORM_MAC) || defined(CATCH_PLATFORM_IPHONE)
!isDebuggerActive() &&
#endif
#if !(defined(__DJGPP__) && defined(__STRICT_ANSI__))
@@ -208,13 +208,13 @@ namespace Catch {
namespace Catch {
Colour::Colour( Code _colourCode ) { use( _colourCode ); }
- Colour::Colour( Colour&& rhs ) noexcept {
- m_moved = rhs.m_moved;
- rhs.m_moved = true;
+ Colour::Colour( Colour&& other ) noexcept {
+ m_moved = other.m_moved;
+ other.m_moved = true;
}
- Colour& Colour::operator=( Colour&& rhs ) noexcept {
- m_moved = rhs.m_moved;
- rhs.m_moved = true;
+ Colour& Colour::operator=( Colour&& other ) noexcept {
+ m_moved = other.m_moved;
+ other.m_moved = true;
return *this;
}
@@ -222,7 +222,13 @@ namespace Catch {
void Colour::use( Code _colourCode ) {
static IColourImpl* impl = platformColourInstance();
- impl->use( _colourCode );
+ // Strictly speaking, this cannot possibly happen.
+ // However, under some conditions it does happen (see #1626),
+ // and this change is small enough that we can let practicality
+ // triumph over purity in this case.
+ if (impl != nullptr) {
+ impl->use( _colourCode );
+ }
}
std::ostream& operator << ( std::ostream& os, Colour const& ) {
diff --git a/include/internal/catch_context.cpp b/include/internal/catch_context.cpp
index 52fca302..e444a6b3 100644
--- a/include/internal/catch_context.cpp
+++ b/include/internal/catch_context.cpp
@@ -7,6 +7,7 @@
*/
#include "catch_context.h"
#include "catch_common.h"
+#include "catch_random_number_generator.h"
namespace Catch {
@@ -59,4 +60,11 @@ namespace Catch {
IContext::~IContext() = default;
IMutableContext::~IMutableContext() = default;
Context::~Context() = default;
+
+
+ SimplePcg32& rng() {
+ static SimplePcg32 s_rng;
+ return s_rng;
+ }
+
}
diff --git a/include/internal/catch_context.h b/include/internal/catch_context.h
index 3d3c6bad..c579c399 100644
--- a/include/internal/catch_context.h
+++ b/include/internal/catch_context.h
@@ -46,6 +46,7 @@ namespace Catch {
{
if( !IMutableContext::currentContext )
IMutableContext::createContext();
+ // NOLINTNEXTLINE(clang-analyzer-core.uninitialized.UndefReturn)
return *IMutableContext::currentContext;
}
@@ -55,6 +56,9 @@ namespace Catch {
}
void cleanUpContext();
+
+ class SimplePcg32;
+ SimplePcg32& rng();
}
#endif // TWOBLUECUBES_CATCH_CONTEXT_H_INCLUDED
diff --git a/include/internal/catch_debug_console.cpp b/include/internal/catch_debug_console.cpp
index 5d25f651..a341d810 100644
--- a/include/internal/catch_debug_console.cpp
+++ b/include/internal/catch_debug_console.cpp
@@ -7,11 +7,21 @@
*/
#include "catch_debug_console.h"
+#include "catch_compiler_capabilities.h"
#include "catch_stream.h"
#include "catch_platform.h"
#include "catch_windows_h_proxy.h"
-#ifdef CATCH_PLATFORM_WINDOWS
+#if defined(CATCH_CONFIG_ANDROID_LOGWRITE)
+#include <android/log.h>
+
+ namespace Catch {
+ void writeToDebugConsole( std::string const& text ) {
+ __android_log_write( ANDROID_LOG_DEBUG, "Catch", text.c_str() );
+ }
+ }
+
+#elif defined(CATCH_PLATFORM_WINDOWS)
namespace Catch {
void writeToDebugConsole( std::string const& text ) {
diff --git a/include/internal/catch_debugger.cpp b/include/internal/catch_debugger.cpp
index f04900a4..fc78c36e 100644
--- a/include/internal/catch_debugger.cpp
+++ b/include/internal/catch_debugger.cpp
@@ -12,7 +12,7 @@
#include "catch_stream.h"
#include "catch_platform.h"
-#ifdef CATCH_PLATFORM_MAC
+#if defined(CATCH_PLATFORM_MAC) || defined(CATCH_PLATFORM_IPHONE)
# include <assert.h>
# include <stdbool.h>
diff --git a/include/internal/catch_debugger.h b/include/internal/catch_debugger.h
index db3ff681..77db8aed 100644
--- a/include/internal/catch_debugger.h
+++ b/include/internal/catch_debugger.h
@@ -19,6 +19,19 @@ namespace Catch {
#define CATCH_TRAP() __asm__("int $3\n" : : ) /* NOLINT */
+#elif defined(CATCH_PLATFORM_IPHONE)
+
+ // use inline assembler
+ #if defined(__i386__) || defined(__x86_64__)
+ #define CATCH_TRAP() __asm__("int $3")
+ #elif defined(__aarch64__)
+ #define CATCH_TRAP() __asm__(".inst 0xd4200000")
+ #elif defined(__arm__) && !defined(__thumb__)
+ #define CATCH_TRAP() __asm__(".inst 0xe7f001f0")
+ #elif defined(__arm__) && defined(__thumb__)
+ #define CATCH_TRAP() __asm__(".inst 0xde01")
+ #endif
+
#elif defined(CATCH_PLATFORM_LINUX)
// If we can use inline assembler, do it because this allows us to break
// directly at the location of the failing check instead of breaking inside
@@ -37,10 +50,12 @@ namespace Catch {
#define CATCH_TRAP() DebugBreak()
#endif
-#ifdef CATCH_TRAP
- #define CATCH_BREAK_INTO_DEBUGGER() []{ if( Catch::isDebuggerActive() ) { CATCH_TRAP(); } }()
-#else
- #define CATCH_BREAK_INTO_DEBUGGER() []{}()
+#ifndef CATCH_BREAK_INTO_DEBUGGER
+ #ifdef CATCH_TRAP
+ #define CATCH_BREAK_INTO_DEBUGGER() []{ if( Catch::isDebuggerActive() ) { CATCH_TRAP(); } }()
+ #else
+ #define CATCH_BREAK_INTO_DEBUGGER() []{}()
+ #endif
#endif
#endif // TWOBLUECUBES_CATCH_DEBUGGER_H_INCLUDED
diff --git a/include/internal/catch_default_main.hpp b/include/internal/catch_default_main.hpp
index 17ad090a..aab5cba3 100644
--- a/include/internal/catch_default_main.hpp
+++ b/include/internal/catch_default_main.hpp
@@ -9,10 +9,11 @@
#define TWOBLUECUBES_CATCH_DEFAULT_MAIN_HPP_INCLUDED
#include "catch_session.h"
+#include "catch_platform.h"
#ifndef __OBJC__
-#if defined(CATCH_CONFIG_WCHAR) && defined(WIN32) && defined(_UNICODE) && !defined(DO_NOT_USE_WMAIN)
+#if defined(CATCH_CONFIG_WCHAR) && defined(CATCH_PLATFORM_WINDOWS) && defined(_UNICODE) && !defined(DO_NOT_USE_WMAIN)
// Standard C/C++ Win32 Unicode wmain entry point
extern "C" int wmain (int argc, wchar_t * argv[], wchar_t * []) {
#else
diff --git a/include/internal/catch_enforce.cpp b/include/internal/catch_enforce.cpp
index f4db1c15..903d43be 100644
--- a/include/internal/catch_enforce.cpp
+++ b/include/internal/catch_enforce.cpp
@@ -7,6 +7,9 @@
#include "catch_enforce.h"
+#include <stdexcept>
+
+
namespace Catch {
#if defined(CATCH_CONFIG_DISABLE_EXCEPTIONS) && !defined(CATCH_CONFIG_DISABLE_EXCEPTIONS_CUSTOM_HANDLER)
[[noreturn]]
@@ -16,4 +19,22 @@ namespace Catch {
std::terminate();
}
#endif
+
+ [[noreturn]]
+ void throw_logic_error(std::string const& msg) {
+ throw_exception(std::logic_error(msg));
+ }
+
+ [[noreturn]]
+ void throw_domain_error(std::string const& msg) {
+ throw_exception(std::domain_error(msg));
+ }
+
+ [[noreturn]]
+ void throw_runtime_error(std::string const& msg) {
+ throw_exception(std::runtime_error(msg));
+ }
+
+
+
} // namespace Catch;
diff --git a/include/internal/catch_enforce.h b/include/internal/catch_enforce.h
index 00694023..0484724d 100644
--- a/include/internal/catch_enforce.h
+++ b/include/internal/catch_enforce.h
@@ -11,8 +11,7 @@
#include "catch_compiler_capabilities.h"
#include "catch_stream.h"
-
-#include <stdexcept>
+#include <exception>
namespace Catch {
#if !defined(CATCH_CONFIG_DISABLE_EXCEPTIONS)
@@ -25,18 +24,30 @@ namespace Catch {
[[noreturn]]
void throw_exception(std::exception const& e);
#endif
+
+ [[noreturn]]
+ void throw_logic_error(std::string const& msg);
+ [[noreturn]]
+ void throw_domain_error(std::string const& msg);
+ [[noreturn]]
+ void throw_runtime_error(std::string const& msg);
+
} // namespace Catch;
-#define CATCH_PREPARE_EXCEPTION( type, msg ) \
- type( ( Catch::ReusableStringStream() << msg ).str() )
-#define CATCH_INTERNAL_ERROR( msg ) \
- Catch::throw_exception(CATCH_PREPARE_EXCEPTION( std::logic_error, CATCH_INTERNAL_LINEINFO << ": Internal Catch error: " << msg))
-#define CATCH_ERROR( msg ) \
- Catch::throw_exception(CATCH_PREPARE_EXCEPTION( std::domain_error, msg ))
-#define CATCH_RUNTIME_ERROR( msg ) \
- Catch::throw_exception(CATCH_PREPARE_EXCEPTION( std::runtime_error, msg ))
-#define CATCH_ENFORCE( condition, msg ) \
- do{ if( !(condition) ) CATCH_ERROR( msg ); } while(false)
+#define CATCH_MAKE_MSG(...) \
+ (Catch::ReusableStringStream() << __VA_ARGS__).str()
+
+#define CATCH_INTERNAL_ERROR(...) \
+ Catch::throw_logic_error(CATCH_MAKE_MSG( CATCH_INTERNAL_LINEINFO << ": Internal Catch2 error: " << __VA_ARGS__))
+
+#define CATCH_ERROR(...) \
+ Catch::throw_domain_error(CATCH_MAKE_MSG( __VA_ARGS__ ))
+
+#define CATCH_RUNTIME_ERROR(...) \
+ Catch::throw_runtime_error(CATCH_MAKE_MSG( __VA_ARGS__ ))
+
+#define CATCH_ENFORCE( condition, ... ) \
+ do{ if( !(condition) ) CATCH_ERROR( __VA_ARGS__ ); } while(false)
#endif // TWOBLUECUBES_CATCH_ENFORCE_H_INCLUDED
diff --git a/include/internal/catch_enum_values_registry.cpp b/include/internal/catch_enum_values_registry.cpp
new file mode 100644
index 00000000..063f9d62
--- /dev/null
+++ b/include/internal/catch_enum_values_registry.cpp
@@ -0,0 +1,75 @@
+/*
+ * Created by Phil on 4/4/2019.
+ * Copyright 2019 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_enum_values_registry.h"
+#include "catch_string_manip.h"
+#include "catch_stream.h"
+
+#include <map>
+#include <cassert>
+
+namespace Catch {
+
+ IMutableEnumValuesRegistry::~IMutableEnumValuesRegistry() {}
+
+ namespace Detail {
+
+ namespace {
+ // Extracts the actual name part of an enum instance
+ // In other words, it returns the Blue part of Bikeshed::Colour::Blue
+ StringRef extractInstanceName(StringRef enumInstance) {
+ // Find last occurence of ":"
+ size_t name_start = enumInstance.size();
+ while (name_start > 0 && enumInstance[name_start - 1] != ':') {
+ --name_start;
+ }
+ return enumInstance.substr(name_start, enumInstance.size() - name_start);
+ }
+ }
+
+ std::vector<StringRef> parseEnums( StringRef enums ) {
+ auto enumValues = splitStringRef( enums, ',' );
+ std::vector<StringRef> parsed;
+ parsed.reserve( enumValues.size() );
+ for( auto const& enumValue : enumValues ) {
+ parsed.push_back(trim(extractInstanceName(enumValue)));
+ }
+ return parsed;
+ }
+
+ EnumInfo::~EnumInfo() {}
+
+ StringRef EnumInfo::lookup( int value ) const {
+ for( auto const& valueToName : m_values ) {
+ if( valueToName.first == value )
+ return valueToName.second;
+ }
+ return "{** unexpected enum value **}"_sr;
+ }
+
+ std::unique_ptr<EnumInfo> makeEnumInfo( StringRef enumName, StringRef allValueNames, std::vector<int> const& values ) {
+ std::unique_ptr<EnumInfo> enumInfo( new EnumInfo );
+ enumInfo->m_name = enumName;
+ enumInfo->m_values.reserve( values.size() );
+
+ const auto valueNames = Catch::Detail::parseEnums( allValueNames );
+ assert( valueNames.size() == values.size() );
+ std::size_t i = 0;
+ for( auto value : values )
+ enumInfo->m_values.emplace_back(value, valueNames[i++]);
+
+ return enumInfo;
+ }
+
+ EnumInfo const& EnumValuesRegistry::registerEnum( StringRef enumName, StringRef allValueNames, std::vector<int> const& values ) {
+ m_enumInfos.push_back(makeEnumInfo(enumName, allValueNames, values));
+ return *m_enumInfos.back();
+ }
+
+ } // Detail
+} // Catch
+
diff --git a/include/internal/catch_enum_values_registry.h b/include/internal/catch_enum_values_registry.h
new file mode 100644
index 00000000..ae252fbf
--- /dev/null
+++ b/include/internal/catch_enum_values_registry.h
@@ -0,0 +1,35 @@
+/*
+ * Created by Phil on 4/4/2019.
+ * Copyright 2019 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_ENUMVALUESREGISTRY_H_INCLUDED
+#define TWOBLUECUBES_CATCH_ENUMVALUESREGISTRY_H_INCLUDED
+
+#include "catch_interfaces_enum_values_registry.h"
+
+#include <vector>
+#include <memory>
+
+namespace Catch {
+
+ namespace Detail {
+
+ std::unique_ptr<EnumInfo> makeEnumInfo( StringRef enumName, StringRef allValueNames, std::vector<int> const& values );
+
+ class EnumValuesRegistry : public IMutableEnumValuesRegistry {
+
+ std::vector<std::unique_ptr<EnumInfo>> m_enumInfos;
+
+ EnumInfo const& registerEnum( StringRef enumName, StringRef allEnums, std::vector<int> const& values) override;
+ };
+
+ std::vector<StringRef> parseEnums( StringRef enums );
+
+ } // Detail
+
+} // Catch
+
+#endif //TWOBLUECUBES_CATCH_ENUMVALUESREGISTRY_H_INCLUDED \ No newline at end of file
diff --git a/include/internal/catch_fatal_condition.cpp b/include/internal/catch_fatal_condition.cpp
index cea271f3..1eb6bb87 100644
--- a/include/internal/catch_fatal_condition.cpp
+++ b/include/internal/catch_fatal_condition.cpp
@@ -97,7 +97,7 @@ namespace Catch {
// 32kb for the alternate stack seems to be sufficient. However, this value
// is experimentally determined, so that's not guaranteed.
- constexpr static std::size_t sigStackSize = 32768 >= MINSIGSTKSZ ? 32768 : MINSIGSTKSZ;
+ static constexpr std::size_t sigStackSize = 32768 >= MINSIGSTKSZ ? 32768 : MINSIGSTKSZ;
static SignalDefs signalDefs[] = {
{ SIGINT, "SIGINT - Terminal interrupt signal" },
diff --git a/include/internal/catch_generators.hpp b/include/internal/catch_generators.hpp
index 8f06b8c6..d0fbe8bf 100644
--- a/include/internal/catch_generators.hpp
+++ b/include/internal/catch_generators.hpp
@@ -57,7 +57,6 @@ namespace Generators {
class SingleValueGenerator final : public IGenerator<T> {
T m_value;
public:
- SingleValueGenerator(T const& value) : m_value( value ) {}
SingleValueGenerator(T&& value) : m_value(std::move(value)) {}
T const& get() const override {
@@ -70,6 +69,9 @@ namespace Generators {
template<typename T>
class FixedValuesGenerator final : public IGenerator<T> {
+ static_assert(!std::is_same<T, bool>::value,
+ "FixedValuesGenerator does not support bools because of std::vector<bool>"
+ "specialization, use SingleValue Generator instead.");
std::vector<T> m_values;
size_t m_idx = 0;
public:
@@ -117,21 +119,21 @@ namespace Generators {
m_generators.emplace_back(std::move(generator));
}
void populate(T&& val) {
- m_generators.emplace_back(value(std::move(val)));
+ m_generators.emplace_back(value(std::forward<T>(val)));
}
template<typename U>
void populate(U&& val) {
- populate(T(std::move(val)));
+ populate(T(std::forward<U>(val)));
}
template<typename U, typename... Gs>
- void populate(U&& valueOrGenerator, Gs... moreGenerators) {
+ void populate(U&& valueOrGenerator, Gs &&... moreGenerators) {
populate(std::forward<U>(valueOrGenerator));
populate(std::forward<Gs>(moreGenerators)...);
}
public:
template <typename... Gs>
- Generators(Gs... moreGenerators) {
+ Generators(Gs &&... moreGenerators) {
m_generators.reserve(sizeof...(Gs));
populate(std::forward<Gs>(moreGenerators)...);
}
@@ -163,7 +165,7 @@ namespace Generators {
struct as {};
template<typename T, typename... Gs>
- auto makeGenerators( GeneratorWrapper<T>&& generator, Gs... moreGenerators ) -> Generators<T> {
+ auto makeGenerators( GeneratorWrapper<T>&& generator, Gs &&... moreGenerators ) -> Generators<T> {
return Generators<T>(std::move(generator), std::forward<Gs>(moreGenerators)...);
}
template<typename T>
@@ -171,11 +173,11 @@ namespace Generators {
return Generators<T>(std::move(generator));
}
template<typename T, typename... Gs>
- auto makeGenerators( T&& val, Gs... moreGenerators ) -> Generators<T> {
+ auto makeGenerators( T&& val, Gs &&... moreGenerators ) -> Generators<T> {
return makeGenerators( value( std::forward<T>( val ) ), std::forward<Gs>( moreGenerators )... );
}
template<typename T, typename U, typename... Gs>
- auto makeGenerators( as<T>, U&& val, Gs... moreGenerators ) -> Generators<T> {
+ auto makeGenerators( as<T>, U&& val, Gs &&... moreGenerators ) -> Generators<T> {
return makeGenerators( value( T( std::forward<U>( val ) ) ), std::forward<Gs>( moreGenerators )... );
}
@@ -201,10 +203,10 @@ namespace Generators {
} // namespace Catch
#define GENERATE( ... ) \
- Catch::Generators::generate( CATCH_INTERNAL_LINEINFO, [ ]{ using namespace Catch::Generators; return makeGenerators( __VA_ARGS__ ); } )
+ Catch::Generators::generate( CATCH_INTERNAL_LINEINFO, [ ]{ using namespace Catch::Generators; return makeGenerators( __VA_ARGS__ ); } ) //NOLINT(google-build-using-namespace)
#define GENERATE_COPY( ... ) \
- Catch::Generators::generate( CATCH_INTERNAL_LINEINFO, [=]{ using namespace Catch::Generators; return makeGenerators( __VA_ARGS__ ); } )
+ Catch::Generators::generate( CATCH_INTERNAL_LINEINFO, [=]{ using namespace Catch::Generators; return makeGenerators( __VA_ARGS__ ); } ) //NOLINT(google-build-using-namespace)
#define GENERATE_REF( ... ) \
- Catch::Generators::generate( CATCH_INTERNAL_LINEINFO, [&]{ using namespace Catch::Generators; return makeGenerators( __VA_ARGS__ ); } )
+ Catch::Generators::generate( CATCH_INTERNAL_LINEINFO, [&]{ using namespace Catch::Generators; return makeGenerators( __VA_ARGS__ ); } ) //NOLINT(google-build-using-namespace)
#endif // TWOBLUECUBES_CATCH_GENERATORS_HPP_INCLUDED
diff --git a/include/internal/catch_generators_generic.hpp b/include/internal/catch_generators_generic.hpp
index 2903ba69..c3410147 100644
--- a/include/internal/catch_generators_generic.hpp
+++ b/include/internal/catch_generators_generic.hpp
@@ -8,6 +8,7 @@
#define TWOBLUECUBES_CATCH_GENERATORS_GENERIC_HPP_INCLUDED
#include "catch_generators.hpp"
+#include "catch_meta.hpp"
namespace Catch {
namespace Generators {
@@ -91,6 +92,9 @@ namespace Generators {
template <typename T>
class RepeatGenerator : public IGenerator<T> {
+ static_assert(!std::is_same<T, bool>::value,
+ "RepeatGenerator currently does not support bools"
+ "because of std::vector<bool> specialization");
GeneratorWrapper<T> m_generator;
mutable std::vector<T> m_returned;
size_t m_target_repeats;
@@ -169,18 +173,7 @@ namespace Generators {
}
};
-#if defined(__cpp_lib_is_invocable) && __cpp_lib_is_invocable >= 201703
- // std::result_of is deprecated in C++17 and removed in C++20. Hence, it is
- // replaced with std::invoke_result here. Also *_t format is preferred over
- // typename *::type format.
- template <typename Func, typename U>
- using MapFunctionReturnType = std::remove_reference_t<std::remove_cv_t<std::invoke_result_t<Func, U>>>;
-#else
- template <typename Func, typename U>
- using MapFunctionReturnType = typename std::remove_reference<typename std::remove_cv<typename std::result_of<Func(U)>::type>::type>::type;
-#endif
-
- template <typename Func, typename U, typename T = MapFunctionReturnType<Func, U>>
+ template <typename Func, typename U, typename T = FunctionReturnType<Func, U>>
GeneratorWrapper<T> map(Func&& function, GeneratorWrapper<U>&& generator) {
return GeneratorWrapper<T>(
pf::make_unique<MapGenerator<T, U, Func>>(std::forward<Func>(function), std::move(generator))
@@ -205,12 +198,14 @@ namespace Generators {
m_chunk_size(size), m_generator(std::move(generator))
{
m_chunk.reserve(m_chunk_size);
- m_chunk.push_back(m_generator.get());
- for (size_t i = 1; i < m_chunk_size; ++i) {
- if (!m_generator.next()) {
- Catch::throw_exception(GeneratorException("Not enough values to initialize the first chunk"));
- }
+ if (m_chunk_size != 0) {
m_chunk.push_back(m_generator.get());
+ for (size_t i = 1; i < m_chunk_size; ++i) {
+ if (!m_generator.next()) {
+ Catch::throw_exception(GeneratorException("Not enough values to initialize the first chunk"));
+ }
+ m_chunk.push_back(m_generator.get());
+ }
}
}
std::vector<T> const& get() const override {
diff --git a/include/internal/catch_generators_specific.hpp b/include/internal/catch_generators_specific.hpp
index 7aae06bd..dee8e711 100644
--- a/include/internal/catch_generators_specific.hpp
+++ b/include/internal/catch_generators_specific.hpp
@@ -10,6 +10,7 @@
#include "catch_context.h"
#include "catch_generators.hpp"
#include "catch_interfaces_config.h"
+#include "catch_random_number_generator.h"
#include <random>
@@ -18,14 +19,13 @@ namespace Generators {
template <typename Float>
class RandomFloatingGenerator final : public IGenerator<Float> {
- // FIXME: What is the right seed?
- std::minstd_rand m_rand;
+ Catch::SimplePcg32& m_rng;
std::uniform_real_distribution<Float> m_dist;
Float m_current_number;
public:
RandomFloatingGenerator(Float a, Float b):
- m_rand(getCurrentContext().getConfig()->rngSeed()),
+ m_rng(rng()),
m_dist(a, b) {
static_cast<void>(next());
}
@@ -34,20 +34,20 @@ public:
return m_current_number;
}
bool next() override {
- m_current_number = m_dist(m_rand);
+ m_current_number = m_dist(m_rng);
return true;
}
};
template <typename Integer>
class RandomIntegerGenerator final : public IGenerator<Integer> {
- std::minstd_rand m_rand;
+ Catch::SimplePcg32& m_rng;
std::uniform_int_distribution<Integer> m_dist;
Integer m_current_number;
public:
RandomIntegerGenerator(Integer a, Integer b):
- m_rand(getCurrentContext().getConfig()->rngSeed()),
+ m_rng(rng()),
m_dist(a, b) {
static_cast<void>(next());
}
@@ -56,7 +56,7 @@ public:
return m_current_number;
}
bool next() override {
- m_current_number = m_dist(m_rand);
+ m_current_number = m_dist(m_rng);
return true;
}
};
@@ -117,7 +117,7 @@ public:
template <typename T>
GeneratorWrapper<T> range(T const& start, T const& end, T const& step) {
- static_assert(std::is_integral<T>::value && !std::is_same<T, bool>::value, "Type must be an integer");
+ static_assert(std::is_arithmetic<T>::value && !std::is_same<T, bool>::value, "Type must be numeric");
return GeneratorWrapper<T>(pf::make_unique<RangeGenerator<T>>(start, end, step));
}
@@ -128,6 +128,46 @@ GeneratorWrapper<T> range(T const& start, T const& end) {
}
+template <typename T>
+class IteratorGenerator final : public IGenerator<T> {
+ static_assert(!std::is_same<T, bool>::value,
+ "IteratorGenerator currently does not support bools"
+ "because of std::vector<bool> specialization");
+
+ std::vector<T> m_elems;
+ size_t m_current = 0;
+public:
+ template <typename InputIterator, typename InputSentinel>
+ IteratorGenerator(InputIterator first, InputSentinel last):m_elems(first, last) {
+ if (m_elems.empty()) {
+ Catch::throw_exception(GeneratorException("IteratorGenerator received no valid values"));
+ }
+ }
+
+ T const& get() const override {
+ return m_elems[m_current];
+ }
+
+ bool next() override {
+ ++m_current;
+ return m_current != m_elems.size();
+ }
+};
+
+template <typename InputIterator,
+ typename InputSentinel,
+ typename ResultType = typename std::iterator_traits<InputIterator>::value_type>
+GeneratorWrapper<ResultType> from_range(InputIterator from, InputSentinel to) {
+ return GeneratorWrapper<ResultType>(pf::make_unique<IteratorGenerator<ResultType>>(from, to));
+}
+
+template <typename Container,
+ typename ResultType = typename Container::value_type>
+GeneratorWrapper<ResultType> from_range(Container const& cnt) {
+ return GeneratorWrapper<ResultType>(pf::make_unique<IteratorGenerator<ResultType>>(cnt.begin(), cnt.end()));
+}
+
+
} // namespace Generators
} // namespace Catch
diff --git a/include/internal/catch_interfaces_capture.h b/include/internal/catch_interfaces_capture.h
index 36f27a33..8c25c8cf 100644
--- a/include/internal/catch_interfaces_capture.h
+++ b/include/internal/catch_interfaces_capture.h
@@ -9,6 +9,7 @@
#define TWOBLUECUBES_CATCH_INTERFACES_CAPTURE_H_INCLUDED
#include <string>
+#include <chrono>
#include "catch_stringref.h"
#include "catch_result_type.h"
@@ -22,14 +23,18 @@ namespace Catch {
struct MessageInfo;
struct MessageBuilder;
struct Counts;
- struct BenchmarkInfo;
- struct BenchmarkStats;
struct AssertionReaction;
struct SourceLineInfo;
struct ITransientExpression;
struct IGeneratorTracker;
+#if defined(CATCH_CONFIG_ENABLE_BENCHMARKING)
+ struct BenchmarkInfo;
+ template <typename Duration = std::chrono::duration<double, std::nano>>
+ struct BenchmarkStats;
+#endif // CATCH_CONFIG_ENABLE_BENCHMARKING
+
struct IResultCapture {
virtual ~IResultCapture();
@@ -41,8 +46,12 @@ namespace Catch {
virtual auto acquireGeneratorTracker( SourceLineInfo const& lineInfo ) -> IGeneratorTracker& = 0;
+#if defined(CATCH_CONFIG_ENABLE_BENCHMARKING)
+ virtual void benchmarkPreparing( std::string const& name ) = 0;
virtual void benchmarkStarting( BenchmarkInfo const& info ) = 0;
- virtual void benchmarkEnded( BenchmarkStats const& stats ) = 0;
+ virtual void benchmarkEnded( BenchmarkStats<> const& stats ) = 0;
+ virtual void benchmarkFailed( std::string const& error ) = 0;
+#endif // CATCH_CONFIG_ENABLE_BENCHMARKING
virtual void pushScopedMessage( MessageInfo const& message ) = 0;
virtual void popScopedMessage( MessageInfo const& message ) = 0;
diff --git a/include/internal/catch_interfaces_config.cpp b/include/internal/catch_interfaces_config.cpp
index b6f5daa2..6617da69 100644
--- a/include/internal/catch_interfaces_config.cpp
+++ b/include/internal/catch_interfaces_config.cpp
@@ -1,4 +1,4 @@
-#include "internal/catch_interfaces_config.h"
+#include "catch_interfaces_config.h"
namespace Catch {
IConfig::~IConfig() = default;
diff --git a/include/internal/catch_interfaces_config.h b/include/internal/catch_interfaces_config.h
index 341bb742..8fb986be 100644
--- a/include/internal/catch_interfaces_config.h
+++ b/include/internal/catch_interfaces_config.h
@@ -9,7 +9,9 @@
#define TWOBLUECUBES_CATCH_INTERFACES_CONFIG_H_INCLUDED
#include "catch_common.h"
+#include "catch_option.hpp"
+#include <chrono>
#include <iosfwd>
#include <string>
#include <vector>
@@ -50,7 +52,7 @@ namespace Catch {
BeforeExit = 2,
BeforeStartAndExit = BeforeStart | BeforeExit
}; };
-
+
class TestSpec;
struct IConfig : NonCopyable {
@@ -72,10 +74,15 @@ namespace Catch {
virtual std::vector<std::string> const& getTestsOrTags() const = 0;
virtual RunTests::InWhatOrder runOrder() const = 0;
virtual unsigned int rngSeed() const = 0;
- virtual int benchmarkResolutionMultiple() const = 0;
virtual UseColour::YesOrNo useColour() const = 0;
virtual std::vector<std::string> const& getSectionsToRun() const = 0;
virtual Verbosity verbosity() const = 0;
+
+ virtual bool benchmarkNoAnalysis() const = 0;
+ virtual int benchmarkSamples() const = 0;
+ virtual double benchmarkConfidenceInterval() const = 0;
+ virtual unsigned int benchmarkResamples() const = 0;
+ virtual std::chrono::milliseconds benchmarkWarmupTime() const = 0;
};
using IConfigPtr = std::shared_ptr<IConfig const>;
diff --git a/include/internal/catch_interfaces_enum_values_registry.h b/include/internal/catch_interfaces_enum_values_registry.h
new file mode 100644
index 00000000..81592c9b
--- /dev/null
+++ b/include/internal/catch_interfaces_enum_values_registry.h
@@ -0,0 +1,46 @@
+/*
+ * Created by Phil on 4/4/2019.
+ * Copyright 2019 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_INTERFACESENUMVALUESREGISTRY_H_INCLUDED
+#define TWOBLUECUBES_CATCH_INTERFACESENUMVALUESREGISTRY_H_INCLUDED
+
+#include "catch_stringref.h"
+
+#include <vector>
+
+namespace Catch {
+
+ namespace Detail {
+ struct EnumInfo {
+ StringRef m_name;
+ std::vector<std::pair<int, StringRef>> m_values;
+
+ ~EnumInfo();
+
+ StringRef lookup( int value ) const;
+ };
+ } // namespace Detail
+
+ struct IMutableEnumValuesRegistry {
+ virtual ~IMutableEnumValuesRegistry();
+
+ virtual Detail::EnumInfo const& registerEnum( StringRef enumName, StringRef allEnums, std::vector<int> const& values ) = 0;
+
+ template<typename E>
+ Detail::EnumInfo const& registerEnum( StringRef enumName, StringRef allEnums, std::initializer_list<E> values ) {
+ static_assert(sizeof(int) >= sizeof(E), "Cannot serialize enum to int");
+ std::vector<int> intValues;
+ intValues.reserve( values.size() );
+ for( auto enumValue : values )
+ intValues.push_back( static_cast<int>( enumValue ) );
+ return registerEnum( enumName, allEnums, intValues );
+ }
+ };
+
+} // Catch
+
+#endif //TWOBLUECUBES_CATCH_INTERFACESENUMVALUESREGISTRY_H_INCLUDED
diff --git a/include/internal/catch_interfaces_exception.cpp b/include/internal/catch_interfaces_exception.cpp
index 8494a2cc..705d8c87 100644
--- a/include/internal/catch_interfaces_exception.cpp
+++ b/include/internal/catch_interfaces_exception.cpp
@@ -1,4 +1,4 @@
-#include "internal/catch_interfaces_exception.h"
+#include "catch_interfaces_exception.h"
namespace Catch {
IExceptionTranslator::~IExceptionTranslator() = default;
diff --git a/include/internal/catch_interfaces_exception.h b/include/internal/catch_interfaces_exception.h
index 73ef9904..a723772e 100644
--- a/include/internal/catch_interfaces_exception.h
+++ b/include/internal/catch_interfaces_exception.h
@@ -75,9 +75,10 @@ namespace Catch {
///////////////////////////////////////////////////////////////////////////////
#define INTERNAL_CATCH_TRANSLATE_EXCEPTION2( translatorName, signature ) \
static std::string translatorName( signature ); \
+ CATCH_INTERNAL_START_WARNINGS_SUPPRESSION \
CATCH_INTERNAL_SUPPRESS_GLOBALS_WARNINGS \
namespace{ Catch::ExceptionTranslatorRegistrar INTERNAL_CATCH_UNIQUE_NAME( catch_internal_ExceptionRegistrar )( &translatorName ); } \
- CATCH_INTERNAL_UNSUPPRESS_GLOBALS_WARNINGS \
+ CATCH_INTERNAL_STOP_WARNINGS_SUPPRESSION \
static std::string translatorName( signature )
#define INTERNAL_CATCH_TRANSLATE_EXCEPTION( signature ) INTERNAL_CATCH_TRANSLATE_EXCEPTION2( INTERNAL_CATCH_UNIQUE_NAME( catch_internal_ExceptionTranslator ), signature )
diff --git a/include/internal/catch_interfaces_registry_hub.cpp b/include/internal/catch_interfaces_registry_hub.cpp
index bd5b8082..7a22d649 100644
--- a/include/internal/catch_interfaces_registry_hub.cpp
+++ b/include/internal/catch_interfaces_registry_hub.cpp
@@ -1,4 +1,4 @@
-#include "internal/catch_interfaces_registry_hub.h"
+#include "catch_interfaces_registry_hub.h"
namespace Catch {
IRegistryHub::~IRegistryHub() = default;
diff --git a/include/internal/catch_interfaces_registry_hub.h b/include/internal/catch_interfaces_registry_hub.h
index 8e1da61e..19ffbf26 100644
--- a/include/internal/catch_interfaces_registry_hub.h
+++ b/include/internal/catch_interfaces_registry_hub.h
@@ -22,6 +22,8 @@ namespace Catch {
struct IReporterRegistry;
struct IReporterFactory;
struct ITagAliasRegistry;
+ struct IMutableEnumValuesRegistry;
+
class StartupExceptionRegistry;
using IReporterFactoryPtr = std::shared_ptr<IReporterFactory>;
@@ -32,7 +34,6 @@ namespace Catch {
virtual IReporterRegistry const& getReporterRegistry() const = 0;
virtual ITestCaseRegistry const& getTestCaseRegistry() const = 0;
virtual ITagAliasRegistry const& getTagAliasRegistry() const = 0;
-
virtual IExceptionTranslatorRegistry const& getExceptionTranslatorRegistry() const = 0;
@@ -47,6 +48,7 @@ namespace Catch {
virtual void registerTranslator( const IExceptionTranslator* translator ) = 0;
virtual void registerTagAlias( std::string const& alias, std::string const& tag, SourceLineInfo const& lineInfo ) = 0;
virtual void registerStartupException() noexcept = 0;
+ virtual IMutableEnumValuesRegistry& getMutableEnumValuesRegistry() = 0;
};
IRegistryHub const& getRegistryHub();
diff --git a/include/internal/catch_interfaces_reporter.h b/include/internal/catch_interfaces_reporter.h
index e5fbf8bb..751ef2c2 100644
--- a/include/internal/catch_interfaces_reporter.h
+++ b/include/internal/catch_interfaces_reporter.h
@@ -18,12 +18,18 @@
#include "catch_option.hpp"
#include "catch_stringref.h"
+#if defined(CATCH_CONFIG_ENABLE_BENCHMARKING)
+#include "benchmark/catch_estimate.hpp"
+#include "benchmark/catch_outlier_classification.hpp"
+#endif // CATCH_CONFIG_ENABLE_BENCHMARKING
+
#include <string>
#include <iosfwd>
#include <map>
#include <set>
#include <memory>
+#include <algorithm>
namespace Catch {
@@ -159,14 +165,43 @@ namespace Catch {
bool aborting;
};
+#if defined(CATCH_CONFIG_ENABLE_BENCHMARKING)
struct BenchmarkInfo {
std::string name;
+ double estimatedDuration;
+ int iterations;
+ int samples;
+ unsigned int resamples;
+ double clockResolution;
+ double clockCost;
};
+
+ template <class Duration>
struct BenchmarkStats {
BenchmarkInfo info;
- std::size_t iterations;
- uint64_t elapsedTimeInNanoseconds;
+
+ std::vector<Duration> samples;
+ Benchmark::Estimate<Duration> mean;
+ Benchmark::Estimate<Duration> standardDeviation;
+ Benchmark::OutlierClassification outliers;
+ double outlierVariance;
+
+ template <typename Duration2>
+ operator BenchmarkStats<Duration2>() const {
+ std::vector<Duration2> samples2;
+ samples2.reserve(samples.size());
+ std::transform(samples.begin(), samples.end(), std::back_inserter(samples2), [](Duration d) { return Duration2(d); });
+ return {
+ info,
+ std::move(samples2),
+ mean,
+ standardDeviation,
+ outliers,
+ outlierVariance,
+ };
+ }
};
+#endif // CATCH_CONFIG_ENABLE_BENCHMARKING
struct IStreamingReporter {
virtual ~IStreamingReporter() = default;
@@ -179,23 +214,26 @@ namespace Catch {
virtual void noMatchingTestCases( std::string const& spec ) = 0;
+ virtual void reportInvalidArguments(std::string const&) {}
+
virtual void testRunStarting( TestRunInfo const& testRunInfo ) = 0;
virtual void testGroupStarting( GroupInfo const& groupInfo ) = 0;
virtual void testCaseStarting( TestCaseInfo const& testInfo ) = 0;
virtual void sectionStarting( SectionInfo const& sectionInfo ) = 0;
- // *** experimental ***
+#if defined(CATCH_CONFIG_ENABLE_BENCHMARKING)
+ virtual void benchmarkPreparing( std::string const& ) {}
virtual void benchmarkStarting( BenchmarkInfo const& ) {}
+ virtual void benchmarkEnded( BenchmarkStats<> const& ) {}
+ virtual void benchmarkFailed( std::string const& ) {}
+#endif // CATCH_CONFIG_ENABLE_BENCHMARKING
virtual void assertionStarting( AssertionInfo const& assertionInfo ) = 0;
// The return value indicates if the messages buffer should be cleared:
virtual bool assertionEnded( AssertionStats const& assertionStats ) = 0;
- // *** experimental ***
- virtual void benchmarkEnded( BenchmarkStats const& ) {}
-
virtual void sectionEnded( SectionStats const& sectionStats ) = 0;
virtual void testCaseEnded( TestCaseStats const& testCaseStats ) = 0;
virtual void testGroupEnded( TestGroupStats const& testGroupStats ) = 0;
diff --git a/include/internal/catch_interfaces_runner.cpp b/include/internal/catch_interfaces_runner.cpp
index 2b052eb8..8d419a14 100644
--- a/include/internal/catch_interfaces_runner.cpp
+++ b/include/internal/catch_interfaces_runner.cpp
@@ -1,4 +1,4 @@
-#include "internal/catch_interfaces_runner.h"
+#include "catch_interfaces_runner.h"
namespace Catch {
IRunner::~IRunner() = default;
diff --git a/include/internal/catch_interfaces_testcase.cpp b/include/internal/catch_interfaces_testcase.cpp
index 35c3db08..9b35e034 100644
--- a/include/internal/catch_interfaces_testcase.cpp
+++ b/include/internal/catch_interfaces_testcase.cpp
@@ -1,4 +1,4 @@
-#include "internal/catch_interfaces_testcase.h"
+#include "catch_interfaces_testcase.h"
namespace Catch {
ITestInvoker::~ITestInvoker() = default;
diff --git a/include/internal/catch_interfaces_testcase.h b/include/internal/catch_interfaces_testcase.h
index f57cc8fe..2492c07d 100644
--- a/include/internal/catch_interfaces_testcase.h
+++ b/include/internal/catch_interfaces_testcase.h
@@ -28,6 +28,7 @@ namespace Catch {
virtual std::vector<TestCase> const& getAllTestsSorted( IConfig const& config ) const = 0;
};
+ bool isThrowSafe( TestCase const& testCase, IConfig const& config );
bool matchTest( TestCase const& testCase, TestSpec const& testSpec, IConfig const& config );
std::vector<TestCase> filterTests( std::vector<TestCase> const& testCases, TestSpec const& testSpec, IConfig const& config );
std::vector<TestCase> const& getAllTestCasesSorted( IConfig const& config );
diff --git a/include/internal/catch_list.cpp b/include/internal/catch_list.cpp
index e1d99222..9f748e4c 100644
--- a/include/internal/catch_list.cpp
+++ b/include/internal/catch_list.cpp
@@ -28,7 +28,7 @@
namespace Catch {
std::size_t listTests( Config const& config ) {
- TestSpec testSpec = config.testSpec();
+ TestSpec const& testSpec = config.testSpec();
if( config.hasTestFilters() )
Catch::cout() << "Matching test cases:\n";
else {
@@ -62,7 +62,7 @@ namespace Catch {
}
std::size_t listTestsNamesOnly( Config const& config ) {
- TestSpec testSpec = config.testSpec();
+ TestSpec const& testSpec = config.testSpec();
std::size_t matchedTests = 0;
std::vector<TestCase> matchedTestCases = filterTests( getAllTestCasesSorted( config ), testSpec, config );
for( auto const& testCaseInfo : matchedTestCases ) {
@@ -84,14 +84,23 @@ namespace Catch {
}
std::string TagInfo::all() const {
- std::string out;
- for( auto const& spelling : spellings )
- out += "[" + spelling + "]";
+ size_t size = 0;
+ for (auto const& spelling : spellings) {
+ // Add 2 for the brackes
+ size += spelling.size() + 2;
+ }
+
+ std::string out; out.reserve(size);
+ for (auto const& spelling : spellings) {
+ out += '[';
+ out += spelling;
+ out += ']';
+ }
return out;
}
std::size_t listTags( Config const& config ) {
- TestSpec testSpec = config.testSpec();
+ TestSpec const& testSpec = config.testSpec();
if( config.hasTestFilters() )
Catch::cout() << "Tags for matching test cases:\n";
else {
diff --git a/include/internal/catch_matchers.h b/include/internal/catch_matchers.h
index aebd4c23..518a6e0d 100644
--- a/include/internal/catch_matchers.h
+++ b/include/internal/catch_matchers.h
@@ -44,6 +44,15 @@ namespace Matchers {
virtual bool match( ObjectT const& arg ) const = 0;
};
+#if defined(__OBJC__)
+ // Hack to fix Catch GH issue #1661. Could use id for generic Object support.
+ // use of const for Object pointers is very uncommon and under ARC it causes some kind of signature mismatch that breaks compilation
+ template<>
+ struct MatcherMethod<NSString*> {
+ virtual bool match( NSString* arg ) const = 0;
+ };
+#endif
+
#ifdef __clang__
# pragma clang diagnostic pop
#endif
@@ -82,9 +91,10 @@ namespace Matchers {
return description;
}
- MatchAllOf<ArgT>& operator && ( MatcherBase<ArgT> const& other ) {
- m_matchers.push_back( &other );
- return *this;
+ MatchAllOf<ArgT> operator && ( MatcherBase<ArgT> const& other ) {
+ auto copy(*this);
+ copy.m_matchers.push_back( &other );
+ return copy;
}
std::vector<MatcherBase<ArgT> const*> m_matchers;
@@ -115,9 +125,10 @@ namespace Matchers {
return description;
}
- MatchAnyOf<ArgT>& operator || ( MatcherBase<ArgT> const& other ) {
- m_matchers.push_back( &other );
- return *this;
+ MatchAnyOf<ArgT> operator || ( MatcherBase<ArgT> const& other ) {
+ auto copy(*this);
+ copy.m_matchers.push_back( &other );
+ return copy;
}
std::vector<MatcherBase<ArgT> const*> m_matchers;
diff --git a/include/internal/catch_matchers_exception.cpp b/include/internal/catch_matchers_exception.cpp
new file mode 100644
index 00000000..b18810e8
--- /dev/null
+++ b/include/internal/catch_matchers_exception.cpp
@@ -0,0 +1,30 @@
+/*
+ * Created by Martin Hořeňovský on 13/10/2019.
+ *
+ * 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_matchers_exception.hpp"
+
+
+namespace Catch {
+namespace Matchers {
+namespace Exception {
+
+bool ExceptionMessageMatcher::match(std::exception const& ex) const {
+ return ex.what() == m_message;
+}
+
+std::string ExceptionMessageMatcher::describe() const {
+ return "exception message matches \"" + m_message + "\"";
+}
+
+}
+Exception::ExceptionMessageMatcher Message(std::string const& message) {
+ return Exception::ExceptionMessageMatcher(message);
+}
+
+// namespace Exception
+} // namespace Matchers
+} // namespace Catch
diff --git a/include/internal/catch_matchers_exception.hpp b/include/internal/catch_matchers_exception.hpp
new file mode 100644
index 00000000..a80b3607
--- /dev/null
+++ b/include/internal/catch_matchers_exception.hpp
@@ -0,0 +1,36 @@
+/*
+ * Created by Martin Hořeňovský on 13/10/2019.
+ *
+ * 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_MATCHERS_EXCEPTION_HPP_INCLUDED
+#define TWOBLUECUBES_CATCH_MATCHERS_EXCEPTION_HPP_INCLUDED
+
+#include "catch_matchers.h"
+
+namespace Catch {
+namespace Matchers {
+namespace Exception {
+
+class ExceptionMessageMatcher : public MatcherBase<std::exception> {
+ std::string m_message;
+public:
+
+ ExceptionMessageMatcher(std::string const& message):
+ m_message(message)
+ {}
+
+ bool match(std::exception const& ex) const override;
+
+ std::string describe() const override;
+};
+
+} // namespace Exception
+
+Exception::ExceptionMessageMatcher Message(std::string const& message);
+
+} // namespace Matchers
+} // namespace Catch
+
+#endif // TWOBLUECUBES_CATCH_MATCHERS_EXCEPTION_HPP_INCLUDED
diff --git a/include/internal/catch_matchers_floating.cpp b/include/internal/catch_matchers_floating.cpp
index 9bc082ed..bcca0725 100644
--- a/include/internal/catch_matchers_floating.cpp
+++ b/include/internal/catch_matchers_floating.cpp
@@ -11,75 +11,102 @@
#include "catch_to_string.hpp"
#include "catch_tostring.h"
+#include <algorithm>
+#include <cmath>
#include <cstdlib>
#include <cstdint>
#include <cstring>
+#include <sstream>
+#include <type_traits>
+#include <iomanip>
+#include <limits>
-namespace Catch {
-namespace Matchers {
-namespace Floating {
-enum class FloatingPointKind : uint8_t {
- Float,
- Double
-};
-}
-}
-}
+namespace Catch {
namespace {
-template <typename T>
-struct Converter;
-
-template <>
-struct Converter<float> {
- static_assert(sizeof(float) == sizeof(int32_t), "Important ULP matcher assumption violated");
- Converter(float f) {
+ int32_t convert(float f) {
+ static_assert(sizeof(float) == sizeof(int32_t), "Important ULP matcher assumption violated");
+ int32_t i;
std::memcpy(&i, &f, sizeof(f));
+ return i;
}
- int32_t i;
-};
-template <>
-struct Converter<double> {
- static_assert(sizeof(double) == sizeof(int64_t), "Important ULP matcher assumption violated");
- Converter(double d) {
+ int64_t convert(double d) {
+ static_assert(sizeof(double) == sizeof(int64_t), "Important ULP matcher assumption violated");
+ int64_t i;
std::memcpy(&i, &d, sizeof(d));
+ return i;
}
- int64_t i;
-};
-template <typename T>
-auto convert(T t) -> Converter<T> {
- return Converter<T>(t);
-}
+ template <typename FP>
+ bool almostEqualUlps(FP lhs, FP rhs, uint64_t maxUlpDiff) {
+ // Comparison with NaN should always be false.
+ // This way we can rule it out before getting into the ugly details
+ if (Catch::isnan(lhs) || Catch::isnan(rhs)) {
+ return false;
+ }
-template <typename FP>
-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 (Catch::isnan(lhs) || Catch::isnan(rhs)) {
- return false;
+ auto lc = convert(lhs);
+ auto rc = convert(rhs);
+
+ if ((lc < 0) != (rc < 0)) {
+ // Potentially we can have +0 and -0
+ return lhs == rhs;
+ }
+
+ auto ulpDiff = std::abs(lc - rc);
+ return static_cast<uint64_t>(ulpDiff) <= maxUlpDiff;
+ }
+
+#if defined(CATCH_CONFIG_GLOBAL_NEXTAFTER)
+
+ float nextafter(float x, float y) {
+ return ::nextafterf(x, y);
+ }
+
+ double nextafter(double x, double y) {
+ return ::nextafter(x, y);
}
- auto lc = convert(lhs);
- auto rc = convert(rhs);
+#endif // ^^^ CATCH_CONFIG_GLOBAL_NEXTAFTER ^^^
- if ((lc.i < 0) != (rc.i < 0)) {
- // Potentially we can have +0 and -0
- return lhs == rhs;
+template <typename FP>
+FP step(FP start, FP direction, uint64_t steps) {
+ for (uint64_t i = 0; i < steps; ++i) {
+#if defined(CATCH_CONFIG_GLOBAL_NEXTAFTER)
+ start = Catch::nextafter(start, direction);
+#else
+ start = std::nextafter(start, direction);
+#endif
}
+ return start;
+}
- auto ulpDiff = std::abs(lc.i - rc.i);
- return ulpDiff <= maxUlpDiff;
+// Performs equivalent check of std::fabs(lhs - rhs) <= margin
+// But without the subtraction to allow for INFINITY in comparison
+bool marginComparison(double lhs, double rhs, double margin) {
+ return (lhs + margin >= rhs) && (rhs + margin >= lhs);
}
+template <typename FloatingPoint>
+void write(std::ostream& out, FloatingPoint num) {
+ out << std::scientific
+ << std::setprecision(std::numeric_limits<FloatingPoint>::max_digits10 - 1)
+ << num;
}
+} // end anonymous namespace
-namespace Catch {
namespace Matchers {
namespace Floating {
+
+ enum class FloatingPointKind : uint8_t {
+ Float,
+ Double
+ };
+
+
WithinAbsMatcher::WithinAbsMatcher(double target, double margin)
:m_target{ target }, m_margin{ margin } {
CATCH_ENFORCE(margin >= 0, "Invalid margin: " << margin << '.'
@@ -97,10 +124,11 @@ namespace Floating {
}
- WithinUlpsMatcher::WithinUlpsMatcher(double target, int ulps, FloatingPointKind baseType)
+ WithinUlpsMatcher::WithinUlpsMatcher(double target, uint64_t ulps, FloatingPointKind baseType)
:m_target{ target }, m_ulps{ ulps }, m_type{ baseType } {
- CATCH_ENFORCE(ulps >= 0, "Invalid ULP setting: " << ulps << '.'
- << " ULPs have to be non-negative.");
+ CATCH_ENFORCE(m_type == FloatingPointKind::Double
+ || m_ulps < (std::numeric_limits<uint32_t>::max)(),
+ "Provided ULP is impossibly large for a float comparison.");
}
#if defined(__clang__)
@@ -125,18 +153,61 @@ namespace Floating {
#endif
std::string WithinUlpsMatcher::describe() const {
- return "is within " + Catch::to_string(m_ulps) + " ULPs of " + ::Catch::Detail::stringify(m_target) + ((m_type == FloatingPointKind::Float)? "f" : "");
+ std::stringstream ret;
+
+ ret << "is within " << m_ulps << " ULPs of ";
+
+ if (m_type == FloatingPointKind::Float) {
+ write(ret, static_cast<float>(m_target));
+ ret << 'f';
+ } else {
+ write(ret, m_target);
+ }
+
+ ret << " ([";
+ if (m_type == FloatingPointKind::Double) {
+ write(ret, step(m_target, static_cast<double>(-INFINITY), m_ulps));
+ ret << ", ";
+ write(ret, step(m_target, static_cast<double>( INFINITY), m_ulps));
+ } else {
+ // We have to cast INFINITY to float because of MinGW, see #1782
+ write(ret, step(static_cast<float>(m_target), static_cast<float>(-INFINITY), m_ulps));
+ ret << ", ";
+ write(ret, step(static_cast<float>(m_target), static_cast<float>( INFINITY), m_ulps));
+ }
+ ret << "])";
+
+ return ret.str();
+ }
+
+ WithinRelMatcher::WithinRelMatcher(double target, double epsilon):
+ m_target(target),
+ m_epsilon(epsilon){
+ CATCH_ENFORCE(m_epsilon >= 0., "Relative comparison with epsilon < 0 does not make sense.");
+ CATCH_ENFORCE(m_epsilon < 1., "Relative comparison with epsilon >= 1 does not make sense.");
+ }
+
+ bool WithinRelMatcher::match(double const& matchee) const {
+ const auto relMargin = m_epsilon * (std::max)(std::fabs(matchee), std::fabs(m_target));
+ return marginComparison(matchee, m_target,
+ std::isinf(relMargin)? 0 : relMargin);
+ }
+
+ std::string WithinRelMatcher::describe() const {
+ Catch::ReusableStringStream sstr;
+ sstr << "and " << m_target << " are within " << m_epsilon * 100. << "% of each other";
+ return sstr.str();
}
}// namespace Floating
-Floating::WithinUlpsMatcher WithinULP(double target, int maxUlpDiff) {
+Floating::WithinUlpsMatcher WithinULP(double target, uint64_t maxUlpDiff) {
return Floating::WithinUlpsMatcher(target, maxUlpDiff, Floating::FloatingPointKind::Double);
}
-Floating::WithinUlpsMatcher WithinULP(float target, int maxUlpDiff) {
+Floating::WithinUlpsMatcher WithinULP(float target, uint64_t maxUlpDiff) {
return Floating::WithinUlpsMatcher(target, maxUlpDiff, Floating::FloatingPointKind::Float);
}
@@ -144,6 +215,23 @@ Floating::WithinAbsMatcher WithinAbs(double target, double margin) {
return Floating::WithinAbsMatcher(target, margin);
}
+Floating::WithinRelMatcher WithinRel(double target, double eps) {
+ return Floating::WithinRelMatcher(target, eps);
+}
+
+Floating::WithinRelMatcher WithinRel(double target) {
+ return Floating::WithinRelMatcher(target, std::numeric_limits<double>::epsilon() * 100);
+}
+
+Floating::WithinRelMatcher WithinRel(float target, float eps) {
+ return Floating::WithinRelMatcher(target, eps);
+}
+
+Floating::WithinRelMatcher WithinRel(float target) {
+ return Floating::WithinRelMatcher(target, std::numeric_limits<float>::epsilon() * 100);
+}
+
+
} // namespace Matchers
} // namespace Catch
diff --git a/include/internal/catch_matchers_floating.h b/include/internal/catch_matchers_floating.h
index ee077526..0f2ff49f 100644
--- a/include/internal/catch_matchers_floating.h
+++ b/include/internal/catch_matchers_floating.h
@@ -9,9 +9,6 @@
#include "catch_matchers.h"
-#include <type_traits>
-#include <cmath>
-
namespace Catch {
namespace Matchers {
@@ -29,23 +26,43 @@ namespace Matchers {
};
struct WithinUlpsMatcher : MatcherBase<double> {
- WithinUlpsMatcher(double target, int ulps, FloatingPointKind baseType);
+ WithinUlpsMatcher(double target, uint64_t ulps, FloatingPointKind baseType);
bool match(double const& matchee) const override;
std::string describe() const override;
private:
double m_target;
- int m_ulps;
+ uint64_t m_ulps;
FloatingPointKind m_type;
};
+ // Given IEEE-754 format for floats and doubles, we can assume
+ // that float -> double promotion is lossless. Given this, we can
+ // assume that if we do the standard relative comparison of
+ // |lhs - rhs| <= epsilon * max(fabs(lhs), fabs(rhs)), then we get
+ // the same result if we do this for floats, as if we do this for
+ // doubles that were promoted from floats.
+ struct WithinRelMatcher : MatcherBase<double> {
+ WithinRelMatcher(double target, double epsilon);
+ bool match(double const& matchee) const override;
+ std::string describe() const override;
+ private:
+ double m_target;
+ double m_epsilon;
+ };
} // 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::WithinUlpsMatcher WithinULP(double target, uint64_t maxUlpDiff);
+ Floating::WithinUlpsMatcher WithinULP(float target, uint64_t maxUlpDiff);
Floating::WithinAbsMatcher WithinAbs(double target, double margin);
+ Floating::WithinRelMatcher WithinRel(double target, double eps);
+ // defaults epsilon to 100*numeric_limits<double>::epsilon()
+ Floating::WithinRelMatcher WithinRel(double target);
+ Floating::WithinRelMatcher WithinRel(float target, float eps);
+ // defaults epsilon to 100*numeric_limits<float>::epsilon()
+ Floating::WithinRelMatcher WithinRel(float target);
} // namespace Matchers
} // namespace Catch
diff --git a/include/internal/catch_message.cpp b/include/internal/catch_message.cpp
index fa7e8746..64c817b7 100644
--- a/include/internal/catch_message.cpp
+++ b/include/internal/catch_message.cpp
@@ -9,6 +9,7 @@
#include "catch_message.h"
#include "catch_interfaces_capture.h"
#include "catch_uncaught_exceptions.h"
+#include "catch_enforce.h"
#include <cassert>
#include <stack>
@@ -76,6 +77,15 @@ namespace Catch {
}
return names.substr(start, end - start + 1);
};
+ auto skipq = [&] (size_t start, char quote) {
+ for (auto i = start + 1; i < names.size() ; ++i) {
+ if (names[i] == quote)
+ return i;
+ if (names[i] == '\\')
+ ++i;
+ }
+ CATCH_INTERNAL_ERROR("CAPTURE parsing encountered unmatched quote");
+ };
size_t start = 0;
std::stack<char> openings;
@@ -96,18 +106,22 @@ namespace Catch {
// case '>':
openings.pop();
break;
+ case '"':
+ case '\'':
+ pos = skipq(pos, c);
+ break;
case ',':
- if (start != pos && openings.size() == 0) {
+ if (start != pos && openings.empty()) {
m_messages.emplace_back(macroName, lineInfo, resultType);
- m_messages.back().message = trimmed(start, pos);
+ m_messages.back().message = static_cast<std::string>(trimmed(start, pos));
m_messages.back().message += " := ";
start = pos;
}
}
}
- assert(openings.size() == 0 && "Mismatched openings");
+ assert(openings.empty() && "Mismatched openings");
m_messages.emplace_back(macroName, lineInfo, resultType);
- m_messages.back().message = trimmed(start, names.size() - 1);
+ m_messages.back().message = static_cast<std::string>(trimmed(start, names.size() - 1));
m_messages.back().message += " := ";
}
Capturer::~Capturer() {
diff --git a/include/internal/catch_meta.hpp b/include/internal/catch_meta.hpp
index 3508a46f..4eca7efc 100644
--- a/include/internal/catch_meta.hpp
+++ b/include/internal/catch_meta.hpp
@@ -12,66 +12,39 @@
#include <type_traits>
namespace Catch {
-template< typename... >
-struct TypeList {};
-
-template< typename... >
-struct append;
-
-template< template<typename...> class L1
- , typename...E1
- , template<typename...> class L2
- , typename...E2
->
-struct append< L1<E1...>, L2<E2...> > {
- using type = L1<E1..., E2...>;
-};
-
-template< template<typename...> class L1
- , typename...E1
- , template<typename...> class L2
- , typename...E2
- , typename...Rest
->
-struct append< L1<E1...>, L2<E2...>, Rest...> {
- using type = typename append< L1<E1..., E2...>, Rest... >::type;
-};
-
-template< template<typename...> class
- , typename...
->
-struct rewrap;
+ template<typename T>
+ struct always_false : std::false_type {};
+
+ template <typename> struct true_given : std::true_type {};
+ struct is_callable_tester {
+ template <typename Fun, typename... Args>
+ true_given<decltype(std::declval<Fun>()(std::declval<Args>()...))> static test(int);
+ template <typename...>
+ std::false_type static test(...);
+ };
-template< template<typename...> class Container
- , template<typename...> class List
- , typename...elems
->
-struct rewrap<Container, List<elems...>> {
- using type = TypeList< Container< elems... > >;
-};
+ template <typename T>
+ struct is_callable;
-template< template<typename...> class Container
- , template<typename...> class List
- , class...Elems
- , typename...Elements>
- struct rewrap<Container, List<Elems...>, Elements...> {
- using type = typename append<TypeList<Container<Elems...>>, typename rewrap<Container, Elements...>::type>::type;
-};
+ template <typename Fun, typename... Args>
+ struct is_callable<Fun(Args...)> : decltype(is_callable_tester::test<Fun, Args...>(0)) {};
-template< template<typename...> class...Containers >
-struct combine {
- template< typename...Types >
- struct with_types {
- template< template <typename...> class Final >
- struct into {
- using type = typename append<Final<>, typename rewrap<Containers, Types...>::type...>::type;
- };
- };
-};
-template<typename T>
-struct always_false : std::false_type {};
+#if defined(__cpp_lib_is_invocable) && __cpp_lib_is_invocable >= 201703
+ // std::result_of is deprecated in C++17 and removed in C++20. Hence, it is
+ // replaced with std::invoke_result here. Also *_t format is preferred over
+ // typename *::type format.
+ template <typename Func, typename U>
+ using FunctionReturnType = std::remove_reference_t<std::remove_cv_t<std::invoke_result_t<Func, U>>>;
+#else
+ template <typename Func, typename U>
+ using FunctionReturnType = typename std::remove_reference<typename std::remove_cv<typename std::result_of<Func(U)>::type>::type>::type;
+#endif
} // namespace Catch
+namespace mpl_{
+ struct na;
+}
+
#endif // TWOBLUECUBES_CATCH_META_HPP_INCLUDED
diff --git a/include/internal/catch_objc.hpp b/include/internal/catch_objc.hpp
index f927e0d3..a1c8e074 100644
--- a/include/internal/catch_objc.hpp
+++ b/include/internal/catch_objc.hpp
@@ -116,7 +116,7 @@ namespace Catch {
arcSafeRelease( m_substr );
}
- bool match( NSString* const& str ) const override {
+ bool match( NSString* str ) const override {
return false;
}
@@ -126,7 +126,7 @@ namespace Catch {
struct Equals : StringHolder {
Equals( NSString* substr ) : StringHolder( substr ){}
- bool match( NSString* const& str ) const override {
+ bool match( NSString* str ) const override {
return (str != nil || m_substr == nil ) &&
[str isEqualToString:m_substr];
}
@@ -139,7 +139,7 @@ namespace Catch {
struct Contains : StringHolder {
Contains( NSString* substr ) : StringHolder( substr ){}
- bool match( NSString* const& str ) const override {
+ bool match( NSString* str ) const override {
return (str != nil || m_substr == nil ) &&
[str rangeOfString:m_substr].location != NSNotFound;
}
@@ -152,7 +152,7 @@ namespace Catch {
struct StartsWith : StringHolder {
StartsWith( NSString* substr ) : StringHolder( substr ){}
- bool match( NSString* const& str ) const override {
+ bool match( NSString* str ) const override {
return (str != nil || m_substr == nil ) &&
[str rangeOfString:m_substr].location == 0;
}
@@ -164,7 +164,7 @@ namespace Catch {
struct EndsWith : StringHolder {
EndsWith( NSString* substr ) : StringHolder( substr ){}
- bool match( NSString* const& str ) const override {
+ bool match( NSString* str ) const override {
return (str != nil || m_substr == nil ) &&
[str rangeOfString:m_substr].location == [str length] - [m_substr length];
}
diff --git a/include/internal/catch_preprocessor.hpp b/include/internal/catch_preprocessor.hpp
index faf41e6b..f1bd0905 100644
--- a/include/internal/catch_preprocessor.hpp
+++ b/include/internal/catch_preprocessor.hpp
@@ -68,22 +68,169 @@
#define INTERNAL_CATCH_STRINGIZE_WITHOUT_PARENS(param) (INTERNAL_CATCH_STRINGIZE(INTERNAL_CATCH_REMOVE_PARENS(param)) + 1)
#endif
+#define INTERNAL_CATCH_MAKE_NAMESPACE2(...) ns_##__VA_ARGS__
+#define INTERNAL_CATCH_MAKE_NAMESPACE(name) INTERNAL_CATCH_MAKE_NAMESPACE2(name)
+
#define INTERNAL_CATCH_REMOVE_PARENS(...) INTERNAL_CATCH_EXPAND1(INTERNAL_CATCH_DEF __VA_ARGS__)
-#define INTERNAL_CATCH_TEMPLATE_UNIQUE_NAME2(Name, ...) INTERNAL_CATCH_TEMPLATE_UNIQUE_NAME3(Name, __VA_ARGS__)
#ifndef CATCH_CONFIG_TRADITIONAL_MSVC_PREPROCESSOR
-#define INTERNAL_CATCH_TEMPLATE_UNIQUE_NAME3(Name,...) Name " - " #__VA_ARGS__
-#define INTERNAL_CATCH_TEMPLATE_UNIQUE_NAME(Name,...) INTERNAL_CATCH_TEMPLATE_UNIQUE_NAME2(Name, INTERNAL_CATCH_REMOVE_PARENS(__VA_ARGS__))
+#define INTERNAL_CATCH_MAKE_TYPE_LIST2(...) decltype(get_wrapper<INTERNAL_CATCH_REMOVE_PARENS_GEN(__VA_ARGS__)>())
+#define INTERNAL_CATCH_MAKE_TYPE_LIST(...) INTERNAL_CATCH_MAKE_TYPE_LIST2(INTERNAL_CATCH_REMOVE_PARENS(__VA_ARGS__))
#else
-// MSVC is adding extra space and needs more calls to properly remove ()
-#define INTERNAL_CATCH_TEMPLATE_UNIQUE_NAME3(Name,...) Name " -" #__VA_ARGS__
-#define INTERNAL_CATCH_TEMPLATE_UNIQUE_NAME1(Name, ...) INTERNAL_CATCH_TEMPLATE_UNIQUE_NAME2(Name, __VA_ARGS__)
-#define INTERNAL_CATCH_TEMPLATE_UNIQUE_NAME(Name, ...) INTERNAL_CATCH_TEMPLATE_UNIQUE_NAME1(Name, INTERNAL_CATCH_EXPAND_VARGS(INTERNAL_CATCH_REMOVE_PARENS(__VA_ARGS__)))
+#define INTERNAL_CATCH_MAKE_TYPE_LIST2(...) INTERNAL_CATCH_EXPAND_VARGS(decltype(get_wrapper<INTERNAL_CATCH_REMOVE_PARENS_GEN(__VA_ARGS__)>()))
+#define INTERNAL_CATCH_MAKE_TYPE_LIST(...) INTERNAL_CATCH_EXPAND_VARGS(INTERNAL_CATCH_MAKE_TYPE_LIST2(INTERNAL_CATCH_REMOVE_PARENS(__VA_ARGS__)))
#endif
-#define INTERNAL_CATCH_MAKE_TYPE_LIST(types) Catch::TypeList<INTERNAL_CATCH_REMOVE_PARENS(types)>
+#define INTERNAL_CATCH_MAKE_TYPE_LISTS_FROM_TYPES(...)\
+ CATCH_REC_LIST(INTERNAL_CATCH_MAKE_TYPE_LIST,__VA_ARGS__)
+
+#define INTERNAL_CATCH_REMOVE_PARENS_1_ARG(_0) INTERNAL_CATCH_REMOVE_PARENS(_0)
+#define INTERNAL_CATCH_REMOVE_PARENS_2_ARG(_0, _1) INTERNAL_CATCH_REMOVE_PARENS(_0), INTERNAL_CATCH_REMOVE_PARENS_1_ARG(_1)
+#define INTERNAL_CATCH_REMOVE_PARENS_3_ARG(_0, _1, _2) INTERNAL_CATCH_REMOVE_PARENS(_0), INTERNAL_CATCH_REMOVE_PARENS_2_ARG(_1, _2)
+#define INTERNAL_CATCH_REMOVE_PARENS_4_ARG(_0, _1, _2, _3) INTERNAL_CATCH_REMOVE_PARENS(_0), INTERNAL_CATCH_REMOVE_PARENS_3_ARG(_1, _2, _3)
+#define INTERNAL_CATCH_REMOVE_PARENS_5_ARG(_0, _1, _2, _3, _4) INTERNAL_CATCH_REMOVE_PARENS(_0), INTERNAL_CATCH_REMOVE_PARENS_4_ARG(_1, _2, _3, _4)
+#define INTERNAL_CATCH_REMOVE_PARENS_6_ARG(_0, _1, _2, _3, _4, _5) INTERNAL_CATCH_REMOVE_PARENS(_0), INTERNAL_CATCH_REMOVE_PARENS_5_ARG(_1, _2, _3, _4, _5)
+#define INTERNAL_CATCH_REMOVE_PARENS_7_ARG(_0, _1, _2, _3, _4, _5, _6) INTERNAL_CATCH_REMOVE_PARENS(_0), INTERNAL_CATCH_REMOVE_PARENS_6_ARG(_1, _2, _4, _5, _6)
+#define INTERNAL_CATCH_REMOVE_PARENS_8_ARG(_0, _1, _2, _3, _4, _5, _6, _7) INTERNAL_CATCH_REMOVE_PARENS(_0), INTERNAL_CATCH_REMOVE_PARENS_7_ARG(_1, _2, _3, _4, _5, _6, _7)
+#define INTERNAL_CATCH_REMOVE_PARENS_9_ARG(_0, _1, _2, _3, _4, _5, _6, _7, _8) INTERNAL_CATCH_REMOVE_PARENS(_0), INTERNAL_CATCH_REMOVE_PARENS_8_ARG(_1, _2, _3, _4, _5, _6, _7, _8)
+#define INTERNAL_CATCH_REMOVE_PARENS_10_ARG(_0, _1, _2, _3, _4, _5, _6, _7, _8, _9) INTERNAL_CATCH_REMOVE_PARENS(_0), INTERNAL_CATCH_REMOVE_PARENS_9_ARG(_1, _2, _3, _4, _5, _6, _7, _8, _9)
+#define INTERNAL_CATCH_REMOVE_PARENS_11_ARG(_0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10) INTERNAL_CATCH_REMOVE_PARENS(_0), INTERNAL_CATCH_REMOVE_PARENS_10_ARG(_1, _2, _3, _4, _5, _6, _7, _8, _9, _10)
+
+#define INTERNAL_CATCH_VA_NARGS_IMPL(_0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, N, ...) N
+
+#define INTERNAL_CATCH_TYPE_GEN\
+ template<typename...> struct TypeList {};\
+ template<typename...Ts>\
+ constexpr auto get_wrapper() noexcept -> TypeList<Ts...> { return {}; }\
+ template<template<typename...> class...> struct TemplateTypeList{};\
+ template<template<typename...> class...Cs>\
+ constexpr auto get_wrapper() noexcept -> TemplateTypeList<Cs...> { return {}; }\
+ template<typename...>\
+ struct append;\
+ template<typename...>\
+ struct rewrap;\
+ template<template<typename...> class, typename...>\
+ struct create;\
+ template<template<typename...> class, typename>\
+ struct convert;\
+ \
+ template<typename T> \
+ struct append<T> { using type = T; };\
+ template< template<typename...> class L1, typename...E1, template<typename...> class L2, typename...E2, typename...Rest>\
+ struct append<L1<E1...>, L2<E2...>, Rest...> { using type = typename append<L1<E1...,E2...>, Rest...>::type; };\
+ template< template<typename...> class L1, typename...E1, typename...Rest>\
+ struct append<L1<E1...>, TypeList<mpl_::na>, Rest...> { using type = L1<E1...>; };\
+ \
+ template< template<typename...> class Container, template<typename...> class List, typename...elems>\
+ struct rewrap<TemplateTypeList<Container>, List<elems...>> { using type = TypeList<Container<elems...>>; };\
+ template< template<typename...> class Container, template<typename...> class List, class...Elems, typename...Elements>\
+ struct rewrap<TemplateTypeList<Container>, List<Elems...>, Elements...> { using type = typename append<TypeList<Container<Elems...>>, typename rewrap<TemplateTypeList<Container>, Elements...>::type>::type; };\
+ \
+ template<template <typename...> class Final, template< typename...> class...Containers, typename...Types>\
+ struct create<Final, TemplateTypeList<Containers...>, TypeList<Types...>> { using type = typename append<Final<>, typename rewrap<TemplateTypeList<Containers>, Types...>::type...>::type; };\
+ template<template <typename...> class Final, template <typename...> class List, typename...Ts>\
+ struct convert<Final, List<Ts...>> { using type = typename append<Final<>,TypeList<Ts>...>::type; };
+
+#define INTERNAL_CATCH_NTTP_1(signature, ...)\
+ template<INTERNAL_CATCH_REMOVE_PARENS(signature)> struct Nttp{};\
+ template<INTERNAL_CATCH_REMOVE_PARENS(signature)>\
+ constexpr auto get_wrapper() noexcept -> Nttp<__VA_ARGS__> { return {}; } \
+ template<template<INTERNAL_CATCH_REMOVE_PARENS(signature)> class...> struct NttpTemplateTypeList{};\
+ template<template<INTERNAL_CATCH_REMOVE_PARENS(signature)> class...Cs>\
+ constexpr auto get_wrapper() noexcept -> NttpTemplateTypeList<Cs...> { return {}; } \
+ \
+ template< template<INTERNAL_CATCH_REMOVE_PARENS(signature)> class Container, template<INTERNAL_CATCH_REMOVE_PARENS(signature)> class List, INTERNAL_CATCH_REMOVE_PARENS(signature)>\
+ struct rewrap<NttpTemplateTypeList<Container>, List<__VA_ARGS__>> { using type = TypeList<Container<__VA_ARGS__>>; };\
+ template< template<INTERNAL_CATCH_REMOVE_PARENS(signature)> class Container, template<INTERNAL_CATCH_REMOVE_PARENS(signature)> class List, INTERNAL_CATCH_REMOVE_PARENS(signature), typename...Elements>\
+ struct rewrap<NttpTemplateTypeList<Container>, List<__VA_ARGS__>, Elements...> { using type = typename append<TypeList<Container<__VA_ARGS__>>, typename rewrap<NttpTemplateTypeList<Container>, Elements...>::type>::type; };\
+ template<template <typename...> class Final, template<INTERNAL_CATCH_REMOVE_PARENS(signature)> class...Containers, typename...Types>\
+ struct create<Final, NttpTemplateTypeList<Containers...>, TypeList<Types...>> { using type = typename append<Final<>, typename rewrap<NttpTemplateTypeList<Containers>, Types...>::type...>::type; };
+
+#define INTERNAL_CATCH_DECLARE_SIG_TEST0(TestName)
+#define INTERNAL_CATCH_DECLARE_SIG_TEST1(TestName, signature)\
+ template<INTERNAL_CATCH_REMOVE_PARENS(signature)>\
+ static void TestName()
+#define INTERNAL_CATCH_DECLARE_SIG_TEST_X(TestName, signature, ...)\
+ template<INTERNAL_CATCH_REMOVE_PARENS(signature)>\
+ static void TestName()
+
+#define INTERNAL_CATCH_DEFINE_SIG_TEST0(TestName)
+#define INTERNAL_CATCH_DEFINE_SIG_TEST1(TestName, signature)\
+ template<INTERNAL_CATCH_REMOVE_PARENS(signature)>\
+ static void TestName()
+#define INTERNAL_CATCH_DEFINE_SIG_TEST_X(TestName, signature,...)\
+ template<INTERNAL_CATCH_REMOVE_PARENS(signature)>\
+ static void TestName()
+
+#define INTERNAL_CATCH_NTTP_REGISTER0(TestFunc, signature)\
+ template<typename Type>\
+ void reg_test(TypeList<Type>, Catch::NameAndTags nameAndTags)\
+ {\
+ Catch::AutoReg( Catch::makeTestInvoker(&TestFunc<Type>), CATCH_INTERNAL_LINEINFO, Catch::StringRef(), nameAndTags);\
+ }
+
+#define INTERNAL_CATCH_NTTP_REGISTER(TestFunc, signature, ...)\
+ template<INTERNAL_CATCH_REMOVE_PARENS(signature)>\
+ void reg_test(Nttp<__VA_ARGS__>, Catch::NameAndTags nameAndTags)\
+ {\
+ Catch::AutoReg( Catch::makeTestInvoker(&TestFunc<__VA_ARGS__>), CATCH_INTERNAL_LINEINFO, Catch::StringRef(), nameAndTags);\
+ }
+
+#define INTERNAL_CATCH_NTTP_REGISTER_METHOD0(TestName, signature, ...)\
+ template<typename Type>\
+ void reg_test(TypeList<Type>, Catch::StringRef className, Catch::NameAndTags nameAndTags)\
+ {\
+ Catch::AutoReg( Catch::makeTestInvoker(&TestName<Type>::test), CATCH_INTERNAL_LINEINFO, className, nameAndTags);\
+ }
+
+#define INTERNAL_CATCH_NTTP_REGISTER_METHOD(TestName, signature, ...)\
+ template<INTERNAL_CATCH_REMOVE_PARENS(signature)>\
+ void reg_test(Nttp<__VA_ARGS__>, Catch::StringRef className, Catch::NameAndTags nameAndTags)\
+ {\
+ Catch::AutoReg( Catch::makeTestInvoker(&TestName<__VA_ARGS__>::test), CATCH_INTERNAL_LINEINFO, className, nameAndTags);\
+ }
+
+#define INTERNAL_CATCH_DECLARE_SIG_TEST_METHOD0(TestName, ClassName)
+#define INTERNAL_CATCH_DECLARE_SIG_TEST_METHOD1(TestName, ClassName, signature)\
+ template<typename TestType> \
+ struct TestName : INTERNAL_CATCH_REMOVE_PARENS(ClassName)<TestType> { \
+ void test();\
+ }
+
+#define INTERNAL_CATCH_DECLARE_SIG_TEST_METHOD_X(TestName, ClassName, signature, ...)\
+ template<INTERNAL_CATCH_REMOVE_PARENS(signature)> \
+ struct TestName : INTERNAL_CATCH_REMOVE_PARENS(ClassName)<__VA_ARGS__> { \
+ void test();\
+ }
+
+#define INTERNAL_CATCH_DEFINE_SIG_TEST_METHOD0(TestName)
+#define INTERNAL_CATCH_DEFINE_SIG_TEST_METHOD1(TestName, signature)\
+ template<typename TestType> \
+ void INTERNAL_CATCH_MAKE_NAMESPACE(TestName)::TestName<TestType>::test()
+#define INTERNAL_CATCH_DEFINE_SIG_TEST_METHOD_X(TestName, signature, ...)\
+ template<INTERNAL_CATCH_REMOVE_PARENS(signature)> \
+ void INTERNAL_CATCH_MAKE_NAMESPACE(TestName)::TestName<__VA_ARGS__>::test()
-#define INTERNAL_CATCH_MAKE_TYPE_LISTS_FROM_TYPES(types)\
- CATCH_REC_LIST(INTERNAL_CATCH_MAKE_TYPE_LIST,INTERNAL_CATCH_REMOVE_PARENS(types))
+#ifndef CATCH_CONFIG_TRADITIONAL_MSVC_PREPROCESSOR
+#define INTERNAL_CATCH_NTTP_0
+#define INTERNAL_CATCH_NTTP_GEN(...) INTERNAL_CATCH_VA_NARGS_IMPL(__VA_ARGS__, INTERNAL_CATCH_NTTP_1(__VA_ARGS__), INTERNAL_CATCH_NTTP_1(__VA_ARGS__), INTERNAL_CATCH_NTTP_1(__VA_ARGS__), INTERNAL_CATCH_NTTP_1(__VA_ARGS__), INTERNAL_CATCH_NTTP_1(__VA_ARGS__), INTERNAL_CATCH_NTTP_1( __VA_ARGS__), INTERNAL_CATCH_NTTP_1( __VA_ARGS__), INTERNAL_CATCH_NTTP_1( __VA_ARGS__), INTERNAL_CATCH_NTTP_1( __VA_ARGS__),INTERNAL_CATCH_NTTP_1( __VA_ARGS__), INTERNAL_CATCH_NTTP_0)
+#define INTERNAL_CATCH_DEFINE_SIG_TEST_METHOD(TestName, ...) INTERNAL_CATCH_VA_NARGS_IMPL( "dummy", __VA_ARGS__, INTERNAL_CATCH_DEFINE_SIG_TEST_METHOD_X,INTERNAL_CATCH_DEFINE_SIG_TEST_METHOD_X, INTERNAL_CATCH_DEFINE_SIG_TEST_METHOD_X, INTERNAL_CATCH_DEFINE_SIG_TEST_METHOD_X, INTERNAL_CATCH_DEFINE_SIG_TEST_METHOD_X, INTERNAL_CATCH_DEFINE_SIG_TEST_METHOD_X, INTERNAL_CATCH_DEFINE_SIG_TEST_METHOD_X,INTERNAL_CATCH_DEFINE_SIG_TEST_METHOD_X,INTERNAL_CATCH_DEFINE_SIG_TEST_METHOD_X, INTERNAL_CATCH_DEFINE_SIG_TEST_METHOD1, INTERNAL_CATCH_DEFINE_SIG_TEST_METHOD0)(TestName, __VA_ARGS__)
+#define INTERNAL_CATCH_DECLARE_SIG_TEST_METHOD(TestName, ClassName, ...) INTERNAL_CATCH_VA_NARGS_IMPL( "dummy", __VA_ARGS__, INTERNAL_CATCH_DECLARE_SIG_TEST_METHOD_X,INTERNAL_CATCH_DECLARE_SIG_TEST_METHOD_X, INTERNAL_CATCH_DECLARE_SIG_TEST_METHOD_X, INTERNAL_CATCH_DECLARE_SIG_TEST_METHOD_X, INTERNAL_CATCH_DECLARE_SIG_TEST_METHOD_X, INTERNAL_CATCH_DECLARE_SIG_TEST_METHOD_X, INTERNAL_CATCH_DECLARE_SIG_TEST_METHOD_X,INTERNAL_CATCH_DECLARE_SIG_TEST_METHOD_X,INTERNAL_CATCH_DECLARE_SIG_TEST_METHOD_X, INTERNAL_CATCH_DECLARE_SIG_TEST_METHOD1, INTERNAL_CATCH_DECLARE_SIG_TEST_METHOD0)(TestName, ClassName, __VA_ARGS__)
+#define INTERNAL_CATCH_NTTP_REG_METHOD_GEN(TestName, ...) INTERNAL_CATCH_VA_NARGS_IMPL( "dummy", __VA_ARGS__, INTERNAL_CATCH_NTTP_REGISTER_METHOD, INTERNAL_CATCH_NTTP_REGISTER_METHOD, INTERNAL_CATCH_NTTP_REGISTER_METHOD, INTERNAL_CATCH_NTTP_REGISTER_METHOD, INTERNAL_CATCH_NTTP_REGISTER_METHOD, INTERNAL_CATCH_NTTP_REGISTER_METHOD, INTERNAL_CATCH_NTTP_REGISTER_METHOD, INTERNAL_CATCH_NTTP_REGISTER_METHOD, INTERNAL_CATCH_NTTP_REGISTER_METHOD, INTERNAL_CATCH_NTTP_REGISTER_METHOD0, INTERNAL_CATCH_NTTP_REGISTER_METHOD0)(TestName, __VA_ARGS__)
+#define INTERNAL_CATCH_NTTP_REG_GEN(TestFunc, ...) INTERNAL_CATCH_VA_NARGS_IMPL( "dummy", __VA_ARGS__, INTERNAL_CATCH_NTTP_REGISTER, INTERNAL_CATCH_NTTP_REGISTER, INTERNAL_CATCH_NTTP_REGISTER, INTERNAL_CATCH_NTTP_REGISTER, INTERNAL_CATCH_NTTP_REGISTER, INTERNAL_CATCH_NTTP_REGISTER, INTERNAL_CATCH_NTTP_REGISTER, INTERNAL_CATCH_NTTP_REGISTER, INTERNAL_CATCH_NTTP_REGISTER, INTERNAL_CATCH_NTTP_REGISTER0, INTERNAL_CATCH_NTTP_REGISTER0)(TestFunc, __VA_ARGS__)
+#define INTERNAL_CATCH_DEFINE_SIG_TEST(TestName, ...) INTERNAL_CATCH_VA_NARGS_IMPL( "dummy", __VA_ARGS__, INTERNAL_CATCH_DEFINE_SIG_TEST_X, INTERNAL_CATCH_DEFINE_SIG_TEST_X, INTERNAL_CATCH_DEFINE_SIG_TEST_X, INTERNAL_CATCH_DEFINE_SIG_TEST_X, INTERNAL_CATCH_DEFINE_SIG_TEST_X, INTERNAL_CATCH_DEFINE_SIG_TEST_X, INTERNAL_CATCH_DEFINE_SIG_TEST_X, INTERNAL_CATCH_DEFINE_SIG_TEST_X,INTERNAL_CATCH_DEFINE_SIG_TEST_X,INTERNAL_CATCH_DEFINE_SIG_TEST1, INTERNAL_CATCH_DEFINE_SIG_TEST0)(TestName, __VA_ARGS__)
+#define INTERNAL_CATCH_DECLARE_SIG_TEST(TestName, ...) INTERNAL_CATCH_VA_NARGS_IMPL( "dummy", __VA_ARGS__, INTERNAL_CATCH_DECLARE_SIG_TEST_X,INTERNAL_CATCH_DECLARE_SIG_TEST_X, INTERNAL_CATCH_DECLARE_SIG_TEST_X, INTERNAL_CATCH_DECLARE_SIG_TEST_X, INTERNAL_CATCH_DECLARE_SIG_TEST_X, INTERNAL_CATCH_DECLARE_SIG_TEST_X, INTERNAL_CATCH_DEFINE_SIG_TEST_X,INTERNAL_CATCH_DECLARE_SIG_TEST_X,INTERNAL_CATCH_DECLARE_SIG_TEST_X, INTERNAL_CATCH_DECLARE_SIG_TEST1, INTERNAL_CATCH_DECLARE_SIG_TEST0)(TestName, __VA_ARGS__)
+#define INTERNAL_CATCH_REMOVE_PARENS_GEN(...) INTERNAL_CATCH_VA_NARGS_IMPL(__VA_ARGS__, INTERNAL_CATCH_REMOVE_PARENS_11_ARG,INTERNAL_CATCH_REMOVE_PARENS_10_ARG,INTERNAL_CATCH_REMOVE_PARENS_9_ARG,INTERNAL_CATCH_REMOVE_PARENS_8_ARG,INTERNAL_CATCH_REMOVE_PARENS_7_ARG,INTERNAL_CATCH_REMOVE_PARENS_6_ARG,INTERNAL_CATCH_REMOVE_PARENS_5_ARG,INTERNAL_CATCH_REMOVE_PARENS_4_ARG,INTERNAL_CATCH_REMOVE_PARENS_3_ARG,INTERNAL_CATCH_REMOVE_PARENS_2_ARG,INTERNAL_CATCH_REMOVE_PARENS_1_ARG)(__VA_ARGS__)
+#else
+#define INTERNAL_CATCH_NTTP_0(signature)
+#define INTERNAL_CATCH_NTTP_GEN(...) INTERNAL_CATCH_EXPAND_VARGS(INTERNAL_CATCH_VA_NARGS_IMPL(__VA_ARGS__, INTERNAL_CATCH_NTTP_1, INTERNAL_CATCH_NTTP_1, INTERNAL_CATCH_NTTP_1, INTERNAL_CATCH_NTTP_1, INTERNAL_CATCH_NTTP_1, INTERNAL_CATCH_NTTP_1, INTERNAL_CATCH_NTTP_1, INTERNAL_CATCH_NTTP_1, INTERNAL_CATCH_NTTP_1,INTERNAL_CATCH_NTTP_1, INTERNAL_CATCH_NTTP_0)( __VA_ARGS__))
+#define INTERNAL_CATCH_DEFINE_SIG_TEST_METHOD(TestName, ...) INTERNAL_CATCH_EXPAND_VARGS(INTERNAL_CATCH_VA_NARGS_IMPL( "dummy", __VA_ARGS__, INTERNAL_CATCH_DEFINE_SIG_TEST_METHOD_X,INTERNAL_CATCH_DEFINE_SIG_TEST_METHOD_X, INTERNAL_CATCH_DEFINE_SIG_TEST_METHOD_X, INTERNAL_CATCH_DEFINE_SIG_TEST_METHOD_X, INTERNAL_CATCH_DEFINE_SIG_TEST_METHOD_X, INTERNAL_CATCH_DEFINE_SIG_TEST_METHOD_X, INTERNAL_CATCH_DEFINE_SIG_TEST_METHOD_X,INTERNAL_CATCH_DEFINE_SIG_TEST_METHOD_X,INTERNAL_CATCH_DEFINE_SIG_TEST_METHOD_X, INTERNAL_CATCH_DEFINE_SIG_TEST_METHOD1, INTERNAL_CATCH_DEFINE_SIG_TEST_METHOD0)(TestName, __VA_ARGS__))
+#define INTERNAL_CATCH_DECLARE_SIG_TEST_METHOD(TestName, ClassName, ...) INTERNAL_CATCH_EXPAND_VARGS(INTERNAL_CATCH_VA_NARGS_IMPL( "dummy", __VA_ARGS__, INTERNAL_CATCH_DECLARE_SIG_TEST_METHOD_X,INTERNAL_CATCH_DECLARE_SIG_TEST_METHOD_X, INTERNAL_CATCH_DECLARE_SIG_TEST_METHOD_X, INTERNAL_CATCH_DECLARE_SIG_TEST_METHOD_X, INTERNAL_CATCH_DECLARE_SIG_TEST_METHOD_X, INTERNAL_CATCH_DECLARE_SIG_TEST_METHOD_X, INTERNAL_CATCH_DECLARE_SIG_TEST_METHOD_X,INTERNAL_CATCH_DECLARE_SIG_TEST_METHOD_X,INTERNAL_CATCH_DECLARE_SIG_TEST_METHOD_X, INTERNAL_CATCH_DECLARE_SIG_TEST_METHOD1, INTERNAL_CATCH_DECLARE_SIG_TEST_METHOD0)(TestName, ClassName, __VA_ARGS__))
+#define INTERNAL_CATCH_NTTP_REG_METHOD_GEN(TestName, ...) INTERNAL_CATCH_EXPAND_VARGS(INTERNAL_CATCH_VA_NARGS_IMPL( "dummy", __VA_ARGS__, INTERNAL_CATCH_NTTP_REGISTER_METHOD, INTERNAL_CATCH_NTTP_REGISTER_METHOD, INTERNAL_CATCH_NTTP_REGISTER_METHOD, INTERNAL_CATCH_NTTP_REGISTER_METHOD, INTERNAL_CATCH_NTTP_REGISTER_METHOD, INTERNAL_CATCH_NTTP_REGISTER_METHOD, INTERNAL_CATCH_NTTP_REGISTER_METHOD, INTERNAL_CATCH_NTTP_REGISTER_METHOD, INTERNAL_CATCH_NTTP_REGISTER_METHOD, INTERNAL_CATCH_NTTP_REGISTER_METHOD0, INTERNAL_CATCH_NTTP_REGISTER_METHOD0)(TestName, __VA_ARGS__))
+#define INTERNAL_CATCH_NTTP_REG_GEN(TestFunc, ...) INTERNAL_CATCH_EXPAND_VARGS(INTERNAL_CATCH_VA_NARGS_IMPL( "dummy", __VA_ARGS__, INTERNAL_CATCH_NTTP_REGISTER, INTERNAL_CATCH_NTTP_REGISTER, INTERNAL_CATCH_NTTP_REGISTER, INTERNAL_CATCH_NTTP_REGISTER, INTERNAL_CATCH_NTTP_REGISTER, INTERNAL_CATCH_NTTP_REGISTER, INTERNAL_CATCH_NTTP_REGISTER, INTERNAL_CATCH_NTTP_REGISTER, INTERNAL_CATCH_NTTP_REGISTER, INTERNAL_CATCH_NTTP_REGISTER0, INTERNAL_CATCH_NTTP_REGISTER0)(TestFunc, __VA_ARGS__))
+#define INTERNAL_CATCH_DEFINE_SIG_TEST(TestName, ...) INTERNAL_CATCH_EXPAND_VARGS(INTERNAL_CATCH_VA_NARGS_IMPL( "dummy", __VA_ARGS__, INTERNAL_CATCH_DEFINE_SIG_TEST_X, INTERNAL_CATCH_DEFINE_SIG_TEST_X, INTERNAL_CATCH_DEFINE_SIG_TEST_X, INTERNAL_CATCH_DEFINE_SIG_TEST_X, INTERNAL_CATCH_DEFINE_SIG_TEST_X, INTERNAL_CATCH_DEFINE_SIG_TEST_X, INTERNAL_CATCH_DEFINE_SIG_TEST_X, INTERNAL_CATCH_DEFINE_SIG_TEST_X,INTERNAL_CATCH_DEFINE_SIG_TEST_X,INTERNAL_CATCH_DEFINE_SIG_TEST1, INTERNAL_CATCH_DEFINE_SIG_TEST0)(TestName, __VA_ARGS__))
+#define INTERNAL_CATCH_DECLARE_SIG_TEST(TestName, ...) INTERNAL_CATCH_EXPAND_VARGS(INTERNAL_CATCH_VA_NARGS_IMPL( "dummy", __VA_ARGS__, INTERNAL_CATCH_DECLARE_SIG_TEST_X,INTERNAL_CATCH_DECLARE_SIG_TEST_X, INTERNAL_CATCH_DECLARE_SIG_TEST_X, INTERNAL_CATCH_DECLARE_SIG_TEST_X, INTERNAL_CATCH_DECLARE_SIG_TEST_X, INTERNAL_CATCH_DECLARE_SIG_TEST_X, INTERNAL_CATCH_DEFINE_SIG_TEST_X,INTERNAL_CATCH_DECLARE_SIG_TEST_X,INTERNAL_CATCH_DECLARE_SIG_TEST_X, INTERNAL_CATCH_DECLARE_SIG_TEST1, INTERNAL_CATCH_DECLARE_SIG_TEST0)(TestName, __VA_ARGS__))
+#define INTERNAL_CATCH_REMOVE_PARENS_GEN(...) INTERNAL_CATCH_EXPAND_VARGS(INTERNAL_CATCH_VA_NARGS_IMPL(__VA_ARGS__, INTERNAL_CATCH_REMOVE_PARENS_11_ARG,INTERNAL_CATCH_REMOVE_PARENS_10_ARG,INTERNAL_CATCH_REMOVE_PARENS_9_ARG,INTERNAL_CATCH_REMOVE_PARENS_8_ARG,INTERNAL_CATCH_REMOVE_PARENS_7_ARG,INTERNAL_CATCH_REMOVE_PARENS_6_ARG,INTERNAL_CATCH_REMOVE_PARENS_5_ARG,INTERNAL_CATCH_REMOVE_PARENS_4_ARG,INTERNAL_CATCH_REMOVE_PARENS_3_ARG,INTERNAL_CATCH_REMOVE_PARENS_2_ARG,INTERNAL_CATCH_REMOVE_PARENS_1_ARG)(__VA_ARGS__))
+#endif
#endif // TWOBLUECUBES_CATCH_PREPROCESSOR_HPP_INCLUDED
diff --git a/include/internal/catch_random_number_generator.cpp b/include/internal/catch_random_number_generator.cpp
index ec8a5eb9..1ef08d4c 100644
--- a/include/internal/catch_random_number_generator.cpp
+++ b/include/internal/catch_random_number_generator.cpp
@@ -7,23 +7,67 @@
#include "catch_random_number_generator.h"
#include "catch_context.h"
+#include "catch_run_context.h"
#include "catch_interfaces_config.h"
namespace Catch {
- std::mt19937& rng() {
- static std::mt19937 s_rng;
- return s_rng;
+namespace {
+
+#if defined(_MSC_VER)
+#pragma warning(push)
+#pragma warning(disable:4146) // we negate uint32 during the rotate
+#endif
+ // Safe rotr implementation thanks to John Regehr
+ uint32_t rotate_right(uint32_t val, uint32_t count) {
+ const uint32_t mask = 31;
+ count &= mask;
+ return (val >> count) | (val << (-count & mask));
+ }
+
+#if defined(_MSC_VER)
+#pragma warning(pop)
+#endif
+
+}
+
+
+ SimplePcg32::SimplePcg32(result_type seed_) {
+ seed(seed_);
+ }
+
+
+ void SimplePcg32::seed(result_type seed_) {
+ m_state = 0;
+ (*this)();
+ m_state += seed_;
+ (*this)();
}
- void seedRng( IConfig const& config ) {
- if( config.rngSeed() != 0 ) {
- std::srand( config.rngSeed() );
- rng().seed( config.rngSeed() );
+ void SimplePcg32::discard(uint64_t skip) {
+ // We could implement this to run in O(log n) steps, but this
+ // should suffice for our use case.
+ for (uint64_t s = 0; s < skip; ++s) {
+ static_cast<void>((*this)());
}
}
- unsigned int rngSeed() {
- return getCurrentContext().getConfig()->rngSeed();
+ SimplePcg32::result_type SimplePcg32::operator()() {
+ // prepare the output value
+ const uint32_t xorshifted = static_cast<uint32_t>(((m_state >> 18u) ^ m_state) >> 27u);
+ const auto output = rotate_right(xorshifted, m_state >> 59u);
+
+ // advance state
+ m_state = m_state * 6364136223846793005ULL + s_inc;
+
+ return output;
+ }
+
+ bool operator==(SimplePcg32 const& lhs, SimplePcg32 const& rhs) {
+ return lhs.m_state == rhs.m_state;
+ }
+
+ bool operator!=(SimplePcg32 const& lhs, SimplePcg32 const& rhs) {
+ return lhs.m_state != rhs.m_state;
}
}
diff --git a/include/internal/catch_random_number_generator.h b/include/internal/catch_random_number_generator.h
index 817b7841..79d62794 100644
--- a/include/internal/catch_random_number_generator.h
+++ b/include/internal/catch_random_number_generator.h
@@ -7,17 +7,52 @@
#ifndef TWOBLUECUBES_CATCH_RANDOM_NUMBER_GENERATOR_H_INCLUDED
#define TWOBLUECUBES_CATCH_RANDOM_NUMBER_GENERATOR_H_INCLUDED
-#include <algorithm>
-#include <random>
+#include <cstdint>
namespace Catch {
- struct IConfig;
+ // This is a simple implementation of C++11 Uniform Random Number
+ // Generator. It does not provide all operators, because Catch2
+ // does not use it, but it should behave as expected inside stdlib's
+ // distributions.
+ // The implementation is based on the PCG family (http://pcg-random.org)
+ class SimplePcg32 {
+ using state_type = std::uint64_t;
+ public:
+ using result_type = std::uint32_t;
+ static constexpr result_type (min)() {
+ return 0;
+ }
+ static constexpr result_type (max)() {
+ return static_cast<result_type>(-1);
+ }
- std::mt19937& rng();
- void seedRng( IConfig const& config );
- unsigned int rngSeed();
+ // Provide some default initial state for the default constructor
+ SimplePcg32():SimplePcg32(0xed743cc4U) {}
-}
+ explicit SimplePcg32(result_type seed_);
+
+ void seed(result_type seed_);
+ void discard(uint64_t skip);
+
+ result_type operator()();
+
+ private:
+ friend bool operator==(SimplePcg32 const& lhs, SimplePcg32 const& rhs);
+ friend bool operator!=(SimplePcg32 const& lhs, SimplePcg32 const& rhs);
+
+ // In theory we also need operator<< and operator>>
+ // In practice we do not use them, so we will skip them for now
+
+
+ std::uint64_t m_state;
+ // This part of the state determines which "stream" of the numbers
+ // is chosen -- we take it as a constant for Catch2, so we only
+ // need to deal with seeding the main state.
+ // Picked by reading 8 bytes from `/dev/random` :-)
+ static const std::uint64_t s_inc = (0x13ed0cc53f939476ULL << 1ULL) | 1ULL;
+ };
+
+} // end namespace Catch
#endif // TWOBLUECUBES_CATCH_RANDOM_NUMBER_GENERATOR_H_INCLUDED
diff --git a/include/internal/catch_registry_hub.cpp b/include/internal/catch_registry_hub.cpp
index a5062398..8a3c7a97 100644
--- a/include/internal/catch_registry_hub.cpp
+++ b/include/internal/catch_registry_hub.cpp
@@ -15,6 +15,7 @@
#include "catch_tag_alias_registry.h"
#include "catch_startup_exception_registry.h"
#include "catch_singletons.hpp"
+#include "catch_enum_values_registry.h"
namespace Catch {
@@ -60,6 +61,9 @@ namespace Catch {
void registerStartupException() noexcept override {
m_exceptionRegistry.add(std::current_exception());
}
+ IMutableEnumValuesRegistry& getMutableEnumValuesRegistry() override {
+ return m_enumValuesRegistry;
+ }
private:
TestRegistry m_testCaseRegistry;
@@ -67,6 +71,7 @@ namespace Catch {
ExceptionTranslatorRegistry m_exceptionTranslatorRegistry;
TagAliasRegistry m_tagAliasRegistry;
StartupExceptionRegistry m_exceptionRegistry;
+ Detail::EnumValuesRegistry m_enumValuesRegistry;
};
}
diff --git a/include/internal/catch_reporter_registrars.hpp b/include/internal/catch_reporter_registrars.hpp
index 660f554a..a1950536 100644
--- a/include/internal/catch_reporter_registrars.hpp
+++ b/include/internal/catch_reporter_registrars.hpp
@@ -58,14 +58,16 @@ namespace Catch {
#if !defined(CATCH_CONFIG_DISABLE)
#define CATCH_REGISTER_REPORTER( name, reporterType ) \
+ CATCH_INTERNAL_START_WARNINGS_SUPPRESSION \
CATCH_INTERNAL_SUPPRESS_GLOBALS_WARNINGS \
namespace{ Catch::ReporterRegistrar<reporterType> catch_internal_RegistrarFor##reporterType( name ); } \
- CATCH_INTERNAL_UNSUPPRESS_GLOBALS_WARNINGS
+ CATCH_INTERNAL_STOP_WARNINGS_SUPPRESSION
#define CATCH_REGISTER_LISTENER( listenerType ) \
- CATCH_INTERNAL_SUPPRESS_GLOBALS_WARNINGS \
- namespace{ Catch::ListenerRegistrar<listenerType> catch_internal_RegistrarFor##listenerType; } \
- CATCH_INTERNAL_SUPPRESS_GLOBALS_WARNINGS
+ CATCH_INTERNAL_START_WARNINGS_SUPPRESSION \
+ CATCH_INTERNAL_SUPPRESS_GLOBALS_WARNINGS \
+ namespace{ Catch::ListenerRegistrar<listenerType> catch_internal_RegistrarFor##listenerType; } \
+ CATCH_INTERNAL_STOP_WARNINGS_SUPPRESSION
#else // CATCH_CONFIG_DISABLE
#define CATCH_REGISTER_REPORTER(name, reporterType)
diff --git a/include/internal/catch_run_context.cpp b/include/internal/catch_run_context.cpp
index bc3a5151..2eb84fb9 100644
--- a/include/internal/catch_run_context.cpp
+++ b/include/internal/catch_run_context.cpp
@@ -230,12 +230,21 @@ namespace Catch {
m_unfinishedSections.push_back(endInfo);
}
+
+#if defined(CATCH_CONFIG_ENABLE_BENCHMARKING)
+ void RunContext::benchmarkPreparing(std::string const& name) {
+ m_reporter->benchmarkPreparing(name);
+ }
void RunContext::benchmarkStarting( BenchmarkInfo const& info ) {
m_reporter->benchmarkStarting( info );
}
- void RunContext::benchmarkEnded( BenchmarkStats const& stats ) {
+ void RunContext::benchmarkEnded( BenchmarkStats<> const& stats ) {
m_reporter->benchmarkEnded( stats );
}
+ void RunContext::benchmarkFailed(std::string const & error) {
+ m_reporter->benchmarkFailed(error);
+ }
+#endif // CATCH_CONFIG_ENABLE_BENCHMARKING
void RunContext::pushScopedMessage(MessageInfo const & message) {
m_messages.push_back(message);
@@ -270,7 +279,7 @@ namespace Catch {
// Don't rebuild the result -- the stringification itself can cause more fatal errors
// Instead, fake a result data.
AssertionResultData tempResult( ResultWas::FatalErrorCondition, { false } );
- tempResult.message = message;
+ tempResult.message = static_cast<std::string>(message);
AssertionResult result(m_lastAssertionInfo, tempResult);
assertionEnded(result);
@@ -433,7 +442,7 @@ namespace Catch {
m_lastAssertionInfo = info;
AssertionResultData data( resultType, LazyExpression( false ) );
- data.message = message;
+ data.message = static_cast<std::string>(message);
AssertionResult assertionResult{ m_lastAssertionInfo, data };
assertionEnded( assertionResult );
if( !assertionResult.isOk() )
@@ -497,4 +506,16 @@ namespace Catch {
else
CATCH_INTERNAL_ERROR("No result capture instance");
}
+
+ void seedRng(IConfig const& config) {
+ if (config.rngSeed() != 0) {
+ std::srand(config.rngSeed());
+ rng().seed(config.rngSeed());
+ }
+ }
+
+ unsigned int rngSeed() {
+ return getCurrentContext().getConfig()->rngSeed();
+ }
+
}
diff --git a/include/internal/catch_run_context.h b/include/internal/catch_run_context.h
index c530a7b2..2a8e72dc 100644
--- a/include/internal/catch_run_context.h
+++ b/include/internal/catch_run_context.h
@@ -82,8 +82,12 @@ namespace Catch {
auto acquireGeneratorTracker( SourceLineInfo const& lineInfo ) -> IGeneratorTracker& override;
+#if defined(CATCH_CONFIG_ENABLE_BENCHMARKING)
+ void benchmarkPreparing( std::string const& name ) override;
void benchmarkStarting( BenchmarkInfo const& info ) override;
- void benchmarkEnded( BenchmarkStats const& stats ) override;
+ void benchmarkEnded( BenchmarkStats<> const& stats ) override;
+ void benchmarkFailed( std::string const& error ) override;
+#endif // CATCH_CONFIG_ENABLE_BENCHMARKING
void pushScopedMessage( MessageInfo const& message ) override;
void popScopedMessage( MessageInfo const& message ) override;
@@ -147,6 +151,8 @@ namespace Catch {
bool m_includeSuccessfulResults;
};
+ void seedRng(IConfig const& config);
+ unsigned int rngSeed();
} // end namespace Catch
#endif // TWOBLUECUBES_CATCH_RUNNER_IMPL_HPP_INCLUDED
diff --git a/include/internal/catch_section.h b/include/internal/catch_section.h
index 00c254b6..cc2b323d 100644
--- a/include/internal/catch_section.h
+++ b/include/internal/catch_section.h
@@ -37,13 +37,15 @@ namespace Catch {
} // end namespace Catch
#define INTERNAL_CATCH_SECTION( ... ) \
+ CATCH_INTERNAL_START_WARNINGS_SUPPRESSION \
CATCH_INTERNAL_SUPPRESS_UNUSED_WARNINGS \
if( Catch::Section const& INTERNAL_CATCH_UNIQUE_NAME( catch_internal_Section ) = Catch::SectionInfo( CATCH_INTERNAL_LINEINFO, __VA_ARGS__ ) ) \
- CATCH_INTERNAL_UNSUPPRESS_UNUSED_WARNINGS
+ CATCH_INTERNAL_STOP_WARNINGS_SUPPRESSION
#define INTERNAL_CATCH_DYNAMIC_SECTION( ... ) \
+ CATCH_INTERNAL_START_WARNINGS_SUPPRESSION \
CATCH_INTERNAL_SUPPRESS_UNUSED_WARNINGS \
if( Catch::Section const& INTERNAL_CATCH_UNIQUE_NAME( catch_internal_Section ) = Catch::SectionInfo( CATCH_INTERNAL_LINEINFO, (Catch::ReusableStringStream() << __VA_ARGS__).str() ) ) \
- CATCH_INTERNAL_UNSUPPRESS_UNUSED_WARNINGS
+ CATCH_INTERNAL_STOP_WARNINGS_SUPPRESSION
#endif // TWOBLUECUBES_CATCH_SECTION_H_INCLUDED
diff --git a/include/internal/catch_session.cpp b/include/internal/catch_session.cpp
index 38b74ef7..24ebe4de 100644
--- a/include/internal/catch_session.cpp
+++ b/include/internal/catch_session.cpp
@@ -25,6 +25,8 @@
#include <cstdlib>
#include <iomanip>
+#include <set>
+#include <iterator>
namespace Catch {
@@ -58,46 +60,61 @@ namespace Catch {
return ret;
}
-
- Catch::Totals runTests(std::shared_ptr<Config> const& config) {
- auto reporter = makeReporter(config);
-
- 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) {
- bool matching = (!testSpec.hasFilters() && !testCase.isHidden()) ||
- (testSpec.hasFilters() && matchTest(testCase, testSpec, *config));
-
- if (!context.aborting() && matching)
- totals += context.runTest(testCase);
- else
- context.reporter().skipTest(testCase);
+ class TestGroup {
+ public:
+ explicit TestGroup(std::shared_ptr<Config> const& config)
+ : m_config{config}
+ , m_context{config, makeReporter(config)}
+ {
+ auto const& allTestCases = getAllTestCasesSorted(*m_config);
+ m_matches = m_config->testSpec().matchesByFilter(allTestCases, *m_config);
+ auto const& invalidArgs = m_config->testSpec().getInvalidArgs();
+
+ if (m_matches.empty() && invalidArgs.empty()) {
+ for (auto const& test : allTestCases)
+ if (!test.isHidden())
+ m_tests.emplace(&test);
+ } else {
+ for (auto const& match : m_matches)
+ m_tests.insert(match.tests.begin(), match.tests.end());
+ }
}
- if (config->warnAboutNoTests() && totals.testCases.total() == 0) {
- ReusableStringStream testConfig;
+ Totals execute() {
+ auto const& invalidArgs = m_config->testSpec().getInvalidArgs();
+ Totals totals;
+ m_context.testGroupStarting(m_config->name(), 1, 1);
+ for (auto const& testCase : m_tests) {
+ if (!m_context.aborting())
+ totals += m_context.runTest(*testCase);
+ else
+ m_context.reporter().skipTest(*testCase);
+ }
+
+ for (auto const& match : m_matches) {
+ if (match.tests.empty()) {
+ m_context.reporter().noMatchingTestCases(match.name);
+ totals.error = -1;
+ }
+ }
- bool first = true;
- for (const auto& input : config->getTestsOrTags()) {
- if (!first) { testConfig << ' '; }
- first = false;
- testConfig << input;
+ if (!invalidArgs.empty()) {
+ for (auto const& invalidArg: invalidArgs)
+ m_context.reporter().reportInvalidArguments(invalidArg);
}
- context.reporter().noMatchingTestCases(testConfig.str());
- totals.error = -1;
+ m_context.testGroupEnded(m_config->name(), totals, 1, 1);
+ return totals;
}
- context.testGroupEnded(config->name(), totals, 1, 1);
- return totals;
- }
+ private:
+ using Tests = std::set<TestCase const*>;
+
+ std::shared_ptr<Config> m_config;
+ RunContext m_context;
+ Tests m_tests;
+ TestSpec::Matches m_matches;
+ };
void applyFilenamesAsTags(Catch::IConfig const& config) {
auto& tests = const_cast<std::vector<TestCase>&>(getAllTestCasesSorted(config));
@@ -134,6 +151,9 @@ namespace Catch {
#if !defined(CATCH_CONFIG_DISABLE_EXCEPTIONS)
const auto& exceptions = getRegistryHub().getStartupExceptionRegistry().getExceptions();
if ( !exceptions.empty() ) {
+ config();
+ getCurrentMutableContext().setConfig(m_config);
+
m_startupExceptions = true;
Colour colourGuard( Colour::Red );
Catch::cerr() << "Errors occurred during startup!" << '\n';
@@ -163,7 +183,7 @@ namespace Catch {
}
void Session::libIdentify() {
Catch::cout()
- << std::left << std::setw(16) << "description: " << "A Catch test executable\n"
+ << std::left << std::setw(16) << "description: " << "A Catch2 test executable\n"
<< std::left << std::setw(16) << "category: " << "testframework\n"
<< std::left << std::setw(16) << "framework: " << "Catch Test\n"
<< std::left << std::setw(16) << "version: " << libraryVersion() << std::endl;
@@ -194,17 +214,17 @@ namespace Catch {
return 0;
}
-#if defined(CATCH_CONFIG_WCHAR) && defined(WIN32) && defined(UNICODE)
+#if defined(CATCH_CONFIG_WCHAR) && defined(_WIN32) && defined(UNICODE)
int Session::applyCommandLine( int argc, wchar_t const * const * argv ) {
char **utf8Argv = new char *[ argc ];
for ( int i = 0; i < argc; ++i ) {
- int bufSize = WideCharToMultiByte( CP_UTF8, 0, argv[i], -1, NULL, 0, NULL, NULL );
+ int bufSize = WideCharToMultiByte( CP_UTF8, 0, argv[i], -1, nullptr, 0, nullptr, nullptr );
utf8Argv[ i ] = new char[ bufSize ];
- WideCharToMultiByte( CP_UTF8, 0, argv[i], -1, utf8Argv[i], bufSize, NULL, NULL );
+ WideCharToMultiByte( CP_UTF8, 0, argv[i], -1, utf8Argv[i], bufSize, nullptr, nullptr );
}
int returnCode = applyCommandLine( argc, utf8Argv );
@@ -271,7 +291,12 @@ namespace Catch {
if( Option<std::size_t> listed = list( m_config ) )
return static_cast<int>( *listed );
- auto totals = runTests( m_config );
+ TestGroup tests { m_config };
+ auto const totals = tests.execute();
+
+ if( m_config->warnAboutNoTests() && totals.error == -1 )
+ return 2;
+
// Note that on unices only the lower 8 bits are usually used, clamping
// the return value to 255 prevents false negative when some multiple
// of 256 tests has failed
diff --git a/include/internal/catch_session.h b/include/internal/catch_session.h
index af820da4..4e83d520 100644
--- a/include/internal/catch_session.h
+++ b/include/internal/catch_session.h
@@ -26,7 +26,7 @@ namespace Catch {
void libIdentify();
int applyCommandLine( int argc, char const * const * argv );
- #if defined(CATCH_CONFIG_WCHAR) && defined(WIN32) && defined(UNICODE)
+ #if defined(CATCH_CONFIG_WCHAR) && defined(_WIN32) && defined(UNICODE)
int applyCommandLine( int argc, wchar_t const * const * argv );
#endif
diff --git a/include/internal/catch_stream.cpp b/include/internal/catch_stream.cpp
index ba2d2be2..3e907c63 100644
--- a/include/internal/catch_stream.cpp
+++ b/include/internal/catch_stream.cpp
@@ -25,7 +25,7 @@ namespace Catch {
Catch::IStream::~IStream() = default;
- namespace detail { namespace {
+ namespace Detail { namespace {
template<typename WriterF, std::size_t bufferSize=256>
class StreamBufImpl : public std::streambuf {
char data[bufferSize];
@@ -124,15 +124,15 @@ namespace Catch {
auto makeStream( StringRef const &filename ) -> IStream const* {
if( filename.empty() )
- return new detail::CoutStream();
+ return new Detail::CoutStream();
else if( filename[0] == '%' ) {
if( filename == "%debug" )
- return new detail::DebugOutStream();
+ return new Detail::DebugOutStream();
else
CATCH_ERROR( "Unrecognised stream: '" << filename << "'" );
}
else
- return new detail::FileStream( filename );
+ return new Detail::FileStream( filename );
}
diff --git a/include/internal/catch_stream.h b/include/internal/catch_stream.h
index 2b41adbd..999849c9 100644
--- a/include/internal/catch_stream.h
+++ b/include/internal/catch_stream.h
@@ -9,6 +9,8 @@
#ifndef TWOBLUECUBES_CATCH_STREAM_H_INCLUDED
#define TWOBLUECUBES_CATCH_STREAM_H_INCLUDED
+#include "catch_common.h"
+
#include <iosfwd>
#include <cstddef>
#include <ostream>
@@ -28,7 +30,7 @@ namespace Catch {
auto makeStream( StringRef const &filename ) -> IStream const*;
- class ReusableStringStream {
+ class ReusableStringStream : NonCopyable {
std::size_t m_index;
std::ostream* m_oss;
public:
diff --git a/include/internal/catch_string_manip.cpp b/include/internal/catch_string_manip.cpp
index 904d1013..65be34d0 100644
--- a/include/internal/catch_string_manip.cpp
+++ b/include/internal/catch_string_manip.cpp
@@ -6,11 +6,13 @@
*/
#include "catch_string_manip.h"
+#include "catch_stringref.h"
#include <algorithm>
#include <ostream>
#include <cstring>
#include <cctype>
+#include <vector>
namespace Catch {
@@ -51,6 +53,18 @@ namespace Catch {
return start != std::string::npos ? str.substr( start, 1+end-start ) : std::string();
}
+ StringRef trim(StringRef ref) {
+ const auto is_ws = [](char c) {
+ return c == ' ' || c == '\t' || c == '\n' || c == '\r';
+ };
+ size_t real_begin = 0;
+ while (real_begin < ref.size() && is_ws(ref[real_begin])) { ++real_begin; }
+ size_t real_end = ref.size();
+ while (real_end > real_begin && is_ws(ref[real_end - 1])) { --real_end; }
+
+ return ref.substr(real_begin, real_end - real_begin);
+ }
+
bool replaceInPlace( std::string& str, std::string const& replaceThis, std::string const& withThis ) {
bool replaced = false;
std::size_t i = str.find( replaceThis );
@@ -65,6 +79,21 @@ namespace Catch {
return replaced;
}
+ std::vector<StringRef> splitStringRef( StringRef str, char delimiter ) {
+ std::vector<StringRef> subStrings;
+ std::size_t start = 0;
+ for(std::size_t pos = 0; pos < str.size(); ++pos ) {
+ if( str[pos] == delimiter ) {
+ if( pos - start > 1 )
+ subStrings.push_back( str.substr( start, pos-start ) );
+ start = pos+1;
+ }
+ }
+ if( start < str.size() )
+ subStrings.push_back( str.substr( start, str.size()-start ) );
+ return subStrings;
+ }
+
pluralise::pluralise( std::size_t count, std::string const& label )
: m_count( count ),
m_label( label )
diff --git a/include/internal/catch_string_manip.h b/include/internal/catch_string_manip.h
index 6292cd57..cdb7be5f 100644
--- a/include/internal/catch_string_manip.h
+++ b/include/internal/catch_string_manip.h
@@ -7,8 +7,11 @@
#ifndef TWOBLUECUBES_CATCH_STRING_MANIP_H_INCLUDED
#define TWOBLUECUBES_CATCH_STRING_MANIP_H_INCLUDED
+#include "catch_stringref.h"
+
#include <string>
#include <iosfwd>
+#include <vector>
namespace Catch {
@@ -19,7 +22,13 @@ namespace Catch {
bool contains( std::string const& s, std::string const& infix );
void toLowerInPlace( std::string& s );
std::string toLower( std::string const& s );
+ //! Returns a new string without whitespace at the start/end
std::string trim( std::string const& str );
+ //! Returns a substring of the original ref without whitespace. Beware lifetimes!
+ StringRef trim(StringRef ref);
+
+ // !!! Be aware, returns refs into original string - make sure original string outlives them
+ std::vector<StringRef> splitStringRef( StringRef str, char delimiter );
bool replaceInPlace( std::string& str, std::string const& replaceThis, std::string const& withThis );
struct pluralise {
diff --git a/include/internal/catch_stringref.cpp b/include/internal/catch_stringref.cpp
index 9e9095e4..215feef3 100644
--- a/include/internal/catch_stringref.cpp
+++ b/include/internal/catch_stringref.cpp
@@ -5,123 +5,46 @@
* file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
*/
-
-#if defined(__clang__)
-# pragma clang diagnostic push
-# pragma clang diagnostic ignored "-Wexit-time-destructors"
-#endif
-
+#include "catch_enforce.h"
#include "catch_stringref.h"
+#include <algorithm>
#include <ostream>
#include <cstring>
#include <cstdint>
-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
: StringRef( rawChars, static_cast<StringRef::size_type>(std::strlen(rawChars) ) )
{}
- StringRef::operator std::string() const {
- return std::string( m_start, m_size );
- }
-
- void StringRef::swap( StringRef& other ) noexcept {
- std::swap( m_start, other.m_start );
- std::swap( m_size, other.m_size );
- std::swap( m_data, other.m_data );
- }
-
auto StringRef::c_str() const -> char const* {
- if( isSubstring() )
- const_cast<StringRef*>( this )->takeOwnership();
+ CATCH_ENFORCE(isNullTerminated(), "Called StringRef::c_str() on a non-null-terminated instance");
return m_start;
}
- auto StringRef::currentData() const noexcept -> char const* {
+ auto StringRef::data() const noexcept -> char const* {
return m_start;
}
- auto StringRef::isOwned() const noexcept -> bool {
- return m_data != nullptr;
- }
- auto StringRef::isSubstring() const noexcept -> bool {
- return m_start[m_size] != '\0';
- }
-
- void StringRef::takeOwnership() {
- if( !isOwned() ) {
- m_data = new char[m_size+1];
- memcpy( m_data, m_start, m_size );
- m_data[m_size] = '\0';
- m_start = m_data;
- }
- }
auto StringRef::substr( size_type start, size_type size ) const noexcept -> StringRef {
- if( start < m_size )
- return StringRef( m_start+start, size );
- else
+ if (start < m_size) {
+ return StringRef(m_start + start, (std::min)(m_size - start, size));
+ } else {
return StringRef();
- }
- auto StringRef::operator == ( StringRef const& other ) const noexcept -> bool {
- return
- size() == other.size() &&
- (std::strncmp( m_start, other.m_start, size() ) == 0);
- }
- auto StringRef::operator != ( StringRef const& other ) const noexcept -> bool {
- return !operator==( other );
- }
-
- auto StringRef::operator[](size_type index) const noexcept -> char {
- return m_start[index];
- }
-
- 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 & 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--;
- }
}
- return noChars;
- }
-
- auto operator + ( StringRef const& lhs, StringRef const& rhs ) -> std::string {
- std::string str;
- str.reserve( lhs.size() + rhs.size() );
- str += lhs;
- str += rhs;
- return str;
}
- auto operator + ( StringRef const& lhs, const char* rhs ) -> std::string {
- return std::string( lhs ) + std::string( rhs );
- }
- auto operator + ( char const* lhs, StringRef const& rhs ) -> std::string {
- return std::string( lhs ) + std::string( rhs );
+ auto StringRef::operator == ( StringRef const& other ) const noexcept -> bool {
+ return m_size == other.m_size
+ && (std::memcmp( m_start, other.m_start, m_size ) == 0);
}
auto operator << ( std::ostream& os, StringRef const& str ) -> std::ostream& {
- return os.write(str.currentData(), str.size());
+ return os.write(str.data(), str.size());
}
auto operator+=( std::string& lhs, StringRef const& rhs ) -> std::string& {
- lhs.append(rhs.currentData(), rhs.size());
+ lhs.append(rhs.data(), rhs.size());
return lhs;
}
} // namespace Catch
-
-#if defined(__clang__)
-# pragma clang diagnostic pop
-#endif
diff --git a/include/internal/catch_stringref.h b/include/internal/catch_stringref.h
index 64f595b3..dc2e748c 100644
--- a/include/internal/catch_stringref.h
+++ b/include/internal/catch_stringref.h
@@ -10,53 +10,30 @@
#include <cstddef>
#include <string>
#include <iosfwd>
+#include <cassert>
namespace Catch {
/// A non-owning string class (similar to the forthcoming std::string_view)
/// Note that, because a StringRef may be a substring of another string,
- /// it may not be null terminated. c_str() must return a null terminated
- /// string, however, and so the StringRef will internally take ownership
- /// (taking a copy), if necessary. In theory this ownership is not externally
- /// visible - but it does mean (substring) StringRefs should not be shared between
- /// threads.
+ /// it may not be null terminated.
class StringRef {
public:
using size_type = std::size_t;
+ using const_iterator = const char*;
private:
- friend struct StringRefTestAccess;
-
- 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 )
- {}
+ char const* m_start = s_empty;
+ size_type m_size = 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;
- }
+ public: // construction
+ constexpr StringRef() noexcept = default;
StringRef( char const* rawChars ) noexcept;
- StringRef( char const* rawChars, size_type size ) noexcept
+ constexpr StringRef( char const* rawChars, size_type size ) noexcept
: m_start( rawChars ),
m_size( size )
{}
@@ -66,66 +43,61 @@ namespace Catch {
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;
+ explicit operator std::string() const {
+ return std::string(m_start, m_size);
}
- 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 != (StringRef const& other) const noexcept -> bool {
+ return !(*this == other);
+ }
- auto operator[] ( size_type index ) const noexcept -> char;
+ auto operator[] ( size_type index ) const noexcept -> char {
+ assert(index < m_size);
+ return m_start[index];
+ }
public: // named queries
- auto empty() const noexcept -> bool {
+ constexpr auto empty() const noexcept -> bool {
return m_size == 0;
}
- auto size() const noexcept -> size_type {
+ constexpr auto size() const noexcept -> size_type {
return m_size;
}
- auto numberOfCharacters() const noexcept -> size_type;
+ // Returns the current start pointer. If the StringRef is not
+ // null-terminated, throws std::domain_exception
auto c_str() const -> char const*;
public: // substrings and searches
- auto substr( size_type start, size_type size ) const noexcept -> StringRef;
+ // Returns a substring of [start, start + length).
+ // If start + length > size(), then the substring is [start, size()).
+ // If start > size(), then the substring is empty.
+ auto substr( size_type start, size_type length ) const noexcept -> StringRef;
- // Returns the current start pointer.
- // Note that the pointer can change when if the StringRef is a substring
- auto currentData() const noexcept -> char const*;
+ // Returns the current start pointer. May not be null-terminated.
+ auto data() const noexcept -> char const*;
- private: // ownership queries - may not be consistent between calls
- auto isOwned() const noexcept -> bool;
- auto isSubstring() const noexcept -> bool;
- };
+ constexpr auto isNullTerminated() const noexcept -> bool {
+ return m_start[m_size] == '\0';
+ }
- 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;
+ public: // iterators
+ constexpr const_iterator begin() const { return m_start; }
+ constexpr const_iterator end() const { return m_start + m_size; }
+ };
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 {
+ constexpr auto operator "" _sr( char const* rawChars, std::size_t size ) noexcept -> StringRef {
return StringRef( rawChars, size );
}
-
} // namespace Catch
-inline auto operator "" _catch_sr( char const* rawChars, std::size_t size ) noexcept -> Catch::StringRef {
+constexpr auto operator "" _catch_sr( char const* rawChars, std::size_t size ) noexcept -> Catch::StringRef {
return Catch::StringRef( rawChars, size );
}
diff --git a/include/internal/catch_tag_alias_autoregistrar.h b/include/internal/catch_tag_alias_autoregistrar.h
index 32a5734e..ebba8e25 100644
--- a/include/internal/catch_tag_alias_autoregistrar.h
+++ b/include/internal/catch_tag_alias_autoregistrar.h
@@ -18,8 +18,9 @@ namespace Catch {
} // end namespace Catch
#define CATCH_REGISTER_TAG_ALIAS( alias, spec ) \
+ CATCH_INTERNAL_START_WARNINGS_SUPPRESSION \
CATCH_INTERNAL_SUPPRESS_GLOBALS_WARNINGS \
namespace{ Catch::RegistrarForTagAliases INTERNAL_CATCH_UNIQUE_NAME( AutoRegisterTagAlias )( alias, spec, CATCH_INTERNAL_LINEINFO ); } \
- CATCH_INTERNAL_UNSUPPRESS_GLOBALS_WARNINGS
+ CATCH_INTERNAL_STOP_WARNINGS_SUPPRESSION
#endif // TWOBLUECUBES_CATCH_TAG_ALIAS_AUTOREGISTRAR_H_INCLUDED
diff --git a/include/internal/catch_test_case_info.cpp b/include/internal/catch_test_case_info.cpp
index 4baa9d4b..cee972fa 100644
--- a/include/internal/catch_test_case_info.cpp
+++ b/include/internal/catch_test_case_info.cpp
@@ -59,8 +59,7 @@ namespace Catch {
std::vector<std::string> tags;
std::string desc, tag;
bool inTag = false;
- std::string _descOrTags = nameAndTags.tags;
- for (char c : _descOrTags) {
+ for (char c : nameAndTags.tags) {
if( !inTag ) {
if( c == '[' )
inTag = true;
@@ -90,10 +89,11 @@ namespace Catch {
}
}
if( isHidden ) {
- tags.push_back( "." );
+ // Add all "hidden" tags to make them behave identically
+ tags.insert( tags.end(), { ".", "!hide" } );
}
- TestCaseInfo info( nameAndTags.name, _className, desc, tags, _lineInfo );
+ TestCaseInfo info( static_cast<std::string>(nameAndTags.name), _className, desc, tags, _lineInfo );
return TestCase( _testCase, std::move(info) );
}
diff --git a/include/internal/catch_test_case_registry_impl.cpp b/include/internal/catch_test_case_registry_impl.cpp
index a85d0edf..b254ca08 100644
--- a/include/internal/catch_test_case_registry_impl.cpp
+++ b/include/internal/catch_test_case_registry_impl.cpp
@@ -11,6 +11,7 @@
#include "catch_enforce.h"
#include "catch_interfaces_registry_hub.h"
#include "catch_random_number_generator.h"
+#include "catch_run_context.h"
#include "catch_string_manip.h"
#include "catch_test_case_info.h"
@@ -36,8 +37,13 @@ namespace Catch {
}
return sorted;
}
+
+ bool isThrowSafe( TestCase const& testCase, IConfig const& config ) {
+ return !testCase.throws() || config.allowThrows();
+ }
+
bool matchTest( TestCase const& testCase, TestSpec const& testSpec, IConfig const& config ) {
- return testSpec.matches( testCase ) && ( config.allowThrows() || !testCase.throws() );
+ return testSpec.matches( testCase ) && isThrowSafe( testCase, config );
}
void enforceNoDuplicateTestCases( std::vector<TestCase> const& functions ) {
@@ -100,7 +106,7 @@ namespace Catch {
}
std::string extractClassName( StringRef const& classOrQualifiedMethodName ) {
- std::string className = classOrQualifiedMethodName;
+ std::string className(classOrQualifiedMethodName);
if( startsWith( className, '&' ) )
{
std::size_t lastColons = className.rfind( "::" );
diff --git a/include/internal/catch_test_case_registry_impl.h b/include/internal/catch_test_case_registry_impl.h
index 8dc5b0fe..359ac3e3 100644
--- a/include/internal/catch_test_case_registry_impl.h
+++ b/include/internal/catch_test_case_registry_impl.h
@@ -23,6 +23,8 @@ namespace Catch {
struct IConfig;
std::vector<TestCase> sortTests( IConfig const& config, std::vector<TestCase> const& unsortedTestCases );
+
+ bool isThrowSafe( TestCase const& testCase, IConfig const& config );
bool matchTest( TestCase const& testCase, TestSpec const& testSpec, IConfig const& config );
void enforceNoDuplicateTestCases( std::vector<TestCase> const& functions );
diff --git a/include/internal/catch_test_case_tracker.cpp b/include/internal/catch_test_case_tracker.cpp
index 1ef830d1..1fc820b1 100644
--- a/include/internal/catch_test_case_tracker.cpp
+++ b/include/internal/catch_test_case_tracker.cpp
@@ -8,6 +8,7 @@
#include "catch_test_case_tracker.h"
#include "catch_enforce.h"
+#include "catch_string_manip.h"
#include <algorithm>
#include <cassert>
@@ -139,7 +140,7 @@ namespace TestCaseTracking {
m_runState = CompletedSuccessfully;
break;
case ExecutingChildren:
- if( m_children.empty() || m_children.back()->isComplete() )
+ if( std::all_of(m_children.begin(), m_children.end(), [](ITrackerPtr const& t){ return t->isComplete(); }) )
m_runState = CompletedSuccessfully;
break;
@@ -174,7 +175,8 @@ namespace TestCaseTracking {
}
SectionTracker::SectionTracker( NameAndLocation const& nameAndLocation, TrackerContext& ctx, ITracker* parent )
- : TrackerBase( nameAndLocation, ctx, parent )
+ : TrackerBase( nameAndLocation, ctx, parent ),
+ m_trimmed_name(trim(nameAndLocation.name))
{
if( parent ) {
while( !parent->isSectionTracker() )
@@ -188,12 +190,11 @@ namespace TestCaseTracking {
bool SectionTracker::isComplete() const {
bool complete = true;
- if ((m_filters.empty() || m_filters[0] == "") ||
- std::find(m_filters.begin(), m_filters.end(),
- m_nameAndLocation.name) != m_filters.end())
+ if ((m_filters.empty() || m_filters[0] == "")
+ || std::find(m_filters.begin(), m_filters.end(), m_trimmed_name) != m_filters.end()) {
complete = TrackerBase::isComplete();
+ }
return complete;
-
}
bool SectionTracker::isSectionTracker() const { return true; }
@@ -217,20 +218,21 @@ namespace TestCaseTracking {
}
void SectionTracker::tryOpen() {
- if( !isComplete() && (m_filters.empty() || m_filters[0].empty() || m_filters[0] == m_nameAndLocation.name ) )
+ if( !isComplete() )
open();
}
void SectionTracker::addInitialFilters( std::vector<std::string> const& filters ) {
if( !filters.empty() ) {
- m_filters.push_back(""); // Root - should never be consulted
- m_filters.push_back(""); // Test Case - not a section filter
+ m_filters.reserve( m_filters.size() + filters.size() + 2 );
+ m_filters.emplace_back(""); // Root - should never be consulted
+ m_filters.emplace_back(""); // Test Case - not a section filter
m_filters.insert( m_filters.end(), filters.begin(), filters.end() );
}
}
void SectionTracker::addNextFilters( std::vector<std::string> const& filters ) {
if( filters.size() > 1 )
- m_filters.insert( m_filters.end(), ++filters.begin(), filters.end() );
+ m_filters.insert( m_filters.end(), filters.begin()+1, filters.end() );
}
} // namespace TestCaseTracking
diff --git a/include/internal/catch_test_case_tracker.h b/include/internal/catch_test_case_tracker.h
index 97b63b8b..563dbef2 100644
--- a/include/internal/catch_test_case_tracker.h
+++ b/include/internal/catch_test_case_tracker.h
@@ -133,6 +133,7 @@ namespace TestCaseTracking {
class SectionTracker : public TrackerBase {
std::vector<std::string> m_filters;
+ std::string m_trimmed_name;
public:
SectionTracker( NameAndLocation const& nameAndLocation, TrackerContext& ctx, ITracker* parent );
diff --git a/include/internal/catch_test_registry.h b/include/internal/catch_test_registry.h
index 0e7b53de..c9624fc7 100644
--- a/include/internal/catch_test_registry.h
+++ b/include/internal/catch_test_registry.h
@@ -12,7 +12,6 @@
#include "catch_interfaces_testcase.h"
#include "catch_compiler_capabilities.h"
#include "catch_stringref.h"
-#include "catch_type_traits.hpp"
#include "catch_preprocessor.hpp"
#include "catch_meta.hpp"
@@ -60,38 +59,70 @@ struct AutoReg : NonCopyable {
}; \
} \
void TestName::test()
- #define INTERNAL_CATCH_TEMPLATE_TEST_CASE_NO_REGISTRATION( TestName, ... ) \
- template<typename TestType> \
- static void TestName()
- #define INTERNAL_CATCH_TEMPLATE_TEST_CASE_METHOD_NO_REGISTRATION( TestName, ClassName, ... ) \
+ #define INTERNAL_CATCH_TEMPLATE_TEST_CASE_NO_REGISTRATION_2( TestName, TestFunc, Name, Tags, Signature, ... ) \
+ INTERNAL_CATCH_DEFINE_SIG_TEST(TestFunc, INTERNAL_CATCH_REMOVE_PARENS(Signature))
+ #define INTERNAL_CATCH_TEMPLATE_TEST_CASE_METHOD_NO_REGISTRATION_2( TestNameClass, TestName, ClassName, Name, Tags, Signature, ... ) \
namespace{ \
- template<typename TestType> \
- struct TestName : INTERNAL_CATCH_REMOVE_PARENS(ClassName <TestType>) { \
- void test(); \
- }; \
+ namespace INTERNAL_CATCH_MAKE_NAMESPACE(TestName) { \
+ INTERNAL_CATCH_DECLARE_SIG_TEST_METHOD(TestName, ClassName, INTERNAL_CATCH_REMOVE_PARENS(Signature));\
} \
- template<typename TestType> \
- void TestName::test()
+ } \
+ INTERNAL_CATCH_DEFINE_SIG_TEST_METHOD(TestName, INTERNAL_CATCH_REMOVE_PARENS(Signature))
+
+ #ifndef CATCH_CONFIG_TRADITIONAL_MSVC_PREPROCESSOR
+ #define INTERNAL_CATCH_TEMPLATE_TEST_CASE_NO_REGISTRATION(Name, Tags, ...) \
+ INTERNAL_CATCH_TEMPLATE_TEST_CASE_NO_REGISTRATION_2( INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_M_P_L_A_T_E____T_E_S_T____ ), INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_M_P_L_A_T_E____T_E_S_T____F_U_N_C____ ), Name, Tags, typename TestType, __VA_ARGS__ )
+ #else
+ #define INTERNAL_CATCH_TEMPLATE_TEST_CASE_NO_REGISTRATION(Name, Tags, ...) \
+ INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_TEST_CASE_NO_REGISTRATION_2( INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_M_P_L_A_T_E____T_E_S_T____ ), INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_M_P_L_A_T_E____T_E_S_T____F_U_N_C____ ), Name, Tags, typename TestType, __VA_ARGS__ ) )
+ #endif
+
+ #ifndef CATCH_CONFIG_TRADITIONAL_MSVC_PREPROCESSOR
+ #define INTERNAL_CATCH_TEMPLATE_TEST_CASE_SIG_NO_REGISTRATION(Name, Tags, Signature, ...) \
+ INTERNAL_CATCH_TEMPLATE_TEST_CASE_NO_REGISTRATION_2( INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_M_P_L_A_T_E____T_E_S_T____ ), INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_M_P_L_A_T_E____T_E_S_T____F_U_N_C____ ), Name, Tags, Signature, __VA_ARGS__ )
+ #else
+ #define INTERNAL_CATCH_TEMPLATE_TEST_CASE_SIG_NO_REGISTRATION(Name, Tags, Signature, ...) \
+ INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_TEST_CASE_NO_REGISTRATION_2( INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_M_P_L_A_T_E____T_E_S_T____ ), INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_M_P_L_A_T_E____T_E_S_T____F_U_N_C____ ), Name, Tags, Signature, __VA_ARGS__ ) )
+ #endif
+
+ #ifndef CATCH_CONFIG_TRADITIONAL_MSVC_PREPROCESSOR
+ #define INTERNAL_CATCH_TEMPLATE_TEST_CASE_METHOD_NO_REGISTRATION( ClassName, Name, Tags,... ) \
+ INTERNAL_CATCH_TEMPLATE_TEST_CASE_METHOD_NO_REGISTRATION_2( INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_M_P_L_A_T_E____T_E_S_T____C_L_A_S_S____ ), INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_M_P_L_A_T_E____T_E_S_T____ ) , ClassName, Name, Tags, typename T, __VA_ARGS__ )
+ #else
+ #define INTERNAL_CATCH_TEMPLATE_TEST_CASE_METHOD_NO_REGISTRATION( ClassName, Name, Tags,... ) \
+ INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_TEST_CASE_METHOD_NO_REGISTRATION_2( INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_M_P_L_A_T_E____T_E_S_T____C_L_A_S_S____ ), INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_M_P_L_A_T_E____T_E_S_T____ ) , ClassName, Name, Tags, typename T, __VA_ARGS__ ) )
+ #endif
+
+ #ifndef CATCH_CONFIG_TRADITIONAL_MSVC_PREPROCESSOR
+ #define INTERNAL_CATCH_TEMPLATE_TEST_CASE_METHOD_SIG_NO_REGISTRATION( ClassName, Name, Tags, Signature, ... ) \
+ INTERNAL_CATCH_TEMPLATE_TEST_CASE_METHOD_NO_REGISTRATION_2( INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_M_P_L_A_T_E____T_E_S_T____C_L_A_S_S____ ), INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_M_P_L_A_T_E____T_E_S_T____ ) , ClassName, Name, Tags, Signature, __VA_ARGS__ )
+ #else
+ #define INTERNAL_CATCH_TEMPLATE_TEST_CASE_METHOD_SIG_NO_REGISTRATION( ClassName, Name, Tags, Signature, ... ) \
+ INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_TEST_CASE_METHOD_NO_REGISTRATION_2( INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_M_P_L_A_T_E____T_E_S_T____C_L_A_S_S____ ), INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_M_P_L_A_T_E____T_E_S_T____ ) , ClassName, Name, Tags, Signature, __VA_ARGS__ ) )
+ #endif
#endif
///////////////////////////////////////////////////////////////////////////////
#define INTERNAL_CATCH_TESTCASE2( TestName, ... ) \
static void TestName(); \
+ CATCH_INTERNAL_START_WARNINGS_SUPPRESSION \
CATCH_INTERNAL_SUPPRESS_GLOBALS_WARNINGS \
namespace{ Catch::AutoReg INTERNAL_CATCH_UNIQUE_NAME( autoRegistrar )( Catch::makeTestInvoker( &TestName ), CATCH_INTERNAL_LINEINFO, Catch::StringRef(), Catch::NameAndTags{ __VA_ARGS__ } ); } /* NOLINT */ \
- CATCH_INTERNAL_UNSUPPRESS_GLOBALS_WARNINGS \
+ CATCH_INTERNAL_STOP_WARNINGS_SUPPRESSION \
static void TestName()
#define INTERNAL_CATCH_TESTCASE( ... ) \
INTERNAL_CATCH_TESTCASE2( INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_S_T____ ), __VA_ARGS__ )
///////////////////////////////////////////////////////////////////////////////
#define INTERNAL_CATCH_METHOD_AS_TEST_CASE( QualifiedMethod, ... ) \
+ CATCH_INTERNAL_START_WARNINGS_SUPPRESSION \
CATCH_INTERNAL_SUPPRESS_GLOBALS_WARNINGS \
namespace{ Catch::AutoReg INTERNAL_CATCH_UNIQUE_NAME( autoRegistrar )( Catch::makeTestInvoker( &QualifiedMethod ), CATCH_INTERNAL_LINEINFO, "&" #QualifiedMethod, Catch::NameAndTags{ __VA_ARGS__ } ); } /* NOLINT */ \
- CATCH_INTERNAL_UNSUPPRESS_GLOBALS_WARNINGS
+ CATCH_INTERNAL_STOP_WARNINGS_SUPPRESSION
///////////////////////////////////////////////////////////////////////////////
#define INTERNAL_CATCH_TEST_CASE_METHOD2( TestName, ClassName, ... )\
+ CATCH_INTERNAL_START_WARNINGS_SUPPRESSION \
CATCH_INTERNAL_SUPPRESS_GLOBALS_WARNINGS \
namespace{ \
struct TestName : INTERNAL_CATCH_REMOVE_PARENS(ClassName) { \
@@ -99,66 +130,77 @@ struct AutoReg : NonCopyable {
}; \
Catch::AutoReg INTERNAL_CATCH_UNIQUE_NAME( autoRegistrar ) ( Catch::makeTestInvoker( &TestName::test ), CATCH_INTERNAL_LINEINFO, #ClassName, Catch::NameAndTags{ __VA_ARGS__ } ); /* NOLINT */ \
} \
- CATCH_INTERNAL_UNSUPPRESS_GLOBALS_WARNINGS \
+ CATCH_INTERNAL_STOP_WARNINGS_SUPPRESSION \
void TestName::test()
#define INTERNAL_CATCH_TEST_CASE_METHOD( ClassName, ... ) \
INTERNAL_CATCH_TEST_CASE_METHOD2( INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_S_T____ ), ClassName, __VA_ARGS__ )
///////////////////////////////////////////////////////////////////////////////
#define INTERNAL_CATCH_REGISTER_TESTCASE( Function, ... ) \
+ CATCH_INTERNAL_START_WARNINGS_SUPPRESSION \
CATCH_INTERNAL_SUPPRESS_GLOBALS_WARNINGS \
Catch::AutoReg INTERNAL_CATCH_UNIQUE_NAME( autoRegistrar )( Catch::makeTestInvoker( Function ), CATCH_INTERNAL_LINEINFO, Catch::StringRef(), Catch::NameAndTags{ __VA_ARGS__ } ); /* NOLINT */ \
- CATCH_INTERNAL_UNSUPPRESS_GLOBALS_WARNINGS
+ CATCH_INTERNAL_STOP_WARNINGS_SUPPRESSION
///////////////////////////////////////////////////////////////////////////////
- #define INTERNAL_CATCH_TEMPLATE_TEST_CASE_2(TestName, TestFunc, Name, Tags, ... )\
+ #define INTERNAL_CATCH_TEMPLATE_TEST_CASE_2(TestName, TestFunc, Name, Tags, Signature, ... )\
+ CATCH_INTERNAL_START_WARNINGS_SUPPRESSION \
CATCH_INTERNAL_SUPPRESS_GLOBALS_WARNINGS \
- template<typename TestType> \
- static void TestFunc();\
+ CATCH_INTERNAL_SUPPRESS_ZERO_VARIADIC_WARNINGS \
+ CATCH_INTERNAL_SUPPRESS_UNUSED_TEMPLATE_WARNINGS \
+ INTERNAL_CATCH_DECLARE_SIG_TEST(TestFunc, INTERNAL_CATCH_REMOVE_PARENS(Signature));\
namespace {\
+ namespace INTERNAL_CATCH_MAKE_NAMESPACE(TestName){\
+ INTERNAL_CATCH_TYPE_GEN\
+ INTERNAL_CATCH_NTTP_GEN(INTERNAL_CATCH_REMOVE_PARENS(Signature))\
+ INTERNAL_CATCH_NTTP_REG_GEN(TestFunc,INTERNAL_CATCH_REMOVE_PARENS(Signature))\
template<typename...Types> \
struct TestName{\
- template<typename...Ts> \
- TestName(Ts...names){\
- CATCH_INTERNAL_CHECK_UNIQUE_TYPES(CATCH_REC_LIST(INTERNAL_CATCH_REMOVE_PARENS, __VA_ARGS__)) \
+ TestName(){\
+ int index = 0; \
+ constexpr char const* tmpl_types[] = {CATCH_REC_LIST(INTERNAL_CATCH_STRINGIZE_WITHOUT_PARENS, __VA_ARGS__)};\
using expander = int[];\
- (void)expander{(Catch::AutoReg( Catch::makeTestInvoker( &TestFunc<Types> ), CATCH_INTERNAL_LINEINFO, Catch::StringRef(), Catch::NameAndTags{ names, Tags } ), 0)... };/* NOLINT */ \
+ (void)expander{(reg_test(Types{}, Catch::NameAndTags{ Name " - " + std::string(tmpl_types[index]), Tags } ), index++, 0)... };/* NOLINT */ \
}\
};\
- INTERNAL_CATCH_TEMPLATE_REGISTRY_INITIATE(TestName, Name, __VA_ARGS__) \
+ static int INTERNAL_CATCH_UNIQUE_NAME( globalRegistrar ) = [](){\
+ TestName<INTERNAL_CATCH_MAKE_TYPE_LISTS_FROM_TYPES(__VA_ARGS__)>();\
+ return 0;\
+ }();\
}\
- CATCH_INTERNAL_UNSUPPRESS_GLOBALS_WARNINGS \
- template<typename TestType> \
- static void TestFunc()
-
-#if defined(CATCH_CPP17_OR_GREATER)
-#define CATCH_INTERNAL_CHECK_UNIQUE_TYPES(...) static_assert(Catch::is_unique<__VA_ARGS__>,"Duplicate type detected in declaration of template test case");
-#else
-#define CATCH_INTERNAL_CHECK_UNIQUE_TYPES(...) static_assert(Catch::is_unique<__VA_ARGS__>::value,"Duplicate type detected in declaration of template test case");
-#endif
+ }\
+ CATCH_INTERNAL_STOP_WARNINGS_SUPPRESSION \
+ INTERNAL_CATCH_DEFINE_SIG_TEST(TestFunc,INTERNAL_CATCH_REMOVE_PARENS(Signature))
#ifndef CATCH_CONFIG_TRADITIONAL_MSVC_PREPROCESSOR
#define INTERNAL_CATCH_TEMPLATE_TEST_CASE(Name, Tags, ...) \
- INTERNAL_CATCH_TEMPLATE_TEST_CASE_2( INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_M_P_L_A_T_E____T_E_S_T____ ), INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_M_P_L_A_T_E____T_E_S_T____F_U_N_C____ ), Name, Tags, __VA_ARGS__ )
+ INTERNAL_CATCH_TEMPLATE_TEST_CASE_2( INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_M_P_L_A_T_E____T_E_S_T____ ), INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_M_P_L_A_T_E____T_E_S_T____F_U_N_C____ ), Name, Tags, typename TestType, __VA_ARGS__ )
#else
#define INTERNAL_CATCH_TEMPLATE_TEST_CASE(Name, Tags, ...) \
- INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_TEST_CASE_2( INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_M_P_L_A_T_E____T_E_S_T____ ), INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_M_P_L_A_T_E____T_E_S_T____F_U_N_C____ ), Name, Tags, __VA_ARGS__ ) )
+ INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_TEST_CASE_2( INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_M_P_L_A_T_E____T_E_S_T____ ), INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_M_P_L_A_T_E____T_E_S_T____F_U_N_C____ ), Name, Tags, typename TestType, __VA_ARGS__ ) )
#endif
- #define INTERNAL_CATCH_TEMPLATE_REGISTRY_INITIATE(TestName, Name, ...)\
- static int INTERNAL_CATCH_UNIQUE_NAME( globalRegistrar ) = [](){\
- TestName<CATCH_REC_LIST(INTERNAL_CATCH_REMOVE_PARENS, __VA_ARGS__)>(CATCH_REC_LIST_UD(INTERNAL_CATCH_TEMPLATE_UNIQUE_NAME,Name, __VA_ARGS__));\
- return 0;\
- }();
+#ifndef CATCH_CONFIG_TRADITIONAL_MSVC_PREPROCESSOR
+ #define INTERNAL_CATCH_TEMPLATE_TEST_CASE_SIG(Name, Tags, Signature, ...) \
+ INTERNAL_CATCH_TEMPLATE_TEST_CASE_2( INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_M_P_L_A_T_E____T_E_S_T____ ), INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_M_P_L_A_T_E____T_E_S_T____F_U_N_C____ ), Name, Tags, Signature, __VA_ARGS__ )
+#else
+ #define INTERNAL_CATCH_TEMPLATE_TEST_CASE_SIG(Name, Tags, Signature, ...) \
+ INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_TEST_CASE_2( INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_M_P_L_A_T_E____T_E_S_T____ ), INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_M_P_L_A_T_E____T_E_S_T____F_U_N_C____ ), Name, Tags, Signature, __VA_ARGS__ ) )
+#endif
- #define INTERNAL_CATCH_TEMPLATE_PRODUCT_TEST_CASE2(TestName, TestFuncName, Name, Tags, TmplTypes, TypesList) \
+ #define INTERNAL_CATCH_TEMPLATE_PRODUCT_TEST_CASE2(TestName, TestFuncName, Name, Tags, Signature, TmplTypes, TypesList) \
+ CATCH_INTERNAL_START_WARNINGS_SUPPRESSION \
CATCH_INTERNAL_SUPPRESS_GLOBALS_WARNINGS \
+ CATCH_INTERNAL_SUPPRESS_ZERO_VARIADIC_WARNINGS \
+ CATCH_INTERNAL_SUPPRESS_UNUSED_TEMPLATE_WARNINGS \
template<typename TestType> static void TestFuncName(); \
- namespace { \
+ namespace {\
+ namespace INTERNAL_CATCH_MAKE_NAMESPACE(TestName) { \
+ INTERNAL_CATCH_TYPE_GEN \
+ INTERNAL_CATCH_NTTP_GEN(INTERNAL_CATCH_REMOVE_PARENS(Signature)) \
template<typename... Types> \
struct TestName { \
- TestName() { \
- CATCH_INTERNAL_CHECK_UNIQUE_TYPES(Types...) \
+ void reg_tests() { \
int index = 0; \
using expander = int[]; \
constexpr char const* tmpl_types[] = {CATCH_REC_LIST(INTERNAL_CATCH_STRINGIZE_WITHOUT_PARENS, INTERNAL_CATCH_REMOVE_PARENS(TmplTypes))};\
@@ -168,65 +210,125 @@ struct AutoReg : NonCopyable {
} \
}; \
static int INTERNAL_CATCH_UNIQUE_NAME( globalRegistrar ) = [](){ \
- using TestInit = Catch::combine<INTERNAL_CATCH_REMOVE_PARENS(TmplTypes)> \
- ::with_types<INTERNAL_CATCH_MAKE_TYPE_LISTS_FROM_TYPES(TypesList)>::into<TestName>::type; \
- TestInit(); \
+ using TestInit = typename create<TestName, decltype(get_wrapper<INTERNAL_CATCH_REMOVE_PARENS(TmplTypes)>()), TypeList<INTERNAL_CATCH_MAKE_TYPE_LISTS_FROM_TYPES(INTERNAL_CATCH_REMOVE_PARENS(TypesList))>>::type; \
+ TestInit t; \
+ t.reg_tests(); \
return 0; \
}(); \
} \
- CATCH_INTERNAL_UNSUPPRESS_GLOBALS_WARNINGS \
+ } \
+ CATCH_INTERNAL_STOP_WARNINGS_SUPPRESSION \
template<typename TestType> \
static void TestFuncName()
#ifndef CATCH_CONFIG_TRADITIONAL_MSVC_PREPROCESSOR
#define INTERNAL_CATCH_TEMPLATE_PRODUCT_TEST_CASE(Name, Tags, ...)\
- INTERNAL_CATCH_TEMPLATE_PRODUCT_TEST_CASE2(INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_M_P_L_A_T_E____T_E_S_T____ ), INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_M_P_L_A_T_E____T_E_S_T____F_U_N_C____ ),Name,Tags,__VA_ARGS__)
+ INTERNAL_CATCH_TEMPLATE_PRODUCT_TEST_CASE2(INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_M_P_L_A_T_E____T_E_S_T____ ), INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_M_P_L_A_T_E____T_E_S_T____F_U_N_C____ ), Name, Tags, typename T,__VA_ARGS__)
#else
#define INTERNAL_CATCH_TEMPLATE_PRODUCT_TEST_CASE(Name, Tags, ...)\
- INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_PRODUCT_TEST_CASE2( INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_M_P_L_A_T_E____T_E_S_T____ ), INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_M_P_L_A_T_E____T_E_S_T____F_U_N_C____ ), Name, Tags, __VA_ARGS__ ) )
+ INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_PRODUCT_TEST_CASE2( INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_M_P_L_A_T_E____T_E_S_T____ ), INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_M_P_L_A_T_E____T_E_S_T____F_U_N_C____ ), Name, Tags, typename T, __VA_ARGS__ ) )
+#endif
+
+#ifndef CATCH_CONFIG_TRADITIONAL_MSVC_PREPROCESSOR
+ #define INTERNAL_CATCH_TEMPLATE_PRODUCT_TEST_CASE_SIG(Name, Tags, Signature, ...)\
+ INTERNAL_CATCH_TEMPLATE_PRODUCT_TEST_CASE2(INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_M_P_L_A_T_E____T_E_S_T____ ), INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_M_P_L_A_T_E____T_E_S_T____F_U_N_C____ ), Name, Tags, Signature, __VA_ARGS__)
+#else
+ #define INTERNAL_CATCH_TEMPLATE_PRODUCT_TEST_CASE_SIG(Name, Tags, Signature, ...)\
+ INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_PRODUCT_TEST_CASE2( INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_M_P_L_A_T_E____T_E_S_T____ ), INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_M_P_L_A_T_E____T_E_S_T____F_U_N_C____ ), Name, Tags, Signature, __VA_ARGS__ ) )
#endif
- #define INTERNAL_CATCH_TEMPLATE_TEST_CASE_METHOD_2( TestNameClass, TestName, ClassName, Name, Tags, ... ) \
+ #define INTERNAL_CATCH_TEMPLATE_LIST_TEST_CASE_2(TestName, TestFunc, Name, Tags, TmplList)\
+ CATCH_INTERNAL_START_WARNINGS_SUPPRESSION \
CATCH_INTERNAL_SUPPRESS_GLOBALS_WARNINGS \
- namespace{ \
- template<typename TestType> \
- struct TestName : INTERNAL_CATCH_REMOVE_PARENS(ClassName <TestType>) { \
- void test();\
- };\
+ CATCH_INTERNAL_SUPPRESS_UNUSED_TEMPLATE_WARNINGS \
+ template<typename TestType> static void TestFunc(); \
+ namespace {\
+ namespace INTERNAL_CATCH_MAKE_NAMESPACE(TestName){\
+ INTERNAL_CATCH_TYPE_GEN\
+ template<typename... Types> \
+ struct TestName { \
+ void reg_tests() { \
+ int index = 0; \
+ using expander = int[]; \
+ (void)expander{(Catch::AutoReg( Catch::makeTestInvoker( &TestFunc<Types> ), CATCH_INTERNAL_LINEINFO, Catch::StringRef(), Catch::NameAndTags{ Name " - " + std::string(INTERNAL_CATCH_STRINGIZE(TmplList)) + " - " + std::to_string(index), Tags } ), index++, 0)... };/* NOLINT */\
+ } \
+ };\
+ static int INTERNAL_CATCH_UNIQUE_NAME( globalRegistrar ) = [](){ \
+ using TestInit = typename convert<TestName, TmplList>::type; \
+ TestInit t; \
+ t.reg_tests(); \
+ return 0; \
+ }(); \
+ }}\
+ CATCH_INTERNAL_STOP_WARNINGS_SUPPRESSION \
+ template<typename TestType> \
+ static void TestFunc()
+
+ #define INTERNAL_CATCH_TEMPLATE_LIST_TEST_CASE(Name, Tags, TmplList) \
+ INTERNAL_CATCH_TEMPLATE_LIST_TEST_CASE_2( INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_M_P_L_A_T_E____T_E_S_T____ ), INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_M_P_L_A_T_E____T_E_S_T____F_U_N_C____ ), Name, Tags, TmplList )
+
+
+ #define INTERNAL_CATCH_TEMPLATE_TEST_CASE_METHOD_2( TestNameClass, TestName, ClassName, Name, Tags, Signature, ... ) \
+ CATCH_INTERNAL_START_WARNINGS_SUPPRESSION \
+ CATCH_INTERNAL_SUPPRESS_GLOBALS_WARNINGS \
+ CATCH_INTERNAL_SUPPRESS_ZERO_VARIADIC_WARNINGS \
+ CATCH_INTERNAL_SUPPRESS_UNUSED_TEMPLATE_WARNINGS \
+ namespace {\
+ namespace INTERNAL_CATCH_MAKE_NAMESPACE(TestName){ \
+ INTERNAL_CATCH_TYPE_GEN\
+ INTERNAL_CATCH_NTTP_GEN(INTERNAL_CATCH_REMOVE_PARENS(Signature))\
+ INTERNAL_CATCH_DECLARE_SIG_TEST_METHOD(TestName, ClassName, INTERNAL_CATCH_REMOVE_PARENS(Signature));\
+ INTERNAL_CATCH_NTTP_REG_METHOD_GEN(TestName, INTERNAL_CATCH_REMOVE_PARENS(Signature))\
template<typename...Types> \
struct TestNameClass{\
- template<typename...Ts> \
- TestNameClass(Ts...names){\
- CATCH_INTERNAL_CHECK_UNIQUE_TYPES(CATCH_REC_LIST(INTERNAL_CATCH_REMOVE_PARENS, __VA_ARGS__)) \
+ TestNameClass(){\
+ int index = 0; \
+ constexpr char const* tmpl_types[] = {CATCH_REC_LIST(INTERNAL_CATCH_STRINGIZE_WITHOUT_PARENS, __VA_ARGS__)};\
using expander = int[];\
- (void)expander{(Catch::AutoReg( Catch::makeTestInvoker( &TestName<Types>::test ), CATCH_INTERNAL_LINEINFO, #ClassName, Catch::NameAndTags{ names, Tags } ), 0)... };/* NOLINT */ \
+ (void)expander{(reg_test(Types{}, #ClassName, Catch::NameAndTags{ Name " - " + std::string(tmpl_types[index]), Tags } ), index++, 0)... };/* NOLINT */ \
}\
};\
- INTERNAL_CATCH_TEMPLATE_REGISTRY_INITIATE(TestNameClass, Name, __VA_ARGS__)\
+ static int INTERNAL_CATCH_UNIQUE_NAME( globalRegistrar ) = [](){\
+ TestNameClass<INTERNAL_CATCH_MAKE_TYPE_LISTS_FROM_TYPES(__VA_ARGS__)>();\
+ return 0;\
+ }();\
}\
- CATCH_INTERNAL_UNSUPPRESS_GLOBALS_WARNINGS\
- template<typename TestType> \
- void TestName<TestType>::test()
+ }\
+ CATCH_INTERNAL_STOP_WARNINGS_SUPPRESSION \
+ INTERNAL_CATCH_DEFINE_SIG_TEST_METHOD(TestName, INTERNAL_CATCH_REMOVE_PARENS(Signature))
#ifndef CATCH_CONFIG_TRADITIONAL_MSVC_PREPROCESSOR
#define INTERNAL_CATCH_TEMPLATE_TEST_CASE_METHOD( ClassName, Name, Tags,... ) \
- INTERNAL_CATCH_TEMPLATE_TEST_CASE_METHOD_2( INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_M_P_L_A_T_E____T_E_S_T____C_L_A_S_S____ ), INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_M_P_L_A_T_E____T_E_S_T____ ) , ClassName, Name, Tags, __VA_ARGS__ )
+ INTERNAL_CATCH_TEMPLATE_TEST_CASE_METHOD_2( INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_M_P_L_A_T_E____T_E_S_T____C_L_A_S_S____ ), INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_M_P_L_A_T_E____T_E_S_T____ ) , ClassName, Name, Tags, typename T, __VA_ARGS__ )
#else
#define INTERNAL_CATCH_TEMPLATE_TEST_CASE_METHOD( ClassName, Name, Tags,... ) \
- INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_TEST_CASE_METHOD_2( INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_M_P_L_A_T_E____T_E_S_T____C_L_A_S_S____ ), INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_M_P_L_A_T_E____T_E_S_T____ ) , ClassName, Name, Tags, __VA_ARGS__ ) )
+ INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_TEST_CASE_METHOD_2( INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_M_P_L_A_T_E____T_E_S_T____C_L_A_S_S____ ), INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_M_P_L_A_T_E____T_E_S_T____ ) , ClassName, Name, Tags, typename T, __VA_ARGS__ ) )
#endif
- #define INTERNAL_CATCH_TEMPLATE_PRODUCT_TEST_CASE_METHOD_2(TestNameClass, TestName, ClassName, Name, Tags, TmplTypes, TypesList)\
+#ifndef CATCH_CONFIG_TRADITIONAL_MSVC_PREPROCESSOR
+ #define INTERNAL_CATCH_TEMPLATE_TEST_CASE_METHOD_SIG( ClassName, Name, Tags, Signature, ... ) \
+ INTERNAL_CATCH_TEMPLATE_TEST_CASE_METHOD_2( INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_M_P_L_A_T_E____T_E_S_T____C_L_A_S_S____ ), INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_M_P_L_A_T_E____T_E_S_T____ ) , ClassName, Name, Tags, Signature, __VA_ARGS__ )
+#else
+ #define INTERNAL_CATCH_TEMPLATE_TEST_CASE_METHOD_SIG( ClassName, Name, Tags, Signature, ... ) \
+ INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_TEST_CASE_METHOD_2( INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_M_P_L_A_T_E____T_E_S_T____C_L_A_S_S____ ), INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_M_P_L_A_T_E____T_E_S_T____ ) , ClassName, Name, Tags, Signature, __VA_ARGS__ ) )
+#endif
+
+ #define INTERNAL_CATCH_TEMPLATE_PRODUCT_TEST_CASE_METHOD_2(TestNameClass, TestName, ClassName, Name, Tags, Signature, TmplTypes, TypesList)\
+ CATCH_INTERNAL_START_WARNINGS_SUPPRESSION \
CATCH_INTERNAL_SUPPRESS_GLOBALS_WARNINGS \
+ CATCH_INTERNAL_SUPPRESS_ZERO_VARIADIC_WARNINGS \
+ CATCH_INTERNAL_SUPPRESS_UNUSED_TEMPLATE_WARNINGS \
template<typename TestType> \
struct TestName : INTERNAL_CATCH_REMOVE_PARENS(ClassName <TestType>) { \
void test();\
};\
namespace {\
+ namespace INTERNAL_CATCH_MAKE_NAMESPACE(TestNameClass) {\
+ INTERNAL_CATCH_TYPE_GEN \
+ INTERNAL_CATCH_NTTP_GEN(INTERNAL_CATCH_REMOVE_PARENS(Signature))\
template<typename...Types>\
struct TestNameClass{\
- TestNameClass(){\
- CATCH_INTERNAL_CHECK_UNIQUE_TYPES(Types...)\
+ void reg_tests(){\
int index = 0;\
using expander = int[];\
constexpr char const* tmpl_types[] = {CATCH_REC_LIST(INTERNAL_CATCH_STRINGIZE_WITHOUT_PARENS, INTERNAL_CATCH_REMOVE_PARENS(TmplTypes))};\
@@ -236,22 +338,65 @@ struct AutoReg : NonCopyable {
}\
};\
static int INTERNAL_CATCH_UNIQUE_NAME( globalRegistrar ) = [](){\
- using TestInit = Catch::combine<INTERNAL_CATCH_REMOVE_PARENS(TmplTypes)>\
- ::with_types<INTERNAL_CATCH_MAKE_TYPE_LISTS_FROM_TYPES(TypesList)>::into<TestNameClass>::type;\
- TestInit();\
+ using TestInit = typename create<TestNameClass, decltype(get_wrapper<INTERNAL_CATCH_REMOVE_PARENS(TmplTypes)>()), TypeList<INTERNAL_CATCH_MAKE_TYPE_LISTS_FROM_TYPES(INTERNAL_CATCH_REMOVE_PARENS(TypesList))>>::type;\
+ TestInit t;\
+ t.reg_tests();\
return 0;\
}(); \
}\
- CATCH_INTERNAL_UNSUPPRESS_GLOBALS_WARNINGS \
+ }\
+ CATCH_INTERNAL_STOP_WARNINGS_SUPPRESSION \
template<typename TestType> \
void TestName<TestType>::test()
#ifndef CATCH_CONFIG_TRADITIONAL_MSVC_PREPROCESSOR
#define INTERNAL_CATCH_TEMPLATE_PRODUCT_TEST_CASE_METHOD( ClassName, Name, Tags, ... )\
- INTERNAL_CATCH_TEMPLATE_PRODUCT_TEST_CASE_METHOD_2( INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_M_P_L_A_T_E____T_E_S_T____ ), INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_M_P_L_A_T_E____T_E_S_T____F_U_N_C____ ), ClassName, Name, Tags, __VA_ARGS__ )
+ INTERNAL_CATCH_TEMPLATE_PRODUCT_TEST_CASE_METHOD_2( INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_M_P_L_A_T_E____T_E_S_T____ ), INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_M_P_L_A_T_E____T_E_S_T____F_U_N_C____ ), ClassName, Name, Tags, typename T, __VA_ARGS__ )
#else
#define INTERNAL_CATCH_TEMPLATE_PRODUCT_TEST_CASE_METHOD( ClassName, Name, Tags, ... )\
- INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_PRODUCT_TEST_CASE_METHOD_2( INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_M_P_L_A_T_E____T_E_S_T____ ), INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_M_P_L_A_T_E____T_E_S_T____F_U_N_C____ ), ClassName, Name, Tags, __VA_ARGS__ ) )
+ INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_PRODUCT_TEST_CASE_METHOD_2( INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_M_P_L_A_T_E____T_E_S_T____ ), INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_M_P_L_A_T_E____T_E_S_T____F_U_N_C____ ), ClassName, Name, Tags, typename T,__VA_ARGS__ ) )
#endif
+#ifndef CATCH_CONFIG_TRADITIONAL_MSVC_PREPROCESSOR
+ #define INTERNAL_CATCH_TEMPLATE_PRODUCT_TEST_CASE_METHOD_SIG( ClassName, Name, Tags, Signature, ... )\
+ INTERNAL_CATCH_TEMPLATE_PRODUCT_TEST_CASE_METHOD_2( INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_M_P_L_A_T_E____T_E_S_T____ ), INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_M_P_L_A_T_E____T_E_S_T____F_U_N_C____ ), ClassName, Name, Tags, Signature, __VA_ARGS__ )
+#else
+ #define INTERNAL_CATCH_TEMPLATE_PRODUCT_TEST_CASE_METHOD_SIG( ClassName, Name, Tags, Signature, ... )\
+ INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_PRODUCT_TEST_CASE_METHOD_2( INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_M_P_L_A_T_E____T_E_S_T____ ), INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_M_P_L_A_T_E____T_E_S_T____F_U_N_C____ ), ClassName, Name, Tags, Signature,__VA_ARGS__ ) )
+#endif
+
+ #define INTERNAL_CATCH_TEMPLATE_LIST_TEST_CASE_METHOD_2( TestNameClass, TestName, ClassName, Name, Tags, TmplList) \
+ CATCH_INTERNAL_START_WARNINGS_SUPPRESSION \
+ CATCH_INTERNAL_SUPPRESS_GLOBALS_WARNINGS \
+ CATCH_INTERNAL_SUPPRESS_UNUSED_TEMPLATE_WARNINGS \
+ template<typename TestType> \
+ struct TestName : INTERNAL_CATCH_REMOVE_PARENS(ClassName <TestType>) { \
+ void test();\
+ };\
+ namespace {\
+ namespace INTERNAL_CATCH_MAKE_NAMESPACE(TestName){ \
+ INTERNAL_CATCH_TYPE_GEN\
+ template<typename...Types>\
+ struct TestNameClass{\
+ void reg_tests(){\
+ int index = 0;\
+ using expander = int[];\
+ (void)expander{(Catch::AutoReg( Catch::makeTestInvoker( &TestName<Types>::test ), CATCH_INTERNAL_LINEINFO, #ClassName, Catch::NameAndTags{ Name " - " + std::string(INTERNAL_CATCH_STRINGIZE(TmplList)) + " - " + std::to_string(index), Tags } ), index++, 0)... };/* NOLINT */ \
+ }\
+ };\
+ static int INTERNAL_CATCH_UNIQUE_NAME( globalRegistrar ) = [](){\
+ using TestInit = typename convert<TestNameClass, TmplList>::type;\
+ TestInit t;\
+ t.reg_tests();\
+ return 0;\
+ }(); \
+ }}\
+ CATCH_INTERNAL_STOP_WARNINGS_SUPPRESSION \
+ template<typename TestType> \
+ void TestName<TestType>::test()
+
+#define INTERNAL_CATCH_TEMPLATE_LIST_TEST_CASE_METHOD(ClassName, Name, Tags, TmplList) \
+ INTERNAL_CATCH_TEMPLATE_LIST_TEST_CASE_METHOD_2( INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_M_P_L_A_T_E____T_E_S_T____ ), INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_M_P_L_A_T_E____T_E_S_T____F_U_N_C____ ), ClassName, Name, Tags, TmplList )
+
+
#endif // TWOBLUECUBES_CATCH_TEST_REGISTRY_HPP_INCLUDED
diff --git a/include/internal/catch_test_spec.cpp b/include/internal/catch_test_spec.cpp
index d9c149d5..65d34d0e 100644
--- a/include/internal/catch_test_spec.cpp
+++ b/include/internal/catch_test_spec.cpp
@@ -7,6 +7,7 @@
#include "catch_test_spec.h"
#include "catch_string_manip.h"
+#include "catch_interfaces_config.h"
#include <algorithm>
#include <string>
@@ -15,45 +16,84 @@
namespace Catch {
+ TestSpec::Pattern::Pattern( std::string const& name )
+ : m_name( name )
+ {}
+
TestSpec::Pattern::~Pattern() = default;
- TestSpec::NamePattern::~NamePattern() = default;
- TestSpec::TagPattern::~TagPattern() = default;
- TestSpec::ExcludedPattern::~ExcludedPattern() = default;
- TestSpec::NamePattern::NamePattern( std::string const& name )
- : m_wildcardPattern( toLower( name ), CaseSensitive::No )
+ std::string const& TestSpec::Pattern::name() const {
+ return m_name;
+ }
+
+
+ TestSpec::NamePattern::NamePattern( std::string const& name, std::string const& filterString )
+ : Pattern( filterString )
+ , m_wildcardPattern( toLower( name ), CaseSensitive::No )
{}
+
bool TestSpec::NamePattern::matches( TestCaseInfo const& testCase ) const {
- return m_wildcardPattern.matches( toLower( testCase.name ) );
+ return m_wildcardPattern.matches( testCase.name );
}
- TestSpec::TagPattern::TagPattern( std::string const& tag ) : m_tag( toLower( tag ) ) {}
+
+ TestSpec::TagPattern::TagPattern( std::string const& tag, std::string const& filterString )
+ : Pattern( filterString )
+ , m_tag( toLower( tag ) )
+ {}
+
bool TestSpec::TagPattern::matches( TestCaseInfo const& testCase ) const {
return std::find(begin(testCase.lcaseTags),
end(testCase.lcaseTags),
m_tag) != end(testCase.lcaseTags);
}
- TestSpec::ExcludedPattern::ExcludedPattern( PatternPtr const& underlyingPattern ) : m_underlyingPattern( underlyingPattern ) {}
- bool TestSpec::ExcludedPattern::matches( TestCaseInfo const& testCase ) const { return !m_underlyingPattern->matches( testCase ); }
+
+ TestSpec::ExcludedPattern::ExcludedPattern( PatternPtr const& underlyingPattern )
+ : Pattern( underlyingPattern->name() )
+ , m_underlyingPattern( underlyingPattern )
+ {}
+
+ bool TestSpec::ExcludedPattern::matches( TestCaseInfo const& testCase ) const {
+ return !m_underlyingPattern->matches( testCase );
+ }
+
bool TestSpec::Filter::matches( TestCaseInfo const& testCase ) const {
- // All patterns in a filter must match for the filter to be a match
- for( auto const& pattern : m_patterns ) {
- if( !pattern->matches( testCase ) )
- return false;
- }
- return true;
+ return std::all_of( m_patterns.begin(), m_patterns.end(), [&]( PatternPtr const& p ){ return p->matches( testCase ); } );
}
+ std::string TestSpec::Filter::name() const {
+ std::string name;
+ for( auto const& p : m_patterns )
+ name += p->name();
+ return name;
+ }
+
+
bool TestSpec::hasFilters() const {
return !m_filters.empty();
}
+
bool TestSpec::matches( TestCaseInfo const& testCase ) const {
- // A TestSpec matches if any filter matches
- for( auto const& filter : m_filters )
- if( filter.matches( testCase ) )
- return true;
- return false;
+ return std::any_of( m_filters.begin(), m_filters.end(), [&]( Filter const& f ){ return f.matches( testCase ); } );
+ }
+
+ TestSpec::Matches TestSpec::matchesByFilter( std::vector<TestCase> const& testCases, IConfig const& config ) const
+ {
+ Matches matches( m_filters.size() );
+ std::transform( m_filters.begin(), m_filters.end(), matches.begin(), [&]( Filter const& filter ){
+ std::vector<TestCase const*> currentMatches;
+ for( auto const& test : testCases )
+ if( isThrowSafe( test, config ) && filter.matches( test ) )
+ currentMatches.emplace_back( &test );
+ return FilterMatch{ filter.name(), currentMatches };
+ } );
+ return matches;
}
+
+ const TestSpec::vectorStrings& TestSpec::getInvalidArgs() const{
+ return (m_invalidArgs);
+ }
+
}
diff --git a/include/internal/catch_test_spec.h b/include/internal/catch_test_spec.h
index d2565187..2e546463 100644
--- a/include/internal/catch_test_spec.h
+++ b/include/internal/catch_test_spec.h
@@ -22,17 +22,23 @@
namespace Catch {
+ struct IConfig;
+
class TestSpec {
- struct Pattern {
+ class Pattern {
+ public:
+ explicit Pattern( std::string const& name );
virtual ~Pattern();
virtual bool matches( TestCaseInfo const& testCase ) const = 0;
+ std::string const& name() const;
+ private:
+ std::string const m_name;
};
using PatternPtr = std::shared_ptr<Pattern>;
class NamePattern : public Pattern {
public:
- NamePattern( std::string const& name );
- virtual ~NamePattern();
+ explicit NamePattern( std::string const& name, std::string const& filterString );
bool matches( TestCaseInfo const& testCase ) const override;
private:
WildcardPattern m_wildcardPattern;
@@ -40,8 +46,7 @@ namespace Catch {
class TagPattern : public Pattern {
public:
- TagPattern( std::string const& tag );
- virtual ~TagPattern();
+ explicit TagPattern( std::string const& tag, std::string const& filterString );
bool matches( TestCaseInfo const& testCase ) const override;
private:
std::string m_tag;
@@ -49,8 +54,7 @@ namespace Catch {
class ExcludedPattern : public Pattern {
public:
- ExcludedPattern( PatternPtr const& underlyingPattern );
- virtual ~ExcludedPattern();
+ explicit ExcludedPattern( PatternPtr const& underlyingPattern );
bool matches( TestCaseInfo const& testCase ) const override;
private:
PatternPtr m_underlyingPattern;
@@ -60,15 +64,25 @@ namespace Catch {
std::vector<PatternPtr> m_patterns;
bool matches( TestCaseInfo const& testCase ) const;
+ std::string name() const;
};
public:
+ struct FilterMatch {
+ std::string name;
+ std::vector<TestCase const*> tests;
+ };
+ using Matches = std::vector<FilterMatch>;
+ using vectorStrings = std::vector<std::string>;
+
bool hasFilters() const;
bool matches( TestCaseInfo const& testCase ) const;
+ Matches matchesByFilter( std::vector<TestCase> const& testCases, IConfig const& config ) const;
+ const vectorStrings & getInvalidArgs() const;
private:
std::vector<Filter> m_filters;
-
+ std::vector<std::string> m_invalidArgs;
friend class TestSpecParser;
};
}
diff --git a/include/internal/catch_test_spec_parser.cpp b/include/internal/catch_test_spec_parser.cpp
index 61c9e4df..dad15c01 100644
--- a/include/internal/catch_test_spec_parser.cpp
+++ b/include/internal/catch_test_spec_parser.cpp
@@ -7,6 +7,7 @@
#include "catch_test_spec_parser.h"
+
namespace Catch {
TestSpecParser::TestSpecParser( ITagAliasRegistry const& tagAliases ) : m_tagAliases( &tagAliases ) {}
@@ -14,64 +15,136 @@ namespace Catch {
TestSpecParser& TestSpecParser::parse( std::string const& arg ) {
m_mode = None;
m_exclusion = false;
- m_start = std::string::npos;
m_arg = m_tagAliases->expandAliases( arg );
m_escapeChars.clear();
+ m_substring.reserve(m_arg.size());
+ m_patternName.reserve(m_arg.size());
+ m_realPatternPos = 0;
+
for( m_pos = 0; m_pos < m_arg.size(); ++m_pos )
- visitChar( m_arg[m_pos] );
- if( m_mode == Name )
- addPattern<TestSpec::NamePattern>();
+ //if visitChar fails
+ if( !visitChar( m_arg[m_pos] ) ){
+ m_testSpec.m_invalidArgs.push_back(arg);
+ break;
+ }
+ endMode();
return *this;
}
TestSpec TestSpecParser::testSpec() {
addFilter();
return m_testSpec;
}
+ bool TestSpecParser::visitChar( char c ) {
+ if( (m_mode != EscapedName) && (c == '\\') ) {
+ escape();
+ addCharToPattern(c);
+ return true;
+ }else if((m_mode != EscapedName) && (c == ',') ) {
+ return separate();
+ }
- void TestSpecParser::visitChar( char c ) {
- if( m_mode == None ) {
- switch( c ) {
- case ' ': return;
- case '~': m_exclusion = true; return;
- case '[': return startNewMode( Tag, ++m_pos );
- case '"': return startNewMode( QuotedName, ++m_pos );
- case '\\': return escape();
- default: startNewMode( Name, m_pos ); break;
- }
+ switch( m_mode ) {
+ case None:
+ if( processNoneChar( c ) )
+ return true;
+ break;
+ case Name:
+ processNameChar( c );
+ break;
+ case EscapedName:
+ endMode();
+ addCharToPattern(c);
+ return true;
+ default:
+ case Tag:
+ case QuotedName:
+ if( processOtherChar( c ) )
+ return true;
+ break;
}
- if( m_mode == Name ) {
- if( c == ',' ) {
- addPattern<TestSpec::NamePattern>();
- addFilter();
- }
- else if( c == '[' ) {
- if( subString() == "exclude:" )
- m_exclusion = true;
- else
- addPattern<TestSpec::NamePattern>();
- startNewMode( Tag, ++m_pos );
- }
- else if( c == '\\' )
- escape();
+
+ m_substring += c;
+ if( !isControlChar( c ) ) {
+ m_patternName += c;
+ m_realPatternPos++;
+ }
+ return true;
+ }
+ // Two of the processing methods return true to signal the caller to return
+ // without adding the given character to the current pattern strings
+ bool TestSpecParser::processNoneChar( char c ) {
+ switch( c ) {
+ case ' ':
+ return true;
+ case '~':
+ m_exclusion = true;
+ return false;
+ case '[':
+ startNewMode( Tag );
+ return false;
+ case '"':
+ startNewMode( QuotedName );
+ return false;
+ default:
+ startNewMode( Name );
+ return false;
}
- else if( m_mode == EscapedName )
- m_mode = Name;
- else if( m_mode == QuotedName && c == '"' )
- addPattern<TestSpec::NamePattern>();
- else if( m_mode == Tag && c == ']' )
- addPattern<TestSpec::TagPattern>();
- }
- void TestSpecParser::startNewMode( Mode mode, std::size_t start ) {
+ }
+ void TestSpecParser::processNameChar( char c ) {
+ if( c == '[' ) {
+ if( m_substring == "exclude:" )
+ m_exclusion = true;
+ else
+ endMode();
+ startNewMode( Tag );
+ }
+ }
+ bool TestSpecParser::processOtherChar( char c ) {
+ if( !isControlChar( c ) )
+ return false;
+ m_substring += c;
+ endMode();
+ return true;
+ }
+ void TestSpecParser::startNewMode( Mode mode ) {
m_mode = mode;
- m_start = start;
+ }
+ void TestSpecParser::endMode() {
+ switch( m_mode ) {
+ case Name:
+ case QuotedName:
+ return addNamePattern();
+ case Tag:
+ return addTagPattern();
+ case EscapedName:
+ revertBackToLastMode();
+ return;
+ case None:
+ default:
+ return startNewMode( None );
+ }
}
void TestSpecParser::escape() {
- if( m_mode == None )
- m_start = m_pos;
+ saveLastMode();
m_mode = EscapedName;
- m_escapeChars.push_back( m_pos );
+ m_escapeChars.push_back(m_realPatternPos);
+ }
+ bool TestSpecParser::isControlChar( char c ) const {
+ switch( m_mode ) {
+ default:
+ return false;
+ case None:
+ return c == '~';
+ case Name:
+ return c == '[';
+ case EscapedName:
+ return true;
+ case QuotedName:
+ return c == '"';
+ case Tag:
+ return c == '[' || c == ']';
+ }
}
- std::string TestSpecParser::subString() const { return m_arg.substr( m_start, m_pos - m_start ); }
void TestSpecParser::addFilter() {
if( !m_currentFilter.m_patterns.empty() ) {
@@ -80,6 +153,84 @@ namespace Catch {
}
}
+ void TestSpecParser::saveLastMode() {
+ lastMode = m_mode;
+ }
+
+ void TestSpecParser::revertBackToLastMode() {
+ m_mode = lastMode;
+ }
+
+ bool TestSpecParser::separate() {
+ if( (m_mode==QuotedName) || (m_mode==Tag) ){
+ //invalid argument, signal failure to previous scope.
+ m_mode = None;
+ m_pos = m_arg.size();
+ m_substring.clear();
+ m_patternName.clear();
+ return false;
+ }
+ endMode();
+ addFilter();
+ return true; //success
+ }
+
+ std::string TestSpecParser::preprocessPattern() {
+ std::string token = m_patternName;
+ for (std::size_t i = 0; i < m_escapeChars.size(); ++i)
+ token = token.substr(0, m_escapeChars[i] - i) + token.substr(m_escapeChars[i] - i + 1);
+ m_escapeChars.clear();
+ if (startsWith(token, "exclude:")) {
+ m_exclusion = true;
+ token = token.substr(8);
+ }
+
+ m_patternName.clear();
+
+ return token;
+ }
+
+ void TestSpecParser::addNamePattern() {
+ auto token = preprocessPattern();
+
+ if (!token.empty()) {
+ TestSpec::PatternPtr pattern = std::make_shared<TestSpec::NamePattern>(token, m_substring);
+ if (m_exclusion)
+ pattern = std::make_shared<TestSpec::ExcludedPattern>(pattern);
+ m_currentFilter.m_patterns.push_back(pattern);
+ }
+ m_substring.clear();
+ m_exclusion = false;
+ m_mode = None;
+ }
+
+ void TestSpecParser::addTagPattern() {
+ auto token = preprocessPattern();
+
+ if (!token.empty()) {
+ // If the tag pattern is the "hide and tag" shorthand (e.g. [.foo])
+ // we have to create a separate hide tag and shorten the real one
+ if (token.size() > 1 && token[0] == '.') {
+ token.erase(token.begin());
+ TestSpec::PatternPtr pattern = std::make_shared<TestSpec::TagPattern>(".", m_substring);
+ if (m_exclusion) {
+ pattern = std::make_shared<TestSpec::ExcludedPattern>(pattern);
+ }
+ m_currentFilter.m_patterns.push_back(pattern);
+ }
+
+ TestSpec::PatternPtr pattern = std::make_shared<TestSpec::TagPattern>(token, m_substring);
+
+ if (m_exclusion) {
+ pattern = std::make_shared<TestSpec::ExcludedPattern>(pattern);
+ }
+ m_currentFilter.m_patterns.push_back(pattern);
+ }
+ m_substring.clear();
+ m_exclusion = false;
+ m_mode = None;
+ }
+
TestSpec parseTestSpec( std::string const& arg ) {
return TestSpecParser( ITagAliasRegistry::get() ).parse( arg ).testSpec();
}
diff --git a/include/internal/catch_test_spec_parser.h b/include/internal/catch_test_spec_parser.h
index 79ce8898..250d7c16 100644
--- a/include/internal/catch_test_spec_parser.h
+++ b/include/internal/catch_test_spec_parser.h
@@ -22,9 +22,13 @@ namespace Catch {
class TestSpecParser {
enum Mode{ None, Name, QuotedName, Tag, EscapedName };
Mode m_mode = None;
+ Mode lastMode = None;
bool m_exclusion = false;
- std::size_t m_start = std::string::npos, m_pos = 0;
+ std::size_t m_pos = 0;
+ std::size_t m_realPatternPos = 0;
std::string m_arg;
+ std::string m_substring;
+ std::string m_patternName;
std::vector<std::size_t> m_escapeChars;
TestSpec::Filter m_currentFilter;
TestSpec m_testSpec;
@@ -37,32 +41,32 @@ namespace Catch {
TestSpec testSpec();
private:
- void visitChar( char c );
- void startNewMode( Mode mode, std::size_t start );
+ bool visitChar( char c );
+ void startNewMode( Mode mode );
+ bool processNoneChar( char c );
+ void processNameChar( char c );
+ bool processOtherChar( char c );
+ void endMode();
void escape();
- std::string subString() const;
+ bool isControlChar( char c ) const;
+ void saveLastMode();
+ void revertBackToLastMode();
+ void addFilter();
+ bool separate();
+
+ // Handles common preprocessing of the pattern for name/tag patterns
+ std::string preprocessPattern();
+ // Adds the current pattern as a test name
+ void addNamePattern();
+ // Adds the current pattern as a tag
+ void addTagPattern();
- template<typename T>
- void addPattern() {
- std::string token = subString();
- for( std::size_t i = 0; i < m_escapeChars.size(); ++i )
- token = token.substr( 0, m_escapeChars[i]-m_start-i ) + token.substr( m_escapeChars[i]-m_start-i+1 );
- m_escapeChars.clear();
- if( startsWith( token, "exclude:" ) ) {
- m_exclusion = true;
- token = token.substr( 8 );
- }
- if( !token.empty() ) {
- TestSpec::PatternPtr pattern = std::make_shared<T>( token );
- if( m_exclusion )
- pattern = std::make_shared<TestSpec::ExcludedPattern>( pattern );
- m_currentFilter.m_patterns.push_back( pattern );
- }
- m_exclusion = false;
- m_mode = None;
+ inline void addCharToPattern(char c) {
+ m_substring += c;
+ m_patternName += c;
+ m_realPatternPos++;
}
- void addFilter();
};
TestSpec parseTestSpec( std::string const& arg );
@@ -72,4 +76,4 @@ namespace Catch {
#pragma clang diagnostic pop
#endif
-#endif // TWOBLUECUBES_CATCH_TEST_SPEC_PARSER_HPP_INCLUDED
+#endif // TWOBLUECUBES_CATCH_TEST_SPEC_PARSER_HPP_INCLUDED \ No newline at end of file
diff --git a/include/internal/catch_tostring.cpp b/include/internal/catch_tostring.cpp
index b857d3fb..a289c341 100644
--- a/include/internal/catch_tostring.cpp
+++ b/include/internal/catch_tostring.cpp
@@ -38,13 +38,11 @@ namespace Detail {
enum Arch { Big, Little };
static Arch which() {
- union _{
- int asInt;
- char asChar[sizeof (int)];
- } u;
-
- u.asInt = 1;
- return ( u.asChar[sizeof(int)-1] == 1 ) ? Big : Little;
+ int one = 1;
+ // If the lowest byte we read is non-zero, we can assume
+ // that little endian format is used.
+ auto value = *reinterpret_cast<char*>(&one);
+ return value ? Little : Big;
}
};
}
@@ -170,6 +168,12 @@ std::string StringMaker<wchar_t *>::convert(wchar_t * str) {
}
#endif
+#if defined(CATCH_CONFIG_CPP17_BYTE)
+#include <cstddef>
+std::string StringMaker<std::byte>::convert(std::byte value) {
+ return ::Catch::Detail::stringify(std::to_integer<unsigned long long>(value));
+}
+#endif // defined(CATCH_CONFIG_CPP17_BYTE)
std::string StringMaker<int>::convert(int value) {
return ::Catch::Detail::stringify(static_cast<long long>(value));
@@ -234,11 +238,16 @@ std::string StringMaker<std::nullptr_t>::convert(std::nullptr_t) {
return "nullptr";
}
+int StringMaker<float>::precision = 5;
+
std::string StringMaker<float>::convert(float value) {
- return fpToString(value, 5) + 'f';
+ return fpToString(value, precision) + 'f';
}
+
+int StringMaker<double>::precision = 10;
+
std::string StringMaker<double>::convert(double value) {
- return fpToString(value, 10);
+ return fpToString(value, precision);
}
std::string ratio_string<std::atto>::symbol() { return "a"; }
diff --git a/include/internal/catch_tostring.h b/include/internal/catch_tostring.h
index 13a43b0c..640fc8cb 100644
--- a/include/internal/catch_tostring.h
+++ b/include/internal/catch_tostring.h
@@ -15,6 +15,7 @@
#include <string>
#include "catch_compiler_capabilities.h"
#include "catch_stream.h"
+#include "catch_interfaces_enum_values_registry.h"
#ifdef CATCH_CONFIG_CPP17_STRING_VIEW
#include <string_view>
@@ -43,9 +44,9 @@ namespace Catch {
template<typename T>
class IsStreamInsertable {
- template<typename SS, typename TT>
+ template<typename Stream, typename U>
static auto test(int)
- -> decltype(std::declval<SS&>() << std::declval<TT>(), std::true_type());
+ -> decltype(std::declval<Stream&>() << std::declval<U>(), std::true_type());
template<typename, typename>
static auto test(...)->std::false_type;
@@ -209,6 +210,12 @@ namespace Catch {
}
};
+#if defined(CATCH_CONFIG_CPP17_BYTE)
+ template<>
+ struct StringMaker<std::byte> {
+ static std::string convert(std::byte value);
+ };
+#endif // defined(CATCH_CONFIG_CPP17_BYTE)
template<>
struct StringMaker<int> {
static std::string convert(int value);
@@ -260,10 +267,13 @@ namespace Catch {
template<>
struct StringMaker<float> {
static std::string convert(float value);
+ static int precision;
};
+
template<>
struct StringMaker<double> {
static std::string convert(double value);
+ static int precision;
};
template <typename T>
@@ -639,6 +649,17 @@ struct ratio_string<std::milli> {
}
#endif // CATCH_CONFIG_ENABLE_CHRONO_STRINGMAKER
+#define INTERNAL_CATCH_REGISTER_ENUM( enumName, ... ) \
+namespace Catch { \
+ template<> struct StringMaker<enumName> { \
+ static std::string convert( enumName value ) { \
+ static const auto& enumInfo = ::Catch::getMutableRegistryHub().getMutableEnumValuesRegistry().registerEnum( #enumName, #__VA_ARGS__, { __VA_ARGS__ } ); \
+ return static_cast<std::string>(enumInfo.lookup( static_cast<int>( value ) )); \
+ } \
+ }; \
+}
+
+#define CATCH_REGISTER_ENUM( enumName, ... ) INTERNAL_CATCH_REGISTER_ENUM( enumName, __VA_ARGS__ )
#ifdef _MSC_VER
#pragma warning(pop)
diff --git a/include/internal/catch_type_traits.hpp b/include/internal/catch_type_traits.hpp
deleted file mode 100644
index 8edb1ecf..00000000
--- a/include/internal/catch_type_traits.hpp
+++ /dev/null
@@ -1,40 +0,0 @@
-/*
- * Created by Jozef on 12/11/2018.
- * 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)
- */
-
-#ifndef TWOBLUECUBES_CATCH_TYPE_TRAITS_HPP_INCLUDED
-#define TWOBLUECUBES_CATCH_TYPE_TRAITS_HPP_INCLUDED
-
-#include <type_traits>
-
-namespace Catch{
-
-#ifdef CATCH_CPP17_OR_GREATER
- template <typename...>
- inline constexpr auto is_unique = std::true_type{};
-
- template <typename T, typename... Rest>
- inline constexpr auto is_unique<T, Rest...> = std::bool_constant<
- (!std::is_same_v<T, Rest> && ...) && is_unique<Rest...>
- >{};
-#else
-
-template <typename...>
-struct is_unique : std::true_type{};
-
-template <typename T0, typename T1, typename... Rest>
-struct is_unique<T0, T1, Rest...> : std::integral_constant
-<bool,
- !std::is_same<T0, T1>::value
- && is_unique<T0, Rest...>::value
- && is_unique<T1, Rest...>::value
->{};
-
-#endif
-}
-
-#endif // TWOBLUECUBES_CATCH_TYPE_TRAITS_HPP_INCLUDED
diff --git a/include/internal/catch_version.cpp b/include/internal/catch_version.cpp
index 5f4917c1..143a350e 100644
--- a/include/internal/catch_version.cpp
+++ b/include/internal/catch_version.cpp
@@ -37,7 +37,7 @@ namespace Catch {
}
Version const& libraryVersion() {
- static Version version( 2, 7, 2, "", 0 );
+ static Version version( 2, 11, 2, "", 0 );
return version;
}
diff --git a/include/internal/catch_wildcard_pattern.cpp b/include/internal/catch_wildcard_pattern.cpp
index 9bf20f04..95e5d3f0 100644
--- a/include/internal/catch_wildcard_pattern.cpp
+++ b/include/internal/catch_wildcard_pattern.cpp
@@ -9,14 +9,12 @@
#include "catch_enforce.h"
#include "catch_string_manip.h"
-#include <sstream>
-
namespace Catch {
WildcardPattern::WildcardPattern( std::string const& pattern,
CaseSensitive::Choice caseSensitivity )
: m_caseSensitivity( caseSensitivity ),
- m_pattern( adjustCase( pattern ) )
+ m_pattern( normaliseString( pattern ) )
{
if( startsWith( m_pattern, '*' ) ) {
m_pattern = m_pattern.substr( 1 );
@@ -31,19 +29,19 @@ namespace Catch {
bool WildcardPattern::matches( std::string const& str ) const {
switch( m_wildcard ) {
case NoWildcard:
- return m_pattern == adjustCase( str );
+ return m_pattern == normaliseString( str );
case WildcardAtStart:
- return endsWith( adjustCase( str ), m_pattern );
+ return endsWith( normaliseString( str ), m_pattern );
case WildcardAtEnd:
- return startsWith( adjustCase( str ), m_pattern );
+ return startsWith( normaliseString( str ), m_pattern );
case WildcardAtBothEnds:
- return contains( adjustCase( str ), m_pattern );
+ return contains( normaliseString( str ), m_pattern );
default:
CATCH_INTERNAL_ERROR( "Unknown enum" );
}
}
- std::string WildcardPattern::adjustCase( std::string const& str ) const {
- return m_caseSensitivity == CaseSensitive::No ? toLower( str ) : str;
+ std::string WildcardPattern::normaliseString( std::string const& str ) const {
+ return trim( m_caseSensitivity == CaseSensitive::No ? toLower( str ) : str );
}
}
diff --git a/include/internal/catch_wildcard_pattern.h b/include/internal/catch_wildcard_pattern.h
index 4dae7171..5d508f7b 100644
--- a/include/internal/catch_wildcard_pattern.h
+++ b/include/internal/catch_wildcard_pattern.h
@@ -28,7 +28,7 @@ namespace Catch
virtual bool matches( std::string const& str ) const;
private:
- std::string adjustCase( std::string const& str ) const;
+ std::string normaliseString( std::string const& str ) const;
CaseSensitive::Choice m_caseSensitivity;
WildcardPosition m_wildcard = NoWildcard;
std::string m_pattern;
diff --git a/include/internal/catch_xmlwriter.cpp b/include/internal/catch_xmlwriter.cpp
index 5354efa7..30f3b0f1 100644
--- a/include/internal/catch_xmlwriter.cpp
+++ b/include/internal/catch_xmlwriter.cpp
@@ -10,8 +10,7 @@
#include "catch_enforce.h"
#include <iomanip>
-
-using uchar = unsigned char;
+#include <type_traits>
namespace Catch {
@@ -51,8 +50,31 @@ namespace {
os.flags(f);
}
+ bool shouldNewline(XmlFormatting fmt) {
+ return !!(static_cast<std::underlying_type<XmlFormatting>::type>(fmt & XmlFormatting::Newline));
+ }
+
+ bool shouldIndent(XmlFormatting fmt) {
+ return !!(static_cast<std::underlying_type<XmlFormatting>::type>(fmt & XmlFormatting::Indent));
+ }
+
} // anonymous namespace
+ XmlFormatting operator | (XmlFormatting lhs, XmlFormatting rhs) {
+ return static_cast<XmlFormatting>(
+ static_cast<std::underlying_type<XmlFormatting>::type>(lhs) |
+ static_cast<std::underlying_type<XmlFormatting>::type>(rhs)
+ );
+ }
+
+ XmlFormatting operator & (XmlFormatting lhs, XmlFormatting rhs) {
+ return static_cast<XmlFormatting>(
+ static_cast<std::underlying_type<XmlFormatting>::type>(lhs) &
+ static_cast<std::underlying_type<XmlFormatting>::type>(rhs)
+ );
+ }
+
+
XmlEncode::XmlEncode( std::string const& str, ForWhat forWhat )
: m_str( str ),
m_forWhat( forWhat )
@@ -63,7 +85,7 @@ namespace {
// (see: http://www.w3.org/TR/xml/#syntax)
for( std::size_t idx = 0; idx < m_str.size(); ++ idx ) {
- uchar c = m_str[idx];
+ unsigned char c = m_str[idx];
switch (c) {
case '<': os << "&lt;"; break;
case '&': os << "&amp;"; break;
@@ -123,7 +145,7 @@ namespace {
bool valid = true;
uint32_t value = headerValue(c);
for (std::size_t n = 1; n < encBytes; ++n) {
- uchar nc = m_str[idx + n];
+ unsigned char nc = m_str[idx + n];
valid &= ((nc & 0xC0) == 0x80);
value = (value << 6) | (nc & 0x3F);
}
@@ -157,13 +179,17 @@ namespace {
return os;
}
- XmlWriter::ScopedElement::ScopedElement( XmlWriter* writer )
- : m_writer( writer )
+ XmlWriter::ScopedElement::ScopedElement( XmlWriter* writer, XmlFormatting fmt )
+ : m_writer( writer ),
+ m_fmt(fmt)
{}
XmlWriter::ScopedElement::ScopedElement( ScopedElement&& other ) noexcept
- : m_writer( other.m_writer ){
+ : m_writer( other.m_writer ),
+ m_fmt(other.m_fmt)
+ {
other.m_writer = nullptr;
+ other.m_fmt = XmlFormatting::None;
}
XmlWriter::ScopedElement& XmlWriter::ScopedElement::operator=( ScopedElement&& other ) noexcept {
if ( m_writer ) {
@@ -171,17 +197,20 @@ namespace {
}
m_writer = other.m_writer;
other.m_writer = nullptr;
+ m_fmt = other.m_fmt;
+ other.m_fmt = XmlFormatting::None;
return *this;
}
XmlWriter::ScopedElement::~ScopedElement() {
- if( m_writer )
- m_writer->endElement();
+ if (m_writer) {
+ m_writer->endElement(m_fmt);
+ }
}
- XmlWriter::ScopedElement& XmlWriter::ScopedElement::writeText( std::string const& text, bool indent ) {
- m_writer->writeText( text, indent );
+ XmlWriter::ScopedElement& XmlWriter::ScopedElement::writeText( std::string const& text, XmlFormatting fmt ) {
+ m_writer->writeText( text, fmt );
return *this;
}
@@ -191,37 +220,47 @@ namespace {
}
XmlWriter::~XmlWriter() {
- while( !m_tags.empty() )
+ while (!m_tags.empty()) {
endElement();
+ }
+ newlineIfNecessary();
}
- XmlWriter& XmlWriter::startElement( std::string const& name ) {
+ XmlWriter& XmlWriter::startElement( std::string const& name, XmlFormatting fmt ) {
ensureTagClosed();
newlineIfNecessary();
- m_os << m_indent << '<' << name;
+ if (shouldIndent(fmt)) {
+ m_os << m_indent;
+ m_indent += " ";
+ }
+ m_os << '<' << name;
m_tags.push_back( name );
- m_indent += " ";
m_tagIsOpen = true;
+ applyFormatting(fmt);
return *this;
}
- XmlWriter::ScopedElement XmlWriter::scopedElement( std::string const& name ) {
- ScopedElement scoped( this );
- startElement( name );
+ XmlWriter::ScopedElement XmlWriter::scopedElement( std::string const& name, XmlFormatting fmt ) {
+ ScopedElement scoped( this, fmt );
+ startElement( name, fmt );
return scoped;
}
- XmlWriter& XmlWriter::endElement() {
- newlineIfNecessary();
- m_indent = m_indent.substr( 0, m_indent.size()-2 );
+ XmlWriter& XmlWriter::endElement(XmlFormatting fmt) {
+ m_indent = m_indent.substr(0, m_indent.size() - 2);
+
if( m_tagIsOpen ) {
m_os << "/>";
m_tagIsOpen = false;
+ } else {
+ newlineIfNecessary();
+ if (shouldIndent(fmt)) {
+ m_os << m_indent;
+ }
+ m_os << "</" << m_tags.back() << ">";
}
- else {
- m_os << m_indent << "</" << m_tags.back() << ">";
- }
- m_os << std::endl;
+ m_os << std::flush;
+ applyFormatting(fmt);
m_tags.pop_back();
return *this;
}
@@ -237,22 +276,26 @@ namespace {
return *this;
}
- XmlWriter& XmlWriter::writeText( std::string const& text, bool indent ) {
+ XmlWriter& XmlWriter::writeText( std::string const& text, XmlFormatting fmt) {
if( !text.empty() ){
bool tagWasOpen = m_tagIsOpen;
ensureTagClosed();
- if( tagWasOpen && indent )
+ if (tagWasOpen && shouldIndent(fmt)) {
m_os << m_indent;
+ }
m_os << XmlEncode( text );
- m_needsNewline = true;
+ applyFormatting(fmt);
}
return *this;
}
- XmlWriter& XmlWriter::writeComment( std::string const& text ) {
+ XmlWriter& XmlWriter::writeComment( std::string const& text, XmlFormatting fmt) {
ensureTagClosed();
- m_os << m_indent << "<!--" << text << "-->";
- m_needsNewline = true;
+ if (shouldIndent(fmt)) {
+ m_os << m_indent;
+ }
+ m_os << "<!--" << text << "-->";
+ applyFormatting(fmt);
return *this;
}
@@ -268,11 +311,16 @@ namespace {
void XmlWriter::ensureTagClosed() {
if( m_tagIsOpen ) {
- m_os << ">" << std::endl;
+ m_os << '>' << std::flush;
+ newlineIfNecessary();
m_tagIsOpen = false;
}
}
+ void XmlWriter::applyFormatting(XmlFormatting fmt) {
+ m_needsNewline = shouldNewline(fmt);
+ }
+
void XmlWriter::writeDeclaration() {
m_os << "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n";
}
diff --git a/include/internal/catch_xmlwriter.h b/include/internal/catch_xmlwriter.h
index c4b1c035..f551b233 100644
--- a/include/internal/catch_xmlwriter.h
+++ b/include/internal/catch_xmlwriter.h
@@ -14,6 +14,14 @@
#include <vector>
namespace Catch {
+ enum class XmlFormatting {
+ None = 0x00,
+ Indent = 0x01,
+ Newline = 0x02,
+ };
+
+ XmlFormatting operator | (XmlFormatting lhs, XmlFormatting rhs);
+ XmlFormatting operator & (XmlFormatting lhs, XmlFormatting rhs);
class XmlEncode {
public:
@@ -35,14 +43,14 @@ namespace Catch {
class ScopedElement {
public:
- ScopedElement( XmlWriter* writer );
+ ScopedElement( XmlWriter* writer, XmlFormatting fmt );
ScopedElement( ScopedElement&& other ) noexcept;
ScopedElement& operator=( ScopedElement&& other ) noexcept;
~ScopedElement();
- ScopedElement& writeText( std::string const& text, bool indent = true );
+ ScopedElement& writeText( std::string const& text, XmlFormatting fmt = XmlFormatting::Newline | XmlFormatting::Indent );
template<typename T>
ScopedElement& writeAttribute( std::string const& name, T const& attribute ) {
@@ -52,6 +60,7 @@ namespace Catch {
private:
mutable XmlWriter* m_writer = nullptr;
+ XmlFormatting m_fmt;
};
XmlWriter( std::ostream& os = Catch::cout() );
@@ -60,11 +69,11 @@ namespace Catch {
XmlWriter( XmlWriter const& ) = delete;
XmlWriter& operator=( XmlWriter const& ) = delete;
- XmlWriter& startElement( std::string const& name );
+ XmlWriter& startElement( std::string const& name, XmlFormatting fmt = XmlFormatting::Newline | XmlFormatting::Indent);
- ScopedElement scopedElement( std::string const& name );
+ ScopedElement scopedElement( std::string const& name, XmlFormatting fmt = XmlFormatting::Newline | XmlFormatting::Indent);
- XmlWriter& endElement();
+ XmlWriter& endElement(XmlFormatting fmt = XmlFormatting::Newline | XmlFormatting::Indent);
XmlWriter& writeAttribute( std::string const& name, std::string const& attribute );
@@ -77,9 +86,9 @@ namespace Catch {
return writeAttribute( name, rss.str() );
}
- XmlWriter& writeText( std::string const& text, bool indent = true );
+ XmlWriter& writeText( std::string const& text, XmlFormatting fmt = XmlFormatting::Newline | XmlFormatting::Indent);
- XmlWriter& writeComment( std::string const& text );
+ XmlWriter& writeComment(std::string const& text, XmlFormatting fmt = XmlFormatting::Newline | XmlFormatting::Indent);
void writeStylesheetRef( std::string const& url );
@@ -89,6 +98,8 @@ namespace Catch {
private:
+ void applyFormatting(XmlFormatting fmt);
+
void writeDeclaration();
void newlineIfNecessary();
diff --git a/include/reporters/catch_reporter_bases.hpp b/include/reporters/catch_reporter_bases.hpp
index a9b0640c..66a891ff 100644
--- a/include/reporters/catch_reporter_bases.hpp
+++ b/include/reporters/catch_reporter_bases.hpp
@@ -51,6 +51,8 @@ namespace Catch {
void noMatchingTestCases(std::string const&) override {}
+ void reportInvalidArguments(std::string const&) override {}
+
void testRunStarting(TestRunInfo const& _testRunInfo) override {
currentTestRunInfo = _testRunInfo;
}
@@ -277,4 +279,4 @@ namespace Catch {
} // end namespace Catch
-#endif // TWOBLUECUBES_CATCH_REPORTER_BASES_HPP_INCLUDED
+#endif // TWOBLUECUBES_CATCH_REPORTER_BASES_HPP_INCLUDED \ No newline at end of file
diff --git a/include/reporters/catch_reporter_compact.cpp b/include/reporters/catch_reporter_compact.cpp
index 65f70266..017f521f 100644
--- a/include/reporters/catch_reporter_compact.cpp
+++ b/include/reporters/catch_reporter_compact.cpp
@@ -8,7 +8,7 @@
#include "catch_reporter_compact.h"
#include "../internal/catch_reporter_registrars.hpp"
-#include "internal/catch_console_colour.h"
+#include "../internal/catch_console_colour.h"
namespace {
@@ -209,24 +209,25 @@ private:
if (itMessage == messages.end())
return;
- // using messages.end() directly yields (or auto) compilation error:
- std::vector<MessageInfo>::const_iterator itEnd = messages.end();
- const std::size_t N = static_cast<std::size_t>(std::distance(itMessage, itEnd));
+ const auto itEnd = messages.cend();
+ const auto N = static_cast<std::size_t>(std::distance(itMessage, itEnd));
{
Colour colourGuard(colour);
stream << " with " << pluralise(N, "message") << ':';
}
- for (; itMessage != itEnd; ) {
+ while (itMessage != itEnd) {
// If this assertion is a warning ignore any INFO messages
if (printInfoMessages || itMessage->type != ResultWas::Info) {
- stream << " '" << itMessage->message << '\'';
- if (++itMessage != itEnd) {
+ printMessage();
+ if (itMessage != itEnd) {
Colour colourGuard(dimColour());
stream << " and";
}
+ continue;
}
+ ++itMessage;
}
}
diff --git a/include/reporters/catch_reporter_console.cpp b/include/reporters/catch_reporter_console.cpp
index 53b977eb..706f93f8 100644
--- a/include/reporters/catch_reporter_console.cpp
+++ b/include/reporters/catch_reporter_console.cpp
@@ -9,7 +9,7 @@
#include "catch_reporter_console.h"
#include "../internal/catch_reporter_registrars.hpp"
-#include "internal/catch_console_colour.h"
+#include "../internal/catch_console_colour.h"
#include "../internal/catch_version.h"
#include "../internal/catch_text.h"
#include "../internal/catch_stringref.h"
@@ -20,11 +20,17 @@
#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
+
+#if defined(__clang__)
+# pragma clang diagnostic push
+// For simplicity, benchmarking-only helpers are always enabled
+# pragma clang diagnostic ignored "-Wunused-function"
#endif
+
namespace Catch {
namespace {
@@ -204,11 +210,11 @@ class Duration {
static const uint64_t s_nanosecondsInASecond = 1000 * s_nanosecondsInAMillisecond;
static const uint64_t s_nanosecondsInAMinute = 60 * s_nanosecondsInASecond;
- uint64_t m_inNanoseconds;
+ double m_inNanoseconds;
Unit m_units;
public:
- explicit Duration(uint64_t inNanoseconds, Unit units = Unit::Auto)
+ explicit Duration(double inNanoseconds, Unit units = Unit::Auto)
: m_inNanoseconds(inNanoseconds),
m_units(units) {
if (m_units == Unit::Auto) {
@@ -237,7 +243,7 @@ public:
case Unit::Minutes:
return m_inNanoseconds / static_cast<double>(s_nanosecondsInAMinute);
default:
- return static_cast<double>(m_inNanoseconds);
+ return m_inNanoseconds;
}
}
auto unitsAsString() const -> std::string {
@@ -258,7 +264,7 @@ public:
}
friend auto operator << (std::ostream& os, Duration const& duration) -> std::ostream& {
- return os << duration.value() << " " << duration.unitsAsString();
+ return os << duration.value() << ' ' << duration.unitsAsString();
}
};
} // end anon namespace
@@ -283,10 +289,16 @@ public:
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";
+
+ Columns headerCols;
+ Spacer spacer(2);
+ for (auto const& info : m_columnInfos) {
+ headerCols += Column(info.name).width(static_cast<std::size_t>(info.width - 2));
+ headerCols += spacer;
+ }
+ m_os << headerCols << '\n';
+
+ m_os << Catch::getLineOfChars<'-'>() << '\n';
}
}
void close() {
@@ -305,30 +317,29 @@ public:
friend TablePrinter& operator << (TablePrinter& tp, ColumnBreak) {
auto colStr = tp.m_oss.str();
- // This takes account of utf8 encodings
- auto strSize = Catch::StringRef(colStr).numberOfCharacters();
+ const auto strSize = colStr.size();
tp.m_oss.str("");
tp.open();
if (tp.m_currentColumn == static_cast<int>(tp.m_columnInfos.size() - 1)) {
tp.m_currentColumn = -1;
- tp.m_os << "\n";
+ tp.m_os << '\n';
}
tp.m_currentColumn++;
auto colInfo = tp.m_columnInfos[tp.m_currentColumn];
- auto padding = (strSize + 2 < static_cast<std::size_t>(colInfo.width))
- ? std::string(colInfo.width - (strSize + 2), ' ')
+ auto padding = (strSize + 1 < static_cast<std::size_t>(colInfo.width))
+ ? std::string(colInfo.width - (strSize + 1), ' ')
: std::string();
if (colInfo.justification == ColumnInfo::Left)
- tp.m_os << colStr << padding << " ";
+ tp.m_os << colStr << padding << ' ';
else
- tp.m_os << padding << colStr << " ";
+ tp.m_os << padding << colStr << ' ';
return tp;
}
friend TablePrinter& operator << (TablePrinter& tp, RowBreak) {
if (tp.m_currentColumn > 0) {
- tp.m_os << "\n";
+ tp.m_os << '\n';
tp.m_currentColumn = -1;
}
return tp;
@@ -338,12 +349,26 @@ public:
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 }
- })) {}
+ [&config]() -> std::vector<ColumnInfo> {
+ if (config.fullConfig()->benchmarkNoAnalysis())
+ {
+ return{
+ { "benchmark name", CATCH_CONFIG_CONSOLE_WIDTH - 43, ColumnInfo::Left },
+ { " samples", 14, ColumnInfo::Right },
+ { " iterations", 14, ColumnInfo::Right },
+ { " mean", 14, ColumnInfo::Right }
+ };
+ }
+ else
+ {
+ return{
+ { "benchmark name", CATCH_CONFIG_CONSOLE_WIDTH - 32, ColumnInfo::Left },
+ { "samples mean std dev", 14, ColumnInfo::Right },
+ { "iterations low mean low std dev", 14, ColumnInfo::Right },
+ { "estimated high mean high std dev", 14, ColumnInfo::Right }
+ };
+ }
+ }())) {}
ConsoleReporter::~ConsoleReporter() = default;
std::string ConsoleReporter::getDescription() {
@@ -354,6 +379,10 @@ void ConsoleReporter::noMatchingTestCases(std::string const& spec) {
stream << "No test cases matched '" << spec << '\'' << std::endl;
}
+void ConsoleReporter::reportInvalidArguments(std::string const&arg){
+ stream << "Invalid Filter: " << arg << std::endl;
+}
+
void ConsoleReporter::assertionStarting(AssertionInfo const&) {}
bool ConsoleReporter::assertionEnded(AssertionStats const& _assertionStats) {
@@ -374,6 +403,7 @@ bool ConsoleReporter::assertionEnded(AssertionStats const& _assertionStats) {
}
void ConsoleReporter::sectionStarting(SectionInfo const& _sectionInfo) {
+ m_tablePrinter->close();
m_headerPrinted = false;
StreamingReporterBase::sectionStarting(_sectionInfo);
}
@@ -397,29 +427,53 @@ void ConsoleReporter::sectionEnded(SectionStats const& _sectionStats) {
StreamingReporterBase::sectionEnded(_sectionStats);
}
+#if defined(CATCH_CONFIG_ENABLE_BENCHMARKING)
+void ConsoleReporter::benchmarkPreparing(std::string const& name) {
+ lazyPrintWithoutClosingBenchmarkTable();
-void ConsoleReporter::benchmarkStarting(BenchmarkInfo const& info) {
- lazyPrintWithoutClosingBenchmarkTable();
+ auto nameCol = Column(name).width(static_cast<std::size_t>(m_tablePrinter->columnInfos()[0].width - 2));
- auto nameCol = Column( info.name ).width( static_cast<std::size_t>( m_tablePrinter->columnInfos()[0].width - 2 ) );
+ bool firstLine = true;
+ for (auto line : nameCol) {
+ if (!firstLine)
+ (*m_tablePrinter) << ColumnBreak() << ColumnBreak() << ColumnBreak();
+ else
+ firstLine = false;
- bool firstLine = true;
- for (auto line : nameCol) {
- if (!firstLine)
- (*m_tablePrinter) << ColumnBreak() << ColumnBreak() << ColumnBreak();
- else
- firstLine = false;
+ (*m_tablePrinter) << line << ColumnBreak();
+ }
+}
- (*m_tablePrinter) << line << ColumnBreak();
+void ConsoleReporter::benchmarkStarting(BenchmarkInfo const& info) {
+ (*m_tablePrinter) << info.samples << ColumnBreak()
+ << info.iterations << ColumnBreak();
+ if (!m_config->benchmarkNoAnalysis())
+ (*m_tablePrinter) << Duration(info.estimatedDuration) << ColumnBreak();
+}
+void ConsoleReporter::benchmarkEnded(BenchmarkStats<> const& stats) {
+ if (m_config->benchmarkNoAnalysis())
+ {
+ (*m_tablePrinter) << Duration(stats.mean.point.count()) << ColumnBreak();
+ }
+ else
+ {
+ (*m_tablePrinter) << ColumnBreak()
+ << Duration(stats.mean.point.count()) << ColumnBreak()
+ << Duration(stats.mean.lower_bound.count()) << ColumnBreak()
+ << Duration(stats.mean.upper_bound.count()) << ColumnBreak() << ColumnBreak()
+ << Duration(stats.standardDeviation.point.count()) << ColumnBreak()
+ << Duration(stats.standardDeviation.lower_bound.count()) << ColumnBreak()
+ << Duration(stats.standardDeviation.upper_bound.count()) << ColumnBreak() << ColumnBreak() << ColumnBreak() << ColumnBreak() << ColumnBreak();
}
}
-void ConsoleReporter::benchmarkEnded(BenchmarkStats const& stats) {
- Duration average(stats.elapsedTimeInNanoseconds / stats.iterations);
+
+void ConsoleReporter::benchmarkFailed(std::string const& error) {
+ Colour colour(Colour::Red);
(*m_tablePrinter)
- << stats.iterations << ColumnBreak()
- << stats.elapsedTimeInNanoseconds << ColumnBreak()
- << average << ColumnBreak();
+ << "Benchmark failed (" << error << ')'
+ << ColumnBreak() << RowBreak();
}
+#endif // CATCH_CONFIG_ENABLE_BENCHMARKING
void ConsoleReporter::testCaseEnded(TestCaseStats const& _testCaseStats) {
m_tablePrinter->close();
@@ -498,11 +552,10 @@ void ConsoleReporter::printTestCaseAndSectionHeader() {
SourceLineInfo lineInfo = m_sectionStack.back().lineInfo;
- if (!lineInfo.empty()) {
- stream << getLineOfChars<'-'>() << '\n';
- Colour colourGuard(Colour::FileName);
- stream << lineInfo << '\n';
- }
+
+ stream << getLineOfChars<'-'>() << '\n';
+ Colour colourGuard(Colour::FileName);
+ stream << lineInfo << '\n';
stream << getLineOfChars<'.'>() << '\n' << std::endl;
}
@@ -627,8 +680,10 @@ void ConsoleReporter::printSummaryDivider() {
}
void ConsoleReporter::printTestFilters() {
- if (m_config->testSpec().hasFilters())
- stream << Colour(Colour::BrightYellow) << "Filters: " << serializeFilters( m_config->getTestsOrTags() ) << '\n';
+ if (m_config->testSpec().hasFilters()) {
+ Colour guard(Colour::BrightYellow);
+ stream << "Filters: " << serializeFilters(m_config->getTestsOrTags()) << '\n';
+ }
}
CATCH_REGISTER_REPORTER("console", ConsoleReporter)
@@ -638,3 +693,7 @@ CATCH_REGISTER_REPORTER("console", ConsoleReporter)
#if defined(_MSC_VER)
#pragma warning(pop)
#endif
+
+#if defined(__clang__)
+# pragma clang diagnostic pop
+#endif
diff --git a/include/reporters/catch_reporter_console.h b/include/reporters/catch_reporter_console.h
index effa58d3..43024daf 100644
--- a/include/reporters/catch_reporter_console.h
+++ b/include/reporters/catch_reporter_console.h
@@ -32,6 +32,8 @@ namespace Catch {
void noMatchingTestCases(std::string const& spec) override;
+ void reportInvalidArguments(std::string const&arg) override;
+
void assertionStarting(AssertionInfo const&) override;
bool assertionEnded(AssertionStats const& _assertionStats) override;
@@ -39,9 +41,12 @@ namespace Catch {
void sectionStarting(SectionInfo const& _sectionInfo) override;
void sectionEnded(SectionStats const& _sectionStats) override;
-
+#if defined(CATCH_CONFIG_ENABLE_BENCHMARKING)
+ void benchmarkPreparing(std::string const& name) override;
void benchmarkStarting(BenchmarkInfo const& info) override;
- void benchmarkEnded(BenchmarkStats const& stats) override;
+ void benchmarkEnded(BenchmarkStats<> const& stats) override;
+ void benchmarkFailed(std::string const& error) override;
+#endif // CATCH_CONFIG_ENABLE_BENCHMARKING
void testCaseEnded(TestCaseStats const& _testCaseStats) override;
void testGroupEnded(TestGroupStats const& _testGroupStats) override;
@@ -81,4 +86,4 @@ namespace Catch {
#pragma warning(pop)
#endif
-#endif // TWOBLUECUBES_CATCH_REPORTER_CONSOLE_H_INCLUDED
+#endif // TWOBLUECUBES_CATCH_REPORTER_CONSOLE_H_INCLUDED \ No newline at end of file
diff --git a/include/reporters/catch_reporter_junit.cpp b/include/reporters/catch_reporter_junit.cpp
index e8375862..7416a523 100644
--- a/include/reporters/catch_reporter_junit.cpp
+++ b/include/reporters/catch_reporter_junit.cpp
@@ -12,6 +12,7 @@
#include "../internal/catch_tostring.h"
#include "../internal/catch_reporter_registrars.hpp"
+#include "../internal/catch_text.h"
#include <cassert>
#include <sstream>
@@ -146,8 +147,8 @@ namespace Catch {
for( auto const& child : groupNode.children )
writeTestCase( *child );
- xml.scopedElement( "system-out" ).writeText( trim( stdOutForSuite ), false );
- xml.scopedElement( "system-err" ).writeText( trim( stdErrForSuite ), false );
+ xml.scopedElement( "system-out" ).writeText( trim( stdOutForSuite ), XmlFormatting::Newline );
+ xml.scopedElement( "system-err" ).writeText( trim( stdErrForSuite ), XmlFormatting::Newline );
}
void JunitReporter::writeTestCase( TestCaseNode const& testCaseNode ) {
@@ -196,9 +197,9 @@ namespace Catch {
writeAssertions( sectionNode );
if( !sectionNode.stdOut.empty() )
- xml.scopedElement( "system-out" ).writeText( trim( sectionNode.stdOut ), false );
+ xml.scopedElement( "system-out" ).writeText( trim( sectionNode.stdOut ), XmlFormatting::Newline );
if( !sectionNode.stdErr.empty() )
- xml.scopedElement( "system-err" ).writeText( trim( sectionNode.stdErr ), false );
+ xml.scopedElement( "system-err" ).writeText( trim( sectionNode.stdErr ), XmlFormatting::Newline );
}
for( auto const& childNode : sectionNode.childSections )
if( className.empty() )
@@ -222,11 +223,7 @@ namespace Catch {
elementName = "error";
break;
case ResultWas::ExplicitFailure:
- elementName = "failure";
- break;
case ResultWas::ExpressionFailed:
- elementName = "failure";
- break;
case ResultWas::DidntThrowException:
elementName = "failure";
break;
@@ -244,10 +241,25 @@ namespace Catch {
XmlWriter::ScopedElement e = xml.scopedElement( elementName );
- xml.writeAttribute( "message", result.getExpandedExpression() );
+ xml.writeAttribute( "message", result.getExpression() );
xml.writeAttribute( "type", result.getTestMacroName() );
ReusableStringStream rss;
+ if (stats.totals.assertions.total() > 0) {
+ rss << "FAILED" << ":\n";
+ if (result.hasExpression()) {
+ rss << " ";
+ rss << result.getExpressionInMacro();
+ rss << '\n';
+ }
+ if (result.hasExpandedExpression()) {
+ rss << "with expansion:\n";
+ rss << Column(result.getExpandedExpression()).indent(2) << '\n';
+ }
+ } else {
+ rss << '\n';
+ }
+
if( !result.getMessage().empty() )
rss << result.getMessage() << '\n';
for( auto const& msg : stats.infoMessages )
@@ -255,7 +267,7 @@ namespace Catch {
rss << msg.message << '\n';
rss << "at " << result.getSourceInfo();
- xml.writeText( rss.str(), false );
+ xml.writeText( rss.str(), XmlFormatting::Newline );
}
}
diff --git a/include/reporters/catch_reporter_listening.cpp b/include/reporters/catch_reporter_listening.cpp
index 9ddae2f2..91e6b39a 100644
--- a/include/reporters/catch_reporter_listening.cpp
+++ b/include/reporters/catch_reporter_listening.cpp
@@ -41,20 +41,42 @@ namespace Catch {
}
m_reporter->noMatchingTestCases( spec );
}
-
+
+ void ListeningReporter::reportInvalidArguments(std::string const&arg){
+ for ( auto const& listener : m_listeners ) {
+ listener->reportInvalidArguments( arg );
+ }
+ m_reporter->reportInvalidArguments( arg );
+ }
+
+#if defined(CATCH_CONFIG_ENABLE_BENCHMARKING)
+ void ListeningReporter::benchmarkPreparing( std::string const& name ) {
+ for (auto const& listener : m_listeners) {
+ listener->benchmarkPreparing(name);
+ }
+ m_reporter->benchmarkPreparing(name);
+ }
void ListeningReporter::benchmarkStarting( BenchmarkInfo const& benchmarkInfo ) {
for ( auto const& listener : m_listeners ) {
listener->benchmarkStarting( benchmarkInfo );
}
m_reporter->benchmarkStarting( benchmarkInfo );
}
- void ListeningReporter::benchmarkEnded( BenchmarkStats const& benchmarkStats ) {
+ void ListeningReporter::benchmarkEnded( BenchmarkStats<> const& benchmarkStats ) {
for ( auto const& listener : m_listeners ) {
listener->benchmarkEnded( benchmarkStats );
}
m_reporter->benchmarkEnded( benchmarkStats );
}
+ void ListeningReporter::benchmarkFailed( std::string const& error ) {
+ for (auto const& listener : m_listeners) {
+ listener->benchmarkFailed(error);
+ }
+ m_reporter->benchmarkFailed(error);
+ }
+#endif // CATCH_CONFIG_ENABLE_BENCHMARKING
+
void ListeningReporter::testRunStarting( TestRunInfo const& testRunInfo ) {
for ( auto const& listener : m_listeners ) {
listener->testRunStarting( testRunInfo );
@@ -139,4 +161,4 @@ namespace Catch {
return true;
}
-} // end namespace Catch
+} // end namespace Catch \ No newline at end of file
diff --git a/include/reporters/catch_reporter_listening.h b/include/reporters/catch_reporter_listening.h
index dddd7a51..bfaa3085 100644
--- a/include/reporters/catch_reporter_listening.h
+++ b/include/reporters/catch_reporter_listening.h
@@ -28,11 +28,17 @@ namespace Catch {
ReporterPreferences getPreferences() const override;
void noMatchingTestCases( std::string const& spec ) override;
-
+
+ void reportInvalidArguments(std::string const&arg) override;
+
static std::set<Verbosity> getSupportedVerbosities();
+#if defined(CATCH_CONFIG_ENABLE_BENCHMARKING)
+ void benchmarkPreparing(std::string const& name) override;
void benchmarkStarting( BenchmarkInfo const& benchmarkInfo ) override;
- void benchmarkEnded( BenchmarkStats const& benchmarkStats ) override;
+ void benchmarkEnded( BenchmarkStats<> const& benchmarkStats ) override;
+ void benchmarkFailed(std::string const&) override;
+#endif // CATCH_CONFIG_ENABLE_BENCHMARKING
void testRunStarting( TestRunInfo const& testRunInfo ) override;
void testGroupStarting( GroupInfo const& groupInfo ) override;
@@ -54,4 +60,4 @@ namespace Catch {
} // end namespace Catch
-#endif // TWOBLUECUBES_CATCH_MULTI_REPORTER_H_INCLUDED
+#endif // TWOBLUECUBES_CATCH_MULTI_REPORTER_H_INCLUDED \ No newline at end of file
diff --git a/include/reporters/catch_reporter_sonarqube.hpp b/include/reporters/catch_reporter_sonarqube.hpp
new file mode 100644
index 00000000..bf7d9299
--- /dev/null
+++ b/include/reporters/catch_reporter_sonarqube.hpp
@@ -0,0 +1,181 @@
+/*
+ * Created by Daniel Garcia on 2018-12-04.
+ * Copyright Social Point SL. 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 CATCH_REPORTER_SONARQUBE_HPP_INCLUDED
+#define CATCH_REPORTER_SONARQUBE_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 <map>
+
+namespace Catch {
+
+ struct SonarQubeReporter : CumulativeReporterBase<SonarQubeReporter> {
+
+ SonarQubeReporter(ReporterConfig const& config)
+ : CumulativeReporterBase(config)
+ , xml(config.stream()) {
+ m_reporterPrefs.shouldRedirectStdOut = true;
+ m_reporterPrefs.shouldReportAllAssertions = true;
+ }
+
+ ~SonarQubeReporter() override;
+
+ static std::string getDescription() {
+ return "Reports test results in the Generic Test Data SonarQube XML format";
+ }
+
+ static std::set<Verbosity> getSupportedVerbosities() {
+ return { Verbosity::Normal };
+ }
+
+ void noMatchingTestCases(std::string const& /*spec*/) override {}
+
+ void testRunStarting(TestRunInfo const& testRunInfo) override {
+ CumulativeReporterBase::testRunStarting(testRunInfo);
+ xml.startElement("testExecutions");
+ xml.writeAttribute("version", "1");
+ }
+
+ void testGroupEnded(TestGroupStats const& testGroupStats) override {
+ CumulativeReporterBase::testGroupEnded(testGroupStats);
+ writeGroup(*m_testGroups.back());
+ }
+
+ void testRunEndedCumulative() override {
+ xml.endElement();
+ }
+
+ void writeGroup(TestGroupNode const& groupNode) {
+ std::map<std::string, TestGroupNode::ChildNodes> testsPerFile;
+ for(auto const& child : groupNode.children)
+ testsPerFile[child->value.testInfo.lineInfo.file].push_back(child);
+
+ for(auto const& kv : testsPerFile)
+ writeTestFile(kv.first.c_str(), kv.second);
+ }
+
+ void writeTestFile(const char* filename, TestGroupNode::ChildNodes const& testCaseNodes) {
+ XmlWriter::ScopedElement e = xml.scopedElement("file");
+ xml.writeAttribute("path", filename);
+
+ for(auto const& child : testCaseNodes)
+ writeTestCase(*child);
+ }
+
+ void writeTestCase(TestCaseNode const& testCaseNode) {
+ // 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();
+ writeSection("", rootSection, testCaseNode.value.testInfo.okToFail());
+ }
+
+ void writeSection(std::string const& rootName, SectionNode const& sectionNode, bool okToFail) {
+ 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");
+ xml.writeAttribute("name", name);
+ xml.writeAttribute("duration", static_cast<long>(sectionNode.stats.durationInSeconds * 1000));
+
+ writeAssertions(sectionNode, okToFail);
+ }
+
+ for(auto const& childNode : sectionNode.childSections)
+ writeSection(name, *childNode, okToFail);
+ }
+
+ void writeAssertions(SectionNode const& sectionNode, bool okToFail) {
+ for(auto const& assertion : sectionNode.assertions)
+ writeAssertion( assertion, okToFail);
+ }
+
+ void writeAssertion(AssertionStats const& stats, bool okToFail) {
+ AssertionResult const& result = stats.assertionResult;
+ if(!result.isOk()) {
+ std::string elementName;
+ if(okToFail) {
+ elementName = "skipped";
+ }
+ else {
+ 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);
+
+ ReusableStringStream messageRss;
+ messageRss << result.getTestMacroName() << "(" << result.getExpression() << ")";
+ xml.writeAttribute("message", messageRss.str());
+
+ ReusableStringStream textRss;
+ if (stats.totals.assertions.total() > 0) {
+ textRss << "FAILED:\n";
+ if (result.hasExpression()) {
+ textRss << "\t" << result.getExpressionInMacro() << "\n";
+ }
+ if (result.hasExpandedExpression()) {
+ textRss << "with expansion:\n\t" << result.getExpandedExpression() << "\n";
+ }
+ }
+
+ if(!result.getMessage().empty())
+ textRss << result.getMessage() << "\n";
+
+ for(auto const& msg : stats.infoMessages)
+ if(msg.type == ResultWas::Info)
+ textRss << msg.message << "\n";
+
+ textRss << "at " << result.getSourceInfo();
+ xml.writeText(textRss.str(), XmlFormatting::Newline);
+ }
+ }
+
+ private:
+ XmlWriter xml;
+ };
+
+#ifdef CATCH_IMPL
+ SonarQubeReporter::~SonarQubeReporter() {}
+#endif
+
+ CATCH_REGISTER_REPORTER( "sonarqube", SonarQubeReporter )
+
+} // end namespace Catch
+
+#endif // CATCH_REPORTER_SONARQUBE_HPP_INCLUDED \ No newline at end of file
diff --git a/include/reporters/catch_reporter_teamcity.hpp b/include/reporters/catch_reporter_teamcity.hpp
index eca2885c..47b7e4aa 100644
--- a/include/reporters/catch_reporter_teamcity.hpp
+++ b/include/reporters/catch_reporter_teamcity.hpp
@@ -183,8 +183,7 @@ namespace Catch {
SourceLineInfo lineInfo = m_sectionStack.front().lineInfo;
- if( !lineInfo.empty() )
- os << lineInfo << "\n";
+ os << lineInfo << "\n";
os << getLineOfChars<'.'>() << "\n\n";
}
diff --git a/include/reporters/catch_reporter_xml.cpp b/include/reporters/catch_reporter_xml.cpp
index c7572d1e..0fb78be0 100644
--- a/include/reporters/catch_reporter_xml.cpp
+++ b/include/reporters/catch_reporter_xml.cpp
@@ -193,9 +193,9 @@ namespace Catch {
e.writeAttribute( "durationInSeconds", m_testCaseTimer.getElapsedSeconds() );
if( !testCaseStats.stdOut.empty() )
- m_xml.scopedElement( "StdOut" ).writeText( trim( testCaseStats.stdOut ), false );
+ m_xml.scopedElement( "StdOut" ).writeText( trim( testCaseStats.stdOut ), XmlFormatting::Newline );
if( !testCaseStats.stdErr.empty() )
- m_xml.scopedElement( "StdErr" ).writeText( trim( testCaseStats.stdErr ), false );
+ m_xml.scopedElement( "StdErr" ).writeText( trim( testCaseStats.stdErr ), XmlFormatting::Newline );
m_xml.endElement();
}
@@ -219,6 +219,51 @@ namespace Catch {
m_xml.endElement();
}
+#if defined(CATCH_CONFIG_ENABLE_BENCHMARKING)
+ void XmlReporter::benchmarkPreparing(std::string const& name) {
+ m_xml.startElement("BenchmarkResults")
+ .writeAttribute("name", name);
+ }
+
+ void XmlReporter::benchmarkStarting(BenchmarkInfo const &info) {
+ m_xml.writeAttribute("samples", info.samples)
+ .writeAttribute("resamples", info.resamples)
+ .writeAttribute("iterations", info.iterations)
+ .writeAttribute("clockResolution", info.clockResolution)
+ .writeAttribute("estimatedDuration", info.estimatedDuration)
+ .writeComment("All values in nano seconds");
+ }
+
+ void XmlReporter::benchmarkEnded(BenchmarkStats<> const& benchmarkStats) {
+ m_xml.startElement("mean")
+ .writeAttribute("value", benchmarkStats.mean.point.count())
+ .writeAttribute("lowerBound", benchmarkStats.mean.lower_bound.count())
+ .writeAttribute("upperBound", benchmarkStats.mean.upper_bound.count())
+ .writeAttribute("ci", benchmarkStats.mean.confidence_interval);
+ m_xml.endElement();
+ m_xml.startElement("standardDeviation")
+ .writeAttribute("value", benchmarkStats.standardDeviation.point.count())
+ .writeAttribute("lowerBound", benchmarkStats.standardDeviation.lower_bound.count())
+ .writeAttribute("upperBound", benchmarkStats.standardDeviation.upper_bound.count())
+ .writeAttribute("ci", benchmarkStats.standardDeviation.confidence_interval);
+ m_xml.endElement();
+ m_xml.startElement("outliers")
+ .writeAttribute("variance", benchmarkStats.outlierVariance)
+ .writeAttribute("lowMild", benchmarkStats.outliers.low_mild)
+ .writeAttribute("lowSevere", benchmarkStats.outliers.low_severe)
+ .writeAttribute("highMild", benchmarkStats.outliers.high_mild)
+ .writeAttribute("highSevere", benchmarkStats.outliers.high_severe);
+ m_xml.endElement();
+ m_xml.endElement();
+ }
+
+ void XmlReporter::benchmarkFailed(std::string const &error) {
+ m_xml.scopedElement("failed").
+ writeAttribute("message", error);
+ m_xml.endElement();
+ }
+#endif // CATCH_CONFIG_ENABLE_BENCHMARKING
+
CATCH_REGISTER_REPORTER( "xml", XmlReporter )
} // end namespace Catch
diff --git a/include/reporters/catch_reporter_xml.h b/include/reporters/catch_reporter_xml.h
index 7926f93a..5b6ba310 100644
--- a/include/reporters/catch_reporter_xml.h
+++ b/include/reporters/catch_reporter_xml.h
@@ -50,6 +50,13 @@ namespace Catch {
void testRunEnded(TestRunStats const& testRunStats) override;
+#if defined(CATCH_CONFIG_ENABLE_BENCHMARKING)
+ void benchmarkPreparing(std::string const& name) override;
+ void benchmarkStarting(BenchmarkInfo const&) override;
+ void benchmarkEnded(BenchmarkStats<> const&) override;
+ void benchmarkFailed(std::string const&) override;
+#endif // CATCH_CONFIG_ENABLE_BENCHMARKING
+
private:
Timer m_testCaseTimer;
XmlWriter m_xml;
diff --git a/misc/appveyorMergeCoverageScript.py b/misc/appveyorMergeCoverageScript.py
index a74e6e0e..93a47fff 100644
--- a/misc/appveyorMergeCoverageScript.py
+++ b/misc/appveyorMergeCoverageScript.py
@@ -4,6 +4,6 @@ import glob
import subprocess
if __name__ == '__main__':
- cov_files = list(glob.glob('cov-report*.bin'))
+ cov_files = list(glob.glob('projects/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)
+ subprocess.check_call(base_cmd)
diff --git a/misc/coverage-helper.cpp b/misc/coverage-helper.cpp
index a6643838..a31e927f 100644
--- a/misc/coverage-helper.cpp
+++ b/misc/coverage-helper.cpp
@@ -29,7 +29,8 @@ std::string escape_arg(const std::string& arg) {
escaped.append(num_backslashes * 2, '\\');
break;
} else if (*it == '"') {
- escaped.append(num_backslashes * 2 + 1, '\\');
+ escaped.append((num_backslashes + 1) * 2, '\\');
+ escaped.push_back('"');
escaped.push_back(*it);
} else {
escaped.append(num_backslashes, '\\');
@@ -89,27 +90,30 @@ std::string windowsify_path(std::string path) {
return path;
}
-void exec_cmd(std::string const& cmd, int log_num, std::string const& path) {
+int exec_cmd(std::string const& cmd, int log_num, std::string const& path) {
std::array<char, 128> buffer;
-#if defined(_WIN32)
+
// cmd has already been escaped outside this function.
auto real_cmd = "OpenCppCoverage --export_type binary:cov-report" + std::to_string(log_num)
+ ".bin --quiet " + "--sources " + escape_arg(path) + " --cover_children -- " + cmd;
std::cout << "=== Marker ===: Cmd: " << real_cmd << '\n';
- std::shared_ptr<FILE> 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<FILE> pipe(popen(cmd.c_str(), "r"), pclose);
-#endif
+ auto pipe = _popen(real_cmd.c_str(), "r");
if (!pipe) {
throw std::runtime_error("popen() failed!");
}
- while (!feof(pipe.get())) {
- if (fgets(buffer.data(), 128, pipe.get()) != nullptr) {
+ while (!feof(pipe)) {
+ if (fgets(buffer.data(), 128, pipe) != nullptr) {
std::cout << buffer.data();
}
}
+
+ auto ret = _pclose(pipe);
+ if (ret == -1) {
+ throw std::runtime_error("underlying error in pclose()");
+ }
+
+ return ret;
}
// argv should be:
@@ -124,7 +128,7 @@ int main(int argc, char** argv) {
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 + ' ' + escape_arg(rhs);
});
diff --git a/projects/CMakeLists.txt b/projects/CMakeLists.txt
index 3fbd9b42..0aafc178 100644
--- a/projects/CMakeLists.txt
+++ b/projects/CMakeLists.txt
@@ -17,11 +17,16 @@ endif(MSVC) #Temporary workaround
set(TEST_SOURCES
${SELF_TEST_DIR}/TestMain.cpp
${SELF_TEST_DIR}/IntrospectiveTests/CmdLine.tests.cpp
+ ${SELF_TEST_DIR}/IntrospectiveTests/Details.tests.cpp
${SELF_TEST_DIR}/IntrospectiveTests/GeneratorsImpl.tests.cpp
+ ${SELF_TEST_DIR}/IntrospectiveTests/InternalBenchmark.tests.cpp
${SELF_TEST_DIR}/IntrospectiveTests/PartTracker.tests.cpp
+ ${SELF_TEST_DIR}/IntrospectiveTests/RandomNumberGeneration.tests.cpp
${SELF_TEST_DIR}/IntrospectiveTests/Tag.tests.cpp
${SELF_TEST_DIR}/IntrospectiveTests/String.tests.cpp
+ ${SELF_TEST_DIR}/IntrospectiveTests/StringManip.tests.cpp
${SELF_TEST_DIR}/IntrospectiveTests/Xml.tests.cpp
+ ${SELF_TEST_DIR}/IntrospectiveTests/ToString.tests.cpp
${SELF_TEST_DIR}/UsageTests/Approx.tests.cpp
${SELF_TEST_DIR}/UsageTests/BDD.tests.cpp
${SELF_TEST_DIR}/UsageTests/Benchmark.tests.cpp
@@ -34,6 +39,7 @@ set(TEST_SOURCES
${SELF_TEST_DIR}/UsageTests/Generators.tests.cpp
${SELF_TEST_DIR}/UsageTests/Message.tests.cpp
${SELF_TEST_DIR}/UsageTests/Misc.tests.cpp
+ ${SELF_TEST_DIR}/UsageTests/ToStringByte.tests.cpp
${SELF_TEST_DIR}/UsageTests/ToStringChrono.tests.cpp
${SELF_TEST_DIR}/UsageTests/ToStringGeneral.tests.cpp
${SELF_TEST_DIR}/UsageTests/ToStringOptional.tests.cpp
@@ -78,6 +84,33 @@ CheckFileList(EXTERNAL_HEADERS ${HEADER_DIR}/external)
# Please keep these ordered alphabetically
+set(BENCHMARK_HEADERS
+ ${HEADER_DIR}/internal/benchmark/catch_benchmark.hpp
+ ${HEADER_DIR}/internal/benchmark/catch_chronometer.hpp
+ ${HEADER_DIR}/internal/benchmark/catch_clock.hpp
+ ${HEADER_DIR}/internal/benchmark/catch_constructor.hpp
+ ${HEADER_DIR}/internal/benchmark/catch_environment.hpp
+ ${HEADER_DIR}/internal/benchmark/catch_estimate.hpp
+ ${HEADER_DIR}/internal/benchmark/catch_execution_plan.hpp
+ ${HEADER_DIR}/internal/benchmark/catch_optimizer.hpp
+ ${HEADER_DIR}/internal/benchmark/catch_outlier_classification.hpp
+ ${HEADER_DIR}/internal/benchmark/catch_sample_analysis.hpp
+ ${HEADER_DIR}/internal/benchmark/detail/catch_analyse.hpp
+ ${HEADER_DIR}/internal/benchmark/detail/catch_benchmark_function.hpp
+ ${HEADER_DIR}/internal/benchmark/detail/catch_complete_invoke.hpp
+ ${HEADER_DIR}/internal/benchmark/detail/catch_estimate_clock.hpp
+ ${HEADER_DIR}/internal/benchmark/detail/catch_measure.hpp
+ ${HEADER_DIR}/internal/benchmark/detail/catch_repeat.hpp
+ ${HEADER_DIR}/internal/benchmark/detail/catch_run_for_at_least.hpp
+ ${HEADER_DIR}/internal/benchmark/detail/catch_stats.hpp
+ ${HEADER_DIR}/internal/benchmark/detail/catch_timing.hpp
+)
+set(BENCHMARK_SOURCES
+ ${HEADER_DIR}/internal/benchmark/detail/catch_stats.cpp
+)
+
+SOURCE_GROUP("benchmark" FILES ${BENCHMARK_HEADERS} ${BENCHMARK_SOURCES})
+
set(INTERNAL_HEADERS
${HEADER_DIR}/internal/catch_approx.h
${HEADER_DIR}/internal/catch_assertionhandler.h
@@ -97,6 +130,7 @@ set(INTERNAL_HEADERS
${HEADER_DIR}/internal/catch_decomposer.h
${HEADER_DIR}/internal/catch_default_main.hpp
${HEADER_DIR}/internal/catch_enforce.h
+ ${HEADER_DIR}/internal/catch_enum_values_registry.h
${HEADER_DIR}/internal/catch_errno_guard.h
${HEADER_DIR}/internal/catch_exception_translator_registry.h
${HEADER_DIR}/internal/catch_external_interfaces.h
@@ -107,6 +141,7 @@ set(INTERNAL_HEADERS
${HEADER_DIR}/internal/catch_impl.hpp
${HEADER_DIR}/internal/catch_interfaces_capture.h
${HEADER_DIR}/internal/catch_interfaces_config.h
+ ${HEADER_DIR}/internal/catch_interfaces_enum_values_registry.h
${HEADER_DIR}/internal/catch_interfaces_exception.h
${HEADER_DIR}/internal/catch_interfaces_registry_hub.h
${HEADER_DIR}/internal/catch_interfaces_reporter.h
@@ -116,6 +151,7 @@ set(INTERNAL_HEADERS
${HEADER_DIR}/internal/catch_leak_detector.h
${HEADER_DIR}/internal/catch_list.h
${HEADER_DIR}/internal/catch_matchers.h
+ ${HEADER_DIR}/internal/catch_matchers_exception.hpp
${HEADER_DIR}/internal/catch_matchers_floating.h
${HEADER_DIR}/internal/catch_matchers_generic.hpp
${HEADER_DIR}/internal/catch_matchers_string.h
@@ -135,7 +171,6 @@ set(INTERNAL_HEADERS
${HEADER_DIR}/internal/catch_reporter_registry.h
${HEADER_DIR}/internal/catch_result_type.h
${HEADER_DIR}/internal/catch_run_context.h
- ${HEADER_DIR}/internal/catch_benchmark.h
${HEADER_DIR}/internal/catch_section.h
${HEADER_DIR}/internal/catch_section_info.h
${HEADER_DIR}/internal/catch_session.h
@@ -159,7 +194,6 @@ set(INTERNAL_HEADERS
${HEADER_DIR}/internal/catch_to_string.hpp
${HEADER_DIR}/internal/catch_tostring.h
${HEADER_DIR}/internal/catch_totals.h
- ${HEADER_DIR}/internal/catch_type_traits.hpp
${HEADER_DIR}/internal/catch_uncaught_exceptions.h
${HEADER_DIR}/internal/catch_user_interfaces.h
${HEADER_DIR}/internal/catch_version.h
@@ -171,7 +205,6 @@ set(IMPL_SOURCES
${HEADER_DIR}/internal/catch_approx.cpp
${HEADER_DIR}/internal/catch_assertionhandler.cpp
${HEADER_DIR}/internal/catch_assertionresult.cpp
- ${HEADER_DIR}/internal/catch_benchmark.cpp
${HEADER_DIR}/internal/catch_capture_matchers.cpp
${HEADER_DIR}/internal/catch_commandline.cpp
${HEADER_DIR}/internal/catch_common.cpp
@@ -182,6 +215,7 @@ set(IMPL_SOURCES
${HEADER_DIR}/internal/catch_debugger.cpp
${HEADER_DIR}/internal/catch_decomposer.cpp
${HEADER_DIR}/internal/catch_enforce.cpp
+ ${HEADER_DIR}/internal/catch_enum_values_registry.cpp
${HEADER_DIR}/internal/catch_errno_guard.cpp
${HEADER_DIR}/internal/catch_exception_translator_registry.cpp
${HEADER_DIR}/internal/catch_fatal_condition.cpp
@@ -196,6 +230,7 @@ set(IMPL_SOURCES
${HEADER_DIR}/internal/catch_list.cpp
${HEADER_DIR}/internal/catch_leak_detector.cpp
${HEADER_DIR}/internal/catch_matchers.cpp
+ ${HEADER_DIR}/internal/catch_matchers_exception.cpp
${HEADER_DIR}/internal/catch_matchers_floating.cpp
${HEADER_DIR}/internal/catch_matchers_generic.cpp
${HEADER_DIR}/internal/catch_matchers_string.cpp
@@ -247,6 +282,7 @@ set(REPORTER_HEADERS
${HEADER_DIR}/reporters/catch_reporter_tap.hpp
${HEADER_DIR}/reporters/catch_reporter_teamcity.hpp
${HEADER_DIR}/reporters/catch_reporter_xml.h
+ ${HEADER_DIR}/reporters/catch_reporter_sonarqube.hpp
)
set(REPORTER_SOURCES
${HEADER_DIR}/reporters/catch_reporter_bases.cpp
@@ -265,7 +301,9 @@ set(HEADERS
${EXTERNAL_HEADERS}
${INTERNAL_HEADERS}
${REPORTER_HEADERS}
- )
+ ${BENCHMARK_HEADERS}
+ ${BENCHMARK_SOURCES}
+)
# Provide some groupings for IDEs
SOURCE_GROUP("Tests" FILES ${TEST_SOURCES})
@@ -276,19 +314,31 @@ include(CTest)
add_executable(SelfTest ${TEST_SOURCES} ${IMPL_SOURCES} ${REPORTER_SOURCES} ${SURROGATE_SOURCES} ${HEADERS})
target_include_directories(SelfTest PRIVATE ${HEADER_DIR})
-if(USE_CPP17)
- message(STATUS "Enabling C++17")
- set_property(TARGET SelfTest PROPERTY CXX_STANDARD 17)
-elseif(USE_CPP14)
- message(STATUS "Enabling C++14")
- set_property(TARGET SelfTest PROPERTY CXX_STANDARD 14)
-else()
- message(STATUS "Enabling C++11")
- set_property(TARGET SelfTest PROPERTY CXX_STANDARD 11)
-endif()
+# It took CMake until 3.8 to abandon the doomed approach of enumerating
+# required features so we just list C++11 features to support older ones.
+target_compile_features(SelfTest
+ PRIVATE
+ cxx_alignas
+ cxx_alignof
+ cxx_attributes
+ cxx_auto_type
+ cxx_constexpr
+ cxx_defaulted_functions
+ cxx_deleted_functions
+ cxx_final
+ cxx_lambdas
+ cxx_noexcept
+ cxx_override
+ cxx_range_for
+ cxx_rvalue_references
+ cxx_static_assert
+ cxx_strong_enums
+ cxx_trailing_return_types
+ cxx_unicode_literals
+ cxx_user_literals
+ cxx_variadic_macros
+)
-set_property(TARGET SelfTest PROPERTY CXX_STANDARD_REQUIRED ON)
-set_property(TARGET SelfTest PROPERTY CXX_EXTENSIONS OFF)
if (CATCH_ENABLE_COVERAGE)
set(ENABLE_COVERAGE ON CACHE BOOL "Enable coverage build." FORCE)
@@ -302,7 +352,7 @@ endif()
if ( CMAKE_CXX_COMPILER_ID MATCHES "Clang|AppleClang|GNU" )
target_compile_options( SelfTest PRIVATE -Wall -Wextra -Wunreachable-code -Wpedantic -Wmissing-declarations )
if (CATCH_ENABLE_WERROR)
- target_compile_options( SelfTest PRIVATE -Werror)
+ target_compile_options( SelfTest PRIVATE -Werror )
endif()
endif()
# Clang specific options go here
@@ -348,8 +398,19 @@ set_tests_properties(ListTestNamesOnly PROPERTIES
add_test(NAME NoAssertions COMMAND $<TARGET_FILE:SelfTest> -w NoAssertions)
set_tests_properties(NoAssertions PROPERTIES PASS_REGULAR_EXPRESSION "No assertions in test case")
-add_test(NAME NoTest COMMAND $<TARGET_FILE:SelfTest> -w NoTests "___nonexistent_test___")
-set_tests_properties(NoTest PROPERTIES PASS_REGULAR_EXPRESSION "No test cases matched")
+add_test(NAME NoTest COMMAND $<TARGET_FILE:SelfTest> Tracker, "___nonexistent_test___")
+set_tests_properties(NoTest PROPERTIES
+ PASS_REGULAR_EXPRESSION "No test cases matched '___nonexistent_test___'"
+ FAIL_REGULAR_EXPRESSION "No tests ran"
+)
+
+add_test(NAME WarnAboutNoTests COMMAND ${CMAKE_COMMAND} -P ${CATCH_DIR}/projects/SelfTest/WarnAboutNoTests.cmake $<TARGET_FILE:SelfTest>)
+
+add_test(NAME UnmatchedOutputFilter COMMAND $<TARGET_FILE:SelfTest> [this-tag-does-not-exist] -w NoTests)
+set_tests_properties(UnmatchedOutputFilter
+ PROPERTIES
+ PASS_REGULAR_EXPRESSION "No test cases matched '\\[this-tag-does-not-exist\\]'"
+)
add_test(NAME FilteredSection-1 COMMAND $<TARGET_FILE:SelfTest> \#1394 -c RunSection)
set_tests_properties(FilteredSection-1 PROPERTIES FAIL_REGULAR_EXPRESSION "No tests ran")
@@ -360,6 +421,36 @@ set_tests_properties(FilteredSection-2 PROPERTIES FAIL_REGULAR_EXPRESSION "No te
add_test(NAME ApprovalTests COMMAND ${PYTHON_EXECUTABLE} ${CATCH_DIR}/scripts/approvalTests.py $<TARGET_FILE:SelfTest>)
set_tests_properties(ApprovalTests PROPERTIES FAIL_REGULAR_EXPRESSION "Results differed")
+add_test(NAME RegressionCheck-1670 COMMAND $<TARGET_FILE:SelfTest> "#1670 regression check" -c A -r compact)
+set_tests_properties(RegressionCheck-1670 PROPERTIES PASS_REGULAR_EXPRESSION "Passed 1 test case with 2 assertions.")
+
+add_test(NAME VersionCheck COMMAND $<TARGET_FILE:SelfTest> -h)
+set_tests_properties(VersionCheck PROPERTIES PASS_REGULAR_EXPRESSION "Catch v${PROJECT_VERSION}")
+
+add_test(NAME LibIdentityTest COMMAND $<TARGET_FILE:SelfTest> --libidentify)
+set_tests_properties(LibIdentityTest PROPERTIES PASS_REGULAR_EXPRESSION "description: A Catch2 test executable")
+
+add_test(NAME FilenameAsTagsTest COMMAND $<TARGET_FILE:SelfTest> -\# --list-tags)
+set_tests_properties(FilenameAsTagsTest PROPERTIES PASS_REGULAR_EXPRESSION "\\[#Approx.tests\\]")
+
+add_test(NAME EscapeSpecialCharactersInTestNames COMMAND $<TARGET_FILE:SelfTest> "Test with special\\, characters \"in name")
+set_tests_properties(EscapeSpecialCharactersInTestNames PROPERTIES PASS_REGULAR_EXPRESSION "1 assertion in 1 test case")
+
+add_test(NAME TestsInFile::SimpleSpecs COMMAND $<TARGET_FILE:SelfTest> "-f ${CATCH_DIR}/projects/SelfTest/Misc/plain-old-tests.input")
+set_tests_properties(TestsInFile::SimpleSpecs PROPERTIES PASS_REGULAR_EXPRESSION "6 assertions in 2 test cases")
+
+add_test(NAME TestsInFile::EscapeSpecialCharacters COMMAND $<TARGET_FILE:SelfTest> "-f ${CATCH_DIR}/projects/SelfTest/Misc/special-characters-in-file.input")
+set_tests_properties(TestsInFile::EscapeSpecialCharacters PROPERTIES PASS_REGULAR_EXPRESSION "1 assertion in 1 test case")
+
+# CTest does not allow us to create an AND of required regular expressions,
+# so we have to split the test into 2 parts and look for parts of the expected
+# output separately.
+add_test(NAME TestsInFile::InvalidTestNames-1 COMMAND $<TARGET_FILE:SelfTest> "-f ${CATCH_DIR}/projects/SelfTest/Misc/invalid-test-names.input")
+set_tests_properties(TestsInFile::InvalidTestNames-1 PROPERTIES PASS_REGULAR_EXPRESSION "Invalid Filter: \"Test with special, characters in \\\\\" name\"")
+
+add_test(NAME TestsInFile::InvalidTestNames-2 COMMAND $<TARGET_FILE:SelfTest> "-f ${CATCH_DIR}/projects/SelfTest/Misc/invalid-test-names.input")
+set_tests_properties(TestsInFile::InvalidTestNames-2 PROPERTIES PASS_REGULAR_EXPRESSION "No tests ran")
+
if (CATCH_USE_VALGRIND)
add_test(NAME ValgrindRunTests COMMAND valgrind --leak-check=full --error-exitcode=1 $<TARGET_FILE:SelfTest>)
diff --git a/projects/ExtraTests/CMakeLists.txt b/projects/ExtraTests/CMakeLists.txt
index c0dd82d8..0e514d96 100644
--- a/projects/ExtraTests/CMakeLists.txt
+++ b/projects/ExtraTests/CMakeLists.txt
@@ -116,6 +116,35 @@ set_tests_properties(
)
+add_executable(BenchmarkingMacros ${TESTS_DIR}/X20-BenchmarkingMacros.cpp)
+target_compile_definitions( BenchmarkingMacros PRIVATE CATCH_CONFIG_ENABLE_BENCHMARKING )
+
+add_test(NAME BenchmarkingMacros COMMAND BenchmarkingMacros -r console -s)
+set_tests_properties(
+ BenchmarkingMacros
+ PROPERTIES
+ PASS_REGULAR_EXPRESSION "benchmark name samples iterations estimated"
+)
+
+# This test touches windows.h, so it should only be compiled under msvc
+if (MSVC)
+ # This test fails if it does not compile and succeeds otherwise
+ add_executable(WindowsHeader ${TESTS_DIR}/X90-WindowsHeaderInclusion.cpp)
+ set_property( TARGET WindowsHeader PROPERTY CXX_STANDARD 11 )
+ set_property( TARGET WindowsHeader PROPERTY CXX_STANDARD_REQUIRED ON )
+ set_property( TARGET WindowsHeader PROPERTY CXX_EXTENSIONS OFF )
+ target_include_directories( WindowsHeader PRIVATE ${SINGLE_INCLUDE_PATH} )
+ add_test(NAME WindowsHeader COMMAND WindowsHeader -r compact)
+endif()
+
+add_executable(DebugBreakMacros ${TESTS_DIR}/X12-CustomDebugBreakMacro.cpp)
+add_test(NAME DebugBreakMacros COMMAND DebugBreakMacros --break)
+set_tests_properties(
+ DebugBreakMacros
+ PROPERTIES
+ PASS_REGULAR_EXPRESSION "Pretty please, break into debugger"
+)
+
set( EXTRA_TEST_BINARIES
PrefixedMacros
DisabledMacros
@@ -123,6 +152,8 @@ set( EXTRA_TEST_BINARIES
DisabledExceptions-CustomHandler
FallbackStringifier
DisableStringification
+ BenchmarkingMacros
+ DebugBreakMacros
)
# Shared config
@@ -133,3 +164,4 @@ foreach( test ${EXTRA_TEST_BINARIES} )
target_include_directories( ${test} PRIVATE ${SINGLE_INCLUDE_PATH} )
endforeach()
+
diff --git a/projects/ExtraTests/X01-PrefixedMacros.cpp b/projects/ExtraTests/X01-PrefixedMacros.cpp
index 7671cbc4..3d2ab9c1 100644
--- a/projects/ExtraTests/X01-PrefixedMacros.cpp
+++ b/projects/ExtraTests/X01-PrefixedMacros.cpp
@@ -48,6 +48,7 @@ CATCH_TEST_CASE("PrefixedMacros") {
CATCH_CHECK_THAT("bdef", Equals("bdef"));
CATCH_INFO( "some info" );
+ CATCH_UNSCOPED_INFO( "some info" );
CATCH_WARN( "some warn" );
CATCH_SECTION("some section") {
int i = 1;
diff --git a/projects/ExtraTests/X12-CustomDebugBreakMacro.cpp b/projects/ExtraTests/X12-CustomDebugBreakMacro.cpp
new file mode 100644
index 00000000..25ab4a0e
--- /dev/null
+++ b/projects/ExtraTests/X12-CustomDebugBreakMacro.cpp
@@ -0,0 +1,17 @@
+// X12-CustomDebugBreakMacro.cpp
+// Test that user-defined `CATCH_BREAK_INTO_DEBUGGER` is respected and used.
+
+#include <iostream>
+
+void custom_debug_break() {
+ std::cerr << "Pretty please, break into debugger\n";
+}
+
+#define CATCH_BREAK_INTO_DEBUGGER() custom_debug_break()
+
+#define CATCH_CONFIG_MAIN
+#include <catch2/catch.hpp>
+
+TEST_CASE("Failing test that breaks into debugger", "[macros]") {
+ REQUIRE(1 == 2);
+}
diff --git a/projects/ExtraTests/X20-BenchmarkingMacros.cpp b/projects/ExtraTests/X20-BenchmarkingMacros.cpp
new file mode 100644
index 00000000..ca2f056b
--- /dev/null
+++ b/projects/ExtraTests/X20-BenchmarkingMacros.cpp
@@ -0,0 +1,125 @@
+// X20-BenchmarkingMacros.cpp
+// Test that the benchmarking support macros compile properly with the single header
+
+#define CATCH_CONFIG_MAIN
+#include <catch2/catch.hpp>
+
+namespace {
+std::uint64_t factorial(std::uint64_t number) {
+ if (number < 2) {
+ return 1;
+ }
+ return number * factorial(number - 1);
+}
+}
+
+TEST_CASE("Benchmark factorial", "[benchmark]") {
+ CHECK(factorial(0) == 1);
+ // some more asserts..
+ CHECK(factorial(10) == 3628800);
+
+ BENCHMARK("factorial 10") {
+ return factorial(10);
+ };
+
+ CHECK(factorial(14) == 87178291200ull);
+ BENCHMARK("factorial 14") {
+ return factorial(14);
+ };
+}
+
+TEST_CASE("Benchmark containers", "[.][benchmark]") {
+ static const int size = 100;
+
+ std::vector<int> v;
+ std::map<int, int> m;
+
+ SECTION("without generator") {
+ BENCHMARK("Load up a vector") {
+ v = std::vector<int>();
+ for (int i = 0; i < size; ++i)
+ v.push_back(i);
+ };
+ REQUIRE(v.size() == size);
+
+ // test optimizer control
+ BENCHMARK("Add up a vector's content") {
+ uint64_t add = 0;
+ for (int i = 0; i < size; ++i)
+ add += v[i];
+ return add;
+ };
+
+ BENCHMARK("Load up a map") {
+ m = std::map<int, int>();
+ for (int i = 0; i < size; ++i)
+ m.insert({ i, i + 1 });
+ };
+ REQUIRE(m.size() == size);
+
+ BENCHMARK("Reserved vector") {
+ v = std::vector<int>();
+ v.reserve(size);
+ for (int i = 0; i < size; ++i)
+ v.push_back(i);
+ };
+ REQUIRE(v.size() == size);
+
+ BENCHMARK("Resized vector") {
+ v = std::vector<int>();
+ v.resize(size);
+ for (int i = 0; i < size; ++i)
+ v[i] = i;
+ };
+ REQUIRE(v.size() == size);
+
+ int array[size];
+ BENCHMARK("A fixed size array that should require no allocations") {
+ for (int i = 0; i < size; ++i)
+ array[i] = i;
+ };
+ int sum = 0;
+ for (int i = 0; i < size; ++i)
+ sum += array[i];
+ REQUIRE(sum > size);
+
+ SECTION("XYZ") {
+
+ BENCHMARK_ADVANCED("Load up vector with chronometer")(Catch::Benchmark::Chronometer meter) {
+ std::vector<int> k;
+ meter.measure([&](int idx) {
+ k = std::vector<int>();
+ for (int i = 0; i < size; ++i)
+ k.push_back(idx);
+ });
+ REQUIRE(k.size() == size);
+ };
+
+ int runs = 0;
+ BENCHMARK("Fill vector indexed", benchmarkIndex) {
+ v = std::vector<int>();
+ v.resize(size);
+ for (int i = 0; i < size; ++i)
+ v[i] = benchmarkIndex;
+ runs = benchmarkIndex;
+ };
+
+ for (size_t i = 0; i < v.size(); ++i) {
+ REQUIRE(v[i] == runs);
+ }
+ }
+ }
+
+ SECTION("with generator") {
+ auto generated = GENERATE(range(0, 10));
+ BENCHMARK("Fill vector generated") {
+ v = std::vector<int>();
+ v.resize(size);
+ for (int i = 0; i < size; ++i)
+ v[i] = generated;
+ };
+ for (size_t i = 0; i < v.size(); ++i) {
+ REQUIRE(v[i] == generated);
+ }
+ }
+}
diff --git a/projects/ExtraTests/X90-WindowsHeaderInclusion.cpp b/projects/ExtraTests/X90-WindowsHeaderInclusion.cpp
new file mode 100644
index 00000000..2b7a074e
--- /dev/null
+++ b/projects/ExtraTests/X90-WindowsHeaderInclusion.cpp
@@ -0,0 +1,12 @@
+// X90-WindowsHeaderInclusion.cpp
+// Test that the Catch2 header compiles even after including windows.h
+// without defining NOMINMAX first. As an FYI, if you do that, you are
+// wrong.
+
+#include <windows.h>
+#define CATCH_CONFIG_MAIN
+#include <catch2/catch.hpp>
+
+TEST_CASE("Catch2 did survive compilation with windows.h", "[compile-test]") {
+ SUCCEED();
+}
diff --git a/projects/SelfTest/Baselines/compact.sw.approved.txt b/projects/SelfTest/Baselines/compact.sw.approved.txt
index 6fedbb92..c61028a2 100644
--- a/projects/SelfTest/Baselines/compact.sw.approved.txt
+++ b/projects/SelfTest/Baselines/compact.sw.approved.txt
@@ -3,6 +3,8 @@ Decomposition.tests.cpp:<line number>: passed: fptr == 0 for: 0 == 0
Decomposition.tests.cpp:<line number>: passed: fptr == 0l for: 0 == 0
Compilation.tests.cpp:<line number>: passed: y.v == 0 for: 0 == 0
Compilation.tests.cpp:<line number>: passed: 0 == y.v for: 0 == 0
+Compilation.tests.cpp:<line number>: passed: y.v == 0 for: 0 == 0
+Compilation.tests.cpp:<line number>: passed: 0 == y.v for: 0 == 0
Compilation.tests.cpp:<line number>: passed: t1 == t2 for: {?} == {?}
Compilation.tests.cpp:<line number>: passed: t1 != t2 for: {?} != {?}
Compilation.tests.cpp:<line number>: passed: t1 < t2 for: {?} < {?}
@@ -155,18 +157,36 @@ Class.tests.cpp:<line number>: passed: Template_Fixture_2<TestType>::m_a.size()
Class.tests.cpp:<line number>: passed: Template_Fixture_2<TestType>::m_a.size() == 0 for: 0 == 0
Class.tests.cpp:<line number>: passed: Template_Fixture_2<TestType>::m_a.size() == 0 for: 0 == 0
Class.tests.cpp:<line number>: passed: Template_Fixture_2<TestType>::m_a.size() == 0 for: 0 == 0
+Class.tests.cpp:<line number>: failed: Template_Fixture_2<TestType>{}.m_a.size() < 2 for: 6 < 2
+Class.tests.cpp:<line number>: failed: Template_Fixture_2<TestType>{}.m_a.size() < 2 for: 2 < 2
+Class.tests.cpp:<line number>: failed: Template_Fixture_2<TestType>{}.m_a.size() < 2 for: 6 < 2
+Class.tests.cpp:<line number>: failed: Template_Fixture_2<TestType>{}.m_a.size() < 2 for: 2 < 2
+Class.tests.cpp:<line number>: passed: Template_Fixture_2<TestType>{}.m_a.size() >= 2 for: 6 >= 2
+Class.tests.cpp:<line number>: passed: Template_Fixture_2<TestType>{}.m_a.size() >= 2 for: 2 >= 2
+Class.tests.cpp:<line number>: passed: Template_Fixture_2<TestType>{}.m_a.size() >= 2 for: 6 >= 2
+Class.tests.cpp:<line number>: passed: Template_Fixture_2<TestType>{}.m_a.size() >= 2 for: 2 >= 2
Class.tests.cpp:<line number>: failed: Template_Fixture<TestType>::m_a == 2 for: 1.0 == 2
Class.tests.cpp:<line number>: failed: Template_Fixture<TestType>::m_a == 2 for: 1.0f == 2
Class.tests.cpp:<line number>: failed: Template_Fixture<TestType>::m_a == 2 for: 1 == 2
Class.tests.cpp:<line number>: passed: Template_Fixture<TestType>::m_a == 1 for: 1.0 == 1
Class.tests.cpp:<line number>: passed: Template_Fixture<TestType>::m_a == 1 for: 1.0f == 1
Class.tests.cpp:<line number>: passed: Template_Fixture<TestType>::m_a == 1 for: 1 == 1
+Class.tests.cpp:<line number>: failed: Nttp_Fixture<V>::value == 0 for: 1 == 0
+Class.tests.cpp:<line number>: failed: Nttp_Fixture<V>::value == 0 for: 3 == 0
+Class.tests.cpp:<line number>: failed: Nttp_Fixture<V>::value == 0 for: 6 == 0
+Class.tests.cpp:<line number>: passed: Nttp_Fixture<V>::value > 0 for: 1 > 0
+Class.tests.cpp:<line number>: passed: Nttp_Fixture<V>::value > 0 for: 3 > 0
+Class.tests.cpp:<line number>: passed: Nttp_Fixture<V>::value > 0 for: 6 > 0
Class.tests.cpp:<line number>: failed: m_a == 2 for: 1 == 2
Class.tests.cpp:<line number>: passed: m_a == 1 for: 1 == 1
Misc.tests.cpp:<line number>: passed: x.size() == 0 for: 0 == 0
Misc.tests.cpp:<line number>: passed: x.size() == 0 for: 0 == 0
Misc.tests.cpp:<line number>: passed: x.size() == 0 for: 0 == 0
Misc.tests.cpp:<line number>: passed: x.size() == 0 for: 0 == 0
+Misc.tests.cpp:<line number>: passed: x.size() > 0 for: 42 > 0
+Misc.tests.cpp:<line number>: passed: x.size() > 0 for: 9 > 0
+Misc.tests.cpp:<line number>: passed: x.size() > 0 for: 42 > 0
+Misc.tests.cpp:<line number>: passed: x.size() > 0 for: 9 > 0
Approx.tests.cpp:<line number>: passed: d == 1.23_a for: 1.23 == Approx( 1.23 )
Approx.tests.cpp:<line number>: passed: d != 1.22_a for: 1.23 != Approx( 1.22 )
Approx.tests.cpp:<line number>: passed: -d == -1.23_a for: -1.23 == Approx( -1.23 )
@@ -223,13 +243,9 @@ Tricky.tests.cpp:<line number>: passed: true
Tricky.tests.cpp:<line number>: passed: true
Tricky.tests.cpp:<line number>: passed: true
Tricky.tests.cpp:<line number>: passed: true
-Approx.tests.cpp:<line number>: passed: INFINITY == Approx(INFINITY) for: inff == Approx( inf )
-Approx.tests.cpp:<line number>: passed: NAN != Approx(NAN) for: nanf != Approx( nan )
-Approx.tests.cpp:<line number>: passed: !(NAN == Approx(NAN)) for: !(nanf == Approx( nan ))
-Tricky.tests.cpp:<line number>: passed: y.v == 0 for: 0 == 0
-Tricky.tests.cpp:<line number>: passed: 0 == y.v for: 0 == 0
Message.tests.cpp:<line number>: passed: with 7 messages: 'a := 1' and 'b := 2' and 'c := 3' and 'a + b := 3' and 'a+b := 3' and 'c > b := true' and 'a == 1 := true'
Message.tests.cpp:<line number>: passed: with 7 messages: 'std::vector<int>{1, 2, 3}[0, 1, 2] := 3' and 'std::vector<int>{1, 2, 3}[(0, 1)] := 2' and 'std::vector<int>{1, 2, 3}[0] := 1' and '(helper_1436<int, int>{12, -12}) := { 12, -12 }' and '(helper_1436<int, int>(-12, 12)) := { -12, 12 }' and '(1, 2) := 2' and '(2, 3) := 3'
+Message.tests.cpp:<line number>: passed: with 11 messages: '("comma, in string", "escaped, \", ") := "escaped, ", "' and '"single quote in string,'," := "single quote in string,',"' and '"some escapes, \\,\\\\" := "some escapes, \,\\"' and '"some, ), unmatched, } prenheses {[<" := "some, ), unmatched, } prenheses {[<"' and ''"' := '"'' and ''\'' := '''' and '',' := ','' and ''}' := '}'' and '')' := ')'' and ''(' := '('' and ''{' := '{''
ToStringGeneral.tests.cpp:<line number>: passed: true with 1 message: 'i := 2'
ToStringGeneral.tests.cpp:<line number>: passed: true with 1 message: '3'
ToStringGeneral.tests.cpp:<line number>: passed: tab == '\t' for: '\t' == '\t'
@@ -260,6 +276,10 @@ Tricky.tests.cpp:<line number>: passed: true
Tricky.tests.cpp:<line number>: passed: std::vector<int>{1, 2} == std::vector<int>{1, 2} for: { 1, 2 } == { 1, 2 }
Tricky.tests.cpp:<line number>: passed: a for: 0x<hex digits>
Tricky.tests.cpp:<line number>: passed: a == &foo for: 0x<hex digits> == 0x<hex digits>
+RandomNumberGeneration.tests.cpp:<line number>: passed: SimplePcg32{} == SimplePcg32{} for: {?} == {?}
+RandomNumberGeneration.tests.cpp:<line number>: passed: SimplePcg32{ 0 } != SimplePcg32{} for: {?} != {?}
+RandomNumberGeneration.tests.cpp:<line number>: passed: !(SimplePcg32{ 1 } == SimplePcg32{ 2 }) for: !({?} == {?})
+RandomNumberGeneration.tests.cpp:<line number>: passed: !(SimplePcg32{ 1 } != SimplePcg32{ 1 }) for: !({?} != {?})
Approx.tests.cpp:<line number>: passed: td == Approx(10.0) for: StrongDoubleTypedef(10) == Approx( 10.0 )
Approx.tests.cpp:<line number>: passed: Approx(10.0) == td for: Approx( 10.0 ) == StrongDoubleTypedef(10)
Approx.tests.cpp:<line number>: passed: td != Approx(11.0) for: StrongDoubleTypedef(10) != Approx( 11.0 )
@@ -292,15 +312,45 @@ Condition.tests.cpp:<line number>: passed: 4 == ul for: 4 == 4
Condition.tests.cpp:<line number>: passed: 5 == c for: 5 == 5
Condition.tests.cpp:<line number>: passed: 6 == uc for: 6 == 6
Condition.tests.cpp:<line number>: passed: (std::numeric_limits<uint32_t>::max)() > ul for: 4294967295 (0x<hex digits>) > 4
+Matchers.tests.cpp:<line number>: passed: testStringForMatching2(), !composed1 for: "some completely different text that contains one common word" not ( contains: "string" or contains: "random" )
+Matchers.tests.cpp:<line number>: passed: testStringForMatching2(), composed2 for: "some completely different text that contains one common word" ( contains: "string" or contains: "random" or contains: "different" )
Matchers.tests.cpp:<line number>: failed: testStringForMatching(), Contains("not there", Catch::CaseSensitive::No) for: "this string contains 'abc' as a substring" contains: "not there" (case insensitive)
Matchers.tests.cpp:<line number>: failed: testStringForMatching(), Contains("STRING") for: "this string contains 'abc' as a substring" contains: "STRING"
+Generators.tests.cpp:<line number>: passed: elem % 2 == 1 for: 1 == 1
+Generators.tests.cpp:<line number>: passed: elem % 2 == 1 for: 1 == 1
+Generators.tests.cpp:<line number>: passed: elem % 2 == 1 for: 1 == 1
+Generators.tests.cpp:<line number>: passed: elem % 2 == 1 for: 1 == 1
+Generators.tests.cpp:<line number>: passed: elem % 2 == 1 for: 1 == 1
+Generators.tests.cpp:<line number>: passed: elem % 2 == 1 for: 1 == 1
+Generators.tests.cpp:<line number>: passed: elem % 2 == 1 for: 1 == 1
+Generators.tests.cpp:<line number>: passed: elem % 2 == 1 for: 1 == 1
+Generators.tests.cpp:<line number>: passed: elem % 2 == 1 for: 1 == 1
+Generators.tests.cpp:<line number>: passed: elem % 2 == 1 for: 1 == 1
+Generators.tests.cpp:<line number>: passed: elem % 2 == 1 for: 1 == 1
+Generators.tests.cpp:<line number>: passed: elem % 2 == 1 for: 1 == 1
+Generators.tests.cpp:<line number>: passed: call_count == 1 for: 1 == 1
+Generators.tests.cpp:<line number>: passed: make_data().size() == test_count for: 6 == 6
Exception.tests.cpp:<line number>: failed: unexpected exception with message: 'custom exception - not std'; expression was: throwCustom()
Exception.tests.cpp:<line number>: failed: unexpected exception with message: 'custom exception - not std'; expression was: throwCustom(), std::exception
Exception.tests.cpp:<line number>: failed: unexpected exception with message: 'custom std exception'
Approx.tests.cpp:<line number>: passed: 101.000001 != Approx(100).epsilon(0.01) for: 101.000001 != Approx( 100.0 )
Approx.tests.cpp:<line number>: passed: std::pow(10, -5) != Approx(std::pow(10, -7)) for: 0.00001 != Approx( 0.0000001 )
+ToString.tests.cpp:<line number>: passed: enumInfo->lookup(0) == "Value1" for: Value1 == "Value1"
+ToString.tests.cpp:<line number>: passed: enumInfo->lookup(1) == "Value2" for: Value2 == "Value2"
+ToString.tests.cpp:<line number>: passed: enumInfo->lookup(3) == "{** unexpected enum value **}" for: {** unexpected enum value **}
+==
+"{** unexpected enum value **}"
Matchers.tests.cpp:<line number>: failed: testStringForMatching(), EndsWith("Substring") for: "this string contains 'abc' as a substring" ends with: "Substring"
Matchers.tests.cpp:<line number>: failed: testStringForMatching(), EndsWith("this", Catch::CaseSensitive::No) for: "this string contains 'abc' as a substring" ends with: "this" (case insensitive)
+EnumToString.tests.cpp:<line number>: passed: stringify( EnumClass3::Value1 ) == "Value1" for: "Value1" == "Value1"
+EnumToString.tests.cpp:<line number>: passed: stringify( EnumClass3::Value2 ) == "Value2" for: "Value2" == "Value2"
+EnumToString.tests.cpp:<line number>: passed: stringify( EnumClass3::Value3 ) == "Value3" for: "Value3" == "Value3"
+EnumToString.tests.cpp:<line number>: passed: stringify( EnumClass3::Value4 ) == "{** unexpected enum value **}" for: "{** unexpected enum value **}"
+==
+"{** unexpected enum value **}"
+EnumToString.tests.cpp:<line number>: passed: stringify( ec3 ) == "Value2" for: "Value2" == "Value2"
+EnumToString.tests.cpp:<line number>: passed: stringify( Bikeshed::Colours::Red ) == "Red" for: "Red" == "Red"
+EnumToString.tests.cpp:<line number>: passed: stringify( Bikeshed::Colours::Blue ) == "Blue" for: "Blue" == "Blue"
Approx.tests.cpp:<line number>: passed: 101.01 != Approx(100).epsilon(0.01) for: 101.01 != Approx( 100.0 )
Condition.tests.cpp:<line number>: failed: data.int_seven == 6 for: 7 == 6
Condition.tests.cpp:<line number>: failed: data.int_seven == 8 for: 7 == 8
@@ -337,16 +387,20 @@ Matchers.tests.cpp:<line number>: failed: expected exception, got none; expressi
Matchers.tests.cpp:<line number>: failed: expected exception, got none; expression was: doesNotThrow(), SpecialException, ExceptionMatcher{1}
Matchers.tests.cpp:<line number>: failed: unexpected exception with message: 'Unknown exception'; expression was: throwsAsInt(1), SpecialException, ExceptionMatcher{1}
Matchers.tests.cpp:<line number>: failed: unexpected exception with message: 'Unknown exception'; expression was: throwsAsInt(1), SpecialException, ExceptionMatcher{1}
-Matchers.tests.cpp:<line number>: failed: throws(3), SpecialException, ExceptionMatcher{1} for: SpecialException::what special exception has value of 1
-Matchers.tests.cpp:<line number>: failed: throws(4), SpecialException, ExceptionMatcher{1} for: SpecialException::what special exception has value of 1
-Matchers.tests.cpp:<line number>: passed: throws(1), SpecialException, ExceptionMatcher{1} for: SpecialException::what special exception has value of 1
-Matchers.tests.cpp:<line number>: passed: throws(2), SpecialException, ExceptionMatcher{2} for: SpecialException::what special exception has value of 2
+Matchers.tests.cpp:<line number>: failed: throwsSpecialException(3), SpecialException, ExceptionMatcher{1} for: SpecialException::what special exception has value of 1
+Matchers.tests.cpp:<line number>: failed: throwsSpecialException(4), SpecialException, ExceptionMatcher{1} for: SpecialException::what special exception has value of 1
+Matchers.tests.cpp:<line number>: passed: throwsSpecialException(1), SpecialException, ExceptionMatcher{1} for: SpecialException::what special exception has value of 1
+Matchers.tests.cpp:<line number>: passed: throwsSpecialException(2), SpecialException, ExceptionMatcher{2} for: SpecialException::what special exception has value of 2
Exception.tests.cpp:<line number>: passed: thisThrows(), "expected exception" for: "expected exception" equals: "expected exception"
Exception.tests.cpp:<line number>: passed: thisThrows(), Equals( "expecteD Exception", Catch::CaseSensitive::No ) for: "expected exception" equals: "expected exception" (case insensitive)
Exception.tests.cpp:<line number>: passed: thisThrows(), StartsWith( "expected" ) for: "expected exception" starts with: "expected"
Exception.tests.cpp:<line number>: passed: thisThrows(), EndsWith( "exception" ) for: "expected exception" ends with: "exception"
Exception.tests.cpp:<line number>: passed: thisThrows(), Contains( "except" ) for: "expected exception" contains: "except"
Exception.tests.cpp:<line number>: passed: thisThrows(), Contains( "exCept", Catch::CaseSensitive::No ) for: "expected exception" contains: "except" (case insensitive)
+Matchers.tests.cpp:<line number>: passed: throwsDerivedException(), DerivedException, Message("DerivedException::what") for: DerivedException::what exception message matches "DerivedException::what"
+Matchers.tests.cpp:<line number>: passed: throwsDerivedException(), DerivedException, !Message("derivedexception::what") for: DerivedException::what not exception message matches "derivedexception::what"
+Matchers.tests.cpp:<line number>: passed: throwsSpecialException(2), SpecialException, !Message("DerivedException::what") for: SpecialException::what not exception message matches "DerivedException::what"
+Matchers.tests.cpp:<line number>: passed: throwsSpecialException(2), SpecialException, Message("SpecialException::what") for: SpecialException::what exception message matches "SpecialException::what"
Exception.tests.cpp:<line number>: failed: unexpected exception with message: 'expected exception'; expression was: thisThrows(), std::string
Exception.tests.cpp:<line number>: failed: expected exception, got none; expression was: thisDoesntThrow(), std::domain_error
Exception.tests.cpp:<line number>: failed: unexpected exception with message: 'expected exception'; expression was: thisThrows()
@@ -359,53 +413,66 @@ Misc.tests.cpp:<line number>: passed: Factorial(1) == 1 for: 1 == 1
Misc.tests.cpp:<line number>: passed: Factorial(2) == 2 for: 2 == 2
Misc.tests.cpp:<line number>: passed: Factorial(3) == 6 for: 6 == 6
Misc.tests.cpp:<line number>: passed: Factorial(10) == 3628800 for: 3628800 (0x<hex digits>) == 3628800 (0x<hex digits>)
+Matchers.tests.cpp:<line number>: passed: 10., WithinRel(11.1, 0.1) for: 10.0 and 11.1 are within 10% of each other
+Matchers.tests.cpp:<line number>: passed: 10., !WithinRel(11.2, 0.1) for: 10.0 not and 11.2 are within 10% of each other
+Matchers.tests.cpp:<line number>: passed: 1., !WithinRel(0., 0.99) for: 1.0 not and 0 are within 99% of each other
+Matchers.tests.cpp:<line number>: passed: -0., WithinRel(0.) for: -0.0 and 0 are within 2.22045e-12% of each other
+Matchers.tests.cpp:<line number>: passed: v1, WithinRel(v2) for: 0.0 and 2.22507e-308 are within 2.22045e-12% of each other
Matchers.tests.cpp:<line number>: passed: 1., WithinAbs(1., 0) for: 1.0 is within 0.0 of 1.0
Matchers.tests.cpp:<line number>: passed: 0., WithinAbs(1., 1) for: 0.0 is within 1.0 of 1.0
Matchers.tests.cpp:<line number>: passed: 0., !WithinAbs(1., 0.99) for: 0.0 not is within 0.99 of 1.0
Matchers.tests.cpp:<line number>: passed: 0., !WithinAbs(1., 0.99) for: 0.0 not is within 0.99 of 1.0
-Matchers.tests.cpp:<line number>: passed: NAN, !WithinAbs(NAN, 0) for: nanf not is within 0.0 of nan
Matchers.tests.cpp:<line number>: passed: 11., !WithinAbs(10., 0.5) for: 11.0 not is within 0.5 of 10.0
Matchers.tests.cpp:<line number>: passed: 10., !WithinAbs(11., 0.5) for: 10.0 not is within 0.5 of 11.0
Matchers.tests.cpp:<line number>: passed: -10., WithinAbs(-10., 0.5) for: -10.0 is within 0.5 of -10.0
Matchers.tests.cpp:<line number>: passed: -10., WithinAbs(-9.6, 0.5) for: -10.0 is within 0.5 of -9.6
-Matchers.tests.cpp:<line number>: passed: 1., WithinULP(1., 0) for: 1.0 is within 0 ULPs of 1.0
-Matchers.tests.cpp:<line number>: passed: nextafter(1., 2.), WithinULP(1., 1) for: 1.0 is within 1 ULPs of 1.0
-Matchers.tests.cpp:<line number>: passed: nextafter(1., 0.), WithinULP(1., 1) for: 1.0 is within 1 ULPs of 1.0
-Matchers.tests.cpp:<line number>: passed: nextafter(1., 2.), !WithinULP(1., 0) for: 1.0 not is within 0 ULPs of 1.0
-Matchers.tests.cpp:<line number>: passed: 1., WithinULP(1., 0) for: 1.0 is within 0 ULPs of 1.0
-Matchers.tests.cpp:<line number>: passed: -0., WithinULP(0., 0) for: -0.0 is within 0 ULPs of 0.0
-Matchers.tests.cpp:<line number>: passed: NAN, !WithinULP(NAN, 123) for: nanf not is within 123 ULPs of nanf
-Matchers.tests.cpp:<line number>: 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:<line number>: 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:<line number>: 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:<line number>: passed: 1., WithinULP(1., 0) for: 1.0 is within 0 ULPs of 1.0000000000000000e+00 ([1.0000000000000000e+00, 1.0000000000000000e+00])
+Matchers.tests.cpp:<line number>: passed: nextafter(1., 2.), WithinULP(1., 1) for: 1.0 is within 1 ULPs of 1.0000000000000000e+00 ([9.9999999999999989e-01, 1.0000000000000002e+00])
+Matchers.tests.cpp:<line number>: passed: 0., WithinULP(nextafter(0., 1.), 1) for: 0.0 is within 1 ULPs of 4.9406564584124654e-324 ([0.0000000000000000e+00, 9.8813129168249309e-324])
+Matchers.tests.cpp:<line number>: passed: 1., WithinULP(nextafter(1., 0.), 1) for: 1.0 is within 1 ULPs of 9.9999999999999989e-01 ([9.9999999999999978e-01, 1.0000000000000000e+00])
+Matchers.tests.cpp:<line number>: passed: 1., !WithinULP(nextafter(1., 2.), 0) for: 1.0 not is within 0 ULPs of 1.0000000000000002e+00 ([1.0000000000000002e+00, 1.0000000000000002e+00])
+Matchers.tests.cpp:<line number>: passed: 1., WithinULP(1., 0) for: 1.0 is within 0 ULPs of 1.0000000000000000e+00 ([1.0000000000000000e+00, 1.0000000000000000e+00])
+Matchers.tests.cpp:<line number>: passed: -0., WithinULP(0., 0) for: -0.0 is within 0 ULPs of 0.0000000000000000e+00 ([0.0000000000000000e+00, 0.0000000000000000e+00])
+Matchers.tests.cpp:<line number>: 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.0000000000000000e+00 ([1.9999999999999998e+00, 2.0000000000000004e+00]) )
+Matchers.tests.cpp:<line number>: 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.0000000000000000e+00 ([1.0000000000000000e+00, 1.0000000000000000e+00]) )
+Matchers.tests.cpp:<line number>: passed: 0.0001, WithinAbs(0., 0.001) || WithinRel(0., 0.1) for: 0.0001 ( is within 0.001 of 0.0 or and 0 are within 10% of each other )
Matchers.tests.cpp:<line number>: passed: WithinAbs(1., 0.)
Matchers.tests.cpp:<line number>: passed: WithinAbs(1., -1.), std::domain_error
Matchers.tests.cpp:<line number>: passed: WithinULP(1., 0)
-Matchers.tests.cpp:<line number>: passed: WithinULP(1., -1), std::domain_error
+Matchers.tests.cpp:<line number>: passed: WithinRel(1., 0.)
+Matchers.tests.cpp:<line number>: passed: WithinRel(1., -0.2), std::domain_error
+Matchers.tests.cpp:<line number>: passed: WithinRel(1., 1.), std::domain_error
+Matchers.tests.cpp:<line number>: passed: 10.f, WithinRel(11.1f, 0.1f) for: 10.0f and 11.1 are within 10% of each other
+Matchers.tests.cpp:<line number>: passed: 10.f, !WithinRel(11.2f, 0.1f) for: 10.0f not and 11.2 are within 10% of each other
+Matchers.tests.cpp:<line number>: passed: 1.f, !WithinRel(0.f, 0.99f) for: 1.0f not and 0 are within 99% of each other
+Matchers.tests.cpp:<line number>: passed: -0.f, WithinRel(0.f) for: -0.0f and 0 are within 0.00119209% of each other
+Matchers.tests.cpp:<line number>: passed: v1, WithinRel(v2) for: 0.0f and 1.17549e-38 are within 0.00119209% of each other
Matchers.tests.cpp:<line number>: passed: 1.f, WithinAbs(1.f, 0) for: 1.0f is within 0.0 of 1.0
Matchers.tests.cpp:<line number>: passed: 0.f, WithinAbs(1.f, 1) for: 0.0f is within 1.0 of 1.0
Matchers.tests.cpp:<line number>: passed: 0.f, !WithinAbs(1.f, 0.99f) for: 0.0f not is within 0.9900000095 of 1.0
Matchers.tests.cpp:<line number>: passed: 0.f, !WithinAbs(1.f, 0.99f) for: 0.0f not is within 0.9900000095 of 1.0
Matchers.tests.cpp:<line number>: passed: 0.f, WithinAbs(-0.f, 0) for: 0.0f is within 0.0 of -0.0
-Matchers.tests.cpp:<line number>: passed: NAN, !WithinAbs(NAN, 0) for: nanf not is within 0.0 of nan
Matchers.tests.cpp:<line number>: passed: 11.f, !WithinAbs(10.f, 0.5f) for: 11.0f not is within 0.5 of 10.0
Matchers.tests.cpp:<line number>: passed: 10.f, !WithinAbs(11.f, 0.5f) for: 10.0f not is within 0.5 of 11.0
Matchers.tests.cpp:<line number>: passed: -10.f, WithinAbs(-10.f, 0.5f) for: -10.0f is within 0.5 of -10.0
Matchers.tests.cpp:<line number>: passed: -10.f, WithinAbs(-9.6f, 0.5f) for: -10.0f is within 0.5 of -9.6000003815
-Matchers.tests.cpp:<line number>: passed: 1.f, WithinULP(1.f, 0) for: 1.0f is within 0 ULPs of 1.0f
-Matchers.tests.cpp:<line number>: passed: nextafter(1.f, 2.f), WithinULP(1.f, 1) for: 1.0f is within 1 ULPs of 1.0f
-Matchers.tests.cpp:<line number>: passed: nextafter(1.f, 0.f), WithinULP(1.f, 1) for: 1.0f is within 1 ULPs of 1.0f
-Matchers.tests.cpp:<line number>: passed: nextafter(1.f, 2.f), !WithinULP(1.f, 0) for: 1.0f not is within 0 ULPs of 1.0f
-Matchers.tests.cpp:<line number>: passed: 1.f, WithinULP(1.f, 0) for: 1.0f is within 0 ULPs of 1.0f
-Matchers.tests.cpp:<line number>: passed: -0.f, WithinULP(0.f, 0) for: -0.0f is within 0 ULPs of 0.0f
-Matchers.tests.cpp:<line number>: passed: NAN, !WithinULP(NAN, 123) for: nanf not is within 123 ULPs of nanf
-Matchers.tests.cpp:<line number>: 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:<line number>: 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:<line number>: 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:<line number>: passed: 1.f, WithinULP(1.f, 0) for: 1.0f is within 0 ULPs of 1.00000000e+00f ([1.00000000e+00, 1.00000000e+00])
+Matchers.tests.cpp:<line number>: passed: nextafter(1.f, 2.f), WithinULP(1.f, 1) for: 1.0f is within 1 ULPs of 1.00000000e+00f ([9.99999940e-01, 1.00000012e+00])
+Matchers.tests.cpp:<line number>: passed: 0.f, WithinULP(nextafter(0.f, 1.f), 1) for: 0.0f is within 1 ULPs of 1.40129846e-45f ([0.00000000e+00, 2.80259693e-45])
+Matchers.tests.cpp:<line number>: passed: 1.f, WithinULP(nextafter(1.f, 0.f), 1) for: 1.0f is within 1 ULPs of 9.99999940e-01f ([9.99999881e-01, 1.00000000e+00])
+Matchers.tests.cpp:<line number>: passed: 1.f, !WithinULP(nextafter(1.f, 2.f), 0) for: 1.0f not is within 0 ULPs of 1.00000012e+00f ([1.00000012e+00, 1.00000012e+00])
+Matchers.tests.cpp:<line number>: passed: 1.f, WithinULP(1.f, 0) for: 1.0f is within 0 ULPs of 1.00000000e+00f ([1.00000000e+00, 1.00000000e+00])
+Matchers.tests.cpp:<line number>: passed: -0.f, WithinULP(0.f, 0) for: -0.0f is within 0 ULPs of 0.00000000e+00f ([0.00000000e+00, 0.00000000e+00])
+Matchers.tests.cpp:<line number>: 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.00000000e+00f ([9.99999940e-01, 1.00000012e+00]) )
+Matchers.tests.cpp:<line number>: 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.00000000e+00f ([1.00000000e+00, 1.00000000e+00]) )
+Matchers.tests.cpp:<line number>: passed: 0.0001f, WithinAbs(0.f, 0.001f) || WithinRel(0.f, 0.1f) for: 0.0001f ( is within 0.001 of 0.0 or and 0 are within 10% of each other )
Matchers.tests.cpp:<line number>: passed: WithinAbs(1.f, 0.f)
Matchers.tests.cpp:<line number>: passed: WithinAbs(1.f, -1.f), std::domain_error
Matchers.tests.cpp:<line number>: passed: WithinULP(1.f, 0)
-Matchers.tests.cpp:<line number>: passed: WithinULP(1.f, -1), std::domain_error
+Matchers.tests.cpp:<line number>: passed: WithinULP(1.f, static_cast<uint64_t>(-1)), std::domain_error
+Matchers.tests.cpp:<line number>: passed: WithinRel(1.f, 0.f)
+Matchers.tests.cpp:<line number>: passed: WithinRel(1.f, -0.2f), std::domain_error
+Matchers.tests.cpp:<line number>: passed: WithinRel(1.f, 1.f), std::domain_error
Generators.tests.cpp:<line number>: passed: i % 2 == 0 for: 0 == 0
Generators.tests.cpp:<line number>: passed: i % 2 == 0 for: 0 == 0
Generators.tests.cpp:<line number>: passed: i % 2 == 0 for: 0 == 0
@@ -440,6 +507,9 @@ Generators.tests.cpp:<line number>: passed: chunk2.front() < 3 for: 1 < 3
Generators.tests.cpp:<line number>: passed: chunk2.size() == 2 for: 2 == 2
Generators.tests.cpp:<line number>: passed: chunk2.front() == chunk2.back() for: 2 == 2
Generators.tests.cpp:<line number>: passed: chunk2.front() < 3 for: 2 < 3
+Generators.tests.cpp:<line number>: passed: chunk2.size() == 0 for: 0 == 0
+Generators.tests.cpp:<line number>: passed: chunk2.size() == 0 for: 0 == 0
+Generators.tests.cpp:<line number>: passed: chunk2.size() == 0 for: 0 == 0
Generators.tests.cpp:<line number>: passed: chunk(2, value(1)), Catch::GeneratorException
Generators.tests.cpp:<line number>: passed: j < i for: -3 < 1
Generators.tests.cpp:<line number>: passed: j < i for: -2 < 1
@@ -563,6 +633,74 @@ GeneratorsImpl.tests.cpp:<line number>: passed: gen.get() == 2 for: 2 == 2
GeneratorsImpl.tests.cpp:<line number>: passed: gen.next() for: true
GeneratorsImpl.tests.cpp:<line number>: passed: gen.get() == 5 for: 5 == 5
GeneratorsImpl.tests.cpp:<line number>: passed: !(gen.next()) for: !false
+GeneratorsImpl.tests.cpp:<line number>: passed: gen.get() == Approx(expected) for: -1.0 == Approx( -1.0 ) with 1 message: 'Current expected value is -1'
+GeneratorsImpl.tests.cpp:<line number>: passed: gen.next() for: true with 1 message: 'Current expected value is -1'
+GeneratorsImpl.tests.cpp:<line number>: passed: gen.get() == Approx(expected) for: -0.9 == Approx( -0.9 ) with 1 message: 'Current expected value is -0.9'
+GeneratorsImpl.tests.cpp:<line number>: passed: gen.next() for: true with 1 message: 'Current expected value is -0.9'
+GeneratorsImpl.tests.cpp:<line number>: passed: gen.get() == Approx(expected) for: -0.8 == Approx( -0.8 ) with 1 message: 'Current expected value is -0.8'
+GeneratorsImpl.tests.cpp:<line number>: passed: gen.next() for: true with 1 message: 'Current expected value is -0.8'
+GeneratorsImpl.tests.cpp:<line number>: passed: gen.get() == Approx(expected) for: -0.7 == Approx( -0.7 ) with 1 message: 'Current expected value is -0.7'
+GeneratorsImpl.tests.cpp:<line number>: passed: gen.next() for: true with 1 message: 'Current expected value is -0.7'
+GeneratorsImpl.tests.cpp:<line number>: passed: gen.get() == Approx(expected) for: -0.6 == Approx( -0.6 ) with 1 message: 'Current expected value is -0.6'
+GeneratorsImpl.tests.cpp:<line number>: passed: gen.next() for: true with 1 message: 'Current expected value is -0.6'
+GeneratorsImpl.tests.cpp:<line number>: passed: gen.get() == Approx(expected) for: -0.5 == Approx( -0.5 ) with 1 message: 'Current expected value is -0.5'
+GeneratorsImpl.tests.cpp:<line number>: passed: gen.next() for: true with 1 message: 'Current expected value is -0.5'
+GeneratorsImpl.tests.cpp:<line number>: passed: gen.get() == Approx(expected) for: -0.4 == Approx( -0.4 ) with 1 message: 'Current expected value is -0.4'
+GeneratorsImpl.tests.cpp:<line number>: passed: gen.next() for: true with 1 message: 'Current expected value is -0.4'
+GeneratorsImpl.tests.cpp:<line number>: passed: gen.get() == Approx(expected) for: -0.3 == Approx( -0.3 ) with 1 message: 'Current expected value is -0.3'
+GeneratorsImpl.tests.cpp:<line number>: passed: gen.next() for: true with 1 message: 'Current expected value is -0.3'
+GeneratorsImpl.tests.cpp:<line number>: passed: gen.get() == Approx(expected) for: -0.2 == Approx( -0.2 ) with 1 message: 'Current expected value is -0.2'
+GeneratorsImpl.tests.cpp:<line number>: passed: gen.next() for: true with 1 message: 'Current expected value is -0.2'
+GeneratorsImpl.tests.cpp:<line number>: passed: gen.get() == Approx(expected) for: -0.1 == Approx( -0.1 ) with 1 message: 'Current expected value is -0.1'
+GeneratorsImpl.tests.cpp:<line number>: passed: gen.next() for: true with 1 message: 'Current expected value is -0.1'
+GeneratorsImpl.tests.cpp:<line number>: passed: gen.get() == Approx(expected) for: -0.0 == Approx( -0.0 ) with 1 message: 'Current expected value is -1.38778e-16'
+GeneratorsImpl.tests.cpp:<line number>: passed: gen.next() for: true with 1 message: 'Current expected value is -1.38778e-16'
+GeneratorsImpl.tests.cpp:<line number>: passed: gen.get() == Approx(expected) for: 0.1 == Approx( 0.1 ) with 1 message: 'Current expected value is 0.1'
+GeneratorsImpl.tests.cpp:<line number>: passed: gen.next() for: true with 1 message: 'Current expected value is 0.1'
+GeneratorsImpl.tests.cpp:<line number>: passed: gen.get() == Approx(expected) for: 0.2 == Approx( 0.2 ) with 1 message: 'Current expected value is 0.2'
+GeneratorsImpl.tests.cpp:<line number>: passed: gen.next() for: true with 1 message: 'Current expected value is 0.2'
+GeneratorsImpl.tests.cpp:<line number>: passed: gen.get() == Approx(expected) for: 0.3 == Approx( 0.3 ) with 1 message: 'Current expected value is 0.3'
+GeneratorsImpl.tests.cpp:<line number>: passed: gen.next() for: true with 1 message: 'Current expected value is 0.3'
+GeneratorsImpl.tests.cpp:<line number>: passed: gen.get() == Approx(expected) for: 0.4 == Approx( 0.4 ) with 1 message: 'Current expected value is 0.4'
+GeneratorsImpl.tests.cpp:<line number>: passed: gen.next() for: true with 1 message: 'Current expected value is 0.4'
+GeneratorsImpl.tests.cpp:<line number>: passed: gen.get() == Approx(expected) for: 0.5 == Approx( 0.5 ) with 1 message: 'Current expected value is 0.5'
+GeneratorsImpl.tests.cpp:<line number>: passed: gen.next() for: true with 1 message: 'Current expected value is 0.5'
+GeneratorsImpl.tests.cpp:<line number>: passed: gen.get() == Approx(expected) for: 0.6 == Approx( 0.6 ) with 1 message: 'Current expected value is 0.6'
+GeneratorsImpl.tests.cpp:<line number>: passed: gen.next() for: true with 1 message: 'Current expected value is 0.6'
+GeneratorsImpl.tests.cpp:<line number>: passed: gen.get() == Approx(expected) for: 0.7 == Approx( 0.7 ) with 1 message: 'Current expected value is 0.7'
+GeneratorsImpl.tests.cpp:<line number>: passed: gen.next() for: true with 1 message: 'Current expected value is 0.7'
+GeneratorsImpl.tests.cpp:<line number>: passed: gen.get() == Approx(expected) for: 0.8 == Approx( 0.8 ) with 1 message: 'Current expected value is 0.8'
+GeneratorsImpl.tests.cpp:<line number>: passed: gen.next() for: true with 1 message: 'Current expected value is 0.8'
+GeneratorsImpl.tests.cpp:<line number>: passed: gen.get() == Approx(expected) for: 0.9 == Approx( 0.9 ) with 1 message: 'Current expected value is 0.9'
+GeneratorsImpl.tests.cpp:<line number>: passed: gen.next() for: true with 1 message: 'Current expected value is 0.9'
+GeneratorsImpl.tests.cpp:<line number>: passed: gen.get() == Approx( rangeEnd ) for: 1.0 == Approx( 1.0 )
+GeneratorsImpl.tests.cpp:<line number>: passed: !(gen.next()) for: !false
+GeneratorsImpl.tests.cpp:<line number>: passed: gen.get() == Approx(expected) for: -1.0 == Approx( -1.0 ) with 1 message: 'Current expected value is -1'
+GeneratorsImpl.tests.cpp:<line number>: passed: gen.next() for: true with 1 message: 'Current expected value is -1'
+GeneratorsImpl.tests.cpp:<line number>: passed: gen.get() == Approx(expected) for: -0.7 == Approx( -0.7 ) with 1 message: 'Current expected value is -0.7'
+GeneratorsImpl.tests.cpp:<line number>: passed: gen.next() for: true with 1 message: 'Current expected value is -0.7'
+GeneratorsImpl.tests.cpp:<line number>: passed: gen.get() == Approx(expected) for: -0.4 == Approx( -0.4 ) with 1 message: 'Current expected value is -0.4'
+GeneratorsImpl.tests.cpp:<line number>: passed: gen.next() for: true with 1 message: 'Current expected value is -0.4'
+GeneratorsImpl.tests.cpp:<line number>: passed: gen.get() == Approx(expected) for: -0.1 == Approx( -0.1 ) with 1 message: 'Current expected value is -0.1'
+GeneratorsImpl.tests.cpp:<line number>: passed: gen.next() for: true with 1 message: 'Current expected value is -0.1'
+GeneratorsImpl.tests.cpp:<line number>: passed: gen.get() == Approx(expected) for: 0.2 == Approx( 0.2 ) with 1 message: 'Current expected value is 0.2'
+GeneratorsImpl.tests.cpp:<line number>: passed: gen.next() for: true with 1 message: 'Current expected value is 0.2'
+GeneratorsImpl.tests.cpp:<line number>: passed: gen.get() == Approx(expected) for: 0.5 == Approx( 0.5 ) with 1 message: 'Current expected value is 0.5'
+GeneratorsImpl.tests.cpp:<line number>: passed: gen.next() for: true with 1 message: 'Current expected value is 0.5'
+GeneratorsImpl.tests.cpp:<line number>: passed: !(gen.next()) for: !false
+GeneratorsImpl.tests.cpp:<line number>: passed: gen.get() == Approx(expected) for: -1.0 == Approx( -1.0 ) with 1 message: 'Current expected value is -1'
+GeneratorsImpl.tests.cpp:<line number>: passed: gen.next() for: true with 1 message: 'Current expected value is -1'
+GeneratorsImpl.tests.cpp:<line number>: passed: gen.get() == Approx(expected) for: -0.7 == Approx( -0.7 ) with 1 message: 'Current expected value is -0.7'
+GeneratorsImpl.tests.cpp:<line number>: passed: gen.next() for: true with 1 message: 'Current expected value is -0.7'
+GeneratorsImpl.tests.cpp:<line number>: passed: gen.get() == Approx(expected) for: -0.4 == Approx( -0.4 ) with 1 message: 'Current expected value is -0.4'
+GeneratorsImpl.tests.cpp:<line number>: passed: gen.next() for: true with 1 message: 'Current expected value is -0.4'
+GeneratorsImpl.tests.cpp:<line number>: passed: gen.get() == Approx(expected) for: -0.1 == Approx( -0.1 ) with 1 message: 'Current expected value is -0.1'
+GeneratorsImpl.tests.cpp:<line number>: passed: gen.next() for: true with 1 message: 'Current expected value is -0.1'
+GeneratorsImpl.tests.cpp:<line number>: passed: gen.get() == Approx(expected) for: 0.2 == Approx( 0.2 ) with 1 message: 'Current expected value is 0.2'
+GeneratorsImpl.tests.cpp:<line number>: passed: gen.next() for: true with 1 message: 'Current expected value is 0.2'
+GeneratorsImpl.tests.cpp:<line number>: passed: gen.get() == Approx(expected) for: 0.5 == Approx( 0.5 ) with 1 message: 'Current expected value is 0.5'
+GeneratorsImpl.tests.cpp:<line number>: passed: gen.next() for: true with 1 message: 'Current expected value is 0.5'
+GeneratorsImpl.tests.cpp:<line number>: passed: !(gen.next()) for: !false
GeneratorsImpl.tests.cpp:<line number>: passed: gen.get() == 5 for: 5 == 5
GeneratorsImpl.tests.cpp:<line number>: passed: gen.next() for: true
GeneratorsImpl.tests.cpp:<line number>: passed: gen.get() == 2 for: 2 == 2
@@ -699,6 +837,51 @@ Condition.tests.cpp:<line number>: passed: data.str_hello < "hellp" for: "hello"
Condition.tests.cpp:<line number>: passed: data.str_hello < "zebra" for: "hello" < "zebra"
Condition.tests.cpp:<line number>: passed: data.str_hello > "hellm" for: "hello" > "hellm"
Condition.tests.cpp:<line number>: passed: data.str_hello > "a" for: "hello" > "a"
+RandomNumberGeneration.tests.cpp:<line number>: passed: rng() == 0x<hex digits> for: 4242248763 (0x<hex digits>)
+==
+4242248763 (0x<hex digits>)
+RandomNumberGeneration.tests.cpp:<line number>: passed: rng() == 0x<hex digits> for: 1867888929 (0x<hex digits>)
+==
+1867888929 (0x<hex digits>)
+RandomNumberGeneration.tests.cpp:<line number>: passed: rng() == 0x<hex digits> for: 1276619030 (0x<hex digits>)
+==
+1276619030 (0x<hex digits>)
+RandomNumberGeneration.tests.cpp:<line number>: passed: rng() == 0x<hex digits> for: 1911218783 (0x<hex digits>)
+==
+1911218783 (0x<hex digits>)
+RandomNumberGeneration.tests.cpp:<line number>: passed: rng() == 0x<hex digits> for: 1827115164 (0x<hex digits>)
+==
+1827115164 (0x<hex digits>)
+RandomNumberGeneration.tests.cpp:<line number>: passed: rng() == 0x<hex digits> for: 1472234645 (0x<hex digits>)
+==
+1472234645 (0x<hex digits>)
+RandomNumberGeneration.tests.cpp:<line number>: passed: rng() == 0x<hex digits> for: 868832940 (0x<hex digits>)
+==
+868832940 (0x<hex digits>)
+RandomNumberGeneration.tests.cpp:<line number>: passed: rng() == 0x<hex digits> for: 570883446 (0x<hex digits>)
+==
+570883446 (0x<hex digits>)
+RandomNumberGeneration.tests.cpp:<line number>: passed: rng() == 0x<hex digits> for: 889299803 (0x<hex digits>)
+==
+889299803 (0x<hex digits>)
+RandomNumberGeneration.tests.cpp:<line number>: passed: rng() == 0x<hex digits> for: 4261393167 (0x<hex digits>)
+==
+4261393167 (0x<hex digits>)
+RandomNumberGeneration.tests.cpp:<line number>: passed: rng() == 0x<hex digits> for: 1472234645 (0x<hex digits>)
+==
+1472234645 (0x<hex digits>)
+RandomNumberGeneration.tests.cpp:<line number>: passed: rng() == 0x<hex digits> for: 868832940 (0x<hex digits>)
+==
+868832940 (0x<hex digits>)
+RandomNumberGeneration.tests.cpp:<line number>: passed: rng() == 0x<hex digits> for: 570883446 (0x<hex digits>)
+==
+570883446 (0x<hex digits>)
+RandomNumberGeneration.tests.cpp:<line number>: passed: rng() == 0x<hex digits> for: 889299803 (0x<hex digits>)
+==
+889299803 (0x<hex digits>)
+RandomNumberGeneration.tests.cpp:<line number>: passed: rng() == 0x<hex digits> for: 4261393167 (0x<hex digits>)
+==
+4261393167 (0x<hex digits>)
Message.tests.cpp:<line number>: failed: explicitly with 1 message: 'Message from section one'
Message.tests.cpp:<line number>: failed: explicitly with 1 message: 'Message from section two'
CmdLine.tests.cpp:<line number>: passed: spec.hasFilters() == false for: false == false
@@ -836,6 +1019,22 @@ CmdLine.tests.cpp:<line number>: passed: spec.matches( tcA ) == false for: false
CmdLine.tests.cpp:<line number>: passed: spec.matches( tcB ) == false for: false == false
CmdLine.tests.cpp:<line number>: passed: spec.matches( tcC ) == false for: false == false
CmdLine.tests.cpp:<line number>: passed: spec.matches( tcD ) == true for: true == true
+CmdLine.tests.cpp:<line number>: passed: spec.matches( fakeTestCase( " aardvark " ) ) for: true
+CmdLine.tests.cpp:<line number>: passed: spec.matches( fakeTestCase( " aardvark" ) ) for: true
+CmdLine.tests.cpp:<line number>: passed: spec.matches( fakeTestCase( " aardvark " ) ) for: true
+CmdLine.tests.cpp:<line number>: passed: spec.matches( fakeTestCase( "aardvark " ) ) for: true
+CmdLine.tests.cpp:<line number>: passed: spec.matches( fakeTestCase( "aardvark" ) ) for: true
+CmdLine.tests.cpp:<line number>: passed: spec.matches( fakeTestCase( " aardvark " ) ) for: true
+CmdLine.tests.cpp:<line number>: passed: spec.matches( fakeTestCase( " aardvark" ) ) for: true
+CmdLine.tests.cpp:<line number>: passed: spec.matches( fakeTestCase( " aardvark " ) ) for: true
+CmdLine.tests.cpp:<line number>: passed: spec.matches( fakeTestCase( "aardvark " ) ) for: true
+CmdLine.tests.cpp:<line number>: passed: spec.matches( fakeTestCase( "aardvark" ) ) for: true
+CmdLine.tests.cpp:<line number>: passed: spec.matches(fakeTestCase("hidden and foo", "[.][foo]")) for: true
+CmdLine.tests.cpp:<line number>: passed: !(spec.matches(fakeTestCase("only foo", "[foo]"))) for: !false
+CmdLine.tests.cpp:<line number>: passed: !(spec.matches(fakeTestCase("hidden and foo", "[.][foo]"))) for: !false
+CmdLine.tests.cpp:<line number>: passed: !(spec.matches(fakeTestCase("only foo", "[foo]"))) for: !false
+CmdLine.tests.cpp:<line number>: passed: !(spec.matches(fakeTestCase("only hidden", "[.]"))) for: !false
+CmdLine.tests.cpp:<line number>: passed: spec.matches(fakeTestCase("neither foo nor hidden", "[bar]")) for: true
Condition.tests.cpp:<line number>: passed: p == 0 for: 0 == 0
Condition.tests.cpp:<line number>: passed: p == pNULL for: 0 == 0
Condition.tests.cpp:<line number>: passed: p != 0 for: 0x<hex digits> != 0
@@ -844,6 +1043,10 @@ Condition.tests.cpp:<line number>: passed: cpc != 0 for: 0x<hex digits> != 0
Condition.tests.cpp:<line number>: passed: returnsNull() == 0 for: {null string} == 0
Condition.tests.cpp:<line number>: passed: returnsConstNull() == 0 for: {null string} == 0
Condition.tests.cpp:<line number>: passed: 0 != p for: 0 != 0x<hex digits>
+ToStringGeneral.tests.cpp:<line number>: passed: str1.size() == 3 + 5 for: 8 == 8
+ToStringGeneral.tests.cpp:<line number>: passed: str2.size() == 3 + 10 for: 13 == 13
+ToStringGeneral.tests.cpp:<line number>: passed: str1.size() == 2 + 5 for: 7 == 7
+ToStringGeneral.tests.cpp:<line number>: passed: str2.size() == 2 + 15 for: 17 == 17
Matchers.tests.cpp:<line number>: passed: "foo", Predicate<const char*>([] (const char* const&) { return true; }) for: "foo" matches undescribed predicate
CmdLine.tests.cpp:<line number>: passed: result for: {?}
CmdLine.tests.cpp:<line number>: passed: config.processName == "" for: "" == ""
@@ -885,6 +1088,16 @@ CmdLine.tests.cpp:<line number>: passed: cli.parse({"test", "-x", "2"}) for: {?}
CmdLine.tests.cpp:<line number>: passed: config.abortAfter == 2 for: 2 == 2
CmdLine.tests.cpp:<line number>: passed: !result for: true
CmdLine.tests.cpp:<line number>: passed: result.errorMessage(), Contains("convert") && Contains("oops") for: "Unable to convert 'oops' to destination type" ( contains: "convert" and contains: "oops" )
+CmdLine.tests.cpp:<line number>: passed: cli.parse({"test", "--wait-for-keypress", std::get<0>(input)}) for: {?}
+CmdLine.tests.cpp:<line number>: passed: config.waitForKeypress == std::get<1>(input) for: 0 == 0
+CmdLine.tests.cpp:<line number>: passed: cli.parse({"test", "--wait-for-keypress", std::get<0>(input)}) for: {?}
+CmdLine.tests.cpp:<line number>: passed: config.waitForKeypress == std::get<1>(input) for: 1 == 1
+CmdLine.tests.cpp:<line number>: passed: cli.parse({"test", "--wait-for-keypress", std::get<0>(input)}) for: {?}
+CmdLine.tests.cpp:<line number>: passed: config.waitForKeypress == std::get<1>(input) for: 2 == 2
+CmdLine.tests.cpp:<line number>: passed: cli.parse({"test", "--wait-for-keypress", std::get<0>(input)}) for: {?}
+CmdLine.tests.cpp:<line number>: passed: config.waitForKeypress == std::get<1>(input) for: 3 == 3
+CmdLine.tests.cpp:<line number>: passed: !result for: true
+CmdLine.tests.cpp:<line number>: passed: result.errorMessage(), Contains("never") && Contains("both") for: "keypress argument must be one of: never, start, exit or both. 'sometimes' not recognised" ( contains: "never" and contains: "both" )
CmdLine.tests.cpp:<line number>: passed: cli.parse({"test", "-e"}) for: {?}
CmdLine.tests.cpp:<line number>: passed: config.noThrow for: true
CmdLine.tests.cpp:<line number>: passed: cli.parse({"test", "--nothrow"}) for: {?}
@@ -907,6 +1120,16 @@ CmdLine.tests.cpp:<line number>: passed: cli.parse({"test", "--use-colour", "no"
CmdLine.tests.cpp:<line number>: passed: config.useColour == UseColour::No for: 2 == 2
CmdLine.tests.cpp:<line number>: passed: !result for: true
CmdLine.tests.cpp:<line number>: 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"
+CmdLine.tests.cpp:<line number>: passed: cli.parse({ "test", "--benchmark-samples=200" }) for: {?}
+CmdLine.tests.cpp:<line number>: passed: config.benchmarkSamples == 200 for: 200 == 200
+CmdLine.tests.cpp:<line number>: passed: cli.parse({ "test", "--benchmark-resamples=20000" }) for: {?}
+CmdLine.tests.cpp:<line number>: passed: config.benchmarkResamples == 20000 for: 20000 (0x<hex digits>) == 20000 (0x<hex digits>)
+CmdLine.tests.cpp:<line number>: passed: cli.parse({ "test", "--benchmark-confidence-interval=0.99" }) for: {?}
+CmdLine.tests.cpp:<line number>: passed: config.benchmarkConfidenceInterval == Catch::Detail::Approx(0.99) for: 0.99 == Approx( 0.99 )
+CmdLine.tests.cpp:<line number>: passed: cli.parse({ "test", "--benchmark-no-analysis" }) for: {?}
+CmdLine.tests.cpp:<line number>: passed: config.benchmarkNoAnalysis for: true
+CmdLine.tests.cpp:<line number>: passed: cli.parse({ "test", "--benchmark-warmup-time=10" }) for: {?}
+CmdLine.tests.cpp:<line number>: passed: config.benchmarkWarmupTime == 10 for: 10 == 10
Misc.tests.cpp:<line number>: passed: std::tuple_size<TestType>::value >= 1 for: 3 >= 1
Misc.tests.cpp:<line number>: passed: std::tuple_size<TestType>::value >= 1 for: 2 >= 1
Misc.tests.cpp:<line number>: passed: std::tuple_size<TestType>::value >= 1 for: 1 >= 1
@@ -941,7 +1164,6 @@ Approx.tests.cpp:<line number>: passed: d != 1.22_a for: 1.23 != Approx( 1.22 )
Approx.tests.cpp:<line number>: passed: Approx( d ) == 1.23 for: Approx( 1.23 ) == 1.23
Approx.tests.cpp:<line number>: passed: Approx( d ) != 1.22 for: Approx( 1.23 ) != 1.22
Approx.tests.cpp:<line number>: passed: Approx( d ) != 1.24 for: Approx( 1.23 ) != 1.24
-Approx.tests.cpp:<line number>: passed: INFINITY == Approx(INFINITY) for: inff == Approx( inf )
Message from section one
Message from section two
Matchers.tests.cpp:<line number>: failed: testStringForMatching(), StartsWith("This String") for: "this string contains 'abc' as a substring" starts with: "This String"
@@ -961,36 +1183,32 @@ Matchers.tests.cpp:<line number>: passed: testStringForMatching(), EndsWith("sub
Matchers.tests.cpp:<line number>: passed: testStringForMatching(), EndsWith(" SuBsTrInG", Catch::CaseSensitive::No) for: "this string contains 'abc' as a substring" ends with: " substring" (case insensitive)
String.tests.cpp:<line number>: passed: empty.empty() for: true
String.tests.cpp:<line number>: passed: empty.size() == 0 for: 0 == 0
+String.tests.cpp:<line number>: passed: empty.isNullTerminated() for: true
String.tests.cpp:<line number>: passed: std::strcmp( empty.c_str(), "" ) == 0 for: 0 == 0
String.tests.cpp:<line number>: passed: s.empty() == false for: false == false
String.tests.cpp:<line number>: passed: s.size() == 5 for: 5 == 5
-String.tests.cpp:<line number>: passed: isSubstring( s ) == false for: false == false
+String.tests.cpp:<line number>: passed: s.isNullTerminated() for: true
String.tests.cpp:<line number>: passed: std::strcmp( rawChars, "hello" ) == 0 for: 0 == 0
-String.tests.cpp:<line number>: passed: isOwned( s ) == false for: false == false
+String.tests.cpp:<line number>: passed: s.c_str()
String.tests.cpp:<line number>: passed: s.c_str() == rawChars for: "hello" == "hello"
-String.tests.cpp:<line number>: passed: isOwned( s ) == false for: false == false
+String.tests.cpp:<line number>: passed: s.data() == rawChars for: "hello" == "hello"
String.tests.cpp:<line number>: passed: original == "original"
-String.tests.cpp:<line number>: passed: isSubstring( original ) for: true
-String.tests.cpp:<line number>: passed: isOwned( original ) == false for: false == false
-String.tests.cpp:<line number>: passed: isSubstring( original ) == false for: false == false
-String.tests.cpp:<line number>: passed: isOwned( original ) for: true
+String.tests.cpp:<line number>: passed: !(original.isNullTerminated()) for: !false
+String.tests.cpp:<line number>: passed: original.c_str()
+String.tests.cpp:<line number>: passed: original.data()
String.tests.cpp:<line number>: passed: ss.empty() == false for: false == false
String.tests.cpp:<line number>: passed: ss.size() == 5 for: 5 == 5
-String.tests.cpp:<line number>: passed: std::strcmp( ss.c_str(), "hello" ) == 0 for: 0 == 0
+String.tests.cpp:<line number>: passed: std::strncmp( ss.data(), "hello", 5 ) == 0 for: 0 == 0
String.tests.cpp:<line number>: passed: ss == "hello" for: hello == "hello"
-String.tests.cpp:<line number>: passed: isSubstring( ss ) for: true
-String.tests.cpp:<line number>: passed: isOwned( ss ) == false for: false == false
-String.tests.cpp:<line number>: passed: rawChars == s.currentData() for: "hello world!" == "hello world!"
-String.tests.cpp:<line number>: passed: ss.c_str() != rawChars for: "hello" != "hello world!"
-String.tests.cpp:<line number>: passed: isSubstring( ss ) == false for: false == false
-String.tests.cpp:<line number>: passed: isOwned( ss ) for: true
-String.tests.cpp:<line number>: passed: ss.currentData() != s.currentData() for: "hello" != "hello world!"
String.tests.cpp:<line number>: passed: ss.size() == 6 for: 6 == 6
String.tests.cpp:<line number>: passed: std::strcmp( ss.c_str(), "world!" ) == 0 for: 0 == 0
-String.tests.cpp:<line number>: passed: s.c_str() == s2.c_str() for: "hello world!" == "hello world!"
-String.tests.cpp:<line number>: passed: s.c_str() != ss.c_str() for: "hello world!" != "hello"
-String.tests.cpp:<line number>: passed: StringRef("hello") == StringRef("hello") for: hello == hello
-String.tests.cpp:<line number>: passed: StringRef("hello") != StringRef("cello") for: hello != cello
+String.tests.cpp:<line number>: passed: s.data() == s2.data() for: "hello world!" == "hello world!"
+String.tests.cpp:<line number>: passed: s.data() == ss.data() for: "hello world!" == "hello world!"
+String.tests.cpp:<line number>: passed: s.substr(s.size() + 1, 123).empty() for: true
+String.tests.cpp:<line number>: passed: std::strcmp(ss.c_str(), "world!") == 0 for: 0 == 0
+String.tests.cpp:<line number>: passed: (char*)buffer1 != (char*)buffer2 for: "Hello" != "Hello"
+String.tests.cpp:<line number>: passed: left == right for: Hello == Hello
+String.tests.cpp:<line number>: passed: left != left.substr(0, 3) for: Hello != Hel
String.tests.cpp:<line number>: passed: sr == "a standard string" for: a standard string == "a standard string"
String.tests.cpp:<line number>: passed: sr.size() == stdStr.size() for: 17 == 17
String.tests.cpp:<line number>: passed: sr == "a standard string" for: a standard string == "a standard string"
@@ -1001,11 +1219,17 @@ String.tests.cpp:<line number>: passed: stdStr == "a stringref" for: "a stringre
String.tests.cpp:<line number>: passed: stdStr.size() == sr.size() for: 11 == 11
String.tests.cpp:<line number>: passed: stdStr == "a stringref" for: "a stringref" == "a stringref"
String.tests.cpp:<line number>: passed: stdStr.size() == sr.size() for: 11 == 11
-String.tests.cpp:<line number>: passed: stdStr == "a stringref" for: "a stringref" == "a stringref"
-String.tests.cpp:<line number>: passed: stdStr.size() == sr.size() for: 11 == 11
-String.tests.cpp:<line number>: passed: ascii.numberOfCharacters() == ascii.size() for: 39 == 39
-String.tests.cpp:<line number>: passed: simpleu8.numberOfCharacters() == 30 for: 30 == 30
-String.tests.cpp:<line number>: passed: emojis.numberOfCharacters() == 9 for: 9 == 9
+String.tests.cpp:<line number>: passed: with 1 message: 'StringRef{}.size() == 0'
+String.tests.cpp:<line number>: passed: with 1 message: 'StringRef{ "abc", 3 }.size() == 3'
+String.tests.cpp:<line number>: passed: with 1 message: 'StringRef{ "abc", 3 }.isNullTerminated()'
+String.tests.cpp:<line number>: passed: with 1 message: 'StringRef{ "abc", 2 }.size() == 2'
+String.tests.cpp:<line number>: passed: with 1 message: '!(StringRef{ "abc", 2 }.isNullTerminated())'
+String.tests.cpp:<line number>: passed: with 1 message: '!(sr1.empty())'
+String.tests.cpp:<line number>: passed: with 1 message: 'sr1.size() == 3'
+String.tests.cpp:<line number>: passed: with 1 message: 'sr1.isNullTerminated()'
+String.tests.cpp:<line number>: passed: with 1 message: 'sr2.empty()'
+String.tests.cpp:<line number>: passed: with 1 message: 'sr2.size() == 0'
+String.tests.cpp:<line number>: passed: with 1 message: 'sr2.isNullTerminated()'
ToStringChrono.tests.cpp:<line number>: passed: minute == seconds for: 1 m == 60 s
ToStringChrono.tests.cpp:<line number>: passed: hour != seconds for: 1 h != 60 s
ToStringChrono.tests.cpp:<line number>: passed: micro != milli for: 1 us != 1 ms
@@ -1039,6 +1263,16 @@ Tag.tests.cpp:<line number>: passed: registry.add( "[no ampersat]", "", Catch::S
Tag.tests.cpp:<line number>: passed: registry.add( "[the @ is not at the start]", "", Catch::SourceLineInfo( "file", 3 ) )
Tag.tests.cpp:<line number>: passed: registry.add( "@no square bracket at start]", "", Catch::SourceLineInfo( "file", 3 ) )
Tag.tests.cpp:<line number>: passed: registry.add( "[@no square bracket at end", "", Catch::SourceLineInfo( "file", 3 ) )
+Class.tests.cpp:<line number>: passed: Template_Fixture<TestType>::m_a == 1 for: 1 == 1
+Class.tests.cpp:<line number>: passed: Template_Fixture<TestType>::m_a == 1 for: 1 == 1
+Class.tests.cpp:<line number>: passed: Template_Fixture<TestType>::m_a == 1 for: 1.0 == 1
+Misc.tests.cpp:<line number>: passed: sizeof(TestType) > 0 for: 1 > 0
+Misc.tests.cpp:<line number>: passed: sizeof(TestType) > 0 for: 4 > 0
+Misc.tests.cpp:<line number>: passed: sizeof(TestType) > 0 for: 1 > 0
+Misc.tests.cpp:<line number>: passed: sizeof(TestType) > 0 for: 4 > 0
+Misc.tests.cpp:<line number>: passed: sizeof(TestType) > 0 for: 4 > 0
+Misc.tests.cpp:<line number>: passed: sizeof(TestType) > 0 for: 1 > 0
+Misc.tests.cpp:<line number>: passed: sizeof(TestType) > 0 for: 4 > 0
Misc.tests.cpp:<line number>: passed: v.size() == 5 for: 5 == 5
Misc.tests.cpp:<line number>: passed: v.capacity() >= 5 for: 5 >= 5
Misc.tests.cpp:<line number>: passed: v.size() == 10 for: 10 == 10
@@ -1107,8 +1341,77 @@ Misc.tests.cpp:<line number>: passed: v.size() == 5 for: 5 == 5
Misc.tests.cpp:<line number>: passed: v.capacity() >= 5 for: 5 >= 5
Misc.tests.cpp:<line number>: passed: v.size() == 5 for: 5 == 5
Misc.tests.cpp:<line number>: passed: v.capacity() >= 5 for: 5 >= 5
+Misc.tests.cpp:<line number>: passed: v.size() == V for: 6 == 6
+Misc.tests.cpp:<line number>: passed: v.capacity() >= V for: 6 >= 6
+Misc.tests.cpp:<line number>: passed: v.size() == 2 * V for: 12 == 12
+Misc.tests.cpp:<line number>: passed: v.capacity() >= 2 * V for: 12 >= 12
+Misc.tests.cpp:<line number>: passed: v.size() == V for: 6 == 6
+Misc.tests.cpp:<line number>: passed: v.capacity() >= V for: 6 >= 6
+Misc.tests.cpp:<line number>: passed: v.size() == 0 for: 0 == 0
+Misc.tests.cpp:<line number>: passed: v.capacity() >= V for: 6 >= 6
+Misc.tests.cpp:<line number>: passed: v.capacity() == 0 for: 0 == 0
+Misc.tests.cpp:<line number>: passed: v.size() == V for: 6 == 6
+Misc.tests.cpp:<line number>: passed: v.capacity() >= V for: 6 >= 6
+Misc.tests.cpp:<line number>: passed: v.size() == V for: 6 == 6
+Misc.tests.cpp:<line number>: passed: v.capacity() >= 2 * V for: 12 >= 12
+Misc.tests.cpp:<line number>: passed: v.size() == V for: 6 == 6
+Misc.tests.cpp:<line number>: passed: v.capacity() >= V for: 6 >= 6
+Misc.tests.cpp:<line number>: passed: v.size() == V for: 6 == 6
+Misc.tests.cpp:<line number>: passed: v.capacity() >= V for: 6 >= 6
+Misc.tests.cpp:<line number>: passed: v.size() == V for: 4 == 4
+Misc.tests.cpp:<line number>: passed: v.capacity() >= V for: 4 >= 4
+Misc.tests.cpp:<line number>: passed: v.size() == 2 * V for: 8 == 8
+Misc.tests.cpp:<line number>: passed: v.capacity() >= 2 * V for: 8 >= 8
+Misc.tests.cpp:<line number>: passed: v.size() == V for: 4 == 4
+Misc.tests.cpp:<line number>: passed: v.capacity() >= V for: 4 >= 4
+Misc.tests.cpp:<line number>: passed: v.size() == 0 for: 0 == 0
+Misc.tests.cpp:<line number>: passed: v.capacity() >= V for: 4 >= 4
+Misc.tests.cpp:<line number>: passed: v.capacity() == 0 for: 0 == 0
+Misc.tests.cpp:<line number>: passed: v.size() == V for: 4 == 4
+Misc.tests.cpp:<line number>: passed: v.capacity() >= V for: 4 >= 4
+Misc.tests.cpp:<line number>: passed: v.size() == V for: 4 == 4
+Misc.tests.cpp:<line number>: passed: v.capacity() >= 2 * V for: 8 >= 8
+Misc.tests.cpp:<line number>: passed: v.size() == V for: 4 == 4
+Misc.tests.cpp:<line number>: passed: v.capacity() >= V for: 4 >= 4
+Misc.tests.cpp:<line number>: passed: v.size() == V for: 4 == 4
+Misc.tests.cpp:<line number>: passed: v.capacity() >= V for: 4 >= 4
+Misc.tests.cpp:<line number>: passed: v.size() == V for: 5 == 5
+Misc.tests.cpp:<line number>: passed: v.capacity() >= V for: 5 >= 5
+Misc.tests.cpp:<line number>: passed: v.size() == 2 * V for: 10 == 10
+Misc.tests.cpp:<line number>: passed: v.capacity() >= 2 * V for: 10 >= 10
+Misc.tests.cpp:<line number>: passed: v.size() == V for: 5 == 5
+Misc.tests.cpp:<line number>: passed: v.capacity() >= V for: 5 >= 5
+Misc.tests.cpp:<line number>: passed: v.size() == 0 for: 0 == 0
+Misc.tests.cpp:<line number>: passed: v.capacity() >= V for: 5 >= 5
+Misc.tests.cpp:<line number>: passed: v.capacity() == 0 for: 0 == 0
+Misc.tests.cpp:<line number>: passed: v.size() == V for: 5 == 5
+Misc.tests.cpp:<line number>: passed: v.capacity() >= V for: 5 >= 5
+Misc.tests.cpp:<line number>: passed: v.size() == V for: 5 == 5
+Misc.tests.cpp:<line number>: passed: v.capacity() >= 2 * V for: 10 >= 10
+Misc.tests.cpp:<line number>: passed: v.size() == V for: 5 == 5
+Misc.tests.cpp:<line number>: passed: v.capacity() >= V for: 5 >= 5
+Misc.tests.cpp:<line number>: passed: v.size() == V for: 5 == 5
+Misc.tests.cpp:<line number>: passed: v.capacity() >= V for: 5 >= 5
+Misc.tests.cpp:<line number>: passed: v.size() == V for: 15 == 15
+Misc.tests.cpp:<line number>: passed: v.capacity() >= V for: 15 >= 15
+Misc.tests.cpp:<line number>: passed: v.size() == 2 * V for: 30 == 30
+Misc.tests.cpp:<line number>: passed: v.capacity() >= 2 * V for: 30 >= 30
+Misc.tests.cpp:<line number>: passed: v.size() == V for: 15 == 15
+Misc.tests.cpp:<line number>: passed: v.capacity() >= V for: 15 >= 15
+Misc.tests.cpp:<line number>: passed: v.size() == 0 for: 0 == 0
+Misc.tests.cpp:<line number>: passed: v.capacity() >= V for: 15 >= 15
+Misc.tests.cpp:<line number>: passed: v.capacity() == 0 for: 0 == 0
+Misc.tests.cpp:<line number>: passed: v.size() == V for: 15 == 15
+Misc.tests.cpp:<line number>: passed: v.capacity() >= V for: 15 >= 15
+Misc.tests.cpp:<line number>: passed: v.size() == V for: 15 == 15
+Misc.tests.cpp:<line number>: passed: v.capacity() >= 2 * V for: 30 >= 30
+Misc.tests.cpp:<line number>: passed: v.size() == V for: 15 == 15
+Misc.tests.cpp:<line number>: passed: v.capacity() >= V for: 15 >= 15
+Misc.tests.cpp:<line number>: passed: v.size() == V for: 15 == 15
+Misc.tests.cpp:<line number>: passed: v.capacity() >= V for: 15 >= 15
VariadicMacros.tests.cpp:<line number>: passed: with 1 message: 'no assertions'
Tricky.tests.cpp:<line number>: passed: 0x<hex digits> == bit30and31 for: 3221225472 (0x<hex digits>) == 3221225472
+CmdLine.tests.cpp:<line number>: passed:
Message.tests.cpp:<line number>: failed - but was ok: 1 == 2
Misc.tests.cpp:<line number>: passed: with 1 message: 'oops!'
Exception.tests.cpp:<line number>: failed: unexpected exception with message: 'For some reason someone is throwing a string literal!'
@@ -1179,6 +1482,30 @@ PartTracker.tests.cpp:<line number>: passed: s1.isComplete() == false for: false
PartTracker.tests.cpp:<line number>: passed: s1.isComplete() for: true
PartTracker.tests.cpp:<line number>: passed: testCase.isComplete() == false for: false == false
PartTracker.tests.cpp:<line number>: passed: testCase.isComplete() for: true
+StringManip.tests.cpp:<line number>: passed: trim(std::string(no_whitespace)) == no_whitespace for: "There is no extra whitespace here"
+==
+"There is no extra whitespace here"
+StringManip.tests.cpp:<line number>: passed: trim(std::string(leading_whitespace)) == no_whitespace for: "There is no extra whitespace here"
+==
+"There is no extra whitespace here"
+StringManip.tests.cpp:<line number>: passed: trim(std::string(trailing_whitespace)) == no_whitespace for: "There is no extra whitespace here"
+==
+"There is no extra whitespace here"
+StringManip.tests.cpp:<line number>: passed: trim(std::string(whitespace_at_both_ends)) == no_whitespace for: "There is no extra whitespace here"
+==
+"There is no extra whitespace here"
+StringManip.tests.cpp:<line number>: passed: trim(StringRef(no_whitespace)) == StringRef(no_whitespace) for: There is no extra whitespace here
+==
+There is no extra whitespace here
+StringManip.tests.cpp:<line number>: passed: trim(StringRef(leading_whitespace)) == StringRef(no_whitespace) for: There is no extra whitespace here
+==
+There is no extra whitespace here
+StringManip.tests.cpp:<line number>: passed: trim(StringRef(trailing_whitespace)) == StringRef(no_whitespace) for: There is no extra whitespace here
+==
+There is no extra whitespace here
+StringManip.tests.cpp:<line number>: passed: trim(StringRef(whitespace_at_both_ends)) == StringRef(no_whitespace) for: There is no extra whitespace here
+==
+There is no extra whitespace here
Exception.tests.cpp:<line number>: failed: unexpected exception with message: '3.14'
Approx.tests.cpp:<line number>: passed: d == approx( 1.23 ) for: 1.23 == Approx( 1.23 )
Approx.tests.cpp:<line number>: passed: d == approx( 1.22 ) for: 1.23 == Approx( 1.22 )
@@ -1254,48 +1581,9 @@ Xml.tests.cpp:<line number>: passed: encode( stringWithQuotes, Catch::XmlEncode:
"don't &quot;quote&quot; me on that"
Xml.tests.cpp:<line number>: passed: encode( "[\x01]" ) == "[\\x01]" for: "[\x01]" == "[\x01]"
Xml.tests.cpp:<line number>: passed: encode( "[\x7F]" ) == "[\\x7F]" for: "[\x7F]" == "[\x7F]"
-Xml.tests.cpp:<line number>: passed: encode(u8"Here be 👾") == u8"Here be 👾" for: "Here be 👾" == "Here be 👾"
-Xml.tests.cpp:<line number>: passed: encode(u8"Å¡Å¡") == u8"Å¡Å¡" for: "Å¡Å¡" == "Å¡Å¡"
-Xml.tests.cpp:<line number>: passed: encode("\xDF\xBF") == "\xDF\xBF" for: "ß¿" == "ß¿"
-Xml.tests.cpp:<line number>: passed: encode("\xE0\xA0\x80") == "\xE0\xA0\x80" for: "à €" == "à €"
-Xml.tests.cpp:<line number>: passed: encode("\xED\x9F\xBF") == "\xED\x9F\xBF" for: "퟿" == "퟿"
-Xml.tests.cpp:<line number>: passed: encode("\xEE\x80\x80") == "\xEE\x80\x80" for: "" == ""
-Xml.tests.cpp:<line number>: passed: encode("\xEF\xBF\xBF") == "\xEF\xBF\xBF" for: "ï¿¿" == "ï¿¿"
-Xml.tests.cpp:<line number>: passed: encode("\xF0\x90\x80\x80") == "\xF0\x90\x80\x80" for: "ð€€" == "ð€€"
-Xml.tests.cpp:<line number>: passed: encode("\xF4\x8F\xBF\xBF") == "\xF4\x8F\xBF\xBF" for: "ô¿¿" == "ô¿¿"
-Xml.tests.cpp:<line number>: passed: encode("Here \xFF be 👾") == u8"Here \\xFF be 👾" for: "Here \xFF be 👾" == "Here \xFF be 👾"
-Xml.tests.cpp:<line number>: passed: encode("\xFF") == "\\xFF" for: "\xFF" == "\xFF"
-Xml.tests.cpp:<line number>: passed: encode("\xC5\xC5\xA0") == u8"\\xC5Å " for: "\xC5Å " == "\xC5Å "
-Xml.tests.cpp:<line number>: passed: encode("\xF4\x90\x80\x80") == u8"\\xF4\\x90\\x80\\x80" for: "\xF4\x90\x80\x80" == "\xF4\x90\x80\x80"
-Xml.tests.cpp:<line number>: passed: encode("\xC0\x80") == u8"\\xC0\\x80" for: "\xC0\x80" == "\xC0\x80"
-Xml.tests.cpp:<line number>: passed: encode("\xF0\x80\x80\x80") == u8"\\xF0\\x80\\x80\\x80" for: "\xF0\x80\x80\x80" == "\xF0\x80\x80\x80"
-Xml.tests.cpp:<line number>: passed: encode("\xC1\xBF") == u8"\\xC1\\xBF" for: "\xC1\xBF" == "\xC1\xBF"
-Xml.tests.cpp:<line number>: passed: encode("\xE0\x9F\xBF") == u8"\\xE0\\x9F\\xBF" for: "\xE0\x9F\xBF" == "\xE0\x9F\xBF"
-Xml.tests.cpp:<line number>: passed: encode("\xF0\x8F\xBF\xBF") == u8"\\xF0\\x8F\\xBF\\xBF" for: "\xF0\x8F\xBF\xBF" == "\xF0\x8F\xBF\xBF"
-Xml.tests.cpp:<line number>: passed: encode("\xED\xA0\x80") == "\xED\xA0\x80" for: "í €" == "í €"
-Xml.tests.cpp:<line number>: passed: encode("\xED\xAF\xBF") == "\xED\xAF\xBF" for: "í¯¿" == "í¯¿"
-Xml.tests.cpp:<line number>: passed: encode("\xED\xB0\x80") == "\xED\xB0\x80" for: "í°€" == "í°€"
-Xml.tests.cpp:<line number>: passed: encode("\xED\xBF\xBF") == "\xED\xBF\xBF" for: "í¿¿" == "í¿¿"
-Xml.tests.cpp:<line number>: passed: encode("\x80") == u8"\\x80" for: "\x80" == "\x80"
-Xml.tests.cpp:<line number>: passed: encode("\x81") == u8"\\x81" for: "\x81" == "\x81"
-Xml.tests.cpp:<line number>: passed: encode("\xBC") == u8"\\xBC" for: "\xBC" == "\xBC"
-Xml.tests.cpp:<line number>: passed: encode("\xBF") == u8"\\xBF" for: "\xBF" == "\xBF"
-Xml.tests.cpp:<line number>: passed: encode("\xF5\x80\x80\x80") == u8"\\xF5\\x80\\x80\\x80" for: "\xF5\x80\x80\x80" == "\xF5\x80\x80\x80"
-Xml.tests.cpp:<line number>: passed: encode("\xF6\x80\x80\x80") == u8"\\xF6\\x80\\x80\\x80" for: "\xF6\x80\x80\x80" == "\xF6\x80\x80\x80"
-Xml.tests.cpp:<line number>: passed: encode("\xF7\x80\x80\x80") == u8"\\xF7\\x80\\x80\\x80" for: "\xF7\x80\x80\x80" == "\xF7\x80\x80\x80"
-Xml.tests.cpp:<line number>: passed: encode("\xDE") == u8"\\xDE" for: "\xDE" == "\xDE"
-Xml.tests.cpp:<line number>: passed: encode("\xDF") == u8"\\xDF" for: "\xDF" == "\xDF"
-Xml.tests.cpp:<line number>: passed: encode("\xE0") == u8"\\xE0" for: "\xE0" == "\xE0"
-Xml.tests.cpp:<line number>: passed: encode("\xEF") == u8"\\xEF" for: "\xEF" == "\xEF"
-Xml.tests.cpp:<line number>: passed: encode("\xF0") == u8"\\xF0" for: "\xF0" == "\xF0"
-Xml.tests.cpp:<line number>: passed: encode("\xF4") == u8"\\xF4" for: "\xF4" == "\xF4"
-Xml.tests.cpp:<line number>: passed: encode("\xE0\x80") == u8"\\xE0\\x80" for: "\xE0\x80" == "\xE0\x80"
-Xml.tests.cpp:<line number>: passed: encode("\xE0\xBF") == u8"\\xE0\\xBF" for: "\xE0\xBF" == "\xE0\xBF"
-Xml.tests.cpp:<line number>: passed: encode("\xE1\x80") == u8"\\xE1\\x80" for: "\xE1\x80" == "\xE1\x80"
-Xml.tests.cpp:<line number>: passed: encode("\xF0\x80") == u8"\\xF0\\x80" for: "\xF0\x80" == "\xF0\x80"
-Xml.tests.cpp:<line number>: passed: encode("\xF4\x80") == u8"\\xF4\\x80" for: "\xF4\x80" == "\xF4\x80"
-Xml.tests.cpp:<line number>: passed: encode("\xF0\x80\x80") == u8"\\xF0\\x80\\x80" for: "\xF0\x80\x80" == "\xF0\x80\x80"
-Xml.tests.cpp:<line number>: passed: encode("\xF4\x80\x80") == u8"\\xF4\\x80\\x80" for: "\xF4\x80\x80" == "\xF4\x80\x80"
+Tag.tests.cpp:<line number>: passed: testcase.tags, VectorContains(std::string(".")) && VectorContains(std::string("!hide")) for: { "!hide", "." } ( Contains: "." and Contains: "!hide" )
+Tag.tests.cpp:<line number>: passed: testcase.tags, VectorContains(std::string(".")) && VectorContains(std::string("!hide")) for: { "!hide", "." } ( Contains: "." and Contains: "!hide" )
+Tag.tests.cpp:<line number>: passed: testcase.tags, VectorContains(std::string(".")) && VectorContains(std::string("!hide")) for: { "!hide", ".", "foo" } ( Contains: "." and Contains: "!hide" )
ToStringVector.tests.cpp:<line number>: passed: Catch::Detail::stringify( empty ) == "{ }" for: "{ }" == "{ }"
ToStringVector.tests.cpp:<line number>: passed: Catch::Detail::stringify( oneValue ) == "{ 42 }" for: "{ 42 }" == "{ 42 }"
ToStringVector.tests.cpp:<line number>: passed: Catch::Detail::stringify( twoValues ) == "{ 42, 250 }" for: "{ 42, 250 }" == "{ 42, 250 }"
@@ -1364,6 +1652,13 @@ Tricky.tests.cpp:<line number>: passed: ptr.get() == 0 for: 0 == 0
ToStringPair.tests.cpp:<line number>: passed: ::Catch::Detail::stringify( pair ) == "{ { 42, \"Arthur\" }, { \"Ford\", 24 } }" for: "{ { 42, "Arthur" }, { "Ford", 24 } }"
==
"{ { 42, "Arthur" }, { "Ford", 24 } }"
+ToString.tests.cpp:<line number>: passed: parseEnums( "" ), Equals( std::vector<Catch::StringRef>{} ) for: { } Equals: { }
+ToString.tests.cpp:<line number>: passed: parseEnums( "ClassName::EnumName::Value1" ), Equals(std::vector<Catch::StringRef>{"Value1"} ) for: { Value1 } Equals: { Value1 }
+ToString.tests.cpp:<line number>: passed: parseEnums( "Value1" ), Equals( std::vector<Catch::StringRef>{"Value1"} ) for: { Value1 } Equals: { Value1 }
+ToString.tests.cpp:<line number>: passed: parseEnums( "EnumName::Value1" ), Equals(std::vector<Catch::StringRef>{"Value1"} ) for: { Value1 } Equals: { Value1 }
+ToString.tests.cpp:<line number>: passed: parseEnums( "ClassName::EnumName::Value1, ClassName::EnumName::Value2" ), Equals( std::vector<Catch::StringRef>{"Value1", "Value2"} ) for: { Value1, Value2 } Equals: { Value1, Value2 }
+ToString.tests.cpp:<line number>: passed: parseEnums( "ClassName::EnumName::Value1, ClassName::EnumName::Value2, ClassName::EnumName::Value3" ), Equals( std::vector<Catch::StringRef>{"Value1", "Value2", "Value3"} ) for: { Value1, Value2, Value3 } Equals: { Value1, Value2, Value3 }
+ToString.tests.cpp:<line number>: passed: parseEnums( "ClassName::EnumName::Value1,ClassName::EnumName::Value2 , ClassName::EnumName::Value3" ), Equals( std::vector<Catch::StringRef>{"Value1", "Value2", "Value3"} ) for: { Value1, Value2, Value3 } Equals: { Value1, Value2, Value3 }
Tricky.tests.cpp:<line number>: passed: p == 0 for: 0 == 0
Message.tests.cpp:<line number>: passed: true with 1 message: 'this MAY be seen IF info is printed for passing assertions'
Message.tests.cpp:<line number>: failed: false with 2 messages: 'this SHOULD be seen' and 'this SHOULD also be seen'
@@ -1374,23 +1669,26 @@ Message.tests.cpp:<line number>: passed: true
Misc.tests.cpp:<line number>: passed: a != b for: 1 != 2
Misc.tests.cpp:<line number>: passed: b != a for: 2 != 1
Misc.tests.cpp:<line number>: passed: a != b for: 1 != 2
-String.tests.cpp:<line number>: passed: Catch::replaceInPlace( letters, "b", "z" ) for: true
-String.tests.cpp:<line number>: passed: letters == "azcdefcg" for: "azcdefcg" == "azcdefcg"
-String.tests.cpp:<line number>: passed: Catch::replaceInPlace( letters, "c", "z" ) for: true
-String.tests.cpp:<line number>: passed: letters == "abzdefzg" for: "abzdefzg" == "abzdefzg"
-String.tests.cpp:<line number>: passed: Catch::replaceInPlace( letters, "a", "z" ) for: true
-String.tests.cpp:<line number>: passed: letters == "zbcdefcg" for: "zbcdefcg" == "zbcdefcg"
-String.tests.cpp:<line number>: passed: Catch::replaceInPlace( letters, "g", "z" ) for: true
-String.tests.cpp:<line number>: passed: letters == "abcdefcz" for: "abcdefcz" == "abcdefcz"
-String.tests.cpp:<line number>: passed: Catch::replaceInPlace( letters, letters, "replaced" ) for: true
-String.tests.cpp:<line number>: passed: letters == "replaced" for: "replaced" == "replaced"
-String.tests.cpp:<line number>: passed: !(Catch::replaceInPlace( letters, "x", "z" )) for: !false
-String.tests.cpp:<line number>: passed: letters == letters for: "abcdefcg" == "abcdefcg"
-String.tests.cpp:<line number>: passed: Catch::replaceInPlace( s, "'", "|'" ) for: true
-String.tests.cpp:<line number>: passed: s == "didn|'t" for: "didn|'t" == "didn|'t"
+StringManip.tests.cpp:<line number>: passed: Catch::replaceInPlace(letters, "b", "z") for: true
+StringManip.tests.cpp:<line number>: passed: letters == "azcdefcg" for: "azcdefcg" == "azcdefcg"
+StringManip.tests.cpp:<line number>: passed: Catch::replaceInPlace(letters, "c", "z") for: true
+StringManip.tests.cpp:<line number>: passed: letters == "abzdefzg" for: "abzdefzg" == "abzdefzg"
+StringManip.tests.cpp:<line number>: passed: Catch::replaceInPlace(letters, "a", "z") for: true
+StringManip.tests.cpp:<line number>: passed: letters == "zbcdefcg" for: "zbcdefcg" == "zbcdefcg"
+StringManip.tests.cpp:<line number>: passed: Catch::replaceInPlace(letters, "g", "z") for: true
+StringManip.tests.cpp:<line number>: passed: letters == "abcdefcz" for: "abcdefcz" == "abcdefcz"
+StringManip.tests.cpp:<line number>: passed: Catch::replaceInPlace(letters, letters, "replaced") for: true
+StringManip.tests.cpp:<line number>: passed: letters == "replaced" for: "replaced" == "replaced"
+StringManip.tests.cpp:<line number>: passed: !(Catch::replaceInPlace(letters, "x", "z")) for: !false
+StringManip.tests.cpp:<line number>: passed: letters == letters for: "abcdefcg" == "abcdefcg"
+StringManip.tests.cpp:<line number>: passed: Catch::replaceInPlace(s, "'", "|'") for: true
+StringManip.tests.cpp:<line number>: passed: s == "didn|'t" for: "didn|'t" == "didn|'t"
Misc.tests.cpp:<line number>: failed: false with 1 message: '3'
Message.tests.cpp:<line number>: failed: false with 2 messages: 'hi' and 'i := 7'
-Tag.tests.cpp:<line number>: passed: testcase.tags, Catch::VectorContains(std::string("magic-tag")) && Catch::VectorContains(std::string(".")) for: { ".", "magic-tag" } ( Contains: "magic-tag" and Contains: "." )
+Tag.tests.cpp:<line number>: passed: testcase.tags, Catch::VectorContains(std::string("magic-tag")) && Catch::VectorContains(std::string(".")) for: { "!hide", ".", "magic-tag" } ( Contains: "magic-tag" and Contains: "." )
+StringManip.tests.cpp:<line number>: passed: splitStringRef("", ','), Equals(std::vector<StringRef>()) for: { } Equals: { }
+StringManip.tests.cpp:<line number>: passed: splitStringRef("abc", ','), Equals(std::vector<StringRef>{"abc"}) for: { abc } Equals: { abc }
+StringManip.tests.cpp:<line number>: passed: splitStringRef("abc,def", ','), Equals(std::vector<StringRef>{"abc", "def"}) for: { abc, def } Equals: { abc, def }
Message.tests.cpp:<line number>: failed: false with 4 messages: 'Count 1 to 3...' and '1' and '2' and '3'
Message.tests.cpp:<line number>: failed: false with 4 messages: 'Count 4 to 6...' and '4' and '5' and '6'
ToStringGeneral.tests.cpp:<line number>: passed: Catch::Detail::stringify( emptyMap ) == "{ }" for: "{ }" == "{ }"
@@ -1514,5 +1812,5 @@ Misc.tests.cpp:<line number>: passed: v.size() == 5 for: 5 == 5
Misc.tests.cpp:<line number>: passed: v.capacity() >= 5 for: 5 >= 5
Misc.tests.cpp:<line number>: passed:
Misc.tests.cpp:<line number>: passed:
-Failed 79 test cases, failed 141 assertions.
+Failed 86 test cases, failed 148 assertions.
diff --git a/projects/SelfTest/Baselines/console.std.approved.txt b/projects/SelfTest/Baselines/console.std.approved.txt
index e5a1d5da..ba4f79d7 100644
--- a/projects/SelfTest/Baselines/console.std.approved.txt
+++ b/projects/SelfTest/Baselines/console.std.approved.txt
@@ -164,6 +164,54 @@ with expansion:
0 == 1
-------------------------------------------------------------------------------
+A TEMPLATE_PRODUCT_TEST_CASE_METHOD_SIG based test run that fails -
+Template_Foo_2<float, 6>
+-------------------------------------------------------------------------------
+Class.tests.cpp:<line number>
+...............................................................................
+
+Class.tests.cpp:<line number>: FAILED:
+ REQUIRE( Template_Fixture_2<TestType>{}.m_a.size() < 2 )
+with expansion:
+ 6 < 2
+
+-------------------------------------------------------------------------------
+A TEMPLATE_PRODUCT_TEST_CASE_METHOD_SIG based test run that fails -
+Template_Foo_2<int, 2>
+-------------------------------------------------------------------------------
+Class.tests.cpp:<line number>
+...............................................................................
+
+Class.tests.cpp:<line number>: FAILED:
+ REQUIRE( Template_Fixture_2<TestType>{}.m_a.size() < 2 )
+with expansion:
+ 2 < 2
+
+-------------------------------------------------------------------------------
+A TEMPLATE_PRODUCT_TEST_CASE_METHOD_SIG based test run that fails - std::array
+<float, 6>
+-------------------------------------------------------------------------------
+Class.tests.cpp:<line number>
+...............................................................................
+
+Class.tests.cpp:<line number>: FAILED:
+ REQUIRE( Template_Fixture_2<TestType>{}.m_a.size() < 2 )
+with expansion:
+ 6 < 2
+
+-------------------------------------------------------------------------------
+A TEMPLATE_PRODUCT_TEST_CASE_METHOD_SIG based test run that fails - std::array
+<int, 2>
+-------------------------------------------------------------------------------
+Class.tests.cpp:<line number>
+...............................................................................
+
+Class.tests.cpp:<line number>: FAILED:
+ REQUIRE( Template_Fixture_2<TestType>{}.m_a.size() < 2 )
+with expansion:
+ 2 < 2
+
+-------------------------------------------------------------------------------
A TEMPLATE_TEST_CASE_METHOD based test run that fails - double
-------------------------------------------------------------------------------
Class.tests.cpp:<line number>
@@ -197,6 +245,39 @@ with expansion:
1 == 2
-------------------------------------------------------------------------------
+A TEMPLATE_TEST_CASE_METHOD_SIG based test run that fails - 1
+-------------------------------------------------------------------------------
+Class.tests.cpp:<line number>
+...............................................................................
+
+Class.tests.cpp:<line number>: FAILED:
+ REQUIRE( Nttp_Fixture<V>::value == 0 )
+with expansion:
+ 1 == 0
+
+-------------------------------------------------------------------------------
+A TEMPLATE_TEST_CASE_METHOD_SIG based test run that fails - 3
+-------------------------------------------------------------------------------
+Class.tests.cpp:<line number>
+...............................................................................
+
+Class.tests.cpp:<line number>: FAILED:
+ REQUIRE( Nttp_Fixture<V>::value == 0 )
+with expansion:
+ 3 == 0
+
+-------------------------------------------------------------------------------
+A TEMPLATE_TEST_CASE_METHOD_SIG based test run that fails - 6
+-------------------------------------------------------------------------------
+Class.tests.cpp:<line number>
+...............................................................................
+
+Class.tests.cpp:<line number>: FAILED:
+ REQUIRE( Nttp_Fixture<V>::value == 0 )
+with expansion:
+ 6 == 0
+
+-------------------------------------------------------------------------------
A TEST_CASE_METHOD based test run that fails
-------------------------------------------------------------------------------
Class.tests.cpp:<line number>
@@ -439,12 +520,12 @@ Matchers.tests.cpp:<line number>
...............................................................................
Matchers.tests.cpp:<line number>: FAILED:
- CHECK_THROWS_MATCHES( throws(3), SpecialException, ExceptionMatcher{1} )
+ CHECK_THROWS_MATCHES( throwsSpecialException(3), SpecialException, ExceptionMatcher{1} )
with expansion:
SpecialException::what special exception has value of 1
Matchers.tests.cpp:<line number>: FAILED:
- REQUIRE_THROWS_MATCHES( throws(4), SpecialException, ExceptionMatcher{1} )
+ REQUIRE_THROWS_MATCHES( throwsSpecialException(4), SpecialException, ExceptionMatcher{1} )
with expansion:
SpecialException::what special exception has value of 1
@@ -1299,6 +1380,6 @@ due to unexpected exception with message:
Why would you throw a std::string?
===============================================================================
-test cases: 260 | 193 passed | 63 failed | 4 failed as expected
-assertions: 1428 | 1283 passed | 124 failed | 21 failed as expected
+test cases: 306 | 232 passed | 70 failed | 4 failed as expected
+assertions: 1676 | 1524 passed | 131 failed | 21 failed as expected
diff --git a/projects/SelfTest/Baselines/console.sw.approved.txt b/projects/SelfTest/Baselines/console.sw.approved.txt
index 9def37d9..e06366c4 100644
--- a/projects/SelfTest/Baselines/console.sw.approved.txt
+++ b/projects/SelfTest/Baselines/console.sw.approved.txt
@@ -50,6 +50,22 @@ with expansion:
0 == 0
-------------------------------------------------------------------------------
+#1027: Bitfields can be captured
+-------------------------------------------------------------------------------
+Compilation.tests.cpp:<line number>
+...............................................................................
+
+Compilation.tests.cpp:<line number>: PASSED:
+ REQUIRE( y.v == 0 )
+with expansion:
+ 0 == 0
+
+Compilation.tests.cpp:<line number>: PASSED:
+ REQUIRE( 0 == y.v )
+with expansion:
+ 0 == 0
+
+-------------------------------------------------------------------------------
#1147
-------------------------------------------------------------------------------
Compilation.tests.cpp:<line number>
@@ -1180,6 +1196,102 @@ with expansion:
0 == 0
-------------------------------------------------------------------------------
+A TEMPLATE_PRODUCT_TEST_CASE_METHOD_SIG based test run that fails -
+Template_Foo_2<float, 6>
+-------------------------------------------------------------------------------
+Class.tests.cpp:<line number>
+...............................................................................
+
+Class.tests.cpp:<line number>: FAILED:
+ REQUIRE( Template_Fixture_2<TestType>{}.m_a.size() < 2 )
+with expansion:
+ 6 < 2
+
+-------------------------------------------------------------------------------
+A TEMPLATE_PRODUCT_TEST_CASE_METHOD_SIG based test run that fails -
+Template_Foo_2<int, 2>
+-------------------------------------------------------------------------------
+Class.tests.cpp:<line number>
+...............................................................................
+
+Class.tests.cpp:<line number>: FAILED:
+ REQUIRE( Template_Fixture_2<TestType>{}.m_a.size() < 2 )
+with expansion:
+ 2 < 2
+
+-------------------------------------------------------------------------------
+A TEMPLATE_PRODUCT_TEST_CASE_METHOD_SIG based test run that fails - std::array
+<float, 6>
+-------------------------------------------------------------------------------
+Class.tests.cpp:<line number>
+...............................................................................
+
+Class.tests.cpp:<line number>: FAILED:
+ REQUIRE( Template_Fixture_2<TestType>{}.m_a.size() < 2 )
+with expansion:
+ 6 < 2
+
+-------------------------------------------------------------------------------
+A TEMPLATE_PRODUCT_TEST_CASE_METHOD_SIG based test run that fails - std::array
+<int, 2>
+-------------------------------------------------------------------------------
+Class.tests.cpp:<line number>
+...............................................................................
+
+Class.tests.cpp:<line number>: FAILED:
+ REQUIRE( Template_Fixture_2<TestType>{}.m_a.size() < 2 )
+with expansion:
+ 2 < 2
+
+-------------------------------------------------------------------------------
+A TEMPLATE_PRODUCT_TEST_CASE_METHOD_SIG based test run that succeeds -
+Template_Foo_2<float,6>
+-------------------------------------------------------------------------------
+Class.tests.cpp:<line number>
+...............................................................................
+
+Class.tests.cpp:<line number>: PASSED:
+ REQUIRE( Template_Fixture_2<TestType>{}.m_a.size() >= 2 )
+with expansion:
+ 6 >= 2
+
+-------------------------------------------------------------------------------
+A TEMPLATE_PRODUCT_TEST_CASE_METHOD_SIG based test run that succeeds -
+Template_Foo_2<int,2>
+-------------------------------------------------------------------------------
+Class.tests.cpp:<line number>
+...............................................................................
+
+Class.tests.cpp:<line number>: PASSED:
+ REQUIRE( Template_Fixture_2<TestType>{}.m_a.size() >= 2 )
+with expansion:
+ 2 >= 2
+
+-------------------------------------------------------------------------------
+A TEMPLATE_PRODUCT_TEST_CASE_METHOD_SIG based test run that succeeds - std::
+array<float,6>
+-------------------------------------------------------------------------------
+Class.tests.cpp:<line number>
+...............................................................................
+
+Class.tests.cpp:<line number>: PASSED:
+ REQUIRE( Template_Fixture_2<TestType>{}.m_a.size() >= 2 )
+with expansion:
+ 6 >= 2
+
+-------------------------------------------------------------------------------
+A TEMPLATE_PRODUCT_TEST_CASE_METHOD_SIG based test run that succeeds - std::
+array<int,2>
+-------------------------------------------------------------------------------
+Class.tests.cpp:<line number>
+...............................................................................
+
+Class.tests.cpp:<line number>: PASSED:
+ REQUIRE( Template_Fixture_2<TestType>{}.m_a.size() >= 2 )
+with expansion:
+ 2 >= 2
+
+-------------------------------------------------------------------------------
A TEMPLATE_TEST_CASE_METHOD based test run that fails - double
-------------------------------------------------------------------------------
Class.tests.cpp:<line number>
@@ -1246,6 +1358,72 @@ with expansion:
1 == 1
-------------------------------------------------------------------------------
+A TEMPLATE_TEST_CASE_METHOD_SIG based test run that fails - 1
+-------------------------------------------------------------------------------
+Class.tests.cpp:<line number>
+...............................................................................
+
+Class.tests.cpp:<line number>: FAILED:
+ REQUIRE( Nttp_Fixture<V>::value == 0 )
+with expansion:
+ 1 == 0
+
+-------------------------------------------------------------------------------
+A TEMPLATE_TEST_CASE_METHOD_SIG based test run that fails - 3
+-------------------------------------------------------------------------------
+Class.tests.cpp:<line number>
+...............................................................................
+
+Class.tests.cpp:<line number>: FAILED:
+ REQUIRE( Nttp_Fixture<V>::value == 0 )
+with expansion:
+ 3 == 0
+
+-------------------------------------------------------------------------------
+A TEMPLATE_TEST_CASE_METHOD_SIG based test run that fails - 6
+-------------------------------------------------------------------------------
+Class.tests.cpp:<line number>
+...............................................................................
+
+Class.tests.cpp:<line number>: FAILED:
+ REQUIRE( Nttp_Fixture<V>::value == 0 )
+with expansion:
+ 6 == 0
+
+-------------------------------------------------------------------------------
+A TEMPLATE_TEST_CASE_METHOD_SIG based test run that succeeds - 1
+-------------------------------------------------------------------------------
+Class.tests.cpp:<line number>
+...............................................................................
+
+Class.tests.cpp:<line number>: PASSED:
+ REQUIRE( Nttp_Fixture<V>::value > 0 )
+with expansion:
+ 1 > 0
+
+-------------------------------------------------------------------------------
+A TEMPLATE_TEST_CASE_METHOD_SIG based test run that succeeds - 3
+-------------------------------------------------------------------------------
+Class.tests.cpp:<line number>
+...............................................................................
+
+Class.tests.cpp:<line number>: PASSED:
+ REQUIRE( Nttp_Fixture<V>::value > 0 )
+with expansion:
+ 3 > 0
+
+-------------------------------------------------------------------------------
+A TEMPLATE_TEST_CASE_METHOD_SIG based test run that succeeds - 6
+-------------------------------------------------------------------------------
+Class.tests.cpp:<line number>
+...............................................................................
+
+Class.tests.cpp:<line number>: PASSED:
+ REQUIRE( Nttp_Fixture<V>::value > 0 )
+with expansion:
+ 6 > 0
+
+-------------------------------------------------------------------------------
A TEST_CASE_METHOD based test run that fails
-------------------------------------------------------------------------------
Class.tests.cpp:<line number>
@@ -1312,6 +1490,50 @@ with expansion:
0 == 0
-------------------------------------------------------------------------------
+A Template product test case with array signature - Bar<float, 42>
+-------------------------------------------------------------------------------
+Misc.tests.cpp:<line number>
+...............................................................................
+
+Misc.tests.cpp:<line number>: PASSED:
+ REQUIRE( x.size() > 0 )
+with expansion:
+ 42 > 0
+
+-------------------------------------------------------------------------------
+A Template product test case with array signature - Bar<int, 9>
+-------------------------------------------------------------------------------
+Misc.tests.cpp:<line number>
+...............................................................................
+
+Misc.tests.cpp:<line number>: PASSED:
+ REQUIRE( x.size() > 0 )
+with expansion:
+ 9 > 0
+
+-------------------------------------------------------------------------------
+A Template product test case with array signature - std::array<float, 42>
+-------------------------------------------------------------------------------
+Misc.tests.cpp:<line number>
+...............................................................................
+
+Misc.tests.cpp:<line number>: PASSED:
+ REQUIRE( x.size() > 0 )
+with expansion:
+ 42 > 0
+
+-------------------------------------------------------------------------------
+A Template product test case with array signature - std::array<int, 9>
+-------------------------------------------------------------------------------
+Misc.tests.cpp:<line number>
+...............................................................................
+
+Misc.tests.cpp:<line number>: PASSED:
+ REQUIRE( x.size() > 0 )
+with expansion:
+ 9 > 0
+
+-------------------------------------------------------------------------------
A comparison that uses literals instead of the normal constructor
-------------------------------------------------------------------------------
Approx.tests.cpp:<line number>
@@ -1718,43 +1940,6 @@ Tricky.tests.cpp:<line number>: PASSED:
REQUIRE( true )
-------------------------------------------------------------------------------
-Assorted miscellaneous tests
--------------------------------------------------------------------------------
-Approx.tests.cpp:<line number>
-...............................................................................
-
-Approx.tests.cpp:<line number>: PASSED:
- REQUIRE( INFINITY == Approx(INFINITY) )
-with expansion:
- inff == Approx( inf )
-
-Approx.tests.cpp:<line number>: PASSED:
- REQUIRE( NAN != Approx(NAN) )
-with expansion:
- nanf != Approx( nan )
-
-Approx.tests.cpp:<line number>: PASSED:
- REQUIRE_FALSE( NAN == Approx(NAN) )
-with expansion:
- !(nanf == Approx( nan ))
-
--------------------------------------------------------------------------------
-Bitfields can be captured (#1027)
--------------------------------------------------------------------------------
-Tricky.tests.cpp:<line number>
-...............................................................................
-
-Tricky.tests.cpp:<line number>: PASSED:
- REQUIRE( y.v == 0 )
-with expansion:
- 0 == 0
-
-Tricky.tests.cpp:<line number>: PASSED:
- REQUIRE( 0 == y.v )
-with expansion:
- 0 == 0
-
--------------------------------------------------------------------------------
CAPTURE can deal with complex expressions
-------------------------------------------------------------------------------
Message.tests.cpp:<line number>
@@ -1787,6 +1972,27 @@ with messages:
(2, 3) := 3
-------------------------------------------------------------------------------
+CAPTURE parses string and character constants
+-------------------------------------------------------------------------------
+Message.tests.cpp:<line number>
+...............................................................................
+
+Message.tests.cpp:<line number>: PASSED:
+with messages:
+ ("comma, in string", "escaped, \", ") := "escaped, ", "
+ "single quote in string,'," := "single quote in string,',"
+ "some escapes, \\,\\\\" := "some escapes, \,\\"
+ "some, ), unmatched, } prenheses {[<" := "some, ), unmatched, } prenheses {[
+ <"
+ '"' := '"'
+ '\'' := '''
+ ',' := ','
+ '}' := '}'
+ ')' := ')'
+ '(' := '('
+ '{' := '{'
+
+-------------------------------------------------------------------------------
Capture and info messages
Capture should stringify like assertions
-------------------------------------------------------------------------------
@@ -1974,6 +2180,32 @@ with expansion:
0x<hex digits> == 0x<hex digits>
-------------------------------------------------------------------------------
+Comparison ops
+-------------------------------------------------------------------------------
+RandomNumberGeneration.tests.cpp:<line number>
+...............................................................................
+
+RandomNumberGeneration.tests.cpp:<line number>: PASSED:
+ REQUIRE( SimplePcg32{} == SimplePcg32{} )
+with expansion:
+ {?} == {?}
+
+RandomNumberGeneration.tests.cpp:<line number>: PASSED:
+ REQUIRE( SimplePcg32{ 0 } != SimplePcg32{} )
+with expansion:
+ {?} != {?}
+
+RandomNumberGeneration.tests.cpp:<line number>: PASSED:
+ REQUIRE_FALSE( SimplePcg32{ 1 } == SimplePcg32{ 2 } )
+with expansion:
+ !({?} == {?})
+
+RandomNumberGeneration.tests.cpp:<line number>: PASSED:
+ REQUIRE_FALSE( SimplePcg32{ 1 } != SimplePcg32{ 1 } )
+with expansion:
+ !({?} != {?})
+
+-------------------------------------------------------------------------------
Comparison with explicitly convertible types
-------------------------------------------------------------------------------
Approx.tests.cpp:<line number>
@@ -2159,6 +2391,24 @@ with expansion:
4294967295 (0x<hex digits>) > 4
-------------------------------------------------------------------------------
+Composed matchers are distinct
+-------------------------------------------------------------------------------
+Matchers.tests.cpp:<line number>
+...............................................................................
+
+Matchers.tests.cpp:<line number>: PASSED:
+ REQUIRE_THAT( testStringForMatching2(), !composed1 )
+with expansion:
+ "some completely different text that contains one common word" not (
+ contains: "string" or contains: "random" )
+
+Matchers.tests.cpp:<line number>: PASSED:
+ REQUIRE_THAT( testStringForMatching2(), composed2 )
+with expansion:
+ "some completely different text that contains one common word" ( contains:
+ "string" or contains: "random" or contains: "different" )
+
+-------------------------------------------------------------------------------
Contains string matcher
-------------------------------------------------------------------------------
Matchers.tests.cpp:<line number>
@@ -2176,6 +2426,167 @@ with expansion:
"this string contains 'abc' as a substring" contains: "STRING"
-------------------------------------------------------------------------------
+Copy and then generate a range
+ from var and iterators
+-------------------------------------------------------------------------------
+Generators.tests.cpp:<line number>
+...............................................................................
+
+Generators.tests.cpp:<line number>: PASSED:
+ REQUIRE( elem % 2 == 1 )
+with expansion:
+ 1 == 1
+
+-------------------------------------------------------------------------------
+Copy and then generate a range
+ from var and iterators
+-------------------------------------------------------------------------------
+Generators.tests.cpp:<line number>
+...............................................................................
+
+Generators.tests.cpp:<line number>: PASSED:
+ REQUIRE( elem % 2 == 1 )
+with expansion:
+ 1 == 1
+
+-------------------------------------------------------------------------------
+Copy and then generate a range
+ from var and iterators
+-------------------------------------------------------------------------------
+Generators.tests.cpp:<line number>
+...............................................................................
+
+Generators.tests.cpp:<line number>: PASSED:
+ REQUIRE( elem % 2 == 1 )
+with expansion:
+ 1 == 1
+
+-------------------------------------------------------------------------------
+Copy and then generate a range
+ from var and iterators
+-------------------------------------------------------------------------------
+Generators.tests.cpp:<line number>
+...............................................................................
+
+Generators.tests.cpp:<line number>: PASSED:
+ REQUIRE( elem % 2 == 1 )
+with expansion:
+ 1 == 1
+
+-------------------------------------------------------------------------------
+Copy and then generate a range
+ from var and iterators
+-------------------------------------------------------------------------------
+Generators.tests.cpp:<line number>
+...............................................................................
+
+Generators.tests.cpp:<line number>: PASSED:
+ REQUIRE( elem % 2 == 1 )
+with expansion:
+ 1 == 1
+
+-------------------------------------------------------------------------------
+Copy and then generate a range
+ from var and iterators
+-------------------------------------------------------------------------------
+Generators.tests.cpp:<line number>
+...............................................................................
+
+Generators.tests.cpp:<line number>: PASSED:
+ REQUIRE( elem % 2 == 1 )
+with expansion:
+ 1 == 1
+
+-------------------------------------------------------------------------------
+Copy and then generate a range
+ From a temporary container
+-------------------------------------------------------------------------------
+Generators.tests.cpp:<line number>
+...............................................................................
+
+Generators.tests.cpp:<line number>: PASSED:
+ REQUIRE( elem % 2 == 1 )
+with expansion:
+ 1 == 1
+
+-------------------------------------------------------------------------------
+Copy and then generate a range
+ From a temporary container
+-------------------------------------------------------------------------------
+Generators.tests.cpp:<line number>
+...............................................................................
+
+Generators.tests.cpp:<line number>: PASSED:
+ REQUIRE( elem % 2 == 1 )
+with expansion:
+ 1 == 1
+
+-------------------------------------------------------------------------------
+Copy and then generate a range
+ From a temporary container
+-------------------------------------------------------------------------------
+Generators.tests.cpp:<line number>
+...............................................................................
+
+Generators.tests.cpp:<line number>: PASSED:
+ REQUIRE( elem % 2 == 1 )
+with expansion:
+ 1 == 1
+
+-------------------------------------------------------------------------------
+Copy and then generate a range
+ From a temporary container
+-------------------------------------------------------------------------------
+Generators.tests.cpp:<line number>
+...............................................................................
+
+Generators.tests.cpp:<line number>: PASSED:
+ REQUIRE( elem % 2 == 1 )
+with expansion:
+ 1 == 1
+
+-------------------------------------------------------------------------------
+Copy and then generate a range
+ From a temporary container
+-------------------------------------------------------------------------------
+Generators.tests.cpp:<line number>
+...............................................................................
+
+Generators.tests.cpp:<line number>: PASSED:
+ REQUIRE( elem % 2 == 1 )
+with expansion:
+ 1 == 1
+
+-------------------------------------------------------------------------------
+Copy and then generate a range
+ From a temporary container
+-------------------------------------------------------------------------------
+Generators.tests.cpp:<line number>
+...............................................................................
+
+Generators.tests.cpp:<line number>: PASSED:
+ REQUIRE( elem % 2 == 1 )
+with expansion:
+ 1 == 1
+
+-------------------------------------------------------------------------------
+Copy and then generate a range
+ Final validation
+-------------------------------------------------------------------------------
+Generators.tests.cpp:<line number>
+...............................................................................
+
+Generators.tests.cpp:<line number>: PASSED:
+ REQUIRE( call_count == 1 )
+with expansion:
+ 1 == 1
+
+Generators.tests.cpp:<line number>: PASSED:
+ REQUIRE( make_data().size() == test_count )
+with expansion:
+ 6 == 6
+
+-------------------------------------------------------------------------------
Custom exceptions can be translated when testing for nothrow
-------------------------------------------------------------------------------
Exception.tests.cpp:<line number>
@@ -2224,6 +2635,29 @@ with expansion:
0.00001 != Approx( 0.0000001 )
-------------------------------------------------------------------------------
+Directly creating an EnumInfo
+-------------------------------------------------------------------------------
+ToString.tests.cpp:<line number>
+...............................................................................
+
+ToString.tests.cpp:<line number>: PASSED:
+ CHECK( enumInfo->lookup(0) == "Value1" )
+with expansion:
+ Value1 == "Value1"
+
+ToString.tests.cpp:<line number>: PASSED:
+ CHECK( enumInfo->lookup(1) == "Value2" )
+with expansion:
+ Value2 == "Value2"
+
+ToString.tests.cpp:<line number>: PASSED:
+ CHECK( enumInfo->lookup(3) == "{** unexpected enum value **}" )
+with expansion:
+ {** unexpected enum value **}
+ ==
+ "{** unexpected enum value **}"
+
+-------------------------------------------------------------------------------
EndsWith string matcher
-------------------------------------------------------------------------------
Matchers.tests.cpp:<line number>
@@ -2241,6 +2675,56 @@ with expansion:
insensitive)
-------------------------------------------------------------------------------
+Enums can quickly have stringification enabled using REGISTER_ENUM
+-------------------------------------------------------------------------------
+EnumToString.tests.cpp:<line number>
+...............................................................................
+
+EnumToString.tests.cpp:<line number>: PASSED:
+ REQUIRE( stringify( EnumClass3::Value1 ) == "Value1" )
+with expansion:
+ "Value1" == "Value1"
+
+EnumToString.tests.cpp:<line number>: PASSED:
+ REQUIRE( stringify( EnumClass3::Value2 ) == "Value2" )
+with expansion:
+ "Value2" == "Value2"
+
+EnumToString.tests.cpp:<line number>: PASSED:
+ REQUIRE( stringify( EnumClass3::Value3 ) == "Value3" )
+with expansion:
+ "Value3" == "Value3"
+
+EnumToString.tests.cpp:<line number>: PASSED:
+ REQUIRE( stringify( EnumClass3::Value4 ) == "{** unexpected enum value **}" )
+with expansion:
+ "{** unexpected enum value **}"
+ ==
+ "{** unexpected enum value **}"
+
+EnumToString.tests.cpp:<line number>: PASSED:
+ REQUIRE( stringify( ec3 ) == "Value2" )
+with expansion:
+ "Value2" == "Value2"
+
+-------------------------------------------------------------------------------
+Enums in namespaces can quickly have stringification enabled using
+REGISTER_ENUM
+-------------------------------------------------------------------------------
+EnumToString.tests.cpp:<line number>
+...............................................................................
+
+EnumToString.tests.cpp:<line number>: PASSED:
+ REQUIRE( stringify( Bikeshed::Colours::Red ) == "Red" )
+with expansion:
+ "Red" == "Red"
+
+EnumToString.tests.cpp:<line number>: PASSED:
+ REQUIRE( stringify( Bikeshed::Colours::Blue ) == "Blue" )
+with expansion:
+ "Blue" == "Blue"
+
+-------------------------------------------------------------------------------
Epsilon only applies to Approx's value
-------------------------------------------------------------------------------
Approx.tests.cpp:<line number>
@@ -2464,12 +2948,12 @@ Matchers.tests.cpp:<line number>
...............................................................................
Matchers.tests.cpp:<line number>: FAILED:
- CHECK_THROWS_MATCHES( throws(3), SpecialException, ExceptionMatcher{1} )
+ CHECK_THROWS_MATCHES( throwsSpecialException(3), SpecialException, ExceptionMatcher{1} )
with expansion:
SpecialException::what special exception has value of 1
Matchers.tests.cpp:<line number>: FAILED:
- REQUIRE_THROWS_MATCHES( throws(4), SpecialException, ExceptionMatcher{1} )
+ REQUIRE_THROWS_MATCHES( throwsSpecialException(4), SpecialException, ExceptionMatcher{1} )
with expansion:
SpecialException::what special exception has value of 1
@@ -2480,12 +2964,12 @@ Matchers.tests.cpp:<line number>
...............................................................................
Matchers.tests.cpp:<line number>: PASSED:
- CHECK_THROWS_MATCHES( throws(1), SpecialException, ExceptionMatcher{1} )
+ CHECK_THROWS_MATCHES( throwsSpecialException(1), SpecialException, ExceptionMatcher{1} )
with expansion:
SpecialException::what special exception has value of 1
Matchers.tests.cpp:<line number>: PASSED:
- REQUIRE_THROWS_MATCHES( throws(2), SpecialException, ExceptionMatcher{2} )
+ REQUIRE_THROWS_MATCHES( throwsSpecialException(2), SpecialException, ExceptionMatcher{2} )
with expansion:
SpecialException::what special exception has value of 2
@@ -2541,6 +3025,32 @@ with expansion:
"expected exception" contains: "except" (case insensitive)
-------------------------------------------------------------------------------
+Exceptions matchers
+-------------------------------------------------------------------------------
+Matchers.tests.cpp:<line number>
+...............................................................................
+
+Matchers.tests.cpp:<line number>: PASSED:
+ REQUIRE_THROWS_MATCHES( throwsDerivedException(), DerivedException, Message("DerivedException::what") )
+with expansion:
+ DerivedException::what exception message matches "DerivedException::what"
+
+Matchers.tests.cpp:<line number>: PASSED:
+ REQUIRE_THROWS_MATCHES( throwsDerivedException(), DerivedException, !Message("derivedexception::what") )
+with expansion:
+ DerivedException::what not exception message matches "derivedexception::what"
+
+Matchers.tests.cpp:<line number>: PASSED:
+ REQUIRE_THROWS_MATCHES( throwsSpecialException(2), SpecialException, !Message("DerivedException::what") )
+with expansion:
+ SpecialException::what not exception message matches "DerivedException::what"
+
+Matchers.tests.cpp:<line number>: PASSED:
+ REQUIRE_THROWS_MATCHES( throwsSpecialException(2), SpecialException, Message("SpecialException::what") )
+with expansion:
+ SpecialException::what exception message matches "SpecialException::what"
+
+-------------------------------------------------------------------------------
Expected exceptions that don't throw or unexpected exceptions fail the test
-------------------------------------------------------------------------------
Exception.tests.cpp:<line number>
@@ -2624,6 +3134,46 @@ with expansion:
-------------------------------------------------------------------------------
Floating point matchers: double
+ Relative
+-------------------------------------------------------------------------------
+Matchers.tests.cpp:<line number>
+...............................................................................
+
+Matchers.tests.cpp:<line number>: PASSED:
+ REQUIRE_THAT( 10., WithinRel(11.1, 0.1) )
+with expansion:
+ 10.0 and 11.1 are within 10% of each other
+
+Matchers.tests.cpp:<line number>: PASSED:
+ REQUIRE_THAT( 10., !WithinRel(11.2, 0.1) )
+with expansion:
+ 10.0 not and 11.2 are within 10% of each other
+
+Matchers.tests.cpp:<line number>: PASSED:
+ REQUIRE_THAT( 1., !WithinRel(0., 0.99) )
+with expansion:
+ 1.0 not and 0 are within 99% of each other
+
+Matchers.tests.cpp:<line number>: PASSED:
+ REQUIRE_THAT( -0., WithinRel(0.) )
+with expansion:
+ -0.0 and 0 are within 2.22045e-12% of each other
+
+-------------------------------------------------------------------------------
+Floating point matchers: double
+ Relative
+ Some subnormal values
+-------------------------------------------------------------------------------
+Matchers.tests.cpp:<line number>
+...............................................................................
+
+Matchers.tests.cpp:<line number>: PASSED:
+ REQUIRE_THAT( v1, WithinRel(v2) )
+with expansion:
+ 0.0 and 2.22507e-308 are within 2.22045e-12% of each other
+
+-------------------------------------------------------------------------------
+Floating point matchers: double
Margin
-------------------------------------------------------------------------------
Matchers.tests.cpp:<line number>
@@ -2650,11 +3200,6 @@ with expansion:
0.0 not is within 0.99 of 1.0
Matchers.tests.cpp:<line number>: PASSED:
- REQUIRE_THAT( NAN, !WithinAbs(NAN, 0) )
-with expansion:
- nanf not is within 0.0 of nan
-
-Matchers.tests.cpp:<line number>: PASSED:
REQUIRE_THAT( 11., !WithinAbs(10., 0.5) )
with expansion:
11.0 not is within 0.5 of 10.0
@@ -2684,37 +3229,44 @@ Matchers.tests.cpp:<line number>
Matchers.tests.cpp:<line number>: PASSED:
REQUIRE_THAT( 1., WithinULP(1., 0) )
with expansion:
- 1.0 is within 0 ULPs of 1.0
+ 1.0 is within 0 ULPs of 1.0000000000000000e+00 ([1.0000000000000000e+00, 1.
+ 0000000000000000e+00])
Matchers.tests.cpp:<line number>: PASSED:
REQUIRE_THAT( nextafter(1., 2.), WithinULP(1., 1) )
with expansion:
- 1.0 is within 1 ULPs of 1.0
+ 1.0 is within 1 ULPs of 1.0000000000000000e+00 ([9.9999999999999989e-01, 1.
+ 0000000000000002e+00])
Matchers.tests.cpp:<line number>: PASSED:
- REQUIRE_THAT( nextafter(1., 0.), WithinULP(1., 1) )
+ REQUIRE_THAT( 0., WithinULP(nextafter(0., 1.), 1) )
with expansion:
- 1.0 is within 1 ULPs of 1.0
+ 0.0 is within 1 ULPs of 4.9406564584124654e-324 ([0.0000000000000000e+00, 9.
+ 8813129168249309e-324])
Matchers.tests.cpp:<line number>: PASSED:
- REQUIRE_THAT( nextafter(1., 2.), !WithinULP(1., 0) )
+ REQUIRE_THAT( 1., WithinULP(nextafter(1., 0.), 1) )
with expansion:
- 1.0 not is within 0 ULPs of 1.0
+ 1.0 is within 1 ULPs of 9.9999999999999989e-01 ([9.9999999999999978e-01, 1.
+ 0000000000000000e+00])
Matchers.tests.cpp:<line number>: PASSED:
- REQUIRE_THAT( 1., WithinULP(1., 0) )
+ REQUIRE_THAT( 1., !WithinULP(nextafter(1., 2.), 0) )
with expansion:
- 1.0 is within 0 ULPs of 1.0
+ 1.0 not is within 0 ULPs of 1.0000000000000002e+00 ([1.0000000000000002e+00,
+ 1.0000000000000002e+00])
Matchers.tests.cpp:<line number>: PASSED:
- REQUIRE_THAT( -0., WithinULP(0., 0) )
+ REQUIRE_THAT( 1., WithinULP(1., 0) )
with expansion:
- -0.0 is within 0 ULPs of 0.0
+ 1.0 is within 0 ULPs of 1.0000000000000000e+00 ([1.0000000000000000e+00, 1.
+ 0000000000000000e+00])
Matchers.tests.cpp:<line number>: PASSED:
- REQUIRE_THAT( NAN, !WithinULP(NAN, 123) )
+ REQUIRE_THAT( -0., WithinULP(0., 0) )
with expansion:
- nanf not is within 123 ULPs of nanf
+ -0.0 is within 0 ULPs of 0.0000000000000000e+00 ([0.0000000000000000e+00, 0.
+ 0000000000000000e+00])
-------------------------------------------------------------------------------
Floating point matchers: double
@@ -2726,17 +3278,19 @@ Matchers.tests.cpp:<line number>
Matchers.tests.cpp:<line number>: PASSED:
REQUIRE_THAT( 1., WithinAbs(1., 0.5) || WithinULP(2., 1) )
with expansion:
- 1.0 ( is within 0.5 of 1.0 or is within 1 ULPs of 2.0 )
+ 1.0 ( is within 0.5 of 1.0 or is within 1 ULPs of 2.0000000000000000e+00 ([1.
+ 9999999999999998e+00, 2.0000000000000004e+00]) )
Matchers.tests.cpp:<line number>: PASSED:
REQUIRE_THAT( 1., WithinAbs(2., 0.5) || WithinULP(1., 0) )
with expansion:
- 1.0 ( is within 0.5 of 2.0 or is within 0 ULPs of 1.0 )
+ 1.0 ( is within 0.5 of 2.0 or is within 0 ULPs of 1.0000000000000000e+00 ([1.
+ 0000000000000000e+00, 1.0000000000000000e+00]) )
Matchers.tests.cpp:<line number>: PASSED:
- REQUIRE_THAT( NAN, !(WithinAbs(NAN, 100) || WithinULP(NAN, 123)) )
+ REQUIRE_THAT( 0.0001, WithinAbs(0., 0.001) || WithinRel(0., 0.1) )
with expansion:
- nanf not ( is within 100.0 of nan or is within 123 ULPs of nanf )
+ 0.0001 ( is within 0.001 of 0.0 or and 0 are within 10% of each other )
-------------------------------------------------------------------------------
Floating point matchers: double
@@ -2755,7 +3309,53 @@ Matchers.tests.cpp:<line number>: PASSED:
REQUIRE_NOTHROW( WithinULP(1., 0) )
Matchers.tests.cpp:<line number>: PASSED:
- REQUIRE_THROWS_AS( WithinULP(1., -1), std::domain_error )
+ REQUIRE_NOTHROW( WithinRel(1., 0.) )
+
+Matchers.tests.cpp:<line number>: PASSED:
+ REQUIRE_THROWS_AS( WithinRel(1., -0.2), std::domain_error )
+
+Matchers.tests.cpp:<line number>: PASSED:
+ REQUIRE_THROWS_AS( WithinRel(1., 1.), std::domain_error )
+
+-------------------------------------------------------------------------------
+Floating point matchers: float
+ Relative
+-------------------------------------------------------------------------------
+Matchers.tests.cpp:<line number>
+...............................................................................
+
+Matchers.tests.cpp:<line number>: PASSED:
+ REQUIRE_THAT( 10.f, WithinRel(11.1f, 0.1f) )
+with expansion:
+ 10.0f and 11.1 are within 10% of each other
+
+Matchers.tests.cpp:<line number>: PASSED:
+ REQUIRE_THAT( 10.f, !WithinRel(11.2f, 0.1f) )
+with expansion:
+ 10.0f not and 11.2 are within 10% of each other
+
+Matchers.tests.cpp:<line number>: PASSED:
+ REQUIRE_THAT( 1.f, !WithinRel(0.f, 0.99f) )
+with expansion:
+ 1.0f not and 0 are within 99% of each other
+
+Matchers.tests.cpp:<line number>: PASSED:
+ REQUIRE_THAT( -0.f, WithinRel(0.f) )
+with expansion:
+ -0.0f and 0 are within 0.00119209% of each other
+
+-------------------------------------------------------------------------------
+Floating point matchers: float
+ Relative
+ Some subnormal values
+-------------------------------------------------------------------------------
+Matchers.tests.cpp:<line number>
+...............................................................................
+
+Matchers.tests.cpp:<line number>: PASSED:
+ REQUIRE_THAT( v1, WithinRel(v2) )
+with expansion:
+ 0.0f and 1.17549e-38 are within 0.00119209% of each other
-------------------------------------------------------------------------------
Floating point matchers: float
@@ -2790,11 +3390,6 @@ with expansion:
0.0f is within 0.0 of -0.0
Matchers.tests.cpp:<line number>: PASSED:
- REQUIRE_THAT( NAN, !WithinAbs(NAN, 0) )
-with expansion:
- nanf not is within 0.0 of nan
-
-Matchers.tests.cpp:<line number>: PASSED:
REQUIRE_THAT( 11.f, !WithinAbs(10.f, 0.5f) )
with expansion:
11.0f not is within 0.5 of 10.0
@@ -2824,37 +3419,38 @@ Matchers.tests.cpp:<line number>
Matchers.tests.cpp:<line number>: PASSED:
REQUIRE_THAT( 1.f, WithinULP(1.f, 0) )
with expansion:
- 1.0f is within 0 ULPs of 1.0f
+ 1.0f is within 0 ULPs of 1.00000000e+00f ([1.00000000e+00, 1.00000000e+00])
Matchers.tests.cpp:<line number>: PASSED:
REQUIRE_THAT( nextafter(1.f, 2.f), WithinULP(1.f, 1) )
with expansion:
- 1.0f is within 1 ULPs of 1.0f
+ 1.0f is within 1 ULPs of 1.00000000e+00f ([9.99999940e-01, 1.00000012e+00])
Matchers.tests.cpp:<line number>: PASSED:
- REQUIRE_THAT( nextafter(1.f, 0.f), WithinULP(1.f, 1) )
+ REQUIRE_THAT( 0.f, WithinULP(nextafter(0.f, 1.f), 1) )
with expansion:
- 1.0f is within 1 ULPs of 1.0f
+ 0.0f is within 1 ULPs of 1.40129846e-45f ([0.00000000e+00, 2.80259693e-45])
Matchers.tests.cpp:<line number>: PASSED:
- REQUIRE_THAT( nextafter(1.f, 2.f), !WithinULP(1.f, 0) )
+ REQUIRE_THAT( 1.f, WithinULP(nextafter(1.f, 0.f), 1) )
with expansion:
- 1.0f not is within 0 ULPs of 1.0f
+ 1.0f is within 1 ULPs of 9.99999940e-01f ([9.99999881e-01, 1.00000000e+00])
Matchers.tests.cpp:<line number>: PASSED:
- REQUIRE_THAT( 1.f, WithinULP(1.f, 0) )
+ REQUIRE_THAT( 1.f, !WithinULP(nextafter(1.f, 2.f), 0) )
with expansion:
- 1.0f is within 0 ULPs of 1.0f
+ 1.0f not is within 0 ULPs of 1.00000012e+00f ([1.00000012e+00, 1.00000012e+
+ 00])
Matchers.tests.cpp:<line number>: PASSED:
- REQUIRE_THAT( -0.f, WithinULP(0.f, 0) )
+ REQUIRE_THAT( 1.f, WithinULP(1.f, 0) )
with expansion:
- -0.0f is within 0 ULPs of 0.0f
+ 1.0f is within 0 ULPs of 1.00000000e+00f ([1.00000000e+00, 1.00000000e+00])
Matchers.tests.cpp:<line number>: PASSED:
- REQUIRE_THAT( NAN, !WithinULP(NAN, 123) )
+ REQUIRE_THAT( -0.f, WithinULP(0.f, 0) )
with expansion:
- nanf not is within 123 ULPs of nanf
+ -0.0f is within 0 ULPs of 0.00000000e+00f ([0.00000000e+00, 0.00000000e+00])
-------------------------------------------------------------------------------
Floating point matchers: float
@@ -2866,17 +3462,19 @@ Matchers.tests.cpp:<line number>
Matchers.tests.cpp:<line number>: PASSED:
REQUIRE_THAT( 1.f, WithinAbs(1.f, 0.5) || WithinULP(1.f, 1) )
with expansion:
- 1.0f ( is within 0.5 of 1.0 or is within 1 ULPs of 1.0f )
+ 1.0f ( is within 0.5 of 1.0 or is within 1 ULPs of 1.00000000e+00f ([9.
+ 99999940e-01, 1.00000012e+00]) )
Matchers.tests.cpp:<line number>: PASSED:
REQUIRE_THAT( 1.f, WithinAbs(2.f, 0.5) || WithinULP(1.f, 0) )
with expansion:
- 1.0f ( is within 0.5 of 2.0 or is within 0 ULPs of 1.0f )
+ 1.0f ( is within 0.5 of 2.0 or is within 0 ULPs of 1.00000000e+00f ([1.
+ 00000000e+00, 1.00000000e+00]) )
Matchers.tests.cpp:<line number>: PASSED:
- REQUIRE_THAT( NAN, !(WithinAbs(NAN, 100) || WithinULP(NAN, 123)) )
+ REQUIRE_THAT( 0.0001f, WithinAbs(0.f, 0.001f) || WithinRel(0.f, 0.1f) )
with expansion:
- nanf not ( is within 100.0 of nan or is within 123 ULPs of nanf )
+ 0.0001f ( is within 0.001 of 0.0 or and 0 are within 10% of each other )
-------------------------------------------------------------------------------
Floating point matchers: float
@@ -2895,7 +3493,16 @@ Matchers.tests.cpp:<line number>: PASSED:
REQUIRE_NOTHROW( WithinULP(1.f, 0) )
Matchers.tests.cpp:<line number>: PASSED:
- REQUIRE_THROWS_AS( WithinULP(1.f, -1), std::domain_error )
+ REQUIRE_THROWS_AS( WithinULP(1.f, static_cast<uint64_t>(-1)), std::domain_error )
+
+Matchers.tests.cpp:<line number>: PASSED:
+ REQUIRE_NOTHROW( WithinRel(1.f, 0.f) )
+
+Matchers.tests.cpp:<line number>: PASSED:
+ REQUIRE_THROWS_AS( WithinRel(1.f, -0.2f), std::domain_error )
+
+Matchers.tests.cpp:<line number>: PASSED:
+ REQUIRE_THROWS_AS( WithinRel(1.f, 1.f), std::domain_error )
-------------------------------------------------------------------------------
Generators -- adapters
@@ -3275,6 +3882,45 @@ with expansion:
-------------------------------------------------------------------------------
Generators -- adapters
Chunking a generator into sized pieces
+ Chunk size of zero
+-------------------------------------------------------------------------------
+Generators.tests.cpp:<line number>
+...............................................................................
+
+Generators.tests.cpp:<line number>: PASSED:
+ REQUIRE( chunk2.size() == 0 )
+with expansion:
+ 0 == 0
+
+-------------------------------------------------------------------------------
+Generators -- adapters
+ Chunking a generator into sized pieces
+ Chunk size of zero
+-------------------------------------------------------------------------------
+Generators.tests.cpp:<line number>
+...............................................................................
+
+Generators.tests.cpp:<line number>: PASSED:
+ REQUIRE( chunk2.size() == 0 )
+with expansion:
+ 0 == 0
+
+-------------------------------------------------------------------------------
+Generators -- adapters
+ Chunking a generator into sized pieces
+ Chunk size of zero
+-------------------------------------------------------------------------------
+Generators.tests.cpp:<line number>
+...............................................................................
+
+Generators.tests.cpp:<line number>: PASSED:
+ REQUIRE( chunk2.size() == 0 )
+with expansion:
+ 0 == 0
+
+-------------------------------------------------------------------------------
+Generators -- adapters
+ Chunking a generator into sized pieces
Throws on too small generators
-------------------------------------------------------------------------------
Generators.tests.cpp:<line number>
@@ -4149,6 +4795,504 @@ with expansion:
-------------------------------------------------------------------------------
Generators internals
Range
+ Positive manual step
+ Floating Point
+ Exact
+-------------------------------------------------------------------------------
+GeneratorsImpl.tests.cpp:<line number>
+...............................................................................
+
+GeneratorsImpl.tests.cpp:<line number>: PASSED:
+ REQUIRE( gen.get() == Approx(expected) )
+with expansion:
+ -1.0 == Approx( -1.0 )
+with message:
+ Current expected value is -1
+
+GeneratorsImpl.tests.cpp:<line number>: PASSED:
+ REQUIRE( gen.next() )
+with expansion:
+ true
+with message:
+ Current expected value is -1
+
+GeneratorsImpl.tests.cpp:<line number>: PASSED:
+ REQUIRE( gen.get() == Approx(expected) )
+with expansion:
+ -0.9 == Approx( -0.9 )
+with message:
+ Current expected value is -0.9
+
+GeneratorsImpl.tests.cpp:<line number>: PASSED:
+ REQUIRE( gen.next() )
+with expansion:
+ true
+with message:
+ Current expected value is -0.9
+
+GeneratorsImpl.tests.cpp:<line number>: PASSED:
+ REQUIRE( gen.get() == Approx(expected) )
+with expansion:
+ -0.8 == Approx( -0.8 )
+with message:
+ Current expected value is -0.8
+
+GeneratorsImpl.tests.cpp:<line number>: PASSED:
+ REQUIRE( gen.next() )
+with expansion:
+ true
+with message:
+ Current expected value is -0.8
+
+GeneratorsImpl.tests.cpp:<line number>: PASSED:
+ REQUIRE( gen.get() == Approx(expected) )
+with expansion:
+ -0.7 == Approx( -0.7 )
+with message:
+ Current expected value is -0.7
+
+GeneratorsImpl.tests.cpp:<line number>: PASSED:
+ REQUIRE( gen.next() )
+with expansion:
+ true
+with message:
+ Current expected value is -0.7
+
+GeneratorsImpl.tests.cpp:<line number>: PASSED:
+ REQUIRE( gen.get() == Approx(expected) )
+with expansion:
+ -0.6 == Approx( -0.6 )
+with message:
+ Current expected value is -0.6
+
+GeneratorsImpl.tests.cpp:<line number>: PASSED:
+ REQUIRE( gen.next() )
+with expansion:
+ true
+with message:
+ Current expected value is -0.6
+
+GeneratorsImpl.tests.cpp:<line number>: PASSED:
+ REQUIRE( gen.get() == Approx(expected) )
+with expansion:
+ -0.5 == Approx( -0.5 )
+with message:
+ Current expected value is -0.5
+
+GeneratorsImpl.tests.cpp:<line number>: PASSED:
+ REQUIRE( gen.next() )
+with expansion:
+ true
+with message:
+ Current expected value is -0.5
+
+GeneratorsImpl.tests.cpp:<line number>: PASSED:
+ REQUIRE( gen.get() == Approx(expected) )
+with expansion:
+ -0.4 == Approx( -0.4 )
+with message:
+ Current expected value is -0.4
+
+GeneratorsImpl.tests.cpp:<line number>: PASSED:
+ REQUIRE( gen.next() )
+with expansion:
+ true
+with message:
+ Current expected value is -0.4
+
+GeneratorsImpl.tests.cpp:<line number>: PASSED:
+ REQUIRE( gen.get() == Approx(expected) )
+with expansion:
+ -0.3 == Approx( -0.3 )
+with message:
+ Current expected value is -0.3
+
+GeneratorsImpl.tests.cpp:<line number>: PASSED:
+ REQUIRE( gen.next() )
+with expansion:
+ true
+with message:
+ Current expected value is -0.3
+
+GeneratorsImpl.tests.cpp:<line number>: PASSED:
+ REQUIRE( gen.get() == Approx(expected) )
+with expansion:
+ -0.2 == Approx( -0.2 )
+with message:
+ Current expected value is -0.2
+
+GeneratorsImpl.tests.cpp:<line number>: PASSED:
+ REQUIRE( gen.next() )
+with expansion:
+ true
+with message:
+ Current expected value is -0.2
+
+GeneratorsImpl.tests.cpp:<line number>: PASSED:
+ REQUIRE( gen.get() == Approx(expected) )
+with expansion:
+ -0.1 == Approx( -0.1 )
+with message:
+ Current expected value is -0.1
+
+GeneratorsImpl.tests.cpp:<line number>: PASSED:
+ REQUIRE( gen.next() )
+with expansion:
+ true
+with message:
+ Current expected value is -0.1
+
+GeneratorsImpl.tests.cpp:<line number>: PASSED:
+ REQUIRE( gen.get() == Approx(expected) )
+with expansion:
+ -0.0 == Approx( -0.0 )
+with message:
+ Current expected value is -1.38778e-16
+
+GeneratorsImpl.tests.cpp:<line number>: PASSED:
+ REQUIRE( gen.next() )
+with expansion:
+ true
+with message:
+ Current expected value is -1.38778e-16
+
+GeneratorsImpl.tests.cpp:<line number>: PASSED:
+ REQUIRE( gen.get() == Approx(expected) )
+with expansion:
+ 0.1 == Approx( 0.1 )
+with message:
+ Current expected value is 0.1
+
+GeneratorsImpl.tests.cpp:<line number>: PASSED:
+ REQUIRE( gen.next() )
+with expansion:
+ true
+with message:
+ Current expected value is 0.1
+
+GeneratorsImpl.tests.cpp:<line number>: PASSED:
+ REQUIRE( gen.get() == Approx(expected) )
+with expansion:
+ 0.2 == Approx( 0.2 )
+with message:
+ Current expected value is 0.2
+
+GeneratorsImpl.tests.cpp:<line number>: PASSED:
+ REQUIRE( gen.next() )
+with expansion:
+ true
+with message:
+ Current expected value is 0.2
+
+GeneratorsImpl.tests.cpp:<line number>: PASSED:
+ REQUIRE( gen.get() == Approx(expected) )
+with expansion:
+ 0.3 == Approx( 0.3 )
+with message:
+ Current expected value is 0.3
+
+GeneratorsImpl.tests.cpp:<line number>: PASSED:
+ REQUIRE( gen.next() )
+with expansion:
+ true
+with message:
+ Current expected value is 0.3
+
+GeneratorsImpl.tests.cpp:<line number>: PASSED:
+ REQUIRE( gen.get() == Approx(expected) )
+with expansion:
+ 0.4 == Approx( 0.4 )
+with message:
+ Current expected value is 0.4
+
+GeneratorsImpl.tests.cpp:<line number>: PASSED:
+ REQUIRE( gen.next() )
+with expansion:
+ true
+with message:
+ Current expected value is 0.4
+
+GeneratorsImpl.tests.cpp:<line number>: PASSED:
+ REQUIRE( gen.get() == Approx(expected) )
+with expansion:
+ 0.5 == Approx( 0.5 )
+with message:
+ Current expected value is 0.5
+
+GeneratorsImpl.tests.cpp:<line number>: PASSED:
+ REQUIRE( gen.next() )
+with expansion:
+ true
+with message:
+ Current expected value is 0.5
+
+GeneratorsImpl.tests.cpp:<line number>: PASSED:
+ REQUIRE( gen.get() == Approx(expected) )
+with expansion:
+ 0.6 == Approx( 0.6 )
+with message:
+ Current expected value is 0.6
+
+GeneratorsImpl.tests.cpp:<line number>: PASSED:
+ REQUIRE( gen.next() )
+with expansion:
+ true
+with message:
+ Current expected value is 0.6
+
+GeneratorsImpl.tests.cpp:<line number>: PASSED:
+ REQUIRE( gen.get() == Approx(expected) )
+with expansion:
+ 0.7 == Approx( 0.7 )
+with message:
+ Current expected value is 0.7
+
+GeneratorsImpl.tests.cpp:<line number>: PASSED:
+ REQUIRE( gen.next() )
+with expansion:
+ true
+with message:
+ Current expected value is 0.7
+
+GeneratorsImpl.tests.cpp:<line number>: PASSED:
+ REQUIRE( gen.get() == Approx(expected) )
+with expansion:
+ 0.8 == Approx( 0.8 )
+with message:
+ Current expected value is 0.8
+
+GeneratorsImpl.tests.cpp:<line number>: PASSED:
+ REQUIRE( gen.next() )
+with expansion:
+ true
+with message:
+ Current expected value is 0.8
+
+GeneratorsImpl.tests.cpp:<line number>: PASSED:
+ REQUIRE( gen.get() == Approx(expected) )
+with expansion:
+ 0.9 == Approx( 0.9 )
+with message:
+ Current expected value is 0.9
+
+GeneratorsImpl.tests.cpp:<line number>: PASSED:
+ REQUIRE( gen.next() )
+with expansion:
+ true
+with message:
+ Current expected value is 0.9
+
+GeneratorsImpl.tests.cpp:<line number>: PASSED:
+ REQUIRE( gen.get() == Approx( rangeEnd ) )
+with expansion:
+ 1.0 == Approx( 1.0 )
+
+GeneratorsImpl.tests.cpp:<line number>: PASSED:
+ REQUIRE_FALSE( gen.next() )
+with expansion:
+ !false
+
+-------------------------------------------------------------------------------
+Generators internals
+ Range
+ Positive manual step
+ Floating Point
+ Slightly over end
+-------------------------------------------------------------------------------
+GeneratorsImpl.tests.cpp:<line number>
+...............................................................................
+
+GeneratorsImpl.tests.cpp:<line number>: PASSED:
+ REQUIRE( gen.get() == Approx(expected) )
+with expansion:
+ -1.0 == Approx( -1.0 )
+with message:
+ Current expected value is -1
+
+GeneratorsImpl.tests.cpp:<line number>: PASSED:
+ REQUIRE( gen.next() )
+with expansion:
+ true
+with message:
+ Current expected value is -1
+
+GeneratorsImpl.tests.cpp:<line number>: PASSED:
+ REQUIRE( gen.get() == Approx(expected) )
+with expansion:
+ -0.7 == Approx( -0.7 )
+with message:
+ Current expected value is -0.7
+
+GeneratorsImpl.tests.cpp:<line number>: PASSED:
+ REQUIRE( gen.next() )
+with expansion:
+ true
+with message:
+ Current expected value is -0.7
+
+GeneratorsImpl.tests.cpp:<line number>: PASSED:
+ REQUIRE( gen.get() == Approx(expected) )
+with expansion:
+ -0.4 == Approx( -0.4 )
+with message:
+ Current expected value is -0.4
+
+GeneratorsImpl.tests.cpp:<line number>: PASSED:
+ REQUIRE( gen.next() )
+with expansion:
+ true
+with message:
+ Current expected value is -0.4
+
+GeneratorsImpl.tests.cpp:<line number>: PASSED:
+ REQUIRE( gen.get() == Approx(expected) )
+with expansion:
+ -0.1 == Approx( -0.1 )
+with message:
+ Current expected value is -0.1
+
+GeneratorsImpl.tests.cpp:<line number>: PASSED:
+ REQUIRE( gen.next() )
+with expansion:
+ true
+with message:
+ Current expected value is -0.1
+
+GeneratorsImpl.tests.cpp:<line number>: PASSED:
+ REQUIRE( gen.get() == Approx(expected) )
+with expansion:
+ 0.2 == Approx( 0.2 )
+with message:
+ Current expected value is 0.2
+
+GeneratorsImpl.tests.cpp:<line number>: PASSED:
+ REQUIRE( gen.next() )
+with expansion:
+ true
+with message:
+ Current expected value is 0.2
+
+GeneratorsImpl.tests.cpp:<line number>: PASSED:
+ REQUIRE( gen.get() == Approx(expected) )
+with expansion:
+ 0.5 == Approx( 0.5 )
+with message:
+ Current expected value is 0.5
+
+GeneratorsImpl.tests.cpp:<line number>: PASSED:
+ REQUIRE( gen.next() )
+with expansion:
+ true
+with message:
+ Current expected value is 0.5
+
+GeneratorsImpl.tests.cpp:<line number>: PASSED:
+ REQUIRE_FALSE( gen.next() )
+with expansion:
+ !false
+
+-------------------------------------------------------------------------------
+Generators internals
+ Range
+ Positive manual step
+ Floating Point
+ Slightly under end
+-------------------------------------------------------------------------------
+GeneratorsImpl.tests.cpp:<line number>
+...............................................................................
+
+GeneratorsImpl.tests.cpp:<line number>: PASSED:
+ REQUIRE( gen.get() == Approx(expected) )
+with expansion:
+ -1.0 == Approx( -1.0 )
+with message:
+ Current expected value is -1
+
+GeneratorsImpl.tests.cpp:<line number>: PASSED:
+ REQUIRE( gen.next() )
+with expansion:
+ true
+with message:
+ Current expected value is -1
+
+GeneratorsImpl.tests.cpp:<line number>: PASSED:
+ REQUIRE( gen.get() == Approx(expected) )
+with expansion:
+ -0.7 == Approx( -0.7 )
+with message:
+ Current expected value is -0.7
+
+GeneratorsImpl.tests.cpp:<line number>: PASSED:
+ REQUIRE( gen.next() )
+with expansion:
+ true
+with message:
+ Current expected value is -0.7
+
+GeneratorsImpl.tests.cpp:<line number>: PASSED:
+ REQUIRE( gen.get() == Approx(expected) )
+with expansion:
+ -0.4 == Approx( -0.4 )
+with message:
+ Current expected value is -0.4
+
+GeneratorsImpl.tests.cpp:<line number>: PASSED:
+ REQUIRE( gen.next() )
+with expansion:
+ true
+with message:
+ Current expected value is -0.4
+
+GeneratorsImpl.tests.cpp:<line number>: PASSED:
+ REQUIRE( gen.get() == Approx(expected) )
+with expansion:
+ -0.1 == Approx( -0.1 )
+with message:
+ Current expected value is -0.1
+
+GeneratorsImpl.tests.cpp:<line number>: PASSED:
+ REQUIRE( gen.next() )
+with expansion:
+ true
+with message:
+ Current expected value is -0.1
+
+GeneratorsImpl.tests.cpp:<line number>: PASSED:
+ REQUIRE( gen.get() == Approx(expected) )
+with expansion:
+ 0.2 == Approx( 0.2 )
+with message:
+ Current expected value is 0.2
+
+GeneratorsImpl.tests.cpp:<line number>: PASSED:
+ REQUIRE( gen.next() )
+with expansion:
+ true
+with message:
+ Current expected value is 0.2
+
+GeneratorsImpl.tests.cpp:<line number>: PASSED:
+ REQUIRE( gen.get() == Approx(expected) )
+with expansion:
+ 0.5 == Approx( 0.5 )
+with message:
+ Current expected value is 0.5
+
+GeneratorsImpl.tests.cpp:<line number>: PASSED:
+ REQUIRE( gen.next() )
+with expansion:
+ true
+with message:
+ Current expected value is 0.5
+
+GeneratorsImpl.tests.cpp:<line number>: PASSED:
+ REQUIRE_FALSE( gen.next() )
+with expansion:
+ !false
+
+-------------------------------------------------------------------------------
+Generators internals
+ Range
Negative manual step
Integer
Exact
@@ -5139,6 +6283,125 @@ with expansion:
"hello" > "a"
-------------------------------------------------------------------------------
+Our PCG implementation provides expected results for known seeds
+ Default seeded
+-------------------------------------------------------------------------------
+RandomNumberGeneration.tests.cpp:<line number>
+...............................................................................
+
+RandomNumberGeneration.tests.cpp:<line number>: PASSED:
+ REQUIRE( rng() == 0x<hex digits> )
+with expansion:
+ 4242248763 (0x<hex digits>)
+ ==
+ 4242248763 (0x<hex digits>)
+
+RandomNumberGeneration.tests.cpp:<line number>: PASSED:
+ REQUIRE( rng() == 0x<hex digits> )
+with expansion:
+ 1867888929 (0x<hex digits>)
+ ==
+ 1867888929 (0x<hex digits>)
+
+RandomNumberGeneration.tests.cpp:<line number>: PASSED:
+ REQUIRE( rng() == 0x<hex digits> )
+with expansion:
+ 1276619030 (0x<hex digits>)
+ ==
+ 1276619030 (0x<hex digits>)
+
+RandomNumberGeneration.tests.cpp:<line number>: PASSED:
+ REQUIRE( rng() == 0x<hex digits> )
+with expansion:
+ 1911218783 (0x<hex digits>)
+ ==
+ 1911218783 (0x<hex digits>)
+
+RandomNumberGeneration.tests.cpp:<line number>: PASSED:
+ REQUIRE( rng() == 0x<hex digits> )
+with expansion:
+ 1827115164 (0x<hex digits>)
+ ==
+ 1827115164 (0x<hex digits>)
+
+-------------------------------------------------------------------------------
+Our PCG implementation provides expected results for known seeds
+ Specific seed
+-------------------------------------------------------------------------------
+RandomNumberGeneration.tests.cpp:<line number>
+...............................................................................
+
+RandomNumberGeneration.tests.cpp:<line number>: PASSED:
+ REQUIRE( rng() == 0x<hex digits> )
+with expansion:
+ 1472234645 (0x<hex digits>)
+ ==
+ 1472234645 (0x<hex digits>)
+
+RandomNumberGeneration.tests.cpp:<line number>: PASSED:
+ REQUIRE( rng() == 0x<hex digits> )
+with expansion:
+ 868832940 (0x<hex digits>)
+ ==
+ 868832940 (0x<hex digits>)
+
+RandomNumberGeneration.tests.cpp:<line number>: PASSED:
+ REQUIRE( rng() == 0x<hex digits> )
+with expansion:
+ 570883446 (0x<hex digits>)
+ ==
+ 570883446 (0x<hex digits>)
+
+RandomNumberGeneration.tests.cpp:<line number>: PASSED:
+ REQUIRE( rng() == 0x<hex digits> )
+with expansion:
+ 889299803 (0x<hex digits>)
+ ==
+ 889299803 (0x<hex digits>)
+
+RandomNumberGeneration.tests.cpp:<line number>: PASSED:
+ REQUIRE( rng() == 0x<hex digits> )
+with expansion:
+ 4261393167 (0x<hex digits>)
+ ==
+ 4261393167 (0x<hex digits>)
+
+RandomNumberGeneration.tests.cpp:<line number>: PASSED:
+ REQUIRE( rng() == 0x<hex digits> )
+with expansion:
+ 1472234645 (0x<hex digits>)
+ ==
+ 1472234645 (0x<hex digits>)
+
+RandomNumberGeneration.tests.cpp:<line number>: PASSED:
+ REQUIRE( rng() == 0x<hex digits> )
+with expansion:
+ 868832940 (0x<hex digits>)
+ ==
+ 868832940 (0x<hex digits>)
+
+RandomNumberGeneration.tests.cpp:<line number>: PASSED:
+ REQUIRE( rng() == 0x<hex digits> )
+with expansion:
+ 570883446 (0x<hex digits>)
+ ==
+ 570883446 (0x<hex digits>)
+
+RandomNumberGeneration.tests.cpp:<line number>: PASSED:
+ REQUIRE( rng() == 0x<hex digits> )
+with expansion:
+ 889299803 (0x<hex digits>)
+ ==
+ 889299803 (0x<hex digits>)
+
+RandomNumberGeneration.tests.cpp:<line number>: PASSED:
+ REQUIRE( rng() == 0x<hex digits> )
+with expansion:
+ 4261393167 (0x<hex digits>)
+ ==
+ 4261393167 (0x<hex digits>)
+
+-------------------------------------------------------------------------------
Output from all sections is reported
one
-------------------------------------------------------------------------------
@@ -6053,6 +7316,114 @@ with expansion:
true == true
-------------------------------------------------------------------------------
+Parse test names and tags
+ Leading and trailing spaces in test spec
+-------------------------------------------------------------------------------
+CmdLine.tests.cpp:<line number>
+...............................................................................
+
+CmdLine.tests.cpp:<line number>: PASSED:
+ CHECK( spec.matches( fakeTestCase( " aardvark " ) ) )
+with expansion:
+ true
+
+CmdLine.tests.cpp:<line number>: PASSED:
+ CHECK( spec.matches( fakeTestCase( " aardvark" ) ) )
+with expansion:
+ true
+
+CmdLine.tests.cpp:<line number>: PASSED:
+ CHECK( spec.matches( fakeTestCase( " aardvark " ) ) )
+with expansion:
+ true
+
+CmdLine.tests.cpp:<line number>: PASSED:
+ CHECK( spec.matches( fakeTestCase( "aardvark " ) ) )
+with expansion:
+ true
+
+CmdLine.tests.cpp:<line number>: PASSED:
+ CHECK( spec.matches( fakeTestCase( "aardvark" ) ) )
+with expansion:
+ true
+
+-------------------------------------------------------------------------------
+Parse test names and tags
+ Leading and trailing spaces in test name
+-------------------------------------------------------------------------------
+CmdLine.tests.cpp:<line number>
+...............................................................................
+
+CmdLine.tests.cpp:<line number>: PASSED:
+ CHECK( spec.matches( fakeTestCase( " aardvark " ) ) )
+with expansion:
+ true
+
+CmdLine.tests.cpp:<line number>: PASSED:
+ CHECK( spec.matches( fakeTestCase( " aardvark" ) ) )
+with expansion:
+ true
+
+CmdLine.tests.cpp:<line number>: PASSED:
+ CHECK( spec.matches( fakeTestCase( " aardvark " ) ) )
+with expansion:
+ true
+
+CmdLine.tests.cpp:<line number>: PASSED:
+ CHECK( spec.matches( fakeTestCase( "aardvark " ) ) )
+with expansion:
+ true
+
+CmdLine.tests.cpp:<line number>: PASSED:
+ CHECK( spec.matches( fakeTestCase( "aardvark" ) ) )
+with expansion:
+ true
+
+-------------------------------------------------------------------------------
+Parse test names and tags
+ Shortened hide tags are split apart when parsing
+-------------------------------------------------------------------------------
+CmdLine.tests.cpp:<line number>
+...............................................................................
+
+CmdLine.tests.cpp:<line number>: PASSED:
+ CHECK( spec.matches(fakeTestCase("hidden and foo", "[.][foo]")) )
+with expansion:
+ true
+
+CmdLine.tests.cpp:<line number>: PASSED:
+ CHECK_FALSE( spec.matches(fakeTestCase("only foo", "[foo]")) )
+with expansion:
+ !false
+
+-------------------------------------------------------------------------------
+Parse test names and tags
+ Shortened hide tags also properly handle exclusion
+-------------------------------------------------------------------------------
+CmdLine.tests.cpp:<line number>
+...............................................................................
+
+CmdLine.tests.cpp:<line number>: PASSED:
+ CHECK_FALSE( spec.matches(fakeTestCase("hidden and foo", "[.][foo]")) )
+with expansion:
+ !false
+
+CmdLine.tests.cpp:<line number>: PASSED:
+ CHECK_FALSE( spec.matches(fakeTestCase("only foo", "[foo]")) )
+with expansion:
+ !false
+
+CmdLine.tests.cpp:<line number>: PASSED:
+ CHECK_FALSE( spec.matches(fakeTestCase("only hidden", "[.]")) )
+with expansion:
+ !false
+
+CmdLine.tests.cpp:<line number>: PASSED:
+ CHECK( spec.matches(fakeTestCase("neither foo nor hidden", "[bar]")) )
+with expansion:
+ true
+
+-------------------------------------------------------------------------------
Pointers can be compared to null
-------------------------------------------------------------------------------
Condition.tests.cpp:<line number>
@@ -6099,6 +7470,40 @@ with expansion:
0 != 0x<hex digits>
-------------------------------------------------------------------------------
+Precision of floating point stringification can be set
+ Floats
+-------------------------------------------------------------------------------
+ToStringGeneral.tests.cpp:<line number>
+...............................................................................
+
+ToStringGeneral.tests.cpp:<line number>: PASSED:
+ CHECK( str1.size() == 3 + 5 )
+with expansion:
+ 8 == 8
+
+ToStringGeneral.tests.cpp:<line number>: PASSED:
+ REQUIRE( str2.size() == 3 + 10 )
+with expansion:
+ 13 == 13
+
+-------------------------------------------------------------------------------
+Precision of floating point stringification can be set
+ Double
+-------------------------------------------------------------------------------
+ToStringGeneral.tests.cpp:<line number>
+...............................................................................
+
+ToStringGeneral.tests.cpp:<line number>: PASSED:
+ CHECK( str1.size() == 2 + 5 )
+with expansion:
+ 7 == 7
+
+ToStringGeneral.tests.cpp:<line number>: PASSED:
+ REQUIRE( str2.size() == 2 + 15 )
+with expansion:
+ 17 == 17
+
+-------------------------------------------------------------------------------
Predicate matcher can accept const char*
-------------------------------------------------------------------------------
Matchers.tests.cpp:<line number>
@@ -6431,6 +7836,102 @@ with expansion:
-------------------------------------------------------------------------------
Process can be configured on command line
+ abort
+ wait-for-keypress
+ Accepted options
+-------------------------------------------------------------------------------
+CmdLine.tests.cpp:<line number>
+...............................................................................
+
+CmdLine.tests.cpp:<line number>: PASSED:
+ CHECK( cli.parse({"test", "--wait-for-keypress", std::get<0>(input)}) )
+with expansion:
+ {?}
+
+CmdLine.tests.cpp:<line number>: PASSED:
+ REQUIRE( config.waitForKeypress == std::get<1>(input) )
+with expansion:
+ 0 == 0
+
+-------------------------------------------------------------------------------
+Process can be configured on command line
+ abort
+ wait-for-keypress
+ Accepted options
+-------------------------------------------------------------------------------
+CmdLine.tests.cpp:<line number>
+...............................................................................
+
+CmdLine.tests.cpp:<line number>: PASSED:
+ CHECK( cli.parse({"test", "--wait-for-keypress", std::get<0>(input)}) )
+with expansion:
+ {?}
+
+CmdLine.tests.cpp:<line number>: PASSED:
+ REQUIRE( config.waitForKeypress == std::get<1>(input) )
+with expansion:
+ 1 == 1
+
+-------------------------------------------------------------------------------
+Process can be configured on command line
+ abort
+ wait-for-keypress
+ Accepted options
+-------------------------------------------------------------------------------
+CmdLine.tests.cpp:<line number>
+...............................................................................
+
+CmdLine.tests.cpp:<line number>: PASSED:
+ CHECK( cli.parse({"test", "--wait-for-keypress", std::get<0>(input)}) )
+with expansion:
+ {?}
+
+CmdLine.tests.cpp:<line number>: PASSED:
+ REQUIRE( config.waitForKeypress == std::get<1>(input) )
+with expansion:
+ 2 == 2
+
+-------------------------------------------------------------------------------
+Process can be configured on command line
+ abort
+ wait-for-keypress
+ Accepted options
+-------------------------------------------------------------------------------
+CmdLine.tests.cpp:<line number>
+...............................................................................
+
+CmdLine.tests.cpp:<line number>: PASSED:
+ CHECK( cli.parse({"test", "--wait-for-keypress", std::get<0>(input)}) )
+with expansion:
+ {?}
+
+CmdLine.tests.cpp:<line number>: PASSED:
+ REQUIRE( config.waitForKeypress == std::get<1>(input) )
+with expansion:
+ 3 == 3
+
+-------------------------------------------------------------------------------
+Process can be configured on command line
+ abort
+ wait-for-keypress
+ invalid options are reported
+-------------------------------------------------------------------------------
+CmdLine.tests.cpp:<line number>
+...............................................................................
+
+CmdLine.tests.cpp:<line number>: PASSED:
+ CHECK( !result )
+with expansion:
+ true
+
+CmdLine.tests.cpp:<line number>: PASSED:
+ REQUIRE_THAT( result.errorMessage(), Contains("never") && Contains("both") )
+with expansion:
+ "keypress argument must be one of: never, start, exit or both. 'sometimes'
+ not recognised" ( contains: "never" and contains: "both" )
+
+-------------------------------------------------------------------------------
+Process can be configured on command line
nothrow
-e
-------------------------------------------------------------------------------
@@ -6621,6 +8122,96 @@ with expansion:
contains: "colour mode must be one of"
-------------------------------------------------------------------------------
+Process can be configured on command line
+ Benchmark options
+ samples
+-------------------------------------------------------------------------------
+CmdLine.tests.cpp:<line number>
+...............................................................................
+
+CmdLine.tests.cpp:<line number>: PASSED:
+ CHECK( cli.parse({ "test", "--benchmark-samples=200" }) )
+with expansion:
+ {?}
+
+CmdLine.tests.cpp:<line number>: PASSED:
+ REQUIRE( config.benchmarkSamples == 200 )
+with expansion:
+ 200 == 200
+
+-------------------------------------------------------------------------------
+Process can be configured on command line
+ Benchmark options
+ resamples
+-------------------------------------------------------------------------------
+CmdLine.tests.cpp:<line number>
+...............................................................................
+
+CmdLine.tests.cpp:<line number>: PASSED:
+ CHECK( cli.parse({ "test", "--benchmark-resamples=20000" }) )
+with expansion:
+ {?}
+
+CmdLine.tests.cpp:<line number>: PASSED:
+ REQUIRE( config.benchmarkResamples == 20000 )
+with expansion:
+ 20000 (0x<hex digits>) == 20000 (0x<hex digits>)
+
+-------------------------------------------------------------------------------
+Process can be configured on command line
+ Benchmark options
+ confidence-interval
+-------------------------------------------------------------------------------
+CmdLine.tests.cpp:<line number>
+...............................................................................
+
+CmdLine.tests.cpp:<line number>: PASSED:
+ CHECK( cli.parse({ "test", "--benchmark-confidence-interval=0.99" }) )
+with expansion:
+ {?}
+
+CmdLine.tests.cpp:<line number>: PASSED:
+ REQUIRE( config.benchmarkConfidenceInterval == Catch::Detail::Approx(0.99) )
+with expansion:
+ 0.99 == Approx( 0.99 )
+
+-------------------------------------------------------------------------------
+Process can be configured on command line
+ Benchmark options
+ no-analysis
+-------------------------------------------------------------------------------
+CmdLine.tests.cpp:<line number>
+...............................................................................
+
+CmdLine.tests.cpp:<line number>: PASSED:
+ CHECK( cli.parse({ "test", "--benchmark-no-analysis" }) )
+with expansion:
+ {?}
+
+CmdLine.tests.cpp:<line number>: PASSED:
+ REQUIRE( config.benchmarkNoAnalysis )
+with expansion:
+ true
+
+-------------------------------------------------------------------------------
+Process can be configured on command line
+ Benchmark options
+ warmup-time
+-------------------------------------------------------------------------------
+CmdLine.tests.cpp:<line number>
+...............................................................................
+
+CmdLine.tests.cpp:<line number>: PASSED:
+ CHECK( cli.parse({ "test", "--benchmark-warmup-time=10" }) )
+with expansion:
+ {?}
+
+CmdLine.tests.cpp:<line number>: PASSED:
+ REQUIRE( config.benchmarkWarmupTime == 10 )
+with expansion:
+ 10 == 10
+
+-------------------------------------------------------------------------------
Product with differing arities - std::tuple<int, double, float>
-------------------------------------------------------------------------------
Misc.tests.cpp:<line number>
@@ -6934,11 +8525,6 @@ Approx.tests.cpp:<line number>: PASSED:
with expansion:
Approx( 1.23 ) != 1.24
-Approx.tests.cpp:<line number>: PASSED:
- REQUIRE( INFINITY == Approx(INFINITY) )
-with expansion:
- inff == Approx( inf )
-
Message from section one
-------------------------------------------------------------------------------
Standard output from all sections is reported
@@ -7084,6 +8670,11 @@ with expansion:
0 == 0
String.tests.cpp:<line number>: PASSED:
+ REQUIRE( empty.isNullTerminated() )
+with expansion:
+ true
+
+String.tests.cpp:<line number>: PASSED:
REQUIRE( std::strcmp( empty.c_str(), "" ) == 0 )
with expansion:
0 == 0
@@ -7106,27 +8697,17 @@ with expansion:
5 == 5
String.tests.cpp:<line number>: PASSED:
- REQUIRE( isSubstring( s ) == false )
+ REQUIRE( s.isNullTerminated() )
with expansion:
- false == false
+ true
String.tests.cpp:<line number>: PASSED:
REQUIRE( std::strcmp( rawChars, "hello" ) == 0 )
with expansion:
0 == 0
--------------------------------------------------------------------------------
-StringRef
- From string literal
- c_str() does not cause copy
--------------------------------------------------------------------------------
-String.tests.cpp:<line number>
-...............................................................................
-
String.tests.cpp:<line number>: PASSED:
- REQUIRE( isOwned( s ) == false )
-with expansion:
- false == false
+ REQUIRE_NOTHROW( s.c_str() )
String.tests.cpp:<line number>: PASSED:
REQUIRE( s.c_str() == rawChars )
@@ -7134,9 +8715,9 @@ with expansion:
"hello" == "hello"
String.tests.cpp:<line number>: PASSED:
- REQUIRE( isOwned( s ) == false )
+ REQUIRE( s.data() == rawChars )
with expansion:
- false == false
+ "hello" == "hello"
-------------------------------------------------------------------------------
StringRef
@@ -7149,24 +8730,15 @@ String.tests.cpp:<line number>: PASSED:
REQUIRE( original == "original" )
String.tests.cpp:<line number>: PASSED:
- REQUIRE( isSubstring( original ) )
-with expansion:
- true
-
-String.tests.cpp:<line number>: PASSED:
- REQUIRE( isOwned( original ) == false )
+ REQUIRE_FALSE( original.isNullTerminated() )
with expansion:
- false == false
+ !false
String.tests.cpp:<line number>: PASSED:
- REQUIRE( isSubstring( original ) == false )
-with expansion:
- false == false
+ REQUIRE_THROWS( original.c_str() )
String.tests.cpp:<line number>: PASSED:
- REQUIRE( isOwned( original ) )
-with expansion:
- true
+ REQUIRE_NOTHROW( original.data() )
-------------------------------------------------------------------------------
StringRef
@@ -7187,7 +8759,7 @@ with expansion:
5 == 5
String.tests.cpp:<line number>: PASSED:
- REQUIRE( std::strcmp( ss.c_str(), "hello" ) == 0 )
+ REQUIRE( std::strncmp( ss.data(), "hello", 5 ) == 0 )
with expansion:
0 == 0
@@ -7199,106 +8771,94 @@ with expansion:
-------------------------------------------------------------------------------
StringRef
Substrings
- c_str() causes copy
+ non-zero-based substring
-------------------------------------------------------------------------------
String.tests.cpp:<line number>
...............................................................................
String.tests.cpp:<line number>: PASSED:
- REQUIRE( isSubstring( ss ) )
-with expansion:
- true
-
-String.tests.cpp:<line number>: PASSED:
- REQUIRE( isOwned( ss ) == false )
-with expansion:
- false == false
-
-String.tests.cpp:<line number>: PASSED:
- REQUIRE( rawChars == s.currentData() )
-with expansion:
- "hello world!" == "hello world!"
-
-String.tests.cpp:<line number>: PASSED:
- REQUIRE( ss.c_str() != rawChars )
+ REQUIRE( ss.size() == 6 )
with expansion:
- "hello" != "hello world!"
+ 6 == 6
String.tests.cpp:<line number>: PASSED:
- REQUIRE( isSubstring( ss ) == false )
+ REQUIRE( std::strcmp( ss.c_str(), "world!" ) == 0 )
with expansion:
- false == false
+ 0 == 0
-String.tests.cpp:<line number>: PASSED:
- REQUIRE( isOwned( ss ) )
-with expansion:
- true
+-------------------------------------------------------------------------------
+StringRef
+ Substrings
+ Pointer values of full refs should match
+-------------------------------------------------------------------------------
+String.tests.cpp:<line number>
+...............................................................................
String.tests.cpp:<line number>: PASSED:
- REQUIRE( ss.currentData() != s.currentData() )
+ REQUIRE( s.data() == s2.data() )
with expansion:
- "hello" != "hello world!"
+ "hello world!" == "hello world!"
-------------------------------------------------------------------------------
StringRef
Substrings
- non-zero-based substring
+ Pointer values of substring refs should also match
-------------------------------------------------------------------------------
String.tests.cpp:<line number>
...............................................................................
String.tests.cpp:<line number>: PASSED:
- REQUIRE( ss.size() == 6 )
-with expansion:
- 6 == 6
-
-String.tests.cpp:<line number>: PASSED:
- REQUIRE( std::strcmp( ss.c_str(), "world!" ) == 0 )
+ REQUIRE( s.data() == ss.data() )
with expansion:
- 0 == 0
+ "hello world!" == "hello world!"
-------------------------------------------------------------------------------
StringRef
Substrings
- Pointer values of full refs should match
+ Past the end substring
-------------------------------------------------------------------------------
String.tests.cpp:<line number>
...............................................................................
String.tests.cpp:<line number>: PASSED:
- REQUIRE( s.c_str() == s2.c_str() )
+ REQUIRE( s.substr(s.size() + 1, 123).empty() )
with expansion:
- "hello world!" == "hello world!"
+ true
-------------------------------------------------------------------------------
StringRef
Substrings
- Pointer values of substring refs should not match
+ Substring off the end are trimmed
-------------------------------------------------------------------------------
String.tests.cpp:<line number>
...............................................................................
String.tests.cpp:<line number>: PASSED:
- REQUIRE( s.c_str() != ss.c_str() )
+ REQUIRE( std::strcmp(ss.c_str(), "world!") == 0 )
with expansion:
- "hello world!" != "hello"
+ 0 == 0
-------------------------------------------------------------------------------
StringRef
- Comparisons
+ Comparisons are deep
-------------------------------------------------------------------------------
String.tests.cpp:<line number>
...............................................................................
String.tests.cpp:<line number>: PASSED:
- REQUIRE( StringRef("hello") == StringRef("hello") )
+ CHECK( (char*)buffer1 != (char*)buffer2 )
+with expansion:
+ "Hello" != "Hello"
+
+String.tests.cpp:<line number>: PASSED:
+ REQUIRE( left == right )
with expansion:
- hello == hello
+ Hello == Hello
String.tests.cpp:<line number>: PASSED:
- REQUIRE( StringRef("hello") != StringRef("cello") )
+ REQUIRE( left != left.substr(0, 3) )
with expansion:
- hello != cello
+ Hello != Hel
-------------------------------------------------------------------------------
StringRef
@@ -7357,7 +8917,7 @@ with expansion:
-------------------------------------------------------------------------------
StringRef
to std::string
- implicitly constructed
+ explicitly constructed
-------------------------------------------------------------------------------
String.tests.cpp:<line number>
...............................................................................
@@ -7375,7 +8935,7 @@ with expansion:
-------------------------------------------------------------------------------
StringRef
to std::string
- explicitly constructed
+ assigned
-------------------------------------------------------------------------------
String.tests.cpp:<line number>
...............................................................................
@@ -7391,44 +8951,62 @@ with expansion:
11 == 11
-------------------------------------------------------------------------------
-StringRef
- to std::string
- assigned
+StringRef at compilation time
+ Simple constructors
-------------------------------------------------------------------------------
String.tests.cpp:<line number>
...............................................................................
String.tests.cpp:<line number>: PASSED:
- REQUIRE( stdStr == "a stringref" )
-with expansion:
- "a stringref" == "a stringref"
+with message:
+ StringRef{}.size() == 0
String.tests.cpp:<line number>: PASSED:
- REQUIRE( stdStr.size() == sr.size() )
-with expansion:
- 11 == 11
+with message:
+ StringRef{ "abc", 3 }.size() == 3
+
+String.tests.cpp:<line number>: PASSED:
+with message:
+ StringRef{ "abc", 3 }.isNullTerminated()
+
+String.tests.cpp:<line number>: PASSED:
+with message:
+ StringRef{ "abc", 2 }.size() == 2
+
+String.tests.cpp:<line number>: PASSED:
+with message:
+ !(StringRef{ "abc", 2 }.isNullTerminated())
-------------------------------------------------------------------------------
-StringRef
- Counting utf-8 codepoints
+StringRef at compilation time
+ UDL construction
-------------------------------------------------------------------------------
String.tests.cpp:<line number>
...............................................................................
String.tests.cpp:<line number>: PASSED:
- REQUIRE( ascii.numberOfCharacters() == ascii.size() )
-with expansion:
- 39 == 39
+with message:
+ !(sr1.empty())
String.tests.cpp:<line number>: PASSED:
- REQUIRE( simpleu8.numberOfCharacters() == 30 )
-with expansion:
- 30 == 30
+with message:
+ sr1.size() == 3
String.tests.cpp:<line number>: PASSED:
- REQUIRE( emojis.numberOfCharacters() == 9 )
-with expansion:
- 9 == 9
+with message:
+ sr1.isNullTerminated()
+
+String.tests.cpp:<line number>: PASSED:
+with message:
+ sr2.empty()
+
+String.tests.cpp:<line number>: PASSED:
+with message:
+ sr2.size() == 0
+
+String.tests.cpp:<line number>: PASSED:
+with message:
+ sr2.isNullTerminated()
-------------------------------------------------------------------------------
Stringifying std::chrono::duration helpers
@@ -7558,6 +9136,123 @@ Tag.tests.cpp:<line number>: PASSED:
CHECK_THROWS( registry.add( "[@no square bracket at end", "", Catch::SourceLineInfo( "file", 3 ) ) )
-------------------------------------------------------------------------------
+Template test case method with test types specified inside std::tuple - MyTypes
+- 0
+-------------------------------------------------------------------------------
+Class.tests.cpp:<line number>
+...............................................................................
+
+Class.tests.cpp:<line number>: PASSED:
+ REQUIRE( Template_Fixture<TestType>::m_a == 1 )
+with expansion:
+ 1 == 1
+
+-------------------------------------------------------------------------------
+Template test case method with test types specified inside std::tuple - MyTypes
+- 1
+-------------------------------------------------------------------------------
+Class.tests.cpp:<line number>
+...............................................................................
+
+Class.tests.cpp:<line number>: PASSED:
+ REQUIRE( Template_Fixture<TestType>::m_a == 1 )
+with expansion:
+ 1 == 1
+
+-------------------------------------------------------------------------------
+Template test case method with test types specified inside std::tuple - MyTypes
+- 2
+-------------------------------------------------------------------------------
+Class.tests.cpp:<line number>
+...............................................................................
+
+Class.tests.cpp:<line number>: PASSED:
+ REQUIRE( Template_Fixture<TestType>::m_a == 1 )
+with expansion:
+ 1.0 == 1
+
+-------------------------------------------------------------------------------
+Template test case with test types specified inside non-copyable and non-
+movable std::tuple - NonCopyableAndNonMovableTypes - 0
+-------------------------------------------------------------------------------
+Misc.tests.cpp:<line number>
+...............................................................................
+
+Misc.tests.cpp:<line number>: PASSED:
+ REQUIRE( sizeof(TestType) > 0 )
+with expansion:
+ 1 > 0
+
+-------------------------------------------------------------------------------
+Template test case with test types specified inside non-copyable and non-
+movable std::tuple - NonCopyableAndNonMovableTypes - 1
+-------------------------------------------------------------------------------
+Misc.tests.cpp:<line number>
+...............................................................................
+
+Misc.tests.cpp:<line number>: PASSED:
+ REQUIRE( sizeof(TestType) > 0 )
+with expansion:
+ 4 > 0
+
+-------------------------------------------------------------------------------
+Template test case with test types specified inside non-default-constructible
+std::tuple - MyNonDefaultConstructibleTypes - 0
+-------------------------------------------------------------------------------
+Misc.tests.cpp:<line number>
+...............................................................................
+
+Misc.tests.cpp:<line number>: PASSED:
+ REQUIRE( sizeof(TestType) > 0 )
+with expansion:
+ 1 > 0
+
+-------------------------------------------------------------------------------
+Template test case with test types specified inside non-default-constructible
+std::tuple - MyNonDefaultConstructibleTypes - 1
+-------------------------------------------------------------------------------
+Misc.tests.cpp:<line number>
+...............................................................................
+
+Misc.tests.cpp:<line number>: PASSED:
+ REQUIRE( sizeof(TestType) > 0 )
+with expansion:
+ 4 > 0
+
+-------------------------------------------------------------------------------
+Template test case with test types specified inside std::tuple - MyTypes - 0
+-------------------------------------------------------------------------------
+Misc.tests.cpp:<line number>
+...............................................................................
+
+Misc.tests.cpp:<line number>: PASSED:
+ REQUIRE( sizeof(TestType) > 0 )
+with expansion:
+ 4 > 0
+
+-------------------------------------------------------------------------------
+Template test case with test types specified inside std::tuple - MyTypes - 1
+-------------------------------------------------------------------------------
+Misc.tests.cpp:<line number>
+...............................................................................
+
+Misc.tests.cpp:<line number>: PASSED:
+ REQUIRE( sizeof(TestType) > 0 )
+with expansion:
+ 1 > 0
+
+-------------------------------------------------------------------------------
+Template test case with test types specified inside std::tuple - MyTypes - 2
+-------------------------------------------------------------------------------
+Misc.tests.cpp:<line number>
+...............................................................................
+
+Misc.tests.cpp:<line number>: PASSED:
+ REQUIRE( sizeof(TestType) > 0 )
+with expansion:
+ 4 > 0
+
+-------------------------------------------------------------------------------
TemplateTest: vectors can be sized and resized - float
-------------------------------------------------------------------------------
Misc.tests.cpp:<line number>
@@ -8138,6 +9833,586 @@ with expansion:
5 >= 5
-------------------------------------------------------------------------------
+TemplateTestSig: vectors can be sized and resized - (std::tuple<int, float>), 6
+-------------------------------------------------------------------------------
+Misc.tests.cpp:<line number>
+...............................................................................
+
+Misc.tests.cpp:<line number>: PASSED:
+ REQUIRE( v.size() == V )
+with expansion:
+ 6 == 6
+
+Misc.tests.cpp:<line number>: PASSED:
+ REQUIRE( v.capacity() >= V )
+with expansion:
+ 6 >= 6
+
+-------------------------------------------------------------------------------
+TemplateTestSig: vectors can be sized and resized - (std::tuple<int, float>), 6
+ resizing bigger changes size and capacity
+-------------------------------------------------------------------------------
+Misc.tests.cpp:<line number>
+...............................................................................
+
+Misc.tests.cpp:<line number>: PASSED:
+ REQUIRE( v.size() == 2 * V )
+with expansion:
+ 12 == 12
+
+Misc.tests.cpp:<line number>: PASSED:
+ REQUIRE( v.capacity() >= 2 * V )
+with expansion:
+ 12 >= 12
+
+-------------------------------------------------------------------------------
+TemplateTestSig: vectors can be sized and resized - (std::tuple<int, float>), 6
+-------------------------------------------------------------------------------
+Misc.tests.cpp:<line number>
+...............................................................................
+
+Misc.tests.cpp:<line number>: PASSED:
+ REQUIRE( v.size() == V )
+with expansion:
+ 6 == 6
+
+Misc.tests.cpp:<line number>: PASSED:
+ REQUIRE( v.capacity() >= V )
+with expansion:
+ 6 >= 6
+
+-------------------------------------------------------------------------------
+TemplateTestSig: vectors can be sized and resized - (std::tuple<int, float>), 6
+ resizing smaller changes size but not capacity
+-------------------------------------------------------------------------------
+Misc.tests.cpp:<line number>
+...............................................................................
+
+Misc.tests.cpp:<line number>: PASSED:
+ REQUIRE( v.size() == 0 )
+with expansion:
+ 0 == 0
+
+Misc.tests.cpp:<line number>: PASSED:
+ REQUIRE( v.capacity() >= V )
+with expansion:
+ 6 >= 6
+
+-------------------------------------------------------------------------------
+TemplateTestSig: vectors can be sized and resized - (std::tuple<int, float>), 6
+ resizing smaller changes size but not capacity
+ We can use the 'swap trick' to reset the capacity
+-------------------------------------------------------------------------------
+Misc.tests.cpp:<line number>
+...............................................................................
+
+Misc.tests.cpp:<line number>: PASSED:
+ REQUIRE( v.capacity() == 0 )
+with expansion:
+ 0 == 0
+
+-------------------------------------------------------------------------------
+TemplateTestSig: vectors can be sized and resized - (std::tuple<int, float>), 6
+-------------------------------------------------------------------------------
+Misc.tests.cpp:<line number>
+...............................................................................
+
+Misc.tests.cpp:<line number>: PASSED:
+ REQUIRE( v.size() == V )
+with expansion:
+ 6 == 6
+
+Misc.tests.cpp:<line number>: PASSED:
+ REQUIRE( v.capacity() >= V )
+with expansion:
+ 6 >= 6
+
+-------------------------------------------------------------------------------
+TemplateTestSig: vectors can be sized and resized - (std::tuple<int, float>), 6
+ reserving bigger changes capacity but not size
+-------------------------------------------------------------------------------
+Misc.tests.cpp:<line number>
+...............................................................................
+
+Misc.tests.cpp:<line number>: PASSED:
+ REQUIRE( v.size() == V )
+with expansion:
+ 6 == 6
+
+Misc.tests.cpp:<line number>: PASSED:
+ REQUIRE( v.capacity() >= 2 * V )
+with expansion:
+ 12 >= 12
+
+-------------------------------------------------------------------------------
+TemplateTestSig: vectors can be sized and resized - (std::tuple<int, float>), 6
+-------------------------------------------------------------------------------
+Misc.tests.cpp:<line number>
+...............................................................................
+
+Misc.tests.cpp:<line number>: PASSED:
+ REQUIRE( v.size() == V )
+with expansion:
+ 6 == 6
+
+Misc.tests.cpp:<line number>: PASSED:
+ REQUIRE( v.capacity() >= V )
+with expansion:
+ 6 >= 6
+
+-------------------------------------------------------------------------------
+TemplateTestSig: vectors can be sized and resized - (std::tuple<int, float>), 6
+ reserving smaller does not change size or capacity
+-------------------------------------------------------------------------------
+Misc.tests.cpp:<line number>
+...............................................................................
+
+Misc.tests.cpp:<line number>: PASSED:
+ REQUIRE( v.size() == V )
+with expansion:
+ 6 == 6
+
+Misc.tests.cpp:<line number>: PASSED:
+ REQUIRE( v.capacity() >= V )
+with expansion:
+ 6 >= 6
+
+-------------------------------------------------------------------------------
+TemplateTestSig: vectors can be sized and resized - float,4
+-------------------------------------------------------------------------------
+Misc.tests.cpp:<line number>
+...............................................................................
+
+Misc.tests.cpp:<line number>: PASSED:
+ REQUIRE( v.size() == V )
+with expansion:
+ 4 == 4
+
+Misc.tests.cpp:<line number>: PASSED:
+ REQUIRE( v.capacity() >= V )
+with expansion:
+ 4 >= 4
+
+-------------------------------------------------------------------------------
+TemplateTestSig: vectors can be sized and resized - float,4
+ resizing bigger changes size and capacity
+-------------------------------------------------------------------------------
+Misc.tests.cpp:<line number>
+...............................................................................
+
+Misc.tests.cpp:<line number>: PASSED:
+ REQUIRE( v.size() == 2 * V )
+with expansion:
+ 8 == 8
+
+Misc.tests.cpp:<line number>: PASSED:
+ REQUIRE( v.capacity() >= 2 * V )
+with expansion:
+ 8 >= 8
+
+-------------------------------------------------------------------------------
+TemplateTestSig: vectors can be sized and resized - float,4
+-------------------------------------------------------------------------------
+Misc.tests.cpp:<line number>
+...............................................................................
+
+Misc.tests.cpp:<line number>: PASSED:
+ REQUIRE( v.size() == V )
+with expansion:
+ 4 == 4
+
+Misc.tests.cpp:<line number>: PASSED:
+ REQUIRE( v.capacity() >= V )
+with expansion:
+ 4 >= 4
+
+-------------------------------------------------------------------------------
+TemplateTestSig: vectors can be sized and resized - float,4
+ resizing smaller changes size but not capacity
+-------------------------------------------------------------------------------
+Misc.tests.cpp:<line number>
+...............................................................................
+
+Misc.tests.cpp:<line number>: PASSED:
+ REQUIRE( v.size() == 0 )
+with expansion:
+ 0 == 0
+
+Misc.tests.cpp:<line number>: PASSED:
+ REQUIRE( v.capacity() >= V )
+with expansion:
+ 4 >= 4
+
+-------------------------------------------------------------------------------
+TemplateTestSig: vectors can be sized and resized - float,4
+ resizing smaller changes size but not capacity
+ We can use the 'swap trick' to reset the capacity
+-------------------------------------------------------------------------------
+Misc.tests.cpp:<line number>
+...............................................................................
+
+Misc.tests.cpp:<line number>: PASSED:
+ REQUIRE( v.capacity() == 0 )
+with expansion:
+ 0 == 0
+
+-------------------------------------------------------------------------------
+TemplateTestSig: vectors can be sized and resized - float,4
+-------------------------------------------------------------------------------
+Misc.tests.cpp:<line number>
+...............................................................................
+
+Misc.tests.cpp:<line number>: PASSED:
+ REQUIRE( v.size() == V )
+with expansion:
+ 4 == 4
+
+Misc.tests.cpp:<line number>: PASSED:
+ REQUIRE( v.capacity() >= V )
+with expansion:
+ 4 >= 4
+
+-------------------------------------------------------------------------------
+TemplateTestSig: vectors can be sized and resized - float,4
+ reserving bigger changes capacity but not size
+-------------------------------------------------------------------------------
+Misc.tests.cpp:<line number>
+...............................................................................
+
+Misc.tests.cpp:<line number>: PASSED:
+ REQUIRE( v.size() == V )
+with expansion:
+ 4 == 4
+
+Misc.tests.cpp:<line number>: PASSED:
+ REQUIRE( v.capacity() >= 2 * V )
+with expansion:
+ 8 >= 8
+
+-------------------------------------------------------------------------------
+TemplateTestSig: vectors can be sized and resized - float,4
+-------------------------------------------------------------------------------
+Misc.tests.cpp:<line number>
+...............................................................................
+
+Misc.tests.cpp:<line number>: PASSED:
+ REQUIRE( v.size() == V )
+with expansion:
+ 4 == 4
+
+Misc.tests.cpp:<line number>: PASSED:
+ REQUIRE( v.capacity() >= V )
+with expansion:
+ 4 >= 4
+
+-------------------------------------------------------------------------------
+TemplateTestSig: vectors can be sized and resized - float,4
+ reserving smaller does not change size or capacity
+-------------------------------------------------------------------------------
+Misc.tests.cpp:<line number>
+...............................................................................
+
+Misc.tests.cpp:<line number>: PASSED:
+ REQUIRE( v.size() == V )
+with expansion:
+ 4 == 4
+
+Misc.tests.cpp:<line number>: PASSED:
+ REQUIRE( v.capacity() >= V )
+with expansion:
+ 4 >= 4
+
+-------------------------------------------------------------------------------
+TemplateTestSig: vectors can be sized and resized - int,5
+-------------------------------------------------------------------------------
+Misc.tests.cpp:<line number>
+...............................................................................
+
+Misc.tests.cpp:<line number>: PASSED:
+ REQUIRE( v.size() == V )
+with expansion:
+ 5 == 5
+
+Misc.tests.cpp:<line number>: PASSED:
+ REQUIRE( v.capacity() >= V )
+with expansion:
+ 5 >= 5
+
+-------------------------------------------------------------------------------
+TemplateTestSig: vectors can be sized and resized - int,5
+ resizing bigger changes size and capacity
+-------------------------------------------------------------------------------
+Misc.tests.cpp:<line number>
+...............................................................................
+
+Misc.tests.cpp:<line number>: PASSED:
+ REQUIRE( v.size() == 2 * V )
+with expansion:
+ 10 == 10
+
+Misc.tests.cpp:<line number>: PASSED:
+ REQUIRE( v.capacity() >= 2 * V )
+with expansion:
+ 10 >= 10
+
+-------------------------------------------------------------------------------
+TemplateTestSig: vectors can be sized and resized - int,5
+-------------------------------------------------------------------------------
+Misc.tests.cpp:<line number>
+...............................................................................
+
+Misc.tests.cpp:<line number>: PASSED:
+ REQUIRE( v.size() == V )
+with expansion:
+ 5 == 5
+
+Misc.tests.cpp:<line number>: PASSED:
+ REQUIRE( v.capacity() >= V )
+with expansion:
+ 5 >= 5
+
+-------------------------------------------------------------------------------
+TemplateTestSig: vectors can be sized and resized - int,5
+ resizing smaller changes size but not capacity
+-------------------------------------------------------------------------------
+Misc.tests.cpp:<line number>
+...............................................................................
+
+Misc.tests.cpp:<line number>: PASSED:
+ REQUIRE( v.size() == 0 )
+with expansion:
+ 0 == 0
+
+Misc.tests.cpp:<line number>: PASSED:
+ REQUIRE( v.capacity() >= V )
+with expansion:
+ 5 >= 5
+
+-------------------------------------------------------------------------------
+TemplateTestSig: vectors can be sized and resized - int,5
+ resizing smaller changes size but not capacity
+ We can use the 'swap trick' to reset the capacity
+-------------------------------------------------------------------------------
+Misc.tests.cpp:<line number>
+...............................................................................
+
+Misc.tests.cpp:<line number>: PASSED:
+ REQUIRE( v.capacity() == 0 )
+with expansion:
+ 0 == 0
+
+-------------------------------------------------------------------------------
+TemplateTestSig: vectors can be sized and resized - int,5
+-------------------------------------------------------------------------------
+Misc.tests.cpp:<line number>
+...............................................................................
+
+Misc.tests.cpp:<line number>: PASSED:
+ REQUIRE( v.size() == V )
+with expansion:
+ 5 == 5
+
+Misc.tests.cpp:<line number>: PASSED:
+ REQUIRE( v.capacity() >= V )
+with expansion:
+ 5 >= 5
+
+-------------------------------------------------------------------------------
+TemplateTestSig: vectors can be sized and resized - int,5
+ reserving bigger changes capacity but not size
+-------------------------------------------------------------------------------
+Misc.tests.cpp:<line number>
+...............................................................................
+
+Misc.tests.cpp:<line number>: PASSED:
+ REQUIRE( v.size() == V )
+with expansion:
+ 5 == 5
+
+Misc.tests.cpp:<line number>: PASSED:
+ REQUIRE( v.capacity() >= 2 * V )
+with expansion:
+ 10 >= 10
+
+-------------------------------------------------------------------------------
+TemplateTestSig: vectors can be sized and resized - int,5
+-------------------------------------------------------------------------------
+Misc.tests.cpp:<line number>
+...............................................................................
+
+Misc.tests.cpp:<line number>: PASSED:
+ REQUIRE( v.size() == V )
+with expansion:
+ 5 == 5
+
+Misc.tests.cpp:<line number>: PASSED:
+ REQUIRE( v.capacity() >= V )
+with expansion:
+ 5 >= 5
+
+-------------------------------------------------------------------------------
+TemplateTestSig: vectors can be sized and resized - int,5
+ reserving smaller does not change size or capacity
+-------------------------------------------------------------------------------
+Misc.tests.cpp:<line number>
+...............................................................................
+
+Misc.tests.cpp:<line number>: PASSED:
+ REQUIRE( v.size() == V )
+with expansion:
+ 5 == 5
+
+Misc.tests.cpp:<line number>: PASSED:
+ REQUIRE( v.capacity() >= V )
+with expansion:
+ 5 >= 5
+
+-------------------------------------------------------------------------------
+TemplateTestSig: vectors can be sized and resized - std::string,15
+-------------------------------------------------------------------------------
+Misc.tests.cpp:<line number>
+...............................................................................
+
+Misc.tests.cpp:<line number>: PASSED:
+ REQUIRE( v.size() == V )
+with expansion:
+ 15 == 15
+
+Misc.tests.cpp:<line number>: PASSED:
+ REQUIRE( v.capacity() >= V )
+with expansion:
+ 15 >= 15
+
+-------------------------------------------------------------------------------
+TemplateTestSig: vectors can be sized and resized - std::string,15
+ resizing bigger changes size and capacity
+-------------------------------------------------------------------------------
+Misc.tests.cpp:<line number>
+...............................................................................
+
+Misc.tests.cpp:<line number>: PASSED:
+ REQUIRE( v.size() == 2 * V )
+with expansion:
+ 30 == 30
+
+Misc.tests.cpp:<line number>: PASSED:
+ REQUIRE( v.capacity() >= 2 * V )
+with expansion:
+ 30 >= 30
+
+-------------------------------------------------------------------------------
+TemplateTestSig: vectors can be sized and resized - std::string,15
+-------------------------------------------------------------------------------
+Misc.tests.cpp:<line number>
+...............................................................................
+
+Misc.tests.cpp:<line number>: PASSED:
+ REQUIRE( v.size() == V )
+with expansion:
+ 15 == 15
+
+Misc.tests.cpp:<line number>: PASSED:
+ REQUIRE( v.capacity() >= V )
+with expansion:
+ 15 >= 15
+
+-------------------------------------------------------------------------------
+TemplateTestSig: vectors can be sized and resized - std::string,15
+ resizing smaller changes size but not capacity
+-------------------------------------------------------------------------------
+Misc.tests.cpp:<line number>
+...............................................................................
+
+Misc.tests.cpp:<line number>: PASSED:
+ REQUIRE( v.size() == 0 )
+with expansion:
+ 0 == 0
+
+Misc.tests.cpp:<line number>: PASSED:
+ REQUIRE( v.capacity() >= V )
+with expansion:
+ 15 >= 15
+
+-------------------------------------------------------------------------------
+TemplateTestSig: vectors can be sized and resized - std::string,15
+ resizing smaller changes size but not capacity
+ We can use the 'swap trick' to reset the capacity
+-------------------------------------------------------------------------------
+Misc.tests.cpp:<line number>
+...............................................................................
+
+Misc.tests.cpp:<line number>: PASSED:
+ REQUIRE( v.capacity() == 0 )
+with expansion:
+ 0 == 0
+
+-------------------------------------------------------------------------------
+TemplateTestSig: vectors can be sized and resized - std::string,15
+-------------------------------------------------------------------------------
+Misc.tests.cpp:<line number>
+...............................................................................
+
+Misc.tests.cpp:<line number>: PASSED:
+ REQUIRE( v.size() == V )
+with expansion:
+ 15 == 15
+
+Misc.tests.cpp:<line number>: PASSED:
+ REQUIRE( v.capacity() >= V )
+with expansion:
+ 15 >= 15
+
+-------------------------------------------------------------------------------
+TemplateTestSig: vectors can be sized and resized - std::string,15
+ reserving bigger changes capacity but not size
+-------------------------------------------------------------------------------
+Misc.tests.cpp:<line number>
+...............................................................................
+
+Misc.tests.cpp:<line number>: PASSED:
+ REQUIRE( v.size() == V )
+with expansion:
+ 15 == 15
+
+Misc.tests.cpp:<line number>: PASSED:
+ REQUIRE( v.capacity() >= 2 * V )
+with expansion:
+ 30 >= 30
+
+-------------------------------------------------------------------------------
+TemplateTestSig: vectors can be sized and resized - std::string,15
+-------------------------------------------------------------------------------
+Misc.tests.cpp:<line number>
+...............................................................................
+
+Misc.tests.cpp:<line number>: PASSED:
+ REQUIRE( v.size() == V )
+with expansion:
+ 15 == 15
+
+Misc.tests.cpp:<line number>: PASSED:
+ REQUIRE( v.capacity() >= V )
+with expansion:
+ 15 >= 15
+
+-------------------------------------------------------------------------------
+TemplateTestSig: vectors can be sized and resized - std::string,15
+ reserving smaller does not change size or capacity
+-------------------------------------------------------------------------------
+Misc.tests.cpp:<line number>
+...............................................................................
+
+Misc.tests.cpp:<line number>: PASSED:
+ REQUIRE( v.size() == V )
+with expansion:
+ 15 == 15
+
+Misc.tests.cpp:<line number>: PASSED:
+ REQUIRE( v.capacity() >= V )
+with expansion:
+ 15 >= 15
+
+-------------------------------------------------------------------------------
Test case with one argument
-------------------------------------------------------------------------------
VariadicMacros.tests.cpp:<line number>
@@ -8159,6 +10434,14 @@ with expansion:
3221225472 (0x<hex digits>) == 3221225472
-------------------------------------------------------------------------------
+Test with special, characters "in name
+-------------------------------------------------------------------------------
+CmdLine.tests.cpp:<line number>
+...............................................................................
+
+CmdLine.tests.cpp:<line number>: PASSED:
+
+-------------------------------------------------------------------------------
The NO_FAIL macro reports a failure but does not fail the test
-------------------------------------------------------------------------------
Message.tests.cpp:<line number>
@@ -8654,6 +10937,68 @@ with expansion:
true
-------------------------------------------------------------------------------
+Trim strings
+-------------------------------------------------------------------------------
+StringManip.tests.cpp:<line number>
+...............................................................................
+
+StringManip.tests.cpp:<line number>: PASSED:
+ REQUIRE( trim(std::string(no_whitespace)) == no_whitespace )
+with expansion:
+ "There is no extra whitespace here"
+ ==
+ "There is no extra whitespace here"
+
+StringManip.tests.cpp:<line number>: PASSED:
+ REQUIRE( trim(std::string(leading_whitespace)) == no_whitespace )
+with expansion:
+ "There is no extra whitespace here"
+ ==
+ "There is no extra whitespace here"
+
+StringManip.tests.cpp:<line number>: PASSED:
+ REQUIRE( trim(std::string(trailing_whitespace)) == no_whitespace )
+with expansion:
+ "There is no extra whitespace here"
+ ==
+ "There is no extra whitespace here"
+
+StringManip.tests.cpp:<line number>: PASSED:
+ REQUIRE( trim(std::string(whitespace_at_both_ends)) == no_whitespace )
+with expansion:
+ "There is no extra whitespace here"
+ ==
+ "There is no extra whitespace here"
+
+StringManip.tests.cpp:<line number>: PASSED:
+ REQUIRE( trim(StringRef(no_whitespace)) == StringRef(no_whitespace) )
+with expansion:
+ There is no extra whitespace here
+ ==
+ There is no extra whitespace here
+
+StringManip.tests.cpp:<line number>: PASSED:
+ REQUIRE( trim(StringRef(leading_whitespace)) == StringRef(no_whitespace) )
+with expansion:
+ There is no extra whitespace here
+ ==
+ There is no extra whitespace here
+
+StringManip.tests.cpp:<line number>: PASSED:
+ REQUIRE( trim(StringRef(trailing_whitespace)) == StringRef(no_whitespace) )
+with expansion:
+ There is no extra whitespace here
+ ==
+ There is no extra whitespace here
+
+StringManip.tests.cpp:<line number>: PASSED:
+ REQUIRE( trim(StringRef(whitespace_at_both_ends)) == StringRef(no_whitespace) )
+with expansion:
+ There is no extra whitespace here
+ ==
+ There is no extra whitespace here
+
+-------------------------------------------------------------------------------
Unexpected exceptions can be translated
-------------------------------------------------------------------------------
Exception.tests.cpp:<line number>
@@ -9253,261 +11598,37 @@ with expansion:
"[\x7F]" == "[\x7F]"
-------------------------------------------------------------------------------
-XmlEncode: UTF-8
- Valid utf-8 strings
--------------------------------------------------------------------------------
-Xml.tests.cpp:<line number>
-...............................................................................
-
-Xml.tests.cpp:<line number>: PASSED:
- CHECK( encode(u8"Here be 👾") == u8"Here be 👾" )
-with expansion:
- "Here be 👾" == "Here be 👾"
-
-Xml.tests.cpp:<line number>: PASSED:
- CHECK( encode(u8"Å¡Å¡") == u8"Å¡Å¡" )
-with expansion:
- "Å¡Å¡" == "Å¡Å¡"
-
-Xml.tests.cpp:<line number>: PASSED:
- CHECK( encode("\xDF\xBF") == "\xDF\xBF" )
-with expansion:
- "ß¿" == "ß¿"
-
-Xml.tests.cpp:<line number>: PASSED:
- CHECK( encode("\xE0\xA0\x80") == "\xE0\xA0\x80" )
-with expansion:
- "à €" == "à €"
-
-Xml.tests.cpp:<line number>: PASSED:
- CHECK( encode("\xED\x9F\xBF") == "\xED\x9F\xBF" )
-with expansion:
- "퟿" == "퟿"
-
-Xml.tests.cpp:<line number>: PASSED:
- CHECK( encode("\xEE\x80\x80") == "\xEE\x80\x80" )
-with expansion:
- "" == ""
-
-Xml.tests.cpp:<line number>: PASSED:
- CHECK( encode("\xEF\xBF\xBF") == "\xEF\xBF\xBF" )
-with expansion:
- "ï¿¿" == "ï¿¿"
-
-Xml.tests.cpp:<line number>: PASSED:
- CHECK( encode("\xF0\x90\x80\x80") == "\xF0\x90\x80\x80" )
-with expansion:
- "ð€€" == "ð€€"
-
-Xml.tests.cpp:<line number>: PASSED:
- CHECK( encode("\xF4\x8F\xBF\xBF") == "\xF4\x8F\xBF\xBF" )
-with expansion:
- "ô¿¿" == "ô¿¿"
-
--------------------------------------------------------------------------------
-XmlEncode: UTF-8
- Invalid utf-8 strings
- Various broken strings
+adding a hide tag implicitly enables all others
-------------------------------------------------------------------------------
-Xml.tests.cpp:<line number>
-...............................................................................
-
-Xml.tests.cpp:<line number>: PASSED:
- CHECK( encode("Here \xFF be 👾") == u8"Here \\xFF be 👾" )
-with expansion:
- "Here \xFF be 👾" == "Here \xFF be 👾"
-
-Xml.tests.cpp:<line number>: PASSED:
- CHECK( encode("\xFF") == "\\xFF" )
-with expansion:
- "\xFF" == "\xFF"
-
-Xml.tests.cpp:<line number>: PASSED:
- CHECK( encode("\xC5\xC5\xA0") == u8"\\xC5Å " )
-with expansion:
- "\xC5Å " == "\xC5Å "
-
-Xml.tests.cpp:<line number>: PASSED:
- CHECK( encode("\xF4\x90\x80\x80") == u8"\\xF4\\x90\\x80\\x80" )
-with expansion:
- "\xF4\x90\x80\x80" == "\xF4\x90\x80\x80"
-
--------------------------------------------------------------------------------
-XmlEncode: UTF-8
- Invalid utf-8 strings
- Overlong encodings
--------------------------------------------------------------------------------
-Xml.tests.cpp:<line number>
-...............................................................................
-
-Xml.tests.cpp:<line number>: PASSED:
- CHECK( encode("\xC0\x80") == u8"\\xC0\\x80" )
-with expansion:
- "\xC0\x80" == "\xC0\x80"
-
-Xml.tests.cpp:<line number>: PASSED:
- CHECK( encode("\xF0\x80\x80\x80") == u8"\\xF0\\x80\\x80\\x80" )
-with expansion:
- "\xF0\x80\x80\x80" == "\xF0\x80\x80\x80"
-
-Xml.tests.cpp:<line number>: PASSED:
- CHECK( encode("\xC1\xBF") == u8"\\xC1\\xBF" )
-with expansion:
- "\xC1\xBF" == "\xC1\xBF"
-
-Xml.tests.cpp:<line number>: PASSED:
- CHECK( encode("\xE0\x9F\xBF") == u8"\\xE0\\x9F\\xBF" )
-with expansion:
- "\xE0\x9F\xBF" == "\xE0\x9F\xBF"
-
-Xml.tests.cpp:<line number>: PASSED:
- CHECK( encode("\xF0\x8F\xBF\xBF") == u8"\\xF0\\x8F\\xBF\\xBF" )
-with expansion:
- "\xF0\x8F\xBF\xBF" == "\xF0\x8F\xBF\xBF"
-
--------------------------------------------------------------------------------
-XmlEncode: UTF-8
- Invalid utf-8 strings
- Surrogate pairs
--------------------------------------------------------------------------------
-Xml.tests.cpp:<line number>
+Tag.tests.cpp:<line number>
...............................................................................
-Xml.tests.cpp:<line number>: PASSED:
- CHECK( encode("\xED\xA0\x80") == "\xED\xA0\x80" )
-with expansion:
- "í €" == "í €"
-
-Xml.tests.cpp:<line number>: PASSED:
- CHECK( encode("\xED\xAF\xBF") == "\xED\xAF\xBF" )
-with expansion:
- "í¯¿" == "í¯¿"
-
-Xml.tests.cpp:<line number>: PASSED:
- CHECK( encode("\xED\xB0\x80") == "\xED\xB0\x80" )
-with expansion:
- "í°€" == "í°€"
-
-Xml.tests.cpp:<line number>: PASSED:
- CHECK( encode("\xED\xBF\xBF") == "\xED\xBF\xBF" )
+Tag.tests.cpp:<line number>: PASSED:
+ REQUIRE_THAT( testcase.tags, VectorContains(std::string(".")) && VectorContains(std::string("!hide")) )
with expansion:
- "í¿¿" == "í¿¿"
+ { "!hide", "." } ( Contains: "." and Contains: "!hide" )
-------------------------------------------------------------------------------
-XmlEncode: UTF-8
- Invalid utf-8 strings
- Invalid start byte
+adding a hide tag implicitly enables all others
-------------------------------------------------------------------------------
-Xml.tests.cpp:<line number>
+Tag.tests.cpp:<line number>
...............................................................................
-Xml.tests.cpp:<line number>: PASSED:
- CHECK( encode("\x80") == u8"\\x80" )
-with expansion:
- "\x80" == "\x80"
-
-Xml.tests.cpp:<line number>: PASSED:
- CHECK( encode("\x81") == u8"\\x81" )
-with expansion:
- "\x81" == "\x81"
-
-Xml.tests.cpp:<line number>: PASSED:
- CHECK( encode("\xBC") == u8"\\xBC" )
-with expansion:
- "\xBC" == "\xBC"
-
-Xml.tests.cpp:<line number>: PASSED:
- CHECK( encode("\xBF") == u8"\\xBF" )
-with expansion:
- "\xBF" == "\xBF"
-
-Xml.tests.cpp:<line number>: PASSED:
- CHECK( encode("\xF5\x80\x80\x80") == u8"\\xF5\\x80\\x80\\x80" )
-with expansion:
- "\xF5\x80\x80\x80" == "\xF5\x80\x80\x80"
-
-Xml.tests.cpp:<line number>: PASSED:
- CHECK( encode("\xF6\x80\x80\x80") == u8"\\xF6\\x80\\x80\\x80" )
-with expansion:
- "\xF6\x80\x80\x80" == "\xF6\x80\x80\x80"
-
-Xml.tests.cpp:<line number>: PASSED:
- CHECK( encode("\xF7\x80\x80\x80") == u8"\\xF7\\x80\\x80\\x80" )
+Tag.tests.cpp:<line number>: PASSED:
+ REQUIRE_THAT( testcase.tags, VectorContains(std::string(".")) && VectorContains(std::string("!hide")) )
with expansion:
- "\xF7\x80\x80\x80" == "\xF7\x80\x80\x80"
+ { "!hide", "." } ( Contains: "." and Contains: "!hide" )
-------------------------------------------------------------------------------
-XmlEncode: UTF-8
- Invalid utf-8 strings
- Missing continuation byte(s)
+adding a hide tag implicitly enables all others
-------------------------------------------------------------------------------
-Xml.tests.cpp:<line number>
+Tag.tests.cpp:<line number>
...............................................................................
-Xml.tests.cpp:<line number>: PASSED:
- CHECK( encode("\xDE") == u8"\\xDE" )
-with expansion:
- "\xDE" == "\xDE"
-
-Xml.tests.cpp:<line number>: PASSED:
- CHECK( encode("\xDF") == u8"\\xDF" )
-with expansion:
- "\xDF" == "\xDF"
-
-Xml.tests.cpp:<line number>: PASSED:
- CHECK( encode("\xE0") == u8"\\xE0" )
-with expansion:
- "\xE0" == "\xE0"
-
-Xml.tests.cpp:<line number>: PASSED:
- CHECK( encode("\xEF") == u8"\\xEF" )
-with expansion:
- "\xEF" == "\xEF"
-
-Xml.tests.cpp:<line number>: PASSED:
- CHECK( encode("\xF0") == u8"\\xF0" )
-with expansion:
- "\xF0" == "\xF0"
-
-Xml.tests.cpp:<line number>: PASSED:
- CHECK( encode("\xF4") == u8"\\xF4" )
-with expansion:
- "\xF4" == "\xF4"
-
-Xml.tests.cpp:<line number>: PASSED:
- CHECK( encode("\xE0\x80") == u8"\\xE0\\x80" )
-with expansion:
- "\xE0\x80" == "\xE0\x80"
-
-Xml.tests.cpp:<line number>: PASSED:
- CHECK( encode("\xE0\xBF") == u8"\\xE0\\xBF" )
-with expansion:
- "\xE0\xBF" == "\xE0\xBF"
-
-Xml.tests.cpp:<line number>: PASSED:
- CHECK( encode("\xE1\x80") == u8"\\xE1\\x80" )
-with expansion:
- "\xE1\x80" == "\xE1\x80"
-
-Xml.tests.cpp:<line number>: PASSED:
- CHECK( encode("\xF0\x80") == u8"\\xF0\\x80" )
-with expansion:
- "\xF0\x80" == "\xF0\x80"
-
-Xml.tests.cpp:<line number>: PASSED:
- CHECK( encode("\xF4\x80") == u8"\\xF4\\x80" )
-with expansion:
- "\xF4\x80" == "\xF4\x80"
-
-Xml.tests.cpp:<line number>: PASSED:
- CHECK( encode("\xF0\x80\x80") == u8"\\xF0\\x80\\x80" )
-with expansion:
- "\xF0\x80\x80" == "\xF0\x80\x80"
-
-Xml.tests.cpp:<line number>: PASSED:
- CHECK( encode("\xF4\x80\x80") == u8"\\xF4\\x80\\x80" )
+Tag.tests.cpp:<line number>: PASSED:
+ REQUIRE_THAT( testcase.tags, VectorContains(std::string(".")) && VectorContains(std::string("!hide")) )
with expansion:
- "\xF4\x80\x80" == "\xF4\x80\x80"
+ { "!hide", ".", "foo" } ( Contains: "." and Contains: "!hide" )
-------------------------------------------------------------------------------
array<int, N> -> toString
@@ -10131,6 +12252,62 @@ with expansion:
"{ { 42, "Arthur" }, { "Ford", 24 } }"
-------------------------------------------------------------------------------
+parseEnums
+ No enums
+-------------------------------------------------------------------------------
+ToString.tests.cpp:<line number>
+...............................................................................
+
+ToString.tests.cpp:<line number>: PASSED:
+ CHECK_THAT( parseEnums( "" ), Equals( std::vector<Catch::StringRef>{} ) )
+with expansion:
+ { } Equals: { }
+
+-------------------------------------------------------------------------------
+parseEnums
+ One enum value
+-------------------------------------------------------------------------------
+ToString.tests.cpp:<line number>
+...............................................................................
+
+ToString.tests.cpp:<line number>: PASSED:
+ CHECK_THAT( parseEnums( "ClassName::EnumName::Value1" ), Equals(std::vector<Catch::StringRef>{"Value1"} ) )
+with expansion:
+ { Value1 } Equals: { Value1 }
+
+ToString.tests.cpp:<line number>: PASSED:
+ CHECK_THAT( parseEnums( "Value1" ), Equals( std::vector<Catch::StringRef>{"Value1"} ) )
+with expansion:
+ { Value1 } Equals: { Value1 }
+
+ToString.tests.cpp:<line number>: PASSED:
+ CHECK_THAT( parseEnums( "EnumName::Value1" ), Equals(std::vector<Catch::StringRef>{"Value1"} ) )
+with expansion:
+ { Value1 } Equals: { Value1 }
+
+-------------------------------------------------------------------------------
+parseEnums
+ Multiple enum values
+-------------------------------------------------------------------------------
+ToString.tests.cpp:<line number>
+...............................................................................
+
+ToString.tests.cpp:<line number>: PASSED:
+ CHECK_THAT( parseEnums( "ClassName::EnumName::Value1, ClassName::EnumName::Value2" ), Equals( std::vector<Catch::StringRef>{"Value1", "Value2"} ) )
+with expansion:
+ { Value1, Value2 } Equals: { Value1, Value2 }
+
+ToString.tests.cpp:<line number>: PASSED:
+ CHECK_THAT( parseEnums( "ClassName::EnumName::Value1, ClassName::EnumName::Value2, ClassName::EnumName::Value3" ), Equals( std::vector<Catch::StringRef>{"Value1", "Value2", "Value3"} ) )
+with expansion:
+ { Value1, Value2, Value3 } Equals: { Value1, Value2, Value3 }
+
+ToString.tests.cpp:<line number>: PASSED:
+ CHECK_THAT( parseEnums( "ClassName::EnumName::Value1,ClassName::EnumName::Value2 , ClassName::EnumName::Value3" ), Equals( std::vector<Catch::StringRef>{"Value1", "Value2", "Value3"} ) )
+with expansion:
+ { Value1, Value2, Value3 } Equals: { Value1, Value2, Value3 }
+
+-------------------------------------------------------------------------------
pointer to class
-------------------------------------------------------------------------------
Tricky.tests.cpp:<line number>
@@ -10219,15 +12396,15 @@ with expansion:
replaceInPlace
replace single char
-------------------------------------------------------------------------------
-String.tests.cpp:<line number>
+StringManip.tests.cpp:<line number>
...............................................................................
-String.tests.cpp:<line number>: PASSED:
- CHECK( Catch::replaceInPlace( letters, "b", "z" ) )
+StringManip.tests.cpp:<line number>: PASSED:
+ CHECK( Catch::replaceInPlace(letters, "b", "z") )
with expansion:
true
-String.tests.cpp:<line number>: PASSED:
+StringManip.tests.cpp:<line number>: PASSED:
CHECK( letters == "azcdefcg" )
with expansion:
"azcdefcg" == "azcdefcg"
@@ -10236,15 +12413,15 @@ with expansion:
replaceInPlace
replace two chars
-------------------------------------------------------------------------------
-String.tests.cpp:<line number>
+StringManip.tests.cpp:<line number>
...............................................................................
-String.tests.cpp:<line number>: PASSED:
- CHECK( Catch::replaceInPlace( letters, "c", "z" ) )
+StringManip.tests.cpp:<line number>: PASSED:
+ CHECK( Catch::replaceInPlace(letters, "c", "z") )
with expansion:
true
-String.tests.cpp:<line number>: PASSED:
+StringManip.tests.cpp:<line number>: PASSED:
CHECK( letters == "abzdefzg" )
with expansion:
"abzdefzg" == "abzdefzg"
@@ -10253,15 +12430,15 @@ with expansion:
replaceInPlace
replace first char
-------------------------------------------------------------------------------
-String.tests.cpp:<line number>
+StringManip.tests.cpp:<line number>
...............................................................................
-String.tests.cpp:<line number>: PASSED:
- CHECK( Catch::replaceInPlace( letters, "a", "z" ) )
+StringManip.tests.cpp:<line number>: PASSED:
+ CHECK( Catch::replaceInPlace(letters, "a", "z") )
with expansion:
true
-String.tests.cpp:<line number>: PASSED:
+StringManip.tests.cpp:<line number>: PASSED:
CHECK( letters == "zbcdefcg" )
with expansion:
"zbcdefcg" == "zbcdefcg"
@@ -10270,15 +12447,15 @@ with expansion:
replaceInPlace
replace last char
-------------------------------------------------------------------------------
-String.tests.cpp:<line number>
+StringManip.tests.cpp:<line number>
...............................................................................
-String.tests.cpp:<line number>: PASSED:
- CHECK( Catch::replaceInPlace( letters, "g", "z" ) )
+StringManip.tests.cpp:<line number>: PASSED:
+ CHECK( Catch::replaceInPlace(letters, "g", "z") )
with expansion:
true
-String.tests.cpp:<line number>: PASSED:
+StringManip.tests.cpp:<line number>: PASSED:
CHECK( letters == "abcdefcz" )
with expansion:
"abcdefcz" == "abcdefcz"
@@ -10287,15 +12464,15 @@ with expansion:
replaceInPlace
replace all chars
-------------------------------------------------------------------------------
-String.tests.cpp:<line number>
+StringManip.tests.cpp:<line number>
...............................................................................
-String.tests.cpp:<line number>: PASSED:
- CHECK( Catch::replaceInPlace( letters, letters, "replaced" ) )
+StringManip.tests.cpp:<line number>: PASSED:
+ CHECK( Catch::replaceInPlace(letters, letters, "replaced") )
with expansion:
true
-String.tests.cpp:<line number>: PASSED:
+StringManip.tests.cpp:<line number>: PASSED:
CHECK( letters == "replaced" )
with expansion:
"replaced" == "replaced"
@@ -10304,15 +12481,15 @@ with expansion:
replaceInPlace
replace no chars
-------------------------------------------------------------------------------
-String.tests.cpp:<line number>
+StringManip.tests.cpp:<line number>
...............................................................................
-String.tests.cpp:<line number>: PASSED:
- CHECK_FALSE( Catch::replaceInPlace( letters, "x", "z" ) )
+StringManip.tests.cpp:<line number>: PASSED:
+ CHECK_FALSE( Catch::replaceInPlace(letters, "x", "z") )
with expansion:
!false
-String.tests.cpp:<line number>: PASSED:
+StringManip.tests.cpp:<line number>: PASSED:
CHECK( letters == letters )
with expansion:
"abcdefcg" == "abcdefcg"
@@ -10321,15 +12498,15 @@ with expansion:
replaceInPlace
escape '
-------------------------------------------------------------------------------
-String.tests.cpp:<line number>
+StringManip.tests.cpp:<line number>
...............................................................................
-String.tests.cpp:<line number>: PASSED:
- CHECK( Catch::replaceInPlace( s, "'", "|'" ) )
+StringManip.tests.cpp:<line number>: PASSED:
+ CHECK( Catch::replaceInPlace(s, "'", "|'") )
with expansion:
true
-String.tests.cpp:<line number>: PASSED:
+StringManip.tests.cpp:<line number>: PASSED:
CHECK( s == "didn|'t" )
with expansion:
"didn|'t" == "didn|'t"
@@ -10375,7 +12552,28 @@ Tag.tests.cpp:<line number>
Tag.tests.cpp:<line number>: PASSED:
REQUIRE_THAT( testcase.tags, Catch::VectorContains(std::string("magic-tag")) && Catch::VectorContains(std::string(".")) )
with expansion:
- { ".", "magic-tag" } ( Contains: "magic-tag" and Contains: "." )
+ { "!hide", ".", "magic-tag" } ( Contains: "magic-tag" and Contains: "." )
+
+-------------------------------------------------------------------------------
+splitString
+-------------------------------------------------------------------------------
+StringManip.tests.cpp:<line number>
+...............................................................................
+
+StringManip.tests.cpp:<line number>: PASSED:
+ CHECK_THAT( splitStringRef("", ','), Equals(std::vector<StringRef>()) )
+with expansion:
+ { } Equals: { }
+
+StringManip.tests.cpp:<line number>: PASSED:
+ CHECK_THAT( splitStringRef("abc", ','), Equals(std::vector<StringRef>{"abc"}) )
+with expansion:
+ { abc } Equals: { abc }
+
+StringManip.tests.cpp:<line number>: PASSED:
+ CHECK_THAT( splitStringRef("abc,def", ','), Equals(std::vector<StringRef>{"abc", "def"}) )
+with expansion:
+ { abc, def } Equals: { abc, def }
-------------------------------------------------------------------------------
stacks unscoped info in loops
@@ -11218,6 +13416,6 @@ Misc.tests.cpp:<line number>
Misc.tests.cpp:<line number>: PASSED:
===============================================================================
-test cases: 260 | 177 passed | 79 failed | 4 failed as expected
-assertions: 1445 | 1283 passed | 141 failed | 21 failed as expected
+test cases: 306 | 216 passed | 86 failed | 4 failed as expected
+assertions: 1693 | 1524 passed | 148 failed | 21 failed as expected
diff --git a/projects/SelfTest/Baselines/console.swa4.approved.txt b/projects/SelfTest/Baselines/console.swa4.approved.txt
index bfa66750..322b8158 100644
--- a/projects/SelfTest/Baselines/console.swa4.approved.txt
+++ b/projects/SelfTest/Baselines/console.swa4.approved.txt
@@ -50,6 +50,22 @@ with expansion:
0 == 0
-------------------------------------------------------------------------------
+#1027: Bitfields can be captured
+-------------------------------------------------------------------------------
+Compilation.tests.cpp:<line number>
+...............................................................................
+
+Compilation.tests.cpp:<line number>: PASSED:
+ REQUIRE( y.v == 0 )
+with expansion:
+ 0 == 0
+
+Compilation.tests.cpp:<line number>: PASSED:
+ REQUIRE( 0 == y.v )
+with expansion:
+ 0 == 0
+
+-------------------------------------------------------------------------------
#1147
-------------------------------------------------------------------------------
Compilation.tests.cpp:<line number>
@@ -352,6 +368,6 @@ Condition.tests.cpp:<line number>: FAILED:
CHECK( true != true )
===============================================================================
-test cases: 18 | 13 passed | 3 failed | 2 failed as expected
-assertions: 40 | 33 passed | 4 failed | 3 failed as expected
+test cases: 19 | 14 passed | 3 failed | 2 failed as expected
+assertions: 42 | 35 passed | 4 failed | 3 failed as expected
diff --git a/projects/SelfTest/Baselines/junit.sw.approved.txt b/projects/SelfTest/Baselines/junit.sw.approved.txt
index af4ebe07..6dd03a98 100644
--- a/projects/SelfTest/Baselines/junit.sw.approved.txt
+++ b/projects/SelfTest/Baselines/junit.sw.approved.txt
@@ -1,7 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?>
<testsuitesloose text artifact
>
- <testsuite name="<exe-name>" errors="17" failures="125" tests="1446" hostname="tbd" time="{duration}" timestamp="{iso8601-timestamp}">
+ <testsuite name="<exe-name>" errors="17" failures="132" tests="1694" hostname="tbd" time="{duration}" timestamp="{iso8601-timestamp}">
<properties>
<property name="filters" value="~[!nonportable]~[!benchmark]~[approvals]"/>
<property name="random-seed" value="1"/>
@@ -9,6 +9,7 @@
<testcase classname="<exe-name>.global" name="# A test name that starts with a #" time="{duration}"/>
<testcase classname="<exe-name>.global" name="#1005: Comparing pointer to int and long (NULL can be either on various systems)" time="{duration}"/>
<testcase classname="<exe-name>.global" name="#1027" time="{duration}"/>
+ <testcase classname="<exe-name>.global" name="#1027: Bitfields can be captured" time="{duration}"/>
<testcase classname="<exe-name>.global" name="#1147" time="{duration}"/>
<testcase classname="<exe-name>.global" name="#1175 - Hidden Test" time="{duration}"/>
<testcase classname="<exe-name>.global" name="#1238" time="{duration}"/>
@@ -17,6 +18,7 @@
<testcase classname="<exe-name>.global" name="#1455 - INFO and WARN can start with a linebreak" time="{duration}"/>
<testcase classname="<exe-name>.global" name="#1514: stderr/stdout is not captured in tests aborted by an exception" time="{duration}">
<failure type="FAIL">
+FAILED:
1514
Tricky.tests.cpp:<line number>
</failure>
@@ -30,6 +32,7 @@ Nor would this
<testcase classname="<exe-name>.global" name="#1548" time="{duration}"/>
<testcase classname="<exe-name>.global" name="#748 - captures with unexpected exceptions/outside assertions" time="{duration}">
<error type="TEST_CASE">
+FAILED:
expected exception
answer := 42
Exception.tests.cpp:<line number>
@@ -37,6 +40,8 @@ Exception.tests.cpp:<line number>
</testcase>
<testcase classname="<exe-name>.global" name="#748 - captures with unexpected exceptions/inside REQUIRE_NOTHROW" time="{duration}">
<error message="thisThrows()" type="REQUIRE_NOTHROW">
+FAILED:
+ REQUIRE_NOTHROW( thisThrows() )
expected exception
answer := 42
Exception.tests.cpp:<line number>
@@ -46,7 +51,11 @@ Exception.tests.cpp:<line number>
<testcase classname="<exe-name>.global" name="#809" time="{duration}"/>
<testcase classname="<exe-name>.global" name="#833" time="{duration}"/>
<testcase classname="<exe-name>.global" name="#835 -- errno should not be touched by Catch" time="{duration}">
- <failure message="1 == 0" type="CHECK">
+ <failure message="f() == 0" type="CHECK">
+FAILED:
+ CHECK( f() == 0 )
+with expansion:
+ 1 == 0
Misc.tests.cpp:<line number>
</failure>
</testcase>
@@ -58,27 +67,53 @@ Misc.tests.cpp:<line number>
<testcase classname="<exe-name>.global" name="#961 -- Dynamically created sections should all be reported/Looped section 4" time="{duration}"/>
<testcase classname="<exe-name>.global" name="'Not' checks that should fail" time="{duration}">
<failure message="false != false" type="CHECK">
+FAILED:
+ CHECK( false != false )
Condition.tests.cpp:<line number>
</failure>
<failure message="true != true" type="CHECK">
+FAILED:
+ CHECK( true != true )
Condition.tests.cpp:<line number>
</failure>
- <failure message="false" type="CHECK">
+ <failure message="!true" type="CHECK">
+FAILED:
+ CHECK( !true )
+with expansion:
+ false
Condition.tests.cpp:<line number>
</failure>
- <failure message="!true" type="CHECK_FALSE">
+ <failure message="!(true)" type="CHECK_FALSE">
+FAILED:
+ CHECK_FALSE( true )
+with expansion:
+ !true
Condition.tests.cpp:<line number>
</failure>
- <failure message="false" type="CHECK">
+ <failure message="!trueValue" type="CHECK">
+FAILED:
+ CHECK( !trueValue )
+with expansion:
+ false
Condition.tests.cpp:<line number>
</failure>
- <failure message="!true" type="CHECK_FALSE">
+ <failure message="!(trueValue)" type="CHECK_FALSE">
+FAILED:
+ CHECK_FALSE( trueValue )
+with expansion:
+ !true
Condition.tests.cpp:<line number>
</failure>
- <failure message="false" type="CHECK">
+ <failure message="!(1 == 1)" type="CHECK">
+FAILED:
+ CHECK( !(1 == 1) )
+with expansion:
+ false
Condition.tests.cpp:<line number>
</failure>
<failure message="!(1 == 1)" type="CHECK_FALSE">
+FAILED:
+ CHECK_FALSE( 1 == 1 )
Condition.tests.cpp:<line number>
</failure>
</testcase>
@@ -90,28 +125,48 @@ Condition.tests.cpp:<line number>
<testcase classname="<exe-name>.global" name="(unimplemented) static bools can be evaluated/direct" time="{duration}"/>
<testcase classname="<exe-name>.global" name="3x3x3 ints" time="{duration}"/>
<testcase classname="<exe-name>.TestClass" name="A METHOD_AS_TEST_CASE based test run that fails" time="{duration}">
- <failure message="&quot;hello&quot; == &quot;world&quot;" type="REQUIRE">
+ <failure message="s == &quot;world&quot;" type="REQUIRE">
+FAILED:
+ REQUIRE( s == "world" )
+with expansion:
+ "hello" == "world"
Class.tests.cpp:<line number>
</failure>
</testcase>
<testcase classname="<exe-name>.TestClass" name="A METHOD_AS_TEST_CASE based test run that succeeds" time="{duration}"/>
<testcase classname="<exe-name>.Template_Fixture_2" name="A TEMPLATE_PRODUCT_TEST_CASE_METHOD based test run that fails - Template_Foo&lt;float>" time="{duration}">
- <failure message="0 == 1" type="REQUIRE">
+ <failure message="Template_Fixture_2&lt;TestType>::m_a.size() == 1" type="REQUIRE">
+FAILED:
+ REQUIRE( Template_Fixture_2&lt;TestType>::m_a.size() == 1 )
+with expansion:
+ 0 == 1
Class.tests.cpp:<line number>
</failure>
</testcase>
<testcase classname="<exe-name>.Template_Fixture_2" name="A TEMPLATE_PRODUCT_TEST_CASE_METHOD based test run that fails - Template_Foo&lt;int>" time="{duration}">
- <failure message="0 == 1" type="REQUIRE">
+ <failure message="Template_Fixture_2&lt;TestType>::m_a.size() == 1" type="REQUIRE">
+FAILED:
+ REQUIRE( Template_Fixture_2&lt;TestType>::m_a.size() == 1 )
+with expansion:
+ 0 == 1
Class.tests.cpp:<line number>
</failure>
</testcase>
<testcase classname="<exe-name>.Template_Fixture_2" name="A TEMPLATE_PRODUCT_TEST_CASE_METHOD based test run that fails - std::vector&lt;float>" time="{duration}">
- <failure message="0 == 1" type="REQUIRE">
+ <failure message="Template_Fixture_2&lt;TestType>::m_a.size() == 1" type="REQUIRE">
+FAILED:
+ REQUIRE( Template_Fixture_2&lt;TestType>::m_a.size() == 1 )
+with expansion:
+ 0 == 1
Class.tests.cpp:<line number>
</failure>
</testcase>
<testcase classname="<exe-name>.Template_Fixture_2" name="A TEMPLATE_PRODUCT_TEST_CASE_METHOD based test run that fails - std::vector&lt;int>" time="{duration}">
- <failure message="0 == 1" type="REQUIRE">
+ <failure message="Template_Fixture_2&lt;TestType>::m_a.size() == 1" type="REQUIRE">
+FAILED:
+ REQUIRE( Template_Fixture_2&lt;TestType>::m_a.size() == 1 )
+with expansion:
+ 0 == 1
Class.tests.cpp:<line number>
</failure>
</testcase>
@@ -119,26 +174,112 @@ Class.tests.cpp:<line number>
<testcase classname="<exe-name>.Template_Fixture_2" name="A TEMPLATE_PRODUCT_TEST_CASE_METHOD based test run that succeeds - Template_Foo&lt;int>" time="{duration}"/>
<testcase classname="<exe-name>.Template_Fixture_2" name="A TEMPLATE_PRODUCT_TEST_CASE_METHOD based test run that succeeds - std::vector&lt;float>" time="{duration}"/>
<testcase classname="<exe-name>.Template_Fixture_2" name="A TEMPLATE_PRODUCT_TEST_CASE_METHOD based test run that succeeds - std::vector&lt;int>" time="{duration}"/>
+ <testcase classname="<exe-name>.Template_Fixture_2" name="A TEMPLATE_PRODUCT_TEST_CASE_METHOD_SIG based test run that fails - Template_Foo_2&lt;float, 6>" time="{duration}">
+ <failure message="Template_Fixture_2&lt;TestType>{}.m_a.size() &lt; 2" type="REQUIRE">
+FAILED:
+ REQUIRE( Template_Fixture_2&lt;TestType>{}.m_a.size() &lt; 2 )
+with expansion:
+ 6 &lt; 2
+Class.tests.cpp:<line number>
+ </failure>
+ </testcase>
+ <testcase classname="<exe-name>.Template_Fixture_2" name="A TEMPLATE_PRODUCT_TEST_CASE_METHOD_SIG based test run that fails - Template_Foo_2&lt;int, 2>" time="{duration}">
+ <failure message="Template_Fixture_2&lt;TestType>{}.m_a.size() &lt; 2" type="REQUIRE">
+FAILED:
+ REQUIRE( Template_Fixture_2&lt;TestType>{}.m_a.size() &lt; 2 )
+with expansion:
+ 2 &lt; 2
+Class.tests.cpp:<line number>
+ </failure>
+ </testcase>
+ <testcase classname="<exe-name>.Template_Fixture_2" name="A TEMPLATE_PRODUCT_TEST_CASE_METHOD_SIG based test run that fails - std::array&lt;float, 6>" time="{duration}">
+ <failure message="Template_Fixture_2&lt;TestType>{}.m_a.size() &lt; 2" type="REQUIRE">
+FAILED:
+ REQUIRE( Template_Fixture_2&lt;TestType>{}.m_a.size() &lt; 2 )
+with expansion:
+ 6 &lt; 2
+Class.tests.cpp:<line number>
+ </failure>
+ </testcase>
+ <testcase classname="<exe-name>.Template_Fixture_2" name="A TEMPLATE_PRODUCT_TEST_CASE_METHOD_SIG based test run that fails - std::array&lt;int, 2>" time="{duration}">
+ <failure message="Template_Fixture_2&lt;TestType>{}.m_a.size() &lt; 2" type="REQUIRE">
+FAILED:
+ REQUIRE( Template_Fixture_2&lt;TestType>{}.m_a.size() &lt; 2 )
+with expansion:
+ 2 &lt; 2
+Class.tests.cpp:<line number>
+ </failure>
+ </testcase>
+ <testcase classname="<exe-name>.Template_Fixture_2" name="A TEMPLATE_PRODUCT_TEST_CASE_METHOD_SIG based test run that succeeds - Template_Foo_2&lt;float,6>" time="{duration}"/>
+ <testcase classname="<exe-name>.Template_Fixture_2" name="A TEMPLATE_PRODUCT_TEST_CASE_METHOD_SIG based test run that succeeds - Template_Foo_2&lt;int,2>" time="{duration}"/>
+ <testcase classname="<exe-name>.Template_Fixture_2" name="A TEMPLATE_PRODUCT_TEST_CASE_METHOD_SIG based test run that succeeds - std::array&lt;float,6>" time="{duration}"/>
+ <testcase classname="<exe-name>.Template_Fixture_2" name="A TEMPLATE_PRODUCT_TEST_CASE_METHOD_SIG based test run that succeeds - std::array&lt;int,2>" time="{duration}"/>
<testcase classname="<exe-name>.Template_Fixture" name="A TEMPLATE_TEST_CASE_METHOD based test run that fails - double" time="{duration}">
- <failure message="1.0 == 2" type="REQUIRE">
+ <failure message="Template_Fixture&lt;TestType>::m_a == 2" type="REQUIRE">
+FAILED:
+ REQUIRE( Template_Fixture&lt;TestType>::m_a == 2 )
+with expansion:
+ 1.0 == 2
Class.tests.cpp:<line number>
</failure>
</testcase>
<testcase classname="<exe-name>.Template_Fixture" name="A TEMPLATE_TEST_CASE_METHOD based test run that fails - float" time="{duration}">
- <failure message="1.0f == 2" type="REQUIRE">
+ <failure message="Template_Fixture&lt;TestType>::m_a == 2" type="REQUIRE">
+FAILED:
+ REQUIRE( Template_Fixture&lt;TestType>::m_a == 2 )
+with expansion:
+ 1.0f == 2
Class.tests.cpp:<line number>
</failure>
</testcase>
<testcase classname="<exe-name>.Template_Fixture" name="A TEMPLATE_TEST_CASE_METHOD based test run that fails - int" time="{duration}">
- <failure message="1 == 2" type="REQUIRE">
+ <failure message="Template_Fixture&lt;TestType>::m_a == 2" type="REQUIRE">
+FAILED:
+ REQUIRE( Template_Fixture&lt;TestType>::m_a == 2 )
+with expansion:
+ 1 == 2
Class.tests.cpp:<line number>
</failure>
</testcase>
<testcase classname="<exe-name>.Template_Fixture" name="A TEMPLATE_TEST_CASE_METHOD based test run that succeeds - double" time="{duration}"/>
<testcase classname="<exe-name>.Template_Fixture" name="A TEMPLATE_TEST_CASE_METHOD based test run that succeeds - float" time="{duration}"/>
<testcase classname="<exe-name>.Template_Fixture" name="A TEMPLATE_TEST_CASE_METHOD based test run that succeeds - int" time="{duration}"/>
+ <testcase classname="<exe-name>.Nttp_Fixture" name="A TEMPLATE_TEST_CASE_METHOD_SIG based test run that fails - 1" time="{duration}">
+ <failure message="Nttp_Fixture&lt;V>::value == 0" type="REQUIRE">
+FAILED:
+ REQUIRE( Nttp_Fixture&lt;V>::value == 0 )
+with expansion:
+ 1 == 0
+Class.tests.cpp:<line number>
+ </failure>
+ </testcase>
+ <testcase classname="<exe-name>.Nttp_Fixture" name="A TEMPLATE_TEST_CASE_METHOD_SIG based test run that fails - 3" time="{duration}">
+ <failure message="Nttp_Fixture&lt;V>::value == 0" type="REQUIRE">
+FAILED:
+ REQUIRE( Nttp_Fixture&lt;V>::value == 0 )
+with expansion:
+ 3 == 0
+Class.tests.cpp:<line number>
+ </failure>
+ </testcase>
+ <testcase classname="<exe-name>.Nttp_Fixture" name="A TEMPLATE_TEST_CASE_METHOD_SIG based test run that fails - 6" time="{duration}">
+ <failure message="Nttp_Fixture&lt;V>::value == 0" type="REQUIRE">
+FAILED:
+ REQUIRE( Nttp_Fixture&lt;V>::value == 0 )
+with expansion:
+ 6 == 0
+Class.tests.cpp:<line number>
+ </failure>
+ </testcase>
+ <testcase classname="<exe-name>.Nttp_Fixture" name="A TEMPLATE_TEST_CASE_METHOD_SIG based test run that succeeds - 1" time="{duration}"/>
+ <testcase classname="<exe-name>.Nttp_Fixture" name="A TEMPLATE_TEST_CASE_METHOD_SIG based test run that succeeds - 3" time="{duration}"/>
+ <testcase classname="<exe-name>.Nttp_Fixture" name="A TEMPLATE_TEST_CASE_METHOD_SIG based test run that succeeds - 6" time="{duration}"/>
<testcase classname="<exe-name>.Fixture" name="A TEST_CASE_METHOD based test run that fails" time="{duration}">
- <failure message="1 == 2" type="REQUIRE">
+ <failure message="m_a == 2" type="REQUIRE">
+FAILED:
+ REQUIRE( m_a == 2 )
+with expansion:
+ 1 == 2
Class.tests.cpp:<line number>
</failure>
</testcase>
@@ -147,19 +288,32 @@ Class.tests.cpp:<line number>
<testcase classname="<exe-name>.global" name="A Template product test case - Foo&lt;int>" time="{duration}"/>
<testcase classname="<exe-name>.global" name="A Template product test case - std::vector&lt;float>" time="{duration}"/>
<testcase classname="<exe-name>.global" name="A Template product test case - std::vector&lt;int>" time="{duration}"/>
+ <testcase classname="<exe-name>.global" name="A Template product test case with array signature - Bar&lt;float, 42>" time="{duration}"/>
+ <testcase classname="<exe-name>.global" name="A Template product test case with array signature - Bar&lt;int, 9>" time="{duration}"/>
+ <testcase classname="<exe-name>.global" name="A Template product test case with array signature - std::array&lt;float, 42>" time="{duration}"/>
+ <testcase classname="<exe-name>.global" name="A Template product test case with array signature - std::array&lt;int, 9>" time="{duration}"/>
<testcase classname="<exe-name>.global" name="A comparison that uses literals instead of the normal constructor" time="{duration}"/>
<testcase classname="<exe-name>.global" name="A couple of nested sections followed by a failure" time="{duration}">
<failure type="FAIL">
+FAILED:
to infinity and beyond
Misc.tests.cpp:<line number>
</failure>
</testcase>
<testcase classname="<exe-name>.global" name="A couple of nested sections followed by a failure/Outer/Inner" time="{duration}"/>
<testcase classname="<exe-name>.global" name="A failing expression with a non streamable type is still captured" time="{duration}">
- <failure message="0x<hex digits> == 0x<hex digits>" type="CHECK">
+ <failure message="&amp;o1 == &amp;o2" type="CHECK">
+FAILED:
+ CHECK( &amp;o1 == &amp;o2 )
+with expansion:
+ 0x<hex digits> == 0x<hex digits>
Tricky.tests.cpp:<line number>
</failure>
- <failure message="{?} == {?}" type="CHECK">
+ <failure message="o1 == o2" type="CHECK">
+FAILED:
+ CHECK( o1 == o2 )
+with expansion:
+ {?} == {?}
Tricky.tests.cpp:<line number>
</failure>
</testcase>
@@ -167,6 +321,8 @@ Tricky.tests.cpp:<line number>
<testcase classname="<exe-name>.global" name="An expression with side-effects should only be evaluated once" time="{duration}"/>
<testcase classname="<exe-name>.global" name="An unchecked exception reports the line of the last assertion" time="{duration}">
<error message="{Unknown expression after the reported line}">
+FAILED:
+ {Unknown expression after the reported line}
unexpected exception
Exception.tests.cpp:<line number>
</error>
@@ -185,10 +341,9 @@ Exception.tests.cpp:<line number>
<testcase classname="<exe-name>.global" name="Assertions then sections/A section" time="{duration}"/>
<testcase classname="<exe-name>.global" name="Assertions then sections/A section/Another section" time="{duration}"/>
<testcase classname="<exe-name>.global" name="Assertions then sections/A section/Another other section" time="{duration}"/>
- <testcase classname="<exe-name>.global" name="Assorted miscellaneous tests" time="{duration}"/>
- <testcase classname="<exe-name>.global" name="Bitfields can be captured (#1027)" time="{duration}"/>
<testcase classname="<exe-name>.global" name="CAPTURE can deal with complex expressions" time="{duration}"/>
<testcase classname="<exe-name>.global" name="CAPTURE can deal with complex expressions involving commas" time="{duration}"/>
+ <testcase classname="<exe-name>.global" name="CAPTURE parses string and character constants" time="{duration}"/>
<testcase classname="<exe-name>.global" name="Capture and info messages/Capture should stringify like assertions" time="{duration}"/>
<testcase classname="<exe-name>.global" name="Capture and info messages/Info should NOT stringify the way assertions do" time="{duration}"/>
<testcase classname="<exe-name>.global" name="Character pretty printing/Specifically escaped" time="{duration}"/>
@@ -196,121 +351,230 @@ Exception.tests.cpp:<line number>
<testcase classname="<exe-name>.global" name="Character pretty printing/Low ASCII" time="{duration}"/>
<testcase classname="<exe-name>.global" name="Commas in various macros are allowed" time="{duration}"/>
<testcase classname="<exe-name>.global" name="Comparing function pointers" time="{duration}"/>
+ <testcase classname="<exe-name>.global" name="Comparison ops" time="{duration}"/>
<testcase classname="<exe-name>.global" name="Comparison with explicitly convertible types" time="{duration}"/>
<testcase classname="<exe-name>.global" name="Comparisons between ints where one side is computed" time="{duration}"/>
<testcase classname="<exe-name>.global" name="Comparisons between unsigned ints and negative signed ints match c++ standard behaviour" time="{duration}"/>
<testcase classname="<exe-name>.global" name="Comparisons with int literals don't warn when mixing signed/ unsigned" time="{duration}"/>
+ <testcase classname="<exe-name>.global" name="Composed matchers are distinct" time="{duration}"/>
<testcase classname="<exe-name>.global" name="Contains string matcher" time="{duration}">
- <failure message="&quot;this string contains 'abc' as a substring&quot; contains: &quot;not there&quot; (case insensitive)" type="CHECK_THAT">
+ <failure message="testStringForMatching(), Contains(&quot;not there&quot;, Catch::CaseSensitive::No)" type="CHECK_THAT">
+FAILED:
+ CHECK_THAT( testStringForMatching(), Contains("not there", Catch::CaseSensitive::No) )
+with expansion:
+ "this string contains 'abc' as a substring" contains: "not there" (case
+ insensitive)
Matchers.tests.cpp:<line number>
</failure>
- <failure message="&quot;this string contains 'abc' as a substring&quot; contains: &quot;STRING&quot;" type="CHECK_THAT">
+ <failure message="testStringForMatching(), Contains(&quot;STRING&quot;)" type="CHECK_THAT">
+FAILED:
+ CHECK_THAT( testStringForMatching(), Contains("STRING") )
+with expansion:
+ "this string contains 'abc' as a substring" contains: "STRING"
Matchers.tests.cpp:<line number>
</failure>
</testcase>
+ <testcase classname="<exe-name>.global" name="Copy and then generate a range/from var and iterators" time="{duration}"/>
+ <testcase classname="<exe-name>.global" name="Copy and then generate a range/From a temporary container" time="{duration}"/>
+ <testcase classname="<exe-name>.global" name="Copy and then generate a range/Final validation" time="{duration}"/>
<testcase classname="<exe-name>.global" name="Custom exceptions can be translated when testing for nothrow" time="{duration}">
<error message="throwCustom()" type="REQUIRE_NOTHROW">
+FAILED:
+ REQUIRE_NOTHROW( throwCustom() )
custom exception - not std
Exception.tests.cpp:<line number>
</error>
</testcase>
<testcase classname="<exe-name>.global" name="Custom exceptions can be translated when testing for throwing as something else" time="{duration}">
<error message="throwCustom(), std::exception" type="REQUIRE_THROWS_AS">
+FAILED:
+ REQUIRE_THROWS_AS( throwCustom(), std::exception )
custom exception - not std
Exception.tests.cpp:<line number>
</error>
</testcase>
<testcase classname="<exe-name>.global" name="Custom std-exceptions can be custom translated" time="{duration}">
<error type="TEST_CASE">
+FAILED:
custom std exception
Exception.tests.cpp:<line number>
</error>
</testcase>
<testcase classname="<exe-name>.global" name="Default scale is invisible to comparison" time="{duration}"/>
+ <testcase classname="<exe-name>.global" name="Directly creating an EnumInfo" time="{duration}"/>
<testcase classname="<exe-name>.global" name="EndsWith string matcher" time="{duration}">
- <failure message="&quot;this string contains 'abc' as a substring&quot; ends with: &quot;Substring&quot;" type="CHECK_THAT">
+ <failure message="testStringForMatching(), EndsWith(&quot;Substring&quot;)" type="CHECK_THAT">
+FAILED:
+ CHECK_THAT( testStringForMatching(), EndsWith("Substring") )
+with expansion:
+ "this string contains 'abc' as a substring" ends with: "Substring"
Matchers.tests.cpp:<line number>
</failure>
- <failure message="&quot;this string contains 'abc' as a substring&quot; ends with: &quot;this&quot; (case insensitive)" type="CHECK_THAT">
+ <failure message="testStringForMatching(), EndsWith(&quot;this&quot;, Catch::CaseSensitive::No)" type="CHECK_THAT">
+FAILED:
+ CHECK_THAT( testStringForMatching(), EndsWith("this", Catch::CaseSensitive::No) )
+with expansion:
+ "this string contains 'abc' as a substring" ends with: "this" (case
+ insensitive)
Matchers.tests.cpp:<line number>
</failure>
</testcase>
+ <testcase classname="<exe-name>.global" name="Enums can quickly have stringification enabled using REGISTER_ENUM" time="{duration}"/>
+ <testcase classname="<exe-name>.global" name="Enums in namespaces can quickly have stringification enabled using REGISTER_ENUM" time="{duration}"/>
<testcase classname="<exe-name>.global" name="Epsilon only applies to Approx's value" time="{duration}"/>
<testcase classname="<exe-name>.global" name="Equality checks that should fail" time="{duration}">
- <failure message="7 == 6" type="CHECK">
+ <failure message="data.int_seven == 6" type="CHECK">
+FAILED:
+ CHECK( data.int_seven == 6 )
+with expansion:
+ 7 == 6
Condition.tests.cpp:<line number>
</failure>
- <failure message="7 == 8" type="CHECK">
+ <failure message="data.int_seven == 8" type="CHECK">
+FAILED:
+ CHECK( data.int_seven == 8 )
+with expansion:
+ 7 == 8
Condition.tests.cpp:<line number>
</failure>
- <failure message="7 == 0" type="CHECK">
+ <failure message="data.int_seven == 0" type="CHECK">
+FAILED:
+ CHECK( data.int_seven == 0 )
+with expansion:
+ 7 == 0
Condition.tests.cpp:<line number>
</failure>
- <failure message="9.1f == Approx( 9.1099996567 )" type="CHECK">
+ <failure message="data.float_nine_point_one == Approx( 9.11f )" type="CHECK">
+FAILED:
+ CHECK( data.float_nine_point_one == Approx( 9.11f ) )
+with expansion:
+ 9.1f == Approx( 9.1099996567 )
Condition.tests.cpp:<line number>
</failure>
- <failure message="9.1f == Approx( 9.0 )" type="CHECK">
+ <failure message="data.float_nine_point_one == Approx( 9.0f )" type="CHECK">
+FAILED:
+ CHECK( data.float_nine_point_one == Approx( 9.0f ) )
+with expansion:
+ 9.1f == Approx( 9.0 )
Condition.tests.cpp:<line number>
</failure>
- <failure message="9.1f == Approx( 1.0 )" type="CHECK">
+ <failure message="data.float_nine_point_one == Approx( 1 )" type="CHECK">
+FAILED:
+ CHECK( data.float_nine_point_one == Approx( 1 ) )
+with expansion:
+ 9.1f == Approx( 1.0 )
Condition.tests.cpp:<line number>
</failure>
- <failure message="9.1f == Approx( 0.0 )" type="CHECK">
+ <failure message="data.float_nine_point_one == Approx( 0 )" type="CHECK">
+FAILED:
+ CHECK( data.float_nine_point_one == Approx( 0 ) )
+with expansion:
+ 9.1f == Approx( 0.0 )
Condition.tests.cpp:<line number>
</failure>
- <failure message="3.1415926535 == Approx( 3.1415 )" type="CHECK">
+ <failure message="data.double_pi == Approx( 3.1415 )" type="CHECK">
+FAILED:
+ CHECK( data.double_pi == Approx( 3.1415 ) )
+with expansion:
+ 3.1415926535 == Approx( 3.1415 )
Condition.tests.cpp:<line number>
</failure>
- <failure message="&quot;hello&quot; == &quot;goodbye&quot;" type="CHECK">
+ <failure message="data.str_hello == &quot;goodbye&quot;" type="CHECK">
+FAILED:
+ CHECK( data.str_hello == "goodbye" )
+with expansion:
+ "hello" == "goodbye"
Condition.tests.cpp:<line number>
</failure>
- <failure message="&quot;hello&quot; == &quot;hell&quot;" type="CHECK">
+ <failure message="data.str_hello == &quot;hell&quot;" type="CHECK">
+FAILED:
+ CHECK( data.str_hello == "hell" )
+with expansion:
+ "hello" == "hell"
Condition.tests.cpp:<line number>
</failure>
- <failure message="&quot;hello&quot; == &quot;hello1&quot;" type="CHECK">
+ <failure message="data.str_hello == &quot;hello1&quot;" type="CHECK">
+FAILED:
+ CHECK( data.str_hello == "hello1" )
+with expansion:
+ "hello" == "hello1"
Condition.tests.cpp:<line number>
</failure>
- <failure message="5 == 6" type="CHECK">
+ <failure message="data.str_hello.size() == 6" type="CHECK">
+FAILED:
+ CHECK( data.str_hello.size() == 6 )
+with expansion:
+ 5 == 6
Condition.tests.cpp:<line number>
</failure>
- <failure message="1.3 == Approx( 1.301 )" type="CHECK">
+ <failure message="x == Approx( 1.301 )" type="CHECK">
+FAILED:
+ CHECK( x == Approx( 1.301 ) )
+with expansion:
+ 1.3 == Approx( 1.301 )
Condition.tests.cpp:<line number>
</failure>
</testcase>
<testcase classname="<exe-name>.global" name="Equality checks that should succeed" time="{duration}"/>
<testcase classname="<exe-name>.global" name="Equals" time="{duration}"/>
<testcase classname="<exe-name>.global" name="Equals string matcher" time="{duration}">
- <failure message="&quot;this string contains 'abc' as a substring&quot; equals: &quot;this string contains 'ABC' as a substring&quot;" type="CHECK_THAT">
+ <failure message="testStringForMatching(), Equals(&quot;this string contains 'ABC' as a substring&quot;)" type="CHECK_THAT">
+FAILED:
+ CHECK_THAT( testStringForMatching(), Equals("this string contains 'ABC' as a substring") )
+with expansion:
+ "this string contains 'abc' as a substring" equals: "this string contains
+ 'ABC' as a substring"
Matchers.tests.cpp:<line number>
</failure>
- <failure message="&quot;this string contains 'abc' as a substring&quot; equals: &quot;something else&quot; (case insensitive)" type="CHECK_THAT">
+ <failure message="testStringForMatching(), Equals(&quot;something else&quot;, Catch::CaseSensitive::No)" type="CHECK_THAT">
+FAILED:
+ CHECK_THAT( testStringForMatching(), Equals("something else", Catch::CaseSensitive::No) )
+with expansion:
+ "this string contains 'abc' as a substring" equals: "something else" (case
+ insensitive)
Matchers.tests.cpp:<line number>
</failure>
</testcase>
<testcase classname="<exe-name>.global" name="Exception as a value (e.g. in REQUIRE_THROWS_MATCHES) can be stringified" time="{duration}"/>
<testcase classname="<exe-name>.global" name="Exception matchers that fail/No exception" time="{duration}">
<failure message="doesNotThrow(), SpecialException, ExceptionMatcher{1}" type="CHECK_THROWS_MATCHES">
+FAILED:
+ CHECK_THROWS_MATCHES( doesNotThrow(), SpecialException, ExceptionMatcher{1} )
Matchers.tests.cpp:<line number>
</failure>
<failure message="doesNotThrow(), SpecialException, ExceptionMatcher{1}" type="REQUIRE_THROWS_MATCHES">
+FAILED:
+ REQUIRE_THROWS_MATCHES( doesNotThrow(), SpecialException, ExceptionMatcher{1} )
Matchers.tests.cpp:<line number>
</failure>
</testcase>
<testcase classname="<exe-name>.global" name="Exception matchers that fail/Type mismatch" time="{duration}">
<error message="throwsAsInt(1), SpecialException, ExceptionMatcher{1}" type="CHECK_THROWS_MATCHES">
+FAILED:
+ CHECK_THROWS_MATCHES( throwsAsInt(1), SpecialException, ExceptionMatcher{1} )
Unknown exception
Matchers.tests.cpp:<line number>
</error>
<error message="throwsAsInt(1), SpecialException, ExceptionMatcher{1}" type="REQUIRE_THROWS_MATCHES">
+FAILED:
+ REQUIRE_THROWS_MATCHES( throwsAsInt(1), SpecialException, ExceptionMatcher{1} )
Unknown exception
Matchers.tests.cpp:<line number>
</error>
</testcase>
<testcase classname="<exe-name>.global" name="Exception matchers that fail/Contents are wrong" time="{duration}">
- <failure message="SpecialException::what special exception has value of 1" type="CHECK_THROWS_MATCHES">
+ <failure message="throwsSpecialException(3), SpecialException, ExceptionMatcher{1}" type="CHECK_THROWS_MATCHES">
+FAILED:
+ CHECK_THROWS_MATCHES( throwsSpecialException(3), SpecialException, ExceptionMatcher{1} )
+with expansion:
+ SpecialException::what special exception has value of 1
Matchers.tests.cpp:<line number>
</failure>
- <failure message="SpecialException::what special exception has value of 1" type="REQUIRE_THROWS_MATCHES">
+ <failure message="throwsSpecialException(4), SpecialException, ExceptionMatcher{1}" type="REQUIRE_THROWS_MATCHES">
+FAILED:
+ REQUIRE_THROWS_MATCHES( throwsSpecialException(4), SpecialException, ExceptionMatcher{1} )
+with expansion:
+ SpecialException::what special exception has value of 1
Matchers.tests.cpp:<line number>
</failure>
</testcase>
@@ -318,41 +582,55 @@ Matchers.tests.cpp:<line number>
<testcase classname="<exe-name>.global" name="Exception messages can be tested for/exact match" time="{duration}"/>
<testcase classname="<exe-name>.global" name="Exception messages can be tested for/different case" time="{duration}"/>
<testcase classname="<exe-name>.global" name="Exception messages can be tested for/wildcarded" time="{duration}"/>
+ <testcase classname="<exe-name>.global" name="Exceptions matchers" time="{duration}"/>
<testcase classname="<exe-name>.global" name="Expected exceptions that don't throw or unexpected exceptions fail the test" time="{duration}">
<error message="thisThrows(), std::string" type="CHECK_THROWS_AS">
+FAILED:
+ CHECK_THROWS_AS( thisThrows(), std::string )
expected exception
Exception.tests.cpp:<line number>
</error>
<failure message="thisDoesntThrow(), std::domain_error" type="CHECK_THROWS_AS">
+FAILED:
+ CHECK_THROWS_AS( thisDoesntThrow(), std::domain_error )
Exception.tests.cpp:<line number>
</failure>
<error message="thisThrows()" type="CHECK_NOTHROW">
+FAILED:
+ CHECK_NOTHROW( thisThrows() )
expected exception
Exception.tests.cpp:<line number>
</error>
</testcase>
<testcase classname="<exe-name>.global" name="FAIL aborts the test" time="{duration}">
<failure type="FAIL">
+FAILED:
This is a failure
Message.tests.cpp:<line number>
</failure>
</testcase>
<testcase classname="<exe-name>.global" name="FAIL does not require an argument" time="{duration}">
<failure type="FAIL">
+FAILED:
Message.tests.cpp:<line number>
</failure>
</testcase>
<testcase classname="<exe-name>.global" name="FAIL_CHECK does not abort the test" time="{duration}">
<failure type="FAIL_CHECK">
+FAILED:
This is a failure
Message.tests.cpp:<line number>
</failure>
</testcase>
<testcase classname="<exe-name>.global" name="Factorials are computed" time="{duration}"/>
+ <testcase classname="<exe-name>.global" name="Floating point matchers: double/Relative" time="{duration}"/>
+ <testcase classname="<exe-name>.global" name="Floating point matchers: double/Relative/Some subnormal values" time="{duration}"/>
<testcase classname="<exe-name>.global" name="Floating point matchers: double/Margin" time="{duration}"/>
<testcase classname="<exe-name>.global" name="Floating point matchers: double/ULPs" time="{duration}"/>
<testcase classname="<exe-name>.global" name="Floating point matchers: double/Composed" time="{duration}"/>
<testcase classname="<exe-name>.global" name="Floating point matchers: double/Constructor validation" time="{duration}"/>
+ <testcase classname="<exe-name>.global" name="Floating point matchers: float/Relative" time="{duration}"/>
+ <testcase classname="<exe-name>.global" name="Floating point matchers: float/Relative/Some subnormal values" time="{duration}"/>
<testcase classname="<exe-name>.global" name="Floating point matchers: float/Margin" time="{duration}"/>
<testcase classname="<exe-name>.global" name="Floating point matchers: float/ULPs" time="{duration}"/>
<testcase classname="<exe-name>.global" name="Floating point matchers: float/Composed" time="{duration}"/>
@@ -366,6 +644,7 @@ Message.tests.cpp:<line number>
<testcase classname="<exe-name>.global" name="Generators -- adapters/Repeating a generator" time="{duration}"/>
<testcase classname="<exe-name>.global" name="Generators -- adapters/Chunking a generator into sized pieces/Number of elements in source is divisible by chunk size" time="{duration}"/>
<testcase classname="<exe-name>.global" name="Generators -- adapters/Chunking a generator into sized pieces/Number of elements in source is not divisible by chunk size" time="{duration}"/>
+ <testcase classname="<exe-name>.global" name="Generators -- adapters/Chunking a generator into sized pieces/Chunk size of zero" time="{duration}"/>
<testcase classname="<exe-name>.global" name="Generators -- adapters/Chunking a generator into sized pieces/Throws on too small generators" time="{duration}"/>
<testcase classname="<exe-name>.global" name="Generators -- simple/one" time="{duration}"/>
<testcase classname="<exe-name>.global" name="Generators -- simple/two" time="{duration}"/>
@@ -385,25 +664,40 @@ Message.tests.cpp:<line number>
<testcase classname="<exe-name>.global" name="Generators internals/Range/Positive manual step/Integer/Exact" time="{duration}"/>
<testcase classname="<exe-name>.global" name="Generators internals/Range/Positive manual step/Integer/Slightly over end" time="{duration}"/>
<testcase classname="<exe-name>.global" name="Generators internals/Range/Positive manual step/Integer/Slightly under end" time="{duration}"/>
+ <testcase classname="<exe-name>.global" name="Generators internals/Range/Positive manual step/Floating Point/Exact" time="{duration}"/>
+ <testcase classname="<exe-name>.global" name="Generators internals/Range/Positive manual step/Floating Point/Slightly over end" time="{duration}"/>
+ <testcase classname="<exe-name>.global" name="Generators internals/Range/Positive manual step/Floating Point/Slightly under end" time="{duration}"/>
<testcase classname="<exe-name>.global" name="Generators internals/Range/Negative manual step/Integer/Exact" time="{duration}"/>
<testcase classname="<exe-name>.global" name="Generators internals/Range/Negative manual step/Integer/Slightly over end" time="{duration}"/>
<testcase classname="<exe-name>.global" name="Generators internals/Range/Negative manual step/Integer/Slightly under end" time="{duration}"/>
<testcase classname="<exe-name>.global" name="Greater-than inequalities with different epsilons" time="{duration}"/>
<testcase classname="<exe-name>.global" name="INFO and WARN do not abort tests" time="{duration}"/>
<testcase classname="<exe-name>.global" name="INFO gets logged on failure" time="{duration}">
- <failure message="2 == 1" type="REQUIRE">
+ <failure message="a == 1" type="REQUIRE">
+FAILED:
+ REQUIRE( a == 1 )
+with expansion:
+ 2 == 1
this message should be logged
so should this
Message.tests.cpp:<line number>
</failure>
</testcase>
<testcase classname="<exe-name>.global" name="INFO gets logged on failure, even if captured before successful assertions" time="{duration}">
- <failure message="2 == 1" type="CHECK">
+ <failure message="a == 1" type="CHECK">
+FAILED:
+ CHECK( a == 1 )
+with expansion:
+ 2 == 1
this message may be logged later
this message should be logged
Message.tests.cpp:<line number>
</failure>
- <failure message="2 == 0" type="CHECK">
+ <failure message="a == 0" type="CHECK">
+FAILED:
+ CHECK( a == 0 )
+with expansion:
+ 2 == 0
this message may be logged later
this message should be logged
and this, but later
@@ -411,26 +705,50 @@ Message.tests.cpp:<line number>
</failure>
</testcase>
<testcase classname="<exe-name>.global" name="INFO is reset for each loop" time="{duration}">
- <failure message="10 &lt; 10" type="REQUIRE">
+ <failure message="i &lt; 10" type="REQUIRE">
+FAILED:
+ REQUIRE( i &lt; 10 )
+with expansion:
+ 10 &lt; 10
current counter 10
i := 10
Message.tests.cpp:<line number>
</failure>
</testcase>
<testcase classname="<exe-name>.global" name="Inequality checks that should fail" time="{duration}">
- <failure message="7 != 7" type="CHECK">
+ <failure message="data.int_seven != 7" type="CHECK">
+FAILED:
+ CHECK( data.int_seven != 7 )
+with expansion:
+ 7 != 7
Condition.tests.cpp:<line number>
</failure>
- <failure message="9.1f != Approx( 9.1000003815 )" type="CHECK">
+ <failure message="data.float_nine_point_one != Approx( 9.1f )" type="CHECK">
+FAILED:
+ CHECK( data.float_nine_point_one != Approx( 9.1f ) )
+with expansion:
+ 9.1f != Approx( 9.1000003815 )
Condition.tests.cpp:<line number>
</failure>
- <failure message="3.1415926535 != Approx( 3.1415926535 )" type="CHECK">
+ <failure message="data.double_pi != Approx( 3.1415926535 )" type="CHECK">
+FAILED:
+ CHECK( data.double_pi != Approx( 3.1415926535 ) )
+with expansion:
+ 3.1415926535 != Approx( 3.1415926535 )
Condition.tests.cpp:<line number>
</failure>
- <failure message="&quot;hello&quot; != &quot;hello&quot;" type="CHECK">
+ <failure message="data.str_hello != &quot;hello&quot;" type="CHECK">
+FAILED:
+ CHECK( data.str_hello != "hello" )
+with expansion:
+ "hello" != "hello"
Condition.tests.cpp:<line number>
</failure>
- <failure message="5 != 5" type="CHECK">
+ <failure message="data.str_hello.size() != 5" type="CHECK">
+FAILED:
+ CHECK( data.str_hello.size() != 5 )
+with expansion:
+ 5 != 5
Condition.tests.cpp:<line number>
</failure>
</testcase>
@@ -441,18 +759,31 @@ Condition.tests.cpp:<line number>
<testcase classname="<exe-name>.global" name="Matchers can be (AnyOf) composed with the || operator" time="{duration}"/>
<testcase classname="<exe-name>.global" name="Matchers can be composed with both &amp;&amp; and ||" time="{duration}"/>
<testcase classname="<exe-name>.global" name="Matchers can be composed with both &amp;&amp; and || - failing" time="{duration}">
- <failure message="&quot;this string contains 'abc' as a substring&quot; ( ( contains: &quot;string&quot; or contains: &quot;different&quot; ) and contains: &quot;random&quot; )" type="CHECK_THAT">
+ <failure message="testStringForMatching(), (Contains(&quot;string&quot;) || Contains(&quot;different&quot;)) &amp;&amp; Contains(&quot;random&quot;)" type="CHECK_THAT">
+FAILED:
+ CHECK_THAT( testStringForMatching(), (Contains("string") || Contains("different")) &amp;&amp; Contains("random") )
+with expansion:
+ "this string contains 'abc' as a substring" ( ( contains: "string" or
+ contains: "different" ) and contains: "random" )
Matchers.tests.cpp:<line number>
</failure>
</testcase>
<testcase classname="<exe-name>.global" name="Matchers can be negated (Not) with the ! operator" time="{duration}"/>
<testcase classname="<exe-name>.global" name="Matchers can be negated (Not) with the ! operator - failing" time="{duration}">
- <failure message="&quot;this string contains 'abc' as a substring&quot; not contains: &quot;substring&quot;" type="CHECK_THAT">
+ <failure message="testStringForMatching(), !Contains(&quot;substring&quot;)" type="CHECK_THAT">
+FAILED:
+ CHECK_THAT( testStringForMatching(), !Contains("substring") )
+with expansion:
+ "this string contains 'abc' as a substring" not contains: "substring"
Matchers.tests.cpp:<line number>
</failure>
</testcase>
<testcase classname="<exe-name>.global" name="Mismatching exception messages failing the test" time="{duration}">
- <failure message="&quot;expected exception&quot; equals: &quot;should fail&quot;" type="REQUIRE_THROWS_WITH">
+ <failure message="thisThrows(), &quot;should fail&quot;" type="REQUIRE_THROWS_WITH">
+FAILED:
+ REQUIRE_THROWS_WITH( thisThrows(), "should fail" )
+with expansion:
+ "expected exception" equals: "should fail"
Exception.tests.cpp:<line number>
</failure>
</testcase>
@@ -460,6 +791,7 @@ Exception.tests.cpp:<line number>
<testcase classname="<exe-name>.global" name="Nice descriptive name" time="{duration}"/>
<testcase classname="<exe-name>.global" name="Non-std exceptions can be translated" time="{duration}">
<error type="TEST_CASE">
+FAILED:
custom exception
Exception.tests.cpp:<line number>
</error>
@@ -467,73 +799,153 @@ Exception.tests.cpp:<line number>
<testcase classname="<exe-name>.global" name="Objects that evaluated in boolean contexts can be checked" time="{duration}"/>
<testcase classname="<exe-name>.global" name="Optionally static assertions" time="{duration}"/>
<testcase classname="<exe-name>.global" name="Ordering comparison checks that should fail" time="{duration}">
- <failure message="7 > 7" type="CHECK">
+ <failure message="data.int_seven > 7" type="CHECK">
+FAILED:
+ CHECK( data.int_seven > 7 )
+with expansion:
+ 7 > 7
Condition.tests.cpp:<line number>
</failure>
- <failure message="7 &lt; 7" type="CHECK">
+ <failure message="data.int_seven &lt; 7" type="CHECK">
+FAILED:
+ CHECK( data.int_seven &lt; 7 )
+with expansion:
+ 7 &lt; 7
Condition.tests.cpp:<line number>
</failure>
- <failure message="7 > 8" type="CHECK">
+ <failure message="data.int_seven > 8" type="CHECK">
+FAILED:
+ CHECK( data.int_seven > 8 )
+with expansion:
+ 7 > 8
Condition.tests.cpp:<line number>
</failure>
- <failure message="7 &lt; 6" type="CHECK">
+ <failure message="data.int_seven &lt; 6" type="CHECK">
+FAILED:
+ CHECK( data.int_seven &lt; 6 )
+with expansion:
+ 7 &lt; 6
Condition.tests.cpp:<line number>
</failure>
- <failure message="7 &lt; 0" type="CHECK">
+ <failure message="data.int_seven &lt; 0" type="CHECK">
+FAILED:
+ CHECK( data.int_seven &lt; 0 )
+with expansion:
+ 7 &lt; 0
Condition.tests.cpp:<line number>
</failure>
- <failure message="7 &lt; -1" type="CHECK">
+ <failure message="data.int_seven &lt; -1" type="CHECK">
+FAILED:
+ CHECK( data.int_seven &lt; -1 )
+with expansion:
+ 7 &lt; -1
Condition.tests.cpp:<line number>
</failure>
- <failure message="7 >= 8" type="CHECK">
+ <failure message="data.int_seven >= 8" type="CHECK">
+FAILED:
+ CHECK( data.int_seven >= 8 )
+with expansion:
+ 7 >= 8
Condition.tests.cpp:<line number>
</failure>
- <failure message="7 &lt;= 6" type="CHECK">
+ <failure message="data.int_seven &lt;= 6" type="CHECK">
+FAILED:
+ CHECK( data.int_seven &lt;= 6 )
+with expansion:
+ 7 &lt;= 6
Condition.tests.cpp:<line number>
</failure>
- <failure message="9.1f &lt; 9" type="CHECK">
+ <failure message="data.float_nine_point_one &lt; 9" type="CHECK">
+FAILED:
+ CHECK( data.float_nine_point_one &lt; 9 )
+with expansion:
+ 9.1f &lt; 9
Condition.tests.cpp:<line number>
</failure>
- <failure message="9.1f > 10" type="CHECK">
+ <failure message="data.float_nine_point_one > 10" type="CHECK">
+FAILED:
+ CHECK( data.float_nine_point_one > 10 )
+with expansion:
+ 9.1f > 10
Condition.tests.cpp:<line number>
</failure>
- <failure message="9.1f > 9.2" type="CHECK">
+ <failure message="data.float_nine_point_one > 9.2" type="CHECK">
+FAILED:
+ CHECK( data.float_nine_point_one > 9.2 )
+with expansion:
+ 9.1f > 9.2
Condition.tests.cpp:<line number>
</failure>
- <failure message="&quot;hello&quot; > &quot;hello&quot;" type="CHECK">
+ <failure message="data.str_hello > &quot;hello&quot;" type="CHECK">
+FAILED:
+ CHECK( data.str_hello > "hello" )
+with expansion:
+ "hello" > "hello"
Condition.tests.cpp:<line number>
</failure>
- <failure message="&quot;hello&quot; &lt; &quot;hello&quot;" type="CHECK">
+ <failure message="data.str_hello &lt; &quot;hello&quot;" type="CHECK">
+FAILED:
+ CHECK( data.str_hello &lt; "hello" )
+with expansion:
+ "hello" &lt; "hello"
Condition.tests.cpp:<line number>
</failure>
- <failure message="&quot;hello&quot; > &quot;hellp&quot;" type="CHECK">
+ <failure message="data.str_hello > &quot;hellp&quot;" type="CHECK">
+FAILED:
+ CHECK( data.str_hello > "hellp" )
+with expansion:
+ "hello" > "hellp"
Condition.tests.cpp:<line number>
</failure>
- <failure message="&quot;hello&quot; > &quot;z&quot;" type="CHECK">
+ <failure message="data.str_hello > &quot;z&quot;" type="CHECK">
+FAILED:
+ CHECK( data.str_hello > "z" )
+with expansion:
+ "hello" > "z"
Condition.tests.cpp:<line number>
</failure>
- <failure message="&quot;hello&quot; &lt; &quot;hellm&quot;" type="CHECK">
+ <failure message="data.str_hello &lt; &quot;hellm&quot;" type="CHECK">
+FAILED:
+ CHECK( data.str_hello &lt; "hellm" )
+with expansion:
+ "hello" &lt; "hellm"
Condition.tests.cpp:<line number>
</failure>
- <failure message="&quot;hello&quot; &lt; &quot;a&quot;" type="CHECK">
+ <failure message="data.str_hello &lt; &quot;a&quot;" type="CHECK">
+FAILED:
+ CHECK( data.str_hello &lt; "a" )
+with expansion:
+ "hello" &lt; "a"
Condition.tests.cpp:<line number>
</failure>
- <failure message="&quot;hello&quot; >= &quot;z&quot;" type="CHECK">
+ <failure message="data.str_hello >= &quot;z&quot;" type="CHECK">
+FAILED:
+ CHECK( data.str_hello >= "z" )
+with expansion:
+ "hello" >= "z"
Condition.tests.cpp:<line number>
</failure>
- <failure message="&quot;hello&quot; &lt;= &quot;a&quot;" type="CHECK">
+ <failure message="data.str_hello &lt;= &quot;a&quot;" type="CHECK">
+FAILED:
+ CHECK( data.str_hello &lt;= "a" )
+with expansion:
+ "hello" &lt;= "a"
Condition.tests.cpp:<line number>
</failure>
</testcase>
<testcase classname="<exe-name>.global" name="Ordering comparison checks that should succeed" time="{duration}"/>
+ <testcase classname="<exe-name>.global" name="Our PCG implementation provides expected results for known seeds/Default seeded" time="{duration}"/>
+ <testcase classname="<exe-name>.global" name="Our PCG implementation provides expected results for known seeds/Specific seed" time="{duration}"/>
<testcase classname="<exe-name>.global" name="Output from all sections is reported/one" time="{duration}">
<failure type="FAIL">
+FAILED:
Message from section one
Message.tests.cpp:<line number>
</failure>
</testcase>
<testcase classname="<exe-name>.global" name="Output from all sections is reported/two" time="{duration}">
<failure type="FAIL">
+FAILED:
Message from section two
Message.tests.cpp:<line number>
</failure>
@@ -569,7 +981,13 @@ Message.tests.cpp:<line number>
<testcase classname="<exe-name>.global" name="Parse test names and tags/empty tag" time="{duration}"/>
<testcase classname="<exe-name>.global" name="Parse test names and tags/empty quoted name" time="{duration}"/>
<testcase classname="<exe-name>.global" name="Parse test names and tags/quoted string followed by tag exclusion" time="{duration}"/>
+ <testcase classname="<exe-name>.global" name="Parse test names and tags/Leading and trailing spaces in test spec" time="{duration}"/>
+ <testcase classname="<exe-name>.global" name="Parse test names and tags/Leading and trailing spaces in test name" time="{duration}"/>
+ <testcase classname="<exe-name>.global" name="Parse test names and tags/Shortened hide tags are split apart when parsing" time="{duration}"/>
+ <testcase classname="<exe-name>.global" name="Parse test names and tags/Shortened hide tags also properly handle exclusion" time="{duration}"/>
<testcase classname="<exe-name>.global" name="Pointers can be compared to null" time="{duration}"/>
+ <testcase classname="<exe-name>.global" name="Precision of floating point stringification can be set/Floats" time="{duration}"/>
+ <testcase classname="<exe-name>.global" name="Precision of floating point stringification can be set/Double" time="{duration}"/>
<testcase classname="<exe-name>.global" name="Predicate matcher can accept const char*" time="{duration}"/>
<testcase classname="<exe-name>.global" name="Process can be configured on command line/empty args don't cause a crash" time="{duration}"/>
<testcase classname="<exe-name>.global" name="Process can be configured on command line/default - no arguments" time="{duration}"/>
@@ -586,6 +1004,8 @@ Message.tests.cpp:<line number>
<testcase classname="<exe-name>.global" name="Process can be configured on command line/abort/-a aborts after first failure" time="{duration}"/>
<testcase classname="<exe-name>.global" name="Process can be configured on command line/abort/-x 2 aborts after two failures" time="{duration}"/>
<testcase classname="<exe-name>.global" name="Process can be configured on command line/abort/-x must be numeric" time="{duration}"/>
+ <testcase classname="<exe-name>.global" name="Process can be configured on command line/abort/wait-for-keypress/Accepted options" time="{duration}"/>
+ <testcase classname="<exe-name>.global" name="Process can be configured on command line/abort/wait-for-keypress/invalid options are reported" time="{duration}"/>
<testcase classname="<exe-name>.global" name="Process can be configured on command line/nothrow/-e" time="{duration}"/>
<testcase classname="<exe-name>.global" name="Process can be configured on command line/nothrow/--nothrow" time="{duration}"/>
<testcase classname="<exe-name>.global" name="Process can be configured on command line/output filename/-o filename" time="{duration}"/>
@@ -596,22 +1016,46 @@ Message.tests.cpp:<line number>
<testcase classname="<exe-name>.global" name="Process can be configured on command line/use-colour/yes" time="{duration}"/>
<testcase classname="<exe-name>.global" name="Process can be configured on command line/use-colour/no" time="{duration}"/>
<testcase classname="<exe-name>.global" name="Process can be configured on command line/use-colour/error" time="{duration}"/>
+ <testcase classname="<exe-name>.global" name="Process can be configured on command line/Benchmark options/samples" time="{duration}"/>
+ <testcase classname="<exe-name>.global" name="Process can be configured on command line/Benchmark options/resamples" time="{duration}"/>
+ <testcase classname="<exe-name>.global" name="Process can be configured on command line/Benchmark options/confidence-interval" time="{duration}"/>
+ <testcase classname="<exe-name>.global" name="Process can be configured on command line/Benchmark options/no-analysis" time="{duration}"/>
+ <testcase classname="<exe-name>.global" name="Process can be configured on command line/Benchmark options/warmup-time" time="{duration}"/>
<testcase classname="<exe-name>.global" name="Product with differing arities - std::tuple&lt;int, double, float>" time="{duration}"/>
<testcase classname="<exe-name>.global" name="Product with differing arities - std::tuple&lt;int, double>" time="{duration}"/>
<testcase classname="<exe-name>.global" name="Product with differing arities - std::tuple&lt;int>" time="{duration}"/>
<testcase classname="<exe-name>.global" name="Reconstruction should be based on stringification: #914" time="{duration}">
- <failure message="Hey, its truthy!" type="CHECK">
+ <failure message="truthy(false)" type="CHECK">
+FAILED:
+ CHECK( truthy(false) )
+with expansion:
+ Hey, its truthy!
Decomposition.tests.cpp:<line number>
</failure>
</testcase>
<testcase classname="<exe-name>.global" name="Regex string matcher" time="{duration}">
- <failure message="&quot;this string contains 'abc' as a substring&quot; matches &quot;this STRING contains 'abc' as a substring&quot; case sensitively" type="CHECK_THAT">
+ <failure message="testStringForMatching(), Matches(&quot;this STRING contains 'abc' as a substring&quot;)" type="CHECK_THAT">
+FAILED:
+ CHECK_THAT( testStringForMatching(), Matches("this STRING contains 'abc' as a substring") )
+with expansion:
+ "this string contains 'abc' as a substring" matches "this STRING contains
+ 'abc' as a substring" case sensitively
Matchers.tests.cpp:<line number>
</failure>
- <failure message="&quot;this string contains 'abc' as a substring&quot; matches &quot;contains 'abc' as a substring&quot; case sensitively" type="CHECK_THAT">
+ <failure message="testStringForMatching(), Matches(&quot;contains 'abc' as a substring&quot;)" type="CHECK_THAT">
+FAILED:
+ CHECK_THAT( testStringForMatching(), Matches("contains 'abc' as a substring") )
+with expansion:
+ "this string contains 'abc' as a substring" matches "contains 'abc' as a
+ substring" case sensitively
Matchers.tests.cpp:<line number>
</failure>
- <failure message="&quot;this string contains 'abc' as a substring&quot; matches &quot;this string contains 'abc' as a&quot; case sensitively" type="CHECK_THAT">
+ <failure message="testStringForMatching(), Matches(&quot;this string contains 'abc' as a&quot;)" type="CHECK_THAT">
+FAILED:
+ CHECK_THAT( testStringForMatching(), Matches("this string contains 'abc' as a") )
+with expansion:
+ "this string contains 'abc' as a substring" matches "this string contains
+ 'abc' as a" case sensitively
Matchers.tests.cpp:<line number>
</failure>
</testcase>
@@ -644,10 +1088,19 @@ Message from section two
</system-out>
</testcase>
<testcase classname="<exe-name>.global" name="StartsWith string matcher" time="{duration}">
- <failure message="&quot;this string contains 'abc' as a substring&quot; starts with: &quot;This String&quot;" type="CHECK_THAT">
+ <failure message="testStringForMatching(), StartsWith(&quot;This String&quot;)" type="CHECK_THAT">
+FAILED:
+ CHECK_THAT( testStringForMatching(), StartsWith("This String") )
+with expansion:
+ "this string contains 'abc' as a substring" starts with: "This String"
Matchers.tests.cpp:<line number>
</failure>
- <failure message="&quot;this string contains 'abc' as a substring&quot; starts with: &quot;string&quot; (case insensitive)" type="CHECK_THAT">
+ <failure message="testStringForMatching(), StartsWith(&quot;string&quot;, Catch::CaseSensitive::No)" type="CHECK_THAT">
+FAILED:
+ CHECK_THAT( testStringForMatching(), StartsWith("string", Catch::CaseSensitive::No) )
+with expansion:
+ "this string contains 'abc' as a substring" starts with: "string" (case
+ insensitive)
Matchers.tests.cpp:<line number>
</failure>
</testcase>
@@ -657,38 +1110,52 @@ Matchers.tests.cpp:<line number>
<testcase classname="<exe-name>.global" name="String matchers" time="{duration}"/>
<testcase classname="<exe-name>.global" name="StringRef/Empty string" time="{duration}"/>
<testcase classname="<exe-name>.global" name="StringRef/From string literal" time="{duration}"/>
- <testcase classname="<exe-name>.global" name="StringRef/From string literal/c_str() does not cause copy" time="{duration}"/>
<testcase classname="<exe-name>.global" name="StringRef/From sub-string" time="{duration}"/>
<testcase classname="<exe-name>.global" name="StringRef/Substrings/zero-based substring" time="{duration}"/>
- <testcase classname="<exe-name>.global" name="StringRef/Substrings/c_str() causes copy" time="{duration}"/>
<testcase classname="<exe-name>.global" name="StringRef/Substrings/non-zero-based substring" time="{duration}"/>
<testcase classname="<exe-name>.global" name="StringRef/Substrings/Pointer values of full refs should match" time="{duration}"/>
- <testcase classname="<exe-name>.global" name="StringRef/Substrings/Pointer values of substring refs should not match" time="{duration}"/>
- <testcase classname="<exe-name>.global" name="StringRef/Comparisons" time="{duration}"/>
+ <testcase classname="<exe-name>.global" name="StringRef/Substrings/Pointer values of substring refs should also match" time="{duration}"/>
+ <testcase classname="<exe-name>.global" name="StringRef/Substrings/Past the end substring" time="{duration}"/>
+ <testcase classname="<exe-name>.global" name="StringRef/Substrings/Substring off the end are trimmed" time="{duration}"/>
+ <testcase classname="<exe-name>.global" name="StringRef/Comparisons are deep" time="{duration}"/>
<testcase classname="<exe-name>.global" name="StringRef/from std::string/implicitly constructed" time="{duration}"/>
<testcase classname="<exe-name>.global" name="StringRef/from std::string/explicitly constructed" time="{duration}"/>
<testcase classname="<exe-name>.global" name="StringRef/from std::string/assigned" time="{duration}"/>
- <testcase classname="<exe-name>.global" name="StringRef/to std::string/implicitly constructed" time="{duration}"/>
<testcase classname="<exe-name>.global" name="StringRef/to std::string/explicitly constructed" time="{duration}"/>
<testcase classname="<exe-name>.global" name="StringRef/to std::string/assigned" time="{duration}"/>
- <testcase classname="<exe-name>.global" name="StringRef/Counting utf-8 codepoints" time="{duration}"/>
+ <testcase classname="<exe-name>.global" name="StringRef at compilation time/Simple constructors" time="{duration}"/>
+ <testcase classname="<exe-name>.global" name="StringRef at compilation time/UDL construction" time="{duration}"/>
<testcase classname="<exe-name>.global" name="Stringifying std::chrono::duration helpers" time="{duration}"/>
<testcase classname="<exe-name>.global" name="Stringifying std::chrono::duration with weird ratios" time="{duration}"/>
<testcase classname="<exe-name>.global" name="Stringifying std::chrono::time_point&lt;system_clock>" time="{duration}"/>
<testcase classname="<exe-name>.global" name="Tabs and newlines show in output" time="{duration}">
- <failure message="&quot;if ($b == 10) {
- $a = 20;
-}&quot;
-==
-&quot;if ($b == 10) {
- $a = 20;
-}
-&quot;" type="CHECK">
+ <failure message="s1 == s2" type="CHECK">
+FAILED:
+ CHECK( s1 == s2 )
+with expansion:
+ "if ($b == 10) {
+ $a = 20;
+ }"
+ ==
+ "if ($b == 10) {
+ $a = 20;
+ }
+ "
Misc.tests.cpp:<line number>
</failure>
</testcase>
<testcase classname="<exe-name>.global" name="Tag alias can be registered against tag patterns/The same tag alias can only be registered once" time="{duration}"/>
<testcase classname="<exe-name>.global" name="Tag alias can be registered against tag patterns/Tag aliases must be of the form [@name]" time="{duration}"/>
+ <testcase classname="<exe-name>.Template_Fixture" name="Template test case method with test types specified inside std::tuple - MyTypes - 0" time="{duration}"/>
+ <testcase classname="<exe-name>.Template_Fixture" name="Template test case method with test types specified inside std::tuple - MyTypes - 1" time="{duration}"/>
+ <testcase classname="<exe-name>.Template_Fixture" name="Template test case method with test types specified inside std::tuple - MyTypes - 2" time="{duration}"/>
+ <testcase classname="<exe-name>.global" name="Template test case with test types specified inside non-copyable and non-movable std::tuple - NonCopyableAndNonMovableTypes - 0" time="{duration}"/>
+ <testcase classname="<exe-name>.global" name="Template test case with test types specified inside non-copyable and non-movable std::tuple - NonCopyableAndNonMovableTypes - 1" time="{duration}"/>
+ <testcase classname="<exe-name>.global" name="Template test case with test types specified inside non-default-constructible std::tuple - MyNonDefaultConstructibleTypes - 0" time="{duration}"/>
+ <testcase classname="<exe-name>.global" name="Template test case with test types specified inside non-default-constructible std::tuple - MyNonDefaultConstructibleTypes - 1" time="{duration}"/>
+ <testcase classname="<exe-name>.global" name="Template test case with test types specified inside std::tuple - MyTypes - 0" time="{duration}"/>
+ <testcase classname="<exe-name>.global" name="Template test case with test types specified inside std::tuple - MyTypes - 1" time="{duration}"/>
+ <testcase classname="<exe-name>.global" name="Template test case with test types specified inside std::tuple - MyTypes - 2" time="{duration}"/>
<testcase classname="<exe-name>.global" name="TemplateTest: vectors can be sized and resized - float" time="{duration}"/>
<testcase classname="<exe-name>.global" name="TemplateTest: vectors can be sized and resized - float/resizing bigger changes size and capacity" time="{duration}"/>
<testcase classname="<exe-name>.global" name="TemplateTest: vectors can be sized and resized - float/resizing smaller changes size but not capacity" time="{duration}"/>
@@ -713,12 +1180,38 @@ Misc.tests.cpp:<line number>
<testcase classname="<exe-name>.global" name="TemplateTest: vectors can be sized and resized - std::tuple&lt;int,float>/resizing smaller changes size but not capacity/We can use the 'swap trick' to reset the capacity" time="{duration}"/>
<testcase classname="<exe-name>.global" name="TemplateTest: vectors can be sized and resized - std::tuple&lt;int,float>/reserving bigger changes capacity but not size" time="{duration}"/>
<testcase classname="<exe-name>.global" name="TemplateTest: vectors can be sized and resized - std::tuple&lt;int,float>/reserving smaller does not change size or capacity" time="{duration}"/>
+ <testcase classname="<exe-name>.global" name="TemplateTestSig: vectors can be sized and resized - (std::tuple&lt;int, float>), 6" time="{duration}"/>
+ <testcase classname="<exe-name>.global" name="TemplateTestSig: vectors can be sized and resized - (std::tuple&lt;int, float>), 6/resizing bigger changes size and capacity" time="{duration}"/>
+ <testcase classname="<exe-name>.global" name="TemplateTestSig: vectors can be sized and resized - (std::tuple&lt;int, float>), 6/resizing smaller changes size but not capacity" time="{duration}"/>
+ <testcase classname="<exe-name>.global" name="TemplateTestSig: vectors can be sized and resized - (std::tuple&lt;int, float>), 6/resizing smaller changes size but not capacity/We can use the 'swap trick' to reset the capacity" time="{duration}"/>
+ <testcase classname="<exe-name>.global" name="TemplateTestSig: vectors can be sized and resized - (std::tuple&lt;int, float>), 6/reserving bigger changes capacity but not size" time="{duration}"/>
+ <testcase classname="<exe-name>.global" name="TemplateTestSig: vectors can be sized and resized - (std::tuple&lt;int, float>), 6/reserving smaller does not change size or capacity" time="{duration}"/>
+ <testcase classname="<exe-name>.global" name="TemplateTestSig: vectors can be sized and resized - float,4" time="{duration}"/>
+ <testcase classname="<exe-name>.global" name="TemplateTestSig: vectors can be sized and resized - float,4/resizing bigger changes size and capacity" time="{duration}"/>
+ <testcase classname="<exe-name>.global" name="TemplateTestSig: vectors can be sized and resized - float,4/resizing smaller changes size but not capacity" time="{duration}"/>
+ <testcase classname="<exe-name>.global" name="TemplateTestSig: vectors can be sized and resized - float,4/resizing smaller changes size but not capacity/We can use the 'swap trick' to reset the capacity" time="{duration}"/>
+ <testcase classname="<exe-name>.global" name="TemplateTestSig: vectors can be sized and resized - float,4/reserving bigger changes capacity but not size" time="{duration}"/>
+ <testcase classname="<exe-name>.global" name="TemplateTestSig: vectors can be sized and resized - float,4/reserving smaller does not change size or capacity" time="{duration}"/>
+ <testcase classname="<exe-name>.global" name="TemplateTestSig: vectors can be sized and resized - int,5" time="{duration}"/>
+ <testcase classname="<exe-name>.global" name="TemplateTestSig: vectors can be sized and resized - int,5/resizing bigger changes size and capacity" time="{duration}"/>
+ <testcase classname="<exe-name>.global" name="TemplateTestSig: vectors can be sized and resized - int,5/resizing smaller changes size but not capacity" time="{duration}"/>
+ <testcase classname="<exe-name>.global" name="TemplateTestSig: vectors can be sized and resized - int,5/resizing smaller changes size but not capacity/We can use the 'swap trick' to reset the capacity" time="{duration}"/>
+ <testcase classname="<exe-name>.global" name="TemplateTestSig: vectors can be sized and resized - int,5/reserving bigger changes capacity but not size" time="{duration}"/>
+ <testcase classname="<exe-name>.global" name="TemplateTestSig: vectors can be sized and resized - int,5/reserving smaller does not change size or capacity" time="{duration}"/>
+ <testcase classname="<exe-name>.global" name="TemplateTestSig: vectors can be sized and resized - std::string,15" time="{duration}"/>
+ <testcase classname="<exe-name>.global" name="TemplateTestSig: vectors can be sized and resized - std::string,15/resizing bigger changes size and capacity" time="{duration}"/>
+ <testcase classname="<exe-name>.global" name="TemplateTestSig: vectors can be sized and resized - std::string,15/resizing smaller changes size but not capacity" time="{duration}"/>
+ <testcase classname="<exe-name>.global" name="TemplateTestSig: vectors can be sized and resized - std::string,15/resizing smaller changes size but not capacity/We can use the 'swap trick' to reset the capacity" time="{duration}"/>
+ <testcase classname="<exe-name>.global" name="TemplateTestSig: vectors can be sized and resized - std::string,15/reserving bigger changes capacity but not size" time="{duration}"/>
+ <testcase classname="<exe-name>.global" name="TemplateTestSig: vectors can be sized and resized - std::string,15/reserving smaller does not change size or capacity" time="{duration}"/>
<testcase classname="<exe-name>.global" name="Test case with one argument" time="{duration}"/>
<testcase classname="<exe-name>.global" name="Test enum bit values" time="{duration}"/>
+ <testcase classname="<exe-name>.global" name="Test with special, characters &quot;in name" time="{duration}"/>
<testcase classname="<exe-name>.global" name="The NO_FAIL macro reports a failure but does not fail the test" time="{duration}"/>
<testcase classname="<exe-name>.global" name="This test 'should' fail but doesn't" time="{duration}"/>
<testcase classname="<exe-name>.global" name="Thrown string literals are translated" time="{duration}">
<error type="TEST_CASE">
+FAILED:
For some reason someone is throwing a string literal!
Exception.tests.cpp:<line number>
</error>
@@ -733,8 +1226,10 @@ Exception.tests.cpp:<line number>
<testcase classname="<exe-name>.global" name="Tracker/successfully close one section, then find another/Re-enter - skips S1 and enters S2/Successfully close S2" time="{duration}"/>
<testcase classname="<exe-name>.global" name="Tracker/successfully close one section, then find another/Re-enter - skips S1 and enters S2/fail S2" time="{duration}"/>
<testcase classname="<exe-name>.global" name="Tracker/open a nested section" time="{duration}"/>
+ <testcase classname="<exe-name>.global" name="Trim strings" time="{duration}"/>
<testcase classname="<exe-name>.global" name="Unexpected exceptions can be translated" time="{duration}">
<error type="TEST_CASE">
+FAILED:
3.14
Exception.tests.cpp:<line number>
</error>
@@ -746,12 +1241,20 @@ Exception.tests.cpp:<line number>
<testcase classname="<exe-name>.global" name="Vector Approx matcher/Vectors with elements/Different length" time="{duration}"/>
<testcase classname="<exe-name>.global" name="Vector Approx matcher/Vectors with elements/Same length, different elements" time="{duration}"/>
<testcase classname="<exe-name>.global" name="Vector Approx matcher -- failing/Empty and non empty vectors are not approx equal" time="{duration}">
- <failure message="{ } is approx: { 1.0, 2.0 }" type="CHECK_THAT">
+ <failure message="empty, Approx(t1)" type="CHECK_THAT">
+FAILED:
+ CHECK_THAT( empty, Approx(t1) )
+with expansion:
+ { } is approx: { 1.0, 2.0 }
Matchers.tests.cpp:<line number>
</failure>
</testcase>
<testcase classname="<exe-name>.global" name="Vector Approx matcher -- failing/Just different vectors" time="{duration}">
- <failure message="{ 2.0, 4.0, 6.0 } is approx: { 1.0, 3.0, 5.0 }" type="CHECK_THAT">
+ <failure message="v1, Approx(v2)" type="CHECK_THAT">
+FAILED:
+ CHECK_THAT( v1, Approx(v2) )
+with expansion:
+ { 2.0, 4.0, 6.0 } is approx: { 1.0, 3.0, 5.0 }
Matchers.tests.cpp:<line number>
</failure>
</testcase>
@@ -761,76 +1264,132 @@ Matchers.tests.cpp:<line number>
<testcase classname="<exe-name>.global" name="Vector matchers/Equals" time="{duration}"/>
<testcase classname="<exe-name>.global" name="Vector matchers/UnorderedEquals" time="{duration}"/>
<testcase classname="<exe-name>.global" name="Vector matchers that fail/Contains (element)" time="{duration}">
- <failure message="{ 1, 2, 3 } Contains: -1" type="CHECK_THAT">
+ <failure message="v, VectorContains(-1)" type="CHECK_THAT">
+FAILED:
+ CHECK_THAT( v, VectorContains(-1) )
+with expansion:
+ { 1, 2, 3 } Contains: -1
Matchers.tests.cpp:<line number>
</failure>
- <failure message="{ } Contains: 1" type="CHECK_THAT">
+ <failure message="empty, VectorContains(1)" type="CHECK_THAT">
+FAILED:
+ CHECK_THAT( empty, VectorContains(1) )
+with expansion:
+ { } Contains: 1
Matchers.tests.cpp:<line number>
</failure>
</testcase>
<testcase classname="<exe-name>.global" name="Vector matchers that fail/Contains (vector)" time="{duration}">
- <failure message="{ } Contains: { 1, 2, 3 }" type="CHECK_THAT">
+ <failure message="empty, Contains(v)" type="CHECK_THAT">
+FAILED:
+ CHECK_THAT( empty, Contains(v) )
+with expansion:
+ { } Contains: { 1, 2, 3 }
Matchers.tests.cpp:<line number>
</failure>
- <failure message="{ 1, 2, 3 } Contains: { 1, 2, 4 }" type="CHECK_THAT">
+ <failure message="v, Contains(v2)" type="CHECK_THAT">
+FAILED:
+ CHECK_THAT( v, Contains(v2) )
+with expansion:
+ { 1, 2, 3 } Contains: { 1, 2, 4 }
Matchers.tests.cpp:<line number>
</failure>
</testcase>
<testcase classname="<exe-name>.global" name="Vector matchers that fail/Equals" time="{duration}">
- <failure message="{ 1, 2, 3 } Equals: { 1, 2 }" type="CHECK_THAT">
+ <failure message="v, Equals(v2)" type="CHECK_THAT">
+FAILED:
+ CHECK_THAT( v, Equals(v2) )
+with expansion:
+ { 1, 2, 3 } Equals: { 1, 2 }
Matchers.tests.cpp:<line number>
</failure>
- <failure message="{ 1, 2 } Equals: { 1, 2, 3 }" type="CHECK_THAT">
+ <failure message="v2, Equals(v)" type="CHECK_THAT">
+FAILED:
+ CHECK_THAT( v2, Equals(v) )
+with expansion:
+ { 1, 2 } Equals: { 1, 2, 3 }
Matchers.tests.cpp:<line number>
</failure>
- <failure message="{ } Equals: { 1, 2, 3 }" type="CHECK_THAT">
+ <failure message="empty, Equals(v)" type="CHECK_THAT">
+FAILED:
+ CHECK_THAT( empty, Equals(v) )
+with expansion:
+ { } Equals: { 1, 2, 3 }
Matchers.tests.cpp:<line number>
</failure>
- <failure message="{ 1, 2, 3 } Equals: { }" type="CHECK_THAT">
+ <failure message="v, Equals(empty)" type="CHECK_THAT">
+FAILED:
+ CHECK_THAT( v, Equals(empty) )
+with expansion:
+ { 1, 2, 3 } Equals: { }
Matchers.tests.cpp:<line number>
</failure>
</testcase>
<testcase classname="<exe-name>.global" name="Vector matchers that fail/UnorderedEquals" time="{duration}">
- <failure message="{ 1, 2, 3 } UnorderedEquals: { }" type="CHECK_THAT">
+ <failure message="v, UnorderedEquals(empty)" type="CHECK_THAT">
+FAILED:
+ CHECK_THAT( v, UnorderedEquals(empty) )
+with expansion:
+ { 1, 2, 3 } UnorderedEquals: { }
Matchers.tests.cpp:<line number>
</failure>
- <failure message="{ } UnorderedEquals: { 1, 2, 3 }" type="CHECK_THAT">
+ <failure message="empty, UnorderedEquals(v)" type="CHECK_THAT">
+FAILED:
+ CHECK_THAT( empty, UnorderedEquals(v) )
+with expansion:
+ { } UnorderedEquals: { 1, 2, 3 }
Matchers.tests.cpp:<line number>
</failure>
- <failure message="{ 1, 3 } UnorderedEquals: { 1, 2, 3 }" type="CHECK_THAT">
+ <failure message="permuted, UnorderedEquals(v)" type="CHECK_THAT">
+FAILED:
+ CHECK_THAT( permuted, UnorderedEquals(v) )
+with expansion:
+ { 1, 3 } UnorderedEquals: { 1, 2, 3 }
Matchers.tests.cpp:<line number>
</failure>
- <failure message="{ 3, 1 } UnorderedEquals: { 1, 2, 3 }" type="CHECK_THAT">
+ <failure message="permuted, UnorderedEquals(v)" type="CHECK_THAT">
+FAILED:
+ CHECK_THAT( permuted, UnorderedEquals(v) )
+with expansion:
+ { 3, 1 } UnorderedEquals: { 1, 2, 3 }
Matchers.tests.cpp:<line number>
</failure>
</testcase>
<testcase classname="<exe-name>.global" name="When checked exceptions are thrown they can be expected or unexpected" time="{duration}"/>
<testcase classname="<exe-name>.global" name="When unchecked exceptions are thrown directly they are always failures" time="{duration}">
<error type="TEST_CASE">
+FAILED:
unexpected exception
Exception.tests.cpp:<line number>
</error>
</testcase>
<testcase classname="<exe-name>.global" name="When unchecked exceptions are thrown during a CHECK the test should continue" time="{duration}">
<error message="thisThrows() == 0" type="CHECK">
+FAILED:
+ CHECK( thisThrows() == 0 )
expected exception
Exception.tests.cpp:<line number>
</error>
</testcase>
<testcase classname="<exe-name>.global" name="When unchecked exceptions are thrown during a REQUIRE the test should abort fail" time="{duration}">
<error message="thisThrows() == 0" type="REQUIRE">
+FAILED:
+ REQUIRE( thisThrows() == 0 )
expected exception
Exception.tests.cpp:<line number>
</error>
</testcase>
<testcase classname="<exe-name>.global" name="When unchecked exceptions are thrown from functions they are always failures" time="{duration}">
<error message="thisThrows() == 0" type="CHECK">
+FAILED:
+ CHECK( thisThrows() == 0 )
expected exception
Exception.tests.cpp:<line number>
</error>
</testcase>
<testcase classname="<exe-name>.global" name="When unchecked exceptions are thrown from sections they are always failures/section name" time="{duration}">
<error type="TEST_CASE">
+FAILED:
unexpected exception
Exception.tests.cpp:<line number>
</error>
@@ -849,30 +1408,41 @@ Exception.tests.cpp:<line number>
<testcase classname="<exe-name>.global" name="XmlEncode/string with quotes" time="{duration}"/>
<testcase classname="<exe-name>.global" name="XmlEncode/string with control char (1)" time="{duration}"/>
<testcase classname="<exe-name>.global" name="XmlEncode/string with control char (x7F)" time="{duration}"/>
- <testcase classname="<exe-name>.global" name="XmlEncode: UTF-8/Valid utf-8 strings" time="{duration}"/>
- <testcase classname="<exe-name>.global" name="XmlEncode: UTF-8/Invalid utf-8 strings/Various broken strings" time="{duration}"/>
- <testcase classname="<exe-name>.global" name="XmlEncode: UTF-8/Invalid utf-8 strings/Overlong encodings" time="{duration}"/>
- <testcase classname="<exe-name>.global" name="XmlEncode: UTF-8/Invalid utf-8 strings/Surrogate pairs" time="{duration}"/>
- <testcase classname="<exe-name>.global" name="XmlEncode: UTF-8/Invalid utf-8 strings/Invalid start byte" time="{duration}"/>
- <testcase classname="<exe-name>.global" name="XmlEncode: UTF-8/Invalid utf-8 strings/Missing continuation byte(s)" time="{duration}"/>
+ <testcase classname="<exe-name>.global" name="adding a hide tag implicitly enables all others" time="{duration}"/>
<testcase classname="<exe-name>.global" name="array&lt;int, N> -> toString" time="{duration}"/>
<testcase classname="<exe-name>.global" name="atomic if" time="{duration}"/>
<testcase classname="<exe-name>.global" name="boolean member" time="{duration}"/>
<testcase classname="<exe-name>.global" name="checkedElse" time="{duration}"/>
<testcase classname="<exe-name>.global" name="checkedElse, failing" time="{duration}">
- <failure message="false" type="CHECKED_ELSE">
+ <failure message="flag" type="CHECKED_ELSE">
+FAILED:
+ CHECKED_ELSE( flag )
+with expansion:
+ false
Misc.tests.cpp:<line number>
</failure>
- <failure message="false" type="REQUIRE">
+ <failure message="testCheckedElse( false )" type="REQUIRE">
+FAILED:
+ REQUIRE( testCheckedElse( false ) )
+with expansion:
+ false
Misc.tests.cpp:<line number>
</failure>
</testcase>
<testcase classname="<exe-name>.global" name="checkedIf" time="{duration}"/>
<testcase classname="<exe-name>.global" name="checkedIf, failing" time="{duration}">
- <failure message="false" type="CHECKED_IF">
+ <failure message="flag" type="CHECKED_IF">
+FAILED:
+ CHECKED_IF( flag )
+with expansion:
+ false
Misc.tests.cpp:<line number>
</failure>
- <failure message="false" type="REQUIRE">
+ <failure message="testCheckedIf( false )" type="REQUIRE">
+FAILED:
+ REQUIRE( testCheckedIf( false ) )
+with expansion:
+ false
Misc.tests.cpp:<line number>
</failure>
</testcase>
@@ -883,24 +1453,34 @@ Misc.tests.cpp:<line number>
<testcase classname="<exe-name>.global" name="even more nested SECTION tests/f (leaf)" time="{duration}"/>
<testcase classname="<exe-name>.global" name="just failure" time="{duration}">
<failure type="FAIL">
+FAILED:
Previous info should not be seen
Message.tests.cpp:<line number>
</failure>
</testcase>
<testcase classname="<exe-name>.global" name="just failure after unscoped info" time="{duration}">
<failure type="FAIL">
+FAILED:
previous unscoped info SHOULD not be seen
Message.tests.cpp:<line number>
</failure>
</testcase>
<testcase classname="<exe-name>.global" name="long long" time="{duration}"/>
<testcase classname="<exe-name>.global" name="looped SECTION tests/b is currently: 0" time="{duration}">
- <failure message="0 > 1" type="CHECK">
+ <failure message="b > a" type="CHECK">
+FAILED:
+ CHECK( b > a )
+with expansion:
+ 0 > 1
Misc.tests.cpp:<line number>
</failure>
</testcase>
<testcase classname="<exe-name>.global" name="looped SECTION tests/b is currently: 1" time="{duration}">
- <failure message="1 > 1" type="CHECK">
+ <failure message="b > a" type="CHECK">
+FAILED:
+ CHECK( b > a )
+with expansion:
+ 1 > 1
Misc.tests.cpp:<line number>
</failure>
</testcase>
@@ -913,34 +1493,62 @@ Misc.tests.cpp:<line number>
<testcase classname="<exe-name>.global" name="looped SECTION tests/b is currently: 8" time="{duration}"/>
<testcase classname="<exe-name>.global" name="looped SECTION tests/b is currently: 9" time="{duration}"/>
<testcase classname="<exe-name>.global" name="looped tests" time="{duration}">
- <failure message="1 == 0" type="CHECK">
+ <failure message="( fib[i] % 2 ) == 0" type="CHECK">
+FAILED:
+ CHECK( ( fib[i] % 2 ) == 0 )
+with expansion:
+ 1 == 0
Testing if fib[0] (1) is even
Misc.tests.cpp:<line number>
</failure>
- <failure message="1 == 0" type="CHECK">
+ <failure message="( fib[i] % 2 ) == 0" type="CHECK">
+FAILED:
+ CHECK( ( fib[i] % 2 ) == 0 )
+with expansion:
+ 1 == 0
Testing if fib[1] (1) is even
Misc.tests.cpp:<line number>
</failure>
- <failure message="1 == 0" type="CHECK">
+ <failure message="( fib[i] % 2 ) == 0" type="CHECK">
+FAILED:
+ CHECK( ( fib[i] % 2 ) == 0 )
+with expansion:
+ 1 == 0
Testing if fib[3] (3) is even
Misc.tests.cpp:<line number>
</failure>
- <failure message="1 == 0" type="CHECK">
+ <failure message="( fib[i] % 2 ) == 0" type="CHECK">
+FAILED:
+ CHECK( ( fib[i] % 2 ) == 0 )
+with expansion:
+ 1 == 0
Testing if fib[4] (5) is even
Misc.tests.cpp:<line number>
</failure>
- <failure message="1 == 0" type="CHECK">
+ <failure message="( fib[i] % 2 ) == 0" type="CHECK">
+FAILED:
+ CHECK( ( fib[i] % 2 ) == 0 )
+with expansion:
+ 1 == 0
Testing if fib[6] (13) is even
Misc.tests.cpp:<line number>
</failure>
- <failure message="1 == 0" type="CHECK">
+ <failure message="( fib[i] % 2 ) == 0" type="CHECK">
+FAILED:
+ CHECK( ( fib[i] % 2 ) == 0 )
+with expansion:
+ 1 == 0
Testing if fib[7] (21) is even
Misc.tests.cpp:<line number>
</failure>
</testcase>
<testcase classname="<exe-name>.global" name="mix info, unscoped info and warning" time="{duration}"/>
<testcase classname="<exe-name>.global" name="more nested SECTION tests/equal/doesn't equal" time="{duration}">
- <failure message="1 == 2" type="REQUIRE">
+ <failure message="a == b" type="REQUIRE">
+FAILED:
+ REQUIRE( a == b )
+with expansion:
+ 1 == 2
Misc.tests.cpp:<line number>
</failure>
</testcase>
@@ -953,6 +1561,8 @@ Misc.tests.cpp:<line number>
<testcase classname="<exe-name>.global" name="not allowed" time="{duration}"/>
<testcase classname="<exe-name>.global" name="not prints unscoped info from previous failures" time="{duration}">
<failure message="false" type="REQUIRE">
+FAILED:
+ REQUIRE( false )
this SHOULD be seen
Message.tests.cpp:<line number>
</failure>
@@ -960,10 +1570,15 @@ Message.tests.cpp:<line number>
<testcase classname="<exe-name>.global" name="null strings" time="{duration}"/>
<testcase classname="<exe-name>.global" name="null_ptr" time="{duration}"/>
<testcase classname="<exe-name>.global" name="pair&lt;pair&lt;int,const char *,pair&lt;std::string,int> > -> toString" time="{duration}"/>
+ <testcase classname="<exe-name>.global" name="parseEnums/No enums" time="{duration}"/>
+ <testcase classname="<exe-name>.global" name="parseEnums/One enum value" time="{duration}"/>
+ <testcase classname="<exe-name>.global" name="parseEnums/Multiple enum values" time="{duration}"/>
<testcase classname="<exe-name>.global" name="pointer to class" time="{duration}"/>
<testcase classname="<exe-name>.global" name="print unscoped info if passing unscoped info is printed" time="{duration}"/>
<testcase classname="<exe-name>.global" name="prints unscoped info on failure" time="{duration}">
<failure message="false" type="REQUIRE">
+FAILED:
+ REQUIRE( false )
this SHOULD be seen
this SHOULD also be seen
Message.tests.cpp:<line number>
@@ -971,6 +1586,8 @@ Message.tests.cpp:<line number>
</testcase>
<testcase classname="<exe-name>.global" name="prints unscoped info only for the first assertion" time="{duration}">
<failure message="false" type="CHECK">
+FAILED:
+ CHECK( false )
this SHOULD be seen only ONCE
Message.tests.cpp:<line number>
</failure>
@@ -986,20 +1603,27 @@ Message.tests.cpp:<line number>
<testcase classname="<exe-name>.global" name="replaceInPlace/escape '" time="{duration}"/>
<testcase classname="<exe-name>.global" name="send a single char to INFO" time="{duration}">
<failure message="false" type="REQUIRE">
+FAILED:
+ REQUIRE( false )
3
Misc.tests.cpp:<line number>
</failure>
</testcase>
<testcase classname="<exe-name>.global" name="sends information to INFO" time="{duration}">
<failure message="false" type="REQUIRE">
+FAILED:
+ REQUIRE( false )
hi
i := 7
Message.tests.cpp:<line number>
</failure>
</testcase>
<testcase classname="<exe-name>.global" name="shortened hide tags are split apart" time="{duration}"/>
+ <testcase classname="<exe-name>.global" name="splitString" time="{duration}"/>
<testcase classname="<exe-name>.global" name="stacks unscoped info in loops" time="{duration}">
<failure message="false" type="CHECK">
+FAILED:
+ CHECK( false )
Count 1 to 3...
1
2
@@ -1007,6 +1631,8 @@ Count 1 to 3...
Message.tests.cpp:<line number>
</failure>
<failure message="false" type="CHECK">
+FAILED:
+ CHECK( false )
Count 4 to 6...
4
5
@@ -1024,7 +1650,11 @@ Message.tests.cpp:<line number>
<testcase classname="<exe-name>.global" name="std::set is convertible string/several items" time="{duration}"/>
<testcase classname="<exe-name>.global" name="std::vector&lt;std::pair&lt;std::string,int> > -> toString" time="{duration}"/>
<testcase classname="<exe-name>.global" name="string literals of different sizes can be compared" time="{duration}">
- <failure message="&quot;first&quot; == &quot;second&quot;" type="REQUIRE">
+ <failure message="std::string( &quot;first&quot; ) == &quot;second&quot;" type="REQUIRE">
+FAILED:
+ REQUIRE( std::string( "first" ) == "second" )
+with expansion:
+ "first" == "second"
Tricky.tests.cpp:<line number>
</failure>
</testcase>
@@ -1041,6 +1671,7 @@ Tricky.tests.cpp:<line number>
<testcase classname="<exe-name>.global" name="tables" time="{duration}"/>
<testcase classname="<exe-name>.global" name="thrown std::strings are translated" time="{duration}">
<error type="TEST_CASE">
+FAILED:
Why would you throw a std::string?
Exception.tests.cpp:<line number>
</error>
diff --git a/projects/SelfTest/Baselines/sonarqube.sw.approved.txt b/projects/SelfTest/Baselines/sonarqube.sw.approved.txt
new file mode 100644
index 00000000..1f89e99c
--- /dev/null
+++ b/projects/SelfTest/Baselines/sonarqube.sw.approved.txt
@@ -0,0 +1,1731 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<testExecutions version="1"loose text artifact
+>
+ <file path="projects/<exe-name>/IntrospectiveTests/CmdLine.tests.cpp">
+ <testCase name="Parse test names and tags/Empty test spec should have no filters" duration="{duration}"/>
+ <testCase name="Parse test names and tags/Test spec from empty string should have no filters" duration="{duration}"/>
+ <testCase name="Parse test names and tags/Test spec from just a comma should have no filters" duration="{duration}"/>
+ <testCase name="Parse test names and tags/Test spec from name should have one filter" duration="{duration}"/>
+ <testCase name="Parse test names and tags/Test spec from quoted name should have one filter" duration="{duration}"/>
+ <testCase name="Parse test names and tags/Test spec from name should have one filter" duration="{duration}"/>
+ <testCase name="Parse test names and tags/Wildcard at the start" duration="{duration}"/>
+ <testCase name="Parse test names and tags/Wildcard at the end" duration="{duration}"/>
+ <testCase name="Parse test names and tags/Wildcard at both ends" duration="{duration}"/>
+ <testCase name="Parse test names and tags/Redundant wildcard at the start" duration="{duration}"/>
+ <testCase name="Parse test names and tags/Redundant wildcard at the end" duration="{duration}"/>
+ <testCase name="Parse test names and tags/Redundant wildcard at both ends" duration="{duration}"/>
+ <testCase name="Parse test names and tags/Wildcard at both ends, redundant at start" duration="{duration}"/>
+ <testCase name="Parse test names and tags/Just wildcard" duration="{duration}"/>
+ <testCase name="Parse test names and tags/Single tag" duration="{duration}"/>
+ <testCase name="Parse test names and tags/Single tag, two matches" duration="{duration}"/>
+ <testCase name="Parse test names and tags/Two tags" duration="{duration}"/>
+ <testCase name="Parse test names and tags/Two tags, spare separated" duration="{duration}"/>
+ <testCase name="Parse test names and tags/Wildcarded name and tag" duration="{duration}"/>
+ <testCase name="Parse test names and tags/Single tag exclusion" duration="{duration}"/>
+ <testCase name="Parse test names and tags/One tag exclusion and one tag inclusion" duration="{duration}"/>
+ <testCase name="Parse test names and tags/One tag exclusion and one wldcarded name inclusion" duration="{duration}"/>
+ <testCase name="Parse test names and tags/One tag exclusion, using exclude:, and one wldcarded name inclusion" duration="{duration}"/>
+ <testCase name="Parse test names and tags/name exclusion" duration="{duration}"/>
+ <testCase name="Parse test names and tags/wildcarded name exclusion" duration="{duration}"/>
+ <testCase name="Parse test names and tags/wildcarded name exclusion with tag inclusion" duration="{duration}"/>
+ <testCase name="Parse test names and tags/wildcarded name exclusion, using exclude:, with tag inclusion" duration="{duration}"/>
+ <testCase name="Parse test names and tags/two wildcarded names" duration="{duration}"/>
+ <testCase name="Parse test names and tags/empty tag" duration="{duration}"/>
+ <testCase name="Parse test names and tags/empty quoted name" duration="{duration}"/>
+ <testCase name="Parse test names and tags/quoted string followed by tag exclusion" duration="{duration}"/>
+ <testCase name="Parse test names and tags/Leading and trailing spaces in test spec" duration="{duration}"/>
+ <testCase name="Parse test names and tags/Leading and trailing spaces in test name" duration="{duration}"/>
+ <testCase name="Parse test names and tags/Shortened hide tags are split apart when parsing" duration="{duration}"/>
+ <testCase name="Parse test names and tags/Shortened hide tags also properly handle exclusion" duration="{duration}"/>
+ <testCase name="Process can be configured on command line/empty args don't cause a crash" duration="{duration}"/>
+ <testCase name="Process can be configured on command line/default - no arguments" duration="{duration}"/>
+ <testCase name="Process can be configured on command line/test lists/Specify one test case using" duration="{duration}"/>
+ <testCase name="Process can be configured on command line/test lists/Specify one test case exclusion using exclude:" duration="{duration}"/>
+ <testCase name="Process can be configured on command line/test lists/Specify one test case exclusion using ~" duration="{duration}"/>
+ <testCase name="Process can be configured on command line/reporter/-r/console" duration="{duration}"/>
+ <testCase name="Process can be configured on command line/reporter/-r/xml" duration="{duration}"/>
+ <testCase name="Process can be configured on command line/reporter/--reporter/junit" duration="{duration}"/>
+ <testCase name="Process can be configured on command line/reporter/Only one reporter is accepted" duration="{duration}"/>
+ <testCase name="Process can be configured on command line/reporter/must match one of the available ones" duration="{duration}"/>
+ <testCase name="Process can be configured on command line/debugger/-b" duration="{duration}"/>
+ <testCase name="Process can be configured on command line/debugger/--break" duration="{duration}"/>
+ <testCase name="Process can be configured on command line/abort/-a aborts after first failure" duration="{duration}"/>
+ <testCase name="Process can be configured on command line/abort/-x 2 aborts after two failures" duration="{duration}"/>
+ <testCase name="Process can be configured on command line/abort/-x must be numeric" duration="{duration}"/>
+ <testCase name="Process can be configured on command line/abort/wait-for-keypress/Accepted options" duration="{duration}"/>
+ <testCase name="Process can be configured on command line/abort/wait-for-keypress/invalid options are reported" duration="{duration}"/>
+ <testCase name="Process can be configured on command line/nothrow/-e" duration="{duration}"/>
+ <testCase name="Process can be configured on command line/nothrow/--nothrow" duration="{duration}"/>
+ <testCase name="Process can be configured on command line/output filename/-o filename" duration="{duration}"/>
+ <testCase name="Process can be configured on command line/output filename/--out" duration="{duration}"/>
+ <testCase name="Process can be configured on command line/combinations/Single character flags can be combined" duration="{duration}"/>
+ <testCase name="Process can be configured on command line/use-colour/without option" duration="{duration}"/>
+ <testCase name="Process can be configured on command line/use-colour/auto" duration="{duration}"/>
+ <testCase name="Process can be configured on command line/use-colour/yes" duration="{duration}"/>
+ <testCase name="Process can be configured on command line/use-colour/no" duration="{duration}"/>
+ <testCase name="Process can be configured on command line/use-colour/error" duration="{duration}"/>
+ <testCase name="Process can be configured on command line/Benchmark options/samples" duration="{duration}"/>
+ <testCase name="Process can be configured on command line/Benchmark options/resamples" duration="{duration}"/>
+ <testCase name="Process can be configured on command line/Benchmark options/confidence-interval" duration="{duration}"/>
+ <testCase name="Process can be configured on command line/Benchmark options/no-analysis" duration="{duration}"/>
+ <testCase name="Process can be configured on command line/Benchmark options/warmup-time" duration="{duration}"/>
+ <testCase name="Test with special, characters &quot;in name" duration="{duration}"/>
+ </file>
+ <file path="projects/<exe-name>/IntrospectiveTests/GeneratorsImpl.tests.cpp">
+ <testCase name="Generators internals/Single value" duration="{duration}"/>
+ <testCase name="Generators internals/Preset values" duration="{duration}"/>
+ <testCase name="Generators internals/Generator combinator" duration="{duration}"/>
+ <testCase name="Generators internals/Explicitly typed generator sequence" duration="{duration}"/>
+ <testCase name="Generators internals/Filter generator" duration="{duration}"/>
+ <testCase name="Generators internals/Take generator/Take less" duration="{duration}"/>
+ <testCase name="Generators internals/Take generator/Take more" duration="{duration}"/>
+ <testCase name="Generators internals/Map with explicit return type" duration="{duration}"/>
+ <testCase name="Generators internals/Map with deduced return type" duration="{duration}"/>
+ <testCase name="Generators internals/Repeat/Singular repeat" duration="{duration}"/>
+ <testCase name="Generators internals/Repeat/Actual repeat" duration="{duration}"/>
+ <testCase name="Generators internals/Range/Positive auto step/Integer" duration="{duration}"/>
+ <testCase name="Generators internals/Range/Negative auto step/Integer" duration="{duration}"/>
+ <testCase name="Generators internals/Range/Positive manual step/Integer/Exact" duration="{duration}"/>
+ <testCase name="Generators internals/Range/Positive manual step/Integer/Slightly over end" duration="{duration}"/>
+ <testCase name="Generators internals/Range/Positive manual step/Integer/Slightly under end" duration="{duration}"/>
+ <testCase name="Generators internals/Range/Positive manual step/Floating Point/Exact" duration="{duration}"/>
+ <testCase name="Generators internals/Range/Positive manual step/Floating Point/Slightly over end" duration="{duration}"/>
+ <testCase name="Generators internals/Range/Positive manual step/Floating Point/Slightly under end" duration="{duration}"/>
+ <testCase name="Generators internals/Range/Negative manual step/Integer/Exact" duration="{duration}"/>
+ <testCase name="Generators internals/Range/Negative manual step/Integer/Slightly over end" duration="{duration}"/>
+ <testCase name="Generators internals/Range/Negative manual step/Integer/Slightly under end" duration="{duration}"/>
+ </file>
+ <file path="projects/<exe-name>/IntrospectiveTests/PartTracker.tests.cpp">
+ <testCase name="Tracker" duration="{duration}"/>
+ <testCase name="Tracker/successfully close one section" duration="{duration}"/>
+ <testCase name="Tracker/fail one section" duration="{duration}"/>
+ <testCase name="Tracker/fail one section/re-enter after failed section" duration="{duration}"/>
+ <testCase name="Tracker/fail one section/re-enter after failed section and find next section" duration="{duration}"/>
+ <testCase name="Tracker/successfully close one section, then find another" duration="{duration}"/>
+ <testCase name="Tracker/successfully close one section, then find another/Re-enter - skips S1 and enters S2" duration="{duration}"/>
+ <testCase name="Tracker/successfully close one section, then find another/Re-enter - skips S1 and enters S2/Successfully close S2" duration="{duration}"/>
+ <testCase name="Tracker/successfully close one section, then find another/Re-enter - skips S1 and enters S2/fail S2" duration="{duration}"/>
+ <testCase name="Tracker/open a nested section" duration="{duration}"/>
+ </file>
+ <file path="projects/<exe-name>/IntrospectiveTests/RandomNumberGeneration.tests.cpp">
+ <testCase name="Comparison ops" duration="{duration}"/>
+ <testCase name="Our PCG implementation provides expected results for known seeds/Default seeded" duration="{duration}"/>
+ <testCase name="Our PCG implementation provides expected results for known seeds/Specific seed" duration="{duration}"/>
+ </file>
+ <file path="projects/<exe-name>/IntrospectiveTests/String.tests.cpp">
+ <testCase name="StringRef/Empty string" duration="{duration}"/>
+ <testCase name="StringRef/From string literal" duration="{duration}"/>
+ <testCase name="StringRef/From sub-string" duration="{duration}"/>
+ <testCase name="StringRef/Substrings/zero-based substring" duration="{duration}"/>
+ <testCase name="StringRef/Substrings/non-zero-based substring" duration="{duration}"/>
+ <testCase name="StringRef/Substrings/Pointer values of full refs should match" duration="{duration}"/>
+ <testCase name="StringRef/Substrings/Pointer values of substring refs should also match" duration="{duration}"/>
+ <testCase name="StringRef/Substrings/Past the end substring" duration="{duration}"/>
+ <testCase name="StringRef/Substrings/Substring off the end are trimmed" duration="{duration}"/>
+ <testCase name="StringRef/Comparisons are deep" duration="{duration}"/>
+ <testCase name="StringRef/from std::string/implicitly constructed" duration="{duration}"/>
+ <testCase name="StringRef/from std::string/explicitly constructed" duration="{duration}"/>
+ <testCase name="StringRef/from std::string/assigned" duration="{duration}"/>
+ <testCase name="StringRef/to std::string/explicitly constructed" duration="{duration}"/>
+ <testCase name="StringRef/to std::string/assigned" duration="{duration}"/>
+ <testCase name="StringRef at compilation time/Simple constructors" duration="{duration}"/>
+ <testCase name="StringRef at compilation time/UDL construction" duration="{duration}"/>
+ </file>
+ <file path="projects/<exe-name>/IntrospectiveTests/StringManip.tests.cpp">
+ <testCase name="Trim strings" duration="{duration}"/>
+ <testCase name="replaceInPlace/replace single char" duration="{duration}"/>
+ <testCase name="replaceInPlace/replace two chars" duration="{duration}"/>
+ <testCase name="replaceInPlace/replace first char" duration="{duration}"/>
+ <testCase name="replaceInPlace/replace last char" duration="{duration}"/>
+ <testCase name="replaceInPlace/replace all chars" duration="{duration}"/>
+ <testCase name="replaceInPlace/replace no chars" duration="{duration}"/>
+ <testCase name="replaceInPlace/escape '" duration="{duration}"/>
+ <testCase name="splitString" duration="{duration}"/>
+ </file>
+ <file path="projects/<exe-name>/IntrospectiveTests/Tag.tests.cpp">
+ <testCase name="Tag alias can be registered against tag patterns/The same tag alias can only be registered once" duration="{duration}"/>
+ <testCase name="Tag alias can be registered against tag patterns/Tag aliases must be of the form [@name]" duration="{duration}"/>
+ <testCase name="adding a hide tag implicitly enables all others" duration="{duration}"/>
+ <testCase name="shortened hide tags are split apart" duration="{duration}"/>
+ </file>
+ <file path="projects/<exe-name>/IntrospectiveTests/ToString.tests.cpp">
+ <testCase name="Directly creating an EnumInfo" duration="{duration}"/>
+ <testCase name="parseEnums/No enums" duration="{duration}"/>
+ <testCase name="parseEnums/One enum value" duration="{duration}"/>
+ <testCase name="parseEnums/Multiple enum values" duration="{duration}"/>
+ </file>
+ <file path="projects/<exe-name>/IntrospectiveTests/Xml.tests.cpp">
+ <testCase name="XmlEncode/normal string" duration="{duration}"/>
+ <testCase name="XmlEncode/empty string" duration="{duration}"/>
+ <testCase name="XmlEncode/string with ampersand" duration="{duration}"/>
+ <testCase name="XmlEncode/string with less-than" duration="{duration}"/>
+ <testCase name="XmlEncode/string with greater-than" duration="{duration}"/>
+ <testCase name="XmlEncode/string with quotes" duration="{duration}"/>
+ <testCase name="XmlEncode/string with control char (1)" duration="{duration}"/>
+ <testCase name="XmlEncode/string with control char (x7F)" duration="{duration}"/>
+ </file>
+ <file path="projects/<exe-name>/UsageTests/Approx.tests.cpp">
+ <testCase name="A comparison that uses literals instead of the normal constructor" duration="{duration}"/>
+ <testCase name="Absolute margin" duration="{duration}"/>
+ <testCase name="Approx setters validate their arguments" duration="{duration}"/>
+ <testCase name="Approx with exactly-representable margin" duration="{duration}"/>
+ <testCase name="Approximate PI" duration="{duration}"/>
+ <testCase name="Approximate comparisons with different epsilons" duration="{duration}"/>
+ <testCase name="Approximate comparisons with floats" duration="{duration}"/>
+ <testCase name="Approximate comparisons with ints" duration="{duration}"/>
+ <testCase name="Approximate comparisons with mixed numeric types" duration="{duration}"/>
+ <testCase name="Comparison with explicitly convertible types" duration="{duration}"/>
+ <testCase name="Default scale is invisible to comparison" duration="{duration}"/>
+ <testCase name="Epsilon only applies to Approx's value" duration="{duration}"/>
+ <testCase name="Greater-than inequalities with different epsilons" duration="{duration}"/>
+ <testCase name="Less-than inequalities with different epsilons" duration="{duration}"/>
+ <testCase name="Some simple comparisons between doubles" duration="{duration}"/>
+ <testCase name="Use a custom approx" duration="{duration}"/>
+ </file>
+ <file path="projects/<exe-name>/UsageTests/BDD.tests.cpp">
+ <testCase name="Scenario: BDD tests requiring Fixtures to provide commonly-accessed data or methods/Given: No operations precede me" duration="{duration}"/>
+ <testCase name="Scenario: BDD tests requiring Fixtures to provide commonly-accessed data or methods/Given: No operations precede me/When: We get the count/Then: Subsequently values are higher" duration="{duration}"/>
+ <testCase name="Scenario: Do that thing with the thing/Given: This stuff exists/And given: And some assumption/When: I do this/Then: it should do this" duration="{duration}"/>
+ <testCase name="Scenario: Do that thing with the thing/Given: This stuff exists/And given: And some assumption/When: I do this/Then: it should do this/And: do that" duration="{duration}"/>
+ <testCase name="Scenario: This is a really long scenario name to see how the list command deals with wrapping/Given: A section name that is so long that it cannot fit in a single console width/When: The test headers are printed as part of the normal running of the scenario/Then: The, deliberately very long and overly verbose (you see what I did there?) section names must wrap, along with an indent" duration="{duration}"/>
+ <testCase name="Scenario: Vector resizing affects size and capacity/Given: an empty vector" duration="{duration}"/>
+ <testCase name="Scenario: Vector resizing affects size and capacity/Given: an empty vector/When: it is made larger/Then: the size and capacity go up" duration="{duration}"/>
+ <testCase name="Scenario: Vector resizing affects size and capacity/Given: an empty vector/When: it is made larger/Then: the size and capacity go up/And when: it is made smaller again/Then: the size goes down but the capacity stays the same" duration="{duration}"/>
+ <testCase name="Scenario: Vector resizing affects size and capacity/Given: an empty vector/When: we reserve more space/Then: The capacity is increased but the size remains the same" duration="{duration}"/>
+ </file>
+ <file path="projects/<exe-name>/UsageTests/Class.tests.cpp">
+ <testCase name="A METHOD_AS_TEST_CASE based test run that fails" duration="{duration}">
+ <failure message="REQUIRE(s == &quot;world&quot;)">
+FAILED:
+ REQUIRE( s == "world" )
+with expansion:
+ "hello" == "world"
+Class.tests.cpp:<line number>
+ </failure>
+ </testCase>
+ <testCase name="A METHOD_AS_TEST_CASE based test run that succeeds" duration="{duration}"/>
+ <testCase name="A TEMPLATE_PRODUCT_TEST_CASE_METHOD based test run that fails - Template_Foo&lt;float>" duration="{duration}">
+ <failure message="REQUIRE(Template_Fixture_2&lt;TestType>::m_a.size() == 1)">
+FAILED:
+ REQUIRE( Template_Fixture_2&lt;TestType>::m_a.size() == 1 )
+with expansion:
+ 0 == 1
+Class.tests.cpp:<line number>
+ </failure>
+ </testCase>
+ <testCase name="A TEMPLATE_PRODUCT_TEST_CASE_METHOD based test run that fails - Template_Foo&lt;int>" duration="{duration}">
+ <failure message="REQUIRE(Template_Fixture_2&lt;TestType>::m_a.size() == 1)">
+FAILED:
+ REQUIRE( Template_Fixture_2&lt;TestType>::m_a.size() == 1 )
+with expansion:
+ 0 == 1
+Class.tests.cpp:<line number>
+ </failure>
+ </testCase>
+ <testCase name="A TEMPLATE_PRODUCT_TEST_CASE_METHOD based test run that fails - std::vector&lt;float>" duration="{duration}">
+ <failure message="REQUIRE(Template_Fixture_2&lt;TestType>::m_a.size() == 1)">
+FAILED:
+ REQUIRE( Template_Fixture_2&lt;TestType>::m_a.size() == 1 )
+with expansion:
+ 0 == 1
+Class.tests.cpp:<line number>
+ </failure>
+ </testCase>
+ <testCase name="A TEMPLATE_PRODUCT_TEST_CASE_METHOD based test run that fails - std::vector&lt;int>" duration="{duration}">
+ <failure message="REQUIRE(Template_Fixture_2&lt;TestType>::m_a.size() == 1)">
+FAILED:
+ REQUIRE( Template_Fixture_2&lt;TestType>::m_a.size() == 1 )
+with expansion:
+ 0 == 1
+Class.tests.cpp:<line number>
+ </failure>
+ </testCase>
+ <testCase name="A TEMPLATE_PRODUCT_TEST_CASE_METHOD based test run that succeeds - Template_Foo&lt;float>" duration="{duration}"/>
+ <testCase name="A TEMPLATE_PRODUCT_TEST_CASE_METHOD based test run that succeeds - Template_Foo&lt;int>" duration="{duration}"/>
+ <testCase name="A TEMPLATE_PRODUCT_TEST_CASE_METHOD based test run that succeeds - std::vector&lt;float>" duration="{duration}"/>
+ <testCase name="A TEMPLATE_PRODUCT_TEST_CASE_METHOD based test run that succeeds - std::vector&lt;int>" duration="{duration}"/>
+ <testCase name="A TEMPLATE_PRODUCT_TEST_CASE_METHOD_SIG based test run that fails - Template_Foo_2&lt;float, 6>" duration="{duration}">
+ <failure message="REQUIRE(Template_Fixture_2&lt;TestType>{}.m_a.size() &lt; 2)">
+FAILED:
+ REQUIRE( Template_Fixture_2&lt;TestType>{}.m_a.size() &lt; 2 )
+with expansion:
+ 6 &lt; 2
+Class.tests.cpp:<line number>
+ </failure>
+ </testCase>
+ <testCase name="A TEMPLATE_PRODUCT_TEST_CASE_METHOD_SIG based test run that fails - Template_Foo_2&lt;int, 2>" duration="{duration}">
+ <failure message="REQUIRE(Template_Fixture_2&lt;TestType>{}.m_a.size() &lt; 2)">
+FAILED:
+ REQUIRE( Template_Fixture_2&lt;TestType>{}.m_a.size() &lt; 2 )
+with expansion:
+ 2 &lt; 2
+Class.tests.cpp:<line number>
+ </failure>
+ </testCase>
+ <testCase name="A TEMPLATE_PRODUCT_TEST_CASE_METHOD_SIG based test run that fails - std::array&lt;float, 6>" duration="{duration}">
+ <failure message="REQUIRE(Template_Fixture_2&lt;TestType>{}.m_a.size() &lt; 2)">
+FAILED:
+ REQUIRE( Template_Fixture_2&lt;TestType>{}.m_a.size() &lt; 2 )
+with expansion:
+ 6 &lt; 2
+Class.tests.cpp:<line number>
+ </failure>
+ </testCase>
+ <testCase name="A TEMPLATE_PRODUCT_TEST_CASE_METHOD_SIG based test run that fails - std::array&lt;int, 2>" duration="{duration}">
+ <failure message="REQUIRE(Template_Fixture_2&lt;TestType>{}.m_a.size() &lt; 2)">
+FAILED:
+ REQUIRE( Template_Fixture_2&lt;TestType>{}.m_a.size() &lt; 2 )
+with expansion:
+ 2 &lt; 2
+Class.tests.cpp:<line number>
+ </failure>
+ </testCase>
+ <testCase name="A TEMPLATE_PRODUCT_TEST_CASE_METHOD_SIG based test run that succeeds - Template_Foo_2&lt;float,6>" duration="{duration}"/>
+ <testCase name="A TEMPLATE_PRODUCT_TEST_CASE_METHOD_SIG based test run that succeeds - Template_Foo_2&lt;int,2>" duration="{duration}"/>
+ <testCase name="A TEMPLATE_PRODUCT_TEST_CASE_METHOD_SIG based test run that succeeds - std::array&lt;float,6>" duration="{duration}"/>
+ <testCase name="A TEMPLATE_PRODUCT_TEST_CASE_METHOD_SIG based test run that succeeds - std::array&lt;int,2>" duration="{duration}"/>
+ <testCase name="A TEMPLATE_TEST_CASE_METHOD based test run that fails - double" duration="{duration}">
+ <failure message="REQUIRE(Template_Fixture&lt;TestType>::m_a == 2)">
+FAILED:
+ REQUIRE( Template_Fixture&lt;TestType>::m_a == 2 )
+with expansion:
+ 1.0 == 2
+Class.tests.cpp:<line number>
+ </failure>
+ </testCase>
+ <testCase name="A TEMPLATE_TEST_CASE_METHOD based test run that fails - float" duration="{duration}">
+ <failure message="REQUIRE(Template_Fixture&lt;TestType>::m_a == 2)">
+FAILED:
+ REQUIRE( Template_Fixture&lt;TestType>::m_a == 2 )
+with expansion:
+ 1.0f == 2
+Class.tests.cpp:<line number>
+ </failure>
+ </testCase>
+ <testCase name="A TEMPLATE_TEST_CASE_METHOD based test run that fails - int" duration="{duration}">
+ <failure message="REQUIRE(Template_Fixture&lt;TestType>::m_a == 2)">
+FAILED:
+ REQUIRE( Template_Fixture&lt;TestType>::m_a == 2 )
+with expansion:
+ 1 == 2
+Class.tests.cpp:<line number>
+ </failure>
+ </testCase>
+ <testCase name="A TEMPLATE_TEST_CASE_METHOD based test run that succeeds - double" duration="{duration}"/>
+ <testCase name="A TEMPLATE_TEST_CASE_METHOD based test run that succeeds - float" duration="{duration}"/>
+ <testCase name="A TEMPLATE_TEST_CASE_METHOD based test run that succeeds - int" duration="{duration}"/>
+ <testCase name="A TEMPLATE_TEST_CASE_METHOD_SIG based test run that fails - 1" duration="{duration}">
+ <failure message="REQUIRE(Nttp_Fixture&lt;V>::value == 0)">
+FAILED:
+ REQUIRE( Nttp_Fixture&lt;V>::value == 0 )
+with expansion:
+ 1 == 0
+Class.tests.cpp:<line number>
+ </failure>
+ </testCase>
+ <testCase name="A TEMPLATE_TEST_CASE_METHOD_SIG based test run that fails - 3" duration="{duration}">
+ <failure message="REQUIRE(Nttp_Fixture&lt;V>::value == 0)">
+FAILED:
+ REQUIRE( Nttp_Fixture&lt;V>::value == 0 )
+with expansion:
+ 3 == 0
+Class.tests.cpp:<line number>
+ </failure>
+ </testCase>
+ <testCase name="A TEMPLATE_TEST_CASE_METHOD_SIG based test run that fails - 6" duration="{duration}">
+ <failure message="REQUIRE(Nttp_Fixture&lt;V>::value == 0)">
+FAILED:
+ REQUIRE( Nttp_Fixture&lt;V>::value == 0 )
+with expansion:
+ 6 == 0
+Class.tests.cpp:<line number>
+ </failure>
+ </testCase>
+ <testCase name="A TEMPLATE_TEST_CASE_METHOD_SIG based test run that succeeds - 1" duration="{duration}"/>
+ <testCase name="A TEMPLATE_TEST_CASE_METHOD_SIG based test run that succeeds - 3" duration="{duration}"/>
+ <testCase name="A TEMPLATE_TEST_CASE_METHOD_SIG based test run that succeeds - 6" duration="{duration}"/>
+ <testCase name="A TEST_CASE_METHOD based test run that fails" duration="{duration}">
+ <failure message="REQUIRE(m_a == 2)">
+FAILED:
+ REQUIRE( m_a == 2 )
+with expansion:
+ 1 == 2
+Class.tests.cpp:<line number>
+ </failure>
+ </testCase>
+ <testCase name="A TEST_CASE_METHOD based test run that succeeds" duration="{duration}"/>
+ <testCase name="Template test case method with test types specified inside std::tuple - MyTypes - 0" duration="{duration}"/>
+ <testCase name="Template test case method with test types specified inside std::tuple - MyTypes - 1" duration="{duration}"/>
+ <testCase name="Template test case method with test types specified inside std::tuple - MyTypes - 2" duration="{duration}"/>
+ </file>
+ <file path="projects/<exe-name>/UsageTests/Compilation.tests.cpp">
+ <testCase name="#1027" duration="{duration}"/>
+ <testCase name="#1027: Bitfields can be captured" duration="{duration}"/>
+ <testCase name="#1147" duration="{duration}"/>
+ <testCase name="#1238" duration="{duration}"/>
+ <testCase name="#1245" duration="{duration}"/>
+ <testCase name="#1403" duration="{duration}"/>
+ <testCase name="#1548" duration="{duration}"/>
+ <testCase name="#809" duration="{duration}"/>
+ <testCase name="#833" duration="{duration}"/>
+ <testCase name="#872" duration="{duration}"/>
+ <testCase name="Optionally static assertions" duration="{duration}"/>
+ </file>
+ <file path="projects/<exe-name>/UsageTests/Condition.tests.cpp">
+ <testCase name="'Not' checks that should fail" duration="{duration}">
+ <failure message="CHECK(false != false)">
+FAILED:
+ CHECK( false != false )
+Condition.tests.cpp:<line number>
+ </failure>
+ <failure message="CHECK(true != true)">
+FAILED:
+ CHECK( true != true )
+Condition.tests.cpp:<line number>
+ </failure>
+ <failure message="CHECK(!true)">
+FAILED:
+ CHECK( !true )
+with expansion:
+ false
+Condition.tests.cpp:<line number>
+ </failure>
+ <failure message="CHECK_FALSE(!(true))">
+FAILED:
+ CHECK_FALSE( true )
+with expansion:
+ !true
+Condition.tests.cpp:<line number>
+ </failure>
+ <failure message="CHECK(!trueValue)">
+FAILED:
+ CHECK( !trueValue )
+with expansion:
+ false
+Condition.tests.cpp:<line number>
+ </failure>
+ <failure message="CHECK_FALSE(!(trueValue))">
+FAILED:
+ CHECK_FALSE( trueValue )
+with expansion:
+ !true
+Condition.tests.cpp:<line number>
+ </failure>
+ <failure message="CHECK(!(1 == 1))">
+FAILED:
+ CHECK( !(1 == 1) )
+with expansion:
+ false
+Condition.tests.cpp:<line number>
+ </failure>
+ <failure message="CHECK_FALSE(!(1 == 1))">
+FAILED:
+ CHECK_FALSE( 1 == 1 )
+Condition.tests.cpp:<line number>
+ </failure>
+ </testCase>
+ <testCase name="'Not' checks that should succeed" duration="{duration}"/>
+ <testCase name="Comparisons between ints where one side is computed" duration="{duration}"/>
+ <testCase name="Comparisons between unsigned ints and negative signed ints match c++ standard behaviour" duration="{duration}"/>
+ <testCase name="Comparisons with int literals don't warn when mixing signed/ unsigned" duration="{duration}"/>
+ <testCase name="Equality checks that should fail" duration="{duration}">
+ <skipped message="CHECK(data.int_seven == 6)">
+FAILED:
+ CHECK( data.int_seven == 6 )
+with expansion:
+ 7 == 6
+Condition.tests.cpp:<line number>
+ </skipped>
+ <skipped message="CHECK(data.int_seven == 8)">
+FAILED:
+ CHECK( data.int_seven == 8 )
+with expansion:
+ 7 == 8
+Condition.tests.cpp:<line number>
+ </skipped>
+ <skipped message="CHECK(data.int_seven == 0)">
+FAILED:
+ CHECK( data.int_seven == 0 )
+with expansion:
+ 7 == 0
+Condition.tests.cpp:<line number>
+ </skipped>
+ <skipped message="CHECK(data.float_nine_point_one == Approx( 9.11f ))">
+FAILED:
+ CHECK( data.float_nine_point_one == Approx( 9.11f ) )
+with expansion:
+ 9.1f == Approx( 9.1099996567 )
+Condition.tests.cpp:<line number>
+ </skipped>
+ <skipped message="CHECK(data.float_nine_point_one == Approx( 9.0f ))">
+FAILED:
+ CHECK( data.float_nine_point_one == Approx( 9.0f ) )
+with expansion:
+ 9.1f == Approx( 9.0 )
+Condition.tests.cpp:<line number>
+ </skipped>
+ <skipped message="CHECK(data.float_nine_point_one == Approx( 1 ))">
+FAILED:
+ CHECK( data.float_nine_point_one == Approx( 1 ) )
+with expansion:
+ 9.1f == Approx( 1.0 )
+Condition.tests.cpp:<line number>
+ </skipped>
+ <skipped message="CHECK(data.float_nine_point_one == Approx( 0 ))">
+FAILED:
+ CHECK( data.float_nine_point_one == Approx( 0 ) )
+with expansion:
+ 9.1f == Approx( 0.0 )
+Condition.tests.cpp:<line number>
+ </skipped>
+ <skipped message="CHECK(data.double_pi == Approx( 3.1415 ))">
+FAILED:
+ CHECK( data.double_pi == Approx( 3.1415 ) )
+with expansion:
+ 3.1415926535 == Approx( 3.1415 )
+Condition.tests.cpp:<line number>
+ </skipped>
+ <skipped message="CHECK(data.str_hello == &quot;goodbye&quot;)">
+FAILED:
+ CHECK( data.str_hello == "goodbye" )
+with expansion:
+ "hello" == "goodbye"
+Condition.tests.cpp:<line number>
+ </skipped>
+ <skipped message="CHECK(data.str_hello == &quot;hell&quot;)">
+FAILED:
+ CHECK( data.str_hello == "hell" )
+with expansion:
+ "hello" == "hell"
+Condition.tests.cpp:<line number>
+ </skipped>
+ <skipped message="CHECK(data.str_hello == &quot;hello1&quot;)">
+FAILED:
+ CHECK( data.str_hello == "hello1" )
+with expansion:
+ "hello" == "hello1"
+Condition.tests.cpp:<line number>
+ </skipped>
+ <skipped message="CHECK(data.str_hello.size() == 6)">
+FAILED:
+ CHECK( data.str_hello.size() == 6 )
+with expansion:
+ 5 == 6
+Condition.tests.cpp:<line number>
+ </skipped>
+ <skipped message="CHECK(x == Approx( 1.301 ))">
+FAILED:
+ CHECK( x == Approx( 1.301 ) )
+with expansion:
+ 1.3 == Approx( 1.301 )
+Condition.tests.cpp:<line number>
+ </skipped>
+ </testCase>
+ <testCase name="Equality checks that should succeed" duration="{duration}"/>
+ <testCase name="Inequality checks that should fail" duration="{duration}">
+ <skipped message="CHECK(data.int_seven != 7)">
+FAILED:
+ CHECK( data.int_seven != 7 )
+with expansion:
+ 7 != 7
+Condition.tests.cpp:<line number>
+ </skipped>
+ <skipped message="CHECK(data.float_nine_point_one != Approx( 9.1f ))">
+FAILED:
+ CHECK( data.float_nine_point_one != Approx( 9.1f ) )
+with expansion:
+ 9.1f != Approx( 9.1000003815 )
+Condition.tests.cpp:<line number>
+ </skipped>
+ <skipped message="CHECK(data.double_pi != Approx( 3.1415926535 ))">
+FAILED:
+ CHECK( data.double_pi != Approx( 3.1415926535 ) )
+with expansion:
+ 3.1415926535 != Approx( 3.1415926535 )
+Condition.tests.cpp:<line number>
+ </skipped>
+ <skipped message="CHECK(data.str_hello != &quot;hello&quot;)">
+FAILED:
+ CHECK( data.str_hello != "hello" )
+with expansion:
+ "hello" != "hello"
+Condition.tests.cpp:<line number>
+ </skipped>
+ <skipped message="CHECK(data.str_hello.size() != 5)">
+FAILED:
+ CHECK( data.str_hello.size() != 5 )
+with expansion:
+ 5 != 5
+Condition.tests.cpp:<line number>
+ </skipped>
+ </testCase>
+ <testCase name="Inequality checks that should succeed" duration="{duration}"/>
+ <testCase name="Ordering comparison checks that should fail" duration="{duration}">
+ <failure message="CHECK(data.int_seven > 7)">
+FAILED:
+ CHECK( data.int_seven > 7 )
+with expansion:
+ 7 > 7
+Condition.tests.cpp:<line number>
+ </failure>
+ <failure message="CHECK(data.int_seven &lt; 7)">
+FAILED:
+ CHECK( data.int_seven &lt; 7 )
+with expansion:
+ 7 &lt; 7
+Condition.tests.cpp:<line number>
+ </failure>
+ <failure message="CHECK(data.int_seven > 8)">
+FAILED:
+ CHECK( data.int_seven > 8 )
+with expansion:
+ 7 > 8
+Condition.tests.cpp:<line number>
+ </failure>
+ <failure message="CHECK(data.int_seven &lt; 6)">
+FAILED:
+ CHECK( data.int_seven &lt; 6 )
+with expansion:
+ 7 &lt; 6
+Condition.tests.cpp:<line number>
+ </failure>
+ <failure message="CHECK(data.int_seven &lt; 0)">
+FAILED:
+ CHECK( data.int_seven &lt; 0 )
+with expansion:
+ 7 &lt; 0
+Condition.tests.cpp:<line number>
+ </failure>
+ <failure message="CHECK(data.int_seven &lt; -1)">
+FAILED:
+ CHECK( data.int_seven &lt; -1 )
+with expansion:
+ 7 &lt; -1
+Condition.tests.cpp:<line number>
+ </failure>
+ <failure message="CHECK(data.int_seven >= 8)">
+FAILED:
+ CHECK( data.int_seven >= 8 )
+with expansion:
+ 7 >= 8
+Condition.tests.cpp:<line number>
+ </failure>
+ <failure message="CHECK(data.int_seven &lt;= 6)">
+FAILED:
+ CHECK( data.int_seven &lt;= 6 )
+with expansion:
+ 7 &lt;= 6
+Condition.tests.cpp:<line number>
+ </failure>
+ <failure message="CHECK(data.float_nine_point_one &lt; 9)">
+FAILED:
+ CHECK( data.float_nine_point_one &lt; 9 )
+with expansion:
+ 9.1f &lt; 9
+Condition.tests.cpp:<line number>
+ </failure>
+ <failure message="CHECK(data.float_nine_point_one > 10)">
+FAILED:
+ CHECK( data.float_nine_point_one > 10 )
+with expansion:
+ 9.1f > 10
+Condition.tests.cpp:<line number>
+ </failure>
+ <failure message="CHECK(data.float_nine_point_one > 9.2)">
+FAILED:
+ CHECK( data.float_nine_point_one > 9.2 )
+with expansion:
+ 9.1f > 9.2
+Condition.tests.cpp:<line number>
+ </failure>
+ <failure message="CHECK(data.str_hello > &quot;hello&quot;)">
+FAILED:
+ CHECK( data.str_hello > "hello" )
+with expansion:
+ "hello" > "hello"
+Condition.tests.cpp:<line number>
+ </failure>
+ <failure message="CHECK(data.str_hello &lt; &quot;hello&quot;)">
+FAILED:
+ CHECK( data.str_hello &lt; "hello" )
+with expansion:
+ "hello" &lt; "hello"
+Condition.tests.cpp:<line number>
+ </failure>
+ <failure message="CHECK(data.str_hello > &quot;hellp&quot;)">
+FAILED:
+ CHECK( data.str_hello > "hellp" )
+with expansion:
+ "hello" > "hellp"
+Condition.tests.cpp:<line number>
+ </failure>
+ <failure message="CHECK(data.str_hello > &quot;z&quot;)">
+FAILED:
+ CHECK( data.str_hello > "z" )
+with expansion:
+ "hello" > "z"
+Condition.tests.cpp:<line number>
+ </failure>
+ <failure message="CHECK(data.str_hello &lt; &quot;hellm&quot;)">
+FAILED:
+ CHECK( data.str_hello &lt; "hellm" )
+with expansion:
+ "hello" &lt; "hellm"
+Condition.tests.cpp:<line number>
+ </failure>
+ <failure message="CHECK(data.str_hello &lt; &quot;a&quot;)">
+FAILED:
+ CHECK( data.str_hello &lt; "a" )
+with expansion:
+ "hello" &lt; "a"
+Condition.tests.cpp:<line number>
+ </failure>
+ <failure message="CHECK(data.str_hello >= &quot;z&quot;)">
+FAILED:
+ CHECK( data.str_hello >= "z" )
+with expansion:
+ "hello" >= "z"
+Condition.tests.cpp:<line number>
+ </failure>
+ <failure message="CHECK(data.str_hello &lt;= &quot;a&quot;)">
+FAILED:
+ CHECK( data.str_hello &lt;= "a" )
+with expansion:
+ "hello" &lt;= "a"
+Condition.tests.cpp:<line number>
+ </failure>
+ </testCase>
+ <testCase name="Ordering comparison checks that should succeed" duration="{duration}"/>
+ <testCase name="Pointers can be compared to null" duration="{duration}"/>
+ <testCase name="comparisons between const int variables" duration="{duration}"/>
+ <testCase name="comparisons between int variables" duration="{duration}"/>
+ </file>
+ <file path="projects/<exe-name>/UsageTests/Decomposition.tests.cpp">
+ <testCase name="#1005: Comparing pointer to int and long (NULL can be either on various systems)" duration="{duration}"/>
+ <testCase name="Reconstruction should be based on stringification: #914" duration="{duration}">
+ <failure message="CHECK(truthy(false))">
+FAILED:
+ CHECK( truthy(false) )
+with expansion:
+ Hey, its truthy!
+Decomposition.tests.cpp:<line number>
+ </failure>
+ </testCase>
+ </file>
+ <file path="projects/<exe-name>/UsageTests/EnumToString.tests.cpp">
+ <testCase name="Enums can quickly have stringification enabled using REGISTER_ENUM" duration="{duration}"/>
+ <testCase name="Enums in namespaces can quickly have stringification enabled using REGISTER_ENUM" duration="{duration}"/>
+ <testCase name="toString(enum class w/operator&lt;&lt;)" duration="{duration}"/>
+ <testCase name="toString(enum class)" duration="{duration}"/>
+ <testCase name="toString(enum w/operator&lt;&lt;)" duration="{duration}"/>
+ <testCase name="toString(enum)" duration="{duration}"/>
+ </file>
+ <file path="projects/<exe-name>/UsageTests/Exception.tests.cpp">
+ <testCase name="#748 - captures with unexpected exceptions/outside assertions" duration="{duration}">
+ <skipped message="TEST_CASE()">
+FAILED:
+expected exception
+answer := 42
+Exception.tests.cpp:<line number>
+ </skipped>
+ </testCase>
+ <testCase name="#748 - captures with unexpected exceptions/inside REQUIRE_NOTHROW" duration="{duration}">
+ <skipped message="REQUIRE_NOTHROW(thisThrows())">
+FAILED:
+ REQUIRE_NOTHROW( thisThrows() )
+expected exception
+answer := 42
+Exception.tests.cpp:<line number>
+ </skipped>
+ </testCase>
+ <testCase name="#748 - captures with unexpected exceptions/inside REQUIRE_THROWS" duration="{duration}"/>
+ <testCase name="An unchecked exception reports the line of the last assertion" duration="{duration}">
+ <error message="({Unknown expression after the reported line})">
+FAILED:
+ {Unknown expression after the reported line}
+unexpected exception
+Exception.tests.cpp:<line number>
+ </error>
+ </testCase>
+ <testCase name="Custom exceptions can be translated when testing for nothrow" duration="{duration}">
+ <error message="REQUIRE_NOTHROW(throwCustom())">
+FAILED:
+ REQUIRE_NOTHROW( throwCustom() )
+custom exception - not std
+Exception.tests.cpp:<line number>
+ </error>
+ </testCase>
+ <testCase name="Custom exceptions can be translated when testing for throwing as something else" duration="{duration}">
+ <error message="REQUIRE_THROWS_AS(throwCustom(), std::exception)">
+FAILED:
+ REQUIRE_THROWS_AS( throwCustom(), std::exception )
+custom exception - not std
+Exception.tests.cpp:<line number>
+ </error>
+ </testCase>
+ <testCase name="Custom std-exceptions can be custom translated" duration="{duration}">
+ <error message="TEST_CASE()">
+FAILED:
+custom std exception
+Exception.tests.cpp:<line number>
+ </error>
+ </testCase>
+ <testCase name="Exception messages can be tested for/exact match" duration="{duration}"/>
+ <testCase name="Exception messages can be tested for/different case" duration="{duration}"/>
+ <testCase name="Exception messages can be tested for/wildcarded" duration="{duration}"/>
+ <testCase name="Expected exceptions that don't throw or unexpected exceptions fail the test" duration="{duration}">
+ <error message="CHECK_THROWS_AS(thisThrows(), std::string)">
+FAILED:
+ CHECK_THROWS_AS( thisThrows(), std::string )
+expected exception
+Exception.tests.cpp:<line number>
+ </error>
+ <failure message="CHECK_THROWS_AS(thisDoesntThrow(), std::domain_error)">
+FAILED:
+ CHECK_THROWS_AS( thisDoesntThrow(), std::domain_error )
+Exception.tests.cpp:<line number>
+ </failure>
+ <error message="CHECK_NOTHROW(thisThrows())">
+FAILED:
+ CHECK_NOTHROW( thisThrows() )
+expected exception
+Exception.tests.cpp:<line number>
+ </error>
+ </testCase>
+ <testCase name="Mismatching exception messages failing the test" duration="{duration}">
+ <failure message="REQUIRE_THROWS_WITH(thisThrows(), &quot;should fail&quot;)">
+FAILED:
+ REQUIRE_THROWS_WITH( thisThrows(), "should fail" )
+with expansion:
+ "expected exception" equals: "should fail"
+Exception.tests.cpp:<line number>
+ </failure>
+ </testCase>
+ <testCase name="Non-std exceptions can be translated" duration="{duration}">
+ <error message="TEST_CASE()">
+FAILED:
+custom exception
+Exception.tests.cpp:<line number>
+ </error>
+ </testCase>
+ <testCase name="Thrown string literals are translated" duration="{duration}">
+ <error message="TEST_CASE()">
+FAILED:
+For some reason someone is throwing a string literal!
+Exception.tests.cpp:<line number>
+ </error>
+ </testCase>
+ <testCase name="Unexpected exceptions can be translated" duration="{duration}">
+ <error message="TEST_CASE()">
+FAILED:
+3.14
+Exception.tests.cpp:<line number>
+ </error>
+ </testCase>
+ <testCase name="When checked exceptions are thrown they can be expected or unexpected" duration="{duration}"/>
+ <testCase name="When unchecked exceptions are thrown directly they are always failures" duration="{duration}">
+ <error message="TEST_CASE()">
+FAILED:
+unexpected exception
+Exception.tests.cpp:<line number>
+ </error>
+ </testCase>
+ <testCase name="When unchecked exceptions are thrown during a CHECK the test should continue" duration="{duration}">
+ <error message="CHECK(thisThrows() == 0)">
+FAILED:
+ CHECK( thisThrows() == 0 )
+expected exception
+Exception.tests.cpp:<line number>
+ </error>
+ </testCase>
+ <testCase name="When unchecked exceptions are thrown during a REQUIRE the test should abort fail" duration="{duration}">
+ <error message="REQUIRE(thisThrows() == 0)">
+FAILED:
+ REQUIRE( thisThrows() == 0 )
+expected exception
+Exception.tests.cpp:<line number>
+ </error>
+ </testCase>
+ <testCase name="When unchecked exceptions are thrown from functions they are always failures" duration="{duration}">
+ <error message="CHECK(thisThrows() == 0)">
+FAILED:
+ CHECK( thisThrows() == 0 )
+expected exception
+Exception.tests.cpp:<line number>
+ </error>
+ </testCase>
+ <testCase name="When unchecked exceptions are thrown from sections they are always failures/section name" duration="{duration}">
+ <error message="TEST_CASE()">
+FAILED:
+unexpected exception
+Exception.tests.cpp:<line number>
+ </error>
+ </testCase>
+ <testCase name="thrown std::strings are translated" duration="{duration}">
+ <error message="TEST_CASE()">
+FAILED:
+Why would you throw a std::string?
+Exception.tests.cpp:<line number>
+ </error>
+ </testCase>
+ </file>
+ <file path="projects/<exe-name>/UsageTests/Generators.tests.cpp">
+ <testCase name="3x3x3 ints" duration="{duration}"/>
+ <testCase name="Copy and then generate a range/from var and iterators" duration="{duration}"/>
+ <testCase name="Copy and then generate a range/From a temporary container" duration="{duration}"/>
+ <testCase name="Copy and then generate a range/Final validation" duration="{duration}"/>
+ <testCase name="Generators -- adapters/Filtering by predicate/Basic usage" duration="{duration}"/>
+ <testCase name="Generators -- adapters/Filtering by predicate/Throws if there are no matching values" duration="{duration}"/>
+ <testCase name="Generators -- adapters/Shortening a range" duration="{duration}"/>
+ <testCase name="Generators -- adapters/Transforming elements/Same type" duration="{duration}"/>
+ <testCase name="Generators -- adapters/Transforming elements/Different type" duration="{duration}"/>
+ <testCase name="Generators -- adapters/Transforming elements/Different deduced type" duration="{duration}"/>
+ <testCase name="Generators -- adapters/Repeating a generator" duration="{duration}"/>
+ <testCase name="Generators -- adapters/Chunking a generator into sized pieces/Number of elements in source is divisible by chunk size" duration="{duration}"/>
+ <testCase name="Generators -- adapters/Chunking a generator into sized pieces/Number of elements in source is not divisible by chunk size" duration="{duration}"/>
+ <testCase name="Generators -- adapters/Chunking a generator into sized pieces/Chunk size of zero" duration="{duration}"/>
+ <testCase name="Generators -- adapters/Chunking a generator into sized pieces/Throws on too small generators" duration="{duration}"/>
+ <testCase name="Generators -- simple/one" duration="{duration}"/>
+ <testCase name="Generators -- simple/two" duration="{duration}"/>
+ <testCase name="Nested generators and captured variables" duration="{duration}"/>
+ <testCase name="strlen3" duration="{duration}"/>
+ <testCase name="tables" duration="{duration}"/>
+ </file>
+ <file path="projects/<exe-name>/UsageTests/Matchers.tests.cpp">
+ <testCase name="Arbitrary predicate matcher/Function pointer" duration="{duration}"/>
+ <testCase name="Arbitrary predicate matcher/Lambdas + different type" duration="{duration}"/>
+ <testCase name="Composed matchers are distinct" duration="{duration}"/>
+ <testCase name="Contains string matcher" duration="{duration}">
+ <failure message="CHECK_THAT(testStringForMatching(), Contains(&quot;not there&quot;, Catch::CaseSensitive::No))">
+FAILED:
+ CHECK_THAT( testStringForMatching(), Contains("not there", Catch::CaseSensitive::No) )
+with expansion:
+ "this string contains 'abc' as a substring" contains: "not there" (case insensitive)
+Matchers.tests.cpp:<line number>
+ </failure>
+ <failure message="CHECK_THAT(testStringForMatching(), Contains(&quot;STRING&quot;))">
+FAILED:
+ CHECK_THAT( testStringForMatching(), Contains("STRING") )
+with expansion:
+ "this string contains 'abc' as a substring" contains: "STRING"
+Matchers.tests.cpp:<line number>
+ </failure>
+ </testCase>
+ <testCase name="EndsWith string matcher" duration="{duration}">
+ <failure message="CHECK_THAT(testStringForMatching(), EndsWith(&quot;Substring&quot;))">
+FAILED:
+ CHECK_THAT( testStringForMatching(), EndsWith("Substring") )
+with expansion:
+ "this string contains 'abc' as a substring" ends with: "Substring"
+Matchers.tests.cpp:<line number>
+ </failure>
+ <failure message="CHECK_THAT(testStringForMatching(), EndsWith(&quot;this&quot;, Catch::CaseSensitive::No))">
+FAILED:
+ CHECK_THAT( testStringForMatching(), EndsWith("this", Catch::CaseSensitive::No) )
+with expansion:
+ "this string contains 'abc' as a substring" ends with: "this" (case insensitive)
+Matchers.tests.cpp:<line number>
+ </failure>
+ </testCase>
+ <testCase name="Equals" duration="{duration}"/>
+ <testCase name="Equals string matcher" duration="{duration}">
+ <failure message="CHECK_THAT(testStringForMatching(), Equals(&quot;this string contains 'ABC' as a substring&quot;))">
+FAILED:
+ CHECK_THAT( testStringForMatching(), Equals("this string contains 'ABC' as a substring") )
+with expansion:
+ "this string contains 'abc' as a substring" equals: "this string contains 'ABC' as a substring"
+Matchers.tests.cpp:<line number>
+ </failure>
+ <failure message="CHECK_THAT(testStringForMatching(), Equals(&quot;something else&quot;, Catch::CaseSensitive::No))">
+FAILED:
+ CHECK_THAT( testStringForMatching(), Equals("something else", Catch::CaseSensitive::No) )
+with expansion:
+ "this string contains 'abc' as a substring" equals: "something else" (case insensitive)
+Matchers.tests.cpp:<line number>
+ </failure>
+ </testCase>
+ <testCase name="Exception matchers that fail/No exception" duration="{duration}">
+ <failure message="CHECK_THROWS_MATCHES(doesNotThrow(), SpecialException, ExceptionMatcher{1})">
+FAILED:
+ CHECK_THROWS_MATCHES( doesNotThrow(), SpecialException, ExceptionMatcher{1} )
+Matchers.tests.cpp:<line number>
+ </failure>
+ <failure message="REQUIRE_THROWS_MATCHES(doesNotThrow(), SpecialException, ExceptionMatcher{1})">
+FAILED:
+ REQUIRE_THROWS_MATCHES( doesNotThrow(), SpecialException, ExceptionMatcher{1} )
+Matchers.tests.cpp:<line number>
+ </failure>
+ </testCase>
+ <testCase name="Exception matchers that fail/Type mismatch" duration="{duration}">
+ <error message="CHECK_THROWS_MATCHES(throwsAsInt(1), SpecialException, ExceptionMatcher{1})">
+FAILED:
+ CHECK_THROWS_MATCHES( throwsAsInt(1), SpecialException, ExceptionMatcher{1} )
+Unknown exception
+Matchers.tests.cpp:<line number>
+ </error>
+ <error message="REQUIRE_THROWS_MATCHES(throwsAsInt(1), SpecialException, ExceptionMatcher{1})">
+FAILED:
+ REQUIRE_THROWS_MATCHES( throwsAsInt(1), SpecialException, ExceptionMatcher{1} )
+Unknown exception
+Matchers.tests.cpp:<line number>
+ </error>
+ </testCase>
+ <testCase name="Exception matchers that fail/Contents are wrong" duration="{duration}">
+ <failure message="CHECK_THROWS_MATCHES(throwsSpecialException(3), SpecialException, ExceptionMatcher{1})">
+FAILED:
+ CHECK_THROWS_MATCHES( throwsSpecialException(3), SpecialException, ExceptionMatcher{1} )
+with expansion:
+ SpecialException::what special exception has value of 1
+Matchers.tests.cpp:<line number>
+ </failure>
+ <failure message="REQUIRE_THROWS_MATCHES(throwsSpecialException(4), SpecialException, ExceptionMatcher{1})">
+FAILED:
+ REQUIRE_THROWS_MATCHES( throwsSpecialException(4), SpecialException, ExceptionMatcher{1} )
+with expansion:
+ SpecialException::what special exception has value of 1
+Matchers.tests.cpp:<line number>
+ </failure>
+ </testCase>
+ <testCase name="Exception matchers that succeed" duration="{duration}"/>
+ <testCase name="Exceptions matchers" duration="{duration}"/>
+ <testCase name="Floating point matchers: double/Relative" duration="{duration}"/>
+ <testCase name="Floating point matchers: double/Relative/Some subnormal values" duration="{duration}"/>
+ <testCase name="Floating point matchers: double/Margin" duration="{duration}"/>
+ <testCase name="Floating point matchers: double/ULPs" duration="{duration}"/>
+ <testCase name="Floating point matchers: double/Composed" duration="{duration}"/>
+ <testCase name="Floating point matchers: double/Constructor validation" duration="{duration}"/>
+ <testCase name="Floating point matchers: float/Relative" duration="{duration}"/>
+ <testCase name="Floating point matchers: float/Relative/Some subnormal values" duration="{duration}"/>
+ <testCase name="Floating point matchers: float/Margin" duration="{duration}"/>
+ <testCase name="Floating point matchers: float/ULPs" duration="{duration}"/>
+ <testCase name="Floating point matchers: float/Composed" duration="{duration}"/>
+ <testCase name="Floating point matchers: float/Constructor validation" duration="{duration}"/>
+ <testCase name="Matchers can be (AllOf) composed with the &amp;&amp; operator" duration="{duration}"/>
+ <testCase name="Matchers can be (AnyOf) composed with the || operator" duration="{duration}"/>
+ <testCase name="Matchers can be composed with both &amp;&amp; and ||" duration="{duration}"/>
+ <testCase name="Matchers can be composed with both &amp;&amp; and || - failing" duration="{duration}">
+ <failure message="CHECK_THAT(testStringForMatching(), (Contains(&quot;string&quot;) || Contains(&quot;different&quot;)) &amp;&amp; Contains(&quot;random&quot;))">
+FAILED:
+ CHECK_THAT( testStringForMatching(), (Contains("string") || Contains("different")) &amp;&amp; Contains("random") )
+with expansion:
+ "this string contains 'abc' as a substring" ( ( contains: "string" or contains: "different" ) and contains: "random" )
+Matchers.tests.cpp:<line number>
+ </failure>
+ </testCase>
+ <testCase name="Matchers can be negated (Not) with the ! operator" duration="{duration}"/>
+ <testCase name="Matchers can be negated (Not) with the ! operator - failing" duration="{duration}">
+ <failure message="CHECK_THAT(testStringForMatching(), !Contains(&quot;substring&quot;))">
+FAILED:
+ CHECK_THAT( testStringForMatching(), !Contains("substring") )
+with expansion:
+ "this string contains 'abc' as a substring" not contains: "substring"
+Matchers.tests.cpp:<line number>
+ </failure>
+ </testCase>
+ <testCase name="Predicate matcher can accept const char*" duration="{duration}"/>
+ <testCase name="Regex string matcher" duration="{duration}">
+ <failure message="CHECK_THAT(testStringForMatching(), Matches(&quot;this STRING contains 'abc' as a substring&quot;))">
+FAILED:
+ CHECK_THAT( testStringForMatching(), Matches("this STRING contains 'abc' as a substring") )
+with expansion:
+ "this string contains 'abc' as a substring" matches "this STRING contains 'abc' as a substring" case sensitively
+Matchers.tests.cpp:<line number>
+ </failure>
+ <failure message="CHECK_THAT(testStringForMatching(), Matches(&quot;contains 'abc' as a substring&quot;))">
+FAILED:
+ CHECK_THAT( testStringForMatching(), Matches("contains 'abc' as a substring") )
+with expansion:
+ "this string contains 'abc' as a substring" matches "contains 'abc' as a substring" case sensitively
+Matchers.tests.cpp:<line number>
+ </failure>
+ <failure message="CHECK_THAT(testStringForMatching(), Matches(&quot;this string contains 'abc' as a&quot;))">
+FAILED:
+ CHECK_THAT( testStringForMatching(), Matches("this string contains 'abc' as a") )
+with expansion:
+ "this string contains 'abc' as a substring" matches "this string contains 'abc' as a" case sensitively
+Matchers.tests.cpp:<line number>
+ </failure>
+ </testCase>
+ <testCase name="Regression test #1" duration="{duration}"/>
+ <testCase name="StartsWith string matcher" duration="{duration}">
+ <failure message="CHECK_THAT(testStringForMatching(), StartsWith(&quot;This String&quot;))">
+FAILED:
+ CHECK_THAT( testStringForMatching(), StartsWith("This String") )
+with expansion:
+ "this string contains 'abc' as a substring" starts with: "This String"
+Matchers.tests.cpp:<line number>
+ </failure>
+ <failure message="CHECK_THAT(testStringForMatching(), StartsWith(&quot;string&quot;, Catch::CaseSensitive::No))">
+FAILED:
+ CHECK_THAT( testStringForMatching(), StartsWith("string", Catch::CaseSensitive::No) )
+with expansion:
+ "this string contains 'abc' as a substring" starts with: "string" (case insensitive)
+Matchers.tests.cpp:<line number>
+ </failure>
+ </testCase>
+ <testCase name="String matchers" duration="{duration}"/>
+ <testCase name="Vector Approx matcher/Empty vector is roughly equal to an empty vector" duration="{duration}"/>
+ <testCase name="Vector Approx matcher/Vectors with elements/A vector is approx equal to itself" duration="{duration}"/>
+ <testCase name="Vector Approx matcher/Vectors with elements/Different length" duration="{duration}"/>
+ <testCase name="Vector Approx matcher/Vectors with elements/Same length, different elements" duration="{duration}"/>
+ <testCase name="Vector Approx matcher -- failing/Empty and non empty vectors are not approx equal" duration="{duration}">
+ <failure message="CHECK_THAT(empty, Approx(t1))">
+FAILED:
+ CHECK_THAT( empty, Approx(t1) )
+with expansion:
+ { } is approx: { 1.0, 2.0 }
+Matchers.tests.cpp:<line number>
+ </failure>
+ </testCase>
+ <testCase name="Vector Approx matcher -- failing/Just different vectors" duration="{duration}">
+ <failure message="CHECK_THAT(v1, Approx(v2))">
+FAILED:
+ CHECK_THAT( v1, Approx(v2) )
+with expansion:
+ { 2.0, 4.0, 6.0 } is approx: { 1.0, 3.0, 5.0 }
+Matchers.tests.cpp:<line number>
+ </failure>
+ </testCase>
+ <testCase name="Vector matchers/Contains (element)" duration="{duration}"/>
+ <testCase name="Vector matchers/Contains (vector)" duration="{duration}"/>
+ <testCase name="Vector matchers/Contains (element), composed" duration="{duration}"/>
+ <testCase name="Vector matchers/Equals" duration="{duration}"/>
+ <testCase name="Vector matchers/UnorderedEquals" duration="{duration}"/>
+ <testCase name="Vector matchers that fail/Contains (element)" duration="{duration}">
+ <failure message="CHECK_THAT(v, VectorContains(-1))">
+FAILED:
+ CHECK_THAT( v, VectorContains(-1) )
+with expansion:
+ { 1, 2, 3 } Contains: -1
+Matchers.tests.cpp:<line number>
+ </failure>
+ <failure message="CHECK_THAT(empty, VectorContains(1))">
+FAILED:
+ CHECK_THAT( empty, VectorContains(1) )
+with expansion:
+ { } Contains: 1
+Matchers.tests.cpp:<line number>
+ </failure>
+ </testCase>
+ <testCase name="Vector matchers that fail/Contains (vector)" duration="{duration}">
+ <failure message="CHECK_THAT(empty, Contains(v))">
+FAILED:
+ CHECK_THAT( empty, Contains(v) )
+with expansion:
+ { } Contains: { 1, 2, 3 }
+Matchers.tests.cpp:<line number>
+ </failure>
+ <failure message="CHECK_THAT(v, Contains(v2))">
+FAILED:
+ CHECK_THAT( v, Contains(v2) )
+with expansion:
+ { 1, 2, 3 } Contains: { 1, 2, 4 }
+Matchers.tests.cpp:<line number>
+ </failure>
+ </testCase>
+ <testCase name="Vector matchers that fail/Equals" duration="{duration}">
+ <failure message="CHECK_THAT(v, Equals(v2))">
+FAILED:
+ CHECK_THAT( v, Equals(v2) )
+with expansion:
+ { 1, 2, 3 } Equals: { 1, 2 }
+Matchers.tests.cpp:<line number>
+ </failure>
+ <failure message="CHECK_THAT(v2, Equals(v))">
+FAILED:
+ CHECK_THAT( v2, Equals(v) )
+with expansion:
+ { 1, 2 } Equals: { 1, 2, 3 }
+Matchers.tests.cpp:<line number>
+ </failure>
+ <failure message="CHECK_THAT(empty, Equals(v))">
+FAILED:
+ CHECK_THAT( empty, Equals(v) )
+with expansion:
+ { } Equals: { 1, 2, 3 }
+Matchers.tests.cpp:<line number>
+ </failure>
+ <failure message="CHECK_THAT(v, Equals(empty))">
+FAILED:
+ CHECK_THAT( v, Equals(empty) )
+with expansion:
+ { 1, 2, 3 } Equals: { }
+Matchers.tests.cpp:<line number>
+ </failure>
+ </testCase>
+ <testCase name="Vector matchers that fail/UnorderedEquals" duration="{duration}">
+ <failure message="CHECK_THAT(v, UnorderedEquals(empty))">
+FAILED:
+ CHECK_THAT( v, UnorderedEquals(empty) )
+with expansion:
+ { 1, 2, 3 } UnorderedEquals: { }
+Matchers.tests.cpp:<line number>
+ </failure>
+ <failure message="CHECK_THAT(empty, UnorderedEquals(v))">
+FAILED:
+ CHECK_THAT( empty, UnorderedEquals(v) )
+with expansion:
+ { } UnorderedEquals: { 1, 2, 3 }
+Matchers.tests.cpp:<line number>
+ </failure>
+ <failure message="CHECK_THAT(permuted, UnorderedEquals(v))">
+FAILED:
+ CHECK_THAT( permuted, UnorderedEquals(v) )
+with expansion:
+ { 1, 3 } UnorderedEquals: { 1, 2, 3 }
+Matchers.tests.cpp:<line number>
+ </failure>
+ <failure message="CHECK_THAT(permuted, UnorderedEquals(v))">
+FAILED:
+ CHECK_THAT( permuted, UnorderedEquals(v) )
+with expansion:
+ { 3, 1 } UnorderedEquals: { 1, 2, 3 }
+Matchers.tests.cpp:<line number>
+ </failure>
+ </testCase>
+ </file>
+ <file path="projects/<exe-name>/UsageTests/Message.tests.cpp">
+ <testCase name="#1455 - INFO and WARN can start with a linebreak" duration="{duration}"/>
+ <testCase name="CAPTURE can deal with complex expressions" duration="{duration}"/>
+ <testCase name="CAPTURE can deal with complex expressions involving commas" duration="{duration}"/>
+ <testCase name="CAPTURE parses string and character constants" duration="{duration}"/>
+ <testCase name="FAIL aborts the test" duration="{duration}">
+ <failure message="FAIL()">
+FAILED:
+This is a failure
+Message.tests.cpp:<line number>
+ </failure>
+ </testCase>
+ <testCase name="FAIL does not require an argument" duration="{duration}">
+ <failure message="FAIL()">
+FAILED:
+Message.tests.cpp:<line number>
+ </failure>
+ </testCase>
+ <testCase name="FAIL_CHECK does not abort the test" duration="{duration}">
+ <failure message="FAIL_CHECK()">
+FAILED:
+This is a failure
+Message.tests.cpp:<line number>
+ </failure>
+ </testCase>
+ <testCase name="INFO and WARN do not abort tests" duration="{duration}"/>
+ <testCase name="INFO gets logged on failure" duration="{duration}">
+ <failure message="REQUIRE(a == 1)">
+FAILED:
+ REQUIRE( a == 1 )
+with expansion:
+ 2 == 1
+this message should be logged
+so should this
+Message.tests.cpp:<line number>
+ </failure>
+ </testCase>
+ <testCase name="INFO gets logged on failure, even if captured before successful assertions" duration="{duration}">
+ <failure message="CHECK(a == 1)">
+FAILED:
+ CHECK( a == 1 )
+with expansion:
+ 2 == 1
+this message may be logged later
+this message should be logged
+Message.tests.cpp:<line number>
+ </failure>
+ <failure message="CHECK(a == 0)">
+FAILED:
+ CHECK( a == 0 )
+with expansion:
+ 2 == 0
+this message may be logged later
+this message should be logged
+and this, but later
+Message.tests.cpp:<line number>
+ </failure>
+ </testCase>
+ <testCase name="INFO is reset for each loop" duration="{duration}">
+ <failure message="REQUIRE(i &lt; 10)">
+FAILED:
+ REQUIRE( i &lt; 10 )
+with expansion:
+ 10 &lt; 10
+current counter 10
+i := 10
+Message.tests.cpp:<line number>
+ </failure>
+ </testCase>
+ <testCase name="Output from all sections is reported/one" duration="{duration}">
+ <failure message="FAIL()">
+FAILED:
+Message from section one
+Message.tests.cpp:<line number>
+ </failure>
+ </testCase>
+ <testCase name="Output from all sections is reported/two" duration="{duration}">
+ <failure message="FAIL()">
+FAILED:
+Message from section two
+Message.tests.cpp:<line number>
+ </failure>
+ </testCase>
+ <testCase name="SUCCEED counts as a test pass" duration="{duration}"/>
+ <testCase name="SUCCEED does not require an argument" duration="{duration}"/>
+ <testCase name="Standard output from all sections is reported/two" duration="{duration}"/>
+ <testCase name="The NO_FAIL macro reports a failure but does not fail the test" duration="{duration}"/>
+ <testCase name="just failure" duration="{duration}">
+ <failure message="FAIL()">
+FAILED:
+Previous info should not be seen
+Message.tests.cpp:<line number>
+ </failure>
+ </testCase>
+ <testCase name="just failure after unscoped info" duration="{duration}">
+ <failure message="FAIL()">
+FAILED:
+previous unscoped info SHOULD not be seen
+Message.tests.cpp:<line number>
+ </failure>
+ </testCase>
+ <testCase name="mix info, unscoped info and warning" duration="{duration}"/>
+ <testCase name="not prints unscoped info from previous failures" duration="{duration}">
+ <failure message="REQUIRE(false)">
+FAILED:
+ REQUIRE( false )
+this SHOULD be seen
+Message.tests.cpp:<line number>
+ </failure>
+ </testCase>
+ <testCase name="print unscoped info if passing unscoped info is printed" duration="{duration}"/>
+ <testCase name="prints unscoped info on failure" duration="{duration}">
+ <failure message="REQUIRE(false)">
+FAILED:
+ REQUIRE( false )
+this SHOULD be seen
+this SHOULD also be seen
+Message.tests.cpp:<line number>
+ </failure>
+ </testCase>
+ <testCase name="prints unscoped info only for the first assertion" duration="{duration}">
+ <failure message="CHECK(false)">
+FAILED:
+ CHECK( false )
+this SHOULD be seen only ONCE
+Message.tests.cpp:<line number>
+ </failure>
+ </testCase>
+ <testCase name="sends information to INFO" duration="{duration}">
+ <failure message="REQUIRE(false)">
+FAILED:
+ REQUIRE( false )
+hi
+i := 7
+Message.tests.cpp:<line number>
+ </failure>
+ </testCase>
+ <testCase name="stacks unscoped info in loops" duration="{duration}">
+ <failure message="CHECK(false)">
+FAILED:
+ CHECK( false )
+Count 1 to 3...
+1
+2
+3
+Message.tests.cpp:<line number>
+ </failure>
+ <failure message="CHECK(false)">
+FAILED:
+ CHECK( false )
+Count 4 to 6...
+4
+5
+6
+Message.tests.cpp:<line number>
+ </failure>
+ </testCase>
+ </file>
+ <file path="projects/<exe-name>/UsageTests/Misc.tests.cpp">
+ <testCase name="# A test name that starts with a #" duration="{duration}"/>
+ <testCase name="#1175 - Hidden Test" duration="{duration}"/>
+ <testCase name="#835 -- errno should not be touched by Catch" duration="{duration}">
+ <skipped message="CHECK(f() == 0)">
+FAILED:
+ CHECK( f() == 0 )
+with expansion:
+ 1 == 0
+Misc.tests.cpp:<line number>
+ </skipped>
+ </testCase>
+ <testCase name="#961 -- Dynamically created sections should all be reported/Looped section 0" duration="{duration}"/>
+ <testCase name="#961 -- Dynamically created sections should all be reported/Looped section 1" duration="{duration}"/>
+ <testCase name="#961 -- Dynamically created sections should all be reported/Looped section 2" duration="{duration}"/>
+ <testCase name="#961 -- Dynamically created sections should all be reported/Looped section 3" duration="{duration}"/>
+ <testCase name="#961 -- Dynamically created sections should all be reported/Looped section 4" duration="{duration}"/>
+ <testCase name="A Template product test case - Foo&lt;float>" duration="{duration}"/>
+ <testCase name="A Template product test case - Foo&lt;int>" duration="{duration}"/>
+ <testCase name="A Template product test case - std::vector&lt;float>" duration="{duration}"/>
+ <testCase name="A Template product test case - std::vector&lt;int>" duration="{duration}"/>
+ <testCase name="A Template product test case with array signature - Bar&lt;float, 42>" duration="{duration}"/>
+ <testCase name="A Template product test case with array signature - Bar&lt;int, 9>" duration="{duration}"/>
+ <testCase name="A Template product test case with array signature - std::array&lt;float, 42>" duration="{duration}"/>
+ <testCase name="A Template product test case with array signature - std::array&lt;int, 9>" duration="{duration}"/>
+ <testCase name="A couple of nested sections followed by a failure" duration="{duration}">
+ <failure message="FAIL()">
+FAILED:
+to infinity and beyond
+Misc.tests.cpp:<line number>
+ </failure>
+ </testCase>
+ <testCase name="A couple of nested sections followed by a failure/Outer/Inner" duration="{duration}"/>
+ <testCase name="Factorials are computed" duration="{duration}"/>
+ <testCase name="ManuallyRegistered" duration="{duration}"/>
+ <testCase name="Nice descriptive name" duration="{duration}"/>
+ <testCase name="Product with differing arities - std::tuple&lt;int, double, float>" duration="{duration}"/>
+ <testCase name="Product with differing arities - std::tuple&lt;int, double>" duration="{duration}"/>
+ <testCase name="Product with differing arities - std::tuple&lt;int>" duration="{duration}"/>
+ <testCase name="Sends stuff to stdout and stderr" duration="{duration}"/>
+ <testCase name="Tabs and newlines show in output" duration="{duration}">
+ <failure message="CHECK(s1 == s2)">
+FAILED:
+ CHECK( s1 == s2 )
+with expansion:
+ "if ($b == 10) {
+ $a = 20;
+}"
+==
+"if ($b == 10) {
+ $a = 20;
+}
+"
+Misc.tests.cpp:<line number>
+ </failure>
+ </testCase>
+ <testCase name="Template test case with test types specified inside non-copyable and non-movable std::tuple - NonCopyableAndNonMovableTypes - 0" duration="{duration}"/>
+ <testCase name="Template test case with test types specified inside non-copyable and non-movable std::tuple - NonCopyableAndNonMovableTypes - 1" duration="{duration}"/>
+ <testCase name="Template test case with test types specified inside non-default-constructible std::tuple - MyNonDefaultConstructibleTypes - 0" duration="{duration}"/>
+ <testCase name="Template test case with test types specified inside non-default-constructible std::tuple - MyNonDefaultConstructibleTypes - 1" duration="{duration}"/>
+ <testCase name="Template test case with test types specified inside std::tuple - MyTypes - 0" duration="{duration}"/>
+ <testCase name="Template test case with test types specified inside std::tuple - MyTypes - 1" duration="{duration}"/>
+ <testCase name="Template test case with test types specified inside std::tuple - MyTypes - 2" duration="{duration}"/>
+ <testCase name="TemplateTest: vectors can be sized and resized - float" duration="{duration}"/>
+ <testCase name="TemplateTest: vectors can be sized and resized - float/resizing bigger changes size and capacity" duration="{duration}"/>
+ <testCase name="TemplateTest: vectors can be sized and resized - float/resizing smaller changes size but not capacity" duration="{duration}"/>
+ <testCase name="TemplateTest: vectors can be sized and resized - float/resizing smaller changes size but not capacity/We can use the 'swap trick' to reset the capacity" duration="{duration}"/>
+ <testCase name="TemplateTest: vectors can be sized and resized - float/reserving bigger changes capacity but not size" duration="{duration}"/>
+ <testCase name="TemplateTest: vectors can be sized and resized - float/reserving smaller does not change size or capacity" duration="{duration}"/>
+ <testCase name="TemplateTest: vectors can be sized and resized - int" duration="{duration}"/>
+ <testCase name="TemplateTest: vectors can be sized and resized - int/resizing bigger changes size and capacity" duration="{duration}"/>
+ <testCase name="TemplateTest: vectors can be sized and resized - int/resizing smaller changes size but not capacity" duration="{duration}"/>
+ <testCase name="TemplateTest: vectors can be sized and resized - int/resizing smaller changes size but not capacity/We can use the 'swap trick' to reset the capacity" duration="{duration}"/>
+ <testCase name="TemplateTest: vectors can be sized and resized - int/reserving bigger changes capacity but not size" duration="{duration}"/>
+ <testCase name="TemplateTest: vectors can be sized and resized - int/reserving smaller does not change size or capacity" duration="{duration}"/>
+ <testCase name="TemplateTest: vectors can be sized and resized - std::string" duration="{duration}"/>
+ <testCase name="TemplateTest: vectors can be sized and resized - std::string/resizing bigger changes size and capacity" duration="{duration}"/>
+ <testCase name="TemplateTest: vectors can be sized and resized - std::string/resizing smaller changes size but not capacity" duration="{duration}"/>
+ <testCase name="TemplateTest: vectors can be sized and resized - std::string/resizing smaller changes size but not capacity/We can use the 'swap trick' to reset the capacity" duration="{duration}"/>
+ <testCase name="TemplateTest: vectors can be sized and resized - std::string/reserving bigger changes capacity but not size" duration="{duration}"/>
+ <testCase name="TemplateTest: vectors can be sized and resized - std::string/reserving smaller does not change size or capacity" duration="{duration}"/>
+ <testCase name="TemplateTest: vectors can be sized and resized - std::tuple&lt;int,float>" duration="{duration}"/>
+ <testCase name="TemplateTest: vectors can be sized and resized - std::tuple&lt;int,float>/resizing bigger changes size and capacity" duration="{duration}"/>
+ <testCase name="TemplateTest: vectors can be sized and resized - std::tuple&lt;int,float>/resizing smaller changes size but not capacity" duration="{duration}"/>
+ <testCase name="TemplateTest: vectors can be sized and resized - std::tuple&lt;int,float>/resizing smaller changes size but not capacity/We can use the 'swap trick' to reset the capacity" duration="{duration}"/>
+ <testCase name="TemplateTest: vectors can be sized and resized - std::tuple&lt;int,float>/reserving bigger changes capacity but not size" duration="{duration}"/>
+ <testCase name="TemplateTest: vectors can be sized and resized - std::tuple&lt;int,float>/reserving smaller does not change size or capacity" duration="{duration}"/>
+ <testCase name="TemplateTestSig: vectors can be sized and resized - (std::tuple&lt;int, float>), 6" duration="{duration}"/>
+ <testCase name="TemplateTestSig: vectors can be sized and resized - (std::tuple&lt;int, float>), 6/resizing bigger changes size and capacity" duration="{duration}"/>
+ <testCase name="TemplateTestSig: vectors can be sized and resized - (std::tuple&lt;int, float>), 6/resizing smaller changes size but not capacity" duration="{duration}"/>
+ <testCase name="TemplateTestSig: vectors can be sized and resized - (std::tuple&lt;int, float>), 6/resizing smaller changes size but not capacity/We can use the 'swap trick' to reset the capacity" duration="{duration}"/>
+ <testCase name="TemplateTestSig: vectors can be sized and resized - (std::tuple&lt;int, float>), 6/reserving bigger changes capacity but not size" duration="{duration}"/>
+ <testCase name="TemplateTestSig: vectors can be sized and resized - (std::tuple&lt;int, float>), 6/reserving smaller does not change size or capacity" duration="{duration}"/>
+ <testCase name="TemplateTestSig: vectors can be sized and resized - float,4" duration="{duration}"/>
+ <testCase name="TemplateTestSig: vectors can be sized and resized - float,4/resizing bigger changes size and capacity" duration="{duration}"/>
+ <testCase name="TemplateTestSig: vectors can be sized and resized - float,4/resizing smaller changes size but not capacity" duration="{duration}"/>
+ <testCase name="TemplateTestSig: vectors can be sized and resized - float,4/resizing smaller changes size but not capacity/We can use the 'swap trick' to reset the capacity" duration="{duration}"/>
+ <testCase name="TemplateTestSig: vectors can be sized and resized - float,4/reserving bigger changes capacity but not size" duration="{duration}"/>
+ <testCase name="TemplateTestSig: vectors can be sized and resized - float,4/reserving smaller does not change size or capacity" duration="{duration}"/>
+ <testCase name="TemplateTestSig: vectors can be sized and resized - int,5" duration="{duration}"/>
+ <testCase name="TemplateTestSig: vectors can be sized and resized - int,5/resizing bigger changes size and capacity" duration="{duration}"/>
+ <testCase name="TemplateTestSig: vectors can be sized and resized - int,5/resizing smaller changes size but not capacity" duration="{duration}"/>
+ <testCase name="TemplateTestSig: vectors can be sized and resized - int,5/resizing smaller changes size but not capacity/We can use the 'swap trick' to reset the capacity" duration="{duration}"/>
+ <testCase name="TemplateTestSig: vectors can be sized and resized - int,5/reserving bigger changes capacity but not size" duration="{duration}"/>
+ <testCase name="TemplateTestSig: vectors can be sized and resized - int,5/reserving smaller does not change size or capacity" duration="{duration}"/>
+ <testCase name="TemplateTestSig: vectors can be sized and resized - std::string,15" duration="{duration}"/>
+ <testCase name="TemplateTestSig: vectors can be sized and resized - std::string,15/resizing bigger changes size and capacity" duration="{duration}"/>
+ <testCase name="TemplateTestSig: vectors can be sized and resized - std::string,15/resizing smaller changes size but not capacity" duration="{duration}"/>
+ <testCase name="TemplateTestSig: vectors can be sized and resized - std::string,15/resizing smaller changes size but not capacity/We can use the 'swap trick' to reset the capacity" duration="{duration}"/>
+ <testCase name="TemplateTestSig: vectors can be sized and resized - std::string,15/reserving bigger changes capacity but not size" duration="{duration}"/>
+ <testCase name="TemplateTestSig: vectors can be sized and resized - std::string,15/reserving smaller does not change size or capacity" duration="{duration}"/>
+ <testCase name="This test 'should' fail but doesn't" duration="{duration}"/>
+ <testCase name="atomic if" duration="{duration}"/>
+ <testCase name="checkedElse" duration="{duration}"/>
+ <testCase name="checkedElse, failing" duration="{duration}">
+ <failure message="CHECKED_ELSE(flag)">
+FAILED:
+ CHECKED_ELSE( flag )
+with expansion:
+ false
+Misc.tests.cpp:<line number>
+ </failure>
+ <failure message="REQUIRE(testCheckedElse( false ))">
+FAILED:
+ REQUIRE( testCheckedElse( false ) )
+with expansion:
+ false
+Misc.tests.cpp:<line number>
+ </failure>
+ </testCase>
+ <testCase name="checkedIf" duration="{duration}"/>
+ <testCase name="checkedIf, failing" duration="{duration}">
+ <failure message="CHECKED_IF(flag)">
+FAILED:
+ CHECKED_IF( flag )
+with expansion:
+ false
+Misc.tests.cpp:<line number>
+ </failure>
+ <failure message="REQUIRE(testCheckedIf( false ))">
+FAILED:
+ REQUIRE( testCheckedIf( false ) )
+with expansion:
+ false
+Misc.tests.cpp:<line number>
+ </failure>
+ </testCase>
+ <testCase name="even more nested SECTION tests/c/d (leaf)" duration="{duration}"/>
+ <testCase name="even more nested SECTION tests/c/e (leaf)" duration="{duration}"/>
+ <testCase name="even more nested SECTION tests/f (leaf)" duration="{duration}"/>
+ <testCase name="long long" duration="{duration}"/>
+ <testCase name="looped SECTION tests/b is currently: 0" duration="{duration}">
+ <failure message="CHECK(b > a)">
+FAILED:
+ CHECK( b > a )
+with expansion:
+ 0 > 1
+Misc.tests.cpp:<line number>
+ </failure>
+ </testCase>
+ <testCase name="looped SECTION tests/b is currently: 1" duration="{duration}">
+ <failure message="CHECK(b > a)">
+FAILED:
+ CHECK( b > a )
+with expansion:
+ 1 > 1
+Misc.tests.cpp:<line number>
+ </failure>
+ </testCase>
+ <testCase name="looped SECTION tests/b is currently: 2" duration="{duration}"/>
+ <testCase name="looped SECTION tests/b is currently: 3" duration="{duration}"/>
+ <testCase name="looped SECTION tests/b is currently: 4" duration="{duration}"/>
+ <testCase name="looped SECTION tests/b is currently: 5" duration="{duration}"/>
+ <testCase name="looped SECTION tests/b is currently: 6" duration="{duration}"/>
+ <testCase name="looped SECTION tests/b is currently: 7" duration="{duration}"/>
+ <testCase name="looped SECTION tests/b is currently: 8" duration="{duration}"/>
+ <testCase name="looped SECTION tests/b is currently: 9" duration="{duration}"/>
+ <testCase name="looped tests" duration="{duration}">
+ <failure message="CHECK(( fib[i] % 2 ) == 0)">
+FAILED:
+ CHECK( ( fib[i] % 2 ) == 0 )
+with expansion:
+ 1 == 0
+Testing if fib[0] (1) is even
+Misc.tests.cpp:<line number>
+ </failure>
+ <failure message="CHECK(( fib[i] % 2 ) == 0)">
+FAILED:
+ CHECK( ( fib[i] % 2 ) == 0 )
+with expansion:
+ 1 == 0
+Testing if fib[1] (1) is even
+Misc.tests.cpp:<line number>
+ </failure>
+ <failure message="CHECK(( fib[i] % 2 ) == 0)">
+FAILED:
+ CHECK( ( fib[i] % 2 ) == 0 )
+with expansion:
+ 1 == 0
+Testing if fib[3] (3) is even
+Misc.tests.cpp:<line number>
+ </failure>
+ <failure message="CHECK(( fib[i] % 2 ) == 0)">
+FAILED:
+ CHECK( ( fib[i] % 2 ) == 0 )
+with expansion:
+ 1 == 0
+Testing if fib[4] (5) is even
+Misc.tests.cpp:<line number>
+ </failure>
+ <failure message="CHECK(( fib[i] % 2 ) == 0)">
+FAILED:
+ CHECK( ( fib[i] % 2 ) == 0 )
+with expansion:
+ 1 == 0
+Testing if fib[6] (13) is even
+Misc.tests.cpp:<line number>
+ </failure>
+ <failure message="CHECK(( fib[i] % 2 ) == 0)">
+FAILED:
+ CHECK( ( fib[i] % 2 ) == 0 )
+with expansion:
+ 1 == 0
+Testing if fib[7] (21) is even
+Misc.tests.cpp:<line number>
+ </failure>
+ </testCase>
+ <testCase name="more nested SECTION tests/equal/doesn't equal" duration="{duration}">
+ <failure message="REQUIRE(a == b)">
+FAILED:
+ REQUIRE( a == b )
+with expansion:
+ 1 == 2
+Misc.tests.cpp:<line number>
+ </failure>
+ </testCase>
+ <testCase name="more nested SECTION tests/doesn't equal/not equal" duration="{duration}"/>
+ <testCase name="more nested SECTION tests/doesn't equal/less than" duration="{duration}"/>
+ <testCase name="nested SECTION tests/doesn't equal" duration="{duration}"/>
+ <testCase name="nested SECTION tests/doesn't equal/not equal" duration="{duration}"/>
+ <testCase name="not allowed" duration="{duration}"/>
+ <testCase name="null strings" duration="{duration}"/>
+ <testCase name="random SECTION tests/doesn't equal" duration="{duration}"/>
+ <testCase name="random SECTION tests/not equal" duration="{duration}"/>
+ <testCase name="send a single char to INFO" duration="{duration}">
+ <failure message="REQUIRE(false)">
+FAILED:
+ REQUIRE( false )
+3
+Misc.tests.cpp:<line number>
+ </failure>
+ </testCase>
+ <testCase name="toString on const wchar_t const pointer returns the string contents" duration="{duration}"/>
+ <testCase name="toString on const wchar_t pointer returns the string contents" duration="{duration}"/>
+ <testCase name="toString on wchar_t const pointer returns the string contents" duration="{duration}"/>
+ <testCase name="toString on wchar_t returns the string contents" duration="{duration}"/>
+ <testCase name="vectors can be sized and resized" duration="{duration}"/>
+ <testCase name="vectors can be sized and resized/resizing bigger changes size and capacity" duration="{duration}"/>
+ <testCase name="vectors can be sized and resized/resizing smaller changes size but not capacity" duration="{duration}"/>
+ <testCase name="vectors can be sized and resized/resizing smaller changes size but not capacity/We can use the 'swap trick' to reset the capacity" duration="{duration}"/>
+ <testCase name="vectors can be sized and resized/reserving bigger changes capacity but not size" duration="{duration}"/>
+ <testCase name="vectors can be sized and resized/reserving smaller does not change size or capacity" duration="{duration}"/>
+ <testCase name="xmlentitycheck/embedded xml: &lt;test>it should be possible to embed xml characters, such as &lt;, &quot; or &amp;, or even whole &lt;xml>documents&lt;/xml> within an attribute&lt;/test>" duration="{duration}"/>
+ <testCase name="xmlentitycheck/encoded chars: these should all be encoded: &amp;&amp;&amp;&quot;&quot;&quot;&lt;&lt;&lt;&amp;&quot;&lt;&lt;&amp;&quot;" duration="{duration}"/>
+ </file>
+ <file path="projects/<exe-name>/UsageTests/ToStringChrono.tests.cpp">
+ <testCase name="Stringifying std::chrono::duration helpers" duration="{duration}"/>
+ <testCase name="Stringifying std::chrono::duration with weird ratios" duration="{duration}"/>
+ <testCase name="Stringifying std::chrono::time_point&lt;system_clock>" duration="{duration}"/>
+ </file>
+ <file path="projects/<exe-name>/UsageTests/ToStringGeneral.tests.cpp">
+ <testCase name="Capture and info messages/Capture should stringify like assertions" duration="{duration}"/>
+ <testCase name="Capture and info messages/Info should NOT stringify the way assertions do" duration="{duration}"/>
+ <testCase name="Character pretty printing/Specifically escaped" duration="{duration}"/>
+ <testCase name="Character pretty printing/General chars" duration="{duration}"/>
+ <testCase name="Character pretty printing/Low ASCII" duration="{duration}"/>
+ <testCase name="Exception as a value (e.g. in REQUIRE_THROWS_MATCHES) can be stringified" duration="{duration}"/>
+ <testCase name="Precision of floating point stringification can be set/Floats" duration="{duration}"/>
+ <testCase name="Precision of floating point stringification can be set/Double" duration="{duration}"/>
+ <testCase name="Static arrays are convertible to string/Single item" duration="{duration}"/>
+ <testCase name="Static arrays are convertible to string/Multiple" duration="{duration}"/>
+ <testCase name="Static arrays are convertible to string/Non-trivial inner items" duration="{duration}"/>
+ <testCase name="std::map is convertible string/empty" duration="{duration}"/>
+ <testCase name="std::map is convertible string/single item" duration="{duration}"/>
+ <testCase name="std::map is convertible string/several items" duration="{duration}"/>
+ <testCase name="std::set is convertible string/empty" duration="{duration}"/>
+ <testCase name="std::set is convertible string/single item" duration="{duration}"/>
+ <testCase name="std::set is convertible string/several items" duration="{duration}"/>
+ </file>
+ <file path="projects/<exe-name>/UsageTests/ToStringPair.tests.cpp">
+ <testCase name="pair&lt;pair&lt;int,const char *,pair&lt;std::string,int> > -> toString" duration="{duration}"/>
+ <testCase name="std::pair&lt;int,const std::string> -> toString" duration="{duration}"/>
+ <testCase name="std::pair&lt;int,std::string> -> toString" duration="{duration}"/>
+ <testCase name="std::vector&lt;std::pair&lt;std::string,int> > -> toString" duration="{duration}"/>
+ </file>
+ <file path="projects/<exe-name>/UsageTests/ToStringTuple.tests.cpp">
+ <testCase name="tuple&lt;>" duration="{duration}"/>
+ <testCase name="tuple&lt;float,int>" duration="{duration}"/>
+ <testCase name="tuple&lt;int>" duration="{duration}"/>
+ <testCase name="tuple&lt;0,int,const char *>" duration="{duration}"/>
+ <testCase name="tuple&lt;string,string>" duration="{duration}"/>
+ <testCase name="tuple&lt;tuple&lt;int>,tuple&lt;>,float>" duration="{duration}"/>
+ </file>
+ <file path="projects/<exe-name>/UsageTests/ToStringVector.tests.cpp">
+ <testCase name="array&lt;int, N> -> toString" duration="{duration}"/>
+ <testCase name="vec&lt;vec&lt;string,alloc>> -> toString" duration="{duration}"/>
+ <testCase name="vector&lt;bool> -> toString" duration="{duration}"/>
+ <testCase name="vector&lt;int,allocator> -> toString" duration="{duration}"/>
+ <testCase name="vector&lt;int> -> toString" duration="{duration}"/>
+ <testCase name="vector&lt;string> -> toString" duration="{duration}"/>
+ </file>
+ <file path="projects/<exe-name>/UsageTests/ToStringWhich.tests.cpp">
+ <testCase name="stringify ranges" duration="{duration}"/>
+ <testCase name="stringify( has_maker )" duration="{duration}"/>
+ <testCase name="stringify( has_maker_and_operator )" duration="{duration}"/>
+ <testCase name="stringify( has_neither )" duration="{duration}"/>
+ <testCase name="stringify( has_operator )" duration="{duration}"/>
+ <testCase name="stringify( has_template_operator )" duration="{duration}"/>
+ <testCase name="stringify( vectors&lt;has_maker> )" duration="{duration}"/>
+ <testCase name="stringify( vectors&lt;has_maker_and_operator> )" duration="{duration}"/>
+ <testCase name="stringify( vectors&lt;has_operator> )" duration="{duration}"/>
+ </file>
+ <file path="projects/<exe-name>/UsageTests/Tricky.tests.cpp">
+ <testCase name="#1514: stderr/stdout is not captured in tests aborted by an exception" duration="{duration}">
+ <failure message="FAIL()">
+FAILED:
+1514
+Tricky.tests.cpp:<line number>
+ </failure>
+ </testCase>
+ <testCase name="(unimplemented) static bools can be evaluated/compare to true" duration="{duration}"/>
+ <testCase name="(unimplemented) static bools can be evaluated/compare to false" duration="{duration}"/>
+ <testCase name="(unimplemented) static bools can be evaluated/negation" duration="{duration}"/>
+ <testCase name="(unimplemented) static bools can be evaluated/double negation" duration="{duration}"/>
+ <testCase name="(unimplemented) static bools can be evaluated/direct" duration="{duration}"/>
+ <testCase name="A failing expression with a non streamable type is still captured" duration="{duration}">
+ <failure message="CHECK(&amp;o1 == &amp;o2)">
+FAILED:
+ CHECK( &amp;o1 == &amp;o2 )
+with expansion:
+ 0x<hex digits> == 0x<hex digits>
+Tricky.tests.cpp:<line number>
+ </failure>
+ <failure message="CHECK(o1 == o2)">
+FAILED:
+ CHECK( o1 == o2 )
+with expansion:
+ {?} == {?}
+Tricky.tests.cpp:<line number>
+ </failure>
+ </testCase>
+ <testCase name="An expression with side-effects should only be evaluated once" duration="{duration}"/>
+ <testCase name="Assertions then sections" duration="{duration}"/>
+ <testCase name="Assertions then sections/A section" duration="{duration}"/>
+ <testCase name="Assertions then sections/A section/Another section" duration="{duration}"/>
+ <testCase name="Assertions then sections/A section/Another other section" duration="{duration}"/>
+ <testCase name="Commas in various macros are allowed" duration="{duration}"/>
+ <testCase name="Comparing function pointers" duration="{duration}"/>
+ <testCase name="Objects that evaluated in boolean contexts can be checked" duration="{duration}"/>
+ <testCase name="Test enum bit values" duration="{duration}"/>
+ <testCase name="Where the LHS is not a simple value" duration="{duration}"/>
+ <testCase name="Where there is more to the expression after the RHS" duration="{duration}"/>
+ <testCase name="X/level/0/a" duration="{duration}"/>
+ <testCase name="X/level/0/b" duration="{duration}"/>
+ <testCase name="X/level/1/a" duration="{duration}"/>
+ <testCase name="X/level/1/b" duration="{duration}"/>
+ <testCase name="boolean member" duration="{duration}"/>
+ <testCase name="non streamable - with conv. op" duration="{duration}"/>
+ <testCase name="non-copyable objects" duration="{duration}"/>
+ <testCase name="null_ptr" duration="{duration}"/>
+ <testCase name="pointer to class" duration="{duration}"/>
+ <testCase name="string literals of different sizes can be compared" duration="{duration}">
+ <failure message="REQUIRE(std::string( &quot;first&quot; ) == &quot;second&quot;)">
+FAILED:
+ REQUIRE( std::string( "first" ) == "second" )
+with expansion:
+ "first" == "second"
+Tricky.tests.cpp:<line number>
+ </failure>
+ </testCase>
+ </file>
+ <file path="projects/<exe-name>/UsageTests/VariadicMacros.tests.cpp">
+ <testCase name="Anonymous test case 1" duration="{duration}"/>
+ <testCase name="Test case with one argument" duration="{duration}"/>
+ <testCase name="Variadic macros/Section with one argument" duration="{duration}"/>
+ </file>
+</testExecutions>
diff --git a/projects/SelfTest/Baselines/xml.sw.approved.txt b/projects/SelfTest/Baselines/xml.sw.approved.txt
index d053b408..4eed7125 100644
--- a/projects/SelfTest/Baselines/xml.sw.approved.txt
+++ b/projects/SelfTest/Baselines/xml.sw.approved.txt
@@ -43,6 +43,25 @@
</Expression>
<OverallResult success="true"/>
</TestCase>
+ <TestCase name="#1027: Bitfields can be captured" filename="projects/<exe-name>/UsageTests/Compilation.tests.cpp" >
+ <Expression success="true" type="REQUIRE" filename="projects/<exe-name>/UsageTests/Compilation.tests.cpp" >
+ <Original>
+ y.v == 0
+ </Original>
+ <Expanded>
+ 0 == 0
+ </Expanded>
+ </Expression>
+ <Expression success="true" type="REQUIRE" filename="projects/<exe-name>/UsageTests/Compilation.tests.cpp" >
+ <Original>
+ 0 == y.v
+ </Original>
+ <Expanded>
+ 0 == 0
+ </Expanded>
+ </Expression>
+ <OverallResult success="true"/>
+ </TestCase>
<TestCase name="#1147" filename="projects/<exe-name>/UsageTests/Compilation.tests.cpp" >
<Expression success="true" type="REQUIRE" filename="projects/<exe-name>/UsageTests/Compilation.tests.cpp" >
<Original>
@@ -94,7 +113,7 @@
</Expression>
<OverallResult success="true"/>
</TestCase>
- <TestCase name="#1175 - Hidden Test" tags="[.]" filename="projects/<exe-name>/UsageTests/Misc.tests.cpp" >
+ <TestCase name="#1175 - Hidden Test" tags="[!hide][.]" filename="projects/<exe-name>/UsageTests/Misc.tests.cpp" >
<OverallResult success="true"/>
</TestCase>
<TestCase name="#1238" filename="projects/<exe-name>/UsageTests/Compilation.tests.cpp" >
@@ -142,7 +161,7 @@
</Expression>
<OverallResult success="true"/>
</TestCase>
- <TestCase name="#1455 - INFO and WARN can start with a linebreak" tags="[.][messages]" filename="projects/<exe-name>/UsageTests/Message.tests.cpp" >
+ <TestCase name="#1455 - INFO and WARN can start with a linebreak" tags="[!hide][.][messages]" filename="projects/<exe-name>/UsageTests/Message.tests.cpp" >
<Info>
This info message starts with a linebreak
@@ -153,7 +172,7 @@ This warning message starts with a linebreak
</Warning>
<OverallResult success="false"/>
</TestCase>
- <TestCase name="#1514: stderr/stdout is not captured in tests aborted by an exception" tags="[.][output-capture][regression]" filename="projects/<exe-name>/UsageTests/Tricky.tests.cpp" >
+ <TestCase name="#1514: stderr/stdout is not captured in tests aborted by an exception" tags="[!hide][.][output-capture][regression]" filename="projects/<exe-name>/UsageTests/Tricky.tests.cpp" >
<Failure filename="projects/<exe-name>/UsageTests/Tricky.tests.cpp" >
1514
</Failure>
@@ -177,7 +196,7 @@ Nor would this
</Expression>
<OverallResult success="true"/>
</TestCase>
- <TestCase name="#748 - captures with unexpected exceptions" tags="[!shouldfail][!throws][.][failing]" filename="projects/<exe-name>/UsageTests/Exception.tests.cpp" >
+ <TestCase name="#748 - captures with unexpected exceptions" tags="[!hide][!shouldfail][!throws][.][failing]" filename="projects/<exe-name>/UsageTests/Exception.tests.cpp" >
<Section name="outside assertions" filename="projects/<exe-name>/UsageTests/Exception.tests.cpp" >
<Info>
answer := 42
@@ -290,7 +309,7 @@ Nor would this
</Expression>
<OverallResult success="true"/>
</TestCase>
- <TestCase name="#835 -- errno should not be touched by Catch" tags="[!shouldfail][.][failing]" filename="projects/<exe-name>/UsageTests/Misc.tests.cpp" >
+ <TestCase name="#835 -- errno should not be touched by Catch" tags="[!hide][!shouldfail][.][failing]" filename="projects/<exe-name>/UsageTests/Misc.tests.cpp" >
<Expression success="false" type="CHECK" filename="projects/<exe-name>/UsageTests/Misc.tests.cpp" >
<Original>
f() == 0
@@ -323,7 +342,7 @@ Nor would this
</Expression>
<OverallResult success="true"/>
</TestCase>
- <TestCase name="#961 -- Dynamically created sections should all be reported" tags="[.]" filename="projects/<exe-name>/UsageTests/Misc.tests.cpp" >
+ <TestCase name="#961 -- Dynamically created sections should all be reported" tags="[!hide][.]" filename="projects/<exe-name>/UsageTests/Misc.tests.cpp" >
<Section name="Looped section 0" filename="projects/<exe-name>/UsageTests/Misc.tests.cpp" >
<OverallResults successes="1" failures="0" expectedFailures="0"/>
</Section>
@@ -341,7 +360,7 @@ Nor would this
</Section>
<OverallResult success="true"/>
</TestCase>
- <TestCase name="'Not' checks that should fail" tags="[.][failing]" filename="projects/<exe-name>/UsageTests/Condition.tests.cpp" >
+ <TestCase name="'Not' checks that should fail" tags="[!hide][.][failing]" filename="projects/<exe-name>/UsageTests/Condition.tests.cpp" >
<Expression success="false" type="CHECK" filename="projects/<exe-name>/UsageTests/Condition.tests.cpp" >
<Original>
false != false
@@ -1208,7 +1227,7 @@ Nor would this
</Expression>
<OverallResult success="true"/>
</TestCase>
- <TestCase name="A METHOD_AS_TEST_CASE based test run that fails" tags="[.][class][failing]" filename="projects/<exe-name>/UsageTests/Class.tests.cpp" >
+ <TestCase name="A METHOD_AS_TEST_CASE based test run that fails" tags="[!hide][.][class][failing]" filename="projects/<exe-name>/UsageTests/Class.tests.cpp" >
<Expression success="false" type="REQUIRE" filename="projects/<exe-name>/UsageTests/Class.tests.cpp" >
<Original>
s == "world"
@@ -1230,7 +1249,7 @@ Nor would this
</Expression>
<OverallResult success="true"/>
</TestCase>
- <TestCase name="A TEMPLATE_PRODUCT_TEST_CASE_METHOD based test run that fails - Template_Foo&lt;float>" tags="[.][class][failing][product][template]" filename="projects/<exe-name>/UsageTests/Class.tests.cpp" >
+ <TestCase name="A TEMPLATE_PRODUCT_TEST_CASE_METHOD based test run that fails - Template_Foo&lt;float>" tags="[!hide][.][class][failing][product][template]" filename="projects/<exe-name>/UsageTests/Class.tests.cpp" >
<Expression success="false" type="REQUIRE" filename="projects/<exe-name>/UsageTests/Class.tests.cpp" >
<Original>
Template_Fixture_2&lt;TestType>::m_a.size() == 1
@@ -1241,7 +1260,7 @@ Nor would this
</Expression>
<OverallResult success="false"/>
</TestCase>
- <TestCase name="A TEMPLATE_PRODUCT_TEST_CASE_METHOD based test run that fails - Template_Foo&lt;int>" tags="[.][class][failing][product][template]" filename="projects/<exe-name>/UsageTests/Class.tests.cpp" >
+ <TestCase name="A TEMPLATE_PRODUCT_TEST_CASE_METHOD based test run that fails - Template_Foo&lt;int>" tags="[!hide][.][class][failing][product][template]" filename="projects/<exe-name>/UsageTests/Class.tests.cpp" >
<Expression success="false" type="REQUIRE" filename="projects/<exe-name>/UsageTests/Class.tests.cpp" >
<Original>
Template_Fixture_2&lt;TestType>::m_a.size() == 1
@@ -1252,7 +1271,7 @@ Nor would this
</Expression>
<OverallResult success="false"/>
</TestCase>
- <TestCase name="A TEMPLATE_PRODUCT_TEST_CASE_METHOD based test run that fails - std::vector&lt;float>" tags="[.][class][failing][product][template]" filename="projects/<exe-name>/UsageTests/Class.tests.cpp" >
+ <TestCase name="A TEMPLATE_PRODUCT_TEST_CASE_METHOD based test run that fails - std::vector&lt;float>" tags="[!hide][.][class][failing][product][template]" filename="projects/<exe-name>/UsageTests/Class.tests.cpp" >
<Expression success="false" type="REQUIRE" filename="projects/<exe-name>/UsageTests/Class.tests.cpp" >
<Original>
Template_Fixture_2&lt;TestType>::m_a.size() == 1
@@ -1263,7 +1282,7 @@ Nor would this
</Expression>
<OverallResult success="false"/>
</TestCase>
- <TestCase name="A TEMPLATE_PRODUCT_TEST_CASE_METHOD based test run that fails - std::vector&lt;int>" tags="[.][class][failing][product][template]" filename="projects/<exe-name>/UsageTests/Class.tests.cpp" >
+ <TestCase name="A TEMPLATE_PRODUCT_TEST_CASE_METHOD based test run that fails - std::vector&lt;int>" tags="[!hide][.][class][failing][product][template]" filename="projects/<exe-name>/UsageTests/Class.tests.cpp" >
<Expression success="false" type="REQUIRE" filename="projects/<exe-name>/UsageTests/Class.tests.cpp" >
<Original>
Template_Fixture_2&lt;TestType>::m_a.size() == 1
@@ -1318,7 +1337,95 @@ Nor would this
</Expression>
<OverallResult success="true"/>
</TestCase>
- <TestCase name="A TEMPLATE_TEST_CASE_METHOD based test run that fails - double" tags="[.][class][failing][template]" filename="projects/<exe-name>/UsageTests/Class.tests.cpp" >
+ <TestCase name="A TEMPLATE_PRODUCT_TEST_CASE_METHOD_SIG based test run that fails - Template_Foo_2&lt;float, 6>" tags="[!hide][.][class][failing][nttp][product][template]" filename="projects/<exe-name>/UsageTests/Class.tests.cpp" >
+ <Expression success="false" type="REQUIRE" filename="projects/<exe-name>/UsageTests/Class.tests.cpp" >
+ <Original>
+ Template_Fixture_2&lt;TestType>{}.m_a.size() &lt; 2
+ </Original>
+ <Expanded>
+ 6 &lt; 2
+ </Expanded>
+ </Expression>
+ <OverallResult success="false"/>
+ </TestCase>
+ <TestCase name="A TEMPLATE_PRODUCT_TEST_CASE_METHOD_SIG based test run that fails - Template_Foo_2&lt;int, 2>" tags="[!hide][.][class][failing][nttp][product][template]" filename="projects/<exe-name>/UsageTests/Class.tests.cpp" >
+ <Expression success="false" type="REQUIRE" filename="projects/<exe-name>/UsageTests/Class.tests.cpp" >
+ <Original>
+ Template_Fixture_2&lt;TestType>{}.m_a.size() &lt; 2
+ </Original>
+ <Expanded>
+ 2 &lt; 2
+ </Expanded>
+ </Expression>
+ <OverallResult success="false"/>
+ </TestCase>
+ <TestCase name="A TEMPLATE_PRODUCT_TEST_CASE_METHOD_SIG based test run that fails - std::array&lt;float, 6>" tags="[!hide][.][class][failing][nttp][product][template]" filename="projects/<exe-name>/UsageTests/Class.tests.cpp" >
+ <Expression success="false" type="REQUIRE" filename="projects/<exe-name>/UsageTests/Class.tests.cpp" >
+ <Original>
+ Template_Fixture_2&lt;TestType>{}.m_a.size() &lt; 2
+ </Original>
+ <Expanded>
+ 6 &lt; 2
+ </Expanded>
+ </Expression>
+ <OverallResult success="false"/>
+ </TestCase>
+ <TestCase name="A TEMPLATE_PRODUCT_TEST_CASE_METHOD_SIG based test run that fails - std::array&lt;int, 2>" tags="[!hide][.][class][failing][nttp][product][template]" filename="projects/<exe-name>/UsageTests/Class.tests.cpp" >
+ <Expression success="false" type="REQUIRE" filename="projects/<exe-name>/UsageTests/Class.tests.cpp" >
+ <Original>
+ Template_Fixture_2&lt;TestType>{}.m_a.size() &lt; 2
+ </Original>
+ <Expanded>
+ 2 &lt; 2
+ </Expanded>
+ </Expression>
+ <OverallResult success="false"/>
+ </TestCase>
+ <TestCase name="A TEMPLATE_PRODUCT_TEST_CASE_METHOD_SIG based test run that succeeds - Template_Foo_2&lt;float,6>" tags="[class][nttp][product][template]" filename="projects/<exe-name>/UsageTests/Class.tests.cpp" >
+ <Expression success="true" type="REQUIRE" filename="projects/<exe-name>/UsageTests/Class.tests.cpp" >
+ <Original>
+ Template_Fixture_2&lt;TestType>{}.m_a.size() >= 2
+ </Original>
+ <Expanded>
+ 6 >= 2
+ </Expanded>
+ </Expression>
+ <OverallResult success="true"/>
+ </TestCase>
+ <TestCase name="A TEMPLATE_PRODUCT_TEST_CASE_METHOD_SIG based test run that succeeds - Template_Foo_2&lt;int,2>" tags="[class][nttp][product][template]" filename="projects/<exe-name>/UsageTests/Class.tests.cpp" >
+ <Expression success="true" type="REQUIRE" filename="projects/<exe-name>/UsageTests/Class.tests.cpp" >
+ <Original>
+ Template_Fixture_2&lt;TestType>{}.m_a.size() >= 2
+ </Original>
+ <Expanded>
+ 2 >= 2
+ </Expanded>
+ </Expression>
+ <OverallResult success="true"/>
+ </TestCase>
+ <TestCase name="A TEMPLATE_PRODUCT_TEST_CASE_METHOD_SIG based test run that succeeds - std::array&lt;float,6>" tags="[class][nttp][product][template]" filename="projects/<exe-name>/UsageTests/Class.tests.cpp" >
+ <Expression success="true" type="REQUIRE" filename="projects/<exe-name>/UsageTests/Class.tests.cpp" >
+ <Original>
+ Template_Fixture_2&lt;TestType>{}.m_a.size() >= 2
+ </Original>
+ <Expanded>
+ 6 >= 2
+ </Expanded>
+ </Expression>
+ <OverallResult success="true"/>
+ </TestCase>
+ <TestCase name="A TEMPLATE_PRODUCT_TEST_CASE_METHOD_SIG based test run that succeeds - std::array&lt;int,2>" tags="[class][nttp][product][template]" filename="projects/<exe-name>/UsageTests/Class.tests.cpp" >
+ <Expression success="true" type="REQUIRE" filename="projects/<exe-name>/UsageTests/Class.tests.cpp" >
+ <Original>
+ Template_Fixture_2&lt;TestType>{}.m_a.size() >= 2
+ </Original>
+ <Expanded>
+ 2 >= 2
+ </Expanded>
+ </Expression>
+ <OverallResult success="true"/>
+ </TestCase>
+ <TestCase name="A TEMPLATE_TEST_CASE_METHOD based test run that fails - double" tags="[!hide][.][class][failing][template]" filename="projects/<exe-name>/UsageTests/Class.tests.cpp" >
<Expression success="false" type="REQUIRE" filename="projects/<exe-name>/UsageTests/Class.tests.cpp" >
<Original>
Template_Fixture&lt;TestType>::m_a == 2
@@ -1329,7 +1436,7 @@ Nor would this
</Expression>
<OverallResult success="false"/>
</TestCase>
- <TestCase name="A TEMPLATE_TEST_CASE_METHOD based test run that fails - float" tags="[.][class][failing][template]" filename="projects/<exe-name>/UsageTests/Class.tests.cpp" >
+ <TestCase name="A TEMPLATE_TEST_CASE_METHOD based test run that fails - float" tags="[!hide][.][class][failing][template]" filename="projects/<exe-name>/UsageTests/Class.tests.cpp" >
<Expression success="false" type="REQUIRE" filename="projects/<exe-name>/UsageTests/Class.tests.cpp" >
<Original>
Template_Fixture&lt;TestType>::m_a == 2
@@ -1340,7 +1447,7 @@ Nor would this
</Expression>
<OverallResult success="false"/>
</TestCase>
- <TestCase name="A TEMPLATE_TEST_CASE_METHOD based test run that fails - int" tags="[.][class][failing][template]" filename="projects/<exe-name>/UsageTests/Class.tests.cpp" >
+ <TestCase name="A TEMPLATE_TEST_CASE_METHOD based test run that fails - int" tags="[!hide][.][class][failing][template]" filename="projects/<exe-name>/UsageTests/Class.tests.cpp" >
<Expression success="false" type="REQUIRE" filename="projects/<exe-name>/UsageTests/Class.tests.cpp" >
<Original>
Template_Fixture&lt;TestType>::m_a == 2
@@ -1384,7 +1491,73 @@ Nor would this
</Expression>
<OverallResult success="true"/>
</TestCase>
- <TestCase name="A TEST_CASE_METHOD based test run that fails" tags="[.][class][failing]" filename="projects/<exe-name>/UsageTests/Class.tests.cpp" >
+ <TestCase name="A TEMPLATE_TEST_CASE_METHOD_SIG based test run that fails - 1" tags="[!hide][.][class][failing][nttp][template]" filename="projects/<exe-name>/UsageTests/Class.tests.cpp" >
+ <Expression success="false" type="REQUIRE" filename="projects/<exe-name>/UsageTests/Class.tests.cpp" >
+ <Original>
+ Nttp_Fixture&lt;V>::value == 0
+ </Original>
+ <Expanded>
+ 1 == 0
+ </Expanded>
+ </Expression>
+ <OverallResult success="false"/>
+ </TestCase>
+ <TestCase name="A TEMPLATE_TEST_CASE_METHOD_SIG based test run that fails - 3" tags="[!hide][.][class][failing][nttp][template]" filename="projects/<exe-name>/UsageTests/Class.tests.cpp" >
+ <Expression success="false" type="REQUIRE" filename="projects/<exe-name>/UsageTests/Class.tests.cpp" >
+ <Original>
+ Nttp_Fixture&lt;V>::value == 0
+ </Original>
+ <Expanded>
+ 3 == 0
+ </Expanded>
+ </Expression>
+ <OverallResult success="false"/>
+ </TestCase>
+ <TestCase name="A TEMPLATE_TEST_CASE_METHOD_SIG based test run that fails - 6" tags="[!hide][.][class][failing][nttp][template]" filename="projects/<exe-name>/UsageTests/Class.tests.cpp" >
+ <Expression success="false" type="REQUIRE" filename="projects/<exe-name>/UsageTests/Class.tests.cpp" >
+ <Original>
+ Nttp_Fixture&lt;V>::value == 0
+ </Original>
+ <Expanded>
+ 6 == 0
+ </Expanded>
+ </Expression>
+ <OverallResult success="false"/>
+ </TestCase>
+ <TestCase name="A TEMPLATE_TEST_CASE_METHOD_SIG based test run that succeeds - 1" tags="[class][nttp][template]" filename="projects/<exe-name>/UsageTests/Class.tests.cpp" >
+ <Expression success="true" type="REQUIRE" filename="projects/<exe-name>/UsageTests/Class.tests.cpp" >
+ <Original>
+ Nttp_Fixture&lt;V>::value > 0
+ </Original>
+ <Expanded>
+ 1 > 0
+ </Expanded>
+ </Expression>
+ <OverallResult success="true"/>
+ </TestCase>
+ <TestCase name="A TEMPLATE_TEST_CASE_METHOD_SIG based test run that succeeds - 3" tags="[class][nttp][template]" filename="projects/<exe-name>/UsageTests/Class.tests.cpp" >
+ <Expression success="true" type="REQUIRE" filename="projects/<exe-name>/UsageTests/Class.tests.cpp" >
+ <Original>
+ Nttp_Fixture&lt;V>::value > 0
+ </Original>
+ <Expanded>
+ 3 > 0
+ </Expanded>
+ </Expression>
+ <OverallResult success="true"/>
+ </TestCase>
+ <TestCase name="A TEMPLATE_TEST_CASE_METHOD_SIG based test run that succeeds - 6" tags="[class][nttp][template]" filename="projects/<exe-name>/UsageTests/Class.tests.cpp" >
+ <Expression success="true" type="REQUIRE" filename="projects/<exe-name>/UsageTests/Class.tests.cpp" >
+ <Original>
+ Nttp_Fixture&lt;V>::value > 0
+ </Original>
+ <Expanded>
+ 6 > 0
+ </Expanded>
+ </Expression>
+ <OverallResult success="true"/>
+ </TestCase>
+ <TestCase name="A TEST_CASE_METHOD based test run that fails" tags="[!hide][.][class][failing]" filename="projects/<exe-name>/UsageTests/Class.tests.cpp" >
<Expression success="false" type="REQUIRE" filename="projects/<exe-name>/UsageTests/Class.tests.cpp" >
<Original>
m_a == 2
@@ -1450,6 +1623,50 @@ Nor would this
</Expression>
<OverallResult success="true"/>
</TestCase>
+ <TestCase name="A Template product test case with array signature - Bar&lt;float, 42>" tags="[nttp][product][template]" filename="projects/<exe-name>/UsageTests/Misc.tests.cpp" >
+ <Expression success="true" type="REQUIRE" filename="projects/<exe-name>/UsageTests/Misc.tests.cpp" >
+ <Original>
+ x.size() > 0
+ </Original>
+ <Expanded>
+ 42 > 0
+ </Expanded>
+ </Expression>
+ <OverallResult success="true"/>
+ </TestCase>
+ <TestCase name="A Template product test case with array signature - Bar&lt;int, 9>" tags="[nttp][product][template]" filename="projects/<exe-name>/UsageTests/Misc.tests.cpp" >
+ <Expression success="true" type="REQUIRE" filename="projects/<exe-name>/UsageTests/Misc.tests.cpp" >
+ <Original>
+ x.size() > 0
+ </Original>
+ <Expanded>
+ 9 > 0
+ </Expanded>
+ </Expression>
+ <OverallResult success="true"/>
+ </TestCase>
+ <TestCase name="A Template product test case with array signature - std::array&lt;float, 42>" tags="[nttp][product][template]" filename="projects/<exe-name>/UsageTests/Misc.tests.cpp" >
+ <Expression success="true" type="REQUIRE" filename="projects/<exe-name>/UsageTests/Misc.tests.cpp" >
+ <Original>
+ x.size() > 0
+ </Original>
+ <Expanded>
+ 42 > 0
+ </Expanded>
+ </Expression>
+ <OverallResult success="true"/>
+ </TestCase>
+ <TestCase name="A Template product test case with array signature - std::array&lt;int, 9>" tags="[nttp][product][template]" filename="projects/<exe-name>/UsageTests/Misc.tests.cpp" >
+ <Expression success="true" type="REQUIRE" filename="projects/<exe-name>/UsageTests/Misc.tests.cpp" >
+ <Original>
+ x.size() > 0
+ </Original>
+ <Expanded>
+ 9 > 0
+ </Expanded>
+ </Expression>
+ <OverallResult success="true"/>
+ </TestCase>
<TestCase name="A comparison that uses literals instead of the normal constructor" tags="[Approx]" filename="projects/<exe-name>/UsageTests/Approx.tests.cpp" >
<Expression success="true" type="REQUIRE" filename="projects/<exe-name>/UsageTests/Approx.tests.cpp" >
<Original>
@@ -1501,7 +1718,7 @@ Nor would this
</Expression>
<OverallResult success="true"/>
</TestCase>
- <TestCase name="A couple of nested sections followed by a failure" tags="[.][failing]" filename="projects/<exe-name>/UsageTests/Misc.tests.cpp" >
+ <TestCase name="A couple of nested sections followed by a failure" tags="[!hide][.][failing]" filename="projects/<exe-name>/UsageTests/Misc.tests.cpp" >
<Section name="Outer" filename="projects/<exe-name>/UsageTests/Misc.tests.cpp" >
<Section name="Inner" filename="projects/<exe-name>/UsageTests/Misc.tests.cpp" >
<OverallResults successes="1" failures="0" expectedFailures="0"/>
@@ -1513,7 +1730,7 @@ Nor would this
</Failure>
<OverallResult success="false"/>
</TestCase>
- <TestCase name="A failing expression with a non streamable type is still captured" tags="[.][Tricky][failing]" filename="projects/<exe-name>/UsageTests/Tricky.tests.cpp" >
+ <TestCase name="A failing expression with a non streamable type is still captured" tags="[!hide][.][Tricky][failing]" filename="projects/<exe-name>/UsageTests/Tricky.tests.cpp" >
<Expression success="false" type="CHECK" filename="projects/<exe-name>/UsageTests/Tricky.tests.cpp" >
<Original>
&amp;o1 == &amp;o2
@@ -1605,7 +1822,7 @@ Nor would this
</Expression>
<OverallResult success="true"/>
</TestCase>
- <TestCase name="An unchecked exception reports the line of the last assertion" tags="[!throws][.][failing]" filename="projects/<exe-name>/UsageTests/Exception.tests.cpp" >
+ <TestCase name="An unchecked exception reports the line of the last assertion" tags="[!hide][!throws][.][failing]" filename="projects/<exe-name>/UsageTests/Exception.tests.cpp" >
<Expression success="true" type="CHECK" filename="projects/<exe-name>/UsageTests/Exception.tests.cpp" >
<Original>
1 == 1
@@ -1955,52 +2172,6 @@ Nor would this
</Section>
<OverallResult success="true"/>
</TestCase>
- <TestCase name="Assorted miscellaneous tests" tags="[Approx]" filename="projects/<exe-name>/UsageTests/Approx.tests.cpp" >
- <Expression success="true" type="REQUIRE" filename="projects/<exe-name>/UsageTests/Approx.tests.cpp" >
- <Original>
- INFINITY == Approx(INFINITY)
- </Original>
- <Expanded>
- inff == Approx( inf )
- </Expanded>
- </Expression>
- <Expression success="true" type="REQUIRE" filename="projects/<exe-name>/UsageTests/Approx.tests.cpp" >
- <Original>
- NAN != Approx(NAN)
- </Original>
- <Expanded>
- nanf != Approx( nan )
- </Expanded>
- </Expression>
- <Expression success="true" type="REQUIRE_FALSE" filename="projects/<exe-name>/UsageTests/Approx.tests.cpp" >
- <Original>
- !(NAN == Approx(NAN))
- </Original>
- <Expanded>
- !(nanf == Approx( nan ))
- </Expanded>
- </Expression>
- <OverallResult success="true"/>
- </TestCase>
- <TestCase name="Bitfields can be captured (#1027)" filename="projects/<exe-name>/UsageTests/Tricky.tests.cpp" >
- <Expression success="true" type="REQUIRE" filename="projects/<exe-name>/UsageTests/Tricky.tests.cpp" >
- <Original>
- y.v == 0
- </Original>
- <Expanded>
- 0 == 0
- </Expanded>
- </Expression>
- <Expression success="true" type="REQUIRE" filename="projects/<exe-name>/UsageTests/Tricky.tests.cpp" >
- <Original>
- 0 == y.v
- </Original>
- <Expanded>
- 0 == 0
- </Expanded>
- </Expression>
- <OverallResult success="true"/>
- </TestCase>
<TestCase name="CAPTURE can deal with complex expressions" tags="[capture][messages]" filename="projects/<exe-name>/UsageTests/Message.tests.cpp" >
<Info>
a := 1
@@ -2049,6 +2220,42 @@ Nor would this
</Info>
<OverallResult success="true"/>
</TestCase>
+ <TestCase name="CAPTURE parses string and character constants" tags="[capture][messages]" filename="projects/<exe-name>/UsageTests/Message.tests.cpp" >
+ <Info>
+ ("comma, in string", "escaped, \", ") := "escaped, ", "
+ </Info>
+ <Info>
+ "single quote in string,'," := "single quote in string,',"
+ </Info>
+ <Info>
+ "some escapes, \\,\\\\" := "some escapes, \,\\"
+ </Info>
+ <Info>
+ "some, ), unmatched, } prenheses {[&lt;" := "some, ), unmatched, } prenheses {[&lt;"
+ </Info>
+ <Info>
+ '"' := '"'
+ </Info>
+ <Info>
+ '\'' := '''
+ </Info>
+ <Info>
+ ',' := ','
+ </Info>
+ <Info>
+ '}' := '}'
+ </Info>
+ <Info>
+ ')' := ')'
+ </Info>
+ <Info>
+ '(' := '('
+ </Info>
+ <Info>
+ '{' := '{'
+ </Info>
+ <OverallResult success="true"/>
+ </TestCase>
<TestCase name="Capture and info messages" filename="projects/<exe-name>/UsageTests/ToStringGeneral.tests.cpp" >
<Section name="Capture should stringify like assertions" filename="projects/<exe-name>/UsageTests/ToStringGeneral.tests.cpp" >
<Info>
@@ -2322,6 +2529,41 @@ Nor would this
</Expression>
<OverallResult success="true"/>
</TestCase>
+ <TestCase name="Comparison ops" tags="[rng]" filename="projects/<exe-name>/IntrospectiveTests/RandomNumberGeneration.tests.cpp" >
+ <Expression success="true" type="REQUIRE" filename="projects/<exe-name>/IntrospectiveTests/RandomNumberGeneration.tests.cpp" >
+ <Original>
+ SimplePcg32{} == SimplePcg32{}
+ </Original>
+ <Expanded>
+ {?} == {?}
+ </Expanded>
+ </Expression>
+ <Expression success="true" type="REQUIRE" filename="projects/<exe-name>/IntrospectiveTests/RandomNumberGeneration.tests.cpp" >
+ <Original>
+ SimplePcg32{ 0 } != SimplePcg32{}
+ </Original>
+ <Expanded>
+ {?} != {?}
+ </Expanded>
+ </Expression>
+ <Expression success="true" type="REQUIRE_FALSE" filename="projects/<exe-name>/IntrospectiveTests/RandomNumberGeneration.tests.cpp" >
+ <Original>
+ !(SimplePcg32{ 1 } == SimplePcg32{ 2 })
+ </Original>
+ <Expanded>
+ !({?} == {?})
+ </Expanded>
+ </Expression>
+ <Expression success="true" type="REQUIRE_FALSE" filename="projects/<exe-name>/IntrospectiveTests/RandomNumberGeneration.tests.cpp" >
+ <Original>
+ !(SimplePcg32{ 1 } != SimplePcg32{ 1 })
+ </Original>
+ <Expanded>
+ !({?} != {?})
+ </Expanded>
+ </Expression>
+ <OverallResult success="true"/>
+ </TestCase>
<TestCase name="Comparison with explicitly convertible types" tags="[Approx]" filename="projects/<exe-name>/UsageTests/Approx.tests.cpp" >
<Expression success="true" type="REQUIRE" filename="projects/<exe-name>/UsageTests/Approx.tests.cpp" >
<Original>
@@ -2590,7 +2832,26 @@ Nor would this
</Expression>
<OverallResult success="true"/>
</TestCase>
- <TestCase name="Contains string matcher" tags="[.][failing][matchers]" filename="projects/<exe-name>/UsageTests/Matchers.tests.cpp" >
+ <TestCase name="Composed matchers are distinct" tags="[composed][matchers]" filename="projects/<exe-name>/UsageTests/Matchers.tests.cpp" >
+ <Expression success="true" type="REQUIRE_THAT" filename="projects/<exe-name>/UsageTests/Matchers.tests.cpp" >
+ <Original>
+ testStringForMatching2(), !composed1
+ </Original>
+ <Expanded>
+ "some completely different text that contains one common word" not ( contains: "string" or contains: "random" )
+ </Expanded>
+ </Expression>
+ <Expression success="true" type="REQUIRE_THAT" filename="projects/<exe-name>/UsageTests/Matchers.tests.cpp" >
+ <Original>
+ testStringForMatching2(), composed2
+ </Original>
+ <Expanded>
+ "some completely different text that contains one common word" ( contains: "string" or contains: "random" or contains: "different" )
+ </Expanded>
+ </Expression>
+ <OverallResult success="true"/>
+ </TestCase>
+ <TestCase name="Contains string matcher" tags="[!hide][.][failing][matchers]" filename="projects/<exe-name>/UsageTests/Matchers.tests.cpp" >
<Expression success="false" type="CHECK_THAT" filename="projects/<exe-name>/UsageTests/Matchers.tests.cpp" >
<Original>
testStringForMatching(), Contains("not there", Catch::CaseSensitive::No)
@@ -2609,7 +2870,161 @@ Nor would this
</Expression>
<OverallResult success="false"/>
</TestCase>
- <TestCase name="Custom exceptions can be translated when testing for nothrow" tags="[!throws][.][failing]" filename="projects/<exe-name>/UsageTests/Exception.tests.cpp" >
+ <TestCase name="Copy and then generate a range" tags="[generators]" filename="projects/<exe-name>/UsageTests/Generators.tests.cpp" >
+ <Section name="from var and iterators" filename="projects/<exe-name>/UsageTests/Generators.tests.cpp" >
+ <Expression success="true" type="REQUIRE" filename="projects/<exe-name>/UsageTests/Generators.tests.cpp" >
+ <Original>
+ elem % 2 == 1
+ </Original>
+ <Expanded>
+ 1 == 1
+ </Expanded>
+ </Expression>
+ <OverallResults successes="1" failures="0" expectedFailures="0"/>
+ </Section>
+ <Section name="from var and iterators" filename="projects/<exe-name>/UsageTests/Generators.tests.cpp" >
+ <Expression success="true" type="REQUIRE" filename="projects/<exe-name>/UsageTests/Generators.tests.cpp" >
+ <Original>
+ elem % 2 == 1
+ </Original>
+ <Expanded>
+ 1 == 1
+ </Expanded>
+ </Expression>
+ <OverallResults successes="1" failures="0" expectedFailures="0"/>
+ </Section>
+ <Section name="from var and iterators" filename="projects/<exe-name>/UsageTests/Generators.tests.cpp" >
+ <Expression success="true" type="REQUIRE" filename="projects/<exe-name>/UsageTests/Generators.tests.cpp" >
+ <Original>
+ elem % 2 == 1
+ </Original>
+ <Expanded>
+ 1 == 1
+ </Expanded>
+ </Expression>
+ <OverallResults successes="1" failures="0" expectedFailures="0"/>
+ </Section>
+ <Section name="from var and iterators" filename="projects/<exe-name>/UsageTests/Generators.tests.cpp" >
+ <Expression success="true" type="REQUIRE" filename="projects/<exe-name>/UsageTests/Generators.tests.cpp" >
+ <Original>
+ elem % 2 == 1
+ </Original>
+ <Expanded>
+ 1 == 1
+ </Expanded>
+ </Expression>
+ <OverallResults successes="1" failures="0" expectedFailures="0"/>
+ </Section>
+ <Section name="from var and iterators" filename="projects/<exe-name>/UsageTests/Generators.tests.cpp" >
+ <Expression success="true" type="REQUIRE" filename="projects/<exe-name>/UsageTests/Generators.tests.cpp" >
+ <Original>
+ elem % 2 == 1
+ </Original>
+ <Expanded>
+ 1 == 1
+ </Expanded>
+ </Expression>
+ <OverallResults successes="1" failures="0" expectedFailures="0"/>
+ </Section>
+ <Section name="from var and iterators" filename="projects/<exe-name>/UsageTests/Generators.tests.cpp" >
+ <Expression success="true" type="REQUIRE" filename="projects/<exe-name>/UsageTests/Generators.tests.cpp" >
+ <Original>
+ elem % 2 == 1
+ </Original>
+ <Expanded>
+ 1 == 1
+ </Expanded>
+ </Expression>
+ <OverallResults successes="1" failures="0" expectedFailures="0"/>
+ </Section>
+ <Section name="From a temporary container" filename="projects/<exe-name>/UsageTests/Generators.tests.cpp" >
+ <Expression success="true" type="REQUIRE" filename="projects/<exe-name>/UsageTests/Generators.tests.cpp" >
+ <Original>
+ elem % 2 == 1
+ </Original>
+ <Expanded>
+ 1 == 1
+ </Expanded>
+ </Expression>
+ <OverallResults successes="1" failures="0" expectedFailures="0"/>
+ </Section>
+ <Section name="From a temporary container" filename="projects/<exe-name>/UsageTests/Generators.tests.cpp" >
+ <Expression success="true" type="REQUIRE" filename="projects/<exe-name>/UsageTests/Generators.tests.cpp" >
+ <Original>
+ elem % 2 == 1
+ </Original>
+ <Expanded>
+ 1 == 1
+ </Expanded>
+ </Expression>
+ <OverallResults successes="1" failures="0" expectedFailures="0"/>
+ </Section>
+ <Section name="From a temporary container" filename="projects/<exe-name>/UsageTests/Generators.tests.cpp" >
+ <Expression success="true" type="REQUIRE" filename="projects/<exe-name>/UsageTests/Generators.tests.cpp" >
+ <Original>
+ elem % 2 == 1
+ </Original>
+ <Expanded>
+ 1 == 1
+ </Expanded>
+ </Expression>
+ <OverallResults successes="1" failures="0" expectedFailures="0"/>
+ </Section>
+ <Section name="From a temporary container" filename="projects/<exe-name>/UsageTests/Generators.tests.cpp" >
+ <Expression success="true" type="REQUIRE" filename="projects/<exe-name>/UsageTests/Generators.tests.cpp" >
+ <Original>
+ elem % 2 == 1
+ </Original>
+ <Expanded>
+ 1 == 1
+ </Expanded>
+ </Expression>
+ <OverallResults successes="1" failures="0" expectedFailures="0"/>
+ </Section>
+ <Section name="From a temporary container" filename="projects/<exe-name>/UsageTests/Generators.tests.cpp" >
+ <Expression success="true" type="REQUIRE" filename="projects/<exe-name>/UsageTests/Generators.tests.cpp" >
+ <Original>
+ elem % 2 == 1
+ </Original>
+ <Expanded>
+ 1 == 1
+ </Expanded>
+ </Expression>
+ <OverallResults successes="1" failures="0" expectedFailures="0"/>
+ </Section>
+ <Section name="From a temporary container" filename="projects/<exe-name>/UsageTests/Generators.tests.cpp" >
+ <Expression success="true" type="REQUIRE" filename="projects/<exe-name>/UsageTests/Generators.tests.cpp" >
+ <Original>
+ elem % 2 == 1
+ </Original>
+ <Expanded>
+ 1 == 1
+ </Expanded>
+ </Expression>
+ <OverallResults successes="1" failures="0" expectedFailures="0"/>
+ </Section>
+ <Section name="Final validation" filename="projects/<exe-name>/UsageTests/Generators.tests.cpp" >
+ <Expression success="true" type="REQUIRE" filename="projects/<exe-name>/UsageTests/Generators.tests.cpp" >
+ <Original>
+ call_count == 1
+ </Original>
+ <Expanded>
+ 1 == 1
+ </Expanded>
+ </Expression>
+ <Expression success="true" type="REQUIRE" filename="projects/<exe-name>/UsageTests/Generators.tests.cpp" >
+ <Original>
+ make_data().size() == test_count
+ </Original>
+ <Expanded>
+ 6 == 6
+ </Expanded>
+ </Expression>
+ <OverallResults successes="2" failures="0" expectedFailures="0"/>
+ </Section>
+ <OverallResult success="true"/>
+ </TestCase>
+ <TestCase name="Custom exceptions can be translated when testing for nothrow" tags="[!hide][!throws][.][failing]" filename="projects/<exe-name>/UsageTests/Exception.tests.cpp" >
<Expression success="false" type="REQUIRE_NOTHROW" filename="projects/<exe-name>/UsageTests/Exception.tests.cpp" >
<Original>
throwCustom()
@@ -2623,7 +3038,7 @@ Nor would this
</Expression>
<OverallResult success="false"/>
</TestCase>
- <TestCase name="Custom exceptions can be translated when testing for throwing as something else" tags="[!throws][.][failing]" filename="projects/<exe-name>/UsageTests/Exception.tests.cpp" >
+ <TestCase name="Custom exceptions can be translated when testing for throwing as something else" tags="[!hide][!throws][.][failing]" filename="projects/<exe-name>/UsageTests/Exception.tests.cpp" >
<Expression success="false" type="REQUIRE_THROWS_AS" filename="projects/<exe-name>/UsageTests/Exception.tests.cpp" >
<Original>
throwCustom(), std::exception
@@ -2637,7 +3052,7 @@ Nor would this
</Expression>
<OverallResult success="false"/>
</TestCase>
- <TestCase name="Custom std-exceptions can be custom translated" tags="[!throws][.][failing]" filename="projects/<exe-name>/UsageTests/Exception.tests.cpp" >
+ <TestCase name="Custom std-exceptions can be custom translated" tags="[!hide][!throws][.][failing]" filename="projects/<exe-name>/UsageTests/Exception.tests.cpp" >
<Exception filename="projects/<exe-name>/UsageTests/Exception.tests.cpp" >
custom std exception
</Exception>
@@ -2662,7 +3077,36 @@ Nor would this
</Expression>
<OverallResult success="true"/>
</TestCase>
- <TestCase name="EndsWith string matcher" tags="[.][failing][matchers]" filename="projects/<exe-name>/UsageTests/Matchers.tests.cpp" >
+ <TestCase name="Directly creating an EnumInfo" filename="projects/<exe-name>/IntrospectiveTests/ToString.tests.cpp" >
+ <Expression success="true" type="CHECK" filename="projects/<exe-name>/IntrospectiveTests/ToString.tests.cpp" >
+ <Original>
+ enumInfo->lookup(0) == "Value1"
+ </Original>
+ <Expanded>
+ Value1 == "Value1"
+ </Expanded>
+ </Expression>
+ <Expression success="true" type="CHECK" filename="projects/<exe-name>/IntrospectiveTests/ToString.tests.cpp" >
+ <Original>
+ enumInfo->lookup(1) == "Value2"
+ </Original>
+ <Expanded>
+ Value2 == "Value2"
+ </Expanded>
+ </Expression>
+ <Expression success="true" type="CHECK" filename="projects/<exe-name>/IntrospectiveTests/ToString.tests.cpp" >
+ <Original>
+ enumInfo->lookup(3) == "{** unexpected enum value **}"
+ </Original>
+ <Expanded>
+ {** unexpected enum value **}
+==
+"{** unexpected enum value **}"
+ </Expanded>
+ </Expression>
+ <OverallResult success="true"/>
+ </TestCase>
+ <TestCase name="EndsWith string matcher" tags="[!hide][.][failing][matchers]" filename="projects/<exe-name>/UsageTests/Matchers.tests.cpp" >
<Expression success="false" type="CHECK_THAT" filename="projects/<exe-name>/UsageTests/Matchers.tests.cpp" >
<Original>
testStringForMatching(), EndsWith("Substring")
@@ -2681,6 +3125,70 @@ Nor would this
</Expression>
<OverallResult success="false"/>
</TestCase>
+ <TestCase name="Enums can quickly have stringification enabled using REGISTER_ENUM" filename="projects/<exe-name>/UsageTests/EnumToString.tests.cpp" >
+ <Expression success="true" type="REQUIRE" filename="projects/<exe-name>/UsageTests/EnumToString.tests.cpp" >
+ <Original>
+ stringify( EnumClass3::Value1 ) == "Value1"
+ </Original>
+ <Expanded>
+ "Value1" == "Value1"
+ </Expanded>
+ </Expression>
+ <Expression success="true" type="REQUIRE" filename="projects/<exe-name>/UsageTests/EnumToString.tests.cpp" >
+ <Original>
+ stringify( EnumClass3::Value2 ) == "Value2"
+ </Original>
+ <Expanded>
+ "Value2" == "Value2"
+ </Expanded>
+ </Expression>
+ <Expression success="true" type="REQUIRE" filename="projects/<exe-name>/UsageTests/EnumToString.tests.cpp" >
+ <Original>
+ stringify( EnumClass3::Value3 ) == "Value3"
+ </Original>
+ <Expanded>
+ "Value3" == "Value3"
+ </Expanded>
+ </Expression>
+ <Expression success="true" type="REQUIRE" filename="projects/<exe-name>/UsageTests/EnumToString.tests.cpp" >
+ <Original>
+ stringify( EnumClass3::Value4 ) == "{** unexpected enum value **}"
+ </Original>
+ <Expanded>
+ "{** unexpected enum value **}"
+==
+"{** unexpected enum value **}"
+ </Expanded>
+ </Expression>
+ <Expression success="true" type="REQUIRE" filename="projects/<exe-name>/UsageTests/EnumToString.tests.cpp" >
+ <Original>
+ stringify( ec3 ) == "Value2"
+ </Original>
+ <Expanded>
+ "Value2" == "Value2"
+ </Expanded>
+ </Expression>
+ <OverallResult success="true"/>
+ </TestCase>
+ <TestCase name="Enums in namespaces can quickly have stringification enabled using REGISTER_ENUM" filename="projects/<exe-name>/UsageTests/EnumToString.tests.cpp" >
+ <Expression success="true" type="REQUIRE" filename="projects/<exe-name>/UsageTests/EnumToString.tests.cpp" >
+ <Original>
+ stringify( Bikeshed::Colours::Red ) == "Red"
+ </Original>
+ <Expanded>
+ "Red" == "Red"
+ </Expanded>
+ </Expression>
+ <Expression success="true" type="REQUIRE" filename="projects/<exe-name>/UsageTests/EnumToString.tests.cpp" >
+ <Original>
+ stringify( Bikeshed::Colours::Blue ) == "Blue"
+ </Original>
+ <Expanded>
+ "Blue" == "Blue"
+ </Expanded>
+ </Expression>
+ <OverallResult success="true"/>
+ </TestCase>
<TestCase name="Epsilon only applies to Approx's value" tags="[Approx]" filename="projects/<exe-name>/UsageTests/Approx.tests.cpp" >
<Expression success="true" type="REQUIRE" filename="projects/<exe-name>/UsageTests/Approx.tests.cpp" >
<Original>
@@ -2692,7 +3200,7 @@ Nor would this
</Expression>
<OverallResult success="true"/>
</TestCase>
- <TestCase name="Equality checks that should fail" tags="[!mayfail][.][failing]" filename="projects/<exe-name>/UsageTests/Condition.tests.cpp" >
+ <TestCase name="Equality checks that should fail" tags="[!hide][!mayfail][.][failing]" filename="projects/<exe-name>/UsageTests/Condition.tests.cpp" >
<Expression success="false" type="CHECK" filename="projects/<exe-name>/UsageTests/Condition.tests.cpp" >
<Original>
data.int_seven == 6
@@ -2877,7 +3385,7 @@ Nor would this
</Expression>
<OverallResult success="true"/>
</TestCase>
- <TestCase name="Equals string matcher" tags="[.][failing][matchers]" filename="projects/<exe-name>/UsageTests/Matchers.tests.cpp" >
+ <TestCase name="Equals string matcher" tags="[!hide][.][failing][matchers]" filename="projects/<exe-name>/UsageTests/Matchers.tests.cpp" >
<Expression success="false" type="CHECK_THAT" filename="projects/<exe-name>/UsageTests/Matchers.tests.cpp" >
<Original>
testStringForMatching(), Equals("this string contains 'ABC' as a substring")
@@ -2927,7 +3435,7 @@ Nor would this
</Expression>
<OverallResult success="true"/>
</TestCase>
- <TestCase name="Exception matchers that fail" tags="[!throws][.][exceptions][failing][matchers]" filename="projects/<exe-name>/UsageTests/Matchers.tests.cpp" >
+ <TestCase name="Exception matchers that fail" tags="[!hide][!throws][.][exceptions][failing][matchers]" filename="projects/<exe-name>/UsageTests/Matchers.tests.cpp" >
<Section name="No exception" filename="projects/<exe-name>/UsageTests/Matchers.tests.cpp" >
<Expression success="false" type="CHECK_THROWS_MATCHES" filename="projects/<exe-name>/UsageTests/Matchers.tests.cpp" >
<Original>
@@ -2975,7 +3483,7 @@ Nor would this
<Section name="Contents are wrong" filename="projects/<exe-name>/UsageTests/Matchers.tests.cpp" >
<Expression success="false" type="CHECK_THROWS_MATCHES" filename="projects/<exe-name>/UsageTests/Matchers.tests.cpp" >
<Original>
- throws(3), SpecialException, ExceptionMatcher{1}
+ throwsSpecialException(3), SpecialException, ExceptionMatcher{1}
</Original>
<Expanded>
SpecialException::what special exception has value of 1
@@ -2983,7 +3491,7 @@ Nor would this
</Expression>
<Expression success="false" type="REQUIRE_THROWS_MATCHES" filename="projects/<exe-name>/UsageTests/Matchers.tests.cpp" >
<Original>
- throws(4), SpecialException, ExceptionMatcher{1}
+ throwsSpecialException(4), SpecialException, ExceptionMatcher{1}
</Original>
<Expanded>
SpecialException::what special exception has value of 1
@@ -2996,7 +3504,7 @@ Nor would this
<TestCase name="Exception matchers that succeed" tags="[!throws][exceptions][matchers]" filename="projects/<exe-name>/UsageTests/Matchers.tests.cpp" >
<Expression success="true" type="CHECK_THROWS_MATCHES" filename="projects/<exe-name>/UsageTests/Matchers.tests.cpp" >
<Original>
- throws(1), SpecialException, ExceptionMatcher{1}
+ throwsSpecialException(1), SpecialException, ExceptionMatcher{1}
</Original>
<Expanded>
SpecialException::what special exception has value of 1
@@ -3004,7 +3512,7 @@ Nor would this
</Expression>
<Expression success="true" type="REQUIRE_THROWS_MATCHES" filename="projects/<exe-name>/UsageTests/Matchers.tests.cpp" >
<Original>
- throws(2), SpecialException, ExceptionMatcher{2}
+ throwsSpecialException(2), SpecialException, ExceptionMatcher{2}
</Original>
<Expanded>
SpecialException::what special exception has value of 2
@@ -3072,7 +3580,42 @@ Nor would this
</Section>
<OverallResult success="true"/>
</TestCase>
- <TestCase name="Expected exceptions that don't throw or unexpected exceptions fail the test" tags="[!throws][.][failing]" filename="projects/<exe-name>/UsageTests/Exception.tests.cpp" >
+ <TestCase name="Exceptions matchers" tags="[!throws][exceptions][matchers]" filename="projects/<exe-name>/UsageTests/Matchers.tests.cpp" >
+ <Expression success="true" type="REQUIRE_THROWS_MATCHES" filename="projects/<exe-name>/UsageTests/Matchers.tests.cpp" >
+ <Original>
+ throwsDerivedException(), DerivedException, Message("DerivedException::what")
+ </Original>
+ <Expanded>
+ DerivedException::what exception message matches "DerivedException::what"
+ </Expanded>
+ </Expression>
+ <Expression success="true" type="REQUIRE_THROWS_MATCHES" filename="projects/<exe-name>/UsageTests/Matchers.tests.cpp" >
+ <Original>
+ throwsDerivedException(), DerivedException, !Message("derivedexception::what")
+ </Original>
+ <Expanded>
+ DerivedException::what not exception message matches "derivedexception::what"
+ </Expanded>
+ </Expression>
+ <Expression success="true" type="REQUIRE_THROWS_MATCHES" filename="projects/<exe-name>/UsageTests/Matchers.tests.cpp" >
+ <Original>
+ throwsSpecialException(2), SpecialException, !Message("DerivedException::what")
+ </Original>
+ <Expanded>
+ SpecialException::what not exception message matches "DerivedException::what"
+ </Expanded>
+ </Expression>
+ <Expression success="true" type="REQUIRE_THROWS_MATCHES" filename="projects/<exe-name>/UsageTests/Matchers.tests.cpp" >
+ <Original>
+ throwsSpecialException(2), SpecialException, Message("SpecialException::what")
+ </Original>
+ <Expanded>
+ SpecialException::what exception message matches "SpecialException::what"
+ </Expanded>
+ </Expression>
+ <OverallResult success="true"/>
+ </TestCase>
+ <TestCase name="Expected exceptions that don't throw or unexpected exceptions fail the test" tags="[!hide][!throws][.][failing]" filename="projects/<exe-name>/UsageTests/Exception.tests.cpp" >
<Expression success="false" type="CHECK_THROWS_AS" filename="projects/<exe-name>/UsageTests/Exception.tests.cpp" >
<Original>
thisThrows(), std::string
@@ -3105,17 +3648,17 @@ Nor would this
</Expression>
<OverallResult success="false"/>
</TestCase>
- <TestCase name="FAIL aborts the test" tags="[.][failing][messages]" filename="projects/<exe-name>/UsageTests/Message.tests.cpp" >
+ <TestCase name="FAIL aborts the test" tags="[!hide][.][failing][messages]" filename="projects/<exe-name>/UsageTests/Message.tests.cpp" >
<Failure filename="projects/<exe-name>/UsageTests/Message.tests.cpp" >
This is a failure
</Failure>
<OverallResult success="false"/>
</TestCase>
- <TestCase name="FAIL does not require an argument" tags="[.][failing][messages]" filename="projects/<exe-name>/UsageTests/Message.tests.cpp" >
+ <TestCase name="FAIL does not require an argument" tags="[!hide][.][failing][messages]" filename="projects/<exe-name>/UsageTests/Message.tests.cpp" >
<Failure filename="projects/<exe-name>/UsageTests/Message.tests.cpp" />
<OverallResult success="false"/>
</TestCase>
- <TestCase name="FAIL_CHECK does not abort the test" tags="[.][failing][messages]" filename="projects/<exe-name>/UsageTests/Message.tests.cpp" >
+ <TestCase name="FAIL_CHECK does not abort the test" tags="[!hide][.][failing][messages]" filename="projects/<exe-name>/UsageTests/Message.tests.cpp" >
<Failure filename="projects/<exe-name>/UsageTests/Message.tests.cpp" >
This is a failure
</Failure>
@@ -3168,6 +3711,52 @@ Nor would this
<OverallResult success="true"/>
</TestCase>
<TestCase name="Floating point matchers: double" tags="[floating-point][matchers]" filename="projects/<exe-name>/UsageTests/Matchers.tests.cpp" >
+ <Section name="Relative" filename="projects/<exe-name>/UsageTests/Matchers.tests.cpp" >
+ <Expression success="true" type="REQUIRE_THAT" filename="projects/<exe-name>/UsageTests/Matchers.tests.cpp" >
+ <Original>
+ 10., WithinRel(11.1, 0.1)
+ </Original>
+ <Expanded>
+ 10.0 and 11.1 are within 10% of each other
+ </Expanded>
+ </Expression>
+ <Expression success="true" type="REQUIRE_THAT" filename="projects/<exe-name>/UsageTests/Matchers.tests.cpp" >
+ <Original>
+ 10., !WithinRel(11.2, 0.1)
+ </Original>
+ <Expanded>
+ 10.0 not and 11.2 are within 10% of each other
+ </Expanded>
+ </Expression>
+ <Expression success="true" type="REQUIRE_THAT" filename="projects/<exe-name>/UsageTests/Matchers.tests.cpp" >
+ <Original>
+ 1., !WithinRel(0., 0.99)
+ </Original>
+ <Expanded>
+ 1.0 not and 0 are within 99% of each other
+ </Expanded>
+ </Expression>
+ <Expression success="true" type="REQUIRE_THAT" filename="projects/<exe-name>/UsageTests/Matchers.tests.cpp" >
+ <Original>
+ -0., WithinRel(0.)
+ </Original>
+ <Expanded>
+ -0.0 and 0 are within 2.22045e-12% of each other
+ </Expanded>
+ </Expression>
+ <Section name="Some subnormal values" filename="projects/<exe-name>/UsageTests/Matchers.tests.cpp" >
+ <Expression success="true" type="REQUIRE_THAT" filename="projects/<exe-name>/UsageTests/Matchers.tests.cpp" >
+ <Original>
+ v1, WithinRel(v2)
+ </Original>
+ <Expanded>
+ 0.0 and 2.22507e-308 are within 2.22045e-12% of each other
+ </Expanded>
+ </Expression>
+ <OverallResults successes="1" failures="0" expectedFailures="0"/>
+ </Section>
+ <OverallResults successes="5" failures="0" expectedFailures="0"/>
+ </Section>
<Section name="Margin" filename="projects/<exe-name>/UsageTests/Matchers.tests.cpp" >
<Expression success="true" type="REQUIRE_THAT" filename="projects/<exe-name>/UsageTests/Matchers.tests.cpp" >
<Original>
@@ -3203,14 +3792,6 @@ Nor would this
</Expression>
<Expression success="true" type="REQUIRE_THAT" filename="projects/<exe-name>/UsageTests/Matchers.tests.cpp" >
<Original>
- NAN, !WithinAbs(NAN, 0)
- </Original>
- <Expanded>
- nanf not is within 0.0 of nan
- </Expanded>
- </Expression>
- <Expression success="true" type="REQUIRE_THAT" filename="projects/<exe-name>/UsageTests/Matchers.tests.cpp" >
- <Original>
11., !WithinAbs(10., 0.5)
</Original>
<Expanded>
@@ -3241,7 +3822,7 @@ Nor would this
-10.0 is within 0.5 of -9.6
</Expanded>
</Expression>
- <OverallResults successes="9" failures="0" expectedFailures="0"/>
+ <OverallResults successes="8" failures="0" expectedFailures="0"/>
</Section>
<Section name="ULPs" filename="projects/<exe-name>/UsageTests/Matchers.tests.cpp" >
<Expression success="true" type="REQUIRE_THAT" filename="projects/<exe-name>/UsageTests/Matchers.tests.cpp" >
@@ -3249,7 +3830,7 @@ Nor would this
1., WithinULP(1., 0)
</Original>
<Expanded>
- 1.0 is within 0 ULPs of 1.0
+ 1.0 is within 0 ULPs of 1.0000000000000000e+00 ([1.0000000000000000e+00, 1.0000000000000000e+00])
</Expanded>
</Expression>
<Expression success="true" type="REQUIRE_THAT" filename="projects/<exe-name>/UsageTests/Matchers.tests.cpp" >
@@ -3257,47 +3838,47 @@ Nor would this
nextafter(1., 2.), WithinULP(1., 1)
</Original>
<Expanded>
- 1.0 is within 1 ULPs of 1.0
+ 1.0 is within 1 ULPs of 1.0000000000000000e+00 ([9.9999999999999989e-01, 1.0000000000000002e+00])
</Expanded>
</Expression>
<Expression success="true" type="REQUIRE_THAT" filename="projects/<exe-name>/UsageTests/Matchers.tests.cpp" >
<Original>
- nextafter(1., 0.), WithinULP(1., 1)
+ 0., WithinULP(nextafter(0., 1.), 1)
</Original>
<Expanded>
- 1.0 is within 1 ULPs of 1.0
+ 0.0 is within 1 ULPs of 4.9406564584124654e-324 ([0.0000000000000000e+00, 9.8813129168249309e-324])
</Expanded>
</Expression>
<Expression success="true" type="REQUIRE_THAT" filename="projects/<exe-name>/UsageTests/Matchers.tests.cpp" >
<Original>
- nextafter(1., 2.), !WithinULP(1., 0)
+ 1., WithinULP(nextafter(1., 0.), 1)
</Original>
<Expanded>
- 1.0 not is within 0 ULPs of 1.0
+ 1.0 is within 1 ULPs of 9.9999999999999989e-01 ([9.9999999999999978e-01, 1.0000000000000000e+00])
</Expanded>
</Expression>
<Expression success="true" type="REQUIRE_THAT" filename="projects/<exe-name>/UsageTests/Matchers.tests.cpp" >
<Original>
- 1., WithinULP(1., 0)
+ 1., !WithinULP(nextafter(1., 2.), 0)
</Original>
<Expanded>
- 1.0 is within 0 ULPs of 1.0
+ 1.0 not is within 0 ULPs of 1.0000000000000002e+00 ([1.0000000000000002e+00, 1.0000000000000002e+00])
</Expanded>
</Expression>
<Expression success="true" type="REQUIRE_THAT" filename="projects/<exe-name>/UsageTests/Matchers.tests.cpp" >
<Original>
- -0., WithinULP(0., 0)
+ 1., WithinULP(1., 0)
</Original>
<Expanded>
- -0.0 is within 0 ULPs of 0.0
+ 1.0 is within 0 ULPs of 1.0000000000000000e+00 ([1.0000000000000000e+00, 1.0000000000000000e+00])
</Expanded>
</Expression>
<Expression success="true" type="REQUIRE_THAT" filename="projects/<exe-name>/UsageTests/Matchers.tests.cpp" >
<Original>
- NAN, !WithinULP(NAN, 123)
+ -0., WithinULP(0., 0)
</Original>
<Expanded>
- nanf not is within 123 ULPs of nanf
+ -0.0 is within 0 ULPs of 0.0000000000000000e+00 ([0.0000000000000000e+00, 0.0000000000000000e+00])
</Expanded>
</Expression>
<OverallResults successes="7" failures="0" expectedFailures="0"/>
@@ -3308,7 +3889,7 @@ Nor would this
1., WithinAbs(1., 0.5) || WithinULP(2., 1)
</Original>
<Expanded>
- 1.0 ( is within 0.5 of 1.0 or is within 1 ULPs of 2.0 )
+ 1.0 ( is within 0.5 of 1.0 or is within 1 ULPs of 2.0000000000000000e+00 ([1.9999999999999998e+00, 2.0000000000000004e+00]) )
</Expanded>
</Expression>
<Expression success="true" type="REQUIRE_THAT" filename="projects/<exe-name>/UsageTests/Matchers.tests.cpp" >
@@ -3316,15 +3897,15 @@ Nor would this
1., WithinAbs(2., 0.5) || WithinULP(1., 0)
</Original>
<Expanded>
- 1.0 ( is within 0.5 of 2.0 or is within 0 ULPs of 1.0 )
+ 1.0 ( is within 0.5 of 2.0 or is within 0 ULPs of 1.0000000000000000e+00 ([1.0000000000000000e+00, 1.0000000000000000e+00]) )
</Expanded>
</Expression>
<Expression success="true" type="REQUIRE_THAT" filename="projects/<exe-name>/UsageTests/Matchers.tests.cpp" >
<Original>
- NAN, !(WithinAbs(NAN, 100) || WithinULP(NAN, 123))
+ 0.0001, WithinAbs(0., 0.001) || WithinRel(0., 0.1)
</Original>
<Expanded>
- nanf not ( is within 100.0 of nan or is within 123 ULPs of nanf )
+ 0.0001 ( is within 0.001 of 0.0 or and 0 are within 10% of each other )
</Expanded>
</Expression>
<OverallResults successes="3" failures="0" expectedFailures="0"/>
@@ -3354,19 +3935,81 @@ Nor would this
WithinULP(1., 0)
</Expanded>
</Expression>
+ <Expression success="true" type="REQUIRE_NOTHROW" filename="projects/<exe-name>/UsageTests/Matchers.tests.cpp" >
+ <Original>
+ WithinRel(1., 0.)
+ </Original>
+ <Expanded>
+ WithinRel(1., 0.)
+ </Expanded>
+ </Expression>
<Expression success="true" type="REQUIRE_THROWS_AS" filename="projects/<exe-name>/UsageTests/Matchers.tests.cpp" >
<Original>
- WithinULP(1., -1), std::domain_error
+ WithinRel(1., -0.2), std::domain_error
</Original>
<Expanded>
- WithinULP(1., -1), std::domain_error
+ WithinRel(1., -0.2), std::domain_error
</Expanded>
</Expression>
- <OverallResults successes="4" failures="0" expectedFailures="0"/>
+ <Expression success="true" type="REQUIRE_THROWS_AS" filename="projects/<exe-name>/UsageTests/Matchers.tests.cpp" >
+ <Original>
+ WithinRel(1., 1.), std::domain_error
+ </Original>
+ <Expanded>
+ WithinRel(1., 1.), std::domain_error
+ </Expanded>
+ </Expression>
+ <OverallResults successes="6" failures="0" expectedFailures="0"/>
</Section>
<OverallResult success="true"/>
</TestCase>
<TestCase name="Floating point matchers: float" tags="[floating-point][matchers]" filename="projects/<exe-name>/UsageTests/Matchers.tests.cpp" >
+ <Section name="Relative" filename="projects/<exe-name>/UsageTests/Matchers.tests.cpp" >
+ <Expression success="true" type="REQUIRE_THAT" filename="projects/<exe-name>/UsageTests/Matchers.tests.cpp" >
+ <Original>
+ 10.f, WithinRel(11.1f, 0.1f)
+ </Original>
+ <Expanded>
+ 10.0f and 11.1 are within 10% of each other
+ </Expanded>
+ </Expression>
+ <Expression success="true" type="REQUIRE_THAT" filename="projects/<exe-name>/UsageTests/Matchers.tests.cpp" >
+ <Original>
+ 10.f, !WithinRel(11.2f, 0.1f)
+ </Original>
+ <Expanded>
+ 10.0f not and 11.2 are within 10% of each other
+ </Expanded>
+ </Expression>
+ <Expression success="true" type="REQUIRE_THAT" filename="projects/<exe-name>/UsageTests/Matchers.tests.cpp" >
+ <Original>
+ 1.f, !WithinRel(0.f, 0.99f)
+ </Original>
+ <Expanded>
+ 1.0f not and 0 are within 99% of each other
+ </Expanded>
+ </Expression>
+ <Expression success="true" type="REQUIRE_THAT" filename="projects/<exe-name>/UsageTests/Matchers.tests.cpp" >
+ <Original>
+ -0.f, WithinRel(0.f)
+ </Original>
+ <Expanded>
+ -0.0f and 0 are within 0.00119209% of each other
+ </Expanded>
+ </Expression>
+ <Section name="Some subnormal values" filename="projects/<exe-name>/UsageTests/Matchers.tests.cpp" >
+ <Expression success="true" type="REQUIRE_THAT" filename="projects/<exe-name>/UsageTests/Matchers.tests.cpp" >
+ <Original>
+ v1, WithinRel(v2)
+ </Original>
+ <Expanded>
+ 0.0f and 1.17549e-38 are within 0.00119209% of each other
+ </Expanded>
+ </Expression>
+ <OverallResults successes="1" failures="0" expectedFailures="0"/>
+ </Section>
+ <OverallResults successes="5" failures="0" expectedFailures="0"/>
+ </Section>
<Section name="Margin" filename="projects/<exe-name>/UsageTests/Matchers.tests.cpp" >
<Expression success="true" type="REQUIRE_THAT" filename="projects/<exe-name>/UsageTests/Matchers.tests.cpp" >
<Original>
@@ -3410,14 +4053,6 @@ Nor would this
</Expression>
<Expression success="true" type="REQUIRE_THAT" filename="projects/<exe-name>/UsageTests/Matchers.tests.cpp" >
<Original>
- NAN, !WithinAbs(NAN, 0)
- </Original>
- <Expanded>
- nanf not is within 0.0 of nan
- </Expanded>
- </Expression>
- <Expression success="true" type="REQUIRE_THAT" filename="projects/<exe-name>/UsageTests/Matchers.tests.cpp" >
- <Original>
11.f, !WithinAbs(10.f, 0.5f)
</Original>
<Expanded>
@@ -3448,7 +4083,7 @@ Nor would this
-10.0f is within 0.5 of -9.6000003815
</Expanded>
</Expression>
- <OverallResults successes="10" failures="0" expectedFailures="0"/>
+ <OverallResults successes="9" failures="0" expectedFailures="0"/>
</Section>
<Section name="ULPs" filename="projects/<exe-name>/UsageTests/Matchers.tests.cpp" >
<Expression success="true" type="REQUIRE_THAT" filename="projects/<exe-name>/UsageTests/Matchers.tests.cpp" >
@@ -3456,7 +4091,7 @@ Nor would this
1.f, WithinULP(1.f, 0)
</Original>
<Expanded>
- 1.0f is within 0 ULPs of 1.0f
+ 1.0f is within 0 ULPs of 1.00000000e+00f ([1.00000000e+00, 1.00000000e+00])
</Expanded>
</Expression>
<Expression success="true" type="REQUIRE_THAT" filename="projects/<exe-name>/UsageTests/Matchers.tests.cpp" >
@@ -3464,47 +4099,47 @@ Nor would this
nextafter(1.f, 2.f), WithinULP(1.f, 1)
</Original>
<Expanded>
- 1.0f is within 1 ULPs of 1.0f
+ 1.0f is within 1 ULPs of 1.00000000e+00f ([9.99999940e-01, 1.00000012e+00])
</Expanded>
</Expression>
<Expression success="true" type="REQUIRE_THAT" filename="projects/<exe-name>/UsageTests/Matchers.tests.cpp" >
<Original>
- nextafter(1.f, 0.f), WithinULP(1.f, 1)
+ 0.f, WithinULP(nextafter(0.f, 1.f), 1)
</Original>
<Expanded>
- 1.0f is within 1 ULPs of 1.0f
+ 0.0f is within 1 ULPs of 1.40129846e-45f ([0.00000000e+00, 2.80259693e-45])
</Expanded>
</Expression>
<Expression success="true" type="REQUIRE_THAT" filename="projects/<exe-name>/UsageTests/Matchers.tests.cpp" >
<Original>
- nextafter(1.f, 2.f), !WithinULP(1.f, 0)
+ 1.f, WithinULP(nextafter(1.f, 0.f), 1)
</Original>
<Expanded>
- 1.0f not is within 0 ULPs of 1.0f
+ 1.0f is within 1 ULPs of 9.99999940e-01f ([9.99999881e-01, 1.00000000e+00])
</Expanded>
</Expression>
<Expression success="true" type="REQUIRE_THAT" filename="projects/<exe-name>/UsageTests/Matchers.tests.cpp" >
<Original>
- 1.f, WithinULP(1.f, 0)
+ 1.f, !WithinULP(nextafter(1.f, 2.f), 0)
</Original>
<Expanded>
- 1.0f is within 0 ULPs of 1.0f
+ 1.0f not is within 0 ULPs of 1.00000012e+00f ([1.00000012e+00, 1.00000012e+00])
</Expanded>
</Expression>
<Expression success="true" type="REQUIRE_THAT" filename="projects/<exe-name>/UsageTests/Matchers.tests.cpp" >
<Original>
- -0.f, WithinULP(0.f, 0)
+ 1.f, WithinULP(1.f, 0)
</Original>
<Expanded>
- -0.0f is within 0 ULPs of 0.0f
+ 1.0f is within 0 ULPs of 1.00000000e+00f ([1.00000000e+00, 1.00000000e+00])
</Expanded>
</Expression>
<Expression success="true" type="REQUIRE_THAT" filename="projects/<exe-name>/UsageTests/Matchers.tests.cpp" >
<Original>
- NAN, !WithinULP(NAN, 123)
+ -0.f, WithinULP(0.f, 0)
</Original>
<Expanded>
- nanf not is within 123 ULPs of nanf
+ -0.0f is within 0 ULPs of 0.00000000e+00f ([0.00000000e+00, 0.00000000e+00])
</Expanded>
</Expression>
<OverallResults successes="7" failures="0" expectedFailures="0"/>
@@ -3515,7 +4150,7 @@ Nor would this
1.f, WithinAbs(1.f, 0.5) || WithinULP(1.f, 1)
</Original>
<Expanded>
- 1.0f ( is within 0.5 of 1.0 or is within 1 ULPs of 1.0f )
+ 1.0f ( is within 0.5 of 1.0 or is within 1 ULPs of 1.00000000e+00f ([9.99999940e-01, 1.00000012e+00]) )
</Expanded>
</Expression>
<Expression success="true" type="REQUIRE_THAT" filename="projects/<exe-name>/UsageTests/Matchers.tests.cpp" >
@@ -3523,15 +4158,15 @@ Nor would this
1.f, WithinAbs(2.f, 0.5) || WithinULP(1.f, 0)
</Original>
<Expanded>
- 1.0f ( is within 0.5 of 2.0 or is within 0 ULPs of 1.0f )
+ 1.0f ( is within 0.5 of 2.0 or is within 0 ULPs of 1.00000000e+00f ([1.00000000e+00, 1.00000000e+00]) )
</Expanded>
</Expression>
<Expression success="true" type="REQUIRE_THAT" filename="projects/<exe-name>/UsageTests/Matchers.tests.cpp" >
<Original>
- NAN, !(WithinAbs(NAN, 100) || WithinULP(NAN, 123))
+ 0.0001f, WithinAbs(0.f, 0.001f) || WithinRel(0.f, 0.1f)
</Original>
<Expanded>
- nanf not ( is within 100.0 of nan or is within 123 ULPs of nanf )
+ 0.0001f ( is within 0.001 of 0.0 or and 0 are within 10% of each other )
</Expanded>
</Expression>
<OverallResults successes="3" failures="0" expectedFailures="0"/>
@@ -3563,13 +4198,37 @@ Nor would this
</Expression>
<Expression success="true" type="REQUIRE_THROWS_AS" filename="projects/<exe-name>/UsageTests/Matchers.tests.cpp" >
<Original>
- WithinULP(1.f, -1), std::domain_error
+ WithinULP(1.f, static_cast&lt;uint64_t>(-1)), std::domain_error
</Original>
<Expanded>
- WithinULP(1.f, -1), std::domain_error
+ WithinULP(1.f, static_cast&lt;uint64_t>(-1)), std::domain_error
</Expanded>
</Expression>
- <OverallResults successes="4" failures="0" expectedFailures="0"/>
+ <Expression success="true" type="REQUIRE_NOTHROW" filename="projects/<exe-name>/UsageTests/Matchers.tests.cpp" >
+ <Original>
+ WithinRel(1.f, 0.f)
+ </Original>
+ <Expanded>
+ WithinRel(1.f, 0.f)
+ </Expanded>
+ </Expression>
+ <Expression success="true" type="REQUIRE_THROWS_AS" filename="projects/<exe-name>/UsageTests/Matchers.tests.cpp" >
+ <Original>
+ WithinRel(1.f, -0.2f), std::domain_error
+ </Original>
+ <Expanded>
+ WithinRel(1.f, -0.2f), std::domain_error
+ </Expanded>
+ </Expression>
+ <Expression success="true" type="REQUIRE_THROWS_AS" filename="projects/<exe-name>/UsageTests/Matchers.tests.cpp" >
+ <Original>
+ WithinRel(1.f, 1.f), std::domain_error
+ </Original>
+ <Expanded>
+ WithinRel(1.f, 1.f), std::domain_error
+ </Expanded>
+ </Expression>
+ <OverallResults successes="7" failures="0" expectedFailures="0"/>
</Section>
<OverallResult success="true"/>
</TestCase>
@@ -3982,6 +4641,48 @@ Nor would this
<OverallResults successes="3" failures="0" expectedFailures="0"/>
</Section>
<Section name="Chunking a generator into sized pieces" filename="projects/<exe-name>/UsageTests/Generators.tests.cpp" >
+ <Section name="Chunk size of zero" filename="projects/<exe-name>/UsageTests/Generators.tests.cpp" >
+ <Expression success="true" type="REQUIRE" filename="projects/<exe-name>/UsageTests/Generators.tests.cpp" >
+ <Original>
+ chunk2.size() == 0
+ </Original>
+ <Expanded>
+ 0 == 0
+ </Expanded>
+ </Expression>
+ <OverallResults successes="1" failures="0" expectedFailures="0"/>
+ </Section>
+ <OverallResults successes="1" failures="0" expectedFailures="0"/>
+ </Section>
+ <Section name="Chunking a generator into sized pieces" filename="projects/<exe-name>/UsageTests/Generators.tests.cpp" >
+ <Section name="Chunk size of zero" filename="projects/<exe-name>/UsageTests/Generators.tests.cpp" >
+ <Expression success="true" type="REQUIRE" filename="projects/<exe-name>/UsageTests/Generators.tests.cpp" >
+ <Original>
+ chunk2.size() == 0
+ </Original>
+ <Expanded>
+ 0 == 0
+ </Expanded>
+ </Expression>
+ <OverallResults successes="1" failures="0" expectedFailures="0"/>
+ </Section>
+ <OverallResults successes="1" failures="0" expectedFailures="0"/>
+ </Section>
+ <Section name="Chunking a generator into sized pieces" filename="projects/<exe-name>/UsageTests/Generators.tests.cpp" >
+ <Section name="Chunk size of zero" filename="projects/<exe-name>/UsageTests/Generators.tests.cpp" >
+ <Expression success="true" type="REQUIRE" filename="projects/<exe-name>/UsageTests/Generators.tests.cpp" >
+ <Original>
+ chunk2.size() == 0
+ </Original>
+ <Expanded>
+ 0 == 0
+ </Expanded>
+ </Expression>
+ <OverallResults successes="1" failures="0" expectedFailures="0"/>
+ </Section>
+ <OverallResults successes="1" failures="0" expectedFailures="0"/>
+ </Section>
+ <Section name="Chunking a generator into sized pieces" filename="projects/<exe-name>/UsageTests/Generators.tests.cpp" >
<Section name="Throws on too small generators" filename="projects/<exe-name>/UsageTests/Generators.tests.cpp" >
<Expression success="true" type="REQUIRE_THROWS_AS" filename="projects/<exe-name>/UsageTests/Generators.tests.cpp" >
<Original>
@@ -5131,6 +5832,778 @@ Nor would this
<OverallResults successes="10" failures="0" expectedFailures="0"/>
</Section>
<Section name="Range" filename="projects/<exe-name>/IntrospectiveTests/GeneratorsImpl.tests.cpp" >
+ <Section name="Positive manual step" filename="projects/<exe-name>/IntrospectiveTests/GeneratorsImpl.tests.cpp" >
+ <Section name="Floating Point" filename="projects/<exe-name>/IntrospectiveTests/GeneratorsImpl.tests.cpp" >
+ <Section name="Exact" filename="projects/<exe-name>/IntrospectiveTests/GeneratorsImpl.tests.cpp" >
+ <Info>
+ Current expected value is -1
+ </Info>
+ <Expression success="true" type="REQUIRE" filename="projects/<exe-name>/IntrospectiveTests/GeneratorsImpl.tests.cpp" >
+ <Original>
+ gen.get() == Approx(expected)
+ </Original>
+ <Expanded>
+ -1.0 == Approx( -1.0 )
+ </Expanded>
+ </Expression>
+ <Info>
+ Current expected value is -1
+ </Info>
+ <Expression success="true" type="REQUIRE" filename="projects/<exe-name>/IntrospectiveTests/GeneratorsImpl.tests.cpp" >
+ <Original>
+ gen.next()
+ </Original>
+ <Expanded>
+ true
+ </Expanded>
+ </Expression>
+ <Info>
+ Current expected value is -0.9
+ </Info>
+ <Expression success="true" type="REQUIRE" filename="projects/<exe-name>/IntrospectiveTests/GeneratorsImpl.tests.cpp" >
+ <Original>
+ gen.get() == Approx(expected)
+ </Original>
+ <Expanded>
+ -0.9 == Approx( -0.9 )
+ </Expanded>
+ </Expression>
+ <Info>
+ Current expected value is -0.9
+ </Info>
+ <Expression success="true" type="REQUIRE" filename="projects/<exe-name>/IntrospectiveTests/GeneratorsImpl.tests.cpp" >
+ <Original>
+ gen.next()
+ </Original>
+ <Expanded>
+ true
+ </Expanded>
+ </Expression>
+ <Info>
+ Current expected value is -0.8
+ </Info>
+ <Expression success="true" type="REQUIRE" filename="projects/<exe-name>/IntrospectiveTests/GeneratorsImpl.tests.cpp" >
+ <Original>
+ gen.get() == Approx(expected)
+ </Original>
+ <Expanded>
+ -0.8 == Approx( -0.8 )
+ </Expanded>
+ </Expression>
+ <Info>
+ Current expected value is -0.8
+ </Info>
+ <Expression success="true" type="REQUIRE" filename="projects/<exe-name>/IntrospectiveTests/GeneratorsImpl.tests.cpp" >
+ <Original>
+ gen.next()
+ </Original>
+ <Expanded>
+ true
+ </Expanded>
+ </Expression>
+ <Info>
+ Current expected value is -0.7
+ </Info>
+ <Expression success="true" type="REQUIRE" filename="projects/<exe-name>/IntrospectiveTests/GeneratorsImpl.tests.cpp" >
+ <Original>
+ gen.get() == Approx(expected)
+ </Original>
+ <Expanded>
+ -0.7 == Approx( -0.7 )
+ </Expanded>
+ </Expression>
+ <Info>
+ Current expected value is -0.7
+ </Info>
+ <Expression success="true" type="REQUIRE" filename="projects/<exe-name>/IntrospectiveTests/GeneratorsImpl.tests.cpp" >
+ <Original>
+ gen.next()
+ </Original>
+ <Expanded>
+ true
+ </Expanded>
+ </Expression>
+ <Info>
+ Current expected value is -0.6
+ </Info>
+ <Expression success="true" type="REQUIRE" filename="projects/<exe-name>/IntrospectiveTests/GeneratorsImpl.tests.cpp" >
+ <Original>
+ gen.get() == Approx(expected)
+ </Original>
+ <Expanded>
+ -0.6 == Approx( -0.6 )
+ </Expanded>
+ </Expression>
+ <Info>
+ Current expected value is -0.6
+ </Info>
+ <Expression success="true" type="REQUIRE" filename="projects/<exe-name>/IntrospectiveTests/GeneratorsImpl.tests.cpp" >
+ <Original>
+ gen.next()
+ </Original>
+ <Expanded>
+ true
+ </Expanded>
+ </Expression>
+ <Info>
+ Current expected value is -0.5
+ </Info>
+ <Expression success="true" type="REQUIRE" filename="projects/<exe-name>/IntrospectiveTests/GeneratorsImpl.tests.cpp" >
+ <Original>
+ gen.get() == Approx(expected)
+ </Original>
+ <Expanded>
+ -0.5 == Approx( -0.5 )
+ </Expanded>
+ </Expression>
+ <Info>
+ Current expected value is -0.5
+ </Info>
+ <Expression success="true" type="REQUIRE" filename="projects/<exe-name>/IntrospectiveTests/GeneratorsImpl.tests.cpp" >
+ <Original>
+ gen.next()
+ </Original>
+ <Expanded>
+ true
+ </Expanded>
+ </Expression>
+ <Info>
+ Current expected value is -0.4
+ </Info>
+ <Expression success="true" type="REQUIRE" filename="projects/<exe-name>/IntrospectiveTests/GeneratorsImpl.tests.cpp" >
+ <Original>
+ gen.get() == Approx(expected)
+ </Original>
+ <Expanded>
+ -0.4 == Approx( -0.4 )
+ </Expanded>
+ </Expression>
+ <Info>
+ Current expected value is -0.4
+ </Info>
+ <Expression success="true" type="REQUIRE" filename="projects/<exe-name>/IntrospectiveTests/GeneratorsImpl.tests.cpp" >
+ <Original>
+ gen.next()
+ </Original>
+ <Expanded>
+ true
+ </Expanded>
+ </Expression>
+ <Info>
+ Current expected value is -0.3
+ </Info>
+ <Expression success="true" type="REQUIRE" filename="projects/<exe-name>/IntrospectiveTests/GeneratorsImpl.tests.cpp" >
+ <Original>
+ gen.get() == Approx(expected)
+ </Original>
+ <Expanded>
+ -0.3 == Approx( -0.3 )
+ </Expanded>
+ </Expression>
+ <Info>
+ Current expected value is -0.3
+ </Info>
+ <Expression success="true" type="REQUIRE" filename="projects/<exe-name>/IntrospectiveTests/GeneratorsImpl.tests.cpp" >
+ <Original>
+ gen.next()
+ </Original>
+ <Expanded>
+ true
+ </Expanded>
+ </Expression>
+ <Info>
+ Current expected value is -0.2
+ </Info>
+ <Expression success="true" type="REQUIRE" filename="projects/<exe-name>/IntrospectiveTests/GeneratorsImpl.tests.cpp" >
+ <Original>
+ gen.get() == Approx(expected)
+ </Original>
+ <Expanded>
+ -0.2 == Approx( -0.2 )
+ </Expanded>
+ </Expression>
+ <Info>
+ Current expected value is -0.2
+ </Info>
+ <Expression success="true" type="REQUIRE" filename="projects/<exe-name>/IntrospectiveTests/GeneratorsImpl.tests.cpp" >
+ <Original>
+ gen.next()
+ </Original>
+ <Expanded>
+ true
+ </Expanded>
+ </Expression>
+ <Info>
+ Current expected value is -0.1
+ </Info>
+ <Expression success="true" type="REQUIRE" filename="projects/<exe-name>/IntrospectiveTests/GeneratorsImpl.tests.cpp" >
+ <Original>
+ gen.get() == Approx(expected)
+ </Original>
+ <Expanded>
+ -0.1 == Approx( -0.1 )
+ </Expanded>
+ </Expression>
+ <Info>
+ Current expected value is -0.1
+ </Info>
+ <Expression success="true" type="REQUIRE" filename="projects/<exe-name>/IntrospectiveTests/GeneratorsImpl.tests.cpp" >
+ <Original>
+ gen.next()
+ </Original>
+ <Expanded>
+ true
+ </Expanded>
+ </Expression>
+ <Info>
+ Current expected value is -1.38778e-16
+ </Info>
+ <Expression success="true" type="REQUIRE" filename="projects/<exe-name>/IntrospectiveTests/GeneratorsImpl.tests.cpp" >
+ <Original>
+ gen.get() == Approx(expected)
+ </Original>
+ <Expanded>
+ -0.0 == Approx( -0.0 )
+ </Expanded>
+ </Expression>
+ <Info>
+ Current expected value is -1.38778e-16
+ </Info>
+ <Expression success="true" type="REQUIRE" filename="projects/<exe-name>/IntrospectiveTests/GeneratorsImpl.tests.cpp" >
+ <Original>
+ gen.next()
+ </Original>
+ <Expanded>
+ true
+ </Expanded>
+ </Expression>
+ <Info>
+ Current expected value is 0.1
+ </Info>
+ <Expression success="true" type="REQUIRE" filename="projects/<exe-name>/IntrospectiveTests/GeneratorsImpl.tests.cpp" >
+ <Original>
+ gen.get() == Approx(expected)
+ </Original>
+ <Expanded>
+ 0.1 == Approx( 0.1 )
+ </Expanded>
+ </Expression>
+ <Info>
+ Current expected value is 0.1
+ </Info>
+ <Expression success="true" type="REQUIRE" filename="projects/<exe-name>/IntrospectiveTests/GeneratorsImpl.tests.cpp" >
+ <Original>
+ gen.next()
+ </Original>
+ <Expanded>
+ true
+ </Expanded>
+ </Expression>
+ <Info>
+ Current expected value is 0.2
+ </Info>
+ <Expression success="true" type="REQUIRE" filename="projects/<exe-name>/IntrospectiveTests/GeneratorsImpl.tests.cpp" >
+ <Original>
+ gen.get() == Approx(expected)
+ </Original>
+ <Expanded>
+ 0.2 == Approx( 0.2 )
+ </Expanded>
+ </Expression>
+ <Info>
+ Current expected value is 0.2
+ </Info>
+ <Expression success="true" type="REQUIRE" filename="projects/<exe-name>/IntrospectiveTests/GeneratorsImpl.tests.cpp" >
+ <Original>
+ gen.next()
+ </Original>
+ <Expanded>
+ true
+ </Expanded>
+ </Expression>
+ <Info>
+ Current expected value is 0.3
+ </Info>
+ <Expression success="true" type="REQUIRE" filename="projects/<exe-name>/IntrospectiveTests/GeneratorsImpl.tests.cpp" >
+ <Original>
+ gen.get() == Approx(expected)
+ </Original>
+ <Expanded>
+ 0.3 == Approx( 0.3 )
+ </Expanded>
+ </Expression>
+ <Info>
+ Current expected value is 0.3
+ </Info>
+ <Expression success="true" type="REQUIRE" filename="projects/<exe-name>/IntrospectiveTests/GeneratorsImpl.tests.cpp" >
+ <Original>
+ gen.next()
+ </Original>
+ <Expanded>
+ true
+ </Expanded>
+ </Expression>
+ <Info>
+ Current expected value is 0.4
+ </Info>
+ <Expression success="true" type="REQUIRE" filename="projects/<exe-name>/IntrospectiveTests/GeneratorsImpl.tests.cpp" >
+ <Original>
+ gen.get() == Approx(expected)
+ </Original>
+ <Expanded>
+ 0.4 == Approx( 0.4 )
+ </Expanded>
+ </Expression>
+ <Info>
+ Current expected value is 0.4
+ </Info>
+ <Expression success="true" type="REQUIRE" filename="projects/<exe-name>/IntrospectiveTests/GeneratorsImpl.tests.cpp" >
+ <Original>
+ gen.next()
+ </Original>
+ <Expanded>
+ true
+ </Expanded>
+ </Expression>
+ <Info>
+ Current expected value is 0.5
+ </Info>
+ <Expression success="true" type="REQUIRE" filename="projects/<exe-name>/IntrospectiveTests/GeneratorsImpl.tests.cpp" >
+ <Original>
+ gen.get() == Approx(expected)
+ </Original>
+ <Expanded>
+ 0.5 == Approx( 0.5 )
+ </Expanded>
+ </Expression>
+ <Info>
+ Current expected value is 0.5
+ </Info>
+ <Expression success="true" type="REQUIRE" filename="projects/<exe-name>/IntrospectiveTests/GeneratorsImpl.tests.cpp" >
+ <Original>
+ gen.next()
+ </Original>
+ <Expanded>
+ true
+ </Expanded>
+ </Expression>
+ <Info>
+ Current expected value is 0.6
+ </Info>
+ <Expression success="true" type="REQUIRE" filename="projects/<exe-name>/IntrospectiveTests/GeneratorsImpl.tests.cpp" >
+ <Original>
+ gen.get() == Approx(expected)
+ </Original>
+ <Expanded>
+ 0.6 == Approx( 0.6 )
+ </Expanded>
+ </Expression>
+ <Info>
+ Current expected value is 0.6
+ </Info>
+ <Expression success="true" type="REQUIRE" filename="projects/<exe-name>/IntrospectiveTests/GeneratorsImpl.tests.cpp" >
+ <Original>
+ gen.next()
+ </Original>
+ <Expanded>
+ true
+ </Expanded>
+ </Expression>
+ <Info>
+ Current expected value is 0.7
+ </Info>
+ <Expression success="true" type="REQUIRE" filename="projects/<exe-name>/IntrospectiveTests/GeneratorsImpl.tests.cpp" >
+ <Original>
+ gen.get() == Approx(expected)
+ </Original>
+ <Expanded>
+ 0.7 == Approx( 0.7 )
+ </Expanded>
+ </Expression>
+ <Info>
+ Current expected value is 0.7
+ </Info>
+ <Expression success="true" type="REQUIRE" filename="projects/<exe-name>/IntrospectiveTests/GeneratorsImpl.tests.cpp" >
+ <Original>
+ gen.next()
+ </Original>
+ <Expanded>
+ true
+ </Expanded>
+ </Expression>
+ <Info>
+ Current expected value is 0.8
+ </Info>
+ <Expression success="true" type="REQUIRE" filename="projects/<exe-name>/IntrospectiveTests/GeneratorsImpl.tests.cpp" >
+ <Original>
+ gen.get() == Approx(expected)
+ </Original>
+ <Expanded>
+ 0.8 == Approx( 0.8 )
+ </Expanded>
+ </Expression>
+ <Info>
+ Current expected value is 0.8
+ </Info>
+ <Expression success="true" type="REQUIRE" filename="projects/<exe-name>/IntrospectiveTests/GeneratorsImpl.tests.cpp" >
+ <Original>
+ gen.next()
+ </Original>
+ <Expanded>
+ true
+ </Expanded>
+ </Expression>
+ <Info>
+ Current expected value is 0.9
+ </Info>
+ <Expression success="true" type="REQUIRE" filename="projects/<exe-name>/IntrospectiveTests/GeneratorsImpl.tests.cpp" >
+ <Original>
+ gen.get() == Approx(expected)
+ </Original>
+ <Expanded>
+ 0.9 == Approx( 0.9 )
+ </Expanded>
+ </Expression>
+ <Info>
+ Current expected value is 0.9
+ </Info>
+ <Expression success="true" type="REQUIRE" filename="projects/<exe-name>/IntrospectiveTests/GeneratorsImpl.tests.cpp" >
+ <Original>
+ gen.next()
+ </Original>
+ <Expanded>
+ true
+ </Expanded>
+ </Expression>
+ <Expression success="true" type="REQUIRE" filename="projects/<exe-name>/IntrospectiveTests/GeneratorsImpl.tests.cpp" >
+ <Original>
+ gen.get() == Approx( rangeEnd )
+ </Original>
+ <Expanded>
+ 1.0 == Approx( 1.0 )
+ </Expanded>
+ </Expression>
+ <Expression success="true" type="REQUIRE_FALSE" filename="projects/<exe-name>/IntrospectiveTests/GeneratorsImpl.tests.cpp" >
+ <Original>
+ !(gen.next())
+ </Original>
+ <Expanded>
+ !false
+ </Expanded>
+ </Expression>
+ <OverallResults successes="42" failures="0" expectedFailures="0"/>
+ </Section>
+ <OverallResults successes="42" failures="0" expectedFailures="0"/>
+ </Section>
+ <OverallResults successes="42" failures="0" expectedFailures="0"/>
+ </Section>
+ <OverallResults successes="42" failures="0" expectedFailures="0"/>
+ </Section>
+ <Section name="Range" filename="projects/<exe-name>/IntrospectiveTests/GeneratorsImpl.tests.cpp" >
+ <Section name="Positive manual step" filename="projects/<exe-name>/IntrospectiveTests/GeneratorsImpl.tests.cpp" >
+ <Section name="Floating Point" filename="projects/<exe-name>/IntrospectiveTests/GeneratorsImpl.tests.cpp" >
+ <Section name="Slightly over end" filename="projects/<exe-name>/IntrospectiveTests/GeneratorsImpl.tests.cpp" >
+ <Info>
+ Current expected value is -1
+ </Info>
+ <Expression success="true" type="REQUIRE" filename="projects/<exe-name>/IntrospectiveTests/GeneratorsImpl.tests.cpp" >
+ <Original>
+ gen.get() == Approx(expected)
+ </Original>
+ <Expanded>
+ -1.0 == Approx( -1.0 )
+ </Expanded>
+ </Expression>
+ <Info>
+ Current expected value is -1
+ </Info>
+ <Expression success="true" type="REQUIRE" filename="projects/<exe-name>/IntrospectiveTests/GeneratorsImpl.tests.cpp" >
+ <Original>
+ gen.next()
+ </Original>
+ <Expanded>
+ true
+ </Expanded>
+ </Expression>
+ <Info>
+ Current expected value is -0.7
+ </Info>
+ <Expression success="true" type="REQUIRE" filename="projects/<exe-name>/IntrospectiveTests/GeneratorsImpl.tests.cpp" >
+ <Original>
+ gen.get() == Approx(expected)
+ </Original>
+ <Expanded>
+ -0.7 == Approx( -0.7 )
+ </Expanded>
+ </Expression>
+ <Info>
+ Current expected value is -0.7
+ </Info>
+ <Expression success="true" type="REQUIRE" filename="projects/<exe-name>/IntrospectiveTests/GeneratorsImpl.tests.cpp" >
+ <Original>
+ gen.next()
+ </Original>
+ <Expanded>
+ true
+ </Expanded>
+ </Expression>
+ <Info>
+ Current expected value is -0.4
+ </Info>
+ <Expression success="true" type="REQUIRE" filename="projects/<exe-name>/IntrospectiveTests/GeneratorsImpl.tests.cpp" >
+ <Original>
+ gen.get() == Approx(expected)
+ </Original>
+ <Expanded>
+ -0.4 == Approx( -0.4 )
+ </Expanded>
+ </Expression>
+ <Info>
+ Current expected value is -0.4
+ </Info>
+ <Expression success="true" type="REQUIRE" filename="projects/<exe-name>/IntrospectiveTests/GeneratorsImpl.tests.cpp" >
+ <Original>
+ gen.next()
+ </Original>
+ <Expanded>
+ true
+ </Expanded>
+ </Expression>
+ <Info>
+ Current expected value is -0.1
+ </Info>
+ <Expression success="true" type="REQUIRE" filename="projects/<exe-name>/IntrospectiveTests/GeneratorsImpl.tests.cpp" >
+ <Original>
+ gen.get() == Approx(expected)
+ </Original>
+ <Expanded>
+ -0.1 == Approx( -0.1 )
+ </Expanded>
+ </Expression>
+ <Info>
+ Current expected value is -0.1
+ </Info>
+ <Expression success="true" type="REQUIRE" filename="projects/<exe-name>/IntrospectiveTests/GeneratorsImpl.tests.cpp" >
+ <Original>
+ gen.next()
+ </Original>
+ <Expanded>
+ true
+ </Expanded>
+ </Expression>
+ <Info>
+ Current expected value is 0.2
+ </Info>
+ <Expression success="true" type="REQUIRE" filename="projects/<exe-name>/IntrospectiveTests/GeneratorsImpl.tests.cpp" >
+ <Original>
+ gen.get() == Approx(expected)
+ </Original>
+ <Expanded>
+ 0.2 == Approx( 0.2 )
+ </Expanded>
+ </Expression>
+ <Info>
+ Current expected value is 0.2
+ </Info>
+ <Expression success="true" type="REQUIRE" filename="projects/<exe-name>/IntrospectiveTests/GeneratorsImpl.tests.cpp" >
+ <Original>
+ gen.next()
+ </Original>
+ <Expanded>
+ true
+ </Expanded>
+ </Expression>
+ <Info>
+ Current expected value is 0.5
+ </Info>
+ <Expression success="true" type="REQUIRE" filename="projects/<exe-name>/IntrospectiveTests/GeneratorsImpl.tests.cpp" >
+ <Original>
+ gen.get() == Approx(expected)
+ </Original>
+ <Expanded>
+ 0.5 == Approx( 0.5 )
+ </Expanded>
+ </Expression>
+ <Info>
+ Current expected value is 0.5
+ </Info>
+ <Expression success="true" type="REQUIRE" filename="projects/<exe-name>/IntrospectiveTests/GeneratorsImpl.tests.cpp" >
+ <Original>
+ gen.next()
+ </Original>
+ <Expanded>
+ true
+ </Expanded>
+ </Expression>
+ <Expression success="true" type="REQUIRE_FALSE" filename="projects/<exe-name>/IntrospectiveTests/GeneratorsImpl.tests.cpp" >
+ <Original>
+ !(gen.next())
+ </Original>
+ <Expanded>
+ !false
+ </Expanded>
+ </Expression>
+ <OverallResults successes="13" failures="0" expectedFailures="0"/>
+ </Section>
+ <OverallResults successes="13" failures="0" expectedFailures="0"/>
+ </Section>
+ <OverallResults successes="13" failures="0" expectedFailures="0"/>
+ </Section>
+ <OverallResults successes="13" failures="0" expectedFailures="0"/>
+ </Section>
+ <Section name="Range" filename="projects/<exe-name>/IntrospectiveTests/GeneratorsImpl.tests.cpp" >
+ <Section name="Positive manual step" filename="projects/<exe-name>/IntrospectiveTests/GeneratorsImpl.tests.cpp" >
+ <Section name="Floating Point" filename="projects/<exe-name>/IntrospectiveTests/GeneratorsImpl.tests.cpp" >
+ <Section name="Slightly under end" filename="projects/<exe-name>/IntrospectiveTests/GeneratorsImpl.tests.cpp" >
+ <Info>
+ Current expected value is -1
+ </Info>
+ <Expression success="true" type="REQUIRE" filename="projects/<exe-name>/IntrospectiveTests/GeneratorsImpl.tests.cpp" >
+ <Original>
+ gen.get() == Approx(expected)
+ </Original>
+ <Expanded>
+ -1.0 == Approx( -1.0 )
+ </Expanded>
+ </Expression>
+ <Info>
+ Current expected value is -1
+ </Info>
+ <Expression success="true" type="REQUIRE" filename="projects/<exe-name>/IntrospectiveTests/GeneratorsImpl.tests.cpp" >
+ <Original>
+ gen.next()
+ </Original>
+ <Expanded>
+ true
+ </Expanded>
+ </Expression>
+ <Info>
+ Current expected value is -0.7
+ </Info>
+ <Expression success="true" type="REQUIRE" filename="projects/<exe-name>/IntrospectiveTests/GeneratorsImpl.tests.cpp" >
+ <Original>
+ gen.get() == Approx(expected)
+ </Original>
+ <Expanded>
+ -0.7 == Approx( -0.7 )
+ </Expanded>
+ </Expression>
+ <Info>
+ Current expected value is -0.7
+ </Info>
+ <Expression success="true" type="REQUIRE" filename="projects/<exe-name>/IntrospectiveTests/GeneratorsImpl.tests.cpp" >
+ <Original>
+ gen.next()
+ </Original>
+ <Expanded>
+ true
+ </Expanded>
+ </Expression>
+ <Info>
+ Current expected value is -0.4
+ </Info>
+ <Expression success="true" type="REQUIRE" filename="projects/<exe-name>/IntrospectiveTests/GeneratorsImpl.tests.cpp" >
+ <Original>
+ gen.get() == Approx(expected)
+ </Original>
+ <Expanded>
+ -0.4 == Approx( -0.4 )
+ </Expanded>
+ </Expression>
+ <Info>
+ Current expected value is -0.4
+ </Info>
+ <Expression success="true" type="REQUIRE" filename="projects/<exe-name>/IntrospectiveTests/GeneratorsImpl.tests.cpp" >
+ <Original>
+ gen.next()
+ </Original>
+ <Expanded>
+ true
+ </Expanded>
+ </Expression>
+ <Info>
+ Current expected value is -0.1
+ </Info>
+ <Expression success="true" type="REQUIRE" filename="projects/<exe-name>/IntrospectiveTests/GeneratorsImpl.tests.cpp" >
+ <Original>
+ gen.get() == Approx(expected)
+ </Original>
+ <Expanded>
+ -0.1 == Approx( -0.1 )
+ </Expanded>
+ </Expression>
+ <Info>
+ Current expected value is -0.1
+ </Info>
+ <Expression success="true" type="REQUIRE" filename="projects/<exe-name>/IntrospectiveTests/GeneratorsImpl.tests.cpp" >
+ <Original>
+ gen.next()
+ </Original>
+ <Expanded>
+ true
+ </Expanded>
+ </Expression>
+ <Info>
+ Current expected value is 0.2
+ </Info>
+ <Expression success="true" type="REQUIRE" filename="projects/<exe-name>/IntrospectiveTests/GeneratorsImpl.tests.cpp" >
+ <Original>
+ gen.get() == Approx(expected)
+ </Original>
+ <Expanded>
+ 0.2 == Approx( 0.2 )
+ </Expanded>
+ </Expression>
+ <Info>
+ Current expected value is 0.2
+ </Info>
+ <Expression success="true" type="REQUIRE" filename="projects/<exe-name>/IntrospectiveTests/GeneratorsImpl.tests.cpp" >
+ <Original>
+ gen.next()
+ </Original>
+ <Expanded>
+ true
+ </Expanded>
+ </Expression>
+ <Info>
+ Current expected value is 0.5
+ </Info>
+ <Expression success="true" type="REQUIRE" filename="projects/<exe-name>/IntrospectiveTests/GeneratorsImpl.tests.cpp" >
+ <Original>
+ gen.get() == Approx(expected)
+ </Original>
+ <Expanded>
+ 0.5 == Approx( 0.5 )
+ </Expanded>
+ </Expression>
+ <Info>
+ Current expected value is 0.5
+ </Info>
+ <Expression success="true" type="REQUIRE" filename="projects/<exe-name>/IntrospectiveTests/GeneratorsImpl.tests.cpp" >
+ <Original>
+ gen.next()
+ </Original>
+ <Expanded>
+ true
+ </Expanded>
+ </Expression>
+ <Expression success="true" type="REQUIRE_FALSE" filename="projects/<exe-name>/IntrospectiveTests/GeneratorsImpl.tests.cpp" >
+ <Original>
+ !(gen.next())
+ </Original>
+ <Expanded>
+ !false
+ </Expanded>
+ </Expression>
+ <OverallResults successes="13" failures="0" expectedFailures="0"/>
+ </Section>
+ <OverallResults successes="13" failures="0" expectedFailures="0"/>
+ </Section>
+ <OverallResults successes="13" failures="0" expectedFailures="0"/>
+ </Section>
+ <OverallResults successes="13" failures="0" expectedFailures="0"/>
+ </Section>
+ <Section name="Range" filename="projects/<exe-name>/IntrospectiveTests/GeneratorsImpl.tests.cpp" >
<Section name="Negative manual step" filename="projects/<exe-name>/IntrospectiveTests/GeneratorsImpl.tests.cpp" >
<Section name="Integer" filename="projects/<exe-name>/IntrospectiveTests/GeneratorsImpl.tests.cpp" >
<Section name="Exact" filename="projects/<exe-name>/IntrospectiveTests/GeneratorsImpl.tests.cpp" >
@@ -5411,7 +6884,7 @@ Nor would this
</Expression>
<OverallResult success="true"/>
</TestCase>
- <TestCase name="INFO and WARN do not abort tests" tags="[.][messages]" filename="projects/<exe-name>/UsageTests/Message.tests.cpp" >
+ <TestCase name="INFO and WARN do not abort tests" tags="[!hide][.][messages]" filename="projects/<exe-name>/UsageTests/Message.tests.cpp" >
<Info>
this is a message
</Info>
@@ -5420,7 +6893,7 @@ Nor would this
</Warning>
<OverallResult success="false"/>
</TestCase>
- <TestCase name="INFO gets logged on failure" tags="[.][failing][messages]" filename="projects/<exe-name>/UsageTests/Message.tests.cpp" >
+ <TestCase name="INFO gets logged on failure" tags="[!hide][.][failing][messages]" filename="projects/<exe-name>/UsageTests/Message.tests.cpp" >
<Info>
this message should be logged
</Info>
@@ -5437,7 +6910,7 @@ Nor would this
</Expression>
<OverallResult success="false"/>
</TestCase>
- <TestCase name="INFO gets logged on failure, even if captured before successful assertions" tags="[.][failing][messages]" filename="projects/<exe-name>/UsageTests/Message.tests.cpp" >
+ <TestCase name="INFO gets logged on failure, even if captured before successful assertions" tags="[!hide][.][failing][messages]" filename="projects/<exe-name>/UsageTests/Message.tests.cpp" >
<Info>
this message may be logged later
</Info>
@@ -5502,7 +6975,7 @@ Nor would this
</Expression>
<OverallResult success="false"/>
</TestCase>
- <TestCase name="INFO is reset for each loop" tags="[.][failing][messages]" filename="projects/<exe-name>/UsageTests/Message.tests.cpp" >
+ <TestCase name="INFO is reset for each loop" tags="[!hide][.][failing][messages]" filename="projects/<exe-name>/UsageTests/Message.tests.cpp" >
<Info>
current counter 0
</Info>
@@ -5659,7 +7132,7 @@ Nor would this
</Expression>
<OverallResult success="false"/>
</TestCase>
- <TestCase name="Inequality checks that should fail" tags="[!shouldfail][.][failing]" filename="projects/<exe-name>/UsageTests/Condition.tests.cpp" >
+ <TestCase name="Inequality checks that should fail" tags="[!hide][!shouldfail][.][failing]" filename="projects/<exe-name>/UsageTests/Condition.tests.cpp" >
<Expression success="false" type="CHECK" filename="projects/<exe-name>/UsageTests/Condition.tests.cpp" >
<Original>
data.int_seven != 7
@@ -5872,7 +7345,7 @@ Nor would this
</Expression>
<OverallResult success="true"/>
</TestCase>
- <TestCase name="Matchers can be composed with both &amp;&amp; and || - failing" tags="[.][failing][matchers][operator&amp;&amp;][operators][operator||]" filename="projects/<exe-name>/UsageTests/Matchers.tests.cpp" >
+ <TestCase name="Matchers can be composed with both &amp;&amp; and || - failing" tags="[!hide][.][failing][matchers][operator&amp;&amp;][operators][operator||]" filename="projects/<exe-name>/UsageTests/Matchers.tests.cpp" >
<Expression success="false" type="CHECK_THAT" filename="projects/<exe-name>/UsageTests/Matchers.tests.cpp" >
<Original>
testStringForMatching(), (Contains("string") || Contains("different")) &amp;&amp; Contains("random")
@@ -5894,7 +7367,7 @@ Nor would this
</Expression>
<OverallResult success="true"/>
</TestCase>
- <TestCase name="Matchers can be negated (Not) with the ! operator - failing" tags="[.][failing][matchers][not][operators]" filename="projects/<exe-name>/UsageTests/Matchers.tests.cpp" >
+ <TestCase name="Matchers can be negated (Not) with the ! operator - failing" tags="[!hide][.][failing][matchers][not][operators]" filename="projects/<exe-name>/UsageTests/Matchers.tests.cpp" >
<Expression success="false" type="CHECK_THAT" filename="projects/<exe-name>/UsageTests/Matchers.tests.cpp" >
<Original>
testStringForMatching(), !Contains("substring")
@@ -5905,7 +7378,7 @@ Nor would this
</Expression>
<OverallResult success="false"/>
</TestCase>
- <TestCase name="Mismatching exception messages failing the test" tags="[!throws][.][failing]" filename="projects/<exe-name>/UsageTests/Exception.tests.cpp" >
+ <TestCase name="Mismatching exception messages failing the test" tags="[!hide][!throws][.][failing]" filename="projects/<exe-name>/UsageTests/Exception.tests.cpp" >
<Expression success="true" type="REQUIRE_THROWS_WITH" filename="projects/<exe-name>/UsageTests/Exception.tests.cpp" >
<Original>
thisThrows(), "expected exception"
@@ -6055,13 +7528,13 @@ Nor would this
</Expression>
<OverallResult success="true"/>
</TestCase>
- <TestCase name="Nice descriptive name" tags="[.][tag1][tag2][tag3]" filename="projects/<exe-name>/UsageTests/Misc.tests.cpp" >
+ <TestCase name="Nice descriptive name" tags="[!hide][.][tag1][tag2][tag3]" filename="projects/<exe-name>/UsageTests/Misc.tests.cpp" >
<Warning>
This one ran
</Warning>
<OverallResult success="false"/>
</TestCase>
- <TestCase name="Non-std exceptions can be translated" tags="[!throws][.][failing]" filename="projects/<exe-name>/UsageTests/Exception.tests.cpp" >
+ <TestCase name="Non-std exceptions can be translated" tags="[!hide][!throws][.][failing]" filename="projects/<exe-name>/UsageTests/Exception.tests.cpp" >
<Exception filename="projects/<exe-name>/UsageTests/Exception.tests.cpp" >
custom exception
</Exception>
@@ -6097,7 +7570,7 @@ Nor would this
<TestCase name="Optionally static assertions" tags="[compilation]" filename="projects/<exe-name>/UsageTests/Compilation.tests.cpp" >
<OverallResult success="true"/>
</TestCase>
- <TestCase name="Ordering comparison checks that should fail" tags="[.][failing]" filename="projects/<exe-name>/UsageTests/Condition.tests.cpp" >
+ <TestCase name="Ordering comparison checks that should fail" tags="[!hide][.][failing]" filename="projects/<exe-name>/UsageTests/Condition.tests.cpp" >
<Expression success="false" type="CHECK" filename="projects/<exe-name>/UsageTests/Condition.tests.cpp" >
<Original>
data.int_seven > 7
@@ -6391,7 +7864,166 @@ Nor would this
</Expression>
<OverallResult success="true"/>
</TestCase>
- <TestCase name="Output from all sections is reported" tags="[.][failing][messages]" filename="projects/<exe-name>/UsageTests/Message.tests.cpp" >
+ <TestCase name="Our PCG implementation provides expected results for known seeds" tags="[rng]" filename="projects/<exe-name>/IntrospectiveTests/RandomNumberGeneration.tests.cpp" >
+ <Section name="Default seeded" filename="projects/<exe-name>/IntrospectiveTests/RandomNumberGeneration.tests.cpp" >
+ <Expression success="true" type="REQUIRE" filename="projects/<exe-name>/IntrospectiveTests/RandomNumberGeneration.tests.cpp" >
+ <Original>
+ rng() == 0x<hex digits>
+ </Original>
+ <Expanded>
+ 4242248763 (0x<hex digits>)
+==
+4242248763 (0x<hex digits>)
+ </Expanded>
+ </Expression>
+ <Expression success="true" type="REQUIRE" filename="projects/<exe-name>/IntrospectiveTests/RandomNumberGeneration.tests.cpp" >
+ <Original>
+ rng() == 0x<hex digits>
+ </Original>
+ <Expanded>
+ 1867888929 (0x<hex digits>)
+==
+1867888929 (0x<hex digits>)
+ </Expanded>
+ </Expression>
+ <Expression success="true" type="REQUIRE" filename="projects/<exe-name>/IntrospectiveTests/RandomNumberGeneration.tests.cpp" >
+ <Original>
+ rng() == 0x<hex digits>
+ </Original>
+ <Expanded>
+ 1276619030 (0x<hex digits>)
+==
+1276619030 (0x<hex digits>)
+ </Expanded>
+ </Expression>
+ <Expression success="true" type="REQUIRE" filename="projects/<exe-name>/IntrospectiveTests/RandomNumberGeneration.tests.cpp" >
+ <Original>
+ rng() == 0x<hex digits>
+ </Original>
+ <Expanded>
+ 1911218783 (0x<hex digits>)
+==
+1911218783 (0x<hex digits>)
+ </Expanded>
+ </Expression>
+ <Expression success="true" type="REQUIRE" filename="projects/<exe-name>/IntrospectiveTests/RandomNumberGeneration.tests.cpp" >
+ <Original>
+ rng() == 0x<hex digits>
+ </Original>
+ <Expanded>
+ 1827115164 (0x<hex digits>)
+==
+1827115164 (0x<hex digits>)
+ </Expanded>
+ </Expression>
+ <OverallResults successes="5" failures="0" expectedFailures="0"/>
+ </Section>
+ <Section name="Specific seed" filename="projects/<exe-name>/IntrospectiveTests/RandomNumberGeneration.tests.cpp" >
+ <Expression success="true" type="REQUIRE" filename="projects/<exe-name>/IntrospectiveTests/RandomNumberGeneration.tests.cpp" >
+ <Original>
+ rng() == 0x<hex digits>
+ </Original>
+ <Expanded>
+ 1472234645 (0x<hex digits>)
+==
+1472234645 (0x<hex digits>)
+ </Expanded>
+ </Expression>
+ <Expression success="true" type="REQUIRE" filename="projects/<exe-name>/IntrospectiveTests/RandomNumberGeneration.tests.cpp" >
+ <Original>
+ rng() == 0x<hex digits>
+ </Original>
+ <Expanded>
+ 868832940 (0x<hex digits>)
+==
+868832940 (0x<hex digits>)
+ </Expanded>
+ </Expression>
+ <Expression success="true" type="REQUIRE" filename="projects/<exe-name>/IntrospectiveTests/RandomNumberGeneration.tests.cpp" >
+ <Original>
+ rng() == 0x<hex digits>
+ </Original>
+ <Expanded>
+ 570883446 (0x<hex digits>)
+==
+570883446 (0x<hex digits>)
+ </Expanded>
+ </Expression>
+ <Expression success="true" type="REQUIRE" filename="projects/<exe-name>/IntrospectiveTests/RandomNumberGeneration.tests.cpp" >
+ <Original>
+ rng() == 0x<hex digits>
+ </Original>
+ <Expanded>
+ 889299803 (0x<hex digits>)
+==
+889299803 (0x<hex digits>)
+ </Expanded>
+ </Expression>
+ <Expression success="true" type="REQUIRE" filename="projects/<exe-name>/IntrospectiveTests/RandomNumberGeneration.tests.cpp" >
+ <Original>
+ rng() == 0x<hex digits>
+ </Original>
+ <Expanded>
+ 4261393167 (0x<hex digits>)
+==
+4261393167 (0x<hex digits>)
+ </Expanded>
+ </Expression>
+ <Expression success="true" type="REQUIRE" filename="projects/<exe-name>/IntrospectiveTests/RandomNumberGeneration.tests.cpp" >
+ <Original>
+ rng() == 0x<hex digits>
+ </Original>
+ <Expanded>
+ 1472234645 (0x<hex digits>)
+==
+1472234645 (0x<hex digits>)
+ </Expanded>
+ </Expression>
+ <Expression success="true" type="REQUIRE" filename="projects/<exe-name>/IntrospectiveTests/RandomNumberGeneration.tests.cpp" >
+ <Original>
+ rng() == 0x<hex digits>
+ </Original>
+ <Expanded>
+ 868832940 (0x<hex digits>)
+==
+868832940 (0x<hex digits>)
+ </Expanded>
+ </Expression>
+ <Expression success="true" type="REQUIRE" filename="projects/<exe-name>/IntrospectiveTests/RandomNumberGeneration.tests.cpp" >
+ <Original>
+ rng() == 0x<hex digits>
+ </Original>
+ <Expanded>
+ 570883446 (0x<hex digits>)
+==
+570883446 (0x<hex digits>)
+ </Expanded>
+ </Expression>
+ <Expression success="true" type="REQUIRE" filename="projects/<exe-name>/IntrospectiveTests/RandomNumberGeneration.tests.cpp" >
+ <Original>
+ rng() == 0x<hex digits>
+ </Original>
+ <Expanded>
+ 889299803 (0x<hex digits>)
+==
+889299803 (0x<hex digits>)
+ </Expanded>
+ </Expression>
+ <Expression success="true" type="REQUIRE" filename="projects/<exe-name>/IntrospectiveTests/RandomNumberGeneration.tests.cpp" >
+ <Original>
+ rng() == 0x<hex digits>
+ </Original>
+ <Expanded>
+ 4261393167 (0x<hex digits>)
+==
+4261393167 (0x<hex digits>)
+ </Expanded>
+ </Expression>
+ <OverallResults successes="10" failures="0" expectedFailures="0"/>
+ </Section>
+ <OverallResult success="true"/>
+ </TestCase>
+ <TestCase name="Output from all sections is reported" tags="[!hide][.][failing][messages]" filename="projects/<exe-name>/UsageTests/Message.tests.cpp" >
<Section name="one" filename="projects/<exe-name>/UsageTests/Message.tests.cpp" >
<Failure filename="projects/<exe-name>/UsageTests/Message.tests.cpp" >
Message from section one
@@ -6406,7 +8038,7 @@ Nor would this
</Section>
<OverallResult success="false"/>
</TestCase>
- <TestCase name="Parse test names and tags" filename="projects/<exe-name>/IntrospectiveTests/CmdLine.tests.cpp" >
+ <TestCase name="Parse test names and tags" tags="[command-line][test-spec]" filename="projects/<exe-name>/IntrospectiveTests/CmdLine.tests.cpp" >
<Section name="Empty test spec should have no filters" filename="projects/<exe-name>/IntrospectiveTests/CmdLine.tests.cpp" >
<Expression success="true" type="CHECK" filename="projects/<exe-name>/IntrospectiveTests/CmdLine.tests.cpp" >
<Original>
@@ -7580,6 +9212,146 @@ Nor would this
</Expression>
<OverallResults successes="5" failures="0" expectedFailures="0"/>
</Section>
+ <Section name="Leading and trailing spaces in test spec" filename="projects/<exe-name>/IntrospectiveTests/CmdLine.tests.cpp" >
+ <Expression success="true" type="CHECK" filename="projects/<exe-name>/IntrospectiveTests/CmdLine.tests.cpp" >
+ <Original>
+ spec.matches( fakeTestCase( " aardvark " ) )
+ </Original>
+ <Expanded>
+ true
+ </Expanded>
+ </Expression>
+ <Expression success="true" type="CHECK" filename="projects/<exe-name>/IntrospectiveTests/CmdLine.tests.cpp" >
+ <Original>
+ spec.matches( fakeTestCase( " aardvark" ) )
+ </Original>
+ <Expanded>
+ true
+ </Expanded>
+ </Expression>
+ <Expression success="true" type="CHECK" filename="projects/<exe-name>/IntrospectiveTests/CmdLine.tests.cpp" >
+ <Original>
+ spec.matches( fakeTestCase( " aardvark " ) )
+ </Original>
+ <Expanded>
+ true
+ </Expanded>
+ </Expression>
+ <Expression success="true" type="CHECK" filename="projects/<exe-name>/IntrospectiveTests/CmdLine.tests.cpp" >
+ <Original>
+ spec.matches( fakeTestCase( "aardvark " ) )
+ </Original>
+ <Expanded>
+ true
+ </Expanded>
+ </Expression>
+ <Expression success="true" type="CHECK" filename="projects/<exe-name>/IntrospectiveTests/CmdLine.tests.cpp" >
+ <Original>
+ spec.matches( fakeTestCase( "aardvark" ) )
+ </Original>
+ <Expanded>
+ true
+ </Expanded>
+ </Expression>
+ <OverallResults successes="5" failures="0" expectedFailures="0"/>
+ </Section>
+ <Section name="Leading and trailing spaces in test name" filename="projects/<exe-name>/IntrospectiveTests/CmdLine.tests.cpp" >
+ <Expression success="true" type="CHECK" filename="projects/<exe-name>/IntrospectiveTests/CmdLine.tests.cpp" >
+ <Original>
+ spec.matches( fakeTestCase( " aardvark " ) )
+ </Original>
+ <Expanded>
+ true
+ </Expanded>
+ </Expression>
+ <Expression success="true" type="CHECK" filename="projects/<exe-name>/IntrospectiveTests/CmdLine.tests.cpp" >
+ <Original>
+ spec.matches( fakeTestCase( " aardvark" ) )
+ </Original>
+ <Expanded>
+ true
+ </Expanded>
+ </Expression>
+ <Expression success="true" type="CHECK" filename="projects/<exe-name>/IntrospectiveTests/CmdLine.tests.cpp" >
+ <Original>
+ spec.matches( fakeTestCase( " aardvark " ) )
+ </Original>
+ <Expanded>
+ true
+ </Expanded>
+ </Expression>
+ <Expression success="true" type="CHECK" filename="projects/<exe-name>/IntrospectiveTests/CmdLine.tests.cpp" >
+ <Original>
+ spec.matches( fakeTestCase( "aardvark " ) )
+ </Original>
+ <Expanded>
+ true
+ </Expanded>
+ </Expression>
+ <Expression success="true" type="CHECK" filename="projects/<exe-name>/IntrospectiveTests/CmdLine.tests.cpp" >
+ <Original>
+ spec.matches( fakeTestCase( "aardvark" ) )
+ </Original>
+ <Expanded>
+ true
+ </Expanded>
+ </Expression>
+ <OverallResults successes="5" failures="0" expectedFailures="0"/>
+ </Section>
+ <Section name="Shortened hide tags are split apart when parsing" filename="projects/<exe-name>/IntrospectiveTests/CmdLine.tests.cpp" >
+ <Expression success="true" type="CHECK" filename="projects/<exe-name>/IntrospectiveTests/CmdLine.tests.cpp" >
+ <Original>
+ spec.matches(fakeTestCase("hidden and foo", "[.][foo]"))
+ </Original>
+ <Expanded>
+ true
+ </Expanded>
+ </Expression>
+ <Expression success="true" type="CHECK_FALSE" filename="projects/<exe-name>/IntrospectiveTests/CmdLine.tests.cpp" >
+ <Original>
+ !(spec.matches(fakeTestCase("only foo", "[foo]")))
+ </Original>
+ <Expanded>
+ !false
+ </Expanded>
+ </Expression>
+ <OverallResults successes="2" failures="0" expectedFailures="0"/>
+ </Section>
+ <Section name="Shortened hide tags also properly handle exclusion" filename="projects/<exe-name>/IntrospectiveTests/CmdLine.tests.cpp" >
+ <Expression success="true" type="CHECK_FALSE" filename="projects/<exe-name>/IntrospectiveTests/CmdLine.tests.cpp" >
+ <Original>
+ !(spec.matches(fakeTestCase("hidden and foo", "[.][foo]")))
+ </Original>
+ <Expanded>
+ !false
+ </Expanded>
+ </Expression>
+ <Expression success="true" type="CHECK_FALSE" filename="projects/<exe-name>/IntrospectiveTests/CmdLine.tests.cpp" >
+ <Original>
+ !(spec.matches(fakeTestCase("only foo", "[foo]")))
+ </Original>
+ <Expanded>
+ !false
+ </Expanded>
+ </Expression>
+ <Expression success="true" type="CHECK_FALSE" filename="projects/<exe-name>/IntrospectiveTests/CmdLine.tests.cpp" >
+ <Original>
+ !(spec.matches(fakeTestCase("only hidden", "[.]")))
+ </Original>
+ <Expanded>
+ !false
+ </Expanded>
+ </Expression>
+ <Expression success="true" type="CHECK" filename="projects/<exe-name>/IntrospectiveTests/CmdLine.tests.cpp" >
+ <Original>
+ spec.matches(fakeTestCase("neither foo nor hidden", "[bar]"))
+ </Original>
+ <Expanded>
+ true
+ </Expanded>
+ </Expression>
+ <OverallResults successes="4" failures="0" expectedFailures="0"/>
+ </Section>
<OverallResult success="true"/>
</TestCase>
<TestCase name="Pointers can be compared to null" filename="projects/<exe-name>/UsageTests/Condition.tests.cpp" >
@@ -7649,6 +9421,47 @@ Nor would this
</Expression>
<OverallResult success="true"/>
</TestCase>
+ <TestCase name="Precision of floating point stringification can be set" tags="[floatingPoint][toString]" filename="projects/<exe-name>/UsageTests/ToStringGeneral.tests.cpp" >
+ <Section name="Floats" filename="projects/<exe-name>/UsageTests/ToStringGeneral.tests.cpp" >
+ <Expression success="true" type="CHECK" filename="projects/<exe-name>/UsageTests/ToStringGeneral.tests.cpp" >
+ <Original>
+ str1.size() == 3 + 5
+ </Original>
+ <Expanded>
+ 8 == 8
+ </Expanded>
+ </Expression>
+ <Expression success="true" type="REQUIRE" filename="projects/<exe-name>/UsageTests/ToStringGeneral.tests.cpp" >
+ <Original>
+ str2.size() == 3 + 10
+ </Original>
+ <Expanded>
+ 13 == 13
+ </Expanded>
+ </Expression>
+ <OverallResults successes="2" failures="0" expectedFailures="0"/>
+ </Section>
+ <Section name="Double" filename="projects/<exe-name>/UsageTests/ToStringGeneral.tests.cpp" >
+ <Expression success="true" type="CHECK" filename="projects/<exe-name>/UsageTests/ToStringGeneral.tests.cpp" >
+ <Original>
+ str1.size() == 2 + 5
+ </Original>
+ <Expanded>
+ 7 == 7
+ </Expanded>
+ </Expression>
+ <Expression success="true" type="REQUIRE" filename="projects/<exe-name>/UsageTests/ToStringGeneral.tests.cpp" >
+ <Original>
+ str2.size() == 2 + 15
+ </Original>
+ <Expanded>
+ 17 == 17
+ </Expanded>
+ </Expression>
+ <OverallResults successes="2" failures="0" expectedFailures="0"/>
+ </Section>
+ <OverallResult success="true"/>
+ </TestCase>
<TestCase name="Predicate matcher can accept const char*" tags="[compilation][matchers]" filename="projects/<exe-name>/UsageTests/Matchers.tests.cpp" >
<Expression success="true" type="REQUIRE_THAT" filename="projects/<exe-name>/UsageTests/Matchers.tests.cpp" >
<Original>
@@ -8065,6 +9878,131 @@ Nor would this
</Section>
<OverallResults successes="2" failures="0" expectedFailures="0"/>
</Section>
+ <Section name="abort" filename="projects/<exe-name>/IntrospectiveTests/CmdLine.tests.cpp" >
+ <Section name="wait-for-keypress" filename="projects/<exe-name>/IntrospectiveTests/CmdLine.tests.cpp" >
+ <Section name="Accepted options" filename="projects/<exe-name>/IntrospectiveTests/CmdLine.tests.cpp" >
+ <Expression success="true" type="CHECK" filename="projects/<exe-name>/IntrospectiveTests/CmdLine.tests.cpp" >
+ <Original>
+ cli.parse({"test", "--wait-for-keypress", std::get&lt;0>(input)})
+ </Original>
+ <Expanded>
+ {?}
+ </Expanded>
+ </Expression>
+ <Expression success="true" type="REQUIRE" filename="projects/<exe-name>/IntrospectiveTests/CmdLine.tests.cpp" >
+ <Original>
+ config.waitForKeypress == std::get&lt;1>(input)
+ </Original>
+ <Expanded>
+ 0 == 0
+ </Expanded>
+ </Expression>
+ <OverallResults successes="2" failures="0" expectedFailures="0"/>
+ </Section>
+ <OverallResults successes="2" failures="0" expectedFailures="0"/>
+ </Section>
+ <OverallResults successes="2" failures="0" expectedFailures="0"/>
+ </Section>
+ <Section name="abort" filename="projects/<exe-name>/IntrospectiveTests/CmdLine.tests.cpp" >
+ <Section name="wait-for-keypress" filename="projects/<exe-name>/IntrospectiveTests/CmdLine.tests.cpp" >
+ <Section name="Accepted options" filename="projects/<exe-name>/IntrospectiveTests/CmdLine.tests.cpp" >
+ <Expression success="true" type="CHECK" filename="projects/<exe-name>/IntrospectiveTests/CmdLine.tests.cpp" >
+ <Original>
+ cli.parse({"test", "--wait-for-keypress", std::get&lt;0>(input)})
+ </Original>
+ <Expanded>
+ {?}
+ </Expanded>
+ </Expression>
+ <Expression success="true" type="REQUIRE" filename="projects/<exe-name>/IntrospectiveTests/CmdLine.tests.cpp" >
+ <Original>
+ config.waitForKeypress == std::get&lt;1>(input)
+ </Original>
+ <Expanded>
+ 1 == 1
+ </Expanded>
+ </Expression>
+ <OverallResults successes="2" failures="0" expectedFailures="0"/>
+ </Section>
+ <OverallResults successes="2" failures="0" expectedFailures="0"/>
+ </Section>
+ <OverallResults successes="2" failures="0" expectedFailures="0"/>
+ </Section>
+ <Section name="abort" filename="projects/<exe-name>/IntrospectiveTests/CmdLine.tests.cpp" >
+ <Section name="wait-for-keypress" filename="projects/<exe-name>/IntrospectiveTests/CmdLine.tests.cpp" >
+ <Section name="Accepted options" filename="projects/<exe-name>/IntrospectiveTests/CmdLine.tests.cpp" >
+ <Expression success="true" type="CHECK" filename="projects/<exe-name>/IntrospectiveTests/CmdLine.tests.cpp" >
+ <Original>
+ cli.parse({"test", "--wait-for-keypress", std::get&lt;0>(input)})
+ </Original>
+ <Expanded>
+ {?}
+ </Expanded>
+ </Expression>
+ <Expression success="true" type="REQUIRE" filename="projects/<exe-name>/IntrospectiveTests/CmdLine.tests.cpp" >
+ <Original>
+ config.waitForKeypress == std::get&lt;1>(input)
+ </Original>
+ <Expanded>
+ 2 == 2
+ </Expanded>
+ </Expression>
+ <OverallResults successes="2" failures="0" expectedFailures="0"/>
+ </Section>
+ <OverallResults successes="2" failures="0" expectedFailures="0"/>
+ </Section>
+ <OverallResults successes="2" failures="0" expectedFailures="0"/>
+ </Section>
+ <Section name="abort" filename="projects/<exe-name>/IntrospectiveTests/CmdLine.tests.cpp" >
+ <Section name="wait-for-keypress" filename="projects/<exe-name>/IntrospectiveTests/CmdLine.tests.cpp" >
+ <Section name="Accepted options" filename="projects/<exe-name>/IntrospectiveTests/CmdLine.tests.cpp" >
+ <Expression success="true" type="CHECK" filename="projects/<exe-name>/IntrospectiveTests/CmdLine.tests.cpp" >
+ <Original>
+ cli.parse({"test", "--wait-for-keypress", std::get&lt;0>(input)})
+ </Original>
+ <Expanded>
+ {?}
+ </Expanded>
+ </Expression>
+ <Expression success="true" type="REQUIRE" filename="projects/<exe-name>/IntrospectiveTests/CmdLine.tests.cpp" >
+ <Original>
+ config.waitForKeypress == std::get&lt;1>(input)
+ </Original>
+ <Expanded>
+ 3 == 3
+ </Expanded>
+ </Expression>
+ <OverallResults successes="2" failures="0" expectedFailures="0"/>
+ </Section>
+ <OverallResults successes="2" failures="0" expectedFailures="0"/>
+ </Section>
+ <OverallResults successes="2" failures="0" expectedFailures="0"/>
+ </Section>
+ <Section name="abort" filename="projects/<exe-name>/IntrospectiveTests/CmdLine.tests.cpp" >
+ <Section name="wait-for-keypress" filename="projects/<exe-name>/IntrospectiveTests/CmdLine.tests.cpp" >
+ <Section name="invalid options are reported" filename="projects/<exe-name>/IntrospectiveTests/CmdLine.tests.cpp" >
+ <Expression success="true" type="CHECK" filename="projects/<exe-name>/IntrospectiveTests/CmdLine.tests.cpp" >
+ <Original>
+ !result
+ </Original>
+ <Expanded>
+ true
+ </Expanded>
+ </Expression>
+ <Expression success="true" type="REQUIRE_THAT" filename="projects/<exe-name>/IntrospectiveTests/CmdLine.tests.cpp" >
+ <Original>
+ result.errorMessage(), Contains("never") &amp;&amp; Contains("both")
+ </Original>
+ <Expanded>
+ "keypress argument must be one of: never, start, exit or both. 'sometimes' not recognised" ( contains: "never" and contains: "both" )
+ </Expanded>
+ </Expression>
+ <OverallResults successes="2" failures="0" expectedFailures="0"/>
+ </Section>
+ <OverallResults successes="2" failures="0" expectedFailures="0"/>
+ </Section>
+ <OverallResults successes="2" failures="0" expectedFailures="0"/>
+ </Section>
<Section name="nothrow" filename="projects/<exe-name>/IntrospectiveTests/CmdLine.tests.cpp" >
<Section name="-e" filename="projects/<exe-name>/IntrospectiveTests/CmdLine.tests.cpp" >
<Expression success="true" type="CHECK" filename="projects/<exe-name>/IntrospectiveTests/CmdLine.tests.cpp" >
@@ -8301,6 +10239,116 @@ Nor would this
</Section>
<OverallResults successes="2" failures="0" expectedFailures="0"/>
</Section>
+ <Section name="Benchmark options" filename="projects/<exe-name>/IntrospectiveTests/CmdLine.tests.cpp" >
+ <Section name="samples" filename="projects/<exe-name>/IntrospectiveTests/CmdLine.tests.cpp" >
+ <Expression success="true" type="CHECK" filename="projects/<exe-name>/IntrospectiveTests/CmdLine.tests.cpp" >
+ <Original>
+ cli.parse({ "test", "--benchmark-samples=200" })
+ </Original>
+ <Expanded>
+ {?}
+ </Expanded>
+ </Expression>
+ <Expression success="true" type="REQUIRE" filename="projects/<exe-name>/IntrospectiveTests/CmdLine.tests.cpp" >
+ <Original>
+ config.benchmarkSamples == 200
+ </Original>
+ <Expanded>
+ 200 == 200
+ </Expanded>
+ </Expression>
+ <OverallResults successes="2" failures="0" expectedFailures="0"/>
+ </Section>
+ <OverallResults successes="2" failures="0" expectedFailures="0"/>
+ </Section>
+ <Section name="Benchmark options" filename="projects/<exe-name>/IntrospectiveTests/CmdLine.tests.cpp" >
+ <Section name="resamples" filename="projects/<exe-name>/IntrospectiveTests/CmdLine.tests.cpp" >
+ <Expression success="true" type="CHECK" filename="projects/<exe-name>/IntrospectiveTests/CmdLine.tests.cpp" >
+ <Original>
+ cli.parse({ "test", "--benchmark-resamples=20000" })
+ </Original>
+ <Expanded>
+ {?}
+ </Expanded>
+ </Expression>
+ <Expression success="true" type="REQUIRE" filename="projects/<exe-name>/IntrospectiveTests/CmdLine.tests.cpp" >
+ <Original>
+ config.benchmarkResamples == 20000
+ </Original>
+ <Expanded>
+ 20000 (0x<hex digits>) == 20000 (0x<hex digits>)
+ </Expanded>
+ </Expression>
+ <OverallResults successes="2" failures="0" expectedFailures="0"/>
+ </Section>
+ <OverallResults successes="2" failures="0" expectedFailures="0"/>
+ </Section>
+ <Section name="Benchmark options" filename="projects/<exe-name>/IntrospectiveTests/CmdLine.tests.cpp" >
+ <Section name="confidence-interval" filename="projects/<exe-name>/IntrospectiveTests/CmdLine.tests.cpp" >
+ <Expression success="true" type="CHECK" filename="projects/<exe-name>/IntrospectiveTests/CmdLine.tests.cpp" >
+ <Original>
+ cli.parse({ "test", "--benchmark-confidence-interval=0.99" })
+ </Original>
+ <Expanded>
+ {?}
+ </Expanded>
+ </Expression>
+ <Expression success="true" type="REQUIRE" filename="projects/<exe-name>/IntrospectiveTests/CmdLine.tests.cpp" >
+ <Original>
+ config.benchmarkConfidenceInterval == Catch::Detail::Approx(0.99)
+ </Original>
+ <Expanded>
+ 0.99 == Approx( 0.99 )
+ </Expanded>
+ </Expression>
+ <OverallResults successes="2" failures="0" expectedFailures="0"/>
+ </Section>
+ <OverallResults successes="2" failures="0" expectedFailures="0"/>
+ </Section>
+ <Section name="Benchmark options" filename="projects/<exe-name>/IntrospectiveTests/CmdLine.tests.cpp" >
+ <Section name="no-analysis" filename="projects/<exe-name>/IntrospectiveTests/CmdLine.tests.cpp" >
+ <Expression success="true" type="CHECK" filename="projects/<exe-name>/IntrospectiveTests/CmdLine.tests.cpp" >
+ <Original>
+ cli.parse({ "test", "--benchmark-no-analysis" })
+ </Original>
+ <Expanded>
+ {?}
+ </Expanded>
+ </Expression>
+ <Expression success="true" type="REQUIRE" filename="projects/<exe-name>/IntrospectiveTests/CmdLine.tests.cpp" >
+ <Original>
+ config.benchmarkNoAnalysis
+ </Original>
+ <Expanded>
+ true
+ </Expanded>
+ </Expression>
+ <OverallResults successes="2" failures="0" expectedFailures="0"/>
+ </Section>
+ <OverallResults successes="2" failures="0" expectedFailures="0"/>
+ </Section>
+ <Section name="Benchmark options" filename="projects/<exe-name>/IntrospectiveTests/CmdLine.tests.cpp" >
+ <Section name="warmup-time" filename="projects/<exe-name>/IntrospectiveTests/CmdLine.tests.cpp" >
+ <Expression success="true" type="CHECK" filename="projects/<exe-name>/IntrospectiveTests/CmdLine.tests.cpp" >
+ <Original>
+ cli.parse({ "test", "--benchmark-warmup-time=10" })
+ </Original>
+ <Expanded>
+ {?}
+ </Expanded>
+ </Expression>
+ <Expression success="true" type="REQUIRE" filename="projects/<exe-name>/IntrospectiveTests/CmdLine.tests.cpp" >
+ <Original>
+ config.benchmarkWarmupTime == 10
+ </Original>
+ <Expanded>
+ 10 == 10
+ </Expanded>
+ </Expression>
+ <OverallResults successes="2" failures="0" expectedFailures="0"/>
+ </Section>
+ <OverallResults successes="2" failures="0" expectedFailures="0"/>
+ </Section>
<OverallResult success="true"/>
</TestCase>
<TestCase name="Product with differing arities - std::tuple&lt;int, double, float>" tags="[product][template]" filename="projects/<exe-name>/UsageTests/Misc.tests.cpp" >
@@ -8336,7 +10384,7 @@ Nor would this
</Expression>
<OverallResult success="true"/>
</TestCase>
- <TestCase name="Reconstruction should be based on stringification: #914" tags="[.][Decomposition][failing]" filename="projects/<exe-name>/UsageTests/Decomposition.tests.cpp" >
+ <TestCase name="Reconstruction should be based on stringification: #914" tags="[!hide][.][Decomposition][failing]" filename="projects/<exe-name>/UsageTests/Decomposition.tests.cpp" >
<Expression success="false" type="CHECK" filename="projects/<exe-name>/UsageTests/Decomposition.tests.cpp" >
<Original>
truthy(false)
@@ -8347,7 +10395,7 @@ Nor would this
</Expression>
<OverallResult success="false"/>
</TestCase>
- <TestCase name="Regex string matcher" tags="[.][failing][matchers]" filename="projects/<exe-name>/UsageTests/Matchers.tests.cpp" >
+ <TestCase name="Regex string matcher" tags="[!hide][.][failing][matchers]" filename="projects/<exe-name>/UsageTests/Matchers.tests.cpp" >
<Expression success="false" type="CHECK_THAT" filename="projects/<exe-name>/UsageTests/Matchers.tests.cpp" >
<Original>
testStringForMatching(), Matches("this STRING contains 'abc' as a substring")
@@ -8388,7 +10436,7 @@ Nor would this
<TestCase name="SUCCEED counts as a test pass" tags="[messages]" filename="projects/<exe-name>/UsageTests/Message.tests.cpp" >
<OverallResult success="true"/>
</TestCase>
- <TestCase name="SUCCEED does not require an argument" tags="[.][messages]" filename="projects/<exe-name>/UsageTests/Message.tests.cpp" >
+ <TestCase name="SUCCEED does not require an argument" tags="[!hide][.][messages]" filename="projects/<exe-name>/UsageTests/Message.tests.cpp" >
<OverallResult success="true"/>
</TestCase>
<TestCase name="Scenario: BDD tests requiring Fixtures to provide commonly-accessed data or methods" tags="[bdd][fixtures]" filename="projects/<exe-name>/UsageTests/BDD.tests.cpp" >
@@ -8556,7 +10604,7 @@ Nor would this
</Section>
<OverallResult success="true"/>
</TestCase>
- <TestCase name="Sends stuff to stdout and stderr" tags="[.]" filename="projects/<exe-name>/UsageTests/Misc.tests.cpp" >
+ <TestCase name="Sends stuff to stdout and stderr" tags="[!hide][.]" filename="projects/<exe-name>/UsageTests/Misc.tests.cpp" >
<OverallResult success="false">
<StdOut>
A string sent directly to stdout
@@ -8632,17 +10680,9 @@ A string sent to stderr via clog
Approx( 1.23 ) != 1.24
</Expanded>
</Expression>
- <Expression success="true" type="REQUIRE" filename="projects/<exe-name>/UsageTests/Approx.tests.cpp" >
- <Original>
- INFINITY == Approx(INFINITY)
- </Original>
- <Expanded>
- inff == Approx( inf )
- </Expanded>
- </Expression>
<OverallResult success="true"/>
</TestCase>
- <TestCase name="Standard output from all sections is reported" tags="[.][messages]" filename="projects/<exe-name>/UsageTests/Message.tests.cpp" >
+ <TestCase name="Standard output from all sections is reported" tags="[!hide][.][messages]" filename="projects/<exe-name>/UsageTests/Message.tests.cpp" >
<Section name="one" filename="projects/<exe-name>/UsageTests/Message.tests.cpp" >
<OverallResults successes="0" failures="1" expectedFailures="0"/>
</Section>
@@ -8656,7 +10696,7 @@ Message from section two
</StdOut>
</OverallResult>
</TestCase>
- <TestCase name="StartsWith string matcher" tags="[.][failing][matchers]" filename="projects/<exe-name>/UsageTests/Matchers.tests.cpp" >
+ <TestCase name="StartsWith string matcher" tags="[!hide][.][failing][matchers]" filename="projects/<exe-name>/UsageTests/Matchers.tests.cpp" >
<Expression success="false" type="CHECK_THAT" filename="projects/<exe-name>/UsageTests/Matchers.tests.cpp" >
<Original>
testStringForMatching(), StartsWith("This String")
@@ -8800,13 +10840,21 @@ Message from section two
</Expression>
<Expression success="true" type="REQUIRE" filename="projects/<exe-name>/IntrospectiveTests/String.tests.cpp" >
<Original>
+ empty.isNullTerminated()
+ </Original>
+ <Expanded>
+ true
+ </Expanded>
+ </Expression>
+ <Expression success="true" type="REQUIRE" filename="projects/<exe-name>/IntrospectiveTests/String.tests.cpp" >
+ <Original>
std::strcmp( empty.c_str(), "" ) == 0
</Original>
<Expanded>
0 == 0
</Expanded>
</Expression>
- <OverallResults successes="3" failures="0" expectedFailures="0"/>
+ <OverallResults successes="4" failures="0" expectedFailures="0"/>
</Section>
<Section name="From string literal" filename="projects/<exe-name>/IntrospectiveTests/String.tests.cpp" >
<Expression success="true" type="REQUIRE" filename="projects/<exe-name>/IntrospectiveTests/String.tests.cpp" >
@@ -8827,10 +10875,10 @@ Message from section two
</Expression>
<Expression success="true" type="REQUIRE" filename="projects/<exe-name>/IntrospectiveTests/String.tests.cpp" >
<Original>
- isSubstring( s ) == false
+ s.isNullTerminated()
</Original>
<Expanded>
- false == false
+ true
</Expanded>
</Expression>
<Expression success="true" type="REQUIRE" filename="projects/<exe-name>/IntrospectiveTests/String.tests.cpp" >
@@ -8841,77 +10889,66 @@ Message from section two
0 == 0
</Expanded>
</Expression>
- <Section name="c_str() does not cause copy" filename="projects/<exe-name>/IntrospectiveTests/String.tests.cpp" >
- <Expression success="true" type="REQUIRE" filename="projects/<exe-name>/IntrospectiveTests/String.tests.cpp" >
- <Original>
- isOwned( s ) == false
- </Original>
- <Expanded>
- false == false
- </Expanded>
- </Expression>
- <Expression success="true" type="REQUIRE" filename="projects/<exe-name>/IntrospectiveTests/String.tests.cpp" >
- <Original>
- s.c_str() == rawChars
- </Original>
- <Expanded>
- "hello" == "hello"
- </Expanded>
- </Expression>
- <Expression success="true" type="REQUIRE" filename="projects/<exe-name>/IntrospectiveTests/String.tests.cpp" >
- <Original>
- isOwned( s ) == false
- </Original>
- <Expanded>
- false == false
- </Expanded>
- </Expression>
- <OverallResults successes="3" failures="0" expectedFailures="0"/>
- </Section>
- <OverallResults successes="7" failures="0" expectedFailures="0"/>
- </Section>
- <Section name="From sub-string" filename="projects/<exe-name>/IntrospectiveTests/String.tests.cpp" >
- <Expression success="true" type="REQUIRE" filename="projects/<exe-name>/IntrospectiveTests/String.tests.cpp" >
+ <Expression success="true" type="REQUIRE_NOTHROW" filename="projects/<exe-name>/IntrospectiveTests/String.tests.cpp" >
<Original>
- original == "original"
+ s.c_str()
</Original>
<Expanded>
- original == "original"
+ s.c_str()
</Expanded>
</Expression>
<Expression success="true" type="REQUIRE" filename="projects/<exe-name>/IntrospectiveTests/String.tests.cpp" >
<Original>
- isSubstring( original )
+ s.c_str() == rawChars
</Original>
<Expanded>
- true
+ "hello" == "hello"
</Expanded>
</Expression>
<Expression success="true" type="REQUIRE" filename="projects/<exe-name>/IntrospectiveTests/String.tests.cpp" >
<Original>
- isOwned( original ) == false
+ s.data() == rawChars
</Original>
<Expanded>
- false == false
+ "hello" == "hello"
</Expanded>
</Expression>
+ <OverallResults successes="7" failures="0" expectedFailures="0"/>
+ </Section>
+ <Section name="From sub-string" filename="projects/<exe-name>/IntrospectiveTests/String.tests.cpp" >
<Expression success="true" type="REQUIRE" filename="projects/<exe-name>/IntrospectiveTests/String.tests.cpp" >
<Original>
- isSubstring( original ) == false
+ original == "original"
</Original>
<Expanded>
- false == false
+ original == "original"
</Expanded>
</Expression>
- <Expression success="true" type="REQUIRE" filename="projects/<exe-name>/IntrospectiveTests/String.tests.cpp" >
+ <Expression success="true" type="REQUIRE_FALSE" filename="projects/<exe-name>/IntrospectiveTests/String.tests.cpp" >
<Original>
- isOwned( original )
+ !(original.isNullTerminated())
</Original>
<Expanded>
- true
+ !false
</Expanded>
</Expression>
- <OverallResults successes="5" failures="0" expectedFailures="0"/>
+ <Expression success="true" type="REQUIRE_THROWS" filename="projects/<exe-name>/IntrospectiveTests/String.tests.cpp" >
+ <Original>
+ original.c_str()
+ </Original>
+ <Expanded>
+ original.c_str()
+ </Expanded>
+ </Expression>
+ <Expression success="true" type="REQUIRE_NOTHROW" filename="projects/<exe-name>/IntrospectiveTests/String.tests.cpp" >
+ <Original>
+ original.data()
+ </Original>
+ <Expanded>
+ original.data()
+ </Expanded>
+ </Expression>
+ <OverallResults successes="4" failures="0" expectedFailures="0"/>
</Section>
<Section name="Substrings" filename="projects/<exe-name>/IntrospectiveTests/String.tests.cpp" >
<Section name="zero-based substring" filename="projects/<exe-name>/IntrospectiveTests/String.tests.cpp" >
@@ -8933,7 +10970,7 @@ Message from section two
</Expression>
<Expression success="true" type="REQUIRE" filename="projects/<exe-name>/IntrospectiveTests/String.tests.cpp" >
<Original>
- std::strcmp( ss.c_str(), "hello" ) == 0
+ std::strncmp( ss.data(), "hello", 5 ) == 0
</Original>
<Expanded>
0 == 0
@@ -8952,97 +10989,63 @@ Message from section two
<OverallResults successes="4" failures="0" expectedFailures="0"/>
</Section>
<Section name="Substrings" filename="projects/<exe-name>/IntrospectiveTests/String.tests.cpp" >
- <Section name="c_str() causes copy" filename="projects/<exe-name>/IntrospectiveTests/String.tests.cpp" >
+ <Section name="non-zero-based substring" filename="projects/<exe-name>/IntrospectiveTests/String.tests.cpp" >
<Expression success="true" type="REQUIRE" filename="projects/<exe-name>/IntrospectiveTests/String.tests.cpp" >
<Original>
- isSubstring( ss )
+ ss.size() == 6
</Original>
<Expanded>
- true
+ 6 == 6
</Expanded>
</Expression>
<Expression success="true" type="REQUIRE" filename="projects/<exe-name>/IntrospectiveTests/String.tests.cpp" >
<Original>
- isOwned( ss ) == false
+ std::strcmp( ss.c_str(), "world!" ) == 0
</Original>
<Expanded>
- false == false
+ 0 == 0
</Expanded>
</Expression>
+ <OverallResults successes="2" failures="0" expectedFailures="0"/>
+ </Section>
+ <OverallResults successes="2" failures="0" expectedFailures="0"/>
+ </Section>
+ <Section name="Substrings" filename="projects/<exe-name>/IntrospectiveTests/String.tests.cpp" >
+ <Section name="Pointer values of full refs should match" filename="projects/<exe-name>/IntrospectiveTests/String.tests.cpp" >
<Expression success="true" type="REQUIRE" filename="projects/<exe-name>/IntrospectiveTests/String.tests.cpp" >
<Original>
- rawChars == s.currentData()
+ s.data() == s2.data()
</Original>
<Expanded>
"hello world!" == "hello world!"
</Expanded>
</Expression>
- <Expression success="true" type="REQUIRE" filename="projects/<exe-name>/IntrospectiveTests/String.tests.cpp" >
- <Original>
- ss.c_str() != rawChars
- </Original>
- <Expanded>
- "hello" != "hello world!"
- </Expanded>
- </Expression>
- <Expression success="true" type="REQUIRE" filename="projects/<exe-name>/IntrospectiveTests/String.tests.cpp" >
- <Original>
- isSubstring( ss ) == false
- </Original>
- <Expanded>
- false == false
- </Expanded>
- </Expression>
- <Expression success="true" type="REQUIRE" filename="projects/<exe-name>/IntrospectiveTests/String.tests.cpp" >
- <Original>
- isOwned( ss )
- </Original>
- <Expanded>
- true
- </Expanded>
- </Expression>
- <Expression success="true" type="REQUIRE" filename="projects/<exe-name>/IntrospectiveTests/String.tests.cpp" >
- <Original>
- ss.currentData() != s.currentData()
- </Original>
- <Expanded>
- "hello" != "hello world!"
- </Expanded>
- </Expression>
- <OverallResults successes="7" failures="0" expectedFailures="0"/>
+ <OverallResults successes="1" failures="0" expectedFailures="0"/>
</Section>
- <OverallResults successes="7" failures="0" expectedFailures="0"/>
+ <OverallResults successes="1" failures="0" expectedFailures="0"/>
</Section>
<Section name="Substrings" filename="projects/<exe-name>/IntrospectiveTests/String.tests.cpp" >
- <Section name="non-zero-based substring" filename="projects/<exe-name>/IntrospectiveTests/String.tests.cpp" >
+ <Section name="Pointer values of substring refs should also match" filename="projects/<exe-name>/IntrospectiveTests/String.tests.cpp" >
<Expression success="true" type="REQUIRE" filename="projects/<exe-name>/IntrospectiveTests/String.tests.cpp" >
<Original>
- ss.size() == 6
+ s.data() == ss.data()
</Original>
<Expanded>
- 6 == 6
- </Expanded>
- </Expression>
- <Expression success="true" type="REQUIRE" filename="projects/<exe-name>/IntrospectiveTests/String.tests.cpp" >
- <Original>
- std::strcmp( ss.c_str(), "world!" ) == 0
- </Original>
- <Expanded>
- 0 == 0
+ "hello world!" == "hello world!"
</Expanded>
</Expression>
- <OverallResults successes="2" failures="0" expectedFailures="0"/>
+ <OverallResults successes="1" failures="0" expectedFailures="0"/>
</Section>
- <OverallResults successes="2" failures="0" expectedFailures="0"/>
+ <OverallResults successes="1" failures="0" expectedFailures="0"/>
</Section>
<Section name="Substrings" filename="projects/<exe-name>/IntrospectiveTests/String.tests.cpp" >
- <Section name="Pointer values of full refs should match" filename="projects/<exe-name>/IntrospectiveTests/String.tests.cpp" >
+ <Section name="Past the end substring" filename="projects/<exe-name>/IntrospectiveTests/String.tests.cpp" >
<Expression success="true" type="REQUIRE" filename="projects/<exe-name>/IntrospectiveTests/String.tests.cpp" >
<Original>
- s.c_str() == s2.c_str()
+ s.substr(s.size() + 1, 123).empty()
</Original>
<Expanded>
- "hello world!" == "hello world!"
+ true
</Expanded>
</Expression>
<OverallResults successes="1" failures="0" expectedFailures="0"/>
@@ -9050,37 +11053,45 @@ Message from section two
<OverallResults successes="1" failures="0" expectedFailures="0"/>
</Section>
<Section name="Substrings" filename="projects/<exe-name>/IntrospectiveTests/String.tests.cpp" >
- <Section name="Pointer values of substring refs should not match" filename="projects/<exe-name>/IntrospectiveTests/String.tests.cpp" >
+ <Section name="Substring off the end are trimmed" filename="projects/<exe-name>/IntrospectiveTests/String.tests.cpp" >
<Expression success="true" type="REQUIRE" filename="projects/<exe-name>/IntrospectiveTests/String.tests.cpp" >
<Original>
- s.c_str() != ss.c_str()
+ std::strcmp(ss.c_str(), "world!") == 0
</Original>
<Expanded>
- "hello world!" != "hello"
+ 0 == 0
</Expanded>
</Expression>
<OverallResults successes="1" failures="0" expectedFailures="0"/>
</Section>
<OverallResults successes="1" failures="0" expectedFailures="0"/>
</Section>
- <Section name="Comparisons" filename="projects/<exe-name>/IntrospectiveTests/String.tests.cpp" >
+ <Section name="Comparisons are deep" filename="projects/<exe-name>/IntrospectiveTests/String.tests.cpp" >
+ <Expression success="true" type="CHECK" filename="projects/<exe-name>/IntrospectiveTests/String.tests.cpp" >
+ <Original>
+ (char*)buffer1 != (char*)buffer2
+ </Original>
+ <Expanded>
+ "Hello" != "Hello"
+ </Expanded>
+ </Expression>
<Expression success="true" type="REQUIRE" filename="projects/<exe-name>/IntrospectiveTests/String.tests.cpp" >
<Original>
- StringRef("hello") == StringRef("hello")
+ left == right
</Original>
<Expanded>
- hello == hello
+ Hello == Hello
</Expanded>
</Expression>
<Expression success="true" type="REQUIRE" filename="projects/<exe-name>/IntrospectiveTests/String.tests.cpp" >
<Original>
- StringRef("hello") != StringRef("cello")
+ left != left.substr(0, 3)
</Original>
<Expanded>
- hello != cello
+ Hello != Hel
</Expanded>
</Expression>
- <OverallResults successes="2" failures="0" expectedFailures="0"/>
+ <OverallResults successes="3" failures="0" expectedFailures="0"/>
</Section>
<Section name="from std::string" filename="projects/<exe-name>/IntrospectiveTests/String.tests.cpp" >
<Section name="implicitly constructed" filename="projects/<exe-name>/IntrospectiveTests/String.tests.cpp" >
@@ -9149,28 +11160,6 @@ Message from section two
<OverallResults successes="2" failures="0" expectedFailures="0"/>
</Section>
<Section name="to std::string" filename="projects/<exe-name>/IntrospectiveTests/String.tests.cpp" >
- <Section name="implicitly constructed" filename="projects/<exe-name>/IntrospectiveTests/String.tests.cpp" >
- <Expression success="true" type="REQUIRE" filename="projects/<exe-name>/IntrospectiveTests/String.tests.cpp" >
- <Original>
- stdStr == "a stringref"
- </Original>
- <Expanded>
- "a stringref" == "a stringref"
- </Expanded>
- </Expression>
- <Expression success="true" type="REQUIRE" filename="projects/<exe-name>/IntrospectiveTests/String.tests.cpp" >
- <Original>
- stdStr.size() == sr.size()
- </Original>
- <Expanded>
- 11 == 11
- </Expanded>
- </Expression>
- <OverallResults successes="2" failures="0" expectedFailures="0"/>
- </Section>
- <OverallResults successes="2" failures="0" expectedFailures="0"/>
- </Section>
- <Section name="to std::string" filename="projects/<exe-name>/IntrospectiveTests/String.tests.cpp" >
<Section name="explicitly constructed" filename="projects/<exe-name>/IntrospectiveTests/String.tests.cpp" >
<Expression success="true" type="REQUIRE" filename="projects/<exe-name>/IntrospectiveTests/String.tests.cpp" >
<Original>
@@ -9214,32 +11203,14 @@ Message from section two
</Section>
<OverallResults successes="2" failures="0" expectedFailures="0"/>
</Section>
- <Section name="Counting utf-8 codepoints" filename="projects/<exe-name>/IntrospectiveTests/String.tests.cpp" >
- <Expression success="true" type="REQUIRE" filename="projects/<exe-name>/IntrospectiveTests/String.tests.cpp" >
- <Original>
- ascii.numberOfCharacters() == ascii.size()
- </Original>
- <Expanded>
- 39 == 39
- </Expanded>
- </Expression>
- <Expression success="true" type="REQUIRE" filename="projects/<exe-name>/IntrospectiveTests/String.tests.cpp" >
- <Original>
- simpleu8.numberOfCharacters() == 30
- </Original>
- <Expanded>
- 30 == 30
- </Expanded>
- </Expression>
- <Expression success="true" type="REQUIRE" filename="projects/<exe-name>/IntrospectiveTests/String.tests.cpp" >
- <Original>
- emojis.numberOfCharacters() == 9
- </Original>
- <Expanded>
- 9 == 9
- </Expanded>
- </Expression>
- <OverallResults successes="3" failures="0" expectedFailures="0"/>
+ <OverallResult success="true"/>
+ </TestCase>
+ <TestCase name="StringRef at compilation time" tags="[StringRef][Strings][constexpr]" filename="projects/<exe-name>/IntrospectiveTests/String.tests.cpp" >
+ <Section name="Simple constructors" filename="projects/<exe-name>/IntrospectiveTests/String.tests.cpp" >
+ <OverallResults successes="5" failures="0" expectedFailures="0"/>
+ </Section>
+ <Section name="UDL construction" filename="projects/<exe-name>/IntrospectiveTests/String.tests.cpp" >
+ <OverallResults successes="6" failures="0" expectedFailures="0"/>
</Section>
<OverallResult success="true"/>
</TestCase>
@@ -9310,7 +11281,7 @@ Message from section two
</Expression>
<OverallResult success="true"/>
</TestCase>
- <TestCase name="Tabs and newlines show in output" tags="[.][failing][whitespace]" filename="projects/<exe-name>/UsageTests/Misc.tests.cpp" >
+ <TestCase name="Tabs and newlines show in output" tags="[!hide][.][failing][whitespace]" filename="projects/<exe-name>/UsageTests/Misc.tests.cpp" >
<Expression success="false" type="CHECK" filename="projects/<exe-name>/UsageTests/Misc.tests.cpp" >
<Original>
s1 == s2
@@ -9409,6 +11380,116 @@ Message from section two
</Section>
<OverallResult success="true"/>
</TestCase>
+ <TestCase name="Template test case method with test types specified inside std::tuple - MyTypes - 0" tags="[class][list][template]" filename="projects/<exe-name>/UsageTests/Class.tests.cpp" >
+ <Expression success="true" type="REQUIRE" filename="projects/<exe-name>/UsageTests/Class.tests.cpp" >
+ <Original>
+ Template_Fixture&lt;TestType>::m_a == 1
+ </Original>
+ <Expanded>
+ 1 == 1
+ </Expanded>
+ </Expression>
+ <OverallResult success="true"/>
+ </TestCase>
+ <TestCase name="Template test case method with test types specified inside std::tuple - MyTypes - 1" tags="[class][list][template]" filename="projects/<exe-name>/UsageTests/Class.tests.cpp" >
+ <Expression success="true" type="REQUIRE" filename="projects/<exe-name>/UsageTests/Class.tests.cpp" >
+ <Original>
+ Template_Fixture&lt;TestType>::m_a == 1
+ </Original>
+ <Expanded>
+ 1 == 1
+ </Expanded>
+ </Expression>
+ <OverallResult success="true"/>
+ </TestCase>
+ <TestCase name="Template test case method with test types specified inside std::tuple - MyTypes - 2" tags="[class][list][template]" filename="projects/<exe-name>/UsageTests/Class.tests.cpp" >
+ <Expression success="true" type="REQUIRE" filename="projects/<exe-name>/UsageTests/Class.tests.cpp" >
+ <Original>
+ Template_Fixture&lt;TestType>::m_a == 1
+ </Original>
+ <Expanded>
+ 1.0 == 1
+ </Expanded>
+ </Expression>
+ <OverallResult success="true"/>
+ </TestCase>
+ <TestCase name="Template test case with test types specified inside non-copyable and non-movable std::tuple - NonCopyableAndNonMovableTypes - 0" tags="[list][template]" filename="projects/<exe-name>/UsageTests/Misc.tests.cpp" >
+ <Expression success="true" type="REQUIRE" filename="projects/<exe-name>/UsageTests/Misc.tests.cpp" >
+ <Original>
+ sizeof(TestType) > 0
+ </Original>
+ <Expanded>
+ 1 > 0
+ </Expanded>
+ </Expression>
+ <OverallResult success="true"/>
+ </TestCase>
+ <TestCase name="Template test case with test types specified inside non-copyable and non-movable std::tuple - NonCopyableAndNonMovableTypes - 1" tags="[list][template]" filename="projects/<exe-name>/UsageTests/Misc.tests.cpp" >
+ <Expression success="true" type="REQUIRE" filename="projects/<exe-name>/UsageTests/Misc.tests.cpp" >
+ <Original>
+ sizeof(TestType) > 0
+ </Original>
+ <Expanded>
+ 4 > 0
+ </Expanded>
+ </Expression>
+ <OverallResult success="true"/>
+ </TestCase>
+ <TestCase name="Template test case with test types specified inside non-default-constructible std::tuple - MyNonDefaultConstructibleTypes - 0" tags="[list][template]" filename="projects/<exe-name>/UsageTests/Misc.tests.cpp" >
+ <Expression success="true" type="REQUIRE" filename="projects/<exe-name>/UsageTests/Misc.tests.cpp" >
+ <Original>
+ sizeof(TestType) > 0
+ </Original>
+ <Expanded>
+ 1 > 0
+ </Expanded>
+ </Expression>
+ <OverallResult success="true"/>
+ </TestCase>
+ <TestCase name="Template test case with test types specified inside non-default-constructible std::tuple - MyNonDefaultConstructibleTypes - 1" tags="[list][template]" filename="projects/<exe-name>/UsageTests/Misc.tests.cpp" >
+ <Expression success="true" type="REQUIRE" filename="projects/<exe-name>/UsageTests/Misc.tests.cpp" >
+ <Original>
+ sizeof(TestType) > 0
+ </Original>
+ <Expanded>
+ 4 > 0
+ </Expanded>
+ </Expression>
+ <OverallResult success="true"/>
+ </TestCase>
+ <TestCase name="Template test case with test types specified inside std::tuple - MyTypes - 0" tags="[list][template]" filename="projects/<exe-name>/UsageTests/Misc.tests.cpp" >
+ <Expression success="true" type="REQUIRE" filename="projects/<exe-name>/UsageTests/Misc.tests.cpp" >
+ <Original>
+ sizeof(TestType) > 0
+ </Original>
+ <Expanded>
+ 4 > 0
+ </Expanded>
+ </Expression>
+ <OverallResult success="true"/>
+ </TestCase>
+ <TestCase name="Template test case with test types specified inside std::tuple - MyTypes - 1" tags="[list][template]" filename="projects/<exe-name>/UsageTests/Misc.tests.cpp" >
+ <Expression success="true" type="REQUIRE" filename="projects/<exe-name>/UsageTests/Misc.tests.cpp" >
+ <Original>
+ sizeof(TestType) > 0
+ </Original>
+ <Expanded>
+ 1 > 0
+ </Expanded>
+ </Expression>
+ <OverallResult success="true"/>
+ </TestCase>
+ <TestCase name="Template test case with test types specified inside std::tuple - MyTypes - 2" tags="[list][template]" filename="projects/<exe-name>/UsageTests/Misc.tests.cpp" >
+ <Expression success="true" type="REQUIRE" filename="projects/<exe-name>/UsageTests/Misc.tests.cpp" >
+ <Original>
+ sizeof(TestType) > 0
+ </Original>
+ <Expanded>
+ 4 > 0
+ </Expanded>
+ </Expression>
+ <OverallResult success="true"/>
+ </TestCase>
<TestCase name="TemplateTest: vectors can be sized and resized - float" tags="[template][vector]" filename="projects/<exe-name>/UsageTests/Misc.tests.cpp" >
<Expression success="true" type="REQUIRE" filename="projects/<exe-name>/UsageTests/Misc.tests.cpp" >
<Original>
@@ -10025,6 +12106,622 @@ Message from section two
</Section>
<OverallResult success="true"/>
</TestCase>
+ <TestCase name="TemplateTestSig: vectors can be sized and resized - (std::tuple&lt;int, float>), 6" tags="[nttp][template][vector]" filename="projects/<exe-name>/UsageTests/Misc.tests.cpp" >
+ <Expression success="true" type="REQUIRE" filename="projects/<exe-name>/UsageTests/Misc.tests.cpp" >
+ <Original>
+ v.size() == V
+ </Original>
+ <Expanded>
+ 6 == 6
+ </Expanded>
+ </Expression>
+ <Expression success="true" type="REQUIRE" filename="projects/<exe-name>/UsageTests/Misc.tests.cpp" >
+ <Original>
+ v.capacity() >= V
+ </Original>
+ <Expanded>
+ 6 >= 6
+ </Expanded>
+ </Expression>
+ <Section name="resizing bigger changes size and capacity" filename="projects/<exe-name>/UsageTests/Misc.tests.cpp" >
+ <Expression success="true" type="REQUIRE" filename="projects/<exe-name>/UsageTests/Misc.tests.cpp" >
+ <Original>
+ v.size() == 2 * V
+ </Original>
+ <Expanded>
+ 12 == 12
+ </Expanded>
+ </Expression>
+ <Expression success="true" type="REQUIRE" filename="projects/<exe-name>/UsageTests/Misc.tests.cpp" >
+ <Original>
+ v.capacity() >= 2 * V
+ </Original>
+ <Expanded>
+ 12 >= 12
+ </Expanded>
+ </Expression>
+ <OverallResults successes="2" failures="0" expectedFailures="0"/>
+ </Section>
+ <Expression success="true" type="REQUIRE" filename="projects/<exe-name>/UsageTests/Misc.tests.cpp" >
+ <Original>
+ v.size() == V
+ </Original>
+ <Expanded>
+ 6 == 6
+ </Expanded>
+ </Expression>
+ <Expression success="true" type="REQUIRE" filename="projects/<exe-name>/UsageTests/Misc.tests.cpp" >
+ <Original>
+ v.capacity() >= V
+ </Original>
+ <Expanded>
+ 6 >= 6
+ </Expanded>
+ </Expression>
+ <Section name="resizing smaller changes size but not capacity" filename="projects/<exe-name>/UsageTests/Misc.tests.cpp" >
+ <Expression success="true" type="REQUIRE" filename="projects/<exe-name>/UsageTests/Misc.tests.cpp" >
+ <Original>
+ v.size() == 0
+ </Original>
+ <Expanded>
+ 0 == 0
+ </Expanded>
+ </Expression>
+ <Expression success="true" type="REQUIRE" filename="projects/<exe-name>/UsageTests/Misc.tests.cpp" >
+ <Original>
+ v.capacity() >= V
+ </Original>
+ <Expanded>
+ 6 >= 6
+ </Expanded>
+ </Expression>
+ <Section name="We can use the 'swap trick' to reset the capacity" filename="projects/<exe-name>/UsageTests/Misc.tests.cpp" >
+ <Expression success="true" type="REQUIRE" filename="projects/<exe-name>/UsageTests/Misc.tests.cpp" >
+ <Original>
+ v.capacity() == 0
+ </Original>
+ <Expanded>
+ 0 == 0
+ </Expanded>
+ </Expression>
+ <OverallResults successes="1" failures="0" expectedFailures="0"/>
+ </Section>
+ <OverallResults successes="3" failures="0" expectedFailures="0"/>
+ </Section>
+ <Expression success="true" type="REQUIRE" filename="projects/<exe-name>/UsageTests/Misc.tests.cpp" >
+ <Original>
+ v.size() == V
+ </Original>
+ <Expanded>
+ 6 == 6
+ </Expanded>
+ </Expression>
+ <Expression success="true" type="REQUIRE" filename="projects/<exe-name>/UsageTests/Misc.tests.cpp" >
+ <Original>
+ v.capacity() >= V
+ </Original>
+ <Expanded>
+ 6 >= 6
+ </Expanded>
+ </Expression>
+ <Section name="reserving bigger changes capacity but not size" filename="projects/<exe-name>/UsageTests/Misc.tests.cpp" >
+ <Expression success="true" type="REQUIRE" filename="projects/<exe-name>/UsageTests/Misc.tests.cpp" >
+ <Original>
+ v.size() == V
+ </Original>
+ <Expanded>
+ 6 == 6
+ </Expanded>
+ </Expression>
+ <Expression success="true" type="REQUIRE" filename="projects/<exe-name>/UsageTests/Misc.tests.cpp" >
+ <Original>
+ v.capacity() >= 2 * V
+ </Original>
+ <Expanded>
+ 12 >= 12
+ </Expanded>
+ </Expression>
+ <OverallResults successes="2" failures="0" expectedFailures="0"/>
+ </Section>
+ <Expression success="true" type="REQUIRE" filename="projects/<exe-name>/UsageTests/Misc.tests.cpp" >
+ <Original>
+ v.size() == V
+ </Original>
+ <Expanded>
+ 6 == 6
+ </Expanded>
+ </Expression>
+ <Expression success="true" type="REQUIRE" filename="projects/<exe-name>/UsageTests/Misc.tests.cpp" >
+ <Original>
+ v.capacity() >= V
+ </Original>
+ <Expanded>
+ 6 >= 6
+ </Expanded>
+ </Expression>
+ <Section name="reserving smaller does not change size or capacity" filename="projects/<exe-name>/UsageTests/Misc.tests.cpp" >
+ <Expression success="true" type="REQUIRE" filename="projects/<exe-name>/UsageTests/Misc.tests.cpp" >
+ <Original>
+ v.size() == V
+ </Original>
+ <Expanded>
+ 6 == 6
+ </Expanded>
+ </Expression>
+ <Expression success="true" type="REQUIRE" filename="projects/<exe-name>/UsageTests/Misc.tests.cpp" >
+ <Original>
+ v.capacity() >= V
+ </Original>
+ <Expanded>
+ 6 >= 6
+ </Expanded>
+ </Expression>
+ <OverallResults successes="2" failures="0" expectedFailures="0"/>
+ </Section>
+ <OverallResult success="true"/>
+ </TestCase>
+ <TestCase name="TemplateTestSig: vectors can be sized and resized - float,4" tags="[nttp][template][vector]" filename="projects/<exe-name>/UsageTests/Misc.tests.cpp" >
+ <Expression success="true" type="REQUIRE" filename="projects/<exe-name>/UsageTests/Misc.tests.cpp" >
+ <Original>
+ v.size() == V
+ </Original>
+ <Expanded>
+ 4 == 4
+ </Expanded>
+ </Expression>
+ <Expression success="true" type="REQUIRE" filename="projects/<exe-name>/UsageTests/Misc.tests.cpp" >
+ <Original>
+ v.capacity() >= V
+ </Original>
+ <Expanded>
+ 4 >= 4
+ </Expanded>
+ </Expression>
+ <Section name="resizing bigger changes size and capacity" filename="projects/<exe-name>/UsageTests/Misc.tests.cpp" >
+ <Expression success="true" type="REQUIRE" filename="projects/<exe-name>/UsageTests/Misc.tests.cpp" >
+ <Original>
+ v.size() == 2 * V
+ </Original>
+ <Expanded>
+ 8 == 8
+ </Expanded>
+ </Expression>
+ <Expression success="true" type="REQUIRE" filename="projects/<exe-name>/UsageTests/Misc.tests.cpp" >
+ <Original>
+ v.capacity() >= 2 * V
+ </Original>
+ <Expanded>
+ 8 >= 8
+ </Expanded>
+ </Expression>
+ <OverallResults successes="2" failures="0" expectedFailures="0"/>
+ </Section>
+ <Expression success="true" type="REQUIRE" filename="projects/<exe-name>/UsageTests/Misc.tests.cpp" >
+ <Original>
+ v.size() == V
+ </Original>
+ <Expanded>
+ 4 == 4
+ </Expanded>
+ </Expression>
+ <Expression success="true" type="REQUIRE" filename="projects/<exe-name>/UsageTests/Misc.tests.cpp" >
+ <Original>
+ v.capacity() >= V
+ </Original>
+ <Expanded>
+ 4 >= 4
+ </Expanded>
+ </Expression>
+ <Section name="resizing smaller changes size but not capacity" filename="projects/<exe-name>/UsageTests/Misc.tests.cpp" >
+ <Expression success="true" type="REQUIRE" filename="projects/<exe-name>/UsageTests/Misc.tests.cpp" >
+ <Original>
+ v.size() == 0
+ </Original>
+ <Expanded>
+ 0 == 0
+ </Expanded>
+ </Expression>
+ <Expression success="true" type="REQUIRE" filename="projects/<exe-name>/UsageTests/Misc.tests.cpp" >
+ <Original>
+ v.capacity() >= V
+ </Original>
+ <Expanded>
+ 4 >= 4
+ </Expanded>
+ </Expression>
+ <Section name="We can use the 'swap trick' to reset the capacity" filename="projects/<exe-name>/UsageTests/Misc.tests.cpp" >
+ <Expression success="true" type="REQUIRE" filename="projects/<exe-name>/UsageTests/Misc.tests.cpp" >
+ <Original>
+ v.capacity() == 0
+ </Original>
+ <Expanded>
+ 0 == 0
+ </Expanded>
+ </Expression>
+ <OverallResults successes="1" failures="0" expectedFailures="0"/>
+ </Section>
+ <OverallResults successes="3" failures="0" expectedFailures="0"/>
+ </Section>
+ <Expression success="true" type="REQUIRE" filename="projects/<exe-name>/UsageTests/Misc.tests.cpp" >
+ <Original>
+ v.size() == V
+ </Original>
+ <Expanded>
+ 4 == 4
+ </Expanded>
+ </Expression>
+ <Expression success="true" type="REQUIRE" filename="projects/<exe-name>/UsageTests/Misc.tests.cpp" >
+ <Original>
+ v.capacity() >= V
+ </Original>
+ <Expanded>
+ 4 >= 4
+ </Expanded>
+ </Expression>
+ <Section name="reserving bigger changes capacity but not size" filename="projects/<exe-name>/UsageTests/Misc.tests.cpp" >
+ <Expression success="true" type="REQUIRE" filename="projects/<exe-name>/UsageTests/Misc.tests.cpp" >
+ <Original>
+ v.size() == V
+ </Original>
+ <Expanded>
+ 4 == 4
+ </Expanded>
+ </Expression>
+ <Expression success="true" type="REQUIRE" filename="projects/<exe-name>/UsageTests/Misc.tests.cpp" >
+ <Original>
+ v.capacity() >= 2 * V
+ </Original>
+ <Expanded>
+ 8 >= 8
+ </Expanded>
+ </Expression>
+ <OverallResults successes="2" failures="0" expectedFailures="0"/>
+ </Section>
+ <Expression success="true" type="REQUIRE" filename="projects/<exe-name>/UsageTests/Misc.tests.cpp" >
+ <Original>
+ v.size() == V
+ </Original>
+ <Expanded>
+ 4 == 4
+ </Expanded>
+ </Expression>
+ <Expression success="true" type="REQUIRE" filename="projects/<exe-name>/UsageTests/Misc.tests.cpp" >
+ <Original>
+ v.capacity() >= V
+ </Original>
+ <Expanded>
+ 4 >= 4
+ </Expanded>
+ </Expression>
+ <Section name="reserving smaller does not change size or capacity" filename="projects/<exe-name>/UsageTests/Misc.tests.cpp" >
+ <Expression success="true" type="REQUIRE" filename="projects/<exe-name>/UsageTests/Misc.tests.cpp" >
+ <Original>
+ v.size() == V
+ </Original>
+ <Expanded>
+ 4 == 4
+ </Expanded>
+ </Expression>
+ <Expression success="true" type="REQUIRE" filename="projects/<exe-name>/UsageTests/Misc.tests.cpp" >
+ <Original>
+ v.capacity() >= V
+ </Original>
+ <Expanded>
+ 4 >= 4
+ </Expanded>
+ </Expression>
+ <OverallResults successes="2" failures="0" expectedFailures="0"/>
+ </Section>
+ <OverallResult success="true"/>
+ </TestCase>
+ <TestCase name="TemplateTestSig: vectors can be sized and resized - int,5" tags="[nttp][template][vector]" filename="projects/<exe-name>/UsageTests/Misc.tests.cpp" >
+ <Expression success="true" type="REQUIRE" filename="projects/<exe-name>/UsageTests/Misc.tests.cpp" >
+ <Original>
+ v.size() == V
+ </Original>
+ <Expanded>
+ 5 == 5
+ </Expanded>
+ </Expression>
+ <Expression success="true" type="REQUIRE" filename="projects/<exe-name>/UsageTests/Misc.tests.cpp" >
+ <Original>
+ v.capacity() >= V
+ </Original>
+ <Expanded>
+ 5 >= 5
+ </Expanded>
+ </Expression>
+ <Section name="resizing bigger changes size and capacity" filename="projects/<exe-name>/UsageTests/Misc.tests.cpp" >
+ <Expression success="true" type="REQUIRE" filename="projects/<exe-name>/UsageTests/Misc.tests.cpp" >
+ <Original>
+ v.size() == 2 * V
+ </Original>
+ <Expanded>
+ 10 == 10
+ </Expanded>
+ </Expression>
+ <Expression success="true" type="REQUIRE" filename="projects/<exe-name>/UsageTests/Misc.tests.cpp" >
+ <Original>
+ v.capacity() >= 2 * V
+ </Original>
+ <Expanded>
+ 10 >= 10
+ </Expanded>
+ </Expression>
+ <OverallResults successes="2" failures="0" expectedFailures="0"/>
+ </Section>
+ <Expression success="true" type="REQUIRE" filename="projects/<exe-name>/UsageTests/Misc.tests.cpp" >
+ <Original>
+ v.size() == V
+ </Original>
+ <Expanded>
+ 5 == 5
+ </Expanded>
+ </Expression>
+ <Expression success="true" type="REQUIRE" filename="projects/<exe-name>/UsageTests/Misc.tests.cpp" >
+ <Original>
+ v.capacity() >= V
+ </Original>
+ <Expanded>
+ 5 >= 5
+ </Expanded>
+ </Expression>
+ <Section name="resizing smaller changes size but not capacity" filename="projects/<exe-name>/UsageTests/Misc.tests.cpp" >
+ <Expression success="true" type="REQUIRE" filename="projects/<exe-name>/UsageTests/Misc.tests.cpp" >
+ <Original>
+ v.size() == 0
+ </Original>
+ <Expanded>
+ 0 == 0
+ </Expanded>
+ </Expression>
+ <Expression success="true" type="REQUIRE" filename="projects/<exe-name>/UsageTests/Misc.tests.cpp" >
+ <Original>
+ v.capacity() >= V
+ </Original>
+ <Expanded>
+ 5 >= 5
+ </Expanded>
+ </Expression>
+ <Section name="We can use the 'swap trick' to reset the capacity" filename="projects/<exe-name>/UsageTests/Misc.tests.cpp" >
+ <Expression success="true" type="REQUIRE" filename="projects/<exe-name>/UsageTests/Misc.tests.cpp" >
+ <Original>
+ v.capacity() == 0
+ </Original>
+ <Expanded>
+ 0 == 0
+ </Expanded>
+ </Expression>
+ <OverallResults successes="1" failures="0" expectedFailures="0"/>
+ </Section>
+ <OverallResults successes="3" failures="0" expectedFailures="0"/>
+ </Section>
+ <Expression success="true" type="REQUIRE" filename="projects/<exe-name>/UsageTests/Misc.tests.cpp" >
+ <Original>
+ v.size() == V
+ </Original>
+ <Expanded>
+ 5 == 5
+ </Expanded>
+ </Expression>
+ <Expression success="true" type="REQUIRE" filename="projects/<exe-name>/UsageTests/Misc.tests.cpp" >
+ <Original>
+ v.capacity() >= V
+ </Original>
+ <Expanded>
+ 5 >= 5
+ </Expanded>
+ </Expression>
+ <Section name="reserving bigger changes capacity but not size" filename="projects/<exe-name>/UsageTests/Misc.tests.cpp" >
+ <Expression success="true" type="REQUIRE" filename="projects/<exe-name>/UsageTests/Misc.tests.cpp" >
+ <Original>
+ v.size() == V
+ </Original>
+ <Expanded>
+ 5 == 5
+ </Expanded>
+ </Expression>
+ <Expression success="true" type="REQUIRE" filename="projects/<exe-name>/UsageTests/Misc.tests.cpp" >
+ <Original>
+ v.capacity() >= 2 * V
+ </Original>
+ <Expanded>
+ 10 >= 10
+ </Expanded>
+ </Expression>
+ <OverallResults successes="2" failures="0" expectedFailures="0"/>
+ </Section>
+ <Expression success="true" type="REQUIRE" filename="projects/<exe-name>/UsageTests/Misc.tests.cpp" >
+ <Original>
+ v.size() == V
+ </Original>
+ <Expanded>
+ 5 == 5
+ </Expanded>
+ </Expression>
+ <Expression success="true" type="REQUIRE" filename="projects/<exe-name>/UsageTests/Misc.tests.cpp" >
+ <Original>
+ v.capacity() >= V
+ </Original>
+ <Expanded>
+ 5 >= 5
+ </Expanded>
+ </Expression>
+ <Section name="reserving smaller does not change size or capacity" filename="projects/<exe-name>/UsageTests/Misc.tests.cpp" >
+ <Expression success="true" type="REQUIRE" filename="projects/<exe-name>/UsageTests/Misc.tests.cpp" >
+ <Original>
+ v.size() == V
+ </Original>
+ <Expanded>
+ 5 == 5
+ </Expanded>
+ </Expression>
+ <Expression success="true" type="REQUIRE" filename="projects/<exe-name>/UsageTests/Misc.tests.cpp" >
+ <Original>
+ v.capacity() >= V
+ </Original>
+ <Expanded>
+ 5 >= 5
+ </Expanded>
+ </Expression>
+ <OverallResults successes="2" failures="0" expectedFailures="0"/>
+ </Section>
+ <OverallResult success="true"/>
+ </TestCase>
+ <TestCase name="TemplateTestSig: vectors can be sized and resized - std::string,15" tags="[nttp][template][vector]" filename="projects/<exe-name>/UsageTests/Misc.tests.cpp" >
+ <Expression success="true" type="REQUIRE" filename="projects/<exe-name>/UsageTests/Misc.tests.cpp" >
+ <Original>
+ v.size() == V
+ </Original>
+ <Expanded>
+ 15 == 15
+ </Expanded>
+ </Expression>
+ <Expression success="true" type="REQUIRE" filename="projects/<exe-name>/UsageTests/Misc.tests.cpp" >
+ <Original>
+ v.capacity() >= V
+ </Original>
+ <Expanded>
+ 15 >= 15
+ </Expanded>
+ </Expression>
+ <Section name="resizing bigger changes size and capacity" filename="projects/<exe-name>/UsageTests/Misc.tests.cpp" >
+ <Expression success="true" type="REQUIRE" filename="projects/<exe-name>/UsageTests/Misc.tests.cpp" >
+ <Original>
+ v.size() == 2 * V
+ </Original>
+ <Expanded>
+ 30 == 30
+ </Expanded>
+ </Expression>
+ <Expression success="true" type="REQUIRE" filename="projects/<exe-name>/UsageTests/Misc.tests.cpp" >
+ <Original>
+ v.capacity() >= 2 * V
+ </Original>
+ <Expanded>
+ 30 >= 30
+ </Expanded>
+ </Expression>
+ <OverallResults successes="2" failures="0" expectedFailures="0"/>
+ </Section>
+ <Expression success="true" type="REQUIRE" filename="projects/<exe-name>/UsageTests/Misc.tests.cpp" >
+ <Original>
+ v.size() == V
+ </Original>
+ <Expanded>
+ 15 == 15
+ </Expanded>
+ </Expression>
+ <Expression success="true" type="REQUIRE" filename="projects/<exe-name>/UsageTests/Misc.tests.cpp" >
+ <Original>
+ v.capacity() >= V
+ </Original>
+ <Expanded>
+ 15 >= 15
+ </Expanded>
+ </Expression>
+ <Section name="resizing smaller changes size but not capacity" filename="projects/<exe-name>/UsageTests/Misc.tests.cpp" >
+ <Expression success="true" type="REQUIRE" filename="projects/<exe-name>/UsageTests/Misc.tests.cpp" >
+ <Original>
+ v.size() == 0
+ </Original>
+ <Expanded>
+ 0 == 0
+ </Expanded>
+ </Expression>
+ <Expression success="true" type="REQUIRE" filename="projects/<exe-name>/UsageTests/Misc.tests.cpp" >
+ <Original>
+ v.capacity() >= V
+ </Original>
+ <Expanded>
+ 15 >= 15
+ </Expanded>
+ </Expression>
+ <Section name="We can use the 'swap trick' to reset the capacity" filename="projects/<exe-name>/UsageTests/Misc.tests.cpp" >
+ <Expression success="true" type="REQUIRE" filename="projects/<exe-name>/UsageTests/Misc.tests.cpp" >
+ <Original>
+ v.capacity() == 0
+ </Original>
+ <Expanded>
+ 0 == 0
+ </Expanded>
+ </Expression>
+ <OverallResults successes="1" failures="0" expectedFailures="0"/>
+ </Section>
+ <OverallResults successes="3" failures="0" expectedFailures="0"/>
+ </Section>
+ <Expression success="true" type="REQUIRE" filename="projects/<exe-name>/UsageTests/Misc.tests.cpp" >
+ <Original>
+ v.size() == V
+ </Original>
+ <Expanded>
+ 15 == 15
+ </Expanded>
+ </Expression>
+ <Expression success="true" type="REQUIRE" filename="projects/<exe-name>/UsageTests/Misc.tests.cpp" >
+ <Original>
+ v.capacity() >= V
+ </Original>
+ <Expanded>
+ 15 >= 15
+ </Expanded>
+ </Expression>
+ <Section name="reserving bigger changes capacity but not size" filename="projects/<exe-name>/UsageTests/Misc.tests.cpp" >
+ <Expression success="true" type="REQUIRE" filename="projects/<exe-name>/UsageTests/Misc.tests.cpp" >
+ <Original>
+ v.size() == V
+ </Original>
+ <Expanded>
+ 15 == 15
+ </Expanded>
+ </Expression>
+ <Expression success="true" type="REQUIRE" filename="projects/<exe-name>/UsageTests/Misc.tests.cpp" >
+ <Original>
+ v.capacity() >= 2 * V
+ </Original>
+ <Expanded>
+ 30 >= 30
+ </Expanded>
+ </Expression>
+ <OverallResults successes="2" failures="0" expectedFailures="0"/>
+ </Section>
+ <Expression success="true" type="REQUIRE" filename="projects/<exe-name>/UsageTests/Misc.tests.cpp" >
+ <Original>
+ v.size() == V
+ </Original>
+ <Expanded>
+ 15 == 15
+ </Expanded>
+ </Expression>
+ <Expression success="true" type="REQUIRE" filename="projects/<exe-name>/UsageTests/Misc.tests.cpp" >
+ <Original>
+ v.capacity() >= V
+ </Original>
+ <Expanded>
+ 15 >= 15
+ </Expanded>
+ </Expression>
+ <Section name="reserving smaller does not change size or capacity" filename="projects/<exe-name>/UsageTests/Misc.tests.cpp" >
+ <Expression success="true" type="REQUIRE" filename="projects/<exe-name>/UsageTests/Misc.tests.cpp" >
+ <Original>
+ v.size() == V
+ </Original>
+ <Expanded>
+ 15 == 15
+ </Expanded>
+ </Expression>
+ <Expression success="true" type="REQUIRE" filename="projects/<exe-name>/UsageTests/Misc.tests.cpp" >
+ <Original>
+ v.capacity() >= V
+ </Original>
+ <Expanded>
+ 15 >= 15
+ </Expanded>
+ </Expression>
+ <OverallResults successes="2" failures="0" expectedFailures="0"/>
+ </Section>
+ <OverallResult success="true"/>
+ </TestCase>
<TestCase name="Test case with one argument" filename="projects/<exe-name>/UsageTests/VariadicMacros.tests.cpp" >
<OverallResult success="true"/>
</TestCase>
@@ -10039,6 +12736,9 @@ Message from section two
</Expression>
<OverallResult success="true"/>
</TestCase>
+ <TestCase name="Test with special, characters &quot;in name" tags="[cli][regression]" filename="projects/<exe-name>/IntrospectiveTests/CmdLine.tests.cpp" >
+ <OverallResult success="true"/>
+ </TestCase>
<TestCase name="The NO_FAIL macro reports a failure but does not fail the test" tags="[messages]" filename="projects/<exe-name>/UsageTests/Message.tests.cpp" >
<Expression success="false" type="CHECK_NOFAIL" filename="projects/<exe-name>/UsageTests/Message.tests.cpp" >
<Original>
@@ -10050,10 +12750,10 @@ Message from section two
</Expression>
<OverallResult success="false"/>
</TestCase>
- <TestCase name="This test 'should' fail but doesn't" tags="[!shouldfail][.][failing]" filename="projects/<exe-name>/UsageTests/Misc.tests.cpp" >
+ <TestCase name="This test 'should' fail but doesn't" tags="[!hide][!shouldfail][.][failing]" filename="projects/<exe-name>/UsageTests/Misc.tests.cpp" >
<OverallResult success="false"/>
</TestCase>
- <TestCase name="Thrown string literals are translated" tags="[!throws][.][failing]" filename="projects/<exe-name>/UsageTests/Exception.tests.cpp" >
+ <TestCase name="Thrown string literals are translated" tags="[!hide][!throws][.][failing]" filename="projects/<exe-name>/UsageTests/Exception.tests.cpp" >
<Exception filename="projects/<exe-name>/UsageTests/Exception.tests.cpp" >
For some reason someone is throwing a string literal!
</Exception>
@@ -10634,7 +13334,90 @@ Message from section two
</Section>
<OverallResult success="true"/>
</TestCase>
- <TestCase name="Unexpected exceptions can be translated" tags="[!throws][.][failing]" filename="projects/<exe-name>/UsageTests/Exception.tests.cpp" >
+ <TestCase name="Trim strings" tags="[string-manip]" filename="projects/<exe-name>/IntrospectiveTests/StringManip.tests.cpp" >
+ <Expression success="true" type="REQUIRE" filename="projects/<exe-name>/IntrospectiveTests/StringManip.tests.cpp" >
+ <Original>
+ trim(std::string(no_whitespace)) == no_whitespace
+ </Original>
+ <Expanded>
+ "There is no extra whitespace here"
+==
+"There is no extra whitespace here"
+ </Expanded>
+ </Expression>
+ <Expression success="true" type="REQUIRE" filename="projects/<exe-name>/IntrospectiveTests/StringManip.tests.cpp" >
+ <Original>
+ trim(std::string(leading_whitespace)) == no_whitespace
+ </Original>
+ <Expanded>
+ "There is no extra whitespace here"
+==
+"There is no extra whitespace here"
+ </Expanded>
+ </Expression>
+ <Expression success="true" type="REQUIRE" filename="projects/<exe-name>/IntrospectiveTests/StringManip.tests.cpp" >
+ <Original>
+ trim(std::string(trailing_whitespace)) == no_whitespace
+ </Original>
+ <Expanded>
+ "There is no extra whitespace here"
+==
+"There is no extra whitespace here"
+ </Expanded>
+ </Expression>
+ <Expression success="true" type="REQUIRE" filename="projects/<exe-name>/IntrospectiveTests/StringManip.tests.cpp" >
+ <Original>
+ trim(std::string(whitespace_at_both_ends)) == no_whitespace
+ </Original>
+ <Expanded>
+ "There is no extra whitespace here"
+==
+"There is no extra whitespace here"
+ </Expanded>
+ </Expression>
+ <Expression success="true" type="REQUIRE" filename="projects/<exe-name>/IntrospectiveTests/StringManip.tests.cpp" >
+ <Original>
+ trim(StringRef(no_whitespace)) == StringRef(no_whitespace)
+ </Original>
+ <Expanded>
+ There is no extra whitespace here
+==
+There is no extra whitespace here
+ </Expanded>
+ </Expression>
+ <Expression success="true" type="REQUIRE" filename="projects/<exe-name>/IntrospectiveTests/StringManip.tests.cpp" >
+ <Original>
+ trim(StringRef(leading_whitespace)) == StringRef(no_whitespace)
+ </Original>
+ <Expanded>
+ There is no extra whitespace here
+==
+There is no extra whitespace here
+ </Expanded>
+ </Expression>
+ <Expression success="true" type="REQUIRE" filename="projects/<exe-name>/IntrospectiveTests/StringManip.tests.cpp" >
+ <Original>
+ trim(StringRef(trailing_whitespace)) == StringRef(no_whitespace)
+ </Original>
+ <Expanded>
+ There is no extra whitespace here
+==
+There is no extra whitespace here
+ </Expanded>
+ </Expression>
+ <Expression success="true" type="REQUIRE" filename="projects/<exe-name>/IntrospectiveTests/StringManip.tests.cpp" >
+ <Original>
+ trim(StringRef(whitespace_at_both_ends)) == StringRef(no_whitespace)
+ </Original>
+ <Expanded>
+ There is no extra whitespace here
+==
+There is no extra whitespace here
+ </Expanded>
+ </Expression>
+ <OverallResult success="true"/>
+ </TestCase>
+ <TestCase name="Unexpected exceptions can be translated" tags="[!hide][!throws][.][failing]" filename="projects/<exe-name>/UsageTests/Exception.tests.cpp" >
<Exception filename="projects/<exe-name>/UsageTests/Exception.tests.cpp" >
3.14
</Exception>
@@ -10793,7 +13576,7 @@ Message from section two
</Section>
<OverallResult success="true"/>
</TestCase>
- <TestCase name="Vector Approx matcher -- failing" tags="[.][approx][failing][matchers][vector]" filename="projects/<exe-name>/UsageTests/Matchers.tests.cpp" >
+ <TestCase name="Vector Approx matcher -- failing" tags="[!hide][.][approx][failing][matchers][vector]" filename="projects/<exe-name>/UsageTests/Matchers.tests.cpp" >
<Section name="Empty and non empty vectors are not approx equal" filename="projects/<exe-name>/UsageTests/Matchers.tests.cpp" >
<Expression success="false" type="CHECK_THAT" filename="projects/<exe-name>/UsageTests/Matchers.tests.cpp" >
<Original>
@@ -10948,7 +13731,7 @@ Message from section two
</Section>
<OverallResult success="true"/>
</TestCase>
- <TestCase name="Vector matchers that fail" tags="[.][failing][matchers][vector]" filename="projects/<exe-name>/UsageTests/Matchers.tests.cpp" >
+ <TestCase name="Vector matchers that fail" tags="[!hide][.][failing][matchers][vector]" filename="projects/<exe-name>/UsageTests/Matchers.tests.cpp" >
<Section name="Contains (element)" filename="projects/<exe-name>/UsageTests/Matchers.tests.cpp" >
<Expression success="false" type="CHECK_THAT" filename="projects/<exe-name>/UsageTests/Matchers.tests.cpp" >
<Original>
@@ -11086,13 +13869,13 @@ Message from section two
</Expression>
<OverallResult success="true"/>
</TestCase>
- <TestCase name="When unchecked exceptions are thrown directly they are always failures" tags="[!throws][.][failing]" filename="projects/<exe-name>/UsageTests/Exception.tests.cpp" >
+ <TestCase name="When unchecked exceptions are thrown directly they are always failures" tags="[!hide][!throws][.][failing]" filename="projects/<exe-name>/UsageTests/Exception.tests.cpp" >
<Exception filename="projects/<exe-name>/UsageTests/Exception.tests.cpp" >
unexpected exception
</Exception>
<OverallResult success="false"/>
</TestCase>
- <TestCase name="When unchecked exceptions are thrown during a CHECK the test should continue" tags="[!throws][.][failing]" filename="projects/<exe-name>/UsageTests/Exception.tests.cpp" >
+ <TestCase name="When unchecked exceptions are thrown during a CHECK the test should continue" tags="[!hide][!throws][.][failing]" filename="projects/<exe-name>/UsageTests/Exception.tests.cpp" >
<Expression success="false" type="CHECK" filename="projects/<exe-name>/UsageTests/Exception.tests.cpp" >
<Original>
thisThrows() == 0
@@ -11106,7 +13889,7 @@ Message from section two
</Expression>
<OverallResult success="false"/>
</TestCase>
- <TestCase name="When unchecked exceptions are thrown during a REQUIRE the test should abort fail" tags="[!throws][.][failing]" filename="projects/<exe-name>/UsageTests/Exception.tests.cpp" >
+ <TestCase name="When unchecked exceptions are thrown during a REQUIRE the test should abort fail" tags="[!hide][!throws][.][failing]" filename="projects/<exe-name>/UsageTests/Exception.tests.cpp" >
<Expression success="false" type="REQUIRE" filename="projects/<exe-name>/UsageTests/Exception.tests.cpp" >
<Original>
thisThrows() == 0
@@ -11120,7 +13903,7 @@ Message from section two
</Expression>
<OverallResult success="false"/>
</TestCase>
- <TestCase name="When unchecked exceptions are thrown from functions they are always failures" tags="[!throws][.][failing]" filename="projects/<exe-name>/UsageTests/Exception.tests.cpp" >
+ <TestCase name="When unchecked exceptions are thrown from functions they are always failures" tags="[!hide][!throws][.][failing]" filename="projects/<exe-name>/UsageTests/Exception.tests.cpp" >
<Expression success="false" type="CHECK" filename="projects/<exe-name>/UsageTests/Exception.tests.cpp" >
<Original>
thisThrows() == 0
@@ -11134,7 +13917,7 @@ Message from section two
</Expression>
<OverallResult success="false"/>
</TestCase>
- <TestCase name="When unchecked exceptions are thrown from sections they are always failures" tags="[!throws][.][failing]" filename="projects/<exe-name>/UsageTests/Exception.tests.cpp" >
+ <TestCase name="When unchecked exceptions are thrown from sections they are always failures" tags="[!hide][!throws][.][failing]" filename="projects/<exe-name>/UsageTests/Exception.tests.cpp" >
<Section name="section name" filename="projects/<exe-name>/UsageTests/Exception.tests.cpp" >
<Exception filename="projects/<exe-name>/UsageTests/Exception.tests.cpp" >
unexpected exception
@@ -11146,13 +13929,13 @@ Message from section two
<TestCase name="When unchecked exceptions are thrown, but caught, they do not affect the test" tags="[!throws]" filename="projects/<exe-name>/UsageTests/Exception.tests.cpp" >
<OverallResult success="false"/>
</TestCase>
- <TestCase name="Where the LHS is not a simple value" tags="[.][Tricky][failing]" filename="projects/<exe-name>/UsageTests/Tricky.tests.cpp" >
+ <TestCase name="Where the LHS is not a simple value" tags="[!hide][.][Tricky][failing]" filename="projects/<exe-name>/UsageTests/Tricky.tests.cpp" >
<Warning>
Uncomment the code in this test to check that it gives a sensible compiler error
</Warning>
<OverallResult success="false"/>
</TestCase>
- <TestCase name="Where there is more to the expression after the RHS" tags="[.][Tricky][failing]" filename="projects/<exe-name>/UsageTests/Tricky.tests.cpp" >
+ <TestCase name="Where there is more to the expression after the RHS" tags="[!hide][.][Tricky][failing]" filename="projects/<exe-name>/UsageTests/Tricky.tests.cpp" >
<Warning>
Uncomment the code in this test to check that it gives a sensible compiler error
</Warning>
@@ -11283,376 +14066,31 @@ Message from section two
</Section>
<OverallResult success="true"/>
</TestCase>
- <TestCase name="XmlEncode: UTF-8" tags="[UTF-8][XML]" filename="projects/<exe-name>/IntrospectiveTests/Xml.tests.cpp" >
- <Section name="Valid utf-8 strings" filename="projects/<exe-name>/IntrospectiveTests/Xml.tests.cpp" >
- <Expression success="true" type="CHECK" filename="projects/<exe-name>/IntrospectiveTests/Xml.tests.cpp" >
- <Original>
- encode(u8"Here be 👾") == u8"Here be 👾"
- </Original>
- <Expanded>
- "Here be 👾" == "Here be 👾"
- </Expanded>
- </Expression>
- <Expression success="true" type="CHECK" filename="projects/<exe-name>/IntrospectiveTests/Xml.tests.cpp" >
- <Original>
- encode(u8"Å¡Å¡") == u8"Å¡Å¡"
- </Original>
- <Expanded>
- "Å¡Å¡" == "Å¡Å¡"
- </Expanded>
- </Expression>
- <Expression success="true" type="CHECK" filename="projects/<exe-name>/IntrospectiveTests/Xml.tests.cpp" >
- <Original>
- encode("\xDF\xBF") == "\xDF\xBF"
- </Original>
- <Expanded>
- "ß¿" == "ß¿"
- </Expanded>
- </Expression>
- <Expression success="true" type="CHECK" filename="projects/<exe-name>/IntrospectiveTests/Xml.tests.cpp" >
- <Original>
- encode("\xE0\xA0\x80") == "\xE0\xA0\x80"
- </Original>
- <Expanded>
- "à €" == "à €"
- </Expanded>
- </Expression>
- <Expression success="true" type="CHECK" filename="projects/<exe-name>/IntrospectiveTests/Xml.tests.cpp" >
- <Original>
- encode("\xED\x9F\xBF") == "\xED\x9F\xBF"
- </Original>
- <Expanded>
- "퟿" == "퟿"
- </Expanded>
- </Expression>
- <Expression success="true" type="CHECK" filename="projects/<exe-name>/IntrospectiveTests/Xml.tests.cpp" >
- <Original>
- encode("\xEE\x80\x80") == "\xEE\x80\x80"
- </Original>
- <Expanded>
- "" == ""
- </Expanded>
- </Expression>
- <Expression success="true" type="CHECK" filename="projects/<exe-name>/IntrospectiveTests/Xml.tests.cpp" >
- <Original>
- encode("\xEF\xBF\xBF") == "\xEF\xBF\xBF"
- </Original>
- <Expanded>
- "ï¿¿" == "ï¿¿"
- </Expanded>
- </Expression>
- <Expression success="true" type="CHECK" filename="projects/<exe-name>/IntrospectiveTests/Xml.tests.cpp" >
- <Original>
- encode("\xF0\x90\x80\x80") == "\xF0\x90\x80\x80"
- </Original>
- <Expanded>
- "ð€€" == "ð€€"
- </Expanded>
- </Expression>
- <Expression success="true" type="CHECK" filename="projects/<exe-name>/IntrospectiveTests/Xml.tests.cpp" >
- <Original>
- encode("\xF4\x8F\xBF\xBF") == "\xF4\x8F\xBF\xBF"
- </Original>
- <Expanded>
- "ô¿¿" == "ô¿¿"
- </Expanded>
- </Expression>
- <OverallResults successes="9" failures="0" expectedFailures="0"/>
- </Section>
- <Section name="Invalid utf-8 strings" filename="projects/<exe-name>/IntrospectiveTests/Xml.tests.cpp" >
- <Section name="Various broken strings" filename="projects/<exe-name>/IntrospectiveTests/Xml.tests.cpp" >
- <Expression success="true" type="CHECK" filename="projects/<exe-name>/IntrospectiveTests/Xml.tests.cpp" >
- <Original>
- encode("Here \xFF be 👾") == u8"Here \\xFF be 👾"
- </Original>
- <Expanded>
- "Here \xFF be 👾" == "Here \xFF be 👾"
- </Expanded>
- </Expression>
- <Expression success="true" type="CHECK" filename="projects/<exe-name>/IntrospectiveTests/Xml.tests.cpp" >
- <Original>
- encode("\xFF") == "\\xFF"
- </Original>
- <Expanded>
- "\xFF" == "\xFF"
- </Expanded>
- </Expression>
- <Expression success="true" type="CHECK" filename="projects/<exe-name>/IntrospectiveTests/Xml.tests.cpp" >
- <Original>
- encode("\xC5\xC5\xA0") == u8"\\xC5Å "
- </Original>
- <Expanded>
- "\xC5Å " == "\xC5Å "
- </Expanded>
- </Expression>
- <Expression success="true" type="CHECK" filename="projects/<exe-name>/IntrospectiveTests/Xml.tests.cpp" >
- <Original>
- encode("\xF4\x90\x80\x80") == u8"\\xF4\\x90\\x80\\x80"
- </Original>
- <Expanded>
- "\xF4\x90\x80\x80" == "\xF4\x90\x80\x80"
- </Expanded>
- </Expression>
- <OverallResults successes="4" failures="0" expectedFailures="0"/>
- </Section>
- <OverallResults successes="4" failures="0" expectedFailures="0"/>
- </Section>
- <Section name="Invalid utf-8 strings" filename="projects/<exe-name>/IntrospectiveTests/Xml.tests.cpp" >
- <Section name="Overlong encodings" filename="projects/<exe-name>/IntrospectiveTests/Xml.tests.cpp" >
- <Expression success="true" type="CHECK" filename="projects/<exe-name>/IntrospectiveTests/Xml.tests.cpp" >
- <Original>
- encode("\xC0\x80") == u8"\\xC0\\x80"
- </Original>
- <Expanded>
- "\xC0\x80" == "\xC0\x80"
- </Expanded>
- </Expression>
- <Expression success="true" type="CHECK" filename="projects/<exe-name>/IntrospectiveTests/Xml.tests.cpp" >
- <Original>
- encode("\xF0\x80\x80\x80") == u8"\\xF0\\x80\\x80\\x80"
- </Original>
- <Expanded>
- "\xF0\x80\x80\x80" == "\xF0\x80\x80\x80"
- </Expanded>
- </Expression>
- <Expression success="true" type="CHECK" filename="projects/<exe-name>/IntrospectiveTests/Xml.tests.cpp" >
- <Original>
- encode("\xC1\xBF") == u8"\\xC1\\xBF"
- </Original>
- <Expanded>
- "\xC1\xBF" == "\xC1\xBF"
- </Expanded>
- </Expression>
- <Expression success="true" type="CHECK" filename="projects/<exe-name>/IntrospectiveTests/Xml.tests.cpp" >
- <Original>
- encode("\xE0\x9F\xBF") == u8"\\xE0\\x9F\\xBF"
- </Original>
- <Expanded>
- "\xE0\x9F\xBF" == "\xE0\x9F\xBF"
- </Expanded>
- </Expression>
- <Expression success="true" type="CHECK" filename="projects/<exe-name>/IntrospectiveTests/Xml.tests.cpp" >
- <Original>
- encode("\xF0\x8F\xBF\xBF") == u8"\\xF0\\x8F\\xBF\\xBF"
- </Original>
- <Expanded>
- "\xF0\x8F\xBF\xBF" == "\xF0\x8F\xBF\xBF"
- </Expanded>
- </Expression>
- <OverallResults successes="5" failures="0" expectedFailures="0"/>
- </Section>
- <OverallResults successes="5" failures="0" expectedFailures="0"/>
- </Section>
- <Section name="Invalid utf-8 strings" filename="projects/<exe-name>/IntrospectiveTests/Xml.tests.cpp" >
- <Section name="Surrogate pairs" filename="projects/<exe-name>/IntrospectiveTests/Xml.tests.cpp" >
- <Expression success="true" type="CHECK" filename="projects/<exe-name>/IntrospectiveTests/Xml.tests.cpp" >
- <Original>
- encode("\xED\xA0\x80") == "\xED\xA0\x80"
- </Original>
- <Expanded>
- "í €" == "í €"
- </Expanded>
- </Expression>
- <Expression success="true" type="CHECK" filename="projects/<exe-name>/IntrospectiveTests/Xml.tests.cpp" >
- <Original>
- encode("\xED\xAF\xBF") == "\xED\xAF\xBF"
- </Original>
- <Expanded>
- "í¯¿" == "í¯¿"
- </Expanded>
- </Expression>
- <Expression success="true" type="CHECK" filename="projects/<exe-name>/IntrospectiveTests/Xml.tests.cpp" >
- <Original>
- encode("\xED\xB0\x80") == "\xED\xB0\x80"
- </Original>
- <Expanded>
- "í°€" == "í°€"
- </Expanded>
- </Expression>
- <Expression success="true" type="CHECK" filename="projects/<exe-name>/IntrospectiveTests/Xml.tests.cpp" >
- <Original>
- encode("\xED\xBF\xBF") == "\xED\xBF\xBF"
- </Original>
- <Expanded>
- "í¿¿" == "í¿¿"
- </Expanded>
- </Expression>
- <OverallResults successes="4" failures="0" expectedFailures="0"/>
- </Section>
- <OverallResults successes="4" failures="0" expectedFailures="0"/>
- </Section>
- <Section name="Invalid utf-8 strings" filename="projects/<exe-name>/IntrospectiveTests/Xml.tests.cpp" >
- <Section name="Invalid start byte" filename="projects/<exe-name>/IntrospectiveTests/Xml.tests.cpp" >
- <Expression success="true" type="CHECK" filename="projects/<exe-name>/IntrospectiveTests/Xml.tests.cpp" >
- <Original>
- encode("\x80") == u8"\\x80"
- </Original>
- <Expanded>
- "\x80" == "\x80"
- </Expanded>
- </Expression>
- <Expression success="true" type="CHECK" filename="projects/<exe-name>/IntrospectiveTests/Xml.tests.cpp" >
- <Original>
- encode("\x81") == u8"\\x81"
- </Original>
- <Expanded>
- "\x81" == "\x81"
- </Expanded>
- </Expression>
- <Expression success="true" type="CHECK" filename="projects/<exe-name>/IntrospectiveTests/Xml.tests.cpp" >
- <Original>
- encode("\xBC") == u8"\\xBC"
- </Original>
- <Expanded>
- "\xBC" == "\xBC"
- </Expanded>
- </Expression>
- <Expression success="true" type="CHECK" filename="projects/<exe-name>/IntrospectiveTests/Xml.tests.cpp" >
- <Original>
- encode("\xBF") == u8"\\xBF"
- </Original>
- <Expanded>
- "\xBF" == "\xBF"
- </Expanded>
- </Expression>
- <Expression success="true" type="CHECK" filename="projects/<exe-name>/IntrospectiveTests/Xml.tests.cpp" >
- <Original>
- encode("\xF5\x80\x80\x80") == u8"\\xF5\\x80\\x80\\x80"
- </Original>
- <Expanded>
- "\xF5\x80\x80\x80" == "\xF5\x80\x80\x80"
- </Expanded>
- </Expression>
- <Expression success="true" type="CHECK" filename="projects/<exe-name>/IntrospectiveTests/Xml.tests.cpp" >
- <Original>
- encode("\xF6\x80\x80\x80") == u8"\\xF6\\x80\\x80\\x80"
- </Original>
- <Expanded>
- "\xF6\x80\x80\x80" == "\xF6\x80\x80\x80"
- </Expanded>
- </Expression>
- <Expression success="true" type="CHECK" filename="projects/<exe-name>/IntrospectiveTests/Xml.tests.cpp" >
- <Original>
- encode("\xF7\x80\x80\x80") == u8"\\xF7\\x80\\x80\\x80"
- </Original>
- <Expanded>
- "\xF7\x80\x80\x80" == "\xF7\x80\x80\x80"
- </Expanded>
- </Expression>
- <OverallResults successes="7" failures="0" expectedFailures="0"/>
- </Section>
- <OverallResults successes="7" failures="0" expectedFailures="0"/>
- </Section>
- <Section name="Invalid utf-8 strings" filename="projects/<exe-name>/IntrospectiveTests/Xml.tests.cpp" >
- <Section name="Missing continuation byte(s)" filename="projects/<exe-name>/IntrospectiveTests/Xml.tests.cpp" >
- <Expression success="true" type="CHECK" filename="projects/<exe-name>/IntrospectiveTests/Xml.tests.cpp" >
- <Original>
- encode("\xDE") == u8"\\xDE"
- </Original>
- <Expanded>
- "\xDE" == "\xDE"
- </Expanded>
- </Expression>
- <Expression success="true" type="CHECK" filename="projects/<exe-name>/IntrospectiveTests/Xml.tests.cpp" >
- <Original>
- encode("\xDF") == u8"\\xDF"
- </Original>
- <Expanded>
- "\xDF" == "\xDF"
- </Expanded>
- </Expression>
- <Expression success="true" type="CHECK" filename="projects/<exe-name>/IntrospectiveTests/Xml.tests.cpp" >
- <Original>
- encode("\xE0") == u8"\\xE0"
- </Original>
- <Expanded>
- "\xE0" == "\xE0"
- </Expanded>
- </Expression>
- <Expression success="true" type="CHECK" filename="projects/<exe-name>/IntrospectiveTests/Xml.tests.cpp" >
- <Original>
- encode("\xEF") == u8"\\xEF"
- </Original>
- <Expanded>
- "\xEF" == "\xEF"
- </Expanded>
- </Expression>
- <Expression success="true" type="CHECK" filename="projects/<exe-name>/IntrospectiveTests/Xml.tests.cpp" >
- <Original>
- encode("\xF0") == u8"\\xF0"
- </Original>
- <Expanded>
- "\xF0" == "\xF0"
- </Expanded>
- </Expression>
- <Expression success="true" type="CHECK" filename="projects/<exe-name>/IntrospectiveTests/Xml.tests.cpp" >
- <Original>
- encode("\xF4") == u8"\\xF4"
- </Original>
- <Expanded>
- "\xF4" == "\xF4"
- </Expanded>
- </Expression>
- <Expression success="true" type="CHECK" filename="projects/<exe-name>/IntrospectiveTests/Xml.tests.cpp" >
- <Original>
- encode("\xE0\x80") == u8"\\xE0\\x80"
- </Original>
- <Expanded>
- "\xE0\x80" == "\xE0\x80"
- </Expanded>
- </Expression>
- <Expression success="true" type="CHECK" filename="projects/<exe-name>/IntrospectiveTests/Xml.tests.cpp" >
- <Original>
- encode("\xE0\xBF") == u8"\\xE0\\xBF"
- </Original>
- <Expanded>
- "\xE0\xBF" == "\xE0\xBF"
- </Expanded>
- </Expression>
- <Expression success="true" type="CHECK" filename="projects/<exe-name>/IntrospectiveTests/Xml.tests.cpp" >
- <Original>
- encode("\xE1\x80") == u8"\\xE1\\x80"
- </Original>
- <Expanded>
- "\xE1\x80" == "\xE1\x80"
- </Expanded>
- </Expression>
- <Expression success="true" type="CHECK" filename="projects/<exe-name>/IntrospectiveTests/Xml.tests.cpp" >
- <Original>
- encode("\xF0\x80") == u8"\\xF0\\x80"
- </Original>
- <Expanded>
- "\xF0\x80" == "\xF0\x80"
- </Expanded>
- </Expression>
- <Expression success="true" type="CHECK" filename="projects/<exe-name>/IntrospectiveTests/Xml.tests.cpp" >
- <Original>
- encode("\xF4\x80") == u8"\\xF4\\x80"
- </Original>
- <Expanded>
- "\xF4\x80" == "\xF4\x80"
- </Expanded>
- </Expression>
- <Expression success="true" type="CHECK" filename="projects/<exe-name>/IntrospectiveTests/Xml.tests.cpp" >
- <Original>
- encode("\xF0\x80\x80") == u8"\\xF0\\x80\\x80"
- </Original>
- <Expanded>
- "\xF0\x80\x80" == "\xF0\x80\x80"
- </Expanded>
- </Expression>
- <Expression success="true" type="CHECK" filename="projects/<exe-name>/IntrospectiveTests/Xml.tests.cpp" >
- <Original>
- encode("\xF4\x80\x80") == u8"\\xF4\\x80\\x80"
- </Original>
- <Expanded>
- "\xF4\x80\x80" == "\xF4\x80\x80"
- </Expanded>
- </Expression>
- <OverallResults successes="13" failures="0" expectedFailures="0"/>
- </Section>
- <OverallResults successes="13" failures="0" expectedFailures="0"/>
- </Section>
+ <TestCase name="adding a hide tag implicitly enables all others" tags="[tags]" filename="projects/<exe-name>/IntrospectiveTests/Tag.tests.cpp" >
+ <Expression success="true" type="REQUIRE_THAT" filename="projects/<exe-name>/IntrospectiveTests/Tag.tests.cpp" >
+ <Original>
+ testcase.tags, VectorContains(std::string(".")) &amp;&amp; VectorContains(std::string("!hide"))
+ </Original>
+ <Expanded>
+ { "!hide", "." } ( Contains: "." and Contains: "!hide" )
+ </Expanded>
+ </Expression>
+ <Expression success="true" type="REQUIRE_THAT" filename="projects/<exe-name>/IntrospectiveTests/Tag.tests.cpp" >
+ <Original>
+ testcase.tags, VectorContains(std::string(".")) &amp;&amp; VectorContains(std::string("!hide"))
+ </Original>
+ <Expanded>
+ { "!hide", "." } ( Contains: "." and Contains: "!hide" )
+ </Expanded>
+ </Expression>
+ <Expression success="true" type="REQUIRE_THAT" filename="projects/<exe-name>/IntrospectiveTests/Tag.tests.cpp" >
+ <Original>
+ testcase.tags, VectorContains(std::string(".")) &amp;&amp; VectorContains(std::string("!hide"))
+ </Original>
+ <Expanded>
+ { "!hide", ".", "foo" } ( Contains: "." and Contains: "!hide" )
+ </Expanded>
+ </Expression>
<OverallResult success="true"/>
</TestCase>
<TestCase name="array&lt;int, N> -> toString" tags="[array][containers][toString]" filename="projects/<exe-name>/UsageTests/ToStringVector.tests.cpp" >
@@ -11723,7 +14161,7 @@ Message from section two
</Expression>
<OverallResult success="true"/>
</TestCase>
- <TestCase name="checkedElse, failing" tags="[.][failing]" filename="projects/<exe-name>/UsageTests/Misc.tests.cpp" >
+ <TestCase name="checkedElse, failing" tags="[!hide][.][failing]" filename="projects/<exe-name>/UsageTests/Misc.tests.cpp" >
<Expression success="false" type="CHECKED_ELSE" filename="projects/<exe-name>/UsageTests/Misc.tests.cpp" >
<Original>
flag
@@ -11761,7 +14199,7 @@ Message from section two
</Expression>
<OverallResult success="true"/>
</TestCase>
- <TestCase name="checkedIf, failing" tags="[.][failing]" filename="projects/<exe-name>/UsageTests/Misc.tests.cpp" >
+ <TestCase name="checkedIf, failing" tags="[!hide][.][failing]" filename="projects/<exe-name>/UsageTests/Misc.tests.cpp" >
<Expression success="false" type="CHECKED_IF" filename="projects/<exe-name>/UsageTests/Misc.tests.cpp" >
<Original>
flag
@@ -11875,13 +14313,13 @@ Message from section two
loose text artifact
<OverallResult success="false"/>
</TestCase>
- <TestCase name="just failure" tags="[.][fail][isolated info][messages]" filename="projects/<exe-name>/UsageTests/Message.tests.cpp" >
+ <TestCase name="just failure" tags="[!hide][.][fail][isolated info][messages]" filename="projects/<exe-name>/UsageTests/Message.tests.cpp" >
<Failure filename="projects/<exe-name>/UsageTests/Message.tests.cpp" >
Previous info should not be seen
</Failure>
<OverallResult success="false"/>
</TestCase>
- <TestCase name="just failure after unscoped info" tags="[.][failing][info][unscoped]" filename="projects/<exe-name>/UsageTests/Message.tests.cpp" >
+ <TestCase name="just failure after unscoped info" tags="[!hide][.][failing][info][unscoped]" filename="projects/<exe-name>/UsageTests/Message.tests.cpp" >
<Failure filename="projects/<exe-name>/UsageTests/Message.tests.cpp" >
previous unscoped info SHOULD not be seen
</Failure>
@@ -11906,7 +14344,7 @@ loose text artifact
</Expression>
<OverallResult success="true"/>
</TestCase>
- <TestCase name="looped SECTION tests" tags="[.][failing][sections]" filename="projects/<exe-name>/UsageTests/Misc.tests.cpp" >
+ <TestCase name="looped SECTION tests" tags="[!hide][.][failing][sections]" filename="projects/<exe-name>/UsageTests/Misc.tests.cpp" >
<Section name="b is currently: 0" filename="projects/<exe-name>/UsageTests/Misc.tests.cpp" >
<Expression success="false" type="CHECK" filename="projects/<exe-name>/UsageTests/Misc.tests.cpp" >
<Original>
@@ -12019,7 +14457,7 @@ loose text artifact
</Section>
<OverallResult success="false"/>
</TestCase>
- <TestCase name="looped tests" tags="[.][failing]" filename="projects/<exe-name>/UsageTests/Misc.tests.cpp" >
+ <TestCase name="looped tests" tags="[!hide][.][failing]" filename="projects/<exe-name>/UsageTests/Misc.tests.cpp" >
<Info>
Testing if fib[0] (1) is even
</Info>
@@ -12131,7 +14569,7 @@ loose text artifact
</Warning>
<OverallResult success="false"/>
</TestCase>
- <TestCase name="more nested SECTION tests" tags="[.][failing][sections]" filename="projects/<exe-name>/UsageTests/Misc.tests.cpp" >
+ <TestCase name="more nested SECTION tests" tags="[!hide][.][failing][sections]" filename="projects/<exe-name>/UsageTests/Misc.tests.cpp" >
<Section name="doesn't equal" filename="projects/<exe-name>/UsageTests/Misc.tests.cpp" >
<Section name="equal" filename="projects/<exe-name>/UsageTests/Misc.tests.cpp" >
<Expression success="false" type="REQUIRE" filename="projects/<exe-name>/UsageTests/Misc.tests.cpp" >
@@ -12176,7 +14614,7 @@ loose text artifact
</Section>
<OverallResult success="false"/>
</TestCase>
- <TestCase name="nested SECTION tests" tags="[.][failing][sections]" filename="projects/<exe-name>/UsageTests/Misc.tests.cpp" >
+ <TestCase name="nested SECTION tests" tags="[!hide][.][failing][sections]" filename="projects/<exe-name>/UsageTests/Misc.tests.cpp" >
<Section name="doesn't equal" filename="projects/<exe-name>/UsageTests/Misc.tests.cpp" >
<Expression success="true" type="REQUIRE" filename="projects/<exe-name>/UsageTests/Misc.tests.cpp" >
<Original>
@@ -12220,7 +14658,7 @@ loose text artifact
</Expression>
<OverallResult success="true"/>
</TestCase>
- <TestCase name="non-copyable objects" tags="[.][failing]" filename="projects/<exe-name>/UsageTests/Tricky.tests.cpp" >
+ <TestCase name="non-copyable objects" tags="[!hide][.][failing]" filename="projects/<exe-name>/UsageTests/Tricky.tests.cpp" >
<Expression success="true" type="CHECK" filename="projects/<exe-name>/UsageTests/Tricky.tests.cpp" >
<Original>
ti == typeid(int)
@@ -12234,7 +14672,7 @@ loose text artifact
<TestCase name="not allowed" tags="[!throws]" filename="projects/<exe-name>/UsageTests/Misc.tests.cpp" >
<OverallResult success="true"/>
</TestCase>
- <TestCase name="not prints unscoped info from previous failures" tags="[.][failing][info][unscoped]" filename="projects/<exe-name>/UsageTests/Message.tests.cpp" >
+ <TestCase name="not prints unscoped info from previous failures" tags="[!hide][.][failing][info][unscoped]" filename="projects/<exe-name>/UsageTests/Message.tests.cpp" >
<Info>
this MAY be seen only for the FIRST assertion IF info is printed for passing assertions
</Info>
@@ -12313,6 +14751,74 @@ loose text artifact
</Expression>
<OverallResult success="true"/>
</TestCase>
+ <TestCase name="parseEnums" tags="[Strings][enums]" filename="projects/<exe-name>/IntrospectiveTests/ToString.tests.cpp" >
+ <Section name="No enums" filename="projects/<exe-name>/IntrospectiveTests/ToString.tests.cpp" >
+ <Expression success="true" type="CHECK_THAT" filename="projects/<exe-name>/IntrospectiveTests/ToString.tests.cpp" >
+ <Original>
+ parseEnums( "" ), Equals( std::vector&lt;Catch::StringRef>{} )
+ </Original>
+ <Expanded>
+ { } Equals: { }
+ </Expanded>
+ </Expression>
+ <OverallResults successes="1" failures="0" expectedFailures="0"/>
+ </Section>
+ <Section name="One enum value" filename="projects/<exe-name>/IntrospectiveTests/ToString.tests.cpp" >
+ <Expression success="true" type="CHECK_THAT" filename="projects/<exe-name>/IntrospectiveTests/ToString.tests.cpp" >
+ <Original>
+ parseEnums( "ClassName::EnumName::Value1" ), Equals(std::vector&lt;Catch::StringRef>{"Value1"} )
+ </Original>
+ <Expanded>
+ { Value1 } Equals: { Value1 }
+ </Expanded>
+ </Expression>
+ <Expression success="true" type="CHECK_THAT" filename="projects/<exe-name>/IntrospectiveTests/ToString.tests.cpp" >
+ <Original>
+ parseEnums( "Value1" ), Equals( std::vector&lt;Catch::StringRef>{"Value1"} )
+ </Original>
+ <Expanded>
+ { Value1 } Equals: { Value1 }
+ </Expanded>
+ </Expression>
+ <Expression success="true" type="CHECK_THAT" filename="projects/<exe-name>/IntrospectiveTests/ToString.tests.cpp" >
+ <Original>
+ parseEnums( "EnumName::Value1" ), Equals(std::vector&lt;Catch::StringRef>{"Value1"} )
+ </Original>
+ <Expanded>
+ { Value1 } Equals: { Value1 }
+ </Expanded>
+ </Expression>
+ <OverallResults successes="3" failures="0" expectedFailures="0"/>
+ </Section>
+ <Section name="Multiple enum values" filename="projects/<exe-name>/IntrospectiveTests/ToString.tests.cpp" >
+ <Expression success="true" type="CHECK_THAT" filename="projects/<exe-name>/IntrospectiveTests/ToString.tests.cpp" >
+ <Original>
+ parseEnums( "ClassName::EnumName::Value1, ClassName::EnumName::Value2" ), Equals( std::vector&lt;Catch::StringRef>{"Value1", "Value2"} )
+ </Original>
+ <Expanded>
+ { Value1, Value2 } Equals: { Value1, Value2 }
+ </Expanded>
+ </Expression>
+ <Expression success="true" type="CHECK_THAT" filename="projects/<exe-name>/IntrospectiveTests/ToString.tests.cpp" >
+ <Original>
+ parseEnums( "ClassName::EnumName::Value1, ClassName::EnumName::Value2, ClassName::EnumName::Value3" ), Equals( std::vector&lt;Catch::StringRef>{"Value1", "Value2", "Value3"} )
+ </Original>
+ <Expanded>
+ { Value1, Value2, Value3 } Equals: { Value1, Value2, Value3 }
+ </Expanded>
+ </Expression>
+ <Expression success="true" type="CHECK_THAT" filename="projects/<exe-name>/IntrospectiveTests/ToString.tests.cpp" >
+ <Original>
+ parseEnums( "ClassName::EnumName::Value1,ClassName::EnumName::Value2 , ClassName::EnumName::Value3" ), Equals( std::vector&lt;Catch::StringRef>{"Value1", "Value2", "Value3"} )
+ </Original>
+ <Expanded>
+ { Value1, Value2, Value3 } Equals: { Value1, Value2, Value3 }
+ </Expanded>
+ </Expression>
+ <OverallResults successes="3" failures="0" expectedFailures="0"/>
+ </Section>
+ <OverallResult success="true"/>
+ </TestCase>
<TestCase name="pointer to class" tags="[Tricky]" filename="projects/<exe-name>/UsageTests/Tricky.tests.cpp" >
<Expression success="true" type="REQUIRE" filename="projects/<exe-name>/UsageTests/Tricky.tests.cpp" >
<Original>
@@ -12338,7 +14844,7 @@ loose text artifact
</Expression>
<OverallResult success="true"/>
</TestCase>
- <TestCase name="prints unscoped info on failure" tags="[.][failing][info][unscoped]" filename="projects/<exe-name>/UsageTests/Message.tests.cpp" >
+ <TestCase name="prints unscoped info on failure" tags="[!hide][.][failing][info][unscoped]" filename="projects/<exe-name>/UsageTests/Message.tests.cpp" >
<Info>
this SHOULD be seen
</Info>
@@ -12355,7 +14861,7 @@ loose text artifact
</Expression>
<OverallResult success="false"/>
</TestCase>
- <TestCase name="prints unscoped info only for the first assertion" tags="[.][failing][info][unscoped]" filename="projects/<exe-name>/UsageTests/Message.tests.cpp" >
+ <TestCase name="prints unscoped info only for the first assertion" tags="[!hide][.][failing][info][unscoped]" filename="projects/<exe-name>/UsageTests/Message.tests.cpp" >
<Info>
this SHOULD be seen only ONCE
</Info>
@@ -12396,7 +14902,7 @@ loose text artifact
</Expression>
<OverallResult success="false"/>
</TestCase>
- <TestCase name="random SECTION tests" tags="[.][failing][sections]" filename="projects/<exe-name>/UsageTests/Misc.tests.cpp" >
+ <TestCase name="random SECTION tests" tags="[!hide][.][failing][sections]" filename="projects/<exe-name>/UsageTests/Misc.tests.cpp" >
<Section name="doesn't equal" filename="projects/<exe-name>/UsageTests/Misc.tests.cpp" >
<Expression success="true" type="REQUIRE" filename="projects/<exe-name>/UsageTests/Misc.tests.cpp" >
<Original>
@@ -12429,17 +14935,17 @@ loose text artifact
</Section>
<OverallResult success="true"/>
</TestCase>
- <TestCase name="replaceInPlace" tags="[StringManip][Strings]" filename="projects/<exe-name>/IntrospectiveTests/String.tests.cpp" >
- <Section name="replace single char" filename="projects/<exe-name>/IntrospectiveTests/String.tests.cpp" >
- <Expression success="true" type="CHECK" filename="projects/<exe-name>/IntrospectiveTests/String.tests.cpp" >
+ <TestCase name="replaceInPlace" tags="[string-manip]" filename="projects/<exe-name>/IntrospectiveTests/StringManip.tests.cpp" >
+ <Section name="replace single char" filename="projects/<exe-name>/IntrospectiveTests/StringManip.tests.cpp" >
+ <Expression success="true" type="CHECK" filename="projects/<exe-name>/IntrospectiveTests/StringManip.tests.cpp" >
<Original>
- Catch::replaceInPlace( letters, "b", "z" )
+ Catch::replaceInPlace(letters, "b", "z")
</Original>
<Expanded>
true
</Expanded>
</Expression>
- <Expression success="true" type="CHECK" filename="projects/<exe-name>/IntrospectiveTests/String.tests.cpp" >
+ <Expression success="true" type="CHECK" filename="projects/<exe-name>/IntrospectiveTests/StringManip.tests.cpp" >
<Original>
letters == "azcdefcg"
</Original>
@@ -12449,16 +14955,16 @@ loose text artifact
</Expression>
<OverallResults successes="2" failures="0" expectedFailures="0"/>
</Section>
- <Section name="replace two chars" filename="projects/<exe-name>/IntrospectiveTests/String.tests.cpp" >
- <Expression success="true" type="CHECK" filename="projects/<exe-name>/IntrospectiveTests/String.tests.cpp" >
+ <Section name="replace two chars" filename="projects/<exe-name>/IntrospectiveTests/StringManip.tests.cpp" >
+ <Expression success="true" type="CHECK" filename="projects/<exe-name>/IntrospectiveTests/StringManip.tests.cpp" >
<Original>
- Catch::replaceInPlace( letters, "c", "z" )
+ Catch::replaceInPlace(letters, "c", "z")
</Original>
<Expanded>
true
</Expanded>
</Expression>
- <Expression success="true" type="CHECK" filename="projects/<exe-name>/IntrospectiveTests/String.tests.cpp" >
+ <Expression success="true" type="CHECK" filename="projects/<exe-name>/IntrospectiveTests/StringManip.tests.cpp" >
<Original>
letters == "abzdefzg"
</Original>
@@ -12468,16 +14974,16 @@ loose text artifact
</Expression>
<OverallResults successes="2" failures="0" expectedFailures="0"/>
</Section>
- <Section name="replace first char" filename="projects/<exe-name>/IntrospectiveTests/String.tests.cpp" >
- <Expression success="true" type="CHECK" filename="projects/<exe-name>/IntrospectiveTests/String.tests.cpp" >
+ <Section name="replace first char" filename="projects/<exe-name>/IntrospectiveTests/StringManip.tests.cpp" >
+ <Expression success="true" type="CHECK" filename="projects/<exe-name>/IntrospectiveTests/StringManip.tests.cpp" >
<Original>
- Catch::replaceInPlace( letters, "a", "z" )
+ Catch::replaceInPlace(letters, "a", "z")
</Original>
<Expanded>
true
</Expanded>
</Expression>
- <Expression success="true" type="CHECK" filename="projects/<exe-name>/IntrospectiveTests/String.tests.cpp" >
+ <Expression success="true" type="CHECK" filename="projects/<exe-name>/IntrospectiveTests/StringManip.tests.cpp" >
<Original>
letters == "zbcdefcg"
</Original>
@@ -12487,16 +14993,16 @@ loose text artifact
</Expression>
<OverallResults successes="2" failures="0" expectedFailures="0"/>
</Section>
- <Section name="replace last char" filename="projects/<exe-name>/IntrospectiveTests/String.tests.cpp" >
- <Expression success="true" type="CHECK" filename="projects/<exe-name>/IntrospectiveTests/String.tests.cpp" >
+ <Section name="replace last char" filename="projects/<exe-name>/IntrospectiveTests/StringManip.tests.cpp" >
+ <Expression success="true" type="CHECK" filename="projects/<exe-name>/IntrospectiveTests/StringManip.tests.cpp" >
<Original>
- Catch::replaceInPlace( letters, "g", "z" )
+ Catch::replaceInPlace(letters, "g", "z")
</Original>
<Expanded>
true
</Expanded>
</Expression>
- <Expression success="true" type="CHECK" filename="projects/<exe-name>/IntrospectiveTests/String.tests.cpp" >
+ <Expression success="true" type="CHECK" filename="projects/<exe-name>/IntrospectiveTests/StringManip.tests.cpp" >
<Original>
letters == "abcdefcz"
</Original>
@@ -12506,16 +15012,16 @@ loose text artifact
</Expression>
<OverallResults successes="2" failures="0" expectedFailures="0"/>
</Section>
- <Section name="replace all chars" filename="projects/<exe-name>/IntrospectiveTests/String.tests.cpp" >
- <Expression success="true" type="CHECK" filename="projects/<exe-name>/IntrospectiveTests/String.tests.cpp" >
+ <Section name="replace all chars" filename="projects/<exe-name>/IntrospectiveTests/StringManip.tests.cpp" >
+ <Expression success="true" type="CHECK" filename="projects/<exe-name>/IntrospectiveTests/StringManip.tests.cpp" >
<Original>
- Catch::replaceInPlace( letters, letters, "replaced" )
+ Catch::replaceInPlace(letters, letters, "replaced")
</Original>
<Expanded>
true
</Expanded>
</Expression>
- <Expression success="true" type="CHECK" filename="projects/<exe-name>/IntrospectiveTests/String.tests.cpp" >
+ <Expression success="true" type="CHECK" filename="projects/<exe-name>/IntrospectiveTests/StringManip.tests.cpp" >
<Original>
letters == "replaced"
</Original>
@@ -12525,16 +15031,16 @@ loose text artifact
</Expression>
<OverallResults successes="2" failures="0" expectedFailures="0"/>
</Section>
- <Section name="replace no chars" filename="projects/<exe-name>/IntrospectiveTests/String.tests.cpp" >
- <Expression success="true" type="CHECK_FALSE" filename="projects/<exe-name>/IntrospectiveTests/String.tests.cpp" >
+ <Section name="replace no chars" filename="projects/<exe-name>/IntrospectiveTests/StringManip.tests.cpp" >
+ <Expression success="true" type="CHECK_FALSE" filename="projects/<exe-name>/IntrospectiveTests/StringManip.tests.cpp" >
<Original>
- !(Catch::replaceInPlace( letters, "x", "z" ))
+ !(Catch::replaceInPlace(letters, "x", "z"))
</Original>
<Expanded>
!false
</Expanded>
</Expression>
- <Expression success="true" type="CHECK" filename="projects/<exe-name>/IntrospectiveTests/String.tests.cpp" >
+ <Expression success="true" type="CHECK" filename="projects/<exe-name>/IntrospectiveTests/StringManip.tests.cpp" >
<Original>
letters == letters
</Original>
@@ -12544,16 +15050,16 @@ loose text artifact
</Expression>
<OverallResults successes="2" failures="0" expectedFailures="0"/>
</Section>
- <Section name="escape '" filename="projects/<exe-name>/IntrospectiveTests/String.tests.cpp" >
- <Expression success="true" type="CHECK" filename="projects/<exe-name>/IntrospectiveTests/String.tests.cpp" >
+ <Section name="escape '" filename="projects/<exe-name>/IntrospectiveTests/StringManip.tests.cpp" >
+ <Expression success="true" type="CHECK" filename="projects/<exe-name>/IntrospectiveTests/StringManip.tests.cpp" >
<Original>
- Catch::replaceInPlace( s, "'", "|'" )
+ Catch::replaceInPlace(s, "'", "|'")
</Original>
<Expanded>
true
</Expanded>
</Expression>
- <Expression success="true" type="CHECK" filename="projects/<exe-name>/IntrospectiveTests/String.tests.cpp" >
+ <Expression success="true" type="CHECK" filename="projects/<exe-name>/IntrospectiveTests/StringManip.tests.cpp" >
<Original>
s == "didn|'t"
</Original>
@@ -12568,7 +15074,7 @@ loose text artifact
<TestCase name="second tag" tags="[tag2]" filename="projects/<exe-name>/UsageTests/Misc.tests.cpp" >
<OverallResult success="false"/>
</TestCase>
- <TestCase name="send a single char to INFO" tags="[.][failing]" filename="projects/<exe-name>/UsageTests/Misc.tests.cpp" >
+ <TestCase name="send a single char to INFO" tags="[!hide][.][failing]" filename="projects/<exe-name>/UsageTests/Misc.tests.cpp" >
<Info>
3
</Info>
@@ -12582,7 +15088,7 @@ loose text artifact
</Expression>
<OverallResult success="false"/>
</TestCase>
- <TestCase name="sends information to INFO" tags="[.][failing]" filename="projects/<exe-name>/UsageTests/Message.tests.cpp" >
+ <TestCase name="sends information to INFO" tags="[!hide][.][failing]" filename="projects/<exe-name>/UsageTests/Message.tests.cpp" >
<Info>
hi
</Info>
@@ -12605,12 +15111,39 @@ loose text artifact
testcase.tags, Catch::VectorContains(std::string("magic-tag")) &amp;&amp; Catch::VectorContains(std::string("."))
</Original>
<Expanded>
- { ".", "magic-tag" } ( Contains: "magic-tag" and Contains: "." )
+ { "!hide", ".", "magic-tag" } ( Contains: "magic-tag" and Contains: "." )
+ </Expanded>
+ </Expression>
+ <OverallResult success="true"/>
+ </TestCase>
+ <TestCase name="splitString" tags="[string-manip]" filename="projects/<exe-name>/IntrospectiveTests/StringManip.tests.cpp" >
+ <Expression success="true" type="CHECK_THAT" filename="projects/<exe-name>/IntrospectiveTests/StringManip.tests.cpp" >
+ <Original>
+ splitStringRef("", ','), Equals(std::vector&lt;StringRef>())
+ </Original>
+ <Expanded>
+ { } Equals: { }
+ </Expanded>
+ </Expression>
+ <Expression success="true" type="CHECK_THAT" filename="projects/<exe-name>/IntrospectiveTests/StringManip.tests.cpp" >
+ <Original>
+ splitStringRef("abc", ','), Equals(std::vector&lt;StringRef>{"abc"})
+ </Original>
+ <Expanded>
+ { abc } Equals: { abc }
+ </Expanded>
+ </Expression>
+ <Expression success="true" type="CHECK_THAT" filename="projects/<exe-name>/IntrospectiveTests/StringManip.tests.cpp" >
+ <Original>
+ splitStringRef("abc,def", ','), Equals(std::vector&lt;StringRef>{"abc", "def"})
+ </Original>
+ <Expanded>
+ { abc, def } Equals: { abc, def }
</Expanded>
</Expression>
<OverallResult success="true"/>
</TestCase>
- <TestCase name="stacks unscoped info in loops" tags="[.][failing][info][unscoped]" filename="projects/<exe-name>/UsageTests/Message.tests.cpp" >
+ <TestCase name="stacks unscoped info in loops" tags="[!hide][.][failing][info][unscoped]" filename="projects/<exe-name>/UsageTests/Message.tests.cpp" >
<Info>
Count 1 to 3...
</Info>
@@ -12764,7 +15297,7 @@ loose text artifact
</Expression>
<OverallResult success="true"/>
</TestCase>
- <TestCase name="string literals of different sizes can be compared" tags="[.][Tricky][failing]" filename="projects/<exe-name>/UsageTests/Tricky.tests.cpp" >
+ <TestCase name="string literals of different sizes can be compared" tags="[!hide][.][Tricky][failing]" filename="projects/<exe-name>/UsageTests/Tricky.tests.cpp" >
<Expression success="false" type="REQUIRE" filename="projects/<exe-name>/UsageTests/Tricky.tests.cpp" >
<Original>
std::string( "first" ) == "second"
@@ -12986,7 +15519,7 @@ loose text artifact
</Expression>
<OverallResult success="true"/>
</TestCase>
- <TestCase name="thrown std::strings are translated" tags="[!throws][.][failing]" filename="projects/<exe-name>/UsageTests/Exception.tests.cpp" >
+ <TestCase name="thrown std::strings are translated" tags="[!hide][!throws][.][failing]" filename="projects/<exe-name>/UsageTests/Exception.tests.cpp" >
<Exception filename="projects/<exe-name>/UsageTests/Exception.tests.cpp" >
Why would you throw a std::string?
</Exception>
@@ -13504,7 +16037,7 @@ loose text artifact
</Section>
<OverallResult success="true"/>
</TestCase>
- <OverallResults successes="1283" failures="142" expectedFailures="21"/>
+ <OverallResults successes="1524" failures="149" expectedFailures="21"/>
</Group>
- <OverallResults successes="1283" failures="141" expectedFailures="21"/>
+ <OverallResults successes="1524" failures="148" expectedFailures="21"/>
</Catch>
diff --git a/projects/SelfTest/IntrospectiveTests/CmdLine.tests.cpp b/projects/SelfTest/IntrospectiveTests/CmdLine.tests.cpp
index 9b5b0ed7..6e590326 100644
--- a/projects/SelfTest/IntrospectiveTests/CmdLine.tests.cpp
+++ b/projects/SelfTest/IntrospectiveTests/CmdLine.tests.cpp
@@ -17,7 +17,7 @@
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" ) {
+TEST_CASE( "Parse test names and tags", "[command-line][test-spec]" ) {
using Catch::parseTestSpec;
using Catch::TestSpec;
@@ -262,7 +262,34 @@ TEST_CASE( "Parse test names and tags" ) {
CHECK( spec.matches( tcC ) == false );
CHECK( spec.matches( tcD ) == true );
}
-
+ SECTION( "Leading and trailing spaces in test spec" ) {
+ TestSpec spec = parseTestSpec( "\" aardvark \"" );
+ CHECK( spec.matches( fakeTestCase( " aardvark " ) ) );
+ CHECK( spec.matches( fakeTestCase( " aardvark" ) ) );
+ CHECK( spec.matches( fakeTestCase( " aardvark " ) ) );
+ CHECK( spec.matches( fakeTestCase( "aardvark " ) ) );
+ CHECK( spec.matches( fakeTestCase( "aardvark" ) ) );
+ }
+ SECTION( "Leading and trailing spaces in test name" ) {
+ TestSpec spec = parseTestSpec( "aardvark" );
+ CHECK( spec.matches( fakeTestCase( " aardvark " ) ) );
+ CHECK( spec.matches( fakeTestCase( " aardvark" ) ) );
+ CHECK( spec.matches( fakeTestCase( " aardvark " ) ) );
+ CHECK( spec.matches( fakeTestCase( "aardvark " ) ) );
+ CHECK( spec.matches( fakeTestCase( "aardvark" ) ) );
+ }
+ SECTION("Shortened hide tags are split apart when parsing") {
+ TestSpec spec = parseTestSpec("[.foo]");
+ CHECK(spec.matches(fakeTestCase("hidden and foo", "[.][foo]")));
+ CHECK_FALSE(spec.matches(fakeTestCase("only foo", "[foo]")));
+ }
+ SECTION("Shortened hide tags also properly handle exclusion") {
+ TestSpec spec = parseTestSpec("~[.foo]");
+ CHECK_FALSE(spec.matches(fakeTestCase("hidden and foo", "[.][foo]")));
+ CHECK_FALSE(spec.matches(fakeTestCase("only foo", "[foo]")));
+ CHECK_FALSE(spec.matches(fakeTestCase("only hidden", "[.]")));
+ CHECK(spec.matches(fakeTestCase("neither foo nor hidden", "[bar]")));
+ }
}
TEST_CASE( "Process can be configured on command line", "[config][command-line]" ) {
@@ -387,7 +414,31 @@ TEST_CASE( "Process can be configured on command line", "[config][command-line]"
REQUIRE_THAT(result.errorMessage(), Contains("convert") && Contains("oops"));
#endif
}
+
+ SECTION("wait-for-keypress") {
+ SECTION("Accepted options") {
+ using tuple_type = std::tuple<char const*, Catch::WaitForKeypress::When>;
+ auto input = GENERATE(table<char const*, Catch::WaitForKeypress::When>({
+ tuple_type{"never", Catch::WaitForKeypress::Never},
+ tuple_type{"start", Catch::WaitForKeypress::BeforeStart},
+ tuple_type{"exit", Catch::WaitForKeypress::BeforeExit},
+ tuple_type{"both", Catch::WaitForKeypress::BeforeStartAndExit},
+ }));
+ CHECK(cli.parse({"test", "--wait-for-keypress", std::get<0>(input)}));
+
+ REQUIRE(config.waitForKeypress == std::get<1>(input));
+ }
+
+ SECTION("invalid options are reported") {
+ auto result = cli.parse({"test", "--wait-for-keypress", "sometimes"});
+ CHECK(!result);
+
+#ifndef CATCH_CONFIG_DISABLE_MATCHERS
+ REQUIRE_THAT(result.errorMessage(), Contains("never") && Contains("both"));
+#endif
+ }
}
+ }
SECTION("nothrow") {
SECTION("-e") {
@@ -462,4 +513,41 @@ TEST_CASE( "Process can be configured on command line", "[config][command-line]"
#endif
}
}
+
+ SECTION("Benchmark options") {
+ SECTION("samples") {
+ CHECK(cli.parse({ "test", "--benchmark-samples=200" }));
+
+ REQUIRE(config.benchmarkSamples == 200);
+ }
+
+ SECTION("resamples") {
+ CHECK(cli.parse({ "test", "--benchmark-resamples=20000" }));
+
+ REQUIRE(config.benchmarkResamples == 20000);
+ }
+
+ SECTION("confidence-interval") {
+ CHECK(cli.parse({ "test", "--benchmark-confidence-interval=0.99" }));
+
+ REQUIRE(config.benchmarkConfidenceInterval == Catch::Detail::Approx(0.99));
+ }
+
+ SECTION("no-analysis") {
+ CHECK(cli.parse({ "test", "--benchmark-no-analysis" }));
+
+ REQUIRE(config.benchmarkNoAnalysis);
+ }
+
+ SECTION("warmup-time") {
+ CHECK(cli.parse({ "test", "--benchmark-warmup-time=10" }));
+
+ REQUIRE(config.benchmarkWarmupTime == 10);
+ }
+ }
+}
+
+TEST_CASE("Test with special, characters \"in name", "[cli][regression]") {
+ // This test case succeeds if we can invoke it from the CLI
+ SUCCEED();
}
diff --git a/projects/SelfTest/IntrospectiveTests/Details.tests.cpp b/projects/SelfTest/IntrospectiveTests/Details.tests.cpp
new file mode 100644
index 00000000..75054fb3
--- /dev/null
+++ b/projects/SelfTest/IntrospectiveTests/Details.tests.cpp
@@ -0,0 +1,23 @@
+/*
+ * 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.hpp"
+
+#if defined(_MSC_VER)
+#pragma warning(push)
+#pragma warning(disable:4702) // unreachable code in the macro expansions
+#endif
+
+TEST_CASE("Check that our error handling macros throw the right exceptions", "[!throws][internals][approvals]") {
+ REQUIRE_THROWS_AS(CATCH_INTERNAL_ERROR(""), std::logic_error);
+ REQUIRE_THROWS_AS(CATCH_ERROR(""), std::domain_error);
+ REQUIRE_THROWS_AS(CATCH_RUNTIME_ERROR(""), std::runtime_error);
+ REQUIRE_THROWS_AS([](){CATCH_ENFORCE(false, "");}(), std::domain_error);
+ REQUIRE_NOTHROW([](){CATCH_ENFORCE(true, "");}());
+}
+
+#if defined(_MSC_VER)
+#pragma warning(pop) // unreachable code in the macro expansions
+#endif
diff --git a/projects/SelfTest/IntrospectiveTests/GeneratorsImpl.tests.cpp b/projects/SelfTest/IntrospectiveTests/GeneratorsImpl.tests.cpp
index dbc1d957..549f3559 100644
--- a/projects/SelfTest/IntrospectiveTests/GeneratorsImpl.tests.cpp
+++ b/projects/SelfTest/IntrospectiveTests/GeneratorsImpl.tests.cpp
@@ -173,6 +173,58 @@ TEST_CASE("Generators internals", "[generators][internals]") {
REQUIRE_FALSE(gen.next());
}
}
+
+ SECTION("Floating Point") {
+ SECTION("Exact") {
+ const auto rangeStart = -1.;
+ const auto rangeEnd = 1.;
+ const auto step = .1;
+
+ auto gen = range(rangeStart, rangeEnd, step);
+ auto expected = rangeStart;
+ while( (rangeEnd - expected) > step ) {
+ INFO( "Current expected value is " << expected )
+ REQUIRE(gen.get() == Approx(expected));
+ REQUIRE(gen.next());
+
+ expected += step;
+ }
+ REQUIRE(gen.get() == Approx( rangeEnd ) );
+ REQUIRE_FALSE(gen.next());
+ }
+ SECTION("Slightly over end") {
+ const auto rangeStart = -1.;
+ const auto rangeEnd = 1.;
+ const auto step = .3;
+
+ auto gen = range(rangeStart, rangeEnd, step);
+ auto expected = rangeStart;
+ while( (rangeEnd - expected) > step ) {
+ INFO( "Current expected value is " << expected )
+ REQUIRE(gen.get() == Approx(expected));
+ REQUIRE(gen.next());
+
+ expected += step;
+ }
+ REQUIRE_FALSE(gen.next());
+ }
+ SECTION("Slightly under end") {
+ const auto rangeStart = -1.;
+ const auto rangeEnd = .9;
+ const auto step = .3;
+
+ auto gen = range(rangeStart, rangeEnd, step);
+ auto expected = rangeStart;
+ while( (rangeEnd - expected) > step ) {
+ INFO( "Current expected value is " << expected )
+ REQUIRE(gen.get() == Approx(expected));
+ REQUIRE(gen.next());
+
+ expected += step;
+ }
+ REQUIRE_FALSE(gen.next());
+ }
+ }
}
SECTION("Negative manual step") {
SECTION("Integer") {
@@ -250,7 +302,7 @@ int const& TestGen::get() const {
}
-TEST_CASE("GENERATE capture macros", "[generators][internals][.approvals]") {
+TEST_CASE("GENERATE capture macros", "[generators][internals][approvals]") {
auto value = GENERATE(take(10, random(0, 10)));
non_copyable nc; nc.value = value;
@@ -258,3 +310,43 @@ TEST_CASE("GENERATE capture macros", "[generators][internals][.approvals]") {
auto value2 = GENERATE_REF(Catch::Generators::GeneratorWrapper<int>(std::unique_ptr<Catch::Generators::IGenerator<int>>(new TestGen(nc))));
REQUIRE(value == value2);
}
+
+TEST_CASE("#1809 - GENERATE_COPY and SingleValueGenerator does not compile", "[generators][compilation][approvals]") {
+ // Verify Issue #1809 fix, only needs to compile.
+ auto a = GENERATE_COPY(1, 2);
+ (void)a;
+ auto b = GENERATE_COPY(as<long>{}, 1, 2);
+ (void)b;
+ int i = 1;
+ int j = 2;
+ auto c = GENERATE_COPY(i, j);
+ (void)c;
+ auto d = GENERATE_COPY(as<long>{}, i, j);
+ (void)d;
+ SUCCEED();
+}
+
+TEST_CASE("Multiple random generators in one test case output different values", "[generators][internals][approvals]") {
+ SECTION("Integer") {
+ auto random1 = Catch::Generators::random(0, 1000);
+ auto random2 = Catch::Generators::random(0, 1000);
+ size_t same = 0;
+ for (size_t i = 0; i < 1000; ++i) {
+ same += random1.get() == random2.get();
+ random1.next(); random2.next();
+ }
+ // 0.5% seems like a sane bound for random identical elements within 1000 runs
+ REQUIRE(same < 5);
+ }
+ SECTION("Float") {
+ auto random1 = Catch::Generators::random(0., 1000.);
+ auto random2 = Catch::Generators::random(0., 1000.);
+ size_t same = 0;
+ for (size_t i = 0; i < 1000; ++i) {
+ same += random1.get() == random2.get();
+ random1.next(); random2.next();
+ }
+ // 0.5% seems like a sane bound for random identical elements within 1000 runs
+ REQUIRE(same < 5);
+ }
+}
diff --git a/projects/SelfTest/IntrospectiveTests/InternalBenchmark.tests.cpp b/projects/SelfTest/IntrospectiveTests/InternalBenchmark.tests.cpp
new file mode 100644
index 00000000..d17998d8
--- /dev/null
+++ b/projects/SelfTest/IntrospectiveTests/InternalBenchmark.tests.cpp
@@ -0,0 +1,405 @@
+/*
+ * Created by Joachim on 16/04/2019.
+ * Adapted from donated nonius code.
+ *
+ * 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.hpp"
+#if defined(CATCH_CONFIG_ENABLE_BENCHMARKING)
+namespace {
+ struct manual_clock {
+ public:
+ using duration = std::chrono::nanoseconds;
+ using time_point = std::chrono::time_point<manual_clock, duration>;
+ using rep = duration::rep;
+ using period = duration::period;
+ enum { is_steady = true };
+
+ static time_point now() {
+ return time_point(duration(tick()));
+ }
+
+ static void advance(int ticks = 1) {
+ tick() += ticks;
+ }
+
+ private:
+ static rep& tick() {
+ static rep the_tick = 0;
+ return the_tick;
+ }
+ };
+
+ struct counting_clock {
+ public:
+ using duration = std::chrono::nanoseconds;
+ using time_point = std::chrono::time_point<counting_clock, duration>;
+ using rep = duration::rep;
+ using period = duration::period;
+ enum { is_steady = true };
+
+ static time_point now() {
+ static rep ticks = 0;
+ return time_point(duration(ticks += rate()));
+ }
+
+ static void set_rate(rep new_rate) { rate() = new_rate; }
+
+ private:
+ static rep& rate() {
+ static rep the_rate = 1;
+ return the_rate;
+ }
+ };
+
+ struct TestChronometerModel : Catch::Benchmark::Detail::ChronometerConcept {
+ int started = 0;
+ int finished = 0;
+
+ void start() override { ++started; }
+ void finish() override { ++finished; }
+ };
+} // namespace
+
+TEST_CASE("warmup", "[benchmark]") {
+ auto rate = 1000;
+ counting_clock::set_rate(rate);
+
+ auto start = counting_clock::now();
+ auto iterations = Catch::Benchmark::Detail::warmup<counting_clock>();
+ auto end = counting_clock::now();
+
+ REQUIRE((iterations * rate) > Catch::Benchmark::Detail::warmup_time.count());
+ REQUIRE((end - start) > Catch::Benchmark::Detail::warmup_time);
+}
+
+TEST_CASE("resolution", "[benchmark]") {
+ auto rate = 1000;
+ counting_clock::set_rate(rate);
+
+ size_t count = 10;
+ auto res = Catch::Benchmark::Detail::resolution<counting_clock>(static_cast<int>(count));
+
+ REQUIRE(res.size() == count);
+
+ for (size_t i = 1; i < count; ++i) {
+ REQUIRE(res[i] == rate);
+ }
+}
+
+TEST_CASE("estimate_clock_resolution", "[benchmark]") {
+ auto rate = 1000;
+ counting_clock::set_rate(rate);
+
+ int iters = 160000;
+ auto res = Catch::Benchmark::Detail::estimate_clock_resolution<counting_clock>(iters);
+
+ REQUIRE(res.mean.count() == rate);
+ REQUIRE(res.outliers.total() == 0);
+}
+
+TEST_CASE("benchmark function call", "[benchmark]") {
+ SECTION("without chronometer") {
+ auto called = 0;
+ auto model = TestChronometerModel{};
+ auto meter = Catch::Benchmark::Chronometer{ model, 1 };
+ auto fn = Catch::Benchmark::Detail::BenchmarkFunction{ [&] {
+ CHECK(model.started == 1);
+ CHECK(model.finished == 0);
+ ++called;
+ } };
+
+ fn(meter);
+
+ CHECK(model.started == 1);
+ CHECK(model.finished == 1);
+ CHECK(called == 1);
+ }
+
+ SECTION("with chronometer") {
+ auto called = 0;
+ auto model = TestChronometerModel{};
+ auto meter = Catch::Benchmark::Chronometer{ model, 1 };
+ auto fn = Catch::Benchmark::Detail::BenchmarkFunction{ [&](Catch::Benchmark::Chronometer) {
+ CHECK(model.started == 0);
+ CHECK(model.finished == 0);
+ ++called;
+ } };
+
+ fn(meter);
+
+ CHECK(model.started == 0);
+ CHECK(model.finished == 0);
+ CHECK(called == 1);
+ }
+}
+
+TEST_CASE("uniform samples", "[benchmark]") {
+ std::vector<double> samples(100);
+ std::fill(samples.begin(), samples.end(), 23);
+
+ using it = std::vector<double>::iterator;
+ auto e = Catch::Benchmark::Detail::bootstrap(0.95, samples.begin(), samples.end(), samples, [](it a, it b) {
+ auto sum = std::accumulate(a, b, 0.);
+ return sum / (b - a);
+ });
+ CHECK(e.point == 23);
+ CHECK(e.upper_bound == 23);
+ CHECK(e.lower_bound == 23);
+ CHECK(e.confidence_interval == 0.95);
+}
+
+
+TEST_CASE("normal_cdf", "[benchmark]") {
+ using Catch::Benchmark::Detail::normal_cdf;
+ CHECK(normal_cdf(0.000000) == Approx(0.50000000000000000));
+ CHECK(normal_cdf(1.000000) == Approx(0.84134474606854293));
+ CHECK(normal_cdf(-1.000000) == Approx(0.15865525393145705));
+ CHECK(normal_cdf(2.809729) == Approx(0.99752083845315409));
+ CHECK(normal_cdf(-1.352570) == Approx(0.08809652095066035));
+}
+
+TEST_CASE("erfc_inv", "[benchmark]") {
+ using Catch::Benchmark::Detail::erfc_inv;
+ CHECK(erfc_inv(1.103560) == Approx(-0.09203687623843015));
+ CHECK(erfc_inv(1.067400) == Approx(-0.05980291115763361));
+ CHECK(erfc_inv(0.050000) == Approx(1.38590382434967796));
+}
+
+TEST_CASE("normal_quantile", "[benchmark]") {
+ using Catch::Benchmark::Detail::normal_quantile;
+ CHECK(normal_quantile(0.551780) == Approx(0.13015979861484198));
+ CHECK(normal_quantile(0.533700) == Approx(0.08457408802851875));
+ CHECK(normal_quantile(0.025000) == Approx(-1.95996398454005449));
+}
+
+
+TEST_CASE("mean", "[benchmark]") {
+ std::vector<double> x{ 10., 20., 14., 16., 30., 24. };
+
+ auto m = Catch::Benchmark::Detail::mean(x.begin(), x.end());
+
+ REQUIRE(m == 19.);
+}
+
+TEST_CASE("weighted_average_quantile", "[benchmark]") {
+ std::vector<double> x{ 10., 20., 14., 16., 30., 24. };
+
+ auto q1 = Catch::Benchmark::Detail::weighted_average_quantile(1, 4, x.begin(), x.end());
+ auto med = Catch::Benchmark::Detail::weighted_average_quantile(1, 2, x.begin(), x.end());
+ auto q3 = Catch::Benchmark::Detail::weighted_average_quantile(3, 4, x.begin(), x.end());
+
+ REQUIRE(q1 == 14.5);
+ REQUIRE(med == 18.);
+ REQUIRE(q3 == 23.);
+}
+
+TEST_CASE("classify_outliers", "[benchmark]") {
+ auto require_outliers = [](Catch::Benchmark::OutlierClassification o, int los, int lom, int him, int his) {
+ REQUIRE(o.low_severe == los);
+ REQUIRE(o.low_mild == lom);
+ REQUIRE(o.high_mild == him);
+ REQUIRE(o.high_severe == his);
+ REQUIRE(o.total() == los + lom + him + his);
+ };
+
+ SECTION("none") {
+ std::vector<double> x{ 10., 20., 14., 16., 30., 24. };
+
+ auto o = Catch::Benchmark::Detail::classify_outliers(x.begin(), x.end());
+
+ REQUIRE(o.samples_seen == static_cast<int>(x.size()));
+ require_outliers(o, 0, 0, 0, 0);
+ }
+ SECTION("low severe") {
+ std::vector<double> x{ -12., 20., 14., 16., 30., 24. };
+
+ auto o = Catch::Benchmark::Detail::classify_outliers(x.begin(), x.end());
+
+ REQUIRE(o.samples_seen == static_cast<int>(x.size()));
+ require_outliers(o, 1, 0, 0, 0);
+ }
+ SECTION("low mild") {
+ std::vector<double> x{ 1., 20., 14., 16., 30., 24. };
+
+ auto o = Catch::Benchmark::Detail::classify_outliers(x.begin(), x.end());
+
+ REQUIRE(o.samples_seen == static_cast<int>(x.size()));
+ require_outliers(o, 0, 1, 0, 0);
+ }
+ SECTION("high mild") {
+ std::vector<double> x{ 10., 20., 14., 16., 36., 24. };
+
+ auto o = Catch::Benchmark::Detail::classify_outliers(x.begin(), x.end());
+
+ REQUIRE(o.samples_seen == static_cast<int>(x.size()));
+ require_outliers(o, 0, 0, 1, 0);
+ }
+ SECTION("high severe") {
+ std::vector<double> x{ 10., 20., 14., 16., 49., 24. };
+
+ auto o = Catch::Benchmark::Detail::classify_outliers(x.begin(), x.end());
+
+ REQUIRE(o.samples_seen == static_cast<int>(x.size()));
+ require_outliers(o, 0, 0, 0, 1);
+ }
+ SECTION("mixed") {
+ std::vector<double> x{ -20., 20., 14., 16., 39., 24. };
+
+ auto o = Catch::Benchmark::Detail::classify_outliers(x.begin(), x.end());
+
+ REQUIRE(o.samples_seen == static_cast<int>(x.size()));
+ require_outliers(o, 1, 0, 1, 0);
+ }
+}
+
+TEST_CASE("analyse", "[benchmark]") {
+ Catch::ConfigData data{};
+ data.benchmarkConfidenceInterval = 0.95;
+ data.benchmarkNoAnalysis = false;
+ data.benchmarkResamples = 1000;
+ data.benchmarkSamples = 99;
+ Catch::Config config{data};
+
+ using Duration = Catch::Benchmark::FloatDuration<Catch::Benchmark::default_clock>;
+
+ Catch::Benchmark::Environment<Duration> env;
+ std::vector<Duration> samples(99);
+ for (size_t i = 0; i < samples.size(); ++i) {
+ samples[i] = Duration(23 + (i % 3 - 1));
+ }
+
+ auto analysis = Catch::Benchmark::Detail::analyse(config, env, samples.begin(), samples.end());
+ CHECK(analysis.mean.point.count() == 23);
+ CHECK(analysis.mean.lower_bound.count() < 23);
+ CHECK(analysis.mean.lower_bound.count() > 22);
+ CHECK(analysis.mean.upper_bound.count() > 23);
+ CHECK(analysis.mean.upper_bound.count() < 24);
+
+ CHECK(analysis.standard_deviation.point.count() > 0.5);
+ CHECK(analysis.standard_deviation.point.count() < 1);
+ CHECK(analysis.standard_deviation.lower_bound.count() > 0.5);
+ CHECK(analysis.standard_deviation.lower_bound.count() < 1);
+ CHECK(analysis.standard_deviation.upper_bound.count() > 0.5);
+ CHECK(analysis.standard_deviation.upper_bound.count() < 1);
+
+ CHECK(analysis.outliers.total() == 0);
+ CHECK(analysis.outliers.low_mild == 0);
+ CHECK(analysis.outliers.low_severe == 0);
+ CHECK(analysis.outliers.high_mild == 0);
+ CHECK(analysis.outliers.high_severe == 0);
+ CHECK(analysis.outliers.samples_seen == samples.size());
+
+ CHECK(analysis.outlier_variance < 0.5);
+ CHECK(analysis.outlier_variance > 0);
+}
+
+TEST_CASE("analyse no analysis", "[benchmark]") {
+ Catch::ConfigData data{};
+ data.benchmarkConfidenceInterval = 0.95;
+ data.benchmarkNoAnalysis = true;
+ data.benchmarkResamples = 1000;
+ data.benchmarkSamples = 99;
+ Catch::Config config{ data };
+
+ using Duration = Catch::Benchmark::FloatDuration<Catch::Benchmark::default_clock>;
+
+ Catch::Benchmark::Environment<Duration> env;
+ std::vector<Duration> samples(99);
+ for (size_t i = 0; i < samples.size(); ++i) {
+ samples[i] = Duration(23 + (i % 3 - 1));
+ }
+
+ auto analysis = Catch::Benchmark::Detail::analyse(config, env, samples.begin(), samples.end());
+ CHECK(analysis.mean.point.count() == 23);
+ CHECK(analysis.mean.lower_bound.count() == 23);
+ CHECK(analysis.mean.upper_bound.count() == 23);
+
+ CHECK(analysis.standard_deviation.point.count() == 0);
+ CHECK(analysis.standard_deviation.lower_bound.count() == 0);
+ CHECK(analysis.standard_deviation.upper_bound.count() == 0);
+
+ CHECK(analysis.outliers.total() == 0);
+ CHECK(analysis.outliers.low_mild == 0);
+ CHECK(analysis.outliers.low_severe == 0);
+ CHECK(analysis.outliers.high_mild == 0);
+ CHECK(analysis.outliers.high_severe == 0);
+ CHECK(analysis.outliers.samples_seen == 0);
+
+ CHECK(analysis.outlier_variance == 0);
+}
+
+TEST_CASE("run_for_at_least, int", "[benchmark]") {
+ manual_clock::duration time(100);
+
+ int old_x = 1;
+ auto Timing = Catch::Benchmark::Detail::run_for_at_least<manual_clock>(time, 1, [&old_x](int x) -> int {
+ CHECK(x >= old_x);
+ manual_clock::advance(x);
+ old_x = x;
+ return x + 17;
+ });
+
+ REQUIRE(Timing.elapsed >= time);
+ REQUIRE(Timing.result == Timing.iterations + 17);
+ REQUIRE(Timing.iterations >= time.count());
+}
+
+TEST_CASE("run_for_at_least, chronometer", "[benchmark]") {
+ manual_clock::duration time(100);
+
+ int old_runs = 1;
+ auto Timing = Catch::Benchmark::Detail::run_for_at_least<manual_clock>(time, 1, [&old_runs](Catch::Benchmark::Chronometer meter) -> int {
+ CHECK(meter.runs() >= old_runs);
+ manual_clock::advance(100);
+ meter.measure([] {
+ manual_clock::advance(1);
+ });
+ old_runs = meter.runs();
+ return meter.runs() + 17;
+ });
+
+ REQUIRE(Timing.elapsed >= time);
+ REQUIRE(Timing.result == Timing.iterations + 17);
+ REQUIRE(Timing.iterations >= time.count());
+}
+
+
+TEST_CASE("measure", "[benchmark]") {
+ auto r = Catch::Benchmark::Detail::measure<manual_clock>([](int x) -> int {
+ CHECK(x == 17);
+ manual_clock::advance(42);
+ return 23;
+ }, 17);
+ auto s = Catch::Benchmark::Detail::measure<manual_clock>([](int x) -> int {
+ CHECK(x == 23);
+ manual_clock::advance(69);
+ return 17;
+ }, 23);
+
+ CHECK(r.elapsed.count() == 42);
+ CHECK(r.result == 23);
+ CHECK(r.iterations == 1);
+
+ CHECK(s.elapsed.count() == 69);
+ CHECK(s.result == 17);
+ CHECK(s.iterations == 1);
+}
+
+TEST_CASE("run benchmark", "[benchmark]") {
+ counting_clock::set_rate(1000);
+ auto start = counting_clock::now();
+
+ Catch::Benchmark::Benchmark bench{ "Test Benchmark", [](Catch::Benchmark::Chronometer meter) {
+ counting_clock::set_rate(100000);
+ meter.measure([] { return counting_clock::now(); });
+ } };
+
+ bench.run<counting_clock>();
+ auto end = counting_clock::now();
+
+ CHECK((end - start).count() == 2867251000);
+}
+#endif // CATCH_CONFIG_ENABLE_BENCHMARKING
diff --git a/projects/SelfTest/IntrospectiveTests/PartTracker.tests.cpp b/projects/SelfTest/IntrospectiveTests/PartTracker.tests.cpp
index 97423265..837d3661 100644
--- a/projects/SelfTest/IntrospectiveTests/PartTracker.tests.cpp
+++ b/projects/SelfTest/IntrospectiveTests/PartTracker.tests.cpp
@@ -189,3 +189,18 @@ TEST_CASE( "#1394 nested", "[.][approvals][tracker]" ) {
REQUIRE(1 == 0);
}
}
+
+// Selecting a "not last" section inside a test case via -c "section" would
+// previously only run the first subsection, instead of running all of them.
+// This allows us to check that `"#1670 regression check" -c A` leads to
+// 2 successful assertions.
+TEST_CASE("#1670 regression check", "[.approvals][tracker]") {
+ SECTION("A") {
+ SECTION("1") SUCCEED();
+ SECTION("2") SUCCEED();
+ }
+ SECTION("B") {
+ SECTION("1") SUCCEED();
+ SECTION("2") SUCCEED();
+ }
+}
diff --git a/projects/SelfTest/IntrospectiveTests/RandomNumberGeneration.tests.cpp b/projects/SelfTest/IntrospectiveTests/RandomNumberGeneration.tests.cpp
new file mode 100644
index 00000000..f8085dbf
--- /dev/null
+++ b/projects/SelfTest/IntrospectiveTests/RandomNumberGeneration.tests.cpp
@@ -0,0 +1,45 @@
+/*
+ * Created by Martin on 06/10/2019.
+ *
+ * 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.hpp"
+
+#include "internal/catch_random_number_generator.h"
+
+TEST_CASE("Our PCG implementation provides expected results for known seeds", "[rng]") {
+ Catch::SimplePcg32 rng;
+ SECTION("Default seeded") {
+ REQUIRE(rng() == 0xfcdb943b);
+ REQUIRE(rng() == 0x6f55b921);
+ REQUIRE(rng() == 0x4c17a916);
+ REQUIRE(rng() == 0x71eae25f);
+ REQUIRE(rng() == 0x6ce7909c);
+ }
+ SECTION("Specific seed") {
+ rng.seed(0xabcd1234);
+ REQUIRE(rng() == 0x57c08495);
+ REQUIRE(rng() == 0x33c956ac);
+ REQUIRE(rng() == 0x2206fd76);
+ REQUIRE(rng() == 0x3501a35b);
+ REQUIRE(rng() == 0xfdffb30f);
+
+ // Also check repeated output after reseeding
+ rng.seed(0xabcd1234);
+ REQUIRE(rng() == 0x57c08495);
+ REQUIRE(rng() == 0x33c956ac);
+ REQUIRE(rng() == 0x2206fd76);
+ REQUIRE(rng() == 0x3501a35b);
+ REQUIRE(rng() == 0xfdffb30f);
+ }
+}
+
+TEST_CASE("Comparison ops", "[rng]") {
+ using Catch::SimplePcg32;
+ REQUIRE(SimplePcg32{} == SimplePcg32{});
+ REQUIRE(SimplePcg32{ 0 } != SimplePcg32{});
+ REQUIRE_FALSE(SimplePcg32{ 1 } == SimplePcg32{ 2 });
+ REQUIRE_FALSE(SimplePcg32{ 1 } != SimplePcg32{ 1 });
+}
diff --git a/projects/SelfTest/IntrospectiveTests/String.tests.cpp b/projects/SelfTest/IntrospectiveTests/String.tests.cpp
index ae21bb3c..3a308657 100644
--- a/projects/SelfTest/IntrospectiveTests/String.tests.cpp
+++ b/projects/SelfTest/IntrospectiveTests/String.tests.cpp
@@ -4,39 +4,15 @@
#include <cstring>
-namespace Catch {
-
- // Implementation of test accessors
- struct StringRefTestAccess {
- static auto isOwned( StringRef const& stringRef ) -> bool {
- return stringRef.isOwned();
- }
- static auto isSubstring( StringRef const& stringRef ) -> bool {
- return stringRef.isSubstring();
- }
- };
-
-
- namespace {
- auto isOwned( StringRef const& stringRef ) -> bool {
- return StringRefTestAccess::isOwned( stringRef );
- }
- auto isSubstring( StringRef const& stringRef ) -> bool {
- return StringRefTestAccess::isSubstring( stringRef );
- }
- } // end anonymous namespace
-
-} // namespace Catch
-
TEST_CASE( "StringRef", "[Strings][StringRef]" ) {
using Catch::StringRef;
- using Catch::isOwned; using Catch::isSubstring;
SECTION( "Empty string" ) {
StringRef empty;
REQUIRE( empty.empty() );
REQUIRE( empty.size() == 0 );
+ REQUIRE( empty.isNullTerminated() );
REQUIRE( std::strcmp( empty.c_str(), "" ) == 0 );
}
@@ -44,29 +20,22 @@ TEST_CASE( "StringRef", "[Strings][StringRef]" ) {
StringRef s = "hello";
REQUIRE( s.empty() == false );
REQUIRE( s.size() == 5 );
- REQUIRE( isSubstring( s ) == false );
+ REQUIRE( s.isNullTerminated() );
- auto rawChars = s.currentData();
+ auto rawChars = s.data();
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 );
- }
+ REQUIRE_NOTHROW(s.c_str());
+ REQUIRE(s.c_str() == rawChars);
+ REQUIRE(s.data() == rawChars);
}
SECTION( "From sub-string" ) {
StringRef original = StringRef( "original string" ).substr(0, 8);
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 ) );
+ REQUIRE_FALSE(original.isNullTerminated());
+ REQUIRE_THROWS(original.c_str());
+ REQUIRE_NOTHROW(original.data());
}
@@ -77,22 +46,9 @@ TEST_CASE( "StringRef", "[Strings][StringRef]" ) {
SECTION( "zero-based substring" ) {
REQUIRE( ss.empty() == false );
REQUIRE( ss.size() == 5 );
- REQUIRE( std::strcmp( ss.c_str(), "hello" ) == 0 );
+ REQUIRE( std::strncmp( ss.data(), "hello", 5 ) == 0 );
REQUIRE( ss == "hello" );
}
- SECTION( "c_str() causes copy" ) {
- REQUIRE( isSubstring( ss ) );
- REQUIRE( isOwned( ss ) == false );
-
- auto rawChars = ss.currentData();
- REQUIRE( rawChars == s.currentData() ); // same pointer value
- REQUIRE( ss.c_str() != rawChars );
-
- REQUIRE( isSubstring( ss ) == false );
- REQUIRE( isOwned( ss ) );
-
- REQUIRE( ss.currentData() != s.currentData() ); // different pointer value
- }
SECTION( "non-zero-based substring") {
ss = s.substr( 6, 6 );
@@ -102,17 +58,32 @@ TEST_CASE( "StringRef", "[Strings][StringRef]" ) {
SECTION( "Pointer values of full refs should match" ) {
StringRef s2 = s;
- REQUIRE( s.c_str() == s2.c_str() );
+ REQUIRE( s.data() == s2.data() );
+ }
+
+ SECTION( "Pointer values of substring refs should also match" ) {
+ REQUIRE( s.data() == ss.data() );
}
- SECTION( "Pointer values of substring refs should not match" ) {
- REQUIRE( s.c_str() != ss.c_str() );
+ SECTION("Past the end substring") {
+ REQUIRE(s.substr(s.size() + 1, 123).empty());
}
+
+ SECTION("Substring off the end are trimmed") {
+ ss = s.substr(6, 123);
+ REQUIRE(std::strcmp(ss.c_str(), "world!") == 0);
+ }
+ // TODO: substring into string + size is longer than end
}
- SECTION( "Comparisons" ) {
- REQUIRE( StringRef("hello") == StringRef("hello") );
- REQUIRE( StringRef("hello") != StringRef("cello") );
+ SECTION( "Comparisons are deep" ) {
+ char buffer1[] = "Hello";
+ char buffer2[] = "Hello";
+ CHECK((char*)buffer1 != (char*)buffer2);
+
+ StringRef left(buffer1), right(buffer2);
+ REQUIRE( left == right );
+ REQUIRE(left != left.substr(0, 3));
}
SECTION( "from std::string" ) {
@@ -139,11 +110,6 @@ TEST_CASE( "StringRef", "[Strings][StringRef]" ) {
SECTION( "to std::string" ) {
StringRef sr = "a stringref";
- SECTION( "implicitly constructed" ) {
- std::string stdStr = sr;
- REQUIRE( stdStr == "a stringref" );
- REQUIRE( stdStr.size() == sr.size() );
- }
SECTION( "explicitly constructed" ) {
std::string stdStr( sr );
REQUIRE( stdStr == "a stringref" );
@@ -151,54 +117,34 @@ TEST_CASE( "StringRef", "[Strings][StringRef]" ) {
}
SECTION( "assigned" ) {
std::string stdStr;
- stdStr = sr;
+ stdStr = static_cast<std::string>(sr);
REQUIRE( stdStr == "a stringref" );
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", "[Strings][StringManip]" ) {
- std::string letters = "abcdefcg";
- SECTION( "replace single char" ) {
- CHECK( Catch::replaceInPlace( letters, "b", "z" ) );
- CHECK( letters == "azcdefcg" );
- }
- SECTION( "replace two chars" ) {
- CHECK( Catch::replaceInPlace( letters, "c", "z" ) );
- CHECK( letters == "abzdefzg" );
- }
- SECTION( "replace first char" ) {
- CHECK( Catch::replaceInPlace( letters, "a", "z" ) );
- CHECK( letters == "zbcdefcg" );
- }
- SECTION( "replace last char" ) {
- CHECK( Catch::replaceInPlace( letters, "g", "z" ) );
- CHECK( letters == "abcdefcz" );
- }
- SECTION( "replace all chars" ) {
- CHECK( Catch::replaceInPlace( letters, letters, "replaced" ) );
- CHECK( letters == "replaced" );
- }
- SECTION( "replace no chars" ) {
- CHECK_FALSE( Catch::replaceInPlace( letters, "x", "z" ) );
- CHECK( letters == letters );
- }
- SECTION( "escape '" ) {
- std::string s = "didn't";
- CHECK( Catch::replaceInPlace( s, "'", "|'" ) );
- CHECK( s == "didn|'t" );
+TEST_CASE("StringRef at compilation time", "[Strings][StringRef][constexpr]") {
+ using Catch::StringRef;
+ SECTION("Simple constructors") {
+ STATIC_REQUIRE(StringRef{}.size() == 0);
+
+ STATIC_REQUIRE(StringRef{ "abc", 3 }.size() == 3);
+ STATIC_REQUIRE(StringRef{ "abc", 3 }.isNullTerminated());
+
+ STATIC_REQUIRE(StringRef{ "abc", 2 }.size() == 2);
+ STATIC_REQUIRE_FALSE(StringRef{ "abc", 2 }.isNullTerminated());
+ }
+ SECTION("UDL construction") {
+ constexpr auto sr1 = "abc"_catch_sr;
+ STATIC_REQUIRE_FALSE(sr1.empty());
+ STATIC_REQUIRE(sr1.size() == 3);
+ STATIC_REQUIRE(sr1.isNullTerminated());
+
+ using Catch::operator"" _sr;
+ constexpr auto sr2 = ""_sr;
+ STATIC_REQUIRE(sr2.empty());
+ STATIC_REQUIRE(sr2.size() == 0);
+ STATIC_REQUIRE(sr2.isNullTerminated());
}
}
diff --git a/projects/SelfTest/IntrospectiveTests/StringManip.tests.cpp b/projects/SelfTest/IntrospectiveTests/StringManip.tests.cpp
new file mode 100644
index 00000000..b817f372
--- /dev/null
+++ b/projects/SelfTest/IntrospectiveTests/StringManip.tests.cpp
@@ -0,0 +1,67 @@
+#include "internal/catch_string_manip.h"
+
+#include "catch.hpp"
+
+static const char * const no_whitespace = "There is no extra whitespace here";
+static const char * const leading_whitespace = " \r \t\n There is no extra whitespace here";
+static const char * const trailing_whitespace = "There is no extra whitespace here \t \n \r ";
+static const char * const whitespace_at_both_ends = " \r\n \t There is no extra whitespace here \t\t\t \n";
+
+TEST_CASE("Trim strings", "[string-manip]") {
+ using Catch::trim; using Catch::StringRef;
+ static_assert(std::is_same<std::string, decltype(trim(std::string{}))>::value, "Trimming std::string should return std::string");
+ static_assert(std::is_same<StringRef, decltype(trim(StringRef{}))>::value, "Trimming StringRef should return StringRef");
+
+ REQUIRE(trim(std::string(no_whitespace)) == no_whitespace);
+ REQUIRE(trim(std::string(leading_whitespace)) == no_whitespace);
+ REQUIRE(trim(std::string(trailing_whitespace)) == no_whitespace);
+ REQUIRE(trim(std::string(whitespace_at_both_ends)) == no_whitespace);
+
+ REQUIRE(trim(StringRef(no_whitespace)) == StringRef(no_whitespace));
+ REQUIRE(trim(StringRef(leading_whitespace)) == StringRef(no_whitespace));
+ REQUIRE(trim(StringRef(trailing_whitespace)) == StringRef(no_whitespace));
+ REQUIRE(trim(StringRef(whitespace_at_both_ends)) == StringRef(no_whitespace));
+}
+
+TEST_CASE("replaceInPlace", "[string-manip]") {
+ std::string letters = "abcdefcg";
+ SECTION("replace single char") {
+ CHECK(Catch::replaceInPlace(letters, "b", "z"));
+ CHECK(letters == "azcdefcg");
+ }
+ SECTION("replace two chars") {
+ CHECK(Catch::replaceInPlace(letters, "c", "z"));
+ CHECK(letters == "abzdefzg");
+ }
+ SECTION("replace first char") {
+ CHECK(Catch::replaceInPlace(letters, "a", "z"));
+ CHECK(letters == "zbcdefcg");
+ }
+ SECTION("replace last char") {
+ CHECK(Catch::replaceInPlace(letters, "g", "z"));
+ CHECK(letters == "abcdefcz");
+ }
+ SECTION("replace all chars") {
+ CHECK(Catch::replaceInPlace(letters, letters, "replaced"));
+ CHECK(letters == "replaced");
+ }
+ SECTION("replace no chars") {
+ CHECK_FALSE(Catch::replaceInPlace(letters, "x", "z"));
+ CHECK(letters == letters);
+ }
+ SECTION("escape '") {
+ std::string s = "didn't";
+ CHECK(Catch::replaceInPlace(s, "'", "|'"));
+ CHECK(s == "didn|'t");
+ }
+}
+
+TEST_CASE("splitString", "[string-manip]") {
+ using namespace Catch::Matchers;
+ using Catch::splitStringRef;
+ using Catch::StringRef;
+
+ CHECK_THAT(splitStringRef("", ','), Equals(std::vector<StringRef>()));
+ CHECK_THAT(splitStringRef("abc", ','), Equals(std::vector<StringRef>{"abc"}));
+ CHECK_THAT(splitStringRef("abc,def", ','), Equals(std::vector<StringRef>{"abc", "def"}));
+}
diff --git a/projects/SelfTest/IntrospectiveTests/Tag.tests.cpp b/projects/SelfTest/IntrospectiveTests/Tag.tests.cpp
index f3890b14..775c2e71 100644
--- a/projects/SelfTest/IntrospectiveTests/Tag.tests.cpp
+++ b/projects/SelfTest/IntrospectiveTests/Tag.tests.cpp
@@ -48,3 +48,10 @@ TEST_CASE("shortened hide tags are split apart") {
auto testcase = Catch::makeTestCase(nullptr, "", {"fake test name", "[.magic-tag]"}, CATCH_INTERNAL_LINEINFO);
REQUIRE_THAT(testcase.tags, Catch::VectorContains(std::string("magic-tag")) && Catch::VectorContains(std::string(".")));
}
+
+TEST_CASE("adding a hide tag implicitly enables all others", "[tags]") {
+ using Catch::VectorContains;
+ auto tag = GENERATE(as<char const*>{}, "[!hide]", "[.]", "[.foo]");
+ auto testcase = Catch::makeTestCase(nullptr, "", {"fake test name", tag}, CATCH_INTERNAL_LINEINFO);
+ REQUIRE_THAT(testcase.tags, VectorContains(std::string(".")) && VectorContains(std::string("!hide")));
+}
diff --git a/projects/SelfTest/IntrospectiveTests/ToString.tests.cpp b/projects/SelfTest/IntrospectiveTests/ToString.tests.cpp
new file mode 100644
index 00000000..caa924f5
--- /dev/null
+++ b/projects/SelfTest/IntrospectiveTests/ToString.tests.cpp
@@ -0,0 +1,42 @@
+#include "catch.hpp"
+
+#include "internal/catch_enum_values_registry.h"
+
+enum class EnumClass3 { Value1, Value2, Value3, Value4 };
+
+
+TEST_CASE( "parseEnums", "[Strings][enums]" ) {
+ using namespace Catch::Matchers;
+ using Catch::Detail::parseEnums;
+
+ SECTION( "No enums" )
+ CHECK_THAT( parseEnums( "" ), Equals( std::vector<Catch::StringRef>{} ) );
+
+ SECTION( "One enum value" ) {
+ CHECK_THAT( parseEnums( "ClassName::EnumName::Value1" ),
+ Equals(std::vector<Catch::StringRef>{"Value1"} ) );
+ CHECK_THAT( parseEnums( "Value1" ),
+ Equals( std::vector<Catch::StringRef>{"Value1"} ) );
+ CHECK_THAT( parseEnums( "EnumName::Value1" ),
+ Equals(std::vector<Catch::StringRef>{"Value1"} ) );
+ }
+
+ SECTION( "Multiple enum values" ) {
+ CHECK_THAT( parseEnums( "ClassName::EnumName::Value1, ClassName::EnumName::Value2" ),
+ Equals( std::vector<Catch::StringRef>{"Value1", "Value2"} ) );
+ CHECK_THAT( parseEnums( "ClassName::EnumName::Value1, ClassName::EnumName::Value2, ClassName::EnumName::Value3" ),
+ Equals( std::vector<Catch::StringRef>{"Value1", "Value2", "Value3"} ) );
+ CHECK_THAT( parseEnums( "ClassName::EnumName::Value1,ClassName::EnumName::Value2 , ClassName::EnumName::Value3" ),
+ Equals( std::vector<Catch::StringRef>{"Value1", "Value2", "Value3"} ) );
+ }
+}
+
+TEST_CASE( "Directly creating an EnumInfo" ) {
+
+ using namespace Catch::Detail;
+ std::unique_ptr<EnumInfo> enumInfo = makeEnumInfo( "EnumName", "EnumName::Value1, EnumName::Value2", {0, 1} );
+
+ CHECK( enumInfo->lookup(0) == "Value1" );
+ CHECK( enumInfo->lookup(1) == "Value2" );
+ CHECK( enumInfo->lookup(3) == "{** unexpected enum value **}" );
+}
diff --git a/projects/SelfTest/IntrospectiveTests/Xml.tests.cpp b/projects/SelfTest/IntrospectiveTests/Xml.tests.cpp
index c3886ab2..bf6c8602 100644
--- a/projects/SelfTest/IntrospectiveTests/Xml.tests.cpp
+++ b/projects/SelfTest/IntrospectiveTests/Xml.tests.cpp
@@ -40,10 +40,11 @@ TEST_CASE( "XmlEncode", "[XML]" ) {
}
// Thanks to Peter Bindels (dascandy) for some of the tests
-TEST_CASE("XmlEncode: UTF-8", "[XML][UTF-8]") {
+TEST_CASE("XmlEncode: UTF-8", "[XML][UTF-8][approvals]") {
+#define ESC(lit) (char*)(lit)
SECTION("Valid utf-8 strings") {
- CHECK(encode(u8"Here be 👾") == u8"Here be 👾");
- CHECK(encode(u8"Å¡Å¡") == u8"Å¡Å¡");
+ CHECK(encode(ESC(u8"Here be 👾")) == ESC(u8"Here be 👾"));
+ CHECK(encode(ESC(u8"Å¡Å¡")) == ESC(u8"Å¡Å¡"));
CHECK(encode("\xDF\xBF") == "\xDF\xBF"); // 0x7FF
CHECK(encode("\xE0\xA0\x80") == "\xE0\xA0\x80"); // 0x800
@@ -55,18 +56,18 @@ TEST_CASE("XmlEncode: UTF-8", "[XML][UTF-8]") {
}
SECTION("Invalid utf-8 strings") {
SECTION("Various broken strings") {
- CHECK(encode("Here \xFF be 👾") == u8"Here \\xFF be 👾");
+ CHECK(encode(ESC("Here \xFF be \xF0\x9F\x91\xBE")) == ESC(u8"Here \\xFF be 👾"));
CHECK(encode("\xFF") == "\\xFF");
- CHECK(encode("\xC5\xC5\xA0") == u8"\\xC5Å ");
- CHECK(encode("\xF4\x90\x80\x80") == u8"\\xF4\\x90\\x80\\x80"); // 0x110000 -- out of unicode range
+ CHECK(encode("\xC5\xC5\xA0") == ESC(u8"\\xC5Å "));
+ CHECK(encode("\xF4\x90\x80\x80") == ESC(u8"\\xF4\\x90\\x80\\x80")); // 0x110000 -- out of unicode range
}
SECTION("Overlong encodings") {
- CHECK(encode("\xC0\x80") == u8"\\xC0\\x80"); // \0
- CHECK(encode("\xF0\x80\x80\x80") == u8"\\xF0\\x80\\x80\\x80"); // Super-over-long \0
- CHECK(encode("\xC1\xBF") == u8"\\xC1\\xBF"); // ASCII char as UTF-8 (0x7F)
- CHECK(encode("\xE0\x9F\xBF") == u8"\\xE0\\x9F\\xBF"); // 0x7FF
- CHECK(encode("\xF0\x8F\xBF\xBF") == u8"\\xF0\\x8F\\xBF\\xBF"); // 0xFFFF
+ CHECK(encode("\xC0\x80") == "\\xC0\\x80"); // \0
+ CHECK(encode("\xF0\x80\x80\x80") == "\\xF0\\x80\\x80\\x80"); // Super-over-long \0
+ CHECK(encode("\xC1\xBF") == "\\xC1\\xBF"); // ASCII char as UTF-8 (0x7F)
+ CHECK(encode("\xE0\x9F\xBF") == "\\xE0\\x9F\\xBF"); // 0x7FF
+ CHECK(encode("\xF0\x8F\xBF\xBF") == "\\xF0\\x8F\\xBF\\xBF"); // 0xFFFF
}
// Note that we actually don't modify surrogate pairs, as we do not do strict checking
@@ -78,35 +79,36 @@ TEST_CASE("XmlEncode: UTF-8", "[XML][UTF-8]") {
}
SECTION("Invalid start byte") {
- CHECK(encode("\x80") == u8"\\x80");
- CHECK(encode("\x81") == u8"\\x81");
- CHECK(encode("\xBC") == u8"\\xBC");
- CHECK(encode("\xBF") == u8"\\xBF");
+ CHECK(encode("\x80") == "\\x80");
+ CHECK(encode("\x81") == "\\x81");
+ CHECK(encode("\xBC") == "\\xBC");
+ CHECK(encode("\xBF") == "\\xBF");
// Out of range
- CHECK(encode("\xF5\x80\x80\x80") == u8"\\xF5\\x80\\x80\\x80");
- CHECK(encode("\xF6\x80\x80\x80") == u8"\\xF6\\x80\\x80\\x80");
- CHECK(encode("\xF7\x80\x80\x80") == u8"\\xF7\\x80\\x80\\x80");
+ CHECK(encode("\xF5\x80\x80\x80") == "\\xF5\\x80\\x80\\x80");
+ CHECK(encode("\xF6\x80\x80\x80") == "\\xF6\\x80\\x80\\x80");
+ CHECK(encode("\xF7\x80\x80\x80") == "\\xF7\\x80\\x80\\x80");
}
SECTION("Missing continuation byte(s)") {
// Missing first continuation byte
- CHECK(encode("\xDE") == u8"\\xDE");
- CHECK(encode("\xDF") == u8"\\xDF");
- CHECK(encode("\xE0") == u8"\\xE0");
- CHECK(encode("\xEF") == u8"\\xEF");
- CHECK(encode("\xF0") == u8"\\xF0");
- CHECK(encode("\xF4") == u8"\\xF4");
+ CHECK(encode("\xDE") == "\\xDE");
+ CHECK(encode("\xDF") == "\\xDF");
+ CHECK(encode("\xE0") == "\\xE0");
+ CHECK(encode("\xEF") == "\\xEF");
+ CHECK(encode("\xF0") == "\\xF0");
+ CHECK(encode("\xF4") == "\\xF4");
// Missing second continuation byte
- CHECK(encode("\xE0\x80") == u8"\\xE0\\x80");
- CHECK(encode("\xE0\xBF") == u8"\\xE0\\xBF");
- CHECK(encode("\xE1\x80") == u8"\\xE1\\x80");
- CHECK(encode("\xF0\x80") == u8"\\xF0\\x80");
- CHECK(encode("\xF4\x80") == u8"\\xF4\\x80");
+ CHECK(encode("\xE0\x80") == "\\xE0\\x80");
+ CHECK(encode("\xE0\xBF") == "\\xE0\\xBF");
+ CHECK(encode("\xE1\x80") == "\\xE1\\x80");
+ CHECK(encode("\xF0\x80") == "\\xF0\\x80");
+ CHECK(encode("\xF4\x80") == "\\xF4\\x80");
// Missing third continuation byte
- CHECK(encode("\xF0\x80\x80") == u8"\\xF0\\x80\\x80");
- CHECK(encode("\xF4\x80\x80") == u8"\\xF4\\x80\\x80");
+ CHECK(encode("\xF0\x80\x80") == "\\xF0\\x80\\x80");
+ CHECK(encode("\xF4\x80\x80") == "\\xF4\\x80\\x80");
}
}
+#undef ESC
}
diff --git a/projects/SelfTest/Misc/invalid-test-names.input b/projects/SelfTest/Misc/invalid-test-names.input
new file mode 100644
index 00000000..e2bc88ec
--- /dev/null
+++ b/projects/SelfTest/Misc/invalid-test-names.input
@@ -0,0 +1 @@
+Test with special, characters in \" name
diff --git a/projects/SelfTest/Misc/plain-old-tests.input b/projects/SelfTest/Misc/plain-old-tests.input
new file mode 100644
index 00000000..ae6d9f1b
--- /dev/null
+++ b/projects/SelfTest/Misc/plain-old-tests.input
@@ -0,0 +1,2 @@
+random SECTION tests
+nested SECTION tests
diff --git a/projects/SelfTest/Misc/special-characters-in-file.input b/projects/SelfTest/Misc/special-characters-in-file.input
new file mode 100644
index 00000000..b68a6bfd
--- /dev/null
+++ b/projects/SelfTest/Misc/special-characters-in-file.input
@@ -0,0 +1 @@
+Test with special\, characters \"in name
diff --git a/projects/SelfTest/TestMain.cpp b/projects/SelfTest/TestMain.cpp
index 1c023ce9..a16f0c22 100644
--- a/projects/SelfTest/TestMain.cpp
+++ b/projects/SelfTest/TestMain.cpp
@@ -13,6 +13,7 @@
#include "reporters/catch_reporter_teamcity.hpp"
#include "reporters/catch_reporter_tap.hpp"
#include "reporters/catch_reporter_automake.hpp"
+#include "reporters/catch_reporter_sonarqube.hpp"
// Some example tag aliases
diff --git a/projects/SelfTest/UsageTests/Approx.tests.cpp b/projects/SelfTest/UsageTests/Approx.tests.cpp
index b95394a0..4029223a 100644
--- a/projects/SelfTest/UsageTests/Approx.tests.cpp
+++ b/projects/SelfTest/UsageTests/Approx.tests.cpp
@@ -61,8 +61,6 @@ TEST_CASE( "Some simple comparisons between doubles", "[Approx]" ) {
REQUIRE( Approx( d ) == 1.23 );
REQUIRE( Approx( d ) != 1.22 );
REQUIRE( Approx( d ) != 1.24 );
-
- REQUIRE(INFINITY == Approx(INFINITY));
}
///////////////////////////////////////////////////////////////////////////////
@@ -183,8 +181,11 @@ TEST_CASE("Epsilon only applies to Approx's value", "[Approx]") {
REQUIRE(101.01 != Approx(100).epsilon(0.01));
}
-TEST_CASE("Assorted miscellaneous tests", "[Approx]") {
+TEST_CASE("Assorted miscellaneous tests", "[Approx][approvals]") {
REQUIRE(INFINITY == Approx(INFINITY));
+ REQUIRE(-INFINITY != Approx(INFINITY));
+ REQUIRE(1 != Approx(INFINITY));
+ REQUIRE(INFINITY != Approx(1));
REQUIRE(NAN != Approx(NAN));
REQUIRE_FALSE(NAN == Approx(NAN));
}
diff --git a/projects/SelfTest/UsageTests/Benchmark.tests.cpp b/projects/SelfTest/UsageTests/Benchmark.tests.cpp
index ddf69504..e795ddd1 100644
--- a/projects/SelfTest/UsageTests/Benchmark.tests.cpp
+++ b/projects/SelfTest/UsageTests/Benchmark.tests.cpp
@@ -2,42 +2,143 @@
#include <map>
-TEST_CASE( "benchmarked", "[!benchmark]" ) {
+#if defined(CATCH_CONFIG_ENABLE_BENCHMARKING)
+namespace {
+ std::uint64_t Fibonacci(std::uint64_t number) {
+ return number < 2 ? 1 : Fibonacci(number - 1) + Fibonacci(number - 2);
+ }
+}
+
+TEST_CASE("Benchmark Fibonacci", "[!benchmark]") {
+ CHECK(Fibonacci(0) == 1);
+ // some more asserts..
+ CHECK(Fibonacci(5) == 8);
+ // some more asserts..
+
+ BENCHMARK("Fibonacci 20") {
+ return Fibonacci(20);
+ };
+
+ BENCHMARK("Fibonacci 25") {
+ return Fibonacci(25);
+ };
+ BENCHMARK("Fibonacci 30") {
+ return Fibonacci(30);
+ };
+
+ BENCHMARK("Fibonacci 35") {
+ return Fibonacci(35);
+ };
+}
+
+TEST_CASE("Benchmark containers", "[!benchmark]") {
static const int size = 100;
std::vector<int> v;
std::map<int, int> m;
- BENCHMARK( "Load up a vector" ) {
- v = std::vector<int>();
- for(int i =0; i < size; ++i )
- v.push_back( i );
- }
- REQUIRE( v.size() == size );
+ SECTION("without generator") {
+ BENCHMARK("Load up a vector") {
+ v = std::vector<int>();
+ for (int i = 0; i < size; ++i)
+ v.push_back(i);
+ };
+ REQUIRE(v.size() == size);
- BENCHMARK( "Load up a map" ) {
- m = std::map<int, int>();
- for(int i =0; i < size; ++i )
- m.insert( { i, i+1 } );
+ // test optimizer control
+ BENCHMARK("Add up a vector's content") {
+ uint64_t add = 0;
+ for (int i = 0; i < size; ++i)
+ add += v[i];
+ return add;
+ };
+
+ BENCHMARK("Load up a map") {
+ m = std::map<int, int>();
+ for (int i = 0; i < size; ++i)
+ m.insert({ i, i + 1 });
+ };
+ REQUIRE(m.size() == size);
+
+ BENCHMARK("Reserved vector") {
+ v = std::vector<int>();
+ v.reserve(size);
+ for (int i = 0; i < size; ++i)
+ v.push_back(i);
+ };
+ REQUIRE(v.size() == size);
+
+ BENCHMARK("Resized vector") {
+ v = std::vector<int>();
+ v.resize(size);
+ for (int i = 0; i < size; ++i)
+ v[i] = i;
+ };
+ REQUIRE(v.size() == size);
+
+ int array[size];
+ BENCHMARK("A fixed size array that should require no allocations") {
+ for (int i = 0; i < size; ++i)
+ array[i] = i;
+ };
+ int sum = 0;
+ for (int i = 0; i < size; ++i)
+ sum += array[i];
+ REQUIRE(sum > size);
+
+ SECTION("XYZ") {
+
+ BENCHMARK_ADVANCED("Load up vector with chronometer")(Catch::Benchmark::Chronometer meter) {
+ std::vector<int> k;
+ meter.measure([&](int idx) {
+ k = std::vector<int>();
+ for (int i = 0; i < size; ++i)
+ k.push_back(idx);
+ });
+ REQUIRE(k.size() == size);
+ };
+
+ int runs = 0;
+ BENCHMARK("Fill vector indexed", benchmarkIndex) {
+ v = std::vector<int>();
+ v.resize(size);
+ for (int i = 0; i < size; ++i)
+ v[i] = benchmarkIndex;
+ runs = benchmarkIndex;
+ };
+
+ for (size_t i = 0; i < v.size(); ++i) {
+ REQUIRE(v[i] == runs);
+ }
+ }
}
- REQUIRE( m.size() == size );
- BENCHMARK( "Reserved vector" ) {
- v = std::vector<int>();
- v.reserve(size);
- for(int i =0; i < size; ++i )
- v.push_back( i );
+ SECTION("with generator") {
+ auto generated = GENERATE(range(0, 10));
+ BENCHMARK("Fill vector generated") {
+ v = std::vector<int>();
+ v.resize(size);
+ for (int i = 0; i < size; ++i)
+ v[i] = generated;
+ };
+ for (size_t i = 0; i < v.size(); ++i) {
+ REQUIRE(v[i] == generated);
+ }
}
- REQUIRE( v.size() == size );
- int array[size];
- BENCHMARK( "A fixed size array that should require no allocations" ) {
- for(int i =0; i < size; ++i )
- array[i] = i;
+ SECTION("construct and destroy example") {
+ BENCHMARK_ADVANCED("construct")(Catch::Benchmark::Chronometer meter) {
+ std::vector<Catch::Benchmark::storage_for<std::string>> storage(meter.runs());
+ meter.measure([&](int i) { storage[i].construct("thing"); });
+ };
+
+ BENCHMARK_ADVANCED("destroy")(Catch::Benchmark::Chronometer meter) {
+ std::vector<Catch::Benchmark::destructable_object<std::string>> storage(meter.runs());
+ for(auto&& o : storage)
+ o.construct("thing");
+ meter.measure([&](int i) { storage[i].destruct(); });
+ };
}
- int sum = 0;
- for(int i =0; i < size; ++i )
- sum += array[i];
- REQUIRE( sum > size );
}
+#endif // CATCH_CONFIG_ENABLE_BENCHMARKING
diff --git a/projects/SelfTest/UsageTests/Class.tests.cpp b/projects/SelfTest/UsageTests/Class.tests.cpp
index 3bde1d82..f658fc19 100644
--- a/projects/SelfTest/UsageTests/Class.tests.cpp
+++ b/projects/SelfTest/UsageTests/Class.tests.cpp
@@ -7,6 +7,7 @@
*/
#include "catch.hpp"
+#include <array>
namespace{ namespace ClassTests {
@@ -58,6 +59,15 @@ struct Template_Foo {
size_t size() { return 0; }
};
+template< typename T, size_t V>
+struct Template_Foo_2 {
+ size_t size() { return V; }
+};
+
+template <int V>
+struct Nttp_Fixture{
+ int value = V;
+};
#endif
@@ -74,11 +84,26 @@ TEMPLATE_TEST_CASE_METHOD(Template_Fixture, "A TEMPLATE_TEST_CASE_METHOD based t
REQUIRE( Template_Fixture<TestType>::m_a == 1 );
}
+TEMPLATE_TEST_CASE_METHOD_SIG(Nttp_Fixture, "A TEMPLATE_TEST_CASE_METHOD_SIG based test run that succeeds", "[class][template][nttp]",((int V), V), 1, 3, 6) {
+ REQUIRE(Nttp_Fixture<V>::value > 0);
+}
+
TEMPLATE_PRODUCT_TEST_CASE_METHOD(Template_Fixture_2, "A TEMPLATE_PRODUCT_TEST_CASE_METHOD based test run that succeeds","[class][template][product]",(std::vector,Template_Foo),(int,float))
{
REQUIRE( Template_Fixture_2<TestType>::m_a.size() == 0 );
}
+TEMPLATE_PRODUCT_TEST_CASE_METHOD_SIG(Template_Fixture_2, "A TEMPLATE_PRODUCT_TEST_CASE_METHOD_SIG based test run that succeeds", "[class][template][product][nttp]", ((typename T, size_t S), T, S),(std::array, Template_Foo_2), ((int,2), (float,6)))
+{
+ REQUIRE(Template_Fixture_2<TestType>{}.m_a.size() >= 2);
+}
+
+using MyTypes = std::tuple<int, char, double>;
+TEMPLATE_LIST_TEST_CASE_METHOD(Template_Fixture, "Template test case method with test types specified inside std::tuple", "[class][template][list]", MyTypes)
+{
+ REQUIRE( Template_Fixture<TestType>::m_a == 1 );
+}
+
// We should be able to write our tests within a different namespace
namespace Inner
{
@@ -92,10 +117,19 @@ namespace Inner
REQUIRE( Template_Fixture<TestType>::m_a == 2 );
}
+ TEMPLATE_TEST_CASE_METHOD_SIG(Nttp_Fixture, "A TEMPLATE_TEST_CASE_METHOD_SIG based test run that fails", "[.][class][template][nttp][failing]", ((int V), V), 1, 3, 6) {
+ REQUIRE(Nttp_Fixture<V>::value == 0);
+ }
+
TEMPLATE_PRODUCT_TEST_CASE_METHOD(Template_Fixture_2, "A TEMPLATE_PRODUCT_TEST_CASE_METHOD based test run that fails","[.][class][template][product][failing]",(std::vector,Template_Foo),(int,float))
{
REQUIRE( Template_Fixture_2<TestType>::m_a.size() == 1 );
}
+
+ TEMPLATE_PRODUCT_TEST_CASE_METHOD_SIG(Template_Fixture_2, "A TEMPLATE_PRODUCT_TEST_CASE_METHOD_SIG based test run that fails", "[.][class][template][product][nttp][failing]", ((typename T, size_t S), T, S), (std::array, Template_Foo_2), ((int, 2), (float, 6)))
+ {
+ REQUIRE(Template_Fixture_2<TestType>{}.m_a.size() < 2);
+ }
}
diff --git a/projects/SelfTest/UsageTests/Compilation.tests.cpp b/projects/SelfTest/UsageTests/Compilation.tests.cpp
index 70b814a6..1c060145 100644
--- a/projects/SelfTest/UsageTests/Compilation.tests.cpp
+++ b/projects/SelfTest/UsageTests/Compilation.tests.cpp
@@ -198,6 +198,40 @@ namespace { namespace CompilationTests {
REQUIRE(std::is_same<TypeList<int>, TypeList<int>>::value);
}
-}} // namespace CompilationTests
+ // #925
+ using signal_t = void (*) (void*);
+
+ struct TestClass {
+ signal_t testMethod_uponComplete_arg = nullptr;
+ };
+ namespace utility {
+ inline static void synchronizing_callback( void * ) { }
+ }
+
+#if defined (_MSC_VER)
+#pragma warning(push)
+// The function pointer comparison below triggers warning because of
+// calling conventions
+#pragma warning(disable:4244)
+#endif
+ TEST_CASE("#925: comparing function pointer to function address failed to compile", "[!nonportable]" ) {
+ TestClass test;
+ REQUIRE(utility::synchronizing_callback != test.testMethod_uponComplete_arg);
+ }
+#if defined (_MSC_VER)
+#pragma warning(pop)
+#endif
+
+ TEST_CASE( "#1027: Bitfields can be captured" ) {
+ struct Y {
+ uint32_t v : 1;
+ };
+ Y y{ 0 };
+ REQUIRE( y.v == 0 );
+ REQUIRE( 0 == y.v );
+ }
+
+
+}} // namespace CompilationTests
diff --git a/projects/SelfTest/UsageTests/EnumToString.tests.cpp b/projects/SelfTest/UsageTests/EnumToString.tests.cpp
index 0b188a82..7f27916e 100644
--- a/projects/SelfTest/UsageTests/EnumToString.tests.cpp
+++ b/projects/SelfTest/UsageTests/EnumToString.tests.cpp
@@ -61,6 +61,39 @@ TEST_CASE( "toString(enum class w/operator<<)", "[toString][enum][enumClass]" )
EnumClass2 e1 = EnumClass2::EnumClass2Value1;
CHECK( ::Catch::Detail::stringify(e1) == "E2/V1" );
- EnumClass2 e3 = static_cast<EnumClass2>(10);
+ auto e3 = static_cast<EnumClass2>(10);
CHECK( ::Catch::Detail::stringify(e3) == "Unknown enum value 10" );
}
+
+enum class EnumClass3 { Value1, Value2, Value3, Value4 };
+
+CATCH_REGISTER_ENUM( EnumClass3, EnumClass3::Value1, EnumClass3::Value2, EnumClass3::Value3 )
+
+
+TEST_CASE( "Enums can quickly have stringification enabled using REGISTER_ENUM" ) {
+ using Catch::Detail::stringify;
+ REQUIRE( stringify( EnumClass3::Value1 ) == "Value1" );
+ REQUIRE( stringify( EnumClass3::Value2 ) == "Value2" );
+ REQUIRE( stringify( EnumClass3::Value3 ) == "Value3" );
+ REQUIRE( stringify( EnumClass3::Value4 ) == "{** unexpected enum value **}" );
+
+ EnumClass3 ec3 = EnumClass3 ::Value2;
+ REQUIRE( stringify( ec3 ) == "Value2" );
+}
+
+namespace Bikeshed {
+ enum class Colours { Red, Green, Blue };
+}
+
+// Important!: This macro must appear at top level scope - not inside a namespace
+// You can fully qualify the names, or use a using if you prefer
+CATCH_REGISTER_ENUM( Bikeshed::Colours,
+ Bikeshed::Colours::Red,
+ Bikeshed::Colours::Green,
+ Bikeshed::Colours::Blue )
+
+TEST_CASE( "Enums in namespaces can quickly have stringification enabled using REGISTER_ENUM" ) {
+ using Catch::Detail::stringify;
+ REQUIRE( stringify( Bikeshed::Colours::Red ) == "Red" );
+ REQUIRE( stringify( Bikeshed::Colours::Blue ) == "Blue" );
+}
diff --git a/projects/SelfTest/UsageTests/Generators.tests.cpp b/projects/SelfTest/UsageTests/Generators.tests.cpp
index f5e3f6a5..0e39bd5c 100644
--- a/projects/SelfTest/UsageTests/Generators.tests.cpp
+++ b/projects/SelfTest/UsageTests/Generators.tests.cpp
@@ -167,6 +167,10 @@ TEST_CASE("Generators -- adapters", "[generators][generic]") {
REQUIRE(chunk2.front() == chunk2.back());
REQUIRE(chunk2.front() < 3);
}
+ SECTION("Chunk size of zero") {
+ auto chunk2 = GENERATE(take(3, chunk(0, value(1))));
+ REQUIRE(chunk2.size() == 0);
+ }
SECTION("Throws on too small generators") {
using namespace Catch::Generators;
REQUIRE_THROWS_AS(chunk(2, value(1)), Catch::GeneratorException);
@@ -176,16 +180,18 @@ TEST_CASE("Generators -- adapters", "[generators][generic]") {
// Note that because of the non-reproducibility of distributions,
// anything involving the random generators cannot be part of approvals
-TEST_CASE("Random generator", "[generators][.][approvals]") {
+TEST_CASE("Random generator", "[generators][approvals]") {
SECTION("Infer int from integral arguments") {
auto val = GENERATE(take(4, random(0, 1)));
STATIC_REQUIRE(std::is_same<decltype(val), int>::value);
- static_cast<void>(val); // Silence VS 2015 unused variable warning
+ REQUIRE(0 <= val);
+ REQUIRE(val <= 1);
}
SECTION("Infer double from double arguments") {
auto val = GENERATE(take(4, random(0., 1.)));
STATIC_REQUIRE(std::is_same<decltype(val), double>::value);
- static_cast<void>(val); // Silence VS 2015 unused variable warning
+ REQUIRE(0. <= val);
+ REQUIRE(val < 1);
}
}
@@ -206,3 +212,45 @@ TEST_CASE("Nested generators and captured variables", "[generators]") {
auto values = GENERATE_COPY(range(from, to));
REQUIRE(values > -6);
}
+
+namespace {
+ size_t call_count = 0;
+ size_t test_count = 0;
+ std::vector<int> make_data() {
+ return { 1, 3, 5, 7, 9, 11 };
+ }
+ std::vector<int> make_data_counted() {
+ ++call_count;
+ return make_data();
+ }
+}
+
+#if defined(__clang__)
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wexit-time-destructors"
+#endif
+
+TEST_CASE("Copy and then generate a range", "[generators]") {
+ SECTION("from var and iterators") {
+ static auto data = make_data();
+
+ // It is important to notice that a generator is only initialized
+ // **once** per run. What this means is that modifying data will not
+ // modify the underlying generator.
+ auto elem = GENERATE_REF(from_range(data.begin(), data.end()));
+ REQUIRE(elem % 2 == 1);
+ }
+ SECTION("From a temporary container") {
+ auto elem = GENERATE(from_range(make_data_counted()));
+ ++test_count;
+ REQUIRE(elem % 2 == 1);
+ }
+ SECTION("Final validation") {
+ REQUIRE(call_count == 1);
+ REQUIRE(make_data().size() == test_count);
+ }
+}
+
+#if defined(__clang__)
+#pragma clang diagnostic pop
+#endif
diff --git a/projects/SelfTest/UsageTests/Matchers.tests.cpp b/projects/SelfTest/UsageTests/Matchers.tests.cpp
index b0b5d58e..23db7b53 100644
--- a/projects/SelfTest/UsageTests/Matchers.tests.cpp
+++ b/projects/SelfTest/UsageTests/Matchers.tests.cpp
@@ -52,11 +52,17 @@ namespace { namespace MatchersTests {
int i;
};
-#if !defined(CATCH_CONFIG_DISABLE_EXCEPTIONS)
+ struct DerivedException : std::exception {
+ char const* what() const noexcept override {
+ return "DerivedException::what";
+ }
+ };
+
void doesNotThrow() {}
+#if !defined(CATCH_CONFIG_DISABLE_EXCEPTIONS)
[[noreturn]]
- void throws(int i) {
+ void throwsSpecialException(int i) {
throw SpecialException{i};
}
@@ -64,6 +70,11 @@ namespace { namespace MatchersTests {
void throwsAsInt(int i) {
throw i;
}
+
+ [[noreturn]]
+ void throwsDerivedException() {
+ throw DerivedException{};
+ }
#endif
class ExceptionMatcher : public Catch::MatcherBase<SpecialException> {
@@ -322,8 +333,8 @@ namespace { namespace MatchersTests {
#if !defined(CATCH_CONFIG_DISABLE_EXCEPTIONS)
TEST_CASE("Exception matchers that succeed", "[matchers][exceptions][!throws]") {
- CHECK_THROWS_MATCHES(throws(1), SpecialException, ExceptionMatcher{1});
- REQUIRE_THROWS_MATCHES(throws(2), SpecialException, ExceptionMatcher{2});
+ CHECK_THROWS_MATCHES(throwsSpecialException(1), SpecialException, ExceptionMatcher{1});
+ REQUIRE_THROWS_MATCHES(throwsSpecialException(2), SpecialException, ExceptionMatcher{2});
}
TEST_CASE("Exception matchers that fail", "[matchers][exceptions][!throws][.failing]") {
@@ -336,13 +347,27 @@ namespace { namespace MatchersTests {
REQUIRE_THROWS_MATCHES(throwsAsInt(1), SpecialException, ExceptionMatcher{1});
}
SECTION("Contents are wrong") {
- CHECK_THROWS_MATCHES(throws(3), SpecialException, ExceptionMatcher{1});
- REQUIRE_THROWS_MATCHES(throws(4), SpecialException, ExceptionMatcher{1});
+ CHECK_THROWS_MATCHES(throwsSpecialException(3), SpecialException, ExceptionMatcher{1});
+ REQUIRE_THROWS_MATCHES(throwsSpecialException(4), SpecialException, ExceptionMatcher{1});
}
}
#endif
TEST_CASE("Floating point matchers: float", "[matchers][floating-point]") {
+ SECTION("Relative") {
+ REQUIRE_THAT(10.f, WithinRel(11.1f, 0.1f));
+ REQUIRE_THAT(10.f, !WithinRel(11.2f, 0.1f));
+ REQUIRE_THAT( 1.f, !WithinRel(0.f, 0.99f));
+ REQUIRE_THAT(-0.f, WithinRel(0.f));
+ SECTION("Some subnormal values") {
+ auto v1 = std::numeric_limits<float>::min();
+ auto v2 = v1;
+ for (int i = 0; i < 5; ++i) {
+ v2 = std::nextafter(v1, 0.f);
+ }
+ REQUIRE_THAT(v1, WithinRel(v2));
+ }
+ }
SECTION("Margin") {
REQUIRE_THAT(1.f, WithinAbs(1.f, 0));
REQUIRE_THAT(0.f, WithinAbs(1.f, 1));
@@ -351,7 +376,6 @@ namespace { namespace MatchersTests {
REQUIRE_THAT(0.f, !WithinAbs(1.f, 0.99f));
REQUIRE_THAT(0.f, WithinAbs(-0.f, 0));
- REQUIRE_THAT(NAN, !WithinAbs(NAN, 0));
REQUIRE_THAT(11.f, !WithinAbs(10.f, 0.5f));
REQUIRE_THAT(10.f, !WithinAbs(11.f, 0.5f));
@@ -362,30 +386,46 @@ namespace { namespace MatchersTests {
REQUIRE_THAT(1.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(0.f, WithinULP(nextafter(0.f, 1.f), 1));
+ REQUIRE_THAT(1.f, WithinULP(nextafter(1.f, 0.f), 1));
+ REQUIRE_THAT(1.f, !WithinULP(nextafter(1.f, 2.f), 0));
REQUIRE_THAT(1.f, WithinULP(1.f, 0));
REQUIRE_THAT(-0.f, WithinULP(0.f, 0));
-
- REQUIRE_THAT(NAN, !WithinULP(NAN, 123));
}
SECTION("Composed") {
REQUIRE_THAT(1.f, WithinAbs(1.f, 0.5) || WithinULP(1.f, 1));
REQUIRE_THAT(1.f, WithinAbs(2.f, 0.5) || WithinULP(1.f, 0));
-
- REQUIRE_THAT(NAN, !(WithinAbs(NAN, 100) || WithinULP(NAN, 123)));
+ REQUIRE_THAT(0.0001f, WithinAbs(0.f, 0.001f) || WithinRel(0.f, 0.1f));
}
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);
+ REQUIRE_THROWS_AS(WithinULP(1.f, static_cast<uint64_t>(-1)), std::domain_error);
+
+ REQUIRE_NOTHROW(WithinRel(1.f, 0.f));
+ REQUIRE_THROWS_AS(WithinRel(1.f, -0.2f), std::domain_error);
+ REQUIRE_THROWS_AS(WithinRel(1.f, 1.f), std::domain_error);
}
}
TEST_CASE("Floating point matchers: double", "[matchers][floating-point]") {
+ SECTION("Relative") {
+ REQUIRE_THAT(10., WithinRel(11.1, 0.1));
+ REQUIRE_THAT(10., !WithinRel(11.2, 0.1));
+ REQUIRE_THAT(1., !WithinRel(0., 0.99));
+ REQUIRE_THAT(-0., WithinRel(0.));
+ SECTION("Some subnormal values") {
+ auto v1 = std::numeric_limits<double>::min();
+ auto v2 = v1;
+ for (int i = 0; i < 5; ++i) {
+ v2 = std::nextafter(v1, 0);
+ }
+ REQUIRE_THAT(v1, WithinRel(v2));
+ }
+ }
SECTION("Margin") {
REQUIRE_THAT(1., WithinAbs(1., 0));
REQUIRE_THAT(0., WithinAbs(1., 1));
@@ -393,8 +433,6 @@ namespace { namespace MatchersTests {
REQUIRE_THAT(0., !WithinAbs(1., 0.99));
REQUIRE_THAT(0., !WithinAbs(1., 0.99));
- REQUIRE_THAT(NAN, !WithinAbs(NAN, 0));
-
REQUIRE_THAT(11., !WithinAbs(10., 0.5));
REQUIRE_THAT(10., !WithinAbs(11., 0.5));
REQUIRE_THAT(-10., WithinAbs(-10., 0.5));
@@ -404,29 +442,43 @@ namespace { namespace MatchersTests {
REQUIRE_THAT(1., 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(0., WithinULP(nextafter(0., 1.), 1));
+ REQUIRE_THAT(1., WithinULP(nextafter(1., 0.), 1));
+ REQUIRE_THAT(1., !WithinULP(nextafter(1., 2.), 0));
REQUIRE_THAT(1., WithinULP(1., 0));
REQUIRE_THAT(-0., WithinULP(0., 0));
-
- REQUIRE_THAT(NAN, !WithinULP(NAN, 123));
}
SECTION("Composed") {
REQUIRE_THAT(1., WithinAbs(1., 0.5) || WithinULP(2., 1));
REQUIRE_THAT(1., WithinAbs(2., 0.5) || WithinULP(1., 0));
-
- REQUIRE_THAT(NAN, !(WithinAbs(NAN, 100) || WithinULP(NAN, 123)));
+ REQUIRE_THAT(0.0001, WithinAbs(0., 0.001) || WithinRel(0., 0.1));
}
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);
+
+ REQUIRE_NOTHROW(WithinRel(1., 0.));
+ REQUIRE_THROWS_AS(WithinRel(1., -0.2), std::domain_error);
+ REQUIRE_THROWS_AS(WithinRel(1., 1.), std::domain_error);
}
}
+ TEST_CASE("Floating point matchers that are problematic in approvals", "[approvals][matchers][floating-point]") {
+ REQUIRE_THAT(NAN, !WithinAbs(NAN, 0));
+ REQUIRE_THAT(NAN, !(WithinAbs(NAN, 100) || WithinULP(NAN, 123)));
+ REQUIRE_THAT(NAN, !WithinULP(NAN, 123));
+ REQUIRE_THAT(INFINITY, WithinRel(INFINITY));
+ REQUIRE_THAT(-INFINITY, !WithinRel(INFINITY));
+ REQUIRE_THAT(1., !WithinRel(INFINITY));
+ REQUIRE_THAT(INFINITY, !WithinRel(1.));
+ REQUIRE_THAT(NAN, !WithinRel(NAN));
+ REQUIRE_THAT(1., !WithinRel(NAN));
+ REQUIRE_THAT(NAN, !WithinRel(1.));
+ }
+
TEST_CASE("Arbitrary predicate matcher", "[matchers][generic]") {
SECTION("Function pointer") {
REQUIRE_THAT(1, Predicate<int>(alwaysTrue, "always true"));
@@ -498,6 +550,25 @@ namespace { namespace MatchersTests {
}
}
+#if !defined(CATCH_CONFIG_DISABLE_EXCEPTIONS)
+ TEST_CASE("Exceptions matchers", "[matchers][exceptions][!throws]") {
+ REQUIRE_THROWS_MATCHES(throwsDerivedException(), DerivedException, Message("DerivedException::what"));
+ REQUIRE_THROWS_MATCHES(throwsDerivedException(), DerivedException, !Message("derivedexception::what"));
+ REQUIRE_THROWS_MATCHES(throwsSpecialException(2), SpecialException, !Message("DerivedException::what"));
+ REQUIRE_THROWS_MATCHES(throwsSpecialException(2), SpecialException, Message("SpecialException::what"));
+ }
+#endif
+
+ TEST_CASE("Composed matchers are distinct", "[matchers][composed]") {
+ auto m1 = Contains("string");
+ auto m2 = Contains("random");
+ auto composed1 = m1 || m2;
+ auto m3 = Contains("different");
+ auto composed2 = composed1 || m3;
+ REQUIRE_THAT(testStringForMatching2(), !composed1);
+ REQUIRE_THAT(testStringForMatching2(), composed2);
+ }
+
} } // namespace MatchersTests
#endif // CATCH_CONFIG_DISABLE_MATCHERS
diff --git a/projects/SelfTest/UsageTests/Message.tests.cpp b/projects/SelfTest/UsageTests/Message.tests.cpp
index ccb7ac2f..93347084 100644
--- a/projects/SelfTest/UsageTests/Message.tests.cpp
+++ b/projects/SelfTest/UsageTests/Message.tests.cpp
@@ -251,6 +251,13 @@ TEST_CASE("CAPTURE can deal with complex expressions involving commas", "[messag
SUCCEED();
}
+TEST_CASE("CAPTURE parses string and character constants", "[messages][capture]") {
+ CAPTURE(("comma, in string", "escaped, \", "), "single quote in string,',", "some escapes, \\,\\\\");
+ CAPTURE("some, ), unmatched, } prenheses {[<");
+ CAPTURE('"', '\'', ',', '}', ')', '(', '{');
+ SUCCEED();
+}
+
#ifdef __clang__
#pragma clang diagnostic pop
#endif
diff --git a/projects/SelfTest/UsageTests/Misc.tests.cpp b/projects/SelfTest/UsageTests/Misc.tests.cpp
index 4de6f1aa..808d1d0a 100644
--- a/projects/SelfTest/UsageTests/Misc.tests.cpp
+++ b/projects/SelfTest/UsageTests/Misc.tests.cpp
@@ -18,6 +18,7 @@
#include <cerrno>
#include <limits>
#include <sstream>
+#include <array>
namespace { namespace MiscTests {
@@ -57,15 +58,21 @@ struct AutoTestReg {
REGISTER_TEST_CASE( manuallyRegisteredTestFunction, "ManuallyRegistered" );
}
};
+
+CATCH_INTERNAL_START_WARNINGS_SUPPRESSION
CATCH_INTERNAL_SUPPRESS_GLOBALS_WARNINGS
static AutoTestReg autoTestReg;
-CATCH_INTERNAL_UNSUPPRESS_GLOBALS_WARNINGS
+CATCH_INTERNAL_STOP_WARNINGS_SUPPRESSION
template<typename T>
struct Foo {
size_t size() { return 0; }
};
+template<typename T, size_t S>
+struct Bar {
+ size_t size() { return S; }
+};
#endif
TEST_CASE( "random SECTION tests", "[.][sections][failing]" ) {
@@ -306,15 +313,91 @@ TEMPLATE_TEST_CASE( "TemplateTest: vectors can be sized and resized", "[vector][
}
}
+TEMPLATE_TEST_CASE_SIG("TemplateTestSig: vectors can be sized and resized", "[vector][template][nttp]", ((typename TestType, int V), TestType, V), (int,5), (float,4), (std::string,15), ((std::tuple<int, float>), 6)) {
+
+ std::vector<TestType> v(V);
+
+ REQUIRE(v.size() == V);
+ REQUIRE(v.capacity() >= V);
+
+ SECTION("resizing bigger changes size and capacity") {
+ v.resize(2 * V);
+
+ REQUIRE(v.size() == 2 * V);
+ REQUIRE(v.capacity() >= 2 * V);
+ }
+ SECTION("resizing smaller changes size but not capacity") {
+ v.resize(0);
+
+ REQUIRE(v.size() == 0);
+ REQUIRE(v.capacity() >= V);
+
+ SECTION("We can use the 'swap trick' to reset the capacity") {
+ std::vector<TestType> empty;
+ empty.swap(v);
+
+ REQUIRE(v.capacity() == 0);
+ }
+ }
+ SECTION("reserving bigger changes capacity but not size") {
+ v.reserve(2 * V);
+
+ REQUIRE(v.size() == V);
+ REQUIRE(v.capacity() >= 2 * V);
+ }
+ SECTION("reserving smaller does not change size or capacity") {
+ v.reserve(0);
+
+ REQUIRE(v.size() == V);
+ REQUIRE(v.capacity() >= V);
+ }
+}
+
TEMPLATE_PRODUCT_TEST_CASE("A Template product test case", "[template][product]", (std::vector, Foo), (int, float)) {
TestType x;
REQUIRE(x.size() == 0);
}
+TEMPLATE_PRODUCT_TEST_CASE_SIG("A Template product test case with array signature", "[template][product][nttp]", ((typename T, size_t S), T, S), (std::array, Bar), ((int, 9), (float, 42))) {
+ TestType x;
+ REQUIRE(x.size() > 0);
+}
+
TEMPLATE_PRODUCT_TEST_CASE("Product with differing arities", "[template][product]", std::tuple, (int, (int, double), (int, double, float))) {
REQUIRE(std::tuple_size<TestType>::value >= 1);
}
+using MyTypes = std::tuple<int, char, float>;
+TEMPLATE_LIST_TEST_CASE("Template test case with test types specified inside std::tuple", "[template][list]", MyTypes)
+{
+ REQUIRE(sizeof(TestType) > 0);
+}
+
+struct NonDefaultConstructibleType {
+ NonDefaultConstructibleType() = delete;
+};
+
+using MyNonDefaultConstructibleTypes = std::tuple<NonDefaultConstructibleType, float>;
+TEMPLATE_LIST_TEST_CASE("Template test case with test types specified inside non-default-constructible std::tuple", "[template][list]", MyNonDefaultConstructibleTypes)
+{
+ REQUIRE(sizeof(TestType) > 0);
+}
+
+struct NonCopyableAndNonMovableType {
+ NonCopyableAndNonMovableType() = default;
+
+ NonCopyableAndNonMovableType(NonCopyableAndNonMovableType const &) = delete;
+ NonCopyableAndNonMovableType(NonCopyableAndNonMovableType &&) = delete;
+ auto operator=(NonCopyableAndNonMovableType const &) -> NonCopyableAndNonMovableType & = delete;
+ auto operator=(NonCopyableAndNonMovableType &&) -> NonCopyableAndNonMovableType & = delete;
+};
+
+using NonCopyableAndNonMovableTypes = std::tuple<NonCopyableAndNonMovableType, float>;
+TEMPLATE_LIST_TEST_CASE("Template test case with test types specified inside non-copyable and non-movable std::tuple", "[template][list]", NonCopyableAndNonMovableTypes)
+{
+ REQUIRE(sizeof(TestType) > 0);
+}
+
// https://github.com/philsquared/Catch/issues/166
TEST_CASE("A couple of nested sections followed by a failure", "[failing][.]") {
SECTION("Outer")
@@ -374,12 +457,6 @@ TEST_CASE( "long long" ) {
REQUIRE( l == std::numeric_limits<long long>::max() );
}
-//TEST_CASE( "Divide by Zero signal handler", "[.][sig]" ) {
-// int i = 0;
-// int x = 10/i; // This should cause the signal to fire
-// CHECK( x == 0 );
-//}
-
TEST_CASE( "This test 'should' fail but doesn't", "[.][failing][!shouldfail]" ) {
SUCCEED( "oops!" );
}
diff --git a/projects/SelfTest/UsageTests/ToStringByte.tests.cpp b/projects/SelfTest/UsageTests/ToStringByte.tests.cpp
new file mode 100644
index 00000000..0aad679f
--- /dev/null
+++ b/projects/SelfTest/UsageTests/ToStringByte.tests.cpp
@@ -0,0 +1,15 @@
+#include "catch.hpp"
+
+#if defined(CATCH_CONFIG_CPP17_BYTE)
+
+TEST_CASE( "std::byte -> toString", "[toString][byte][approvals]" ) {
+ using type = std::byte;
+ REQUIRE( "0" == ::Catch::Detail::stringify( type{ 0 } ) );
+}
+
+TEST_CASE( "std::vector<std::byte> -> toString", "[toString][byte][approvals]" ) {
+ using type = std::vector<std::byte>;
+ REQUIRE( "{ 0, 1, 2 }" == ::Catch::Detail::stringify( type{ std::byte{0}, std::byte{1}, std::byte{2} } ) );
+}
+
+#endif // CATCH_INTERNAL_CONFIG_CPP17_BYTE
diff --git a/projects/SelfTest/UsageTests/ToStringGeneral.tests.cpp b/projects/SelfTest/UsageTests/ToStringGeneral.tests.cpp
index 09ac3045..69d6320d 100644
--- a/projects/SelfTest/UsageTests/ToStringGeneral.tests.cpp
+++ b/projects/SelfTest/UsageTests/ToStringGeneral.tests.cpp
@@ -128,6 +128,40 @@ TEST_CASE("String views are stringified like other strings", "[toString][approva
#endif
+TEST_CASE("Precision of floating point stringification can be set", "[toString][floatingPoint]") {
+ SECTION("Floats") {
+ using sm = Catch::StringMaker<float>;
+ const auto oldPrecision = sm::precision;
+
+ const float testFloat = 1.12345678901234567899f;
+ auto str1 = sm::convert(testFloat);
+ sm::precision = 5;
+ // "1." prefix = 2 chars, f suffix is another char
+ CHECK(str1.size() == 3 + 5);
+
+ sm::precision = 10;
+ auto str2 = sm::convert(testFloat);
+ REQUIRE(str2.size() == 3 + 10);
+ sm::precision = oldPrecision;
+ }
+ SECTION("Double") {
+ using sm = Catch::StringMaker<double>;
+ const auto oldPrecision = sm::precision;
+
+ const double testDouble = 1.123456789012345678901234567899;
+ sm::precision = 5;
+ auto str1 = sm::convert(testDouble);
+ // "1." prefix = 2 chars
+ CHECK(str1.size() == 2 + 5);
+
+ sm::precision = 15;
+ auto str2 = sm::convert(testDouble);
+ REQUIRE(str2.size() == 2 + 15);
+
+ sm::precision = oldPrecision;
+ }
+}
+
namespace {
struct WhatException : std::exception {
diff --git a/projects/SelfTest/UsageTests/ToStringVariant.tests.cpp b/projects/SelfTest/UsageTests/ToStringVariant.tests.cpp
index a048e155..b97bb4bd 100644
--- a/projects/SelfTest/UsageTests/ToStringVariant.tests.cpp
+++ b/projects/SelfTest/UsageTests/ToStringVariant.tests.cpp
@@ -9,12 +9,12 @@
// We need 2 types with non-trivial copies/moves
struct MyType1 {
MyType1() = default;
- MyType1(MyType1 const&) { throw 1; }
+ [[noreturn]] MyType1(MyType1 const&) { throw 1; }
MyType1& operator=(MyType1 const&) { throw 3; }
};
struct MyType2 {
MyType2() = default;
- MyType2(MyType2 const&) { throw 2; }
+ [[noreturn]] MyType2(MyType2 const&) { throw 2; }
MyType2& operator=(MyType2 const&) { throw 4; }
};
diff --git a/projects/SelfTest/UsageTests/ToStringVector.tests.cpp b/projects/SelfTest/UsageTests/ToStringVector.tests.cpp
index 63b49e50..ea4d5c86 100644
--- a/projects/SelfTest/UsageTests/ToStringVector.tests.cpp
+++ b/projects/SelfTest/UsageTests/ToStringVector.tests.cpp
@@ -17,9 +17,9 @@ TEST_CASE( "vector<string> -> toString", "[toString][vector]" )
{
std::vector<std::string> vv;
REQUIRE( ::Catch::Detail::stringify(vv) == "{ }" );
- vv.push_back( "hello" );
+ vv.emplace_back( "hello" );
REQUIRE( ::Catch::Detail::stringify(vv) == "{ \"hello\" }" );
- vv.push_back( "world" );
+ vv.emplace_back( "world" );
REQUIRE( ::Catch::Detail::stringify(vv) == "{ \"hello\", \"world\" }" );
}
@@ -83,4 +83,4 @@ TEST_CASE( "array<int, N> -> toString", "[toString][containers][array]" ) {
REQUIRE( Catch::Detail::stringify( oneValue ) == "{ 42 }" );
std::array<int, 2> twoValues = {{ 42, 250 }};
REQUIRE( Catch::Detail::stringify( twoValues ) == "{ 42, 250 }" );
-} \ No newline at end of file
+}
diff --git a/projects/SelfTest/UsageTests/Tricky.tests.cpp b/projects/SelfTest/UsageTests/Tricky.tests.cpp
index 77bad2fc..8467e541 100644
--- a/projects/SelfTest/UsageTests/Tricky.tests.cpp
+++ b/projects/SelfTest/UsageTests/Tricky.tests.cpp
@@ -17,7 +17,7 @@
#include "catch.hpp"
-#include <stdio.h>
+#include <cstdio>
#include <sstream>
#include <iostream>
@@ -394,12 +394,6 @@ TEST_CASE("Commas in various macros are allowed") {
}
}
-TEST_CASE( "null deref", "[.][failing][!nonportable]" ) {
- CHECK( false );
- int *x = NULL;
- *x = 1;
-}
-
TEST_CASE( "non-copyable objects", "[.][failing]" ) {
#if CHECK_CONFIG_USE_RTTI
// Thanks to Agustin Bergé (@k-ballo on the cpplang Slack) for raising this
@@ -408,32 +402,6 @@ TEST_CASE( "non-copyable objects", "[.][failing]" ) {
#endif
}
-// #925
-using signal_t = void (*) (void*);
-
-struct TestClass {
- signal_t testMethod_uponComplete_arg = nullptr;
-};
-
-namespace utility {
- inline static void synchronizing_callback( void * ) { }
-}
-
-TEST_CASE("#925: comparing function pointer to function address failed to compile", "[!nonportable]" ) {
-
- TestClass test;
- REQUIRE(utility::synchronizing_callback != test.testMethod_uponComplete_arg);
-}
-
-TEST_CASE( "Bitfields can be captured (#1027)" ) {
- struct Y {
- uint32_t v : 1;
- };
- Y y{ 0 };
- REQUIRE( y.v == 0 );
- REQUIRE( 0 == y.v );
-}
-
TEST_CASE("#1514: stderr/stdout is not captured in tests aborted by an exception", "[output-capture][regression][.]") {
std::cout << "This would not be caught previously\n" << std::flush;
std::clog << "Nor would this\n" << std::flush;
diff --git a/projects/SelfTest/WarnAboutNoTests.cmake b/projects/SelfTest/WarnAboutNoTests.cmake
new file mode 100644
index 00000000..4637e3f3
--- /dev/null
+++ b/projects/SelfTest/WarnAboutNoTests.cmake
@@ -0,0 +1,19 @@
+# Workaround for a peculiarity where CTest disregards the return code from a
+# test command if a PASS_REGULAR_EXPRESSION is also set
+execute_process(
+ COMMAND ${CMAKE_ARGV3} -w NoTests "___nonexistent_test___"
+ RESULT_VARIABLE ret
+ OUTPUT_VARIABLE out
+)
+
+message("${out}")
+
+if(NOT ${ret} MATCHES "^[0-9]+$")
+ message(FATAL_ERROR "${ret}")
+endif()
+
+if(${ret} EQUAL 0)
+ message(FATAL_ERROR "Expected nonzero return code")
+elseif(${out} MATCHES "Helper failed with")
+ message(FATAL_ERROR "Helper failed")
+endif()
diff --git a/projects/Where did the projects go.txt b/projects/Where did the projects go.txt
deleted file mode 100644
index c7b011d5..00000000
--- a/projects/Where did the projects go.txt
+++ /dev/null
@@ -1,13 +0,0 @@
-The canonical project format is now CMake.
-To generate an XCode or Visual Studio project you'll need CMake, which you can download from https://cmake.org if necessary.
-
-To generate the project files open a terminal/ console within the projects directory (where this file is located), create a directory called "Generated" (using mkdir or md), cd into it, then type:
-
-CMake -G <project format> ../..
-
-Where <project format> is XCode for XCode projects, or "Visual Studio 14" for Visual Studio 2015 (replace 14 with the major version number for any other supported Visual Studio version - or execute CMake -help for the full list)
-
-Remember to re-run CMake any time you pull from GitHub.
-Note that the projects/Generated folder is excluded in .gitignore. So it is recommended to use this.
-
-CMake can also generate make files or projects for other build systems. Run CMake -help for the full set of options.
diff --git a/scripts/approvalTests.py b/scripts/approvalTests.py
index bb01e6d5..838a1a78 100755
--- a/scripts/approvalTests.py
+++ b/scripts/approvalTests.py
@@ -1,4 +1,4 @@
-#!/usr/bin/env python
+#!/usr/bin/env python3
from __future__ import print_function
@@ -29,6 +29,7 @@ filelocParser = re.compile(r'''
lineNumberParser = re.compile(r' line="[0-9]*"')
hexParser = re.compile(r'\b(0[xX][0-9a-fA-F]+)\b')
durationsParser = re.compile(r' time="[0-9]*\.[0-9]*"')
+sonarqubeDurationParser = re.compile(r' duration="[0-9]+"')
timestampsParser = re.compile(r'\d{4}-\d{2}-\d{2}T\d{2}\:\d{2}\:\d{2}Z')
versionParser = re.compile(r'Catch v[0-9]+\.[0-9]+\.[0-9]+(-develop\.[0-9]+)?')
nullParser = re.compile(r'\b(__null|nullptr)\b')
@@ -138,6 +139,7 @@ def filterLine(line, isCompact):
# strip durations and timestamps
line = durationsParser.sub(' time="{duration}"', line)
+ line = sonarqubeDurationParser.sub(' duration="{duration}"', line)
line = timestampsParser.sub('{iso8601-timestamp}', line)
line = specialCaseParser.sub('file:\g<1>', line)
line = errnoParser.sub('errno', line)
@@ -204,6 +206,8 @@ approve("junit.sw", ["~[!nonportable]~[!benchmark]~[approvals]", "-s", "-w", "No
approve("xml.sw", ["~[!nonportable]~[!benchmark]~[approvals]", "-s", "-w", "NoAssertions", "-r", "xml", "--order", "lex", "--rng-seed", "1"])
# compact reporter, include passes, warn about No Assertions
approve('compact.sw', ['~[!nonportable]~[!benchmark]~[approvals]', '-s', '-w', 'NoAssertions', '-r', 'compact', '--order', 'lex', "--rng-seed", "1"])
+# sonarqube reporter, include passes, warn about No Assertions
+approve("sonarqube.sw", ["~[!nonportable]~[!benchmark]~[approvals]", "-s", "-w", "NoAssertions", "-r", "sonarqube", "--order", "lex", "--rng-seed", "1"])
if overallResult != 0:
print("If these differences are expected, run approve.py to approve new baselines.")
diff --git a/scripts/approve.py b/scripts/approve.py
index f03417dc..1e0d5a7a 100755
--- a/scripts/approve.py
+++ b/scripts/approve.py
@@ -1,4 +1,4 @@
-#!/usr/bin/env python
+#!/usr/bin/env python3
from __future__ import print_function
diff --git a/scripts/benchmarkCompile.py b/scripts/benchmarkCompile.py
index 586c26ac..34113b9e 100755
--- a/scripts/benchmarkCompile.py
+++ b/scripts/benchmarkCompile.py
@@ -1,4 +1,4 @@
-#!/usr/bin/env python
+#!/usr/bin/env python3
from __future__ import print_function
diff --git a/scripts/developBuild.py b/scripts/developBuild.py
index a8115fe2..9252c7d6 100755
--- a/scripts/developBuild.py
+++ b/scripts/developBuild.py
@@ -1,4 +1,4 @@
-#!/usr/bin/env python
+#!/usr/bin/env python3
from __future__ import print_function
import releaseCommon
diff --git a/scripts/embedClara.py b/scripts/embedClara.py
index 7ceb3e32..d8c1520a 100755
--- a/scripts/embedClara.py
+++ b/scripts/embedClara.py
@@ -1,4 +1,4 @@
-#!/usr/bin/env python
+#!/usr/bin/env python3
# Execute this script any time you import a new copy of Clara into the third_party area
import os
diff --git a/scripts/extractFeaturesFromReleaseNotes.py b/scripts/extractFeaturesFromReleaseNotes.py
new file mode 100644
index 00000000..11f4955c
--- /dev/null
+++ b/scripts/extractFeaturesFromReleaseNotes.py
@@ -0,0 +1,94 @@
+#!/usr/bin/env python3
+
+#
+# extractFeaturesFromReleaseNotes.py
+#
+# Read the release notes - docs/release-notes.md - and generate text
+# for pasting in to individual documentation pages, to indicate which
+# versions recent features were released in.
+#
+# Using the output of the file is easier than manually constructing
+# the text to paste in to documentation pages.
+#
+# One way to use this:
+# - run this script, saving the output to some temporary file
+# - diff this output with the actual release notes page
+# - the differences are Markdown text that can be pasted in to the
+# appropriate documentation pages in the docs/ directory.
+# - each release also has a github link to show which documentation files
+# were changed in it.
+# This can be helpful to see which documentation pages
+# to add the 'Introduced in Catch ...' snippets to the relevant pages.
+#
+
+from __future__ import print_function
+
+import re
+
+
+def create_introduced_in_text(version, bug_number = None):
+ """Generate text to paste in to documentation file"""
+ if bug_number:
+ return '> [Introduced](https://github.com/catchorg/Catch2/issues/%s) in Catch %s.' % (bug_number, version)
+ else:
+ # Use this text for changes that don't have issue numbers
+ return '> Introduced in Catch %s.' % version
+
+
+def link_to_changes_in_release(release, releases):
+ """
+ Markdown text for a hyperlink showing all edits in a release, or empty string
+
+ :param release: A release version, as a string
+ :param releases: A container of releases, in descending order - newest to oldest
+ :return: Markdown text for a hyperlink showing the differences between the give release and the prior one,
+ or empty string, if the previous release is not known
+ """
+
+ if release == releases[-1]:
+ # This is the earliest release we know about
+ return ''
+ index = releases.index(release)
+ previous_release = releases[index + 1]
+ return '\n[Changes in %s](https://github.com/catchorg/Catch2/compare/v%s...v%s)' % (release, previous_release, release)
+
+
+def write_recent_release_notes_with_introduced_text():
+ current_version = None
+ release_toc_regex = r'\[(\d.\d.\d)\]\(#\d+\)<br>'
+ issue_number_regex = r'#[0-9]+'
+ releases = []
+ with open('../docs/release-notes.md') as release_notes:
+ for line in release_notes:
+ line = line[:-1]
+ print(line)
+
+ # Extract version number from table of contents
+ match = re.search(release_toc_regex, line)
+ if match:
+ release_name = match.group(1)
+ releases.append(release_name)
+
+ if line.startswith('## '):
+ # It's a section with version number
+ current_version = line.replace('## ', '')
+
+ # We decided not to add released-date info for older versions
+ if current_version == 'Older versions':
+ break
+
+ print(create_introduced_in_text(current_version))
+ print(link_to_changes_in_release(current_version, releases))
+
+ # Not yet found a version number, so to avoid picking up hyperlinks to
+ # version numbers in the index, keep going
+ if not current_version:
+ continue
+
+ for bug_link in re.findall(issue_number_regex, line):
+ bug_number = bug_link.replace('#', '')
+ print(create_introduced_in_text(current_version, bug_number))
+
+
+if __name__ == '__main__':
+ write_recent_release_notes_with_introduced_text()
diff --git a/scripts/fixWhitespace.py b/scripts/fixWhitespace.py
index bfa4aa08..4591c1c4 100755
--- a/scripts/fixWhitespace.py
+++ b/scripts/fixWhitespace.py
@@ -1,4 +1,4 @@
-#!/usr/bin/env python
+#!/usr/bin/env python3
from __future__ import print_function
import os
diff --git a/scripts/generateSingleHeader.py b/scripts/generateSingleHeader.py
index 31033d68..ffd11780 100755
--- a/scripts/generateSingleHeader.py
+++ b/scripts/generateSingleHeader.py
@@ -1,4 +1,4 @@
-#!/usr/bin/env python
+#!/usr/bin/env python3
from __future__ import print_function
@@ -23,6 +23,7 @@ def generate(v):
blankParser = re.compile( r'^\s*$')
seenHeaders = set([])
+ possibleHeaders = set([])
rootPath = os.path.join( catchPath, 'include/' )
outputPath = os.path.join( catchPath, 'single_include/catch2/catch.hpp' )
@@ -52,8 +53,20 @@ def generate(v):
if globals['includeImpl'] or globals['implIfDefs'] == -1:
out.write( line )
+ def getDirsToSearch( ):
+ return [os.path.join( rootPath, s) for s in ['', 'internal', 'reporters', 'internal/benchmark', 'internal/benchmark/detail']]
+
+ def collectPossibleHeaders():
+ dirs = getDirsToSearch()
+ for dir in dirs:
+ hpps = glob(os.path.join(dir, '*.hpp'))
+ hs = glob(os.path.join(dir, '*.h'))
+ possibleHeaders.update( hpp.rpartition( os.sep )[2] for hpp in hpps )
+ possibleHeaders.update( h.rpartition( os.sep )[2] for h in hs )
+
+
def insertCpps():
- dirs = [os.path.join( rootPath, s) for s in ['', 'internal', 'reporters']]
+ dirs = getDirsToSearch()
cppFiles = []
for dir in dirs:
cppFiles += glob(os.path.join(dir, '*.cpp'))
@@ -103,6 +116,13 @@ def generate(v):
write( line.rstrip() + "\n" )
write( u'// end {}\n'.format(filename) )
+ def warnUnparsedHeaders():
+ unparsedHeaders = possibleHeaders.difference( seenHeaders )
+ # These headers aren't packaged into the unified header, exclude them from any warning
+ whitelist = ['catch.hpp', 'catch_reporter_teamcity.hpp', 'catch_with_main.hpp', 'catch_reporter_automake.hpp', 'catch_reporter_tap.hpp', 'catch_reporter_sonarqube.hpp']
+ unparsedHeaders = unparsedHeaders.difference( whitelist )
+ if unparsedHeaders:
+ print( "WARNING: unparsed headers detected\n{0}\n".format( unparsedHeaders ) )
write( u"/*\n" )
write( u" * Catch v{0}\n".format( v.getVersionString() ) )
@@ -117,11 +137,13 @@ def generate(v):
write( u"#ifndef TWOBLUECUBES_SINGLE_INCLUDE_CATCH_HPP_INCLUDED\n" )
write( u"#define TWOBLUECUBES_SINGLE_INCLUDE_CATCH_HPP_INCLUDED\n" )
+ collectPossibleHeaders()
parseFile( rootPath, 'catch.hpp' )
+ warnUnparsedHeaders()
write( u"#endif // TWOBLUECUBES_SINGLE_INCLUDE_CATCH_HPP_INCLUDED\n\n" )
out.close()
- print ("Generated single include for Catch v{0}\n".format( v.getVersionString() ) )
+ print( "Generated single include for Catch v{0}\n".format( v.getVersionString() ) )
if __name__ == '__main__':
diff --git a/scripts/majorRelease.py b/scripts/majorRelease.py
index 8da34066..e9e285a8 100755
--- a/scripts/majorRelease.py
+++ b/scripts/majorRelease.py
@@ -1,4 +1,4 @@
-#!/usr/bin/env python
+#!/usr/bin/env python3
from __future__ import print_function
import releaseCommon
diff --git a/scripts/minorRelease.py b/scripts/minorRelease.py
index 6e71cd80..2b57c2ea 100755
--- a/scripts/minorRelease.py
+++ b/scripts/minorRelease.py
@@ -1,4 +1,4 @@
-#!/usr/bin/env python
+#!/usr/bin/env python3
from __future__ import print_function
import releaseCommon
diff --git a/scripts/patchRelease.py b/scripts/patchRelease.py
index 14176420..d20db714 100755
--- a/scripts/patchRelease.py
+++ b/scripts/patchRelease.py
@@ -1,4 +1,4 @@
-#!/usr/bin/env python
+#!/usr/bin/env python3
from __future__ import print_function
import releaseCommon
diff --git a/scripts/releaseCommon.py b/scripts/releaseCommon.py
index 9cdc4f6c..283337d4 100644
--- a/scripts/releaseCommon.py
+++ b/scripts/releaseCommon.py
@@ -4,6 +4,8 @@ import os
import sys
import re
import string
+import glob
+import fnmatch
from scriptCommon import catchPath
@@ -98,29 +100,47 @@ def updateReadmeFile(version):
def updateCmakeFile(version):
- with open(cmakePath, 'r') as file:
+ with open(cmakePath, 'rb') as file:
lines = file.readlines()
- with open(cmakePath, 'w') as file:
+ replacementRegex = re.compile(b'project\\(Catch2 LANGUAGES CXX VERSION \\d+\\.\\d+\\.\\d+\\)')
+ replacement = 'project(Catch2 LANGUAGES CXX VERSION {0})'.format(version.getVersionString()).encode('ascii')
+ with open(cmakePath, 'wb') as file:
for line in lines:
- if 'project(Catch2 LANGUAGES CXX VERSION ' in line:
- file.write('project(Catch2 LANGUAGES CXX VERSION {0})\n'.format(version.getVersionString()))
- else:
- file.write(line)
+ file.write(replacementRegex.sub(replacement, line))
def updateVersionDefine(version):
- with open(definePath, 'r') as file:
+ # First member of the tuple is the compiled regex object, the second is replacement if it matches
+ replacementRegexes = [(re.compile(b'#define CATCH_VERSION_MAJOR \\d+'),'#define CATCH_VERSION_MAJOR {}'.format(version.majorVersion).encode('ascii')),
+ (re.compile(b'#define CATCH_VERSION_MINOR \\d+'),'#define CATCH_VERSION_MINOR {}'.format(version.minorVersion).encode('ascii')),
+ (re.compile(b'#define CATCH_VERSION_PATCH \\d+'),'#define CATCH_VERSION_PATCH {}'.format(version.patchNumber).encode('ascii')),
+ ]
+ with open(definePath, 'rb') as file:
lines = file.readlines()
- with open(definePath, 'w') as file:
+ with open(definePath, 'wb') 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)
+ for replacement in replacementRegexes:
+ line = replacement[0].sub(replacement[1], line)
+ file.write(line)
+
+
+def updateVersionPlaceholder(filename, version):
+ with open(filename, 'rb') as file:
+ lines = file.readlines()
+ placeholderRegex = re.compile(b' in Catch X.Y.Z')
+ replacement = ' in Catch {}.{}.{}'.format(version.majorVersion, version.minorVersion, version.patchNumber).encode('ascii')
+ with open(filename, 'wb') as file:
+ for line in lines:
+ file.write(placeholderRegex.sub(replacement, line))
+
+
+def updateDocumentationVersionPlaceholders(version):
+ print('Updating version placeholder in documentation')
+ docsPath = os.path.join(catchPath, 'docs/')
+ for basePath, _, files in os.walk(docsPath):
+ for file in files:
+ if fnmatch.fnmatch(file, "*.md") and "contributing.md" != file:
+ updateVersionPlaceholder(os.path.join(basePath, file), version)
def performUpdates(version):
@@ -136,10 +156,11 @@ def performUpdates(version):
# 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'):
+ for rep in ('automake', 'tap', 'teamcity', 'sonarqube'):
sourceFile = os.path.join(catchPath, 'include/reporters/catch_reporter_{}.hpp'.format(rep))
destFile = os.path.join(catchPath, 'single_include', 'catch2', 'catch_reporter_{}.hpp'.format(rep))
shutil.copyfile(sourceFile, destFile)
updateReadmeFile(version)
updateCmakeFile(version)
+ updateDocumentationVersionPlaceholders(version)
diff --git a/scripts/releaseNotes.py b/scripts/releaseNotes.py
index 5e770bba..7f580e98 100755
--- a/scripts/releaseNotes.py
+++ b/scripts/releaseNotes.py
@@ -1,4 +1,4 @@
-#!/usr/bin/env python
+#!/usr/bin/env python3
from __future__ import print_function
diff --git a/scripts/updateDocumentToC.py b/scripts/updateDocumentToC.py
index 325c8a3c..41b48752 100644
--- a/scripts/updateDocumentToC.py
+++ b/scripts/updateDocumentToC.py
@@ -1,4 +1,4 @@
-#!/usr/bin/env python
+#!/usr/bin/env python3
#
# updateDocumentToC.py
diff --git a/scripts/updateWandbox.py b/scripts/updateWandbox.py
index 564f9489..3668da52 100644
--- a/scripts/updateWandbox.py
+++ b/scripts/updateWandbox.py
@@ -1,16 +1,22 @@
-#!/usr/bin/env python
+#!/usr/bin/env python3
import json
import os
-import urllib2
+import urllib.request
+import urllib.parse
+
from scriptCommon import catchPath
def upload(options):
- request = urllib2.Request('http://melpon.org/wandbox/api/compile.json')
- request.add_header('Content-Type', 'application/json')
- response = urllib2.urlopen(request, json.dumps(options))
- return json.loads(response.read())
+# request_blah = urllib.request.Request('https://
+
+ request = urllib.request.Request('https://melpon.org/wandbox/api/compile.json', method='POST')
+ json_bytes = json.dumps(options).encode('utf-8')
+ request.add_header('Content-Type', 'application/json; charset=utf-8')
+ request.add_header('Content-Length', len(json_bytes))
+ response = urllib.request.urlopen(request, json_bytes)
+ return json.loads(response.read().decode('utf-8'))
main_file = '''
#define CATCH_CONFIG_MAIN // This tells Catch to provide a main() - only do this in one cpp file
@@ -41,7 +47,7 @@ def uploadFiles():
'save': True
})
- if 'status' in response and 'compiler_error' not in response:
+ if 'url' in response and 'compiler_error' not in response:
return True, response['url']
else:
return False, response
diff --git a/single_include/catch2/catch.hpp b/single_include/catch2/catch.hpp
index df14c357..f57d7f43 100644
--- a/single_include/catch2/catch.hpp
+++ b/single_include/catch2/catch.hpp
@@ -1,9 +1,9 @@
/*
- * Catch v2.7.2
- * Generated: 2019-04-22 23:13:14.687465
+ * Catch v2.11.2
+ * Generated: 2020-03-19 12:35:04.038733
* ----------------------------------------------------------
* This file has been merged from multiple headers. Please don't edit it directly
- * Copyright (c) 2019 Two Blue Cubes Ltd. All rights reserved.
+ * Copyright (c) 2020 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)
@@ -14,7 +14,7 @@
#define CATCH_VERSION_MAJOR 2
-#define CATCH_VERSION_MINOR 7
+#define CATCH_VERSION_MINOR 11
#define CATCH_VERSION_PATCH 2
#ifdef __clang__
@@ -136,26 +136,38 @@ namespace Catch {
# define CATCH_INTERNAL_CONFIG_CPP17_UNCAUGHT_EXCEPTIONS
#endif
-#ifdef __clang__
+// We have to avoid both ICC and Clang, because they try to mask themselves
+// as gcc, and we want only GCC in this block
+#if defined(__GNUC__) && !defined(__clang__) && !defined(__ICC)
+# define CATCH_INTERNAL_START_WARNINGS_SUPPRESSION _Pragma( "GCC diagnostic push" )
+# define CATCH_INTERNAL_STOP_WARNINGS_SUPPRESSION _Pragma( "GCC diagnostic pop" )
+
+# define CATCH_INTERNAL_IGNORE_BUT_WARN(...) (void)__builtin_constant_p(__VA_ARGS__)
+
+#endif
+
+#if defined(__clang__)
+
+# define CATCH_INTERNAL_START_WARNINGS_SUPPRESSION _Pragma( "clang diagnostic push" )
+# define CATCH_INTERNAL_STOP_WARNINGS_SUPPRESSION _Pragma( "clang diagnostic pop" )
+
+# define CATCH_INTERNAL_IGNORE_BUT_WARN(...) (void)__builtin_constant_p(__VA_ARGS__)
+
+# define CATCH_INTERNAL_SUPPRESS_GLOBALS_WARNINGS \
+ _Pragma( "clang diagnostic ignored \"-Wexit-time-destructors\"" ) \
+ _Pragma( "clang diagnostic ignored \"-Wglobal-constructors\"")
+
+# define CATCH_INTERNAL_SUPPRESS_PARENTHESES_WARNINGS \
+ _Pragma( "clang diagnostic ignored \"-Wparentheses\"" )
+
+# define CATCH_INTERNAL_SUPPRESS_UNUSED_WARNINGS \
+ _Pragma( "clang diagnostic ignored \"-Wunused-variable\"" )
-# define CATCH_INTERNAL_SUPPRESS_GLOBALS_WARNINGS \
- _Pragma( "clang diagnostic push" ) \
- _Pragma( "clang diagnostic ignored \"-Wexit-time-destructors\"" ) \
- _Pragma( "clang diagnostic ignored \"-Wglobal-constructors\"")
-# define CATCH_INTERNAL_UNSUPPRESS_GLOBALS_WARNINGS \
- _Pragma( "clang diagnostic pop" )
-
-# define CATCH_INTERNAL_SUPPRESS_PARENTHESES_WARNINGS \
- _Pragma( "clang diagnostic push" ) \
- _Pragma( "clang diagnostic ignored \"-Wparentheses\"" )
-# define CATCH_INTERNAL_UNSUPPRESS_PARENTHESES_WARNINGS \
- _Pragma( "clang diagnostic pop" )
-
-# define CATCH_INTERNAL_SUPPRESS_UNUSED_WARNINGS \
- _Pragma( "clang diagnostic push" ) \
- _Pragma( "clang diagnostic ignored \"-Wunused-variable\"" )
-# define CATCH_INTERNAL_UNSUPPRESS_UNUSED_WARNINGS \
- _Pragma( "clang diagnostic pop" )
+# define CATCH_INTERNAL_SUPPRESS_ZERO_VARIADIC_WARNINGS \
+ _Pragma( "clang diagnostic ignored \"-Wgnu-zero-variadic-macro-arguments\"" )
+
+# define CATCH_INTERNAL_SUPPRESS_UNUSED_TEMPLATE_WARNINGS \
+ _Pragma( "clang diagnostic ignored \"-Wunused-template\"" )
#endif // __clang__
@@ -180,6 +192,7 @@ namespace Catch {
// Android somehow still does not support std::to_string
#if defined(__ANDROID__)
# define CATCH_INTERNAL_CONFIG_NO_CPP11_TO_STRING
+# define CATCH_INTERNAL_CONFIG_ANDROID_LOGWRITE
#endif
////////////////////////////////////////////////////////////////////////////////
@@ -204,16 +217,21 @@ namespace Catch {
// some versions of cygwin (most) do not support std::to_string. Use the libstd check.
// https://gcc.gnu.org/onlinedocs/gcc-4.8.2/libstdc++/api/a01053_source.html line 2812-2813
# if !((__cplusplus >= 201103L) && defined(_GLIBCXX_USE_C99) \
- && !defined(_GLIBCXX_HAVE_BROKEN_VSWPRINTF))
+ && !defined(_GLIBCXX_HAVE_BROKEN_VSWPRINTF))
-# define CATCH_INTERNAL_CONFIG_NO_CPP11_TO_STRING
+# define CATCH_INTERNAL_CONFIG_NO_CPP11_TO_STRING
# endif
#endif // __CYGWIN__
////////////////////////////////////////////////////////////////////////////////
// Visual C++
-#ifdef _MSC_VER
+#if defined(_MSC_VER)
+
+# define CATCH_INTERNAL_START_WARNINGS_SUPPRESSION __pragma( warning(push) )
+# define CATCH_INTERNAL_STOP_WARNINGS_SUPPRESSION __pragma( warning(pop) )
+
+# define CATCH_INTERNAL_IGNORE_BUT_WARN(...) (void)sizeof(__VA_ARGS__)
# if _MSC_VER >= 1900 // Visual Studio 2015 or newer
# define CATCH_INTERNAL_CONFIG_CPP17_UNCAUGHT_EXCEPTIONS
@@ -230,10 +248,17 @@ namespace Catch {
// MSVC traditional preprocessor needs some workaround for __VA_ARGS__
// _MSVC_TRADITIONAL == 0 means new conformant preprocessor
// _MSVC_TRADITIONAL == 1 means old traditional non-conformant preprocessor
-# if !defined(_MSVC_TRADITIONAL) || (defined(_MSVC_TRADITIONAL) && _MSVC_TRADITIONAL)
-# define CATCH_INTERNAL_CONFIG_TRADITIONAL_MSVC_PREPROCESSOR
-# endif
+# if !defined(__clang__) // Handle Clang masquerading for msvc
+# if !defined(_MSVC_TRADITIONAL) || (defined(_MSVC_TRADITIONAL) && _MSVC_TRADITIONAL)
+# define CATCH_INTERNAL_CONFIG_TRADITIONAL_MSVC_PREPROCESSOR
+# endif // MSVC_TRADITIONAL
+# endif // __clang__
+
+#endif // _MSC_VER
+#if defined(_REENTRANT) || defined(_MSC_VER)
+// Enable async processing, as -pthread is specified or no additional linking is required
+# define CATCH_INTERNAL_CONFIG_USE_ASYNC
#endif // _MSC_VER
////////////////////////////////////////////////////////////////////////////////
@@ -266,40 +291,53 @@ namespace Catch {
#endif
////////////////////////////////////////////////////////////////////////////////
-// Check if string_view is available and usable
-// The check is split apart to work around v140 (VS2015) preprocessor issue...
-#if defined(__has_include)
-#if __has_include(<string_view>) && defined(CATCH_CPP17_OR_GREATER)
-# define CATCH_INTERNAL_CONFIG_CPP17_STRING_VIEW
-#endif
+
+// RTX is a special version of Windows that is real time.
+// This means that it is detected as Windows, but does not provide
+// the same set of capabilities as real Windows does.
+#if defined(UNDER_RTSS) || defined(RTX64_BUILD)
+ #define CATCH_INTERNAL_CONFIG_NO_WINDOWS_SEH
+ #define CATCH_INTERNAL_CONFIG_NO_ASYNC
+ #define CATCH_CONFIG_COLOUR_NONE
#endif
-////////////////////////////////////////////////////////////////////////////////
-// Check if optional is available and usable
-#if defined(__has_include)
-# if __has_include(<optional>) && defined(CATCH_CPP17_OR_GREATER)
-# define CATCH_INTERNAL_CONFIG_CPP17_OPTIONAL
-# endif // __has_include(<optional>) && defined(CATCH_CPP17_OR_GREATER)
-#endif // __has_include
+#if !defined(_GLIBCXX_USE_C99_MATH_TR1)
+#define CATCH_INTERNAL_CONFIG_GLOBAL_NEXTAFTER
+#endif
-////////////////////////////////////////////////////////////////////////////////
-// Check if variant is available and usable
+// Various stdlib support checks that require __has_include
#if defined(__has_include)
-# if __has_include(<variant>) && defined(CATCH_CPP17_OR_GREATER)
-# if defined(__clang__) && (__clang_major__ < 8)
- // work around clang bug with libstdc++ https://bugs.llvm.org/show_bug.cgi?id=31852
- // fix should be in clang 8, workaround in libstdc++ 8.2
-# include <ciso646>
-# if defined(__GLIBCXX__) && defined(_GLIBCXX_RELEASE) && (_GLIBCXX_RELEASE < 9)
-# define CATCH_CONFIG_NO_CPP17_VARIANT
-# else
-# define CATCH_INTERNAL_CONFIG_CPP17_VARIANT
-# endif // defined(__GLIBCXX__) && defined(_GLIBCXX_RELEASE) && (_GLIBCXX_RELEASE < 9)
-# else
-# define CATCH_INTERNAL_CONFIG_CPP17_VARIANT
-# endif // defined(__clang__) && (__clang_major__ < 8)
-# endif // __has_include(<variant>) && defined(CATCH_CPP17_OR_GREATER)
-#endif // __has_include
+ // Check if string_view is available and usable
+ #if __has_include(<string_view>) && defined(CATCH_CPP17_OR_GREATER)
+ # define CATCH_INTERNAL_CONFIG_CPP17_STRING_VIEW
+ #endif
+
+ // Check if optional is available and usable
+ # if __has_include(<optional>) && defined(CATCH_CPP17_OR_GREATER)
+ # define CATCH_INTERNAL_CONFIG_CPP17_OPTIONAL
+ # endif // __has_include(<optional>) && defined(CATCH_CPP17_OR_GREATER)
+
+ // Check if byte is available and usable
+ # if __has_include(<cstddef>) && defined(CATCH_CPP17_OR_GREATER)
+ # define CATCH_INTERNAL_CONFIG_CPP17_BYTE
+ # endif // __has_include(<cstddef>) && defined(CATCH_CPP17_OR_GREATER)
+
+ // Check if variant is available and usable
+ # if __has_include(<variant>) && defined(CATCH_CPP17_OR_GREATER)
+ # if defined(__clang__) && (__clang_major__ < 8)
+ // work around clang bug with libstdc++ https://bugs.llvm.org/show_bug.cgi?id=31852
+ // fix should be in clang 8, workaround in libstdc++ 8.2
+ # include <ciso646>
+ # if defined(__GLIBCXX__) && defined(_GLIBCXX_RELEASE) && (_GLIBCXX_RELEASE < 9)
+ # define CATCH_CONFIG_NO_CPP17_VARIANT
+ # else
+ # define CATCH_INTERNAL_CONFIG_CPP17_VARIANT
+ # endif // defined(__GLIBCXX__) && defined(_GLIBCXX_RELEASE) && (_GLIBCXX_RELEASE < 9)
+ # else
+ # define CATCH_INTERNAL_CONFIG_CPP17_VARIANT
+ # endif // defined(__clang__) && (__clang_major__ < 8)
+ # endif // __has_include(<variant>) && defined(CATCH_CPP17_OR_GREATER)
+#endif // defined(__has_include)
#if defined(CATCH_INTERNAL_CONFIG_COUNTER) && !defined(CATCH_CONFIG_NO_COUNTER) && !defined(CATCH_CONFIG_COUNTER)
# define CATCH_CONFIG_COUNTER
@@ -336,6 +374,10 @@ namespace Catch {
# define CATCH_CONFIG_CPP17_VARIANT
#endif
+#if defined(CATCH_INTERNAL_CONFIG_CPP17_BYTE) && !defined(CATCH_CONFIG_NO_CPP17_BYTE) && !defined(CATCH_CONFIG_CPP17_BYTE)
+# define CATCH_CONFIG_CPP17_BYTE
+#endif
+
#if defined(CATCH_CONFIG_EXPERIMENTAL_REDIRECT)
# define CATCH_INTERNAL_CONFIG_NEW_CAPTURE
#endif
@@ -352,17 +394,53 @@ namespace Catch {
# define CATCH_CONFIG_POLYFILL_ISNAN
#endif
+#if defined(CATCH_INTERNAL_CONFIG_USE_ASYNC) && !defined(CATCH_INTERNAL_CONFIG_NO_ASYNC) && !defined(CATCH_CONFIG_NO_USE_ASYNC) && !defined(CATCH_CONFIG_USE_ASYNC)
+# define CATCH_CONFIG_USE_ASYNC
+#endif
+
+#if defined(CATCH_INTERNAL_CONFIG_ANDROID_LOGWRITE) && !defined(CATCH_CONFIG_NO_ANDROID_LOGWRITE) && !defined(CATCH_CONFIG_ANDROID_LOGWRITE)
+# define CATCH_CONFIG_ANDROID_LOGWRITE
+#endif
+
+#if defined(CATCH_INTERNAL_CONFIG_GLOBAL_NEXTAFTER) && !defined(CATCH_CONFIG_NO_GLOBAL_NEXTAFTER) && !defined(CATCH_CONFIG_GLOBAL_NEXTAFTER)
+# define CATCH_CONFIG_GLOBAL_NEXTAFTER
+#endif
+
+// Even if we do not think the compiler has that warning, we still have
+// to provide a macro that can be used by the code.
+#if !defined(CATCH_INTERNAL_START_WARNINGS_SUPPRESSION)
+# define CATCH_INTERNAL_START_WARNINGS_SUPPRESSION
+#endif
+#if !defined(CATCH_INTERNAL_STOP_WARNINGS_SUPPRESSION)
+# define CATCH_INTERNAL_STOP_WARNINGS_SUPPRESSION
+#endif
#if !defined(CATCH_INTERNAL_SUPPRESS_PARENTHESES_WARNINGS)
# define CATCH_INTERNAL_SUPPRESS_PARENTHESES_WARNINGS
-# define CATCH_INTERNAL_UNSUPPRESS_PARENTHESES_WARNINGS
#endif
#if !defined(CATCH_INTERNAL_SUPPRESS_GLOBALS_WARNINGS)
# define CATCH_INTERNAL_SUPPRESS_GLOBALS_WARNINGS
-# define CATCH_INTERNAL_UNSUPPRESS_GLOBALS_WARNINGS
#endif
#if !defined(CATCH_INTERNAL_SUPPRESS_UNUSED_WARNINGS)
# define CATCH_INTERNAL_SUPPRESS_UNUSED_WARNINGS
-# define CATCH_INTERNAL_UNSUPPRESS_UNUSED_WARNINGS
+#endif
+#if !defined(CATCH_INTERNAL_SUPPRESS_ZERO_VARIADIC_WARNINGS)
+# define CATCH_INTERNAL_SUPPRESS_ZERO_VARIADIC_WARNINGS
+#endif
+
+// The goal of this macro is to avoid evaluation of the arguments, but
+// still have the compiler warn on problems inside...
+#if !defined(CATCH_INTERNAL_IGNORE_BUT_WARN)
+# define CATCH_INTERNAL_IGNORE_BUT_WARN(...)
+#endif
+
+#if defined(__APPLE__) && defined(__apple_build_version__) && (__clang_major__ < 10)
+# undef CATCH_INTERNAL_SUPPRESS_UNUSED_TEMPLATE_WARNINGS
+#elif defined(__clang__) && (__clang_major__ < 5)
+# undef CATCH_INTERNAL_SUPPRESS_UNUSED_TEMPLATE_WARNINGS
+#endif
+
+#if !defined(CATCH_INTERNAL_SUPPRESS_UNUSED_TEMPLATE_WARNINGS)
+# define CATCH_INTERNAL_SUPPRESS_UNUSED_TEMPLATE_WARNINGS
#endif
#if defined(CATCH_CONFIG_DISABLE_EXCEPTIONS)
@@ -427,7 +505,7 @@ namespace Catch {
SourceLineInfo( SourceLineInfo&& ) noexcept = default;
SourceLineInfo& operator = ( SourceLineInfo&& ) noexcept = default;
- bool empty() const noexcept;
+ bool empty() const noexcept { return file[0] == '\0'; }
bool operator == ( SourceLineInfo const& other ) const noexcept;
bool operator < ( SourceLineInfo const& other ) const noexcept;
@@ -468,9 +546,10 @@ namespace Catch {
} // end namespace Catch
#define CATCH_REGISTER_TAG_ALIAS( alias, spec ) \
+ CATCH_INTERNAL_START_WARNINGS_SUPPRESSION \
CATCH_INTERNAL_SUPPRESS_GLOBALS_WARNINGS \
namespace{ Catch::RegistrarForTagAliases INTERNAL_CATCH_UNIQUE_NAME( AutoRegisterTagAlias )( alias, spec, CATCH_INTERNAL_LINEINFO ); } \
- CATCH_INTERNAL_UNSUPPRESS_GLOBALS_WARNINGS
+ CATCH_INTERNAL_STOP_WARNINGS_SUPPRESSION
// end catch_tag_alias_autoregistrar.h
// start catch_test_registry.h
@@ -497,6 +576,7 @@ namespace Catch {
virtual std::vector<TestCase> const& getAllTestsSorted( IConfig const& config ) const = 0;
};
+ bool isThrowSafe( TestCase const& testCase, IConfig const& config );
bool matchTest( TestCase const& testCase, TestSpec const& testSpec, IConfig const& config );
std::vector<TestCase> filterTests( std::vector<TestCase> const& testCases, TestSpec const& testSpec, IConfig const& config );
std::vector<TestCase> const& getAllTestCasesSorted( IConfig const& config );
@@ -509,53 +589,30 @@ namespace Catch {
#include <cstddef>
#include <string>
#include <iosfwd>
+#include <cassert>
namespace Catch {
/// A non-owning string class (similar to the forthcoming std::string_view)
/// Note that, because a StringRef may be a substring of another string,
- /// it may not be null terminated. c_str() must return a null terminated
- /// string, however, and so the StringRef will internally take ownership
- /// (taking a copy), if necessary. In theory this ownership is not externally
- /// visible - but it does mean (substring) StringRefs should not be shared between
- /// threads.
+ /// it may not be null terminated.
class StringRef {
public:
using size_type = std::size_t;
+ using const_iterator = const char*;
private:
- friend struct StringRefTestAccess;
-
- 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 )
- {}
-
- StringRef( StringRef const& other ) noexcept
- : m_start( other.m_start ),
- m_size( other.m_size )
- {}
+ char const* m_start = s_empty;
+ size_type m_size = 0;
- StringRef( StringRef&& other ) noexcept
- : m_start( other.m_start ),
- m_size( other.m_size ),
- m_data( other.m_data )
- {
- other.m_data = nullptr;
- }
+ public: // construction
+ constexpr StringRef() noexcept = default;
StringRef( char const* rawChars ) noexcept;
- StringRef( char const* rawChars, size_type size ) noexcept
+ constexpr StringRef( char const* rawChars, size_type size ) noexcept
: m_start( rawChars ),
m_size( size )
{}
@@ -565,101 +622,64 @@ namespace Catch {
m_size( stdString.size() )
{}
- ~StringRef() noexcept {
- delete[] m_data;
+ explicit operator std::string() const {
+ return std::string(m_start, m_size);
}
- 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;
- }
-
- 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 != (StringRef const& other) const noexcept -> bool {
+ return !(*this == other);
+ }
- auto operator[] ( size_type index ) const noexcept -> char;
+ auto operator[] ( size_type index ) const noexcept -> char {
+ assert(index < m_size);
+ return m_start[index];
+ }
public: // named queries
- auto empty() const noexcept -> bool {
+ constexpr auto empty() const noexcept -> bool {
return m_size == 0;
}
- auto size() const noexcept -> size_type {
+ constexpr auto size() const noexcept -> size_type {
return m_size;
}
- auto numberOfCharacters() const noexcept -> size_type;
+ // Returns the current start pointer. If the StringRef is not
+ // null-terminated, throws std::domain_exception
auto c_str() const -> char const*;
public: // substrings and searches
- auto substr( size_type start, size_type size ) const noexcept -> StringRef;
+ // Returns a substring of [start, start + length).
+ // If start + length > size(), then the substring is [start, size()).
+ // If start > size(), then the substring is empty.
+ auto substr( size_type start, size_type length ) const noexcept -> StringRef;
- // Returns the current start pointer.
- // Note that the pointer can change when if the StringRef is a substring
- auto currentData() const noexcept -> char const*;
+ // Returns the current start pointer. May not be null-terminated.
+ auto data() const noexcept -> char const*;
- private: // ownership queries - may not be consistent between calls
- auto isOwned() const noexcept -> bool;
- auto isSubstring() const noexcept -> bool;
- };
+ constexpr auto isNullTerminated() const noexcept -> bool {
+ return m_start[m_size] == '\0';
+ }
- 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;
+ public: // iterators
+ constexpr const_iterator begin() const { return m_start; }
+ constexpr const_iterator end() const { return m_start + m_size; }
+ };
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 {
+ constexpr auto operator "" _sr( char const* rawChars, std::size_t size ) noexcept -> StringRef {
return StringRef( rawChars, size );
}
-
} // namespace Catch
-inline auto operator "" _catch_sr( char const* rawChars, std::size_t size ) noexcept -> Catch::StringRef {
+constexpr auto operator "" _catch_sr( char const* rawChars, std::size_t size ) noexcept -> Catch::StringRef {
return Catch::StringRef( rawChars, size );
}
// end catch_stringref.h
-// start catch_type_traits.hpp
-
-
-#include <type_traits>
-
-namespace Catch{
-
-#ifdef CATCH_CPP17_OR_GREATER
- template <typename...>
- inline constexpr auto is_unique = std::true_type{};
-
- template <typename T, typename... Rest>
- inline constexpr auto is_unique<T, Rest...> = std::bool_constant<
- (!std::is_same_v<T, Rest> && ...) && is_unique<Rest...>
- >{};
-#else
-
-template <typename...>
-struct is_unique : std::true_type{};
-
-template <typename T0, typename T1, typename... Rest>
-struct is_unique<T0, T1, Rest...> : std::integral_constant
-<bool,
- !std::is_same<T0, T1>::value
- && is_unique<T0, Rest...>::value
- && is_unique<T1, Rest...>::value
->{};
-
-#endif
-}
-
-// end catch_type_traits.hpp
// start catch_preprocessor.hpp
@@ -722,23 +742,170 @@ struct is_unique<T0, T1, Rest...> : std::integral_constant
#define INTERNAL_CATCH_STRINGIZE_WITHOUT_PARENS(param) (INTERNAL_CATCH_STRINGIZE(INTERNAL_CATCH_REMOVE_PARENS(param)) + 1)
#endif
+#define INTERNAL_CATCH_MAKE_NAMESPACE2(...) ns_##__VA_ARGS__
+#define INTERNAL_CATCH_MAKE_NAMESPACE(name) INTERNAL_CATCH_MAKE_NAMESPACE2(name)
+
#define INTERNAL_CATCH_REMOVE_PARENS(...) INTERNAL_CATCH_EXPAND1(INTERNAL_CATCH_DEF __VA_ARGS__)
-#define INTERNAL_CATCH_TEMPLATE_UNIQUE_NAME2(Name, ...) INTERNAL_CATCH_TEMPLATE_UNIQUE_NAME3(Name, __VA_ARGS__)
#ifndef CATCH_CONFIG_TRADITIONAL_MSVC_PREPROCESSOR
-#define INTERNAL_CATCH_TEMPLATE_UNIQUE_NAME3(Name,...) Name " - " #__VA_ARGS__
-#define INTERNAL_CATCH_TEMPLATE_UNIQUE_NAME(Name,...) INTERNAL_CATCH_TEMPLATE_UNIQUE_NAME2(Name, INTERNAL_CATCH_REMOVE_PARENS(__VA_ARGS__))
+#define INTERNAL_CATCH_MAKE_TYPE_LIST2(...) decltype(get_wrapper<INTERNAL_CATCH_REMOVE_PARENS_GEN(__VA_ARGS__)>())
+#define INTERNAL_CATCH_MAKE_TYPE_LIST(...) INTERNAL_CATCH_MAKE_TYPE_LIST2(INTERNAL_CATCH_REMOVE_PARENS(__VA_ARGS__))
#else
-// MSVC is adding extra space and needs more calls to properly remove ()
-#define INTERNAL_CATCH_TEMPLATE_UNIQUE_NAME3(Name,...) Name " -" #__VA_ARGS__
-#define INTERNAL_CATCH_TEMPLATE_UNIQUE_NAME1(Name, ...) INTERNAL_CATCH_TEMPLATE_UNIQUE_NAME2(Name, __VA_ARGS__)
-#define INTERNAL_CATCH_TEMPLATE_UNIQUE_NAME(Name, ...) INTERNAL_CATCH_TEMPLATE_UNIQUE_NAME1(Name, INTERNAL_CATCH_EXPAND_VARGS(INTERNAL_CATCH_REMOVE_PARENS(__VA_ARGS__)))
+#define INTERNAL_CATCH_MAKE_TYPE_LIST2(...) INTERNAL_CATCH_EXPAND_VARGS(decltype(get_wrapper<INTERNAL_CATCH_REMOVE_PARENS_GEN(__VA_ARGS__)>()))
+#define INTERNAL_CATCH_MAKE_TYPE_LIST(...) INTERNAL_CATCH_EXPAND_VARGS(INTERNAL_CATCH_MAKE_TYPE_LIST2(INTERNAL_CATCH_REMOVE_PARENS(__VA_ARGS__)))
#endif
-#define INTERNAL_CATCH_MAKE_TYPE_LIST(types) Catch::TypeList<INTERNAL_CATCH_REMOVE_PARENS(types)>
+#define INTERNAL_CATCH_MAKE_TYPE_LISTS_FROM_TYPES(...)\
+ CATCH_REC_LIST(INTERNAL_CATCH_MAKE_TYPE_LIST,__VA_ARGS__)
+
+#define INTERNAL_CATCH_REMOVE_PARENS_1_ARG(_0) INTERNAL_CATCH_REMOVE_PARENS(_0)
+#define INTERNAL_CATCH_REMOVE_PARENS_2_ARG(_0, _1) INTERNAL_CATCH_REMOVE_PARENS(_0), INTERNAL_CATCH_REMOVE_PARENS_1_ARG(_1)
+#define INTERNAL_CATCH_REMOVE_PARENS_3_ARG(_0, _1, _2) INTERNAL_CATCH_REMOVE_PARENS(_0), INTERNAL_CATCH_REMOVE_PARENS_2_ARG(_1, _2)
+#define INTERNAL_CATCH_REMOVE_PARENS_4_ARG(_0, _1, _2, _3) INTERNAL_CATCH_REMOVE_PARENS(_0), INTERNAL_CATCH_REMOVE_PARENS_3_ARG(_1, _2, _3)
+#define INTERNAL_CATCH_REMOVE_PARENS_5_ARG(_0, _1, _2, _3, _4) INTERNAL_CATCH_REMOVE_PARENS(_0), INTERNAL_CATCH_REMOVE_PARENS_4_ARG(_1, _2, _3, _4)
+#define INTERNAL_CATCH_REMOVE_PARENS_6_ARG(_0, _1, _2, _3, _4, _5) INTERNAL_CATCH_REMOVE_PARENS(_0), INTERNAL_CATCH_REMOVE_PARENS_5_ARG(_1, _2, _3, _4, _5)
+#define INTERNAL_CATCH_REMOVE_PARENS_7_ARG(_0, _1, _2, _3, _4, _5, _6) INTERNAL_CATCH_REMOVE_PARENS(_0), INTERNAL_CATCH_REMOVE_PARENS_6_ARG(_1, _2, _4, _5, _6)
+#define INTERNAL_CATCH_REMOVE_PARENS_8_ARG(_0, _1, _2, _3, _4, _5, _6, _7) INTERNAL_CATCH_REMOVE_PARENS(_0), INTERNAL_CATCH_REMOVE_PARENS_7_ARG(_1, _2, _3, _4, _5, _6, _7)
+#define INTERNAL_CATCH_REMOVE_PARENS_9_ARG(_0, _1, _2, _3, _4, _5, _6, _7, _8) INTERNAL_CATCH_REMOVE_PARENS(_0), INTERNAL_CATCH_REMOVE_PARENS_8_ARG(_1, _2, _3, _4, _5, _6, _7, _8)
+#define INTERNAL_CATCH_REMOVE_PARENS_10_ARG(_0, _1, _2, _3, _4, _5, _6, _7, _8, _9) INTERNAL_CATCH_REMOVE_PARENS(_0), INTERNAL_CATCH_REMOVE_PARENS_9_ARG(_1, _2, _3, _4, _5, _6, _7, _8, _9)
+#define INTERNAL_CATCH_REMOVE_PARENS_11_ARG(_0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10) INTERNAL_CATCH_REMOVE_PARENS(_0), INTERNAL_CATCH_REMOVE_PARENS_10_ARG(_1, _2, _3, _4, _5, _6, _7, _8, _9, _10)
+
+#define INTERNAL_CATCH_VA_NARGS_IMPL(_0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, N, ...) N
+
+#define INTERNAL_CATCH_TYPE_GEN\
+ template<typename...> struct TypeList {};\
+ template<typename...Ts>\
+ constexpr auto get_wrapper() noexcept -> TypeList<Ts...> { return {}; }\
+ template<template<typename...> class...> struct TemplateTypeList{};\
+ template<template<typename...> class...Cs>\
+ constexpr auto get_wrapper() noexcept -> TemplateTypeList<Cs...> { return {}; }\
+ template<typename...>\
+ struct append;\
+ template<typename...>\
+ struct rewrap;\
+ template<template<typename...> class, typename...>\
+ struct create;\
+ template<template<typename...> class, typename>\
+ struct convert;\
+ \
+ template<typename T> \
+ struct append<T> { using type = T; };\
+ template< template<typename...> class L1, typename...E1, template<typename...> class L2, typename...E2, typename...Rest>\
+ struct append<L1<E1...>, L2<E2...>, Rest...> { using type = typename append<L1<E1...,E2...>, Rest...>::type; };\
+ template< template<typename...> class L1, typename...E1, typename...Rest>\
+ struct append<L1<E1...>, TypeList<mpl_::na>, Rest...> { using type = L1<E1...>; };\
+ \
+ template< template<typename...> class Container, template<typename...> class List, typename...elems>\
+ struct rewrap<TemplateTypeList<Container>, List<elems...>> { using type = TypeList<Container<elems...>>; };\
+ template< template<typename...> class Container, template<typename...> class List, class...Elems, typename...Elements>\
+ struct rewrap<TemplateTypeList<Container>, List<Elems...>, Elements...> { using type = typename append<TypeList<Container<Elems...>>, typename rewrap<TemplateTypeList<Container>, Elements...>::type>::type; };\
+ \
+ template<template <typename...> class Final, template< typename...> class...Containers, typename...Types>\
+ struct create<Final, TemplateTypeList<Containers...>, TypeList<Types...>> { using type = typename append<Final<>, typename rewrap<TemplateTypeList<Containers>, Types...>::type...>::type; };\
+ template<template <typename...> class Final, template <typename...> class List, typename...Ts>\
+ struct convert<Final, List<Ts...>> { using type = typename append<Final<>,TypeList<Ts>...>::type; };
+
+#define INTERNAL_CATCH_NTTP_1(signature, ...)\
+ template<INTERNAL_CATCH_REMOVE_PARENS(signature)> struct Nttp{};\
+ template<INTERNAL_CATCH_REMOVE_PARENS(signature)>\
+ constexpr auto get_wrapper() noexcept -> Nttp<__VA_ARGS__> { return {}; } \
+ template<template<INTERNAL_CATCH_REMOVE_PARENS(signature)> class...> struct NttpTemplateTypeList{};\
+ template<template<INTERNAL_CATCH_REMOVE_PARENS(signature)> class...Cs>\
+ constexpr auto get_wrapper() noexcept -> NttpTemplateTypeList<Cs...> { return {}; } \
+ \
+ template< template<INTERNAL_CATCH_REMOVE_PARENS(signature)> class Container, template<INTERNAL_CATCH_REMOVE_PARENS(signature)> class List, INTERNAL_CATCH_REMOVE_PARENS(signature)>\
+ struct rewrap<NttpTemplateTypeList<Container>, List<__VA_ARGS__>> { using type = TypeList<Container<__VA_ARGS__>>; };\
+ template< template<INTERNAL_CATCH_REMOVE_PARENS(signature)> class Container, template<INTERNAL_CATCH_REMOVE_PARENS(signature)> class List, INTERNAL_CATCH_REMOVE_PARENS(signature), typename...Elements>\
+ struct rewrap<NttpTemplateTypeList<Container>, List<__VA_ARGS__>, Elements...> { using type = typename append<TypeList<Container<__VA_ARGS__>>, typename rewrap<NttpTemplateTypeList<Container>, Elements...>::type>::type; };\
+ template<template <typename...> class Final, template<INTERNAL_CATCH_REMOVE_PARENS(signature)> class...Containers, typename...Types>\
+ struct create<Final, NttpTemplateTypeList<Containers...>, TypeList<Types...>> { using type = typename append<Final<>, typename rewrap<NttpTemplateTypeList<Containers>, Types...>::type...>::type; };
+
+#define INTERNAL_CATCH_DECLARE_SIG_TEST0(TestName)
+#define INTERNAL_CATCH_DECLARE_SIG_TEST1(TestName, signature)\
+ template<INTERNAL_CATCH_REMOVE_PARENS(signature)>\
+ static void TestName()
+#define INTERNAL_CATCH_DECLARE_SIG_TEST_X(TestName, signature, ...)\
+ template<INTERNAL_CATCH_REMOVE_PARENS(signature)>\
+ static void TestName()
+
+#define INTERNAL_CATCH_DEFINE_SIG_TEST0(TestName)
+#define INTERNAL_CATCH_DEFINE_SIG_TEST1(TestName, signature)\
+ template<INTERNAL_CATCH_REMOVE_PARENS(signature)>\
+ static void TestName()
+#define INTERNAL_CATCH_DEFINE_SIG_TEST_X(TestName, signature,...)\
+ template<INTERNAL_CATCH_REMOVE_PARENS(signature)>\
+ static void TestName()
+
+#define INTERNAL_CATCH_NTTP_REGISTER0(TestFunc, signature)\
+ template<typename Type>\
+ void reg_test(TypeList<Type>, Catch::NameAndTags nameAndTags)\
+ {\
+ Catch::AutoReg( Catch::makeTestInvoker(&TestFunc<Type>), CATCH_INTERNAL_LINEINFO, Catch::StringRef(), nameAndTags);\
+ }
+
+#define INTERNAL_CATCH_NTTP_REGISTER(TestFunc, signature, ...)\
+ template<INTERNAL_CATCH_REMOVE_PARENS(signature)>\
+ void reg_test(Nttp<__VA_ARGS__>, Catch::NameAndTags nameAndTags)\
+ {\
+ Catch::AutoReg( Catch::makeTestInvoker(&TestFunc<__VA_ARGS__>), CATCH_INTERNAL_LINEINFO, Catch::StringRef(), nameAndTags);\
+ }
+
+#define INTERNAL_CATCH_NTTP_REGISTER_METHOD0(TestName, signature, ...)\
+ template<typename Type>\
+ void reg_test(TypeList<Type>, Catch::StringRef className, Catch::NameAndTags nameAndTags)\
+ {\
+ Catch::AutoReg( Catch::makeTestInvoker(&TestName<Type>::test), CATCH_INTERNAL_LINEINFO, className, nameAndTags);\
+ }
+
+#define INTERNAL_CATCH_NTTP_REGISTER_METHOD(TestName, signature, ...)\
+ template<INTERNAL_CATCH_REMOVE_PARENS(signature)>\
+ void reg_test(Nttp<__VA_ARGS__>, Catch::StringRef className, Catch::NameAndTags nameAndTags)\
+ {\
+ Catch::AutoReg( Catch::makeTestInvoker(&TestName<__VA_ARGS__>::test), CATCH_INTERNAL_LINEINFO, className, nameAndTags);\
+ }
+
+#define INTERNAL_CATCH_DECLARE_SIG_TEST_METHOD0(TestName, ClassName)
+#define INTERNAL_CATCH_DECLARE_SIG_TEST_METHOD1(TestName, ClassName, signature)\
+ template<typename TestType> \
+ struct TestName : INTERNAL_CATCH_REMOVE_PARENS(ClassName)<TestType> { \
+ void test();\
+ }
+
+#define INTERNAL_CATCH_DECLARE_SIG_TEST_METHOD_X(TestName, ClassName, signature, ...)\
+ template<INTERNAL_CATCH_REMOVE_PARENS(signature)> \
+ struct TestName : INTERNAL_CATCH_REMOVE_PARENS(ClassName)<__VA_ARGS__> { \
+ void test();\
+ }
+
+#define INTERNAL_CATCH_DEFINE_SIG_TEST_METHOD0(TestName)
+#define INTERNAL_CATCH_DEFINE_SIG_TEST_METHOD1(TestName, signature)\
+ template<typename TestType> \
+ void INTERNAL_CATCH_MAKE_NAMESPACE(TestName)::TestName<TestType>::test()
+#define INTERNAL_CATCH_DEFINE_SIG_TEST_METHOD_X(TestName, signature, ...)\
+ template<INTERNAL_CATCH_REMOVE_PARENS(signature)> \
+ void INTERNAL_CATCH_MAKE_NAMESPACE(TestName)::TestName<__VA_ARGS__>::test()
-#define INTERNAL_CATCH_MAKE_TYPE_LISTS_FROM_TYPES(types)\
- CATCH_REC_LIST(INTERNAL_CATCH_MAKE_TYPE_LIST,INTERNAL_CATCH_REMOVE_PARENS(types))
+#ifndef CATCH_CONFIG_TRADITIONAL_MSVC_PREPROCESSOR
+#define INTERNAL_CATCH_NTTP_0
+#define INTERNAL_CATCH_NTTP_GEN(...) INTERNAL_CATCH_VA_NARGS_IMPL(__VA_ARGS__, INTERNAL_CATCH_NTTP_1(__VA_ARGS__), INTERNAL_CATCH_NTTP_1(__VA_ARGS__), INTERNAL_CATCH_NTTP_1(__VA_ARGS__), INTERNAL_CATCH_NTTP_1(__VA_ARGS__), INTERNAL_CATCH_NTTP_1(__VA_ARGS__), INTERNAL_CATCH_NTTP_1( __VA_ARGS__), INTERNAL_CATCH_NTTP_1( __VA_ARGS__), INTERNAL_CATCH_NTTP_1( __VA_ARGS__), INTERNAL_CATCH_NTTP_1( __VA_ARGS__),INTERNAL_CATCH_NTTP_1( __VA_ARGS__), INTERNAL_CATCH_NTTP_0)
+#define INTERNAL_CATCH_DEFINE_SIG_TEST_METHOD(TestName, ...) INTERNAL_CATCH_VA_NARGS_IMPL( "dummy", __VA_ARGS__, INTERNAL_CATCH_DEFINE_SIG_TEST_METHOD_X,INTERNAL_CATCH_DEFINE_SIG_TEST_METHOD_X, INTERNAL_CATCH_DEFINE_SIG_TEST_METHOD_X, INTERNAL_CATCH_DEFINE_SIG_TEST_METHOD_X, INTERNAL_CATCH_DEFINE_SIG_TEST_METHOD_X, INTERNAL_CATCH_DEFINE_SIG_TEST_METHOD_X, INTERNAL_CATCH_DEFINE_SIG_TEST_METHOD_X,INTERNAL_CATCH_DEFINE_SIG_TEST_METHOD_X,INTERNAL_CATCH_DEFINE_SIG_TEST_METHOD_X, INTERNAL_CATCH_DEFINE_SIG_TEST_METHOD1, INTERNAL_CATCH_DEFINE_SIG_TEST_METHOD0)(TestName, __VA_ARGS__)
+#define INTERNAL_CATCH_DECLARE_SIG_TEST_METHOD(TestName, ClassName, ...) INTERNAL_CATCH_VA_NARGS_IMPL( "dummy", __VA_ARGS__, INTERNAL_CATCH_DECLARE_SIG_TEST_METHOD_X,INTERNAL_CATCH_DECLARE_SIG_TEST_METHOD_X, INTERNAL_CATCH_DECLARE_SIG_TEST_METHOD_X, INTERNAL_CATCH_DECLARE_SIG_TEST_METHOD_X, INTERNAL_CATCH_DECLARE_SIG_TEST_METHOD_X, INTERNAL_CATCH_DECLARE_SIG_TEST_METHOD_X, INTERNAL_CATCH_DECLARE_SIG_TEST_METHOD_X,INTERNAL_CATCH_DECLARE_SIG_TEST_METHOD_X,INTERNAL_CATCH_DECLARE_SIG_TEST_METHOD_X, INTERNAL_CATCH_DECLARE_SIG_TEST_METHOD1, INTERNAL_CATCH_DECLARE_SIG_TEST_METHOD0)(TestName, ClassName, __VA_ARGS__)
+#define INTERNAL_CATCH_NTTP_REG_METHOD_GEN(TestName, ...) INTERNAL_CATCH_VA_NARGS_IMPL( "dummy", __VA_ARGS__, INTERNAL_CATCH_NTTP_REGISTER_METHOD, INTERNAL_CATCH_NTTP_REGISTER_METHOD, INTERNAL_CATCH_NTTP_REGISTER_METHOD, INTERNAL_CATCH_NTTP_REGISTER_METHOD, INTERNAL_CATCH_NTTP_REGISTER_METHOD, INTERNAL_CATCH_NTTP_REGISTER_METHOD, INTERNAL_CATCH_NTTP_REGISTER_METHOD, INTERNAL_CATCH_NTTP_REGISTER_METHOD, INTERNAL_CATCH_NTTP_REGISTER_METHOD, INTERNAL_CATCH_NTTP_REGISTER_METHOD0, INTERNAL_CATCH_NTTP_REGISTER_METHOD0)(TestName, __VA_ARGS__)
+#define INTERNAL_CATCH_NTTP_REG_GEN(TestFunc, ...) INTERNAL_CATCH_VA_NARGS_IMPL( "dummy", __VA_ARGS__, INTERNAL_CATCH_NTTP_REGISTER, INTERNAL_CATCH_NTTP_REGISTER, INTERNAL_CATCH_NTTP_REGISTER, INTERNAL_CATCH_NTTP_REGISTER, INTERNAL_CATCH_NTTP_REGISTER, INTERNAL_CATCH_NTTP_REGISTER, INTERNAL_CATCH_NTTP_REGISTER, INTERNAL_CATCH_NTTP_REGISTER, INTERNAL_CATCH_NTTP_REGISTER, INTERNAL_CATCH_NTTP_REGISTER0, INTERNAL_CATCH_NTTP_REGISTER0)(TestFunc, __VA_ARGS__)
+#define INTERNAL_CATCH_DEFINE_SIG_TEST(TestName, ...) INTERNAL_CATCH_VA_NARGS_IMPL( "dummy", __VA_ARGS__, INTERNAL_CATCH_DEFINE_SIG_TEST_X, INTERNAL_CATCH_DEFINE_SIG_TEST_X, INTERNAL_CATCH_DEFINE_SIG_TEST_X, INTERNAL_CATCH_DEFINE_SIG_TEST_X, INTERNAL_CATCH_DEFINE_SIG_TEST_X, INTERNAL_CATCH_DEFINE_SIG_TEST_X, INTERNAL_CATCH_DEFINE_SIG_TEST_X, INTERNAL_CATCH_DEFINE_SIG_TEST_X,INTERNAL_CATCH_DEFINE_SIG_TEST_X,INTERNAL_CATCH_DEFINE_SIG_TEST1, INTERNAL_CATCH_DEFINE_SIG_TEST0)(TestName, __VA_ARGS__)
+#define INTERNAL_CATCH_DECLARE_SIG_TEST(TestName, ...) INTERNAL_CATCH_VA_NARGS_IMPL( "dummy", __VA_ARGS__, INTERNAL_CATCH_DECLARE_SIG_TEST_X,INTERNAL_CATCH_DECLARE_SIG_TEST_X, INTERNAL_CATCH_DECLARE_SIG_TEST_X, INTERNAL_CATCH_DECLARE_SIG_TEST_X, INTERNAL_CATCH_DECLARE_SIG_TEST_X, INTERNAL_CATCH_DECLARE_SIG_TEST_X, INTERNAL_CATCH_DEFINE_SIG_TEST_X,INTERNAL_CATCH_DECLARE_SIG_TEST_X,INTERNAL_CATCH_DECLARE_SIG_TEST_X, INTERNAL_CATCH_DECLARE_SIG_TEST1, INTERNAL_CATCH_DECLARE_SIG_TEST0)(TestName, __VA_ARGS__)
+#define INTERNAL_CATCH_REMOVE_PARENS_GEN(...) INTERNAL_CATCH_VA_NARGS_IMPL(__VA_ARGS__, INTERNAL_CATCH_REMOVE_PARENS_11_ARG,INTERNAL_CATCH_REMOVE_PARENS_10_ARG,INTERNAL_CATCH_REMOVE_PARENS_9_ARG,INTERNAL_CATCH_REMOVE_PARENS_8_ARG,INTERNAL_CATCH_REMOVE_PARENS_7_ARG,INTERNAL_CATCH_REMOVE_PARENS_6_ARG,INTERNAL_CATCH_REMOVE_PARENS_5_ARG,INTERNAL_CATCH_REMOVE_PARENS_4_ARG,INTERNAL_CATCH_REMOVE_PARENS_3_ARG,INTERNAL_CATCH_REMOVE_PARENS_2_ARG,INTERNAL_CATCH_REMOVE_PARENS_1_ARG)(__VA_ARGS__)
+#else
+#define INTERNAL_CATCH_NTTP_0(signature)
+#define INTERNAL_CATCH_NTTP_GEN(...) INTERNAL_CATCH_EXPAND_VARGS(INTERNAL_CATCH_VA_NARGS_IMPL(__VA_ARGS__, INTERNAL_CATCH_NTTP_1, INTERNAL_CATCH_NTTP_1, INTERNAL_CATCH_NTTP_1, INTERNAL_CATCH_NTTP_1, INTERNAL_CATCH_NTTP_1, INTERNAL_CATCH_NTTP_1, INTERNAL_CATCH_NTTP_1, INTERNAL_CATCH_NTTP_1, INTERNAL_CATCH_NTTP_1,INTERNAL_CATCH_NTTP_1, INTERNAL_CATCH_NTTP_0)( __VA_ARGS__))
+#define INTERNAL_CATCH_DEFINE_SIG_TEST_METHOD(TestName, ...) INTERNAL_CATCH_EXPAND_VARGS(INTERNAL_CATCH_VA_NARGS_IMPL( "dummy", __VA_ARGS__, INTERNAL_CATCH_DEFINE_SIG_TEST_METHOD_X,INTERNAL_CATCH_DEFINE_SIG_TEST_METHOD_X, INTERNAL_CATCH_DEFINE_SIG_TEST_METHOD_X, INTERNAL_CATCH_DEFINE_SIG_TEST_METHOD_X, INTERNAL_CATCH_DEFINE_SIG_TEST_METHOD_X, INTERNAL_CATCH_DEFINE_SIG_TEST_METHOD_X, INTERNAL_CATCH_DEFINE_SIG_TEST_METHOD_X,INTERNAL_CATCH_DEFINE_SIG_TEST_METHOD_X,INTERNAL_CATCH_DEFINE_SIG_TEST_METHOD_X, INTERNAL_CATCH_DEFINE_SIG_TEST_METHOD1, INTERNAL_CATCH_DEFINE_SIG_TEST_METHOD0)(TestName, __VA_ARGS__))
+#define INTERNAL_CATCH_DECLARE_SIG_TEST_METHOD(TestName, ClassName, ...) INTERNAL_CATCH_EXPAND_VARGS(INTERNAL_CATCH_VA_NARGS_IMPL( "dummy", __VA_ARGS__, INTERNAL_CATCH_DECLARE_SIG_TEST_METHOD_X,INTERNAL_CATCH_DECLARE_SIG_TEST_METHOD_X, INTERNAL_CATCH_DECLARE_SIG_TEST_METHOD_X, INTERNAL_CATCH_DECLARE_SIG_TEST_METHOD_X, INTERNAL_CATCH_DECLARE_SIG_TEST_METHOD_X, INTERNAL_CATCH_DECLARE_SIG_TEST_METHOD_X, INTERNAL_CATCH_DECLARE_SIG_TEST_METHOD_X,INTERNAL_CATCH_DECLARE_SIG_TEST_METHOD_X,INTERNAL_CATCH_DECLARE_SIG_TEST_METHOD_X, INTERNAL_CATCH_DECLARE_SIG_TEST_METHOD1, INTERNAL_CATCH_DECLARE_SIG_TEST_METHOD0)(TestName, ClassName, __VA_ARGS__))
+#define INTERNAL_CATCH_NTTP_REG_METHOD_GEN(TestName, ...) INTERNAL_CATCH_EXPAND_VARGS(INTERNAL_CATCH_VA_NARGS_IMPL( "dummy", __VA_ARGS__, INTERNAL_CATCH_NTTP_REGISTER_METHOD, INTERNAL_CATCH_NTTP_REGISTER_METHOD, INTERNAL_CATCH_NTTP_REGISTER_METHOD, INTERNAL_CATCH_NTTP_REGISTER_METHOD, INTERNAL_CATCH_NTTP_REGISTER_METHOD, INTERNAL_CATCH_NTTP_REGISTER_METHOD, INTERNAL_CATCH_NTTP_REGISTER_METHOD, INTERNAL_CATCH_NTTP_REGISTER_METHOD, INTERNAL_CATCH_NTTP_REGISTER_METHOD, INTERNAL_CATCH_NTTP_REGISTER_METHOD0, INTERNAL_CATCH_NTTP_REGISTER_METHOD0)(TestName, __VA_ARGS__))
+#define INTERNAL_CATCH_NTTP_REG_GEN(TestFunc, ...) INTERNAL_CATCH_EXPAND_VARGS(INTERNAL_CATCH_VA_NARGS_IMPL( "dummy", __VA_ARGS__, INTERNAL_CATCH_NTTP_REGISTER, INTERNAL_CATCH_NTTP_REGISTER, INTERNAL_CATCH_NTTP_REGISTER, INTERNAL_CATCH_NTTP_REGISTER, INTERNAL_CATCH_NTTP_REGISTER, INTERNAL_CATCH_NTTP_REGISTER, INTERNAL_CATCH_NTTP_REGISTER, INTERNAL_CATCH_NTTP_REGISTER, INTERNAL_CATCH_NTTP_REGISTER, INTERNAL_CATCH_NTTP_REGISTER0, INTERNAL_CATCH_NTTP_REGISTER0)(TestFunc, __VA_ARGS__))
+#define INTERNAL_CATCH_DEFINE_SIG_TEST(TestName, ...) INTERNAL_CATCH_EXPAND_VARGS(INTERNAL_CATCH_VA_NARGS_IMPL( "dummy", __VA_ARGS__, INTERNAL_CATCH_DEFINE_SIG_TEST_X, INTERNAL_CATCH_DEFINE_SIG_TEST_X, INTERNAL_CATCH_DEFINE_SIG_TEST_X, INTERNAL_CATCH_DEFINE_SIG_TEST_X, INTERNAL_CATCH_DEFINE_SIG_TEST_X, INTERNAL_CATCH_DEFINE_SIG_TEST_X, INTERNAL_CATCH_DEFINE_SIG_TEST_X, INTERNAL_CATCH_DEFINE_SIG_TEST_X,INTERNAL_CATCH_DEFINE_SIG_TEST_X,INTERNAL_CATCH_DEFINE_SIG_TEST1, INTERNAL_CATCH_DEFINE_SIG_TEST0)(TestName, __VA_ARGS__))
+#define INTERNAL_CATCH_DECLARE_SIG_TEST(TestName, ...) INTERNAL_CATCH_EXPAND_VARGS(INTERNAL_CATCH_VA_NARGS_IMPL( "dummy", __VA_ARGS__, INTERNAL_CATCH_DECLARE_SIG_TEST_X,INTERNAL_CATCH_DECLARE_SIG_TEST_X, INTERNAL_CATCH_DECLARE_SIG_TEST_X, INTERNAL_CATCH_DECLARE_SIG_TEST_X, INTERNAL_CATCH_DECLARE_SIG_TEST_X, INTERNAL_CATCH_DECLARE_SIG_TEST_X, INTERNAL_CATCH_DEFINE_SIG_TEST_X,INTERNAL_CATCH_DECLARE_SIG_TEST_X,INTERNAL_CATCH_DECLARE_SIG_TEST_X, INTERNAL_CATCH_DECLARE_SIG_TEST1, INTERNAL_CATCH_DECLARE_SIG_TEST0)(TestName, __VA_ARGS__))
+#define INTERNAL_CATCH_REMOVE_PARENS_GEN(...) INTERNAL_CATCH_EXPAND_VARGS(INTERNAL_CATCH_VA_NARGS_IMPL(__VA_ARGS__, INTERNAL_CATCH_REMOVE_PARENS_11_ARG,INTERNAL_CATCH_REMOVE_PARENS_10_ARG,INTERNAL_CATCH_REMOVE_PARENS_9_ARG,INTERNAL_CATCH_REMOVE_PARENS_8_ARG,INTERNAL_CATCH_REMOVE_PARENS_7_ARG,INTERNAL_CATCH_REMOVE_PARENS_6_ARG,INTERNAL_CATCH_REMOVE_PARENS_5_ARG,INTERNAL_CATCH_REMOVE_PARENS_4_ARG,INTERNAL_CATCH_REMOVE_PARENS_3_ARG,INTERNAL_CATCH_REMOVE_PARENS_2_ARG,INTERNAL_CATCH_REMOVE_PARENS_1_ARG)(__VA_ARGS__))
+#endif
// end catch_preprocessor.hpp
// start catch_meta.hpp
@@ -747,68 +914,40 @@ struct is_unique<T0, T1, Rest...> : std::integral_constant
#include <type_traits>
namespace Catch {
-template< typename... >
-struct TypeList {};
-
-template< typename... >
-struct append;
-
-template< template<typename...> class L1
- , typename...E1
- , template<typename...> class L2
- , typename...E2
->
-struct append< L1<E1...>, L2<E2...> > {
- using type = L1<E1..., E2...>;
-};
-
-template< template<typename...> class L1
- , typename...E1
- , template<typename...> class L2
- , typename...E2
- , typename...Rest
->
-struct append< L1<E1...>, L2<E2...>, Rest...> {
- using type = typename append< L1<E1..., E2...>, Rest... >::type;
-};
+ template<typename T>
+ struct always_false : std::false_type {};
+
+ template <typename> struct true_given : std::true_type {};
+ struct is_callable_tester {
+ template <typename Fun, typename... Args>
+ true_given<decltype(std::declval<Fun>()(std::declval<Args>()...))> static test(int);
+ template <typename...>
+ std::false_type static test(...);
+ };
-template< template<typename...> class
- , typename...
->
-struct rewrap;
-
-template< template<typename...> class Container
- , template<typename...> class List
- , typename...elems
->
-struct rewrap<Container, List<elems...>> {
- using type = TypeList< Container< elems... > >;
-};
+ template <typename T>
+ struct is_callable;
-template< template<typename...> class Container
- , template<typename...> class List
- , class...Elems
- , typename...Elements>
- struct rewrap<Container, List<Elems...>, Elements...> {
- using type = typename append<TypeList<Container<Elems...>>, typename rewrap<Container, Elements...>::type>::type;
-};
+ template <typename Fun, typename... Args>
+ struct is_callable<Fun(Args...)> : decltype(is_callable_tester::test<Fun, Args...>(0)) {};
-template< template<typename...> class...Containers >
-struct combine {
- template< typename...Types >
- struct with_types {
- template< template <typename...> class Final >
- struct into {
- using type = typename append<Final<>, typename rewrap<Containers, Types...>::type...>::type;
- };
- };
-};
-
-template<typename T>
-struct always_false : std::false_type {};
+#if defined(__cpp_lib_is_invocable) && __cpp_lib_is_invocable >= 201703
+ // std::result_of is deprecated in C++17 and removed in C++20. Hence, it is
+ // replaced with std::invoke_result here. Also *_t format is preferred over
+ // typename *::type format.
+ template <typename Func, typename U>
+ using FunctionReturnType = std::remove_reference_t<std::remove_cv_t<std::invoke_result_t<Func, U>>>;
+#else
+ template <typename Func, typename U>
+ using FunctionReturnType = typename std::remove_reference<typename std::remove_cv<typename std::result_of<Func(U)>::type>::type>::type;
+#endif
} // namespace Catch
+namespace mpl_{
+ struct na;
+}
+
// end catch_meta.hpp
namespace Catch {
@@ -854,38 +993,70 @@ struct AutoReg : NonCopyable {
}; \
} \
void TestName::test()
- #define INTERNAL_CATCH_TEMPLATE_TEST_CASE_NO_REGISTRATION( TestName, ... ) \
- template<typename TestType> \
- static void TestName()
- #define INTERNAL_CATCH_TEMPLATE_TEST_CASE_METHOD_NO_REGISTRATION( TestName, ClassName, ... ) \
+ #define INTERNAL_CATCH_TEMPLATE_TEST_CASE_NO_REGISTRATION_2( TestName, TestFunc, Name, Tags, Signature, ... ) \
+ INTERNAL_CATCH_DEFINE_SIG_TEST(TestFunc, INTERNAL_CATCH_REMOVE_PARENS(Signature))
+ #define INTERNAL_CATCH_TEMPLATE_TEST_CASE_METHOD_NO_REGISTRATION_2( TestNameClass, TestName, ClassName, Name, Tags, Signature, ... ) \
namespace{ \
- template<typename TestType> \
- struct TestName : INTERNAL_CATCH_REMOVE_PARENS(ClassName <TestType>) { \
- void test(); \
- }; \
+ namespace INTERNAL_CATCH_MAKE_NAMESPACE(TestName) { \
+ INTERNAL_CATCH_DECLARE_SIG_TEST_METHOD(TestName, ClassName, INTERNAL_CATCH_REMOVE_PARENS(Signature));\
} \
- template<typename TestType> \
- void TestName::test()
+ } \
+ INTERNAL_CATCH_DEFINE_SIG_TEST_METHOD(TestName, INTERNAL_CATCH_REMOVE_PARENS(Signature))
+
+ #ifndef CATCH_CONFIG_TRADITIONAL_MSVC_PREPROCESSOR
+ #define INTERNAL_CATCH_TEMPLATE_TEST_CASE_NO_REGISTRATION(Name, Tags, ...) \
+ INTERNAL_CATCH_TEMPLATE_TEST_CASE_NO_REGISTRATION_2( INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_M_P_L_A_T_E____T_E_S_T____ ), INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_M_P_L_A_T_E____T_E_S_T____F_U_N_C____ ), Name, Tags, typename TestType, __VA_ARGS__ )
+ #else
+ #define INTERNAL_CATCH_TEMPLATE_TEST_CASE_NO_REGISTRATION(Name, Tags, ...) \
+ INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_TEST_CASE_NO_REGISTRATION_2( INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_M_P_L_A_T_E____T_E_S_T____ ), INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_M_P_L_A_T_E____T_E_S_T____F_U_N_C____ ), Name, Tags, typename TestType, __VA_ARGS__ ) )
+ #endif
+
+ #ifndef CATCH_CONFIG_TRADITIONAL_MSVC_PREPROCESSOR
+ #define INTERNAL_CATCH_TEMPLATE_TEST_CASE_SIG_NO_REGISTRATION(Name, Tags, Signature, ...) \
+ INTERNAL_CATCH_TEMPLATE_TEST_CASE_NO_REGISTRATION_2( INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_M_P_L_A_T_E____T_E_S_T____ ), INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_M_P_L_A_T_E____T_E_S_T____F_U_N_C____ ), Name, Tags, Signature, __VA_ARGS__ )
+ #else
+ #define INTERNAL_CATCH_TEMPLATE_TEST_CASE_SIG_NO_REGISTRATION(Name, Tags, Signature, ...) \
+ INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_TEST_CASE_NO_REGISTRATION_2( INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_M_P_L_A_T_E____T_E_S_T____ ), INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_M_P_L_A_T_E____T_E_S_T____F_U_N_C____ ), Name, Tags, Signature, __VA_ARGS__ ) )
+ #endif
+
+ #ifndef CATCH_CONFIG_TRADITIONAL_MSVC_PREPROCESSOR
+ #define INTERNAL_CATCH_TEMPLATE_TEST_CASE_METHOD_NO_REGISTRATION( ClassName, Name, Tags,... ) \
+ INTERNAL_CATCH_TEMPLATE_TEST_CASE_METHOD_NO_REGISTRATION_2( INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_M_P_L_A_T_E____T_E_S_T____C_L_A_S_S____ ), INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_M_P_L_A_T_E____T_E_S_T____ ) , ClassName, Name, Tags, typename T, __VA_ARGS__ )
+ #else
+ #define INTERNAL_CATCH_TEMPLATE_TEST_CASE_METHOD_NO_REGISTRATION( ClassName, Name, Tags,... ) \
+ INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_TEST_CASE_METHOD_NO_REGISTRATION_2( INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_M_P_L_A_T_E____T_E_S_T____C_L_A_S_S____ ), INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_M_P_L_A_T_E____T_E_S_T____ ) , ClassName, Name, Tags, typename T, __VA_ARGS__ ) )
+ #endif
+
+ #ifndef CATCH_CONFIG_TRADITIONAL_MSVC_PREPROCESSOR
+ #define INTERNAL_CATCH_TEMPLATE_TEST_CASE_METHOD_SIG_NO_REGISTRATION( ClassName, Name, Tags, Signature, ... ) \
+ INTERNAL_CATCH_TEMPLATE_TEST_CASE_METHOD_NO_REGISTRATION_2( INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_M_P_L_A_T_E____T_E_S_T____C_L_A_S_S____ ), INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_M_P_L_A_T_E____T_E_S_T____ ) , ClassName, Name, Tags, Signature, __VA_ARGS__ )
+ #else
+ #define INTERNAL_CATCH_TEMPLATE_TEST_CASE_METHOD_SIG_NO_REGISTRATION( ClassName, Name, Tags, Signature, ... ) \
+ INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_TEST_CASE_METHOD_NO_REGISTRATION_2( INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_M_P_L_A_T_E____T_E_S_T____C_L_A_S_S____ ), INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_M_P_L_A_T_E____T_E_S_T____ ) , ClassName, Name, Tags, Signature, __VA_ARGS__ ) )
+ #endif
#endif
///////////////////////////////////////////////////////////////////////////////
#define INTERNAL_CATCH_TESTCASE2( TestName, ... ) \
static void TestName(); \
+ CATCH_INTERNAL_START_WARNINGS_SUPPRESSION \
CATCH_INTERNAL_SUPPRESS_GLOBALS_WARNINGS \
namespace{ Catch::AutoReg INTERNAL_CATCH_UNIQUE_NAME( autoRegistrar )( Catch::makeTestInvoker( &TestName ), CATCH_INTERNAL_LINEINFO, Catch::StringRef(), Catch::NameAndTags{ __VA_ARGS__ } ); } /* NOLINT */ \
- CATCH_INTERNAL_UNSUPPRESS_GLOBALS_WARNINGS \
+ CATCH_INTERNAL_STOP_WARNINGS_SUPPRESSION \
static void TestName()
#define INTERNAL_CATCH_TESTCASE( ... ) \
INTERNAL_CATCH_TESTCASE2( INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_S_T____ ), __VA_ARGS__ )
///////////////////////////////////////////////////////////////////////////////
#define INTERNAL_CATCH_METHOD_AS_TEST_CASE( QualifiedMethod, ... ) \
+ CATCH_INTERNAL_START_WARNINGS_SUPPRESSION \
CATCH_INTERNAL_SUPPRESS_GLOBALS_WARNINGS \
namespace{ Catch::AutoReg INTERNAL_CATCH_UNIQUE_NAME( autoRegistrar )( Catch::makeTestInvoker( &QualifiedMethod ), CATCH_INTERNAL_LINEINFO, "&" #QualifiedMethod, Catch::NameAndTags{ __VA_ARGS__ } ); } /* NOLINT */ \
- CATCH_INTERNAL_UNSUPPRESS_GLOBALS_WARNINGS
+ CATCH_INTERNAL_STOP_WARNINGS_SUPPRESSION
///////////////////////////////////////////////////////////////////////////////
#define INTERNAL_CATCH_TEST_CASE_METHOD2( TestName, ClassName, ... )\
+ CATCH_INTERNAL_START_WARNINGS_SUPPRESSION \
CATCH_INTERNAL_SUPPRESS_GLOBALS_WARNINGS \
namespace{ \
struct TestName : INTERNAL_CATCH_REMOVE_PARENS(ClassName) { \
@@ -893,66 +1064,77 @@ struct AutoReg : NonCopyable {
}; \
Catch::AutoReg INTERNAL_CATCH_UNIQUE_NAME( autoRegistrar ) ( Catch::makeTestInvoker( &TestName::test ), CATCH_INTERNAL_LINEINFO, #ClassName, Catch::NameAndTags{ __VA_ARGS__ } ); /* NOLINT */ \
} \
- CATCH_INTERNAL_UNSUPPRESS_GLOBALS_WARNINGS \
+ CATCH_INTERNAL_STOP_WARNINGS_SUPPRESSION \
void TestName::test()
#define INTERNAL_CATCH_TEST_CASE_METHOD( ClassName, ... ) \
INTERNAL_CATCH_TEST_CASE_METHOD2( INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_S_T____ ), ClassName, __VA_ARGS__ )
///////////////////////////////////////////////////////////////////////////////
#define INTERNAL_CATCH_REGISTER_TESTCASE( Function, ... ) \
+ CATCH_INTERNAL_START_WARNINGS_SUPPRESSION \
CATCH_INTERNAL_SUPPRESS_GLOBALS_WARNINGS \
Catch::AutoReg INTERNAL_CATCH_UNIQUE_NAME( autoRegistrar )( Catch::makeTestInvoker( Function ), CATCH_INTERNAL_LINEINFO, Catch::StringRef(), Catch::NameAndTags{ __VA_ARGS__ } ); /* NOLINT */ \
- CATCH_INTERNAL_UNSUPPRESS_GLOBALS_WARNINGS
+ CATCH_INTERNAL_STOP_WARNINGS_SUPPRESSION
///////////////////////////////////////////////////////////////////////////////
- #define INTERNAL_CATCH_TEMPLATE_TEST_CASE_2(TestName, TestFunc, Name, Tags, ... )\
+ #define INTERNAL_CATCH_TEMPLATE_TEST_CASE_2(TestName, TestFunc, Name, Tags, Signature, ... )\
+ CATCH_INTERNAL_START_WARNINGS_SUPPRESSION \
CATCH_INTERNAL_SUPPRESS_GLOBALS_WARNINGS \
- template<typename TestType> \
- static void TestFunc();\
+ CATCH_INTERNAL_SUPPRESS_ZERO_VARIADIC_WARNINGS \
+ CATCH_INTERNAL_SUPPRESS_UNUSED_TEMPLATE_WARNINGS \
+ INTERNAL_CATCH_DECLARE_SIG_TEST(TestFunc, INTERNAL_CATCH_REMOVE_PARENS(Signature));\
namespace {\
+ namespace INTERNAL_CATCH_MAKE_NAMESPACE(TestName){\
+ INTERNAL_CATCH_TYPE_GEN\
+ INTERNAL_CATCH_NTTP_GEN(INTERNAL_CATCH_REMOVE_PARENS(Signature))\
+ INTERNAL_CATCH_NTTP_REG_GEN(TestFunc,INTERNAL_CATCH_REMOVE_PARENS(Signature))\
template<typename...Types> \
struct TestName{\
- template<typename...Ts> \
- TestName(Ts...names){\
- CATCH_INTERNAL_CHECK_UNIQUE_TYPES(CATCH_REC_LIST(INTERNAL_CATCH_REMOVE_PARENS, __VA_ARGS__)) \
+ TestName(){\
+ int index = 0; \
+ constexpr char const* tmpl_types[] = {CATCH_REC_LIST(INTERNAL_CATCH_STRINGIZE_WITHOUT_PARENS, __VA_ARGS__)};\
using expander = int[];\
- (void)expander{(Catch::AutoReg( Catch::makeTestInvoker( &TestFunc<Types> ), CATCH_INTERNAL_LINEINFO, Catch::StringRef(), Catch::NameAndTags{ names, Tags } ), 0)... };/* NOLINT */ \
+ (void)expander{(reg_test(Types{}, Catch::NameAndTags{ Name " - " + std::string(tmpl_types[index]), Tags } ), index++, 0)... };/* NOLINT */ \
}\
};\
- INTERNAL_CATCH_TEMPLATE_REGISTRY_INITIATE(TestName, Name, __VA_ARGS__) \
+ static int INTERNAL_CATCH_UNIQUE_NAME( globalRegistrar ) = [](){\
+ TestName<INTERNAL_CATCH_MAKE_TYPE_LISTS_FROM_TYPES(__VA_ARGS__)>();\
+ return 0;\
+ }();\
}\
- CATCH_INTERNAL_UNSUPPRESS_GLOBALS_WARNINGS \
- template<typename TestType> \
- static void TestFunc()
-
-#if defined(CATCH_CPP17_OR_GREATER)
-#define CATCH_INTERNAL_CHECK_UNIQUE_TYPES(...) static_assert(Catch::is_unique<__VA_ARGS__>,"Duplicate type detected in declaration of template test case");
-#else
-#define CATCH_INTERNAL_CHECK_UNIQUE_TYPES(...) static_assert(Catch::is_unique<__VA_ARGS__>::value,"Duplicate type detected in declaration of template test case");
-#endif
+ }\
+ CATCH_INTERNAL_STOP_WARNINGS_SUPPRESSION \
+ INTERNAL_CATCH_DEFINE_SIG_TEST(TestFunc,INTERNAL_CATCH_REMOVE_PARENS(Signature))
#ifndef CATCH_CONFIG_TRADITIONAL_MSVC_PREPROCESSOR
#define INTERNAL_CATCH_TEMPLATE_TEST_CASE(Name, Tags, ...) \
- INTERNAL_CATCH_TEMPLATE_TEST_CASE_2( INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_M_P_L_A_T_E____T_E_S_T____ ), INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_M_P_L_A_T_E____T_E_S_T____F_U_N_C____ ), Name, Tags, __VA_ARGS__ )
+ INTERNAL_CATCH_TEMPLATE_TEST_CASE_2( INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_M_P_L_A_T_E____T_E_S_T____ ), INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_M_P_L_A_T_E____T_E_S_T____F_U_N_C____ ), Name, Tags, typename TestType, __VA_ARGS__ )
#else
#define INTERNAL_CATCH_TEMPLATE_TEST_CASE(Name, Tags, ...) \
- INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_TEST_CASE_2( INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_M_P_L_A_T_E____T_E_S_T____ ), INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_M_P_L_A_T_E____T_E_S_T____F_U_N_C____ ), Name, Tags, __VA_ARGS__ ) )
+ INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_TEST_CASE_2( INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_M_P_L_A_T_E____T_E_S_T____ ), INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_M_P_L_A_T_E____T_E_S_T____F_U_N_C____ ), Name, Tags, typename TestType, __VA_ARGS__ ) )
#endif
- #define INTERNAL_CATCH_TEMPLATE_REGISTRY_INITIATE(TestName, Name, ...)\
- static int INTERNAL_CATCH_UNIQUE_NAME( globalRegistrar ) = [](){\
- TestName<CATCH_REC_LIST(INTERNAL_CATCH_REMOVE_PARENS, __VA_ARGS__)>(CATCH_REC_LIST_UD(INTERNAL_CATCH_TEMPLATE_UNIQUE_NAME,Name, __VA_ARGS__));\
- return 0;\
- }();
+#ifndef CATCH_CONFIG_TRADITIONAL_MSVC_PREPROCESSOR
+ #define INTERNAL_CATCH_TEMPLATE_TEST_CASE_SIG(Name, Tags, Signature, ...) \
+ INTERNAL_CATCH_TEMPLATE_TEST_CASE_2( INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_M_P_L_A_T_E____T_E_S_T____ ), INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_M_P_L_A_T_E____T_E_S_T____F_U_N_C____ ), Name, Tags, Signature, __VA_ARGS__ )
+#else
+ #define INTERNAL_CATCH_TEMPLATE_TEST_CASE_SIG(Name, Tags, Signature, ...) \
+ INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_TEST_CASE_2( INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_M_P_L_A_T_E____T_E_S_T____ ), INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_M_P_L_A_T_E____T_E_S_T____F_U_N_C____ ), Name, Tags, Signature, __VA_ARGS__ ) )
+#endif
- #define INTERNAL_CATCH_TEMPLATE_PRODUCT_TEST_CASE2(TestName, TestFuncName, Name, Tags, TmplTypes, TypesList) \
+ #define INTERNAL_CATCH_TEMPLATE_PRODUCT_TEST_CASE2(TestName, TestFuncName, Name, Tags, Signature, TmplTypes, TypesList) \
+ CATCH_INTERNAL_START_WARNINGS_SUPPRESSION \
CATCH_INTERNAL_SUPPRESS_GLOBALS_WARNINGS \
+ CATCH_INTERNAL_SUPPRESS_ZERO_VARIADIC_WARNINGS \
+ CATCH_INTERNAL_SUPPRESS_UNUSED_TEMPLATE_WARNINGS \
template<typename TestType> static void TestFuncName(); \
- namespace { \
+ namespace {\
+ namespace INTERNAL_CATCH_MAKE_NAMESPACE(TestName) { \
+ INTERNAL_CATCH_TYPE_GEN \
+ INTERNAL_CATCH_NTTP_GEN(INTERNAL_CATCH_REMOVE_PARENS(Signature)) \
template<typename... Types> \
struct TestName { \
- TestName() { \
- CATCH_INTERNAL_CHECK_UNIQUE_TYPES(Types...) \
+ void reg_tests() { \
int index = 0; \
using expander = int[]; \
constexpr char const* tmpl_types[] = {CATCH_REC_LIST(INTERNAL_CATCH_STRINGIZE_WITHOUT_PARENS, INTERNAL_CATCH_REMOVE_PARENS(TmplTypes))};\
@@ -962,65 +1144,124 @@ struct AutoReg : NonCopyable {
} \
}; \
static int INTERNAL_CATCH_UNIQUE_NAME( globalRegistrar ) = [](){ \
- using TestInit = Catch::combine<INTERNAL_CATCH_REMOVE_PARENS(TmplTypes)> \
- ::with_types<INTERNAL_CATCH_MAKE_TYPE_LISTS_FROM_TYPES(TypesList)>::into<TestName>::type; \
- TestInit(); \
+ using TestInit = typename create<TestName, decltype(get_wrapper<INTERNAL_CATCH_REMOVE_PARENS(TmplTypes)>()), TypeList<INTERNAL_CATCH_MAKE_TYPE_LISTS_FROM_TYPES(INTERNAL_CATCH_REMOVE_PARENS(TypesList))>>::type; \
+ TestInit t; \
+ t.reg_tests(); \
return 0; \
}(); \
} \
- CATCH_INTERNAL_UNSUPPRESS_GLOBALS_WARNINGS \
+ } \
+ CATCH_INTERNAL_STOP_WARNINGS_SUPPRESSION \
template<typename TestType> \
static void TestFuncName()
#ifndef CATCH_CONFIG_TRADITIONAL_MSVC_PREPROCESSOR
#define INTERNAL_CATCH_TEMPLATE_PRODUCT_TEST_CASE(Name, Tags, ...)\
- INTERNAL_CATCH_TEMPLATE_PRODUCT_TEST_CASE2(INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_M_P_L_A_T_E____T_E_S_T____ ), INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_M_P_L_A_T_E____T_E_S_T____F_U_N_C____ ),Name,Tags,__VA_ARGS__)
+ INTERNAL_CATCH_TEMPLATE_PRODUCT_TEST_CASE2(INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_M_P_L_A_T_E____T_E_S_T____ ), INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_M_P_L_A_T_E____T_E_S_T____F_U_N_C____ ), Name, Tags, typename T,__VA_ARGS__)
#else
#define INTERNAL_CATCH_TEMPLATE_PRODUCT_TEST_CASE(Name, Tags, ...)\
- INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_PRODUCT_TEST_CASE2( INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_M_P_L_A_T_E____T_E_S_T____ ), INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_M_P_L_A_T_E____T_E_S_T____F_U_N_C____ ), Name, Tags, __VA_ARGS__ ) )
+ INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_PRODUCT_TEST_CASE2( INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_M_P_L_A_T_E____T_E_S_T____ ), INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_M_P_L_A_T_E____T_E_S_T____F_U_N_C____ ), Name, Tags, typename T, __VA_ARGS__ ) )
+#endif
+
+#ifndef CATCH_CONFIG_TRADITIONAL_MSVC_PREPROCESSOR
+ #define INTERNAL_CATCH_TEMPLATE_PRODUCT_TEST_CASE_SIG(Name, Tags, Signature, ...)\
+ INTERNAL_CATCH_TEMPLATE_PRODUCT_TEST_CASE2(INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_M_P_L_A_T_E____T_E_S_T____ ), INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_M_P_L_A_T_E____T_E_S_T____F_U_N_C____ ), Name, Tags, Signature, __VA_ARGS__)
+#else
+ #define INTERNAL_CATCH_TEMPLATE_PRODUCT_TEST_CASE_SIG(Name, Tags, Signature, ...)\
+ INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_PRODUCT_TEST_CASE2( INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_M_P_L_A_T_E____T_E_S_T____ ), INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_M_P_L_A_T_E____T_E_S_T____F_U_N_C____ ), Name, Tags, Signature, __VA_ARGS__ ) )
#endif
- #define INTERNAL_CATCH_TEMPLATE_TEST_CASE_METHOD_2( TestNameClass, TestName, ClassName, Name, Tags, ... ) \
+ #define INTERNAL_CATCH_TEMPLATE_LIST_TEST_CASE_2(TestName, TestFunc, Name, Tags, TmplList)\
+ CATCH_INTERNAL_START_WARNINGS_SUPPRESSION \
CATCH_INTERNAL_SUPPRESS_GLOBALS_WARNINGS \
- namespace{ \
- template<typename TestType> \
- struct TestName : INTERNAL_CATCH_REMOVE_PARENS(ClassName <TestType>) { \
- void test();\
- };\
+ CATCH_INTERNAL_SUPPRESS_UNUSED_TEMPLATE_WARNINGS \
+ template<typename TestType> static void TestFunc(); \
+ namespace {\
+ namespace INTERNAL_CATCH_MAKE_NAMESPACE(TestName){\
+ INTERNAL_CATCH_TYPE_GEN\
+ template<typename... Types> \
+ struct TestName { \
+ void reg_tests() { \
+ int index = 0; \
+ using expander = int[]; \
+ (void)expander{(Catch::AutoReg( Catch::makeTestInvoker( &TestFunc<Types> ), CATCH_INTERNAL_LINEINFO, Catch::StringRef(), Catch::NameAndTags{ Name " - " + std::string(INTERNAL_CATCH_STRINGIZE(TmplList)) + " - " + std::to_string(index), Tags } ), index++, 0)... };/* NOLINT */\
+ } \
+ };\
+ static int INTERNAL_CATCH_UNIQUE_NAME( globalRegistrar ) = [](){ \
+ using TestInit = typename convert<TestName, TmplList>::type; \
+ TestInit t; \
+ t.reg_tests(); \
+ return 0; \
+ }(); \
+ }}\
+ CATCH_INTERNAL_STOP_WARNINGS_SUPPRESSION \
+ template<typename TestType> \
+ static void TestFunc()
+
+ #define INTERNAL_CATCH_TEMPLATE_LIST_TEST_CASE(Name, Tags, TmplList) \
+ INTERNAL_CATCH_TEMPLATE_LIST_TEST_CASE_2( INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_M_P_L_A_T_E____T_E_S_T____ ), INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_M_P_L_A_T_E____T_E_S_T____F_U_N_C____ ), Name, Tags, TmplList )
+
+ #define INTERNAL_CATCH_TEMPLATE_TEST_CASE_METHOD_2( TestNameClass, TestName, ClassName, Name, Tags, Signature, ... ) \
+ CATCH_INTERNAL_START_WARNINGS_SUPPRESSION \
+ CATCH_INTERNAL_SUPPRESS_GLOBALS_WARNINGS \
+ CATCH_INTERNAL_SUPPRESS_ZERO_VARIADIC_WARNINGS \
+ CATCH_INTERNAL_SUPPRESS_UNUSED_TEMPLATE_WARNINGS \
+ namespace {\
+ namespace INTERNAL_CATCH_MAKE_NAMESPACE(TestName){ \
+ INTERNAL_CATCH_TYPE_GEN\
+ INTERNAL_CATCH_NTTP_GEN(INTERNAL_CATCH_REMOVE_PARENS(Signature))\
+ INTERNAL_CATCH_DECLARE_SIG_TEST_METHOD(TestName, ClassName, INTERNAL_CATCH_REMOVE_PARENS(Signature));\
+ INTERNAL_CATCH_NTTP_REG_METHOD_GEN(TestName, INTERNAL_CATCH_REMOVE_PARENS(Signature))\
template<typename...Types> \
struct TestNameClass{\
- template<typename...Ts> \
- TestNameClass(Ts...names){\
- CATCH_INTERNAL_CHECK_UNIQUE_TYPES(CATCH_REC_LIST(INTERNAL_CATCH_REMOVE_PARENS, __VA_ARGS__)) \
+ TestNameClass(){\
+ int index = 0; \
+ constexpr char const* tmpl_types[] = {CATCH_REC_LIST(INTERNAL_CATCH_STRINGIZE_WITHOUT_PARENS, __VA_ARGS__)};\
using expander = int[];\
- (void)expander{(Catch::AutoReg( Catch::makeTestInvoker( &TestName<Types>::test ), CATCH_INTERNAL_LINEINFO, #ClassName, Catch::NameAndTags{ names, Tags } ), 0)... };/* NOLINT */ \
+ (void)expander{(reg_test(Types{}, #ClassName, Catch::NameAndTags{ Name " - " + std::string(tmpl_types[index]), Tags } ), index++, 0)... };/* NOLINT */ \
}\
};\
- INTERNAL_CATCH_TEMPLATE_REGISTRY_INITIATE(TestNameClass, Name, __VA_ARGS__)\
+ static int INTERNAL_CATCH_UNIQUE_NAME( globalRegistrar ) = [](){\
+ TestNameClass<INTERNAL_CATCH_MAKE_TYPE_LISTS_FROM_TYPES(__VA_ARGS__)>();\
+ return 0;\
+ }();\
}\
- CATCH_INTERNAL_UNSUPPRESS_GLOBALS_WARNINGS\
- template<typename TestType> \
- void TestName<TestType>::test()
+ }\
+ CATCH_INTERNAL_STOP_WARNINGS_SUPPRESSION \
+ INTERNAL_CATCH_DEFINE_SIG_TEST_METHOD(TestName, INTERNAL_CATCH_REMOVE_PARENS(Signature))
#ifndef CATCH_CONFIG_TRADITIONAL_MSVC_PREPROCESSOR
#define INTERNAL_CATCH_TEMPLATE_TEST_CASE_METHOD( ClassName, Name, Tags,... ) \
- INTERNAL_CATCH_TEMPLATE_TEST_CASE_METHOD_2( INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_M_P_L_A_T_E____T_E_S_T____C_L_A_S_S____ ), INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_M_P_L_A_T_E____T_E_S_T____ ) , ClassName, Name, Tags, __VA_ARGS__ )
+ INTERNAL_CATCH_TEMPLATE_TEST_CASE_METHOD_2( INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_M_P_L_A_T_E____T_E_S_T____C_L_A_S_S____ ), INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_M_P_L_A_T_E____T_E_S_T____ ) , ClassName, Name, Tags, typename T, __VA_ARGS__ )
#else
#define INTERNAL_CATCH_TEMPLATE_TEST_CASE_METHOD( ClassName, Name, Tags,... ) \
- INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_TEST_CASE_METHOD_2( INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_M_P_L_A_T_E____T_E_S_T____C_L_A_S_S____ ), INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_M_P_L_A_T_E____T_E_S_T____ ) , ClassName, Name, Tags, __VA_ARGS__ ) )
+ INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_TEST_CASE_METHOD_2( INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_M_P_L_A_T_E____T_E_S_T____C_L_A_S_S____ ), INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_M_P_L_A_T_E____T_E_S_T____ ) , ClassName, Name, Tags, typename T, __VA_ARGS__ ) )
+#endif
+
+#ifndef CATCH_CONFIG_TRADITIONAL_MSVC_PREPROCESSOR
+ #define INTERNAL_CATCH_TEMPLATE_TEST_CASE_METHOD_SIG( ClassName, Name, Tags, Signature, ... ) \
+ INTERNAL_CATCH_TEMPLATE_TEST_CASE_METHOD_2( INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_M_P_L_A_T_E____T_E_S_T____C_L_A_S_S____ ), INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_M_P_L_A_T_E____T_E_S_T____ ) , ClassName, Name, Tags, Signature, __VA_ARGS__ )
+#else
+ #define INTERNAL_CATCH_TEMPLATE_TEST_CASE_METHOD_SIG( ClassName, Name, Tags, Signature, ... ) \
+ INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_TEST_CASE_METHOD_2( INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_M_P_L_A_T_E____T_E_S_T____C_L_A_S_S____ ), INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_M_P_L_A_T_E____T_E_S_T____ ) , ClassName, Name, Tags, Signature, __VA_ARGS__ ) )
#endif
- #define INTERNAL_CATCH_TEMPLATE_PRODUCT_TEST_CASE_METHOD_2(TestNameClass, TestName, ClassName, Name, Tags, TmplTypes, TypesList)\
+ #define INTERNAL_CATCH_TEMPLATE_PRODUCT_TEST_CASE_METHOD_2(TestNameClass, TestName, ClassName, Name, Tags, Signature, TmplTypes, TypesList)\
+ CATCH_INTERNAL_START_WARNINGS_SUPPRESSION \
CATCH_INTERNAL_SUPPRESS_GLOBALS_WARNINGS \
+ CATCH_INTERNAL_SUPPRESS_ZERO_VARIADIC_WARNINGS \
+ CATCH_INTERNAL_SUPPRESS_UNUSED_TEMPLATE_WARNINGS \
template<typename TestType> \
struct TestName : INTERNAL_CATCH_REMOVE_PARENS(ClassName <TestType>) { \
void test();\
};\
namespace {\
+ namespace INTERNAL_CATCH_MAKE_NAMESPACE(TestNameClass) {\
+ INTERNAL_CATCH_TYPE_GEN \
+ INTERNAL_CATCH_NTTP_GEN(INTERNAL_CATCH_REMOVE_PARENS(Signature))\
template<typename...Types>\
struct TestNameClass{\
- TestNameClass(){\
- CATCH_INTERNAL_CHECK_UNIQUE_TYPES(Types...)\
+ void reg_tests(){\
int index = 0;\
using expander = int[];\
constexpr char const* tmpl_types[] = {CATCH_REC_LIST(INTERNAL_CATCH_STRINGIZE_WITHOUT_PARENS, INTERNAL_CATCH_REMOVE_PARENS(TmplTypes))};\
@@ -1030,24 +1271,66 @@ struct AutoReg : NonCopyable {
}\
};\
static int INTERNAL_CATCH_UNIQUE_NAME( globalRegistrar ) = [](){\
- using TestInit = Catch::combine<INTERNAL_CATCH_REMOVE_PARENS(TmplTypes)>\
- ::with_types<INTERNAL_CATCH_MAKE_TYPE_LISTS_FROM_TYPES(TypesList)>::into<TestNameClass>::type;\
- TestInit();\
+ using TestInit = typename create<TestNameClass, decltype(get_wrapper<INTERNAL_CATCH_REMOVE_PARENS(TmplTypes)>()), TypeList<INTERNAL_CATCH_MAKE_TYPE_LISTS_FROM_TYPES(INTERNAL_CATCH_REMOVE_PARENS(TypesList))>>::type;\
+ TestInit t;\
+ t.reg_tests();\
return 0;\
}(); \
}\
- CATCH_INTERNAL_UNSUPPRESS_GLOBALS_WARNINGS \
+ }\
+ CATCH_INTERNAL_STOP_WARNINGS_SUPPRESSION \
template<typename TestType> \
void TestName<TestType>::test()
#ifndef CATCH_CONFIG_TRADITIONAL_MSVC_PREPROCESSOR
#define INTERNAL_CATCH_TEMPLATE_PRODUCT_TEST_CASE_METHOD( ClassName, Name, Tags, ... )\
- INTERNAL_CATCH_TEMPLATE_PRODUCT_TEST_CASE_METHOD_2( INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_M_P_L_A_T_E____T_E_S_T____ ), INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_M_P_L_A_T_E____T_E_S_T____F_U_N_C____ ), ClassName, Name, Tags, __VA_ARGS__ )
+ INTERNAL_CATCH_TEMPLATE_PRODUCT_TEST_CASE_METHOD_2( INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_M_P_L_A_T_E____T_E_S_T____ ), INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_M_P_L_A_T_E____T_E_S_T____F_U_N_C____ ), ClassName, Name, Tags, typename T, __VA_ARGS__ )
#else
#define INTERNAL_CATCH_TEMPLATE_PRODUCT_TEST_CASE_METHOD( ClassName, Name, Tags, ... )\
- INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_PRODUCT_TEST_CASE_METHOD_2( INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_M_P_L_A_T_E____T_E_S_T____ ), INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_M_P_L_A_T_E____T_E_S_T____F_U_N_C____ ), ClassName, Name, Tags, __VA_ARGS__ ) )
+ INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_PRODUCT_TEST_CASE_METHOD_2( INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_M_P_L_A_T_E____T_E_S_T____ ), INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_M_P_L_A_T_E____T_E_S_T____F_U_N_C____ ), ClassName, Name, Tags, typename T,__VA_ARGS__ ) )
#endif
+#ifndef CATCH_CONFIG_TRADITIONAL_MSVC_PREPROCESSOR
+ #define INTERNAL_CATCH_TEMPLATE_PRODUCT_TEST_CASE_METHOD_SIG( ClassName, Name, Tags, Signature, ... )\
+ INTERNAL_CATCH_TEMPLATE_PRODUCT_TEST_CASE_METHOD_2( INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_M_P_L_A_T_E____T_E_S_T____ ), INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_M_P_L_A_T_E____T_E_S_T____F_U_N_C____ ), ClassName, Name, Tags, Signature, __VA_ARGS__ )
+#else
+ #define INTERNAL_CATCH_TEMPLATE_PRODUCT_TEST_CASE_METHOD_SIG( ClassName, Name, Tags, Signature, ... )\
+ INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_PRODUCT_TEST_CASE_METHOD_2( INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_M_P_L_A_T_E____T_E_S_T____ ), INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_M_P_L_A_T_E____T_E_S_T____F_U_N_C____ ), ClassName, Name, Tags, Signature,__VA_ARGS__ ) )
+#endif
+
+ #define INTERNAL_CATCH_TEMPLATE_LIST_TEST_CASE_METHOD_2( TestNameClass, TestName, ClassName, Name, Tags, TmplList) \
+ CATCH_INTERNAL_START_WARNINGS_SUPPRESSION \
+ CATCH_INTERNAL_SUPPRESS_GLOBALS_WARNINGS \
+ CATCH_INTERNAL_SUPPRESS_UNUSED_TEMPLATE_WARNINGS \
+ template<typename TestType> \
+ struct TestName : INTERNAL_CATCH_REMOVE_PARENS(ClassName <TestType>) { \
+ void test();\
+ };\
+ namespace {\
+ namespace INTERNAL_CATCH_MAKE_NAMESPACE(TestName){ \
+ INTERNAL_CATCH_TYPE_GEN\
+ template<typename...Types>\
+ struct TestNameClass{\
+ void reg_tests(){\
+ int index = 0;\
+ using expander = int[];\
+ (void)expander{(Catch::AutoReg( Catch::makeTestInvoker( &TestName<Types>::test ), CATCH_INTERNAL_LINEINFO, #ClassName, Catch::NameAndTags{ Name " - " + std::string(INTERNAL_CATCH_STRINGIZE(TmplList)) + " - " + std::to_string(index), Tags } ), index++, 0)... };/* NOLINT */ \
+ }\
+ };\
+ static int INTERNAL_CATCH_UNIQUE_NAME( globalRegistrar ) = [](){\
+ using TestInit = typename convert<TestNameClass, TmplList>::type;\
+ TestInit t;\
+ t.reg_tests();\
+ return 0;\
+ }(); \
+ }}\
+ CATCH_INTERNAL_STOP_WARNINGS_SUPPRESSION \
+ template<typename TestType> \
+ void TestName<TestType>::test()
+
+#define INTERNAL_CATCH_TEMPLATE_LIST_TEST_CASE_METHOD(ClassName, Name, Tags, TmplList) \
+ INTERNAL_CATCH_TEMPLATE_LIST_TEST_CASE_METHOD_2( INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_M_P_L_A_T_E____T_E_S_T____ ), INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_M_P_L_A_T_E____T_E_S_T____F_U_N_C____ ), ClassName, Name, Tags, TmplList )
+
// end catch_test_registry.h
// start catch_capture.hpp
@@ -1147,7 +1430,7 @@ namespace Catch {
auto makeStream( StringRef const &filename ) -> IStream const*;
- class ReusableStringStream {
+ class ReusableStringStream : NonCopyable {
std::size_t m_index;
std::ostream* m_oss;
public:
@@ -1166,6 +1449,42 @@ namespace Catch {
}
// end catch_stream.h
+// start catch_interfaces_enum_values_registry.h
+
+#include <vector>
+
+namespace Catch {
+
+ namespace Detail {
+ struct EnumInfo {
+ StringRef m_name;
+ std::vector<std::pair<int, StringRef>> m_values;
+
+ ~EnumInfo();
+
+ StringRef lookup( int value ) const;
+ };
+ } // namespace Detail
+
+ struct IMutableEnumValuesRegistry {
+ virtual ~IMutableEnumValuesRegistry();
+
+ virtual Detail::EnumInfo const& registerEnum( StringRef enumName, StringRef allEnums, std::vector<int> const& values ) = 0;
+
+ template<typename E>
+ Detail::EnumInfo const& registerEnum( StringRef enumName, StringRef allEnums, std::initializer_list<E> values ) {
+ static_assert(sizeof(int) >= sizeof(E), "Cannot serialize enum to int");
+ std::vector<int> intValues;
+ intValues.reserve( values.size() );
+ for( auto enumValue : values )
+ intValues.push_back( static_cast<int>( enumValue ) );
+ return registerEnum( enumName, allEnums, intValues );
+ }
+ };
+
+} // Catch
+
+// end catch_interfaces_enum_values_registry.h
#ifdef CATCH_CONFIG_CPP17_STRING_VIEW
#include <string_view>
@@ -1236,9 +1555,9 @@ namespace Catch {
template<typename T>
class IsStreamInsertable {
- template<typename SS, typename TT>
+ template<typename Stream, typename U>
static auto test(int)
- -> decltype(std::declval<SS&>() << std::declval<TT>(), std::true_type());
+ -> decltype(std::declval<Stream&>() << std::declval<U>(), std::true_type());
template<typename, typename>
static auto test(...)->std::false_type;
@@ -1400,6 +1719,12 @@ namespace Catch {
}
};
+#if defined(CATCH_CONFIG_CPP17_BYTE)
+ template<>
+ struct StringMaker<std::byte> {
+ static std::string convert(std::byte value);
+ };
+#endif // defined(CATCH_CONFIG_CPP17_BYTE)
template<>
struct StringMaker<int> {
static std::string convert(int value);
@@ -1451,10 +1776,13 @@ namespace Catch {
template<>
struct StringMaker<float> {
static std::string convert(float value);
+ static int precision;
};
+
template<>
struct StringMaker<double> {
static std::string convert(double value);
+ static int precision;
};
template <typename T>
@@ -1827,6 +2155,18 @@ struct ratio_string<std::milli> {
}
#endif // CATCH_CONFIG_ENABLE_CHRONO_STRINGMAKER
+#define INTERNAL_CATCH_REGISTER_ENUM( enumName, ... ) \
+namespace Catch { \
+ template<> struct StringMaker<enumName> { \
+ static std::string convert( enumName value ) { \
+ static const auto& enumInfo = ::Catch::getMutableRegistryHub().getMutableEnumValuesRegistry().registerEnum( #enumName, #__VA_ARGS__, { __VA_ARGS__ } ); \
+ return static_cast<std::string>(enumInfo.lookup( static_cast<int>( value ) )); \
+ } \
+ }; \
+}
+
+#define CATCH_REGISTER_ENUM( enumName, ... ) INTERNAL_CATCH_REGISTER_ENUM( enumName, __VA_ARGS__ )
+
#ifdef _MSC_VER
#pragma warning(pop)
#endif
@@ -2066,6 +2406,7 @@ namespace Catch {
// start catch_interfaces_capture.h
#include <string>
+#include <chrono>
namespace Catch {
@@ -2076,14 +2417,18 @@ namespace Catch {
struct MessageInfo;
struct MessageBuilder;
struct Counts;
- struct BenchmarkInfo;
- struct BenchmarkStats;
struct AssertionReaction;
struct SourceLineInfo;
struct ITransientExpression;
struct IGeneratorTracker;
+#if defined(CATCH_CONFIG_ENABLE_BENCHMARKING)
+ struct BenchmarkInfo;
+ template <typename Duration = std::chrono::duration<double, std::nano>>
+ struct BenchmarkStats;
+#endif // CATCH_CONFIG_ENABLE_BENCHMARKING
+
struct IResultCapture {
virtual ~IResultCapture();
@@ -2095,8 +2440,12 @@ namespace Catch {
virtual auto acquireGeneratorTracker( SourceLineInfo const& lineInfo ) -> IGeneratorTracker& = 0;
+#if defined(CATCH_CONFIG_ENABLE_BENCHMARKING)
+ virtual void benchmarkPreparing( std::string const& name ) = 0;
virtual void benchmarkStarting( BenchmarkInfo const& info ) = 0;
- virtual void benchmarkEnded( BenchmarkStats const& stats ) = 0;
+ virtual void benchmarkEnded( BenchmarkStats<> const& stats ) = 0;
+ virtual void benchmarkFailed( std::string const& error ) = 0;
+#endif // CATCH_CONFIG_ENABLE_BENCHMARKING
virtual void pushScopedMessage( MessageInfo const& message ) = 0;
virtual void popScopedMessage( MessageInfo const& message ) = 0;
@@ -2327,15 +2676,16 @@ namespace Catch {
///////////////////////////////////////////////////////////////////////////////
#define INTERNAL_CATCH_TEST( macroName, resultDisposition, ... ) \
do { \
+ CATCH_INTERNAL_IGNORE_BUT_WARN(__VA_ARGS__); \
Catch::AssertionHandler catchAssertionHandler( macroName##_catch_sr, CATCH_INTERNAL_LINEINFO, CATCH_INTERNAL_STRINGIFY(__VA_ARGS__), resultDisposition ); \
INTERNAL_CATCH_TRY { \
+ CATCH_INTERNAL_START_WARNINGS_SUPPRESSION \
CATCH_INTERNAL_SUPPRESS_PARENTHESES_WARNINGS \
catchAssertionHandler.handleExpr( Catch::Decomposer() <= __VA_ARGS__ ); \
- CATCH_INTERNAL_UNSUPPRESS_PARENTHESES_WARNINGS \
+ CATCH_INTERNAL_STOP_WARNINGS_SUPPRESSION \
} INTERNAL_CATCH_CATCH( catchAssertionHandler ) \
INTERNAL_CATCH_REACT( catchAssertionHandler ) \
- } while( (void)0, (false) && static_cast<bool>( !!(__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 &&.
+ } while( false )
///////////////////////////////////////////////////////////////////////////////
#define INTERNAL_CATCH_IF( macroName, resultDisposition, ... ) \
@@ -2552,62 +2902,18 @@ namespace Catch {
} // end namespace Catch
#define INTERNAL_CATCH_SECTION( ... ) \
+ CATCH_INTERNAL_START_WARNINGS_SUPPRESSION \
CATCH_INTERNAL_SUPPRESS_UNUSED_WARNINGS \
if( Catch::Section const& INTERNAL_CATCH_UNIQUE_NAME( catch_internal_Section ) = Catch::SectionInfo( CATCH_INTERNAL_LINEINFO, __VA_ARGS__ ) ) \
- CATCH_INTERNAL_UNSUPPRESS_UNUSED_WARNINGS
+ CATCH_INTERNAL_STOP_WARNINGS_SUPPRESSION
#define INTERNAL_CATCH_DYNAMIC_SECTION( ... ) \
+ CATCH_INTERNAL_START_WARNINGS_SUPPRESSION \
CATCH_INTERNAL_SUPPRESS_UNUSED_WARNINGS \
if( Catch::Section const& INTERNAL_CATCH_UNIQUE_NAME( catch_internal_Section ) = Catch::SectionInfo( CATCH_INTERNAL_LINEINFO, (Catch::ReusableStringStream() << __VA_ARGS__).str() ) ) \
- CATCH_INTERNAL_UNSUPPRESS_UNUSED_WARNINGS
+ CATCH_INTERNAL_STOP_WARNINGS_SUPPRESSION
// end catch_section.h
-// start catch_benchmark.h
-
-#include <cstdint>
-#include <string>
-
-namespace Catch {
-
- class BenchmarkLooper {
-
- std::string m_name;
- std::size_t m_count = 0;
- std::size_t m_iterationsToRun = 1;
- uint64_t m_resolution;
- Timer m_timer;
-
- static auto getResolution() -> uint64_t;
- public:
- // Keep most of this inline as it's on the code path that is being timed
- BenchmarkLooper( StringRef name )
- : m_name( name ),
- m_resolution( getResolution() )
- {
- reportStart();
- m_timer.start();
- }
-
- explicit operator bool() {
- if( m_count < m_iterationsToRun )
- return true;
- return needsMoreIterations();
- }
-
- void increment() {
- ++m_count;
- }
-
- void reportStart();
- auto needsMoreIterations() -> bool;
- };
-
-} // end namespace Catch
-
-#define BENCHMARK( name ) \
- for( Catch::BenchmarkLooper looper( name ); looper; looper.increment() )
-
-// end catch_benchmark.h
// start catch_interfaces_exception.h
// start catch_interfaces_registry_hub.h
@@ -2624,6 +2930,8 @@ namespace Catch {
struct IReporterRegistry;
struct IReporterFactory;
struct ITagAliasRegistry;
+ struct IMutableEnumValuesRegistry;
+
class StartupExceptionRegistry;
using IReporterFactoryPtr = std::shared_ptr<IReporterFactory>;
@@ -2634,7 +2942,6 @@ namespace Catch {
virtual IReporterRegistry const& getReporterRegistry() const = 0;
virtual ITestCaseRegistry const& getTestCaseRegistry() const = 0;
virtual ITagAliasRegistry const& getTagAliasRegistry() const = 0;
-
virtual IExceptionTranslatorRegistry const& getExceptionTranslatorRegistry() const = 0;
virtual StartupExceptionRegistry const& getStartupExceptionRegistry() const = 0;
@@ -2648,6 +2955,7 @@ namespace Catch {
virtual void registerTranslator( const IExceptionTranslator* translator ) = 0;
virtual void registerTagAlias( std::string const& alias, std::string const& tag, SourceLineInfo const& lineInfo ) = 0;
virtual void registerStartupException() noexcept = 0;
+ virtual IMutableEnumValuesRegistry& getMutableEnumValuesRegistry() = 0;
};
IRegistryHub const& getRegistryHub();
@@ -2721,9 +3029,10 @@ namespace Catch {
///////////////////////////////////////////////////////////////////////////////
#define INTERNAL_CATCH_TRANSLATE_EXCEPTION2( translatorName, signature ) \
static std::string translatorName( signature ); \
+ CATCH_INTERNAL_START_WARNINGS_SUPPRESSION \
CATCH_INTERNAL_SUPPRESS_GLOBALS_WARNINGS \
namespace{ Catch::ExceptionTranslatorRegistrar INTERNAL_CATCH_UNIQUE_NAME( catch_internal_ExceptionRegistrar )( &translatorName ); } \
- CATCH_INTERNAL_UNSUPPRESS_GLOBALS_WARNINGS \
+ CATCH_INTERNAL_STOP_WARNINGS_SUPPRESSION \
static std::string translatorName( signature )
#define INTERNAL_CATCH_TRANSLATE_EXCEPTION( signature ) INTERNAL_CATCH_TRANSLATE_EXCEPTION2( INTERNAL_CATCH_UNIQUE_NAME( catch_internal_ExceptionTranslator ), signature )
@@ -2854,6 +3163,7 @@ struct StringMaker<Catch::Detail::Approx> {
#include <string>
#include <iosfwd>
+#include <vector>
namespace Catch {
@@ -2864,7 +3174,13 @@ namespace Catch {
bool contains( std::string const& s, std::string const& infix );
void toLowerInPlace( std::string& s );
std::string toLower( std::string const& s );
+ //! Returns a new string without whitespace at the start/end
std::string trim( std::string const& str );
+ //! Returns a substring of the original ref without whitespace. Beware lifetimes!
+ StringRef trim(StringRef ref);
+
+ // !!! Be aware, returns refs into original string - make sure original string outlives them
+ std::vector<StringRef> splitStringRef( StringRef str, char delimiter );
bool replaceInPlace( std::string& str, std::string const& replaceThis, std::string const& withThis );
struct pluralise {
@@ -2917,6 +3233,15 @@ namespace Matchers {
virtual bool match( ObjectT const& arg ) const = 0;
};
+#if defined(__OBJC__)
+ // Hack to fix Catch GH issue #1661. Could use id for generic Object support.
+ // use of const for Object pointers is very uncommon and under ARC it causes some kind of signature mismatch that breaks compilation
+ template<>
+ struct MatcherMethod<NSString*> {
+ virtual bool match( NSString* arg ) const = 0;
+ };
+#endif
+
#ifdef __clang__
# pragma clang diagnostic pop
#endif
@@ -2954,9 +3279,10 @@ namespace Matchers {
return description;
}
- MatchAllOf<ArgT>& operator && ( MatcherBase<ArgT> const& other ) {
- m_matchers.push_back( &other );
- return *this;
+ MatchAllOf<ArgT> operator && ( MatcherBase<ArgT> const& other ) {
+ auto copy(*this);
+ copy.m_matchers.push_back( &other );
+ return copy;
}
std::vector<MatcherBase<ArgT> const*> m_matchers;
@@ -2987,9 +3313,10 @@ namespace Matchers {
return description;
}
- MatchAnyOf<ArgT>& operator || ( MatcherBase<ArgT> const& other ) {
- m_matchers.push_back( &other );
- return *this;
+ MatchAnyOf<ArgT> operator || ( MatcherBase<ArgT> const& other ) {
+ auto copy(*this);
+ copy.m_matchers.push_back( &other );
+ return copy;
}
std::vector<MatcherBase<ArgT> const*> m_matchers;
@@ -3033,10 +3360,34 @@ using Matchers::Impl::MatcherBase;
} // namespace Catch
// end catch_matchers.h
-// start catch_matchers_floating.h
+// start catch_matchers_exception.hpp
-#include <type_traits>
-#include <cmath>
+namespace Catch {
+namespace Matchers {
+namespace Exception {
+
+class ExceptionMessageMatcher : public MatcherBase<std::exception> {
+ std::string m_message;
+public:
+
+ ExceptionMessageMatcher(std::string const& message):
+ m_message(message)
+ {}
+
+ bool match(std::exception const& ex) const override;
+
+ std::string describe() const override;
+};
+
+} // namespace Exception
+
+Exception::ExceptionMessageMatcher Message(std::string const& message);
+
+} // namespace Matchers
+} // namespace Catch
+
+// end catch_matchers_exception.hpp
+// start catch_matchers_floating.h
namespace Catch {
namespace Matchers {
@@ -3055,22 +3406,43 @@ namespace Matchers {
};
struct WithinUlpsMatcher : MatcherBase<double> {
- WithinUlpsMatcher(double target, int ulps, FloatingPointKind baseType);
+ WithinUlpsMatcher(double target, uint64_t ulps, FloatingPointKind baseType);
bool match(double const& matchee) const override;
std::string describe() const override;
private:
double m_target;
- int m_ulps;
+ uint64_t m_ulps;
FloatingPointKind m_type;
};
+ // Given IEEE-754 format for floats and doubles, we can assume
+ // that float -> double promotion is lossless. Given this, we can
+ // assume that if we do the standard relative comparison of
+ // |lhs - rhs| <= epsilon * max(fabs(lhs), fabs(rhs)), then we get
+ // the same result if we do this for floats, as if we do this for
+ // doubles that were promoted from floats.
+ struct WithinRelMatcher : MatcherBase<double> {
+ WithinRelMatcher(double target, double epsilon);
+ bool match(double const& matchee) const override;
+ std::string describe() const override;
+ private:
+ double m_target;
+ double m_epsilon;
+ };
+
} // 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::WithinUlpsMatcher WithinULP(double target, uint64_t maxUlpDiff);
+ Floating::WithinUlpsMatcher WithinULP(float target, uint64_t maxUlpDiff);
Floating::WithinAbsMatcher WithinAbs(double target, double margin);
+ Floating::WithinRelMatcher WithinRel(double target, double eps);
+ // defaults epsilon to 100*numeric_limits<double>::epsilon()
+ Floating::WithinRelMatcher WithinRel(double target);
+ Floating::WithinRelMatcher WithinRel(float target, float eps);
+ // defaults epsilon to 100*numeric_limits<float>::epsilon()
+ Floating::WithinRelMatcher WithinRel(float target);
} // namespace Matchers
} // namespace Catch
@@ -3468,7 +3840,7 @@ namespace Catch {
// end catch_interfaces_generatortracker.h
// start catch_enforce.h
-#include <stdexcept>
+#include <exception>
namespace Catch {
#if !defined(CATCH_CONFIG_DISABLE_EXCEPTIONS)
@@ -3481,18 +3853,30 @@ namespace Catch {
[[noreturn]]
void throw_exception(std::exception const& e);
#endif
+
+ [[noreturn]]
+ void throw_logic_error(std::string const& msg);
+ [[noreturn]]
+ void throw_domain_error(std::string const& msg);
+ [[noreturn]]
+ void throw_runtime_error(std::string const& msg);
+
} // namespace Catch;
-#define CATCH_PREPARE_EXCEPTION( type, msg ) \
- type( ( Catch::ReusableStringStream() << msg ).str() )
-#define CATCH_INTERNAL_ERROR( msg ) \
- Catch::throw_exception(CATCH_PREPARE_EXCEPTION( std::logic_error, CATCH_INTERNAL_LINEINFO << ": Internal Catch error: " << msg))
-#define CATCH_ERROR( msg ) \
- Catch::throw_exception(CATCH_PREPARE_EXCEPTION( std::domain_error, msg ))
-#define CATCH_RUNTIME_ERROR( msg ) \
- Catch::throw_exception(CATCH_PREPARE_EXCEPTION( std::runtime_error, msg ))
-#define CATCH_ENFORCE( condition, msg ) \
- do{ if( !(condition) ) CATCH_ERROR( msg ); } while(false)
+#define CATCH_MAKE_MSG(...) \
+ (Catch::ReusableStringStream() << __VA_ARGS__).str()
+
+#define CATCH_INTERNAL_ERROR(...) \
+ Catch::throw_logic_error(CATCH_MAKE_MSG( CATCH_INTERNAL_LINEINFO << ": Internal Catch2 error: " << __VA_ARGS__))
+
+#define CATCH_ERROR(...) \
+ Catch::throw_domain_error(CATCH_MAKE_MSG( __VA_ARGS__ ))
+
+#define CATCH_RUNTIME_ERROR(...) \
+ Catch::throw_runtime_error(CATCH_MAKE_MSG( __VA_ARGS__ ))
+
+#define CATCH_ENFORCE( condition, ... ) \
+ do{ if( !(condition) ) CATCH_ERROR( __VA_ARGS__ ); } while(false)
// end catch_enforce.h
#include <memory>
@@ -3541,7 +3925,6 @@ namespace Generators {
class SingleValueGenerator final : public IGenerator<T> {
T m_value;
public:
- SingleValueGenerator(T const& value) : m_value( value ) {}
SingleValueGenerator(T&& value) : m_value(std::move(value)) {}
T const& get() const override {
@@ -3554,6 +3937,9 @@ namespace Generators {
template<typename T>
class FixedValuesGenerator final : public IGenerator<T> {
+ static_assert(!std::is_same<T, bool>::value,
+ "FixedValuesGenerator does not support bools because of std::vector<bool>"
+ "specialization, use SingleValue Generator instead.");
std::vector<T> m_values;
size_t m_idx = 0;
public:
@@ -3601,21 +3987,21 @@ namespace Generators {
m_generators.emplace_back(std::move(generator));
}
void populate(T&& val) {
- m_generators.emplace_back(value(std::move(val)));
+ m_generators.emplace_back(value(std::forward<T>(val)));
}
template<typename U>
void populate(U&& val) {
- populate(T(std::move(val)));
+ populate(T(std::forward<U>(val)));
}
template<typename U, typename... Gs>
- void populate(U&& valueOrGenerator, Gs... moreGenerators) {
+ void populate(U&& valueOrGenerator, Gs &&... moreGenerators) {
populate(std::forward<U>(valueOrGenerator));
populate(std::forward<Gs>(moreGenerators)...);
}
public:
template <typename... Gs>
- Generators(Gs... moreGenerators) {
+ Generators(Gs &&... moreGenerators) {
m_generators.reserve(sizeof...(Gs));
populate(std::forward<Gs>(moreGenerators)...);
}
@@ -3646,7 +4032,7 @@ namespace Generators {
struct as {};
template<typename T, typename... Gs>
- auto makeGenerators( GeneratorWrapper<T>&& generator, Gs... moreGenerators ) -> Generators<T> {
+ auto makeGenerators( GeneratorWrapper<T>&& generator, Gs &&... moreGenerators ) -> Generators<T> {
return Generators<T>(std::move(generator), std::forward<Gs>(moreGenerators)...);
}
template<typename T>
@@ -3654,11 +4040,11 @@ namespace Generators {
return Generators<T>(std::move(generator));
}
template<typename T, typename... Gs>
- auto makeGenerators( T&& val, Gs... moreGenerators ) -> Generators<T> {
+ auto makeGenerators( T&& val, Gs &&... moreGenerators ) -> Generators<T> {
return makeGenerators( value( std::forward<T>( val ) ), std::forward<Gs>( moreGenerators )... );
}
template<typename T, typename U, typename... Gs>
- auto makeGenerators( as<T>, U&& val, Gs... moreGenerators ) -> Generators<T> {
+ auto makeGenerators( as<T>, U&& val, Gs &&... moreGenerators ) -> Generators<T> {
return makeGenerators( value( T( std::forward<U>( val ) ) ), std::forward<Gs>( moreGenerators )... );
}
@@ -3684,11 +4070,11 @@ namespace Generators {
} // namespace Catch
#define GENERATE( ... ) \
- Catch::Generators::generate( CATCH_INTERNAL_LINEINFO, [ ]{ using namespace Catch::Generators; return makeGenerators( __VA_ARGS__ ); } )
+ Catch::Generators::generate( CATCH_INTERNAL_LINEINFO, [ ]{ using namespace Catch::Generators; return makeGenerators( __VA_ARGS__ ); } ) //NOLINT(google-build-using-namespace)
#define GENERATE_COPY( ... ) \
- Catch::Generators::generate( CATCH_INTERNAL_LINEINFO, [=]{ using namespace Catch::Generators; return makeGenerators( __VA_ARGS__ ); } )
+ Catch::Generators::generate( CATCH_INTERNAL_LINEINFO, [=]{ using namespace Catch::Generators; return makeGenerators( __VA_ARGS__ ); } ) //NOLINT(google-build-using-namespace)
#define GENERATE_REF( ... ) \
- Catch::Generators::generate( CATCH_INTERNAL_LINEINFO, [&]{ using namespace Catch::Generators; return makeGenerators( __VA_ARGS__ ); } )
+ Catch::Generators::generate( CATCH_INTERNAL_LINEINFO, [&]{ using namespace Catch::Generators; return makeGenerators( __VA_ARGS__ ); } ) //NOLINT(google-build-using-namespace)
// end catch_generators.hpp
// start catch_generators_generic.hpp
@@ -3773,6 +4159,9 @@ namespace Generators {
template <typename T>
class RepeatGenerator : public IGenerator<T> {
+ static_assert(!std::is_same<T, bool>::value,
+ "RepeatGenerator currently does not support bools"
+ "because of std::vector<bool> specialization");
GeneratorWrapper<T> m_generator;
mutable std::vector<T> m_returned;
size_t m_target_repeats;
@@ -3851,18 +4240,7 @@ namespace Generators {
}
};
-#if defined(__cpp_lib_is_invocable) && __cpp_lib_is_invocable >= 201703
- // std::result_of is deprecated in C++17 and removed in C++20. Hence, it is
- // replaced with std::invoke_result here. Also *_t format is preferred over
- // typename *::type format.
- template <typename Func, typename U>
- using MapFunctionReturnType = std::remove_reference_t<std::remove_cv_t<std::invoke_result_t<Func, U>>>;
-#else
- template <typename Func, typename U>
- using MapFunctionReturnType = typename std::remove_reference<typename std::remove_cv<typename std::result_of<Func(U)>::type>::type>::type;
-#endif
-
- template <typename Func, typename U, typename T = MapFunctionReturnType<Func, U>>
+ template <typename Func, typename U, typename T = FunctionReturnType<Func, U>>
GeneratorWrapper<T> map(Func&& function, GeneratorWrapper<U>&& generator) {
return GeneratorWrapper<T>(
pf::make_unique<MapGenerator<T, U, Func>>(std::forward<Func>(function), std::move(generator))
@@ -3887,12 +4265,14 @@ namespace Generators {
m_chunk_size(size), m_generator(std::move(generator))
{
m_chunk.reserve(m_chunk_size);
- m_chunk.push_back(m_generator.get());
- for (size_t i = 1; i < m_chunk_size; ++i) {
- if (!m_generator.next()) {
- Catch::throw_exception(GeneratorException("Not enough values to initialize the first chunk"));
- }
+ if (m_chunk_size != 0) {
m_chunk.push_back(m_generator.get());
+ for (size_t i = 1; i < m_chunk_size; ++i) {
+ if (!m_generator.next()) {
+ Catch::throw_exception(GeneratorException("Not enough values to initialize the first chunk"));
+ }
+ m_chunk.push_back(m_generator.get());
+ }
}
}
std::vector<T> const& get() const override {
@@ -3963,6 +4343,7 @@ namespace Catch {
{
if( !IMutableContext::currentContext )
IMutableContext::createContext();
+ // NOLINTNEXTLINE(clang-analyzer-core.uninitialized.UndefReturn)
return *IMutableContext::currentContext;
}
@@ -3972,11 +4353,80 @@ namespace Catch {
}
void cleanUpContext();
+
+ class SimplePcg32;
+ SimplePcg32& rng();
}
// end catch_context.h
// start catch_interfaces_config.h
+// start catch_option.hpp
+
+namespace Catch {
+
+ // An optional type
+ template<typename T>
+ class Option {
+ public:
+ Option() : nullableValue( nullptr ) {}
+ Option( T const& _value )
+ : nullableValue( new( storage ) T( _value ) )
+ {}
+ Option( Option const& _other )
+ : nullableValue( _other ? new( storage ) T( *_other ) : nullptr )
+ {}
+
+ ~Option() {
+ reset();
+ }
+
+ Option& operator= ( Option const& _other ) {
+ if( &_other != this ) {
+ reset();
+ if( _other )
+ nullableValue = new( storage ) T( *_other );
+ }
+ return *this;
+ }
+ Option& operator = ( T const& _value ) {
+ reset();
+ nullableValue = new( storage ) T( _value );
+ return *this;
+ }
+
+ void reset() {
+ if( nullableValue )
+ nullableValue->~T();
+ nullableValue = nullptr;
+ }
+
+ T& operator*() { return *nullableValue; }
+ T const& operator*() const { return *nullableValue; }
+ T* operator->() { return nullableValue; }
+ const T* operator->() const { return nullableValue; }
+
+ T valueOr( T const& defaultValue ) const {
+ return nullableValue ? *nullableValue : defaultValue;
+ }
+
+ bool some() const { return nullableValue != nullptr; }
+ bool none() const { return nullableValue == nullptr; }
+
+ bool operator !() const { return nullableValue == nullptr; }
+ explicit operator bool() const {
+ return some();
+ }
+
+ private:
+ T *nullableValue;
+ alignas(alignof(T)) char storage[sizeof(T)];
+ };
+
+} // end namespace Catch
+
+// end catch_option.hpp
+#include <chrono>
#include <iosfwd>
#include <string>
#include <vector>
@@ -4039,16 +4489,71 @@ namespace Catch {
virtual std::vector<std::string> const& getTestsOrTags() const = 0;
virtual RunTests::InWhatOrder runOrder() const = 0;
virtual unsigned int rngSeed() const = 0;
- virtual int benchmarkResolutionMultiple() const = 0;
virtual UseColour::YesOrNo useColour() const = 0;
virtual std::vector<std::string> const& getSectionsToRun() const = 0;
virtual Verbosity verbosity() const = 0;
+
+ virtual bool benchmarkNoAnalysis() const = 0;
+ virtual int benchmarkSamples() const = 0;
+ virtual double benchmarkConfidenceInterval() const = 0;
+ virtual unsigned int benchmarkResamples() const = 0;
+ virtual std::chrono::milliseconds benchmarkWarmupTime() const = 0;
};
using IConfigPtr = std::shared_ptr<IConfig const>;
}
// end catch_interfaces_config.h
+// start catch_random_number_generator.h
+
+#include <cstdint>
+
+namespace Catch {
+
+ // This is a simple implementation of C++11 Uniform Random Number
+ // Generator. It does not provide all operators, because Catch2
+ // does not use it, but it should behave as expected inside stdlib's
+ // distributions.
+ // The implementation is based on the PCG family (http://pcg-random.org)
+ class SimplePcg32 {
+ using state_type = std::uint64_t;
+ public:
+ using result_type = std::uint32_t;
+ static constexpr result_type (min)() {
+ return 0;
+ }
+ static constexpr result_type (max)() {
+ return static_cast<result_type>(-1);
+ }
+
+ // Provide some default initial state for the default constructor
+ SimplePcg32():SimplePcg32(0xed743cc4U) {}
+
+ explicit SimplePcg32(result_type seed_);
+
+ void seed(result_type seed_);
+ void discard(uint64_t skip);
+
+ result_type operator()();
+
+ private:
+ friend bool operator==(SimplePcg32 const& lhs, SimplePcg32 const& rhs);
+ friend bool operator!=(SimplePcg32 const& lhs, SimplePcg32 const& rhs);
+
+ // In theory we also need operator<< and operator>>
+ // In practice we do not use them, so we will skip them for now
+
+ std::uint64_t m_state;
+ // This part of the state determines which "stream" of the numbers
+ // is chosen -- we take it as a constant for Catch2, so we only
+ // need to deal with seeding the main state.
+ // Picked by reading 8 bytes from `/dev/random` :-)
+ static const std::uint64_t s_inc = (0x13ed0cc53f939476ULL << 1ULL) | 1ULL;
+ };
+
+} // end namespace Catch
+
+// end catch_random_number_generator.h
#include <random>
namespace Catch {
@@ -4056,14 +4561,13 @@ namespace Generators {
template <typename Float>
class RandomFloatingGenerator final : public IGenerator<Float> {
- // FIXME: What is the right seed?
- std::minstd_rand m_rand;
+ Catch::SimplePcg32& m_rng;
std::uniform_real_distribution<Float> m_dist;
Float m_current_number;
public:
RandomFloatingGenerator(Float a, Float b):
- m_rand(getCurrentContext().getConfig()->rngSeed()),
+ m_rng(rng()),
m_dist(a, b) {
static_cast<void>(next());
}
@@ -4072,20 +4576,20 @@ public:
return m_current_number;
}
bool next() override {
- m_current_number = m_dist(m_rand);
+ m_current_number = m_dist(m_rng);
return true;
}
};
template <typename Integer>
class RandomIntegerGenerator final : public IGenerator<Integer> {
- std::minstd_rand m_rand;
+ Catch::SimplePcg32& m_rng;
std::uniform_int_distribution<Integer> m_dist;
Integer m_current_number;
public:
RandomIntegerGenerator(Integer a, Integer b):
- m_rand(getCurrentContext().getConfig()->rngSeed()),
+ m_rng(rng()),
m_dist(a, b) {
static_cast<void>(next());
}
@@ -4094,7 +4598,7 @@ public:
return m_current_number;
}
bool next() override {
- m_current_number = m_dist(m_rand);
+ m_current_number = m_dist(m_rng);
return true;
}
};
@@ -4154,7 +4658,7 @@ public:
template <typename T>
GeneratorWrapper<T> range(T const& start, T const& end, T const& step) {
- static_assert(std::is_integral<T>::value && !std::is_same<T, bool>::value, "Type must be an integer");
+ static_assert(std::is_arithmetic<T>::value && !std::is_same<T, bool>::value, "Type must be numeric");
return GeneratorWrapper<T>(pf::make_unique<RangeGenerator<T>>(start, end, step));
}
@@ -4164,6 +4668,45 @@ GeneratorWrapper<T> range(T const& start, T const& end) {
return GeneratorWrapper<T>(pf::make_unique<RangeGenerator<T>>(start, end));
}
+template <typename T>
+class IteratorGenerator final : public IGenerator<T> {
+ static_assert(!std::is_same<T, bool>::value,
+ "IteratorGenerator currently does not support bools"
+ "because of std::vector<bool> specialization");
+
+ std::vector<T> m_elems;
+ size_t m_current = 0;
+public:
+ template <typename InputIterator, typename InputSentinel>
+ IteratorGenerator(InputIterator first, InputSentinel last):m_elems(first, last) {
+ if (m_elems.empty()) {
+ Catch::throw_exception(GeneratorException("IteratorGenerator received no valid values"));
+ }
+ }
+
+ T const& get() const override {
+ return m_elems[m_current];
+ }
+
+ bool next() override {
+ ++m_current;
+ return m_current != m_elems.size();
+ }
+};
+
+template <typename InputIterator,
+ typename InputSentinel,
+ typename ResultType = typename std::iterator_traits<InputIterator>::value_type>
+GeneratorWrapper<ResultType> from_range(InputIterator from, InputSentinel to) {
+ return GeneratorWrapper<ResultType>(pf::make_unique<IteratorGenerator<ResultType>>(from, to));
+}
+
+template <typename Container,
+ typename ResultType = typename Container::value_type>
+GeneratorWrapper<ResultType> from_range(Container const& cnt) {
+ return GeneratorWrapper<ResultType>(pf::make_unique<IteratorGenerator<ResultType>>(cnt.begin(), cnt.end()));
+}
+
} // namespace Generators
} // namespace Catch
@@ -4367,7 +4910,7 @@ namespace Catch {
arcSafeRelease( m_substr );
}
- bool match( NSString* const& str ) const override {
+ bool match( NSString* str ) const override {
return false;
}
@@ -4377,7 +4920,7 @@ namespace Catch {
struct Equals : StringHolder {
Equals( NSString* substr ) : StringHolder( substr ){}
- bool match( NSString* const& str ) const override {
+ bool match( NSString* str ) const override {
return (str != nil || m_substr == nil ) &&
[str isEqualToString:m_substr];
}
@@ -4390,7 +4933,7 @@ namespace Catch {
struct Contains : StringHolder {
Contains( NSString* substr ) : StringHolder( substr ){}
- bool match( NSString* const& str ) const override {
+ bool match( NSString* str ) const override {
return (str != nil || m_substr == nil ) &&
[str rangeOfString:m_substr].location != NSNotFound;
}
@@ -4403,7 +4946,7 @@ namespace Catch {
struct StartsWith : StringHolder {
StartsWith( NSString* substr ) : StringHolder( substr ){}
- bool match( NSString* const& str ) const override {
+ bool match( NSString* str ) const override {
return (str != nil || m_substr == nil ) &&
[str rangeOfString:m_substr].location == 0;
}
@@ -4415,7 +4958,7 @@ namespace Catch {
struct EndsWith : StringHolder {
EndsWith( NSString* substr ) : StringHolder( substr ){}
- bool match( NSString* const& str ) const override {
+ bool match( NSString* str ) const override {
return (str != nil || m_substr == nil ) &&
[str rangeOfString:m_substr].location == [str length] - [m_substr length];
}
@@ -4466,7 +5009,8 @@ return @ desc; \
// end catch_objc.hpp
#endif
-#ifdef CATCH_CONFIG_EXTERNAL_INTERFACES
+// Benchmarking needs the externally-facing parts of reporters to work
+#if defined(CATCH_CONFIG_EXTERNAL_INTERFACES) || defined(CATCH_CONFIG_ENABLE_BENCHMARKING)
// start catch_external_interfaces.h
// start catch_reporter_bases.hpp
@@ -4508,7 +5052,7 @@ namespace Catch
virtual bool matches( std::string const& str ) const;
private:
- std::string adjustCase( std::string const& str ) const;
+ std::string normaliseString( std::string const& str ) const;
CaseSensitive::Choice m_caseSensitivity;
WildcardPosition m_wildcard = NoWildcard;
std::string m_pattern;
@@ -4522,17 +5066,23 @@ namespace Catch
namespace Catch {
+ struct IConfig;
+
class TestSpec {
- struct Pattern {
+ class Pattern {
+ public:
+ explicit Pattern( std::string const& name );
virtual ~Pattern();
virtual bool matches( TestCaseInfo const& testCase ) const = 0;
+ std::string const& name() const;
+ private:
+ std::string const m_name;
};
using PatternPtr = std::shared_ptr<Pattern>;
class NamePattern : public Pattern {
public:
- NamePattern( std::string const& name );
- virtual ~NamePattern();
+ explicit NamePattern( std::string const& name, std::string const& filterString );
bool matches( TestCaseInfo const& testCase ) const override;
private:
WildcardPattern m_wildcardPattern;
@@ -4540,8 +5090,7 @@ namespace Catch {
class TagPattern : public Pattern {
public:
- TagPattern( std::string const& tag );
- virtual ~TagPattern();
+ explicit TagPattern( std::string const& tag, std::string const& filterString );
bool matches( TestCaseInfo const& testCase ) const override;
private:
std::string m_tag;
@@ -4549,8 +5098,7 @@ namespace Catch {
class ExcludedPattern : public Pattern {
public:
- ExcludedPattern( PatternPtr const& underlyingPattern );
- virtual ~ExcludedPattern();
+ explicit ExcludedPattern( PatternPtr const& underlyingPattern );
bool matches( TestCaseInfo const& testCase ) const override;
private:
PatternPtr m_underlyingPattern;
@@ -4560,15 +5108,25 @@ namespace Catch {
std::vector<PatternPtr> m_patterns;
bool matches( TestCaseInfo const& testCase ) const;
+ std::string name() const;
};
public:
+ struct FilterMatch {
+ std::string name;
+ std::vector<TestCase const*> tests;
+ };
+ using Matches = std::vector<FilterMatch>;
+ using vectorStrings = std::vector<std::string>;
+
bool hasFilters() const;
bool matches( TestCaseInfo const& testCase ) const;
+ Matches matchesByFilter( std::vector<TestCase> const& testCases, IConfig const& config ) const;
+ const vectorStrings & getInvalidArgs() const;
private:
std::vector<Filter> m_filters;
-
+ std::vector<std::string> m_invalidArgs;
friend class TestSpecParser;
};
}
@@ -4603,9 +5161,13 @@ namespace Catch {
class TestSpecParser {
enum Mode{ None, Name, QuotedName, Tag, EscapedName };
Mode m_mode = None;
+ Mode lastMode = None;
bool m_exclusion = false;
- std::size_t m_start = std::string::npos, m_pos = 0;
+ std::size_t m_pos = 0;
+ std::size_t m_realPatternPos = 0;
std::string m_arg;
+ std::string m_substring;
+ std::string m_patternName;
std::vector<std::size_t> m_escapeChars;
TestSpec::Filter m_currentFilter;
TestSpec m_testSpec;
@@ -4618,32 +5180,32 @@ namespace Catch {
TestSpec testSpec();
private:
- void visitChar( char c );
- void startNewMode( Mode mode, std::size_t start );
+ bool visitChar( char c );
+ void startNewMode( Mode mode );
+ bool processNoneChar( char c );
+ void processNameChar( char c );
+ bool processOtherChar( char c );
+ void endMode();
void escape();
- std::string subString() const;
+ bool isControlChar( char c ) const;
+ void saveLastMode();
+ void revertBackToLastMode();
+ void addFilter();
+ bool separate();
- template<typename T>
- void addPattern() {
- std::string token = subString();
- for( std::size_t i = 0; i < m_escapeChars.size(); ++i )
- token = token.substr( 0, m_escapeChars[i]-m_start-i ) + token.substr( m_escapeChars[i]-m_start-i+1 );
- m_escapeChars.clear();
- if( startsWith( token, "exclude:" ) ) {
- m_exclusion = true;
- token = token.substr( 8 );
- }
- if( !token.empty() ) {
- TestSpec::PatternPtr pattern = std::make_shared<T>( token );
- if( m_exclusion )
- pattern = std::make_shared<TestSpec::ExcludedPattern>( pattern );
- m_currentFilter.m_patterns.push_back( pattern );
- }
- m_exclusion = false;
- m_mode = None;
+ // Handles common preprocessing of the pattern for name/tag patterns
+ std::string preprocessPattern();
+ // Adds the current pattern as a test name
+ void addNamePattern();
+ // Adds the current pattern as a tag
+ void addTagPattern();
+
+ inline void addCharToPattern(char c) {
+ m_substring += c;
+ m_patternName += c;
+ m_realPatternPos++;
}
- void addFilter();
};
TestSpec parseTestSpec( std::string const& arg );
@@ -4684,7 +5246,12 @@ namespace Catch {
int abortAfter = -1;
unsigned int rngSeed = 0;
- int benchmarkResolutionMultiple = 100;
+
+ bool benchmarkNoAnalysis = false;
+ unsigned int benchmarkSamples = 100;
+ double benchmarkConfidenceInterval = 0.95;
+ unsigned int benchmarkResamples = 100000;
+ std::chrono::milliseconds::rep benchmarkWarmupTime = 100;
Verbosity verbosity = Verbosity::Normal;
WarnAbout::What warnings = WarnAbout::Nothing;
@@ -4741,12 +5308,16 @@ namespace Catch {
ShowDurations::OrNot showDurations() const override;
RunTests::InWhatOrder runOrder() const override;
unsigned int rngSeed() const override;
- int benchmarkResolutionMultiple() const override;
UseColour::YesOrNo useColour() const override;
bool shouldDebugBreak() const override;
int abortAfter() const override;
bool showInvisibles() const override;
Verbosity verbosity() const override;
+ bool benchmarkNoAnalysis() const override;
+ int benchmarkSamples() const override;
+ double benchmarkConfidenceInterval() const override;
+ unsigned int benchmarkResamples() const override;
+ std::chrono::milliseconds benchmarkWarmupTime() const override;
private:
@@ -4807,76 +5378,59 @@ namespace Catch {
} // end namespace Catch
// end catch_assertionresult.h
-// start catch_option.hpp
-
-namespace Catch {
+#if defined(CATCH_CONFIG_ENABLE_BENCHMARKING)
+// start catch_estimate.hpp
- // An optional type
- template<typename T>
- class Option {
- public:
- Option() : nullableValue( nullptr ) {}
- Option( T const& _value )
- : nullableValue( new( storage ) T( _value ) )
- {}
- Option( Option const& _other )
- : nullableValue( _other ? new( storage ) T( *_other ) : nullptr )
- {}
+ // Statistics estimates
- ~Option() {
- reset();
- }
- Option& operator= ( Option const& _other ) {
- if( &_other != this ) {
- reset();
- if( _other )
- nullableValue = new( storage ) T( *_other );
+namespace Catch {
+ namespace Benchmark {
+ template <typename Duration>
+ struct Estimate {
+ Duration point;
+ Duration lower_bound;
+ Duration upper_bound;
+ double confidence_interval;
+
+ template <typename Duration2>
+ operator Estimate<Duration2>() const {
+ return { point, lower_bound, upper_bound, confidence_interval };
}
- return *this;
- }
- Option& operator = ( T const& _value ) {
- reset();
- nullableValue = new( storage ) T( _value );
- return *this;
- }
-
- void reset() {
- if( nullableValue )
- nullableValue->~T();
- nullableValue = nullptr;
- }
-
- T& operator*() { return *nullableValue; }
- T const& operator*() const { return *nullableValue; }
- T* operator->() { return nullableValue; }
- const T* operator->() const { return nullableValue; }
-
- T valueOr( T const& defaultValue ) const {
- return nullableValue ? *nullableValue : defaultValue;
- }
+ };
+ } // namespace Benchmark
+} // namespace Catch
- bool some() const { return nullableValue != nullptr; }
- bool none() const { return nullableValue == nullptr; }
+// end catch_estimate.hpp
+// start catch_outlier_classification.hpp
- bool operator !() const { return nullableValue == nullptr; }
- explicit operator bool() const {
- return some();
- }
+// Outlier information
- private:
- T *nullableValue;
- alignas(alignof(T)) char storage[sizeof(T)];
- };
+namespace Catch {
+ namespace Benchmark {
+ struct OutlierClassification {
+ int samples_seen = 0;
+ int low_severe = 0; // more than 3 times IQR below Q1
+ int low_mild = 0; // 1.5 to 3 times IQR below Q1
+ int high_mild = 0; // 1.5 to 3 times IQR above Q3
+ int high_severe = 0; // more than 3 times IQR above Q3
+
+ int total() const {
+ return low_severe + low_mild + high_mild + high_severe;
+ }
+ };
+ } // namespace Benchmark
+} // namespace Catch
-} // end namespace Catch
+// end catch_outlier_classification.hpp
+#endif // CATCH_CONFIG_ENABLE_BENCHMARKING
-// end catch_option.hpp
#include <string>
#include <iosfwd>
#include <map>
#include <set>
#include <memory>
+#include <algorithm>
namespace Catch {
@@ -5012,14 +5566,43 @@ namespace Catch {
bool aborting;
};
+#if defined(CATCH_CONFIG_ENABLE_BENCHMARKING)
struct BenchmarkInfo {
std::string name;
+ double estimatedDuration;
+ int iterations;
+ int samples;
+ unsigned int resamples;
+ double clockResolution;
+ double clockCost;
};
+
+ template <class Duration>
struct BenchmarkStats {
BenchmarkInfo info;
- std::size_t iterations;
- uint64_t elapsedTimeInNanoseconds;
+
+ std::vector<Duration> samples;
+ Benchmark::Estimate<Duration> mean;
+ Benchmark::Estimate<Duration> standardDeviation;
+ Benchmark::OutlierClassification outliers;
+ double outlierVariance;
+
+ template <typename Duration2>
+ operator BenchmarkStats<Duration2>() const {
+ std::vector<Duration2> samples2;
+ samples2.reserve(samples.size());
+ std::transform(samples.begin(), samples.end(), std::back_inserter(samples2), [](Duration d) { return Duration2(d); });
+ return {
+ info,
+ std::move(samples2),
+ mean,
+ standardDeviation,
+ outliers,
+ outlierVariance,
+ };
+ }
};
+#endif // CATCH_CONFIG_ENABLE_BENCHMARKING
struct IStreamingReporter {
virtual ~IStreamingReporter() = default;
@@ -5032,23 +5615,26 @@ namespace Catch {
virtual void noMatchingTestCases( std::string const& spec ) = 0;
+ virtual void reportInvalidArguments(std::string const&) {}
+
virtual void testRunStarting( TestRunInfo const& testRunInfo ) = 0;
virtual void testGroupStarting( GroupInfo const& groupInfo ) = 0;
virtual void testCaseStarting( TestCaseInfo const& testInfo ) = 0;
virtual void sectionStarting( SectionInfo const& sectionInfo ) = 0;
- // *** experimental ***
+#if defined(CATCH_CONFIG_ENABLE_BENCHMARKING)
+ virtual void benchmarkPreparing( std::string const& ) {}
virtual void benchmarkStarting( BenchmarkInfo const& ) {}
+ virtual void benchmarkEnded( BenchmarkStats<> const& ) {}
+ virtual void benchmarkFailed( std::string const& ) {}
+#endif // CATCH_CONFIG_ENABLE_BENCHMARKING
virtual void assertionStarting( AssertionInfo const& assertionInfo ) = 0;
// The return value indicates if the messages buffer should be cleared:
virtual bool assertionEnded( AssertionStats const& assertionStats ) = 0;
- // *** experimental ***
- virtual void benchmarkEnded( BenchmarkStats const& ) {}
-
virtual void sectionEnded( SectionStats const& sectionStats ) = 0;
virtual void testCaseEnded( TestCaseStats const& testCaseStats ) = 0;
virtual void testGroupEnded( TestGroupStats const& testGroupStats ) = 0;
@@ -5123,6 +5709,8 @@ namespace Catch {
void noMatchingTestCases(std::string const&) override {}
+ void reportInvalidArguments(std::string const&) override {}
+
void testRunStarting(TestRunInfo const& _testRunInfo) override {
currentTestRunInfo = _testRunInfo;
}
@@ -5457,14 +6045,16 @@ namespace Catch {
#if !defined(CATCH_CONFIG_DISABLE)
#define CATCH_REGISTER_REPORTER( name, reporterType ) \
+ CATCH_INTERNAL_START_WARNINGS_SUPPRESSION \
CATCH_INTERNAL_SUPPRESS_GLOBALS_WARNINGS \
namespace{ Catch::ReporterRegistrar<reporterType> catch_internal_RegistrarFor##reporterType( name ); } \
- CATCH_INTERNAL_UNSUPPRESS_GLOBALS_WARNINGS
+ CATCH_INTERNAL_STOP_WARNINGS_SUPPRESSION
#define CATCH_REGISTER_LISTENER( listenerType ) \
- CATCH_INTERNAL_SUPPRESS_GLOBALS_WARNINGS \
- namespace{ Catch::ListenerRegistrar<listenerType> catch_internal_RegistrarFor##listenerType; } \
- CATCH_INTERNAL_SUPPRESS_GLOBALS_WARNINGS
+ CATCH_INTERNAL_START_WARNINGS_SUPPRESSION \
+ CATCH_INTERNAL_SUPPRESS_GLOBALS_WARNINGS \
+ namespace{ Catch::ListenerRegistrar<listenerType> catch_internal_RegistrarFor##listenerType; } \
+ CATCH_INTERNAL_STOP_WARNINGS_SUPPRESSION
#else // CATCH_CONFIG_DISABLE
#define CATCH_REGISTER_REPORTER(name, reporterType)
@@ -5526,6 +6116,8 @@ namespace Catch {
void noMatchingTestCases(std::string const& spec) override;
+ void reportInvalidArguments(std::string const&arg) override;
+
void assertionStarting(AssertionInfo const&) override;
bool assertionEnded(AssertionStats const& _assertionStats) override;
@@ -5533,8 +6125,12 @@ namespace Catch {
void sectionStarting(SectionInfo const& _sectionInfo) override;
void sectionEnded(SectionStats const& _sectionStats) override;
+#if defined(CATCH_CONFIG_ENABLE_BENCHMARKING)
+ void benchmarkPreparing(std::string const& name) override;
void benchmarkStarting(BenchmarkInfo const& info) override;
- void benchmarkEnded(BenchmarkStats const& stats) override;
+ void benchmarkEnded(BenchmarkStats<> const& stats) override;
+ void benchmarkFailed(std::string const& error) override;
+#endif // CATCH_CONFIG_ENABLE_BENCHMARKING
void testCaseEnded(TestCaseStats const& _testCaseStats) override;
void testGroupEnded(TestGroupStats const& _testGroupStats) override;
@@ -5581,6 +6177,14 @@ namespace Catch {
#include <vector>
namespace Catch {
+ enum class XmlFormatting {
+ None = 0x00,
+ Indent = 0x01,
+ Newline = 0x02,
+ };
+
+ XmlFormatting operator | (XmlFormatting lhs, XmlFormatting rhs);
+ XmlFormatting operator & (XmlFormatting lhs, XmlFormatting rhs);
class XmlEncode {
public:
@@ -5602,14 +6206,14 @@ namespace Catch {
class ScopedElement {
public:
- ScopedElement( XmlWriter* writer );
+ ScopedElement( XmlWriter* writer, XmlFormatting fmt );
ScopedElement( ScopedElement&& other ) noexcept;
ScopedElement& operator=( ScopedElement&& other ) noexcept;
~ScopedElement();
- ScopedElement& writeText( std::string const& text, bool indent = true );
+ ScopedElement& writeText( std::string const& text, XmlFormatting fmt = XmlFormatting::Newline | XmlFormatting::Indent );
template<typename T>
ScopedElement& writeAttribute( std::string const& name, T const& attribute ) {
@@ -5619,6 +6223,7 @@ namespace Catch {
private:
mutable XmlWriter* m_writer = nullptr;
+ XmlFormatting m_fmt;
};
XmlWriter( std::ostream& os = Catch::cout() );
@@ -5627,11 +6232,11 @@ namespace Catch {
XmlWriter( XmlWriter const& ) = delete;
XmlWriter& operator=( XmlWriter const& ) = delete;
- XmlWriter& startElement( std::string const& name );
+ XmlWriter& startElement( std::string const& name, XmlFormatting fmt = XmlFormatting::Newline | XmlFormatting::Indent);
- ScopedElement scopedElement( std::string const& name );
+ ScopedElement scopedElement( std::string const& name, XmlFormatting fmt = XmlFormatting::Newline | XmlFormatting::Indent);
- XmlWriter& endElement();
+ XmlWriter& endElement(XmlFormatting fmt = XmlFormatting::Newline | XmlFormatting::Indent);
XmlWriter& writeAttribute( std::string const& name, std::string const& attribute );
@@ -5644,9 +6249,9 @@ namespace Catch {
return writeAttribute( name, rss.str() );
}
- XmlWriter& writeText( std::string const& text, bool indent = true );
+ XmlWriter& writeText( std::string const& text, XmlFormatting fmt = XmlFormatting::Newline | XmlFormatting::Indent);
- XmlWriter& writeComment( std::string const& text );
+ XmlWriter& writeComment(std::string const& text, XmlFormatting fmt = XmlFormatting::Newline | XmlFormatting::Indent);
void writeStylesheetRef( std::string const& url );
@@ -5656,6 +6261,8 @@ namespace Catch {
private:
+ void applyFormatting(XmlFormatting fmt);
+
void writeDeclaration();
void newlineIfNecessary();
@@ -5756,6 +6363,13 @@ namespace Catch {
void testRunEnded(TestRunStats const& testRunStats) override;
+#if defined(CATCH_CONFIG_ENABLE_BENCHMARKING)
+ void benchmarkPreparing(std::string const& name) override;
+ void benchmarkStarting(BenchmarkInfo const&) override;
+ void benchmarkEnded(BenchmarkStats<> const&) override;
+ void benchmarkFailed(std::string const&) override;
+#endif // CATCH_CONFIG_ENABLE_BENCHMARKING
+
private:
Timer m_testCaseTimer;
XmlWriter m_xml;
@@ -5769,6 +6383,1031 @@ namespace Catch {
// end catch_external_interfaces.h
#endif
+#if defined(CATCH_CONFIG_ENABLE_BENCHMARKING)
+// start catch_benchmarking_all.hpp
+
+// A proxy header that includes all of the benchmarking headers to allow
+// concise include of the benchmarking features. You should prefer the
+// individual includes in standard use.
+
+// start catch_benchmark.hpp
+
+ // Benchmark
+
+// start catch_chronometer.hpp
+
+// User-facing chronometer
+
+
+// start catch_clock.hpp
+
+// Clocks
+
+
+#include <chrono>
+#include <ratio>
+
+namespace Catch {
+ namespace Benchmark {
+ template <typename Clock>
+ using ClockDuration = typename Clock::duration;
+ template <typename Clock>
+ using FloatDuration = std::chrono::duration<double, typename Clock::period>;
+
+ template <typename Clock>
+ using TimePoint = typename Clock::time_point;
+
+ using default_clock = std::chrono::steady_clock;
+
+ template <typename Clock>
+ struct now {
+ TimePoint<Clock> operator()() const {
+ return Clock::now();
+ }
+ };
+
+ using fp_seconds = std::chrono::duration<double, std::ratio<1>>;
+ } // namespace Benchmark
+} // namespace Catch
+
+// end catch_clock.hpp
+// start catch_optimizer.hpp
+
+ // Hinting the optimizer
+
+
+#if defined(_MSC_VER)
+# include <atomic> // atomic_thread_fence
+#endif
+
+namespace Catch {
+ namespace Benchmark {
+#if defined(__GNUC__) || defined(__clang__)
+ template <typename T>
+ inline void keep_memory(T* p) {
+ asm volatile("" : : "g"(p) : "memory");
+ }
+ inline void keep_memory() {
+ asm volatile("" : : : "memory");
+ }
+
+ namespace Detail {
+ inline void optimizer_barrier() { keep_memory(); }
+ } // namespace Detail
+#elif defined(_MSC_VER)
+
+#pragma optimize("", off)
+ template <typename T>
+ inline void keep_memory(T* p) {
+ // thanks @milleniumbug
+ *reinterpret_cast<char volatile*>(p) = *reinterpret_cast<char const volatile*>(p);
+ }
+ // TODO equivalent keep_memory()
+#pragma optimize("", on)
+
+ namespace Detail {
+ inline void optimizer_barrier() {
+ std::atomic_thread_fence(std::memory_order_seq_cst);
+ }
+ } // namespace Detail
+
+#endif
+
+ template <typename T>
+ inline void deoptimize_value(T&& x) {
+ keep_memory(&x);
+ }
+
+ template <typename Fn, typename... Args>
+ inline auto invoke_deoptimized(Fn&& fn, Args&&... args) -> typename std::enable_if<!std::is_same<void, decltype(fn(args...))>::value>::type {
+ deoptimize_value(std::forward<Fn>(fn) (std::forward<Args...>(args...)));
+ }
+
+ template <typename Fn, typename... Args>
+ inline auto invoke_deoptimized(Fn&& fn, Args&&... args) -> typename std::enable_if<std::is_same<void, decltype(fn(args...))>::value>::type {
+ std::forward<Fn>(fn) (std::forward<Args...>(args...));
+ }
+ } // namespace Benchmark
+} // namespace Catch
+
+// end catch_optimizer.hpp
+// start catch_complete_invoke.hpp
+
+// Invoke with a special case for void
+
+
+#include <type_traits>
+#include <utility>
+
+namespace Catch {
+ namespace Benchmark {
+ namespace Detail {
+ template <typename T>
+ struct CompleteType { using type = T; };
+ template <>
+ struct CompleteType<void> { struct type {}; };
+
+ template <typename T>
+ using CompleteType_t = typename CompleteType<T>::type;
+
+ template <typename Result>
+ struct CompleteInvoker {
+ template <typename Fun, typename... Args>
+ static Result invoke(Fun&& fun, Args&&... args) {
+ return std::forward<Fun>(fun)(std::forward<Args>(args)...);
+ }
+ };
+ template <>
+ struct CompleteInvoker<void> {
+ template <typename Fun, typename... Args>
+ static CompleteType_t<void> invoke(Fun&& fun, Args&&... args) {
+ std::forward<Fun>(fun)(std::forward<Args>(args)...);
+ return {};
+ }
+ };
+ template <typename Sig>
+ using ResultOf_t = typename std::result_of<Sig>::type;
+
+ // invoke and not return void :(
+ template <typename Fun, typename... Args>
+ CompleteType_t<ResultOf_t<Fun(Args...)>> complete_invoke(Fun&& fun, Args&&... args) {
+ return CompleteInvoker<ResultOf_t<Fun(Args...)>>::invoke(std::forward<Fun>(fun), std::forward<Args>(args)...);
+ }
+
+ const std::string benchmarkErrorMsg = "a benchmark failed to run successfully";
+ } // namespace Detail
+
+ template <typename Fun>
+ Detail::CompleteType_t<Detail::ResultOf_t<Fun()>> user_code(Fun&& fun) {
+ CATCH_TRY{
+ return Detail::complete_invoke(std::forward<Fun>(fun));
+ } CATCH_CATCH_ALL{
+ getResultCapture().benchmarkFailed(translateActiveException());
+ CATCH_RUNTIME_ERROR(Detail::benchmarkErrorMsg);
+ }
+ }
+ } // namespace Benchmark
+} // namespace Catch
+
+// end catch_complete_invoke.hpp
+namespace Catch {
+ namespace Benchmark {
+ namespace Detail {
+ struct ChronometerConcept {
+ virtual void start() = 0;
+ virtual void finish() = 0;
+ virtual ~ChronometerConcept() = default;
+ };
+ template <typename Clock>
+ struct ChronometerModel final : public ChronometerConcept {
+ void start() override { started = Clock::now(); }
+ void finish() override { finished = Clock::now(); }
+
+ ClockDuration<Clock> elapsed() const { return finished - started; }
+
+ TimePoint<Clock> started;
+ TimePoint<Clock> finished;
+ };
+ } // namespace Detail
+
+ struct Chronometer {
+ public:
+ template <typename Fun>
+ void measure(Fun&& fun) { measure(std::forward<Fun>(fun), is_callable<Fun(int)>()); }
+
+ int runs() const { return k; }
+
+ Chronometer(Detail::ChronometerConcept& meter, int k)
+ : impl(&meter)
+ , k(k) {}
+
+ private:
+ template <typename Fun>
+ void measure(Fun&& fun, std::false_type) {
+ measure([&fun](int) { return fun(); }, std::true_type());
+ }
+
+ template <typename Fun>
+ void measure(Fun&& fun, std::true_type) {
+ Detail::optimizer_barrier();
+ impl->start();
+ for (int i = 0; i < k; ++i) invoke_deoptimized(fun, i);
+ impl->finish();
+ Detail::optimizer_barrier();
+ }
+
+ Detail::ChronometerConcept* impl;
+ int k;
+ };
+ } // namespace Benchmark
+} // namespace Catch
+
+// end catch_chronometer.hpp
+// start catch_environment.hpp
+
+// Environment information
+
+
+namespace Catch {
+ namespace Benchmark {
+ template <typename Duration>
+ struct EnvironmentEstimate {
+ Duration mean;
+ OutlierClassification outliers;
+
+ template <typename Duration2>
+ operator EnvironmentEstimate<Duration2>() const {
+ return { mean, outliers };
+ }
+ };
+ template <typename Clock>
+ struct Environment {
+ using clock_type = Clock;
+ EnvironmentEstimate<FloatDuration<Clock>> clock_resolution;
+ EnvironmentEstimate<FloatDuration<Clock>> clock_cost;
+ };
+ } // namespace Benchmark
+} // namespace Catch
+
+// end catch_environment.hpp
+// start catch_execution_plan.hpp
+
+ // Execution plan
+
+
+// start catch_benchmark_function.hpp
+
+ // Dumb std::function implementation for consistent call overhead
+
+
+#include <cassert>
+#include <type_traits>
+#include <utility>
+#include <memory>
+
+namespace Catch {
+ namespace Benchmark {
+ namespace Detail {
+ template <typename T>
+ using Decay = typename std::decay<T>::type;
+ template <typename T, typename U>
+ struct is_related
+ : std::is_same<Decay<T>, Decay<U>> {};
+
+ /// We need to reinvent std::function because every piece of code that might add overhead
+ /// in a measurement context needs to have consistent performance characteristics so that we
+ /// can account for it in the measurement.
+ /// Implementations of std::function with optimizations that aren't always applicable, like
+ /// small buffer optimizations, are not uncommon.
+ /// This is effectively an implementation of std::function without any such optimizations;
+ /// it may be slow, but it is consistently slow.
+ struct BenchmarkFunction {
+ private:
+ struct callable {
+ virtual void call(Chronometer meter) const = 0;
+ virtual callable* clone() const = 0;
+ virtual ~callable() = default;
+ };
+ template <typename Fun>
+ struct model : public callable {
+ model(Fun&& fun) : fun(std::move(fun)) {}
+ model(Fun const& fun) : fun(fun) {}
+
+ model<Fun>* clone() const override { return new model<Fun>(*this); }
+
+ void call(Chronometer meter) const override {
+ call(meter, is_callable<Fun(Chronometer)>());
+ }
+ void call(Chronometer meter, std::true_type) const {
+ fun(meter);
+ }
+ void call(Chronometer meter, std::false_type) const {
+ meter.measure(fun);
+ }
+
+ Fun fun;
+ };
+
+ struct do_nothing { void operator()() const {} };
+
+ template <typename T>
+ BenchmarkFunction(model<T>* c) : f(c) {}
+
+ public:
+ BenchmarkFunction()
+ : f(new model<do_nothing>{ {} }) {}
+
+ template <typename Fun,
+ typename std::enable_if<!is_related<Fun, BenchmarkFunction>::value, int>::type = 0>
+ BenchmarkFunction(Fun&& fun)
+ : f(new model<typename std::decay<Fun>::type>(std::forward<Fun>(fun))) {}
+
+ BenchmarkFunction(BenchmarkFunction&& that)
+ : f(std::move(that.f)) {}
+
+ BenchmarkFunction(BenchmarkFunction const& that)
+ : f(that.f->clone()) {}
+
+ BenchmarkFunction& operator=(BenchmarkFunction&& that) {
+ f = std::move(that.f);
+ return *this;
+ }
+
+ BenchmarkFunction& operator=(BenchmarkFunction const& that) {
+ f.reset(that.f->clone());
+ return *this;
+ }
+
+ void operator()(Chronometer meter) const { f->call(meter); }
+
+ private:
+ std::unique_ptr<callable> f;
+ };
+ } // namespace Detail
+ } // namespace Benchmark
+} // namespace Catch
+
+// end catch_benchmark_function.hpp
+// start catch_repeat.hpp
+
+// repeat algorithm
+
+
+#include <type_traits>
+#include <utility>
+
+namespace Catch {
+ namespace Benchmark {
+ namespace Detail {
+ template <typename Fun>
+ struct repeater {
+ void operator()(int k) const {
+ for (int i = 0; i < k; ++i) {
+ fun();
+ }
+ }
+ Fun fun;
+ };
+ template <typename Fun>
+ repeater<typename std::decay<Fun>::type> repeat(Fun&& fun) {
+ return { std::forward<Fun>(fun) };
+ }
+ } // namespace Detail
+ } // namespace Benchmark
+} // namespace Catch
+
+// end catch_repeat.hpp
+// start catch_run_for_at_least.hpp
+
+// Run a function for a minimum amount of time
+
+
+// start catch_measure.hpp
+
+// Measure
+
+
+// start catch_timing.hpp
+
+// Timing
+
+
+#include <tuple>
+#include <type_traits>
+
+namespace Catch {
+ namespace Benchmark {
+ template <typename Duration, typename Result>
+ struct Timing {
+ Duration elapsed;
+ Result result;
+ int iterations;
+ };
+ template <typename Clock, typename Sig>
+ using TimingOf = Timing<ClockDuration<Clock>, Detail::CompleteType_t<Detail::ResultOf_t<Sig>>>;
+ } // namespace Benchmark
+} // namespace Catch
+
+// end catch_timing.hpp
+#include <utility>
+
+namespace Catch {
+ namespace Benchmark {
+ namespace Detail {
+ template <typename Clock, typename Fun, typename... Args>
+ TimingOf<Clock, Fun(Args...)> measure(Fun&& fun, Args&&... args) {
+ auto start = Clock::now();
+ auto&& r = Detail::complete_invoke(fun, std::forward<Args>(args)...);
+ auto end = Clock::now();
+ auto delta = end - start;
+ return { delta, std::forward<decltype(r)>(r), 1 };
+ }
+ } // namespace Detail
+ } // namespace Benchmark
+} // namespace Catch
+
+// end catch_measure.hpp
+#include <utility>
+#include <type_traits>
+
+namespace Catch {
+ namespace Benchmark {
+ namespace Detail {
+ template <typename Clock, typename Fun>
+ TimingOf<Clock, Fun(int)> measure_one(Fun&& fun, int iters, std::false_type) {
+ return Detail::measure<Clock>(fun, iters);
+ }
+ template <typename Clock, typename Fun>
+ TimingOf<Clock, Fun(Chronometer)> measure_one(Fun&& fun, int iters, std::true_type) {
+ Detail::ChronometerModel<Clock> meter;
+ auto&& result = Detail::complete_invoke(fun, Chronometer(meter, iters));
+
+ return { meter.elapsed(), std::move(result), iters };
+ }
+
+ template <typename Clock, typename Fun>
+ using run_for_at_least_argument_t = typename std::conditional<is_callable<Fun(Chronometer)>::value, Chronometer, int>::type;
+
+ struct optimized_away_error : std::exception {
+ const char* what() const noexcept override {
+ return "could not measure benchmark, maybe it was optimized away";
+ }
+ };
+
+ template <typename Clock, typename Fun>
+ TimingOf<Clock, Fun(run_for_at_least_argument_t<Clock, Fun>)> run_for_at_least(ClockDuration<Clock> how_long, int seed, Fun&& fun) {
+ auto iters = seed;
+ while (iters < (1 << 30)) {
+ auto&& Timing = measure_one<Clock>(fun, iters, is_callable<Fun(Chronometer)>());
+
+ if (Timing.elapsed >= how_long) {
+ return { Timing.elapsed, std::move(Timing.result), iters };
+ }
+ iters *= 2;
+ }
+ throw optimized_away_error{};
+ }
+ } // namespace Detail
+ } // namespace Benchmark
+} // namespace Catch
+
+// end catch_run_for_at_least.hpp
+#include <algorithm>
+
+namespace Catch {
+ namespace Benchmark {
+ template <typename Duration>
+ struct ExecutionPlan {
+ int iterations_per_sample;
+ Duration estimated_duration;
+ Detail::BenchmarkFunction benchmark;
+ Duration warmup_time;
+ int warmup_iterations;
+
+ template <typename Duration2>
+ operator ExecutionPlan<Duration2>() const {
+ return { iterations_per_sample, estimated_duration, benchmark, warmup_time, warmup_iterations };
+ }
+
+ template <typename Clock>
+ std::vector<FloatDuration<Clock>> run(const IConfig &cfg, Environment<FloatDuration<Clock>> env) const {
+ // warmup a bit
+ Detail::run_for_at_least<Clock>(std::chrono::duration_cast<ClockDuration<Clock>>(warmup_time), warmup_iterations, Detail::repeat(now<Clock>{}));
+
+ std::vector<FloatDuration<Clock>> times;
+ times.reserve(cfg.benchmarkSamples());
+ std::generate_n(std::back_inserter(times), cfg.benchmarkSamples(), [this, env] {
+ Detail::ChronometerModel<Clock> model;
+ this->benchmark(Chronometer(model, iterations_per_sample));
+ auto sample_time = model.elapsed() - env.clock_cost.mean;
+ if (sample_time < FloatDuration<Clock>::zero()) sample_time = FloatDuration<Clock>::zero();
+ return sample_time / iterations_per_sample;
+ });
+ return times;
+ }
+ };
+ } // namespace Benchmark
+} // namespace Catch
+
+// end catch_execution_plan.hpp
+// start catch_estimate_clock.hpp
+
+ // Environment measurement
+
+
+// start catch_stats.hpp
+
+// Statistical analysis tools
+
+
+#include <algorithm>
+#include <functional>
+#include <vector>
+#include <iterator>
+#include <numeric>
+#include <tuple>
+#include <cmath>
+#include <utility>
+#include <cstddef>
+#include <random>
+
+namespace Catch {
+ namespace Benchmark {
+ namespace Detail {
+ using sample = std::vector<double>;
+
+ double weighted_average_quantile(int k, int q, std::vector<double>::iterator first, std::vector<double>::iterator last);
+
+ template <typename Iterator>
+ OutlierClassification classify_outliers(Iterator first, Iterator last) {
+ std::vector<double> copy(first, last);
+
+ auto q1 = weighted_average_quantile(1, 4, copy.begin(), copy.end());
+ auto q3 = weighted_average_quantile(3, 4, copy.begin(), copy.end());
+ auto iqr = q3 - q1;
+ auto los = q1 - (iqr * 3.);
+ auto lom = q1 - (iqr * 1.5);
+ auto him = q3 + (iqr * 1.5);
+ auto his = q3 + (iqr * 3.);
+
+ OutlierClassification o;
+ for (; first != last; ++first) {
+ auto&& t = *first;
+ if (t < los) ++o.low_severe;
+ else if (t < lom) ++o.low_mild;
+ else if (t > his) ++o.high_severe;
+ else if (t > him) ++o.high_mild;
+ ++o.samples_seen;
+ }
+ return o;
+ }
+
+ template <typename Iterator>
+ double mean(Iterator first, Iterator last) {
+ auto count = last - first;
+ double sum = std::accumulate(first, last, 0.);
+ return sum / count;
+ }
+
+ template <typename URng, typename Iterator, typename Estimator>
+ sample resample(URng& rng, int resamples, Iterator first, Iterator last, Estimator& estimator) {
+ auto n = last - first;
+ std::uniform_int_distribution<decltype(n)> dist(0, n - 1);
+
+ sample out;
+ out.reserve(resamples);
+ std::generate_n(std::back_inserter(out), resamples, [n, first, &estimator, &dist, &rng] {
+ std::vector<double> resampled;
+ resampled.reserve(n);
+ std::generate_n(std::back_inserter(resampled), n, [first, &dist, &rng] { return first[dist(rng)]; });
+ return estimator(resampled.begin(), resampled.end());
+ });
+ std::sort(out.begin(), out.end());
+ return out;
+ }
+
+ template <typename Estimator, typename Iterator>
+ sample jackknife(Estimator&& estimator, Iterator first, Iterator last) {
+ auto n = last - first;
+ auto second = std::next(first);
+ sample results;
+ results.reserve(n);
+
+ for (auto it = first; it != last; ++it) {
+ std::iter_swap(it, first);
+ results.push_back(estimator(second, last));
+ }
+
+ return results;
+ }
+
+ inline double normal_cdf(double x) {
+ return std::erfc(-x / std::sqrt(2.0)) / 2.0;
+ }
+
+ double erfc_inv(double x);
+
+ double normal_quantile(double p);
+
+ template <typename Iterator, typename Estimator>
+ Estimate<double> bootstrap(double confidence_level, Iterator first, Iterator last, sample const& resample, Estimator&& estimator) {
+ auto n_samples = last - first;
+
+ double point = estimator(first, last);
+ // Degenerate case with a single sample
+ if (n_samples == 1) return { point, point, point, confidence_level };
+
+ sample jack = jackknife(estimator, first, last);
+ double jack_mean = mean(jack.begin(), jack.end());
+ double sum_squares, sum_cubes;
+ std::tie(sum_squares, sum_cubes) = std::accumulate(jack.begin(), jack.end(), std::make_pair(0., 0.), [jack_mean](std::pair<double, double> sqcb, double x) -> std::pair<double, double> {
+ auto d = jack_mean - x;
+ auto d2 = d * d;
+ auto d3 = d2 * d;
+ return { sqcb.first + d2, sqcb.second + d3 };
+ });
+
+ double accel = sum_cubes / (6 * std::pow(sum_squares, 1.5));
+ int n = static_cast<int>(resample.size());
+ double prob_n = std::count_if(resample.begin(), resample.end(), [point](double x) { return x < point; }) / (double)n;
+ // degenerate case with uniform samples
+ if (prob_n == 0) return { point, point, point, confidence_level };
+
+ double bias = normal_quantile(prob_n);
+ double z1 = normal_quantile((1. - confidence_level) / 2.);
+
+ auto cumn = [n](double x) -> int {
+ return std::lround(normal_cdf(x) * n); };
+ auto a = [bias, accel](double b) { return bias + b / (1. - accel * b); };
+ double b1 = bias + z1;
+ double b2 = bias - z1;
+ double a1 = a(b1);
+ double a2 = a(b2);
+ auto lo = std::max(cumn(a1), 0);
+ auto hi = std::min(cumn(a2), n - 1);
+
+ return { point, resample[lo], resample[hi], confidence_level };
+ }
+
+ double outlier_variance(Estimate<double> mean, Estimate<double> stddev, int n);
+
+ struct bootstrap_analysis {
+ Estimate<double> mean;
+ Estimate<double> standard_deviation;
+ double outlier_variance;
+ };
+
+ bootstrap_analysis analyse_samples(double confidence_level, int n_resamples, std::vector<double>::iterator first, std::vector<double>::iterator last);
+ } // namespace Detail
+ } // namespace Benchmark
+} // namespace Catch
+
+// end catch_stats.hpp
+#include <algorithm>
+#include <iterator>
+#include <tuple>
+#include <vector>
+#include <cmath>
+
+namespace Catch {
+ namespace Benchmark {
+ namespace Detail {
+ template <typename Clock>
+ std::vector<double> resolution(int k) {
+ std::vector<TimePoint<Clock>> times;
+ times.reserve(k + 1);
+ std::generate_n(std::back_inserter(times), k + 1, now<Clock>{});
+
+ std::vector<double> deltas;
+ deltas.reserve(k);
+ std::transform(std::next(times.begin()), times.end(), times.begin(),
+ std::back_inserter(deltas),
+ [](TimePoint<Clock> a, TimePoint<Clock> b) { return static_cast<double>((a - b).count()); });
+
+ return deltas;
+ }
+
+ const auto warmup_iterations = 10000;
+ const auto warmup_time = std::chrono::milliseconds(100);
+ const auto minimum_ticks = 1000;
+ const auto warmup_seed = 10000;
+ const auto clock_resolution_estimation_time = std::chrono::milliseconds(500);
+ const auto clock_cost_estimation_time_limit = std::chrono::seconds(1);
+ const auto clock_cost_estimation_tick_limit = 100000;
+ const auto clock_cost_estimation_time = std::chrono::milliseconds(10);
+ const auto clock_cost_estimation_iterations = 10000;
+
+ template <typename Clock>
+ int warmup() {
+ return run_for_at_least<Clock>(std::chrono::duration_cast<ClockDuration<Clock>>(warmup_time), warmup_seed, &resolution<Clock>)
+ .iterations;
+ }
+ template <typename Clock>
+ EnvironmentEstimate<FloatDuration<Clock>> estimate_clock_resolution(int iterations) {
+ auto r = run_for_at_least<Clock>(std::chrono::duration_cast<ClockDuration<Clock>>(clock_resolution_estimation_time), iterations, &resolution<Clock>)
+ .result;
+ return {
+ FloatDuration<Clock>(mean(r.begin(), r.end())),
+ classify_outliers(r.begin(), r.end()),
+ };
+ }
+ template <typename Clock>
+ EnvironmentEstimate<FloatDuration<Clock>> estimate_clock_cost(FloatDuration<Clock> resolution) {
+ auto time_limit = std::min(resolution * clock_cost_estimation_tick_limit, FloatDuration<Clock>(clock_cost_estimation_time_limit));
+ auto time_clock = [](int k) {
+ return Detail::measure<Clock>([k] {
+ for (int i = 0; i < k; ++i) {
+ volatile auto ignored = Clock::now();
+ (void)ignored;
+ }
+ }).elapsed;
+ };
+ time_clock(1);
+ int iters = clock_cost_estimation_iterations;
+ auto&& r = run_for_at_least<Clock>(std::chrono::duration_cast<ClockDuration<Clock>>(clock_cost_estimation_time), iters, time_clock);
+ std::vector<double> times;
+ int nsamples = static_cast<int>(std::ceil(time_limit / r.elapsed));
+ times.reserve(nsamples);
+ std::generate_n(std::back_inserter(times), nsamples, [time_clock, &r] {
+ return static_cast<double>((time_clock(r.iterations) / r.iterations).count());
+ });
+ return {
+ FloatDuration<Clock>(mean(times.begin(), times.end())),
+ classify_outliers(times.begin(), times.end()),
+ };
+ }
+
+ template <typename Clock>
+ Environment<FloatDuration<Clock>> measure_environment() {
+ static Environment<FloatDuration<Clock>>* env = nullptr;
+ if (env) {
+ return *env;
+ }
+
+ auto iters = Detail::warmup<Clock>();
+ auto resolution = Detail::estimate_clock_resolution<Clock>(iters);
+ auto cost = Detail::estimate_clock_cost<Clock>(resolution.mean);
+
+ env = new Environment<FloatDuration<Clock>>{ resolution, cost };
+ return *env;
+ }
+ } // namespace Detail
+ } // namespace Benchmark
+} // namespace Catch
+
+// end catch_estimate_clock.hpp
+// start catch_analyse.hpp
+
+ // Run and analyse one benchmark
+
+
+// start catch_sample_analysis.hpp
+
+// Benchmark results
+
+
+#include <algorithm>
+#include <vector>
+#include <string>
+#include <iterator>
+
+namespace Catch {
+ namespace Benchmark {
+ template <typename Duration>
+ struct SampleAnalysis {
+ std::vector<Duration> samples;
+ Estimate<Duration> mean;
+ Estimate<Duration> standard_deviation;
+ OutlierClassification outliers;
+ double outlier_variance;
+
+ template <typename Duration2>
+ operator SampleAnalysis<Duration2>() const {
+ std::vector<Duration2> samples2;
+ samples2.reserve(samples.size());
+ std::transform(samples.begin(), samples.end(), std::back_inserter(samples2), [](Duration d) { return Duration2(d); });
+ return {
+ std::move(samples2),
+ mean,
+ standard_deviation,
+ outliers,
+ outlier_variance,
+ };
+ }
+ };
+ } // namespace Benchmark
+} // namespace Catch
+
+// end catch_sample_analysis.hpp
+#include <algorithm>
+#include <iterator>
+#include <vector>
+
+namespace Catch {
+ namespace Benchmark {
+ namespace Detail {
+ template <typename Duration, typename Iterator>
+ SampleAnalysis<Duration> analyse(const IConfig &cfg, Environment<Duration>, Iterator first, Iterator last) {
+ if (!cfg.benchmarkNoAnalysis()) {
+ std::vector<double> samples;
+ samples.reserve(last - first);
+ std::transform(first, last, std::back_inserter(samples), [](Duration d) { return d.count(); });
+
+ auto analysis = Catch::Benchmark::Detail::analyse_samples(cfg.benchmarkConfidenceInterval(), cfg.benchmarkResamples(), samples.begin(), samples.end());
+ auto outliers = Catch::Benchmark::Detail::classify_outliers(samples.begin(), samples.end());
+
+ auto wrap_estimate = [](Estimate<double> e) {
+ return Estimate<Duration> {
+ Duration(e.point),
+ Duration(e.lower_bound),
+ Duration(e.upper_bound),
+ e.confidence_interval,
+ };
+ };
+ std::vector<Duration> samples2;
+ samples2.reserve(samples.size());
+ std::transform(samples.begin(), samples.end(), std::back_inserter(samples2), [](double d) { return Duration(d); });
+ return {
+ std::move(samples2),
+ wrap_estimate(analysis.mean),
+ wrap_estimate(analysis.standard_deviation),
+ outliers,
+ analysis.outlier_variance,
+ };
+ } else {
+ std::vector<Duration> samples;
+ samples.reserve(last - first);
+
+ Duration mean = Duration(0);
+ int i = 0;
+ for (auto it = first; it < last; ++it, ++i) {
+ samples.push_back(Duration(*it));
+ mean += Duration(*it);
+ }
+ mean /= i;
+
+ return {
+ std::move(samples),
+ Estimate<Duration>{mean, mean, mean, 0.0},
+ Estimate<Duration>{Duration(0), Duration(0), Duration(0), 0.0},
+ OutlierClassification{},
+ 0.0
+ };
+ }
+ }
+ } // namespace Detail
+ } // namespace Benchmark
+} // namespace Catch
+
+// end catch_analyse.hpp
+#include <algorithm>
+#include <functional>
+#include <string>
+#include <vector>
+#include <cmath>
+
+namespace Catch {
+ namespace Benchmark {
+ struct Benchmark {
+ Benchmark(std::string &&name)
+ : name(std::move(name)) {}
+
+ template <class FUN>
+ Benchmark(std::string &&name, FUN &&func)
+ : fun(std::move(func)), name(std::move(name)) {}
+
+ template <typename Clock>
+ ExecutionPlan<FloatDuration<Clock>> prepare(const IConfig &cfg, Environment<FloatDuration<Clock>> env) const {
+ auto min_time = env.clock_resolution.mean * Detail::minimum_ticks;
+ auto run_time = std::max(min_time, std::chrono::duration_cast<decltype(min_time)>(cfg.benchmarkWarmupTime()));
+ auto&& test = Detail::run_for_at_least<Clock>(std::chrono::duration_cast<ClockDuration<Clock>>(run_time), 1, fun);
+ int new_iters = static_cast<int>(std::ceil(min_time * test.iterations / test.elapsed));
+ return { new_iters, test.elapsed / test.iterations * new_iters * cfg.benchmarkSamples(), fun, std::chrono::duration_cast<FloatDuration<Clock>>(cfg.benchmarkWarmupTime()), Detail::warmup_iterations };
+ }
+
+ template <typename Clock = default_clock>
+ void run() {
+ IConfigPtr cfg = getCurrentContext().getConfig();
+
+ auto env = Detail::measure_environment<Clock>();
+
+ getResultCapture().benchmarkPreparing(name);
+ CATCH_TRY{
+ auto plan = user_code([&] {
+ return prepare<Clock>(*cfg, env);
+ });
+
+ BenchmarkInfo info {
+ name,
+ plan.estimated_duration.count(),
+ plan.iterations_per_sample,
+ cfg->benchmarkSamples(),
+ cfg->benchmarkResamples(),
+ env.clock_resolution.mean.count(),
+ env.clock_cost.mean.count()
+ };
+
+ getResultCapture().benchmarkStarting(info);
+
+ auto samples = user_code([&] {
+ return plan.template run<Clock>(*cfg, env);
+ });
+
+ auto analysis = Detail::analyse(*cfg, env, samples.begin(), samples.end());
+ BenchmarkStats<FloatDuration<Clock>> stats{ info, analysis.samples, analysis.mean, analysis.standard_deviation, analysis.outliers, analysis.outlier_variance };
+ getResultCapture().benchmarkEnded(stats);
+
+ } CATCH_CATCH_ALL{
+ if (translateActiveException() != Detail::benchmarkErrorMsg) // benchmark errors have been reported, otherwise rethrow.
+ std::rethrow_exception(std::current_exception());
+ }
+ }
+
+ // sets lambda to be used in fun *and* executes benchmark!
+ template <typename Fun,
+ typename std::enable_if<!Detail::is_related<Fun, Benchmark>::value, int>::type = 0>
+ Benchmark & operator=(Fun func) {
+ fun = Detail::BenchmarkFunction(func);
+ run();
+ return *this;
+ }
+
+ explicit operator bool() {
+ return true;
+ }
+
+ private:
+ Detail::BenchmarkFunction fun;
+ std::string name;
+ };
+ }
+} // namespace Catch
+
+#define INTERNAL_CATCH_GET_1_ARG(arg1, arg2, ...) arg1
+#define INTERNAL_CATCH_GET_2_ARG(arg1, arg2, ...) arg2
+
+#define INTERNAL_CATCH_BENCHMARK(BenchmarkName, name, benchmarkIndex)\
+ if( Catch::Benchmark::Benchmark BenchmarkName{name} ) \
+ BenchmarkName = [&](int benchmarkIndex)
+
+#define INTERNAL_CATCH_BENCHMARK_ADVANCED(BenchmarkName, name)\
+ if( Catch::Benchmark::Benchmark BenchmarkName{name} ) \
+ BenchmarkName = [&]
+
+// end catch_benchmark.hpp
+// start catch_constructor.hpp
+
+// Constructor and destructor helpers
+
+
+#include <type_traits>
+
+namespace Catch {
+ namespace Benchmark {
+ namespace Detail {
+ template <typename T, bool Destruct>
+ struct ObjectStorage
+ {
+ using TStorage = typename std::aligned_storage<sizeof(T), std::alignment_of<T>::value>::type;
+
+ ObjectStorage() : data() {}
+
+ ObjectStorage(const ObjectStorage& other)
+ {
+ new(&data) T(other.stored_object());
+ }
+
+ ObjectStorage(ObjectStorage&& other)
+ {
+ new(&data) T(std::move(other.stored_object()));
+ }
+
+ ~ObjectStorage() { destruct_on_exit<T>(); }
+
+ template <typename... Args>
+ void construct(Args&&... args)
+ {
+ new (&data) T(std::forward<Args>(args)...);
+ }
+
+ template <bool AllowManualDestruction = !Destruct>
+ typename std::enable_if<AllowManualDestruction>::type destruct()
+ {
+ stored_object().~T();
+ }
+
+ private:
+ // If this is a constructor benchmark, destruct the underlying object
+ template <typename U>
+ void destruct_on_exit(typename std::enable_if<Destruct, U>::type* = 0) { destruct<true>(); }
+ // Otherwise, don't
+ template <typename U>
+ void destruct_on_exit(typename std::enable_if<!Destruct, U>::type* = 0) { }
+
+ T& stored_object() {
+ return *static_cast<T*>(static_cast<void*>(&data));
+ }
+
+ T const& stored_object() const {
+ return *static_cast<T*>(static_cast<void*>(&data));
+ }
+
+ TStorage data;
+ };
+ }
+
+ template <typename T>
+ using storage_for = Detail::ObjectStorage<T, true>;
+
+ template <typename T>
+ using destructable_object = Detail::ObjectStorage<T, false>;
+ }
+}
+
+// end catch_constructor.hpp
+// end catch_benchmarking_all.hpp
+#endif
+
#endif // ! CATCH_CONFIG_IMPL_ONLY
#ifdef CATCH_IMPL
@@ -5903,6 +7542,7 @@ namespace TestCaseTracking {
class SectionTracker : public TrackerBase {
std::vector<std::string> m_filters;
+ std::string m_trimmed_name;
public:
SectionTracker( NameAndLocation const& nameAndLocation, TrackerContext& ctx, ITracker* parent );
@@ -5940,6 +7580,217 @@ namespace Catch {
}
// end catch_leak_detector.h
// Cpp files will be included in the single-header file here
+// start catch_stats.cpp
+
+// Statistical analysis tools
+
+#if defined(CATCH_CONFIG_ENABLE_BENCHMARKING)
+
+#include <cassert>
+#include <random>
+
+#if defined(CATCH_CONFIG_USE_ASYNC)
+#include <future>
+#endif
+
+namespace {
+ double erf_inv(double x) {
+ // Code accompanying the article "Approximating the erfinv function" in GPU Computing Gems, Volume 2
+ double w, p;
+
+ w = -log((1.0 - x) * (1.0 + x));
+
+ if (w < 6.250000) {
+ w = w - 3.125000;
+ p = -3.6444120640178196996e-21;
+ p = -1.685059138182016589e-19 + p * w;
+ p = 1.2858480715256400167e-18 + p * w;
+ p = 1.115787767802518096e-17 + p * w;
+ p = -1.333171662854620906e-16 + p * w;
+ p = 2.0972767875968561637e-17 + p * w;
+ p = 6.6376381343583238325e-15 + p * w;
+ p = -4.0545662729752068639e-14 + p * w;
+ p = -8.1519341976054721522e-14 + p * w;
+ p = 2.6335093153082322977e-12 + p * w;
+ p = -1.2975133253453532498e-11 + p * w;
+ p = -5.4154120542946279317e-11 + p * w;
+ p = 1.051212273321532285e-09 + p * w;
+ p = -4.1126339803469836976e-09 + p * w;
+ p = -2.9070369957882005086e-08 + p * w;
+ p = 4.2347877827932403518e-07 + p * w;
+ p = -1.3654692000834678645e-06 + p * w;
+ p = -1.3882523362786468719e-05 + p * w;
+ p = 0.0001867342080340571352 + p * w;
+ p = -0.00074070253416626697512 + p * w;
+ p = -0.0060336708714301490533 + p * w;
+ p = 0.24015818242558961693 + p * w;
+ p = 1.6536545626831027356 + p * w;
+ } else if (w < 16.000000) {
+ w = sqrt(w) - 3.250000;
+ p = 2.2137376921775787049e-09;
+ p = 9.0756561938885390979e-08 + p * w;
+ p = -2.7517406297064545428e-07 + p * w;
+ p = 1.8239629214389227755e-08 + p * w;
+ p = 1.5027403968909827627e-06 + p * w;
+ p = -4.013867526981545969e-06 + p * w;
+ p = 2.9234449089955446044e-06 + p * w;
+ p = 1.2475304481671778723e-05 + p * w;
+ p = -4.7318229009055733981e-05 + p * w;
+ p = 6.8284851459573175448e-05 + p * w;
+ p = 2.4031110387097893999e-05 + p * w;
+ p = -0.0003550375203628474796 + p * w;
+ p = 0.00095328937973738049703 + p * w;
+ p = -0.0016882755560235047313 + p * w;
+ p = 0.0024914420961078508066 + p * w;
+ p = -0.0037512085075692412107 + p * w;
+ p = 0.005370914553590063617 + p * w;
+ p = 1.0052589676941592334 + p * w;
+ p = 3.0838856104922207635 + p * w;
+ } else {
+ w = sqrt(w) - 5.000000;
+ p = -2.7109920616438573243e-11;
+ p = -2.5556418169965252055e-10 + p * w;
+ p = 1.5076572693500548083e-09 + p * w;
+ p = -3.7894654401267369937e-09 + p * w;
+ p = 7.6157012080783393804e-09 + p * w;
+ p = -1.4960026627149240478e-08 + p * w;
+ p = 2.9147953450901080826e-08 + p * w;
+ p = -6.7711997758452339498e-08 + p * w;
+ p = 2.2900482228026654717e-07 + p * w;
+ p = -9.9298272942317002539e-07 + p * w;
+ p = 4.5260625972231537039e-06 + p * w;
+ p = -1.9681778105531670567e-05 + p * w;
+ p = 7.5995277030017761139e-05 + p * w;
+ p = -0.00021503011930044477347 + p * w;
+ p = -0.00013871931833623122026 + p * w;
+ p = 1.0103004648645343977 + p * w;
+ p = 4.8499064014085844221 + p * w;
+ }
+ return p * x;
+ }
+
+ double standard_deviation(std::vector<double>::iterator first, std::vector<double>::iterator last) {
+ auto m = Catch::Benchmark::Detail::mean(first, last);
+ double variance = std::accumulate(first, last, 0., [m](double a, double b) {
+ double diff = b - m;
+ return a + diff * diff;
+ }) / (last - first);
+ return std::sqrt(variance);
+ }
+
+}
+
+namespace Catch {
+ namespace Benchmark {
+ namespace Detail {
+
+ double weighted_average_quantile(int k, int q, std::vector<double>::iterator first, std::vector<double>::iterator last) {
+ auto count = last - first;
+ double idx = (count - 1) * k / static_cast<double>(q);
+ int j = static_cast<int>(idx);
+ double g = idx - j;
+ std::nth_element(first, first + j, last);
+ auto xj = first[j];
+ if (g == 0) return xj;
+
+ auto xj1 = *std::min_element(first + (j + 1), last);
+ return xj + g * (xj1 - xj);
+ }
+
+ double erfc_inv(double x) {
+ return erf_inv(1.0 - x);
+ }
+
+ double normal_quantile(double p) {
+ static const double ROOT_TWO = std::sqrt(2.0);
+
+ double result = 0.0;
+ assert(p >= 0 && p <= 1);
+ if (p < 0 || p > 1) {
+ return result;
+ }
+
+ result = -erfc_inv(2.0 * p);
+ // result *= normal distribution standard deviation (1.0) * sqrt(2)
+ result *= /*sd * */ ROOT_TWO;
+ // result += normal disttribution mean (0)
+ return result;
+ }
+
+ double outlier_variance(Estimate<double> mean, Estimate<double> stddev, int n) {
+ double sb = stddev.point;
+ double mn = mean.point / n;
+ double mg_min = mn / 2.;
+ double sg = std::min(mg_min / 4., sb / std::sqrt(n));
+ double sg2 = sg * sg;
+ double sb2 = sb * sb;
+
+ auto c_max = [n, mn, sb2, sg2](double x) -> double {
+ double k = mn - x;
+ double d = k * k;
+ double nd = n * d;
+ double k0 = -n * nd;
+ double k1 = sb2 - n * sg2 + nd;
+ double det = k1 * k1 - 4 * sg2 * k0;
+ return (int)(-2. * k0 / (k1 + std::sqrt(det)));
+ };
+
+ auto var_out = [n, sb2, sg2](double c) {
+ double nc = n - c;
+ return (nc / n) * (sb2 - nc * sg2);
+ };
+
+ return std::min(var_out(1), var_out(std::min(c_max(0.), c_max(mg_min)))) / sb2;
+ }
+
+ bootstrap_analysis analyse_samples(double confidence_level, int n_resamples, std::vector<double>::iterator first, std::vector<double>::iterator last) {
+ CATCH_INTERNAL_START_WARNINGS_SUPPRESSION
+ CATCH_INTERNAL_SUPPRESS_GLOBALS_WARNINGS
+ static std::random_device entropy;
+ CATCH_INTERNAL_STOP_WARNINGS_SUPPRESSION
+
+ auto n = static_cast<int>(last - first); // seriously, one can't use integral types without hell in C++
+
+ auto mean = &Detail::mean<std::vector<double>::iterator>;
+ auto stddev = &standard_deviation;
+
+#if defined(CATCH_CONFIG_USE_ASYNC)
+ auto Estimate = [=](double(*f)(std::vector<double>::iterator, std::vector<double>::iterator)) {
+ auto seed = entropy();
+ return std::async(std::launch::async, [=] {
+ std::mt19937 rng(seed);
+ auto resampled = resample(rng, n_resamples, first, last, f);
+ return bootstrap(confidence_level, first, last, resampled, f);
+ });
+ };
+
+ auto mean_future = Estimate(mean);
+ auto stddev_future = Estimate(stddev);
+
+ auto mean_estimate = mean_future.get();
+ auto stddev_estimate = stddev_future.get();
+#else
+ auto Estimate = [=](double(*f)(std::vector<double>::iterator, std::vector<double>::iterator)) {
+ auto seed = entropy();
+ std::mt19937 rng(seed);
+ auto resampled = resample(rng, n_resamples, first, last, f);
+ return bootstrap(confidence_level, first, last, resampled, f);
+ };
+
+ auto mean_estimate = Estimate(mean);
+ auto stddev_estimate = Estimate(stddev);
+#endif // CATCH_USE_ASYNC
+
+ double outlier_variance = Detail::outlier_variance(mean_estimate, stddev_estimate, n);
+
+ return { mean_estimate, stddev_estimate, outlier_variance };
+ }
+ } // namespace Detail
+ } // namespace Benchmark
+} // namespace Catch
+
+#endif // CATCH_CONFIG_ENABLE_BENCHMARKING
+// end catch_stats.cpp
// start catch_approx.cpp
#include <cmath>
@@ -5984,7 +7835,8 @@ namespace Detail {
bool Approx::equalityComparisonImpl(const double other) const {
// First try with fixed margin, then compute margin based on epsilon, scale and Approx's value
// Thanks to Richard Harris for his help refining the scaled margin value
- return marginComparison(m_value, other, m_margin) || marginComparison(m_value, other, m_epsilon * (m_scale + std::fabs(m_value)));
+ return marginComparison(m_value, other, m_margin)
+ || marginComparison(m_value, other, m_epsilon * (m_scale + std::fabs(std::isinf(m_value)? 0 : m_value)));
}
void Approx::setMargin(double newMargin) {
@@ -6030,6 +7882,19 @@ namespace Catch {
#define CATCH_TRAP() __asm__("int $3\n" : : ) /* NOLINT */
+#elif defined(CATCH_PLATFORM_IPHONE)
+
+ // use inline assembler
+ #if defined(__i386__) || defined(__x86_64__)
+ #define CATCH_TRAP() __asm__("int $3")
+ #elif defined(__aarch64__)
+ #define CATCH_TRAP() __asm__(".inst 0xd4200000")
+ #elif defined(__arm__) && !defined(__thumb__)
+ #define CATCH_TRAP() __asm__(".inst 0xe7f001f0")
+ #elif defined(__arm__) && defined(__thumb__)
+ #define CATCH_TRAP() __asm__(".inst 0xde01")
+ #endif
+
#elif defined(CATCH_PLATFORM_LINUX)
// If we can use inline assembler, do it because this allows us to break
// directly at the location of the failing check instead of breaking inside
@@ -6048,10 +7913,12 @@ namespace Catch {
#define CATCH_TRAP() DebugBreak()
#endif
-#ifdef CATCH_TRAP
- #define CATCH_BREAK_INTO_DEBUGGER() []{ if( Catch::isDebuggerActive() ) { CATCH_TRAP(); } }()
-#else
- #define CATCH_BREAK_INTO_DEBUGGER() []{}()
+#ifndef CATCH_BREAK_INTO_DEBUGGER
+ #ifdef CATCH_TRAP
+ #define CATCH_BREAK_INTO_DEBUGGER() []{ if( Catch::isDebuggerActive() ) { CATCH_TRAP(); } }()
+ #else
+ #define CATCH_BREAK_INTO_DEBUGGER() []{}()
+ #endif
#endif
// end catch_debugger.h
@@ -6200,8 +8067,12 @@ namespace Catch {
auto acquireGeneratorTracker( SourceLineInfo const& lineInfo ) -> IGeneratorTracker& override;
+#if defined(CATCH_CONFIG_ENABLE_BENCHMARKING)
+ void benchmarkPreparing( std::string const& name ) override;
void benchmarkStarting( BenchmarkInfo const& info ) override;
- void benchmarkEnded( BenchmarkStats const& stats ) override;
+ void benchmarkEnded( BenchmarkStats<> const& stats ) override;
+ void benchmarkFailed( std::string const& error ) override;
+#endif // CATCH_CONFIG_ENABLE_BENCHMARKING
void pushScopedMessage( MessageInfo const& message ) override;
void popScopedMessage( MessageInfo const& message ) override;
@@ -6265,6 +8136,8 @@ namespace Catch {
bool m_includeSuccessfulResults;
};
+ void seedRng(IConfig const& config);
+ unsigned int rngSeed();
} // end namespace Catch
// end catch_run_context.h
@@ -6411,7 +8284,7 @@ namespace Catch {
}
bool AssertionResult::hasExpression() const {
- return m_info.capturedExpression[0] != 0;
+ return !m_info.capturedExpression.empty();
}
bool AssertionResult::hasMessage() const {
@@ -6419,16 +8292,22 @@ namespace Catch {
}
std::string AssertionResult::getExpression() const {
- if( isFalseTest( m_info.resultDisposition ) )
- return "!(" + m_info.capturedExpression + ")";
- else
- return m_info.capturedExpression;
+ // Possibly overallocating by 3 characters should be basically free
+ std::string expr; expr.reserve(m_info.capturedExpression.size() + 3);
+ if (isFalseTest(m_info.resultDisposition)) {
+ expr += "!(";
+ }
+ expr += m_info.capturedExpression;
+ if (isFalseTest(m_info.resultDisposition)) {
+ expr += ')';
+ }
+ return expr;
}
std::string AssertionResult::getExpressionInMacro() const {
std::string expr;
- if( m_info.macroName[0] == 0 )
- expr = m_info.capturedExpression;
+ if( m_info.macroName.empty() )
+ expr = static_cast<std::string>(m_info.capturedExpression);
else {
expr.reserve( m_info.macroName.size() + m_info.capturedExpression.size() + 4 );
expr += m_info.macroName;
@@ -6463,32 +8342,6 @@ namespace Catch {
} // end namespace Catch
// end catch_assertionresult.cpp
-// start catch_benchmark.cpp
-
-namespace Catch {
-
- auto BenchmarkLooper::getResolution() -> uint64_t {
- return getEstimatedClockResolution() * getCurrentContext().getConfig()->benchmarkResolutionMultiple();
- }
-
- void BenchmarkLooper::reportStart() {
- getResultCapture().benchmarkStarting( { m_name } );
- }
- auto BenchmarkLooper::needsMoreIterations() -> bool {
- auto elapsed = m_timer.getElapsedNanoseconds();
-
- // Exponentially increasing iterations until we're confident in our timer resolution
- if( elapsed < m_resolution ) {
- m_iterationsToRun *= 10;
- return true;
- }
-
- getResultCapture().benchmarkEnded( { { m_name }, m_count, elapsed } );
- return false;
- }
-
-} // end namespace Catch
-// end catch_benchmark.cpp
// start catch_capture_matchers.cpp
namespace Catch {
@@ -7836,9 +9689,14 @@ namespace Catch {
if( !line.empty() && !startsWith( line, '#' ) ) {
if( !startsWith( line, '"' ) )
line = '"' + line + '"';
- config.testsOrTags.push_back( line + ',' );
+ config.testsOrTags.push_back( line );
+ config.testsOrTags.emplace_back( "," );
}
}
+ //Remove comma in the end
+ if(!config.testsOrTags.empty())
+ config.testsOrTags.erase( config.testsOrTags.end()-1 );
+
return ParserResult::ok( ParseResultType::Matched );
};
auto const setTestOrder = [&]( std::string const& order ) {
@@ -7873,14 +9731,16 @@ namespace Catch {
};
auto const setWaitForKeypress = [&]( std::string const& keypress ) {
auto keypressLc = toLower( keypress );
- if( keypressLc == "start" )
+ if (keypressLc == "never")
+ config.waitForKeypress = WaitForKeypress::Never;
+ else if( keypressLc == "start" )
config.waitForKeypress = WaitForKeypress::BeforeStart;
else if( keypressLc == "exit" )
config.waitForKeypress = WaitForKeypress::BeforeExit;
else if( keypressLc == "both" )
config.waitForKeypress = WaitForKeypress::BeforeStartAndExit;
else
- return ParserResult::runtimeError( "keypress argument must be one of: start, exit or both. '" + keypress + "' not recognised" );
+ return ParserResult::runtimeError( "keypress argument must be one of: never, start, exit or both. '" + keypress + "' not recognised" );
return ParserResult::ok( ParseResultType::Matched );
};
auto const setVerbosity = [&]( std::string const& verbosity ) {
@@ -7980,13 +9840,24 @@ namespace Catch {
| Opt( config.libIdentify )
["--libidentify"]
( "report name and version according to libidentify standard" )
- | Opt( setWaitForKeypress, "start|exit|both" )
+ | Opt( setWaitForKeypress, "never|start|exit|both" )
["--wait-for-keypress"]
( "waits for a keypress before exiting" )
- | Opt( config.benchmarkResolutionMultiple, "multiplier" )
- ["--benchmark-resolution-multiple"]
- ( "multiple of clock resolution to run benchmarks" )
-
+ | Opt( config.benchmarkSamples, "samples" )
+ ["--benchmark-samples"]
+ ( "number of samples to collect (default: 100)" )
+ | Opt( config.benchmarkResamples, "resamples" )
+ ["--benchmark-resamples"]
+ ( "number of resamples for the bootstrap (default: 100000)" )
+ | Opt( config.benchmarkConfidenceInterval, "confidence interval" )
+ ["--benchmark-confidence-interval"]
+ ( "confidence interval for the bootstrap (between 0 and 1, default: 0.95)" )
+ | Opt( config.benchmarkNoAnalysis )
+ ["--benchmark-no-analysis"]
+ ( "perform only measurements; do not perform any analysis" )
+ | Opt( config.benchmarkWarmupTime, "benchmarkWarmupTime" )
+ ["--benchmark-warmup-time"]
+ ( "amount of time in milliseconds spent on warming up each test (default: 100)" )
| Arg( config.testsOrTags, "test name|pattern|tags" )
( "which test or tests to use" );
@@ -8002,9 +9873,6 @@ namespace Catch {
namespace Catch {
- bool SourceLineInfo::empty() const noexcept {
- return file[0] == '\0';
- }
bool SourceLineInfo::operator == ( SourceLineInfo const& other ) const noexcept {
return line == other.line && (file == other.file || std::strcmp(file, other.file) == 0);
}
@@ -8040,11 +9908,23 @@ namespace Catch {
: m_data( data ),
m_stream( openStream() )
{
+ // We need to trim filter specs to avoid trouble with superfluous
+ // whitespace (esp. important for bdd macros, as those are manually
+ // aligned with whitespace).
+
+ for (auto& elem : m_data.testsOrTags) {
+ elem = trim(elem);
+ }
+ for (auto& elem : m_data.sectionsToRun) {
+ elem = trim(elem);
+ }
+
TestSpecParser parser(ITagAliasRegistry::get());
- if (!data.testsOrTags.empty()) {
+ if (!m_data.testsOrTags.empty()) {
m_hasTestFilters = true;
- for( auto const& testOrTags : data.testsOrTags )
- parser.parse( testOrTags );
+ for (auto const& testOrTags : m_data.testsOrTags) {
+ parser.parse(testOrTags);
+ }
}
m_testSpec = parser.testSpec();
}
@@ -8079,13 +9959,18 @@ namespace Catch {
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; }
- int Config::benchmarkResolutionMultiple() const { return m_data.benchmarkResolutionMultiple; }
UseColour::YesOrNo Config::useColour() const { return m_data.useColour; }
bool Config::shouldDebugBreak() const { return m_data.shouldDebugBreak; }
int Config::abortAfter() const { return m_data.abortAfter; }
bool Config::showInvisibles() const { return m_data.showInvisibles; }
Verbosity Config::verbosity() const { return m_data.verbosity; }
+ bool Config::benchmarkNoAnalysis() const { return m_data.benchmarkNoAnalysis; }
+ int Config::benchmarkSamples() const { return m_data.benchmarkSamples; }
+ double Config::benchmarkConfidenceInterval() const { return m_data.benchmarkConfidenceInterval; }
+ unsigned int Config::benchmarkResamples() const { return m_data.benchmarkResamples; }
+ std::chrono::milliseconds Config::benchmarkWarmupTime() const { return std::chrono::milliseconds(m_data.benchmarkWarmupTime); }
+
IStream const* Config::openStream() {
return Catch::makeStream(m_data.outputFilename);
}
@@ -8125,7 +10010,7 @@ namespace Catch {
};
struct NoColourImpl : IColourImpl {
- void use( Colour::Code ) {}
+ void use( Colour::Code ) override {}
static IColourImpl* instance() {
static NoColourImpl s_instance;
@@ -8257,7 +10142,7 @@ namespace {
bool useColourOnPlatform() {
return
-#ifdef CATCH_PLATFORM_MAC
+#if defined(CATCH_PLATFORM_MAC) || defined(CATCH_PLATFORM_IPHONE)
!isDebuggerActive() &&
#endif
#if !(defined(__DJGPP__) && defined(__STRICT_ANSI__))
@@ -8298,13 +10183,13 @@ namespace Catch {
namespace Catch {
Colour::Colour( Code _colourCode ) { use( _colourCode ); }
- Colour::Colour( Colour&& rhs ) noexcept {
- m_moved = rhs.m_moved;
- rhs.m_moved = true;
+ Colour::Colour( Colour&& other ) noexcept {
+ m_moved = other.m_moved;
+ other.m_moved = true;
}
- Colour& Colour::operator=( Colour&& rhs ) noexcept {
- m_moved = rhs.m_moved;
- rhs.m_moved = true;
+ Colour& Colour::operator=( Colour&& other ) noexcept {
+ m_moved = other.m_moved;
+ other.m_moved = true;
return *this;
}
@@ -8312,7 +10197,13 @@ namespace Catch {
void Colour::use( Code _colourCode ) {
static IColourImpl* impl = platformColourInstance();
- impl->use( _colourCode );
+ // Strictly speaking, this cannot possibly happen.
+ // However, under some conditions it does happen (see #1626),
+ // and this change is small enough that we can let practicality
+ // triumph over purity in this case.
+ if (impl != nullptr) {
+ impl->use( _colourCode );
+ }
}
std::ostream& operator << ( std::ostream& os, Colour const& ) {
@@ -8379,6 +10270,12 @@ namespace Catch {
IContext::~IContext() = default;
IMutableContext::~IMutableContext() = default;
Context::~Context() = default;
+
+ SimplePcg32& rng() {
+ static SimplePcg32 s_rng;
+ return s_rng;
+ }
+
}
// end catch_context.cpp
// start catch_debug_console.cpp
@@ -8392,7 +10289,16 @@ namespace Catch {
}
// end catch_debug_console.h
-#ifdef CATCH_PLATFORM_WINDOWS
+#if defined(CATCH_CONFIG_ANDROID_LOGWRITE)
+#include <android/log.h>
+
+ namespace Catch {
+ void writeToDebugConsole( std::string const& text ) {
+ __android_log_write( ANDROID_LOG_DEBUG, "Catch", text.c_str() );
+ }
+ }
+
+#elif defined(CATCH_PLATFORM_WINDOWS)
namespace Catch {
void writeToDebugConsole( std::string const& text ) {
@@ -8413,7 +10319,7 @@ namespace Catch {
// end catch_debug_console.cpp
// start catch_debugger.cpp
-#ifdef CATCH_PLATFORM_MAC
+#if defined(CATCH_PLATFORM_MAC) || defined(CATCH_PLATFORM_IPHONE)
# include <assert.h>
# include <stdbool.h>
@@ -8541,6 +10447,8 @@ namespace Catch {
// end catch_decomposer.cpp
// start catch_enforce.cpp
+#include <stdexcept>
+
namespace Catch {
#if defined(CATCH_CONFIG_DISABLE_EXCEPTIONS) && !defined(CATCH_CONFIG_DISABLE_EXCEPTIONS_CUSTOM_HANDLER)
[[noreturn]]
@@ -8550,8 +10458,116 @@ namespace Catch {
std::terminate();
}
#endif
+
+ [[noreturn]]
+ void throw_logic_error(std::string const& msg) {
+ throw_exception(std::logic_error(msg));
+ }
+
+ [[noreturn]]
+ void throw_domain_error(std::string const& msg) {
+ throw_exception(std::domain_error(msg));
+ }
+
+ [[noreturn]]
+ void throw_runtime_error(std::string const& msg) {
+ throw_exception(std::runtime_error(msg));
+ }
+
} // namespace Catch;
// end catch_enforce.cpp
+// start catch_enum_values_registry.cpp
+// start catch_enum_values_registry.h
+
+#include <vector>
+#include <memory>
+
+namespace Catch {
+
+ namespace Detail {
+
+ std::unique_ptr<EnumInfo> makeEnumInfo( StringRef enumName, StringRef allValueNames, std::vector<int> const& values );
+
+ class EnumValuesRegistry : public IMutableEnumValuesRegistry {
+
+ std::vector<std::unique_ptr<EnumInfo>> m_enumInfos;
+
+ EnumInfo const& registerEnum( StringRef enumName, StringRef allEnums, std::vector<int> const& values) override;
+ };
+
+ std::vector<StringRef> parseEnums( StringRef enums );
+
+ } // Detail
+
+} // Catch
+
+// end catch_enum_values_registry.h
+
+#include <map>
+#include <cassert>
+
+namespace Catch {
+
+ IMutableEnumValuesRegistry::~IMutableEnumValuesRegistry() {}
+
+ namespace Detail {
+
+ namespace {
+ // Extracts the actual name part of an enum instance
+ // In other words, it returns the Blue part of Bikeshed::Colour::Blue
+ StringRef extractInstanceName(StringRef enumInstance) {
+ // Find last occurence of ":"
+ size_t name_start = enumInstance.size();
+ while (name_start > 0 && enumInstance[name_start - 1] != ':') {
+ --name_start;
+ }
+ return enumInstance.substr(name_start, enumInstance.size() - name_start);
+ }
+ }
+
+ std::vector<StringRef> parseEnums( StringRef enums ) {
+ auto enumValues = splitStringRef( enums, ',' );
+ std::vector<StringRef> parsed;
+ parsed.reserve( enumValues.size() );
+ for( auto const& enumValue : enumValues ) {
+ parsed.push_back(trim(extractInstanceName(enumValue)));
+ }
+ return parsed;
+ }
+
+ EnumInfo::~EnumInfo() {}
+
+ StringRef EnumInfo::lookup( int value ) const {
+ for( auto const& valueToName : m_values ) {
+ if( valueToName.first == value )
+ return valueToName.second;
+ }
+ return "{** unexpected enum value **}"_sr;
+ }
+
+ std::unique_ptr<EnumInfo> makeEnumInfo( StringRef enumName, StringRef allValueNames, std::vector<int> const& values ) {
+ std::unique_ptr<EnumInfo> enumInfo( new EnumInfo );
+ enumInfo->m_name = enumName;
+ enumInfo->m_values.reserve( values.size() );
+
+ const auto valueNames = Catch::Detail::parseEnums( allValueNames );
+ assert( valueNames.size() == values.size() );
+ std::size_t i = 0;
+ for( auto value : values )
+ enumInfo->m_values.emplace_back(value, valueNames[i++]);
+
+ return enumInfo;
+ }
+
+ EnumInfo const& EnumValuesRegistry::registerEnum( StringRef enumName, StringRef allValueNames, std::vector<int> const& values ) {
+ m_enumInfos.push_back(makeEnumInfo(enumName, allValueNames, values));
+ return *m_enumInfos.back();
+ }
+
+ } // Detail
+} // Catch
+
+// end catch_enum_values_registry.cpp
// start catch_errno_guard.cpp
#include <cerrno>
@@ -8746,7 +10762,7 @@ namespace Catch {
// 32kb for the alternate stack seems to be sufficient. However, this value
// is experimentally determined, so that's not guaranteed.
- constexpr static std::size_t sigStackSize = 32768 >= MINSIGSTKSZ ? 32768 : MINSIGSTKSZ;
+ static constexpr std::size_t sigStackSize = 32768 >= MINSIGSTKSZ ? 32768 : MINSIGSTKSZ;
static SignalDefs signalDefs[] = {
{ SIGINT, "SIGINT - Terminal interrupt signal" },
@@ -8823,22 +10839,6 @@ namespace Catch {
// end catch_fatal_condition.cpp
// start catch_generators.cpp
-// start catch_random_number_generator.h
-
-#include <algorithm>
-#include <random>
-
-namespace Catch {
-
- struct IConfig;
-
- std::mt19937& rng();
- void seedRng( IConfig const& config );
- unsigned int rngSeed();
-
-}
-
-// end catch_random_number_generator.h
#include <limits>
#include <set>
@@ -8911,10 +10911,16 @@ namespace Catch {
void noMatchingTestCases( std::string const& spec ) override;
+ void reportInvalidArguments(std::string const&arg) override;
+
static std::set<Verbosity> getSupportedVerbosities();
+#if defined(CATCH_CONFIG_ENABLE_BENCHMARKING)
+ void benchmarkPreparing(std::string const& name) override;
void benchmarkStarting( BenchmarkInfo const& benchmarkInfo ) override;
- void benchmarkEnded( BenchmarkStats const& benchmarkStats ) override;
+ void benchmarkEnded( BenchmarkStats<> const& benchmarkStats ) override;
+ void benchmarkFailed(std::string const&) override;
+#endif // CATCH_CONFIG_ENABLE_BENCHMARKING
void testRunStarting( TestRunInfo const& testRunInfo ) override;
void testGroupStarting( GroupInfo const& groupInfo ) override;
@@ -9124,7 +11130,7 @@ namespace Catch {
namespace Catch {
std::size_t listTests( Config const& config ) {
- TestSpec testSpec = config.testSpec();
+ TestSpec const& testSpec = config.testSpec();
if( config.hasTestFilters() )
Catch::cout() << "Matching test cases:\n";
else {
@@ -9158,7 +11164,7 @@ namespace Catch {
}
std::size_t listTestsNamesOnly( Config const& config ) {
- TestSpec testSpec = config.testSpec();
+ TestSpec const& testSpec = config.testSpec();
std::size_t matchedTests = 0;
std::vector<TestCase> matchedTestCases = filterTests( getAllTestCasesSorted( config ), testSpec, config );
for( auto const& testCaseInfo : matchedTestCases ) {
@@ -9180,14 +11186,23 @@ namespace Catch {
}
std::string TagInfo::all() const {
- std::string out;
- for( auto const& spelling : spellings )
- out += "[" + spelling + "]";
+ size_t size = 0;
+ for (auto const& spelling : spellings) {
+ // Add 2 for the brackes
+ size += spelling.size() + 2;
+ }
+
+ std::string out; out.reserve(size);
+ for (auto const& spelling : spellings) {
+ out += '[';
+ out += spelling;
+ out += ']';
+ }
return out;
}
std::size_t listTags( Config const& config ) {
- TestSpec testSpec = config.testSpec();
+ TestSpec const& testSpec = config.testSpec();
if( config.hasTestFilters() )
Catch::cout() << "Tags for matching test cases:\n";
else {
@@ -9281,6 +11296,29 @@ using Matchers::Impl::MatcherBase;
} // namespace Catch
// end catch_matchers.cpp
+// start catch_matchers_exception.cpp
+
+namespace Catch {
+namespace Matchers {
+namespace Exception {
+
+bool ExceptionMessageMatcher::match(std::exception const& ex) const {
+ return ex.what() == m_message;
+}
+
+std::string ExceptionMessageMatcher::describe() const {
+ return "exception message matches \"" + m_message + "\"";
+}
+
+}
+Exception::ExceptionMessageMatcher Message(std::string const& message) {
+ return Exception::ExceptionMessageMatcher(message);
+}
+
+// namespace Exception
+} // namespace Matchers
+} // namespace Catch
+// end catch_matchers_exception.cpp
// start catch_matchers_floating.cpp
// start catch_polyfills.hpp
@@ -9309,74 +11347,100 @@ namespace Catch {
} // end namespace Catch
// end catch_to_string.hpp
+#include <algorithm>
+#include <cmath>
#include <cstdlib>
#include <cstdint>
#include <cstring>
+#include <sstream>
+#include <type_traits>
+#include <iomanip>
+#include <limits>
namespace Catch {
-namespace Matchers {
-namespace Floating {
-enum class FloatingPointKind : uint8_t {
- Float,
- Double
-};
-}
-}
-}
-
namespace {
-template <typename T>
-struct Converter;
-
-template <>
-struct Converter<float> {
- static_assert(sizeof(float) == sizeof(int32_t), "Important ULP matcher assumption violated");
- Converter(float f) {
+ int32_t convert(float f) {
+ static_assert(sizeof(float) == sizeof(int32_t), "Important ULP matcher assumption violated");
+ int32_t i;
std::memcpy(&i, &f, sizeof(f));
+ return i;
}
- int32_t i;
-};
-template <>
-struct Converter<double> {
- static_assert(sizeof(double) == sizeof(int64_t), "Important ULP matcher assumption violated");
- Converter(double d) {
+ int64_t convert(double d) {
+ static_assert(sizeof(double) == sizeof(int64_t), "Important ULP matcher assumption violated");
+ int64_t i;
std::memcpy(&i, &d, sizeof(d));
+ return i;
}
- int64_t i;
-};
-template <typename T>
-auto convert(T t) -> Converter<T> {
- return Converter<T>(t);
-}
+ template <typename FP>
+ bool almostEqualUlps(FP lhs, FP rhs, uint64_t maxUlpDiff) {
+ // Comparison with NaN should always be false.
+ // This way we can rule it out before getting into the ugly details
+ if (Catch::isnan(lhs) || Catch::isnan(rhs)) {
+ return false;
+ }
-template <typename FP>
-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 (Catch::isnan(lhs) || Catch::isnan(rhs)) {
- return false;
+ auto lc = convert(lhs);
+ auto rc = convert(rhs);
+
+ if ((lc < 0) != (rc < 0)) {
+ // Potentially we can have +0 and -0
+ return lhs == rhs;
+ }
+
+ auto ulpDiff = std::abs(lc - rc);
+ return static_cast<uint64_t>(ulpDiff) <= maxUlpDiff;
+ }
+
+#if defined(CATCH_CONFIG_GLOBAL_NEXTAFTER)
+
+ float nextafter(float x, float y) {
+ return ::nextafterf(x, y);
}
- auto lc = convert(lhs);
- auto rc = convert(rhs);
+ double nextafter(double x, double y) {
+ return ::nextafter(x, y);
+ }
+
+#endif // ^^^ CATCH_CONFIG_GLOBAL_NEXTAFTER ^^^
- if ((lc.i < 0) != (rc.i < 0)) {
- // Potentially we can have +0 and -0
- return lhs == rhs;
+template <typename FP>
+FP step(FP start, FP direction, uint64_t steps) {
+ for (uint64_t i = 0; i < steps; ++i) {
+#if defined(CATCH_CONFIG_GLOBAL_NEXTAFTER)
+ start = Catch::nextafter(start, direction);
+#else
+ start = std::nextafter(start, direction);
+#endif
}
+ return start;
+}
- auto ulpDiff = std::abs(lc.i - rc.i);
- return ulpDiff <= maxUlpDiff;
+// Performs equivalent check of std::fabs(lhs - rhs) <= margin
+// But without the subtraction to allow for INFINITY in comparison
+bool marginComparison(double lhs, double rhs, double margin) {
+ return (lhs + margin >= rhs) && (rhs + margin >= lhs);
}
+template <typename FloatingPoint>
+void write(std::ostream& out, FloatingPoint num) {
+ out << std::scientific
+ << std::setprecision(std::numeric_limits<FloatingPoint>::max_digits10 - 1)
+ << num;
}
-namespace Catch {
+} // end anonymous namespace
+
namespace Matchers {
namespace Floating {
+
+ enum class FloatingPointKind : uint8_t {
+ Float,
+ Double
+ };
+
WithinAbsMatcher::WithinAbsMatcher(double target, double margin)
:m_target{ target }, m_margin{ margin } {
CATCH_ENFORCE(margin >= 0, "Invalid margin: " << margin << '.'
@@ -9393,10 +11457,11 @@ namespace Floating {
return "is within " + ::Catch::Detail::stringify(m_margin) + " of " + ::Catch::Detail::stringify(m_target);
}
- WithinUlpsMatcher::WithinUlpsMatcher(double target, int ulps, FloatingPointKind baseType)
+ WithinUlpsMatcher::WithinUlpsMatcher(double target, uint64_t ulps, FloatingPointKind baseType)
:m_target{ target }, m_ulps{ ulps }, m_type{ baseType } {
- CATCH_ENFORCE(ulps >= 0, "Invalid ULP setting: " << ulps << '.'
- << " ULPs have to be non-negative.");
+ CATCH_ENFORCE(m_type == FloatingPointKind::Double
+ || m_ulps < (std::numeric_limits<uint32_t>::max)(),
+ "Provided ULP is impossibly large for a float comparison.");
}
#if defined(__clang__)
@@ -9421,16 +11486,59 @@ namespace Floating {
#endif
std::string WithinUlpsMatcher::describe() const {
- return "is within " + Catch::to_string(m_ulps) + " ULPs of " + ::Catch::Detail::stringify(m_target) + ((m_type == FloatingPointKind::Float)? "f" : "");
+ std::stringstream ret;
+
+ ret << "is within " << m_ulps << " ULPs of ";
+
+ if (m_type == FloatingPointKind::Float) {
+ write(ret, static_cast<float>(m_target));
+ ret << 'f';
+ } else {
+ write(ret, m_target);
+ }
+
+ ret << " ([";
+ if (m_type == FloatingPointKind::Double) {
+ write(ret, step(m_target, static_cast<double>(-INFINITY), m_ulps));
+ ret << ", ";
+ write(ret, step(m_target, static_cast<double>( INFINITY), m_ulps));
+ } else {
+ // We have to cast INFINITY to float because of MinGW, see #1782
+ write(ret, step(static_cast<float>(m_target), static_cast<float>(-INFINITY), m_ulps));
+ ret << ", ";
+ write(ret, step(static_cast<float>(m_target), static_cast<float>( INFINITY), m_ulps));
+ }
+ ret << "])";
+
+ return ret.str();
+ }
+
+ WithinRelMatcher::WithinRelMatcher(double target, double epsilon):
+ m_target(target),
+ m_epsilon(epsilon){
+ CATCH_ENFORCE(m_epsilon >= 0., "Relative comparison with epsilon < 0 does not make sense.");
+ CATCH_ENFORCE(m_epsilon < 1., "Relative comparison with epsilon >= 1 does not make sense.");
+ }
+
+ bool WithinRelMatcher::match(double const& matchee) const {
+ const auto relMargin = m_epsilon * (std::max)(std::fabs(matchee), std::fabs(m_target));
+ return marginComparison(matchee, m_target,
+ std::isinf(relMargin)? 0 : relMargin);
+ }
+
+ std::string WithinRelMatcher::describe() const {
+ Catch::ReusableStringStream sstr;
+ sstr << "and " << m_target << " are within " << m_epsilon * 100. << "% of each other";
+ return sstr.str();
}
}// namespace Floating
-Floating::WithinUlpsMatcher WithinULP(double target, int maxUlpDiff) {
+Floating::WithinUlpsMatcher WithinULP(double target, uint64_t maxUlpDiff) {
return Floating::WithinUlpsMatcher(target, maxUlpDiff, Floating::FloatingPointKind::Double);
}
-Floating::WithinUlpsMatcher WithinULP(float target, int maxUlpDiff) {
+Floating::WithinUlpsMatcher WithinULP(float target, uint64_t maxUlpDiff) {
return Floating::WithinUlpsMatcher(target, maxUlpDiff, Floating::FloatingPointKind::Float);
}
@@ -9438,6 +11546,22 @@ Floating::WithinAbsMatcher WithinAbs(double target, double margin) {
return Floating::WithinAbsMatcher(target, margin);
}
+Floating::WithinRelMatcher WithinRel(double target, double eps) {
+ return Floating::WithinRelMatcher(target, eps);
+}
+
+Floating::WithinRelMatcher WithinRel(double target) {
+ return Floating::WithinRelMatcher(target, std::numeric_limits<double>::epsilon() * 100);
+}
+
+Floating::WithinRelMatcher WithinRel(float target, float eps) {
+ return Floating::WithinRelMatcher(target, eps);
+}
+
+Floating::WithinRelMatcher WithinRel(float target) {
+ return Floating::WithinRelMatcher(target, std::numeric_limits<float>::epsilon() * 100);
+}
+
} // namespace Matchers
} // namespace Catch
@@ -9626,6 +11750,15 @@ namespace Catch {
}
return names.substr(start, end - start + 1);
};
+ auto skipq = [&] (size_t start, char quote) {
+ for (auto i = start + 1; i < names.size() ; ++i) {
+ if (names[i] == quote)
+ return i;
+ if (names[i] == '\\')
+ ++i;
+ }
+ CATCH_INTERNAL_ERROR("CAPTURE parsing encountered unmatched quote");
+ };
size_t start = 0;
std::stack<char> openings;
@@ -9646,18 +11779,22 @@ namespace Catch {
// case '>':
openings.pop();
break;
+ case '"':
+ case '\'':
+ pos = skipq(pos, c);
+ break;
case ',':
- if (start != pos && openings.size() == 0) {
+ if (start != pos && openings.empty()) {
m_messages.emplace_back(macroName, lineInfo, resultType);
- m_messages.back().message = trimmed(start, pos);
+ m_messages.back().message = static_cast<std::string>(trimmed(start, pos));
m_messages.back().message += " := ";
start = pos;
}
}
}
- assert(openings.size() == 0 && "Mismatched openings");
+ assert(openings.empty() && "Mismatched openings");
m_messages.emplace_back(macroName, lineInfo, resultType);
- m_messages.back().message = trimmed(start, names.size() - 1);
+ m_messages.back().message = static_cast<std::string>(trimmed(start, names.size() - 1));
m_messages.back().message += " := ";
}
Capturer::~Capturer() {
@@ -9951,20 +12088,61 @@ namespace Catch {
namespace Catch {
- std::mt19937& rng() {
- static std::mt19937 s_rng;
- return s_rng;
+namespace {
+
+#if defined(_MSC_VER)
+#pragma warning(push)
+#pragma warning(disable:4146) // we negate uint32 during the rotate
+#endif
+ // Safe rotr implementation thanks to John Regehr
+ uint32_t rotate_right(uint32_t val, uint32_t count) {
+ const uint32_t mask = 31;
+ count &= mask;
+ return (val >> count) | (val << (-count & mask));
+ }
+
+#if defined(_MSC_VER)
+#pragma warning(pop)
+#endif
+
+}
+
+ SimplePcg32::SimplePcg32(result_type seed_) {
+ seed(seed_);
}
- void seedRng( IConfig const& config ) {
- if( config.rngSeed() != 0 ) {
- std::srand( config.rngSeed() );
- rng().seed( config.rngSeed() );
+ void SimplePcg32::seed(result_type seed_) {
+ m_state = 0;
+ (*this)();
+ m_state += seed_;
+ (*this)();
+ }
+
+ void SimplePcg32::discard(uint64_t skip) {
+ // We could implement this to run in O(log n) steps, but this
+ // should suffice for our use case.
+ for (uint64_t s = 0; s < skip; ++s) {
+ static_cast<void>((*this)());
}
}
- unsigned int rngSeed() {
- return getCurrentContext().getConfig()->rngSeed();
+ SimplePcg32::result_type SimplePcg32::operator()() {
+ // prepare the output value
+ const uint32_t xorshifted = static_cast<uint32_t>(((m_state >> 18u) ^ m_state) >> 27u);
+ const auto output = rotate_right(xorshifted, m_state >> 59u);
+
+ // advance state
+ m_state = m_state * 6364136223846793005ULL + s_inc;
+
+ return output;
+ }
+
+ bool operator==(SimplePcg32 const& lhs, SimplePcg32 const& rhs) {
+ return lhs.m_state == rhs.m_state;
+ }
+
+ bool operator!=(SimplePcg32 const& lhs, SimplePcg32 const& rhs) {
+ return lhs.m_state != rhs.m_state;
}
}
// end catch_random_number_generator.cpp
@@ -9983,6 +12161,8 @@ namespace Catch {
struct IConfig;
std::vector<TestCase> sortTests( IConfig const& config, std::vector<TestCase> const& unsortedTestCases );
+
+ bool isThrowSafe( TestCase const& testCase, IConfig const& config );
bool matchTest( TestCase const& testCase, TestSpec const& testSpec, IConfig const& config );
void enforceNoDuplicateTestCases( std::vector<TestCase> const& functions );
@@ -10184,6 +12364,9 @@ namespace Catch {
void registerStartupException() noexcept override {
m_exceptionRegistry.add(std::current_exception());
}
+ IMutableEnumValuesRegistry& getMutableEnumValuesRegistry() override {
+ return m_enumValuesRegistry;
+ }
private:
TestRegistry m_testCaseRegistry;
@@ -10191,6 +12374,7 @@ namespace Catch {
ExceptionTranslatorRegistry m_exceptionTranslatorRegistry;
TagAliasRegistry m_tagAliasRegistry;
StartupExceptionRegistry m_exceptionRegistry;
+ Detail::EnumValuesRegistry m_enumValuesRegistry;
};
}
@@ -10486,12 +12670,21 @@ namespace Catch {
m_unfinishedSections.push_back(endInfo);
}
+
+#if defined(CATCH_CONFIG_ENABLE_BENCHMARKING)
+ void RunContext::benchmarkPreparing(std::string const& name) {
+ m_reporter->benchmarkPreparing(name);
+ }
void RunContext::benchmarkStarting( BenchmarkInfo const& info ) {
m_reporter->benchmarkStarting( info );
}
- void RunContext::benchmarkEnded( BenchmarkStats const& stats ) {
+ void RunContext::benchmarkEnded( BenchmarkStats<> const& stats ) {
m_reporter->benchmarkEnded( stats );
}
+ void RunContext::benchmarkFailed(std::string const & error) {
+ m_reporter->benchmarkFailed(error);
+ }
+#endif // CATCH_CONFIG_ENABLE_BENCHMARKING
void RunContext::pushScopedMessage(MessageInfo const & message) {
m_messages.push_back(message);
@@ -10526,7 +12719,7 @@ namespace Catch {
// Don't rebuild the result -- the stringification itself can cause more fatal errors
// Instead, fake a result data.
AssertionResultData tempResult( ResultWas::FatalErrorCondition, { false } );
- tempResult.message = message;
+ tempResult.message = static_cast<std::string>(message);
AssertionResult result(m_lastAssertionInfo, tempResult);
assertionEnded(result);
@@ -10689,7 +12882,7 @@ namespace Catch {
m_lastAssertionInfo = info;
AssertionResultData data( resultType, LazyExpression( false ) );
- data.message = message;
+ data.message = static_cast<std::string>(message);
AssertionResult assertionResult{ m_lastAssertionInfo, data };
assertionEnded( assertionResult );
if( !assertionResult.isOk() )
@@ -10752,6 +12945,18 @@ namespace Catch {
else
CATCH_INTERNAL_ERROR("No result capture instance");
}
+
+ void seedRng(IConfig const& config) {
+ if (config.rngSeed() != 0) {
+ std::srand(config.rngSeed());
+ rng().seed(config.rngSeed());
+ }
+ }
+
+ unsigned int rngSeed() {
+ return getCurrentContext().getConfig()->rngSeed();
+ }
+
}
// end catch_run_context.cpp
// start catch_section.cpp
@@ -10813,7 +13018,7 @@ namespace Catch {
void libIdentify();
int applyCommandLine( int argc, char const * const * argv );
- #if defined(CATCH_CONFIG_WCHAR) && defined(WIN32) && defined(UNICODE)
+ #if defined(CATCH_CONFIG_WCHAR) && defined(_WIN32) && defined(UNICODE)
int applyCommandLine( int argc, wchar_t const * const * argv );
#endif
@@ -10880,6 +13085,8 @@ namespace Catch {
// end catch_version.h
#include <cstdlib>
#include <iomanip>
+#include <set>
+#include <iterator>
namespace Catch {
@@ -10913,45 +13120,61 @@ namespace Catch {
return ret;
}
- Catch::Totals runTests(std::shared_ptr<Config> const& config) {
- auto reporter = makeReporter(config);
-
- 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) {
- bool matching = (!testSpec.hasFilters() && !testCase.isHidden()) ||
- (testSpec.hasFilters() && matchTest(testCase, testSpec, *config));
-
- if (!context.aborting() && matching)
- totals += context.runTest(testCase);
- else
- context.reporter().skipTest(testCase);
+ class TestGroup {
+ public:
+ explicit TestGroup(std::shared_ptr<Config> const& config)
+ : m_config{config}
+ , m_context{config, makeReporter(config)}
+ {
+ auto const& allTestCases = getAllTestCasesSorted(*m_config);
+ m_matches = m_config->testSpec().matchesByFilter(allTestCases, *m_config);
+ auto const& invalidArgs = m_config->testSpec().getInvalidArgs();
+
+ if (m_matches.empty() && invalidArgs.empty()) {
+ for (auto const& test : allTestCases)
+ if (!test.isHidden())
+ m_tests.emplace(&test);
+ } else {
+ for (auto const& match : m_matches)
+ m_tests.insert(match.tests.begin(), match.tests.end());
+ }
}
- if (config->warnAboutNoTests() && totals.testCases.total() == 0) {
- ReusableStringStream testConfig;
+ Totals execute() {
+ auto const& invalidArgs = m_config->testSpec().getInvalidArgs();
+ Totals totals;
+ m_context.testGroupStarting(m_config->name(), 1, 1);
+ for (auto const& testCase : m_tests) {
+ if (!m_context.aborting())
+ totals += m_context.runTest(*testCase);
+ else
+ m_context.reporter().skipTest(*testCase);
+ }
- bool first = true;
- for (const auto& input : config->getTestsOrTags()) {
- if (!first) { testConfig << ' '; }
- first = false;
- testConfig << input;
+ for (auto const& match : m_matches) {
+ if (match.tests.empty()) {
+ m_context.reporter().noMatchingTestCases(match.name);
+ totals.error = -1;
+ }
}
- context.reporter().noMatchingTestCases(testConfig.str());
- totals.error = -1;
+ if (!invalidArgs.empty()) {
+ for (auto const& invalidArg: invalidArgs)
+ m_context.reporter().reportInvalidArguments(invalidArg);
+ }
+
+ m_context.testGroupEnded(m_config->name(), totals, 1, 1);
+ return totals;
}
- context.testGroupEnded(config->name(), totals, 1, 1);
- return totals;
- }
+ private:
+ using Tests = std::set<TestCase const*>;
+
+ std::shared_ptr<Config> m_config;
+ RunContext m_context;
+ Tests m_tests;
+ TestSpec::Matches m_matches;
+ };
void applyFilenamesAsTags(Catch::IConfig const& config) {
auto& tests = const_cast<std::vector<TestCase>&>(getAllTestCasesSorted(config));
@@ -10988,6 +13211,9 @@ namespace Catch {
#if !defined(CATCH_CONFIG_DISABLE_EXCEPTIONS)
const auto& exceptions = getRegistryHub().getStartupExceptionRegistry().getExceptions();
if ( !exceptions.empty() ) {
+ config();
+ getCurrentMutableContext().setConfig(m_config);
+
m_startupExceptions = true;
Colour colourGuard( Colour::Red );
Catch::cerr() << "Errors occurred during startup!" << '\n';
@@ -11017,7 +13243,7 @@ namespace Catch {
}
void Session::libIdentify() {
Catch::cout()
- << std::left << std::setw(16) << "description: " << "A Catch test executable\n"
+ << std::left << std::setw(16) << "description: " << "A Catch2 test executable\n"
<< std::left << std::setw(16) << "category: " << "testframework\n"
<< std::left << std::setw(16) << "framework: " << "Catch Test\n"
<< std::left << std::setw(16) << "version: " << libraryVersion() << std::endl;
@@ -11048,17 +13274,17 @@ namespace Catch {
return 0;
}
-#if defined(CATCH_CONFIG_WCHAR) && defined(WIN32) && defined(UNICODE)
+#if defined(CATCH_CONFIG_WCHAR) && defined(_WIN32) && defined(UNICODE)
int Session::applyCommandLine( int argc, wchar_t const * const * argv ) {
char **utf8Argv = new char *[ argc ];
for ( int i = 0; i < argc; ++i ) {
- int bufSize = WideCharToMultiByte( CP_UTF8, 0, argv[i], -1, NULL, 0, NULL, NULL );
+ int bufSize = WideCharToMultiByte( CP_UTF8, 0, argv[i], -1, nullptr, 0, nullptr, nullptr );
utf8Argv[ i ] = new char[ bufSize ];
- WideCharToMultiByte( CP_UTF8, 0, argv[i], -1, utf8Argv[i], bufSize, NULL, NULL );
+ WideCharToMultiByte( CP_UTF8, 0, argv[i], -1, utf8Argv[i], bufSize, nullptr, nullptr );
}
int returnCode = applyCommandLine( argc, utf8Argv );
@@ -11125,7 +13351,12 @@ namespace Catch {
if( Option<std::size_t> listed = list( m_config ) )
return static_cast<int>( *listed );
- auto totals = runTests( m_config );
+ TestGroup tests { m_config };
+ auto const totals = tests.execute();
+
+ if( m_config->warnAboutNoTests() && totals.error == -1 )
+ return 2;
+
// Note that on unices only the lower 8 bits are usually used, clamping
// the return value to 255 prevents false negative when some multiple
// of 256 tests has failed
@@ -11202,7 +13433,7 @@ namespace Catch {
Catch::IStream::~IStream() = default;
- namespace detail { namespace {
+ namespace Detail { namespace {
template<typename WriterF, std::size_t bufferSize=256>
class StreamBufImpl : public std::streambuf {
char data[bufferSize];
@@ -11301,15 +13532,15 @@ namespace Catch {
auto makeStream( StringRef const &filename ) -> IStream const* {
if( filename.empty() )
- return new detail::CoutStream();
+ return new Detail::CoutStream();
else if( filename[0] == '%' ) {
if( filename == "%debug" )
- return new detail::DebugOutStream();
+ return new Detail::DebugOutStream();
else
CATCH_ERROR( "Unrecognised stream: '" << filename << "'" );
}
else
- return new detail::FileStream( filename );
+ return new Detail::FileStream( filename );
}
// This class encapsulates the idea of a pool of ostringstreams that can be reused.
@@ -11366,6 +13597,7 @@ namespace Catch {
#include <ostream>
#include <cstring>
#include <cctype>
+#include <vector>
namespace Catch {
@@ -11406,6 +13638,18 @@ namespace Catch {
return start != std::string::npos ? str.substr( start, 1+end-start ) : std::string();
}
+ StringRef trim(StringRef ref) {
+ const auto is_ws = [](char c) {
+ return c == ' ' || c == '\t' || c == '\n' || c == '\r';
+ };
+ size_t real_begin = 0;
+ while (real_begin < ref.size() && is_ws(ref[real_begin])) { ++real_begin; }
+ size_t real_end = ref.size();
+ while (real_end > real_begin && is_ws(ref[real_end - 1])) { --real_end; }
+
+ return ref.substr(real_begin, real_end - real_begin);
+ }
+
bool replaceInPlace( std::string& str, std::string const& replaceThis, std::string const& withThis ) {
bool replaced = false;
std::size_t i = str.find( replaceThis );
@@ -11420,6 +13664,21 @@ namespace Catch {
return replaced;
}
+ std::vector<StringRef> splitStringRef( StringRef str, char delimiter ) {
+ std::vector<StringRef> subStrings;
+ std::size_t start = 0;
+ for(std::size_t pos = 0; pos < str.size(); ++pos ) {
+ if( str[pos] == delimiter ) {
+ if( pos - start > 1 )
+ subStrings.push_back( str.substr( start, pos-start ) );
+ start = pos+1;
+ }
+ }
+ if( start < str.size() )
+ subStrings.push_back( str.substr( start, str.size()-start ) );
+ return subStrings;
+ }
+
pluralise::pluralise( std::size_t count, std::string const& label )
: m_count( count ),
m_label( label )
@@ -11436,123 +13695,46 @@ namespace Catch {
// end catch_string_manip.cpp
// start catch_stringref.cpp
-#if defined(__clang__)
-# pragma clang diagnostic push
-# pragma clang diagnostic ignored "-Wexit-time-destructors"
-#endif
-
+#include <algorithm>
#include <ostream>
#include <cstring>
#include <cstdint>
-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
: StringRef( rawChars, static_cast<StringRef::size_type>(std::strlen(rawChars) ) )
{}
- StringRef::operator std::string() const {
- return std::string( m_start, m_size );
- }
-
- void StringRef::swap( StringRef& other ) noexcept {
- std::swap( m_start, other.m_start );
- std::swap( m_size, other.m_size );
- std::swap( m_data, other.m_data );
- }
-
auto StringRef::c_str() const -> char const* {
- if( isSubstring() )
- const_cast<StringRef*>( this )->takeOwnership();
+ CATCH_ENFORCE(isNullTerminated(), "Called StringRef::c_str() on a non-null-terminated instance");
return m_start;
}
- auto StringRef::currentData() const noexcept -> char const* {
+ auto StringRef::data() const noexcept -> char const* {
return m_start;
}
- auto StringRef::isOwned() const noexcept -> bool {
- return m_data != nullptr;
- }
- auto StringRef::isSubstring() const noexcept -> bool {
- return m_start[m_size] != '\0';
- }
-
- void StringRef::takeOwnership() {
- if( !isOwned() ) {
- m_data = new char[m_size+1];
- memcpy( m_data, m_start, m_size );
- m_data[m_size] = '\0';
- m_start = m_data;
- }
- }
auto StringRef::substr( size_type start, size_type size ) const noexcept -> StringRef {
- if( start < m_size )
- return StringRef( m_start+start, size );
- else
+ if (start < m_size) {
+ return StringRef(m_start + start, (std::min)(m_size - start, size));
+ } else {
return StringRef();
- }
- auto StringRef::operator == ( StringRef const& other ) const noexcept -> bool {
- return
- size() == other.size() &&
- (std::strncmp( m_start, other.m_start, size() ) == 0);
- }
- auto StringRef::operator != ( StringRef const& other ) const noexcept -> bool {
- return !operator==( other );
- }
-
- auto StringRef::operator[](size_type index) const noexcept -> char {
- return m_start[index];
- }
-
- 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 & 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--;
- }
}
- return noChars;
- }
-
- auto operator + ( StringRef const& lhs, StringRef const& rhs ) -> std::string {
- std::string str;
- str.reserve( lhs.size() + rhs.size() );
- str += lhs;
- str += rhs;
- return str;
- }
- auto operator + ( StringRef const& lhs, const char* rhs ) -> std::string {
- return std::string( lhs ) + std::string( rhs );
}
- auto operator + ( char const* lhs, StringRef const& rhs ) -> std::string {
- return std::string( lhs ) + std::string( rhs );
+ auto StringRef::operator == ( StringRef const& other ) const noexcept -> bool {
+ return m_size == other.m_size
+ && (std::memcmp( m_start, other.m_start, m_size ) == 0);
}
auto operator << ( std::ostream& os, StringRef const& str ) -> std::ostream& {
- return os.write(str.currentData(), str.size());
+ return os.write(str.data(), str.size());
}
auto operator+=( std::string& lhs, StringRef const& rhs ) -> std::string& {
- lhs.append(rhs.currentData(), rhs.size());
+ lhs.append(rhs.data(), rhs.size());
return lhs;
}
} // namespace Catch
-
-#if defined(__clang__)
-# pragma clang diagnostic pop
-#endif
// end catch_stringref.cpp
// start catch_tag_alias.cpp
@@ -11671,8 +13853,7 @@ namespace Catch {
std::vector<std::string> tags;
std::string desc, tag;
bool inTag = false;
- std::string _descOrTags = nameAndTags.tags;
- for (char c : _descOrTags) {
+ for (char c : nameAndTags.tags) {
if( !inTag ) {
if( c == '[' )
inTag = true;
@@ -11702,10 +13883,11 @@ namespace Catch {
}
}
if( isHidden ) {
- tags.push_back( "." );
+ // Add all "hidden" tags to make them behave identically
+ tags.insert( tags.end(), { ".", "!hide" } );
}
- TestCaseInfo info( nameAndTags.name, _className, desc, tags, _lineInfo );
+ TestCaseInfo info( static_cast<std::string>(nameAndTags.name), _className, desc, tags, _lineInfo );
return TestCase( _testCase, std::move(info) );
}
@@ -11819,8 +14001,13 @@ namespace Catch {
}
return sorted;
}
+
+ bool isThrowSafe( TestCase const& testCase, IConfig const& config ) {
+ return !testCase.throws() || config.allowThrows();
+ }
+
bool matchTest( TestCase const& testCase, TestSpec const& testSpec, IConfig const& config ) {
- return testSpec.matches( testCase ) && ( config.allowThrows() || !testCase.throws() );
+ return testSpec.matches( testCase ) && isThrowSafe( testCase, config );
}
void enforceNoDuplicateTestCases( std::vector<TestCase> const& functions ) {
@@ -11881,7 +14068,7 @@ namespace Catch {
}
std::string extractClassName( StringRef const& classOrQualifiedMethodName ) {
- std::string className = classOrQualifiedMethodName;
+ std::string className(classOrQualifiedMethodName);
if( startsWith( className, '&' ) )
{
std::size_t lastColons = className.rfind( "::" );
@@ -12023,7 +14210,7 @@ namespace TestCaseTracking {
m_runState = CompletedSuccessfully;
break;
case ExecutingChildren:
- if( m_children.empty() || m_children.back()->isComplete() )
+ if( std::all_of(m_children.begin(), m_children.end(), [](ITrackerPtr const& t){ return t->isComplete(); }) )
m_runState = CompletedSuccessfully;
break;
@@ -12058,7 +14245,8 @@ namespace TestCaseTracking {
}
SectionTracker::SectionTracker( NameAndLocation const& nameAndLocation, TrackerContext& ctx, ITracker* parent )
- : TrackerBase( nameAndLocation, ctx, parent )
+ : TrackerBase( nameAndLocation, ctx, parent ),
+ m_trimmed_name(trim(nameAndLocation.name))
{
if( parent ) {
while( !parent->isSectionTracker() )
@@ -12072,12 +14260,11 @@ namespace TestCaseTracking {
bool SectionTracker::isComplete() const {
bool complete = true;
- if ((m_filters.empty() || m_filters[0] == "") ||
- std::find(m_filters.begin(), m_filters.end(),
- m_nameAndLocation.name) != m_filters.end())
+ if ((m_filters.empty() || m_filters[0] == "")
+ || std::find(m_filters.begin(), m_filters.end(), m_trimmed_name) != m_filters.end()) {
complete = TrackerBase::isComplete();
+ }
return complete;
-
}
bool SectionTracker::isSectionTracker() const { return true; }
@@ -12101,20 +14288,21 @@ namespace TestCaseTracking {
}
void SectionTracker::tryOpen() {
- if( !isComplete() && (m_filters.empty() || m_filters[0].empty() || m_filters[0] == m_nameAndLocation.name ) )
+ if( !isComplete() )
open();
}
void SectionTracker::addInitialFilters( std::vector<std::string> const& filters ) {
if( !filters.empty() ) {
- m_filters.push_back(""); // Root - should never be consulted
- m_filters.push_back(""); // Test Case - not a section filter
+ m_filters.reserve( m_filters.size() + filters.size() + 2 );
+ m_filters.emplace_back(""); // Root - should never be consulted
+ m_filters.emplace_back(""); // Test Case - not a section filter
m_filters.insert( m_filters.end(), filters.begin(), filters.end() );
}
}
void SectionTracker::addNextFilters( std::vector<std::string> const& filters ) {
if( filters.size() > 1 )
- m_filters.insert( m_filters.end(), ++filters.begin(), filters.end() );
+ m_filters.insert( m_filters.end(), filters.begin()+1, filters.end() );
}
} // namespace TestCaseTracking
@@ -12166,47 +14354,81 @@ namespace Catch {
namespace Catch {
+ TestSpec::Pattern::Pattern( std::string const& name )
+ : m_name( name )
+ {}
+
TestSpec::Pattern::~Pattern() = default;
- TestSpec::NamePattern::~NamePattern() = default;
- TestSpec::TagPattern::~TagPattern() = default;
- TestSpec::ExcludedPattern::~ExcludedPattern() = default;
- TestSpec::NamePattern::NamePattern( std::string const& name )
- : m_wildcardPattern( toLower( name ), CaseSensitive::No )
+ std::string const& TestSpec::Pattern::name() const {
+ return m_name;
+ }
+
+ TestSpec::NamePattern::NamePattern( std::string const& name, std::string const& filterString )
+ : Pattern( filterString )
+ , m_wildcardPattern( toLower( name ), CaseSensitive::No )
{}
+
bool TestSpec::NamePattern::matches( TestCaseInfo const& testCase ) const {
- return m_wildcardPattern.matches( toLower( testCase.name ) );
+ return m_wildcardPattern.matches( testCase.name );
}
- TestSpec::TagPattern::TagPattern( std::string const& tag ) : m_tag( toLower( tag ) ) {}
+ TestSpec::TagPattern::TagPattern( std::string const& tag, std::string const& filterString )
+ : Pattern( filterString )
+ , m_tag( toLower( tag ) )
+ {}
+
bool TestSpec::TagPattern::matches( TestCaseInfo const& testCase ) const {
return std::find(begin(testCase.lcaseTags),
end(testCase.lcaseTags),
m_tag) != end(testCase.lcaseTags);
}
- TestSpec::ExcludedPattern::ExcludedPattern( PatternPtr const& underlyingPattern ) : m_underlyingPattern( underlyingPattern ) {}
- bool TestSpec::ExcludedPattern::matches( TestCaseInfo const& testCase ) const { return !m_underlyingPattern->matches( testCase ); }
+ TestSpec::ExcludedPattern::ExcludedPattern( PatternPtr const& underlyingPattern )
+ : Pattern( underlyingPattern->name() )
+ , m_underlyingPattern( underlyingPattern )
+ {}
+
+ bool TestSpec::ExcludedPattern::matches( TestCaseInfo const& testCase ) const {
+ return !m_underlyingPattern->matches( testCase );
+ }
bool TestSpec::Filter::matches( TestCaseInfo const& testCase ) const {
- // All patterns in a filter must match for the filter to be a match
- for( auto const& pattern : m_patterns ) {
- if( !pattern->matches( testCase ) )
- return false;
- }
- return true;
+ return std::all_of( m_patterns.begin(), m_patterns.end(), [&]( PatternPtr const& p ){ return p->matches( testCase ); } );
+ }
+
+ std::string TestSpec::Filter::name() const {
+ std::string name;
+ for( auto const& p : m_patterns )
+ name += p->name();
+ return name;
}
bool TestSpec::hasFilters() const {
return !m_filters.empty();
}
+
bool TestSpec::matches( TestCaseInfo const& testCase ) const {
- // A TestSpec matches if any filter matches
- for( auto const& filter : m_filters )
- if( filter.matches( testCase ) )
- return true;
- return false;
+ return std::any_of( m_filters.begin(), m_filters.end(), [&]( Filter const& f ){ return f.matches( testCase ); } );
+ }
+
+ TestSpec::Matches TestSpec::matchesByFilter( std::vector<TestCase> const& testCases, IConfig const& config ) const
+ {
+ Matches matches( m_filters.size() );
+ std::transform( m_filters.begin(), m_filters.end(), matches.begin(), [&]( Filter const& filter ){
+ std::vector<TestCase const*> currentMatches;
+ for( auto const& test : testCases )
+ if( isThrowSafe( test, config ) && filter.matches( test ) )
+ currentMatches.emplace_back( &test );
+ return FilterMatch{ filter.name(), currentMatches };
+ } );
+ return matches;
+ }
+
+ const TestSpec::vectorStrings& TestSpec::getInvalidArgs() const{
+ return (m_invalidArgs);
}
+
}
// end catch_test_spec.cpp
// start catch_test_spec_parser.cpp
@@ -12218,64 +14440,136 @@ namespace Catch {
TestSpecParser& TestSpecParser::parse( std::string const& arg ) {
m_mode = None;
m_exclusion = false;
- m_start = std::string::npos;
m_arg = m_tagAliases->expandAliases( arg );
m_escapeChars.clear();
+ m_substring.reserve(m_arg.size());
+ m_patternName.reserve(m_arg.size());
+ m_realPatternPos = 0;
+
for( m_pos = 0; m_pos < m_arg.size(); ++m_pos )
- visitChar( m_arg[m_pos] );
- if( m_mode == Name )
- addPattern<TestSpec::NamePattern>();
+ //if visitChar fails
+ if( !visitChar( m_arg[m_pos] ) ){
+ m_testSpec.m_invalidArgs.push_back(arg);
+ break;
+ }
+ endMode();
return *this;
}
TestSpec TestSpecParser::testSpec() {
addFilter();
return m_testSpec;
}
+ bool TestSpecParser::visitChar( char c ) {
+ if( (m_mode != EscapedName) && (c == '\\') ) {
+ escape();
+ addCharToPattern(c);
+ return true;
+ }else if((m_mode != EscapedName) && (c == ',') ) {
+ return separate();
+ }
- void TestSpecParser::visitChar( char c ) {
- if( m_mode == None ) {
- switch( c ) {
- case ' ': return;
- case '~': m_exclusion = true; return;
- case '[': return startNewMode( Tag, ++m_pos );
- case '"': return startNewMode( QuotedName, ++m_pos );
- case '\\': return escape();
- default: startNewMode( Name, m_pos ); break;
- }
+ switch( m_mode ) {
+ case None:
+ if( processNoneChar( c ) )
+ return true;
+ break;
+ case Name:
+ processNameChar( c );
+ break;
+ case EscapedName:
+ endMode();
+ addCharToPattern(c);
+ return true;
+ default:
+ case Tag:
+ case QuotedName:
+ if( processOtherChar( c ) )
+ return true;
+ break;
}
- if( m_mode == Name ) {
- if( c == ',' ) {
- addPattern<TestSpec::NamePattern>();
- addFilter();
- }
- else if( c == '[' ) {
- if( subString() == "exclude:" )
- m_exclusion = true;
- else
- addPattern<TestSpec::NamePattern>();
- startNewMode( Tag, ++m_pos );
- }
- else if( c == '\\' )
- escape();
+
+ m_substring += c;
+ if( !isControlChar( c ) ) {
+ m_patternName += c;
+ m_realPatternPos++;
+ }
+ return true;
+ }
+ // Two of the processing methods return true to signal the caller to return
+ // without adding the given character to the current pattern strings
+ bool TestSpecParser::processNoneChar( char c ) {
+ switch( c ) {
+ case ' ':
+ return true;
+ case '~':
+ m_exclusion = true;
+ return false;
+ case '[':
+ startNewMode( Tag );
+ return false;
+ case '"':
+ startNewMode( QuotedName );
+ return false;
+ default:
+ startNewMode( Name );
+ return false;
+ }
+ }
+ void TestSpecParser::processNameChar( char c ) {
+ if( c == '[' ) {
+ if( m_substring == "exclude:" )
+ m_exclusion = true;
+ else
+ endMode();
+ startNewMode( Tag );
}
- else if( m_mode == EscapedName )
- m_mode = Name;
- else if( m_mode == QuotedName && c == '"' )
- addPattern<TestSpec::NamePattern>();
- else if( m_mode == Tag && c == ']' )
- addPattern<TestSpec::TagPattern>();
}
- void TestSpecParser::startNewMode( Mode mode, std::size_t start ) {
+ bool TestSpecParser::processOtherChar( char c ) {
+ if( !isControlChar( c ) )
+ return false;
+ m_substring += c;
+ endMode();
+ return true;
+ }
+ void TestSpecParser::startNewMode( Mode mode ) {
m_mode = mode;
- m_start = start;
+ }
+ void TestSpecParser::endMode() {
+ switch( m_mode ) {
+ case Name:
+ case QuotedName:
+ return addNamePattern();
+ case Tag:
+ return addTagPattern();
+ case EscapedName:
+ revertBackToLastMode();
+ return;
+ case None:
+ default:
+ return startNewMode( None );
+ }
}
void TestSpecParser::escape() {
- if( m_mode == None )
- m_start = m_pos;
+ saveLastMode();
m_mode = EscapedName;
- m_escapeChars.push_back( m_pos );
+ m_escapeChars.push_back(m_realPatternPos);
+ }
+ bool TestSpecParser::isControlChar( char c ) const {
+ switch( m_mode ) {
+ default:
+ return false;
+ case None:
+ return c == '~';
+ case Name:
+ return c == '[';
+ case EscapedName:
+ return true;
+ case QuotedName:
+ return c == '"';
+ case Tag:
+ return c == '[' || c == ']';
+ }
}
- std::string TestSpecParser::subString() const { return m_arg.substr( m_start, m_pos - m_start ); }
void TestSpecParser::addFilter() {
if( !m_currentFilter.m_patterns.empty() ) {
@@ -12284,6 +14578,84 @@ namespace Catch {
}
}
+ void TestSpecParser::saveLastMode() {
+ lastMode = m_mode;
+ }
+
+ void TestSpecParser::revertBackToLastMode() {
+ m_mode = lastMode;
+ }
+
+ bool TestSpecParser::separate() {
+ if( (m_mode==QuotedName) || (m_mode==Tag) ){
+ //invalid argument, signal failure to previous scope.
+ m_mode = None;
+ m_pos = m_arg.size();
+ m_substring.clear();
+ m_patternName.clear();
+ return false;
+ }
+ endMode();
+ addFilter();
+ return true; //success
+ }
+
+ std::string TestSpecParser::preprocessPattern() {
+ std::string token = m_patternName;
+ for (std::size_t i = 0; i < m_escapeChars.size(); ++i)
+ token = token.substr(0, m_escapeChars[i] - i) + token.substr(m_escapeChars[i] - i + 1);
+ m_escapeChars.clear();
+ if (startsWith(token, "exclude:")) {
+ m_exclusion = true;
+ token = token.substr(8);
+ }
+
+ m_patternName.clear();
+
+ return token;
+ }
+
+ void TestSpecParser::addNamePattern() {
+ auto token = preprocessPattern();
+
+ if (!token.empty()) {
+ TestSpec::PatternPtr pattern = std::make_shared<TestSpec::NamePattern>(token, m_substring);
+ if (m_exclusion)
+ pattern = std::make_shared<TestSpec::ExcludedPattern>(pattern);
+ m_currentFilter.m_patterns.push_back(pattern);
+ }
+ m_substring.clear();
+ m_exclusion = false;
+ m_mode = None;
+ }
+
+ void TestSpecParser::addTagPattern() {
+ auto token = preprocessPattern();
+
+ if (!token.empty()) {
+ // If the tag pattern is the "hide and tag" shorthand (e.g. [.foo])
+ // we have to create a separate hide tag and shorten the real one
+ if (token.size() > 1 && token[0] == '.') {
+ token.erase(token.begin());
+ TestSpec::PatternPtr pattern = std::make_shared<TestSpec::TagPattern>(".", m_substring);
+ if (m_exclusion) {
+ pattern = std::make_shared<TestSpec::ExcludedPattern>(pattern);
+ }
+ m_currentFilter.m_patterns.push_back(pattern);
+ }
+
+ TestSpec::PatternPtr pattern = std::make_shared<TestSpec::TagPattern>(token, m_substring);
+
+ if (m_exclusion) {
+ pattern = std::make_shared<TestSpec::ExcludedPattern>(pattern);
+ }
+ m_currentFilter.m_patterns.push_back(pattern);
+ }
+ m_substring.clear();
+ m_exclusion = false;
+ m_mode = None;
+ }
+
TestSpec parseTestSpec( std::string const& arg ) {
return TestSpecParser( ITagAliasRegistry::get() ).parse( arg ).testSpec();
}
@@ -12385,13 +14757,11 @@ namespace Detail {
enum Arch { Big, Little };
static Arch which() {
- union _{
- int asInt;
- char asChar[sizeof (int)];
- } u;
-
- u.asInt = 1;
- return ( u.asChar[sizeof(int)-1] == 1 ) ? Big : Little;
+ int one = 1;
+ // If the lowest byte we read is non-zero, we can assume
+ // that little endian format is used.
+ auto value = *reinterpret_cast<char*>(&one);
+ return value ? Little : Big;
}
};
}
@@ -12515,6 +14885,13 @@ std::string StringMaker<wchar_t *>::convert(wchar_t * str) {
}
#endif
+#if defined(CATCH_CONFIG_CPP17_BYTE)
+#include <cstddef>
+std::string StringMaker<std::byte>::convert(std::byte value) {
+ return ::Catch::Detail::stringify(std::to_integer<unsigned long long>(value));
+}
+#endif // defined(CATCH_CONFIG_CPP17_BYTE)
+
std::string StringMaker<int>::convert(int value) {
return ::Catch::Detail::stringify(static_cast<long long>(value));
}
@@ -12577,11 +14954,16 @@ std::string StringMaker<std::nullptr_t>::convert(std::nullptr_t) {
return "nullptr";
}
+int StringMaker<float>::precision = 5;
+
std::string StringMaker<float>::convert(float value) {
- return fpToString(value, 5) + 'f';
+ return fpToString(value, precision) + 'f';
}
+
+int StringMaker<double>::precision = 10;
+
std::string StringMaker<double>::convert(double value) {
- return fpToString(value, 10);
+ return fpToString(value, precision);
}
std::string ratio_string<std::atto>::symbol() { return "a"; }
@@ -12699,7 +15081,7 @@ namespace Catch {
}
Version const& libraryVersion() {
- static Version version( 2, 7, 2, "", 0 );
+ static Version version( 2, 11, 2, "", 0 );
return version;
}
@@ -12707,14 +15089,12 @@ namespace Catch {
// end catch_version.cpp
// start catch_wildcard_pattern.cpp
-#include <sstream>
-
namespace Catch {
WildcardPattern::WildcardPattern( std::string const& pattern,
CaseSensitive::Choice caseSensitivity )
: m_caseSensitivity( caseSensitivity ),
- m_pattern( adjustCase( pattern ) )
+ m_pattern( normaliseString( pattern ) )
{
if( startsWith( m_pattern, '*' ) ) {
m_pattern = m_pattern.substr( 1 );
@@ -12729,28 +15109,27 @@ namespace Catch {
bool WildcardPattern::matches( std::string const& str ) const {
switch( m_wildcard ) {
case NoWildcard:
- return m_pattern == adjustCase( str );
+ return m_pattern == normaliseString( str );
case WildcardAtStart:
- return endsWith( adjustCase( str ), m_pattern );
+ return endsWith( normaliseString( str ), m_pattern );
case WildcardAtEnd:
- return startsWith( adjustCase( str ), m_pattern );
+ return startsWith( normaliseString( str ), m_pattern );
case WildcardAtBothEnds:
- return contains( adjustCase( str ), m_pattern );
+ return contains( normaliseString( str ), m_pattern );
default:
CATCH_INTERNAL_ERROR( "Unknown enum" );
}
}
- std::string WildcardPattern::adjustCase( std::string const& str ) const {
- return m_caseSensitivity == CaseSensitive::No ? toLower( str ) : str;
+ std::string WildcardPattern::normaliseString( std::string const& str ) const {
+ return trim( m_caseSensitivity == CaseSensitive::No ? toLower( str ) : str );
}
}
// end catch_wildcard_pattern.cpp
// start catch_xmlwriter.cpp
#include <iomanip>
-
-using uchar = unsigned char;
+#include <type_traits>
namespace Catch {
@@ -12790,8 +15169,30 @@ namespace {
os.flags(f);
}
+ bool shouldNewline(XmlFormatting fmt) {
+ return !!(static_cast<std::underlying_type<XmlFormatting>::type>(fmt & XmlFormatting::Newline));
+ }
+
+ bool shouldIndent(XmlFormatting fmt) {
+ return !!(static_cast<std::underlying_type<XmlFormatting>::type>(fmt & XmlFormatting::Indent));
+ }
+
} // anonymous namespace
+ XmlFormatting operator | (XmlFormatting lhs, XmlFormatting rhs) {
+ return static_cast<XmlFormatting>(
+ static_cast<std::underlying_type<XmlFormatting>::type>(lhs) |
+ static_cast<std::underlying_type<XmlFormatting>::type>(rhs)
+ );
+ }
+
+ XmlFormatting operator & (XmlFormatting lhs, XmlFormatting rhs) {
+ return static_cast<XmlFormatting>(
+ static_cast<std::underlying_type<XmlFormatting>::type>(lhs) &
+ static_cast<std::underlying_type<XmlFormatting>::type>(rhs)
+ );
+ }
+
XmlEncode::XmlEncode( std::string const& str, ForWhat forWhat )
: m_str( str ),
m_forWhat( forWhat )
@@ -12802,7 +15203,7 @@ namespace {
// (see: http://www.w3.org/TR/xml/#syntax)
for( std::size_t idx = 0; idx < m_str.size(); ++ idx ) {
- uchar c = m_str[idx];
+ unsigned char c = m_str[idx];
switch (c) {
case '<': os << "&lt;"; break;
case '&': os << "&amp;"; break;
@@ -12862,7 +15263,7 @@ namespace {
bool valid = true;
uint32_t value = headerValue(c);
for (std::size_t n = 1; n < encBytes; ++n) {
- uchar nc = m_str[idx + n];
+ unsigned char nc = m_str[idx + n];
valid &= ((nc & 0xC0) == 0x80);
value = (value << 6) | (nc & 0x3F);
}
@@ -12896,13 +15297,17 @@ namespace {
return os;
}
- XmlWriter::ScopedElement::ScopedElement( XmlWriter* writer )
- : m_writer( writer )
+ XmlWriter::ScopedElement::ScopedElement( XmlWriter* writer, XmlFormatting fmt )
+ : m_writer( writer ),
+ m_fmt(fmt)
{}
XmlWriter::ScopedElement::ScopedElement( ScopedElement&& other ) noexcept
- : m_writer( other.m_writer ){
+ : m_writer( other.m_writer ),
+ m_fmt(other.m_fmt)
+ {
other.m_writer = nullptr;
+ other.m_fmt = XmlFormatting::None;
}
XmlWriter::ScopedElement& XmlWriter::ScopedElement::operator=( ScopedElement&& other ) noexcept {
if ( m_writer ) {
@@ -12910,16 +15315,19 @@ namespace {
}
m_writer = other.m_writer;
other.m_writer = nullptr;
+ m_fmt = other.m_fmt;
+ other.m_fmt = XmlFormatting::None;
return *this;
}
XmlWriter::ScopedElement::~ScopedElement() {
- if( m_writer )
- m_writer->endElement();
+ if (m_writer) {
+ m_writer->endElement(m_fmt);
+ }
}
- XmlWriter::ScopedElement& XmlWriter::ScopedElement::writeText( std::string const& text, bool indent ) {
- m_writer->writeText( text, indent );
+ XmlWriter::ScopedElement& XmlWriter::ScopedElement::writeText( std::string const& text, XmlFormatting fmt ) {
+ m_writer->writeText( text, fmt );
return *this;
}
@@ -12929,37 +15337,47 @@ namespace {
}
XmlWriter::~XmlWriter() {
- while( !m_tags.empty() )
+ while (!m_tags.empty()) {
endElement();
+ }
+ newlineIfNecessary();
}
- XmlWriter& XmlWriter::startElement( std::string const& name ) {
+ XmlWriter& XmlWriter::startElement( std::string const& name, XmlFormatting fmt ) {
ensureTagClosed();
newlineIfNecessary();
- m_os << m_indent << '<' << name;
+ if (shouldIndent(fmt)) {
+ m_os << m_indent;
+ m_indent += " ";
+ }
+ m_os << '<' << name;
m_tags.push_back( name );
- m_indent += " ";
m_tagIsOpen = true;
+ applyFormatting(fmt);
return *this;
}
- XmlWriter::ScopedElement XmlWriter::scopedElement( std::string const& name ) {
- ScopedElement scoped( this );
- startElement( name );
+ XmlWriter::ScopedElement XmlWriter::scopedElement( std::string const& name, XmlFormatting fmt ) {
+ ScopedElement scoped( this, fmt );
+ startElement( name, fmt );
return scoped;
}
- XmlWriter& XmlWriter::endElement() {
- newlineIfNecessary();
- m_indent = m_indent.substr( 0, m_indent.size()-2 );
+ XmlWriter& XmlWriter::endElement(XmlFormatting fmt) {
+ m_indent = m_indent.substr(0, m_indent.size() - 2);
+
if( m_tagIsOpen ) {
m_os << "/>";
m_tagIsOpen = false;
+ } else {
+ newlineIfNecessary();
+ if (shouldIndent(fmt)) {
+ m_os << m_indent;
+ }
+ m_os << "</" << m_tags.back() << ">";
}
- else {
- m_os << m_indent << "</" << m_tags.back() << ">";
- }
- m_os << std::endl;
+ m_os << std::flush;
+ applyFormatting(fmt);
m_tags.pop_back();
return *this;
}
@@ -12975,22 +15393,26 @@ namespace {
return *this;
}
- XmlWriter& XmlWriter::writeText( std::string const& text, bool indent ) {
+ XmlWriter& XmlWriter::writeText( std::string const& text, XmlFormatting fmt) {
if( !text.empty() ){
bool tagWasOpen = m_tagIsOpen;
ensureTagClosed();
- if( tagWasOpen && indent )
+ if (tagWasOpen && shouldIndent(fmt)) {
m_os << m_indent;
+ }
m_os << XmlEncode( text );
- m_needsNewline = true;
+ applyFormatting(fmt);
}
return *this;
}
- XmlWriter& XmlWriter::writeComment( std::string const& text ) {
+ XmlWriter& XmlWriter::writeComment( std::string const& text, XmlFormatting fmt) {
ensureTagClosed();
- m_os << m_indent << "<!--" << text << "-->";
- m_needsNewline = true;
+ if (shouldIndent(fmt)) {
+ m_os << m_indent;
+ }
+ m_os << "<!--" << text << "-->";
+ applyFormatting(fmt);
return *this;
}
@@ -13006,11 +15428,16 @@ namespace {
void XmlWriter::ensureTagClosed() {
if( m_tagIsOpen ) {
- m_os << ">" << std::endl;
+ m_os << '>' << std::flush;
+ newlineIfNecessary();
m_tagIsOpen = false;
}
}
+ void XmlWriter::applyFormatting(XmlFormatting fmt) {
+ m_needsNewline = shouldNewline(fmt);
+ }
+
void XmlWriter::writeDeclaration() {
m_os << "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n";
}
@@ -13286,24 +15713,25 @@ private:
if (itMessage == messages.end())
return;
- // using messages.end() directly yields (or auto) compilation error:
- std::vector<MessageInfo>::const_iterator itEnd = messages.end();
- const std::size_t N = static_cast<std::size_t>(std::distance(itMessage, itEnd));
+ const auto itEnd = messages.cend();
+ const auto N = static_cast<std::size_t>(std::distance(itMessage, itEnd));
{
Colour colourGuard(colour);
stream << " with " << pluralise(N, "message") << ':';
}
- for (; itMessage != itEnd; ) {
+ while (itMessage != itEnd) {
// If this assertion is a warning ignore any INFO messages
if (printInfoMessages || itMessage->type != ResultWas::Info) {
- stream << " '" << itMessage->message << '\'';
- if (++itMessage != itEnd) {
+ printMessage();
+ if (itMessage != itEnd) {
Colour colourGuard(dimColour());
stream << " and";
}
+ continue;
}
+ ++itMessage;
}
}
@@ -13376,8 +15804,13 @@ private:
#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
+
+#if defined(__clang__)
+# pragma clang diagnostic push
+// For simplicity, benchmarking-only helpers are always enabled
+# pragma clang diagnostic ignored "-Wunused-function"
#endif
namespace Catch {
@@ -13559,11 +15992,11 @@ class Duration {
static const uint64_t s_nanosecondsInASecond = 1000 * s_nanosecondsInAMillisecond;
static const uint64_t s_nanosecondsInAMinute = 60 * s_nanosecondsInASecond;
- uint64_t m_inNanoseconds;
+ double m_inNanoseconds;
Unit m_units;
public:
- explicit Duration(uint64_t inNanoseconds, Unit units = Unit::Auto)
+ explicit Duration(double inNanoseconds, Unit units = Unit::Auto)
: m_inNanoseconds(inNanoseconds),
m_units(units) {
if (m_units == Unit::Auto) {
@@ -13592,7 +16025,7 @@ public:
case Unit::Minutes:
return m_inNanoseconds / static_cast<double>(s_nanosecondsInAMinute);
default:
- return static_cast<double>(m_inNanoseconds);
+ return m_inNanoseconds;
}
}
auto unitsAsString() const -> std::string {
@@ -13613,7 +16046,7 @@ public:
}
friend auto operator << (std::ostream& os, Duration const& duration) -> std::ostream& {
- return os << duration.value() << " " << duration.unitsAsString();
+ return os << duration.value() << ' ' << duration.unitsAsString();
}
};
} // end anon namespace
@@ -13638,10 +16071,16 @@ public:
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";
+
+ Columns headerCols;
+ Spacer spacer(2);
+ for (auto const& info : m_columnInfos) {
+ headerCols += Column(info.name).width(static_cast<std::size_t>(info.width - 2));
+ headerCols += spacer;
+ }
+ m_os << headerCols << '\n';
+
+ m_os << Catch::getLineOfChars<'-'>() << '\n';
}
}
void close() {
@@ -13660,30 +16099,29 @@ public:
friend TablePrinter& operator << (TablePrinter& tp, ColumnBreak) {
auto colStr = tp.m_oss.str();
- // This takes account of utf8 encodings
- auto strSize = Catch::StringRef(colStr).numberOfCharacters();
+ const auto strSize = colStr.size();
tp.m_oss.str("");
tp.open();
if (tp.m_currentColumn == static_cast<int>(tp.m_columnInfos.size() - 1)) {
tp.m_currentColumn = -1;
- tp.m_os << "\n";
+ tp.m_os << '\n';
}
tp.m_currentColumn++;
auto colInfo = tp.m_columnInfos[tp.m_currentColumn];
- auto padding = (strSize + 2 < static_cast<std::size_t>(colInfo.width))
- ? std::string(colInfo.width - (strSize + 2), ' ')
+ auto padding = (strSize + 1 < static_cast<std::size_t>(colInfo.width))
+ ? std::string(colInfo.width - (strSize + 1), ' ')
: std::string();
if (colInfo.justification == ColumnInfo::Left)
- tp.m_os << colStr << padding << " ";
+ tp.m_os << colStr << padding << ' ';
else
- tp.m_os << padding << colStr << " ";
+ tp.m_os << padding << colStr << ' ';
return tp;
}
friend TablePrinter& operator << (TablePrinter& tp, RowBreak) {
if (tp.m_currentColumn > 0) {
- tp.m_os << "\n";
+ tp.m_os << '\n';
tp.m_currentColumn = -1;
}
return tp;
@@ -13693,12 +16131,26 @@ public:
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 }
- })) {}
+ [&config]() -> std::vector<ColumnInfo> {
+ if (config.fullConfig()->benchmarkNoAnalysis())
+ {
+ return{
+ { "benchmark name", CATCH_CONFIG_CONSOLE_WIDTH - 43, ColumnInfo::Left },
+ { " samples", 14, ColumnInfo::Right },
+ { " iterations", 14, ColumnInfo::Right },
+ { " mean", 14, ColumnInfo::Right }
+ };
+ }
+ else
+ {
+ return{
+ { "benchmark name", CATCH_CONFIG_CONSOLE_WIDTH - 32, ColumnInfo::Left },
+ { "samples mean std dev", 14, ColumnInfo::Right },
+ { "iterations low mean low std dev", 14, ColumnInfo::Right },
+ { "estimated high mean high std dev", 14, ColumnInfo::Right }
+ };
+ }
+ }())) {}
ConsoleReporter::~ConsoleReporter() = default;
std::string ConsoleReporter::getDescription() {
@@ -13709,6 +16161,10 @@ void ConsoleReporter::noMatchingTestCases(std::string const& spec) {
stream << "No test cases matched '" << spec << '\'' << std::endl;
}
+void ConsoleReporter::reportInvalidArguments(std::string const&arg){
+ stream << "Invalid Filter: " << arg << std::endl;
+}
+
void ConsoleReporter::assertionStarting(AssertionInfo const&) {}
bool ConsoleReporter::assertionEnded(AssertionStats const& _assertionStats) {
@@ -13729,6 +16185,7 @@ bool ConsoleReporter::assertionEnded(AssertionStats const& _assertionStats) {
}
void ConsoleReporter::sectionStarting(SectionInfo const& _sectionInfo) {
+ m_tablePrinter->close();
m_headerPrinted = false;
StreamingReporterBase::sectionStarting(_sectionInfo);
}
@@ -13752,28 +16209,53 @@ void ConsoleReporter::sectionEnded(SectionStats const& _sectionStats) {
StreamingReporterBase::sectionEnded(_sectionStats);
}
-void ConsoleReporter::benchmarkStarting(BenchmarkInfo const& info) {
- lazyPrintWithoutClosingBenchmarkTable();
+#if defined(CATCH_CONFIG_ENABLE_BENCHMARKING)
+void ConsoleReporter::benchmarkPreparing(std::string const& name) {
+ lazyPrintWithoutClosingBenchmarkTable();
- auto nameCol = Column( info.name ).width( static_cast<std::size_t>( m_tablePrinter->columnInfos()[0].width - 2 ) );
+ auto nameCol = Column(name).width(static_cast<std::size_t>(m_tablePrinter->columnInfos()[0].width - 2));
- bool firstLine = true;
- for (auto line : nameCol) {
- if (!firstLine)
- (*m_tablePrinter) << ColumnBreak() << ColumnBreak() << ColumnBreak();
- else
- firstLine = false;
+ bool firstLine = true;
+ for (auto line : nameCol) {
+ if (!firstLine)
+ (*m_tablePrinter) << ColumnBreak() << ColumnBreak() << ColumnBreak();
+ else
+ firstLine = false;
- (*m_tablePrinter) << line << ColumnBreak();
+ (*m_tablePrinter) << line << ColumnBreak();
+ }
+}
+
+void ConsoleReporter::benchmarkStarting(BenchmarkInfo const& info) {
+ (*m_tablePrinter) << info.samples << ColumnBreak()
+ << info.iterations << ColumnBreak();
+ if (!m_config->benchmarkNoAnalysis())
+ (*m_tablePrinter) << Duration(info.estimatedDuration) << ColumnBreak();
+}
+void ConsoleReporter::benchmarkEnded(BenchmarkStats<> const& stats) {
+ if (m_config->benchmarkNoAnalysis())
+ {
+ (*m_tablePrinter) << Duration(stats.mean.point.count()) << ColumnBreak();
+ }
+ else
+ {
+ (*m_tablePrinter) << ColumnBreak()
+ << Duration(stats.mean.point.count()) << ColumnBreak()
+ << Duration(stats.mean.lower_bound.count()) << ColumnBreak()
+ << Duration(stats.mean.upper_bound.count()) << ColumnBreak() << ColumnBreak()
+ << Duration(stats.standardDeviation.point.count()) << ColumnBreak()
+ << Duration(stats.standardDeviation.lower_bound.count()) << ColumnBreak()
+ << Duration(stats.standardDeviation.upper_bound.count()) << ColumnBreak() << ColumnBreak() << ColumnBreak() << ColumnBreak() << ColumnBreak();
}
}
-void ConsoleReporter::benchmarkEnded(BenchmarkStats const& stats) {
- Duration average(stats.elapsedTimeInNanoseconds / stats.iterations);
+
+void ConsoleReporter::benchmarkFailed(std::string const& error) {
+ Colour colour(Colour::Red);
(*m_tablePrinter)
- << stats.iterations << ColumnBreak()
- << stats.elapsedTimeInNanoseconds << ColumnBreak()
- << average << ColumnBreak();
+ << "Benchmark failed (" << error << ')'
+ << ColumnBreak() << RowBreak();
}
+#endif // CATCH_CONFIG_ENABLE_BENCHMARKING
void ConsoleReporter::testCaseEnded(TestCaseStats const& _testCaseStats) {
m_tablePrinter->close();
@@ -13852,11 +16334,9 @@ void ConsoleReporter::printTestCaseAndSectionHeader() {
SourceLineInfo lineInfo = m_sectionStack.back().lineInfo;
- if (!lineInfo.empty()) {
- stream << getLineOfChars<'-'>() << '\n';
- Colour colourGuard(Colour::FileName);
- stream << lineInfo << '\n';
- }
+ stream << getLineOfChars<'-'>() << '\n';
+ Colour colourGuard(Colour::FileName);
+ stream << lineInfo << '\n';
stream << getLineOfChars<'.'>() << '\n' << std::endl;
}
@@ -13981,8 +16461,10 @@ void ConsoleReporter::printSummaryDivider() {
}
void ConsoleReporter::printTestFilters() {
- if (m_config->testSpec().hasFilters())
- stream << Colour(Colour::BrightYellow) << "Filters: " << serializeFilters( m_config->getTestsOrTags() ) << '\n';
+ if (m_config->testSpec().hasFilters()) {
+ Colour guard(Colour::BrightYellow);
+ stream << "Filters: " << serializeFilters(m_config->getTestsOrTags()) << '\n';
+ }
}
CATCH_REGISTER_REPORTER("console", ConsoleReporter)
@@ -13992,6 +16474,10 @@ CATCH_REGISTER_REPORTER("console", ConsoleReporter)
#if defined(_MSC_VER)
#pragma warning(pop)
#endif
+
+#if defined(__clang__)
+# pragma clang diagnostic pop
+#endif
// end catch_reporter_console.cpp
// start catch_reporter_junit.cpp
@@ -14128,8 +16614,8 @@ namespace Catch {
for( auto const& child : groupNode.children )
writeTestCase( *child );
- xml.scopedElement( "system-out" ).writeText( trim( stdOutForSuite ), false );
- xml.scopedElement( "system-err" ).writeText( trim( stdErrForSuite ), false );
+ xml.scopedElement( "system-out" ).writeText( trim( stdOutForSuite ), XmlFormatting::Newline );
+ xml.scopedElement( "system-err" ).writeText( trim( stdErrForSuite ), XmlFormatting::Newline );
}
void JunitReporter::writeTestCase( TestCaseNode const& testCaseNode ) {
@@ -14178,9 +16664,9 @@ namespace Catch {
writeAssertions( sectionNode );
if( !sectionNode.stdOut.empty() )
- xml.scopedElement( "system-out" ).writeText( trim( sectionNode.stdOut ), false );
+ xml.scopedElement( "system-out" ).writeText( trim( sectionNode.stdOut ), XmlFormatting::Newline );
if( !sectionNode.stdErr.empty() )
- xml.scopedElement( "system-err" ).writeText( trim( sectionNode.stdErr ), false );
+ xml.scopedElement( "system-err" ).writeText( trim( sectionNode.stdErr ), XmlFormatting::Newline );
}
for( auto const& childNode : sectionNode.childSections )
if( className.empty() )
@@ -14204,11 +16690,7 @@ namespace Catch {
elementName = "error";
break;
case ResultWas::ExplicitFailure:
- elementName = "failure";
- break;
case ResultWas::ExpressionFailed:
- elementName = "failure";
- break;
case ResultWas::DidntThrowException:
elementName = "failure";
break;
@@ -14226,10 +16708,25 @@ namespace Catch {
XmlWriter::ScopedElement e = xml.scopedElement( elementName );
- xml.writeAttribute( "message", result.getExpandedExpression() );
+ xml.writeAttribute( "message", result.getExpression() );
xml.writeAttribute( "type", result.getTestMacroName() );
ReusableStringStream rss;
+ if (stats.totals.assertions.total() > 0) {
+ rss << "FAILED" << ":\n";
+ if (result.hasExpression()) {
+ rss << " ";
+ rss << result.getExpressionInMacro();
+ rss << '\n';
+ }
+ if (result.hasExpandedExpression()) {
+ rss << "with expansion:\n";
+ rss << Column(result.getExpandedExpression()).indent(2) << '\n';
+ }
+ } else {
+ rss << '\n';
+ }
+
if( !result.getMessage().empty() )
rss << result.getMessage() << '\n';
for( auto const& msg : stats.infoMessages )
@@ -14237,7 +16734,7 @@ namespace Catch {
rss << msg.message << '\n';
rss << "at " << result.getSourceInfo();
- xml.writeText( rss.str(), false );
+ xml.writeText( rss.str(), XmlFormatting::Newline );
}
}
@@ -14281,19 +16778,41 @@ namespace Catch {
m_reporter->noMatchingTestCases( spec );
}
+ void ListeningReporter::reportInvalidArguments(std::string const&arg){
+ for ( auto const& listener : m_listeners ) {
+ listener->reportInvalidArguments( arg );
+ }
+ m_reporter->reportInvalidArguments( arg );
+ }
+
+#if defined(CATCH_CONFIG_ENABLE_BENCHMARKING)
+ void ListeningReporter::benchmarkPreparing( std::string const& name ) {
+ for (auto const& listener : m_listeners) {
+ listener->benchmarkPreparing(name);
+ }
+ m_reporter->benchmarkPreparing(name);
+ }
void ListeningReporter::benchmarkStarting( BenchmarkInfo const& benchmarkInfo ) {
for ( auto const& listener : m_listeners ) {
listener->benchmarkStarting( benchmarkInfo );
}
m_reporter->benchmarkStarting( benchmarkInfo );
}
- void ListeningReporter::benchmarkEnded( BenchmarkStats const& benchmarkStats ) {
+ void ListeningReporter::benchmarkEnded( BenchmarkStats<> const& benchmarkStats ) {
for ( auto const& listener : m_listeners ) {
listener->benchmarkEnded( benchmarkStats );
}
m_reporter->benchmarkEnded( benchmarkStats );
}
+ void ListeningReporter::benchmarkFailed( std::string const& error ) {
+ for (auto const& listener : m_listeners) {
+ listener->benchmarkFailed(error);
+ }
+ m_reporter->benchmarkFailed(error);
+ }
+#endif // CATCH_CONFIG_ENABLE_BENCHMARKING
+
void ListeningReporter::testRunStarting( TestRunInfo const& testRunInfo ) {
for ( auto const& listener : m_listeners ) {
listener->testRunStarting( testRunInfo );
@@ -14561,9 +17080,9 @@ namespace Catch {
e.writeAttribute( "durationInSeconds", m_testCaseTimer.getElapsedSeconds() );
if( !testCaseStats.stdOut.empty() )
- m_xml.scopedElement( "StdOut" ).writeText( trim( testCaseStats.stdOut ), false );
+ m_xml.scopedElement( "StdOut" ).writeText( trim( testCaseStats.stdOut ), XmlFormatting::Newline );
if( !testCaseStats.stdErr.empty() )
- m_xml.scopedElement( "StdErr" ).writeText( trim( testCaseStats.stdErr ), false );
+ m_xml.scopedElement( "StdErr" ).writeText( trim( testCaseStats.stdErr ), XmlFormatting::Newline );
m_xml.endElement();
}
@@ -14587,6 +17106,51 @@ namespace Catch {
m_xml.endElement();
}
+#if defined(CATCH_CONFIG_ENABLE_BENCHMARKING)
+ void XmlReporter::benchmarkPreparing(std::string const& name) {
+ m_xml.startElement("BenchmarkResults")
+ .writeAttribute("name", name);
+ }
+
+ void XmlReporter::benchmarkStarting(BenchmarkInfo const &info) {
+ m_xml.writeAttribute("samples", info.samples)
+ .writeAttribute("resamples", info.resamples)
+ .writeAttribute("iterations", info.iterations)
+ .writeAttribute("clockResolution", info.clockResolution)
+ .writeAttribute("estimatedDuration", info.estimatedDuration)
+ .writeComment("All values in nano seconds");
+ }
+
+ void XmlReporter::benchmarkEnded(BenchmarkStats<> const& benchmarkStats) {
+ m_xml.startElement("mean")
+ .writeAttribute("value", benchmarkStats.mean.point.count())
+ .writeAttribute("lowerBound", benchmarkStats.mean.lower_bound.count())
+ .writeAttribute("upperBound", benchmarkStats.mean.upper_bound.count())
+ .writeAttribute("ci", benchmarkStats.mean.confidence_interval);
+ m_xml.endElement();
+ m_xml.startElement("standardDeviation")
+ .writeAttribute("value", benchmarkStats.standardDeviation.point.count())
+ .writeAttribute("lowerBound", benchmarkStats.standardDeviation.lower_bound.count())
+ .writeAttribute("upperBound", benchmarkStats.standardDeviation.upper_bound.count())
+ .writeAttribute("ci", benchmarkStats.standardDeviation.confidence_interval);
+ m_xml.endElement();
+ m_xml.startElement("outliers")
+ .writeAttribute("variance", benchmarkStats.outlierVariance)
+ .writeAttribute("lowMild", benchmarkStats.outliers.low_mild)
+ .writeAttribute("lowSevere", benchmarkStats.outliers.low_severe)
+ .writeAttribute("highMild", benchmarkStats.outliers.high_mild)
+ .writeAttribute("highSevere", benchmarkStats.outliers.high_severe);
+ m_xml.endElement();
+ m_xml.endElement();
+ }
+
+ void XmlReporter::benchmarkFailed(std::string const &error) {
+ m_xml.scopedElement("failed").
+ writeAttribute("message", error);
+ m_xml.endElement();
+ }
+#endif // CATCH_CONFIG_ENABLE_BENCHMARKING
+
CATCH_REGISTER_REPORTER( "xml", XmlReporter )
} // end namespace Catch
@@ -14612,7 +17176,7 @@ namespace Catch {
#ifndef __OBJC__
-#if defined(CATCH_CONFIG_WCHAR) && defined(WIN32) && defined(_UNICODE) && !defined(DO_NOT_USE_WMAIN)
+#if defined(CATCH_CONFIG_WCHAR) && defined(CATCH_PLATFORM_WINDOWS) && defined(_UNICODE) && !defined(DO_NOT_USE_WMAIN)
// Standard C/C++ Win32 Unicode wmain entry point
extern "C" int wmain (int argc, wchar_t * argv[], wchar_t * []) {
#else
@@ -14689,6 +17253,7 @@ int main (int argc, char * const argv[]) {
#endif // CATCH_CONFIG_DISABLE_MATCHERS
#define CATCH_INFO( msg ) INTERNAL_CATCH_INFO( "CATCH_INFO", msg )
+#define CATCH_UNSCOPED_INFO( msg ) INTERNAL_CATCH_UNSCOPED_INFO( "CATCH_UNSCOPED_INFO", msg )
#define CATCH_WARN( msg ) INTERNAL_CATCH_MSG( "CATCH_WARN", Catch::ResultWas::Warning, Catch::ResultDisposition::ContinueOnFailure, msg )
#define CATCH_CAPTURE( ... ) INTERNAL_CATCH_CAPTURE( INTERNAL_CATCH_UNIQUE_NAME(capturer), "CATCH_CAPTURE",__VA_ARGS__ )
@@ -14706,14 +17271,22 @@ int main (int argc, char * const argv[]) {
#ifndef CATCH_CONFIG_TRADITIONAL_MSVC_PREPROCESSOR
#define CATCH_TEMPLATE_TEST_CASE( ... ) INTERNAL_CATCH_TEMPLATE_TEST_CASE( __VA_ARGS__ )
+#define CATCH_TEMPLATE_TEST_CASE_SIG( ... ) INTERNAL_CATCH_TEMPLATE_TEST_CASE_SIG( __VA_ARGS__ )
#define CATCH_TEMPLATE_TEST_CASE_METHOD( className, ... ) INTERNAL_CATCH_TEMPLATE_TEST_CASE_METHOD( className, __VA_ARGS__ )
+#define CATCH_TEMPLATE_TEST_CASE_METHOD_SIG( className, ... ) INTERNAL_CATCH_TEMPLATE_TEST_CASE_METHOD_SIG( className, __VA_ARGS__ )
#define CATCH_TEMPLATE_PRODUCT_TEST_CASE( ... ) INTERNAL_CATCH_TEMPLATE_PRODUCT_TEST_CASE( __VA_ARGS__ )
+#define CATCH_TEMPLATE_PRODUCT_TEST_CASE_SIG( ... ) INTERNAL_CATCH_TEMPLATE_PRODUCT_TEST_CASE_SIG( __VA_ARGS__ )
#define CATCH_TEMPLATE_PRODUCT_TEST_CASE_METHOD( className, ... ) INTERNAL_CATCH_TEMPLATE_PRODUCT_TEST_CASE_METHOD( className, __VA_ARGS__ )
+#define CATCH_TEMPLATE_PRODUCT_TEST_CASE_METHOD_SIG( className, ... ) INTERNAL_CATCH_TEMPLATE_PRODUCT_TEST_CASE_METHOD_SIG( className, __VA_ARGS__ )
#else
#define CATCH_TEMPLATE_TEST_CASE( ... ) INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_TEST_CASE( __VA_ARGS__ ) )
+#define CATCH_TEMPLATE_TEST_CASE_SIG( ... ) INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_TEST_CASE_SIG( __VA_ARGS__ ) )
#define CATCH_TEMPLATE_TEST_CASE_METHOD( className, ... ) INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_TEST_CASE_METHOD( className, __VA_ARGS__ ) )
+#define CATCH_TEMPLATE_TEST_CASE_METHOD_SIG( className, ... ) INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_TEST_CASE_METHOD_SIG( className, __VA_ARGS__ ) )
#define CATCH_TEMPLATE_PRODUCT_TEST_CASE( ... ) INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_PRODUCT_TEST_CASE( __VA_ARGS__ ) )
+#define CATCH_TEMPLATE_PRODUCT_TEST_CASE_SIG( ... ) INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_PRODUCT_TEST_CASE_SIG( __VA_ARGS__ ) )
#define CATCH_TEMPLATE_PRODUCT_TEST_CASE_METHOD( className, ... ) INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_PRODUCT_TEST_CASE_METHOD( className, __VA_ARGS__ ) )
+#define CATCH_TEMPLATE_PRODUCT_TEST_CASE_METHOD_SIG( className, ... ) INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_PRODUCT_TEST_CASE_METHOD_SIG( className, __VA_ARGS__ ) )
#endif
#if !defined(CATCH_CONFIG_RUNTIME_STATIC_REQUIRE)
@@ -14734,6 +17307,13 @@ int main (int argc, char * const argv[]) {
#define CATCH_THEN( desc ) INTERNAL_CATCH_DYNAMIC_SECTION( " Then: " << desc )
#define CATCH_AND_THEN( desc ) INTERNAL_CATCH_DYNAMIC_SECTION( " And: " << desc )
+#if defined(CATCH_CONFIG_ENABLE_BENCHMARKING)
+#define CATCH_BENCHMARK(...) \
+ INTERNAL_CATCH_BENCHMARK(INTERNAL_CATCH_UNIQUE_NAME(____C_A_T_C_H____B_E_N_C_H____), INTERNAL_CATCH_GET_1_ARG(__VA_ARGS__,,), INTERNAL_CATCH_GET_2_ARG(__VA_ARGS__,,))
+#define CATCH_BENCHMARK_ADVANCED(name) \
+ INTERNAL_CATCH_BENCHMARK_ADVANCED(INTERNAL_CATCH_UNIQUE_NAME(____C_A_T_C_H____B_E_N_C_H____), name)
+#endif // CATCH_CONFIG_ENABLE_BENCHMARKING
+
// If CATCH_CONFIG_PREFIX_ALL is not defined then the CATCH_ prefix is not required
#else
@@ -14786,14 +17366,26 @@ int main (int argc, char * const argv[]) {
#ifndef CATCH_CONFIG_TRADITIONAL_MSVC_PREPROCESSOR
#define TEMPLATE_TEST_CASE( ... ) INTERNAL_CATCH_TEMPLATE_TEST_CASE( __VA_ARGS__ )
+#define TEMPLATE_TEST_CASE_SIG( ... ) INTERNAL_CATCH_TEMPLATE_TEST_CASE_SIG( __VA_ARGS__ )
#define TEMPLATE_TEST_CASE_METHOD( className, ... ) INTERNAL_CATCH_TEMPLATE_TEST_CASE_METHOD( className, __VA_ARGS__ )
+#define TEMPLATE_TEST_CASE_METHOD_SIG( className, ... ) INTERNAL_CATCH_TEMPLATE_TEST_CASE_METHOD_SIG( className, __VA_ARGS__ )
#define TEMPLATE_PRODUCT_TEST_CASE( ... ) INTERNAL_CATCH_TEMPLATE_PRODUCT_TEST_CASE( __VA_ARGS__ )
+#define TEMPLATE_PRODUCT_TEST_CASE_SIG( ... ) INTERNAL_CATCH_TEMPLATE_PRODUCT_TEST_CASE_SIG( __VA_ARGS__ )
#define TEMPLATE_PRODUCT_TEST_CASE_METHOD( className, ... ) INTERNAL_CATCH_TEMPLATE_PRODUCT_TEST_CASE_METHOD( className, __VA_ARGS__ )
+#define TEMPLATE_PRODUCT_TEST_CASE_METHOD_SIG( className, ... ) INTERNAL_CATCH_TEMPLATE_PRODUCT_TEST_CASE_METHOD_SIG( className, __VA_ARGS__ )
+#define TEMPLATE_LIST_TEST_CASE( ... ) INTERNAL_CATCH_TEMPLATE_LIST_TEST_CASE(__VA_ARGS__)
+#define TEMPLATE_LIST_TEST_CASE_METHOD( className, ... ) INTERNAL_CATCH_TEMPLATE_LIST_TEST_CASE_METHOD( className, __VA_ARGS__ )
#else
#define TEMPLATE_TEST_CASE( ... ) INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_TEST_CASE( __VA_ARGS__ ) )
+#define TEMPLATE_TEST_CASE_SIG( ... ) INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_TEST_CASE_SIG( __VA_ARGS__ ) )
#define TEMPLATE_TEST_CASE_METHOD( className, ... ) INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_TEST_CASE_METHOD( className, __VA_ARGS__ ) )
+#define TEMPLATE_TEST_CASE_METHOD_SIG( className, ... ) INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_TEST_CASE_METHOD_SIG( className, __VA_ARGS__ ) )
#define TEMPLATE_PRODUCT_TEST_CASE( ... ) INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_PRODUCT_TEST_CASE( __VA_ARGS__ ) )
+#define TEMPLATE_PRODUCT_TEST_CASE_SIG( ... ) INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_PRODUCT_TEST_CASE_SIG( __VA_ARGS__ ) )
#define TEMPLATE_PRODUCT_TEST_CASE_METHOD( className, ... ) INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_PRODUCT_TEST_CASE_METHOD( className, __VA_ARGS__ ) )
+#define TEMPLATE_PRODUCT_TEST_CASE_METHOD_SIG( className, ... ) INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_PRODUCT_TEST_CASE_METHOD_SIG( className, __VA_ARGS__ ) )
+#define TEMPLATE_LIST_TEST_CASE( ... ) INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_LIST_TEST_CASE( __VA_ARGS__ ) )
+#define TEMPLATE_LIST_TEST_CASE_METHOD( className, ... ) INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_LIST_TEST_CASE_METHOD( className, __VA_ARGS__ ) )
#endif
#if !defined(CATCH_CONFIG_RUNTIME_STATIC_REQUIRE)
@@ -14819,6 +17411,13 @@ int main (int argc, char * const argv[]) {
#define THEN( desc ) INTERNAL_CATCH_DYNAMIC_SECTION( " Then: " << desc )
#define AND_THEN( desc ) INTERNAL_CATCH_DYNAMIC_SECTION( " And: " << desc )
+#if defined(CATCH_CONFIG_ENABLE_BENCHMARKING)
+#define BENCHMARK(...) \
+ INTERNAL_CATCH_BENCHMARK(INTERNAL_CATCH_UNIQUE_NAME(____C_A_T_C_H____B_E_N_C_H____), INTERNAL_CATCH_GET_1_ARG(__VA_ARGS__,,), INTERNAL_CATCH_GET_2_ARG(__VA_ARGS__,,))
+#define BENCHMARK_ADVANCED(name) \
+ INTERNAL_CATCH_BENCHMARK_ADVANCED(INTERNAL_CATCH_UNIQUE_NAME(____C_A_T_C_H____B_E_N_C_H____), name)
+#endif // CATCH_CONFIG_ENABLE_BENCHMARKING
+
using Catch::Detail::Approx;
#else // CATCH_CONFIG_DISABLE
@@ -14858,9 +17457,10 @@ using Catch::Detail::Approx;
#define CATCH_REQUIRE_THAT( arg, matcher ) (void)(0)
#endif // CATCH_CONFIG_DISABLE_MATCHERS
-#define CATCH_INFO( msg ) (void)(0)
-#define CATCH_WARN( msg ) (void)(0)
-#define CATCH_CAPTURE( msg ) (void)(0)
+#define CATCH_INFO( msg ) (void)(0)
+#define CATCH_UNSCOPED_INFO( msg ) (void)(0)
+#define CATCH_WARN( msg ) (void)(0)
+#define CATCH_CAPTURE( msg ) (void)(0)
#define CATCH_TEST_CASE( ... ) INTERNAL_CATCH_TESTCASE_NO_REGISTRATION(INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_S_T____ ))
#define CATCH_TEST_CASE_METHOD( className, ... ) INTERNAL_CATCH_TESTCASE_NO_REGISTRATION(INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_S_T____ ))
@@ -14875,15 +17475,23 @@ using Catch::Detail::Approx;
#define CATCH_ANON_TEST_CASE() INTERNAL_CATCH_TESTCASE_NO_REGISTRATION(INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_S_T____ ))
#ifndef CATCH_CONFIG_TRADITIONAL_MSVC_PREPROCESSOR
-#define CATCH_TEMPLATE_TEST_CASE( ... ) INTERNAL_CATCH_TEMPLATE_TEST_CASE_NO_REGISTRATION(INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_M_P_L_A_T_E____T_E_S_T____ ) )
-#define CATCH_TEMPLATE_TEST_CASE_METHOD( className, ... ) INTERNAL_CATCH_TEMPLATE_TEST_CASE_METHOD_NO_REGISTRATION(INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_M_P_L_A_T_E____T_E_S_T____ ), className )
+#define CATCH_TEMPLATE_TEST_CASE( ... ) INTERNAL_CATCH_TEMPLATE_TEST_CASE_NO_REGISTRATION(__VA_ARGS__)
+#define CATCH_TEMPLATE_TEST_CASE_SIG( ... ) INTERNAL_CATCH_TEMPLATE_TEST_CASE_SIG_NO_REGISTRATION(__VA_ARGS__)
+#define CATCH_TEMPLATE_TEST_CASE_METHOD( className, ... ) INTERNAL_CATCH_TEMPLATE_TEST_CASE_METHOD_NO_REGISTRATION(className, __VA_ARGS__)
+#define CATCH_TEMPLATE_TEST_CASE_METHOD_SIG( className, ... ) INTERNAL_CATCH_TEMPLATE_TEST_CASE_METHOD_SIG_NO_REGISTRATION(className, __VA_ARGS__ )
#define CATCH_TEMPLATE_PRODUCT_TEST_CASE( ... ) CATCH_TEMPLATE_TEST_CASE( __VA_ARGS__ )
+#define CATCH_TEMPLATE_PRODUCT_TEST_CASE_SIG( ... ) CATCH_TEMPLATE_TEST_CASE( __VA_ARGS__ )
#define CATCH_TEMPLATE_PRODUCT_TEST_CASE_METHOD( className, ... ) CATCH_TEMPLATE_TEST_CASE_METHOD( className, __VA_ARGS__ )
+#define CATCH_TEMPLATE_PRODUCT_TEST_CASE_METHOD_SIG( className, ... ) CATCH_TEMPLATE_TEST_CASE_METHOD( className, __VA_ARGS__ )
#else
-#define CATCH_TEMPLATE_TEST_CASE( ... ) INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_TEST_CASE_NO_REGISTRATION(INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_M_P_L_A_T_E____T_E_S_T____ ) ) )
-#define CATCH_TEMPLATE_TEST_CASE_METHOD( className, ... ) INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_TEST_CASE_METHOD_NO_REGISTRATION(INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_M_P_L_A_T_E____T_E_S_T____ ), className ) )
+#define CATCH_TEMPLATE_TEST_CASE( ... ) INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_TEST_CASE_NO_REGISTRATION(__VA_ARGS__) )
+#define CATCH_TEMPLATE_TEST_CASE_SIG( ... ) INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_TEST_CASE_SIG_NO_REGISTRATION(__VA_ARGS__) )
+#define CATCH_TEMPLATE_TEST_CASE_METHOD( className, ... ) INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_TEST_CASE_METHOD_NO_REGISTRATION(className, __VA_ARGS__ ) )
+#define CATCH_TEMPLATE_TEST_CASE_METHOD_SIG( className, ... ) INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_TEST_CASE_METHOD_SIG_NO_REGISTRATION(className, __VA_ARGS__ ) )
#define CATCH_TEMPLATE_PRODUCT_TEST_CASE( ... ) CATCH_TEMPLATE_TEST_CASE( __VA_ARGS__ )
+#define CATCH_TEMPLATE_PRODUCT_TEST_CASE_SIG( ... ) CATCH_TEMPLATE_TEST_CASE( __VA_ARGS__ )
#define CATCH_TEMPLATE_PRODUCT_TEST_CASE_METHOD( className, ... ) CATCH_TEMPLATE_TEST_CASE_METHOD( className, __VA_ARGS__ )
+#define CATCH_TEMPLATE_PRODUCT_TEST_CASE_METHOD_SIG( className, ... ) CATCH_TEMPLATE_TEST_CASE_METHOD( className, __VA_ARGS__ )
#endif
// "BDD-style" convenience wrappers
@@ -14934,6 +17542,7 @@ using Catch::Detail::Approx;
#endif // CATCH_CONFIG_DISABLE_MATCHERS
#define INFO( msg ) (void)(0)
+#define UNSCOPED_INFO( msg ) (void)(0)
#define WARN( msg ) (void)(0)
#define CAPTURE( msg ) (void)(0)
@@ -14949,15 +17558,23 @@ using Catch::Detail::Approx;
#define ANON_TEST_CASE() INTERNAL_CATCH_TESTCASE_NO_REGISTRATION(INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_S_T____ ))
#ifndef CATCH_CONFIG_TRADITIONAL_MSVC_PREPROCESSOR
-#define TEMPLATE_TEST_CASE( ... ) INTERNAL_CATCH_TEMPLATE_TEST_CASE_NO_REGISTRATION(INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_M_P_L_A_T_E____T_E_S_T____ ) )
-#define TEMPLATE_TEST_CASE_METHOD( className, ... ) INTERNAL_CATCH_TEMPLATE_TEST_CASE_METHOD_NO_REGISTRATION(INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_M_P_L_A_T_E____T_E_S_T____ ), className )
+#define TEMPLATE_TEST_CASE( ... ) INTERNAL_CATCH_TEMPLATE_TEST_CASE_NO_REGISTRATION(__VA_ARGS__)
+#define TEMPLATE_TEST_CASE_SIG( ... ) INTERNAL_CATCH_TEMPLATE_TEST_CASE_SIG_NO_REGISTRATION(__VA_ARGS__)
+#define TEMPLATE_TEST_CASE_METHOD( className, ... ) INTERNAL_CATCH_TEMPLATE_TEST_CASE_METHOD_NO_REGISTRATION(className, __VA_ARGS__)
+#define TEMPLATE_TEST_CASE_METHOD_SIG( className, ... ) INTERNAL_CATCH_TEMPLATE_TEST_CASE_METHOD_SIG_NO_REGISTRATION(className, __VA_ARGS__ )
#define TEMPLATE_PRODUCT_TEST_CASE( ... ) TEMPLATE_TEST_CASE( __VA_ARGS__ )
+#define TEMPLATE_PRODUCT_TEST_CASE_SIG( ... ) TEMPLATE_TEST_CASE( __VA_ARGS__ )
#define TEMPLATE_PRODUCT_TEST_CASE_METHOD( className, ... ) TEMPLATE_TEST_CASE_METHOD( className, __VA_ARGS__ )
+#define TEMPLATE_PRODUCT_TEST_CASE_METHOD_SIG( className, ... ) TEMPLATE_TEST_CASE_METHOD( className, __VA_ARGS__ )
#else
-#define TEMPLATE_TEST_CASE( ... ) INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_TEST_CASE_NO_REGISTRATION(INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_M_P_L_A_T_E____T_E_S_T____ ) ) )
-#define TEMPLATE_TEST_CASE_METHOD( className, ... ) INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_TEST_CASE_METHOD_NO_REGISTRATION(INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_M_P_L_A_T_E____T_E_S_T____ ), className ) )
+#define TEMPLATE_TEST_CASE( ... ) INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_TEST_CASE_NO_REGISTRATION(__VA_ARGS__) )
+#define TEMPLATE_TEST_CASE_SIG( ... ) INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_TEST_CASE_SIG_NO_REGISTRATION(__VA_ARGS__) )
+#define TEMPLATE_TEST_CASE_METHOD( className, ... ) INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_TEST_CASE_METHOD_NO_REGISTRATION(className, __VA_ARGS__ ) )
+#define TEMPLATE_TEST_CASE_METHOD_SIG( className, ... ) INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_TEST_CASE_METHOD_SIG_NO_REGISTRATION(className, __VA_ARGS__ ) )
#define TEMPLATE_PRODUCT_TEST_CASE( ... ) TEMPLATE_TEST_CASE( __VA_ARGS__ )
+#define TEMPLATE_PRODUCT_TEST_CASE_SIG( ... ) TEMPLATE_TEST_CASE( __VA_ARGS__ )
#define TEMPLATE_PRODUCT_TEST_CASE_METHOD( className, ... ) TEMPLATE_TEST_CASE_METHOD( className, __VA_ARGS__ )
+#define TEMPLATE_PRODUCT_TEST_CASE_METHOD_SIG( className, ... ) TEMPLATE_TEST_CASE_METHOD( className, __VA_ARGS__ )
#endif
#define STATIC_REQUIRE( ... ) (void)(0)
diff --git a/single_include/catch2/catch_reporter_sonarqube.hpp b/single_include/catch2/catch_reporter_sonarqube.hpp
new file mode 100644
index 00000000..bf7d9299
--- /dev/null
+++ b/single_include/catch2/catch_reporter_sonarqube.hpp
@@ -0,0 +1,181 @@
+/*
+ * Created by Daniel Garcia on 2018-12-04.
+ * Copyright Social Point SL. 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 CATCH_REPORTER_SONARQUBE_HPP_INCLUDED
+#define CATCH_REPORTER_SONARQUBE_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 <map>
+
+namespace Catch {
+
+ struct SonarQubeReporter : CumulativeReporterBase<SonarQubeReporter> {
+
+ SonarQubeReporter(ReporterConfig const& config)
+ : CumulativeReporterBase(config)
+ , xml(config.stream()) {
+ m_reporterPrefs.shouldRedirectStdOut = true;
+ m_reporterPrefs.shouldReportAllAssertions = true;
+ }
+
+ ~SonarQubeReporter() override;
+
+ static std::string getDescription() {
+ return "Reports test results in the Generic Test Data SonarQube XML format";
+ }
+
+ static std::set<Verbosity> getSupportedVerbosities() {
+ return { Verbosity::Normal };
+ }
+
+ void noMatchingTestCases(std::string const& /*spec*/) override {}
+
+ void testRunStarting(TestRunInfo const& testRunInfo) override {
+ CumulativeReporterBase::testRunStarting(testRunInfo);
+ xml.startElement("testExecutions");
+ xml.writeAttribute("version", "1");
+ }
+
+ void testGroupEnded(TestGroupStats const& testGroupStats) override {
+ CumulativeReporterBase::testGroupEnded(testGroupStats);
+ writeGroup(*m_testGroups.back());
+ }
+
+ void testRunEndedCumulative() override {
+ xml.endElement();
+ }
+
+ void writeGroup(TestGroupNode const& groupNode) {
+ std::map<std::string, TestGroupNode::ChildNodes> testsPerFile;
+ for(auto const& child : groupNode.children)
+ testsPerFile[child->value.testInfo.lineInfo.file].push_back(child);
+
+ for(auto const& kv : testsPerFile)
+ writeTestFile(kv.first.c_str(), kv.second);
+ }
+
+ void writeTestFile(const char* filename, TestGroupNode::ChildNodes const& testCaseNodes) {
+ XmlWriter::ScopedElement e = xml.scopedElement("file");
+ xml.writeAttribute("path", filename);
+
+ for(auto const& child : testCaseNodes)
+ writeTestCase(*child);
+ }
+
+ void writeTestCase(TestCaseNode const& testCaseNode) {
+ // 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();
+ writeSection("", rootSection, testCaseNode.value.testInfo.okToFail());
+ }
+
+ void writeSection(std::string const& rootName, SectionNode const& sectionNode, bool okToFail) {
+ 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");
+ xml.writeAttribute("name", name);
+ xml.writeAttribute("duration", static_cast<long>(sectionNode.stats.durationInSeconds * 1000));
+
+ writeAssertions(sectionNode, okToFail);
+ }
+
+ for(auto const& childNode : sectionNode.childSections)
+ writeSection(name, *childNode, okToFail);
+ }
+
+ void writeAssertions(SectionNode const& sectionNode, bool okToFail) {
+ for(auto const& assertion : sectionNode.assertions)
+ writeAssertion( assertion, okToFail);
+ }
+
+ void writeAssertion(AssertionStats const& stats, bool okToFail) {
+ AssertionResult const& result = stats.assertionResult;
+ if(!result.isOk()) {
+ std::string elementName;
+ if(okToFail) {
+ elementName = "skipped";
+ }
+ else {
+ 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);
+
+ ReusableStringStream messageRss;
+ messageRss << result.getTestMacroName() << "(" << result.getExpression() << ")";
+ xml.writeAttribute("message", messageRss.str());
+
+ ReusableStringStream textRss;
+ if (stats.totals.assertions.total() > 0) {
+ textRss << "FAILED:\n";
+ if (result.hasExpression()) {
+ textRss << "\t" << result.getExpressionInMacro() << "\n";
+ }
+ if (result.hasExpandedExpression()) {
+ textRss << "with expansion:\n\t" << result.getExpandedExpression() << "\n";
+ }
+ }
+
+ if(!result.getMessage().empty())
+ textRss << result.getMessage() << "\n";
+
+ for(auto const& msg : stats.infoMessages)
+ if(msg.type == ResultWas::Info)
+ textRss << msg.message << "\n";
+
+ textRss << "at " << result.getSourceInfo();
+ xml.writeText(textRss.str(), XmlFormatting::Newline);
+ }
+ }
+
+ private:
+ XmlWriter xml;
+ };
+
+#ifdef CATCH_IMPL
+ SonarQubeReporter::~SonarQubeReporter() {}
+#endif
+
+ CATCH_REGISTER_REPORTER( "sonarqube", SonarQubeReporter )
+
+} // end namespace Catch
+
+#endif // CATCH_REPORTER_SONARQUBE_HPP_INCLUDED \ No newline at end of file
diff --git a/single_include/catch2/catch_reporter_teamcity.hpp b/single_include/catch2/catch_reporter_teamcity.hpp
index eca2885c..47b7e4aa 100644
--- a/single_include/catch2/catch_reporter_teamcity.hpp
+++ b/single_include/catch2/catch_reporter_teamcity.hpp
@@ -183,8 +183,7 @@ namespace Catch {
SourceLineInfo lineInfo = m_sectionStack.front().lineInfo;
- if( !lineInfo.empty() )
- os << lineInfo << "\n";
+ os << lineInfo << "\n";
os << getLineOfChars<'.'>() << "\n\n";
}