mirror of
https://github.com/catchorg/Catch2.git
synced 2025-09-11 07:55:39 +02:00
Compare commits
60 Commits
Author | SHA1 | Date | |
---|---|---|---|
![]() |
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.6.1)
|
||||
|
||||
# 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/rJhfG8exsneDGleb)
|
||||
[](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.6.1/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}\"")
|
||||
@@ -174,10 +174,17 @@ function(ParseFile SourceFile TestTarget)
|
||||
|
||||
# Add the test and set its properties
|
||||
add_test(NAME "\"${CTestName}\"" COMMAND ${OptionalCatchTestLauncher} ${TestTarget} ${Name} ${AdditionalCatchParameters})
|
||||
set_tests_properties("\"${CTestName}\"" PROPERTIES FAIL_REGULAR_EXPRESSION "No tests ran"
|
||||
LABELS "${Labels}")
|
||||
# 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/)
|
||||
|
@@ -200,11 +200,12 @@ On Windows Catch includes `windows.h`. To minimize global namespace clutter in t
|
||||
|
||||
By default, Catch does not stringify some types from the standard library. This is done to avoid dragging in various standard library headers by default. However, Catch does contain these and can be configured to provide them, using these macros:
|
||||
|
||||
CATCH_CONFIG_ENABLE_PAIR_STRINGMAKER // Provide StringMaker specialization for std::pair
|
||||
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_ALL_STRINGMAKERS // Defines all of the above
|
||||
CATCH_CONFIG_ENABLE_PAIR_STRINGMAKER // Provide StringMaker specialization for std::pair
|
||||
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
|
||||
|
||||
|
||||
## Disabling exceptions
|
||||
|
@@ -1,8 +1,8 @@
|
||||
<a id="top"></a>
|
||||
# Contributing to Catch
|
||||
|
||||
So you want to contribute something to Catch? That's great! Whether it's a bug fix, a new feature, support for
|
||||
additional compilers - or just a fix to the documentation - all contributions are very welcome and very much appreciated.
|
||||
So you want to contribute something to Catch? That's great! Whether it's a bug fix, a new feature, support for
|
||||
additional compilers - or just a fix to the documentation - all contributions are very welcome and very much appreciated.
|
||||
Of course so are bug reports and other comments and questions.
|
||||
|
||||
If you are contributing to the code base there are a few simple guidelines to keep in mind. This also includes notes to
|
||||
@@ -16,7 +16,7 @@ Ongoing development is currently on _master_. At some point an integration branc
|
||||
|
||||
## Directory structure
|
||||
|
||||
_Users_ of Catch primarily use the single header version. _Maintainers_ should work with the full source (which is still,
|
||||
_Users_ of Catch primarily use the single header version. _Maintainers_ should work with the full source (which is still,
|
||||
primarily, in headers). This can be found in the `include` folder. There are a set of test files, currently under
|
||||
`projects/SelfTest`. The test app can be built via CMake from the `CMakeLists.txt` file in the root, or you can generate
|
||||
project files for Visual Studio, XCode, and others (instructions in the `projects` folder). If you have access to CLion,
|
||||
@@ -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,125 @@
|
||||
<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
|
||||
* 4 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
|
||||
|
||||
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`)
|
||||
|
||||
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`.
|
||||
_Note that `random` is currently not a part of the first-party generators_.
|
||||
|
||||
----------
|
||||
|
||||
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).
|
||||
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).
|
||||
|
||||
|
@@ -14,6 +14,9 @@
|
||||
- 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 variables in generator expressions](../examples/310-Gen-VariablesInGenerators.cpp)
|
||||
|
||||
|
||||
## Planned
|
||||
|
||||
|
@@ -45,6 +45,9 @@ These macros come in three forms:
|
||||
|
||||
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.
|
||||
|
||||
_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._
|
||||
|
||||
**WARN(** _message expression_ **)**
|
||||
|
||||
The message is always reported but does not fail the test.
|
||||
|
@@ -32,6 +32,9 @@ A, single-header-only, type-safe, command line parser - which also prints format
|
||||
### [Couchbase-lite-core](https://github.com/couchbase/couchbase-lite-core)
|
||||
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
|
||||
|
||||
|
@@ -2,6 +2,8 @@
|
||||
|
||||
# Release notes
|
||||
**Contents**<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 +20,63 @@
|
||||
[Older versions](#older-versions)<br>
|
||||
[Even Older versions](#even-older-versions)<br>
|
||||
|
||||
## 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
|
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,8 @@ set( SOURCES_IDIOMATIC_TESTS
|
||||
110-Fix-ClassFixture.cpp
|
||||
120-Bdd-ScenarioGivenWhenThen.cpp
|
||||
210-Evt-EventListeners.cpp
|
||||
300-Gen-OwnGenerator.cpp
|
||||
310-Gen-VariablesInGenerators.cpp
|
||||
)
|
||||
|
||||
# main-s for reporter-specific test sources:
|
||||
|
@@ -10,8 +10,8 @@
|
||||
#define TWOBLUECUBES_CATCH_HPP_INCLUDED
|
||||
|
||||
#define CATCH_VERSION_MAJOR 2
|
||||
#define CATCH_VERSION_MINOR 5
|
||||
#define CATCH_VERSION_PATCH 0
|
||||
#define CATCH_VERSION_MINOR 6
|
||||
#define CATCH_VERSION_PATCH 1
|
||||
|
||||
#ifdef __clang__
|
||||
# pragma clang system_header
|
||||
@@ -101,7 +101,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 +115,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 +148,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
|
||||
|
||||
|
||||
@@ -226,9 +230,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 +321,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 +396,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)
|
||||
|
@@ -52,10 +52,10 @@ namespace Catch {
|
||||
line( _line )
|
||||
{}
|
||||
|
||||
SourceLineInfo( SourceLineInfo const& other ) = default;
|
||||
SourceLineInfo( SourceLineInfo && ) = default;
|
||||
SourceLineInfo& operator = ( SourceLineInfo const& ) = default;
|
||||
SourceLineInfo& operator = ( SourceLineInfo && ) = default;
|
||||
SourceLineInfo( SourceLineInfo const& other ) = default;
|
||||
SourceLineInfo& operator = ( SourceLineInfo const& ) = 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)
|
||||
@@ -193,9 +201,11 @@
|
||||
# include <ciso646>
|
||||
# if defined(__GLIBCXX__) && defined(_GLIBCXX_RELEASE) && (_GLIBCXX_RELEASE < 9)
|
||||
# define CATCH_CONFIG_NO_CPP17_VARIANT
|
||||
# else
|
||||
# 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,202 +42,312 @@ 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 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 {
|
||||
template <typename T>
|
||||
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();
|
||||
}
|
||||
bool next() {
|
||||
return m_generator->next();
|
||||
}
|
||||
};
|
||||
|
||||
std::vector<size_t> randomiseIndices( size_t selectionSize, size_t sourceSize );
|
||||
template <typename T>
|
||||
GeneratorWrapper<T> value(T&& value) {
|
||||
return GeneratorWrapper<T>(pf::make_unique<SingleValueGenerator<T>>(std::forward<T>(value)));
|
||||
}
|
||||
template <typename T>
|
||||
GeneratorWrapper<T> values(std::initializer_list<T> values) {
|
||||
return GeneratorWrapper<T>(pf::make_unique<FixedValuesGenerator<T>>(values));
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
class GeneratorRandomiser : public IGenerator<T> {
|
||||
Generator<T> m_baseGenerator;
|
||||
class Generators : public IGenerator<T> {
|
||||
std::vector<GeneratorWrapper<T>> m_generators;
|
||||
size_t m_current = 0;
|
||||
|
||||
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]];
|
||||
void populate(GeneratorWrapper<T>&& generator) {
|
||||
m_generators.emplace_back(std::move(generator));
|
||||
}
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
struct RequiresASpecialisationFor;
|
||||
|
||||
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 ) );
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
auto random( T const& first, T const& last ) -> Generator<T> {
|
||||
auto gen = range( first, last );
|
||||
auto size = gen.size();
|
||||
|
||||
return Generator<T>( size, pf::make_unique<GeneratorRandomiser<T>>( std::move( gen ), size ) );
|
||||
}
|
||||
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 ) ) );
|
||||
void populate(T&& val) {
|
||||
m_generators.emplace_back(value(std::move(val)));
|
||||
}
|
||||
template<typename U>
|
||||
void populate( U&& val ) {
|
||||
populate( T( std::move( val ) ) );
|
||||
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 )... );
|
||||
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)...);
|
||||
}
|
||||
|
||||
T const& get() const override {
|
||||
return m_generators[m_current].get();
|
||||
}
|
||||
|
||||
bool next() override {
|
||||
if (m_current >= m_generators.size()) {
|
||||
return false;
|
||||
}
|
||||
CATCH_INTERNAL_ERROR("Index '" << index << "' is out of range (" << sizes << ')');
|
||||
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 )... );
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
class TakeGenerator : public IGenerator<T> {
|
||||
GeneratorWrapper<T> m_generator;
|
||||
size_t m_returned = 0;
|
||||
size_t m_target;
|
||||
public:
|
||||
TakeGenerator(size_t target, GeneratorWrapper<T>&& generator):
|
||||
m_generator(std::move(generator)),
|
||||
m_target(target)
|
||||
{
|
||||
assert(target != 0 && "Empty generators are not allowed");
|
||||
}
|
||||
T const& get() const override {
|
||||
return m_generator.get();
|
||||
}
|
||||
bool next() override {
|
||||
++m_returned;
|
||||
if (m_returned >= m_target) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const auto success = m_generator.next();
|
||||
// If the underlying generator does not contain enough values
|
||||
// then we cut short as well
|
||||
if (!success) {
|
||||
m_returned = m_target;
|
||||
}
|
||||
return success;
|
||||
}
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
GeneratorWrapper<T> take(size_t target, GeneratorWrapper<T>&& generator) {
|
||||
return GeneratorWrapper<T>(pf::make_unique<TakeGenerator<T>>(target, std::move(generator)));
|
||||
}
|
||||
|
||||
|
||||
template <typename T, typename Predicate>
|
||||
class FilterGenerator : public IGenerator<T> {
|
||||
GeneratorWrapper<T> m_generator;
|
||||
Predicate m_predicate;
|
||||
public:
|
||||
template <typename P = Predicate>
|
||||
FilterGenerator(P&& pred, GeneratorWrapper<T>&& generator):
|
||||
m_generator(std::move(generator)),
|
||||
m_predicate(std::forward<P>(pred))
|
||||
{
|
||||
if (!m_predicate(m_generator.get())) {
|
||||
// It might happen that there are no values that pass the
|
||||
// filter. In that case we throw an exception.
|
||||
auto has_initial_value = next();
|
||||
if (!has_initial_value) {
|
||||
Catch::throw_exception(GeneratorException("No valid value found in filtered generator"));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
T const& get() const override {
|
||||
return m_generator.get();
|
||||
}
|
||||
|
||||
bool next() override {
|
||||
bool success = m_generator.next();
|
||||
if (!success) {
|
||||
return false;
|
||||
}
|
||||
while (!m_predicate(m_generator.get()) && (success = m_generator.next()) == true);
|
||||
return success;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
template <typename T, typename Predicate>
|
||||
GeneratorWrapper<T> filter(Predicate&& pred, GeneratorWrapper<T>&& generator) {
|
||||
return GeneratorWrapper<T>(std::unique_ptr<IGenerator<T>>(pf::make_unique<FilterGenerator<T, Predicate>>(std::forward<Predicate>(pred), std::move(generator))));
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
class RepeatGenerator : public IGenerator<T> {
|
||||
GeneratorWrapper<T> m_generator;
|
||||
mutable std::vector<T> m_returned;
|
||||
size_t m_target_repeats;
|
||||
size_t m_current_repeat = 0;
|
||||
size_t m_repeat_index = 0;
|
||||
public:
|
||||
RepeatGenerator(size_t repeats, GeneratorWrapper<T>&& generator):
|
||||
m_generator(std::move(generator)),
|
||||
m_target_repeats(repeats)
|
||||
{
|
||||
assert(m_target_repeats > 0 && "Repeat generator must repeat at least once");
|
||||
}
|
||||
|
||||
T const& get() const override {
|
||||
if (m_current_repeat == 0) {
|
||||
m_returned.push_back(m_generator.get());
|
||||
return m_returned.back();
|
||||
}
|
||||
return m_returned[m_repeat_index];
|
||||
}
|
||||
|
||||
bool next() override {
|
||||
// There are 2 basic cases:
|
||||
// 1) We are still reading the generator
|
||||
// 2) We are reading our own cache
|
||||
|
||||
// In the first case, we need to poke the underlying generator.
|
||||
// If it happily moves, we are left in that state, otherwise it is time to start reading from our cache
|
||||
if (m_current_repeat == 0) {
|
||||
const auto success = m_generator.next();
|
||||
if (!success) {
|
||||
++m_current_repeat;
|
||||
}
|
||||
return m_current_repeat < m_target_repeats;
|
||||
}
|
||||
|
||||
// In the second case, we need to move indices forward and check that we haven't run up against the end
|
||||
++m_repeat_index;
|
||||
if (m_repeat_index == m_returned.size()) {
|
||||
m_repeat_index = 0;
|
||||
++m_current_repeat;
|
||||
}
|
||||
return m_current_repeat < m_target_repeats;
|
||||
}
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
GeneratorWrapper<T> repeat(size_t repeats, GeneratorWrapper<T>&& generator) {
|
||||
return GeneratorWrapper<T>(pf::make_unique<RepeatGenerator<T>>(repeats, std::move(generator)));
|
||||
}
|
||||
|
||||
template <typename T, typename U, typename Func>
|
||||
class MapGenerator : public IGenerator<T> {
|
||||
// TBD: provide static assert for mapping function, for friendly error message
|
||||
GeneratorWrapper<U> m_generator;
|
||||
Func m_function;
|
||||
// To avoid returning dangling reference, we have to save the values
|
||||
T m_cache;
|
||||
public:
|
||||
template <typename F2 = Func>
|
||||
MapGenerator(F2&& function, GeneratorWrapper<U>&& generator) :
|
||||
m_generator(std::move(generator)),
|
||||
m_function(std::forward<F2>(function)),
|
||||
m_cache(m_function(m_generator.get()))
|
||||
{}
|
||||
|
||||
T const& get() const override {
|
||||
return m_cache;
|
||||
}
|
||||
bool next() override {
|
||||
const auto success = m_generator.next();
|
||||
if (success) {
|
||||
m_cache = m_function(m_generator.get());
|
||||
}
|
||||
return success;
|
||||
}
|
||||
};
|
||||
|
||||
template <typename T, typename U, typename Func>
|
||||
GeneratorWrapper<T> map(Func&& function, GeneratorWrapper<U>&& generator) {
|
||||
return GeneratorWrapper<T>(
|
||||
pf::make_unique<MapGenerator<T, U, Func>>(std::forward<Func>(function), std::move(generator))
|
||||
);
|
||||
}
|
||||
template <typename T, typename Func>
|
||||
GeneratorWrapper<T> map(Func&& function, GeneratorWrapper<T>&& generator) {
|
||||
return GeneratorWrapper<T>(
|
||||
pf::make_unique<MapGenerator<T, T, Func>>(std::forward<Func>(function), std::move(generator))
|
||||
);
|
||||
}
|
||||
|
||||
auto acquireGeneratorTracker( SourceLineInfo const& lineInfo ) -> IGeneratorTracker&;
|
||||
|
||||
@@ -232,15 +355,16 @@ namespace Generators {
|
||||
// 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]) {
|
||||
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() )
|
||||
tracker.setGenerator( pf::make_unique<Generators<UnderlyingType>>( generatorExpression() ) );
|
||||
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
|
||||
|
@@ -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
|
||||
|
@@ -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
|
||||
|
||||
|
81
include/internal/catch_meta.hpp
Normal file
81
include/internal/catch_meta.hpp
Normal file
@@ -0,0 +1,81 @@
|
||||
/*
|
||||
* 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>
|
||||
|
||||
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 {};
|
||||
|
||||
#endif // TWOBLUECUBES_CATCH_META_HPP_INCLUDED
|
@@ -71,4 +71,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) 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,28 +36,24 @@ 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
|
||||
@@ -68,9 +63,6 @@ namespace Catch {
|
||||
void setGenerator( GeneratorBasePtr&& generator ) override {
|
||||
m_generator = std::move( generator );
|
||||
}
|
||||
auto getIndex() const -> size_t override {
|
||||
return m_index;
|
||||
}
|
||||
};
|
||||
GeneratorTracker::~GeneratorTracker() {}
|
||||
}
|
||||
|
@@ -128,7 +128,7 @@ 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;
|
||||
|
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -165,6 +171,8 @@ namespace Catch {
|
||||
return 1;
|
||||
|
||||
auto result = m_cli.parse( clara::Args( argc, argv ) );
|
||||
config();
|
||||
getCurrentMutableContext().setConfig( m_config );
|
||||
if( !result ) {
|
||||
Catch::cerr()
|
||||
<< Colour( Colour::Red )
|
||||
@@ -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,38 @@ 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[]; \
|
||||
(void)expander{(Catch::AutoReg( Catch::makeTestInvoker( &TestFuncName<Types> ), CATCH_INTERNAL_LINEINFO, Catch::StringRef(), Catch::NameAndTags{ Name " - " + Catch::StringMaker<int>::convert(index++), Tags } ), 0)... };/* NOLINT */ \
|
||||
} \
|
||||
}; \
|
||||
static int INTERNAL_CATCH_UNIQUE_NAME( globalRegistrar ) = [](){ \
|
||||
using TestInit = 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 +213,39 @@ 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[];\
|
||||
(void)expander{(Catch::AutoReg( Catch::makeTestInvoker( &TestName<Types>::test ), CATCH_INTERNAL_LINEINFO, #ClassName, Catch::NameAndTags{ Name " - " + Catch::StringMaker<int>::convert(index++), Tags } ), 0)... };/* NOLINT */ \
|
||||
}\
|
||||
};\
|
||||
static int INTERNAL_CATCH_UNIQUE_NAME( globalRegistrar ) = [](){\
|
||||
using TestInit = 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, 6, 1, "", 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
|
||||
|
@@ -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
|
||||
@@ -91,9 +124,9 @@ int main(int argc, char** argv) {
|
||||
assert(sep - begin(args) == 2 && "Structure differs from expected!");
|
||||
|
||||
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
|
||||
@@ -118,6 +119,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 +346,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)
|
||||
|
@@ -57,108 +57,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 +156,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 +399,98 @@ 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: 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: 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
|
||||
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 +793,9 @@ CmdLine.tests.cpp:<line number>: passed: cli.parse({"test", "--use-colour", "no"
|
||||
CmdLine.tests.cpp:<line number>: passed: config.useColour == UseColour::No for: 2 == 2
|
||||
CmdLine.tests.cpp:<line number>: passed: !result for: true
|
||||
CmdLine.tests.cpp:<line number>: passed: result.errorMessage(), Contains( "colour mode must be one of" ) for: "colour mode must be one of: auto, yes or no. 'wrong' not recognised" contains: "colour mode must be one of"
|
||||
Misc.tests.cpp:<line number>: passed: std::tuple_size<TestType>::value >= 1 for: 1 >= 1
|
||||
Misc.tests.cpp:<line number>: passed: std::tuple_size<TestType>::value >= 1 for: 2 >= 1
|
||||
Misc.tests.cpp:<line number>: passed: std::tuple_size<TestType>::value >= 1 for: 3 >= 1
|
||||
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 +1065,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 )
|
||||
@@ -1322,6 +1305,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 +1376,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 69 test cases, failed 129 assertions.
|
||||
|
||||
|
@@ -92,6 +92,50 @@ Class.tests.cpp:<line number>: FAILED:
|
||||
with expansion:
|
||||
"hello" == "world"
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
A TEMPLATE_PRODUCT_TEST_CASE_METHOD based test run that fails - 0
|
||||
-------------------------------------------------------------------------------
|
||||
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 - 1
|
||||
-------------------------------------------------------------------------------
|
||||
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 - 2
|
||||
-------------------------------------------------------------------------------
|
||||
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 - 3
|
||||
-------------------------------------------------------------------------------
|
||||
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
|
||||
-------------------------------------------------------------------------------
|
||||
@@ -1126,6 +1170,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: 245 | 185 passed | 56 failed | 4 failed as expected
|
||||
assertions: 1297 | 1161 passed | 115 failed | 21 failed as expected
|
||||
|
||||
|
File diff suppressed because it is too large
Load Diff
@@ -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="113" tests="1312" 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}"/>
|
||||
@@ -70,13 +73,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 - 0" time="{duration}">
|
||||
<failure message="0 == 1" type="REQUIRE">
|
||||
Class.tests.cpp:<line number>
|
||||
</failure>
|
||||
</testcase>
|
||||
<testcase classname="<exe-name>.Template_Fixture_2" name="A TEMPLATE_PRODUCT_TEST_CASE_METHOD based test run that fails - 1" time="{duration}">
|
||||
<failure message="0 == 1" type="REQUIRE">
|
||||
Class.tests.cpp:<line number>
|
||||
</failure>
|
||||
</testcase>
|
||||
<testcase classname="<exe-name>.Template_Fixture_2" name="A TEMPLATE_PRODUCT_TEST_CASE_METHOD based test run that fails - 2" time="{duration}">
|
||||
<failure message="0 == 1" type="REQUIRE">
|
||||
Class.tests.cpp:<line number>
|
||||
</failure>
|
||||
</testcase>
|
||||
<testcase classname="<exe-name>.Template_Fixture_2" name="A TEMPLATE_PRODUCT_TEST_CASE_METHOD based test run that fails - 3" time="{duration}">
|
||||
<failure message="0 == 1" type="REQUIRE">
|
||||
Class.tests.cpp:<line number>
|
||||
</failure>
|
||||
</testcase>
|
||||
<testcase classname="<exe-name>.Template_Fixture_2" name="A TEMPLATE_PRODUCT_TEST_CASE_METHOD based test run that succeeds - 0" time="{duration}"/>
|
||||
<testcase classname="<exe-name>.Template_Fixture_2" name="A TEMPLATE_PRODUCT_TEST_CASE_METHOD based test run that succeeds - 1" time="{duration}"/>
|
||||
<testcase classname="<exe-name>.Template_Fixture_2" name="A TEMPLATE_PRODUCT_TEST_CASE_METHOD based test run that succeeds - 2" time="{duration}"/>
|
||||
<testcase classname="<exe-name>.Template_Fixture_2" name="A TEMPLATE_PRODUCT_TEST_CASE_METHOD based test run that succeeds - 3" time="{duration}"/>
|
||||
<testcase classname="<exe-name>.Template_Fixture" 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 +128,10 @@ Class.tests.cpp:<line number>
|
||||
</failure>
|
||||
</testcase>
|
||||
<testcase classname="<exe-name>.Fixture" name="A TEST_CASE_METHOD based test run that succeeds" time="{duration}"/>
|
||||
<testcase classname="<exe-name>.global" name="A Template product test case - 0" time="{duration}"/>
|
||||
<testcase classname="<exe-name>.global" name="A Template product test case - 1" time="{duration}"/>
|
||||
<testcase classname="<exe-name>.global" name="A Template product test case - 2" time="{duration}"/>
|
||||
<testcase classname="<exe-name>.global" name="A Template product test case - 3" time="{duration}"/>
|
||||
<testcase classname="<exe-name>.global" name="A 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 +342,23 @@ 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" 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 -- 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="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 +566,9 @@ Message.tests.cpp:<line number>
|
||||
<testcase classname="<exe-name>.global" name="Process can be configured on command line/use-colour/yes" time="{duration}"/>
|
||||
<testcase classname="<exe-name>.global" name="Process can be configured on command line/use-colour/no" time="{duration}"/>
|
||||
<testcase classname="<exe-name>.global" name="Process can be configured on command line/use-colour/error" time="{duration}"/>
|
||||
<testcase classname="<exe-name>.global" name="Product with differing arities - 0" time="{duration}"/>
|
||||
<testcase classname="<exe-name>.global" name="Product with differing arities - 1" time="{duration}"/>
|
||||
<testcase classname="<exe-name>.global" name="Product with differing arities - 2" time="{duration}"/>
|
||||
<testcase classname="<exe-name>.global" name="Reconstruction should be based on stringification: #914" time="{duration}">
|
||||
<failure message="Hey, its truthy!" type="CHECK">
|
||||
Decomposition.tests.cpp:<line number>
|
||||
@@ -660,13 +703,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
|
||||
@@ -914,6 +950,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?
|
||||
|
File diff suppressed because it is too large
Load Diff
@@ -1,93 +1,103 @@
|
||||
#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 );
|
||||
}
|
||||
}
|
||||
|
||||
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("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());
|
||||
}
|
||||
}
|
||||
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("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());
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
@@ -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 );
|
||||
static bool previouslyRun = false;
|
||||
static bool previouslyRunNested = false;
|
||||
|
||||
REQUIRE( g1.isComplete() == false );
|
||||
REQUIRE( s1.isComplete() == false );
|
||||
TEST_CASE( "#1394", "[.][approvals][tracker]" ) {
|
||||
// -- Don't re-run after specified section is done
|
||||
REQUIRE(previouslyRun == 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() );
|
||||
}
|
||||
}
|
||||
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( "Fail an inner section" ) {
|
||||
ITracker& s2 = SectionTracker::acquire( ctx, makeNAL( "S2" ) );
|
||||
REQUIRE( s2.isOpen() );
|
||||
|
||||
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() );
|
||||
}
|
||||
}
|
||||
// !TBD"
|
||||
// nested generator
|
||||
// two sections within a generator
|
||||
SECTION( "RunSection" ) {
|
||||
previouslyRun = true;
|
||||
}
|
||||
SECTION( "SkipSection" ) {
|
||||
// cause an error if this section is called because it shouldn't be
|
||||
REQUIRE(1 == 0);
|
||||
}
|
||||
}
|
||||
|
||||
TEST_CASE( "#1394 nested", "[.][approvals][tracker]" ) {
|
||||
REQUIRE(previouslyRunNested == false);
|
||||
|
||||
SECTION( "NestedRunSection" ) {
|
||||
SECTION( "s1" ) {
|
||||
previouslyRunNested = true;
|
||||
}
|
||||
}
|
||||
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 );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
@@ -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" );
|
||||
|
||||
SECTION( "one" ) {
|
||||
auto j = GENERATE( range( 8, 11 ), 2 );
|
||||
|
||||
CAPTURE( i, j );
|
||||
SUCCEED();
|
||||
// Generators and sections can be nested freely
|
||||
TEST_CASE("Generators -- simple", "[generators]") {
|
||||
auto i = GENERATE(1, 2, 3);
|
||||
SECTION("one") {
|
||||
auto j = GENERATE(values({ -3, -2, -1 }));
|
||||
REQUIRE(j < i);
|
||||
}
|
||||
SECTION( "two" ) {
|
||||
auto j = GENERATE( 3.141, 1.379 );
|
||||
CAPTURE( i, j );
|
||||
SUCCEED();
|
||||
|
||||
SECTION("two") {
|
||||
// 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 ) );
|
||||
|
||||
CHECK( x < y );
|
||||
// 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,36 @@ SCENARIO("Eating cucumbers", "[approvals]") {
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
// There are also some generic generator manipulators
|
||||
TEST_CASE("Generators -- adapters", "[generators]") {
|
||||
// TODO: This won't work yet, introduce GENERATE_VAR?
|
||||
//auto numbers = Catch::Generators::values({ 1, 2, 3, 4, 5, 6 });
|
||||
SECTION("Filtering by predicate") {
|
||||
// This filters out all odd (false) numbers, giving [2, 4, 6]
|
||||
auto i = GENERATE(filter([] (int val) { return val % 2 == 0; }, values({ 1, 2, 3, 4, 5, 6 })));
|
||||
REQUIRE(i % 2 == 0);
|
||||
}
|
||||
SECTION("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);
|
||||
}
|
||||
}
|
||||
|
@@ -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,19 +38,18 @@ 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; }
|
||||
};
|
||||
|
||||
type value{1.5f};
|
||||
REQUIRE_THROWS_AS( value.emplace<int>(sample{}), int );
|
||||
REQUIRE( value.valueless_by_exception() );
|
||||
CHECK( "{valueless variant}" == ::Catch::Detail::stringify(value) );
|
||||
}
|
||||
}
|
||||
|
||||
TEST_CASE( "variant -- valueless-by-exception", "[toString][variant][approvals]" ) {
|
||||
using type = std::variant<MyType1, MyType2>;
|
||||
|
||||
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]")
|
||||
{
|
||||
using type = std::variant<std::string, int>;
|
||||
@@ -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) );
|
||||
|
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