Compare commits

...

39 Commits

Author SHA1 Message Date
Martin Hořeňovský
3f0283de7a v3.3.2 2023-02-27 15:12:49 +01:00
Martin Hořeňovský
6fbb3f0723 Add IsNaN matcher 2023-02-26 00:14:32 +01:00
Martin Hořeňovský
9ff3cde87b Simplify test name creation for list-templated test cases 2023-02-23 15:12:14 +01:00
Martin Hořeňovský
4d802ca58f Use StringRef UDL in more preprocessor-generated strings 2023-02-23 13:25:08 +01:00
Martin Hořeňovský
13711be7cf Use StringRef UDL for generated generator names 2023-02-23 13:25:07 +01:00
Martin Hořeňovský
27ba26f743 Merge pull request #2643 from kisielk/patch-1
cmake-integration.md: Use "tests" as test target name in all examples.
2023-02-22 20:59:12 +01:00
Martin Hořeňovský
a209bcfb54 Update build instructions in contributing.md
We now show the more modern `-S {source}` instead of the old and
undocumented `-H{source}` CMake flag, and also show the available
presets, instead of individually specifying the different testing
options.

Closes #2593
2023-02-22 20:11:45 +01:00
Martin Hořeňovský
584973a485 Early evaluate line loc in NameAndLoc::operator==
I do not know if checking the tracker name or the tracker's file
part of the location first would provide better results, but
in the common case, the line part of the location check should be
rather unique, because different `SECTION`s will have different
source lines where they are defined.

I also propagated this same check into `ITracker::findChild`,
because this significantly improves performance of section tracking
in Debug builds -> 10% in macro benchmark heavily focused on section
tracking. In Release build there is usually no difference, because
the inliner will inline `NameAndLoc::operator==` into `findChild`,
and then eliminate the redundant check. (If the inliner decides
against, then this still improves the performance on average).
2023-02-20 15:19:57 +01:00
Martin Hořeňovský
4f7c8cb28a Avoid copying NameAndLocationRef when passed as argument
`NameAndLocationRef` is pretty large type, so even in release build,
it is unlikely to be passed in registers. In addition to the fact
that some platforms currently do not allow passing even small types
in register (Windows ABI!!), it is better to pass it as a ref,
effectively passing around a pointer.
2023-02-20 15:17:35 +01:00
Martin Hořeňovský
e1dbad4c9e Inline StringRef::operator==
This enables its inlining even without LTO, which in turns enables
callers to determine that two StringRefs are unequals with simple
comparison of two numbers, without any function calls.
2023-02-20 15:05:09 +01:00
Martin Hořeňovský
2befd98da2 Inline some non-virtual functions in ITracker and TrackerContext 2023-02-20 15:02:50 +01:00
Martin Hořeňovský
00f259aeb2 Move captured output into TestCaseStats when sending testCaseEnded 2023-02-20 14:48:39 +01:00
Martin Hořeňovský
fed1436246 Avoid allocating trimmed name for SectionTracker 2023-02-20 14:32:46 +01:00
Martin Hořeňovský
0477326ad9 Directly construct empty string for invalid SectionInfo 2023-02-20 14:32:14 +01:00
Martin Hořeňovský
f04c93462b Small refactoring in AssertionResult 2023-02-20 14:32:12 +01:00
Martin Hořeňovský
1af351cea1 Remove unused TrackerContext::endRun function 2023-02-20 14:32:10 +01:00
Martin Hořeňovský
dcc9fa3f38 Use StringRef UDL for more string literals when expanding macros
* for the name of the listener when registering listener
* for the original expression in assertion macros
2023-02-20 14:31:26 +01:00
Martin Hořeňovský
bf6a15a69a Rewrite -# docs 2023-02-17 15:55:21 +01:00
Martin Hořeňovský
6135a78c31 Don't insert the foo part of [.foo] tag twice when parsing test spec 2023-02-13 22:16:53 +01:00
Martin Hořeňovský
e8ba329b6c Add support for iterator+sentinel pairs in Contains matcher 2023-02-10 23:25:45 +01:00
Martin Hořeňovský
4aa88299af Preconstruct error message in RunContext::handleIncomplete 2023-02-10 21:36:04 +01:00
Kamil Kisiel
4ff9be3bc5 cmake-integration.md: Use "tests" as test target name in all examples. 2023-02-10 11:09:26 -08:00
Martin Hořeňovský
76cdaa3b51 Merge pull request #2637 from jbadwaik/nvhpc_unused_warning
Suppress declared_but_not_referenced warning for NVHPC
2023-02-08 19:51:39 +01:00
Jayesh Badwaik (FZ Juelich)
644294df60 Suppress declared_but_not_referenced warning for NVHPC
Catch2 suppresses unused variable and equivalent warnings in a couple
  of places, but most importantly, in the declaration of autoRegistrar
  in test registry. This warning gets triggered by NVHPC compiler. The
  current patch adds three macros, namely:

      CATCH_INTERNAL_START_WARNINGS_SUPPRESSION
      CATCH_INTERNAL_SUPPRESS_UNUSED_VARIABLE_WARNINGS
      CATCH_INTERNAL_STOP_WARNINGS_SUPPRESSION

  for the NVHPC Compiler which in particular prevents that warning from
  occurring. The compiler is detected completely separately from the
  other compilers in this patch, because from what I found out, NVHPC
  defines __GNUC__ as well for some reason. (I suspect because it
  advertises itself as GNU compatible.)

  We also add a condition to make sure that the `__GNUC__` path is not
  taken by the NVHPC compiler.
2023-02-08 12:40:55 +01:00
Martin Hořeňovský
cefa8fcf32 Enable use of UnorderedRangeEquals with iterator+sentinel pairs 2023-02-06 15:34:38 +01:00
Martin Hořeňovský
772fa3f790 Add Catch::Detail::is_permutation that supports sentinels
Also split out helpers for testing matcher ranges (types whose
begin/end/empty/etc require ADL lookup, types whose iteration
uses iterator + sentinel pair, etc) into their own file.
2023-02-06 15:29:01 +01:00
Martin Hořeňovský
f3c0a3cd09 Fix RangeEquals matcher to handle iterator + sentinel ranges
Also added tests for types that require ADL lookup for their
`begin` and `end`.
2023-02-03 18:22:41 +01:00
Martin Hořeňovský
42d9d4533e Add test for empty result of filter generator 2023-02-01 18:27:41 +01:00
Martin Hořeňovský
618d44c448 Update docs about thread safe assertions 2023-02-01 15:24:47 +01:00
Martin Hořeňovský
388f7e1737 Cleanup unneeded allocations from reporters
The CompactReporter changes save 21 (430764 -> 430743) allocations
when running the SelfTest binary in default configuration. They
save about 500 allocations when running the binary with `-s`.
2023-01-30 15:30:36 +01:00
Martin Hořeňovský
2ab20a0e00 v3.3.1 2023-01-29 23:18:57 +01:00
Martin Hořeňovský
60264b8807 Avoid copying strings in sonarqube when sorting tests by file 2023-01-29 20:45:13 +01:00
Martin Hořeňovský
65ffee5189 Don't take ownership of SECTION's name for inactive sections
This eliminates 1945 (432709 -> 430764) allocations from running
`./tests/SelfTest -o /dev/null`. In general terms, this saves
an allocation every time an unvisited `SECTION` is passed, which
means that the saved allocations are quadratic in number of sibling
(same level) `SECTION`s in a test case.
2023-01-29 10:44:20 +01:00
Martin Hořeňovský
43f02027e4 Avoid allocations when looking for trackers
Now we delay allocating owning `NameAndLocation` instances until
we construct a new tracker (because a tracker's lifetime can be
significantly different from the underlying tracked-thing's name).

This saves 4239 allocations (436948 -> 432709) when running
`./tests/SelfTest -o /dev/null`, at some cost to code clarity
due to introducing a new ref type, `NameAndLocationRef`.
2023-01-29 10:14:20 +01:00
Martin Hořeňovský
906552f8c8 Clean up extraneous copies in Messages
This removes 109 allocations from running `tests/SelfTest`
(437057 -> 436948).
2023-01-28 22:14:37 +01:00
Martin Hořeňovský
356dfc1439 Move name and sample analysis in benchmarks into BenchmarkStats
This always saves 1 allocation per benchmark, and another two
allocations if the benchmark name is longer than the SSO buffer.
2023-01-28 21:40:59 +01:00
Martin Hořeňovský
e5d1eb757f Move AssertionResultData into AssertionResult in RunContext
When running `./tests/SelfTest -o /dev/null`, this saves 109
allocations (437167 -> 437058).
2023-01-28 19:57:38 +01:00
Martin Hořeňovský
2403f5620e Move SectionEndInfo into sectionEnded call in SECTION's destructor
When running `./tests/SelfTest -o /dev/null`, this saves 1272
allocations (437439 -> 437167). In general, this saves multiple
allocations per end of an entered `SECTION`, if the section name
was too long for SSO, because `RunContext::sectionEnded` can then
move the section's name further down the callstack.
2023-01-28 13:00:30 +01:00
Martin Hořeňovský
d58491c85a Move sectionInfo into sectionEndInfo when SECTION ends
When running `./tests/SelfTest -o /dev/null`, this saves 468
allocations (438907 -> 437439). In general, this saves 1 allocation
every time an entered `SECTION` ends and the section name was long
enough to move out of the SSO buffer.
2023-01-28 12:56:29 +01:00
78 changed files with 2166 additions and 720 deletions

View File

@@ -31,7 +31,7 @@ if (CMAKE_BINARY_DIR STREQUAL CMAKE_CURRENT_SOURCE_DIR)
endif()
project(Catch2
VERSION 3.3.0 # CML version placeholder, don't delete
VERSION 3.3.2 # CML version placeholder, don't delete
LANGUAGES CXX
# HOMEPAGE_URL is not supported until CMake version 3.12, which
# we do not target yet.

View File

@@ -90,12 +90,12 @@ cmake_minimum_required(VERSION 3.5)
project(baz LANGUAGES CXX VERSION 0.0.1)
find_package(Catch2 REQUIRED)
add_executable(foo test.cpp)
target_link_libraries(foo PRIVATE Catch2::Catch2)
add_executable(tests test.cpp)
target_link_libraries(tests PRIVATE Catch2::Catch2)
include(CTest)
include(Catch)
catch_discover_tests(foo)
catch_discover_tests(tests)
```
When using `FetchContent`, `include(Catch)` will fail unless
@@ -108,7 +108,7 @@ directory.
list(APPEND CMAKE_MODULE_PATH ${catch2_SOURCE_DIR}/extras)
include(CTest)
include(Catch)
catch_discover_tests()
catch_discover_tests(tests)
```
#### Customization
@@ -222,12 +222,12 @@ cmake_minimum_required(VERSION 3.5)
project(baz LANGUAGES CXX VERSION 0.0.1)
find_package(Catch2 REQUIRED)
add_executable(foo test.cpp)
target_link_libraries(foo PRIVATE Catch2::Catch2)
add_executable(tests test.cpp)
target_link_libraries(tests PRIVATE Catch2::Catch2)
include(CTest)
include(ParseAndAddCatchTests)
ParseAndAddCatchTests(foo)
ParseAndAddCatchTests(tests)
```

View File

@@ -507,10 +507,13 @@ start of the first section.</br>
## Filenames as tags
<pre>-#, --filenames-as-tags</pre>
When this option is used then every test is given an additional tag which is formed of the unqualified
filename it is found in, with any extension stripped, prefixed with the `#` character.
This option adds an extra tag to all test cases. The tag is `#` followed
by the unqualified filename the test case is defined in, with the _last_
extension stripped out.
For example, tests within the file `tests\SelfTest\UsageTests\BDD.tests.cpp`
will be given the `[#BDD.tests]` tag.
So, for example, tests within the file `~\Dev\MyProject\Ferrets.cpp` would be tagged `[#Ferrets]`.
<a id="colour-mode"></a>
## Override output colouring

View File

@@ -55,6 +55,15 @@ tests from `SelfTest` through a specific reporter and then compare the
generated output with a known good output ("Baseline"). By default, new
tests should be placed here.
To configure a Catch2 build with just the basic tests, use the `basic-tests`
preset, like so:
```
# Assuming you are in Catch2's root folder
cmake -B basic-test-build -S . -DCMAKE_BUILD_TYPE=Debug --preset basic-tests
```
However, not all tests can be written as plain unit tests. For example,
checking that Catch2 orders tests randomly when asked to, and that this
random ordering is subset-invariant, is better done as an integration
@@ -76,21 +85,23 @@ configuration and require separate compilation.
Finally, CMake config tests test that you set Catch2's compile-time
configuration options through CMake, using CMake options of the same name.
None of these tests are enabled by default. To enable them, add
These test categories can be enabled one by one, by passing
`-DCATCH_BUILD_EXAMPLES=ON`, `-DCATCH_BUILD_EXTRA_TESTS=ON`, and
`-DCATCH_ENABLE_CONFIGURE_TESTS=ON` when configuration the CMake build.
`-DCATCH_ENABLE_CONFIGURE_TESTS=ON` when configuring the build.
Bringing this all together, the steps below should configure, build,
and run all tests in the `Debug` compilation.
Catch2 also provides a preset that promises to enable _all_ test types,
`all-tests`.
The snippet below will build & run all tests, in `Debug` compilation mode.
<!-- snippet: catch2-build-and-test -->
<a id='snippet-catch2-build-and-test'></a>
```sh
# 1. Regenerate the amalgamated distribution
# 1. Regenerate the amalgamated distribution (some tests are built against it)
./tools/scripts/generateAmalgamatedFiles.py
# 2. Configure the full test build
cmake -Bdebug-build -H. -DCMAKE_BUILD_TYPE=Debug -DCATCH_DEVELOPMENT_BUILD=ON -DCATCH_BUILD_EXAMPLES=ON -DCATCH_BUILD_EXTRA_TESTS=ON
cmake -B debug-build -S . -DCMAKE_BUILD_TYPE=Debug --preset all-tests
# 3. Run the actual build
cmake --build debug-build

View File

@@ -88,8 +88,8 @@ because only one thread passes the `REQUIRE` macro and this is not
REQUIRE(cnt == 16);
```
Because C++11 provides the necessary tools to do this, we are planning
to remove this limitation in the future.
We currently do not plan to support thread-safe assertions.
### Process isolation in a test
Catch does not support running tests in isolated (forked) processes. While this might in the future, the fact that Windows does not support forking and only allows full-on process creation and the desire to keep code as similar as possible across platforms, mean that this is likely to take significant development time, that is not currently available.

View File

@@ -141,18 +141,27 @@ are a permutation of the ones in `some_vec`.
### Floating point matchers
Catch2 provides 3 matchers that target floating point numbers. These
Catch2 provides 4 matchers that target floating point numbers. These
are:
* `WithinAbs(double target, double margin)`,
* `WithinULP(FloatingPoint target, uint64_t maxUlpDiff)`, and
* `WithinRel(FloatingPoint target, FloatingPoint eps)`.
* `IsNaN()`
> `WithinRel` matcher was introduced in Catch2 2.10.0
For more details, read [the docs on comparing floating point
> `IsNaN` matcher was introduced in Catch2 3.3.2.
The first three serve to compare two floating pointe numbers. For more
details about how they work, read [the docs on comparing floating point
numbers](comparing-floating-point-numbers.md#floating-point-matchers).
`IsNaN` then does exactly what it says on the tin. It matches the input
if it is a NaN (Not a Number). The advantage of using it over just plain
`REQUIRE(std::isnan(x))`, is that if the check fails, with `REQUIRE` you
won't see the value of `x`, but with `REQUIRE_THAT(x, IsNaN())`, you will.
### Miscellaneous matchers

View File

@@ -2,6 +2,8 @@
# Release notes
**Contents**<br>
[3.3.2](#332)<br>
[3.3.1](#331)<br>
[3.3.0](#330)<br>
[3.2.1](#321)<br>
[3.2.0](#320)<br>
@@ -55,6 +57,38 @@
## 3.3.2
### Improvements
* Further reduced allocations
* The compact, console, TAP and XML reporters perform less allocations in various cases
* Removed 1 allocation per entered `SECTION`/`TEST_CASE`.
* Removed 2 allocations per test case exit, if stdout/stderr is captured
* Improved performance
* Section tracking is 10%-25% faster than in v3.3.0
* Assertion handling is 5%-10% faster than in v3.3.0
* Test case registration is 1%-2% faster than in v3.3.0
* Tiny speedup for registering listeners
* Tiny speedup for `CAPTURE`, `TEST_CASE_METHOD`, `METHOD_AS_TEST_CASE`, and `TEMPLATE_LIST_TEST_*` macros.
* `Contains`, `RangeEquals` and `UnorderedRangeEquals` matchers now support ranges with iterator + sentinel pair
* Added `IsNaN` matcher
* Unlike `REQUIRE(isnan(x))`, `REQUIRE_THAT(x, IsNaN())` shows you the value of `x`.
* Suppressed `declared_but_not_referenced` warning for NVHPC (#2637)
### Fixes
* Fixed performance regression in section tracking introduced in v3.3.1
* Extreme cases would cause the tracking to run about 4x slower than in 3.3.0
## 3.3.1
### Improvements
* Reduced allocations and improved performance
* The exact improvements are dependent on your usage of Catch2.
* For example running Catch2's SelfTest binary performs 8k less allocations.
* The main improvement comes from smarter handling of `SECTION`s, especially sibling `SECTION`s
## 3.3.0
### Improvements

View File

@@ -69,7 +69,8 @@ All tag names beginning with non-alphanumeric characters are reserved by Catch.
* `[!nonportable]` - Indicates that behaviour may vary between platforms or compilers.
* `[#<filename>]` - running with `-#` or `--filenames-as-tags` causes Catch to add the filename, prefixed with `#` (and with any extension stripped), as a tag to all contained tests, e.g. tests in testfile.cpp would all be tagged `[#testfile]`.
* `[#<filename>]` - these tags are added to test cases when you run Catch2
with [`-#` or `--filenames-as-tags`](command-line.md#filenames-as-tags).
* `[@<alias>]` - tag aliases all begin with `@` (see below).

View File

@@ -5,8 +5,8 @@
// SPDX-License-Identifier: BSL-1.0
// Catch v3.3.0
// Generated: 2023-01-22 19:46:24.251531
// Catch v3.3.2
// Generated: 2023-02-26 10:28:48.270752
// ----------------------------------------------------------
// This file is an amalgamation of multiple different files.
// You probably shouldn't edit it directly.
@@ -428,9 +428,9 @@ namespace Catch {
return reconstructedExpression;
}
AssertionResult::AssertionResult( AssertionInfo const& info, AssertionResultData const& data )
AssertionResult::AssertionResult( AssertionInfo const& info, AssertionResultData&& data )
: m_info( info ),
m_resultData( data )
m_resultData( CATCH_MOVE(data) )
{}
// Result was a success
@@ -469,16 +469,15 @@ namespace Catch {
}
std::string AssertionResult::getExpressionInMacro() const {
std::string expr;
if( m_info.macroName.empty() )
expr = static_cast<std::string>(m_info.capturedExpression);
else {
expr.reserve( m_info.macroName.size() + m_info.capturedExpression.size() + 4 );
expr += m_info.macroName;
expr += "( ";
expr += m_info.capturedExpression;
expr += " )";
if ( m_info.macroName.empty() ) {
return static_cast<std::string>( m_info.capturedExpression );
}
std::string expr;
expr.reserve( m_info.macroName.size() + m_info.capturedExpression.size() + 4 );
expr += m_info.macroName;
expr += "( ";
expr += m_info.capturedExpression;
expr += " )";
return expr;
}
@@ -758,8 +757,8 @@ namespace Catch {
////////////////////////////////////////////////////////////////////////////
ScopedMessage::ScopedMessage( MessageBuilder const& builder ):
m_info( builder.m_info ) {
ScopedMessage::ScopedMessage( MessageBuilder&& builder ):
m_info( CATCH_MOVE(builder.m_info) ) {
m_info.message = builder.m_stream.str();
getResultCapture().pushScopedMessage( m_info );
}
@@ -2022,7 +2021,7 @@ namespace Catch {
}
Version const& libraryVersion() {
static Version version( 3, 3, 0, "", 0 );
static Version version( 3, 3, 2, "", 0 );
return version;
}
@@ -2179,18 +2178,17 @@ namespace Catch {
// Copy message into messages list.
// !TBD This should have been done earlier, somewhere
MessageBuilder builder( assertionResult.getTestMacroName(), assertionResult.getSourceInfo(), assertionResult.getResultType() );
builder << assertionResult.getMessage();
builder.m_info.message = builder.m_stream.str();
builder.m_info.message = static_cast<std::string>(assertionResult.getMessage());
infoMessages.push_back( builder.m_info );
infoMessages.push_back( CATCH_MOVE(builder.m_info) );
}
}
SectionStats::SectionStats( SectionInfo const& _sectionInfo,
SectionStats::SectionStats( SectionInfo&& _sectionInfo,
Counts const& _assertions,
double _durationInSeconds,
bool _missingAssertions )
: sectionInfo( _sectionInfo ),
: sectionInfo( CATCH_MOVE(_sectionInfo) ),
assertions( _assertions ),
durationInSeconds( _durationInSeconds ),
missingAssertions( _missingAssertions )
@@ -2199,13 +2197,13 @@ namespace Catch {
TestCaseStats::TestCaseStats( TestCaseInfo const& _testInfo,
Totals const& _totals,
std::string const& _stdOut,
std::string const& _stdErr,
std::string&& _stdOut,
std::string&& _stdErr,
bool _aborting )
: testInfo( &_testInfo ),
totals( _totals ),
stdOut( _stdOut ),
stdErr( _stdErr ),
stdOut( CATCH_MOVE(_stdOut) ),
stdErr( CATCH_MOVE(_stdErr) ),
aborting( _aborting )
{}
@@ -4993,12 +4991,12 @@ namespace Catch {
struct GeneratorTracker : TestCaseTracking::TrackerBase, IGeneratorTracker {
GeneratorBasePtr m_generator;
GeneratorTracker( TestCaseTracking::NameAndLocation const& nameAndLocation, TrackerContext& ctx, ITracker* parent )
: TrackerBase( nameAndLocation, ctx, parent )
GeneratorTracker( TestCaseTracking::NameAndLocation&& nameAndLocation, TrackerContext& ctx, ITracker* parent )
: TrackerBase( CATCH_MOVE(nameAndLocation), ctx, parent )
{}
~GeneratorTracker() override;
static GeneratorTracker* acquire( TrackerContext& ctx, TestCaseTracking::NameAndLocation const& nameAndLocation ) {
static GeneratorTracker* acquire( TrackerContext& ctx, TestCaseTracking::NameAndLocationRef const& nameAndLocation ) {
GeneratorTracker* tracker;
ITracker& currentTracker = ctx.currentTracker();
@@ -5140,13 +5138,8 @@ namespace Catch {
Totals RunContext::runTest(TestCaseHandle const& testCase) {
const Totals prevTotals = m_totals;
std::string redirectedCout;
std::string redirectedCerr;
auto const& testInfo = testCase.getTestCaseInfo();
m_reporter->testCaseStarting(testInfo);
m_activeTestCase = &testCase;
@@ -5188,9 +5181,11 @@ namespace Catch {
seedRng( *m_config );
uint64_t testRuns = 0;
std::string redirectedCout;
std::string redirectedCerr;
do {
m_trackerContext.startCycle();
m_testCaseTracker = &SectionTracker::acquire(m_trackerContext, TestCaseTracking::NameAndLocation(testInfo.name, testInfo.lineInfo));
m_testCaseTracker = &SectionTracker::acquire(m_trackerContext, TestCaseTracking::NameAndLocationRef(testInfo.name, testInfo.lineInfo));
m_reporter->testCasePartialStarting(testInfo, testRuns);
@@ -5201,7 +5196,7 @@ namespace Catch {
redirectedCerr += oneRunCerr;
const auto singleRunTotals = m_totals.delta(beforeRunTotals);
auto statsForOneRun = TestCaseStats(testInfo, singleRunTotals, oneRunCout, oneRunCerr, aborting());
auto statsForOneRun = TestCaseStats(testInfo, singleRunTotals, CATCH_MOVE(oneRunCout), CATCH_MOVE(oneRunCerr), aborting());
m_reporter->testCasePartialEnded(statsForOneRun, testRuns);
++testRuns;
@@ -5216,8 +5211,8 @@ namespace Catch {
m_totals.testCases += deltaTotals.testCases;
m_reporter->testCaseEnded(TestCaseStats(testInfo,
deltaTotals,
redirectedCout,
redirectedCerr,
CATCH_MOVE(redirectedCout),
CATCH_MOVE(redirectedCerr),
aborting()));
m_activeTestCase = nullptr;
@@ -5261,12 +5256,17 @@ namespace Catch {
m_lastAssertionInfo.capturedExpression = "{Unknown expression after the reported line}"_sr;
}
bool RunContext::sectionStarted(SectionInfo const & sectionInfo, Counts & assertions) {
ITracker& sectionTracker = SectionTracker::acquire(m_trackerContext, TestCaseTracking::NameAndLocation(sectionInfo.name, sectionInfo.lineInfo));
bool RunContext::sectionStarted(StringRef sectionName, SourceLineInfo const& sectionLineInfo, Counts & assertions) {
ITracker& sectionTracker =
SectionTracker::acquire( m_trackerContext,
TestCaseTracking::NameAndLocationRef(
sectionName, sectionLineInfo ) );
if (!sectionTracker.isOpen())
return false;
m_activeSections.push_back(&sectionTracker);
SectionInfo sectionInfo( sectionLineInfo, static_cast<std::string>(sectionName) );
m_lastAssertionInfo.lineInfo = sectionInfo.lineInfo;
m_reporter->sectionStarting(sectionInfo);
@@ -5281,8 +5281,8 @@ namespace Catch {
using namespace Generators;
GeneratorTracker* tracker = GeneratorTracker::acquire(
m_trackerContext,
TestCaseTracking::NameAndLocation(
static_cast<std::string>( generatorName ), lineInfo ) );
TestCaseTracking::NameAndLocationRef(
generatorName, lineInfo ) );
m_lastAssertionInfo.lineInfo = lineInfo;
return tracker;
}
@@ -5299,7 +5299,7 @@ namespace Catch {
"Trying to create tracker for a genreator that already has one" );
auto newTracker = Catch::Detail::make_unique<Generators::GeneratorTracker>(
nameAndLoc, m_trackerContext, &currentTracker );
CATCH_MOVE(nameAndLoc), m_trackerContext, &currentTracker );
auto ret = newTracker.get();
currentTracker.addChild( CATCH_MOVE( newTracker ) );
@@ -5320,7 +5320,7 @@ namespace Catch {
return true;
}
void RunContext::sectionEnded(SectionEndInfo const & endInfo) {
void RunContext::sectionEnded(SectionEndInfo&& endInfo) {
Counts assertions = m_totals.assertions - endInfo.prevAssertions;
bool missingAssertions = testForMissingAssertions(assertions);
@@ -5329,19 +5329,20 @@ namespace Catch {
m_activeSections.pop_back();
}
m_reporter->sectionEnded(SectionStats(endInfo.sectionInfo, assertions, endInfo.durationInSeconds, missingAssertions));
m_reporter->sectionEnded(SectionStats(CATCH_MOVE(endInfo.sectionInfo), assertions, endInfo.durationInSeconds, missingAssertions));
m_messages.clear();
m_messageScopes.clear();
}
void RunContext::sectionEndedEarly(SectionEndInfo const & endInfo) {
if (m_unfinishedSections.empty())
void RunContext::sectionEndedEarly(SectionEndInfo&& endInfo) {
if ( m_unfinishedSections.empty() ) {
m_activeSections.back()->fail();
else
} else {
m_activeSections.back()->close();
}
m_activeSections.pop_back();
m_unfinishedSections.push_back(endInfo);
m_unfinishedSections.push_back(CATCH_MOVE(endInfo));
}
void RunContext::benchmarkPreparing( StringRef name ) {
@@ -5365,8 +5366,8 @@ 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 );
void RunContext::emplaceUnscopedMessage( MessageBuilder&& builder ) {
m_messageScopes.emplace_back( CATCH_MOVE(builder) );
}
std::string RunContext::getCurrentTestName() const {
@@ -5391,7 +5392,7 @@ namespace Catch {
// Instead, fake a result data.
AssertionResultData tempResult( ResultWas::FatalErrorCondition, { false } );
tempResult.message = static_cast<std::string>(message);
AssertionResult result(m_lastAssertionInfo, tempResult);
AssertionResult result(m_lastAssertionInfo, CATCH_MOVE(tempResult));
assertionEnded(result);
@@ -5403,7 +5404,7 @@ namespace Catch {
Counts assertions;
assertions.failed = 1;
SectionStats testCaseSectionStats(testCaseSection, assertions, 0, false);
SectionStats testCaseSectionStats(CATCH_MOVE(testCaseSection), assertions, 0, false);
m_reporter->sectionEnded(testCaseSectionStats);
auto const& testInfo = m_activeTestCase->getTestCaseInfo();
@@ -5482,7 +5483,7 @@ namespace Catch {
m_messages.clear();
m_messageScopes.clear();
SectionStats testCaseSectionStats(testCaseSection, assertions, duration, missingAssertions);
SectionStats testCaseSectionStats(CATCH_MOVE(testCaseSection), assertions, duration, missingAssertions);
m_reporter->sectionEnded(testCaseSectionStats);
}
@@ -5506,7 +5507,7 @@ namespace Catch {
itEnd = m_unfinishedSections.rend();
it != itEnd;
++it)
sectionEnded(*it);
sectionEnded(CATCH_MOVE(*it));
m_unfinishedSections.clear();
}
@@ -5542,7 +5543,7 @@ namespace Catch {
m_lastAssertionInfo = info;
AssertionResultData data( resultType, LazyExpression( negated ) );
AssertionResult assertionResult{ info, data };
AssertionResult assertionResult{ info, CATCH_MOVE( data ) };
assertionResult.m_resultData.lazyExpression.m_transientExpression = expr;
assertionEnded( assertionResult );
@@ -5560,7 +5561,8 @@ namespace Catch {
AssertionResultData data( resultType, LazyExpression( false ) );
data.message = static_cast<std::string>(message);
AssertionResult assertionResult{ m_lastAssertionInfo, data };
AssertionResult assertionResult{ m_lastAssertionInfo,
CATCH_MOVE( data ) };
assertionEnded( assertionResult );
if ( !assertionResult.isOk() ) {
populateReaction( reaction );
@@ -5586,7 +5588,7 @@ namespace Catch {
AssertionResultData data( ResultWas::ThrewException, LazyExpression( false ) );
data.message = message;
AssertionResult assertionResult{ info, data };
AssertionResult assertionResult{ info, CATCH_MOVE(data) };
assertionEnded( assertionResult );
populateReaction( reaction );
}
@@ -5599,11 +5601,12 @@ namespace Catch {
void RunContext::handleIncomplete(
AssertionInfo const& info
) {
using namespace std::string_literals;
m_lastAssertionInfo = info;
AssertionResultData data( ResultWas::ThrewException, LazyExpression( false ) );
data.message = "Exception translation was disabled by CATCH_CONFIG_FAST_COMPILE";
AssertionResult assertionResult{ info, data };
data.message = "Exception translation was disabled by CATCH_CONFIG_FAST_COMPILE"s;
AssertionResult assertionResult{ info, CATCH_MOVE( data ) };
assertionEnded( assertionResult );
}
void RunContext::handleNonExpr(
@@ -5614,7 +5617,7 @@ namespace Catch {
m_lastAssertionInfo = info;
AssertionResultData data( resultType, LazyExpression( false ) );
AssertionResult assertionResult{ info, data };
AssertionResult assertionResult{ info, CATCH_MOVE( data ) };
assertionEnded( assertionResult );
if( !assertionResult.isOk() )
@@ -5646,7 +5649,7 @@ namespace Catch {
Section::Section( SectionInfo&& info ):
m_info( CATCH_MOVE( info ) ),
m_sectionIncluded(
getResultCapture().sectionStarted( m_info, m_assertions ) ) {
getResultCapture().sectionStarted( m_info.name, m_info.lineInfo, m_assertions ) ) {
// Non-"included" sections will not use the timing information
// anyway, so don't bother with the potential syscall.
if (m_sectionIncluded) {
@@ -5654,13 +5657,31 @@ namespace Catch {
}
}
Section::Section( SourceLineInfo const& _lineInfo,
StringRef _name,
const char* const ):
m_info( { "invalid", static_cast<std::size_t>( -1 ) }, std::string{} ),
m_sectionIncluded(
getResultCapture().sectionStarted( _name, _lineInfo, m_assertions ) ) {
// We delay initialization the SectionInfo member until we know
// this section needs it, so we avoid allocating std::string for name.
// We also delay timer start to avoid the potential syscall unless we
// will actually use the result.
if ( m_sectionIncluded ) {
m_info.name = static_cast<std::string>( _name );
m_info.lineInfo = _lineInfo;
m_timer.start();
}
}
Section::~Section() {
if( m_sectionIncluded ) {
SectionEndInfo endInfo{ m_info, m_assertions, m_timer.getElapsedSeconds() };
if( uncaught_exceptions() )
getResultCapture().sectionEndedEarly( endInfo );
else
getResultCapture().sectionEnded( endInfo );
SectionEndInfo endInfo{ CATCH_MOVE(m_info), m_assertions, m_timer.getElapsedSeconds() };
if ( uncaught_exceptions() ) {
getResultCapture().sectionEndedEarly( CATCH_MOVE(endInfo) );
} else {
getResultCapture().sectionEnded( CATCH_MOVE( endInfo ) );
}
}
}
@@ -5876,10 +5897,6 @@ namespace Catch {
: StringRef( rawChars, std::strlen(rawChars) )
{}
auto StringRef::operator == ( StringRef other ) const noexcept -> bool {
return m_size == other.m_size
&& (std::memcmp( m_start, other.m_start, m_size ) == 0);
}
bool StringRef::operator<(StringRef rhs) const noexcept {
if (m_size < rhs.m_size) {
@@ -6155,8 +6172,8 @@ namespace Catch {
namespace Catch {
namespace TestCaseTracking {
NameAndLocation::NameAndLocation( std::string const& _name, SourceLineInfo const& _location )
: name( _name ),
NameAndLocation::NameAndLocation( std::string&& _name, SourceLineInfo const& _location )
: name( CATCH_MOVE(_name) ),
location( _location )
{}
@@ -6171,14 +6188,17 @@ namespace TestCaseTracking {
m_children.push_back( CATCH_MOVE(child) );
}
ITracker* ITracker::findChild( NameAndLocation const& nameAndLocation ) {
ITracker* ITracker::findChild( NameAndLocationRef const& nameAndLocation ) {
auto it = std::find_if(
m_children.begin(),
m_children.end(),
[&nameAndLocation]( ITrackerPtr const& tracker ) {
return tracker->nameAndLocation().location ==
nameAndLocation.location &&
tracker->nameAndLocation().name == nameAndLocation.name;
auto const& tnameAndLoc = tracker->nameAndLocation();
if ( tnameAndLoc.location.line !=
nameAndLocation.location.line ) {
return false;
}
return tnameAndLoc == nameAndLocation;
} );
return ( it != m_children.end() ) ? it->get() : nullptr;
}
@@ -6186,10 +6206,6 @@ namespace TestCaseTracking {
bool ITracker::isSectionTracker() const { return false; }
bool ITracker::isGeneratorTracker() const { return false; }
bool ITracker::isSuccessfullyCompleted() const {
return m_runState == CompletedSuccessfully;
}
bool ITracker::isOpen() const {
return m_runState != NotStarted && !isComplete();
}
@@ -6216,16 +6232,6 @@ namespace TestCaseTracking {
return *m_rootTracker;
}
void TrackerContext::endRun() {
m_rootTracker.reset();
m_currentTracker = nullptr;
m_runState = NotStarted;
}
void TrackerContext::startCycle() {
m_currentTracker = m_rootTracker.get();
m_runState = Executing;
}
void TrackerContext::completeCycle() {
m_runState = CompletedCycle;
}
@@ -6233,16 +6239,13 @@ namespace TestCaseTracking {
bool TrackerContext::completedCycle() const {
return m_runState == CompletedCycle;
}
ITracker& TrackerContext::currentTracker() {
return *m_currentTracker;
}
void TrackerContext::setCurrentTracker( ITracker* tracker ) {
m_currentTracker = tracker;
}
TrackerBase::TrackerBase( NameAndLocation const& nameAndLocation, TrackerContext& ctx, ITracker* parent ):
ITracker(nameAndLocation, parent),
TrackerBase::TrackerBase( NameAndLocation&& nameAndLocation, TrackerContext& ctx, ITracker* parent ):
ITracker(CATCH_MOVE(nameAndLocation), parent),
m_ctx( ctx )
{}
@@ -6302,13 +6305,14 @@ namespace TestCaseTracking {
m_ctx.setCurrentTracker( this );
}
SectionTracker::SectionTracker( NameAndLocation const& nameAndLocation, TrackerContext& ctx, ITracker* parent )
: TrackerBase( nameAndLocation, ctx, parent ),
m_trimmed_name(trim(nameAndLocation.name))
SectionTracker::SectionTracker( NameAndLocation&& nameAndLocation, TrackerContext& ctx, ITracker* parent )
: TrackerBase( CATCH_MOVE(nameAndLocation), ctx, parent ),
m_trimmed_name(trim(StringRef(ITracker::nameAndLocation().name)))
{
if( parent ) {
while( !parent->isSectionTracker() )
while ( !parent->isSectionTracker() ) {
parent = parent->parent();
}
SectionTracker& parentSection = static_cast<SectionTracker&>( *parent );
addNextFilters( parentSection.m_filters );
@@ -6328,24 +6332,30 @@ namespace TestCaseTracking {
bool SectionTracker::isSectionTracker() const { return true; }
SectionTracker& SectionTracker::acquire( TrackerContext& ctx, NameAndLocation const& nameAndLocation ) {
SectionTracker* section;
SectionTracker& SectionTracker::acquire( TrackerContext& ctx, NameAndLocationRef const& nameAndLocation ) {
SectionTracker* tracker;
ITracker& currentTracker = ctx.currentTracker();
if ( ITracker* childTracker =
currentTracker.findChild( nameAndLocation ) ) {
assert( childTracker );
assert( childTracker->isSectionTracker() );
section = static_cast<SectionTracker*>( childTracker );
tracker = static_cast<SectionTracker*>( childTracker );
} else {
auto newSection = Catch::Detail::make_unique<SectionTracker>(
nameAndLocation, ctx, &currentTracker );
section = newSection.get();
currentTracker.addChild( CATCH_MOVE( newSection ) );
auto newTracker = Catch::Detail::make_unique<SectionTracker>(
NameAndLocation{ static_cast<std::string>(nameAndLocation.name),
nameAndLocation.location },
ctx,
&currentTracker );
tracker = newTracker.get();
currentTracker.addChild( CATCH_MOVE( newTracker ) );
}
if( !ctx.completedCycle() )
section->tryOpen();
return *section;
if ( !ctx.completedCycle() ) {
tracker->tryOpen();
}
return *tracker;
}
void SectionTracker::tryOpen() {
@@ -6366,10 +6376,6 @@ namespace TestCaseTracking {
m_filters.insert( m_filters.end(), filters.begin()+1, filters.end() );
}
std::vector<StringRef> const& SectionTracker::getFilters() const {
return m_filters;
}
StringRef SectionTracker::trimmedName() const {
return m_trimmed_name;
}
@@ -6668,10 +6674,8 @@ namespace Catch {
token.erase(token.begin());
if (m_exclusion) {
m_currentFilter.m_forbidden.emplace_back(Detail::make_unique<TestSpec::TagPattern>(".", m_substring));
m_currentFilter.m_forbidden.emplace_back(Detail::make_unique<TestSpec::TagPattern>(token, m_substring));
} else {
m_currentFilter.m_required.emplace_back(Detail::make_unique<TestSpec::TagPattern>(".", m_substring));
m_currentFilter.m_required.emplace_back(Detail::make_unique<TestSpec::TagPattern>(token, m_substring));
}
}
if (m_exclusion) {
@@ -7614,7 +7618,19 @@ WithinRelMatcher WithinRel(float target) {
}
} // namespace Matchers
bool IsNaNMatcher::match( double const& matchee ) const {
return std::isnan( matchee );
}
std::string IsNaNMatcher::describe() const {
using namespace std::string_literals;
return "is NaN"s;
}
IsNaNMatcher IsNaN() { return IsNaNMatcher(); }
} // namespace Matchers
} // namespace Catch
@@ -8051,7 +8067,7 @@ private:
private:
std::ostream& stream;
AssertionResult const& result;
std::vector<MessageInfo> messages;
std::vector<MessageInfo> const& messages;
std::vector<MessageInfo>::const_iterator itMessage;
bool printInfoMessages;
ColourImpl* colourImpl;
@@ -8145,7 +8161,6 @@ public:
stats(_stats),
result(_stats.assertionResult),
colour(Colour::None),
message(result.getMessage()),
messages(_stats.infoMessages),
colourImpl(colourImpl_),
printInfoMessages(_printInfoMessages) {
@@ -8154,10 +8169,10 @@ public:
colour = Colour::Success;
passOrFail = "PASSED"_sr;
//if( result.hasMessage() )
if (_stats.infoMessages.size() == 1)
messageLabel = "with message";
if (_stats.infoMessages.size() > 1)
messageLabel = "with messages";
if (messages.size() == 1)
messageLabel = "with message"_sr;
if (messages.size() > 1)
messageLabel = "with messages"_sr;
break;
case ResultWas::ExpressionFailed:
if (result.isOk()) {
@@ -8167,51 +8182,57 @@ public:
colour = Colour::Error;
passOrFail = "FAILED"_sr;
}
if (_stats.infoMessages.size() == 1)
messageLabel = "with message";
if (_stats.infoMessages.size() > 1)
messageLabel = "with messages";
if (messages.size() == 1)
messageLabel = "with message"_sr;
if (messages.size() > 1)
messageLabel = "with messages"_sr;
break;
case ResultWas::ThrewException:
colour = Colour::Error;
passOrFail = "FAILED"_sr;
messageLabel = "due to unexpected exception with ";
if (_stats.infoMessages.size() == 1)
messageLabel += "message";
if (_stats.infoMessages.size() > 1)
messageLabel += "messages";
// todo switch
switch (messages.size()) { case 0:
messageLabel = "due to unexpected exception with "_sr;
break;
case 1:
messageLabel = "due to unexpected exception with message"_sr;
break;
default:
messageLabel = "due to unexpected exception with messages"_sr;
break;
}
break;
case ResultWas::FatalErrorCondition:
colour = Colour::Error;
passOrFail = "FAILED"_sr;
messageLabel = "due to a fatal error condition";
messageLabel = "due to a fatal error condition"_sr;
break;
case ResultWas::DidntThrowException:
colour = Colour::Error;
passOrFail = "FAILED"_sr;
messageLabel = "because no exception was thrown where one was expected";
messageLabel = "because no exception was thrown where one was expected"_sr;
break;
case ResultWas::Info:
messageLabel = "info";
messageLabel = "info"_sr;
break;
case ResultWas::Warning:
messageLabel = "warning";
messageLabel = "warning"_sr;
break;
case ResultWas::ExplicitFailure:
passOrFail = "FAILED"_sr;
colour = Colour::Error;
if (_stats.infoMessages.size() == 1)
messageLabel = "explicitly with message";
if (_stats.infoMessages.size() > 1)
messageLabel = "explicitly with messages";
if (messages.size() == 1)
messageLabel = "explicitly with message"_sr;
if (messages.size() > 1)
messageLabel = "explicitly with messages"_sr;
break;
case ResultWas::ExplicitSkip:
colour = Colour::Skip;
passOrFail = "SKIPPED"_sr;
if (_stats.infoMessages.size() == 1)
messageLabel = "explicitly with message";
if (_stats.infoMessages.size() > 1)
messageLabel = "explicitly with messages";
if (messages.size() == 1)
messageLabel = "explicitly with message"_sr;
if (messages.size() > 1)
messageLabel = "explicitly with messages"_sr;
break;
// These cases are here to prevent compiler warnings
case ResultWas::Unknown:
@@ -8275,9 +8296,8 @@ private:
AssertionResult const& result;
Colour::Code colour;
StringRef passOrFail;
std::string messageLabel;
std::string message;
std::vector<MessageInfo> messages;
StringRef messageLabel;
std::vector<MessageInfo> const& messages;
ColourImpl* colourImpl;
bool printInfoMessages;
};
@@ -8809,7 +8829,8 @@ namespace Catch {
void
CumulativeReporterBase::sectionStarting( SectionInfo const& sectionInfo ) {
SectionStats incompleteStats( sectionInfo, Counts(), 0, false );
// We need a copy, because SectionStats expect to take ownership
SectionStats incompleteStats( SectionInfo(sectionInfo), Counts(), 0, false );
SectionNode* node;
if ( m_sectionStack.empty() ) {
if ( !m_rootSection ) {
@@ -9792,7 +9813,7 @@ namespace Catch {
}
void SonarQubeReporter::writeRun( TestRunNode const& runNode ) {
std::map<std::string, std::vector<TestCaseNode const*>> testsPerFile;
std::map<StringRef, std::vector<TestCaseNode const*>> testsPerFile;
for ( auto const& child : runNode.children ) {
testsPerFile[child->value.testInfo->lineInfo.file].push_back(
@@ -9804,7 +9825,7 @@ namespace Catch {
}
}
void SonarQubeReporter::writeTestFile(std::string const& filename, std::vector<TestCaseNode const*> const& testCaseNodes) {
void SonarQubeReporter::writeTestFile(StringRef filename, std::vector<TestCaseNode const*> const& testCaseNodes) {
XmlWriter::ScopedElement e = xml.scopedElement("file");
xml.writeAttribute("path"_sr, filename);
@@ -10103,7 +10124,7 @@ namespace Catch {
private:
std::ostream& stream;
AssertionResult const& result;
std::vector<MessageInfo> messages;
std::vector<MessageInfo> const& messages;
std::vector<MessageInfo>::const_iterator itMessage;
bool printInfoMessages;
std::size_t counter;
@@ -10366,7 +10387,7 @@ namespace Catch {
void XmlReporter::testCaseStarting( TestCaseInfo const& testInfo ) {
StreamingReporterBase::testCaseStarting(testInfo);
m_xml.startElement( "TestCase" )
.writeAttribute( "name"_sr, trim( testInfo.name ) )
.writeAttribute( "name"_sr, trim( StringRef(testInfo.name) ) )
.writeAttribute( "tags"_sr, testInfo.tagsAsString() );
writeSourceInfo( testInfo.lineInfo );
@@ -10380,7 +10401,7 @@ namespace Catch {
StreamingReporterBase::sectionStarting( sectionInfo );
if( m_sectionDepth++ > 0 ) {
m_xml.startElement( "Section" )
.writeAttribute( "name"_sr, trim( sectionInfo.name ) );
.writeAttribute( "name"_sr, trim( StringRef(sectionInfo.name) ) );
writeSourceInfo( sectionInfo.lineInfo );
m_xml.ensureTagClosed();
}
@@ -10494,11 +10515,10 @@ namespace Catch {
if ( m_config->showDurations() == ShowDurations::Always )
e.writeAttribute( "durationInSeconds"_sr, m_testCaseTimer.getElapsedSeconds() );
if( !testCaseStats.stdOut.empty() )
m_xml.scopedElement( "StdOut" ).writeText( trim( testCaseStats.stdOut ), XmlFormatting::Newline );
m_xml.scopedElement( "StdOut" ).writeText( trim( StringRef(testCaseStats.stdOut) ), XmlFormatting::Newline );
if( !testCaseStats.stdErr.empty() )
m_xml.scopedElement( "StdErr" ).writeText( trim( testCaseStats.stdErr ), XmlFormatting::Newline );
m_xml.scopedElement( "StdErr" ).writeText( trim( StringRef(testCaseStats.stdErr) ), XmlFormatting::Newline );
m_xml.endElement();
}

View File

@@ -5,8 +5,8 @@
// SPDX-License-Identifier: BSL-1.0
// Catch v3.3.0
// Generated: 2023-01-22 19:46:23.163056
// Catch v3.3.2
// Generated: 2023-02-26 10:28:46.785908
// ----------------------------------------------------------
// This file is an amalgamation of multiple different files.
// You probably shouldn't edit it directly.
@@ -95,6 +95,8 @@ namespace Catch {
#include <iosfwd>
#include <cassert>
#include <cstring>
namespace Catch {
/// A non-owning string class (similar to the forthcoming std::string_view)
@@ -131,7 +133,10 @@ namespace Catch {
}
public: // operators
auto operator == ( StringRef other ) const noexcept -> bool;
auto operator == ( StringRef other ) const noexcept -> bool {
return m_size == other.m_size
&& (std::memcmp( m_start, other.m_start, m_size ) == 0);
}
auto operator != (StringRef other) const noexcept -> bool {
return !(*this == other);
}
@@ -352,7 +357,7 @@ namespace Catch {
// Only GCC compiler should be used in this block, so other compilers trying to
// mask themselves as GCC should be ignored.
#if defined(__GNUC__) && !defined(__clang__) && !defined(__ICC) && !defined(__CUDACC__) && !defined(__LCC__)
#if defined(__GNUC__) && !defined(__clang__) && !defined(__ICC) && !defined(__CUDACC__) && !defined(__LCC__) && !defined(__NVCOMPILER)
# define CATCH_INTERNAL_START_WARNINGS_SUPPRESSION _Pragma( "GCC diagnostic push" )
# define CATCH_INTERNAL_STOP_WARNINGS_SUPPRESSION _Pragma( "GCC diagnostic pop" )
@@ -371,6 +376,12 @@ namespace Catch {
#endif
#if defined(__NVCOMPILER)
# define CATCH_INTERNAL_START_WARNINGS_SUPPRESSION _Pragma( "diag push" )
# define CATCH_INTERNAL_STOP_WARNINGS_SUPPRESSION _Pragma( "diag pop" )
# define CATCH_INTERNAL_SUPPRESS_UNUSED_VARIABLE_WARNINGS _Pragma( "diag_suppress declared_but_not_referenced" )
#endif
#if defined(__CUDACC__) && !defined(__clang__)
# ifdef __NVCC_DIAG_PRAGMA_SUPPORT__
// New pragmas introduced in CUDA 11.5+
@@ -1039,7 +1050,7 @@ namespace Catch {
class AssertionResult {
public:
AssertionResult() = delete;
AssertionResult( AssertionInfo const& info, AssertionResultData const& data );
AssertionResult( AssertionInfo const& info, AssertionResultData&& data );
bool isOk() const;
bool succeeded() const;
@@ -1217,10 +1228,11 @@ namespace Catch {
public:
virtual ~IResultCapture();
virtual bool sectionStarted( SectionInfo const& sectionInfo,
Counts& assertions ) = 0;
virtual void sectionEnded( SectionEndInfo const& endInfo ) = 0;
virtual void sectionEndedEarly( SectionEndInfo const& endInfo ) = 0;
virtual bool sectionStarted( StringRef sectionName,
SourceLineInfo const& sectionLineInfo,
Counts& assertions ) = 0;
virtual void sectionEnded( SectionEndInfo&& endInfo ) = 0;
virtual void sectionEndedEarly( SectionEndInfo&& endInfo ) = 0;
virtual IGeneratorTracker*
acquireGeneratorTracker( StringRef generatorName,
@@ -1238,7 +1250,7 @@ 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 emplaceUnscopedMessage( MessageBuilder&& builder ) = 0;
virtual void handleFatalErrorCondition( StringRef message ) = 0;
@@ -1419,7 +1431,7 @@ namespace Catch {
};
struct SectionStats {
SectionStats( SectionInfo const& _sectionInfo,
SectionStats( SectionInfo&& _sectionInfo,
Counts const& _assertions,
double _durationInSeconds,
bool _missingAssertions );
@@ -1433,8 +1445,8 @@ namespace Catch {
struct TestCaseStats {
TestCaseStats( TestCaseInfo const& _testInfo,
Totals const& _totals,
std::string const& _stdOut,
std::string const& _stdErr,
std::string&& _stdOut,
std::string&& _stdErr,
bool _aborting );
TestCaseInfo const * testInfo;
@@ -2691,7 +2703,7 @@ namespace Catch {
});
BenchmarkInfo info {
name,
CATCH_MOVE(name),
plan.estimated_duration.count(),
plan.iterations_per_sample,
cfg->benchmarkSamples(),
@@ -2707,7 +2719,7 @@ namespace Catch {
});
auto analysis = Detail::analyse(*cfg, env, samples.begin(), samples.end());
BenchmarkStats<FloatDuration<Clock>> stats{ info, analysis.samples, analysis.mean, analysis.standard_deviation, analysis.outliers, analysis.outlier_variance };
BenchmarkStats<FloatDuration<Clock>> stats{ CATCH_MOVE(info), CATCH_MOVE(analysis.samples), analysis.mean, analysis.standard_deviation, analysis.outliers, analysis.outlier_variance };
getResultCapture().benchmarkEnded(stats);
} CATCH_CATCH_ANON (TestFailureException) {
getResultCapture().benchmarkFailed("Benchmark failed due to failed assertion"_sr);
@@ -4459,11 +4471,10 @@ namespace Catch {
ResultWas::OfType type ):
m_info(macroName, lineInfo, type) {}
template<typename T>
MessageBuilder& operator << ( T const& value ) {
MessageBuilder&& operator << ( T const& value ) && {
m_stream << value;
return *this;
return CATCH_MOVE(*this);
}
MessageInfo m_info;
@@ -4471,7 +4482,7 @@ namespace Catch {
class ScopedMessage {
public:
explicit ScopedMessage( MessageBuilder const& builder );
explicit ScopedMessage( MessageBuilder&& builder );
ScopedMessage( ScopedMessage& duplicate ) = delete;
ScopedMessage( ScopedMessage&& old ) noexcept;
~ScopedMessage();
@@ -4518,7 +4529,10 @@ namespace Catch {
///////////////////////////////////////////////////////////////////////////////
#define INTERNAL_CATCH_CAPTURE( varName, macroName, ... ) \
Catch::Capturer varName( macroName, CATCH_INTERNAL_LINEINFO, Catch::ResultWas::Info, #__VA_ARGS__ ); \
Catch::Capturer varName( macroName##_catch_sr, \
CATCH_INTERNAL_LINEINFO, \
Catch::ResultWas::Info, \
#__VA_ARGS__##_catch_sr ); \
varName.captureValues( 0, __VA_ARGS__ )
///////////////////////////////////////////////////////////////////////////////
@@ -5904,9 +5918,9 @@ namespace Catch {
#if !defined(CATCH_CONFIG_DISABLE)
#if !defined(CATCH_CONFIG_DISABLE_STRINGIFICATION)
#define CATCH_INTERNAL_STRINGIFY(...) #__VA_ARGS__
#define CATCH_INTERNAL_STRINGIFY(...) #__VA_ARGS__##_catch_sr
#else
#define CATCH_INTERNAL_STRINGIFY(...) "Disabled by CATCH_CONFIG_DISABLE_STRINGIFICATION"
#define CATCH_INTERNAL_STRINGIFY(...) "Disabled by CATCH_CONFIG_DISABLE_STRINGIFICATION"_catch_sr
#endif
#if defined(CATCH_CONFIG_FAST_COMPILE) || defined(CATCH_CONFIG_DISABLE_EXCEPTIONS)
@@ -6071,6 +6085,9 @@ namespace Catch {
class Section : Detail::NonCopyable {
public:
Section( SectionInfo&& info );
Section( SourceLineInfo const& _lineInfo,
StringRef _name,
const char* const = nullptr );
~Section();
// This indicates whether the section should be executed or not
@@ -6089,7 +6106,7 @@ namespace Catch {
#define INTERNAL_CATCH_SECTION( ... ) \
CATCH_INTERNAL_START_WARNINGS_SUPPRESSION \
CATCH_INTERNAL_SUPPRESS_UNUSED_VARIABLE_WARNINGS \
if( Catch::Section const& INTERNAL_CATCH_UNIQUE_NAME( catch_internal_Section ) = Catch::SectionInfo( CATCH_INTERNAL_LINEINFO, __VA_ARGS__ ) ) \
if( Catch::Section const& INTERNAL_CATCH_UNIQUE_NAME( catch_internal_Section ) = Catch::Section( CATCH_INTERNAL_LINEINFO, __VA_ARGS__ ) ) \
CATCH_INTERNAL_STOP_WARNINGS_SUPPRESSION
#define INTERNAL_CATCH_DYNAMIC_SECTION( ... ) \
@@ -6230,7 +6247,13 @@ struct AutoReg : Detail::NonCopyable {
CATCH_INTERNAL_START_WARNINGS_SUPPRESSION \
CATCH_INTERNAL_SUPPRESS_GLOBALS_WARNINGS \
CATCH_INTERNAL_SUPPRESS_UNUSED_VARIABLE_WARNINGS \
namespace{ const Catch::AutoReg INTERNAL_CATCH_UNIQUE_NAME( autoRegistrar )( Catch::makeTestInvoker( &QualifiedMethod ), CATCH_INTERNAL_LINEINFO, "&" #QualifiedMethod, Catch::NameAndTags{ __VA_ARGS__ } ); } /* NOLINT */ \
namespace { \
const Catch::AutoReg INTERNAL_CATCH_UNIQUE_NAME( autoRegistrar )( \
Catch::makeTestInvoker( &QualifiedMethod ), \
CATCH_INTERNAL_LINEINFO, \
"&" #QualifiedMethod##_catch_sr, \
Catch::NameAndTags{ __VA_ARGS__ } ); \
} /* NOLINT */ \
CATCH_INTERNAL_STOP_WARNINGS_SUPPRESSION
///////////////////////////////////////////////////////////////////////////////
@@ -6242,7 +6265,11 @@ struct AutoReg : Detail::NonCopyable {
struct TestName : INTERNAL_CATCH_REMOVE_PARENS(ClassName) { \
void test(); \
}; \
const Catch::AutoReg INTERNAL_CATCH_UNIQUE_NAME( autoRegistrar ) ( Catch::makeTestInvoker( &TestName::test ), CATCH_INTERNAL_LINEINFO, #ClassName, Catch::NameAndTags{ __VA_ARGS__ } ); /* NOLINT */ \
const Catch::AutoReg INTERNAL_CATCH_UNIQUE_NAME( autoRegistrar )( \
Catch::makeTestInvoker( &TestName::test ), \
CATCH_INTERNAL_LINEINFO, \
#ClassName##_catch_sr, \
Catch::NameAndTags{ __VA_ARGS__ } ); /* NOLINT */ \
} \
CATCH_INTERNAL_STOP_WARNINGS_SUPPRESSION \
void TestName::test()
@@ -6875,7 +6902,7 @@ struct AutoReg : Detail::NonCopyable {
void reg_tests() { \
size_t index = 0; \
using expander = size_t[]; \
(void)expander{(Catch::AutoReg( Catch::makeTestInvoker( &TestFunc<Types> ), CATCH_INTERNAL_LINEINFO, Catch::StringRef(), Catch::NameAndTags{ Name " - " + std::string(INTERNAL_CATCH_STRINGIZE(TmplList)) + " - " + std::to_string(index), Tags } ), index++)... };/* NOLINT */\
(void)expander{(Catch::AutoReg( Catch::makeTestInvoker( &TestFunc<Types> ), CATCH_INTERNAL_LINEINFO, Catch::StringRef(), Catch::NameAndTags{ Name " - " INTERNAL_CATCH_STRINGIZE(TmplList) " - " + std::to_string(index), Tags } ), index++)... };/* NOLINT */\
} \
};\
static int INTERNAL_CATCH_UNIQUE_NAME( globalRegistrar ) = [](){ \
@@ -7010,7 +7037,7 @@ struct AutoReg : Detail::NonCopyable {
void reg_tests(){\
size_t index = 0;\
using expander = size_t[];\
(void)expander{(Catch::AutoReg( Catch::makeTestInvoker( &TestName<Types>::test ), CATCH_INTERNAL_LINEINFO, #ClassName, Catch::NameAndTags{ Name " - " + std::string(INTERNAL_CATCH_STRINGIZE(TmplList)) + " - " + std::to_string(index), Tags } ), index++)... };/* NOLINT */ \
(void)expander{(Catch::AutoReg( Catch::makeTestInvoker( &TestName<Types>::test ), CATCH_INTERNAL_LINEINFO, #ClassName##_catch_sr, Catch::NameAndTags{ Name " - " INTERNAL_CATCH_STRINGIZE(TmplList) " - " + std::to_string(index), Tags } ), index++)... };/* NOLINT */ \
}\
};\
static int INTERNAL_CATCH_UNIQUE_NAME( globalRegistrar ) = [](){\
@@ -7399,7 +7426,7 @@ namespace Catch {
#define CATCH_VERSION_MAJOR 3
#define CATCH_VERSION_MINOR 3
#define CATCH_VERSION_PATCH 0
#define CATCH_VERSION_PATCH 2
#endif // CATCH_VERSION_MACROS_HPP_INCLUDED
@@ -7751,16 +7778,19 @@ namespace Detail {
} // namespace Generators
} // namespace Catch
#define CATCH_INTERNAL_GENERATOR_STRINGIZE_IMPL( ... ) #__VA_ARGS__##_catch_sr
#define CATCH_INTERNAL_GENERATOR_STRINGIZE(...) CATCH_INTERNAL_GENERATOR_STRINGIZE_IMPL(__VA_ARGS__)
#define GENERATE( ... ) \
Catch::Generators::generate( INTERNAL_CATCH_STRINGIZE(INTERNAL_CATCH_UNIQUE_NAME(generator)), \
Catch::Generators::generate( CATCH_INTERNAL_GENERATOR_STRINGIZE(INTERNAL_CATCH_UNIQUE_NAME(generator)), \
CATCH_INTERNAL_LINEINFO, \
[ ]{ using namespace Catch::Generators; return makeGenerators( __VA_ARGS__ ); } ) //NOLINT(google-build-using-namespace)
#define GENERATE_COPY( ... ) \
Catch::Generators::generate( INTERNAL_CATCH_STRINGIZE(INTERNAL_CATCH_UNIQUE_NAME(generator)), \
Catch::Generators::generate( CATCH_INTERNAL_GENERATOR_STRINGIZE(INTERNAL_CATCH_UNIQUE_NAME(generator)), \
CATCH_INTERNAL_LINEINFO, \
[=]{ using namespace Catch::Generators; return makeGenerators( __VA_ARGS__ ); } ) //NOLINT(google-build-using-namespace)
#define GENERATE_REF( ... ) \
Catch::Generators::generate( INTERNAL_CATCH_STRINGIZE(INTERNAL_CATCH_UNIQUE_NAME(generator)), \
Catch::Generators::generate( CATCH_INTERNAL_GENERATOR_STRINGIZE(INTERNAL_CATCH_UNIQUE_NAME(generator)), \
CATCH_INTERNAL_LINEINFO, \
[&]{ using namespace Catch::Generators; return makeGenerators( __VA_ARGS__ ); } ) //NOLINT(google-build-using-namespace)
@@ -8916,6 +8946,139 @@ namespace Detail {
#endif // CATCH_GETENV_HPP_INCLUDED
#ifndef CATCH_IS_PERMUTATION_HPP_INCLUDED
#define CATCH_IS_PERMUTATION_HPP_INCLUDED
#include <algorithm>
#include <iterator>
namespace Catch {
namespace Detail {
template <typename ForwardIter,
typename Sentinel,
typename T,
typename Comparator>
ForwardIter find_sentinel( ForwardIter start,
Sentinel sentinel,
T const& value,
Comparator cmp ) {
while ( start != sentinel ) {
if ( cmp( *start, value ) ) { break; }
++start;
}
return start;
}
template <typename ForwardIter,
typename Sentinel,
typename T,
typename Comparator>
std::ptrdiff_t count_sentinel( ForwardIter start,
Sentinel sentinel,
T const& value,
Comparator cmp ) {
std::ptrdiff_t count = 0;
while ( start != sentinel ) {
if ( cmp( *start, value ) ) { ++count; }
++start;
}
return count;
}
template <typename ForwardIter, typename Sentinel>
std::enable_if_t<!std::is_same<ForwardIter, Sentinel>::value,
std::ptrdiff_t>
sentinel_distance( ForwardIter iter, const Sentinel sentinel ) {
std::ptrdiff_t dist = 0;
while ( iter != sentinel ) {
++iter;
++dist;
}
return dist;
}
template <typename ForwardIter>
std::ptrdiff_t sentinel_distance( ForwardIter first,
ForwardIter last ) {
return std::distance( first, last );
}
template <typename ForwardIter1,
typename Sentinel1,
typename ForwardIter2,
typename Sentinel2,
typename Comparator>
bool check_element_counts( ForwardIter1 first_1,
const Sentinel1 end_1,
ForwardIter2 first_2,
const Sentinel2 end_2,
Comparator cmp ) {
auto cursor = first_1;
while ( cursor != end_1 ) {
if ( find_sentinel( first_1, cursor, *cursor, cmp ) ==
cursor ) {
// we haven't checked this element yet
const auto count_in_range_2 =
count_sentinel( first_2, end_2, *cursor, cmp );
// Not a single instance in 2nd range, so it cannot be a
// permutation of 1st range
if ( count_in_range_2 == 0 ) { return false; }
const auto count_in_range_1 =
count_sentinel( cursor, end_1, *cursor, cmp );
if ( count_in_range_1 != count_in_range_2 ) {
return false;
}
}
++cursor;
}
return true;
}
template <typename ForwardIter1,
typename Sentinel1,
typename ForwardIter2,
typename Sentinel2,
typename Comparator>
bool is_permutation( ForwardIter1 first_1,
const Sentinel1 end_1,
ForwardIter2 first_2,
const Sentinel2 end_2,
Comparator cmp ) {
// TODO: no optimization for stronger iterators, because we would also have to constrain on sentinel vs not sentinel types
// TODO: Comparator has to be "both sides", e.g. a == b => b == a
// This skips shared prefix of the two ranges
while (first_1 != end_1 && first_2 != end_2 && cmp(*first_1, *first_2)) {
++first_1;
++first_2;
}
// We need to handle case where at least one of the ranges has no more elements
if (first_1 == end_1 || first_2 == end_2) {
return first_1 == end_1 && first_2 == end_2;
}
// pair counting is n**2, so we pay linear walk to compare the sizes first
auto dist_1 = sentinel_distance( first_1, end_1 );
auto dist_2 = sentinel_distance( first_2, end_2 );
if (dist_1 != dist_2) { return false; }
// Since we do not try to handle stronger iterators pair (e.g.
// bidir) optimally, the only thing left to do is to check counts in
// the remaining ranges.
return check_element_counts( first_1, end_1, first_2, end_2, cmp );
}
} // namespace Detail
} // namespace Catch
#endif // CATCH_IS_PERMUTATION_HPP_INCLUDED
#ifndef CATCH_ISTREAM_HPP_INCLUDED
#define CATCH_ISTREAM_HPP_INCLUDED
@@ -9194,10 +9357,14 @@ namespace TestCaseTracking {
std::string name;
SourceLineInfo location;
NameAndLocation( std::string const& _name, SourceLineInfo const& _location );
NameAndLocation( std::string&& _name, SourceLineInfo const& _location );
friend bool operator==(NameAndLocation const& lhs, NameAndLocation const& rhs) {
return lhs.name == rhs.name
&& lhs.location == rhs.location;
// This is a very cheap check that should have a very high hit rate.
// If we get to SourceLineInfo::operator==, we will redo it, but the
// cost of repeating is trivial at that point (we will be paying
// multiple strcmp/memcmps at that point).
if ( lhs.location.line != rhs.location.line ) { return false; }
return lhs.name == rhs.name && lhs.location == rhs.location;
}
friend bool operator!=(NameAndLocation const& lhs,
NameAndLocation const& rhs) {
@@ -9205,6 +9372,37 @@ namespace TestCaseTracking {
}
};
/**
* This is a variant of `NameAndLocation` that does not own the name string
*
* This avoids extra allocations when trying to locate a tracker by its
* name and location, as long as we make sure that trackers only keep
* around the owning variant.
*/
struct NameAndLocationRef {
StringRef name;
SourceLineInfo location;
constexpr NameAndLocationRef( StringRef name_,
SourceLineInfo location_ ):
name( name_ ), location( location_ ) {}
friend bool operator==( NameAndLocation const& lhs,
NameAndLocationRef const& rhs ) {
// This is a very cheap check that should have a very high hit rate.
// If we get to SourceLineInfo::operator==, we will redo it, but the
// cost of repeating is trivial at that point (we will be paying
// multiple strcmp/memcmps at that point).
if ( lhs.location.line != rhs.location.line ) { return false; }
return StringRef( lhs.name ) == rhs.name &&
lhs.location == rhs.location;
}
friend bool operator==( NameAndLocationRef const& lhs,
NameAndLocation const& rhs ) {
return rhs == lhs;
}
};
class ITracker;
using ITrackerPtr = Catch::Detail::unique_ptr<ITracker>;
@@ -9229,8 +9427,8 @@ namespace TestCaseTracking {
CycleState m_runState = NotStarted;
public:
ITracker( NameAndLocation const& nameAndLoc, ITracker* parent ):
m_nameAndLocation( nameAndLoc ),
ITracker( NameAndLocation&& nameAndLoc, ITracker* parent ):
m_nameAndLocation( CATCH_MOVE(nameAndLoc) ),
m_parent( parent )
{}
@@ -9251,7 +9449,9 @@ namespace TestCaseTracking {
//! Returns true if tracker run to completion (successfully or not)
virtual bool isComplete() const = 0;
//! Returns true if tracker run to completion succesfully
bool isSuccessfullyCompleted() const;
bool isSuccessfullyCompleted() const {
return m_runState == CompletedSuccessfully;
}
//! Returns true if tracker has started but hasn't been completed
bool isOpen() const;
//! Returns true iff tracker has started
@@ -9269,7 +9469,7 @@ namespace TestCaseTracking {
*
* Returns nullptr if not found.
*/
ITracker* findChild( NameAndLocation const& nameAndLocation );
ITracker* findChild( NameAndLocationRef const& nameAndLocation );
//! Have any children been added?
bool hasChildren() const {
return !m_children.empty();
@@ -9310,13 +9510,15 @@ namespace TestCaseTracking {
public:
ITracker& startRun();
void endRun();
void startCycle();
void startCycle() {
m_currentTracker = m_rootTracker.get();
m_runState = Executing;
}
void completeCycle();
bool completedCycle() const;
ITracker& currentTracker();
ITracker& currentTracker() { return *m_currentTracker; }
void setCurrentTracker( ITracker* tracker );
};
@@ -9326,7 +9528,7 @@ namespace TestCaseTracking {
TrackerContext& m_ctx;
public:
TrackerBase( NameAndLocation const& nameAndLocation, TrackerContext& ctx, ITracker* parent );
TrackerBase( NameAndLocation&& nameAndLocation, TrackerContext& ctx, ITracker* parent );
bool isComplete() const override;
@@ -9342,22 +9544,26 @@ namespace TestCaseTracking {
class SectionTracker : public TrackerBase {
std::vector<StringRef> m_filters;
std::string m_trimmed_name;
// Note that lifetime-wise we piggy back off the name stored in the `ITracker` parent`.
// Currently it allocates owns the name, so this is safe. If it is later refactored
// to not own the name, the name still has to outlive the `ITracker` parent, so
// this should still be safe.
StringRef m_trimmed_name;
public:
SectionTracker( NameAndLocation const& nameAndLocation, TrackerContext& ctx, ITracker* parent );
SectionTracker( NameAndLocation&& nameAndLocation, TrackerContext& ctx, ITracker* parent );
bool isSectionTracker() const override;
bool isComplete() const override;
static SectionTracker& acquire( TrackerContext& ctx, NameAndLocation const& nameAndLocation );
static SectionTracker& acquire( TrackerContext& ctx, NameAndLocationRef const& nameAndLocation );
void tryOpen();
void addInitialFilters( std::vector<std::string> const& filters );
void addNextFilters( std::vector<StringRef> const& filters );
//! Returns filters active in this tracker
std::vector<StringRef> const& getFilters() const;
std::vector<StringRef> const& getFilters() const { return m_filters; }
//! Returns whitespace-trimmed name of the tracked section
StringRef trimmedName() const;
};
@@ -9420,10 +9626,12 @@ namespace Catch {
ResultWas::OfType resultType,
AssertionReaction &reaction ) override;
bool sectionStarted( SectionInfo const& sectionInfo, Counts& assertions ) override;
bool sectionStarted( StringRef sectionName,
SourceLineInfo const& sectionLineInfo,
Counts& assertions ) override;
void sectionEnded( SectionEndInfo const& endInfo ) override;
void sectionEndedEarly( SectionEndInfo const& endInfo ) override;
void sectionEnded( SectionEndInfo&& endInfo ) override;
void sectionEndedEarly( SectionEndInfo&& endInfo ) override;
IGeneratorTracker*
acquireGeneratorTracker( StringRef generatorName,
@@ -9442,7 +9650,7 @@ namespace Catch {
void pushScopedMessage( MessageInfo const& message ) override;
void popScopedMessage( MessageInfo const& message ) override;
void emplaceUnscopedMessage( MessageBuilder const& builder ) override;
void emplaceUnscopedMessage( MessageBuilder&& builder ) override;
std::string getCurrentTestName() const override;
@@ -10929,13 +11137,11 @@ namespace Catch {
}
template <typename RangeLike>
bool match(RangeLike&& rng) const {
using std::begin; using std::end;
return end(rng) != std::find_if(begin(rng), end(rng),
[&](auto const& elem) {
return m_eq(elem, m_desired);
});
bool match( RangeLike&& rng ) const {
for ( auto&& elem : rng ) {
if ( m_eq( elem, m_desired ) ) { return true; }
}
return false;
}
};
@@ -10987,7 +11193,7 @@ namespace Catch {
/**
* Creates a matcher that checks whether a range contains a specific element.
*
* Uses `eq` to do the comparisons
* Uses `eq` to do the comparisons, the element is provided on the rhs
*/
template <typename T, typename Equality>
ContainsElementMatcher<T, Equality> Contains(T&& elem, Equality&& eq) {
@@ -11076,6 +11282,11 @@ namespace Matchers {
double m_margin;
};
//! Creates a matcher that accepts numbers within certain range of target
WithinAbsMatcher WithinAbs( double target, double margin );
class WithinUlpsMatcher final : public MatcherBase<double> {
public:
WithinUlpsMatcher( double target,
@@ -11089,6 +11300,13 @@ namespace Matchers {
Detail::FloatingPointKind m_type;
};
//! Creates a matcher that accepts doubles within certain ULP range of target
WithinUlpsMatcher WithinULP(double target, uint64_t maxUlpDiff);
//! Creates a matcher that accepts floats within certain ULP range of target
WithinUlpsMatcher WithinULP(float target, uint64_t maxUlpDiff);
// Given IEEE-754 format for floats and doubles, we can assume
// that float -> double promotion is lossless. Given this, we can
// assume that if we do the standard relative comparison of
@@ -11105,13 +11323,6 @@ namespace Matchers {
double m_epsilon;
};
//! Creates a matcher that accepts doubles within certain ULP range of target
WithinUlpsMatcher WithinULP(double target, uint64_t maxUlpDiff);
//! Creates a matcher that accepts floats within certain ULP range of target
WithinUlpsMatcher WithinULP(float target, uint64_t maxUlpDiff);
//! Creates a matcher that accepts numbers within certain range of target
WithinAbsMatcher WithinAbs(double target, double margin);
//! Creates a matcher that accepts doubles within certain relative range of target
WithinRelMatcher WithinRel(double target, double eps);
//! Creates a matcher that accepts doubles within 100*DBL_EPS relative range of target
@@ -11121,6 +11332,17 @@ namespace Matchers {
//! Creates a matcher that accepts floats within 100*FLT_EPS relative range of target
WithinRelMatcher WithinRel(float target);
class IsNaNMatcher final : public MatcherBase<double> {
public:
IsNaNMatcher() = default;
bool match( double const& matchee ) const override;
std::string describe() const override;
};
IsNaNMatcher IsNaN();
} // namespace Matchers
} // namespace Catch
@@ -11339,6 +11561,7 @@ namespace Catch {
#ifndef CATCH_MATCHERS_RANGE_EQUALS_HPP_INCLUDED
#define CATCH_MATCHERS_RANGE_EQUALS_HPP_INCLUDED
#include <algorithm>
#include <utility>
@@ -11363,13 +11586,19 @@ namespace Catch {
template <typename RangeLike>
bool match( RangeLike&& rng ) const {
using std::begin;
using std::end;
return std::equal( begin(m_desired),
end(m_desired),
begin(rng),
end(rng),
m_predicate );
auto rng_start = begin( rng );
const auto rng_end = end( rng );
auto target_start = begin( m_desired );
const auto target_end = end( m_desired );
while (rng_start != rng_end && target_start != target_end) {
if (!m_predicate(*rng_start, *target_start)) {
return false;
}
++rng_start;
++target_start;
}
return rng_start == rng_end && target_start == target_end;
}
std::string describe() const override {
@@ -11397,11 +11626,11 @@ namespace Catch {
bool match( RangeLike&& rng ) const {
using std::begin;
using std::end;
return std::is_permutation( begin( m_desired ),
end( m_desired ),
begin( rng ),
end( rng ),
m_predicate );
return Catch::Detail::is_permutation( begin( m_desired ),
end( m_desired ),
begin( rng ),
end( rng ),
m_predicate );
}
std::string describe() const override {
@@ -12518,7 +12747,7 @@ namespace Catch {
CATCH_INTERNAL_SUPPRESS_GLOBALS_WARNINGS \
namespace { \
Catch::ListenerRegistrar<listenerType> INTERNAL_CATCH_UNIQUE_NAME( \
catch_internal_RegistrarFor )( #listenerType ); \
catch_internal_RegistrarFor )( #listenerType##_catch_sr ); \
} \
CATCH_INTERNAL_STOP_WARNINGS_SUPPRESSION
@@ -12565,7 +12794,7 @@ namespace Catch {
void writeRun( TestRunNode const& groupNode );
void writeTestFile(std::string const& filename, std::vector<TestCaseNode const*> const& testCaseNodes);
void writeTestFile(StringRef filename, std::vector<TestCaseNode const*> const& testCaseNodes);
void writeTestCase(TestCaseNode const& testCaseNode);

View File

@@ -8,7 +8,7 @@
project(
'catch2',
'cpp',
version: '3.3.0', # CML version placeholder, don't delete
version: '3.3.2', # CML version placeholder, don't delete
license: 'BSL-1.0',
meson_version: '>=0.50.0',
)

View File

@@ -88,6 +88,7 @@ set(IMPL_HEADERS
${SOURCES_DIR}/internal/catch_floating_point_helpers.hpp
${SOURCES_DIR}/internal/catch_getenv.hpp
${SOURCES_DIR}/internal/catch_istream.hpp
${SOURCES_DIR}/internal/catch_is_permutation.hpp
${SOURCES_DIR}/internal/catch_lazy_expr.hpp
${SOURCES_DIR}/internal/catch_leak_detector.hpp
${SOURCES_DIR}/internal/catch_list.hpp

View File

@@ -64,7 +64,7 @@ namespace Catch {
});
BenchmarkInfo info {
name,
CATCH_MOVE(name),
plan.estimated_duration.count(),
plan.iterations_per_sample,
cfg->benchmarkSamples(),
@@ -80,7 +80,7 @@ namespace Catch {
});
auto analysis = Detail::analyse(*cfg, env, samples.begin(), samples.end());
BenchmarkStats<FloatDuration<Clock>> stats{ info, analysis.samples, analysis.mean, analysis.standard_deviation, analysis.outliers, analysis.outlier_variance };
BenchmarkStats<FloatDuration<Clock>> stats{ CATCH_MOVE(info), CATCH_MOVE(analysis.samples), analysis.mean, analysis.standard_deviation, analysis.outliers, analysis.outlier_variance };
getResultCapture().benchmarkEnded(stats);
} CATCH_CATCH_ANON (TestFailureException) {
getResultCapture().benchmarkFailed("Benchmark failed due to failed assertion"_sr);

View File

@@ -70,6 +70,7 @@
#include <catch2/internal/catch_fatal_condition_handler.hpp>
#include <catch2/internal/catch_floating_point_helpers.hpp>
#include <catch2/internal/catch_getenv.hpp>
#include <catch2/internal/catch_is_permutation.hpp>
#include <catch2/internal/catch_istream.hpp>
#include <catch2/internal/catch_lazy_expr.hpp>
#include <catch2/internal/catch_leak_detector.hpp>

View File

@@ -7,6 +7,7 @@
// SPDX-License-Identifier: BSL-1.0
#include <catch2/catch_assertion_result.hpp>
#include <catch2/internal/catch_reusable_string_stream.hpp>
#include <catch2/internal/catch_move_and_forward.hpp>
namespace Catch {
@@ -26,9 +27,9 @@ namespace Catch {
return reconstructedExpression;
}
AssertionResult::AssertionResult( AssertionInfo const& info, AssertionResultData const& data )
AssertionResult::AssertionResult( AssertionInfo const& info, AssertionResultData&& data )
: m_info( info ),
m_resultData( data )
m_resultData( CATCH_MOVE(data) )
{}
// Result was a success
@@ -67,16 +68,15 @@ namespace Catch {
}
std::string AssertionResult::getExpressionInMacro() const {
std::string expr;
if( m_info.macroName.empty() )
expr = static_cast<std::string>(m_info.capturedExpression);
else {
expr.reserve( m_info.macroName.size() + m_info.capturedExpression.size() + 4 );
expr += m_info.macroName;
expr += "( ";
expr += m_info.capturedExpression;
expr += " )";
if ( m_info.macroName.empty() ) {
return static_cast<std::string>( m_info.capturedExpression );
}
std::string expr;
expr.reserve( m_info.macroName.size() + m_info.capturedExpression.size() + 4 );
expr += m_info.macroName;
expr += "( ";
expr += m_info.capturedExpression;
expr += " )";
return expr;
}

View File

@@ -35,7 +35,7 @@ namespace Catch {
class AssertionResult {
public:
AssertionResult() = delete;
AssertionResult( AssertionInfo const& info, AssertionResultData const& data );
AssertionResult( AssertionInfo const& info, AssertionResultData&& data );
bool isOk() const;
bool succeeded() const;

View File

@@ -19,8 +19,8 @@ namespace Catch {
////////////////////////////////////////////////////////////////////////////
ScopedMessage::ScopedMessage( MessageBuilder const& builder ):
m_info( builder.m_info ) {
ScopedMessage::ScopedMessage( MessageBuilder&& builder ):
m_info( CATCH_MOVE(builder.m_info) ) {
m_info.message = builder.m_stream.str();
getResultCapture().pushScopedMessage( m_info );
}

View File

@@ -39,11 +39,10 @@ namespace Catch {
ResultWas::OfType type ):
m_info(macroName, lineInfo, type) {}
template<typename T>
MessageBuilder& operator << ( T const& value ) {
MessageBuilder&& operator << ( T const& value ) && {
m_stream << value;
return *this;
return CATCH_MOVE(*this);
}
MessageInfo m_info;
@@ -51,7 +50,7 @@ namespace Catch {
class ScopedMessage {
public:
explicit ScopedMessage( MessageBuilder const& builder );
explicit ScopedMessage( MessageBuilder&& builder );
ScopedMessage( ScopedMessage& duplicate ) = delete;
ScopedMessage( ScopedMessage&& old ) noexcept;
~ScopedMessage();
@@ -98,7 +97,10 @@ namespace Catch {
///////////////////////////////////////////////////////////////////////////////
#define INTERNAL_CATCH_CAPTURE( varName, macroName, ... ) \
Catch::Capturer varName( macroName, CATCH_INTERNAL_LINEINFO, Catch::ResultWas::Info, #__VA_ARGS__ ); \
Catch::Capturer varName( macroName##_catch_sr, \
CATCH_INTERNAL_LINEINFO, \
Catch::ResultWas::Info, \
#__VA_ARGS__##_catch_sr ); \
varName.captureValues( 0, __VA_ARGS__ )
///////////////////////////////////////////////////////////////////////////////

View File

@@ -36,7 +36,7 @@ namespace Catch {
}
Version const& libraryVersion() {
static Version version( 3, 3, 0, "", 0 );
static Version version( 3, 3, 2, "", 0 );
return version;
}

View File

@@ -10,6 +10,6 @@
#define CATCH_VERSION_MAJOR 3
#define CATCH_VERSION_MINOR 3
#define CATCH_VERSION_PATCH 0
#define CATCH_VERSION_PATCH 2
#endif // CATCH_VERSION_MACROS_HPP_INCLUDED

View File

@@ -14,7 +14,6 @@
#include <catch2/internal/catch_stringref.hpp>
#include <catch2/internal/catch_move_and_forward.hpp>
#include <catch2/internal/catch_unique_name.hpp>
#include <catch2/internal/catch_preprocessor.hpp>
#include <vector>
#include <tuple>
@@ -232,16 +231,19 @@ namespace Detail {
} // namespace Generators
} // namespace Catch
#define CATCH_INTERNAL_GENERATOR_STRINGIZE_IMPL( ... ) #__VA_ARGS__##_catch_sr
#define CATCH_INTERNAL_GENERATOR_STRINGIZE(...) CATCH_INTERNAL_GENERATOR_STRINGIZE_IMPL(__VA_ARGS__)
#define GENERATE( ... ) \
Catch::Generators::generate( INTERNAL_CATCH_STRINGIZE(INTERNAL_CATCH_UNIQUE_NAME(generator)), \
Catch::Generators::generate( CATCH_INTERNAL_GENERATOR_STRINGIZE(INTERNAL_CATCH_UNIQUE_NAME(generator)), \
CATCH_INTERNAL_LINEINFO, \
[ ]{ using namespace Catch::Generators; return makeGenerators( __VA_ARGS__ ); } ) //NOLINT(google-build-using-namespace)
#define GENERATE_COPY( ... ) \
Catch::Generators::generate( INTERNAL_CATCH_STRINGIZE(INTERNAL_CATCH_UNIQUE_NAME(generator)), \
Catch::Generators::generate( CATCH_INTERNAL_GENERATOR_STRINGIZE(INTERNAL_CATCH_UNIQUE_NAME(generator)), \
CATCH_INTERNAL_LINEINFO, \
[=]{ using namespace Catch::Generators; return makeGenerators( __VA_ARGS__ ); } ) //NOLINT(google-build-using-namespace)
#define GENERATE_REF( ... ) \
Catch::Generators::generate( INTERNAL_CATCH_STRINGIZE(INTERNAL_CATCH_UNIQUE_NAME(generator)), \
Catch::Generators::generate( CATCH_INTERNAL_GENERATOR_STRINGIZE(INTERNAL_CATCH_UNIQUE_NAME(generator)), \
CATCH_INTERNAL_LINEINFO, \
[&]{ using namespace Catch::Generators; return makeGenerators( __VA_ARGS__ ); } ) //NOLINT(google-build-using-namespace)

View File

@@ -44,10 +44,11 @@ namespace Catch {
public:
virtual ~IResultCapture();
virtual bool sectionStarted( SectionInfo const& sectionInfo,
Counts& assertions ) = 0;
virtual void sectionEnded( SectionEndInfo const& endInfo ) = 0;
virtual void sectionEndedEarly( SectionEndInfo const& endInfo ) = 0;
virtual bool sectionStarted( StringRef sectionName,
SourceLineInfo const& sectionLineInfo,
Counts& assertions ) = 0;
virtual void sectionEnded( SectionEndInfo&& endInfo ) = 0;
virtual void sectionEndedEarly( SectionEndInfo&& endInfo ) = 0;
virtual IGeneratorTracker*
acquireGeneratorTracker( StringRef generatorName,
@@ -65,7 +66,7 @@ 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 emplaceUnscopedMessage( MessageBuilder&& builder ) = 0;
virtual void handleFatalErrorCondition( StringRef message ) = 0;

View File

@@ -60,18 +60,17 @@ namespace Catch {
// Copy message into messages list.
// !TBD This should have been done earlier, somewhere
MessageBuilder builder( assertionResult.getTestMacroName(), assertionResult.getSourceInfo(), assertionResult.getResultType() );
builder << assertionResult.getMessage();
builder.m_info.message = builder.m_stream.str();
builder.m_info.message = static_cast<std::string>(assertionResult.getMessage());
infoMessages.push_back( builder.m_info );
infoMessages.push_back( CATCH_MOVE(builder.m_info) );
}
}
SectionStats::SectionStats( SectionInfo const& _sectionInfo,
SectionStats::SectionStats( SectionInfo&& _sectionInfo,
Counts const& _assertions,
double _durationInSeconds,
bool _missingAssertions )
: sectionInfo( _sectionInfo ),
: sectionInfo( CATCH_MOVE(_sectionInfo) ),
assertions( _assertions ),
durationInSeconds( _durationInSeconds ),
missingAssertions( _missingAssertions )
@@ -80,13 +79,13 @@ namespace Catch {
TestCaseStats::TestCaseStats( TestCaseInfo const& _testInfo,
Totals const& _totals,
std::string const& _stdOut,
std::string const& _stdErr,
std::string&& _stdOut,
std::string&& _stdErr,
bool _aborting )
: testInfo( &_testInfo ),
totals( _totals ),
stdOut( _stdOut ),
stdErr( _stdErr ),
stdOut( CATCH_MOVE(_stdOut) ),
stdErr( CATCH_MOVE(_stdErr) ),
aborting( _aborting )
{}

View File

@@ -78,7 +78,7 @@ namespace Catch {
};
struct SectionStats {
SectionStats( SectionInfo const& _sectionInfo,
SectionStats( SectionInfo&& _sectionInfo,
Counts const& _assertions,
double _durationInSeconds,
bool _missingAssertions );
@@ -92,8 +92,8 @@ namespace Catch {
struct TestCaseStats {
TestCaseStats( TestCaseInfo const& _testInfo,
Totals const& _totals,
std::string const& _stdOut,
std::string const& _stdErr,
std::string&& _stdOut,
std::string&& _stdErr,
bool _aborting );
TestCaseInfo const * testInfo;

View File

@@ -41,7 +41,7 @@
// Only GCC compiler should be used in this block, so other compilers trying to
// mask themselves as GCC should be ignored.
#if defined(__GNUC__) && !defined(__clang__) && !defined(__ICC) && !defined(__CUDACC__) && !defined(__LCC__)
#if defined(__GNUC__) && !defined(__clang__) && !defined(__ICC) && !defined(__CUDACC__) && !defined(__LCC__) && !defined(__NVCOMPILER)
# define CATCH_INTERNAL_START_WARNINGS_SUPPRESSION _Pragma( "GCC diagnostic push" )
# define CATCH_INTERNAL_STOP_WARNINGS_SUPPRESSION _Pragma( "GCC diagnostic pop" )
@@ -60,6 +60,12 @@
#endif
#if defined(__NVCOMPILER)
# define CATCH_INTERNAL_START_WARNINGS_SUPPRESSION _Pragma( "diag push" )
# define CATCH_INTERNAL_STOP_WARNINGS_SUPPRESSION _Pragma( "diag pop" )
# define CATCH_INTERNAL_SUPPRESS_UNUSED_VARIABLE_WARNINGS _Pragma( "diag_suppress declared_but_not_referenced" )
#endif
#if defined(__CUDACC__) && !defined(__clang__)
# ifdef __NVCC_DIAG_PRAGMA_SUPPORT__
// New pragmas introduced in CUDA 11.5+

View File

@@ -0,0 +1,138 @@
// Copyright Catch2 Authors
// Distributed under the Boost Software License, Version 1.0.
// (See accompanying file LICENSE.txt or copy at
// https://www.boost.org/LICENSE_1_0.txt)
// SPDX-License-Identifier: BSL-1.0
#ifndef CATCH_IS_PERMUTATION_HPP_INCLUDED
#define CATCH_IS_PERMUTATION_HPP_INCLUDED
#include <algorithm>
#include <iterator>
namespace Catch {
namespace Detail {
template <typename ForwardIter,
typename Sentinel,
typename T,
typename Comparator>
ForwardIter find_sentinel( ForwardIter start,
Sentinel sentinel,
T const& value,
Comparator cmp ) {
while ( start != sentinel ) {
if ( cmp( *start, value ) ) { break; }
++start;
}
return start;
}
template <typename ForwardIter,
typename Sentinel,
typename T,
typename Comparator>
std::ptrdiff_t count_sentinel( ForwardIter start,
Sentinel sentinel,
T const& value,
Comparator cmp ) {
std::ptrdiff_t count = 0;
while ( start != sentinel ) {
if ( cmp( *start, value ) ) { ++count; }
++start;
}
return count;
}
template <typename ForwardIter, typename Sentinel>
std::enable_if_t<!std::is_same<ForwardIter, Sentinel>::value,
std::ptrdiff_t>
sentinel_distance( ForwardIter iter, const Sentinel sentinel ) {
std::ptrdiff_t dist = 0;
while ( iter != sentinel ) {
++iter;
++dist;
}
return dist;
}
template <typename ForwardIter>
std::ptrdiff_t sentinel_distance( ForwardIter first,
ForwardIter last ) {
return std::distance( first, last );
}
template <typename ForwardIter1,
typename Sentinel1,
typename ForwardIter2,
typename Sentinel2,
typename Comparator>
bool check_element_counts( ForwardIter1 first_1,
const Sentinel1 end_1,
ForwardIter2 first_2,
const Sentinel2 end_2,
Comparator cmp ) {
auto cursor = first_1;
while ( cursor != end_1 ) {
if ( find_sentinel( first_1, cursor, *cursor, cmp ) ==
cursor ) {
// we haven't checked this element yet
const auto count_in_range_2 =
count_sentinel( first_2, end_2, *cursor, cmp );
// Not a single instance in 2nd range, so it cannot be a
// permutation of 1st range
if ( count_in_range_2 == 0 ) { return false; }
const auto count_in_range_1 =
count_sentinel( cursor, end_1, *cursor, cmp );
if ( count_in_range_1 != count_in_range_2 ) {
return false;
}
}
++cursor;
}
return true;
}
template <typename ForwardIter1,
typename Sentinel1,
typename ForwardIter2,
typename Sentinel2,
typename Comparator>
bool is_permutation( ForwardIter1 first_1,
const Sentinel1 end_1,
ForwardIter2 first_2,
const Sentinel2 end_2,
Comparator cmp ) {
// TODO: no optimization for stronger iterators, because we would also have to constrain on sentinel vs not sentinel types
// TODO: Comparator has to be "both sides", e.g. a == b => b == a
// This skips shared prefix of the two ranges
while (first_1 != end_1 && first_2 != end_2 && cmp(*first_1, *first_2)) {
++first_1;
++first_2;
}
// We need to handle case where at least one of the ranges has no more elements
if (first_1 == end_1 || first_2 == end_2) {
return first_1 == end_1 && first_2 == end_2;
}
// pair counting is n**2, so we pay linear walk to compare the sizes first
auto dist_1 = sentinel_distance( first_1, end_1 );
auto dist_2 = sentinel_distance( first_2, end_2 );
if (dist_1 != dist_2) { return false; }
// Since we do not try to handle stronger iterators pair (e.g.
// bidir) optimally, the only thing left to do is to check counts in
// the remaining ranges.
return check_element_counts( first_1, end_1, first_2, end_2, cmp );
}
} // namespace Detail
} // namespace Catch
#endif // CATCH_IS_PERMUTATION_HPP_INCLUDED

View File

@@ -29,12 +29,12 @@ namespace Catch {
struct GeneratorTracker : TestCaseTracking::TrackerBase, IGeneratorTracker {
GeneratorBasePtr m_generator;
GeneratorTracker( TestCaseTracking::NameAndLocation const& nameAndLocation, TrackerContext& ctx, ITracker* parent )
: TrackerBase( nameAndLocation, ctx, parent )
GeneratorTracker( TestCaseTracking::NameAndLocation&& nameAndLocation, TrackerContext& ctx, ITracker* parent )
: TrackerBase( CATCH_MOVE(nameAndLocation), ctx, parent )
{}
~GeneratorTracker() override;
static GeneratorTracker* acquire( TrackerContext& ctx, TestCaseTracking::NameAndLocation const& nameAndLocation ) {
static GeneratorTracker* acquire( TrackerContext& ctx, TestCaseTracking::NameAndLocationRef const& nameAndLocation ) {
GeneratorTracker* tracker;
ITracker& currentTracker = ctx.currentTracker();
@@ -176,13 +176,8 @@ namespace Catch {
Totals RunContext::runTest(TestCaseHandle const& testCase) {
const Totals prevTotals = m_totals;
std::string redirectedCout;
std::string redirectedCerr;
auto const& testInfo = testCase.getTestCaseInfo();
m_reporter->testCaseStarting(testInfo);
m_activeTestCase = &testCase;
@@ -224,9 +219,11 @@ namespace Catch {
seedRng( *m_config );
uint64_t testRuns = 0;
std::string redirectedCout;
std::string redirectedCerr;
do {
m_trackerContext.startCycle();
m_testCaseTracker = &SectionTracker::acquire(m_trackerContext, TestCaseTracking::NameAndLocation(testInfo.name, testInfo.lineInfo));
m_testCaseTracker = &SectionTracker::acquire(m_trackerContext, TestCaseTracking::NameAndLocationRef(testInfo.name, testInfo.lineInfo));
m_reporter->testCasePartialStarting(testInfo, testRuns);
@@ -237,7 +234,7 @@ namespace Catch {
redirectedCerr += oneRunCerr;
const auto singleRunTotals = m_totals.delta(beforeRunTotals);
auto statsForOneRun = TestCaseStats(testInfo, singleRunTotals, oneRunCout, oneRunCerr, aborting());
auto statsForOneRun = TestCaseStats(testInfo, singleRunTotals, CATCH_MOVE(oneRunCout), CATCH_MOVE(oneRunCerr), aborting());
m_reporter->testCasePartialEnded(statsForOneRun, testRuns);
++testRuns;
@@ -252,8 +249,8 @@ namespace Catch {
m_totals.testCases += deltaTotals.testCases;
m_reporter->testCaseEnded(TestCaseStats(testInfo,
deltaTotals,
redirectedCout,
redirectedCerr,
CATCH_MOVE(redirectedCout),
CATCH_MOVE(redirectedCerr),
aborting()));
m_activeTestCase = nullptr;
@@ -297,12 +294,17 @@ namespace Catch {
m_lastAssertionInfo.capturedExpression = "{Unknown expression after the reported line}"_sr;
}
bool RunContext::sectionStarted(SectionInfo const & sectionInfo, Counts & assertions) {
ITracker& sectionTracker = SectionTracker::acquire(m_trackerContext, TestCaseTracking::NameAndLocation(sectionInfo.name, sectionInfo.lineInfo));
bool RunContext::sectionStarted(StringRef sectionName, SourceLineInfo const& sectionLineInfo, Counts & assertions) {
ITracker& sectionTracker =
SectionTracker::acquire( m_trackerContext,
TestCaseTracking::NameAndLocationRef(
sectionName, sectionLineInfo ) );
if (!sectionTracker.isOpen())
return false;
m_activeSections.push_back(&sectionTracker);
SectionInfo sectionInfo( sectionLineInfo, static_cast<std::string>(sectionName) );
m_lastAssertionInfo.lineInfo = sectionInfo.lineInfo;
m_reporter->sectionStarting(sectionInfo);
@@ -317,8 +319,8 @@ namespace Catch {
using namespace Generators;
GeneratorTracker* tracker = GeneratorTracker::acquire(
m_trackerContext,
TestCaseTracking::NameAndLocation(
static_cast<std::string>( generatorName ), lineInfo ) );
TestCaseTracking::NameAndLocationRef(
generatorName, lineInfo ) );
m_lastAssertionInfo.lineInfo = lineInfo;
return tracker;
}
@@ -335,7 +337,7 @@ namespace Catch {
"Trying to create tracker for a genreator that already has one" );
auto newTracker = Catch::Detail::make_unique<Generators::GeneratorTracker>(
nameAndLoc, m_trackerContext, &currentTracker );
CATCH_MOVE(nameAndLoc), m_trackerContext, &currentTracker );
auto ret = newTracker.get();
currentTracker.addChild( CATCH_MOVE( newTracker ) );
@@ -356,7 +358,7 @@ namespace Catch {
return true;
}
void RunContext::sectionEnded(SectionEndInfo const & endInfo) {
void RunContext::sectionEnded(SectionEndInfo&& endInfo) {
Counts assertions = m_totals.assertions - endInfo.prevAssertions;
bool missingAssertions = testForMissingAssertions(assertions);
@@ -365,19 +367,20 @@ namespace Catch {
m_activeSections.pop_back();
}
m_reporter->sectionEnded(SectionStats(endInfo.sectionInfo, assertions, endInfo.durationInSeconds, missingAssertions));
m_reporter->sectionEnded(SectionStats(CATCH_MOVE(endInfo.sectionInfo), assertions, endInfo.durationInSeconds, missingAssertions));
m_messages.clear();
m_messageScopes.clear();
}
void RunContext::sectionEndedEarly(SectionEndInfo const & endInfo) {
if (m_unfinishedSections.empty())
void RunContext::sectionEndedEarly(SectionEndInfo&& endInfo) {
if ( m_unfinishedSections.empty() ) {
m_activeSections.back()->fail();
else
} else {
m_activeSections.back()->close();
}
m_activeSections.pop_back();
m_unfinishedSections.push_back(endInfo);
m_unfinishedSections.push_back(CATCH_MOVE(endInfo));
}
void RunContext::benchmarkPreparing( StringRef name ) {
@@ -401,8 +404,8 @@ 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 );
void RunContext::emplaceUnscopedMessage( MessageBuilder&& builder ) {
m_messageScopes.emplace_back( CATCH_MOVE(builder) );
}
std::string RunContext::getCurrentTestName() const {
@@ -427,7 +430,7 @@ namespace Catch {
// Instead, fake a result data.
AssertionResultData tempResult( ResultWas::FatalErrorCondition, { false } );
tempResult.message = static_cast<std::string>(message);
AssertionResult result(m_lastAssertionInfo, tempResult);
AssertionResult result(m_lastAssertionInfo, CATCH_MOVE(tempResult));
assertionEnded(result);
@@ -439,7 +442,7 @@ namespace Catch {
Counts assertions;
assertions.failed = 1;
SectionStats testCaseSectionStats(testCaseSection, assertions, 0, false);
SectionStats testCaseSectionStats(CATCH_MOVE(testCaseSection), assertions, 0, false);
m_reporter->sectionEnded(testCaseSectionStats);
auto const& testInfo = m_activeTestCase->getTestCaseInfo();
@@ -518,7 +521,7 @@ namespace Catch {
m_messages.clear();
m_messageScopes.clear();
SectionStats testCaseSectionStats(testCaseSection, assertions, duration, missingAssertions);
SectionStats testCaseSectionStats(CATCH_MOVE(testCaseSection), assertions, duration, missingAssertions);
m_reporter->sectionEnded(testCaseSectionStats);
}
@@ -542,7 +545,7 @@ namespace Catch {
itEnd = m_unfinishedSections.rend();
it != itEnd;
++it)
sectionEnded(*it);
sectionEnded(CATCH_MOVE(*it));
m_unfinishedSections.clear();
}
@@ -578,7 +581,7 @@ namespace Catch {
m_lastAssertionInfo = info;
AssertionResultData data( resultType, LazyExpression( negated ) );
AssertionResult assertionResult{ info, data };
AssertionResult assertionResult{ info, CATCH_MOVE( data ) };
assertionResult.m_resultData.lazyExpression.m_transientExpression = expr;
assertionEnded( assertionResult );
@@ -596,7 +599,8 @@ namespace Catch {
AssertionResultData data( resultType, LazyExpression( false ) );
data.message = static_cast<std::string>(message);
AssertionResult assertionResult{ m_lastAssertionInfo, data };
AssertionResult assertionResult{ m_lastAssertionInfo,
CATCH_MOVE( data ) };
assertionEnded( assertionResult );
if ( !assertionResult.isOk() ) {
populateReaction( reaction );
@@ -622,7 +626,7 @@ namespace Catch {
AssertionResultData data( ResultWas::ThrewException, LazyExpression( false ) );
data.message = message;
AssertionResult assertionResult{ info, data };
AssertionResult assertionResult{ info, CATCH_MOVE(data) };
assertionEnded( assertionResult );
populateReaction( reaction );
}
@@ -635,11 +639,12 @@ namespace Catch {
void RunContext::handleIncomplete(
AssertionInfo const& info
) {
using namespace std::string_literals;
m_lastAssertionInfo = info;
AssertionResultData data( ResultWas::ThrewException, LazyExpression( false ) );
data.message = "Exception translation was disabled by CATCH_CONFIG_FAST_COMPILE";
AssertionResult assertionResult{ info, data };
data.message = "Exception translation was disabled by CATCH_CONFIG_FAST_COMPILE"s;
AssertionResult assertionResult{ info, CATCH_MOVE( data ) };
assertionEnded( assertionResult );
}
void RunContext::handleNonExpr(
@@ -650,7 +655,7 @@ namespace Catch {
m_lastAssertionInfo = info;
AssertionResultData data( resultType, LazyExpression( false ) );
AssertionResult assertionResult{ info, data };
AssertionResult assertionResult{ info, CATCH_MOVE( data ) };
assertionEnded( assertionResult );
if( !assertionResult.isOk() )

View File

@@ -68,10 +68,12 @@ namespace Catch {
ResultWas::OfType resultType,
AssertionReaction &reaction ) override;
bool sectionStarted( SectionInfo const& sectionInfo, Counts& assertions ) override;
bool sectionStarted( StringRef sectionName,
SourceLineInfo const& sectionLineInfo,
Counts& assertions ) override;
void sectionEnded( SectionEndInfo const& endInfo ) override;
void sectionEndedEarly( SectionEndInfo const& endInfo ) override;
void sectionEnded( SectionEndInfo&& endInfo ) override;
void sectionEndedEarly( SectionEndInfo&& endInfo ) override;
IGeneratorTracker*
acquireGeneratorTracker( StringRef generatorName,
@@ -90,7 +92,7 @@ namespace Catch {
void pushScopedMessage( MessageInfo const& message ) override;
void popScopedMessage( MessageInfo const& message ) override;
void emplaceUnscopedMessage( MessageBuilder const& builder ) override;
void emplaceUnscopedMessage( MessageBuilder&& builder ) override;
std::string getCurrentTestName() const override;

View File

@@ -15,7 +15,7 @@ namespace Catch {
Section::Section( SectionInfo&& info ):
m_info( CATCH_MOVE( info ) ),
m_sectionIncluded(
getResultCapture().sectionStarted( m_info, m_assertions ) ) {
getResultCapture().sectionStarted( m_info.name, m_info.lineInfo, m_assertions ) ) {
// Non-"included" sections will not use the timing information
// anyway, so don't bother with the potential syscall.
if (m_sectionIncluded) {
@@ -23,13 +23,31 @@ namespace Catch {
}
}
Section::Section( SourceLineInfo const& _lineInfo,
StringRef _name,
const char* const ):
m_info( { "invalid", static_cast<std::size_t>( -1 ) }, std::string{} ),
m_sectionIncluded(
getResultCapture().sectionStarted( _name, _lineInfo, m_assertions ) ) {
// We delay initialization the SectionInfo member until we know
// this section needs it, so we avoid allocating std::string for name.
// We also delay timer start to avoid the potential syscall unless we
// will actually use the result.
if ( m_sectionIncluded ) {
m_info.name = static_cast<std::string>( _name );
m_info.lineInfo = _lineInfo;
m_timer.start();
}
}
Section::~Section() {
if( m_sectionIncluded ) {
SectionEndInfo endInfo{ m_info, m_assertions, m_timer.getElapsedSeconds() };
if( uncaught_exceptions() )
getResultCapture().sectionEndedEarly( endInfo );
else
getResultCapture().sectionEnded( endInfo );
SectionEndInfo endInfo{ CATCH_MOVE(m_info), m_assertions, m_timer.getElapsedSeconds() };
if ( uncaught_exceptions() ) {
getResultCapture().sectionEndedEarly( CATCH_MOVE(endInfo) );
} else {
getResultCapture().sectionEnded( CATCH_MOVE( endInfo ) );
}
}
}

View File

@@ -20,6 +20,9 @@ namespace Catch {
class Section : Detail::NonCopyable {
public:
Section( SectionInfo&& info );
Section( SourceLineInfo const& _lineInfo,
StringRef _name,
const char* const = nullptr );
~Section();
// This indicates whether the section should be executed or not
@@ -38,7 +41,7 @@ namespace Catch {
#define INTERNAL_CATCH_SECTION( ... ) \
CATCH_INTERNAL_START_WARNINGS_SUPPRESSION \
CATCH_INTERNAL_SUPPRESS_UNUSED_VARIABLE_WARNINGS \
if( Catch::Section const& INTERNAL_CATCH_UNIQUE_NAME( catch_internal_Section ) = Catch::SectionInfo( CATCH_INTERNAL_LINEINFO, __VA_ARGS__ ) ) \
if( Catch::Section const& INTERNAL_CATCH_UNIQUE_NAME( catch_internal_Section ) = Catch::Section( CATCH_INTERNAL_LINEINFO, __VA_ARGS__ ) ) \
CATCH_INTERNAL_STOP_WARNINGS_SUPPRESSION
#define INTERNAL_CATCH_DYNAMIC_SECTION( ... ) \

View File

@@ -17,10 +17,6 @@ namespace Catch {
: StringRef( rawChars, std::strlen(rawChars) )
{}
auto StringRef::operator == ( StringRef other ) const noexcept -> bool {
return m_size == other.m_size
&& (std::memcmp( m_start, other.m_start, m_size ) == 0);
}
bool StringRef::operator<(StringRef rhs) const noexcept {
if (m_size < rhs.m_size) {

View File

@@ -13,6 +13,8 @@
#include <iosfwd>
#include <cassert>
#include <cstring>
namespace Catch {
/// A non-owning string class (similar to the forthcoming std::string_view)
@@ -49,7 +51,10 @@ namespace Catch {
}
public: // operators
auto operator == ( StringRef other ) const noexcept -> bool;
auto operator == ( StringRef other ) const noexcept -> bool {
return m_size == other.m_size
&& (std::memcmp( m_start, other.m_start, m_size ) == 0);
}
auto operator != (StringRef other) const noexcept -> bool {
return !(*this == other);
}

View File

@@ -181,7 +181,7 @@
void reg_tests() { \
size_t index = 0; \
using expander = size_t[]; \
(void)expander{(Catch::AutoReg( Catch::makeTestInvoker( &TestFunc<Types> ), CATCH_INTERNAL_LINEINFO, Catch::StringRef(), Catch::NameAndTags{ Name " - " + std::string(INTERNAL_CATCH_STRINGIZE(TmplList)) + " - " + std::to_string(index), Tags } ), index++)... };/* NOLINT */\
(void)expander{(Catch::AutoReg( Catch::makeTestInvoker( &TestFunc<Types> ), CATCH_INTERNAL_LINEINFO, Catch::StringRef(), Catch::NameAndTags{ Name " - " INTERNAL_CATCH_STRINGIZE(TmplList) " - " + std::to_string(index), Tags } ), index++)... };/* NOLINT */\
} \
};\
static int INTERNAL_CATCH_UNIQUE_NAME( globalRegistrar ) = [](){ \
@@ -316,7 +316,7 @@
void reg_tests(){\
size_t index = 0;\
using expander = size_t[];\
(void)expander{(Catch::AutoReg( Catch::makeTestInvoker( &TestName<Types>::test ), CATCH_INTERNAL_LINEINFO, #ClassName, Catch::NameAndTags{ Name " - " + std::string(INTERNAL_CATCH_STRINGIZE(TmplList)) + " - " + std::to_string(index), Tags } ), index++)... };/* NOLINT */ \
(void)expander{(Catch::AutoReg( Catch::makeTestInvoker( &TestName<Types>::test ), CATCH_INTERNAL_LINEINFO, #ClassName##_catch_sr, Catch::NameAndTags{ Name " - " INTERNAL_CATCH_STRINGIZE(TmplList) " - " + std::to_string(index), Tags } ), index++)... };/* NOLINT */ \
}\
};\
static int INTERNAL_CATCH_UNIQUE_NAME( globalRegistrar ) = [](){\

View File

@@ -22,8 +22,8 @@
namespace Catch {
namespace TestCaseTracking {
NameAndLocation::NameAndLocation( std::string const& _name, SourceLineInfo const& _location )
: name( _name ),
NameAndLocation::NameAndLocation( std::string&& _name, SourceLineInfo const& _location )
: name( CATCH_MOVE(_name) ),
location( _location )
{}
@@ -38,14 +38,17 @@ namespace TestCaseTracking {
m_children.push_back( CATCH_MOVE(child) );
}
ITracker* ITracker::findChild( NameAndLocation const& nameAndLocation ) {
ITracker* ITracker::findChild( NameAndLocationRef const& nameAndLocation ) {
auto it = std::find_if(
m_children.begin(),
m_children.end(),
[&nameAndLocation]( ITrackerPtr const& tracker ) {
return tracker->nameAndLocation().location ==
nameAndLocation.location &&
tracker->nameAndLocation().name == nameAndLocation.name;
auto const& tnameAndLoc = tracker->nameAndLocation();
if ( tnameAndLoc.location.line !=
nameAndLocation.location.line ) {
return false;
}
return tnameAndLoc == nameAndLocation;
} );
return ( it != m_children.end() ) ? it->get() : nullptr;
}
@@ -53,10 +56,6 @@ namespace TestCaseTracking {
bool ITracker::isSectionTracker() const { return false; }
bool ITracker::isGeneratorTracker() const { return false; }
bool ITracker::isSuccessfullyCompleted() const {
return m_runState == CompletedSuccessfully;
}
bool ITracker::isOpen() const {
return m_runState != NotStarted && !isComplete();
}
@@ -83,16 +82,6 @@ namespace TestCaseTracking {
return *m_rootTracker;
}
void TrackerContext::endRun() {
m_rootTracker.reset();
m_currentTracker = nullptr;
m_runState = NotStarted;
}
void TrackerContext::startCycle() {
m_currentTracker = m_rootTracker.get();
m_runState = Executing;
}
void TrackerContext::completeCycle() {
m_runState = CompletedCycle;
}
@@ -100,16 +89,13 @@ namespace TestCaseTracking {
bool TrackerContext::completedCycle() const {
return m_runState == CompletedCycle;
}
ITracker& TrackerContext::currentTracker() {
return *m_currentTracker;
}
void TrackerContext::setCurrentTracker( ITracker* tracker ) {
m_currentTracker = tracker;
}
TrackerBase::TrackerBase( NameAndLocation const& nameAndLocation, TrackerContext& ctx, ITracker* parent ):
ITracker(nameAndLocation, parent),
TrackerBase::TrackerBase( NameAndLocation&& nameAndLocation, TrackerContext& ctx, ITracker* parent ):
ITracker(CATCH_MOVE(nameAndLocation), parent),
m_ctx( ctx )
{}
@@ -169,13 +155,14 @@ namespace TestCaseTracking {
m_ctx.setCurrentTracker( this );
}
SectionTracker::SectionTracker( NameAndLocation const& nameAndLocation, TrackerContext& ctx, ITracker* parent )
: TrackerBase( nameAndLocation, ctx, parent ),
m_trimmed_name(trim(nameAndLocation.name))
SectionTracker::SectionTracker( NameAndLocation&& nameAndLocation, TrackerContext& ctx, ITracker* parent )
: TrackerBase( CATCH_MOVE(nameAndLocation), ctx, parent ),
m_trimmed_name(trim(StringRef(ITracker::nameAndLocation().name)))
{
if( parent ) {
while( !parent->isSectionTracker() )
while ( !parent->isSectionTracker() ) {
parent = parent->parent();
}
SectionTracker& parentSection = static_cast<SectionTracker&>( *parent );
addNextFilters( parentSection.m_filters );
@@ -195,24 +182,30 @@ namespace TestCaseTracking {
bool SectionTracker::isSectionTracker() const { return true; }
SectionTracker& SectionTracker::acquire( TrackerContext& ctx, NameAndLocation const& nameAndLocation ) {
SectionTracker* section;
SectionTracker& SectionTracker::acquire( TrackerContext& ctx, NameAndLocationRef const& nameAndLocation ) {
SectionTracker* tracker;
ITracker& currentTracker = ctx.currentTracker();
if ( ITracker* childTracker =
currentTracker.findChild( nameAndLocation ) ) {
assert( childTracker );
assert( childTracker->isSectionTracker() );
section = static_cast<SectionTracker*>( childTracker );
tracker = static_cast<SectionTracker*>( childTracker );
} else {
auto newSection = Catch::Detail::make_unique<SectionTracker>(
nameAndLocation, ctx, &currentTracker );
section = newSection.get();
currentTracker.addChild( CATCH_MOVE( newSection ) );
auto newTracker = Catch::Detail::make_unique<SectionTracker>(
NameAndLocation{ static_cast<std::string>(nameAndLocation.name),
nameAndLocation.location },
ctx,
&currentTracker );
tracker = newTracker.get();
currentTracker.addChild( CATCH_MOVE( newTracker ) );
}
if( !ctx.completedCycle() )
section->tryOpen();
return *section;
if ( !ctx.completedCycle() ) {
tracker->tryOpen();
}
return *tracker;
}
void SectionTracker::tryOpen() {
@@ -233,10 +226,6 @@ namespace TestCaseTracking {
m_filters.insert( m_filters.end(), filters.begin()+1, filters.end() );
}
std::vector<StringRef> const& SectionTracker::getFilters() const {
return m_filters;
}
StringRef SectionTracker::trimmedName() const {
return m_trimmed_name;
}

View File

@@ -22,10 +22,14 @@ namespace TestCaseTracking {
std::string name;
SourceLineInfo location;
NameAndLocation( std::string const& _name, SourceLineInfo const& _location );
NameAndLocation( std::string&& _name, SourceLineInfo const& _location );
friend bool operator==(NameAndLocation const& lhs, NameAndLocation const& rhs) {
return lhs.name == rhs.name
&& lhs.location == rhs.location;
// This is a very cheap check that should have a very high hit rate.
// If we get to SourceLineInfo::operator==, we will redo it, but the
// cost of repeating is trivial at that point (we will be paying
// multiple strcmp/memcmps at that point).
if ( lhs.location.line != rhs.location.line ) { return false; }
return lhs.name == rhs.name && lhs.location == rhs.location;
}
friend bool operator!=(NameAndLocation const& lhs,
NameAndLocation const& rhs) {
@@ -33,6 +37,37 @@ namespace TestCaseTracking {
}
};
/**
* This is a variant of `NameAndLocation` that does not own the name string
*
* This avoids extra allocations when trying to locate a tracker by its
* name and location, as long as we make sure that trackers only keep
* around the owning variant.
*/
struct NameAndLocationRef {
StringRef name;
SourceLineInfo location;
constexpr NameAndLocationRef( StringRef name_,
SourceLineInfo location_ ):
name( name_ ), location( location_ ) {}
friend bool operator==( NameAndLocation const& lhs,
NameAndLocationRef const& rhs ) {
// This is a very cheap check that should have a very high hit rate.
// If we get to SourceLineInfo::operator==, we will redo it, but the
// cost of repeating is trivial at that point (we will be paying
// multiple strcmp/memcmps at that point).
if ( lhs.location.line != rhs.location.line ) { return false; }
return StringRef( lhs.name ) == rhs.name &&
lhs.location == rhs.location;
}
friend bool operator==( NameAndLocationRef const& lhs,
NameAndLocation const& rhs ) {
return rhs == lhs;
}
};
class ITracker;
using ITrackerPtr = Catch::Detail::unique_ptr<ITracker>;
@@ -57,8 +92,8 @@ namespace TestCaseTracking {
CycleState m_runState = NotStarted;
public:
ITracker( NameAndLocation const& nameAndLoc, ITracker* parent ):
m_nameAndLocation( nameAndLoc ),
ITracker( NameAndLocation&& nameAndLoc, ITracker* parent ):
m_nameAndLocation( CATCH_MOVE(nameAndLoc) ),
m_parent( parent )
{}
@@ -79,7 +114,9 @@ namespace TestCaseTracking {
//! Returns true if tracker run to completion (successfully or not)
virtual bool isComplete() const = 0;
//! Returns true if tracker run to completion succesfully
bool isSuccessfullyCompleted() const;
bool isSuccessfullyCompleted() const {
return m_runState == CompletedSuccessfully;
}
//! Returns true if tracker has started but hasn't been completed
bool isOpen() const;
//! Returns true iff tracker has started
@@ -97,7 +134,7 @@ namespace TestCaseTracking {
*
* Returns nullptr if not found.
*/
ITracker* findChild( NameAndLocation const& nameAndLocation );
ITracker* findChild( NameAndLocationRef const& nameAndLocation );
//! Have any children been added?
bool hasChildren() const {
return !m_children.empty();
@@ -138,13 +175,15 @@ namespace TestCaseTracking {
public:
ITracker& startRun();
void endRun();
void startCycle();
void startCycle() {
m_currentTracker = m_rootTracker.get();
m_runState = Executing;
}
void completeCycle();
bool completedCycle() const;
ITracker& currentTracker();
ITracker& currentTracker() { return *m_currentTracker; }
void setCurrentTracker( ITracker* tracker );
};
@@ -154,7 +193,7 @@ namespace TestCaseTracking {
TrackerContext& m_ctx;
public:
TrackerBase( NameAndLocation const& nameAndLocation, TrackerContext& ctx, ITracker* parent );
TrackerBase( NameAndLocation&& nameAndLocation, TrackerContext& ctx, ITracker* parent );
bool isComplete() const override;
@@ -170,22 +209,26 @@ namespace TestCaseTracking {
class SectionTracker : public TrackerBase {
std::vector<StringRef> m_filters;
std::string m_trimmed_name;
// Note that lifetime-wise we piggy back off the name stored in the `ITracker` parent`.
// Currently it allocates owns the name, so this is safe. If it is later refactored
// to not own the name, the name still has to outlive the `ITracker` parent, so
// this should still be safe.
StringRef m_trimmed_name;
public:
SectionTracker( NameAndLocation const& nameAndLocation, TrackerContext& ctx, ITracker* parent );
SectionTracker( NameAndLocation&& nameAndLocation, TrackerContext& ctx, ITracker* parent );
bool isSectionTracker() const override;
bool isComplete() const override;
static SectionTracker& acquire( TrackerContext& ctx, NameAndLocation const& nameAndLocation );
static SectionTracker& acquire( TrackerContext& ctx, NameAndLocationRef const& nameAndLocation );
void tryOpen();
void addInitialFilters( std::vector<std::string> const& filters );
void addNextFilters( std::vector<StringRef> const& filters );
//! Returns filters active in this tracker
std::vector<StringRef> const& getFilters() const;
std::vector<StringRef> const& getFilters() const { return m_filters; }
//! Returns whitespace-trimmed name of the tracked section
StringRef trimmedName() const;
};

View File

@@ -23,9 +23,9 @@
#if !defined(CATCH_CONFIG_DISABLE)
#if !defined(CATCH_CONFIG_DISABLE_STRINGIFICATION)
#define CATCH_INTERNAL_STRINGIFY(...) #__VA_ARGS__
#define CATCH_INTERNAL_STRINGIFY(...) #__VA_ARGS__##_catch_sr
#else
#define CATCH_INTERNAL_STRINGIFY(...) "Disabled by CATCH_CONFIG_DISABLE_STRINGIFICATION"
#define CATCH_INTERNAL_STRINGIFY(...) "Disabled by CATCH_CONFIG_DISABLE_STRINGIFICATION"_catch_sr
#endif
#if defined(CATCH_CONFIG_FAST_COMPILE) || defined(CATCH_CONFIG_DISABLE_EXCEPTIONS)

View File

@@ -89,7 +89,13 @@ struct AutoReg : Detail::NonCopyable {
CATCH_INTERNAL_START_WARNINGS_SUPPRESSION \
CATCH_INTERNAL_SUPPRESS_GLOBALS_WARNINGS \
CATCH_INTERNAL_SUPPRESS_UNUSED_VARIABLE_WARNINGS \
namespace{ const Catch::AutoReg INTERNAL_CATCH_UNIQUE_NAME( autoRegistrar )( Catch::makeTestInvoker( &QualifiedMethod ), CATCH_INTERNAL_LINEINFO, "&" #QualifiedMethod, Catch::NameAndTags{ __VA_ARGS__ } ); } /* NOLINT */ \
namespace { \
const Catch::AutoReg INTERNAL_CATCH_UNIQUE_NAME( autoRegistrar )( \
Catch::makeTestInvoker( &QualifiedMethod ), \
CATCH_INTERNAL_LINEINFO, \
"&" #QualifiedMethod##_catch_sr, \
Catch::NameAndTags{ __VA_ARGS__ } ); \
} /* NOLINT */ \
CATCH_INTERNAL_STOP_WARNINGS_SUPPRESSION
///////////////////////////////////////////////////////////////////////////////
@@ -101,7 +107,11 @@ struct AutoReg : Detail::NonCopyable {
struct TestName : INTERNAL_CATCH_REMOVE_PARENS(ClassName) { \
void test(); \
}; \
const Catch::AutoReg INTERNAL_CATCH_UNIQUE_NAME( autoRegistrar ) ( Catch::makeTestInvoker( &TestName::test ), CATCH_INTERNAL_LINEINFO, #ClassName, Catch::NameAndTags{ __VA_ARGS__ } ); /* NOLINT */ \
const Catch::AutoReg INTERNAL_CATCH_UNIQUE_NAME( autoRegistrar )( \
Catch::makeTestInvoker( &TestName::test ), \
CATCH_INTERNAL_LINEINFO, \
#ClassName##_catch_sr, \
Catch::NameAndTags{ __VA_ARGS__ } ); /* NOLINT */ \
} \
CATCH_INTERNAL_STOP_WARNINGS_SUPPRESSION \
void TestName::test()

View File

@@ -221,10 +221,8 @@ namespace Catch {
token.erase(token.begin());
if (m_exclusion) {
m_currentFilter.m_forbidden.emplace_back(Detail::make_unique<TestSpec::TagPattern>(".", m_substring));
m_currentFilter.m_forbidden.emplace_back(Detail::make_unique<TestSpec::TagPattern>(token, m_substring));
} else {
m_currentFilter.m_required.emplace_back(Detail::make_unique<TestSpec::TagPattern>(".", m_substring));
m_currentFilter.m_required.emplace_back(Detail::make_unique<TestSpec::TagPattern>(token, m_substring));
}
}
if (m_exclusion) {

View File

@@ -33,13 +33,11 @@ namespace Catch {
}
template <typename RangeLike>
bool match(RangeLike&& rng) const {
using std::begin; using std::end;
return end(rng) != std::find_if(begin(rng), end(rng),
[&](auto const& elem) {
return m_eq(elem, m_desired);
});
bool match( RangeLike&& rng ) const {
for ( auto&& elem : rng ) {
if ( m_eq( elem, m_desired ) ) { return true; }
}
return false;
}
};
@@ -91,7 +89,7 @@ namespace Catch {
/**
* Creates a matcher that checks whether a range contains a specific element.
*
* Uses `eq` to do the comparisons
* Uses `eq` to do the comparisons, the element is provided on the rhs
*/
template <typename T, typename Equality>
ContainsElementMatcher<T, Equality> Contains(T&& elem, Equality&& eq) {

View File

@@ -225,5 +225,17 @@ WithinRelMatcher WithinRel(float target) {
}
} // namespace Matchers
bool IsNaNMatcher::match( double const& matchee ) const {
return std::isnan( matchee );
}
std::string IsNaNMatcher::describe() const {
using namespace std::string_literals;
return "is NaN"s;
}
IsNaNMatcher IsNaN() { return IsNaNMatcher(); }
} // namespace Matchers
} // namespace Catch

View File

@@ -27,6 +27,11 @@ namespace Matchers {
double m_margin;
};
//! Creates a matcher that accepts numbers within certain range of target
WithinAbsMatcher WithinAbs( double target, double margin );
class WithinUlpsMatcher final : public MatcherBase<double> {
public:
WithinUlpsMatcher( double target,
@@ -40,6 +45,13 @@ namespace Matchers {
Detail::FloatingPointKind m_type;
};
//! Creates a matcher that accepts doubles within certain ULP range of target
WithinUlpsMatcher WithinULP(double target, uint64_t maxUlpDiff);
//! Creates a matcher that accepts floats within certain ULP range of target
WithinUlpsMatcher WithinULP(float target, uint64_t maxUlpDiff);
// Given IEEE-754 format for floats and doubles, we can assume
// that float -> double promotion is lossless. Given this, we can
// assume that if we do the standard relative comparison of
@@ -56,13 +68,6 @@ namespace Matchers {
double m_epsilon;
};
//! Creates a matcher that accepts doubles within certain ULP range of target
WithinUlpsMatcher WithinULP(double target, uint64_t maxUlpDiff);
//! Creates a matcher that accepts floats within certain ULP range of target
WithinUlpsMatcher WithinULP(float target, uint64_t maxUlpDiff);
//! Creates a matcher that accepts numbers within certain range of target
WithinAbsMatcher WithinAbs(double target, double margin);
//! Creates a matcher that accepts doubles within certain relative range of target
WithinRelMatcher WithinRel(double target, double eps);
//! Creates a matcher that accepts doubles within 100*DBL_EPS relative range of target
@@ -72,6 +77,17 @@ namespace Matchers {
//! Creates a matcher that accepts floats within 100*FLT_EPS relative range of target
WithinRelMatcher WithinRel(float target);
class IsNaNMatcher final : public MatcherBase<double> {
public:
IsNaNMatcher() = default;
bool match( double const& matchee ) const override;
std::string describe() const override;
};
IsNaNMatcher IsNaN();
} // namespace Matchers
} // namespace Catch

View File

@@ -8,8 +8,10 @@
#ifndef CATCH_MATCHERS_RANGE_EQUALS_HPP_INCLUDED
#define CATCH_MATCHERS_RANGE_EQUALS_HPP_INCLUDED
#include <algorithm>
#include <catch2/internal/catch_is_permutation.hpp>
#include <catch2/matchers/catch_matchers_templated.hpp>
#include <algorithm>
#include <utility>
namespace Catch {
@@ -33,13 +35,19 @@ namespace Catch {
template <typename RangeLike>
bool match( RangeLike&& rng ) const {
using std::begin;
using std::end;
return std::equal( begin(m_desired),
end(m_desired),
begin(rng),
end(rng),
m_predicate );
auto rng_start = begin( rng );
const auto rng_end = end( rng );
auto target_start = begin( m_desired );
const auto target_end = end( m_desired );
while (rng_start != rng_end && target_start != target_end) {
if (!m_predicate(*rng_start, *target_start)) {
return false;
}
++rng_start;
++target_start;
}
return rng_start == rng_end && target_start == target_end;
}
std::string describe() const override {
@@ -67,11 +75,11 @@ namespace Catch {
bool match( RangeLike&& rng ) const {
using std::begin;
using std::end;
return std::is_permutation( begin( m_desired ),
end( m_desired ),
begin( rng ),
end( rng ),
m_predicate );
return Catch::Detail::is_permutation( begin( m_desired ),
end( m_desired ),
begin( rng ),
end( rng ),
m_predicate );
}
std::string describe() const override {

View File

@@ -93,6 +93,7 @@ internal_headers = [
'internal/catch_floating_point_helpers.hpp',
'internal/catch_getenv.hpp',
'internal/catch_istream.hpp',
'internal/catch_is_permutation.hpp',
'internal/catch_lazy_expr.hpp',
'internal/catch_leak_detector.hpp',
'internal/catch_list.hpp',

View File

@@ -192,7 +192,7 @@ private:
private:
std::ostream& stream;
AssertionResult const& result;
std::vector<MessageInfo> messages;
std::vector<MessageInfo> const& messages;
std::vector<MessageInfo>::const_iterator itMessage;
bool printInfoMessages;
ColourImpl* colourImpl;

View File

@@ -51,7 +51,6 @@ public:
stats(_stats),
result(_stats.assertionResult),
colour(Colour::None),
message(result.getMessage()),
messages(_stats.infoMessages),
colourImpl(colourImpl_),
printInfoMessages(_printInfoMessages) {
@@ -60,10 +59,10 @@ public:
colour = Colour::Success;
passOrFail = "PASSED"_sr;
//if( result.hasMessage() )
if (_stats.infoMessages.size() == 1)
messageLabel = "with message";
if (_stats.infoMessages.size() > 1)
messageLabel = "with messages";
if (messages.size() == 1)
messageLabel = "with message"_sr;
if (messages.size() > 1)
messageLabel = "with messages"_sr;
break;
case ResultWas::ExpressionFailed:
if (result.isOk()) {
@@ -73,51 +72,57 @@ public:
colour = Colour::Error;
passOrFail = "FAILED"_sr;
}
if (_stats.infoMessages.size() == 1)
messageLabel = "with message";
if (_stats.infoMessages.size() > 1)
messageLabel = "with messages";
if (messages.size() == 1)
messageLabel = "with message"_sr;
if (messages.size() > 1)
messageLabel = "with messages"_sr;
break;
case ResultWas::ThrewException:
colour = Colour::Error;
passOrFail = "FAILED"_sr;
messageLabel = "due to unexpected exception with ";
if (_stats.infoMessages.size() == 1)
messageLabel += "message";
if (_stats.infoMessages.size() > 1)
messageLabel += "messages";
// todo switch
switch (messages.size()) { case 0:
messageLabel = "due to unexpected exception with "_sr;
break;
case 1:
messageLabel = "due to unexpected exception with message"_sr;
break;
default:
messageLabel = "due to unexpected exception with messages"_sr;
break;
}
break;
case ResultWas::FatalErrorCondition:
colour = Colour::Error;
passOrFail = "FAILED"_sr;
messageLabel = "due to a fatal error condition";
messageLabel = "due to a fatal error condition"_sr;
break;
case ResultWas::DidntThrowException:
colour = Colour::Error;
passOrFail = "FAILED"_sr;
messageLabel = "because no exception was thrown where one was expected";
messageLabel = "because no exception was thrown where one was expected"_sr;
break;
case ResultWas::Info:
messageLabel = "info";
messageLabel = "info"_sr;
break;
case ResultWas::Warning:
messageLabel = "warning";
messageLabel = "warning"_sr;
break;
case ResultWas::ExplicitFailure:
passOrFail = "FAILED"_sr;
colour = Colour::Error;
if (_stats.infoMessages.size() == 1)
messageLabel = "explicitly with message";
if (_stats.infoMessages.size() > 1)
messageLabel = "explicitly with messages";
if (messages.size() == 1)
messageLabel = "explicitly with message"_sr;
if (messages.size() > 1)
messageLabel = "explicitly with messages"_sr;
break;
case ResultWas::ExplicitSkip:
colour = Colour::Skip;
passOrFail = "SKIPPED"_sr;
if (_stats.infoMessages.size() == 1)
messageLabel = "explicitly with message";
if (_stats.infoMessages.size() > 1)
messageLabel = "explicitly with messages";
if (messages.size() == 1)
messageLabel = "explicitly with message"_sr;
if (messages.size() > 1)
messageLabel = "explicitly with messages"_sr;
break;
// These cases are here to prevent compiler warnings
case ResultWas::Unknown:
@@ -181,9 +186,8 @@ private:
AssertionResult const& result;
Colour::Code colour;
StringRef passOrFail;
std::string messageLabel;
std::string message;
std::vector<MessageInfo> messages;
StringRef messageLabel;
std::vector<MessageInfo> const& messages;
ColourImpl* colourImpl;
bool printInfoMessages;
};

View File

@@ -70,7 +70,8 @@ namespace Catch {
void
CumulativeReporterBase::sectionStarting( SectionInfo const& sectionInfo ) {
SectionStats incompleteStats( sectionInfo, Counts(), 0, false );
// We need a copy, because SectionStats expect to take ownership
SectionStats incompleteStats( SectionInfo(sectionInfo), Counts(), 0, false );
SectionNode* node;
if ( m_sectionStack.empty() ) {
if ( !m_rootSection ) {

View File

@@ -118,7 +118,7 @@ namespace Catch {
CATCH_INTERNAL_SUPPRESS_GLOBALS_WARNINGS \
namespace { \
Catch::ListenerRegistrar<listenerType> INTERNAL_CATCH_UNIQUE_NAME( \
catch_internal_RegistrarFor )( #listenerType ); \
catch_internal_RegistrarFor )( #listenerType##_catch_sr ); \
} \
CATCH_INTERNAL_STOP_WARNINGS_SUPPRESSION

View File

@@ -40,7 +40,7 @@ namespace Catch {
}
void SonarQubeReporter::writeRun( TestRunNode const& runNode ) {
std::map<std::string, std::vector<TestCaseNode const*>> testsPerFile;
std::map<StringRef, std::vector<TestCaseNode const*>> testsPerFile;
for ( auto const& child : runNode.children ) {
testsPerFile[child->value.testInfo->lineInfo.file].push_back(
@@ -52,7 +52,7 @@ namespace Catch {
}
}
void SonarQubeReporter::writeTestFile(std::string const& filename, std::vector<TestCaseNode const*> const& testCaseNodes) {
void SonarQubeReporter::writeTestFile(StringRef filename, std::vector<TestCaseNode const*> const& testCaseNodes) {
XmlWriter::ScopedElement e = xml.scopedElement("file");
xml.writeAttribute("path"_sr, filename);

View File

@@ -41,7 +41,7 @@ namespace Catch {
void writeRun( TestRunNode const& groupNode );
void writeTestFile(std::string const& filename, std::vector<TestCaseNode const*> const& testCaseNodes);
void writeTestFile(StringRef filename, std::vector<TestCaseNode const*> const& testCaseNodes);
void writeTestCase(TestCaseNode const& testCaseNode);

View File

@@ -184,7 +184,7 @@ namespace Catch {
private:
std::ostream& stream;
AssertionResult const& result;
std::vector<MessageInfo> messages;
std::vector<MessageInfo> const& messages;
std::vector<MessageInfo>::const_iterator itMessage;
bool printInfoMessages;
std::size_t counter;

View File

@@ -66,7 +66,7 @@ namespace Catch {
void XmlReporter::testCaseStarting( TestCaseInfo const& testInfo ) {
StreamingReporterBase::testCaseStarting(testInfo);
m_xml.startElement( "TestCase" )
.writeAttribute( "name"_sr, trim( testInfo.name ) )
.writeAttribute( "name"_sr, trim( StringRef(testInfo.name) ) )
.writeAttribute( "tags"_sr, testInfo.tagsAsString() );
writeSourceInfo( testInfo.lineInfo );
@@ -80,7 +80,7 @@ namespace Catch {
StreamingReporterBase::sectionStarting( sectionInfo );
if( m_sectionDepth++ > 0 ) {
m_xml.startElement( "Section" )
.writeAttribute( "name"_sr, trim( sectionInfo.name ) );
.writeAttribute( "name"_sr, trim( StringRef(sectionInfo.name) ) );
writeSourceInfo( sectionInfo.lineInfo );
m_xml.ensureTagClosed();
}
@@ -194,11 +194,10 @@ namespace Catch {
if ( m_config->showDurations() == ShowDurations::Always )
e.writeAttribute( "durationInSeconds"_sr, m_testCaseTimer.getElapsedSeconds() );
if( !testCaseStats.stdOut.empty() )
m_xml.scopedElement( "StdOut" ).writeText( trim( testCaseStats.stdOut ), XmlFormatting::Newline );
m_xml.scopedElement( "StdOut" ).writeText( trim( StringRef(testCaseStats.stdOut) ), XmlFormatting::Newline );
if( !testCaseStats.stdErr.empty() )
m_xml.scopedElement( "StdErr" ).writeText( trim( testCaseStats.stdErr ), XmlFormatting::Newline );
m_xml.scopedElement( "StdErr" ).writeText( trim( StringRef(testCaseStats.stdErr) ), XmlFormatting::Newline );
m_xml.endElement();
}

View File

@@ -77,6 +77,7 @@ endif(MSVC) #Temporary workaround
# Please keep these ordered alphabetically
set(TEST_SOURCES
${SELF_TEST_DIR}/TestRegistrations.cpp
${SELF_TEST_DIR}/IntrospectiveTests/Algorithms.tests.cpp
${SELF_TEST_DIR}/IntrospectiveTests/Clara.tests.cpp
${SELF_TEST_DIR}/IntrospectiveTests/CmdLine.tests.cpp
${SELF_TEST_DIR}/IntrospectiveTests/CmdLineHelpers.tests.cpp
@@ -134,6 +135,7 @@ set(TEST_SOURCES
set(TEST_HEADERS
${SELF_TEST_DIR}/helpers/parse_test_spec.hpp
${SELF_TEST_DIR}/helpers/range_test_helpers.hpp
${SELF_TEST_DIR}/helpers/type_with_lit_0_comparisons.hpp
)

View File

@@ -151,6 +151,7 @@ Nor would this
:test-result: FAIL FAIL does not require an argument
:test-result: FAIL FAIL_CHECK does not abort the test
:test-result: PASS Factorials are computed
:test-result: PASS Filter generator throws exception for empty generator
:test-result: PASS Floating point matchers: double
:test-result: PASS Floating point matchers: float
:test-result: PASS Generators -- adapters

View File

@@ -149,6 +149,7 @@
:test-result: FAIL FAIL does not require an argument
:test-result: FAIL FAIL_CHECK does not abort the test
:test-result: PASS Factorials are computed
:test-result: PASS Filter generator throws exception for empty generator
:test-result: PASS Floating point matchers: double
:test-result: PASS Floating point matchers: float
:test-result: PASS Generators -- adapters

View File

@@ -599,6 +599,7 @@ Misc.tests.cpp:<line number>: passed: Factorial(1) == 1 for: 1 == 1
Misc.tests.cpp:<line number>: passed: Factorial(2) == 2 for: 2 == 2
Misc.tests.cpp:<line number>: passed: Factorial(3) == 6 for: 6 == 6
Misc.tests.cpp:<line number>: passed: Factorial(10) == 3628800 for: 3628800 (0x<hex digits>) == 3628800 (0x<hex digits>)
GeneratorsImpl.tests.cpp:<line number>: passed: filter( []( int ) { return false; }, value( 3 ) ), Catch::GeneratorException
Matchers.tests.cpp:<line number>: passed: 10., WithinRel( 11.1, 0.1 ) for: 10.0 and 11.1 are within 10% of each other
Matchers.tests.cpp:<line number>: passed: 10., !WithinRel( 11.2, 0.1 ) for: 10.0 not and 11.2 are within 10% of each other
Matchers.tests.cpp:<line number>: passed: 1., !WithinRel( 0., 0.99 ) for: 1.0 not and 0 are within 99% of each other
@@ -628,6 +629,7 @@ Matchers.tests.cpp:<line number>: passed: WithinULP( 1., 0 )
Matchers.tests.cpp:<line number>: passed: WithinRel( 1., 0. )
Matchers.tests.cpp:<line number>: passed: WithinRel( 1., -0.2 ), std::domain_error
Matchers.tests.cpp:<line number>: passed: WithinRel( 1., 1. ), std::domain_error
Matchers.tests.cpp:<line number>: passed: 1., !IsNaN() for: 1.0 not is NaN
Matchers.tests.cpp:<line number>: passed: 10.f, WithinRel( 11.1f, 0.1f ) for: 10.0f and 11.1 are within 10% of each other
Matchers.tests.cpp:<line number>: passed: 10.f, !WithinRel( 11.2f, 0.1f ) for: 10.0f not and 11.2 are within 10% of each other
Matchers.tests.cpp:<line number>: passed: 1.f, !WithinRel( 0.f, 0.99f ) for: 1.0f not and 0 are within 99% of each other
@@ -660,6 +662,7 @@ Matchers.tests.cpp:<line number>: passed: WithinULP( 1.f, static_cast<uint64_t>(
Matchers.tests.cpp:<line number>: passed: WithinRel( 1.f, 0.f )
Matchers.tests.cpp:<line number>: passed: WithinRel( 1.f, -0.2f ), std::domain_error
Matchers.tests.cpp:<line number>: passed: WithinRel( 1.f, 1.f ), std::domain_error
Matchers.tests.cpp:<line number>: passed: 1., !IsNaN() for: 1.0 not is NaN
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
@@ -1992,6 +1995,18 @@ MatchersRanges.tests.cpp:<line number>: passed: array_a, !RangeEquals( array_c )
MatchersRanges.tests.cpp:<line number>: passed: vector_a, !RangeEquals( vector_b ) for: { 1, 2, 3 } not elements are { 1, 2, 3, 4 }
MatchersRanges.tests.cpp:<line number>: passed: vector_a, RangeEquals( vector_a_plus_1, close_enough ) for: { 1, 2, 3 } elements are { 2, 3, 4 }
MatchersRanges.tests.cpp:<line number>: passed: vector_a, !RangeEquals( vector_b, close_enough ) for: { 1, 2, 3 } not elements are { 3, 3, 4 }
MatchersRanges.tests.cpp:<line number>: passed: needs_adl1, RangeEquals( needs_adl2 ) for: { 1, 2, 3, 4, 5 } elements are { 1, 2, 3, 4, 5 }
MatchersRanges.tests.cpp:<line number>: passed: needs_adl1, RangeEquals( needs_adl3, []( int l, int r ) { return l + 1 == r; } ) for: { 1, 2, 3, 4, 5 } elements are { 2, 3, 4, 5, 6 }
MatchersRanges.tests.cpp:<line number>: passed: mocked1, !RangeEquals( arr ) for: { 1, 2, 3, 4 } not elements are { 1, 2, 4, 4 }
MatchersRanges.tests.cpp:<line number>: passed: mocked1.m_derefed[0] for: true
MatchersRanges.tests.cpp:<line number>: passed: mocked1.m_derefed[1] for: true
MatchersRanges.tests.cpp:<line number>: passed: mocked1.m_derefed[2] for: true
MatchersRanges.tests.cpp:<line number>: passed: !(mocked1.m_derefed[3]) for: !false
MatchersRanges.tests.cpp:<line number>: passed: mocked1, RangeEquals( arr ) for: { 1, 2, 3, 4 } elements are { 1, 2, 3, 4 }
MatchersRanges.tests.cpp:<line number>: passed: mocked1.m_derefed[0] for: true
MatchersRanges.tests.cpp:<line number>: passed: mocked1.m_derefed[1] for: true
MatchersRanges.tests.cpp:<line number>: passed: mocked1.m_derefed[2] for: true
MatchersRanges.tests.cpp:<line number>: passed: mocked1.m_derefed[3] for: true
MatchersRanges.tests.cpp:<line number>: passed: empty_vector, UnorderedRangeEquals( empty_vector ) for: { } unordered elements are { }
MatchersRanges.tests.cpp:<line number>: passed: empty_vector, !UnorderedRangeEquals( non_empty_vector ) for: { } not unordered elements are { 1 }
MatchersRanges.tests.cpp:<line number>: passed: non_empty_vector, !UnorderedRangeEquals( empty_vector ) for: { 1 } not unordered elements are { }
@@ -2001,6 +2016,7 @@ MatchersRanges.tests.cpp:<line number>: passed: array_a, !UnorderedRangeEquals(
MatchersRanges.tests.cpp:<line number>: passed: vector_a, !UnorderedRangeEquals( vector_b ) for: { 1, 2, 3 } not unordered elements are { 1, 2, 3, 4 }
MatchersRanges.tests.cpp:<line number>: passed: vector_a, UnorderedRangeEquals( vector_a_plus_1, close_enough ) for: { 1, 10, 20 } unordered elements are { 11, 21, 2 }
MatchersRanges.tests.cpp:<line number>: passed: vector_a, !UnorderedRangeEquals( vector_b, close_enough ) for: { 1, 10, 21 } not unordered elements are { 11, 21, 3 }
MatchersRanges.tests.cpp:<line number>: passed: needs_adl1, UnorderedRangeEquals( needs_adl2 ) for: { 1, 2, 3, 4, 5 } unordered elements are { 1, 2, 3, 4, 5 }
MatchersRanges.tests.cpp:<line number>: passed: empty_vec, SizeIs(0) for: { } has size == 0
MatchersRanges.tests.cpp:<line number>: passed: empty_vec, !SizeIs(2) for: { } not has size == 2
MatchersRanges.tests.cpp:<line number>: passed: empty_vec, SizeIs(Lt(2)) for: { } size matches is less than 2
@@ -2522,7 +2538,7 @@ InternalBenchmark.tests.cpp:<line number>: passed: med == 18. for: 18.0 == 18.0
InternalBenchmark.tests.cpp:<line number>: passed: q3 == 23. for: 23.0 == 23.0
Misc.tests.cpp:<line number>: passed:
Misc.tests.cpp:<line number>: passed:
test cases: 408 | 308 passed | 84 failed | 5 skipped | 11 failed as expected
assertions: 2210 | 2033 passed | 145 failed | 32 failed as expected
test cases: 409 | 309 passed | 84 failed | 5 skipped | 11 failed as expected
assertions: 2226 | 2049 passed | 145 failed | 32 failed as expected

View File

@@ -597,6 +597,7 @@ Misc.tests.cpp:<line number>: passed: Factorial(1) == 1 for: 1 == 1
Misc.tests.cpp:<line number>: passed: Factorial(2) == 2 for: 2 == 2
Misc.tests.cpp:<line number>: passed: Factorial(3) == 6 for: 6 == 6
Misc.tests.cpp:<line number>: passed: Factorial(10) == 3628800 for: 3628800 (0x<hex digits>) == 3628800 (0x<hex digits>)
GeneratorsImpl.tests.cpp:<line number>: passed: filter( []( int ) { return false; }, value( 3 ) ), Catch::GeneratorException
Matchers.tests.cpp:<line number>: passed: 10., WithinRel( 11.1, 0.1 ) for: 10.0 and 11.1 are within 10% of each other
Matchers.tests.cpp:<line number>: passed: 10., !WithinRel( 11.2, 0.1 ) for: 10.0 not and 11.2 are within 10% of each other
Matchers.tests.cpp:<line number>: passed: 1., !WithinRel( 0., 0.99 ) for: 1.0 not and 0 are within 99% of each other
@@ -626,6 +627,7 @@ Matchers.tests.cpp:<line number>: passed: WithinULP( 1., 0 )
Matchers.tests.cpp:<line number>: passed: WithinRel( 1., 0. )
Matchers.tests.cpp:<line number>: passed: WithinRel( 1., -0.2 ), std::domain_error
Matchers.tests.cpp:<line number>: passed: WithinRel( 1., 1. ), std::domain_error
Matchers.tests.cpp:<line number>: passed: 1., !IsNaN() for: 1.0 not is NaN
Matchers.tests.cpp:<line number>: passed: 10.f, WithinRel( 11.1f, 0.1f ) for: 10.0f and 11.1 are within 10% of each other
Matchers.tests.cpp:<line number>: passed: 10.f, !WithinRel( 11.2f, 0.1f ) for: 10.0f not and 11.2 are within 10% of each other
Matchers.tests.cpp:<line number>: passed: 1.f, !WithinRel( 0.f, 0.99f ) for: 1.0f not and 0 are within 99% of each other
@@ -658,6 +660,7 @@ Matchers.tests.cpp:<line number>: passed: WithinULP( 1.f, static_cast<uint64_t>(
Matchers.tests.cpp:<line number>: passed: WithinRel( 1.f, 0.f )
Matchers.tests.cpp:<line number>: passed: WithinRel( 1.f, -0.2f ), std::domain_error
Matchers.tests.cpp:<line number>: passed: WithinRel( 1.f, 1.f ), std::domain_error
Matchers.tests.cpp:<line number>: passed: 1., !IsNaN() for: 1.0 not is NaN
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
@@ -1985,6 +1988,18 @@ MatchersRanges.tests.cpp:<line number>: passed: array_a, !RangeEquals( array_c )
MatchersRanges.tests.cpp:<line number>: passed: vector_a, !RangeEquals( vector_b ) for: { 1, 2, 3 } not elements are { 1, 2, 3, 4 }
MatchersRanges.tests.cpp:<line number>: passed: vector_a, RangeEquals( vector_a_plus_1, close_enough ) for: { 1, 2, 3 } elements are { 2, 3, 4 }
MatchersRanges.tests.cpp:<line number>: passed: vector_a, !RangeEquals( vector_b, close_enough ) for: { 1, 2, 3 } not elements are { 3, 3, 4 }
MatchersRanges.tests.cpp:<line number>: passed: needs_adl1, RangeEquals( needs_adl2 ) for: { 1, 2, 3, 4, 5 } elements are { 1, 2, 3, 4, 5 }
MatchersRanges.tests.cpp:<line number>: passed: needs_adl1, RangeEquals( needs_adl3, []( int l, int r ) { return l + 1 == r; } ) for: { 1, 2, 3, 4, 5 } elements are { 2, 3, 4, 5, 6 }
MatchersRanges.tests.cpp:<line number>: passed: mocked1, !RangeEquals( arr ) for: { 1, 2, 3, 4 } not elements are { 1, 2, 4, 4 }
MatchersRanges.tests.cpp:<line number>: passed: mocked1.m_derefed[0] for: true
MatchersRanges.tests.cpp:<line number>: passed: mocked1.m_derefed[1] for: true
MatchersRanges.tests.cpp:<line number>: passed: mocked1.m_derefed[2] for: true
MatchersRanges.tests.cpp:<line number>: passed: !(mocked1.m_derefed[3]) for: !false
MatchersRanges.tests.cpp:<line number>: passed: mocked1, RangeEquals( arr ) for: { 1, 2, 3, 4 } elements are { 1, 2, 3, 4 }
MatchersRanges.tests.cpp:<line number>: passed: mocked1.m_derefed[0] for: true
MatchersRanges.tests.cpp:<line number>: passed: mocked1.m_derefed[1] for: true
MatchersRanges.tests.cpp:<line number>: passed: mocked1.m_derefed[2] for: true
MatchersRanges.tests.cpp:<line number>: passed: mocked1.m_derefed[3] for: true
MatchersRanges.tests.cpp:<line number>: passed: empty_vector, UnorderedRangeEquals( empty_vector ) for: { } unordered elements are { }
MatchersRanges.tests.cpp:<line number>: passed: empty_vector, !UnorderedRangeEquals( non_empty_vector ) for: { } not unordered elements are { 1 }
MatchersRanges.tests.cpp:<line number>: passed: non_empty_vector, !UnorderedRangeEquals( empty_vector ) for: { 1 } not unordered elements are { }
@@ -1994,6 +2009,7 @@ MatchersRanges.tests.cpp:<line number>: passed: array_a, !UnorderedRangeEquals(
MatchersRanges.tests.cpp:<line number>: passed: vector_a, !UnorderedRangeEquals( vector_b ) for: { 1, 2, 3 } not unordered elements are { 1, 2, 3, 4 }
MatchersRanges.tests.cpp:<line number>: passed: vector_a, UnorderedRangeEquals( vector_a_plus_1, close_enough ) for: { 1, 10, 20 } unordered elements are { 11, 21, 2 }
MatchersRanges.tests.cpp:<line number>: passed: vector_a, !UnorderedRangeEquals( vector_b, close_enough ) for: { 1, 10, 21 } not unordered elements are { 11, 21, 3 }
MatchersRanges.tests.cpp:<line number>: passed: needs_adl1, UnorderedRangeEquals( needs_adl2 ) for: { 1, 2, 3, 4, 5 } unordered elements are { 1, 2, 3, 4, 5 }
MatchersRanges.tests.cpp:<line number>: passed: empty_vec, SizeIs(0) for: { } has size == 0
MatchersRanges.tests.cpp:<line number>: passed: empty_vec, !SizeIs(2) for: { } not has size == 2
MatchersRanges.tests.cpp:<line number>: passed: empty_vec, SizeIs(Lt(2)) for: { } size matches is less than 2
@@ -2511,7 +2527,7 @@ InternalBenchmark.tests.cpp:<line number>: passed: med == 18. for: 18.0 == 18.0
InternalBenchmark.tests.cpp:<line number>: passed: q3 == 23. for: 23.0 == 23.0
Misc.tests.cpp:<line number>: passed:
Misc.tests.cpp:<line number>: passed:
test cases: 408 | 308 passed | 84 failed | 5 skipped | 11 failed as expected
assertions: 2210 | 2033 passed | 145 failed | 32 failed as expected
test cases: 409 | 309 passed | 84 failed | 5 skipped | 11 failed as expected
assertions: 2226 | 2049 passed | 145 failed | 32 failed as expected

View File

@@ -1533,6 +1533,6 @@ due to unexpected exception with message:
Why would you throw a std::string?
===============================================================================
test cases: 408 | 322 passed | 69 failed | 6 skipped | 11 failed as expected
assertions: 2193 | 2033 passed | 128 failed | 32 failed as expected
test cases: 409 | 323 passed | 69 failed | 6 skipped | 11 failed as expected
assertions: 2209 | 2049 passed | 128 failed | 32 failed as expected

View File

@@ -4477,6 +4477,15 @@ Misc.tests.cpp:<line number>: PASSED:
with expansion:
3628800 (0x<hex digits>) == 3628800 (0x<hex digits>)
-------------------------------------------------------------------------------
Filter generator throws exception for empty generator
-------------------------------------------------------------------------------
GeneratorsImpl.tests.cpp:<line number>
...............................................................................
GeneratorsImpl.tests.cpp:<line number>: PASSED:
REQUIRE_THROWS_AS( filter( []( int ) { return false; }, value( 3 ) ), Catch::GeneratorException )
-------------------------------------------------------------------------------
Floating point matchers: double
Relative
@@ -4662,6 +4671,18 @@ Matchers.tests.cpp:<line number>: PASSED:
Matchers.tests.cpp:<line number>: PASSED:
REQUIRE_THROWS_AS( WithinRel( 1., 1. ), std::domain_error )
-------------------------------------------------------------------------------
Floating point matchers: double
IsNaN
-------------------------------------------------------------------------------
Matchers.tests.cpp:<line number>
...............................................................................
Matchers.tests.cpp:<line number>: PASSED:
REQUIRE_THAT( 1., !IsNaN() )
with expansion:
1.0 not is NaN
-------------------------------------------------------------------------------
Floating point matchers: float
Relative
@@ -4855,6 +4876,18 @@ Matchers.tests.cpp:<line number>: PASSED:
Matchers.tests.cpp:<line number>: PASSED:
REQUIRE_THROWS_AS( WithinRel( 1.f, 1.f ), std::domain_error )
-------------------------------------------------------------------------------
Floating point matchers: float
IsNaN
-------------------------------------------------------------------------------
Matchers.tests.cpp:<line number>
...............................................................................
Matchers.tests.cpp:<line number>: PASSED:
REQUIRE_THAT( 1., !IsNaN() )
with expansion:
1.0 not is NaN
-------------------------------------------------------------------------------
Generators -- adapters
Filtering by predicate
@@ -14229,6 +14262,89 @@ MatchersRanges.tests.cpp:<line number>: PASSED:
with expansion:
{ 1, 2, 3 } not elements are { 3, 3, 4 }
-------------------------------------------------------------------------------
Usage of RangeEquals range matcher
Ranges that need ADL begin/end
-------------------------------------------------------------------------------
MatchersRanges.tests.cpp:<line number>
...............................................................................
MatchersRanges.tests.cpp:<line number>: PASSED:
REQUIRE_THAT( needs_adl1, RangeEquals( needs_adl2 ) )
with expansion:
{ 1, 2, 3, 4, 5 } elements are { 1, 2, 3, 4, 5 }
MatchersRanges.tests.cpp:<line number>: PASSED:
REQUIRE_THAT( needs_adl1, RangeEquals( needs_adl3, []( int l, int r ) { return l + 1 == r; } ) )
with expansion:
{ 1, 2, 3, 4, 5 } elements are { 2, 3, 4, 5, 6 }
-------------------------------------------------------------------------------
Usage of RangeEquals range matcher
Check short-circuiting behaviour
Check short-circuits on failure
-------------------------------------------------------------------------------
MatchersRanges.tests.cpp:<line number>
...............................................................................
MatchersRanges.tests.cpp:<line number>: PASSED:
REQUIRE_THAT( mocked1, !RangeEquals( arr ) )
with expansion:
{ 1, 2, 3, 4 } not elements are { 1, 2, 4, 4 }
MatchersRanges.tests.cpp:<line number>: PASSED:
REQUIRE( mocked1.m_derefed[0] )
with expansion:
true
MatchersRanges.tests.cpp:<line number>: PASSED:
REQUIRE( mocked1.m_derefed[1] )
with expansion:
true
MatchersRanges.tests.cpp:<line number>: PASSED:
REQUIRE( mocked1.m_derefed[2] )
with expansion:
true
MatchersRanges.tests.cpp:<line number>: PASSED:
REQUIRE_FALSE( mocked1.m_derefed[3] )
with expansion:
!false
-------------------------------------------------------------------------------
Usage of RangeEquals range matcher
Check short-circuiting behaviour
All elements are checked on success
-------------------------------------------------------------------------------
MatchersRanges.tests.cpp:<line number>
...............................................................................
MatchersRanges.tests.cpp:<line number>: PASSED:
REQUIRE_THAT( mocked1, RangeEquals( arr ) )
with expansion:
{ 1, 2, 3, 4 } elements are { 1, 2, 3, 4 }
MatchersRanges.tests.cpp:<line number>: PASSED:
REQUIRE( mocked1.m_derefed[0] )
with expansion:
true
MatchersRanges.tests.cpp:<line number>: PASSED:
REQUIRE( mocked1.m_derefed[1] )
with expansion:
true
MatchersRanges.tests.cpp:<line number>: PASSED:
REQUIRE( mocked1.m_derefed[2] )
with expansion:
true
MatchersRanges.tests.cpp:<line number>: PASSED:
REQUIRE( mocked1.m_derefed[3] )
with expansion:
true
-------------------------------------------------------------------------------
Usage of UnorderedRangeEquals range matcher
Basic usage
@@ -14338,6 +14454,18 @@ MatchersRanges.tests.cpp:<line number>: PASSED:
with expansion:
{ 1, 10, 21 } not unordered elements are { 11, 21, 3 }
-------------------------------------------------------------------------------
Usage of UnorderedRangeEquals range matcher
Ranges that need ADL begin/end
-------------------------------------------------------------------------------
MatchersRanges.tests.cpp:<line number>
...............................................................................
MatchersRanges.tests.cpp:<line number>: PASSED:
REQUIRE_THAT( needs_adl1, UnorderedRangeEquals( needs_adl2 ) )
with expansion:
{ 1, 2, 3, 4, 5 } unordered elements are { 1, 2, 3, 4, 5 }
-------------------------------------------------------------------------------
Usage of the SizeIs range matcher
Some with stdlib containers
@@ -18103,6 +18231,6 @@ Misc.tests.cpp:<line number>
Misc.tests.cpp:<line number>: PASSED:
===============================================================================
test cases: 408 | 308 passed | 84 failed | 5 skipped | 11 failed as expected
assertions: 2210 | 2033 passed | 145 failed | 32 failed as expected
test cases: 409 | 309 passed | 84 failed | 5 skipped | 11 failed as expected
assertions: 2226 | 2049 passed | 145 failed | 32 failed as expected

View File

@@ -4475,6 +4475,15 @@ Misc.tests.cpp:<line number>: PASSED:
with expansion:
3628800 (0x<hex digits>) == 3628800 (0x<hex digits>)
-------------------------------------------------------------------------------
Filter generator throws exception for empty generator
-------------------------------------------------------------------------------
GeneratorsImpl.tests.cpp:<line number>
...............................................................................
GeneratorsImpl.tests.cpp:<line number>: PASSED:
REQUIRE_THROWS_AS( filter( []( int ) { return false; }, value( 3 ) ), Catch::GeneratorException )
-------------------------------------------------------------------------------
Floating point matchers: double
Relative
@@ -4660,6 +4669,18 @@ Matchers.tests.cpp:<line number>: PASSED:
Matchers.tests.cpp:<line number>: PASSED:
REQUIRE_THROWS_AS( WithinRel( 1., 1. ), std::domain_error )
-------------------------------------------------------------------------------
Floating point matchers: double
IsNaN
-------------------------------------------------------------------------------
Matchers.tests.cpp:<line number>
...............................................................................
Matchers.tests.cpp:<line number>: PASSED:
REQUIRE_THAT( 1., !IsNaN() )
with expansion:
1.0 not is NaN
-------------------------------------------------------------------------------
Floating point matchers: float
Relative
@@ -4853,6 +4874,18 @@ Matchers.tests.cpp:<line number>: PASSED:
Matchers.tests.cpp:<line number>: PASSED:
REQUIRE_THROWS_AS( WithinRel( 1.f, 1.f ), std::domain_error )
-------------------------------------------------------------------------------
Floating point matchers: float
IsNaN
-------------------------------------------------------------------------------
Matchers.tests.cpp:<line number>
...............................................................................
Matchers.tests.cpp:<line number>: PASSED:
REQUIRE_THAT( 1., !IsNaN() )
with expansion:
1.0 not is NaN
-------------------------------------------------------------------------------
Generators -- adapters
Filtering by predicate
@@ -14222,6 +14255,89 @@ MatchersRanges.tests.cpp:<line number>: PASSED:
with expansion:
{ 1, 2, 3 } not elements are { 3, 3, 4 }
-------------------------------------------------------------------------------
Usage of RangeEquals range matcher
Ranges that need ADL begin/end
-------------------------------------------------------------------------------
MatchersRanges.tests.cpp:<line number>
...............................................................................
MatchersRanges.tests.cpp:<line number>: PASSED:
REQUIRE_THAT( needs_adl1, RangeEquals( needs_adl2 ) )
with expansion:
{ 1, 2, 3, 4, 5 } elements are { 1, 2, 3, 4, 5 }
MatchersRanges.tests.cpp:<line number>: PASSED:
REQUIRE_THAT( needs_adl1, RangeEquals( needs_adl3, []( int l, int r ) { return l + 1 == r; } ) )
with expansion:
{ 1, 2, 3, 4, 5 } elements are { 2, 3, 4, 5, 6 }
-------------------------------------------------------------------------------
Usage of RangeEquals range matcher
Check short-circuiting behaviour
Check short-circuits on failure
-------------------------------------------------------------------------------
MatchersRanges.tests.cpp:<line number>
...............................................................................
MatchersRanges.tests.cpp:<line number>: PASSED:
REQUIRE_THAT( mocked1, !RangeEquals( arr ) )
with expansion:
{ 1, 2, 3, 4 } not elements are { 1, 2, 4, 4 }
MatchersRanges.tests.cpp:<line number>: PASSED:
REQUIRE( mocked1.m_derefed[0] )
with expansion:
true
MatchersRanges.tests.cpp:<line number>: PASSED:
REQUIRE( mocked1.m_derefed[1] )
with expansion:
true
MatchersRanges.tests.cpp:<line number>: PASSED:
REQUIRE( mocked1.m_derefed[2] )
with expansion:
true
MatchersRanges.tests.cpp:<line number>: PASSED:
REQUIRE_FALSE( mocked1.m_derefed[3] )
with expansion:
!false
-------------------------------------------------------------------------------
Usage of RangeEquals range matcher
Check short-circuiting behaviour
All elements are checked on success
-------------------------------------------------------------------------------
MatchersRanges.tests.cpp:<line number>
...............................................................................
MatchersRanges.tests.cpp:<line number>: PASSED:
REQUIRE_THAT( mocked1, RangeEquals( arr ) )
with expansion:
{ 1, 2, 3, 4 } elements are { 1, 2, 3, 4 }
MatchersRanges.tests.cpp:<line number>: PASSED:
REQUIRE( mocked1.m_derefed[0] )
with expansion:
true
MatchersRanges.tests.cpp:<line number>: PASSED:
REQUIRE( mocked1.m_derefed[1] )
with expansion:
true
MatchersRanges.tests.cpp:<line number>: PASSED:
REQUIRE( mocked1.m_derefed[2] )
with expansion:
true
MatchersRanges.tests.cpp:<line number>: PASSED:
REQUIRE( mocked1.m_derefed[3] )
with expansion:
true
-------------------------------------------------------------------------------
Usage of UnorderedRangeEquals range matcher
Basic usage
@@ -14331,6 +14447,18 @@ MatchersRanges.tests.cpp:<line number>: PASSED:
with expansion:
{ 1, 10, 21 } not unordered elements are { 11, 21, 3 }
-------------------------------------------------------------------------------
Usage of UnorderedRangeEquals range matcher
Ranges that need ADL begin/end
-------------------------------------------------------------------------------
MatchersRanges.tests.cpp:<line number>
...............................................................................
MatchersRanges.tests.cpp:<line number>: PASSED:
REQUIRE_THAT( needs_adl1, UnorderedRangeEquals( needs_adl2 ) )
with expansion:
{ 1, 2, 3, 4, 5 } unordered elements are { 1, 2, 3, 4, 5 }
-------------------------------------------------------------------------------
Usage of the SizeIs range matcher
Some with stdlib containers
@@ -18092,6 +18220,6 @@ Misc.tests.cpp:<line number>
Misc.tests.cpp:<line number>: PASSED:
===============================================================================
test cases: 408 | 308 passed | 84 failed | 5 skipped | 11 failed as expected
assertions: 2210 | 2033 passed | 145 failed | 32 failed as expected
test cases: 409 | 309 passed | 84 failed | 5 skipped | 11 failed as expected
assertions: 2226 | 2049 passed | 145 failed | 32 failed as expected

View File

@@ -1,7 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?>
<testsuitesloose text artifact
>
<testsuite name="<exe-name>" errors="17" failures="128" skipped="11" tests="2221" hostname="tbd" time="{duration}" timestamp="{iso8601-timestamp}">
<testsuite name="<exe-name>" errors="17" failures="128" skipped="11" tests="2237" hostname="tbd" time="{duration}" timestamp="{iso8601-timestamp}">
<properties>
<property name="random-seed" value="1"/>
<property name="filters" value="&quot;*&quot; ~[!nonportable] ~[!benchmark] ~[approvals]"/>
@@ -687,18 +687,21 @@ at Message.tests.cpp:<line number>
</failure>
</testcase>
<testcase classname="<exe-name>.global" name="Factorials are computed" time="{duration}" status="run"/>
<testcase classname="<exe-name>.global" name="Filter generator throws exception for empty generator" time="{duration}" status="run"/>
<testcase classname="<exe-name>.global" name="Floating point matchers: double/Relative" time="{duration}" status="run"/>
<testcase classname="<exe-name>.global" name="Floating point matchers: double/Relative/Some subnormal values" time="{duration}" status="run"/>
<testcase classname="<exe-name>.global" name="Floating point matchers: double/Margin" time="{duration}" status="run"/>
<testcase classname="<exe-name>.global" name="Floating point matchers: double/ULPs" time="{duration}" status="run"/>
<testcase classname="<exe-name>.global" name="Floating point matchers: double/Composed" time="{duration}" status="run"/>
<testcase classname="<exe-name>.global" name="Floating point matchers: double/Constructor validation" time="{duration}" status="run"/>
<testcase classname="<exe-name>.global" name="Floating point matchers: double/IsNaN" time="{duration}" status="run"/>
<testcase classname="<exe-name>.global" name="Floating point matchers: float/Relative" time="{duration}" status="run"/>
<testcase classname="<exe-name>.global" name="Floating point matchers: float/Relative/Some subnormal values" time="{duration}" status="run"/>
<testcase classname="<exe-name>.global" name="Floating point matchers: float/Margin" time="{duration}" status="run"/>
<testcase classname="<exe-name>.global" name="Floating point matchers: float/ULPs" time="{duration}" status="run"/>
<testcase classname="<exe-name>.global" name="Floating point matchers: float/Composed" time="{duration}" status="run"/>
<testcase classname="<exe-name>.global" name="Floating point matchers: float/Constructor validation" time="{duration}" status="run"/>
<testcase classname="<exe-name>.global" name="Floating point matchers: float/IsNaN" time="{duration}" status="run"/>
<testcase classname="<exe-name>.global" name="Generators -- adapters/Filtering by predicate/Basic usage" time="{duration}" status="run"/>
<testcase classname="<exe-name>.global" name="Generators -- adapters/Filtering by predicate/Throws if there are no matching values" time="{duration}" status="run"/>
<testcase classname="<exe-name>.global" name="Generators -- adapters/Shortening a range" time="{duration}" status="run"/>
@@ -1439,6 +1442,9 @@ at Exception.tests.cpp:<line number>
<testcase classname="<exe-name>.global" name="Usage of RangeEquals range matcher/Basic usage/Two non-equal-sized, non-empty containers (with same first elements)" time="{duration}" status="run"/>
<testcase classname="<exe-name>.global" name="Usage of RangeEquals range matcher/Custom predicate/Two equal non-empty containers (close enough)" time="{duration}" status="run"/>
<testcase classname="<exe-name>.global" name="Usage of RangeEquals range matcher/Custom predicate/Two non-equal non-empty containers (close enough)" time="{duration}" status="run"/>
<testcase classname="<exe-name>.global" name="Usage of RangeEquals range matcher/Ranges that need ADL begin/end" time="{duration}" status="run"/>
<testcase classname="<exe-name>.global" name="Usage of RangeEquals range matcher/Check short-circuiting behaviour/Check short-circuits on failure" time="{duration}" status="run"/>
<testcase classname="<exe-name>.global" name="Usage of RangeEquals range matcher/Check short-circuiting behaviour/All elements are checked on success" time="{duration}" status="run"/>
<testcase classname="<exe-name>.global" name="Usage of UnorderedRangeEquals range matcher/Basic usage/Empty container matches empty container" time="{duration}" status="run"/>
<testcase classname="<exe-name>.global" name="Usage of UnorderedRangeEquals range matcher/Basic usage/Empty container does not match non-empty container" time="{duration}" status="run"/>
<testcase classname="<exe-name>.global" name="Usage of UnorderedRangeEquals range matcher/Basic usage/Two equal 1-length non-empty containers" time="{duration}" status="run"/>
@@ -1447,6 +1453,7 @@ at Exception.tests.cpp:<line number>
<testcase classname="<exe-name>.global" name="Usage of UnorderedRangeEquals range matcher/Basic usage/Two non-equal-sized, non-empty containers" time="{duration}" status="run"/>
<testcase classname="<exe-name>.global" name="Usage of UnorderedRangeEquals range matcher/Custom predicate/Two equal non-empty containers (close enough)" time="{duration}" status="run"/>
<testcase classname="<exe-name>.global" name="Usage of UnorderedRangeEquals range matcher/Custom predicate/Two non-equal non-empty containers (close enough)" time="{duration}" status="run"/>
<testcase classname="<exe-name>.global" name="Usage of UnorderedRangeEquals range matcher/Ranges that need ADL begin/end" time="{duration}" status="run"/>
<testcase classname="<exe-name>.global" name="Usage of the SizeIs range matcher/Some with stdlib containers" time="{duration}" status="run"/>
<testcase classname="<exe-name>.global" name="Usage of the SizeIs range matcher/Type requires ADL found size free function" time="{duration}" status="run"/>
<testcase classname="<exe-name>.global" name="Usage of the SizeIs range matcher/Type has size member" time="{duration}" status="run"/>

View File

@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<testsuites>
<testsuite name="<exe-name>" errors="17" failures="128" skipped="11" tests="2221" hostname="tbd" time="{duration}" timestamp="{iso8601-timestamp}">
<testsuite name="<exe-name>" errors="17" failures="128" skipped="11" tests="2237" hostname="tbd" time="{duration}" timestamp="{iso8601-timestamp}">
<properties>
<property name="random-seed" value="1"/>
<property name="filters" value="&quot;*&quot; ~[!nonportable] ~[!benchmark] ~[approvals]"/>
@@ -686,18 +686,21 @@ at Message.tests.cpp:<line number>
</failure>
</testcase>
<testcase classname="<exe-name>.global" name="Factorials are computed" time="{duration}" status="run"/>
<testcase classname="<exe-name>.global" name="Filter generator throws exception for empty generator" time="{duration}" status="run"/>
<testcase classname="<exe-name>.global" name="Floating point matchers: double/Relative" time="{duration}" status="run"/>
<testcase classname="<exe-name>.global" name="Floating point matchers: double/Relative/Some subnormal values" time="{duration}" status="run"/>
<testcase classname="<exe-name>.global" name="Floating point matchers: double/Margin" time="{duration}" status="run"/>
<testcase classname="<exe-name>.global" name="Floating point matchers: double/ULPs" time="{duration}" status="run"/>
<testcase classname="<exe-name>.global" name="Floating point matchers: double/Composed" time="{duration}" status="run"/>
<testcase classname="<exe-name>.global" name="Floating point matchers: double/Constructor validation" time="{duration}" status="run"/>
<testcase classname="<exe-name>.global" name="Floating point matchers: double/IsNaN" time="{duration}" status="run"/>
<testcase classname="<exe-name>.global" name="Floating point matchers: float/Relative" time="{duration}" status="run"/>
<testcase classname="<exe-name>.global" name="Floating point matchers: float/Relative/Some subnormal values" time="{duration}" status="run"/>
<testcase classname="<exe-name>.global" name="Floating point matchers: float/Margin" time="{duration}" status="run"/>
<testcase classname="<exe-name>.global" name="Floating point matchers: float/ULPs" time="{duration}" status="run"/>
<testcase classname="<exe-name>.global" name="Floating point matchers: float/Composed" time="{duration}" status="run"/>
<testcase classname="<exe-name>.global" name="Floating point matchers: float/Constructor validation" time="{duration}" status="run"/>
<testcase classname="<exe-name>.global" name="Floating point matchers: float/IsNaN" time="{duration}" status="run"/>
<testcase classname="<exe-name>.global" name="Generators -- adapters/Filtering by predicate/Basic usage" time="{duration}" status="run"/>
<testcase classname="<exe-name>.global" name="Generators -- adapters/Filtering by predicate/Throws if there are no matching values" time="{duration}" status="run"/>
<testcase classname="<exe-name>.global" name="Generators -- adapters/Shortening a range" time="{duration}" status="run"/>
@@ -1438,6 +1441,9 @@ at Exception.tests.cpp:<line number>
<testcase classname="<exe-name>.global" name="Usage of RangeEquals range matcher/Basic usage/Two non-equal-sized, non-empty containers (with same first elements)" time="{duration}" status="run"/>
<testcase classname="<exe-name>.global" name="Usage of RangeEquals range matcher/Custom predicate/Two equal non-empty containers (close enough)" time="{duration}" status="run"/>
<testcase classname="<exe-name>.global" name="Usage of RangeEquals range matcher/Custom predicate/Two non-equal non-empty containers (close enough)" time="{duration}" status="run"/>
<testcase classname="<exe-name>.global" name="Usage of RangeEquals range matcher/Ranges that need ADL begin/end" time="{duration}" status="run"/>
<testcase classname="<exe-name>.global" name="Usage of RangeEquals range matcher/Check short-circuiting behaviour/Check short-circuits on failure" time="{duration}" status="run"/>
<testcase classname="<exe-name>.global" name="Usage of RangeEquals range matcher/Check short-circuiting behaviour/All elements are checked on success" time="{duration}" status="run"/>
<testcase classname="<exe-name>.global" name="Usage of UnorderedRangeEquals range matcher/Basic usage/Empty container matches empty container" time="{duration}" status="run"/>
<testcase classname="<exe-name>.global" name="Usage of UnorderedRangeEquals range matcher/Basic usage/Empty container does not match non-empty container" time="{duration}" status="run"/>
<testcase classname="<exe-name>.global" name="Usage of UnorderedRangeEquals range matcher/Basic usage/Two equal 1-length non-empty containers" time="{duration}" status="run"/>
@@ -1446,6 +1452,7 @@ at Exception.tests.cpp:<line number>
<testcase classname="<exe-name>.global" name="Usage of UnorderedRangeEquals range matcher/Basic usage/Two non-equal-sized, non-empty containers" time="{duration}" status="run"/>
<testcase classname="<exe-name>.global" name="Usage of UnorderedRangeEquals range matcher/Custom predicate/Two equal non-empty containers (close enough)" time="{duration}" status="run"/>
<testcase classname="<exe-name>.global" name="Usage of UnorderedRangeEquals range matcher/Custom predicate/Two non-equal non-empty containers (close enough)" time="{duration}" status="run"/>
<testcase classname="<exe-name>.global" name="Usage of UnorderedRangeEquals range matcher/Ranges that need ADL begin/end" time="{duration}" status="run"/>
<testcase classname="<exe-name>.global" name="Usage of the SizeIs range matcher/Some with stdlib containers" time="{duration}" status="run"/>
<testcase classname="<exe-name>.global" name="Usage of the SizeIs range matcher/Type requires ADL found size free function" time="{duration}" status="run"/>
<testcase classname="<exe-name>.global" name="Usage of the SizeIs range matcher/Type has size member" time="{duration}" status="run"/>

View File

@@ -71,6 +71,7 @@
<testCase name="convertToBits" duration="{duration}"/>
</file>
<file path="tests/<exe-name>/IntrospectiveTests/GeneratorsImpl.tests.cpp">
<testCase name="Filter generator throws exception for empty generator" duration="{duration}"/>
<testCase name="Generators internals/Single value" duration="{duration}"/>
<testCase name="Generators internals/Preset values" duration="{duration}"/>
<testCase name="Generators internals/Generator combinator" duration="{duration}"/>
@@ -1171,12 +1172,14 @@ at Matchers.tests.cpp:<line number>
<testCase name="Floating point matchers: double/ULPs" duration="{duration}"/>
<testCase name="Floating point matchers: double/Composed" duration="{duration}"/>
<testCase name="Floating point matchers: double/Constructor validation" duration="{duration}"/>
<testCase name="Floating point matchers: double/IsNaN" duration="{duration}"/>
<testCase name="Floating point matchers: float/Relative" duration="{duration}"/>
<testCase name="Floating point matchers: float/Relative/Some subnormal values" duration="{duration}"/>
<testCase name="Floating point matchers: float/Margin" duration="{duration}"/>
<testCase name="Floating point matchers: float/ULPs" duration="{duration}"/>
<testCase name="Floating point matchers: float/Composed" duration="{duration}"/>
<testCase name="Floating point matchers: float/Constructor validation" duration="{duration}"/>
<testCase name="Floating point matchers: float/IsNaN" duration="{duration}"/>
<testCase name="Matchers can be (AllOf) composed with the &amp;&amp; operator" duration="{duration}"/>
<testCase name="Matchers can be (AnyOf) composed with the || operator" duration="{duration}"/>
<testCase name="Matchers can be composed with both &amp;&amp; and ||" duration="{duration}"/>
@@ -1427,6 +1430,9 @@ at Matchers.tests.cpp:<line number>
<testCase name="Usage of RangeEquals range matcher/Basic usage/Two non-equal-sized, non-empty containers (with same first elements)" duration="{duration}"/>
<testCase name="Usage of RangeEquals range matcher/Custom predicate/Two equal non-empty containers (close enough)" duration="{duration}"/>
<testCase name="Usage of RangeEquals range matcher/Custom predicate/Two non-equal non-empty containers (close enough)" duration="{duration}"/>
<testCase name="Usage of RangeEquals range matcher/Ranges that need ADL begin/end" duration="{duration}"/>
<testCase name="Usage of RangeEquals range matcher/Check short-circuiting behaviour/Check short-circuits on failure" duration="{duration}"/>
<testCase name="Usage of RangeEquals range matcher/Check short-circuiting behaviour/All elements are checked on success" duration="{duration}"/>
<testCase name="Usage of UnorderedRangeEquals range matcher/Basic usage/Empty container matches empty container" duration="{duration}"/>
<testCase name="Usage of UnorderedRangeEquals range matcher/Basic usage/Empty container does not match non-empty container" duration="{duration}"/>
<testCase name="Usage of UnorderedRangeEquals range matcher/Basic usage/Two equal 1-length non-empty containers" duration="{duration}"/>
@@ -1435,6 +1441,7 @@ at Matchers.tests.cpp:<line number>
<testCase name="Usage of UnorderedRangeEquals range matcher/Basic usage/Two non-equal-sized, non-empty containers" duration="{duration}"/>
<testCase name="Usage of UnorderedRangeEquals range matcher/Custom predicate/Two equal non-empty containers (close enough)" duration="{duration}"/>
<testCase name="Usage of UnorderedRangeEquals range matcher/Custom predicate/Two non-equal non-empty containers (close enough)" duration="{duration}"/>
<testCase name="Usage of UnorderedRangeEquals range matcher/Ranges that need ADL begin/end" duration="{duration}"/>
<testCase name="Usage of the SizeIs range matcher/Some with stdlib containers" duration="{duration}"/>
<testCase name="Usage of the SizeIs range matcher/Type requires ADL found size free function" duration="{duration}"/>
<testCase name="Usage of the SizeIs range matcher/Type has size member" duration="{duration}"/>

View File

@@ -70,6 +70,7 @@
<testCase name="convertToBits" duration="{duration}"/>
</file>
<file path="tests/<exe-name>/IntrospectiveTests/GeneratorsImpl.tests.cpp">
<testCase name="Filter generator throws exception for empty generator" duration="{duration}"/>
<testCase name="Generators internals/Single value" duration="{duration}"/>
<testCase name="Generators internals/Preset values" duration="{duration}"/>
<testCase name="Generators internals/Generator combinator" duration="{duration}"/>
@@ -1170,12 +1171,14 @@ at Matchers.tests.cpp:<line number>
<testCase name="Floating point matchers: double/ULPs" duration="{duration}"/>
<testCase name="Floating point matchers: double/Composed" duration="{duration}"/>
<testCase name="Floating point matchers: double/Constructor validation" duration="{duration}"/>
<testCase name="Floating point matchers: double/IsNaN" duration="{duration}"/>
<testCase name="Floating point matchers: float/Relative" duration="{duration}"/>
<testCase name="Floating point matchers: float/Relative/Some subnormal values" duration="{duration}"/>
<testCase name="Floating point matchers: float/Margin" duration="{duration}"/>
<testCase name="Floating point matchers: float/ULPs" duration="{duration}"/>
<testCase name="Floating point matchers: float/Composed" duration="{duration}"/>
<testCase name="Floating point matchers: float/Constructor validation" duration="{duration}"/>
<testCase name="Floating point matchers: float/IsNaN" duration="{duration}"/>
<testCase name="Matchers can be (AllOf) composed with the &amp;&amp; operator" duration="{duration}"/>
<testCase name="Matchers can be (AnyOf) composed with the || operator" duration="{duration}"/>
<testCase name="Matchers can be composed with both &amp;&amp; and ||" duration="{duration}"/>
@@ -1426,6 +1429,9 @@ at Matchers.tests.cpp:<line number>
<testCase name="Usage of RangeEquals range matcher/Basic usage/Two non-equal-sized, non-empty containers (with same first elements)" duration="{duration}"/>
<testCase name="Usage of RangeEquals range matcher/Custom predicate/Two equal non-empty containers (close enough)" duration="{duration}"/>
<testCase name="Usage of RangeEquals range matcher/Custom predicate/Two non-equal non-empty containers (close enough)" duration="{duration}"/>
<testCase name="Usage of RangeEquals range matcher/Ranges that need ADL begin/end" duration="{duration}"/>
<testCase name="Usage of RangeEquals range matcher/Check short-circuiting behaviour/Check short-circuits on failure" duration="{duration}"/>
<testCase name="Usage of RangeEquals range matcher/Check short-circuiting behaviour/All elements are checked on success" duration="{duration}"/>
<testCase name="Usage of UnorderedRangeEquals range matcher/Basic usage/Empty container matches empty container" duration="{duration}"/>
<testCase name="Usage of UnorderedRangeEquals range matcher/Basic usage/Empty container does not match non-empty container" duration="{duration}"/>
<testCase name="Usage of UnorderedRangeEquals range matcher/Basic usage/Two equal 1-length non-empty containers" duration="{duration}"/>
@@ -1434,6 +1440,7 @@ at Matchers.tests.cpp:<line number>
<testCase name="Usage of UnorderedRangeEquals range matcher/Basic usage/Two non-equal-sized, non-empty containers" duration="{duration}"/>
<testCase name="Usage of UnorderedRangeEquals range matcher/Custom predicate/Two equal non-empty containers (close enough)" duration="{duration}"/>
<testCase name="Usage of UnorderedRangeEquals range matcher/Custom predicate/Two non-equal non-empty containers (close enough)" duration="{duration}"/>
<testCase name="Usage of UnorderedRangeEquals range matcher/Ranges that need ADL begin/end" duration="{duration}"/>
<testCase name="Usage of the SizeIs range matcher/Some with stdlib containers" duration="{duration}"/>
<testCase name="Usage of the SizeIs range matcher/Type requires ADL found size free function" duration="{duration}"/>
<testCase name="Usage of the SizeIs range matcher/Type has size member" duration="{duration}"/>

View File

@@ -1130,6 +1130,8 @@ ok {test-number} - Factorial(2) == 2 for: 2 == 2
ok {test-number} - Factorial(3) == 6 for: 6 == 6
# Factorials are computed
ok {test-number} - Factorial(10) == 3628800 for: 3628800 (0x<hex digits>) == 3628800 (0x<hex digits>)
# Filter generator throws exception for empty generator
ok {test-number} - filter( []( int ) { return false; }, value( 3 ) ), Catch::GeneratorException
# Floating point matchers: double
ok {test-number} - 10., WithinRel( 11.1, 0.1 ) for: 10.0 and 11.1 are within 10% of each other
# Floating point matchers: double
@@ -1188,6 +1190,8 @@ ok {test-number} - WithinRel( 1., 0. )
ok {test-number} - WithinRel( 1., -0.2 ), std::domain_error
# Floating point matchers: double
ok {test-number} - WithinRel( 1., 1. ), std::domain_error
# Floating point matchers: double
ok {test-number} - 1., !IsNaN() for: 1.0 not is NaN
# Floating point matchers: float
ok {test-number} - 10.f, WithinRel( 11.1f, 0.1f ) for: 10.0f and 11.1 are within 10% of each other
# Floating point matchers: float
@@ -1252,6 +1256,8 @@ ok {test-number} - WithinRel( 1.f, 0.f )
ok {test-number} - WithinRel( 1.f, -0.2f ), std::domain_error
# Floating point matchers: float
ok {test-number} - WithinRel( 1.f, 1.f ), std::domain_error
# Floating point matchers: float
ok {test-number} - 1., !IsNaN() for: 1.0 not is NaN
# Generators -- adapters
ok {test-number} - i % 2 == 0 for: 0 == 0
# Generators -- adapters
@@ -3489,6 +3495,30 @@ ok {test-number} - vector_a, !RangeEquals( vector_b ) for: { 1, 2, 3 } not eleme
ok {test-number} - vector_a, RangeEquals( vector_a_plus_1, close_enough ) for: { 1, 2, 3 } elements are { 2, 3, 4 }
# Usage of RangeEquals range matcher
ok {test-number} - vector_a, !RangeEquals( vector_b, close_enough ) for: { 1, 2, 3 } not elements are { 3, 3, 4 }
# Usage of RangeEquals range matcher
ok {test-number} - needs_adl1, RangeEquals( needs_adl2 ) for: { 1, 2, 3, 4, 5 } elements are { 1, 2, 3, 4, 5 }
# Usage of RangeEquals range matcher
ok {test-number} - needs_adl1, RangeEquals( needs_adl3, []( int l, int r ) { return l + 1 == r; } ) for: { 1, 2, 3, 4, 5 } elements are { 2, 3, 4, 5, 6 }
# Usage of RangeEquals range matcher
ok {test-number} - mocked1, !RangeEquals( arr ) for: { 1, 2, 3, 4 } not elements are { 1, 2, 4, 4 }
# Usage of RangeEquals range matcher
ok {test-number} - mocked1.m_derefed[0] for: true
# Usage of RangeEquals range matcher
ok {test-number} - mocked1.m_derefed[1] for: true
# Usage of RangeEquals range matcher
ok {test-number} - mocked1.m_derefed[2] for: true
# Usage of RangeEquals range matcher
ok {test-number} - !(mocked1.m_derefed[3]) for: !false
# Usage of RangeEquals range matcher
ok {test-number} - mocked1, RangeEquals( arr ) for: { 1, 2, 3, 4 } elements are { 1, 2, 3, 4 }
# Usage of RangeEquals range matcher
ok {test-number} - mocked1.m_derefed[0] for: true
# Usage of RangeEquals range matcher
ok {test-number} - mocked1.m_derefed[1] for: true
# Usage of RangeEquals range matcher
ok {test-number} - mocked1.m_derefed[2] for: true
# Usage of RangeEquals range matcher
ok {test-number} - mocked1.m_derefed[3] for: true
# Usage of UnorderedRangeEquals range matcher
ok {test-number} - empty_vector, UnorderedRangeEquals( empty_vector ) for: { } unordered elements are { }
# Usage of UnorderedRangeEquals range matcher
@@ -3507,6 +3537,8 @@ ok {test-number} - vector_a, !UnorderedRangeEquals( vector_b ) for: { 1, 2, 3 }
ok {test-number} - vector_a, UnorderedRangeEquals( vector_a_plus_1, close_enough ) for: { 1, 10, 20 } unordered elements are { 11, 21, 2 }
# Usage of UnorderedRangeEquals range matcher
ok {test-number} - vector_a, !UnorderedRangeEquals( vector_b, close_enough ) for: { 1, 10, 21 } not unordered elements are { 11, 21, 3 }
# Usage of UnorderedRangeEquals range matcher
ok {test-number} - needs_adl1, UnorderedRangeEquals( needs_adl2 ) for: { 1, 2, 3, 4, 5 } unordered elements are { 1, 2, 3, 4, 5 }
# Usage of the SizeIs range matcher
ok {test-number} - empty_vec, SizeIs(0) for: { } has size == 0
# Usage of the SizeIs range matcher
@@ -4445,5 +4477,5 @@ ok {test-number} - q3 == 23. for: 23.0 == 23.0
ok {test-number} -
# xmlentitycheck
ok {test-number} -
1..2221
1..2237

View File

@@ -1128,6 +1128,8 @@ ok {test-number} - Factorial(2) == 2 for: 2 == 2
ok {test-number} - Factorial(3) == 6 for: 6 == 6
# Factorials are computed
ok {test-number} - Factorial(10) == 3628800 for: 3628800 (0x<hex digits>) == 3628800 (0x<hex digits>)
# Filter generator throws exception for empty generator
ok {test-number} - filter( []( int ) { return false; }, value( 3 ) ), Catch::GeneratorException
# Floating point matchers: double
ok {test-number} - 10., WithinRel( 11.1, 0.1 ) for: 10.0 and 11.1 are within 10% of each other
# Floating point matchers: double
@@ -1186,6 +1188,8 @@ ok {test-number} - WithinRel( 1., 0. )
ok {test-number} - WithinRel( 1., -0.2 ), std::domain_error
# Floating point matchers: double
ok {test-number} - WithinRel( 1., 1. ), std::domain_error
# Floating point matchers: double
ok {test-number} - 1., !IsNaN() for: 1.0 not is NaN
# Floating point matchers: float
ok {test-number} - 10.f, WithinRel( 11.1f, 0.1f ) for: 10.0f and 11.1 are within 10% of each other
# Floating point matchers: float
@@ -1250,6 +1254,8 @@ ok {test-number} - WithinRel( 1.f, 0.f )
ok {test-number} - WithinRel( 1.f, -0.2f ), std::domain_error
# Floating point matchers: float
ok {test-number} - WithinRel( 1.f, 1.f ), std::domain_error
# Floating point matchers: float
ok {test-number} - 1., !IsNaN() for: 1.0 not is NaN
# Generators -- adapters
ok {test-number} - i % 2 == 0 for: 0 == 0
# Generators -- adapters
@@ -3482,6 +3488,30 @@ ok {test-number} - vector_a, !RangeEquals( vector_b ) for: { 1, 2, 3 } not eleme
ok {test-number} - vector_a, RangeEquals( vector_a_plus_1, close_enough ) for: { 1, 2, 3 } elements are { 2, 3, 4 }
# Usage of RangeEquals range matcher
ok {test-number} - vector_a, !RangeEquals( vector_b, close_enough ) for: { 1, 2, 3 } not elements are { 3, 3, 4 }
# Usage of RangeEquals range matcher
ok {test-number} - needs_adl1, RangeEquals( needs_adl2 ) for: { 1, 2, 3, 4, 5 } elements are { 1, 2, 3, 4, 5 }
# Usage of RangeEquals range matcher
ok {test-number} - needs_adl1, RangeEquals( needs_adl3, []( int l, int r ) { return l + 1 == r; } ) for: { 1, 2, 3, 4, 5 } elements are { 2, 3, 4, 5, 6 }
# Usage of RangeEquals range matcher
ok {test-number} - mocked1, !RangeEquals( arr ) for: { 1, 2, 3, 4 } not elements are { 1, 2, 4, 4 }
# Usage of RangeEquals range matcher
ok {test-number} - mocked1.m_derefed[0] for: true
# Usage of RangeEquals range matcher
ok {test-number} - mocked1.m_derefed[1] for: true
# Usage of RangeEquals range matcher
ok {test-number} - mocked1.m_derefed[2] for: true
# Usage of RangeEquals range matcher
ok {test-number} - !(mocked1.m_derefed[3]) for: !false
# Usage of RangeEquals range matcher
ok {test-number} - mocked1, RangeEquals( arr ) for: { 1, 2, 3, 4 } elements are { 1, 2, 3, 4 }
# Usage of RangeEquals range matcher
ok {test-number} - mocked1.m_derefed[0] for: true
# Usage of RangeEquals range matcher
ok {test-number} - mocked1.m_derefed[1] for: true
# Usage of RangeEquals range matcher
ok {test-number} - mocked1.m_derefed[2] for: true
# Usage of RangeEquals range matcher
ok {test-number} - mocked1.m_derefed[3] for: true
# Usage of UnorderedRangeEquals range matcher
ok {test-number} - empty_vector, UnorderedRangeEquals( empty_vector ) for: { } unordered elements are { }
# Usage of UnorderedRangeEquals range matcher
@@ -3500,6 +3530,8 @@ ok {test-number} - vector_a, !UnorderedRangeEquals( vector_b ) for: { 1, 2, 3 }
ok {test-number} - vector_a, UnorderedRangeEquals( vector_a_plus_1, close_enough ) for: { 1, 10, 20 } unordered elements are { 11, 21, 2 }
# Usage of UnorderedRangeEquals range matcher
ok {test-number} - vector_a, !UnorderedRangeEquals( vector_b, close_enough ) for: { 1, 10, 21 } not unordered elements are { 11, 21, 3 }
# Usage of UnorderedRangeEquals range matcher
ok {test-number} - needs_adl1, UnorderedRangeEquals( needs_adl2 ) for: { 1, 2, 3, 4, 5 } unordered elements are { 1, 2, 3, 4, 5 }
# Usage of the SizeIs range matcher
ok {test-number} - empty_vec, SizeIs(0) for: { } has size == 0
# Usage of the SizeIs range matcher
@@ -4434,5 +4466,5 @@ ok {test-number} - q3 == 23. for: 23.0 == 23.0
ok {test-number} -
# xmlentitycheck
ok {test-number} -
1..2221
1..2237

View File

@@ -370,6 +370,8 @@
##teamcity[testFinished name='FAIL_CHECK does not abort the test' duration="{duration}"]
##teamcity[testStarted name='Factorials are computed']
##teamcity[testFinished name='Factorials are computed' duration="{duration}"]
##teamcity[testStarted name='Filter generator throws exception for empty generator']
##teamcity[testFinished name='Filter generator throws exception for empty generator' duration="{duration}"]
##teamcity[testStarted name='Floating point matchers: double']
##teamcity[testFinished name='Floating point matchers: double' duration="{duration}"]
##teamcity[testStarted name='Floating point matchers: float']

View File

@@ -370,6 +370,8 @@
##teamcity[testFinished name='FAIL_CHECK does not abort the test' duration="{duration}"]
##teamcity[testStarted name='Factorials are computed']
##teamcity[testFinished name='Factorials are computed' duration="{duration}"]
##teamcity[testStarted name='Filter generator throws exception for empty generator']
##teamcity[testFinished name='Filter generator throws exception for empty generator' duration="{duration}"]
##teamcity[testStarted name='Floating point matchers: double']
##teamcity[testFinished name='Floating point matchers: double' duration="{duration}"]
##teamcity[testStarted name='Floating point matchers: float']

View File

@@ -5025,6 +5025,17 @@ C
</Expression>
<OverallResult success="true" skips="0"/>
</TestCase>
<TestCase name="Filter generator throws exception for empty generator" tags="[generators]" filename="tests/<exe-name>/IntrospectiveTests/GeneratorsImpl.tests.cpp" >
<Expression success="true" type="REQUIRE_THROWS_AS" filename="tests/<exe-name>/IntrospectiveTests/GeneratorsImpl.tests.cpp" >
<Original>
filter( []( int ) { return false; }, value( 3 ) ), Catch::GeneratorException
</Original>
<Expanded>
filter( []( int ) { return false; }, value( 3 ) ), Catch::GeneratorException
</Expanded>
</Expression>
<OverallResult success="true" skips="0"/>
</TestCase>
<TestCase name="Floating point matchers: double" tags="[floating-point][matchers]" filename="tests/<exe-name>/UsageTests/Matchers.tests.cpp" >
<Section name="Relative" filename="tests/<exe-name>/UsageTests/Matchers.tests.cpp" >
<Expression success="true" type="REQUIRE_THAT" filename="tests/<exe-name>/UsageTests/Matchers.tests.cpp" >
@@ -5276,6 +5287,17 @@ C
</Expression>
<OverallResults successes="6" failures="0" expectedFailures="0" skipped="false"/>
</Section>
<Section name="IsNaN" filename="tests/<exe-name>/UsageTests/Matchers.tests.cpp" >
<Expression success="true" type="REQUIRE_THAT" filename="tests/<exe-name>/UsageTests/Matchers.tests.cpp" >
<Original>
1., !IsNaN()
</Original>
<Expanded>
1.0 not is NaN
</Expanded>
</Expression>
<OverallResults successes="1" failures="0" expectedFailures="0" skipped="false"/>
</Section>
<OverallResult success="true" skips="0"/>
</TestCase>
<TestCase name="Floating point matchers: float" tags="[floating-point][matchers]" filename="tests/<exe-name>/UsageTests/Matchers.tests.cpp" >
@@ -5553,6 +5575,17 @@ C
</Expression>
<OverallResults successes="7" failures="0" expectedFailures="0" skipped="false"/>
</Section>
<Section name="IsNaN" filename="tests/<exe-name>/UsageTests/Matchers.tests.cpp" >
<Expression success="true" type="REQUIRE_THAT" filename="tests/<exe-name>/UsageTests/Matchers.tests.cpp" >
<Original>
1., !IsNaN()
</Original>
<Expanded>
1.0 not is NaN
</Expanded>
</Expression>
<OverallResults successes="1" failures="0" expectedFailures="0" skipped="false"/>
</Section>
<OverallResult success="true" skips="0"/>
</TestCase>
<TestCase name="Generators -- adapters" tags="[generators][generic]" filename="tests/<exe-name>/UsageTests/Generators.tests.cpp" >
@@ -16645,6 +16678,117 @@ There is no extra whitespace here
</Section>
<OverallResults successes="1" failures="0" expectedFailures="0" skipped="false"/>
</Section>
<Section name="Ranges that need ADL begin/end" filename="tests/<exe-name>/UsageTests/MatchersRanges.tests.cpp" >
<Expression success="true" type="REQUIRE_THAT" filename="tests/<exe-name>/UsageTests/MatchersRanges.tests.cpp" >
<Original>
needs_adl1, RangeEquals( needs_adl2 )
</Original>
<Expanded>
{ 1, 2, 3, 4, 5 } elements are { 1, 2, 3, 4, 5 }
</Expanded>
</Expression>
<Expression success="true" type="REQUIRE_THAT" filename="tests/<exe-name>/UsageTests/MatchersRanges.tests.cpp" >
<Original>
needs_adl1, RangeEquals( needs_adl3, []( int l, int r ) { return l + 1 == r; } )
</Original>
<Expanded>
{ 1, 2, 3, 4, 5 } elements are { 2, 3, 4, 5, 6 }
</Expanded>
</Expression>
<OverallResults successes="2" failures="0" expectedFailures="0" skipped="false"/>
</Section>
<Section name="Check short-circuiting behaviour" filename="tests/<exe-name>/UsageTests/MatchersRanges.tests.cpp" >
<Section name="Check short-circuits on failure" filename="tests/<exe-name>/UsageTests/MatchersRanges.tests.cpp" >
<Expression success="true" type="REQUIRE_THAT" filename="tests/<exe-name>/UsageTests/MatchersRanges.tests.cpp" >
<Original>
mocked1, !RangeEquals( arr )
</Original>
<Expanded>
{ 1, 2, 3, 4 } not elements are { 1, 2, 4, 4 }
</Expanded>
</Expression>
<Expression success="true" type="REQUIRE" filename="tests/<exe-name>/UsageTests/MatchersRanges.tests.cpp" >
<Original>
mocked1.m_derefed[0]
</Original>
<Expanded>
true
</Expanded>
</Expression>
<Expression success="true" type="REQUIRE" filename="tests/<exe-name>/UsageTests/MatchersRanges.tests.cpp" >
<Original>
mocked1.m_derefed[1]
</Original>
<Expanded>
true
</Expanded>
</Expression>
<Expression success="true" type="REQUIRE" filename="tests/<exe-name>/UsageTests/MatchersRanges.tests.cpp" >
<Original>
mocked1.m_derefed[2]
</Original>
<Expanded>
true
</Expanded>
</Expression>
<Expression success="true" type="REQUIRE_FALSE" filename="tests/<exe-name>/UsageTests/MatchersRanges.tests.cpp" >
<Original>
!(mocked1.m_derefed[3])
</Original>
<Expanded>
!false
</Expanded>
</Expression>
<OverallResults successes="5" failures="0" expectedFailures="0" skipped="false"/>
</Section>
<OverallResults successes="5" failures="0" expectedFailures="0" skipped="false"/>
</Section>
<Section name="Check short-circuiting behaviour" filename="tests/<exe-name>/UsageTests/MatchersRanges.tests.cpp" >
<Section name="All elements are checked on success" filename="tests/<exe-name>/UsageTests/MatchersRanges.tests.cpp" >
<Expression success="true" type="REQUIRE_THAT" filename="tests/<exe-name>/UsageTests/MatchersRanges.tests.cpp" >
<Original>
mocked1, RangeEquals( arr )
</Original>
<Expanded>
{ 1, 2, 3, 4 } elements are { 1, 2, 3, 4 }
</Expanded>
</Expression>
<Expression success="true" type="REQUIRE" filename="tests/<exe-name>/UsageTests/MatchersRanges.tests.cpp" >
<Original>
mocked1.m_derefed[0]
</Original>
<Expanded>
true
</Expanded>
</Expression>
<Expression success="true" type="REQUIRE" filename="tests/<exe-name>/UsageTests/MatchersRanges.tests.cpp" >
<Original>
mocked1.m_derefed[1]
</Original>
<Expanded>
true
</Expanded>
</Expression>
<Expression success="true" type="REQUIRE" filename="tests/<exe-name>/UsageTests/MatchersRanges.tests.cpp" >
<Original>
mocked1.m_derefed[2]
</Original>
<Expanded>
true
</Expanded>
</Expression>
<Expression success="true" type="REQUIRE" filename="tests/<exe-name>/UsageTests/MatchersRanges.tests.cpp" >
<Original>
mocked1.m_derefed[3]
</Original>
<Expanded>
true
</Expanded>
</Expression>
<OverallResults successes="5" failures="0" expectedFailures="0" skipped="false"/>
</Section>
<OverallResults successes="5" failures="0" expectedFailures="0" skipped="false"/>
</Section>
<OverallResult success="true" skips="0"/>
</TestCase>
<TestCase name="Usage of UnorderedRangeEquals range matcher" tags="[matchers][quantifiers][templated]" filename="tests/<exe-name>/UsageTests/MatchersRanges.tests.cpp" >
@@ -16768,6 +16912,17 @@ There is no extra whitespace here
</Section>
<OverallResults successes="1" failures="0" expectedFailures="0" skipped="false"/>
</Section>
<Section name="Ranges that need ADL begin/end" filename="tests/<exe-name>/UsageTests/MatchersRanges.tests.cpp" >
<Expression success="true" type="REQUIRE_THAT" filename="tests/<exe-name>/UsageTests/MatchersRanges.tests.cpp" >
<Original>
needs_adl1, UnorderedRangeEquals( needs_adl2 )
</Original>
<Expanded>
{ 1, 2, 3, 4, 5 } unordered elements are { 1, 2, 3, 4, 5 }
</Expanded>
</Expression>
<OverallResults successes="1" failures="0" expectedFailures="0" skipped="false"/>
</Section>
<OverallResult success="true" skips="0"/>
</TestCase>
<TestCase name="Usage of the SizeIs range matcher" tags="[matchers][size][templated]" filename="tests/<exe-name>/UsageTests/MatchersRanges.tests.cpp" >
@@ -21048,6 +21203,6 @@ b1!
</Section>
<OverallResult success="true" skips="0"/>
</TestCase>
<OverallResults successes="2033" failures="145" expectedFailures="32" skips="11"/>
<OverallResultsCases successes="308" failures="84" expectedFailures="11" skips="5"/>
<OverallResults successes="2049" failures="145" expectedFailures="32" skips="11"/>
<OverallResultsCases successes="309" failures="84" expectedFailures="11" skips="5"/>
</Catch2TestRun>

View File

@@ -5025,6 +5025,17 @@ C
</Expression>
<OverallResult success="true" skips="0"/>
</TestCase>
<TestCase name="Filter generator throws exception for empty generator" tags="[generators]" filename="tests/<exe-name>/IntrospectiveTests/GeneratorsImpl.tests.cpp" >
<Expression success="true" type="REQUIRE_THROWS_AS" filename="tests/<exe-name>/IntrospectiveTests/GeneratorsImpl.tests.cpp" >
<Original>
filter( []( int ) { return false; }, value( 3 ) ), Catch::GeneratorException
</Original>
<Expanded>
filter( []( int ) { return false; }, value( 3 ) ), Catch::GeneratorException
</Expanded>
</Expression>
<OverallResult success="true" skips="0"/>
</TestCase>
<TestCase name="Floating point matchers: double" tags="[floating-point][matchers]" filename="tests/<exe-name>/UsageTests/Matchers.tests.cpp" >
<Section name="Relative" filename="tests/<exe-name>/UsageTests/Matchers.tests.cpp" >
<Expression success="true" type="REQUIRE_THAT" filename="tests/<exe-name>/UsageTests/Matchers.tests.cpp" >
@@ -5276,6 +5287,17 @@ C
</Expression>
<OverallResults successes="6" failures="0" expectedFailures="0" skipped="false"/>
</Section>
<Section name="IsNaN" filename="tests/<exe-name>/UsageTests/Matchers.tests.cpp" >
<Expression success="true" type="REQUIRE_THAT" filename="tests/<exe-name>/UsageTests/Matchers.tests.cpp" >
<Original>
1., !IsNaN()
</Original>
<Expanded>
1.0 not is NaN
</Expanded>
</Expression>
<OverallResults successes="1" failures="0" expectedFailures="0" skipped="false"/>
</Section>
<OverallResult success="true" skips="0"/>
</TestCase>
<TestCase name="Floating point matchers: float" tags="[floating-point][matchers]" filename="tests/<exe-name>/UsageTests/Matchers.tests.cpp" >
@@ -5553,6 +5575,17 @@ C
</Expression>
<OverallResults successes="7" failures="0" expectedFailures="0" skipped="false"/>
</Section>
<Section name="IsNaN" filename="tests/<exe-name>/UsageTests/Matchers.tests.cpp" >
<Expression success="true" type="REQUIRE_THAT" filename="tests/<exe-name>/UsageTests/Matchers.tests.cpp" >
<Original>
1., !IsNaN()
</Original>
<Expanded>
1.0 not is NaN
</Expanded>
</Expression>
<OverallResults successes="1" failures="0" expectedFailures="0" skipped="false"/>
</Section>
<OverallResult success="true" skips="0"/>
</TestCase>
<TestCase name="Generators -- adapters" tags="[generators][generic]" filename="tests/<exe-name>/UsageTests/Generators.tests.cpp" >
@@ -16645,6 +16678,117 @@ There is no extra whitespace here
</Section>
<OverallResults successes="1" failures="0" expectedFailures="0" skipped="false"/>
</Section>
<Section name="Ranges that need ADL begin/end" filename="tests/<exe-name>/UsageTests/MatchersRanges.tests.cpp" >
<Expression success="true" type="REQUIRE_THAT" filename="tests/<exe-name>/UsageTests/MatchersRanges.tests.cpp" >
<Original>
needs_adl1, RangeEquals( needs_adl2 )
</Original>
<Expanded>
{ 1, 2, 3, 4, 5 } elements are { 1, 2, 3, 4, 5 }
</Expanded>
</Expression>
<Expression success="true" type="REQUIRE_THAT" filename="tests/<exe-name>/UsageTests/MatchersRanges.tests.cpp" >
<Original>
needs_adl1, RangeEquals( needs_adl3, []( int l, int r ) { return l + 1 == r; } )
</Original>
<Expanded>
{ 1, 2, 3, 4, 5 } elements are { 2, 3, 4, 5, 6 }
</Expanded>
</Expression>
<OverallResults successes="2" failures="0" expectedFailures="0" skipped="false"/>
</Section>
<Section name="Check short-circuiting behaviour" filename="tests/<exe-name>/UsageTests/MatchersRanges.tests.cpp" >
<Section name="Check short-circuits on failure" filename="tests/<exe-name>/UsageTests/MatchersRanges.tests.cpp" >
<Expression success="true" type="REQUIRE_THAT" filename="tests/<exe-name>/UsageTests/MatchersRanges.tests.cpp" >
<Original>
mocked1, !RangeEquals( arr )
</Original>
<Expanded>
{ 1, 2, 3, 4 } not elements are { 1, 2, 4, 4 }
</Expanded>
</Expression>
<Expression success="true" type="REQUIRE" filename="tests/<exe-name>/UsageTests/MatchersRanges.tests.cpp" >
<Original>
mocked1.m_derefed[0]
</Original>
<Expanded>
true
</Expanded>
</Expression>
<Expression success="true" type="REQUIRE" filename="tests/<exe-name>/UsageTests/MatchersRanges.tests.cpp" >
<Original>
mocked1.m_derefed[1]
</Original>
<Expanded>
true
</Expanded>
</Expression>
<Expression success="true" type="REQUIRE" filename="tests/<exe-name>/UsageTests/MatchersRanges.tests.cpp" >
<Original>
mocked1.m_derefed[2]
</Original>
<Expanded>
true
</Expanded>
</Expression>
<Expression success="true" type="REQUIRE_FALSE" filename="tests/<exe-name>/UsageTests/MatchersRanges.tests.cpp" >
<Original>
!(mocked1.m_derefed[3])
</Original>
<Expanded>
!false
</Expanded>
</Expression>
<OverallResults successes="5" failures="0" expectedFailures="0" skipped="false"/>
</Section>
<OverallResults successes="5" failures="0" expectedFailures="0" skipped="false"/>
</Section>
<Section name="Check short-circuiting behaviour" filename="tests/<exe-name>/UsageTests/MatchersRanges.tests.cpp" >
<Section name="All elements are checked on success" filename="tests/<exe-name>/UsageTests/MatchersRanges.tests.cpp" >
<Expression success="true" type="REQUIRE_THAT" filename="tests/<exe-name>/UsageTests/MatchersRanges.tests.cpp" >
<Original>
mocked1, RangeEquals( arr )
</Original>
<Expanded>
{ 1, 2, 3, 4 } elements are { 1, 2, 3, 4 }
</Expanded>
</Expression>
<Expression success="true" type="REQUIRE" filename="tests/<exe-name>/UsageTests/MatchersRanges.tests.cpp" >
<Original>
mocked1.m_derefed[0]
</Original>
<Expanded>
true
</Expanded>
</Expression>
<Expression success="true" type="REQUIRE" filename="tests/<exe-name>/UsageTests/MatchersRanges.tests.cpp" >
<Original>
mocked1.m_derefed[1]
</Original>
<Expanded>
true
</Expanded>
</Expression>
<Expression success="true" type="REQUIRE" filename="tests/<exe-name>/UsageTests/MatchersRanges.tests.cpp" >
<Original>
mocked1.m_derefed[2]
</Original>
<Expanded>
true
</Expanded>
</Expression>
<Expression success="true" type="REQUIRE" filename="tests/<exe-name>/UsageTests/MatchersRanges.tests.cpp" >
<Original>
mocked1.m_derefed[3]
</Original>
<Expanded>
true
</Expanded>
</Expression>
<OverallResults successes="5" failures="0" expectedFailures="0" skipped="false"/>
</Section>
<OverallResults successes="5" failures="0" expectedFailures="0" skipped="false"/>
</Section>
<OverallResult success="true" skips="0"/>
</TestCase>
<TestCase name="Usage of UnorderedRangeEquals range matcher" tags="[matchers][quantifiers][templated]" filename="tests/<exe-name>/UsageTests/MatchersRanges.tests.cpp" >
@@ -16768,6 +16912,17 @@ There is no extra whitespace here
</Section>
<OverallResults successes="1" failures="0" expectedFailures="0" skipped="false"/>
</Section>
<Section name="Ranges that need ADL begin/end" filename="tests/<exe-name>/UsageTests/MatchersRanges.tests.cpp" >
<Expression success="true" type="REQUIRE_THAT" filename="tests/<exe-name>/UsageTests/MatchersRanges.tests.cpp" >
<Original>
needs_adl1, UnorderedRangeEquals( needs_adl2 )
</Original>
<Expanded>
{ 1, 2, 3, 4, 5 } unordered elements are { 1, 2, 3, 4, 5 }
</Expanded>
</Expression>
<OverallResults successes="1" failures="0" expectedFailures="0" skipped="false"/>
</Section>
<OverallResult success="true" skips="0"/>
</TestCase>
<TestCase name="Usage of the SizeIs range matcher" tags="[matchers][size][templated]" filename="tests/<exe-name>/UsageTests/MatchersRanges.tests.cpp" >
@@ -21047,6 +21202,6 @@ b1!
</Section>
<OverallResult success="true" skips="0"/>
</TestCase>
<OverallResults successes="2033" failures="145" expectedFailures="32" skips="11"/>
<OverallResultsCases successes="308" failures="84" expectedFailures="11" skips="5"/>
<OverallResults successes="2049" failures="145" expectedFailures="32" skips="11"/>
<OverallResultsCases successes="309" failures="84" expectedFailures="11" skips="5"/>
</Catch2TestRun>

View File

@@ -0,0 +1,94 @@
// Copyright Catch2 Authors
// Distributed under the Boost Software License, Version 1.0.
// (See accompanying file LICENSE.txt or copy at
// https://www.boost.org/LICENSE_1_0.txt)
// SPDX-License-Identifier: BSL-1.0
#include <catch2/catch_test_macros.hpp>
#include <catch2/internal/catch_is_permutation.hpp>
#include <helpers/range_test_helpers.hpp>
#include <array>
namespace {
template <typename Range1, typename Range2>
static bool is_permutation(Range1 const& r1, Range2 const& r2) {
using std::begin; using std::end;
return Catch::Detail::is_permutation(
begin( r1 ), end( r1 ), begin( r2 ), end( r2 ), std::equal_to<>{} );
}
}
TEST_CASE("is_permutation", "[algorithms][approvals]") {
SECTION( "Handle empty ranges" ) {
std::array<int, 0> empty;
std::array<int, 2> non_empty{ { 2, 3 } };
REQUIRE( is_permutation( empty, empty ) );
REQUIRE_FALSE( is_permutation( empty, non_empty ) );
REQUIRE_FALSE( is_permutation( non_empty, empty ) );
}
SECTION( "Different length ranges" ) {
std::array<int, 6> arr1{ { 1, 3, 5, 7, 8, 9 } };
// arr2 is prefix of arr1
std::array<int, 4> arr2{ { 1, 3, 5, 7 } };
// arr3 shares prefix with arr1 and arr2, but is not a permutation
std::array<int, 5> arr3{ { 1, 3, 5, 9, 8 } };
REQUIRE_FALSE( is_permutation( arr1, arr2 ) );
REQUIRE_FALSE( is_permutation( arr1, arr3 ) );
REQUIRE_FALSE( is_permutation( arr2, arr3 ) );
}
SECTION( "Same length ranges" ) {
SECTION( "Shared elements, but different counts" ) {
const std::array<int, 6>
arr1{ { 1, 1, 1, 1, 2, 2 } },
arr2{ { 1, 1, 2, 2, 2, 2 } };
REQUIRE_FALSE( is_permutation( arr1, arr2 ) );
}
SECTION( "Identical ranges" ) {
const std::array<int, 6>
arr1{ { 1, 1, 1, 1, 2, 2 } },
arr2{ { 1, 1, 2, 2, 2, 2 } };
REQUIRE( is_permutation( arr1, arr1 ) );
REQUIRE( is_permutation( arr2, arr2 ) );
}
SECTION( "Completely distinct elements" ) {
// Completely distinct elements
const std::array<int, 4>
arr1{ { 1, 2, 3, 4 } },
arr2{ { 10, 20, 30, 40 } };
REQUIRE_FALSE( is_permutation( arr1, arr2 ) );
}
SECTION( "Reverse ranges" ) {
const std::array<int, 5>
arr1{ { 1, 2, 3, 4, 5 } },
arr2{ { 5, 4, 3, 2, 1 } };
REQUIRE( is_permutation( arr1, arr2 ) );
}
SECTION( "Shared prefix & permuted elements" ) {
const std::array<int, 5>
arr1{ { 1, 1, 2, 3, 4 } },
arr2{ { 1, 1, 4, 2, 3 } };
REQUIRE( is_permutation( arr1, arr2 ) );
}
SECTION( "Permutations with element count > 1" ) {
const std::array<int, 7>
arr1{ { 2, 2, 3, 3, 3, 1, 1 } },
arr2{ { 3, 2, 1, 3, 2, 1, 3 } };
REQUIRE( is_permutation( arr1, arr2 ) );
}
}
}
TEST_CASE("is_permutation supports iterator + sentinel pairs",
"[algorithms][is-permutation][approvals]") {
const has_different_begin_end_types<int>
range_1{ 1, 2, 3, 4 },
range_2{ 4, 3, 2, 1 };
REQUIRE( is_permutation( range_1, range_2 ) );
const has_different_begin_end_types<int> range_3{ 3, 3, 2, 1 };
REQUIRE_FALSE( is_permutation( range_1, range_3 ) );
}

View File

@@ -16,6 +16,7 @@
#include <catch2/generators/catch_generators_adapters.hpp>
#include <catch2/generators/catch_generators_random.hpp>
#include <catch2/generators/catch_generators_range.hpp>
#include <catch2/generators/catch_generator_exception.hpp>
// Tests of generator implementation details
TEST_CASE("Generators internals", "[generators][internals]") {
@@ -534,3 +535,12 @@ TEST_CASE( "Random generators can be seeded", "[generators][approvals]" ) {
}
}
}
TEST_CASE("Filter generator throws exception for empty generator",
"[generators]") {
using namespace Catch::Generators;
REQUIRE_THROWS_AS(
filter( []( int ) { return false; }, value( 3 ) ),
Catch::GeneratorException );
}

View File

@@ -14,8 +14,8 @@
using namespace Catch;
namespace {
Catch::TestCaseTracking::NameAndLocation makeNAL( std::string const& name ) {
return Catch::TestCaseTracking::NameAndLocation( name, Catch::SourceLineInfo("",0) );
Catch::TestCaseTracking::NameAndLocationRef makeNAL( StringRef name ) {
return Catch::TestCaseTracking::NameAndLocationRef( name, Catch::SourceLineInfo("",0) );
}
}

View File

@@ -497,6 +497,9 @@ TEST_CASE( "Floating point matchers: float", "[matchers][floating-point]" ) {
REQUIRE_THROWS_AS( WithinRel( 1.f, -0.2f ), std::domain_error );
REQUIRE_THROWS_AS( WithinRel( 1.f, 1.f ), std::domain_error );
}
SECTION( "IsNaN" ) {
REQUIRE_THAT( 1., !IsNaN() );
}
}
TEST_CASE( "Floating point matchers: double", "[matchers][floating-point]" ) {
@@ -552,6 +555,9 @@ TEST_CASE( "Floating point matchers: double", "[matchers][floating-point]" ) {
REQUIRE_THROWS_AS( WithinRel( 1., -0.2 ), std::domain_error );
REQUIRE_THROWS_AS( WithinRel( 1., 1. ), std::domain_error );
}
SECTION("IsNaN") {
REQUIRE_THAT( 1., !IsNaN() );
}
}
TEST_CASE( "Floating point matchers that are problematic in approvals",
@@ -566,6 +572,8 @@ TEST_CASE( "Floating point matchers that are problematic in approvals",
REQUIRE_THAT( NAN, !WithinRel( NAN ) );
REQUIRE_THAT( 1., !WithinRel( NAN ) );
REQUIRE_THAT( NAN, !WithinRel( 1. ) );
REQUIRE_THAT( NAN, IsNaN() );
REQUIRE_THAT( static_cast<double>(NAN), IsNaN() );
}
TEST_CASE( "Arbitrary predicate matcher", "[matchers][generic]" ) {

View File

@@ -15,195 +15,15 @@
#include <catch2/matchers/catch_matchers_predicate.hpp>
#include <catch2/matchers/catch_matchers_string.hpp>
#include <helpers/range_test_helpers.hpp>
#include <cmath>
#include <initializer_list>
#include <list>
#include <map>
#include <type_traits>
#include <vector>
#include <memory>
namespace {
namespace unrelated {
template <typename T>
class needs_ADL_begin {
std::vector<T> m_elements;
public:
using iterator = typename std::vector<T>::iterator;
using const_iterator = typename std::vector<T>::const_iterator;
needs_ADL_begin(std::initializer_list<T> init) : m_elements(init) {}
const_iterator Begin() const { return m_elements.begin(); }
const_iterator End() const { return m_elements.end(); }
friend const_iterator begin(needs_ADL_begin const& lhs) {
return lhs.Begin();
}
friend const_iterator end(needs_ADL_begin const& rhs) {
return rhs.End();
}
};
} // end unrelated namespace
#if defined(__clang__)
# pragma clang diagnostic push
# pragma clang diagnostic ignored "-Wunused-function"
#endif
template <typename T>
class has_different_begin_end_types {
// Using std::vector<T> leads to annoying issues when T is bool
// so we just use list because the perf is not critical and ugh.
std::list<T> m_elements;
// Different type for the "end" iterator
struct iterator_end {};
// Fake-ish forward iterator that only compares to a different type
class iterator {
using underlying_iter = typename std::list<T>::const_iterator;
underlying_iter m_start;
underlying_iter m_end;
public:
iterator( underlying_iter start, underlying_iter end ):
m_start( start ), m_end( end ) {}
using iterator_category = std::forward_iterator_tag;
using difference_type = std::ptrdiff_t;
using value_type = T;
using const_reference = T const&;
using pointer = T const*;
friend bool operator==( iterator iter, iterator_end ) {
return iter.m_start == iter.m_end;
}
friend bool operator!=( iterator iter, iterator_end ) {
return iter.m_start != iter.m_end;
}
iterator& operator++() {
++m_start;
return *this;
}
iterator operator++(int) {
auto tmp(*this);
++m_start;
return tmp;
}
const_reference operator*() const {
return *m_start;
}
pointer operator->() const {
return m_start;
}
};
public:
explicit has_different_begin_end_types( std::initializer_list<T> init ):
m_elements( init ) {}
iterator begin() const {
return { m_elements.begin(), m_elements.end() };
}
iterator_end end() const {
return {};
}
};
#if defined(__clang__)
# pragma clang diagnostic pop
#endif
template <typename T> struct with_mocked_iterator_access {
std::vector<T> m_elements;
// use plain arrays to have nicer printouts with CHECK(...)
mutable std::unique_ptr<bool[]> m_derefed;
// We want to check which elements were dereferenced when iterating, so
// we can check whether iterator-using code traverses range correctly
template <bool is_const> class basic_iterator {
template <typename U>
using constify_t = std::conditional_t<is_const, std::add_const_t<U>, U>;
constify_t<with_mocked_iterator_access>* m_origin;
size_t m_origin_idx;
public:
using iterator_category = std::forward_iterator_tag;
using difference_type = std::ptrdiff_t;
using value_type = constify_t<T>;
using const_reference = typename std::vector<T>::const_reference;
using reference = typename std::vector<T>::reference;
using pointer = typename std::vector<T>::pointer;
basic_iterator( constify_t<with_mocked_iterator_access>* origin,
std::size_t origin_idx ):
m_origin{ origin }, m_origin_idx{ origin_idx } {}
friend bool operator==( basic_iterator lhs, basic_iterator rhs ) {
return lhs.m_origin == rhs.m_origin &&
lhs.m_origin_idx == rhs.m_origin_idx;
}
friend bool operator!=( basic_iterator lhs, basic_iterator rhs ) {
return !( lhs == rhs );
}
basic_iterator& operator++() {
++m_origin_idx;
return *this;
}
basic_iterator operator++( int ) {
auto tmp( *this );
++( *this );
return tmp;
}
const_reference operator*() const {
assert( m_origin_idx < m_origin->m_elements.size() && "Attempted to deref invalid position" );
m_origin->m_derefed[m_origin_idx] = true;
return m_origin->m_elements[m_origin_idx];
}
pointer operator->() const {
assert( m_origin_idx < m_origin->m_elements.size() && "Attempted to deref invalid position" );
return &m_origin->m_elements[m_origin_idx];
}
};
using iterator = basic_iterator<false>;
using const_iterator = basic_iterator<true>;
with_mocked_iterator_access( std::initializer_list<T> init ):
m_elements( init ),
m_derefed( std::make_unique<bool[]>( m_elements.size() ) ) {}
const_iterator begin() const { return { this, 0 }; }
const_iterator end() const { return { this, m_elements.size() }; }
iterator begin() { return { this, 0 }; }
iterator end() { return { this, m_elements.size() }; }
};
} // end anon namespace
namespace Catch {
// make sure with_mocked_iterator_access is not considered a range by Catch,
// so that below StringMaker is used instead of the default one for ranges
template <typename T>
struct is_range<with_mocked_iterator_access<T>> : std::false_type {};
template <typename T>
struct StringMaker<with_mocked_iterator_access<T>> {
static std::string
convert( with_mocked_iterator_access<T> const& access ) {
// We have to avoid the type's iterators, because we check
// their use in tests
return ::Catch::Detail::stringify( access.m_elements );
}
};
} // namespace Catch
struct MoveOnlyTestElement {
int num = 0;
MoveOnlyTestElement(int n) :num(n) {}
@@ -287,16 +107,6 @@ namespace {
bool empty() const { return false; }
};
namespace unrelated {
struct ADL_empty {
bool Empty() const { return true; }
friend bool empty(ADL_empty e) {
return e.Empty();
}
};
} // end namespace unrelated
} // end unnamed namespace
TEST_CASE("Basic use of the Empty range matcher", "[matchers][templated][empty]") {
@@ -346,17 +156,6 @@ namespace {
return LessThanMatcher{ sz };
}
namespace unrelated {
struct ADL_size {
size_t sz() const {
return 12;
}
friend size_t size(ADL_size s) {
return s.sz();
}
};
} // end namespace unrelated
struct has_size {
size_t size() const {
return 13;
@@ -832,6 +631,31 @@ TEST_CASE( "The quantifier range matchers support types with different types ret
}
}
TEST_CASE( "RangeEquals supports ranges with different types returned from begin and end",
"[matchers][templated][range][approvals] ") {
using Catch::Matchers::RangeEquals;
using Catch::Matchers::UnorderedRangeEquals;
has_different_begin_end_types<int> diff_types{ 1, 2, 3, 4, 5 };
std::array<int, 5> arr1{ { 1, 2, 3, 4, 5 } }, arr2{ { 2, 3, 4, 5, 6 } };
REQUIRE_THAT( diff_types, RangeEquals( arr1 ) );
REQUIRE_THAT( diff_types, RangeEquals( arr2, []( int l, int r ) {
return l + 1 == r;
} ) );
REQUIRE_THAT( diff_types, UnorderedRangeEquals( diff_types ) );
}
TEST_CASE( "RangeContains supports ranges with different types returned from "
"begin and end",
"[matchers][templated][range][approvals]" ) {
using Catch::Matchers::Contains;
has_different_begin_end_types<size_t> diff_types{ 1, 2, 3, 4, 5 };
REQUIRE_THAT( diff_types, Contains( size_t( 3 ) ) );
REQUIRE_THAT( diff_types, Contains( LessThanMatcher( size_t( 4 ) ) ) );
}
#endif
TEST_CASE( "Usage of RangeEquals range matcher", "[matchers][templated][quantifiers]" ) {
@@ -891,10 +715,40 @@ TEST_CASE( "Usage of RangeEquals range matcher", "[matchers][templated][quantifi
}
}
// Cannot usefully test short-circuits, as the complexiy of std::equal is
// only guaranteed to be O(n) or better (even if many implementations
// short-circuit if the range lengths differ for
// LegacyRandomAccessIterators)
SECTION( "Ranges that need ADL begin/end" ) {
unrelated::needs_ADL_begin<int> const
needs_adl1{ 1, 2, 3, 4, 5 },
needs_adl2{ 1, 2, 3, 4, 5 },
needs_adl3{ 2, 3, 4, 5, 6 };
REQUIRE_THAT( needs_adl1, RangeEquals( needs_adl2 ) );
REQUIRE_THAT( needs_adl1, RangeEquals( needs_adl3, []( int l, int r ) {
return l + 1 == r;
} ) );
}
SECTION("Check short-circuiting behaviour") {
with_mocked_iterator_access<int> const mocked1{ 1, 2, 3, 4 };
SECTION( "Check short-circuits on failure" ) {
std::array<int, 4> arr{ { 1, 2, 4, 4 } };
REQUIRE_THAT( mocked1, !RangeEquals( arr ) );
REQUIRE( mocked1.m_derefed[0] );
REQUIRE( mocked1.m_derefed[1] );
REQUIRE( mocked1.m_derefed[2] );
REQUIRE_FALSE( mocked1.m_derefed[3] );
}
SECTION("All elements are checked on success") {
std::array<int, 4> arr{ { 1, 2, 3, 4 } };
REQUIRE_THAT( mocked1, RangeEquals( arr ) );
REQUIRE( mocked1.m_derefed[0] );
REQUIRE( mocked1.m_derefed[1] );
REQUIRE( mocked1.m_derefed[2] );
REQUIRE( mocked1.m_derefed[3] );
}
}
}
TEST_CASE( "Usage of UnorderedRangeEquals range matcher",
@@ -958,8 +812,14 @@ TEST_CASE( "Usage of UnorderedRangeEquals range matcher",
}
}
// As above with RangeEquals, short cicuiting and other optimisations
// are left to the STL implementation
SECTION( "Ranges that need ADL begin/end" ) {
unrelated::needs_ADL_begin<int> const
needs_adl1{ 1, 2, 3, 4, 5 },
needs_adl2{ 1, 2, 3, 4, 5 };
REQUIRE_THAT( needs_adl1, UnorderedRangeEquals( needs_adl2 ) );
}
}
/**

View File

@@ -0,0 +1,210 @@
// Copyright Catch2 Authors
// Distributed under the Boost Software License, Version 1.0.
// (See accompanying file LICENSE.txt or copy at
// https://www.boost.org/LICENSE_1_0.txt)
// SPDX-License-Identifier: BSL-1.0
#ifndef CATCH_TEST_HELPERS_RANGE_TEST_HELPERS_HPP_INCLUDED
#define CATCH_TEST_HELPERS_RANGE_TEST_HELPERS_HPP_INCLUDED
#include <catch2/catch_tostring.hpp>
#include <initializer_list>
#include <list>
#include <memory>
#include <vector>
namespace unrelated {
template <typename T>
class needs_ADL_begin {
std::vector<T> m_elements;
public:
using iterator = typename std::vector<T>::iterator;
using const_iterator = typename std::vector<T>::const_iterator;
needs_ADL_begin( std::initializer_list<T> init ): m_elements( init ) {}
const_iterator Begin() const { return m_elements.begin(); }
const_iterator End() const { return m_elements.end(); }
friend const_iterator begin( needs_ADL_begin const& lhs ) {
return lhs.Begin();
}
friend const_iterator end( needs_ADL_begin const& rhs ) {
return rhs.End();
}
};
struct ADL_empty {
bool Empty() const { return true; }
friend bool empty( ADL_empty e ) { return e.Empty(); }
};
struct ADL_size {
size_t sz() const { return 12; }
friend size_t size( ADL_size s ) { return s.sz(); }
};
} // namespace unrelated
#if defined( __clang__ )
# pragma clang diagnostic push
# pragma clang diagnostic ignored "-Wunused-function"
#endif
template <typename T>
class has_different_begin_end_types {
// Using std::vector<T> leads to annoying issues when T is bool
// so we just use list because the perf is not critical and ugh.
std::list<T> m_elements;
// Different type for the "end" iterator
struct iterator_end {};
// Fake-ish forward iterator that only compares to a different type
class iterator {
using underlying_iter = typename std::list<T>::const_iterator;
underlying_iter m_start;
underlying_iter m_end;
public:
iterator( underlying_iter start, underlying_iter end ):
m_start( start ), m_end( end ) {}
using iterator_category = std::forward_iterator_tag;
using difference_type = std::ptrdiff_t;
using value_type = T;
using const_reference = T const&;
using pointer = T const*;
friend bool operator==( iterator iter, iterator_end ) {
return iter.m_start == iter.m_end;
}
friend bool operator==(iterator lhs, iterator rhs) {
return lhs.m_start == rhs.m_start && lhs.m_end == rhs.m_end;
}
friend bool operator!=( iterator iter, iterator_end ) {
return iter.m_start != iter.m_end;
}
friend bool operator!=( iterator lhs, iterator rhs ) {
return !( lhs == rhs );
}
iterator& operator++() {
++m_start;
return *this;
}
iterator operator++( int ) {
auto tmp( *this );
++m_start;
return tmp;
}
const_reference operator*() const { return *m_start; }
pointer operator->() const { return m_start; }
};
public:
explicit has_different_begin_end_types( std::initializer_list<T> init ):
m_elements( init ) {}
iterator begin() const { return { m_elements.begin(), m_elements.end() }; }
iterator_end end() const { return {}; }
};
#if defined( __clang__ )
# pragma clang diagnostic pop
#endif
template <typename T>
struct with_mocked_iterator_access {
std::vector<T> m_elements;
// use plain arrays to have nicer printouts with CHECK(...)
mutable std::unique_ptr<bool[]> m_derefed;
// We want to check which elements were dereferenced when iterating, so
// we can check whether iterator-using code traverses range correctly
template <bool is_const>
class basic_iterator {
template <typename U>
using constify_t = std::conditional_t<is_const, std::add_const_t<U>, U>;
constify_t<with_mocked_iterator_access>* m_origin;
size_t m_origin_idx;
public:
using iterator_category = std::forward_iterator_tag;
using difference_type = std::ptrdiff_t;
using value_type = constify_t<T>;
using const_reference = typename std::vector<T>::const_reference;
using reference = typename std::vector<T>::reference;
using pointer = typename std::vector<T>::pointer;
basic_iterator( constify_t<with_mocked_iterator_access>* origin,
std::size_t origin_idx ):
m_origin{ origin }, m_origin_idx{ origin_idx } {}
friend bool operator==( basic_iterator lhs, basic_iterator rhs ) {
return lhs.m_origin == rhs.m_origin &&
lhs.m_origin_idx == rhs.m_origin_idx;
}
friend bool operator!=( basic_iterator lhs, basic_iterator rhs ) {
return !( lhs == rhs );
}
basic_iterator& operator++() {
++m_origin_idx;
return *this;
}
basic_iterator operator++( int ) {
auto tmp( *this );
++( *this );
return tmp;
}
const_reference operator*() const {
assert( m_origin_idx < m_origin->m_elements.size() &&
"Attempted to deref invalid position" );
m_origin->m_derefed[m_origin_idx] = true;
return m_origin->m_elements[m_origin_idx];
}
pointer operator->() const {
assert( m_origin_idx < m_origin->m_elements.size() &&
"Attempted to deref invalid position" );
return &m_origin->m_elements[m_origin_idx];
}
};
using iterator = basic_iterator<false>;
using const_iterator = basic_iterator<true>;
with_mocked_iterator_access( std::initializer_list<T> init ):
m_elements( init ),
m_derefed( std::make_unique<bool[]>( m_elements.size() ) ) {}
const_iterator begin() const { return { this, 0 }; }
const_iterator end() const { return { this, m_elements.size() }; }
iterator begin() { return { this, 0 }; }
iterator end() { return { this, m_elements.size() }; }
};
namespace Catch {
// make sure with_mocked_iterator_access is not considered a range by Catch,
// so that below StringMaker is used instead of the default one for ranges
template <typename T>
struct is_range<with_mocked_iterator_access<T>> : std::false_type {};
template <typename T>
struct StringMaker<with_mocked_iterator_access<T>> {
static std::string
convert( with_mocked_iterator_access<T> const& access ) {
// We have to avoid the type's iterators, because we check
// their use in tests
return ::Catch::Detail::stringify( access.m_elements );
}
};
} // namespace Catch
#endif // CATCH_TEST_HELPERS_RANGE_TEST_HELPERS_HPP_INCLUDED

View File

@@ -9,6 +9,7 @@
# Please keep these ordered alphabetically
self_test_sources = files(
'SelfTest/helpers/parse_test_spec.cpp',
'SelfTest/IntrospectiveTests/Algorithms.tests.cpp',
'SelfTest/IntrospectiveTests/Clara.tests.cpp',
'SelfTest/IntrospectiveTests/CmdLine.tests.cpp',
'SelfTest/IntrospectiveTests/CmdLineHelpers.tests.cpp',

View File

@@ -6,7 +6,7 @@ rem 1. Regenerate the amalgamated distribution
python tools\scripts\generateAmalgamatedFiles.py
rem 2. Configure the full test build
cmake -Bdebug-build -H. -DCMAKE_BUILD_TYPE=Debug -DCATCH_DEVELOPMENT_BUILD=ON -DCATCH_BUILD_EXAMPLES=ON -DCATCH_BUILD_EXTRA_TESTS=ON -DCATCH_ENABLE_CONFIGURE_TESTS=ON
cmake -B debug-build -S . -DCMAKE_BUILD_TYPE=Debug --preset all-tests
rem 3. Run the actual build
cmake --build debug-build

View File

@@ -8,7 +8,7 @@
./tools/scripts/generateAmalgamatedFiles.py
# 2. Configure the full test build
cmake -Bdebug-build -H. -DCMAKE_BUILD_TYPE=Debug -DCATCH_DEVELOPMENT_BUILD=ON -DCATCH_BUILD_EXAMPLES=ON -DCATCH_BUILD_EXTRA_TESTS=ON -DCATCH_ENABLE_CONFIGURE_TESTS=ON
cmake -B debug-build -S . -DCMAKE_BUILD_TYPE=Debug --preset all-tests
# 3. Run the actual build
cmake --build debug-build