mirror of
https://github.com/catchorg/Catch2.git
synced 2025-09-13 17:05:39 +02:00
Compare commits
63 Commits
Author | SHA1 | Date | |
---|---|---|---|
![]() |
2c869e17e4 | ||
![]() |
0ab11aa9b4 | ||
![]() |
7a6af7ba76 | ||
![]() |
fa096b26d1 | ||
![]() |
820b1f12bf | ||
![]() |
6070745cab | ||
![]() |
3d9e7db2e0 | ||
![]() |
cf55cfd76f | ||
![]() |
3701c2e2e6 | ||
![]() |
7dc7d77af2 | ||
![]() |
06bc20cf37 | ||
![]() |
7a4beed6a6 | ||
![]() |
67b4ada6b0 | ||
![]() |
119569a67e | ||
![]() |
ab713894cc | ||
![]() |
69fc94d6f8 | ||
![]() |
49cd7c96b4 | ||
![]() |
e998d152cc | ||
![]() |
42a5903188 | ||
![]() |
c071f07e1a | ||
![]() |
53776a90cf | ||
![]() |
4511dc0c16 | ||
![]() |
e7c3bdb351 | ||
![]() |
9aab958667 | ||
![]() |
8cd58f75ec | ||
![]() |
d5a69cd400 | ||
![]() |
1d13d88833 | ||
![]() |
de0674c116 | ||
![]() |
3d7282c2bd | ||
![]() |
e5c0e3322d | ||
![]() |
dc8c8e957f | ||
![]() |
ba9193370b | ||
![]() |
7b70b11c23 | ||
![]() |
ab80277a86 | ||
![]() |
7e7ab0e28b | ||
![]() |
425957dc63 | ||
![]() |
d017f6d18f | ||
![]() |
91244d30a7 | ||
![]() |
62b3f6c3c2 | ||
![]() |
e7c26f09d1 | ||
![]() |
a22b7df46c | ||
![]() |
032068b889 | ||
![]() |
2aed6233cf | ||
![]() |
fb74bb133c | ||
![]() |
0b42ada60d | ||
![]() |
c424ca47f9 | ||
![]() |
52f3abadbb | ||
![]() |
53281b471f | ||
![]() |
03ffc1014c | ||
![]() |
87739ad3fe | ||
![]() |
0c27554af5 | ||
![]() |
11488e63b6 | ||
![]() |
820271bf24 | ||
![]() |
56d4510138 | ||
![]() |
c0d3a2e08f | ||
![]() |
2c3018a9d5 | ||
![]() |
9a6551b22b | ||
![]() |
800f1b1d3d | ||
![]() |
9cf5897a11 | ||
![]() |
6f32c67ea7 | ||
![]() |
7eea3ab245 | ||
![]() |
80af9ca687 | ||
![]() |
33286fdc37 |
@@ -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
|
||||
|
@@ -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
|
||||
|
@@ -5,11 +5,11 @@
|
||||
[](https://travis-ci.org/catchorg/Catch2)
|
||||
[](https://ci.appveyor.com/project/catchorg/catch2)
|
||||
[](https://codecov.io/gh/catchorg/Catch2)
|
||||
[](https://wandbox.org/permlink/5icuqPwk9miJLAL1)
|
||||
[](https://wandbox.org/permlink/8YrGVqYqqSC4Sc5R)
|
||||
[](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.
|
||||
|
||||
|
@@ -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
|
||||
|
@@ -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._
|
||||
|
@@ -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.
|
||||
|
@@ -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 <# of samples></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 <# of resamples></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 <confidence-interval></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.
|
||||
|
||||
|
@@ -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
|
||||
|
@@ -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
|
||||
|
@@ -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`:
|
||||
|
@@ -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_ **)**
|
||||
|
@@ -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.
|
||||
|
@@ -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)
|
||||
|
@@ -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.
|
||||
|
@@ -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)
|
||||
|
||||
|
@@ -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
|
||||
|
@@ -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.
|
||||
|
@@ -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
|
||||
|
@@ -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
|
||||
|
@@ -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
|
||||
|
||||
|
@@ -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 ) {
|
||||
|
@@ -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" },
|
||||
|
@@ -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:
|
||||
|
@@ -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 {
|
||||
|
@@ -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 );
|
||||
|
@@ -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;
|
||||
}
|
||||
|
||||
|
@@ -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
|
||||
|
@@ -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];
|
||||
}
|
||||
|
@@ -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
|
||||
|
@@ -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
|
||||
|
||||
|
@@ -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 ) {
|
||||
|
@@ -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 );
|
||||
|
@@ -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;
|
||||
|
||||
|
@@ -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;\
|
||||
|
@@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
|
@@ -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;
|
||||
|
@@ -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() ) {
|
||||
|
@@ -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;
|
||||
}
|
||||
|
@@ -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));
|
||||
|
@@ -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);
|
||||
|
@@ -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;
|
||||
}
|
||||
|
||||
|
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
|
@@ -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))
|
||||
|
@@ -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;
|
||||
|
@@ -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)
|
||||
|
@@ -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:
|
||||
|
@@ -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>)
|
||||
|
@@ -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
|
||||
|
@@ -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
|
||||
|
||||
|
@@ -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
|
||||
|
||||
|
@@ -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
|
||||
|
||||
|
@@ -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}"/>
|
||||
|
@@ -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>
|
||||
|
@@ -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();
|
||||
}
|
||||
}
|
||||
|
@@ -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
|
||||
|
||||
|
||||
|
@@ -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);
|
||||
|
@@ -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!" );
|
||||
}
|
||||
|
15
projects/SelfTest/UsageTests/ToStringByte.tests.cpp
Normal file
15
projects/SelfTest/UsageTests/ToStringByte.tests.cpp
Normal 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
|
@@ -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;
|
||||
|
19
projects/SelfTest/WarnAboutNoTests.cmake
Normal file
19
projects/SelfTest/WarnAboutNoTests.cmake
Normal 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()
|
94
scripts/extractFeaturesFromReleaseNotes.py
Normal file
94
scripts/extractFeaturesFromReleaseNotes.py
Normal 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()
|
@@ -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)
|
||||
|
@@ -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))
|
||||
|
Reference in New Issue
Block a user