mirror of
https://github.com/catchorg/Catch2.git
synced 2025-09-12 00:15:39 +02:00
Compare commits
105 Commits
Author | SHA1 | Date | |
---|---|---|---|
![]() |
b9dd1936e5 | ||
![]() |
293d617c49 | ||
![]() |
7be35af167 | ||
![]() |
08147a23f9 | ||
![]() |
8af8704089 | ||
![]() |
3816e99d0c | ||
![]() |
b77cec05c0 | ||
![]() |
54089c4c8c | ||
![]() |
296d447452 | ||
![]() |
0531965349 | ||
![]() |
a1cdff4f18 | ||
![]() |
4611125801 | ||
![]() |
e509012e64 | ||
![]() |
448825db03 | ||
![]() |
0fff8e7791 | ||
![]() |
68a3c129ac | ||
![]() |
1ce5ec9b74 | ||
![]() |
37a4e32319 | ||
![]() |
0424c9a62c | ||
![]() |
d633072794 | ||
![]() |
51ed08be22 | ||
![]() |
1701325caa | ||
![]() |
7aee973a4a | ||
![]() |
99575b45db | ||
![]() |
1a03918455 | ||
![]() |
bd667f4d69 | ||
![]() |
28db5ed4c9 | ||
![]() |
7d2451f119 | ||
![]() |
5bf6e47381 | ||
![]() |
29b3b7ae6b | ||
![]() |
ef5fd8d42f | ||
![]() |
693647c43f | ||
![]() |
288387fa10 | ||
![]() |
165de9b072 | ||
![]() |
bf4771a7ed | ||
![]() |
7012a31a39 | ||
![]() |
269303d9d9 | ||
![]() |
e8bfd882e8 | ||
![]() |
2bd0722470 | ||
![]() |
45ebf17ec7 | ||
![]() |
093b72416d | ||
![]() |
c99a346490 | ||
![]() |
359a54b6bd | ||
![]() |
711d750ca7 | ||
![]() |
95f7712808 | ||
![]() |
dbbab8727c | ||
![]() |
5d4061af12 | ||
![]() |
9ccea82d7f | ||
![]() |
dd3d27de57 | ||
![]() |
7f229b4ff1 | ||
![]() |
c03b23c84b | ||
![]() |
17686ba571 | ||
![]() |
d75e9b3c0f | ||
![]() |
67308bb606 | ||
![]() |
16dc219704 | ||
![]() |
63d1a96908 | ||
![]() |
061f1f836a | ||
![]() |
5929d9530c | ||
![]() |
e46a70f829 | ||
![]() |
64a9c02315 | ||
![]() |
61f4c7ab85 | ||
![]() |
50fefd059a | ||
![]() |
a2baabbf71 | ||
![]() |
6f9cdd6583 | ||
![]() |
d9e99dc2ca | ||
![]() |
804a2118c2 | ||
![]() |
aa1e470058 | ||
![]() |
8d5d54e529 | ||
![]() |
73d533ff5c | ||
![]() |
899c5ed3df | ||
![]() |
084b1d5fe6 | ||
![]() |
4109870435 | ||
![]() |
2988e9f6cf | ||
![]() |
bc02ada4b0 | ||
![]() |
61e1ea9185 | ||
![]() |
b275ead8c3 | ||
![]() |
b0381e42b2 | ||
![]() |
8989c9b560 | ||
![]() |
d084162b2f | ||
![]() |
0387fb64ce | ||
![]() |
75200b462c | ||
![]() |
17e09be3b9 | ||
![]() |
1c99b0ff81 | ||
![]() |
64a0f466ec | ||
![]() |
47602ac556 | ||
![]() |
d1e7344f16 | ||
![]() |
3ed5441067 | ||
![]() |
bdee512057 | ||
![]() |
188b3e6511 | ||
![]() |
bbf70ca74b | ||
![]() |
23f023f9ed | ||
![]() |
c1720d0c42 | ||
![]() |
d54c2258e0 | ||
![]() |
b3faceede2 | ||
![]() |
e7fce90b49 | ||
![]() |
799c7a2eed | ||
![]() |
9bc15939a5 | ||
![]() |
461843b1f0 | ||
![]() |
5b4ffd3c93 | ||
![]() |
21a1cd5683 | ||
![]() |
4902cd7215 | ||
![]() |
18ff34788c | ||
![]() |
d0de666362 | ||
![]() |
862955d657 | ||
![]() |
557e47c3ca |
@@ -31,7 +31,7 @@ class BuilderSettings(object):
|
||||
not match the stable pattern. Otherwise it will upload to stable
|
||||
channel.
|
||||
"""
|
||||
return os.getenv("CONAN_UPLOAD", "https://api.bintray.com/conan/horenmar/Catch2")
|
||||
return os.getenv("CONAN_UPLOAD", "https://api.bintray.com/conan/catchorg/Catch2")
|
||||
|
||||
@property
|
||||
def upload_only_when_stable(self):
|
||||
@@ -49,7 +49,7 @@ class BuilderSettings(object):
|
||||
def reference(self):
|
||||
""" Read project version from branch create Conan referece
|
||||
"""
|
||||
return os.getenv("CONAN_REFERENCE", "Catch2/{}@{}/{}".format(self._version, self.username, self.channel))
|
||||
return os.getenv("CONAN_REFERENCE", "Catch2/{}".format(self._version))
|
||||
|
||||
@property
|
||||
def channel(self):
|
||||
|
29
.github/ISSUE_TEMPLATE/bug_report.md
vendored
Normal file
29
.github/ISSUE_TEMPLATE/bug_report.md
vendored
Normal file
@@ -0,0 +1,29 @@
|
||||
---
|
||||
name: Bug report
|
||||
about: Create an issue that documents a bug
|
||||
title: ''
|
||||
labels: ''
|
||||
assignees: ''
|
||||
|
||||
---
|
||||
|
||||
**Describe the bug**
|
||||
A clear and concise description of what the bug is.
|
||||
|
||||
**Expected behavior**
|
||||
A clear and concise description of what you expected to happen.
|
||||
|
||||
**Reproduction steps**
|
||||
Steps to reproduce the bug.
|
||||
<!-- Usually this means a small and self-contained piece of code that uses Catch and specifying compiler flags if relevant. -->
|
||||
|
||||
|
||||
**Platform information:**
|
||||
<!-- Fill in any extra information that might be important for your issue. -->
|
||||
- OS: **Windows NT**
|
||||
- Compiler+version: **GCC v2.9.5**
|
||||
- Catch version: **v1.2.3**
|
||||
|
||||
|
||||
**Additional context**
|
||||
Add any other context about the problem here.
|
14
.github/ISSUE_TEMPLATE/feature_request.md
vendored
Normal file
14
.github/ISSUE_TEMPLATE/feature_request.md
vendored
Normal file
@@ -0,0 +1,14 @@
|
||||
---
|
||||
name: Feature request
|
||||
about: Create an issue that requests a feature or other improvement
|
||||
title: ''
|
||||
labels: ''
|
||||
assignees: ''
|
||||
|
||||
---
|
||||
|
||||
**Description**
|
||||
Describe the feature/change you request and why do you want it.
|
||||
|
||||
**Additional context**
|
||||
Add any other context or screenshots about the feature request here.
|
29
.github/issue_template.md
vendored
29
.github/issue_template.md
vendored
@@ -1,29 +0,0 @@
|
||||
## Description
|
||||
<!--
|
||||
If your issue is a bugreport, this means describing what you did,
|
||||
what did you want to happen and what actually did happen.
|
||||
|
||||
If your issue is a feature request, describe the feature and why do you
|
||||
want it.
|
||||
-->
|
||||
|
||||
|
||||
### Steps to reproduce
|
||||
<!--
|
||||
This is only relevant for bug reports, but if you do have one,
|
||||
please provide a minimal set of steps to reproduce the problem.
|
||||
|
||||
Usually this means providing a small and self-contained code using Catch
|
||||
and specifying compiler flags/tools used if relevant.
|
||||
-->
|
||||
|
||||
|
||||
### Extra information
|
||||
<!--
|
||||
Fill in any extra information that might be important for your issue.
|
||||
|
||||
If your issue is a bugreport, definitely fill out at least the following.
|
||||
-->
|
||||
* Catch version: **v42.42.42**
|
||||
* Operating System: **Joe's discount operating system**
|
||||
* Compiler+version: **Hidden Dragon v1.2.3**
|
@@ -1,5 +1,4 @@
|
||||
language: cpp
|
||||
sudo: false
|
||||
|
||||
branches:
|
||||
except:
|
||||
@@ -277,7 +276,7 @@ matrix:
|
||||
- "3.7"
|
||||
dist: xenial
|
||||
install:
|
||||
- pip install conan conan-package-tools
|
||||
- pip install conan==1.10.2 conan-package-tools
|
||||
env:
|
||||
- CONAN_GCC_VERSIONS=8
|
||||
- CONAN_DOCKER_IMAGE=conanio/gcc8
|
||||
@@ -305,7 +304,7 @@ before_script:
|
||||
# Use Debug builds for running Valgrind and building examples
|
||||
- cmake -H. -BBuild-Debug -DCMAKE_BUILD_TYPE=Debug -Wdev -DUSE_CPP14=${CPP14} -DUSE_CPP17=${CPP17} -DCATCH_USE_VALGRIND=${VALGRIND} -DCATCH_BUILD_EXAMPLES=${EXAMPLES} -DCATCH_ENABLE_COVERAGE=${COVERAGE} -DCATCH_BUILD_EXTRA_TESTS=${EXTRAS}
|
||||
# Don't bother with release build for coverage build
|
||||
- cmake -H. -BBuild-Release -DCMAKE_BUILD_TYPE=Release -Wdev -DUSE_CPP14=${CPP14}
|
||||
- cmake -H. -BBuild-Release -DCMAKE_BUILD_TYPE=Release -Wdev -DUSE_CPP14=${CPP14} -DUSE_CPP17=${CPP17}
|
||||
|
||||
|
||||
script:
|
||||
|
@@ -6,7 +6,7 @@ if(NOT DEFINED PROJECT_NAME)
|
||||
set(NOT_SUBPROJECT ON)
|
||||
endif()
|
||||
|
||||
project(Catch2 LANGUAGES CXX VERSION 2.5.0)
|
||||
project(Catch2 LANGUAGES CXX VERSION 2.7.1)
|
||||
|
||||
# Provide path for scripts
|
||||
list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_LIST_DIR}/CMake")
|
||||
|
@@ -5,17 +5,17 @@
|
||||
[](https://travis-ci.org/catchorg/Catch2)
|
||||
[](https://ci.appveyor.com/project/catchorg/catch2)
|
||||
[](https://codecov.io/gh/catchorg/Catch2)
|
||||
[](https://wandbox.org/permlink/7lDqHmzKQxA2eaM0)
|
||||
[](https://wandbox.org/permlink/ZFBZ5XbLA9F1gzKi)
|
||||
[](https://discord.gg/4CWS9zD)
|
||||
|
||||
|
||||
<a href="https://github.com/catchorg/Catch2/releases/download/v2.5.0/catch.hpp">The latest version of the single header can be downloaded directly using this link</a>
|
||||
<a href="https://github.com/catchorg/Catch2/releases/download/v2.7.1/catch.hpp">The latest version of the single header can be downloaded directly using this link</a>
|
||||
|
||||
## Catch2 is released!
|
||||
|
||||
If you've been using an earlier version of Catch, please see the
|
||||
Breaking Changes section of [the release notes](https://github.com/catchorg/Catch2/releases/tag/v2.0.1)
|
||||
before moving to Catch2. You might also like to read [this blog post](http://www.levelofindirection.com/journal/2017/11/3/catch2-released.html) for more details.
|
||||
before moving to Catch2. You might also like to read [this blog post](https://levelofindirection.com/blog/catch2-released.html) for more details.
|
||||
|
||||
## What's the Catch?
|
||||
|
||||
|
@@ -109,7 +109,7 @@ function(ParseFile SourceFile TestTarget)
|
||||
# Get test type and fixture if applicable
|
||||
string(REGEX MATCH "(CATCH_)?(TEST_CASE_METHOD|SCENARIO|TEST_CASE)[ \t]*\\([^,^\"]*" TestTypeAndFixture "${TestName}")
|
||||
string(REGEX MATCH "(CATCH_)?(TEST_CASE_METHOD|SCENARIO|TEST_CASE)" TestType "${TestTypeAndFixture}")
|
||||
string(REPLACE "${TestType}(" "" TestFixture "${TestTypeAndFixture}")
|
||||
string(REGEX REPLACE "${TestType}\\([ \t]*" "" TestFixture "${TestTypeAndFixture}")
|
||||
|
||||
# Get string parts of test definition
|
||||
string(REGEX MATCHALL "\"+([^\\^\"]|\\\\\")+\"+" TestStrings "${TestName}")
|
||||
@@ -164,7 +164,7 @@ function(ParseFile SourceFile TestTarget)
|
||||
break()
|
||||
endif(result)
|
||||
endforeach(label)
|
||||
if(PARSE_CATCH_TESTS_NO_HIDDEN_TESTS AND ${HiddenTagFound})
|
||||
if(PARSE_CATCH_TESTS_NO_HIDDEN_TESTS AND ${HiddenTagFound} AND ${CMAKE_VERSION} VERSION_LESS "3.9")
|
||||
PrintDebugMessage("Skipping test \"${CTestName}\" as it has [!hide], [.] or [.foo] label")
|
||||
else()
|
||||
PrintDebugMessage("Adding test \"${CTestName}\"")
|
||||
@@ -172,12 +172,22 @@ function(ParseFile SourceFile TestTarget)
|
||||
PrintDebugMessage("Setting labels to ${Labels}")
|
||||
endif()
|
||||
|
||||
# Escape commas in the test spec
|
||||
string(REPLACE "," "\\," Name ${Name})
|
||||
|
||||
# Add the test and set its properties
|
||||
add_test(NAME "\"${CTestName}\"" COMMAND ${OptionalCatchTestLauncher} ${TestTarget} ${Name} ${AdditionalCatchParameters})
|
||||
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()
|
||||
|
||||
|
@@ -10,7 +10,7 @@
|
||||
|
||||
Most test frameworks have a large collection of assertion macros to capture all possible conditional forms (```_EQUALS```, ```_NOTEQUALS```, ```_GREATER_THAN``` etc).
|
||||
|
||||
Catch is different. Because it decomposes natural C-style conditional expressions most of these forms are reduced to one or two that you will use all the time. That said there are a rich set of auxiliary macros as well. We'll describe all of these here.
|
||||
Catch is different. Because it decomposes natural C-style conditional expressions most of these forms are reduced to one or two that you will use all the time. That said there is a rich set of auxiliary macros as well. We'll describe all of these here.
|
||||
|
||||
Most of these macros come in two forms:
|
||||
|
||||
@@ -61,7 +61,7 @@ Catch provides a way to perform tolerant comparisons of floating point values th
|
||||
REQUIRE( performComputation() == Approx( 2.1 ) );
|
||||
```
|
||||
|
||||
Catch also provides a UDL for `Approx`; `_a`. It resides in
|
||||
Catch also provides a user-defined literal for `Approx`; `_a`. It resides in
|
||||
the `Catch::literals` namespace and can be used like so:
|
||||
```cpp
|
||||
using namespace Catch::literals;
|
||||
|
@@ -48,7 +48,7 @@ If Catch2 has been installed in system, both of these can be used after
|
||||
doing `find_package(Catch2 REQUIRED)`. Otherwise you need to add them
|
||||
to your CMake module path.
|
||||
|
||||
### `Catch.cmake` and `AddCatchTests.cmake`
|
||||
### `Catch.cmake` and `CatchAddTests.cmake`
|
||||
|
||||
`Catch.cmake` provides function `catch_discover_tests` to get tests from
|
||||
a target. This function works by running the resulting executable with
|
||||
|
@@ -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,137 @@
|
||||
<a id="top"></a>
|
||||
# Data Generators
|
||||
|
||||
_Generators are currently considered an experimental feature and their
|
||||
API can change between versions freely._
|
||||
|
||||
Data generators (also known as _data driven/parametrized test cases_)
|
||||
let you reuse the same set of assertions across different input values.
|
||||
In Catch2, this means that they respect the ordering and nesting
|
||||
of the `TEST_CASE` and `SECTION` macros.
|
||||
|
||||
How does combining generators and test cases work might be better
|
||||
explained by an example:
|
||||
of the `TEST_CASE` and `SECTION` macros, and their nested sections
|
||||
are run once per each value in a generator.
|
||||
|
||||
This is best explained with an example:
|
||||
```cpp
|
||||
TEST_CASE("Generators") {
|
||||
auto i = GENERATE( range(1, 11) );
|
||||
|
||||
SECTION( "Some section" ) {
|
||||
auto j = GENERATE( range( 11, 21 ) );
|
||||
REQUIRE(i < j);
|
||||
auto i = GENERATE(1, 2, 3);
|
||||
SECTION("one") {
|
||||
auto j = GENERATE( -3, -2, -1 );
|
||||
REQUIRE(j < i);
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
the assertion will be checked 100 times, because there are 10 possible
|
||||
values for `i` (1, 2, ..., 10) and for each of them, there are 10 possible
|
||||
values for `j` (11, 12, ..., 20).
|
||||
The assertion in this test case will be run 9 times, because there
|
||||
are 3 possible values for `i` (1, 2, and 3) and there are 3 possible
|
||||
values for `j` (-3, -2, and -1).
|
||||
|
||||
|
||||
There are 2 parts to generators in Catch2, the `GENERATE` macro together
|
||||
with the already provided generators, and the `IGenerator<T>` interface
|
||||
that allows users to implement their own generators.
|
||||
|
||||
## Provided generators
|
||||
|
||||
Catch2's provided generator functionality consists of three parts,
|
||||
|
||||
* `GENERATE` macro, that serves to integrate generator expression with
|
||||
a test case,
|
||||
* 2 fundamental generators
|
||||
* `ValueGenerator<T>` -- contains only single element
|
||||
* `ValuesGenerator<T>` -- contains multiple elements
|
||||
* 5 generic generators that modify other generators
|
||||
* `FilterGenerator<T, Predicate>` -- filters out elements from a generator
|
||||
for which the predicate returns "false"
|
||||
* `TakeGenerator<T>` -- takes first `n` elements from a generator
|
||||
* `RepeatGenerator<T>` -- repeats output from a generator `n` times
|
||||
* `MapGenerator<T, U, Func>` -- returns the result of applying `Func`
|
||||
on elements from a different generator
|
||||
* `ChunkGenerator<T>` -- returns chunks (inside `std::vector`) of n elements from a generator
|
||||
* 3 specific purpose generators
|
||||
* `RandomIntegerGenerator<Integral>` -- generates random Integrals from range
|
||||
* `RandomFloatGenerator<Float>` -- generates random Floats from range
|
||||
* `RangeGenerator<T>` -- generates all values inside a specific range
|
||||
|
||||
The generators also have associated helper functions that infer their
|
||||
type, making their usage much nicer. These are
|
||||
|
||||
* `value(T&&)` for `ValueGenerator<T>`
|
||||
* `values(std::initializer_list<T>)` for `ValuesGenerator<T>`
|
||||
* `filter(predicate, GeneratorWrapper<T>&&)` for `FilterGenerator<T, Predicate>`
|
||||
* `take(count, GeneratorWrapper<T>&&)` for `TakeGenerator<T>`
|
||||
* `repeat(repeats, GeneratorWrapper<T>&&)` for `RepeatGenerator<T>`
|
||||
* `map(func, GeneratorWrapper<T>&&)` for `MapGenerator<T, U, Func>` (map `U` to `T`, deduced from `Func`)
|
||||
* `map<T>(func, GeneratorWrapper<U>&&)` for `MapGenerator<T, U, Func>` (map `U` to `T`)
|
||||
* `chunk(chunk-size, GeneratorWrapper<T>&&)` for `ChunkGenerator<T>`
|
||||
* `random(IntegerOrFloat a, IntegerOrFloat b)` for `RandomIntegerGenerator` or `RandomFloatGenerator`
|
||||
* `range(start, end)` for `RangeGenerator<T>` with a step size of `1`
|
||||
* `range(start, end, step)` for `RangeGenerator<T>` with a custom step size
|
||||
|
||||
|
||||
And can be used as shown in the example below to create a generator
|
||||
that returns 100 odd random number:
|
||||
|
||||
You can also combine multiple generators by concatenation:
|
||||
```cpp
|
||||
static int square(int x) { return x * x; }
|
||||
TEST_CASE("Generators 2") {
|
||||
auto i = GENERATE(0, 1, -1, range(-20, -10), range(10, 20));
|
||||
CAPTURE(i);
|
||||
REQUIRE(square(i) >= 0);
|
||||
TEST_CASE("Generating random ints", "[example][generator]") {
|
||||
SECTION("Deducing functions") {
|
||||
auto i = GENERATE(take(100, filter([](int i) { return i % 2 == 1; }, random(-100, 100))));
|
||||
REQUIRE(i > -100);
|
||||
REQUIRE(i < 100);
|
||||
REQUIRE(i % 2 == 1);
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
This will call `square` with arguments `0`, `1`, `-1`, `-20`, ..., `-11`,
|
||||
`10`, ..., `19`.
|
||||
|
||||
----------
|
||||
Apart from registering generators with Catch2, the `GENERATE` macro has
|
||||
one more purpose, and that is to provide simple way of generating trivial
|
||||
generators, as seen in the first example on this page, where we used it
|
||||
as `auto i = GENERATE(1, 2, 3);`. This usage converted each of the three
|
||||
literals into a single `ValueGenerator<int>` and then placed them all in
|
||||
a special generator that concatenates other generators. It can also be
|
||||
used with other generators as arguments, such as `auto i = GENERATE(0, 2,
|
||||
take(100, random(300, 3000)));`. This is useful e.g. if you know that
|
||||
specific inputs are problematic and want to test them separately/first.
|
||||
|
||||
**For safety reasons, you cannot use variables inside the `GENERATE` macro.
|
||||
This is done because the generator expression _will_ outlive the outside
|
||||
scope and thus capturing references is dangerous. If you need to use
|
||||
variables inside the generator expression, make sure you thought through
|
||||
the lifetime implications and use `GENERATE_COPY` or `GENERATE_REF`.**
|
||||
|
||||
You can also override the inferred type by using `as<type>` as the first
|
||||
argument to the macro. This can be useful when dealing with string literals,
|
||||
if you want them to come out as `std::string`:
|
||||
|
||||
```cpp
|
||||
TEST_CASE("type conversion", "[generators]") {
|
||||
auto str = GENERATE(as<std::string>{}, "a", "bb", "ccc");
|
||||
REQUIRE(str.size() > 0);
|
||||
}
|
||||
```
|
||||
|
||||
## Generator interface
|
||||
|
||||
You can also implement your own generators, by deriving from the
|
||||
`IGenerator<T>` interface:
|
||||
|
||||
```cpp
|
||||
template<typename T>
|
||||
struct IGenerator : GeneratorUntypedBase {
|
||||
// via GeneratorUntypedBase:
|
||||
// Attempts to move the generator to the next element.
|
||||
// Returns true if successful (and thus has another element that can be read)
|
||||
virtual bool next() = 0;
|
||||
|
||||
// Precondition:
|
||||
// The generator is either freshly constructed or the last call to next() returned true
|
||||
virtual T const& get() const = 0;
|
||||
};
|
||||
```
|
||||
|
||||
However, to be able to use your custom generator inside `GENERATE`, it
|
||||
will need to be wrapped inside a `GeneratorWrapper<T>`.
|
||||
`GeneratorWrapper<T>` is a value wrapper around a
|
||||
`std::unique_ptr<IGenerator<T>>`.
|
||||
|
||||
For full example of implementing your own generator, look into Catch2's
|
||||
examples, specifically
|
||||
[Generators: Create your own generator](../examples/300-Gen-OwnGenerator.cpp).
|
||||
|
||||
Because of the experimental nature of the current Generator implementation,
|
||||
we won't list all of the first-party generators in Catch2. Instead you
|
||||
should look at our current usage tests in
|
||||
[projects/SelfTest/UsageTests/Generators.tests.cpp](/projects/SelfTest/UsageTests/Generators.tests.cpp).
|
||||
For implementing your own generators, you can look at their implementation in
|
||||
[include/internal/catch_generators.hpp](/include/internal/catch_generators.hpp).
|
||||
|
@@ -14,6 +14,11 @@
|
||||
- Report: [TeamCity reporter](../examples/207-Rpt-TeamCityReporter.cpp)
|
||||
- Listener: [Listeners](../examples/210-Evt-EventListeners.cpp)
|
||||
- Configuration: [Provide your own output streams](../examples/231-Cfg-OutputStreams.cpp)
|
||||
- Generators: [Create your own generator](../examples/300-Gen-OwnGenerator.cpp)
|
||||
- Generators: [Use map to convert types in GENERATE expression](../examples/301-Gen-MapTypeConversion.cpp)
|
||||
- Generators: [Use variables in generator expressions](../examples/310-Gen-VariablesInGenerators.cpp)
|
||||
- Generators: [Use custom variable capture in generator expressions](../examples/311-Gen-CustomCapture.cpp)
|
||||
|
||||
|
||||
## Planned
|
||||
|
||||
|
@@ -1,7 +1,7 @@
|
||||
<a id="top"></a>
|
||||
# Logging macros
|
||||
|
||||
Additional messages can be logged during a test case. Note that the messages are scoped and thus will not be reported if failure occurs in scope preceding the message declaration. An example:
|
||||
Additional messages can be logged during a test case. Note that the messages logged with `INFO` are scoped and thus will not be reported if failure occurs in scope preceding the message declaration. An example:
|
||||
|
||||
```cpp
|
||||
TEST_CASE("Foo") {
|
||||
@@ -28,6 +28,60 @@ The number is 1
|
||||
```
|
||||
When the last `CHECK` fails in the "Bar" test case, then only one message will be printed: `Test case start`.
|
||||
|
||||
## Logging without local scope
|
||||
|
||||
`UNSCOPED_INFO` is similar to `INFO` with two key differences:
|
||||
|
||||
- Lifetime of an unscoped message is not tied to its own scope.
|
||||
- An unscoped message can be reported by the first following assertion only, regardless of the result of that assertion.
|
||||
|
||||
In other words, lifetime of `UNSCOPED_INFO` is limited by the following assertion (or by the end of test case/section, whichever comes first) whereas lifetime of `INFO` is limited by its own scope.
|
||||
|
||||
These differences make this macro useful for reporting information from helper functions or inner scopes. An example:
|
||||
|
||||
```cpp
|
||||
void print_some_info() {
|
||||
UNSCOPED_INFO("Info from helper");
|
||||
}
|
||||
|
||||
TEST_CASE("Baz") {
|
||||
print_some_info();
|
||||
for (int i = 0; i < 2; ++i) {
|
||||
UNSCOPED_INFO("The number is " << i);
|
||||
}
|
||||
CHECK(false);
|
||||
}
|
||||
|
||||
TEST_CASE("Qux") {
|
||||
INFO("First info");
|
||||
UNSCOPED_INFO("First unscoped info");
|
||||
CHECK(false);
|
||||
|
||||
INFO("Second info");
|
||||
UNSCOPED_INFO("Second unscoped info");
|
||||
CHECK(false);
|
||||
}
|
||||
```
|
||||
|
||||
"Baz" test case prints:
|
||||
```
|
||||
Info from helper
|
||||
The number is 0
|
||||
The number is 1
|
||||
```
|
||||
|
||||
With "Qux" test case, two messages will be printed when the first `CHECK` fails:
|
||||
```
|
||||
First info
|
||||
First unscoped info
|
||||
```
|
||||
|
||||
"First unscoped info" message will be cleared after the first `CHECK`, while "First info" message will persist until the end of the test case. Therefore, when the second `CHECK` fails, three messages will be printed:
|
||||
```
|
||||
First info
|
||||
Second info
|
||||
Second unscoped info
|
||||
```
|
||||
|
||||
## Streaming macros
|
||||
|
||||
@@ -43,7 +97,14 @@ These macros come in three forms:
|
||||
|
||||
**INFO(** _message expression_ **)**
|
||||
|
||||
The message is logged to a buffer, but only reported with the next assertion that is logged. This allows you to log contextual information in case of failures which is not shown during a successful test run (for the console reporter, without -s). Messages are removed from the buffer at the end of their scope, so may be used, for example, in loops.
|
||||
The message is logged to a buffer, but only reported with next assertions that are logged. This allows you to log contextual information in case of failures which is not shown during a successful test run (for the console reporter, without -s). Messages are removed from the buffer at the end of their scope, so may be used, for example, in loops.
|
||||
|
||||
_Note that in Catch2 2.x.x `INFO` can be used without a trailing semicolon as there is a trailing semicolon inside macro.
|
||||
This semicolon will be removed with next major version. It is highly advised to use a trailing semicolon after `INFO` macro._
|
||||
|
||||
**UNSCOPED_INFO(** _message expression_ **)**
|
||||
|
||||
Similar to `INFO`, but messages are not limited to their own scope: They are removed from the buffer after each assertion, section or test case, whichever comes first.
|
||||
|
||||
**WARN(** _message expression_ **)**
|
||||
|
||||
|
@@ -100,7 +100,7 @@ public:
|
||||
// include any provided data (the begin/ end in this case) and
|
||||
// be written as if it were stating a fact (in the output it will be
|
||||
// preceded by the value under test).
|
||||
virtual std::string describe() const {
|
||||
virtual std::string describe() const override {
|
||||
std::ostringstream ss;
|
||||
ss << "is between " << m_begin << " and " << m_end;
|
||||
return ss.str();
|
||||
|
@@ -17,26 +17,32 @@ Listing a project here does not imply endorsement and the plan is to keep these
|
||||
|
||||
## Libraries & Frameworks
|
||||
|
||||
### [ApprovalTests.cpp](https://github.com/approvals/ApprovalTests.cpp)
|
||||
C++11 implementation of Approval Tests, for quick, convenient testing of legacy code.
|
||||
|
||||
### [Azmq](https://github.com/zeromq/azmq)
|
||||
Boost Asio style bindings for ZeroMQ
|
||||
Boost Asio style bindings for ZeroMQ.
|
||||
|
||||
### [ChakraCore](https://github.com/Microsoft/ChakraCore)
|
||||
The core part of the Chakra JavaScript engine that powers Microsoft Edge
|
||||
The core part of the Chakra JavaScript engine that powers Microsoft Edge.
|
||||
|
||||
### [ChaiScript](https://github.com/ChaiScript/ChaiScript)
|
||||
A, header-only, embedded scripting language designed from the ground up to directly target C++ and take advantage of modern C++ development techniques
|
||||
A, header-only, embedded scripting language designed from the ground up to directly target C++ and take advantage of modern C++ development techniques.
|
||||
|
||||
### [Clara](https://github.com/philsquared/Clara)
|
||||
A, single-header-only, type-safe, command line parser - which also prints formatted usage strings.
|
||||
|
||||
### [Couchbase-lite-core](https://github.com/couchbase/couchbase-lite-core)
|
||||
The next-generation core storage and query engine for Couchbase Lite
|
||||
The next-generation core storage and query engine for Couchbase Lite.
|
||||
|
||||
### [cppcodec](https://github.com/tplgy/cppcodec)
|
||||
Header-only C++11 library to encode/decode base64, base64url, base32, base32hex and hex (a.k.a. base16) as specified in RFC 4648, plus Crockford's base32.
|
||||
|
||||
### [DtCraft](https://github.com/twhuang-uiuc/DtCraft)
|
||||
A High-performance Cluster Computing Engine
|
||||
A High-performance Cluster Computing Engine.
|
||||
|
||||
### [forest](https://github.com/xorz57/forest)
|
||||
Template Library of Tree Data Structures
|
||||
Template Library of Tree Data Structures.
|
||||
|
||||
### [Fuxedo](https://github.com/fuxedo/fuxedo)
|
||||
Open source Oracle Tuxedo-like XATMI middleware for C and C++.
|
||||
@@ -60,25 +66,25 @@ A small C++ library wrapper for the native C ODBC API.
|
||||
A header-only framework for benchmarking small snippets of C++ code.
|
||||
|
||||
### [SOCI](https://github.com/SOCI/soci)
|
||||
The C++ Database Access Library
|
||||
The C++ Database Access Library.
|
||||
|
||||
### [polymorphic_value](https://github.com/jbcoe/polymorphic_value)
|
||||
A polymorphic value-type for C++
|
||||
A polymorphic value-type for C++.
|
||||
|
||||
### [Ppconsul](https://github.com/oliora/ppconsul)
|
||||
A C++ client library for Consul. Consul is a distributed tool for discovering and configuring services in your infrastructure
|
||||
A C++ client library for Consul. Consul is a distributed tool for discovering and configuring services in your infrastructure.
|
||||
|
||||
### [Reactive-Extensions/ RxCpp](https://github.com/Reactive-Extensions/RxCpp)
|
||||
A library of algorithms for values-distributed-in-time
|
||||
A library of algorithms for values-distributed-in-time.
|
||||
|
||||
### [thor](https://github.com/xorz57/thor)
|
||||
Wrapper Library for CUDA
|
||||
Wrapper Library for CUDA.
|
||||
|
||||
### [TextFlowCpp](https://github.com/philsquared/textflowcpp)
|
||||
A small, single-header-only, library for wrapping and composing columns of text
|
||||
A small, single-header-only, library for wrapping and composing columns of text.
|
||||
|
||||
### [Trompeloeil](https://github.com/rollbear/trompeloeil)
|
||||
A thread safe header only mocking framework for C++14
|
||||
A thread-safe header-only mocking framework for C++14.
|
||||
|
||||
### [args](https://github.com/Taywee/args)
|
||||
A simple header-only C++ argument parser library.
|
||||
@@ -92,16 +98,19 @@ ArangoDB is a native multi-model database with flexible data models for document
|
||||
Minimal, open-source and cross-platform audio tool for live music production.
|
||||
|
||||
### [MAME](https://github.com/mamedev/mame)
|
||||
MAME originally stood for Multiple Arcade Machine Emulator
|
||||
MAME originally stood for Multiple Arcade Machine Emulator.
|
||||
|
||||
### [Newsbeuter](https://github.com/akrennmair/newsbeuter)
|
||||
Newsbeuter is an open-source RSS/Atom feed reader for text terminals.
|
||||
|
||||
### [raspigcd](https://github.com/pantadeusz/raspigcd)
|
||||
Low level CLI app and library for execution of GCODE on Raspberry Pi without any additional microcontrolers (just RPi + Stepsticks).
|
||||
|
||||
### [SpECTRE](https://github.com/sxs-collaboration/spectre)
|
||||
SpECTRE is a code for multi-scale, multi-physics problems in astrophysics and gravitational physics.
|
||||
|
||||
### [Standardese](https://github.com/foonathan/standardese)
|
||||
Standardese aims to be a nextgen Doxygen
|
||||
Standardese aims to be a nextgen Doxygen.
|
||||
|
||||
---
|
||||
|
||||
|
@@ -2,6 +2,10 @@
|
||||
|
||||
# Release notes
|
||||
**Contents**<br>
|
||||
[2.7.1](#271)<br>
|
||||
[2.7.0](#270)<br>
|
||||
[2.6.1](#261)<br>
|
||||
[2.6.0](#260)<br>
|
||||
[2.5.0](#250)<br>
|
||||
[2.4.2](#242)<br>
|
||||
[2.4.1](#241)<br>
|
||||
@@ -18,6 +22,109 @@
|
||||
[Older versions](#older-versions)<br>
|
||||
[Even Older versions](#even-older-versions)<br>
|
||||
|
||||
## 2.7.1
|
||||
|
||||
### Improvements
|
||||
* Reporters now print out the filters applied to test cases (#1550, #1585)
|
||||
* Added `GENERATE_COPY` and `GENERATE_VAR` macros that can use variables inside the generator expression
|
||||
* Because of the significant danger of lifetime issues, the default `GENERATE` macro still does not allow variables
|
||||
* The `map` generator helper now deduces the mapped return type (#1576)
|
||||
|
||||
### Fixes
|
||||
* Fixed ObjC++ compilation (#1571)
|
||||
* Fixed test tag parsing so that `[.foo]` is now parsed as `[.][foo]`.
|
||||
* Suppressed warning caused by the Windows headers defining SE codes in different manners (#1575)
|
||||
|
||||
## 2.7.0
|
||||
|
||||
### Improvements
|
||||
* `TEMPLATE_PRODUCT_TEST_CASE` now uses the resulting type in the name, instead of the serial number (#1544)
|
||||
* Catch2's single header is now strictly ASCII (#1542)
|
||||
* Added generator for random integral/floating point types
|
||||
* The types are inferred within the `random` helper
|
||||
* Added back RangeGenerator (#1526)
|
||||
* RangeGenerator returns elements within a certain range
|
||||
* Added ChunkGenerator generic transform (#1538)
|
||||
* A ChunkGenerator returns the elements from different generator in chunks of n elements
|
||||
* Added `UNSCOPED_INFO` (#415, #983, #1522)
|
||||
* This is a variant of `INFO` that lives until next assertion/end of the test case.
|
||||
|
||||
|
||||
### Fixes
|
||||
* All calls to C stdlib functions are now `std::` qualified (#1541)
|
||||
* Code brought in from Clara was also updated.
|
||||
* Running tests will no longer open the specified output file twice (#1545)
|
||||
* This would cause trouble when the file was not a file, but rather a named pipe
|
||||
* Fixes the CLion/Resharper integration with Catch
|
||||
* Fixed `-Wunreachable-code` occuring with (old) ccache+cmake+clang combination (#1540)
|
||||
* Fixed `-Wdefaulted-function-deleted` warning with Clang 8 (#1537)
|
||||
* Catch2's type traits and helpers are now properly namespaced inside `Catch::` (#1548)
|
||||
* Fixed std{out,err} redirection for failing test (#1514, #1525)
|
||||
* Somehow, this bug has been present for well over a year before it was reported
|
||||
|
||||
|
||||
### Contrib
|
||||
* `ParseAndAddCatchTests` now properly escapes commas in the test name
|
||||
|
||||
|
||||
|
||||
## 2.6.1
|
||||
|
||||
### Improvements
|
||||
* The JUnit reporter now also reports random seed (#1520, #1521)
|
||||
|
||||
### Fixes
|
||||
* The TAP reporter now formats comments with test name properly (#1529)
|
||||
* `CATCH_REQUIRE_THROWS`'s internals were unified with `REQUIRE_THROWS` (#1536)
|
||||
* This fixes a potential `-Wunused-value` warning when used
|
||||
* Fixed a potential segfault when using any of the `--list-*` options (#1533, #1534)
|
||||
|
||||
|
||||
## 2.6.0
|
||||
|
||||
**With this release the data generator feature is now fully supported.**
|
||||
|
||||
|
||||
### 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._
|
||||
|
||||
---
|
||||
|
||||
|
@@ -23,7 +23,7 @@ The full source for Catch2, including test projects, documentation, and other th
|
||||
|
||||
## Where to put it?
|
||||
|
||||
Catch2 is header only. All you need to do is drop the file somewhere reachable from your project - either in some central location you can set your header search path to find, or directly into your project tree itself! This is a particularly good option for other Open-Source projects that want to use Catch for their test suite. See [this blog entry for more on that](http://www.levelofindirection.com/journal/2011/5/27/unit-testing-in-c-and-objective-c-just-got-ridiculously-easi.html).
|
||||
Catch2 is header only. All you need to do is drop the file somewhere reachable from your project - either in some central location you can set your header search path to find, or directly into your project tree itself! This is a particularly good option for other Open-Source projects that want to use Catch for their test suite. See [this blog entry for more on that](https://levelofindirection.com/blog/unit-testing-in-cpp-and-objective-c-just-got-ridiculously-easier-still.html).
|
||||
|
||||
The rest of this tutorial will assume that the Catch2 single-include header (or the include folder) is available unqualified - but you may need to prefix it with a folder name if necessary.
|
||||
|
||||
@@ -103,7 +103,7 @@ Of course there are still more issues to deal with. For example we'll hit proble
|
||||
|
||||
### What did we do here?
|
||||
|
||||
Although this was a simple test it's been enough to demonstrate a few things about how Catch is used. Let's take moment to consider those before we move on.
|
||||
Although this was a simple test it's been enough to demonstrate a few things about how Catch is used. Let's take a moment to consider those before we move on.
|
||||
|
||||
1. All we did was ```#define``` one identifier and ```#include``` one header and we got everything - even an implementation of ```main()``` that will [respond to command line arguments](command-line.md#top). You can only use that ```#define``` in one implementation file, for (hopefully) obvious reasons. Once you have more than one file with unit tests in you'll just ```#include "catch.hpp"``` and go. Usually it's a good idea to have a dedicated implementation file that just has ```#define CATCH_CONFIG_MAIN``` and ```#include "catch.hpp"```. You can also provide your own implementation of main and drive Catch yourself (see [Supplying-your-own-main()](own-main.md#top)).
|
||||
2. We introduce test cases with the ```TEST_CASE``` macro. This macro takes one or two arguments - a free form test name and, optionally, one or more tags (for more see <a href="#test-cases-and-sections">Test cases and Sections</a>, ). The test name must be unique. You can run sets of tests by specifying a wildcarded test name or a tag expression. See the [command line docs](command-line.md#top) for more information on running tests.
|
||||
@@ -159,7 +159,7 @@ This works because the ```SECTION``` macro contains an if statement that calls b
|
||||
|
||||
So far so good - this is already an improvement on the setup/teardown approach because now we see our setup code inline and use the stack.
|
||||
|
||||
The power of sections really shows, however, when we need to execute a sequence of, checked, operations. Continuing the vector example, we might want to verify that attempting to reserve a capacity smaller than the current capacity of the vector changes nothing. We can do that, naturally, like so:
|
||||
The power of sections really shows, however, when we need to execute a sequence of checked operations. Continuing the vector example, we might want to verify that attempting to reserve a capacity smaller than the current capacity of the vector changes nothing. We can do that, naturally, like so:
|
||||
|
||||
```c++
|
||||
SECTION( "reserving bigger changes capacity but not size" ) {
|
||||
@@ -260,8 +260,9 @@ Do not write your tests in header files!
|
||||
## Type parametrised test cases
|
||||
|
||||
Test cases in Catch2 can be also parametrised by type, via the
|
||||
`TEMPLATE_TEST_CASE` macro, which behaves in the same way the `TEST_CASE`
|
||||
macro, but is run for every type.
|
||||
`TEMPLATE_TEST_CASE` and `TEMPLATE_PRODUCT_TEST_CASE` macros,
|
||||
which behave in the same way the `TEST_CASE` macro, but are run for
|
||||
every type or type combination.
|
||||
|
||||
For more details, see our documentation on [test cases and
|
||||
sections](test-cases-and-sections.md#type-parametrised-test-cases).
|
||||
|
@@ -387,16 +387,16 @@ TEST_CASE( "2: Testcase with sections", "[tag-A][tag-B]" ) {
|
||||
REQUIRE( i == 42 );
|
||||
|
||||
SECTION("Section 1") {
|
||||
INFO("Section 1")
|
||||
INFO("Section 1");
|
||||
i = 7;
|
||||
SECTION("Section 1.1") {
|
||||
INFO("Section 1.1")
|
||||
INFO("Section 1.1");
|
||||
REQUIRE( i == 42 );
|
||||
}
|
||||
}
|
||||
|
||||
SECTION("Section 2") {
|
||||
INFO("Section 2")
|
||||
INFO("Section 2");
|
||||
REQUIRE( i == 42 );
|
||||
}
|
||||
WARN("At end of test case");
|
||||
|
59
examples/300-Gen-OwnGenerator.cpp
Normal file
59
examples/300-Gen-OwnGenerator.cpp
Normal file
@@ -0,0 +1,59 @@
|
||||
// 300-Gen-OwnGenerator.cpp
|
||||
// Shows how to define a custom generator.
|
||||
|
||||
// Specifically we will implement a random number generator for integers
|
||||
// It will have infinite capacity and settable lower/upper bound
|
||||
|
||||
#include <catch2/catch.hpp>
|
||||
|
||||
#include <random>
|
||||
|
||||
// This class shows how to implement a simple generator for Catch tests
|
||||
class RandomIntGenerator : public Catch::Generators::IGenerator<int> {
|
||||
std::minstd_rand m_rand;
|
||||
std::uniform_int_distribution<> m_dist;
|
||||
int current_number;
|
||||
public:
|
||||
|
||||
RandomIntGenerator(int low, int high):
|
||||
m_rand(std::random_device{}()),
|
||||
m_dist(low, high)
|
||||
{
|
||||
static_cast<void>(next());
|
||||
}
|
||||
|
||||
int const& get() const override;
|
||||
bool next() override {
|
||||
current_number = m_dist(m_rand);
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
// Avoids -Wweak-vtables
|
||||
int const& RandomIntGenerator::get() const {
|
||||
return current_number;
|
||||
}
|
||||
|
||||
// This helper function provides a nicer UX when instantiating the generator
|
||||
// Notice that it returns an instance of GeneratorWrapper<int>, which
|
||||
// is a value-wrapper around std::unique_ptr<IGenerator<int>>.
|
||||
Catch::Generators::GeneratorWrapper<int> random(int low, int high) {
|
||||
return Catch::Generators::GeneratorWrapper<int>(std::unique_ptr<Catch::Generators::IGenerator<int>>(new RandomIntGenerator(low, high)));
|
||||
}
|
||||
|
||||
// The two sections in this test case are equivalent, but the first one
|
||||
// is much more readable/nicer to use
|
||||
TEST_CASE("Generating random ints", "[example][generator]") {
|
||||
SECTION("Nice UX") {
|
||||
auto i = GENERATE(take(100, random(-100, 100)));
|
||||
REQUIRE(i >= -100);
|
||||
REQUIRE(i <= 100);
|
||||
}
|
||||
SECTION("Creating the random generator directly") {
|
||||
auto i = GENERATE(take(100, GeneratorWrapper<int>(std::unique_ptr<IGenerator<int>>(new RandomIntGenerator(-100, 100)))));
|
||||
REQUIRE(i >= -100);
|
||||
REQUIRE(i <= 100);
|
||||
}
|
||||
}
|
||||
|
||||
// Compiling and running this file will result in 400 successful assertions
|
54
examples/301-Gen-MapTypeConversion.cpp
Normal file
54
examples/301-Gen-MapTypeConversion.cpp
Normal file
@@ -0,0 +1,54 @@
|
||||
// 301-Gen-MapTypeConversion.cpp
|
||||
// Shows how to use map to modify generator's return type.
|
||||
|
||||
// TODO
|
||||
|
||||
#include <catch2/catch.hpp>
|
||||
|
||||
#include <string>
|
||||
#include <sstream>
|
||||
|
||||
// Returns a line from a stream. You could have it e.g. read lines from
|
||||
// a file, but to avoid problems with paths in examples, we will use
|
||||
// a fixed stringstream.
|
||||
class LineGenerator : public Catch::Generators::IGenerator<std::string> {
|
||||
std::string m_line;
|
||||
std::stringstream m_stream;
|
||||
public:
|
||||
LineGenerator() {
|
||||
m_stream.str("1\n2\n3\n4\n");
|
||||
if (!next()) {
|
||||
throw Catch::GeneratorException("Couldn't read a single line");
|
||||
}
|
||||
}
|
||||
|
||||
std::string const& get() const override {
|
||||
return m_line;
|
||||
}
|
||||
|
||||
bool next() override {
|
||||
return !!std::getline(m_stream, m_line);
|
||||
}
|
||||
};
|
||||
|
||||
// This helper function provides a nicer UX when instantiating the generator
|
||||
// Notice that it returns an instance of GeneratorWrapper<std::string>, which
|
||||
// is a value-wrapper around std::unique_ptr<IGenerator<std::string>>.
|
||||
Catch::Generators::GeneratorWrapper<std::string> lines(std::string /* ignored for example */) {
|
||||
return Catch::Generators::GeneratorWrapper<std::string>(
|
||||
std::unique_ptr<Catch::Generators::IGenerator<std::string>>(
|
||||
new LineGenerator()
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
|
||||
TEST_CASE("filter can convert types inside the generator expression", "[example][generator]") {
|
||||
auto num = GENERATE(map<int>([](std::string const& line) { return std::stoi(line); },
|
||||
lines("fake-file")));
|
||||
|
||||
REQUIRE(num > 0);
|
||||
}
|
||||
|
||||
// Compiling and running this file will result in 4 successful assertions
|
33
examples/310-Gen-VariablesInGenerators.cpp
Normal file
33
examples/310-Gen-VariablesInGenerators.cpp
Normal file
@@ -0,0 +1,33 @@
|
||||
// 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>
|
||||
|
||||
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(std::get<0>(r), std::get<1>(r))));
|
||||
|
||||
// GENERATE_COPY copies all variables mentioned inside the expression
|
||||
// thus this will work.
|
||||
auto number = GENERATE_COPY(take(50, random(std::get<0>(r), std::get<1>(r))));
|
||||
|
||||
REQUIRE(std::abs(number) > 0);
|
||||
}
|
||||
|
||||
// Compiling and running this file will result in 150 successful assertions
|
||||
|
41
examples/311-Gen-CustomCapture.cpp
Normal file
41
examples/311-Gen-CustomCapture.cpp
Normal file
@@ -0,0 +1,41 @@
|
||||
// 311-Gen-CustomCapture.cpp
|
||||
// Shows how to provide custom capture list to the generator expression
|
||||
|
||||
// Note that using variables inside generators is dangerous and should
|
||||
// be done only if you know what you are doing, because the generators
|
||||
// _WILL_ outlive the variables. Also, even if you know what you are
|
||||
// doing, you should probably use GENERATE_COPY or GENERATE_REF macros
|
||||
// instead. However, if your use case requires having a
|
||||
// per-variable custom capture list, this example shows how to achieve
|
||||
// that.
|
||||
|
||||
#include <catch2/catch.hpp>
|
||||
|
||||
TEST_CASE("Generate random doubles across different ranges",
|
||||
"[generator][example][advanced]") {
|
||||
// Workaround for old libstdc++
|
||||
using record = std::tuple<double, double>;
|
||||
// Set up 3 ranges to generate numbers from
|
||||
auto r1 = GENERATE(table<double, double>({
|
||||
record{3, 4},
|
||||
record{-4, -3},
|
||||
record{10, 1000}
|
||||
}));
|
||||
|
||||
auto r2(r1);
|
||||
|
||||
// This will take r1 by reference and r2 by value.
|
||||
// Note that there are no advantages for doing so in this example,
|
||||
// it is done only for expository purposes.
|
||||
auto number = Catch::Generators::generate( CATCH_INTERNAL_LINEINFO,
|
||||
[&r1, r2]{
|
||||
using namespace Catch::Generators;
|
||||
return makeGenerators(take(50, random(std::get<0>(r1), std::get<1>(r2))));
|
||||
}
|
||||
);
|
||||
|
||||
REQUIRE(std::abs(number) > 0);
|
||||
}
|
||||
|
||||
// Compiling and running this file will result in 150 successful assertions
|
||||
|
@@ -44,6 +44,10 @@ set( SOURCES_IDIOMATIC_TESTS
|
||||
110-Fix-ClassFixture.cpp
|
||||
120-Bdd-ScenarioGivenWhenThen.cpp
|
||||
210-Evt-EventListeners.cpp
|
||||
300-Gen-OwnGenerator.cpp
|
||||
301-Gen-MapTypeConversion.cpp
|
||||
310-Gen-VariablesInGenerators.cpp
|
||||
311-Gen-CustomCapture.cpp
|
||||
)
|
||||
|
||||
# main-s for reporter-specific test sources:
|
||||
|
@@ -10,8 +10,8 @@
|
||||
#define TWOBLUECUBES_CATCH_HPP_INCLUDED
|
||||
|
||||
#define CATCH_VERSION_MAJOR 2
|
||||
#define CATCH_VERSION_MINOR 5
|
||||
#define CATCH_VERSION_PATCH 0
|
||||
#define CATCH_VERSION_MINOR 7
|
||||
#define CATCH_VERSION_PATCH 1
|
||||
|
||||
#ifdef __clang__
|
||||
# pragma clang system_header
|
||||
@@ -63,6 +63,8 @@
|
||||
#include "internal/catch_capture_matchers.h"
|
||||
#endif
|
||||
#include "internal/catch_generators.hpp"
|
||||
#include "internal/catch_generators_generic.hpp"
|
||||
#include "internal/catch_generators_specific.hpp"
|
||||
|
||||
// These files are included here so the single_include script doesn't put them
|
||||
// in the conditionally compiled sections
|
||||
@@ -101,7 +103,7 @@
|
||||
#define CATCH_REQUIRE( ... ) INTERNAL_CATCH_TEST( "CATCH_REQUIRE", Catch::ResultDisposition::Normal, __VA_ARGS__ )
|
||||
#define CATCH_REQUIRE_FALSE( ... ) INTERNAL_CATCH_TEST( "CATCH_REQUIRE_FALSE", Catch::ResultDisposition::Normal | Catch::ResultDisposition::FalseTest, __VA_ARGS__ )
|
||||
|
||||
#define CATCH_REQUIRE_THROWS( ... ) INTERNAL_CATCH_THROWS( "CATCH_REQUIRE_THROWS", Catch::ResultDisposition::Normal, "", __VA_ARGS__ )
|
||||
#define CATCH_REQUIRE_THROWS( ... ) INTERNAL_CATCH_THROWS( "CATCH_REQUIRE_THROWS", Catch::ResultDisposition::Normal, __VA_ARGS__ )
|
||||
#define CATCH_REQUIRE_THROWS_AS( expr, exceptionType ) INTERNAL_CATCH_THROWS_AS( "CATCH_REQUIRE_THROWS_AS", exceptionType, Catch::ResultDisposition::Normal, expr )
|
||||
#define CATCH_REQUIRE_THROWS_WITH( expr, matcher ) INTERNAL_CATCH_THROWS_STR_MATCHES( "CATCH_REQUIRE_THROWS_WITH", Catch::ResultDisposition::Normal, matcher, expr )
|
||||
#if !defined(CATCH_CONFIG_DISABLE_MATCHERS)
|
||||
@@ -115,7 +117,7 @@
|
||||
#define CATCH_CHECKED_ELSE( ... ) INTERNAL_CATCH_ELSE( "CATCH_CHECKED_ELSE", Catch::ResultDisposition::ContinueOnFailure, __VA_ARGS__ )
|
||||
#define CATCH_CHECK_NOFAIL( ... ) INTERNAL_CATCH_TEST( "CATCH_CHECK_NOFAIL", Catch::ResultDisposition::ContinueOnFailure | Catch::ResultDisposition::SuppressFail, __VA_ARGS__ )
|
||||
|
||||
#define CATCH_CHECK_THROWS( ... ) INTERNAL_CATCH_THROWS( "CATCH_CHECK_THROWS", Catch::ResultDisposition::ContinueOnFailure, "", __VA_ARGS__ )
|
||||
#define CATCH_CHECK_THROWS( ... ) INTERNAL_CATCH_THROWS( "CATCH_CHECK_THROWS", Catch::ResultDisposition::ContinueOnFailure, __VA_ARGS__ )
|
||||
#define CATCH_CHECK_THROWS_AS( expr, exceptionType ) INTERNAL_CATCH_THROWS_AS( "CATCH_CHECK_THROWS_AS", exceptionType, Catch::ResultDisposition::ContinueOnFailure, expr )
|
||||
#define CATCH_CHECK_THROWS_WITH( expr, matcher ) INTERNAL_CATCH_THROWS_STR_MATCHES( "CATCH_CHECK_THROWS_WITH", Catch::ResultDisposition::ContinueOnFailure, matcher, expr )
|
||||
#if !defined(CATCH_CONFIG_DISABLE_MATCHERS)
|
||||
@@ -148,9 +150,13 @@
|
||||
#ifndef CATCH_CONFIG_TRADITIONAL_MSVC_PREPROCESSOR
|
||||
#define CATCH_TEMPLATE_TEST_CASE( ... ) INTERNAL_CATCH_TEMPLATE_TEST_CASE( __VA_ARGS__ )
|
||||
#define CATCH_TEMPLATE_TEST_CASE_METHOD( className, ... ) INTERNAL_CATCH_TEMPLATE_TEST_CASE_METHOD( className, __VA_ARGS__ )
|
||||
#define CATCH_TEMPLATE_PRODUCT_TEST_CASE( ... ) INTERNAL_CATCH_TEMPLATE_PRODUCT_TEST_CASE( __VA_ARGS__ )
|
||||
#define CATCH_TEMPLATE_PRODUCT_TEST_CASE_METHOD( className, ... ) INTERNAL_CATCH_TEMPLATE_PRODUCT_TEST_CASE_METHOD( className, __VA_ARGS__ )
|
||||
#else
|
||||
#define CATCH_TEMPLATE_TEST_CASE( ... ) INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_TEST_CASE( __VA_ARGS__ ) )
|
||||
#define CATCH_TEMPLATE_TEST_CASE_METHOD( className, ... ) INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_TEST_CASE_METHOD( className, __VA_ARGS__ ) )
|
||||
#define CATCH_TEMPLATE_PRODUCT_TEST_CASE( ... ) INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_PRODUCT_TEST_CASE( __VA_ARGS__ ) )
|
||||
#define CATCH_TEMPLATE_PRODUCT_TEST_CASE_METHOD( className, ... ) INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_PRODUCT_TEST_CASE_METHOD( className, __VA_ARGS__ ) )
|
||||
#endif
|
||||
|
||||
|
||||
@@ -209,6 +215,7 @@
|
||||
#endif // CATCH_CONFIG_DISABLE_MATCHERS
|
||||
|
||||
#define INFO( msg ) INTERNAL_CATCH_INFO( "INFO", msg )
|
||||
#define UNSCOPED_INFO( msg ) INTERNAL_CATCH_UNSCOPED_INFO( "UNSCOPED_INFO", msg )
|
||||
#define WARN( msg ) INTERNAL_CATCH_MSG( "WARN", Catch::ResultWas::Warning, Catch::ResultDisposition::ContinueOnFailure, msg )
|
||||
#define CAPTURE( ... ) INTERNAL_CATCH_CAPTURE( INTERNAL_CATCH_UNIQUE_NAME(capturer), "CAPTURE",__VA_ARGS__ )
|
||||
|
||||
@@ -226,9 +233,13 @@
|
||||
#ifndef CATCH_CONFIG_TRADITIONAL_MSVC_PREPROCESSOR
|
||||
#define TEMPLATE_TEST_CASE( ... ) INTERNAL_CATCH_TEMPLATE_TEST_CASE( __VA_ARGS__ )
|
||||
#define TEMPLATE_TEST_CASE_METHOD( className, ... ) INTERNAL_CATCH_TEMPLATE_TEST_CASE_METHOD( className, __VA_ARGS__ )
|
||||
#define TEMPLATE_PRODUCT_TEST_CASE( ... ) INTERNAL_CATCH_TEMPLATE_PRODUCT_TEST_CASE( __VA_ARGS__ )
|
||||
#define TEMPLATE_PRODUCT_TEST_CASE_METHOD( className, ... ) INTERNAL_CATCH_TEMPLATE_PRODUCT_TEST_CASE_METHOD( className, __VA_ARGS__ )
|
||||
#else
|
||||
#define TEMPLATE_TEST_CASE( ... ) INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_TEST_CASE( __VA_ARGS__ ) )
|
||||
#define TEMPLATE_TEST_CASE_METHOD( className, ... ) INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_TEST_CASE_METHOD( className, __VA_ARGS__ ) )
|
||||
#define TEMPLATE_PRODUCT_TEST_CASE( ... ) INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_PRODUCT_TEST_CASE( __VA_ARGS__ ) )
|
||||
#define TEMPLATE_PRODUCT_TEST_CASE_METHOD( className, ... ) INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_PRODUCT_TEST_CASE_METHOD( className, __VA_ARGS__ ) )
|
||||
#endif
|
||||
|
||||
|
||||
@@ -313,9 +324,13 @@ using Catch::Detail::Approx;
|
||||
#ifndef CATCH_CONFIG_TRADITIONAL_MSVC_PREPROCESSOR
|
||||
#define CATCH_TEMPLATE_TEST_CASE( ... ) INTERNAL_CATCH_TEMPLATE_TEST_CASE_NO_REGISTRATION(INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_M_P_L_A_T_E____T_E_S_T____ ) )
|
||||
#define CATCH_TEMPLATE_TEST_CASE_METHOD( className, ... ) INTERNAL_CATCH_TEMPLATE_TEST_CASE_METHOD_NO_REGISTRATION(INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_M_P_L_A_T_E____T_E_S_T____ ), className )
|
||||
#define CATCH_TEMPLATE_PRODUCT_TEST_CASE( ... ) CATCH_TEMPLATE_TEST_CASE( __VA_ARGS__ )
|
||||
#define CATCH_TEMPLATE_PRODUCT_TEST_CASE_METHOD( className, ... ) CATCH_TEMPLATE_TEST_CASE_METHOD( className, __VA_ARGS__ )
|
||||
#else
|
||||
#define CATCH_TEMPLATE_TEST_CASE( ... ) INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_TEST_CASE_NO_REGISTRATION(INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_M_P_L_A_T_E____T_E_S_T____ ) ) )
|
||||
#define CATCH_TEMPLATE_TEST_CASE_METHOD( className, ... ) INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_TEST_CASE_METHOD_NO_REGISTRATION(INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_M_P_L_A_T_E____T_E_S_T____ ), className ) )
|
||||
#define CATCH_TEMPLATE_PRODUCT_TEST_CASE( ... ) CATCH_TEMPLATE_TEST_CASE( __VA_ARGS__ )
|
||||
#define CATCH_TEMPLATE_PRODUCT_TEST_CASE_METHOD( className, ... ) CATCH_TEMPLATE_TEST_CASE_METHOD( className, __VA_ARGS__ )
|
||||
#endif
|
||||
|
||||
// "BDD-style" convenience wrappers
|
||||
@@ -384,9 +399,13 @@ using Catch::Detail::Approx;
|
||||
#ifndef CATCH_CONFIG_TRADITIONAL_MSVC_PREPROCESSOR
|
||||
#define TEMPLATE_TEST_CASE( ... ) INTERNAL_CATCH_TEMPLATE_TEST_CASE_NO_REGISTRATION(INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_M_P_L_A_T_E____T_E_S_T____ ) )
|
||||
#define TEMPLATE_TEST_CASE_METHOD( className, ... ) INTERNAL_CATCH_TEMPLATE_TEST_CASE_METHOD_NO_REGISTRATION(INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_M_P_L_A_T_E____T_E_S_T____ ), className )
|
||||
#define TEMPLATE_PRODUCT_TEST_CASE( ... ) TEMPLATE_TEST_CASE( __VA_ARGS__ )
|
||||
#define TEMPLATE_PRODUCT_TEST_CASE_METHOD( className, ... ) TEMPLATE_TEST_CASE_METHOD( className, __VA_ARGS__ )
|
||||
#else
|
||||
#define TEMPLATE_TEST_CASE( ... ) INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_TEST_CASE_NO_REGISTRATION(INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_M_P_L_A_T_E____T_E_S_T____ ) ) )
|
||||
#define TEMPLATE_TEST_CASE_METHOD( className, ... ) INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_TEST_CASE_METHOD_NO_REGISTRATION(INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_M_P_L_A_T_E____T_E_S_T____ ), className ) )
|
||||
#define TEMPLATE_PRODUCT_TEST_CASE( ... ) TEMPLATE_TEST_CASE( __VA_ARGS__ )
|
||||
#define TEMPLATE_PRODUCT_TEST_CASE_METHOD( className, ... ) TEMPLATE_TEST_CASE_METHOD( className, __VA_ARGS__ )
|
||||
#endif
|
||||
|
||||
#define STATIC_REQUIRE( ... ) (void)(0)
|
||||
|
4
include/external/clara.hpp
vendored
4
include/external/clara.hpp
vendored
@@ -370,7 +370,7 @@ inline auto Column::operator + (Column const& other) -> Columns {
|
||||
// ----------- end of #include from clara_textflow.hpp -----------
|
||||
// ........... back in clara.hpp
|
||||
|
||||
|
||||
#include <cctype>
|
||||
#include <string>
|
||||
#include <memory>
|
||||
#include <set>
|
||||
@@ -664,7 +664,7 @@ namespace detail {
|
||||
}
|
||||
inline auto convertInto( std::string const &source, bool &target ) -> ParserResult {
|
||||
std::string srcLC = source;
|
||||
std::transform( srcLC.begin(), srcLC.end(), srcLC.begin(), []( char c ) { return static_cast<char>( ::tolower(c) ); } );
|
||||
std::transform( srcLC.begin(), srcLC.end(), srcLC.begin(), []( char c ) { return static_cast<char>( std::tolower(c) ); } );
|
||||
if (srcLC == "y" || srcLC == "1" || srcLC == "true" || srcLC == "yes" || srcLC == "on")
|
||||
target = true;
|
||||
else if (srcLC == "n" || srcLC == "0" || srcLC == "false" || srcLC == "no" || srcLC == "off")
|
||||
|
@@ -48,7 +48,7 @@
|
||||
CATCH_INTERNAL_UNSUPPRESS_PARENTHESES_WARNINGS \
|
||||
} INTERNAL_CATCH_CATCH( catchAssertionHandler ) \
|
||||
INTERNAL_CATCH_REACT( catchAssertionHandler ) \
|
||||
} while( (void)0, false && static_cast<bool>( !!(__VA_ARGS__) ) ) // the expression here is never evaluated at runtime but it forces the compiler to give it a look
|
||||
} while( (void)0, (false) && static_cast<bool>( !!(__VA_ARGS__) ) ) // the expression here is never evaluated at runtime but it forces the compiler to give it a look
|
||||
// The double negation silences MSVC's C4800 warning, the static_cast forces short-circuit evaluation if the type has overloaded &&.
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
@@ -130,6 +130,10 @@
|
||||
#define INTERNAL_CATCH_INFO( macroName, log ) \
|
||||
Catch::ScopedMessage INTERNAL_CATCH_UNIQUE_NAME( scopedMessage )( Catch::MessageBuilder( macroName##_catch_sr, CATCH_INTERNAL_LINEINFO, Catch::ResultWas::Info ) << log );
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
#define INTERNAL_CATCH_UNSCOPED_INFO( macroName, log ) \
|
||||
Catch::getResultCapture().emplaceUnscopedMessage( Catch::MessageBuilder( macroName##_catch_sr, CATCH_INTERNAL_LINEINFO, Catch::ResultWas::Info ) << log )
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// Although this is matcher-based, it can be used with just a string
|
||||
#define INTERNAL_CATCH_THROWS_STR_MATCHES( macroName, resultDisposition, matcher, ... ) \
|
||||
|
@@ -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
|
||||
|
@@ -82,7 +82,7 @@ namespace Catch {
|
||||
std::string getProcessName() const;
|
||||
std::string const& getReporterName() const;
|
||||
|
||||
std::vector<std::string> const& getTestsOrTags() const;
|
||||
std::vector<std::string> const& getTestsOrTags() const override;
|
||||
std::vector<std::string> const& getSectionsToRun() const override;
|
||||
|
||||
virtual TestSpec const& testSpec() const override;
|
||||
|
@@ -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() );
|
||||
}
|
||||
}
|
||||
|
@@ -37,10 +37,10 @@ namespace Catch {
|
||||
// Windows can easily distinguish between SO and SigSegV,
|
||||
// but SigInt, SigTerm, etc are handled differently.
|
||||
static SignalDefs signalDefs[] = {
|
||||
{ EXCEPTION_ILLEGAL_INSTRUCTION, "SIGILL - Illegal instruction signal" },
|
||||
{ EXCEPTION_STACK_OVERFLOW, "SIGSEGV - Stack overflow" },
|
||||
{ EXCEPTION_ACCESS_VIOLATION, "SIGSEGV - Segmentation violation signal" },
|
||||
{ EXCEPTION_INT_DIVIDE_BY_ZERO, "Divide by zero error" },
|
||||
{ static_cast<DWORD>(EXCEPTION_ILLEGAL_INSTRUCTION), "SIGILL - Illegal instruction signal" },
|
||||
{ static_cast<DWORD>(EXCEPTION_STACK_OVERFLOW), "SIGSEGV - Stack overflow" },
|
||||
{ static_cast<DWORD>(EXCEPTION_ACCESS_VIOLATION), "SIGSEGV - Segmentation violation signal" },
|
||||
{ static_cast<DWORD>(EXCEPTION_INT_DIVIDE_BY_ZERO), "Divide by zero error" },
|
||||
};
|
||||
|
||||
LONG CALLBACK FatalConditionHandler::handleVectoredException(PEXCEPTION_POINTERS ExceptionInfo) {
|
||||
|
@@ -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,225 +42,169 @@ 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 )... );
|
||||
}
|
||||
|
||||
|
||||
auto acquireGeneratorTracker( SourceLineInfo const& lineInfo ) -> IGeneratorTracker&;
|
||||
|
||||
template<typename L>
|
||||
// Note: The type after -> is weird, because VS2015 cannot parse
|
||||
// the expression used in the typedef inside, when it is in
|
||||
// return type. Yeah, ¯\_(ツ)_/¯
|
||||
auto generate( SourceLineInfo const& lineInfo, L const& generatorExpression ) -> decltype(std::declval<decltype(generatorExpression())>()[0]) {
|
||||
// return type. Yeah.
|
||||
auto generate( SourceLineInfo const& lineInfo, L const& generatorExpression ) -> decltype(std::declval<decltype(generatorExpression())>().get()) {
|
||||
using UnderlyingType = typename decltype(generatorExpression())::type;
|
||||
|
||||
IGeneratorTracker& tracker = acquireGeneratorTracker( lineInfo );
|
||||
if( !tracker.hasGenerator() )
|
||||
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
|
||||
} // namespace Catch
|
||||
|
||||
#define GENERATE( ... ) \
|
||||
Catch::Generators::generate( CATCH_INTERNAL_LINEINFO, []{ using namespace Catch::Generators; return makeGenerators( __VA_ARGS__ ); } )
|
||||
|
||||
Catch::Generators::generate( CATCH_INTERNAL_LINEINFO, [ ]{ using namespace Catch::Generators; return makeGenerators( __VA_ARGS__ ); } )
|
||||
#define GENERATE_COPY( ... ) \
|
||||
Catch::Generators::generate( CATCH_INTERNAL_LINEINFO, [=]{ using namespace Catch::Generators; return makeGenerators( __VA_ARGS__ ); } )
|
||||
#define GENERATE_REF( ... ) \
|
||||
Catch::Generators::generate( CATCH_INTERNAL_LINEINFO, [&]{ using namespace Catch::Generators; return makeGenerators( __VA_ARGS__ ); } )
|
||||
|
||||
#endif // TWOBLUECUBES_CATCH_GENERATORS_HPP_INCLUDED
|
||||
|
242
include/internal/catch_generators_generic.hpp
Normal file
242
include/internal/catch_generators_generic.hpp
Normal file
@@ -0,0 +1,242 @@
|
||||
/*
|
||||
* Created by Martin on 23/2/2019.
|
||||
*
|
||||
* Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
* file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
*/
|
||||
#ifndef TWOBLUECUBES_CATCH_GENERATORS_GENERIC_HPP_INCLUDED
|
||||
#define TWOBLUECUBES_CATCH_GENERATORS_GENERIC_HPP_INCLUDED
|
||||
|
||||
#include "catch_generators.hpp"
|
||||
|
||||
namespace Catch {
|
||||
namespace Generators {
|
||||
|
||||
template <typename T>
|
||||
class TakeGenerator : public IGenerator<T> {
|
||||
GeneratorWrapper<T> m_generator;
|
||||
size_t m_returned = 0;
|
||||
size_t m_target;
|
||||
public:
|
||||
TakeGenerator(size_t target, GeneratorWrapper<T>&& generator):
|
||||
m_generator(std::move(generator)),
|
||||
m_target(target)
|
||||
{
|
||||
assert(target != 0 && "Empty generators are not allowed");
|
||||
}
|
||||
T const& get() const override {
|
||||
return m_generator.get();
|
||||
}
|
||||
bool next() override {
|
||||
++m_returned;
|
||||
if (m_returned >= m_target) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const auto success = m_generator.next();
|
||||
// If the underlying generator does not contain enough values
|
||||
// then we cut short as well
|
||||
if (!success) {
|
||||
m_returned = m_target;
|
||||
}
|
||||
return success;
|
||||
}
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
GeneratorWrapper<T> take(size_t target, GeneratorWrapper<T>&& generator) {
|
||||
return GeneratorWrapper<T>(pf::make_unique<TakeGenerator<T>>(target, std::move(generator)));
|
||||
}
|
||||
|
||||
|
||||
template <typename T, typename Predicate>
|
||||
class FilterGenerator : public IGenerator<T> {
|
||||
GeneratorWrapper<T> m_generator;
|
||||
Predicate m_predicate;
|
||||
public:
|
||||
template <typename P = Predicate>
|
||||
FilterGenerator(P&& pred, GeneratorWrapper<T>&& generator):
|
||||
m_generator(std::move(generator)),
|
||||
m_predicate(std::forward<P>(pred))
|
||||
{
|
||||
if (!m_predicate(m_generator.get())) {
|
||||
// It might happen that there are no values that pass the
|
||||
// filter. In that case we throw an exception.
|
||||
auto has_initial_value = next();
|
||||
if (!has_initial_value) {
|
||||
Catch::throw_exception(GeneratorException("No valid value found in filtered generator"));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
T const& get() const override {
|
||||
return m_generator.get();
|
||||
}
|
||||
|
||||
bool next() override {
|
||||
bool success = m_generator.next();
|
||||
if (!success) {
|
||||
return false;
|
||||
}
|
||||
while (!m_predicate(m_generator.get()) && (success = m_generator.next()) == true);
|
||||
return success;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
template <typename T, typename Predicate>
|
||||
GeneratorWrapper<T> filter(Predicate&& pred, GeneratorWrapper<T>&& generator) {
|
||||
return GeneratorWrapper<T>(std::unique_ptr<IGenerator<T>>(pf::make_unique<FilterGenerator<T, Predicate>>(std::forward<Predicate>(pred), std::move(generator))));
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
class RepeatGenerator : public IGenerator<T> {
|
||||
GeneratorWrapper<T> m_generator;
|
||||
mutable std::vector<T> m_returned;
|
||||
size_t m_target_repeats;
|
||||
size_t m_current_repeat = 0;
|
||||
size_t m_repeat_index = 0;
|
||||
public:
|
||||
RepeatGenerator(size_t repeats, GeneratorWrapper<T>&& generator):
|
||||
m_generator(std::move(generator)),
|
||||
m_target_repeats(repeats)
|
||||
{
|
||||
assert(m_target_repeats > 0 && "Repeat generator must repeat at least once");
|
||||
}
|
||||
|
||||
T const& get() const override {
|
||||
if (m_current_repeat == 0) {
|
||||
m_returned.push_back(m_generator.get());
|
||||
return m_returned.back();
|
||||
}
|
||||
return m_returned[m_repeat_index];
|
||||
}
|
||||
|
||||
bool next() override {
|
||||
// There are 2 basic cases:
|
||||
// 1) We are still reading the generator
|
||||
// 2) We are reading our own cache
|
||||
|
||||
// In the first case, we need to poke the underlying generator.
|
||||
// If it happily moves, we are left in that state, otherwise it is time to start reading from our cache
|
||||
if (m_current_repeat == 0) {
|
||||
const auto success = m_generator.next();
|
||||
if (!success) {
|
||||
++m_current_repeat;
|
||||
}
|
||||
return m_current_repeat < m_target_repeats;
|
||||
}
|
||||
|
||||
// In the second case, we need to move indices forward and check that we haven't run up against the end
|
||||
++m_repeat_index;
|
||||
if (m_repeat_index == m_returned.size()) {
|
||||
m_repeat_index = 0;
|
||||
++m_current_repeat;
|
||||
}
|
||||
return m_current_repeat < m_target_repeats;
|
||||
}
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
GeneratorWrapper<T> repeat(size_t repeats, GeneratorWrapper<T>&& generator) {
|
||||
return GeneratorWrapper<T>(pf::make_unique<RepeatGenerator<T>>(repeats, std::move(generator)));
|
||||
}
|
||||
|
||||
template <typename T, typename U, typename Func>
|
||||
class MapGenerator : public IGenerator<T> {
|
||||
// TBD: provide static assert for mapping function, for friendly error message
|
||||
GeneratorWrapper<U> m_generator;
|
||||
Func m_function;
|
||||
// To avoid returning dangling reference, we have to save the values
|
||||
T m_cache;
|
||||
public:
|
||||
template <typename F2 = Func>
|
||||
MapGenerator(F2&& function, GeneratorWrapper<U>&& generator) :
|
||||
m_generator(std::move(generator)),
|
||||
m_function(std::forward<F2>(function)),
|
||||
m_cache(m_function(m_generator.get()))
|
||||
{}
|
||||
|
||||
T const& get() const override {
|
||||
return m_cache;
|
||||
}
|
||||
bool next() override {
|
||||
const auto success = m_generator.next();
|
||||
if (success) {
|
||||
m_cache = m_function(m_generator.get());
|
||||
}
|
||||
return success;
|
||||
}
|
||||
};
|
||||
|
||||
#if defined(__cpp_lib_is_invocable) && __cpp_lib_is_invocable >= 201703
|
||||
// std::result_of is deprecated in C++17 and removed in C++20. Hence, it is
|
||||
// replaced with std::invoke_result here. Also *_t format is preferred over
|
||||
// typename *::type format.
|
||||
template <typename Func, typename U>
|
||||
using MapFunctionReturnType = std::remove_reference_t<std::remove_cv_t<std::invoke_result_t<Func, U>>>;
|
||||
#else
|
||||
template <typename Func, typename U>
|
||||
using MapFunctionReturnType = typename std::remove_reference<typename std::remove_cv<typename std::result_of<Func(U)>::type>::type>::type;
|
||||
#endif
|
||||
|
||||
template <typename Func, typename U, typename T = MapFunctionReturnType<Func, U>>
|
||||
GeneratorWrapper<T> map(Func&& function, GeneratorWrapper<U>&& generator) {
|
||||
return GeneratorWrapper<T>(
|
||||
pf::make_unique<MapGenerator<T, U, Func>>(std::forward<Func>(function), std::move(generator))
|
||||
);
|
||||
}
|
||||
|
||||
template <typename T, typename U, typename Func>
|
||||
GeneratorWrapper<T> map(Func&& function, GeneratorWrapper<U>&& generator) {
|
||||
return GeneratorWrapper<T>(
|
||||
pf::make_unique<MapGenerator<T, U, Func>>(std::forward<Func>(function), std::move(generator))
|
||||
);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
class ChunkGenerator final : public IGenerator<std::vector<T>> {
|
||||
std::vector<T> m_chunk;
|
||||
size_t m_chunk_size;
|
||||
GeneratorWrapper<T> m_generator;
|
||||
bool m_used_up = false;
|
||||
public:
|
||||
ChunkGenerator(size_t size, GeneratorWrapper<T> generator) :
|
||||
m_chunk_size(size), m_generator(std::move(generator))
|
||||
{
|
||||
m_chunk.reserve(m_chunk_size);
|
||||
m_chunk.push_back(m_generator.get());
|
||||
for (size_t i = 1; i < m_chunk_size; ++i) {
|
||||
if (!m_generator.next()) {
|
||||
Catch::throw_exception(GeneratorException("Not enough values to initialize the first chunk"));
|
||||
}
|
||||
m_chunk.push_back(m_generator.get());
|
||||
}
|
||||
}
|
||||
std::vector<T> const& get() const override {
|
||||
return m_chunk;
|
||||
}
|
||||
bool next() override {
|
||||
m_chunk.clear();
|
||||
for (size_t idx = 0; idx < m_chunk_size; ++idx) {
|
||||
if (!m_generator.next()) {
|
||||
return false;
|
||||
}
|
||||
m_chunk.push_back(m_generator.get());
|
||||
}
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
GeneratorWrapper<std::vector<T>> chunk(size_t size, GeneratorWrapper<T>&& generator) {
|
||||
return GeneratorWrapper<std::vector<T>>(
|
||||
pf::make_unique<ChunkGenerator<T>>(size, std::move(generator))
|
||||
);
|
||||
}
|
||||
|
||||
} // namespace Generators
|
||||
} // namespace Catch
|
||||
|
||||
|
||||
#endif // TWOBLUECUBES_CATCH_GENERATORS_GENERIC_HPP_INCLUDED
|
135
include/internal/catch_generators_specific.hpp
Normal file
135
include/internal/catch_generators_specific.hpp
Normal file
@@ -0,0 +1,135 @@
|
||||
/*
|
||||
* Created by Martin on 15/6/2018.
|
||||
*
|
||||
* Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
* file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
*/
|
||||
#ifndef TWOBLUECUBES_CATCH_GENERATORS_SPECIFIC_HPP_INCLUDED
|
||||
#define TWOBLUECUBES_CATCH_GENERATORS_SPECIFIC_HPP_INCLUDED
|
||||
|
||||
#include "catch_context.h"
|
||||
#include "catch_generators.hpp"
|
||||
#include "catch_interfaces_config.h"
|
||||
|
||||
#include <random>
|
||||
|
||||
namespace Catch {
|
||||
namespace Generators {
|
||||
|
||||
template <typename Float>
|
||||
class RandomFloatingGenerator final : public IGenerator<Float> {
|
||||
// FIXME: What is the right seed?
|
||||
std::minstd_rand m_rand;
|
||||
std::uniform_real_distribution<Float> m_dist;
|
||||
Float m_current_number;
|
||||
public:
|
||||
|
||||
RandomFloatingGenerator(Float a, Float b):
|
||||
m_rand(getCurrentContext().getConfig()->rngSeed()),
|
||||
m_dist(a, b) {
|
||||
static_cast<void>(next());
|
||||
}
|
||||
|
||||
Float const& get() const override {
|
||||
return m_current_number;
|
||||
}
|
||||
bool next() override {
|
||||
m_current_number = m_dist(m_rand);
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
template <typename Integer>
|
||||
class RandomIntegerGenerator final : public IGenerator<Integer> {
|
||||
std::minstd_rand m_rand;
|
||||
std::uniform_int_distribution<Integer> m_dist;
|
||||
Integer m_current_number;
|
||||
public:
|
||||
|
||||
RandomIntegerGenerator(Integer a, Integer b):
|
||||
m_rand(getCurrentContext().getConfig()->rngSeed()),
|
||||
m_dist(a, b) {
|
||||
static_cast<void>(next());
|
||||
}
|
||||
|
||||
Integer const& get() const override {
|
||||
return m_current_number;
|
||||
}
|
||||
bool next() override {
|
||||
m_current_number = m_dist(m_rand);
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
// TODO: Ideally this would be also constrained against the various char types,
|
||||
// but I don't expect users to run into that in practice.
|
||||
template <typename T>
|
||||
typename std::enable_if<std::is_integral<T>::value && !std::is_same<T, bool>::value,
|
||||
GeneratorWrapper<T>>::type
|
||||
random(T a, T b) {
|
||||
return GeneratorWrapper<T>(
|
||||
pf::make_unique<RandomIntegerGenerator<T>>(a, b)
|
||||
);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
typename std::enable_if<std::is_floating_point<T>::value,
|
||||
GeneratorWrapper<T>>::type
|
||||
random(T a, T b) {
|
||||
return GeneratorWrapper<T>(
|
||||
pf::make_unique<RandomFloatingGenerator<T>>(a, b)
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
template <typename T>
|
||||
class RangeGenerator final : public IGenerator<T> {
|
||||
T m_current;
|
||||
T m_end;
|
||||
T m_step;
|
||||
bool m_positive;
|
||||
|
||||
public:
|
||||
RangeGenerator(T const& start, T const& end, T const& step):
|
||||
m_current(start),
|
||||
m_end(end),
|
||||
m_step(step),
|
||||
m_positive(m_step > T(0))
|
||||
{
|
||||
assert(m_current != m_end && "Range start and end cannot be equal");
|
||||
assert(m_step != T(0) && "Step size cannot be zero");
|
||||
assert(((m_positive && m_current <= m_end) || (!m_positive && m_current >= m_end)) && "Step moves away from end");
|
||||
}
|
||||
|
||||
RangeGenerator(T const& start, T const& end):
|
||||
RangeGenerator(start, end, (start < end) ? T(1) : T(-1))
|
||||
{}
|
||||
|
||||
T const& get() const override {
|
||||
return m_current;
|
||||
}
|
||||
|
||||
bool next() override {
|
||||
m_current += m_step;
|
||||
return (m_positive) ? (m_current < m_end) : (m_current > m_end);
|
||||
}
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
GeneratorWrapper<T> range(T const& start, T const& end, T const& step) {
|
||||
static_assert(std::is_integral<T>::value && !std::is_same<T, bool>::value, "Type must be an integer");
|
||||
return GeneratorWrapper<T>(pf::make_unique<RangeGenerator<T>>(start, end, step));
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
GeneratorWrapper<T> range(T const& start, T const& end) {
|
||||
static_assert(std::is_integral<T>::value && !std::is_same<T, bool>::value, "Type must be an integer");
|
||||
return GeneratorWrapper<T>(pf::make_unique<RangeGenerator<T>>(start, end));
|
||||
}
|
||||
|
||||
|
||||
} // namespace Generators
|
||||
} // namespace Catch
|
||||
|
||||
|
||||
#endif // TWOBLUECUBES_CATCH_GENERATORS_SPECIFIC_HPP_INCLUDED
|
@@ -20,6 +20,7 @@ namespace Catch {
|
||||
struct SectionInfo;
|
||||
struct SectionEndInfo;
|
||||
struct MessageInfo;
|
||||
struct MessageBuilder;
|
||||
struct Counts;
|
||||
struct BenchmarkInfo;
|
||||
struct BenchmarkStats;
|
||||
@@ -46,6 +47,8 @@ namespace Catch {
|
||||
virtual void pushScopedMessage( MessageInfo const& message ) = 0;
|
||||
virtual void popScopedMessage( MessageInfo const& message ) = 0;
|
||||
|
||||
virtual void emplaceUnscopedMessage( MessageBuilder const& builder ) = 0;
|
||||
|
||||
virtual void handleFatalErrorCondition( StringRef message ) = 0;
|
||||
|
||||
virtual void handleExpr
|
||||
|
@@ -69,6 +69,7 @@ namespace Catch {
|
||||
virtual ShowDurations::OrNot showDurations() const = 0;
|
||||
virtual TestSpec const& testSpec() const = 0;
|
||||
virtual bool hasTestFilters() const = 0;
|
||||
virtual std::vector<std::string> const& getTestsOrTags() const = 0;
|
||||
virtual RunTests::InWhatOrder runOrder() const = 0;
|
||||
virtual unsigned int rngSeed() const = 0;
|
||||
virtual int benchmarkResolutionMultiple() const = 0;
|
||||
|
@@ -13,16 +13,17 @@
|
||||
namespace Catch {
|
||||
|
||||
namespace Generators {
|
||||
class GeneratorBase {
|
||||
protected:
|
||||
size_t m_size = 0;
|
||||
|
||||
class GeneratorUntypedBase {
|
||||
public:
|
||||
GeneratorBase( size_t size ) : m_size( size ) {}
|
||||
virtual ~GeneratorBase();
|
||||
auto size() const -> size_t { return m_size; }
|
||||
GeneratorUntypedBase() = default;
|
||||
virtual ~GeneratorUntypedBase();
|
||||
// Attempts to move the generator to the next element
|
||||
//
|
||||
// Returns true iff the move succeeded (and a valid element
|
||||
// can be retrieved).
|
||||
virtual bool next() = 0;
|
||||
};
|
||||
using GeneratorBasePtr = std::unique_ptr<GeneratorBase>;
|
||||
using GeneratorBasePtr = std::unique_ptr<GeneratorUntypedBase>;
|
||||
|
||||
} // namespace Generators
|
||||
|
||||
@@ -31,7 +32,6 @@ namespace Catch {
|
||||
virtual auto hasGenerator() const -> bool = 0;
|
||||
virtual auto getGenerator() const -> Generators::GeneratorBasePtr const& = 0;
|
||||
virtual void setGenerator( Generators::GeneratorBasePtr&& generator ) = 0;
|
||||
virtual auto getIndex() const -> std::size_t = 0;
|
||||
};
|
||||
|
||||
} // namespace Catch
|
||||
|
@@ -80,8 +80,8 @@ namespace Catch {
|
||||
|
||||
AssertionStats( AssertionStats const& ) = default;
|
||||
AssertionStats( AssertionStats && ) = default;
|
||||
AssertionStats& operator = ( AssertionStats const& ) = default;
|
||||
AssertionStats& operator = ( AssertionStats && ) = default;
|
||||
AssertionStats& operator = ( AssertionStats const& ) = delete;
|
||||
AssertionStats& operator = ( AssertionStats && ) = delete;
|
||||
virtual ~AssertionStats();
|
||||
|
||||
AssertionResult assertionResult;
|
||||
|
@@ -9,7 +9,6 @@
|
||||
#define TWOBLUECUBES_CATCH_INTERFACES_TESTCASE_H_INCLUDED
|
||||
|
||||
#include <vector>
|
||||
#include <memory>
|
||||
|
||||
namespace Catch {
|
||||
|
||||
@@ -20,8 +19,6 @@ namespace Catch {
|
||||
virtual ~ITestInvoker();
|
||||
};
|
||||
|
||||
using ITestCasePtr = std::shared_ptr<ITestInvoker>;
|
||||
|
||||
class TestCase;
|
||||
struct IConfig;
|
||||
|
||||
|
@@ -12,6 +12,7 @@
|
||||
#include "catch_interfaces_reporter.h"
|
||||
#include "catch_interfaces_testcase.h"
|
||||
|
||||
#include "catch_context.h"
|
||||
#include "catch_stream.h"
|
||||
#include "catch_text.h"
|
||||
|
||||
@@ -146,15 +147,16 @@ namespace Catch {
|
||||
return factories.size();
|
||||
}
|
||||
|
||||
Option<std::size_t> list( Config const& config ) {
|
||||
Option<std::size_t> list( std::shared_ptr<Config> const& config ) {
|
||||
Option<std::size_t> listedCount;
|
||||
if( config.listTests() )
|
||||
listedCount = listedCount.valueOr(0) + listTests( config );
|
||||
if( config.listTestNamesOnly() )
|
||||
listedCount = listedCount.valueOr(0) + listTestsNamesOnly( config );
|
||||
if( config.listTags() )
|
||||
listedCount = listedCount.valueOr(0) + listTags( config );
|
||||
if( config.listReporters() )
|
||||
getCurrentMutableContext().setConfig( config );
|
||||
if( config->listTests() )
|
||||
listedCount = listedCount.valueOr(0) + listTests( *config );
|
||||
if( config->listTestNamesOnly() )
|
||||
listedCount = listedCount.valueOr(0) + listTestsNamesOnly( *config );
|
||||
if( config->listTags() )
|
||||
listedCount = listedCount.valueOr(0) + listTags( *config );
|
||||
if( config->listReporters() )
|
||||
listedCount = listedCount.valueOr(0) + listReporters();
|
||||
return listedCount;
|
||||
}
|
||||
|
@@ -31,7 +31,7 @@ namespace Catch {
|
||||
|
||||
std::size_t listReporters();
|
||||
|
||||
Option<std::size_t> list( Config const& config );
|
||||
Option<std::size_t> list( std::shared_ptr<Config> const& config );
|
||||
|
||||
} // end namespace Catch
|
||||
|
||||
|
@@ -47,14 +47,20 @@ namespace Catch {
|
||||
|
||||
|
||||
ScopedMessage::ScopedMessage( MessageBuilder const& builder )
|
||||
: m_info( builder.m_info )
|
||||
: m_info( builder.m_info ), m_moved()
|
||||
{
|
||||
m_info.message = builder.m_stream.str();
|
||||
getResultCapture().pushScopedMessage( m_info );
|
||||
}
|
||||
|
||||
ScopedMessage::ScopedMessage( ScopedMessage&& old )
|
||||
: m_info( old.m_info ), m_moved()
|
||||
{
|
||||
old.m_moved = true;
|
||||
}
|
||||
|
||||
ScopedMessage::~ScopedMessage() {
|
||||
if ( !uncaught_exceptions() ){
|
||||
if ( !uncaught_exceptions() && !m_moved ){
|
||||
getResultCapture().popScopedMessage(m_info);
|
||||
}
|
||||
}
|
||||
|
@@ -64,9 +64,12 @@ namespace Catch {
|
||||
class ScopedMessage {
|
||||
public:
|
||||
explicit ScopedMessage( MessageBuilder const& builder );
|
||||
ScopedMessage( ScopedMessage& duplicate ) = delete;
|
||||
ScopedMessage( ScopedMessage&& old );
|
||||
~ScopedMessage();
|
||||
|
||||
MessageInfo m_info;
|
||||
bool m_moved;
|
||||
};
|
||||
|
||||
class Capturer {
|
||||
|
77
include/internal/catch_meta.hpp
Normal file
77
include/internal/catch_meta.hpp
Normal file
@@ -0,0 +1,77 @@
|
||||
/*
|
||||
* Created by Jozef on 02/12/2018.
|
||||
* Copyright 2018 Two Blue Cubes Ltd. All rights reserved.
|
||||
*
|
||||
* Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
* file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
*/
|
||||
|
||||
#ifndef TWOBLUECUBES_CATCH_META_HPP_INCLUDED
|
||||
#define TWOBLUECUBES_CATCH_META_HPP_INCLUDED
|
||||
|
||||
#include <type_traits>
|
||||
|
||||
namespace Catch {
|
||||
template< typename... >
|
||||
struct TypeList {};
|
||||
|
||||
template< typename... >
|
||||
struct append;
|
||||
|
||||
template< template<typename...> class L1
|
||||
, typename...E1
|
||||
, template<typename...> class L2
|
||||
, typename...E2
|
||||
>
|
||||
struct append< L1<E1...>, L2<E2...> > {
|
||||
using type = L1<E1..., E2...>;
|
||||
};
|
||||
|
||||
template< template<typename...> class L1
|
||||
, typename...E1
|
||||
, template<typename...> class L2
|
||||
, typename...E2
|
||||
, typename...Rest
|
||||
>
|
||||
struct append< L1<E1...>, L2<E2...>, Rest...> {
|
||||
using type = typename append< L1<E1..., E2...>, Rest... >::type;
|
||||
};
|
||||
|
||||
template< template<typename...> class
|
||||
, typename...
|
||||
>
|
||||
struct rewrap;
|
||||
|
||||
template< template<typename...> class Container
|
||||
, template<typename...> class List
|
||||
, typename...elems
|
||||
>
|
||||
struct rewrap<Container, List<elems...>> {
|
||||
using type = TypeList< Container< elems... > >;
|
||||
};
|
||||
|
||||
template< template<typename...> class Container
|
||||
, template<typename...> class List
|
||||
, class...Elems
|
||||
, typename...Elements>
|
||||
struct rewrap<Container, List<Elems...>, Elements...> {
|
||||
using type = typename append<TypeList<Container<Elems...>>, typename rewrap<Container, Elements...>::type>::type;
|
||||
};
|
||||
|
||||
template< template<typename...> class...Containers >
|
||||
struct combine {
|
||||
template< typename...Types >
|
||||
struct with_types {
|
||||
template< template <typename...> class Final >
|
||||
struct into {
|
||||
using type = typename append<Final<>, typename rewrap<Containers, Types...>::type...>::type;
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
struct always_false : std::false_type {};
|
||||
|
||||
} // namespace Catch
|
||||
|
||||
#endif // TWOBLUECUBES_CATCH_META_HPP_INCLUDED
|
@@ -116,7 +116,7 @@ namespace Catch {
|
||||
arcSafeRelease( m_substr );
|
||||
}
|
||||
|
||||
bool match( NSString* arg ) const override {
|
||||
bool match( NSString* const& str ) const override {
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -126,7 +126,7 @@ namespace Catch {
|
||||
struct Equals : StringHolder {
|
||||
Equals( NSString* substr ) : StringHolder( substr ){}
|
||||
|
||||
bool match( NSString* str ) const override {
|
||||
bool match( NSString* const& str ) const override {
|
||||
return (str != nil || m_substr == nil ) &&
|
||||
[str isEqualToString:m_substr];
|
||||
}
|
||||
@@ -139,7 +139,7 @@ namespace Catch {
|
||||
struct Contains : StringHolder {
|
||||
Contains( NSString* substr ) : StringHolder( substr ){}
|
||||
|
||||
bool match( NSString* str ) const {
|
||||
bool match( NSString* const& str ) const override {
|
||||
return (str != nil || m_substr == nil ) &&
|
||||
[str rangeOfString:m_substr].location != NSNotFound;
|
||||
}
|
||||
@@ -152,7 +152,7 @@ namespace Catch {
|
||||
struct StartsWith : StringHolder {
|
||||
StartsWith( NSString* substr ) : StringHolder( substr ){}
|
||||
|
||||
bool match( NSString* str ) const override {
|
||||
bool match( NSString* const& str ) const override {
|
||||
return (str != nil || m_substr == nil ) &&
|
||||
[str rangeOfString:m_substr].location == 0;
|
||||
}
|
||||
@@ -164,7 +164,7 @@ namespace Catch {
|
||||
struct EndsWith : StringHolder {
|
||||
EndsWith( NSString* substr ) : StringHolder( substr ){}
|
||||
|
||||
bool match( NSString* str ) const override {
|
||||
bool match( NSString* const& str ) const override {
|
||||
return (str != nil || m_substr == nil ) &&
|
||||
[str rangeOfString:m_substr].location == [str length] - [m_substr length];
|
||||
}
|
||||
|
@@ -49,6 +49,15 @@ namespace Catch {
|
||||
{}
|
||||
auto RedirectedStdErr::str() const -> std::string { return m_rss.str(); }
|
||||
|
||||
RedirectedStreams::RedirectedStreams(std::string& redirectedCout, std::string& redirectedCerr)
|
||||
: m_redirectedCout(redirectedCout),
|
||||
m_redirectedCerr(redirectedCerr)
|
||||
{}
|
||||
|
||||
RedirectedStreams::~RedirectedStreams() {
|
||||
m_redirectedCout += m_redirectedStdOut.str();
|
||||
m_redirectedCerr += m_redirectedStdErr.str();
|
||||
}
|
||||
|
||||
#if defined(CATCH_CONFIG_NEW_CAPTURE)
|
||||
|
||||
|
@@ -46,6 +46,21 @@ namespace Catch {
|
||||
auto str() const -> std::string;
|
||||
};
|
||||
|
||||
class RedirectedStreams {
|
||||
public:
|
||||
RedirectedStreams(RedirectedStreams const&) = delete;
|
||||
RedirectedStreams& operator=(RedirectedStreams const&) = delete;
|
||||
RedirectedStreams(RedirectedStreams&&) = delete;
|
||||
RedirectedStreams& operator=(RedirectedStreams&&) = delete;
|
||||
|
||||
RedirectedStreams(std::string& redirectedCout, std::string& redirectedCerr);
|
||||
~RedirectedStreams();
|
||||
private:
|
||||
std::string& m_redirectedCout;
|
||||
std::string& m_redirectedCerr;
|
||||
RedirectedStdOut m_redirectedStdOut;
|
||||
RedirectedStdErr m_redirectedStdErr;
|
||||
};
|
||||
|
||||
#if defined(CATCH_CONFIG_NEW_CAPTURE)
|
||||
|
||||
|
@@ -57,6 +57,16 @@
|
||||
#define INTERNAL_CATCH_EXPAND2(...) INTERNAL_CATCH_NO## __VA_ARGS__
|
||||
#define INTERNAL_CATCH_DEF(...) INTERNAL_CATCH_DEF __VA_ARGS__
|
||||
#define INTERNAL_CATCH_NOINTERNAL_CATCH_DEF
|
||||
#define INTERNAL_CATCH_STRINGIZE(...) INTERNAL_CATCH_STRINGIZE2(__VA_ARGS__)
|
||||
#ifndef CATCH_CONFIG_TRADITIONAL_MSVC_PREPROCESSOR
|
||||
#define INTERNAL_CATCH_STRINGIZE2(...) #__VA_ARGS__
|
||||
#define INTERNAL_CATCH_STRINGIZE_WITHOUT_PARENS(param) INTERNAL_CATCH_STRINGIZE(INTERNAL_CATCH_REMOVE_PARENS(param))
|
||||
#else
|
||||
// MSVC is adding extra space and needs another indirection to expand INTERNAL_CATCH_NOINTERNAL_CATCH_DEF
|
||||
#define INTERNAL_CATCH_STRINGIZE2(...) INTERNAL_CATCH_STRINGIZE3(__VA_ARGS__)
|
||||
#define INTERNAL_CATCH_STRINGIZE3(...) #__VA_ARGS__
|
||||
#define INTERNAL_CATCH_STRINGIZE_WITHOUT_PARENS(param) (INTERNAL_CATCH_STRINGIZE(INTERNAL_CATCH_REMOVE_PARENS(param)) + 1)
|
||||
#endif
|
||||
|
||||
#define INTERNAL_CATCH_REMOVE_PARENS(...) INTERNAL_CATCH_EXPAND1(INTERNAL_CATCH_DEF __VA_ARGS__)
|
||||
|
||||
@@ -71,4 +81,9 @@
|
||||
#define INTERNAL_CATCH_TEMPLATE_UNIQUE_NAME(Name, ...) INTERNAL_CATCH_TEMPLATE_UNIQUE_NAME1(Name, INTERNAL_CATCH_EXPAND_VARGS(INTERNAL_CATCH_REMOVE_PARENS(__VA_ARGS__)))
|
||||
#endif
|
||||
|
||||
#define INTERNAL_CATCH_MAKE_TYPE_LIST(types) Catch::TypeList<INTERNAL_CATCH_REMOVE_PARENS(types)>
|
||||
|
||||
#define INTERNAL_CATCH_MAKE_TYPE_LISTS_FROM_TYPES(types)\
|
||||
CATCH_REC_LIST(INTERNAL_CATCH_MAKE_TYPE_LIST,INTERNAL_CATCH_REMOVE_PARENS(types))
|
||||
|
||||
#endif // TWOBLUECUBES_CATCH_PREPROCESSOR_HPP_INCLUDED
|
||||
|
@@ -14,7 +14,6 @@ namespace Catch {
|
||||
|
||||
namespace Generators {
|
||||
struct GeneratorTracker : TestCaseTracking::TrackerBase, IGeneratorTracker {
|
||||
size_t m_index = static_cast<size_t>( -1 );
|
||||
GeneratorBasePtr m_generator;
|
||||
|
||||
GeneratorTracker( TestCaseTracking::NameAndLocation const& nameAndLocation, TrackerContext& ctx, ITracker* parent )
|
||||
@@ -28,7 +27,7 @@ namespace Catch {
|
||||
ITracker& currentTracker = ctx.currentTracker();
|
||||
if( TestCaseTracking::ITrackerPtr childTracker = currentTracker.findChild( nameAndLocation ) ) {
|
||||
assert( childTracker );
|
||||
assert( childTracker->isIndexTracker() );
|
||||
assert( childTracker->isGeneratorTracker() );
|
||||
tracker = std::static_pointer_cast<GeneratorTracker>( childTracker );
|
||||
}
|
||||
else {
|
||||
@@ -37,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,14 +63,10 @@ namespace Catch {
|
||||
void setGenerator( GeneratorBasePtr&& generator ) override {
|
||||
m_generator = std::move( generator );
|
||||
}
|
||||
auto getIndex() const -> size_t override {
|
||||
return m_index;
|
||||
}
|
||||
};
|
||||
GeneratorTracker::~GeneratorTracker() {}
|
||||
}
|
||||
|
||||
|
||||
RunContext::RunContext(IConfigPtr const& _config, IStreamingReporterPtr&& reporter)
|
||||
: m_runInfo(_config->name()),
|
||||
m_context(getCurrentMutableContext()),
|
||||
@@ -170,6 +161,9 @@ namespace Catch {
|
||||
// and should be let to clear themselves out.
|
||||
static_cast<void>(m_reporter->assertionEnded(AssertionStats(result, m_messages, m_totals)));
|
||||
|
||||
if (result.getResultType() != ResultWas::Warning)
|
||||
m_messageScopes.clear();
|
||||
|
||||
// Reset working state
|
||||
resetAssertionInfo();
|
||||
m_lastResult = result;
|
||||
@@ -224,6 +218,7 @@ namespace Catch {
|
||||
|
||||
m_reporter->sectionEnded(SectionStats(endInfo.sectionInfo, assertions, endInfo.durationInSeconds, missingAssertions));
|
||||
m_messages.clear();
|
||||
m_messageScopes.clear();
|
||||
}
|
||||
|
||||
void RunContext::sectionEndedEarly(SectionEndInfo const & endInfo) {
|
||||
@@ -250,6 +245,10 @@ namespace Catch {
|
||||
m_messages.erase(std::remove(m_messages.begin(), m_messages.end(), message), m_messages.end());
|
||||
}
|
||||
|
||||
void RunContext::emplaceUnscopedMessage( MessageBuilder const& builder ) {
|
||||
m_messageScopes.emplace_back( builder );
|
||||
}
|
||||
|
||||
std::string RunContext::getCurrentTestName() const {
|
||||
return m_activeTestCase
|
||||
? m_activeTestCase->getTestCaseInfo().name
|
||||
@@ -310,6 +309,7 @@ namespace Catch {
|
||||
m_lastAssertionPassed = true;
|
||||
++m_totals.assertions.passed;
|
||||
resetAssertionInfo();
|
||||
m_messageScopes.clear();
|
||||
}
|
||||
|
||||
bool RunContext::aborting() const {
|
||||
@@ -331,13 +331,10 @@ namespace Catch {
|
||||
CATCH_TRY {
|
||||
if (m_reporter->getPreferences().shouldRedirectStdOut) {
|
||||
#if !defined(CATCH_CONFIG_EXPERIMENTAL_REDIRECT)
|
||||
RedirectedStdOut redirectedStdOut;
|
||||
RedirectedStdErr redirectedStdErr;
|
||||
RedirectedStreams redirectedStreams(redirectedCout, redirectedCerr);
|
||||
|
||||
timer.start();
|
||||
invokeActiveTestCase();
|
||||
redirectedCout += redirectedStdOut.str();
|
||||
redirectedCerr += redirectedStdErr.str();
|
||||
#else
|
||||
OutputRedirect r(redirectedCout, redirectedCerr);
|
||||
timer.start();
|
||||
@@ -364,6 +361,7 @@ namespace Catch {
|
||||
m_testCaseTracker->close();
|
||||
handleUnfinishedSections();
|
||||
m_messages.clear();
|
||||
m_messageScopes.clear();
|
||||
|
||||
SectionStats testCaseSectionStats(testCaseSection, assertions, duration, missingAssertions);
|
||||
m_reporter->sectionEnded(testCaseSectionStats);
|
||||
|
@@ -88,6 +88,8 @@ namespace Catch {
|
||||
void pushScopedMessage( MessageInfo const& message ) override;
|
||||
void popScopedMessage( MessageInfo const& message ) override;
|
||||
|
||||
void emplaceUnscopedMessage( MessageBuilder const& builder ) override;
|
||||
|
||||
std::string getCurrentTestName() const override;
|
||||
|
||||
const AssertionResult* getLastResult() const override;
|
||||
@@ -128,13 +130,14 @@ namespace Catch {
|
||||
TestRunInfo m_runInfo;
|
||||
IMutableContext& m_context;
|
||||
TestCase const* m_activeTestCase = nullptr;
|
||||
ITracker* m_testCaseTracker;
|
||||
ITracker* m_testCaseTracker = nullptr;
|
||||
Option<AssertionResult> m_lastResult;
|
||||
|
||||
IConfigPtr m_config;
|
||||
Totals m_totals;
|
||||
IStreamingReporterPtr m_reporter;
|
||||
std::vector<MessageInfo> m_messages;
|
||||
std::vector<ScopedMessage> m_messageScopes; /* Keeps owners of so-called unscoped messages. */
|
||||
AssertionInfo m_lastAssertionInfo;
|
||||
std::vector<SectionEndInfo> m_unfinishedSections;
|
||||
std::vector<ITracker*> m_activeSections;
|
||||
|
@@ -10,6 +10,7 @@
|
||||
#include "catch_console_colour.h"
|
||||
#include "catch_enforce.h"
|
||||
#include "catch_list.h"
|
||||
#include "catch_context.h"
|
||||
#include "catch_run_context.h"
|
||||
#include "catch_stream.h"
|
||||
#include "catch_test_spec.h"
|
||||
@@ -42,14 +43,19 @@ namespace Catch {
|
||||
return createReporter(config->getReporterName(), config);
|
||||
}
|
||||
|
||||
auto multi = std::unique_ptr<ListeningReporter>(new ListeningReporter);
|
||||
|
||||
// On older platforms, returning std::unique_ptr<ListeningReporter>
|
||||
// when the return type is std::unique_ptr<IStreamingReporter>
|
||||
// doesn't compile without a std::move call. However, this causes
|
||||
// a warning on newer platforms. Thus, we have to work around
|
||||
// it a bit and downcast the pointer manually.
|
||||
auto ret = std::unique_ptr<IStreamingReporter>(new ListeningReporter);
|
||||
auto& multi = static_cast<ListeningReporter&>(*ret);
|
||||
auto const& listeners = Catch::getRegistryHub().getReporterRegistry().getListeners();
|
||||
for (auto const& listener : listeners) {
|
||||
multi->addListener(listener->create(Catch::ReporterConfig(config)));
|
||||
multi.addListener(listener->create(Catch::ReporterConfig(config)));
|
||||
}
|
||||
multi->addReporter(createReporter(config->getReporterName(), config));
|
||||
return std::move(multi);
|
||||
multi.addReporter(createReporter(config->getReporterName(), config));
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
@@ -166,6 +172,8 @@ namespace Catch {
|
||||
|
||||
auto result = m_cli.parse( clara::Args( argc, argv ) );
|
||||
if( !result ) {
|
||||
config();
|
||||
getCurrentMutableContext().setConfig(m_config);
|
||||
Catch::cerr()
|
||||
<< Colour( Colour::Red )
|
||||
<< "\nError(s) in input:\n"
|
||||
@@ -257,7 +265,7 @@ namespace Catch {
|
||||
applyFilenamesAsTags( *m_config );
|
||||
|
||||
// Handle list request
|
||||
if( Option<std::size_t> listed = list( config() ) )
|
||||
if( Option<std::size_t> listed = list( m_config ) )
|
||||
return static_cast<int>( *listed );
|
||||
|
||||
auto totals = runTests( m_config );
|
||||
|
@@ -13,8 +13,6 @@
|
||||
|
||||
namespace Catch {
|
||||
|
||||
class StringData;
|
||||
|
||||
/// A non-owning string class (similar to the forthcoming std::string_view)
|
||||
/// Note that, because a StringRef may be a substring of another string,
|
||||
/// it may not be null terminated. c_str() must return a null terminated
|
||||
|
@@ -16,10 +16,11 @@
|
||||
# pragma clang diagnostic ignored "-Wcovered-switch-default"
|
||||
# endif
|
||||
#elif defined __GNUC__
|
||||
// GCC likes to warn on REQUIREs, and we cannot suppress them
|
||||
// locally because g++'s support for _Pragma is lacking in older,
|
||||
// still supported, versions
|
||||
# pragma GCC diagnostic ignored "-Wparentheses"
|
||||
// Because REQUIREs trigger GCC's -Wparentheses, and because still
|
||||
// supported version of g++ have only buggy support for _Pragmas,
|
||||
// Wparentheses have to be suppressed globally.
|
||||
# pragma GCC diagnostic ignored "-Wparentheses" // See #674 for details
|
||||
|
||||
# pragma GCC diagnostic push
|
||||
# pragma GCC diagnostic ignored "-Wunused-variable"
|
||||
# pragma GCC diagnostic ignored "-Wpadded"
|
||||
|
@@ -75,6 +75,12 @@ namespace Catch {
|
||||
else if( prop == TestCaseInfo::None )
|
||||
enforceNotReservedTag( tag, _lineInfo );
|
||||
|
||||
// Merged hide tags like `[.approvals]` should be added as
|
||||
// `[.][approvals]`. The `[.]` is added at later point, so
|
||||
// we only strip the prefix
|
||||
if (startsWith(tag, '.') && tag.size() > 1) {
|
||||
tag.erase(0, 1);
|
||||
}
|
||||
tags.push_back( tag );
|
||||
tag.clear();
|
||||
inTag = false;
|
||||
|
@@ -121,7 +121,7 @@ namespace TestCaseTracking {
|
||||
}
|
||||
|
||||
bool TrackerBase::isSectionTracker() const { return false; }
|
||||
bool TrackerBase::isIndexTracker() const { return false; }
|
||||
bool TrackerBase::isGeneratorTracker() const { return false; }
|
||||
|
||||
void TrackerBase::open() {
|
||||
m_runState = Executing;
|
||||
@@ -190,6 +190,17 @@ namespace TestCaseTracking {
|
||||
}
|
||||
}
|
||||
|
||||
bool SectionTracker::isComplete() const {
|
||||
bool complete = true;
|
||||
|
||||
if ((m_filters.empty() || m_filters[0] == "") ||
|
||||
std::find(m_filters.begin(), m_filters.end(),
|
||||
m_nameAndLocation.name) != m_filters.end())
|
||||
complete = TrackerBase::isComplete();
|
||||
return complete;
|
||||
|
||||
}
|
||||
|
||||
bool SectionTracker::isSectionTracker() const { return true; }
|
||||
|
||||
SectionTracker& SectionTracker::acquire( TrackerContext& ctx, NameAndLocation const& nameAndLocation ) {
|
||||
@@ -227,55 +238,11 @@ namespace TestCaseTracking {
|
||||
m_filters.insert( m_filters.end(), ++filters.begin(), filters.end() );
|
||||
}
|
||||
|
||||
IndexTracker::IndexTracker( NameAndLocation const& nameAndLocation, TrackerContext& ctx, ITracker* parent, int size )
|
||||
: TrackerBase( nameAndLocation, ctx, parent ),
|
||||
m_size( size )
|
||||
{}
|
||||
|
||||
bool IndexTracker::isIndexTracker() const { return true; }
|
||||
|
||||
IndexTracker& IndexTracker::acquire( TrackerContext& ctx, NameAndLocation const& nameAndLocation, int size ) {
|
||||
std::shared_ptr<IndexTracker> tracker;
|
||||
|
||||
ITracker& currentTracker = ctx.currentTracker();
|
||||
if( ITrackerPtr childTracker = currentTracker.findChild( nameAndLocation ) ) {
|
||||
assert( childTracker );
|
||||
assert( childTracker->isIndexTracker() );
|
||||
tracker = std::static_pointer_cast<IndexTracker>( childTracker );
|
||||
}
|
||||
else {
|
||||
tracker = std::make_shared<IndexTracker>( nameAndLocation, ctx, ¤tTracker, size );
|
||||
currentTracker.addChild( tracker );
|
||||
}
|
||||
|
||||
if( !ctx.completedCycle() && !tracker->isComplete() ) {
|
||||
if( tracker->m_runState != ExecutingChildren && tracker->m_runState != NeedsAnotherRun )
|
||||
tracker->moveNext();
|
||||
tracker->open();
|
||||
}
|
||||
|
||||
return *tracker;
|
||||
}
|
||||
|
||||
int IndexTracker::index() const { return m_index; }
|
||||
|
||||
void IndexTracker::moveNext() {
|
||||
m_index++;
|
||||
m_children.clear();
|
||||
}
|
||||
|
||||
void IndexTracker::close() {
|
||||
TrackerBase::close();
|
||||
if( m_runState == CompletedSuccessfully && m_index < m_size-1 )
|
||||
m_runState = Executing;
|
||||
}
|
||||
|
||||
} // namespace TestCaseTracking
|
||||
|
||||
using TestCaseTracking::ITracker;
|
||||
using TestCaseTracking::TrackerContext;
|
||||
using TestCaseTracking::SectionTracker;
|
||||
using TestCaseTracking::IndexTracker;
|
||||
|
||||
} // namespace Catch
|
||||
|
||||
|
@@ -54,7 +54,7 @@ namespace TestCaseTracking {
|
||||
|
||||
// Debug/ checking
|
||||
virtual bool isSectionTracker() const = 0;
|
||||
virtual bool isIndexTracker() const = 0;
|
||||
virtual bool isGeneratorTracker() const = 0;
|
||||
};
|
||||
|
||||
class TrackerContext {
|
||||
@@ -120,7 +120,7 @@ namespace TestCaseTracking {
|
||||
void openChild() override;
|
||||
|
||||
bool isSectionTracker() const override;
|
||||
bool isIndexTracker() const override;
|
||||
bool isGeneratorTracker() const override;
|
||||
|
||||
void open();
|
||||
|
||||
@@ -140,6 +140,8 @@ namespace TestCaseTracking {
|
||||
|
||||
bool isSectionTracker() const override;
|
||||
|
||||
bool isComplete() const override;
|
||||
|
||||
static SectionTracker& acquire( TrackerContext& ctx, NameAndLocation const& nameAndLocation );
|
||||
|
||||
void tryOpen();
|
||||
@@ -148,28 +150,11 @@ namespace TestCaseTracking {
|
||||
void addNextFilters( std::vector<std::string> const& filters );
|
||||
};
|
||||
|
||||
class IndexTracker : public TrackerBase {
|
||||
int m_size;
|
||||
int m_index = -1;
|
||||
public:
|
||||
IndexTracker( NameAndLocation const& nameAndLocation, TrackerContext& ctx, ITracker* parent, int size );
|
||||
|
||||
bool isIndexTracker() const override;
|
||||
void close() override;
|
||||
|
||||
static IndexTracker& acquire( TrackerContext& ctx, NameAndLocation const& nameAndLocation, int size );
|
||||
|
||||
int index() const;
|
||||
|
||||
void moveNext();
|
||||
};
|
||||
|
||||
} // namespace TestCaseTracking
|
||||
|
||||
using TestCaseTracking::ITracker;
|
||||
using TestCaseTracking::TrackerContext;
|
||||
using TestCaseTracking::SectionTracker;
|
||||
using TestCaseTracking::IndexTracker;
|
||||
|
||||
} // namespace Catch
|
||||
|
||||
|
@@ -14,6 +14,7 @@
|
||||
#include "catch_stringref.h"
|
||||
#include "catch_type_traits.hpp"
|
||||
#include "catch_preprocessor.hpp"
|
||||
#include "catch_meta.hpp"
|
||||
|
||||
namespace Catch {
|
||||
|
||||
@@ -150,6 +151,41 @@ struct AutoReg : NonCopyable {
|
||||
return 0;\
|
||||
}();
|
||||
|
||||
#define INTERNAL_CATCH_TEMPLATE_PRODUCT_TEST_CASE2(TestName, TestFuncName, Name, Tags, TmplTypes, TypesList) \
|
||||
CATCH_INTERNAL_SUPPRESS_GLOBALS_WARNINGS \
|
||||
template<typename TestType> static void TestFuncName(); \
|
||||
namespace { \
|
||||
template<typename... Types> \
|
||||
struct TestName { \
|
||||
TestName() { \
|
||||
CATCH_INTERNAL_CHECK_UNIQUE_TYPES(Types...) \
|
||||
int index = 0; \
|
||||
using expander = int[]; \
|
||||
constexpr char const* tmpl_types[] = {CATCH_REC_LIST(INTERNAL_CATCH_STRINGIZE_WITHOUT_PARENS, INTERNAL_CATCH_REMOVE_PARENS(TmplTypes))};\
|
||||
constexpr char const* types_list[] = {CATCH_REC_LIST(INTERNAL_CATCH_STRINGIZE_WITHOUT_PARENS, INTERNAL_CATCH_REMOVE_PARENS(TypesList))};\
|
||||
constexpr auto num_types = sizeof(types_list) / sizeof(types_list[0]);\
|
||||
(void)expander{(Catch::AutoReg( Catch::makeTestInvoker( &TestFuncName<Types> ), CATCH_INTERNAL_LINEINFO, Catch::StringRef(), Catch::NameAndTags{ Name " - " + std::string(tmpl_types[index / num_types]) + "<" + std::string(types_list[index % num_types]) + ">", Tags } ), index++, 0)... };/* NOLINT */\
|
||||
} \
|
||||
}; \
|
||||
static int INTERNAL_CATCH_UNIQUE_NAME( globalRegistrar ) = [](){ \
|
||||
using TestInit = Catch::combine<INTERNAL_CATCH_REMOVE_PARENS(TmplTypes)> \
|
||||
::with_types<INTERNAL_CATCH_MAKE_TYPE_LISTS_FROM_TYPES(TypesList)>::into<TestName>::type; \
|
||||
TestInit(); \
|
||||
return 0; \
|
||||
}(); \
|
||||
} \
|
||||
CATCH_INTERNAL_UNSUPPRESS_GLOBALS_WARNINGS \
|
||||
template<typename TestType> \
|
||||
static void TestFuncName()
|
||||
|
||||
#ifndef CATCH_CONFIG_TRADITIONAL_MSVC_PREPROCESSOR
|
||||
#define INTERNAL_CATCH_TEMPLATE_PRODUCT_TEST_CASE(Name, Tags, ...)\
|
||||
INTERNAL_CATCH_TEMPLATE_PRODUCT_TEST_CASE2(INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_M_P_L_A_T_E____T_E_S_T____ ), INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_M_P_L_A_T_E____T_E_S_T____F_U_N_C____ ),Name,Tags,__VA_ARGS__)
|
||||
#else
|
||||
#define INTERNAL_CATCH_TEMPLATE_PRODUCT_TEST_CASE(Name, Tags, ...)\
|
||||
INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_PRODUCT_TEST_CASE2( INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_M_P_L_A_T_E____T_E_S_T____ ), INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_M_P_L_A_T_E____T_E_S_T____F_U_N_C____ ), Name, Tags, __VA_ARGS__ ) )
|
||||
#endif
|
||||
|
||||
#define INTERNAL_CATCH_TEMPLATE_TEST_CASE_METHOD_2( TestNameClass, TestName, ClassName, Name, Tags, ... ) \
|
||||
CATCH_INTERNAL_SUPPRESS_GLOBALS_WARNINGS \
|
||||
namespace{ \
|
||||
@@ -180,4 +216,42 @@ struct AutoReg : NonCopyable {
|
||||
INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_TEST_CASE_METHOD_2( INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_M_P_L_A_T_E____T_E_S_T____C_L_A_S_S____ ), INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_M_P_L_A_T_E____T_E_S_T____ ) , ClassName, Name, Tags, __VA_ARGS__ ) )
|
||||
#endif
|
||||
|
||||
#define INTERNAL_CATCH_TEMPLATE_PRODUCT_TEST_CASE_METHOD_2(TestNameClass, TestName, ClassName, Name, Tags, TmplTypes, TypesList)\
|
||||
CATCH_INTERNAL_SUPPRESS_GLOBALS_WARNINGS \
|
||||
template<typename TestType> \
|
||||
struct TestName : INTERNAL_CATCH_REMOVE_PARENS(ClassName <TestType>) { \
|
||||
void test();\
|
||||
};\
|
||||
namespace {\
|
||||
template<typename...Types>\
|
||||
struct TestNameClass{\
|
||||
TestNameClass(){\
|
||||
CATCH_INTERNAL_CHECK_UNIQUE_TYPES(Types...)\
|
||||
int index = 0;\
|
||||
using expander = int[];\
|
||||
constexpr char const* tmpl_types[] = {CATCH_REC_LIST(INTERNAL_CATCH_STRINGIZE_WITHOUT_PARENS, INTERNAL_CATCH_REMOVE_PARENS(TmplTypes))};\
|
||||
constexpr char const* types_list[] = {CATCH_REC_LIST(INTERNAL_CATCH_STRINGIZE_WITHOUT_PARENS, INTERNAL_CATCH_REMOVE_PARENS(TypesList))};\
|
||||
constexpr auto num_types = sizeof(types_list) / sizeof(types_list[0]);\
|
||||
(void)expander{(Catch::AutoReg( Catch::makeTestInvoker( &TestName<Types>::test ), CATCH_INTERNAL_LINEINFO, #ClassName, Catch::NameAndTags{ Name " - " + std::string(tmpl_types[index / num_types]) + "<" + std::string(types_list[index % num_types]) + ">", Tags } ), index++, 0)... };/* NOLINT */ \
|
||||
}\
|
||||
};\
|
||||
static int INTERNAL_CATCH_UNIQUE_NAME( globalRegistrar ) = [](){\
|
||||
using TestInit = Catch::combine<INTERNAL_CATCH_REMOVE_PARENS(TmplTypes)>\
|
||||
::with_types<INTERNAL_CATCH_MAKE_TYPE_LISTS_FROM_TYPES(TypesList)>::into<TestNameClass>::type;\
|
||||
TestInit();\
|
||||
return 0;\
|
||||
}(); \
|
||||
}\
|
||||
CATCH_INTERNAL_UNSUPPRESS_GLOBALS_WARNINGS \
|
||||
template<typename TestType> \
|
||||
void TestName<TestType>::test()
|
||||
|
||||
#ifndef CATCH_CONFIG_TRADITIONAL_MSVC_PREPROCESSOR
|
||||
#define INTERNAL_CATCH_TEMPLATE_PRODUCT_TEST_CASE_METHOD( ClassName, Name, Tags, ... )\
|
||||
INTERNAL_CATCH_TEMPLATE_PRODUCT_TEST_CASE_METHOD_2( INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_M_P_L_A_T_E____T_E_S_T____ ), INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_M_P_L_A_T_E____T_E_S_T____F_U_N_C____ ), ClassName, Name, Tags, __VA_ARGS__ )
|
||||
#else
|
||||
#define INTERNAL_CATCH_TEMPLATE_PRODUCT_TEST_CASE_METHOD( ClassName, Name, Tags, ... )\
|
||||
INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_PRODUCT_TEST_CASE_METHOD_2( INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_M_P_L_A_T_E____T_E_S_T____ ), INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_M_P_L_A_T_E____T_E_S_T____F_U_N_C____ ), ClassName, Name, Tags, __VA_ARGS__ ) )
|
||||
#endif
|
||||
|
||||
#endif // TWOBLUECUBES_CATCH_TEST_REGISTRY_HPP_INCLUDED
|
||||
|
@@ -40,7 +40,7 @@ namespace Catch {
|
||||
// is terrible and we should move on.
|
||||
// TBD: How to signal that the measured resolution is probably wrong?
|
||||
if (ticks > startTime + 3 * nanosecondsInSecond) {
|
||||
return sum / i;
|
||||
return sum / ( i + 1u );
|
||||
}
|
||||
}
|
||||
|
||||
|
@@ -348,6 +348,7 @@ namespace Catch {
|
||||
# define CATCH_CONFIG_ENABLE_TUPLE_STRINGMAKER
|
||||
# define CATCH_CONFIG_ENABLE_VARIANT_STRINGMAKER
|
||||
# define CATCH_CONFIG_ENABLE_CHRONO_STRINGMAKER
|
||||
# define CATCH_CONFIG_ENABLE_OPTIONAL_STRINGMAKER
|
||||
#endif
|
||||
|
||||
// Separate std::pair specialization
|
||||
@@ -369,6 +370,24 @@ namespace Catch {
|
||||
}
|
||||
#endif // CATCH_CONFIG_ENABLE_PAIR_STRINGMAKER
|
||||
|
||||
#if defined(CATCH_CONFIG_ENABLE_OPTIONAL_STRINGMAKER) && defined(CATCH_CONFIG_CPP17_OPTIONAL)
|
||||
#include <optional>
|
||||
namespace Catch {
|
||||
template<typename T>
|
||||
struct StringMaker<std::optional<T> > {
|
||||
static std::string convert(const std::optional<T>& optional) {
|
||||
ReusableStringStream rss;
|
||||
if (optional.has_value()) {
|
||||
rss << ::Catch::Detail::stringify(*optional);
|
||||
} else {
|
||||
rss << "{ }";
|
||||
}
|
||||
return rss.str();
|
||||
}
|
||||
};
|
||||
}
|
||||
#endif // CATCH_CONFIG_ENABLE_OPTIONAL_STRINGMAKER
|
||||
|
||||
// Separate std::tuple specialization
|
||||
#if defined(CATCH_CONFIG_ENABLE_TUPLE_STRINGMAKER)
|
||||
#include <tuple>
|
||||
|
@@ -9,6 +9,8 @@
|
||||
#ifndef TWOBLUECUBES_CATCH_TYPE_TRAITS_HPP_INCLUDED
|
||||
#define TWOBLUECUBES_CATCH_TYPE_TRAITS_HPP_INCLUDED
|
||||
|
||||
#include <type_traits>
|
||||
|
||||
namespace Catch{
|
||||
|
||||
#ifdef CATCH_CPP17_OR_GREATER
|
||||
|
@@ -37,7 +37,7 @@ namespace Catch {
|
||||
}
|
||||
|
||||
Version const& libraryVersion() {
|
||||
static Version version( 2, 5, 0, "", 0 );
|
||||
static Version version( 2, 7, 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
|
||||
|
@@ -36,11 +36,25 @@ namespace Catch {
|
||||
#ifdef _MSC_VER
|
||||
sprintf_s(buffer, "%.3f", duration);
|
||||
#else
|
||||
sprintf(buffer, "%.3f", duration);
|
||||
std::sprintf(buffer, "%.3f", duration);
|
||||
#endif
|
||||
return std::string(buffer);
|
||||
}
|
||||
|
||||
std::string serializeFilters( std::vector<std::string> const& container ) {
|
||||
ReusableStringStream oss;
|
||||
bool first = true;
|
||||
for (auto&& filter : container)
|
||||
{
|
||||
if (!first)
|
||||
oss << ' ';
|
||||
else
|
||||
first = false;
|
||||
|
||||
oss << filter;
|
||||
}
|
||||
return oss.str();
|
||||
}
|
||||
|
||||
TestEventListenerBase::TestEventListenerBase(ReporterConfig const & _config)
|
||||
:StreamingReporterBase(_config) {}
|
||||
|
@@ -25,6 +25,8 @@ namespace Catch {
|
||||
// Returns double formatted as %.3f (format expected on output)
|
||||
std::string getFormattedDuration( double duration );
|
||||
|
||||
std::string serializeFilters( std::vector<std::string> const& container );
|
||||
|
||||
template<typename DerivedT>
|
||||
struct StreamingReporterBase : IStreamingReporter {
|
||||
|
||||
@@ -52,6 +54,7 @@ namespace Catch {
|
||||
void testRunStarting(TestRunInfo const& _testRunInfo) override {
|
||||
currentTestRunInfo = _testRunInfo;
|
||||
}
|
||||
|
||||
void testGroupStarting(GroupInfo const& _groupInfo) override {
|
||||
currentGroupInfo = _groupInfo;
|
||||
}
|
||||
|
@@ -245,7 +245,7 @@ public:
|
||||
case Unit::Nanoseconds:
|
||||
return "ns";
|
||||
case Unit::Microseconds:
|
||||
return "µs";
|
||||
return "us";
|
||||
case Unit::Milliseconds:
|
||||
return "ms";
|
||||
case Unit::Seconds:
|
||||
@@ -441,6 +441,10 @@ void ConsoleReporter::testRunEnded(TestRunStats const& _testRunStats) {
|
||||
stream << std::endl;
|
||||
StreamingReporterBase::testRunEnded(_testRunStats);
|
||||
}
|
||||
void ConsoleReporter::testRunStarting(TestRunInfo const& _testInfo) {
|
||||
StreamingReporterBase::testRunStarting(_testInfo);
|
||||
printTestFilters();
|
||||
}
|
||||
|
||||
void ConsoleReporter::lazyPrint() {
|
||||
|
||||
@@ -622,6 +626,11 @@ void ConsoleReporter::printSummaryDivider() {
|
||||
stream << getLineOfChars<'-'>() << '\n';
|
||||
}
|
||||
|
||||
void ConsoleReporter::printTestFilters() {
|
||||
if (m_config->testSpec().hasFilters())
|
||||
stream << Colour(Colour::BrightYellow) << "Filters: " << serializeFilters( m_config->getTestsOrTags() ) << '\n';
|
||||
}
|
||||
|
||||
CATCH_REGISTER_REPORTER("console", ConsoleReporter)
|
||||
|
||||
} // end namespace Catch
|
||||
|
@@ -46,7 +46,7 @@ namespace Catch {
|
||||
void testCaseEnded(TestCaseStats const& _testCaseStats) override;
|
||||
void testGroupEnded(TestGroupStats const& _testGroupStats) override;
|
||||
void testRunEnded(TestRunStats const& _testRunStats) override;
|
||||
|
||||
void testRunStarting(TestRunInfo const& _testRunInfo) override;
|
||||
private:
|
||||
|
||||
void lazyPrint();
|
||||
@@ -69,6 +69,7 @@ namespace Catch {
|
||||
|
||||
void printTotalsDivider(Totals const& totals);
|
||||
void printSummaryDivider();
|
||||
void printTestFilters();
|
||||
|
||||
private:
|
||||
bool m_headerPrinted = false;
|
||||
|
@@ -76,6 +76,22 @@ namespace Catch {
|
||||
void JunitReporter::testRunStarting( TestRunInfo const& runInfo ) {
|
||||
CumulativeReporterBase::testRunStarting( runInfo );
|
||||
xml.startElement( "testsuites" );
|
||||
|
||||
if ( m_config->hasTestFilters() || m_config->rngSeed() != 0 )
|
||||
xml.startElement("properties");
|
||||
|
||||
if ( m_config->hasTestFilters() ) {
|
||||
xml.scopedElement( "property" )
|
||||
.writeAttribute( "name" , "filters" )
|
||||
.writeAttribute( "value" , serializeFilters( m_config->getTestsOrTags() ) );
|
||||
}
|
||||
|
||||
if( m_config->rngSeed() != 0 ) {
|
||||
xml.scopedElement( "property" )
|
||||
.writeAttribute( "name", "random-seed" )
|
||||
.writeAttribute( "value", m_config->rngSeed() );
|
||||
xml.endElement();
|
||||
}
|
||||
}
|
||||
|
||||
void JunitReporter::testGroupStarting( GroupInfo const& groupInfo ) {
|
||||
|
@@ -42,9 +42,9 @@ namespace Catch {
|
||||
bool assertionEnded( AssertionStats const& _assertionStats ) override {
|
||||
++counter;
|
||||
|
||||
stream << "# " << currentTestCaseInfo->name << std::endl;
|
||||
AssertionPrinter printer( stream, _assertionStats, counter );
|
||||
printer.print();
|
||||
stream << " # " << currentTestCaseInfo->name ;
|
||||
|
||||
stream << std::endl;
|
||||
return true;
|
||||
|
@@ -55,6 +55,8 @@ namespace Catch {
|
||||
m_xml.startElement( "Catch" );
|
||||
if( !m_config->name().empty() )
|
||||
m_xml.writeAttribute( "name", m_config->name() );
|
||||
if (m_config->testSpec().hasFilters())
|
||||
m_xml.writeAttribute( "filters", serializeFilters( m_config->getTestsOrTags() ) );
|
||||
if( m_config->rngSeed() != 0 )
|
||||
m_xml.scopedElement( "Randomness" )
|
||||
.writeAttribute( "seed", m_config->rngSeed() );
|
||||
|
@@ -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 {
|
||||
|
@@ -19,7 +19,7 @@ set(TEST_SOURCES
|
||||
${SELF_TEST_DIR}/IntrospectiveTests/CmdLine.tests.cpp
|
||||
${SELF_TEST_DIR}/IntrospectiveTests/GeneratorsImpl.tests.cpp
|
||||
${SELF_TEST_DIR}/IntrospectiveTests/PartTracker.tests.cpp
|
||||
${SELF_TEST_DIR}/IntrospectiveTests/TagAlias.tests.cpp
|
||||
${SELF_TEST_DIR}/IntrospectiveTests/Tag.tests.cpp
|
||||
${SELF_TEST_DIR}/IntrospectiveTests/String.tests.cpp
|
||||
${SELF_TEST_DIR}/IntrospectiveTests/Xml.tests.cpp
|
||||
${SELF_TEST_DIR}/UsageTests/Approx.tests.cpp
|
||||
@@ -36,6 +36,7 @@ set(TEST_SOURCES
|
||||
${SELF_TEST_DIR}/UsageTests/Misc.tests.cpp
|
||||
${SELF_TEST_DIR}/UsageTests/ToStringChrono.tests.cpp
|
||||
${SELF_TEST_DIR}/UsageTests/ToStringGeneral.tests.cpp
|
||||
${SELF_TEST_DIR}/UsageTests/ToStringOptional.tests.cpp
|
||||
${SELF_TEST_DIR}/UsageTests/ToStringPair.tests.cpp
|
||||
${SELF_TEST_DIR}/UsageTests/ToStringTuple.tests.cpp
|
||||
${SELF_TEST_DIR}/UsageTests/ToStringVariant.tests.cpp
|
||||
@@ -101,6 +102,8 @@ set(INTERNAL_HEADERS
|
||||
${HEADER_DIR}/internal/catch_external_interfaces.h
|
||||
${HEADER_DIR}/internal/catch_fatal_condition.h
|
||||
${HEADER_DIR}/internal/catch_generators.hpp
|
||||
${HEADER_DIR}/internal/catch_generators_generic.hpp
|
||||
${HEADER_DIR}/internal/catch_generators_specific.hpp
|
||||
${HEADER_DIR}/internal/catch_impl.hpp
|
||||
${HEADER_DIR}/internal/catch_interfaces_capture.h
|
||||
${HEADER_DIR}/internal/catch_interfaces_config.h
|
||||
@@ -118,6 +121,7 @@ set(INTERNAL_HEADERS
|
||||
${HEADER_DIR}/internal/catch_matchers_string.h
|
||||
${HEADER_DIR}/internal/catch_matchers_vector.h
|
||||
${HEADER_DIR}/internal/catch_message.h
|
||||
${HEADER_DIR}/internal/catch_meta.hpp
|
||||
${HEADER_DIR}/internal/catch_objc.hpp
|
||||
${HEADER_DIR}/internal/catch_objc_arc.hpp
|
||||
${HEADER_DIR}/internal/catch_option.hpp
|
||||
@@ -344,10 +348,16 @@ set_tests_properties(NoAssertions PROPERTIES PASS_REGULAR_EXPRESSION "No asserti
|
||||
add_test(NAME NoTest COMMAND $<TARGET_FILE:SelfTest> -w NoTests "___nonexistent_test___")
|
||||
set_tests_properties(NoTest PROPERTIES PASS_REGULAR_EXPRESSION "No test cases matched")
|
||||
|
||||
add_test(NAME FilteredSection-1 COMMAND $<TARGET_FILE:SelfTest> \#1394 -c RunSection)
|
||||
set_tests_properties(FilteredSection-1 PROPERTIES FAIL_REGULAR_EXPRESSION "No tests ran")
|
||||
add_test(NAME FilteredSection-2 COMMAND $<TARGET_FILE:SelfTest> \#1394\ nested -c NestedRunSection -c s1)
|
||||
set_tests_properties(FilteredSection-2 PROPERTIES FAIL_REGULAR_EXPRESSION "No tests ran")
|
||||
|
||||
# AppVeyor has a Python 2.7 in path, but doesn't have .py files as autorunnable
|
||||
add_test(NAME ApprovalTests COMMAND ${PYTHON_EXECUTABLE} ${CATCH_DIR}/scripts/approvalTests.py $<TARGET_FILE:SelfTest>)
|
||||
set_tests_properties(ApprovalTests PROPERTIES FAIL_REGULAR_EXPRESSION "Results differed")
|
||||
|
||||
|
||||
if (CATCH_USE_VALGRIND)
|
||||
add_test(NAME ValgrindRunTests COMMAND valgrind --leak-check=full --error-exitcode=1 $<TARGET_FILE:SelfTest>)
|
||||
add_test(NAME ValgrindListTests COMMAND valgrind --leak-check=full --error-exitcode=1 $<TARGET_FILE:SelfTest> --list-tests --verbosity high)
|
||||
|
@@ -14,6 +14,10 @@ Compilation.tests.cpp:<line number>: passed: std::memcmp(uarr, "123", sizeof(uar
|
||||
Compilation.tests.cpp:<line number>: passed: std::memcmp(sarr, "456", sizeof(sarr)) == 0 for: 0 == 0 with 2 messages: 'uarr := "123"' and 'sarr := "456"'
|
||||
Compilation.tests.cpp:<line number>: passed:
|
||||
Compilation.tests.cpp:<line number>: passed: h1 == h2 for: [1403 helper] == [1403 helper]
|
||||
This would not be caught previously
|
||||
Nor would this
|
||||
Tricky.tests.cpp:<line number>: failed: explicitly with 1 message: '1514'
|
||||
Compilation.tests.cpp:<line number>: passed: std::is_same<TypeList<int>, TypeList<int>>::value for: true
|
||||
Exception.tests.cpp:<line number>: failed: unexpected exception with message: 'answer := 42' with 1 message: 'expected exception'
|
||||
Exception.tests.cpp:<line number>: failed: unexpected exception with message: 'answer := 42'; expression was: thisThrows() with 1 message: 'expected exception'
|
||||
Exception.tests.cpp:<line number>: passed: thisThrows() with 1 message: 'answer := 42'
|
||||
@@ -57,108 +61,97 @@ Tricky.tests.cpp:<line number>: passed: !is_true<false>::value for: true
|
||||
Tricky.tests.cpp:<line number>: passed: !!is_true<true>::value for: true
|
||||
Tricky.tests.cpp:<line number>: passed: is_true<true>::value for: true
|
||||
Tricky.tests.cpp:<line number>: passed: !(is_true<false>::value) for: !false
|
||||
Generators.tests.cpp:<line number>: passed: x < y for: 1 < 101
|
||||
Generators.tests.cpp:<line number>: passed: x < y for: 1 < 102
|
||||
Generators.tests.cpp:<line number>: passed: x < y for: 1 < 103
|
||||
Generators.tests.cpp:<line number>: passed: x < y for: 1 < 104
|
||||
Generators.tests.cpp:<line number>: passed: x < y for: 1 < 105
|
||||
Generators.tests.cpp:<line number>: passed: x < y for: 1 < 106
|
||||
Generators.tests.cpp:<line number>: passed: x < y for: 1 < 107
|
||||
Generators.tests.cpp:<line number>: passed: x < y for: 1 < 108
|
||||
Generators.tests.cpp:<line number>: passed: x < y for: 1 < 109
|
||||
Generators.tests.cpp:<line number>: passed: x < y for: 1 < 110
|
||||
Generators.tests.cpp:<line number>: passed: x < y for: 2 < 101
|
||||
Generators.tests.cpp:<line number>: passed: x < y for: 2 < 102
|
||||
Generators.tests.cpp:<line number>: passed: x < y for: 2 < 103
|
||||
Generators.tests.cpp:<line number>: passed: x < y for: 2 < 104
|
||||
Generators.tests.cpp:<line number>: passed: x < y for: 2 < 105
|
||||
Generators.tests.cpp:<line number>: passed: x < y for: 2 < 106
|
||||
Generators.tests.cpp:<line number>: passed: x < y for: 2 < 107
|
||||
Generators.tests.cpp:<line number>: passed: x < y for: 2 < 108
|
||||
Generators.tests.cpp:<line number>: passed: x < y for: 2 < 109
|
||||
Generators.tests.cpp:<line number>: passed: x < y for: 2 < 110
|
||||
Generators.tests.cpp:<line number>: passed: x < y for: 3 < 101
|
||||
Generators.tests.cpp:<line number>: passed: x < y for: 3 < 102
|
||||
Generators.tests.cpp:<line number>: passed: x < y for: 3 < 103
|
||||
Generators.tests.cpp:<line number>: passed: x < y for: 3 < 104
|
||||
Generators.tests.cpp:<line number>: passed: x < y for: 3 < 105
|
||||
Generators.tests.cpp:<line number>: passed: x < y for: 3 < 106
|
||||
Generators.tests.cpp:<line number>: passed: x < y for: 3 < 107
|
||||
Generators.tests.cpp:<line number>: passed: x < y for: 3 < 108
|
||||
Generators.tests.cpp:<line number>: passed: x < y for: 3 < 109
|
||||
Generators.tests.cpp:<line number>: passed: x < y for: 3 < 110
|
||||
Generators.tests.cpp:<line number>: passed: x < y for: 4 < 101
|
||||
Generators.tests.cpp:<line number>: passed: x < y for: 4 < 102
|
||||
Generators.tests.cpp:<line number>: passed: x < y for: 4 < 103
|
||||
Generators.tests.cpp:<line number>: passed: x < y for: 4 < 104
|
||||
Generators.tests.cpp:<line number>: passed: x < y for: 4 < 105
|
||||
Generators.tests.cpp:<line number>: passed: x < y for: 4 < 106
|
||||
Generators.tests.cpp:<line number>: passed: x < y for: 4 < 107
|
||||
Generators.tests.cpp:<line number>: passed: x < y for: 4 < 108
|
||||
Generators.tests.cpp:<line number>: passed: x < y for: 4 < 109
|
||||
Generators.tests.cpp:<line number>: passed: x < y for: 4 < 110
|
||||
Generators.tests.cpp:<line number>: passed: x < y for: 5 < 101
|
||||
Generators.tests.cpp:<line number>: passed: x < y for: 5 < 102
|
||||
Generators.tests.cpp:<line number>: passed: x < y for: 5 < 103
|
||||
Generators.tests.cpp:<line number>: passed: x < y for: 5 < 104
|
||||
Generators.tests.cpp:<line number>: passed: x < y for: 5 < 105
|
||||
Generators.tests.cpp:<line number>: passed: x < y for: 5 < 106
|
||||
Generators.tests.cpp:<line number>: passed: x < y for: 5 < 107
|
||||
Generators.tests.cpp:<line number>: passed: x < y for: 5 < 108
|
||||
Generators.tests.cpp:<line number>: passed: x < y for: 5 < 109
|
||||
Generators.tests.cpp:<line number>: passed: x < y for: 5 < 110
|
||||
Generators.tests.cpp:<line number>: passed: x < y for: 6 < 101
|
||||
Generators.tests.cpp:<line number>: passed: x < y for: 6 < 102
|
||||
Generators.tests.cpp:<line number>: passed: x < y for: 6 < 103
|
||||
Generators.tests.cpp:<line number>: passed: x < y for: 6 < 104
|
||||
Generators.tests.cpp:<line number>: passed: x < y for: 6 < 105
|
||||
Generators.tests.cpp:<line number>: passed: x < y for: 6 < 106
|
||||
Generators.tests.cpp:<line number>: passed: x < y for: 6 < 107
|
||||
Generators.tests.cpp:<line number>: passed: x < y for: 6 < 108
|
||||
Generators.tests.cpp:<line number>: passed: x < y for: 6 < 109
|
||||
Generators.tests.cpp:<line number>: passed: x < y for: 6 < 110
|
||||
Generators.tests.cpp:<line number>: passed: x < y for: 7 < 101
|
||||
Generators.tests.cpp:<line number>: passed: x < y for: 7 < 102
|
||||
Generators.tests.cpp:<line number>: passed: x < y for: 7 < 103
|
||||
Generators.tests.cpp:<line number>: passed: x < y for: 7 < 104
|
||||
Generators.tests.cpp:<line number>: passed: x < y for: 7 < 105
|
||||
Generators.tests.cpp:<line number>: passed: x < y for: 7 < 106
|
||||
Generators.tests.cpp:<line number>: passed: x < y for: 7 < 107
|
||||
Generators.tests.cpp:<line number>: passed: x < y for: 7 < 108
|
||||
Generators.tests.cpp:<line number>: passed: x < y for: 7 < 109
|
||||
Generators.tests.cpp:<line number>: passed: x < y for: 7 < 110
|
||||
Generators.tests.cpp:<line number>: passed: x < y for: 8 < 101
|
||||
Generators.tests.cpp:<line number>: passed: x < y for: 8 < 102
|
||||
Generators.tests.cpp:<line number>: passed: x < y for: 8 < 103
|
||||
Generators.tests.cpp:<line number>: passed: x < y for: 8 < 104
|
||||
Generators.tests.cpp:<line number>: passed: x < y for: 8 < 105
|
||||
Generators.tests.cpp:<line number>: passed: x < y for: 8 < 106
|
||||
Generators.tests.cpp:<line number>: passed: x < y for: 8 < 107
|
||||
Generators.tests.cpp:<line number>: passed: x < y for: 8 < 108
|
||||
Generators.tests.cpp:<line number>: passed: x < y for: 8 < 109
|
||||
Generators.tests.cpp:<line number>: passed: x < y for: 8 < 110
|
||||
Generators.tests.cpp:<line number>: passed: x < y for: 9 < 101
|
||||
Generators.tests.cpp:<line number>: passed: x < y for: 9 < 102
|
||||
Generators.tests.cpp:<line number>: passed: x < y for: 9 < 103
|
||||
Generators.tests.cpp:<line number>: passed: x < y for: 9 < 104
|
||||
Generators.tests.cpp:<line number>: passed: x < y for: 9 < 105
|
||||
Generators.tests.cpp:<line number>: passed: x < y for: 9 < 106
|
||||
Generators.tests.cpp:<line number>: passed: x < y for: 9 < 107
|
||||
Generators.tests.cpp:<line number>: passed: x < y for: 9 < 108
|
||||
Generators.tests.cpp:<line number>: passed: x < y for: 9 < 109
|
||||
Generators.tests.cpp:<line number>: passed: x < y for: 9 < 110
|
||||
Generators.tests.cpp:<line number>: passed: x < y for: 10 < 101
|
||||
Generators.tests.cpp:<line number>: passed: x < y for: 10 < 102
|
||||
Generators.tests.cpp:<line number>: passed: x < y for: 10 < 103
|
||||
Generators.tests.cpp:<line number>: passed: x < y for: 10 < 104
|
||||
Generators.tests.cpp:<line number>: passed: x < y for: 10 < 105
|
||||
Generators.tests.cpp:<line number>: passed: x < y for: 10 < 106
|
||||
Generators.tests.cpp:<line number>: passed: x < y for: 10 < 107
|
||||
Generators.tests.cpp:<line number>: passed: x < y for: 10 < 108
|
||||
Generators.tests.cpp:<line number>: passed: x < y for: 10 < 109
|
||||
Generators.tests.cpp:<line number>: passed: x < y for: 10 < 110
|
||||
Generators.tests.cpp:<line number>: passed: x < y for: 1 < 4
|
||||
Generators.tests.cpp:<line number>: passed: y < z for: 4 < 7
|
||||
Generators.tests.cpp:<line number>: passed: x < z for: 1 < 7
|
||||
Generators.tests.cpp:<line number>: passed: x < y for: 1 < 4
|
||||
Generators.tests.cpp:<line number>: passed: y < z for: 4 < 8
|
||||
Generators.tests.cpp:<line number>: passed: x < z for: 1 < 8
|
||||
Generators.tests.cpp:<line number>: passed: x < y for: 1 < 4
|
||||
Generators.tests.cpp:<line number>: passed: y < z for: 4 < 9
|
||||
Generators.tests.cpp:<line number>: passed: x < z for: 1 < 9
|
||||
Generators.tests.cpp:<line number>: passed: x < y for: 1 < 5
|
||||
Generators.tests.cpp:<line number>: passed: y < z for: 5 < 7
|
||||
Generators.tests.cpp:<line number>: passed: x < z for: 1 < 7
|
||||
Generators.tests.cpp:<line number>: passed: x < y for: 1 < 5
|
||||
Generators.tests.cpp:<line number>: passed: y < z for: 5 < 8
|
||||
Generators.tests.cpp:<line number>: passed: x < z for: 1 < 8
|
||||
Generators.tests.cpp:<line number>: passed: x < y for: 1 < 5
|
||||
Generators.tests.cpp:<line number>: passed: y < z for: 5 < 9
|
||||
Generators.tests.cpp:<line number>: passed: x < z for: 1 < 9
|
||||
Generators.tests.cpp:<line number>: passed: x < y for: 1 < 6
|
||||
Generators.tests.cpp:<line number>: passed: y < z for: 6 < 7
|
||||
Generators.tests.cpp:<line number>: passed: x < z for: 1 < 7
|
||||
Generators.tests.cpp:<line number>: passed: x < y for: 1 < 6
|
||||
Generators.tests.cpp:<line number>: passed: y < z for: 6 < 8
|
||||
Generators.tests.cpp:<line number>: passed: x < z for: 1 < 8
|
||||
Generators.tests.cpp:<line number>: passed: x < y for: 1 < 6
|
||||
Generators.tests.cpp:<line number>: passed: y < z for: 6 < 9
|
||||
Generators.tests.cpp:<line number>: passed: x < z for: 1 < 9
|
||||
Generators.tests.cpp:<line number>: passed: x < y for: 2 < 4
|
||||
Generators.tests.cpp:<line number>: passed: y < z for: 4 < 7
|
||||
Generators.tests.cpp:<line number>: passed: x < z for: 2 < 7
|
||||
Generators.tests.cpp:<line number>: passed: x < y for: 2 < 4
|
||||
Generators.tests.cpp:<line number>: passed: y < z for: 4 < 8
|
||||
Generators.tests.cpp:<line number>: passed: x < z for: 2 < 8
|
||||
Generators.tests.cpp:<line number>: passed: x < y for: 2 < 4
|
||||
Generators.tests.cpp:<line number>: passed: y < z for: 4 < 9
|
||||
Generators.tests.cpp:<line number>: passed: x < z for: 2 < 9
|
||||
Generators.tests.cpp:<line number>: passed: x < y for: 2 < 5
|
||||
Generators.tests.cpp:<line number>: passed: y < z for: 5 < 7
|
||||
Generators.tests.cpp:<line number>: passed: x < z for: 2 < 7
|
||||
Generators.tests.cpp:<line number>: passed: x < y for: 2 < 5
|
||||
Generators.tests.cpp:<line number>: passed: y < z for: 5 < 8
|
||||
Generators.tests.cpp:<line number>: passed: x < z for: 2 < 8
|
||||
Generators.tests.cpp:<line number>: passed: x < y for: 2 < 5
|
||||
Generators.tests.cpp:<line number>: passed: y < z for: 5 < 9
|
||||
Generators.tests.cpp:<line number>: passed: x < z for: 2 < 9
|
||||
Generators.tests.cpp:<line number>: passed: x < y for: 2 < 6
|
||||
Generators.tests.cpp:<line number>: passed: y < z for: 6 < 7
|
||||
Generators.tests.cpp:<line number>: passed: x < z for: 2 < 7
|
||||
Generators.tests.cpp:<line number>: passed: x < y for: 2 < 6
|
||||
Generators.tests.cpp:<line number>: passed: y < z for: 6 < 8
|
||||
Generators.tests.cpp:<line number>: passed: x < z for: 2 < 8
|
||||
Generators.tests.cpp:<line number>: passed: x < y for: 2 < 6
|
||||
Generators.tests.cpp:<line number>: passed: y < z for: 6 < 9
|
||||
Generators.tests.cpp:<line number>: passed: x < z for: 2 < 9
|
||||
Generators.tests.cpp:<line number>: passed: x < y for: 3 < 4
|
||||
Generators.tests.cpp:<line number>: passed: y < z for: 4 < 7
|
||||
Generators.tests.cpp:<line number>: passed: x < z for: 3 < 7
|
||||
Generators.tests.cpp:<line number>: passed: x < y for: 3 < 4
|
||||
Generators.tests.cpp:<line number>: passed: y < z for: 4 < 8
|
||||
Generators.tests.cpp:<line number>: passed: x < z for: 3 < 8
|
||||
Generators.tests.cpp:<line number>: passed: x < y for: 3 < 4
|
||||
Generators.tests.cpp:<line number>: passed: y < z for: 4 < 9
|
||||
Generators.tests.cpp:<line number>: passed: x < z for: 3 < 9
|
||||
Generators.tests.cpp:<line number>: passed: x < y for: 3 < 5
|
||||
Generators.tests.cpp:<line number>: passed: y < z for: 5 < 7
|
||||
Generators.tests.cpp:<line number>: passed: x < z for: 3 < 7
|
||||
Generators.tests.cpp:<line number>: passed: x < y for: 3 < 5
|
||||
Generators.tests.cpp:<line number>: passed: y < z for: 5 < 8
|
||||
Generators.tests.cpp:<line number>: passed: x < z for: 3 < 8
|
||||
Generators.tests.cpp:<line number>: passed: x < y for: 3 < 5
|
||||
Generators.tests.cpp:<line number>: passed: y < z for: 5 < 9
|
||||
Generators.tests.cpp:<line number>: passed: x < z for: 3 < 9
|
||||
Generators.tests.cpp:<line number>: passed: x < y for: 3 < 6
|
||||
Generators.tests.cpp:<line number>: passed: y < z for: 6 < 7
|
||||
Generators.tests.cpp:<line number>: passed: x < z for: 3 < 7
|
||||
Generators.tests.cpp:<line number>: passed: x < y for: 3 < 6
|
||||
Generators.tests.cpp:<line number>: passed: y < z for: 6 < 8
|
||||
Generators.tests.cpp:<line number>: passed: x < z for: 3 < 8
|
||||
Generators.tests.cpp:<line number>: passed: x < y for: 3 < 6
|
||||
Generators.tests.cpp:<line number>: passed: y < z for: 6 < 9
|
||||
Generators.tests.cpp:<line number>: passed: x < z for: 3 < 9
|
||||
Class.tests.cpp:<line number>: failed: s == "world" for: "hello" == "world"
|
||||
Class.tests.cpp:<line number>: passed: s == "hello" for: "hello" == "hello"
|
||||
Class.tests.cpp:<line number>: failed: Template_Fixture_2<TestType>::m_a.size() == 1 for: 0 == 1
|
||||
Class.tests.cpp:<line number>: failed: Template_Fixture_2<TestType>::m_a.size() == 1 for: 0 == 1
|
||||
Class.tests.cpp:<line number>: failed: Template_Fixture_2<TestType>::m_a.size() == 1 for: 0 == 1
|
||||
Class.tests.cpp:<line number>: failed: Template_Fixture_2<TestType>::m_a.size() == 1 for: 0 == 1
|
||||
Class.tests.cpp:<line number>: passed: Template_Fixture_2<TestType>::m_a.size() == 0 for: 0 == 0
|
||||
Class.tests.cpp:<line number>: passed: Template_Fixture_2<TestType>::m_a.size() == 0 for: 0 == 0
|
||||
Class.tests.cpp:<line number>: passed: Template_Fixture_2<TestType>::m_a.size() == 0 for: 0 == 0
|
||||
Class.tests.cpp:<line number>: passed: Template_Fixture_2<TestType>::m_a.size() == 0 for: 0 == 0
|
||||
Class.tests.cpp:<line number>: failed: Template_Fixture<TestType>::m_a == 2 for: 1.0 == 2
|
||||
Class.tests.cpp:<line number>: failed: Template_Fixture<TestType>::m_a == 2 for: 1.0f == 2
|
||||
Class.tests.cpp:<line number>: failed: Template_Fixture<TestType>::m_a == 2 for: 1 == 2
|
||||
@@ -167,6 +160,10 @@ Class.tests.cpp:<line number>: passed: Template_Fixture<TestType>::m_a == 1 for:
|
||||
Class.tests.cpp:<line number>: passed: Template_Fixture<TestType>::m_a == 1 for: 1 == 1
|
||||
Class.tests.cpp:<line number>: failed: m_a == 2 for: 1 == 2
|
||||
Class.tests.cpp:<line number>: passed: m_a == 1 for: 1 == 1
|
||||
Misc.tests.cpp:<line number>: passed: x.size() == 0 for: 0 == 0
|
||||
Misc.tests.cpp:<line number>: passed: x.size() == 0 for: 0 == 0
|
||||
Misc.tests.cpp:<line number>: passed: x.size() == 0 for: 0 == 0
|
||||
Misc.tests.cpp:<line number>: passed: x.size() == 0 for: 0 == 0
|
||||
Approx.tests.cpp:<line number>: passed: d == 1.23_a for: 1.23 == Approx( 1.23 )
|
||||
Approx.tests.cpp:<line number>: passed: d != 1.22_a for: 1.23 != Approx( 1.22 )
|
||||
Approx.tests.cpp:<line number>: passed: -d == -1.23_a for: -1.23 == Approx( -1.23 )
|
||||
@@ -406,48 +403,189 @@ Matchers.tests.cpp:<line number>: passed: WithinAbs(1.f, 0.f)
|
||||
Matchers.tests.cpp:<line number>: passed: WithinAbs(1.f, -1.f), std::domain_error
|
||||
Matchers.tests.cpp:<line number>: passed: WithinULP(1.f, 0)
|
||||
Matchers.tests.cpp:<line number>: passed: WithinULP(1.f, -1), std::domain_error
|
||||
Generators.tests.cpp:<line number>: passed: with 2 messages: 'i := "a"' and 'j := 8'
|
||||
Generators.tests.cpp:<line number>: passed: with 2 messages: 'i := "a"' and 'j := 9'
|
||||
Generators.tests.cpp:<line number>: passed: with 2 messages: 'i := "a"' and 'j := 10'
|
||||
Generators.tests.cpp:<line number>: passed: with 2 messages: 'i := "a"' and 'j := 2'
|
||||
Generators.tests.cpp:<line number>: passed: with 2 messages: 'i := "a"' and 'j := 3.141'
|
||||
Generators.tests.cpp:<line number>: passed: with 2 messages: 'i := "a"' and 'j := 1.379'
|
||||
Generators.tests.cpp:<line number>: passed: with 2 messages: 'i := "b"' and 'j := 8'
|
||||
Generators.tests.cpp:<line number>: passed: with 2 messages: 'i := "b"' and 'j := 9'
|
||||
Generators.tests.cpp:<line number>: passed: with 2 messages: 'i := "b"' and 'j := 10'
|
||||
Generators.tests.cpp:<line number>: passed: with 2 messages: 'i := "b"' and 'j := 2'
|
||||
Generators.tests.cpp:<line number>: passed: with 2 messages: 'i := "b"' and 'j := 3.141'
|
||||
Generators.tests.cpp:<line number>: passed: with 2 messages: 'i := "b"' and 'j := 1.379'
|
||||
Generators.tests.cpp:<line number>: passed: with 2 messages: 'i := "c"' and 'j := 8'
|
||||
Generators.tests.cpp:<line number>: passed: with 2 messages: 'i := "c"' and 'j := 9'
|
||||
Generators.tests.cpp:<line number>: passed: with 2 messages: 'i := "c"' and 'j := 10'
|
||||
Generators.tests.cpp:<line number>: passed: with 2 messages: 'i := "c"' and 'j := 2'
|
||||
Generators.tests.cpp:<line number>: passed: with 2 messages: 'i := "c"' and 'j := 3.141'
|
||||
Generators.tests.cpp:<line number>: passed: with 2 messages: 'i := "c"' and 'j := 1.379'
|
||||
GeneratorsImpl.tests.cpp:<line number>: passed: gen.size() == 2 for: 2 == 2
|
||||
GeneratorsImpl.tests.cpp:<line number>: passed: gen[0] == 1 for: 1 == 1
|
||||
GeneratorsImpl.tests.cpp:<line number>: passed: gen[1] == 2 for: 2 == 2
|
||||
GeneratorsImpl.tests.cpp:<line number>: passed: gen.size() == 4 for: 4 == 4
|
||||
GeneratorsImpl.tests.cpp:<line number>: passed: gen[0] == 3 for: 3 == 3
|
||||
GeneratorsImpl.tests.cpp:<line number>: passed: gen[1] == 1 for: 1 == 1
|
||||
GeneratorsImpl.tests.cpp:<line number>: passed: gen[2] == 4 for: 4 == 4
|
||||
GeneratorsImpl.tests.cpp:<line number>: passed: gen[3] == 1 for: 1 == 1
|
||||
GeneratorsImpl.tests.cpp:<line number>: passed: gen.size() == 4 for: 4 == 4
|
||||
GeneratorsImpl.tests.cpp:<line number>: passed: gen[0] == 1 for: 1 == 1
|
||||
GeneratorsImpl.tests.cpp:<line number>: passed: gen[1] == 2 for: 2 == 2
|
||||
GeneratorsImpl.tests.cpp:<line number>: passed: gen[2] == 9 for: 9 == 9
|
||||
GeneratorsImpl.tests.cpp:<line number>: passed: gen[3] == 7 for: 7 == 7
|
||||
GeneratorsImpl.tests.cpp:<line number>: passed: gen.size() == 2 for: 2 == 2
|
||||
GeneratorsImpl.tests.cpp:<line number>: passed: gen[0] == 3 for: 3 == 3
|
||||
GeneratorsImpl.tests.cpp:<line number>: passed: gen[1] == 1 for: 1 == 1
|
||||
GeneratorsImpl.tests.cpp:<line number>: passed: gen.size() == 2 for: 2 == 2
|
||||
GeneratorsImpl.tests.cpp:<line number>: passed: gen[0] == 3 for: 3 == 3
|
||||
GeneratorsImpl.tests.cpp:<line number>: passed: gen[1] == 1 for: 1 == 1
|
||||
GeneratorsImpl.tests.cpp:<line number>: passed: base->size() == 4 for: 4 == 4
|
||||
GeneratorsImpl.tests.cpp:<line number>: passed: typed for: 0x<hex digits>
|
||||
GeneratorsImpl.tests.cpp:<line number>: passed: typed->size() == 4 for: 4 == 4
|
||||
GeneratorsImpl.tests.cpp:<line number>: passed: (*typed)[0] == 7 for: 7 == 7
|
||||
GeneratorsImpl.tests.cpp:<line number>: passed: (*typed)[3] == 11 for: 11 == 11
|
||||
Generators.tests.cpp:<line number>: passed: i % 2 == 0 for: 0 == 0
|
||||
Generators.tests.cpp:<line number>: passed: i % 2 == 0 for: 0 == 0
|
||||
Generators.tests.cpp:<line number>: passed: i % 2 == 0 for: 0 == 0
|
||||
Generators.tests.cpp:<line number>: passed: filter([] (int) {return false; }, value(1)), Catch::GeneratorException
|
||||
Generators.tests.cpp:<line number>: passed: i < 4 for: 1 < 4
|
||||
Generators.tests.cpp:<line number>: passed: i < 4 for: 2 < 4
|
||||
Generators.tests.cpp:<line number>: passed: i < 4 for: 3 < 4
|
||||
Generators.tests.cpp:<line number>: passed: i % 2 == 0 for: 0 == 0
|
||||
Generators.tests.cpp:<line number>: passed: i % 2 == 0 for: 0 == 0
|
||||
Generators.tests.cpp:<line number>: passed: i % 2 == 0 for: 0 == 0
|
||||
Generators.tests.cpp:<line number>: passed: i.size() == 1 for: 1 == 1
|
||||
Generators.tests.cpp:<line number>: passed: i.size() == 1 for: 1 == 1
|
||||
Generators.tests.cpp:<line number>: passed: i.size() == 1 for: 1 == 1
|
||||
Generators.tests.cpp:<line number>: passed: i.size() == 1 for: 1 == 1
|
||||
Generators.tests.cpp:<line number>: passed: i.size() == 1 for: 1 == 1
|
||||
Generators.tests.cpp:<line number>: passed: i.size() == 1 for: 1 == 1
|
||||
Generators.tests.cpp:<line number>: passed: j > 0 for: 1 > 0
|
||||
Generators.tests.cpp:<line number>: passed: j > 0 for: 2 > 0
|
||||
Generators.tests.cpp:<line number>: passed: j > 0 for: 3 > 0
|
||||
Generators.tests.cpp:<line number>: passed: j > 0 for: 1 > 0
|
||||
Generators.tests.cpp:<line number>: passed: j > 0 for: 2 > 0
|
||||
Generators.tests.cpp:<line number>: passed: j > 0 for: 3 > 0
|
||||
Generators.tests.cpp:<line number>: passed: chunk2.size() == 2 for: 2 == 2
|
||||
Generators.tests.cpp:<line number>: passed: chunk2.front() == chunk2.back() for: 1 == 1
|
||||
Generators.tests.cpp:<line number>: passed: chunk2.size() == 2 for: 2 == 2
|
||||
Generators.tests.cpp:<line number>: passed: chunk2.front() == chunk2.back() for: 2 == 2
|
||||
Generators.tests.cpp:<line number>: passed: chunk2.size() == 2 for: 2 == 2
|
||||
Generators.tests.cpp:<line number>: passed: chunk2.front() == chunk2.back() for: 3 == 3
|
||||
Generators.tests.cpp:<line number>: passed: chunk2.size() == 2 for: 2 == 2
|
||||
Generators.tests.cpp:<line number>: passed: chunk2.front() == chunk2.back() for: 1 == 1
|
||||
Generators.tests.cpp:<line number>: passed: chunk2.front() < 3 for: 1 < 3
|
||||
Generators.tests.cpp:<line number>: passed: chunk2.size() == 2 for: 2 == 2
|
||||
Generators.tests.cpp:<line number>: passed: chunk2.front() == chunk2.back() for: 2 == 2
|
||||
Generators.tests.cpp:<line number>: passed: chunk2.front() < 3 for: 2 < 3
|
||||
Generators.tests.cpp:<line number>: passed: chunk(2, value(1)), Catch::GeneratorException
|
||||
Generators.tests.cpp:<line number>: passed: j < i for: -3 < 1
|
||||
Generators.tests.cpp:<line number>: passed: j < i for: -2 < 1
|
||||
Generators.tests.cpp:<line number>: passed: j < i for: -1 < 1
|
||||
Generators.tests.cpp:<line number>: passed: 4u * i > str.size() for: 4 > 1
|
||||
Generators.tests.cpp:<line number>: passed: 4u * i > str.size() for: 4 > 2
|
||||
Generators.tests.cpp:<line number>: passed: 4u * i > str.size() for: 4 > 3
|
||||
Generators.tests.cpp:<line number>: passed: j < i for: -3 < 2
|
||||
Generators.tests.cpp:<line number>: passed: j < i for: -2 < 2
|
||||
Generators.tests.cpp:<line number>: passed: j < i for: -1 < 2
|
||||
Generators.tests.cpp:<line number>: passed: 4u * i > str.size() for: 8 > 1
|
||||
Generators.tests.cpp:<line number>: passed: 4u * i > str.size() for: 8 > 2
|
||||
Generators.tests.cpp:<line number>: passed: 4u * i > str.size() for: 8 > 3
|
||||
Generators.tests.cpp:<line number>: passed: j < i for: -3 < 3
|
||||
Generators.tests.cpp:<line number>: passed: j < i for: -2 < 3
|
||||
Generators.tests.cpp:<line number>: passed: j < i for: -1 < 3
|
||||
Generators.tests.cpp:<line number>: passed: 4u * i > str.size() for: 12 > 1
|
||||
Generators.tests.cpp:<line number>: passed: 4u * i > str.size() for: 12 > 2
|
||||
Generators.tests.cpp:<line number>: passed: 4u * i > str.size() for: 12 > 3
|
||||
GeneratorsImpl.tests.cpp:<line number>: passed: gen.get() == 123 for: 123 == 123
|
||||
GeneratorsImpl.tests.cpp:<line number>: passed: !(gen.next()) for: !false
|
||||
GeneratorsImpl.tests.cpp:<line number>: passed: gen.get() == 1 for: 1 == 1
|
||||
GeneratorsImpl.tests.cpp:<line number>: passed: gen.next() for: true
|
||||
GeneratorsImpl.tests.cpp:<line number>: passed: gen.get() == 3 for: 3 == 3
|
||||
GeneratorsImpl.tests.cpp:<line number>: passed: gen.next() for: true
|
||||
GeneratorsImpl.tests.cpp:<line number>: passed: gen.get() == 5 for: 5 == 5
|
||||
GeneratorsImpl.tests.cpp:<line number>: passed: !(gen.next()) for: !false
|
||||
GeneratorsImpl.tests.cpp:<line number>: passed: gen.get() == 1 for: 1 == 1
|
||||
GeneratorsImpl.tests.cpp:<line number>: passed: gen.next() for: true
|
||||
GeneratorsImpl.tests.cpp:<line number>: passed: gen.get() == 5 for: 5 == 5
|
||||
GeneratorsImpl.tests.cpp:<line number>: passed: gen.next() for: true
|
||||
GeneratorsImpl.tests.cpp:<line number>: passed: gen.get() == 2 for: 2 == 2
|
||||
GeneratorsImpl.tests.cpp:<line number>: passed: gen.next() for: true
|
||||
GeneratorsImpl.tests.cpp:<line number>: passed: gen.get() == 4 for: 4 == 4
|
||||
GeneratorsImpl.tests.cpp:<line number>: passed: gen.next() for: true
|
||||
GeneratorsImpl.tests.cpp:<line number>: passed: gen.get() == 0 for: 0 == 0
|
||||
GeneratorsImpl.tests.cpp:<line number>: passed: !(gen.next()) for: !false
|
||||
GeneratorsImpl.tests.cpp:<line number>: passed: gen.get().size() == 2 for: 2 == 2
|
||||
GeneratorsImpl.tests.cpp:<line number>: passed: gen.get() == "aa" for: "aa" == "aa"
|
||||
GeneratorsImpl.tests.cpp:<line number>: passed: gen.next() for: true
|
||||
GeneratorsImpl.tests.cpp:<line number>: passed: gen.get() == "bb" for: "bb" == "bb"
|
||||
GeneratorsImpl.tests.cpp:<line number>: passed: gen.next() for: true
|
||||
GeneratorsImpl.tests.cpp:<line number>: passed: gen.get() == "cc" for: "cc" == "cc"
|
||||
GeneratorsImpl.tests.cpp:<line number>: passed: !(gen.next()) for: !false
|
||||
GeneratorsImpl.tests.cpp:<line number>: passed: gen.get() == 1 for: 1 == 1
|
||||
GeneratorsImpl.tests.cpp:<line number>: passed: gen.next() for: true
|
||||
GeneratorsImpl.tests.cpp:<line number>: passed: gen.get() == 3 for: 3 == 3
|
||||
GeneratorsImpl.tests.cpp:<line number>: passed: !(gen.next()) for: !false
|
||||
GeneratorsImpl.tests.cpp:<line number>: passed: filter([] (int) { return false; }, value(1)), Catch::GeneratorException
|
||||
GeneratorsImpl.tests.cpp:<line number>: passed: gen.get() == 1 for: 1 == 1
|
||||
GeneratorsImpl.tests.cpp:<line number>: passed: gen.next() for: true
|
||||
GeneratorsImpl.tests.cpp:<line number>: passed: gen.get() == 2 for: 2 == 2
|
||||
GeneratorsImpl.tests.cpp:<line number>: passed: !(gen.next()) for: !false
|
||||
GeneratorsImpl.tests.cpp:<line number>: passed: gen.get() == 1 for: 1 == 1
|
||||
GeneratorsImpl.tests.cpp:<line number>: passed: !(gen.next()) for: !false
|
||||
GeneratorsImpl.tests.cpp:<line number>: passed: gen.get() == 2.0 for: 2.0 == 2.0
|
||||
GeneratorsImpl.tests.cpp:<line number>: passed: gen.next() for: true
|
||||
GeneratorsImpl.tests.cpp:<line number>: passed: gen.get() == 4.0 for: 4.0 == 4.0
|
||||
GeneratorsImpl.tests.cpp:<line number>: passed: gen.next() for: true
|
||||
GeneratorsImpl.tests.cpp:<line number>: passed: gen.get() == 6.0 for: 6.0 == 6.0
|
||||
GeneratorsImpl.tests.cpp:<line number>: passed: !(gen.next()) for: !false
|
||||
GeneratorsImpl.tests.cpp:<line number>: passed: gen.get() == 2.0 for: 2.0 == 2.0
|
||||
GeneratorsImpl.tests.cpp:<line number>: passed: gen.next() for: true
|
||||
GeneratorsImpl.tests.cpp:<line number>: passed: gen.get() == 4.0 for: 4.0 == 4.0
|
||||
GeneratorsImpl.tests.cpp:<line number>: passed: gen.next() for: true
|
||||
GeneratorsImpl.tests.cpp:<line number>: passed: gen.get() == 6.0 for: 6.0 == 6.0
|
||||
GeneratorsImpl.tests.cpp:<line number>: passed: !(gen.next()) for: !false
|
||||
GeneratorsImpl.tests.cpp:<line number>: passed: gen.get() == 3 for: 3 == 3
|
||||
GeneratorsImpl.tests.cpp:<line number>: passed: !(gen.next()) for: !false
|
||||
GeneratorsImpl.tests.cpp:<line number>: passed: gen.get() == 1 for: 1 == 1
|
||||
GeneratorsImpl.tests.cpp:<line number>: passed: gen.next() for: true
|
||||
GeneratorsImpl.tests.cpp:<line number>: passed: gen.get() == 2 for: 2 == 2
|
||||
GeneratorsImpl.tests.cpp:<line number>: passed: gen.next() for: true
|
||||
GeneratorsImpl.tests.cpp:<line number>: passed: gen.get() == 3 for: 3 == 3
|
||||
GeneratorsImpl.tests.cpp:<line number>: passed: gen.next() for: true
|
||||
GeneratorsImpl.tests.cpp:<line number>: passed: gen.get() == 1 for: 1 == 1
|
||||
GeneratorsImpl.tests.cpp:<line number>: passed: gen.next() for: true
|
||||
GeneratorsImpl.tests.cpp:<line number>: passed: gen.get() == 2 for: 2 == 2
|
||||
GeneratorsImpl.tests.cpp:<line number>: passed: gen.next() for: true
|
||||
GeneratorsImpl.tests.cpp:<line number>: passed: gen.get() == 3 for: 3 == 3
|
||||
GeneratorsImpl.tests.cpp:<line number>: passed: !(gen.next()) for: !false
|
||||
GeneratorsImpl.tests.cpp:<line number>: passed: gen.get() == -2 for: -2 == -2
|
||||
GeneratorsImpl.tests.cpp:<line number>: passed: gen.next() for: true
|
||||
GeneratorsImpl.tests.cpp:<line number>: passed: gen.get() == -1 for: -1 == -1
|
||||
GeneratorsImpl.tests.cpp:<line number>: passed: gen.next() for: true
|
||||
GeneratorsImpl.tests.cpp:<line number>: passed: gen.get() == 0 for: 0 == 0
|
||||
GeneratorsImpl.tests.cpp:<line number>: passed: gen.next() for: true
|
||||
GeneratorsImpl.tests.cpp:<line number>: passed: gen.get() == 1 for: 1 == 1
|
||||
GeneratorsImpl.tests.cpp:<line number>: passed: !(gen.next()) for: !false
|
||||
GeneratorsImpl.tests.cpp:<line number>: passed: gen.get() == 2 for: 2 == 2
|
||||
GeneratorsImpl.tests.cpp:<line number>: passed: gen.next() for: true
|
||||
GeneratorsImpl.tests.cpp:<line number>: passed: gen.get() == 1 for: 1 == 1
|
||||
GeneratorsImpl.tests.cpp:<line number>: passed: gen.next() for: true
|
||||
GeneratorsImpl.tests.cpp:<line number>: passed: gen.get() == 0 for: 0 == 0
|
||||
GeneratorsImpl.tests.cpp:<line number>: passed: gen.next() for: true
|
||||
GeneratorsImpl.tests.cpp:<line number>: passed: gen.get() == -1 for: -1 == -1
|
||||
GeneratorsImpl.tests.cpp:<line number>: passed: !(gen.next()) for: !false
|
||||
GeneratorsImpl.tests.cpp:<line number>: passed: gen.get() == -7 for: -7 == -7
|
||||
GeneratorsImpl.tests.cpp:<line number>: passed: gen.next() for: true
|
||||
GeneratorsImpl.tests.cpp:<line number>: passed: gen.get() == -4 for: -4 == -4
|
||||
GeneratorsImpl.tests.cpp:<line number>: passed: gen.next() for: true
|
||||
GeneratorsImpl.tests.cpp:<line number>: passed: gen.get() == -1 for: -1 == -1
|
||||
GeneratorsImpl.tests.cpp:<line number>: passed: gen.next() for: true
|
||||
GeneratorsImpl.tests.cpp:<line number>: passed: gen.get() == 2 for: 2 == 2
|
||||
GeneratorsImpl.tests.cpp:<line number>: passed: !(gen.next()) for: !false
|
||||
GeneratorsImpl.tests.cpp:<line number>: passed: gen.get() == -7 for: -7 == -7
|
||||
GeneratorsImpl.tests.cpp:<line number>: passed: gen.next() for: true
|
||||
GeneratorsImpl.tests.cpp:<line number>: passed: gen.get() == -4 for: -4 == -4
|
||||
GeneratorsImpl.tests.cpp:<line number>: passed: gen.next() for: true
|
||||
GeneratorsImpl.tests.cpp:<line number>: passed: gen.get() == -1 for: -1 == -1
|
||||
GeneratorsImpl.tests.cpp:<line number>: passed: gen.next() for: true
|
||||
GeneratorsImpl.tests.cpp:<line number>: passed: gen.get() == 2 for: 2 == 2
|
||||
GeneratorsImpl.tests.cpp:<line number>: passed: !(gen.next()) for: !false
|
||||
GeneratorsImpl.tests.cpp:<line number>: passed: gen.get() == -7 for: -7 == -7
|
||||
GeneratorsImpl.tests.cpp:<line number>: passed: gen.next() for: true
|
||||
GeneratorsImpl.tests.cpp:<line number>: passed: gen.get() == -4 for: -4 == -4
|
||||
GeneratorsImpl.tests.cpp:<line number>: passed: gen.next() for: true
|
||||
GeneratorsImpl.tests.cpp:<line number>: passed: gen.get() == -1 for: -1 == -1
|
||||
GeneratorsImpl.tests.cpp:<line number>: passed: gen.next() for: true
|
||||
GeneratorsImpl.tests.cpp:<line number>: passed: gen.get() == 2 for: 2 == 2
|
||||
GeneratorsImpl.tests.cpp:<line number>: passed: gen.next() for: true
|
||||
GeneratorsImpl.tests.cpp:<line number>: passed: gen.get() == 5 for: 5 == 5
|
||||
GeneratorsImpl.tests.cpp:<line number>: passed: !(gen.next()) for: !false
|
||||
GeneratorsImpl.tests.cpp:<line number>: passed: gen.get() == 5 for: 5 == 5
|
||||
GeneratorsImpl.tests.cpp:<line number>: passed: gen.next() for: true
|
||||
GeneratorsImpl.tests.cpp:<line number>: passed: gen.get() == 2 for: 2 == 2
|
||||
GeneratorsImpl.tests.cpp:<line number>: passed: gen.next() for: true
|
||||
GeneratorsImpl.tests.cpp:<line number>: passed: gen.get() == -1 for: -1 == -1
|
||||
GeneratorsImpl.tests.cpp:<line number>: passed: gen.next() for: true
|
||||
GeneratorsImpl.tests.cpp:<line number>: passed: gen.get() == -4 for: -4 == -4
|
||||
GeneratorsImpl.tests.cpp:<line number>: passed: !(gen.next()) for: !false
|
||||
GeneratorsImpl.tests.cpp:<line number>: passed: gen.get() == 5 for: 5 == 5
|
||||
GeneratorsImpl.tests.cpp:<line number>: passed: gen.next() for: true
|
||||
GeneratorsImpl.tests.cpp:<line number>: passed: gen.get() == 2 for: 2 == 2
|
||||
GeneratorsImpl.tests.cpp:<line number>: passed: gen.next() for: true
|
||||
GeneratorsImpl.tests.cpp:<line number>: passed: gen.get() == -1 for: -1 == -1
|
||||
GeneratorsImpl.tests.cpp:<line number>: passed: gen.next() for: true
|
||||
GeneratorsImpl.tests.cpp:<line number>: passed: gen.get() == -4 for: -4 == -4
|
||||
GeneratorsImpl.tests.cpp:<line number>: passed: !(gen.next()) for: !false
|
||||
GeneratorsImpl.tests.cpp:<line number>: passed: gen.get() == 5 for: 5 == 5
|
||||
GeneratorsImpl.tests.cpp:<line number>: passed: gen.next() for: true
|
||||
GeneratorsImpl.tests.cpp:<line number>: passed: gen.get() == 2 for: 2 == 2
|
||||
GeneratorsImpl.tests.cpp:<line number>: passed: gen.next() for: true
|
||||
GeneratorsImpl.tests.cpp:<line number>: passed: gen.get() == -1 for: -1 == -1
|
||||
GeneratorsImpl.tests.cpp:<line number>: passed: gen.next() for: true
|
||||
GeneratorsImpl.tests.cpp:<line number>: passed: gen.get() == -4 for: -4 == -4
|
||||
GeneratorsImpl.tests.cpp:<line number>: passed: gen.next() for: true
|
||||
GeneratorsImpl.tests.cpp:<line number>: passed: gen.get() == -7 for: -7 == -7
|
||||
GeneratorsImpl.tests.cpp:<line number>: passed: !(gen.next()) for: !false
|
||||
Approx.tests.cpp:<line number>: passed: d >= Approx( 1.22 ) for: 1.23 >= Approx( 1.22 )
|
||||
Approx.tests.cpp:<line number>: passed: d >= Approx( 1.23 ) for: 1.23 >= Approx( 1.23 )
|
||||
Approx.tests.cpp:<line number>: passed: !(d >= Approx( 1.24 )) for: !(1.23 >= Approx( 1.24 ))
|
||||
@@ -499,6 +637,22 @@ Matchers.tests.cpp:<line number>: passed: testStringForMatching(), !Contains("di
|
||||
Matchers.tests.cpp:<line number>: failed: testStringForMatching(), !Contains("substring") for: "this string contains 'abc' as a substring" not contains: "substring"
|
||||
Exception.tests.cpp:<line number>: passed: thisThrows(), "expected exception" for: "expected exception" equals: "expected exception"
|
||||
Exception.tests.cpp:<line number>: failed: thisThrows(), "should fail" for: "expected exception" equals: "should fail"
|
||||
Generators.tests.cpp:<line number>: passed: values > -6 for: 3 > -6
|
||||
Generators.tests.cpp:<line number>: passed: values > -6 for: 4 > -6
|
||||
Generators.tests.cpp:<line number>: passed: values > -6 for: 5 > -6
|
||||
Generators.tests.cpp:<line number>: passed: values > -6 for: 6 > -6
|
||||
Generators.tests.cpp:<line number>: passed: values > -6 for: -5 > -6
|
||||
Generators.tests.cpp:<line number>: passed: values > -6 for: -4 > -6
|
||||
Generators.tests.cpp:<line number>: passed: values > -6 for: 90 > -6
|
||||
Generators.tests.cpp:<line number>: passed: values > -6 for: 91 > -6
|
||||
Generators.tests.cpp:<line number>: passed: values > -6 for: 92 > -6
|
||||
Generators.tests.cpp:<line number>: passed: values > -6 for: 93 > -6
|
||||
Generators.tests.cpp:<line number>: passed: values > -6 for: 94 > -6
|
||||
Generators.tests.cpp:<line number>: passed: values > -6 for: 95 > -6
|
||||
Generators.tests.cpp:<line number>: passed: values > -6 for: 96 > -6
|
||||
Generators.tests.cpp:<line number>: passed: values > -6 for: 97 > -6
|
||||
Generators.tests.cpp:<line number>: passed: values > -6 for: 98 > -6
|
||||
Generators.tests.cpp:<line number>: passed: values > -6 for: 99 > -6
|
||||
Misc.tests.cpp:<line number>: warning: 'This one ran'
|
||||
Exception.tests.cpp:<line number>: failed: unexpected exception with message: 'custom exception'
|
||||
Tricky.tests.cpp:<line number>: passed: True for: {?}
|
||||
@@ -750,6 +904,9 @@ CmdLine.tests.cpp:<line number>: passed: cli.parse({"test", "--use-colour", "no"
|
||||
CmdLine.tests.cpp:<line number>: passed: config.useColour == UseColour::No for: 2 == 2
|
||||
CmdLine.tests.cpp:<line number>: passed: !result for: true
|
||||
CmdLine.tests.cpp:<line number>: passed: result.errorMessage(), Contains( "colour mode must be one of" ) for: "colour mode must be one of: auto, yes or no. 'wrong' not recognised" contains: "colour mode must be one of"
|
||||
Misc.tests.cpp:<line number>: passed: std::tuple_size<TestType>::value >= 1 for: 3 >= 1
|
||||
Misc.tests.cpp:<line number>: passed: std::tuple_size<TestType>::value >= 1 for: 2 >= 1
|
||||
Misc.tests.cpp:<line number>: passed: std::tuple_size<TestType>::value >= 1 for: 1 >= 1
|
||||
Decomposition.tests.cpp:<line number>: failed: truthy(false) for: Hey, its truthy!
|
||||
Matchers.tests.cpp:<line number>: failed: testStringForMatching(), Matches("this STRING contains 'abc' as a substring") for: "this string contains 'abc' as a substring" matches "this STRING contains 'abc' as a substring" case sensitively
|
||||
Matchers.tests.cpp:<line number>: failed: testStringForMatching(), Matches("contains 'abc' as a substring") for: "this string contains 'abc' as a substring" matches "contains 'abc' as a substring" case sensitively
|
||||
@@ -863,22 +1020,22 @@ Misc.tests.cpp:<line number>: failed: s1 == s2 for: "if ($b == 10) {
|
||||
$a = 20;
|
||||
}
|
||||
"
|
||||
TagAlias.tests.cpp:<line number>: passed: what, Contains( "[@zzz]" ) for: "error: tag alias, '[@zzz]' already registered.
|
||||
Tag.tests.cpp:<line number>: passed: what, Contains( "[@zzz]" ) for: "error: tag alias, '[@zzz]' already registered.
|
||||
First seen at: file:2
|
||||
Redefined at: file:10" contains: "[@zzz]"
|
||||
TagAlias.tests.cpp:<line number>: passed: what, Contains( "file" ) for: "error: tag alias, '[@zzz]' already registered.
|
||||
Tag.tests.cpp:<line number>: passed: what, Contains( "file" ) for: "error: tag alias, '[@zzz]' already registered.
|
||||
First seen at: file:2
|
||||
Redefined at: file:10" contains: "file"
|
||||
TagAlias.tests.cpp:<line number>: passed: what, Contains( "2" ) for: "error: tag alias, '[@zzz]' already registered.
|
||||
Tag.tests.cpp:<line number>: passed: what, Contains( "2" ) for: "error: tag alias, '[@zzz]' already registered.
|
||||
First seen at: file:2
|
||||
Redefined at: file:10" contains: "2"
|
||||
TagAlias.tests.cpp:<line number>: passed: what, Contains( "10" ) for: "error: tag alias, '[@zzz]' already registered.
|
||||
Tag.tests.cpp:<line number>: passed: what, Contains( "10" ) for: "error: tag alias, '[@zzz]' already registered.
|
||||
First seen at: file:2
|
||||
Redefined at: file:10" contains: "10"
|
||||
TagAlias.tests.cpp:<line number>: passed: registry.add( "[no ampersat]", "", Catch::SourceLineInfo( "file", 3 ) )
|
||||
TagAlias.tests.cpp:<line number>: passed: registry.add( "[the @ is not at the start]", "", Catch::SourceLineInfo( "file", 3 ) )
|
||||
TagAlias.tests.cpp:<line number>: passed: registry.add( "@no square bracket at start]", "", Catch::SourceLineInfo( "file", 3 ) )
|
||||
TagAlias.tests.cpp:<line number>: passed: registry.add( "[@no square bracket at end", "", Catch::SourceLineInfo( "file", 3 ) )
|
||||
Tag.tests.cpp:<line number>: passed: registry.add( "[no ampersat]", "", Catch::SourceLineInfo( "file", 3 ) )
|
||||
Tag.tests.cpp:<line number>: passed: registry.add( "[the @ is not at the start]", "", Catch::SourceLineInfo( "file", 3 ) )
|
||||
Tag.tests.cpp:<line number>: passed: registry.add( "@no square bracket at start]", "", Catch::SourceLineInfo( "file", 3 ) )
|
||||
Tag.tests.cpp:<line number>: passed: registry.add( "[@no square bracket at end", "", Catch::SourceLineInfo( "file", 3 ) )
|
||||
Misc.tests.cpp:<line number>: passed: v.size() == 5 for: 5 == 5
|
||||
Misc.tests.cpp:<line number>: passed: v.capacity() >= 5 for: 5 >= 5
|
||||
Misc.tests.cpp:<line number>: passed: v.size() == 10 for: 10 == 10
|
||||
@@ -1019,69 +1176,6 @@ PartTracker.tests.cpp:<line number>: passed: s1.isComplete() == false for: false
|
||||
PartTracker.tests.cpp:<line number>: passed: s1.isComplete() for: true
|
||||
PartTracker.tests.cpp:<line number>: passed: testCase.isComplete() == false for: false == false
|
||||
PartTracker.tests.cpp:<line number>: passed: testCase.isComplete() for: true
|
||||
PartTracker.tests.cpp:<line number>: passed: testCase.isOpen() for: true
|
||||
PartTracker.tests.cpp:<line number>: passed: s1.isOpen() for: true
|
||||
PartTracker.tests.cpp:<line number>: passed: g1.isOpen() for: true
|
||||
PartTracker.tests.cpp:<line number>: passed: g1.index() == 0 for: 0 == 0
|
||||
PartTracker.tests.cpp:<line number>: passed: g1.isComplete() == false for: false == false
|
||||
PartTracker.tests.cpp:<line number>: passed: s1.isComplete() == false for: false == false
|
||||
PartTracker.tests.cpp:<line number>: passed: s1.isComplete() == false for: false == false
|
||||
PartTracker.tests.cpp:<line number>: passed: testCase.isSuccessfullyCompleted() == false for: false == false
|
||||
PartTracker.tests.cpp:<line number>: passed: testCase2.isOpen() for: true
|
||||
PartTracker.tests.cpp:<line number>: passed: s1b.isOpen() for: true
|
||||
PartTracker.tests.cpp:<line number>: passed: g1b.isOpen() for: true
|
||||
PartTracker.tests.cpp:<line number>: passed: g1b.index() == 1 for: 1 == 1
|
||||
PartTracker.tests.cpp:<line number>: passed: s1.isComplete() == false for: false == false
|
||||
PartTracker.tests.cpp:<line number>: passed: s1b.isComplete() for: true
|
||||
PartTracker.tests.cpp:<line number>: passed: g1b.isComplete() for: true
|
||||
PartTracker.tests.cpp:<line number>: passed: testCase2.isComplete() for: true
|
||||
PartTracker.tests.cpp:<line number>: passed: testCase.isOpen() for: true
|
||||
PartTracker.tests.cpp:<line number>: passed: s1.isOpen() for: true
|
||||
PartTracker.tests.cpp:<line number>: passed: g1.isOpen() for: true
|
||||
PartTracker.tests.cpp:<line number>: passed: g1.index() == 0 for: 0 == 0
|
||||
PartTracker.tests.cpp:<line number>: passed: g1.isComplete() == false for: false == false
|
||||
PartTracker.tests.cpp:<line number>: passed: s1.isComplete() == false for: false == false
|
||||
PartTracker.tests.cpp:<line number>: passed: s2.isOpen() for: true
|
||||
PartTracker.tests.cpp:<line number>: passed: s2.isComplete() for: true
|
||||
PartTracker.tests.cpp:<line number>: passed: s1.isComplete() == false for: false == false
|
||||
PartTracker.tests.cpp:<line number>: passed: testCase.isComplete() == false for: false == false
|
||||
PartTracker.tests.cpp:<line number>: passed: testCase2.isOpen() for: true
|
||||
PartTracker.tests.cpp:<line number>: passed: s1b.isOpen() for: true
|
||||
PartTracker.tests.cpp:<line number>: passed: g1b.isOpen() for: true
|
||||
PartTracker.tests.cpp:<line number>: passed: g1b.index() == 1 for: 1 == 1
|
||||
PartTracker.tests.cpp:<line number>: passed: s2b.isOpen() for: true
|
||||
PartTracker.tests.cpp:<line number>: passed: s2b.isComplete() for: true
|
||||
PartTracker.tests.cpp:<line number>: passed: g1b.isComplete() for: true
|
||||
PartTracker.tests.cpp:<line number>: passed: s1b.isComplete() for: true
|
||||
PartTracker.tests.cpp:<line number>: passed: testCase2.isComplete() for: true
|
||||
PartTracker.tests.cpp:<line number>: passed: testCase.isOpen() for: true
|
||||
PartTracker.tests.cpp:<line number>: passed: s1.isOpen() for: true
|
||||
PartTracker.tests.cpp:<line number>: passed: g1.isOpen() for: true
|
||||
PartTracker.tests.cpp:<line number>: passed: g1.index() == 0 for: 0 == 0
|
||||
PartTracker.tests.cpp:<line number>: passed: g1.isComplete() == false for: false == false
|
||||
PartTracker.tests.cpp:<line number>: passed: s1.isComplete() == false for: false == false
|
||||
PartTracker.tests.cpp:<line number>: passed: s2.isOpen() for: true
|
||||
PartTracker.tests.cpp:<line number>: passed: s2.isComplete() for: true
|
||||
PartTracker.tests.cpp:<line number>: passed: s2.isSuccessfullyCompleted() == false for: false == false
|
||||
PartTracker.tests.cpp:<line number>: passed: s1.isComplete() == false for: false == false
|
||||
PartTracker.tests.cpp:<line number>: passed: testCase.isComplete() == false for: false == false
|
||||
PartTracker.tests.cpp:<line number>: passed: testCase2.isOpen() for: true
|
||||
PartTracker.tests.cpp:<line number>: passed: s1b.isOpen() for: true
|
||||
PartTracker.tests.cpp:<line number>: passed: g1b.isOpen() for: true
|
||||
PartTracker.tests.cpp:<line number>: passed: g1b.index() == 0 for: 0 == 0
|
||||
PartTracker.tests.cpp:<line number>: passed: s2b.isOpen() == false for: false == false
|
||||
PartTracker.tests.cpp:<line number>: passed: g1b.isComplete() == false for: false == false
|
||||
PartTracker.tests.cpp:<line number>: passed: s1b.isComplete() == false for: false == false
|
||||
PartTracker.tests.cpp:<line number>: passed: testCase2.isComplete() == false for: false == false
|
||||
PartTracker.tests.cpp:<line number>: passed: testCase3.isOpen() for: true
|
||||
PartTracker.tests.cpp:<line number>: passed: s1c.isOpen() for: true
|
||||
PartTracker.tests.cpp:<line number>: passed: g1c.isOpen() for: true
|
||||
PartTracker.tests.cpp:<line number>: passed: g1c.index() == 1 for: 1 == 1
|
||||
PartTracker.tests.cpp:<line number>: passed: s2c.isOpen() for: true
|
||||
PartTracker.tests.cpp:<line number>: passed: s2c.isComplete() for: true
|
||||
PartTracker.tests.cpp:<line number>: passed: g1c.isComplete() for: true
|
||||
PartTracker.tests.cpp:<line number>: passed: s1c.isComplete() for: true
|
||||
PartTracker.tests.cpp:<line number>: passed: testCase3.isComplete() for: true
|
||||
Exception.tests.cpp:<line number>: failed: unexpected exception with message: '3.14'
|
||||
Approx.tests.cpp:<line number>: passed: d == approx( 1.23 ) for: 1.23 == Approx( 1.23 )
|
||||
Approx.tests.cpp:<line number>: passed: d == approx( 1.22 ) for: 1.23 == Approx( 1.22 )
|
||||
@@ -1216,6 +1310,7 @@ Misc.tests.cpp:<line number>: passed:
|
||||
Misc.tests.cpp:<line number>: passed:
|
||||
loose text artifact
|
||||
Message.tests.cpp:<line number>: failed: explicitly with 1 message: 'Previous info should not be seen'
|
||||
Message.tests.cpp:<line number>: failed: explicitly with 1 message: 'previous unscoped info SHOULD not be seen'
|
||||
Misc.tests.cpp:<line number>: passed: l == std::numeric_limits<long long>::max() for: 9223372036854775807 (0x<hex digits>)
|
||||
==
|
||||
9223372036854775807 (0x<hex digits>)
|
||||
@@ -1237,6 +1332,8 @@ Misc.tests.cpp:<line number>: failed: ( fib[i] % 2 ) == 0 for: 1 == 0 with 1 mes
|
||||
Misc.tests.cpp:<line number>: passed: ( fib[i] % 2 ) == 0 for: 0 == 0 with 1 message: 'Testing if fib[5] (8) is even'
|
||||
Misc.tests.cpp:<line number>: failed: ( fib[i] % 2 ) == 0 for: 1 == 0 with 1 message: 'Testing if fib[6] (13) is even'
|
||||
Misc.tests.cpp:<line number>: failed: ( fib[i] % 2 ) == 0 for: 1 == 0 with 1 message: 'Testing if fib[7] (21) is even'
|
||||
Message.tests.cpp:<line number>: warning: 'info' with 2 messages: 'unscoped info' and 'and warn may mix'
|
||||
Message.tests.cpp:<line number>: warning: 'info' with 2 messages: 'unscoped info' and 'they are not cleared after warnings'
|
||||
Misc.tests.cpp:<line number>: failed: a == b for: 1 == 2
|
||||
Misc.tests.cpp:<line number>: passed: a != b for: 1 != 2
|
||||
Misc.tests.cpp:<line number>: passed: a < b for: 1 < 2
|
||||
@@ -1246,6 +1343,9 @@ Misc.tests.cpp:<line number>: passed: a != b for: 1 != 2
|
||||
Tricky.tests.cpp:<line number>: passed: s == "7" for: "7" == "7"
|
||||
Tricky.tests.cpp:<line number>: passed: ti == typeid(int) for: {?} == {?}
|
||||
Misc.tests.cpp:<line number>: passed:
|
||||
Message.tests.cpp:<line number>: passed: true with 1 message: 'this MAY be seen only for the FIRST assertion IF info is printed for passing assertions'
|
||||
Message.tests.cpp:<line number>: passed: true with 1 message: 'this MAY be seen only for the SECOND assertion IF info is printed for passing assertions'
|
||||
Message.tests.cpp:<line number>: failed: false with 1 message: 'this SHOULD be seen'
|
||||
Misc.tests.cpp:<line number>: passed: makeString( false ) != static_cast<char*>(0) for: "valid string" != {null string}
|
||||
Misc.tests.cpp:<line number>: passed: makeString( true ) == static_cast<char*>(0) for: {null string} == {null string}
|
||||
Tricky.tests.cpp:<line number>: passed: ptr.get() == 0 for: 0 == 0
|
||||
@@ -1253,6 +1353,12 @@ ToStringPair.tests.cpp:<line number>: passed: ::Catch::Detail::stringify( pair )
|
||||
==
|
||||
"{ { 42, "Arthur" }, { "Ford", 24 } }"
|
||||
Tricky.tests.cpp:<line number>: passed: p == 0 for: 0 == 0
|
||||
Message.tests.cpp:<line number>: passed: true with 1 message: 'this MAY be seen IF info is printed for passing assertions'
|
||||
Message.tests.cpp:<line number>: failed: false with 2 messages: 'this SHOULD be seen' and 'this SHOULD also be seen'
|
||||
Message.tests.cpp:<line number>: failed: false with 1 message: 'this SHOULD be seen only ONCE'
|
||||
Message.tests.cpp:<line number>: passed: true
|
||||
Message.tests.cpp:<line number>: passed: true with 1 message: 'this MAY also be seen only ONCE IF info is printed for passing assertions'
|
||||
Message.tests.cpp:<line number>: passed: true
|
||||
Misc.tests.cpp:<line number>: passed: a != b for: 1 != 2
|
||||
Misc.tests.cpp:<line number>: passed: b != a for: 2 != 1
|
||||
Misc.tests.cpp:<line number>: passed: a != b for: 1 != 2
|
||||
@@ -1272,6 +1378,9 @@ String.tests.cpp:<line number>: passed: Catch::replaceInPlace( s, "'", "|'" ) fo
|
||||
String.tests.cpp:<line number>: passed: s == "didn|'t" for: "didn|'t" == "didn|'t"
|
||||
Misc.tests.cpp:<line number>: failed: false with 1 message: '3'
|
||||
Message.tests.cpp:<line number>: failed: false with 2 messages: 'hi' and 'i := 7'
|
||||
Tag.tests.cpp:<line number>: passed: testcase.tags, Catch::VectorContains(std::string("magic-tag")) && Catch::VectorContains(std::string(".")) for: { ".", "magic-tag" } ( Contains: "magic-tag" and Contains: "." )
|
||||
Message.tests.cpp:<line number>: failed: false with 4 messages: 'Count 1 to 3...' and '1' and '2' and '3'
|
||||
Message.tests.cpp:<line number>: failed: false with 4 messages: 'Count 4 to 6...' and '4' and '5' and '6'
|
||||
ToStringGeneral.tests.cpp:<line number>: passed: Catch::Detail::stringify( emptyMap ) == "{ }" for: "{ }" == "{ }"
|
||||
ToStringGeneral.tests.cpp:<line number>: passed: Catch::Detail::stringify( map ) == "{ { \"one\", 1 } }" for: "{ { "one", 1 } }" == "{ { "one", 1 } }"
|
||||
ToStringGeneral.tests.cpp:<line number>: passed: Catch::Detail::stringify( map ) == "{ { \"abc\", 1 }, { \"def\", 2 }, { \"ghi\", 3 } }" for: "{ { "abc", 1 }, { "def", 2 }, { "ghi", 3 } }"
|
||||
@@ -1322,6 +1431,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 +1502,5 @@ Misc.tests.cpp:<line number>: passed: v.size() == 5 for: 5 == 5
|
||||
Misc.tests.cpp:<line number>: passed: v.capacity() >= 5 for: 5 >= 5
|
||||
Misc.tests.cpp:<line number>: passed:
|
||||
Misc.tests.cpp:<line number>: passed:
|
||||
Failed 65 test cases, failed 125 assertions.
|
||||
Failed 77 test cases, failed 138 assertions.
|
||||
|
||||
|
@@ -1,3 +1,6 @@
|
||||
Filters: ~[!nonportable]~[!benchmark]~[approvals]
|
||||
This would not be caught previously
|
||||
Nor would this
|
||||
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
<exe-name> is a <version> host application.
|
||||
@@ -5,6 +8,16 @@ Run with -? for options
|
||||
|
||||
Randomness seeded to: 1
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
#1514: stderr/stdout is not captured in tests aborted by an exception
|
||||
-------------------------------------------------------------------------------
|
||||
Tricky.tests.cpp:<line number>
|
||||
...............................................................................
|
||||
|
||||
Tricky.tests.cpp:<line number>: FAILED:
|
||||
explicitly with message:
|
||||
1514
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
#748 - captures with unexpected exceptions
|
||||
outside assertions
|
||||
@@ -92,6 +105,54 @@ Class.tests.cpp:<line number>: FAILED:
|
||||
with expansion:
|
||||
"hello" == "world"
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
A TEMPLATE_PRODUCT_TEST_CASE_METHOD based test run that fails - Template_Foo
|
||||
<float>
|
||||
-------------------------------------------------------------------------------
|
||||
Class.tests.cpp:<line number>
|
||||
...............................................................................
|
||||
|
||||
Class.tests.cpp:<line number>: FAILED:
|
||||
REQUIRE( Template_Fixture_2<TestType>::m_a.size() == 1 )
|
||||
with expansion:
|
||||
0 == 1
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
A TEMPLATE_PRODUCT_TEST_CASE_METHOD based test run that fails - Template_Foo
|
||||
<int>
|
||||
-------------------------------------------------------------------------------
|
||||
Class.tests.cpp:<line number>
|
||||
...............................................................................
|
||||
|
||||
Class.tests.cpp:<line number>: FAILED:
|
||||
REQUIRE( Template_Fixture_2<TestType>::m_a.size() == 1 )
|
||||
with expansion:
|
||||
0 == 1
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
A TEMPLATE_PRODUCT_TEST_CASE_METHOD based test run that fails - std::vector
|
||||
<float>
|
||||
-------------------------------------------------------------------------------
|
||||
Class.tests.cpp:<line number>
|
||||
...............................................................................
|
||||
|
||||
Class.tests.cpp:<line number>: FAILED:
|
||||
REQUIRE( Template_Fixture_2<TestType>::m_a.size() == 1 )
|
||||
with expansion:
|
||||
0 == 1
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
A TEMPLATE_PRODUCT_TEST_CASE_METHOD based test run that fails - std::vector
|
||||
<int>
|
||||
-------------------------------------------------------------------------------
|
||||
Class.tests.cpp:<line number>
|
||||
...............................................................................
|
||||
|
||||
Class.tests.cpp:<line number>: FAILED:
|
||||
REQUIRE( Template_Fixture_2<TestType>::m_a.size() == 1 )
|
||||
with expansion:
|
||||
0 == 1
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
A TEMPLATE_TEST_CASE_METHOD based test run that fails - double
|
||||
-------------------------------------------------------------------------------
|
||||
@@ -996,6 +1057,16 @@ Message.tests.cpp:<line number>: FAILED:
|
||||
explicitly with message:
|
||||
Previous info should not be seen
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
just failure after unscoped info
|
||||
-------------------------------------------------------------------------------
|
||||
Message.tests.cpp:<line number>
|
||||
...............................................................................
|
||||
|
||||
Message.tests.cpp:<line number>: FAILED:
|
||||
explicitly with message:
|
||||
previous unscoped info SHOULD not be seen
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
looped SECTION tests
|
||||
b is currently: 0
|
||||
@@ -1068,6 +1139,18 @@ with expansion:
|
||||
with message:
|
||||
Testing if fib[7] (21) is even
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
mix info, unscoped info and warning
|
||||
-------------------------------------------------------------------------------
|
||||
Message.tests.cpp:<line number>
|
||||
...............................................................................
|
||||
|
||||
Message.tests.cpp:<line number>: warning:
|
||||
and warn may mix
|
||||
|
||||
Message.tests.cpp:<line number>: warning:
|
||||
they are not cleared after warnings
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
more nested SECTION tests
|
||||
doesn't equal
|
||||
@@ -1081,6 +1164,40 @@ Misc.tests.cpp:<line number>: FAILED:
|
||||
with expansion:
|
||||
1 == 2
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
not prints unscoped info from previous failures
|
||||
-------------------------------------------------------------------------------
|
||||
Message.tests.cpp:<line number>
|
||||
...............................................................................
|
||||
|
||||
Message.tests.cpp:<line number>: FAILED:
|
||||
REQUIRE( false )
|
||||
with message:
|
||||
this SHOULD be seen
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
prints unscoped info on failure
|
||||
-------------------------------------------------------------------------------
|
||||
Message.tests.cpp:<line number>
|
||||
...............................................................................
|
||||
|
||||
Message.tests.cpp:<line number>: FAILED:
|
||||
REQUIRE( false )
|
||||
with messages:
|
||||
this SHOULD be seen
|
||||
this SHOULD also be seen
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
prints unscoped info only for the first assertion
|
||||
-------------------------------------------------------------------------------
|
||||
Message.tests.cpp:<line number>
|
||||
...............................................................................
|
||||
|
||||
Message.tests.cpp:<line number>: FAILED:
|
||||
CHECK( false )
|
||||
with message:
|
||||
this SHOULD be seen only ONCE
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
send a single char to INFO
|
||||
-------------------------------------------------------------------------------
|
||||
@@ -1104,6 +1221,28 @@ with messages:
|
||||
hi
|
||||
i := 7
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
stacks unscoped info in loops
|
||||
-------------------------------------------------------------------------------
|
||||
Message.tests.cpp:<line number>
|
||||
...............................................................................
|
||||
|
||||
Message.tests.cpp:<line number>: FAILED:
|
||||
CHECK( false )
|
||||
with messages:
|
||||
Count 1 to 3...
|
||||
1
|
||||
2
|
||||
3
|
||||
|
||||
Message.tests.cpp:<line number>: FAILED:
|
||||
CHECK( false )
|
||||
with messages:
|
||||
Count 4 to 6...
|
||||
4
|
||||
5
|
||||
6
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
string literals of different sizes can be compared
|
||||
-------------------------------------------------------------------------------
|
||||
@@ -1126,6 +1265,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: 257 | 191 passed | 62 failed | 4 failed as expected
|
||||
assertions: 1419 | 1276 passed | 122 failed | 21 failed as expected
|
||||
|
||||
|
File diff suppressed because it is too large
Load Diff
@@ -1,3 +1,4 @@
|
||||
Filters: ~[!nonportable]~[!benchmark]~[approvals]
|
||||
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
<exe-name> is a <version> host application.
|
||||
@@ -133,6 +134,29 @@ Compilation.tests.cpp:<line number>: PASSED:
|
||||
with expansion:
|
||||
[1403 helper] == [1403 helper]
|
||||
|
||||
This would not be caught previously
|
||||
Nor would this
|
||||
-------------------------------------------------------------------------------
|
||||
#1514: stderr/stdout is not captured in tests aborted by an exception
|
||||
-------------------------------------------------------------------------------
|
||||
Tricky.tests.cpp:<line number>
|
||||
...............................................................................
|
||||
|
||||
Tricky.tests.cpp:<line number>: FAILED:
|
||||
explicitly with message:
|
||||
1514
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
#1548
|
||||
-------------------------------------------------------------------------------
|
||||
Compilation.tests.cpp:<line number>
|
||||
...............................................................................
|
||||
|
||||
Compilation.tests.cpp:<line number>: PASSED:
|
||||
REQUIRE( std::is_same<TypeList<int>, TypeList<int>>::value )
|
||||
with expansion:
|
||||
true
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
#748 - captures with unexpected exceptions
|
||||
outside assertions
|
||||
@@ -317,12 +341,7 @@ Condition.tests.cpp:<line number>: FAILED:
|
||||
with expansion:
|
||||
false
|
||||
|
||||
Condition.tests.cpp:<line number>: FAILED:
|
||||
CHECK_FALSE( true )
|
||||
with expansion:
|
||||
!true
|
||||
|
||||
===============================================================================
|
||||
test cases: 15 | 12 passed | 1 failed | 2 failed as expected
|
||||
assertions: 39 | 32 passed | 4 failed | 3 failed as expected
|
||||
test cases: 17 | 13 passed | 2 failed | 2 failed as expected
|
||||
assertions: 40 | 33 passed | 4 failed | 3 failed as expected
|
||||
|
||||
|
@@ -1,7 +1,11 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<testsuitesloose text artifact
|
||||
>
|
||||
<testsuite name="<exe-name>" errors="17" failures="109" tests="1325" hostname="tbd" time="{duration}" timestamp="{iso8601-timestamp}">
|
||||
<testsuites>
|
||||
<properties>
|
||||
<property name="filters" value="~[!nonportable]~[!benchmark]~[approvals]"/>
|
||||
<property name="random-seed" value="1"/>
|
||||
</properties>
|
||||
loose text artifact
|
||||
<testsuite name="<exe-name>" errors="17" failures="122" tests="1436" hostname="tbd" time="{duration}" timestamp="{iso8601-timestamp}">
|
||||
<testcase classname="<exe-name>.global" name="# A test name that starts with a #" time="{duration}"/>
|
||||
<testcase classname="<exe-name>.global" name="#1005: Comparing pointer to int and long (NULL can be either on various systems)" time="{duration}"/>
|
||||
<testcase classname="<exe-name>.global" name="#1027" time="{duration}"/>
|
||||
@@ -10,6 +14,19 @@
|
||||
<testcase classname="<exe-name>.global" name="#1238" time="{duration}"/>
|
||||
<testcase classname="<exe-name>.(Fixture_1245<int, int>)" name="#1245" time="{duration}"/>
|
||||
<testcase classname="<exe-name>.global" name="#1403" time="{duration}"/>
|
||||
<testcase classname="<exe-name>.global" name="#1514: stderr/stdout is not captured in tests aborted by an exception" time="{duration}">
|
||||
<failure type="FAIL">
|
||||
1514
|
||||
Tricky.tests.cpp:<line number>
|
||||
</failure>
|
||||
<system-out>
|
||||
This would not be caught previously
|
||||
</system-out>
|
||||
<system-err>
|
||||
Nor would this
|
||||
</system-err>
|
||||
</testcase>
|
||||
<testcase classname="<exe-name>.global" name="#1548" time="{duration}"/>
|
||||
<testcase classname="<exe-name>.global" name="#748 - captures with unexpected exceptions/outside assertions" time="{duration}">
|
||||
<error type="TEST_CASE">
|
||||
expected exception
|
||||
@@ -70,13 +87,37 @@ Condition.tests.cpp:<line number>
|
||||
<testcase classname="<exe-name>.global" name="(unimplemented) static bools can be evaluated/negation" time="{duration}"/>
|
||||
<testcase classname="<exe-name>.global" name="(unimplemented) static bools can be evaluated/double negation" time="{duration}"/>
|
||||
<testcase classname="<exe-name>.global" name="(unimplemented) static bools can be evaluated/direct" time="{duration}"/>
|
||||
<testcase classname="<exe-name>.global" name="10x10 ints" time="{duration}"/>
|
||||
<testcase classname="<exe-name>.global" name="3x3x3 ints" time="{duration}"/>
|
||||
<testcase classname="<exe-name>.TestClass" name="A METHOD_AS_TEST_CASE based test run that fails" time="{duration}">
|
||||
<failure message=""hello" == "world"" type="REQUIRE">
|
||||
Class.tests.cpp:<line number>
|
||||
</failure>
|
||||
</testcase>
|
||||
<testcase classname="<exe-name>.TestClass" name="A METHOD_AS_TEST_CASE based test run that succeeds" time="{duration}"/>
|
||||
<testcase classname="<exe-name>.Template_Fixture_2" name="A TEMPLATE_PRODUCT_TEST_CASE_METHOD based test run that fails - Template_Foo<float>" time="{duration}">
|
||||
<failure message="0 == 1" type="REQUIRE">
|
||||
Class.tests.cpp:<line number>
|
||||
</failure>
|
||||
</testcase>
|
||||
<testcase classname="<exe-name>.Template_Fixture_2" name="A TEMPLATE_PRODUCT_TEST_CASE_METHOD based test run that fails - Template_Foo<int>" time="{duration}">
|
||||
<failure message="0 == 1" type="REQUIRE">
|
||||
Class.tests.cpp:<line number>
|
||||
</failure>
|
||||
</testcase>
|
||||
<testcase classname="<exe-name>.Template_Fixture_2" name="A TEMPLATE_PRODUCT_TEST_CASE_METHOD based test run that fails - std::vector<float>" time="{duration}">
|
||||
<failure message="0 == 1" type="REQUIRE">
|
||||
Class.tests.cpp:<line number>
|
||||
</failure>
|
||||
</testcase>
|
||||
<testcase classname="<exe-name>.Template_Fixture_2" name="A TEMPLATE_PRODUCT_TEST_CASE_METHOD based test run that fails - std::vector<int>" time="{duration}">
|
||||
<failure message="0 == 1" type="REQUIRE">
|
||||
Class.tests.cpp:<line number>
|
||||
</failure>
|
||||
</testcase>
|
||||
<testcase classname="<exe-name>.Template_Fixture_2" name="A TEMPLATE_PRODUCT_TEST_CASE_METHOD based test run that succeeds - Template_Foo<float>" time="{duration}"/>
|
||||
<testcase classname="<exe-name>.Template_Fixture_2" name="A TEMPLATE_PRODUCT_TEST_CASE_METHOD based test run that succeeds - Template_Foo<int>" time="{duration}"/>
|
||||
<testcase classname="<exe-name>.Template_Fixture_2" name="A TEMPLATE_PRODUCT_TEST_CASE_METHOD based test run that succeeds - std::vector<float>" time="{duration}"/>
|
||||
<testcase classname="<exe-name>.Template_Fixture_2" name="A TEMPLATE_PRODUCT_TEST_CASE_METHOD based test run that succeeds - std::vector<int>" time="{duration}"/>
|
||||
<testcase classname="<exe-name>.Template_Fixture" name="A TEMPLATE_TEST_CASE_METHOD based test run that fails - double" time="{duration}">
|
||||
<failure message="1.0 == 2" type="REQUIRE">
|
||||
Class.tests.cpp:<line number>
|
||||
@@ -101,6 +142,10 @@ Class.tests.cpp:<line number>
|
||||
</failure>
|
||||
</testcase>
|
||||
<testcase classname="<exe-name>.Fixture" name="A TEST_CASE_METHOD based test run that succeeds" time="{duration}"/>
|
||||
<testcase classname="<exe-name>.global" name="A Template product test case - Foo<float>" time="{duration}"/>
|
||||
<testcase classname="<exe-name>.global" name="A Template product test case - Foo<int>" time="{duration}"/>
|
||||
<testcase classname="<exe-name>.global" name="A Template product test case - std::vector<float>" time="{duration}"/>
|
||||
<testcase classname="<exe-name>.global" name="A Template product test case - std::vector<int>" time="{duration}"/>
|
||||
<testcase classname="<exe-name>.global" name="A comparison that uses literals instead of the normal constructor" time="{duration}"/>
|
||||
<testcase classname="<exe-name>.global" name="A couple of nested sections followed by a failure" time="{duration}">
|
||||
<failure type="FAIL">
|
||||
@@ -311,14 +356,37 @@ Message.tests.cpp:<line number>
|
||||
<testcase classname="<exe-name>.global" name="Floating point matchers: float/ULPs" time="{duration}"/>
|
||||
<testcase classname="<exe-name>.global" name="Floating point matchers: float/Composed" time="{duration}"/>
|
||||
<testcase classname="<exe-name>.global" name="Floating point matchers: float/Constructor validation" time="{duration}"/>
|
||||
<testcase classname="<exe-name>.global" name="Generators/one" time="{duration}"/>
|
||||
<testcase classname="<exe-name>.global" name="Generators/two" time="{duration}"/>
|
||||
<testcase classname="<exe-name>.global" name="Generators impl/range" time="{duration}"/>
|
||||
<testcase classname="<exe-name>.global" name="Generators impl/fixed values" time="{duration}"/>
|
||||
<testcase classname="<exe-name>.global" name="Generators impl/combined" time="{duration}"/>
|
||||
<testcase classname="<exe-name>.global" name="Generators impl/values" time="{duration}"/>
|
||||
<testcase classname="<exe-name>.global" name="Generators impl/values2" time="{duration}"/>
|
||||
<testcase classname="<exe-name>.global" name="Generators impl/type erasure" time="{duration}"/>
|
||||
<testcase classname="<exe-name>.global" name="Generators -- adapters/Filtering by predicate/Basic usage" time="{duration}"/>
|
||||
<testcase classname="<exe-name>.global" name="Generators -- adapters/Filtering by predicate/Throws if there are no matching values" time="{duration}"/>
|
||||
<testcase classname="<exe-name>.global" name="Generators -- adapters/Shortening a range" time="{duration}"/>
|
||||
<testcase classname="<exe-name>.global" name="Generators -- adapters/Transforming elements/Same type" time="{duration}"/>
|
||||
<testcase classname="<exe-name>.global" name="Generators -- adapters/Transforming elements/Different type" time="{duration}"/>
|
||||
<testcase classname="<exe-name>.global" name="Generators -- adapters/Transforming elements/Different deduced type" time="{duration}"/>
|
||||
<testcase classname="<exe-name>.global" name="Generators -- adapters/Repeating a generator" time="{duration}"/>
|
||||
<testcase classname="<exe-name>.global" name="Generators -- adapters/Chunking a generator into sized pieces/Number of elements in source is divisible by chunk size" time="{duration}"/>
|
||||
<testcase classname="<exe-name>.global" name="Generators -- adapters/Chunking a generator into sized pieces/Number of elements in source is not divisible by chunk size" time="{duration}"/>
|
||||
<testcase classname="<exe-name>.global" name="Generators -- adapters/Chunking a generator into sized pieces/Throws on too small generators" time="{duration}"/>
|
||||
<testcase classname="<exe-name>.global" name="Generators -- simple/one" time="{duration}"/>
|
||||
<testcase classname="<exe-name>.global" name="Generators -- simple/two" time="{duration}"/>
|
||||
<testcase classname="<exe-name>.global" name="Generators internals/Single value" time="{duration}"/>
|
||||
<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 with explicit return type" time="{duration}"/>
|
||||
<testcase classname="<exe-name>.global" name="Generators internals/Map with deduced return type" time="{duration}"/>
|
||||
<testcase classname="<exe-name>.global" name="Generators internals/Repeat/Singular repeat" time="{duration}"/>
|
||||
<testcase classname="<exe-name>.global" name="Generators internals/Repeat/Actual repeat" time="{duration}"/>
|
||||
<testcase classname="<exe-name>.global" name="Generators internals/Range/Positive auto step/Integer" time="{duration}"/>
|
||||
<testcase classname="<exe-name>.global" name="Generators internals/Range/Negative auto step/Integer" time="{duration}"/>
|
||||
<testcase classname="<exe-name>.global" name="Generators internals/Range/Positive manual step/Integer/Exact" time="{duration}"/>
|
||||
<testcase classname="<exe-name>.global" name="Generators internals/Range/Positive manual step/Integer/Slightly over end" time="{duration}"/>
|
||||
<testcase classname="<exe-name>.global" name="Generators internals/Range/Positive manual step/Integer/Slightly under end" time="{duration}"/>
|
||||
<testcase classname="<exe-name>.global" name="Generators internals/Range/Negative manual step/Integer/Exact" time="{duration}"/>
|
||||
<testcase classname="<exe-name>.global" name="Generators internals/Range/Negative manual step/Integer/Slightly over end" time="{duration}"/>
|
||||
<testcase classname="<exe-name>.global" name="Generators internals/Range/Negative manual step/Integer/Slightly under end" time="{duration}"/>
|
||||
<testcase classname="<exe-name>.global" name="Greater-than inequalities with different epsilons" time="{duration}"/>
|
||||
<testcase classname="<exe-name>.global" name="INFO and WARN do not abort tests" time="{duration}"/>
|
||||
<testcase classname="<exe-name>.global" name="INFO gets logged on failure" time="{duration}">
|
||||
@@ -387,6 +455,7 @@ Matchers.tests.cpp:<line number>
|
||||
Exception.tests.cpp:<line number>
|
||||
</failure>
|
||||
</testcase>
|
||||
<testcase classname="<exe-name>.global" name="Nested generators and captured variables" time="{duration}"/>
|
||||
<testcase classname="<exe-name>.global" name="Nice descriptive name" time="{duration}"/>
|
||||
<testcase classname="<exe-name>.global" name="Non-std exceptions can be translated" time="{duration}">
|
||||
<error type="TEST_CASE">
|
||||
@@ -526,6 +595,9 @@ Message.tests.cpp:<line number>
|
||||
<testcase classname="<exe-name>.global" name="Process can be configured on command line/use-colour/yes" time="{duration}"/>
|
||||
<testcase classname="<exe-name>.global" name="Process can be configured on command line/use-colour/no" time="{duration}"/>
|
||||
<testcase classname="<exe-name>.global" name="Process can be configured on command line/use-colour/error" time="{duration}"/>
|
||||
<testcase classname="<exe-name>.global" name="Product with differing arities - std::tuple<int, double, float>" time="{duration}"/>
|
||||
<testcase classname="<exe-name>.global" name="Product with differing arities - std::tuple<int, double>" time="{duration}"/>
|
||||
<testcase classname="<exe-name>.global" name="Product with differing arities - std::tuple<int>" time="{duration}"/>
|
||||
<testcase classname="<exe-name>.global" name="Reconstruction should be based on stringification: #914" time="{duration}">
|
||||
<failure message="Hey, its truthy!" type="CHECK">
|
||||
Decomposition.tests.cpp:<line number>
|
||||
@@ -660,13 +732,6 @@ Exception.tests.cpp:<line number>
|
||||
<testcase classname="<exe-name>.global" name="Tracker/successfully close one section, then find another/Re-enter - skips S1 and enters S2/Successfully close S2" time="{duration}"/>
|
||||
<testcase classname="<exe-name>.global" name="Tracker/successfully close one section, then find another/Re-enter - skips S1 and enters S2/fail S2" time="{duration}"/>
|
||||
<testcase classname="<exe-name>.global" name="Tracker/open a nested section" time="{duration}"/>
|
||||
<testcase classname="<exe-name>.global" name="Tracker/start a generator" time="{duration}"/>
|
||||
<testcase classname="<exe-name>.global" name="Tracker/start a generator/close outer section" time="{duration}"/>
|
||||
<testcase classname="<exe-name>.global" name="Tracker/start a generator/close outer section/Re-enter for second generation" time="{duration}"/>
|
||||
<testcase classname="<exe-name>.global" name="Tracker/start a generator/Start a new inner section" time="{duration}"/>
|
||||
<testcase classname="<exe-name>.global" name="Tracker/start a generator/Start a new inner section/Re-enter for second generation" time="{duration}"/>
|
||||
<testcase classname="<exe-name>.global" name="Tracker/start a generator/Fail an inner section" time="{duration}"/>
|
||||
<testcase classname="<exe-name>.global" name="Tracker/start a generator/Fail an inner section/Re-enter for second generation" time="{duration}"/>
|
||||
<testcase classname="<exe-name>.global" name="Unexpected exceptions can be translated" time="{duration}">
|
||||
<error type="TEST_CASE">
|
||||
3.14
|
||||
@@ -804,6 +869,12 @@ Misc.tests.cpp:<line number>
|
||||
<testcase classname="<exe-name>.global" name="just failure" time="{duration}">
|
||||
<failure type="FAIL">
|
||||
Previous info should not be seen
|
||||
Message.tests.cpp:<line number>
|
||||
</failure>
|
||||
</testcase>
|
||||
<testcase classname="<exe-name>.global" name="just failure after unscoped info" time="{duration}">
|
||||
<failure type="FAIL">
|
||||
previous unscoped info SHOULD not be seen
|
||||
Message.tests.cpp:<line number>
|
||||
</failure>
|
||||
</testcase>
|
||||
@@ -852,6 +923,7 @@ Testing if fib[7] (21) is even
|
||||
Misc.tests.cpp:<line number>
|
||||
</failure>
|
||||
</testcase>
|
||||
<testcase classname="<exe-name>.global" name="mix info, unscoped info and warning" time="{duration}"/>
|
||||
<testcase classname="<exe-name>.global" name="more nested SECTION tests/equal/doesn't equal" time="{duration}">
|
||||
<failure message="1 == 2" type="REQUIRE">
|
||||
Misc.tests.cpp:<line number>
|
||||
@@ -864,10 +936,30 @@ Misc.tests.cpp:<line number>
|
||||
<testcase classname="<exe-name>.global" name="non streamable - with conv. op" time="{duration}"/>
|
||||
<testcase classname="<exe-name>.global" name="non-copyable objects" time="{duration}"/>
|
||||
<testcase classname="<exe-name>.global" name="not allowed" time="{duration}"/>
|
||||
<testcase classname="<exe-name>.global" name="not prints unscoped info from previous failures" time="{duration}">
|
||||
<failure message="false" type="REQUIRE">
|
||||
this SHOULD be seen
|
||||
Message.tests.cpp:<line number>
|
||||
</failure>
|
||||
</testcase>
|
||||
<testcase classname="<exe-name>.global" name="null strings" time="{duration}"/>
|
||||
<testcase classname="<exe-name>.global" name="null_ptr" time="{duration}"/>
|
||||
<testcase classname="<exe-name>.global" name="pair<pair<int,const char *,pair<std::string,int> > -> toString" time="{duration}"/>
|
||||
<testcase classname="<exe-name>.global" name="pointer to class" time="{duration}"/>
|
||||
<testcase classname="<exe-name>.global" name="print unscoped info if passing unscoped info is printed" time="{duration}"/>
|
||||
<testcase classname="<exe-name>.global" name="prints unscoped info on failure" time="{duration}">
|
||||
<failure message="false" type="REQUIRE">
|
||||
this SHOULD be seen
|
||||
this SHOULD also be seen
|
||||
Message.tests.cpp:<line number>
|
||||
</failure>
|
||||
</testcase>
|
||||
<testcase classname="<exe-name>.global" name="prints unscoped info only for the first assertion" time="{duration}">
|
||||
<failure message="false" type="CHECK">
|
||||
this SHOULD be seen only ONCE
|
||||
Message.tests.cpp:<line number>
|
||||
</failure>
|
||||
</testcase>
|
||||
<testcase classname="<exe-name>.global" name="random SECTION tests/doesn't equal" time="{duration}"/>
|
||||
<testcase classname="<exe-name>.global" name="random SECTION tests/not equal" time="{duration}"/>
|
||||
<testcase classname="<exe-name>.global" name="replaceInPlace/replace single char" time="{duration}"/>
|
||||
@@ -887,6 +979,23 @@ Misc.tests.cpp:<line number>
|
||||
<failure message="false" type="REQUIRE">
|
||||
hi
|
||||
i := 7
|
||||
Message.tests.cpp:<line number>
|
||||
</failure>
|
||||
</testcase>
|
||||
<testcase classname="<exe-name>.global" name="shortened hide tags are split apart" time="{duration}"/>
|
||||
<testcase classname="<exe-name>.global" name="stacks unscoped info in loops" time="{duration}">
|
||||
<failure message="false" type="CHECK">
|
||||
Count 1 to 3...
|
||||
1
|
||||
2
|
||||
3
|
||||
Message.tests.cpp:<line number>
|
||||
</failure>
|
||||
<failure message="false" type="CHECK">
|
||||
Count 4 to 6...
|
||||
4
|
||||
5
|
||||
6
|
||||
Message.tests.cpp:<line number>
|
||||
</failure>
|
||||
</testcase>
|
||||
@@ -914,6 +1023,7 @@ Tricky.tests.cpp:<line number>
|
||||
<testcase classname="<exe-name>.global" name="stringify( vectors<has_maker_and_operator> )" time="{duration}"/>
|
||||
<testcase classname="<exe-name>.global" name="stringify( vectors<has_operator> )" time="{duration}"/>
|
||||
<testcase classname="<exe-name>.global" name="strlen3" time="{duration}"/>
|
||||
<testcase classname="<exe-name>.global" name="tables" time="{duration}"/>
|
||||
<testcase classname="<exe-name>.global" name="thrown std::strings are translated" time="{duration}">
|
||||
<error type="TEST_CASE">
|
||||
Why would you throw a std::string?
|
||||
@@ -948,11 +1058,13 @@ Exception.tests.cpp:<line number>
|
||||
<testcase classname="<exe-name>.global" name="xmlentitycheck/embedded xml: <test>it should be possible to embed xml characters, such as <, " or &, or even whole <xml>documents</xml> within an attribute</test>" time="{duration}"/>
|
||||
<testcase classname="<exe-name>.global" name="xmlentitycheck/encoded chars: these should all be encoded: &&&"""<<<&"<<&"" time="{duration}"/>
|
||||
<system-out>
|
||||
This would not be caught previously
|
||||
A string sent directly to stdout
|
||||
Message from section one
|
||||
Message from section two
|
||||
</system-out>
|
||||
<system-err>
|
||||
Nor would this
|
||||
A string sent directly to stderr
|
||||
A string sent to stderr via clog
|
||||
</system-err>
|
||||
|
File diff suppressed because it is too large
Load Diff
@@ -1,93 +1,260 @@
|
||||
#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 with explicit return type") {
|
||||
auto gen = map<double>([] (int i) {return 2.0 * i; }, values({ 1, 2, 3 }));
|
||||
REQUIRE(gen.get() == 2.0);
|
||||
REQUIRE(gen.next());
|
||||
REQUIRE(gen.get() == 4.0);
|
||||
REQUIRE(gen.next());
|
||||
REQUIRE(gen.get() == 6.0);
|
||||
REQUIRE_FALSE(gen.next());
|
||||
}
|
||||
SECTION("Map with deduced return type") {
|
||||
auto gen = map([] (int i) {return 2.0 * i; }, values({ 1, 2, 3 }));
|
||||
REQUIRE(gen.get() == 2.0);
|
||||
REQUIRE(gen.next());
|
||||
REQUIRE(gen.get() == 4.0);
|
||||
REQUIRE(gen.next());
|
||||
REQUIRE(gen.get() == 6.0);
|
||||
REQUIRE_FALSE(gen.next());
|
||||
}
|
||||
SECTION("Repeat") {
|
||||
SECTION("Singular repeat") {
|
||||
auto gen = repeat(1, value(3));
|
||||
REQUIRE(gen.get() == 3);
|
||||
REQUIRE_FALSE(gen.next());
|
||||
}
|
||||
SECTION("Actual repeat") {
|
||||
auto gen = repeat(2, values({ 1, 2, 3 }));
|
||||
REQUIRE(gen.get() == 1);
|
||||
REQUIRE(gen.next());
|
||||
REQUIRE(gen.get() == 2);
|
||||
REQUIRE(gen.next());
|
||||
REQUIRE(gen.get() == 3);
|
||||
REQUIRE(gen.next());
|
||||
REQUIRE(gen.get() == 1);
|
||||
REQUIRE(gen.next());
|
||||
REQUIRE(gen.get() == 2);
|
||||
REQUIRE(gen.next());
|
||||
REQUIRE(gen.get() == 3);
|
||||
REQUIRE_FALSE(gen.next());
|
||||
}
|
||||
}
|
||||
SECTION("Range") {
|
||||
SECTION("Positive auto step") {
|
||||
SECTION("Integer") {
|
||||
auto gen = range(-2, 2);
|
||||
REQUIRE(gen.get() == -2);
|
||||
REQUIRE(gen.next());
|
||||
REQUIRE(gen.get() == -1);
|
||||
REQUIRE(gen.next());
|
||||
REQUIRE(gen.get() == 0);
|
||||
REQUIRE(gen.next());
|
||||
REQUIRE(gen.get() == 1);
|
||||
REQUIRE_FALSE(gen.next());
|
||||
}
|
||||
}
|
||||
SECTION("Negative auto step") {
|
||||
SECTION("Integer") {
|
||||
auto gen = range(2, -2);
|
||||
REQUIRE(gen.get() == 2);
|
||||
REQUIRE(gen.next());
|
||||
REQUIRE(gen.get() == 1);
|
||||
REQUIRE(gen.next());
|
||||
REQUIRE(gen.get() == 0);
|
||||
REQUIRE(gen.next());
|
||||
REQUIRE(gen.get() == -1);
|
||||
REQUIRE_FALSE(gen.next());
|
||||
}
|
||||
}
|
||||
SECTION("Positive manual step") {
|
||||
SECTION("Integer") {
|
||||
SECTION("Exact") {
|
||||
auto gen = range(-7, 5, 3);
|
||||
REQUIRE(gen.get() == -7);
|
||||
REQUIRE(gen.next());
|
||||
REQUIRE(gen.get() == -4);
|
||||
REQUIRE(gen.next());
|
||||
REQUIRE(gen.get() == -1);
|
||||
REQUIRE(gen.next());
|
||||
REQUIRE(gen.get() == 2);
|
||||
REQUIRE_FALSE(gen.next());
|
||||
}
|
||||
SECTION("Slightly over end") {
|
||||
auto gen = range(-7, 4, 3);
|
||||
REQUIRE(gen.get() == -7);
|
||||
REQUIRE(gen.next());
|
||||
REQUIRE(gen.get() == -4);
|
||||
REQUIRE(gen.next());
|
||||
REQUIRE(gen.get() == -1);
|
||||
REQUIRE(gen.next());
|
||||
REQUIRE(gen.get() == 2);
|
||||
REQUIRE_FALSE(gen.next());
|
||||
}
|
||||
SECTION("Slightly under end") {
|
||||
auto gen = range(-7, 6, 3);
|
||||
REQUIRE(gen.get() == -7);
|
||||
REQUIRE(gen.next());
|
||||
REQUIRE(gen.get() == -4);
|
||||
REQUIRE(gen.next());
|
||||
REQUIRE(gen.get() == -1);
|
||||
REQUIRE(gen.next());
|
||||
REQUIRE(gen.get() == 2);
|
||||
REQUIRE(gen.next());
|
||||
REQUIRE(gen.get() == 5);
|
||||
REQUIRE_FALSE(gen.next());
|
||||
}
|
||||
}
|
||||
}
|
||||
SECTION("Negative manual step") {
|
||||
SECTION("Integer") {
|
||||
SECTION("Exact") {
|
||||
auto gen = range(5, -7, -3);
|
||||
REQUIRE(gen.get() == 5);
|
||||
REQUIRE(gen.next());
|
||||
REQUIRE(gen.get() == 2);
|
||||
REQUIRE(gen.next());
|
||||
REQUIRE(gen.get() == -1);
|
||||
REQUIRE(gen.next());
|
||||
REQUIRE(gen.get() == -4);
|
||||
REQUIRE_FALSE(gen.next());
|
||||
}
|
||||
SECTION("Slightly over end") {
|
||||
auto gen = range(5, -6, -3);
|
||||
REQUIRE(gen.get() == 5);
|
||||
REQUIRE(gen.next());
|
||||
REQUIRE(gen.get() == 2);
|
||||
REQUIRE(gen.next());
|
||||
REQUIRE(gen.get() == -1);
|
||||
REQUIRE(gen.next());
|
||||
REQUIRE(gen.get() == -4);
|
||||
REQUIRE_FALSE(gen.next());
|
||||
}
|
||||
SECTION("Slightly under end") {
|
||||
auto gen = range(5, -8, -3);
|
||||
REQUIRE(gen.get() == 5);
|
||||
REQUIRE(gen.next());
|
||||
REQUIRE(gen.get() == 2);
|
||||
REQUIRE(gen.next());
|
||||
REQUIRE(gen.get() == -1);
|
||||
REQUIRE(gen.next());
|
||||
REQUIRE(gen.get() == -4);
|
||||
REQUIRE(gen.next());
|
||||
REQUIRE(gen.get() == -7);
|
||||
REQUIRE_FALSE(gen.next());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
// todo: uncopyable type used in a generator
|
||||
// idea: uncopyable tag type for a stupid generator
|
||||
|
||||
namespace {
|
||||
struct non_copyable {
|
||||
non_copyable() = default;
|
||||
non_copyable(non_copyable const&) = delete;
|
||||
non_copyable& operator=(non_copyable const&) = delete;
|
||||
int value = -1;
|
||||
};
|
||||
|
||||
// This class shows how to implement a simple generator for Catch tests
|
||||
class TestGen : public Catch::Generators::IGenerator<int> {
|
||||
int current_number;
|
||||
public:
|
||||
|
||||
TestGen(non_copyable const& nc):
|
||||
current_number(nc.value) {}
|
||||
|
||||
int const& get() const override;
|
||||
bool next() override {
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
// Avoids -Wweak-vtables
|
||||
int const& TestGen::get() const {
|
||||
return current_number;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
TEST_CASE("GENERATE capture macros", "[generators][internals][.approvals]") {
|
||||
auto value = GENERATE(take(10, random(0, 10)));
|
||||
|
||||
non_copyable nc; nc.value = value;
|
||||
// neither `GENERATE_COPY` nor plain `GENERATE` would compile here
|
||||
auto value2 = GENERATE_REF(Catch::Generators::GeneratorWrapper<int>(std::unique_ptr<Catch::Generators::IGenerator<int>>(new TestGen(nc))));
|
||||
REQUIRE(value == value2);
|
||||
}
|
||||
|
@@ -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);
|
||||
}
|
||||
}
|
||||
|
@@ -40,3 +40,8 @@ TEST_CASE( "Tag alias can be registered against tag patterns" ) {
|
||||
CHECK_THROWS( registry.add( "[@no square bracket at end", "", Catch::SourceLineInfo( "file", 3 ) ) );
|
||||
}
|
||||
}
|
||||
|
||||
TEST_CASE("shortened hide tags are split apart") {
|
||||
auto testcase = Catch::makeTestCase(nullptr, "", {"fake test name", "[.magic-tag]"}, CATCH_INTERNAL_LINEINFO);
|
||||
REQUIRE_THAT(testcase.tags, Catch::VectorContains(std::string("magic-tag")) && Catch::VectorContains(std::string(".")));
|
||||
}
|
@@ -46,6 +46,18 @@ struct Template_Fixture {
|
||||
T m_a;
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
struct Template_Fixture_2 {
|
||||
Template_Fixture_2() {}
|
||||
|
||||
T m_a;
|
||||
};
|
||||
|
||||
template< typename T>
|
||||
struct Template_Foo {
|
||||
size_t size() { return 0; }
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
@@ -62,6 +74,11 @@ TEMPLATE_TEST_CASE_METHOD(Template_Fixture, "A TEMPLATE_TEST_CASE_METHOD based t
|
||||
REQUIRE( Template_Fixture<TestType>::m_a == 1 );
|
||||
}
|
||||
|
||||
TEMPLATE_PRODUCT_TEST_CASE_METHOD(Template_Fixture_2, "A TEMPLATE_PRODUCT_TEST_CASE_METHOD based test run that succeeds","[class][template][product]",(std::vector,Template_Foo),(int,float))
|
||||
{
|
||||
REQUIRE( Template_Fixture_2<TestType>::m_a.size() == 0 );
|
||||
}
|
||||
|
||||
// We should be able to write our tests within a different namespace
|
||||
namespace Inner
|
||||
{
|
||||
@@ -74,6 +91,11 @@ namespace Inner
|
||||
{
|
||||
REQUIRE( Template_Fixture<TestType>::m_a == 2 );
|
||||
}
|
||||
|
||||
TEMPLATE_PRODUCT_TEST_CASE_METHOD(Template_Fixture_2, "A TEMPLATE_PRODUCT_TEST_CASE_METHOD based test run that fails","[.][class][template][product][failing]",(std::vector,Template_Foo),(int,float))
|
||||
{
|
||||
REQUIRE( Template_Fixture_2<TestType>::m_a.size() == 1 );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
@@ -17,6 +17,11 @@ namespace foo {
|
||||
};
|
||||
}
|
||||
|
||||
namespace bar {
|
||||
template <typename... Ts>
|
||||
struct TypeList {};
|
||||
}
|
||||
|
||||
#ifdef __GNUC__
|
||||
#pragma GCC diagnostic ignored "-Wmissing-declarations"
|
||||
#endif
|
||||
@@ -184,6 +189,11 @@ namespace { namespace CompilationTests {
|
||||
STATIC_REQUIRE_FALSE( std::is_void<int>::value );
|
||||
}
|
||||
|
||||
TEST_CASE("#1548", "[compilation]") {
|
||||
using namespace bar;
|
||||
REQUIRE(std::is_same<TypeList<int>, TypeList<int>>::value);
|
||||
}
|
||||
|
||||
}} // namespace CompilationTests
|
||||
|
||||
|
||||
|
@@ -1,75 +1,63 @@
|
||||
#include "catch.hpp"
|
||||
|
||||
// Examples of usage of Generators
|
||||
#include <cstring>
|
||||
|
||||
// This test doesn't do much - it just shows how you can have several generators, of different
|
||||
// types (ie `i` and `j` are different types), can be sequenced using `,` and
|
||||
// can be expressed as named generators (like range) or as individual values.
|
||||
// Generators can be mixed with SECTIONs.
|
||||
// At time of writing the generated values are not automatically reported as part of the test
|
||||
// name or associated values - so we explicitly CAPTURE then (run this with `-s` to see them).
|
||||
// We could also incorporate them into the section names using DYNAMIC_SECTION. See the BDD
|
||||
// example later for more information.
|
||||
TEST_CASE("Generators") {
|
||||
|
||||
auto i = GENERATE( as<std::string>(), "a", "b", "c" );
|
||||
|
||||
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,97 @@ SCENARIO("Eating cucumbers", "[approvals]") {
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
// There are also some generic generator manipulators
|
||||
TEST_CASE("Generators -- adapters", "[generators][generic]") {
|
||||
// TODO: This won't work yet, introduce GENERATE_VAR?
|
||||
//auto numbers = Catch::Generators::values({ 1, 2, 3, 4, 5, 6 });
|
||||
SECTION("Filtering by predicate") {
|
||||
SECTION("Basic usage") {
|
||||
// This filters out all odd (false) numbers, giving [2, 4, 6]
|
||||
auto i = GENERATE(filter([] (int val) { return val % 2 == 0; }, values({ 1, 2, 3, 4, 5, 6 })));
|
||||
REQUIRE(i % 2 == 0);
|
||||
}
|
||||
SECTION("Throws if there are no matching values") {
|
||||
using namespace Catch::Generators;
|
||||
REQUIRE_THROWS_AS(filter([] (int) {return false; }, value(1)), Catch::GeneratorException);
|
||||
}
|
||||
}
|
||||
SECTION("Shortening a range") {
|
||||
// This takes the first 3 elements from the values, giving back [1, 2, 3]
|
||||
auto i = GENERATE(take(3, values({ 1, 2, 3, 4, 5, 6 })));
|
||||
REQUIRE(i < 4);
|
||||
}
|
||||
SECTION("Transforming elements") {
|
||||
SECTION("Same type") {
|
||||
// This doubles values [1, 2, 3] into [2, 4, 6]
|
||||
auto i = GENERATE(map([] (int val) { return val * 2; }, values({ 1, 2, 3 })));
|
||||
REQUIRE(i % 2 == 0);
|
||||
}
|
||||
SECTION("Different type") {
|
||||
// This takes a generator that returns ints and maps them into strings
|
||||
auto i = GENERATE(map<std::string>([] (int val) { return std::to_string(val); }, values({ 1, 2, 3 })));
|
||||
REQUIRE(i.size() == 1);
|
||||
}
|
||||
SECTION("Different deduced type") {
|
||||
// This takes a generator that returns ints and maps them into strings
|
||||
auto i = GENERATE(map([] (int val) { return std::to_string(val); }, values({ 1, 2, 3 })));
|
||||
REQUIRE(i.size() == 1);
|
||||
}
|
||||
}
|
||||
SECTION("Repeating a generator") {
|
||||
// This will return values [1, 2, 3, 1, 2, 3]
|
||||
auto j = GENERATE(repeat(2, values({ 1, 2, 3 })));
|
||||
REQUIRE(j > 0);
|
||||
}
|
||||
SECTION("Chunking a generator into sized pieces") {
|
||||
SECTION("Number of elements in source is divisible by chunk size") {
|
||||
auto chunk2 = GENERATE(chunk(2, values({ 1, 1, 2, 2, 3, 3 })));
|
||||
REQUIRE(chunk2.size() == 2);
|
||||
REQUIRE(chunk2.front() == chunk2.back());
|
||||
}
|
||||
SECTION("Number of elements in source is not divisible by chunk size") {
|
||||
auto chunk2 = GENERATE(chunk(2, values({ 1, 1, 2, 2, 3 })));
|
||||
REQUIRE(chunk2.size() == 2);
|
||||
REQUIRE(chunk2.front() == chunk2.back());
|
||||
REQUIRE(chunk2.front() < 3);
|
||||
}
|
||||
SECTION("Throws on too small generators") {
|
||||
using namespace Catch::Generators;
|
||||
REQUIRE_THROWS_AS(chunk(2, value(1)), Catch::GeneratorException);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Note that because of the non-reproducibility of distributions,
|
||||
// anything involving the random generators cannot be part of approvals
|
||||
TEST_CASE("Random generator", "[generators][.][approvals]") {
|
||||
SECTION("Infer int from integral arguments") {
|
||||
auto val = GENERATE(take(4, random(0, 1)));
|
||||
STATIC_REQUIRE(std::is_same<decltype(val), int>::value);
|
||||
static_cast<void>(val); // Silence VS 2015 unused variable warning
|
||||
}
|
||||
SECTION("Infer double from double arguments") {
|
||||
auto val = GENERATE(take(4, random(0., 1.)));
|
||||
STATIC_REQUIRE(std::is_same<decltype(val), double>::value);
|
||||
static_cast<void>(val); // Silence VS 2015 unused variable warning
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
TEST_CASE("Nested generators and captured variables", "[generators]") {
|
||||
// Workaround for old libstdc++
|
||||
using record = std::tuple<int, int>;
|
||||
// Set up 3 ranges to generate numbers from
|
||||
auto extent = GENERATE(table<int, int>({
|
||||
record{3, 7},
|
||||
record{-5, -3},
|
||||
record{90, 100}
|
||||
}));
|
||||
|
||||
auto from = std::get<0>(extent);
|
||||
auto to = std::get<1>(extent);
|
||||
|
||||
auto values = GENERATE_COPY(range(from, to));
|
||||
REQUIRE(values > -6);
|
||||
}
|
||||
|
@@ -132,6 +132,71 @@ TEST_CASE( "Pointers can be converted to strings", "[messages][.][approvals]" )
|
||||
WARN( "toString(p): " << ::Catch::Detail::stringify( &p ) );
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
static void unscoped_info( T msg ) {
|
||||
UNSCOPED_INFO( msg );
|
||||
}
|
||||
|
||||
TEST_CASE( "just unscoped info", "[unscoped][info]" ) {
|
||||
unscoped_info( "this should NOT be seen" );
|
||||
unscoped_info( "this also should NOT be seen" );
|
||||
}
|
||||
|
||||
TEST_CASE( "just failure after unscoped info", "[failing][.][unscoped][info]" ) {
|
||||
FAIL( "previous unscoped info SHOULD not be seen" );
|
||||
}
|
||||
|
||||
TEST_CASE( "print unscoped info if passing unscoped info is printed", "[unscoped][info]" ) {
|
||||
unscoped_info( "this MAY be seen IF info is printed for passing assertions" );
|
||||
REQUIRE( true );
|
||||
}
|
||||
|
||||
TEST_CASE( "prints unscoped info on failure", "[failing][.][unscoped][info]" ) {
|
||||
unscoped_info( "this SHOULD be seen" );
|
||||
unscoped_info( "this SHOULD also be seen" );
|
||||
REQUIRE( false );
|
||||
unscoped_info( "but this should NOT be seen" );
|
||||
}
|
||||
|
||||
TEST_CASE( "not prints unscoped info from previous failures", "[failing][.][unscoped][info]" ) {
|
||||
unscoped_info( "this MAY be seen only for the FIRST assertion IF info is printed for passing assertions" );
|
||||
REQUIRE( true );
|
||||
unscoped_info( "this MAY be seen only for the SECOND assertion IF info is printed for passing assertions" );
|
||||
REQUIRE( true );
|
||||
unscoped_info( "this SHOULD be seen" );
|
||||
REQUIRE( false );
|
||||
}
|
||||
|
||||
TEST_CASE( "prints unscoped info only for the first assertion", "[failing][.][unscoped][info]" ) {
|
||||
unscoped_info( "this SHOULD be seen only ONCE" );
|
||||
CHECK( false );
|
||||
CHECK( true );
|
||||
unscoped_info( "this MAY also be seen only ONCE IF info is printed for passing assertions" );
|
||||
CHECK( true );
|
||||
CHECK( true );
|
||||
}
|
||||
|
||||
TEST_CASE( "stacks unscoped info in loops", "[failing][.][unscoped][info]" ) {
|
||||
UNSCOPED_INFO("Count 1 to 3...");
|
||||
for (int i = 1; i <= 3; i++) {
|
||||
unscoped_info(i);
|
||||
}
|
||||
CHECK( false );
|
||||
|
||||
UNSCOPED_INFO("Count 4 to 6...");
|
||||
for (int i = 4; i <= 6; i++) {
|
||||
unscoped_info(i);
|
||||
}
|
||||
CHECK( false );
|
||||
}
|
||||
|
||||
TEST_CASE( "mix info, unscoped info and warning", "[unscoped][info]" ) {
|
||||
INFO("info");
|
||||
unscoped_info("unscoped info");
|
||||
WARN("and warn may mix");
|
||||
WARN("they are not cleared after warnings");
|
||||
}
|
||||
|
||||
TEST_CASE( "CAPTURE can deal with complex expressions", "[messages][capture]" ) {
|
||||
int a = 1;
|
||||
int b = 2;
|
||||
|
@@ -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) );
|
||||
|
@@ -19,6 +19,7 @@
|
||||
|
||||
#include <stdio.h>
|
||||
#include <sstream>
|
||||
#include <iostream>
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
TEST_CASE
|
||||
@@ -426,3 +427,10 @@ TEST_CASE( "Bitfields can be captured (#1027)" ) {
|
||||
REQUIRE( y.v == 0 );
|
||||
REQUIRE( 0 == y.v );
|
||||
}
|
||||
|
||||
TEST_CASE("#1514: stderr/stdout is not captured in tests aborted by an exception", "[output-capture][regression][.]") {
|
||||
std::cout << "This would not be caught previously\n" << std::flush;
|
||||
std::clog << "Nor would this\n" << std::flush;
|
||||
// FAIL aborts the test by throwing a Catch exception
|
||||
FAIL("1514");
|
||||
}
|
||||
|
@@ -6,8 +6,13 @@ import subprocess
|
||||
catchPath = os.path.dirname(os.path.realpath( os.path.dirname(sys.argv[0])))
|
||||
|
||||
def getBuildExecutable():
|
||||
dir = os.environ.get('CATCH_DEV_OUT_DIR', "cmake-build-debug/projects/SelfTest")
|
||||
return dir
|
||||
if os.name == 'nt':
|
||||
dir = os.environ.get('CATCH_DEV_OUT_DIR', "cmake-build-debug/projects/SelfTest.exe")
|
||||
return dir
|
||||
else:
|
||||
dir = os.environ.get('CATCH_DEV_OUT_DIR', "cmake-build-debug/projects/SelfTest")
|
||||
return dir
|
||||
|
||||
|
||||
def runAndCapture( args ):
|
||||
child = subprocess.Popen(" ".join( args ), shell=True, stdout=subprocess.PIPE)
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user