Compare commits

...

88 Commits

Author SHA1 Message Date
Martin Hořeňovský
0a34cc201e v2.2.1 2018-03-11 12:04:28 +01:00
Martin Hořeňovský
11c89a5f7d Bring in Clara v1.1.4
This fixes #1214
2018-03-09 10:37:56 +01:00
Martin Hořeňovský
dc3e7f9cf7 Fix incorrectly clamped return value
Fixes #1215
2018-03-09 10:00:55 +01:00
Martin Hořeňovský
d14b7563c2 v2.2.0 2018-03-07 11:06:15 +01:00
Martin Hořeňovský
a3d3a633b2 Don't build dev-appveyor* branches on TravisCI 2018-03-07 10:53:09 +01:00
Martin Hořeňovský
8d4796309f Merge pull request #1206 from zemasoft/master
Introduce support for DJGPP cross compiler
2018-03-07 10:47:18 +01:00
Martin Hořeňovský
552589f25b Merge branch 'master' into master 2018-03-07 10:37:50 +01:00
Tomas Zeman
95c849f613 Introduce support for DJGPP cross compiler
DJGPP cross compiler is targeting DOS which does not support POSIX
signals. Probably for the same reason (targeting DOS) this compiler
does not support wide characters.
2018-03-07 10:35:32 +01:00
Tomas Zeman
352853ed7e Introduce conditional wchar_t (and std::wstring) support
The support is turned on by default but the user might need to be able
to turn it off which is now possible by defining CATCH_CONFIG_NO_WCHAR.
2018-03-07 10:35:31 +01:00
Josh Soref
b11175548a Fixup various spelling errors (#1208) 2018-03-07 10:08:35 +01:00
Bastian Dörig
d38f782995 Ensure Catch2ConfigVersion.cmake is installed properly
The old version would lead to error when Catch was installed
as a subproject. The file would be written to the subproject's
build directory and then would not be installed properly.
2018-03-07 09:42:58 +01:00
Martin Hořeňovský
dc8a8e6371 Speed up AppVeyor build times
* Examples are no longer built for all images
* Coverage is no longer collected from every build
* The number of configurations is reduced
2018-03-06 22:46:49 +01:00
Martin Hořeňovský
9d1858b195 Simplify internal configuration of POSIX signals 2018-03-06 17:58:37 +01:00
Martin Hořeňovský
1d1f8dc992 Stop installing lcov in builds without COVERAGE=1 2018-03-06 15:38:22 +01:00
Martin Hořeňovský
1466686ade Speed up TravisCI build
* Examples are no longer built on all travis images
* Coverage is no longer collected from all travis images
* Valgrind is no longer used with all travis images

This should greatly reduce the amount of compiling, downloading
binaries and general work the common images do.
2018-03-06 15:24:12 +01:00
Martin Hořeňovský
93db01c647 Fix C++14 toggle for OSX build 2018-03-05 15:09:25 +01:00
Martin Hořeňovský
2e285b9579 Use char const * const * for Session::run
Needed to embed newer version of Clara

Closes #1178
Closes #1031
2018-03-04 17:58:27 +01:00
Martin Hořeňovský
d2ddb997a7 Cleanup for performance reasons
* Eliminated some copies
* Made makeTestCase fit into 4 arguments -- avoids spills on Win64
* Made string literals into StringRef literals
2018-03-02 16:24:35 +01:00
Tomas Zeman
865d5f59b4 Fix 'defined but not used' warning
The warning occurred when !CATCH_CONFIG_WINDOWS_SEH
&& !CATCH_CONFIG_POSIX_SIGNALS.
2018-03-01 13:37:23 +01:00
Martin Hořeňovský
05cd05743a Provide a public method to get StringRef's underlying pointer
This allows reducing the amount of friends needed for its interface
and some extra tricks later.

The bad part is that the pointer can become invalidated via
calls to other StringRef's public methods, but c'est la vie.
2018-02-28 22:49:00 +01:00
Martin Hořeňovský
950ccf4749 StringRef appends itself to std::string efficiently 2018-02-28 16:02:25 +01:00
Martin Hořeňovský
cf4b7eead9 Document CATCH_CONFIG_CPP17_UNCAUGHT_EXCEPTIONS macro
Also fix how it can be disabled.
2018-02-25 21:22:38 +01:00
Martin Hořeňovský
7b6e49d795 Simplify logic selecting between signal handling/SEH/nothing
It was a bit of a mess previously
2018-02-23 14:56:07 +01:00
Martin Hořeňovský
0c5df42c28 Fix how windows.h is included in our files.
To prevent bugs with stitching system headers inside Catch,
the proxy header is responsible for guarding against inclusion
on Linux, rather than the includers.

Might be related to #1197
2018-02-23 12:40:12 +01:00
Martin Hořeňovský
4e57661919 StringRef will not take ownership when writing itself to stream
This also fixes some tests that were previously failing unnoticed - WTF?
2018-02-17 20:41:50 +01:00
Martin Hořeňovský
5a8f9c84dd Fix doubled line in baselines 2018-02-16 22:10:39 +01:00
Martin Hořeňovský
f988b4eb35 Covered more translation possibilities 2018-02-15 19:58:49 +01:00
Martin Hořeňovský
c8d765a575 Cleanup some tests 2018-02-15 16:06:35 +01:00
Martin Hořeňovský
da783abee9 Move fallback conversion after enum-check 2018-02-15 16:06:35 +01:00
Martin Hořeňovský
c0267e5c20 Add test for overriding the fallback stringifier 2018-02-15 16:06:35 +01:00
Phil Nash
bb84f0788a Removed unnecessary use of ostringstream from catch_enforce.h 2018-02-15 13:59:02 +00:00
Nils Deppe
e84768fff1 Add SpECTRE project to list of users. 2018-02-14 08:31:33 +01:00
Martin Hořeňovský
31673ee0ca Document CATCH_CONFIG_DEFAULT_REPORTER macro 2018-02-11 18:10:28 +01:00
Martin Hořeňovský
34d7a33574 Add a way to change fallback stringifier
This allows reuse of projects existing stringification machinery

Closes #1024
2018-02-11 16:31:12 +01:00
Martin Hořeňovský
082c3b84bc Fix typos in documentation 2018-02-10 22:16:32 +01:00
Martin Hořeňovský
ef2e112561 Disable POSIX signals for Emscripten
Related to #1114
2018-02-10 20:42:08 +01:00
Martin Hořeňovský
a90305f857 Add another known bug to limitations.md
Related to #1183
2018-02-10 13:51:33 +01:00
Martin Hořeňovský
543c9d3a67 Set patch coverage check to target 80% 2018-02-09 20:09:55 +01:00
dvirtz
ca8470fbad https://github.com/catchorg/Catch2/issues/1175 - don't list hidden tests by default 2018-02-09 19:55:40 +01:00
dvirtz
355b3f9952 Add option to warn when no tests ran
Closes #1158
2018-02-09 18:49:36 +01:00
Martin Hořeňovský
7cbd0b587a v2.1.2 2018-02-09 17:10:27 +01:00
Martin Hořeňovský
2f15ccd4d3 Passthrough error code from coverage helper 2018-02-09 16:54:10 +01:00
Martin Hořeňovský
8f3fc15b73 Update version of Clara
Fixes #1165
2018-02-09 16:50:19 +01:00
Martin Hořeňovský
e13d9cab02 Keep .py files with LF endings so they can be executed from bash 2018-02-09 16:49:35 +01:00
Martin Hořeňovský
414e2fa946 Make embedClara.py executable 2018-02-09 16:49:21 +01:00
Martin Hořeňovský
b5ef68b044 Force MSVC to use utf-8 2018-02-08 15:44:33 +01:00
Martin Hořeňovský
681f5daa13 Update approval tests 2018-02-08 15:00:56 +01:00
Martin Hořeňovský
3b6fda3c1b Add tests for StringRef::numberOfCharacters 2018-02-08 13:10:12 +01:00
Martin Hořeňovský
1b2fa601c6 Remove superfluous comment 2018-02-08 13:09:02 +01:00
Daniel J. Rollins
39bfc6e82b Export Catch as a CMake package and 'linkable' target
Create a namespaced Catch2::Catch target that is 'linkable' through
`target_link_libraries()` and export it so it is findable through
`find_package()`.

`find_package()` will find versions with the same major number and with
minor number >= requested.

This makes catch a lot easier to use in CMake-based projects. Whether it
is found using `find_package` or included in the client project as a
subdirectory, the client can include the catch headers per-target with
`target_include_directories(target PRIVATE Catch2::Catch).

Example usage:

    cmake_minimum_required(VERSION 3.1)

    # include Catch2 as subdirectory or installed package
    # add_subdirectory(Catch2)
    find_package(Catch2 VERSION 2.1.0 REQUIRED)

    add_executable(tests tests/catch_main.cpp)
    target_link_libraries(tests PRIVATE Catch2::Catch)
2018-02-08 12:18:42 +01:00
Martin Hořeňovský
ba6d33fb8c Enable -Wpedantic, fix unconditional use of C++14 extension 2018-02-05 10:04:59 +01:00
Zachary Michaels
4be81d3588 Remove unnecessary semicolons 2018-02-05 10:03:51 +01:00
Josh Lospinoso
5201e92564 Redirect std::uncaught_exception to Catch::uncaught_exception
This means that only one place needs to work with warnings from
the deprecation of `std::uncaught_exception()` in C++17.

Closes #1162.
2018-02-02 15:36:15 +01:00
Martin Hořeňovský
5e484862f2 Add Catch::is_range to documentation 2018-02-01 20:29:49 +01:00
philsquared
5713381d06 Fixes for cygwin 2018-02-01 16:14:20 +00:00
Martin Hořeňovský
1ab6be30a2 Add a BrightYellow colour, also use it for reconstructed exprs
Closes #979
2018-02-01 14:58:33 +00:00
Martin Hořeňovský
126850e76b Prefer operator<< to range-based stringification
Fixes #1172
2018-02-01 14:07:23 +01:00
George Fotopoulos
5e8df1c384 Update opensource-users.md 2018-01-28 21:05:24 +01:00
Martin Hořeňovský
44dbda9f01 Add CATCH_VERSION_* defines for external use
I wonder how much use they will actually see, but their cost is
fairly minor.

Closes #1131
2018-01-26 20:56:14 +01:00
Phil Nash
ca2455e6e6 Fixed NoAssertions warning 2018-01-26 16:52:28 +00:00
Martin Hořeňovský
42213d4c31 Keep LICENCE.txt with LF as line endings for easy hashing 2018-01-26 16:45:32 +01:00
Martin Hořeňovský
62dae592c3 v2.1.1 2018-01-26 16:06:07 +01:00
Martin Hořeňovský
9a5705411a Add % to codecov coverage decrease threshold
Maybe now it will work?
2018-01-26 15:45:31 +01:00
Martin Hořeňovský
a1aefce6e4 Guard against CLR exceptions when translating exceptions
Partially fixes #1138, need to decide what to do about structured
exceptions.
2018-01-24 12:11:29 +01:00
Phil Nash
d5959907f5 Added Catch::clara namespace to doc for adding Opt
- Thanks to sakamoto-poteko in #1159 for point out its ommission
2018-01-23 07:44:09 +00:00
Phil Nash
31e6499e64 Embed Clara v1.1.1 2018-01-22 15:08:28 +00:00
David Seifert
b0f4f16ee0 Namespace Catch CMake options 2018-01-18 23:20:26 +01:00
David Seifert
1e3ddbb496 Specify VERSION in modern CMake 2018-01-18 23:20:26 +01:00
Martin Hořeňovský
15ad95c8db Make generateSingleHeader compatible with Python 2.7 2018-01-18 16:28:19 +01:00
Martin Hořeňovský
00a10d5a5e Return fixed codecov settings 2018-01-18 13:51:32 +01:00
David Seifert
0d687a15d3 Change CMake project name to 'Catch2' 2018-01-18 13:13:39 +01:00
David Seifert
bdf431c400 Install documentation 2018-01-18 13:13:39 +01:00
David Seifert
a0359980f0 Use CTest to control test suite via BUILD_TESTING 2018-01-18 13:13:39 +01:00
David Seifert
8d4074aad9 Use GNUInstallDirs module
* `GNUInstallDirs` is a standardised way to
  change paths, which makes systems integration
  easier and allows for a more consistent user
  experience.
2018-01-18 13:13:39 +01:00
Martin Hořeňovský
f0f40a0dbf Ensure that the single header is kept with LFs 2018-01-18 12:44:59 +01:00
Martin Hořeňovský
fa4fd7f296 Modify codecov.yml again 2018-01-15 13:59:48 +01:00
Martin Hořeňovský
07c84adfba Allow disabling -Werror in CMake
Related to #1152
2018-01-14 18:14:11 +01:00
Martin Hořeňovský
8d854c689b Provide useful and unambigous stringification for static arrays 2018-01-14 18:06:43 +01:00
Martin Hořeňovský
f0909dfe02 Add yet another expansion of INF macro
Closes #1151
2018-01-14 17:04:36 +01:00
Martin Hořeňovský
de36b2ada6 Fix compilation for types where relops don't return bool
Closes #1147
2018-01-12 15:49:56 +01:00
Martin Hořeňovský
9700ee4fc0 Update CTest autodiscovery documentation 2018-01-12 12:28:14 +01:00
Martin Hořeňovský
bbda8cd77c Update reporter docs with their new location 2018-01-12 12:20:52 +01:00
Martin Hořeňovský
4575594bbf Comment why the return code is clamped 2018-01-12 11:49:48 +01:00
Martin Hořeňovský
c053dca26e Update path to vcpkg's portfile 2018-01-12 11:09:46 +01:00
garethsb-sony
3d7104c124 Catch `catch_discover_tests`
Copied from [Dynamic Catch test discovery in CMake](https://gist.github.com/garethsb/a01ed0dbd4977d439c16200640549935), which was inspired by [Dynamic Google Test Discovery in CMake 3.10](https://blog.kitware.com/dynamic-google-test-discovery-in-cmake-3-10/).

Original source code:

- Adapted by [Gareth Sylvester-Bradley](https://github.com/garethsb) from [GoogleTest ``gtest_discover_tests``](https://gitlab.kitware.com/cmake/cmake/merge_requests/1056).
- BSD 3-clause "New" or "Revised" License.
- Copyright 2000-2017 Kitware, Inc. and Contributors. All rights reserved.
2018-01-11 21:17:12 +01:00
Martin Hořeňovský
6441c20a2c Modify codecov behaviour 2018-01-11 21:13:52 +01:00
Martin Hořeňovský
5774c4f9c2 Update release process with the need to release reporters 2018-01-11 21:06:35 +01:00
Martin Hořeňovský
2bc33dd04d Fix script responsible for updating release link in the readme 2018-01-10 14:02:15 +01:00
95 changed files with 2671 additions and 910 deletions

13
.gitattributes vendored
View File

@@ -8,4 +8,15 @@
*.hpp text
# Windows specific files should retain windows line-endings
*.sln text eol=crlf
*.sln text eol=crlf
# Keep executable scripts with LFs so they can be run after being
# checked out on Windows
*.py text eol=lf
# Keep the single include header with LFs to make sure it is uploaded,
# hashed etc with LF
single_include/*.hpp eol=lf
# Also keep the LICENCE file with LFs for the same reason
LICENCE.txt eol=lf

View File

@@ -1,6 +1,10 @@
language: cpp
sudo: false
branches:
except:
- /dev-appveyor.*/
common_sources: &all_sources
- ubuntu-toolchain-r-test
- llvm-toolchain-trusty
@@ -17,145 +21,140 @@ matrix:
addons:
apt:
sources: *all_sources
packages: ['valgrind', 'lcov', 'clang-3.5']
env: COMPILER='clang++-3.5' VALGRIND=1
packages: ['clang-3.5']
env: COMPILER='clang++-3.5'
- os: linux
compiler: clang
addons:
apt:
sources: *all_sources
packages: ['valgrind', 'lcov', 'clang-3.6']
env: COMPILER='clang++-3.6' VALGRIND=1
packages: ['clang-3.6']
env: COMPILER='clang++-3.6'
# Travis's containers do not seem to have Clang 3.7 in apt, no matter what sources I add.
# - os: linux
# compiler: clang
# addons:
# apt:
# sources: *all_sources
# packages: ['valgrind', 'clang-3.7']
# env: COMPILER='clang++-3.7' VALGRIND=1
# Clang 3.7 is intentionally skipped as we cannot get it easily on
# TravisCI container
- os: linux
compiler: clang
addons:
apt:
sources: *all_sources
packages: ['valgrind', 'lcov', 'clang-3.8']
env: COMPILER='clang++-3.8' VALGRIND=1
packages: ['lcov', 'clang-3.8']
env: COMPILER='clang++-3.8'
- os: linux
compiler: clang
addons:
apt:
sources: *all_sources
packages: ['clang-3.9', 'valgrind', 'lcov']
env: COMPILER='clang++-3.9' VALGRIND=1
packages: ['clang-3.9']
env: COMPILER='clang++-3.9'
- os: linux
compiler: clang
addons:
apt:
sources: *all_sources
packages: ['clang-4.0', 'valgrind', 'lcov']
env: COMPILER='clang++-4.0' VALGRIND=1
packages: ['clang-4.0']
env: COMPILER='clang++-4.0'
- os: linux
compiler: clang
addons:
apt:
sources: *all_sources
packages: ['clang-5.0', 'valgrind', 'lcov']
env: COMPILER='clang++-5.0' VALGRIND=1
packages: ['clang-5.0']
env: COMPILER='clang++-5.0'
# 2/ Linux GCC Builds
- os: linux
compiler: gcc
addons:
apt:
sources: ['ubuntu-toolchain-r-test']
packages: ['valgrind', 'lcov', 'g++-4.8']
env: COMPILER='g++-4.8' VALGRIND=1
sources: *all_sources
packages: ['g++-4.8']
env: COMPILER='g++-4.8'
- os: linux
compiler: gcc
addons:
apt:
sources: *all_sources
packages: ['valgrind', 'lcov', 'g++-4.9']
env: COMPILER='g++-4.9' VALGRIND=1
packages: ['g++-4.9']
env: COMPILER='g++-4.9'
- os: linux
compiler: gcc
addons:
apt:
sources: *all_sources
packages: ['valgrind', 'lcov', 'g++-5']
env: COMPILER='g++-5' VALGRIND=1
packages: ['g++-5']
env: COMPILER='g++-5'
- os: linux
compiler: gcc
addons: &gcc6
apt:
sources: *all_sources
packages: ['valgrind', 'lcov', 'g++-6']
env: COMPILER='g++-6' VALGRIND=1
packages: ['g++-6']
env: COMPILER='g++-6'
- os: linux
compiler: gcc
addons: &gcc7
apt:
sources: *all_sources
packages: ['valgrind', 'lcov', 'g++-7']
env: COMPILER='g++-7' VALGRIND=1
packages: ['g++-7']
env: COMPILER='g++-7'
# 3b/ Linux C++14 Clang builds
# Note that we need newer libstdc++ for C++14 support
- os: linux
compiler: clang
addons:
apt:
packages: ['clang-3.8', 'valgrind', 'lcov', 'libstdc++-6-dev']
packages: ['clang-3.8', 'libstdc++-6-dev']
sources:
- ubuntu-toolchain-r-test
- llvm-toolchain-trusty
env: COMPILER='clang++-3.8' CPP14=1 VALGRIND=1
env: COMPILER='clang++-3.8' CPP14=1
- os: linux
compiler: clang
addons:
apt:
sources: *all_sources
packages: ['clang-3.9', 'valgrind', 'lcov', 'libstdc++-6-dev']
env: COMPILER='clang++-3.9' CPP14=1 VALGRIND=1
packages: ['clang-3.9', 'libstdc++-6-dev']
env: COMPILER='clang++-3.9' CPP14=1
- os: linux
compiler: clang
addons:
apt:
sources: *all_sources
packages: ['clang-4.0', 'valgrind', 'lcov', 'libstdc++-6-dev']
env: COMPILER='clang++-4.0' CPP14=1 VALGRIND=1
packages: ['clang-4.0', 'libstdc++-6-dev']
env: COMPILER='clang++-4.0' CPP14=1
- os: linux
compiler: clang
addons:
apt:
sources: *all_sources
packages: ['clang-5.0', 'valgrind', 'lcov', 'libstdc++-6-dev']
env: COMPILER='clang++-5.0' CPP14=1 VALGRIND=1
packages: ['clang-5.0', 'libstdc++-6-dev']
env: COMPILER='clang++-5.0' CPP14=1
# 4a/ Linux C++14 GCC builds
- os: linux
compiler: gcc
addons: *gcc6
env: COMPILER='g++-6' CPP14=1 VALGRIND=1
env: COMPILER='g++-6' CPP14=1
- os: linux
compiler: gcc
addons: *gcc7
env: COMPILER='g++-7' CPP14=1 VALGRIND=1
env: COMPILER='g++-7' CPP14=1
# 5/ OSX Clang Builds
- os: osx
@@ -181,8 +180,39 @@ matrix:
- os: osx
osx_image: xcode9.1
compiler: clang
env: COMPILER='clang++' USE_CPP14=1
env: COMPILER='clang++' CPP14=1
# 6/ Special builds -- examples, coverage, valgrind, etc.
- os: linux
compiler: gcc
addons:
apt:
sources: *all_sources
packages: ['lcov', 'g++-7']
env: COMPILER='g++-7' CPP14=1 EXAMPLES=1 COVERAGE=1
- os: linux
compiler: clang
addons:
apt:
packages: ['clang-3.8', 'lcov']
sources:
- ubuntu-toolchain-r-test
- llvm-toolchain-trusty
env: COMPILER='clang++-3.8' EXAMPLES=1 COVERAGE=1
- os: linux
compiler: gcc
addons:
apt:
sources: *all_sources
packages: ['valgrind', 'lcov', 'g++-7']
env: COMPILER='g++-7' CPP14=1 VALGRIND=1
- os: osx
osx_image: xcode9.1
compiler: clang
env: COMPILER='clang++' CPP14=1 EXAMPLES=1 COVERAGE=1
install:
- DEPS_DIR="${TRAVIS_BUILD_DIR}/deps"
@@ -204,7 +234,7 @@ before_script:
- |
# Use Debug builds for running Valgrind and building examples
cmake -H. -BBuild-Debug -DCMAKE_BUILD_TYPE=Debug -Wdev -DUSE_CPP14=${CPP14} -DUSE_VALGRIND=${VALGRIND} -DBUILD_EXAMPLES=ON -DENABLE_COVERAGE=ON
cmake -H. -BBuild-Debug -DCMAKE_BUILD_TYPE=Debug -Wdev -DUSE_CPP14=${CPP14} -DCATCH_USE_VALGRIND=${VALGRIND} -DCATCH_BUILD_EXAMPLES=${EXAMPLES} -DCATCH_ENABLE_COVERAGE=${COVERAGE}
# Don't bother with release build for coverage build
cmake -H. -BBuild-Release -DCMAKE_BUILD_TYPE=Release -Wdev -DUSE_CPP14=${CPP14}
@@ -215,7 +245,9 @@ script:
make -j 2
CTEST_OUTPUT_ON_FAILURE=1 ctest -j 2
# Coverage collection does not work for OS X atm
if [[ "${TRAVIS_OS_NAME}" == "linux" ]]; then
echo "${TRAVIS_OS_NAME}";
echo "${COVERAGE}";
if [[ "${TRAVIS_OS_NAME}" == "linux" ]] && [[ "${COVERAGE}" == "1" ]]; then
make gcov
make lcov
bash <(curl -s https://codecov.io/bash) -X gcov || echo "Codecov did not collect coverage reports"

View File

@@ -1,10 +1,19 @@
cmake_minimum_required(VERSION 3.0)
cmake_minimum_required(VERSION 3.1)
project(CatchSelfTest)
# detect if Catch is being bundled,
# disable testsuite in that case
if(NOT DEFINED PROJECT_NAME)
set(NOT_SUBPROJECT ON)
endif()
option(USE_VALGRIND "Perform SelfTests with Valgrind" OFF)
option(BUILD_EXAMPLES "Build documentation examples" OFF)
option(ENABLE_COVERAGE "Generate coverage for codecov.io" OFF)
project(Catch2 LANGUAGES CXX VERSION 2.2.1)
include(GNUInstallDirs)
option(CATCH_USE_VALGRIND "Perform SelfTests with Valgrind" OFF)
option(CATCH_BUILD_EXAMPLES "Build documentation examples" OFF)
option(CATCH_ENABLE_COVERAGE "Generate coverage for codecov.io" OFF)
option(CATCH_ENABLE_WERROR "Enable all warnings as errors" ON)
set_property(GLOBAL PROPERTY USE_FOLDERS ON)
@@ -13,7 +22,6 @@ set(CATCH_DIR ${CMAKE_CURRENT_SOURCE_DIR})
set(SELF_TEST_DIR ${CATCH_DIR}/projects/SelfTest)
set(BENCHMARK_DIR ${CATCH_DIR}/projects/Benchmark)
set(HEADER_DIR ${CATCH_DIR}/include)
set(CATCH_VERSION_NUMBER 2.1.0)
if(USE_WMAIN)
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} /ENTRY:wmainCRTStartup")
@@ -179,6 +187,7 @@ set(INTERNAL_HEADERS
${HEADER_DIR}/internal/catch_timer.h
${HEADER_DIR}/internal/catch_tostring.h
${HEADER_DIR}/internal/catch_totals.h
${HEADER_DIR}/internal/catch_uncaught_exceptions.h
${HEADER_DIR}/internal/catch_user_interfaces.h
${HEADER_DIR}/internal/catch_version.h
${HEADER_DIR}/internal/catch_wildcard_pattern.h
@@ -239,6 +248,7 @@ set(IMPL_SOURCES
${HEADER_DIR}/internal/catch_timer.cpp
${HEADER_DIR}/internal/catch_tostring.cpp
${HEADER_DIR}/internal/catch_totals.cpp
${HEADER_DIR}/internal/catch_uncaught_exceptions.cpp
${HEADER_DIR}/internal/catch_version.cpp
${HEADER_DIR}/internal/catch_wildcard_pattern.cpp
${HEADER_DIR}/internal/catch_xmlwriter.cpp
@@ -284,7 +294,19 @@ SOURCE_GROUP("Surrogates" FILES ${SURROGATE_SOURCES})
# Projects consuming Catch via ExternalProject_Add might want to use install step
# without building all of our selftests.
if (NOT NO_SELFTEST)
if(DEFINED NO_SELFTEST)
message(DEPRECATION "*** CMake option NO_SELFTEST is deprecated; use BUILD_TESTING instead")
if (NO_SELFTEST)
set(BUILD_TESTING OFF CACHE BOOL "Disable Catch2 internal testsuite" FORCE)
else()
set(BUILD_TESTING ON CACHE BOOL "Disable Catch2 internal testsuite" FORCE)
endif()
endif()
include(CTest)
if (BUILD_TESTING AND NOT_SUBPROJECT)
add_executable(SelfTest ${TEST_SOURCES} ${IMPL_SOURCES} ${REPORTER_SOURCES} ${SURROGATE_SOURCES} ${HEADERS})
target_include_directories(SelfTest PRIVATE ${HEADER_DIR})
@@ -299,7 +321,8 @@ if (NOT NO_SELFTEST)
set_property(TARGET SelfTest PROPERTY CXX_STANDARD_REQUIRED ON)
set_property(TARGET SelfTest PROPERTY CXX_EXTENSIONS OFF)
if (ENABLE_COVERAGE)
if (CATCH_ENABLE_COVERAGE)
set(ENABLE_COVERAGE ON CACHE BOOL "Enable coverage build." FORCE)
list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_LIST_DIR}/CMake")
find_package(codecov)
add_coverage(SelfTest)
@@ -307,18 +330,25 @@ if (NOT NO_SELFTEST)
coverage_evaluate()
endif()
# Add desired warnings
# Add per compiler options
if ( CMAKE_CXX_COMPILER_ID MATCHES "Clang|AppleClang|GNU" )
target_compile_options( SelfTest PRIVATE -Wall -Wextra -Wunreachable-code -Werror )
target_compile_options( SelfTest PRIVATE -Wall -Wextra -Wunreachable-code -Wpedantic)
if (CATCH_ENABLE_WERROR)
target_compile_options( SelfTest PRIVATE -Werror)
endif()
endif()
# Clang specific warning go here
# Clang specific options go here
if ( CMAKE_CXX_COMPILER_ID MATCHES "Clang" )
# Actually keep these
target_compile_options( SelfTest PRIVATE -Wweak-vtables -Wexit-time-destructors -Wglobal-constructors -Wmissing-noreturn )
endif()
if ( CMAKE_CXX_COMPILER_ID MATCHES "MSVC" )
STRING(REGEX REPLACE "/W[0-9]" "/W4" CMAKE_CXX_FLAGS ${CMAKE_CXX_FLAGS}) # override default warning level
target_compile_options( SelfTest PRIVATE /w44265 /WX /w44061 /w44062 )
target_compile_options( SelfTest PRIVATE /w44265 /w44061 /w44062 )
if (CATCH_ENABLE_WERROR)
target_compile_options( SelfTest PRIVATE /WX)
endif()
# Force MSVC to consider everything as encoded in utf-8
target_compile_options( SelfTest PRIVATE /utf-8 )
endif()
@@ -327,24 +357,35 @@ if (NOT NO_SELFTEST)
add_test(NAME RunTests COMMAND $<TARGET_FILE:SelfTest>)
add_test(NAME ListTests COMMAND $<TARGET_FILE:SelfTest> --list-tests --verbosity high)
set_tests_properties(ListTests PROPERTIES PASS_REGULAR_EXPRESSION "[0-9]+ test cases")
set_tests_properties(ListTests PROPERTIES
PASS_REGULAR_EXPRESSION "[0-9]+ test cases"
FAIL_REGULAR_EXPRESSION "Hidden Test"
)
add_test(NAME ListTags COMMAND $<TARGET_FILE:SelfTest> --list-tags)
set_tests_properties(ListTags PROPERTIES PASS_REGULAR_EXPRESSION "[0-9]+ tags")
set_tests_properties(ListTags PROPERTIES
PASS_REGULAR_EXPRESSION "[0-9]+ tags"
FAIL_REGULAR_EXPRESSION "[.]")
add_test(NAME ListReporters COMMAND $<TARGET_FILE:SelfTest> --list-reporters)
set_tests_properties(ListReporters PROPERTIES PASS_REGULAR_EXPRESSION "Available reporters:")
add_test(NAME ListTestNamesOnly COMMAND $<TARGET_FILE:SelfTest> --list-test-names-only)
set_tests_properties(ListTestNamesOnly PROPERTIES PASS_REGULAR_EXPRESSION "Regex string matcher")
set_tests_properties(ListTestNamesOnly PROPERTIES
PASS_REGULAR_EXPRESSION "Regex string matcher"
FAIL_REGULAR_EXPRESSION "Hidden Test")
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")
# AppVeyor has a Python 2.7 in path, but doesn't have .py files as autorunnable
add_test(NAME ApprovalTests COMMAND python ${CMAKE_CURRENT_SOURCE_DIR}/scripts/approvalTests.py $<TARGET_FILE:SelfTest>)
set_tests_properties(ApprovalTests PROPERTIES FAIL_REGULAR_EXPRESSION "Results differed")
if (USE_VALGRIND)
if (CATCH_USE_VALGRIND)
add_test(NAME ValgrindRunTests COMMAND valgrind --leak-check=full --error-exitcode=1 $<TARGET_FILE:SelfTest>)
add_test(NAME ValgrindListTests COMMAND valgrind --leak-check=full --error-exitcode=1 $<TARGET_FILE:SelfTest> --list-tests --verbosity high)
set_tests_properties(ValgrindListTests PROPERTIES PASS_REGULAR_EXPRESSION "definitely lost: 0 bytes in 0 blocks")
@@ -355,18 +396,20 @@ if (NOT NO_SELFTEST)
endif() # !NO_SELFTEST
if(BUILD_EXAMPLES)
if(CATCH_BUILD_EXAMPLES)
add_subdirectory(examples)
endif()
install(DIRECTORY "single_include/" DESTINATION "include/catch")
install(DIRECTORY "single_include/" DESTINATION "${CMAKE_INSTALL_INCLUDEDIR}/catch")
install(DIRECTORY docs/ DESTINATION "${CMAKE_INSTALL_DOCDIR}")
## Provide some pkg-config integration
# Don't bother on Windows
if(NOT WIN32 OR NOT CMAKE_HOST_SYSTEM_NAME MATCHES Windows)
set(PKGCONFIG_INSTALL_DIR
"${CMAKE_INSTALL_PREFIX}/share/pkgconfig"
"${CMAKE_INSTALL_DATAROOTDIR}/pkgconfig"
CACHE PATH "Path where catch.pc is installed"
)
@@ -374,3 +417,38 @@ if(NOT WIN32 OR NOT CMAKE_HOST_SYSTEM_NAME MATCHES Windows)
install(FILES ${CMAKE_CURRENT_BINARY_DIR}/catch.pc DESTINATION ${PKGCONFIG_INSTALL_DIR})
endif()
# add catch as a 'linkable' target
add_library(Catch INTERFACE)
# depend on some obvious c++11 features so the dependency is transitively added dependants
target_compile_features(Catch INTERFACE cxx_auto_type cxx_constexpr cxx_noexcept)
target_include_directories(Catch
INTERFACE
$<BUILD_INTERFACE:${CMAKE_CURRENT_LIST_DIR}/single_include>
$<INSTALL_INTERFACE:include/catch>
$<INSTALL_INTERFACE:include>)
# provide a namespaced alias for clients to 'link' against if catch is included as a sub-project
add_library(Catch2::Catch ALIAS Catch)
set(CATCH_CMAKE_CONFIG_DESTINATION "${CMAKE_INSTALL_LIBDIR}/cmake/Catch2")
# create and install an export set for catch target as Catch2::Catch
install(TARGETS Catch EXPORT Catch2Config DESTINATION ${CMAKE_INSTALL_LIBDIR})
install(EXPORT Catch2Config
NAMESPACE Catch2::
DESTINATION ${CATCH_CMAKE_CONFIG_DESTINATION})
# install Catch2ConfigVersion.cmake file to handle versions in find_package
include(CMakePackageConfigHelpers)
write_basic_package_version_file(
"${CMAKE_CURRENT_BINARY_DIR}/Catch2ConfigVersion.cmake"
COMPATIBILITY SameMajorVersion)
install(FILES
"${CMAKE_CURRENT_BINARY_DIR}/Catch2ConfigVersion.cmake"
DESTINATION ${CATCH_CMAKE_CONFIG_DESTINATION})

View File

@@ -5,9 +5,9 @@
[![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/nerce2MiN6sVmfCi)
[![Try online](https://img.shields.io/badge/try-online-blue.svg)](https://wandbox.org/permlink/zDKMK3eGMC9IP2jy)
<a href="https://github.com/catchorg/Catch2/releases/download/v2.0.1/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.2.1/catch.hpp">The latest version of the single header can be downloaded directly using this link</a>
## Catch2 is released!

View File

@@ -19,18 +19,51 @@ environment:
- additional_flags: "/D_UNICODE /DUNICODE"
wmain: 1
coverage: 0
# Have a coverage dimension
- additional_flags: ""
wmain: 0
coverage: 1
# Have an examples dimension
- additional_flags: ""
wmain: 0
examples: 1
matrix:
exclude:
- os: Visual Studio 2015
additional_flags: "/permissive- /std:c++latest"
init:
- git config --global core.autocrlf input
- os: Visual Studio 2015
additional_flags: "/D_UNICODE /DUNICODE"
# Exclude unwanted coverage configurations
- coverage: 1
platform: Win32
- coverage: 1
os: Visual Studio 2015
- coverage: 1
configuration: Release
# Exclude unwanted examples configurations
- examples: 1
platform: Win32
- examples: 1
os: Visual Studio 2015
- examples: 1
configuration: Release
install:
- ps: if (($env:CONFIGURATION) -eq "Debug" ) { python -m pip install codecov }
- ps: if (($env:CONFIGURATION) -eq "Debug" ) { .\misc\installOpenCppCoverage.ps1 }
- ps: if (($env:CONFIGURATION) -eq "Debug" -And ($env:coverage) -eq "1" ) { python -m pip install codecov }
- ps: if (($env:CONFIGURATION) -eq "Debug" -And ($env:coverage) -eq "1" ) { .\misc\installOpenCppCoverage.ps1 }
# Win32 and x64 are CMake-compatible solution platform names.
# This allows us to pass %PLATFORM% to CMake -A.
@@ -54,7 +87,7 @@ before_build:
# build with MSBuild
build:
project: Build\CatchSelfTest.sln # path to Visual Studio solution or project
project: Build\Catch2.sln # path to Visual Studio solution or project
parallel: true # enable MSBuild parallel builds
verbosity: normal # MSBuild verbosity level {quiet|minimal|normal|detailed}

View File

@@ -1,9 +1,6 @@
prefix=@CMAKE_INSTALL_PREFIX@
exec_prefix=${prefix}
includedir=@CMAKE_INSTALL_FULL_INCLUDEDIR@
Name: Catch
Description: Testing library for C++
Requires:
Version: @CATCH_VERSION_NUMBER@
Libs:
Cflags: -I${prefix}/@INCLUDE_INSTALL_DIR@/include
Version: @Catch2_VERSION@
Cflags: -I${includedir}

View File

@@ -1,6 +1,22 @@
coverage:
precision: 2
round: nearest
range: "60...90"
status:
project:
default:
threshold: 2%
patch:
default:
target: 80%
codecov:
branch: master
comment:
layout: "diff"
coverage:
ignore:
- "projects/SelfTest"

View File

@@ -4,7 +4,7 @@ from conans import ConanFile
class CatchConan(ConanFile):
name = "Catch"
version = "2.1.0"
version = "2.2.1"
description = "A modern, C++-native, header-only, framework for unit-tests, TDD and BDD"
author = "philsquared"
generators = "cmake"

175
contrib/Catch.cmake Normal file
View File

@@ -0,0 +1,175 @@
# Distributed under the OSI-approved BSD 3-Clause License. See accompanying
# file Copyright.txt or https://cmake.org/licensing for details.
#[=======================================================================[.rst:
Catch
-----
This module defines a function to help use the Catch test framework.
The :command:`catch_discover_tests` discovers tests by asking the compiled test
executable to enumerate its tests. This does not require CMake to be re-run
when tests change. However, it may not work in a cross-compiling environment,
and setting test properties is less convenient.
This command is intended to replace use of :command:`add_test` to register
tests, and will create a separate CTest test for each Catch test case. Note
that this is in some cases less efficient, as common set-up and tear-down logic
cannot be shared by multiple test cases executing in the same instance.
However, it provides more fine-grained pass/fail information to CTest, which is
usually considered as more beneficial. By default, the CTest test name is the
same as the Catch name; see also ``TEST_PREFIX`` and ``TEST_SUFFIX``.
.. command:: catch_discover_tests
Automatically add tests with CTest by querying the compiled test executable
for available tests::
catch_discover_tests(target
[TEST_SPEC arg1...]
[EXTRA_ARGS arg1...]
[WORKING_DIRECTORY dir]
[TEST_PREFIX prefix]
[TEST_SUFFIX suffix]
[PROPERTIES name1 value1...]
[TEST_LIST var]
)
``catch_discover_tests`` sets up a post-build command on the test executable
that generates the list of tests by parsing the output from running the test
with the ``--list-test-names-only`` argument. This ensures that the full
list of tests is obtained. Since test discovery occurs at build time, it is
not necessary to re-run CMake when the list of tests changes.
However, it requires that :prop_tgt:`CROSSCOMPILING_EMULATOR` is properly set
in order to function in a cross-compiling environment.
Additionally, setting properties on tests is somewhat less convenient, since
the tests are not available at CMake time. Additional test properties may be
assigned to the set of tests as a whole using the ``PROPERTIES`` option. If
more fine-grained test control is needed, custom content may be provided
through an external CTest script using the :prop_dir:`TEST_INCLUDE_FILES`
directory property. The set of discovered tests is made accessible to such a
script via the ``<target>_TESTS`` variable.
The options are:
``target``
Specifies the Catch executable, which must be a known CMake executable
target. CMake will substitute the location of the built executable when
running the test.
``TEST_SPEC arg1...``
Specifies test cases, wildcarded test cases, tags and tag expressions to
pass to the Catch executable with the ``--list-test-names-only`` argument.
``EXTRA_ARGS arg1...``
Any extra arguments to pass on the command line to each test case.
``WORKING_DIRECTORY dir``
Specifies the directory in which to run the discovered test cases. If this
option is not provided, the current binary directory is used.
``TEST_PREFIX prefix``
Specifies a ``prefix`` to be prepended to the name of each discovered test
case. This can be useful when the same test executable is being used in
multiple calls to ``catch_discover_tests()`` but with different
``TEST_SPEC`` or ``EXTRA_ARGS``.
``TEST_SUFFIX suffix``
Similar to ``TEST_PREFIX`` except the ``suffix`` is appended to the name of
every discovered test case. Both ``TEST_PREFIX`` and ``TEST_SUFFIX`` may
be specified.
``PROPERTIES name1 value1...``
Specifies additional properties to be set on all tests discovered by this
invocation of ``catch_discover_tests``.
``TEST_LIST var``
Make the list of tests available in the variable ``var``, rather than the
default ``<target>_TESTS``. This can be useful when the same test
executable is being used in multiple calls to ``catch_discover_tests()``.
Note that this variable is only available in CTest.
#]=======================================================================]
#------------------------------------------------------------------------------
function(catch_discover_tests TARGET)
cmake_parse_arguments(
""
""
"TEST_PREFIX;TEST_SUFFIX;WORKING_DIRECTORY;TEST_LIST"
"TEST_SPEC;EXTRA_ARGS;PROPERTIES"
${ARGN}
)
if(NOT _WORKING_DIRECTORY)
set(_WORKING_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}")
endif()
if(NOT _TEST_LIST)
set(_TEST_LIST ${TARGET}_TESTS)
endif()
## Generate a unique name based on the extra arguments
string(SHA1 args_hash "${_TEST_SPEC} ${_EXTRA_ARGS}")
string(SUBSTRING ${args_hash} 0 7 args_hash)
# Define rule to generate test list for aforementioned test executable
set(ctest_include_file "${CMAKE_CURRENT_BINARY_DIR}/${TARGET}_include-${args_hash}.cmake")
set(ctest_tests_file "${CMAKE_CURRENT_BINARY_DIR}/${TARGET}_tests-${args_hash}.cmake")
get_property(crosscompiling_emulator
TARGET ${TARGET}
PROPERTY CROSSCOMPILING_EMULATOR
)
add_custom_command(
TARGET ${TARGET} POST_BUILD
BYPRODUCTS "${ctest_tests_file}"
COMMAND "${CMAKE_COMMAND}"
-D "TEST_TARGET=${TARGET}"
-D "TEST_EXECUTABLE=$<TARGET_FILE:${TARGET}>"
-D "TEST_EXECUTOR=${crosscompiling_emulator}"
-D "TEST_WORKING_DIR=${_WORKING_DIRECTORY}"
-D "TEST_SPEC=${_TEST_SPEC}"
-D "TEST_EXTRA_ARGS=${_EXTRA_ARGS}"
-D "TEST_PROPERTIES=${_PROPERTIES}"
-D "TEST_PREFIX=${_TEST_PREFIX}"
-D "TEST_SUFFIX=${_TEST_SUFFIX}"
-D "TEST_LIST=${_TEST_LIST}"
-D "CTEST_FILE=${ctest_tests_file}"
-P "${_CATCH_DISCOVER_TESTS_SCRIPT}"
VERBATIM
)
file(WRITE "${ctest_include_file}"
"if(EXISTS \"${ctest_tests_file}\")\n"
" include(\"${ctest_tests_file}\")\n"
"else()\n"
" add_test(${TARGET}_NOT_BUILT-${args_hash} ${TARGET}_NOT_BUILT-${args_hash})\n"
"endif()\n"
)
if(NOT ${CMAKE_VERSION} VERSION_LESS "3.10.0")
# Add discovered tests to directory TEST_INCLUDE_FILES
set_property(DIRECTORY
APPEND PROPERTY TEST_INCLUDE_FILES "${ctest_include_file}"
)
else()
# Add discovered tests as directory TEST_INCLUDE_FILE if possible
get_property(test_include_file_set DIRECTORY PROPERTY TEST_INCLUDE_FILE SET)
if (NOT ${test_include_file_set})
set_property(DIRECTORY
PROPERTY TEST_INCLUDE_FILE "${ctest_include_file}"
)
else()
message(FATAL_ERROR
"Cannot set more than one TEST_INCLUDE_FILE"
)
endif()
endif()
endfunction()
###############################################################################
set(_CATCH_DISCOVER_TESTS_SCRIPT
${CMAKE_CURRENT_LIST_DIR}/CatchAddTests.cmake
)

View File

@@ -0,0 +1,77 @@
# Distributed under the OSI-approved BSD 3-Clause License. See accompanying
# file Copyright.txt or https://cmake.org/licensing for details.
set(prefix "${TEST_PREFIX}")
set(suffix "${TEST_SUFFIX}")
set(spec ${TEST_SPEC})
set(extra_args ${TEST_EXTRA_ARGS})
set(properties ${TEST_PROPERTIES})
set(script)
set(suite)
set(tests)
function(add_command NAME)
set(_args "")
foreach(_arg ${ARGN})
if(_arg MATCHES "[^-./:a-zA-Z0-9_]")
set(_args "${_args} [==[${_arg}]==]") # form a bracket_argument
else()
set(_args "${_args} ${_arg}")
endif()
endforeach()
set(script "${script}${NAME}(${_args})\n" PARENT_SCOPE)
endfunction()
# Run test executable to get list of available tests
if(NOT EXISTS "${TEST_EXECUTABLE}")
message(FATAL_ERROR
"Specified test executable '${TEST_EXECUTABLE}' does not exist"
)
endif()
execute_process(
COMMAND ${TEST_EXECUTOR} "${TEST_EXECUTABLE}" ${spec} --list-test-names-only
OUTPUT_VARIABLE output
RESULT_VARIABLE result
)
# Catch --list-test-names-only reports the number of tests, so 0 is... surprising
if(${result} EQUAL 0)
message(WARNING
"Test executable '${TEST_EXECUTABLE}' contains no tests!\n"
)
elseif(${result} LESS 0)
message(FATAL_ERROR
"Error running test executable '${TEST_EXECUTABLE}':\n"
" Result: ${result}\n"
" Output: ${output}\n"
)
endif()
string(REPLACE "\n" ";" output "${output}")
# Parse output
foreach(line ${output})
# Test name; strip spaces to get just the name...
string(REGEX REPLACE " +" "" test "${line}")
# ...and add to script
add_command(add_test
"${prefix}${test}${suffix}"
${TEST_EXECUTOR}
"${TEST_EXECUTABLE}"
"${test}"
${extra_args}
)
add_command(set_tests_properties
"${prefix}${test}${suffix}"
PROPERTIES
WORKING_DIRECTORY "${TEST_WORKING_DIR}"
${properties}
)
list(APPEND tests "${prefix}${test}${suffix}")
endforeach()
# Create a list of all discovered tests, which users may use to e.g. set
# properties on the tests
add_command(set ${TEST_LIST} ${tests})
# Write CTest script
file(WRITE "${CTEST_FILE}" "${script}")

View File

@@ -9,7 +9,7 @@
Most test frameworks have a large collection of assertion macros to capture all possible conditional forms (```_EQUALS```, ```_NOTEQUALS```, ```_GREATER_THAN``` etc).
Catch is different. Because it decomposes natural C-style conditional expressions most of these forms are reduced to one or two that you will use all the time. That said there are a rich set of auxilliary macros as well. We'll describe all of these here.
Catch is different. Because it decomposes natural C-style conditional expressions most of these forms are reduced to one or two that you will use all the time. That said there are a rich set of auxiliary macros as well. We'll describe all of these here.
Most of these macros come in two forms:

View File

@@ -28,9 +28,14 @@ The advantage of this format is that the JUnit Ant schema is widely understood b
The disadvantage is that this schema was designed to correspond to how JUnit works - and there is a significant mismatch with how Catch works. Additionally the format is not streamable (because opening elements hold counts of failed and passing tests as attributes) - so the whole test run must complete before it can be written.
## Other reporters
Other reporters are not part of the single-header distribution and need to be downloaded and included separately. All reporters are stored in `include/reporters` directory in the git repository, and are named `catch_reporter_*.hpp`. For example, to use the TeamCity reporter you need to download `include/reporters/catch_reporter_teamcity.hpp` and include it after Catch itself.
Other reporters are not part of the single-header distribution and need
to be downloaded and included separately. All reporters are stored in
`single_include` directory in the git repository, and are named
`catch_reporter_*.hpp`. For example, to use the TeamCity reporter you
need to download `single_include/catch_reporter_teamcity.hpp` and include
it after Catch itself.
```
```cpp
#define CATCH_CONFIG_MAIN
#include "catch.hpp"
#include "catch_reporter_teamcity.hpp"
@@ -124,7 +129,15 @@ The advantage of this approach is that you can always automatically update Catch
### Automatic test registration
If you are also using ctest, `contrib/ParseAndAddCatchTests.cmake` is a CMake script that attempts to parse your test files and automatically register all test cases, using tags as labels. This means that these
We provide 2 CMake scripts that can automatically register Catch-based
tests with CTest,
* `contrib/ParseAndAddCatchTests.cmake`
* `contrib/CatchAddTests.cmake`
The first is based on parsing the test implementation files, and attempts
to register all `TEST_CASE`s using their tags as labels. This means that
these:
```cpp
TEST_CASE("Test1", "[unit]") {
int a = 1;
@@ -144,7 +157,14 @@ TEST_CASE("Test3", "[a][b][c]") {
REQUIRE(a == b);
}
```
would be registered as 3 tests, `Test1`, `Test2` and `Test3`, and 4 ctest labels would be created, `a`, `b`, `c` and `unit`.
would be registered as 3 tests, `Test1`, `Test2` and `Test3`,
and 4 CTest labels would be created, `a`, `b`, `c` and `unit`.
The second is based on parsing the output of a Catch binary given
`--list-test-names-only`. This means that it deals with inactive
(e.g. commented-out) tests better, but requires CMake 3.10 for full
functionality.
### CodeCoverage module (GCOV, LCOV...)

View File

@@ -78,7 +78,7 @@ Wildcards consist of the `*` character at the beginning and/or end of test case
Test specs are case insensitive.
If a spec is prefixed with `exclude:` or the `~` character then the pattern matches an exclusion. This means that tests matching the pattern are excluded from the set - even if a prior inclusion spec included them. Subsequent inclusion specs will take precendence, however.
If a spec is prefixed with `exclude:` or the `~` character then the pattern matches an exclusion. This means that tests matching the pattern are excluded from the set - even if a prior inclusion spec included them. Subsequent inclusion specs will take precedence, however.
Inclusions and exclusions are evaluated in left-to-right order.
Test case examples:
@@ -94,7 +94,7 @@ a* ~ab* abc Matches all tests that start with 'a', except those that
</pre>
Names within square brackets are interpreted as tags.
A series of tags form an AND expression wheras a comma-separated sequence forms an OR expression. e.g.:
A series of tags form an AND expression whereas a comma-separated sequence forms an OR expression. e.g.:
<pre>[one][two],[three]</pre>
This matches all tests tagged `[one]` and `[two]`, as well as all tests tagged `[three]`
@@ -192,9 +192,16 @@ This option transforms tabs and newline characters into ```\t``` and ```\n``` re
## Warnings
<pre>-w, --warn &lt;warning name></pre>
Enables reporting of warnings (only one, at time of this writing). If a warning is issued it fails the test.
Enables reporting of suspicious test states. There are currently two
available warnings
```
NoAssertions // Fail test case / leaf section if no assertions
// (e.g. `REQUIRE`) is encountered.
NoTests // Return non-zero exit code when no test cases were run
// Also calls reporter's noMatchingTestCases method
```
The ony available warning, presently, is ```NoAssertions```. This warning fails a test case, or (leaf) section if no assertions (```REQUIRE```/ ```CHECK``` etc) are encountered.
<a id="reporting-timings"></a>
## Reporting timings
@@ -262,7 +269,7 @@ either before running any tests, after running all tests - or both, depending on
When running benchmarks the clock resolution is estimated. Benchmarks are then run for exponentially increasing
numbers of iterations until some multiple of the estimated resolution is exceed. By default that multiple is 100, but
it can be overriden here.
it can be overridden here.
<a id="usage"></a>
## Usage

View File

@@ -7,6 +7,8 @@
[Terminal colour](#terminal-colour)<br>
[Console width](#console-width)<br>
[stdout](#stdout)<br>
[Fallback stringifier](#fallback-stringifier)<br>
[Default reporter](#default-reporter)<br>
[Other toggles](#other-toggles)<br>
[Windows header clutter](#windows-header-clutter)<br>
[Enabling stringification](#enabling-stringification)<br>
@@ -24,7 +26,7 @@ Although Catch is header only it still, internally, maintains a distinction betw
# Reporter / Listener interfaces
CATCH_CONFIG_EXTERNAL_INTERFACES // Brings in neccessary headers for Reporter/Listener implementation
CATCH_CONFIG_EXTERNAL_INTERFACES // Brings in necessary headers for Reporter/Listener implementation
Brings in various parts of Catch that are required for user defined Reporters and Listeners. This means that new Reporters and Listeners can be defined in this file as well as in the main file.
@@ -73,6 +75,40 @@ Catch does not use ```std::cout```, ```std::cerr``` and ```std::clog``` directly
This can be useful on certain platforms that do not provide the standard iostreams, such as certain embedded systems.
## Fallback stringifier
By default Catch's stringification machinery falls back to a "{?}". To
let projects reuse their own existing stringification machinery, this
fallback can be overridden by defining `CATCH_CONFIG_FALLBACK_STRINGIFIER`
to a name of a function that should perform the stringification instead.
The provided function must return std::string and must accept any type
(e.g. via overloading).
_Note that if the provided function does not handle a type and this type
requires to be stringified, the compilation will fail._
## Default reporter
Catch's default reporter can be changed by defining macro
`CATCH_CONFIG_DEFAULT_REPORTER` to string literal naming the desired
default reporter.
This means that defining `CATCH_CONFIG_DEFAULT_REPORTER` to `"console"`
is equivalent with the out-of-the-box experience.
## C++17 toggles
CATCH_CONFIG_CPP17_UNCAUGHT_EXCEPTIONS // Use std::uncaught_exceptions instead of std::uncaught_exception
Catch contains basic compiler/standard detection and attempts to use
some C++17 features whenever appropriate. This automatic detection
can be manually overridden in both directions, that is, a feature
can be enabled by defining the macro in the table above, and disabled
by using `_NO_` in the macro, e.g. `CATCH_CONFIG_NO_CPP17_UNCAUGHT_EXCEPTIONS`.
## Other toggles
@@ -84,6 +120,7 @@ This can be useful on certain platforms that do not provide the standard iostrea
CATCH_CONFIG_WINDOWS_CRTDBG // Enable leak checking using Windows's CRT Debug Heap
CATCH_CONFIG_DISABLE_STRINGIFICATION // Disable stringifying the original expression
CATCH_CONFIG_DISABLE // Disables assertions and test case registration
CATCH_CONFIG_WCHAR // Enables use of wchart_t
Currently Catch enables `CATCH_CONFIG_WINDOWS_SEH` only when compiled with MSVC, because some versions of MinGW do not have the necessary Win32 API support.
@@ -91,12 +128,15 @@ Currently Catch enables `CATCH_CONFIG_WINDOWS_SEH` only when compiled with MSVC,
`CATCH_CONFIG_WINDOWS_CRTDBG` is off by default. If enabled, Windows's CRT is used to check for memory leaks, and displays them after the tests finish running.
`CATCH_CONFIG_WCHAR` is on by default, but can be disabled. Currently
it is only used in support for DJGPP cross-compiler.
These toggles can be disabled by using `_NO_` form of the toggle, e.g. `CATCH_CONFIG_NO_WINDOWS_SEH`.
### `CATCH_CONFIG_FAST_COMPILE`
Defining this flag speeds up compilation of test files by ~20%, by making 2 changes:
* The `-b` (`--break`) flag no longer makes Catch break into debugger in the same stack frame as the failed test, but rather in a stack frame *below*.
* Non-exception family of macros ({`REQUIRE`,`CHECK`}{`_`,`_FALSE`, `_FALSE`}, no longer use local try-cache block. This disables exception translation, but should not lead to false negatives.
* Non-exception family of macros ({`REQUIRE`,`CHECK`}{`_`,`_FALSE`, `_THAT`}, no longer use local try-catch block. This disables exception translation, but should not lead to false negatives.
`CATCH_CONFIG_FAST_COMPILE` has to be either defined, or not defined, in all translation units that are linked into single test binary, or the behaviour of setting `-b` flag and throwing unexpected exceptions will be unpredictable.

View File

@@ -44,7 +44,7 @@ _Note that you should not use any assertion macros within a Listener!_
## Events that can be hooked
The following are the methods that can be overriden in the Listener:
The following are the methods that can be overridden in the Listener:
```c++
// The whole test run, starting and ending

View File

@@ -96,6 +96,14 @@ with expansion:
""\" == ""\"
```
### Visual Studio 2015 -- Alignment compilation error (C2718)
VS 2015 has a known bug, where `declval<T>` can cause compilation error
if `T` has alignment requirements that it cannot meet.
A workaround is to explicitly specialize `Catch::is_range` for given
type (this avoids code path that uses `declval<T>` in a SFINAE context).
### Visual Studio 2015 -- Wrong line number reported in debug mode

View File

@@ -1,18 +1,18 @@
<a id="top"></a>
# Open Source projects using Catch
Catch is great for open source. With its [liberal license](../LICENSE.txt) and single-header, dependency-free, distribution
Catch is great for open source. With its [liberal license](../LICENSE.txt) and single-header, dependency-free, distribution
it's easy to just drop the header into your project and start writing tests - what's not to like?
As a result Catch is now being used in many Open Source projects, including some quite well known ones.
This page is an attempt to track those projects. Obviously it can never be complete.
This effort largely relies on the maintainers of the projects themselves updating this page and submitting a PR
(or, if you prefer contact one of the maintainers of Catch directly, use the
(or, if you prefer contact one of the maintainers of Catch directly, use the
[forums](https://groups.google.com/forum/?fromgroups#!forum/catch-forum)), or raise an [issue](https://github.com/philsquared/Catch/issues) to let us know).
Of course users of those projects might want to update this page too. That's fine - as long you're confident the project maintainers won't mind.
If you're an Open Source project maintainer and see your project listed here but would rather it wasn't -
If you're an Open Source project maintainer and see your project listed here but would rather it wasn't -
just let us know via any of the previously mentioned means - although I'm sure there won't be many who feel that way.
Listing a project here does not imply endorsement and the plan is to keep these ordered alphabetically to avoid an implication of relative importance.
## Libraries & Frameworks
@@ -21,7 +21,7 @@ Listing a project here does not imply endorsement and the plan is to keep these
Boost Asio style bindings for ZeroMQ
### [ChakraCore](https://github.com/Microsoft/ChakraCore)
The core part of the Chakra Javascript engine that powers Microsoft Edge
The core part of the Chakra JavaScript engine that powers Microsoft Edge
### [ChaiScript](https://github.com/ChaiScript/ChaiScript)
A, header-only, embedded scripting language designed from the ground up to directly target C++ and take advantage of modern C++ development techniques
@@ -35,6 +35,9 @@ The next-generation core storage and query engine for Couchbase Lite
### [DtCraft](https://github.com/twhuang-uiuc/DtCraft)
A High-performance Cluster Computing Engine
### [forest](https://github.com/xorz57/forest)
Forest is an open-source, template library of tree data structures written in C++11.
### [Fuxedo](https://github.com/fuxedo/fuxedo)
Open source Oracle Tuxedo-like XATMI middleware for C and C++.
@@ -88,6 +91,9 @@ MAME originally stood for Multiple Arcade Machine Emulator
### [Newsbeuter](https://github.com/akrennmair/newsbeuter)
Newsbeuter is an open-source RSS/Atom feed reader for text terminals.
### [SpECTRE](https://github.com/sxs-collaboration/spectre)
SpECTRE is a code for multi-scale, multi-physics problems in astrophysics and gravitational physics.
### [Standardese](https://github.com/foonathan/standardese)
Standardese aims to be a nextgen Doxygen

View File

@@ -30,7 +30,7 @@ int main( int argc, char* argv[] ) {
## Amending the config
If you still want Catch to process the command line, but you want to programatically tweak the config, you can do so in one of two ways:
If you still want Catch to process the command line, but you want to programmatically tweak the config, you can do so in one of two ways:
```c++
#define CATCH_CONFIG_RUNNER
@@ -81,6 +81,7 @@ int main( int argc, char* argv[] )
int height = 0; // Some user variable you want to be able to set
// Build a new parser on top of Catch's
using namespace Catch::clara;
auto cli
= session.cli() // Get Catch's composite command line parser
| Opt( height, "height" ) // bind variable to a new option, with a hint string
@@ -105,6 +106,20 @@ int main( int argc, char* argv[] )
See the [Clara documentation](https://github.com/philsquared/Clara/blob/master/README.md) for more details.
## Version detection
Catch provides a triplet of macros providing the header's version,
* `CATCH_VERSION_MAJOR`
* `CATCH_VERSION_MINOR`
* `CATCH_VERSION_PATCH`
these macros expand into a single number, that corresponds to the appropriate
part of the version. As an example, given single header version v2.3.4,
the macros would expand into `2`, `3`, and `4` respectively.
---
[Home](Readme.md#top)

View File

@@ -1,5 +1,73 @@
<a id="top"></a>
# 2.2.1
## Fixes
* Fixed compilation error when compiling Catch2 with `std=c++17` against libc++ (#1214)
* Clara (Catch2's CLI parsing library) used `std::optional` without including it explicitly
* Fixed Catch2 return code always being 0 (#1215)
* In the words of STL, "We feel superbad about letting this in"
# 2.2.0
## Fixes
* Hidden tests are not listed by default when listing tests (#1175)
* This makes `catch_discover_tests` CMake script work better
* Fixed regression that meant `<windows.h>` could potentially not be included properly (#1197)
* Fixed installing `Catch2ConfigVersion.cmake` when Catch2 is a subproject.
## Improvements
* Added an option to warn (+ exit with error) when no tests were ran (#1158)
* Use as `-w NoTests`
* Added provisional support for Emscripten (#1114)
* [Added a way to override the fallback stringifier](https://github.com/catchorg/Catch2/blob/master/docs/configuration.md#fallback-stringifier) (#1024)
* This allows project's own stringification machinery to be easily reused for Catch
* `Catch::Session::run()` now accepts `char const * const *`, allowing it to accept array of string literals (#1031, #1178)
* The embedded version of Clara was bumped to v1.1.3
* Various minor performance improvements
* Added support for DJGPP DOS crosscompiler (#1206)
# 2.1.2
## Fixes
* Fixed compilation error with `-fno-rtti` (#1165)
* Fixed NoAssertion warnings
* `operator<<` is used before range-based stringification (#1172)
* Fixed `-Wpedantic` warnings (extra semicolons and binary literals) (#1173)
## Improvements
* Added `CATCH_VERSION_{MAJOR,MINOR,PATCH}` macros (#1131)
* Added `BrightYellow` colour for use in reporters (#979)
* It is also used by ConsoleReporter for reconstructed expressions
## Other changes
* Catch is now exported as a CMake package and linkable target (#1170)
# 2.1.1
## Improvements
* Static arrays are now properly stringified like ranges across MSVC/GCC/Clang
* Embedded newer version of Clara -- v1.1.1
* This should fix some warnings dragged in from Clara
* MSVC's CLR exceptions are supported
## Fixes
* Fixed compilation when comparison operators do not return bool (#1147)
* Fixed CLR exceptions blowing up the executable during translation (#1138)
## Other changes
* Many CMake changes
* `NO_SELFTEST` option is deprecated, use `BUILD_TESTING` instead.
* Catch specific CMake options were prefixed with `CATCH_` for namespacing purposes
* Other changes to simplify Catch2's packaging
# 2.1.0
## Improvements
@@ -340,8 +408,8 @@ Cygwin issue with `gettimeofday` - `#define` was not early enough
* Cygwin compatibility fixes
* Signal handling is no longer compiled by default.
* Usage of `gettimeofday` inside Catch should no longer cause compilation errors.
* Improved `-Wparentheses` supression for gcc (#674)
* When compiled with gcc 4.8 or newer, the supression is localized to assertions only
* Improved `-Wparentheses` suppression for gcc (#674)
* When compiled with gcc 4.8 or newer, the suppression is localized to assertions only
* Otherwise it is supressed for the whole TU
* Fixed test spec parser issue (with escapes in multiple names)
@@ -360,7 +428,7 @@ Xml:
* C-escape control characters instead of XML encoding them (which requires XML 1.1)
* Revert XML output to XML 1.0
* Can provide stylesheet references by extending the XML reporter
* Added description and tags attribites to XML Reporter
* Added description and tags attributes to XML Reporter
* Tags are closed and the stream flushed more eagerly to avoid stdout interpolation

View File

@@ -1,11 +1,11 @@
<a id="top"></a>
# How to release
When enough changes have accumulated, it is time to release new version of Catch. This document describes the proces in doing so, that no steps are forgotten. Note that all referenced scripts can be found in the `scripts/` directory.
When enough changes have accumulated, it is time to release new version of Catch. This document describes the process in doing so, that no steps are forgotten. Note that all referenced scripts can be found in the `scripts/` directory.
## Neccessary steps
## Necessary steps
These steps are neccessary and have to be performed before each new release. They serve to make sure that the new release is correct and linked-to from the standard places.
These steps are necessary and have to be performed before each new release. They serve to make sure that the new release is correct and linked-to from the standard places.
### Approval testing
@@ -21,10 +21,8 @@ Catch uses a variant of [semantic versioning](http://semver.org/), with breaking
After deciding which part of version number should be incremented, you can use one of the `*Release.py` scripts to perform the required changes to Catch.
### Generate updated single-include header
After updating version number, regenerate single-include header using `generateSingleHeader.py`.
This will take care of generating the single include header, updating
version numbers everywhere and pushing the new version to Wandbox.
### Release notes
@@ -39,16 +37,24 @@ After version number is incremented, single-include header is regenerated and re
### Release on GitHub
After pushing changes to GitHub, GitHub release *needs* to be created. Tag version and release title should be same as the new version, description should contain the release notes for the current release. Single header version of `catch.hpp` *needs* to be attached as a binary, as that is where the official download link links to. Preferably it should use linux line endings.
After pushing changes to GitHub, GitHub release *needs* to be created.
Tag version and release title should be same as the new version,
description should contain the release notes for the current release.
Single header version of `catch.hpp` *needs* to be attached as a binary,
as that is where the official download link links to. Preferably
it should use linux line endings. All non-bundled reporters (Automake,
TAP, TeamCity) should also be attached as binaries, as they are dependent
on a specific version of the single-include header.
## Optional steps
The following steps are optional, and do not have to be performed when releasing new version of Catch. However, they are *should* happen, but they can happen the next day without losing anything significant.
The following steps are optional, and do not have to be performed when releasing new version of Catch. However, they *should* happen, but they can happen the next day without losing anything significant.
### vcpkg update
Catch is maintaining its own port in Microsoft's package manager [vcpkg](https://github.com/Microsoft/vcpkg). This means that when new version of Catch is released, it should be posted there as well. `updateVcpkgPackage.py` can do a lot of neccessary work for you, it creates a branch and commits neccessary changes. You should review these changes, push and open a PR against vcpkg's upstream.
Catch is maintaining its own port in Microsoft's package manager [vcpkg](https://github.com/Microsoft/vcpkg). This means that when new version of Catch is released, it should be posted there as well. `updateVcpkgPackage.py` can do a lot of necessary work for you, it creates a branch and commits necessary changes. You should review these changes, push and open a PR against vcpkg's upstream.
Note that the script assumes you have your fork of vcpkg checked out in a directory next to the directory where you have checked out Catch, like so:
```
@@ -57,8 +63,3 @@ GitHub
vcpkg
```
### Wandbox update
Recently we also included a link to wandbox with preloaded Catch on the main page. Strictly speaking it is unneccessary to update this after every release, Catch usually does not change that much between versions, but it should be kept up to date anyway.

View File

@@ -33,6 +33,23 @@ namespace Catch {
}
```
## Catch::is_range<T> specialisation
As a fallback, Catch attempts to detect if the type can be iterated
(`begin(T)` and `end(T)` are valid) and if it can be, it is stringified
as a range. For certain types this can lead to infinite recursion, so
it can be disabled by specializing `Catch::is_range` like so:
```cpp
namespace Catch {
template<>
struct is_range<T> {
static const bool value = false;
};
}
```
## Exceptions
By default all exceptions deriving from `std::exception` will be translated to strings by calling the `what()` method. For exception types that do not derive from `std::exception` - or if `what()` does not return a suitable string - use `CATCH_TRANSLATE_EXCEPTION`. This defines a function that takes your exception type, by reference, and returns a string. It can appear anywhere in the code - it doesn't have to be in the same translation unit. For example:

View File

@@ -1,7 +1,7 @@
#
# Build examples.
#
# Requires BUILD_EXAMPLES to be defined 'true', see ../CMakeLists.txt.
# Requires CATCH_BUILD_EXAMPLES to be defined 'true', see ../CMakeLists.txt.
#
cmake_minimum_required( VERSION 3.0 )

View File

@@ -9,6 +9,9 @@
#ifndef TWOBLUECUBES_CATCH_HPP_INCLUDED
#define TWOBLUECUBES_CATCH_HPP_INCLUDED
#define CATCH_VERSION_MAJOR 2
#define CATCH_VERSION_MINOR 2
#define CATCH_VERSION_PATCH 1
#ifdef __clang__
# pragma clang system_header

View File

@@ -1,5 +1,11 @@
// v1.0-develop.2
// See https://github.com/philsquared/Clara
// Copyright 2017 Two Blue Cubes Ltd. All rights reserved.
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
//
// See https://github.com/philsquared/Clara for more details
// Clara v1.1.4
#ifndef CATCH_CLARA_HPP_INCLUDED
#define CATCH_CLARA_HPP_INCLUDED
@@ -12,6 +18,16 @@
#define CATCH_CLARA_TEXTFLOW_CONFIG_CONSOLE_WIDTH CATCH_CLARA_CONFIG_CONSOLE_WIDTH
#endif
#ifndef CLARA_CONFIG_OPTIONAL_TYPE
#ifdef __has_include
#if __has_include(<optional>) && __cplusplus >= 201703L
#include <optional>
#define CLARA_CONFIG_OPTIONAL_TYPE std::optional
#endif
#endif
#endif
// ----------- #included from clara_textflow.hpp -----------
// TextFlowCpp
@@ -370,7 +386,7 @@ namespace detail {
template<typename ClassT, typename ReturnT, typename ArgT>
struct UnaryLambdaTraits<ReturnT( ClassT::* )( ArgT ) const> {
static const bool isValid = true;
using ArgType = typename std::remove_const<typename std::remove_reference<ArgT>::type>::type;;
using ArgType = typename std::remove_const<typename std::remove_reference<ArgT>::type>::type;
using ReturnType = ReturnT;
};
@@ -383,11 +399,9 @@ namespace detail {
std::vector<std::string> m_args;
public:
Args( int argc, char *argv[] ) {
m_exeName = argv[0];
for( int i = 1; i < argc; ++i )
m_args.push_back( argv[i] );
}
Args( int argc, char const* const* argv )
: m_exeName(argv[0]),
m_args(argv + 1, argv + argc) {}
Args( std::initializer_list<std::string> args )
: m_exeName( *args.begin() ),
@@ -535,7 +549,7 @@ namespace detail {
return *this;
}
~ResultValueBase() {
~ResultValueBase() override {
if( m_type == Ok )
m_value.~T();
}
@@ -573,16 +587,14 @@ namespace detail {
auto errorMessage() const -> std::string { return m_errorMessage; }
protected:
virtual void enforceOk() const {
// !TBD: If no exceptions, std::terminate here or something
switch( m_type ) {
case ResultBase::LogicError:
throw std::logic_error( m_errorMessage );
case ResultBase::RuntimeError:
throw std::runtime_error( m_errorMessage );
case ResultBase::Ok:
break;
}
void enforceOk() const override {
// Errors shouldn't reach this point, but if they do
// the actual error message will be in m_errorMessage
assert( m_type != ResultBase::LogicError );
assert( m_type != ResultBase::RuntimeError );
if( m_type != ResultBase::Ok )
std::abort();
}
std::string m_errorMessage; // Only populated if resultType is an error
@@ -652,47 +664,43 @@ namespace detail {
return ParserResult::runtimeError( "Expected a boolean value but did not recognise: '" + source + "'" );
return ParserResult::ok( ParseResultType::Matched );
}
#ifdef CLARA_CONFIG_OPTIONAL_TYPE
template<typename T>
inline auto convertInto( std::string const &source, CLARA_CONFIG_OPTIONAL_TYPE<T>& target ) -> ParserResult {
T temp;
auto result = convertInto( source, temp );
if( result )
target = std::move(temp);
return result;
}
#endif // CLARA_CONFIG_OPTIONAL_TYPE
struct BoundRefBase {
BoundRefBase() = default;
BoundRefBase( BoundRefBase const & ) = delete;
BoundRefBase( BoundRefBase && ) = delete;
BoundRefBase &operator=( BoundRefBase const & ) = delete;
BoundRefBase &operator=( BoundRefBase && ) = delete;
struct NonCopyable {
NonCopyable() = default;
NonCopyable( NonCopyable const & ) = delete;
NonCopyable( NonCopyable && ) = delete;
NonCopyable &operator=( NonCopyable const & ) = delete;
NonCopyable &operator=( NonCopyable && ) = delete;
};
virtual ~BoundRefBase() = default;
virtual auto isFlag() const -> bool = 0;
struct BoundRef : NonCopyable {
virtual ~BoundRef() = default;
virtual auto isContainer() const -> bool { return false; }
virtual auto isFlag() const -> bool { return false; }
};
struct BoundValueRefBase : BoundRef {
virtual auto setValue( std::string const &arg ) -> ParserResult = 0;
};
struct BoundFlagRefBase : BoundRef {
virtual auto setFlag( bool flag ) -> ParserResult = 0;
};
struct BoundValueRefBase : BoundRefBase {
auto isFlag() const -> bool override { return false; }
auto setFlag( bool ) -> ParserResult override {
return ParserResult::logicError( "Flags can only be set on boolean fields" );
}
};
struct BoundFlagRefBase : BoundRefBase {
auto isFlag() const -> bool override { return true; }
auto setValue( std::string const &arg ) -> ParserResult override {
bool flag;
auto result = convertInto( arg, flag );
if( result )
setFlag( flag );
return result;
}
virtual auto isFlag() const -> bool { return true; }
};
template<typename T>
struct BoundRef : BoundValueRefBase {
struct BoundValueRef : BoundValueRefBase {
T &m_ref;
explicit BoundRef( T &ref ) : m_ref( ref ) {}
explicit BoundValueRef( T &ref ) : m_ref( ref ) {}
auto setValue( std::string const &arg ) -> ParserResult override {
return convertInto( arg, m_ref );
@@ -700,10 +708,10 @@ namespace detail {
};
template<typename T>
struct BoundRef<std::vector<T>> : BoundValueRefBase {
struct BoundValueRef<std::vector<T>> : BoundValueRefBase {
std::vector<T> &m_ref;
explicit BoundRef( std::vector<T> &ref ) : m_ref( ref ) {}
explicit BoundValueRef( std::vector<T> &ref ) : m_ref( ref ) {}
auto isContainer() const -> bool override { return true; }
@@ -748,12 +756,12 @@ namespace detail {
template<typename ArgType, typename L>
inline auto invokeLambda( L const &lambda, std::string const &arg ) -> ParserResult {
ArgType temp;
ArgType temp{};
auto result = convertInto( arg, temp );
return !result
? result
: LambdaInvoker<typename UnaryLambdaTraits<L>::ReturnType>::invoke( lambda, temp );
};
}
template<typename L>
@@ -803,6 +811,9 @@ namespace detail {
public:
template<typename T>
auto operator|( T const &other ) const -> Parser;
template<typename T>
auto operator+( T const &other ) const -> Parser;
};
// Common code and state for Args and Opts
@@ -810,16 +821,16 @@ namespace detail {
class ParserRefImpl : public ComposableParserImpl<DerivedT> {
protected:
Optionality m_optionality = Optionality::Optional;
std::shared_ptr<BoundRefBase> m_ref;
std::shared_ptr<BoundRef> m_ref;
std::string m_hint;
std::string m_description;
explicit ParserRefImpl( std::shared_ptr<BoundRefBase> const &ref ) : m_ref( ref ) {}
explicit ParserRefImpl( std::shared_ptr<BoundRef> const &ref ) : m_ref( ref ) {}
public:
template<typename T>
ParserRefImpl( T &ref, std::string const &hint )
: m_ref( std::make_shared<BoundRef<T>>( ref ) ),
: m_ref( std::make_shared<BoundValueRef<T>>( ref ) ),
m_hint( hint )
{}
@@ -860,10 +871,10 @@ namespace detail {
class ExeName : public ComposableParserImpl<ExeName> {
std::shared_ptr<std::string> m_name;
std::shared_ptr<BoundRefBase> m_ref;
std::shared_ptr<BoundValueRefBase> m_ref;
template<typename LambdaT>
static auto makeRef(LambdaT const &lambda) -> std::shared_ptr<BoundRefBase> {
static auto makeRef(LambdaT const &lambda) -> std::shared_ptr<BoundValueRefBase> {
return std::make_shared<BoundLambda<LambdaT>>( lambda) ;
}
@@ -871,7 +882,7 @@ namespace detail {
ExeName() : m_name( std::make_shared<std::string>( "<executable>" ) ) {}
explicit ExeName( std::string &ref ) : ExeName() {
m_ref = std::make_shared<BoundRef<std::string>>( ref );
m_ref = std::make_shared<BoundValueRef<std::string>>( ref );
}
template<typename LambdaT>
@@ -914,7 +925,10 @@ namespace detail {
if( token.type != TokenType::Argument )
return InternalParseResult::ok( ParseState( ParseResultType::NoMatch, remainingTokens ) );
auto result = m_ref->setValue( remainingTokens->token );
assert( !m_ref->isFlag() );
auto valueRef = static_cast<detail::BoundValueRefBase*>( m_ref.get() );
auto result = valueRef->setValue( remainingTokens->token );
if( !result )
return InternalParseResult( result );
else
@@ -988,19 +1002,21 @@ namespace detail {
auto const &token = *remainingTokens;
if( isMatch(token.token ) ) {
if( m_ref->isFlag() ) {
auto result = m_ref->setFlag( true );
auto flagRef = static_cast<detail::BoundFlagRefBase*>( m_ref.get() );
auto result = flagRef->setFlag( true );
if( !result )
return InternalParseResult( result );
if( result.value() == ParseResultType::ShortCircuitAll )
return InternalParseResult::ok( ParseState( result.value(), remainingTokens ) );
} else {
auto valueRef = static_cast<detail::BoundValueRefBase*>( m_ref.get() );
++remainingTokens;
if( !remainingTokens )
return InternalParseResult::runtimeError( "Expected argument following " + token.token );
auto const &argToken = *remainingTokens;
if( argToken.type != TokenType::Argument )
return InternalParseResult::runtimeError( "Expected argument following " + token.token );
auto result = m_ref->setValue( argToken.token );
auto result = valueRef->setValue( argToken.token );
if( !result )
return InternalParseResult( result );
if( result.value() == ParseResultType::ShortCircuitAll )
@@ -1077,6 +1093,12 @@ namespace detail {
return Parser( *this ) |= other;
}
// Forward deprecated interface with '+' instead of '|'
template<typename T>
auto operator+=( T const &other ) -> Parser & { return operator|=( other ); }
template<typename T>
auto operator+( T const &other ) const -> Parser { return operator|( other ); }
auto getHelpColumns() const -> std::vector<HelpColumns> {
std::vector<HelpColumns> cols;
for (auto const &o : m_options) {
@@ -1116,6 +1138,8 @@ namespace detail {
for( auto const &cols : rows )
optWidth = (std::max)(optWidth, cols.left.size() + 2);
optWidth = (std::min)(optWidth, consoleWidth/2);
for( auto const &cols : rows ) {
auto row =
TextFlow::Column( cols.left ).width( optWidth ).indent( 2 ) +

View File

@@ -65,9 +65,9 @@ namespace Catch {
expr = m_info.capturedExpression;
else {
expr.reserve( m_info.macroName.size() + m_info.capturedExpression.size() + 4 );
expr += m_info.macroName.c_str();
expr += m_info.macroName;
expr += "( ";
expr += m_info.capturedExpression.c_str();
expr += m_info.capturedExpression;
expr += " )";
}
return expr;

View File

@@ -13,7 +13,7 @@ namespace Catch {
using StringMatcher = Matchers::Impl::MatcherBase<std::string>;
// This is the general overload that takes a any string matcher
// There is another overload, in catch_assertinhandler.h/.cpp, that only takes a string and infers
// There is another overload, in catch_assertionhandler.h/.cpp, that only takes a string and infers
// the Equals matcher (so the header does not mention matchers)
void handleExceptionMatchExpr( AssertionHandler& handler, StringMatcher const& matcher, StringRef matcherString ) {
std::string exceptionMessage = Catch::translateActiveException();

View File

@@ -20,9 +20,19 @@ namespace Catch {
using namespace clara;
auto const setWarning = [&]( std::string const& warning ) {
if( warning != "NoAssertions" )
auto warningSet = [&]() {
if( warning == "NoAssertions" )
return WarnAbout::NoAssertions;
if ( warning == "NoTests" )
return WarnAbout::NoTests;
return WarnAbout::Nothing;
}();
if (warningSet == WarnAbout::Nothing)
return ParserResult::runtimeError( "Unrecognised warning: '" + warning + "'" );
config.warnings = static_cast<WarnAbout::What>( config.warnings | WarnAbout::NoAssertions );
config.warnings = static_cast<WarnAbout::What>( config.warnings | warningSet );
return ParserResult::ok( ParseResultType::Matched );
};
auto const loadTestNamesFromFile = [&]( std::string const& filename ) {

View File

@@ -31,6 +31,14 @@
# define CATCH_CPP14_OR_GREATER
# endif
# if __cplusplus >= 201703L
# define CATCH_CPP17_OR_GREATER
# endif
#endif
#if defined(CATCH_CPP17_OR_GREATER)
# define CATCH_INTERNAL_CONFIG_CPP17_UNCAUGHT_EXCEPTIONS
#endif
#ifdef __clang__
@@ -51,14 +59,16 @@
#endif // __clang__
////////////////////////////////////////////////////////////////////////////////
// Assume that non-Windows platforms support posix signals by default
#if !defined(CATCH_PLATFORM_WINDOWS)
#define CATCH_INTERNAL_CONFIG_POSIX_SIGNALS
#endif
////////////////////////////////////////////////////////////////////////////////
// We know some environments not to support full POSIX signals
#if defined(__CYGWIN__) || defined(__QNX__)
# if !defined(CATCH_CONFIG_POSIX_SIGNALS)
# define CATCH_INTERNAL_CONFIG_NO_POSIX_SIGNALS
# endif
#if defined(__CYGWIN__) || defined(__QNX__) || defined(__EMSCRIPTEN__) || defined(__DJGPP__)
#define CATCH_INTERNAL_CONFIG_NO_POSIX_SIGNALS
#endif
#ifdef __OS400__
@@ -80,6 +90,11 @@
// Visual C++
#ifdef _MSC_VER
# if _MSC_VER >= 1900 // Visual Studio 2015 or newer
# define CATCH_INTERNAL_CONFIG_CPP17_UNCAUGHT_EXCEPTIONS
# endif
// Universal Windows platform does not support SEH
// Or console colours (or console at all...)
# if defined(WINAPI_FAMILY) && (WINAPI_FAMILY == WINAPI_FAMILY_APP)
@@ -92,6 +107,13 @@
////////////////////////////////////////////////////////////////////////////////
// DJGPP
#ifdef __DJGPP__
# define CATCH_INTERNAL_CONFIG_NO_WCHAR
#endif // __DJGPP__
////////////////////////////////////////////////////////////////////////////////
// Use of __COUNTER__ is suppressed during code analysis in
// CLion/AppCode 2017.2.x and former, because __COUNTER__ is not properly
// handled by it.
@@ -108,9 +130,18 @@
# define CATCH_CONFIG_WINDOWS_SEH
#endif
// This is set by default, because we assume that unix compilers are posix-signal-compatible by default.
#if !defined(CATCH_INTERNAL_CONFIG_NO_POSIX_SIGNALS) && !defined(CATCH_CONFIG_NO_POSIX_SIGNALS) && !defined(CATCH_CONFIG_POSIX_SIGNALS)
#if defined(CATCH_INTERNAL_CONFIG_POSIX_SIGNALS) && !defined(CATCH_INTERNAL_CONFIG_NO_POSIX_SIGNALS) && !defined(CATCH_CONFIG_NO_POSIX_SIGNALS) && !defined(CATCH_CONFIG_POSIX_SIGNALS)
# define CATCH_CONFIG_POSIX_SIGNALS
#endif
// This is set by default, because we assume that compilers with no wchar_t support are just rare exceptions.
#if !defined(CATCH_INTERNAL_CONFIG_NO_WCHAR) && !defined(CATCH_CONFIG_NO_WCHAR) && !defined(CATCH_CONFIG_WCHAR)
# define CATCH_CONFIG_WCHAR
#endif
#if defined(CATCH_INTERNAL_CONFIG_CPP17_UNCAUGHT_EXCEPTIONS) && !defined(CATCH_CONFIG_NO_CPP17_UNCAUGHT_EXCEPTIONS) && !defined(CATCH_CONFIG_CPP17_UNCAUGHT_EXCEPTIONS)
# define CATCH_CONFIG_CPP17_UNCAUGHT_EXCEPTIONS
#endif
#if !defined(CATCH_INTERNAL_SUPPRESS_PARENTHESES_WARNINGS)
# define CATCH_INTERNAL_SUPPRESS_PARENTHESES_WARNINGS

View File

@@ -15,12 +15,16 @@ namespace Catch {
: m_data( data ),
m_stream( openStream() )
{
if( !data.testsOrTags.empty() ) {
TestSpecParser parser( ITagAliasRegistry::get() );
TestSpecParser parser(ITagAliasRegistry::get());
if (data.testsOrTags.empty()) {
parser.parse("~[.]"); // All not hidden tests
}
else {
m_hasTestFilters = true;
for( auto const& testOrTags : data.testsOrTags )
parser.parse( testOrTags );
m_testSpec = parser.testSpec();
}
m_testSpec = parser.testSpec();
}
std::string const& Config::getFilename() const {
@@ -35,9 +39,11 @@ namespace Catch {
std::string Config::getProcessName() const { return m_data.processName; }
std::vector<std::string> const& Config::getReporterNames() const { return m_data.reporterNames; }
std::vector<std::string> const& Config::getTestsOrTags() const { return m_data.testsOrTags; }
std::vector<std::string> const& Config::getSectionsToRun() const { return m_data.sectionsToRun; }
TestSpec const& Config::testSpec() const { return m_testSpec; }
bool Config::hasTestFilters() const { return m_hasTestFilters; }
bool Config::showHelp() const { return m_data.showHelp; }
@@ -46,7 +52,8 @@ namespace Catch {
std::ostream& Config::stream() const { return m_stream->stream(); }
std::string Config::name() const { return m_data.name.empty() ? m_data.processName : m_data.name; }
bool Config::includeSuccessfulResults() const { return m_data.showSuccessfulTests; }
bool Config::warnAboutMissingAssertions() const { return m_data.warnings & WarnAbout::NoAssertions; }
bool Config::warnAboutMissingAssertions() const { return !!(m_data.warnings & WarnAbout::NoAssertions); }
bool Config::warnAboutNoTests() const { return !!(m_data.warnings & WarnAbout::NoTests); }
ShowDurations::OrNot Config::showDurations() const { return m_data.showDurations; }
RunTests::InWhatOrder Config::runOrder() const { return m_data.runOrder; }
unsigned int Config::rngSeed() const { return m_data.rngSeed; }

View File

@@ -78,9 +78,11 @@ namespace Catch {
std::string getProcessName() const;
std::vector<std::string> const& getReporterNames() const;
std::vector<std::string> const& getTestsOrTags() const;
std::vector<std::string> const& getSectionsToRun() const override;
virtual TestSpec const& testSpec() const override;
bool hasTestFilters() const override;
bool showHelp() const;
@@ -90,6 +92,7 @@ namespace Catch {
std::string name() const override;
bool includeSuccessfulResults() const override;
bool warnAboutMissingAssertions() const override;
bool warnAboutNoTests() const override;
ShowDurations::OrNot showDurations() const override;
RunTests::InWhatOrder runOrder() const override;
unsigned int rngSeed() const override;
@@ -107,6 +110,7 @@ namespace Catch {
std::unique_ptr<IStream const> m_stream;
TestSpec m_testSpec;
bool m_hasTestFilters = false;
};
} // end namespace Catch

View File

@@ -11,8 +11,8 @@
# pragma clang diagnostic push
# pragma clang diagnostic ignored "-Wexit-time-destructors"
#endif
#include "catch_console_colour.h"
#include "catch_enforce.h"
#include "catch_errno_guard.h"
@@ -84,8 +84,12 @@ namespace {
case Colour::BrightRed: return setTextAttribute( FOREGROUND_INTENSITY | FOREGROUND_RED );
case Colour::BrightGreen: return setTextAttribute( FOREGROUND_INTENSITY | FOREGROUND_GREEN );
case Colour::BrightWhite: return setTextAttribute( FOREGROUND_INTENSITY | FOREGROUND_GREEN | FOREGROUND_RED | FOREGROUND_BLUE );
case Colour::BrightYellow: return setTextAttribute( FOREGROUND_INTENSITY | FOREGROUND_RED | FOREGROUND_GREEN );
case Colour::Bright: CATCH_INTERNAL_ERROR( "not a colour" );
default:
CATCH_ERROR( "Unknown colour requested" );
}
}
@@ -143,8 +147,10 @@ namespace {
case Colour::BrightRed: return setColour( "[1;31m" );
case Colour::BrightGreen: return setColour( "[1;32m" );
case Colour::BrightWhite: return setColour( "[1;37m" );
case Colour::BrightYellow: return setColour( "[1;33m" );
case Colour::Bright: CATCH_INTERNAL_ERROR( "not a colour" );
default: CATCH_INTERNAL_ERROR( "Unknown colour requested" );
}
}
static IColourImpl* instance() {
@@ -163,7 +169,12 @@ namespace {
#ifdef CATCH_PLATFORM_MAC
!isDebuggerActive() &&
#endif
isatty(STDOUT_FILENO);
#if !(defined(__DJGPP__) && defined(__STRICT_ANSI__))
isatty(STDOUT_FILENO)
#else
false
#endif
;
}
IColourImpl* platformColourInstance() {
ErrnoGuard guard;
@@ -196,7 +207,7 @@ namespace Catch {
namespace Catch {
Colour::Colour( Code _colourCode ) { use( _colourCode ); }
Colour::Colour( Colour&& rhs ) noexcept {
Colour::Colour( Colour&& rhs ) noexcept {
m_moved = rhs.m_moved;
rhs.m_moved = true;
}
@@ -205,7 +216,7 @@ namespace Catch {
rhs.m_moved = true;
return *this;
}
Colour::~Colour(){ if( !m_moved ) use( None ); }
void Colour::use( Code _colourCode ) {

View File

@@ -30,10 +30,11 @@ namespace Catch {
BrightGreen = Bright | Green,
LightGrey = Bright | Grey,
BrightWhite = Bright | White,
BrightYellow = Bright | Yellow,
// By intention
FileName = LightGrey,
Warning = Yellow,
Warning = BrightYellow,
ResultError = BrightRed,
ResultSuccess = BrightGreen,
ResultExpectedFailure = Warning,
@@ -42,7 +43,7 @@ namespace Catch {
Success = Green,
OriginalExpression = Cyan,
ReconstructedExpression = Yellow,
ReconstructedExpression = BrightYellow,
SecondaryText = LightGrey,
Headers = White

View File

@@ -9,21 +9,23 @@
#include "catch_debug_console.h"
#include "catch_stream.h"
#include "catch_platform.h"
#include "catch_windows_h_proxy.h"
#ifdef CATCH_PLATFORM_WINDOWS
#include "catch_windows_h_proxy.h"
namespace Catch {
void writeToDebugConsole( std::string const& text ) {
::OutputDebugStringA( text.c_str() );
}
}
#else
namespace Catch {
void writeToDebugConsole( std::string const& text ) {
// !TBD: Need a version for Mac/ XCode and other IDEs
Catch::cout() << text;
}
}
#endif // Platform

View File

@@ -40,7 +40,10 @@ namespace Catch {
#ifdef CATCH_TRAP
#define CATCH_BREAK_INTO_DEBUGGER() if( Catch::isDebuggerActive() ) { CATCH_TRAP(); }
#else
#define CATCH_BREAK_INTO_DEBUGGER() (void)0, 0
namespace Catch {
inline void doNothing() {}
}
#define CATCH_BREAK_INTO_DEBUGGER() Catch::doNothing()
#endif
#endif // TWOBLUECUBES_CATCH_DEBUGGER_H_INCLUDED

View File

@@ -82,7 +82,7 @@ namespace Catch {
// Specialised comparison functions to handle equality comparisons between ints and pointers (NULL deduces as an int)
template<typename LhsT, typename RhsT>
auto compareEqual( LhsT const& lhs, RhsT const& rhs ) -> bool { return lhs == rhs; };
auto compareEqual( LhsT const& lhs, RhsT const& rhs ) -> bool { return static_cast<bool>(lhs == rhs); }
template<typename T>
auto compareEqual( T* const& lhs, int rhs ) -> bool { return lhs == reinterpret_cast<void const*>( rhs ); }
template<typename T>
@@ -93,7 +93,7 @@ namespace Catch {
auto compareEqual( long lhs, T* const& rhs ) -> bool { return reinterpret_cast<void const*>( lhs ) == rhs; }
template<typename LhsT, typename RhsT>
auto compareNotEqual( LhsT const& lhs, RhsT&& rhs ) -> bool { return lhs != rhs; };
auto compareNotEqual( LhsT const& lhs, RhsT&& rhs ) -> bool { return static_cast<bool>(lhs != rhs); }
template<typename T>
auto compareNotEqual( T* const& lhs, int rhs ) -> bool { return lhs != reinterpret_cast<void const*>( rhs ); }
template<typename T>
@@ -128,19 +128,19 @@ namespace Catch {
template<typename RhsT>
auto operator > ( RhsT const& rhs ) -> BinaryExpr<LhsT, RhsT const&> const {
return { m_lhs > rhs, m_lhs, ">", rhs };
return { static_cast<bool>(m_lhs > rhs), m_lhs, ">", rhs };
}
template<typename RhsT>
auto operator < ( RhsT const& rhs ) -> BinaryExpr<LhsT, RhsT const&> const {
return { m_lhs < rhs, m_lhs, "<", rhs };
return { static_cast<bool>(m_lhs < rhs), m_lhs, "<", rhs };
}
template<typename RhsT>
auto operator >= ( RhsT const& rhs ) -> BinaryExpr<LhsT, RhsT const&> const {
return { m_lhs >= rhs, m_lhs, ">=", rhs };
return { static_cast<bool>(m_lhs >= rhs), m_lhs, ">=", rhs };
}
template<typename RhsT>
auto operator <= ( RhsT const& rhs ) -> BinaryExpr<LhsT, RhsT const&> const {
return { m_lhs <= rhs, m_lhs, "<=", rhs };
return { static_cast<bool>(m_lhs <= rhs), m_lhs, "<=", rhs };
}
auto makeUnaryExpr() const -> UnaryExpr<LhsT> {

View File

@@ -12,7 +12,7 @@
#ifndef __OBJC__
#if defined(WIN32) && defined(_UNICODE) && !defined(DO_NOT_USE_WMAIN)
#if defined(CATCH_CONFIG_WCHAR) && defined(WIN32) && defined(_UNICODE) && !defined(DO_NOT_USE_WMAIN)
// Standard C/C++ Win32 Unicode wmain entry point
extern "C" int wmain (int argc, wchar_t * argv[], wchar_t * []) {
#else

View File

@@ -11,10 +11,9 @@
#include "catch_stream.h"
#include <stdexcept>
#include <iosfwd>
#define CATCH_PREPARE_EXCEPTION( type, msg ) \
type( static_cast<std::ostringstream&&>( Catch::ReusableStringStream().get() << msg ).str() )
type( ( Catch::ReusableStringStream() << msg ).str() )
#define CATCH_INTERNAL_ERROR( msg ) \
throw CATCH_PREPARE_EXCEPTION( std::logic_error, CATCH_INTERNAL_LINEINFO << ": Internal Catch error: " << msg);
#define CATCH_ERROR( msg ) \

View File

@@ -33,6 +33,17 @@ namespace Catch {
return Catch::Detail::stringify( [exception description] );
}
#else
// Compiling a mixed mode project with MSVC means that CLR
// exceptions will be caught in (...) as well. However, these
// do not fill-in std::current_exception and thus lead to crash
// when attempting rethrow.
// /EHa switch also causes structured exceptions to be caught
// here, but they fill-in current_exception properly, so
// at worst the output should be a little weird, instead of
// causing a crash.
if (std::current_exception() == nullptr) {
return "Non C++ exception. Possibly a CLR exception.";
}
return tryTranslators();
#endif
}

View File

@@ -17,6 +17,8 @@
# pragma GCC diagnostic ignored "-Wmissing-field-initializers"
#endif
#if defined( CATCH_CONFIG_WINDOWS_SEH ) || defined( CATCH_CONFIG_POSIX_SIGNALS )
namespace {
// Report the error condition
void reportFatal( char const * const message ) {
@@ -24,15 +26,9 @@ namespace {
}
}
#if defined ( CATCH_PLATFORM_WINDOWS ) /////////////////////////////////////////
#endif // signals/SEH handling
# if !defined ( CATCH_CONFIG_WINDOWS_SEH )
namespace Catch {
void FatalConditionHandler::reset() {}
}
# else // CATCH_CONFIG_WINDOWS_SEH is defined
#if defined( CATCH_CONFIG_WINDOWS_SEH )
namespace Catch {
struct SignalDefs { DWORD id; const char* name; };
@@ -72,7 +68,6 @@ namespace Catch {
void FatalConditionHandler::reset() {
if (isSet) {
// Unregister handler and restore the old guarantee
RemoveVectoredExceptionHandler(exceptionHandlerHandle);
SetThreadStackGuarantee(&guaranteeSize);
exceptionHandlerHandle = nullptr;
@@ -91,20 +86,7 @@ PVOID FatalConditionHandler::exceptionHandlerHandle = nullptr;
} // namespace Catch
# endif // CATCH_CONFIG_WINDOWS_SEH
#else // Not Windows - assumed to be POSIX compatible //////////////////////////
# if !defined(CATCH_CONFIG_POSIX_SIGNALS)
namespace Catch {
void FatalConditionHandler::reset() {}
}
# else // CATCH_CONFIG_POSIX_SIGNALS is defined
#include <signal.h>
#elif defined( CATCH_CONFIG_POSIX_SIGNALS )
namespace Catch {
@@ -176,9 +158,13 @@ namespace Catch {
} // namespace Catch
# endif // CATCH_CONFIG_POSIX_SIGNALS
#else
#endif // not Windows
namespace Catch {
void FatalConditionHandler::reset() {}
}
#endif // signals/SEH handling
#if defined(__GNUC__)
# pragma GCC diagnostic pop

View File

@@ -9,23 +9,12 @@
#ifndef TWOBLUECUBES_CATCH_FATAL_CONDITION_H_INCLUDED
#define TWOBLUECUBES_CATCH_FATAL_CONDITION_H_INCLUDED
#include <string>
#include "catch_platform.h"
#include "catch_compiler_capabilities.h"
#if defined ( CATCH_PLATFORM_WINDOWS ) /////////////////////////////////////////
#include "catch_windows_h_proxy.h"
# if !defined ( CATCH_CONFIG_WINDOWS_SEH )
namespace Catch {
struct FatalConditionHandler {
void reset();
};
}
# else // CATCH_CONFIG_WINDOWS_SEH is defined
#if defined( CATCH_CONFIG_WINDOWS_SEH )
namespace Catch {
@@ -44,20 +33,7 @@ namespace Catch {
} // namespace Catch
# endif // CATCH_CONFIG_WINDOWS_SEH
#else // Not Windows - assumed to be POSIX compatible //////////////////////////
# if !defined(CATCH_CONFIG_POSIX_SIGNALS)
namespace Catch {
struct FatalConditionHandler {
void reset();
};
}
# else // CATCH_CONFIG_POSIX_SIGNALS is defined
#elif defined ( CATCH_CONFIG_POSIX_SIGNALS )
#include <signal.h>
@@ -66,7 +42,7 @@ namespace Catch {
struct FatalConditionHandler {
static bool isSet;
static struct sigaction oldSigActions[];// [sizeof(signalDefs) / sizeof(SignalDefs)];
static struct sigaction oldSigActions[];
static stack_t oldSigStack;
static char altStackMem[];
@@ -79,8 +55,15 @@ namespace Catch {
} // namespace Catch
# endif // CATCH_CONFIG_POSIX_SIGNALS
#endif // not Windows
#else
namespace Catch {
struct FatalConditionHandler {
void reset();
};
}
#endif
#endif // TWOBLUECUBES_CATCH_FATAL_CONDITION_H_INCLUDED

View File

@@ -25,7 +25,8 @@ namespace Catch {
struct WarnAbout { enum What {
Nothing = 0x00,
NoAssertions = 0x01
NoAssertions = 0x01,
NoTests = 0x02
}; };
struct ShowDurations { enum OrNot {
@@ -62,10 +63,12 @@ namespace Catch {
virtual bool includeSuccessfulResults() const = 0;
virtual bool shouldDebugBreak() const = 0;
virtual bool warnAboutMissingAssertions() const = 0;
virtual bool warnAboutNoTests() const = 0;
virtual int abortAfter() const = 0;
virtual bool showInvisibles() const = 0;
virtual ShowDurations::OrNot showDurations() const = 0;
virtual TestSpec const& testSpec() const = 0;
virtual bool hasTestFilters() const = 0;
virtual RunTests::InWhatOrder runOrder() const = 0;
virtual unsigned int rngSeed() const = 0;
virtual int benchmarkResolutionMultiple() const = 0;

View File

@@ -28,11 +28,10 @@ namespace Catch {
std::size_t listTests( Config const& config ) {
TestSpec testSpec = config.testSpec();
if( config.testSpec().hasFilters() )
if( config.hasTestFilters() )
Catch::cout() << "Matching test cases:\n";
else {
Catch::cout() << "All available test cases:\n";
testSpec = TestSpecParser( ITagAliasRegistry::get() ).parse( "*" ).testSpec();
}
auto matchedTestCases = filterTests( getAllTestCasesSorted( config ), testSpec, config );
@@ -54,7 +53,7 @@ namespace Catch {
Catch::cout() << Column( testCaseInfo.tagsAsString() ).indent( 6 ) << "\n";
}
if( !config.testSpec().hasFilters() )
if( !config.hasTestFilters() )
Catch::cout() << pluralise( matchedTestCases.size(), "test case" ) << '\n' << std::endl;
else
Catch::cout() << pluralise( matchedTestCases.size(), "matching test case" ) << '\n' << std::endl;
@@ -63,8 +62,6 @@ namespace Catch {
std::size_t listTestsNamesOnly( Config const& config ) {
TestSpec testSpec = config.testSpec();
if( !config.testSpec().hasFilters() )
testSpec = TestSpecParser( ITagAliasRegistry::get() ).parse( "*" ).testSpec();
std::size_t matchedTests = 0;
std::vector<TestCase> matchedTestCases = filterTests( getAllTestCasesSorted( config ), testSpec, config );
for( auto const& testCaseInfo : matchedTestCases ) {
@@ -94,11 +91,10 @@ namespace Catch {
std::size_t listTags( Config const& config ) {
TestSpec testSpec = config.testSpec();
if( config.testSpec().hasFilters() )
if( config.hasTestFilters() )
Catch::cout() << "Tags for matching test cases:\n";
else {
Catch::cout() << "All available tags:\n";
testSpec = TestSpecParser( ITagAliasRegistry::get() ).parse( "*" ).testSpec();
}
std::map<std::string, TagInfo> tagCounts;

View File

@@ -8,6 +8,7 @@
#include "catch_message.h"
#include "catch_interfaces_capture.h"
#include "catch_uncaught_exceptions.h"
namespace Catch {
@@ -49,18 +50,9 @@ namespace Catch {
getResultCapture().pushScopedMessage( m_info );
}
#if defined(_MSC_VER)
#pragma warning(push)
#pragma warning(disable:4996) // std::uncaught_exception is deprecated in C++17
#endif
ScopedMessage::~ScopedMessage() {
if ( !std::uncaught_exception() ){
if ( !uncaught_exceptions() ){
getResultCapture().popScopedMessage(m_info);
}
}
#if defined(_MSC_VER)
#pragma warning(pop)
#endif
} // end namespace Catch

View File

@@ -57,7 +57,7 @@ namespace Catch {
m_context(getCurrentMutableContext()),
m_config(_config),
m_reporter(std::move(reporter)),
m_lastAssertionInfo{ "", SourceLineInfo("",0), "", ResultDisposition::Normal },
m_lastAssertionInfo{ StringRef(), SourceLineInfo("",0), StringRef(), ResultDisposition::Normal },
m_includeSuccessfulResults( m_config->includeSuccessfulResults() )
{
m_context.setRunner(this);
@@ -84,7 +84,7 @@ namespace Catch {
std::string redirectedCout;
std::string redirectedCerr;
TestCaseInfo testInfo = testCase.getTestCaseInfo();
auto const& testInfo = testCase.getTestCaseInfo();
m_reporter->testCaseStarting(testInfo);
@@ -292,7 +292,7 @@ namespace Catch {
Counts prevAssertions = m_totals.assertions;
double duration = 0;
m_shouldReportUnexpected = true;
m_lastAssertionInfo = { "TEST_CASE", testCaseInfo.lineInfo, "", ResultDisposition::Normal };
m_lastAssertionInfo = { "TEST_CASE"_sr, testCaseInfo.lineInfo, StringRef(), ResultDisposition::Normal };
seedRng(*m_config);
@@ -321,12 +321,13 @@ namespace Catch {
handleUnexpectedInflightException( m_lastAssertionInfo, translateActiveException(), dummyReaction );
}
}
Counts assertions = m_totals.assertions - prevAssertions;
bool missingAssertions = testForMissingAssertions(assertions);
m_testCaseTracker->close();
handleUnfinishedSections();
m_messages.clear();
Counts assertions = m_totals.assertions - prevAssertions;
bool missingAssertions = testForMissingAssertions(assertions);
SectionStats testCaseSectionStats(testCaseSection, assertions, duration, missingAssertions);
m_reporter->sectionEnded(testCaseSectionStats);
}

View File

@@ -8,6 +8,7 @@
#include "catch_section.h"
#include "catch_capture.hpp"
#include "catch_uncaught_exceptions.h"
namespace Catch {
@@ -18,22 +19,15 @@ namespace Catch {
m_timer.start();
}
#if defined(_MSC_VER)
#pragma warning(push)
#pragma warning(disable:4996) // std::uncaught_exception is deprecated in C++17
#endif
Section::~Section() {
if( m_sectionIncluded ) {
SectionEndInfo endInfo( m_info, m_assertions, m_timer.getElapsedSeconds() );
if( std::uncaught_exception() )
if( uncaught_exceptions() )
getResultCapture().sectionEndedEarly( endInfo );
else
getResultCapture().sectionEnded( endInfo );
}
}
#if defined(_MSC_VER)
#pragma warning(pop)
#endif
// This indicates whether the section should be executed or not
Section::operator bool() const {

View File

@@ -18,6 +18,8 @@
#include "catch_random_number_generator.h"
#include "catch_startup_exception_registry.h"
#include "catch_text.h"
#include "catch_stream.h"
#include "catch_windows_h_proxy.h"
#include <cstdlib>
#include <iomanip>
@@ -69,8 +71,6 @@ namespace Catch {
context.testGroupStarting(config->name(), 1, 1);
TestSpec testSpec = config->testSpec();
if (!testSpec.hasFilters())
testSpec = TestSpecParser(ITagAliasRegistry::get()).parse("~[.]").testSpec(); // All not hidden tests
auto const& allTestCases = getAllTestCasesSorted(*config);
for (auto const& testCase : allTestCases) {
@@ -80,6 +80,20 @@ namespace Catch {
context.reporter().skipTest(testCase);
}
if (config->warnAboutNoTests() && totals.testCases.total() == 0) {
ReusableStringStream testConfig;
bool first = true;
for (const auto& input : config->getTestsOrTags()) {
if (!first) { testConfig << ' '; }
first = false;
testConfig << input;
}
context.reporter().noMatchingTestCases(testConfig.str());
totals.error = -1;
}
context.testGroupEnded(config->name(), totals, 1, 1);
return totals;
}
@@ -119,7 +133,7 @@ namespace Catch {
if ( !exceptions.empty() ) {
m_startupExceptions = true;
Colour colourGuard( Colour::Red );
Catch::cerr() << "Errors occured during startup!" << '\n';
Catch::cerr() << "Errors occurred during startup!" << '\n';
// iterate over all exceptions and notify user
for ( const auto& ex_ptr : exceptions ) {
try {
@@ -151,7 +165,7 @@ namespace Catch {
<< std::left << std::setw(16) << "version: " << libraryVersion() << std::endl;
}
int Session::applyCommandLine( int argc, char* argv[] ) {
int Session::applyCommandLine( int argc, char const * const * argv ) {
if( m_startupExceptions )
return 1;
@@ -188,7 +202,7 @@ namespace Catch {
return returnCode;
}
#if defined(WIN32) && defined(UNICODE)
#if defined(CATCH_CONFIG_WCHAR) && defined(WIN32) && defined(UNICODE)
int Session::run( int argc, wchar_t* const argv[] ) {
char **utf8Argv = new char *[ argc ];
@@ -259,7 +273,11 @@ namespace Catch {
if( Option<std::size_t> listed = list( config() ) )
return static_cast<int>( *listed );
return (std::min)( MaxExitCode, static_cast<int>( runTests( m_config ).assertions.failed ) );
auto totals = runTests( m_config );
// Note that on unices only the lower 8 bits are usually used, clamping
// the return value to 255 prevents false negative when some multiple
// of 256 tests has failed
return (std::min) (MaxExitCode, (std::max) (totals.error, static_cast<int>(totals.assertions.failed)));
}
catch( std::exception& ex ) {
Catch::cerr() << ex.what() << std::endl;

View File

@@ -25,12 +25,12 @@ namespace Catch {
void showHelp() const;
void libIdentify();
int applyCommandLine( int argc, char* argv[] );
int applyCommandLine( int argc, char const * const * argv );
void useConfigData( ConfigData const& configData );
int run( int argc, char* argv[] );
#if defined(WIN32) && defined(UNICODE)
#if defined(CATCH_CONFIG_WCHAR) && defined(WIN32) && defined(UNICODE)
int run( int argc, wchar_t* const argv[] );
#endif
int run();

View File

@@ -15,6 +15,13 @@
#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
@@ -36,7 +43,7 @@ namespace Catch {
const_cast<StringRef*>( this )->takeOwnership();
return m_start;
}
auto StringRef::data() const noexcept -> char const* {
auto StringRef::currentData() const noexcept -> char const* {
return m_start;
}
@@ -79,13 +86,12 @@ namespace Catch {
// Make adjustments for uft encodings
for( size_type i=0; i < m_size; ++i ) {
char c = m_start[i];
if( ( c & 0b11000000 ) == 0b11000000 ) {
if( ( c & 0b11100000 ) == 0b11000000 )
if( ( c & byte_2_lead ) == byte_2_lead ) {
noChars--;
if (( c & byte_3_lead ) == byte_3_lead )
noChars--;
if( ( c & byte_4_lead ) == byte_4_lead )
noChars--;
else if( ( c & 0b11110000 ) == 0b11100000 )
noChars-=2;
else if( ( c & 0b11111000 ) == 0b11110000 )
noChars-=3;
}
}
return noChars;
@@ -106,7 +112,12 @@ namespace Catch {
}
auto operator << ( std::ostream& os, StringRef const& str ) -> std::ostream& {
return os << str.c_str();
return os.write(str.currentData(), str.size());
}
auto operator+=( std::string& lhs, StringRef const& rhs ) -> std::string& {
lhs.append(rhs.currentData(), rhs.size());
return lhs;
}
} // namespace Catch

View File

@@ -12,7 +12,7 @@
#include <iosfwd>
namespace Catch {
class StringData;
/// A non-owning string class (similar to the forthcoming std::string_view)
@@ -31,13 +31,13 @@ namespace Catch {
char const* m_start;
size_type m_size;
char* m_data = nullptr;
void takeOwnership();
static constexpr char const* const s_empty = "";
public: // construction/ assignment
StringRef() noexcept
: StringRef( s_empty, 0 )
@@ -83,13 +83,13 @@ namespace Catch {
operator std::string() const;
void swap( StringRef& other ) noexcept;
public: // operators
auto operator == ( StringRef const& other ) const noexcept -> bool;
auto operator != ( StringRef const& other ) const noexcept -> bool;
auto operator[] ( size_type index ) const noexcept -> char;
public: // named queries
auto empty() const noexcept -> bool {
return m_size == 0;
@@ -100,22 +100,27 @@ namespace Catch {
auto numberOfCharacters() const noexcept -> size_type;
auto c_str() const -> char const*;
public: // substrings and searches
auto substr( size_type start, size_type size ) const noexcept -> StringRef;
// Returns the current start pointer.
// Note that the pointer can change when if the StringRef is a substring
auto currentData() const noexcept -> char const*;
private: // ownership queries - may not be consistent between calls
auto isOwned() const noexcept -> bool;
auto isSubstring() const noexcept -> bool;
auto data() const noexcept -> char const*;
};
auto operator + ( StringRef const& lhs, StringRef const& rhs ) -> std::string;
auto operator + ( StringRef const& lhs, char const* rhs ) -> std::string;
auto operator + ( char const* lhs, StringRef const& rhs ) -> std::string;
auto operator += ( std::string& lhs, StringRef const& sr ) -> std::string&;
auto operator << ( std::ostream& os, StringRef const& sr ) -> std::ostream&;
inline auto operator "" _sr( char const* rawChars, std::size_t size ) noexcept -> StringRef {
return StringRef( rawChars, size );
}

View File

@@ -48,8 +48,7 @@ namespace Catch {
TestCase makeTestCase( ITestInvoker* _testCase,
std::string const& _className,
std::string const& _name,
std::string const& _descOrTags,
NameAndTags const& nameAndTags,
SourceLineInfo const& _lineInfo )
{
bool isHidden = false;
@@ -58,6 +57,7 @@ namespace Catch {
std::vector<std::string> tags;
std::string desc, tag;
bool inTag = false;
std::string _descOrTags = nameAndTags.tags;
for (char c : _descOrTags) {
if( !inTag ) {
if( c == '[' )
@@ -85,8 +85,8 @@ namespace Catch {
tags.push_back( "." );
}
TestCaseInfo info( _name, _className, desc, tags, _lineInfo );
return TestCase( _testCase, info );
TestCaseInfo info( nameAndTags.name, _className, desc, tags, _lineInfo );
return TestCase( _testCase, std::move(info) );
}
void setTags( TestCaseInfo& testCaseInfo, std::vector<std::string> tags ) {
@@ -147,7 +147,7 @@ namespace Catch {
}
TestCase::TestCase( ITestInvoker* testCase, TestCaseInfo const& info ) : TestCaseInfo( info ), test( testCase ) {}
TestCase::TestCase( ITestInvoker* testCase, TestCaseInfo&& info ) : TestCaseInfo( std::move(info) ), test( testCase ) {}
TestCase TestCase::withName( std::string const& _newName ) const {

View File

@@ -9,6 +9,7 @@
#define TWOBLUECUBES_CATCH_TEST_CASE_INFO_H_INCLUDED
#include "catch_common.h"
#include "catch_test_registry.h"
#include <string>
#include <vector>
@@ -61,7 +62,7 @@ namespace Catch {
class TestCase : public TestCaseInfo {
public:
TestCase( ITestInvoker* testCase, TestCaseInfo const& info );
TestCase( ITestInvoker* testCase, TestCaseInfo&& info );
TestCase withName( std::string const& _newName ) const;
@@ -78,8 +79,7 @@ namespace Catch {
TestCase makeTestCase( ITestInvoker* testCase,
std::string const& className,
std::string const& name,
std::string const& description,
NameAndTags const& nameAndTags,
SourceLineInfo const& lineInfo );
}

View File

@@ -96,7 +96,7 @@ namespace Catch {
m_testAsFunction();
}
std::string extractClassName( std::string const& classOrQualifiedMethodName ) {
std::string extractClassName( StringRef const& classOrQualifiedMethodName ) {
std::string className = classOrQualifiedMethodName;
if( startsWith( className, '&' ) )
{

View File

@@ -22,7 +22,7 @@ namespace Catch {
class TestCase;
struct IConfig;
std::vector<TestCase> sortTests( IConfig const& config, std::vector<TestCase> const& unsortedTestCases );
std::vector<TestCase> sortTests( IConfig const& config, std::vector<TestCase> const& unsortedTestCases );
bool matchTest( TestCase const& testCase, TestSpec const& testSpec, IConfig const& config );
void enforceNoDuplicateTestCases( std::vector<TestCase> const& functions );
@@ -58,7 +58,7 @@ namespace Catch {
};
std::string extractClassName( std::string const& classOrQualifiedMethodName );
std::string extractClassName( StringRef const& classOrQualifiedMethodName );
///////////////////////////////////////////////////////////////////////////

View File

@@ -15,23 +15,22 @@ namespace Catch {
return new(std::nothrow) TestInvokerAsFunction( testAsFunction );
}
NameAndTags::NameAndTags( StringRef name_ , StringRef tags_ ) noexcept : name( name_ ), tags( tags_ ) {}
NameAndTags::NameAndTags( StringRef const& name_ , StringRef const& tags_ ) noexcept : name( name_ ), tags( tags_ ) {}
AutoReg::AutoReg( ITestInvoker* invoker, SourceLineInfo const& lineInfo, StringRef classOrMethod, NameAndTags const& nameAndTags ) noexcept {
AutoReg::AutoReg( ITestInvoker* invoker, SourceLineInfo const& lineInfo, StringRef const& classOrMethod, NameAndTags const& nameAndTags ) noexcept {
try {
getMutableRegistryHub()
.registerTest(
makeTestCase(
invoker,
extractClassName( classOrMethod ),
nameAndTags.name,
nameAndTags.tags,
nameAndTags,
lineInfo));
} catch (...) {
// Do not throw when constructing global objects, instead register the exception to be processed later
getMutableRegistryHub().registerStartupException();
}
}
AutoReg::~AutoReg() = default;
}

View File

@@ -35,13 +35,13 @@ auto makeTestInvoker( void (C::*testAsMethod)() ) noexcept -> ITestInvoker* {
}
struct NameAndTags {
NameAndTags( StringRef name_ = StringRef(), StringRef tags_ = StringRef() ) noexcept;
NameAndTags( StringRef const& name_ = StringRef(), StringRef const& tags_ = StringRef() ) noexcept;
StringRef name;
StringRef tags;
};
struct AutoReg : NonCopyable {
AutoReg( ITestInvoker* invoker, SourceLineInfo const& lineInfo, StringRef classOrMethod, NameAndTags const& nameAndTags ) noexcept;
AutoReg( ITestInvoker* invoker, SourceLineInfo const& lineInfo, StringRef const& classOrMethod, NameAndTags const& nameAndTags ) noexcept;
~AutoReg();
};

View File

@@ -116,6 +116,7 @@ std::string StringMaker<std::string>::convert(const std::string& str) {
return s;
}
#ifdef CATCH_CONFIG_WCHAR
std::string StringMaker<std::wstring>::convert(const std::wstring& wstr) {
std::string s;
s.reserve(wstr.size());
@@ -124,6 +125,7 @@ std::string StringMaker<std::wstring>::convert(const std::wstring& wstr) {
}
return ::Catch::Detail::stringify(s);
}
#endif
std::string StringMaker<char const*>::convert(char const* str) {
if (str) {
@@ -139,6 +141,7 @@ std::string StringMaker<char*>::convert(char* str) {
return{ "{null string}" };
}
}
#ifdef CATCH_CONFIG_WCHAR
std::string StringMaker<wchar_t const*>::convert(wchar_t const * str) {
if (str) {
return ::Catch::Detail::stringify(std::wstring{ str });
@@ -153,6 +156,7 @@ std::string StringMaker<wchar_t *>::convert(wchar_t * str) {
return{ "{null string}" };
}
}
#endif
std::string StringMaker<int>::convert(int value) {

View File

@@ -13,6 +13,7 @@
#include <cstddef>
#include <type_traits>
#include <string>
#include "catch_compiler_capabilities.h"
#include "catch_stream.h"
#ifdef __OBJC__
@@ -61,13 +62,18 @@ namespace Catch {
std::string convertUnknownEnumToString( E e );
template<typename T>
typename std::enable_if<!std::is_enum<T>::value, std::string>::type convertUnstreamable( T const& ) {
typename std::enable_if<!std::is_enum<T>::value, std::string>::type convertUnstreamable( T const& value ) {
#if !defined(CATCH_CONFIG_FALLBACK_STRINGIFIER)
(void)value;
return Detail::unprintableString;
};
#else
return CATCH_CONFIG_FALLBACK_STRINGIFIER(value);
#endif
}
template<typename T>
typename std::enable_if<std::is_enum<T>::value, std::string>::type convertUnstreamable( T const& value ) {
return convertUnknownEnumToString( value );
};
}
} // namespace Detail
@@ -114,10 +120,12 @@ namespace Catch {
struct StringMaker<std::string> {
static std::string convert(const std::string& str);
};
#ifdef CATCH_CONFIG_WCHAR
template<>
struct StringMaker<std::wstring> {
static std::string convert(const std::wstring& wstr);
};
#endif
template<>
struct StringMaker<char const *> {
@@ -127,6 +135,7 @@ namespace Catch {
struct StringMaker<char *> {
static std::string convert(char * str);
};
#ifdef CATCH_CONFIG_WCHAR
template<>
struct StringMaker<wchar_t const *> {
static std::string convert(wchar_t const * str);
@@ -135,18 +144,7 @@ namespace Catch {
struct StringMaker<wchar_t *> {
static std::string convert(wchar_t * str);
};
template<typename T>
struct is_string_array : std::false_type {};
template<std::size_t N>
struct is_string_array<char[N]> : std::true_type {};
template<std::size_t N>
struct is_string_array<signed char[N]> : std::true_type {};
template<std::size_t N>
struct is_string_array<unsigned char[N]> : std::true_type {};
#endif
template<int SZ>
struct StringMaker<char[SZ]> {
@@ -399,12 +397,20 @@ namespace Catch {
}
template<typename R>
struct StringMaker<R, typename std::enable_if<is_range<R>::value && !is_string_array<R>::value>::type> {
struct StringMaker<R, typename std::enable_if<is_range<R>::value && !::Catch::Detail::IsStreamInsertable<R>::value>::type> {
static std::string convert( R const& range ) {
return rangeToString( range );
}
};
template <typename T, int SZ>
struct StringMaker<T[SZ]> {
static std::string convert(T const(&arr)[SZ]) {
return rangeToString(arr);
}
};
} // namespace Catch
// Separate std::chrono::duration specialization

View File

@@ -32,7 +32,7 @@ namespace Catch {
Totals delta( Totals const& prevTotals ) const;
int error = 0;
Counts assertions;
Counts testCases;
};

View File

@@ -0,0 +1,21 @@
/*
* Created by Josh on 1/2/2018.
* Copyright 2018 Two Blue Cubes Ltd. All rights reserved.
*
* Distributed under the Boost Software License, Version 1.0. (See accompanying
* file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
*/
#include "catch_compiler_capabilities.h"
#include "catch_uncaught_exceptions.h"
#include <exception>
namespace Catch {
bool uncaught_exceptions() {
#if defined(CATCH_CONFIG_CPP17_UNCAUGHT_EXCEPTIONS)
return std::uncaught_exceptions() > 0;
#else
return std::uncaught_exception();
#endif
}
} // end namespace Catch

View File

@@ -0,0 +1,15 @@
/*
* Created by Josh on 1/2/2018.
* Copyright 2018 Two Blue Cubes Ltd. All rights reserved.
*
* Distributed under the Boost Software License, Version 1.0. (See accompanying
* file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
*/
#ifndef TWOBLUECUBES_CATCH_UNCAUGHT_EXCEPTIONS_H_INCLUDED
#define TWOBLUECUBES_CATCH_UNCAUGHT_EXCEPTIONS_H_INCLUDED
namespace Catch {
bool uncaught_exceptions();
} // end namespace Catch
#endif // TWOBLUECUBES_CATCH_UNCAUGHT_EXCEPTIONS_H_INCLUDED

View File

@@ -37,7 +37,7 @@ namespace Catch {
}
Version const& libraryVersion() {
static Version version( 2, 1, 0, "", 0 );
static Version version( 2, 2, 1, "", 0 );
return version;
}

View File

@@ -64,7 +64,7 @@ namespace Catch {
m_reporterPrefs.shouldRedirectStdOut = true;
}
JunitReporter::~JunitReporter() {};
JunitReporter::~JunitReporter() {}
std::string JunitReporter::getDescription() {
return "Reports test results in an XML format that looks like Ant's junitreport target";

View File

@@ -26,7 +26,7 @@ namespace Catch {
~TAPReporter() override;
static std::string getDescription() {
return "Reports test results in TAP format, suitable for test harneses";
return "Reports test results in TAP format, suitable for test harnesses";
}
ReporterPreferences getPreferences() const override {

View File

@@ -1,12 +1,26 @@
@REM # In debug build, we want to
@REM # 1) Prebuild memcheck redirecter
@REM # 2) Regenerate single header include for examples
@REM # 3) Enable building examples
@REM # Possibilities:
@REM # Debug build + coverage
@REM # Debug build + examples
@REM # Debug build + ---
@REM # Release build
if "%CONFIGURATION%"=="Debug" (
python scripts\generateSingleHeader.py
cmake -Hmisc -Bbuild-misc -A%PLATFORM%
cmake --build build-misc
cmake -H. -BBuild -A%PLATFORM% -DUSE_WMAIN=%wmain% -DBUILD_EXAMPLES=ON -DMEMORYCHECK_COMMAND=build-misc\Debug\CoverageHelper.exe -DMEMORYCHECK_COMMAND_OPTIONS=--sep-- -DMEMORYCHECK_TYPE=Valgrind
if "%coverage%"=="1" (
@REM # coverage needs to build the special helper as well as the main
cmake -Hmisc -Bbuild-misc -A%PLATFORM%
cmake --build build-misc
cmake -H. -BBuild -A%PLATFORM% -DUSE_WMAIN=%wmain% -DMEMORYCHECK_COMMAND=build-misc\Debug\CoverageHelper.exe -DMEMORYCHECK_COMMAND_OPTIONS=--sep-- -DMEMORYCHECK_TYPE=Valgrind
) else (
@REM # We know that coverage is 0
if "%examples%"=="1" (
@REM # Examples live off the single header, so it needs to be regenerated
python scripts\generateSingleHeader.py
cmake -H. -BBuild -A%PLATFORM% -DUSE_WMAIN=%wmain% -DCATCH_BUILD_EXAMPLES=ON
) else (
@REM # This is just a plain debug build
cmake -H. -BBuild -A%PLATFORM% -DUSE_WMAIN=%wmain%
)
)
)
if "%CONFIGURATION%"=="Release" (
cmake -H. -BBuild -A%PLATFORM% -DUSE_WMAIN=%wmain%

View File

@@ -1,8 +1,12 @@
cd Build
if "%CONFIGURATION%"=="Debug" (
ctest -j 2 -C %CONFIGURATION% -D ExperimentalMemCheck
python ..\misc\appveyorMergeCoverageScript.py
codecov --root .. --no-color --disable gcov -f cobertura.xml -t %CODECOV_TOKEN%
if "%coverage%"=="1" (
ctest -j 2 -C %CONFIGURATION% -D ExperimentalMemCheck
python ..\misc\appveyorMergeCoverageScript.py
codecov --root .. --no-color --disable gcov -f cobertura.xml -t %CODECOV_TOKEN%
) else (
ctest -j 2 -C %CONFIGURATION%
)
)
if "%CONFIGURATION%"=="Release" (
ctest -j 2 -C %CONFIGURATION%

View File

@@ -96,5 +96,10 @@ int main(int argc, char** argv) {
return lhs + ' ' + rhs;
});
exec_cmd(cmdline, num, windowsify_path(catch_path(args[0])));
try {
return exec_cmd(cmdline, num, windowsify_path(catch_path(args[0])));
} catch (std::exception const& ex) {
std::cerr << "Helper failed with: '" << ex.what() << "'\n";
return 12;
}
}

View File

@@ -1,5 +1,5 @@
# Downloads are done from the oficial github release page links
$downloadUrl = "https://github.com/OpenCppCoverage/OpenCppCoverage/releases/download/release-0.9.6.1/OpenCppCoverageSetup-x64-0.9.6.1.exe"
# Downloads are done from the official github release page links
$downloadUrl = "https://github.com/OpenCppCoverage/OpenCppCoverage/releases/download/release-0.9.7.0/OpenCppCoverageSetup-x64-0.9.7.0.exe"
$installerPath = [System.IO.Path]::Combine($Env:USERPROFILE, "Downloads", "OpenCppCoverageSetup.exe")
if(-Not (Test-Path $installerPath)) {

View File

@@ -53,7 +53,7 @@
:test-result: PASS Inequality checks that should succeed
:test-result: PASS Less-than inequalities with different epsilons
:test-result: PASS Long strings can be wrapped
:test-result: PASS Long text is truncted
:test-result: PASS Long text is truncated
:test-result: PASS ManuallyRegistered
:test-result: PASS Matchers can be (AllOf) composed with the && operator
:test-result: PASS Matchers can be (AnyOf) composed with the || operator

View File

@@ -3,6 +3,13 @@ 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: t1 == t2 for: {?} == {?}
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: {?} > {?}
Compilation.tests.cpp:<line number>: passed: t1 <= t2 for: {?} <= {?}
Compilation.tests.cpp:<line number>: passed: t1 >= t2 for: {?} >= {?}
Misc.tests.cpp:<line number>: passed:
Exception.tests.cpp:<line number>: failed: unexpected exception with message: 'answer := 42' with 1 message: 'expected exception'
Exception.tests.cpp:<line number>: failed: unexpected exception with message: 'answer := 42'; expression was: thisThrows() with 1 message: 'expected exception'
Exception.tests.cpp:<line number>: passed: thisThrows() with 1 message: 'answer := 42'
@@ -229,9 +236,9 @@ Matchers.tests.cpp:<line number>: passed: 0., !WithinAbs(1., 0.99) for: 0.0 not
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: 1., WithinULP(1., 0) for: 1.0 is within 0 ULPs of 1.0
Matchers.tests.cpp:<line number>: passed: std::nextafter(1., 2.), WithinULP(1., 1) for: 1.0 is within 1 ULPs of 1.0
Matchers.tests.cpp:<line number>: passed: std::nextafter(1., 0.), WithinULP(1., 1) for: 1.0 is within 1 ULPs of 1.0
Matchers.tests.cpp:<line number>: passed: std::nextafter(1., 2.), !WithinULP(1., 0) for: 1.0 not 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
@@ -249,9 +256,9 @@ Matchers.tests.cpp:<line number>: passed: 0.f, !WithinAbs(1.f, 0.99f) for: 0.0f
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: 1.f, WithinULP(1.f, 0) for: 1.0f is within 0 ULPs of 1.0f
Matchers.tests.cpp:<line number>: passed: std::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: std::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: std::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: 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
@@ -508,13 +515,17 @@ CmdLine.tests.cpp:<line number>: passed: config.shouldDebugBreak == false for: f
CmdLine.tests.cpp:<line number>: passed: config.abortAfter == -1 for: -1 == -1
CmdLine.tests.cpp:<line number>: passed: config.noThrow == false for: false == false
CmdLine.tests.cpp:<line number>: passed: config.reporterNames.empty() for: true
CmdLine.tests.cpp:<line number>: passed: !(cfg.hasTestFilters()) for: !false
CmdLine.tests.cpp:<line number>: passed: result for: {?}
CmdLine.tests.cpp:<line number>: passed: cfg.hasTestFilters() for: true
CmdLine.tests.cpp:<line number>: passed: cfg.testSpec().matches(fakeTestCase("notIncluded")) == false for: false == false
CmdLine.tests.cpp:<line number>: passed: cfg.testSpec().matches(fakeTestCase("test1")) for: true
CmdLine.tests.cpp:<line number>: passed: result for: {?}
CmdLine.tests.cpp:<line number>: passed: cfg.hasTestFilters() for: true
CmdLine.tests.cpp:<line number>: passed: cfg.testSpec().matches(fakeTestCase("test1")) == false for: false == false
CmdLine.tests.cpp:<line number>: passed: cfg.testSpec().matches(fakeTestCase("alwaysIncluded")) for: true
CmdLine.tests.cpp:<line number>: passed: result for: {?}
CmdLine.tests.cpp:<line number>: passed: cfg.hasTestFilters() for: true
CmdLine.tests.cpp:<line number>: passed: cfg.testSpec().matches(fakeTestCase("test1")) == false for: false == false
CmdLine.tests.cpp:<line number>: passed: cfg.testSpec().matches(fakeTestCase("alwaysIncluded")) for: true
CmdLine.tests.cpp:<line number>: passed: cli.parse({"test", "-r", "console"}) for: {?}
@@ -592,6 +603,11 @@ 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"
Matchers.tests.cpp:<line number>: failed: testStringForMatching(), StartsWith("string", Catch::CaseSensitive::No) for: "this string contains 'abc' as a substring" starts with: "string" (case insensitive)
ToStringGeneral.tests.cpp:<line number>: passed: Catch::Detail::stringify(singular) == "{ 1 }" for: "{ 1 }" == "{ 1 }"
ToStringGeneral.tests.cpp:<line number>: passed: Catch::Detail::stringify(arr) == "{ 3, 2, 1 }" for: "{ 3, 2, 1 }" == "{ 3, 2, 1 }"
ToStringGeneral.tests.cpp:<line number>: passed: Catch::Detail::stringify(arr) == R"({ { "1:1", "1:2", "1:3" }, { "2:1", "2:2" } })" for: "{ { "1:1", "1:2", "1:3" }, { "2:1", "2:2" } }"
==
"{ { "1:1", "1:2", "1:3" }, { "2:1", "2:2" } }"
Matchers.tests.cpp:<line number>: passed: testStringForMatching(), Contains("string") for: "this string contains 'abc' as a substring" contains: "string"
Matchers.tests.cpp:<line number>: passed: testStringForMatching(), Contains("string", Catch::CaseSensitive::No) for: "this string contains 'abc' as a substring" contains: "string" (case insensitive)
Matchers.tests.cpp:<line number>: passed: testStringForMatching(), Contains("abc") for: "this string contains 'abc' as a substring" contains: "abc"
@@ -611,18 +627,21 @@ String.tests.cpp:<line number>: passed: isOwned( s ) == false for: false == fals
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: original == "original"
String.tests.cpp:<line number>: failed: isSubstring( original ) for: false
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: 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: 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 == data( s ) for: "hello world!" == "hello world!"
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: data( ss ) != data( s ) for: "hello" != "hello world!"
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!"
@@ -641,6 +660,9 @@ 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: 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
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
@@ -678,6 +700,7 @@ 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
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!'
PartTracker.tests.cpp:<line number>: passed: testCase.isOpen() for: true
PartTracker.tests.cpp:<line number>: passed: s1.isOpen() for: true
PartTracker.tests.cpp:<line number>: passed: s1.isSuccessfullyCompleted() for: true
@@ -963,19 +986,24 @@ ToStringPair.tests.cpp:<line number>: passed: ::Catch::Detail::stringify( pr ) =
==
"{ { "green", 55 } }"
Tricky.tests.cpp:<line number>: failed: std::string( "first" ) == "second" for: "first" == "second"
ToStringWhich.tests.cpp:<line number>: passed: ::Catch::Detail::stringify(streamable_range{}) == "op<<(streamable_range)" for: "op<<(streamable_range)"
==
"op<<(streamable_range)"
ToStringWhich.tests.cpp:<line number>: passed: ::Catch::Detail::stringify(stringmaker_range{}) == "stringmaker(streamable_range)" for: "stringmaker(streamable_range)"
==
"stringmaker(streamable_range)"
ToStringWhich.tests.cpp:<line number>: passed: ::Catch::Detail::stringify(just_range{}) == "{ 1, 2, 3, 4 }" for: "{ 1, 2, 3, 4 }" == "{ 1, 2, 3, 4 }"
ToStringWhich.tests.cpp:<line number>: passed: ::Catch::Detail::stringify(disabled_range{}) == "{ !!! }" for: "{ !!! }" == "{ !!! }"
ToStringWhich.tests.cpp:<line number>: passed: ::Catch::Detail::stringify( item ) == "StringMaker<has_maker>" for: "StringMaker<has_maker>"
==
"StringMaker<has_maker>"
ToStringWhich.tests.cpp:<line number>: passed: ::Catch::Detail::stringify( item ) == "StringMaker<has_maker_and_operator>" for: "StringMaker<has_maker_and_operator>"
==
"StringMaker<has_maker_and_operator>"
ToStringWhich.tests.cpp:<line number>: passed: ::Catch::Detail::stringify(item) == "{ !!! }" for: "{ !!! }" == "{ !!! }"
ToStringWhich.tests.cpp:<line number>: passed: ::Catch::Detail::stringify( item ) == "operator<<( has_operator )" for: "operator<<( has_operator )"
==
"operator<<( has_operator )"
Misc.tests.cpp:<line number>: passed: result == "/"wide load/"" for: ""wide load"" == ""wide load""
Misc.tests.cpp:<line number>: passed: result == "/"wide load/"" for: ""wide load"" == ""wide load""
Misc.tests.cpp:<line number>: passed: result == "/"wide load/"" for: ""wide load"" == ""wide load""
Misc.tests.cpp:<line number>: passed: result == "/"wide load/"" for: ""wide load"" == ""wide load""
ToStringWhich.tests.cpp:<line number>: passed: ::Catch::Detail::stringify( v ) == "{ StringMaker<has_maker> }" for: "{ StringMaker<has_maker> }"
==
"{ StringMaker<has_maker> }"
@@ -985,6 +1013,11 @@ ToStringWhich.tests.cpp:<line number>: passed: ::Catch::Detail::stringify( v ) =
ToStringWhich.tests.cpp:<line number>: passed: ::Catch::Detail::stringify( v ) == "{ operator<<( has_operator ) }" for: "{ operator<<( has_operator ) }"
==
"{ operator<<( has_operator ) }"
Exception.tests.cpp:<line number>: failed: unexpected exception with message: 'Why would you throw a std::string?'
Misc.tests.cpp:<line number>: passed: result == "/"wide load/"" for: ""wide load"" == ""wide load""
Misc.tests.cpp:<line number>: passed: result == "/"wide load/"" for: ""wide load"" == ""wide load""
Misc.tests.cpp:<line number>: passed: result == "/"wide load/"" for: ""wide load"" == ""wide load""
Misc.tests.cpp:<line number>: passed: result == "/"wide load/"" for: ""wide load"" == ""wide load""
EnumToString.tests.cpp:<line number>: passed: ::Catch::Detail::stringify(e0) == "E2/V0" for: "E2/V0" == "E2/V0"
EnumToString.tests.cpp:<line number>: passed: ::Catch::Detail::stringify(e1) == "E2/V1" for: "E2/V1" == "E2/V1"
EnumToString.tests.cpp:<line number>: passed: ::Catch::Detail::stringify(e3) == "Unknown enum value 10" for: "Unknown enum value 10"
@@ -1047,5 +1080,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 49 test cases, failed 108 assertions.
Failed 62 test cases, failed 121 assertions.

View File

@@ -738,6 +738,16 @@ with expansion:
}
"
-------------------------------------------------------------------------------
Thrown string literals are translated
-------------------------------------------------------------------------------
Exception.tests.cpp:<line number>
...............................................................................
Exception.tests.cpp:<line number>: FAILED:
due to unexpected exception with message:
For some reason someone is throwing a string literal!
-------------------------------------------------------------------------------
Unexpected exceptions can be translated
-------------------------------------------------------------------------------
@@ -1063,7 +1073,17 @@ Tricky.tests.cpp:<line number>: FAILED:
with expansion:
"first" == "second"
===============================================================================
test cases: 195 | 144 passed | 47 failed | 4 failed as expected
assertions: 983 | 857 passed | 105 failed | 21 failed as expected
-------------------------------------------------------------------------------
thrown std::strings are translated
-------------------------------------------------------------------------------
Exception.tests.cpp:<line number>
...............................................................................
Exception.tests.cpp:<line number>: FAILED:
due to unexpected exception with message:
Why would you throw a std::string?
===============================================================================
test cases: 202 | 149 passed | 49 failed | 4 failed as expected
assertions: 1007 | 879 passed | 107 failed | 21 failed as expected

View File

@@ -51,6 +51,57 @@ PASSED:
with expansion:
0 == 0
-------------------------------------------------------------------------------
#1147
-------------------------------------------------------------------------------
Compilation.tests.cpp:<line number>
...............................................................................
Compilation.tests.cpp:<line number>:
PASSED:
REQUIRE( t1 == t2 )
with expansion:
{?} == {?}
Compilation.tests.cpp:<line number>:
PASSED:
REQUIRE( t1 != t2 )
with expansion:
{?} != {?}
Compilation.tests.cpp:<line number>:
PASSED:
REQUIRE( t1 < t2 )
with expansion:
{?} < {?}
Compilation.tests.cpp:<line number>:
PASSED:
REQUIRE( t1 > t2 )
with expansion:
{?} > {?}
Compilation.tests.cpp:<line number>:
PASSED:
REQUIRE( t1 <= t2 )
with expansion:
{?} <= {?}
Compilation.tests.cpp:<line number>:
PASSED:
REQUIRE( t1 >= t2 )
with expansion:
{?} >= {?}
-------------------------------------------------------------------------------
#1175 - Hidden Test
-------------------------------------------------------------------------------
Misc.tests.cpp:<line number>
...............................................................................
Misc.tests.cpp:<line number>:
PASSED:
-------------------------------------------------------------------------------
#748 - captures with unexpected exceptions
outside assertions
@@ -532,6 +583,15 @@ PASSED:
with expansion:
100.3 == Approx( 100.0 )
-------------------------------------------------------------------------------
An empty test with no assertions
-------------------------------------------------------------------------------
Misc.tests.cpp:<line number>
...............................................................................
No assertions in test case 'An empty test with no assertions'
-------------------------------------------------------------------------------
An expression with side-effects should only be evaluated once
-------------------------------------------------------------------------------
@@ -1813,19 +1873,19 @@ with expansion:
Matchers.tests.cpp:<line number>:
PASSED:
REQUIRE_THAT( std::nextafter(1., 2.), WithinULP(1., 1) )
REQUIRE_THAT( nextafter(1., 2.), WithinULP(1., 1) )
with expansion:
1.0 is within 1 ULPs of 1.0
Matchers.tests.cpp:<line number>:
PASSED:
REQUIRE_THAT( std::nextafter(1., 0.), WithinULP(1., 1) )
REQUIRE_THAT( nextafter(1., 0.), WithinULP(1., 1) )
with expansion:
1.0 is within 1 ULPs of 1.0
Matchers.tests.cpp:<line number>:
PASSED:
REQUIRE_THAT( std::nextafter(1., 2.), !WithinULP(1., 0) )
REQUIRE_THAT( nextafter(1., 2.), !WithinULP(1., 0) )
with expansion:
1.0 not is within 0 ULPs of 1.0
@@ -1953,19 +2013,19 @@ with expansion:
Matchers.tests.cpp:<line number>:
PASSED:
REQUIRE_THAT( std::nextafter(1.f, 2.f), WithinULP(1.f, 1) )
REQUIRE_THAT( nextafter(1.f, 2.f), WithinULP(1.f, 1) )
with expansion:
1.0f is within 1 ULPs of 1.0f
Matchers.tests.cpp:<line number>:
PASSED:
REQUIRE_THAT( std::nextafter(1.f, 0.f), WithinULP(1.f, 1) )
REQUIRE_THAT( nextafter(1.f, 0.f), WithinULP(1.f, 1) )
with expansion:
1.0f is within 1 ULPs of 1.0f
Matchers.tests.cpp:<line number>:
PASSED:
REQUIRE_THAT( std::nextafter(1.f, 2.f), !WithinULP(1.f, 0) )
REQUIRE_THAT( nextafter(1.f, 2.f), !WithinULP(1.f, 0) )
with expansion:
1.0f not is within 0 ULPs of 1.0f
@@ -2076,6 +2136,9 @@ warning:
this is a message
this is a warning
No assertions in test case 'INFO and WARN do not abort tests'
-------------------------------------------------------------------------------
INFO gets logged on failure
-------------------------------------------------------------------------------
@@ -2488,6 +2551,9 @@ Misc.tests.cpp:<line number>:
warning:
This one ran
No assertions in test case 'Nice descriptive name'
-------------------------------------------------------------------------------
Non-std exceptions can be translated
-------------------------------------------------------------------------------
@@ -3908,6 +3974,12 @@ PASSED:
with expansion:
true
CmdLine.tests.cpp:<line number>:
PASSED:
CHECK_FALSE( cfg.hasTestFilters() )
with expansion:
!false
-------------------------------------------------------------------------------
Process can be configured on command line
test lists
@@ -3922,6 +3994,12 @@ PASSED:
with expansion:
{?}
CmdLine.tests.cpp:<line number>:
PASSED:
REQUIRE( cfg.hasTestFilters() )
with expansion:
true
CmdLine.tests.cpp:<line number>:
PASSED:
REQUIRE( cfg.testSpec().matches(fakeTestCase("notIncluded")) == false )
@@ -3948,6 +4026,12 @@ PASSED:
with expansion:
{?}
CmdLine.tests.cpp:<line number>:
PASSED:
REQUIRE( cfg.hasTestFilters() )
with expansion:
true
CmdLine.tests.cpp:<line number>:
PASSED:
REQUIRE( cfg.testSpec().matches(fakeTestCase("test1")) == false )
@@ -3974,6 +4058,12 @@ PASSED:
with expansion:
{?}
CmdLine.tests.cpp:<line number>:
PASSED:
REQUIRE( cfg.hasTestFilters() )
with expansion:
true
CmdLine.tests.cpp:<line number>:
PASSED:
REQUIRE( cfg.testSpec().matches(fakeTestCase("test1")) == false )
@@ -4620,6 +4710,15 @@ with expansion:
A string sent directly to stdout
A string sent directly to stderr
A string sent to stderr via clog
-------------------------------------------------------------------------------
Sends stuff to stdout and stderr
-------------------------------------------------------------------------------
Misc.tests.cpp:<line number>
...............................................................................
No assertions in test case 'Sends stuff to stdout and stderr'
-------------------------------------------------------------------------------
Some simple comparisons between doubles
-------------------------------------------------------------------------------
@@ -4707,6 +4806,47 @@ with expansion:
"this string contains 'abc' as a substring" starts with: "string" (case
insensitive)
-------------------------------------------------------------------------------
Static arrays are convertible to string
Single item
-------------------------------------------------------------------------------
ToStringGeneral.tests.cpp:<line number>
...............................................................................
ToStringGeneral.tests.cpp:<line number>:
PASSED:
REQUIRE( Catch::Detail::stringify(singular) == "{ 1 }" )
with expansion:
"{ 1 }" == "{ 1 }"
-------------------------------------------------------------------------------
Static arrays are convertible to string
Multiple
-------------------------------------------------------------------------------
ToStringGeneral.tests.cpp:<line number>
...............................................................................
ToStringGeneral.tests.cpp:<line number>:
PASSED:
REQUIRE( Catch::Detail::stringify(arr) == "{ 3, 2, 1 }" )
with expansion:
"{ 3, 2, 1 }" == "{ 3, 2, 1 }"
-------------------------------------------------------------------------------
Static arrays are convertible to string
Non-trivial inner items
-------------------------------------------------------------------------------
ToStringGeneral.tests.cpp:<line number>
...............................................................................
ToStringGeneral.tests.cpp:<line number>:
PASSED:
REQUIRE( Catch::Detail::stringify(arr) == R"({ { "1:1", "1:2", "1:3" }, { "2:1", "2:2" } })" )
with expansion:
"{ { "1:1", "1:2", "1:3" }, { "2:1", "2:2" } }"
==
"{ { "1:1", "1:2", "1:3" }, { "2:1", "2:2" } }"
-------------------------------------------------------------------------------
String matchers
-------------------------------------------------------------------------------
@@ -4858,10 +4998,29 @@ String.tests.cpp:<line number>:
PASSED:
REQUIRE( original == "original" )
String.tests.cpp:<line number>: FAILED:
String.tests.cpp:<line number>:
PASSED:
REQUIRE( isSubstring( original ) )
with expansion:
false
true
String.tests.cpp:<line number>:
PASSED:
REQUIRE( isOwned( original ) == false )
with expansion:
false == false
String.tests.cpp:<line number>:
PASSED:
REQUIRE( isSubstring( original ) == false )
with expansion:
false == false
String.tests.cpp:<line number>:
PASSED:
REQUIRE( isOwned( original ) )
with expansion:
true
-------------------------------------------------------------------------------
StringRef
@@ -4917,7 +5076,7 @@ with expansion:
String.tests.cpp:<line number>:
PASSED:
REQUIRE( rawChars == data( s ) )
REQUIRE( rawChars == s.currentData() )
with expansion:
"hello world!" == "hello world!"
@@ -4941,7 +5100,7 @@ with expansion:
String.tests.cpp:<line number>:
PASSED:
REQUIRE( data( ss ) != data( s ) )
REQUIRE( ss.currentData() != s.currentData() )
with expansion:
"hello" != "hello world!"
@@ -5132,6 +5291,31 @@ PASSED:
with expansion:
11 == 11
-------------------------------------------------------------------------------
StringRef
Counting utf-8 codepoints
-------------------------------------------------------------------------------
String.tests.cpp:<line number>
...............................................................................
String.tests.cpp:<line number>:
PASSED:
REQUIRE( ascii.numberOfCharacters() == ascii.size() )
with expansion:
39 == 39
String.tests.cpp:<line number>:
PASSED:
REQUIRE( simpleu8.numberOfCharacters() == 30 )
with expansion:
30 == 30
String.tests.cpp:<line number>:
PASSED:
REQUIRE( emojis.numberOfCharacters() == 9 )
with expansion:
9 == 9
-------------------------------------------------------------------------------
Stringifying std::chrono::duration helpers
-------------------------------------------------------------------------------
@@ -5307,6 +5491,9 @@ Message.tests.cpp:<line number>:
FAILED - but was ok:
CHECK_NOFAIL( 1 == 2 )
No assertions in test case 'The NO_FAIL macro reports a failure but does not fail the test'
-------------------------------------------------------------------------------
This test 'should' fail but doesn't
-------------------------------------------------------------------------------
@@ -5318,6 +5505,16 @@ PASSED:
with message:
oops!
-------------------------------------------------------------------------------
Thrown string literals are translated
-------------------------------------------------------------------------------
Exception.tests.cpp:<line number>
...............................................................................
Exception.tests.cpp:<line number>: FAILED:
due to unexpected exception with message:
For some reason someone is throwing a string literal!
-------------------------------------------------------------------------------
Tracker
-------------------------------------------------------------------------------
@@ -6672,6 +6869,15 @@ Exception.tests.cpp:<line number>: FAILED:
due to unexpected exception with message:
unexpected exception
-------------------------------------------------------------------------------
When unchecked exceptions are thrown, but caught, they do not affect the test
-------------------------------------------------------------------------------
Exception.tests.cpp:<line number>
...............................................................................
No assertions in test case 'When unchecked exceptions are thrown, but caught, they do not affect the test'
-------------------------------------------------------------------------------
Where the LHS is not a simple value
-------------------------------------------------------------------------------
@@ -6683,6 +6889,9 @@ warning:
Uncomment the code in this test to check that it gives a sensible compiler
error
No assertions in test case 'Where the LHS is not a simple value'
-------------------------------------------------------------------------------
Where there is more to the expression after the RHS
-------------------------------------------------------------------------------
@@ -6694,6 +6903,9 @@ warning:
Uncomment the code in this test to check that it gives a sensible compiler
error
No assertions in test case 'Where there is more to the expression after the RHS'
-------------------------------------------------------------------------------
X/level/0/a
-------------------------------------------------------------------------------
@@ -7060,7 +7272,25 @@ Misc.tests.cpp:<line number>
Misc.tests.cpp:<line number>:
PASSED:
-------------------------------------------------------------------------------
first tag
-------------------------------------------------------------------------------
Misc.tests.cpp:<line number>
...............................................................................
No assertions in test case 'first tag'
loose text artifact
-------------------------------------------------------------------------------
has printf
-------------------------------------------------------------------------------
Tricky.tests.cpp:<line number>
...............................................................................
No assertions in test case 'has printf'
-------------------------------------------------------------------------------
just failure
-------------------------------------------------------------------------------
@@ -7071,6 +7301,15 @@ Message.tests.cpp:<line number>: FAILED:
explicitly with message:
Previous info should not be seen
-------------------------------------------------------------------------------
just info
-------------------------------------------------------------------------------
Message.tests.cpp:<line number>
...............................................................................
No assertions in test case 'just info'
-------------------------------------------------------------------------------
long long
-------------------------------------------------------------------------------
@@ -7489,6 +7728,15 @@ PASSED:
with expansion:
"didn|'t" == "didn|'t"
-------------------------------------------------------------------------------
second tag
-------------------------------------------------------------------------------
Misc.tests.cpp:<line number>
...............................................................................
No assertions in test case 'second tag'
-------------------------------------------------------------------------------
send a single char to INFO
-------------------------------------------------------------------------------
@@ -7643,6 +7891,40 @@ Tricky.tests.cpp:<line number>: FAILED:
with expansion:
"first" == "second"
-------------------------------------------------------------------------------
stringify ranges
-------------------------------------------------------------------------------
ToStringWhich.tests.cpp:<line number>
...............................................................................
ToStringWhich.tests.cpp:<line number>:
PASSED:
REQUIRE( ::Catch::Detail::stringify(streamable_range{}) == "op<<(streamable_range)" )
with expansion:
"op<<(streamable_range)"
==
"op<<(streamable_range)"
ToStringWhich.tests.cpp:<line number>:
PASSED:
REQUIRE( ::Catch::Detail::stringify(stringmaker_range{}) == "stringmaker(streamable_range)" )
with expansion:
"stringmaker(streamable_range)"
==
"stringmaker(streamable_range)"
ToStringWhich.tests.cpp:<line number>:
PASSED:
REQUIRE( ::Catch::Detail::stringify(just_range{}) == "{ 1, 2, 3, 4 }" )
with expansion:
"{ 1, 2, 3, 4 }" == "{ 1, 2, 3, 4 }"
ToStringWhich.tests.cpp:<line number>:
PASSED:
REQUIRE( ::Catch::Detail::stringify(disabled_range{}) == "{ !!! }" )
with expansion:
"{ !!! }" == "{ !!! }"
-------------------------------------------------------------------------------
stringify( has_maker )
-------------------------------------------------------------------------------
@@ -7658,7 +7940,7 @@ with expansion:
"StringMaker<has_maker>"
-------------------------------------------------------------------------------
stringify( has_maker_and_toString )
stringify( has_maker_and_operator )
-------------------------------------------------------------------------------
ToStringWhich.tests.cpp:<line number>
...............................................................................
@@ -7671,6 +7953,18 @@ with expansion:
==
"StringMaker<has_maker_and_operator>"
-------------------------------------------------------------------------------
stringify( has_neither )
-------------------------------------------------------------------------------
ToStringWhich.tests.cpp:<line number>
...............................................................................
ToStringWhich.tests.cpp:<line number>:
PASSED:
REQUIRE( ::Catch::Detail::stringify(item) == "{ !!! }" )
with expansion:
"{ !!! }" == "{ !!! }"
-------------------------------------------------------------------------------
stringify( has_operator )
-------------------------------------------------------------------------------
@@ -7685,6 +7979,58 @@ with expansion:
==
"operator<<( has_operator )"
-------------------------------------------------------------------------------
stringify( vectors<has_maker> )
-------------------------------------------------------------------------------
ToStringWhich.tests.cpp:<line number>
...............................................................................
ToStringWhich.tests.cpp:<line number>:
PASSED:
REQUIRE( ::Catch::Detail::stringify( v ) == "{ StringMaker<has_maker> }" )
with expansion:
"{ StringMaker<has_maker> }"
==
"{ StringMaker<has_maker> }"
-------------------------------------------------------------------------------
stringify( vectors<has_maker_and_operator> )
-------------------------------------------------------------------------------
ToStringWhich.tests.cpp:<line number>
...............................................................................
ToStringWhich.tests.cpp:<line number>:
PASSED:
REQUIRE( ::Catch::Detail::stringify( v ) == "{ StringMaker<has_maker_and_operator> }" )
with expansion:
"{ StringMaker<has_maker_and_operator> }"
==
"{ StringMaker<has_maker_and_operator> }"
-------------------------------------------------------------------------------
stringify( vectors<has_operator> )
-------------------------------------------------------------------------------
ToStringWhich.tests.cpp:<line number>
...............................................................................
ToStringWhich.tests.cpp:<line number>:
PASSED:
REQUIRE( ::Catch::Detail::stringify( v ) == "{ operator<<( has_operator ) }" )
with expansion:
"{ operator<<( has_operator ) }"
==
"{ operator<<( has_operator ) }"
-------------------------------------------------------------------------------
thrown std::strings are translated
-------------------------------------------------------------------------------
Exception.tests.cpp:<line number>
...............................................................................
Exception.tests.cpp:<line number>: FAILED:
due to unexpected exception with message:
Why would you throw a std::string?
-------------------------------------------------------------------------------
toString on const wchar_t const pointer returns the string contents
-------------------------------------------------------------------------------
@@ -7733,48 +8079,6 @@ PASSED:
with expansion:
""wide load"" == ""wide load""
-------------------------------------------------------------------------------
toString( vectors<has_maker> )
-------------------------------------------------------------------------------
ToStringWhich.tests.cpp:<line number>
...............................................................................
ToStringWhich.tests.cpp:<line number>:
PASSED:
REQUIRE( ::Catch::Detail::stringify( v ) == "{ StringMaker<has_maker> }" )
with expansion:
"{ StringMaker<has_maker> }"
==
"{ StringMaker<has_maker> }"
-------------------------------------------------------------------------------
toString( vectors<has_maker_and_operator> )
-------------------------------------------------------------------------------
ToStringWhich.tests.cpp:<line number>
...............................................................................
ToStringWhich.tests.cpp:<line number>:
PASSED:
REQUIRE( ::Catch::Detail::stringify( v ) == "{ StringMaker<has_maker_and_operator> }" )
with expansion:
"{ StringMaker<has_maker_and_operator> }"
==
"{ StringMaker<has_maker_and_operator> }"
-------------------------------------------------------------------------------
toString( vectors<has_operator> )
-------------------------------------------------------------------------------
ToStringWhich.tests.cpp:<line number>
...............................................................................
ToStringWhich.tests.cpp:<line number>:
PASSED:
REQUIRE( ::Catch::Detail::stringify( v ) == "{ operator<<( has_operator ) }" )
with expansion:
"{ operator<<( has_operator ) }"
==
"{ operator<<( has_operator ) }"
-------------------------------------------------------------------------------
toString(enum class w/operator<<)
-------------------------------------------------------------------------------
@@ -8246,6 +8550,6 @@ Misc.tests.cpp:<line number>:
PASSED:
===============================================================================
test cases: 195 | 142 passed | 49 failed | 4 failed as expected
assertions: 982 | 853 passed | 108 failed | 21 failed as expected
test cases: 202 | 136 passed | 62 failed | 4 failed as expected
assertions: 1021 | 879 passed | 121 failed | 21 failed as expected

View File

@@ -51,6 +51,57 @@ PASSED:
with expansion:
0 == 0
-------------------------------------------------------------------------------
#1147
-------------------------------------------------------------------------------
Compilation.tests.cpp:<line number>
...............................................................................
Compilation.tests.cpp:<line number>:
PASSED:
REQUIRE( t1 == t2 )
with expansion:
{?} == {?}
Compilation.tests.cpp:<line number>:
PASSED:
REQUIRE( t1 != t2 )
with expansion:
{?} != {?}
Compilation.tests.cpp:<line number>:
PASSED:
REQUIRE( t1 < t2 )
with expansion:
{?} < {?}
Compilation.tests.cpp:<line number>:
PASSED:
REQUIRE( t1 > t2 )
with expansion:
{?} > {?}
Compilation.tests.cpp:<line number>:
PASSED:
REQUIRE( t1 <= t2 )
with expansion:
{?} <= {?}
Compilation.tests.cpp:<line number>:
PASSED:
REQUIRE( t1 >= t2 )
with expansion:
{?} >= {?}
-------------------------------------------------------------------------------
#1175 - Hidden Test
-------------------------------------------------------------------------------
Misc.tests.cpp:<line number>
...............................................................................
Misc.tests.cpp:<line number>:
PASSED:
-------------------------------------------------------------------------------
#748 - captures with unexpected exceptions
outside assertions
@@ -257,6 +308,6 @@ with expansion:
!true
===============================================================================
test cases: 10 | 7 passed | 1 failed | 2 failed as expected
assertions: 28 | 21 passed | 4 failed | 3 failed as expected
test cases: 12 | 9 passed | 1 failed | 2 failed as expected
assertions: 35 | 28 passed | 4 failed | 3 failed as expected

View File

@@ -1,10 +1,12 @@
<?xml version="1.0" encoding="UTF-8"?>
<testsuitesloose text artifact
>
<testsuite name="<exe-name>" errors="15" failures="94" tests="983" hostname="tbd" time="{duration}" timestamp="{iso8601-timestamp}">
<testsuite name="<exe-name>" errors="17" failures="105" tests="1022" hostname="tbd" time="{duration}" timestamp="{iso8601-timestamp}">
<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="#1147" time="{duration}"/>
<testcase classname="<exe-name>.global" name="#1175 - Hidden Test" time="{duration}"/>
<testcase classname="<exe-name>.global" name="#748 - captures with unexpected exceptions/outside assertions" time="{duration}">
<error type="TEST_CASE">
expected exception
@@ -537,15 +539,14 @@ Matchers.tests.cpp:<line number>
Matchers.tests.cpp:<line number>
</failure>
</testcase>
<testcase classname="<exe-name>.global" name="Static arrays are convertible to string/Single item" time="{duration}"/>
<testcase classname="<exe-name>.global" name="Static arrays are convertible to string/Multiple" time="{duration}"/>
<testcase classname="<exe-name>.global" name="Static arrays are convertible to string/Non-trivial inner items" time="{duration}"/>
<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}">
<failure message="false" type="REQUIRE">
String.tests.cpp:<line number>
</failure>
</testcase>
<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}"/>
@@ -558,6 +559,7 @@ String.tests.cpp:<line number>
<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="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}"/>
@@ -579,6 +581,12 @@ Misc.tests.cpp:<line number>
<testcase classname="<exe-name>.global" name="Test enum bit values" 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">
For some reason someone is throwing a string literal!
Exception.tests.cpp:<line number>
</error>
</testcase>
<testcase classname="<exe-name>.global" name="Tracker" time="{duration}"/>
<testcase classname="<exe-name>.global" name="Tracker/successfully close one section" time="{duration}"/>
<testcase classname="<exe-name>.global" name="Tracker/fail one section" time="{duration}"/>
@@ -814,16 +822,24 @@ Message.tests.cpp:<line number>
Tricky.tests.cpp:<line number>
</failure>
</testcase>
<testcase classname="<exe-name>.global" name="stringify ranges" time="{duration}"/>
<testcase classname="<exe-name>.global" name="stringify( has_maker )" time="{duration}"/>
<testcase classname="<exe-name>.global" name="stringify( has_maker_and_toString )" time="{duration}"/>
<testcase classname="<exe-name>.global" name="stringify( has_maker_and_operator )" time="{duration}"/>
<testcase classname="<exe-name>.global" name="stringify( has_neither )" time="{duration}"/>
<testcase classname="<exe-name>.global" name="stringify( has_operator )" time="{duration}"/>
<testcase classname="<exe-name>.global" name="stringify( vectors&lt;has_maker> )" time="{duration}"/>
<testcase classname="<exe-name>.global" name="stringify( vectors&lt;has_maker_and_operator> )" time="{duration}"/>
<testcase classname="<exe-name>.global" name="stringify( vectors&lt;has_operator> )" time="{duration}"/>
<testcase classname="<exe-name>.global" name="thrown std::strings are translated" time="{duration}">
<error type="TEST_CASE">
Why would you throw a std::string?
Exception.tests.cpp:<line number>
</error>
</testcase>
<testcase classname="<exe-name>.global" name="toString on const wchar_t const pointer returns the string contents" time="{duration}"/>
<testcase classname="<exe-name>.global" name="toString on const wchar_t pointer returns the string contents" time="{duration}"/>
<testcase classname="<exe-name>.global" name="toString on wchar_t const pointer returns the string contents" time="{duration}"/>
<testcase classname="<exe-name>.global" name="toString on wchar_t returns the string contents" time="{duration}"/>
<testcase classname="<exe-name>.global" name="toString( vectors&lt;has_maker> )" time="{duration}"/>
<testcase classname="<exe-name>.global" name="toString( vectors&lt;has_maker_and_operator> )" time="{duration}"/>
<testcase classname="<exe-name>.global" name="toString( vectors&lt;has_operator> )" time="{duration}"/>
<testcase classname="<exe-name>.global" name="toString(enum class w/operator&lt;&lt;)" time="{duration}"/>
<testcase classname="<exe-name>.global" name="toString(enum class)" time="{duration}"/>
<testcase classname="<exe-name>.global" name="toString(enum w/operator&lt;&lt;)" time="{duration}"/>

View File

@@ -42,6 +42,60 @@
</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>
t1 == t2
</Original>
<Expanded>
{?} == {?}
</Expanded>
</Expression>
<Expression success="true" type="REQUIRE" filename="projects/<exe-name>/UsageTests/Compilation.tests.cpp" >
<Original>
t1 != t2
</Original>
<Expanded>
{?} != {?}
</Expanded>
</Expression>
<Expression success="true" type="REQUIRE" filename="projects/<exe-name>/UsageTests/Compilation.tests.cpp" >
<Original>
t1 &lt; t2
</Original>
<Expanded>
{?} &lt; {?}
</Expanded>
</Expression>
<Expression success="true" type="REQUIRE" filename="projects/<exe-name>/UsageTests/Compilation.tests.cpp" >
<Original>
t1 > t2
</Original>
<Expanded>
{?} > {?}
</Expanded>
</Expression>
<Expression success="true" type="REQUIRE" filename="projects/<exe-name>/UsageTests/Compilation.tests.cpp" >
<Original>
t1 &lt;= t2
</Original>
<Expanded>
{?} &lt;= {?}
</Expanded>
</Expression>
<Expression success="true" type="REQUIRE" filename="projects/<exe-name>/UsageTests/Compilation.tests.cpp" >
<Original>
t1 >= t2
</Original>
<Expanded>
{?} >= {?}
</Expanded>
</Expression>
<OverallResult success="true"/>
</TestCase>
<TestCase name="#1175 - Hidden Test" tags="[.]" filename="projects/<exe-name>/UsageTests/Misc.tests.cpp" >
<OverallResult success="true"/>
</TestCase>
<TestCase name="#748 - captures with unexpected exceptions" tags="[!shouldfail][!throws][.][failing]" filename="projects/<exe-name>/UsageTests/Exception.tests.cpp" >
<Section name="outside assertions" filename="projects/<exe-name>/UsageTests/Exception.tests.cpp" >
<Info>
@@ -549,7 +603,7 @@
<OverallResult success="true"/>
</TestCase>
<TestCase name="An empty test with no assertions" tags="[empty]" filename="projects/<exe-name>/UsageTests/Misc.tests.cpp" >
<OverallResult success="true"/>
<OverallResult success="false"/>
</TestCase>
<TestCase name="An expression with side-effects should only be evaluated once" tags="[Tricky]" filename="projects/<exe-name>/UsageTests/Tricky.tests.cpp" >
<Expression success="true" type="REQUIRE" filename="projects/<exe-name>/UsageTests/Tricky.tests.cpp" >
@@ -2067,7 +2121,7 @@
</Expression>
<Expression success="true" type="REQUIRE_THAT" filename="projects/<exe-name>/UsageTests/Matchers.tests.cpp" >
<Original>
std::nextafter(1., 2.), WithinULP(1., 1)
nextafter(1., 2.), WithinULP(1., 1)
</Original>
<Expanded>
1.0 is within 1 ULPs of 1.0
@@ -2075,7 +2129,7 @@
</Expression>
<Expression success="true" type="REQUIRE_THAT" filename="projects/<exe-name>/UsageTests/Matchers.tests.cpp" >
<Original>
std::nextafter(1., 0.), WithinULP(1., 1)
nextafter(1., 0.), WithinULP(1., 1)
</Original>
<Expanded>
1.0 is within 1 ULPs of 1.0
@@ -2083,7 +2137,7 @@
</Expression>
<Expression success="true" type="REQUIRE_THAT" filename="projects/<exe-name>/UsageTests/Matchers.tests.cpp" >
<Original>
std::nextafter(1., 2.), !WithinULP(1., 0)
nextafter(1., 2.), !WithinULP(1., 0)
</Original>
<Expanded>
1.0 not is within 0 ULPs of 1.0
@@ -2242,7 +2296,7 @@
</Expression>
<Expression success="true" type="REQUIRE_THAT" filename="projects/<exe-name>/UsageTests/Matchers.tests.cpp" >
<Original>
std::nextafter(1.f, 2.f), WithinULP(1.f, 1)
nextafter(1.f, 2.f), WithinULP(1.f, 1)
</Original>
<Expanded>
1.0f is within 1 ULPs of 1.0f
@@ -2250,7 +2304,7 @@
</Expression>
<Expression success="true" type="REQUIRE_THAT" filename="projects/<exe-name>/UsageTests/Matchers.tests.cpp" >
<Original>
std::nextafter(1.f, 0.f), WithinULP(1.f, 1)
nextafter(1.f, 0.f), WithinULP(1.f, 1)
</Original>
<Expanded>
1.0f is within 1 ULPs of 1.0f
@@ -2258,7 +2312,7 @@
</Expression>
<Expression success="true" type="REQUIRE_THAT" filename="projects/<exe-name>/UsageTests/Matchers.tests.cpp" >
<Original>
std::nextafter(1.f, 2.f), !WithinULP(1.f, 0)
nextafter(1.f, 2.f), !WithinULP(1.f, 0)
</Original>
<Expanded>
1.0f not is within 0 ULPs of 1.0f
@@ -2396,7 +2450,7 @@
<Warning>
this is a warning
</Warning>
<OverallResult success="true"/>
<OverallResult success="false"/>
</TestCase>
<TestCase name="INFO gets logged on failure" tags="[.][failing][messages]" filename="projects/<exe-name>/UsageTests/Message.tests.cpp" >
<Info>
@@ -2906,7 +2960,7 @@
<Warning>
This one ran
</Warning>
<OverallResult success="true"/>
<OverallResult success="false"/>
</TestCase>
<TestCase name="Non-std exceptions can be translated" tags="[!throws][.][failing]" filename="projects/<exe-name>/UsageTests/Exception.tests.cpp" >
<Exception filename="projects/<exe-name>/UsageTests/Exception.tests.cpp" >
@@ -4573,7 +4627,15 @@
true
</Expanded>
</Expression>
<OverallResults successes="6" failures="0" expectedFailures="0"/>
<Expression success="true" type="CHECK_FALSE" filename="projects/<exe-name>/IntrospectiveTests/CmdLine.tests.cpp" >
<Original>
!(cfg.hasTestFilters())
</Original>
<Expanded>
!false
</Expanded>
</Expression>
<OverallResults successes="7" failures="0" expectedFailures="0"/>
</Section>
<Section name="test lists" filename="projects/<exe-name>/IntrospectiveTests/CmdLine.tests.cpp" >
<Section name="1 test" description="Specify one test case using" filename="projects/<exe-name>/IntrospectiveTests/CmdLine.tests.cpp" >
@@ -4585,6 +4647,14 @@
{?}
</Expanded>
</Expression>
<Expression success="true" type="REQUIRE" filename="projects/<exe-name>/IntrospectiveTests/CmdLine.tests.cpp" >
<Original>
cfg.hasTestFilters()
</Original>
<Expanded>
true
</Expanded>
</Expression>
<Expression success="true" type="REQUIRE" filename="projects/<exe-name>/IntrospectiveTests/CmdLine.tests.cpp" >
<Original>
cfg.testSpec().matches(fakeTestCase("notIncluded")) == false
@@ -4601,9 +4671,9 @@
true
</Expanded>
</Expression>
<OverallResults successes="3" failures="0" expectedFailures="0"/>
<OverallResults successes="4" failures="0" expectedFailures="0"/>
</Section>
<OverallResults successes="3" failures="0" expectedFailures="0"/>
<OverallResults successes="4" failures="0" expectedFailures="0"/>
</Section>
<Section name="test lists" filename="projects/<exe-name>/IntrospectiveTests/CmdLine.tests.cpp" >
<Section name="Specify one test case exclusion using exclude:" filename="projects/<exe-name>/IntrospectiveTests/CmdLine.tests.cpp" >
@@ -4615,6 +4685,14 @@
{?}
</Expanded>
</Expression>
<Expression success="true" type="REQUIRE" filename="projects/<exe-name>/IntrospectiveTests/CmdLine.tests.cpp" >
<Original>
cfg.hasTestFilters()
</Original>
<Expanded>
true
</Expanded>
</Expression>
<Expression success="true" type="REQUIRE" filename="projects/<exe-name>/IntrospectiveTests/CmdLine.tests.cpp" >
<Original>
cfg.testSpec().matches(fakeTestCase("test1")) == false
@@ -4631,9 +4709,9 @@
true
</Expanded>
</Expression>
<OverallResults successes="3" failures="0" expectedFailures="0"/>
<OverallResults successes="4" failures="0" expectedFailures="0"/>
</Section>
<OverallResults successes="3" failures="0" expectedFailures="0"/>
<OverallResults successes="4" failures="0" expectedFailures="0"/>
</Section>
<Section name="test lists" filename="projects/<exe-name>/IntrospectiveTests/CmdLine.tests.cpp" >
<Section name="Specify one test case exclusion using ~" filename="projects/<exe-name>/IntrospectiveTests/CmdLine.tests.cpp" >
@@ -4645,6 +4723,14 @@
{?}
</Expanded>
</Expression>
<Expression success="true" type="REQUIRE" filename="projects/<exe-name>/IntrospectiveTests/CmdLine.tests.cpp" >
<Original>
cfg.hasTestFilters()
</Original>
<Expanded>
true
</Expanded>
</Expression>
<Expression success="true" type="REQUIRE" filename="projects/<exe-name>/IntrospectiveTests/CmdLine.tests.cpp" >
<Original>
cfg.testSpec().matches(fakeTestCase("test1")) == false
@@ -4661,9 +4747,9 @@
true
</Expanded>
</Expression>
<OverallResults successes="3" failures="0" expectedFailures="0"/>
<OverallResults successes="4" failures="0" expectedFailures="0"/>
</Section>
<OverallResults successes="3" failures="0" expectedFailures="0"/>
<OverallResults successes="4" failures="0" expectedFailures="0"/>
</Section>
<Section name="reporter" filename="projects/<exe-name>/IntrospectiveTests/CmdLine.tests.cpp" >
<Section name="-r/console" filename="projects/<exe-name>/IntrospectiveTests/CmdLine.tests.cpp" >
@@ -5324,7 +5410,7 @@
<OverallResult success="true"/>
</TestCase>
<TestCase name="Sends stuff to stdout and stderr" tags="[.]" filename="projects/<exe-name>/UsageTests/Misc.tests.cpp" >
<OverallResult success="true">
<OverallResult success="false">
<StdOut>
A string sent directly to stdout
</StdOut>
@@ -5426,6 +5512,44 @@ Message from section two
</Expression>
<OverallResult success="false"/>
</TestCase>
<TestCase name="Static arrays are convertible to string" tags="[toString]" filename="projects/<exe-name>/UsageTests/ToStringGeneral.tests.cpp" >
<Section name="Single item" filename="projects/<exe-name>/UsageTests/ToStringGeneral.tests.cpp" >
<Expression success="true" type="REQUIRE" filename="projects/<exe-name>/UsageTests/ToStringGeneral.tests.cpp" >
<Original>
Catch::Detail::stringify(singular) == "{ 1 }"
</Original>
<Expanded>
"{ 1 }" == "{ 1 }"
</Expanded>
</Expression>
<OverallResults successes="1" failures="0" expectedFailures="0"/>
</Section>
<Section name="Multiple" filename="projects/<exe-name>/UsageTests/ToStringGeneral.tests.cpp" >
<Expression success="true" type="REQUIRE" filename="projects/<exe-name>/UsageTests/ToStringGeneral.tests.cpp" >
<Original>
Catch::Detail::stringify(arr) == "{ 3, 2, 1 }"
</Original>
<Expanded>
"{ 3, 2, 1 }" == "{ 3, 2, 1 }"
</Expanded>
</Expression>
<OverallResults successes="1" failures="0" expectedFailures="0"/>
</Section>
<Section name="Non-trivial inner items" filename="projects/<exe-name>/UsageTests/ToStringGeneral.tests.cpp" >
<Expression success="true" type="REQUIRE" filename="projects/<exe-name>/UsageTests/ToStringGeneral.tests.cpp" >
<Original>
Catch::Detail::stringify(arr) == R"({ { "1:1", "1:2", "1:3" }, { "2:1", "2:2" } })"
</Original>
<Expanded>
"{ { "1:1", "1:2", "1:3" }, { "2:1", "2:2" } }"
==
"{ { "1:1", "1:2", "1:3" }, { "2:1", "2:2" } }"
</Expanded>
</Expression>
<OverallResults successes="1" failures="0" expectedFailures="0"/>
</Section>
<OverallResult success="true"/>
</TestCase>
<TestCase name="String matchers" tags="[matchers]" filename="projects/<exe-name>/UsageTests/Matchers.tests.cpp" >
<Expression success="true" type="REQUIRE_THAT" filename="projects/<exe-name>/UsageTests/Matchers.tests.cpp" >
<Original>
@@ -5493,7 +5617,7 @@ Message from section two
</Expression>
<OverallResult success="true"/>
</TestCase>
<TestCase name="StringRef" tags="[Strings]" filename="projects/<exe-name>/IntrospectiveTests/String.tests.cpp" >
<TestCase name="StringRef" tags="[StringRef][Strings]" filename="projects/<exe-name>/IntrospectiveTests/String.tests.cpp" >
<Section name="Empty string" filename="projects/<exe-name>/IntrospectiveTests/String.tests.cpp" >
<Expression success="true" type="REQUIRE" filename="projects/<exe-name>/IntrospectiveTests/String.tests.cpp" >
<Original>
@@ -5592,15 +5716,39 @@ Message from section two
original == "original"
</Expanded>
</Expression>
<Expression success="false" type="REQUIRE" filename="projects/<exe-name>/IntrospectiveTests/String.tests.cpp" >
<Expression success="true" type="REQUIRE" filename="projects/<exe-name>/IntrospectiveTests/String.tests.cpp" >
<Original>
isSubstring( original )
</Original>
<Expanded>
false
true
</Expanded>
</Expression>
<OverallResults successes="1" failures="1" expectedFailures="0"/>
<Expression success="true" type="REQUIRE" filename="projects/<exe-name>/IntrospectiveTests/String.tests.cpp" >
<Original>
isOwned( original ) == false
</Original>
<Expanded>
false == false
</Expanded>
</Expression>
<Expression success="true" type="REQUIRE" filename="projects/<exe-name>/IntrospectiveTests/String.tests.cpp" >
<Original>
isSubstring( original ) == false
</Original>
<Expanded>
false == false
</Expanded>
</Expression>
<Expression success="true" type="REQUIRE" filename="projects/<exe-name>/IntrospectiveTests/String.tests.cpp" >
<Original>
isOwned( original )
</Original>
<Expanded>
true
</Expanded>
</Expression>
<OverallResults successes="5" 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" >
@@ -5660,7 +5808,7 @@ Message from section two
</Expression>
<Expression success="true" type="REQUIRE" filename="projects/<exe-name>/IntrospectiveTests/String.tests.cpp" >
<Original>
rawChars == data( s )
rawChars == s.currentData()
</Original>
<Expanded>
"hello world!" == "hello world!"
@@ -5692,7 +5840,7 @@ Message from section two
</Expression>
<Expression success="true" type="REQUIRE" filename="projects/<exe-name>/IntrospectiveTests/String.tests.cpp" >
<Original>
data( ss ) != data( s )
ss.currentData() != s.currentData()
</Original>
<Expanded>
"hello" != "hello world!"
@@ -5903,7 +6051,34 @@ Message from section two
</Section>
<OverallResults successes="2" failures="0" expectedFailures="0"/>
</Section>
<OverallResult success="false"/>
<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"/>
</Section>
<OverallResult success="true"/>
</TestCase>
<TestCase name="Stringifying std::chrono::duration helpers" tags="[chrono][toString]" filename="projects/<exe-name>/UsageTests/ToStringChrono.tests.cpp" >
<Expression success="true" type="REQUIRE" filename="projects/<exe-name>/UsageTests/ToStringChrono.tests.cpp" >
@@ -6094,11 +6269,17 @@ Message from section two
1 == 2
</Expanded>
</Expression>
<OverallResult success="true"/>
<OverallResult success="false"/>
</TestCase>
<TestCase name="This test 'should' fail but doesn't" tags="[!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" >
<Exception filename="projects/<exe-name>/UsageTests/Exception.tests.cpp" >
For some reason someone is throwing a string literal!
</Exception>
<OverallResult success="false"/>
</TestCase>
<TestCase name="Tracker" filename="projects/<exe-name>/IntrospectiveTests/PartTracker.tests.cpp" >
<Expression success="true" type="REQUIRE" filename="projects/<exe-name>/IntrospectiveTests/PartTracker.tests.cpp" >
<Original>
@@ -7610,19 +7791,19 @@ Message from section two
<OverallResult success="false"/>
</TestCase>
<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="true"/>
<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" >
<Warning>
Uncomment the code in this test to check that it gives a sensible compiler error
</Warning>
<OverallResult success="true"/>
<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" >
<Warning>
Uncomment the code in this test to check that it gives a sensible compiler error
</Warning>
<OverallResult success="true"/>
<OverallResult success="false"/>
</TestCase>
<TestCase name="X/level/0/a" tags="[Tricky]" filename="projects/<exe-name>/UsageTests/Tricky.tests.cpp" >
<OverallResult success="true"/>
@@ -7963,11 +8144,11 @@ Message from section two
<OverallResult success="true"/>
</TestCase>
<TestCase name="first tag" tags="[tag1]" filename="projects/<exe-name>/UsageTests/Misc.tests.cpp" >
<OverallResult success="true"/>
<OverallResult success="false"/>
</TestCase>
<TestCase name="has printf" filename="projects/<exe-name>/UsageTests/Tricky.tests.cpp" >
loose text artifact
<OverallResult success="true"/>
<OverallResult success="false"/>
</TestCase>
<TestCase name="just failure" tags="[.][fail][isolated info][messages]" filename="projects/<exe-name>/UsageTests/Message.tests.cpp" >
<Failure filename="projects/<exe-name>/UsageTests/Message.tests.cpp" >
@@ -7976,7 +8157,7 @@ loose text artifact
<OverallResult success="false"/>
</TestCase>
<TestCase name="just info" tags="[info][isolated info][messages]" filename="projects/<exe-name>/UsageTests/Message.tests.cpp" >
<OverallResult success="true"/>
<OverallResult success="false"/>
</TestCase>
<TestCase name="long long" filename="projects/<exe-name>/UsageTests/Misc.tests.cpp" >
<Expression success="true" type="REQUIRE" filename="projects/<exe-name>/UsageTests/Misc.tests.cpp" >
@@ -8286,7 +8467,7 @@ loose text artifact
</Section>
<OverallResult success="true"/>
</TestCase>
<TestCase name="replaceInPlace" filename="projects/<exe-name>/IntrospectiveTests/String.tests.cpp" >
<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" >
<Original>
@@ -8423,7 +8604,7 @@ loose text artifact
<OverallResult success="true"/>
</TestCase>
<TestCase name="second tag" tags="[tag2]" filename="projects/<exe-name>/UsageTests/Misc.tests.cpp" >
<OverallResult success="true"/>
<OverallResult success="false"/>
</TestCase>
<TestCase name="send a single char to INFO" tags="[.][failing]" filename="projects/<exe-name>/UsageTests/Misc.tests.cpp" >
<Info>
@@ -8578,6 +8759,45 @@ loose text artifact
</Expression>
<OverallResult success="false"/>
</TestCase>
<TestCase name="stringify ranges" tags="[toString]" filename="projects/<exe-name>/UsageTests/ToStringWhich.tests.cpp" >
<Expression success="true" type="REQUIRE" filename="projects/<exe-name>/UsageTests/ToStringWhich.tests.cpp" >
<Original>
::Catch::Detail::stringify(streamable_range{}) == "op&lt;&lt;(streamable_range)"
</Original>
<Expanded>
"op&lt;&lt;(streamable_range)"
==
"op&lt;&lt;(streamable_range)"
</Expanded>
</Expression>
<Expression success="true" type="REQUIRE" filename="projects/<exe-name>/UsageTests/ToStringWhich.tests.cpp" >
<Original>
::Catch::Detail::stringify(stringmaker_range{}) == "stringmaker(streamable_range)"
</Original>
<Expanded>
"stringmaker(streamable_range)"
==
"stringmaker(streamable_range)"
</Expanded>
</Expression>
<Expression success="true" type="REQUIRE" filename="projects/<exe-name>/UsageTests/ToStringWhich.tests.cpp" >
<Original>
::Catch::Detail::stringify(just_range{}) == "{ 1, 2, 3, 4 }"
</Original>
<Expanded>
"{ 1, 2, 3, 4 }" == "{ 1, 2, 3, 4 }"
</Expanded>
</Expression>
<Expression success="true" type="REQUIRE" filename="projects/<exe-name>/UsageTests/ToStringWhich.tests.cpp" >
<Original>
::Catch::Detail::stringify(disabled_range{}) == "{ !!! }"
</Original>
<Expanded>
"{ !!! }" == "{ !!! }"
</Expanded>
</Expression>
<OverallResult success="true"/>
</TestCase>
<TestCase name="stringify( has_maker )" tags="[toString]" filename="projects/<exe-name>/UsageTests/ToStringWhich.tests.cpp" >
<Expression success="true" type="REQUIRE" filename="projects/<exe-name>/UsageTests/ToStringWhich.tests.cpp" >
<Original>
@@ -8591,7 +8811,7 @@ loose text artifact
</Expression>
<OverallResult success="true"/>
</TestCase>
<TestCase name="stringify( has_maker_and_toString )" tags="[.][toString]" filename="projects/<exe-name>/UsageTests/ToStringWhich.tests.cpp" >
<TestCase name="stringify( has_maker_and_operator )" tags="[toString]" filename="projects/<exe-name>/UsageTests/ToStringWhich.tests.cpp" >
<Expression success="true" type="REQUIRE" filename="projects/<exe-name>/UsageTests/ToStringWhich.tests.cpp" >
<Original>
::Catch::Detail::stringify( item ) == "StringMaker&lt;has_maker_and_operator>"
@@ -8604,6 +8824,17 @@ loose text artifact
</Expression>
<OverallResult success="true"/>
</TestCase>
<TestCase name="stringify( has_neither )" tags="[toString]" filename="projects/<exe-name>/UsageTests/ToStringWhich.tests.cpp" >
<Expression success="true" type="REQUIRE" filename="projects/<exe-name>/UsageTests/ToStringWhich.tests.cpp" >
<Original>
::Catch::Detail::stringify(item) == "{ !!! }"
</Original>
<Expanded>
"{ !!! }" == "{ !!! }"
</Expanded>
</Expression>
<OverallResult success="true"/>
</TestCase>
<TestCase name="stringify( has_operator )" tags="[toString]" filename="projects/<exe-name>/UsageTests/ToStringWhich.tests.cpp" >
<Expression success="true" type="REQUIRE" filename="projects/<exe-name>/UsageTests/ToStringWhich.tests.cpp" >
<Original>
@@ -8617,6 +8848,51 @@ loose text artifact
</Expression>
<OverallResult success="true"/>
</TestCase>
<TestCase name="stringify( vectors&lt;has_maker> )" tags="[toString]" filename="projects/<exe-name>/UsageTests/ToStringWhich.tests.cpp" >
<Expression success="true" type="REQUIRE" filename="projects/<exe-name>/UsageTests/ToStringWhich.tests.cpp" >
<Original>
::Catch::Detail::stringify( v ) == "{ StringMaker&lt;has_maker> }"
</Original>
<Expanded>
"{ StringMaker&lt;has_maker> }"
==
"{ StringMaker&lt;has_maker> }"
</Expanded>
</Expression>
<OverallResult success="true"/>
</TestCase>
<TestCase name="stringify( vectors&lt;has_maker_and_operator> )" tags="[toString]" filename="projects/<exe-name>/UsageTests/ToStringWhich.tests.cpp" >
<Expression success="true" type="REQUIRE" filename="projects/<exe-name>/UsageTests/ToStringWhich.tests.cpp" >
<Original>
::Catch::Detail::stringify( v ) == "{ StringMaker&lt;has_maker_and_operator> }"
</Original>
<Expanded>
"{ StringMaker&lt;has_maker_and_operator> }"
==
"{ StringMaker&lt;has_maker_and_operator> }"
</Expanded>
</Expression>
<OverallResult success="true"/>
</TestCase>
<TestCase name="stringify( vectors&lt;has_operator> )" tags="[toString]" filename="projects/<exe-name>/UsageTests/ToStringWhich.tests.cpp" >
<Expression success="true" type="REQUIRE" filename="projects/<exe-name>/UsageTests/ToStringWhich.tests.cpp" >
<Original>
::Catch::Detail::stringify( v ) == "{ operator&lt;&lt;( has_operator ) }"
</Original>
<Expanded>
"{ operator&lt;&lt;( has_operator ) }"
==
"{ operator&lt;&lt;( has_operator ) }"
</Expanded>
</Expression>
<OverallResult success="true"/>
</TestCase>
<TestCase name="thrown std::strings are translated" tags="[!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>
<OverallResult success="false"/>
</TestCase>
<TestCase name="toString on const wchar_t const pointer returns the string contents" tags="[toString]" filename="projects/<exe-name>/UsageTests/Misc.tests.cpp" >
<Expression success="true" type="CHECK" filename="projects/<exe-name>/UsageTests/Misc.tests.cpp" >
<Original>
@@ -8661,45 +8937,6 @@ loose text artifact
</Expression>
<OverallResult success="true"/>
</TestCase>
<TestCase name="toString( vectors&lt;has_maker> )" tags="[toString]" filename="projects/<exe-name>/UsageTests/ToStringWhich.tests.cpp" >
<Expression success="true" type="REQUIRE" filename="projects/<exe-name>/UsageTests/ToStringWhich.tests.cpp" >
<Original>
::Catch::Detail::stringify( v ) == "{ StringMaker&lt;has_maker> }"
</Original>
<Expanded>
"{ StringMaker&lt;has_maker> }"
==
"{ StringMaker&lt;has_maker> }"
</Expanded>
</Expression>
<OverallResult success="true"/>
</TestCase>
<TestCase name="toString( vectors&lt;has_maker_and_operator> )" tags="[toString]" filename="projects/<exe-name>/UsageTests/ToStringWhich.tests.cpp" >
<Expression success="true" type="REQUIRE" filename="projects/<exe-name>/UsageTests/ToStringWhich.tests.cpp" >
<Original>
::Catch::Detail::stringify( v ) == "{ StringMaker&lt;has_maker_and_operator> }"
</Original>
<Expanded>
"{ StringMaker&lt;has_maker_and_operator> }"
==
"{ StringMaker&lt;has_maker_and_operator> }"
</Expanded>
</Expression>
<OverallResult success="true"/>
</TestCase>
<TestCase name="toString( vectors&lt;has_operator> )" tags="[toString]" filename="projects/<exe-name>/UsageTests/ToStringWhich.tests.cpp" >
<Expression success="true" type="REQUIRE" filename="projects/<exe-name>/UsageTests/ToStringWhich.tests.cpp" >
<Original>
::Catch::Detail::stringify( v ) == "{ operator&lt;&lt;( has_operator ) }"
</Original>
<Expanded>
"{ operator&lt;&lt;( has_operator ) }"
==
"{ operator&lt;&lt;( has_operator ) }"
</Expanded>
</Expression>
<OverallResult success="true"/>
</TestCase>
<TestCase name="toString(enum class w/operator&lt;&lt;)" tags="[enum][enumClass][toString]" filename="projects/<exe-name>/UsageTests/EnumToString.tests.cpp" >
<Expression success="true" type="CHECK" filename="projects/<exe-name>/UsageTests/EnumToString.tests.cpp" >
<Original>
@@ -9168,7 +9405,7 @@ loose text artifact
</Section>
<OverallResult success="true"/>
</TestCase>
<OverallResults successes="853" failures="109" expectedFailures="21"/>
<OverallResults successes="879" failures="122" expectedFailures="21"/>
</Group>
<OverallResults successes="853" failures="108" expectedFailures="21"/>
<OverallResults successes="879" failures="121" expectedFailures="21"/>
</Catch>

View File

@@ -15,7 +15,7 @@
# pragma clang diagnostic ignored "-Wc++98-compat"
#endif
inline Catch::TestCase fakeTestCase( const char* name, const char* desc = "" ){ return Catch::makeTestCase( nullptr, "", name, desc, CATCH_INTERNAL_LINEINFO ); }
inline Catch::TestCase fakeTestCase(const char* name, const char* desc = "") { return Catch::makeTestCase(nullptr, "", { name, desc }, CATCH_INTERNAL_LINEINFO); }
TEST_CASE( "Parse test names and tags" ) {
@@ -289,6 +289,9 @@ TEST_CASE( "Process can be configured on command line", "[config][command-line]"
CHECK(config.abortAfter == -1);
CHECK(config.noThrow == false);
CHECK(config.reporterNames.empty());
Catch::Config cfg(config);
CHECK_FALSE(cfg.hasTestFilters());
}
SECTION("test lists") {
@@ -297,6 +300,7 @@ TEST_CASE( "Process can be configured on command line", "[config][command-line]"
CHECK(result);
Catch::Config cfg(config);
REQUIRE(cfg.hasTestFilters());
REQUIRE(cfg.testSpec().matches(fakeTestCase("notIncluded")) == false);
REQUIRE(cfg.testSpec().matches(fakeTestCase("test1")));
}
@@ -305,6 +309,7 @@ TEST_CASE( "Process can be configured on command line", "[config][command-line]"
CHECK(result);
Catch::Config cfg(config);
REQUIRE(cfg.hasTestFilters());
REQUIRE(cfg.testSpec().matches(fakeTestCase("test1")) == false);
REQUIRE(cfg.testSpec().matches(fakeTestCase("alwaysIncluded")));
}
@@ -314,6 +319,7 @@ TEST_CASE( "Process can be configured on command line", "[config][command-line]"
CHECK(result);
Catch::Config cfg(config);
REQUIRE(cfg.hasTestFilters());
REQUIRE(cfg.testSpec().matches(fakeTestCase("test1")) == false);
REQUIRE(cfg.testSpec().matches(fakeTestCase("alwaysIncluded")));
}

View File

@@ -14,9 +14,6 @@ namespace Catch {
static auto isSubstring( StringRef const& stringRef ) -> bool {
return stringRef.isSubstring();
}
static auto data( StringRef const& stringRef ) -> char const* {
return stringRef.data();
}
};
auto isOwned( StringRef const& stringRef ) -> bool {
@@ -25,19 +22,16 @@ namespace Catch {
auto isSubstring( StringRef const& stringRef ) -> bool {
return StringRefTestAccess::isSubstring( stringRef );
}
auto data( StringRef const& stringRef ) -> char const* {
return StringRefTestAccess::data( stringRef );
}
} // namespace Catch2
namespace Catch {
inline auto toString( Catch::StringRef const& stringRef ) -> std::string {
return std::string( data( stringRef ), stringRef.size() );
return std::string( stringRef.currentData(), stringRef.size() );
}
} // namespace Catch
TEST_CASE( "StringRef", "[Strings]" ) {
TEST_CASE( "StringRef", "[Strings][StringRef]" ) {
using Catch::StringRef;
SECTION( "Empty string" ) {
@@ -46,21 +40,21 @@ TEST_CASE( "StringRef", "[Strings]" ) {
REQUIRE( empty.size() == 0 );
REQUIRE( std::strcmp( empty.c_str(), "" ) == 0 );
}
SECTION( "From string literal" ) {
StringRef s = "hello";
REQUIRE( s.empty() == false );
REQUIRE( s.size() == 5 );
REQUIRE( isSubstring( s ) == false );
auto rawChars = data( s );
auto rawChars = s.currentData();
REQUIRE( std::strcmp( rawChars, "hello" ) == 0 );
SECTION( "c_str() does not cause copy" ) {
REQUIRE( isOwned( s ) == false );
REQUIRE( s.c_str() == rawChars );
REQUIRE( isOwned( s ) == false );
}
}
@@ -69,19 +63,18 @@ TEST_CASE( "StringRef", "[Strings]" ) {
REQUIRE( original == "original" );
REQUIRE( isSubstring( original ) );
REQUIRE( isOwned( original ) == false );
original.c_str(); // Forces it to take ownership
REQUIRE( isSubstring( original ) == false );
REQUIRE( isOwned( original ) );
}
SECTION( "Substrings" ) {
StringRef s = "hello world!";
StringRef ss = s.substr(0, 5);
SECTION( "zero-based substring" ) {
REQUIRE( ss.empty() == false );
REQUIRE( ss.size() == 5 );
@@ -91,33 +84,33 @@ TEST_CASE( "StringRef", "[Strings]" ) {
SECTION( "c_str() causes copy" ) {
REQUIRE( isSubstring( ss ) );
REQUIRE( isOwned( ss ) == false );
auto rawChars = data( ss );
REQUIRE( rawChars == data( s ) ); // same pointer value
auto rawChars = ss.currentData();
REQUIRE( rawChars == s.currentData() ); // same pointer value
REQUIRE( ss.c_str() != rawChars );
REQUIRE( isSubstring( ss ) == false );
REQUIRE( isOwned( ss ) );
REQUIRE( data( ss ) != data( s ) ); // different pointer value
REQUIRE( ss.currentData() != s.currentData() ); // different pointer value
}
SECTION( "non-zero-based substring") {
ss = s.substr( 6, 6 );
REQUIRE( ss.size() == 6 );
REQUIRE( std::strcmp( ss.c_str(), "world!" ) == 0 );
}
SECTION( "Pointer values of full refs should match" ) {
StringRef s2 = s;
REQUIRE( s.c_str() == s2.c_str() );
}
SECTION( "Pointer values of substring refs should not match" ) {
REQUIRE( s.c_str() != ss.c_str() );
}
}
SECTION( "Comparisons" ) {
REQUIRE( StringRef("hello") == StringRef("hello") );
REQUIRE( StringRef("hello") != StringRef("cello") );
@@ -164,9 +157,21 @@ TEST_CASE( "StringRef", "[Strings]" ) {
REQUIRE( stdStr.size() == sr.size() );
}
}
SECTION( "Counting utf-8 codepoints" ) {
StringRef ascii = "just a plain old boring ascii string...";
REQUIRE(ascii.numberOfCharacters() == ascii.size());
StringRef simpleu8 = u8"Trocha češtiny nikoho nezabila";
REQUIRE(simpleu8.numberOfCharacters() == 30);
StringRef emojis = u8"Here be 👾";
REQUIRE(emojis.numberOfCharacters() == 9);
}
}
TEST_CASE( "replaceInPlace" ) {
TEST_CASE( "replaceInPlace", "[Strings][StringManip]" ) {
std::string letters = "abcdefcg";
SECTION( "replace single char" ) {
CHECK( Catch::replaceInPlace( letters, "b", "z" ) );

View File

@@ -29,5 +29,5 @@ CATCH_REGISTER_TAG_ALIAS( "[@tricky]", "[tricky]~[.]" )
struct TestListener : Catch::TestEventListenerBase {
using TestEventListenerBase::TestEventListenerBase; // inherit constructor
};
CATCH_REGISTER_LISTENER( TestListener );
CATCH_REGISTER_LISTENER( TestListener )

View File

@@ -12,6 +12,19 @@ namespace { namespace CompilationTests {
#ifndef COMPILATION_TEST_HELPERS_INCLUDED // Don't compile this more than once per TU
#define COMPILATION_TEST_HELPERS_INCLUDED
// Comparison operators can return non-booleans.
// This is unusual, but should be supported.
struct logic_t {
logic_t operator< (logic_t) const { return {}; }
logic_t operator<=(logic_t) const { return {}; }
logic_t operator> (logic_t) const { return {}; }
logic_t operator>=(logic_t) const { return {}; }
logic_t operator==(logic_t) const { return {}; }
logic_t operator!=(logic_t) const { return {}; }
explicit operator bool() const { return true; }
};
// This is a minimal example for an issue we have found in 1.7.0
struct foo {
int i;
@@ -109,4 +122,16 @@ namespace { namespace CompilationTests {
REQUIRE(0 == y.v);
}
// Comparison operators can return non-booleans.
// This is unusual, but should be supported.
TEST_CASE("#1147") {
logic_t t1, t2;
REQUIRE(t1 == t2);
REQUIRE(t1 != t2);
REQUIRE(t1 < t2);
REQUIRE(t1 > t2);
REQUIRE(t1 <= t2);
REQUIRE(t1 >= t2);
}
}} // namespace CompilationTests

View File

@@ -12,7 +12,7 @@
#include <stdexcept>
#ifdef _MSC_VER
#pragma warning(disable:4702) // Unreachable code -- uncoditional throws and so on
#pragma warning(disable:4702) // Unreachable code -- unconditional throws and so on
#endif
#ifdef __clang__
#pragma clang diagnostic push
@@ -154,6 +154,15 @@ TEST_CASE( "Unexpected exceptions can be translated", "[.][failing][!throws]" )
throw double( 3.14 );
}
TEST_CASE("Thrown string literals are translated", "[.][failing][!throws]") {
throw "For some reason someone is throwing a string literal!";
}
TEST_CASE("thrown std::strings are translated", "[.][failing][!throws]") {
throw std::string{ "Why would you throw a std::string?" };
}
#ifndef CATCH_CONFIG_DISABLE_MATCHERS
TEST_CASE( "Exception messages can be tested for", "[!throws]" ) {

View File

@@ -77,6 +77,20 @@ namespace { namespace MatchersTests {
using namespace Catch::Matchers;
#ifdef __DJGPP__
float nextafter(float from, float to)
{
return ::nextafterf(from, to);
}
double nextafter(double from, double to)
{
return ::nextafter(from, to);
}
#else
using std::nextafter;
#endif
TEST_CASE("String matchers", "[matchers]") {
REQUIRE_THAT(testStringForMatching(), Contains("string"));
REQUIRE_THAT(testStringForMatching(), Contains("string", Catch::CaseSensitive::No));
@@ -130,12 +144,16 @@ namespace { namespace MatchersTests {
(defined(_GLIBCXX_RELEASE) && \
_GLIBCXX_RELEASE > 4))))
// DJGPP meets the above condition but <regex> does not work properly anyway
#ifndef __DJGPP__
REQUIRE_THAT(testStringForMatching(), Matches("this string contains 'abc' as a substring"));
REQUIRE_THAT(testStringForMatching(),
Matches("this string CONTAINS 'abc' as a substring", Catch::CaseSensitive::No));
REQUIRE_THAT(testStringForMatching(), Matches("^this string contains 'abc' as a substring$"));
REQUIRE_THAT(testStringForMatching(), Matches("^.* 'abc' .*$"));
REQUIRE_THAT(testStringForMatching(), Matches("^.* 'ABC' .*$", Catch::CaseSensitive::No));
#endif
#endif
REQUIRE_THAT(testStringForMatching2(), !Matches("this string contains 'abc' as a substring"));
@@ -307,9 +325,9 @@ namespace { namespace MatchersTests {
SECTION("ULPs") {
REQUIRE_THAT(1.f, WithinULP(1.f, 0));
REQUIRE_THAT(std::nextafter(1.f, 2.f), WithinULP(1.f, 1));
REQUIRE_THAT(std::nextafter(1.f, 0.f), WithinULP(1.f, 1));
REQUIRE_THAT(std::nextafter(1.f, 2.f), !WithinULP(1.f, 0));
REQUIRE_THAT(nextafter(1.f, 2.f), WithinULP(1.f, 1));
REQUIRE_THAT(nextafter(1.f, 0.f), WithinULP(1.f, 1));
REQUIRE_THAT(nextafter(1.f, 2.f), !WithinULP(1.f, 0));
REQUIRE_THAT(1.f, WithinULP(1.f, 0));
REQUIRE_THAT(-0.f, WithinULP(0.f, 0));
@@ -344,9 +362,9 @@ namespace { namespace MatchersTests {
SECTION("ULPs") {
REQUIRE_THAT(1., WithinULP(1., 0));
REQUIRE_THAT(std::nextafter(1., 2.), WithinULP(1., 1));
REQUIRE_THAT(std::nextafter(1., 0.), WithinULP(1., 1));
REQUIRE_THAT(std::nextafter(1., 2.), !WithinULP(1., 0));
REQUIRE_THAT(nextafter(1., 2.), WithinULP(1., 1));
REQUIRE_THAT(nextafter(1., 0.), WithinULP(1., 1));
REQUIRE_THAT(nextafter(1., 2.), !WithinULP(1., 0));
REQUIRE_THAT(1., WithinULP(1., 0));
REQUIRE_THAT(-0., WithinULP(0., 0));

View File

@@ -290,6 +290,7 @@ TEST_CASE( "Tabs and newlines show in output", "[.][whitespace][failing]" ) {
}
#ifdef CATCH_CONFIG_WCHAR
TEST_CASE( "toString on const wchar_t const pointer returns the string contents", "[toString]" ) {
const wchar_t * const s = L"wide load";
std::string result = ::Catch::Detail::stringify( s );
@@ -313,6 +314,7 @@ TEST_CASE( "toString on wchar_t returns the string contents", "[toString]" ) {
std::string result = ::Catch::Detail::stringify( s );
CHECK( result == "\"wide load\"" );
}
#endif
TEST_CASE( "long long" ) {
long long l = std::numeric_limits<long long>::max();
@@ -348,4 +350,9 @@ TEST_CASE( "#961 -- Dynamically created sections should all be reported", "[.]"
}
}
TEST_CASE( "#1175 - Hidden Test", "[.]" ) {
// Just for checking that hidden test is not listed by default
SUCCEED();
}
}} // namespace MiscTests

View File

@@ -100,3 +100,18 @@ TEST_CASE( "std::set is convertible string", "[toString]" ) {
REQUIRE( Catch::Detail::stringify( set ) == "{ \"abc\", \"def\", \"ghi\" }" );
}
}
TEST_CASE("Static arrays are convertible to string", "[toString]") {
SECTION("Single item") {
int singular[1] = { 1 };
REQUIRE(Catch::Detail::stringify(singular) == "{ 1 }");
}
SECTION("Multiple") {
int arr[3] = { 3, 2, 1 };
REQUIRE(Catch::Detail::stringify(arr) == "{ 3, 2, 1 }");
}
SECTION("Non-trivial inner items") {
std::vector<std::string> arr[2] = { {"1:1", "1:2", "1:3"}, {"2:1", "2:2"} };
REQUIRE(Catch::Detail::stringify(arr) == R"({ { "1:1", "1:2", "1:3" }, { "2:1", "2:2" } })");
}
}

View File

@@ -2,7 +2,7 @@
#include <vector>
#include <array>
// vedctor
// vector
TEST_CASE( "vector<int> -> toString", "[toString][vector]" )
{
std::vector<int> vv;

View File

@@ -1,13 +1,25 @@
#include "catch.hpp"
/*
Demonstrate which version of toString/StringMaker is being used
for various types
*/
* Demonstrate which version of toString/StringMaker is being used
* for various types
*/
// Replace fallback stringifier for this TU
// We should avoid ODR violations because these specific types aren't
// present in different TUs
#include <string>
template <typename T>
std::string fallbackStringifier(T const&) {
return "{ !!! }";
}
#define CATCH_CONFIG_FALLBACK_STRINGIFIER fallbackStringifier
#include "catch.hpp"
struct has_operator { };
struct has_maker {};
struct has_maker_and_operator {};
struct has_neither {};
std::ostream& operator<<(std::ostream& os, const has_operator&) {
os << "operator<<( has_operator )";
@@ -47,27 +59,102 @@ TEST_CASE( "stringify( has_maker )", "[toString]" ) {
}
// Call the stringmaker
TEST_CASE( "stringify( has_maker_and_toString )", "[.][toString]" ) {
TEST_CASE( "stringify( has_maker_and_operator )", "[toString]" ) {
has_maker_and_operator item;
REQUIRE( ::Catch::Detail::stringify( item ) == "StringMaker<has_maker_and_operator>" );
}
TEST_CASE("stringify( has_neither )", "[toString]") {
has_neither item;
REQUIRE( ::Catch::Detail::stringify(item) == "{ !!! }" );
}
// Vectors...
// Don't run this in approval tests as it is sensitive to two phase lookup differences
TEST_CASE( "toString( vectors<has_operator> )", "[toString]" ) {
TEST_CASE( "stringify( vectors<has_operator> )", "[toString]" ) {
std::vector<has_operator> v(1);
REQUIRE( ::Catch::Detail::stringify( v ) == "{ operator<<( has_operator ) }" );
}
TEST_CASE( "toString( vectors<has_maker> )", "[toString]" ) {
TEST_CASE( "stringify( vectors<has_maker> )", "[toString]" ) {
std::vector<has_maker> v(1);
REQUIRE( ::Catch::Detail::stringify( v ) == "{ StringMaker<has_maker> }" );
}
// Don't run this in approval tests as it is sensitive to two phase lookup differences
TEST_CASE( "toString( vectors<has_maker_and_operator> )", "[toString]" ) {
TEST_CASE( "stringify( vectors<has_maker_and_operator> )", "[toString]" ) {
std::vector<has_maker_and_operator> v(1);
REQUIRE( ::Catch::Detail::stringify( v ) == "{ StringMaker<has_maker_and_operator> }" );
}
// Range-based conversion should only be used if other possibilities fail
struct int_iterator {
using iterator_category = std::input_iterator_tag;
using difference_type = std::ptrdiff_t;
using value_type = int;
using reference = int&;
using pointer = int*;
int_iterator() = default;
int_iterator(int i) :val(i) {}
value_type operator*() const { return val; }
bool operator==(int_iterator rhs) const { return val == rhs.val; }
bool operator!=(int_iterator rhs) const { return val != rhs.val; }
int_iterator operator++() { ++val; return *this; }
int_iterator operator++(int) {
auto temp(*this);
++val;
return temp;
}
private:
int val = 5;
};
struct streamable_range {
int_iterator begin() const { return int_iterator{ 1 }; }
int_iterator end() const { return {}; }
};
std::ostream& operator<<(std::ostream& os, const streamable_range&) {
os << "op<<(streamable_range)";
return os;
}
struct stringmaker_range {
int_iterator begin() const { return int_iterator{ 1 }; }
int_iterator end() const { return {}; }
};
namespace Catch {
template <>
struct StringMaker<stringmaker_range> {
static std::string convert(stringmaker_range const&) {
return "stringmaker(streamable_range)";
}
};
}
struct just_range {
int_iterator begin() const { return int_iterator{ 1 }; }
int_iterator end() const { return {}; }
};
struct disabled_range {
int_iterator begin() const { return int_iterator{ 1 }; }
int_iterator end() const { return {}; }
};
namespace Catch {
template <>
struct is_range<disabled_range> {
static const bool value = false;
};
}
TEST_CASE("stringify ranges", "[toString]") {
REQUIRE(::Catch::Detail::stringify(streamable_range{}) == "op<<(streamable_range)");
REQUIRE(::Catch::Detail::stringify(stringmaker_range{}) == "stringmaker(streamable_range)");
REQUIRE(::Catch::Detail::stringify(just_range{}) == "{ 1, 2, 3, 4 }");
REQUIRE(::Catch::Detail::stringify(disabled_range{}) == "{ !!! }");
}

View File

@@ -61,9 +61,9 @@ FILE_2 description
.\" .Sh DIAGNOSTICS \" May not be needed
.\" .Bl -diag
.\" .It Diagnostic Tag
.\" Diagnostic informtion here.
.\" Diagnostic information here.
.\" .It Diagnostic Tag
.\" Diagnostic informtion here.
.\" Diagnostic information here.
.\" .El
.Sh SEE ALSO
.\" List links in ascending order by section, alphabetically within a section.

View File

@@ -50,6 +50,8 @@ infParser = re.compile(r'''
|
\(__builtin_inff\(\)\) # Linux (ubuntu) INFINITY macro
|
\(__builtin_inff\ \(\)\) # Fedora INFINITY macro
|
__builtin_huge_valf\(\) # OSX macro
''', re.VERBOSE)
nanParser = re.compile(r'''

2
scripts/embedClara.py Normal file → Executable file
View File

@@ -1,3 +1,5 @@
#!/usr/bin/env python
# Execute this script any time you import a new copy of Clara into the third_party area
import os
import sys

View File

@@ -3,6 +3,7 @@
from __future__ import print_function
import os
import io
import sys
import re
import datetime
@@ -46,11 +47,11 @@ def generate(v):
outDir = os.path.dirname(outputPath)
if not os.path.exists(outDir):
os.makedirs(outDir)
out = open( outputPath, 'w' )
out = io.open( outputPath, 'w', newline='\n')
def write( line ):
if globals['includeImpl'] or globals['implIfDefs'] == -1:
out.write( line )
out.write( line.decode('utf-8') )
def insertCpps():
dirs = [os.path.join( rootPath, s) for s in ['', 'internal', 'reporters']]
@@ -104,22 +105,22 @@ def generate(v):
write( '// end {}\n'.format(filename) )
out.write( "/*\n" )
out.write( " * Catch v{0}\n".format( v.getVersionString() ) )
out.write( " * Generated: {0}\n".format( datetime.datetime.now() ) )
out.write( " * ----------------------------------------------------------\n" )
out.write( " * This file has been merged from multiple headers. Please don't edit it directly\n" )
out.write( " * Copyright (c) {} Two Blue Cubes Ltd. All rights reserved.\n".format( datetime.date.today().year ) )
out.write( " *\n" )
out.write( " * Distributed under the Boost Software License, Version 1.0. (See accompanying\n" )
out.write( " * file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)\n" )
out.write( " */\n" )
out.write( "#ifndef TWOBLUECUBES_SINGLE_INCLUDE_CATCH_HPP_INCLUDED\n" )
out.write( "#define TWOBLUECUBES_SINGLE_INCLUDE_CATCH_HPP_INCLUDED\n" )
write( "/*\n" )
write( " * Catch v{0}\n".format( v.getVersionString() ) )
write( " * Generated: {0}\n".format( datetime.datetime.now() ) )
write( " * ----------------------------------------------------------\n" )
write( " * This file has been merged from multiple headers. Please don't edit it directly\n" )
write( " * Copyright (c) {} Two Blue Cubes Ltd. All rights reserved.\n".format( datetime.date.today().year ) )
write( " *\n" )
write( " * Distributed under the Boost Software License, Version 1.0. (See accompanying\n" )
write( " * file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)\n" )
write( " */\n" )
write( "#ifndef TWOBLUECUBES_SINGLE_INCLUDE_CATCH_HPP_INCLUDED\n" )
write( "#define TWOBLUECUBES_SINGLE_INCLUDE_CATCH_HPP_INCLUDED\n" )
parseFile( rootPath, 'catch.hpp' )
out.write( "#endif // TWOBLUECUBES_SINGLE_INCLUDE_CATCH_HPP_INCLUDED\n\n" )
write( "#endif // TWOBLUECUBES_SINGLE_INCLUDE_CATCH_HPP_INCLUDED\n\n" )
out.close()
print ("Generated single include for Catch v{0}\n".format( v.getVersionString() ) )

View File

@@ -10,6 +10,7 @@ from scriptCommon import catchPath
versionParser = re.compile( r'(\s*static\sVersion\sversion)\s*\(\s*(.*)\s*,\s*(.*)\s*,\s*(.*)\s*,\s*\"(.*)\"\s*,\s*(.*)\s*\).*' )
rootPath = os.path.join( catchPath, 'include/' )
versionPath = os.path.join( rootPath, "internal/catch_version.cpp" )
definePath = os.path.join(rootPath, 'catch.hpp')
readmePath = os.path.join( catchPath, "README.md" )
conanPath = os.path.join(catchPath, 'conanfile.py')
conanTestPath = os.path.join(catchPath, 'test_package', 'conanfile.py')
@@ -80,7 +81,7 @@ class Version:
def updateReadmeFile(version):
import updateWandbox
downloadParser = re.compile( r'<a href=\"https://github.com/philsquared/Catch/releases/download/v\d+\.\d+\.\d+/catch.hpp\">' )
downloadParser = re.compile( r'<a href=\"https://github.com/catchorg/Catch2/releases/download/v\d+\.\d+\.\d+/catch.hpp\">' )
success, wandboxLink = updateWandbox.uploadFiles()
if not success:
print('Error when uploading to wandbox: {}'.format(wandboxLink))
@@ -92,7 +93,7 @@ def updateReadmeFile(version):
f.close()
f = open( readmePath, 'w' )
for line in lines:
line = downloadParser.sub( r'<a href="https://github.com/philsquared/Catch/releases/download/v{0}/catch.hpp">'.format(version.getVersionString()) , line)
line = downloadParser.sub( r'<a href="https://github.com/catchorg/Catch2/releases/download/v{0}/catch.hpp">'.format(version.getVersionString()) , line)
if '[![Try online](https://img.shields.io/badge/try-online-blue.svg)]' in line:
line = '[![Try online](https://img.shields.io/badge/try-online-blue.svg)]({0})'.format(wandboxLink)
f.write( line + "\n" )
@@ -128,20 +129,36 @@ def updateConanTestFile(version):
f.write( line + "\n" )
def updateCmakeFile(version):
cmakeParser = re.compile(r'set(CATCH_VERSION_NUMBER \d+\.\d+\.\d+)')
with open(cmakePath, 'r') as file:
lines = file.readlines()
with open(cmakePath, 'w') as file:
for line in lines:
if 'set(CATCH_VERSION_NUMBER ' in line:
file.write('set(CATCH_VERSION_NUMBER {0})\n'.format(version.getVersionString()))
if 'project(Catch2 LANGUAGES CXX VERSION ' in line:
file.write('project(Catch2 LANGUAGES CXX VERSION {0})\n'.format(version.getVersionString()))
else:
file.write(line)
def updateVersionDefine(version):
with open(definePath, 'r') as file:
lines = file.readlines()
with open(definePath, 'w') as file:
for line in lines:
if '#define CATCH_VERSION_MAJOR' in line:
file.write('#define CATCH_VERSION_MAJOR {}\n'.format(version.majorVersion))
elif '#define CATCH_VERSION_MINOR' in line:
file.write('#define CATCH_VERSION_MINOR {}\n'.format(version.minorVersion))
elif '#define CATCH_VERSION_PATCH' in line:
file.write('#define CATCH_VERSION_PATCH {}\n'.format(version.patchNumber))
else:
file.write(line)
def performUpdates(version):
# First update version file, so we can regenerate single header and
# have it ready for upload to wandbox, when updating readme
version.updateVersionFile()
updateVersionDefine(version)
import generateSingleHeader
generateSingleHeader.generate(version)

View File

@@ -127,7 +127,7 @@ def tagAndCollect(lines, id_tag=True, back_links=False, exclude_h=None):
A list of 3-value sublists, where the first value
represents the heading, the second value the string
that was inserted assigned to the IDs in the anchor tags,
and the third value is an integer that reprents the headline level.
and the third value is an integer that represents the headline level.
E.g.,
[['some header lvl3', 'some-header-lvl3', 3], ...]
@@ -282,7 +282,7 @@ def markdownToclify(
input_file: str
Path to the markdown input file.
output_file: str (defaul: None)
output_file: str (default: None)
Path to the markdown output file.
min_toc_len: int (default: 2)
@@ -420,7 +420,7 @@ def updateDocumentToCMain():
default=minTocEntries,
type=int,
metavar='N',
help='the minimum number of entries to create a table of contents for [{deflt}]'.format(deflt=minTocEntries))
help='the minimum number of entries to create a table of contents for [{default}]'.format(default=minTocEntries))
parser.add_argument(
'--remove-toc',

View File

@@ -8,7 +8,7 @@ from releaseCommon import Version
print(catchPath)
default_path = '../vcpkg/ports/catch/'
default_path = '../vcpkg/ports/catch2/'
def adjusted_path(path):
return os.path.join(catchPath, path)
@@ -89,7 +89,7 @@ def git_push(path_to_repo):
# Make sure we branch off master
subprocess.call('git checkout master', shell=True)
# Update repo to current master, so we don't work off old version of the portsfile
# Update repo to current master, so we don't work off old version of the portfile
subprocess.call('git pull Microsoft master', shell=True)
subprocess.call('git push', shell=True)

File diff suppressed because it is too large Load Diff

View File

@@ -26,7 +26,7 @@ namespace Catch {
~TAPReporter() override;
static std::string getDescription() {
return "Reports test results in TAP format, suitable for test harneses";
return "Reports test results in TAP format, suitable for test harnesses";
}
ReporterPreferences getPreferences() const override {

View File

@@ -10,7 +10,7 @@ class CatchConanTest(ConanFile):
settings = "os", "compiler", "arch", "build_type"
username = getenv("CONAN_USERNAME", "philsquared")
channel = getenv("CONAN_CHANNEL", "testing")
requires = "Catch/2.1.0@%s/%s" % (username, channel)
requires = "Catch/2.2.1@%s/%s" % (username, channel)
def build(self):
cmake = CMake(self)

150
third_party/clara.hpp vendored
View File

@@ -1,5 +1,11 @@
// v1.0-develop.2
// See https://github.com/philsquared/Clara
// Copyright 2017 Two Blue Cubes Ltd. All rights reserved.
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
//
// See https://github.com/philsquared/Clara for more details
// Clara v1.1.4
#ifndef CLARA_HPP_INCLUDED
#define CLARA_HPP_INCLUDED
@@ -12,6 +18,16 @@
#define CLARA_TEXTFLOW_CONFIG_CONSOLE_WIDTH CLARA_CONFIG_CONSOLE_WIDTH
#endif
#ifndef CLARA_CONFIG_OPTIONAL_TYPE
#ifdef __has_include
#if __has_include(<optional>) && __cplusplus >= 201703L
#include <optional>
#define CLARA_CONFIG_OPTIONAL_TYPE std::optional
#endif
#endif
#endif
// ----------- #included from clara_textflow.hpp -----------
// TextFlowCpp
@@ -370,7 +386,7 @@ namespace detail {
template<typename ClassT, typename ReturnT, typename ArgT>
struct UnaryLambdaTraits<ReturnT( ClassT::* )( ArgT ) const> {
static const bool isValid = true;
using ArgType = typename std::remove_const<typename std::remove_reference<ArgT>::type>::type;;
using ArgType = typename std::remove_const<typename std::remove_reference<ArgT>::type>::type;
using ReturnType = ReturnT;
};
@@ -383,11 +399,9 @@ namespace detail {
std::vector<std::string> m_args;
public:
Args( int argc, char *argv[] ) {
m_exeName = argv[0];
for( int i = 1; i < argc; ++i )
m_args.push_back( argv[i] );
}
Args( int argc, char const* const* argv )
: m_exeName(argv[0]),
m_args(argv + 1, argv + argc) {}
Args( std::initializer_list<std::string> args )
: m_exeName( *args.begin() ),
@@ -535,7 +549,7 @@ namespace detail {
return *this;
}
~ResultValueBase() {
~ResultValueBase() override {
if( m_type == Ok )
m_value.~T();
}
@@ -573,16 +587,14 @@ namespace detail {
auto errorMessage() const -> std::string { return m_errorMessage; }
protected:
virtual void enforceOk() const {
// !TBD: If no exceptions, std::terminate here or something
switch( m_type ) {
case ResultBase::LogicError:
throw std::logic_error( m_errorMessage );
case ResultBase::RuntimeError:
throw std::runtime_error( m_errorMessage );
case ResultBase::Ok:
break;
}
void enforceOk() const override {
// Errors shouldn't reach this point, but if they do
// the actual error message will be in m_errorMessage
assert( m_type != ResultBase::LogicError );
assert( m_type != ResultBase::RuntimeError );
if( m_type != ResultBase::Ok )
std::abort();
}
std::string m_errorMessage; // Only populated if resultType is an error
@@ -652,47 +664,43 @@ namespace detail {
return ParserResult::runtimeError( "Expected a boolean value but did not recognise: '" + source + "'" );
return ParserResult::ok( ParseResultType::Matched );
}
#ifdef CLARA_CONFIG_OPTIONAL_TYPE
template<typename T>
inline auto convertInto( std::string const &source, CLARA_CONFIG_OPTIONAL_TYPE<T>& target ) -> ParserResult {
T temp;
auto result = convertInto( source, temp );
if( result )
target = std::move(temp);
return result;
}
#endif // CLARA_CONFIG_OPTIONAL_TYPE
struct BoundRefBase {
BoundRefBase() = default;
BoundRefBase( BoundRefBase const & ) = delete;
BoundRefBase( BoundRefBase && ) = delete;
BoundRefBase &operator=( BoundRefBase const & ) = delete;
BoundRefBase &operator=( BoundRefBase && ) = delete;
struct NonCopyable {
NonCopyable() = default;
NonCopyable( NonCopyable const & ) = delete;
NonCopyable( NonCopyable && ) = delete;
NonCopyable &operator=( NonCopyable const & ) = delete;
NonCopyable &operator=( NonCopyable && ) = delete;
};
virtual ~BoundRefBase() = default;
virtual auto isFlag() const -> bool = 0;
struct BoundRef : NonCopyable {
virtual ~BoundRef() = default;
virtual auto isContainer() const -> bool { return false; }
virtual auto isFlag() const -> bool { return false; }
};
struct BoundValueRefBase : BoundRef {
virtual auto setValue( std::string const &arg ) -> ParserResult = 0;
};
struct BoundFlagRefBase : BoundRef {
virtual auto setFlag( bool flag ) -> ParserResult = 0;
};
struct BoundValueRefBase : BoundRefBase {
auto isFlag() const -> bool override { return false; }
auto setFlag( bool ) -> ParserResult override {
return ParserResult::logicError( "Flags can only be set on boolean fields" );
}
};
struct BoundFlagRefBase : BoundRefBase {
auto isFlag() const -> bool override { return true; }
auto setValue( std::string const &arg ) -> ParserResult override {
bool flag;
auto result = convertInto( arg, flag );
if( result )
setFlag( flag );
return result;
}
virtual auto isFlag() const -> bool { return true; }
};
template<typename T>
struct BoundRef : BoundValueRefBase {
struct BoundValueRef : BoundValueRefBase {
T &m_ref;
explicit BoundRef( T &ref ) : m_ref( ref ) {}
explicit BoundValueRef( T &ref ) : m_ref( ref ) {}
auto setValue( std::string const &arg ) -> ParserResult override {
return convertInto( arg, m_ref );
@@ -700,10 +708,10 @@ namespace detail {
};
template<typename T>
struct BoundRef<std::vector<T>> : BoundValueRefBase {
struct BoundValueRef<std::vector<T>> : BoundValueRefBase {
std::vector<T> &m_ref;
explicit BoundRef( std::vector<T> &ref ) : m_ref( ref ) {}
explicit BoundValueRef( std::vector<T> &ref ) : m_ref( ref ) {}
auto isContainer() const -> bool override { return true; }
@@ -748,12 +756,12 @@ namespace detail {
template<typename ArgType, typename L>
inline auto invokeLambda( L const &lambda, std::string const &arg ) -> ParserResult {
ArgType temp;
ArgType temp{};
auto result = convertInto( arg, temp );
return !result
? result
: LambdaInvoker<typename UnaryLambdaTraits<L>::ReturnType>::invoke( lambda, temp );
};
}
template<typename L>
@@ -803,6 +811,9 @@ namespace detail {
public:
template<typename T>
auto operator|( T const &other ) const -> Parser;
template<typename T>
auto operator+( T const &other ) const -> Parser;
};
// Common code and state for Args and Opts
@@ -810,16 +821,16 @@ namespace detail {
class ParserRefImpl : public ComposableParserImpl<DerivedT> {
protected:
Optionality m_optionality = Optionality::Optional;
std::shared_ptr<BoundRefBase> m_ref;
std::shared_ptr<BoundRef> m_ref;
std::string m_hint;
std::string m_description;
explicit ParserRefImpl( std::shared_ptr<BoundRefBase> const &ref ) : m_ref( ref ) {}
explicit ParserRefImpl( std::shared_ptr<BoundRef> const &ref ) : m_ref( ref ) {}
public:
template<typename T>
ParserRefImpl( T &ref, std::string const &hint )
: m_ref( std::make_shared<BoundRef<T>>( ref ) ),
: m_ref( std::make_shared<BoundValueRef<T>>( ref ) ),
m_hint( hint )
{}
@@ -860,10 +871,10 @@ namespace detail {
class ExeName : public ComposableParserImpl<ExeName> {
std::shared_ptr<std::string> m_name;
std::shared_ptr<BoundRefBase> m_ref;
std::shared_ptr<BoundValueRefBase> m_ref;
template<typename LambdaT>
static auto makeRef(LambdaT const &lambda) -> std::shared_ptr<BoundRefBase> {
static auto makeRef(LambdaT const &lambda) -> std::shared_ptr<BoundValueRefBase> {
return std::make_shared<BoundLambda<LambdaT>>( lambda) ;
}
@@ -871,7 +882,7 @@ namespace detail {
ExeName() : m_name( std::make_shared<std::string>( "<executable>" ) ) {}
explicit ExeName( std::string &ref ) : ExeName() {
m_ref = std::make_shared<BoundRef<std::string>>( ref );
m_ref = std::make_shared<BoundValueRef<std::string>>( ref );
}
template<typename LambdaT>
@@ -914,7 +925,10 @@ namespace detail {
if( token.type != TokenType::Argument )
return InternalParseResult::ok( ParseState( ParseResultType::NoMatch, remainingTokens ) );
auto result = m_ref->setValue( remainingTokens->token );
assert( !m_ref->isFlag() );
auto valueRef = static_cast<detail::BoundValueRefBase*>( m_ref.get() );
auto result = valueRef->setValue( remainingTokens->token );
if( !result )
return InternalParseResult( result );
else
@@ -988,19 +1002,21 @@ namespace detail {
auto const &token = *remainingTokens;
if( isMatch(token.token ) ) {
if( m_ref->isFlag() ) {
auto result = m_ref->setFlag( true );
auto flagRef = static_cast<detail::BoundFlagRefBase*>( m_ref.get() );
auto result = flagRef->setFlag( true );
if( !result )
return InternalParseResult( result );
if( result.value() == ParseResultType::ShortCircuitAll )
return InternalParseResult::ok( ParseState( result.value(), remainingTokens ) );
} else {
auto valueRef = static_cast<detail::BoundValueRefBase*>( m_ref.get() );
++remainingTokens;
if( !remainingTokens )
return InternalParseResult::runtimeError( "Expected argument following " + token.token );
auto const &argToken = *remainingTokens;
if( argToken.type != TokenType::Argument )
return InternalParseResult::runtimeError( "Expected argument following " + token.token );
auto result = m_ref->setValue( argToken.token );
auto result = valueRef->setValue( argToken.token );
if( !result )
return InternalParseResult( result );
if( result.value() == ParseResultType::ShortCircuitAll )
@@ -1077,6 +1093,12 @@ namespace detail {
return Parser( *this ) |= other;
}
// Forward deprecated interface with '+' instead of '|'
template<typename T>
auto operator+=( T const &other ) -> Parser & { return operator|=( other ); }
template<typename T>
auto operator+( T const &other ) const -> Parser { return operator|( other ); }
auto getHelpColumns() const -> std::vector<HelpColumns> {
std::vector<HelpColumns> cols;
for (auto const &o : m_options) {
@@ -1116,6 +1138,8 @@ namespace detail {
for( auto const &cols : rows )
optWidth = (std::max)(optWidth, cols.left.size() + 2);
optWidth = (std::min)(optWidth, consoleWidth/2);
for( auto const &cols : rows ) {
auto row =
TextFlow::Column( cols.left ).width( optWidth ).indent( 2 ) +