mirror of
https://github.com/catchorg/Catch2.git
synced 2025-09-14 01:15:39 +02:00
Compare commits
52 Commits
Author | SHA1 | Date | |
---|---|---|---|
![]() |
b9dd1936e5 | ||
![]() |
293d617c49 | ||
![]() |
7be35af167 | ||
![]() |
08147a23f9 | ||
![]() |
8af8704089 | ||
![]() |
3816e99d0c | ||
![]() |
b77cec05c0 | ||
![]() |
54089c4c8c | ||
![]() |
296d447452 | ||
![]() |
0531965349 | ||
![]() |
a1cdff4f18 | ||
![]() |
4611125801 | ||
![]() |
e509012e64 | ||
![]() |
448825db03 | ||
![]() |
0fff8e7791 | ||
![]() |
68a3c129ac | ||
![]() |
1ce5ec9b74 | ||
![]() |
37a4e32319 | ||
![]() |
0424c9a62c | ||
![]() |
d633072794 | ||
![]() |
51ed08be22 | ||
![]() |
1701325caa | ||
![]() |
7aee973a4a | ||
![]() |
99575b45db | ||
![]() |
1a03918455 | ||
![]() |
bd667f4d69 | ||
![]() |
28db5ed4c9 | ||
![]() |
7d2451f119 | ||
![]() |
5bf6e47381 | ||
![]() |
29b3b7ae6b | ||
![]() |
ef5fd8d42f | ||
![]() |
693647c43f | ||
![]() |
288387fa10 | ||
![]() |
165de9b072 | ||
![]() |
bf4771a7ed | ||
![]() |
7012a31a39 | ||
![]() |
269303d9d9 | ||
![]() |
e8bfd882e8 | ||
![]() |
2bd0722470 | ||
![]() |
45ebf17ec7 | ||
![]() |
093b72416d | ||
![]() |
c99a346490 | ||
![]() |
359a54b6bd | ||
![]() |
711d750ca7 | ||
![]() |
95f7712808 | ||
![]() |
dbbab8727c | ||
![]() |
5d4061af12 | ||
![]() |
9ccea82d7f | ||
![]() |
dd3d27de57 | ||
![]() |
7f229b4ff1 | ||
![]() |
c03b23c84b | ||
![]() |
17686ba571 |
@@ -6,7 +6,7 @@ if(NOT DEFINED PROJECT_NAME)
|
||||
set(NOT_SUBPROJECT ON)
|
||||
endif()
|
||||
|
||||
project(Catch2 LANGUAGES CXX VERSION 2.6.0)
|
||||
project(Catch2 LANGUAGES CXX VERSION 2.7.1)
|
||||
|
||||
# Provide path for scripts
|
||||
list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_LIST_DIR}/CMake")
|
||||
|
@@ -5,17 +5,17 @@
|
||||
[](https://travis-ci.org/catchorg/Catch2)
|
||||
[](https://ci.appveyor.com/project/catchorg/catch2)
|
||||
[](https://codecov.io/gh/catchorg/Catch2)
|
||||
[](https://wandbox.org/permlink/85qcYBOdUKzlnpl5)
|
||||
[](https://wandbox.org/permlink/ZFBZ5XbLA9F1gzKi)
|
||||
[](https://discord.gg/4CWS9zD)
|
||||
|
||||
|
||||
<a href="https://github.com/catchorg/Catch2/releases/download/v2.6.0/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.7.1/catch.hpp">The latest version of the single header can be downloaded directly using this link</a>
|
||||
|
||||
## Catch2 is released!
|
||||
|
||||
If you've been using an earlier version of Catch, please see the
|
||||
Breaking Changes section of [the release notes](https://github.com/catchorg/Catch2/releases/tag/v2.0.1)
|
||||
before moving to Catch2. You might also like to read [this blog post](http://www.levelofindirection.com/journal/2017/11/3/catch2-released.html) for more details.
|
||||
before moving to Catch2. You might also like to read [this blog post](https://levelofindirection.com/blog/catch2-released.html) for more details.
|
||||
|
||||
## What's the Catch?
|
||||
|
||||
|
@@ -172,6 +172,9 @@ function(ParseFile SourceFile TestTarget)
|
||||
PrintDebugMessage("Setting labels to ${Labels}")
|
||||
endif()
|
||||
|
||||
# Escape commas in the test spec
|
||||
string(REPLACE "," "\\," Name ${Name})
|
||||
|
||||
# Add the test and set its properties
|
||||
add_test(NAME "\"${CTestName}\"" COMMAND ${OptionalCatchTestLauncher} ${TestTarget} ${Name} ${AdditionalCatchParameters})
|
||||
# Old CMake versions do not document VERSION_GREATER_EQUAL, so we use VERSION_GREATER with 3.8 instead
|
||||
|
@@ -10,7 +10,7 @@
|
||||
|
||||
Most test frameworks have a large collection of assertion macros to capture all possible conditional forms (```_EQUALS```, ```_NOTEQUALS```, ```_GREATER_THAN``` etc).
|
||||
|
||||
Catch is different. Because it decomposes natural C-style conditional expressions most of these forms are reduced to one or two that you will use all the time. That said there are a rich set of auxiliary macros as well. We'll describe all of these here.
|
||||
Catch is different. Because it decomposes natural C-style conditional expressions most of these forms are reduced to one or two that you will use all the time. That said there is a rich set of auxiliary macros as well. We'll describe all of these here.
|
||||
|
||||
Most of these macros come in two forms:
|
||||
|
||||
@@ -61,7 +61,7 @@ Catch provides a way to perform tolerant comparisons of floating point values th
|
||||
REQUIRE( performComputation() == Approx( 2.1 ) );
|
||||
```
|
||||
|
||||
Catch also provides a UDL for `Approx`; `_a`. It resides in
|
||||
Catch also provides a user-defined literal for `Approx`; `_a`. It resides in
|
||||
the `Catch::literals` namespace and can be used like so:
|
||||
```cpp
|
||||
using namespace Catch::literals;
|
||||
|
@@ -48,7 +48,7 @@ If Catch2 has been installed in system, both of these can be used after
|
||||
doing `find_package(Catch2 REQUIRED)`. Otherwise you need to add them
|
||||
to your CMake module path.
|
||||
|
||||
### `Catch.cmake` and `AddCatchTests.cmake`
|
||||
### `Catch.cmake` and `CatchAddTests.cmake`
|
||||
|
||||
`Catch.cmake` provides function `catch_discover_tests` to get tests from
|
||||
a target. This function works by running the resulting executable with
|
||||
|
@@ -16,3 +16,4 @@ fact then please let us know - either directly, via a PR or
|
||||
- [Bloomlife](https://bloomlife.com)
|
||||
- NASA
|
||||
- [Inscopix Inc.](https://www.inscopix.com/)
|
||||
- [Makimo](https://makimo.pl/)
|
||||
|
@@ -36,13 +36,18 @@ a test case,
|
||||
* 2 fundamental generators
|
||||
* `ValueGenerator<T>` -- contains only single element
|
||||
* `ValuesGenerator<T>` -- contains multiple elements
|
||||
* 4 generic generators that modify other generators
|
||||
* 5 generic generators that modify other generators
|
||||
* `FilterGenerator<T, Predicate>` -- filters out elements from a generator
|
||||
for which the predicate returns "false"
|
||||
* `TakeGenerator<T>` -- takes first `n` elements from a generator
|
||||
* `RepeatGenerator<T>` -- repeats output from a generator `n` times
|
||||
* `MapGenerator<T, U, Func>` -- returns the result of applying `Func`
|
||||
on elements from a different generator
|
||||
* `ChunkGenerator<T>` -- returns chunks (inside `std::vector`) of n elements from a generator
|
||||
* 3 specific purpose generators
|
||||
* `RandomIntegerGenerator<Integral>` -- generates random Integrals from range
|
||||
* `RandomFloatGenerator<Float>` -- generates random Floats from range
|
||||
* `RangeGenerator<T>` -- generates all values inside a specific range
|
||||
|
||||
The generators also have associated helper functions that infer their
|
||||
type, making their usage much nicer. These are
|
||||
@@ -52,8 +57,13 @@ type, making their usage much nicer. These are
|
||||
* `filter(predicate, GeneratorWrapper<T>&&)` for `FilterGenerator<T, Predicate>`
|
||||
* `take(count, GeneratorWrapper<T>&&)` for `TakeGenerator<T>`
|
||||
* `repeat(repeats, GeneratorWrapper<T>&&)` for `RepeatGenerator<T>`
|
||||
* `map(func, GeneratorWrapper<T>&&)` for `MapGenerator<T, T, Func>` (map `T` to `T`)
|
||||
* `map(func, GeneratorWrapper<T>&&)` for `MapGenerator<T, U, Func>` (map `U` to `T`, deduced from `Func`)
|
||||
* `map<T>(func, GeneratorWrapper<U>&&)` for `MapGenerator<T, U, Func>` (map `U` to `T`)
|
||||
* `chunk(chunk-size, GeneratorWrapper<T>&&)` for `ChunkGenerator<T>`
|
||||
* `random(IntegerOrFloat a, IntegerOrFloat b)` for `RandomIntegerGenerator` or `RandomFloatGenerator`
|
||||
* `range(start, end)` for `RangeGenerator<T>` with a step size of `1`
|
||||
* `range(start, end, step)` for `RangeGenerator<T>` with a custom step size
|
||||
|
||||
|
||||
And can be used as shown in the example below to create a generator
|
||||
that returns 100 odd random number:
|
||||
@@ -69,8 +79,6 @@ TEST_CASE("Generating random ints", "[example][generator]") {
|
||||
}
|
||||
```
|
||||
|
||||
_Note that `random` is currently not a part of the first-party generators_.
|
||||
|
||||
|
||||
Apart from registering generators with Catch2, the `GENERATE` macro has
|
||||
one more purpose, and that is to provide simple way of generating trivial
|
||||
@@ -82,7 +90,11 @@ used with other generators as arguments, such as `auto i = GENERATE(0, 2,
|
||||
take(100, random(300, 3000)));`. This is useful e.g. if you know that
|
||||
specific inputs are problematic and want to test them separately/first.
|
||||
|
||||
**For safety reasons, you cannot use variables inside the `GENERATE` macro.**
|
||||
**For safety reasons, you cannot use variables inside the `GENERATE` macro.
|
||||
This is done because the generator expression _will_ outlive the outside
|
||||
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`.**
|
||||
|
||||
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,
|
||||
@@ -90,7 +102,7 @@ if you want them to come out as `std::string`:
|
||||
|
||||
```cpp
|
||||
TEST_CASE("type conversion", "[generators]") {
|
||||
auto str = GENERATE(as<std::string>{}, "a", "bb", "ccc");`
|
||||
auto str = GENERATE(as<std::string>{}, "a", "bb", "ccc");
|
||||
REQUIRE(str.size() > 0);
|
||||
}
|
||||
```
|
||||
|
@@ -15,7 +15,9 @@
|
||||
- Listener: [Listeners](../examples/210-Evt-EventListeners.cpp)
|
||||
- Configuration: [Provide your own output streams](../examples/231-Cfg-OutputStreams.cpp)
|
||||
- Generators: [Create your own generator](../examples/300-Gen-OwnGenerator.cpp)
|
||||
- Generators: [Use map to convert types in GENERATE expression](../examples/301-Gen-MapTypeConversion.cpp)
|
||||
- Generators: [Use variables in generator expressions](../examples/310-Gen-VariablesInGenerators.cpp)
|
||||
- Generators: [Use custom variable capture in generator expressions](../examples/311-Gen-CustomCapture.cpp)
|
||||
|
||||
|
||||
## Planned
|
||||
|
@@ -1,7 +1,7 @@
|
||||
<a id="top"></a>
|
||||
# Logging macros
|
||||
|
||||
Additional messages can be logged during a test case. Note that the messages are scoped and thus will not be reported if failure occurs in scope preceding the message declaration. An example:
|
||||
Additional messages can be logged during a test case. Note that the messages logged with `INFO` are scoped and thus will not be reported if failure occurs in scope preceding the message declaration. An example:
|
||||
|
||||
```cpp
|
||||
TEST_CASE("Foo") {
|
||||
@@ -28,6 +28,60 @@ The number is 1
|
||||
```
|
||||
When the last `CHECK` fails in the "Bar" test case, then only one message will be printed: `Test case start`.
|
||||
|
||||
## Logging without local scope
|
||||
|
||||
`UNSCOPED_INFO` is similar to `INFO` with two key differences:
|
||||
|
||||
- Lifetime of an unscoped message is not tied to its own scope.
|
||||
- An unscoped message can be reported by the first following assertion only, regardless of the result of that assertion.
|
||||
|
||||
In other words, lifetime of `UNSCOPED_INFO` is limited by the following assertion (or by the end of test case/section, whichever comes first) whereas lifetime of `INFO` is limited by its own scope.
|
||||
|
||||
These differences make this macro useful for reporting information from helper functions or inner scopes. An example:
|
||||
|
||||
```cpp
|
||||
void print_some_info() {
|
||||
UNSCOPED_INFO("Info from helper");
|
||||
}
|
||||
|
||||
TEST_CASE("Baz") {
|
||||
print_some_info();
|
||||
for (int i = 0; i < 2; ++i) {
|
||||
UNSCOPED_INFO("The number is " << i);
|
||||
}
|
||||
CHECK(false);
|
||||
}
|
||||
|
||||
TEST_CASE("Qux") {
|
||||
INFO("First info");
|
||||
UNSCOPED_INFO("First unscoped info");
|
||||
CHECK(false);
|
||||
|
||||
INFO("Second info");
|
||||
UNSCOPED_INFO("Second unscoped info");
|
||||
CHECK(false);
|
||||
}
|
||||
```
|
||||
|
||||
"Baz" test case prints:
|
||||
```
|
||||
Info from helper
|
||||
The number is 0
|
||||
The number is 1
|
||||
```
|
||||
|
||||
With "Qux" test case, two messages will be printed when the first `CHECK` fails:
|
||||
```
|
||||
First info
|
||||
First unscoped info
|
||||
```
|
||||
|
||||
"First unscoped info" message will be cleared after the first `CHECK`, while "First info" message will persist until the end of the test case. Therefore, when the second `CHECK` fails, three messages will be printed:
|
||||
```
|
||||
First info
|
||||
Second info
|
||||
Second unscoped info
|
||||
```
|
||||
|
||||
## Streaming macros
|
||||
|
||||
@@ -43,11 +97,15 @@ These macros come in three forms:
|
||||
|
||||
**INFO(** _message expression_ **)**
|
||||
|
||||
The message is logged to a buffer, but only reported with the next assertion that is logged. This allows you to log contextual information in case of failures which is not shown during a successful test run (for the console reporter, without -s). Messages are removed from the buffer at the end of their scope, so may be used, for example, in loops.
|
||||
The message is logged to a buffer, but only reported with next assertions that are logged. This allows you to log contextual information in case of failures which is not shown during a successful test run (for the console reporter, without -s). Messages are removed from the buffer at the end of their scope, so may be used, for example, in loops.
|
||||
|
||||
_Note that in Catch2 2.x.x `INFO` can be used without a trailing semicolon as there is a trailing semicolon inside macro.
|
||||
This semicolon will be removed with next major version. It is highly advised to use a trailing semicolon after `INFO` macro._
|
||||
|
||||
**UNSCOPED_INFO(** _message expression_ **)**
|
||||
|
||||
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_ **)**
|
||||
|
||||
The message is always reported but does not fail the test.
|
||||
|
@@ -100,7 +100,7 @@ public:
|
||||
// include any provided data (the begin/ end in this case) and
|
||||
// be written as if it were stating a fact (in the output it will be
|
||||
// preceded by the value under test).
|
||||
virtual std::string describe() const {
|
||||
virtual std::string describe() const override {
|
||||
std::ostringstream ss;
|
||||
ss << "is between " << m_begin << " and " << m_end;
|
||||
return ss.str();
|
||||
|
@@ -17,29 +17,32 @@ Listing a project here does not imply endorsement and the plan is to keep these
|
||||
|
||||
## Libraries & Frameworks
|
||||
|
||||
### [ApprovalTests.cpp](https://github.com/approvals/ApprovalTests.cpp)
|
||||
C++11 implementation of Approval Tests, for quick, convenient testing of legacy code.
|
||||
|
||||
### [Azmq](https://github.com/zeromq/azmq)
|
||||
Boost Asio style bindings for ZeroMQ
|
||||
Boost Asio style bindings for ZeroMQ.
|
||||
|
||||
### [ChakraCore](https://github.com/Microsoft/ChakraCore)
|
||||
The core part of the Chakra JavaScript engine that powers Microsoft Edge
|
||||
The core part of the Chakra JavaScript engine that powers Microsoft Edge.
|
||||
|
||||
### [ChaiScript](https://github.com/ChaiScript/ChaiScript)
|
||||
A, header-only, embedded scripting language designed from the ground up to directly target C++ and take advantage of modern C++ development techniques
|
||||
A, header-only, embedded scripting language designed from the ground up to directly target C++ and take advantage of modern C++ development techniques.
|
||||
|
||||
### [Clara](https://github.com/philsquared/Clara)
|
||||
A, single-header-only, type-safe, command line parser - which also prints formatted usage strings.
|
||||
|
||||
### [Couchbase-lite-core](https://github.com/couchbase/couchbase-lite-core)
|
||||
The next-generation core storage and query engine for Couchbase Lite
|
||||
The next-generation core storage and query engine for Couchbase Lite.
|
||||
|
||||
### [cppcodec](https://github.com/tplgy/cppcodec)
|
||||
Header-only C++11 library to encode/decode base64, base64url, base32, base32hex and hex (a.k.a. base16) as specified in RFC 4648, plus Crockford's base32.
|
||||
|
||||
### [DtCraft](https://github.com/twhuang-uiuc/DtCraft)
|
||||
A High-performance Cluster Computing Engine
|
||||
A High-performance Cluster Computing Engine.
|
||||
|
||||
### [forest](https://github.com/xorz57/forest)
|
||||
Template Library of Tree Data Structures
|
||||
Template Library of Tree Data Structures.
|
||||
|
||||
### [Fuxedo](https://github.com/fuxedo/fuxedo)
|
||||
Open source Oracle Tuxedo-like XATMI middleware for C and C++.
|
||||
@@ -63,25 +66,25 @@ A small C++ library wrapper for the native C ODBC API.
|
||||
A header-only framework for benchmarking small snippets of C++ code.
|
||||
|
||||
### [SOCI](https://github.com/SOCI/soci)
|
||||
The C++ Database Access Library
|
||||
The C++ Database Access Library.
|
||||
|
||||
### [polymorphic_value](https://github.com/jbcoe/polymorphic_value)
|
||||
A polymorphic value-type for C++
|
||||
A polymorphic value-type for C++.
|
||||
|
||||
### [Ppconsul](https://github.com/oliora/ppconsul)
|
||||
A C++ client library for Consul. Consul is a distributed tool for discovering and configuring services in your infrastructure
|
||||
A C++ client library for Consul. Consul is a distributed tool for discovering and configuring services in your infrastructure.
|
||||
|
||||
### [Reactive-Extensions/ RxCpp](https://github.com/Reactive-Extensions/RxCpp)
|
||||
A library of algorithms for values-distributed-in-time
|
||||
A library of algorithms for values-distributed-in-time.
|
||||
|
||||
### [thor](https://github.com/xorz57/thor)
|
||||
Wrapper Library for CUDA
|
||||
Wrapper Library for CUDA.
|
||||
|
||||
### [TextFlowCpp](https://github.com/philsquared/textflowcpp)
|
||||
A small, single-header-only, library for wrapping and composing columns of text
|
||||
A small, single-header-only, library for wrapping and composing columns of text.
|
||||
|
||||
### [Trompeloeil](https://github.com/rollbear/trompeloeil)
|
||||
A thread safe header only mocking framework for C++14
|
||||
A thread-safe header-only mocking framework for C++14.
|
||||
|
||||
### [args](https://github.com/Taywee/args)
|
||||
A simple header-only C++ argument parser library.
|
||||
@@ -95,16 +98,19 @@ ArangoDB is a native multi-model database with flexible data models for document
|
||||
Minimal, open-source and cross-platform audio tool for live music production.
|
||||
|
||||
### [MAME](https://github.com/mamedev/mame)
|
||||
MAME originally stood for Multiple Arcade Machine Emulator
|
||||
MAME originally stood for Multiple Arcade Machine Emulator.
|
||||
|
||||
### [Newsbeuter](https://github.com/akrennmair/newsbeuter)
|
||||
Newsbeuter is an open-source RSS/Atom feed reader for text terminals.
|
||||
|
||||
### [raspigcd](https://github.com/pantadeusz/raspigcd)
|
||||
Low level CLI app and library for execution of GCODE on Raspberry Pi without any additional microcontrolers (just RPi + Stepsticks).
|
||||
|
||||
### [SpECTRE](https://github.com/sxs-collaboration/spectre)
|
||||
SpECTRE is a code for multi-scale, multi-physics problems in astrophysics and gravitational physics.
|
||||
|
||||
### [Standardese](https://github.com/foonathan/standardese)
|
||||
Standardese aims to be a nextgen Doxygen
|
||||
Standardese aims to be a nextgen Doxygen.
|
||||
|
||||
---
|
||||
|
||||
|
@@ -2,6 +2,9 @@
|
||||
|
||||
# Release notes
|
||||
**Contents**<br>
|
||||
[2.7.1](#271)<br>
|
||||
[2.7.0](#270)<br>
|
||||
[2.6.1](#261)<br>
|
||||
[2.6.0](#260)<br>
|
||||
[2.5.0](#250)<br>
|
||||
[2.4.2](#242)<br>
|
||||
@@ -19,6 +22,64 @@
|
||||
[Older versions](#older-versions)<br>
|
||||
[Even Older versions](#even-older-versions)<br>
|
||||
|
||||
## 2.7.1
|
||||
|
||||
### 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
|
||||
* 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)
|
||||
|
||||
### Fixes
|
||||
* Fixed ObjC++ compilation (#1571)
|
||||
* Fixed test tag parsing so that `[.foo]` is now parsed as `[.][foo]`.
|
||||
* Suppressed warning caused by the Windows headers defining SE codes in different manners (#1575)
|
||||
|
||||
## 2.7.0
|
||||
|
||||
### Improvements
|
||||
* `TEMPLATE_PRODUCT_TEST_CASE` now uses the resulting type in the name, instead of the serial number (#1544)
|
||||
* Catch2's single header is now strictly ASCII (#1542)
|
||||
* Added generator for random integral/floating point types
|
||||
* The types are inferred within the `random` helper
|
||||
* Added back RangeGenerator (#1526)
|
||||
* RangeGenerator returns elements within a certain range
|
||||
* Added ChunkGenerator generic transform (#1538)
|
||||
* A ChunkGenerator returns the elements from different generator in chunks of n elements
|
||||
* Added `UNSCOPED_INFO` (#415, #983, #1522)
|
||||
* This is a variant of `INFO` that lives until next assertion/end of the test case.
|
||||
|
||||
|
||||
### Fixes
|
||||
* All calls to C stdlib functions are now `std::` qualified (#1541)
|
||||
* Code brought in from Clara was also updated.
|
||||
* Running tests will no longer open the specified output file twice (#1545)
|
||||
* This would cause trouble when the file was not a file, but rather a named pipe
|
||||
* Fixes the CLion/Resharper integration with Catch
|
||||
* Fixed `-Wunreachable-code` occuring with (old) ccache+cmake+clang combination (#1540)
|
||||
* Fixed `-Wdefaulted-function-deleted` warning with Clang 8 (#1537)
|
||||
* Catch2's type traits and helpers are now properly namespaced inside `Catch::` (#1548)
|
||||
* Fixed std{out,err} redirection for failing test (#1514, #1525)
|
||||
* Somehow, this bug has been present for well over a year before it was reported
|
||||
|
||||
|
||||
### Contrib
|
||||
* `ParseAndAddCatchTests` now properly escapes commas in the test name
|
||||
|
||||
|
||||
|
||||
## 2.6.1
|
||||
|
||||
### Improvements
|
||||
* The JUnit reporter now also reports random seed (#1520, #1521)
|
||||
|
||||
### Fixes
|
||||
* The TAP reporter now formats comments with test name properly (#1529)
|
||||
* `CATCH_REQUIRE_THROWS`'s internals were unified with `REQUIRE_THROWS` (#1536)
|
||||
* This fixes a potential `-Wunused-value` warning when used
|
||||
* Fixed a potential segfault when using any of the `--list-*` options (#1533, #1534)
|
||||
|
||||
|
||||
## 2.6.0
|
||||
|
||||
**With this release the data generator feature is now fully supported.**
|
||||
|
@@ -48,3 +48,25 @@ dependent on a specific version of the single-include header.
|
||||
|
||||
Since 2.5.0, the release tag and the "binaries" (headers) should be PGP
|
||||
signed.
|
||||
|
||||
#### Signing a tag
|
||||
|
||||
To create a signed tag, use `git tag -s <VERSION>`, where `<VERSION>`
|
||||
is the version being released, e.g. `git tag -s v2.6.0`.
|
||||
|
||||
Use the version name as the short message and the release notes as
|
||||
the body (long) message.
|
||||
|
||||
#### Signing the headers
|
||||
|
||||
This will create ASCII-armored signatures for the headers that are
|
||||
uploaded to the GitHub release:
|
||||
|
||||
```
|
||||
$ gpg2 --armor --output catch.hpp.asc --detach-sig catch.hpp
|
||||
$ gpg2 --armor --output catch_reporter_automake.hpp.asc --detach-sig catch_reporter_automake.hpp
|
||||
$ gpg2 --armor --output catch_reporter_teamcity.hpp.asc --detach-sig catch_reporter_teamcity.hpp
|
||||
$ gpg2 --armor --output catch_reporter_tap.hpp.asc --detach-sig catch_reporter_tap.hpp
|
||||
```
|
||||
|
||||
_GPG does not support signing multiple files in single invocation._
|
||||
|
@@ -23,7 +23,7 @@ The full source for Catch2, including test projects, documentation, and other th
|
||||
|
||||
## Where to put it?
|
||||
|
||||
Catch2 is header only. All you need to do is drop the file somewhere reachable from your project - either in some central location you can set your header search path to find, or directly into your project tree itself! This is a particularly good option for other Open-Source projects that want to use Catch for their test suite. See [this blog entry for more on that](http://www.levelofindirection.com/journal/2011/5/27/unit-testing-in-c-and-objective-c-just-got-ridiculously-easi.html).
|
||||
Catch2 is header only. All you need to do is drop the file somewhere reachable from your project - either in some central location you can set your header search path to find, or directly into your project tree itself! This is a particularly good option for other Open-Source projects that want to use Catch for their test suite. See [this blog entry for more on that](https://levelofindirection.com/blog/unit-testing-in-cpp-and-objective-c-just-got-ridiculously-easier-still.html).
|
||||
|
||||
The rest of this tutorial will assume that the Catch2 single-include header (or the include folder) is available unqualified - but you may need to prefix it with a folder name if necessary.
|
||||
|
||||
@@ -103,7 +103,7 @@ Of course there are still more issues to deal with. For example we'll hit proble
|
||||
|
||||
### What did we do here?
|
||||
|
||||
Although this was a simple test it's been enough to demonstrate a few things about how Catch is used. Let's take moment to consider those before we move on.
|
||||
Although this was a simple test it's been enough to demonstrate a few things about how Catch is used. Let's take a moment to consider those before we move on.
|
||||
|
||||
1. All we did was ```#define``` one identifier and ```#include``` one header and we got everything - even an implementation of ```main()``` that will [respond to command line arguments](command-line.md#top). You can only use that ```#define``` in one implementation file, for (hopefully) obvious reasons. Once you have more than one file with unit tests in you'll just ```#include "catch.hpp"``` and go. Usually it's a good idea to have a dedicated implementation file that just has ```#define CATCH_CONFIG_MAIN``` and ```#include "catch.hpp"```. You can also provide your own implementation of main and drive Catch yourself (see [Supplying-your-own-main()](own-main.md#top)).
|
||||
2. We introduce test cases with the ```TEST_CASE``` macro. This macro takes one or two arguments - a free form test name and, optionally, one or more tags (for more see <a href="#test-cases-and-sections">Test cases and Sections</a>, ). The test name must be unique. You can run sets of tests by specifying a wildcarded test name or a tag expression. See the [command line docs](command-line.md#top) for more information on running tests.
|
||||
@@ -159,7 +159,7 @@ This works because the ```SECTION``` macro contains an if statement that calls b
|
||||
|
||||
So far so good - this is already an improvement on the setup/teardown approach because now we see our setup code inline and use the stack.
|
||||
|
||||
The power of sections really shows, however, when we need to execute a sequence of, checked, operations. Continuing the vector example, we might want to verify that attempting to reserve a capacity smaller than the current capacity of the vector changes nothing. We can do that, naturally, like so:
|
||||
The power of sections really shows, however, when we need to execute a sequence of checked operations. Continuing the vector example, we might want to verify that attempting to reserve a capacity smaller than the current capacity of the vector changes nothing. We can do that, naturally, like so:
|
||||
|
||||
```c++
|
||||
SECTION( "reserving bigger changes capacity but not size" ) {
|
||||
|
54
examples/301-Gen-MapTypeConversion.cpp
Normal file
54
examples/301-Gen-MapTypeConversion.cpp
Normal file
@@ -0,0 +1,54 @@
|
||||
// 301-Gen-MapTypeConversion.cpp
|
||||
// Shows how to use map to modify generator's return type.
|
||||
|
||||
// TODO
|
||||
|
||||
#include <catch2/catch.hpp>
|
||||
|
||||
#include <string>
|
||||
#include <sstream>
|
||||
|
||||
// Returns a line from a stream. You could have it e.g. read lines from
|
||||
// a file, but to avoid problems with paths in examples, we will use
|
||||
// a fixed stringstream.
|
||||
class LineGenerator : public Catch::Generators::IGenerator<std::string> {
|
||||
std::string m_line;
|
||||
std::stringstream m_stream;
|
||||
public:
|
||||
LineGenerator() {
|
||||
m_stream.str("1\n2\n3\n4\n");
|
||||
if (!next()) {
|
||||
throw Catch::GeneratorException("Couldn't read a single line");
|
||||
}
|
||||
}
|
||||
|
||||
std::string const& get() const override {
|
||||
return m_line;
|
||||
}
|
||||
|
||||
bool next() override {
|
||||
return !!std::getline(m_stream, m_line);
|
||||
}
|
||||
};
|
||||
|
||||
// This helper function provides a nicer UX when instantiating the generator
|
||||
// Notice that it returns an instance of GeneratorWrapper<std::string>, which
|
||||
// is a value-wrapper around std::unique_ptr<IGenerator<std::string>>.
|
||||
Catch::Generators::GeneratorWrapper<std::string> lines(std::string /* ignored for example */) {
|
||||
return Catch::Generators::GeneratorWrapper<std::string>(
|
||||
std::unique_ptr<Catch::Generators::IGenerator<std::string>>(
|
||||
new LineGenerator()
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
|
||||
TEST_CASE("filter can convert types inside the generator expression", "[example][generator]") {
|
||||
auto num = GENERATE(map<int>([](std::string const& line) { return std::stoi(line); },
|
||||
lines("fake-file")));
|
||||
|
||||
REQUIRE(num > 0);
|
||||
}
|
||||
|
||||
// Compiling and running this file will result in 4 successful assertions
|
@@ -8,41 +8,6 @@
|
||||
|
||||
#include <catch2/catch.hpp>
|
||||
|
||||
#include <random>
|
||||
|
||||
// Lets start by implementing a parametrizable double generator
|
||||
class RandomDoubleGenerator : public Catch::Generators::IGenerator<double> {
|
||||
std::minstd_rand m_rand;
|
||||
std::uniform_real_distribution<> m_dist;
|
||||
double current_number;
|
||||
public:
|
||||
|
||||
RandomDoubleGenerator(double low, double high):
|
||||
m_rand(std::random_device{}()),
|
||||
m_dist(low, high)
|
||||
{
|
||||
static_cast<void>(next());
|
||||
}
|
||||
|
||||
double const& get() const override;
|
||||
bool next() override {
|
||||
current_number = m_dist(m_rand);
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
// Avoids -Wweak-vtables
|
||||
double const& RandomDoubleGenerator::get() const {
|
||||
return current_number;
|
||||
}
|
||||
|
||||
|
||||
// Also provide a nice shortcut for creating the generator
|
||||
Catch::Generators::GeneratorWrapper<double> random(double low, double high) {
|
||||
return Catch::Generators::GeneratorWrapper<double>(std::unique_ptr<Catch::Generators::IGenerator<double>>(new RandomDoubleGenerator(low, high)));
|
||||
}
|
||||
|
||||
|
||||
TEST_CASE("Generate random doubles across different ranges",
|
||||
"[generator][example][advanced]") {
|
||||
// Workaround for old libstdc++
|
||||
@@ -55,16 +20,12 @@ TEST_CASE("Generate random doubles across different ranges",
|
||||
}));
|
||||
|
||||
// This will not compile (intentionally), because it accesses a variable
|
||||
// auto number = GENERATE(take(50, random(r.first, r.second)));
|
||||
|
||||
// We have to manually register the generators instead
|
||||
// Notice that we are using value capture in the lambda, to avoid lifetime issues
|
||||
auto number = Catch::Generators::generate( CATCH_INTERNAL_LINEINFO,
|
||||
[=]{
|
||||
using namespace Catch::Generators;
|
||||
return makeGenerators(take(50, random(std::get<0>(r), std::get<1>(r))));
|
||||
}
|
||||
);
|
||||
// auto number = GENERATE(take(50, random(std::get<0>(r), std::get<1>(r))));
|
||||
|
||||
// GENERATE_COPY copies all variables mentioned inside the expression
|
||||
// thus this will work.
|
||||
auto number = GENERATE_COPY(take(50, random(std::get<0>(r), std::get<1>(r))));
|
||||
|
||||
REQUIRE(std::abs(number) > 0);
|
||||
}
|
||||
|
||||
|
41
examples/311-Gen-CustomCapture.cpp
Normal file
41
examples/311-Gen-CustomCapture.cpp
Normal file
@@ -0,0 +1,41 @@
|
||||
// 311-Gen-CustomCapture.cpp
|
||||
// Shows how to provide custom capture list to the generator expression
|
||||
|
||||
// Note that using variables inside generators is dangerous and should
|
||||
// be done only if you know what you are doing, because the generators
|
||||
// _WILL_ outlive the variables. Also, even if you know what you are
|
||||
// doing, you should probably use GENERATE_COPY or GENERATE_REF macros
|
||||
// instead. However, if your use case requires having a
|
||||
// per-variable custom capture list, this example shows how to achieve
|
||||
// that.
|
||||
|
||||
#include <catch2/catch.hpp>
|
||||
|
||||
TEST_CASE("Generate random doubles across different ranges",
|
||||
"[generator][example][advanced]") {
|
||||
// Workaround for old libstdc++
|
||||
using record = std::tuple<double, double>;
|
||||
// Set up 3 ranges to generate numbers from
|
||||
auto r1 = GENERATE(table<double, double>({
|
||||
record{3, 4},
|
||||
record{-4, -3},
|
||||
record{10, 1000}
|
||||
}));
|
||||
|
||||
auto r2(r1);
|
||||
|
||||
// This will take r1 by reference and r2 by value.
|
||||
// Note that there are no advantages for doing so in this example,
|
||||
// it is done only for expository purposes.
|
||||
auto number = Catch::Generators::generate( CATCH_INTERNAL_LINEINFO,
|
||||
[&r1, r2]{
|
||||
using namespace Catch::Generators;
|
||||
return makeGenerators(take(50, random(std::get<0>(r1), std::get<1>(r2))));
|
||||
}
|
||||
);
|
||||
|
||||
REQUIRE(std::abs(number) > 0);
|
||||
}
|
||||
|
||||
// Compiling and running this file will result in 150 successful assertions
|
||||
|
@@ -45,7 +45,9 @@ set( SOURCES_IDIOMATIC_TESTS
|
||||
120-Bdd-ScenarioGivenWhenThen.cpp
|
||||
210-Evt-EventListeners.cpp
|
||||
300-Gen-OwnGenerator.cpp
|
||||
301-Gen-MapTypeConversion.cpp
|
||||
310-Gen-VariablesInGenerators.cpp
|
||||
311-Gen-CustomCapture.cpp
|
||||
)
|
||||
|
||||
# main-s for reporter-specific test sources:
|
||||
|
@@ -10,8 +10,8 @@
|
||||
#define TWOBLUECUBES_CATCH_HPP_INCLUDED
|
||||
|
||||
#define CATCH_VERSION_MAJOR 2
|
||||
#define CATCH_VERSION_MINOR 6
|
||||
#define CATCH_VERSION_PATCH 0
|
||||
#define CATCH_VERSION_MINOR 7
|
||||
#define CATCH_VERSION_PATCH 1
|
||||
|
||||
#ifdef __clang__
|
||||
# pragma clang system_header
|
||||
@@ -63,6 +63,8 @@
|
||||
#include "internal/catch_capture_matchers.h"
|
||||
#endif
|
||||
#include "internal/catch_generators.hpp"
|
||||
#include "internal/catch_generators_generic.hpp"
|
||||
#include "internal/catch_generators_specific.hpp"
|
||||
|
||||
// These files are included here so the single_include script doesn't put them
|
||||
// in the conditionally compiled sections
|
||||
@@ -101,7 +103,7 @@
|
||||
#define CATCH_REQUIRE( ... ) INTERNAL_CATCH_TEST( "CATCH_REQUIRE", Catch::ResultDisposition::Normal, __VA_ARGS__ )
|
||||
#define CATCH_REQUIRE_FALSE( ... ) INTERNAL_CATCH_TEST( "CATCH_REQUIRE_FALSE", Catch::ResultDisposition::Normal | Catch::ResultDisposition::FalseTest, __VA_ARGS__ )
|
||||
|
||||
#define CATCH_REQUIRE_THROWS( ... ) INTERNAL_CATCH_THROWS( "CATCH_REQUIRE_THROWS", Catch::ResultDisposition::Normal, "", __VA_ARGS__ )
|
||||
#define CATCH_REQUIRE_THROWS( ... ) INTERNAL_CATCH_THROWS( "CATCH_REQUIRE_THROWS", Catch::ResultDisposition::Normal, __VA_ARGS__ )
|
||||
#define CATCH_REQUIRE_THROWS_AS( expr, exceptionType ) INTERNAL_CATCH_THROWS_AS( "CATCH_REQUIRE_THROWS_AS", exceptionType, Catch::ResultDisposition::Normal, expr )
|
||||
#define CATCH_REQUIRE_THROWS_WITH( expr, matcher ) INTERNAL_CATCH_THROWS_STR_MATCHES( "CATCH_REQUIRE_THROWS_WITH", Catch::ResultDisposition::Normal, matcher, expr )
|
||||
#if !defined(CATCH_CONFIG_DISABLE_MATCHERS)
|
||||
@@ -115,7 +117,7 @@
|
||||
#define CATCH_CHECKED_ELSE( ... ) INTERNAL_CATCH_ELSE( "CATCH_CHECKED_ELSE", Catch::ResultDisposition::ContinueOnFailure, __VA_ARGS__ )
|
||||
#define CATCH_CHECK_NOFAIL( ... ) INTERNAL_CATCH_TEST( "CATCH_CHECK_NOFAIL", Catch::ResultDisposition::ContinueOnFailure | Catch::ResultDisposition::SuppressFail, __VA_ARGS__ )
|
||||
|
||||
#define CATCH_CHECK_THROWS( ... ) INTERNAL_CATCH_THROWS( "CATCH_CHECK_THROWS", Catch::ResultDisposition::ContinueOnFailure, "", __VA_ARGS__ )
|
||||
#define CATCH_CHECK_THROWS( ... ) INTERNAL_CATCH_THROWS( "CATCH_CHECK_THROWS", Catch::ResultDisposition::ContinueOnFailure, __VA_ARGS__ )
|
||||
#define CATCH_CHECK_THROWS_AS( expr, exceptionType ) INTERNAL_CATCH_THROWS_AS( "CATCH_CHECK_THROWS_AS", exceptionType, Catch::ResultDisposition::ContinueOnFailure, expr )
|
||||
#define CATCH_CHECK_THROWS_WITH( expr, matcher ) INTERNAL_CATCH_THROWS_STR_MATCHES( "CATCH_CHECK_THROWS_WITH", Catch::ResultDisposition::ContinueOnFailure, matcher, expr )
|
||||
#if !defined(CATCH_CONFIG_DISABLE_MATCHERS)
|
||||
@@ -213,6 +215,7 @@
|
||||
#endif // CATCH_CONFIG_DISABLE_MATCHERS
|
||||
|
||||
#define INFO( msg ) INTERNAL_CATCH_INFO( "INFO", msg )
|
||||
#define UNSCOPED_INFO( msg ) INTERNAL_CATCH_UNSCOPED_INFO( "UNSCOPED_INFO", msg )
|
||||
#define WARN( msg ) INTERNAL_CATCH_MSG( "WARN", Catch::ResultWas::Warning, Catch::ResultDisposition::ContinueOnFailure, msg )
|
||||
#define CAPTURE( ... ) INTERNAL_CATCH_CAPTURE( INTERNAL_CATCH_UNIQUE_NAME(capturer), "CAPTURE",__VA_ARGS__ )
|
||||
|
||||
|
4
include/external/clara.hpp
vendored
4
include/external/clara.hpp
vendored
@@ -370,7 +370,7 @@ inline auto Column::operator + (Column const& other) -> Columns {
|
||||
// ----------- end of #include from clara_textflow.hpp -----------
|
||||
// ........... back in clara.hpp
|
||||
|
||||
|
||||
#include <cctype>
|
||||
#include <string>
|
||||
#include <memory>
|
||||
#include <set>
|
||||
@@ -664,7 +664,7 @@ namespace detail {
|
||||
}
|
||||
inline auto convertInto( std::string const &source, bool &target ) -> ParserResult {
|
||||
std::string srcLC = source;
|
||||
std::transform( srcLC.begin(), srcLC.end(), srcLC.begin(), []( char c ) { return static_cast<char>( ::tolower(c) ); } );
|
||||
std::transform( srcLC.begin(), srcLC.end(), srcLC.begin(), []( char c ) { return static_cast<char>( std::tolower(c) ); } );
|
||||
if (srcLC == "y" || srcLC == "1" || srcLC == "true" || srcLC == "yes" || srcLC == "on")
|
||||
target = true;
|
||||
else if (srcLC == "n" || srcLC == "0" || srcLC == "false" || srcLC == "no" || srcLC == "off")
|
||||
|
@@ -48,7 +48,7 @@
|
||||
CATCH_INTERNAL_UNSUPPRESS_PARENTHESES_WARNINGS \
|
||||
} INTERNAL_CATCH_CATCH( catchAssertionHandler ) \
|
||||
INTERNAL_CATCH_REACT( catchAssertionHandler ) \
|
||||
} while( (void)0, false && static_cast<bool>( !!(__VA_ARGS__) ) ) // the expression here is never evaluated at runtime but it forces the compiler to give it a look
|
||||
} while( (void)0, (false) && static_cast<bool>( !!(__VA_ARGS__) ) ) // the expression here is never evaluated at runtime but it forces the compiler to give it a look
|
||||
// The double negation silences MSVC's C4800 warning, the static_cast forces short-circuit evaluation if the type has overloaded &&.
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
@@ -130,6 +130,10 @@
|
||||
#define INTERNAL_CATCH_INFO( macroName, log ) \
|
||||
Catch::ScopedMessage INTERNAL_CATCH_UNIQUE_NAME( scopedMessage )( Catch::MessageBuilder( macroName##_catch_sr, CATCH_INTERNAL_LINEINFO, Catch::ResultWas::Info ) << log );
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
#define INTERNAL_CATCH_UNSCOPED_INFO( macroName, log ) \
|
||||
Catch::getResultCapture().emplaceUnscopedMessage( Catch::MessageBuilder( macroName##_catch_sr, CATCH_INTERNAL_LINEINFO, Catch::ResultWas::Info ) << log )
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// Although this is matcher-based, it can be used with just a string
|
||||
#define INTERNAL_CATCH_THROWS_STR_MATCHES( macroName, resultDisposition, matcher, ... ) \
|
||||
|
@@ -82,7 +82,7 @@ namespace Catch {
|
||||
std::string getProcessName() const;
|
||||
std::string const& getReporterName() const;
|
||||
|
||||
std::vector<std::string> const& getTestsOrTags() const;
|
||||
std::vector<std::string> const& getTestsOrTags() const override;
|
||||
std::vector<std::string> const& getSectionsToRun() const override;
|
||||
|
||||
virtual TestSpec const& testSpec() const override;
|
||||
|
@@ -37,10 +37,10 @@ namespace Catch {
|
||||
// Windows can easily distinguish between SO and SigSegV,
|
||||
// but SigInt, SigTerm, etc are handled differently.
|
||||
static SignalDefs signalDefs[] = {
|
||||
{ EXCEPTION_ILLEGAL_INSTRUCTION, "SIGILL - Illegal instruction signal" },
|
||||
{ EXCEPTION_STACK_OVERFLOW, "SIGSEGV - Stack overflow" },
|
||||
{ EXCEPTION_ACCESS_VIOLATION, "SIGSEGV - Segmentation violation signal" },
|
||||
{ EXCEPTION_INT_DIVIDE_BY_ZERO, "Divide by zero error" },
|
||||
{ static_cast<DWORD>(EXCEPTION_ILLEGAL_INSTRUCTION), "SIGILL - Illegal instruction signal" },
|
||||
{ static_cast<DWORD>(EXCEPTION_STACK_OVERFLOW), "SIGSEGV - Stack overflow" },
|
||||
{ static_cast<DWORD>(EXCEPTION_ACCESS_VIOLATION), "SIGSEGV - Segmentation violation signal" },
|
||||
{ static_cast<DWORD>(EXCEPTION_INT_DIVIDE_BY_ZERO), "Divide by zero error" },
|
||||
};
|
||||
|
||||
LONG CALLBACK FatalConditionHandler::handleVectoredException(PEXCEPTION_POINTERS ExceptionInfo) {
|
||||
|
@@ -179,182 +179,12 @@ namespace Generators {
|
||||
return makeGenerators( value( T( std::forward<U>( val ) ) ), std::forward<Gs>( moreGenerators )... );
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
class TakeGenerator : public IGenerator<T> {
|
||||
GeneratorWrapper<T> m_generator;
|
||||
size_t m_returned = 0;
|
||||
size_t m_target;
|
||||
public:
|
||||
TakeGenerator(size_t target, GeneratorWrapper<T>&& generator):
|
||||
m_generator(std::move(generator)),
|
||||
m_target(target)
|
||||
{
|
||||
assert(target != 0 && "Empty generators are not allowed");
|
||||
}
|
||||
T const& get() const override {
|
||||
return m_generator.get();
|
||||
}
|
||||
bool next() override {
|
||||
++m_returned;
|
||||
if (m_returned >= m_target) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const auto success = m_generator.next();
|
||||
// If the underlying generator does not contain enough values
|
||||
// then we cut short as well
|
||||
if (!success) {
|
||||
m_returned = m_target;
|
||||
}
|
||||
return success;
|
||||
}
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
GeneratorWrapper<T> take(size_t target, GeneratorWrapper<T>&& generator) {
|
||||
return GeneratorWrapper<T>(pf::make_unique<TakeGenerator<T>>(target, std::move(generator)));
|
||||
}
|
||||
|
||||
|
||||
template <typename T, typename Predicate>
|
||||
class FilterGenerator : public IGenerator<T> {
|
||||
GeneratorWrapper<T> m_generator;
|
||||
Predicate m_predicate;
|
||||
public:
|
||||
template <typename P = Predicate>
|
||||
FilterGenerator(P&& pred, GeneratorWrapper<T>&& generator):
|
||||
m_generator(std::move(generator)),
|
||||
m_predicate(std::forward<P>(pred))
|
||||
{
|
||||
if (!m_predicate(m_generator.get())) {
|
||||
// It might happen that there are no values that pass the
|
||||
// filter. In that case we throw an exception.
|
||||
auto has_initial_value = next();
|
||||
if (!has_initial_value) {
|
||||
Catch::throw_exception(GeneratorException("No valid value found in filtered generator"));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
T const& get() const override {
|
||||
return m_generator.get();
|
||||
}
|
||||
|
||||
bool next() override {
|
||||
bool success = m_generator.next();
|
||||
if (!success) {
|
||||
return false;
|
||||
}
|
||||
while (!m_predicate(m_generator.get()) && (success = m_generator.next()) == true);
|
||||
return success;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
template <typename T, typename Predicate>
|
||||
GeneratorWrapper<T> filter(Predicate&& pred, GeneratorWrapper<T>&& generator) {
|
||||
return GeneratorWrapper<T>(std::unique_ptr<IGenerator<T>>(pf::make_unique<FilterGenerator<T, Predicate>>(std::forward<Predicate>(pred), std::move(generator))));
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
class RepeatGenerator : public IGenerator<T> {
|
||||
GeneratorWrapper<T> m_generator;
|
||||
mutable std::vector<T> m_returned;
|
||||
size_t m_target_repeats;
|
||||
size_t m_current_repeat = 0;
|
||||
size_t m_repeat_index = 0;
|
||||
public:
|
||||
RepeatGenerator(size_t repeats, GeneratorWrapper<T>&& generator):
|
||||
m_generator(std::move(generator)),
|
||||
m_target_repeats(repeats)
|
||||
{
|
||||
assert(m_target_repeats > 0 && "Repeat generator must repeat at least once");
|
||||
}
|
||||
|
||||
T const& get() const override {
|
||||
if (m_current_repeat == 0) {
|
||||
m_returned.push_back(m_generator.get());
|
||||
return m_returned.back();
|
||||
}
|
||||
return m_returned[m_repeat_index];
|
||||
}
|
||||
|
||||
bool next() override {
|
||||
// There are 2 basic cases:
|
||||
// 1) We are still reading the generator
|
||||
// 2) We are reading our own cache
|
||||
|
||||
// In the first case, we need to poke the underlying generator.
|
||||
// If it happily moves, we are left in that state, otherwise it is time to start reading from our cache
|
||||
if (m_current_repeat == 0) {
|
||||
const auto success = m_generator.next();
|
||||
if (!success) {
|
||||
++m_current_repeat;
|
||||
}
|
||||
return m_current_repeat < m_target_repeats;
|
||||
}
|
||||
|
||||
// In the second case, we need to move indices forward and check that we haven't run up against the end
|
||||
++m_repeat_index;
|
||||
if (m_repeat_index == m_returned.size()) {
|
||||
m_repeat_index = 0;
|
||||
++m_current_repeat;
|
||||
}
|
||||
return m_current_repeat < m_target_repeats;
|
||||
}
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
GeneratorWrapper<T> repeat(size_t repeats, GeneratorWrapper<T>&& generator) {
|
||||
return GeneratorWrapper<T>(pf::make_unique<RepeatGenerator<T>>(repeats, std::move(generator)));
|
||||
}
|
||||
|
||||
template <typename T, typename U, typename Func>
|
||||
class MapGenerator : public IGenerator<T> {
|
||||
// TBD: provide static assert for mapping function, for friendly error message
|
||||
GeneratorWrapper<U> m_generator;
|
||||
Func m_function;
|
||||
// To avoid returning dangling reference, we have to save the values
|
||||
T m_cache;
|
||||
public:
|
||||
template <typename F2 = Func>
|
||||
MapGenerator(F2&& function, GeneratorWrapper<U>&& generator) :
|
||||
m_generator(std::move(generator)),
|
||||
m_function(std::forward<F2>(function)),
|
||||
m_cache(m_function(m_generator.get()))
|
||||
{}
|
||||
|
||||
T const& get() const override {
|
||||
return m_cache;
|
||||
}
|
||||
bool next() override {
|
||||
const auto success = m_generator.next();
|
||||
if (success) {
|
||||
m_cache = m_function(m_generator.get());
|
||||
}
|
||||
return success;
|
||||
}
|
||||
};
|
||||
|
||||
template <typename T, typename U, typename Func>
|
||||
GeneratorWrapper<T> map(Func&& function, GeneratorWrapper<U>&& generator) {
|
||||
return GeneratorWrapper<T>(
|
||||
pf::make_unique<MapGenerator<T, U, Func>>(std::forward<Func>(function), std::move(generator))
|
||||
);
|
||||
}
|
||||
template <typename T, typename Func>
|
||||
GeneratorWrapper<T> map(Func&& function, GeneratorWrapper<T>&& generator) {
|
||||
return GeneratorWrapper<T>(
|
||||
pf::make_unique<MapGenerator<T, T, Func>>(std::forward<Func>(function), std::move(generator))
|
||||
);
|
||||
}
|
||||
|
||||
auto acquireGeneratorTracker( SourceLineInfo const& lineInfo ) -> IGeneratorTracker&;
|
||||
|
||||
template<typename L>
|
||||
// Note: The type after -> is weird, because VS2015 cannot parse
|
||||
// the expression used in the typedef inside, when it is in
|
||||
// return type. Yeah, ¯\_(ツ)_/¯
|
||||
// return type. Yeah.
|
||||
auto generate( SourceLineInfo const& lineInfo, L const& generatorExpression ) -> decltype(std::declval<decltype(generatorExpression())>().get()) {
|
||||
using UnderlyingType = typename decltype(generatorExpression())::type;
|
||||
|
||||
@@ -371,7 +201,10 @@ namespace Generators {
|
||||
} // namespace Catch
|
||||
|
||||
#define GENERATE( ... ) \
|
||||
Catch::Generators::generate( CATCH_INTERNAL_LINEINFO, []{ using namespace Catch::Generators; return makeGenerators( __VA_ARGS__ ); } )
|
||||
|
||||
Catch::Generators::generate( CATCH_INTERNAL_LINEINFO, [ ]{ using namespace Catch::Generators; return makeGenerators( __VA_ARGS__ ); } )
|
||||
#define GENERATE_COPY( ... ) \
|
||||
Catch::Generators::generate( CATCH_INTERNAL_LINEINFO, [=]{ using namespace Catch::Generators; return makeGenerators( __VA_ARGS__ ); } )
|
||||
#define GENERATE_REF( ... ) \
|
||||
Catch::Generators::generate( CATCH_INTERNAL_LINEINFO, [&]{ using namespace Catch::Generators; return makeGenerators( __VA_ARGS__ ); } )
|
||||
|
||||
#endif // TWOBLUECUBES_CATCH_GENERATORS_HPP_INCLUDED
|
||||
|
242
include/internal/catch_generators_generic.hpp
Normal file
242
include/internal/catch_generators_generic.hpp
Normal file
@@ -0,0 +1,242 @@
|
||||
/*
|
||||
* Created by Martin on 23/2/2019.
|
||||
*
|
||||
* Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
* file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
*/
|
||||
#ifndef TWOBLUECUBES_CATCH_GENERATORS_GENERIC_HPP_INCLUDED
|
||||
#define TWOBLUECUBES_CATCH_GENERATORS_GENERIC_HPP_INCLUDED
|
||||
|
||||
#include "catch_generators.hpp"
|
||||
|
||||
namespace Catch {
|
||||
namespace Generators {
|
||||
|
||||
template <typename T>
|
||||
class TakeGenerator : public IGenerator<T> {
|
||||
GeneratorWrapper<T> m_generator;
|
||||
size_t m_returned = 0;
|
||||
size_t m_target;
|
||||
public:
|
||||
TakeGenerator(size_t target, GeneratorWrapper<T>&& generator):
|
||||
m_generator(std::move(generator)),
|
||||
m_target(target)
|
||||
{
|
||||
assert(target != 0 && "Empty generators are not allowed");
|
||||
}
|
||||
T const& get() const override {
|
||||
return m_generator.get();
|
||||
}
|
||||
bool next() override {
|
||||
++m_returned;
|
||||
if (m_returned >= m_target) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const auto success = m_generator.next();
|
||||
// If the underlying generator does not contain enough values
|
||||
// then we cut short as well
|
||||
if (!success) {
|
||||
m_returned = m_target;
|
||||
}
|
||||
return success;
|
||||
}
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
GeneratorWrapper<T> take(size_t target, GeneratorWrapper<T>&& generator) {
|
||||
return GeneratorWrapper<T>(pf::make_unique<TakeGenerator<T>>(target, std::move(generator)));
|
||||
}
|
||||
|
||||
|
||||
template <typename T, typename Predicate>
|
||||
class FilterGenerator : public IGenerator<T> {
|
||||
GeneratorWrapper<T> m_generator;
|
||||
Predicate m_predicate;
|
||||
public:
|
||||
template <typename P = Predicate>
|
||||
FilterGenerator(P&& pred, GeneratorWrapper<T>&& generator):
|
||||
m_generator(std::move(generator)),
|
||||
m_predicate(std::forward<P>(pred))
|
||||
{
|
||||
if (!m_predicate(m_generator.get())) {
|
||||
// It might happen that there are no values that pass the
|
||||
// filter. In that case we throw an exception.
|
||||
auto has_initial_value = next();
|
||||
if (!has_initial_value) {
|
||||
Catch::throw_exception(GeneratorException("No valid value found in filtered generator"));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
T const& get() const override {
|
||||
return m_generator.get();
|
||||
}
|
||||
|
||||
bool next() override {
|
||||
bool success = m_generator.next();
|
||||
if (!success) {
|
||||
return false;
|
||||
}
|
||||
while (!m_predicate(m_generator.get()) && (success = m_generator.next()) == true);
|
||||
return success;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
template <typename T, typename Predicate>
|
||||
GeneratorWrapper<T> filter(Predicate&& pred, GeneratorWrapper<T>&& generator) {
|
||||
return GeneratorWrapper<T>(std::unique_ptr<IGenerator<T>>(pf::make_unique<FilterGenerator<T, Predicate>>(std::forward<Predicate>(pred), std::move(generator))));
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
class RepeatGenerator : public IGenerator<T> {
|
||||
GeneratorWrapper<T> m_generator;
|
||||
mutable std::vector<T> m_returned;
|
||||
size_t m_target_repeats;
|
||||
size_t m_current_repeat = 0;
|
||||
size_t m_repeat_index = 0;
|
||||
public:
|
||||
RepeatGenerator(size_t repeats, GeneratorWrapper<T>&& generator):
|
||||
m_generator(std::move(generator)),
|
||||
m_target_repeats(repeats)
|
||||
{
|
||||
assert(m_target_repeats > 0 && "Repeat generator must repeat at least once");
|
||||
}
|
||||
|
||||
T const& get() const override {
|
||||
if (m_current_repeat == 0) {
|
||||
m_returned.push_back(m_generator.get());
|
||||
return m_returned.back();
|
||||
}
|
||||
return m_returned[m_repeat_index];
|
||||
}
|
||||
|
||||
bool next() override {
|
||||
// There are 2 basic cases:
|
||||
// 1) We are still reading the generator
|
||||
// 2) We are reading our own cache
|
||||
|
||||
// In the first case, we need to poke the underlying generator.
|
||||
// If it happily moves, we are left in that state, otherwise it is time to start reading from our cache
|
||||
if (m_current_repeat == 0) {
|
||||
const auto success = m_generator.next();
|
||||
if (!success) {
|
||||
++m_current_repeat;
|
||||
}
|
||||
return m_current_repeat < m_target_repeats;
|
||||
}
|
||||
|
||||
// In the second case, we need to move indices forward and check that we haven't run up against the end
|
||||
++m_repeat_index;
|
||||
if (m_repeat_index == m_returned.size()) {
|
||||
m_repeat_index = 0;
|
||||
++m_current_repeat;
|
||||
}
|
||||
return m_current_repeat < m_target_repeats;
|
||||
}
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
GeneratorWrapper<T> repeat(size_t repeats, GeneratorWrapper<T>&& generator) {
|
||||
return GeneratorWrapper<T>(pf::make_unique<RepeatGenerator<T>>(repeats, std::move(generator)));
|
||||
}
|
||||
|
||||
template <typename T, typename U, typename Func>
|
||||
class MapGenerator : public IGenerator<T> {
|
||||
// TBD: provide static assert for mapping function, for friendly error message
|
||||
GeneratorWrapper<U> m_generator;
|
||||
Func m_function;
|
||||
// To avoid returning dangling reference, we have to save the values
|
||||
T m_cache;
|
||||
public:
|
||||
template <typename F2 = Func>
|
||||
MapGenerator(F2&& function, GeneratorWrapper<U>&& generator) :
|
||||
m_generator(std::move(generator)),
|
||||
m_function(std::forward<F2>(function)),
|
||||
m_cache(m_function(m_generator.get()))
|
||||
{}
|
||||
|
||||
T const& get() const override {
|
||||
return m_cache;
|
||||
}
|
||||
bool next() override {
|
||||
const auto success = m_generator.next();
|
||||
if (success) {
|
||||
m_cache = m_function(m_generator.get());
|
||||
}
|
||||
return success;
|
||||
}
|
||||
};
|
||||
|
||||
#if defined(__cpp_lib_is_invocable) && __cpp_lib_is_invocable >= 201703
|
||||
// std::result_of is deprecated in C++17 and removed in C++20. Hence, it is
|
||||
// replaced with std::invoke_result here. Also *_t format is preferred over
|
||||
// typename *::type format.
|
||||
template <typename Func, typename U>
|
||||
using MapFunctionReturnType = std::remove_reference_t<std::remove_cv_t<std::invoke_result_t<Func, U>>>;
|
||||
#else
|
||||
template <typename Func, typename U>
|
||||
using MapFunctionReturnType = typename std::remove_reference<typename std::remove_cv<typename std::result_of<Func(U)>::type>::type>::type;
|
||||
#endif
|
||||
|
||||
template <typename Func, typename U, typename T = MapFunctionReturnType<Func, U>>
|
||||
GeneratorWrapper<T> map(Func&& function, GeneratorWrapper<U>&& generator) {
|
||||
return GeneratorWrapper<T>(
|
||||
pf::make_unique<MapGenerator<T, U, Func>>(std::forward<Func>(function), std::move(generator))
|
||||
);
|
||||
}
|
||||
|
||||
template <typename T, typename U, typename Func>
|
||||
GeneratorWrapper<T> map(Func&& function, GeneratorWrapper<U>&& generator) {
|
||||
return GeneratorWrapper<T>(
|
||||
pf::make_unique<MapGenerator<T, U, Func>>(std::forward<Func>(function), std::move(generator))
|
||||
);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
class ChunkGenerator final : public IGenerator<std::vector<T>> {
|
||||
std::vector<T> m_chunk;
|
||||
size_t m_chunk_size;
|
||||
GeneratorWrapper<T> m_generator;
|
||||
bool m_used_up = false;
|
||||
public:
|
||||
ChunkGenerator(size_t size, GeneratorWrapper<T> generator) :
|
||||
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"));
|
||||
}
|
||||
m_chunk.push_back(m_generator.get());
|
||||
}
|
||||
}
|
||||
std::vector<T> const& get() const override {
|
||||
return m_chunk;
|
||||
}
|
||||
bool next() override {
|
||||
m_chunk.clear();
|
||||
for (size_t idx = 0; idx < m_chunk_size; ++idx) {
|
||||
if (!m_generator.next()) {
|
||||
return false;
|
||||
}
|
||||
m_chunk.push_back(m_generator.get());
|
||||
}
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
GeneratorWrapper<std::vector<T>> chunk(size_t size, GeneratorWrapper<T>&& generator) {
|
||||
return GeneratorWrapper<std::vector<T>>(
|
||||
pf::make_unique<ChunkGenerator<T>>(size, std::move(generator))
|
||||
);
|
||||
}
|
||||
|
||||
} // namespace Generators
|
||||
} // namespace Catch
|
||||
|
||||
|
||||
#endif // TWOBLUECUBES_CATCH_GENERATORS_GENERIC_HPP_INCLUDED
|
135
include/internal/catch_generators_specific.hpp
Normal file
135
include/internal/catch_generators_specific.hpp
Normal file
@@ -0,0 +1,135 @@
|
||||
/*
|
||||
* Created by Martin on 15/6/2018.
|
||||
*
|
||||
* Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
* file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
*/
|
||||
#ifndef TWOBLUECUBES_CATCH_GENERATORS_SPECIFIC_HPP_INCLUDED
|
||||
#define TWOBLUECUBES_CATCH_GENERATORS_SPECIFIC_HPP_INCLUDED
|
||||
|
||||
#include "catch_context.h"
|
||||
#include "catch_generators.hpp"
|
||||
#include "catch_interfaces_config.h"
|
||||
|
||||
#include <random>
|
||||
|
||||
namespace Catch {
|
||||
namespace Generators {
|
||||
|
||||
template <typename Float>
|
||||
class RandomFloatingGenerator final : public IGenerator<Float> {
|
||||
// FIXME: What is the right seed?
|
||||
std::minstd_rand m_rand;
|
||||
std::uniform_real_distribution<Float> m_dist;
|
||||
Float m_current_number;
|
||||
public:
|
||||
|
||||
RandomFloatingGenerator(Float a, Float b):
|
||||
m_rand(getCurrentContext().getConfig()->rngSeed()),
|
||||
m_dist(a, b) {
|
||||
static_cast<void>(next());
|
||||
}
|
||||
|
||||
Float const& get() const override {
|
||||
return m_current_number;
|
||||
}
|
||||
bool next() override {
|
||||
m_current_number = m_dist(m_rand);
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
template <typename Integer>
|
||||
class RandomIntegerGenerator final : public IGenerator<Integer> {
|
||||
std::minstd_rand m_rand;
|
||||
std::uniform_int_distribution<Integer> m_dist;
|
||||
Integer m_current_number;
|
||||
public:
|
||||
|
||||
RandomIntegerGenerator(Integer a, Integer b):
|
||||
m_rand(getCurrentContext().getConfig()->rngSeed()),
|
||||
m_dist(a, b) {
|
||||
static_cast<void>(next());
|
||||
}
|
||||
|
||||
Integer const& get() const override {
|
||||
return m_current_number;
|
||||
}
|
||||
bool next() override {
|
||||
m_current_number = m_dist(m_rand);
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
// TODO: Ideally this would be also constrained against the various char types,
|
||||
// but I don't expect users to run into that in practice.
|
||||
template <typename T>
|
||||
typename std::enable_if<std::is_integral<T>::value && !std::is_same<T, bool>::value,
|
||||
GeneratorWrapper<T>>::type
|
||||
random(T a, T b) {
|
||||
return GeneratorWrapper<T>(
|
||||
pf::make_unique<RandomIntegerGenerator<T>>(a, b)
|
||||
);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
typename std::enable_if<std::is_floating_point<T>::value,
|
||||
GeneratorWrapper<T>>::type
|
||||
random(T a, T b) {
|
||||
return GeneratorWrapper<T>(
|
||||
pf::make_unique<RandomFloatingGenerator<T>>(a, b)
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
template <typename T>
|
||||
class RangeGenerator final : public IGenerator<T> {
|
||||
T m_current;
|
||||
T m_end;
|
||||
T m_step;
|
||||
bool m_positive;
|
||||
|
||||
public:
|
||||
RangeGenerator(T const& start, T const& end, T const& step):
|
||||
m_current(start),
|
||||
m_end(end),
|
||||
m_step(step),
|
||||
m_positive(m_step > T(0))
|
||||
{
|
||||
assert(m_current != m_end && "Range start and end cannot be equal");
|
||||
assert(m_step != T(0) && "Step size cannot be zero");
|
||||
assert(((m_positive && m_current <= m_end) || (!m_positive && m_current >= m_end)) && "Step moves away from end");
|
||||
}
|
||||
|
||||
RangeGenerator(T const& start, T const& end):
|
||||
RangeGenerator(start, end, (start < end) ? T(1) : T(-1))
|
||||
{}
|
||||
|
||||
T const& get() const override {
|
||||
return m_current;
|
||||
}
|
||||
|
||||
bool next() override {
|
||||
m_current += m_step;
|
||||
return (m_positive) ? (m_current < m_end) : (m_current > m_end);
|
||||
}
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
GeneratorWrapper<T> range(T const& start, T const& end, T const& step) {
|
||||
static_assert(std::is_integral<T>::value && !std::is_same<T, bool>::value, "Type must be an integer");
|
||||
return GeneratorWrapper<T>(pf::make_unique<RangeGenerator<T>>(start, end, step));
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
GeneratorWrapper<T> range(T const& start, T const& end) {
|
||||
static_assert(std::is_integral<T>::value && !std::is_same<T, bool>::value, "Type must be an integer");
|
||||
return GeneratorWrapper<T>(pf::make_unique<RangeGenerator<T>>(start, end));
|
||||
}
|
||||
|
||||
|
||||
} // namespace Generators
|
||||
} // namespace Catch
|
||||
|
||||
|
||||
#endif // TWOBLUECUBES_CATCH_GENERATORS_SPECIFIC_HPP_INCLUDED
|
@@ -20,6 +20,7 @@ namespace Catch {
|
||||
struct SectionInfo;
|
||||
struct SectionEndInfo;
|
||||
struct MessageInfo;
|
||||
struct MessageBuilder;
|
||||
struct Counts;
|
||||
struct BenchmarkInfo;
|
||||
struct BenchmarkStats;
|
||||
@@ -46,6 +47,8 @@ namespace Catch {
|
||||
virtual void pushScopedMessage( MessageInfo const& message ) = 0;
|
||||
virtual void popScopedMessage( MessageInfo const& message ) = 0;
|
||||
|
||||
virtual void emplaceUnscopedMessage( MessageBuilder const& builder ) = 0;
|
||||
|
||||
virtual void handleFatalErrorCondition( StringRef message ) = 0;
|
||||
|
||||
virtual void handleExpr
|
||||
|
@@ -69,6 +69,7 @@ namespace Catch {
|
||||
virtual ShowDurations::OrNot showDurations() const = 0;
|
||||
virtual TestSpec const& testSpec() const = 0;
|
||||
virtual bool hasTestFilters() const = 0;
|
||||
virtual std::vector<std::string> const& getTestsOrTags() const = 0;
|
||||
virtual RunTests::InWhatOrder runOrder() const = 0;
|
||||
virtual unsigned int rngSeed() const = 0;
|
||||
virtual int benchmarkResolutionMultiple() const = 0;
|
||||
|
@@ -80,8 +80,8 @@ namespace Catch {
|
||||
|
||||
AssertionStats( AssertionStats const& ) = default;
|
||||
AssertionStats( AssertionStats && ) = default;
|
||||
AssertionStats& operator = ( AssertionStats const& ) = default;
|
||||
AssertionStats& operator = ( AssertionStats && ) = default;
|
||||
AssertionStats& operator = ( AssertionStats const& ) = delete;
|
||||
AssertionStats& operator = ( AssertionStats && ) = delete;
|
||||
virtual ~AssertionStats();
|
||||
|
||||
AssertionResult assertionResult;
|
||||
|
@@ -12,6 +12,7 @@
|
||||
#include "catch_interfaces_reporter.h"
|
||||
#include "catch_interfaces_testcase.h"
|
||||
|
||||
#include "catch_context.h"
|
||||
#include "catch_stream.h"
|
||||
#include "catch_text.h"
|
||||
|
||||
@@ -146,15 +147,16 @@ namespace Catch {
|
||||
return factories.size();
|
||||
}
|
||||
|
||||
Option<std::size_t> list( Config const& config ) {
|
||||
Option<std::size_t> list( std::shared_ptr<Config> const& config ) {
|
||||
Option<std::size_t> listedCount;
|
||||
if( config.listTests() )
|
||||
listedCount = listedCount.valueOr(0) + listTests( config );
|
||||
if( config.listTestNamesOnly() )
|
||||
listedCount = listedCount.valueOr(0) + listTestsNamesOnly( config );
|
||||
if( config.listTags() )
|
||||
listedCount = listedCount.valueOr(0) + listTags( config );
|
||||
if( config.listReporters() )
|
||||
getCurrentMutableContext().setConfig( config );
|
||||
if( config->listTests() )
|
||||
listedCount = listedCount.valueOr(0) + listTests( *config );
|
||||
if( config->listTestNamesOnly() )
|
||||
listedCount = listedCount.valueOr(0) + listTestsNamesOnly( *config );
|
||||
if( config->listTags() )
|
||||
listedCount = listedCount.valueOr(0) + listTags( *config );
|
||||
if( config->listReporters() )
|
||||
listedCount = listedCount.valueOr(0) + listReporters();
|
||||
return listedCount;
|
||||
}
|
||||
|
@@ -31,7 +31,7 @@ namespace Catch {
|
||||
|
||||
std::size_t listReporters();
|
||||
|
||||
Option<std::size_t> list( Config const& config );
|
||||
Option<std::size_t> list( std::shared_ptr<Config> const& config );
|
||||
|
||||
} // end namespace Catch
|
||||
|
||||
|
@@ -47,14 +47,20 @@ namespace Catch {
|
||||
|
||||
|
||||
ScopedMessage::ScopedMessage( MessageBuilder const& builder )
|
||||
: m_info( builder.m_info )
|
||||
: m_info( builder.m_info ), m_moved()
|
||||
{
|
||||
m_info.message = builder.m_stream.str();
|
||||
getResultCapture().pushScopedMessage( m_info );
|
||||
}
|
||||
|
||||
ScopedMessage::ScopedMessage( ScopedMessage&& old )
|
||||
: m_info( old.m_info ), m_moved()
|
||||
{
|
||||
old.m_moved = true;
|
||||
}
|
||||
|
||||
ScopedMessage::~ScopedMessage() {
|
||||
if ( !uncaught_exceptions() ){
|
||||
if ( !uncaught_exceptions() && !m_moved ){
|
||||
getResultCapture().popScopedMessage(m_info);
|
||||
}
|
||||
}
|
||||
|
@@ -64,9 +64,12 @@ namespace Catch {
|
||||
class ScopedMessage {
|
||||
public:
|
||||
explicit ScopedMessage( MessageBuilder const& builder );
|
||||
ScopedMessage( ScopedMessage& duplicate ) = delete;
|
||||
ScopedMessage( ScopedMessage&& old );
|
||||
~ScopedMessage();
|
||||
|
||||
MessageInfo m_info;
|
||||
bool m_moved;
|
||||
};
|
||||
|
||||
class Capturer {
|
||||
|
@@ -11,65 +11,59 @@
|
||||
|
||||
#include <type_traits>
|
||||
|
||||
namespace Catch {
|
||||
template< typename... >
|
||||
struct TypeList{};
|
||||
struct TypeList {};
|
||||
|
||||
template< typename... >
|
||||
struct append;
|
||||
|
||||
template< template<typename...> class L1
|
||||
, typename...E1
|
||||
, template<typename...> class L2
|
||||
, typename...E2
|
||||
>
|
||||
struct append< L1<E1...>, L2<E2...> >
|
||||
{
|
||||
using type = L1<E1..., E2...>;
|
||||
, typename...E1
|
||||
, template<typename...> class L2
|
||||
, typename...E2
|
||||
>
|
||||
struct append< L1<E1...>, L2<E2...> > {
|
||||
using type = L1<E1..., E2...>;
|
||||
};
|
||||
|
||||
template< template<typename...> class L1
|
||||
, typename...E1
|
||||
, template<typename...> class L2
|
||||
, typename...E2
|
||||
, typename...Rest
|
||||
>
|
||||
struct append< L1<E1...>, L2<E2...>, Rest...>
|
||||
{
|
||||
using type = typename append< L1<E1..., E2...>, Rest... >::type;
|
||||
, typename...E1
|
||||
, template<typename...> class L2
|
||||
, typename...E2
|
||||
, typename...Rest
|
||||
>
|
||||
struct append< L1<E1...>, L2<E2...>, Rest...> {
|
||||
using type = typename append< L1<E1..., E2...>, Rest... >::type;
|
||||
};
|
||||
|
||||
template< template<typename...> class
|
||||
, typename...
|
||||
>
|
||||
, typename...
|
||||
>
|
||||
struct rewrap;
|
||||
|
||||
template< template<typename...> class Container
|
||||
, template<typename...> class List
|
||||
, typename...elems
|
||||
>
|
||||
struct rewrap<Container, List<elems...>>
|
||||
{
|
||||
, template<typename...> class List
|
||||
, typename...elems
|
||||
>
|
||||
struct rewrap<Container, List<elems...>> {
|
||||
using type = TypeList< Container< elems... > >;
|
||||
};
|
||||
|
||||
template< template<typename...> class Container
|
||||
, template<typename...> class List
|
||||
, class...Elems
|
||||
, typename...Elements>
|
||||
struct rewrap<Container, List<Elems...>, Elements...>
|
||||
{
|
||||
, template<typename...> class List
|
||||
, class...Elems
|
||||
, typename...Elements>
|
||||
struct rewrap<Container, List<Elems...>, Elements...> {
|
||||
using type = typename append<TypeList<Container<Elems...>>, typename rewrap<Container, Elements...>::type>::type;
|
||||
};
|
||||
|
||||
template< template<typename...> class...Containers >
|
||||
struct combine
|
||||
{
|
||||
struct combine {
|
||||
template< typename...Types >
|
||||
struct with_types
|
||||
{
|
||||
struct with_types {
|
||||
template< template <typename...> class Final >
|
||||
struct into
|
||||
{
|
||||
struct into {
|
||||
using type = typename append<Final<>, typename rewrap<Containers, Types...>::type...>::type;
|
||||
};
|
||||
};
|
||||
@@ -78,4 +72,6 @@ struct combine
|
||||
template<typename T>
|
||||
struct always_false : std::false_type {};
|
||||
|
||||
} // namespace Catch
|
||||
|
||||
#endif // TWOBLUECUBES_CATCH_META_HPP_INCLUDED
|
||||
|
@@ -116,7 +116,7 @@ namespace Catch {
|
||||
arcSafeRelease( m_substr );
|
||||
}
|
||||
|
||||
bool match( NSString* arg ) const override {
|
||||
bool match( NSString* const& str ) const override {
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -126,7 +126,7 @@ namespace Catch {
|
||||
struct Equals : StringHolder {
|
||||
Equals( NSString* substr ) : StringHolder( substr ){}
|
||||
|
||||
bool match( NSString* str ) const override {
|
||||
bool match( NSString* const& 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* str ) const {
|
||||
bool match( NSString* const& 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* str ) const override {
|
||||
bool match( NSString* const& 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* str ) const override {
|
||||
bool match( NSString* const& str ) const override {
|
||||
return (str != nil || m_substr == nil ) &&
|
||||
[str rangeOfString:m_substr].location == [str length] - [m_substr length];
|
||||
}
|
||||
|
@@ -49,6 +49,15 @@ namespace Catch {
|
||||
{}
|
||||
auto RedirectedStdErr::str() const -> std::string { return m_rss.str(); }
|
||||
|
||||
RedirectedStreams::RedirectedStreams(std::string& redirectedCout, std::string& redirectedCerr)
|
||||
: m_redirectedCout(redirectedCout),
|
||||
m_redirectedCerr(redirectedCerr)
|
||||
{}
|
||||
|
||||
RedirectedStreams::~RedirectedStreams() {
|
||||
m_redirectedCout += m_redirectedStdOut.str();
|
||||
m_redirectedCerr += m_redirectedStdErr.str();
|
||||
}
|
||||
|
||||
#if defined(CATCH_CONFIG_NEW_CAPTURE)
|
||||
|
||||
|
@@ -46,6 +46,21 @@ namespace Catch {
|
||||
auto str() const -> std::string;
|
||||
};
|
||||
|
||||
class RedirectedStreams {
|
||||
public:
|
||||
RedirectedStreams(RedirectedStreams const&) = delete;
|
||||
RedirectedStreams& operator=(RedirectedStreams const&) = delete;
|
||||
RedirectedStreams(RedirectedStreams&&) = delete;
|
||||
RedirectedStreams& operator=(RedirectedStreams&&) = delete;
|
||||
|
||||
RedirectedStreams(std::string& redirectedCout, std::string& redirectedCerr);
|
||||
~RedirectedStreams();
|
||||
private:
|
||||
std::string& m_redirectedCout;
|
||||
std::string& m_redirectedCerr;
|
||||
RedirectedStdOut m_redirectedStdOut;
|
||||
RedirectedStdErr m_redirectedStdErr;
|
||||
};
|
||||
|
||||
#if defined(CATCH_CONFIG_NEW_CAPTURE)
|
||||
|
||||
|
@@ -57,6 +57,16 @@
|
||||
#define INTERNAL_CATCH_EXPAND2(...) INTERNAL_CATCH_NO## __VA_ARGS__
|
||||
#define INTERNAL_CATCH_DEF(...) INTERNAL_CATCH_DEF __VA_ARGS__
|
||||
#define INTERNAL_CATCH_NOINTERNAL_CATCH_DEF
|
||||
#define INTERNAL_CATCH_STRINGIZE(...) INTERNAL_CATCH_STRINGIZE2(__VA_ARGS__)
|
||||
#ifndef CATCH_CONFIG_TRADITIONAL_MSVC_PREPROCESSOR
|
||||
#define INTERNAL_CATCH_STRINGIZE2(...) #__VA_ARGS__
|
||||
#define INTERNAL_CATCH_STRINGIZE_WITHOUT_PARENS(param) INTERNAL_CATCH_STRINGIZE(INTERNAL_CATCH_REMOVE_PARENS(param))
|
||||
#else
|
||||
// MSVC is adding extra space and needs another indirection to expand INTERNAL_CATCH_NOINTERNAL_CATCH_DEF
|
||||
#define INTERNAL_CATCH_STRINGIZE2(...) INTERNAL_CATCH_STRINGIZE3(__VA_ARGS__)
|
||||
#define INTERNAL_CATCH_STRINGIZE3(...) #__VA_ARGS__
|
||||
#define INTERNAL_CATCH_STRINGIZE_WITHOUT_PARENS(param) (INTERNAL_CATCH_STRINGIZE(INTERNAL_CATCH_REMOVE_PARENS(param)) + 1)
|
||||
#endif
|
||||
|
||||
#define INTERNAL_CATCH_REMOVE_PARENS(...) INTERNAL_CATCH_EXPAND1(INTERNAL_CATCH_DEF __VA_ARGS__)
|
||||
|
||||
@@ -71,7 +81,7 @@
|
||||
#define INTERNAL_CATCH_TEMPLATE_UNIQUE_NAME(Name, ...) INTERNAL_CATCH_TEMPLATE_UNIQUE_NAME1(Name, INTERNAL_CATCH_EXPAND_VARGS(INTERNAL_CATCH_REMOVE_PARENS(__VA_ARGS__)))
|
||||
#endif
|
||||
|
||||
#define INTERNAL_CATCH_MAKE_TYPE_LIST(types) TypeList<INTERNAL_CATCH_REMOVE_PARENS(types)>
|
||||
#define INTERNAL_CATCH_MAKE_TYPE_LIST(types) Catch::TypeList<INTERNAL_CATCH_REMOVE_PARENS(types)>
|
||||
|
||||
#define INTERNAL_CATCH_MAKE_TYPE_LISTS_FROM_TYPES(types)\
|
||||
CATCH_REC_LIST(INTERNAL_CATCH_MAKE_TYPE_LIST,INTERNAL_CATCH_REMOVE_PARENS(types))
|
||||
|
@@ -67,7 +67,6 @@ namespace Catch {
|
||||
GeneratorTracker::~GeneratorTracker() {}
|
||||
}
|
||||
|
||||
|
||||
RunContext::RunContext(IConfigPtr const& _config, IStreamingReporterPtr&& reporter)
|
||||
: m_runInfo(_config->name()),
|
||||
m_context(getCurrentMutableContext()),
|
||||
@@ -162,6 +161,9 @@ namespace Catch {
|
||||
// and should be let to clear themselves out.
|
||||
static_cast<void>(m_reporter->assertionEnded(AssertionStats(result, m_messages, m_totals)));
|
||||
|
||||
if (result.getResultType() != ResultWas::Warning)
|
||||
m_messageScopes.clear();
|
||||
|
||||
// Reset working state
|
||||
resetAssertionInfo();
|
||||
m_lastResult = result;
|
||||
@@ -216,6 +218,7 @@ namespace Catch {
|
||||
|
||||
m_reporter->sectionEnded(SectionStats(endInfo.sectionInfo, assertions, endInfo.durationInSeconds, missingAssertions));
|
||||
m_messages.clear();
|
||||
m_messageScopes.clear();
|
||||
}
|
||||
|
||||
void RunContext::sectionEndedEarly(SectionEndInfo const & endInfo) {
|
||||
@@ -242,6 +245,10 @@ namespace Catch {
|
||||
m_messages.erase(std::remove(m_messages.begin(), m_messages.end(), message), m_messages.end());
|
||||
}
|
||||
|
||||
void RunContext::emplaceUnscopedMessage( MessageBuilder const& builder ) {
|
||||
m_messageScopes.emplace_back( builder );
|
||||
}
|
||||
|
||||
std::string RunContext::getCurrentTestName() const {
|
||||
return m_activeTestCase
|
||||
? m_activeTestCase->getTestCaseInfo().name
|
||||
@@ -302,6 +309,7 @@ namespace Catch {
|
||||
m_lastAssertionPassed = true;
|
||||
++m_totals.assertions.passed;
|
||||
resetAssertionInfo();
|
||||
m_messageScopes.clear();
|
||||
}
|
||||
|
||||
bool RunContext::aborting() const {
|
||||
@@ -323,13 +331,10 @@ namespace Catch {
|
||||
CATCH_TRY {
|
||||
if (m_reporter->getPreferences().shouldRedirectStdOut) {
|
||||
#if !defined(CATCH_CONFIG_EXPERIMENTAL_REDIRECT)
|
||||
RedirectedStdOut redirectedStdOut;
|
||||
RedirectedStdErr redirectedStdErr;
|
||||
RedirectedStreams redirectedStreams(redirectedCout, redirectedCerr);
|
||||
|
||||
timer.start();
|
||||
invokeActiveTestCase();
|
||||
redirectedCout += redirectedStdOut.str();
|
||||
redirectedCerr += redirectedStdErr.str();
|
||||
#else
|
||||
OutputRedirect r(redirectedCout, redirectedCerr);
|
||||
timer.start();
|
||||
@@ -356,6 +361,7 @@ namespace Catch {
|
||||
m_testCaseTracker->close();
|
||||
handleUnfinishedSections();
|
||||
m_messages.clear();
|
||||
m_messageScopes.clear();
|
||||
|
||||
SectionStats testCaseSectionStats(testCaseSection, assertions, duration, missingAssertions);
|
||||
m_reporter->sectionEnded(testCaseSectionStats);
|
||||
|
@@ -88,6 +88,8 @@ namespace Catch {
|
||||
void pushScopedMessage( MessageInfo const& message ) override;
|
||||
void popScopedMessage( MessageInfo const& message ) override;
|
||||
|
||||
void emplaceUnscopedMessage( MessageBuilder const& builder ) override;
|
||||
|
||||
std::string getCurrentTestName() const override;
|
||||
|
||||
const AssertionResult* getLastResult() const override;
|
||||
@@ -135,6 +137,7 @@ namespace Catch {
|
||||
Totals m_totals;
|
||||
IStreamingReporterPtr m_reporter;
|
||||
std::vector<MessageInfo> m_messages;
|
||||
std::vector<ScopedMessage> m_messageScopes; /* Keeps owners of so-called unscoped messages. */
|
||||
AssertionInfo m_lastAssertionInfo;
|
||||
std::vector<SectionEndInfo> m_unfinishedSections;
|
||||
std::vector<ITracker*> m_activeSections;
|
||||
|
@@ -10,6 +10,7 @@
|
||||
#include "catch_console_colour.h"
|
||||
#include "catch_enforce.h"
|
||||
#include "catch_list.h"
|
||||
#include "catch_context.h"
|
||||
#include "catch_run_context.h"
|
||||
#include "catch_stream.h"
|
||||
#include "catch_test_spec.h"
|
||||
@@ -171,6 +172,8 @@ namespace Catch {
|
||||
|
||||
auto result = m_cli.parse( clara::Args( argc, argv ) );
|
||||
if( !result ) {
|
||||
config();
|
||||
getCurrentMutableContext().setConfig(m_config);
|
||||
Catch::cerr()
|
||||
<< Colour( Colour::Red )
|
||||
<< "\nError(s) in input:\n"
|
||||
@@ -262,7 +265,7 @@ namespace Catch {
|
||||
applyFilenamesAsTags( *m_config );
|
||||
|
||||
// Handle list request
|
||||
if( Option<std::size_t> listed = list( config() ) )
|
||||
if( Option<std::size_t> listed = list( m_config ) )
|
||||
return static_cast<int>( *listed );
|
||||
|
||||
auto totals = runTests( m_config );
|
||||
|
@@ -75,6 +75,12 @@ namespace Catch {
|
||||
else if( prop == TestCaseInfo::None )
|
||||
enforceNotReservedTag( tag, _lineInfo );
|
||||
|
||||
// Merged hide tags like `[.approvals]` should be added as
|
||||
// `[.][approvals]`. The `[.]` is added at later point, so
|
||||
// we only strip the prefix
|
||||
if (startsWith(tag, '.') && tag.size() > 1) {
|
||||
tag.erase(0, 1);
|
||||
}
|
||||
tags.push_back( tag );
|
||||
tag.clear();
|
||||
inTag = false;
|
||||
|
@@ -161,11 +161,14 @@ struct AutoReg : NonCopyable {
|
||||
CATCH_INTERNAL_CHECK_UNIQUE_TYPES(Types...) \
|
||||
int index = 0; \
|
||||
using expander = int[]; \
|
||||
(void)expander{(Catch::AutoReg( Catch::makeTestInvoker( &TestFuncName<Types> ), CATCH_INTERNAL_LINEINFO, Catch::StringRef(), Catch::NameAndTags{ Name " - " + Catch::StringMaker<int>::convert(index++), Tags } ), 0)... };/* NOLINT */ \
|
||||
constexpr char const* tmpl_types[] = {CATCH_REC_LIST(INTERNAL_CATCH_STRINGIZE_WITHOUT_PARENS, INTERNAL_CATCH_REMOVE_PARENS(TmplTypes))};\
|
||||
constexpr char const* types_list[] = {CATCH_REC_LIST(INTERNAL_CATCH_STRINGIZE_WITHOUT_PARENS, INTERNAL_CATCH_REMOVE_PARENS(TypesList))};\
|
||||
constexpr auto num_types = sizeof(types_list) / sizeof(types_list[0]);\
|
||||
(void)expander{(Catch::AutoReg( Catch::makeTestInvoker( &TestFuncName<Types> ), CATCH_INTERNAL_LINEINFO, Catch::StringRef(), Catch::NameAndTags{ Name " - " + std::string(tmpl_types[index / num_types]) + "<" + std::string(types_list[index % num_types]) + ">", Tags } ), index++, 0)... };/* NOLINT */\
|
||||
} \
|
||||
}; \
|
||||
static int INTERNAL_CATCH_UNIQUE_NAME( globalRegistrar ) = [](){ \
|
||||
using TestInit = combine<INTERNAL_CATCH_REMOVE_PARENS(TmplTypes)> \
|
||||
using TestInit = Catch::combine<INTERNAL_CATCH_REMOVE_PARENS(TmplTypes)> \
|
||||
::with_types<INTERNAL_CATCH_MAKE_TYPE_LISTS_FROM_TYPES(TypesList)>::into<TestName>::type; \
|
||||
TestInit(); \
|
||||
return 0; \
|
||||
@@ -226,11 +229,14 @@ struct AutoReg : NonCopyable {
|
||||
CATCH_INTERNAL_CHECK_UNIQUE_TYPES(Types...)\
|
||||
int index = 0;\
|
||||
using expander = int[];\
|
||||
(void)expander{(Catch::AutoReg( Catch::makeTestInvoker( &TestName<Types>::test ), CATCH_INTERNAL_LINEINFO, #ClassName, Catch::NameAndTags{ Name " - " + Catch::StringMaker<int>::convert(index++), Tags } ), 0)... };/* NOLINT */ \
|
||||
constexpr char const* tmpl_types[] = {CATCH_REC_LIST(INTERNAL_CATCH_STRINGIZE_WITHOUT_PARENS, INTERNAL_CATCH_REMOVE_PARENS(TmplTypes))};\
|
||||
constexpr char const* types_list[] = {CATCH_REC_LIST(INTERNAL_CATCH_STRINGIZE_WITHOUT_PARENS, INTERNAL_CATCH_REMOVE_PARENS(TypesList))};\
|
||||
constexpr auto num_types = sizeof(types_list) / sizeof(types_list[0]);\
|
||||
(void)expander{(Catch::AutoReg( Catch::makeTestInvoker( &TestName<Types>::test ), CATCH_INTERNAL_LINEINFO, #ClassName, Catch::NameAndTags{ Name " - " + std::string(tmpl_types[index / num_types]) + "<" + std::string(types_list[index % num_types]) + ">", Tags } ), index++, 0)... };/* NOLINT */ \
|
||||
}\
|
||||
};\
|
||||
static int INTERNAL_CATCH_UNIQUE_NAME( globalRegistrar ) = [](){\
|
||||
using TestInit = combine<INTERNAL_CATCH_REMOVE_PARENS(TmplTypes)>\
|
||||
using TestInit = Catch::combine<INTERNAL_CATCH_REMOVE_PARENS(TmplTypes)>\
|
||||
::with_types<INTERNAL_CATCH_MAKE_TYPE_LISTS_FROM_TYPES(TypesList)>::into<TestNameClass>::type;\
|
||||
TestInit();\
|
||||
return 0;\
|
||||
|
@@ -37,7 +37,7 @@ namespace Catch {
|
||||
}
|
||||
|
||||
Version const& libraryVersion() {
|
||||
static Version version( 2, 6, 0, "", 0 );
|
||||
static Version version( 2, 7, 1, "", 0 );
|
||||
return version;
|
||||
}
|
||||
|
||||
|
@@ -36,11 +36,25 @@ namespace Catch {
|
||||
#ifdef _MSC_VER
|
||||
sprintf_s(buffer, "%.3f", duration);
|
||||
#else
|
||||
sprintf(buffer, "%.3f", duration);
|
||||
std::sprintf(buffer, "%.3f", duration);
|
||||
#endif
|
||||
return std::string(buffer);
|
||||
}
|
||||
|
||||
std::string serializeFilters( std::vector<std::string> const& container ) {
|
||||
ReusableStringStream oss;
|
||||
bool first = true;
|
||||
for (auto&& filter : container)
|
||||
{
|
||||
if (!first)
|
||||
oss << ' ';
|
||||
else
|
||||
first = false;
|
||||
|
||||
oss << filter;
|
||||
}
|
||||
return oss.str();
|
||||
}
|
||||
|
||||
TestEventListenerBase::TestEventListenerBase(ReporterConfig const & _config)
|
||||
:StreamingReporterBase(_config) {}
|
||||
|
@@ -25,6 +25,8 @@ namespace Catch {
|
||||
// Returns double formatted as %.3f (format expected on output)
|
||||
std::string getFormattedDuration( double duration );
|
||||
|
||||
std::string serializeFilters( std::vector<std::string> const& container );
|
||||
|
||||
template<typename DerivedT>
|
||||
struct StreamingReporterBase : IStreamingReporter {
|
||||
|
||||
@@ -52,6 +54,7 @@ namespace Catch {
|
||||
void testRunStarting(TestRunInfo const& _testRunInfo) override {
|
||||
currentTestRunInfo = _testRunInfo;
|
||||
}
|
||||
|
||||
void testGroupStarting(GroupInfo const& _groupInfo) override {
|
||||
currentGroupInfo = _groupInfo;
|
||||
}
|
||||
|
@@ -245,7 +245,7 @@ public:
|
||||
case Unit::Nanoseconds:
|
||||
return "ns";
|
||||
case Unit::Microseconds:
|
||||
return "µs";
|
||||
return "us";
|
||||
case Unit::Milliseconds:
|
||||
return "ms";
|
||||
case Unit::Seconds:
|
||||
@@ -441,6 +441,10 @@ void ConsoleReporter::testRunEnded(TestRunStats const& _testRunStats) {
|
||||
stream << std::endl;
|
||||
StreamingReporterBase::testRunEnded(_testRunStats);
|
||||
}
|
||||
void ConsoleReporter::testRunStarting(TestRunInfo const& _testInfo) {
|
||||
StreamingReporterBase::testRunStarting(_testInfo);
|
||||
printTestFilters();
|
||||
}
|
||||
|
||||
void ConsoleReporter::lazyPrint() {
|
||||
|
||||
@@ -622,6 +626,11 @@ void ConsoleReporter::printSummaryDivider() {
|
||||
stream << getLineOfChars<'-'>() << '\n';
|
||||
}
|
||||
|
||||
void ConsoleReporter::printTestFilters() {
|
||||
if (m_config->testSpec().hasFilters())
|
||||
stream << Colour(Colour::BrightYellow) << "Filters: " << serializeFilters( m_config->getTestsOrTags() ) << '\n';
|
||||
}
|
||||
|
||||
CATCH_REGISTER_REPORTER("console", ConsoleReporter)
|
||||
|
||||
} // end namespace Catch
|
||||
|
@@ -46,7 +46,7 @@ namespace Catch {
|
||||
void testCaseEnded(TestCaseStats const& _testCaseStats) override;
|
||||
void testGroupEnded(TestGroupStats const& _testGroupStats) override;
|
||||
void testRunEnded(TestRunStats const& _testRunStats) override;
|
||||
|
||||
void testRunStarting(TestRunInfo const& _testRunInfo) override;
|
||||
private:
|
||||
|
||||
void lazyPrint();
|
||||
@@ -69,6 +69,7 @@ namespace Catch {
|
||||
|
||||
void printTotalsDivider(Totals const& totals);
|
||||
void printSummaryDivider();
|
||||
void printTestFilters();
|
||||
|
||||
private:
|
||||
bool m_headerPrinted = false;
|
||||
|
@@ -76,6 +76,22 @@ namespace Catch {
|
||||
void JunitReporter::testRunStarting( TestRunInfo const& runInfo ) {
|
||||
CumulativeReporterBase::testRunStarting( runInfo );
|
||||
xml.startElement( "testsuites" );
|
||||
|
||||
if ( m_config->hasTestFilters() || m_config->rngSeed() != 0 )
|
||||
xml.startElement("properties");
|
||||
|
||||
if ( m_config->hasTestFilters() ) {
|
||||
xml.scopedElement( "property" )
|
||||
.writeAttribute( "name" , "filters" )
|
||||
.writeAttribute( "value" , serializeFilters( m_config->getTestsOrTags() ) );
|
||||
}
|
||||
|
||||
if( m_config->rngSeed() != 0 ) {
|
||||
xml.scopedElement( "property" )
|
||||
.writeAttribute( "name", "random-seed" )
|
||||
.writeAttribute( "value", m_config->rngSeed() );
|
||||
xml.endElement();
|
||||
}
|
||||
}
|
||||
|
||||
void JunitReporter::testGroupStarting( GroupInfo const& groupInfo ) {
|
||||
|
@@ -42,9 +42,9 @@ namespace Catch {
|
||||
bool assertionEnded( AssertionStats const& _assertionStats ) override {
|
||||
++counter;
|
||||
|
||||
stream << "# " << currentTestCaseInfo->name << std::endl;
|
||||
AssertionPrinter printer( stream, _assertionStats, counter );
|
||||
printer.print();
|
||||
stream << " # " << currentTestCaseInfo->name ;
|
||||
|
||||
stream << std::endl;
|
||||
return true;
|
||||
|
@@ -55,6 +55,8 @@ namespace Catch {
|
||||
m_xml.startElement( "Catch" );
|
||||
if( !m_config->name().empty() )
|
||||
m_xml.writeAttribute( "name", m_config->name() );
|
||||
if (m_config->testSpec().hasFilters())
|
||||
m_xml.writeAttribute( "filters", serializeFilters( m_config->getTestsOrTags() ) );
|
||||
if( m_config->rngSeed() != 0 )
|
||||
m_xml.scopedElement( "Randomness" )
|
||||
.writeAttribute( "seed", m_config->rngSeed() );
|
||||
|
@@ -19,7 +19,7 @@ set(TEST_SOURCES
|
||||
${SELF_TEST_DIR}/IntrospectiveTests/CmdLine.tests.cpp
|
||||
${SELF_TEST_DIR}/IntrospectiveTests/GeneratorsImpl.tests.cpp
|
||||
${SELF_TEST_DIR}/IntrospectiveTests/PartTracker.tests.cpp
|
||||
${SELF_TEST_DIR}/IntrospectiveTests/TagAlias.tests.cpp
|
||||
${SELF_TEST_DIR}/IntrospectiveTests/Tag.tests.cpp
|
||||
${SELF_TEST_DIR}/IntrospectiveTests/String.tests.cpp
|
||||
${SELF_TEST_DIR}/IntrospectiveTests/Xml.tests.cpp
|
||||
${SELF_TEST_DIR}/UsageTests/Approx.tests.cpp
|
||||
@@ -102,6 +102,8 @@ set(INTERNAL_HEADERS
|
||||
${HEADER_DIR}/internal/catch_external_interfaces.h
|
||||
${HEADER_DIR}/internal/catch_fatal_condition.h
|
||||
${HEADER_DIR}/internal/catch_generators.hpp
|
||||
${HEADER_DIR}/internal/catch_generators_generic.hpp
|
||||
${HEADER_DIR}/internal/catch_generators_specific.hpp
|
||||
${HEADER_DIR}/internal/catch_impl.hpp
|
||||
${HEADER_DIR}/internal/catch_interfaces_capture.h
|
||||
${HEADER_DIR}/internal/catch_interfaces_config.h
|
||||
|
@@ -14,6 +14,10 @@ Compilation.tests.cpp:<line number>: passed: std::memcmp(uarr, "123", sizeof(uar
|
||||
Compilation.tests.cpp:<line number>: passed: std::memcmp(sarr, "456", sizeof(sarr)) == 0 for: 0 == 0 with 2 messages: 'uarr := "123"' and 'sarr := "456"'
|
||||
Compilation.tests.cpp:<line number>: passed:
|
||||
Compilation.tests.cpp:<line number>: passed: h1 == h2 for: [1403 helper] == [1403 helper]
|
||||
This would not be caught previously
|
||||
Nor would this
|
||||
Tricky.tests.cpp:<line number>: failed: explicitly with 1 message: '1514'
|
||||
Compilation.tests.cpp:<line number>: passed: std::is_same<TypeList<int>, TypeList<int>>::value for: true
|
||||
Exception.tests.cpp:<line number>: failed: unexpected exception with message: 'answer := 42' with 1 message: 'expected exception'
|
||||
Exception.tests.cpp:<line number>: failed: unexpected exception with message: 'answer := 42'; expression was: thisThrows() with 1 message: 'expected exception'
|
||||
Exception.tests.cpp:<line number>: passed: thisThrows() with 1 message: 'answer := 42'
|
||||
@@ -402,6 +406,7 @@ Matchers.tests.cpp:<line number>: passed: WithinULP(1.f, -1), std::domain_error
|
||||
Generators.tests.cpp:<line number>: passed: i % 2 == 0 for: 0 == 0
|
||||
Generators.tests.cpp:<line number>: passed: i % 2 == 0 for: 0 == 0
|
||||
Generators.tests.cpp:<line number>: passed: i % 2 == 0 for: 0 == 0
|
||||
Generators.tests.cpp:<line number>: passed: filter([] (int) {return false; }, value(1)), Catch::GeneratorException
|
||||
Generators.tests.cpp:<line number>: passed: i < 4 for: 1 < 4
|
||||
Generators.tests.cpp:<line number>: passed: i < 4 for: 2 < 4
|
||||
Generators.tests.cpp:<line number>: passed: i < 4 for: 3 < 4
|
||||
@@ -411,12 +416,28 @@ Generators.tests.cpp:<line number>: passed: i % 2 == 0 for: 0 == 0
|
||||
Generators.tests.cpp:<line number>: passed: i.size() == 1 for: 1 == 1
|
||||
Generators.tests.cpp:<line number>: passed: i.size() == 1 for: 1 == 1
|
||||
Generators.tests.cpp:<line number>: passed: i.size() == 1 for: 1 == 1
|
||||
Generators.tests.cpp:<line number>: passed: i.size() == 1 for: 1 == 1
|
||||
Generators.tests.cpp:<line number>: passed: i.size() == 1 for: 1 == 1
|
||||
Generators.tests.cpp:<line number>: passed: i.size() == 1 for: 1 == 1
|
||||
Generators.tests.cpp:<line number>: passed: j > 0 for: 1 > 0
|
||||
Generators.tests.cpp:<line number>: passed: j > 0 for: 2 > 0
|
||||
Generators.tests.cpp:<line number>: passed: j > 0 for: 3 > 0
|
||||
Generators.tests.cpp:<line number>: passed: j > 0 for: 1 > 0
|
||||
Generators.tests.cpp:<line number>: passed: j > 0 for: 2 > 0
|
||||
Generators.tests.cpp:<line number>: passed: j > 0 for: 3 > 0
|
||||
Generators.tests.cpp:<line number>: passed: chunk2.size() == 2 for: 2 == 2
|
||||
Generators.tests.cpp:<line number>: passed: chunk2.front() == chunk2.back() for: 1 == 1
|
||||
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.size() == 2 for: 2 == 2
|
||||
Generators.tests.cpp:<line number>: passed: chunk2.front() == chunk2.back() for: 3 == 3
|
||||
Generators.tests.cpp:<line number>: passed: chunk2.size() == 2 for: 2 == 2
|
||||
Generators.tests.cpp:<line number>: passed: chunk2.front() == chunk2.back() for: 1 == 1
|
||||
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: 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
|
||||
Generators.tests.cpp:<line number>: passed: j < i for: -1 < 1
|
||||
@@ -477,6 +498,12 @@ GeneratorsImpl.tests.cpp:<line number>: passed: gen.get() == 4.0 for: 4.0 == 4.0
|
||||
GeneratorsImpl.tests.cpp:<line number>: passed: gen.next() for: true
|
||||
GeneratorsImpl.tests.cpp:<line number>: passed: gen.get() == 6.0 for: 6.0 == 6.0
|
||||
GeneratorsImpl.tests.cpp:<line number>: passed: !(gen.next()) for: !false
|
||||
GeneratorsImpl.tests.cpp:<line number>: passed: gen.get() == 2.0 for: 2.0 == 2.0
|
||||
GeneratorsImpl.tests.cpp:<line number>: passed: gen.next() for: true
|
||||
GeneratorsImpl.tests.cpp:<line number>: passed: gen.get() == 4.0 for: 4.0 == 4.0
|
||||
GeneratorsImpl.tests.cpp:<line number>: passed: gen.next() for: true
|
||||
GeneratorsImpl.tests.cpp:<line number>: passed: gen.get() == 6.0 for: 6.0 == 6.0
|
||||
GeneratorsImpl.tests.cpp:<line number>: passed: !(gen.next()) for: !false
|
||||
GeneratorsImpl.tests.cpp:<line number>: passed: gen.get() == 3 for: 3 == 3
|
||||
GeneratorsImpl.tests.cpp:<line number>: passed: !(gen.next()) for: !false
|
||||
GeneratorsImpl.tests.cpp:<line number>: passed: gen.get() == 1 for: 1 == 1
|
||||
@@ -491,6 +518,74 @@ GeneratorsImpl.tests.cpp:<line number>: passed: gen.get() == 2 for: 2 == 2
|
||||
GeneratorsImpl.tests.cpp:<line number>: passed: gen.next() for: true
|
||||
GeneratorsImpl.tests.cpp:<line number>: passed: gen.get() == 3 for: 3 == 3
|
||||
GeneratorsImpl.tests.cpp:<line number>: passed: !(gen.next()) for: !false
|
||||
GeneratorsImpl.tests.cpp:<line number>: passed: gen.get() == -2 for: -2 == -2
|
||||
GeneratorsImpl.tests.cpp:<line number>: passed: gen.next() for: true
|
||||
GeneratorsImpl.tests.cpp:<line number>: passed: gen.get() == -1 for: -1 == -1
|
||||
GeneratorsImpl.tests.cpp:<line number>: passed: gen.next() for: true
|
||||
GeneratorsImpl.tests.cpp:<line number>: passed: gen.get() == 0 for: 0 == 0
|
||||
GeneratorsImpl.tests.cpp:<line number>: passed: gen.next() for: true
|
||||
GeneratorsImpl.tests.cpp:<line number>: passed: gen.get() == 1 for: 1 == 1
|
||||
GeneratorsImpl.tests.cpp:<line number>: passed: !(gen.next()) for: !false
|
||||
GeneratorsImpl.tests.cpp:<line number>: passed: gen.get() == 2 for: 2 == 2
|
||||
GeneratorsImpl.tests.cpp:<line number>: passed: gen.next() for: true
|
||||
GeneratorsImpl.tests.cpp:<line number>: passed: gen.get() == 1 for: 1 == 1
|
||||
GeneratorsImpl.tests.cpp:<line number>: passed: gen.next() for: true
|
||||
GeneratorsImpl.tests.cpp:<line number>: passed: gen.get() == 0 for: 0 == 0
|
||||
GeneratorsImpl.tests.cpp:<line number>: passed: gen.next() for: true
|
||||
GeneratorsImpl.tests.cpp:<line number>: passed: gen.get() == -1 for: -1 == -1
|
||||
GeneratorsImpl.tests.cpp:<line number>: passed: !(gen.next()) for: !false
|
||||
GeneratorsImpl.tests.cpp:<line number>: passed: gen.get() == -7 for: -7 == -7
|
||||
GeneratorsImpl.tests.cpp:<line number>: passed: gen.next() for: true
|
||||
GeneratorsImpl.tests.cpp:<line number>: passed: gen.get() == -4 for: -4 == -4
|
||||
GeneratorsImpl.tests.cpp:<line number>: passed: gen.next() for: true
|
||||
GeneratorsImpl.tests.cpp:<line number>: passed: gen.get() == -1 for: -1 == -1
|
||||
GeneratorsImpl.tests.cpp:<line number>: passed: gen.next() for: true
|
||||
GeneratorsImpl.tests.cpp:<line number>: passed: gen.get() == 2 for: 2 == 2
|
||||
GeneratorsImpl.tests.cpp:<line number>: passed: !(gen.next()) for: !false
|
||||
GeneratorsImpl.tests.cpp:<line number>: passed: gen.get() == -7 for: -7 == -7
|
||||
GeneratorsImpl.tests.cpp:<line number>: passed: gen.next() for: true
|
||||
GeneratorsImpl.tests.cpp:<line number>: passed: gen.get() == -4 for: -4 == -4
|
||||
GeneratorsImpl.tests.cpp:<line number>: passed: gen.next() for: true
|
||||
GeneratorsImpl.tests.cpp:<line number>: passed: gen.get() == -1 for: -1 == -1
|
||||
GeneratorsImpl.tests.cpp:<line number>: passed: gen.next() for: true
|
||||
GeneratorsImpl.tests.cpp:<line number>: passed: gen.get() == 2 for: 2 == 2
|
||||
GeneratorsImpl.tests.cpp:<line number>: passed: !(gen.next()) for: !false
|
||||
GeneratorsImpl.tests.cpp:<line number>: passed: gen.get() == -7 for: -7 == -7
|
||||
GeneratorsImpl.tests.cpp:<line number>: passed: gen.next() for: true
|
||||
GeneratorsImpl.tests.cpp:<line number>: passed: gen.get() == -4 for: -4 == -4
|
||||
GeneratorsImpl.tests.cpp:<line number>: passed: gen.next() for: true
|
||||
GeneratorsImpl.tests.cpp:<line number>: passed: gen.get() == -1 for: -1 == -1
|
||||
GeneratorsImpl.tests.cpp:<line number>: passed: gen.next() for: true
|
||||
GeneratorsImpl.tests.cpp:<line number>: passed: gen.get() == 2 for: 2 == 2
|
||||
GeneratorsImpl.tests.cpp:<line number>: passed: gen.next() for: true
|
||||
GeneratorsImpl.tests.cpp:<line number>: passed: gen.get() == 5 for: 5 == 5
|
||||
GeneratorsImpl.tests.cpp:<line number>: passed: !(gen.next()) for: !false
|
||||
GeneratorsImpl.tests.cpp:<line number>: passed: gen.get() == 5 for: 5 == 5
|
||||
GeneratorsImpl.tests.cpp:<line number>: passed: gen.next() for: true
|
||||
GeneratorsImpl.tests.cpp:<line number>: passed: gen.get() == 2 for: 2 == 2
|
||||
GeneratorsImpl.tests.cpp:<line number>: passed: gen.next() for: true
|
||||
GeneratorsImpl.tests.cpp:<line number>: passed: gen.get() == -1 for: -1 == -1
|
||||
GeneratorsImpl.tests.cpp:<line number>: passed: gen.next() for: true
|
||||
GeneratorsImpl.tests.cpp:<line number>: passed: gen.get() == -4 for: -4 == -4
|
||||
GeneratorsImpl.tests.cpp:<line number>: passed: !(gen.next()) for: !false
|
||||
GeneratorsImpl.tests.cpp:<line number>: passed: gen.get() == 5 for: 5 == 5
|
||||
GeneratorsImpl.tests.cpp:<line number>: passed: gen.next() for: true
|
||||
GeneratorsImpl.tests.cpp:<line number>: passed: gen.get() == 2 for: 2 == 2
|
||||
GeneratorsImpl.tests.cpp:<line number>: passed: gen.next() for: true
|
||||
GeneratorsImpl.tests.cpp:<line number>: passed: gen.get() == -1 for: -1 == -1
|
||||
GeneratorsImpl.tests.cpp:<line number>: passed: gen.next() for: true
|
||||
GeneratorsImpl.tests.cpp:<line number>: passed: gen.get() == -4 for: -4 == -4
|
||||
GeneratorsImpl.tests.cpp:<line number>: passed: !(gen.next()) for: !false
|
||||
GeneratorsImpl.tests.cpp:<line number>: passed: gen.get() == 5 for: 5 == 5
|
||||
GeneratorsImpl.tests.cpp:<line number>: passed: gen.next() for: true
|
||||
GeneratorsImpl.tests.cpp:<line number>: passed: gen.get() == 2 for: 2 == 2
|
||||
GeneratorsImpl.tests.cpp:<line number>: passed: gen.next() for: true
|
||||
GeneratorsImpl.tests.cpp:<line number>: passed: gen.get() == -1 for: -1 == -1
|
||||
GeneratorsImpl.tests.cpp:<line number>: passed: gen.next() for: true
|
||||
GeneratorsImpl.tests.cpp:<line number>: passed: gen.get() == -4 for: -4 == -4
|
||||
GeneratorsImpl.tests.cpp:<line number>: passed: gen.next() for: true
|
||||
GeneratorsImpl.tests.cpp:<line number>: passed: gen.get() == -7 for: -7 == -7
|
||||
GeneratorsImpl.tests.cpp:<line number>: passed: !(gen.next()) for: !false
|
||||
Approx.tests.cpp:<line number>: passed: d >= Approx( 1.22 ) for: 1.23 >= Approx( 1.22 )
|
||||
Approx.tests.cpp:<line number>: passed: d >= Approx( 1.23 ) for: 1.23 >= Approx( 1.23 )
|
||||
Approx.tests.cpp:<line number>: passed: !(d >= Approx( 1.24 )) for: !(1.23 >= Approx( 1.24 ))
|
||||
@@ -542,6 +637,22 @@ Matchers.tests.cpp:<line number>: passed: testStringForMatching(), !Contains("di
|
||||
Matchers.tests.cpp:<line number>: failed: testStringForMatching(), !Contains("substring") for: "this string contains 'abc' as a substring" not contains: "substring"
|
||||
Exception.tests.cpp:<line number>: passed: thisThrows(), "expected exception" for: "expected exception" equals: "expected exception"
|
||||
Exception.tests.cpp:<line number>: failed: thisThrows(), "should fail" for: "expected exception" equals: "should fail"
|
||||
Generators.tests.cpp:<line number>: passed: values > -6 for: 3 > -6
|
||||
Generators.tests.cpp:<line number>: passed: values > -6 for: 4 > -6
|
||||
Generators.tests.cpp:<line number>: passed: values > -6 for: 5 > -6
|
||||
Generators.tests.cpp:<line number>: passed: values > -6 for: 6 > -6
|
||||
Generators.tests.cpp:<line number>: passed: values > -6 for: -5 > -6
|
||||
Generators.tests.cpp:<line number>: passed: values > -6 for: -4 > -6
|
||||
Generators.tests.cpp:<line number>: passed: values > -6 for: 90 > -6
|
||||
Generators.tests.cpp:<line number>: passed: values > -6 for: 91 > -6
|
||||
Generators.tests.cpp:<line number>: passed: values > -6 for: 92 > -6
|
||||
Generators.tests.cpp:<line number>: passed: values > -6 for: 93 > -6
|
||||
Generators.tests.cpp:<line number>: passed: values > -6 for: 94 > -6
|
||||
Generators.tests.cpp:<line number>: passed: values > -6 for: 95 > -6
|
||||
Generators.tests.cpp:<line number>: passed: values > -6 for: 96 > -6
|
||||
Generators.tests.cpp:<line number>: passed: values > -6 for: 97 > -6
|
||||
Generators.tests.cpp:<line number>: passed: values > -6 for: 98 > -6
|
||||
Generators.tests.cpp:<line number>: passed: values > -6 for: 99 > -6
|
||||
Misc.tests.cpp:<line number>: warning: 'This one ran'
|
||||
Exception.tests.cpp:<line number>: failed: unexpected exception with message: 'custom exception'
|
||||
Tricky.tests.cpp:<line number>: passed: True for: {?}
|
||||
@@ -793,9 +904,9 @@ CmdLine.tests.cpp:<line number>: passed: cli.parse({"test", "--use-colour", "no"
|
||||
CmdLine.tests.cpp:<line number>: passed: config.useColour == UseColour::No for: 2 == 2
|
||||
CmdLine.tests.cpp:<line number>: passed: !result for: true
|
||||
CmdLine.tests.cpp:<line number>: passed: result.errorMessage(), Contains( "colour mode must be one of" ) for: "colour mode must be one of: auto, yes or no. 'wrong' not recognised" contains: "colour mode must be one of"
|
||||
Misc.tests.cpp:<line number>: passed: std::tuple_size<TestType>::value >= 1 for: 1 >= 1
|
||||
Misc.tests.cpp:<line number>: passed: std::tuple_size<TestType>::value >= 1 for: 2 >= 1
|
||||
Misc.tests.cpp:<line number>: passed: std::tuple_size<TestType>::value >= 1 for: 3 >= 1
|
||||
Misc.tests.cpp:<line number>: passed: std::tuple_size<TestType>::value >= 1 for: 2 >= 1
|
||||
Misc.tests.cpp:<line number>: passed: std::tuple_size<TestType>::value >= 1 for: 1 >= 1
|
||||
Decomposition.tests.cpp:<line number>: failed: truthy(false) for: Hey, its truthy!
|
||||
Matchers.tests.cpp:<line number>: failed: testStringForMatching(), Matches("this STRING contains 'abc' as a substring") for: "this string contains 'abc' as a substring" matches "this STRING contains 'abc' as a substring" case sensitively
|
||||
Matchers.tests.cpp:<line number>: failed: testStringForMatching(), Matches("contains 'abc' as a substring") for: "this string contains 'abc' as a substring" matches "contains 'abc' as a substring" case sensitively
|
||||
@@ -909,22 +1020,22 @@ Misc.tests.cpp:<line number>: failed: s1 == s2 for: "if ($b == 10) {
|
||||
$a = 20;
|
||||
}
|
||||
"
|
||||
TagAlias.tests.cpp:<line number>: passed: what, Contains( "[@zzz]" ) for: "error: tag alias, '[@zzz]' already registered.
|
||||
Tag.tests.cpp:<line number>: passed: what, Contains( "[@zzz]" ) for: "error: tag alias, '[@zzz]' already registered.
|
||||
First seen at: file:2
|
||||
Redefined at: file:10" contains: "[@zzz]"
|
||||
TagAlias.tests.cpp:<line number>: passed: what, Contains( "file" ) for: "error: tag alias, '[@zzz]' already registered.
|
||||
Tag.tests.cpp:<line number>: passed: what, Contains( "file" ) for: "error: tag alias, '[@zzz]' already registered.
|
||||
First seen at: file:2
|
||||
Redefined at: file:10" contains: "file"
|
||||
TagAlias.tests.cpp:<line number>: passed: what, Contains( "2" ) for: "error: tag alias, '[@zzz]' already registered.
|
||||
Tag.tests.cpp:<line number>: passed: what, Contains( "2" ) for: "error: tag alias, '[@zzz]' already registered.
|
||||
First seen at: file:2
|
||||
Redefined at: file:10" contains: "2"
|
||||
TagAlias.tests.cpp:<line number>: passed: what, Contains( "10" ) for: "error: tag alias, '[@zzz]' already registered.
|
||||
Tag.tests.cpp:<line number>: passed: what, Contains( "10" ) for: "error: tag alias, '[@zzz]' already registered.
|
||||
First seen at: file:2
|
||||
Redefined at: file:10" contains: "10"
|
||||
TagAlias.tests.cpp:<line number>: passed: registry.add( "[no ampersat]", "", Catch::SourceLineInfo( "file", 3 ) )
|
||||
TagAlias.tests.cpp:<line number>: passed: registry.add( "[the @ is not at the start]", "", Catch::SourceLineInfo( "file", 3 ) )
|
||||
TagAlias.tests.cpp:<line number>: passed: registry.add( "@no square bracket at start]", "", Catch::SourceLineInfo( "file", 3 ) )
|
||||
TagAlias.tests.cpp:<line number>: passed: registry.add( "[@no square bracket at end", "", Catch::SourceLineInfo( "file", 3 ) )
|
||||
Tag.tests.cpp:<line number>: passed: registry.add( "[no ampersat]", "", Catch::SourceLineInfo( "file", 3 ) )
|
||||
Tag.tests.cpp:<line number>: passed: registry.add( "[the @ is not at the start]", "", Catch::SourceLineInfo( "file", 3 ) )
|
||||
Tag.tests.cpp:<line number>: passed: registry.add( "@no square bracket at start]", "", Catch::SourceLineInfo( "file", 3 ) )
|
||||
Tag.tests.cpp:<line number>: passed: registry.add( "[@no square bracket at end", "", Catch::SourceLineInfo( "file", 3 ) )
|
||||
Misc.tests.cpp:<line number>: passed: v.size() == 5 for: 5 == 5
|
||||
Misc.tests.cpp:<line number>: passed: v.capacity() >= 5 for: 5 >= 5
|
||||
Misc.tests.cpp:<line number>: passed: v.size() == 10 for: 10 == 10
|
||||
@@ -1199,6 +1310,7 @@ Misc.tests.cpp:<line number>: passed:
|
||||
Misc.tests.cpp:<line number>: passed:
|
||||
loose text artifact
|
||||
Message.tests.cpp:<line number>: failed: explicitly with 1 message: 'Previous info should not be seen'
|
||||
Message.tests.cpp:<line number>: failed: explicitly with 1 message: 'previous unscoped info SHOULD not be seen'
|
||||
Misc.tests.cpp:<line number>: passed: l == std::numeric_limits<long long>::max() for: 9223372036854775807 (0x<hex digits>)
|
||||
==
|
||||
9223372036854775807 (0x<hex digits>)
|
||||
@@ -1220,6 +1332,8 @@ Misc.tests.cpp:<line number>: failed: ( fib[i] % 2 ) == 0 for: 1 == 0 with 1 mes
|
||||
Misc.tests.cpp:<line number>: passed: ( fib[i] % 2 ) == 0 for: 0 == 0 with 1 message: 'Testing if fib[5] (8) is even'
|
||||
Misc.tests.cpp:<line number>: failed: ( fib[i] % 2 ) == 0 for: 1 == 0 with 1 message: 'Testing if fib[6] (13) is even'
|
||||
Misc.tests.cpp:<line number>: failed: ( fib[i] % 2 ) == 0 for: 1 == 0 with 1 message: 'Testing if fib[7] (21) is even'
|
||||
Message.tests.cpp:<line number>: warning: 'info' with 2 messages: 'unscoped info' and 'and warn may mix'
|
||||
Message.tests.cpp:<line number>: warning: 'info' with 2 messages: 'unscoped info' and 'they are not cleared after warnings'
|
||||
Misc.tests.cpp:<line number>: failed: a == b for: 1 == 2
|
||||
Misc.tests.cpp:<line number>: passed: a != b for: 1 != 2
|
||||
Misc.tests.cpp:<line number>: passed: a < b for: 1 < 2
|
||||
@@ -1229,6 +1343,9 @@ Misc.tests.cpp:<line number>: passed: a != b for: 1 != 2
|
||||
Tricky.tests.cpp:<line number>: passed: s == "7" for: "7" == "7"
|
||||
Tricky.tests.cpp:<line number>: passed: ti == typeid(int) for: {?} == {?}
|
||||
Misc.tests.cpp:<line number>: passed:
|
||||
Message.tests.cpp:<line number>: passed: true with 1 message: 'this MAY be seen only for the FIRST assertion IF info is printed for passing assertions'
|
||||
Message.tests.cpp:<line number>: passed: true with 1 message: 'this MAY be seen only for the SECOND assertion IF info is printed for passing assertions'
|
||||
Message.tests.cpp:<line number>: failed: false with 1 message: 'this SHOULD be seen'
|
||||
Misc.tests.cpp:<line number>: passed: makeString( false ) != static_cast<char*>(0) for: "valid string" != {null string}
|
||||
Misc.tests.cpp:<line number>: passed: makeString( true ) == static_cast<char*>(0) for: {null string} == {null string}
|
||||
Tricky.tests.cpp:<line number>: passed: ptr.get() == 0 for: 0 == 0
|
||||
@@ -1236,6 +1353,12 @@ ToStringPair.tests.cpp:<line number>: passed: ::Catch::Detail::stringify( pair )
|
||||
==
|
||||
"{ { 42, "Arthur" }, { "Ford", 24 } }"
|
||||
Tricky.tests.cpp:<line number>: passed: p == 0 for: 0 == 0
|
||||
Message.tests.cpp:<line number>: passed: true with 1 message: 'this MAY be seen IF info is printed for passing assertions'
|
||||
Message.tests.cpp:<line number>: failed: false with 2 messages: 'this SHOULD be seen' and 'this SHOULD also be seen'
|
||||
Message.tests.cpp:<line number>: failed: false with 1 message: 'this SHOULD be seen only ONCE'
|
||||
Message.tests.cpp:<line number>: passed: true
|
||||
Message.tests.cpp:<line number>: passed: true with 1 message: 'this MAY also be seen only ONCE IF info is printed for passing assertions'
|
||||
Message.tests.cpp:<line number>: passed: true
|
||||
Misc.tests.cpp:<line number>: passed: a != b for: 1 != 2
|
||||
Misc.tests.cpp:<line number>: passed: b != a for: 2 != 1
|
||||
Misc.tests.cpp:<line number>: passed: a != b for: 1 != 2
|
||||
@@ -1255,6 +1378,9 @@ String.tests.cpp:<line number>: passed: Catch::replaceInPlace( s, "'", "|'" ) fo
|
||||
String.tests.cpp:<line number>: passed: s == "didn|'t" for: "didn|'t" == "didn|'t"
|
||||
Misc.tests.cpp:<line number>: failed: false with 1 message: '3'
|
||||
Message.tests.cpp:<line number>: failed: false with 2 messages: 'hi' and 'i := 7'
|
||||
Tag.tests.cpp:<line number>: passed: testcase.tags, Catch::VectorContains(std::string("magic-tag")) && Catch::VectorContains(std::string(".")) for: { ".", "magic-tag" } ( Contains: "magic-tag" and Contains: "." )
|
||||
Message.tests.cpp:<line number>: failed: false with 4 messages: 'Count 1 to 3...' and '1' and '2' and '3'
|
||||
Message.tests.cpp:<line number>: failed: false with 4 messages: 'Count 4 to 6...' and '4' and '5' and '6'
|
||||
ToStringGeneral.tests.cpp:<line number>: passed: Catch::Detail::stringify( emptyMap ) == "{ }" for: "{ }" == "{ }"
|
||||
ToStringGeneral.tests.cpp:<line number>: passed: Catch::Detail::stringify( map ) == "{ { \"one\", 1 } }" for: "{ { "one", 1 } }" == "{ { "one", 1 } }"
|
||||
ToStringGeneral.tests.cpp:<line number>: passed: Catch::Detail::stringify( map ) == "{ { \"abc\", 1 }, { \"def\", 2 }, { \"ghi\", 3 } }" for: "{ { "abc", 1 }, { "def", 2 }, { "ghi", 3 } }"
|
||||
@@ -1376,5 +1502,5 @@ Misc.tests.cpp:<line number>: passed: v.size() == 5 for: 5 == 5
|
||||
Misc.tests.cpp:<line number>: passed: v.capacity() >= 5 for: 5 >= 5
|
||||
Misc.tests.cpp:<line number>: passed:
|
||||
Misc.tests.cpp:<line number>: passed:
|
||||
Failed 69 test cases, failed 129 assertions.
|
||||
Failed 77 test cases, failed 138 assertions.
|
||||
|
||||
|
@@ -1,3 +1,6 @@
|
||||
Filters: ~[!nonportable]~[!benchmark]~[approvals]
|
||||
This would not be caught previously
|
||||
Nor would this
|
||||
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
<exe-name> is a <version> host application.
|
||||
@@ -5,6 +8,16 @@ Run with -? for options
|
||||
|
||||
Randomness seeded to: 1
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
#1514: stderr/stdout is not captured in tests aborted by an exception
|
||||
-------------------------------------------------------------------------------
|
||||
Tricky.tests.cpp:<line number>
|
||||
...............................................................................
|
||||
|
||||
Tricky.tests.cpp:<line number>: FAILED:
|
||||
explicitly with message:
|
||||
1514
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
#748 - captures with unexpected exceptions
|
||||
outside assertions
|
||||
@@ -93,7 +106,8 @@ with expansion:
|
||||
"hello" == "world"
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
A TEMPLATE_PRODUCT_TEST_CASE_METHOD based test run that fails - 0
|
||||
A TEMPLATE_PRODUCT_TEST_CASE_METHOD based test run that fails - Template_Foo
|
||||
<float>
|
||||
-------------------------------------------------------------------------------
|
||||
Class.tests.cpp:<line number>
|
||||
...............................................................................
|
||||
@@ -104,7 +118,8 @@ with expansion:
|
||||
0 == 1
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
A TEMPLATE_PRODUCT_TEST_CASE_METHOD based test run that fails - 1
|
||||
A TEMPLATE_PRODUCT_TEST_CASE_METHOD based test run that fails - Template_Foo
|
||||
<int>
|
||||
-------------------------------------------------------------------------------
|
||||
Class.tests.cpp:<line number>
|
||||
...............................................................................
|
||||
@@ -115,7 +130,8 @@ with expansion:
|
||||
0 == 1
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
A TEMPLATE_PRODUCT_TEST_CASE_METHOD based test run that fails - 2
|
||||
A TEMPLATE_PRODUCT_TEST_CASE_METHOD based test run that fails - std::vector
|
||||
<float>
|
||||
-------------------------------------------------------------------------------
|
||||
Class.tests.cpp:<line number>
|
||||
...............................................................................
|
||||
@@ -126,7 +142,8 @@ with expansion:
|
||||
0 == 1
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
A TEMPLATE_PRODUCT_TEST_CASE_METHOD based test run that fails - 3
|
||||
A TEMPLATE_PRODUCT_TEST_CASE_METHOD based test run that fails - std::vector
|
||||
<int>
|
||||
-------------------------------------------------------------------------------
|
||||
Class.tests.cpp:<line number>
|
||||
...............................................................................
|
||||
@@ -1040,6 +1057,16 @@ Message.tests.cpp:<line number>: FAILED:
|
||||
explicitly with message:
|
||||
Previous info should not be seen
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
just failure after unscoped info
|
||||
-------------------------------------------------------------------------------
|
||||
Message.tests.cpp:<line number>
|
||||
...............................................................................
|
||||
|
||||
Message.tests.cpp:<line number>: FAILED:
|
||||
explicitly with message:
|
||||
previous unscoped info SHOULD not be seen
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
looped SECTION tests
|
||||
b is currently: 0
|
||||
@@ -1112,6 +1139,18 @@ with expansion:
|
||||
with message:
|
||||
Testing if fib[7] (21) is even
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
mix info, unscoped info and warning
|
||||
-------------------------------------------------------------------------------
|
||||
Message.tests.cpp:<line number>
|
||||
...............................................................................
|
||||
|
||||
Message.tests.cpp:<line number>: warning:
|
||||
and warn may mix
|
||||
|
||||
Message.tests.cpp:<line number>: warning:
|
||||
they are not cleared after warnings
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
more nested SECTION tests
|
||||
doesn't equal
|
||||
@@ -1125,6 +1164,40 @@ Misc.tests.cpp:<line number>: FAILED:
|
||||
with expansion:
|
||||
1 == 2
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
not prints unscoped info from previous failures
|
||||
-------------------------------------------------------------------------------
|
||||
Message.tests.cpp:<line number>
|
||||
...............................................................................
|
||||
|
||||
Message.tests.cpp:<line number>: FAILED:
|
||||
REQUIRE( false )
|
||||
with message:
|
||||
this SHOULD be seen
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
prints unscoped info on failure
|
||||
-------------------------------------------------------------------------------
|
||||
Message.tests.cpp:<line number>
|
||||
...............................................................................
|
||||
|
||||
Message.tests.cpp:<line number>: FAILED:
|
||||
REQUIRE( false )
|
||||
with messages:
|
||||
this SHOULD be seen
|
||||
this SHOULD also be seen
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
prints unscoped info only for the first assertion
|
||||
-------------------------------------------------------------------------------
|
||||
Message.tests.cpp:<line number>
|
||||
...............................................................................
|
||||
|
||||
Message.tests.cpp:<line number>: FAILED:
|
||||
CHECK( false )
|
||||
with message:
|
||||
this SHOULD be seen only ONCE
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
send a single char to INFO
|
||||
-------------------------------------------------------------------------------
|
||||
@@ -1148,6 +1221,28 @@ with messages:
|
||||
hi
|
||||
i := 7
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
stacks unscoped info in loops
|
||||
-------------------------------------------------------------------------------
|
||||
Message.tests.cpp:<line number>
|
||||
...............................................................................
|
||||
|
||||
Message.tests.cpp:<line number>: FAILED:
|
||||
CHECK( false )
|
||||
with messages:
|
||||
Count 1 to 3...
|
||||
1
|
||||
2
|
||||
3
|
||||
|
||||
Message.tests.cpp:<line number>: FAILED:
|
||||
CHECK( false )
|
||||
with messages:
|
||||
Count 4 to 6...
|
||||
4
|
||||
5
|
||||
6
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
string literals of different sizes can be compared
|
||||
-------------------------------------------------------------------------------
|
||||
@@ -1170,6 +1265,6 @@ due to unexpected exception with message:
|
||||
Why would you throw a std::string?
|
||||
|
||||
===============================================================================
|
||||
test cases: 245 | 185 passed | 56 failed | 4 failed as expected
|
||||
assertions: 1297 | 1161 passed | 115 failed | 21 failed as expected
|
||||
test cases: 257 | 191 passed | 62 failed | 4 failed as expected
|
||||
assertions: 1419 | 1276 passed | 122 failed | 21 failed as expected
|
||||
|
||||
|
File diff suppressed because it is too large
Load Diff
@@ -1,3 +1,4 @@
|
||||
Filters: ~[!nonportable]~[!benchmark]~[approvals]
|
||||
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
<exe-name> is a <version> host application.
|
||||
@@ -133,6 +134,29 @@ Compilation.tests.cpp:<line number>: PASSED:
|
||||
with expansion:
|
||||
[1403 helper] == [1403 helper]
|
||||
|
||||
This would not be caught previously
|
||||
Nor would this
|
||||
-------------------------------------------------------------------------------
|
||||
#1514: stderr/stdout is not captured in tests aborted by an exception
|
||||
-------------------------------------------------------------------------------
|
||||
Tricky.tests.cpp:<line number>
|
||||
...............................................................................
|
||||
|
||||
Tricky.tests.cpp:<line number>: FAILED:
|
||||
explicitly with message:
|
||||
1514
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
#1548
|
||||
-------------------------------------------------------------------------------
|
||||
Compilation.tests.cpp:<line number>
|
||||
...............................................................................
|
||||
|
||||
Compilation.tests.cpp:<line number>: PASSED:
|
||||
REQUIRE( std::is_same<TypeList<int>, TypeList<int>>::value )
|
||||
with expansion:
|
||||
true
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
#748 - captures with unexpected exceptions
|
||||
outside assertions
|
||||
@@ -317,12 +341,7 @@ Condition.tests.cpp:<line number>: FAILED:
|
||||
with expansion:
|
||||
false
|
||||
|
||||
Condition.tests.cpp:<line number>: FAILED:
|
||||
CHECK_FALSE( true )
|
||||
with expansion:
|
||||
!true
|
||||
|
||||
===============================================================================
|
||||
test cases: 15 | 12 passed | 1 failed | 2 failed as expected
|
||||
assertions: 39 | 32 passed | 4 failed | 3 failed as expected
|
||||
test cases: 17 | 13 passed | 2 failed | 2 failed as expected
|
||||
assertions: 40 | 33 passed | 4 failed | 3 failed as expected
|
||||
|
||||
|
@@ -1,7 +1,11 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<testsuitesloose text artifact
|
||||
>
|
||||
<testsuite name="<exe-name>" errors="17" failures="113" tests="1312" hostname="tbd" time="{duration}" timestamp="{iso8601-timestamp}">
|
||||
<testsuites>
|
||||
<properties>
|
||||
<property name="filters" value="~[!nonportable]~[!benchmark]~[approvals]"/>
|
||||
<property name="random-seed" value="1"/>
|
||||
</properties>
|
||||
loose text artifact
|
||||
<testsuite name="<exe-name>" errors="17" failures="122" tests="1436" hostname="tbd" time="{duration}" timestamp="{iso8601-timestamp}">
|
||||
<testcase classname="<exe-name>.global" name="# A test name that starts with a #" time="{duration}"/>
|
||||
<testcase classname="<exe-name>.global" name="#1005: Comparing pointer to int and long (NULL can be either on various systems)" time="{duration}"/>
|
||||
<testcase classname="<exe-name>.global" name="#1027" time="{duration}"/>
|
||||
@@ -10,6 +14,19 @@
|
||||
<testcase classname="<exe-name>.global" name="#1238" time="{duration}"/>
|
||||
<testcase classname="<exe-name>.(Fixture_1245<int, int>)" name="#1245" time="{duration}"/>
|
||||
<testcase classname="<exe-name>.global" name="#1403" time="{duration}"/>
|
||||
<testcase classname="<exe-name>.global" name="#1514: stderr/stdout is not captured in tests aborted by an exception" time="{duration}">
|
||||
<failure type="FAIL">
|
||||
1514
|
||||
Tricky.tests.cpp:<line number>
|
||||
</failure>
|
||||
<system-out>
|
||||
This would not be caught previously
|
||||
</system-out>
|
||||
<system-err>
|
||||
Nor would this
|
||||
</system-err>
|
||||
</testcase>
|
||||
<testcase classname="<exe-name>.global" name="#1548" time="{duration}"/>
|
||||
<testcase classname="<exe-name>.global" name="#748 - captures with unexpected exceptions/outside assertions" time="{duration}">
|
||||
<error type="TEST_CASE">
|
||||
expected exception
|
||||
@@ -77,30 +94,30 @@ Class.tests.cpp:<line number>
|
||||
</failure>
|
||||
</testcase>
|
||||
<testcase classname="<exe-name>.TestClass" name="A METHOD_AS_TEST_CASE based test run that succeeds" time="{duration}"/>
|
||||
<testcase classname="<exe-name>.Template_Fixture_2" name="A TEMPLATE_PRODUCT_TEST_CASE_METHOD based test run that fails - 0" time="{duration}">
|
||||
<testcase classname="<exe-name>.Template_Fixture_2" name="A TEMPLATE_PRODUCT_TEST_CASE_METHOD based test run that fails - Template_Foo<float>" time="{duration}">
|
||||
<failure message="0 == 1" type="REQUIRE">
|
||||
Class.tests.cpp:<line number>
|
||||
</failure>
|
||||
</testcase>
|
||||
<testcase classname="<exe-name>.Template_Fixture_2" name="A TEMPLATE_PRODUCT_TEST_CASE_METHOD based test run that fails - 1" time="{duration}">
|
||||
<testcase classname="<exe-name>.Template_Fixture_2" name="A TEMPLATE_PRODUCT_TEST_CASE_METHOD based test run that fails - Template_Foo<int>" time="{duration}">
|
||||
<failure message="0 == 1" type="REQUIRE">
|
||||
Class.tests.cpp:<line number>
|
||||
</failure>
|
||||
</testcase>
|
||||
<testcase classname="<exe-name>.Template_Fixture_2" name="A TEMPLATE_PRODUCT_TEST_CASE_METHOD based test run that fails - 2" time="{duration}">
|
||||
<testcase classname="<exe-name>.Template_Fixture_2" name="A TEMPLATE_PRODUCT_TEST_CASE_METHOD based test run that fails - std::vector<float>" time="{duration}">
|
||||
<failure message="0 == 1" type="REQUIRE">
|
||||
Class.tests.cpp:<line number>
|
||||
</failure>
|
||||
</testcase>
|
||||
<testcase classname="<exe-name>.Template_Fixture_2" name="A TEMPLATE_PRODUCT_TEST_CASE_METHOD based test run that fails - 3" time="{duration}">
|
||||
<testcase classname="<exe-name>.Template_Fixture_2" name="A TEMPLATE_PRODUCT_TEST_CASE_METHOD based test run that fails - std::vector<int>" time="{duration}">
|
||||
<failure message="0 == 1" type="REQUIRE">
|
||||
Class.tests.cpp:<line number>
|
||||
</failure>
|
||||
</testcase>
|
||||
<testcase classname="<exe-name>.Template_Fixture_2" name="A TEMPLATE_PRODUCT_TEST_CASE_METHOD based test run that succeeds - 0" time="{duration}"/>
|
||||
<testcase classname="<exe-name>.Template_Fixture_2" name="A TEMPLATE_PRODUCT_TEST_CASE_METHOD based test run that succeeds - 1" time="{duration}"/>
|
||||
<testcase classname="<exe-name>.Template_Fixture_2" name="A TEMPLATE_PRODUCT_TEST_CASE_METHOD based test run that succeeds - 2" time="{duration}"/>
|
||||
<testcase classname="<exe-name>.Template_Fixture_2" name="A TEMPLATE_PRODUCT_TEST_CASE_METHOD based test run that succeeds - 3" time="{duration}"/>
|
||||
<testcase classname="<exe-name>.Template_Fixture_2" name="A TEMPLATE_PRODUCT_TEST_CASE_METHOD based test run that succeeds - Template_Foo<float>" time="{duration}"/>
|
||||
<testcase classname="<exe-name>.Template_Fixture_2" name="A TEMPLATE_PRODUCT_TEST_CASE_METHOD based test run that succeeds - Template_Foo<int>" time="{duration}"/>
|
||||
<testcase classname="<exe-name>.Template_Fixture_2" name="A TEMPLATE_PRODUCT_TEST_CASE_METHOD based test run that succeeds - std::vector<float>" time="{duration}"/>
|
||||
<testcase classname="<exe-name>.Template_Fixture_2" name="A TEMPLATE_PRODUCT_TEST_CASE_METHOD based test run that succeeds - std::vector<int>" time="{duration}"/>
|
||||
<testcase classname="<exe-name>.Template_Fixture" name="A TEMPLATE_TEST_CASE_METHOD based test run that fails - double" time="{duration}">
|
||||
<failure message="1.0 == 2" type="REQUIRE">
|
||||
Class.tests.cpp:<line number>
|
||||
@@ -125,10 +142,10 @@ Class.tests.cpp:<line number>
|
||||
</failure>
|
||||
</testcase>
|
||||
<testcase classname="<exe-name>.Fixture" name="A TEST_CASE_METHOD based test run that succeeds" time="{duration}"/>
|
||||
<testcase classname="<exe-name>.global" name="A Template product test case - 0" time="{duration}"/>
|
||||
<testcase classname="<exe-name>.global" name="A Template product test case - 1" time="{duration}"/>
|
||||
<testcase classname="<exe-name>.global" name="A Template product test case - 2" time="{duration}"/>
|
||||
<testcase classname="<exe-name>.global" name="A Template product test case - 3" time="{duration}"/>
|
||||
<testcase classname="<exe-name>.global" name="A Template product test case - Foo<float>" time="{duration}"/>
|
||||
<testcase classname="<exe-name>.global" name="A Template product test case - Foo<int>" time="{duration}"/>
|
||||
<testcase classname="<exe-name>.global" name="A Template product test case - std::vector<float>" time="{duration}"/>
|
||||
<testcase classname="<exe-name>.global" name="A Template product test case - std::vector<int>" time="{duration}"/>
|
||||
<testcase classname="<exe-name>.global" name="A comparison that uses literals instead of the normal constructor" time="{duration}"/>
|
||||
<testcase classname="<exe-name>.global" name="A couple of nested sections followed by a failure" time="{duration}">
|
||||
<failure type="FAIL">
|
||||
@@ -339,11 +356,16 @@ Message.tests.cpp:<line number>
|
||||
<testcase classname="<exe-name>.global" name="Floating point matchers: float/ULPs" time="{duration}"/>
|
||||
<testcase classname="<exe-name>.global" name="Floating point matchers: float/Composed" time="{duration}"/>
|
||||
<testcase classname="<exe-name>.global" name="Floating point matchers: float/Constructor validation" time="{duration}"/>
|
||||
<testcase classname="<exe-name>.global" name="Generators -- adapters/Filtering by predicate" time="{duration}"/>
|
||||
<testcase classname="<exe-name>.global" name="Generators -- adapters/Filtering by predicate/Basic usage" time="{duration}"/>
|
||||
<testcase classname="<exe-name>.global" name="Generators -- adapters/Filtering by predicate/Throws if there are no matching values" time="{duration}"/>
|
||||
<testcase classname="<exe-name>.global" name="Generators -- adapters/Shortening a range" time="{duration}"/>
|
||||
<testcase classname="<exe-name>.global" name="Generators -- adapters/Transforming elements/Same type" time="{duration}"/>
|
||||
<testcase classname="<exe-name>.global" name="Generators -- adapters/Transforming elements/Different type" time="{duration}"/>
|
||||
<testcase classname="<exe-name>.global" name="Generators -- adapters/Transforming elements/Different deduced type" time="{duration}"/>
|
||||
<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/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}"/>
|
||||
<testcase classname="<exe-name>.global" name="Generators internals/Single value" time="{duration}"/>
|
||||
@@ -353,9 +375,18 @@ Message.tests.cpp:<line number>
|
||||
<testcase classname="<exe-name>.global" name="Generators internals/Filter generator" time="{duration}"/>
|
||||
<testcase classname="<exe-name>.global" name="Generators internals/Take generator/Take less" time="{duration}"/>
|
||||
<testcase classname="<exe-name>.global" name="Generators internals/Take generator/Take more" time="{duration}"/>
|
||||
<testcase classname="<exe-name>.global" name="Generators internals/Map" time="{duration}"/>
|
||||
<testcase classname="<exe-name>.global" name="Generators internals/Map with explicit return type" time="{duration}"/>
|
||||
<testcase classname="<exe-name>.global" name="Generators internals/Map with deduced return type" time="{duration}"/>
|
||||
<testcase classname="<exe-name>.global" name="Generators internals/Repeat/Singular repeat" time="{duration}"/>
|
||||
<testcase classname="<exe-name>.global" name="Generators internals/Repeat/Actual repeat" time="{duration}"/>
|
||||
<testcase classname="<exe-name>.global" name="Generators internals/Range/Positive auto step/Integer" time="{duration}"/>
|
||||
<testcase classname="<exe-name>.global" name="Generators internals/Range/Negative auto step/Integer" time="{duration}"/>
|
||||
<testcase classname="<exe-name>.global" name="Generators internals/Range/Positive manual step/Integer/Exact" time="{duration}"/>
|
||||
<testcase classname="<exe-name>.global" name="Generators internals/Range/Positive manual step/Integer/Slightly over end" time="{duration}"/>
|
||||
<testcase classname="<exe-name>.global" name="Generators internals/Range/Positive manual step/Integer/Slightly under end" time="{duration}"/>
|
||||
<testcase classname="<exe-name>.global" name="Generators internals/Range/Negative manual step/Integer/Exact" time="{duration}"/>
|
||||
<testcase classname="<exe-name>.global" name="Generators internals/Range/Negative manual step/Integer/Slightly over end" time="{duration}"/>
|
||||
<testcase classname="<exe-name>.global" name="Generators internals/Range/Negative manual step/Integer/Slightly under end" time="{duration}"/>
|
||||
<testcase classname="<exe-name>.global" name="Greater-than inequalities with different epsilons" time="{duration}"/>
|
||||
<testcase classname="<exe-name>.global" name="INFO and WARN do not abort tests" time="{duration}"/>
|
||||
<testcase classname="<exe-name>.global" name="INFO gets logged on failure" time="{duration}">
|
||||
@@ -424,6 +455,7 @@ Matchers.tests.cpp:<line number>
|
||||
Exception.tests.cpp:<line number>
|
||||
</failure>
|
||||
</testcase>
|
||||
<testcase classname="<exe-name>.global" name="Nested generators and captured variables" time="{duration}"/>
|
||||
<testcase classname="<exe-name>.global" name="Nice descriptive name" time="{duration}"/>
|
||||
<testcase classname="<exe-name>.global" name="Non-std exceptions can be translated" time="{duration}">
|
||||
<error type="TEST_CASE">
|
||||
@@ -563,9 +595,9 @@ Message.tests.cpp:<line number>
|
||||
<testcase classname="<exe-name>.global" name="Process can be configured on command line/use-colour/yes" time="{duration}"/>
|
||||
<testcase classname="<exe-name>.global" name="Process can be configured on command line/use-colour/no" time="{duration}"/>
|
||||
<testcase classname="<exe-name>.global" name="Process can be configured on command line/use-colour/error" time="{duration}"/>
|
||||
<testcase classname="<exe-name>.global" name="Product with differing arities - 0" time="{duration}"/>
|
||||
<testcase classname="<exe-name>.global" name="Product with differing arities - 1" time="{duration}"/>
|
||||
<testcase classname="<exe-name>.global" name="Product with differing arities - 2" time="{duration}"/>
|
||||
<testcase classname="<exe-name>.global" name="Product with differing arities - std::tuple<int, double, float>" time="{duration}"/>
|
||||
<testcase classname="<exe-name>.global" name="Product with differing arities - std::tuple<int, double>" time="{duration}"/>
|
||||
<testcase classname="<exe-name>.global" name="Product with differing arities - std::tuple<int>" time="{duration}"/>
|
||||
<testcase classname="<exe-name>.global" name="Reconstruction should be based on stringification: #914" time="{duration}">
|
||||
<failure message="Hey, its truthy!" type="CHECK">
|
||||
Decomposition.tests.cpp:<line number>
|
||||
@@ -837,6 +869,12 @@ Misc.tests.cpp:<line number>
|
||||
<testcase classname="<exe-name>.global" name="just failure" time="{duration}">
|
||||
<failure type="FAIL">
|
||||
Previous info should not be seen
|
||||
Message.tests.cpp:<line number>
|
||||
</failure>
|
||||
</testcase>
|
||||
<testcase classname="<exe-name>.global" name="just failure after unscoped info" time="{duration}">
|
||||
<failure type="FAIL">
|
||||
previous unscoped info SHOULD not be seen
|
||||
Message.tests.cpp:<line number>
|
||||
</failure>
|
||||
</testcase>
|
||||
@@ -885,6 +923,7 @@ Testing if fib[7] (21) is even
|
||||
Misc.tests.cpp:<line number>
|
||||
</failure>
|
||||
</testcase>
|
||||
<testcase classname="<exe-name>.global" name="mix info, unscoped info and warning" time="{duration}"/>
|
||||
<testcase classname="<exe-name>.global" name="more nested SECTION tests/equal/doesn't equal" time="{duration}">
|
||||
<failure message="1 == 2" type="REQUIRE">
|
||||
Misc.tests.cpp:<line number>
|
||||
@@ -897,10 +936,30 @@ Misc.tests.cpp:<line number>
|
||||
<testcase classname="<exe-name>.global" name="non streamable - with conv. op" time="{duration}"/>
|
||||
<testcase classname="<exe-name>.global" name="non-copyable objects" time="{duration}"/>
|
||||
<testcase classname="<exe-name>.global" name="not allowed" time="{duration}"/>
|
||||
<testcase classname="<exe-name>.global" name="not prints unscoped info from previous failures" time="{duration}">
|
||||
<failure message="false" type="REQUIRE">
|
||||
this SHOULD be seen
|
||||
Message.tests.cpp:<line number>
|
||||
</failure>
|
||||
</testcase>
|
||||
<testcase classname="<exe-name>.global" name="null strings" time="{duration}"/>
|
||||
<testcase classname="<exe-name>.global" name="null_ptr" time="{duration}"/>
|
||||
<testcase classname="<exe-name>.global" name="pair<pair<int,const char *,pair<std::string,int> > -> toString" time="{duration}"/>
|
||||
<testcase classname="<exe-name>.global" name="pointer to class" time="{duration}"/>
|
||||
<testcase classname="<exe-name>.global" name="print unscoped info if passing unscoped info is printed" time="{duration}"/>
|
||||
<testcase classname="<exe-name>.global" name="prints unscoped info on failure" time="{duration}">
|
||||
<failure message="false" type="REQUIRE">
|
||||
this SHOULD be seen
|
||||
this SHOULD also be seen
|
||||
Message.tests.cpp:<line number>
|
||||
</failure>
|
||||
</testcase>
|
||||
<testcase classname="<exe-name>.global" name="prints unscoped info only for the first assertion" time="{duration}">
|
||||
<failure message="false" type="CHECK">
|
||||
this SHOULD be seen only ONCE
|
||||
Message.tests.cpp:<line number>
|
||||
</failure>
|
||||
</testcase>
|
||||
<testcase classname="<exe-name>.global" name="random SECTION tests/doesn't equal" time="{duration}"/>
|
||||
<testcase classname="<exe-name>.global" name="random SECTION tests/not equal" time="{duration}"/>
|
||||
<testcase classname="<exe-name>.global" name="replaceInPlace/replace single char" time="{duration}"/>
|
||||
@@ -920,6 +979,23 @@ Misc.tests.cpp:<line number>
|
||||
<failure message="false" type="REQUIRE">
|
||||
hi
|
||||
i := 7
|
||||
Message.tests.cpp:<line number>
|
||||
</failure>
|
||||
</testcase>
|
||||
<testcase classname="<exe-name>.global" name="shortened hide tags are split apart" time="{duration}"/>
|
||||
<testcase classname="<exe-name>.global" name="stacks unscoped info in loops" time="{duration}">
|
||||
<failure message="false" type="CHECK">
|
||||
Count 1 to 3...
|
||||
1
|
||||
2
|
||||
3
|
||||
Message.tests.cpp:<line number>
|
||||
</failure>
|
||||
<failure message="false" type="CHECK">
|
||||
Count 4 to 6...
|
||||
4
|
||||
5
|
||||
6
|
||||
Message.tests.cpp:<line number>
|
||||
</failure>
|
||||
</testcase>
|
||||
@@ -982,11 +1058,13 @@ Exception.tests.cpp:<line number>
|
||||
<testcase classname="<exe-name>.global" name="xmlentitycheck/embedded xml: <test>it should be possible to embed xml characters, such as <, " or &, or even whole <xml>documents</xml> within an attribute</test>" time="{duration}"/>
|
||||
<testcase classname="<exe-name>.global" name="xmlentitycheck/encoded chars: these should all be encoded: &&&"""<<<&"<<&"" time="{duration}"/>
|
||||
<system-out>
|
||||
This would not be caught previously
|
||||
A string sent directly to stdout
|
||||
Message from section one
|
||||
Message from section two
|
||||
</system-out>
|
||||
<system-err>
|
||||
Nor would this
|
||||
A string sent directly to stderr
|
||||
A string sent to stderr via clog
|
||||
</system-err>
|
||||
|
File diff suppressed because it is too large
Load Diff
@@ -68,7 +68,7 @@ TEST_CASE("Generators internals", "[generators][internals]") {
|
||||
REQUIRE_FALSE(gen.next());
|
||||
}
|
||||
}
|
||||
SECTION("Map") {
|
||||
SECTION("Map with explicit return type") {
|
||||
auto gen = map<double>([] (int i) {return 2.0 * i; }, values({ 1, 2, 3 }));
|
||||
REQUIRE(gen.get() == 2.0);
|
||||
REQUIRE(gen.next());
|
||||
@@ -77,6 +77,15 @@ TEST_CASE("Generators internals", "[generators][internals]") {
|
||||
REQUIRE(gen.get() == 6.0);
|
||||
REQUIRE_FALSE(gen.next());
|
||||
}
|
||||
SECTION("Map with deduced return type") {
|
||||
auto gen = map([] (int i) {return 2.0 * i; }, values({ 1, 2, 3 }));
|
||||
REQUIRE(gen.get() == 2.0);
|
||||
REQUIRE(gen.next());
|
||||
REQUIRE(gen.get() == 4.0);
|
||||
REQUIRE(gen.next());
|
||||
REQUIRE(gen.get() == 6.0);
|
||||
REQUIRE_FALSE(gen.next());
|
||||
}
|
||||
SECTION("Repeat") {
|
||||
SECTION("Singular repeat") {
|
||||
auto gen = repeat(1, value(3));
|
||||
@@ -99,5 +108,153 @@ TEST_CASE("Generators internals", "[generators][internals]") {
|
||||
REQUIRE_FALSE(gen.next());
|
||||
}
|
||||
}
|
||||
SECTION("Range") {
|
||||
SECTION("Positive auto step") {
|
||||
SECTION("Integer") {
|
||||
auto gen = range(-2, 2);
|
||||
REQUIRE(gen.get() == -2);
|
||||
REQUIRE(gen.next());
|
||||
REQUIRE(gen.get() == -1);
|
||||
REQUIRE(gen.next());
|
||||
REQUIRE(gen.get() == 0);
|
||||
REQUIRE(gen.next());
|
||||
REQUIRE(gen.get() == 1);
|
||||
REQUIRE_FALSE(gen.next());
|
||||
}
|
||||
}
|
||||
SECTION("Negative auto step") {
|
||||
SECTION("Integer") {
|
||||
auto gen = range(2, -2);
|
||||
REQUIRE(gen.get() == 2);
|
||||
REQUIRE(gen.next());
|
||||
REQUIRE(gen.get() == 1);
|
||||
REQUIRE(gen.next());
|
||||
REQUIRE(gen.get() == 0);
|
||||
REQUIRE(gen.next());
|
||||
REQUIRE(gen.get() == -1);
|
||||
REQUIRE_FALSE(gen.next());
|
||||
}
|
||||
}
|
||||
SECTION("Positive manual step") {
|
||||
SECTION("Integer") {
|
||||
SECTION("Exact") {
|
||||
auto gen = range(-7, 5, 3);
|
||||
REQUIRE(gen.get() == -7);
|
||||
REQUIRE(gen.next());
|
||||
REQUIRE(gen.get() == -4);
|
||||
REQUIRE(gen.next());
|
||||
REQUIRE(gen.get() == -1);
|
||||
REQUIRE(gen.next());
|
||||
REQUIRE(gen.get() == 2);
|
||||
REQUIRE_FALSE(gen.next());
|
||||
}
|
||||
SECTION("Slightly over end") {
|
||||
auto gen = range(-7, 4, 3);
|
||||
REQUIRE(gen.get() == -7);
|
||||
REQUIRE(gen.next());
|
||||
REQUIRE(gen.get() == -4);
|
||||
REQUIRE(gen.next());
|
||||
REQUIRE(gen.get() == -1);
|
||||
REQUIRE(gen.next());
|
||||
REQUIRE(gen.get() == 2);
|
||||
REQUIRE_FALSE(gen.next());
|
||||
}
|
||||
SECTION("Slightly under end") {
|
||||
auto gen = range(-7, 6, 3);
|
||||
REQUIRE(gen.get() == -7);
|
||||
REQUIRE(gen.next());
|
||||
REQUIRE(gen.get() == -4);
|
||||
REQUIRE(gen.next());
|
||||
REQUIRE(gen.get() == -1);
|
||||
REQUIRE(gen.next());
|
||||
REQUIRE(gen.get() == 2);
|
||||
REQUIRE(gen.next());
|
||||
REQUIRE(gen.get() == 5);
|
||||
REQUIRE_FALSE(gen.next());
|
||||
}
|
||||
}
|
||||
}
|
||||
SECTION("Negative manual step") {
|
||||
SECTION("Integer") {
|
||||
SECTION("Exact") {
|
||||
auto gen = range(5, -7, -3);
|
||||
REQUIRE(gen.get() == 5);
|
||||
REQUIRE(gen.next());
|
||||
REQUIRE(gen.get() == 2);
|
||||
REQUIRE(gen.next());
|
||||
REQUIRE(gen.get() == -1);
|
||||
REQUIRE(gen.next());
|
||||
REQUIRE(gen.get() == -4);
|
||||
REQUIRE_FALSE(gen.next());
|
||||
}
|
||||
SECTION("Slightly over end") {
|
||||
auto gen = range(5, -6, -3);
|
||||
REQUIRE(gen.get() == 5);
|
||||
REQUIRE(gen.next());
|
||||
REQUIRE(gen.get() == 2);
|
||||
REQUIRE(gen.next());
|
||||
REQUIRE(gen.get() == -1);
|
||||
REQUIRE(gen.next());
|
||||
REQUIRE(gen.get() == -4);
|
||||
REQUIRE_FALSE(gen.next());
|
||||
}
|
||||
SECTION("Slightly under end") {
|
||||
auto gen = range(5, -8, -3);
|
||||
REQUIRE(gen.get() == 5);
|
||||
REQUIRE(gen.next());
|
||||
REQUIRE(gen.get() == 2);
|
||||
REQUIRE(gen.next());
|
||||
REQUIRE(gen.get() == -1);
|
||||
REQUIRE(gen.next());
|
||||
REQUIRE(gen.get() == -4);
|
||||
REQUIRE(gen.next());
|
||||
REQUIRE(gen.get() == -7);
|
||||
REQUIRE_FALSE(gen.next());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
// todo: uncopyable type used in a generator
|
||||
// idea: uncopyable tag type for a stupid generator
|
||||
|
||||
namespace {
|
||||
struct non_copyable {
|
||||
non_copyable() = default;
|
||||
non_copyable(non_copyable const&) = delete;
|
||||
non_copyable& operator=(non_copyable const&) = delete;
|
||||
int value = -1;
|
||||
};
|
||||
|
||||
// This class shows how to implement a simple generator for Catch tests
|
||||
class TestGen : public Catch::Generators::IGenerator<int> {
|
||||
int current_number;
|
||||
public:
|
||||
|
||||
TestGen(non_copyable const& nc):
|
||||
current_number(nc.value) {}
|
||||
|
||||
int const& get() const override;
|
||||
bool next() override {
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
// Avoids -Wweak-vtables
|
||||
int const& TestGen::get() const {
|
||||
return current_number;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
TEST_CASE("GENERATE capture macros", "[generators][internals][.approvals]") {
|
||||
auto value = GENERATE(take(10, random(0, 10)));
|
||||
|
||||
non_copyable nc; nc.value = value;
|
||||
// neither `GENERATE_COPY` nor plain `GENERATE` would compile here
|
||||
auto value2 = GENERATE_REF(Catch::Generators::GeneratorWrapper<int>(std::unique_ptr<Catch::Generators::IGenerator<int>>(new TestGen(nc))));
|
||||
REQUIRE(value == value2);
|
||||
}
|
||||
|
@@ -40,3 +40,8 @@ TEST_CASE( "Tag alias can be registered against tag patterns" ) {
|
||||
CHECK_THROWS( registry.add( "[@no square bracket at end", "", Catch::SourceLineInfo( "file", 3 ) ) );
|
||||
}
|
||||
}
|
||||
|
||||
TEST_CASE("shortened hide tags are split apart") {
|
||||
auto testcase = Catch::makeTestCase(nullptr, "", {"fake test name", "[.magic-tag]"}, CATCH_INTERNAL_LINEINFO);
|
||||
REQUIRE_THAT(testcase.tags, Catch::VectorContains(std::string("magic-tag")) && Catch::VectorContains(std::string(".")));
|
||||
}
|
@@ -17,6 +17,11 @@ namespace foo {
|
||||
};
|
||||
}
|
||||
|
||||
namespace bar {
|
||||
template <typename... Ts>
|
||||
struct TypeList {};
|
||||
}
|
||||
|
||||
#ifdef __GNUC__
|
||||
#pragma GCC diagnostic ignored "-Wmissing-declarations"
|
||||
#endif
|
||||
@@ -184,6 +189,11 @@ namespace { namespace CompilationTests {
|
||||
STATIC_REQUIRE_FALSE( std::is_void<int>::value );
|
||||
}
|
||||
|
||||
TEST_CASE("#1548", "[compilation]") {
|
||||
using namespace bar;
|
||||
REQUIRE(std::is_same<TypeList<int>, TypeList<int>>::value);
|
||||
}
|
||||
|
||||
}} // namespace CompilationTests
|
||||
|
||||
|
||||
|
@@ -114,13 +114,19 @@ SCENARIO("Eating cucumbers", "[generators][approvals]") {
|
||||
#endif
|
||||
|
||||
// There are also some generic generator manipulators
|
||||
TEST_CASE("Generators -- adapters", "[generators]") {
|
||||
TEST_CASE("Generators -- adapters", "[generators][generic]") {
|
||||
// TODO: This won't work yet, introduce GENERATE_VAR?
|
||||
//auto numbers = Catch::Generators::values({ 1, 2, 3, 4, 5, 6 });
|
||||
SECTION("Filtering by predicate") {
|
||||
// This filters out all odd (false) numbers, giving [2, 4, 6]
|
||||
auto i = GENERATE(filter([] (int val) { return val % 2 == 0; }, values({ 1, 2, 3, 4, 5, 6 })));
|
||||
REQUIRE(i % 2 == 0);
|
||||
SECTION("Basic usage") {
|
||||
// This filters out all odd (false) numbers, giving [2, 4, 6]
|
||||
auto i = GENERATE(filter([] (int val) { return val % 2 == 0; }, values({ 1, 2, 3, 4, 5, 6 })));
|
||||
REQUIRE(i % 2 == 0);
|
||||
}
|
||||
SECTION("Throws if there are no matching values") {
|
||||
using namespace Catch::Generators;
|
||||
REQUIRE_THROWS_AS(filter([] (int) {return false; }, value(1)), Catch::GeneratorException);
|
||||
}
|
||||
}
|
||||
SECTION("Shortening a range") {
|
||||
// This takes the first 3 elements from the values, giving back [1, 2, 3]
|
||||
@@ -138,10 +144,65 @@ TEST_CASE("Generators -- adapters", "[generators]") {
|
||||
auto i = GENERATE(map<std::string>([] (int val) { return std::to_string(val); }, values({ 1, 2, 3 })));
|
||||
REQUIRE(i.size() == 1);
|
||||
}
|
||||
SECTION("Different deduced type") {
|
||||
// This takes a generator that returns ints and maps them into strings
|
||||
auto i = GENERATE(map([] (int val) { return std::to_string(val); }, values({ 1, 2, 3 })));
|
||||
REQUIRE(i.size() == 1);
|
||||
}
|
||||
}
|
||||
SECTION("Repeating a generator") {
|
||||
// This will return values [1, 2, 3, 1, 2, 3]
|
||||
auto j = GENERATE(repeat(2, values({ 1, 2, 3 })));
|
||||
REQUIRE(j > 0);
|
||||
}
|
||||
SECTION("Chunking a generator into sized pieces") {
|
||||
SECTION("Number of elements in source is divisible by chunk size") {
|
||||
auto chunk2 = GENERATE(chunk(2, values({ 1, 1, 2, 2, 3, 3 })));
|
||||
REQUIRE(chunk2.size() == 2);
|
||||
REQUIRE(chunk2.front() == chunk2.back());
|
||||
}
|
||||
SECTION("Number of elements in source is not divisible by chunk size") {
|
||||
auto chunk2 = GENERATE(chunk(2, values({ 1, 1, 2, 2, 3 })));
|
||||
REQUIRE(chunk2.size() == 2);
|
||||
REQUIRE(chunk2.front() == chunk2.back());
|
||||
REQUIRE(chunk2.front() < 3);
|
||||
}
|
||||
SECTION("Throws on too small generators") {
|
||||
using namespace Catch::Generators;
|
||||
REQUIRE_THROWS_AS(chunk(2, value(1)), Catch::GeneratorException);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Note that because of the non-reproducibility of distributions,
|
||||
// anything involving the random generators cannot be part of approvals
|
||||
TEST_CASE("Random generator", "[generators][.][approvals]") {
|
||||
SECTION("Infer int from integral arguments") {
|
||||
auto val = GENERATE(take(4, random(0, 1)));
|
||||
STATIC_REQUIRE(std::is_same<decltype(val), int>::value);
|
||||
static_cast<void>(val); // Silence VS 2015 unused variable warning
|
||||
}
|
||||
SECTION("Infer double from double arguments") {
|
||||
auto val = GENERATE(take(4, random(0., 1.)));
|
||||
STATIC_REQUIRE(std::is_same<decltype(val), double>::value);
|
||||
static_cast<void>(val); // Silence VS 2015 unused variable warning
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
TEST_CASE("Nested generators and captured variables", "[generators]") {
|
||||
// Workaround for old libstdc++
|
||||
using record = std::tuple<int, int>;
|
||||
// Set up 3 ranges to generate numbers from
|
||||
auto extent = GENERATE(table<int, int>({
|
||||
record{3, 7},
|
||||
record{-5, -3},
|
||||
record{90, 100}
|
||||
}));
|
||||
|
||||
auto from = std::get<0>(extent);
|
||||
auto to = std::get<1>(extent);
|
||||
|
||||
auto values = GENERATE_COPY(range(from, to));
|
||||
REQUIRE(values > -6);
|
||||
}
|
||||
|
@@ -132,6 +132,71 @@ TEST_CASE( "Pointers can be converted to strings", "[messages][.][approvals]" )
|
||||
WARN( "toString(p): " << ::Catch::Detail::stringify( &p ) );
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
static void unscoped_info( T msg ) {
|
||||
UNSCOPED_INFO( msg );
|
||||
}
|
||||
|
||||
TEST_CASE( "just unscoped info", "[unscoped][info]" ) {
|
||||
unscoped_info( "this should NOT be seen" );
|
||||
unscoped_info( "this also should NOT be seen" );
|
||||
}
|
||||
|
||||
TEST_CASE( "just failure after unscoped info", "[failing][.][unscoped][info]" ) {
|
||||
FAIL( "previous unscoped info SHOULD not be seen" );
|
||||
}
|
||||
|
||||
TEST_CASE( "print unscoped info if passing unscoped info is printed", "[unscoped][info]" ) {
|
||||
unscoped_info( "this MAY be seen IF info is printed for passing assertions" );
|
||||
REQUIRE( true );
|
||||
}
|
||||
|
||||
TEST_CASE( "prints unscoped info on failure", "[failing][.][unscoped][info]" ) {
|
||||
unscoped_info( "this SHOULD be seen" );
|
||||
unscoped_info( "this SHOULD also be seen" );
|
||||
REQUIRE( false );
|
||||
unscoped_info( "but this should NOT be seen" );
|
||||
}
|
||||
|
||||
TEST_CASE( "not prints unscoped info from previous failures", "[failing][.][unscoped][info]" ) {
|
||||
unscoped_info( "this MAY be seen only for the FIRST assertion IF info is printed for passing assertions" );
|
||||
REQUIRE( true );
|
||||
unscoped_info( "this MAY be seen only for the SECOND assertion IF info is printed for passing assertions" );
|
||||
REQUIRE( true );
|
||||
unscoped_info( "this SHOULD be seen" );
|
||||
REQUIRE( false );
|
||||
}
|
||||
|
||||
TEST_CASE( "prints unscoped info only for the first assertion", "[failing][.][unscoped][info]" ) {
|
||||
unscoped_info( "this SHOULD be seen only ONCE" );
|
||||
CHECK( false );
|
||||
CHECK( true );
|
||||
unscoped_info( "this MAY also be seen only ONCE IF info is printed for passing assertions" );
|
||||
CHECK( true );
|
||||
CHECK( true );
|
||||
}
|
||||
|
||||
TEST_CASE( "stacks unscoped info in loops", "[failing][.][unscoped][info]" ) {
|
||||
UNSCOPED_INFO("Count 1 to 3...");
|
||||
for (int i = 1; i <= 3; i++) {
|
||||
unscoped_info(i);
|
||||
}
|
||||
CHECK( false );
|
||||
|
||||
UNSCOPED_INFO("Count 4 to 6...");
|
||||
for (int i = 4; i <= 6; i++) {
|
||||
unscoped_info(i);
|
||||
}
|
||||
CHECK( false );
|
||||
}
|
||||
|
||||
TEST_CASE( "mix info, unscoped info and warning", "[unscoped][info]" ) {
|
||||
INFO("info");
|
||||
unscoped_info("unscoped info");
|
||||
WARN("and warn may mix");
|
||||
WARN("they are not cleared after warnings");
|
||||
}
|
||||
|
||||
TEST_CASE( "CAPTURE can deal with complex expressions", "[messages][capture]" ) {
|
||||
int a = 1;
|
||||
int b = 2;
|
||||
|
@@ -19,6 +19,7 @@
|
||||
|
||||
#include <stdio.h>
|
||||
#include <sstream>
|
||||
#include <iostream>
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
TEST_CASE
|
||||
@@ -426,3 +427,10 @@ TEST_CASE( "Bitfields can be captured (#1027)" ) {
|
||||
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;
|
||||
// FAIL aborts the test by throwing a Catch exception
|
||||
FAIL("1514");
|
||||
}
|
||||
|
@@ -6,8 +6,13 @@ import subprocess
|
||||
catchPath = os.path.dirname(os.path.realpath( os.path.dirname(sys.argv[0])))
|
||||
|
||||
def getBuildExecutable():
|
||||
dir = os.environ.get('CATCH_DEV_OUT_DIR', "cmake-build-debug/projects/SelfTest")
|
||||
return dir
|
||||
if os.name == 'nt':
|
||||
dir = os.environ.get('CATCH_DEV_OUT_DIR', "cmake-build-debug/projects/SelfTest.exe")
|
||||
return dir
|
||||
else:
|
||||
dir = os.environ.get('CATCH_DEV_OUT_DIR', "cmake-build-debug/projects/SelfTest")
|
||||
return dir
|
||||
|
||||
|
||||
def runAndCapture( args ):
|
||||
child = subprocess.Popen(" ".join( args ), shell=True, stdout=subprocess.PIPE)
|
||||
|
File diff suppressed because it is too large
Load Diff
@@ -42,9 +42,9 @@ namespace Catch {
|
||||
bool assertionEnded( AssertionStats const& _assertionStats ) override {
|
||||
++counter;
|
||||
|
||||
stream << "# " << currentTestCaseInfo->name << std::endl;
|
||||
AssertionPrinter printer( stream, _assertionStats, counter );
|
||||
printer.print();
|
||||
stream << " # " << currentTestCaseInfo->name ;
|
||||
|
||||
stream << std::endl;
|
||||
return true;
|
||||
|
Reference in New Issue
Block a user