mirror of
https://github.com/catchorg/Catch2.git
synced 2025-09-16 02:05:38 +02:00
Compare commits
86 Commits
Author | SHA1 | Date | |
---|---|---|---|
![]() |
d633072794 | ||
![]() |
51ed08be22 | ||
![]() |
1701325caa | ||
![]() |
7aee973a4a | ||
![]() |
99575b45db | ||
![]() |
1a03918455 | ||
![]() |
bd667f4d69 | ||
![]() |
28db5ed4c9 | ||
![]() |
7d2451f119 | ||
![]() |
5bf6e47381 | ||
![]() |
29b3b7ae6b | ||
![]() |
ef5fd8d42f | ||
![]() |
693647c43f | ||
![]() |
288387fa10 | ||
![]() |
165de9b072 | ||
![]() |
bf4771a7ed | ||
![]() |
7012a31a39 | ||
![]() |
269303d9d9 | ||
![]() |
e8bfd882e8 | ||
![]() |
2bd0722470 | ||
![]() |
45ebf17ec7 | ||
![]() |
093b72416d | ||
![]() |
c99a346490 | ||
![]() |
359a54b6bd | ||
![]() |
711d750ca7 | ||
![]() |
95f7712808 | ||
![]() |
dbbab8727c | ||
![]() |
5d4061af12 | ||
![]() |
9ccea82d7f | ||
![]() |
dd3d27de57 | ||
![]() |
7f229b4ff1 | ||
![]() |
c03b23c84b | ||
![]() |
17686ba571 | ||
![]() |
d75e9b3c0f | ||
![]() |
67308bb606 | ||
![]() |
16dc219704 | ||
![]() |
63d1a96908 | ||
![]() |
061f1f836a | ||
![]() |
5929d9530c | ||
![]() |
e46a70f829 | ||
![]() |
64a9c02315 | ||
![]() |
61f4c7ab85 | ||
![]() |
50fefd059a | ||
![]() |
a2baabbf71 | ||
![]() |
6f9cdd6583 | ||
![]() |
d9e99dc2ca | ||
![]() |
804a2118c2 | ||
![]() |
aa1e470058 | ||
![]() |
8d5d54e529 | ||
![]() |
73d533ff5c | ||
![]() |
899c5ed3df | ||
![]() |
084b1d5fe6 | ||
![]() |
4109870435 | ||
![]() |
2988e9f6cf | ||
![]() |
bc02ada4b0 | ||
![]() |
61e1ea9185 | ||
![]() |
b275ead8c3 | ||
![]() |
b0381e42b2 | ||
![]() |
8989c9b560 | ||
![]() |
d084162b2f | ||
![]() |
0387fb64ce | ||
![]() |
75200b462c | ||
![]() |
17e09be3b9 | ||
![]() |
1c99b0ff81 | ||
![]() |
64a0f466ec | ||
![]() |
47602ac556 | ||
![]() |
d1e7344f16 | ||
![]() |
3ed5441067 | ||
![]() |
bdee512057 | ||
![]() |
188b3e6511 | ||
![]() |
bbf70ca74b | ||
![]() |
23f023f9ed | ||
![]() |
c1720d0c42 | ||
![]() |
d54c2258e0 | ||
![]() |
b3faceede2 | ||
![]() |
e7fce90b49 | ||
![]() |
799c7a2eed | ||
![]() |
9bc15939a5 | ||
![]() |
461843b1f0 | ||
![]() |
5b4ffd3c93 | ||
![]() |
21a1cd5683 | ||
![]() |
4902cd7215 | ||
![]() |
18ff34788c | ||
![]() |
d0de666362 | ||
![]() |
862955d657 | ||
![]() |
557e47c3ca |
@@ -31,7 +31,7 @@ class BuilderSettings(object):
|
||||
not match the stable pattern. Otherwise it will upload to stable
|
||||
channel.
|
||||
"""
|
||||
return os.getenv("CONAN_UPLOAD", "https://api.bintray.com/conan/horenmar/Catch2")
|
||||
return os.getenv("CONAN_UPLOAD", "https://api.bintray.com/conan/catchorg/Catch2")
|
||||
|
||||
@property
|
||||
def upload_only_when_stable(self):
|
||||
@@ -49,7 +49,7 @@ class BuilderSettings(object):
|
||||
def reference(self):
|
||||
""" Read project version from branch create Conan referece
|
||||
"""
|
||||
return os.getenv("CONAN_REFERENCE", "Catch2/{}@{}/{}".format(self._version, self.username, self.channel))
|
||||
return os.getenv("CONAN_REFERENCE", "Catch2/{}".format(self._version))
|
||||
|
||||
@property
|
||||
def channel(self):
|
||||
|
29
.github/ISSUE_TEMPLATE/bug_report.md
vendored
Normal file
29
.github/ISSUE_TEMPLATE/bug_report.md
vendored
Normal file
@@ -0,0 +1,29 @@
|
||||
---
|
||||
name: Bug report
|
||||
about: Create an issue that documents a bug
|
||||
title: ''
|
||||
labels: ''
|
||||
assignees: ''
|
||||
|
||||
---
|
||||
|
||||
**Describe the bug**
|
||||
A clear and concise description of what the bug is.
|
||||
|
||||
**Expected behavior**
|
||||
A clear and concise description of what you expected to happen.
|
||||
|
||||
**Reproduction steps**
|
||||
Steps to reproduce the bug.
|
||||
<!-- Usually this means a small and self-contained piece of code that uses Catch and specifying compiler flags if relevant. -->
|
||||
|
||||
|
||||
**Platform information:**
|
||||
<!-- Fill in any extra information that might be important for your issue. -->
|
||||
- OS: **Windows NT**
|
||||
- Compiler+version: **GCC v2.9.5**
|
||||
- Catch version: **v1.2.3**
|
||||
|
||||
|
||||
**Additional context**
|
||||
Add any other context about the problem here.
|
14
.github/ISSUE_TEMPLATE/feature_request.md
vendored
Normal file
14
.github/ISSUE_TEMPLATE/feature_request.md
vendored
Normal file
@@ -0,0 +1,14 @@
|
||||
---
|
||||
name: Feature request
|
||||
about: Create an issue that requests a feature or other improvement
|
||||
title: ''
|
||||
labels: ''
|
||||
assignees: ''
|
||||
|
||||
---
|
||||
|
||||
**Description**
|
||||
Describe the feature/change you request and why do you want it.
|
||||
|
||||
**Additional context**
|
||||
Add any other context or screenshots about the feature request here.
|
29
.github/issue_template.md
vendored
29
.github/issue_template.md
vendored
@@ -1,29 +0,0 @@
|
||||
## Description
|
||||
<!--
|
||||
If your issue is a bugreport, this means describing what you did,
|
||||
what did you want to happen and what actually did happen.
|
||||
|
||||
If your issue is a feature request, describe the feature and why do you
|
||||
want it.
|
||||
-->
|
||||
|
||||
|
||||
### Steps to reproduce
|
||||
<!--
|
||||
This is only relevant for bug reports, but if you do have one,
|
||||
please provide a minimal set of steps to reproduce the problem.
|
||||
|
||||
Usually this means providing a small and self-contained code using Catch
|
||||
and specifying compiler flags/tools used if relevant.
|
||||
-->
|
||||
|
||||
|
||||
### Extra information
|
||||
<!--
|
||||
Fill in any extra information that might be important for your issue.
|
||||
|
||||
If your issue is a bugreport, definitely fill out at least the following.
|
||||
-->
|
||||
* Catch version: **v42.42.42**
|
||||
* Operating System: **Joe's discount operating system**
|
||||
* Compiler+version: **Hidden Dragon v1.2.3**
|
@@ -1,5 +1,4 @@
|
||||
language: cpp
|
||||
sudo: false
|
||||
|
||||
branches:
|
||||
except:
|
||||
@@ -277,7 +276,7 @@ matrix:
|
||||
- "3.7"
|
||||
dist: xenial
|
||||
install:
|
||||
- pip install conan conan-package-tools
|
||||
- pip install conan==1.10.2 conan-package-tools
|
||||
env:
|
||||
- CONAN_GCC_VERSIONS=8
|
||||
- CONAN_DOCKER_IMAGE=conanio/gcc8
|
||||
@@ -305,7 +304,7 @@ before_script:
|
||||
# Use Debug builds for running Valgrind and building examples
|
||||
- cmake -H. -BBuild-Debug -DCMAKE_BUILD_TYPE=Debug -Wdev -DUSE_CPP14=${CPP14} -DUSE_CPP17=${CPP17} -DCATCH_USE_VALGRIND=${VALGRIND} -DCATCH_BUILD_EXAMPLES=${EXAMPLES} -DCATCH_ENABLE_COVERAGE=${COVERAGE} -DCATCH_BUILD_EXTRA_TESTS=${EXTRAS}
|
||||
# Don't bother with release build for coverage build
|
||||
- cmake -H. -BBuild-Release -DCMAKE_BUILD_TYPE=Release -Wdev -DUSE_CPP14=${CPP14}
|
||||
- cmake -H. -BBuild-Release -DCMAKE_BUILD_TYPE=Release -Wdev -DUSE_CPP14=${CPP14} -DUSE_CPP17=${CPP17}
|
||||
|
||||
|
||||
script:
|
||||
|
@@ -6,7 +6,7 @@ if(NOT DEFINED PROJECT_NAME)
|
||||
set(NOT_SUBPROJECT ON)
|
||||
endif()
|
||||
|
||||
project(Catch2 LANGUAGES CXX VERSION 2.5.0)
|
||||
project(Catch2 LANGUAGES CXX VERSION 2.7.0)
|
||||
|
||||
# Provide path for scripts
|
||||
list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_LIST_DIR}/CMake")
|
||||
|
@@ -5,11 +5,11 @@
|
||||
[](https://travis-ci.org/catchorg/Catch2)
|
||||
[](https://ci.appveyor.com/project/catchorg/catch2)
|
||||
[](https://codecov.io/gh/catchorg/Catch2)
|
||||
[](https://wandbox.org/permlink/7lDqHmzKQxA2eaM0)
|
||||
[](https://wandbox.org/permlink/byNJIivVphHo170P)
|
||||
[](https://discord.gg/4CWS9zD)
|
||||
|
||||
|
||||
<a href="https://github.com/catchorg/Catch2/releases/download/v2.5.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.0/catch.hpp">The latest version of the single header can be downloaded directly using this link</a>
|
||||
|
||||
## Catch2 is released!
|
||||
|
||||
|
@@ -109,7 +109,7 @@ function(ParseFile SourceFile TestTarget)
|
||||
# Get test type and fixture if applicable
|
||||
string(REGEX MATCH "(CATCH_)?(TEST_CASE_METHOD|SCENARIO|TEST_CASE)[ \t]*\\([^,^\"]*" TestTypeAndFixture "${TestName}")
|
||||
string(REGEX MATCH "(CATCH_)?(TEST_CASE_METHOD|SCENARIO|TEST_CASE)" TestType "${TestTypeAndFixture}")
|
||||
string(REPLACE "${TestType}(" "" TestFixture "${TestTypeAndFixture}")
|
||||
string(REGEX REPLACE "${TestType}\\([ \t]*" "" TestFixture "${TestTypeAndFixture}")
|
||||
|
||||
# Get string parts of test definition
|
||||
string(REGEX MATCHALL "\"+([^\\^\"]|\\\\\")+\"+" TestStrings "${TestName}")
|
||||
@@ -164,7 +164,7 @@ function(ParseFile SourceFile TestTarget)
|
||||
break()
|
||||
endif(result)
|
||||
endforeach(label)
|
||||
if(PARSE_CATCH_TESTS_NO_HIDDEN_TESTS AND ${HiddenTagFound})
|
||||
if(PARSE_CATCH_TESTS_NO_HIDDEN_TESTS AND ${HiddenTagFound} AND ${CMAKE_VERSION} VERSION_LESS "3.9")
|
||||
PrintDebugMessage("Skipping test \"${CTestName}\" as it has [!hide], [.] or [.foo] label")
|
||||
else()
|
||||
PrintDebugMessage("Adding test \"${CTestName}\"")
|
||||
@@ -172,11 +172,21 @@ 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
|
||||
if(PARSE_CATCH_TESTS_NO_HIDDEN_TESTS AND ${HiddenTagFound} AND ${CMAKE_VERSION} VERSION_GREATER "3.8")
|
||||
PrintDebugMessage("Setting DISABLED test property")
|
||||
set_tests_properties("\"${CTestName}\"" PROPERTIES DISABLED ON)
|
||||
else()
|
||||
set_tests_properties("\"${CTestName}\"" PROPERTIES FAIL_REGULAR_EXPRESSION "No tests ran"
|
||||
LABELS "${Labels}")
|
||||
endif()
|
||||
endif()
|
||||
|
||||
|
||||
endforeach()
|
||||
endfunction()
|
||||
|
@@ -13,5 +13,7 @@ fact then please let us know - either directly, via a PR or
|
||||
[issue](https://github.com/philsquared/Catch/issues), or on the [forums](https://groups.google.com/forum/?fromgroups#!forum/catch-forum).
|
||||
|
||||
- Bloomberg
|
||||
- [Bloomlife](https://bloomlife.com)
|
||||
- NASA
|
||||
- [Inscopix Inc.](https://www.inscopix.com/)
|
||||
- [Makimo](https://makimo.pl/)
|
||||
|
@@ -204,6 +204,7 @@ By default, Catch does not stringify some types from the standard library. This
|
||||
CATCH_CONFIG_ENABLE_TUPLE_STRINGMAKER // Provide StringMaker specialization for std::tuple
|
||||
CATCH_CONFIG_ENABLE_CHRONO_STRINGMAKER // Provide StringMaker specialization for std::chrono::duration, std::chrono::timepoint
|
||||
CATCH_CONFIG_ENABLE_VARIANT_STRINGMAKER // Provide StringMaker specialization for std::variant, std::monostate (on C++17)
|
||||
CATCH_CONFIG_ENABLE_OPTIONAL_STRINGMAKER // Provide StringMaker specialization for std::optional (on C++17)
|
||||
CATCH_CONFIG_ENABLE_ALL_STRINGMAKERS // Defines all of the above
|
||||
|
||||
|
||||
|
@@ -37,20 +37,42 @@ as these are managed by the scripts!__
|
||||
|
||||
## Testing your changes
|
||||
|
||||
Obviously all changes to Catch's code should be tested. If you added new functionality, you should add tests covering and
|
||||
showcasing it. Even if you have only made changes to Catch internals (ie you implemented some performance improvements),
|
||||
you should still test your changes.
|
||||
Obviously all changes to Catch's code should be tested. If you added new
|
||||
functionality, you should add tests covering and showcasing it. Even if you have
|
||||
only made changes to Catch internals (i.e. you implemented some performance
|
||||
improvements), you should still test your changes.
|
||||
|
||||
This means 3 things
|
||||
This means 2 things
|
||||
|
||||
* Compiling Catch's SelfTest project -- code that does not compile is evidently incorrect. Obviously, you are not expected to
|
||||
have access to all compilers and platforms Catch supports, Catch's CI pipeline will compile your code using supported compilers
|
||||
once you open a PR.
|
||||
* Running the SelfTest binary. There should be no unexpected failures on simple run.
|
||||
* Running Catch's approval tests. Approval tests compare current output of the SelfTest binary in various configurations against
|
||||
known good output. Catch's repository provides utility scripts `approvalTests.py` to help you with this. It needs to be passed
|
||||
the SelfTest binary compiled with your changes, like so: `$ ./scripts/approvalTests.py clang-build/SelfTest`. The output should
|
||||
be fairly self-explanatory.
|
||||
* Compiling Catch's SelfTest project:
|
||||
```
|
||||
$ cd Catch2
|
||||
$ cmake -Bdebug-build -H. -DCMAKE_BUILD_TYPE=Debug
|
||||
$ cmake --build debug-build
|
||||
```
|
||||
because code that does not compile is evidently incorrect. Obviously,
|
||||
you are not expected to have access to all the compilers and platforms
|
||||
supported by Catch2, but you should at least smoke test your changes
|
||||
on your platform. Our CI pipeline will check your PR against most of
|
||||
the supported platforms, but it takes an hour to finish -- compiling
|
||||
locally takes just a few minutes.
|
||||
|
||||
|
||||
* Running the tests via CTest:
|
||||
```
|
||||
$ cd debug-build
|
||||
$ ctest -j 2 --output-on-failure
|
||||
```
|
||||
If you added new tests, approval tests are very likely to fail. If they
|
||||
do not, it means that your changes weren't run as part of them. This
|
||||
_might_ be intentional, but usually is not.
|
||||
|
||||
The approval tests compare current output of the SelfTest binary in various
|
||||
configurations against known good outputs. The reason it fails is,
|
||||
_usually_, that you've added new tests but have not yet approved the changes
|
||||
they introduce. This is done with the `scripts/approve.py` script, but
|
||||
before you do so, you need to check that the introduced changes are indeed
|
||||
intentional.
|
||||
|
||||
|
||||
|
||||
|
@@ -83,6 +83,11 @@ be changed so that hidden tests are included in a run only if they
|
||||
positively match a testspec.
|
||||
|
||||
|
||||
### Console Colour API
|
||||
|
||||
The API for Catch2's console colour will be changed to take an extra
|
||||
argument, the stream to which the colour code should be applied.
|
||||
|
||||
---
|
||||
|
||||
[Home](Readme.md#top)
|
||||
|
@@ -1,50 +1,133 @@
|
||||
<a id="top"></a>
|
||||
# Data Generators
|
||||
|
||||
_Generators are currently considered an experimental feature and their
|
||||
API can change between versions freely._
|
||||
|
||||
Data generators (also known as _data driven/parametrized test cases_)
|
||||
let you reuse the same set of assertions across different input values.
|
||||
In Catch2, this means that they respect the ordering and nesting
|
||||
of the `TEST_CASE` and `SECTION` macros.
|
||||
|
||||
How does combining generators and test cases work might be better
|
||||
explained by an example:
|
||||
of the `TEST_CASE` and `SECTION` macros, and their nested sections
|
||||
are run once per each value in a generator.
|
||||
|
||||
This is best explained with an example:
|
||||
```cpp
|
||||
TEST_CASE("Generators") {
|
||||
auto i = GENERATE( range(1, 11) );
|
||||
|
||||
SECTION( "Some section" ) {
|
||||
auto j = GENERATE( range( 11, 21 ) );
|
||||
REQUIRE(i < j);
|
||||
auto i = GENERATE(1, 2, 3);
|
||||
SECTION("one") {
|
||||
auto j = GENERATE( -3, -2, -1 );
|
||||
REQUIRE(j < i);
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
the assertion will be checked 100 times, because there are 10 possible
|
||||
values for `i` (1, 2, ..., 10) and for each of them, there are 10 possible
|
||||
values for `j` (11, 12, ..., 20).
|
||||
The assertion in this test case will be run 9 times, because there
|
||||
are 3 possible values for `i` (1, 2, and 3) and there are 3 possible
|
||||
values for `j` (-3, -2, and -1).
|
||||
|
||||
|
||||
There are 2 parts to generators in Catch2, the `GENERATE` macro together
|
||||
with the already provided generators, and the `IGenerator<T>` interface
|
||||
that allows users to implement their own generators.
|
||||
|
||||
## Provided generators
|
||||
|
||||
Catch2's provided generator functionality consists of three parts,
|
||||
|
||||
* `GENERATE` macro, that serves to integrate generator expression with
|
||||
a test case,
|
||||
* 2 fundamental generators
|
||||
* `ValueGenerator<T>` -- contains only single element
|
||||
* `ValuesGenerator<T>` -- contains multiple elements
|
||||
* 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
|
||||
|
||||
* `value(T&&)` for `ValueGenerator<T>`
|
||||
* `values(std::initializer_list<T>)` for `ValuesGenerator<T>`
|
||||
* `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<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:
|
||||
|
||||
You can also combine multiple generators by concatenation:
|
||||
```cpp
|
||||
static int square(int x) { return x * x; }
|
||||
TEST_CASE("Generators 2") {
|
||||
auto i = GENERATE(0, 1, -1, range(-20, -10), range(10, 20));
|
||||
CAPTURE(i);
|
||||
REQUIRE(square(i) >= 0);
|
||||
TEST_CASE("Generating random ints", "[example][generator]") {
|
||||
SECTION("Deducing functions") {
|
||||
auto i = GENERATE(take(100, filter([](int i) { return i % 2 == 1; }, random(-100, 100))));
|
||||
REQUIRE(i > -100);
|
||||
REQUIRE(i < 100);
|
||||
REQUIRE(i % 2 == 1);
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
This will call `square` with arguments `0`, `1`, `-1`, `-20`, ..., `-11`,
|
||||
`10`, ..., `19`.
|
||||
|
||||
----------
|
||||
Apart from registering generators with Catch2, the `GENERATE` macro has
|
||||
one more purpose, and that is to provide simple way of generating trivial
|
||||
generators, as seen in the first example on this page, where we used it
|
||||
as `auto i = GENERATE(1, 2, 3);`. This usage converted each of the three
|
||||
literals into a single `ValueGenerator<int>` and then placed them all in
|
||||
a special generator that concatenates other generators. It can also be
|
||||
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.**
|
||||
|
||||
You can also override the inferred type by using `as<type>` as the first
|
||||
argument to the macro. This can be useful when dealing with string literals,
|
||||
if you want them to come out as `std::string`:
|
||||
|
||||
```cpp
|
||||
TEST_CASE("type conversion", "[generators]") {
|
||||
auto str = GENERATE(as<std::string>{}, "a", "bb", "ccc");`
|
||||
REQUIRE(str.size() > 0);
|
||||
}
|
||||
```
|
||||
|
||||
## Generator interface
|
||||
|
||||
You can also implement your own generators, by deriving from the
|
||||
`IGenerator<T>` interface:
|
||||
|
||||
```cpp
|
||||
template<typename T>
|
||||
struct IGenerator : GeneratorUntypedBase {
|
||||
// via GeneratorUntypedBase:
|
||||
// Attempts to move the generator to the next element.
|
||||
// Returns true if successful (and thus has another element that can be read)
|
||||
virtual bool next() = 0;
|
||||
|
||||
// Precondition:
|
||||
// The generator is either freshly constructed or the last call to next() returned true
|
||||
virtual T const& get() const = 0;
|
||||
};
|
||||
```
|
||||
|
||||
However, to be able to use your custom generator inside `GENERATE`, it
|
||||
will need to be wrapped inside a `GeneratorWrapper<T>`.
|
||||
`GeneratorWrapper<T>` is a value wrapper around a
|
||||
`std::unique_ptr<IGenerator<T>>`.
|
||||
|
||||
For full example of implementing your own generator, look into Catch2's
|
||||
examples, specifically
|
||||
[Generators: Create your own generator](../examples/300-Gen-OwnGenerator.cpp).
|
||||
|
||||
Because of the experimental nature of the current Generator implementation,
|
||||
we won't list all of the first-party generators in Catch2. Instead you
|
||||
should look at our current usage tests in
|
||||
[projects/SelfTest/UsageTests/Generators.tests.cpp](/projects/SelfTest/UsageTests/Generators.tests.cpp).
|
||||
For implementing your own generators, you can look at their implementation in
|
||||
[include/internal/catch_generators.hpp](/include/internal/catch_generators.hpp).
|
||||
|
@@ -14,6 +14,10 @@
|
||||
- Report: [TeamCity reporter](../examples/207-Rpt-TeamCityReporter.cpp)
|
||||
- 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)
|
||||
|
||||
|
||||
## Planned
|
||||
|
||||
|
@@ -1,7 +1,7 @@
|
||||
<a id="top"></a>
|
||||
# Logging macros
|
||||
|
||||
Additional messages can be logged during a test case. Note that the messages are scoped and thus will not be reported if failure occurs in scope preceding the message declaration. An example:
|
||||
Additional messages can be logged during a test case. Note that the messages logged with `INFO` are scoped and thus will not be reported if failure occurs in scope preceding the message declaration. An example:
|
||||
|
||||
```cpp
|
||||
TEST_CASE("Foo") {
|
||||
@@ -28,6 +28,60 @@ The number is 1
|
||||
```
|
||||
When the last `CHECK` fails in the "Bar" test case, then only one message will be printed: `Test case start`.
|
||||
|
||||
## Logging without local scope
|
||||
|
||||
`UNSCOPED_INFO` is similar to `INFO` with two key differences:
|
||||
|
||||
- Lifetime of an unscoped message is not tied to its own scope.
|
||||
- An unscoped message can be reported by the first following assertion only, regardless of the result of that assertion.
|
||||
|
||||
In other words, lifetime of `UNSCOPED_INFO` is limited by the following assertion (or by the end of test case/section, whichever comes first) whereas lifetime of `INFO` is limited by its own scope.
|
||||
|
||||
These differences make this macro useful for reporting information from helper functions or inner scopes. An example:
|
||||
|
||||
```cpp
|
||||
void print_some_info() {
|
||||
UNSCOPED_INFO("Info from helper");
|
||||
}
|
||||
|
||||
TEST_CASE("Baz") {
|
||||
print_some_info();
|
||||
for (int i = 0; i < 2; ++i) {
|
||||
UNSCOPED_INFO("The number is " << i);
|
||||
}
|
||||
CHECK(false);
|
||||
}
|
||||
|
||||
TEST_CASE("Qux") {
|
||||
INFO("First info");
|
||||
UNSCOPED_INFO("First unscoped info");
|
||||
CHECK(false);
|
||||
|
||||
INFO("Second info");
|
||||
UNSCOPED_INFO("Second unscoped info");
|
||||
CHECK(false);
|
||||
}
|
||||
```
|
||||
|
||||
"Baz" test case prints:
|
||||
```
|
||||
Info from helper
|
||||
The number is 0
|
||||
The number is 1
|
||||
```
|
||||
|
||||
With "Qux" test case, two messages will be printed when the first `CHECK` fails:
|
||||
```
|
||||
First info
|
||||
First unscoped info
|
||||
```
|
||||
|
||||
"First unscoped info" message will be cleared after the first `CHECK`, while "First info" message will persist until the end of the test case. Therefore, when the second `CHECK` fails, three messages will be printed:
|
||||
```
|
||||
First info
|
||||
Second info
|
||||
Second unscoped info
|
||||
```
|
||||
|
||||
## Streaming macros
|
||||
|
||||
@@ -43,7 +97,14 @@ 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_ **)**
|
||||
|
||||
|
@@ -18,25 +18,28 @@ Listing a project here does not imply endorsement and the plan is to keep these
|
||||
## Libraries & Frameworks
|
||||
|
||||
### [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++.
|
||||
@@ -60,25 +63,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.
|
||||
@@ -92,7 +95,7 @@ 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.
|
||||
@@ -101,7 +104,7 @@ Newsbeuter is an open-source RSS/Atom feed reader for text terminals.
|
||||
SpECTRE is a code for multi-scale, multi-physics problems in astrophysics and gravitational physics.
|
||||
|
||||
### [Standardese](https://github.com/foonathan/standardese)
|
||||
Standardese aims to be a nextgen Doxygen
|
||||
Standardese aims to be a nextgen Doxygen.
|
||||
|
||||
---
|
||||
|
||||
|
@@ -2,6 +2,9 @@
|
||||
|
||||
# Release notes
|
||||
**Contents**<br>
|
||||
[2.7.0](#270)<br>
|
||||
[2.6.1](#261)<br>
|
||||
[2.6.0](#260)<br>
|
||||
[2.5.0](#250)<br>
|
||||
[2.4.2](#242)<br>
|
||||
[2.4.1](#241)<br>
|
||||
@@ -18,6 +21,96 @@
|
||||
[Older versions](#older-versions)<br>
|
||||
[Even Older versions](#even-older-versions)<br>
|
||||
|
||||
## 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.**
|
||||
|
||||
|
||||
### Improvements
|
||||
* Added `TEMPLATE_PRODUCT_TEST_CASE` (#1454, #1468)
|
||||
* This allows you to easily test various type combinations, see documentation for details
|
||||
* The error message for `&&` and `||` inside assertions has been improved (#1273, #1480)
|
||||
* The error message for chained comparisons inside assertions has been improved (#1481)
|
||||
* Added `StringMaker` specialization for `std::optional` (#1510)
|
||||
* The generator interface has been redone once again (#1516)
|
||||
* It is no longer considered experimental and is fully supported
|
||||
* The new interface supports "Input" generators
|
||||
* The generator documentation has been fully updated
|
||||
* We also added 2 generator examples
|
||||
|
||||
|
||||
### Fixes
|
||||
* Fixed `-Wredundant-move` on newer Clang (#1474)
|
||||
* Removed unreachable mentions `std::current_exception`, `std::rethrow_exception` in no-exceptions mode (#1462)
|
||||
* This should fix compilation with IAR
|
||||
* Fixed missing `<type_traits>` include (#1494)
|
||||
* Fixed various static analysis warnings
|
||||
* Unrestored stream state in `XmlWriter` (#1489)
|
||||
* Potential division by zero in `estimateClockResolution` (#1490)
|
||||
* Uninitialized member in `RunContext` (#1491)
|
||||
* `SourceLineInfo` move ops are now marked `noexcept`
|
||||
* `CATCH_BREAK_INTO_DEBUGGER` is now always a function
|
||||
* Fix double run of a test case if user asks for a specific section (#1394, #1492)
|
||||
* ANSI colour code output now respects `-o` flag and writes to the file as well (#1502)
|
||||
* Fixed detection of `std::variant` support for compilers other than Clang (#1511)
|
||||
|
||||
|
||||
### Contrib
|
||||
* `ParseAndAddCatchTests` has learned how to use `DISABLED` CTest property (#1452)
|
||||
* `ParseAndAddCatchTests` now works when there is a whitspace before the test name (#1493)
|
||||
|
||||
|
||||
### Miscellaneous
|
||||
* We added new issue templates for reporting issues on GitHub
|
||||
* `contributing.md` has been updated to reflect the current test status (#1484)
|
||||
|
||||
|
||||
|
||||
## 2.5.0
|
||||
|
||||
### Improvements
|
||||
|
@@ -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._
|
||||
|
@@ -95,7 +95,8 @@ Other than the additional prefixes and the formatting in the console reporter th
|
||||
## Type parametrised test cases
|
||||
|
||||
In addition to `TEST_CASE`s, Catch2 also supports test cases parametrised
|
||||
by type, in the form of `TEMPLATE_TEST_CASE`.
|
||||
by types, in the form of `TEMPLATE_TEST_CASE` and
|
||||
`TEMPLATE_PRODUCT_TEST_CASE`.
|
||||
|
||||
* **TEMPLATE_TEST_CASE(** _test name_ , _tags_, _type1_, _type2_, ..., _typen_ **)**
|
||||
|
||||
@@ -147,9 +148,48 @@ TEMPLATE_TEST_CASE( "vectors can be sized and resized", "[vector][template]", in
|
||||
}
|
||||
```
|
||||
|
||||
* **TEMPLATE_PRODUCT_TEST_CASE(** _test name_ , _tags_, (_template-type1_, _template-type2_, ..., _template-typen_), (_template-arg1_, _template-arg2_, ..., _template-argm_) **)**
|
||||
|
||||
_template-type1_ through _template-typen_ is list of template template
|
||||
types which should be combined with each of _template-arg1_ through
|
||||
_template-argm_, resulting in _n * m_ test cases. Inside the test case,
|
||||
the resulting type is available under the name of `TestType`.
|
||||
|
||||
To specify more than 1 type as a single _template-type_ or _template-arg_,
|
||||
you must enclose the types in an additional set of parentheses, e.g.
|
||||
`((int, float), (char, double))` specifies 2 template-args, each
|
||||
consisting of 2 concrete types (`int`, `float` and `char`, `double`
|
||||
respectively). You can also omit the outer set of parentheses if you
|
||||
specify only one type as the full set of either the _template-types_,
|
||||
or the _template-args_.
|
||||
|
||||
|
||||
Example:
|
||||
```cpp
|
||||
template< typename T>
|
||||
struct Foo {
|
||||
size_t size() {
|
||||
return 0;
|
||||
}
|
||||
};
|
||||
|
||||
TEMPLATE_PRODUCT_TEST_CASE("A Template product test case", "[template][product]", (std::vector, Foo), (int, float)) {
|
||||
TestType x;
|
||||
REQUIRE(x.size() == 0);
|
||||
}
|
||||
```
|
||||
|
||||
You can also have different arities in the _template-arg_ packs:
|
||||
```cpp
|
||||
TEMPLATE_PRODUCT_TEST_CASE("Product with differing arities", "[template][product]", std::tuple, (int, (int, double), (int, double, float))) {
|
||||
TestType x;
|
||||
REQUIRE(std::tuple_size<TestType>::value >= 1);
|
||||
}
|
||||
```
|
||||
|
||||
_While there is an upper limit on the number of types you can specify
|
||||
in single `TEMPLATE_TEST_CASE`, the limit is very high and should not
|
||||
be encountered in practice._
|
||||
in single `TEMPLATE_TEST_CASE` or `TEMPLATE_PRODUCT_TEST_CASE`, the limit
|
||||
is very high and should not be encountered in practice._
|
||||
|
||||
---
|
||||
|
||||
|
@@ -31,16 +31,22 @@ class UniqueTestsFixture {
|
||||
The two test cases here will create uniquely-named derived classes of UniqueTestsFixture and thus can access the `getID()` protected method and `conn` member variables. This ensures that both the test cases are able to create a DBConnection using the same method (DRY principle) and that any ID's created are unique such that the order that tests are executed does not matter.
|
||||
|
||||
|
||||
Catch2 also provides `TEMPLATE_TEST_CASE_METHOD` that can be used together
|
||||
with templated fixtures to perform tests for multiple different types.
|
||||
However, unlike `TEST_CASE_METHOD`, `TEMPLATE_TEST_CASE_METHOD` requires
|
||||
the tag specification to be non-empty, as it is followed by further macros
|
||||
arguments.
|
||||
Catch2 also provides `TEMPLATE_TEST_CASE_METHOD` and
|
||||
`TEMPLATE_PRODUCT_TEST_CASE_METHOD` that can be used together
|
||||
with templated fixtures and templated template fixtures to perform
|
||||
tests for multiple different types. Unlike `TEST_CASE_METHOD`,
|
||||
`TEMPLATE_TEST_CASE_METHOD` and `TEMPLATE_PRODUCT_TEST_CASE_METHOD` do
|
||||
require the tag specification to be non-empty, as it is followed by
|
||||
further macro arguments.
|
||||
|
||||
Also note that, because of limitations of the C++ preprocessor, if you
|
||||
want to specify a type with multiple template parameters, you need to
|
||||
enclose it in parentheses, e.g. `std::map<int, std::string>` needs to be
|
||||
passed as `(std::map<int, std::string>)`.
|
||||
In the case of `TEMPLATE_PRODUCT_TEST_CASE_METHOD`, if a member of the
|
||||
type list should consist of more than single type, it needs to be enclosed
|
||||
in another pair of parentheses, e.g. `(std::map, std::pair)` and
|
||||
`((int, float), (char, double))`.
|
||||
|
||||
Example:
|
||||
```cpp
|
||||
@@ -54,11 +60,29 @@ struct Template_Fixture {
|
||||
TEMPLATE_TEST_CASE_METHOD(Template_Fixture,"A TEMPLATE_TEST_CASE_METHOD based test run that succeeds", "[class][template]", int, float, double) {
|
||||
REQUIRE( Template_Fixture<TestType>::m_a == 1 );
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
struct Template_Template_Fixture {
|
||||
Template_Template_Fixture() {}
|
||||
|
||||
T m_a;
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
struct Foo_class {
|
||||
size_t size() {
|
||||
return 0;
|
||||
}
|
||||
};
|
||||
|
||||
TEMPLATE_PRODUCT_TEST_CASE_METHOD(Template_Template_Fixture, "A TEMPLATE_PRODUCT_TEST_CASE_METHOD based test succeeds", "[class][template]", (Foo_class, std::vector), int) {
|
||||
REQUIRE( Template_Template_Fixture<TestType>::m_a.size() == 0 );
|
||||
}
|
||||
```
|
||||
|
||||
_While there is an upper limit on the number of types you can specify
|
||||
in single `TEMPLATE_TEST_CASE`, the limit is very high and should not
|
||||
be encountered in practice._
|
||||
in single `TEMPLATE_TEST_CASE_METHOD` or `TEMPLATE_PRODUCT_TEST_CASE_METHOD`,
|
||||
the limit is very high and should not be encountered in practice._
|
||||
|
||||
---
|
||||
|
||||
|
@@ -260,8 +260,9 @@ Do not write your tests in header files!
|
||||
## Type parametrised test cases
|
||||
|
||||
Test cases in Catch2 can be also parametrised by type, via the
|
||||
`TEMPLATE_TEST_CASE` macro, which behaves in the same way the `TEST_CASE`
|
||||
macro, but is run for every type.
|
||||
`TEMPLATE_TEST_CASE` and `TEMPLATE_PRODUCT_TEST_CASE` macros,
|
||||
which behave in the same way the `TEST_CASE` macro, but are run for
|
||||
every type or type combination.
|
||||
|
||||
For more details, see our documentation on [test cases and
|
||||
sections](test-cases-and-sections.md#type-parametrised-test-cases).
|
||||
|
@@ -387,16 +387,16 @@ TEST_CASE( "2: Testcase with sections", "[tag-A][tag-B]" ) {
|
||||
REQUIRE( i == 42 );
|
||||
|
||||
SECTION("Section 1") {
|
||||
INFO("Section 1")
|
||||
INFO("Section 1");
|
||||
i = 7;
|
||||
SECTION("Section 1.1") {
|
||||
INFO("Section 1.1")
|
||||
INFO("Section 1.1");
|
||||
REQUIRE( i == 42 );
|
||||
}
|
||||
}
|
||||
|
||||
SECTION("Section 2") {
|
||||
INFO("Section 2")
|
||||
INFO("Section 2");
|
||||
REQUIRE( i == 42 );
|
||||
}
|
||||
WARN("At end of test case");
|
||||
|
59
examples/300-Gen-OwnGenerator.cpp
Normal file
59
examples/300-Gen-OwnGenerator.cpp
Normal file
@@ -0,0 +1,59 @@
|
||||
// 300-Gen-OwnGenerator.cpp
|
||||
// Shows how to define a custom generator.
|
||||
|
||||
// Specifically we will implement a random number generator for integers
|
||||
// It will have infinite capacity and settable lower/upper bound
|
||||
|
||||
#include <catch2/catch.hpp>
|
||||
|
||||
#include <random>
|
||||
|
||||
// This class shows how to implement a simple generator for Catch tests
|
||||
class RandomIntGenerator : public Catch::Generators::IGenerator<int> {
|
||||
std::minstd_rand m_rand;
|
||||
std::uniform_int_distribution<> m_dist;
|
||||
int current_number;
|
||||
public:
|
||||
|
||||
RandomIntGenerator(int low, int high):
|
||||
m_rand(std::random_device{}()),
|
||||
m_dist(low, high)
|
||||
{
|
||||
static_cast<void>(next());
|
||||
}
|
||||
|
||||
int const& get() const override;
|
||||
bool next() override {
|
||||
current_number = m_dist(m_rand);
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
// Avoids -Wweak-vtables
|
||||
int const& RandomIntGenerator::get() const {
|
||||
return current_number;
|
||||
}
|
||||
|
||||
// This helper function provides a nicer UX when instantiating the generator
|
||||
// Notice that it returns an instance of GeneratorWrapper<int>, which
|
||||
// is a value-wrapper around std::unique_ptr<IGenerator<int>>.
|
||||
Catch::Generators::GeneratorWrapper<int> random(int low, int high) {
|
||||
return Catch::Generators::GeneratorWrapper<int>(std::unique_ptr<Catch::Generators::IGenerator<int>>(new RandomIntGenerator(low, high)));
|
||||
}
|
||||
|
||||
// The two sections in this test case are equivalent, but the first one
|
||||
// is much more readable/nicer to use
|
||||
TEST_CASE("Generating random ints", "[example][generator]") {
|
||||
SECTION("Nice UX") {
|
||||
auto i = GENERATE(take(100, random(-100, 100)));
|
||||
REQUIRE(i >= -100);
|
||||
REQUIRE(i <= 100);
|
||||
}
|
||||
SECTION("Creating the random generator directly") {
|
||||
auto i = GENERATE(take(100, GeneratorWrapper<int>(std::unique_ptr<IGenerator<int>>(new RandomIntGenerator(-100, 100)))));
|
||||
REQUIRE(i >= -100);
|
||||
REQUIRE(i <= 100);
|
||||
}
|
||||
}
|
||||
|
||||
// Compiling and running this file will result in 400 successful assertions
|
54
examples/301-Gen-MapTypeConversion.cpp
Normal file
54
examples/301-Gen-MapTypeConversion.cpp
Normal file
@@ -0,0 +1,54 @@
|
||||
// 301-Gen-MapTypeConversion.cpp
|
||||
// Shows how to use map to modify generator's return type.
|
||||
|
||||
// TODO
|
||||
|
||||
#include <catch2/catch.hpp>
|
||||
|
||||
#include <string>
|
||||
#include <sstream>
|
||||
|
||||
// Returns a line from a stream. You could have it e.g. read lines from
|
||||
// a file, but to avoid problems with paths in examples, we will use
|
||||
// a fixed stringstream.
|
||||
class LineGenerator : public Catch::Generators::IGenerator<std::string> {
|
||||
std::string m_line;
|
||||
std::stringstream m_stream;
|
||||
public:
|
||||
LineGenerator() {
|
||||
m_stream.str("1\n2\n3\n4\n");
|
||||
if (!next()) {
|
||||
throw Catch::GeneratorException("Couldn't read a single line");
|
||||
}
|
||||
}
|
||||
|
||||
std::string const& get() const override {
|
||||
return m_line;
|
||||
}
|
||||
|
||||
bool next() override {
|
||||
return !!std::getline(m_stream, m_line);
|
||||
}
|
||||
};
|
||||
|
||||
// This helper function provides a nicer UX when instantiating the generator
|
||||
// Notice that it returns an instance of GeneratorWrapper<std::string>, which
|
||||
// is a value-wrapper around std::unique_ptr<IGenerator<std::string>>.
|
||||
Catch::Generators::GeneratorWrapper<std::string> lines(std::string /* ignored for example */) {
|
||||
return Catch::Generators::GeneratorWrapper<std::string>(
|
||||
std::unique_ptr<Catch::Generators::IGenerator<std::string>>(
|
||||
new LineGenerator()
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
|
||||
TEST_CASE("filter can convert types inside the generator expression", "[example][generator]") {
|
||||
auto num = GENERATE(map<int>([](std::string const& line) { return std::stoi(line); },
|
||||
lines("fake-file")));
|
||||
|
||||
REQUIRE(num > 0);
|
||||
}
|
||||
|
||||
// Compiling and running this file will result in 4 successful assertions
|
72
examples/310-Gen-VariablesInGenerators.cpp
Normal file
72
examples/310-Gen-VariablesInGenerators.cpp
Normal file
@@ -0,0 +1,72 @@
|
||||
// 310-Gen-VariablesInGenerator.cpp
|
||||
// Shows how to use variables when creating generators.
|
||||
|
||||
// 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 -- thus they should be either captured
|
||||
// by value directly, or copied by the generators during construction.
|
||||
|
||||
#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++
|
||||
using record = std::tuple<double, double>;
|
||||
// Set up 3 ranges to generate numbers from
|
||||
auto r = GENERATE(table<double, double>({
|
||||
record{3, 4},
|
||||
record{-4, -3},
|
||||
record{10, 1000}
|
||||
}));
|
||||
|
||||
// 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))));
|
||||
}
|
||||
);
|
||||
REQUIRE(std::abs(number) > 0);
|
||||
}
|
||||
|
||||
// Compiling and running this file will result in 150 successful assertions
|
||||
|
@@ -44,6 +44,9 @@ set( SOURCES_IDIOMATIC_TESTS
|
||||
110-Fix-ClassFixture.cpp
|
||||
120-Bdd-ScenarioGivenWhenThen.cpp
|
||||
210-Evt-EventListeners.cpp
|
||||
300-Gen-OwnGenerator.cpp
|
||||
301-Gen-MapTypeConversion.cpp
|
||||
310-Gen-VariablesInGenerators.cpp
|
||||
)
|
||||
|
||||
# main-s for reporter-specific test sources:
|
||||
|
@@ -10,7 +10,7 @@
|
||||
#define TWOBLUECUBES_CATCH_HPP_INCLUDED
|
||||
|
||||
#define CATCH_VERSION_MAJOR 2
|
||||
#define CATCH_VERSION_MINOR 5
|
||||
#define CATCH_VERSION_MINOR 7
|
||||
#define CATCH_VERSION_PATCH 0
|
||||
|
||||
#ifdef __clang__
|
||||
@@ -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)
|
||||
@@ -148,9 +150,13 @@
|
||||
#ifndef CATCH_CONFIG_TRADITIONAL_MSVC_PREPROCESSOR
|
||||
#define CATCH_TEMPLATE_TEST_CASE( ... ) INTERNAL_CATCH_TEMPLATE_TEST_CASE( __VA_ARGS__ )
|
||||
#define CATCH_TEMPLATE_TEST_CASE_METHOD( className, ... ) INTERNAL_CATCH_TEMPLATE_TEST_CASE_METHOD( className, __VA_ARGS__ )
|
||||
#define CATCH_TEMPLATE_PRODUCT_TEST_CASE( ... ) INTERNAL_CATCH_TEMPLATE_PRODUCT_TEST_CASE( __VA_ARGS__ )
|
||||
#define CATCH_TEMPLATE_PRODUCT_TEST_CASE_METHOD( className, ... ) INTERNAL_CATCH_TEMPLATE_PRODUCT_TEST_CASE_METHOD( className, __VA_ARGS__ )
|
||||
#else
|
||||
#define CATCH_TEMPLATE_TEST_CASE( ... ) INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_TEST_CASE( __VA_ARGS__ ) )
|
||||
#define CATCH_TEMPLATE_TEST_CASE_METHOD( className, ... ) INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_TEST_CASE_METHOD( className, __VA_ARGS__ ) )
|
||||
#define CATCH_TEMPLATE_PRODUCT_TEST_CASE( ... ) INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_PRODUCT_TEST_CASE( __VA_ARGS__ ) )
|
||||
#define CATCH_TEMPLATE_PRODUCT_TEST_CASE_METHOD( className, ... ) INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_PRODUCT_TEST_CASE_METHOD( className, __VA_ARGS__ ) )
|
||||
#endif
|
||||
|
||||
|
||||
@@ -209,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__ )
|
||||
|
||||
@@ -226,9 +233,13 @@
|
||||
#ifndef CATCH_CONFIG_TRADITIONAL_MSVC_PREPROCESSOR
|
||||
#define TEMPLATE_TEST_CASE( ... ) INTERNAL_CATCH_TEMPLATE_TEST_CASE( __VA_ARGS__ )
|
||||
#define TEMPLATE_TEST_CASE_METHOD( className, ... ) INTERNAL_CATCH_TEMPLATE_TEST_CASE_METHOD( className, __VA_ARGS__ )
|
||||
#define TEMPLATE_PRODUCT_TEST_CASE( ... ) INTERNAL_CATCH_TEMPLATE_PRODUCT_TEST_CASE( __VA_ARGS__ )
|
||||
#define TEMPLATE_PRODUCT_TEST_CASE_METHOD( className, ... ) INTERNAL_CATCH_TEMPLATE_PRODUCT_TEST_CASE_METHOD( className, __VA_ARGS__ )
|
||||
#else
|
||||
#define TEMPLATE_TEST_CASE( ... ) INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_TEST_CASE( __VA_ARGS__ ) )
|
||||
#define TEMPLATE_TEST_CASE_METHOD( className, ... ) INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_TEST_CASE_METHOD( className, __VA_ARGS__ ) )
|
||||
#define TEMPLATE_PRODUCT_TEST_CASE( ... ) INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_PRODUCT_TEST_CASE( __VA_ARGS__ ) )
|
||||
#define TEMPLATE_PRODUCT_TEST_CASE_METHOD( className, ... ) INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_PRODUCT_TEST_CASE_METHOD( className, __VA_ARGS__ ) )
|
||||
#endif
|
||||
|
||||
|
||||
@@ -313,9 +324,13 @@ using Catch::Detail::Approx;
|
||||
#ifndef CATCH_CONFIG_TRADITIONAL_MSVC_PREPROCESSOR
|
||||
#define CATCH_TEMPLATE_TEST_CASE( ... ) INTERNAL_CATCH_TEMPLATE_TEST_CASE_NO_REGISTRATION(INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_M_P_L_A_T_E____T_E_S_T____ ) )
|
||||
#define CATCH_TEMPLATE_TEST_CASE_METHOD( className, ... ) INTERNAL_CATCH_TEMPLATE_TEST_CASE_METHOD_NO_REGISTRATION(INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_M_P_L_A_T_E____T_E_S_T____ ), className )
|
||||
#define CATCH_TEMPLATE_PRODUCT_TEST_CASE( ... ) CATCH_TEMPLATE_TEST_CASE( __VA_ARGS__ )
|
||||
#define CATCH_TEMPLATE_PRODUCT_TEST_CASE_METHOD( className, ... ) CATCH_TEMPLATE_TEST_CASE_METHOD( className, __VA_ARGS__ )
|
||||
#else
|
||||
#define CATCH_TEMPLATE_TEST_CASE( ... ) INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_TEST_CASE_NO_REGISTRATION(INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_M_P_L_A_T_E____T_E_S_T____ ) ) )
|
||||
#define CATCH_TEMPLATE_TEST_CASE_METHOD( className, ... ) INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_TEST_CASE_METHOD_NO_REGISTRATION(INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_M_P_L_A_T_E____T_E_S_T____ ), className ) )
|
||||
#define CATCH_TEMPLATE_PRODUCT_TEST_CASE( ... ) CATCH_TEMPLATE_TEST_CASE( __VA_ARGS__ )
|
||||
#define CATCH_TEMPLATE_PRODUCT_TEST_CASE_METHOD( className, ... ) CATCH_TEMPLATE_TEST_CASE_METHOD( className, __VA_ARGS__ )
|
||||
#endif
|
||||
|
||||
// "BDD-style" convenience wrappers
|
||||
@@ -384,9 +399,13 @@ using Catch::Detail::Approx;
|
||||
#ifndef CATCH_CONFIG_TRADITIONAL_MSVC_PREPROCESSOR
|
||||
#define TEMPLATE_TEST_CASE( ... ) INTERNAL_CATCH_TEMPLATE_TEST_CASE_NO_REGISTRATION(INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_M_P_L_A_T_E____T_E_S_T____ ) )
|
||||
#define TEMPLATE_TEST_CASE_METHOD( className, ... ) INTERNAL_CATCH_TEMPLATE_TEST_CASE_METHOD_NO_REGISTRATION(INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_M_P_L_A_T_E____T_E_S_T____ ), className )
|
||||
#define TEMPLATE_PRODUCT_TEST_CASE( ... ) TEMPLATE_TEST_CASE( __VA_ARGS__ )
|
||||
#define TEMPLATE_PRODUCT_TEST_CASE_METHOD( className, ... ) TEMPLATE_TEST_CASE_METHOD( className, __VA_ARGS__ )
|
||||
#else
|
||||
#define TEMPLATE_TEST_CASE( ... ) INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_TEST_CASE_NO_REGISTRATION(INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_M_P_L_A_T_E____T_E_S_T____ ) ) )
|
||||
#define TEMPLATE_TEST_CASE_METHOD( className, ... ) INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_TEST_CASE_METHOD_NO_REGISTRATION(INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_M_P_L_A_T_E____T_E_S_T____ ), className ) )
|
||||
#define TEMPLATE_PRODUCT_TEST_CASE( ... ) TEMPLATE_TEST_CASE( __VA_ARGS__ )
|
||||
#define TEMPLATE_PRODUCT_TEST_CASE_METHOD( className, ... ) TEMPLATE_TEST_CASE_METHOD( className, __VA_ARGS__ )
|
||||
#endif
|
||||
|
||||
#define STATIC_REQUIRE( ... ) (void)(0)
|
||||
|
4
include/external/clara.hpp
vendored
4
include/external/clara.hpp
vendored
@@ -370,7 +370,7 @@ inline auto Column::operator + (Column const& other) -> Columns {
|
||||
// ----------- end of #include from clara_textflow.hpp -----------
|
||||
// ........... back in clara.hpp
|
||||
|
||||
|
||||
#include <cctype>
|
||||
#include <string>
|
||||
#include <memory>
|
||||
#include <set>
|
||||
@@ -664,7 +664,7 @@ namespace detail {
|
||||
}
|
||||
inline auto convertInto( std::string const &source, bool &target ) -> ParserResult {
|
||||
std::string srcLC = source;
|
||||
std::transform( srcLC.begin(), srcLC.end(), srcLC.begin(), []( char c ) { return static_cast<char>( ::tolower(c) ); } );
|
||||
std::transform( srcLC.begin(), srcLC.end(), srcLC.begin(), []( char c ) { return static_cast<char>( std::tolower(c) ); } );
|
||||
if (srcLC == "y" || srcLC == "1" || srcLC == "true" || srcLC == "yes" || srcLC == "on")
|
||||
target = true;
|
||||
else if (srcLC == "n" || srcLC == "0" || srcLC == "false" || srcLC == "no" || srcLC == "off")
|
||||
|
@@ -48,7 +48,7 @@
|
||||
CATCH_INTERNAL_UNSUPPRESS_PARENTHESES_WARNINGS \
|
||||
} INTERNAL_CATCH_CATCH( catchAssertionHandler ) \
|
||||
INTERNAL_CATCH_REACT( catchAssertionHandler ) \
|
||||
} while( (void)0, false && static_cast<bool>( !!(__VA_ARGS__) ) ) // the expression here is never evaluated at runtime but it forces the compiler to give it a look
|
||||
} while( (void)0, (false) && static_cast<bool>( !!(__VA_ARGS__) ) ) // the expression here is never evaluated at runtime but it forces the compiler to give it a look
|
||||
// The double negation silences MSVC's C4800 warning, the static_cast forces short-circuit evaluation if the type has overloaded &&.
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
@@ -130,6 +130,10 @@
|
||||
#define INTERNAL_CATCH_INFO( macroName, log ) \
|
||||
Catch::ScopedMessage INTERNAL_CATCH_UNIQUE_NAME( scopedMessage )( Catch::MessageBuilder( macroName##_catch_sr, CATCH_INTERNAL_LINEINFO, Catch::ResultWas::Info ) << log );
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
#define INTERNAL_CATCH_UNSCOPED_INFO( macroName, log ) \
|
||||
Catch::getResultCapture().emplaceUnscopedMessage( Catch::MessageBuilder( macroName##_catch_sr, CATCH_INTERNAL_LINEINFO, Catch::ResultWas::Info ) << log )
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// Although this is matcher-based, it can be used with just a string
|
||||
#define INTERNAL_CATCH_THROWS_STR_MATCHES( macroName, resultDisposition, matcher, ... ) \
|
||||
|
@@ -53,9 +53,9 @@ namespace Catch {
|
||||
{}
|
||||
|
||||
SourceLineInfo( SourceLineInfo const& other ) = default;
|
||||
SourceLineInfo( SourceLineInfo && ) = default;
|
||||
SourceLineInfo& operator = ( SourceLineInfo const& ) = default;
|
||||
SourceLineInfo& operator = ( SourceLineInfo && ) = default;
|
||||
SourceLineInfo( SourceLineInfo&& ) noexcept = default;
|
||||
SourceLineInfo& operator = ( SourceLineInfo&& ) noexcept = default;
|
||||
|
||||
bool empty() const noexcept;
|
||||
bool operator == ( SourceLineInfo const& other ) const noexcept;
|
||||
|
@@ -183,6 +183,14 @@
|
||||
#endif
|
||||
#endif
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// Check if optional is available and usable
|
||||
#if defined(__has_include)
|
||||
# if __has_include(<optional>) && defined(CATCH_CPP17_OR_GREATER)
|
||||
# define CATCH_INTERNAL_CONFIG_CPP17_OPTIONAL
|
||||
# endif // __has_include(<optional>) && defined(CATCH_CPP17_OR_GREATER)
|
||||
#endif // __has_include
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// Check if variant is available and usable
|
||||
#if defined(__has_include)
|
||||
@@ -196,6 +204,8 @@
|
||||
# else
|
||||
# define CATCH_INTERNAL_CONFIG_CPP17_VARIANT
|
||||
# endif // defined(__GLIBCXX__) && defined(_GLIBCXX_RELEASE) && (_GLIBCXX_RELEASE < 9)
|
||||
# else
|
||||
# define CATCH_INTERNAL_CONFIG_CPP17_VARIANT
|
||||
# endif // defined(__clang__) && (__clang_major__ < 8)
|
||||
# endif // __has_include(<variant>) && defined(CATCH_CPP17_OR_GREATER)
|
||||
#endif // __has_include
|
||||
@@ -220,6 +230,10 @@
|
||||
# define CATCH_CONFIG_CPP11_TO_STRING
|
||||
#endif
|
||||
|
||||
#if defined(CATCH_INTERNAL_CONFIG_CPP17_OPTIONAL) && !defined(CATCH_CONFIG_NO_CPP17_OPTIONAL) && !defined(CATCH_CONFIG_CPP17_OPTIONAL)
|
||||
# define CATCH_CONFIG_CPP17_OPTIONAL
|
||||
#endif
|
||||
|
||||
#if defined(CATCH_INTERNAL_CONFIG_CPP17_UNCAUGHT_EXCEPTIONS) && !defined(CATCH_CONFIG_NO_CPP17_UNCAUGHT_EXCEPTIONS) && !defined(CATCH_CONFIG_CPP17_UNCAUGHT_EXCEPTIONS)
|
||||
# define CATCH_CONFIG_CPP17_UNCAUGHT_EXCEPTIONS
|
||||
#endif
|
||||
|
@@ -160,7 +160,8 @@ namespace {
|
||||
|
||||
private:
|
||||
void setColour( const char* _escapeCode ) {
|
||||
Catch::cout() << '\033' << _escapeCode;
|
||||
getCurrentContext().getConfig()->stream()
|
||||
<< '\033' << _escapeCode;
|
||||
}
|
||||
};
|
||||
|
||||
|
@@ -38,12 +38,9 @@ namespace Catch {
|
||||
#endif
|
||||
|
||||
#ifdef CATCH_TRAP
|
||||
#define CATCH_BREAK_INTO_DEBUGGER() if( Catch::isDebuggerActive() ) { CATCH_TRAP(); }
|
||||
#define CATCH_BREAK_INTO_DEBUGGER() []{ if( Catch::isDebuggerActive() ) { CATCH_TRAP(); } }()
|
||||
#else
|
||||
namespace Catch {
|
||||
inline void doNothing() {}
|
||||
}
|
||||
#define CATCH_BREAK_INTO_DEBUGGER() Catch::doNothing()
|
||||
#define CATCH_BREAK_INTO_DEBUGGER() []{}()
|
||||
#endif
|
||||
|
||||
#endif // TWOBLUECUBES_CATCH_DEBUGGER_H_INCLUDED
|
||||
|
@@ -10,6 +10,7 @@
|
||||
|
||||
#include "catch_tostring.h"
|
||||
#include "catch_stringref.h"
|
||||
#include "catch_meta.hpp"
|
||||
|
||||
#include <iosfwd>
|
||||
|
||||
@@ -19,6 +20,7 @@
|
||||
#pragma warning(disable:4018) // more "signed/unsigned mismatch"
|
||||
#pragma warning(disable:4312) // Converting int to T* using reinterpret_cast (issue on x64 platform)
|
||||
#pragma warning(disable:4180) // qualifier applied to function type has no meaning
|
||||
#pragma warning(disable:4800) // Forcing result to true or false
|
||||
#endif
|
||||
|
||||
namespace Catch {
|
||||
@@ -62,6 +64,62 @@ namespace Catch {
|
||||
m_op( op ),
|
||||
m_rhs( rhs )
|
||||
{}
|
||||
|
||||
template<typename T>
|
||||
auto operator && ( T ) const -> BinaryExpr<LhsT, RhsT const&> const {
|
||||
static_assert(always_false<T>::value,
|
||||
"chained comparisons are not supported inside assertions, "
|
||||
"wrap the expression inside parentheses, or decompose it");
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
auto operator || ( T ) const -> BinaryExpr<LhsT, RhsT const&> const {
|
||||
static_assert(always_false<T>::value,
|
||||
"chained comparisons are not supported inside assertions, "
|
||||
"wrap the expression inside parentheses, or decompose it");
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
auto operator == ( T ) const -> BinaryExpr<LhsT, RhsT const&> const {
|
||||
static_assert(always_false<T>::value,
|
||||
"chained comparisons are not supported inside assertions, "
|
||||
"wrap the expression inside parentheses, or decompose it");
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
auto operator != ( T ) const -> BinaryExpr<LhsT, RhsT const&> const {
|
||||
static_assert(always_false<T>::value,
|
||||
"chained comparisons are not supported inside assertions, "
|
||||
"wrap the expression inside parentheses, or decompose it");
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
auto operator > ( T ) const -> BinaryExpr<LhsT, RhsT const&> const {
|
||||
static_assert(always_false<T>::value,
|
||||
"chained comparisons are not supported inside assertions, "
|
||||
"wrap the expression inside parentheses, or decompose it");
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
auto operator < ( T ) const -> BinaryExpr<LhsT, RhsT const&> const {
|
||||
static_assert(always_false<T>::value,
|
||||
"chained comparisons are not supported inside assertions, "
|
||||
"wrap the expression inside parentheses, or decompose it");
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
auto operator >= ( T ) const -> BinaryExpr<LhsT, RhsT const&> const {
|
||||
static_assert(always_false<T>::value,
|
||||
"chained comparisons are not supported inside assertions, "
|
||||
"wrap the expression inside parentheses, or decompose it");
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
auto operator <= ( T ) const -> BinaryExpr<LhsT, RhsT const&> const {
|
||||
static_assert(always_false<T>::value,
|
||||
"chained comparisons are not supported inside assertions, "
|
||||
"wrap the expression inside parentheses, or decompose it");
|
||||
}
|
||||
};
|
||||
|
||||
template<typename LhsT>
|
||||
@@ -74,7 +132,7 @@ namespace Catch {
|
||||
|
||||
public:
|
||||
explicit UnaryExpr( LhsT lhs )
|
||||
: ITransientExpression{ false, lhs ? true : false },
|
||||
: ITransientExpression{ false, static_cast<bool>(lhs) },
|
||||
m_lhs( lhs )
|
||||
{}
|
||||
};
|
||||
@@ -143,6 +201,20 @@ namespace Catch {
|
||||
return { static_cast<bool>(m_lhs <= rhs), m_lhs, "<=", rhs };
|
||||
}
|
||||
|
||||
template<typename RhsT>
|
||||
auto operator && ( RhsT const& ) -> BinaryExpr<LhsT, RhsT const&> const {
|
||||
static_assert(always_false<RhsT>::value,
|
||||
"operator&& is not supported inside assertions, "
|
||||
"wrap the expression inside parentheses, or decompose it");
|
||||
}
|
||||
|
||||
template<typename RhsT>
|
||||
auto operator || ( RhsT const& ) -> BinaryExpr<LhsT, RhsT const&> const {
|
||||
static_assert(always_false<RhsT>::value,
|
||||
"operator|| is not supported inside assertions, "
|
||||
"wrap the expression inside parentheses, or decompose it");
|
||||
}
|
||||
|
||||
auto makeUnaryExpr() const -> UnaryExpr<LhsT> {
|
||||
return UnaryExpr<LhsT>{ m_lhs };
|
||||
}
|
||||
|
@@ -67,17 +67,23 @@ namespace Catch {
|
||||
}
|
||||
}
|
||||
|
||||
std::string ExceptionTranslatorRegistry::tryTranslators() const {
|
||||
if (m_translators.empty()) {
|
||||
std::rethrow_exception(std::current_exception());
|
||||
} else {
|
||||
return m_translators[0]->translate(m_translators.begin() + 1, m_translators.end());
|
||||
}
|
||||
}
|
||||
|
||||
#else // ^^ Exceptions are enabled // Exceptions are disabled vv
|
||||
std::string ExceptionTranslatorRegistry::translateActiveException() const {
|
||||
CATCH_INTERNAL_ERROR("Attempted to translate active exception under CATCH_CONFIG_DISABLE_EXCEPTIONS!");
|
||||
}
|
||||
|
||||
std::string ExceptionTranslatorRegistry::tryTranslators() const {
|
||||
CATCH_INTERNAL_ERROR("Attempted to use exception translators under CATCH_CONFIG_DISABLE_EXCEPTIONS!");
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
std::string ExceptionTranslatorRegistry::tryTranslators() const {
|
||||
if( m_translators.empty() )
|
||||
std::rethrow_exception(std::current_exception());
|
||||
else
|
||||
return m_translators[0]->translate( m_translators.begin()+1, m_translators.end() );
|
||||
}
|
||||
}
|
||||
|
@@ -16,35 +16,17 @@ namespace Catch {
|
||||
|
||||
IGeneratorTracker::~IGeneratorTracker() {}
|
||||
|
||||
const char* GeneratorException::what() const noexcept {
|
||||
return m_msg;
|
||||
}
|
||||
|
||||
namespace Generators {
|
||||
|
||||
GeneratorBase::~GeneratorBase() {}
|
||||
|
||||
std::vector<size_t> randomiseIndices( size_t selectionSize, size_t sourceSize ) {
|
||||
|
||||
assert( selectionSize <= sourceSize );
|
||||
std::vector<size_t> indices;
|
||||
indices.reserve( selectionSize );
|
||||
std::uniform_int_distribution<size_t> uid( 0, sourceSize-1 );
|
||||
|
||||
std::set<size_t> seen;
|
||||
// !TBD: improve this algorithm
|
||||
while( indices.size() < selectionSize ) {
|
||||
auto index = uid( rng() );
|
||||
if( seen.insert( index ).second )
|
||||
indices.push_back( index );
|
||||
}
|
||||
return indices;
|
||||
}
|
||||
GeneratorUntypedBase::~GeneratorUntypedBase() {}
|
||||
|
||||
auto acquireGeneratorTracker( SourceLineInfo const& lineInfo ) -> IGeneratorTracker& {
|
||||
return getResultCapture().acquireGeneratorTracker( lineInfo );
|
||||
}
|
||||
|
||||
template<>
|
||||
auto all<int>() -> Generator<int> {
|
||||
return range( std::numeric_limits<int>::min(), std::numeric_limits<int>::max() );
|
||||
}
|
||||
|
||||
} // namespace Generators
|
||||
} // namespace Catch
|
||||
|
@@ -16,8 +16,21 @@
|
||||
#include <cassert>
|
||||
|
||||
#include <utility>
|
||||
#include <exception>
|
||||
|
||||
namespace Catch {
|
||||
|
||||
class GeneratorException : public std::exception {
|
||||
const char* const m_msg = "";
|
||||
|
||||
public:
|
||||
GeneratorException(const char* msg):
|
||||
m_msg(msg)
|
||||
{}
|
||||
|
||||
const char* what() const noexcept override final;
|
||||
};
|
||||
|
||||
namespace Generators {
|
||||
|
||||
// !TBD move this into its own location?
|
||||
@@ -29,218 +42,159 @@ namespace Generators {
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
struct IGenerator {
|
||||
virtual ~IGenerator() {}
|
||||
virtual auto get( size_t index ) const -> T = 0;
|
||||
struct IGenerator : GeneratorUntypedBase {
|
||||
virtual ~IGenerator() = default;
|
||||
|
||||
// Returns the current element of the generator
|
||||
//
|
||||
// \Precondition The generator is either freshly constructed,
|
||||
// or the last call to `next()` returned true
|
||||
virtual T const& get() const = 0;
|
||||
using type = T;
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
class SingleValueGenerator : public IGenerator<T> {
|
||||
class SingleValueGenerator final : public IGenerator<T> {
|
||||
T m_value;
|
||||
public:
|
||||
SingleValueGenerator(T const& value) : m_value( value ) {}
|
||||
SingleValueGenerator(T&& value) : m_value(std::move(value)) {}
|
||||
|
||||
auto get( size_t ) const -> T override {
|
||||
T const& get() const override {
|
||||
return m_value;
|
||||
}
|
||||
bool next() override {
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
class FixedValuesGenerator : public IGenerator<T> {
|
||||
class FixedValuesGenerator final : public IGenerator<T> {
|
||||
std::vector<T> m_values;
|
||||
|
||||
size_t m_idx = 0;
|
||||
public:
|
||||
FixedValuesGenerator( std::initializer_list<T> values ) : m_values( values ) {}
|
||||
|
||||
auto get( size_t index ) const -> T override {
|
||||
return m_values[index];
|
||||
T const& get() const override {
|
||||
return m_values[m_idx];
|
||||
}
|
||||
bool next() override {
|
||||
++m_idx;
|
||||
return m_idx < m_values.size();
|
||||
}
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
class RangeGenerator : public IGenerator<T> {
|
||||
T const m_first;
|
||||
T const m_last;
|
||||
|
||||
public:
|
||||
RangeGenerator( T const& first, T const& last ) : m_first( first ), m_last( last ) {
|
||||
assert( m_last > m_first );
|
||||
}
|
||||
|
||||
auto get( size_t index ) const -> T override {
|
||||
// ToDo:: introduce a safe cast to catch potential overflows
|
||||
return static_cast<T>(m_first+index);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
template<typename T>
|
||||
struct NullGenerator : IGenerator<T> {
|
||||
auto get( size_t ) const -> T override {
|
||||
CATCH_INTERNAL_ERROR("A Null Generator is always empty");
|
||||
}
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
class Generator {
|
||||
class GeneratorWrapper final {
|
||||
std::unique_ptr<IGenerator<T>> m_generator;
|
||||
size_t m_size;
|
||||
|
||||
public:
|
||||
Generator( size_t size, std::unique_ptr<IGenerator<T>> generator )
|
||||
: m_generator( std::move( generator ) ),
|
||||
m_size( size )
|
||||
GeneratorWrapper(std::unique_ptr<IGenerator<T>> generator):
|
||||
m_generator(std::move(generator))
|
||||
{}
|
||||
|
||||
auto size() const -> size_t { return m_size; }
|
||||
auto operator[]( size_t index ) const -> T {
|
||||
assert( index < m_size );
|
||||
return m_generator->get( index );
|
||||
T const& get() const {
|
||||
return m_generator->get();
|
||||
}
|
||||
};
|
||||
|
||||
std::vector<size_t> randomiseIndices( size_t selectionSize, size_t sourceSize );
|
||||
|
||||
template<typename T>
|
||||
class GeneratorRandomiser : public IGenerator<T> {
|
||||
Generator<T> m_baseGenerator;
|
||||
|
||||
std::vector<size_t> m_indices;
|
||||
public:
|
||||
GeneratorRandomiser( Generator<T>&& baseGenerator, size_t numberOfItems )
|
||||
: m_baseGenerator( std::move( baseGenerator ) ),
|
||||
m_indices( randomiseIndices( numberOfItems, m_baseGenerator.size() ) )
|
||||
{}
|
||||
|
||||
auto get( size_t index ) const -> T override {
|
||||
return m_baseGenerator[m_indices[index]];
|
||||
bool next() {
|
||||
return m_generator->next();
|
||||
}
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
struct RequiresASpecialisationFor;
|
||||
|
||||
GeneratorWrapper<T> value(T&& value) {
|
||||
return GeneratorWrapper<T>(pf::make_unique<SingleValueGenerator<T>>(std::forward<T>(value)));
|
||||
}
|
||||
template <typename T>
|
||||
auto all() -> Generator<T> { return RequiresASpecialisationFor<T>(); }
|
||||
|
||||
template<>
|
||||
auto all<int>() -> Generator<int>;
|
||||
|
||||
|
||||
template<typename T>
|
||||
auto range( T const& first, T const& last ) -> Generator<T> {
|
||||
return Generator<T>( (last-first), pf::make_unique<RangeGenerator<T>>( first, last ) );
|
||||
GeneratorWrapper<T> values(std::initializer_list<T> values) {
|
||||
return GeneratorWrapper<T>(pf::make_unique<FixedValuesGenerator<T>>(values));
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
auto random( T const& first, T const& last ) -> Generator<T> {
|
||||
auto gen = range( first, last );
|
||||
auto size = gen.size();
|
||||
class Generators : public IGenerator<T> {
|
||||
std::vector<GeneratorWrapper<T>> m_generators;
|
||||
size_t m_current = 0;
|
||||
|
||||
return Generator<T>( size, pf::make_unique<GeneratorRandomiser<T>>( std::move( gen ), size ) );
|
||||
void populate(GeneratorWrapper<T>&& generator) {
|
||||
m_generators.emplace_back(std::move(generator));
|
||||
}
|
||||
template<typename T>
|
||||
auto random( size_t size ) -> Generator<T> {
|
||||
return Generator<T>( size, pf::make_unique<GeneratorRandomiser<T>>( all<T>(), size ) );
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
auto values( std::initializer_list<T> values ) -> Generator<T> {
|
||||
return Generator<T>( values.size(), pf::make_unique<FixedValuesGenerator<T>>( values ) );
|
||||
}
|
||||
template<typename T>
|
||||
auto value( T const& val ) -> Generator<T> {
|
||||
return Generator<T>( 1, pf::make_unique<SingleValueGenerator<T>>( val ) );
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
auto as() -> Generator<T> {
|
||||
return Generator<T>( 0, pf::make_unique<NullGenerator<T>>() );
|
||||
}
|
||||
|
||||
template<typename... Ts>
|
||||
auto table( std::initializer_list<std::tuple<Ts...>>&& tuples ) -> Generator<std::tuple<Ts...>> {
|
||||
return values<std::tuple<Ts...>>( std::forward<std::initializer_list<std::tuple<Ts...>>>( tuples ) );
|
||||
}
|
||||
|
||||
|
||||
template<typename T>
|
||||
struct Generators : GeneratorBase {
|
||||
std::vector<Generator<T>> m_generators;
|
||||
|
||||
using type = T;
|
||||
|
||||
Generators() : GeneratorBase( 0 ) {}
|
||||
|
||||
void populate(T&& val) {
|
||||
m_size += 1;
|
||||
m_generators.emplace_back(value(std::move(val)));
|
||||
}
|
||||
template<typename U>
|
||||
void populate(U&& val) {
|
||||
populate(T(std::move(val)));
|
||||
}
|
||||
void populate( Generator<T>&& generator ) {
|
||||
m_size += generator.size();
|
||||
m_generators.emplace_back( std::move( generator ) );
|
||||
}
|
||||
|
||||
template<typename U, typename... Gs>
|
||||
void populate(U&& valueOrGenerator, Gs... moreGenerators) {
|
||||
populate(std::forward<U>(valueOrGenerator));
|
||||
populate(std::forward<Gs>(moreGenerators)...);
|
||||
}
|
||||
|
||||
auto operator[]( size_t index ) const -> T {
|
||||
size_t sizes = 0;
|
||||
for( auto const& gen : m_generators ) {
|
||||
auto localIndex = index-sizes;
|
||||
sizes += gen.size();
|
||||
if( index < sizes )
|
||||
return gen[localIndex];
|
||||
public:
|
||||
template <typename... Gs>
|
||||
Generators(Gs... moreGenerators) {
|
||||
m_generators.reserve(sizeof...(Gs));
|
||||
populate(std::forward<Gs>(moreGenerators)...);
|
||||
}
|
||||
CATCH_INTERNAL_ERROR("Index '" << index << "' is out of range (" << sizes << ')');
|
||||
|
||||
T const& get() const override {
|
||||
return m_generators[m_current].get();
|
||||
}
|
||||
|
||||
bool next() override {
|
||||
if (m_current >= m_generators.size()) {
|
||||
return false;
|
||||
}
|
||||
const bool current_status = m_generators[m_current].next();
|
||||
if (!current_status) {
|
||||
++m_current;
|
||||
}
|
||||
return m_current < m_generators.size();
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
template<typename... Ts>
|
||||
GeneratorWrapper<std::tuple<Ts...>> table( std::initializer_list<std::tuple<typename std::decay<Ts>::type...>> tuples ) {
|
||||
return values<std::tuple<Ts...>>( tuples );
|
||||
}
|
||||
|
||||
// Tag type to signal that a generator sequence should convert arguments to a specific type
|
||||
template <typename T>
|
||||
struct as {};
|
||||
|
||||
template<typename T, typename... Gs>
|
||||
auto makeGenerators( Generator<T>&& generator, Gs... moreGenerators ) -> Generators<T> {
|
||||
Generators<T> generators;
|
||||
generators.m_generators.reserve( 1+sizeof...(Gs) );
|
||||
generators.populate( std::move( generator ), std::forward<Gs>( moreGenerators )... );
|
||||
return generators;
|
||||
auto makeGenerators( GeneratorWrapper<T>&& generator, Gs... moreGenerators ) -> Generators<T> {
|
||||
return Generators<T>(std::move(generator), std::forward<Gs>(moreGenerators)...);
|
||||
}
|
||||
template<typename T>
|
||||
auto makeGenerators( Generator<T>&& generator ) -> Generators<T> {
|
||||
Generators<T> generators;
|
||||
generators.populate( std::move( generator ) );
|
||||
return generators;
|
||||
auto makeGenerators( GeneratorWrapper<T>&& generator ) -> Generators<T> {
|
||||
return Generators<T>(std::move(generator));
|
||||
}
|
||||
template<typename T, typename... Gs>
|
||||
auto makeGenerators( T&& val, Gs... moreGenerators ) -> Generators<T> {
|
||||
return makeGenerators( value( std::forward<T>( val ) ), std::forward<Gs>( moreGenerators )... );
|
||||
}
|
||||
template<typename T, typename U, typename... Gs>
|
||||
auto makeGenerators( U&& val, Gs... moreGenerators ) -> Generators<T> {
|
||||
auto makeGenerators( as<T>, U&& val, Gs... moreGenerators ) -> Generators<T> {
|
||||
return makeGenerators( value( T( std::forward<U>( val ) ) ), std::forward<Gs>( moreGenerators )... );
|
||||
}
|
||||
|
||||
|
||||
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, ¯\_(ツ)_/¯
|
||||
auto generate( SourceLineInfo const& lineInfo, L const& generatorExpression ) -> decltype(std::declval<decltype(generatorExpression())>()[0]) {
|
||||
// return type. Yeah.
|
||||
auto generate( SourceLineInfo const& lineInfo, L const& generatorExpression ) -> decltype(std::declval<decltype(generatorExpression())>().get()) {
|
||||
using UnderlyingType = typename decltype(generatorExpression())::type;
|
||||
|
||||
IGeneratorTracker& tracker = acquireGeneratorTracker( lineInfo );
|
||||
if( !tracker.hasGenerator() )
|
||||
if (!tracker.hasGenerator()) {
|
||||
tracker.setGenerator(pf::make_unique<Generators<UnderlyingType>>(generatorExpression()));
|
||||
}
|
||||
|
||||
auto const& generator = static_cast<Generators<UnderlyingType> const&>( *tracker.getGenerator() );
|
||||
return generator[tracker.getIndex()];
|
||||
auto const& generator = static_cast<IGenerator<UnderlyingType> const&>( *tracker.getGenerator() );
|
||||
return generator.get();
|
||||
}
|
||||
|
||||
} // namespace Generators
|
||||
|
230
include/internal/catch_generators_generic.hpp
Normal file
230
include/internal/catch_generators_generic.hpp
Normal file
@@ -0,0 +1,230 @@
|
||||
/*
|
||||
* 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;
|
||||
}
|
||||
};
|
||||
|
||||
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))
|
||||
);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
class ChunkGenerator final : public IGenerator<std::vector<T>> {
|
||||
std::vector<T> m_chunk;
|
||||
size_t m_chunk_size;
|
||||
GeneratorWrapper<T> m_generator;
|
||||
bool m_used_up = false;
|
||||
public:
|
||||
ChunkGenerator(size_t size, GeneratorWrapper<T> generator) :
|
||||
m_chunk_size(size), m_generator(std::move(generator))
|
||||
{
|
||||
m_chunk.reserve(m_chunk_size);
|
||||
m_chunk.push_back(m_generator.get());
|
||||
for (size_t i = 1; i < m_chunk_size; ++i) {
|
||||
if (!m_generator.next()) {
|
||||
Catch::throw_exception(GeneratorException("Not enough values to initialize the first chunk"));
|
||||
}
|
||||
m_chunk.push_back(m_generator.get());
|
||||
}
|
||||
}
|
||||
std::vector<T> const& get() const override {
|
||||
return m_chunk;
|
||||
}
|
||||
bool next() override {
|
||||
m_chunk.clear();
|
||||
for (size_t idx = 0; idx < m_chunk_size; ++idx) {
|
||||
if (!m_generator.next()) {
|
||||
return false;
|
||||
}
|
||||
m_chunk.push_back(m_generator.get());
|
||||
}
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
GeneratorWrapper<std::vector<T>> chunk(size_t size, GeneratorWrapper<T>&& generator) {
|
||||
return GeneratorWrapper<std::vector<T>>(
|
||||
pf::make_unique<ChunkGenerator<T>>(size, std::move(generator))
|
||||
);
|
||||
}
|
||||
|
||||
} // namespace Generators
|
||||
} // namespace Catch
|
||||
|
||||
|
||||
#endif // TWOBLUECUBES_CATCH_GENERATORS_GENERIC_HPP_INCLUDED
|
135
include/internal/catch_generators_specific.hpp
Normal file
135
include/internal/catch_generators_specific.hpp
Normal file
@@ -0,0 +1,135 @@
|
||||
/*
|
||||
* Created by Martin on 15/6/2018.
|
||||
*
|
||||
* Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
* file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
*/
|
||||
#ifndef TWOBLUECUBES_CATCH_GENERATORS_SPECIFIC_HPP_INCLUDED
|
||||
#define TWOBLUECUBES_CATCH_GENERATORS_SPECIFIC_HPP_INCLUDED
|
||||
|
||||
#include "catch_context.h"
|
||||
#include "catch_generators.hpp"
|
||||
#include "catch_interfaces_config.h"
|
||||
|
||||
#include <random>
|
||||
|
||||
namespace Catch {
|
||||
namespace Generators {
|
||||
|
||||
template <typename Float>
|
||||
class RandomFloatingGenerator final : public IGenerator<Float> {
|
||||
// FIXME: What is the right seed?
|
||||
std::minstd_rand m_rand;
|
||||
std::uniform_real_distribution<Float> m_dist;
|
||||
Float m_current_number;
|
||||
public:
|
||||
|
||||
RandomFloatingGenerator(Float a, Float b):
|
||||
m_rand(getCurrentContext().getConfig()->rngSeed()),
|
||||
m_dist(a, b) {
|
||||
static_cast<void>(next());
|
||||
}
|
||||
|
||||
Float const& get() const override {
|
||||
return m_current_number;
|
||||
}
|
||||
bool next() override {
|
||||
m_current_number = m_dist(m_rand);
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
template <typename Integer>
|
||||
class RandomIntegerGenerator final : public IGenerator<Integer> {
|
||||
std::minstd_rand m_rand;
|
||||
std::uniform_int_distribution<Integer> m_dist;
|
||||
Integer m_current_number;
|
||||
public:
|
||||
|
||||
RandomIntegerGenerator(Integer a, Integer b):
|
||||
m_rand(getCurrentContext().getConfig()->rngSeed()),
|
||||
m_dist(a, b) {
|
||||
static_cast<void>(next());
|
||||
}
|
||||
|
||||
Integer const& get() const override {
|
||||
return m_current_number;
|
||||
}
|
||||
bool next() override {
|
||||
m_current_number = m_dist(m_rand);
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
// TODO: Ideally this would be also constrained against the various char types,
|
||||
// but I don't expect users to run into that in practice.
|
||||
template <typename T>
|
||||
typename std::enable_if<std::is_integral<T>::value && !std::is_same<T, bool>::value,
|
||||
GeneratorWrapper<T>>::type
|
||||
random(T a, T b) {
|
||||
return GeneratorWrapper<T>(
|
||||
pf::make_unique<RandomIntegerGenerator<T>>(a, b)
|
||||
);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
typename std::enable_if<std::is_floating_point<T>::value,
|
||||
GeneratorWrapper<T>>::type
|
||||
random(T a, T b) {
|
||||
return GeneratorWrapper<T>(
|
||||
pf::make_unique<RandomFloatingGenerator<T>>(a, b)
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
template <typename T>
|
||||
class RangeGenerator final : public IGenerator<T> {
|
||||
T m_current;
|
||||
T m_end;
|
||||
T m_step;
|
||||
bool m_positive;
|
||||
|
||||
public:
|
||||
RangeGenerator(T const& start, T const& end, T const& step):
|
||||
m_current(start),
|
||||
m_end(end),
|
||||
m_step(step),
|
||||
m_positive(m_step > T(0))
|
||||
{
|
||||
assert(m_current != m_end && "Range start and end cannot be equal");
|
||||
assert(m_step != T(0) && "Step size cannot be zero");
|
||||
assert(((m_positive && m_current <= m_end) || (!m_positive && m_current >= m_end)) && "Step moves away from end");
|
||||
}
|
||||
|
||||
RangeGenerator(T const& start, T const& end):
|
||||
RangeGenerator(start, end, (start < end) ? T(1) : T(-1))
|
||||
{}
|
||||
|
||||
T const& get() const override {
|
||||
return m_current;
|
||||
}
|
||||
|
||||
bool next() override {
|
||||
m_current += m_step;
|
||||
return (m_positive) ? (m_current < m_end) : (m_current > m_end);
|
||||
}
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
GeneratorWrapper<T> range(T const& start, T const& end, T const& step) {
|
||||
static_assert(std::is_integral<T>::value && !std::is_same<T, bool>::value, "Type must be an integer");
|
||||
return GeneratorWrapper<T>(pf::make_unique<RangeGenerator<T>>(start, end, step));
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
GeneratorWrapper<T> range(T const& start, T const& end) {
|
||||
static_assert(std::is_integral<T>::value && !std::is_same<T, bool>::value, "Type must be an integer");
|
||||
return GeneratorWrapper<T>(pf::make_unique<RangeGenerator<T>>(start, end));
|
||||
}
|
||||
|
||||
|
||||
} // namespace Generators
|
||||
} // namespace Catch
|
||||
|
||||
|
||||
#endif // TWOBLUECUBES_CATCH_GENERATORS_SPECIFIC_HPP_INCLUDED
|
@@ -20,6 +20,7 @@ namespace Catch {
|
||||
struct SectionInfo;
|
||||
struct SectionEndInfo;
|
||||
struct MessageInfo;
|
||||
struct MessageBuilder;
|
||||
struct Counts;
|
||||
struct BenchmarkInfo;
|
||||
struct BenchmarkStats;
|
||||
@@ -46,6 +47,8 @@ namespace Catch {
|
||||
virtual void pushScopedMessage( MessageInfo const& message ) = 0;
|
||||
virtual void popScopedMessage( MessageInfo const& message ) = 0;
|
||||
|
||||
virtual void emplaceUnscopedMessage( MessageBuilder const& builder ) = 0;
|
||||
|
||||
virtual void handleFatalErrorCondition( StringRef message ) = 0;
|
||||
|
||||
virtual void handleExpr
|
||||
|
@@ -13,16 +13,17 @@
|
||||
namespace Catch {
|
||||
|
||||
namespace Generators {
|
||||
class GeneratorBase {
|
||||
protected:
|
||||
size_t m_size = 0;
|
||||
|
||||
class GeneratorUntypedBase {
|
||||
public:
|
||||
GeneratorBase( size_t size ) : m_size( size ) {}
|
||||
virtual ~GeneratorBase();
|
||||
auto size() const -> size_t { return m_size; }
|
||||
GeneratorUntypedBase() = default;
|
||||
virtual ~GeneratorUntypedBase();
|
||||
// Attempts to move the generator to the next element
|
||||
//
|
||||
// Returns true iff the move succeeded (and a valid element
|
||||
// can be retrieved).
|
||||
virtual bool next() = 0;
|
||||
};
|
||||
using GeneratorBasePtr = std::unique_ptr<GeneratorBase>;
|
||||
using GeneratorBasePtr = std::unique_ptr<GeneratorUntypedBase>;
|
||||
|
||||
} // namespace Generators
|
||||
|
||||
@@ -31,7 +32,6 @@ namespace Catch {
|
||||
virtual auto hasGenerator() const -> bool = 0;
|
||||
virtual auto getGenerator() const -> Generators::GeneratorBasePtr const& = 0;
|
||||
virtual void setGenerator( Generators::GeneratorBasePtr&& generator ) = 0;
|
||||
virtual auto getIndex() const -> std::size_t = 0;
|
||||
};
|
||||
|
||||
} // namespace Catch
|
||||
|
@@ -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;
|
||||
|
@@ -9,7 +9,6 @@
|
||||
#define TWOBLUECUBES_CATCH_INTERFACES_TESTCASE_H_INCLUDED
|
||||
|
||||
#include <vector>
|
||||
#include <memory>
|
||||
|
||||
namespace Catch {
|
||||
|
||||
@@ -20,8 +19,6 @@ namespace Catch {
|
||||
virtual ~ITestInvoker();
|
||||
};
|
||||
|
||||
using ITestCasePtr = std::shared_ptr<ITestInvoker>;
|
||||
|
||||
class TestCase;
|
||||
struct IConfig;
|
||||
|
||||
|
@@ -12,6 +12,7 @@
|
||||
#include "catch_interfaces_reporter.h"
|
||||
#include "catch_interfaces_testcase.h"
|
||||
|
||||
#include "catch_context.h"
|
||||
#include "catch_stream.h"
|
||||
#include "catch_text.h"
|
||||
|
||||
@@ -146,15 +147,16 @@ namespace Catch {
|
||||
return factories.size();
|
||||
}
|
||||
|
||||
Option<std::size_t> list( Config const& config ) {
|
||||
Option<std::size_t> list( std::shared_ptr<Config> const& config ) {
|
||||
Option<std::size_t> listedCount;
|
||||
if( config.listTests() )
|
||||
listedCount = listedCount.valueOr(0) + listTests( config );
|
||||
if( config.listTestNamesOnly() )
|
||||
listedCount = listedCount.valueOr(0) + listTestsNamesOnly( config );
|
||||
if( config.listTags() )
|
||||
listedCount = listedCount.valueOr(0) + listTags( config );
|
||||
if( config.listReporters() )
|
||||
getCurrentMutableContext().setConfig( config );
|
||||
if( config->listTests() )
|
||||
listedCount = listedCount.valueOr(0) + listTests( *config );
|
||||
if( config->listTestNamesOnly() )
|
||||
listedCount = listedCount.valueOr(0) + listTestsNamesOnly( *config );
|
||||
if( config->listTags() )
|
||||
listedCount = listedCount.valueOr(0) + listTags( *config );
|
||||
if( config->listReporters() )
|
||||
listedCount = listedCount.valueOr(0) + listReporters();
|
||||
return listedCount;
|
||||
}
|
||||
|
@@ -31,7 +31,7 @@ namespace Catch {
|
||||
|
||||
std::size_t listReporters();
|
||||
|
||||
Option<std::size_t> list( Config const& config );
|
||||
Option<std::size_t> list( std::shared_ptr<Config> const& config );
|
||||
|
||||
} // end namespace Catch
|
||||
|
||||
|
@@ -47,14 +47,20 @@ namespace Catch {
|
||||
|
||||
|
||||
ScopedMessage::ScopedMessage( MessageBuilder const& builder )
|
||||
: m_info( builder.m_info )
|
||||
: m_info( builder.m_info ), m_moved()
|
||||
{
|
||||
m_info.message = builder.m_stream.str();
|
||||
getResultCapture().pushScopedMessage( m_info );
|
||||
}
|
||||
|
||||
ScopedMessage::ScopedMessage( ScopedMessage&& old )
|
||||
: m_info( old.m_info ), m_moved()
|
||||
{
|
||||
old.m_moved = true;
|
||||
}
|
||||
|
||||
ScopedMessage::~ScopedMessage() {
|
||||
if ( !uncaught_exceptions() ){
|
||||
if ( !uncaught_exceptions() && !m_moved ){
|
||||
getResultCapture().popScopedMessage(m_info);
|
||||
}
|
||||
}
|
||||
|
@@ -64,9 +64,12 @@ namespace Catch {
|
||||
class ScopedMessage {
|
||||
public:
|
||||
explicit ScopedMessage( MessageBuilder const& builder );
|
||||
ScopedMessage( ScopedMessage& duplicate ) = delete;
|
||||
ScopedMessage( ScopedMessage&& old );
|
||||
~ScopedMessage();
|
||||
|
||||
MessageInfo m_info;
|
||||
bool m_moved;
|
||||
};
|
||||
|
||||
class Capturer {
|
||||
|
77
include/internal/catch_meta.hpp
Normal file
77
include/internal/catch_meta.hpp
Normal file
@@ -0,0 +1,77 @@
|
||||
/*
|
||||
* Created by Jozef on 02/12/2018.
|
||||
* Copyright 2018 Two Blue Cubes Ltd. All rights reserved.
|
||||
*
|
||||
* Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
* file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
*/
|
||||
|
||||
#ifndef TWOBLUECUBES_CATCH_META_HPP_INCLUDED
|
||||
#define TWOBLUECUBES_CATCH_META_HPP_INCLUDED
|
||||
|
||||
#include <type_traits>
|
||||
|
||||
namespace Catch {
|
||||
template< typename... >
|
||||
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...>;
|
||||
};
|
||||
|
||||
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;
|
||||
};
|
||||
|
||||
template< template<typename...> class
|
||||
, typename...
|
||||
>
|
||||
struct rewrap;
|
||||
|
||||
template< template<typename...> class Container
|
||||
, 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...> {
|
||||
using type = typename append<TypeList<Container<Elems...>>, typename rewrap<Container, Elements...>::type>::type;
|
||||
};
|
||||
|
||||
template< template<typename...> class...Containers >
|
||||
struct combine {
|
||||
template< typename...Types >
|
||||
struct with_types {
|
||||
template< template <typename...> class Final >
|
||||
struct into {
|
||||
using type = typename append<Final<>, typename rewrap<Containers, Types...>::type...>::type;
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
struct always_false : std::false_type {};
|
||||
|
||||
} // namespace Catch
|
||||
|
||||
#endif // TWOBLUECUBES_CATCH_META_HPP_INCLUDED
|
@@ -49,6 +49,15 @@ namespace Catch {
|
||||
{}
|
||||
auto RedirectedStdErr::str() const -> std::string { return m_rss.str(); }
|
||||
|
||||
RedirectedStreams::RedirectedStreams(std::string& redirectedCout, std::string& redirectedCerr)
|
||||
: m_redirectedCout(redirectedCout),
|
||||
m_redirectedCerr(redirectedCerr)
|
||||
{}
|
||||
|
||||
RedirectedStreams::~RedirectedStreams() {
|
||||
m_redirectedCout += m_redirectedStdOut.str();
|
||||
m_redirectedCerr += m_redirectedStdErr.str();
|
||||
}
|
||||
|
||||
#if defined(CATCH_CONFIG_NEW_CAPTURE)
|
||||
|
||||
|
@@ -46,6 +46,21 @@ namespace Catch {
|
||||
auto str() const -> std::string;
|
||||
};
|
||||
|
||||
class RedirectedStreams {
|
||||
public:
|
||||
RedirectedStreams(RedirectedStreams const&) = delete;
|
||||
RedirectedStreams& operator=(RedirectedStreams const&) = delete;
|
||||
RedirectedStreams(RedirectedStreams&&) = delete;
|
||||
RedirectedStreams& operator=(RedirectedStreams&&) = delete;
|
||||
|
||||
RedirectedStreams(std::string& redirectedCout, std::string& redirectedCerr);
|
||||
~RedirectedStreams();
|
||||
private:
|
||||
std::string& m_redirectedCout;
|
||||
std::string& m_redirectedCerr;
|
||||
RedirectedStdOut m_redirectedStdOut;
|
||||
RedirectedStdErr m_redirectedStdErr;
|
||||
};
|
||||
|
||||
#if defined(CATCH_CONFIG_NEW_CAPTURE)
|
||||
|
||||
|
@@ -57,6 +57,16 @@
|
||||
#define INTERNAL_CATCH_EXPAND2(...) INTERNAL_CATCH_NO## __VA_ARGS__
|
||||
#define INTERNAL_CATCH_DEF(...) INTERNAL_CATCH_DEF __VA_ARGS__
|
||||
#define INTERNAL_CATCH_NOINTERNAL_CATCH_DEF
|
||||
#define INTERNAL_CATCH_STRINGIZE(...) INTERNAL_CATCH_STRINGIZE2(__VA_ARGS__)
|
||||
#ifndef CATCH_CONFIG_TRADITIONAL_MSVC_PREPROCESSOR
|
||||
#define INTERNAL_CATCH_STRINGIZE2(...) #__VA_ARGS__
|
||||
#define INTERNAL_CATCH_STRINGIZE_WITHOUT_PARENS(param) INTERNAL_CATCH_STRINGIZE(INTERNAL_CATCH_REMOVE_PARENS(param))
|
||||
#else
|
||||
// MSVC is adding extra space and needs another indirection to expand INTERNAL_CATCH_NOINTERNAL_CATCH_DEF
|
||||
#define INTERNAL_CATCH_STRINGIZE2(...) INTERNAL_CATCH_STRINGIZE3(__VA_ARGS__)
|
||||
#define INTERNAL_CATCH_STRINGIZE3(...) #__VA_ARGS__
|
||||
#define INTERNAL_CATCH_STRINGIZE_WITHOUT_PARENS(param) (INTERNAL_CATCH_STRINGIZE(INTERNAL_CATCH_REMOVE_PARENS(param)) + 1)
|
||||
#endif
|
||||
|
||||
#define INTERNAL_CATCH_REMOVE_PARENS(...) INTERNAL_CATCH_EXPAND1(INTERNAL_CATCH_DEF __VA_ARGS__)
|
||||
|
||||
@@ -71,4 +81,9 @@
|
||||
#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) 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))
|
||||
|
||||
#endif // TWOBLUECUBES_CATCH_PREPROCESSOR_HPP_INCLUDED
|
||||
|
@@ -14,7 +14,6 @@ namespace Catch {
|
||||
|
||||
namespace Generators {
|
||||
struct GeneratorTracker : TestCaseTracking::TrackerBase, IGeneratorTracker {
|
||||
size_t m_index = static_cast<size_t>( -1 );
|
||||
GeneratorBasePtr m_generator;
|
||||
|
||||
GeneratorTracker( TestCaseTracking::NameAndLocation const& nameAndLocation, TrackerContext& ctx, ITracker* parent )
|
||||
@@ -28,7 +27,7 @@ namespace Catch {
|
||||
ITracker& currentTracker = ctx.currentTracker();
|
||||
if( TestCaseTracking::ITrackerPtr childTracker = currentTracker.findChild( nameAndLocation ) ) {
|
||||
assert( childTracker );
|
||||
assert( childTracker->isIndexTracker() );
|
||||
assert( childTracker->isGeneratorTracker() );
|
||||
tracker = std::static_pointer_cast<GeneratorTracker>( childTracker );
|
||||
}
|
||||
else {
|
||||
@@ -37,29 +36,25 @@ namespace Catch {
|
||||
}
|
||||
|
||||
if( !ctx.completedCycle() && !tracker->isComplete() ) {
|
||||
if( tracker->m_runState != ExecutingChildren && tracker->m_runState != NeedsAnotherRun )
|
||||
tracker->moveNext();
|
||||
tracker->open();
|
||||
}
|
||||
|
||||
return *tracker;
|
||||
}
|
||||
|
||||
void moveNext() {
|
||||
m_index++;
|
||||
m_children.clear();
|
||||
}
|
||||
|
||||
// TrackerBase interface
|
||||
bool isIndexTracker() const override { return true; }
|
||||
bool isGeneratorTracker() const override { return true; }
|
||||
auto hasGenerator() const -> bool override {
|
||||
return !!m_generator;
|
||||
}
|
||||
void close() override {
|
||||
TrackerBase::close();
|
||||
if( m_runState == CompletedSuccessfully && m_index < m_generator->size()-1 )
|
||||
// Generator interface only finds out if it has another item on atual move
|
||||
if (m_runState == CompletedSuccessfully && m_generator->next()) {
|
||||
m_children.clear();
|
||||
m_runState = Executing;
|
||||
}
|
||||
}
|
||||
|
||||
// IGeneratorTracker interface
|
||||
auto getGenerator() const -> GeneratorBasePtr const& override {
|
||||
@@ -68,14 +63,10 @@ namespace Catch {
|
||||
void setGenerator( GeneratorBasePtr&& generator ) override {
|
||||
m_generator = std::move( generator );
|
||||
}
|
||||
auto getIndex() const -> size_t override {
|
||||
return m_index;
|
||||
}
|
||||
};
|
||||
GeneratorTracker::~GeneratorTracker() {}
|
||||
}
|
||||
|
||||
|
||||
RunContext::RunContext(IConfigPtr const& _config, IStreamingReporterPtr&& reporter)
|
||||
: m_runInfo(_config->name()),
|
||||
m_context(getCurrentMutableContext()),
|
||||
@@ -170,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;
|
||||
@@ -224,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) {
|
||||
@@ -250,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
|
||||
@@ -310,6 +309,7 @@ namespace Catch {
|
||||
m_lastAssertionPassed = true;
|
||||
++m_totals.assertions.passed;
|
||||
resetAssertionInfo();
|
||||
m_messageScopes.clear();
|
||||
}
|
||||
|
||||
bool RunContext::aborting() const {
|
||||
@@ -331,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();
|
||||
@@ -364,6 +361,7 @@ namespace Catch {
|
||||
m_testCaseTracker->close();
|
||||
handleUnfinishedSections();
|
||||
m_messages.clear();
|
||||
m_messageScopes.clear();
|
||||
|
||||
SectionStats testCaseSectionStats(testCaseSection, assertions, duration, missingAssertions);
|
||||
m_reporter->sectionEnded(testCaseSectionStats);
|
||||
|
@@ -88,6 +88,8 @@ namespace Catch {
|
||||
void pushScopedMessage( MessageInfo const& message ) override;
|
||||
void popScopedMessage( MessageInfo const& message ) override;
|
||||
|
||||
void emplaceUnscopedMessage( MessageBuilder const& builder ) override;
|
||||
|
||||
std::string getCurrentTestName() const override;
|
||||
|
||||
const AssertionResult* getLastResult() const override;
|
||||
@@ -128,13 +130,14 @@ namespace Catch {
|
||||
TestRunInfo m_runInfo;
|
||||
IMutableContext& m_context;
|
||||
TestCase const* m_activeTestCase = nullptr;
|
||||
ITracker* m_testCaseTracker;
|
||||
ITracker* m_testCaseTracker = nullptr;
|
||||
Option<AssertionResult> m_lastResult;
|
||||
|
||||
IConfigPtr m_config;
|
||||
Totals m_totals;
|
||||
IStreamingReporterPtr m_reporter;
|
||||
std::vector<MessageInfo> m_messages;
|
||||
std::vector<ScopedMessage> m_messageScopes; /* Keeps owners of so-called unscoped messages. */
|
||||
AssertionInfo m_lastAssertionInfo;
|
||||
std::vector<SectionEndInfo> m_unfinishedSections;
|
||||
std::vector<ITracker*> m_activeSections;
|
||||
|
@@ -10,6 +10,7 @@
|
||||
#include "catch_console_colour.h"
|
||||
#include "catch_enforce.h"
|
||||
#include "catch_list.h"
|
||||
#include "catch_context.h"
|
||||
#include "catch_run_context.h"
|
||||
#include "catch_stream.h"
|
||||
#include "catch_test_spec.h"
|
||||
@@ -42,14 +43,19 @@ namespace Catch {
|
||||
return createReporter(config->getReporterName(), config);
|
||||
}
|
||||
|
||||
auto multi = std::unique_ptr<ListeningReporter>(new ListeningReporter);
|
||||
|
||||
// On older platforms, returning std::unique_ptr<ListeningReporter>
|
||||
// when the return type is std::unique_ptr<IStreamingReporter>
|
||||
// doesn't compile without a std::move call. However, this causes
|
||||
// a warning on newer platforms. Thus, we have to work around
|
||||
// it a bit and downcast the pointer manually.
|
||||
auto ret = std::unique_ptr<IStreamingReporter>(new ListeningReporter);
|
||||
auto& multi = static_cast<ListeningReporter&>(*ret);
|
||||
auto const& listeners = Catch::getRegistryHub().getReporterRegistry().getListeners();
|
||||
for (auto const& listener : listeners) {
|
||||
multi->addListener(listener->create(Catch::ReporterConfig(config)));
|
||||
multi.addListener(listener->create(Catch::ReporterConfig(config)));
|
||||
}
|
||||
multi->addReporter(createReporter(config->getReporterName(), config));
|
||||
return std::move(multi);
|
||||
multi.addReporter(createReporter(config->getReporterName(), config));
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
@@ -166,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"
|
||||
@@ -257,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 );
|
||||
|
@@ -13,8 +13,6 @@
|
||||
|
||||
namespace Catch {
|
||||
|
||||
class StringData;
|
||||
|
||||
/// A non-owning string class (similar to the forthcoming std::string_view)
|
||||
/// Note that, because a StringRef may be a substring of another string,
|
||||
/// it may not be null terminated. c_str() must return a null terminated
|
||||
|
@@ -16,10 +16,11 @@
|
||||
# pragma clang diagnostic ignored "-Wcovered-switch-default"
|
||||
# endif
|
||||
#elif defined __GNUC__
|
||||
// GCC likes to warn on REQUIREs, and we cannot suppress them
|
||||
// locally because g++'s support for _Pragma is lacking in older,
|
||||
// still supported, versions
|
||||
# pragma GCC diagnostic ignored "-Wparentheses"
|
||||
// Because REQUIREs trigger GCC's -Wparentheses, and because still
|
||||
// supported version of g++ have only buggy support for _Pragmas,
|
||||
// Wparentheses have to be suppressed globally.
|
||||
# pragma GCC diagnostic ignored "-Wparentheses" // See #674 for details
|
||||
|
||||
# pragma GCC diagnostic push
|
||||
# pragma GCC diagnostic ignored "-Wunused-variable"
|
||||
# pragma GCC diagnostic ignored "-Wpadded"
|
||||
|
@@ -121,7 +121,7 @@ namespace TestCaseTracking {
|
||||
}
|
||||
|
||||
bool TrackerBase::isSectionTracker() const { return false; }
|
||||
bool TrackerBase::isIndexTracker() const { return false; }
|
||||
bool TrackerBase::isGeneratorTracker() const { return false; }
|
||||
|
||||
void TrackerBase::open() {
|
||||
m_runState = Executing;
|
||||
@@ -190,6 +190,17 @@ namespace TestCaseTracking {
|
||||
}
|
||||
}
|
||||
|
||||
bool SectionTracker::isComplete() const {
|
||||
bool complete = true;
|
||||
|
||||
if ((m_filters.empty() || m_filters[0] == "") ||
|
||||
std::find(m_filters.begin(), m_filters.end(),
|
||||
m_nameAndLocation.name) != m_filters.end())
|
||||
complete = TrackerBase::isComplete();
|
||||
return complete;
|
||||
|
||||
}
|
||||
|
||||
bool SectionTracker::isSectionTracker() const { return true; }
|
||||
|
||||
SectionTracker& SectionTracker::acquire( TrackerContext& ctx, NameAndLocation const& nameAndLocation ) {
|
||||
@@ -227,55 +238,11 @@ namespace TestCaseTracking {
|
||||
m_filters.insert( m_filters.end(), ++filters.begin(), filters.end() );
|
||||
}
|
||||
|
||||
IndexTracker::IndexTracker( NameAndLocation const& nameAndLocation, TrackerContext& ctx, ITracker* parent, int size )
|
||||
: TrackerBase( nameAndLocation, ctx, parent ),
|
||||
m_size( size )
|
||||
{}
|
||||
|
||||
bool IndexTracker::isIndexTracker() const { return true; }
|
||||
|
||||
IndexTracker& IndexTracker::acquire( TrackerContext& ctx, NameAndLocation const& nameAndLocation, int size ) {
|
||||
std::shared_ptr<IndexTracker> tracker;
|
||||
|
||||
ITracker& currentTracker = ctx.currentTracker();
|
||||
if( ITrackerPtr childTracker = currentTracker.findChild( nameAndLocation ) ) {
|
||||
assert( childTracker );
|
||||
assert( childTracker->isIndexTracker() );
|
||||
tracker = std::static_pointer_cast<IndexTracker>( childTracker );
|
||||
}
|
||||
else {
|
||||
tracker = std::make_shared<IndexTracker>( nameAndLocation, ctx, ¤tTracker, size );
|
||||
currentTracker.addChild( tracker );
|
||||
}
|
||||
|
||||
if( !ctx.completedCycle() && !tracker->isComplete() ) {
|
||||
if( tracker->m_runState != ExecutingChildren && tracker->m_runState != NeedsAnotherRun )
|
||||
tracker->moveNext();
|
||||
tracker->open();
|
||||
}
|
||||
|
||||
return *tracker;
|
||||
}
|
||||
|
||||
int IndexTracker::index() const { return m_index; }
|
||||
|
||||
void IndexTracker::moveNext() {
|
||||
m_index++;
|
||||
m_children.clear();
|
||||
}
|
||||
|
||||
void IndexTracker::close() {
|
||||
TrackerBase::close();
|
||||
if( m_runState == CompletedSuccessfully && m_index < m_size-1 )
|
||||
m_runState = Executing;
|
||||
}
|
||||
|
||||
} // namespace TestCaseTracking
|
||||
|
||||
using TestCaseTracking::ITracker;
|
||||
using TestCaseTracking::TrackerContext;
|
||||
using TestCaseTracking::SectionTracker;
|
||||
using TestCaseTracking::IndexTracker;
|
||||
|
||||
} // namespace Catch
|
||||
|
||||
|
@@ -54,7 +54,7 @@ namespace TestCaseTracking {
|
||||
|
||||
// Debug/ checking
|
||||
virtual bool isSectionTracker() const = 0;
|
||||
virtual bool isIndexTracker() const = 0;
|
||||
virtual bool isGeneratorTracker() const = 0;
|
||||
};
|
||||
|
||||
class TrackerContext {
|
||||
@@ -120,7 +120,7 @@ namespace TestCaseTracking {
|
||||
void openChild() override;
|
||||
|
||||
bool isSectionTracker() const override;
|
||||
bool isIndexTracker() const override;
|
||||
bool isGeneratorTracker() const override;
|
||||
|
||||
void open();
|
||||
|
||||
@@ -140,6 +140,8 @@ namespace TestCaseTracking {
|
||||
|
||||
bool isSectionTracker() const override;
|
||||
|
||||
bool isComplete() const override;
|
||||
|
||||
static SectionTracker& acquire( TrackerContext& ctx, NameAndLocation const& nameAndLocation );
|
||||
|
||||
void tryOpen();
|
||||
@@ -148,28 +150,11 @@ namespace TestCaseTracking {
|
||||
void addNextFilters( std::vector<std::string> const& filters );
|
||||
};
|
||||
|
||||
class IndexTracker : public TrackerBase {
|
||||
int m_size;
|
||||
int m_index = -1;
|
||||
public:
|
||||
IndexTracker( NameAndLocation const& nameAndLocation, TrackerContext& ctx, ITracker* parent, int size );
|
||||
|
||||
bool isIndexTracker() const override;
|
||||
void close() override;
|
||||
|
||||
static IndexTracker& acquire( TrackerContext& ctx, NameAndLocation const& nameAndLocation, int size );
|
||||
|
||||
int index() const;
|
||||
|
||||
void moveNext();
|
||||
};
|
||||
|
||||
} // namespace TestCaseTracking
|
||||
|
||||
using TestCaseTracking::ITracker;
|
||||
using TestCaseTracking::TrackerContext;
|
||||
using TestCaseTracking::SectionTracker;
|
||||
using TestCaseTracking::IndexTracker;
|
||||
|
||||
} // namespace Catch
|
||||
|
||||
|
@@ -14,6 +14,7 @@
|
||||
#include "catch_stringref.h"
|
||||
#include "catch_type_traits.hpp"
|
||||
#include "catch_preprocessor.hpp"
|
||||
#include "catch_meta.hpp"
|
||||
|
||||
namespace Catch {
|
||||
|
||||
@@ -150,6 +151,41 @@ struct AutoReg : NonCopyable {
|
||||
return 0;\
|
||||
}();
|
||||
|
||||
#define INTERNAL_CATCH_TEMPLATE_PRODUCT_TEST_CASE2(TestName, TestFuncName, Name, Tags, TmplTypes, TypesList) \
|
||||
CATCH_INTERNAL_SUPPRESS_GLOBALS_WARNINGS \
|
||||
template<typename TestType> static void TestFuncName(); \
|
||||
namespace { \
|
||||
template<typename... Types> \
|
||||
struct TestName { \
|
||||
TestName() { \
|
||||
CATCH_INTERNAL_CHECK_UNIQUE_TYPES(Types...) \
|
||||
int index = 0; \
|
||||
using expander = int[]; \
|
||||
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 = Catch::combine<INTERNAL_CATCH_REMOVE_PARENS(TmplTypes)> \
|
||||
::with_types<INTERNAL_CATCH_MAKE_TYPE_LISTS_FROM_TYPES(TypesList)>::into<TestName>::type; \
|
||||
TestInit(); \
|
||||
return 0; \
|
||||
}(); \
|
||||
} \
|
||||
CATCH_INTERNAL_UNSUPPRESS_GLOBALS_WARNINGS \
|
||||
template<typename TestType> \
|
||||
static void TestFuncName()
|
||||
|
||||
#ifndef CATCH_CONFIG_TRADITIONAL_MSVC_PREPROCESSOR
|
||||
#define INTERNAL_CATCH_TEMPLATE_PRODUCT_TEST_CASE(Name, Tags, ...)\
|
||||
INTERNAL_CATCH_TEMPLATE_PRODUCT_TEST_CASE2(INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_M_P_L_A_T_E____T_E_S_T____ ), INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_M_P_L_A_T_E____T_E_S_T____F_U_N_C____ ),Name,Tags,__VA_ARGS__)
|
||||
#else
|
||||
#define INTERNAL_CATCH_TEMPLATE_PRODUCT_TEST_CASE(Name, Tags, ...)\
|
||||
INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_PRODUCT_TEST_CASE2( INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_M_P_L_A_T_E____T_E_S_T____ ), INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_M_P_L_A_T_E____T_E_S_T____F_U_N_C____ ), Name, Tags, __VA_ARGS__ ) )
|
||||
#endif
|
||||
|
||||
#define INTERNAL_CATCH_TEMPLATE_TEST_CASE_METHOD_2( TestNameClass, TestName, ClassName, Name, Tags, ... ) \
|
||||
CATCH_INTERNAL_SUPPRESS_GLOBALS_WARNINGS \
|
||||
namespace{ \
|
||||
@@ -180,4 +216,42 @@ struct AutoReg : NonCopyable {
|
||||
INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_TEST_CASE_METHOD_2( INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_M_P_L_A_T_E____T_E_S_T____C_L_A_S_S____ ), INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_M_P_L_A_T_E____T_E_S_T____ ) , ClassName, Name, Tags, __VA_ARGS__ ) )
|
||||
#endif
|
||||
|
||||
#define INTERNAL_CATCH_TEMPLATE_PRODUCT_TEST_CASE_METHOD_2(TestNameClass, TestName, ClassName, Name, Tags, TmplTypes, TypesList)\
|
||||
CATCH_INTERNAL_SUPPRESS_GLOBALS_WARNINGS \
|
||||
template<typename TestType> \
|
||||
struct TestName : INTERNAL_CATCH_REMOVE_PARENS(ClassName <TestType>) { \
|
||||
void test();\
|
||||
};\
|
||||
namespace {\
|
||||
template<typename...Types>\
|
||||
struct TestNameClass{\
|
||||
TestNameClass(){\
|
||||
CATCH_INTERNAL_CHECK_UNIQUE_TYPES(Types...)\
|
||||
int index = 0;\
|
||||
using expander = int[];\
|
||||
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 = Catch::combine<INTERNAL_CATCH_REMOVE_PARENS(TmplTypes)>\
|
||||
::with_types<INTERNAL_CATCH_MAKE_TYPE_LISTS_FROM_TYPES(TypesList)>::into<TestNameClass>::type;\
|
||||
TestInit();\
|
||||
return 0;\
|
||||
}(); \
|
||||
}\
|
||||
CATCH_INTERNAL_UNSUPPRESS_GLOBALS_WARNINGS \
|
||||
template<typename TestType> \
|
||||
void TestName<TestType>::test()
|
||||
|
||||
#ifndef CATCH_CONFIG_TRADITIONAL_MSVC_PREPROCESSOR
|
||||
#define INTERNAL_CATCH_TEMPLATE_PRODUCT_TEST_CASE_METHOD( ClassName, Name, Tags, ... )\
|
||||
INTERNAL_CATCH_TEMPLATE_PRODUCT_TEST_CASE_METHOD_2( INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_M_P_L_A_T_E____T_E_S_T____ ), INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_M_P_L_A_T_E____T_E_S_T____F_U_N_C____ ), ClassName, Name, Tags, __VA_ARGS__ )
|
||||
#else
|
||||
#define INTERNAL_CATCH_TEMPLATE_PRODUCT_TEST_CASE_METHOD( ClassName, Name, Tags, ... )\
|
||||
INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_PRODUCT_TEST_CASE_METHOD_2( INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_M_P_L_A_T_E____T_E_S_T____ ), INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_M_P_L_A_T_E____T_E_S_T____F_U_N_C____ ), ClassName, Name, Tags, __VA_ARGS__ ) )
|
||||
#endif
|
||||
|
||||
#endif // TWOBLUECUBES_CATCH_TEST_REGISTRY_HPP_INCLUDED
|
||||
|
@@ -40,7 +40,7 @@ namespace Catch {
|
||||
// is terrible and we should move on.
|
||||
// TBD: How to signal that the measured resolution is probably wrong?
|
||||
if (ticks > startTime + 3 * nanosecondsInSecond) {
|
||||
return sum / i;
|
||||
return sum / ( i + 1u );
|
||||
}
|
||||
}
|
||||
|
||||
|
@@ -348,6 +348,7 @@ namespace Catch {
|
||||
# define CATCH_CONFIG_ENABLE_TUPLE_STRINGMAKER
|
||||
# define CATCH_CONFIG_ENABLE_VARIANT_STRINGMAKER
|
||||
# define CATCH_CONFIG_ENABLE_CHRONO_STRINGMAKER
|
||||
# define CATCH_CONFIG_ENABLE_OPTIONAL_STRINGMAKER
|
||||
#endif
|
||||
|
||||
// Separate std::pair specialization
|
||||
@@ -369,6 +370,24 @@ namespace Catch {
|
||||
}
|
||||
#endif // CATCH_CONFIG_ENABLE_PAIR_STRINGMAKER
|
||||
|
||||
#if defined(CATCH_CONFIG_ENABLE_OPTIONAL_STRINGMAKER) && defined(CATCH_CONFIG_CPP17_OPTIONAL)
|
||||
#include <optional>
|
||||
namespace Catch {
|
||||
template<typename T>
|
||||
struct StringMaker<std::optional<T> > {
|
||||
static std::string convert(const std::optional<T>& optional) {
|
||||
ReusableStringStream rss;
|
||||
if (optional.has_value()) {
|
||||
rss << ::Catch::Detail::stringify(*optional);
|
||||
} else {
|
||||
rss << "{ }";
|
||||
}
|
||||
return rss.str();
|
||||
}
|
||||
};
|
||||
}
|
||||
#endif // CATCH_CONFIG_ENABLE_OPTIONAL_STRINGMAKER
|
||||
|
||||
// Separate std::tuple specialization
|
||||
#if defined(CATCH_CONFIG_ENABLE_TUPLE_STRINGMAKER)
|
||||
#include <tuple>
|
||||
|
@@ -9,6 +9,8 @@
|
||||
#ifndef TWOBLUECUBES_CATCH_TYPE_TRAITS_HPP_INCLUDED
|
||||
#define TWOBLUECUBES_CATCH_TYPE_TRAITS_HPP_INCLUDED
|
||||
|
||||
#include <type_traits>
|
||||
|
||||
namespace Catch{
|
||||
|
||||
#ifdef CATCH_CPP17_OR_GREATER
|
||||
|
@@ -37,7 +37,7 @@ namespace Catch {
|
||||
}
|
||||
|
||||
Version const& libraryVersion() {
|
||||
static Version version( 2, 5, 0, "", 0 );
|
||||
static Version version( 2, 7, 0, "", 0 );
|
||||
return version;
|
||||
}
|
||||
|
||||
|
@@ -44,9 +44,11 @@ namespace {
|
||||
}
|
||||
|
||||
void hexEscapeChar(std::ostream& os, unsigned char c) {
|
||||
std::ios_base::fmtflags f(os.flags());
|
||||
os << "\\x"
|
||||
<< std::uppercase << std::hex << std::setfill('0') << std::setw(2)
|
||||
<< static_cast<int>(c);
|
||||
os.flags(f);
|
||||
}
|
||||
|
||||
} // anonymous namespace
|
||||
|
@@ -36,7 +36,7 @@ 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);
|
||||
}
|
||||
|
@@ -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:
|
||||
|
@@ -76,6 +76,13 @@ namespace Catch {
|
||||
void JunitReporter::testRunStarting( TestRunInfo const& runInfo ) {
|
||||
CumulativeReporterBase::testRunStarting( runInfo );
|
||||
xml.startElement( "testsuites" );
|
||||
if( m_config->rngSeed() != 0 ) {
|
||||
xml.startElement( "properties" );
|
||||
xml.scopedElement( "property" )
|
||||
.writeAttribute( "name", "random-seed" )
|
||||
.writeAttribute( "value", m_config->rngSeed() );
|
||||
xml.endElement();
|
||||
}
|
||||
}
|
||||
|
||||
void JunitReporter::testGroupStarting( GroupInfo const& groupInfo ) {
|
||||
|
@@ -42,9 +42,9 @@ namespace Catch {
|
||||
bool assertionEnded( AssertionStats const& _assertionStats ) override {
|
||||
++counter;
|
||||
|
||||
stream << "# " << currentTestCaseInfo->name << std::endl;
|
||||
AssertionPrinter printer( stream, _assertionStats, counter );
|
||||
printer.print();
|
||||
stream << " # " << currentTestCaseInfo->name ;
|
||||
|
||||
stream << std::endl;
|
||||
return true;
|
||||
|
@@ -9,6 +9,38 @@
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
std::string escape_arg(const std::string& arg) {
|
||||
if (arg.empty() == false &&
|
||||
arg.find_first_of(" \t\n\v\"") == arg.npos) {
|
||||
return arg;
|
||||
}
|
||||
|
||||
std::string escaped;
|
||||
escaped.push_back('"');
|
||||
for (auto it = arg.begin(); ; ++it) {
|
||||
int num_backslashes = 0;
|
||||
|
||||
while (it != arg.end() && *it == '\\') {
|
||||
++it;
|
||||
++num_backslashes;
|
||||
}
|
||||
|
||||
if (it == arg.end()) {
|
||||
escaped.append(num_backslashes * 2, '\\');
|
||||
break;
|
||||
} else if (*it == '"') {
|
||||
escaped.append(num_backslashes * 2 + 1, '\\');
|
||||
escaped.push_back(*it);
|
||||
} else {
|
||||
escaped.append(num_backslashes, '\\');
|
||||
escaped.push_back(*it);
|
||||
}
|
||||
}
|
||||
escaped.push_back('"');
|
||||
|
||||
return escaped;
|
||||
}
|
||||
|
||||
|
||||
void create_empty_file(std::string const& path) {
|
||||
std::ofstream ofs(path);
|
||||
@@ -60,8 +92,9 @@ std::string windowsify_path(std::string path) {
|
||||
void exec_cmd(std::string const& cmd, int log_num, std::string const& path) {
|
||||
std::array<char, 128> buffer;
|
||||
#if defined(_WIN32)
|
||||
// cmd has already been escaped outside this function.
|
||||
auto real_cmd = "OpenCppCoverage --export_type binary:cov-report" + std::to_string(log_num)
|
||||
+ ".bin --quiet " + "--sources " + path + " --cover_children -- " + cmd;
|
||||
+ ".bin --quiet " + "--sources " + escape_arg(path) + " --cover_children -- " + cmd;
|
||||
std::cout << "=== Marker ===: Cmd: " << real_cmd << '\n';
|
||||
std::shared_ptr<FILE> pipe(_popen(real_cmd.c_str(), "r"), _pclose);
|
||||
#else // Just for testing, in the real world we will always work under WIN32
|
||||
@@ -93,7 +126,7 @@ int main(int argc, char** argv) {
|
||||
auto num = parse_log_file_arg(args[1]);
|
||||
|
||||
auto cmdline = std::accumulate(++sep, end(args), std::string{}, [] (const std::string& lhs, const std::string& rhs) {
|
||||
return lhs + ' ' + rhs;
|
||||
return lhs + ' ' + escape_arg(rhs);
|
||||
});
|
||||
|
||||
try {
|
||||
|
@@ -36,6 +36,7 @@ set(TEST_SOURCES
|
||||
${SELF_TEST_DIR}/UsageTests/Misc.tests.cpp
|
||||
${SELF_TEST_DIR}/UsageTests/ToStringChrono.tests.cpp
|
||||
${SELF_TEST_DIR}/UsageTests/ToStringGeneral.tests.cpp
|
||||
${SELF_TEST_DIR}/UsageTests/ToStringOptional.tests.cpp
|
||||
${SELF_TEST_DIR}/UsageTests/ToStringPair.tests.cpp
|
||||
${SELF_TEST_DIR}/UsageTests/ToStringTuple.tests.cpp
|
||||
${SELF_TEST_DIR}/UsageTests/ToStringVariant.tests.cpp
|
||||
@@ -101,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
|
||||
@@ -118,6 +121,7 @@ set(INTERNAL_HEADERS
|
||||
${HEADER_DIR}/internal/catch_matchers_string.h
|
||||
${HEADER_DIR}/internal/catch_matchers_vector.h
|
||||
${HEADER_DIR}/internal/catch_message.h
|
||||
${HEADER_DIR}/internal/catch_meta.hpp
|
||||
${HEADER_DIR}/internal/catch_objc.hpp
|
||||
${HEADER_DIR}/internal/catch_objc_arc.hpp
|
||||
${HEADER_DIR}/internal/catch_option.hpp
|
||||
@@ -344,10 +348,16 @@ set_tests_properties(NoAssertions PROPERTIES PASS_REGULAR_EXPRESSION "No asserti
|
||||
add_test(NAME NoTest COMMAND $<TARGET_FILE:SelfTest> -w NoTests "___nonexistent_test___")
|
||||
set_tests_properties(NoTest PROPERTIES PASS_REGULAR_EXPRESSION "No test cases matched")
|
||||
|
||||
add_test(NAME FilteredSection-1 COMMAND $<TARGET_FILE:SelfTest> \#1394 -c RunSection)
|
||||
set_tests_properties(FilteredSection-1 PROPERTIES FAIL_REGULAR_EXPRESSION "No tests ran")
|
||||
add_test(NAME FilteredSection-2 COMMAND $<TARGET_FILE:SelfTest> \#1394\ nested -c NestedRunSection -c s1)
|
||||
set_tests_properties(FilteredSection-2 PROPERTIES FAIL_REGULAR_EXPRESSION "No tests ran")
|
||||
|
||||
# AppVeyor has a Python 2.7 in path, but doesn't have .py files as autorunnable
|
||||
add_test(NAME ApprovalTests COMMAND ${PYTHON_EXECUTABLE} ${CATCH_DIR}/scripts/approvalTests.py $<TARGET_FILE:SelfTest>)
|
||||
set_tests_properties(ApprovalTests PROPERTIES FAIL_REGULAR_EXPRESSION "Results differed")
|
||||
|
||||
|
||||
if (CATCH_USE_VALGRIND)
|
||||
add_test(NAME ValgrindRunTests COMMAND valgrind --leak-check=full --error-exitcode=1 $<TARGET_FILE:SelfTest>)
|
||||
add_test(NAME ValgrindListTests COMMAND valgrind --leak-check=full --error-exitcode=1 $<TARGET_FILE:SelfTest> --list-tests --verbosity high)
|
||||
|
@@ -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'
|
||||
@@ -57,108 +61,97 @@ Tricky.tests.cpp:<line number>: passed: !is_true<false>::value for: true
|
||||
Tricky.tests.cpp:<line number>: passed: !!is_true<true>::value for: true
|
||||
Tricky.tests.cpp:<line number>: passed: is_true<true>::value for: true
|
||||
Tricky.tests.cpp:<line number>: passed: !(is_true<false>::value) for: !false
|
||||
Generators.tests.cpp:<line number>: passed: x < y for: 1 < 101
|
||||
Generators.tests.cpp:<line number>: passed: x < y for: 1 < 102
|
||||
Generators.tests.cpp:<line number>: passed: x < y for: 1 < 103
|
||||
Generators.tests.cpp:<line number>: passed: x < y for: 1 < 104
|
||||
Generators.tests.cpp:<line number>: passed: x < y for: 1 < 105
|
||||
Generators.tests.cpp:<line number>: passed: x < y for: 1 < 106
|
||||
Generators.tests.cpp:<line number>: passed: x < y for: 1 < 107
|
||||
Generators.tests.cpp:<line number>: passed: x < y for: 1 < 108
|
||||
Generators.tests.cpp:<line number>: passed: x < y for: 1 < 109
|
||||
Generators.tests.cpp:<line number>: passed: x < y for: 1 < 110
|
||||
Generators.tests.cpp:<line number>: passed: x < y for: 2 < 101
|
||||
Generators.tests.cpp:<line number>: passed: x < y for: 2 < 102
|
||||
Generators.tests.cpp:<line number>: passed: x < y for: 2 < 103
|
||||
Generators.tests.cpp:<line number>: passed: x < y for: 2 < 104
|
||||
Generators.tests.cpp:<line number>: passed: x < y for: 2 < 105
|
||||
Generators.tests.cpp:<line number>: passed: x < y for: 2 < 106
|
||||
Generators.tests.cpp:<line number>: passed: x < y for: 2 < 107
|
||||
Generators.tests.cpp:<line number>: passed: x < y for: 2 < 108
|
||||
Generators.tests.cpp:<line number>: passed: x < y for: 2 < 109
|
||||
Generators.tests.cpp:<line number>: passed: x < y for: 2 < 110
|
||||
Generators.tests.cpp:<line number>: passed: x < y for: 3 < 101
|
||||
Generators.tests.cpp:<line number>: passed: x < y for: 3 < 102
|
||||
Generators.tests.cpp:<line number>: passed: x < y for: 3 < 103
|
||||
Generators.tests.cpp:<line number>: passed: x < y for: 3 < 104
|
||||
Generators.tests.cpp:<line number>: passed: x < y for: 3 < 105
|
||||
Generators.tests.cpp:<line number>: passed: x < y for: 3 < 106
|
||||
Generators.tests.cpp:<line number>: passed: x < y for: 3 < 107
|
||||
Generators.tests.cpp:<line number>: passed: x < y for: 3 < 108
|
||||
Generators.tests.cpp:<line number>: passed: x < y for: 3 < 109
|
||||
Generators.tests.cpp:<line number>: passed: x < y for: 3 < 110
|
||||
Generators.tests.cpp:<line number>: passed: x < y for: 4 < 101
|
||||
Generators.tests.cpp:<line number>: passed: x < y for: 4 < 102
|
||||
Generators.tests.cpp:<line number>: passed: x < y for: 4 < 103
|
||||
Generators.tests.cpp:<line number>: passed: x < y for: 4 < 104
|
||||
Generators.tests.cpp:<line number>: passed: x < y for: 4 < 105
|
||||
Generators.tests.cpp:<line number>: passed: x < y for: 4 < 106
|
||||
Generators.tests.cpp:<line number>: passed: x < y for: 4 < 107
|
||||
Generators.tests.cpp:<line number>: passed: x < y for: 4 < 108
|
||||
Generators.tests.cpp:<line number>: passed: x < y for: 4 < 109
|
||||
Generators.tests.cpp:<line number>: passed: x < y for: 4 < 110
|
||||
Generators.tests.cpp:<line number>: passed: x < y for: 5 < 101
|
||||
Generators.tests.cpp:<line number>: passed: x < y for: 5 < 102
|
||||
Generators.tests.cpp:<line number>: passed: x < y for: 5 < 103
|
||||
Generators.tests.cpp:<line number>: passed: x < y for: 5 < 104
|
||||
Generators.tests.cpp:<line number>: passed: x < y for: 5 < 105
|
||||
Generators.tests.cpp:<line number>: passed: x < y for: 5 < 106
|
||||
Generators.tests.cpp:<line number>: passed: x < y for: 5 < 107
|
||||
Generators.tests.cpp:<line number>: passed: x < y for: 5 < 108
|
||||
Generators.tests.cpp:<line number>: passed: x < y for: 5 < 109
|
||||
Generators.tests.cpp:<line number>: passed: x < y for: 5 < 110
|
||||
Generators.tests.cpp:<line number>: passed: x < y for: 6 < 101
|
||||
Generators.tests.cpp:<line number>: passed: x < y for: 6 < 102
|
||||
Generators.tests.cpp:<line number>: passed: x < y for: 6 < 103
|
||||
Generators.tests.cpp:<line number>: passed: x < y for: 6 < 104
|
||||
Generators.tests.cpp:<line number>: passed: x < y for: 6 < 105
|
||||
Generators.tests.cpp:<line number>: passed: x < y for: 6 < 106
|
||||
Generators.tests.cpp:<line number>: passed: x < y for: 6 < 107
|
||||
Generators.tests.cpp:<line number>: passed: x < y for: 6 < 108
|
||||
Generators.tests.cpp:<line number>: passed: x < y for: 6 < 109
|
||||
Generators.tests.cpp:<line number>: passed: x < y for: 6 < 110
|
||||
Generators.tests.cpp:<line number>: passed: x < y for: 7 < 101
|
||||
Generators.tests.cpp:<line number>: passed: x < y for: 7 < 102
|
||||
Generators.tests.cpp:<line number>: passed: x < y for: 7 < 103
|
||||
Generators.tests.cpp:<line number>: passed: x < y for: 7 < 104
|
||||
Generators.tests.cpp:<line number>: passed: x < y for: 7 < 105
|
||||
Generators.tests.cpp:<line number>: passed: x < y for: 7 < 106
|
||||
Generators.tests.cpp:<line number>: passed: x < y for: 7 < 107
|
||||
Generators.tests.cpp:<line number>: passed: x < y for: 7 < 108
|
||||
Generators.tests.cpp:<line number>: passed: x < y for: 7 < 109
|
||||
Generators.tests.cpp:<line number>: passed: x < y for: 7 < 110
|
||||
Generators.tests.cpp:<line number>: passed: x < y for: 8 < 101
|
||||
Generators.tests.cpp:<line number>: passed: x < y for: 8 < 102
|
||||
Generators.tests.cpp:<line number>: passed: x < y for: 8 < 103
|
||||
Generators.tests.cpp:<line number>: passed: x < y for: 8 < 104
|
||||
Generators.tests.cpp:<line number>: passed: x < y for: 8 < 105
|
||||
Generators.tests.cpp:<line number>: passed: x < y for: 8 < 106
|
||||
Generators.tests.cpp:<line number>: passed: x < y for: 8 < 107
|
||||
Generators.tests.cpp:<line number>: passed: x < y for: 8 < 108
|
||||
Generators.tests.cpp:<line number>: passed: x < y for: 8 < 109
|
||||
Generators.tests.cpp:<line number>: passed: x < y for: 8 < 110
|
||||
Generators.tests.cpp:<line number>: passed: x < y for: 9 < 101
|
||||
Generators.tests.cpp:<line number>: passed: x < y for: 9 < 102
|
||||
Generators.tests.cpp:<line number>: passed: x < y for: 9 < 103
|
||||
Generators.tests.cpp:<line number>: passed: x < y for: 9 < 104
|
||||
Generators.tests.cpp:<line number>: passed: x < y for: 9 < 105
|
||||
Generators.tests.cpp:<line number>: passed: x < y for: 9 < 106
|
||||
Generators.tests.cpp:<line number>: passed: x < y for: 9 < 107
|
||||
Generators.tests.cpp:<line number>: passed: x < y for: 9 < 108
|
||||
Generators.tests.cpp:<line number>: passed: x < y for: 9 < 109
|
||||
Generators.tests.cpp:<line number>: passed: x < y for: 9 < 110
|
||||
Generators.tests.cpp:<line number>: passed: x < y for: 10 < 101
|
||||
Generators.tests.cpp:<line number>: passed: x < y for: 10 < 102
|
||||
Generators.tests.cpp:<line number>: passed: x < y for: 10 < 103
|
||||
Generators.tests.cpp:<line number>: passed: x < y for: 10 < 104
|
||||
Generators.tests.cpp:<line number>: passed: x < y for: 10 < 105
|
||||
Generators.tests.cpp:<line number>: passed: x < y for: 10 < 106
|
||||
Generators.tests.cpp:<line number>: passed: x < y for: 10 < 107
|
||||
Generators.tests.cpp:<line number>: passed: x < y for: 10 < 108
|
||||
Generators.tests.cpp:<line number>: passed: x < y for: 10 < 109
|
||||
Generators.tests.cpp:<line number>: passed: x < y for: 10 < 110
|
||||
Generators.tests.cpp:<line number>: passed: x < y for: 1 < 4
|
||||
Generators.tests.cpp:<line number>: passed: y < z for: 4 < 7
|
||||
Generators.tests.cpp:<line number>: passed: x < z for: 1 < 7
|
||||
Generators.tests.cpp:<line number>: passed: x < y for: 1 < 4
|
||||
Generators.tests.cpp:<line number>: passed: y < z for: 4 < 8
|
||||
Generators.tests.cpp:<line number>: passed: x < z for: 1 < 8
|
||||
Generators.tests.cpp:<line number>: passed: x < y for: 1 < 4
|
||||
Generators.tests.cpp:<line number>: passed: y < z for: 4 < 9
|
||||
Generators.tests.cpp:<line number>: passed: x < z for: 1 < 9
|
||||
Generators.tests.cpp:<line number>: passed: x < y for: 1 < 5
|
||||
Generators.tests.cpp:<line number>: passed: y < z for: 5 < 7
|
||||
Generators.tests.cpp:<line number>: passed: x < z for: 1 < 7
|
||||
Generators.tests.cpp:<line number>: passed: x < y for: 1 < 5
|
||||
Generators.tests.cpp:<line number>: passed: y < z for: 5 < 8
|
||||
Generators.tests.cpp:<line number>: passed: x < z for: 1 < 8
|
||||
Generators.tests.cpp:<line number>: passed: x < y for: 1 < 5
|
||||
Generators.tests.cpp:<line number>: passed: y < z for: 5 < 9
|
||||
Generators.tests.cpp:<line number>: passed: x < z for: 1 < 9
|
||||
Generators.tests.cpp:<line number>: passed: x < y for: 1 < 6
|
||||
Generators.tests.cpp:<line number>: passed: y < z for: 6 < 7
|
||||
Generators.tests.cpp:<line number>: passed: x < z for: 1 < 7
|
||||
Generators.tests.cpp:<line number>: passed: x < y for: 1 < 6
|
||||
Generators.tests.cpp:<line number>: passed: y < z for: 6 < 8
|
||||
Generators.tests.cpp:<line number>: passed: x < z for: 1 < 8
|
||||
Generators.tests.cpp:<line number>: passed: x < y for: 1 < 6
|
||||
Generators.tests.cpp:<line number>: passed: y < z for: 6 < 9
|
||||
Generators.tests.cpp:<line number>: passed: x < z for: 1 < 9
|
||||
Generators.tests.cpp:<line number>: passed: x < y for: 2 < 4
|
||||
Generators.tests.cpp:<line number>: passed: y < z for: 4 < 7
|
||||
Generators.tests.cpp:<line number>: passed: x < z for: 2 < 7
|
||||
Generators.tests.cpp:<line number>: passed: x < y for: 2 < 4
|
||||
Generators.tests.cpp:<line number>: passed: y < z for: 4 < 8
|
||||
Generators.tests.cpp:<line number>: passed: x < z for: 2 < 8
|
||||
Generators.tests.cpp:<line number>: passed: x < y for: 2 < 4
|
||||
Generators.tests.cpp:<line number>: passed: y < z for: 4 < 9
|
||||
Generators.tests.cpp:<line number>: passed: x < z for: 2 < 9
|
||||
Generators.tests.cpp:<line number>: passed: x < y for: 2 < 5
|
||||
Generators.tests.cpp:<line number>: passed: y < z for: 5 < 7
|
||||
Generators.tests.cpp:<line number>: passed: x < z for: 2 < 7
|
||||
Generators.tests.cpp:<line number>: passed: x < y for: 2 < 5
|
||||
Generators.tests.cpp:<line number>: passed: y < z for: 5 < 8
|
||||
Generators.tests.cpp:<line number>: passed: x < z for: 2 < 8
|
||||
Generators.tests.cpp:<line number>: passed: x < y for: 2 < 5
|
||||
Generators.tests.cpp:<line number>: passed: y < z for: 5 < 9
|
||||
Generators.tests.cpp:<line number>: passed: x < z for: 2 < 9
|
||||
Generators.tests.cpp:<line number>: passed: x < y for: 2 < 6
|
||||
Generators.tests.cpp:<line number>: passed: y < z for: 6 < 7
|
||||
Generators.tests.cpp:<line number>: passed: x < z for: 2 < 7
|
||||
Generators.tests.cpp:<line number>: passed: x < y for: 2 < 6
|
||||
Generators.tests.cpp:<line number>: passed: y < z for: 6 < 8
|
||||
Generators.tests.cpp:<line number>: passed: x < z for: 2 < 8
|
||||
Generators.tests.cpp:<line number>: passed: x < y for: 2 < 6
|
||||
Generators.tests.cpp:<line number>: passed: y < z for: 6 < 9
|
||||
Generators.tests.cpp:<line number>: passed: x < z for: 2 < 9
|
||||
Generators.tests.cpp:<line number>: passed: x < y for: 3 < 4
|
||||
Generators.tests.cpp:<line number>: passed: y < z for: 4 < 7
|
||||
Generators.tests.cpp:<line number>: passed: x < z for: 3 < 7
|
||||
Generators.tests.cpp:<line number>: passed: x < y for: 3 < 4
|
||||
Generators.tests.cpp:<line number>: passed: y < z for: 4 < 8
|
||||
Generators.tests.cpp:<line number>: passed: x < z for: 3 < 8
|
||||
Generators.tests.cpp:<line number>: passed: x < y for: 3 < 4
|
||||
Generators.tests.cpp:<line number>: passed: y < z for: 4 < 9
|
||||
Generators.tests.cpp:<line number>: passed: x < z for: 3 < 9
|
||||
Generators.tests.cpp:<line number>: passed: x < y for: 3 < 5
|
||||
Generators.tests.cpp:<line number>: passed: y < z for: 5 < 7
|
||||
Generators.tests.cpp:<line number>: passed: x < z for: 3 < 7
|
||||
Generators.tests.cpp:<line number>: passed: x < y for: 3 < 5
|
||||
Generators.tests.cpp:<line number>: passed: y < z for: 5 < 8
|
||||
Generators.tests.cpp:<line number>: passed: x < z for: 3 < 8
|
||||
Generators.tests.cpp:<line number>: passed: x < y for: 3 < 5
|
||||
Generators.tests.cpp:<line number>: passed: y < z for: 5 < 9
|
||||
Generators.tests.cpp:<line number>: passed: x < z for: 3 < 9
|
||||
Generators.tests.cpp:<line number>: passed: x < y for: 3 < 6
|
||||
Generators.tests.cpp:<line number>: passed: y < z for: 6 < 7
|
||||
Generators.tests.cpp:<line number>: passed: x < z for: 3 < 7
|
||||
Generators.tests.cpp:<line number>: passed: x < y for: 3 < 6
|
||||
Generators.tests.cpp:<line number>: passed: y < z for: 6 < 8
|
||||
Generators.tests.cpp:<line number>: passed: x < z for: 3 < 8
|
||||
Generators.tests.cpp:<line number>: passed: x < y for: 3 < 6
|
||||
Generators.tests.cpp:<line number>: passed: y < z for: 6 < 9
|
||||
Generators.tests.cpp:<line number>: passed: x < z for: 3 < 9
|
||||
Class.tests.cpp:<line number>: failed: s == "world" for: "hello" == "world"
|
||||
Class.tests.cpp:<line number>: passed: s == "hello" for: "hello" == "hello"
|
||||
Class.tests.cpp:<line number>: failed: Template_Fixture_2<TestType>::m_a.size() == 1 for: 0 == 1
|
||||
Class.tests.cpp:<line number>: failed: Template_Fixture_2<TestType>::m_a.size() == 1 for: 0 == 1
|
||||
Class.tests.cpp:<line number>: failed: Template_Fixture_2<TestType>::m_a.size() == 1 for: 0 == 1
|
||||
Class.tests.cpp:<line number>: failed: Template_Fixture_2<TestType>::m_a.size() == 1 for: 0 == 1
|
||||
Class.tests.cpp:<line number>: passed: Template_Fixture_2<TestType>::m_a.size() == 0 for: 0 == 0
|
||||
Class.tests.cpp:<line number>: passed: Template_Fixture_2<TestType>::m_a.size() == 0 for: 0 == 0
|
||||
Class.tests.cpp:<line number>: passed: Template_Fixture_2<TestType>::m_a.size() == 0 for: 0 == 0
|
||||
Class.tests.cpp:<line number>: passed: Template_Fixture_2<TestType>::m_a.size() == 0 for: 0 == 0
|
||||
Class.tests.cpp:<line number>: failed: Template_Fixture<TestType>::m_a == 2 for: 1.0 == 2
|
||||
Class.tests.cpp:<line number>: failed: Template_Fixture<TestType>::m_a == 2 for: 1.0f == 2
|
||||
Class.tests.cpp:<line number>: failed: Template_Fixture<TestType>::m_a == 2 for: 1 == 2
|
||||
@@ -167,6 +160,10 @@ Class.tests.cpp:<line number>: passed: Template_Fixture<TestType>::m_a == 1 for:
|
||||
Class.tests.cpp:<line number>: passed: Template_Fixture<TestType>::m_a == 1 for: 1 == 1
|
||||
Class.tests.cpp:<line number>: failed: m_a == 2 for: 1 == 2
|
||||
Class.tests.cpp:<line number>: passed: m_a == 1 for: 1 == 1
|
||||
Misc.tests.cpp:<line number>: passed: x.size() == 0 for: 0 == 0
|
||||
Misc.tests.cpp:<line number>: passed: x.size() == 0 for: 0 == 0
|
||||
Misc.tests.cpp:<line number>: passed: x.size() == 0 for: 0 == 0
|
||||
Misc.tests.cpp:<line number>: passed: x.size() == 0 for: 0 == 0
|
||||
Approx.tests.cpp:<line number>: passed: d == 1.23_a for: 1.23 == Approx( 1.23 )
|
||||
Approx.tests.cpp:<line number>: passed: d != 1.22_a for: 1.23 != Approx( 1.22 )
|
||||
Approx.tests.cpp:<line number>: passed: -d == -1.23_a for: -1.23 == Approx( -1.23 )
|
||||
@@ -406,48 +403,180 @@ Matchers.tests.cpp:<line number>: passed: WithinAbs(1.f, 0.f)
|
||||
Matchers.tests.cpp:<line number>: passed: WithinAbs(1.f, -1.f), std::domain_error
|
||||
Matchers.tests.cpp:<line number>: passed: WithinULP(1.f, 0)
|
||||
Matchers.tests.cpp:<line number>: passed: WithinULP(1.f, -1), std::domain_error
|
||||
Generators.tests.cpp:<line number>: passed: with 2 messages: 'i := "a"' and 'j := 8'
|
||||
Generators.tests.cpp:<line number>: passed: with 2 messages: 'i := "a"' and 'j := 9'
|
||||
Generators.tests.cpp:<line number>: passed: with 2 messages: 'i := "a"' and 'j := 10'
|
||||
Generators.tests.cpp:<line number>: passed: with 2 messages: 'i := "a"' and 'j := 2'
|
||||
Generators.tests.cpp:<line number>: passed: with 2 messages: 'i := "a"' and 'j := 3.141'
|
||||
Generators.tests.cpp:<line number>: passed: with 2 messages: 'i := "a"' and 'j := 1.379'
|
||||
Generators.tests.cpp:<line number>: passed: with 2 messages: 'i := "b"' and 'j := 8'
|
||||
Generators.tests.cpp:<line number>: passed: with 2 messages: 'i := "b"' and 'j := 9'
|
||||
Generators.tests.cpp:<line number>: passed: with 2 messages: 'i := "b"' and 'j := 10'
|
||||
Generators.tests.cpp:<line number>: passed: with 2 messages: 'i := "b"' and 'j := 2'
|
||||
Generators.tests.cpp:<line number>: passed: with 2 messages: 'i := "b"' and 'j := 3.141'
|
||||
Generators.tests.cpp:<line number>: passed: with 2 messages: 'i := "b"' and 'j := 1.379'
|
||||
Generators.tests.cpp:<line number>: passed: with 2 messages: 'i := "c"' and 'j := 8'
|
||||
Generators.tests.cpp:<line number>: passed: with 2 messages: 'i := "c"' and 'j := 9'
|
||||
Generators.tests.cpp:<line number>: passed: with 2 messages: 'i := "c"' and 'j := 10'
|
||||
Generators.tests.cpp:<line number>: passed: with 2 messages: 'i := "c"' and 'j := 2'
|
||||
Generators.tests.cpp:<line number>: passed: with 2 messages: 'i := "c"' and 'j := 3.141'
|
||||
Generators.tests.cpp:<line number>: passed: with 2 messages: 'i := "c"' and 'j := 1.379'
|
||||
GeneratorsImpl.tests.cpp:<line number>: passed: gen.size() == 2 for: 2 == 2
|
||||
GeneratorsImpl.tests.cpp:<line number>: passed: gen[0] == 1 for: 1 == 1
|
||||
GeneratorsImpl.tests.cpp:<line number>: passed: gen[1] == 2 for: 2 == 2
|
||||
GeneratorsImpl.tests.cpp:<line number>: passed: gen.size() == 4 for: 4 == 4
|
||||
GeneratorsImpl.tests.cpp:<line number>: passed: gen[0] == 3 for: 3 == 3
|
||||
GeneratorsImpl.tests.cpp:<line number>: passed: gen[1] == 1 for: 1 == 1
|
||||
GeneratorsImpl.tests.cpp:<line number>: passed: gen[2] == 4 for: 4 == 4
|
||||
GeneratorsImpl.tests.cpp:<line number>: passed: gen[3] == 1 for: 1 == 1
|
||||
GeneratorsImpl.tests.cpp:<line number>: passed: gen.size() == 4 for: 4 == 4
|
||||
GeneratorsImpl.tests.cpp:<line number>: passed: gen[0] == 1 for: 1 == 1
|
||||
GeneratorsImpl.tests.cpp:<line number>: passed: gen[1] == 2 for: 2 == 2
|
||||
GeneratorsImpl.tests.cpp:<line number>: passed: gen[2] == 9 for: 9 == 9
|
||||
GeneratorsImpl.tests.cpp:<line number>: passed: gen[3] == 7 for: 7 == 7
|
||||
GeneratorsImpl.tests.cpp:<line number>: passed: gen.size() == 2 for: 2 == 2
|
||||
GeneratorsImpl.tests.cpp:<line number>: passed: gen[0] == 3 for: 3 == 3
|
||||
GeneratorsImpl.tests.cpp:<line number>: passed: gen[1] == 1 for: 1 == 1
|
||||
GeneratorsImpl.tests.cpp:<line number>: passed: gen.size() == 2 for: 2 == 2
|
||||
GeneratorsImpl.tests.cpp:<line number>: passed: gen[0] == 3 for: 3 == 3
|
||||
GeneratorsImpl.tests.cpp:<line number>: passed: gen[1] == 1 for: 1 == 1
|
||||
GeneratorsImpl.tests.cpp:<line number>: passed: base->size() == 4 for: 4 == 4
|
||||
GeneratorsImpl.tests.cpp:<line number>: passed: typed for: 0x<hex digits>
|
||||
GeneratorsImpl.tests.cpp:<line number>: passed: typed->size() == 4 for: 4 == 4
|
||||
GeneratorsImpl.tests.cpp:<line number>: passed: (*typed)[0] == 7 for: 7 == 7
|
||||
GeneratorsImpl.tests.cpp:<line number>: passed: (*typed)[3] == 11 for: 11 == 11
|
||||
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
|
||||
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: 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
|
||||
Generators.tests.cpp:<line number>: passed: 4u * i > str.size() for: 4 > 1
|
||||
Generators.tests.cpp:<line number>: passed: 4u * i > str.size() for: 4 > 2
|
||||
Generators.tests.cpp:<line number>: passed: 4u * i > str.size() for: 4 > 3
|
||||
Generators.tests.cpp:<line number>: passed: j < i for: -3 < 2
|
||||
Generators.tests.cpp:<line number>: passed: j < i for: -2 < 2
|
||||
Generators.tests.cpp:<line number>: passed: j < i for: -1 < 2
|
||||
Generators.tests.cpp:<line number>: passed: 4u * i > str.size() for: 8 > 1
|
||||
Generators.tests.cpp:<line number>: passed: 4u * i > str.size() for: 8 > 2
|
||||
Generators.tests.cpp:<line number>: passed: 4u * i > str.size() for: 8 > 3
|
||||
Generators.tests.cpp:<line number>: passed: j < i for: -3 < 3
|
||||
Generators.tests.cpp:<line number>: passed: j < i for: -2 < 3
|
||||
Generators.tests.cpp:<line number>: passed: j < i for: -1 < 3
|
||||
Generators.tests.cpp:<line number>: passed: 4u * i > str.size() for: 12 > 1
|
||||
Generators.tests.cpp:<line number>: passed: 4u * i > str.size() for: 12 > 2
|
||||
Generators.tests.cpp:<line number>: passed: 4u * i > str.size() for: 12 > 3
|
||||
GeneratorsImpl.tests.cpp:<line number>: passed: gen.get() == 123 for: 123 == 123
|
||||
GeneratorsImpl.tests.cpp:<line number>: passed: !(gen.next()) for: !false
|
||||
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() == 3 for: 3 == 3
|
||||
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() == 1 for: 1 == 1
|
||||
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: 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() == 4 for: 4 == 4
|
||||
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: !false
|
||||
GeneratorsImpl.tests.cpp:<line number>: passed: gen.get().size() == 2 for: 2 == 2
|
||||
GeneratorsImpl.tests.cpp:<line number>: passed: gen.get() == "aa" for: "aa" == "aa"
|
||||
GeneratorsImpl.tests.cpp:<line number>: passed: gen.next() for: true
|
||||
GeneratorsImpl.tests.cpp:<line number>: passed: gen.get() == "bb" for: "bb" == "bb"
|
||||
GeneratorsImpl.tests.cpp:<line number>: passed: gen.next() for: true
|
||||
GeneratorsImpl.tests.cpp:<line number>: passed: gen.get() == "cc" for: "cc" == "cc"
|
||||
GeneratorsImpl.tests.cpp:<line number>: passed: !(gen.next()) for: !false
|
||||
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() == 3 for: 3 == 3
|
||||
GeneratorsImpl.tests.cpp:<line number>: passed: !(gen.next()) for: !false
|
||||
GeneratorsImpl.tests.cpp:<line number>: passed: filter([] (int) { return false; }, value(1)), Catch::GeneratorException
|
||||
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() == 1 for: 1 == 1
|
||||
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
|
||||
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() == 3 for: 3 == 3
|
||||
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() == 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 ))
|
||||
@@ -750,6 +879,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: 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
|
||||
@@ -1019,69 +1151,6 @@ PartTracker.tests.cpp:<line number>: passed: s1.isComplete() == false for: false
|
||||
PartTracker.tests.cpp:<line number>: passed: s1.isComplete() for: true
|
||||
PartTracker.tests.cpp:<line number>: passed: testCase.isComplete() == false for: false == false
|
||||
PartTracker.tests.cpp:<line number>: passed: testCase.isComplete() for: true
|
||||
PartTracker.tests.cpp:<line number>: passed: testCase.isOpen() for: true
|
||||
PartTracker.tests.cpp:<line number>: passed: s1.isOpen() for: true
|
||||
PartTracker.tests.cpp:<line number>: passed: g1.isOpen() for: true
|
||||
PartTracker.tests.cpp:<line number>: passed: g1.index() == 0 for: 0 == 0
|
||||
PartTracker.tests.cpp:<line number>: passed: g1.isComplete() == false for: false == false
|
||||
PartTracker.tests.cpp:<line number>: passed: s1.isComplete() == false for: false == false
|
||||
PartTracker.tests.cpp:<line number>: passed: s1.isComplete() == false for: false == false
|
||||
PartTracker.tests.cpp:<line number>: passed: testCase.isSuccessfullyCompleted() == false for: false == false
|
||||
PartTracker.tests.cpp:<line number>: passed: testCase2.isOpen() for: true
|
||||
PartTracker.tests.cpp:<line number>: passed: s1b.isOpen() for: true
|
||||
PartTracker.tests.cpp:<line number>: passed: g1b.isOpen() for: true
|
||||
PartTracker.tests.cpp:<line number>: passed: g1b.index() == 1 for: 1 == 1
|
||||
PartTracker.tests.cpp:<line number>: passed: s1.isComplete() == false for: false == false
|
||||
PartTracker.tests.cpp:<line number>: passed: s1b.isComplete() for: true
|
||||
PartTracker.tests.cpp:<line number>: passed: g1b.isComplete() for: true
|
||||
PartTracker.tests.cpp:<line number>: passed: testCase2.isComplete() for: true
|
||||
PartTracker.tests.cpp:<line number>: passed: testCase.isOpen() for: true
|
||||
PartTracker.tests.cpp:<line number>: passed: s1.isOpen() for: true
|
||||
PartTracker.tests.cpp:<line number>: passed: g1.isOpen() for: true
|
||||
PartTracker.tests.cpp:<line number>: passed: g1.index() == 0 for: 0 == 0
|
||||
PartTracker.tests.cpp:<line number>: passed: g1.isComplete() == false for: false == false
|
||||
PartTracker.tests.cpp:<line number>: passed: s1.isComplete() == false for: false == false
|
||||
PartTracker.tests.cpp:<line number>: passed: s2.isOpen() for: true
|
||||
PartTracker.tests.cpp:<line number>: passed: s2.isComplete() for: true
|
||||
PartTracker.tests.cpp:<line number>: passed: s1.isComplete() == false for: false == false
|
||||
PartTracker.tests.cpp:<line number>: passed: testCase.isComplete() == false for: false == false
|
||||
PartTracker.tests.cpp:<line number>: passed: testCase2.isOpen() for: true
|
||||
PartTracker.tests.cpp:<line number>: passed: s1b.isOpen() for: true
|
||||
PartTracker.tests.cpp:<line number>: passed: g1b.isOpen() for: true
|
||||
PartTracker.tests.cpp:<line number>: passed: g1b.index() == 1 for: 1 == 1
|
||||
PartTracker.tests.cpp:<line number>: passed: s2b.isOpen() for: true
|
||||
PartTracker.tests.cpp:<line number>: passed: s2b.isComplete() for: true
|
||||
PartTracker.tests.cpp:<line number>: passed: g1b.isComplete() for: true
|
||||
PartTracker.tests.cpp:<line number>: passed: s1b.isComplete() for: true
|
||||
PartTracker.tests.cpp:<line number>: passed: testCase2.isComplete() for: true
|
||||
PartTracker.tests.cpp:<line number>: passed: testCase.isOpen() for: true
|
||||
PartTracker.tests.cpp:<line number>: passed: s1.isOpen() for: true
|
||||
PartTracker.tests.cpp:<line number>: passed: g1.isOpen() for: true
|
||||
PartTracker.tests.cpp:<line number>: passed: g1.index() == 0 for: 0 == 0
|
||||
PartTracker.tests.cpp:<line number>: passed: g1.isComplete() == false for: false == false
|
||||
PartTracker.tests.cpp:<line number>: passed: s1.isComplete() == false for: false == false
|
||||
PartTracker.tests.cpp:<line number>: passed: s2.isOpen() for: true
|
||||
PartTracker.tests.cpp:<line number>: passed: s2.isComplete() for: true
|
||||
PartTracker.tests.cpp:<line number>: passed: s2.isSuccessfullyCompleted() == false for: false == false
|
||||
PartTracker.tests.cpp:<line number>: passed: s1.isComplete() == false for: false == false
|
||||
PartTracker.tests.cpp:<line number>: passed: testCase.isComplete() == false for: false == false
|
||||
PartTracker.tests.cpp:<line number>: passed: testCase2.isOpen() for: true
|
||||
PartTracker.tests.cpp:<line number>: passed: s1b.isOpen() for: true
|
||||
PartTracker.tests.cpp:<line number>: passed: g1b.isOpen() for: true
|
||||
PartTracker.tests.cpp:<line number>: passed: g1b.index() == 0 for: 0 == 0
|
||||
PartTracker.tests.cpp:<line number>: passed: s2b.isOpen() == false for: false == false
|
||||
PartTracker.tests.cpp:<line number>: passed: g1b.isComplete() == false for: false == false
|
||||
PartTracker.tests.cpp:<line number>: passed: s1b.isComplete() == false for: false == false
|
||||
PartTracker.tests.cpp:<line number>: passed: testCase2.isComplete() == false for: false == false
|
||||
PartTracker.tests.cpp:<line number>: passed: testCase3.isOpen() for: true
|
||||
PartTracker.tests.cpp:<line number>: passed: s1c.isOpen() for: true
|
||||
PartTracker.tests.cpp:<line number>: passed: g1c.isOpen() for: true
|
||||
PartTracker.tests.cpp:<line number>: passed: g1c.index() == 1 for: 1 == 1
|
||||
PartTracker.tests.cpp:<line number>: passed: s2c.isOpen() for: true
|
||||
PartTracker.tests.cpp:<line number>: passed: s2c.isComplete() for: true
|
||||
PartTracker.tests.cpp:<line number>: passed: g1c.isComplete() for: true
|
||||
PartTracker.tests.cpp:<line number>: passed: s1c.isComplete() for: true
|
||||
PartTracker.tests.cpp:<line number>: passed: testCase3.isComplete() for: true
|
||||
Exception.tests.cpp:<line number>: failed: unexpected exception with message: '3.14'
|
||||
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.22 ) for: 1.23 == Approx( 1.22 )
|
||||
@@ -1216,6 +1285,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>)
|
||||
@@ -1237,6 +1307,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
|
||||
@@ -1246,6 +1318,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
|
||||
@@ -1253,6 +1328,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
|
||||
@@ -1272,6 +1353,8 @@ 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'
|
||||
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 } }"
|
||||
@@ -1322,6 +1405,10 @@ Generators.tests.cpp:<line number>: passed: data.str.size() == data.len for: 3 =
|
||||
Generators.tests.cpp:<line number>: passed: data.str.size() == data.len for: 3 == 3
|
||||
Generators.tests.cpp:<line number>: passed: data.str.size() == data.len for: 5 == 5
|
||||
Generators.tests.cpp:<line number>: passed: data.str.size() == data.len for: 4 == 4
|
||||
Generators.tests.cpp:<line number>: passed: strlen(std::get<0>(data)) == static_cast<size_t>(std::get<1>(data)) for: 5 == 5
|
||||
Generators.tests.cpp:<line number>: passed: strlen(std::get<0>(data)) == static_cast<size_t>(std::get<1>(data)) for: 6 == 6
|
||||
Generators.tests.cpp:<line number>: passed: strlen(std::get<0>(data)) == static_cast<size_t>(std::get<1>(data)) for: 5 == 5
|
||||
Generators.tests.cpp:<line number>: passed: strlen(std::get<0>(data)) == static_cast<size_t>(std::get<1>(data)) for: 6 == 6
|
||||
Exception.tests.cpp:<line number>: failed: unexpected exception with message: 'Why would you throw a std::string?'
|
||||
Misc.tests.cpp:<line number>: passed: result == "\"wide load\"" for: ""wide load"" == ""wide load""
|
||||
Misc.tests.cpp:<line number>: passed: result == "\"wide load\"" for: ""wide load"" == ""wide load""
|
||||
@@ -1389,5 +1476,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 65 test cases, failed 125 assertions.
|
||||
Failed 77 test cases, failed 138 assertions.
|
||||
|
||||
|
@@ -1,3 +1,5 @@
|
||||
This would not be caught previously
|
||||
Nor would this
|
||||
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
<exe-name> is a <version> host application.
|
||||
@@ -5,6 +7,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
|
||||
@@ -92,6 +104,54 @@ Class.tests.cpp:<line number>: FAILED:
|
||||
with expansion:
|
||||
"hello" == "world"
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
A TEMPLATE_PRODUCT_TEST_CASE_METHOD based test run that fails - Template_Foo
|
||||
<float>
|
||||
-------------------------------------------------------------------------------
|
||||
Class.tests.cpp:<line number>
|
||||
...............................................................................
|
||||
|
||||
Class.tests.cpp:<line number>: FAILED:
|
||||
REQUIRE( Template_Fixture_2<TestType>::m_a.size() == 1 )
|
||||
with expansion:
|
||||
0 == 1
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
A TEMPLATE_PRODUCT_TEST_CASE_METHOD based test run that fails - Template_Foo
|
||||
<int>
|
||||
-------------------------------------------------------------------------------
|
||||
Class.tests.cpp:<line number>
|
||||
...............................................................................
|
||||
|
||||
Class.tests.cpp:<line number>: FAILED:
|
||||
REQUIRE( Template_Fixture_2<TestType>::m_a.size() == 1 )
|
||||
with expansion:
|
||||
0 == 1
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
A TEMPLATE_PRODUCT_TEST_CASE_METHOD based test run that fails - std::vector
|
||||
<float>
|
||||
-------------------------------------------------------------------------------
|
||||
Class.tests.cpp:<line number>
|
||||
...............................................................................
|
||||
|
||||
Class.tests.cpp:<line number>: FAILED:
|
||||
REQUIRE( Template_Fixture_2<TestType>::m_a.size() == 1 )
|
||||
with expansion:
|
||||
0 == 1
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
A TEMPLATE_PRODUCT_TEST_CASE_METHOD based test run that fails - std::vector
|
||||
<int>
|
||||
-------------------------------------------------------------------------------
|
||||
Class.tests.cpp:<line number>
|
||||
...............................................................................
|
||||
|
||||
Class.tests.cpp:<line number>: FAILED:
|
||||
REQUIRE( Template_Fixture_2<TestType>::m_a.size() == 1 )
|
||||
with expansion:
|
||||
0 == 1
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
A TEMPLATE_TEST_CASE_METHOD based test run that fails - double
|
||||
-------------------------------------------------------------------------------
|
||||
@@ -996,6 +1056,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
|
||||
@@ -1068,6 +1138,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
|
||||
@@ -1081,6 +1163,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
|
||||
-------------------------------------------------------------------------------
|
||||
@@ -1104,6 +1220,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
|
||||
-------------------------------------------------------------------------------
|
||||
@@ -1126,6 +1264,6 @@ due to unexpected exception with message:
|
||||
Why would you throw a std::string?
|
||||
|
||||
===============================================================================
|
||||
test cases: 228 | 172 passed | 52 failed | 4 failed as expected
|
||||
assertions: 1310 | 1178 passed | 111 failed | 21 failed as expected
|
||||
test cases: 255 | 189 passed | 62 failed | 4 failed as expected
|
||||
assertions: 1393 | 1250 passed | 122 failed | 21 failed as expected
|
||||
|
||||
|
File diff suppressed because it is too large
Load Diff
@@ -133,6 +133,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 +340,7 @@ Condition.tests.cpp:<line number>: FAILED:
|
||||
with expansion:
|
||||
false
|
||||
|
||||
Condition.tests.cpp:<line number>: FAILED:
|
||||
CHECK_FALSE( true )
|
||||
with expansion:
|
||||
!true
|
||||
|
||||
===============================================================================
|
||||
test cases: 15 | 12 passed | 1 failed | 2 failed as expected
|
||||
assertions: 39 | 32 passed | 4 failed | 3 failed as expected
|
||||
test cases: 17 | 13 passed | 2 failed | 2 failed as expected
|
||||
assertions: 40 | 33 passed | 4 failed | 3 failed as expected
|
||||
|
||||
|
@@ -1,7 +1,10 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<testsuitesloose text artifact
|
||||
>
|
||||
<testsuite name="<exe-name>" errors="17" failures="109" tests="1325" hostname="tbd" time="{duration}" timestamp="{iso8601-timestamp}">
|
||||
<testsuites>
|
||||
<properties>
|
||||
<property name="random-seed" value="1"/>
|
||||
</properties>
|
||||
loose text artifact
|
||||
<testsuite name="<exe-name>" errors="17" failures="122" tests="1410" 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 +13,19 @@
|
||||
<testcase classname="<exe-name>.global" name="#1238" time="{duration}"/>
|
||||
<testcase classname="<exe-name>.(Fixture_1245<int, int>)" name="#1245" time="{duration}"/>
|
||||
<testcase classname="<exe-name>.global" name="#1403" time="{duration}"/>
|
||||
<testcase classname="<exe-name>.global" name="#1514: stderr/stdout is not captured in tests aborted by an exception" time="{duration}">
|
||||
<failure type="FAIL">
|
||||
1514
|
||||
Tricky.tests.cpp:<line number>
|
||||
</failure>
|
||||
<system-out>
|
||||
This would not be caught previously
|
||||
</system-out>
|
||||
<system-err>
|
||||
Nor would this
|
||||
</system-err>
|
||||
</testcase>
|
||||
<testcase classname="<exe-name>.global" name="#1548" time="{duration}"/>
|
||||
<testcase classname="<exe-name>.global" name="#748 - captures with unexpected exceptions/outside assertions" time="{duration}">
|
||||
<error type="TEST_CASE">
|
||||
expected exception
|
||||
@@ -70,13 +86,37 @@ Condition.tests.cpp:<line number>
|
||||
<testcase classname="<exe-name>.global" name="(unimplemented) static bools can be evaluated/negation" time="{duration}"/>
|
||||
<testcase classname="<exe-name>.global" name="(unimplemented) static bools can be evaluated/double negation" time="{duration}"/>
|
||||
<testcase classname="<exe-name>.global" name="(unimplemented) static bools can be evaluated/direct" time="{duration}"/>
|
||||
<testcase classname="<exe-name>.global" name="10x10 ints" time="{duration}"/>
|
||||
<testcase classname="<exe-name>.global" name="3x3x3 ints" time="{duration}"/>
|
||||
<testcase classname="<exe-name>.TestClass" name="A METHOD_AS_TEST_CASE based test run that fails" time="{duration}">
|
||||
<failure message=""hello" == "world"" type="REQUIRE">
|
||||
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 - Template_Foo<float>" time="{duration}">
|
||||
<failure message="0 == 1" type="REQUIRE">
|
||||
Class.tests.cpp:<line number>
|
||||
</failure>
|
||||
</testcase>
|
||||
<testcase classname="<exe-name>.Template_Fixture_2" name="A TEMPLATE_PRODUCT_TEST_CASE_METHOD based test run that fails - Template_Foo<int>" time="{duration}">
|
||||
<failure message="0 == 1" type="REQUIRE">
|
||||
Class.tests.cpp:<line number>
|
||||
</failure>
|
||||
</testcase>
|
||||
<testcase classname="<exe-name>.Template_Fixture_2" name="A TEMPLATE_PRODUCT_TEST_CASE_METHOD based test run that fails - std::vector<float>" time="{duration}">
|
||||
<failure message="0 == 1" type="REQUIRE">
|
||||
Class.tests.cpp:<line number>
|
||||
</failure>
|
||||
</testcase>
|
||||
<testcase classname="<exe-name>.Template_Fixture_2" name="A TEMPLATE_PRODUCT_TEST_CASE_METHOD based test run that fails - std::vector<int>" time="{duration}">
|
||||
<failure message="0 == 1" type="REQUIRE">
|
||||
Class.tests.cpp:<line number>
|
||||
</failure>
|
||||
</testcase>
|
||||
<testcase classname="<exe-name>.Template_Fixture_2" name="A TEMPLATE_PRODUCT_TEST_CASE_METHOD based test run that succeeds - Template_Foo<float>" time="{duration}"/>
|
||||
<testcase classname="<exe-name>.Template_Fixture_2" name="A TEMPLATE_PRODUCT_TEST_CASE_METHOD based test run that succeeds - Template_Foo<int>" time="{duration}"/>
|
||||
<testcase classname="<exe-name>.Template_Fixture_2" name="A TEMPLATE_PRODUCT_TEST_CASE_METHOD based test run that succeeds - std::vector<float>" time="{duration}"/>
|
||||
<testcase classname="<exe-name>.Template_Fixture_2" name="A TEMPLATE_PRODUCT_TEST_CASE_METHOD based test run that succeeds - std::vector<int>" time="{duration}"/>
|
||||
<testcase classname="<exe-name>.Template_Fixture" name="A TEMPLATE_TEST_CASE_METHOD based test run that fails - double" time="{duration}">
|
||||
<failure message="1.0 == 2" type="REQUIRE">
|
||||
Class.tests.cpp:<line number>
|
||||
@@ -101,6 +141,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 - Foo<float>" time="{duration}"/>
|
||||
<testcase classname="<exe-name>.global" name="A Template product test case - Foo<int>" time="{duration}"/>
|
||||
<testcase classname="<exe-name>.global" name="A Template product test case - std::vector<float>" time="{duration}"/>
|
||||
<testcase classname="<exe-name>.global" name="A Template product test case - std::vector<int>" time="{duration}"/>
|
||||
<testcase classname="<exe-name>.global" name="A comparison that uses literals instead of the normal constructor" time="{duration}"/>
|
||||
<testcase classname="<exe-name>.global" name="A couple of nested sections followed by a failure" time="{duration}">
|
||||
<failure type="FAIL">
|
||||
@@ -311,14 +355,35 @@ 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/one" time="{duration}"/>
|
||||
<testcase classname="<exe-name>.global" name="Generators/two" time="{duration}"/>
|
||||
<testcase classname="<exe-name>.global" name="Generators impl/range" time="{duration}"/>
|
||||
<testcase classname="<exe-name>.global" name="Generators impl/fixed values" time="{duration}"/>
|
||||
<testcase classname="<exe-name>.global" name="Generators impl/combined" time="{duration}"/>
|
||||
<testcase classname="<exe-name>.global" name="Generators impl/values" time="{duration}"/>
|
||||
<testcase classname="<exe-name>.global" name="Generators impl/values2" time="{duration}"/>
|
||||
<testcase classname="<exe-name>.global" name="Generators impl/type erasure" 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/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}"/>
|
||||
<testcase classname="<exe-name>.global" name="Generators internals/Preset values" time="{duration}"/>
|
||||
<testcase classname="<exe-name>.global" name="Generators internals/Generator combinator" time="{duration}"/>
|
||||
<testcase classname="<exe-name>.global" name="Generators internals/Explicitly typed generator sequence" time="{duration}"/>
|
||||
<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/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}">
|
||||
@@ -526,6 +591,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 - std::tuple<int, double, float>" time="{duration}"/>
|
||||
<testcase classname="<exe-name>.global" name="Product with differing arities - std::tuple<int, double>" time="{duration}"/>
|
||||
<testcase classname="<exe-name>.global" name="Product with differing arities - std::tuple<int>" time="{duration}"/>
|
||||
<testcase classname="<exe-name>.global" name="Reconstruction should be based on stringification: #914" time="{duration}">
|
||||
<failure message="Hey, its truthy!" type="CHECK">
|
||||
Decomposition.tests.cpp:<line number>
|
||||
@@ -660,13 +728,6 @@ Exception.tests.cpp:<line number>
|
||||
<testcase classname="<exe-name>.global" name="Tracker/successfully close one section, then find another/Re-enter - skips S1 and enters S2/Successfully close S2" time="{duration}"/>
|
||||
<testcase classname="<exe-name>.global" name="Tracker/successfully close one section, then find another/Re-enter - skips S1 and enters S2/fail S2" time="{duration}"/>
|
||||
<testcase classname="<exe-name>.global" name="Tracker/open a nested section" time="{duration}"/>
|
||||
<testcase classname="<exe-name>.global" name="Tracker/start a generator" time="{duration}"/>
|
||||
<testcase classname="<exe-name>.global" name="Tracker/start a generator/close outer section" time="{duration}"/>
|
||||
<testcase classname="<exe-name>.global" name="Tracker/start a generator/close outer section/Re-enter for second generation" time="{duration}"/>
|
||||
<testcase classname="<exe-name>.global" name="Tracker/start a generator/Start a new inner section" time="{duration}"/>
|
||||
<testcase classname="<exe-name>.global" name="Tracker/start a generator/Start a new inner section/Re-enter for second generation" time="{duration}"/>
|
||||
<testcase classname="<exe-name>.global" name="Tracker/start a generator/Fail an inner section" time="{duration}"/>
|
||||
<testcase classname="<exe-name>.global" name="Tracker/start a generator/Fail an inner section/Re-enter for second generation" time="{duration}"/>
|
||||
<testcase classname="<exe-name>.global" name="Unexpected exceptions can be translated" time="{duration}">
|
||||
<error type="TEST_CASE">
|
||||
3.14
|
||||
@@ -804,6 +865,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>
|
||||
@@ -852,6 +919,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>
|
||||
@@ -864,10 +932,30 @@ Misc.tests.cpp:<line number>
|
||||
<testcase classname="<exe-name>.global" name="non streamable - with conv. op" time="{duration}"/>
|
||||
<testcase classname="<exe-name>.global" name="non-copyable objects" time="{duration}"/>
|
||||
<testcase classname="<exe-name>.global" name="not allowed" time="{duration}"/>
|
||||
<testcase classname="<exe-name>.global" name="not prints unscoped info from previous failures" time="{duration}">
|
||||
<failure message="false" type="REQUIRE">
|
||||
this SHOULD be seen
|
||||
Message.tests.cpp:<line number>
|
||||
</failure>
|
||||
</testcase>
|
||||
<testcase classname="<exe-name>.global" name="null strings" time="{duration}"/>
|
||||
<testcase classname="<exe-name>.global" name="null_ptr" time="{duration}"/>
|
||||
<testcase classname="<exe-name>.global" name="pair<pair<int,const char *,pair<std::string,int> > -> toString" time="{duration}"/>
|
||||
<testcase classname="<exe-name>.global" name="pointer to class" time="{duration}"/>
|
||||
<testcase classname="<exe-name>.global" name="print unscoped info if passing unscoped info is printed" time="{duration}"/>
|
||||
<testcase classname="<exe-name>.global" name="prints unscoped info on failure" time="{duration}">
|
||||
<failure message="false" type="REQUIRE">
|
||||
this SHOULD be seen
|
||||
this SHOULD also be seen
|
||||
Message.tests.cpp:<line number>
|
||||
</failure>
|
||||
</testcase>
|
||||
<testcase classname="<exe-name>.global" name="prints unscoped info only for the first assertion" time="{duration}">
|
||||
<failure message="false" type="CHECK">
|
||||
this SHOULD be seen only ONCE
|
||||
Message.tests.cpp:<line number>
|
||||
</failure>
|
||||
</testcase>
|
||||
<testcase classname="<exe-name>.global" name="random SECTION tests/doesn't equal" time="{duration}"/>
|
||||
<testcase classname="<exe-name>.global" name="random SECTION tests/not equal" time="{duration}"/>
|
||||
<testcase classname="<exe-name>.global" name="replaceInPlace/replace single char" time="{duration}"/>
|
||||
@@ -887,6 +975,22 @@ 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="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>
|
||||
@@ -914,6 +1018,7 @@ Tricky.tests.cpp:<line number>
|
||||
<testcase classname="<exe-name>.global" name="stringify( vectors<has_maker_and_operator> )" time="{duration}"/>
|
||||
<testcase classname="<exe-name>.global" name="stringify( vectors<has_operator> )" time="{duration}"/>
|
||||
<testcase classname="<exe-name>.global" name="strlen3" time="{duration}"/>
|
||||
<testcase classname="<exe-name>.global" name="tables" time="{duration}"/>
|
||||
<testcase classname="<exe-name>.global" name="thrown std::strings are translated" time="{duration}">
|
||||
<error type="TEST_CASE">
|
||||
Why would you throw a std::string?
|
||||
@@ -948,11 +1053,13 @@ Exception.tests.cpp:<line number>
|
||||
<testcase classname="<exe-name>.global" name="xmlentitycheck/embedded xml: <test>it should be possible to embed xml characters, such as <, " or &, or even whole <xml>documents</xml> within an attribute</test>" time="{duration}"/>
|
||||
<testcase classname="<exe-name>.global" name="xmlentitycheck/encoded chars: these should all be encoded: &&&"""<<<&"<<&"" time="{duration}"/>
|
||||
<system-out>
|
||||
This would not be caught previously
|
||||
A string sent directly to stdout
|
||||
Message from section one
|
||||
Message from section two
|
||||
</system-out>
|
||||
<system-err>
|
||||
Nor would this
|
||||
A string sent directly to stderr
|
||||
A string sent to stderr via clog
|
||||
</system-err>
|
||||
|
File diff suppressed because it is too large
Load Diff
@@ -1,93 +1,209 @@
|
||||
#include "catch.hpp"
|
||||
|
||||
// Tests of generartor implementation details
|
||||
|
||||
TEST_CASE("Generators impl", "[impl]") {
|
||||
// Tests of generator implementation details
|
||||
TEST_CASE("Generators internals", "[generators][internals]") {
|
||||
using namespace Catch::Generators;
|
||||
|
||||
SECTION( "range" ) {
|
||||
auto gen = range(1,3);
|
||||
|
||||
CHECK( gen.size() == 2 );
|
||||
|
||||
CHECK( gen[0] == 1 );
|
||||
CHECK( gen[1] == 2 );
|
||||
SECTION("Single value") {
|
||||
auto gen = value(123);
|
||||
REQUIRE(gen.get() == 123);
|
||||
REQUIRE_FALSE(gen.next());
|
||||
}
|
||||
SECTION( "fixed values" ) {
|
||||
auto gen = values( { 3, 1, 4, 1 } );
|
||||
|
||||
CHECK( gen.size() == 4 );
|
||||
CHECK( gen[0] == 3 );
|
||||
CHECK( gen[1] == 1 );
|
||||
CHECK( gen[2] == 4 );
|
||||
CHECK( gen[3] == 1 );
|
||||
SECTION("Preset values") {
|
||||
auto gen = values({ 1, 3, 5 });
|
||||
REQUIRE(gen.get() == 1);
|
||||
REQUIRE(gen.next());
|
||||
REQUIRE(gen.get() == 3);
|
||||
REQUIRE(gen.next());
|
||||
REQUIRE(gen.get() == 5);
|
||||
REQUIRE_FALSE(gen.next());
|
||||
}
|
||||
SECTION( "combined" ) {
|
||||
auto gen = makeGenerators( range( 1, 3 ), values( { 9, 7 } ) );
|
||||
|
||||
CHECK( gen.size() == 4 );
|
||||
CHECK( gen[0] == 1 );
|
||||
CHECK( gen[1] == 2 );
|
||||
CHECK( gen[2] == 9 );
|
||||
CHECK( gen[3] == 7 );
|
||||
SECTION("Generator combinator") {
|
||||
auto gen = makeGenerators(1, 5, values({ 2, 4 }), 0);
|
||||
REQUIRE(gen.get() == 1);
|
||||
REQUIRE(gen.next());
|
||||
REQUIRE(gen.get() == 5);
|
||||
REQUIRE(gen.next());
|
||||
REQUIRE(gen.get() == 2);
|
||||
REQUIRE(gen.next());
|
||||
REQUIRE(gen.get() == 4);
|
||||
REQUIRE(gen.next());
|
||||
REQUIRE(gen.get() == 0);
|
||||
REQUIRE_FALSE(gen.next());
|
||||
}
|
||||
|
||||
SECTION( "values" ) {
|
||||
auto gen = makeGenerators( 3, 1 );
|
||||
|
||||
CHECK( gen.size() == 2 );
|
||||
CHECK( gen[0] == 3 );
|
||||
CHECK( gen[1] == 1 );
|
||||
SECTION("Explicitly typed generator sequence") {
|
||||
auto gen = makeGenerators(as<std::string>{}, "aa", "bb", "cc");
|
||||
// This just checks that the type is std::string:
|
||||
REQUIRE(gen.get().size() == 2);
|
||||
// Iterate over the generator
|
||||
REQUIRE(gen.get() == "aa");
|
||||
REQUIRE(gen.next());
|
||||
REQUIRE(gen.get() == "bb");
|
||||
REQUIRE(gen.next());
|
||||
REQUIRE(gen.get() == "cc");
|
||||
REQUIRE_FALSE(gen.next());
|
||||
}
|
||||
SECTION( "values2" ) {
|
||||
auto gen = makeGenerators( 3, 1 );
|
||||
SECTION("Filter generator") {
|
||||
// Normal usage
|
||||
auto gen = filter([] (int i) { return i != 2; }, values({ 2, 1, 2, 3, 2, 2 }));
|
||||
REQUIRE(gen.get() == 1);
|
||||
REQUIRE(gen.next());
|
||||
REQUIRE(gen.get() == 3);
|
||||
REQUIRE_FALSE(gen.next());
|
||||
|
||||
CHECK( gen.size() == 2 );
|
||||
CHECK( gen[0] == 3 );
|
||||
CHECK( gen[1] == 1 );
|
||||
// Completely filtered-out generator should throw on construction
|
||||
REQUIRE_THROWS_AS(filter([] (int) { return false; }, value(1)), Catch::GeneratorException);
|
||||
}
|
||||
|
||||
|
||||
SECTION( "type erasure" ) {
|
||||
auto gen = makeGenerators( range( 7, 10 ), 11 );
|
||||
|
||||
// Make type erased version
|
||||
auto dynCopy = pf::make_unique<Generators<int>>( std::move( gen ) );
|
||||
std::unique_ptr<GeneratorBase const> base = std::move( dynCopy );
|
||||
|
||||
// Only thing we can do is ask for the size
|
||||
CHECK( base->size() == 4 );
|
||||
|
||||
// Restore typed version
|
||||
auto typed = dynamic_cast<Generators<int> const*>( base.get() );
|
||||
REQUIRE( typed );
|
||||
CHECK( typed->size() == 4 );
|
||||
CHECK( (*typed)[0] == 7 );
|
||||
CHECK( (*typed)[3] == 11 );
|
||||
SECTION("Take generator") {
|
||||
SECTION("Take less") {
|
||||
auto gen = take(2, values({ 1, 2, 3 }));
|
||||
REQUIRE(gen.get() == 1);
|
||||
REQUIRE(gen.next());
|
||||
REQUIRE(gen.get() == 2);
|
||||
REQUIRE_FALSE(gen.next());
|
||||
}
|
||||
SECTION("Take more") {
|
||||
auto gen = take(2, value(1));
|
||||
REQUIRE(gen.get() == 1);
|
||||
REQUIRE_FALSE(gen.next());
|
||||
}
|
||||
}
|
||||
|
||||
TEST_CASE("Generators impl - random", "[approvals]") {
|
||||
using namespace Catch::Generators;
|
||||
|
||||
SECTION( "random range" ) {
|
||||
auto gen = random( 3, 9 );
|
||||
|
||||
CHECK( gen.size() == 6 );
|
||||
for( size_t i = 0; i < 6; ++i ) {
|
||||
CHECK( gen[i] >= 3 );
|
||||
CHECK( gen[i] <= 8 );
|
||||
if( i > 0 )
|
||||
CHECK( gen[i] != gen[i-1] );
|
||||
SECTION("Map") {
|
||||
auto gen = map<double>([] (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));
|
||||
REQUIRE(gen.get() == 3);
|
||||
REQUIRE_FALSE(gen.next());
|
||||
}
|
||||
SECTION("Actual repeat") {
|
||||
auto gen = repeat(2, values({ 1, 2, 3 }));
|
||||
REQUIRE(gen.get() == 1);
|
||||
REQUIRE(gen.next());
|
||||
REQUIRE(gen.get() == 2);
|
||||
REQUIRE(gen.next());
|
||||
REQUIRE(gen.get() == 3);
|
||||
REQUIRE(gen.next());
|
||||
REQUIRE(gen.get() == 1);
|
||||
REQUIRE(gen.next());
|
||||
REQUIRE(gen.get() == 2);
|
||||
REQUIRE(gen.next());
|
||||
REQUIRE(gen.get() == 3);
|
||||
REQUIRE_FALSE(gen.next());
|
||||
}
|
||||
}
|
||||
SECTION( "random selection" ) {
|
||||
auto gen = random<int>( 10 );
|
||||
|
||||
CHECK( gen.size() == 10 );
|
||||
for( size_t i = 0; i < 10; ++i ) {
|
||||
if( i > 0 )
|
||||
CHECK( gen[i] != gen[i-1] );
|
||||
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());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
@@ -173,154 +173,34 @@ TEST_CASE( "Tracker" ) {
|
||||
testCase.close();
|
||||
REQUIRE( testCase.isComplete() );
|
||||
}
|
||||
|
||||
SECTION( "start a generator" ) {
|
||||
IndexTracker& g1 = IndexTracker::acquire( ctx, makeNAL( "G1" ), 2 );
|
||||
REQUIRE( g1.isOpen() );
|
||||
REQUIRE( g1.index() == 0 );
|
||||
|
||||
REQUIRE( g1.isComplete() == false );
|
||||
REQUIRE( s1.isComplete() == false );
|
||||
|
||||
SECTION( "close outer section" )
|
||||
{
|
||||
s1.close();
|
||||
REQUIRE( s1.isComplete() == false );
|
||||
testCase.close();
|
||||
REQUIRE( testCase.isSuccessfullyCompleted() == false );
|
||||
|
||||
SECTION( "Re-enter for second generation" ) {
|
||||
ctx.startCycle();
|
||||
ITracker& testCase2 = SectionTracker::acquire( ctx, makeNAL( "Testcase" ) );
|
||||
REQUIRE( testCase2.isOpen() );
|
||||
|
||||
ITracker& s1b = SectionTracker::acquire( ctx, makeNAL( "S1" ) );
|
||||
REQUIRE( s1b.isOpen() );
|
||||
|
||||
|
||||
IndexTracker& g1b = IndexTracker::acquire( ctx, makeNAL( "G1" ), 2 );
|
||||
REQUIRE( g1b.isOpen() );
|
||||
REQUIRE( g1b.index() == 1 );
|
||||
|
||||
REQUIRE( s1.isComplete() == false );
|
||||
|
||||
s1b.close();
|
||||
REQUIRE( s1b.isComplete() );
|
||||
REQUIRE( g1b.isComplete() );
|
||||
testCase2.close();
|
||||
REQUIRE( testCase2.isComplete() );
|
||||
}
|
||||
|
||||
static bool previouslyRun = false;
|
||||
static bool previouslyRunNested = false;
|
||||
|
||||
TEST_CASE( "#1394", "[.][approvals][tracker]" ) {
|
||||
// -- Don't re-run after specified section is done
|
||||
REQUIRE(previouslyRun == false);
|
||||
|
||||
SECTION( "RunSection" ) {
|
||||
previouslyRun = true;
|
||||
}
|
||||
SECTION( "Start a new inner section" ) {
|
||||
ITracker& s2 = SectionTracker::acquire( ctx, makeNAL( "S2" ) );
|
||||
REQUIRE( s2.isOpen() );
|
||||
|
||||
s2.close();
|
||||
REQUIRE( s2.isComplete() );
|
||||
|
||||
s1.close();
|
||||
REQUIRE( s1.isComplete() == false );
|
||||
|
||||
testCase.close();
|
||||
REQUIRE( testCase.isComplete() == false );
|
||||
|
||||
SECTION( "Re-enter for second generation" ) {
|
||||
ctx.startCycle();
|
||||
ITracker& testCase2 = SectionTracker::acquire( ctx, makeNAL( "Testcase" ) );
|
||||
REQUIRE( testCase2.isOpen() );
|
||||
|
||||
ITracker& s1b = SectionTracker::acquire( ctx, makeNAL( "S1" ) );
|
||||
REQUIRE( s1b.isOpen() );
|
||||
|
||||
// generator - next value
|
||||
IndexTracker& g1b = IndexTracker::acquire( ctx, makeNAL( "G1" ), 2 );
|
||||
REQUIRE( g1b.isOpen() );
|
||||
REQUIRE( g1b.index() == 1 );
|
||||
|
||||
// inner section again
|
||||
ITracker& s2b = SectionTracker::acquire( ctx, makeNAL( "S2" ) );
|
||||
REQUIRE( s2b.isOpen() );
|
||||
|
||||
s2b.close();
|
||||
REQUIRE( s2b.isComplete() );
|
||||
|
||||
s1b.close();
|
||||
REQUIRE( g1b.isComplete() );
|
||||
REQUIRE( s1b.isComplete() );
|
||||
|
||||
testCase2.close();
|
||||
REQUIRE( testCase2.isComplete() );
|
||||
SECTION( "SkipSection" ) {
|
||||
// cause an error if this section is called because it shouldn't be
|
||||
REQUIRE(1 == 0);
|
||||
}
|
||||
}
|
||||
|
||||
SECTION( "Fail an inner section" ) {
|
||||
ITracker& s2 = SectionTracker::acquire( ctx, makeNAL( "S2" ) );
|
||||
REQUIRE( s2.isOpen() );
|
||||
TEST_CASE( "#1394 nested", "[.][approvals][tracker]" ) {
|
||||
REQUIRE(previouslyRunNested == false);
|
||||
|
||||
s2.fail();
|
||||
REQUIRE( s2.isComplete() );
|
||||
REQUIRE( s2.isSuccessfullyCompleted() == false );
|
||||
|
||||
s1.close();
|
||||
REQUIRE( s1.isComplete() == false );
|
||||
|
||||
testCase.close();
|
||||
REQUIRE( testCase.isComplete() == false );
|
||||
|
||||
SECTION( "Re-enter for second generation" ) {
|
||||
ctx.startCycle();
|
||||
ITracker& testCase2 = SectionTracker::acquire( ctx, makeNAL( "Testcase" ) );
|
||||
REQUIRE( testCase2.isOpen() );
|
||||
|
||||
ITracker& s1b = SectionTracker::acquire( ctx, makeNAL( "S1" ) );
|
||||
REQUIRE( s1b.isOpen() );
|
||||
|
||||
// generator - still same value
|
||||
IndexTracker& g1b = IndexTracker::acquire( ctx, makeNAL( "G1" ), 2 );
|
||||
REQUIRE( g1b.isOpen() );
|
||||
REQUIRE( g1b.index() == 0 );
|
||||
|
||||
// inner section again - this time won't open
|
||||
ITracker& s2b = SectionTracker::acquire( ctx, makeNAL( "S2" ) );
|
||||
REQUIRE( s2b.isOpen() == false );
|
||||
|
||||
s1b.close();
|
||||
REQUIRE( g1b.isComplete() == false );
|
||||
REQUIRE( s1b.isComplete() == false );
|
||||
|
||||
testCase2.close();
|
||||
REQUIRE( testCase2.isComplete() == false );
|
||||
|
||||
// Another cycle - now should complete
|
||||
ctx.startCycle();
|
||||
ITracker& testCase3 = SectionTracker::acquire( ctx, makeNAL( "Testcase" ) );
|
||||
REQUIRE( testCase3.isOpen() );
|
||||
|
||||
ITracker& s1c = SectionTracker::acquire( ctx, makeNAL( "S1" ) );
|
||||
REQUIRE( s1c.isOpen() );
|
||||
|
||||
// generator - now next value
|
||||
IndexTracker& g1c = IndexTracker::acquire( ctx, makeNAL( "G1" ), 2 );
|
||||
REQUIRE( g1c.isOpen() );
|
||||
REQUIRE( g1c.index() == 1 );
|
||||
|
||||
// inner section - now should open again
|
||||
ITracker& s2c = SectionTracker::acquire( ctx, makeNAL( "S2" ) );
|
||||
REQUIRE( s2c.isOpen() );
|
||||
|
||||
s2c.close();
|
||||
REQUIRE( s2c.isComplete() );
|
||||
|
||||
s1c.close();
|
||||
REQUIRE( g1c.isComplete() );
|
||||
REQUIRE( s1c.isComplete() );
|
||||
|
||||
testCase3.close();
|
||||
REQUIRE( testCase3.isComplete() );
|
||||
SECTION( "NestedRunSection" ) {
|
||||
SECTION( "s1" ) {
|
||||
previouslyRunNested = true;
|
||||
}
|
||||
}
|
||||
// !TBD"
|
||||
// nested generator
|
||||
// two sections within a generator
|
||||
SECTION( "NestedSkipSection" ) {
|
||||
// cause an error if this section is called because it shouldn't be
|
||||
REQUIRE(1 == 0);
|
||||
}
|
||||
}
|
||||
|
@@ -46,6 +46,18 @@ struct Template_Fixture {
|
||||
T m_a;
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
struct Template_Fixture_2 {
|
||||
Template_Fixture_2() {}
|
||||
|
||||
T m_a;
|
||||
};
|
||||
|
||||
template< typename T>
|
||||
struct Template_Foo {
|
||||
size_t size() { return 0; }
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
@@ -62,6 +74,11 @@ TEMPLATE_TEST_CASE_METHOD(Template_Fixture, "A TEMPLATE_TEST_CASE_METHOD based t
|
||||
REQUIRE( Template_Fixture<TestType>::m_a == 1 );
|
||||
}
|
||||
|
||||
TEMPLATE_PRODUCT_TEST_CASE_METHOD(Template_Fixture_2, "A TEMPLATE_PRODUCT_TEST_CASE_METHOD based test run that succeeds","[class][template][product]",(std::vector,Template_Foo),(int,float))
|
||||
{
|
||||
REQUIRE( Template_Fixture_2<TestType>::m_a.size() == 0 );
|
||||
}
|
||||
|
||||
// We should be able to write our tests within a different namespace
|
||||
namespace Inner
|
||||
{
|
||||
@@ -74,6 +91,11 @@ namespace Inner
|
||||
{
|
||||
REQUIRE( Template_Fixture<TestType>::m_a == 2 );
|
||||
}
|
||||
|
||||
TEMPLATE_PRODUCT_TEST_CASE_METHOD(Template_Fixture_2, "A TEMPLATE_PRODUCT_TEST_CASE_METHOD based test run that fails","[.][class][template][product][failing]",(std::vector,Template_Foo),(int,float))
|
||||
{
|
||||
REQUIRE( Template_Fixture_2<TestType>::m_a.size() == 1 );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
@@ -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
|
||||
|
||||
|
||||
|
@@ -1,75 +1,63 @@
|
||||
#include "catch.hpp"
|
||||
|
||||
// Examples of usage of Generators
|
||||
#include <cstring>
|
||||
|
||||
// This test doesn't do much - it just shows how you can have several generators, of different
|
||||
// types (ie `i` and `j` are different types), can be sequenced using `,` and
|
||||
// can be expressed as named generators (like range) or as individual values.
|
||||
// Generators can be mixed with SECTIONs.
|
||||
// At time of writing the generated values are not automatically reported as part of the test
|
||||
// name or associated values - so we explicitly CAPTURE then (run this with `-s` to see them).
|
||||
// We could also incorporate them into the section names using DYNAMIC_SECTION. See the BDD
|
||||
// example later for more information.
|
||||
TEST_CASE("Generators") {
|
||||
|
||||
auto i = GENERATE( as<std::string>(), "a", "b", "c" );
|
||||
|
||||
// Generators and sections can be nested freely
|
||||
TEST_CASE("Generators -- simple", "[generators]") {
|
||||
auto i = GENERATE(1, 2, 3);
|
||||
SECTION("one") {
|
||||
auto j = GENERATE( range( 8, 11 ), 2 );
|
||||
|
||||
CAPTURE( i, j );
|
||||
SUCCEED();
|
||||
auto j = GENERATE(values({ -3, -2, -1 }));
|
||||
REQUIRE(j < i);
|
||||
}
|
||||
|
||||
SECTION("two") {
|
||||
auto j = GENERATE( 3.141, 1.379 );
|
||||
CAPTURE( i, j );
|
||||
SUCCEED();
|
||||
// You can also explicitly set type for generators via Catch::Generators::as
|
||||
auto str = GENERATE(as<std::string>{}, "a", "bb", "ccc");
|
||||
REQUIRE(4u * i > str.size());
|
||||
}
|
||||
}
|
||||
|
||||
// This one generates the cross-product of two ranges.
|
||||
// It's mostly here to demonstrate the performance which, at time of writing,
|
||||
// leaves a lot to be desired.
|
||||
TEST_CASE( "100x100 ints", "[.][approvals]" ) {
|
||||
auto x = GENERATE( range( 0,100 ) );
|
||||
auto y = GENERATE( range( 200,300 ) );
|
||||
|
||||
// You can create a cartesian-product of generators by creating multiple ones
|
||||
TEST_CASE("3x3x3 ints", "[generators]") {
|
||||
auto x = GENERATE(1, 2, 3);
|
||||
auto y = GENERATE(4, 5, 6);
|
||||
auto z = GENERATE(7, 8, 9);
|
||||
// These assertions will be run 27 times (3x3x3)
|
||||
CHECK(x < y);
|
||||
CHECK(y < z);
|
||||
REQUIRE(x < z);
|
||||
}
|
||||
|
||||
// smaller version
|
||||
TEST_CASE( "10x10 ints" ) {
|
||||
auto x = GENERATE( range( 1,11 ) );
|
||||
auto y = GENERATE( range( 101, 111 ) );
|
||||
// You can also create data tuples
|
||||
TEST_CASE("tables", "[generators]") {
|
||||
// Note that this will not compile with libstdc++ older than libstdc++6
|
||||
// See https://stackoverflow.com/questions/12436586/tuple-vector-and-initializer-list
|
||||
// for possible workarounds
|
||||
// auto data = GENERATE(table<char const*, int>({
|
||||
// {"first", 5},
|
||||
// {"second", 6},
|
||||
// {"third", 5},
|
||||
// {"etc...", 6}
|
||||
// }));
|
||||
|
||||
CHECK( x < y );
|
||||
// Workaround for the libstdc++ bug mentioned above
|
||||
using tuple_type = std::tuple<char const*, int>;
|
||||
auto data = GENERATE(table<char const*, int>({
|
||||
tuple_type{"first", 5},
|
||||
tuple_type{"second", 6},
|
||||
tuple_type{"third", 5},
|
||||
tuple_type{"etc...", 6}
|
||||
}));
|
||||
|
||||
REQUIRE(strlen(std::get<0>(data)) == static_cast<size_t>(std::get<1>(data)));
|
||||
}
|
||||
|
||||
// Some of the following tests use structured bindings for convenience and so are
|
||||
// conditionally compiled using the de-facto (and soon to be formally) standard
|
||||
// feature macros
|
||||
|
||||
#ifdef __cpp_structured_bindings
|
||||
|
||||
// One way to do pairs of values (actual/ expected?)
|
||||
// For a simple case like this I'd recommend writing out a series of REQUIREs
|
||||
// but it demonstrates a possible usage.
|
||||
// Spelling out the pair like this is a bit verbose, so read on for better examples
|
||||
// - the use of structured bindings here is an optional convenience
|
||||
TEST_CASE( "strlen", "[approvals]" ) {
|
||||
auto [test_input, expected] = GENERATE( values<std::pair<std::string_view, size_t>>({
|
||||
{"one", 3},
|
||||
{"two", 3},
|
||||
{"three", 5},
|
||||
{"four", 4}
|
||||
}));
|
||||
|
||||
REQUIRE( test_input.size() == expected );
|
||||
}
|
||||
|
||||
// A nicer way to do pairs (or more) of values - using the table generator.
|
||||
// Note, you must specify the types up-front.
|
||||
TEST_CASE( "strlen2", "[approvals]" ) {
|
||||
// Structured bindings make the table utility much nicer to use
|
||||
TEST_CASE( "strlen2", "[approvals][generators]" ) {
|
||||
auto [test_input, expected] = GENERATE( table<std::string, size_t>({
|
||||
{"one", 3},
|
||||
{"two", 3},
|
||||
@@ -81,11 +69,11 @@ TEST_CASE( "strlen2", "[approvals]" ) {
|
||||
}
|
||||
#endif
|
||||
|
||||
// An alternate way of doing data tables without structure bindings
|
||||
// - I'd prefer to have the Data class within the test case but gcc 4.x doesn't seem to like it
|
||||
|
||||
// An alternate way of doing data tables without structured bindings
|
||||
struct Data { std::string str; size_t len; };
|
||||
|
||||
TEST_CASE( "strlen3" ) {
|
||||
TEST_CASE( "strlen3", "[generators]" ) {
|
||||
auto data = GENERATE( values<Data>({
|
||||
{"one", 3},
|
||||
{"two", 3},
|
||||
@@ -96,15 +84,7 @@ TEST_CASE( "strlen3" ) {
|
||||
REQUIRE( data.str.size() == data.len );
|
||||
}
|
||||
|
||||
// A nod towards property-based testing - generate a random selection of numbers
|
||||
// in a range and assert on global properties those numbers.
|
||||
static auto square( int i ) -> int { return i*i; }
|
||||
|
||||
TEST_CASE( "Random numbers in a range", "[.][approvals]" ) {
|
||||
auto x = GENERATE( random( -10000, 10000 ) );
|
||||
CAPTURE( x );
|
||||
REQUIRE( square(x) >= 0 );
|
||||
}
|
||||
|
||||
#ifdef __cpp_structured_bindings
|
||||
|
||||
@@ -118,7 +98,7 @@ TEST_CASE( "Random numbers in a range", "[.][approvals]" ) {
|
||||
|
||||
static auto eatCucumbers( int start, int eat ) -> int { return start-eat; }
|
||||
|
||||
SCENARIO("Eating cucumbers", "[approvals]") {
|
||||
SCENARIO("Eating cucumbers", "[generators][approvals]") {
|
||||
|
||||
auto [start, eat, left] = GENERATE( table<int,int,int> ({
|
||||
{ 12, 5, 7 },
|
||||
@@ -132,3 +112,74 @@ SCENARIO("Eating cucumbers", "[approvals]") {
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
// There are also some generic generator manipulators
|
||||
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") {
|
||||
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]
|
||||
auto i = GENERATE(take(3, values({ 1, 2, 3, 4, 5, 6 })));
|
||||
REQUIRE(i < 4);
|
||||
}
|
||||
SECTION("Transforming elements") {
|
||||
SECTION("Same type") {
|
||||
// This doubles values [1, 2, 3] into [2, 4, 6]
|
||||
auto i = GENERATE(map([] (int val) { return val * 2; }, values({ 1, 2, 3 })));
|
||||
REQUIRE(i % 2 == 0);
|
||||
}
|
||||
SECTION("Different type") {
|
||||
// This takes a generator that returns ints and maps them into strings
|
||||
auto i = GENERATE(map<std::string>([] (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
|
||||
}
|
||||
}
|
||||
|
@@ -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;
|
||||
|
@@ -61,6 +61,11 @@ CATCH_INTERNAL_SUPPRESS_GLOBALS_WARNINGS
|
||||
static AutoTestReg autoTestReg;
|
||||
CATCH_INTERNAL_UNSUPPRESS_GLOBALS_WARNINGS
|
||||
|
||||
template<typename T>
|
||||
struct Foo {
|
||||
size_t size() { return 0; }
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
TEST_CASE( "random SECTION tests", "[.][sections][failing]" ) {
|
||||
@@ -301,6 +306,15 @@ TEMPLATE_TEST_CASE( "TemplateTest: vectors can be sized and resized", "[vector][
|
||||
}
|
||||
}
|
||||
|
||||
TEMPLATE_PRODUCT_TEST_CASE("A Template product test case", "[template][product]", (std::vector, Foo), (int, float)) {
|
||||
TestType x;
|
||||
REQUIRE(x.size() == 0);
|
||||
}
|
||||
|
||||
TEMPLATE_PRODUCT_TEST_CASE("Product with differing arities", "[template][product]", std::tuple, (int, (int, double), (int, double, float))) {
|
||||
REQUIRE(std::tuple_size<TestType>::value >= 1);
|
||||
}
|
||||
|
||||
// https://github.com/philsquared/Catch/issues/166
|
||||
TEST_CASE("A couple of nested sections followed by a failure", "[failing][.]") {
|
||||
SECTION("Outer")
|
||||
|
23
projects/SelfTest/UsageTests/ToStringOptional.tests.cpp
Normal file
23
projects/SelfTest/UsageTests/ToStringOptional.tests.cpp
Normal file
@@ -0,0 +1,23 @@
|
||||
#define CATCH_CONFIG_ENABLE_OPTIONAL_STRINGMAKER
|
||||
#include "catch.hpp"
|
||||
|
||||
#if defined(CATCH_CONFIG_CPP17_OPTIONAL)
|
||||
|
||||
TEST_CASE( "std::optional<int> -> toString", "[toString][optional][approvals]" ) {
|
||||
using type = std::optional<int>;
|
||||
REQUIRE( "{ }" == ::Catch::Detail::stringify( type{} ) );
|
||||
REQUIRE( "0" == ::Catch::Detail::stringify( type{ 0 } ) );
|
||||
}
|
||||
|
||||
TEST_CASE( "std::optional<std::string> -> toString", "[toString][optional][approvals]" ) {
|
||||
using type = std::optional<std::string>;
|
||||
REQUIRE( "{ }" == ::Catch::Detail::stringify( type{} ) );
|
||||
REQUIRE( "\"abc\"" == ::Catch::Detail::stringify( type{ "abc" } ) );
|
||||
}
|
||||
|
||||
TEST_CASE( "std::vector<std::optional<int> > -> toString", "[toString][optional][approvals]" ) {
|
||||
using type = std::vector<std::optional<int> >;
|
||||
REQUIRE( "{ 0, { }, 2 }" == ::Catch::Detail::stringify( type{ 0, {}, 2 } ) );
|
||||
}
|
||||
|
||||
#endif // CATCH_INTERNAL_CONFIG_CPP17_OPTIONAL
|
@@ -6,6 +6,18 @@
|
||||
#include <string>
|
||||
#include <variant>
|
||||
|
||||
// We need 2 types with non-trivial copies/moves
|
||||
struct MyType1 {
|
||||
MyType1() = default;
|
||||
MyType1(MyType1 const&) { throw 1; }
|
||||
MyType1& operator=(MyType1 const&) { throw 3; }
|
||||
};
|
||||
struct MyType2 {
|
||||
MyType2() = default;
|
||||
MyType2(MyType2 const&) { throw 2; }
|
||||
MyType2& operator=(MyType2 const&) { throw 4; }
|
||||
};
|
||||
|
||||
TEST_CASE( "variant<std::monostate>", "[toString][variant][approvals]")
|
||||
{
|
||||
using type = std::variant<std::monostate>;
|
||||
@@ -26,18 +38,17 @@ TEST_CASE( "variant<float, int>", "[toString][variant][approvals]")
|
||||
using type = std::variant<float, int>;
|
||||
CHECK( "0.5f" == ::Catch::Detail::stringify(type{0.5f}) );
|
||||
CHECK( "0" == ::Catch::Detail::stringify(type{0}) );
|
||||
}
|
||||
|
||||
SECTION("valueless by exception") {
|
||||
struct sample {
|
||||
operator int() const { throw 42; }
|
||||
};
|
||||
TEST_CASE( "variant -- valueless-by-exception", "[toString][variant][approvals]" ) {
|
||||
using type = std::variant<MyType1, MyType2>;
|
||||
|
||||
type value{1.5f};
|
||||
REQUIRE_THROWS_AS( value.emplace<int>(sample{}), int );
|
||||
type value;
|
||||
REQUIRE_THROWS_AS(value.emplace<MyType2>(MyType2{}), int);
|
||||
REQUIRE(value.valueless_by_exception());
|
||||
CHECK("{valueless variant}" == ::Catch::Detail::stringify(value));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
TEST_CASE( "variant<string, int>", "[toString][variant][approvals]")
|
||||
{
|
||||
@@ -48,22 +59,18 @@ TEST_CASE( "variant<string, int>", "[toString][variant][approvals]")
|
||||
|
||||
TEST_CASE( "variant<variant<float, int>, string>", "[toString][variant][approvals]")
|
||||
{
|
||||
using inner = std::variant<float, int>;
|
||||
using inner = std::variant<MyType1, float, int>;
|
||||
using type = std::variant<inner, std::string>;
|
||||
CHECK( "0.5f" == ::Catch::Detail::stringify(type{0.5f}) );
|
||||
CHECK( "0" == ::Catch::Detail::stringify(type{0}) );
|
||||
CHECK( "\"foo\"" == ::Catch::Detail::stringify(type{"foo"}) );
|
||||
|
||||
struct sample {
|
||||
operator int() const { throw 42; }
|
||||
};
|
||||
|
||||
SECTION("valueless nested variant") {
|
||||
type value = inner{0.5f};
|
||||
REQUIRE( std::holds_alternative<inner>(value) );
|
||||
REQUIRE( std::holds_alternative<float>(std::get<inner>(value)) );
|
||||
|
||||
REQUIRE_THROWS_AS( std::get<0>(value).emplace<int>(sample{}), int );
|
||||
REQUIRE_THROWS_AS( std::get<0>(value).emplace<MyType1>(MyType1{}), int );
|
||||
|
||||
// outer variant is still valid and contains inner
|
||||
REQUIRE( std::holds_alternative<inner>(value) );
|
||||
|
@@ -19,6 +19,7 @@
|
||||
|
||||
#include <stdio.h>
|
||||
#include <sstream>
|
||||
#include <iostream>
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
TEST_CASE
|
||||
@@ -426,3 +427,10 @@ TEST_CASE( "Bitfields can be captured (#1027)" ) {
|
||||
REQUIRE( y.v == 0 );
|
||||
REQUIRE( 0 == y.v );
|
||||
}
|
||||
|
||||
TEST_CASE("#1514: stderr/stdout is not captured in tests aborted by an exception", "[output-capture][regression][.]") {
|
||||
std::cout << "This would not be caught previously\n" << std::flush;
|
||||
std::clog << "Nor would this\n" << std::flush;
|
||||
// FAIL aborts the test by throwing a Catch exception
|
||||
FAIL("1514");
|
||||
}
|
||||
|
@@ -6,9 +6,14 @@ import subprocess
|
||||
catchPath = os.path.dirname(os.path.realpath( os.path.dirname(sys.argv[0])))
|
||||
|
||||
def getBuildExecutable():
|
||||
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)
|
||||
lines = []
|
||||
|
File diff suppressed because it is too large
Load Diff
@@ -42,9 +42,9 @@ namespace Catch {
|
||||
bool assertionEnded( AssertionStats const& _assertionStats ) override {
|
||||
++counter;
|
||||
|
||||
stream << "# " << currentTestCaseInfo->name << std::endl;
|
||||
AssertionPrinter printer( stream, _assertionStats, counter );
|
||||
printer.print();
|
||||
stream << " # " << currentTestCaseInfo->name ;
|
||||
|
||||
stream << std::endl;
|
||||
return true;
|
||||
|
Reference in New Issue
Block a user