mirror of
https://github.com/catchorg/Catch2.git
synced 2025-09-22 20:45:39 +02:00
Compare commits
4 Commits
devel
...
devel-spon
Author | SHA1 | Date | |
---|---|---|---|
![]() |
3bf91d2045 | ||
![]() |
4b226acdd7 | ||
![]() |
5bd6e441c0 | ||
![]() |
f209c79a3c |
109
README-2.md
Normal file
109
README-2.md
Normal file
@@ -0,0 +1,109 @@
|
||||
<a id="top"></a>
|
||||
|
||||
<table width="100%">
|
||||
<tr>
|
||||
<td align="center" width="50%"><img src="/data/artwork/catch2-logo-full-with-background.svg" width="100%"></td>
|
||||
<td align="center" width="50%"><figure><figcaption>Special thanks to:</figcaption><img src="/data/sponsors/github_repo_sponsorship-inverted.png" width="100%"></figure></td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
[](https://github.com/catchorg/catch2/releases)
|
||||
[](https://github.com/catchorg/Catch2/actions/workflows/linux-simple-builds.yml)
|
||||
[](https://github.com/catchorg/Catch2/actions/workflows/linux-other-builds.yml)
|
||||
[](https://github.com/catchorg/Catch2/actions/workflows/mac-builds.yml)
|
||||
[](https://ci.appveyor.com/project/catchorg/catch2)
|
||||
[](https://codecov.io/gh/catchorg/Catch2)
|
||||
[](https://godbolt.org/z/EdoY15q9G)
|
||||
[](https://discord.gg/4CWS9zD)
|
||||
|
||||
|
||||
## What is Catch2?
|
||||
|
||||
Catch2 is mainly a unit testing framework for C++, but it also
|
||||
provides basic micro-benchmarking features, and simple BDD macros.
|
||||
|
||||
Catch2's main advantage is that using it is both simple and natural.
|
||||
Test names do not have to be valid identifiers, assertions look like
|
||||
normal C++ boolean expressions, and sections provide a nice and local way
|
||||
to share set-up and tear-down code in tests.
|
||||
|
||||
**Example unit test**
|
||||
```cpp
|
||||
#include <catch2/catch_test_macros.hpp>
|
||||
|
||||
#include <cstdint>
|
||||
|
||||
uint32_t factorial( uint32_t number ) {
|
||||
return number <= 1 ? number : factorial(number-1) * number;
|
||||
}
|
||||
|
||||
TEST_CASE( "Factorials are computed", "[factorial]" ) {
|
||||
REQUIRE( factorial( 1) == 1 );
|
||||
REQUIRE( factorial( 2) == 2 );
|
||||
REQUIRE( factorial( 3) == 6 );
|
||||
REQUIRE( factorial(10) == 3'628'800 );
|
||||
}
|
||||
```
|
||||
|
||||
**Example microbenchmark**
|
||||
```cpp
|
||||
#include <catch2/catch_test_macros.hpp>
|
||||
#include <catch2/benchmark/catch_benchmark.hpp>
|
||||
|
||||
#include <cstdint>
|
||||
|
||||
uint64_t fibonacci(uint64_t number) {
|
||||
return number < 2 ? number : fibonacci(number - 1) + fibonacci(number - 2);
|
||||
}
|
||||
|
||||
TEST_CASE("Benchmark Fibonacci", "[!benchmark]") {
|
||||
REQUIRE(fibonacci(5) == 5);
|
||||
|
||||
REQUIRE(fibonacci(20) == 6'765);
|
||||
BENCHMARK("fibonacci 20") {
|
||||
return fibonacci(20);
|
||||
};
|
||||
|
||||
REQUIRE(fibonacci(25) == 75'025);
|
||||
BENCHMARK("fibonacci 25") {
|
||||
return fibonacci(25);
|
||||
};
|
||||
}
|
||||
```
|
||||
|
||||
_Note that benchmarks are not run by default, so you need to run it explicitly
|
||||
with the `[!benchmark]` tag._
|
||||
|
||||
|
||||
## Catch2 v3 has been released!
|
||||
|
||||
You are on the `devel` branch, where the v3 version is being developed.
|
||||
v3 brings a bunch of significant changes, the big one being that Catch2
|
||||
is no longer a single-header library. Catch2 now behaves as a normal
|
||||
library, with multiple headers and separately compiled implementation.
|
||||
|
||||
The documentation is slowly being updated to take these changes into
|
||||
account, but this work is currently still ongoing.
|
||||
|
||||
For migrating from the v2 releases to v3, you should look at [our
|
||||
documentation](docs/migrate-v2-to-v3.md#top). It provides a simple
|
||||
guidelines on getting started, and collects most common migration
|
||||
problems.
|
||||
|
||||
For the previous major version of Catch2 [look into the `v2.x` branch
|
||||
here on GitHub](https://github.com/catchorg/Catch2/tree/v2.x).
|
||||
|
||||
|
||||
## How to use it
|
||||
This documentation comprises these three parts:
|
||||
|
||||
* [Why do we need yet another C++ Test Framework?](docs/why-catch.md#top)
|
||||
* [Tutorial](docs/tutorial.md#top) - getting started
|
||||
* [Reference section](docs/Readme.md#top) - all the details
|
||||
|
||||
|
||||
## More
|
||||
* Issues and bugs can be raised on the [Issue tracker on GitHub](https://github.com/catchorg/Catch2/issues)
|
||||
* For discussion or questions please use [our Discord](https://discord.gg/4CWS9zD)
|
||||
* See who else is using Catch2 in [Open Source Software](docs/opensource-users.md#top)
|
||||
or [commercially](docs/commercial-users.md#top).
|
@@ -1,5 +1,11 @@
|
||||
<a id="top"></a>
|
||||

|
||||
|
||||
<table width="100%">
|
||||
<tr>
|
||||
<td align="center" width="50%"><img src="/data/artwork/catch2-logo-full-with-background.svg" width="100%"></td>
|
||||
<td align="center" width="50%"><figure><figcaption>Special thanks to:</figcaption><img src="/data/sponsors/github_repo_sponsorship.png" width="100%"></figure></td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
[](https://github.com/catchorg/catch2/releases)
|
||||
[](https://github.com/catchorg/Catch2/actions/workflows/linux-simple-builds.yml)
|
||||
|
BIN
data/sponsors/github_repo_sponsorship-inverted.png
Normal file
BIN
data/sponsors/github_repo_sponsorship-inverted.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 188 KiB |
BIN
data/sponsors/github_repo_sponsorship.png
Normal file
BIN
data/sponsors/github_repo_sponsorship.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 264 KiB |
@@ -119,6 +119,8 @@ namespace Catch {
|
||||
m_data.reporterSpecifications.push_back( std::move( *parsed ) );
|
||||
}
|
||||
|
||||
// Reading bazel env vars can change some parts of the config data,
|
||||
// so we have to process the bazel env before acting on the config.
|
||||
if ( enableBazelEnvSupport() ) {
|
||||
readBazelEnvVars();
|
||||
}
|
||||
@@ -183,6 +185,8 @@ namespace Catch {
|
||||
|
||||
bool Config::showHelp() const { return m_data.showHelp; }
|
||||
|
||||
std::string const& Config::getExitGuardFilePath() const { return m_data.prematureExitGuardFilePath; }
|
||||
|
||||
// IConfig interface
|
||||
bool Config::allowThrows() const { return !m_data.noThrow; }
|
||||
StringRef Config::name() const { return m_data.name.empty() ? m_data.processName : m_data.name; }
|
||||
@@ -244,6 +248,11 @@ namespace Catch {
|
||||
m_data.shardCount = bazelShardOptions->shardCount;
|
||||
}
|
||||
}
|
||||
|
||||
const auto bazelExitGuardFile = Detail::getEnv( "TEST_PREMATURE_EXIT_FILE" );
|
||||
if (bazelExitGuardFile) {
|
||||
m_data.prematureExitGuardFilePath = bazelExitGuardFile;
|
||||
}
|
||||
}
|
||||
|
||||
} // end namespace Catch
|
||||
|
@@ -87,6 +87,8 @@ namespace Catch {
|
||||
|
||||
std::vector<std::string> testsOrTags;
|
||||
std::vector<std::string> sectionsToRun;
|
||||
|
||||
std::string prematureExitGuardFilePath;
|
||||
};
|
||||
|
||||
|
||||
@@ -114,6 +116,8 @@ namespace Catch {
|
||||
|
||||
bool showHelp() const;
|
||||
|
||||
std::string const& getExitGuardFilePath() const;
|
||||
|
||||
// IConfig interface
|
||||
bool allowThrows() const override;
|
||||
StringRef name() const override;
|
||||
|
@@ -26,6 +26,8 @@
|
||||
#include <catch2/internal/catch_istream.hpp>
|
||||
|
||||
#include <cassert>
|
||||
#include <cstdio>
|
||||
#include <cstdlib>
|
||||
#include <exception>
|
||||
#include <iomanip>
|
||||
#include <set>
|
||||
@@ -140,6 +142,50 @@ namespace Catch {
|
||||
}
|
||||
}
|
||||
|
||||
// Creates empty file at path. The path must be writable, we do not
|
||||
// try to create directories in path because that's hard in C++14.
|
||||
void setUpGuardFile( std::string const& guardFilePath ) {
|
||||
if ( !guardFilePath.empty() ) {
|
||||
#if defined( _MSC_VER )
|
||||
std::FILE* file = nullptr;
|
||||
if ( fopen_s( &file, guardFilePath.c_str(), "w" ) ) {
|
||||
char msgBuffer[100];
|
||||
const auto err = errno;
|
||||
std::string errMsg;
|
||||
if ( !strerror_s( msgBuffer, err ) ) {
|
||||
errMsg = msgBuffer;
|
||||
} else {
|
||||
errMsg = "Could not translate errno to a string";
|
||||
}
|
||||
|
||||
#else
|
||||
std::FILE* file = std::fopen( guardFilePath.c_str(), "w" );
|
||||
if ( !file ) {
|
||||
const auto err = errno;
|
||||
const char* errMsg = std::strerror( err );
|
||||
#endif
|
||||
|
||||
CATCH_RUNTIME_ERROR( "Could not open the exit guard file '"
|
||||
<< guardFilePath << "' because '"
|
||||
<< errMsg << "' (" << err << ')' );
|
||||
}
|
||||
const int ret = std::fclose( file );
|
||||
CATCH_ENFORCE(
|
||||
ret == 0,
|
||||
"Error when closing the exit guard file: " << ret );
|
||||
}
|
||||
}
|
||||
|
||||
// Removes file at path. Assuming we created it in setUpGuardFile.
|
||||
void tearDownGuardFile( std::string const& guardFilePath ) {
|
||||
if ( !guardFilePath.empty() ) {
|
||||
const int ret = std::remove( guardFilePath.c_str() );
|
||||
CATCH_ENFORCE(
|
||||
ret == 0,
|
||||
"Error when removing the exit guard file: " << ret );
|
||||
}
|
||||
}
|
||||
|
||||
} // anon namespace
|
||||
|
||||
Session::Session() {
|
||||
@@ -258,6 +304,7 @@ namespace Catch {
|
||||
static_cast<void>(std::getchar());
|
||||
}
|
||||
int exitCode = runInternal();
|
||||
|
||||
if( ( m_configData.waitForKeypress & WaitForKeypress::BeforeExit ) != 0 ) {
|
||||
Catch::cout() << "...waiting for enter/ return before exiting, with code: " << exitCode << '\n' << std::flush;
|
||||
static_cast<void>(std::getchar());
|
||||
@@ -298,6 +345,10 @@ namespace Catch {
|
||||
CATCH_TRY {
|
||||
config(); // Force config to be constructed
|
||||
|
||||
// We need to retrieve potential Bazel config with the full Config
|
||||
// constructor, so we have to create the guard file after it is created.
|
||||
setUpGuardFile( m_config->getExitGuardFilePath() );
|
||||
|
||||
seedRng( *m_config );
|
||||
|
||||
if (m_configData.filenamesAsTags) {
|
||||
@@ -327,9 +378,12 @@ namespace Catch {
|
||||
TestGroup tests { CATCH_MOVE(reporter), m_config.get() };
|
||||
auto const totals = tests.execute();
|
||||
|
||||
// If we got here, running the tests finished normally-enough.
|
||||
// They might've failed, but that would've been reported elsewhere.
|
||||
tearDownGuardFile( m_config->getExitGuardFilePath() );
|
||||
|
||||
if ( tests.hadUnmatchedTestSpecs()
|
||||
&& m_config->warnAboutUnmatchedTestSpecs() ) {
|
||||
// UnmatchedTestSpecExitCode
|
||||
return UnmatchedTestSpecExitCode;
|
||||
}
|
||||
|
||||
|
@@ -305,6 +305,9 @@ namespace Catch {
|
||||
| Opt( config.allowZeroTests )
|
||||
["--allow-running-no-tests"]
|
||||
( "Treat 'No tests run' as a success" )
|
||||
| Opt( config.prematureExitGuardFilePath, "path" )
|
||||
["--premature-exit-guard-file"]
|
||||
( "create a file before running tests and delete it during clean exit" )
|
||||
| Arg( config.testsOrTags, "test name|pattern|tags" )
|
||||
( "which test or tests to use" );
|
||||
|
||||
|
Reference in New Issue
Block a user