Compare commits

..

63 Commits

Author SHA1 Message Date
Martin Hořeňovský
2c869e17e4 v2.9.2 2019-08-08 14:05:24 +02:00
Martin Hořeňovský
0ab11aa9b4 (Hopefully) Fix Obj-C++ compilation of matchers
Thanks to bdb for the patch, related to #1661
2019-08-07 20:35:27 +02:00
Martin Hořeňovský
7a6af7ba76 Merge pull request #1717 from ax3l/fix-storageClassFirst
static constexpr: storage class first
2019-08-07 09:23:47 +02:00
Martin Hořeňovský
fa096b26d1 Merge pull request #1715 from sfranzen/fix-compact-reporter
Fix infinite loop in compact reporter printer
2019-08-07 09:12:38 +02:00
Axel Huebl
820b1f12bf static constexpr: storage class first
Seen with PGI compiler for `static constexpr`:
```
warning: storage class is not first
```
2019-08-06 19:17:16 -05:00
Steven Franzen
6070745cab Improve reporting of unmatched filters (#1684)
This PR ultimately does 3 things
* Separately tracks matched tests per each filter part (that is, a set of filters separated by an OR (`,`)), which allows Catch2 to report each of the alternative filters that don't match any tests.
* Fixes `-w NoTests` to return non-zero in the process
* Adds tests for `-w NoTests`.
2019-08-06 20:51:19 +02:00
Steven Franzen
3d9e7db2e0 Fix infinite loop in compact reporter printer
Also simplify some variables with auto deduction.
2019-08-06 20:19:42 +02:00
Martin Hořeňovský
cf55cfd76f Tiny speedup when listing tags
Noticed that the code was originally concatenating strings just to
then append the result to another string. Now it does not create
temporaries and also preallocates the string buffer.
2019-08-05 19:12:29 +02:00
Martin Hořeňovský
3701c2e2e6 Small cleanup of self tests 2019-08-04 13:50:25 +02:00
Martin Hořeňovský
7dc7d77af2 Add a test for Catch version output 2019-08-03 20:16:46 +02:00
Martin Hořeňovský
06bc20cf37 Improve handling of newlines in release scripts
Under WSL, Python in text mode will translate `\n` into `\r\n`, even
though other tools and utilities use `\n` (because WSL is basically
Linux). This leads to the update scripts leaving the files with
Windows newlines even though git and similar expect them to have
Linux newlines.

By instead handling files in binary mode, we can keep the original
newlines. This commits switches parts of the update process to
binary mode, but not all because some of the will require a lot of
work to fix.
2019-08-03 19:59:35 +02:00
Martin Hořeňovský
7a4beed6a6 Make release script update version placeholders in docs 2019-08-03 10:44:57 +02:00
Clare Macrae
67b4ada6b0 Add 'Introduced in Catch 2.3.0.' text 2019-08-02 19:18:47 +02:00
Clare Macrae
119569a67e Add 'Introduced in Catch 2.4.0.' text 2019-08-02 19:18:47 +02:00
Clare Macrae
ab713894cc Add docs for AND_GIVEN macro - see #1360 2019-08-02 19:18:47 +02:00
Clare Macrae
69fc94d6f8 Add 'Introduced in Catch 2.4.1.' text 2019-08-02 19:18:47 +02:00
Clare Macrae
49cd7c96b4 Add 'Introduced in Catch 2.4.2.' text 2019-08-02 19:18:47 +02:00
Clare Macrae
e998d152cc Add 'Introduced in Catch 2.5.0.' text 2019-08-02 19:18:47 +02:00
Clare Macrae
42a5903188 Add 'Introduced in Catch 2.6.0.' text 2019-08-02 19:18:47 +02:00
Clare Macrae
c071f07e1a Add 'Introduced in Catch 2.7.0.' note 2019-08-02 19:18:47 +02:00
Clare Macrae
53776a90cf Add 'Introduced in Catch 2.7.1.' note 2019-08-02 19:18:47 +02:00
Clare Macrae
4511dc0c16 Add 'Introduced in Catch 2.8.0.' text 2019-08-02 19:18:47 +02:00
Clare Macrae
e7c3bdb351 Add 'Introduced in Catch 2.8.0.' text 2019-08-02 19:18:47 +02:00
Clare Macrae
9aab958667 Add section headers, so I can later say when features were introduced 2019-08-02 19:18:47 +02:00
Clare Macrae
8cd58f75ec Add missing struct Template_Fixture_2 so that the example compiles.
Code copied from projects/SelfTest/UsageTests/Class.tests.cpp
2019-08-02 19:18:47 +02:00
Clare Macrae
d5a69cd400 Add 'Introduced in Catch 2.9.0.' text 2019-08-02 19:18:47 +02:00
Clare Macrae
1d13d88833 Helper script to create "Introduced in ..." text - see #1667 2019-08-02 19:18:47 +02:00
Martin Hořeňovský
de0674c116 Add a template for creating new documentation page
Related to #1695
2019-08-02 13:17:22 +02:00
Martin Hořeňovský
3d7282c2bd Add a section on documentation to contributing.md
Related to #1695
2019-08-02 10:58:51 +02:00
Mike Cowan
e5c0e3322d Add Android implementation of writeToDebugConsole that prints to Logcat (#1710) 2019-07-31 23:12:34 +02:00
Martin Hořeňovský
dc8c8e957f Use an up to date conan package version again
Last time it was fixed to a specific version because the `conan`
and the `conan-package-tools` package that `pip install` would
gather were not compatible, let's hope it won't happen again.
2019-07-31 15:59:16 +02:00
Martin Hořeňovský
ba9193370b Add autoconfiguration for RTX
Closes #1693
2019-07-30 11:28:28 +02:00
Czapa10
7b70b11c23 Add PopHead to Open Source projects using Catch 2019-07-30 09:37:05 +02:00
Martin Hořeňovský
ab80277a86 Improve the REQUIRE_THROWS_MATCHES documentation a bit 2019-07-29 20:39:02 +02:00
Joachim Meyer
7e7ab0e28b Fix xml reporter crashing when a benchmark failed. 2019-07-29 15:30:33 +02:00
Martin Hořeňovský
425957dc63 Update vector matcher documentation
As it turns out, there were 2 undocumented vector matchers. I also
improved the documentation of them all.

Closes #1699
2019-07-27 18:41:42 +02:00
Martin Hořeňovský
d017f6d18f Document CATCH_CONFIG_CPP17_BYTE macro
Leftover from #1686
2019-07-26 21:43:46 +02:00
Martin Hořeňovský
91244d30a7 Document CATCH_CONFIG_CPP17_OPTIONAL macro 2019-07-26 21:42:54 +02:00
Martin Hořeňovský
62b3f6c3c2 Merge pull request #1698 from sfranzen/fix-#1634
Fix CTest command issue with square brackets
2019-07-22 13:15:35 +02:00
Benjamin Worpitz
e7c26f09d1 Fix non-default-constructible type lists used in TEMPLATE_LIST_TEST_CASE (#1697)
* Fix non-default-constructible type lists used in TEMPLATE_LIST_TEST_CASE

std::tuple is not default constructible when the first type is not
default-constuctible. Therefore it can not be instantiated.
to circumvent this, we have to use std::declval in the unevaluate decltype
context.
2019-07-22 12:56:33 +02:00
Martin Hořeňovský
a22b7df46c Merge pull request #1700 from claremacrae/patch-3
Fix typo in 2.7.1 release notes
2019-07-22 12:13:29 +02:00
Clare Macrae
032068b889 Fix typo in 2.7.1 release notes
GENERATE_VAR -> GENERATE_REF
2019-07-21 22:04:50 +01:00
Steven Franzen
2aed6233cf Fix CTest command issue with square brackets 2019-07-21 16:29:46 +02:00
Martin Hořeňovský
fb74bb133c Fix coverage report merging
For some time now (I'd guess almost a year 🤷), the coverage
merging on Windows has been failing, because the reports have been
generated in a different folder than expected. Our merge script did
not report failure because it was not checking the returned error
code from OpenCppCoverage, and for some reason, the `codecov` tool
happily returned 0 even though it did not find the file it was
supposed to upload...

The former is also fixed by this commit.
2019-07-20 21:12:17 +02:00
Martin Hořeňovský
0b42ada60d Coverage helper now passes-on test return value
This allows #1684 to proceed forward.
2019-07-20 21:05:31 +02:00
Martin Hořeňovský
c424ca47f9 Revert "Do not resolve symbolic path when sanitizing filepath during approvals"
This reverts commit 52f3abadbb.

Opens #1691
2019-07-19 18:16:21 +02:00
Martin Hořeňovský
52f3abadbb Do not resolve symbolic path when sanitizing filepath during approvals
Fixes #1691
2019-07-18 16:33:57 +02:00
Martin Hořeňovský
53281b471f Prevent compilation of generators that use bool in dangerous manner
Closes #1692
2019-07-18 11:54:18 +02:00
Martin Hořeňovský
03ffc1014c Add a notice that benchmarking supports needs opt-in 2019-07-14 15:49:17 +02:00
Stuart Dootson
87739ad3fe Add std::byte stringification support (#1686)
* Add `std::byte` support

1. Add byte detection in Catch config
2. Add a `std::byte`specialisation for Catch2::Detail::StringMaker
2019-07-13 14:47:56 +02:00
Clare Macrae
0c27554af5 Update Contents in docs #1667 2019-07-06 17:25:55 +02:00
Martin Hořeňovský
11488e63b6 Use _WIN32 macro for detecting MSVC Windows
Previously we used `WIN32`, which sometimes does exist, but according to
https://docs.microsoft.com/en-us/cpp/preprocessor/predefined-macros?view=vs-2019
`_WIN32` is the one that is actually provided by the compiler.

Closes #1676.
2019-07-06 16:55:10 +02:00
Martin Hořeňovský
820271bf24 Remove the weird backronym from readme 2019-07-02 20:43:37 +02:00
Martin Hořeňovský
56d4510138 Default the SelfTest project to C++11
Unlike the previous approach, this will still obey
`-DCMAKE_CXX_STANDARD=X` properly.
2019-07-02 20:42:14 +02:00
Martin Hořeňovský
c0d3a2e08f Merge pull request #1672 from sommd/master
Fix ChunkGenerator with chunk-size 0
2019-07-01 18:07:37 +02:00
Martin Hořeňovský
2c3018a9d5 Merge pull request #1673 from sfranzen/fix-sections
Fix TrackerBase::close children completion check
2019-06-30 09:17:01 +02:00
Martin Hořeňovský
9a6551b22b Add integration test for the children completion check fix 2019-06-30 00:00:41 +02:00
Steven Franzen
800f1b1d3d Fix TrackerBase::close children completion check
Now verifies that all children have completed, instead of only the last.
2019-06-29 18:02:28 +02:00
David Sommerich
9cf5897a11 Fix ChunkGenerator with chunk-size 0
Fixes #1671
2019-06-29 23:48:30 +10:00
Scott Hutchinson
6f32c67ea7 Adding to documentation for --order and --rng-seed 2019-06-21 15:17:55 +02:00
Martin Hořeňovský
7eea3ab245 Actually fix the CMake platform-independence problem 2019-06-17 19:41:17 +02:00
Justin Bassett
80af9ca687 Rollback ctest labels in CatchAddTests.cmake
Parsing --list-tests is broken, as Catch automatically line wraps the
line when it gets too long, stripping any whitespace in the process.
This means that it's impossible to reproduce the exact name of the
test if the test's name is long enough to line-wrap.

Furthermore, overwriting the LABELS property with the discovered labels
breaks users who manually added custom ctest labels.

Rolling back to using --list-test-names-only for now, as it does not
wrap lines even on very long test names.

We may be able parse the output of --list-tags to produce the ctest labels.
However, the straightforward way of doing this is to use CMake's
get_property(TEST ...) and set_property(TEST ... APPEND ...), which don't
work if the test name has spaces or other special characters. We would
need to mangle the test name to a valid CMake identifier to do it that way.
2019-06-17 19:17:32 +02:00
Martin Hořeňovský
33286fdc37 Fix bug with making arch-independent CMake config file
Closes #1660
2019-06-17 19:08:16 +02:00
63 changed files with 1427 additions and 455 deletions

View File

@@ -276,7 +276,7 @@ matrix:
- "3.7"
dist: xenial
install:
- pip install conan==1.10.2 conan-package-tools
- pip install conan conan-package-tools
env:
- CONAN_GCC_VERSIONS=8
- CONAN_DOCKER_IMAGE=conanio/gcc8

View File

@@ -6,7 +6,7 @@ if(NOT DEFINED PROJECT_NAME)
set(NOT_SUBPROJECT ON)
endif()
project(Catch2 LANGUAGES CXX VERSION 2.9.1)
project(Catch2 LANGUAGES CXX VERSION 2.9.2)
if (CMAKE_BINARY_DIR STREQUAL CMAKE_SOURCE_DIR)
message(FATAL_ERROR "Building in-source is not supported! Create a build dir and remove ${CMAKE_SOURCE_DIR}/CMakeCache.txt")
@@ -136,9 +136,11 @@ if (NOT_SUBPROJECT)
#
# CMake does not provide a direct customization point for this in
# `write_basic_package_version_file`, but it can be accomplished
# indirectly by temporarily undefining `CMAKE_SIZEOF_VOID_P`.
# indirectly by temporarily redefining `CMAKE_SIZEOF_VOID_P` to an
# empty string. Note that just undefining the variable could be
# insufficient in cases where the variable was already in CMake cache
set(CATCH2_CMAKE_SIZEOF_VOID_P ${CMAKE_SIZEOF_VOID_P})
unset(CMAKE_SIZEOF_VOID_P)
set(CMAKE_SIZEOF_VOID_P "")
write_basic_package_version_file(
"${CMAKE_CURRENT_BINARY_DIR}/Catch2ConfigVersion.cmake"
COMPATIBILITY

View File

@@ -5,11 +5,11 @@
[![Build Status](https://travis-ci.org/catchorg/Catch2.svg?branch=master)](https://travis-ci.org/catchorg/Catch2)
[![Build status](https://ci.appveyor.com/api/projects/status/github/catchorg/Catch2?svg=true)](https://ci.appveyor.com/project/catchorg/catch2)
[![codecov](https://codecov.io/gh/catchorg/Catch2/branch/master/graph/badge.svg)](https://codecov.io/gh/catchorg/Catch2)
[![Try online](https://img.shields.io/badge/try-online-blue.svg)](https://wandbox.org/permlink/5icuqPwk9miJLAL1)
[![Try online](https://img.shields.io/badge/try-online-blue.svg)](https://wandbox.org/permlink/8YrGVqYqqSC4Sc5R)
[![Join the chat in Discord: https://discord.gg/4CWS9zD](https://img.shields.io/badge/Discord-Chat!-brightgreen.svg)](https://discord.gg/4CWS9zD)
<a href="https://github.com/catchorg/Catch2/releases/download/v2.9.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.9.2/catch.hpp">The latest version of the single header can be downloaded directly using this link</a>
## Catch2 is released!
@@ -19,9 +19,8 @@ before moving to Catch2. You might also like to read [this blog post](https://le
## What's the Catch?
Catch2 stands for C++ Automated Test Cases in a Header and is a
multi-paradigm test framework for C++. which also supports Objective-C
(and maybe C).
Catch2 is a multi-paradigm test framework for C++. which also supports
Objective-C (and maybe C).
It is primarily distributed as a single header file, although certain
extensions may require additional headers.

View File

@@ -22,39 +22,6 @@ function(add_command NAME)
set(script "${script}${NAME}(${_args})\n" PARENT_SCOPE)
endfunction()
macro(_add_catch_test_labels LINE)
# convert to list of tags
string(REPLACE "][" "]\\;[" tags ${line})
add_command(
set_tests_properties "${prefix}${test}${suffix}"
PROPERTIES
LABELS "${tags}"
)
endmacro()
macro(_add_catch_test LINE)
set(test ${line})
# use escape commas to handle properly test cases with commans inside the name
string(REPLACE "," "\\," test_name ${test})
# ...and add to script
add_command(
add_test "${prefix}${test}${suffix}"
${TEST_EXECUTOR}
"${TEST_EXECUTABLE}"
"${test_name}"
${extra_args}
)
add_command(
set_tests_properties "${prefix}${test}${suffix}"
PROPERTIES
WORKING_DIRECTORY "${TEST_WORKING_DIR}"
${properties}
)
list(APPEND tests "${prefix}${test}${suffix}")
endmacro()
# Run test executable to get list of available tests
if(NOT EXISTS "${TEST_EXECUTABLE}")
message(FATAL_ERROR
@@ -62,7 +29,7 @@ if(NOT EXISTS "${TEST_EXECUTABLE}")
)
endif()
execute_process(
COMMAND ${TEST_EXECUTOR} "${TEST_EXECUTABLE}" ${spec} --list-tests
COMMAND ${TEST_EXECUTOR} "${TEST_EXECUTABLE}" ${spec} --list-test-names-only
OUTPUT_VARIABLE output
RESULT_VARIABLE result
)
@@ -80,22 +47,30 @@ elseif(${result} LESS 0)
endif()
string(REPLACE "\n" ";" output "${output}")
set(test)
set(tags_regex "(\\[([^\\[]*)\\])+$")
# Parse output
foreach(line ${output})
# lines without leading whitespaces are catch output not tests
if(${line} MATCHES "^[ \t]+")
# strip leading spaces and tabs
string(REGEX REPLACE "^[ \t]+" "" line ${line})
if(${line} MATCHES "${tags_regex}")
_add_catch_test_labels(${line})
else()
_add_catch_test(${line})
endif()
endif()
set(test ${line})
# Escape characters in test case names that would be parsed by Catch2
set(test_name ${test})
foreach(char , [ ])
string(REPLACE ${char} "\\${char}" test_name ${test_name})
endforeach(char)
# ...and add to script
add_command(add_test
"${prefix}${test}${suffix}"
${TEST_EXECUTOR}
"${TEST_EXECUTABLE}"
"${test_name}"
${extra_args}
)
add_command(set_tests_properties
"${prefix}${test}${suffix}"
PROPERTIES
WORKING_DIRECTORY "${TEST_WORKING_DIR}"
${properties}
)
list(APPEND tests "${prefix}${test}${suffix}")
endforeach()
# Create a list of all discovered tests, which users may use to e.g. set

View File

@@ -136,7 +136,7 @@ REQUIRE_THROWS_WITH( dismantleHal(), "My mind is going" );
* **REQUIRE_THROWS_MATCHES(** _expression_, _exception type_, _matcher for given exception type_ **)** and
* **CHECK_THROWS_MATCHES(** _expression_, _exception type_, _matcher for given exception type_ **)**
Expects that exception of _exception type_ is thrown and it matches provided matcher (see next section for Matchers).
Expects that exception of _exception type_ is thrown and it matches provided matcher (see the [documentation for Matchers](matchers.md#top)).
_Please note that the `THROW` family of assertions expects to be passed a single expression, not a statement or series of statements. If you want to check a more complicated sequence of operations, you can use a C++11 lambda function._

View File

@@ -1,6 +1,12 @@
<a id="top"></a>
# Authoring benchmarks
> [Introduced](https://github.com/catchorg/Catch2/issues/1616) in Catch 2.9.0.
_Note that benchmarking support is disabled by default and to enable it,
you need to define `CATCH_CONFIG_ENABLE_BENCHMARKING`. For more details,
see the [compile-time configuration documentation](configuration.md#top)._
Writing benchmarks is not easy. Catch simplifies certain aspects but you'll
always need to take care about various aspects. Understanding a few things about
the way Catch runs your code will be very helpful when writing your benchmarks.

View File

@@ -21,8 +21,8 @@
[Identify framework and version according to the libIdentify standard](#identify-framework-and-version-according-to-the-libidentify-standard)<br>
[Wait for key before continuing](#wait-for-key-before-continuing)<br>
[Specify the number of benchmark samples to collect](#specify-the-number-of-benchmark-samples-to-collect)<br>
[Specify the number of benchmark resamples for bootstrapping](#specify-the-number-of-resamples-for-bootstrapping)<br>
[Specify the confidence interval for bootstrapping](#specify-the-confidence-interval-for-bootstrapping)<br>
[Specify the number of resamples for bootstrapping](#specify-the-number-of-resamples-for-bootstrapping)<br>
[Specify the confidence-interval for bootstrapping](#specify-the-confidence-interval-for-bootstrapping)<br>
[Disable statistical analysis of collected benchmark samples](#disable-statistical-analysis-of-collected-benchmark-samples)<br>
[Usage](#usage)<br>
[Specify the section to run](#specify-the-section-to-run)<br>
@@ -242,7 +242,7 @@ Test cases are ordered one of three ways:
### decl
Declaration order. The order the tests were originally declared in. Note that ordering between files is not guaranteed and is implementation dependent.
Declaration order (this is the default order if no --order argument is provided). The order the tests were originally declared in. Note that ordering between files is not guaranteed and is implementation dependent.
### lex
Lexicographically sorted. Tests are sorted, alpha-numerically, by name.
@@ -256,7 +256,7 @@ Randomly sorted. Test names are sorted using ```std::random_shuffle()```. By def
Sets a seed for the random number generator using ```std::srand()```.
If a number is provided this is used directly as the seed so the random pattern is repeatable.
Alternatively if the keyword ```time``` is provided then the result of calling ```std::time(0)``` is used and so the pattern becomes unpredictable.
Alternatively if the keyword ```time``` is provided then the result of calling ```std::time(0)``` is used and so the pattern becomes unpredictable. In some cases, you might need to pass the keyword ```time``` in double quotes instead of single quotes.
In either case the actual value for the seed is printed as part of Catch's output so if an issue is discovered that is sensitive to test ordering the ordering can be reproduced - even if it was originally seeded from ```std::time(0)```.
@@ -277,6 +277,8 @@ either before running any tests, after running all tests - or both, depending on
## Specify the number of benchmark samples to collect
<pre>--benchmark-samples &lt;# of samples&gt;</pre>
> [Introduced](https://github.com/catchorg/Catch2/issues/1616) in Catch 2.9.0.
When running benchmarks a number of "samples" is collected. This is the base data for later statistical analysis.
Per sample a clock resolution dependent number of iterations of the user code is run, which is independent of the number of samples. Defaults to 100.
@@ -284,6 +286,8 @@ Per sample a clock resolution dependent number of iterations of the user code is
## Specify the number of resamples for bootstrapping
<pre>--benchmark-resamples &lt;# of resamples&gt;</pre>
> [Introduced](https://github.com/catchorg/Catch2/issues/1616) in Catch 2.9.0.
After the measurements are performed, statistical [bootstrapping] is performed
on the samples. The number of resamples for that bootstrapping is configurable
but defaults to 100000. Due to the bootstrapping it is possible to give
@@ -297,6 +301,8 @@ defaults to 95%).
## Specify the confidence-interval for bootstrapping
<pre>--benchmark-confidence-interval &lt;confidence-interval&gt;</pre>
> [Introduced](https://github.com/catchorg/Catch2/issues/1616) in Catch 2.9.0.
The confidence-interval is used for statistical bootstrapping on the samples to
calculate the upper and lower bounds of mean and standard deviation.
Must be between 0 and 1 and defaults to 0.95.
@@ -305,6 +311,8 @@ Must be between 0 and 1 and defaults to 0.95.
## Disable statistical analysis of collected benchmark samples
<pre>--benchmark-no-analysis</pre>
> [Introduced](https://github.com/catchorg/Catch2/issues/1616) in Catch 2.9.0.
When this flag is specified no bootstrapping or any other statistical analysis is performed.
Instead the user code is only measured and the plain mean from the samples is reported.

View File

@@ -127,8 +127,12 @@ Catch's selection, by defining either `CATCH_CONFIG_CPP11_TO_STRING` or
## C++17 toggles
CATCH_CONFIG_CPP17_UNCAUGHT_EXCEPTIONS // Use std::uncaught_exceptions instead of std::uncaught_exception
CATCH_CONFIG_CPP17_STRING_VIEW // Provide StringMaker specialization for std::string_view
CATCH_CONFIG_CPP17_VARIANT // Override C++17 detection for CATCH_CONFIG_ENABLE_VARIANT_STRINGMAKER
CATCH_CONFIG_CPP17_STRING_VIEW // Override std::string_view support detection(Catch provides a StringMaker specialization by default)
CATCH_CONFIG_CPP17_VARIANT // Override std::variant support detection (checked by CATCH_CONFIG_ENABLE_VARIANT_STRINGMAKER)
CATCH_CONFIG_CPP17_OPTIONAL // Override std::optional support detection (checked by CATCH_CONFIG_ENABLE_OPTIONAL_STRINGMAKER)
CATCH_CONFIG_CPP17_BYTE // Override std::byte support detection (Catch provides a StringMaker specialization by default)
> `CATCH_CONFIG_CPP17_STRING_VIEW` was [introduced](https://github.com/catchorg/Catch2/issues/1376) in Catch 2.4.1.
Catch contains basic compiler/standard detection and attempts to use
some C++17 features whenever appropriate. This automatic detection
@@ -209,9 +213,14 @@ By default, Catch does not stringify some types from the standard library. This
CATCH_CONFIG_ENABLE_OPTIONAL_STRINGMAKER // Provide StringMaker specialization for std::optional (on C++17)
CATCH_CONFIG_ENABLE_ALL_STRINGMAKERS // Defines all of the above
> `CATCH_CONFIG_ENABLE_VARIANT_STRINGMAKER` was [introduced](https://github.com/catchorg/Catch2/issues/1380) in Catch 2.4.1.
> `CATCH_CONFIG_ENABLE_OPTIONAL_STRINGMAKER` was [introduced](https://github.com/catchorg/Catch2/issues/1510) in Catch 2.6.0.
## Disabling exceptions
> Introduced in Catch 2.4.0.
By default, Catch2 uses exceptions to signal errors and to abort tests
when an assertion from the `REQUIRE` family of assertions fails. We also
provide an experimental support for disabling exceptions. Catch2 should

View File

@@ -1,6 +1,13 @@
<a id="top"></a>
# Contributing to Catch
**Contents**<br>
[Branches](#branches)<br>
[Directory structure](#directory-structure)<br>
[Testing your changes](#testing-your-changes)<br>
[Documenting your code](#documenting-your-code)<br>
[Code constructs to watch out for](#code-constructs-to-watch-out-for)<br>
So you want to contribute something to Catch? That's great! Whether it's a bug fix, a new feature, support for
additional compilers - or just a fix to the documentation - all contributions are very welcome and very much appreciated.
Of course so are bug reports and other comments and questions.
@@ -75,6 +82,59 @@ before you do so, you need to check that the introduced changes are indeed
intentional.
## Documenting your code
If you have added new feature to Catch2, it needs documentation, so that
other people can use it as well. This section collects some technical
information that you will need for updating Catch2's documentation, and
possibly some generic advise as well.
First, the technicalities:
* We introduced version tags to the documentation, which show users in
which version a specific feature was introduced. This means that newly
written documentation should be tagged with a placeholder, that will
be replaced with the actual version upon release. There are 2 styles
of placeholders used through the documentation, you should pick one that
fits your text better (if in doubt, take a look at the existing version
tags for other features).
* `> [Introduced](link-to-issue-or-PR) in Catch X.Y.Z` - this
placeholder is usually used after a section heading
* `> X (Y and Z) was [introduced](link-to-issue-or-PR) in Catch X.Y.Z`
- this placeholder is used when you need to tag a subpart of something,
e.g. list
* Crosslinks to different pages should target the `top` anchor, like this
`[link to contributing](contributing.md#top)`.
* If you have introduced a new document, there is a simple template you
should use. It provides you with the top anchor mentioned above, and also
with a backlink to the top of the documentation:
```markdown
<a id="top"></a>
# Cool feature
Text that explains how to use the cool feature.
---
[Home](Readme.md#top)
```
* For pages with more than 4 subheadings, we provide a table of contents
(ToC) at the top of the page. Because GitHub markdown does not support
automatic generation of ToC, it has to be handled semi-manually. Thus,
if you've added a new subheading to some page, you should add it to the
ToC. This can be done either manually, or by running the
`updateDocumentToC.py` script in the `scripts/` folder.
Now, for the generic tips:
* Usage examples are good
* Don't be afraid to introduce new pages
* Try to be reasonably consistent with the surrounding documentation
## Code constructs to watch out for
This section is a (sadly incomplete) listing of various constructs that

View File

@@ -1,6 +1,8 @@
<a id="top"></a>
# Data Generators
> Introduced in Catch 2.6.0.
Data generators (also known as _data driven/parametrized test cases_)
let you reuse the same set of assertions across different input values.
In Catch2, this means that they respect the ordering and nesting
@@ -49,6 +51,8 @@ a test case,
* `RandomFloatGenerator<Float>` -- generates random Floats from range
* `RangeGenerator<T>` -- generates all values inside a specific range
> `ChunkGenerator<T>`, `RandomIntegerGenerator<Integral>`, `RandomFloatGenerator<Float>` and `RangeGenerator<T>` were introduced in Catch 2.7.0.
The generators also have associated helper functions that infer their
type, making their usage much nicer. These are
@@ -64,6 +68,7 @@ type, making their usage much nicer. These are
* `range(start, end)` for `RangeGenerator<T>` with a step size of `1`
* `range(start, end, step)` for `RangeGenerator<T>` with a custom step size
> `chunk()`, `random()` and both `range()` functions were introduced in Catch 2.7.0.
And can be used as shown in the example below to create a generator
that returns 100 odd random number:
@@ -96,6 +101,8 @@ scope and thus capturing references is dangerous. If you need to use
variables inside the generator expression, make sure you thought through
the lifetime implications and use `GENERATE_COPY` or `GENERATE_REF`.**
> `GENERATE_COPY` and `GENERATE_REF` were introduced in Catch 2.7.1.
You can also override the inferred type by using `as<type>` as the first
argument to the macro. This can be useful when dealing with string literals,
if you want them to come out as `std::string`:

View File

@@ -30,6 +30,8 @@ When the last `CHECK` fails in the "Bar" test case, then only one message will b
## Logging without local scope
> [Introduced](https://github.com/catchorg/Catch2/issues/1522) in Catch 2.7.0.
`UNSCOPED_INFO` is similar to `INFO` with two key differences:
- Lifetime of an unscoped message is not tied to its own scope.
@@ -104,6 +106,8 @@ This semicolon will be removed with next major version. It is highly advised to
**UNSCOPED_INFO(** _message expression_ **)**
> [Introduced](https://github.com/catchorg/Catch2/issues/1522) in Catch 2.7.0.
Similar to `INFO`, but messages are not limited to their own scope: They are removed from the buffer after each assertion, section or test case, whichever comes first.
**WARN(** _message expression_ **)**

View File

@@ -45,7 +45,16 @@ Each of the provided `std::string` matchers also takes an optional second argume
### Vector matchers
The vector matchers are `Contains`, `VectorContains` and `Equals`. `VectorContains` looks for a single element in the matched vector, `Contains` looks for a set (vector) of elements inside the matched vector.
Catch2 currently provides 5 built-in matchers that work on `std::vector`.
These are
* `Contains` which checks whether a specified vector is present in the result
* `VectorContains` which checks whether a specified element is present in the result
* `Equals` which checks whether the result is exactly equal (order matters) to a specific vector
* `UnorderedEquals` which checks whether the result is equal to a specific vector under a permutation
* `Approx` which checks whether the result is "approx-equal" (order matters, but comparison is done via `Approx`) to a specific vector
> Approx matcher was [introduced](https://github.com/catchorg/Catch2/issues/1499) in Catch 2.7.2.
### Floating point matchers
The floating point matchers are `WithinULP` and `WithinAbs`. `WithinAbs` accepts floating point numbers that are within a certain margin of target. `WithinULP` performs an [ULP](https://en.wikipedia.org/wiki/Unit_in_the_last_place)-based comparison of two floating point numbers and accepts them if they are less than certain number of ULPs apart.

View File

@@ -112,6 +112,9 @@ SpECTRE is a code for multi-scale, multi-physics problems in astrophysics and gr
### [Standardese](https://github.com/foonathan/standardese)
Standardese aims to be a nextgen Doxygen.
### [PopHead](https://github.com/SPC-Some-Polish-Coders/PopHead)
A 2D, Zombie, RPG game which is being made on our own engine.
---
[Home](Readme.md#top)

View File

@@ -59,6 +59,8 @@ TEST_CASE( "SUCCEED showcase" ) {
* `STATIC_REQUIRE`
> [Introduced](https://github.com/catchorg/Catch2/issues/1362) in Catch 2.4.2.
`STATIC_REQUIRE( expr )` is a macro that can be used the same way as a
`static_assert`, but also registers the success with Catch2, so it is
reported as a success at runtime. The whole check can also be deferred
@@ -132,6 +134,8 @@ ANON_TEST_CASE() {
* `DYNAMIC_SECTION`
> Introduced in Catch 2.3.0.
`DYNAMIC_SECTION` is a `SECTION` where the user can use `operator<<` to
create the final name for that section. This can be useful with e.g.
generators, or when creating a `SECTION` dynamically, within a loop.

View File

@@ -2,6 +2,7 @@
# Release notes
**Contents**<br>
[2.9.2](#292)<br>
[2.9.1](#291)<br>
[2.9.0](#290)<br>
[2.8.0](#280)<br>
@@ -26,6 +27,42 @@
[Older versions](#older-versions)<br>
[Even Older versions](#even-older-versions)<br>
## 2.9.2
### Fixes
* `ChunkGenerator` can now be used with chunks of size 0 (#1671)
* Nested subsections are now run properly when specific section is run via the `-c` argument (#1670, #1673)
* Catch2 now consistently uses `_WIN32` to detect Windows platform (#1676)
* `TEMPLATE_LIST_TEST_CASE` now support non-default constructible type lists (#1697)
* Fixed a crash in the XMLReporter when a benchmark throws exception during warmup (#1706)
* Fixed a possible infinite loop in CompactReporter (#1715)
* Fixed `-w NoTests` returning 0 even when no tests were matched (#1449, #1683, #1684)
* Fixed matcher compilation under Obj-C++ (#1661)
### Improvements
* `RepeatGenerator` and `FixedValuesGenerator` now fail to compile when used with `bool` (#1692)
* Previously they would fail at runtime.
* Catch2 now supports Android's debug logging for its debug output (#1710)
* Catch2 now detects and configures itself for the RTX platform (#1693)
* You still need to pass `--benchmark-no-analysis` if you are using benchmarking under RTX
* Removed a "storage class is not first" warning when compiling Catch2 with PGI compiler (#1717)
### Miscellaneous
* Documentation now contains indication when a specific feature was introduced (#1695)
* These start with Catch2 v2.3.0, (a bit over a year ago).
* `docs/contributing.md` has been updated to provide contributors guidance on how to add these to newly written documentation
* Various other documentation improvements
* ToC fixes
* Documented `--order` and `--rng-seed` command line options
* Benchmarking documentation now clearly states that it requires opt-in
* Documented `CATCH_CONFIG_CPP17_OPTIONAL` and `CATCH_CONFIG_CPP17_BYTE` macros
* Properly documented built-in vector matchers
* Improved `*_THROWS_MATCHES` documentation a bit
* CMake config file is now arch-independent even if `CMAKE_SIZEOF_VOID_P` is in CMake cache (#1660)
* `CatchAddTests` now properly escapes `[` and `]` in test names (#1634, #1698)
## 2.9.1
### Fixes
@@ -88,7 +125,7 @@
### Improvements
* Reporters now print out the filters applied to test cases (#1550, #1585)
* Added `GENERATE_COPY` and `GENERATE_VAR` macros that can use variables inside the generator expression
* Added `GENERATE_COPY` and `GENERATE_REF` macros that can use variables inside the generator expression
* Because of the significant danger of lifetime issues, the default `GENERATE` macro still does not allow variables
* The `map` generator helper now deduces the mapped return type (#1576)

View File

@@ -84,10 +84,13 @@ This macro maps onto ```TEST_CASE``` and works in the same way, except that the
These macros map onto ```SECTION```s except that the section names are the _something_s prefixed by "given: ", "when: " or "then: " respectively.
* **AND_GIVEN(** _something_ **)**
* **AND_WHEN(** _something_ **)**
* **AND_THEN(** _something_ **)**
Similar to ```WHEN``` and ```THEN``` except that the prefixes start with "and ". These are used to chain ```WHEN```s and ```THEN```s together.
Similar to ```GIVEN```, ```WHEN``` and ```THEN``` except that the prefixes start with "and ". These are used to chain ```GIVEN```s, ```WHEN```s and ```THEN```s together.
> `AND_GIVEN` was [introduced](https://github.com/catchorg/Catch2/issues/1360) in Catch 2.4.0.
When any of these macros are used the console reporter recognises them and formats the test case header such that the Givens, Whens and Thens are aligned to aid readability.
@@ -101,6 +104,8 @@ by types, in the form of `TEMPLATE_TEST_CASE`,
* **TEMPLATE_TEST_CASE(** _test name_ , _tags_, _type1_, _type2_, ..., _typen_ **)**
> [Introduced](https://github.com/catchorg/Catch2/issues/1437) in Catch 2.5.0.
_test name_ and _tag_ are exactly the same as they are in `TEST_CASE`,
with the difference that the tag string must be provided (however, it
can be empty). _type1_ through _typen_ is the list of types for which
@@ -151,6 +156,8 @@ TEMPLATE_TEST_CASE( "vectors can be sized and resized", "[vector][template]", in
* **TEMPLATE_PRODUCT_TEST_CASE(** _test name_ , _tags_, (_template-type1_, _template-type2_, ..., _template-typen_), (_template-arg1_, _template-arg2_, ..., _template-argm_) **)**
> [Introduced](https://github.com/catchorg/Catch2/issues/1468) in Catch 2.6.0.
_template-type1_ through _template-typen_ is list of template template
types which should be combined with each of _template-arg1_ through
_template-argm_, resulting in _n * m_ test cases. Inside the test case,
@@ -194,6 +201,8 @@ is very high and should not be encountered in practice._
* **TEMPLATE_LIST_TEST_CASE(** _test name_, _tags_, _type list_ **)**
> [Introduced](https://github.com/catchorg/Catch2/issues/1627) in Catch 2.9.0.
_type list_ is a generic list of types on which test case should be instantiated.
List can be `std::tuple`, `boost::mpl::list`, `boost::mp11::mp_list` or anything with
`template <typename...>` signature.
@@ -212,6 +221,8 @@ TEMPLATE_LIST_TEST_CASE("Template test case with test types specified inside std
## Signature based parametrised test cases
> [Introduced](https://github.com/catchorg/Catch2/issues/1609) in Catch 2.8.0.
In addition to [type parametrised test cases](#type-parametrised-test-cases) Catch2 also supports
signature base parametrised test cases, in form of `TEMPLATE_TEST_CASE_SIG` and `TEMPLATE_PRODUCT_TEST_CASE_SIG`.
These test cases have similar syntax like [type parametrised test cases](#type-parametrised-test-cases), with one

View File

@@ -1,6 +1,8 @@
<a id="top"></a>
# Test fixtures
## Defining test fixtures
Although Catch allows you to group tests together as sections within a test case, it can still be convenient, sometimes, to group them using a more traditional test fixture. Catch fully supports this too. You define the test fixture as a simple structure:
```c++
@@ -84,6 +86,9 @@ _While there is an upper limit on the number of types you can specify
in single `TEMPLATE_TEST_CASE_METHOD` or `TEMPLATE_PRODUCT_TEST_CASE_METHOD`,
the limit is very high and should not be encountered in practice._
## Signature-based parametrised test fixtures
> [Introduced](https://github.com/catchorg/Catch2/issues/1609) in Catch 2.8.0.
Catch2 also provides `TEMPLATE_TEST_CASE_METHOD_SIG` and `TEMPLATE_PRODUCT_TEST_CASE_METHOD_SIG` to support
fixtures using non-type template parameters. These test cases work similar to `TEMPLATE_TEST_CASE_METHOD` and `TEMPLATE_PRODUCT_TEST_CASE_METHOD`,
@@ -100,6 +105,13 @@ TEMPLATE_TEST_CASE_METHOD_SIG(Nttp_Fixture, "A TEMPLATE_TEST_CASE_METHOD_SIG bas
REQUIRE(Nttp_Fixture<V>::value > 0);
}
template<typename T>
struct Template_Fixture_2 {
Template_Fixture_2() {}
T m_a;
};
template< typename T, size_t V>
struct Template_Foo_2 {
size_t size() { return V; }
@@ -111,6 +123,8 @@ TEMPLATE_PRODUCT_TEST_CASE_METHOD_SIG(Template_Fixture_2, "A TEMPLATE_PRODUCT_TE
}
```
## Template fixtures with types specified in template type lists
Catch2 also provides `TEMPLATE_LIST_TEST_CASE_METHOD` to support template fixtures with types specified in
template type lists like `std::tuple`, `boost::mpl::list` or `boost::mp11::mp_list`. This test case works the same as `TEMPLATE_TEST_CASE_METHOD`,
only difference is the source of types. This allows you to reuse the template type list in multiple test cases.

View File

@@ -71,6 +71,8 @@ CATCH_TRANSLATE_EXCEPTION( MyType& ex ) {
## Enums
> Introduced in Catch 2.8.0.
Enums that already have a `<<` overload for `std::ostream` will convert to strings as expected.
If you only need to convert enums to strings for test reporting purposes you can provide a `StringMaker` specialisations as any other type.
However, as a convenience, Catch provides the `REGISTER_ENUM` helper macro that will generate the `StringMaker` specialiation for you with minimal code.
@@ -108,6 +110,8 @@ TEST_CASE() {
## Floating point precision
> [Introduced](https://github.com/catchorg/Catch2/issues/1614) in Catch 2.8.0.
Catch provides a built-in `StringMaker` specialization for both `float`
and `double`. By default, it uses what we think is a reasonable precision,
but you can customize it by modifying the `precision` static variable

View File

@@ -11,7 +11,7 @@
#define CATCH_VERSION_MAJOR 2
#define CATCH_VERSION_MINOR 9
#define CATCH_VERSION_PATCH 1
#define CATCH_VERSION_PATCH 2
#ifdef __clang__
# pragma clang system_header

View File

@@ -184,6 +184,18 @@
#define CATCH_INTERNAL_CONFIG_COUNTER
#endif
////////////////////////////////////////////////////////////////////////////////
// RTX is a special version of Windows that is real time.
// This means that it is detected as Windows, but does not provide
// the same set of capabilities as real Windows does.
#if defined(UNDER_RTSS) || defined(RTX64_BUILD)
#define CATCH_INTERNAL_CONFIG_NO_WINDOWS_SEH
#define CATCH_INTERNAL_CONFIG_NO_ASYNC
#define CATCH_CONFIG_COLOUR_NONE
#endif
////////////////////////////////////////////////////////////////////////////////
// Check if string_view is available and usable
// The check is split apart to work around v140 (VS2015) preprocessor issue...
@@ -201,6 +213,14 @@
# endif // __has_include(<optional>) && defined(CATCH_CPP17_OR_GREATER)
#endif // __has_include
////////////////////////////////////////////////////////////////////////////////
// Check if byte is available and usable
#if defined(__has_include)
# if __has_include(<cstddef>) && defined(CATCH_CPP17_OR_GREATER)
# define CATCH_INTERNAL_CONFIG_CPP17_BYTE
# endif // __has_include(<cstddef>) && defined(CATCH_CPP17_OR_GREATER)
#endif // __has_include
////////////////////////////////////////////////////////////////////////////////
// Check if variant is available and usable
#if defined(__has_include)
@@ -256,6 +276,11 @@
# define CATCH_CONFIG_CPP17_VARIANT
#endif
#if defined(CATCH_INTERNAL_CONFIG_CPP17_BYTE) && !defined(CATCH_CONFIG_NO_CPP17_BYTE) && !defined(CATCH_CONFIG_CPP17_BYTE)
# define CATCH_CONFIG_CPP17_BYTE
#endif
#if defined(CATCH_CONFIG_EXPERIMENTAL_REDIRECT)
# define CATCH_INTERNAL_CONFIG_NEW_CAPTURE
#endif
@@ -272,7 +297,7 @@
# define CATCH_CONFIG_POLYFILL_ISNAN
#endif
#if defined(CATCH_INTERNAL_CONFIG_USE_ASYNC) && !defined(CATCH_CONFIG_NO_USE_ASYNC) && !defined(CATCH_CONFIG_USE_ASYNC)
#if defined(CATCH_INTERNAL_CONFIG_USE_ASYNC) && !defined(CATCH_INTERNAL_CONFIG_NO_ASYNC) && !defined(CATCH_CONFIG_NO_USE_ASYNC) && !defined(CATCH_CONFIG_USE_ASYNC)
# define CATCH_CONFIG_USE_ASYNC
#endif

View File

@@ -11,7 +11,16 @@
#include "catch_platform.h"
#include "catch_windows_h_proxy.h"
#ifdef CATCH_PLATFORM_WINDOWS
#if defined(__ANDROID__)
#include <android/log.h>
namespace Catch {
void writeToDebugConsole( std::string const& text ) {
__android_log_print( ANDROID_LOG_DEBUG, "Catch", text.c_str() );
}
}
#elif defined(CATCH_PLATFORM_WINDOWS)
namespace Catch {
void writeToDebugConsole( std::string const& text ) {

View File

@@ -97,7 +97,7 @@ namespace Catch {
// 32kb for the alternate stack seems to be sufficient. However, this value
// is experimentally determined, so that's not guaranteed.
constexpr static std::size_t sigStackSize = 32768 >= MINSIGSTKSZ ? 32768 : MINSIGSTKSZ;
static constexpr std::size_t sigStackSize = 32768 >= MINSIGSTKSZ ? 32768 : MINSIGSTKSZ;
static SignalDefs signalDefs[] = {
{ SIGINT, "SIGINT - Terminal interrupt signal" },

View File

@@ -70,6 +70,9 @@ namespace Generators {
template<typename T>
class FixedValuesGenerator final : public IGenerator<T> {
static_assert(!std::is_same<T, bool>::value,
"ValuesGenerator does not support bools because of std::vector<bool>"
"specialization, use SingleValue Generator instead.");
std::vector<T> m_values;
size_t m_idx = 0;
public:

View File

@@ -91,6 +91,9 @@ namespace Generators {
template <typename T>
class RepeatGenerator : public IGenerator<T> {
static_assert(!std::is_same<T, bool>::value,
"RepeatGenerator currently does not support bools"
"because of std::vector<bool> specialization");
GeneratorWrapper<T> m_generator;
mutable std::vector<T> m_returned;
size_t m_target_repeats;
@@ -205,12 +208,14 @@ namespace Generators {
m_chunk_size(size), m_generator(std::move(generator))
{
m_chunk.reserve(m_chunk_size);
m_chunk.push_back(m_generator.get());
for (size_t i = 1; i < m_chunk_size; ++i) {
if (!m_generator.next()) {
Catch::throw_exception(GeneratorException("Not enough values to initialize the first chunk"));
}
if (m_chunk_size != 0) {
m_chunk.push_back(m_generator.get());
for (size_t i = 1; i < m_chunk_size; ++i) {
if (!m_generator.next()) {
Catch::throw_exception(GeneratorException("Not enough values to initialize the first chunk"));
}
m_chunk.push_back(m_generator.get());
}
}
}
std::vector<T> const& get() const override {

View File

@@ -28,6 +28,7 @@ namespace Catch {
virtual std::vector<TestCase> const& getAllTestsSorted( IConfig const& config ) const = 0;
};
bool isThrowSafe( TestCase const& testCase, IConfig const& config );
bool matchTest( TestCase const& testCase, TestSpec const& testSpec, IConfig const& config );
std::vector<TestCase> filterTests( std::vector<TestCase> const& testCases, TestSpec const& testSpec, IConfig const& config );
std::vector<TestCase> const& getAllTestCasesSorted( IConfig const& config );

View File

@@ -84,9 +84,18 @@ namespace Catch {
}
std::string TagInfo::all() const {
std::string out;
for( auto const& spelling : spellings )
out += "[" + spelling + "]";
size_t size = 0;
for (auto const& spelling : spellings) {
// Add 2 for the brackes
size += spelling.size() + 2;
}
std::string out; out.reserve(size);
for (auto const& spelling : spellings) {
out += '[';
out += spelling;
out += ']';
}
return out;
}

View File

@@ -44,6 +44,15 @@ namespace Matchers {
virtual bool match( ObjectT const& arg ) const = 0;
};
#if defined(__OBJC__)
// Hack to fix Catch GH issue #1661. Could use id for generic Object support.
// use of const for Object pointers is very uncommon and under ARC it causes some kind of signature mismatch that breaks compilation
template<>
struct MatcherMethod<NSString*> {
virtual bool match( NSString* arg ) const = 0;
};
#endif
#ifdef __clang__
# pragma clang diagnostic pop
#endif

View File

@@ -116,7 +116,7 @@ namespace Catch {
arcSafeRelease( m_substr );
}
bool match( NSString* const& str ) const override {
bool match( NSString* str ) const override {
return false;
}
@@ -126,7 +126,7 @@ namespace Catch {
struct Equals : StringHolder {
Equals( NSString* substr ) : StringHolder( substr ){}
bool match( NSString* const& str ) const override {
bool match( NSString* str ) const override {
return (str != nil || m_substr == nil ) &&
[str isEqualToString:m_substr];
}
@@ -139,7 +139,7 @@ namespace Catch {
struct Contains : StringHolder {
Contains( NSString* substr ) : StringHolder( substr ){}
bool match( NSString* const& str ) const override {
bool match( NSString* str ) const override {
return (str != nil || m_substr == nil ) &&
[str rangeOfString:m_substr].location != NSNotFound;
}
@@ -152,7 +152,7 @@ namespace Catch {
struct StartsWith : StringHolder {
StartsWith( NSString* substr ) : StringHolder( substr ){}
bool match( NSString* const& str ) const override {
bool match( NSString* str ) const override {
return (str != nil || m_substr == nil ) &&
[str rangeOfString:m_substr].location == 0;
}
@@ -164,7 +164,7 @@ namespace Catch {
struct EndsWith : StringHolder {
EndsWith( NSString* substr ) : StringHolder( substr ){}
bool match( NSString* const& str ) const override {
bool match( NSString* str ) const override {
return (str != nil || m_substr == nil ) &&
[str rangeOfString:m_substr].location == [str length] - [m_substr length];
}

View File

@@ -25,6 +25,8 @@
#include <cstdlib>
#include <iomanip>
#include <set>
#include <iterator>
namespace Catch {
@@ -58,46 +60,53 @@ namespace Catch {
return ret;
}
class TestGroup {
public:
explicit TestGroup(std::shared_ptr<Config> const& config)
: m_config{config}
, m_context{config, makeReporter(config)}
{
auto const& allTestCases = getAllTestCasesSorted(*m_config);
m_matches = m_config->testSpec().matchesByFilter(allTestCases, *m_config);
Catch::Totals runTests(std::shared_ptr<Config> const& config) {
auto reporter = makeReporter(config);
RunContext context(config, std::move(reporter));
Totals totals;
context.testGroupStarting(config->name(), 1, 1);
TestSpec testSpec = config->testSpec();
auto const& allTestCases = getAllTestCasesSorted(*config);
for (auto const& testCase : allTestCases) {
bool matching = (!testSpec.hasFilters() && !testCase.isHidden()) ||
(testSpec.hasFilters() && matchTest(testCase, testSpec, *config));
if (!context.aborting() && matching)
totals += context.runTest(testCase);
else
context.reporter().skipTest(testCase);
if (m_matches.empty()) {
for (auto const& test : allTestCases)
if (!test.isHidden())
m_tests.emplace(&test);
} else {
for (auto const& match : m_matches)
m_tests.insert(match.tests.begin(), match.tests.end());
}
}
if (config->warnAboutNoTests() && totals.testCases.total() == 0) {
ReusableStringStream testConfig;
bool first = true;
for (const auto& input : config->getTestsOrTags()) {
if (!first) { testConfig << ' '; }
first = false;
testConfig << input;
Totals execute() {
Totals totals;
m_context.testGroupStarting(m_config->name(), 1, 1);
for (auto const& testCase : m_tests) {
if (!m_context.aborting())
totals += m_context.runTest(*testCase);
else
m_context.reporter().skipTest(*testCase);
}
context.reporter().noMatchingTestCases(testConfig.str());
totals.error = -1;
for (auto const& match : m_matches) {
if (match.tests.empty()) {
m_context.reporter().noMatchingTestCases(match.name);
totals.error = -1;
}
}
m_context.testGroupEnded(m_config->name(), totals, 1, 1);
return totals;
}
context.testGroupEnded(config->name(), totals, 1, 1);
return totals;
}
private:
using Tests = std::set<TestCase const*>;
std::shared_ptr<Config> m_config;
RunContext m_context;
Tests m_tests;
TestSpec::Matches m_matches;
};
void applyFilenamesAsTags(Catch::IConfig const& config) {
auto& tests = const_cast<std::vector<TestCase>&>(getAllTestCasesSorted(config));
@@ -197,7 +206,7 @@ namespace Catch {
return 0;
}
#if defined(CATCH_CONFIG_WCHAR) && defined(WIN32) && defined(UNICODE)
#if defined(CATCH_CONFIG_WCHAR) && defined(_WIN32) && defined(UNICODE)
int Session::applyCommandLine( int argc, wchar_t const * const * argv ) {
char **utf8Argv = new char *[ argc ];
@@ -274,7 +283,12 @@ namespace Catch {
if( Option<std::size_t> listed = list( m_config ) )
return static_cast<int>( *listed );
auto totals = runTests( m_config );
TestGroup tests { m_config };
auto const totals = tests.execute();
if( m_config->warnAboutNoTests() && totals.error == -1 )
return 2;
// Note that on unices only the lower 8 bits are usually used, clamping
// the return value to 255 prevents false negative when some multiple
// of 256 tests has failed

View File

@@ -26,7 +26,7 @@ namespace Catch {
void libIdentify();
int applyCommandLine( int argc, char const * const * argv );
#if defined(CATCH_CONFIG_WCHAR) && defined(WIN32) && defined(UNICODE)
#if defined(CATCH_CONFIG_WCHAR) && defined(_WIN32) && defined(UNICODE)
int applyCommandLine( int argc, wchar_t const * const * argv );
#endif

View File

@@ -36,8 +36,13 @@ namespace Catch {
}
return sorted;
}
bool isThrowSafe( TestCase const& testCase, IConfig const& config ) {
return !testCase.throws() || config.allowThrows();
}
bool matchTest( TestCase const& testCase, TestSpec const& testSpec, IConfig const& config ) {
return testSpec.matches( testCase ) && ( config.allowThrows() || !testCase.throws() );
return testSpec.matches( testCase ) && isThrowSafe( testCase, config );
}
void enforceNoDuplicateTestCases( std::vector<TestCase> const& functions ) {

View File

@@ -23,6 +23,8 @@ namespace Catch {
struct IConfig;
std::vector<TestCase> sortTests( IConfig const& config, std::vector<TestCase> const& unsortedTestCases );
bool isThrowSafe( TestCase const& testCase, IConfig const& config );
bool matchTest( TestCase const& testCase, TestSpec const& testSpec, IConfig const& config );
void enforceNoDuplicateTestCases( std::vector<TestCase> const& functions );

View File

@@ -139,7 +139,7 @@ namespace TestCaseTracking {
m_runState = CompletedSuccessfully;
break;
case ExecutingChildren:
if( m_children.empty() || m_children.back()->isComplete() )
if( std::all_of(m_children.begin(), m_children.end(), [](ITrackerPtr const& t){ return t->isComplete(); }) )
m_runState = CompletedSuccessfully;
break;

View File

@@ -247,7 +247,7 @@ struct AutoReg : NonCopyable {
} \
};\
static int INTERNAL_CATCH_UNIQUE_NAME( globalRegistrar ) = [](){ \
using TestInit = decltype(convert<TestName>(TmplList {})); \
using TestInit = decltype(convert<TestName>(std::declval<TmplList>())); \
TestInit t; \
t.reg_tests(); \
return 0; \
@@ -374,7 +374,7 @@ struct AutoReg : NonCopyable {
}\
};\
static int INTERNAL_CATCH_UNIQUE_NAME( globalRegistrar ) = [](){\
using TestInit = decltype(convert<TestNameClass>(TmplList {}));\
using TestInit = decltype(convert<TestNameClass>(std::declval<TmplList>()));\
TestInit t;\
t.reg_tests();\
return 0;\

View File

@@ -7,6 +7,7 @@
#include "catch_test_spec.h"
#include "catch_string_manip.h"
#include "catch_interfaces_config.h"
#include <algorithm>
#include <string>
@@ -15,45 +16,80 @@
namespace Catch {
TestSpec::Pattern::~Pattern() = default;
TestSpec::NamePattern::~NamePattern() = default;
TestSpec::TagPattern::~TagPattern() = default;
TestSpec::ExcludedPattern::~ExcludedPattern() = default;
TestSpec::NamePattern::NamePattern( std::string const& name )
: m_wildcardPattern( toLower( name ), CaseSensitive::No )
TestSpec::Pattern::Pattern( std::string const& name )
: m_name( name )
{}
TestSpec::Pattern::~Pattern() = default;
std::string const& TestSpec::Pattern::name() const {
return m_name;
}
TestSpec::NamePattern::NamePattern( std::string const& name, std::string const& filterString )
: Pattern( filterString )
, m_wildcardPattern( toLower( name ), CaseSensitive::No )
{}
bool TestSpec::NamePattern::matches( TestCaseInfo const& testCase ) const {
return m_wildcardPattern.matches( toLower( testCase.name ) );
}
TestSpec::TagPattern::TagPattern( std::string const& tag ) : m_tag( toLower( tag ) ) {}
TestSpec::TagPattern::TagPattern( std::string const& tag, std::string const& filterString )
: Pattern( filterString )
, m_tag( toLower( tag ) )
{}
bool TestSpec::TagPattern::matches( TestCaseInfo const& testCase ) const {
return std::find(begin(testCase.lcaseTags),
end(testCase.lcaseTags),
m_tag) != end(testCase.lcaseTags);
}
TestSpec::ExcludedPattern::ExcludedPattern( PatternPtr const& underlyingPattern ) : m_underlyingPattern( underlyingPattern ) {}
bool TestSpec::ExcludedPattern::matches( TestCaseInfo const& testCase ) const { return !m_underlyingPattern->matches( testCase ); }
TestSpec::ExcludedPattern::ExcludedPattern( PatternPtr const& underlyingPattern )
: Pattern( underlyingPattern->name() )
, m_underlyingPattern( underlyingPattern )
{}
bool TestSpec::ExcludedPattern::matches( TestCaseInfo const& testCase ) const {
return !m_underlyingPattern->matches( testCase );
}
bool TestSpec::Filter::matches( TestCaseInfo const& testCase ) const {
// All patterns in a filter must match for the filter to be a match
for( auto const& pattern : m_patterns ) {
if( !pattern->matches( testCase ) )
return false;
}
return true;
return std::all_of( m_patterns.begin(), m_patterns.end(), [&]( PatternPtr const& p ){ return p->matches( testCase ); } );
}
std::string TestSpec::Filter::name() const {
std::string name;
for( auto const& p : m_patterns )
name += p->name();
return name;
}
bool TestSpec::hasFilters() const {
return !m_filters.empty();
}
bool TestSpec::matches( TestCaseInfo const& testCase ) const {
// A TestSpec matches if any filter matches
for( auto const& filter : m_filters )
if( filter.matches( testCase ) )
return true;
return false;
return std::any_of( m_filters.begin(), m_filters.end(), [&]( Filter const& f ){ return f.matches( testCase ); } );
}
TestSpec::Matches TestSpec::matchesByFilter( std::vector<TestCase> const& testCases, IConfig const& config ) const
{
Matches matches( m_filters.size() );
std::transform( m_filters.begin(), m_filters.end(), matches.begin(), [&]( Filter const& filter ){
std::vector<TestCase const*> currentMatches;
for( auto const& test : testCases )
if( isThrowSafe( test, config ) && filter.matches( test ) )
currentMatches.emplace_back( &test );
return FilterMatch{ filter.name(), currentMatches };
} );
return matches;
}
}

View File

@@ -22,17 +22,23 @@
namespace Catch {
struct IConfig;
class TestSpec {
struct Pattern {
class Pattern {
public:
explicit Pattern( std::string const& name );
virtual ~Pattern();
virtual bool matches( TestCaseInfo const& testCase ) const = 0;
std::string const& name() const;
private:
std::string const m_name;
};
using PatternPtr = std::shared_ptr<Pattern>;
class NamePattern : public Pattern {
public:
NamePattern( std::string const& name );
virtual ~NamePattern();
explicit NamePattern( std::string const& name, std::string const& filterString );
bool matches( TestCaseInfo const& testCase ) const override;
private:
WildcardPattern m_wildcardPattern;
@@ -40,8 +46,7 @@ namespace Catch {
class TagPattern : public Pattern {
public:
TagPattern( std::string const& tag );
virtual ~TagPattern();
explicit TagPattern( std::string const& tag, std::string const& filterString );
bool matches( TestCaseInfo const& testCase ) const override;
private:
std::string m_tag;
@@ -49,8 +54,7 @@ namespace Catch {
class ExcludedPattern : public Pattern {
public:
ExcludedPattern( PatternPtr const& underlyingPattern );
virtual ~ExcludedPattern();
explicit ExcludedPattern( PatternPtr const& underlyingPattern );
bool matches( TestCaseInfo const& testCase ) const override;
private:
PatternPtr m_underlyingPattern;
@@ -60,11 +64,19 @@ namespace Catch {
std::vector<PatternPtr> m_patterns;
bool matches( TestCaseInfo const& testCase ) const;
std::string name() const;
};
public:
struct FilterMatch {
std::string name;
std::vector<TestCase const*> tests;
};
using Matches = std::vector<FilterMatch>;
bool hasFilters() const;
bool matches( TestCaseInfo const& testCase ) const;
Matches matchesByFilter( std::vector<TestCase> const& testCases, IConfig const& config ) const;
private:
std::vector<Filter> m_filters;

View File

@@ -14,64 +14,125 @@ namespace Catch {
TestSpecParser& TestSpecParser::parse( std::string const& arg ) {
m_mode = None;
m_exclusion = false;
m_start = std::string::npos;
m_arg = m_tagAliases->expandAliases( arg );
m_escapeChars.clear();
m_substring.reserve(m_arg.size());
m_patternName.reserve(m_arg.size());
for( m_pos = 0; m_pos < m_arg.size(); ++m_pos )
visitChar( m_arg[m_pos] );
if( m_mode == Name )
addPattern<TestSpec::NamePattern>();
endMode();
return *this;
}
TestSpec TestSpecParser::testSpec() {
addFilter();
return m_testSpec;
}
void TestSpecParser::visitChar( char c ) {
if( m_mode == None ) {
switch( c ) {
case ' ': return;
case '~': m_exclusion = true; return;
case '[': return startNewMode( Tag, ++m_pos );
case '"': return startNewMode( QuotedName, ++m_pos );
case '\\': return escape();
default: startNewMode( Name, m_pos ); break;
}
if( c == ',' ) {
endMode();
addFilter();
return;
}
if( m_mode == Name ) {
if( c == ',' ) {
addPattern<TestSpec::NamePattern>();
addFilter();
}
else if( c == '[' ) {
if( subString() == "exclude:" )
m_exclusion = true;
else
addPattern<TestSpec::NamePattern>();
startNewMode( Tag, ++m_pos );
}
else if( c == '\\' )
escape();
switch( m_mode ) {
case None:
if( processNoneChar( c ) )
return;
break;
case Name:
processNameChar( c );
break;
case EscapedName:
endMode();
break;
default:
case Tag:
case QuotedName:
if( processOtherChar( c ) )
return;
break;
}
else if( m_mode == EscapedName )
m_mode = Name;
else if( m_mode == QuotedName && c == '"' )
addPattern<TestSpec::NamePattern>();
else if( m_mode == Tag && c == ']' )
addPattern<TestSpec::TagPattern>();
m_substring += c;
if( !isControlChar( c ) )
m_patternName += c;
}
void TestSpecParser::startNewMode( Mode mode, std::size_t start ) {
// Two of the processing methods return true to signal the caller to return
// without adding the given character to the current pattern strings
bool TestSpecParser::processNoneChar( char c ) {
switch( c ) {
case ' ':
return true;
case '~':
m_exclusion = true;
return false;
case '[':
startNewMode( Tag );
return false;
case '"':
startNewMode( QuotedName );
return false;
case '\\':
escape();
return true;
default:
startNewMode( Name );
return false;
}
}
void TestSpecParser::processNameChar( char c ) {
if( c == '[' ) {
if( m_substring == "exclude:" )
m_exclusion = true;
else
endMode();
startNewMode( Tag );
}
}
bool TestSpecParser::processOtherChar( char c ) {
if( !isControlChar( c ) )
return false;
m_substring += c;
endMode();
return true;
}
void TestSpecParser::startNewMode( Mode mode ) {
m_mode = mode;
m_start = start;
}
void TestSpecParser::endMode() {
switch( m_mode ) {
case Name:
case QuotedName:
return addPattern<TestSpec::NamePattern>();
case Tag:
return addPattern<TestSpec::TagPattern>();
case EscapedName:
return startNewMode( Name );
case None:
default:
return startNewMode( None );
}
}
void TestSpecParser::escape() {
if( m_mode == None )
m_start = m_pos;
m_mode = EscapedName;
m_escapeChars.push_back( m_pos );
}
std::string TestSpecParser::subString() const { return m_arg.substr( m_start, m_pos - m_start ); }
bool TestSpecParser::isControlChar( char c ) const {
switch( m_mode ) {
default:
return false;
case None:
return c == '~';
case Name:
return c == '[';
case EscapedName:
return true;
case QuotedName:
return c == '"';
case Tag:
return c == '[' || c == ']';
}
}
void TestSpecParser::addFilter() {
if( !m_currentFilter.m_patterns.empty() ) {

View File

@@ -23,8 +23,10 @@ namespace Catch {
enum Mode{ None, Name, QuotedName, Tag, EscapedName };
Mode m_mode = None;
bool m_exclusion = false;
std::size_t m_start = std::string::npos, m_pos = 0;
std::size_t m_pos = 0;
std::string m_arg;
std::string m_substring;
std::string m_patternName;
std::vector<std::size_t> m_escapeChars;
TestSpec::Filter m_currentFilter;
TestSpec m_testSpec;
@@ -38,26 +40,32 @@ namespace Catch {
private:
void visitChar( char c );
void startNewMode( Mode mode, std::size_t start );
void startNewMode( Mode mode );
bool processNoneChar( char c );
void processNameChar( char c );
bool processOtherChar( char c );
void endMode();
void escape();
std::string subString() const;
bool isControlChar( char c ) const;
template<typename T>
void addPattern() {
std::string token = subString();
std::string token = m_patternName;
for( std::size_t i = 0; i < m_escapeChars.size(); ++i )
token = token.substr( 0, m_escapeChars[i]-m_start-i ) + token.substr( m_escapeChars[i]-m_start-i+1 );
token = token.substr( 0, m_escapeChars[i] - i ) + token.substr( m_escapeChars[i] -i +1 );
m_escapeChars.clear();
if( startsWith( token, "exclude:" ) ) {
m_exclusion = true;
token = token.substr( 8 );
}
if( !token.empty() ) {
TestSpec::PatternPtr pattern = std::make_shared<T>( token );
TestSpec::PatternPtr pattern = std::make_shared<T>( token, m_substring );
if( m_exclusion )
pattern = std::make_shared<TestSpec::ExcludedPattern>( pattern );
m_currentFilter.m_patterns.push_back( pattern );
}
m_substring.clear();
m_patternName.clear();
m_exclusion = false;
m_mode = None;
}

View File

@@ -170,6 +170,12 @@ std::string StringMaker<wchar_t *>::convert(wchar_t * str) {
}
#endif
#if defined(CATCH_CONFIG_CPP17_BYTE)
#include <cstddef>
std::string StringMaker<std::byte>::convert(std::byte value) {
return ::Catch::Detail::stringify(std::to_integer<unsigned long long>(value));
}
#endif // defined(CATCH_CONFIG_CPP17_BYTE)
std::string StringMaker<int>::convert(int value) {
return ::Catch::Detail::stringify(static_cast<long long>(value));

View File

@@ -210,6 +210,12 @@ namespace Catch {
}
};
#if defined(CATCH_CONFIG_CPP17_BYTE)
template<>
struct StringMaker<std::byte> {
static std::string convert(std::byte value);
};
#endif // defined(CATCH_CONFIG_CPP17_BYTE)
template<>
struct StringMaker<int> {
static std::string convert(int value);

View File

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

View File

@@ -209,24 +209,25 @@ private:
if (itMessage == messages.end())
return;
// using messages.end() directly yields (or auto) compilation error:
std::vector<MessageInfo>::const_iterator itEnd = messages.end();
const std::size_t N = static_cast<std::size_t>(std::distance(itMessage, itEnd));
const auto itEnd = messages.cend();
const auto N = static_cast<std::size_t>(std::distance(itMessage, itEnd));
{
Colour colourGuard(colour);
stream << " with " << pluralise(N, "message") << ':';
}
for (; itMessage != itEnd; ) {
while (itMessage != itEnd) {
// If this assertion is a warning ignore any INFO messages
if (printInfoMessages || itMessage->type != ResultWas::Info) {
stream << " '" << itMessage->message << '\'';
if (++itMessage != itEnd) {
printMessage();
if (itMessage != itEnd) {
Colour colourGuard(dimColour());
stream << " and";
}
continue;
}
++itMessage;
}
}

View File

@@ -220,10 +220,13 @@ namespace Catch {
}
#if defined(CATCH_CONFIG_ENABLE_BENCHMARKING)
void XmlReporter::benchmarkStarting(BenchmarkInfo const &info) {
void XmlReporter::benchmarkPreparing(std::string const& name) {
m_xml.startElement("BenchmarkResults")
.writeAttribute("name", info.name)
.writeAttribute("samples", info.samples)
.writeAttribute("name", name);
}
void XmlReporter::benchmarkStarting(BenchmarkInfo const &info) {
m_xml.writeAttribute("samples", info.samples)
.writeAttribute("resamples", info.resamples)
.writeAttribute("iterations", info.iterations)
.writeAttribute("clockResolution", static_cast<uint64_t>(info.clockResolution))

View File

@@ -51,6 +51,7 @@ namespace Catch {
void testRunEnded(TestRunStats const& testRunStats) override;
#if defined(CATCH_CONFIG_ENABLE_BENCHMARKING)
void benchmarkPreparing(std::string const& name) override;
void benchmarkStarting(BenchmarkInfo const&) override;
void benchmarkEnded(BenchmarkStats<> const&) override;
void benchmarkFailed(std::string const&) override;

View File

@@ -4,6 +4,6 @@ import glob
import subprocess
if __name__ == '__main__':
cov_files = list(glob.glob('cov-report*.bin'))
cov_files = list(glob.glob('projects/cov-report*.bin'))
base_cmd = ['OpenCppCoverage', '--quiet', '--export_type=cobertura:cobertura.xml'] + ['--input_coverage={}'.format(f) for f in cov_files]
subprocess.call(base_cmd)
subprocess.check_call(base_cmd)

View File

@@ -89,27 +89,30 @@ std::string windowsify_path(std::string path) {
return path;
}
void exec_cmd(std::string const& cmd, int log_num, std::string const& path) {
int exec_cmd(std::string const& cmd, int log_num, std::string const& path) {
std::array<char, 128> buffer;
#if defined(_WIN32)
// cmd has already been escaped outside this function.
auto real_cmd = "OpenCppCoverage --export_type binary:cov-report" + std::to_string(log_num)
+ ".bin --quiet " + "--sources " + escape_arg(path) + " --cover_children -- " + cmd;
std::cout << "=== Marker ===: Cmd: " << real_cmd << '\n';
std::shared_ptr<FILE> pipe(_popen(real_cmd.c_str(), "r"), _pclose);
#else // Just for testing, in the real world we will always work under WIN32
(void)log_num; (void)path;
std::shared_ptr<FILE> pipe(popen(cmd.c_str(), "r"), pclose);
#endif
auto pipe = _popen(real_cmd.c_str(), "r");
if (!pipe) {
throw std::runtime_error("popen() failed!");
}
while (!feof(pipe.get())) {
if (fgets(buffer.data(), 128, pipe.get()) != nullptr) {
while (!feof(pipe)) {
if (fgets(buffer.data(), 128, pipe) != nullptr) {
std::cout << buffer.data();
}
}
auto ret = _pclose(pipe);
if (ret == -1) {
throw std::runtime_error("underlying error in pclose()");
}
return ret;
}
// argv should be:

View File

@@ -36,6 +36,7 @@ set(TEST_SOURCES
${SELF_TEST_DIR}/UsageTests/Generators.tests.cpp
${SELF_TEST_DIR}/UsageTests/Message.tests.cpp
${SELF_TEST_DIR}/UsageTests/Misc.tests.cpp
${SELF_TEST_DIR}/UsageTests/ToStringByte.tests.cpp
${SELF_TEST_DIR}/UsageTests/ToStringChrono.tests.cpp
${SELF_TEST_DIR}/UsageTests/ToStringGeneral.tests.cpp
${SELF_TEST_DIR}/UsageTests/ToStringOptional.tests.cpp
@@ -308,6 +309,32 @@ include(CTest)
add_executable(SelfTest ${TEST_SOURCES} ${IMPL_SOURCES} ${REPORTER_SOURCES} ${SURROGATE_SOURCES} ${HEADERS})
target_include_directories(SelfTest PRIVATE ${HEADER_DIR})
# It took CMake until 3.8 to abandon the doomed approach of enumerating
# required features so we just list C++11 features to support older ones.
target_compile_features(SelfTest
PRIVATE
cxx_alignas
cxx_alignof
cxx_attributes
cxx_auto_type
cxx_constexpr
cxx_defaulted_functions
cxx_deleted_functions
cxx_final
cxx_lambdas
cxx_noexcept
cxx_override
cxx_range_for
cxx_rvalue_references
cxx_static_assert
cxx_strong_enums
cxx_trailing_return_types
cxx_unicode_literals
cxx_user_literals
cxx_variadic_macros
)
if (CATCH_ENABLE_COVERAGE)
set(ENABLE_COVERAGE ON CACHE BOOL "Enable coverage build." FORCE)
find_package(codecov)
@@ -366,8 +393,19 @@ set_tests_properties(ListTestNamesOnly PROPERTIES
add_test(NAME NoAssertions COMMAND $<TARGET_FILE:SelfTest> -w NoAssertions)
set_tests_properties(NoAssertions PROPERTIES PASS_REGULAR_EXPRESSION "No assertions in test case")
add_test(NAME NoTest COMMAND $<TARGET_FILE:SelfTest> -w NoTests "___nonexistent_test___")
set_tests_properties(NoTest PROPERTIES PASS_REGULAR_EXPRESSION "No test cases matched")
add_test(NAME NoTest COMMAND $<TARGET_FILE:SelfTest> Tracker, "___nonexistent_test___")
set_tests_properties(NoTest PROPERTIES
PASS_REGULAR_EXPRESSION "No test cases matched '___nonexistent_test___'"
FAIL_REGULAR_EXPRESSION "No tests ran"
)
add_test(NAME WarnAboutNoTests COMMAND ${CMAKE_COMMAND} -P ${CATCH_DIR}/projects/SelfTest/WarnAboutNoTests.cmake $<TARGET_FILE:SelfTest>)
add_test(NAME UnmatchedOutputFilter COMMAND $<TARGET_FILE:SelfTest> [this-tag-does-not-exist] -w NoTests)
set_tests_properties(UnmatchedOutputFilter
PROPERTIES
PASS_REGULAR_EXPRESSION "No test cases matched '\\[this-tag-does-not-exist\\]'"
)
add_test(NAME FilteredSection-1 COMMAND $<TARGET_FILE:SelfTest> \#1394 -c RunSection)
set_tests_properties(FilteredSection-1 PROPERTIES FAIL_REGULAR_EXPRESSION "No tests ran")
@@ -378,6 +416,12 @@ set_tests_properties(FilteredSection-2 PROPERTIES FAIL_REGULAR_EXPRESSION "No te
add_test(NAME ApprovalTests COMMAND ${PYTHON_EXECUTABLE} ${CATCH_DIR}/scripts/approvalTests.py $<TARGET_FILE:SelfTest>)
set_tests_properties(ApprovalTests PROPERTIES FAIL_REGULAR_EXPRESSION "Results differed")
add_test(NAME RegressionCheck-1670 COMMAND $<TARGET_FILE:SelfTest> "#1670 regression check" -c A -r compact)
set_tests_properties(RegressionCheck-1670 PROPERTIES PASS_REGULAR_EXPRESSION "Passed 1 test case with 2 assertions.")
add_test(NAME VersionCheck COMMAND $<TARGET_FILE:SelfTest> -h)
set_tests_properties(VersionCheck PROPERTIES PASS_REGULAR_EXPRESSION "Catch v${PROJECT_VERSION}")
if (CATCH_USE_VALGRIND)
add_test(NAME ValgrindRunTests COMMAND valgrind --leak-check=full --error-exitcode=1 $<TARGET_FILE:SelfTest>)

View File

@@ -3,6 +3,8 @@ Decomposition.tests.cpp:<line number>: passed: fptr == 0 for: 0 == 0
Decomposition.tests.cpp:<line number>: passed: fptr == 0l for: 0 == 0
Compilation.tests.cpp:<line number>: passed: y.v == 0 for: 0 == 0
Compilation.tests.cpp:<line number>: passed: 0 == y.v for: 0 == 0
Compilation.tests.cpp:<line number>: passed: y.v == 0 for: 0 == 0
Compilation.tests.cpp:<line number>: passed: 0 == y.v for: 0 == 0
Compilation.tests.cpp:<line number>: passed: t1 == t2 for: {?} == {?}
Compilation.tests.cpp:<line number>: passed: t1 != t2 for: {?} != {?}
Compilation.tests.cpp:<line number>: passed: t1 < t2 for: {?} < {?}
@@ -244,8 +246,6 @@ Tricky.tests.cpp:<line number>: passed: true
Approx.tests.cpp:<line number>: passed: INFINITY == Approx(INFINITY) for: inff == Approx( inf )
Approx.tests.cpp:<line number>: passed: NAN != Approx(NAN) for: nanf != Approx( nan )
Approx.tests.cpp:<line number>: passed: !(NAN == Approx(NAN)) for: !(nanf == Approx( nan ))
Tricky.tests.cpp:<line number>: passed: y.v == 0 for: 0 == 0
Tricky.tests.cpp:<line number>: passed: 0 == y.v for: 0 == 0
Message.tests.cpp:<line number>: passed: with 7 messages: 'a := 1' and 'b := 2' and 'c := 3' and 'a + b := 3' and 'a+b := 3' and 'c > b := true' and 'a == 1 := true'
Message.tests.cpp:<line number>: passed: with 7 messages: 'std::vector<int>{1, 2, 3}[0, 1, 2] := 3' and 'std::vector<int>{1, 2, 3}[(0, 1)] := 2' and 'std::vector<int>{1, 2, 3}[0] := 1' and '(helper_1436<int, int>{12, -12}) := { 12, -12 }' and '(helper_1436<int, int>(-12, 12)) := { -12, 12 }' and '(1, 2) := 2' and '(2, 3) := 3'
Message.tests.cpp:<line number>: passed: with 11 messages: '("comma, in string", "escaped, \", ") := "escaped, ", "' and '"single quote in string,'," := "single quote in string,',"' and '"some escapes, \\,\\\\" := "some escapes, \,\\"' and '"some, ), unmatched, } prenheses {[<" := "some, ), unmatched, } prenheses {[<"' and ''"' := '"'' and ''\'' := '''' and '',' := ','' and ''}' := '}'' and '')' := ')'' and ''(' := '('' and ''{' := '{''
@@ -467,6 +467,9 @@ Generators.tests.cpp:<line number>: passed: chunk2.front() < 3 for: 1 < 3
Generators.tests.cpp:<line number>: passed: chunk2.size() == 2 for: 2 == 2
Generators.tests.cpp:<line number>: passed: chunk2.front() == chunk2.back() for: 2 == 2
Generators.tests.cpp:<line number>: passed: chunk2.front() < 3 for: 2 < 3
Generators.tests.cpp:<line number>: passed: chunk2.size() == 0 for: 0 == 0
Generators.tests.cpp:<line number>: passed: chunk2.size() == 0 for: 0 == 0
Generators.tests.cpp:<line number>: passed: chunk2.size() == 0 for: 0 == 0
Generators.tests.cpp:<line number>: passed: chunk(2, value(1)), Catch::GeneratorException
Generators.tests.cpp:<line number>: passed: j < i for: -3 < 1
Generators.tests.cpp:<line number>: passed: j < i for: -2 < 1
@@ -1081,6 +1084,9 @@ Tag.tests.cpp:<line number>: passed: registry.add( "[@no square bracket at end",
Class.tests.cpp:<line number>: passed: Template_Fixture<TestType>::m_a == 1 for: 1 == 1
Class.tests.cpp:<line number>: passed: Template_Fixture<TestType>::m_a == 1 for: 1 == 1
Class.tests.cpp:<line number>: passed: Template_Fixture<TestType>::m_a == 1 for: 1.0 == 1
Misc.tests.cpp:<line number>: passed: sizeof(TestType) > 0 for: 1 > 0
Misc.tests.cpp:<line number>: passed: sizeof(TestType) > 0 for: 1 > 0
Misc.tests.cpp:<line number>: passed: sizeof(TestType) > 0 for: 4 > 0
Misc.tests.cpp:<line number>: passed: sizeof(TestType) > 0 for: 4 > 0
Misc.tests.cpp:<line number>: passed: sizeof(TestType) > 0 for: 1 > 0
Misc.tests.cpp:<line number>: passed: sizeof(TestType) > 0 for: 4 > 0

View File

@@ -1380,6 +1380,6 @@ due to unexpected exception with message:
Why would you throw a std::string?
===============================================================================
test cases: 295 | 221 passed | 70 failed | 4 failed as expected
assertions: 1547 | 1395 passed | 131 failed | 21 failed as expected
test cases: 298 | 224 passed | 70 failed | 4 failed as expected
assertions: 1553 | 1401 passed | 131 failed | 21 failed as expected

View File

@@ -39,6 +39,22 @@ with expansion:
Compilation.tests.cpp:<line number>
...............................................................................
Compilation.tests.cpp:<line number>: PASSED:
REQUIRE( y.v == 0 )
with expansion:
0 == 0
Compilation.tests.cpp:<line number>: PASSED:
REQUIRE( 0 == y.v )
with expansion:
0 == 0
-------------------------------------------------------------------------------
#1027: Bitfields can be captured
-------------------------------------------------------------------------------
Compilation.tests.cpp:<line number>
...............................................................................
Compilation.tests.cpp:<line number>: PASSED:
REQUIRE( y.v == 0 )
with expansion:
@@ -1944,22 +1960,6 @@ Approx.tests.cpp:<line number>: PASSED:
with expansion:
!(nanf == Approx( nan ))
-------------------------------------------------------------------------------
Bitfields can be captured (#1027)
-------------------------------------------------------------------------------
Tricky.tests.cpp:<line number>
...............................................................................
Tricky.tests.cpp:<line number>: PASSED:
REQUIRE( y.v == 0 )
with expansion:
0 == 0
Tricky.tests.cpp:<line number>: PASSED:
REQUIRE( 0 == y.v )
with expansion:
0 == 0
-------------------------------------------------------------------------------
CAPTURE can deal with complex expressions
-------------------------------------------------------------------------------
@@ -3547,6 +3547,45 @@ Generators.tests.cpp:<line number>: PASSED:
with expansion:
2 < 3
-------------------------------------------------------------------------------
Generators -- adapters
Chunking a generator into sized pieces
Chunk size of zero
-------------------------------------------------------------------------------
Generators.tests.cpp:<line number>
...............................................................................
Generators.tests.cpp:<line number>: PASSED:
REQUIRE( chunk2.size() == 0 )
with expansion:
0 == 0
-------------------------------------------------------------------------------
Generators -- adapters
Chunking a generator into sized pieces
Chunk size of zero
-------------------------------------------------------------------------------
Generators.tests.cpp:<line number>
...............................................................................
Generators.tests.cpp:<line number>: PASSED:
REQUIRE( chunk2.size() == 0 )
with expansion:
0 == 0
-------------------------------------------------------------------------------
Generators -- adapters
Chunking a generator into sized pieces
Chunk size of zero
-------------------------------------------------------------------------------
Generators.tests.cpp:<line number>
...............................................................................
Generators.tests.cpp:<line number>: PASSED:
REQUIRE( chunk2.size() == 0 )
with expansion:
0 == 0
-------------------------------------------------------------------------------
Generators -- adapters
Chunking a generator into sized pieces
@@ -7983,6 +8022,42 @@ Class.tests.cpp:<line number>: PASSED:
with expansion:
1.0 == 1
-------------------------------------------------------------------------------
Template test case with test types specified inside non-default-constructible
std::tuple - MyNonDefaultConstructibleTypes - 0
-------------------------------------------------------------------------------
Misc.tests.cpp:<line number>
...............................................................................
Misc.tests.cpp:<line number>: PASSED:
REQUIRE( sizeof(TestType) > 0 )
with expansion:
1 > 0
-------------------------------------------------------------------------------
Template test case with test types specified inside non-default-constructible
std::tuple - MyNonDefaultConstructibleTypes - 1
-------------------------------------------------------------------------------
Misc.tests.cpp:<line number>
...............................................................................
Misc.tests.cpp:<line number>: PASSED:
REQUIRE( sizeof(TestType) > 0 )
with expansion:
1 > 0
-------------------------------------------------------------------------------
Template test case with test types specified inside non-default-constructible
std::tuple - MyNonDefaultConstructibleTypes - 2
-------------------------------------------------------------------------------
Misc.tests.cpp:<line number>
...............................................................................
Misc.tests.cpp:<line number>: PASSED:
REQUIRE( sizeof(TestType) > 0 )
with expansion:
4 > 0
-------------------------------------------------------------------------------
Template test case with test types specified inside std::tuple - MyTypes - 0
-------------------------------------------------------------------------------
@@ -12334,6 +12409,6 @@ Misc.tests.cpp:<line number>
Misc.tests.cpp:<line number>: PASSED:
===============================================================================
test cases: 295 | 205 passed | 86 failed | 4 failed as expected
assertions: 1564 | 1395 passed | 148 failed | 21 failed as expected
test cases: 298 | 208 passed | 86 failed | 4 failed as expected
assertions: 1570 | 1401 passed | 148 failed | 21 failed as expected

View File

@@ -39,6 +39,22 @@ with expansion:
Compilation.tests.cpp:<line number>
...............................................................................
Compilation.tests.cpp:<line number>: PASSED:
REQUIRE( y.v == 0 )
with expansion:
0 == 0
Compilation.tests.cpp:<line number>: PASSED:
REQUIRE( 0 == y.v )
with expansion:
0 == 0
-------------------------------------------------------------------------------
#1027: Bitfields can be captured
-------------------------------------------------------------------------------
Compilation.tests.cpp:<line number>
...............................................................................
Compilation.tests.cpp:<line number>: PASSED:
REQUIRE( y.v == 0 )
with expansion:
@@ -352,6 +368,6 @@ Condition.tests.cpp:<line number>: FAILED:
CHECK( true != true )
===============================================================================
test cases: 18 | 13 passed | 3 failed | 2 failed as expected
assertions: 40 | 33 passed | 4 failed | 3 failed as expected
test cases: 19 | 14 passed | 3 failed | 2 failed as expected
assertions: 42 | 35 passed | 4 failed | 3 failed as expected

View File

@@ -1,7 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?>
<testsuitesloose text artifact
>
<testsuite name="<exe-name>" errors="17" failures="132" tests="1565" hostname="tbd" time="{duration}" timestamp="{iso8601-timestamp}">
<testsuite name="<exe-name>" errors="17" failures="132" tests="1571" hostname="tbd" time="{duration}" timestamp="{iso8601-timestamp}">
<properties>
<property name="filters" value="~[!nonportable]~[!benchmark]~[approvals]"/>
<property name="random-seed" value="1"/>
@@ -9,6 +9,7 @@
<testcase classname="<exe-name>.global" name="# A test name that starts with a #" time="{duration}"/>
<testcase classname="<exe-name>.global" name="#1005: Comparing pointer to int and long (NULL can be either on various systems)" time="{duration}"/>
<testcase classname="<exe-name>.global" name="#1027" time="{duration}"/>
<testcase classname="<exe-name>.global" name="#1027: Bitfields can be captured" time="{duration}"/>
<testcase classname="<exe-name>.global" name="#1147" time="{duration}"/>
<testcase classname="<exe-name>.global" name="#1175 - Hidden Test" time="{duration}"/>
<testcase classname="<exe-name>.global" name="#1238" time="{duration}"/>
@@ -232,7 +233,6 @@ Exception.tests.cpp:<line number>
<testcase classname="<exe-name>.global" name="Assertions then sections/A section/Another section" time="{duration}"/>
<testcase classname="<exe-name>.global" name="Assertions then sections/A section/Another other section" time="{duration}"/>
<testcase classname="<exe-name>.global" name="Assorted miscellaneous tests" time="{duration}"/>
<testcase classname="<exe-name>.global" name="Bitfields can be captured (#1027)" time="{duration}"/>
<testcase classname="<exe-name>.global" name="CAPTURE can deal with complex expressions" time="{duration}"/>
<testcase classname="<exe-name>.global" name="CAPTURE can deal with complex expressions involving commas" time="{duration}"/>
<testcase classname="<exe-name>.global" name="CAPTURE parses string and character constants" time="{duration}"/>
@@ -416,6 +416,7 @@ Message.tests.cpp:<line number>
<testcase classname="<exe-name>.global" name="Generators -- adapters/Repeating a generator" time="{duration}"/>
<testcase classname="<exe-name>.global" name="Generators -- adapters/Chunking a generator into sized pieces/Number of elements in source is divisible by chunk size" time="{duration}"/>
<testcase classname="<exe-name>.global" name="Generators -- adapters/Chunking a generator into sized pieces/Number of elements in source is not divisible by chunk size" time="{duration}"/>
<testcase classname="<exe-name>.global" name="Generators -- adapters/Chunking a generator into sized pieces/Chunk size of zero" time="{duration}"/>
<testcase classname="<exe-name>.global" name="Generators -- adapters/Chunking a generator into sized pieces/Throws on too small generators" time="{duration}"/>
<testcase classname="<exe-name>.global" name="Generators -- simple/one" time="{duration}"/>
<testcase classname="<exe-name>.global" name="Generators -- simple/two" time="{duration}"/>
@@ -749,6 +750,9 @@ Misc.tests.cpp:<line number>
<testcase classname="<exe-name>.Template_Fixture" name="Template test case method with test types specified inside std::tuple - MyTypes - 0" time="{duration}"/>
<testcase classname="<exe-name>.Template_Fixture" name="Template test case method with test types specified inside std::tuple - MyTypes - 1" time="{duration}"/>
<testcase classname="<exe-name>.Template_Fixture" name="Template test case method with test types specified inside std::tuple - MyTypes - 2" time="{duration}"/>
<testcase classname="<exe-name>.global" name="Template test case with test types specified inside non-default-constructible std::tuple - MyNonDefaultConstructibleTypes - 0" time="{duration}"/>
<testcase classname="<exe-name>.global" name="Template test case with test types specified inside non-default-constructible std::tuple - MyNonDefaultConstructibleTypes - 1" time="{duration}"/>
<testcase classname="<exe-name>.global" name="Template test case with test types specified inside non-default-constructible std::tuple - MyNonDefaultConstructibleTypes - 2" time="{duration}"/>
<testcase classname="<exe-name>.global" name="Template test case with test types specified inside std::tuple - MyTypes - 0" time="{duration}"/>
<testcase classname="<exe-name>.global" name="Template test case with test types specified inside std::tuple - MyTypes - 1" time="{duration}"/>
<testcase classname="<exe-name>.global" name="Template test case with test types specified inside std::tuple - MyTypes - 2" time="{duration}"/>

View File

@@ -43,6 +43,25 @@
</Expression>
<OverallResult success="true"/>
</TestCase>
<TestCase name="#1027: Bitfields can be captured" filename="projects/<exe-name>/UsageTests/Compilation.tests.cpp" >
<Expression success="true" type="REQUIRE" filename="projects/<exe-name>/UsageTests/Compilation.tests.cpp" >
<Original>
y.v == 0
</Original>
<Expanded>
0 == 0
</Expanded>
</Expression>
<Expression success="true" type="REQUIRE" filename="projects/<exe-name>/UsageTests/Compilation.tests.cpp" >
<Original>
0 == y.v
</Original>
<Expanded>
0 == 0
</Expanded>
</Expression>
<OverallResult success="true"/>
</TestCase>
<TestCase name="#1147" filename="projects/<exe-name>/UsageTests/Compilation.tests.cpp" >
<Expression success="true" type="REQUIRE" filename="projects/<exe-name>/UsageTests/Compilation.tests.cpp" >
<Original>
@@ -2180,25 +2199,6 @@ Nor would this
</Expression>
<OverallResult success="true"/>
</TestCase>
<TestCase name="Bitfields can be captured (#1027)" filename="projects/<exe-name>/UsageTests/Tricky.tests.cpp" >
<Expression success="true" type="REQUIRE" filename="projects/<exe-name>/UsageTests/Tricky.tests.cpp" >
<Original>
y.v == 0
</Original>
<Expanded>
0 == 0
</Expanded>
</Expression>
<Expression success="true" type="REQUIRE" filename="projects/<exe-name>/UsageTests/Tricky.tests.cpp" >
<Original>
0 == y.v
</Original>
<Expanded>
0 == 0
</Expanded>
</Expression>
<OverallResult success="true"/>
</TestCase>
<TestCase name="CAPTURE can deal with complex expressions" tags="[capture][messages]" filename="projects/<exe-name>/UsageTests/Message.tests.cpp" >
<Info>
a := 1
@@ -4260,6 +4260,48 @@ Nor would this
</Section>
<OverallResults successes="3" failures="0" expectedFailures="0"/>
</Section>
<Section name="Chunking a generator into sized pieces" filename="projects/<exe-name>/UsageTests/Generators.tests.cpp" >
<Section name="Chunk size of zero" filename="projects/<exe-name>/UsageTests/Generators.tests.cpp" >
<Expression success="true" type="REQUIRE" filename="projects/<exe-name>/UsageTests/Generators.tests.cpp" >
<Original>
chunk2.size() == 0
</Original>
<Expanded>
0 == 0
</Expanded>
</Expression>
<OverallResults successes="1" failures="0" expectedFailures="0"/>
</Section>
<OverallResults successes="1" failures="0" expectedFailures="0"/>
</Section>
<Section name="Chunking a generator into sized pieces" filename="projects/<exe-name>/UsageTests/Generators.tests.cpp" >
<Section name="Chunk size of zero" filename="projects/<exe-name>/UsageTests/Generators.tests.cpp" >
<Expression success="true" type="REQUIRE" filename="projects/<exe-name>/UsageTests/Generators.tests.cpp" >
<Original>
chunk2.size() == 0
</Original>
<Expanded>
0 == 0
</Expanded>
</Expression>
<OverallResults successes="1" failures="0" expectedFailures="0"/>
</Section>
<OverallResults successes="1" failures="0" expectedFailures="0"/>
</Section>
<Section name="Chunking a generator into sized pieces" filename="projects/<exe-name>/UsageTests/Generators.tests.cpp" >
<Section name="Chunk size of zero" filename="projects/<exe-name>/UsageTests/Generators.tests.cpp" >
<Expression success="true" type="REQUIRE" filename="projects/<exe-name>/UsageTests/Generators.tests.cpp" >
<Original>
chunk2.size() == 0
</Original>
<Expanded>
0 == 0
</Expanded>
</Expression>
<OverallResults successes="1" failures="0" expectedFailures="0"/>
</Section>
<OverallResults successes="1" failures="0" expectedFailures="0"/>
</Section>
<Section name="Chunking a generator into sized pieces" filename="projects/<exe-name>/UsageTests/Generators.tests.cpp" >
<Section name="Throws on too small generators" filename="projects/<exe-name>/UsageTests/Generators.tests.cpp" >
<Expression success="true" type="REQUIRE_THROWS_AS" filename="projects/<exe-name>/UsageTests/Generators.tests.cpp" >
@@ -9853,6 +9895,39 @@ Message from section two
</Expression>
<OverallResult success="true"/>
</TestCase>
<TestCase name="Template test case with test types specified inside non-default-constructible std::tuple - MyNonDefaultConstructibleTypes - 0" tags="[list][template]" filename="projects/<exe-name>/UsageTests/Misc.tests.cpp" >
<Expression success="true" type="REQUIRE" filename="projects/<exe-name>/UsageTests/Misc.tests.cpp" >
<Original>
sizeof(TestType) > 0
</Original>
<Expanded>
1 > 0
</Expanded>
</Expression>
<OverallResult success="true"/>
</TestCase>
<TestCase name="Template test case with test types specified inside non-default-constructible std::tuple - MyNonDefaultConstructibleTypes - 1" tags="[list][template]" filename="projects/<exe-name>/UsageTests/Misc.tests.cpp" >
<Expression success="true" type="REQUIRE" filename="projects/<exe-name>/UsageTests/Misc.tests.cpp" >
<Original>
sizeof(TestType) > 0
</Original>
<Expanded>
1 > 0
</Expanded>
</Expression>
<OverallResult success="true"/>
</TestCase>
<TestCase name="Template test case with test types specified inside non-default-constructible std::tuple - MyNonDefaultConstructibleTypes - 2" tags="[list][template]" filename="projects/<exe-name>/UsageTests/Misc.tests.cpp" >
<Expression success="true" type="REQUIRE" filename="projects/<exe-name>/UsageTests/Misc.tests.cpp" >
<Original>
sizeof(TestType) > 0
</Original>
<Expanded>
4 > 0
</Expanded>
</Expression>
<OverallResult success="true"/>
</TestCase>
<TestCase name="Template test case with test types specified inside std::tuple - MyTypes - 0" tags="[list][template]" filename="projects/<exe-name>/UsageTests/Misc.tests.cpp" >
<Expression success="true" type="REQUIRE" filename="projects/<exe-name>/UsageTests/Misc.tests.cpp" >
<Original>
@@ -14692,7 +14767,7 @@ loose text artifact
</Section>
<OverallResult success="true"/>
</TestCase>
<OverallResults successes="1395" failures="149" expectedFailures="21"/>
<OverallResults successes="1401" failures="149" expectedFailures="21"/>
</Group>
<OverallResults successes="1395" failures="148" expectedFailures="21"/>
<OverallResults successes="1401" failures="148" expectedFailures="21"/>
</Catch>

View File

@@ -189,3 +189,18 @@ TEST_CASE( "#1394 nested", "[.][approvals][tracker]" ) {
REQUIRE(1 == 0);
}
}
// Selecting a "not last" section inside a test case via -c "section" would
// previously only run the first subsection, instead of running all of them.
// This allows us to check that `"#1670 regression check" -c A` leads to
// 2 successful assertions.
TEST_CASE("#1670 regression check", "[.approvals][tracker]") {
SECTION("A") {
SECTION("1") SUCCEED();
SECTION("2") SUCCEED();
}
SECTION("B") {
SECTION("1") SUCCEED();
SECTION("2") SUCCEED();
}
}

View File

@@ -194,6 +194,31 @@ namespace { namespace CompilationTests {
REQUIRE(std::is_same<TypeList<int>, TypeList<int>>::value);
}
// #925
using signal_t = void (*) (void*);
struct TestClass {
signal_t testMethod_uponComplete_arg = nullptr;
};
namespace utility {
inline static void synchronizing_callback( void * ) { }
}
TEST_CASE("#925: comparing function pointer to function address failed to compile", "[!nonportable]" ) {
TestClass test;
REQUIRE(utility::synchronizing_callback != test.testMethod_uponComplete_arg);
}
TEST_CASE( "#1027: Bitfields can be captured" ) {
struct Y {
uint32_t v : 1;
};
Y y{ 0 };
REQUIRE( y.v == 0 );
REQUIRE( 0 == y.v );
}
}} // namespace CompilationTests

View File

@@ -167,6 +167,10 @@ TEST_CASE("Generators -- adapters", "[generators][generic]") {
REQUIRE(chunk2.front() == chunk2.back());
REQUIRE(chunk2.front() < 3);
}
SECTION("Chunk size of zero") {
auto chunk2 = GENERATE(take(3, chunk(0, value(1))));
REQUIRE(chunk2.size() == 0);
}
SECTION("Throws on too small generators") {
using namespace Catch::Generators;
REQUIRE_THROWS_AS(chunk(2, value(1)), Catch::GeneratorException);

View File

@@ -371,6 +371,16 @@ TEMPLATE_LIST_TEST_CASE("Template test case with test types specified inside std
REQUIRE(sizeof(TestType) > 0);
}
struct NonDefaultConstructibleType {
NonDefaultConstructibleType() = delete;
};
using MyNonDefaultConstructibleTypes = std::tuple<NonDefaultConstructibleType, char, float>;
TEMPLATE_LIST_TEST_CASE("Template test case with test types specified inside non-default-constructible std::tuple", "[template][list]", MyNonDefaultConstructibleTypes)
{
REQUIRE(sizeof(TestType) > 0);
}
// https://github.com/philsquared/Catch/issues/166
TEST_CASE("A couple of nested sections followed by a failure", "[failing][.]") {
SECTION("Outer")
@@ -430,12 +440,6 @@ TEST_CASE( "long long" ) {
REQUIRE( l == std::numeric_limits<long long>::max() );
}
//TEST_CASE( "Divide by Zero signal handler", "[.][sig]" ) {
// int i = 0;
// int x = 10/i; // This should cause the signal to fire
// CHECK( x == 0 );
//}
TEST_CASE( "This test 'should' fail but doesn't", "[.][failing][!shouldfail]" ) {
SUCCEED( "oops!" );
}

View File

@@ -0,0 +1,15 @@
#include "catch.hpp"
#if defined(CATCH_CONFIG_CPP17_BYTE)
TEST_CASE( "std::byte -> toString", "[toString][byte][approvals]" ) {
using type = std::byte;
REQUIRE( "0" == ::Catch::Detail::stringify( type{ 0 } ) );
}
TEST_CASE( "std::vector<std::byte> -> toString", "[toString][byte][approvals]" ) {
using type = std::vector<std::byte>;
REQUIRE( "{ 0, 1, 2 }" == ::Catch::Detail::stringify( type{ std::byte{0}, std::byte{1}, std::byte{2} } ) );
}
#endif // CATCH_INTERNAL_CONFIG_CPP17_BYTE

View File

@@ -402,32 +402,6 @@ TEST_CASE( "non-copyable objects", "[.][failing]" ) {
CHECK( ti == typeid(int) );
}
// #925
using signal_t = void (*) (void*);
struct TestClass {
signal_t testMethod_uponComplete_arg = nullptr;
};
namespace utility {
inline static void synchronizing_callback( void * ) { }
}
TEST_CASE("#925: comparing function pointer to function address failed to compile", "[!nonportable]" ) {
TestClass test;
REQUIRE(utility::synchronizing_callback != test.testMethod_uponComplete_arg);
}
TEST_CASE( "Bitfields can be captured (#1027)" ) {
struct Y {
uint32_t v : 1;
};
Y y{ 0 };
REQUIRE( y.v == 0 );
REQUIRE( 0 == y.v );
}
TEST_CASE("#1514: stderr/stdout is not captured in tests aborted by an exception", "[output-capture][regression][.]") {
std::cout << "This would not be caught previously\n" << std::flush;
std::clog << "Nor would this\n" << std::flush;

View File

@@ -0,0 +1,19 @@
# Workaround for a peculiarity where CTest disregards the return code from a
# test command if a PASS_REGULAR_EXPRESSION is also set
execute_process(
COMMAND ${CMAKE_ARGV3} -w NoTests "___nonexistent_test___"
RESULT_VARIABLE ret
OUTPUT_VARIABLE out
)
message("${out}")
if(NOT ${ret} MATCHES "^[0-9]+$")
message(FATAL_ERROR "${ret}")
endif()
if(${ret} EQUAL 0)
message(FATAL_ERROR "Expected nonzero return code")
elseif(${out} MATCHES "Helper failed with")
message(FATAL_ERROR "Helper failed")
endif()

View File

@@ -0,0 +1,94 @@
#!/usr/bin/env python
#
# extractFeaturesFromReleaseNotes.py
#
# Read the release notes - docs/release-notes.md - and generate text
# for pasting in to individual documentation pages, to indicate which
# versions recent features were released in.
#
# Using the output of the file is easier than manually constructing
# the text to paste in to documentation pages.
#
# One way to use this:
# - run this script, saving the output to some temporary file
# - diff this output with the actual release notes page
# - the differences are Markdown text that can be pasted in to the
# appropriate documentation pages in the docs/ directory.
# - each release also has a github link to show which documentation files
# were changed in it.
# This can be helpful to see which documentation pages
# to add the 'Introduced in Catch ...' snippets to the relevant pages.
#
from __future__ import print_function
import re
def create_introduced_in_text(version, bug_number = None):
"""Generate text to paste in to documentation file"""
if bug_number:
return '> [Introduced](https://github.com/catchorg/Catch2/issues/%s) in Catch %s.' % (bug_number, version)
else:
# Use this text for changes that don't have issue numbers
return '> Introduced in Catch %s.' % version
def link_to_changes_in_release(release, releases):
"""
Markdown text for a hyperlink showing all edits in a release, or empty string
:param release: A release version, as a string
:param releases: A container of releases, in descending order - newest to oldest
:return: Markdown text for a hyperlink showing the differences between the give release and the prior one,
or empty string, if the previous release is not known
"""
if release == releases[-1]:
# This is the earliest release we know about
return ''
index = releases.index(release)
previous_release = releases[index + 1]
return '\n[Changes in %s](https://github.com/catchorg/Catch2/compare/v%s...v%s)' % (release, previous_release, release)
def write_recent_release_notes_with_introduced_text():
current_version = None
release_toc_regex = r'\[(\d.\d.\d)\]\(#\d+\)<br>'
issue_number_regex = r'#[0-9]+'
releases = []
with open('../docs/release-notes.md') as release_notes:
for line in release_notes:
line = line[:-1]
print(line)
# Extract version number from table of contents
match = re.search(release_toc_regex, line)
if match:
release_name = match.group(1)
releases.append(release_name)
if line.startswith('## '):
# It's a section with version number
current_version = line.replace('## ', '')
# We decided not to add released-date info for older versions
if current_version == 'Older versions':
break
print(create_introduced_in_text(current_version))
print(link_to_changes_in_release(current_version, releases))
# Not yet found a version number, so to avoid picking up hyperlinks to
# version numbers in the index, keep going
if not current_version:
continue
for bug_link in re.findall(issue_number_regex, line):
bug_number = bug_link.replace('#', '')
print(create_introduced_in_text(current_version, bug_number))
if __name__ == '__main__':
write_recent_release_notes_with_introduced_text()

View File

@@ -4,6 +4,8 @@ import os
import sys
import re
import string
import glob
import fnmatch
from scriptCommon import catchPath
@@ -98,29 +100,47 @@ def updateReadmeFile(version):
def updateCmakeFile(version):
with open(cmakePath, 'r') as file:
with open(cmakePath, 'rb') as file:
lines = file.readlines()
with open(cmakePath, 'w') as file:
replacementRegex = re.compile(b'project\\(Catch2 LANGUAGES CXX VERSION \\d+\\.\\d+\\.\\d+\\)')
replacement = 'project(Catch2 LANGUAGES CXX VERSION {0})'.format(version.getVersionString()).encode('ascii')
with open(cmakePath, 'wb') as file:
for line in lines:
if 'project(Catch2 LANGUAGES CXX VERSION ' in line:
file.write('project(Catch2 LANGUAGES CXX VERSION {0})\n'.format(version.getVersionString()))
else:
file.write(line)
file.write(replacementRegex.sub(replacement, line))
def updateVersionDefine(version):
with open(definePath, 'r') as file:
# First member of the tuple is the compiled regex object, the second is replacement if it matches
replacementRegexes = [(re.compile(b'#define CATCH_VERSION_MAJOR \\d+'),'#define CATCH_VERSION_MAJOR {}'.format(version.majorVersion).encode('ascii')),
(re.compile(b'#define CATCH_VERSION_MINOR \\d+'),'#define CATCH_VERSION_MINOR {}'.format(version.minorVersion).encode('ascii')),
(re.compile(b'#define CATCH_VERSION_PATCH \\d+'),'#define CATCH_VERSION_PATCH {}'.format(version.patchNumber).encode('ascii')),
]
with open(definePath, 'rb') as file:
lines = file.readlines()
with open(definePath, 'w') as file:
with open(definePath, 'wb') as file:
for line in lines:
if '#define CATCH_VERSION_MAJOR' in line:
file.write('#define CATCH_VERSION_MAJOR {}\n'.format(version.majorVersion))
elif '#define CATCH_VERSION_MINOR' in line:
file.write('#define CATCH_VERSION_MINOR {}\n'.format(version.minorVersion))
elif '#define CATCH_VERSION_PATCH' in line:
file.write('#define CATCH_VERSION_PATCH {}\n'.format(version.patchNumber))
else:
file.write(line)
for replacement in replacementRegexes:
line = replacement[0].sub(replacement[1], line)
file.write(line)
def updateVersionPlaceholder(filename, version):
with open(filename, 'rb') as file:
lines = file.readlines()
placeholderRegex = re.compile(b'\) in Catch X.Y.Z')
replacement = '\) in Catch {}.{}.{}'.format(version.majorVersion, version.minorVersion, version.patchNumber).encode('ascii')
with open(filename, 'wb') as file:
for line in lines:
file.write(placeholderRegex.sub(replacement, line))
def updateDocumentationVersionPlaceholders(version):
print('Updating version placeholder in documentation')
docsPath = os.path.join(catchPath, 'docs/')
for basePath, _, files in os.walk(docsPath):
for file in files:
if fnmatch.fnmatch(file, "*.md") and "contributing.md" != file:
updateVersionPlaceholder(os.path.join(basePath, file), version)
def performUpdates(version):
@@ -143,3 +163,4 @@ def performUpdates(version):
updateReadmeFile(version)
updateCmakeFile(version)
updateDocumentationVersionPlaceholders(version)

View File

@@ -1,6 +1,6 @@
/*
* Catch v2.9.1
* Generated: 2019-06-17 11:59:24.363643
* Catch v2.9.2
* Generated: 2019-08-08 13:35:12.279703
* ----------------------------------------------------------
* This file has been merged from multiple headers. Please don't edit it directly
* Copyright (c) 2019 Two Blue Cubes Ltd. All rights reserved.
@@ -15,7 +15,7 @@
#define CATCH_VERSION_MAJOR 2
#define CATCH_VERSION_MINOR 9
#define CATCH_VERSION_PATCH 1
#define CATCH_VERSION_PATCH 2
#ifdef __clang__
# pragma clang system_header
@@ -275,6 +275,17 @@ namespace Catch {
#define CATCH_INTERNAL_CONFIG_COUNTER
#endif
////////////////////////////////////////////////////////////////////////////////
// RTX is a special version of Windows that is real time.
// This means that it is detected as Windows, but does not provide
// the same set of capabilities as real Windows does.
#if defined(UNDER_RTSS) || defined(RTX64_BUILD)
#define CATCH_INTERNAL_CONFIG_NO_WINDOWS_SEH
#define CATCH_INTERNAL_CONFIG_NO_ASYNC
#define CATCH_CONFIG_COLOUR_NONE
#endif
////////////////////////////////////////////////////////////////////////////////
// Check if string_view is available and usable
// The check is split apart to work around v140 (VS2015) preprocessor issue...
@@ -292,6 +303,14 @@ namespace Catch {
# endif // __has_include(<optional>) && defined(CATCH_CPP17_OR_GREATER)
#endif // __has_include
////////////////////////////////////////////////////////////////////////////////
// Check if byte is available and usable
#if defined(__has_include)
# if __has_include(<cstddef>) && defined(CATCH_CPP17_OR_GREATER)
# define CATCH_INTERNAL_CONFIG_CPP17_BYTE
# endif // __has_include(<cstddef>) && defined(CATCH_CPP17_OR_GREATER)
#endif // __has_include
////////////////////////////////////////////////////////////////////////////////
// Check if variant is available and usable
#if defined(__has_include)
@@ -346,6 +365,10 @@ namespace Catch {
# define CATCH_CONFIG_CPP17_VARIANT
#endif
#if defined(CATCH_INTERNAL_CONFIG_CPP17_BYTE) && !defined(CATCH_CONFIG_NO_CPP17_BYTE) && !defined(CATCH_CONFIG_CPP17_BYTE)
# define CATCH_CONFIG_CPP17_BYTE
#endif
#if defined(CATCH_CONFIG_EXPERIMENTAL_REDIRECT)
# define CATCH_INTERNAL_CONFIG_NEW_CAPTURE
#endif
@@ -362,7 +385,7 @@ namespace Catch {
# define CATCH_CONFIG_POLYFILL_ISNAN
#endif
#if defined(CATCH_INTERNAL_CONFIG_USE_ASYNC) && !defined(CATCH_CONFIG_NO_USE_ASYNC) && !defined(CATCH_CONFIG_USE_ASYNC)
#if defined(CATCH_INTERNAL_CONFIG_USE_ASYNC) && !defined(CATCH_INTERNAL_CONFIG_NO_ASYNC) && !defined(CATCH_CONFIG_NO_USE_ASYNC) && !defined(CATCH_CONFIG_USE_ASYNC)
# define CATCH_CONFIG_USE_ASYNC
#endif
@@ -515,6 +538,7 @@ namespace Catch {
virtual std::vector<TestCase> const& getAllTestsSorted( IConfig const& config ) const = 0;
};
bool isThrowSafe( TestCase const& testCase, IConfig const& config );
bool matchTest( TestCase const& testCase, TestSpec const& testSpec, IConfig const& config );
std::vector<TestCase> filterTests( std::vector<TestCase> const& testCases, TestSpec const& testSpec, IConfig const& config );
std::vector<TestCase> const& getAllTestCasesSorted( IConfig const& config );
@@ -1153,7 +1177,7 @@ struct AutoReg : NonCopyable {
} \
};\
static int INTERNAL_CATCH_UNIQUE_NAME( globalRegistrar ) = [](){ \
using TestInit = decltype(convert<TestName>(TmplList {})); \
using TestInit = decltype(convert<TestName>(std::declval<TmplList>())); \
TestInit t; \
t.reg_tests(); \
return 0; \
@@ -1279,7 +1303,7 @@ struct AutoReg : NonCopyable {
}\
};\
static int INTERNAL_CATCH_UNIQUE_NAME( globalRegistrar ) = [](){\
using TestInit = decltype(convert<TestNameClass>(TmplList {}));\
using TestInit = decltype(convert<TestNameClass>(std::declval<TmplList>()));\
TestInit t;\
t.reg_tests();\
return 0;\
@@ -1679,6 +1703,12 @@ namespace Catch {
}
};
#if defined(CATCH_CONFIG_CPP17_BYTE)
template<>
struct StringMaker<std::byte> {
static std::string convert(std::byte value);
};
#endif // defined(CATCH_CONFIG_CPP17_BYTE)
template<>
struct StringMaker<int> {
static std::string convert(int value);
@@ -3180,6 +3210,15 @@ namespace Matchers {
virtual bool match( ObjectT const& arg ) const = 0;
};
#if defined(__OBJC__)
// Hack to fix Catch GH issue #1661. Could use id for generic Object support.
// use of const for Object pointers is very uncommon and under ARC it causes some kind of signature mismatch that breaks compilation
template<>
struct MatcherMethod<NSString*> {
virtual bool match( NSString* arg ) const = 0;
};
#endif
#ifdef __clang__
# pragma clang diagnostic pop
#endif
@@ -3829,6 +3868,9 @@ namespace Generators {
template<typename T>
class FixedValuesGenerator final : public IGenerator<T> {
static_assert(!std::is_same<T, bool>::value,
"ValuesGenerator does not support bools because of std::vector<bool>"
"specialization, use SingleValue Generator instead.");
std::vector<T> m_values;
size_t m_idx = 0;
public:
@@ -4048,6 +4090,9 @@ namespace Generators {
template <typename T>
class RepeatGenerator : public IGenerator<T> {
static_assert(!std::is_same<T, bool>::value,
"RepeatGenerator currently does not support bools"
"because of std::vector<bool> specialization");
GeneratorWrapper<T> m_generator;
mutable std::vector<T> m_returned;
size_t m_target_repeats;
@@ -4162,12 +4207,14 @@ namespace Generators {
m_chunk_size(size), m_generator(std::move(generator))
{
m_chunk.reserve(m_chunk_size);
m_chunk.push_back(m_generator.get());
for (size_t i = 1; i < m_chunk_size; ++i) {
if (!m_generator.next()) {
Catch::throw_exception(GeneratorException("Not enough values to initialize the first chunk"));
}
if (m_chunk_size != 0) {
m_chunk.push_back(m_generator.get());
for (size_t i = 1; i < m_chunk_size; ++i) {
if (!m_generator.next()) {
Catch::throw_exception(GeneratorException("Not enough values to initialize the first chunk"));
}
m_chunk.push_back(m_generator.get());
}
}
}
std::vector<T> const& get() const override {
@@ -4711,7 +4758,7 @@ namespace Catch {
arcSafeRelease( m_substr );
}
bool match( NSString* const& str ) const override {
bool match( NSString* str ) const override {
return false;
}
@@ -4721,7 +4768,7 @@ namespace Catch {
struct Equals : StringHolder {
Equals( NSString* substr ) : StringHolder( substr ){}
bool match( NSString* const& str ) const override {
bool match( NSString* str ) const override {
return (str != nil || m_substr == nil ) &&
[str isEqualToString:m_substr];
}
@@ -4734,7 +4781,7 @@ namespace Catch {
struct Contains : StringHolder {
Contains( NSString* substr ) : StringHolder( substr ){}
bool match( NSString* const& str ) const override {
bool match( NSString* str ) const override {
return (str != nil || m_substr == nil ) &&
[str rangeOfString:m_substr].location != NSNotFound;
}
@@ -4747,7 +4794,7 @@ namespace Catch {
struct StartsWith : StringHolder {
StartsWith( NSString* substr ) : StringHolder( substr ){}
bool match( NSString* const& str ) const override {
bool match( NSString* str ) const override {
return (str != nil || m_substr == nil ) &&
[str rangeOfString:m_substr].location == 0;
}
@@ -4759,7 +4806,7 @@ namespace Catch {
struct EndsWith : StringHolder {
EndsWith( NSString* substr ) : StringHolder( substr ){}
bool match( NSString* const& str ) const override {
bool match( NSString* str ) const override {
return (str != nil || m_substr == nil ) &&
[str rangeOfString:m_substr].location == [str length] - [m_substr length];
}
@@ -4867,17 +4914,23 @@ namespace Catch
namespace Catch {
struct IConfig;
class TestSpec {
struct Pattern {
class Pattern {
public:
explicit Pattern( std::string const& name );
virtual ~Pattern();
virtual bool matches( TestCaseInfo const& testCase ) const = 0;
std::string const& name() const;
private:
std::string const m_name;
};
using PatternPtr = std::shared_ptr<Pattern>;
class NamePattern : public Pattern {
public:
NamePattern( std::string const& name );
virtual ~NamePattern();
explicit NamePattern( std::string const& name, std::string const& filterString );
bool matches( TestCaseInfo const& testCase ) const override;
private:
WildcardPattern m_wildcardPattern;
@@ -4885,8 +4938,7 @@ namespace Catch {
class TagPattern : public Pattern {
public:
TagPattern( std::string const& tag );
virtual ~TagPattern();
explicit TagPattern( std::string const& tag, std::string const& filterString );
bool matches( TestCaseInfo const& testCase ) const override;
private:
std::string m_tag;
@@ -4894,8 +4946,7 @@ namespace Catch {
class ExcludedPattern : public Pattern {
public:
ExcludedPattern( PatternPtr const& underlyingPattern );
virtual ~ExcludedPattern();
explicit ExcludedPattern( PatternPtr const& underlyingPattern );
bool matches( TestCaseInfo const& testCase ) const override;
private:
PatternPtr m_underlyingPattern;
@@ -4905,11 +4956,19 @@ namespace Catch {
std::vector<PatternPtr> m_patterns;
bool matches( TestCaseInfo const& testCase ) const;
std::string name() const;
};
public:
struct FilterMatch {
std::string name;
std::vector<TestCase const*> tests;
};
using Matches = std::vector<FilterMatch>;
bool hasFilters() const;
bool matches( TestCaseInfo const& testCase ) const;
Matches matchesByFilter( std::vector<TestCase> const& testCases, IConfig const& config ) const;
private:
std::vector<Filter> m_filters;
@@ -4949,8 +5008,10 @@ namespace Catch {
enum Mode{ None, Name, QuotedName, Tag, EscapedName };
Mode m_mode = None;
bool m_exclusion = false;
std::size_t m_start = std::string::npos, m_pos = 0;
std::size_t m_pos = 0;
std::string m_arg;
std::string m_substring;
std::string m_patternName;
std::vector<std::size_t> m_escapeChars;
TestSpec::Filter m_currentFilter;
TestSpec m_testSpec;
@@ -4964,26 +5025,32 @@ namespace Catch {
private:
void visitChar( char c );
void startNewMode( Mode mode, std::size_t start );
void startNewMode( Mode mode );
bool processNoneChar( char c );
void processNameChar( char c );
bool processOtherChar( char c );
void endMode();
void escape();
std::string subString() const;
bool isControlChar( char c ) const;
template<typename T>
void addPattern() {
std::string token = subString();
std::string token = m_patternName;
for( std::size_t i = 0; i < m_escapeChars.size(); ++i )
token = token.substr( 0, m_escapeChars[i]-m_start-i ) + token.substr( m_escapeChars[i]-m_start-i+1 );
token = token.substr( 0, m_escapeChars[i] - i ) + token.substr( m_escapeChars[i] -i +1 );
m_escapeChars.clear();
if( startsWith( token, "exclude:" ) ) {
m_exclusion = true;
token = token.substr( 8 );
}
if( !token.empty() ) {
TestSpec::PatternPtr pattern = std::make_shared<T>( token );
TestSpec::PatternPtr pattern = std::make_shared<T>( token, m_substring );
if( m_exclusion )
pattern = std::make_shared<TestSpec::ExcludedPattern>( pattern );
m_currentFilter.m_patterns.push_back( pattern );
}
m_substring.clear();
m_patternName.clear();
m_exclusion = false;
m_mode = None;
}
@@ -6126,6 +6193,7 @@ namespace Catch {
void testRunEnded(TestRunStats const& testRunStats) override;
#if defined(CATCH_CONFIG_ENABLE_BENCHMARKING)
void benchmarkPreparing(std::string const& name) override;
void benchmarkStarting(BenchmarkInfo const&) override;
void benchmarkEnded(BenchmarkStats<> const&) override;
void benchmarkFailed(std::string const&) override;
@@ -9919,7 +9987,16 @@ namespace Catch {
}
// end catch_debug_console.h
#ifdef CATCH_PLATFORM_WINDOWS
#if defined(__ANDROID__)
#include <android/log.h>
namespace Catch {
void writeToDebugConsole( std::string const& text ) {
__android_log_print( ANDROID_LOG_DEBUG, "Catch", text.c_str() );
}
}
#elif defined(CATCH_PLATFORM_WINDOWS)
namespace Catch {
void writeToDebugConsole( std::string const& text ) {
@@ -10373,7 +10450,7 @@ namespace Catch {
// 32kb for the alternate stack seems to be sufficient. However, this value
// is experimentally determined, so that's not guaranteed.
constexpr static std::size_t sigStackSize = 32768 >= MINSIGSTKSZ ? 32768 : MINSIGSTKSZ;
static constexpr std::size_t sigStackSize = 32768 >= MINSIGSTKSZ ? 32768 : MINSIGSTKSZ;
static SignalDefs signalDefs[] = {
{ SIGINT, "SIGINT - Terminal interrupt signal" },
@@ -10811,9 +10888,18 @@ namespace Catch {
}
std::string TagInfo::all() const {
std::string out;
for( auto const& spelling : spellings )
out += "[" + spelling + "]";
size_t size = 0;
for (auto const& spelling : spellings) {
// Add 2 for the brackes
size += spelling.size() + 2;
}
std::string out; out.reserve(size);
for (auto const& spelling : spellings) {
out += '[';
out += spelling;
out += ']';
}
return out;
}
@@ -11660,6 +11746,8 @@ namespace Catch {
struct IConfig;
std::vector<TestCase> sortTests( IConfig const& config, std::vector<TestCase> const& unsortedTestCases );
bool isThrowSafe( TestCase const& testCase, IConfig const& config );
bool matchTest( TestCase const& testCase, TestSpec const& testSpec, IConfig const& config );
void enforceNoDuplicateTestCases( std::vector<TestCase> const& functions );
@@ -12503,7 +12591,7 @@ namespace Catch {
void libIdentify();
int applyCommandLine( int argc, char const * const * argv );
#if defined(CATCH_CONFIG_WCHAR) && defined(WIN32) && defined(UNICODE)
#if defined(CATCH_CONFIG_WCHAR) && defined(_WIN32) && defined(UNICODE)
int applyCommandLine( int argc, wchar_t const * const * argv );
#endif
@@ -12570,6 +12658,8 @@ namespace Catch {
// end catch_version.h
#include <cstdlib>
#include <iomanip>
#include <set>
#include <iterator>
namespace Catch {
@@ -12603,45 +12693,53 @@ namespace Catch {
return ret;
}
Catch::Totals runTests(std::shared_ptr<Config> const& config) {
auto reporter = makeReporter(config);
class TestGroup {
public:
explicit TestGroup(std::shared_ptr<Config> const& config)
: m_config{config}
, m_context{config, makeReporter(config)}
{
auto const& allTestCases = getAllTestCasesSorted(*m_config);
m_matches = m_config->testSpec().matchesByFilter(allTestCases, *m_config);
RunContext context(config, std::move(reporter));
Totals totals;
context.testGroupStarting(config->name(), 1, 1);
TestSpec testSpec = config->testSpec();
auto const& allTestCases = getAllTestCasesSorted(*config);
for (auto const& testCase : allTestCases) {
bool matching = (!testSpec.hasFilters() && !testCase.isHidden()) ||
(testSpec.hasFilters() && matchTest(testCase, testSpec, *config));
if (!context.aborting() && matching)
totals += context.runTest(testCase);
else
context.reporter().skipTest(testCase);
if (m_matches.empty()) {
for (auto const& test : allTestCases)
if (!test.isHidden())
m_tests.emplace(&test);
} else {
for (auto const& match : m_matches)
m_tests.insert(match.tests.begin(), match.tests.end());
}
}
if (config->warnAboutNoTests() && totals.testCases.total() == 0) {
ReusableStringStream testConfig;
bool first = true;
for (const auto& input : config->getTestsOrTags()) {
if (!first) { testConfig << ' '; }
first = false;
testConfig << input;
Totals execute() {
Totals totals;
m_context.testGroupStarting(m_config->name(), 1, 1);
for (auto const& testCase : m_tests) {
if (!m_context.aborting())
totals += m_context.runTest(*testCase);
else
m_context.reporter().skipTest(*testCase);
}
context.reporter().noMatchingTestCases(testConfig.str());
totals.error = -1;
for (auto const& match : m_matches) {
if (match.tests.empty()) {
m_context.reporter().noMatchingTestCases(match.name);
totals.error = -1;
}
}
m_context.testGroupEnded(m_config->name(), totals, 1, 1);
return totals;
}
context.testGroupEnded(config->name(), totals, 1, 1);
return totals;
}
private:
using Tests = std::set<TestCase const*>;
std::shared_ptr<Config> m_config;
RunContext m_context;
Tests m_tests;
TestSpec::Matches m_matches;
};
void applyFilenamesAsTags(Catch::IConfig const& config) {
auto& tests = const_cast<std::vector<TestCase>&>(getAllTestCasesSorted(config));
@@ -12741,7 +12839,7 @@ namespace Catch {
return 0;
}
#if defined(CATCH_CONFIG_WCHAR) && defined(WIN32) && defined(UNICODE)
#if defined(CATCH_CONFIG_WCHAR) && defined(_WIN32) && defined(UNICODE)
int Session::applyCommandLine( int argc, wchar_t const * const * argv ) {
char **utf8Argv = new char *[ argc ];
@@ -12818,7 +12916,12 @@ namespace Catch {
if( Option<std::size_t> listed = list( m_config ) )
return static_cast<int>( *listed );
auto totals = runTests( m_config );
TestGroup tests { m_config };
auto const totals = tests.execute();
if( m_config->warnAboutNoTests() && totals.error == -1 )
return 2;
// Note that on unices only the lower 8 bits are usually used, clamping
// the return value to 255 prevents false negative when some multiple
// of 256 tests has failed
@@ -13529,8 +13632,13 @@ namespace Catch {
}
return sorted;
}
bool isThrowSafe( TestCase const& testCase, IConfig const& config ) {
return !testCase.throws() || config.allowThrows();
}
bool matchTest( TestCase const& testCase, TestSpec const& testSpec, IConfig const& config ) {
return testSpec.matches( testCase ) && ( config.allowThrows() || !testCase.throws() );
return testSpec.matches( testCase ) && isThrowSafe( testCase, config );
}
void enforceNoDuplicateTestCases( std::vector<TestCase> const& functions ) {
@@ -13733,7 +13841,7 @@ namespace TestCaseTracking {
m_runState = CompletedSuccessfully;
break;
case ExecutingChildren:
if( m_children.empty() || m_children.back()->isComplete() )
if( std::all_of(m_children.begin(), m_children.end(), [](ITrackerPtr const& t){ return t->isComplete(); }) )
m_runState = CompletedSuccessfully;
break;
@@ -13876,47 +13984,77 @@ namespace Catch {
namespace Catch {
TestSpec::Pattern::~Pattern() = default;
TestSpec::NamePattern::~NamePattern() = default;
TestSpec::TagPattern::~TagPattern() = default;
TestSpec::ExcludedPattern::~ExcludedPattern() = default;
TestSpec::NamePattern::NamePattern( std::string const& name )
: m_wildcardPattern( toLower( name ), CaseSensitive::No )
TestSpec::Pattern::Pattern( std::string const& name )
: m_name( name )
{}
TestSpec::Pattern::~Pattern() = default;
std::string const& TestSpec::Pattern::name() const {
return m_name;
}
TestSpec::NamePattern::NamePattern( std::string const& name, std::string const& filterString )
: Pattern( filterString )
, m_wildcardPattern( toLower( name ), CaseSensitive::No )
{}
bool TestSpec::NamePattern::matches( TestCaseInfo const& testCase ) const {
return m_wildcardPattern.matches( toLower( testCase.name ) );
}
TestSpec::TagPattern::TagPattern( std::string const& tag ) : m_tag( toLower( tag ) ) {}
TestSpec::TagPattern::TagPattern( std::string const& tag, std::string const& filterString )
: Pattern( filterString )
, m_tag( toLower( tag ) )
{}
bool TestSpec::TagPattern::matches( TestCaseInfo const& testCase ) const {
return std::find(begin(testCase.lcaseTags),
end(testCase.lcaseTags),
m_tag) != end(testCase.lcaseTags);
}
TestSpec::ExcludedPattern::ExcludedPattern( PatternPtr const& underlyingPattern ) : m_underlyingPattern( underlyingPattern ) {}
bool TestSpec::ExcludedPattern::matches( TestCaseInfo const& testCase ) const { return !m_underlyingPattern->matches( testCase ); }
TestSpec::ExcludedPattern::ExcludedPattern( PatternPtr const& underlyingPattern )
: Pattern( underlyingPattern->name() )
, m_underlyingPattern( underlyingPattern )
{}
bool TestSpec::ExcludedPattern::matches( TestCaseInfo const& testCase ) const {
return !m_underlyingPattern->matches( testCase );
}
bool TestSpec::Filter::matches( TestCaseInfo const& testCase ) const {
// All patterns in a filter must match for the filter to be a match
for( auto const& pattern : m_patterns ) {
if( !pattern->matches( testCase ) )
return false;
}
return true;
return std::all_of( m_patterns.begin(), m_patterns.end(), [&]( PatternPtr const& p ){ return p->matches( testCase ); } );
}
std::string TestSpec::Filter::name() const {
std::string name;
for( auto const& p : m_patterns )
name += p->name();
return name;
}
bool TestSpec::hasFilters() const {
return !m_filters.empty();
}
bool TestSpec::matches( TestCaseInfo const& testCase ) const {
// A TestSpec matches if any filter matches
for( auto const& filter : m_filters )
if( filter.matches( testCase ) )
return true;
return false;
return std::any_of( m_filters.begin(), m_filters.end(), [&]( Filter const& f ){ return f.matches( testCase ); } );
}
TestSpec::Matches TestSpec::matchesByFilter( std::vector<TestCase> const& testCases, IConfig const& config ) const
{
Matches matches( m_filters.size() );
std::transform( m_filters.begin(), m_filters.end(), matches.begin(), [&]( Filter const& filter ){
std::vector<TestCase const*> currentMatches;
for( auto const& test : testCases )
if( isThrowSafe( test, config ) && filter.matches( test ) )
currentMatches.emplace_back( &test );
return FilterMatch{ filter.name(), currentMatches };
} );
return matches;
}
}
// end catch_test_spec.cpp
// start catch_test_spec_parser.cpp
@@ -13928,64 +14066,125 @@ namespace Catch {
TestSpecParser& TestSpecParser::parse( std::string const& arg ) {
m_mode = None;
m_exclusion = false;
m_start = std::string::npos;
m_arg = m_tagAliases->expandAliases( arg );
m_escapeChars.clear();
m_substring.reserve(m_arg.size());
m_patternName.reserve(m_arg.size());
for( m_pos = 0; m_pos < m_arg.size(); ++m_pos )
visitChar( m_arg[m_pos] );
if( m_mode == Name )
addPattern<TestSpec::NamePattern>();
endMode();
return *this;
}
TestSpec TestSpecParser::testSpec() {
addFilter();
return m_testSpec;
}
void TestSpecParser::visitChar( char c ) {
if( m_mode == None ) {
switch( c ) {
case ' ': return;
case '~': m_exclusion = true; return;
case '[': return startNewMode( Tag, ++m_pos );
case '"': return startNewMode( QuotedName, ++m_pos );
case '\\': return escape();
default: startNewMode( Name, m_pos ); break;
}
if( c == ',' ) {
endMode();
addFilter();
return;
}
if( m_mode == Name ) {
if( c == ',' ) {
addPattern<TestSpec::NamePattern>();
addFilter();
}
else if( c == '[' ) {
if( subString() == "exclude:" )
m_exclusion = true;
else
addPattern<TestSpec::NamePattern>();
startNewMode( Tag, ++m_pos );
}
else if( c == '\\' )
escape();
switch( m_mode ) {
case None:
if( processNoneChar( c ) )
return;
break;
case Name:
processNameChar( c );
break;
case EscapedName:
endMode();
break;
default:
case Tag:
case QuotedName:
if( processOtherChar( c ) )
return;
break;
}
else if( m_mode == EscapedName )
m_mode = Name;
else if( m_mode == QuotedName && c == '"' )
addPattern<TestSpec::NamePattern>();
else if( m_mode == Tag && c == ']' )
addPattern<TestSpec::TagPattern>();
m_substring += c;
if( !isControlChar( c ) )
m_patternName += c;
}
void TestSpecParser::startNewMode( Mode mode, std::size_t start ) {
// Two of the processing methods return true to signal the caller to return
// without adding the given character to the current pattern strings
bool TestSpecParser::processNoneChar( char c ) {
switch( c ) {
case ' ':
return true;
case '~':
m_exclusion = true;
return false;
case '[':
startNewMode( Tag );
return false;
case '"':
startNewMode( QuotedName );
return false;
case '\\':
escape();
return true;
default:
startNewMode( Name );
return false;
}
}
void TestSpecParser::processNameChar( char c ) {
if( c == '[' ) {
if( m_substring == "exclude:" )
m_exclusion = true;
else
endMode();
startNewMode( Tag );
}
}
bool TestSpecParser::processOtherChar( char c ) {
if( !isControlChar( c ) )
return false;
m_substring += c;
endMode();
return true;
}
void TestSpecParser::startNewMode( Mode mode ) {
m_mode = mode;
m_start = start;
}
void TestSpecParser::endMode() {
switch( m_mode ) {
case Name:
case QuotedName:
return addPattern<TestSpec::NamePattern>();
case Tag:
return addPattern<TestSpec::TagPattern>();
case EscapedName:
return startNewMode( Name );
case None:
default:
return startNewMode( None );
}
}
void TestSpecParser::escape() {
if( m_mode == None )
m_start = m_pos;
m_mode = EscapedName;
m_escapeChars.push_back( m_pos );
}
std::string TestSpecParser::subString() const { return m_arg.substr( m_start, m_pos - m_start ); }
bool TestSpecParser::isControlChar( char c ) const {
switch( m_mode ) {
default:
return false;
case None:
return c == '~';
case Name:
return c == '[';
case EscapedName:
return true;
case QuotedName:
return c == '"';
case Tag:
return c == '[' || c == ']';
}
}
void TestSpecParser::addFilter() {
if( !m_currentFilter.m_patterns.empty() ) {
@@ -14225,6 +14424,13 @@ std::string StringMaker<wchar_t *>::convert(wchar_t * str) {
}
#endif
#if defined(CATCH_CONFIG_CPP17_BYTE)
#include <cstddef>
std::string StringMaker<std::byte>::convert(std::byte value) {
return ::Catch::Detail::stringify(std::to_integer<unsigned long long>(value));
}
#endif // defined(CATCH_CONFIG_CPP17_BYTE)
std::string StringMaker<int>::convert(int value) {
return ::Catch::Detail::stringify(static_cast<long long>(value));
}
@@ -14414,7 +14620,7 @@ namespace Catch {
}
Version const& libraryVersion() {
static Version version( 2, 9, 1, "", 0 );
static Version version( 2, 9, 2, "", 0 );
return version;
}
@@ -15001,24 +15207,25 @@ private:
if (itMessage == messages.end())
return;
// using messages.end() directly yields (or auto) compilation error:
std::vector<MessageInfo>::const_iterator itEnd = messages.end();
const std::size_t N = static_cast<std::size_t>(std::distance(itMessage, itEnd));
const auto itEnd = messages.cend();
const auto N = static_cast<std::size_t>(std::distance(itMessage, itEnd));
{
Colour colourGuard(colour);
stream << " with " << pluralise(N, "message") << ':';
}
for (; itMessage != itEnd; ) {
while (itMessage != itEnd) {
// If this assertion is a warning ignore any INFO messages
if (printInfoMessages || itMessage->type != ResultWas::Info) {
stream << " '" << itMessage->message << '\'';
if (++itMessage != itEnd) {
printMessage();
if (itMessage != itEnd) {
Colour colourGuard(dimColour());
stream << " and";
}
continue;
}
++itMessage;
}
}
@@ -16355,10 +16562,13 @@ namespace Catch {
}
#if defined(CATCH_CONFIG_ENABLE_BENCHMARKING)
void XmlReporter::benchmarkStarting(BenchmarkInfo const &info) {
void XmlReporter::benchmarkPreparing(std::string const& name) {
m_xml.startElement("BenchmarkResults")
.writeAttribute("name", info.name)
.writeAttribute("samples", info.samples)
.writeAttribute("name", name);
}
void XmlReporter::benchmarkStarting(BenchmarkInfo const &info) {
m_xml.writeAttribute("samples", info.samples)
.writeAttribute("resamples", info.resamples)
.writeAttribute("iterations", info.iterations)
.writeAttribute("clockResolution", static_cast<uint64_t>(info.clockResolution))