mirror of
https://github.com/catchorg/Catch2.git
synced 2025-09-13 00:45:39 +02:00
Compare commits
45 Commits
Author | SHA1 | Date | |
---|---|---|---|
![]() |
e1c9d5569d | ||
![]() |
d512decaac | ||
![]() |
f23f96883a | ||
![]() |
d7b8c3ace3 | ||
![]() |
32733e08c0 | ||
![]() |
930f49a641 | ||
![]() |
c409dccee5 | ||
![]() |
95bfb33167 | ||
![]() |
59d2d08c0f | ||
![]() |
fa6d52e2a3 | ||
![]() |
5ac348cd6e | ||
![]() |
776a4686c7 | ||
![]() |
3136c4fb6a | ||
![]() |
74e0e737a6 | ||
![]() |
0685216175 | ||
![]() |
fc320f6b8f | ||
![]() |
5290d4bedc | ||
![]() |
7ada02e21e | ||
![]() |
849f2848bd | ||
![]() |
2fbd66c51c | ||
![]() |
51b29ced1a | ||
![]() |
9a558171d8 | ||
![]() |
c5c688820c | ||
![]() |
6a08225863 | ||
![]() |
4327baba40 | ||
![]() |
50cc14c94c | ||
![]() |
87b745da66 | ||
![]() |
7d0b205564 | ||
![]() |
8fb1219013 | ||
![]() |
23c80bcc92 | ||
![]() |
a2c8dce85c | ||
![]() |
1e379de9d7 | ||
![]() |
4eea438b73 | ||
![]() |
407ee0af2f | ||
![]() |
060a41ec7b | ||
![]() |
90825a4f7a | ||
![]() |
9e8ae7d470 | ||
![]() |
84856844e1 | ||
![]() |
01ef7076f5 | ||
![]() |
ae14a47360 | ||
![]() |
f2b23db6d1 | ||
![]() |
1aa98c76ac | ||
![]() |
3195c242c2 | ||
![]() |
31906d83ec | ||
![]() |
91fa55303b |
@@ -6,12 +6,16 @@ if(NOT DEFINED PROJECT_NAME)
|
||||
set(NOT_SUBPROJECT ON)
|
||||
endif()
|
||||
|
||||
project(Catch2 LANGUAGES CXX VERSION 2.10.0)
|
||||
|
||||
if (CMAKE_BINARY_DIR STREQUAL CMAKE_SOURCE_DIR)
|
||||
# Catch2's build breaks if done in-tree. You probably should not build
|
||||
# things in tree anyway, but we can allow projects that include Catch2
|
||||
# as a subproject to build in-tree as long as it is not in our tree.
|
||||
if (CMAKE_BINARY_DIR STREQUAL CMAKE_CURRENT_SOURCE_DIR)
|
||||
message(FATAL_ERROR "Building in-source is not supported! Create a build dir and remove ${CMAKE_SOURCE_DIR}/CMakeCache.txt")
|
||||
endif()
|
||||
|
||||
|
||||
project(Catch2 LANGUAGES CXX VERSION 2.11.0)
|
||||
|
||||
# Provide path for scripts
|
||||
list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_LIST_DIR}/CMake")
|
||||
|
||||
|
@@ -5,11 +5,11 @@
|
||||
[](https://travis-ci.org/catchorg/Catch2)
|
||||
[](https://ci.appveyor.com/project/catchorg/catch2)
|
||||
[](https://codecov.io/gh/catchorg/Catch2)
|
||||
[](https://wandbox.org/permlink/00GdTUbFWaV3bNah)
|
||||
[](https://wandbox.org/permlink/HU1MkiBgFetFQJU4)
|
||||
[](https://discord.gg/4CWS9zD)
|
||||
|
||||
|
||||
<a href="https://github.com/catchorg/Catch2/releases/download/v2.10.0/catch.hpp">The latest version of the single header can be downloaded directly using this link</a>
|
||||
<a href="https://github.com/catchorg/Catch2/releases/download/v2.11.0/catch.hpp">The latest version of the single header can be downloaded directly using this link</a>
|
||||
|
||||
## Catch2 is released!
|
||||
|
||||
|
@@ -1,6 +1,11 @@
|
||||
# version string format -- This will be overwritten later anyway
|
||||
version: "{build}"
|
||||
|
||||
# We need a more up to date pip because Python 2.7 is EOL soon
|
||||
init:
|
||||
- set PATH=C:\Python35\Scripts;%PATH%
|
||||
|
||||
|
||||
branches:
|
||||
except:
|
||||
- /dev-travis.+/
|
||||
@@ -62,7 +67,7 @@ matrix:
|
||||
|
||||
|
||||
install:
|
||||
- ps: if (($env:CONFIGURATION) -eq "Debug" -And ($env:coverage) -eq "1" ) { python -m pip --disable-pip-version-check install codecov }
|
||||
- ps: if (($env:CONFIGURATION) -eq "Debug" -And ($env:coverage) -eq "1" ) { pip --disable-pip-version-check install codecov }
|
||||
- ps: if (($env:CONFIGURATION) -eq "Debug" -And ($env:coverage) -eq "1" ) { .\misc\installOpenCppCoverage.ps1 }
|
||||
|
||||
# Win32 and x64 are CMake-compatible solution platform names.
|
||||
|
@@ -14,6 +14,7 @@ coverage:
|
||||
- "**/catch_reporter_tap.hpp"
|
||||
- "**/catch_reporter_automake.hpp"
|
||||
- "**/catch_reporter_teamcity.hpp"
|
||||
- "**/catch_reporter_sonarqube.hpp"
|
||||
- "**/external/clara.hpp"
|
||||
|
||||
|
||||
|
@@ -12,7 +12,7 @@ Build Systems may refer to low-level tools, like CMake, or larger systems that r
|
||||
|
||||
## Continuous Integration systems
|
||||
|
||||
Probably the most important aspect to using Catch with a build server is the use of different reporters. Catch comes bundled with three reporters that should cover the majority of build servers out there - although adding more for better integration with some is always a possibility (currently we also offer TeamCity, TAP and Automake reporters).
|
||||
Probably the most important aspect to using Catch with a build server is the use of different reporters. Catch comes bundled with three reporters that should cover the majority of build servers out there - although adding more for better integration with some is always a possibility (currently we also offer TeamCity, TAP, Automake and SonarQube reporters).
|
||||
|
||||
Two of these reporters are built in (XML and JUnit) and the third (TeamCity) is included as a separate header. It's possible that the other two may be split out in the future too - as that would make the core of Catch smaller for those that don't need them.
|
||||
|
||||
@@ -65,6 +65,10 @@ The Automake Reporter writes out the [meta tags](https://www.gnu.org/software/au
|
||||
|
||||
Because of the incremental nature of Catch's test suites and ability to run specific tests, our implementation of TAP reporter writes out the number of tests in a suite last.
|
||||
|
||||
### SonarQube Reporter
|
||||
```-r sonarqube```
|
||||
[SonarQube Generic Test Data](https://docs.sonarqube.org/latest/analysis/generic-test/) XML format for tests metrics.
|
||||
|
||||
## Low-level tools
|
||||
|
||||
### Precompiled headers (PCHs)
|
||||
|
@@ -99,6 +99,7 @@ exclude:notThis Matches all tests except, 'notThis'
|
||||
~*private* Matches all tests except those that contain 'private'
|
||||
a* ~ab* abc Matches all tests that start with 'a', except those that
|
||||
start with 'ab', except 'abc', which is included
|
||||
-# [#somefile] Matches all tests from the file 'somefile.cpp'
|
||||
</pre>
|
||||
|
||||
Names within square brackets are interpreted as tags.
|
||||
|
@@ -70,6 +70,10 @@ locally takes just a few minutes.
|
||||
$ cd debug-build
|
||||
$ ctest -j 2 --output-on-failure
|
||||
```
|
||||
__Note:__ When running your tests with multi-configuration generators like
|
||||
Visual Studio, you might get errors "Test not available without configuration."
|
||||
You then have to pick one configuration (e.g. ` -C Debug`) in the `ctest` call.
|
||||
|
||||
If you added new tests, approval tests are very likely to fail. If they
|
||||
do not, it means that your changes weren't run as part of them. This
|
||||
_might_ be intentional, but usually is not.
|
||||
|
@@ -93,6 +93,17 @@ positively match a testspec.
|
||||
The API for Catch2's console colour will be changed to take an extra
|
||||
argument, the stream to which the colour code should be applied.
|
||||
|
||||
|
||||
### Type erasure in the `PredicateMatcher`
|
||||
|
||||
Currently, the `PredicateMatcher` uses `std::function` for type erasure,
|
||||
so that type of the matcher is always `PredicateMatcher<T>`, regardless
|
||||
of the type of the predicate. Because of the high compilation overhead
|
||||
of `std::function`, and the fact that the type erasure is used only rarely,
|
||||
`PredicateMatcher` will no longer be type erased in the future. Instead,
|
||||
the predicate type will be made part of the PredicateMatcher's type.
|
||||
|
||||
|
||||
---
|
||||
|
||||
[Home](Readme.md#top)
|
||||
|
@@ -49,7 +49,7 @@ a test case,
|
||||
* 4 specific purpose generators
|
||||
* `RandomIntegerGenerator<Integral>` -- generates random Integrals from range
|
||||
* `RandomFloatGenerator<Float>` -- generates random Floats from range
|
||||
* `RangeGenerator<T>` -- generates all values inside a specific range
|
||||
* `RangeGenerator<T>` -- generates all values inside an arithmetic range
|
||||
* `IteratorGenerator<T>` -- copies and returns values from an iterator range
|
||||
|
||||
> `ChunkGenerator<T>`, `RandomIntegerGenerator<Integral>`, `RandomFloatGenerator<Float>` and `RangeGenerator<T>` were introduced in Catch 2.7.0.
|
||||
@@ -69,8 +69,8 @@ type, making their usage much nicer. These are
|
||||
* `map<T>(func, GeneratorWrapper<U>&&)` for `MapGenerator<T, U, Func>` (map `U` to `T`)
|
||||
* `chunk(chunk-size, GeneratorWrapper<T>&&)` for `ChunkGenerator<T>`
|
||||
* `random(IntegerOrFloat a, IntegerOrFloat b)` for `RandomIntegerGenerator` or `RandomFloatGenerator`
|
||||
* `range(start, end)` for `RangeGenerator<T>` with a step size of `1`
|
||||
* `range(start, end, step)` for `RangeGenerator<T>` with a custom step size
|
||||
* `range(Arithemtic start, Arithmetic end)` for `RangeGenerator<Arithmetic>` with a step size of `1`
|
||||
* `range(Arithmetic start, Arithmetic end, Arithmetic step)` for `RangeGenerator<Arithmetic>` with a custom step size
|
||||
* `from_range(InputIterator from, InputIterator to)` for `IteratorGenerator<T>`
|
||||
* `from_range(Container const&)` for `IteratorGenerator<T>`
|
||||
|
||||
@@ -78,6 +78,8 @@ type, making their usage much nicer. These are
|
||||
|
||||
> `from_range` has been introduced in Catch 2.10.0
|
||||
|
||||
> `range()` for floating point numbers has been introduced in Catch 2.11.0
|
||||
|
||||
And can be used as shown in the example below to create a generator
|
||||
that returns 100 odd random number:
|
||||
|
||||
|
@@ -45,6 +45,15 @@ the `REQUIRE` family of macros), Catch2 does not know that there are no
|
||||
more sections in that test case and must run the test case again.
|
||||
|
||||
|
||||
### MinGW/CygWin compilation (linking) is extremely slow
|
||||
|
||||
Compiling Catch2 with MinGW can be exceedingly slow, especially during
|
||||
the linking step. As far as we can tell, this is caused by deficiencies
|
||||
in its default linker. If you can tell MinGW to instead use lld, via
|
||||
`-fuse-ld=lld`, the link time should drop down to reasonable length
|
||||
again.
|
||||
|
||||
|
||||
## Features
|
||||
This section outlines some missing features, what is their status and their possible workarounds.
|
||||
|
||||
|
@@ -17,7 +17,7 @@ For example, to assert that a string ends with a certain substring:
|
||||
using Catch::Matchers::EndsWith; // or Catch::EndsWith
|
||||
std::string str = getStringFromSomewhere();
|
||||
REQUIRE_THAT( str, EndsWith( "as a service" ) );
|
||||
```
|
||||
```
|
||||
|
||||
The matcher objects can take multiple arguments, allowing more fine tuning.
|
||||
The built-in string matchers, for example, take a second argument specifying whether the comparison is
|
||||
@@ -35,6 +35,22 @@ REQUIRE_THAT( str,
|
||||
(StartsWith( "Big data" ) && !Contains( "web scale" ) ) );
|
||||
```
|
||||
|
||||
_The combining operators do not take ownership of the matcher objects.
|
||||
This means that if you store the combined object, you have to ensure that
|
||||
the matcher objects outlive its last use. What this means is that code
|
||||
like this leads to a use-after-free and (hopefully) a crash:_
|
||||
|
||||
```cpp
|
||||
TEST_CASE("Bugs, bugs, bugs", "[Bug]"){
|
||||
std::string str = "Bugs as a service";
|
||||
|
||||
auto match_expression = Catch::EndsWith( "as a service" ) ||
|
||||
(Catch::StartsWith( "Big data" ) && !Catch::Contains( "web scale" ) );
|
||||
REQUIRE_THAT(str, match_expression);
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
## Built in matchers
|
||||
Catch2 provides some matchers by default. They can be found in the
|
||||
`Catch::Matchers::foo` namespace and are imported into the `Catch`
|
||||
|
@@ -53,9 +53,6 @@ Open source Oracle Tuxedo-like XATMI middleware for C and C++.
|
||||
### [Inja](https://github.com/pantor/inja)
|
||||
A header-only template engine for modern C++.
|
||||
|
||||
### [JSON for Modern C++](https://github.com/nlohmann/json)
|
||||
A, single-header, JSON parsing library that takes advantage of what C++ has to offer.
|
||||
|
||||
### [libcluon](https://github.com/chrberger/libcluon)
|
||||
A single-header-only library written in C++14 to glue distributed software components (UDP, TCP, shared memory) supporting natively Protobuf, LCM/ZCM, MsgPack, and JSON for dynamic message transformations in-between.
|
||||
|
||||
|
@@ -2,6 +2,9 @@
|
||||
|
||||
# Release notes
|
||||
**Contents**<br>
|
||||
[2.11.0](#2110)<br>
|
||||
[2.10.2](#2102)<br>
|
||||
[2.10.1](#2101)<br>
|
||||
[2.10.0](#2100)<br>
|
||||
[2.9.2](#292)<br>
|
||||
[2.9.1](#291)<br>
|
||||
@@ -29,6 +32,51 @@
|
||||
[Even Older versions](#even-older-versions)<br>
|
||||
|
||||
|
||||
## 2.11.0
|
||||
|
||||
### Improvements
|
||||
* JUnit reporter output now contains more details in case of failure (#1347, #1719)
|
||||
* Added SonarQube Test Data reporter (#1738)
|
||||
* It is in a separate header, just like the TAP, Automake, and TeamCity reporters
|
||||
* `range` generator now allows floating point numbers (#1776)
|
||||
* Reworked part of internals to increase throughput
|
||||
|
||||
|
||||
### Fixes
|
||||
* The single header version should contain full benchmarking support (#1800)
|
||||
* `[.foo]` is now properly parsed as `[.][foo]` when used on the command line (#1798)
|
||||
* Fixed compilation of benchmarking on platforms where `steady_clock::period` is not `std::nano` (#1794)
|
||||
|
||||
|
||||
|
||||
## 2.10.2
|
||||
|
||||
### Improvements
|
||||
* Catch2 will now compile on platform where `INFINITY` is double (#1782)
|
||||
|
||||
|
||||
### Fixes
|
||||
* Warning suppressed during listener registration will no longer leak
|
||||
|
||||
|
||||
|
||||
## 2.10.1
|
||||
|
||||
### Improvements
|
||||
* Catch2 now guards itself against `min` and `max` macros from `windows.h` (#1772)
|
||||
* Templated tests will now compile with ICC (#1748)
|
||||
* `WithinULP` matcher now uses scientific notation for stringification (#1760)
|
||||
|
||||
|
||||
### Fixes
|
||||
* Templated tests no longer trigger `-Wunused-templates` (#1762)
|
||||
* Suppressed clang-analyzer false positive in context getter (#1230, #1735)
|
||||
|
||||
|
||||
### Miscellaneous
|
||||
* CMake no longer prohibits in-tree build when Catch2 is used as a subproject (#1773, #1774)
|
||||
|
||||
|
||||
|
||||
## 2.10.0
|
||||
|
||||
|
@@ -42,8 +42,8 @@ Tag version and release title should be same as the new version,
|
||||
description should contain the release notes for the current release.
|
||||
Single header version of `catch.hpp` *needs* to be attached as a binary,
|
||||
as that is where the official download link links to. Preferably
|
||||
it should use linux line endings. All non-bundled reporters (Automake,
|
||||
TAP, TeamCity) should also be attached as binaries, as they might be
|
||||
it should use linux line endings. All non-bundled reporters (Automake, TAP,
|
||||
TeamCity, SonarQube) should also be attached as binaries, as they might be
|
||||
dependent on a specific version of the single-include header.
|
||||
|
||||
Since 2.5.0, the release tag and the "binaries" (headers) should be PGP
|
||||
@@ -67,6 +67,7 @@ $ gpg2 --armor --output catch.hpp.asc --detach-sig catch.hpp
|
||||
$ gpg2 --armor --output catch_reporter_automake.hpp.asc --detach-sig catch_reporter_automake.hpp
|
||||
$ gpg2 --armor --output catch_reporter_teamcity.hpp.asc --detach-sig catch_reporter_teamcity.hpp
|
||||
$ gpg2 --armor --output catch_reporter_tap.hpp.asc --detach-sig catch_reporter_tap.hpp
|
||||
$ gpg2 --armor --output catch_reporter_sonarqube.hpp.asc --detach-sig catch_reporter_sonarqube.hpp
|
||||
```
|
||||
|
||||
_GPG does not support signing multiple files in single invocation._
|
||||
|
@@ -29,6 +29,7 @@ Do this in one source file - the same one you have `CATCH_CONFIG_MAIN` or `CATCH
|
||||
Use this when building as part of a TeamCity build to see results as they happen ([code example](../examples/207-Rpt-TeamCityReporter.cpp)).
|
||||
* `tap` writes in the TAP ([Test Anything Protocol](https://en.wikipedia.org/wiki/Test_Anything_Protocol)) format.
|
||||
* `automake` writes in a format that correspond to [automake .trs](https://www.gnu.org/software/automake/manual/html_node/Log-files-generation-and-test-results-recording.html) files
|
||||
* `sonarqube` writes the [SonarQube Generic Test Data](https://docs.sonarqube.org/latest/analysis/generic-test/) XML format.
|
||||
|
||||
You see what reporters are available from the command line by running with `--list-reporters`.
|
||||
|
||||
|
@@ -10,11 +10,12 @@
|
||||
#define CATCH_CONFIG_MAIN
|
||||
#include <catch2/catch.hpp>
|
||||
|
||||
|
||||
class out_buff : public std::stringbuf {
|
||||
std::FILE* m_stream;
|
||||
public:
|
||||
out_buff(std::FILE* stream) :m_stream(stream) {}
|
||||
~out_buff() { pubsync(); }
|
||||
out_buff(std::FILE* stream):m_stream(stream) {}
|
||||
~out_buff();
|
||||
int sync() {
|
||||
int ret = 0;
|
||||
for (unsigned char c : str()) {
|
||||
@@ -29,6 +30,12 @@ public:
|
||||
}
|
||||
};
|
||||
|
||||
out_buff::~out_buff() { pubsync(); }
|
||||
|
||||
#if defined(__clang__)
|
||||
#pragma clang diagnostic ignored "-Wexit-time-destructors" // static variables in cout/cerr/clog
|
||||
#endif
|
||||
|
||||
namespace Catch {
|
||||
std::ostream& cout() {
|
||||
static std::ostream ret(new out_buff(stdout));
|
||||
|
@@ -22,15 +22,17 @@ public:
|
||||
}
|
||||
}
|
||||
|
||||
std::string const& get() const override {
|
||||
return m_line;
|
||||
}
|
||||
std::string const& get() const override;
|
||||
|
||||
bool next() override {
|
||||
return !!std::getline(m_stream, m_line);
|
||||
}
|
||||
};
|
||||
|
||||
std::string const& LineGenerator::get() const {
|
||||
return m_line;
|
||||
}
|
||||
|
||||
// This helper function provides a nicer UX when instantiating the generator
|
||||
// Notice that it returns an instance of GeneratorWrapper<std::string>, which
|
||||
// is a value-wrapper around std::unique_ptr<IGenerator<std::string>>.
|
||||
|
@@ -10,7 +10,7 @@
|
||||
#define TWOBLUECUBES_CATCH_HPP_INCLUDED
|
||||
|
||||
#define CATCH_VERSION_MAJOR 2
|
||||
#define CATCH_VERSION_MINOR 10
|
||||
#define CATCH_VERSION_MINOR 11
|
||||
#define CATCH_VERSION_PATCH 0
|
||||
|
||||
#ifdef __clang__
|
||||
@@ -80,7 +80,7 @@
|
||||
#endif
|
||||
|
||||
#if defined(CATCH_CONFIG_ENABLE_BENCHMARKING)
|
||||
#include "internal/benchmark/catch_benchmark.hpp"
|
||||
#include "internal/benchmark/catch_benchmarking_all.hpp"
|
||||
#endif
|
||||
|
||||
#endif // ! CATCH_CONFIG_IMPL_ONLY
|
||||
|
@@ -79,7 +79,7 @@ namespace Catch {
|
||||
});
|
||||
|
||||
auto analysis = Detail::analyse(*cfg, env, samples.begin(), samples.end());
|
||||
BenchmarkStats<std::chrono::duration<double, std::nano>> stats{ info, analysis.samples, analysis.mean, analysis.standard_deviation, analysis.outliers, analysis.outlier_variance };
|
||||
BenchmarkStats<FloatDuration<Clock>> stats{ info, analysis.samples, analysis.mean, analysis.standard_deviation, analysis.outliers, analysis.outlier_variance };
|
||||
getResultCapture().benchmarkEnded(stats);
|
||||
|
||||
} CATCH_CATCH_ALL{
|
||||
|
29
include/internal/benchmark/catch_benchmarking_all.hpp
Normal file
29
include/internal/benchmark/catch_benchmarking_all.hpp
Normal file
@@ -0,0 +1,29 @@
|
||||
/*
|
||||
* Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
* file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
*/
|
||||
|
||||
|
||||
// A proxy header that includes all of the benchmarking headers to allow
|
||||
// concise include of the benchmarking features. You should prefer the
|
||||
// individual includes in standard use.
|
||||
|
||||
#include "catch_benchmark.hpp"
|
||||
#include "catch_chronometer.hpp"
|
||||
#include "catch_clock.hpp"
|
||||
#include "catch_constructor.hpp"
|
||||
#include "catch_environment.hpp"
|
||||
#include "catch_estimate.hpp"
|
||||
#include "catch_execution_plan.hpp"
|
||||
#include "catch_optimizer.hpp"
|
||||
#include "catch_outlier_classification.hpp"
|
||||
#include "catch_sample_analysis.hpp"
|
||||
#include "detail/catch_analyse.hpp"
|
||||
#include "detail/catch_benchmark_function.hpp"
|
||||
#include "detail/catch_complete_invoke.hpp"
|
||||
#include "detail/catch_estimate_clock.hpp"
|
||||
#include "detail/catch_measure.hpp"
|
||||
#include "detail/catch_repeat.hpp"
|
||||
#include "detail/catch_run_for_at_least.hpp"
|
||||
#include "detail/catch_stats.hpp"
|
||||
#include "detail/catch_timing.hpp"
|
@@ -176,9 +176,10 @@ namespace Catch {
|
||||
|
||||
|
||||
bootstrap_analysis analyse_samples(double confidence_level, int n_resamples, std::vector<double>::iterator first, std::vector<double>::iterator last) {
|
||||
CATCH_INTERNAL_START_WARNINGS_SUPPRESSION
|
||||
CATCH_INTERNAL_SUPPRESS_GLOBALS_WARNINGS
|
||||
static std::random_device entropy;
|
||||
CATCH_INTERNAL_UNSUPPRESS_GLOBALS_WARNINGS
|
||||
CATCH_INTERNAL_STOP_WARNINGS_SUPPRESSION
|
||||
|
||||
auto n = static_cast<int>(last - first); // seriously, one can't use integral types without hell in C++
|
||||
|
||||
|
@@ -43,9 +43,10 @@
|
||||
do { \
|
||||
Catch::AssertionHandler catchAssertionHandler( macroName##_catch_sr, CATCH_INTERNAL_LINEINFO, CATCH_INTERNAL_STRINGIFY(__VA_ARGS__), resultDisposition ); \
|
||||
INTERNAL_CATCH_TRY { \
|
||||
CATCH_INTERNAL_START_WARNINGS_SUPPRESSION \
|
||||
CATCH_INTERNAL_SUPPRESS_PARENTHESES_WARNINGS \
|
||||
catchAssertionHandler.handleExpr( Catch::Decomposer() <= __VA_ARGS__ ); \
|
||||
CATCH_INTERNAL_UNSUPPRESS_PARENTHESES_WARNINGS \
|
||||
CATCH_INTERNAL_STOP_WARNINGS_SUPPRESSION \
|
||||
} INTERNAL_CATCH_CATCH( catchAssertionHandler ) \
|
||||
INTERNAL_CATCH_REACT( catchAssertionHandler ) \
|
||||
} while( (void)0, (false) && static_cast<bool>( !!(__VA_ARGS__) ) ) // the expression here is never evaluated at runtime but it forces the compiler to give it a look
|
||||
|
@@ -49,9 +49,15 @@ namespace Catch {
|
||||
if( !line.empty() && !startsWith( line, '#' ) ) {
|
||||
if( !startsWith( line, '"' ) )
|
||||
line = '"' + line + '"';
|
||||
config.testsOrTags.push_back( line + ',' );
|
||||
config.testsOrTags.push_back( line );
|
||||
config.testsOrTags.push_back( "," );
|
||||
|
||||
}
|
||||
}
|
||||
//Remove comma in the end
|
||||
if(!config.testsOrTags.empty())
|
||||
config.testsOrTags.erase( config.testsOrTags.end()-1 );
|
||||
|
||||
return ParserResult::ok( ParseResultType::Matched );
|
||||
};
|
||||
auto const setTestOrder = [&]( std::string const& order ) {
|
||||
|
@@ -43,32 +43,33 @@
|
||||
# define CATCH_INTERNAL_CONFIG_CPP17_UNCAUGHT_EXCEPTIONS
|
||||
#endif
|
||||
|
||||
#ifdef __clang__
|
||||
// We have to avoid both ICC and Clang, because they try to mask themselves
|
||||
// as gcc, and we want only GCC in this block
|
||||
#if defined(__GNUC__) && !defined(__clang__) && !defined(__ICC)
|
||||
# define CATCH_INTERNAL_START_WARNINGS_SUPPRESSION _Pragma( "GCC diagnostic push" )
|
||||
# define CATCH_INTERNAL_STOP_WARNINGS_SUPPRESSION _Pragma( "GCC diagnostic pop" )
|
||||
#endif
|
||||
|
||||
# define CATCH_INTERNAL_SUPPRESS_GLOBALS_WARNINGS \
|
||||
_Pragma( "clang diagnostic push" ) \
|
||||
_Pragma( "clang diagnostic ignored \"-Wexit-time-destructors\"" ) \
|
||||
_Pragma( "clang diagnostic ignored \"-Wglobal-constructors\"")
|
||||
# define CATCH_INTERNAL_UNSUPPRESS_GLOBALS_WARNINGS \
|
||||
_Pragma( "clang diagnostic pop" )
|
||||
#if defined(__clang__)
|
||||
|
||||
# define CATCH_INTERNAL_SUPPRESS_PARENTHESES_WARNINGS \
|
||||
_Pragma( "clang diagnostic push" ) \
|
||||
_Pragma( "clang diagnostic ignored \"-Wparentheses\"" )
|
||||
# define CATCH_INTERNAL_UNSUPPRESS_PARENTHESES_WARNINGS \
|
||||
_Pragma( "clang diagnostic pop" )
|
||||
# define CATCH_INTERNAL_START_WARNINGS_SUPPRESSION _Pragma( "clang diagnostic push" )
|
||||
# define CATCH_INTERNAL_STOP_WARNINGS_SUPPRESSION _Pragma( "clang diagnostic pop" )
|
||||
|
||||
# define CATCH_INTERNAL_SUPPRESS_UNUSED_WARNINGS \
|
||||
_Pragma( "clang diagnostic push" ) \
|
||||
_Pragma( "clang diagnostic ignored \"-Wunused-variable\"" )
|
||||
# define CATCH_INTERNAL_UNSUPPRESS_UNUSED_WARNINGS \
|
||||
_Pragma( "clang diagnostic pop" )
|
||||
# define CATCH_INTERNAL_SUPPRESS_GLOBALS_WARNINGS \
|
||||
_Pragma( "clang diagnostic ignored \"-Wexit-time-destructors\"" ) \
|
||||
_Pragma( "clang diagnostic ignored \"-Wglobal-constructors\"")
|
||||
|
||||
# define CATCH_INTERNAL_SUPPRESS_ZERO_VARIADIC_WARNINGS \
|
||||
_Pragma( "clang diagnostic push" ) \
|
||||
_Pragma( "clang diagnostic ignored \"-Wgnu-zero-variadic-macro-arguments\"" )
|
||||
# define CATCH_INTERNAL_UNSUPPRESS_ZERO_VARIADIC_WARNINGS \
|
||||
_Pragma( "clang diagnostic pop" )
|
||||
# define CATCH_INTERNAL_SUPPRESS_PARENTHESES_WARNINGS \
|
||||
_Pragma( "clang diagnostic ignored \"-Wparentheses\"" )
|
||||
|
||||
# define CATCH_INTERNAL_SUPPRESS_UNUSED_WARNINGS \
|
||||
_Pragma( "clang diagnostic ignored \"-Wunused-variable\"" )
|
||||
|
||||
# define CATCH_INTERNAL_SUPPRESS_ZERO_VARIADIC_WARNINGS \
|
||||
_Pragma( "clang diagnostic ignored \"-Wgnu-zero-variadic-macro-arguments\"" )
|
||||
|
||||
# define CATCH_INTERNAL_SUPPRESS_UNUSED_TEMPLATE_WARNINGS \
|
||||
_Pragma( "clang diagnostic ignored \"-Wunused-template\"" )
|
||||
|
||||
#endif // __clang__
|
||||
|
||||
@@ -128,8 +129,10 @@
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// Visual C++
|
||||
#ifdef _MSC_VER
|
||||
#if defined(_MSC_VER)
|
||||
|
||||
# define CATCH_INTERNAL_START_WARNINGS_SUPPRESSION __pragma( warning(push) )
|
||||
# define CATCH_INTERNAL_STOP_WARNINGS_SUPPRESSION __pragma( warning(pop) )
|
||||
|
||||
# if _MSC_VER >= 1900 // Visual Studio 2015 or newer
|
||||
# define CATCH_INTERNAL_CONFIG_CPP17_UNCAUGHT_EXCEPTIONS
|
||||
@@ -304,21 +307,37 @@
|
||||
# define CATCH_CONFIG_GLOBAL_NEXTAFTER
|
||||
#endif
|
||||
|
||||
|
||||
// Even if we do not think the compiler has that warning, we still have
|
||||
// to provide a macro that can be used by the code.
|
||||
#if !defined(CATCH_INTERNAL_START_WARNINGS_SUPPRESSION)
|
||||
# define CATCH_INTERNAL_START_WARNINGS_SUPPRESSION
|
||||
#endif
|
||||
#if !defined(CATCH_INTERNAL_STOP_WARNINGS_SUPPRESSION)
|
||||
# define CATCH_INTERNAL_STOP_WARNINGS_SUPPRESSION
|
||||
#endif
|
||||
#if !defined(CATCH_INTERNAL_SUPPRESS_PARENTHESES_WARNINGS)
|
||||
# define CATCH_INTERNAL_SUPPRESS_PARENTHESES_WARNINGS
|
||||
# define CATCH_INTERNAL_UNSUPPRESS_PARENTHESES_WARNINGS
|
||||
#endif
|
||||
#if !defined(CATCH_INTERNAL_SUPPRESS_GLOBALS_WARNINGS)
|
||||
# define CATCH_INTERNAL_SUPPRESS_GLOBALS_WARNINGS
|
||||
# define CATCH_INTERNAL_UNSUPPRESS_GLOBALS_WARNINGS
|
||||
#endif
|
||||
#if !defined(CATCH_INTERNAL_SUPPRESS_UNUSED_WARNINGS)
|
||||
# define CATCH_INTERNAL_SUPPRESS_UNUSED_WARNINGS
|
||||
# define CATCH_INTERNAL_UNSUPPRESS_UNUSED_WARNINGS
|
||||
#endif
|
||||
#if !defined(CATCH_INTERNAL_SUPPRESS_ZERO_VARIADIC_WARNINGS)
|
||||
# define CATCH_INTERNAL_SUPPRESS_ZERO_VARIADIC_WARNINGS
|
||||
# define CATCH_INTERNAL_UNSUPPRESS_ZERO_VARIADIC_WARNINGS
|
||||
#endif
|
||||
|
||||
|
||||
#if defined(__APPLE__) && defined(__apple_build_version__) && (__clang_major__ < 10)
|
||||
# undef CATCH_INTERNAL_SUPPRESS_UNUSED_TEMPLATE_WARNINGS
|
||||
#elif defined(__clang__) && (__clang_major__ < 5)
|
||||
# undef CATCH_INTERNAL_SUPPRESS_UNUSED_TEMPLATE_WARNINGS
|
||||
#endif
|
||||
|
||||
#if !defined(CATCH_INTERNAL_SUPPRESS_UNUSED_TEMPLATE_WARNINGS)
|
||||
# define CATCH_INTERNAL_SUPPRESS_UNUSED_TEMPLATE_WARNINGS
|
||||
#endif
|
||||
|
||||
#if defined(CATCH_CONFIG_DISABLE_EXCEPTIONS)
|
||||
|
@@ -46,6 +46,7 @@ namespace Catch {
|
||||
{
|
||||
if( !IMutableContext::currentContext )
|
||||
IMutableContext::createContext();
|
||||
// NOLINTNEXTLINE(clang-analyzer-core.uninitialized.UndefReturn)
|
||||
return *IMutableContext::currentContext;
|
||||
}
|
||||
|
||||
|
@@ -8,6 +8,7 @@
|
||||
#define TWOBLUECUBES_CATCH_GENERATORS_GENERIC_HPP_INCLUDED
|
||||
|
||||
#include "catch_generators.hpp"
|
||||
#include "catch_meta.hpp"
|
||||
|
||||
namespace Catch {
|
||||
namespace Generators {
|
||||
@@ -172,18 +173,7 @@ namespace Generators {
|
||||
}
|
||||
};
|
||||
|
||||
#if defined(__cpp_lib_is_invocable) && __cpp_lib_is_invocable >= 201703
|
||||
// std::result_of is deprecated in C++17 and removed in C++20. Hence, it is
|
||||
// replaced with std::invoke_result here. Also *_t format is preferred over
|
||||
// typename *::type format.
|
||||
template <typename Func, typename U>
|
||||
using MapFunctionReturnType = std::remove_reference_t<std::remove_cv_t<std::invoke_result_t<Func, U>>>;
|
||||
#else
|
||||
template <typename Func, typename U>
|
||||
using MapFunctionReturnType = typename std::remove_reference<typename std::remove_cv<typename std::result_of<Func(U)>::type>::type>::type;
|
||||
#endif
|
||||
|
||||
template <typename Func, typename U, typename T = MapFunctionReturnType<Func, U>>
|
||||
template <typename Func, typename U, typename T = FunctionReturnType<Func, U>>
|
||||
GeneratorWrapper<T> map(Func&& function, GeneratorWrapper<U>&& generator) {
|
||||
return GeneratorWrapper<T>(
|
||||
pf::make_unique<MapGenerator<T, U, Func>>(std::forward<Func>(function), std::move(generator))
|
||||
|
@@ -117,7 +117,7 @@ public:
|
||||
|
||||
template <typename T>
|
||||
GeneratorWrapper<T> range(T const& start, T const& end, T const& step) {
|
||||
static_assert(std::is_integral<T>::value && !std::is_same<T, bool>::value, "Type must be an integer");
|
||||
static_assert(std::is_arithmetic<T>::value && !std::is_same<T, bool>::value, "Type must be numeric");
|
||||
return GeneratorWrapper<T>(pf::make_unique<RangeGenerator<T>>(start, end, step));
|
||||
}
|
||||
|
||||
|
@@ -73,9 +73,10 @@ namespace Catch {
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
#define INTERNAL_CATCH_TRANSLATE_EXCEPTION2( translatorName, signature ) \
|
||||
static std::string translatorName( signature ); \
|
||||
CATCH_INTERNAL_START_WARNINGS_SUPPRESSION \
|
||||
CATCH_INTERNAL_SUPPRESS_GLOBALS_WARNINGS \
|
||||
namespace{ Catch::ExceptionTranslatorRegistrar INTERNAL_CATCH_UNIQUE_NAME( catch_internal_ExceptionRegistrar )( &translatorName ); } \
|
||||
CATCH_INTERNAL_UNSUPPRESS_GLOBALS_WARNINGS \
|
||||
CATCH_INTERNAL_STOP_WARNINGS_SUPPRESSION \
|
||||
static std::string translatorName( signature )
|
||||
|
||||
#define INTERNAL_CATCH_TRANSLATE_EXCEPTION( signature ) INTERNAL_CATCH_TRANSLATE_EXCEPTION2( INTERNAL_CATCH_UNIQUE_NAME( catch_internal_ExceptionTranslator ), signature )
|
||||
|
@@ -214,6 +214,8 @@ namespace Catch {
|
||||
|
||||
virtual void noMatchingTestCases( std::string const& spec ) = 0;
|
||||
|
||||
virtual void reportInvalidArguments(std::string const&) {}
|
||||
|
||||
virtual void testRunStarting( TestRunInfo const& testRunInfo ) = 0;
|
||||
virtual void testGroupStarting( GroupInfo const& groupInfo ) = 0;
|
||||
|
||||
|
@@ -101,14 +101,17 @@ FP step(FP start, FP direction, uint64_t steps) {
|
||||
return start;
|
||||
}
|
||||
|
||||
namespace {
|
||||
|
||||
// Performs equivalent check of std::fabs(lhs - rhs) <= margin
|
||||
// But without the subtraction to allow for INFINITY in comparison
|
||||
bool marginComparison(double lhs, double rhs, double margin) {
|
||||
return (lhs + margin >= rhs) && (rhs + margin >= lhs);
|
||||
}
|
||||
// Performs equivalent check of std::fabs(lhs - rhs) <= margin
|
||||
// But without the subtraction to allow for INFINITY in comparison
|
||||
bool marginComparison(double lhs, double rhs, double margin) {
|
||||
return (lhs + margin >= rhs) && (rhs + margin >= lhs);
|
||||
}
|
||||
|
||||
template <typename FloatingPoint>
|
||||
void write(std::ostream& out, FloatingPoint num) {
|
||||
out << std::scientific
|
||||
<< std::setprecision(std::numeric_limits<FloatingPoint>::max_digits10 - 1)
|
||||
<< num;
|
||||
}
|
||||
|
||||
} // end anonymous namespace
|
||||
@@ -142,7 +145,7 @@ namespace Floating {
|
||||
WithinUlpsMatcher::WithinUlpsMatcher(double target, uint64_t ulps, FloatingPointKind baseType)
|
||||
:m_target{ target }, m_ulps{ ulps }, m_type{ baseType } {
|
||||
CATCH_ENFORCE(m_type == FloatingPointKind::Double
|
||||
|| m_ulps < std::numeric_limits<uint32_t>::max(),
|
||||
|| m_ulps < (std::numeric_limits<uint32_t>::max)(),
|
||||
"Provided ULP is impossibly large for a float comparison.");
|
||||
}
|
||||
|
||||
@@ -170,27 +173,29 @@ namespace Floating {
|
||||
std::string WithinUlpsMatcher::describe() const {
|
||||
std::stringstream ret;
|
||||
|
||||
ret << "is within " << m_ulps << " ULPs of " << ::Catch::Detail::stringify(m_target);
|
||||
ret << "is within " << m_ulps << " ULPs of ";
|
||||
|
||||
if (m_type == FloatingPointKind::Float) {
|
||||
write(ret, static_cast<float>(m_target));
|
||||
ret << 'f';
|
||||
} else {
|
||||
write(ret, m_target);
|
||||
}
|
||||
|
||||
ret << " ([";
|
||||
ret << std::fixed << std::setprecision(std::numeric_limits<double>::max_digits10);
|
||||
if (m_type == FloatingPointKind::Double) {
|
||||
ret << step(m_target, static_cast<double>(-INFINITY), m_ulps)
|
||||
<< ", "
|
||||
<< step(m_target, static_cast<double>(INFINITY), m_ulps);
|
||||
write(ret, step(m_target, static_cast<double>(-INFINITY), m_ulps));
|
||||
ret << ", ";
|
||||
write(ret, step(m_target, static_cast<double>( INFINITY), m_ulps));
|
||||
} else {
|
||||
ret << step<float>(static_cast<float>(m_target), -INFINITY, m_ulps)
|
||||
<< ", "
|
||||
<< step<float>(static_cast<float>(m_target), INFINITY, m_ulps);
|
||||
// We have to cast INFINITY to float because of MinGW, see #1782
|
||||
write(ret, step(static_cast<float>(m_target), static_cast<float>(-INFINITY), m_ulps));
|
||||
ret << ", ";
|
||||
write(ret, step(static_cast<float>(m_target), static_cast<float>( INFINITY), m_ulps));
|
||||
}
|
||||
ret << "])";
|
||||
|
||||
return ret.str();
|
||||
//return "is within " + Catch::to_string(m_ulps) + " ULPs of " + ::Catch::Detail::stringify(m_target) + ((m_type == FloatingPointKind::Float)? "f" : "");
|
||||
}
|
||||
|
||||
WithinRelMatcher::WithinRelMatcher(double target, double epsilon):
|
||||
@@ -201,7 +206,7 @@ namespace Floating {
|
||||
}
|
||||
|
||||
bool WithinRelMatcher::match(double const& matchee) const {
|
||||
const auto relMargin = m_epsilon * std::max(std::fabs(matchee), std::fabs(m_target));
|
||||
const auto relMargin = m_epsilon * (std::max)(std::fabs(matchee), std::fabs(m_target));
|
||||
return marginComparison(matchee, m_target,
|
||||
std::isinf(relMargin)? 0 : relMargin);
|
||||
}
|
||||
|
@@ -12,22 +12,34 @@
|
||||
#include <type_traits>
|
||||
|
||||
namespace Catch {
|
||||
template<typename T>
|
||||
struct always_false : std::false_type {};
|
||||
template<typename T>
|
||||
struct always_false : std::false_type {};
|
||||
|
||||
template <typename> struct true_given : std::true_type {};
|
||||
struct is_callable_tester {
|
||||
template <typename Fun, typename... Args>
|
||||
true_given<decltype(std::declval<Fun>()(std::declval<Args>()...))> static test(int);
|
||||
template <typename...>
|
||||
std::false_type static test(...);
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
struct is_callable;
|
||||
|
||||
template <typename> struct true_given : std::true_type {};
|
||||
struct is_callable_tester {
|
||||
template <typename Fun, typename... Args>
|
||||
true_given<decltype(std::declval<Fun>()(std::declval<Args>()...))> static test(int);
|
||||
template <typename...>
|
||||
std::false_type static test(...);
|
||||
};
|
||||
struct is_callable<Fun(Args...)> : decltype(is_callable_tester::test<Fun, Args...>(0)) {};
|
||||
|
||||
template <typename T>
|
||||
struct is_callable;
|
||||
|
||||
template <typename Fun, typename... Args>
|
||||
struct is_callable<Fun(Args...)> : decltype(is_callable_tester::test<Fun, Args...>(0)) {};
|
||||
#if defined(__cpp_lib_is_invocable) && __cpp_lib_is_invocable >= 201703
|
||||
// std::result_of is deprecated in C++17 and removed in C++20. Hence, it is
|
||||
// replaced with std::invoke_result here. Also *_t format is preferred over
|
||||
// typename *::type format.
|
||||
template <typename Func, typename U>
|
||||
using FunctionReturnType = std::remove_reference_t<std::remove_cv_t<std::invoke_result_t<Func, U>>>;
|
||||
#else
|
||||
template <typename Func, typename U>
|
||||
using FunctionReturnType = typename std::remove_reference<typename std::remove_cv<typename std::result_of<Func(U)>::type>::type>::type;
|
||||
#endif
|
||||
|
||||
} // namespace Catch
|
||||
|
||||
|
@@ -102,35 +102,49 @@
|
||||
template<typename...> struct TypeList {};\
|
||||
template<typename...Ts>\
|
||||
constexpr auto get_wrapper() noexcept -> TypeList<Ts...> { return {}; }\
|
||||
template<template<typename...> class...> struct TemplateTypeList{};\
|
||||
template<template<typename...> class...Cs>\
|
||||
constexpr auto get_wrapper() noexcept -> TemplateTypeList<Cs...> { return {}; }\
|
||||
template<typename...>\
|
||||
struct append;\
|
||||
template<typename...>\
|
||||
struct rewrap;\
|
||||
template<template<typename...> class, typename...>\
|
||||
struct create;\
|
||||
template<template<typename...> class, typename>\
|
||||
struct convert;\
|
||||
\
|
||||
template<template<typename...> class L1, typename...E1, template<typename...> class L2, typename...E2> \
|
||||
constexpr auto append(L1<E1...>, L2<E2...>) noexcept -> L1<E1...,E2...> { return {}; }\
|
||||
template<typename T> \
|
||||
struct append<T> { using type = T; };\
|
||||
template< template<typename...> class L1, typename...E1, template<typename...> class L2, typename...E2, typename...Rest>\
|
||||
constexpr auto append(L1<E1...>, L2<E2...>, Rest...) noexcept -> decltype(append(L1<E1...,E2...>{}, Rest{}...)) { return {}; }\
|
||||
struct append<L1<E1...>, L2<E2...>, Rest...> { using type = typename append<L1<E1...,E2...>, Rest...>::type; };\
|
||||
template< template<typename...> class L1, typename...E1, typename...Rest>\
|
||||
constexpr auto append(L1<E1...>, TypeList<mpl_::na>, Rest...) noexcept -> L1<E1...> { return {}; }\
|
||||
struct append<L1<E1...>, TypeList<mpl_::na>, Rest...> { using type = L1<E1...>; };\
|
||||
\
|
||||
template< template<typename...> class Container, template<typename...> class List, typename...elems>\
|
||||
constexpr auto rewrap(List<elems...>) noexcept -> TypeList<Container<elems...>> { return {}; }\
|
||||
struct rewrap<TemplateTypeList<Container>, List<elems...>> { using type = TypeList<Container<elems...>>; };\
|
||||
template< template<typename...> class Container, template<typename...> class List, class...Elems, typename...Elements>\
|
||||
constexpr auto rewrap(List<Elems...>,Elements...) noexcept -> decltype(append(TypeList<Container<Elems...>>{}, rewrap<Container>(Elements{}...))) { return {}; }\
|
||||
struct rewrap<TemplateTypeList<Container>, List<Elems...>, Elements...> { using type = typename append<TypeList<Container<Elems...>>, typename rewrap<TemplateTypeList<Container>, Elements...>::type>::type; };\
|
||||
\
|
||||
template<template <typename...> class Final, template< typename...> class...Containers, typename...Types>\
|
||||
constexpr auto create(TypeList<Types...>) noexcept -> decltype(append(Final<>{}, rewrap<Containers>(Types{}...)...)) { return {}; }\
|
||||
struct create<Final, TemplateTypeList<Containers...>, TypeList<Types...>> { using type = typename append<Final<>, typename rewrap<TemplateTypeList<Containers>, Types...>::type...>::type; };\
|
||||
template<template <typename...> class Final, template <typename...> class List, typename...Ts>\
|
||||
constexpr auto convert(const List<Ts...>& ) noexcept -> decltype(append(Final<>{},TypeList<Ts>{}...)) { return {}; }
|
||||
struct convert<Final, List<Ts...>> { using type = typename append<Final<>,TypeList<Ts>...>::type; };
|
||||
|
||||
#define INTERNAL_CATCH_NTTP_1(signature, ...)\
|
||||
template<INTERNAL_CATCH_REMOVE_PARENS(signature)> struct Nttp{};\
|
||||
template<INTERNAL_CATCH_REMOVE_PARENS(signature)>\
|
||||
constexpr auto get_wrapper() noexcept -> Nttp<__VA_ARGS__> { return {}; } \
|
||||
template<template<INTERNAL_CATCH_REMOVE_PARENS(signature)> class...> struct NttpTemplateTypeList{};\
|
||||
template<template<INTERNAL_CATCH_REMOVE_PARENS(signature)> class...Cs>\
|
||||
constexpr auto get_wrapper() noexcept -> NttpTemplateTypeList<Cs...> { return {}; } \
|
||||
\
|
||||
template< template<INTERNAL_CATCH_REMOVE_PARENS(signature)> class Container, template<INTERNAL_CATCH_REMOVE_PARENS(signature)> class List, INTERNAL_CATCH_REMOVE_PARENS(signature)>\
|
||||
constexpr auto rewrap(List<__VA_ARGS__>) noexcept -> TypeList<Container<__VA_ARGS__>> { return {}; }\
|
||||
struct rewrap<NttpTemplateTypeList<Container>, List<__VA_ARGS__>> { using type = TypeList<Container<__VA_ARGS__>>; };\
|
||||
template< template<INTERNAL_CATCH_REMOVE_PARENS(signature)> class Container, template<INTERNAL_CATCH_REMOVE_PARENS(signature)> class List, INTERNAL_CATCH_REMOVE_PARENS(signature), typename...Elements>\
|
||||
constexpr auto rewrap(List<__VA_ARGS__>,Elements...elems) noexcept -> decltype(append(TypeList<Container<__VA_ARGS__>>{}, rewrap<Container>(elems...))) { return {}; }\
|
||||
struct rewrap<NttpTemplateTypeList<Container>, List<__VA_ARGS__>, Elements...> { using type = typename append<TypeList<Container<__VA_ARGS__>>, typename rewrap<NttpTemplateTypeList<Container>, Elements...>::type>::type; };\
|
||||
template<template <typename...> class Final, template<INTERNAL_CATCH_REMOVE_PARENS(signature)> class...Containers, typename...Types>\
|
||||
constexpr auto create(TypeList<Types...>) noexcept -> decltype(append(Final<>{}, rewrap<Containers>(Types{}...)...)) { return {}; }
|
||||
struct create<Final, NttpTemplateTypeList<Containers...>, TypeList<Types...>> { using type = typename append<Final<>, typename rewrap<NttpTemplateTypeList<Containers>, Types...>::type...>::type; };
|
||||
|
||||
#define INTERNAL_CATCH_DECLARE_SIG_TEST0(TestName)
|
||||
#define INTERNAL_CATCH_DECLARE_SIG_TEST1(TestName, signature)\
|
||||
|
@@ -20,10 +20,10 @@ namespace Catch {
|
||||
using state_type = std::uint64_t;
|
||||
public:
|
||||
using result_type = std::uint32_t;
|
||||
static constexpr result_type min() {
|
||||
static constexpr result_type (min)() {
|
||||
return 0;
|
||||
}
|
||||
static constexpr result_type max() {
|
||||
static constexpr result_type (max)() {
|
||||
return static_cast<result_type>(-1);
|
||||
}
|
||||
|
||||
|
@@ -58,14 +58,16 @@ namespace Catch {
|
||||
#if !defined(CATCH_CONFIG_DISABLE)
|
||||
|
||||
#define CATCH_REGISTER_REPORTER( name, reporterType ) \
|
||||
CATCH_INTERNAL_START_WARNINGS_SUPPRESSION \
|
||||
CATCH_INTERNAL_SUPPRESS_GLOBALS_WARNINGS \
|
||||
namespace{ Catch::ReporterRegistrar<reporterType> catch_internal_RegistrarFor##reporterType( name ); } \
|
||||
CATCH_INTERNAL_UNSUPPRESS_GLOBALS_WARNINGS
|
||||
CATCH_INTERNAL_STOP_WARNINGS_SUPPRESSION
|
||||
|
||||
#define CATCH_REGISTER_LISTENER( listenerType ) \
|
||||
CATCH_INTERNAL_SUPPRESS_GLOBALS_WARNINGS \
|
||||
namespace{ Catch::ListenerRegistrar<listenerType> catch_internal_RegistrarFor##listenerType; } \
|
||||
CATCH_INTERNAL_SUPPRESS_GLOBALS_WARNINGS
|
||||
CATCH_INTERNAL_START_WARNINGS_SUPPRESSION \
|
||||
CATCH_INTERNAL_SUPPRESS_GLOBALS_WARNINGS \
|
||||
namespace{ Catch::ListenerRegistrar<listenerType> catch_internal_RegistrarFor##listenerType; } \
|
||||
CATCH_INTERNAL_STOP_WARNINGS_SUPPRESSION
|
||||
#else // CATCH_CONFIG_DISABLE
|
||||
|
||||
#define CATCH_REGISTER_REPORTER(name, reporterType)
|
||||
|
@@ -37,13 +37,15 @@ namespace Catch {
|
||||
} // end namespace Catch
|
||||
|
||||
#define INTERNAL_CATCH_SECTION( ... ) \
|
||||
CATCH_INTERNAL_START_WARNINGS_SUPPRESSION \
|
||||
CATCH_INTERNAL_SUPPRESS_UNUSED_WARNINGS \
|
||||
if( Catch::Section const& INTERNAL_CATCH_UNIQUE_NAME( catch_internal_Section ) = Catch::SectionInfo( CATCH_INTERNAL_LINEINFO, __VA_ARGS__ ) ) \
|
||||
CATCH_INTERNAL_UNSUPPRESS_UNUSED_WARNINGS
|
||||
CATCH_INTERNAL_STOP_WARNINGS_SUPPRESSION
|
||||
|
||||
#define INTERNAL_CATCH_DYNAMIC_SECTION( ... ) \
|
||||
CATCH_INTERNAL_START_WARNINGS_SUPPRESSION \
|
||||
CATCH_INTERNAL_SUPPRESS_UNUSED_WARNINGS \
|
||||
if( Catch::Section const& INTERNAL_CATCH_UNIQUE_NAME( catch_internal_Section ) = Catch::SectionInfo( CATCH_INTERNAL_LINEINFO, (Catch::ReusableStringStream() << __VA_ARGS__).str() ) ) \
|
||||
CATCH_INTERNAL_UNSUPPRESS_UNUSED_WARNINGS
|
||||
CATCH_INTERNAL_STOP_WARNINGS_SUPPRESSION
|
||||
|
||||
#endif // TWOBLUECUBES_CATCH_SECTION_H_INCLUDED
|
||||
|
@@ -68,8 +68,9 @@ namespace Catch {
|
||||
{
|
||||
auto const& allTestCases = getAllTestCasesSorted(*m_config);
|
||||
m_matches = m_config->testSpec().matchesByFilter(allTestCases, *m_config);
|
||||
|
||||
if (m_matches.empty()) {
|
||||
auto const& invalidArgs = m_config->testSpec().getInvalidArgs();
|
||||
|
||||
if (m_matches.empty() && invalidArgs.empty()) {
|
||||
for (auto const& test : allTestCases)
|
||||
if (!test.isHidden())
|
||||
m_tests.emplace(&test);
|
||||
@@ -80,6 +81,7 @@ namespace Catch {
|
||||
}
|
||||
|
||||
Totals execute() {
|
||||
auto const& invalidArgs = m_config->testSpec().getInvalidArgs();
|
||||
Totals totals;
|
||||
m_context.testGroupStarting(m_config->name(), 1, 1);
|
||||
for (auto const& testCase : m_tests) {
|
||||
@@ -95,6 +97,12 @@ namespace Catch {
|
||||
totals.error = -1;
|
||||
}
|
||||
}
|
||||
|
||||
if (!invalidArgs.empty()) {
|
||||
for (auto const& invalidArg: invalidArgs)
|
||||
m_context.reporter().reportInvalidArguments(invalidArg);
|
||||
}
|
||||
|
||||
m_context.testGroupEnded(m_config->name(), totals, 1, 1);
|
||||
return totals;
|
||||
}
|
||||
|
@@ -9,6 +9,8 @@
|
||||
#ifndef TWOBLUECUBES_CATCH_STREAM_H_INCLUDED
|
||||
#define TWOBLUECUBES_CATCH_STREAM_H_INCLUDED
|
||||
|
||||
#include "catch_common.h"
|
||||
|
||||
#include <iosfwd>
|
||||
#include <cstddef>
|
||||
#include <ostream>
|
||||
@@ -28,7 +30,7 @@ namespace Catch {
|
||||
|
||||
auto makeStream( StringRef const &filename ) -> IStream const*;
|
||||
|
||||
class ReusableStringStream {
|
||||
class ReusableStringStream : NonCopyable {
|
||||
std::size_t m_index;
|
||||
std::ostream* m_oss;
|
||||
public:
|
||||
|
@@ -5,14 +5,10 @@
|
||||
* file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
*/
|
||||
|
||||
|
||||
#if defined(__clang__)
|
||||
# pragma clang diagnostic push
|
||||
# pragma clang diagnostic ignored "-Wexit-time-destructors"
|
||||
#endif
|
||||
|
||||
#include "catch_enforce.h"
|
||||
#include "catch_stringref.h"
|
||||
|
||||
#include <algorithm>
|
||||
#include <ostream>
|
||||
#include <cstring>
|
||||
#include <cstdint>
|
||||
@@ -22,63 +18,33 @@ namespace Catch {
|
||||
: StringRef( rawChars, static_cast<StringRef::size_type>(std::strlen(rawChars) ) )
|
||||
{}
|
||||
|
||||
void StringRef::swap( StringRef& other ) noexcept {
|
||||
std::swap( m_start, other.m_start );
|
||||
std::swap( m_size, other.m_size );
|
||||
std::swap( m_data, other.m_data );
|
||||
}
|
||||
|
||||
auto StringRef::c_str() const -> char const* {
|
||||
if( !isSubstring() )
|
||||
return m_start;
|
||||
|
||||
const_cast<StringRef *>( this )->takeOwnership();
|
||||
return m_data;
|
||||
CATCH_ENFORCE(isNullTerminated(), "Called StringRef::c_str() on a non-null-terminated instance");
|
||||
return m_start;
|
||||
}
|
||||
auto StringRef::currentData() const noexcept -> char const* {
|
||||
auto StringRef::data() const noexcept -> char const* {
|
||||
return m_start;
|
||||
}
|
||||
|
||||
auto StringRef::isOwned() const noexcept -> bool {
|
||||
return m_data != nullptr;
|
||||
}
|
||||
auto StringRef::isSubstring() const noexcept -> bool {
|
||||
return m_start[m_size] != '\0';
|
||||
}
|
||||
|
||||
void StringRef::takeOwnership() {
|
||||
if( !isOwned() ) {
|
||||
m_data = new char[m_size+1];
|
||||
memcpy( m_data, m_start, m_size );
|
||||
m_data[m_size] = '\0';
|
||||
auto StringRef::substr( size_type start, size_type size ) const noexcept -> StringRef {
|
||||
if (start < m_size) {
|
||||
return StringRef(m_start + start, (std::min)(m_size - start, size));
|
||||
} else {
|
||||
return StringRef();
|
||||
}
|
||||
}
|
||||
auto StringRef::substr( size_type start, size_type size ) const noexcept -> StringRef {
|
||||
if( start < m_size )
|
||||
return StringRef( m_start+start, size );
|
||||
else
|
||||
return StringRef();
|
||||
}
|
||||
auto StringRef::operator == ( StringRef const& other ) const noexcept -> bool {
|
||||
return
|
||||
size() == other.size() &&
|
||||
(std::strncmp( m_start, other.m_start, size() ) == 0);
|
||||
}
|
||||
auto StringRef::operator != ( StringRef const& other ) const noexcept -> bool {
|
||||
return !operator==( other );
|
||||
return m_size == other.m_size
|
||||
&& (std::memcmp( m_start, other.m_start, m_size ) == 0);
|
||||
}
|
||||
|
||||
auto operator << ( std::ostream& os, StringRef const& str ) -> std::ostream& {
|
||||
return os.write(str.currentData(), str.size());
|
||||
return os.write(str.data(), str.size());
|
||||
}
|
||||
|
||||
auto operator+=( std::string& lhs, StringRef const& rhs ) -> std::string& {
|
||||
lhs.append(rhs.currentData(), rhs.size());
|
||||
lhs.append(rhs.data(), rhs.size());
|
||||
return lhs;
|
||||
}
|
||||
|
||||
} // namespace Catch
|
||||
|
||||
#if defined(__clang__)
|
||||
# pragma clang diagnostic pop
|
||||
#endif
|
||||
|
@@ -16,49 +16,24 @@ namespace Catch {
|
||||
|
||||
/// A non-owning string class (similar to the forthcoming std::string_view)
|
||||
/// Note that, because a StringRef may be a substring of another string,
|
||||
/// it may not be null terminated. c_str() must return a null terminated
|
||||
/// string, however, and so the StringRef will internally take ownership
|
||||
/// (taking a copy), if necessary. In theory this ownership is not externally
|
||||
/// visible - but it does mean (substring) StringRefs should not be shared between
|
||||
/// threads.
|
||||
/// it may not be null terminated.
|
||||
class StringRef {
|
||||
public:
|
||||
using size_type = std::size_t;
|
||||
using const_iterator = const char*;
|
||||
|
||||
private:
|
||||
friend struct StringRefTestAccess;
|
||||
|
||||
char const* m_start;
|
||||
size_type m_size;
|
||||
|
||||
char* m_data = nullptr;
|
||||
|
||||
void takeOwnership();
|
||||
|
||||
static constexpr char const* const s_empty = "";
|
||||
|
||||
public: // construction/ assignment
|
||||
StringRef() noexcept
|
||||
: StringRef( s_empty, 0 )
|
||||
{}
|
||||
char const* m_start = s_empty;
|
||||
size_type m_size = 0;
|
||||
|
||||
StringRef( StringRef const& other ) noexcept
|
||||
: m_start( other.m_start ),
|
||||
m_size( other.m_size )
|
||||
{}
|
||||
|
||||
StringRef( StringRef&& other ) noexcept
|
||||
: m_start( other.m_start ),
|
||||
m_size( other.m_size ),
|
||||
m_data( other.m_data )
|
||||
{
|
||||
other.m_data = nullptr;
|
||||
}
|
||||
public: // construction
|
||||
constexpr StringRef() noexcept = default;
|
||||
|
||||
StringRef( char const* rawChars ) noexcept;
|
||||
|
||||
StringRef( char const* rawChars, size_type size ) noexcept
|
||||
constexpr StringRef( char const* rawChars, size_type size ) noexcept
|
||||
: m_start( rawChars ),
|
||||
m_size( size )
|
||||
{}
|
||||
@@ -68,27 +43,15 @@ namespace Catch {
|
||||
m_size( stdString.size() )
|
||||
{}
|
||||
|
||||
~StringRef() noexcept {
|
||||
delete[] m_data;
|
||||
}
|
||||
|
||||
auto operator = ( StringRef const &other ) noexcept -> StringRef& {
|
||||
delete[] m_data;
|
||||
m_data = nullptr;
|
||||
m_start = other.m_start;
|
||||
m_size = other.m_size;
|
||||
return *this;
|
||||
}
|
||||
|
||||
explicit operator std::string() const {
|
||||
return std::string(m_start, m_size);
|
||||
}
|
||||
|
||||
void swap( StringRef& other ) noexcept;
|
||||
|
||||
public: // operators
|
||||
auto operator == ( StringRef const& other ) const noexcept -> bool;
|
||||
auto operator != ( StringRef const& other ) const noexcept -> bool;
|
||||
auto operator != (StringRef const& other) const noexcept -> bool {
|
||||
return !(*this == other);
|
||||
}
|
||||
|
||||
auto operator[] ( size_type index ) const noexcept -> char {
|
||||
assert(index < m_size);
|
||||
@@ -96,42 +59,45 @@ namespace Catch {
|
||||
}
|
||||
|
||||
public: // named queries
|
||||
auto empty() const noexcept -> bool {
|
||||
constexpr auto empty() const noexcept -> bool {
|
||||
return m_size == 0;
|
||||
}
|
||||
auto size() const noexcept -> size_type {
|
||||
constexpr auto size() const noexcept -> size_type {
|
||||
return m_size;
|
||||
}
|
||||
|
||||
// Returns the current start pointer. If the StringRef is not
|
||||
// null-terminated, throws std::domain_exception
|
||||
auto c_str() const -> char const*;
|
||||
|
||||
public: // substrings and searches
|
||||
auto substr( size_type start, size_type size ) const noexcept -> StringRef;
|
||||
// Returns a substring of [start, start + length).
|
||||
// If start + length > size(), then the substring is [start, size()).
|
||||
// If start > size(), then the substring is empty.
|
||||
auto substr( size_type start, size_type length ) const noexcept -> StringRef;
|
||||
|
||||
// Returns the current start pointer.
|
||||
// Note that the pointer can change when if the StringRef is a substring
|
||||
auto currentData() const noexcept -> char const*;
|
||||
// Returns the current start pointer. May not be null-terminated.
|
||||
auto data() const noexcept -> char const*;
|
||||
|
||||
constexpr auto isNullTerminated() const noexcept -> bool {
|
||||
return m_start[m_size] == '\0';
|
||||
}
|
||||
|
||||
public: // iterators
|
||||
const_iterator begin() const { return m_start; }
|
||||
const_iterator end() const { return m_start + m_size; }
|
||||
|
||||
private: // ownership queries - may not be consistent between calls
|
||||
auto isOwned() const noexcept -> bool;
|
||||
auto isSubstring() const noexcept -> bool;
|
||||
constexpr const_iterator begin() const { return m_start; }
|
||||
constexpr const_iterator end() const { return m_start + m_size; }
|
||||
};
|
||||
|
||||
auto operator += ( std::string& lhs, StringRef const& sr ) -> std::string&;
|
||||
auto operator << ( std::ostream& os, StringRef const& sr ) -> std::ostream&;
|
||||
|
||||
|
||||
inline auto operator "" _sr( char const* rawChars, std::size_t size ) noexcept -> StringRef {
|
||||
constexpr auto operator "" _sr( char const* rawChars, std::size_t size ) noexcept -> StringRef {
|
||||
return StringRef( rawChars, size );
|
||||
}
|
||||
|
||||
} // namespace Catch
|
||||
|
||||
inline auto operator "" _catch_sr( char const* rawChars, std::size_t size ) noexcept -> Catch::StringRef {
|
||||
constexpr auto operator "" _catch_sr( char const* rawChars, std::size_t size ) noexcept -> Catch::StringRef {
|
||||
return Catch::StringRef( rawChars, size );
|
||||
}
|
||||
|
||||
|
@@ -18,8 +18,9 @@ namespace Catch {
|
||||
} // end namespace Catch
|
||||
|
||||
#define CATCH_REGISTER_TAG_ALIAS( alias, spec ) \
|
||||
CATCH_INTERNAL_START_WARNINGS_SUPPRESSION \
|
||||
CATCH_INTERNAL_SUPPRESS_GLOBALS_WARNINGS \
|
||||
namespace{ Catch::RegistrarForTagAliases INTERNAL_CATCH_UNIQUE_NAME( AutoRegisterTagAlias )( alias, spec, CATCH_INTERNAL_LINEINFO ); } \
|
||||
CATCH_INTERNAL_UNSUPPRESS_GLOBALS_WARNINGS
|
||||
CATCH_INTERNAL_STOP_WARNINGS_SUPPRESSION
|
||||
|
||||
#endif // TWOBLUECUBES_CATCH_TAG_ALIAS_AUTOREGISTRAR_H_INCLUDED
|
||||
|
@@ -75,7 +75,7 @@ struct AutoReg : NonCopyable {
|
||||
#else
|
||||
#define INTERNAL_CATCH_TEMPLATE_TEST_CASE_NO_REGISTRATION(Name, Tags, ...) \
|
||||
INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_TEST_CASE_NO_REGISTRATION_2( INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_M_P_L_A_T_E____T_E_S_T____ ), INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_M_P_L_A_T_E____T_E_S_T____F_U_N_C____ ), Name, Tags, typename TestType, __VA_ARGS__ ) )
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifndef CATCH_CONFIG_TRADITIONAL_MSVC_PREPROCESSOR
|
||||
#define INTERNAL_CATCH_TEMPLATE_TEST_CASE_SIG_NO_REGISTRATION(Name, Tags, Signature, ...) \
|
||||
@@ -105,21 +105,24 @@ struct AutoReg : NonCopyable {
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
#define INTERNAL_CATCH_TESTCASE2( TestName, ... ) \
|
||||
static void TestName(); \
|
||||
CATCH_INTERNAL_START_WARNINGS_SUPPRESSION \
|
||||
CATCH_INTERNAL_SUPPRESS_GLOBALS_WARNINGS \
|
||||
namespace{ Catch::AutoReg INTERNAL_CATCH_UNIQUE_NAME( autoRegistrar )( Catch::makeTestInvoker( &TestName ), CATCH_INTERNAL_LINEINFO, Catch::StringRef(), Catch::NameAndTags{ __VA_ARGS__ } ); } /* NOLINT */ \
|
||||
CATCH_INTERNAL_UNSUPPRESS_GLOBALS_WARNINGS \
|
||||
CATCH_INTERNAL_STOP_WARNINGS_SUPPRESSION \
|
||||
static void TestName()
|
||||
#define INTERNAL_CATCH_TESTCASE( ... ) \
|
||||
INTERNAL_CATCH_TESTCASE2( INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_S_T____ ), __VA_ARGS__ )
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
#define INTERNAL_CATCH_METHOD_AS_TEST_CASE( QualifiedMethod, ... ) \
|
||||
CATCH_INTERNAL_START_WARNINGS_SUPPRESSION \
|
||||
CATCH_INTERNAL_SUPPRESS_GLOBALS_WARNINGS \
|
||||
namespace{ Catch::AutoReg INTERNAL_CATCH_UNIQUE_NAME( autoRegistrar )( Catch::makeTestInvoker( &QualifiedMethod ), CATCH_INTERNAL_LINEINFO, "&" #QualifiedMethod, Catch::NameAndTags{ __VA_ARGS__ } ); } /* NOLINT */ \
|
||||
CATCH_INTERNAL_UNSUPPRESS_GLOBALS_WARNINGS
|
||||
CATCH_INTERNAL_STOP_WARNINGS_SUPPRESSION
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
#define INTERNAL_CATCH_TEST_CASE_METHOD2( TestName, ClassName, ... )\
|
||||
CATCH_INTERNAL_START_WARNINGS_SUPPRESSION \
|
||||
CATCH_INTERNAL_SUPPRESS_GLOBALS_WARNINGS \
|
||||
namespace{ \
|
||||
struct TestName : INTERNAL_CATCH_REMOVE_PARENS(ClassName) { \
|
||||
@@ -127,21 +130,24 @@ struct AutoReg : NonCopyable {
|
||||
}; \
|
||||
Catch::AutoReg INTERNAL_CATCH_UNIQUE_NAME( autoRegistrar ) ( Catch::makeTestInvoker( &TestName::test ), CATCH_INTERNAL_LINEINFO, #ClassName, Catch::NameAndTags{ __VA_ARGS__ } ); /* NOLINT */ \
|
||||
} \
|
||||
CATCH_INTERNAL_UNSUPPRESS_GLOBALS_WARNINGS \
|
||||
CATCH_INTERNAL_STOP_WARNINGS_SUPPRESSION \
|
||||
void TestName::test()
|
||||
#define INTERNAL_CATCH_TEST_CASE_METHOD( ClassName, ... ) \
|
||||
INTERNAL_CATCH_TEST_CASE_METHOD2( INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_S_T____ ), ClassName, __VA_ARGS__ )
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
#define INTERNAL_CATCH_REGISTER_TESTCASE( Function, ... ) \
|
||||
CATCH_INTERNAL_START_WARNINGS_SUPPRESSION \
|
||||
CATCH_INTERNAL_SUPPRESS_GLOBALS_WARNINGS \
|
||||
Catch::AutoReg INTERNAL_CATCH_UNIQUE_NAME( autoRegistrar )( Catch::makeTestInvoker( Function ), CATCH_INTERNAL_LINEINFO, Catch::StringRef(), Catch::NameAndTags{ __VA_ARGS__ } ); /* NOLINT */ \
|
||||
CATCH_INTERNAL_UNSUPPRESS_GLOBALS_WARNINGS
|
||||
CATCH_INTERNAL_STOP_WARNINGS_SUPPRESSION
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
#define INTERNAL_CATCH_TEMPLATE_TEST_CASE_2(TestName, TestFunc, Name, Tags, Signature, ... )\
|
||||
CATCH_INTERNAL_START_WARNINGS_SUPPRESSION \
|
||||
CATCH_INTERNAL_SUPPRESS_GLOBALS_WARNINGS \
|
||||
CATCH_INTERNAL_SUPPRESS_ZERO_VARIADIC_WARNINGS \
|
||||
CATCH_INTERNAL_SUPPRESS_UNUSED_TEMPLATE_WARNINGS \
|
||||
INTERNAL_CATCH_DECLARE_SIG_TEST(TestFunc, INTERNAL_CATCH_REMOVE_PARENS(Signature));\
|
||||
namespace {\
|
||||
namespace INTERNAL_CATCH_MAKE_NAMESPACE(TestName){\
|
||||
@@ -163,8 +169,7 @@ struct AutoReg : NonCopyable {
|
||||
}();\
|
||||
}\
|
||||
}\
|
||||
CATCH_INTERNAL_UNSUPPRESS_GLOBALS_WARNINGS \
|
||||
CATCH_INTERNAL_UNSUPPRESS_ZERO_VARIADIC_WARNINGS \
|
||||
CATCH_INTERNAL_STOP_WARNINGS_SUPPRESSION \
|
||||
INTERNAL_CATCH_DEFINE_SIG_TEST(TestFunc,INTERNAL_CATCH_REMOVE_PARENS(Signature))
|
||||
|
||||
#ifndef CATCH_CONFIG_TRADITIONAL_MSVC_PREPROCESSOR
|
||||
@@ -173,7 +178,7 @@ struct AutoReg : NonCopyable {
|
||||
#else
|
||||
#define INTERNAL_CATCH_TEMPLATE_TEST_CASE(Name, Tags, ...) \
|
||||
INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_TEST_CASE_2( INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_M_P_L_A_T_E____T_E_S_T____ ), INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_M_P_L_A_T_E____T_E_S_T____F_U_N_C____ ), Name, Tags, typename TestType, __VA_ARGS__ ) )
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifndef CATCH_CONFIG_TRADITIONAL_MSVC_PREPROCESSOR
|
||||
#define INTERNAL_CATCH_TEMPLATE_TEST_CASE_SIG(Name, Tags, Signature, ...) \
|
||||
@@ -184,8 +189,10 @@ struct AutoReg : NonCopyable {
|
||||
#endif
|
||||
|
||||
#define INTERNAL_CATCH_TEMPLATE_PRODUCT_TEST_CASE2(TestName, TestFuncName, Name, Tags, Signature, TmplTypes, TypesList) \
|
||||
CATCH_INTERNAL_START_WARNINGS_SUPPRESSION \
|
||||
CATCH_INTERNAL_SUPPRESS_GLOBALS_WARNINGS \
|
||||
CATCH_INTERNAL_SUPPRESS_ZERO_VARIADIC_WARNINGS \
|
||||
CATCH_INTERNAL_SUPPRESS_UNUSED_TEMPLATE_WARNINGS \
|
||||
template<typename TestType> static void TestFuncName(); \
|
||||
namespace {\
|
||||
namespace INTERNAL_CATCH_MAKE_NAMESPACE(TestName) { \
|
||||
@@ -203,15 +210,14 @@ struct AutoReg : NonCopyable {
|
||||
} \
|
||||
}; \
|
||||
static int INTERNAL_CATCH_UNIQUE_NAME( globalRegistrar ) = [](){ \
|
||||
using TestInit = decltype(create<TestName, INTERNAL_CATCH_REMOVE_PARENS(TmplTypes)>(TypeList<INTERNAL_CATCH_MAKE_TYPE_LISTS_FROM_TYPES(INTERNAL_CATCH_REMOVE_PARENS(TypesList))>{})); \
|
||||
using TestInit = typename create<TestName, decltype(get_wrapper<INTERNAL_CATCH_REMOVE_PARENS(TmplTypes)>()), TypeList<INTERNAL_CATCH_MAKE_TYPE_LISTS_FROM_TYPES(INTERNAL_CATCH_REMOVE_PARENS(TypesList))>>::type; \
|
||||
TestInit t; \
|
||||
t.reg_tests(); \
|
||||
return 0; \
|
||||
}(); \
|
||||
} \
|
||||
} \
|
||||
CATCH_INTERNAL_UNSUPPRESS_GLOBALS_WARNINGS \
|
||||
CATCH_INTERNAL_UNSUPPRESS_ZERO_VARIADIC_WARNINGS \
|
||||
CATCH_INTERNAL_STOP_WARNINGS_SUPPRESSION \
|
||||
template<typename TestType> \
|
||||
static void TestFuncName()
|
||||
|
||||
@@ -232,7 +238,9 @@ struct AutoReg : NonCopyable {
|
||||
#endif
|
||||
|
||||
#define INTERNAL_CATCH_TEMPLATE_LIST_TEST_CASE_2(TestName, TestFunc, Name, Tags, TmplList)\
|
||||
CATCH_INTERNAL_START_WARNINGS_SUPPRESSION \
|
||||
CATCH_INTERNAL_SUPPRESS_GLOBALS_WARNINGS \
|
||||
CATCH_INTERNAL_SUPPRESS_UNUSED_TEMPLATE_WARNINGS \
|
||||
template<typename TestType> static void TestFunc(); \
|
||||
namespace {\
|
||||
namespace INTERNAL_CATCH_MAKE_NAMESPACE(TestName){\
|
||||
@@ -246,13 +254,13 @@ struct AutoReg : NonCopyable {
|
||||
} \
|
||||
};\
|
||||
static int INTERNAL_CATCH_UNIQUE_NAME( globalRegistrar ) = [](){ \
|
||||
using TestInit = decltype(convert<TestName>(std::declval<TmplList>())); \
|
||||
using TestInit = typename convert<TestName, TmplList>::type; \
|
||||
TestInit t; \
|
||||
t.reg_tests(); \
|
||||
return 0; \
|
||||
}(); \
|
||||
}(); \
|
||||
}}\
|
||||
CATCH_INTERNAL_UNSUPPRESS_GLOBALS_WARNINGS \
|
||||
CATCH_INTERNAL_STOP_WARNINGS_SUPPRESSION \
|
||||
template<typename TestType> \
|
||||
static void TestFunc()
|
||||
|
||||
@@ -261,8 +269,10 @@ struct AutoReg : NonCopyable {
|
||||
|
||||
|
||||
#define INTERNAL_CATCH_TEMPLATE_TEST_CASE_METHOD_2( TestNameClass, TestName, ClassName, Name, Tags, Signature, ... ) \
|
||||
CATCH_INTERNAL_START_WARNINGS_SUPPRESSION \
|
||||
CATCH_INTERNAL_SUPPRESS_GLOBALS_WARNINGS \
|
||||
CATCH_INTERNAL_SUPPRESS_ZERO_VARIADIC_WARNINGS \
|
||||
CATCH_INTERNAL_SUPPRESS_UNUSED_TEMPLATE_WARNINGS \
|
||||
namespace {\
|
||||
namespace INTERNAL_CATCH_MAKE_NAMESPACE(TestName){ \
|
||||
INTERNAL_CATCH_TYPE_GEN\
|
||||
@@ -284,8 +294,7 @@ struct AutoReg : NonCopyable {
|
||||
}();\
|
||||
}\
|
||||
}\
|
||||
CATCH_INTERNAL_UNSUPPRESS_GLOBALS_WARNINGS\
|
||||
CATCH_INTERNAL_UNSUPPRESS_ZERO_VARIADIC_WARNINGS\
|
||||
CATCH_INTERNAL_STOP_WARNINGS_SUPPRESSION \
|
||||
INTERNAL_CATCH_DEFINE_SIG_TEST_METHOD(TestName, INTERNAL_CATCH_REMOVE_PARENS(Signature))
|
||||
|
||||
#ifndef CATCH_CONFIG_TRADITIONAL_MSVC_PREPROCESSOR
|
||||
@@ -305,8 +314,10 @@ struct AutoReg : NonCopyable {
|
||||
#endif
|
||||
|
||||
#define INTERNAL_CATCH_TEMPLATE_PRODUCT_TEST_CASE_METHOD_2(TestNameClass, TestName, ClassName, Name, Tags, Signature, TmplTypes, TypesList)\
|
||||
CATCH_INTERNAL_START_WARNINGS_SUPPRESSION \
|
||||
CATCH_INTERNAL_SUPPRESS_GLOBALS_WARNINGS \
|
||||
CATCH_INTERNAL_SUPPRESS_ZERO_VARIADIC_WARNINGS \
|
||||
CATCH_INTERNAL_SUPPRESS_UNUSED_TEMPLATE_WARNINGS \
|
||||
template<typename TestType> \
|
||||
struct TestName : INTERNAL_CATCH_REMOVE_PARENS(ClassName <TestType>) { \
|
||||
void test();\
|
||||
@@ -327,15 +338,14 @@ struct AutoReg : NonCopyable {
|
||||
}\
|
||||
};\
|
||||
static int INTERNAL_CATCH_UNIQUE_NAME( globalRegistrar ) = [](){\
|
||||
using TestInit = decltype(create<TestNameClass, INTERNAL_CATCH_REMOVE_PARENS(TmplTypes)>(TypeList<INTERNAL_CATCH_MAKE_TYPE_LISTS_FROM_TYPES(INTERNAL_CATCH_REMOVE_PARENS(TypesList))>{}));\
|
||||
using TestInit = typename create<TestNameClass, decltype(get_wrapper<INTERNAL_CATCH_REMOVE_PARENS(TmplTypes)>()), TypeList<INTERNAL_CATCH_MAKE_TYPE_LISTS_FROM_TYPES(INTERNAL_CATCH_REMOVE_PARENS(TypesList))>>::type;\
|
||||
TestInit t;\
|
||||
t.reg_tests();\
|
||||
return 0;\
|
||||
}(); \
|
||||
}\
|
||||
}\
|
||||
CATCH_INTERNAL_UNSUPPRESS_GLOBALS_WARNINGS \
|
||||
CATCH_INTERNAL_UNSUPPRESS_ZERO_VARIADIC_WARNINGS \
|
||||
CATCH_INTERNAL_STOP_WARNINGS_SUPPRESSION \
|
||||
template<typename TestType> \
|
||||
void TestName<TestType>::test()
|
||||
|
||||
@@ -356,7 +366,9 @@ struct AutoReg : NonCopyable {
|
||||
#endif
|
||||
|
||||
#define INTERNAL_CATCH_TEMPLATE_LIST_TEST_CASE_METHOD_2( TestNameClass, TestName, ClassName, Name, Tags, TmplList) \
|
||||
CATCH_INTERNAL_START_WARNINGS_SUPPRESSION \
|
||||
CATCH_INTERNAL_SUPPRESS_GLOBALS_WARNINGS \
|
||||
CATCH_INTERNAL_SUPPRESS_UNUSED_TEMPLATE_WARNINGS \
|
||||
template<typename TestType> \
|
||||
struct TestName : INTERNAL_CATCH_REMOVE_PARENS(ClassName <TestType>) { \
|
||||
void test();\
|
||||
@@ -373,13 +385,13 @@ struct AutoReg : NonCopyable {
|
||||
}\
|
||||
};\
|
||||
static int INTERNAL_CATCH_UNIQUE_NAME( globalRegistrar ) = [](){\
|
||||
using TestInit = decltype(convert<TestNameClass>(std::declval<TmplList>()));\
|
||||
using TestInit = typename convert<TestNameClass, TmplList>::type;\
|
||||
TestInit t;\
|
||||
t.reg_tests();\
|
||||
return 0;\
|
||||
}(); \
|
||||
}}\
|
||||
CATCH_INTERNAL_UNSUPPRESS_GLOBALS_WARNINGS \
|
||||
CATCH_INTERNAL_STOP_WARNINGS_SUPPRESSION \
|
||||
template<typename TestType> \
|
||||
void TestName<TestType>::test()
|
||||
|
||||
|
@@ -91,5 +91,9 @@ namespace Catch {
|
||||
} );
|
||||
return matches;
|
||||
}
|
||||
|
||||
const TestSpec::vectorStrings& TestSpec::getInvalidArgs() const{
|
||||
return (m_invalidArgs);
|
||||
}
|
||||
|
||||
}
|
||||
|
@@ -73,14 +73,16 @@ namespace Catch {
|
||||
std::vector<TestCase const*> tests;
|
||||
};
|
||||
using Matches = std::vector<FilterMatch>;
|
||||
using vectorStrings = std::vector<std::string>;
|
||||
|
||||
bool hasFilters() const;
|
||||
bool matches( TestCaseInfo const& testCase ) const;
|
||||
Matches matchesByFilter( std::vector<TestCase> const& testCases, IConfig const& config ) const;
|
||||
const vectorStrings & getInvalidArgs() const;
|
||||
|
||||
private:
|
||||
std::vector<Filter> m_filters;
|
||||
|
||||
std::vector<std::string> m_invalidArgs;
|
||||
friend class TestSpecParser;
|
||||
};
|
||||
}
|
||||
|
@@ -20,8 +20,13 @@ namespace Catch {
|
||||
m_substring.reserve(m_arg.size());
|
||||
m_patternName.reserve(m_arg.size());
|
||||
m_realPatternPos = 0;
|
||||
|
||||
for( m_pos = 0; m_pos < m_arg.size(); ++m_pos )
|
||||
visitChar( m_arg[m_pos] );
|
||||
//if visitChar fails
|
||||
if( !visitChar( m_arg[m_pos] ) ){
|
||||
m_testSpec.m_invalidArgs.push_back(arg);
|
||||
break;
|
||||
}
|
||||
endMode();
|
||||
return *this;
|
||||
}
|
||||
@@ -29,38 +34,32 @@ namespace Catch {
|
||||
addFilter();
|
||||
return m_testSpec;
|
||||
}
|
||||
void TestSpecParser::visitChar( char c ) {
|
||||
bool TestSpecParser::visitChar( char c ) {
|
||||
if( (m_mode != EscapedName) && (c == '\\') ) {
|
||||
escape();
|
||||
m_substring += c;
|
||||
m_patternName += c;
|
||||
m_realPatternPos++;
|
||||
return;
|
||||
addCharToPattern(c);
|
||||
return true;
|
||||
}else if((m_mode != EscapedName) && (c == ',') ) {
|
||||
endMode();
|
||||
addFilter();
|
||||
return;
|
||||
return separate();
|
||||
}
|
||||
|
||||
switch( m_mode ) {
|
||||
case None:
|
||||
if( processNoneChar( c ) )
|
||||
return;
|
||||
return true;
|
||||
break;
|
||||
case Name:
|
||||
processNameChar( c );
|
||||
break;
|
||||
case EscapedName:
|
||||
endMode();
|
||||
m_substring += c;
|
||||
m_patternName += c;
|
||||
m_realPatternPos++;
|
||||
return;
|
||||
addCharToPattern(c);
|
||||
return true;
|
||||
default:
|
||||
case Tag:
|
||||
case QuotedName:
|
||||
if( processOtherChar( c ) )
|
||||
return;
|
||||
return true;
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -69,6 +68,7 @@ namespace Catch {
|
||||
m_patternName += c;
|
||||
m_realPatternPos++;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
// Two of the processing methods return true to signal the caller to return
|
||||
// without adding the given character to the current pattern strings
|
||||
@@ -113,9 +113,9 @@ namespace Catch {
|
||||
switch( m_mode ) {
|
||||
case Name:
|
||||
case QuotedName:
|
||||
return addPattern<TestSpec::NamePattern>();
|
||||
return addNamePattern();
|
||||
case Tag:
|
||||
return addPattern<TestSpec::TagPattern>();
|
||||
return addTagPattern();
|
||||
case EscapedName:
|
||||
revertBackToLastMode();
|
||||
return;
|
||||
@@ -156,11 +156,81 @@ namespace Catch {
|
||||
void TestSpecParser::saveLastMode() {
|
||||
lastMode = m_mode;
|
||||
}
|
||||
|
||||
|
||||
void TestSpecParser::revertBackToLastMode() {
|
||||
m_mode = lastMode;
|
||||
}
|
||||
|
||||
|
||||
bool TestSpecParser::separate() {
|
||||
if( (m_mode==QuotedName) || (m_mode==Tag) ){
|
||||
//invalid argument, signal failure to previous scope.
|
||||
m_mode = None;
|
||||
m_pos = m_arg.size();
|
||||
m_substring.clear();
|
||||
m_patternName.clear();
|
||||
return false;
|
||||
}
|
||||
endMode();
|
||||
addFilter();
|
||||
return true; //success
|
||||
}
|
||||
|
||||
std::string TestSpecParser::preprocessPattern() {
|
||||
std::string token = m_patternName;
|
||||
for (std::size_t i = 0; i < m_escapeChars.size(); ++i)
|
||||
token = token.substr(0, m_escapeChars[i] - i) + token.substr(m_escapeChars[i] - i + 1);
|
||||
m_escapeChars.clear();
|
||||
if (startsWith(token, "exclude:")) {
|
||||
m_exclusion = true;
|
||||
token = token.substr(8);
|
||||
}
|
||||
|
||||
m_patternName.clear();
|
||||
|
||||
return token;
|
||||
}
|
||||
|
||||
void TestSpecParser::addNamePattern() {
|
||||
auto token = preprocessPattern();
|
||||
|
||||
if (!token.empty()) {
|
||||
TestSpec::PatternPtr pattern = std::make_shared<TestSpec::NamePattern>(token, m_substring);
|
||||
if (m_exclusion)
|
||||
pattern = std::make_shared<TestSpec::ExcludedPattern>(pattern);
|
||||
m_currentFilter.m_patterns.push_back(pattern);
|
||||
}
|
||||
m_substring.clear();
|
||||
m_exclusion = false;
|
||||
m_mode = None;
|
||||
}
|
||||
|
||||
void TestSpecParser::addTagPattern() {
|
||||
auto token = preprocessPattern();
|
||||
|
||||
if (!token.empty()) {
|
||||
// If the tag pattern is the "hide and tag" shorthand (e.g. [.foo])
|
||||
// we have to create a separate hide tag and shorten the real one
|
||||
if (token.size() > 1 && token[0] == '.') {
|
||||
token.erase(token.begin());
|
||||
TestSpec::PatternPtr pattern = std::make_shared<TestSpec::TagPattern>(".", m_substring);
|
||||
if (m_exclusion) {
|
||||
pattern = std::make_shared<TestSpec::ExcludedPattern>(pattern);
|
||||
}
|
||||
m_currentFilter.m_patterns.push_back(pattern);
|
||||
}
|
||||
|
||||
TestSpec::PatternPtr pattern = std::make_shared<TestSpec::TagPattern>(token, m_substring);
|
||||
|
||||
if (m_exclusion) {
|
||||
pattern = std::make_shared<TestSpec::ExcludedPattern>(pattern);
|
||||
}
|
||||
m_currentFilter.m_patterns.push_back(pattern);
|
||||
}
|
||||
m_substring.clear();
|
||||
m_exclusion = false;
|
||||
m_mode = None;
|
||||
}
|
||||
|
||||
TestSpec parseTestSpec( std::string const& arg ) {
|
||||
return TestSpecParser( ITagAliasRegistry::get() ).parse( arg ).testSpec();
|
||||
}
|
||||
|
@@ -41,7 +41,7 @@ namespace Catch {
|
||||
TestSpec testSpec();
|
||||
|
||||
private:
|
||||
void visitChar( char c );
|
||||
bool visitChar( char c );
|
||||
void startNewMode( Mode mode );
|
||||
bool processNoneChar( char c );
|
||||
void processNameChar( char c );
|
||||
@@ -51,30 +51,22 @@ namespace Catch {
|
||||
bool isControlChar( char c ) const;
|
||||
void saveLastMode();
|
||||
void revertBackToLastMode();
|
||||
|
||||
template<typename T>
|
||||
void addPattern() {
|
||||
std::string token = m_patternName;
|
||||
for( std::size_t i = 0; i < m_escapeChars.size(); ++i )
|
||||
token = token.substr( 0, m_escapeChars[i] - i ) + token.substr( m_escapeChars[i] -i +1 );
|
||||
m_escapeChars.clear();
|
||||
if( startsWith( token, "exclude:" ) ) {
|
||||
m_exclusion = true;
|
||||
token = token.substr( 8 );
|
||||
}
|
||||
if( !token.empty() ) {
|
||||
TestSpec::PatternPtr pattern = std::make_shared<T>( token, m_substring );
|
||||
if( m_exclusion )
|
||||
pattern = std::make_shared<TestSpec::ExcludedPattern>( pattern );
|
||||
m_currentFilter.m_patterns.push_back( pattern );
|
||||
}
|
||||
m_substring.clear();
|
||||
m_patternName.clear();
|
||||
m_exclusion = false;
|
||||
m_mode = None;
|
||||
void addFilter();
|
||||
bool separate();
|
||||
|
||||
// Handles common preprocessing of the pattern for name/tag patterns
|
||||
std::string preprocessPattern();
|
||||
// Adds the current pattern as a test name
|
||||
void addNamePattern();
|
||||
// Adds the current pattern as a tag
|
||||
void addTagPattern();
|
||||
|
||||
inline void addCharToPattern(char c) {
|
||||
m_substring += c;
|
||||
m_patternName += c;
|
||||
m_realPatternPos++;
|
||||
}
|
||||
|
||||
void addFilter();
|
||||
};
|
||||
TestSpec parseTestSpec( std::string const& arg );
|
||||
|
||||
|
@@ -38,13 +38,11 @@ namespace Detail {
|
||||
enum Arch { Big, Little };
|
||||
|
||||
static Arch which() {
|
||||
union _{
|
||||
int asInt;
|
||||
char asChar[sizeof (int)];
|
||||
} u;
|
||||
|
||||
u.asInt = 1;
|
||||
return ( u.asChar[sizeof(int)-1] == 1 ) ? Big : Little;
|
||||
int one = 1;
|
||||
// If the lowest byte we read is non-zero, we can assume
|
||||
// that little endian format is used.
|
||||
auto value = *reinterpret_cast<char*>(&one);
|
||||
return value ? Little : Big;
|
||||
}
|
||||
};
|
||||
}
|
||||
@@ -241,13 +239,13 @@ std::string StringMaker<std::nullptr_t>::convert(std::nullptr_t) {
|
||||
}
|
||||
|
||||
int StringMaker<float>::precision = 5;
|
||||
|
||||
|
||||
std::string StringMaker<float>::convert(float value) {
|
||||
return fpToString(value, precision) + 'f';
|
||||
}
|
||||
|
||||
int StringMaker<double>::precision = 10;
|
||||
|
||||
|
||||
std::string StringMaker<double>::convert(double value) {
|
||||
return fpToString(value, precision);
|
||||
}
|
||||
|
@@ -37,7 +37,7 @@ namespace Catch {
|
||||
}
|
||||
|
||||
Version const& libraryVersion() {
|
||||
static Version version( 2, 10, 0, "", 0 );
|
||||
static Version version( 2, 11, 0, "", 0 );
|
||||
return version;
|
||||
}
|
||||
|
||||
|
@@ -10,6 +10,7 @@
|
||||
#include "catch_enforce.h"
|
||||
|
||||
#include <iomanip>
|
||||
#include <type_traits>
|
||||
|
||||
using uchar = unsigned char;
|
||||
|
||||
@@ -51,8 +52,31 @@ namespace {
|
||||
os.flags(f);
|
||||
}
|
||||
|
||||
bool shouldNewline(XmlFormatting fmt) {
|
||||
return !!(static_cast<std::underlying_type<XmlFormatting>::type>(fmt & XmlFormatting::Newline));
|
||||
}
|
||||
|
||||
bool shouldIndent(XmlFormatting fmt) {
|
||||
return !!(static_cast<std::underlying_type<XmlFormatting>::type>(fmt & XmlFormatting::Indent));
|
||||
}
|
||||
|
||||
} // anonymous namespace
|
||||
|
||||
XmlFormatting operator | (XmlFormatting lhs, XmlFormatting rhs) {
|
||||
return static_cast<XmlFormatting>(
|
||||
static_cast<std::underlying_type<XmlFormatting>::type>(lhs) |
|
||||
static_cast<std::underlying_type<XmlFormatting>::type>(rhs)
|
||||
);
|
||||
}
|
||||
|
||||
XmlFormatting operator & (XmlFormatting lhs, XmlFormatting rhs) {
|
||||
return static_cast<XmlFormatting>(
|
||||
static_cast<std::underlying_type<XmlFormatting>::type>(lhs) &
|
||||
static_cast<std::underlying_type<XmlFormatting>::type>(rhs)
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
XmlEncode::XmlEncode( std::string const& str, ForWhat forWhat )
|
||||
: m_str( str ),
|
||||
m_forWhat( forWhat )
|
||||
@@ -157,13 +181,17 @@ namespace {
|
||||
return os;
|
||||
}
|
||||
|
||||
XmlWriter::ScopedElement::ScopedElement( XmlWriter* writer )
|
||||
: m_writer( writer )
|
||||
XmlWriter::ScopedElement::ScopedElement( XmlWriter* writer, XmlFormatting fmt )
|
||||
: m_writer( writer ),
|
||||
m_fmt(fmt)
|
||||
{}
|
||||
|
||||
XmlWriter::ScopedElement::ScopedElement( ScopedElement&& other ) noexcept
|
||||
: m_writer( other.m_writer ){
|
||||
: m_writer( other.m_writer ),
|
||||
m_fmt(other.m_fmt)
|
||||
{
|
||||
other.m_writer = nullptr;
|
||||
other.m_fmt = XmlFormatting::None;
|
||||
}
|
||||
XmlWriter::ScopedElement& XmlWriter::ScopedElement::operator=( ScopedElement&& other ) noexcept {
|
||||
if ( m_writer ) {
|
||||
@@ -171,17 +199,20 @@ namespace {
|
||||
}
|
||||
m_writer = other.m_writer;
|
||||
other.m_writer = nullptr;
|
||||
m_fmt = other.m_fmt;
|
||||
other.m_fmt = XmlFormatting::None;
|
||||
return *this;
|
||||
}
|
||||
|
||||
|
||||
XmlWriter::ScopedElement::~ScopedElement() {
|
||||
if( m_writer )
|
||||
m_writer->endElement();
|
||||
if (m_writer) {
|
||||
m_writer->endElement(m_fmt);
|
||||
}
|
||||
}
|
||||
|
||||
XmlWriter::ScopedElement& XmlWriter::ScopedElement::writeText( std::string const& text, bool indent ) {
|
||||
m_writer->writeText( text, indent );
|
||||
XmlWriter::ScopedElement& XmlWriter::ScopedElement::writeText( std::string const& text, XmlFormatting fmt ) {
|
||||
m_writer->writeText( text, fmt );
|
||||
return *this;
|
||||
}
|
||||
|
||||
@@ -191,37 +222,47 @@ namespace {
|
||||
}
|
||||
|
||||
XmlWriter::~XmlWriter() {
|
||||
while( !m_tags.empty() )
|
||||
while (!m_tags.empty()) {
|
||||
endElement();
|
||||
}
|
||||
newlineIfNecessary();
|
||||
}
|
||||
|
||||
XmlWriter& XmlWriter::startElement( std::string const& name ) {
|
||||
XmlWriter& XmlWriter::startElement( std::string const& name, XmlFormatting fmt ) {
|
||||
ensureTagClosed();
|
||||
newlineIfNecessary();
|
||||
m_os << m_indent << '<' << name;
|
||||
if (shouldIndent(fmt)) {
|
||||
m_os << m_indent;
|
||||
m_indent += " ";
|
||||
}
|
||||
m_os << '<' << name;
|
||||
m_tags.push_back( name );
|
||||
m_indent += " ";
|
||||
m_tagIsOpen = true;
|
||||
applyFormatting(fmt);
|
||||
return *this;
|
||||
}
|
||||
|
||||
XmlWriter::ScopedElement XmlWriter::scopedElement( std::string const& name ) {
|
||||
ScopedElement scoped( this );
|
||||
startElement( name );
|
||||
XmlWriter::ScopedElement XmlWriter::scopedElement( std::string const& name, XmlFormatting fmt ) {
|
||||
ScopedElement scoped( this, fmt );
|
||||
startElement( name, fmt );
|
||||
return scoped;
|
||||
}
|
||||
|
||||
XmlWriter& XmlWriter::endElement() {
|
||||
newlineIfNecessary();
|
||||
m_indent = m_indent.substr( 0, m_indent.size()-2 );
|
||||
XmlWriter& XmlWriter::endElement(XmlFormatting fmt) {
|
||||
m_indent = m_indent.substr(0, m_indent.size() - 2);
|
||||
|
||||
if( m_tagIsOpen ) {
|
||||
m_os << "/>";
|
||||
m_tagIsOpen = false;
|
||||
} else {
|
||||
newlineIfNecessary();
|
||||
if (shouldIndent(fmt)) {
|
||||
m_os << m_indent;
|
||||
}
|
||||
m_os << "</" << m_tags.back() << ">";
|
||||
}
|
||||
else {
|
||||
m_os << m_indent << "</" << m_tags.back() << ">";
|
||||
}
|
||||
m_os << std::endl;
|
||||
m_os << std::flush;
|
||||
applyFormatting(fmt);
|
||||
m_tags.pop_back();
|
||||
return *this;
|
||||
}
|
||||
@@ -237,22 +278,26 @@ namespace {
|
||||
return *this;
|
||||
}
|
||||
|
||||
XmlWriter& XmlWriter::writeText( std::string const& text, bool indent ) {
|
||||
XmlWriter& XmlWriter::writeText( std::string const& text, XmlFormatting fmt) {
|
||||
if( !text.empty() ){
|
||||
bool tagWasOpen = m_tagIsOpen;
|
||||
ensureTagClosed();
|
||||
if( tagWasOpen && indent )
|
||||
if (tagWasOpen && shouldIndent(fmt)) {
|
||||
m_os << m_indent;
|
||||
}
|
||||
m_os << XmlEncode( text );
|
||||
m_needsNewline = true;
|
||||
applyFormatting(fmt);
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
XmlWriter& XmlWriter::writeComment( std::string const& text ) {
|
||||
XmlWriter& XmlWriter::writeComment( std::string const& text, XmlFormatting fmt) {
|
||||
ensureTagClosed();
|
||||
m_os << m_indent << "<!--" << text << "-->";
|
||||
m_needsNewline = true;
|
||||
if (shouldIndent(fmt)) {
|
||||
m_os << m_indent;
|
||||
}
|
||||
m_os << "<!--" << text << "-->";
|
||||
applyFormatting(fmt);
|
||||
return *this;
|
||||
}
|
||||
|
||||
@@ -268,11 +313,16 @@ namespace {
|
||||
|
||||
void XmlWriter::ensureTagClosed() {
|
||||
if( m_tagIsOpen ) {
|
||||
m_os << ">" << std::endl;
|
||||
m_os << '>' << std::flush;
|
||||
newlineIfNecessary();
|
||||
m_tagIsOpen = false;
|
||||
}
|
||||
}
|
||||
|
||||
void XmlWriter::applyFormatting(XmlFormatting fmt) {
|
||||
m_needsNewline = shouldNewline(fmt);
|
||||
}
|
||||
|
||||
void XmlWriter::writeDeclaration() {
|
||||
m_os << "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n";
|
||||
}
|
||||
|
@@ -14,6 +14,14 @@
|
||||
#include <vector>
|
||||
|
||||
namespace Catch {
|
||||
enum class XmlFormatting {
|
||||
None = 0x00,
|
||||
Indent = 0x01,
|
||||
Newline = 0x02,
|
||||
};
|
||||
|
||||
XmlFormatting operator | (XmlFormatting lhs, XmlFormatting rhs);
|
||||
XmlFormatting operator & (XmlFormatting lhs, XmlFormatting rhs);
|
||||
|
||||
class XmlEncode {
|
||||
public:
|
||||
@@ -35,14 +43,14 @@ namespace Catch {
|
||||
|
||||
class ScopedElement {
|
||||
public:
|
||||
ScopedElement( XmlWriter* writer );
|
||||
ScopedElement( XmlWriter* writer, XmlFormatting fmt );
|
||||
|
||||
ScopedElement( ScopedElement&& other ) noexcept;
|
||||
ScopedElement& operator=( ScopedElement&& other ) noexcept;
|
||||
|
||||
~ScopedElement();
|
||||
|
||||
ScopedElement& writeText( std::string const& text, bool indent = true );
|
||||
ScopedElement& writeText( std::string const& text, XmlFormatting fmt = XmlFormatting::Newline | XmlFormatting::Indent );
|
||||
|
||||
template<typename T>
|
||||
ScopedElement& writeAttribute( std::string const& name, T const& attribute ) {
|
||||
@@ -52,6 +60,7 @@ namespace Catch {
|
||||
|
||||
private:
|
||||
mutable XmlWriter* m_writer = nullptr;
|
||||
XmlFormatting m_fmt;
|
||||
};
|
||||
|
||||
XmlWriter( std::ostream& os = Catch::cout() );
|
||||
@@ -60,11 +69,11 @@ namespace Catch {
|
||||
XmlWriter( XmlWriter const& ) = delete;
|
||||
XmlWriter& operator=( XmlWriter const& ) = delete;
|
||||
|
||||
XmlWriter& startElement( std::string const& name );
|
||||
XmlWriter& startElement( std::string const& name, XmlFormatting fmt = XmlFormatting::Newline | XmlFormatting::Indent);
|
||||
|
||||
ScopedElement scopedElement( std::string const& name );
|
||||
ScopedElement scopedElement( std::string const& name, XmlFormatting fmt = XmlFormatting::Newline | XmlFormatting::Indent);
|
||||
|
||||
XmlWriter& endElement();
|
||||
XmlWriter& endElement(XmlFormatting fmt = XmlFormatting::Newline | XmlFormatting::Indent);
|
||||
|
||||
XmlWriter& writeAttribute( std::string const& name, std::string const& attribute );
|
||||
|
||||
@@ -77,9 +86,9 @@ namespace Catch {
|
||||
return writeAttribute( name, rss.str() );
|
||||
}
|
||||
|
||||
XmlWriter& writeText( std::string const& text, bool indent = true );
|
||||
XmlWriter& writeText( std::string const& text, XmlFormatting fmt = XmlFormatting::Newline | XmlFormatting::Indent);
|
||||
|
||||
XmlWriter& writeComment( std::string const& text );
|
||||
XmlWriter& writeComment(std::string const& text, XmlFormatting fmt = XmlFormatting::Newline | XmlFormatting::Indent);
|
||||
|
||||
void writeStylesheetRef( std::string const& url );
|
||||
|
||||
@@ -89,6 +98,8 @@ namespace Catch {
|
||||
|
||||
private:
|
||||
|
||||
void applyFormatting(XmlFormatting fmt);
|
||||
|
||||
void writeDeclaration();
|
||||
|
||||
void newlineIfNecessary();
|
||||
|
@@ -51,6 +51,8 @@ namespace Catch {
|
||||
|
||||
void noMatchingTestCases(std::string const&) override {}
|
||||
|
||||
void reportInvalidArguments(std::string const&) override {}
|
||||
|
||||
void testRunStarting(TestRunInfo const& _testRunInfo) override {
|
||||
currentTestRunInfo = _testRunInfo;
|
||||
}
|
||||
@@ -277,4 +279,4 @@ namespace Catch {
|
||||
|
||||
} // end namespace Catch
|
||||
|
||||
#endif // TWOBLUECUBES_CATCH_REPORTER_BASES_HPP_INCLUDED
|
||||
#endif // TWOBLUECUBES_CATCH_REPORTER_BASES_HPP_INCLUDED
|
@@ -383,6 +383,10 @@ void ConsoleReporter::noMatchingTestCases(std::string const& spec) {
|
||||
stream << "No test cases matched '" << spec << '\'' << std::endl;
|
||||
}
|
||||
|
||||
void ConsoleReporter::reportInvalidArguments(std::string const&arg){
|
||||
stream << "Invalid Filter: " << arg << std::endl;
|
||||
}
|
||||
|
||||
void ConsoleReporter::assertionStarting(AssertionInfo const&) {}
|
||||
|
||||
bool ConsoleReporter::assertionEnded(AssertionStats const& _assertionStats) {
|
||||
@@ -694,4 +698,4 @@ CATCH_REGISTER_REPORTER("console", ConsoleReporter)
|
||||
|
||||
#if defined(__clang__)
|
||||
# pragma clang diagnostic pop
|
||||
#endif
|
||||
#endif
|
@@ -32,6 +32,8 @@ namespace Catch {
|
||||
|
||||
void noMatchingTestCases(std::string const& spec) override;
|
||||
|
||||
void reportInvalidArguments(std::string const&arg) override;
|
||||
|
||||
void assertionStarting(AssertionInfo const&) override;
|
||||
|
||||
bool assertionEnded(AssertionStats const& _assertionStats) override;
|
||||
@@ -84,4 +86,4 @@ namespace Catch {
|
||||
#pragma warning(pop)
|
||||
#endif
|
||||
|
||||
#endif // TWOBLUECUBES_CATCH_REPORTER_CONSOLE_H_INCLUDED
|
||||
#endif // TWOBLUECUBES_CATCH_REPORTER_CONSOLE_H_INCLUDED
|
@@ -12,6 +12,7 @@
|
||||
|
||||
#include "../internal/catch_tostring.h"
|
||||
#include "../internal/catch_reporter_registrars.hpp"
|
||||
#include "../internal/catch_text.h"
|
||||
|
||||
#include <cassert>
|
||||
#include <sstream>
|
||||
@@ -146,8 +147,8 @@ namespace Catch {
|
||||
for( auto const& child : groupNode.children )
|
||||
writeTestCase( *child );
|
||||
|
||||
xml.scopedElement( "system-out" ).writeText( trim( stdOutForSuite ), false );
|
||||
xml.scopedElement( "system-err" ).writeText( trim( stdErrForSuite ), false );
|
||||
xml.scopedElement( "system-out" ).writeText( trim( stdOutForSuite ), XmlFormatting::Newline );
|
||||
xml.scopedElement( "system-err" ).writeText( trim( stdErrForSuite ), XmlFormatting::Newline );
|
||||
}
|
||||
|
||||
void JunitReporter::writeTestCase( TestCaseNode const& testCaseNode ) {
|
||||
@@ -196,9 +197,9 @@ namespace Catch {
|
||||
writeAssertions( sectionNode );
|
||||
|
||||
if( !sectionNode.stdOut.empty() )
|
||||
xml.scopedElement( "system-out" ).writeText( trim( sectionNode.stdOut ), false );
|
||||
xml.scopedElement( "system-out" ).writeText( trim( sectionNode.stdOut ), XmlFormatting::Newline );
|
||||
if( !sectionNode.stdErr.empty() )
|
||||
xml.scopedElement( "system-err" ).writeText( trim( sectionNode.stdErr ), false );
|
||||
xml.scopedElement( "system-err" ).writeText( trim( sectionNode.stdErr ), XmlFormatting::Newline );
|
||||
}
|
||||
for( auto const& childNode : sectionNode.childSections )
|
||||
if( className.empty() )
|
||||
@@ -244,10 +245,25 @@ namespace Catch {
|
||||
|
||||
XmlWriter::ScopedElement e = xml.scopedElement( elementName );
|
||||
|
||||
xml.writeAttribute( "message", result.getExpandedExpression() );
|
||||
xml.writeAttribute( "message", result.getExpression() );
|
||||
xml.writeAttribute( "type", result.getTestMacroName() );
|
||||
|
||||
ReusableStringStream rss;
|
||||
if (stats.totals.assertions.total() > 0) {
|
||||
rss << "FAILED" << ":\n";
|
||||
if (result.hasExpression()) {
|
||||
rss << " ";
|
||||
rss << result.getExpressionInMacro();
|
||||
rss << '\n';
|
||||
}
|
||||
if (result.hasExpandedExpression()) {
|
||||
rss << "with expansion:\n";
|
||||
rss << Column(result.getExpandedExpression()).indent(2) << '\n';
|
||||
}
|
||||
} else {
|
||||
rss << '\n';
|
||||
}
|
||||
|
||||
if( !result.getMessage().empty() )
|
||||
rss << result.getMessage() << '\n';
|
||||
for( auto const& msg : stats.infoMessages )
|
||||
@@ -255,7 +271,7 @@ namespace Catch {
|
||||
rss << msg.message << '\n';
|
||||
|
||||
rss << "at " << result.getSourceInfo();
|
||||
xml.writeText( rss.str(), false );
|
||||
xml.writeText( rss.str(), XmlFormatting::Newline );
|
||||
}
|
||||
}
|
||||
|
||||
|
@@ -41,6 +41,13 @@ namespace Catch {
|
||||
}
|
||||
m_reporter->noMatchingTestCases( spec );
|
||||
}
|
||||
|
||||
void ListeningReporter::reportInvalidArguments(std::string const&arg){
|
||||
for ( auto const& listener : m_listeners ) {
|
||||
listener->reportInvalidArguments( arg );
|
||||
}
|
||||
m_reporter->reportInvalidArguments( arg );
|
||||
}
|
||||
|
||||
#if defined(CATCH_CONFIG_ENABLE_BENCHMARKING)
|
||||
void ListeningReporter::benchmarkPreparing( std::string const& name ) {
|
||||
@@ -154,4 +161,4 @@ namespace Catch {
|
||||
return true;
|
||||
}
|
||||
|
||||
} // end namespace Catch
|
||||
} // end namespace Catch
|
@@ -28,7 +28,9 @@ namespace Catch {
|
||||
ReporterPreferences getPreferences() const override;
|
||||
|
||||
void noMatchingTestCases( std::string const& spec ) override;
|
||||
|
||||
|
||||
void reportInvalidArguments(std::string const&arg) override;
|
||||
|
||||
static std::set<Verbosity> getSupportedVerbosities();
|
||||
|
||||
#if defined(CATCH_CONFIG_ENABLE_BENCHMARKING)
|
||||
@@ -58,4 +60,4 @@ namespace Catch {
|
||||
|
||||
} // end namespace Catch
|
||||
|
||||
#endif // TWOBLUECUBES_CATCH_MULTI_REPORTER_H_INCLUDED
|
||||
#endif // TWOBLUECUBES_CATCH_MULTI_REPORTER_H_INCLUDED
|
181
include/reporters/catch_reporter_sonarqube.hpp
Normal file
181
include/reporters/catch_reporter_sonarqube.hpp
Normal file
@@ -0,0 +1,181 @@
|
||||
/*
|
||||
* Created by Daniel Garcia on 2018-12-04.
|
||||
* Copyright Social Point SL. All rights reserved.
|
||||
*
|
||||
* Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
* file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
*/
|
||||
#ifndef CATCH_REPORTER_SONARQUBE_HPP_INCLUDED
|
||||
#define CATCH_REPORTER_SONARQUBE_HPP_INCLUDED
|
||||
|
||||
|
||||
// Don't #include any Catch headers here - we can assume they are already
|
||||
// included before this header.
|
||||
// This is not good practice in general but is necessary in this case so this
|
||||
// file can be distributed as a single header that works with the main
|
||||
// Catch single header.
|
||||
|
||||
#include <map>
|
||||
|
||||
namespace Catch {
|
||||
|
||||
struct SonarQubeReporter : CumulativeReporterBase<SonarQubeReporter> {
|
||||
|
||||
SonarQubeReporter(ReporterConfig const& config)
|
||||
: CumulativeReporterBase(config)
|
||||
, xml(config.stream()) {
|
||||
m_reporterPrefs.shouldRedirectStdOut = true;
|
||||
m_reporterPrefs.shouldReportAllAssertions = true;
|
||||
}
|
||||
|
||||
~SonarQubeReporter() override;
|
||||
|
||||
static std::string getDescription() {
|
||||
return "Reports test results in the Generic Test Data SonarQube XML format";
|
||||
}
|
||||
|
||||
static std::set<Verbosity> getSupportedVerbosities() {
|
||||
return { Verbosity::Normal };
|
||||
}
|
||||
|
||||
void noMatchingTestCases(std::string const& /*spec*/) override {}
|
||||
|
||||
void testRunStarting(TestRunInfo const& testRunInfo) override {
|
||||
CumulativeReporterBase::testRunStarting(testRunInfo);
|
||||
xml.startElement("testExecutions");
|
||||
xml.writeAttribute("version", "1");
|
||||
}
|
||||
|
||||
void testGroupEnded(TestGroupStats const& testGroupStats) override {
|
||||
CumulativeReporterBase::testGroupEnded(testGroupStats);
|
||||
writeGroup(*m_testGroups.back());
|
||||
}
|
||||
|
||||
void testRunEndedCumulative() override {
|
||||
xml.endElement();
|
||||
}
|
||||
|
||||
void writeGroup(TestGroupNode const& groupNode) {
|
||||
std::map<std::string, TestGroupNode::ChildNodes> testsPerFile;
|
||||
for(auto const& child : groupNode.children)
|
||||
testsPerFile[child->value.testInfo.lineInfo.file].push_back(child);
|
||||
|
||||
for(auto const& kv : testsPerFile)
|
||||
writeTestFile(kv.first.c_str(), kv.second);
|
||||
}
|
||||
|
||||
void writeTestFile(const char* filename, TestGroupNode::ChildNodes const& testCaseNodes) {
|
||||
XmlWriter::ScopedElement e = xml.scopedElement("file");
|
||||
xml.writeAttribute("path", filename);
|
||||
|
||||
for(auto const& child : testCaseNodes)
|
||||
writeTestCase(*child);
|
||||
}
|
||||
|
||||
void writeTestCase(TestCaseNode const& testCaseNode) {
|
||||
// All test cases have exactly one section - which represents the
|
||||
// test case itself. That section may have 0-n nested sections
|
||||
assert(testCaseNode.children.size() == 1);
|
||||
SectionNode const& rootSection = *testCaseNode.children.front();
|
||||
writeSection("", rootSection, testCaseNode.value.testInfo.okToFail());
|
||||
}
|
||||
|
||||
void writeSection(std::string const& rootName, SectionNode const& sectionNode, bool okToFail) {
|
||||
std::string name = trim(sectionNode.stats.sectionInfo.name);
|
||||
if(!rootName.empty())
|
||||
name = rootName + '/' + name;
|
||||
|
||||
if(!sectionNode.assertions.empty() || !sectionNode.stdOut.empty() || !sectionNode.stdErr.empty()) {
|
||||
XmlWriter::ScopedElement e = xml.scopedElement("testCase");
|
||||
xml.writeAttribute("name", name);
|
||||
xml.writeAttribute("duration", static_cast<long>(sectionNode.stats.durationInSeconds * 1000));
|
||||
|
||||
writeAssertions(sectionNode, okToFail);
|
||||
}
|
||||
|
||||
for(auto const& childNode : sectionNode.childSections)
|
||||
writeSection(name, *childNode, okToFail);
|
||||
}
|
||||
|
||||
void writeAssertions(SectionNode const& sectionNode, bool okToFail) {
|
||||
for(auto const& assertion : sectionNode.assertions)
|
||||
writeAssertion( assertion, okToFail);
|
||||
}
|
||||
|
||||
void writeAssertion(AssertionStats const& stats, bool okToFail) {
|
||||
AssertionResult const& result = stats.assertionResult;
|
||||
if(!result.isOk()) {
|
||||
std::string elementName;
|
||||
if(okToFail) {
|
||||
elementName = "skipped";
|
||||
}
|
||||
else {
|
||||
switch(result.getResultType()) {
|
||||
case ResultWas::ThrewException:
|
||||
case ResultWas::FatalErrorCondition:
|
||||
elementName = "error";
|
||||
break;
|
||||
case ResultWas::ExplicitFailure:
|
||||
elementName = "failure";
|
||||
break;
|
||||
case ResultWas::ExpressionFailed:
|
||||
elementName = "failure";
|
||||
break;
|
||||
case ResultWas::DidntThrowException:
|
||||
elementName = "failure";
|
||||
break;
|
||||
|
||||
// We should never see these here:
|
||||
case ResultWas::Info:
|
||||
case ResultWas::Warning:
|
||||
case ResultWas::Ok:
|
||||
case ResultWas::Unknown:
|
||||
case ResultWas::FailureBit:
|
||||
case ResultWas::Exception:
|
||||
elementName = "internalError";
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
XmlWriter::ScopedElement e = xml.scopedElement(elementName);
|
||||
|
||||
ReusableStringStream messageRss;
|
||||
messageRss << result.getTestMacroName() << "(" << result.getExpression() << ")";
|
||||
xml.writeAttribute("message", messageRss.str());
|
||||
|
||||
ReusableStringStream textRss;
|
||||
if (stats.totals.assertions.total() > 0) {
|
||||
textRss << "FAILED:\n";
|
||||
if (result.hasExpression()) {
|
||||
textRss << "\t" << result.getExpressionInMacro() << "\n";
|
||||
}
|
||||
if (result.hasExpandedExpression()) {
|
||||
textRss << "with expansion:\n\t" << result.getExpandedExpression() << "\n";
|
||||
}
|
||||
}
|
||||
|
||||
if(!result.getMessage().empty())
|
||||
textRss << result.getMessage() << "\n";
|
||||
|
||||
for(auto const& msg : stats.infoMessages)
|
||||
if(msg.type == ResultWas::Info)
|
||||
textRss << msg.message << "\n";
|
||||
|
||||
textRss << "at " << result.getSourceInfo();
|
||||
xml.writeText(textRss.str(), XmlFormatting::Newline);
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
XmlWriter xml;
|
||||
};
|
||||
|
||||
#ifdef CATCH_IMPL
|
||||
SonarQubeReporter::~SonarQubeReporter() {}
|
||||
#endif
|
||||
|
||||
CATCH_REGISTER_REPORTER( "sonarqube", SonarQubeReporter )
|
||||
|
||||
} // end namespace Catch
|
||||
|
||||
#endif // CATCH_REPORTER_SONARQUBE_HPP_INCLUDED
|
@@ -193,9 +193,9 @@ namespace Catch {
|
||||
e.writeAttribute( "durationInSeconds", m_testCaseTimer.getElapsedSeconds() );
|
||||
|
||||
if( !testCaseStats.stdOut.empty() )
|
||||
m_xml.scopedElement( "StdOut" ).writeText( trim( testCaseStats.stdOut ), false );
|
||||
m_xml.scopedElement( "StdOut" ).writeText( trim( testCaseStats.stdOut ), XmlFormatting::Newline );
|
||||
if( !testCaseStats.stdErr.empty() )
|
||||
m_xml.scopedElement( "StdErr" ).writeText( trim( testCaseStats.stdErr ), false );
|
||||
m_xml.scopedElement( "StdErr" ).writeText( trim( testCaseStats.stdErr ), XmlFormatting::Newline );
|
||||
|
||||
m_xml.endElement();
|
||||
}
|
||||
|
@@ -282,6 +282,7 @@ set(REPORTER_HEADERS
|
||||
${HEADER_DIR}/reporters/catch_reporter_tap.hpp
|
||||
${HEADER_DIR}/reporters/catch_reporter_teamcity.hpp
|
||||
${HEADER_DIR}/reporters/catch_reporter_xml.h
|
||||
${HEADER_DIR}/reporters/catch_reporter_sonarqube.hpp
|
||||
)
|
||||
set(REPORTER_SOURCES
|
||||
${HEADER_DIR}/reporters/catch_reporter_bases.cpp
|
||||
@@ -435,11 +436,20 @@ set_tests_properties(FilenameAsTagsTest PROPERTIES PASS_REGULAR_EXPRESSION "\\[#
|
||||
add_test(NAME EscapeSpecialCharactersInTestNames COMMAND $<TARGET_FILE:SelfTest> "Test with special\\, characters \"in name")
|
||||
set_tests_properties(EscapeSpecialCharactersInTestNames PROPERTIES PASS_REGULAR_EXPRESSION "1 assertion in 1 test case")
|
||||
|
||||
add_test(NAME SpecialCharactersInTestNamesFromFile COMMAND $<TARGET_FILE:SelfTest> "-f ${CATCH_DIR}/projects/SelfTest/Misc/special-characters-in-file.input")
|
||||
set_tests_properties(SpecialCharactersInTestNamesFromFile PROPERTIES PASS_REGULAR_EXPRESSION "1 assertion in 1 test case")
|
||||
add_test(NAME TestsInFile::SimpleSpecs COMMAND $<TARGET_FILE:SelfTest> "-f ${CATCH_DIR}/projects/SelfTest/Misc/plain-old-tests.input")
|
||||
set_tests_properties(TestsInFile::SimpleSpecs PROPERTIES PASS_REGULAR_EXPRESSION "6 assertions in 2 test cases")
|
||||
|
||||
add_test(NAME RunningTestsFromFile COMMAND $<TARGET_FILE:SelfTest> "-f ${CATCH_DIR}/projects/SelfTest/Misc/plain-old-tests.input")
|
||||
set_tests_properties(RunningTestsFromFile PROPERTIES PASS_REGULAR_EXPRESSION "6 assertions in 2 test cases")
|
||||
add_test(NAME TestsInFile::EscapeSpecialCharacters COMMAND $<TARGET_FILE:SelfTest> "-f ${CATCH_DIR}/projects/SelfTest/Misc/special-characters-in-file.input")
|
||||
set_tests_properties(TestsInFile::EscapeSpecialCharacters PROPERTIES PASS_REGULAR_EXPRESSION "1 assertion in 1 test case")
|
||||
|
||||
# CTest does not allow us to create an AND of required regular expressions,
|
||||
# so we have to split the test into 2 parts and look for parts of the expected
|
||||
# output separately.
|
||||
add_test(NAME TestsInFile::InvalidTestNames-1 COMMAND $<TARGET_FILE:SelfTest> "-f ${CATCH_DIR}/projects/SelfTest/Misc/invalid-test-names.input")
|
||||
set_tests_properties(TestsInFile::InvalidTestNames-1 PROPERTIES PASS_REGULAR_EXPRESSION "Invalid Filter: \"Test with special, characters in \\\\\" name\"")
|
||||
|
||||
add_test(NAME TestsInFile::InvalidTestNames-2 COMMAND $<TARGET_FILE:SelfTest> "-f ${CATCH_DIR}/projects/SelfTest/Misc/invalid-test-names.input")
|
||||
set_tests_properties(TestsInFile::InvalidTestNames-2 PROPERTIES PASS_REGULAR_EXPRESSION "No tests ran")
|
||||
|
||||
|
||||
if (CATCH_USE_VALGRIND)
|
||||
|
@@ -126,6 +126,16 @@ set_tests_properties(
|
||||
PASS_REGULAR_EXPRESSION "benchmark name samples iterations estimated"
|
||||
)
|
||||
|
||||
# This test touches windows.h, so it should only be compiled under msvc
|
||||
if (MSVC)
|
||||
# This test fails if it does not compile and succeeds otherwise
|
||||
add_executable(WindowsHeader ${TESTS_DIR}/X90-WindowsHeaderInclusion.cpp)
|
||||
set_property( TARGET WindowsHeader PROPERTY CXX_STANDARD 11 )
|
||||
set_property( TARGET WindowsHeader PROPERTY CXX_STANDARD_REQUIRED ON )
|
||||
set_property( TARGET WindowsHeader PROPERTY CXX_EXTENSIONS OFF )
|
||||
target_include_directories( WindowsHeader PRIVATE ${SINGLE_INCLUDE_PATH} )
|
||||
add_test(NAME WindowsHeader COMMAND WindowsHeader -r compact)
|
||||
endif()
|
||||
|
||||
set( EXTRA_TEST_BINARIES
|
||||
PrefixedMacros
|
||||
@@ -145,3 +155,4 @@ foreach( test ${EXTRA_TEST_BINARIES} )
|
||||
target_include_directories( ${test} PRIVATE ${SINGLE_INCLUDE_PATH} )
|
||||
endforeach()
|
||||
|
||||
|
||||
|
@@ -26,14 +26,6 @@ TEST_CASE("Benchmark factorial", "[benchmark]") {
|
||||
BENCHMARK("factorial 14") {
|
||||
return factorial(14);
|
||||
};
|
||||
//
|
||||
// BENCHMARK("factorial 20") {
|
||||
// return factorial(20);
|
||||
// };
|
||||
//
|
||||
// BENCHMARK("factorial 35") {
|
||||
// return factorial(35);
|
||||
// };
|
||||
}
|
||||
|
||||
TEST_CASE("Benchmark containers", "[.][benchmark]") {
|
||||
|
12
projects/ExtraTests/X90-WindowsHeaderInclusion.cpp
Normal file
12
projects/ExtraTests/X90-WindowsHeaderInclusion.cpp
Normal file
@@ -0,0 +1,12 @@
|
||||
// X90-WindowsHeaderInclusion.cpp
|
||||
// Test that the Catch2 header compiles even after including windows.h
|
||||
// without defining NOMINMAX first. As an FYI, if you do that, you are
|
||||
// wrong.
|
||||
|
||||
#include <windows.h>
|
||||
#define CATCH_CONFIG_MAIN
|
||||
#include <catch2/catch.hpp>
|
||||
|
||||
TEST_CASE("Catch2 did survive compilation with windows.h", "[compile-test]") {
|
||||
SUCCEED();
|
||||
}
|
@@ -424,14 +424,15 @@ Matchers.tests.cpp:<line number>: passed: 11., !WithinAbs(10., 0.5) for: 11.0 no
|
||||
Matchers.tests.cpp:<line number>: passed: 10., !WithinAbs(11., 0.5) for: 10.0 not is within 0.5 of 11.0
|
||||
Matchers.tests.cpp:<line number>: passed: -10., WithinAbs(-10., 0.5) for: -10.0 is within 0.5 of -10.0
|
||||
Matchers.tests.cpp:<line number>: passed: -10., WithinAbs(-9.6, 0.5) for: -10.0 is within 0.5 of -9.6
|
||||
Matchers.tests.cpp:<line number>: passed: 1., WithinULP(1., 0) for: 1.0 is within 0 ULPs of 1.0 ([1.00000000000000000, 1.00000000000000000])
|
||||
Matchers.tests.cpp:<line number>: passed: nextafter(1., 2.), WithinULP(1., 1) for: 1.0 is within 1 ULPs of 1.0 ([0.99999999999999989, 1.00000000000000022])
|
||||
Matchers.tests.cpp:<line number>: passed: nextafter(1., 0.), WithinULP(1., 1) for: 1.0 is within 1 ULPs of 1.0 ([0.99999999999999989, 1.00000000000000022])
|
||||
Matchers.tests.cpp:<line number>: passed: nextafter(1., 2.), !WithinULP(1., 0) for: 1.0 not is within 0 ULPs of 1.0 ([1.00000000000000000, 1.00000000000000000])
|
||||
Matchers.tests.cpp:<line number>: passed: 1., WithinULP(1., 0) for: 1.0 is within 0 ULPs of 1.0 ([1.00000000000000000, 1.00000000000000000])
|
||||
Matchers.tests.cpp:<line number>: passed: -0., WithinULP(0., 0) for: -0.0 is within 0 ULPs of 0.0 ([0.00000000000000000, 0.00000000000000000])
|
||||
Matchers.tests.cpp:<line number>: passed: 1., WithinAbs(1., 0.5) || WithinULP(2., 1) for: 1.0 ( is within 0.5 of 1.0 or is within 1 ULPs of 2.0 ([1.99999999999999978, 2.00000000000000044]) )
|
||||
Matchers.tests.cpp:<line number>: passed: 1., WithinAbs(2., 0.5) || WithinULP(1., 0) for: 1.0 ( is within 0.5 of 2.0 or is within 0 ULPs of 1.0 ([1.00000000000000000, 1.00000000000000000]) )
|
||||
Matchers.tests.cpp:<line number>: passed: 1., WithinULP(1., 0) for: 1.0 is within 0 ULPs of 1.0000000000000000e+00 ([1.0000000000000000e+00, 1.0000000000000000e+00])
|
||||
Matchers.tests.cpp:<line number>: passed: nextafter(1., 2.), WithinULP(1., 1) for: 1.0 is within 1 ULPs of 1.0000000000000000e+00 ([9.9999999999999989e-01, 1.0000000000000002e+00])
|
||||
Matchers.tests.cpp:<line number>: passed: 0., WithinULP(nextafter(0., 1.), 1) for: 0.0 is within 1 ULPs of 4.9406564584124654e-324 ([0.0000000000000000e+00, 9.8813129168249309e-324])
|
||||
Matchers.tests.cpp:<line number>: passed: 1., WithinULP(nextafter(1., 0.), 1) for: 1.0 is within 1 ULPs of 9.9999999999999989e-01 ([9.9999999999999978e-01, 1.0000000000000000e+00])
|
||||
Matchers.tests.cpp:<line number>: passed: 1., !WithinULP(nextafter(1., 2.), 0) for: 1.0 not is within 0 ULPs of 1.0000000000000002e+00 ([1.0000000000000002e+00, 1.0000000000000002e+00])
|
||||
Matchers.tests.cpp:<line number>: passed: 1., WithinULP(1., 0) for: 1.0 is within 0 ULPs of 1.0000000000000000e+00 ([1.0000000000000000e+00, 1.0000000000000000e+00])
|
||||
Matchers.tests.cpp:<line number>: passed: -0., WithinULP(0., 0) for: -0.0 is within 0 ULPs of 0.0000000000000000e+00 ([0.0000000000000000e+00, 0.0000000000000000e+00])
|
||||
Matchers.tests.cpp:<line number>: passed: 1., WithinAbs(1., 0.5) || WithinULP(2., 1) for: 1.0 ( is within 0.5 of 1.0 or is within 1 ULPs of 2.0000000000000000e+00 ([1.9999999999999998e+00, 2.0000000000000004e+00]) )
|
||||
Matchers.tests.cpp:<line number>: passed: 1., WithinAbs(2., 0.5) || WithinULP(1., 0) for: 1.0 ( is within 0.5 of 2.0 or is within 0 ULPs of 1.0000000000000000e+00 ([1.0000000000000000e+00, 1.0000000000000000e+00]) )
|
||||
Matchers.tests.cpp:<line number>: passed: 0.0001, WithinAbs(0., 0.001) || WithinRel(0., 0.1) for: 0.0001 ( is within 0.001 of 0.0 or and 0 are within 10% of each other )
|
||||
Matchers.tests.cpp:<line number>: passed: WithinAbs(1., 0.)
|
||||
Matchers.tests.cpp:<line number>: passed: WithinAbs(1., -1.), std::domain_error
|
||||
@@ -453,14 +454,15 @@ Matchers.tests.cpp:<line number>: passed: 11.f, !WithinAbs(10.f, 0.5f) for: 11.0
|
||||
Matchers.tests.cpp:<line number>: passed: 10.f, !WithinAbs(11.f, 0.5f) for: 10.0f not is within 0.5 of 11.0
|
||||
Matchers.tests.cpp:<line number>: passed: -10.f, WithinAbs(-10.f, 0.5f) for: -10.0f is within 0.5 of -10.0
|
||||
Matchers.tests.cpp:<line number>: passed: -10.f, WithinAbs(-9.6f, 0.5f) for: -10.0f is within 0.5 of -9.6000003815
|
||||
Matchers.tests.cpp:<line number>: passed: 1.f, WithinULP(1.f, 0) for: 1.0f is within 0 ULPs of 1.0f ([1.00000000000000000, 1.00000000000000000])
|
||||
Matchers.tests.cpp:<line number>: passed: nextafter(1.f, 2.f), WithinULP(1.f, 1) for: 1.0f is within 1 ULPs of 1.0f ([0.99999994039535522, 1.00000011920928955])
|
||||
Matchers.tests.cpp:<line number>: passed: nextafter(1.f, 0.f), WithinULP(1.f, 1) for: 1.0f is within 1 ULPs of 1.0f ([0.99999994039535522, 1.00000011920928955])
|
||||
Matchers.tests.cpp:<line number>: passed: nextafter(1.f, 2.f), !WithinULP(1.f, 0) for: 1.0f not is within 0 ULPs of 1.0f ([1.00000000000000000, 1.00000000000000000])
|
||||
Matchers.tests.cpp:<line number>: passed: 1.f, WithinULP(1.f, 0) for: 1.0f is within 0 ULPs of 1.0f ([1.00000000000000000, 1.00000000000000000])
|
||||
Matchers.tests.cpp:<line number>: passed: -0.f, WithinULP(0.f, 0) for: -0.0f is within 0 ULPs of 0.0f ([0.00000000000000000, 0.00000000000000000])
|
||||
Matchers.tests.cpp:<line number>: passed: 1.f, WithinAbs(1.f, 0.5) || WithinULP(1.f, 1) for: 1.0f ( is within 0.5 of 1.0 or is within 1 ULPs of 1.0f ([0.99999994039535522, 1.00000011920928955]) )
|
||||
Matchers.tests.cpp:<line number>: passed: 1.f, WithinAbs(2.f, 0.5) || WithinULP(1.f, 0) for: 1.0f ( is within 0.5 of 2.0 or is within 0 ULPs of 1.0f ([1.00000000000000000, 1.00000000000000000]) )
|
||||
Matchers.tests.cpp:<line number>: passed: 1.f, WithinULP(1.f, 0) for: 1.0f is within 0 ULPs of 1.00000000e+00f ([1.00000000e+00, 1.00000000e+00])
|
||||
Matchers.tests.cpp:<line number>: passed: nextafter(1.f, 2.f), WithinULP(1.f, 1) for: 1.0f is within 1 ULPs of 1.00000000e+00f ([9.99999940e-01, 1.00000012e+00])
|
||||
Matchers.tests.cpp:<line number>: passed: 0.f, WithinULP(nextafter(0.f, 1.f), 1) for: 0.0f is within 1 ULPs of 1.40129846e-45f ([0.00000000e+00, 2.80259693e-45])
|
||||
Matchers.tests.cpp:<line number>: passed: 1.f, WithinULP(nextafter(1.f, 0.f), 1) for: 1.0f is within 1 ULPs of 9.99999940e-01f ([9.99999881e-01, 1.00000000e+00])
|
||||
Matchers.tests.cpp:<line number>: passed: 1.f, !WithinULP(nextafter(1.f, 2.f), 0) for: 1.0f not is within 0 ULPs of 1.00000012e+00f ([1.00000012e+00, 1.00000012e+00])
|
||||
Matchers.tests.cpp:<line number>: passed: 1.f, WithinULP(1.f, 0) for: 1.0f is within 0 ULPs of 1.00000000e+00f ([1.00000000e+00, 1.00000000e+00])
|
||||
Matchers.tests.cpp:<line number>: passed: -0.f, WithinULP(0.f, 0) for: -0.0f is within 0 ULPs of 0.00000000e+00f ([0.00000000e+00, 0.00000000e+00])
|
||||
Matchers.tests.cpp:<line number>: passed: 1.f, WithinAbs(1.f, 0.5) || WithinULP(1.f, 1) for: 1.0f ( is within 0.5 of 1.0 or is within 1 ULPs of 1.00000000e+00f ([9.99999940e-01, 1.00000012e+00]) )
|
||||
Matchers.tests.cpp:<line number>: passed: 1.f, WithinAbs(2.f, 0.5) || WithinULP(1.f, 0) for: 1.0f ( is within 0.5 of 2.0 or is within 0 ULPs of 1.00000000e+00f ([1.00000000e+00, 1.00000000e+00]) )
|
||||
Matchers.tests.cpp:<line number>: passed: 0.0001f, WithinAbs(0.f, 0.001f) || WithinRel(0.f, 0.1f) for: 0.0001f ( is within 0.001 of 0.0 or and 0 are within 10% of each other )
|
||||
Matchers.tests.cpp:<line number>: passed: WithinAbs(1.f, 0.f)
|
||||
Matchers.tests.cpp:<line number>: passed: WithinAbs(1.f, -1.f), std::domain_error
|
||||
@@ -629,6 +631,74 @@ GeneratorsImpl.tests.cpp:<line number>: passed: gen.get() == 2 for: 2 == 2
|
||||
GeneratorsImpl.tests.cpp:<line number>: passed: gen.next() for: true
|
||||
GeneratorsImpl.tests.cpp:<line number>: passed: gen.get() == 5 for: 5 == 5
|
||||
GeneratorsImpl.tests.cpp:<line number>: passed: !(gen.next()) for: !false
|
||||
GeneratorsImpl.tests.cpp:<line number>: passed: gen.get() == Approx(expected) for: -1.0 == Approx( -1.0 ) with 1 message: 'Current expected value is -1'
|
||||
GeneratorsImpl.tests.cpp:<line number>: passed: gen.next() for: true with 1 message: 'Current expected value is -1'
|
||||
GeneratorsImpl.tests.cpp:<line number>: passed: gen.get() == Approx(expected) for: -0.9 == Approx( -0.9 ) with 1 message: 'Current expected value is -0.9'
|
||||
GeneratorsImpl.tests.cpp:<line number>: passed: gen.next() for: true with 1 message: 'Current expected value is -0.9'
|
||||
GeneratorsImpl.tests.cpp:<line number>: passed: gen.get() == Approx(expected) for: -0.8 == Approx( -0.8 ) with 1 message: 'Current expected value is -0.8'
|
||||
GeneratorsImpl.tests.cpp:<line number>: passed: gen.next() for: true with 1 message: 'Current expected value is -0.8'
|
||||
GeneratorsImpl.tests.cpp:<line number>: passed: gen.get() == Approx(expected) for: -0.7 == Approx( -0.7 ) with 1 message: 'Current expected value is -0.7'
|
||||
GeneratorsImpl.tests.cpp:<line number>: passed: gen.next() for: true with 1 message: 'Current expected value is -0.7'
|
||||
GeneratorsImpl.tests.cpp:<line number>: passed: gen.get() == Approx(expected) for: -0.6 == Approx( -0.6 ) with 1 message: 'Current expected value is -0.6'
|
||||
GeneratorsImpl.tests.cpp:<line number>: passed: gen.next() for: true with 1 message: 'Current expected value is -0.6'
|
||||
GeneratorsImpl.tests.cpp:<line number>: passed: gen.get() == Approx(expected) for: -0.5 == Approx( -0.5 ) with 1 message: 'Current expected value is -0.5'
|
||||
GeneratorsImpl.tests.cpp:<line number>: passed: gen.next() for: true with 1 message: 'Current expected value is -0.5'
|
||||
GeneratorsImpl.tests.cpp:<line number>: passed: gen.get() == Approx(expected) for: -0.4 == Approx( -0.4 ) with 1 message: 'Current expected value is -0.4'
|
||||
GeneratorsImpl.tests.cpp:<line number>: passed: gen.next() for: true with 1 message: 'Current expected value is -0.4'
|
||||
GeneratorsImpl.tests.cpp:<line number>: passed: gen.get() == Approx(expected) for: -0.3 == Approx( -0.3 ) with 1 message: 'Current expected value is -0.3'
|
||||
GeneratorsImpl.tests.cpp:<line number>: passed: gen.next() for: true with 1 message: 'Current expected value is -0.3'
|
||||
GeneratorsImpl.tests.cpp:<line number>: passed: gen.get() == Approx(expected) for: -0.2 == Approx( -0.2 ) with 1 message: 'Current expected value is -0.2'
|
||||
GeneratorsImpl.tests.cpp:<line number>: passed: gen.next() for: true with 1 message: 'Current expected value is -0.2'
|
||||
GeneratorsImpl.tests.cpp:<line number>: passed: gen.get() == Approx(expected) for: -0.1 == Approx( -0.1 ) with 1 message: 'Current expected value is -0.1'
|
||||
GeneratorsImpl.tests.cpp:<line number>: passed: gen.next() for: true with 1 message: 'Current expected value is -0.1'
|
||||
GeneratorsImpl.tests.cpp:<line number>: passed: gen.get() == Approx(expected) for: -0.0 == Approx( -0.0 ) with 1 message: 'Current expected value is -1.38778e-16'
|
||||
GeneratorsImpl.tests.cpp:<line number>: passed: gen.next() for: true with 1 message: 'Current expected value is -1.38778e-16'
|
||||
GeneratorsImpl.tests.cpp:<line number>: passed: gen.get() == Approx(expected) for: 0.1 == Approx( 0.1 ) with 1 message: 'Current expected value is 0.1'
|
||||
GeneratorsImpl.tests.cpp:<line number>: passed: gen.next() for: true with 1 message: 'Current expected value is 0.1'
|
||||
GeneratorsImpl.tests.cpp:<line number>: passed: gen.get() == Approx(expected) for: 0.2 == Approx( 0.2 ) with 1 message: 'Current expected value is 0.2'
|
||||
GeneratorsImpl.tests.cpp:<line number>: passed: gen.next() for: true with 1 message: 'Current expected value is 0.2'
|
||||
GeneratorsImpl.tests.cpp:<line number>: passed: gen.get() == Approx(expected) for: 0.3 == Approx( 0.3 ) with 1 message: 'Current expected value is 0.3'
|
||||
GeneratorsImpl.tests.cpp:<line number>: passed: gen.next() for: true with 1 message: 'Current expected value is 0.3'
|
||||
GeneratorsImpl.tests.cpp:<line number>: passed: gen.get() == Approx(expected) for: 0.4 == Approx( 0.4 ) with 1 message: 'Current expected value is 0.4'
|
||||
GeneratorsImpl.tests.cpp:<line number>: passed: gen.next() for: true with 1 message: 'Current expected value is 0.4'
|
||||
GeneratorsImpl.tests.cpp:<line number>: passed: gen.get() == Approx(expected) for: 0.5 == Approx( 0.5 ) with 1 message: 'Current expected value is 0.5'
|
||||
GeneratorsImpl.tests.cpp:<line number>: passed: gen.next() for: true with 1 message: 'Current expected value is 0.5'
|
||||
GeneratorsImpl.tests.cpp:<line number>: passed: gen.get() == Approx(expected) for: 0.6 == Approx( 0.6 ) with 1 message: 'Current expected value is 0.6'
|
||||
GeneratorsImpl.tests.cpp:<line number>: passed: gen.next() for: true with 1 message: 'Current expected value is 0.6'
|
||||
GeneratorsImpl.tests.cpp:<line number>: passed: gen.get() == Approx(expected) for: 0.7 == Approx( 0.7 ) with 1 message: 'Current expected value is 0.7'
|
||||
GeneratorsImpl.tests.cpp:<line number>: passed: gen.next() for: true with 1 message: 'Current expected value is 0.7'
|
||||
GeneratorsImpl.tests.cpp:<line number>: passed: gen.get() == Approx(expected) for: 0.8 == Approx( 0.8 ) with 1 message: 'Current expected value is 0.8'
|
||||
GeneratorsImpl.tests.cpp:<line number>: passed: gen.next() for: true with 1 message: 'Current expected value is 0.8'
|
||||
GeneratorsImpl.tests.cpp:<line number>: passed: gen.get() == Approx(expected) for: 0.9 == Approx( 0.9 ) with 1 message: 'Current expected value is 0.9'
|
||||
GeneratorsImpl.tests.cpp:<line number>: passed: gen.next() for: true with 1 message: 'Current expected value is 0.9'
|
||||
GeneratorsImpl.tests.cpp:<line number>: passed: gen.get() == Approx( rangeEnd ) for: 1.0 == Approx( 1.0 )
|
||||
GeneratorsImpl.tests.cpp:<line number>: passed: !(gen.next()) for: !false
|
||||
GeneratorsImpl.tests.cpp:<line number>: passed: gen.get() == Approx(expected) for: -1.0 == Approx( -1.0 ) with 1 message: 'Current expected value is -1'
|
||||
GeneratorsImpl.tests.cpp:<line number>: passed: gen.next() for: true with 1 message: 'Current expected value is -1'
|
||||
GeneratorsImpl.tests.cpp:<line number>: passed: gen.get() == Approx(expected) for: -0.7 == Approx( -0.7 ) with 1 message: 'Current expected value is -0.7'
|
||||
GeneratorsImpl.tests.cpp:<line number>: passed: gen.next() for: true with 1 message: 'Current expected value is -0.7'
|
||||
GeneratorsImpl.tests.cpp:<line number>: passed: gen.get() == Approx(expected) for: -0.4 == Approx( -0.4 ) with 1 message: 'Current expected value is -0.4'
|
||||
GeneratorsImpl.tests.cpp:<line number>: passed: gen.next() for: true with 1 message: 'Current expected value is -0.4'
|
||||
GeneratorsImpl.tests.cpp:<line number>: passed: gen.get() == Approx(expected) for: -0.1 == Approx( -0.1 ) with 1 message: 'Current expected value is -0.1'
|
||||
GeneratorsImpl.tests.cpp:<line number>: passed: gen.next() for: true with 1 message: 'Current expected value is -0.1'
|
||||
GeneratorsImpl.tests.cpp:<line number>: passed: gen.get() == Approx(expected) for: 0.2 == Approx( 0.2 ) with 1 message: 'Current expected value is 0.2'
|
||||
GeneratorsImpl.tests.cpp:<line number>: passed: gen.next() for: true with 1 message: 'Current expected value is 0.2'
|
||||
GeneratorsImpl.tests.cpp:<line number>: passed: gen.get() == Approx(expected) for: 0.5 == Approx( 0.5 ) with 1 message: 'Current expected value is 0.5'
|
||||
GeneratorsImpl.tests.cpp:<line number>: passed: gen.next() for: true with 1 message: 'Current expected value is 0.5'
|
||||
GeneratorsImpl.tests.cpp:<line number>: passed: !(gen.next()) for: !false
|
||||
GeneratorsImpl.tests.cpp:<line number>: passed: gen.get() == Approx(expected) for: -1.0 == Approx( -1.0 ) with 1 message: 'Current expected value is -1'
|
||||
GeneratorsImpl.tests.cpp:<line number>: passed: gen.next() for: true with 1 message: 'Current expected value is -1'
|
||||
GeneratorsImpl.tests.cpp:<line number>: passed: gen.get() == Approx(expected) for: -0.7 == Approx( -0.7 ) with 1 message: 'Current expected value is -0.7'
|
||||
GeneratorsImpl.tests.cpp:<line number>: passed: gen.next() for: true with 1 message: 'Current expected value is -0.7'
|
||||
GeneratorsImpl.tests.cpp:<line number>: passed: gen.get() == Approx(expected) for: -0.4 == Approx( -0.4 ) with 1 message: 'Current expected value is -0.4'
|
||||
GeneratorsImpl.tests.cpp:<line number>: passed: gen.next() for: true with 1 message: 'Current expected value is -0.4'
|
||||
GeneratorsImpl.tests.cpp:<line number>: passed: gen.get() == Approx(expected) for: -0.1 == Approx( -0.1 ) with 1 message: 'Current expected value is -0.1'
|
||||
GeneratorsImpl.tests.cpp:<line number>: passed: gen.next() for: true with 1 message: 'Current expected value is -0.1'
|
||||
GeneratorsImpl.tests.cpp:<line number>: passed: gen.get() == Approx(expected) for: 0.2 == Approx( 0.2 ) with 1 message: 'Current expected value is 0.2'
|
||||
GeneratorsImpl.tests.cpp:<line number>: passed: gen.next() for: true with 1 message: 'Current expected value is 0.2'
|
||||
GeneratorsImpl.tests.cpp:<line number>: passed: gen.get() == Approx(expected) for: 0.5 == Approx( 0.5 ) with 1 message: 'Current expected value is 0.5'
|
||||
GeneratorsImpl.tests.cpp:<line number>: passed: gen.next() for: true with 1 message: 'Current expected value is 0.5'
|
||||
GeneratorsImpl.tests.cpp:<line number>: passed: !(gen.next()) for: !false
|
||||
GeneratorsImpl.tests.cpp:<line number>: passed: gen.get() == 5 for: 5 == 5
|
||||
GeneratorsImpl.tests.cpp:<line number>: passed: gen.next() for: true
|
||||
GeneratorsImpl.tests.cpp:<line number>: passed: gen.get() == 2 for: 2 == 2
|
||||
@@ -957,6 +1027,12 @@ CmdLine.tests.cpp:<line number>: passed: spec.matches( fakeTestCase( " aardvark
|
||||
CmdLine.tests.cpp:<line number>: passed: spec.matches( fakeTestCase( " aardvark " ) ) for: true
|
||||
CmdLine.tests.cpp:<line number>: passed: spec.matches( fakeTestCase( "aardvark " ) ) for: true
|
||||
CmdLine.tests.cpp:<line number>: passed: spec.matches( fakeTestCase( "aardvark" ) ) for: true
|
||||
CmdLine.tests.cpp:<line number>: passed: spec.matches(fakeTestCase("hidden and foo", "[.][foo]")) for: true
|
||||
CmdLine.tests.cpp:<line number>: passed: !(spec.matches(fakeTestCase("only foo", "[foo]"))) for: !false
|
||||
CmdLine.tests.cpp:<line number>: passed: !(spec.matches(fakeTestCase("hidden and foo", "[.][foo]"))) for: !false
|
||||
CmdLine.tests.cpp:<line number>: passed: !(spec.matches(fakeTestCase("only foo", "[foo]"))) for: !false
|
||||
CmdLine.tests.cpp:<line number>: passed: !(spec.matches(fakeTestCase("only hidden", "[.]"))) for: !false
|
||||
CmdLine.tests.cpp:<line number>: passed: spec.matches(fakeTestCase("neither foo nor hidden", "[bar]")) for: true
|
||||
Condition.tests.cpp:<line number>: passed: p == 0 for: 0 == 0
|
||||
Condition.tests.cpp:<line number>: passed: p == pNULL for: 0 == 0
|
||||
Condition.tests.cpp:<line number>: passed: p != 0 for: 0x<hex digits> != 0
|
||||
@@ -1093,37 +1169,32 @@ Matchers.tests.cpp:<line number>: passed: testStringForMatching(), EndsWith("sub
|
||||
Matchers.tests.cpp:<line number>: passed: testStringForMatching(), EndsWith(" SuBsTrInG", Catch::CaseSensitive::No) for: "this string contains 'abc' as a substring" ends with: " substring" (case insensitive)
|
||||
String.tests.cpp:<line number>: passed: empty.empty() for: true
|
||||
String.tests.cpp:<line number>: passed: empty.size() == 0 for: 0 == 0
|
||||
String.tests.cpp:<line number>: passed: empty.isNullTerminated() for: true
|
||||
String.tests.cpp:<line number>: passed: std::strcmp( empty.c_str(), "" ) == 0 for: 0 == 0
|
||||
String.tests.cpp:<line number>: passed: s.empty() == false for: false == false
|
||||
String.tests.cpp:<line number>: passed: s.size() == 5 for: 5 == 5
|
||||
String.tests.cpp:<line number>: passed: isSubstring( s ) == false for: false == false
|
||||
String.tests.cpp:<line number>: passed: s.isNullTerminated() for: true
|
||||
String.tests.cpp:<line number>: passed: std::strcmp( rawChars, "hello" ) == 0 for: 0 == 0
|
||||
String.tests.cpp:<line number>: passed: isOwned( s ) == false for: false == false
|
||||
String.tests.cpp:<line number>: passed: s.c_str()
|
||||
String.tests.cpp:<line number>: passed: s.c_str() == rawChars for: "hello" == "hello"
|
||||
String.tests.cpp:<line number>: passed: isOwned( s ) == false for: false == false
|
||||
String.tests.cpp:<line number>: passed: s.data() == rawChars for: "hello" == "hello"
|
||||
String.tests.cpp:<line number>: passed: original == "original"
|
||||
String.tests.cpp:<line number>: passed: isSubstring( original ) for: true
|
||||
String.tests.cpp:<line number>: passed: isOwned( original ) == false for: false == false
|
||||
String.tests.cpp:<line number>: passed: isOwned( original ) for: true
|
||||
String.tests.cpp:<line number>: passed: !(original.isNullTerminated()) for: !false
|
||||
String.tests.cpp:<line number>: passed: original.c_str()
|
||||
String.tests.cpp:<line number>: passed: original.data()
|
||||
String.tests.cpp:<line number>: passed: ss.empty() == false for: false == false
|
||||
String.tests.cpp:<line number>: passed: ss.size() == 5 for: 5 == 5
|
||||
String.tests.cpp:<line number>: passed: std::strcmp( ss.c_str(), "hello" ) == 0 for: 0 == 0
|
||||
String.tests.cpp:<line number>: passed: std::strncmp( ss.data(), "hello", 5 ) == 0 for: 0 == 0
|
||||
String.tests.cpp:<line number>: passed: ss == "hello" for: hello == "hello"
|
||||
String.tests.cpp:<line number>: passed: isSubstring( ss ) for: true
|
||||
String.tests.cpp:<line number>: passed: isOwned( ss ) == false for: false == false
|
||||
String.tests.cpp:<line number>: passed: rawChars == s.currentData() for: "hello world!" == "hello world!"
|
||||
String.tests.cpp:<line number>: passed: ss.c_str() != rawChars for: "hello" != "hello world!"
|
||||
String.tests.cpp:<line number>: passed: isOwned( ss ) for: true
|
||||
String.tests.cpp:<line number>: passed: isOwned(ss) == false for: false == false
|
||||
String.tests.cpp:<line number>: passed: ss == "hello" for: hello == "hello"
|
||||
String.tests.cpp:<line number>: passed: rawChars == ss.currentData() for: "hello world!" == "hello world!"
|
||||
String.tests.cpp:<line number>: passed: ss.size() == 6 for: 6 == 6
|
||||
String.tests.cpp:<line number>: passed: std::strcmp( ss.c_str(), "world!" ) == 0 for: 0 == 0
|
||||
String.tests.cpp:<line number>: passed: s.c_str() == s2.c_str() for: "hello world!" == "hello world!"
|
||||
String.tests.cpp:<line number>: passed: s.c_str() != ss.c_str() for: "hello world!" != "hello"
|
||||
String.tests.cpp:<line number>: passed: s.data() == s2.data() for: "hello world!" == "hello world!"
|
||||
String.tests.cpp:<line number>: passed: s.data() == ss.data() for: "hello world!" == "hello world!"
|
||||
String.tests.cpp:<line number>: passed: s.substr(s.size() + 1, 123).empty() for: true
|
||||
String.tests.cpp:<line number>: passed: StringRef("hello") == StringRef("hello") for: hello == hello
|
||||
String.tests.cpp:<line number>: passed: StringRef("hello") != StringRef("cello") for: hello != cello
|
||||
String.tests.cpp:<line number>: passed: std::strcmp(ss.c_str(), "world!") == 0 for: 0 == 0
|
||||
String.tests.cpp:<line number>: passed: (char*)buffer1 != (char*)buffer2 for: "Hello" != "Hello"
|
||||
String.tests.cpp:<line number>: passed: left == right for: Hello == Hello
|
||||
String.tests.cpp:<line number>: passed: left != left.substr(0, 3) for: Hello != Hel
|
||||
String.tests.cpp:<line number>: passed: sr == "a standard string" for: a standard string == "a standard string"
|
||||
String.tests.cpp:<line number>: passed: sr.size() == stdStr.size() for: 17 == 17
|
||||
String.tests.cpp:<line number>: passed: sr == "a standard string" for: a standard string == "a standard string"
|
||||
@@ -1134,6 +1205,17 @@ String.tests.cpp:<line number>: passed: stdStr == "a stringref" for: "a stringre
|
||||
String.tests.cpp:<line number>: passed: stdStr.size() == sr.size() for: 11 == 11
|
||||
String.tests.cpp:<line number>: passed: stdStr == "a stringref" for: "a stringref" == "a stringref"
|
||||
String.tests.cpp:<line number>: passed: stdStr.size() == sr.size() for: 11 == 11
|
||||
String.tests.cpp:<line number>: passed: with 1 message: 'StringRef{}.size() == 0'
|
||||
String.tests.cpp:<line number>: passed: with 1 message: 'StringRef{ "abc", 3 }.size() == 3'
|
||||
String.tests.cpp:<line number>: passed: with 1 message: 'StringRef{ "abc", 3 }.isNullTerminated()'
|
||||
String.tests.cpp:<line number>: passed: with 1 message: 'StringRef{ "abc", 2 }.size() == 2'
|
||||
String.tests.cpp:<line number>: passed: with 1 message: '!(StringRef{ "abc", 2 }.isNullTerminated())'
|
||||
String.tests.cpp:<line number>: passed: with 1 message: '!(sr1.empty())'
|
||||
String.tests.cpp:<line number>: passed: with 1 message: 'sr1.size() == 3'
|
||||
String.tests.cpp:<line number>: passed: with 1 message: 'sr1.isNullTerminated()'
|
||||
String.tests.cpp:<line number>: passed: with 1 message: 'sr2.empty()'
|
||||
String.tests.cpp:<line number>: passed: with 1 message: 'sr2.size() == 0'
|
||||
String.tests.cpp:<line number>: passed: with 1 message: 'sr2.isNullTerminated()'
|
||||
ToStringChrono.tests.cpp:<line number>: passed: minute == seconds for: 1 m == 60 s
|
||||
ToStringChrono.tests.cpp:<line number>: passed: hour != seconds for: 1 h != 60 s
|
||||
ToStringChrono.tests.cpp:<line number>: passed: micro != milli for: 1 us != 1 ms
|
||||
@@ -1485,48 +1567,6 @@ Xml.tests.cpp:<line number>: passed: encode( stringWithQuotes, Catch::XmlEncode:
|
||||
"don't "quote" me on that"
|
||||
Xml.tests.cpp:<line number>: passed: encode( "[\x01]" ) == "[\\x01]" for: "[\x01]" == "[\x01]"
|
||||
Xml.tests.cpp:<line number>: passed: encode( "[\x7F]" ) == "[\\x7F]" for: "[\x7F]" == "[\x7F]"
|
||||
Xml.tests.cpp:<line number>: passed: encode(u8"Here be 👾") == u8"Here be 👾" for: "Here be 👾" == "Here be 👾"
|
||||
Xml.tests.cpp:<line number>: passed: encode(u8"šš") == u8"šš" for: "šš" == "šš"
|
||||
Xml.tests.cpp:<line number>: passed: encode("\xDF\xBF") == "\xDF\xBF" for: "߿" == "߿"
|
||||
Xml.tests.cpp:<line number>: passed: encode("\xE0\xA0\x80") == "\xE0\xA0\x80" for: "ࠀ" == "ࠀ"
|
||||
Xml.tests.cpp:<line number>: passed: encode("\xED\x9F\xBF") == "\xED\x9F\xBF" for: "" == ""
|
||||
Xml.tests.cpp:<line number>: passed: encode("\xEE\x80\x80") == "\xEE\x80\x80" for: "" == ""
|
||||
Xml.tests.cpp:<line number>: passed: encode("\xEF\xBF\xBF") == "\xEF\xBF\xBF" for: "" == ""
|
||||
Xml.tests.cpp:<line number>: passed: encode("\xF0\x90\x80\x80") == "\xF0\x90\x80\x80" for: "𐀀" == "𐀀"
|
||||
Xml.tests.cpp:<line number>: passed: encode("\xF4\x8F\xBF\xBF") == "\xF4\x8F\xBF\xBF" for: "" == ""
|
||||
Xml.tests.cpp:<line number>: passed: encode("Here \xFF be 👾") == u8"Here \\xFF be 👾" for: "Here \xFF be 👾" == "Here \xFF be 👾"
|
||||
Xml.tests.cpp:<line number>: passed: encode("\xFF") == "\\xFF" for: "\xFF" == "\xFF"
|
||||
Xml.tests.cpp:<line number>: passed: encode("\xC5\xC5\xA0") == u8"\\xC5Š" for: "\xC5Š" == "\xC5Š"
|
||||
Xml.tests.cpp:<line number>: passed: encode("\xF4\x90\x80\x80") == u8"\\xF4\\x90\\x80\\x80" for: "\xF4\x90\x80\x80" == "\xF4\x90\x80\x80"
|
||||
Xml.tests.cpp:<line number>: passed: encode("\xC0\x80") == u8"\\xC0\\x80" for: "\xC0\x80" == "\xC0\x80"
|
||||
Xml.tests.cpp:<line number>: passed: encode("\xF0\x80\x80\x80") == u8"\\xF0\\x80\\x80\\x80" for: "\xF0\x80\x80\x80" == "\xF0\x80\x80\x80"
|
||||
Xml.tests.cpp:<line number>: passed: encode("\xC1\xBF") == u8"\\xC1\\xBF" for: "\xC1\xBF" == "\xC1\xBF"
|
||||
Xml.tests.cpp:<line number>: passed: encode("\xE0\x9F\xBF") == u8"\\xE0\\x9F\\xBF" for: "\xE0\x9F\xBF" == "\xE0\x9F\xBF"
|
||||
Xml.tests.cpp:<line number>: passed: encode("\xF0\x8F\xBF\xBF") == u8"\\xF0\\x8F\\xBF\\xBF" for: "\xF0\x8F\xBF\xBF" == "\xF0\x8F\xBF\xBF"
|
||||
Xml.tests.cpp:<line number>: passed: encode("\xED\xA0\x80") == "\xED\xA0\x80" for: "<22><><EFBFBD>" == "<22><><EFBFBD>"
|
||||
Xml.tests.cpp:<line number>: passed: encode("\xED\xAF\xBF") == "\xED\xAF\xBF" for: "<22><><EFBFBD>" == "<22><><EFBFBD>"
|
||||
Xml.tests.cpp:<line number>: passed: encode("\xED\xB0\x80") == "\xED\xB0\x80" for: "<22><><EFBFBD>" == "<22><><EFBFBD>"
|
||||
Xml.tests.cpp:<line number>: passed: encode("\xED\xBF\xBF") == "\xED\xBF\xBF" for: "<22><><EFBFBD>" == "<22><><EFBFBD>"
|
||||
Xml.tests.cpp:<line number>: passed: encode("\x80") == u8"\\x80" for: "\x80" == "\x80"
|
||||
Xml.tests.cpp:<line number>: passed: encode("\x81") == u8"\\x81" for: "\x81" == "\x81"
|
||||
Xml.tests.cpp:<line number>: passed: encode("\xBC") == u8"\\xBC" for: "\xBC" == "\xBC"
|
||||
Xml.tests.cpp:<line number>: passed: encode("\xBF") == u8"\\xBF" for: "\xBF" == "\xBF"
|
||||
Xml.tests.cpp:<line number>: passed: encode("\xF5\x80\x80\x80") == u8"\\xF5\\x80\\x80\\x80" for: "\xF5\x80\x80\x80" == "\xF5\x80\x80\x80"
|
||||
Xml.tests.cpp:<line number>: passed: encode("\xF6\x80\x80\x80") == u8"\\xF6\\x80\\x80\\x80" for: "\xF6\x80\x80\x80" == "\xF6\x80\x80\x80"
|
||||
Xml.tests.cpp:<line number>: passed: encode("\xF7\x80\x80\x80") == u8"\\xF7\\x80\\x80\\x80" for: "\xF7\x80\x80\x80" == "\xF7\x80\x80\x80"
|
||||
Xml.tests.cpp:<line number>: passed: encode("\xDE") == u8"\\xDE" for: "\xDE" == "\xDE"
|
||||
Xml.tests.cpp:<line number>: passed: encode("\xDF") == u8"\\xDF" for: "\xDF" == "\xDF"
|
||||
Xml.tests.cpp:<line number>: passed: encode("\xE0") == u8"\\xE0" for: "\xE0" == "\xE0"
|
||||
Xml.tests.cpp:<line number>: passed: encode("\xEF") == u8"\\xEF" for: "\xEF" == "\xEF"
|
||||
Xml.tests.cpp:<line number>: passed: encode("\xF0") == u8"\\xF0" for: "\xF0" == "\xF0"
|
||||
Xml.tests.cpp:<line number>: passed: encode("\xF4") == u8"\\xF4" for: "\xF4" == "\xF4"
|
||||
Xml.tests.cpp:<line number>: passed: encode("\xE0\x80") == u8"\\xE0\\x80" for: "\xE0\x80" == "\xE0\x80"
|
||||
Xml.tests.cpp:<line number>: passed: encode("\xE0\xBF") == u8"\\xE0\\xBF" for: "\xE0\xBF" == "\xE0\xBF"
|
||||
Xml.tests.cpp:<line number>: passed: encode("\xE1\x80") == u8"\\xE1\\x80" for: "\xE1\x80" == "\xE1\x80"
|
||||
Xml.tests.cpp:<line number>: passed: encode("\xF0\x80") == u8"\\xF0\\x80" for: "\xF0\x80" == "\xF0\x80"
|
||||
Xml.tests.cpp:<line number>: passed: encode("\xF4\x80") == u8"\\xF4\\x80" for: "\xF4\x80" == "\xF4\x80"
|
||||
Xml.tests.cpp:<line number>: passed: encode("\xF0\x80\x80") == u8"\\xF0\\x80\\x80" for: "\xF0\x80\x80" == "\xF0\x80\x80"
|
||||
Xml.tests.cpp:<line number>: passed: encode("\xF4\x80\x80") == u8"\\xF4\\x80\\x80" for: "\xF4\x80\x80" == "\xF4\x80\x80"
|
||||
ToStringVector.tests.cpp:<line number>: passed: Catch::Detail::stringify( empty ) == "{ }" for: "{ }" == "{ }"
|
||||
ToStringVector.tests.cpp:<line number>: passed: Catch::Detail::stringify( oneValue ) == "{ 42 }" for: "{ 42 }" == "{ 42 }"
|
||||
ToStringVector.tests.cpp:<line number>: passed: Catch::Detail::stringify( twoValues ) == "{ 42, 250 }" for: "{ 42, 250 }" == "{ 42, 250 }"
|
||||
|
@@ -1381,5 +1381,5 @@ due to unexpected exception with message:
|
||||
|
||||
===============================================================================
|
||||
test cases: 304 | 230 passed | 70 failed | 4 failed as expected
|
||||
assertions: 1619 | 1467 passed | 131 failed | 21 failed as expected
|
||||
assertions: 1659 | 1507 passed | 131 failed | 21 failed as expected
|
||||
|
||||
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
1726
projects/SelfTest/Baselines/sonarqube.sw.approved.txt
Normal file
1726
projects/SelfTest/Baselines/sonarqube.sw.approved.txt
Normal file
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -17,7 +17,7 @@
|
||||
|
||||
inline Catch::TestCase fakeTestCase(const char* name, const char* desc = "") { return Catch::makeTestCase(nullptr, "", { name, desc }, CATCH_INTERNAL_LINEINFO); }
|
||||
|
||||
TEST_CASE( "Parse test names and tags" ) {
|
||||
TEST_CASE( "Parse test names and tags", "[command-line][test-spec]" ) {
|
||||
|
||||
using Catch::parseTestSpec;
|
||||
using Catch::TestSpec;
|
||||
@@ -269,7 +269,6 @@ TEST_CASE( "Parse test names and tags" ) {
|
||||
CHECK( spec.matches( fakeTestCase( " aardvark " ) ) );
|
||||
CHECK( spec.matches( fakeTestCase( "aardvark " ) ) );
|
||||
CHECK( spec.matches( fakeTestCase( "aardvark" ) ) );
|
||||
|
||||
}
|
||||
SECTION( "Leading and trailing spaces in test name" ) {
|
||||
TestSpec spec = parseTestSpec( "aardvark" );
|
||||
@@ -278,7 +277,18 @@ TEST_CASE( "Parse test names and tags" ) {
|
||||
CHECK( spec.matches( fakeTestCase( " aardvark " ) ) );
|
||||
CHECK( spec.matches( fakeTestCase( "aardvark " ) ) );
|
||||
CHECK( spec.matches( fakeTestCase( "aardvark" ) ) );
|
||||
|
||||
}
|
||||
SECTION("Shortened hide tags are split apart when parsing") {
|
||||
TestSpec spec = parseTestSpec("[.foo]");
|
||||
CHECK(spec.matches(fakeTestCase("hidden and foo", "[.][foo]")));
|
||||
CHECK_FALSE(spec.matches(fakeTestCase("only foo", "[foo]")));
|
||||
}
|
||||
SECTION("Shortened hide tags also properly handle exclusion") {
|
||||
TestSpec spec = parseTestSpec("~[.foo]");
|
||||
CHECK_FALSE(spec.matches(fakeTestCase("hidden and foo", "[.][foo]")));
|
||||
CHECK_FALSE(spec.matches(fakeTestCase("only foo", "[foo]")));
|
||||
CHECK_FALSE(spec.matches(fakeTestCase("only hidden", "[.]")));
|
||||
CHECK(spec.matches(fakeTestCase("neither foo nor hidden", "[bar]")));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -486,7 +496,7 @@ TEST_CASE( "Process can be configured on command line", "[config][command-line]"
|
||||
|
||||
REQUIRE(config.benchmarkSamples == 200);
|
||||
}
|
||||
|
||||
|
||||
SECTION("resamples") {
|
||||
CHECK(cli.parse({ "test", "--benchmark-resamples=20000" }));
|
||||
|
||||
|
@@ -173,6 +173,58 @@ TEST_CASE("Generators internals", "[generators][internals]") {
|
||||
REQUIRE_FALSE(gen.next());
|
||||
}
|
||||
}
|
||||
|
||||
SECTION("Floating Point") {
|
||||
SECTION("Exact") {
|
||||
const auto rangeStart = -1.;
|
||||
const auto rangeEnd = 1.;
|
||||
const auto step = .1;
|
||||
|
||||
auto gen = range(rangeStart, rangeEnd, step);
|
||||
auto expected = rangeStart;
|
||||
while( (rangeEnd - expected) > step ) {
|
||||
INFO( "Current expected value is " << expected )
|
||||
REQUIRE(gen.get() == Approx(expected));
|
||||
REQUIRE(gen.next());
|
||||
|
||||
expected += step;
|
||||
}
|
||||
REQUIRE(gen.get() == Approx( rangeEnd ) );
|
||||
REQUIRE_FALSE(gen.next());
|
||||
}
|
||||
SECTION("Slightly over end") {
|
||||
const auto rangeStart = -1.;
|
||||
const auto rangeEnd = 1.;
|
||||
const auto step = .3;
|
||||
|
||||
auto gen = range(rangeStart, rangeEnd, step);
|
||||
auto expected = rangeStart;
|
||||
while( (rangeEnd - expected) > step ) {
|
||||
INFO( "Current expected value is " << expected )
|
||||
REQUIRE(gen.get() == Approx(expected));
|
||||
REQUIRE(gen.next());
|
||||
|
||||
expected += step;
|
||||
}
|
||||
REQUIRE_FALSE(gen.next());
|
||||
}
|
||||
SECTION("Slightly under end") {
|
||||
const auto rangeStart = -1.;
|
||||
const auto rangeEnd = .9;
|
||||
const auto step = .3;
|
||||
|
||||
auto gen = range(rangeStart, rangeEnd, step);
|
||||
auto expected = rangeStart;
|
||||
while( (rangeEnd - expected) > step ) {
|
||||
INFO( "Current expected value is " << expected )
|
||||
REQUIRE(gen.get() == Approx(expected));
|
||||
REQUIRE(gen.next());
|
||||
|
||||
expected += step;
|
||||
}
|
||||
REQUIRE_FALSE(gen.next());
|
||||
}
|
||||
}
|
||||
}
|
||||
SECTION("Negative manual step") {
|
||||
SECTION("Integer") {
|
||||
|
@@ -4,39 +4,15 @@
|
||||
|
||||
#include <cstring>
|
||||
|
||||
namespace Catch {
|
||||
|
||||
// Implementation of test accessors
|
||||
struct StringRefTestAccess {
|
||||
static auto isOwned( StringRef const& stringRef ) -> bool {
|
||||
return stringRef.isOwned();
|
||||
}
|
||||
static auto isSubstring( StringRef const& stringRef ) -> bool {
|
||||
return stringRef.isSubstring();
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
namespace {
|
||||
auto isOwned( StringRef const& stringRef ) -> bool {
|
||||
return StringRefTestAccess::isOwned( stringRef );
|
||||
}
|
||||
auto isSubstring( StringRef const& stringRef ) -> bool {
|
||||
return StringRefTestAccess::isSubstring( stringRef );
|
||||
}
|
||||
} // end anonymous namespace
|
||||
|
||||
} // namespace Catch
|
||||
|
||||
TEST_CASE( "StringRef", "[Strings][StringRef]" ) {
|
||||
|
||||
using Catch::StringRef;
|
||||
using Catch::isOwned; using Catch::isSubstring;
|
||||
|
||||
SECTION( "Empty string" ) {
|
||||
StringRef empty;
|
||||
REQUIRE( empty.empty() );
|
||||
REQUIRE( empty.size() == 0 );
|
||||
REQUIRE( empty.isNullTerminated() );
|
||||
REQUIRE( std::strcmp( empty.c_str(), "" ) == 0 );
|
||||
}
|
||||
|
||||
@@ -44,28 +20,22 @@ TEST_CASE( "StringRef", "[Strings][StringRef]" ) {
|
||||
StringRef s = "hello";
|
||||
REQUIRE( s.empty() == false );
|
||||
REQUIRE( s.size() == 5 );
|
||||
REQUIRE( isSubstring( s ) == false );
|
||||
REQUIRE( s.isNullTerminated() );
|
||||
|
||||
auto rawChars = s.currentData();
|
||||
auto rawChars = s.data();
|
||||
REQUIRE( std::strcmp( rawChars, "hello" ) == 0 );
|
||||
|
||||
SECTION( "c_str() does not cause copy" ) {
|
||||
REQUIRE( isOwned( s ) == false );
|
||||
|
||||
REQUIRE( s.c_str() == rawChars );
|
||||
|
||||
REQUIRE( isOwned( s ) == false );
|
||||
}
|
||||
REQUIRE_NOTHROW(s.c_str());
|
||||
REQUIRE(s.c_str() == rawChars);
|
||||
REQUIRE(s.data() == rawChars);
|
||||
}
|
||||
SECTION( "From sub-string" ) {
|
||||
StringRef original = StringRef( "original string" ).substr(0, 8);
|
||||
REQUIRE( original == "original" );
|
||||
REQUIRE( isSubstring( original ) );
|
||||
REQUIRE( isOwned( original ) == false );
|
||||
|
||||
original.c_str(); // Forces it to take ownership
|
||||
|
||||
REQUIRE( isOwned( original ) );
|
||||
REQUIRE_FALSE(original.isNullTerminated());
|
||||
REQUIRE_THROWS(original.c_str());
|
||||
REQUIRE_NOTHROW(original.data());
|
||||
}
|
||||
|
||||
|
||||
@@ -76,26 +46,9 @@ TEST_CASE( "StringRef", "[Strings][StringRef]" ) {
|
||||
SECTION( "zero-based substring" ) {
|
||||
REQUIRE( ss.empty() == false );
|
||||
REQUIRE( ss.size() == 5 );
|
||||
REQUIRE( std::strcmp( ss.c_str(), "hello" ) == 0 );
|
||||
REQUIRE( std::strncmp( ss.data(), "hello", 5 ) == 0 );
|
||||
REQUIRE( ss == "hello" );
|
||||
}
|
||||
SECTION( "c_str() causes copy" ) {
|
||||
REQUIRE( isSubstring( ss ) );
|
||||
REQUIRE( isOwned( ss ) == false );
|
||||
|
||||
auto rawChars = ss.currentData();
|
||||
REQUIRE( rawChars == s.currentData() ); // same pointer value
|
||||
REQUIRE( ss.c_str() != rawChars );
|
||||
|
||||
REQUIRE( isOwned( ss ) );
|
||||
|
||||
SECTION( "Self-assignment after substring" ) {
|
||||
ss = *&ss; // the *& are there to suppress warnings (see: "Improvements to Clang's diagnostics" in https://rev.ng/gitlab/revng-bar-2019/clang/raw/master/docs/ReleaseNotes.rst)
|
||||
REQUIRE( isOwned(ss) == false );
|
||||
REQUIRE( ss == "hello" );
|
||||
REQUIRE( rawChars == ss.currentData() ); // same pointer value
|
||||
}
|
||||
}
|
||||
|
||||
SECTION( "non-zero-based substring") {
|
||||
ss = s.substr( 6, 6 );
|
||||
@@ -105,21 +58,32 @@ TEST_CASE( "StringRef", "[Strings][StringRef]" ) {
|
||||
|
||||
SECTION( "Pointer values of full refs should match" ) {
|
||||
StringRef s2 = s;
|
||||
REQUIRE( s.c_str() == s2.c_str() );
|
||||
REQUIRE( s.data() == s2.data() );
|
||||
}
|
||||
|
||||
SECTION( "Pointer values of substring refs should not match" ) {
|
||||
REQUIRE( s.c_str() != ss.c_str() );
|
||||
SECTION( "Pointer values of substring refs should also match" ) {
|
||||
REQUIRE( s.data() == ss.data() );
|
||||
}
|
||||
|
||||
SECTION("Past the end substring") {
|
||||
REQUIRE(s.substr(s.size() + 1, 123).empty());
|
||||
}
|
||||
|
||||
SECTION("Substring off the end are trimmed") {
|
||||
ss = s.substr(6, 123);
|
||||
REQUIRE(std::strcmp(ss.c_str(), "world!") == 0);
|
||||
}
|
||||
// TODO: substring into string + size is longer than end
|
||||
}
|
||||
|
||||
SECTION( "Comparisons" ) {
|
||||
REQUIRE( StringRef("hello") == StringRef("hello") );
|
||||
REQUIRE( StringRef("hello") != StringRef("cello") );
|
||||
SECTION( "Comparisons are deep" ) {
|
||||
char buffer1[] = "Hello";
|
||||
char buffer2[] = "Hello";
|
||||
CHECK((char*)buffer1 != (char*)buffer2);
|
||||
|
||||
StringRef left(buffer1), right(buffer2);
|
||||
REQUIRE( left == right );
|
||||
REQUIRE(left != left.substr(0, 3));
|
||||
}
|
||||
|
||||
SECTION( "from std::string" ) {
|
||||
@@ -159,3 +123,28 @@ TEST_CASE( "StringRef", "[Strings][StringRef]" ) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
TEST_CASE("StringRef at compilation time", "[Strings][StringRef][constexpr]") {
|
||||
using Catch::StringRef;
|
||||
SECTION("Simple constructors") {
|
||||
STATIC_REQUIRE(StringRef{}.size() == 0);
|
||||
|
||||
STATIC_REQUIRE(StringRef{ "abc", 3 }.size() == 3);
|
||||
STATIC_REQUIRE(StringRef{ "abc", 3 }.isNullTerminated());
|
||||
|
||||
STATIC_REQUIRE(StringRef{ "abc", 2 }.size() == 2);
|
||||
STATIC_REQUIRE_FALSE(StringRef{ "abc", 2 }.isNullTerminated());
|
||||
}
|
||||
SECTION("UDL construction") {
|
||||
constexpr auto sr1 = "abc"_catch_sr;
|
||||
STATIC_REQUIRE_FALSE(sr1.empty());
|
||||
STATIC_REQUIRE(sr1.size() == 3);
|
||||
STATIC_REQUIRE(sr1.isNullTerminated());
|
||||
|
||||
using Catch::operator"" _sr;
|
||||
constexpr auto sr2 = ""_sr;
|
||||
STATIC_REQUIRE(sr2.empty());
|
||||
STATIC_REQUIRE(sr2.size() == 0);
|
||||
STATIC_REQUIRE(sr2.isNullTerminated());
|
||||
}
|
||||
}
|
||||
|
@@ -40,10 +40,11 @@ TEST_CASE( "XmlEncode", "[XML]" ) {
|
||||
}
|
||||
|
||||
// Thanks to Peter Bindels (dascandy) for some of the tests
|
||||
TEST_CASE("XmlEncode: UTF-8", "[XML][UTF-8]") {
|
||||
TEST_CASE("XmlEncode: UTF-8", "[XML][UTF-8][approvals]") {
|
||||
#define ESC(lit) (char*)(lit)
|
||||
SECTION("Valid utf-8 strings") {
|
||||
CHECK(encode(u8"Here be 👾") == u8"Here be 👾");
|
||||
CHECK(encode(u8"šš") == u8"šš");
|
||||
CHECK(encode(ESC(u8"Here be 👾")) == ESC(u8"Here be 👾"));
|
||||
CHECK(encode(ESC(u8"šš")) == ESC(u8"šš"));
|
||||
|
||||
CHECK(encode("\xDF\xBF") == "\xDF\xBF"); // 0x7FF
|
||||
CHECK(encode("\xE0\xA0\x80") == "\xE0\xA0\x80"); // 0x800
|
||||
@@ -55,18 +56,18 @@ TEST_CASE("XmlEncode: UTF-8", "[XML][UTF-8]") {
|
||||
}
|
||||
SECTION("Invalid utf-8 strings") {
|
||||
SECTION("Various broken strings") {
|
||||
CHECK(encode("Here \xFF be 👾") == u8"Here \\xFF be 👾");
|
||||
CHECK(encode(ESC("Here \xFF be \xF0\x9F\x91\xBE")) == ESC(u8"Here \\xFF be 👾"));
|
||||
CHECK(encode("\xFF") == "\\xFF");
|
||||
CHECK(encode("\xC5\xC5\xA0") == u8"\\xC5Š");
|
||||
CHECK(encode("\xF4\x90\x80\x80") == u8"\\xF4\\x90\\x80\\x80"); // 0x110000 -- out of unicode range
|
||||
CHECK(encode("\xC5\xC5\xA0") == ESC(u8"\\xC5Š"));
|
||||
CHECK(encode("\xF4\x90\x80\x80") == ESC(u8"\\xF4\\x90\\x80\\x80")); // 0x110000 -- out of unicode range
|
||||
}
|
||||
|
||||
SECTION("Overlong encodings") {
|
||||
CHECK(encode("\xC0\x80") == u8"\\xC0\\x80"); // \0
|
||||
CHECK(encode("\xF0\x80\x80\x80") == u8"\\xF0\\x80\\x80\\x80"); // Super-over-long \0
|
||||
CHECK(encode("\xC1\xBF") == u8"\\xC1\\xBF"); // ASCII char as UTF-8 (0x7F)
|
||||
CHECK(encode("\xE0\x9F\xBF") == u8"\\xE0\\x9F\\xBF"); // 0x7FF
|
||||
CHECK(encode("\xF0\x8F\xBF\xBF") == u8"\\xF0\\x8F\\xBF\\xBF"); // 0xFFFF
|
||||
CHECK(encode("\xC0\x80") == "\\xC0\\x80"); // \0
|
||||
CHECK(encode("\xF0\x80\x80\x80") == "\\xF0\\x80\\x80\\x80"); // Super-over-long \0
|
||||
CHECK(encode("\xC1\xBF") == "\\xC1\\xBF"); // ASCII char as UTF-8 (0x7F)
|
||||
CHECK(encode("\xE0\x9F\xBF") == "\\xE0\\x9F\\xBF"); // 0x7FF
|
||||
CHECK(encode("\xF0\x8F\xBF\xBF") == "\\xF0\\x8F\\xBF\\xBF"); // 0xFFFF
|
||||
}
|
||||
|
||||
// Note that we actually don't modify surrogate pairs, as we do not do strict checking
|
||||
@@ -78,35 +79,36 @@ TEST_CASE("XmlEncode: UTF-8", "[XML][UTF-8]") {
|
||||
}
|
||||
|
||||
SECTION("Invalid start byte") {
|
||||
CHECK(encode("\x80") == u8"\\x80");
|
||||
CHECK(encode("\x81") == u8"\\x81");
|
||||
CHECK(encode("\xBC") == u8"\\xBC");
|
||||
CHECK(encode("\xBF") == u8"\\xBF");
|
||||
CHECK(encode("\x80") == "\\x80");
|
||||
CHECK(encode("\x81") == "\\x81");
|
||||
CHECK(encode("\xBC") == "\\xBC");
|
||||
CHECK(encode("\xBF") == "\\xBF");
|
||||
// Out of range
|
||||
CHECK(encode("\xF5\x80\x80\x80") == u8"\\xF5\\x80\\x80\\x80");
|
||||
CHECK(encode("\xF6\x80\x80\x80") == u8"\\xF6\\x80\\x80\\x80");
|
||||
CHECK(encode("\xF7\x80\x80\x80") == u8"\\xF7\\x80\\x80\\x80");
|
||||
CHECK(encode("\xF5\x80\x80\x80") == "\\xF5\\x80\\x80\\x80");
|
||||
CHECK(encode("\xF6\x80\x80\x80") == "\\xF6\\x80\\x80\\x80");
|
||||
CHECK(encode("\xF7\x80\x80\x80") == "\\xF7\\x80\\x80\\x80");
|
||||
}
|
||||
|
||||
SECTION("Missing continuation byte(s)") {
|
||||
// Missing first continuation byte
|
||||
CHECK(encode("\xDE") == u8"\\xDE");
|
||||
CHECK(encode("\xDF") == u8"\\xDF");
|
||||
CHECK(encode("\xE0") == u8"\\xE0");
|
||||
CHECK(encode("\xEF") == u8"\\xEF");
|
||||
CHECK(encode("\xF0") == u8"\\xF0");
|
||||
CHECK(encode("\xF4") == u8"\\xF4");
|
||||
CHECK(encode("\xDE") == "\\xDE");
|
||||
CHECK(encode("\xDF") == "\\xDF");
|
||||
CHECK(encode("\xE0") == "\\xE0");
|
||||
CHECK(encode("\xEF") == "\\xEF");
|
||||
CHECK(encode("\xF0") == "\\xF0");
|
||||
CHECK(encode("\xF4") == "\\xF4");
|
||||
|
||||
// Missing second continuation byte
|
||||
CHECK(encode("\xE0\x80") == u8"\\xE0\\x80");
|
||||
CHECK(encode("\xE0\xBF") == u8"\\xE0\\xBF");
|
||||
CHECK(encode("\xE1\x80") == u8"\\xE1\\x80");
|
||||
CHECK(encode("\xF0\x80") == u8"\\xF0\\x80");
|
||||
CHECK(encode("\xF4\x80") == u8"\\xF4\\x80");
|
||||
CHECK(encode("\xE0\x80") == "\\xE0\\x80");
|
||||
CHECK(encode("\xE0\xBF") == "\\xE0\\xBF");
|
||||
CHECK(encode("\xE1\x80") == "\\xE1\\x80");
|
||||
CHECK(encode("\xF0\x80") == "\\xF0\\x80");
|
||||
CHECK(encode("\xF4\x80") == "\\xF4\\x80");
|
||||
|
||||
// Missing third continuation byte
|
||||
CHECK(encode("\xF0\x80\x80") == u8"\\xF0\\x80\\x80");
|
||||
CHECK(encode("\xF4\x80\x80") == u8"\\xF4\\x80\\x80");
|
||||
CHECK(encode("\xF0\x80\x80") == "\\xF0\\x80\\x80");
|
||||
CHECK(encode("\xF4\x80\x80") == "\\xF4\\x80\\x80");
|
||||
}
|
||||
}
|
||||
#undef ESC
|
||||
}
|
||||
|
1
projects/SelfTest/Misc/invalid-test-names.input
Normal file
1
projects/SelfTest/Misc/invalid-test-names.input
Normal file
@@ -0,0 +1 @@
|
||||
Test with special, characters in \" name
|
@@ -13,6 +13,7 @@
|
||||
#include "reporters/catch_reporter_teamcity.hpp"
|
||||
#include "reporters/catch_reporter_tap.hpp"
|
||||
#include "reporters/catch_reporter_automake.hpp"
|
||||
#include "reporters/catch_reporter_sonarqube.hpp"
|
||||
|
||||
|
||||
// Some example tag aliases
|
||||
|
@@ -382,8 +382,9 @@ namespace { namespace MatchersTests {
|
||||
REQUIRE_THAT(1.f, WithinULP(1.f, 0));
|
||||
|
||||
REQUIRE_THAT(nextafter(1.f, 2.f), WithinULP(1.f, 1));
|
||||
REQUIRE_THAT(nextafter(1.f, 0.f), WithinULP(1.f, 1));
|
||||
REQUIRE_THAT(nextafter(1.f, 2.f), !WithinULP(1.f, 0));
|
||||
REQUIRE_THAT(0.f, WithinULP(nextafter(0.f, 1.f), 1));
|
||||
REQUIRE_THAT(1.f, WithinULP(nextafter(1.f, 0.f), 1));
|
||||
REQUIRE_THAT(1.f, !WithinULP(nextafter(1.f, 2.f), 0));
|
||||
|
||||
REQUIRE_THAT(1.f, WithinULP(1.f, 0));
|
||||
REQUIRE_THAT(-0.f, WithinULP(0.f, 0));
|
||||
@@ -437,8 +438,9 @@ namespace { namespace MatchersTests {
|
||||
REQUIRE_THAT(1., WithinULP(1., 0));
|
||||
|
||||
REQUIRE_THAT(nextafter(1., 2.), WithinULP(1., 1));
|
||||
REQUIRE_THAT(nextafter(1., 0.), WithinULP(1., 1));
|
||||
REQUIRE_THAT(nextafter(1., 2.), !WithinULP(1., 0));
|
||||
REQUIRE_THAT(0., WithinULP(nextafter(0., 1.), 1));
|
||||
REQUIRE_THAT(1., WithinULP(nextafter(1., 0.), 1));
|
||||
REQUIRE_THAT(1., !WithinULP(nextafter(1., 2.), 0));
|
||||
|
||||
REQUIRE_THAT(1., WithinULP(1., 0));
|
||||
REQUIRE_THAT(-0., WithinULP(0., 0));
|
||||
|
@@ -58,9 +58,11 @@ struct AutoTestReg {
|
||||
REGISTER_TEST_CASE( manuallyRegisteredTestFunction, "ManuallyRegistered" );
|
||||
}
|
||||
};
|
||||
|
||||
CATCH_INTERNAL_START_WARNINGS_SUPPRESSION
|
||||
CATCH_INTERNAL_SUPPRESS_GLOBALS_WARNINGS
|
||||
static AutoTestReg autoTestReg;
|
||||
CATCH_INTERNAL_UNSUPPRESS_GLOBALS_WARNINGS
|
||||
CATCH_INTERNAL_STOP_WARNINGS_SUPPRESSION
|
||||
|
||||
template<typename T>
|
||||
struct Foo {
|
||||
|
@@ -9,12 +9,12 @@
|
||||
// We need 2 types with non-trivial copies/moves
|
||||
struct MyType1 {
|
||||
MyType1() = default;
|
||||
MyType1(MyType1 const&) { throw 1; }
|
||||
[[noreturn]] MyType1(MyType1 const&) { throw 1; }
|
||||
MyType1& operator=(MyType1 const&) { throw 3; }
|
||||
};
|
||||
struct MyType2 {
|
||||
MyType2() = default;
|
||||
MyType2(MyType2 const&) { throw 2; }
|
||||
[[noreturn]] MyType2(MyType2 const&) { throw 2; }
|
||||
MyType2& operator=(MyType2 const&) { throw 4; }
|
||||
};
|
||||
|
||||
|
@@ -390,12 +390,6 @@ TEST_CASE("Commas in various macros are allowed") {
|
||||
}
|
||||
}
|
||||
|
||||
TEST_CASE( "null deref", "[.][failing][!nonportable]" ) {
|
||||
CHECK( false );
|
||||
int *x = NULL;
|
||||
*x = 1;
|
||||
}
|
||||
|
||||
TEST_CASE( "non-copyable objects", "[.][failing]" ) {
|
||||
// Thanks to Agustin Bergé (@k-ballo on the cpplang Slack) for raising this
|
||||
std::type_info const& ti = typeid(int);
|
||||
|
@@ -29,6 +29,7 @@ filelocParser = re.compile(r'''
|
||||
lineNumberParser = re.compile(r' line="[0-9]*"')
|
||||
hexParser = re.compile(r'\b(0[xX][0-9a-fA-F]+)\b')
|
||||
durationsParser = re.compile(r' time="[0-9]*\.[0-9]*"')
|
||||
sonarqubeDurationParser = re.compile(r' duration="[0-9]+"')
|
||||
timestampsParser = re.compile(r'\d{4}-\d{2}-\d{2}T\d{2}\:\d{2}\:\d{2}Z')
|
||||
versionParser = re.compile(r'Catch v[0-9]+\.[0-9]+\.[0-9]+(-develop\.[0-9]+)?')
|
||||
nullParser = re.compile(r'\b(__null|nullptr)\b')
|
||||
@@ -138,6 +139,7 @@ def filterLine(line, isCompact):
|
||||
|
||||
# strip durations and timestamps
|
||||
line = durationsParser.sub(' time="{duration}"', line)
|
||||
line = sonarqubeDurationParser.sub(' duration="{duration}"', line)
|
||||
line = timestampsParser.sub('{iso8601-timestamp}', line)
|
||||
line = specialCaseParser.sub('file:\g<1>', line)
|
||||
line = errnoParser.sub('errno', line)
|
||||
@@ -204,6 +206,8 @@ approve("junit.sw", ["~[!nonportable]~[!benchmark]~[approvals]", "-s", "-w", "No
|
||||
approve("xml.sw", ["~[!nonportable]~[!benchmark]~[approvals]", "-s", "-w", "NoAssertions", "-r", "xml", "--order", "lex", "--rng-seed", "1"])
|
||||
# compact reporter, include passes, warn about No Assertions
|
||||
approve('compact.sw', ['~[!nonportable]~[!benchmark]~[approvals]', '-s', '-w', 'NoAssertions', '-r', 'compact', '--order', 'lex', "--rng-seed", "1"])
|
||||
# sonarqube reporter, include passes, warn about No Assertions
|
||||
approve("sonarqube.sw", ["~[!nonportable]~[!benchmark]~[approvals]", "-s", "-w", "NoAssertions", "-r", "sonarqube", "--order", "lex", "--rng-seed", "1"])
|
||||
|
||||
if overallResult != 0:
|
||||
print("If these differences are expected, run approve.py to approve new baselines.")
|
||||
|
@@ -156,7 +156,7 @@ def performUpdates(version):
|
||||
# We probably should have some kind of convention to select which reporters need to be copied automagically,
|
||||
# but this works for now
|
||||
import shutil
|
||||
for rep in ('automake', 'tap', 'teamcity'):
|
||||
for rep in ('automake', 'tap', 'teamcity', 'sonarqube'):
|
||||
sourceFile = os.path.join(catchPath, 'include/reporters/catch_reporter_{}.hpp'.format(rep))
|
||||
destFile = os.path.join(catchPath, 'single_include', 'catch2', 'catch_reporter_{}.hpp'.format(rep))
|
||||
shutil.copyfile(sourceFile, destFile)
|
||||
|
@@ -41,7 +41,7 @@ def uploadFiles():
|
||||
'save': True
|
||||
})
|
||||
|
||||
if 'status' in response and 'compiler_error' not in response:
|
||||
if 'url' in response and 'compiler_error' not in response:
|
||||
return True, response['url']
|
||||
else:
|
||||
return False, response
|
||||
|
File diff suppressed because it is too large
Load Diff
181
single_include/catch2/catch_reporter_sonarqube.hpp
Normal file
181
single_include/catch2/catch_reporter_sonarqube.hpp
Normal file
@@ -0,0 +1,181 @@
|
||||
/*
|
||||
* Created by Daniel Garcia on 2018-12-04.
|
||||
* Copyright Social Point SL. All rights reserved.
|
||||
*
|
||||
* Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
* file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
*/
|
||||
#ifndef CATCH_REPORTER_SONARQUBE_HPP_INCLUDED
|
||||
#define CATCH_REPORTER_SONARQUBE_HPP_INCLUDED
|
||||
|
||||
|
||||
// Don't #include any Catch headers here - we can assume they are already
|
||||
// included before this header.
|
||||
// This is not good practice in general but is necessary in this case so this
|
||||
// file can be distributed as a single header that works with the main
|
||||
// Catch single header.
|
||||
|
||||
#include <map>
|
||||
|
||||
namespace Catch {
|
||||
|
||||
struct SonarQubeReporter : CumulativeReporterBase<SonarQubeReporter> {
|
||||
|
||||
SonarQubeReporter(ReporterConfig const& config)
|
||||
: CumulativeReporterBase(config)
|
||||
, xml(config.stream()) {
|
||||
m_reporterPrefs.shouldRedirectStdOut = true;
|
||||
m_reporterPrefs.shouldReportAllAssertions = true;
|
||||
}
|
||||
|
||||
~SonarQubeReporter() override;
|
||||
|
||||
static std::string getDescription() {
|
||||
return "Reports test results in the Generic Test Data SonarQube XML format";
|
||||
}
|
||||
|
||||
static std::set<Verbosity> getSupportedVerbosities() {
|
||||
return { Verbosity::Normal };
|
||||
}
|
||||
|
||||
void noMatchingTestCases(std::string const& /*spec*/) override {}
|
||||
|
||||
void testRunStarting(TestRunInfo const& testRunInfo) override {
|
||||
CumulativeReporterBase::testRunStarting(testRunInfo);
|
||||
xml.startElement("testExecutions");
|
||||
xml.writeAttribute("version", "1");
|
||||
}
|
||||
|
||||
void testGroupEnded(TestGroupStats const& testGroupStats) override {
|
||||
CumulativeReporterBase::testGroupEnded(testGroupStats);
|
||||
writeGroup(*m_testGroups.back());
|
||||
}
|
||||
|
||||
void testRunEndedCumulative() override {
|
||||
xml.endElement();
|
||||
}
|
||||
|
||||
void writeGroup(TestGroupNode const& groupNode) {
|
||||
std::map<std::string, TestGroupNode::ChildNodes> testsPerFile;
|
||||
for(auto const& child : groupNode.children)
|
||||
testsPerFile[child->value.testInfo.lineInfo.file].push_back(child);
|
||||
|
||||
for(auto const& kv : testsPerFile)
|
||||
writeTestFile(kv.first.c_str(), kv.second);
|
||||
}
|
||||
|
||||
void writeTestFile(const char* filename, TestGroupNode::ChildNodes const& testCaseNodes) {
|
||||
XmlWriter::ScopedElement e = xml.scopedElement("file");
|
||||
xml.writeAttribute("path", filename);
|
||||
|
||||
for(auto const& child : testCaseNodes)
|
||||
writeTestCase(*child);
|
||||
}
|
||||
|
||||
void writeTestCase(TestCaseNode const& testCaseNode) {
|
||||
// All test cases have exactly one section - which represents the
|
||||
// test case itself. That section may have 0-n nested sections
|
||||
assert(testCaseNode.children.size() == 1);
|
||||
SectionNode const& rootSection = *testCaseNode.children.front();
|
||||
writeSection("", rootSection, testCaseNode.value.testInfo.okToFail());
|
||||
}
|
||||
|
||||
void writeSection(std::string const& rootName, SectionNode const& sectionNode, bool okToFail) {
|
||||
std::string name = trim(sectionNode.stats.sectionInfo.name);
|
||||
if(!rootName.empty())
|
||||
name = rootName + '/' + name;
|
||||
|
||||
if(!sectionNode.assertions.empty() || !sectionNode.stdOut.empty() || !sectionNode.stdErr.empty()) {
|
||||
XmlWriter::ScopedElement e = xml.scopedElement("testCase");
|
||||
xml.writeAttribute("name", name);
|
||||
xml.writeAttribute("duration", static_cast<long>(sectionNode.stats.durationInSeconds * 1000));
|
||||
|
||||
writeAssertions(sectionNode, okToFail);
|
||||
}
|
||||
|
||||
for(auto const& childNode : sectionNode.childSections)
|
||||
writeSection(name, *childNode, okToFail);
|
||||
}
|
||||
|
||||
void writeAssertions(SectionNode const& sectionNode, bool okToFail) {
|
||||
for(auto const& assertion : sectionNode.assertions)
|
||||
writeAssertion( assertion, okToFail);
|
||||
}
|
||||
|
||||
void writeAssertion(AssertionStats const& stats, bool okToFail) {
|
||||
AssertionResult const& result = stats.assertionResult;
|
||||
if(!result.isOk()) {
|
||||
std::string elementName;
|
||||
if(okToFail) {
|
||||
elementName = "skipped";
|
||||
}
|
||||
else {
|
||||
switch(result.getResultType()) {
|
||||
case ResultWas::ThrewException:
|
||||
case ResultWas::FatalErrorCondition:
|
||||
elementName = "error";
|
||||
break;
|
||||
case ResultWas::ExplicitFailure:
|
||||
elementName = "failure";
|
||||
break;
|
||||
case ResultWas::ExpressionFailed:
|
||||
elementName = "failure";
|
||||
break;
|
||||
case ResultWas::DidntThrowException:
|
||||
elementName = "failure";
|
||||
break;
|
||||
|
||||
// We should never see these here:
|
||||
case ResultWas::Info:
|
||||
case ResultWas::Warning:
|
||||
case ResultWas::Ok:
|
||||
case ResultWas::Unknown:
|
||||
case ResultWas::FailureBit:
|
||||
case ResultWas::Exception:
|
||||
elementName = "internalError";
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
XmlWriter::ScopedElement e = xml.scopedElement(elementName);
|
||||
|
||||
ReusableStringStream messageRss;
|
||||
messageRss << result.getTestMacroName() << "(" << result.getExpression() << ")";
|
||||
xml.writeAttribute("message", messageRss.str());
|
||||
|
||||
ReusableStringStream textRss;
|
||||
if (stats.totals.assertions.total() > 0) {
|
||||
textRss << "FAILED:\n";
|
||||
if (result.hasExpression()) {
|
||||
textRss << "\t" << result.getExpressionInMacro() << "\n";
|
||||
}
|
||||
if (result.hasExpandedExpression()) {
|
||||
textRss << "with expansion:\n\t" << result.getExpandedExpression() << "\n";
|
||||
}
|
||||
}
|
||||
|
||||
if(!result.getMessage().empty())
|
||||
textRss << result.getMessage() << "\n";
|
||||
|
||||
for(auto const& msg : stats.infoMessages)
|
||||
if(msg.type == ResultWas::Info)
|
||||
textRss << msg.message << "\n";
|
||||
|
||||
textRss << "at " << result.getSourceInfo();
|
||||
xml.writeText(textRss.str(), XmlFormatting::Newline);
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
XmlWriter xml;
|
||||
};
|
||||
|
||||
#ifdef CATCH_IMPL
|
||||
SonarQubeReporter::~SonarQubeReporter() {}
|
||||
#endif
|
||||
|
||||
CATCH_REGISTER_REPORTER( "sonarqube", SonarQubeReporter )
|
||||
|
||||
} // end namespace Catch
|
||||
|
||||
#endif // CATCH_REPORTER_SONARQUBE_HPP_INCLUDED
|
Reference in New Issue
Block a user