Compare commits

..

52 Commits

Author SHA1 Message Date
Martin Hořeňovský
b9dd1936e5 v2.7.1 2019-04-08 13:38:00 +02:00
Martin Hořeňovský
293d617c49 Merge pull request #1592 from robinlinden/fix-cmake-integration-typo
Use correct filename in CMake integration docs
2019-04-08 13:20:41 +02:00
Robin Lindén
7be35af167 Use correct filename in CMake integration docs 2019-04-07 15:41:34 +02:00
Martin Hořeňovský
08147a23f9 Fix ObjC matchers
Closes #1571
2019-04-03 20:32:11 +02:00
Ziv Shahaf
8af8704089 support for printing test filters (PR #1585) 2019-04-03 20:24:52 +02:00
Martin Hořeňovský
3816e99d0c Add GENERATE_COPY and GENERATE_VAR capturing generator macros 2019-03-31 14:11:10 +02:00
Martin Hořeňovský
b77cec05c0 Fix test tag parsing to split [.foo] into [.][foo] 2019-03-29 10:48:56 +01:00
Omer Ozarslan
54089c4c8c Deducing return type of map generator helper (#1576)
* Deduce map return type implicitly

Giving the first template argument to map generator function to deduce
return type is now optional even if the return type is different from
the type generated by mapped generator.
2019-03-24 15:44:22 +01:00
Martin Hořeňovský
296d447452 Merge pull request #1575 from alabuzhev/warning_ntstatus
Suppress warning caused by ntstatus.h inclusion
2019-03-20 15:22:27 +01:00
Alex Alabuzhev
0531965349 Suppress warning caused by ntstatus.h inclusion 2019-03-19 23:57:56 +00:00
Tadeusz Puźniakowski
a1cdff4f18 raspigcd - opensource-users
Added raspigcd that uses Catch2 for tests
2019-03-19 20:35:59 +01:00
Steve Hollasch
4611125801 generators.md: fix extraneous back tick in doc 2019-03-14 09:14:02 +01:00
Clare Macrae
e509012e64 Update blog URL and fic typos in tutorial.md 2019-03-09 18:02:29 +01:00
Clare Macrae
448825db03 Readability improvements for assertions.md 2019-03-09 18:02:29 +01:00
Clare Macrae
0fff8e7791 Add ApprovalTests.cpp to list of open source users 2019-03-09 18:02:29 +01:00
Martin Hořeňovský
68a3c129ac Merge pull request #1562 from claremacrae/patch-2
Update url of blog post
2019-03-09 17:35:08 +01:00
Martin Hořeňovský
1ce5ec9b74 Merge pull request #1565 from inobelar/patch-1
Added override keyword near IntRange::describe() method
2019-03-09 17:33:42 +01:00
Yurii Nakonechnyi
37a4e32319 Added override keyword near IntRange::describe() method 2019-03-09 15:05:27 +02:00
Clare Macrae
0424c9a62c Update url of blog post 2019-03-08 08:56:00 +00:00
Martin Hořeňovský
d633072794 v2.7.0 2019-03-07 21:44:57 +01:00
Martin Hořeňovský
51ed08be22 Take changes to Clara from master 2019-03-07 20:48:36 +01:00
Omer Ozarslan
1701325caa Document unscoped info 2019-03-06 22:04:35 +01:00
Omer Ozarslan
7aee973a4a Add tests for unscoped info
Update approval tests as new tests are added for messaging.
2019-03-06 22:04:35 +01:00
Omer Ozarslan
99575b45db Add unscoped info functionality
This adds UNSCOPED_INFO macro, creating a log message that is stored
until the end of next assertion or the end of test case, whichever comes
first. These messages are not scoped locally, unlike messages created by
INFO macro.
2019-03-06 22:04:35 +01:00
Martin Hořeňovský
1a03918455 Force flush streams in tests for #1514
This avoids the problem where writes to stderr/stdout stop being
line-buffered when stderr/stdout is redirected to a file, which led
to different order of outputs between Linux and Windows in our tests.
2019-03-06 21:53:26 +01:00
Martin Hořeňovský
bd667f4d69 Add comma-escaping in test specs to ParseAndAddCatchTests.cmake
Fixes #1527
2019-03-03 13:11:11 +01:00
Martin Hořeňovský
28db5ed4c9 Add tests for #1514
If the regression comes back, it will only be caught by approvals,
but that's better than nothing.
2019-03-02 21:22:47 +01:00
SimonChh
7d2451f119 Fix output redirection in failing tests (#1525)
Fixes #1514
2019-03-02 21:18:48 +01:00
Martin Hořeňovský
5bf6e47381 Add another example for generators 2019-02-26 12:52:21 +01:00
Martin Hořeňovský
29b3b7ae6b Namespace our type traits in catch_meta
Previously they could conflict with user-defined type traits that
were in the global namespace.

Fixes #1548
2019-02-23 21:06:20 +01:00
Martin Hořeňovský
ef5fd8d42f Add another test for FilterGenerator 2019-02-23 20:37:35 +01:00
Martin Hořeňovský
693647c43f Add ChunkGenerator
This generator collects values from the underlying generator until it
has a specified amount of them, and then returns them in one "chunk".
In case the underlying generator does not have enough elements for
a specific chunk, the left-over elements are discarded.

Closes #1538
2019-02-23 20:28:58 +01:00
Martin Hořeňovský
288387fa10 Cleanup: move things around 2019-02-23 17:16:28 +01:00
Rick de Water
165de9b072 Add RangeGenerator 2019-02-23 16:58:34 +01:00
hbina4326
bf4771a7ed Script helper getBuildExecutable now works properly on Windows 2019-02-23 14:44:40 +01:00
Martin Hořeňovský
7012a31a39 Fix VS2015 warning issue 2019-02-20 10:14:46 +01:00
Martin Hořeňovský
269303d9d9 Introduce random number (Integral and Float) generators 2019-02-20 00:09:15 +01:00
Khem Raj
e8bfd882e8 Fix -Wdefaulted-function-deleted warning
Clang8 warns

catch_interfaces_reporter.h:84:25: error: explicitly defaulted move assignment operator is implicitly deleted [-Werror,-Wdefaulted-function-deleted]
|         AssertionStats& operator = ( AssertionStats && )     = default;
|                         ^

Signed-off-by: Khem Raj <raj.khem@gmail.com>
2019-02-18 20:42:42 +01:00
Paul Lesur
2bd0722470 fix "code will never be executed" under clang 2019-02-18 19:01:43 +01:00
Igor Akhmetov
45ebf17ec7 Do not open the output file twice
7f229b4f caused the output file to get opened twice, while
some types of files (e.g. named pipes) can be only opened once.

After this change Session::applyCommandLine opens the output file
only when there is an error to print.
2019-02-18 18:59:54 +01:00
Martin Hořeňovský
093b72416d Remove non-ASCII characters from the distributable parts
Closes #1542
2019-02-18 10:33:41 +01:00
Tobias Ribizel
c99a346490 Use correct type name instead of index for TEMPLATE_PRODUCT_TEST_CASE (#1544)
Previously, for a TEMPLATE_PRODUCT_TEST_CASE("Test" ..., T, (P1, P2)),
the generated test case names were

  Test - 0
  Test - 1

With this commit, the correct typename is used:

  Test - T<P1>
  Test - T<P2>

-----------

MSVC needs another indirection to evaluate INTERNAL_CATCH_STRINGIZE
and also inserts a space before theINTERNAL_CATCH_STRINGIZE_WITHOUT_PARENS
parameter, which we can get rid of by pointer arithmetic.
2019-02-17 21:52:22 +01:00
Martin Hořeňovský
359a54b6bd Merge pull request #1539 from mattclarke/patch-1
Docs: missing hyphens and full-stops added
2019-02-17 21:24:42 +01:00
Girts Folkmanis
711d750ca7 use "std" namespace for "sprintf"
Some compilers don't export C compatibility functions in `::`. Using
`std::sprintf` should work for those (and all other compilers).

Reference: https://en.cppreference.com/w/cpp/header#C_compatibility_headers
2019-02-17 21:02:21 +01:00
Matt Clarke
95f7712808 Missing hyphens and full-stops added
The use of full-stops is inconsistent, so I have added them where there are none.
The other option was to remove them instead.
2019-02-13 10:13:14 +01:00
Martin Hořeňovský
dbbab8727c v2.6.1 2019-02-12 19:58:12 +01:00
Martin Hořeňovský
5d4061af12 Update release process docs to include PGP-signing 2019-02-12 19:33:08 +01:00
Darren Gilroy
9ccea82d7f Catch: resolve inconsistency in CATCH_REQUIRE_THROWS
The REQUIRE_THROWS and CATCH_REQUIRE_THROWS macros have
a subtle inconsistency in their implementation which can
cause a warning if [-Wunused-value] is used.

This commit changes CATCH_REQUIRE_THROWS so it has the
same implementation as REQUIRE_THROWS

It looks like REQUIRE_THROWS was change in commit
fae0fa4ec but not CATCH_REQUIRE_THROWS.

Similar changes for CATCH_CHECK_THROWS
2019-02-09 17:42:53 +01:00
Berkus Karchebnyy
dd3d27de57 Fix TAP protocol reporter
According to TAP protocol version 13, the comments after the test name
only may contain Directives - # TODO or # SKIP. We should put
the comment (aka suite name) on a separate line before the test.

See http://testanything.org/tap-version-13-specification.html#directives
2019-02-08 10:48:32 +01:00
Jozef Grajciar
7f229b4ff1 fix SEGFAULTs
issue was that mutable context had no config thus trying to get stream
caused SEGFAULT

Closes #1533, #1534
2019-02-08 10:41:23 +01:00
Jozef Grajciar
c03b23c84b Added Makimo to list of commercial users
Closes #1528
2019-02-04 20:04:48 +01:00
Nathaniel Dosé
17686ba571 junit reporter reports random seed (--rng-seed)
Fixes #1520
2019-02-01 10:34:20 +01:00
67 changed files with 4400 additions and 703 deletions

View File

@@ -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")

View File

@@ -5,17 +5,17 @@
[![Build Status](https://travis-ci.org/catchorg/Catch2.svg?branch=master)](https://travis-ci.org/catchorg/Catch2)
[![Build status](https://ci.appveyor.com/api/projects/status/github/catchorg/Catch2?svg=true)](https://ci.appveyor.com/project/catchorg/catch2)
[![codecov](https://codecov.io/gh/catchorg/Catch2/branch/master/graph/badge.svg)](https://codecov.io/gh/catchorg/Catch2)
[![Try online](https://img.shields.io/badge/try-online-blue.svg)](https://wandbox.org/permlink/85qcYBOdUKzlnpl5)
[![Try online](https://img.shields.io/badge/try-online-blue.svg)](https://wandbox.org/permlink/ZFBZ5XbLA9F1gzKi)
[![Join the chat in Discord: https://discord.gg/4CWS9zD](https://img.shields.io/badge/Discord-Chat!-brightgreen.svg)](https://discord.gg/4CWS9zD)
<a href="https://github.com/catchorg/Catch2/releases/download/v2.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?

View File

@@ -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

View File

@@ -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;

View File

@@ -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

View File

@@ -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/)

View File

@@ -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);
}
```

View File

@@ -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

View File

@@ -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.

View File

@@ -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();

View File

@@ -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.
---

View File

@@ -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.**

View File

@@ -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._

View File

@@ -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" ) {

View 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

View File

@@ -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);
}

View 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

View File

@@ -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:

View File

@@ -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__ )

View File

@@ -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")

View File

@@ -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, ... ) \

View File

@@ -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;

View File

@@ -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) {

View File

@@ -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

View 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

View 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

View File

@@ -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

View File

@@ -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;

View File

@@ -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;

View File

@@ -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;
}

View File

@@ -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

View File

@@ -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);
}
}

View File

@@ -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 {

View File

@@ -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

View File

@@ -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];
}

View File

@@ -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)

View File

@@ -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)

View File

@@ -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))

View File

@@ -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);

View File

@@ -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;

View File

@@ -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 );

View File

@@ -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;

View File

@@ -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;\

View File

@@ -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;
}

View File

@@ -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) {}

View File

@@ -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;
}

View File

@@ -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

View File

@@ -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;

View File

@@ -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 ) {

View File

@@ -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;

View File

@@ -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() );

View File

@@ -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

View File

@@ -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.

View File

@@ -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

View File

@@ -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

View File

@@ -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&lt;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&lt;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&lt;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&lt;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&lt;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&lt;float>" time="{duration}"/>
<testcase classname="<exe-name>.Template_Fixture_2" name="A TEMPLATE_PRODUCT_TEST_CASE_METHOD based test run that succeeds - Template_Foo&lt;int>" time="{duration}"/>
<testcase classname="<exe-name>.Template_Fixture_2" name="A TEMPLATE_PRODUCT_TEST_CASE_METHOD based test run that succeeds - std::vector&lt;float>" time="{duration}"/>
<testcase classname="<exe-name>.Template_Fixture_2" name="A TEMPLATE_PRODUCT_TEST_CASE_METHOD based test run that succeeds - std::vector&lt;int>" time="{duration}"/>
<testcase classname="<exe-name>.Template_Fixture" 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&lt;float>" time="{duration}"/>
<testcase classname="<exe-name>.global" name="A Template product test case - Foo&lt;int>" time="{duration}"/>
<testcase classname="<exe-name>.global" name="A Template product test case - std::vector&lt;float>" time="{duration}"/>
<testcase classname="<exe-name>.global" name="A Template product test case - std::vector&lt;int>" time="{duration}"/>
<testcase classname="<exe-name>.global" name="A 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&lt;int, double, float>" time="{duration}"/>
<testcase classname="<exe-name>.global" name="Product with differing arities - std::tuple&lt;int, double>" time="{duration}"/>
<testcase classname="<exe-name>.global" name="Product with differing arities - std::tuple&lt;int>" time="{duration}"/>
<testcase classname="<exe-name>.global" name="Reconstruction should be based on stringification: #914" time="{duration}">
<failure message="Hey, its truthy!" type="CHECK">
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&lt;pair&lt;int,const char *,pair&lt;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: &lt;test>it should be possible to embed xml characters, such as &lt;, &quot; or &amp;, or even whole &lt;xml>documents&lt;/xml> within an attribute&lt;/test>" time="{duration}"/>
<testcase classname="<exe-name>.global" name="xmlentitycheck/encoded chars: these should all be encoded: &amp;&amp;&amp;&quot;&quot;&quot;&lt;&lt;&lt;&amp;&quot;&lt;&lt;&amp;&quot;" 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

View File

@@ -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);
}

View File

@@ -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(".")));
}

View File

@@ -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

View File

@@ -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);
}

View File

@@ -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;

View File

@@ -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");
}

View File

@@ -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

View File

@@ -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;